From 8b497f5a56df559c92df5b2de165a37697ac9d53 Mon Sep 17 00:00:00 2001 From: Tinglong Yang Date: Tue, 25 Jan 2022 22:36:19 +0800 Subject: [PATCH 001/254] change: delete useless code for get old_cpath. (#2000) --- src/ngx_http_lua_util.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 232a1c1315..b783cf850c 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -281,7 +281,6 @@ ngx_http_lua_new_state(lua_State *parent_vm, ngx_cycle_t *cycle, lua_pushliteral(L, LUA_DEFAULT_CPATH ";"); /* package default */ lua_getfield(L, -2, "cpath"); /* package default old */ - old_cpath = lua_tolstring(L, -1, &old_cpath_len); lua_concat(L, 2); /* package new */ lua_setfield(L, -2, "cpath"); /* package */ #endif From 8cf9c632d8ac453a74ce7aabf4e88d66f2fea6a6 Mon Sep 17 00:00:00 2001 From: Johnny Wang Date: Wed, 26 Jan 2022 23:42:01 +0800 Subject: [PATCH 002/254] travis-ci: upgraded openssl to 1.1.1m, pcre to 8.45. (#2002) --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index daae0704f7..335ae71ee6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -37,7 +37,7 @@ env: - LUAJIT_LIB=$LUAJIT_PREFIX/lib - LUAJIT_INC=$LUAJIT_PREFIX/include/luajit-2.1 - LUA_INCLUDE_DIR=$LUAJIT_INC - - PCRE_VER=8.44 + - PCRE_VER=8.45 - PCRE_PREFIX=/opt/pcre - PCRE_LIB=$PCRE_PREFIX/lib - PCRE_INC=$PCRE_PREFIX/include @@ -52,7 +52,7 @@ env: - TEST_NGINX_SLEEP=0.006 jobs: - NGINX_VERSION=1.21.4 OPENSSL_VER=1.1.0l OPENSSL_PATCH_VER=1.1.0d - - NGINX_VERSION=1.21.4 OPENSSL_VER=1.1.1l OPENSSL_PATCH_VER=1.1.1f + - NGINX_VERSION=1.21.4 OPENSSL_VER=1.1.1m OPENSSL_PATCH_VER=1.1.1f services: - memcached From 2615bafa34f649923c6d80bc4b4393a2e62b87f3 Mon Sep 17 00:00:00 2001 From: Gordon McKinney Date: Tue, 8 Feb 2022 23:28:10 +0800 Subject: [PATCH 003/254] bugfix: segment fault when get header via ngx.req.raw_header with malformed requests. Co-authored-by: lijunlong@openresty.com --- src/ngx_http_lua_headers.c | 6 ++++++ t/104-req-raw-header.t | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/src/ngx_http_lua_headers.c b/src/ngx_http_lua_headers.c index 3ebe7847cb..54977dce8e 100644 --- a/src/ngx_http_lua_headers.c +++ b/src/ngx_http_lua_headers.c @@ -167,6 +167,12 @@ ngx_http_lua_ngx_req_raw_header(lua_State *L) size = 0; b = c->buffer; + if (mr->request_line.len == 0) { + /* return empty string on invalid request */ + lua_pushlstring(L, "", 0); + return 1; + } + if (mr->request_line.data[mr->request_line.len] == CR) { line_break_len = 2; diff --git a/t/104-req-raw-header.t b/t/104-req-raw-header.t index f147b2bcf9..aa66630485 100644 --- a/t/104-req-raw-header.t +++ b/t/104-req-raw-header.t @@ -1017,3 +1017,36 @@ client sent invalid header line: "\x20..." while reading client request headers [error] --- skip_nginx 3: < 1.21.1 + + + +=== TEST 35: bugfix: invalid http request +--- log_level: error +--- http_config + lua_package_path "../lua-resty-core/lib/?.lua;;"; +--- config + location /t { + content_by_lua_block { + local sock = ngx.socket.tcp() + local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_SERVER_PORT) + if not ok then + ngx.log(ngx.ERR, "failed to connect to memc: ", err) + return + end + sock:send("\n") + sock:close() + + ngx.say("OK") + } + } + + log_by_lua_block { + local h = ngx.req.raw_header() + } + +--- request +GET /t +--- response_body +OK +--- no_error_log +[error] From 297e73cde6f08aa7f6bd530b9f0a301570ddf15d Mon Sep 17 00:00:00 2001 From: lijunlong Date: Wed, 9 Feb 2022 12:43:14 +0800 Subject: [PATCH 004/254] bugfix: the error message should use the first line rather than the last line of the code block when load lua code block failed. (#2005) --- src/ngx_http_lua_common.h | 2 + src/ngx_http_lua_directive.c | 15 +++++++- t/002-content.t | 71 +++++++++++++++++++++++++++++++++++- 3 files changed, 85 insertions(+), 3 deletions(-) diff --git a/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h index ed88f0a2f5..65a6415a89 100644 --- a/src/ngx_http_lua_common.h +++ b/src/ngx_http_lua_common.h @@ -276,6 +276,8 @@ struct ngx_http_lua_main_conf_s { of requests */ ngx_uint_t malloc_trim_req_count; + ngx_uint_t directive_line; + #if (nginx_version >= 1011011) /* the following 2 fields are only used by ngx.req.raw_headers() for now */ ngx_buf_t **busy_buf_ptrs; diff --git a/src/ngx_http_lua_directive.c b/src/ngx_http_lua_directive.c index 831132f12d..4366b4fff6 100644 --- a/src/ngx_http_lua_directive.c +++ b/src/ngx_http_lua_directive.c @@ -1302,6 +1302,9 @@ ngx_http_lua_gen_chunk_name(ngx_conf_t *cf, const char *tag, size_t tag_len, { u_char *p, *out; size_t len; + ngx_uint_t start_line; + + ngx_http_lua_main_conf_t *lmcf; len = sizeof("=(:)") - 1 + tag_len + cf->conf_file->file.name.len + NGX_INT64_LEN + 1; @@ -1328,10 +1331,14 @@ ngx_http_lua_gen_chunk_name(ngx_conf_t *cf, const char *tag, size_t tag_len, found: + lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_lua_module); + start_line = lmcf->directive_line > 0 + ? lmcf->directive_line : cf->conf_file->line; + 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); + p, start_line); *chunkname_len = p - out - 1; /* exclude the trailing '\0' byte */ @@ -1343,6 +1350,7 @@ ngx_http_lua_gen_chunk_name(ngx_conf_t *cf, const char *tag, size_t tag_len, char * ngx_http_lua_conf_lua_block_parse(ngx_conf_t *cf, ngx_command_t *cmd) { + ngx_http_lua_main_conf_t *lmcf; ngx_http_lua_block_parser_ctx_t ctx; int level = 1; @@ -1376,6 +1384,9 @@ ngx_http_lua_conf_lua_block_parse(ngx_conf_t *cf, ngx_command_t *cmd) ctx.token_len = 0; start_line = cf->conf_file->line; + lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_lua_module); + lmcf->directive_line = start_line; + dd("init start line: %d", (int) start_line); ctx.start_line = start_line; @@ -1494,6 +1505,8 @@ ngx_http_lua_conf_lua_block_parse(ngx_conf_t *cf, ngx_command_t *cmd) done: + lmcf->directive_line = 0; + if (rc == NGX_ERROR) { return NGX_CONF_ERROR; } diff --git a/t/002-content.t b/t/002-content.t index d6a3600444..703ba84a26 100644 --- a/t/002-content.t +++ b/t/002-content.t @@ -10,7 +10,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); #repeat_each(1); -plan tests => repeat_each() * (blocks() * 2 + 24); +plan tests => repeat_each() * (blocks() * 2 + 27); #no_diff(); #no_long_string(); @@ -849,4 +849,71 @@ GET /lua --- response_body_like: 500 Internal Server Error --- error_code: 500 --- error_log eval -qr/failed to load inlined Lua code: / +qr/failed to load inlined Lua code: content_by_lua\(nginx.conf:40\)/ + + + +=== TEST 43: syntax error in content_by_lua_block +--- config + location /lua { + + content_by_lua_block { + 'for end'; + } + } +--- request +GET /lua +--- response_body_like: 500 Internal Server Error +--- error_code: 500 +--- error_log eval +qr/failed to load inlined Lua code: content_by_lua\(nginx.conf:41\)/ + + + +=== TEST 44: syntax error in second content_by_lua_block +--- config + location /foo { + content_by_lua_block { + 'for end'; + } + } + + location /lua { + content_by_lua_block { + 'for end'; + } + } +--- request +GET /lua +--- response_body_like: 500 Internal Server Error +--- error_code: 500 +--- error_log eval +qr/failed to load inlined Lua code: content_by_lua\(nginx.conf:46\)/ + + + +=== TEST 45: syntax error in thrid content_by_lua_block +--- config + location /foo { + content_by_lua_block { + 'for end'; + } + } + + location /bar { + content_by_lua_block { + 'for end'; + } + } + + location /lua { + content_by_lua_block { + 'for end'; + } + } +--- request +GET /lua +--- response_body_like: 500 Internal Server Error +--- error_code: 500 +--- error_log eval +qr/failed to load inlined Lua code: content_by_lua\(nginx.conf:52\)/ From 907d1d9adac214abe93f8c7d5dea38909a868f0f Mon Sep 17 00:00:00 2001 From: Chrono Date: Fri, 11 Feb 2022 19:48:54 +0800 Subject: [PATCH 005/254] doc: modified the todo section. we now have exit_worker_by_lua (#2009) --- README.markdown | 1 - doc/HttpLuaModule.wiki | 37 ++++++++++++++++++------------------- 2 files changed, 18 insertions(+), 20 deletions(-) diff --git a/README.markdown b/README.markdown index a3a631cb3e..5a87d0c45d 100644 --- a/README.markdown +++ b/README.markdown @@ -974,7 +974,6 @@ TODO * cosocket: add configure options for different strategies of handling the cosocket connection exceeding in the pools. * review and apply vadim-pavlov's patch for [ngx.location.capture](#ngxlocationcapture)'s `extra_headers` option * use `ngx_hash_t` to optimize the built-in header look-up process for [ngx.req.set_header](#ngxreqset_header), [ngx.header.HEADER](#ngxheaderheader), and etc. -* add directives to run Lua codes when Nginx stops. * add `ignore_resp_headers`, `ignore_resp_body`, and `ignore_resp` options to [ngx.location.capture](#ngxlocationcapture) and [ngx.location.capture_multi](#ngxlocationcapture_multi) methods, to allow micro performance tuning on the user side. * add automatic Lua code time slicing support by yielding and resuming the Lua VM actively via Lua's debug hooks. * add `stat` mode similar to [mod_lua](https://httpd.apache.org/docs/trunk/mod/mod_lua.html). diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 0d7a6f73b1..5c79dda3d6 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -809,7 +809,6 @@ phases. * cosocket: add configure options for different strategies of handling the cosocket connection exceeding in the pools. * review and apply vadim-pavlov's patch for [[#ngx.location.capture|ngx.location.capture]]'s extra_headers option * use ngx_hash_t to optimize the built-in header look-up process for [[#ngx.req.set_header|ngx.req.set_header]], [[#ngx.header.HEADER|ngx.header.HEADER]], and etc. -* add directives to run Lua codes when Nginx stops. * add ignore_resp_headers, ignore_resp_body, and ignore_resp options to [[#ngx.location.capture|ngx.location.capture]] and [[#ngx.location.capture_multi|ngx.location.capture_multi]] methods, to allow micro performance tuning on the user side. * add automatic Lua code time slicing support by yielding and resuming the Lua VM actively via Lua's debug hooks. * add stat mode similar to [https://httpd.apache.org/docs/trunk/mod/mod_lua.html mod_lua]. @@ -1607,8 +1606,8 @@ Note that this handler always runs ''after'' the standard [[HttpRewriteModule]]. location /foo { set $a 12; # create and initialize $a set $b ""; # create and initialize $b - rewrite_by_lua_block { - ngx.var.b = tonumber(ngx.var.a) + 1 + rewrite_by_lua_block { + ngx.var.b = tonumber(ngx.var.a) + 1 } echo "res = $b"; } @@ -1622,8 +1621,8 @@ On the other hand, the following will not work as expected: ? location /foo { ? set $a 12; # create and initialize $a ? set $b ''; # create and initialize $b - ? rewrite_by_lua_block { - ? ngx.var.b = tonumber(ngx.var.a) + 1 + ? rewrite_by_lua_block { + ? ngx.var.b = tonumber(ngx.var.a) + 1 ? } ? if ($b = '13') { ? rewrite ^ /bar redirect; @@ -1698,8 +1697,8 @@ If the [[HttpRewriteModule]]'s [[HttpRewriteModule#rewrite|rewrite]] directive i location /foo { rewrite ^ /bar; - rewrite_by_lua_block { - ngx.exit(503) + rewrite_by_lua_block { + ngx.exit(503) } } location /bar { @@ -1892,8 +1891,8 @@ Here is an example of overriding a response header (or adding one if absent) in location / { proxy_pass http://mybackend; - header_filter_by_lua_block { - ngx.header.Foo = "blah" + header_filter_by_lua_block { + ngx.header.Foo = "blah" } } @@ -1964,8 +1963,8 @@ The Lua code can pass its own modified version of the input data chunk to the do location / { proxy_pass http://mybackend; - body_filter_by_lua_block { - ngx.arg[1] = string.upper(ngx.arg[1]) + body_filter_by_lua_block { + ngx.arg[1] = string.upper(ngx.arg[1]) } } @@ -2006,11 +2005,11 @@ When the Lua code may change the length of the response body, then it is require location /foo { # fastcgi_pass/proxy_pass/... - header_filter_by_lua_block { - ngx.header.content_length = nil + header_filter_by_lua_block { + ngx.header.content_length = nil } - body_filter_by_lua_block { - ngx.arg[1] = string.len(ngx.arg[1]) .. "\n" + body_filter_by_lua_block { + ngx.arg[1] = string.len(ngx.arg[1]) .. "\n" } } @@ -3688,8 +3687,8 @@ Lua tables can be used for both requests and responses when the number of subreq table.insert(reqs, { "/memcached" }) -- issue all the requests at once and wait until they all return - local resps = { - ngx.location.capture_multi(reqs) + local resps = { + ngx.location.capture_multi(reqs) } -- loop over the responses table @@ -5201,8 +5200,8 @@ For example, location = /md5 { - content_by_lua_block { - ngx.say(ngx.md5("hello")) + content_by_lua_block { + ngx.say(ngx.md5("hello")) } } From 70a50e66c4e43287d0bbd4ec9bd0485f53a7e110 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Mon, 14 Feb 2022 15:12:45 +0800 Subject: [PATCH 006/254] optimize: change lua chunkname to config filename and line number for (init/header_filter/body_filter)_by_lua_block and so on. (#2008) --- src/ngx_http_lua_balancer.c | 12 +- src/ngx_http_lua_bodyfilterby.c | 3 +- src/ngx_http_lua_common.h | 11 ++ src/ngx_http_lua_directive.c | 132 ++++++++++++++++--- src/ngx_http_lua_directive.h | 3 +- src/ngx_http_lua_exitworkerby.c | 10 +- src/ngx_http_lua_headerfilterby.c | 3 +- src/ngx_http_lua_initby.c | 11 +- src/ngx_http_lua_initworkerby.c | 10 +- src/ngx_http_lua_module.c | 12 ++ src/ngx_http_lua_ssl_certby.c | 12 +- src/ngx_http_lua_ssl_client_helloby.c | 13 +- src/ngx_http_lua_ssl_session_fetchby.c | 11 +- src/ngx_http_lua_ssl_session_storeby.c | 11 +- t/001-set.t | 2 +- t/002-content.t | 171 ++++++++++++++++++++++++- t/009-log.t | 8 +- t/025-codecache.t | 16 +-- t/041-header-filter.t | 52 +++++++- t/082-body-filter.t | 54 +++++++- t/086-init-by.t | 44 +++++++ t/091-coroutine.t | 6 +- t/124-init-worker.t | 50 ++++++++ t/138-balancer.t | 35 ++++- t/139-ssl-cert-by.t | 16 +-- t/142-ssl-session-store.t | 10 +- t/143-ssl-session-fetch.t | 38 +++--- t/158-global-var.t | 16 +-- t/162-exit-worker.t | 48 ++++++- 29 files changed, 722 insertions(+), 98 deletions(-) diff --git a/src/ngx_http_lua_balancer.c b/src/ngx_http_lua_balancer.c index e4ac57a301..af4da73388 100644 --- a/src/ngx_http_lua_balancer.c +++ b/src/ngx_http_lua_balancer.c @@ -90,7 +90,7 @@ ngx_http_lua_balancer_handler_inline(ngx_http_request_t *r, lscf->balancer.src.len, &lscf->balancer.src_ref, lscf->balancer.src_key, - "=balancer_by_lua"); + (const char *) lscf->balancer.chunkname); if (rc != NGX_OK) { return rc; } @@ -125,6 +125,8 @@ char * ngx_http_lua_balancer_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { + size_t chunkname_len; + u_char *chunkname; u_char *cache_key = NULL; u_char *name; ngx_str_t *value; @@ -172,8 +174,16 @@ ngx_http_lua_balancer_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, return NGX_CONF_ERROR; } + chunkname = ngx_http_lua_gen_chunk_name(cf, "balancer_by_lua", + sizeof("balancer_by_lua") - 1, + &chunkname_len); + if (chunkname == NULL) { + return NGX_CONF_ERROR; + } + /* Don't eval nginx variables for inline lua code */ lscf->balancer.src = value[1]; + lscf->balancer.chunkname = chunkname; } lscf->balancer.src_key = cache_key; diff --git a/src/ngx_http_lua_bodyfilterby.c b/src/ngx_http_lua_bodyfilterby.c index 902488911e..1aa01e552b 100644 --- a/src/ngx_http_lua_bodyfilterby.c +++ b/src/ngx_http_lua_bodyfilterby.c @@ -161,7 +161,8 @@ ngx_http_lua_body_filter_inline(ngx_http_request_t *r, ngx_chain_t *in) llcf->body_filter_src.value.len, &llcf->body_filter_src_ref, llcf->body_filter_src_key, - "=body_filter_by_lua"); + (const char *) + llcf->body_filter_chunkname); if (rc != NGX_OK) { return NGX_ERROR; } diff --git a/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h index 65a6415a89..017e2a0434 100644 --- a/src/ngx_http_lua_common.h +++ b/src/ngx_http_lua_common.h @@ -31,6 +31,7 @@ typedef struct { size_t size; int ref; u_char *key; + u_char *chunkname; ngx_str_t script; } ngx_http_lua_set_var_data_t; #endif @@ -233,12 +234,15 @@ struct ngx_http_lua_main_conf_s { ngx_http_lua_main_conf_handler_pt init_handler; ngx_str_t init_src; + u_char *init_chunkname; ngx_http_lua_main_conf_handler_pt init_worker_handler; ngx_str_t init_worker_src; + u_char *init_worker_chunkname; ngx_http_lua_main_conf_handler_pt exit_worker_handler; ngx_str_t exit_worker_src; + u_char *exit_worker_chunkname; ngx_http_lua_balancer_peer_data_t *balancer_peer_data; /* neither yielding nor recursion is possible in @@ -310,21 +314,25 @@ union ngx_http_lua_srv_conf_u { ngx_http_lua_srv_conf_handler_pt ssl_cert_handler; ngx_str_t ssl_cert_src; u_char *ssl_cert_src_key; + u_char *ssl_cert_chunkname; int ssl_cert_src_ref; ngx_http_lua_srv_conf_handler_pt ssl_sess_store_handler; ngx_str_t ssl_sess_store_src; u_char *ssl_sess_store_src_key; + u_char *ssl_sess_store_chunkname; int ssl_sess_store_src_ref; ngx_http_lua_srv_conf_handler_pt ssl_sess_fetch_handler; ngx_str_t ssl_sess_fetch_src; u_char *ssl_sess_fetch_src_key; + u_char *ssl_sess_fetch_chunkname; int ssl_sess_fetch_src_ref; ngx_http_lua_srv_conf_handler_pt ssl_client_hello_handler; ngx_str_t ssl_client_hello_src; u_char *ssl_client_hello_src_key; + u_char *ssl_client_hello_chunkname; int ssl_client_hello_src_ref; } srv; #endif @@ -333,6 +341,7 @@ union ngx_http_lua_srv_conf_u { ngx_http_lua_srv_conf_handler_pt handler; ngx_str_t src; u_char *src_key; + u_char *chunkname; int src_ref; } balancer; }; @@ -403,6 +412,7 @@ typedef struct { inline script/script file path */ + u_char *header_filter_chunkname; u_char *header_filter_src_key; /* cached key for header_filter_src */ int header_filter_src_ref; @@ -410,6 +420,7 @@ typedef struct { ngx_http_complex_value_t body_filter_src; u_char *body_filter_src_key; + u_char *body_filter_chunkname; int body_filter_src_ref; ngx_msec_t keepalive_timeout; diff --git a/src/ngx_http_lua_directive.c b/src/ngx_http_lua_directive.c index 4366b4fff6..dda447fb7e 100644 --- a/src/ngx_http_lua_directive.c +++ b/src/ngx_http_lua_directive.c @@ -32,6 +32,9 @@ #include "ngx_http_lua_log.h" +#define LJ_CHUNKNAME_MAX_LEN 42 + + typedef struct ngx_http_lua_block_parser_ctx_s ngx_http_lua_block_parser_ctx_t; @@ -43,8 +46,6 @@ typedef struct ngx_http_lua_block_parser_ctx_s static ngx_int_t ngx_http_lua_set_by_lua_init(ngx_http_request_t *r); #endif -static u_char *ngx_http_lua_gen_chunk_name(ngx_conf_t *cf, const char *tag, - size_t tag_len, size_t *chunkname_len); static ngx_int_t ngx_http_lua_conf_read_lua_token(ngx_conf_t *cf, ngx_http_lua_block_parser_ctx_t *ctx); static u_char *ngx_http_lua_strlstrn(u_char *s1, u_char *last, u_char *s2, @@ -280,6 +281,8 @@ ngx_http_lua_set_by_lua_block(ngx_conf_t *cf, ngx_command_t *cmd, char * ngx_http_lua_set_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { + size_t chunkname_len; + u_char *chunkname; u_char *cache_key; ngx_str_t *value; ngx_str_t target; @@ -312,7 +315,15 @@ ngx_http_lua_set_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return NGX_CONF_ERROR; } + chunkname = ngx_http_lua_gen_chunk_name(cf, "set_by_lua", + sizeof("set_by_lua") - 1, + &chunkname_len); + if (chunkname == NULL) { + return NGX_CONF_ERROR; + } + filter_data->key = cache_key; + filter_data->chunkname = chunkname; filter_data->ref = LUA_REFNIL; filter_data->script = value[2]; filter_data->size = filter.size; @@ -375,6 +386,7 @@ ngx_http_lua_set_by_lua_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) filter_data->key = cache_key; filter_data->ref = LUA_REFNIL; filter_data->size = filter.size; + filter_data->chunkname = NULL; ngx_str_null(&filter_data->script); @@ -404,7 +416,8 @@ ngx_http_lua_filter_set_by_lua_inline(ngx_http_request_t *r, ngx_str_t *val, filter_data->script.data, filter_data->script.len, &filter_data->ref, - filter_data->key, "=set_by_lua"); + filter_data->key, + (const char *) filter_data->chunkname); if (rc != NGX_OK) { return NGX_ERROR; } @@ -912,7 +925,8 @@ char * ngx_http_lua_header_filter_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { - u_char *cache_key = NULL; + size_t chunkname_len; + u_char *cache_key = NULL, *chunkname; ngx_str_t *value; ngx_http_lua_main_conf_t *lmcf; ngx_http_lua_loc_conf_t *llcf = conf; @@ -947,8 +961,15 @@ ngx_http_lua_header_filter_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, return NGX_CONF_ERROR; } + chunkname = ngx_http_lua_gen_chunk_name(cf, "header_filter_by_lua", + sizeof("header_filter_by_lua") - 1, &chunkname_len); + if (chunkname == NULL) { + return NGX_CONF_ERROR; + } + /* Don't eval nginx variables for inline lua code */ llcf->header_filter_src.value = value[1]; + llcf->header_filter_chunkname = chunkname; } else { ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); @@ -1004,7 +1025,8 @@ char * ngx_http_lua_body_filter_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { - u_char *cache_key = NULL; + size_t chunkname_len; + u_char *cache_key = NULL, *chunkname; ngx_str_t *value; ngx_http_lua_main_conf_t *lmcf; ngx_http_lua_loc_conf_t *llcf = conf; @@ -1039,8 +1061,16 @@ ngx_http_lua_body_filter_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, return NGX_CONF_ERROR; } + chunkname = ngx_http_lua_gen_chunk_name(cf, "body_filter_by_lua", + sizeof("body_filter_by_lua") - 1, &chunkname_len); + if (chunkname == NULL) { + return NGX_CONF_ERROR; + } + + /* Don't eval nginx variables for inline lua code */ llcf->body_filter_src.value = value[1]; + llcf->body_filter_chunkname = chunkname; } else { ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); @@ -1100,6 +1130,8 @@ ngx_http_lua_init_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, u_char *name; ngx_str_t *value; ngx_http_lua_main_conf_t *lmcf = conf; + size_t chunkname_len; + u_char *chunkname; dd("enter"); @@ -1135,6 +1167,15 @@ ngx_http_lua_init_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, } else { lmcf->init_src = value[1]; + + chunkname = ngx_http_lua_gen_chunk_name(cf, "init_by_lua", + sizeof("init_by_lua") - 1, + &chunkname_len); + if (chunkname == NULL) { + return NGX_CONF_ERROR; + } + + lmcf->init_chunkname = chunkname; } return NGX_CONF_OK; @@ -1167,6 +1208,8 @@ ngx_http_lua_init_worker_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, u_char *name; ngx_str_t *value; ngx_http_lua_main_conf_t *lmcf = conf; + size_t chunkname_len; + u_char *chunkname; dd("enter"); @@ -1195,6 +1238,14 @@ ngx_http_lua_init_worker_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, } else { lmcf->init_worker_src = value[1]; + + chunkname = ngx_http_lua_gen_chunk_name(cf, "init_worker_by_lua", + sizeof("init_worker_by_lua") - 1, &chunkname_len); + if (chunkname == NULL) { + return NGX_CONF_ERROR; + } + + lmcf->init_worker_chunkname = chunkname; } return NGX_CONF_OK; @@ -1227,6 +1278,8 @@ ngx_http_lua_exit_worker_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, u_char *name; ngx_str_t *value; ngx_http_lua_main_conf_t *lmcf = conf; + size_t chunkname_len; + u_char *chunkname; /* must specify a content handler */ if (cmd->post == NULL) { @@ -1253,6 +1306,15 @@ ngx_http_lua_exit_worker_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, } else { lmcf->exit_worker_src = value[1]; + + chunkname = ngx_http_lua_gen_chunk_name(cf, "exit_worker_by_lua", + sizeof("exit_worker_by_lua")- 1, + &chunkname_len); + if (chunkname == NULL) { + return NGX_CONF_ERROR; + } + + lmcf->exit_worker_chunkname = chunkname; } return NGX_CONF_OK; @@ -1296,13 +1358,18 @@ ngx_http_lua_set_by_lua_init(ngx_http_request_t *r) #endif -static u_char * +u_char * ngx_http_lua_gen_chunk_name(ngx_conf_t *cf, const char *tag, size_t tag_len, size_t *chunkname_len) { u_char *p, *out; size_t len; ngx_uint_t start_line; + ngx_str_t *conf_prefix; + ngx_str_t *filename; + u_char *filename_end; + const char *pre_str = ""; + ngx_uint_t start_line_len; ngx_http_lua_main_conf_t *lmcf; @@ -1314,30 +1381,55 @@ ngx_http_lua_gen_chunk_name(ngx_conf_t *cf, const char *tag, size_t tag_len, return NULL; } - if (cf->conf_file->file.name.len) { - p = cf->conf_file->file.name.data + cf->conf_file->file.name.len; - while (--p >= cf->conf_file->file.name.data) { - if (*p == '/' || *p == '\\') { - p++; + lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_lua_module); + start_line = lmcf->directive_line > 0 + ? lmcf->directive_line : cf->conf_file->line; + p = ngx_snprintf(out, len, "%d", start_line); + start_line_len = p - out; + + filename = &cf->conf_file->file.name; + filename_end = filename->data + filename->len; + if (filename->len > 0) { + if (filename->len >= 11) { + p = filename_end - 11; + if ((*p == '/' || *p == '\\') + && ngx_memcmp(p, "/nginx.conf", 11) == 0) + { + p++; /* now p is nginx.conf */ goto found; } } - p++; + conf_prefix = &cf->cycle->conf_prefix; + p = filename->data + conf_prefix->len; + if ((conf_prefix->len < filename->len) + && ngx_memcmp(conf_prefix->data, + filename->data, conf_prefix->len) == 0) + { + /* files in conf_prefix directory, use the relative path */ + if (filename_end - p + start_line_len > LJ_CHUNKNAME_MAX_LEN) { + p = filename_end - LJ_CHUNKNAME_MAX_LEN + start_line_len + 3; + pre_str = "..."; + } - } else { - p = cf->conf_file->file.name.data; + goto found; + } } + p = filename->data; + + if (filename->len + start_line_len <= LJ_CHUNKNAME_MAX_LEN) { + goto found; + } + + p = filename_end - LJ_CHUNKNAME_MAX_LEN + start_line_len + 3; + pre_str = "..."; + found: - lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_lua_module); - start_line = lmcf->directive_line > 0 - ? lmcf->directive_line : cf->conf_file->line; - 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 = ngx_snprintf(out, len, "=%*s(%s%*s:%d)%Z", + tag_len, tag, pre_str, filename_end - p, p, start_line); *chunkname_len = p - out - 1; /* exclude the trailing '\0' byte */ diff --git a/src/ngx_http_lua_directive.h b/src/ngx_http_lua_directive.h index adfba12761..315c0a9f2d 100644 --- a/src/ngx_http_lua_directive.h +++ b/src/ngx_http_lua_directive.h @@ -81,7 +81,8 @@ char *ngx_http_lua_conf_lua_block_parse(ngx_conf_t *cf, ngx_command_t *cmd); char *ngx_http_lua_capture_error_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); - +u_char *ngx_http_lua_gen_chunk_name(ngx_conf_t *cf, const char *tag, + size_t tag_len, size_t *chunkname_len); #endif /* _NGX_HTTP_LUA_DIRECTIVE_H_INCLUDED_ */ diff --git a/src/ngx_http_lua_exitworkerby.c b/src/ngx_http_lua_exitworkerby.c index f1329566bc..65edc04e63 100644 --- a/src/ngx_http_lua_exitworkerby.c +++ b/src/ngx_http_lua_exitworkerby.c @@ -95,12 +95,20 @@ ngx_http_lua_exit_worker_by_inline(ngx_log_t *log, ngx_http_lua_main_conf_t *lmcf, lua_State *L) { int status; + const char *chunkname; status = luaL_loadbuffer(L, (char *) lmcf->exit_worker_src.data, lmcf->exit_worker_src.len, "=exit_worker_by_lua") || ngx_http_lua_do_call(log, L); - return ngx_http_lua_report(log, L, status, "exit_worker_by_lua"); + if (lmcf->exit_worker_chunkname == NULL) { + chunkname = "exit_worker_by_lua"; + + } else { + chunkname = (const char *) lmcf->exit_worker_chunkname; + } + + return ngx_http_lua_report(log, L, status, chunkname); } diff --git a/src/ngx_http_lua_headerfilterby.c b/src/ngx_http_lua_headerfilterby.c index 4741c72267..f2fe165bd5 100644 --- a/src/ngx_http_lua_headerfilterby.c +++ b/src/ngx_http_lua_headerfilterby.c @@ -171,7 +171,8 @@ ngx_http_lua_header_filter_inline(ngx_http_request_t *r) llcf->header_filter_src.value.len, &llcf->header_filter_src_ref, llcf->header_filter_src_key, - "=header_filter_by_lua"); + (const char *) + llcf->header_filter_chunkname); if (rc != NGX_OK) { return NGX_ERROR; } diff --git a/src/ngx_http_lua_initby.c b/src/ngx_http_lua_initby.c index e8941da6ca..bfd88c52ad 100644 --- a/src/ngx_http_lua_initby.c +++ b/src/ngx_http_lua_initby.c @@ -18,12 +18,21 @@ ngx_http_lua_init_by_inline(ngx_log_t *log, ngx_http_lua_main_conf_t *lmcf, lua_State *L) { int status; + const char *chunkname; + status = luaL_loadbuffer(L, (char *) lmcf->init_src.data, lmcf->init_src.len, "=init_by_lua") || ngx_http_lua_do_call(log, L); - return ngx_http_lua_report(log, L, status, "init_by_lua"); + if (lmcf->init_chunkname == NULL) { + chunkname = "init_by_lua"; + + } else { + chunkname = (const char *) lmcf->init_chunkname; + } + + return ngx_http_lua_report(log, L, status, chunkname); } diff --git a/src/ngx_http_lua_initworkerby.c b/src/ngx_http_lua_initworkerby.c index 94de796ade..e559c89613 100644 --- a/src/ngx_http_lua_initworkerby.c +++ b/src/ngx_http_lua_initworkerby.c @@ -317,12 +317,20 @@ ngx_http_lua_init_worker_by_inline(ngx_log_t *log, ngx_http_lua_main_conf_t *lmcf, lua_State *L) { int status; + const char *chunkname; status = luaL_loadbuffer(L, (char *) lmcf->init_worker_src.data, lmcf->init_worker_src.len, "=init_worker_by_lua") || ngx_http_lua_do_call(log, L); - return ngx_http_lua_report(log, L, status, "init_worker_by_lua"); + if (lmcf->init_worker_chunkname == NULL) { + chunkname = "init_worker_by_lua"; + + } else { + chunkname = (const char *) lmcf->init_worker_chunkname; + } + + return ngx_http_lua_report(log, L, status, chunkname); } diff --git a/src/ngx_http_lua_module.c b/src/ngx_http_lua_module.c index fbeba12a7f..09fd0a91f8 100644 --- a/src/ngx_http_lua_module.c +++ b/src/ngx_http_lua_module.c @@ -1103,22 +1103,27 @@ ngx_http_lua_create_srv_conf(ngx_conf_t *cf) /* set by ngx_pcalloc: * lscf->srv.ssl_client_hello_handler = NULL; * lscf->srv.ssl_client_hello_src = { 0, NULL }; + * lscf->srv.ssl_client_hello_chunkname = NULL; * lscf->srv.ssl_client_hello_src_key = NULL; * * lscf->srv.ssl_cert_handler = NULL; * lscf->srv.ssl_cert_src = { 0, NULL }; + * lscf->srv.ssl_cert_chunkname = NULL; * lscf->srv.ssl_cert_src_key = NULL; * * lscf->srv.ssl_session_store_handler = NULL; * lscf->srv.ssl_session_store_src = { 0, NULL }; + * lscf->srv.ssl_session_store_chunkname = NULL; * lscf->srv.ssl_session_store_src_key = NULL; * * lscf->srv.ssl_session_fetch_handler = NULL; * lscf->srv.ssl_session_fetch_src = { 0, NULL }; + * lscf->srv.ssl_session_fetch_chunkname = NULL; * lscf->srv.ssl_session_fetch_src_key = NULL; * * lscf->balancer.handler = NULL; * lscf->balancer.src = { 0, NULL }; + * lscf->balancer.chunkname = NULL; * lscf->balancer.src_key = NULL; */ @@ -1151,6 +1156,8 @@ ngx_http_lua_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) conf->srv.ssl_client_hello_src_ref = prev->srv.ssl_client_hello_src_ref; conf->srv.ssl_client_hello_src_key = prev->srv.ssl_client_hello_src_key; conf->srv.ssl_client_hello_handler = prev->srv.ssl_client_hello_handler; + conf->srv.ssl_client_hello_chunkname + = prev->srv.ssl_client_hello_chunkname; } if (conf->srv.ssl_client_hello_src.len) { @@ -1190,6 +1197,7 @@ ngx_http_lua_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) conf->srv.ssl_cert_src_ref = prev->srv.ssl_cert_src_ref; conf->srv.ssl_cert_src_key = prev->srv.ssl_cert_src_key; conf->srv.ssl_cert_handler = prev->srv.ssl_cert_handler; + conf->srv.ssl_cert_chunkname = prev->srv.ssl_cert_chunkname; } if (conf->srv.ssl_cert_src.len) { @@ -1229,6 +1237,7 @@ ngx_http_lua_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) conf->srv.ssl_sess_store_src_ref = prev->srv.ssl_sess_store_src_ref; conf->srv.ssl_sess_store_src_key = prev->srv.ssl_sess_store_src_key; conf->srv.ssl_sess_store_handler = prev->srv.ssl_sess_store_handler; + conf->srv.ssl_sess_store_chunkname = prev->srv.ssl_sess_store_chunkname; } if (conf->srv.ssl_sess_store_src.len) { @@ -1252,6 +1261,7 @@ ngx_http_lua_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) conf->srv.ssl_sess_fetch_src_ref = prev->srv.ssl_sess_fetch_src_ref; conf->srv.ssl_sess_fetch_src_key = prev->srv.ssl_sess_fetch_src_key; conf->srv.ssl_sess_fetch_handler = prev->srv.ssl_sess_fetch_handler; + conf->srv.ssl_sess_fetch_chunkname = prev->srv.ssl_sess_fetch_chunkname; } if (conf->srv.ssl_sess_fetch_src.len) { @@ -1393,6 +1403,7 @@ ngx_http_lua_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) conf->header_filter_handler = prev->header_filter_handler; conf->header_filter_src_ref = prev->header_filter_src_ref; conf->header_filter_src_key = prev->header_filter_src_key; + conf->header_filter_chunkname = prev->header_filter_chunkname; } if (conf->body_filter_src.value.len == 0) { @@ -1400,6 +1411,7 @@ ngx_http_lua_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) conf->body_filter_handler = prev->body_filter_handler; conf->body_filter_src_ref = prev->body_filter_src_ref; conf->body_filter_src_key = prev->body_filter_src_key; + conf->body_filter_chunkname = prev->body_filter_chunkname; } #if (NGX_HTTP_SSL) diff --git a/src/ngx_http_lua_ssl_certby.c b/src/ngx_http_lua_ssl_certby.c index ce7f6483af..0499bfb355 100644 --- a/src/ngx_http_lua_ssl_certby.c +++ b/src/ngx_http_lua_ssl_certby.c @@ -70,7 +70,8 @@ ngx_http_lua_ssl_cert_handler_inline(ngx_http_request_t *r, lscf->srv.ssl_cert_src.len, &lscf->srv.ssl_cert_src_ref, lscf->srv.ssl_cert_src_key, - "=ssl_certificate_by_lua"); + (const char *) + lscf->srv.ssl_cert_chunkname); if (rc != NGX_OK) { return rc; } @@ -115,6 +116,8 @@ ngx_http_lua_ssl_cert_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, #else + size_t chunkname_len; + u_char *chunkname; u_char *cache_key = NULL; u_char *name; ngx_str_t *value; @@ -163,8 +166,15 @@ ngx_http_lua_ssl_cert_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, return NGX_CONF_ERROR; } + chunkname = ngx_http_lua_gen_chunk_name(cf, "ssl_certificate_by_lua", + sizeof("ssl_certificate_by_lua") - 1, &chunkname_len); + if (chunkname == NULL) { + return NGX_CONF_ERROR; + } + /* Don't eval nginx variables for inline lua code */ lscf->srv.ssl_cert_src = value[1]; + lscf->srv.ssl_cert_chunkname = chunkname; } lscf->srv.ssl_cert_src_key = cache_key; diff --git a/src/ngx_http_lua_ssl_client_helloby.c b/src/ngx_http_lua_ssl_client_helloby.c index a65b6e88f3..10500d89e3 100644 --- a/src/ngx_http_lua_ssl_client_helloby.c +++ b/src/ngx_http_lua_ssl_client_helloby.c @@ -61,7 +61,7 @@ ngx_http_lua_ssl_client_hello_handler_inline(ngx_http_request_t *r, lscf->srv.ssl_client_hello_src.len, &lscf->srv.ssl_client_hello_src_ref, lscf->srv.ssl_client_hello_src_key, - "=ssl_client_hello_by_lua"); + (const char *) lscf->srv.ssl_client_hello_chunkname); if (rc != NGX_OK) { return rc; } @@ -106,6 +106,8 @@ ngx_http_lua_ssl_client_hello_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, #else + size_t chunkname_len; + u_char *chunkname; u_char *cache_key = NULL; u_char *name; ngx_str_t *value; @@ -154,9 +156,16 @@ ngx_http_lua_ssl_client_hello_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, return NGX_CONF_ERROR; } + chunkname = ngx_http_lua_gen_chunk_name(cf, "ssl_client_hello_by_lua", + sizeof("ssl_client_helloo_by_lua")- 1, + &chunkname_len); + if (chunkname == NULL) { + return NGX_CONF_ERROR; + } + /* Don't eval nginx variables for inline lua code */ lscf->srv.ssl_client_hello_src = value[1]; - + lscf->srv.ssl_client_hello_chunkname = chunkname; } lscf->srv.ssl_client_hello_src_key = cache_key; diff --git a/src/ngx_http_lua_ssl_session_fetchby.c b/src/ngx_http_lua_ssl_session_fetchby.c index 6584e6ab58..66e9848550 100644 --- a/src/ngx_http_lua_ssl_session_fetchby.c +++ b/src/ngx_http_lua_ssl_session_fetchby.c @@ -66,7 +66,7 @@ ngx_http_lua_ssl_sess_fetch_handler_inline(ngx_http_request_t *r, lscf->srv.ssl_sess_fetch_src.len, &lscf->srv.ssl_sess_fetch_src_ref, lscf->srv.ssl_sess_fetch_src_key, - "=ssl_session_fetch_by_lua_block"); + (const char *) lscf->srv.ssl_sess_fetch_chunkname); if (rc != NGX_OK) { return rc; } @@ -102,6 +102,8 @@ char * ngx_http_lua_ssl_sess_fetch_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { + size_t chunkname_len; + u_char *chunkname; u_char *cache_key = NULL; u_char *name; ngx_str_t *value; @@ -153,8 +155,15 @@ ngx_http_lua_ssl_sess_fetch_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, return NGX_CONF_ERROR; } + chunkname = ngx_http_lua_gen_chunk_name(cf, "ssl_session_fetch_by_lua", + sizeof("ssl_session_fetch_by_lua") - 1, &chunkname_len); + if (chunkname == NULL) { + return NGX_CONF_ERROR; + } + /* Don't eval nginx variables for inline lua code */ lscf->srv.ssl_sess_fetch_src = value[1]; + lscf->srv.ssl_sess_fetch_chunkname = chunkname; } lscf->srv.ssl_sess_fetch_src_key = cache_key; diff --git a/src/ngx_http_lua_ssl_session_storeby.c b/src/ngx_http_lua_ssl_session_storeby.c index 0654d93715..b25cbcc2c4 100644 --- a/src/ngx_http_lua_ssl_session_storeby.c +++ b/src/ngx_http_lua_ssl_session_storeby.c @@ -64,7 +64,7 @@ ngx_http_lua_ssl_sess_store_handler_inline(ngx_http_request_t *r, lscf->srv.ssl_sess_store_src.len, &lscf->srv.ssl_sess_store_src_ref, lscf->srv.ssl_sess_store_src_key, - "=ssl_session_store_by_lua_block"); + (const char *) lscf->srv.ssl_sess_store_chunkname); if (rc != NGX_OK) { return rc; } @@ -100,6 +100,8 @@ char * ngx_http_lua_ssl_sess_store_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { + size_t chunkname_len; + u_char *chunkname; u_char *cache_key = NULL; u_char *name; ngx_str_t *value; @@ -151,8 +153,15 @@ ngx_http_lua_ssl_sess_store_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, return NGX_CONF_ERROR; } + chunkname = ngx_http_lua_gen_chunk_name(cf, "ssl_session_store_by_lua", + sizeof("ssl_session_store_by_lua") - 1, &chunkname_len); + if (chunkname == NULL) { + return NGX_CONF_ERROR; + } + /* Don't eval nginx variables for inline lua code */ lscf->srv.ssl_sess_store_src = value[1]; + lscf->srv.ssl_sess_store_chunkname = chunkname; } lscf->srv.ssl_sess_store_src_key = cache_key; diff --git a/t/001-set.t b/t/001-set.t index 62dec1a7f9..db18f0258c 100644 --- a/t/001-set.t +++ b/t/001-set.t @@ -573,7 +573,7 @@ GET /lua --- response_body_like: 500 Internal Server Error --- error_code: 500 --- error_log -failed to run set_by_lua*: set_by_lua:1: Bad +failed to run set_by_lua*: set_by_lua(nginx.conf:40):1: Bad diff --git a/t/002-content.t b/t/002-content.t index 703ba84a26..661c2e39e3 100644 --- a/t/002-content.t +++ b/t/002-content.t @@ -10,7 +10,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); #repeat_each(1); -plan tests => repeat_each() * (blocks() * 2 + 27); +plan tests => repeat_each() * (blocks() * 2 + 32); #no_diff(); #no_long_string(); @@ -917,3 +917,172 @@ GET /lua --- error_code: 500 --- error_log eval qr/failed to load inlined Lua code: content_by_lua\(nginx.conf:52\)/ + + + +=== TEST 46: syntax error in included file +--- config + location /foo { + content_by_lua_block { + 'for end'; + } + } + + location /bar { + content_by_lua_block { + 'for end'; + } + } + + include ../html/lua.conf; +--- user_files +>>> lua.conf + location /lua { + content_by_lua_block { + 'for end'; + } + } +--- request +GET /lua +--- response_body_like: 500 Internal Server Error +--- error_code: 500 +--- error_log +failed to load inlined Lua code: content_by_lua(../html/lua.conf:2):2: unexpected symbol near ''for end'' + + + +=== TEST 47: syntax error with very long filename +--- config + location /foo { + content_by_lua_block { + 'for end'; + } + } + + location /bar { + content_by_lua_block { + 'for end'; + } + } + + include ../html/1234567890123456789012345678901234.conf; +--- user_files +>>> 1234567890123456789012345678901234.conf + location /lua { + content_by_lua_block { + 'for end'; + } + } +--- request +GET /lua +--- response_body_like: 500 Internal Server Error +--- error_code: 500 +--- error_log +failed to load inlined Lua code: content_by_lua(...234567890123456789012345678901234.conf:2) + + + +=== TEST 48: syntax error in /tmp/lua.conf +--- config + location /foo { + content_by_lua_block { + 'for end'; + } + } + + location /bar { + content_by_lua_block { + 'for end'; + } + } + + include /tmp/lua.conf; +--- user_files +>>> /tmp/lua.conf + location /lua { + content_by_lua_block { + 'for end'; + } + } +--- request +GET /lua +--- response_body_like: 500 Internal Server Error +--- error_code: 500 +--- error_log +failed to load inlined Lua code: content_by_lua(/tmp/lua.conf:2) + + + +=== TEST 49: syntax error in /tmp/12345678901234567890123456789012345.conf +--- config + location /foo { + content_by_lua_block { + 'for end'; + } + } + + location /bar { + content_by_lua_block { + 'for end'; + } + } + + include /tmp/12345678901234567890123456789012345.conf; + +--- user_files +>>> /tmp/12345678901234567890123456789012345.conf + location /lua { + content_by_lua_block { + 'for end'; + } + } +--- request +GET /lua +--- response_body_like: 500 Internal Server Error +--- error_code: 500 +--- error_log +failed to load inlined Lua code: content_by_lua(...345678901234567890123456789012345.conf:2) + + + +=== TEST 50: the error line number greater than 9 +--- config + location /foo { + content_by_lua_block { + 'for end'; + } + } + + location /bar { + content_by_lua_block { + 'for end'; + } + } + + include /tmp/12345678901234567890123456789012345.conf; + +--- user_files +>>> /tmp/12345678901234567890123456789012345.conf + location /lua { + + + + + + + + + + + + + content_by_lua_block { + 'for end'; + } + } +--- request +GET /lua +--- response_body_like: 500 Internal Server Error +--- error_code: 500 +--- error_log +failed to load inlined Lua code: content_by_lua(...45678901234567890123456789012345.conf:14) diff --git a/t/009-log.t b/t/009-log.t index c4597698ef..4446c71277 100644 --- a/t/009-log.t +++ b/t/009-log.t @@ -243,7 +243,7 @@ GET /log --- response_body 32 --- error_log eval -qr/\[error\] \S+: \S+ \[lua\] set_by_lua:2: HELLO,/ +qr/\[error\] \S+: \S+ \[lua\] set_by_lua\(nginx.conf:43\):2: HELLO,/ @@ -261,7 +261,7 @@ GET /log --- response_body 32 --- error_log eval -qr/\[error\] \S+: \S+ \[lua\] set_by_lua:2: truefalsenil,/ +qr/\[error\] \S+: \S+ \[lua\] set_by_lua\(nginx.conf:43\):2: truefalsenil,/ @@ -368,7 +368,7 @@ GET /log --- response_headers foo: 32 --- error_log eval -qr/\[notice\] .*? \[lua\] header_filter_by_lua:2: hello world/ +qr/\[notice\] .*? \[lua\] header_filter_by_lua\(nginx.conf:43\):2: hello world/ --- response_body hi @@ -390,7 +390,7 @@ foo: 32 --- response_body hi --- error_log eval -qr/\[error\] .*? \[lua\] header_filter_by_lua:2: howdy, lua!/ +qr/\[error\] .*? \[lua\] header_filter_by_lua\(nginx.conf:43\):2: howdy, lua!/ diff --git a/t/025-codecache.t b/t/025-codecache.t index cf62ff0182..ebe4f61b7b 100644 --- a/t/025-codecache.t +++ b/t/025-codecache.t @@ -1862,17 +1862,17 @@ code cache hit (key='log_by_lua_nhli_8a9441d0a30531ba8bb34ab11c55cfc3', ref=12) "] --- error_log eval [ -qr/balancer_by_lua:\d+: hello/, -qr/ssl_session_fetch_by_lua_block:\d+: hello/, -qr/ssl_certificate_by_lua:\d+: hello/, -qr/ssl_session_store_by_lua_block:\d+: hello/, -qr/set_by_lua:\d+: hello/, +qr/balancer_by_lua\(nginx\.conf:\d+\):\d+: hello/, +qr/ssl_session_fetch_by_lua\(nginx\.conf:\d+\):\d+: hello/, +qr/ssl_certificate_by_lua\(nginx\.conf:\d+\):\d+: hello/, +qr/ssl_session_store_by_lua\(nginx\.conf:\d+\):\d+: hello/, +qr/set_by_lua\(nginx\.conf:\d+\):\d+: hello/, qr/rewrite_by_lua\(nginx\.conf:\d+\):\d+: hello/, qr/access_by_lua\(nginx\.conf:\d+\):\d+: hello/, qr/content_by_lua\(nginx\.conf:\d+\):\d+: hello/, -qr/header_filter_by_lua:\d+: hello/, -qr/body_filter_by_lua:\d+: hello/, -qr/log_by_lua\(nginx\.conf:\d+\):\d+: hello/, +qr/header_filter_by_lua\(nginx\.conf:\d+\):\d+: hello/, +qr/body_filter_by_lua\(nginx\.conf:\d+\):\d+: hello/, +qr/log_by_lua\(nginx.conf:\d+\):\d+: hello/, ] --- log_level: debug --- no_error_log diff --git a/t/041-header-filter.t b/t/041-header-filter.t index 0adc699c6c..cfc6f53234 100644 --- a/t/041-header-filter.t +++ b/t/041-header-filter.t @@ -462,7 +462,7 @@ GET /lua GET /lua --- ignore_response --- error_log -failed to run header_filter_by_lua*: header_filter_by_lua:2: Something bad +failed to run header_filter_by_lua*: header_filter_by_lua(nginx.conf:47):2: Something bad --- no_error_log [alert] @@ -799,3 +799,53 @@ GET /t --- error_code: 302 --- no_error_log [error] + + + +=== TEST 42: syntax error in header_filter_by_lua_block +--- config + location /lua { + + header_filter_by_lua_block { + 'for end'; + } + content_by_lua_block { + ngx.say("Hello world") + } + } +--- request +GET /lua +--- ignore_response +--- error_log +failed to load inlined Lua code: header_filter_by_lua(nginx.conf:41):2: unexpected symbol near ''for end'' +--- no_error_log +no_such_error + + + +=== TEST 43: syntax error in second content_by_lua_block +--- config + location /foo { + header_filter_by_lua_block { + 'for end'; + } + content_by_lua_block { + ngx.say("Hello world") + } + } + + location /lua { + header_filter_by_lua_block { + 'for end'; + } + content_by_lua_block { + ngx.say("Hello world") + } + } +--- request +GET /lua +--- ignore_response +--- error_log +failed to load inlined Lua code: header_filter_by_lua(nginx.conf:49):2: unexpected symbol near ''for end'' +--- no_error_log +no_such_error diff --git a/t/082-body-filter.t b/t/082-body-filter.t index 5f765fa439..a69c78fa70 100644 --- a/t/082-body-filter.t +++ b/t/082-body-filter.t @@ -317,7 +317,7 @@ hiya globe GET /t --- ignore_response --- error_log -failed to run body_filter_by_lua*: body_filter_by_lua:4: something bad happened! +failed to run body_filter_by_lua*: body_filter_by_lua(nginx.conf:49):4: something bad happened! @@ -838,3 +838,55 @@ GET /lua --- ignore_response --- error_log API disabled in the context of body_filter_by_lua* + + + +=== TEST 27: syntax error in body_filter_by_lua_block +--- config + location /lua { + + body_filter_by_lua_block { + 'for end'; + } + content_by_lua_block { + ngx.say("Hello world") + } + } +--- request +GET /lua +--- ignore_response +--- error_log +failed to load inlined Lua code: body_filter_by_lua(nginx.conf:41):2: unexpected symbol near ''for end'' +--- no_error_log +no_such_error1 +no_such_error2 + + + +=== TEST 28: syntax error in second body_by_lua_block +--- config + location /foo { + body_filter_by_lua_block { + 'for end'; + } + content_by_lua_block { + ngx.say("Hello world") + } + } + + location /lua { + body_filter_by_lua_block { + 'for end'; + } + content_by_lua_block { + ngx.say("Hello world") + } + } +--- request +GET /lua +--- ignore_response +--- error_log +failed to load inlined Lua code: body_filter_by_lua(nginx.conf:49):2: unexpected symbol near ''for end'' +--- no_error_log +no_such_error1 +no_such_error2 diff --git a/t/086-init-by.t b/t/086-init-by.t index bea34a461a..8d9a8596b4 100644 --- a/t/086-init-by.t +++ b/t/086-init-by.t @@ -321,3 +321,47 @@ INIT 2: foo = 3 failed to init --- error_log [error] + + + +=== TEST 13: syntax error in init_by_lua_block +--- http_config + init_by_lua_block { + ngx.log(ngx.debug, "pass") + error("failed to init" + ngx.log(ngx.debug, "unreachable") + } +--- config + location /lua { + content_by_lua_block { + ngx.say("hello world") + } + } +--- must_die +--- error_log +=init_by_lua(nginx.conf:25) error: init_by_lua:4: ')' expected (to close '(' at line 3) near 'ngx' +--- no_error_log +no_such_error_log + + + +=== TEST 14: syntax error in init_by_lua_file +--- http_config + init_by_lua_file html/init.lua; +--- config + location /lua { + content_by_lua_block { + ngx.say("hello world") + } + } +--- user_files +>>> init.lua + ngx.log(ngx.debug, "pass") + error("failed to init" + ngx.log(ngx.debug, "unreachable") + +--- must_die +--- error_log eval +qr|init_by_lua_file error: .*lua-nginx-module/t/servroot/html/init.lua:3: '\)' expected \(to close '\(' at line 2\) near 'ngx'| +--- no_error_log +no_such_error_log diff --git a/t/091-coroutine.t b/t/091-coroutine.t index b9b3d9d38d..74b7c682fe 100644 --- a/t/091-coroutine.t +++ b/t/091-coroutine.t @@ -1691,7 +1691,7 @@ GET /t --- error_log eval [ qr/\[notice\] .*? in wrapped coroutine/, - qr/\[error\] .*? failed to run header_filter_by_lua\*: header_filter_by_lua:\d+: header_filter_by_lua:\d+: something went wrong/, + qr/\[error\] .*? failed to run header_filter_by_lua\*: header_filter_by_lua\(nginx.conf:\d+\):\d+: header_filter_by_lua\(nginx.conf:\d+\):\d+: something went wrong/, "stack traceback:", "in function 'co'" ] @@ -1713,9 +1713,9 @@ GET /t --- config --- must_die ---- grep_error_log eval: qr/init_by_lua error: .*? something went wrong/ +--- grep_error_log eval: qr/init_by_lua\(nginx.conf:25\) error: .*? something went wrong/ --- grep_error_log_out -init_by_lua error: init_by_lua:7: init_by_lua:4: something went wrong +init_by_lua(nginx.conf:25) error: init_by_lua:7: init_by_lua:4: something went wrong diff --git a/t/124-init-worker.t b/t/124-init-worker.t index b7e17a07f1..d10ee17285 100644 --- a/t/124-init-worker.t +++ b/t/124-init-worker.t @@ -975,3 +975,53 @@ qr/lua close the global Lua VM ([0-9A-F]+)$/, --- no_error_log [error] start privileged agent process + + + +=== TEST 25: syntax error in init_worker_by_lua_block +--- http_config + init_worker_by_lua_block { + ngx.log(ngx.debug, "pass") + error("failed to init" + ngx.log(ngx.debug, "unreachable") + } +--- config + location /t { + content_by_lua_block { + ngx.say("hello world") + } + } +--- request + GET /t +--- response_body +hello world +--- error_log +=init_worker_by_lua(nginx.conf:25) error: init_worker_by_lua:4: ')' expected (to close '(' at line 3) near 'ngx' +--- no_error_log +no_such_error_log + + + +=== TEST 26: syntax error in init_worker_by_lua_file +--- http_config + init_worker_by_lua_file html/init.lua; +--- config + location /t { + content_by_lua_block { + ngx.say("hello world") + } + } +--- user_files +>>> init.lua + ngx.log(ngx.debug, "pass") + error("failed to init" + ngx.log(ngx.debug, "unreachable") + +--- request + GET /t +--- response_body +hello world +--- error_log eval +qr|init_worker_by_lua_file error: .*lua-nginx-module/t/servroot/html/init.lua:3: '\)' expected \(to close '\(' at line 2\) near 'ngx'| +--- no_error_log +no_such_error_log diff --git a/t/138-balancer.t b/t/138-balancer.t index dca1784673..2894157e0e 100644 --- a/t/138-balancer.t +++ b/t/138-balancer.t @@ -38,7 +38,7 @@ __DATA__ --- error_code: 502 --- error_log eval [ -'[lua] balancer_by_lua:2: hello from balancer by lua! while connecting to upstream,', +'[lua] balancer_by_lua(nginx.conf:27):2: hello from balancer by lua! while connecting to upstream,', qr{\[crit\] .*? connect\(\) to 0\.0\.0\.1:80 failed .*?, upstream: "http://0\.0\.0\.1:80/t"}, ] --- no_error_log @@ -64,7 +64,7 @@ qr{\[crit\] .*? connect\(\) to 0\.0\.0\.1:80 failed .*?, upstream: "http://0\.0\ --- response_body_like: 403 Forbidden --- error_code: 403 --- error_log -[lua] balancer_by_lua:2: hello from balancer by lua! while connecting to upstream, +[lua] balancer_by_lua(nginx.conf:27):2: hello from balancer by lua! while connecting to upstream, --- no_error_log eval [ '[warn]', @@ -92,7 +92,7 @@ qr{\[crit\] .*? connect\(\) to 0\.0\.0\.1:80 failed .*?, upstream: "http://0\.0\ --- error_code: 502 --- error_log eval [ -'[lua] balancer_by_lua:2: hello from balancer by lua! while connecting to upstream,', +'[lua] balancer_by_lua(nginx.conf:27):2: hello from balancer by lua! while connecting to upstream,', qr{\[crit\] .*? connect\(\) to 0\.0\.0\.1:80 failed .*?, upstream: "http://0\.0\.0\.1:80/t"}, ] --- no_error_log @@ -257,7 +257,7 @@ qr{\[crit\] .*? connect\(\) to 0\.0\.0\.1:80 failed .*?, upstream: "http://0\.0\ --- response_body_like: 500 Internal Server Error --- error_code: 500 --- error_log eval -qr/\[error\] .*? failed to run balancer_by_lua\*: balancer_by_lua:2: API disabled in the context of balancer_by_lua\*/ +qr/\[error\] .*? failed to run balancer_by_lua\*: balancer_by_lua\(nginx\.conf:27\):2: API disabled in the context of balancer_by_lua\*/ @@ -278,7 +278,7 @@ qr/\[error\] .*? failed to run balancer_by_lua\*: balancer_by_lua:2: API disable --- response_body_like: 500 Internal Server Error --- error_code: 500 --- error_log eval -qr/\[error\] .*? failed to run balancer_by_lua\*: balancer_by_lua:2: API disabled in the context of balancer_by_lua\*/ +qr/\[error\] .*? failed to run balancer_by_lua\*: balancer_by_lua\(nginx\.conf:27\):2: API disabled in the context of balancer_by_lua\*/ @@ -427,7 +427,7 @@ ctx counter: nil --- error_code: 502 --- error_log eval [ -'[lua] balancer_by_lua:2: hello from balancer by lua! while connecting to upstream,', +'[lua] balancer_by_lua(nginx.conf:27):2: hello from balancer by lua! while connecting to upstream,', qr{\[crit\] .*? connect\(\) to 0\.0\.0\.1:80 failed .*?, upstream: "http://0\.0\.0\.1:80/t"}, ] --- no_error_log @@ -567,3 +567,26 @@ connect() failed (111: Connection refused) while connecting to upstream --- no_error_log upstream sent more data than specified in "Content-Length" header while reading upstream [alert] + + + +=== TEST 18: error in balancer_by_llua_block +--- http_config + upstream backend { + server 0.0.0.1; + balancer_by_lua_block { + ngx.say("hello" + } + } +--- config + location = /t { + proxy_pass http://backend; + } +--- request + GET /t +--- response_body_like: 500 Internal Server Error +--- error_code: 500 +--- error_log eval + "failed to load inlined Lua code: balancer_by_lua(nginx.conf:27):3: ')' expected (to close '(' at line 2) near ''", +--- no_error_log +[warn] diff --git a/t/139-ssl-cert-by.t b/t/139-ssl-cert-by.t index d7e20bafea..38296352f5 100644 --- a/t/139-ssl-cert-by.t +++ b/t/139-ssl-cert-by.t @@ -117,18 +117,18 @@ lua ssl server name: "test.com" --- no_error_log [error] [alert] ---- grep_error_log eval: qr/ssl_certificate_by_lua:.*?,|\bssl cert: connection reusable: \d+|\breusable connection: \d+/ +--- grep_error_log eval: qr/ssl_certificate_by_lua\(nginx.conf:\d+\):.*?,|\bssl cert: connection reusable: \d+|\breusable connection: \d+/ --- grep_error_log_out eval # Since nginx version 1.17.9, nginx call ngx_reusable_connection(c, 0) # before call ssl callback function $Test::Nginx::Util::NginxVersion >= 1.017009 ? qr/reusable connection: 0 ssl cert: connection reusable: 0 -ssl_certificate_by_lua:1: ssl cert by lua is running!,/ +ssl_certificate_by_lua\(nginx.conf:28\):1: ssl cert by lua is running!,/ : qr /reusable connection: 1 ssl cert: connection reusable: 1 reusable connection: 0 -ssl_certificate_by_lua:1: ssl cert by lua is running!,/ +ssl_certificate_by_lua\(nginx.conf:28\):1: ssl cert by lua is running!,/ @@ -789,7 +789,7 @@ failed to do SSL handshake: handshake failed --- error_log eval [ -'runtime error: ssl_certificate_by_lua:2: bad bad bad', +'runtime error: ssl_certificate_by_lua(nginx.conf:28):2: bad bad bad', 'lua_certificate_by_lua: handler return value: 500, cert cb exit code: 0', qr/\[info\] .*? SSL_do_handshake\(\) failed .*?cert cb error/, qr/context: ssl_certificate_by_lua\*, client: \d+\.\d+\.\d+\.\d+, server: \d+\.\d+\.\d+\.\d+:\d+/, @@ -861,7 +861,7 @@ failed to do SSL handshake: handshake failed --- error_log eval [ -'runtime error: ssl_certificate_by_lua:3: bad bad bad', +'runtime error: ssl_certificate_by_lua(nginx.conf:28):3: bad bad bad', 'lua_certificate_by_lua: cert cb exit code: 0', qr/\[info\] .*? SSL_do_handshake\(\) failed .*?cert cb error/, ] @@ -1050,7 +1050,7 @@ failed to do SSL handshake: handshake failed --- error_log eval [ 'lua ssl server name: "test.com"', -'ssl_certificate_by_lua:1: API disabled in the context of ssl_certificate_by_lua*', +'ssl_certificate_by_lua(nginx.conf:28):1: API disabled in the context of ssl_certificate_by_lua*', qr/\[info\] .*?cert cb error/, ] @@ -1481,7 +1481,7 @@ close: 1 nil --- error_log lua ssl server name: "test.com" -ssl_certificate_by_lua:1: ssl cert by lua is running! +ssl_certificate_by_lua(nginx.conf:25):1: ssl cert by lua is running! --- no_error_log [error] @@ -1681,7 +1681,7 @@ close: 1 nil --- error_log eval [ -'ssl_certificate_by_lua:1: ssl cert by lua is running!', +'ssl_certificate_by_lua(nginx.conf:29):1: ssl cert by lua is running!', 'lua ssl server name: "test.com"', ] --- no_error_log diff --git a/t/142-ssl-session-store.t b/t/142-ssl-session-store.t index 14e90574b0..6769a336bc 100644 --- a/t/142-ssl-session-store.t +++ b/t/142-ssl-session-store.t @@ -86,11 +86,11 @@ lua ssl server name: "test.com" --- no_error_log [error] [alert] ---- grep_error_log eval: qr/ssl_session_store_by_lua_block:.*?,|\bssl session store: connection reusable: \d+|\breusable connection: \d+/ +--- grep_error_log eval: qr/ssl_session_store_by_lua\(nginx.conf:\d+\):.*?,|\bssl session store: connection reusable: \d+|\breusable connection: \d+/ --- grep_error_log_out eval qr/^reusable connection: 0 ssl session store: connection reusable: 0 -ssl_session_store_by_lua_block:1: ssl session store by lua is running!, +ssl_session_store_by_lua\(nginx\.conf:25\):1: ssl session store by lua is running!, /m, @@ -536,7 +536,7 @@ ssl handshake: userdata close: 1 nil --- error_log -failed to run session_store_by_lua*: ssl_session_store_by_lua_block:2: bad bad bad +failed to run session_store_by_lua*: ssl_session_store_by_lua(nginx.conf:25):2: bad bad bad --- no_error_log should never reached here @@ -678,7 +678,7 @@ close: 1 nil [ 'lua ssl server name: "test.com"', qr/elapsed in ssl cert by lua: 0.(?:09|1[01])\d+,/, -'ssl_session_store_by_lua_block:1: ssl store session by lua is running!', +'ssl_session_store_by_lua(nginx.conf:25):1: ssl store session by lua is running!', ] --- no_error_log @@ -896,7 +896,7 @@ close: 1 nil --- error_log lua ssl server name: "test.com" -ssl_session_store_by_lua_block:1: ssl session store by lua is running! +ssl_session_store_by_lua(nginx.conf:25):1: ssl session store by lua is running! --- no_error_log [error] diff --git a/t/143-ssl-session-fetch.t b/t/143-ssl-session-fetch.t index 084e7d596c..0e90c23665 100644 --- a/t/143-ssl-session-fetch.t +++ b/t/143-ssl-session-fetch.t @@ -83,7 +83,7 @@ connected: 1 ssl handshake: userdata close: 1 nil ---- grep_error_log eval: qr/ssl_session_fetch_by_lua_block:.*?,|\bssl session fetch: connection reusable: \d+|\breusable connection: \d+/ +--- grep_error_log eval: qr/ssl_session_fetch_by_lua\(nginx\.conf:\d+\):.*?,|\bssl session fetch: connection reusable: \d+|\breusable connection: \d+/ --- grep_error_log_out eval # Since nginx version 1.17.9, nginx call ngx_reusable_connection(c, 0) @@ -93,11 +93,11 @@ $Test::Nginx::Util::NginxVersion >= 1.017009 ? qr/\A(?:reusable connection: [01]\n)+\z/s, qr/^reusable connection: 0 ssl session fetch: connection reusable: 0 -ssl_session_fetch_by_lua_block:1: ssl fetch sess by lua is running!, +ssl_session_fetch_by_lua\(nginx\.conf:25\):1: ssl fetch sess by lua is running!, /m, qr/^reusable connection: 0 ssl session fetch: connection reusable: 0 -ssl_session_fetch_by_lua_block:1: ssl fetch sess by lua is running!, +ssl_session_fetch_by_lua\(nginx\.conf:25\):1: ssl fetch sess by lua is running!, /m, ] : @@ -106,12 +106,12 @@ qr/\A(?:reusable connection: [01]\n)+\z/s, qr/^reusable connection: 1 ssl session fetch: connection reusable: 1 reusable connection: 0 -ssl_session_fetch_by_lua_block:1: ssl fetch sess by lua is running!, +ssl_session_fetch_by_lua\(nginx\.conf:25\):1: ssl fetch sess by lua is running!, /m, qr/^reusable connection: 1 ssl session fetch: connection reusable: 1 reusable connection: 0 -ssl_session_fetch_by_lua_block:1: ssl fetch sess by lua is running!, +ssl_session_fetch_by_lua\(nginx\.conf:25\):1: ssl fetch sess by lua is running!, /m, ] --- no_error_log @@ -694,14 +694,14 @@ ssl handshake: userdata close: 1 nil --- grep_error_log eval -qr/ssl_session_fetch_by_lua_block:2: bad bad bad/s +qr/ssl_session_fetch_by_lua\(nginx.conf:\d+\):2: bad bad bad/s --- grep_error_log_out eval [ '', -'ssl_session_fetch_by_lua_block:2: bad bad bad +'ssl_session_fetch_by_lua(nginx.conf:25):2: bad bad bad ', -'ssl_session_fetch_by_lua_block:2: bad bad bad +'ssl_session_fetch_by_lua(nginx.conf:25):2: bad bad bad ', ] @@ -777,15 +777,15 @@ ssl handshake: userdata close: 1 nil --- grep_error_log eval -qr/ssl_session_fetch_by_lua_block:3: bad bad bad|ssl_session_fetch_by_lua\*: sess get cb exit code: 0/s +qr/ssl_session_fetch_by_lua\(nginx.conf:\d+\):3: bad bad bad|ssl_session_fetch_by_lua\*: sess get cb exit code: 0/s --- grep_error_log_out eval [ '', -'ssl_session_fetch_by_lua_block:3: bad bad bad +'ssl_session_fetch_by_lua(nginx.conf:25):3: bad bad bad ssl_session_fetch_by_lua*: sess get cb exit code: 0 ', -'ssl_session_fetch_by_lua_block:3: bad bad bad +'ssl_session_fetch_by_lua(nginx.conf:25):3: bad bad bad ssl_session_fetch_by_lua*: sess get cb exit code: 0 ', @@ -1113,14 +1113,14 @@ ssl handshake: userdata close: 1 nil --- grep_error_log eval -qr/ssl_session_fetch_by_lua_block:1: ssl fetch sess by lua is running!/s +qr/ssl_session_fetch_by_lua\(nginx.conf:\d+\):1: ssl fetch sess by lua is running!/s --- grep_error_log_out eval [ '', -'ssl_session_fetch_by_lua_block:1: ssl fetch sess by lua is running! +'ssl_session_fetch_by_lua(nginx.conf:25):1: ssl fetch sess by lua is running! ', -'ssl_session_fetch_by_lua_block:1: ssl fetch sess by lua is running! +'ssl_session_fetch_by_lua(nginx.conf:25):1: ssl fetch sess by lua is running! ', ] @@ -1348,7 +1348,7 @@ GET /t connected: 1 ssl handshake: userdata close: 1 nil ---- grep_error_log eval: qr/ssl_session_fetch_by_lua_block:.*?,|\bssl session fetch: connection reusable: \d+|\breusable connection: \d+/ +--- grep_error_log eval: qr/ssl_session_fetch_by_lua\(nginx\.conf:\d+\):.*?,|\bssl session fetch: connection reusable: \d+|\breusable connection: \d+/ --- grep_error_log_out eval # Since nginx version 1.17.9, nginx call ngx_reusable_connection(c, 0) # before call ssl callback function @@ -1357,11 +1357,11 @@ $Test::Nginx::Util::NginxVersion >= 1.017009 ? qr/\A(?:reusable connection: [01]\n)+\z/s, qr/^reusable connection: 0 ssl session fetch: connection reusable: 0 -ssl_session_fetch_by_lua_block:1: ssl_session_fetch_by_lua\* is running!, +ssl_session_fetch_by_lua\(nginx\.conf:\d+\):1: ssl_session_fetch_by_lua\* is running!, /m, qr/^reusable connection: 0 ssl session fetch: connection reusable: 0 -ssl_session_fetch_by_lua_block:1: ssl_session_fetch_by_lua\* is running!, +ssl_session_fetch_by_lua\(nginx\.conf:\d+\):1: ssl_session_fetch_by_lua\* is running!, /m, ] : @@ -1370,12 +1370,12 @@ qr/\A(?:reusable connection: [01]\n)+\z/s, qr/^reusable connection: 1 ssl session fetch: connection reusable: 1 reusable connection: 0 -ssl_session_fetch_by_lua_block:1: ssl_session_fetch_by_lua\* is running!, +ssl_session_fetch_by_lua\(nginx\.conf:\d+\):1: ssl_session_fetch_by_lua\* is running!, /m, qr/^reusable connection: 1 ssl session fetch: connection reusable: 1 reusable connection: 0 -ssl_session_fetch_by_lua_block:1: ssl_session_fetch_by_lua\* is running!, +ssl_session_fetch_by_lua\(nginx\.conf:\d+\):1: ssl_session_fetch_by_lua\* is running!, /m, ] --- no_error_log diff --git a/t/158-global-var.t b/t/158-global-var.t index def3b7418f..3f5db60fa2 100644 --- a/t/158-global-var.t +++ b/t/158-global-var.t @@ -60,10 +60,10 @@ __DATA__ --- response_body_like chomp \A[12]\n\z --- grep_error_log eval -qr/(old foo: \d+|\[\w+\].*?writing a global Lua variable \('[^'\s]+'\)|set_by_lua:\d+: in main chunk, )/ +qr/(old foo: \d+|\[\w+\].*?writing a global Lua variable \('[^'\s]+'\)|set_by_lua\(nginx.conf:\d+\):\d+: in main chunk, )/ --- grep_error_log_out eval [qr/\A\[warn\] .*?writing a global Lua variable \('foo'\) -set_by_lua:3: in main chunk, \n\z/, "old foo: 1\n"] +set_by_lua\(nginx.conf:40\):3: in main chunk, \n\z/, "old foo: 1\n"] @@ -154,10 +154,10 @@ content_by_lua\(nginx\.conf:\d+\):\d+: in main chunk, \n\z/, "old foo: 1\n"] --- response_body_like chomp \A(?:nil|1)\n\z --- grep_error_log eval -qr/(old foo: \d+|\[\w+\].*?writing a global Lua variable \('[^'\s]+'\)|\w+_by_lua:\d+: in main chunk, )/ +qr/(old foo: \d+|\[\w+\].*?writing a global Lua variable \('[^'\s]+'\)|\w+_by_lua\(nginx\.conf:\d+\):\d+: in main chunk, )/ --- grep_error_log_out eval [qr/\A\[warn\] .*?writing a global Lua variable \('foo'\) -header_filter_by_lua:3: in main chunk, \n\z/, "old foo: 1\n"] +header_filter_by_lua\(nginx.conf:43\):3: in main chunk, \n\z/, "old foo: 1\n"] @@ -179,10 +179,10 @@ header_filter_by_lua:3: in main chunk, \n\z/, "old foo: 1\n"] --- response_body_like chomp \A(?:nil|2)\n\z --- grep_error_log eval -qr/(old foo: \d+|\[\w+\].*?writing a global Lua variable \('[^'\s]+'\)|\w+_by_lua:\d+: in main chunk,)/ +qr/(old foo: \d+|\[\w+\].*?writing a global Lua variable \('[^'\s]+'\)|\w+_by_lua\(nginx\.conf:\d+\):\d+: in main chunk,)/ --- grep_error_log_out eval [qr/\[warn\] .*?writing a global Lua variable \('foo'\) -body_filter_by_lua:3: in main chunk, +body_filter_by_lua\(nginx.conf:43\):3: in main chunk, old foo: 1\n\z/, "old foo: 2\nold foo: 3\n"] @@ -297,10 +297,10 @@ log_by_lua\(nginx\.conf:\d+\):\d+: in main chunk\n\z/, "old foo: 1\n"] --- response_body_like chomp \A[12]done\n\z --- grep_error_log eval -qr/(old foo: \d+|\[\w+\].*?writing a global Lua variable \('[^'\s]+'\)|\w+_by_lua:\d+: in main chunk)/ +qr/(old foo: \d+|\[\w+\].*?writing a global Lua variable \('[^'\s]+'\)|\w+_by_lua\(nginx.conf:\d+\):\d+: in main chunk)/ --- grep_error_log_out eval [qr/\A\[warn\] .*?writing a global Lua variable \('foo'\) -ssl_certificate_by_lua:3: in main chunk\n\z/, "old foo: 1\n"] +ssl_certificate_by_lua\(nginx.conf:28\):3: in main chunk\n\z/, "old foo: 1\n"] diff --git a/t/162-exit-worker.t b/t/162-exit-worker.t index 3138617615..fcae47a4ee 100644 --- a/t/162-exit-worker.t +++ b/t/162-exit-worker.t @@ -6,7 +6,7 @@ master_on(); repeat_each(2); # NB: the shutdown_error_log block is independent from repeat times -plan tests => repeat_each() * (blocks() * 2 + 1) + 13; +plan tests => repeat_each() * (blocks() * 2 + 1) + 15; #log_level("warn"); no_long_string(); @@ -194,3 +194,49 @@ qr/cache loader process \d+ exited/, qr/cache manager process \d+ exited/, qr/hello from exit worker by lua, process type: worker/, ] + + + +=== TEST 8: syntax error in exit_worker_by_lua_block +--- http_config + exit_worker_by_lua_block { + ngx.log(ngx.debug, "pass") + error("failed to init" + ngx.log(ngx.debug, "unreachable") + } +--- config + location /t { + content_by_lua_block { + ngx.say("hello world") + } + } +--- request + GET /t +--- response_body +hello world +--- shutdown_error_log +=exit_worker_by_lua(nginx.conf:25) error: exit_worker_by_lua:4: ')' expected (to close '(' at line 3) near 'ngx' + + + +=== TEST 9: syntax error in exit_worker_by_lua_file +--- http_config + exit_worker_by_lua_file html/exit.lua; +--- config + location /t { + content_by_lua_block { + ngx.say("hello world") + } + } +--- user_files +>>> exit.lua + ngx.log(ngx.debug, "pass") + error("failed to init" + ngx.log(ngx.debug, "unreachable") + +--- request + GET /t +--- response_body +hello world +--- shutdown_error_log eval +qr|exit_worker_by_lua_file error: .*lua-nginx-module/t/servroot/html/exit.lua:3: '\)' expected \(to close '\(' at line 2\) near 'ngx'| From 15b693b3381f6115fa8a7870e6cd313c608b6cdb Mon Sep 17 00:00:00 2001 From: lijunlong Date: Mon, 14 Feb 2022 17:48:42 +0800 Subject: [PATCH 007/254] bugfix: passing the wrong chunkname argument to luaL_loadbuffer. (#2010) The total length of the chunkname is 60. The format is "=tag(file:line)". So the space left for the tag, file and line is only 56 chars. --- src/ngx_http_lua_directive.c | 17 ++++++++++------- src/ngx_http_lua_exitworkerby.c | 12 ++++++------ src/ngx_http_lua_initby.c | 12 ++++++------ src/ngx_http_lua_initworkerby.c | 12 ++++++------ t/041-header-filter.t | 24 ++++++++++++++++++++++++ t/086-init-by.t | 2 +- t/089-phase.t | 2 +- t/091-coroutine.t | 4 ++-- t/124-init-worker.t | 2 +- t/162-exit-worker.t | 2 +- 10 files changed, 58 insertions(+), 31 deletions(-) diff --git a/src/ngx_http_lua_directive.c b/src/ngx_http_lua_directive.c index dda447fb7e..c8317edf3d 100644 --- a/src/ngx_http_lua_directive.c +++ b/src/ngx_http_lua_directive.c @@ -32,7 +32,10 @@ #include "ngx_http_lua_log.h" -#define LJ_CHUNKNAME_MAX_LEN 42 +/* the max length is 60, after deducting the fixed four characters "=(:)" + * only 56 left. + */ +#define LJ_CHUNKNAME_MAX_LEN 56 typedef struct ngx_http_lua_block_parser_ctx_s @@ -1369,7 +1372,7 @@ ngx_http_lua_gen_chunk_name(ngx_conf_t *cf, const char *tag, size_t tag_len, ngx_str_t *filename; u_char *filename_end; const char *pre_str = ""; - ngx_uint_t start_line_len; + ngx_uint_t reserve_len; ngx_http_lua_main_conf_t *lmcf; @@ -1385,7 +1388,7 @@ ngx_http_lua_gen_chunk_name(ngx_conf_t *cf, const char *tag, size_t tag_len, start_line = lmcf->directive_line > 0 ? lmcf->directive_line : cf->conf_file->line; p = ngx_snprintf(out, len, "%d", start_line); - start_line_len = p - out; + reserve_len = tag_len + p - out; filename = &cf->conf_file->file.name; filename_end = filename->data + filename->len; @@ -1407,8 +1410,8 @@ ngx_http_lua_gen_chunk_name(ngx_conf_t *cf, const char *tag, size_t tag_len, filename->data, conf_prefix->len) == 0) { /* files in conf_prefix directory, use the relative path */ - if (filename_end - p + start_line_len > LJ_CHUNKNAME_MAX_LEN) { - p = filename_end - LJ_CHUNKNAME_MAX_LEN + start_line_len + 3; + if (filename_end - p + reserve_len > LJ_CHUNKNAME_MAX_LEN) { + p = filename_end - LJ_CHUNKNAME_MAX_LEN + reserve_len + 3; pre_str = "..."; } @@ -1418,11 +1421,11 @@ ngx_http_lua_gen_chunk_name(ngx_conf_t *cf, const char *tag, size_t tag_len, p = filename->data; - if (filename->len + start_line_len <= LJ_CHUNKNAME_MAX_LEN) { + if (filename->len + reserve_len <= LJ_CHUNKNAME_MAX_LEN) { goto found; } - p = filename_end - LJ_CHUNKNAME_MAX_LEN + start_line_len + 3; + p = filename_end - LJ_CHUNKNAME_MAX_LEN + reserve_len + 3; pre_str = "..."; found: diff --git a/src/ngx_http_lua_exitworkerby.c b/src/ngx_http_lua_exitworkerby.c index 65edc04e63..e8f65110ae 100644 --- a/src/ngx_http_lua_exitworkerby.c +++ b/src/ngx_http_lua_exitworkerby.c @@ -97,18 +97,18 @@ ngx_http_lua_exit_worker_by_inline(ngx_log_t *log, int status; const char *chunkname; - status = luaL_loadbuffer(L, (char *) lmcf->exit_worker_src.data, - lmcf->exit_worker_src.len, "=exit_worker_by_lua") - || ngx_http_lua_do_call(log, L); - if (lmcf->exit_worker_chunkname == NULL) { - chunkname = "exit_worker_by_lua"; + chunkname = "=exit_worker_by_lua"; } else { chunkname = (const char *) lmcf->exit_worker_chunkname; } - return ngx_http_lua_report(log, L, status, chunkname); + status = luaL_loadbuffer(L, (char *) lmcf->exit_worker_src.data, + lmcf->exit_worker_src.len, chunkname) + || ngx_http_lua_do_call(log, L); + + return ngx_http_lua_report(log, L, status, "exit_worker_by_lua"); } diff --git a/src/ngx_http_lua_initby.c b/src/ngx_http_lua_initby.c index bfd88c52ad..1f956e7ebd 100644 --- a/src/ngx_http_lua_initby.c +++ b/src/ngx_http_lua_initby.c @@ -21,18 +21,18 @@ ngx_http_lua_init_by_inline(ngx_log_t *log, ngx_http_lua_main_conf_t *lmcf, const char *chunkname; - status = luaL_loadbuffer(L, (char *) lmcf->init_src.data, - lmcf->init_src.len, "=init_by_lua") - || ngx_http_lua_do_call(log, L); - if (lmcf->init_chunkname == NULL) { - chunkname = "init_by_lua"; + chunkname = "=init_by_lua"; } else { chunkname = (const char *) lmcf->init_chunkname; } - return ngx_http_lua_report(log, L, status, chunkname); + status = luaL_loadbuffer(L, (char *) lmcf->init_src.data, + lmcf->init_src.len, chunkname) + || ngx_http_lua_do_call(log, L); + + return ngx_http_lua_report(log, L, status, "init_by_lua"); } diff --git a/src/ngx_http_lua_initworkerby.c b/src/ngx_http_lua_initworkerby.c index e559c89613..3235a4d30a 100644 --- a/src/ngx_http_lua_initworkerby.c +++ b/src/ngx_http_lua_initworkerby.c @@ -319,18 +319,18 @@ ngx_http_lua_init_worker_by_inline(ngx_log_t *log, int status; const char *chunkname; - status = luaL_loadbuffer(L, (char *) lmcf->init_worker_src.data, - lmcf->init_worker_src.len, "=init_worker_by_lua") - || ngx_http_lua_do_call(log, L); - if (lmcf->init_worker_chunkname == NULL) { - chunkname = "init_worker_by_lua"; + chunkname = "=init_worker_by_lua"; } else { chunkname = (const char *) lmcf->init_worker_chunkname; } - return ngx_http_lua_report(log, L, status, chunkname); + status = luaL_loadbuffer(L, (char *) lmcf->init_worker_src.data, + lmcf->init_worker_src.len, chunkname) + || ngx_http_lua_do_call(log, L); + + return ngx_http_lua_report(log, L, status, "init_worker_by_lua"); } diff --git a/t/041-header-filter.t b/t/041-header-filter.t index cfc6f53234..be390b3259 100644 --- a/t/041-header-filter.t +++ b/t/041-header-filter.t @@ -849,3 +849,27 @@ GET /lua failed to load inlined Lua code: header_filter_by_lua(nginx.conf:49):2: unexpected symbol near ''for end'' --- no_error_log no_such_error + + + +=== TEST 44: syntax error in /tmp/12345678901234567890123456789012345.conf +--- config + location /lua { + content_by_lua_block { + ngx.say("Hello world") + } + + include /tmp/12345678901234567890123456789012345.conf; + } +--- user_files +>>> /tmp/12345678901234567890123456789012345.conf + header_filter_by_lua_block { + 'for end'; + } +--- request +GET /lua +--- ignore_response +--- error_log +failed to load inlined Lua code: header_filter_by_lua(...901234567890123456789012345.conf:1):2: unexpected symbol near ''for end'' +--- no_error_log +[alert] diff --git a/t/086-init-by.t b/t/086-init-by.t index 8d9a8596b4..a998fc53d6 100644 --- a/t/086-init-by.t +++ b/t/086-init-by.t @@ -339,7 +339,7 @@ failed to init } --- must_die --- error_log -=init_by_lua(nginx.conf:25) error: init_by_lua:4: ')' expected (to close '(' at line 3) near 'ngx' +init_by_lua error: init_by_lua(nginx.conf:25):4: ')' expected (to close '(' at line 3) near 'ngx' --- no_error_log no_such_error_log diff --git a/t/089-phase.t b/t/089-phase.t index a7405f2d54..355b7ac33f 100644 --- a/t/089-phase.t +++ b/t/089-phase.t @@ -198,6 +198,6 @@ GET /lua ok --- shutdown_error_log eval [ -qr/exit_worker_by_lua:\d+: exit_worker/, +qr/exit_worker_by_lua\(nginx\.conf:\d+\):\d+: exit_worker/, qr/exiting now$/, ] diff --git a/t/091-coroutine.t b/t/091-coroutine.t index 74b7c682fe..fafc5a45cc 100644 --- a/t/091-coroutine.t +++ b/t/091-coroutine.t @@ -1713,9 +1713,9 @@ GET /t --- config --- must_die ---- grep_error_log eval: qr/init_by_lua\(nginx.conf:25\) error: .*? something went wrong/ +--- grep_error_log eval: qr/init_by_lua\(nginx.conf:25\).*? something went wrong/ --- grep_error_log_out -init_by_lua(nginx.conf:25) error: init_by_lua:7: init_by_lua:4: something went wrong +init_by_lua(nginx.conf:25):7: init_by_lua(nginx.conf:25):4: something went wrong diff --git a/t/124-init-worker.t b/t/124-init-worker.t index d10ee17285..d06ec9937b 100644 --- a/t/124-init-worker.t +++ b/t/124-init-worker.t @@ -996,7 +996,7 @@ start privileged agent process --- response_body hello world --- error_log -=init_worker_by_lua(nginx.conf:25) error: init_worker_by_lua:4: ')' expected (to close '(' at line 3) near 'ngx' +init_worker_by_lua error: init_worker_by_lua(nginx.conf:25):4: ')' expected (to close '(' at line 3) near 'ngx' --- no_error_log no_such_error_log diff --git a/t/162-exit-worker.t b/t/162-exit-worker.t index fcae47a4ee..60145ee737 100644 --- a/t/162-exit-worker.t +++ b/t/162-exit-worker.t @@ -215,7 +215,7 @@ qr/hello from exit worker by lua, process type: worker/, --- response_body hello world --- shutdown_error_log -=exit_worker_by_lua(nginx.conf:25) error: exit_worker_by_lua:4: ')' expected (to close '(' at line 3) near 'ngx' +exit_worker_by_lua error: exit_worker_by_lua(nginx.conf:25):4: ')' expected (to close '(' at line 3) near 'ngx' From cee06592f8bcdb7977b1f77d5cac4e4c24e8b36d Mon Sep 17 00:00:00 2001 From: Noah Jahn <36347998+noahjahn@users.noreply.github.com> Date: Thu, 17 Feb 2022 22:39:21 -0500 Subject: [PATCH 008/254] doc: fixed link to lua-resty-core --- README.markdown | 2 +- doc/HttpLuaModule.wiki | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.markdown b/README.markdown index 5a87d0c45d..f1e7826dac 100644 --- a/README.markdown +++ b/README.markdown @@ -354,7 +354,7 @@ Alternatively, ngx_lua can be manually compiled into Nginx: 1. Download the latest version of the ngx_devel_kit (NDK) module [HERE](https://github.com/simplresty/ngx_devel_kit/tags) 1. Download the latest version of ngx_lua [HERE](https://github.com/openresty/lua-nginx-module/tags) 1. Download the latest supported version of Nginx [HERE](https://nginx.org/) (See [Nginx Compatibility](#nginx-compatibility)) -1. Download the latest version of the lua-resty-core [HERE](https://lua-resty-core) +1. Download the latest version of the lua-resty-core [HERE](https://github.com/openresty/lua-resty-core) 1. Download the latest version of the lua-resty-lrucache [HERE](https://github.com/openresty/lua-resty-lrucache) Build the source with this module: diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 5c79dda3d6..a0111a36e5 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -285,7 +285,7 @@ Alternatively, ngx_lua can be manually compiled into Nginx: # Download the latest version of the ngx_devel_kit (NDK) module [https://github.com/simplresty/ngx_devel_kit/tags HERE] # Download the latest version of ngx_lua [https://github.com/openresty/lua-nginx-module/tags HERE] # Download the latest supported version of Nginx [https://nginx.org/ HERE] (See [[#Nginx Compatibility|Nginx Compatibility]]) -# Download the latest version of the lua-resty-core [HERE](https://lua-resty-core) +# Download the latest version of the lua-resty-core [HERE](https://github.com/openresty/lua-resty-core) # Download the latest version of the lua-resty-lrucache [HERE](https://github.com/openresty/lua-resty-lrucache) Build the source with this module: From 77540f78c33f27d5b3b93a485d43bb423bc83372 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Fri, 18 Feb 2022 14:19:29 +0800 Subject: [PATCH 009/254] doc: change description for ssl_client_hello_by_lua. --- README.markdown | 4 ++-- doc/HttpLuaModule.wiki | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.markdown b/README.markdown index f1e7826dac..6583c0a406 100644 --- a/README.markdown +++ b/README.markdown @@ -2738,7 +2738,7 @@ This directive requires OpenSSL 1.1.1 or greater. If you are using the [official pre-built packages](https://openresty.org/en/linux-packages.html) for -[OpenResty](https://openresty.org/) 1.19.9.2 or later, then everything should +[OpenResty](https://openresty.org/) 1.21.4.1 or later, then everything should work out of the box. If you are not using one of the [OpenSSL @@ -2749,7 +2749,7 @@ in order to use this directive: Similarly, if you are not using the Nginx core shipped with -[OpenResty](https://openresty.org) 1.19.9.2 or later, you will need to apply +[OpenResty](https://openresty.org) 1.21.4.1 or later, you will need to apply patches to the standard Nginx core: diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index a0111a36e5..3b94c211cf 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -2319,7 +2319,7 @@ This directive requires OpenSSL 1.1.1 or greater. If you are using the [official pre-built packages](https://openresty.org/en/linux-packages.html) for -[OpenResty](https://openresty.org/) 1.19.9.2 or later, then everything should +[OpenResty](https://openresty.org/) 1.21.4.1 or later, then everything should work out of the box. If you are not using one of the [OpenSSL @@ -2330,7 +2330,7 @@ in order to use this directive: https://openresty.org/en/openssl-patches.html Similarly, if you are not using the Nginx core shipped with -[OpenResty](https://openresty.org) 1.19.9.2 or later, you will need to apply +[OpenResty](https://openresty.org) 1.21.4.1 or later, you will need to apply patches to the standard Nginx core: https://openresty.org/en/nginx-ssl-patches.html From 66294b9d0675c2393e7d4ee625d7bd2aefc6b9c0 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Thu, 24 Feb 2022 09:47:02 +0800 Subject: [PATCH 010/254] bugfix: ambiguous error message 'connection in dubious state' when connection is closed. (#2016) --- src/ngx_http_lua_socket_tcp.c | 10 ++++-- t/058-tcp-socket.t | 68 ++++++++++++++++++++++++++++++++++- t/071-idle-socket.t | 2 +- 3 files changed, 75 insertions(+), 5 deletions(-) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 26467fddbc..ceaf4ff175 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -5188,7 +5188,12 @@ ngx_http_lua_socket_tcp_setkeepalive(lua_State *L) pc = &u->peer; c = pc->connection; - if (c == NULL || u->read_closed || u->write_closed) { + /* When the server closes the connection, + * epoll will return EPOLLRDHUP event and nginx will set pending_eof. + */ + if (c == NULL || u->read_closed || u->write_closed + || c->read->eof || c->read->pending_eof) + { lua_pushnil(L); lua_pushliteral(L, "closed"); return 2; @@ -5218,8 +5223,7 @@ ngx_http_lua_socket_tcp_setkeepalive(lua_State *L) return 2; } - if (c->read->eof - || c->read->error + if (c->read->error || c->read->timedout || c->write->error || c->write->timedout) diff --git a/t/058-tcp-socket.t b/t/058-tcp-socket.t index 593e49461f..6ffb32f584 100644 --- a/t/058-tcp-socket.t +++ b/t/058-tcp-socket.t @@ -4,7 +4,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * 231; +plan tests => repeat_each() * (blocks() * 3 + 21); our $HtmlDir = html_dir; @@ -4367,3 +4367,69 @@ connect failed: missing the port number finish --- no_error_log [error] + + + +=== TEST 73: reset the buffer pos when keepalive +--- config + server_tokens off; + location /t { + set $port $TEST_NGINX_SERVER_PORT; + + content_by_lua_block { + for i = 1, 10 + do + local sock = ngx.socket.tcp() + local port = ngx.var.port + local ok, err = sock:connect("127.0.0.1", port) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + local req = "GET /hi HTTP/1.1\r\nHost: localhost\r\n\r\n" + + local bytes, err = sock:send(req) + if not bytes then + ngx.say("failed to send request: ", err) + return + end + + local line, err, part = sock:receive() + if not line then + ngx.say("receive err: ", err) + return + end + + data, err = sock:receiveany(4096) + if not data then + ngx.say("receiveany er: ", err) + return + end + + ok, err = sock:setkeepalive(10000, 32) + if not ok then + ngx.say("reused times: ", i, ", setkeepalive err: ", err) + return + end + end + ngx.say("END") + } + } + + location /hi { + keepalive_requests 3; + content_by_lua_block { + ngx.say("Hello") + } + + more_clear_headers Date; + } + +--- request +GET /t +--- response_body +reused times: 3, setkeepalive err: closed +--- no_error_log +[error] +--- skip_eval: 3: $ENV{TEST_NGINX_EVENT_TYPE} && $ENV{TEST_NGINX_EVENT_TYPE} ne 'epoll' diff --git a/t/071-idle-socket.t b/t/071-idle-socket.t index c9002be8ea..49d45a1b54 100644 --- a/t/071-idle-socket.t +++ b/t/071-idle-socket.t @@ -367,7 +367,7 @@ Transfer-Encoding: chunked\r Connection: close\r \r 6\r -failed to set keepalive: (?:unread data in buffer|connection in dubious state) +failed to set keepalive: (?:unread data in buffer|closed|connection in dubious state) } --- no_error_log [error] From 7d585bd535bae9841ccb5a6856355b4b78bdc9f5 Mon Sep 17 00:00:00 2001 From: Johnny Wang Date: Sun, 27 Feb 2022 20:58:41 +0800 Subject: [PATCH 011/254] bugfix: fixed size of the array when initialized in the init_worker_by* phase. (#2017) --- src/ngx_http_lua_initworkerby.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/ngx_http_lua_initworkerby.c b/src/ngx_http_lua_initworkerby.c index 3235a4d30a..449e604ace 100644 --- a/src/ngx_http_lua_initworkerby.c +++ b/src/ngx_http_lua_initworkerby.c @@ -118,14 +118,15 @@ ngx_http_lua_init_worker(ngx_cycle_t *cycle) ngx_queue_init(&fake_cycle->reusable_connections_queue); if (ngx_array_init(&fake_cycle->listening, cycle->pool, - cycle->listening.nelts || 1, + cycle->listening.nelts ? cycle->listening.nelts : 1, sizeof(ngx_listening_t)) != NGX_OK) { goto failed; } - if (ngx_array_init(&fake_cycle->paths, cycle->pool, cycle->paths.nelts || 1, + if (ngx_array_init(&fake_cycle->paths, cycle->pool, + cycle->paths.nelts ? cycle->paths.nelts : 1, sizeof(ngx_path_t *)) != NGX_OK) { @@ -135,7 +136,8 @@ ngx_http_lua_init_worker(ngx_cycle_t *cycle) part = &cycle->open_files.part; ofile = part->elts; - if (ngx_list_init(&fake_cycle->open_files, cycle->pool, part->nelts || 1, + if (ngx_list_init(&fake_cycle->open_files, cycle->pool, + part->nelts ? part->nelts : 1, sizeof(ngx_open_file_t)) != NGX_OK) { From d001dea7783c7128bbc9dc0f96f2a24badd9ec2c Mon Sep 17 00:00:00 2001 From: lijunlong Date: Sun, 2 Jan 2022 10:11:42 +0800 Subject: [PATCH 012/254] bugfix: posted event handler was called after event memory was freed. (#1982) --- src/ngx_http_lua_semaphore.c | 9 ++++++- t/154-semaphore.t | 50 ++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/src/ngx_http_lua_semaphore.c b/src/ngx_http_lua_semaphore.c index 6f45eeffcc..435beaa29a 100644 --- a/src/ngx_http_lua_semaphore.c +++ b/src/ngx_http_lua_semaphore.c @@ -466,8 +466,11 @@ ngx_http_lua_sema_handler(ngx_event_t *ev) sem = ev->data; + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "semaphore handler: wait queue: %sempty, resource count: %d", + ngx_queue_empty(&sem->wait_queue) ? "" : "not ", + sem->resource_count); while (!ngx_queue_empty(&sem->wait_queue) && sem->resource_count > 0) { - q = ngx_queue_head(&sem->wait_queue); ngx_queue_remove(q); @@ -566,6 +569,10 @@ ngx_http_lua_ffi_sema_gc(ngx_http_lua_sema_t *sem) "destroyed", sem); } + if (sem->sem_event.posted) { + ngx_delete_posted_event(&sem->sem_event); + } + ngx_http_lua_free_sema(sem); } diff --git a/t/154-semaphore.t b/t/154-semaphore.t index c7b00e03f6..5bb2b937af 100644 --- a/t/154-semaphore.t +++ b/t/154-semaphore.t @@ -118,3 +118,53 @@ hello, world --- no_shutdown_error_log semaphore gc wait queue is not empty --- SKIP + + + +=== TEST 3: exit before post_handler was called +If gc is called before the ngx_http_lua_sema_handler and free the sema memory +ngx_http_lua_sema_handler would use the freed memory. +--- config + location /up { + content_by_lua_block { + local semaphore = require "ngx.semaphore" + local sem = semaphore.new() + + local function sem_wait() + ngx.log(ngx.ERR, "ngx.sem wait start") + local ok, err = sem:wait(10) + if not ok then + ngx.log(ngx.ERR, "ngx.sem wait err: ", err) + else + ngx.log(ngx.ERR, "ngx.sem wait success") + end + end + local co = ngx.thread.spawn(sem_wait) + ngx.log(ngx.ERR, "ngx.sem post start") + sem:post() + ngx.log(ngx.ERR, "ngx.sem post end") + ngx.say("hello") + ngx.exit(200) + ngx.say("not reach here") + } + } + + location /t { + content_by_lua_block { + local res = ngx.location.capture("/up") + collectgarbage() + ngx.print(res.body) + } + } + +--- request +GET /t +--- response_body +hello +--- grep_error_log eval: qr/(ngx.sem .*?,|http close request|semaphore handler: wait queue: empty, resource count: 1|in lua gc, semaphore)/ +--- grep_error_log_out +ngx.sem wait start, +ngx.sem post start, +ngx.sem post end, +in lua gc, semaphore +http close request From 97d1b704d0d86b5370d57604a9e2e3f86e4a33ec Mon Sep 17 00:00:00 2001 From: lijunlong Date: Mon, 10 Jan 2022 20:33:16 +0800 Subject: [PATCH 013/254] bugfix: ngx.pipe waits until timeout because child process forgot to close pipe after dup2. After the fork, the pipe will be copied by dup2, so there are two fd for the same open file description. eg: 0, 11 for the same pipe file, 1, 13 for another pipe file. When running a short life process, the fd will be closed automatically when the process exits. When running a daemon process, the daemon may close fd 0, fd 1 and redirect them to /dev/null, but left the fd 11 and fd 13 opened forever. when ngx.pipe reads from the pipe, it will wait for reading until the pipe is closed or timeout. Because the daemon won't close the pipe, so ngx.pipe will wait for the timeout. --- src/ngx_http_lua_pipe.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/ngx_http_lua_pipe.c b/src/ngx_http_lua_pipe.c index 9ea0ba1c41..93dc7d5bc5 100644 --- a/src/ngx_http_lua_pipe.c +++ b/src/ngx_http_lua_pipe.c @@ -773,6 +773,12 @@ ngx_http_lua_ffi_pipe_spawn(ngx_http_lua_ffi_pipe_proc_t *proc, } } + close(in[0]); + close(out[1]); + if (!merge_stderr) { + close(err[1]); + } + if (environ != NULL) { #if (NGX_HTTP_LUA_HAVE_EXECVPE) if (execvpe(file, (char * const *) argv, (char * const *) environ) From 496d9853347e8eefa81a442e42d33b4b92f5c825 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Wed, 2 Mar 2022 17:23:00 +0800 Subject: [PATCH 014/254] tests: change the count of the record after adding ngx.get_raw_phase. (#2019) --- t/062-count.t | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/t/062-count.t b/t/062-count.t index f5ba12c91d..104126281a 100644 --- a/t/062-count.t +++ b/t/062-count.t @@ -34,7 +34,7 @@ __DATA__ --- request GET /test --- response_body -ngx: 115 +ngx: 116 --- no_error_log [error] @@ -55,7 +55,7 @@ ngx: 115 --- request GET /test --- response_body -115 +116 --- no_error_log [error] @@ -83,7 +83,7 @@ GET /test --- request GET /test --- response_body -n = 115 +n = 116 --- no_error_log [error] @@ -305,7 +305,7 @@ GET /t --- response_body_like: 404 Not Found --- error_code: 404 --- error_log -ngx. entry count: 115 +ngx. entry count: 116 From bd92edf3b82438455036af1408d2377954f28b8f Mon Sep 17 00:00:00 2001 From: Blaise Wang Date: Fri, 4 Mar 2022 09:04:19 +0800 Subject: [PATCH 015/254] doc: modify openssl patch requirements. (#2022) --- README.markdown | 18 ++---------------- doc/HttpLuaModule.wiki | 18 ++---------------- 2 files changed, 4 insertions(+), 32 deletions(-) diff --git a/README.markdown b/README.markdown index 6583c0a406..b603a8b06b 100644 --- a/README.markdown +++ b/README.markdown @@ -2741,14 +2741,7 @@ packages](https://openresty.org/en/linux-packages.html) for [OpenResty](https://openresty.org/) 1.21.4.1 or later, then everything should work out of the box. -If you are not using one of the [OpenSSL -packages](https://openresty.org/en/linux-packages.html) provided by -[OpenResty](https://openresty.org), you will need to apply patches to OpenSSL -in order to use this directive: - - - -Similarly, if you are not using the Nginx core shipped with +If you are not using the Nginx core shipped with [OpenResty](https://openresty.org) 1.21.4.1 or later, you will need to apply patches to the standard Nginx core: @@ -2858,14 +2851,7 @@ packages](https://openresty.org/en/linux-packages.html) for [OpenResty](https://openresty.org/) 1.9.7.2 or later, then everything should work out of the box. -If you are not using one of the [OpenSSL -packages](https://openresty.org/en/linux-packages.html) provided by -[OpenResty](https://openresty.org), you will need to apply patches to OpenSSL -in order to use this directive: - - - -Similarly, if you are not using the Nginx core shipped with +If you are not using the Nginx core shipped with [OpenResty](https://openresty.org) 1.9.7.2 or later, you will need to apply patches to the standard Nginx core: diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 3b94c211cf..b5bacd7772 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -2322,14 +2322,7 @@ packages](https://openresty.org/en/linux-packages.html) for [OpenResty](https://openresty.org/) 1.21.4.1 or later, then everything should work out of the box. -If you are not using one of the [OpenSSL -packages](https://openresty.org/en/linux-packages.html) provided by -[OpenResty](https://openresty.org), you will need to apply patches to OpenSSL -in order to use this directive: - -https://openresty.org/en/openssl-patches.html - -Similarly, if you are not using the Nginx core shipped with +If you are not using the Nginx core shipped with [OpenResty](https://openresty.org) 1.21.4.1 or later, you will need to apply patches to the standard Nginx core: @@ -2432,14 +2425,7 @@ packages](https://openresty.org/en/linux-packages.html) for [OpenResty](https://openresty.org/) 1.9.7.2 or later, then everything should work out of the box. -If you are not using one of the [OpenSSL -packages](https://openresty.org/en/linux-packages.html) provided by -[OpenResty](https://openresty.org), you will need to apply patches to OpenSSL -in order to use this directive: - -https://openresty.org/en/openssl-patches.html - -Similarly, if you are not using the Nginx core shipped with +If you are not using the Nginx core shipped with [OpenResty](https://openresty.org) 1.9.7.2 or later, you will need to apply patches to the standard Nginx core: From 974d5d163d86af6852c39143ac6076d0144f79de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BD=97=E6=B3=BD=E8=BD=A9?= Date: Fri, 4 Mar 2022 17:18:50 +0800 Subject: [PATCH 016/254] feature: add FFI implementation for ngx.arg getter (#2021) --- src/ngx_http_lua_bodyfilterby.c | 78 ++++++++++++++++++++------------- src/ngx_http_lua_bodyfilterby.h | 1 - src/ngx_http_lua_setby.c | 14 +++--- src/ngx_http_lua_setby.h | 1 - src/ngx_http_lua_util.c | 33 -------------- 5 files changed, 53 insertions(+), 74 deletions(-) diff --git a/src/ngx_http_lua_bodyfilterby.c b/src/ngx_http_lua_bodyfilterby.c index 1aa01e552b..632f5afea3 100644 --- a/src/ngx_http_lua_bodyfilterby.c +++ b/src/ngx_http_lua_bodyfilterby.c @@ -396,51 +396,48 @@ ngx_http_lua_body_filter_init(void) int -ngx_http_lua_body_filter_param_get(lua_State *L, ngx_http_request_t *r) +ngx_http_lua_ffi_get_body_filter_param_eof(ngx_http_request_t *r) { - u_char *data, *p; - size_t size; ngx_chain_t *cl; - ngx_buf_t *b; - int idx; ngx_chain_t *in; ngx_http_lua_main_conf_t *lmcf; - idx = luaL_checkint(L, 2); + lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); + in = lmcf->body_filter_chain; - dd("index: %d", idx); + /* asking for the eof argument */ - if (idx != 1 && idx != 2) { - lua_pushnil(L); - return 1; + for (cl = in; cl; cl = cl->next) { + if (cl->buf->last_buf || cl->buf->last_in_chain) { + return 1; + } } - lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); - in = lmcf->body_filter_chain; + return 0; +} - if (idx == 2) { - /* asking for the eof argument */ - for (cl = in; cl; cl = cl->next) { - if (cl->buf->last_buf || cl->buf->last_in_chain) { - lua_pushboolean(L, 1); - return 1; - } - } +int +ngx_http_lua_ffi_get_body_filter_param_body(ngx_http_request_t *r, + u_char **data_p, size_t *len_p) +{ + size_t size; + ngx_chain_t *cl; + ngx_buf_t *b; + ngx_chain_t *in; - lua_pushboolean(L, 0); - return 1; - } + ngx_http_lua_main_conf_t *lmcf; - /* idx == 1 */ + lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); + in = lmcf->body_filter_chain; size = 0; if (in == NULL) { /* being a cleared chain on the Lua land */ - lua_pushliteral(L, ""); - return 1; + *len_p = 0; + return NGX_OK; } if (in->next == NULL) { @@ -448,8 +445,9 @@ ngx_http_lua_body_filter_param_get(lua_State *L, ngx_http_request_t *r) dd("seen only single buffer"); b = in->buf; - lua_pushlstring(L, (char *) b->pos, b->last - b->pos); - return 1; + *data_p = b->pos; + *len_p = b->last - b->pos; + return NGX_OK; } dd("seen multiple buffers"); @@ -464,7 +462,26 @@ ngx_http_lua_body_filter_param_get(lua_State *L, ngx_http_request_t *r) } } - data = (u_char *) lua_newuserdata(L, size); + /* the buf is need and is not allocated from Lua land yet, return with + * the actual size */ + *len_p = size; + return NGX_AGAIN; +} + + +int +ngx_http_lua_ffi_copy_body_filter_param_body(ngx_http_request_t *r, + u_char *data) +{ + u_char *p; + ngx_chain_t *cl; + ngx_buf_t *b; + ngx_chain_t *in; + + ngx_http_lua_main_conf_t *lmcf; + + lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); + in = lmcf->body_filter_chain; for (p = data, cl = in; cl; cl = cl->next) { b = cl->buf; @@ -475,8 +492,7 @@ ngx_http_lua_body_filter_param_get(lua_State *L, ngx_http_request_t *r) } } - lua_pushlstring(L, (char *) data, size); - return 1; + return NGX_OK; } diff --git a/src/ngx_http_lua_bodyfilterby.h b/src/ngx_http_lua_bodyfilterby.h index b108202faa..359646f2b5 100644 --- a/src/ngx_http_lua_bodyfilterby.h +++ b/src/ngx_http_lua_bodyfilterby.h @@ -21,7 +21,6 @@ ngx_int_t ngx_http_lua_body_filter_inline(ngx_http_request_t *r, ngx_chain_t *in); ngx_int_t ngx_http_lua_body_filter_file(ngx_http_request_t *r, ngx_chain_t *in); -int ngx_http_lua_body_filter_param_get(lua_State *L, ngx_http_request_t *r); int ngx_http_lua_body_filter_param_set(lua_State *L, ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx); diff --git a/src/ngx_http_lua_setby.c b/src/ngx_http_lua_setby.c index f00468c903..98e8d47f5a 100644 --- a/src/ngx_http_lua_setby.c +++ b/src/ngx_http_lua_setby.c @@ -123,16 +123,15 @@ ngx_http_lua_set_by_chunk(lua_State *L, ngx_http_request_t *r, ngx_str_t *val, } -int -ngx_http_lua_setby_param_get(lua_State *L, ngx_http_request_t *r) +void +ngx_http_lua_ffi_get_setby_param(ngx_http_request_t *r, int idx, + u_char **data_p, size_t *len_p) { - int idx; int n; ngx_http_variable_value_t *v; ngx_http_lua_main_conf_t *lmcf; - idx = luaL_checkint(L, 2); idx--; lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); @@ -144,13 +143,12 @@ ngx_http_lua_setby_param_get(lua_State *L, ngx_http_request_t *r) v = lmcf->setby_args; if (idx < 0 || idx > n - 1) { - lua_pushnil(L); + *len_p = 0; } else { - lua_pushlstring(L, (const char *) (v[idx].data), v[idx].len); + *data_p = v[idx].data; + *len_p = v[idx].len; } - - return 1; } diff --git a/src/ngx_http_lua_setby.h b/src/ngx_http_lua_setby.h index f43eef753e..8fd1e2c7b3 100644 --- a/src/ngx_http_lua_setby.h +++ b/src/ngx_http_lua_setby.h @@ -7,7 +7,6 @@ ngx_int_t ngx_http_lua_set_by_chunk(lua_State *L, ngx_http_request_t *r, ngx_str_t *val, ngx_http_variable_value_t *args, size_t nargs, ngx_str_t *script); -int ngx_http_lua_setby_param_get(lua_State *L, ngx_http_request_t *r); #endif /* _NGX_HTTP_LUA_SET_BY_H_INCLUDED_ */ diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index b783cf850c..762958396b 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -119,7 +119,6 @@ static int ngx_http_lua_thread_traceback(lua_State *L, lua_State *co, static void ngx_http_lua_inject_ngx_api(lua_State *L, ngx_http_lua_main_conf_t *lmcf, ngx_log_t *log); static void ngx_http_lua_inject_arg_api(lua_State *L); -static int ngx_http_lua_param_get(lua_State *L); static int ngx_http_lua_param_set(lua_State *L); static ngx_int_t ngx_http_lua_output_filter(ngx_http_request_t *r, ngx_chain_t *in); @@ -3099,9 +3098,6 @@ ngx_http_lua_inject_arg_api(lua_State *L) lua_createtable(L, 0 /* narr */, 2 /* nrec */); /* the metatable */ - lua_pushcfunction(L, ngx_http_lua_param_get); - lua_setfield(L, -2, "__index"); - lua_pushcfunction(L, ngx_http_lua_param_set); lua_setfield(L, -2, "__newindex"); @@ -3113,35 +3109,6 @@ ngx_http_lua_inject_arg_api(lua_State *L) } -static int -ngx_http_lua_param_get(lua_State *L) -{ - ngx_http_lua_ctx_t *ctx; - ngx_http_request_t *r; - - r = ngx_http_lua_get_req(L); - if (r == NULL) { - return 0; - } - - ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); - if (ctx == NULL) { - return luaL_error(L, "ctx not found"); - } - - ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_SET - | NGX_HTTP_LUA_CONTEXT_BODY_FILTER); - - if (ctx->context & (NGX_HTTP_LUA_CONTEXT_SET)) { - return ngx_http_lua_setby_param_get(L, r); - } - - /* ctx->context & (NGX_HTTP_LUA_CONTEXT_BODY_FILTER) */ - - return ngx_http_lua_body_filter_param_get(L, r); -} - - static int ngx_http_lua_param_set(lua_State *L) { From d959374e027475c27a96c3dde38486b4506edda4 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Sat, 5 Mar 2022 17:03:37 +0800 Subject: [PATCH 017/254] optimize: use ngx_hash_t to optimize the built-in header look-up process for ngx.header.HEADER. --- README.markdown | 2 +- doc/HttpLuaModule.wiki | 2 +- src/ngx_http_lua_common.h | 2 + src/ngx_http_lua_headers_out.c | 97 ++++++++++++++++++++-------------- src/ngx_http_lua_headers_out.h | 2 + src/ngx_http_lua_module.c | 10 ++++ src/ngx_http_lua_util.h | 37 +++++++++++++ 7 files changed, 110 insertions(+), 42 deletions(-) diff --git a/README.markdown b/README.markdown index b603a8b06b..f54e797eb4 100644 --- a/README.markdown +++ b/README.markdown @@ -973,7 +973,7 @@ TODO * cosocket: review and merge aviramc's [patch](https://github.com/openresty/lua-nginx-module/pull/290) for adding the `bsdrecv` method. * cosocket: add configure options for different strategies of handling the cosocket connection exceeding in the pools. * review and apply vadim-pavlov's patch for [ngx.location.capture](#ngxlocationcapture)'s `extra_headers` option -* use `ngx_hash_t` to optimize the built-in header look-up process for [ngx.req.set_header](#ngxreqset_header), [ngx.header.HEADER](#ngxheaderheader), and etc. +* use `ngx_hash_t` to optimize the built-in header look-up process for [ngx.req.set_header](#ngxreqset_header), and etc. * add `ignore_resp_headers`, `ignore_resp_body`, and `ignore_resp` options to [ngx.location.capture](#ngxlocationcapture) and [ngx.location.capture_multi](#ngxlocationcapture_multi) methods, to allow micro performance tuning on the user side. * add automatic Lua code time slicing support by yielding and resuming the Lua VM actively via Lua's debug hooks. * add `stat` mode similar to [mod_lua](https://httpd.apache.org/docs/trunk/mod/mod_lua.html). diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index b5bacd7772..9a8dfc8b30 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -808,7 +808,7 @@ phases. * cosocket: review and merge aviramc's [https://github.com/openresty/lua-nginx-module/pull/290 patch] for adding the bsdrecv method. * cosocket: add configure options for different strategies of handling the cosocket connection exceeding in the pools. * review and apply vadim-pavlov's patch for [[#ngx.location.capture|ngx.location.capture]]'s extra_headers option -* use ngx_hash_t to optimize the built-in header look-up process for [[#ngx.req.set_header|ngx.req.set_header]], [[#ngx.header.HEADER|ngx.header.HEADER]], and etc. +* use ngx_hash_t to optimize the built-in header look-up process for [[#ngx.req.set_header|ngx.req.set_header]], and etc. * add ignore_resp_headers, ignore_resp_body, and ignore_resp options to [[#ngx.location.capture|ngx.location.capture]] and [[#ngx.location.capture_multi|ngx.location.capture_multi]] methods, to allow micro performance tuning on the user side. * add automatic Lua code time slicing support by yielding and resuming the Lua VM actively via Lua's debug hooks. * add stat mode similar to [https://httpd.apache.org/docs/trunk/mod/mod_lua.html mod_lua]. diff --git a/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h index 017e2a0434..3a2480f041 100644 --- a/src/ngx_http_lua_common.h +++ b/src/ngx_http_lua_common.h @@ -214,6 +214,8 @@ struct ngx_http_lua_main_conf_s { ngx_int_t lua_thread_cache_max_entries; + ngx_hash_t builtin_headers_out; + #if (NGX_PCRE) ngx_int_t regex_cache_entries; ngx_int_t regex_cache_max_entries; diff --git a/src/ngx_http_lua_headers_out.c b/src/ngx_http_lua_headers_out.c index 050f12b4ed..6e9f9c19ac 100644 --- a/src/ngx_http_lua_headers_out.c +++ b/src/ngx_http_lua_headers_out.c @@ -486,8 +486,9 @@ 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; - ngx_uint_t i; + ngx_http_lua_main_conf_t *lmcf; + ngx_http_lua_set_header_t *lsh; + ngx_hash_t *hash; dd("set header value: %.*s", (int) value.len, value.data); @@ -499,53 +500,25 @@ ngx_http_lua_set_output_header(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx, return NGX_ERROR; } - if (value.len > 0) { - hv.hash = ngx_hash_key_lc(key.data, key.len); - - } else { - hv.hash = 0; - } - + hv.hash = ngx_hash_key_lc(key.data, key.len); hv.key = key; hv.offset = 0; hv.no_override = !override; - hv.handler = NULL; - - for (i = 0; handlers[i].name.len; i++) { - if (hv.key.len != handlers[i].name.len - || ngx_strncasecmp(hv.key.data, handlers[i].name.data, - handlers[i].name.len) != 0) - { - dd("hv key comparison: %s <> %s", handlers[i].name.data, - hv.key.data); - - continue; - } - - dd("Matched handler: %s %s", handlers[i].name.data, hv.key.data); - - hv.offset = handlers[i].offset; - hv.handler = handlers[i].handler; - + hv.handler = ngx_http_set_header; + + lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); + hash = &lmcf->builtin_headers_out; + lsh = ngx_http_lua_hash_find_lc(hash, hv.hash, hv.key.data, hv.key.len); + if (lsh) { + dd("Matched handler: %s %s", lsh->name.data, hv.key.data); + hv.offset = lsh->offset; + hv.handler = lsh->handler; if (hv.handler == ngx_http_set_content_type_header) { ctx->mime_set = 1; } - - break; - } - - if (handlers[i].name.len == 0 && handlers[i].handler) { - hv.offset = handlers[i].offset; - hv.handler = handlers[i].handler; } -#if 1 - if (hv.handler == NULL) { - return NGX_ERROR; - } -#endif - return hv.handler(r, &hv, &value); } @@ -658,4 +631,48 @@ ngx_http_lua_get_output_header(lua_State *L, ngx_http_request_t *r, return 1; } + +ngx_int_t +ngx_http_lua_init_builtin_headers_out(ngx_conf_t *cf, + ngx_http_lua_main_conf_t *lmcf) +{ + ngx_array_t headers; + ngx_hash_key_t *hk; + ngx_hash_init_t hash; + ngx_http_lua_set_header_t *handlers = ngx_http_lua_set_handlers; + ngx_uint_t count; + + count = sizeof(ngx_http_lua_set_handlers) + / sizeof(ngx_http_lua_set_header_t); + + if (ngx_array_init(&headers, cf->temp_pool, count, sizeof(ngx_hash_key_t)) + != NGX_OK) + { + return NGX_ERROR; + } + + while (handlers->name.data) { + hk = ngx_array_push(&headers); + if (hk == NULL) { + return NGX_ERROR; + } + + hk->key = handlers->name; + hk->key_hash = ngx_hash_key_lc(handlers->name.data, handlers->name.len); + hk->value = (void *) handlers; + + handlers++; + } + + hash.hash = &lmcf->builtin_headers_out; + hash.key = ngx_hash_key_lc; + hash.max_size = 512; + hash.bucket_size = ngx_align(64, ngx_cacheline_size); + hash.name = "builtin_headers_out_hash"; + hash.pool = cf->pool; + hash.temp_pool = NULL; + + return ngx_hash_init(&hash, headers.elts, headers.nelts); +} + /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_headers_out.h b/src/ngx_http_lua_headers_out.h index 6ec1fe391d..944f57a462 100644 --- a/src/ngx_http_lua_headers_out.h +++ b/src/ngx_http_lua_headers_out.h @@ -16,6 +16,8 @@ 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_http_lua_ctx_t *ctx, ngx_str_t *key); +ngx_int_t ngx_http_lua_init_builtin_headers_out(ngx_conf_t *cf, + ngx_http_lua_main_conf_t *lmcf); #endif /* _NGX_HTTP_LUA_HEADERS_OUT_H_INCLUDED_ */ diff --git a/src/ngx_http_lua_module.c b/src/ngx_http_lua_module.c index 09fd0a91f8..bd4535af35 100644 --- a/src/ngx_http_lua_module.c +++ b/src/ngx_http_lua_module.c @@ -31,6 +31,7 @@ #include "ngx_http_lua_ssl_session_storeby.h" #include "ngx_http_lua_ssl_session_fetchby.h" #include "ngx_http_lua_headers.h" +#include "ngx_http_lua_headers_out.h" #include "ngx_http_lua_pipe.h" @@ -1086,6 +1087,15 @@ ngx_http_lua_init_main_conf(ngx_conf_t *cf, void *conf) lmcf->worker_thread_vm_pool_size = 100; } + if (ngx_http_lua_init_builtin_headers_out(cf, lmcf) != NGX_OK) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "init header out error"); + + return NGX_CONF_ERROR; + } + + dd("init built in headers out hash size: %ld", + lmcf->builtin_headers_out.size); + return NGX_CONF_OK; } diff --git a/src/ngx_http_lua_util.h b/src/ngx_http_lua_util.h index 9ad34b93ea..52b1ff9356 100644 --- a/src/ngx_http_lua_util.h +++ b/src/ngx_http_lua_util.h @@ -685,6 +685,43 @@ ngx_http_lua_new_cached_thread(lua_State *L, lua_State **out_co, } +static ngx_inline void * +ngx_http_lua_hash_find_lc(ngx_hash_t *hash, ngx_uint_t key, u_char *name, + size_t len) +{ + ngx_uint_t i; + ngx_hash_elt_t *elt; + + elt = hash->buckets[key % hash->size]; + + if (elt == NULL) { + return NULL; + } + + while (elt->value) { + if (len != (size_t) elt->len) { + goto next; + } + + for (i = 0; i < len; i++) { + if (ngx_tolower(name[i]) != elt->name[i]) { + goto next; + } + } + + return elt->value; + + next: + + elt = (ngx_hash_elt_t *) ngx_align_ptr(&elt->name[0] + elt->len, + sizeof(void *)); + continue; + } + + return NULL; +} + + extern ngx_uint_t ngx_http_lua_location_hash; extern ngx_uint_t ngx_http_lua_content_length_hash; From 247086ed3892647ab5ecc4fd9946186bb76f15db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BD=97=E6=B3=BD=E8=BD=A9?= Date: Tue, 8 Mar 2022 08:40:57 +0800 Subject: [PATCH 018/254] doc: describe the second argument of get_uri_args (#2023) Signed-off-by: spacewander --- README.markdown | 5 +++-- doc/HttpLuaModule.wiki | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/README.markdown b/README.markdown index f54e797eb4..4e0b979879 100644 --- a/README.markdown +++ b/README.markdown @@ -4903,11 +4903,12 @@ See also [ngx.req.set_uri](#ngxreqset_uri). ngx.req.get_uri_args -------------------- -**syntax:** *args, err = ngx.req.get_uri_args(max_args?)* +**syntax:** *args, err = ngx.req.get_uri_args(max_args?, tab?)* **context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, balancer_by_lua** -Returns a Lua table holding all the current request URL query arguments. +Returns a Lua table holding all the current request URL query arguments. An optional `tab` argument +can be used to reuse the table returned by this method. ```nginx diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 9a8dfc8b30..0d69fd205b 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -4101,11 +4101,12 @@ See also [[#ngx.req.set_uri|ngx.req.set_uri]]. == ngx.req.get_uri_args == -'''syntax:''' ''args, err = ngx.req.get_uri_args(max_args?)'' +'''syntax:''' ''args, err = ngx.req.get_uri_args(max_args?, tab?)'' '''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, balancer_by_lua*'' -Returns a Lua table holding all the current request URL query arguments. +Returns a Lua table holding all the current request URL query arguments. An optional tab argument +can be used to reuse the table returned by this method. location = /test { From a7444abe8e50b49d91a922c958f904ba893e54e7 Mon Sep 17 00:00:00 2001 From: Johnny Wang Date: Wed, 9 Mar 2022 16:17:15 +0800 Subject: [PATCH 019/254] tests: 160-disable-init-by-lua.t: prevent the test process from overwriting the original pid file. (#2024) --- t/160-disable-init-by-lua.t | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/t/160-disable-init-by-lua.t b/t/160-disable-init-by-lua.t index dd0098d0d5..e98c136dcf 100644 --- a/t/160-disable-init-by-lua.t +++ b/t/160-disable-init-by-lua.t @@ -12,6 +12,9 @@ my $http_config = <<_EOC_; function set_up_ngx_tmp_conf(conf) if conf == nil then conf = [[ + # to prevent the test process from overwriting the + # original pid file + pid logs/test_nginx.pid; events { worker_connections 64; } @@ -150,6 +153,7 @@ qr/\[error\] .*? init_by_lua:\d+: run init_by_lua/ location = /t { content_by_lua_block { local conf = [[ + pid logs/test_nginx.pid; events { worker_connections 64; } From 1fea11712274a26b9b3b5b3b44fb0791a312091d Mon Sep 17 00:00:00 2001 From: Johnny Wang Date: Thu, 10 Mar 2022 18:04:32 +0800 Subject: [PATCH 020/254] tests: use random port numbers instead of fixed port number to prevent conflict. (#2025) --- t/109-timer-hup.t | 4 ++-- t/138-balancer.t | 6 +++--- t/139-ssl-cert-by.t | 24 ++++++++++++------------ 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/t/109-timer-hup.t b/t/109-timer-hup.t index 2c197c2826..bff1b33466 100644 --- a/t/109-timer-hup.t +++ b/t/109-timer-hup.t @@ -336,7 +336,7 @@ lua found 100 pending timers lua_shared_dict test_dict 1m; server { - listen 12355; + listen $TEST_NGINX_RAND_PORT_1; location = /foo { echo 'foo'; } @@ -350,7 +350,7 @@ lua found 100 pending timers -- Connect the socket local sock = ngx.socket.tcp() - local ok,err = sock:connect("127.0.0.1", 12355) + local ok,err = sock:connect("127.0.0.1", $TEST_NGINX_RAND_PORT_1) if not ok then ngx.log(ngx.ERR, err) end diff --git a/t/138-balancer.t b/t/138-balancer.t index 2894157e0e..d9c943388e 100644 --- a/t/138-balancer.t +++ b/t/138-balancer.t @@ -535,7 +535,7 @@ failed to set more tries: reduced tries due to limit lua_package_path "../lua-resty-core/lib/?.lua;;"; server { - listen 127.0.0.1:8888; + listen 127.0.0.1:$TEST_NGINX_RAND_PORT_1; location / { return 200 "it works"; @@ -543,8 +543,8 @@ failed to set more tries: reduced tries due to limit } upstream foo { - server 127.0.0.1:8888 max_fails=0; - server 127.0.0.1:8889 max_fails=0 weight=9999; + server 127.0.0.1:$TEST_NGINX_RAND_PORT_1 max_fails=0; + server 127.0.0.1:$TEST_NGINX_RAND_PORT_2 max_fails=0 weight=9999; balancer_by_lua_block { local bal = require "ngx.balancer" diff --git a/t/139-ssl-cert-by.t b/t/139-ssl-cert-by.t index 38296352f5..502e0ac184 100644 --- a/t/139-ssl-cert-by.t +++ b/t/139-ssl-cert-by.t @@ -456,7 +456,7 @@ received memc reply: OK === TEST 5: ngx.exit(0) - no yield --- http_config server { - listen 127.0.0.2:8080 ssl; + listen 127.0.0.2:$TEST_NGINX_RAND_PORT_1 ssl; server_name test.com; ssl_certificate_by_lua_block { ngx.exit(0) @@ -484,7 +484,7 @@ received memc reply: OK sock:settimeout(2000) - local ok, err = sock:connect("127.0.0.2", 8080) + local ok, err = sock:connect("127.0.0.2", $TEST_NGINX_RAND_PORT_1) if not ok then ngx.say("failed to connect: ", err) return @@ -523,7 +523,7 @@ should never reached here === TEST 6: ngx.exit(ngx.ERROR) - no yield --- http_config server { - listen 127.0.0.2:8080 ssl; + listen 127.0.0.2:$TEST_NGINX_RAND_PORT_1 ssl; server_name test.com; ssl_certificate_by_lua_block { ngx.exit(ngx.ERROR) @@ -551,7 +551,7 @@ should never reached here sock:settimeout(2000) - local ok, err = sock:connect("127.0.0.2", 8080) + local ok, err = sock:connect("127.0.0.2", $TEST_NGINX_RAND_PORT_1) if not ok then ngx.say("failed to connect: ", err) return @@ -593,7 +593,7 @@ should never reached here === TEST 7: ngx.exit(0) - yield --- http_config server { - listen 127.0.0.2:8080 ssl; + listen 127.0.0.2:$TEST_NGINX_RAND_PORT_1 ssl; server_name test.com; ssl_certificate_by_lua_block { ngx.sleep(0.001) @@ -623,7 +623,7 @@ should never reached here sock:settimeout(2000) - local ok, err = sock:connect("127.0.0.2", 8080) + local ok, err = sock:connect("127.0.0.2", $TEST_NGINX_RAND_PORT_1) if not ok then ngx.say("failed to connect: ", err) return @@ -662,7 +662,7 @@ should never reached here === TEST 8: ngx.exit(ngx.ERROR) - yield --- http_config server { - listen 127.0.0.2:8080 ssl; + listen 127.0.0.2:$TEST_NGINX_RAND_PORT_1 ssl; server_name test.com; ssl_certificate_by_lua_block { ngx.sleep(0.001) @@ -692,7 +692,7 @@ should never reached here sock:settimeout(2000) - local ok, err = sock:connect("127.0.0.2", 8080) + local ok, err = sock:connect("127.0.0.2", $TEST_NGINX_RAND_PORT_1) if not ok then ngx.say("failed to connect: ", err) return @@ -734,7 +734,7 @@ should never reached here === TEST 9: lua exception - no yield --- http_config server { - listen 127.0.0.2:8080 ssl; + listen 127.0.0.2:$TEST_NGINX_RAND_PORT_1 ssl; server_name test.com; ssl_certificate_by_lua_block { error("bad bad bad") @@ -762,7 +762,7 @@ should never reached here sock:settimeout(2000) - local ok, err = sock:connect("127.0.0.2", 8080) + local ok, err = sock:connect("127.0.0.2", $TEST_NGINX_RAND_PORT_1) if not ok then ngx.say("failed to connect: ", err) return @@ -805,7 +805,7 @@ should never reached here === TEST 10: lua exception - yield --- http_config server { - listen 127.0.0.2:8080 ssl; + listen 127.0.0.2:$TEST_NGINX_RAND_PORT_1 ssl; server_name test.com; ssl_certificate_by_lua_block { ngx.sleep(0.001) @@ -834,7 +834,7 @@ should never reached here sock:settimeout(2000) - local ok, err = sock:connect("127.0.0.2", 8080) + local ok, err = sock:connect("127.0.0.2", $TEST_NGINX_RAND_PORT_1) if not ok then ngx.say("failed to connect: ", err) return From 2b902657f370e392bd5066d2eafed7a3429af19e Mon Sep 17 00:00:00 2001 From: Datong Sun Date: Tue, 15 Mar 2022 22:12:30 +0800 Subject: [PATCH 021/254] cosocket: add function `tcpsock:setclientcert`, reimplemented `tcpsock:sslhandshake` with FFI This adds support for setting client certificate/private key that will be used later for mutual TLS handshake with a server. Also, the `tcpsock:sslhandshake` implementation has been rewritten to use FFI C API to be more performant and easier to maintain. Co-authored-by: Chrono Law --- .travis.yml | 2 +- README.markdown | 28 +- src/ngx_http_lua_socket_tcp.c | 420 +++++++++++++------------- src/ngx_http_lua_socket_tcp.h | 3 + t/062-count.t | 2 +- t/129-ssl-socket.t | 52 ++-- t/139-ssl-cert-by.t | 30 +- t/140-ssl-c-api.t | 14 +- t/142-ssl-session-store.t | 26 +- t/143-ssl-session-fetch.t | 38 +-- t/155-tls13.t | 2 +- t/162-socket-tls-handshake.t | 376 +++++++++++++++++++++++ t/166-ssl-client-hello.t | 34 +-- t/cert/mtls_ca.crt | 78 +++++ t/cert/mtls_ca.key | 27 ++ t/cert/mtls_cert_gen/.gitignore | 4 + t/cert/mtls_cert_gen/generate.sh | 23 ++ t/cert/mtls_cert_gen/mtls_ca.json | 18 ++ t/cert/mtls_cert_gen/mtls_client.json | 18 ++ t/cert/mtls_cert_gen/mtls_server.json | 17 ++ t/cert/mtls_cert_gen/profile.json | 27 ++ t/cert/mtls_client.crt | 87 ++++++ t/cert/mtls_client.key | 27 ++ t/cert/mtls_server.crt | 87 ++++++ t/cert/mtls_server.key | 27 ++ 25 files changed, 1158 insertions(+), 309 deletions(-) create mode 100644 t/162-socket-tls-handshake.t create mode 100644 t/cert/mtls_ca.crt create mode 100644 t/cert/mtls_ca.key create mode 100644 t/cert/mtls_cert_gen/.gitignore create mode 100755 t/cert/mtls_cert_gen/generate.sh create mode 100644 t/cert/mtls_cert_gen/mtls_ca.json create mode 100644 t/cert/mtls_cert_gen/mtls_client.json create mode 100644 t/cert/mtls_cert_gen/mtls_server.json create mode 100644 t/cert/mtls_cert_gen/profile.json create mode 100644 t/cert/mtls_client.crt create mode 100644 t/cert/mtls_client.key create mode 100644 t/cert/mtls_server.crt create mode 100644 t/cert/mtls_server.key diff --git a/.travis.yml b/.travis.yml index 335ae71ee6..dbf1ed6acf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -88,7 +88,7 @@ install: - git clone https://github.com/openresty/rds-json-nginx-module.git ../rds-json-nginx-module - git clone https://github.com/openresty/srcache-nginx-module.git ../srcache-nginx-module - git clone https://github.com/openresty/redis2-nginx-module.git ../redis2-nginx-module - - git clone https://github.com/openresty/lua-resty-core.git ../lua-resty-core + - git clone https://github.com/dndx/lua-resty-core.git ../lua-resty-core - git clone https://github.com/openresty/lua-resty-lrucache.git ../lua-resty-lrucache - git clone https://github.com/openresty/lua-resty-mysql.git ../lua-resty-mysql - git clone https://github.com/openresty/lua-resty-string.git ../lua-resty-string diff --git a/README.markdown b/README.markdown index 4e0b979879..7f0ac24cb1 100644 --- a/README.markdown +++ b/README.markdown @@ -977,7 +977,6 @@ TODO * add `ignore_resp_headers`, `ignore_resp_body`, and `ignore_resp` options to [ngx.location.capture](#ngxlocationcapture) and [ngx.location.capture_multi](#ngxlocationcapture_multi) methods, to allow micro performance tuning on the user side. * add automatic Lua code time slicing support by yielding and resuming the Lua VM actively via Lua's debug hooks. * add `stat` mode similar to [mod_lua](https://httpd.apache.org/docs/trunk/mod/mod_lua.html). -* cosocket: add client SSL certificate support. [Back to TOC](#table-of-contents) @@ -3594,6 +3593,7 @@ Nginx API for Lua * [ngx.socket.stream](#ngxsocketstream) * [ngx.socket.tcp](#ngxsockettcp) * [tcpsock:connect](#tcpsockconnect) +* [tcpsock:setclientcert](#tcpsocksetclientcert) * [tcpsock:sslhandshake](#tcpsocksslhandshake) * [tcpsock:send](#tcpsocksend) * [tcpsock:receive](#tcpsockreceive) @@ -7565,6 +7565,7 @@ ngx.socket.tcp Creates and returns a TCP or stream-oriented unix domain socket object (also known as one type of the "cosocket" objects). The following methods are supported on this object: * [connect](#tcpsockconnect) +* [setclientcert](#tcpsocksetclientcert) * [sslhandshake](#tcpsocksslhandshake) * [send](#tcpsocksend) * [receive](#tcpsockreceive) @@ -7724,6 +7725,31 @@ This method was first introduced in the `v0.5.0rc1` release. [Back to TOC](#nginx-api-for-lua) +tcpsock:setclientcert +-------------------- + +**syntax:** *ok, err = tcpsock:setclientcert(cert, pkey)* + +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_client_hello_by_lua** + +Set client certificate chain and corresponding private key to the TCP socket object. +The certificate chain and private key provided will be used later by the [tcpsock:sslhandshake](#tcpsocksslhandshake) method. + +* `cert` specify a client certificate chain cdata object that will be used while handshaking with +remote server. These objects can be created using [ngx.ssl.parse\_pem\_cert](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ssl.md#parse_pem_cert) +function provided by lua-resty-core. Note that specifying the `cert` option requires +corresponding `pkey` be provided too. See below. +* `pkey` specify a private key corresponds to the `cert` option above. +These objects can be created using [ngx.ssl.parse\_pem\_priv\_key](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ssl.md#parse_pem_priv_key) +function provided by lua-resty-core. + +If both of `cert` and `pkey` are `nil`, this method will clear any existing client certificate and private key +that was previously set on the cosocket object. + +This method was first introduced in the `v0.10.22` release. + +[Back to TOC](#nginx-api-for-lua) + tcpsock:sslhandshake -------------------- diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index ceaf4ff175..72549ca41e 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -22,7 +22,9 @@ static int ngx_http_lua_socket_tcp(lua_State *L); static int ngx_http_lua_socket_tcp_connect(lua_State *L); #if (NGX_HTTP_SSL) -static int ngx_http_lua_socket_tcp_sslhandshake(lua_State *L); +static void ngx_http_lua_ssl_handshake_handler(ngx_connection_t *c); +static int ngx_http_lua_ssl_handshake_retval_handler(ngx_http_request_t *r, + ngx_http_lua_socket_tcp_upstream_t *u, lua_State *L); #endif static int ngx_http_lua_socket_tcp_receive(lua_State *L); static int ngx_http_lua_socket_tcp_receiveany(lua_State *L); @@ -149,12 +151,6 @@ static void ngx_http_lua_socket_shutdown_pool_helper( ngx_http_lua_socket_pool_t *spool); static int ngx_http_lua_socket_prepare_error_retvals(ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u, lua_State *L, ngx_uint_t ft_type); -#if (NGX_HTTP_SSL) -static int ngx_http_lua_ssl_handshake_retval_handler(ngx_http_request_t *r, - ngx_http_lua_socket_tcp_upstream_t *u, lua_State *L); -static void ngx_http_lua_ssl_handshake_handler(ngx_connection_t *c); -static int ngx_http_lua_ssl_free_session(lua_State *L); -#endif static void ngx_http_lua_socket_tcp_close_connection(ngx_connection_t *c); @@ -164,6 +160,8 @@ enum { SOCKET_CONNECT_TIMEOUT_INDEX = 2, SOCKET_SEND_TIMEOUT_INDEX = 4, SOCKET_READ_TIMEOUT_INDEX = 5, + SOCKET_CLIENT_CERT_INDEX = 6 , + SOCKET_CLIENT_PKEY_INDEX = 7 , }; @@ -222,9 +220,6 @@ static char ngx_http_lua_upstream_udata_metatable_key; static char ngx_http_lua_downstream_udata_metatable_key; static char ngx_http_lua_pool_udata_metatable_key; static char ngx_http_lua_pattern_udata_metatable_key; -#if (NGX_HTTP_SSL) -static char ngx_http_lua_ssl_session_metatable_key; -#endif #define ngx_http_lua_tcp_socket_metatable_literal_key "__tcp_cosocket_mt" @@ -319,18 +314,11 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) /* {{{tcp object metatable */ lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( tcp_socket_metatable_key)); - lua_createtable(L, 0 /* narr */, 14 /* nrec */); + lua_createtable(L, 0 /* narr */, 15 /* nrec */); lua_pushcfunction(L, ngx_http_lua_socket_tcp_connect); lua_setfield(L, -2, "connect"); -#if (NGX_HTTP_SSL) - - lua_pushcfunction(L, ngx_http_lua_socket_tcp_sslhandshake); - lua_setfield(L, -2, "sslhandshake"); - -#endif - lua_pushcfunction(L, ngx_http_lua_socket_tcp_receive); lua_setfield(L, -2, "receive"); @@ -404,19 +392,6 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) lua_setfield(L, -2, "__gc"); lua_rawset(L, LUA_REGISTRYINDEX); /* }}} */ - -#if (NGX_HTTP_SSL) - - /* {{{ssl session userdata metatable */ - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - ssl_session_metatable_key)); - lua_createtable(L, 0 /* narr */, 1 /* nrec */); /* metatable */ - lua_pushcfunction(L, ngx_http_lua_ssl_free_session); - lua_setfield(L, -2, "__gc"); - lua_rawset(L, LUA_REGISTRYINDEX); - /* }}} */ - -#endif } @@ -451,7 +426,7 @@ ngx_http_lua_socket_tcp(lua_State *L) ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_YIELDABLE); - lua_createtable(L, 5 /* narr */, 1 /* nrec */); + lua_createtable(L, 7 /* narr */, 1 /* nrec */); lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( tcp_socket_metatable_key)); lua_rawget(L, LUA_REGISTRYINDEX); @@ -1559,64 +1534,73 @@ ngx_http_lua_socket_conn_error_retval_handler(ngx_http_request_t *r, #if (NGX_HTTP_SSL) -static int -ngx_http_lua_socket_tcp_sslhandshake(lua_State *L) +static const char * +ngx_http_lua_socket_tcp_check_busy(ngx_http_request_t *r, + ngx_http_lua_socket_tcp_upstream_t *u, unsigned int ops) { - int n, top; - ngx_int_t rc; - ngx_str_t name = ngx_null_string; - ngx_connection_t *c; - ngx_ssl_session_t **psession; - ngx_http_request_t *r; - ngx_http_lua_ctx_t *ctx; - ngx_http_lua_co_ctx_t *coctx; - - ngx_http_lua_socket_tcp_upstream_t *u; - - /* Lua function arguments: self [,session] [,host] [,verify] - [,send_status_req] */ + if ((ops & SOCKET_OP_CONNECT) && u->conn_waiting) { + return "socket busy connecting"; + } - n = lua_gettop(L); - if (n < 1 || n > 5) { - return luaL_error(L, "ngx.socket sslhandshake: expecting 1 ~ 5 " - "arguments (including the object), but seen %d", n); + if ((ops & SOCKET_OP_READ) && u->read_waiting) { + return "socket busy reading"; } - r = ngx_http_lua_get_req(L); - if (r == NULL) { - return luaL_error(L, "no request found"); + if ((ops & SOCKET_OP_WRITE) + && (u->write_waiting + || (u->raw_downstream + && (r->connection->buffered & NGX_HTTP_LOWLEVEL_BUFFERED)))) + { + return "socket busy writing"; } - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua tcp socket ssl handshake"); + return NULL; +} - luaL_checktype(L, 1, LUA_TTABLE); - lua_rawgeti(L, 1, SOCKET_CTX_INDEX); - u = lua_touserdata(L, -1); +int +ngx_http_lua_ffi_socket_tcp_sslhandshake(ngx_http_request_t *r, + ngx_http_lua_socket_tcp_upstream_t *u, ngx_ssl_session_t *sess, + int enable_session_reuse, ngx_str_t *server_name, int verify, + int ocsp_status_req, STACK_OF(X509) *chain, EVP_PKEY *pkey, + const char **errmsg) +{ + ngx_int_t rc, i; + ngx_connection_t *c; + ngx_http_lua_ctx_t *ctx; + ngx_http_lua_co_ctx_t *coctx; + const char *busy_msg; + ngx_ssl_conn_t *ssl_conn; + X509 *x509; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua tcp socket ssl handshake"); if (u == NULL || u->peer.connection == NULL || u->read_closed || u->write_closed) { - lua_pushnil(L); - lua_pushliteral(L, "closed"); - return 2; + *errmsg = "closed"; + return NGX_ERROR; } if (u->request != r) { - return luaL_error(L, "bad request"); + *errmsg = "bad request"; + return NGX_ERROR; } - ngx_http_lua_socket_check_busy_connecting(r, u, L); - ngx_http_lua_socket_check_busy_reading(r, u, L); - ngx_http_lua_socket_check_busy_writing(r, u, L); + busy_msg = ngx_http_lua_socket_tcp_check_busy(r, u, SOCKET_OP_CONNECT + | SOCKET_OP_READ + | SOCKET_OP_WRITE); + if (busy_msg != NULL) { + *errmsg = busy_msg; + return NGX_ERROR; + } if (u->raw_downstream || u->body_downstream) { - lua_pushnil(L); - lua_pushliteral(L, "not supported for downstream"); - return 2; + *errmsg = "not supported for downstream sockets"; + return NGX_ERROR; } c = u->peer.connection; @@ -1624,122 +1608,140 @@ ngx_http_lua_socket_tcp_sslhandshake(lua_State *L) u->ssl_session_reuse = 1; if (c->ssl && c->ssl->handshaked) { - switch (lua_type(L, 2)) { - case LUA_TUSERDATA: - lua_pushvalue(L, 2); - break; + if (sess != NULL) { + return NGX_DONE; + } - case LUA_TBOOLEAN: - if (!lua_toboolean(L, 2)) { - /* avoid generating the ssl session */ - lua_pushboolean(L, 1); - break; - } - /* fall through */ + u->ssl_session_reuse = enable_session_reuse; - default: - ngx_http_lua_ssl_handshake_retval_handler(r, u, L); - break; - } + (void) ngx_http_lua_ssl_handshake_retval_handler(r, u, NULL); - return 1; + return NGX_OK; } if (ngx_ssl_create_connection(u->conf->ssl, c, NGX_SSL_BUFFER|NGX_SSL_CLIENT) != NGX_OK) { - lua_pushnil(L); - lua_pushliteral(L, "failed to create ssl connection"); - return 2; + *errmsg = "failed to create ssl connection"; + return NGX_ERROR; } + ssl_conn = c->ssl->connection; + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { - return luaL_error(L, "no ctx found"); + return NGX_HTTP_LUA_FFI_NO_REQ_CTX; } coctx = ctx->cur_co_ctx; c->sendfile = 0; - if (n >= 2) { - if (lua_type(L, 2) == LUA_TBOOLEAN) { - u->ssl_session_reuse = lua_toboolean(L, 2); + if (sess != NULL) { + if (ngx_ssl_set_session(c, sess) != NGX_OK) { + *errmsg = "ssl set session failed"; + return NGX_ERROR; + } - } else { - psession = lua_touserdata(L, 2); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "lua ssl set session: %p", sess); - if (psession != NULL && *psession != NULL) { - if (ngx_ssl_set_session(c, *psession) != NGX_OK) { - lua_pushnil(L); - lua_pushliteral(L, "lua ssl set session failed"); - return 2; - } + } else { + u->ssl_session_reuse = enable_session_reuse; + } - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, - "lua ssl set session: %p", *psession); - } + if (chain != NULL) { + ngx_http_lua_assert(pkey != NULL); /* ensured by resty.core */ + + if (sk_X509_num(chain) < 1) { + ERR_clear_error(); + *errmsg = "invalid client certificate chain"; + return NGX_ERROR; } - if (n >= 3) { - name.data = (u_char *) lua_tolstring(L, 3, &name.len); + x509 = sk_X509_value(chain, 0); + if (x509 == NULL) { + ERR_clear_error(); + *errmsg = "ssl fetch client certificate from chain failed"; + return NGX_ERROR; + } - if (name.data) { - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua ssl server name: \"%*s\"", name.len, - name.data); + if (SSL_use_certificate(ssl_conn, x509) == 0) { + ERR_clear_error(); + *errmsg = "ssl set client certificate failed"; + return NGX_ERROR; + } -#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME + /* read rest of the chain */ - if (SSL_set_tlsext_host_name(c->ssl->connection, - (char *) name.data) - == 0) - { - lua_pushnil(L); - lua_pushliteral(L, "SSL_set_tlsext_host_name failed"); - return 2; - } + for (i = 1; i < sk_X509_num(chain); i++) { + x509 = sk_X509_value(chain, i); + if (x509 == NULL) { + ERR_clear_error(); + *errmsg = "ssl fetch client intermediate certificate from " + "chain failed"; + return NGX_ERROR; + } -#else + if (SSL_add1_chain_cert(ssl_conn, x509) == 0) { + ERR_clear_error(); + *errmsg = "ssl set client intermediate certificate failed"; + return NGX_ERROR; + } + } - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, - "lua socket SNI disabled because the current " - "version of OpenSSL lacks the support"); + if (SSL_use_PrivateKey(ssl_conn, pkey) == 0) { + ERR_clear_error(); + *errmsg = "ssl set client private key failed"; + return NGX_ERROR; + } + } + if (server_name != NULL && server_name->data != NULL) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua ssl server name: \"%V\"", server_name); + +#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME + if (SSL_set_tlsext_host_name(c->ssl->connection, + (char *) server_name->data) + == 0) + { + *errmsg = "SSL_set_tlsext_host_name failed"; + return NGX_ERROR; + } + +#else + *errmsg = "no TLS extension support"; + return NGX_ERROR; #endif - } + } - if (n >= 4) { - u->ssl_verify = lua_toboolean(L, 4); + u->ssl_verify = verify; - if (n >= 5) { - if (lua_toboolean(L, 5)) { + if (ocsp_status_req) { #ifdef NGX_HTTP_LUA_USE_OCSP - SSL_set_tlsext_status_type(c->ssl->connection, - TLSEXT_STATUSTYPE_ocsp); + SSL_set_tlsext_status_type(c->ssl->connection, + TLSEXT_STATUSTYPE_ocsp); + #else - return luaL_error(L, "no OCSP support"); + *errmsg = "no OCSP support"; + return NGX_ERROR; #endif - } - } - } - } } - dd("found sni name: %.*s %p", (int) name.len, name.data, name.data); - - if (name.len == 0) { + if (server_name->len == 0) { u->ssl_name.len = 0; } else { if (u->ssl_name.data) { /* buffer already allocated */ - if (u->ssl_name.len >= name.len) { + if (u->ssl_name.len >= server_name->len) { /* reuse it */ - ngx_memcpy(u->ssl_name.data, name.data, name.len); - u->ssl_name.len = name.len; + ngx_memcpy(u->ssl_name.data, server_name->data, + server_name->len); + u->ssl_name.len = server_name->len; } else { ngx_free(u->ssl_name.data); @@ -1750,17 +1752,15 @@ ngx_http_lua_socket_tcp_sslhandshake(lua_State *L) new_ssl_name: - u->ssl_name.data = ngx_alloc(name.len, ngx_cycle->log); + u->ssl_name.data = ngx_alloc(server_name->len, ngx_cycle->log); if (u->ssl_name.data == NULL) { u->ssl_name.len = 0; - - lua_pushnil(L); - lua_pushliteral(L, "no memory"); - return 2; + *errmsg = "no memory"; + return NGX_ERROR; } - ngx_memcpy(u->ssl_name.data, name.data, name.len); - u->ssl_name.len = name.len; + ngx_memcpy(u->ssl_name.data, server_name->data, server_name->len); + u->ssl_name.len = server_name->len; } } @@ -1774,7 +1774,8 @@ ngx_http_lua_socket_tcp_sslhandshake(lua_State *L) rc = ngx_ssl_handshake(c); - dd("ngx_ssl_handshake returned %d", (int) rc); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "ngx_ssl_handshake returned: %d", rc); if (rc == NGX_AGAIN) { if (c->write->timer_set) { @@ -1799,21 +1800,24 @@ ngx_http_lua_socket_tcp_sslhandshake(lua_State *L) r->write_event_handler = ngx_http_core_run_phases; } - return lua_yield(L, 0); + return NGX_AGAIN; } - top = lua_gettop(L); ngx_http_lua_ssl_handshake_handler(c); - return lua_gettop(L) - top; + + if (rc == NGX_ERROR) { + *errmsg = u->error_ret; + return NGX_ERROR; + } + + return NGX_OK; } static void ngx_http_lua_ssl_handshake_handler(ngx_connection_t *c) { - const char *err; int waiting; - lua_State *L; ngx_int_t rc; ngx_connection_t *dc; /* downstream connection */ ngx_http_request_t *r; @@ -1836,11 +1840,9 @@ ngx_http_lua_ssl_handshake_handler(ngx_connection_t *c) waiting = u->conn_waiting; dc = r->connection; - L = u->write_co_ctx->co; if (c->read->timedout) { - lua_pushnil(L); - lua_pushliteral(L, "timeout"); + u->error_ret = "timeout"; goto failed; } @@ -1849,19 +1851,18 @@ ngx_http_lua_ssl_handshake_handler(ngx_connection_t *c) } if (c->ssl->handshaked) { - if (u->ssl_verify) { rc = SSL_get_verify_result(c->ssl->connection); if (rc != X509_V_OK) { - lua_pushnil(L); - err = lua_pushfstring(L, "%d: %s", (int) rc, - X509_verify_cert_error_string(rc)); + u->error_ret = X509_verify_cert_error_string(rc); + u->openssl_error_code_ret = rc; llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); if (llcf->log_socket_errors) { ngx_log_error(NGX_LOG_ERR, dc->log, 0, "lua ssl " - "certificate verify error: (%s)", err); + "certificate verify error: (%d: %s)", + rc, u->error_ret); } goto failed; @@ -1872,8 +1873,7 @@ ngx_http_lua_ssl_handshake_handler(ngx_connection_t *c) if (u->ssl_name.len && ngx_ssl_check_host(c, &u->ssl_name) != NGX_OK) { - lua_pushnil(L); - lua_pushliteral(L, "certificate host mismatch"); + u->error_ret = "certificate host mismatch"; llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); if (llcf->log_socket_errors) { @@ -1892,7 +1892,7 @@ ngx_http_lua_ssl_handshake_handler(ngx_connection_t *c) ngx_http_lua_socket_handle_conn_success(r, u); } else { - (void) ngx_http_lua_ssl_handshake_retval_handler(r, u, L); + (void) ngx_http_lua_ssl_handshake_retval_handler(r, u, NULL); } if (waiting) { @@ -1902,60 +1902,83 @@ ngx_http_lua_ssl_handshake_handler(ngx_connection_t *c) return; } - lua_pushnil(L); - lua_pushliteral(L, "handshake failed"); + u->error_ret = "handshake failed"; failed: if (waiting) { u->write_prepare_retvals = - ngx_http_lua_socket_conn_error_retval_handler; - ngx_http_lua_socket_handle_conn_error(r, u, - NGX_HTTP_LUA_SOCKET_FT_SSL); + ngx_http_lua_socket_conn_error_retval_handler; + ngx_http_lua_socket_handle_conn_error(r, u, NGX_HTTP_LUA_SOCKET_FT_SSL); ngx_http_run_posted_requests(dc); } else { - (void) ngx_http_lua_socket_conn_error_retval_handler(r, u, L); + u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_SSL; + + (void) ngx_http_lua_socket_conn_error_retval_handler(r, u, NULL); } } +int +ngx_http_lua_ffi_socket_tcp_get_sslhandshake_result(ngx_http_request_t *r, + ngx_http_lua_socket_tcp_upstream_t *u, ngx_ssl_session_t **sess, + const char **errmsg, int *openssl_error_code) +{ + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua cosocket get SSL handshake result for upstream: %p", u); + + if (u->error_ret != NULL) { + *errmsg = u->error_ret; + *openssl_error_code = u->openssl_error_code_ret; + + return NGX_ERROR; + } + + *sess = u->ssl_session_ret; + + return NGX_OK; +} + + static int ngx_http_lua_ssl_handshake_retval_handler(ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u, lua_State *L) { ngx_connection_t *c; - ngx_ssl_session_t *ssl_session, **ud; + ngx_ssl_session_t *ssl_session; if (!u->ssl_session_reuse) { - lua_pushboolean(L, 1); - return 1; + return 0; } - ud = lua_newuserdata(L, sizeof(ngx_ssl_session_t *)); - c = u->peer.connection; ssl_session = ngx_ssl_get_session(c); if (ssl_session == NULL) { - *ud = NULL; + u->ssl_session_ret = NULL; } else { - *ud = ssl_session; + u->ssl_session_ret = ssl_session; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "lua ssl save session: %p", ssl_session); - - /* set up the __gc metamethod */ - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - ssl_session_metatable_key)); - lua_rawget(L, LUA_REGISTRYINDEX); - lua_setmetatable(L, -2); } - return 1; + return 0; } + +void +ngx_http_lua_ffi_ssl_free_session(ngx_ssl_session_t *sess) +{ + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua ssl free session: %p", sess); + + ngx_ssl_free_session(sess); +} + + #endif /* NGX_HTTP_SSL */ @@ -2008,12 +2031,14 @@ ngx_http_lua_socket_prepare_error_retvals(ngx_http_request_t *r, u_char errstr[NGX_MAX_ERROR_STR]; u_char *p; - if (ft_type & (NGX_HTTP_LUA_SOCKET_FT_RESOLVER - | NGX_HTTP_LUA_SOCKET_FT_SSL)) - { + if (ft_type & NGX_HTTP_LUA_SOCKET_FT_RESOLVER) { return 2; } + if (ft_type & NGX_HTTP_LUA_SOCKET_FT_SSL) { + return 0; + } + lua_pushnil(L); if (ft_type & NGX_HTTP_LUA_SOCKET_FT_TIMEOUT) { @@ -6105,27 +6130,6 @@ ngx_http_lua_coctx_cleanup(void *data) } -#if (NGX_HTTP_SSL) - -static int -ngx_http_lua_ssl_free_session(lua_State *L) -{ - ngx_ssl_session_t **psession; - - psession = lua_touserdata(L, 1); - if (psession && *psession != NULL) { - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "lua ssl free session: %p", *psession); - - ngx_ssl_free_session(*psession); - } - - return 0; -} - -#endif /* NGX_HTTP_SSL */ - - void ngx_http_lua_cleanup_conn_pools(lua_State *L) { diff --git a/src/ngx_http_lua_socket_tcp.h b/src/ngx_http_lua_socket_tcp.h index a0a5a5181a..ee9411bc8d 100644 --- a/src/ngx_http_lua_socket_tcp.h +++ b/src/ngx_http_lua_socket_tcp.h @@ -120,6 +120,9 @@ struct ngx_http_lua_socket_tcp_upstream_s { #if (NGX_HTTP_SSL) ngx_str_t ssl_name; + ngx_ssl_session_t *ssl_session_ret; + const char *error_ret; + int openssl_error_code_ret; #endif unsigned ft_type:16; diff --git a/t/062-count.t b/t/062-count.t index 104126281a..d977909bb6 100644 --- a/t/062-count.t +++ b/t/062-count.t @@ -459,7 +459,7 @@ worker: 4 --- request GET /test --- response_body -n = 14 +n = 15 --- no_error_log [error] diff --git a/t/129-ssl-socket.t b/t/129-ssl-socket.t index c26f0cec53..cbbd679468 100644 --- a/t/129-ssl-socket.t +++ b/t/129-ssl-socket.t @@ -106,7 +106,7 @@ __DATA__ GET /t --- response_body_like chop \Aconnected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 59 bytes. received: HTTP/1.1 (?:200 OK|302 Found) close: 1 nil @@ -190,7 +190,7 @@ SSL reused session GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 53 bytes. received: HTTP/1.1 201 Created close: 1 nil @@ -271,7 +271,7 @@ SSL reused session GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 58 bytes. received: HTTP/1.1 302 Moved Temporarily close: 1 nil @@ -355,12 +355,12 @@ SSL reused session GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 200 OK close: 1 nil connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 200 OK close: 1 nil @@ -603,7 +603,7 @@ SSL reused session GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 80 bytes. received: HTTP/1.1 404 Not Found close: 1 nil @@ -688,7 +688,7 @@ $::DSTRootCertificate" GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 58 bytes. received: HTTP/1.1 302 Moved Temporarily close: 1 nil @@ -1008,7 +1008,7 @@ $::DSTRootCertificate" GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 58 bytes. received: HTTP/1.1 302 Moved Temporarily close: 1 nil @@ -1087,7 +1087,7 @@ SSL reused session GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 58 bytes. received: HTTP/1.1 302 Moved Temporarily close: 1 nil @@ -1179,7 +1179,7 @@ SSL reused session GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 53 bytes. received: HTTP/1.1 200 OK close: 1 nil @@ -1269,7 +1269,7 @@ SSL reused session GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 53 bytes. received: HTTP/1.1 200 OK close: 1 nil @@ -1418,13 +1418,13 @@ $::DSTRootCertificate" GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata set keepalive: 1 nil connected: 1 -ssl handshake: userdata +ssl handshake: cdata set keepalive: 1 nil connected: 1 -ssl handshake: userdata +ssl handshake: cdata set keepalive: 1 nil --- log_level: debug @@ -1494,13 +1494,13 @@ $::DSTRootCertificate" GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata set keepalive: 1 nil connected: 1 -ssl handshake: userdata +ssl handshake: cdata set keepalive: 1 nil connected: 1 -ssl handshake: userdata +ssl handshake: cdata set keepalive: 1 nil --- log_level: debug @@ -1637,7 +1637,7 @@ attempt to call method 'sslhandshake' (a nil value) GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -1742,7 +1742,7 @@ SSL reused session GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -2031,8 +2031,8 @@ SSL reused session GET /t --- response_body connected: 1 -ssl handshake: userdata -ssl handshake: userdata +ssl handshake: cdata +ssl handshake: cdata sent http request: 58 bytes. received: HTTP/1.1 302 Moved Temporarily close: 1 nil @@ -2232,7 +2232,7 @@ SSL reused session GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata --- user_files eval ">>> test.key @@ -2405,7 +2405,7 @@ SSL reused session GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -2529,7 +2529,7 @@ SSL reused session -=== TEST 31: handshake, too many arguments +=== TEST 31: handshake, too few arguments --- config server_tokens off; resolver $TEST_NGINX_RESOLVER ipv6=off; @@ -2633,7 +2633,7 @@ qr/\[error\] .* ngx.socket sslhandshake: expecting 1 ~ 5 arguments \(including t GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 53 bytes. received: HTTP/1.1 200 OK close: 1 nil @@ -2726,7 +2726,7 @@ SSL reused session GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 53 bytes. received: HTTP/1.1 200 OK close: 1 nil diff --git a/t/139-ssl-cert-by.t b/t/139-ssl-cert-by.t index 502e0ac184..2180466907 100644 --- a/t/139-ssl-cert-by.t +++ b/t/139-ssl-cert-by.t @@ -100,7 +100,7 @@ __DATA__ GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -209,7 +209,7 @@ ssl_certificate_by_lua\(nginx.conf:28\):1: ssl cert by lua is running!,/ GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -314,7 +314,7 @@ qr/elapsed in ssl cert by lua: 0.(?:09|1\d)\d+,/, GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -432,7 +432,7 @@ my timer run! GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -924,7 +924,7 @@ should never reached here GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata --- error_log lua ssl server name: "test.com" @@ -1137,7 +1137,7 @@ print("ssl cert by lua is running!") GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -1248,7 +1248,7 @@ a.lua:1: ssl cert by lua is running! GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -1372,7 +1372,7 @@ lua ssl server name: "test.com" GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -1468,7 +1468,7 @@ GitHub openresty/lua-resty-core#42 GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -1566,7 +1566,7 @@ github issue #723 GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -1668,7 +1668,7 @@ ssl_certificate_by_lua:1: ssl cert by lua is running! GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 59 bytes. received: HTTP/1.1 200 OK received: Server: nginx @@ -1963,7 +1963,7 @@ qr/\[info\] .*? SSL_do_handshake\(\) failed\b/, GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -2063,7 +2063,7 @@ client ip: 127.0.0.1 GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -2221,7 +2221,7 @@ qr/elapsed in ssl_certificate_by_lua\*: 0\.(?:09|1\d)\d+,/, GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata --- no_error_log [error] [alert] @@ -2311,7 +2311,7 @@ ssl handshake: userdata GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata --- no_error_log [error] [alert] diff --git a/t/140-ssl-c-api.t b/t/140-ssl-c-api.t index 31a6e2f434..5b2ae018fe 100644 --- a/t/140-ssl-c-api.t +++ b/t/140-ssl-c-api.t @@ -217,7 +217,7 @@ __DATA__ GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -371,7 +371,7 @@ lua ssl server name: "test.com" GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -499,7 +499,7 @@ lua ssl server name: "test.com" GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -650,7 +650,7 @@ failed to parse PEM priv key: PEM_read_bio_PrivateKey() failed GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -800,7 +800,7 @@ lua ssl server name: "test.com" GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -1182,7 +1182,7 @@ client certificate subject: nil GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -1306,7 +1306,7 @@ lua ssl server name: "test.com" GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx diff --git a/t/142-ssl-session-store.t b/t/142-ssl-session-store.t index 6769a336bc..61598732be 100644 --- a/t/142-ssl-session-store.t +++ b/t/142-ssl-session-store.t @@ -77,7 +77,7 @@ __DATA__ GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata close: 1 nil --- error_log @@ -152,7 +152,7 @@ ssl_session_store_by_lua\(nginx\.conf:25\):1: ssl session store by lua is runnin GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata close: 1 nil --- error_log @@ -227,7 +227,7 @@ API disabled in the context of ssl_session_store_by_lua* GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata close: 1 nil --- error_log @@ -319,7 +319,7 @@ my timer run! GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata close: 1 nil --- error_log @@ -390,7 +390,7 @@ API disabled in the context of ssl_session_store_by_lua* GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata close: 1 nil --- error_log @@ -462,7 +462,7 @@ ngx.exit does not yield and the error code is eaten. GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata close: 1 nil --- error_log @@ -532,7 +532,7 @@ ssl_session_store_by_lua*: handler return value: 0, sess new cb exit code: 0 GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata close: 1 nil --- error_log @@ -600,7 +600,7 @@ should never reached here GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata close: 1 nil --- error_log @@ -671,7 +671,7 @@ get_phase: ssl_session_store GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata close: 1 nil --- error_log eval @@ -744,7 +744,7 @@ print("ssl store session by lua is running!") GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata close: 1 nil --- error_log @@ -820,7 +820,7 @@ a.lua:1: ssl store session by lua is running! GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata close: 1 nil --- no_error_log @@ -891,7 +891,7 @@ qr/\[emerg\] .*? "ssl_session_store_by_lua_block" directive is not allowed here GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata close: 1 nil --- error_log @@ -955,7 +955,7 @@ ssl_session_store_by_lua(nginx.conf:25):1: ssl session store by lua is running! GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata close: 1 nil --- error_log eval qr/ssl_session_store_by_lua\*: skipped since TLS version >= 1\.3 \(\d+\)/ diff --git a/t/143-ssl-session-fetch.t b/t/143-ssl-session-fetch.t index 0e90c23665..8c5174dd94 100644 --- a/t/143-ssl-session-fetch.t +++ b/t/143-ssl-session-fetch.t @@ -80,7 +80,7 @@ __DATA__ GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata close: 1 nil --- grep_error_log eval: qr/ssl_session_fetch_by_lua\(nginx\.conf:\d+\):.*?,|\bssl session fetch: connection reusable: \d+|\breusable connection: \d+/ @@ -180,7 +180,7 @@ ssl_session_fetch_by_lua\(nginx\.conf:25\):1: ssl fetch sess by lua is running!, GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata close: 1 nil --- grep_error_log eval @@ -264,7 +264,7 @@ qr/elapsed in ssl fetch session by lua: 0.(?:09|1[01])\d+,/, GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata close: 1 nil --- grep_error_log eval @@ -365,7 +365,7 @@ qr/my timer run!/s GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata close: 1 nil --- grep_error_log eval @@ -446,7 +446,7 @@ qr/received memc reply: OK/s GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata close: 1 nil --- grep_error_log eval @@ -527,7 +527,7 @@ should never reached here GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata close: 1 nil --- grep_error_log eval @@ -609,7 +609,7 @@ should never reached here GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata close: 1 nil --- grep_error_log eval @@ -690,7 +690,7 @@ should never reached here GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata close: 1 nil --- grep_error_log eval @@ -773,7 +773,7 @@ should never reached here GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata close: 1 nil --- grep_error_log eval @@ -853,7 +853,7 @@ should never reached here GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata close: 1 nil --- grep_error_log eval @@ -939,7 +939,7 @@ qr/get_phase: ssl_session_fetch/s GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata close: 1 nil --- grep_error_log eval @@ -1025,7 +1025,7 @@ print("ssl fetch sess by lua is running!") GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata close: 1 nil --- grep_error_log eval @@ -1109,7 +1109,7 @@ qr/\S+:\d+: ssl fetch sess by lua is running!/s GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata close: 1 nil --- grep_error_log eval @@ -1285,7 +1285,7 @@ GET /t GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata close: 1 nil --- no_error_log [warn] @@ -1346,7 +1346,7 @@ close: 1 nil GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata close: 1 nil --- grep_error_log eval: qr/ssl_session_fetch_by_lua\(nginx\.conf:\d+\):.*?,|\bssl session fetch: connection reusable: \d+|\breusable connection: \d+/ --- grep_error_log_out eval @@ -1444,7 +1444,7 @@ ssl_session_fetch_by_lua\(nginx\.conf:\d+\):1: ssl_session_fetch_by_lua\* is run GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata close: 1 nil --- grep_error_log eval qr/elapsed in ssl_session_fetch_by_lua\*: 0\.(?:09|1[01])\d+,/, @@ -1537,7 +1537,7 @@ qr/elapsed in ssl_session_fetch_by_lua\*: 0\.(?:09|1[01])\d+,/, GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata close: 1 nil --- grep_error_log eval: qr/received memc reply of \d+ bytes/ --- grep_error_log_out eval @@ -1632,7 +1632,7 @@ close: 1 nil GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata close: 1 nil --- grep_error_log eval: qr/uthread: [^.,]+/ --- grep_error_log_out eval @@ -1732,7 +1732,7 @@ uthread: failed to kill: already waited or killed GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata close: 1 nil --- grep_error_log eval: qr/uthread: [^.,]+/ --- grep_error_log_out eval diff --git a/t/155-tls13.t b/t/155-tls13.t index 9f7cf86d2e..4e684cd335 100644 --- a/t/155-tls13.t +++ b/t/155-tls13.t @@ -91,7 +91,7 @@ __DATA__ GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata --- user_files eval ">>> test.key diff --git a/t/162-socket-tls-handshake.t b/t/162-socket-tls-handshake.t new file mode 100644 index 0000000000..c4076af042 --- /dev/null +++ b/t/162-socket-tls-handshake.t @@ -0,0 +1,376 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use Test::Nginx::Socket::Lua; + +repeat_each(2); + +plan tests => repeat_each() * 43; + +$ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; + +log_level 'debug'; + +no_long_string(); +#no_diff(); + +sub read_file { + my $infile = shift; + open my $in, $infile + or die "cannot open $infile for reading: $!"; + my $cert = do { local $/; <$in> }; + close $in; + $cert; +} + +our $MTLSCA = read_file("t/cert/mtls_ca.crt"); +our $MTLSClient = read_file("t/cert/mtls_client.crt"); +our $MTLSClientKey = read_file("t/cert/mtls_client.key"); +our $MTLSServer = read_file("t/cert/mtls_server.crt"); +our $MTLSServerKey = read_file("t/cert/mtls_server.key"); + +our $HtmlDir = html_dir; + +our $mtls_http_config = <<"_EOC_"; +server { + listen unix:$::HtmlDir/mtls.sock ssl; + + ssl_certificate $::HtmlDir/mtls_server.crt; + ssl_certificate_key $::HtmlDir/mtls_server.key; + ssl_client_certificate $::HtmlDir/mtls_ca.crt; + ssl_verify_client on; + server_tokens off; + + location / { + return 200 "hello, \$ssl_client_s_dn"; + } +} +_EOC_ + +our $mtls_user_files = <<"_EOC_"; +>>> mtls_server.key +$::MTLSServerKey +>>> mtls_server.crt +$::MTLSServer +>>> mtls_ca.crt +$::MTLSCA +>>> mtls_client.key +$::MTLSClientKey +>>> mtls_client.crt +$::MTLSClient +_EOC_ + +run_tests(); + +__DATA__ + +=== TEST 1: sanity: www.google.com +--- config + server_tokens off; + resolver $TEST_NGINX_RESOLVER ipv6=off; + + location /t { + content_by_lua_block { + -- avoid flushing google in "check leak" testing mode: + local counter = package.loaded.counter + if not counter then + counter = 1 + elseif counter >= 2 then + return ngx.exit(503) + else + counter = counter + 1 + end + + package.loaded.counter = counter + + do + local sock = ngx.socket.tcp() + sock:settimeout(2000) + + local ok, err = sock:connect("www.google.com", 443) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake() + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + local req = "GET / HTTP/1.1\r\nHost: www.google.com\r\nConnection: close\r\n\r\n" + local bytes, err = sock:send(req) + if not bytes then + ngx.say("failed to send http request: ", err) + return + end + + ngx.say("sent http request: ", bytes, " bytes.") + + local line, err = sock:receive() + if not line then + ngx.say("failed to receive response status line: ", err) + return + end + + ngx.say("received: ", line) + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + + collectgarbage() + } + } +--- request +GET /t +--- response_body_like chop +\Aconnected: 1 +ssl handshake: cdata +sent http request: 59 bytes. +received: HTTP/1.1 (?:200 OK|302 Found) +close: 1 nil +\z +--- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+/ +--- grep_error_log_out eval +qr/^lua ssl save session: ([0-9A-F]+) +lua ssl free session: ([0-9A-F]+) +$/ +--- no_error_log +lua ssl server name: +SSL reused session +[error] +[alert] +--- timeout: 5 + + + +=== TEST 2: mutual TLS handshake, upstream is not accessible without client certs +--- http_config eval: $::mtls_http_config +--- config eval +" + location /t { + content_by_lua_block { + local sock = ngx.socket.tcp() + local ok, err = sock:connect('unix:$::HtmlDir/mtls.sock') + if not ok then + ngx.say('failed to connect: ', err) + end + + assert(sock:sslhandshake()) + + ngx.say('connected: ', ok) + + local req = 'GET /\\r\\n' + + local bytes, err = sock:send(req) + if not bytes then + ngx.say('failed to send request: ', err) + return + end + + ngx.say('request sent: ', bytes) + + ngx.say(sock:receive('*a')) + + assert(sock:close()) + } + } +" +--- user_files eval: $::mtls_user_files +--- request +GET /t +--- response_body_like: 400 No required SSL certificate was sent +--- no_error_log +[alert] +[error] +[crit] +[emerg] + + + +=== TEST 3: mutual TLS handshake, upstream is accessible with client certs +--- http_config eval: $::mtls_http_config +--- config eval +" + location /t { + content_by_lua_block { + local sock = ngx.socket.tcp() + local ok, err = sock:connect('unix:$::HtmlDir/mtls.sock') + if not ok then + ngx.say('failed to connect: ', err) + end + + local f = assert(io.open('$::HtmlDir/mtls_client.crt')) + local cert_data = f:read('*a') + f:close() + + f = assert(io.open('$::HtmlDir/mtls_client.key')) + local key_data = f:read('*a') + f:close() + + local ssl = require('ngx.ssl') + + local chain = assert(ssl.parse_pem_cert(cert_data)) + local priv = assert(ssl.parse_pem_priv_key(key_data)) + + sock:setclientcert(chain, priv) + + assert(sock:sslhandshake()) + + ngx.say('connected: ', ok) + + local req = 'GET /\\r\\n' + + local bytes, err = sock:send(req) + if not bytes then + ngx.say('failed to send request: ', err) + return + end + + ngx.say('request sent: ', bytes) + + ngx.say(sock:receive('*a')) + + assert(sock:close()) + } + } +" +--- user_files eval: $::mtls_user_files +--- request +GET /t +--- response_body +connected: 1 +request sent: 7 +hello, CN=foo@example.com,O=OpenResty,ST=California,C=US +--- no_error_log +[alert] +[error] +[crit] +[emerg] + + + +=== TEST 4: incorrect type of client cert +--- config + location /t { + content_by_lua_block { + local sock = ngx.socket.tcp() + + local ok, err = sock:setclientcert("doesnt", "work") + if not ok then + ngx.say('failed to setclientcert: ', err) + return + end + + assert(sock:close()) + } + } +--- request +GET /t +--- response_body +failed to setclientcert: bad cert arg: cdata expected, got string +--- no_error_log +[alert] +[error] +[crit] +[emerg] + + + +=== TEST 5: incorrect type of client key +--- config eval +" + location /t { + content_by_lua_block { + local sock = ngx.socket.tcp() + + local f = assert(io.open('$::HtmlDir/mtls_client.crt')) + local cert_data = f:read('*a') + f:close() + + local ssl = require('ngx.ssl') + + local chain = assert(ssl.parse_pem_cert(cert_data)) + + local ok, err = sock:setclientcert(chain, 'work') + if not ok then + ngx.say('failed to setclientcert: ', err) + return + end + + assert(sock:close()) + } + } +" +--- user_files eval: $::mtls_user_files +--- request +GET /t +--- response_body +failed to setclientcert: bad pkey arg: cdata expected, got string +--- no_error_log +[alert] +[error] +[crit] +[emerg] + + + +=== TEST 6: missing client cert +--- config + location /t { + content_by_lua_block { + local sock = ngx.socket.tcp() + + local ok, err = sock:setclientcert(nil, "work") + if not ok then + ngx.say('failed to setclientcert: ', err) + return + end + + assert(sock:close()) + } + } +--- request +GET /t +--- response_body +failed to setclientcert: client certificate must be supplied with corresponding private key +--- no_error_log +[alert] +[error] +[crit] +[emerg] + + + +=== TEST 7: missing private key +--- config + location /t { + content_by_lua_block { + local sock = ngx.socket.tcp() + + local ok, err = sock:setclientcert('doesnt', nil) + if not ok then + ngx.say('failed to setclientcert: ', err) + return + end + + assert(sock:close()) + } + } +--- request +GET /t +--- response_body +failed to setclientcert: client certificate must be supplied with corresponding private key +--- no_error_log +[alert] +[error] +[crit] +[emerg] + + + diff --git a/t/166-ssl-client-hello.t b/t/166-ssl-client-hello.t index 79787f63a0..da021300af 100644 --- a/t/166-ssl-client-hello.t +++ b/t/166-ssl-client-hello.t @@ -100,7 +100,7 @@ __DATA__ GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -209,7 +209,7 @@ ssl_client_hello_by_lua:1: ssl client hello by lua is running!,/ GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -314,7 +314,7 @@ qr/elapsed in ssl client hello by lua: 0.(?:09|1\d)\d+,/, GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -432,7 +432,7 @@ my timer run! GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -924,7 +924,7 @@ should never reached here GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata --- error_log lua ssl server name: "test.com" @@ -1135,7 +1135,7 @@ print("ssl client hello by lua is running!") GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -1246,7 +1246,7 @@ a.lua:1: ssl client hello by lua is running! GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -1370,7 +1370,7 @@ lua ssl server name: "test.com" GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -1466,7 +1466,7 @@ GitHub openresty/lua-resty-core#42 GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -1561,7 +1561,7 @@ ssl_client_hello_by_lua:1: ssl client hello by lua is running! GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -1817,7 +1817,7 @@ ssl_client_hello_by_lua:1: ssl client hello by lua is running! GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -2005,7 +2005,7 @@ ssl_client_hello_by_lua:1: ssl client hello by lua is running! GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 57 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -2103,7 +2103,7 @@ ssl_client_hello_by_lua:1: ssl client hello by lua in server2 is running! GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -2208,7 +2208,7 @@ ssl_client_hello_by_lua:1: ssl client hello by lua is running! GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -2308,7 +2308,7 @@ client ip: 127.0.0.1 GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx @@ -2465,7 +2465,7 @@ qr/elapsed in ssl_client_hello_by_lua\*: 0\.(?:09|1\d)\d+,/, GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata --- no_error_log [error] [alert] @@ -2555,7 +2555,7 @@ ssl handshake: userdata GET /t --- response_body connected: 1 -ssl handshake: userdata +ssl handshake: cdata --- no_error_log [error] [alert] diff --git a/t/cert/mtls_ca.crt b/t/cert/mtls_ca.crt new file mode 100644 index 0000000000..1fe7e1f985 --- /dev/null +++ b/t/cert/mtls_ca.crt @@ -0,0 +1,78 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 32:ed:21:56:d8:4e:aa:03:89:a9:4a:a4:e2:85:2d:8a:3b:2b:89:22 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C = US, ST = California, O = OpenResty, CN = OpenResty Testing Root CA + Validity + Not Before: Mar 13 15:49:00 2022 GMT + Not After : Mar 8 15:49:00 2042 GMT + Subject: C = US, ST = California, O = OpenResty, CN = OpenResty Testing Root CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (2048 bit) + Modulus: + 00:e6:37:d2:c6:17:36:c7:b2:7f:7d:cf:d0:62:87: + 99:d9:21:b8:de:ff:d8:e2:3a:1c:68:90:8f:ce:17: + 68:22:b0:60:30:cc:29:e8:34:ee:ff:b2:25:de:6e: + 1a:d4:df:10:19:11:4b:40:61:d3:a9:4d:80:ed:97: + 81:4e:c5:74:e8:4d:63:e3:5f:21:bc:5a:6e:22:a0: + 17:91:c1:cb:25:53:9b:9d:4e:e1:51:5b:f6:52:e7: + 0a:27:f6:16:c2:31:cb:6c:47:f4:89:51:15:cc:06: + be:31:3e:1c:ea:ee:81:9b:c4:97:96:fd:e5:1c:95: + 9e:c0:65:cd:a9:9a:cb:68:67:f2:62:a0:21:eb:5a: + c5:a1:92:ed:32:41:28:f9:47:34:eb:44:ae:d6:e7: + 76:71:11:98:c9:2e:ce:6c:7c:10:1b:c7:4c:c3:14: + 89:4e:d9:4c:d9:c7:43:e9:3c:29:ca:62:a9:91:b3: + 87:e7:d7:b4:18:ab:65:f9:6b:ed:82:ca:a1:36:35: + 18:05:cb:5c:24:26:13:13:f8:99:ac:99:be:9b:a6: + 73:df:0d:16:95:b1:dc:be:fe:7a:c2:b6:dc:c8:93: + cf:10:e0:29:03:0e:28:78:18:84:ee:14:92:ab:be: + 5a:a0:14:a2:4a:2f:d3:d0:b8:0e:00:d2:5a:cd:e4: + bd:a1 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + F0:D7:4B:14:73:E1:67:00:6B:54:B4:19:20:76:12:9F:9D:8E:C8:09 + Signature Algorithm: sha256WithRSAEncryption + 6d:52:21:6d:6e:8c:e5:4a:28:07:65:6d:d8:7c:23:2e:c6:c1: + d0:ec:27:b3:b0:c3:d3:e8:fa:72:b9:de:32:4e:ff:97:8d:86: + a9:6d:b3:a9:b4:2d:77:ca:28:97:6a:3d:7b:a2:15:ed:34:dc: + 72:9f:6f:e7:01:0c:d3:28:6a:80:1b:50:09:fd:d7:2c:d8:92: + d5:10:c4:73:15:20:7d:99:dc:de:30:7b:3c:6e:e9:66:b2:0e: + 4e:1a:c1:51:57:6e:5b:b0:a9:f6:ff:0b:8f:07:67:31:40:5b: + 11:a9:06:d3:d3:76:c5:d2:56:95:9a:9e:4a:16:44:4b:32:e5: + af:dd:4b:4d:5d:57:b8:85:69:36:93:2a:c6:0c:8f:e1:42:35: + be:8e:f3:e7:35:d3:2c:3a:03:31:40:75:8e:e8:dd:57:35:20: + 5e:18:a9:76:ce:85:be:7e:3a:cf:6e:08:58:5b:47:d5:e9:c4: + ec:0e:e9:8e:3c:2d:5c:7b:59:20:5b:24:92:a0:e0:1e:a3:5a: + 67:d8:ff:7f:a5:82:f1:df:db:05:65:79:88:b1:3c:e6:01:d1: + 5a:c7:d2:6e:9a:e6:a2:da:4a:c7:19:78:d9:14:71:6e:1f:70: + f3:41:e5:b3:78:31:d5:22:0e:7c:1a:b2:43:d9:86:ff:53:ea: + 2b:ba:d2:27 +-----BEGIN CERTIFICATE----- +MIIDhDCCAmygAwIBAgIUMu0hVthOqgOJqUqk4oUtijsriSIwDQYJKoZIhvcNAQEL +BQAwWjELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAoT +CU9wZW5SZXN0eTEiMCAGA1UEAxMZT3BlblJlc3R5IFRlc3RpbmcgUm9vdCBDQTAe +Fw0yMjAzMTMxNTQ5MDBaFw00MjAzMDgxNTQ5MDBaMFoxCzAJBgNVBAYTAlVTMRMw +EQYDVQQIEwpDYWxpZm9ybmlhMRIwEAYDVQQKEwlPcGVuUmVzdHkxIjAgBgNVBAMT +GU9wZW5SZXN0eSBUZXN0aW5nIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IB +DwAwggEKAoIBAQDmN9LGFzbHsn99z9Bih5nZIbje/9jiOhxokI/OF2gisGAwzCno +NO7/siXebhrU3xAZEUtAYdOpTYDtl4FOxXToTWPjXyG8Wm4ioBeRwcslU5udTuFR +W/ZS5won9hbCMctsR/SJURXMBr4xPhzq7oGbxJeW/eUclZ7AZc2pmstoZ/JioCHr +WsWhku0yQSj5RzTrRK7W53ZxEZjJLs5sfBAbx0zDFIlO2UzZx0PpPCnKYqmRs4fn +17QYq2X5a+2CyqE2NRgFy1wkJhMT+Jmsmb6bpnPfDRaVsdy+/nrCttzIk88Q4CkD +Dih4GITuFJKrvlqgFKJKL9PQuA4A0lrN5L2hAgMBAAGjQjBAMA4GA1UdDwEB/wQE +AwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTw10sUc+FnAGtUtBkgdhKf +nY7ICTANBgkqhkiG9w0BAQsFAAOCAQEAbVIhbW6M5UooB2Vt2HwjLsbB0Owns7DD +0+j6crneMk7/l42GqW2zqbQtd8ool2o9e6IV7TTccp9v5wEM0yhqgBtQCf3XLNiS +1RDEcxUgfZnc3jB7PG7pZrIOThrBUVduW7Cp9v8LjwdnMUBbEakG09N2xdJWlZqe +ShZESzLlr91LTV1XuIVpNpMqxgyP4UI1vo7z5zXTLDoDMUB1jujdVzUgXhipds6F +vn46z24IWFtH1enE7A7pjjwtXHtZIFskkqDgHqNaZ9j/f6WC8d/bBWV5iLE85gHR +WsfSbprmotpKxxl42RRxbh9w80Hls3gx1SIOfBqyQ9mG/1PqK7rSJw== +-----END CERTIFICATE----- diff --git a/t/cert/mtls_ca.key b/t/cert/mtls_ca.key new file mode 100644 index 0000000000..d39b42f9d9 --- /dev/null +++ b/t/cert/mtls_ca.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEA5jfSxhc2x7J/fc/QYoeZ2SG43v/Y4jocaJCPzhdoIrBgMMwp +6DTu/7Il3m4a1N8QGRFLQGHTqU2A7ZeBTsV06E1j418hvFpuIqAXkcHLJVObnU7h +UVv2UucKJ/YWwjHLbEf0iVEVzAa+MT4c6u6Bm8SXlv3lHJWewGXNqZrLaGfyYqAh +61rFoZLtMkEo+Uc060Su1ud2cRGYyS7ObHwQG8dMwxSJTtlM2cdD6TwpymKpkbOH +59e0GKtl+WvtgsqhNjUYBctcJCYTE/iZrJm+m6Zz3w0WlbHcvv56wrbcyJPPEOAp +Aw4oeBiE7hSSq75aoBSiSi/T0LgOANJazeS9oQIDAQABAoIBAQDhH9+uNE8uUv/X +MNvvLfklWpOlBf25o+fZ3NuzRjJgEafOsCee2fyI8FWVwIfeeE8OpFm5GLDZk1+r +dwdM10xuSheO5Z1gyfF/TJwfvamA09SNrPArFkm3YhUNZNl2hykMtwSLL06oWEOu +dbXjit4VS9aNIbTlEe7O5/6Ih0W3zmr1yvUua2swmAZMx3GFA4kbjZZ9vDs27sdu +K+VY3DYRbq1HkiNFT0otfke5bObFBCG7Yp8JLyhYaIkGYFoBXuZ6JNY8EuU2+YyP +6r40tJ7StR1Q6eZJh9/1leaYGZLCh5oFyKpilTuxHbRbr5A28RJKjKvPsdDgTtQn +yHGg70FRAoGBAOhC3TQlFcT2WCCZHHql9JEEHnHVBWnL3Jg7VJuL1i6pEIz7qQkW +AtBEIY/nnTcVNfJ6eXznYtutYvvRSgQTUsBNRoj3s1z9wKOo4uw4LoIUXDEmHCr+ +49DiQyIO21SNMHA+dVxvGRDDjLI9Uc+Scb64QOodoX75HLRZG++24mtdAoGBAP2/ +gCjga2p8Jx9UnhIcrEIIGANyxEQeBdhF56Nt9CJy/Iwi3a6qQ/GkbeoDm5FhXnXo +xcBaHyv2lwi4uO/hONY8eRnYxAWMwAKMZe6VnU1hWI2Ytkh+OcMPMh7NIGQf6X1o +JZrBtnTms060TuuDjLeIlaubDR/xDrMWTMKjKbsVAoGAVLuYAZ8J6xpIGlRhbGlA +6OrMxJCHcgpahvsWKc0BLXKmRBjHmTX7fslsSRihZWgKj1SZH7U2fpgpxV6cFxKJ +nPhUJEHhoKo+bjZ92tnANdqBq7iQjCsDJ8Bz52fuIlGD+1795+PsDA6bNKdkQkrV +zlNf80kuEqmFDFJ5+6EHx00CgYAf+jkpbZa71aeMgDpnZ+uhaqm0DYuEVhBAgBa/ +9sRUbw86jc5IC7cCRcmAOzIosQ+ZZls9cV4KSUohVD4iJMzn2rkcM8AIPwOXjp/t +4DbxoHnrZjpaimW3Gjwju5AAbjEbl7tddFoNA2HHYlurvGlIW9MYzDJsOxGyKfZE +dRF2PQKBgQDUKNHgDYEjLJ99S5Fm5zN/64bKzzDtktGdqOxik5pBKcs/BvOdLM0i +eCjGz/3qrEoenFIBwF/IRz3ug90Zr8bWOu6DudReflAKI/N13dZ2gOTAfaX4ljJF +w0ohSi6xs+mu1GmtipGtNxHi/J3na2BeSnSRFSUg6Zd+oh8BZQKmNg== +-----END RSA PRIVATE KEY----- diff --git a/t/cert/mtls_cert_gen/.gitignore b/t/cert/mtls_cert_gen/.gitignore new file mode 100644 index 0000000000..f375caaefe --- /dev/null +++ b/t/cert/mtls_cert_gen/.gitignore @@ -0,0 +1,4 @@ +*.pem +*.csr +cfssl +cfssljson diff --git a/t/cert/mtls_cert_gen/generate.sh b/t/cert/mtls_cert_gen/generate.sh new file mode 100755 index 0000000000..46625fdd07 --- /dev/null +++ b/t/cert/mtls_cert_gen/generate.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +rm *.pem *.csr cfssl cfssljson + +wget -O cfssl https://github.com/cloudflare/cfssl/releases/download/v1.6.1/cfssl_1.6.1_linux_amd64 +wget -O cfssljson https://github.com/cloudflare/cfssl/releases/download/v1.6.1/cfssljson_1.6.1_linux_amd64 +chmod +x cfssl cfssljson + +./cfssl gencert -initca -config profile.json mtls_ca.json | ./cfssljson -bare mtls_ca + +./cfssl gencert -ca mtls_ca.pem -ca-key mtls_ca-key.pem -config profile.json -profile=client mtls_client.json | ./cfssljson -bare mtls_client +./cfssl gencert -ca mtls_ca.pem -ca-key mtls_ca-key.pem -config profile.json -profile=server mtls_server.json | ./cfssljson -bare mtls_server + +openssl x509 -in mtls_ca.pem -text > ../mtls_ca.crt +mv mtls_ca-key.pem ../mtls_ca.key + +openssl x509 -in mtls_client.pem -text > ../mtls_client.crt +mv mtls_client-key.pem ../mtls_client.key + +openssl x509 -in mtls_server.pem -text > ../mtls_server.crt +mv mtls_server-key.pem ../mtls_server.key + +rm *.pem *.csr cfssl cfssljson diff --git a/t/cert/mtls_cert_gen/mtls_ca.json b/t/cert/mtls_cert_gen/mtls_ca.json new file mode 100644 index 0000000000..0a4a7ab139 --- /dev/null +++ b/t/cert/mtls_cert_gen/mtls_ca.json @@ -0,0 +1,18 @@ +{ + "CA": { + "expiry": "175200h", + "pathlen": 0 + }, + "CN": "OpenResty Testing Root CA", + "key": { + "algo": "rsa", + "size": 2048 + }, + "names": [ + { + "C": "US", + "O": "OpenResty", + "ST": "California" + } + ] +} diff --git a/t/cert/mtls_cert_gen/mtls_client.json b/t/cert/mtls_cert_gen/mtls_client.json new file mode 100644 index 0000000000..4d59f47a5b --- /dev/null +++ b/t/cert/mtls_cert_gen/mtls_client.json @@ -0,0 +1,18 @@ +{ + "CN": "foo@example.com", + "key": { + "algo": "rsa", + "size": 2048 + }, + "names": [ + { + "C": "US", + "O": "OpenResty", + "ST": "California" + } + ], + "hosts": [ + "foo@example.com", + "bar@example.com" + ] +} diff --git a/t/cert/mtls_cert_gen/mtls_server.json b/t/cert/mtls_cert_gen/mtls_server.json new file mode 100644 index 0000000000..655af54ef8 --- /dev/null +++ b/t/cert/mtls_cert_gen/mtls_server.json @@ -0,0 +1,17 @@ +{ + "CN": "example.com", + "key": { + "algo": "rsa", + "size": 2048 + }, + "names": [ + { + "C": "US", + "O": "OpenResty", + "ST": "California" + } + ], + "hosts": [ + "example.com" + ] +} diff --git a/t/cert/mtls_cert_gen/profile.json b/t/cert/mtls_cert_gen/profile.json new file mode 100644 index 0000000000..d3b6ab16cb --- /dev/null +++ b/t/cert/mtls_cert_gen/profile.json @@ -0,0 +1,27 @@ +{ + "signing": { + "default": { + "expiry": "175200h" + }, + "profiles": { + "server": { + "usages": [ + "signing", + "digital signing", + "key encipherment", + "server auth" + ], + "expiry": "175199h" + }, + "client": { + "usages": [ + "signing", + "digital signature", + "key encipherment", + "client auth" + ], + "expiry": "175199h" + } + } + } +} diff --git a/t/cert/mtls_client.crt b/t/cert/mtls_client.crt new file mode 100644 index 0000000000..dd0efdf7f8 --- /dev/null +++ b/t/cert/mtls_client.crt @@ -0,0 +1,87 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 19:0a:a3:a8:9c:d4:0f:dc:c6:fa:23:7b:f8:fc:bd:f4:73:4e:7e:b1 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C = US, ST = California, O = OpenResty, CN = OpenResty Testing Root CA + Validity + Not Before: Mar 13 15:49:00 2022 GMT + Not After : Mar 8 14:49:00 2042 GMT + Subject: C = US, ST = California, O = OpenResty, CN = foo@example.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (2048 bit) + Modulus: + 00:be:5b:09:4c:94:71:d3:82:54:4a:42:6a:76:aa: + 34:5d:28:d9:45:e6:44:9a:74:9f:a6:e6:78:49:9e: + c6:20:75:32:5f:92:3b:ec:6e:4b:7b:b0:75:1c:75: + 09:00:05:77:d6:59:ca:55:5b:13:b6:76:3a:c6:18: + dc:37:6a:20:93:e6:26:56:5d:0b:96:8c:01:f2:96: + 38:08:08:36:a2:64:12:21:a0:8d:48:cd:9a:26:78: + 92:29:b6:63:eb:14:d9:b6:e5:87:f7:d5:55:a4:cc: + 53:1c:a3:7c:b8:bd:ad:7c:a4:d4:86:1f:a7:1c:43: + c5:1a:b5:f1:03:bd:fe:19:98:1d:b7:13:2b:93:a2: + 2a:0e:21:7e:42:a9:bb:28:69:49:59:e7:89:0e:7d: + 5a:ce:fb:d4:0c:20:6a:e1:db:b2:6a:e5:a7:55:e0: + d0:58:4a:e2:08:78:82:b9:06:0c:65:f9:24:06:e6: + 8a:13:b2:9a:ef:1b:4a:b2:3a:b4:98:7f:dd:3c:0e: + 85:0b:a6:c6:47:2f:63:c2:73:52:41:db:7c:06:c3: + 2a:b5:2d:d1:e1:30:d5:c4:79:c9:b9:35:68:46:ad: + c4:45:57:ea:11:88:27:37:ed:ac:49:2d:c4:d6:c6: + a6:74:8d:d3:bc:e0:d9:69:25:0c:0c:b0:e3:b7:cb: + 8d:99 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Digital Signature, Key Encipherment + X509v3 Extended Key Usage: + TLS Web Client Authentication + X509v3 Basic Constraints: critical + CA:FALSE + X509v3 Subject Key Identifier: + 22:70:5E:30:8C:4D:66:39:E7:60:C9:29:A2:ED:95:32:34:63:5C:C0 + X509v3 Authority Key Identifier: + keyid:F0:D7:4B:14:73:E1:67:00:6B:54:B4:19:20:76:12:9F:9D:8E:C8:09 + + X509v3 Subject Alternative Name: + email:foo@example.com, email:bar@example.com + Signature Algorithm: sha256WithRSAEncryption + 96:e7:2a:fc:2a:56:16:80:e2:d3:79:0c:46:db:c3:88:ab:d3: + ef:39:66:4b:a9:ab:6c:0e:30:08:07:7c:fc:03:6c:f7:dd:fb: + 3e:a8:c8:68:28:ab:4e:73:97:80:27:5d:c5:9d:52:00:aa:08: + 25:c8:f9:dc:df:64:73:a4:58:5b:bd:5f:1a:53:a4:33:a3:b1: + 45:38:2d:be:d7:f3:a4:c4:f4:7a:07:71:44:f1:a2:65:02:e4: + 71:84:01:b5:83:4b:de:83:b5:ad:ac:b9:3c:17:42:0c:9a:7d: + eb:7f:ab:26:dd:9b:3a:fd:95:37:55:cc:01:c3:3f:20:df:e5: + ed:49:51:7a:42:ea:f3:8a:3f:da:6e:c1:1a:11:b9:45:4d:6e: + c9:21:f4:e3:4f:31:72:5b:bb:01:92:b6:7f:f1:8a:9e:6c:d0: + 7f:96:d7:eb:29:09:53:38:26:41:00:f2:33:04:77:bd:a9:ee: + 60:9e:06:b7:7d:26:ae:1c:4f:56:bd:a5:b6:50:40:be:be:84: + 2a:54:21:59:47:7d:a5:1e:63:6d:28:36:4d:a6:e4:62:69:9b: + 9b:fa:2b:48:e8:64:d7:14:f4:62:a2:26:17:a5:05:58:4a:38: + d2:44:e7:33:90:b9:c1:8c:85:02:99:b8:03:1a:03:d2:cf:ac: + a5:6b:44:98 +-----BEGIN CERTIFICATE----- +MIID3DCCAsSgAwIBAgIUGQqjqJzUD9zG+iN7+Py99HNOfrEwDQYJKoZIhvcNAQEL +BQAwWjELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAoT +CU9wZW5SZXN0eTEiMCAGA1UEAxMZT3BlblJlc3R5IFRlc3RpbmcgUm9vdCBDQTAe +Fw0yMjAzMTMxNTQ5MDBaFw00MjAzMDgxNDQ5MDBaMFAxCzAJBgNVBAYTAlVTMRMw +EQYDVQQIEwpDYWxpZm9ybmlhMRIwEAYDVQQKEwlPcGVuUmVzdHkxGDAWBgNVBAMM +D2Zvb0BleGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AL5bCUyUcdOCVEpCanaqNF0o2UXmRJp0n6bmeEmexiB1Ml+SO+xuS3uwdRx1CQAF +d9ZZylVbE7Z2OsYY3DdqIJPmJlZdC5aMAfKWOAgINqJkEiGgjUjNmiZ4kim2Y+sU +2bblh/fVVaTMUxyjfLi9rXyk1IYfpxxDxRq18QO9/hmYHbcTK5OiKg4hfkKpuyhp +SVnniQ59Ws771AwgauHbsmrlp1Xg0FhK4gh4grkGDGX5JAbmihOymu8bSrI6tJh/ +3TwOhQumxkcvY8JzUkHbfAbDKrUt0eEw1cR5ybk1aEatxEVX6hGIJzftrEktxNbG +pnSN07zg2WklDAyw47fLjZkCAwEAAaOBozCBoDAOBgNVHQ8BAf8EBAMCBaAwEwYD +VR0lBAwwCgYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUInBeMIxN +ZjnnYMkpou2VMjRjXMAwHwYDVR0jBBgwFoAU8NdLFHPhZwBrVLQZIHYSn52OyAkw +KwYDVR0RBCQwIoEPZm9vQGV4YW1wbGUuY29tgQ9iYXJAZXhhbXBsZS5jb20wDQYJ +KoZIhvcNAQELBQADggEBAJbnKvwqVhaA4tN5DEbbw4ir0+85Zkupq2wOMAgHfPwD +bPfd+z6oyGgoq05zl4AnXcWdUgCqCCXI+dzfZHOkWFu9XxpTpDOjsUU4Lb7X86TE +9HoHcUTxomUC5HGEAbWDS96Dta2suTwXQgyafet/qybdmzr9lTdVzAHDPyDf5e1J +UXpC6vOKP9puwRoRuUVNbskh9ONPMXJbuwGStn/xip5s0H+W1+spCVM4JkEA8jME +d72p7mCeBrd9Jq4cT1a9pbZQQL6+hCpUIVlHfaUeY20oNk2m5GJpm5v6K0joZNcU +9GKiJhelBVhKONJE5zOQucGMhQKZuAMaA9LPrKVrRJg= +-----END CERTIFICATE----- diff --git a/t/cert/mtls_client.key b/t/cert/mtls_client.key new file mode 100644 index 0000000000..7d77e5506d --- /dev/null +++ b/t/cert/mtls_client.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEogIBAAKCAQEAvlsJTJRx04JUSkJqdqo0XSjZReZEmnSfpuZ4SZ7GIHUyX5I7 +7G5Le7B1HHUJAAV31lnKVVsTtnY6xhjcN2ogk+YmVl0LlowB8pY4CAg2omQSIaCN +SM2aJniSKbZj6xTZtuWH99VVpMxTHKN8uL2tfKTUhh+nHEPFGrXxA73+GZgdtxMr +k6IqDiF+Qqm7KGlJWeeJDn1azvvUDCBq4duyauWnVeDQWEriCHiCuQYMZfkkBuaK +E7Ka7xtKsjq0mH/dPA6FC6bGRy9jwnNSQdt8BsMqtS3R4TDVxHnJuTVoRq3ERVfq +EYgnN+2sSS3E1samdI3TvODZaSUMDLDjt8uNmQIDAQABAoIBACqRsUKu78WdH7x7 +ndNrvMoYmH5JQI5KBmoMoFnWZ/haPSmiSkRVZgwDKi1y/tBCaMpGyjjMZVwolHw4 +kwbRdPeeQHSP2keQh974OQ+SxqUKPAPJI89kK1TvIcCySSYJQ6bjLcT+sGhqSSve +Y8XspR96vQxBh92KSknu5jcwBeMy/eG0mmszzP3y2R0BPztuZdE6dq/KxWQ/R4/P +JG9V1rNkIY+1JZvIICIH1Ehn4UKjiE+FJmyDbDlPKEi7W4CpRnShMLOF4cCFnQLW +RQds3Dj9GcVY+8Q/GLZF0ATjekIyEsKZEgrMAUF5ZSGRpjJQEHX7oseAiQGQxtHT +nj5b1AECgYEAwewXbbd1MqRQ6ohfsQ8j5HSMY6ahvUzs1dZUckr2jw8B98tfi/uj +a6Jq1KZe12+4dfwruRSaYdTsSVuvNiSJOxElY0C1p+lXdprFf7XfoQ6UNtg22jcH +9f8cftnlJoV5whh3YKjqnnnAWUQZ61FTNJ258/t+x0ZgpBJvqBoHwDUCgYEA+0qp +FZ5xS4FLJMc+Xf/hUeXo+04e4OD/se3atYqyuh1ghmQZfRRPOC110HG99H+rzq/x +xPMvRFahkAMyi+/3oIcBEuXvoQyqscIsAhkWD/e9t3Qc9OsWe1hlAgWKZxr6oR2U +KKR1FD7UVecOH+FKCKaL5UpEt4yEigc1NtSlTFUCgYBnV5agrIyzQSex5J0CMWxS +Od362PkGdXEc/8we4F4GnNvSnrm7Uo2jNXmy+zo9mtb1YT43sogXLK4C5e44bz4G +kTuYagqkgdBPb2lihpy3KprHo2+P2JXQfXRFEX9xiN37Fqi/hSUK8R0VNRqO8dbi +ik9nexXzwkiMBxsjvUN2JQKBgFy62FpZ9YTfWVNhEuqtGgCWzrqtwUdKwBBwrVyA +qiNz48Kz/ZPigrlATVF2J5qp4kSLOLRs6OxW65exFl39V2utZgALSbosanDeLk83 +4qRRz3h7KJRYjBtIKz3rvX7+va3mtF2rEmk+Jizs7pFlGWTH0Kf0GBeDiwVEU6bA +IZ9hAoGAQTjnRGMjvyhq0aPYP+mRFiMKSkcL1nyXizYInfAnbfbL/uEODH7D+iMf +kak+UgmeD9ce5d/APmZp3/FzYH/M8ivBgG+MnaI+MLVMhmQdLZyMtbSKKaDpiim7 +DdN1wCXYbur0HlO2t+wemMZPpQu7wybgEOLlIG7Yj/0OWDcal1c= +-----END RSA PRIVATE KEY----- diff --git a/t/cert/mtls_server.crt b/t/cert/mtls_server.crt new file mode 100644 index 0000000000..7cbc2a804b --- /dev/null +++ b/t/cert/mtls_server.crt @@ -0,0 +1,87 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 2f:d5:41:13:5a:ff:c7:1c:5b:ce:28:cd:a6:f7:a5:5a:0d:c0:e2:d2 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C = US, ST = California, O = OpenResty, CN = OpenResty Testing Root CA + Validity + Not Before: Mar 13 15:49:00 2022 GMT + Not After : Mar 8 14:49:00 2042 GMT + Subject: C = US, ST = California, O = OpenResty, CN = example.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (2048 bit) + Modulus: + 00:d7:03:80:a7:42:7d:06:5a:7b:70:d8:11:96:dd: + 63:35:53:07:28:71:52:05:40:55:83:61:a7:14:ac: + cf:4b:9b:ab:b7:4e:9d:79:e9:13:3d:bc:c3:67:8f: + dd:88:d9:8b:c2:31:aa:b8:28:9e:13:70:db:76:b0: + 12:1c:f8:35:c6:2e:33:9c:b9:04:e3:47:e0:f9:e4: + 7f:a5:55:03:0c:2d:b2:54:17:29:12:dd:61:6e:5c: + 33:9f:e5:8f:8a:2b:41:53:dc:e1:98:49:63:df:e3: + 00:30:2d:1b:bb:f0:8f:cb:04:ec:c9:98:c4:09:5b: + b4:ba:a9:a0:0a:77:d2:42:76:7c:ac:64:c3:97:85: + 50:5d:7d:02:61:2a:00:93:d0:69:5e:87:22:f0:c1: + 1e:53:46:02:40:37:c9:55:77:99:7d:9d:3d:35:14: + 74:84:e3:73:ca:e7:4a:ab:33:98:26:aa:41:4b:b5: + e6:63:7c:a4:1e:25:6a:88:f4:56:d9:2c:63:dd:89: + 19:fa:25:41:44:95:87:40:a7:9b:4e:3a:91:29:32: + 79:66:05:f4:2f:68:2c:06:53:df:4d:60:be:ac:09: + 20:61:9c:6f:1a:a6:07:5a:e7:41:91:9d:36:77:38: + 18:3a:69:7b:67:29:9f:1d:e0:c2:d2:8f:16:5b:14: + e8:e1 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Digital Signature, Key Encipherment + X509v3 Extended Key Usage: + TLS Web Server Authentication + X509v3 Basic Constraints: critical + CA:FALSE + X509v3 Subject Key Identifier: + 16:07:B5:C2:4C:B5:2D:4F:B8:E9:D6:FA:2F:3F:C0:1B:B6:4F:20:E6 + X509v3 Authority Key Identifier: + keyid:F0:D7:4B:14:73:E1:67:00:6B:54:B4:19:20:76:12:9F:9D:8E:C8:09 + + X509v3 Subject Alternative Name: + DNS:example.com + Signature Algorithm: sha256WithRSAEncryption + d9:c0:c0:d6:8b:44:04:26:b3:98:24:2c:12:82:6d:15:79:92: + 76:c9:77:94:c1:be:8f:8a:18:78:96:04:68:c9:0a:d1:84:c5: + de:cd:ba:b5:a2:3b:d4:0a:70:be:00:49:19:c0:6e:ca:e9:e5: + 8b:b6:e3:a2:39:0d:d8:ee:55:1a:08:73:39:19:d3:07:07:33: + 8c:d8:1b:0f:1b:73:0e:84:72:cf:e6:c1:a1:da:39:aa:c0:2e: + 3d:b9:a6:8f:ec:98:3a:07:58:34:c2:5e:4c:1a:6b:db:ce:51: + 92:25:1d:ba:78:4b:11:b6:f1:69:02:cb:ac:32:bb:80:f9:15: + 91:bf:4e:6a:ab:51:51:7c:7b:1a:72:80:96:eb:0c:fa:56:0e: + f2:87:3c:16:8a:04:aa:8a:9d:0c:d9:e0:c4:2a:20:42:5a:12: + 41:52:30:50:3d:85:f8:07:31:6b:af:a4:d2:44:38:69:ab:88: + 05:d4:5b:68:34:02:dc:99:5a:6c:b7:ea:fc:79:76:fe:68:29: + df:94:22:58:46:f2:40:cb:e1:92:17:d8:1e:3d:fa:a2:56:4f: + ac:3c:3d:ae:f7:90:12:ac:3b:6c:1e:1f:26:48:08:87:9a:0e: + 8d:9d:75:ef:86:1e:63:ac:e9:14:47:ad:3f:4f:10:57:2a:d1: + 95:ec:6f:24 +-----BEGIN CERTIFICATE----- +MIIDwzCCAqugAwIBAgIUL9VBE1r/xxxbzijNpvelWg3A4tIwDQYJKoZIhvcNAQEL +BQAwWjELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAoT +CU9wZW5SZXN0eTEiMCAGA1UEAxMZT3BlblJlc3R5IFRlc3RpbmcgUm9vdCBDQTAe +Fw0yMjAzMTMxNTQ5MDBaFw00MjAzMDgxNDQ5MDBaMEwxCzAJBgNVBAYTAlVTMRMw +EQYDVQQIEwpDYWxpZm9ybmlhMRIwEAYDVQQKEwlPcGVuUmVzdHkxFDASBgNVBAMT +C2V4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1wOA +p0J9Blp7cNgRlt1jNVMHKHFSBUBVg2GnFKzPS5urt06deekTPbzDZ4/diNmLwjGq +uCieE3DbdrASHPg1xi4znLkE40fg+eR/pVUDDC2yVBcpEt1hblwzn+WPiitBU9zh +mElj3+MAMC0bu/CPywTsyZjECVu0uqmgCnfSQnZ8rGTDl4VQXX0CYSoAk9BpXoci +8MEeU0YCQDfJVXeZfZ09NRR0hONzyudKqzOYJqpBS7XmY3ykHiVqiPRW2Sxj3YkZ ++iVBRJWHQKebTjqRKTJ5ZgX0L2gsBlPfTWC+rAkgYZxvGqYHWudBkZ02dzgYOml7 +ZymfHeDC0o8WWxTo4QIDAQABo4GOMIGLMA4GA1UdDwEB/wQEAwIFoDATBgNVHSUE +DDAKBggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBQWB7XCTLUtT7jp +1vovP8Abtk8g5jAfBgNVHSMEGDAWgBTw10sUc+FnAGtUtBkgdhKfnY7ICTAWBgNV +HREEDzANggtleGFtcGxlLmNvbTANBgkqhkiG9w0BAQsFAAOCAQEA2cDA1otEBCaz +mCQsEoJtFXmSdsl3lMG+j4oYeJYEaMkK0YTF3s26taI71ApwvgBJGcBuyunli7bj +ojkN2O5VGghzORnTBwczjNgbDxtzDoRyz+bBodo5qsAuPbmmj+yYOgdYNMJeTBpr +285RkiUdunhLEbbxaQLLrDK7gPkVkb9OaqtRUXx7GnKAlusM+lYO8oc8FooEqoqd +DNngxCogQloSQVIwUD2F+Acxa6+k0kQ4aauIBdRbaDQC3JlabLfq/Hl2/mgp35Qi +WEbyQMvhkhfYHj36olZPrDw9rveQEqw7bB4fJkgIh5oOjZ1174YeY6zpFEetP08Q +VyrRlexvJA== +-----END CERTIFICATE----- diff --git a/t/cert/mtls_server.key b/t/cert/mtls_server.key new file mode 100644 index 0000000000..f5b85d18d8 --- /dev/null +++ b/t/cert/mtls_server.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEA1wOAp0J9Blp7cNgRlt1jNVMHKHFSBUBVg2GnFKzPS5urt06d +eekTPbzDZ4/diNmLwjGquCieE3DbdrASHPg1xi4znLkE40fg+eR/pVUDDC2yVBcp +Et1hblwzn+WPiitBU9zhmElj3+MAMC0bu/CPywTsyZjECVu0uqmgCnfSQnZ8rGTD +l4VQXX0CYSoAk9BpXoci8MEeU0YCQDfJVXeZfZ09NRR0hONzyudKqzOYJqpBS7Xm +Y3ykHiVqiPRW2Sxj3YkZ+iVBRJWHQKebTjqRKTJ5ZgX0L2gsBlPfTWC+rAkgYZxv +GqYHWudBkZ02dzgYOml7ZymfHeDC0o8WWxTo4QIDAQABAoIBAEnmZUiXnJsbbEPr +r5f3vYptYA9xa2xsoTeHz8JWZuUouwtE1PE6v6c/grXMh6rqgpObOH8VTseFyZhw +ibk1Ql48MPcTzG9FnDinZYvwvRxpdFpcn3xhZIRm4kN5xi0KEuj9CPireM1RmxXz +2w1scC+qIKxlejNxNpvVgzE136mBqEFKJzecP+yZuH/A86MQCgwqqa3jSz5ApNg+ +1aJE34cGFieDbAN+9sdqWA3OkRrHoy8EakUf4JEvwX1AwUN832mj+N/LfmcCGMeD +YhzybzlPBV2q2T1+pHIdNT99JVNPkgdTe1903EjnG5oSDGHt2i9MdnNkMsffDWNt +pJiqSHECgYEA2hL6l8Py4oa5AJ2WXriuHRJykAs90K0akftQt4i4lWCbeRhaGh7h +kPgpDS33RkE4SymVVr0c05abMCKabQBwbu4PNCqetCFtfmIQdQCTUbLbXjL8UuD2 +QnF7nbHiwyGBKRMU/F74oX3z7lXLgRtIiyyo5yYgIAQqpz3oJAaXNTUCgYEA/GhE +Ziez8FXVAg3XwwrE3SexRFKv1JqipYE4mr+ouzfpn9yn8mttxbOORiAAEBl3ZPhd +ZUBzLy19fdFZ8RJ0zPsqoZxsd09/XetaBU56C/g9u0fycj1L2elh9rQAlOW0Grus +l8jBh01TGtlg0xobK0zjwdGPcbYkp1IzIqyD9n0CgYEAicBvVyrJ5FnhxwfEkrTq +FycuAtt3Arg2DnzH8geFQaayzv2Y/OMA7Yg0tkSQ7GoKW0A7O31eFjIOeYuCLNSY +MRpjtDov4e0zsx/S8XWZmYP3mjtutBOyuyngQi655TTm18FcAkcjmy9qxOShFj7b +xj5BuzGUHWVEZDxwxUD8hvkCgYBnrcyqyZQ4HImqllUSYNIMpclC71QaWIqGwVWm ++yMsBAOLDvBNu6MTmnXOiEZ+VnecmgiDFr45ms35aI0xYQtpR6JzT/Wd7KG8ynfn +xhyL3iQ9UYhdNKB7mkoLNFUo1FHuyThUALq+AR0p4jDLheWzG5pSeuoZI2Ba+oDW +tVZfYQKBgC5phtERR5LKU5Wkzm+uY2j+Nzh4kuKkdLosB9pUW8VnrwFDLZ+r1CxG +L6CxOZ0AylCMIlrFeUXMa91kLDJYch0NUPHuGBkdIBDXi2kqN7GflTdV3Z8uev20 +uMjErA93yVOWHTR3Wo8WIHy5mdsNRQgGAPw1RVW7rnYIyXJW/mTs +-----END RSA PRIVATE KEY----- From 8df296c47992d33681cf639d2d251248d834dd2b Mon Sep 17 00:00:00 2001 From: lijunlong Date: Tue, 15 Mar 2022 23:40:32 +0800 Subject: [PATCH 022/254] travis: fixe the uri of lua-resty-core. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index dbf1ed6acf..335ae71ee6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -88,7 +88,7 @@ install: - git clone https://github.com/openresty/rds-json-nginx-module.git ../rds-json-nginx-module - git clone https://github.com/openresty/srcache-nginx-module.git ../srcache-nginx-module - git clone https://github.com/openresty/redis2-nginx-module.git ../redis2-nginx-module - - git clone https://github.com/dndx/lua-resty-core.git ../lua-resty-core + - git clone https://github.com/openresty/lua-resty-core.git ../lua-resty-core - git clone https://github.com/openresty/lua-resty-lrucache.git ../lua-resty-lrucache - git clone https://github.com/openresty/lua-resty-mysql.git ../lua-resty-mysql - git clone https://github.com/openresty/lua-resty-string.git ../lua-resty-string From 3d1431790f714fd5e6c8425b46224c2f0b7724a5 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Fri, 18 Mar 2022 08:11:44 +0800 Subject: [PATCH 023/254] travis: update openssl to 1.1.1n. (#2028) --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 335ae71ee6..6e6ecee4f6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -52,7 +52,7 @@ env: - TEST_NGINX_SLEEP=0.006 jobs: - NGINX_VERSION=1.21.4 OPENSSL_VER=1.1.0l OPENSSL_PATCH_VER=1.1.0d - - NGINX_VERSION=1.21.4 OPENSSL_VER=1.1.1m OPENSSL_PATCH_VER=1.1.1f + - NGINX_VERSION=1.21.4 OPENSSL_VER=1.1.1n OPENSSL_PATCH_VER=1.1.1f services: - memcached From c1d378824ce55ffab62fbf4d42ee3a7e49a79013 Mon Sep 17 00:00:00 2001 From: xiaobiaozhao <52393536+xiaobiaozhao@users.noreply.github.com> Date: Mon, 21 Mar 2022 15:45:22 +0800 Subject: [PATCH 024/254] feature: add `server_rewrite_by_lua*`. (#2004) Co-authored-by: lijunlong --- README.markdown | 93 ++++++ config | 2 + doc/HttpLuaModule.wiki | 82 +++++ src/ngx_http_lua_common.h | 12 +- src/ngx_http_lua_control.c | 3 + src/ngx_http_lua_directive.c | 106 ++++++ src/ngx_http_lua_directive.h | 4 + src/ngx_http_lua_module.c | 37 +++ src/ngx_http_lua_output.c | 4 + src/ngx_http_lua_req_body.c | 1 + src/ngx_http_lua_server_rewriteby.c | 339 +++++++++++++++++++ src/ngx_http_lua_server_rewriteby.h | 20 ++ src/ngx_http_lua_socket_tcp.c | 1 + src/ngx_http_lua_uri.c | 6 +- src/ngx_http_lua_util.c | 1 + src/ngx_http_lua_util.h | 2 + t/089-phase.t | 22 +- t/162-socket-tls-handshake.t | 3 - t/167-server-rewrite.t | 488 ++++++++++++++++++++++++++++ 19 files changed, 1219 insertions(+), 7 deletions(-) create mode 100644 src/ngx_http_lua_server_rewriteby.c create mode 100644 src/ngx_http_lua_server_rewriteby.h create mode 100644 t/167-server-rewrite.t diff --git a/README.markdown b/README.markdown index 7f0ac24cb1..98d92a6b08 100644 --- a/README.markdown +++ b/README.markdown @@ -1131,6 +1131,8 @@ Directives * [content_by_lua](#content_by_lua) * [content_by_lua_block](#content_by_lua_block) * [content_by_lua_file](#content_by_lua_file) +* [server_rewrite_by_lua_block](#server_rewrite_by_lua_block) +* [server_rewrite_by_lua_file](#server_rewrite_by_lua_file) * [rewrite_by_lua](#rewrite_by_lua) * [rewrite_by_lua_block](#rewrite_by_lua_block) * [rewrite_by_lua_file](#rewrite_by_lua_file) @@ -1909,6 +1911,97 @@ But be very careful about malicious user inputs and always carefully validate or [Back to TOC](#directives) +server_rewrite_by_lua_block +--------------------------- + +**syntax:** *server_rewrite_by_lua_block { lua-script }* + +**context:** *http, server* + +**phase:** *server rewrite* + +Acts as a server rewrite phase handler and executes Lua code string specified in `{ lua-script }` for every request. +The Lua code may make [API calls](#nginx-api-for-lua) and is executed as a new spawned coroutine in an independent global environment (i.e. a sandbox). + +```nginx + + server { + ... + + server_rewrite_by_lua_block { + ngx.ctx.a = "server_rewrite_by_lua_block in http" + } + + location /lua { + content_by_lua_block { + ngx.say(ngx.ctx.a) + ngx.log(ngx.INFO, ngx.ctx.a) + } + } + } +``` + +Just as any other rewrite phase handlers, [server_rewrite_by_lua_block](#server_rewrite_by_lua_block) also runs in subrequests. + +```nginx + + server { + server_rewrite_by_lua_block { + ngx.log(ngx.INFO, "is_subrequest:", ngx.is_subrequest) + } + + location /lua { + content_by_lua_block { + local res = ngx.location.capture("/sub") + ngx.print(res.body) + } + } + + location /sub { + content_by_lua_block { + ngx.say("OK") + } + } + } +``` + +Note that when calling `ngx.exit(ngx.OK)` within a [server_rewrite_by_lua_block](#server_rewrite_by_lua_block) handler, the Nginx request processing control flow will still continue to the content handler. To terminate the current request from within a [server_rewrite_by_lua_block](#server_rewrite_by_lua_block) handler, call [ngx.exit](#ngxexit) with status >= 200 (`ngx.HTTP_OK`) and status < 300 (`ngx.HTTP_SPECIAL_RESPONSE`) for successful quits and `ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)` (or its friends) for failures. + + +```nginx + + server_rewrite_by_lua_block { + ngx.exit(503) + } + + location /bar { + ... + # never exec + } +``` + + +[Back to TOC](#directives) + +server_rewrite_by_lua_file +-------------------------- + +**syntax:** *server_rewrite_by_lua_file <path-to-lua-script-file>* + +**context:** *http, server* + +**phase:** *server rewrite* + +Equivalent to [server_rewrite_by_lua_block](#server_rewrite_by_lua_block), except that the file specified by `` contains the Lua code, or, as from the `v0.10.22` release, the [LuaJIT bytecode](#luajit-bytecode-support) to be executed. + +Nginx variables can be used in the `` string to provide flexibility. This however carries some risks and is not ordinarily recommended. + +When a relative path like `foo/bar.lua` is given, they will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option while starting the Nginx server. + +When the Lua code cache is turned on (by default), the user code is loaded once at the first request and cached and the Nginx config must be reloaded each time the Lua source file is modified. The Lua code cache can be temporarily disabled during development by switching [lua_code_cache](#lua_code_cache) `off` in `nginx.conf` to avoid reloading Nginx. + +[Back to TOC](#directives) + rewrite_by_lua -------------- diff --git a/config b/config index 14870a04e8..0e572c8bea 100644 --- a/config +++ b/config @@ -261,6 +261,7 @@ HTTP_LUA_SRCS=" \ $ngx_addon_dir/src/ngx_http_lua_util.c \ $ngx_addon_dir/src/ngx_http_lua_cache.c \ $ngx_addon_dir/src/ngx_http_lua_contentby.c \ + $ngx_addon_dir/src/ngx_http_lua_server_rewriteby.c \ $ngx_addon_dir/src/ngx_http_lua_rewriteby.c \ $ngx_addon_dir/src/ngx_http_lua_accessby.c \ $ngx_addon_dir/src/ngx_http_lua_setby.c \ @@ -325,6 +326,7 @@ HTTP_LUA_DEPS=" \ $ngx_addon_dir/src/ngx_http_lua_util.h \ $ngx_addon_dir/src/ngx_http_lua_cache.h \ $ngx_addon_dir/src/ngx_http_lua_contentby.h \ + $ngx_addon_dir/src/ngx_http_lua_server_rewriteby.c \ $ngx_addon_dir/src/ngx_http_lua_rewriteby.h \ $ngx_addon_dir/src/ngx_http_lua_accessby.h \ $ngx_addon_dir/src/ngx_http_lua_setby.h \ diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 0d69fd205b..9270d18da0 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -1568,6 +1568,88 @@ Nginx variables are supported in the file path for dynamic dispatch, for example But be very careful about malicious user inputs and always carefully validate or filter out the user-supplied path components. +== server_rewrite_by_lua_block == + +'''syntax:''' ''server_rewrite_by_lua_block { lua-script }'' + +'''context:''' ''http, server'' + +'''phase:''' ''server rewrite'' + +Acts as a server rewrite phase handler and executes Lua code string specified in { lua-script } for every request. +The Lua code may make [[#Nginx API for Lua|API calls]] and is executed as a new spawned coroutine in an independent global environment (i.e. a sandbox). + + +server { + ... + + server_rewrite_by_lua_block { + ngx.ctx.a = "server_rewrite_by_lua_block in http" + } + + location /lua { + content_by_lua_block { + ngx.say(ngx.ctx.a) + ngx.log(ngx.INFO, ngx.ctx.a) + } + } +} + + +Just as any other rewrite phase handlers, [[#server_rewrite_by_lua_block|server_rewrite_by_lua_block]] also runs in subrequests. + + +server { + server_rewrite_by_lua_block { + ngx.log(ngx.INFO, "is_subrequest:", ngx.is_subrequest) + } + + location /lua { + content_by_lua_block { + local res = ngx.location.capture("/sub") + ngx.print(res.body) + } + } + + location /sub { + content_by_lua_block { + ngx.say("OK") + } + } +} + + +Note that when calling ngx.exit(ngx.OK) within a [[#server_rewrite_by_lua_block|server_rewrite_by_lua_block]] handler, the Nginx request processing control flow will still continue to the content handler. To terminate the current request from within a [[#server_rewrite_by_lua_block|server_rewrite_by_lua_block]] handler, call [[#ngx.exit|ngx.exit]] with status >= 200 (ngx.HTTP_OK) and status < 300 (ngx.HTTP_SPECIAL_RESPONSE) for successful quits and ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR) (or its friends) for failures. + + + + server_rewrite_by_lua_block { + ngx.exit(503) + } + + location /bar { + ... + # never exec + } + + + +== server_rewrite_by_lua_file == + +'''syntax:''' ''server_rewrite_by_lua_file '' + +'''context:''' ''http, server'' + +'''phase:''' ''server rewrite'' + +Equivalent to [[#server_rewrite_by_lua_block|server_rewrite_by_lua_block]], except that the file specified by contains the Lua code, or, as from the v0.10.22 release, the [[#LuaJIT bytecode support|LuaJIT bytecode]] to be executed. + +Nginx variables can be used in the string to provide flexibility. This however carries some risks and is not ordinarily recommended. + +When a relative path like foo/bar.lua is given, they will be turned into the absolute path relative to the server prefix path determined by the -p PATH command-line option while starting the Nginx server. + +When the Lua code cache is turned on (by default), the user code is loaded once at the first request and cached and the Nginx config must be reloaded each time the Lua source file is modified. The Lua code cache can be temporarily disabled during development by switching [[#lua_code_cache|lua_code_cache]] off in nginx.conf to avoid reloading Nginx. + == rewrite_by_lua == '''syntax:''' ''rewrite_by_lua '' diff --git a/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h index 3a2480f041..f293c5b1d9 100644 --- a/src/ngx_http_lua_common.h +++ b/src/ngx_http_lua_common.h @@ -141,6 +141,7 @@ typedef struct { #define NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH 0x1000 #define NGX_HTTP_LUA_CONTEXT_EXIT_WORKER 0x2000 #define NGX_HTTP_LUA_CONTEXT_SSL_CLIENT_HELLO 0x4000 +#define NGX_HTTP_LUA_CONTEXT_SERVER_REWRITE 0x8000 #define NGX_HTTP_LUA_FFI_NO_REQ_CTX -100 @@ -307,6 +308,7 @@ struct ngx_http_lua_main_conf_s { unsigned requires_log:1; unsigned requires_shm:1; unsigned requires_capture_log:1; + unsigned requires_server_rewrite:1; }; @@ -336,6 +338,12 @@ union ngx_http_lua_srv_conf_u { u_char *ssl_client_hello_src_key; u_char *ssl_client_hello_chunkname; int ssl_client_hello_src_ref; + + ngx_http_lua_srv_conf_handler_pt server_rewrite_handler; + ngx_http_complex_value_t server_rewrite_src; + u_char *server_rewrite_src_key; + u_char *server_rewrite_chunkname; + int server_rewrite_src_ref; } srv; #endif @@ -378,6 +386,8 @@ typedef struct { ngx_http_output_body_filter_pt body_filter_handler; + + u_char *rewrite_chunkname; ngx_http_complex_value_t rewrite_src; /* rewrite_by_lua inline script/script @@ -631,7 +641,7 @@ typedef struct ngx_http_lua_ctx_s { response headers */ unsigned mime_set:1; /* whether the user has set Content-Type response header */ - + unsigned entered_server_rewrite_phase:1; unsigned entered_rewrite_phase:1; unsigned entered_access_phase:1; unsigned entered_content_phase:1; diff --git a/src/ngx_http_lua_control.c b/src/ngx_http_lua_control.c index c79101cf06..99460456c1 100644 --- a/src/ngx_http_lua_control.c +++ b/src/ngx_http_lua_control.c @@ -91,6 +91,7 @@ ngx_http_lua_ngx_exec(lua_State *L) } ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE + | NGX_HTTP_LUA_CONTEXT_SERVER_REWRITE | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT); @@ -232,6 +233,7 @@ ngx_http_lua_ngx_redirect(lua_State *L) } ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE + | NGX_HTTP_LUA_CONTEXT_SERVER_REWRITE | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT); @@ -373,6 +375,7 @@ ngx_http_lua_ffi_exit(ngx_http_request_t *r, int status, u_char *err, } if (ngx_http_lua_ffi_check_context(ctx, NGX_HTTP_LUA_CONTEXT_REWRITE + | NGX_HTTP_LUA_CONTEXT_SERVER_REWRITE | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT | NGX_HTTP_LUA_CONTEXT_TIMER diff --git a/src/ngx_http_lua_directive.c b/src/ngx_http_lua_directive.c index c8317edf3d..f1623056b5 100644 --- a/src/ngx_http_lua_directive.c +++ b/src/ngx_http_lua_directive.c @@ -17,6 +17,7 @@ #include "ngx_http_lua_cache.h" #include "ngx_http_lua_contentby.h" #include "ngx_http_lua_accessby.h" +#include "ngx_http_lua_server_rewriteby.h" #include "ngx_http_lua_rewriteby.h" #include "ngx_http_lua_logby.h" #include "ngx_http_lua_headerfilterby.h" @@ -590,6 +591,111 @@ ngx_http_lua_rewrite_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } +char * +ngx_http_lua_server_rewrite_by_lua_block(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf) +{ + char *rv; + ngx_conf_t save; + save = *cf; + cf->handler = ngx_http_lua_server_rewrite_by_lua; + cf->handler_conf = conf; + + rv = ngx_http_lua_conf_lua_block_parse(cf, cmd); + + *cf = save; + + return rv; +} + + +char * +ngx_http_lua_server_rewrite_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + size_t chunkname_len; + u_char *cache_key = NULL, *chunkname; + ngx_str_t *value; + ngx_http_lua_main_conf_t *lmcf; + ngx_http_lua_srv_conf_t *lscf = conf; + + ngx_http_compile_complex_value_t ccv; + + dd("enter"); + + /* must specify a content handler */ + if (cmd->post == NULL) { + return NGX_CONF_ERROR; + } + + if (lscf->srv.server_rewrite_handler) { + return "is duplicate"; + } + + value = cf->args->elts; + + if (value[1].len == 0) { + /* Oops...Invalid location conf */ + ngx_conf_log_error(NGX_LOG_ERR, cf, 0, + "invalid location config: no runnable Lua code"); + + return NGX_CONF_ERROR; + } + + if (cmd->post == ngx_http_lua_server_rewrite_handler_inline) { + chunkname = + ngx_http_lua_gen_chunk_name(cf, "server_rewrite_by_lua", + sizeof("server_rewrite_by_lua") - 1, + &chunkname_len); + if (chunkname == NULL) { + return NGX_CONF_ERROR; + } + + cache_key = + ngx_http_lua_gen_chunk_cache_key(cf, "server_rewrite_by_lua", + value[1].data, + value[1].len); + if (cache_key == NULL) { + return NGX_CONF_ERROR; + } + + /* Don't eval nginx variables for inline lua code */ + lscf->srv.server_rewrite_src.value = value[1]; + lscf->srv.server_rewrite_chunkname = chunkname; + + } else { + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + ccv.cf = cf; + ccv.value = &value[1]; + ccv.complex_value = &lscf->srv.server_rewrite_src; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + if (lscf->srv.server_rewrite_src.lengths == NULL) { + /* no variable found */ + cache_key = ngx_http_lua_gen_file_cache_key(cf, value[1].data, + value[1].len); + if (cache_key == NULL) { + return NGX_CONF_ERROR; + } + } + } + + lscf->srv.server_rewrite_src_key = cache_key; + lscf->srv.server_rewrite_handler = + (ngx_http_lua_srv_conf_handler_pt) cmd->post; + + lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_lua_module); + + lmcf->requires_server_rewrite = 1; + lmcf->requires_capture_filter = 1; + + return NGX_CONF_OK; +} + + char * ngx_http_lua_access_by_lua_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) diff --git a/src/ngx_http_lua_directive.h b/src/ngx_http_lua_directive.h index 315c0a9f2d..4bec5e3094 100644 --- a/src/ngx_http_lua_directive.h +++ b/src/ngx_http_lua_directive.h @@ -25,6 +25,10 @@ char *ngx_http_lua_content_by_lua_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); char *ngx_http_lua_content_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +char *ngx_http_lua_server_rewrite_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +char *ngx_http_lua_server_rewrite_by_lua_block(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); char *ngx_http_lua_rewrite_by_lua_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); char *ngx_http_lua_rewrite_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, diff --git a/src/ngx_http_lua_module.c b/src/ngx_http_lua_module.c index bd4535af35..243974d96d 100644 --- a/src/ngx_http_lua_module.c +++ b/src/ngx_http_lua_module.c @@ -14,6 +14,7 @@ #include "ngx_http_lua_directive.h" #include "ngx_http_lua_capturefilter.h" #include "ngx_http_lua_contentby.h" +#include "ngx_http_lua_server_rewriteby.h" #include "ngx_http_lua_rewriteby.h" #include "ngx_http_lua_accessby.h" #include "ngx_http_lua_logby.h" @@ -291,6 +292,22 @@ static ngx_command_t ngx_http_lua_cmds[] = { (void *) ngx_http_lua_filter_set_by_lua_file }, #endif + /* server_rewrite_by_lua_block { } */ + { ngx_string("server_rewrite_by_lua_block"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS, + ngx_http_lua_server_rewrite_by_lua_block, + NGX_HTTP_SRV_CONF_OFFSET, + 0, + (void *) ngx_http_lua_server_rewrite_handler_inline }, + + /* server_rewrite_by_lua_file filename; */ + { ngx_string("server_rewrite_by_lua_file"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_http_lua_server_rewrite_by_lua, + NGX_HTTP_SRV_CONF_OFFSET, + 0, + (void *) ngx_http_lua_server_rewrite_handler_file }, + /* rewrite_by_lua "" */ { ngx_string("rewrite_by_lua"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF @@ -753,6 +770,16 @@ ngx_http_lua_init(ngx_conf_t *cf) cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); + if (lmcf->requires_server_rewrite) { + h = ngx_array_push( + &cmcf->phases[NGX_HTTP_SERVER_REWRITE_PHASE].handlers); + if (h == NULL) { + return NGX_ERROR; + } + + *h = ngx_http_lua_server_rewrite_handler; + } + if (lmcf->requires_rewrite) { h = ngx_array_push(&cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers); if (h == NULL) { @@ -1291,6 +1318,16 @@ ngx_http_lua_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) } #endif /* NGX_HTTP_SSL */ + + if (conf->srv.server_rewrite_src.value.len == 0) { + conf->srv.server_rewrite_src = prev->srv.server_rewrite_src; + conf->srv.server_rewrite_src_ref = prev->srv.server_rewrite_src_ref; + conf->srv.server_rewrite_src_key = prev->srv.server_rewrite_src_key; + conf->srv.server_rewrite_handler = prev->srv.server_rewrite_handler; + conf->srv.server_rewrite_chunkname + = prev->srv.server_rewrite_chunkname; + } + return NGX_CONF_OK; } diff --git a/src/ngx_http_lua_output.c b/src/ngx_http_lua_output.c index 8d8c71d89e..b2a98d133a 100644 --- a/src/ngx_http_lua_output.c +++ b/src/ngx_http_lua_output.c @@ -63,6 +63,7 @@ ngx_http_lua_ngx_echo(lua_State *L, unsigned newline) } ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE + | NGX_HTTP_LUA_CONTEXT_SERVER_REWRITE | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT); @@ -499,6 +500,7 @@ ngx_http_lua_ngx_flush(lua_State *L) } ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE + | NGX_HTTP_LUA_CONTEXT_SERVER_REWRITE | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT); @@ -653,6 +655,7 @@ ngx_http_lua_ngx_eof(lua_State *L) } ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE + | NGX_HTTP_LUA_CONTEXT_SERVER_REWRITE | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT); @@ -715,6 +718,7 @@ ngx_http_lua_ngx_send_headers(lua_State *L) } ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE + | NGX_HTTP_LUA_CONTEXT_SERVER_REWRITE | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT); diff --git a/src/ngx_http_lua_req_body.c b/src/ngx_http_lua_req_body.c index d6e5640a0b..935fafc8a4 100644 --- a/src/ngx_http_lua_req_body.c +++ b/src/ngx_http_lua_req_body.c @@ -101,6 +101,7 @@ ngx_http_lua_ngx_req_read_body(lua_State *L) } ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE + | NGX_HTTP_LUA_CONTEXT_SERVER_REWRITE | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT); diff --git a/src/ngx_http_lua_server_rewriteby.c b/src/ngx_http_lua_server_rewriteby.c new file mode 100644 index 0000000000..22bb69e8c8 --- /dev/null +++ b/src/ngx_http_lua_server_rewriteby.c @@ -0,0 +1,339 @@ + +/* + * Copyright (C) Xiaozhe Wang (chaoslawful) + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + +#include +#include "ngx_http_lua_server_rewriteby.h" +#include "ngx_http_lua_util.h" +#include "ngx_http_lua_exception.h" +#include "ngx_http_lua_cache.h" + +static ngx_int_t ngx_http_lua_server_rewrite_by_chunk(lua_State *L, + ngx_http_request_t *r); + +ngx_int_t +ngx_http_lua_server_rewrite_handler(ngx_http_request_t *r) +{ + ngx_int_t rc; + lua_State *L; + ngx_http_lua_srv_conf_t *lscf; + ngx_http_lua_loc_conf_t *llcf; + ngx_http_lua_ctx_t *ctx; + + /* XXX we need to take into account ngx_rewrite's location dump */ + if (r->uri_changed) { + return NGX_DECLINED; + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua server rewrite handler, uri:\"%V\" c:%ud", &r->uri, + r->main->count); + + lscf = ngx_http_get_module_srv_conf(r, ngx_http_lua_module); + llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); + L = ngx_http_lua_get_lua_vm(r, NULL); + + if (lscf->srv.server_rewrite_handler == NULL) { + dd("no rewrite handler found"); + return NGX_DECLINED; + } + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + + dd("ctx = %p", ctx); + + if (ctx == NULL) { + ctx = ngx_http_lua_create_ctx(r); + if (ctx == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + } + + dd("entered? %d", (int) ctx->entered_server_rewrite_phase); + + if (ctx->entered_server_rewrite_phase) { + dd("rewriteby: calling wev handler"); + rc = ctx->resume_handler(r); + dd("rewriteby: wev handler returns %d", (int) rc); + + if (rc == NGX_OK) { + rc = NGX_DECLINED; + } + + if (rc == NGX_DECLINED) { + if (r->header_sent) { + dd("header already sent"); + + /* response header was already generated in rewrite_by_lua*, + * so it is no longer safe to proceed to later phases + * which may generate responses again */ + + if (!ctx->eof) { + dd("eof not yet sent"); + + rc = ngx_http_lua_send_chain_link(r, ctx, NULL + /* indicate last_buf */); + if (rc == NGX_ERROR || rc > NGX_OK) { + return rc; + } + } + + return NGX_HTTP_OK; + } + + r->write_event_handler = ngx_http_core_run_phases; + ctx->entered_server_rewrite_phase = 0; + + return NGX_DECLINED; + } + + return rc; + } + + if (ctx->waiting_more_body) { + return NGX_DONE; + } + + /* TODO: lscf do not have force_read_body */ + if (llcf->force_read_body && !ctx->read_body_done) { + r->request_body_in_single_buf = 1; + r->request_body_in_persistent_file = 1; + r->request_body_in_clean_file = 1; + + rc = ngx_http_read_client_request_body(r, + ngx_http_lua_generic_phase_post_read); + + if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { + return rc; + } + + if (rc == NGX_AGAIN) { + ctx->waiting_more_body = 1; + return NGX_DONE; + } + } + + dd("calling server rewrite handler"); + return lscf->srv.server_rewrite_handler(r, lscf, L); +} + + +ngx_int_t +ngx_http_lua_server_rewrite_handler_inline(ngx_http_request_t *r, + ngx_http_lua_srv_conf_t *lscf, lua_State *L) +{ + ngx_int_t rc; + + dd("server_rewrite by lua inline"); + + + /* load Lua inline script (w/ cache) sp = 1 */ + rc = ngx_http_lua_cache_loadbuffer(r->connection->log, L, + lscf->srv.server_rewrite_src.value.data, + lscf->srv.server_rewrite_src.value.len, + &lscf->srv.server_rewrite_src_ref, + lscf->srv.server_rewrite_src_key, + (const char *) + lscf->srv.server_rewrite_chunkname); + if (rc != NGX_OK) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + return ngx_http_lua_server_rewrite_by_chunk(L, r); +} + + +ngx_int_t +ngx_http_lua_server_rewrite_handler_file(ngx_http_request_t *r, + ngx_http_lua_srv_conf_t *lscf, lua_State *L) +{ + ngx_int_t rc; + u_char *script_path; + ngx_str_t eval_src; + + + if (ngx_http_complex_value(r, &lscf->srv.server_rewrite_src, + &eval_src) != NGX_OK) + { + return NGX_ERROR; + } + + script_path = ngx_http_lua_rebase_path(r->pool, eval_src.data, + eval_src.len); + + if (script_path == NULL) { + return NGX_ERROR; + } + + /* load Lua script file (w/ cache) sp = 1 */ + rc = ngx_http_lua_cache_loadfile(r->connection->log, L, script_path, + &lscf->srv.server_rewrite_src_ref, + lscf->srv.server_rewrite_src_key); + if (rc != NGX_OK) { + if (rc < NGX_HTTP_SPECIAL_RESPONSE) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + return rc; + } + + return ngx_http_lua_server_rewrite_by_chunk(L, r); +} + + +static ngx_int_t +ngx_http_lua_server_rewrite_by_chunk(lua_State *L, ngx_http_request_t *r) +{ + int co_ref; + lua_State *co; + ngx_int_t rc; + ngx_uint_t nreqs; + ngx_event_t *rev; + ngx_connection_t *c; + ngx_http_lua_ctx_t *ctx; + ngx_http_cleanup_t *cln; + + ngx_http_lua_loc_conf_t *llcf; + + /* {{{ new coroutine to handle request */ + co = ngx_http_lua_new_thread(r, L, &co_ref); + + if (co == NULL) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "lua: failed to create new coroutine to handle request"); + + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + /* move code closure to new coroutine */ + lua_xmove(L, co, 1); + +#ifndef OPENRESTY_LUAJIT + /* set closure's env table to new coroutine's globals table */ + ngx_http_lua_get_globals_table(co); + lua_setfenv(co, -2); +#endif + + /* save nginx request in coroutine globals table */ + ngx_http_lua_set_req(co, r); + + /* {{{ initialize request context */ + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + + dd("ctx = %p", ctx); + + if (ctx == NULL) { + return NGX_ERROR; + } + + ngx_http_lua_reset_ctx(r, L, ctx); + + ctx->entered_server_rewrite_phase = 1; + + ctx->cur_co_ctx = &ctx->entry_co_ctx; + ctx->cur_co_ctx->co = co; + ctx->cur_co_ctx->co_ref = co_ref; +#ifdef NGX_LUA_USE_ASSERT + ctx->cur_co_ctx->co_top = 1; +#endif + + ngx_http_lua_attach_co_ctx_to_L(co, ctx->cur_co_ctx); + + /* }}} */ + + /* {{{ register request cleanup hooks */ + if (ctx->cleanup == NULL) { + cln = ngx_http_cleanup_add(r, 0); + if (cln == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + cln->handler = ngx_http_lua_request_cleanup_handler; + cln->data = ctx; + ctx->cleanup = &cln->handler; + } + /* }}} */ + + ctx->context = NGX_HTTP_LUA_CONTEXT_SERVER_REWRITE; + + llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); + + if (llcf->check_client_abort) { + r->read_event_handler = ngx_http_lua_rd_check_broken_connection; + +#if (NGX_HTTP_V2) + if (!r->stream) { +#endif + + rev = r->connection->read; + + if (!rev->active) { + if (ngx_add_event(rev, NGX_READ_EVENT, 0) != NGX_OK) { + return NGX_ERROR; + } + } + +#if (NGX_HTTP_V2) + } +#endif + + } else { + r->read_event_handler = ngx_http_block_reading; + } + + c = r->connection; + nreqs = c->requests; + + rc = ngx_http_lua_run_thread(L, r, ctx, 0); + + if (rc == NGX_ERROR || rc > NGX_OK) { + return rc; + } + + if (rc == NGX_AGAIN) { + rc = ngx_http_lua_run_posted_threads(c, L, r, ctx, nreqs); + + } else if (rc == NGX_DONE) { + ngx_http_lua_finalize_request(r, NGX_DONE); + rc = ngx_http_lua_run_posted_threads(c, L, r, ctx, nreqs); + } + + if (rc == NGX_OK || rc == NGX_DECLINED) { + if (r->header_sent) { + dd("header already sent"); + + /* response header was already generated in rewrite_by_lua*, + * so it is no longer safe to proceed to later phases + * which may generate responses again */ + + if (!ctx->eof) { + dd("eof not yet sent"); + + rc = ngx_http_lua_send_chain_link(r, ctx, NULL + /* indicate last_buf */); + if (rc == NGX_ERROR || rc > NGX_OK) { + return rc; + } + } + + return NGX_HTTP_OK; + } + + r->write_event_handler = ngx_http_core_run_phases; + ctx->entered_server_rewrite_phase = 0; + + return NGX_DECLINED; + } + + return rc; +} + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_server_rewriteby.h b/src/ngx_http_lua_server_rewriteby.h new file mode 100644 index 0000000000..a35ebd2b72 --- /dev/null +++ b/src/ngx_http_lua_server_rewriteby.h @@ -0,0 +1,20 @@ + +/* + * Copyright (C) Xiaozhe Wang (chaoslawful) + * Copyright (C) Yichun Zhang (agentzh) + */ + +#ifndef _NGX_HTTP_LUA_SERVER_REWRITEBY_H_INCLUDED_ +#define _NGX_HTTP_LUA_SERVER_REWRITEBY_H_INCLUDED_ + +#include "ngx_http_lua_common.h" + +ngx_int_t ngx_http_lua_server_rewrite_handler(ngx_http_request_t *r); +ngx_int_t ngx_http_lua_server_rewrite_handler_inline(ngx_http_request_t *r, + ngx_http_lua_srv_conf_t *lscf, lua_State *L); +ngx_int_t ngx_http_lua_server_rewrite_handler_file(ngx_http_request_t *r, + ngx_http_lua_srv_conf_t *lscf, lua_State *L); + +#endif /* _NGX_HTTP_LUA_SERVER_REWRITEBY_H_INCLUDED_ */ + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 72549ca41e..1f564ac129 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -4931,6 +4931,7 @@ ngx_http_lua_req_socket(lua_State *L) } ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE + | NGX_HTTP_LUA_CONTEXT_SERVER_REWRITE | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT); diff --git a/src/ngx_http_lua_uri.c b/src/ngx_http_lua_uri.c index 0f88846fef..c37dde9cb2 100644 --- a/src/ngx_http_lua_uri.c +++ b/src/ngx_http_lua_uri.c @@ -92,12 +92,14 @@ ngx_http_lua_ngx_req_set_uri(lua_State *L) return luaL_error(L, "no ctx found"); } - dd("rewrite: %d, access: %d, content: %d", + dd("server_rewrite: %d, rewrite: %d, access: %d, content: %d", + (int) ctx->entered_serverrewrite_phase, (int) ctx->entered_rewrite_phase, (int) ctx->entered_access_phase, (int) ctx->entered_content_phase); - ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE); + ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE + | NGX_HTTP_LUA_CONTEXT_SERVER_REWRITE); ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua set uri jump to \"%*s\"", len, p); diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 762958396b..39ba0b21fb 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -1003,6 +1003,7 @@ ngx_http_lua_reset_ctx(ngx_http_request_t *r, lua_State *L, ctx->entry_co_ctx.co_ref = LUA_NOREF; + ctx->entered_server_rewrite_phase = 0; ctx->entered_rewrite_phase = 0; ctx->entered_access_phase = 0; ctx->entered_content_phase = 0; diff --git a/src/ngx_http_lua_util.h b/src/ngx_http_lua_util.h index 52b1ff9356..4c4da976c5 100644 --- a/src/ngx_http_lua_util.h +++ b/src/ngx_http_lua_util.h @@ -33,6 +33,7 @@ #define NGX_HTTP_LUA_ESCAPE_HEADER_VALUE 8 #define NGX_HTTP_LUA_CONTEXT_YIELDABLE (NGX_HTTP_LUA_CONTEXT_REWRITE \ + | NGX_HTTP_LUA_CONTEXT_SERVER_REWRITE \ | NGX_HTTP_LUA_CONTEXT_ACCESS \ | NGX_HTTP_LUA_CONTEXT_CONTENT \ | NGX_HTTP_LUA_CONTEXT_TIMER \ @@ -48,6 +49,7 @@ #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*" \ + : (c) == NGX_HTTP_LUA_CONTEXT_SERVER_REWRITE ? "server_rewrite_by_lua*" \ : (c) == NGX_HTTP_LUA_CONTEXT_ACCESS ? "access_by_lua*" \ : (c) == NGX_HTTP_LUA_CONTEXT_CONTENT ? "content_by_lua*" \ : (c) == NGX_HTTP_LUA_CONTEXT_LOG ? "log_by_lua*" \ diff --git a/t/089-phase.t b/t/089-phase.t index 355b7ac33f..028c400c73 100644 --- a/t/089-phase.t +++ b/t/089-phase.t @@ -8,7 +8,7 @@ log_level('warn'); repeat_each(2); -plan tests => repeat_each() * (blocks() * 2 + 1) + 2; +plan tests => repeat_each() * (blocks() * 2 + 2) + 2; #no_diff(); #no_long_string(); @@ -201,3 +201,23 @@ ok qr/exit_worker_by_lua\(nginx\.conf:\d+\):\d+: exit_worker/, qr/exiting now$/, ] + + + +=== TEST 12: server_rewrite_by_lua_block in http +--- http_config + server_rewrite_by_lua_block { + ngx.ctx.phase = ngx.get_phase() + } +--- config + location /lua { + content_by_lua_block { + ngx.say(ngx.ctx.phase) + } + } +--- request +GET /lua +--- response_body +server_rewrite +--- no_error_log +[error] diff --git a/t/162-socket-tls-handshake.t b/t/162-socket-tls-handshake.t index c4076af042..4474895c53 100644 --- a/t/162-socket-tls-handshake.t +++ b/t/162-socket-tls-handshake.t @@ -371,6 +371,3 @@ failed to setclientcert: client certificate must be supplied with corresponding [error] [crit] [emerg] - - - diff --git a/t/167-server-rewrite.t b/t/167-server-rewrite.t new file mode 100644 index 0000000000..152c5ce35d --- /dev/null +++ b/t/167-server-rewrite.t @@ -0,0 +1,488 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use Test::Nginx::Socket::Lua; +use t::StapThread; + +our $GCScript = <<_EOC_; +$t::StapThread::GCScript + +F(ngx_http_lua_check_broken_connection) { + println("lua check broken conn") +} + +F(ngx_http_lua_request_cleanup) { + println("lua req cleanup") +} +_EOC_ + +our $StapScript = $t::StapThread::StapScript; + +repeat_each(2); + +plan tests => repeat_each() * (blocks() * 3 + 10); + +#log_level("info"); +#no_long_string(); + +run_tests(); + +__DATA__ + +=== TEST 1: server_rewrite_by_lua_block in http +--- http_config + server_rewrite_by_lua_block { + ngx.ctx.a = "server_rewrite_by_lua_block in http" + } +--- config + location /lua { + content_by_lua_block { + ngx.say(ngx.ctx.a) + ngx.log(ngx.INFO, ngx.ctx.a) + } + } +--- request +GET /lua +--- response_body +server_rewrite_by_lua_block in http +--- error_log +server_rewrite_by_lua_block in http +--- no_error_log +[error] + + + +=== TEST 2: server_rewrite_by_lua_block in server +--- config + server_rewrite_by_lua_block { + ngx.log(ngx.INFO, "server_rewrite_by_lua_block in server") + } + location /lua { + content_by_lua_block { + ngx.say("OK") + } + } +--- request +GET /lua +--- response_body +OK +--- error_log +server_rewrite_by_lua_block in server +--- no_error_log +[error] + + + +=== TEST 3: redirect +--- config + server_rewrite_by_lua_block { + ngx.redirect("/foo") + } +--- request +GET /lua +--- raw_response_headers_like: Location: /foo\r\n +--- response_body_like: 302 Found +--- error_code: 302 +--- no_error_log +[error] + + + +=== TEST 4: flush +--- config + server_rewrite_by_lua_block { + ngx.say("foo") + ngx.flush(true) + } + location /lua { + content_by_lua_block { + ngx.say("OK") + } + } +--- request +GET /lua +--- response_body +foo +--- no_error_log +[error] + + + +=== TEST 5: eof +--- config + server_rewrite_by_lua_block { + ngx.say("foo") + ngx.eof() + } + location /lua { + content_by_lua_block { + ngx.say("OK") + } + } +--- request +GET /lua +--- response_body +foo +--- no_error_log +[error] + + + +=== TEST 6: send_headers +--- config + server_rewrite_by_lua_block { + ngx.header["Foox"] = {"conx1", "conx2" } + ngx.header["Fooy"] = {"cony1", "cony2" } + ngx.send_headers() + } + location /lua { + content_by_lua_block { + ngx.say("OK") + } + } +--- request +GET /lua +--- response_body +--- response_headers +Foox: conx1, conx2 +Fooy: cony1, cony2 +--- no_error_log +[error] + + + +=== TEST 7: read_body +--- config + server_rewrite_by_lua_block { + ngx.req.read_body() + ngx.say(ngx.var.request_body) + } +--- request +POST /lua +hello, world +--- response_body +hello, world +--- no_error_log +[error] + + + +=== TEST 8: req_sock +--- config + server_rewrite_by_lua_block { + local sock = ngx.req.socket() + sock:receive(2) + sock:receive(2) + sock:receive(1) + ngx.sleep(1) + } + location /lua { + content_by_lua_block { + ngx.say("OK") + } + } +--- request +POST /lua +hello + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +lua check broken conn +lua check broken conn +lua req cleanup +delete thread 1 + +--- wait: 1 +--- timeout: 0.2 +--- abort +--- ignore_response +--- no_error_log +[error] + + + +=== TEST 9: rewrite args (not break cycle by default) +--- config + location /bar { + echo "bar: $uri?$args"; + } + server_rewrite_by_lua_block { + if ngx.var.uri ~= "/bar" then + ngx.req.set_uri_args("hello") + ngx.req.set_uri("/bar", true) + end + } + location /foo { + + echo "foo: $uri?$args"; + } +--- request + GET /foo?world +--- response_body +bar: /bar?hello + + + +=== TEST 10: server_rewrite_by_lua_block overwrite by server +--- http_config + server_rewrite_by_lua_block { + ngx.log(ngx.INFO, "server_rewrite_by_lua_block in http") + } +--- config + server_rewrite_by_lua_block { + ngx.log(ngx.INFO, "server_rewrite_by_lua_block in server") + } + location /lua { + content_by_lua_block { + ngx.say("OK") + } + } +--- request +GET /lua +--- response_body +OK +--- error_log +server_rewrite_by_lua_block in server +--- no_error_log +[error] + + + +=== TEST 11: sleep +--- config + server_rewrite_by_lua_block { + ngx.sleep(0.001) + ngx.log(ngx.INFO, "server_rewrite_by_lua_block in server") + } + location /lua { + content_by_lua_block { + ngx.say("OK") + } + } +--- request +GET /lua +--- response_body +OK +--- error_log +server_rewrite_by_lua_block in server +--- no_error_log +[error] + + + +=== TEST 12: ngx.exit(ngx.OK) +--- config + server_rewrite_by_lua_block { + ngx.log(ngx.INFO, "ngx.exit") + ngx.exit(ngx.OK) + } + location /lua { + content_by_lua_block { + ngx.say("OK") + } + } +--- request +GET /lua +--- response_body +OK +--- error_log +ngx.exit +--- no_error_log +[error] + + + +=== TEST 13: ngx.exit(503) +--- config + server_rewrite_by_lua_block { + ngx.exit(503) + } + location /lua { + content_by_lua_block { + ngx.log(ngx.ERR, "content_by_lua") + ngx.say("OK") + } + } +--- request +GET /lua +--- error_code: 503 +--- no_error_log +[error] + + + +=== TEST 14: subrequests +--- config + server_rewrite_by_lua_block { + ngx.log(ngx.INFO, "is_subrequest:", ngx.is_subrequest) + } + + location /lua { + content_by_lua_block { + local res = ngx.location.capture("/sub") + ngx.print(res.body) + } + } + + location /sub { + content_by_lua_block { + ngx.say("OK") + } + } + +--- request +GET /lua +--- response_body +OK +--- error_log +is_subrequest:false +is_subrequest:true +--- no_error_log +[error] + + + +=== TEST 15: rewrite by ngx_http_rewrite_module +--- config + server_rewrite_by_lua_block { + ngx.log(ngx.INFO, "uri is ", ngx.var.uri) + } + + rewrite ^ /re; + + location /re { + content_by_lua_block { + ngx.say("RE") + } + } + + location /ok { + content_by_lua_block { + ngx.say("OK") + } + } + +--- request +GET /lua +--- response_body +RE +--- error_log +uri is /lua +--- no_error_log +[error] + + + +=== TEST 16: exec +--- config + server_rewrite_by_lua_block { + if ngx.var.uri ~= "/ok" then + ngx.exec("/ok") + end + ngx.log(ngx.INFO, "uri is ", ngx.var.uri) + } + + location /ok { + content_by_lua_block { + ngx.say("OK") + } + } + +--- request +GET /lua +--- response_body +OK +--- error_log +uri is /ok +--- no_error_log +[error] + + + +=== TEST 17: server_rewrite_by_lua and rewrite_by_lua +--- http_config + server_rewrite_by_lua_block { + ngx.log(ngx.INFO, "server_rewrite_by_lua_block in http") + } +--- config + location /lua { + rewrite_by_lua_block { + ngx.log(ngx.INFO, "rewrite_by_lua_block in location") + } + content_by_lua_block { + ngx.say("OK") + } + } +--- request +GET /lua +--- response_body +OK +--- error_log +server_rewrite_by_lua_block in http +rewrite_by_lua_block in location +--- no_error_log +[error] + + + +=== TEST 18: server_rewrite_by_lua_file +--- http_config + server_rewrite_by_lua_file 'html/foo.lua'; +--- config + location /lua { + content_by_lua_block { + ngx.say("OK") + } + } +--- request +GET /lua +--- user_files +>>> foo.lua +ngx.log(ngx.INFO, "rewrite_by_lua_file in server") +--- response_body +OK +--- error_log +rewrite_by_lua_file in server +--- no_error_log +[error] + + + +=== TEST 19: syntax error server_rewrite_by_lua_block in http +--- http_config + server_rewrite_by_lua_block { + 'for end'; + } +--- config + location /lua { + content_by_lua_block { + ngx.say("OK") + } + } +--- request +GET /lua +--- ignore_response +--- error_log +failed to load inlined Lua code: server_rewrite_by_lua(nginx.conf:25):2: unexpected symbol near ''for end'' +--- no_error_log +no_such_error + + + +=== TEST 20: syntax error server_rewrite_by_lua_block in server +--- config + server_rewrite_by_lua_block { + 'for end'; + } + location /lua { + content_by_lua_block { + ngx.say("Hello world") + } + } +--- request +GET /lua +--- ignore_response +--- error_log +failed to load inlined Lua code: server_rewrite_by_lua(nginx.conf:39):2: unexpected symbol near ''for end'' +--- no_error_log +no_such_error From 6c0cc5c45635a6fbaf9b6ebeda5232f4004f5cbc Mon Sep 17 00:00:00 2001 From: lijunlong Date: Mon, 21 Mar 2022 20:35:46 +0800 Subject: [PATCH 025/254] doc: did not generate README.markdown from doc/HttpLuaModule.wiki. (#2029) --- README.markdown | 2 +- doc/HttpLuaModule.wiki | 24 +++++++++++++++++++++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/README.markdown b/README.markdown index 98d92a6b08..7bcbedffd7 100644 --- a/README.markdown +++ b/README.markdown @@ -7819,7 +7819,7 @@ This method was first introduced in the `v0.5.0rc1` release. [Back to TOC](#nginx-api-for-lua) tcpsock:setclientcert --------------------- +--------------------- **syntax:** *ok, err = tcpsock:setclientcert(cert, pkey)* diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 9270d18da0..6185b6d653 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -812,7 +812,6 @@ phases. * add ignore_resp_headers, ignore_resp_body, and ignore_resp options to [[#ngx.location.capture|ngx.location.capture]] and [[#ngx.location.capture_multi|ngx.location.capture_multi]] methods, to allow micro performance tuning on the user side. * add automatic Lua code time slicing support by yielding and resuming the Lua VM actively via Lua's debug hooks. * add stat mode similar to [https://httpd.apache.org/docs/trunk/mod/mod_lua.html mod_lua]. -* cosocket: add client SSL certificate support. = Changes = @@ -6500,6 +6499,7 @@ This API function was first added to the v0.10.1 release. Creates and returns a TCP or stream-oriented unix domain socket object (also known as one type of the "cosocket" objects). The following methods are supported on this object: * [[#tcpsock:connect|connect]] +* [[#tcpsock:setclientcert|setclientcert]] * [[#tcpsock:sslhandshake|sslhandshake]] * [[#tcpsock:send|send]] * [[#tcpsock:receive|receive]] @@ -6650,6 +6650,28 @@ The support for the options table argument was first introduced in the v0. This method was first introduced in the v0.5.0rc1 release. +== tcpsock:setclientcert == + +'''syntax:''' ''ok, err = tcpsock:setclientcert(cert, pkey)'' + +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_client_hello_by_lua*'' + +Set client certificate chain and corresponding private key to the TCP socket object. +The certificate chain and private key provided will be used later by the [tcpsock:sslhandshake](#tcpsocksslhandshake) method. + +* cert specify a client certificate chain cdata object that will be used while handshaking with +remote server. These objects can be created using [ngx.ssl.parse\_pem\_cert](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ssl.md#parse_pem_cert) +function provided by lua-resty-core. Note that specifying the cert option requires +corresponding pkey be provided too. See below. +* pkey specify a private key corresponds to the cert option above. +These objects can be created using [ngx.ssl.parse\_pem\_priv\_key](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ssl.md#parse_pem_priv_key) +function provided by lua-resty-core. + +If both of cert and pkey are nil, this method will clear any existing client certificate and private key +that was previously set on the cosocket object. + +This method was first introduced in the `v0.10.22` release. + == tcpsock:sslhandshake == '''syntax:''' ''session, err = tcpsock:sslhandshake(reused_session?, server_name?, ssl_verify?, send_status_req?)'' From f0c04dbf61b17d4742f90f1aeab94cbe4170c830 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Fri, 1 Apr 2022 23:04:02 +0800 Subject: [PATCH 026/254] bugfix: failed to compile when nginx https is disabled. (#2034) --- src/ngx_http_lua_common.h | 4 ++-- src/ngx_http_lua_module.c | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h index f293c5b1d9..31b39fc709 100644 --- a/src/ngx_http_lua_common.h +++ b/src/ngx_http_lua_common.h @@ -313,8 +313,8 @@ struct ngx_http_lua_main_conf_s { union ngx_http_lua_srv_conf_u { -#if (NGX_HTTP_SSL) struct { +#if (NGX_HTTP_SSL) ngx_http_lua_srv_conf_handler_pt ssl_cert_handler; ngx_str_t ssl_cert_src; u_char *ssl_cert_src_key; @@ -338,6 +338,7 @@ union ngx_http_lua_srv_conf_u { u_char *ssl_client_hello_src_key; u_char *ssl_client_hello_chunkname; int ssl_client_hello_src_ref; +#endif ngx_http_lua_srv_conf_handler_pt server_rewrite_handler; ngx_http_complex_value_t server_rewrite_src; @@ -345,7 +346,6 @@ union ngx_http_lua_srv_conf_u { u_char *server_rewrite_chunkname; int server_rewrite_src_ref; } srv; -#endif struct { ngx_http_lua_srv_conf_handler_pt handler; diff --git a/src/ngx_http_lua_module.c b/src/ngx_http_lua_module.c index 243974d96d..16f442464c 100644 --- a/src/ngx_http_lua_module.c +++ b/src/ngx_http_lua_module.c @@ -1180,10 +1180,11 @@ ngx_http_lua_create_srv_conf(ngx_conf_t *cf) static char * ngx_http_lua_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) { + ngx_http_lua_srv_conf_t *conf = child; + ngx_http_lua_srv_conf_t *prev = parent; + #if (NGX_HTTP_SSL) - ngx_http_lua_srv_conf_t *prev = parent; - ngx_http_lua_srv_conf_t *conf = child; ngx_http_ssl_srv_conf_t *sscf; dd("merge srv conf"); From bc2ecdae2cb88beba2d4fe190ec3560a4d3dec74 Mon Sep 17 00:00:00 2001 From: xiaobiaozhao <52393536+xiaobiaozhao@users.noreply.github.com> Date: Sat, 2 Apr 2022 08:47:09 +0800 Subject: [PATCH 027/254] ci: add util/build-without-ssl.sh. (#2035) --- .travis.yml | 2 ++ util/build-without-ssl.sh | 67 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100755 util/build-without-ssl.sh diff --git a/.travis.yml b/.travis.yml index 6e6ecee4f6..56ff18e272 100644 --- a/.travis.yml +++ b/.travis.yml @@ -130,6 +130,8 @@ script: - sudo make PATH=$PATH install_sw > build.log 2>&1 || (cat build.log && exit 1) - cd .. - export NGX_BUILD_CC=$CC + - sh util/build-without-ssl.sh $NGINX_VERSION > build.log 2>&1 || (cat build.log && exit 1) + - rm -fr buildroot - sh util/build.sh $NGINX_VERSION > build.log 2>&1 || (cat build.log && exit 1) - nginx -V - ldd `which nginx`|grep -E 'luajit|ssl|pcre' diff --git a/util/build-without-ssl.sh b/util/build-without-ssl.sh new file mode 100755 index 0000000000..906be75706 --- /dev/null +++ b/util/build-without-ssl.sh @@ -0,0 +1,67 @@ +#!/usr/bin/env bash + +# this script is for developers only. +# dependent on the ngx-build script from the nginx-devel-utils repository: +# https://github.com/openresty/nginx-devel-utils/blob/master/ngx-build +# the resulting nginx is located at ./work/nginx/sbin/nginx + +root=`pwd` +version=${1:-1.4.1} +home=~ +force=$2 + +# the ngx-build script is from https://github.com/agentzh/nginx-devel-utils + + #--add-module=$home/work/nginx_upload_module-2.2.0 \ + + #--without-pcre \ + #--without-http_rewrite_module \ + #--without-http_autoindex_module \ + #--with-cc=gcc46 \ + #--with-cc=clang \ + #--without-http_referer_module \ + #--with-http_spdy_module \ + +add_fake_shm_module="--add-module=$root/t/data/fake-shm-module" + +time ngx-build $force $version \ + --with-threads \ + --with-pcre-jit \ + --with-ipv6 \ + --with-cc-opt="-DNGX_LUA_USE_ASSERT -I$PCRE_INC" \ + --with-http_v2_module \ + --with-http_realip_module \ + --add-module=$root/../ndk-nginx-module \ + --add-module=$root/../set-misc-nginx-module \ + --with-ld-opt="-L$PCRE_LIB -Wl,-rpath,$PCRE_LIB:$LIBDRIZZLE_LIB" \ + --without-mail_pop3_module \ + --without-mail_imap_module \ + --with-http_image_filter_module \ + --without-mail_smtp_module \ + --with-stream \ + --without-http_upstream_ip_hash_module \ + --without-http_memcached_module \ + --without-http_auth_basic_module \ + --without-http_userid_module \ + --with-http_auth_request_module \ + --add-module=$root/../echo-nginx-module \ + --add-module=$root/../memc-nginx-module \ + --add-module=$root/../srcache-nginx-module \ + --add-module=$root \ + --add-module=$root/../lua-upstream-nginx-module \ + --add-module=$root/../headers-more-nginx-module \ + --add-module=$root/../drizzle-nginx-module \ + --add-module=$root/../rds-json-nginx-module \ + --add-module=$root/../coolkit-nginx-module \ + --add-module=$root/../redis2-nginx-module \ + --add-module=$root/../stream-lua-nginx-module \ + --add-module=$root/t/data/fake-module \ + $add_fake_shm_module \ + --add-module=$root/t/data/fake-delayed-load-module \ + --with-http_gunzip_module \ + --with-http_dav_module \ + --with-select_module \ + --with-poll_module \ + $opts \ + --with-debug + From 653d6a36f46b077cb902d7ba40824c299cf9bbf4 Mon Sep 17 00:00:00 2001 From: Chrono Date: Wed, 6 Apr 2022 20:48:29 +0800 Subject: [PATCH 028/254] bugfix: Apple Silicon FFI ABI limitation workaround There is a known issue in LuaJIT (https://github.com/LuaJIT/LuaJIT/issues/205#issuecomment-236426398) that passing non 64-bit value after the 8th argument in FFI calls doesn't work on Apple ARM64 devices, there is no plan on addressing this issue anytime soon from LuaJIT side. This commit conditionally compiles proxy FFI functions that takes in pointer to struct in order to reduce the length of the argument list, getting around this issue. --- src/ngx_http_lua_headers.c | 12 +++++++++ src/ngx_http_lua_headers_out.h | 16 ++++++++++++ src/ngx_http_lua_shdict.c | 34 +++++++++++++++++++++++++ src/ngx_http_lua_shdict.h | 46 ++++++++++++++++++++++++++++++++++ 4 files changed, 108 insertions(+) diff --git a/src/ngx_http_lua_headers.c b/src/ngx_http_lua_headers.c index 54977dce8e..8098615dfc 100644 --- a/src/ngx_http_lua_headers.c +++ b/src/ngx_http_lua_headers.c @@ -1240,4 +1240,16 @@ ngx_http_lua_ngx_raw_header_cleanup(void *data) #endif +#if (NGX_DARWIN) +int +ngx_http_lua_ffi_set_resp_header_macos(ngx_http_lua_set_resp_header_params_t *p) +{ + return ngx_http_lua_ffi_set_resp_header(p->r, p->key_data, p->key_len, + p->is_nil, p->sval, p->sval_len, + p->mvals, p->mvals_len, + p->override, p->errmsg); +} +#endif + + /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_headers_out.h b/src/ngx_http_lua_headers_out.h index 944f57a462..eb3c794723 100644 --- a/src/ngx_http_lua_headers_out.h +++ b/src/ngx_http_lua_headers_out.h @@ -12,6 +12,22 @@ #include "ngx_http_lua_common.h" +#if (NGX_DARWIN) +typedef struct { + ngx_http_request_t *r; + const char *key_data; + size_t key_len; + int is_nil; + const char *sval; + size_t sval_len; + void *mvals; + size_t mvals_len; + int override; + char **errmsg; +} ngx_http_lua_set_resp_header_params_t; +#endif + + 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, diff --git a/src/ngx_http_lua_shdict.c b/src/ngx_http_lua_shdict.c index 26622d29f0..27f3b100f3 100644 --- a/src/ngx_http_lua_shdict.c +++ b/src/ngx_http_lua_shdict.c @@ -2092,4 +2092,38 @@ ngx_http_lua_ffi_shdict_free_space(ngx_shm_zone_t *zone) #endif +#if (NGX_DARWIN) +int +ngx_http_lua_ffi_shdict_get_macos(ngx_http_lua_shdict_get_params_t *p) +{ + return ngx_http_lua_ffi_shdict_get(p->zone, p->key, p->key_len, + p->value_type, p->str_value_buf, + p->str_value_len, p->num_value, + p->user_flags, p->get_stale, + p->is_stale, p->errmsg); +} + + +int +ngx_http_lua_ffi_shdict_store_macos(ngx_http_lua_shdict_store_params_t *p) +{ + return ngx_http_lua_ffi_shdict_store(p->zone, p->op, p->key, p->key_len, + p->value_type, p->str_value_buf, + p->str_value_len, p->num_value, + p->exptime, p->user_flags, + p->errmsg, p->forcible); +} + + +int +ngx_http_lua_ffi_shdict_incr_macos(ngx_http_lua_shdict_incr_params_t *p) +{ + return ngx_http_lua_ffi_shdict_incr(p->zone, p->key, p->key_len, + p->num_value, p->errmsg, + p->has_init, p->init, p->init_ttl, + p->forcible); +} +#endif + + /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_shdict.h b/src/ngx_http_lua_shdict.h index 90a0099f5d..67dd4d4eb0 100644 --- a/src/ngx_http_lua_shdict.h +++ b/src/ngx_http_lua_shdict.h @@ -55,6 +55,52 @@ typedef struct { } ngx_http_lua_shm_zone_ctx_t; +#if (NGX_DARWIN) +typedef struct { + void *zone; + const unsigned char *key; + size_t key_len; + int *value_type; + unsigned char **str_value_buf; + size_t *str_value_len; + double *num_value; + int *user_flags; + int get_stale; + int *is_stale; + char **errmsg; +} ngx_http_lua_shdict_get_params_t; + + +typedef struct { + void *zone; + int op; + const unsigned char *key; + size_t key_len; + int value_type; + const unsigned char *str_value_buf; + size_t str_value_len; + double num_value; + long exptime; + int user_flags; + char **errmsg; + int *forcible; +} ngx_http_lua_shdict_store_params_t; + + +typedef struct { + void *zone; + const unsigned char *key; + size_t key_len; + double *num_value; + char **errmsg; + int has_init; + double init; + long init_ttl; + int *forcible; +} ngx_http_lua_shdict_incr_params_t; +#endif + + ngx_int_t ngx_http_lua_shdict_init_zone(ngx_shm_zone_t *shm_zone, void *data); void ngx_http_lua_shdict_rbtree_insert_value(ngx_rbtree_node_t *temp, ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); From 86e1a6446a3b33c41536734df2601a5c469330cf Mon Sep 17 00:00:00 2001 From: jizhuozhi Date: Sun, 8 May 2022 20:59:54 +0800 Subject: [PATCH 029/254] feature: content_by_lua_file return 503 if read err and file is existed #1992 (#1995) --- README.markdown | 2 ++ src/ngx_http_lua_cache.c | 8 +++++++- t/002-content.t | 12 ++++++++++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index 7bcbedffd7..ab92fa06ca 100644 --- a/README.markdown +++ b/README.markdown @@ -1886,6 +1886,8 @@ content_by_lua_file Equivalent to [content_by_lua_block](#content_by_lua_block), except that the file specified by `` contains the Lua code, or, as from the `v0.5.0rc32` release, the [LuaJIT bytecode](#luajit-bytecode-support) to be executed. +If the file is not found, a `404 Not Found` status code will be returned, and a `503 Service Temporarily Unavailable` status code will be returned in case of errors in reading other files. + Nginx variables can be used in the `` string to provide flexibility. This however carries some risks and is not ordinarily recommended. When a relative path like `foo/bar.lua` is given, they will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option while starting the Nginx server. diff --git a/src/ngx_http_lua_cache.c b/src/ngx_http_lua_cache.c index 0b1b8ecda8..534424688d 100644 --- a/src/ngx_http_lua_cache.c +++ b/src/ngx_http_lua_cache.c @@ -307,7 +307,13 @@ ngx_http_lua_cache_loadfile(ngx_log_t *log, lua_State *L, break; case LUA_ERRFILE: - errcode = NGX_HTTP_NOT_FOUND; + if (errno == ENOENT) { + errcode = NGX_HTTP_NOT_FOUND; + + } else { + errcode = NGX_HTTP_SERVICE_UNAVAILABLE; + } + /* fall through */ default: diff --git a/t/002-content.t b/t/002-content.t index 661c2e39e3..54de40ebd5 100644 --- a/t/002-content.t +++ b/t/002-content.t @@ -1086,3 +1086,15 @@ GET /lua --- error_code: 500 --- error_log failed to load inlined Lua code: content_by_lua(...45678901234567890123456789012345.conf:14) + + + +=== TEST 51: Lua file permission denied +--- config + location /lua { + content_by_lua_file /etc/shadow; + } +--- request +GET /lua +--- response_body_like: 503 Service Temporarily Unavailable +--- error_code: 503 From 8a8e710cb9e388b8bfd16d9eee57504e90e3acef Mon Sep 17 00:00:00 2001 From: Ilya Shipitsin Date: Fri, 13 May 2022 04:56:31 +0500 Subject: [PATCH 030/254] fix potential null pointer dereference found by Coverity (#2043) * fix potential null pointer dereference found by Coverity *** CID 352757: Null pointer dereferences (FORWARD_NULL) /src/ngx_http_lua_socket_tcp.c: 1733 in ngx_http_lua_ffi_socket_tcp_sslhandshake() 1727 #else 1728 *errmsg = "no OCSP support"; 1729 return NGX_ERROR; 1730 #endif 1731 } 1732 >>> CID 352757: Null pointer dereferences (FORWARD_NULL) >>> Dereferencing null pointer "server_name". 1733 if (server_name->len == 0) { 1734 u->ssl_name.len = 0; 1735 1736 } else { 1737 if (u->ssl_name.data) { 1738 /* buffer already allocated */ Co-authored-by: lijunlong --- src/ngx_http_lua_socket_tcp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 1f564ac129..35ff6250e1 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -1730,7 +1730,7 @@ ngx_http_lua_ffi_socket_tcp_sslhandshake(ngx_http_request_t *r, #endif } - if (server_name->len == 0) { + if (server_name == NULL || server_name->len == 0) { u->ssl_name.len = 0; } else { From af130ae896aae23877a9ba76c8f57e269a3c4468 Mon Sep 17 00:00:00 2001 From: Ilya Shipitsin Date: Sat, 14 May 2022 17:57:02 +0500 Subject: [PATCH 031/254] fix dead code found by coverity *** CID 352755: Control flow issues (DEADCODE) /src/ngx_http_lua_socket_tcp.c: 1541 in ngx_http_lua_socket_tcp_check_busy() 1535 #if (NGX_HTTP_SSL) 1536 1537 static const char * 1538 ngx_http_lua_socket_tcp_check_busy(ngx_http_request_t *r, 1539 ngx_http_lua_socket_tcp_upstream_t *u, unsigned int ops) 1540 { >>> CID 352755: Control flow issues (DEADCODE) >>> Execution cannot reach the expression "u->conn_waiting" inside this statement: "if (ops & SOCKET_OP_CONNECT...". 1541 if ((ops & SOCKET_OP_CONNECT) && u->conn_waiting) { 1542 return "socket busy connecting"; 1543 } 1544 1545 if ((ops & SOCKET_OP_READ) && u->read_waiting) { 1546 return "socket busy reading"; --- src/ngx_http_lua_socket_tcp.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 35ff6250e1..d8f1d4d1c1 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -166,10 +166,10 @@ enum { enum { - SOCKET_OP_CONNECT, - SOCKET_OP_READ, - SOCKET_OP_WRITE, - SOCKET_OP_RESUME_CONN, + SOCKET_OP_CONNECT = 0x01, + SOCKET_OP_READ = 0x02, + SOCKET_OP_WRITE = 0x04, + SOCKET_OP_RESUME_CONN = 0x08, }; From 381e9b3a61a119df688a9b2452a18d710c385de9 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Fri, 20 May 2022 14:13:27 +0800 Subject: [PATCH 032/254] bugfix: wrong memory size for the pernding timers array. (#2048) --- src/ngx_http_lua_timer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ngx_http_lua_timer.c b/src/ngx_http_lua_timer.c index e82e3406ce..795bd4f5f3 100644 --- a/src/ngx_http_lua_timer.c +++ b/src/ngx_http_lua_timer.c @@ -821,7 +821,7 @@ ngx_http_lua_abort_pending_timers(ngx_event_t *ev) prev = NULL; events = ngx_pcalloc(ngx_cycle->pool, - lmcf->pending_timers * sizeof(ngx_event_t)); + lmcf->pending_timers * sizeof(ngx_event_t *)); if (events == NULL) { return; } From b91221bd6c234a20aab18e41905dcc7d64dea07e Mon Sep 17 00:00:00 2001 From: Ilya Shipitsin Date: Wed, 25 May 2022 18:03:37 +0500 Subject: [PATCH 033/254] optimize: fix potential null pointer dereference found by coverity (#2051) deref_ptr: Directly dereferencing pointer ctx. 1143 *ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); CID 258020 (#1 of 1): Dereference before null check (REVERSE_INULL)check_after_deref: Null-checking ctx suggests that it may be null, but it has already been dereferenced on all paths leading to the check. 1144 if (ctx == NULL) { 1145 return NGX_HTTP_LUA_FFI_NO_REQ_CTX; 1146 } --- src/ngx_http_lua_pipe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ngx_http_lua_pipe.c b/src/ngx_http_lua_pipe.c index 93dc7d5bc5..d0936c6d9e 100644 --- a/src/ngx_http_lua_pipe.c +++ b/src/ngx_http_lua_pipe.c @@ -1141,7 +1141,7 @@ ngx_http_lua_pipe_get_lua_ctx(ngx_http_request_t *r, int rc; *ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); - if (ctx == NULL) { + if (*ctx == NULL) { return NGX_HTTP_LUA_FFI_NO_REQ_CTX; } From b6db2e741dc77fa7c5f6da12ef7d7f9c26a930a5 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Wed, 25 May 2022 21:04:25 +0800 Subject: [PATCH 034/254] optimize: add error log when closing the pipe failed. (#2050) --- src/ngx_http_lua_pipe.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/ngx_http_lua_pipe.c b/src/ngx_http_lua_pipe.c index d0936c6d9e..1d9425b59f 100644 --- a/src/ngx_http_lua_pipe.c +++ b/src/ngx_http_lua_pipe.c @@ -773,10 +773,21 @@ ngx_http_lua_ffi_pipe_spawn(ngx_http_lua_ffi_pipe_proc_t *proc, } } - close(in[0]); - close(out[1]); + if (close(in[0]) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, + "lua pipe failed to close the in[0]"); + } + + if (close(out[1]) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, + "lua pipe failed to close the out[1]"); + } + if (!merge_stderr) { - close(err[1]); + if (close(err[1]) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, + "lua pipe failed to close the err[1]"); + } } if (environ != NULL) { From 0ac2ab27976d0834a7baf6c418ee4bed4dcac9e6 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Wed, 25 May 2022 21:09:00 +0800 Subject: [PATCH 035/254] bugfix: tctx.pool is double freed. (#2049) } else if (tctx.pool) { CID 251579 (#1 of 1): Use after free (USE_AFTER_FREE) 18. deref_arg: Calling ngx_destroy_pool dereferences freed pointer tctx.pool. 762 ngx_destroy_pool(tctx.pool); 763 } 764} --- src/ngx_http_lua_timer.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ngx_http_lua_timer.c b/src/ngx_http_lua_timer.c index 795bd4f5f3..e75b4ad65d 100644 --- a/src/ngx_http_lua_timer.c +++ b/src/ngx_http_lua_timer.c @@ -565,6 +565,8 @@ ngx_http_lua_timer_handler(ngx_event_t *ev) c = ngx_http_lua_create_fake_connection(tctx.pool); if (c == NULL) { errmsg = "could not create fake connection"; + /* tctx.pool is free in ngx_http_lua_create_fake_connection */ + tctx.pool = NULL; goto failed; } From e7660d75a3877faffcecef373ef66de214e6ad65 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Thu, 26 May 2022 09:03:07 +0800 Subject: [PATCH 036/254] doc: revised English grammar in ngx_http_lua_timer.c. (#2053) --- src/ngx_http_lua_timer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ngx_http_lua_timer.c b/src/ngx_http_lua_timer.c index e75b4ad65d..060cab543a 100644 --- a/src/ngx_http_lua_timer.c +++ b/src/ngx_http_lua_timer.c @@ -565,7 +565,7 @@ ngx_http_lua_timer_handler(ngx_event_t *ev) c = ngx_http_lua_create_fake_connection(tctx.pool); if (c == NULL) { errmsg = "could not create fake connection"; - /* tctx.pool is free in ngx_http_lua_create_fake_connection */ + /* tctx.pool is freed in ngx_http_lua_create_fake_connection */ tctx.pool = NULL; goto failed; } From 2c60e8966da3d72d591d2cb12980b18c5b0de3cd Mon Sep 17 00:00:00 2001 From: lijunlong Date: Mon, 30 May 2022 11:28:58 +0800 Subject: [PATCH 037/254] optimize: destroy pipe proc when freeing the request. (#2052) * optimize: destroy pipe proc when freeing the request. The connections are cached until gc collect. check the number of the free via the following cmd: gdb --batch -q -p 3049 -ex "print ngx_cycle->free_connection_n" 2>/dev/null; The nginx config to reproduce the problem location / { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc, err = ngx_pipe.spawn({"sh", "-c", "sleep 1; echo 100; sleep 5;"}) if not proc then ngx.say(err) return end proc:set_timeouts(nil, nil, nil, 2000) local data, err, partial = proc:stdout_read_line() proc:wait() ngx.say(data) } } --- src/ngx_http_lua_pipe.c | 30 +++++++++++++++++++++++++++++- src/ngx_http_lua_pipe.h | 2 ++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/ngx_http_lua_pipe.c b/src/ngx_http_lua_pipe.c index 1d9425b59f..c947d5599f 100644 --- a/src/ngx_http_lua_pipe.c +++ b/src/ngx_http_lua_pipe.c @@ -78,6 +78,8 @@ static void ngx_http_lua_pipe_proc_read_stdout_cleanup(void *data); static void ngx_http_lua_pipe_proc_read_stderr_cleanup(void *data); static void ngx_http_lua_pipe_proc_write_cleanup(void *data); static void ngx_http_lua_pipe_proc_wait_cleanup(void *data); +void ngx_http_lua_ffi_pipe_proc_destroy( + ngx_http_lua_ffi_pipe_proc_t *proc); static ngx_rbtree_t ngx_http_lua_pipe_rbtree; @@ -420,6 +422,9 @@ ngx_http_lua_pipe_sigchld_event_handler(ngx_event_t *ev) &ngx_posted_events); } + /* TODO: we should proactively close and free up the pipe after + * the user consume all the data in the pipe. + */ pipe_node->proc->pipe->dead = 1; if (WIFSIGNALED(status)) { @@ -562,7 +567,8 @@ ngx_http_lua_execvpe(const char *program, char * const argv[], int -ngx_http_lua_ffi_pipe_spawn(ngx_http_lua_ffi_pipe_proc_t *proc, +ngx_http_lua_ffi_pipe_spawn(ngx_http_request_t *r, + ngx_http_lua_ffi_pipe_proc_t *proc, const char *file, const char **argv, int merge_stderr, size_t buffer_size, const char **environ, u_char *errbuf, size_t *errbuf_size) { @@ -582,6 +588,7 @@ ngx_http_lua_ffi_pipe_spawn(ngx_http_lua_ffi_pipe_proc_t *proc, ngx_http_lua_pipe_node_t *pipe_node; struct sigaction sa; ngx_http_lua_pipe_signal_t *sig; + ngx_http_cleanup_t *cln; sigset_t set; pool_size = ngx_align(NGX_MIN_POOL_SIZE + buffer_size * 2, @@ -869,6 +876,21 @@ ngx_http_lua_ffi_pipe_spawn(ngx_http_lua_ffi_pipe_proc_t *proc, pp->stderr_fd = stderr_fd; } + if (pp->cleanup == NULL) { + cln = ngx_http_lua_cleanup_add(r, 0); + + if (cln == NULL) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "no memory") + - errbuf; + goto close_in_out_err_fd; + } + + cln->handler = (ngx_http_cleanup_pt) ngx_http_lua_ffi_pipe_proc_destroy; + cln->data = proc; + pp->cleanup = &cln->handler; + pp->r = r; + } + node = (ngx_rbtree_node_t *) (pp + 1); node->key = pid; pipe_node = (ngx_http_lua_pipe_node_t *) &node->color; @@ -1139,6 +1161,12 @@ ngx_http_lua_ffi_pipe_proc_destroy(ngx_http_lua_ffi_pipe_proc_t *proc) } } + if (pipe->cleanup != NULL) { + *pipe->cleanup = NULL; + ngx_http_lua_cleanup_free(pipe->r, pipe->cleanup); + pipe->cleanup = NULL; + } + ngx_http_lua_pipe_proc_finalize(proc); ngx_destroy_pool(pipe->pool); proc->pipe = NULL; diff --git a/src/ngx_http_lua_pipe.h b/src/ngx_http_lua_pipe.h index ecb86c8806..f1c9283526 100644 --- a/src/ngx_http_lua_pipe.h +++ b/src/ngx_http_lua_pipe.h @@ -57,6 +57,8 @@ struct ngx_http_lua_pipe_s { ngx_http_lua_pipe_ctx_t *stdout_ctx; ngx_http_lua_pipe_ctx_t *stderr_ctx; ngx_http_lua_pipe_retval_handler retval_handler; + ngx_http_cleanup_pt *cleanup; + ngx_http_request_t *r; size_t buffer_size; unsigned closed:1; unsigned dead:1; From 3fe8d9ddeb144b121e26cc2251b925e4f673f554 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Tue, 14 Jun 2022 18:15:12 +0800 Subject: [PATCH 038/254] change: can not receive udp datagram greater 8192. (#2057) --- src/ngx_http_lua_socket_udp.c | 2 +- t/087-udp-socket.t | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ngx_http_lua_socket_udp.c b/src/ngx_http_lua_socket_udp.c index 4f970e6cca..cbb6621b47 100644 --- a/src/ngx_http_lua_socket_udp.c +++ b/src/ngx_http_lua_socket_udp.c @@ -24,7 +24,7 @@ #endif -#define UDP_MAX_DATAGRAM_SIZE 8192 +#define UDP_MAX_DATAGRAM_SIZE 65536 static int ngx_http_lua_socket_udp(lua_State *L); diff --git a/t/087-udp-socket.t b/t/087-udp-socket.t index 80c5e36517..6c26b93876 100644 --- a/t/087-udp-socket.t +++ b/t/087-udp-socket.t @@ -69,7 +69,7 @@ GET /t [error] --- log_level: debug --- error_log -lua udp socket receive buffer size: 8192 +lua udp socket receive buffer size: 65536 @@ -595,7 +595,7 @@ received a good response. [error] --- log_level: debug --- error_log -lua udp socket receive buffer size: 8192 +lua udp socket receive buffer size: 65536 --- no_check_leak @@ -662,7 +662,7 @@ received a good response. [error] --- log_level: debug --- error_log -lua udp socket receive buffer size: 8192 +lua udp socket receive buffer size: 65536 --- no_check_leak From 9a0a8968cded113ecd31913c4e0aefc195578ac0 Mon Sep 17 00:00:00 2001 From: kingluo Date: Sat, 18 Jun 2022 22:50:55 +0800 Subject: [PATCH 039/254] bugfix: did not wakeup coroutine when worker thread finished. --- README.markdown | 41 +++--------------- doc/HttpLuaModule.wiki | 33 +++------------ src/ngx_http_lua_common.h | 4 ++ src/ngx_http_lua_worker_thread.c | 73 ++++++++++++++++++++++---------- t/166-worker-thread.t | 38 +++++++++++++++++ 5 files changed, 105 insertions(+), 84 deletions(-) diff --git a/README.markdown b/README.markdown index ab92fa06ca..17563b5757 100644 --- a/README.markdown +++ b/README.markdown @@ -1,8 +1,3 @@ - - Name ==== @@ -9329,42 +9324,18 @@ Example1: do md5 calculation. default_type 'text/plain'; content_by_lua_block { - local ok, ret, md5_or_err = ngx.run_worker_thread("testpool", "calc_md5", "md5", ngx.var.arg_str) - if not ok then - ngx.say(ret) - return - end - if not ret then - ngx.say(md5_or_err) - return - end - ngx.say(md5_or_err) + local ok, md5_or_err = ngx.run_worker_thread("testpool", "md5", "md5") + ngx.say(ok, " : ", md5_or_err) } } ``` -`calc_md5.lua` +`md5.lua` ```lua - - local resty_md5 = require "resty.md5" - local resty_str = require "resty.string" - - local function md5(str) - local md5 = resty_md5:new() - if not md5 then - return false, "md5 new error" - end - - local ok = md5:update(str) - if not ok then - return false, "md5 update error" - end - - local digest = md5:final() - return true, resty_str.to_hex(digest) - end - return {md5=md5} +local function md5() + return ngx.md5("hello") +end ``` Example2: write logs into the log file. diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 6185b6d653..371b9cb84f 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -8005,39 +8005,18 @@ location /calc_md5 { default_type 'text/plain'; content_by_lua_block { - local ok, ret, md5_or_err = ngx.run_worker_thread("testpool", "calc_md5", "md5", ngx.var.arg_str) - if not ok then - ngx.say(ret) - return - end - if not ret then - ngx.say(md5_or_err) - return - end - ngx.say(md5_or_err) + local ok, md5_or_err = ngx.run_worker_thread("testpool", "md5", "md5") + ngx.say(ok, " : ", md5_or_err) } } + -calc_md5.lua +md5.lua -local resty_md5 = require "resty.md5" -local resty_str = require "resty.string" - -local function md5(str) - local md5 = resty_md5:new() - if not md5 then - return false, "md5 new error" - end - - local ok = md5:update(str) - if not ok then - return false, "md5 update error" - end - - local digest = md5:final() - return true, resty_str.to_hex(digest) +local function md5() + return ngx.md5("hello") end return {md5=md5} diff --git a/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h index 31b39fc709..dafa729f8e 100644 --- a/src/ngx_http_lua_common.h +++ b/src/ngx_http_lua_common.h @@ -494,6 +494,10 @@ struct ngx_http_lua_co_ctx_s { uint8_t *sr_flags; + unsigned nresults_from_worker_thread; /* number of results + * from worker + * thread callback */ + unsigned nsubreqs; /* number of subrequests of the * current request */ diff --git a/src/ngx_http_lua_worker_thread.c b/src/ngx_http_lua_worker_thread.c index 69c6da1d01..d3e9cbfd30 100644 --- a/src/ngx_http_lua_worker_thread.c +++ b/src/ngx_http_lua_worker_thread.c @@ -288,6 +288,50 @@ ngx_http_lua_worker_thread_handler(void *data, ngx_log_t *log) } +static ngx_int_t +ngx_http_lua_worker_thread_resume(ngx_http_request_t *r) +{ + lua_State *vm; + ngx_connection_t *c; + ngx_int_t rc; + ngx_uint_t nreqs; + ngx_http_lua_ctx_t *ctx; + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx == NULL) { + return NGX_ERROR; + } + + ctx->resume_handler = ngx_http_lua_wev_handler; + + c = r->connection; + vm = ngx_http_lua_get_lua_vm(r, ctx); + nreqs = c->requests; + + rc = ngx_http_lua_run_thread(vm, r, ctx, + ctx->cur_co_ctx->nresults_from_worker_thread); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua run thread returned %d", rc); + + if (rc == NGX_AGAIN) { + return ngx_http_lua_run_posted_threads(c, vm, r, ctx, nreqs); + } + + if (rc == NGX_DONE) { + ngx_http_lua_finalize_request(r, NGX_DONE); + return ngx_http_lua_run_posted_threads(c, vm, r, ctx, nreqs); + } + + if (ctx->entered_content_phase) { + ngx_http_lua_finalize_request(r, rc); + return NGX_DONE; + } + + return rc; +} + + /* executed in nginx event loop */ static void ngx_http_lua_worker_thread_event_handler(ngx_event_t *ev) @@ -300,7 +344,6 @@ ngx_http_lua_worker_thread_event_handler(ngx_event_t *ev) size_t len; const char *str; int i; - int rc; ngx_http_lua_ctx_t *ctx; lua_State *vm; int saved_top; @@ -350,6 +393,7 @@ ngx_http_lua_worker_thread_event_handler(ngx_event_t *ev) } ctx->cur_co_ctx = worker_thread_ctx->wait_co_ctx; + ctx->cur_co_ctx->nresults_from_worker_thread = nresults; ctx->cur_co_ctx->cleanup = NULL; ngx_http_lua_free_task_ctx(worker_thread_ctx->ctx); @@ -357,30 +401,15 @@ ngx_http_lua_worker_thread_event_handler(ngx_event_t *ev) /* resume the caller coroutine */ - vm = ngx_http_lua_get_lua_vm(r, ctx); - - rc = ngx_http_lua_run_thread(vm, r, ctx, nresults); - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua run thread returned %d", rc); - - if (rc == NGX_AGAIN) { - ngx_http_lua_run_posted_threads(c, vm, r, ctx, c->requests); - return; - } + if (ctx->entered_content_phase) { + (void) ngx_http_lua_worker_thread_resume(r); - if (rc == NGX_DONE) { - ngx_http_lua_finalize_request(r, NGX_DONE); - ngx_http_lua_run_posted_threads(c, vm, r, ctx, c->requests); - return; + } else { + ctx->resume_handler = ngx_http_lua_worker_thread_resume; + ngx_http_core_run_phases(r); } - /* rc == NGX_ERROR || rc >= NGX_OK */ - - if (ctx->entered_content_phase) { - ngx_http_lua_finalize_request(r, rc); - return; - } + ngx_http_run_posted_requests(c); return; diff --git a/t/166-worker-thread.t b/t/166-worker-thread.t index 8b874c55ad..3288f3a15b 100644 --- a/t/166-worker-thread.t +++ b/t/166-worker-thread.t @@ -1208,3 +1208,41 @@ return {hello=hello} GET /hello --- response_body_like chop ^true : \d+$ + + + +=== TEST 39: write_log_file +--- main_config + thread_pool testpool threads=100; +--- http_config eval + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" +--- config +location /write_log_file { + default_type 'text/plain'; + + content_by_lua_block { + local ok, err = ngx.run_worker_thread("testpool", "write_log_file", "log", ngx.var.arg_str) + if not ok then + ngx.say(ok, " : ", err) + return + end + ngx.say(ok) + } +} +--- user_files +>>> write_log_file.lua +local function log(str) + local file, err = io.open("/tmp/tmp.log", "w") + if not file then + return false, err + end + file:write(str) + file:flush() + file:close() + return true +end +return {log=log} +--- request +GET /write_log_file?str=hello +--- response_body +true From c8597eda0c3181f15ff58dedf3fb41f4259146fb Mon Sep 17 00:00:00 2001 From: lijunlong Date: Thu, 23 Jun 2022 19:55:30 +0800 Subject: [PATCH 040/254] tests: change the running phase to cover the bug reported in google group. (#2064) bug: https://groups.google.com/g/openresty/c/qkS_9whMvXc --- t/166-worker-thread.t | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/166-worker-thread.t b/t/166-worker-thread.t index 3288f3a15b..2762acde54 100644 --- a/t/166-worker-thread.t +++ b/t/166-worker-thread.t @@ -1220,7 +1220,7 @@ GET /hello location /write_log_file { default_type 'text/plain'; - content_by_lua_block { + access_by_lua_block { local ok, err = ngx.run_worker_thread("testpool", "write_log_file", "log", ngx.var.arg_str) if not ok then ngx.say(ok, " : ", err) From b6d167cf1a93c0c885c28db5a439f2404874cb26 Mon Sep 17 00:00:00 2001 From: Hiroaki Nakamura Date: Tue, 28 Jun 2022 14:37:24 +0900 Subject: [PATCH 041/254] bugfix: update handling of multiple headers changed in nginx 1.23.0 (#2063) --- src/ngx_http_lua_headers_in.c | 46 ++++++++++++++++++++++++ src/ngx_http_lua_headers_out.c | 64 ++++++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+) diff --git a/src/ngx_http_lua_headers_in.c b/src/ngx_http_lua_headers_in.c index a55d9cac7e..4405481408 100644 --- a/src/ngx_http_lua_headers_in.c +++ b/src/ngx_http_lua_headers_in.c @@ -152,9 +152,15 @@ static ngx_http_lua_set_header_t ngx_http_lua_set_handlers[] = { ngx_http_set_builtin_header }, #endif +#if defined(nginx_version) && nginx_version >= 1023000 + { ngx_string("Cookie"), + offsetof(ngx_http_headers_in_t, cookie), + ngx_http_set_builtin_multi_header }, +#else { ngx_string("Cookie"), offsetof(ngx_http_headers_in_t, cookies), ngx_http_set_builtin_multi_header }, +#endif { ngx_null_string, 0, ngx_http_set_header } }; @@ -580,6 +586,45 @@ static ngx_int_t ngx_http_set_builtin_multi_header(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, ngx_str_t *value) { +#if defined(nginx_version) && nginx_version >= 1023000 + ngx_table_elt_t **headers, **ph, *h; + int nelts; + + headers = (ngx_table_elt_t **) ((char *) &r->headers_in + hv->offset); + + if (!hv->no_override && *headers != NULL) { + nelts = 0; + for (h = *headers; h; h = h->next) { + nelts++; + } + + *headers = NULL; + + dd("clear multi-value headers: %d", nelts); + } + + if (ngx_http_set_header_helper(r, hv, value, &h) == NGX_ERROR) { + return NGX_ERROR; + } + + if (value->len == 0) { + return NGX_OK; + } + + dd("new multi-value header: %p", h); + + if (*headers) { + for (ph = headers; *ph; ph = &(*ph)->next) { /* void */ } + *ph = h; + + } else { + *headers = h; + } + + h->next = NULL; + + return NGX_OK; +#else ngx_array_t *headers; ngx_table_elt_t **v, *h; @@ -626,6 +671,7 @@ ngx_http_set_builtin_multi_header(ngx_http_request_t *r, *v = h; return NGX_OK; +#endif } diff --git a/src/ngx_http_lua_headers_out.c b/src/ngx_http_lua_headers_out.c index 6e9f9c19ac..571723d9a6 100644 --- a/src/ngx_http_lua_headers_out.c +++ b/src/ngx_http_lua_headers_out.c @@ -311,6 +311,69 @@ static ngx_int_t ngx_http_set_builtin_multi_header(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, ngx_str_t *value) { +#if defined(nginx_version) && nginx_version >= 1023000 + ngx_table_elt_t **headers, *h, *ho, **ph; + + headers = (ngx_table_elt_t **) ((char *) &r->headers_out + hv->offset); + + if (hv->no_override) { + for (h = *headers; h; h = h->next) { + if (!h->hash) { + h->value = *value; + h->hash = hv->hash; + return NGX_OK; + } + } + + goto create; + } + + /* override old values (if any) */ + + if (*headers) { + for (h = (*headers)->next; h; h = h->next) { + h->hash = 0; + h->value.len = 0; + } + + h = *headers; + + h->value = *value; + + if (value->len == 0) { + h->hash = 0; + + } else { + h->hash = hv->hash; + } + + return NGX_OK; + } + +create: + + for (ph = headers; *ph; ph = &(*ph)->next) { /* void */ } + + ho = ngx_list_push(&r->headers_out.headers); + if (ho == NULL) { + return NGX_ERROR; + } + + ho->value = *value; + + if (value->len == 0) { + ho->hash = 0; + + } else { + ho->hash = hv->hash; + } + + ho->key = hv->key; + ho->next = NULL; + *ph = ho; + + return NGX_OK; +#else ngx_array_t *pa; ngx_table_elt_t *ho, **ph; ngx_uint_t i; @@ -384,6 +447,7 @@ ngx_http_set_builtin_multi_header(ngx_http_request_t *r, *ph = ho; return NGX_OK; +#endif } From c55fceb5cf9dbafa179b6925a13bb6f47787b0ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BD=97=E6=B3=BD=E8=BD=A9?= Date: Fri, 1 Jul 2022 10:02:31 +0800 Subject: [PATCH 042/254] ci: add a way to check PR title automatically (#2067) Signed-off-by: spacewander --- .github/workflows/semantic-pull-request.yml | 32 +++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 .github/workflows/semantic-pull-request.yml diff --git a/.github/workflows/semantic-pull-request.yml b/.github/workflows/semantic-pull-request.yml new file mode 100644 index 0000000000..2112f9e790 --- /dev/null +++ b/.github/workflows/semantic-pull-request.yml @@ -0,0 +1,32 @@ +name: "Lint PR" + +on: + pull_request_target: + types: + - opened + - edited + - synchronize + +jobs: + main: + name: Validate PR title + runs-on: ubuntu-latest + steps: + - uses: amannn/action-semantic-pull-request@v4 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + # Configure which types are allowed. + # Default: https://github.com/commitizen/conventional-commit-types + types: | + change + chore + ci + doc + feature + fix + optimize + refactor + revert + style + test From 74b8d4b4f969508a47cd0ef9e510eec367f1e9c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BD=97=E6=B3=BD=E8=BD=A9?= Date: Fri, 1 Jul 2022 13:10:50 +0800 Subject: [PATCH 043/254] chore: update the PR types (#2069) Signed-off-by: spacewander --- .github/workflows/semantic-pull-request.yml | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/.github/workflows/semantic-pull-request.yml b/.github/workflows/semantic-pull-request.yml index 2112f9e790..12b87cb3c1 100644 --- a/.github/workflows/semantic-pull-request.yml +++ b/.github/workflows/semantic-pull-request.yml @@ -19,14 +19,12 @@ jobs: # Configure which types are allowed. # Default: https://github.com/commitizen/conventional-commit-types types: | - change - chore - ci - doc - feature - fix - optimize - refactor - revert - style - test + bugfix # bug fixes + change # backward incompatible changes + doc # documentation changes including code comments + editor # code editor related configurations + feature # implementing a new feature + optimize # performance optimizations + refactor # code refactoring and other code rearrangement + style # coding style changes + tests # test suite changes From 1c43f1c4f2018a0f999fbf45afc8daf0352b104a Mon Sep 17 00:00:00 2001 From: Johnny Wang Date: Fri, 1 Jul 2022 13:11:15 +0800 Subject: [PATCH 044/254] ci: bumped OpenSSL to 1.1.1p. (#2070) --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 56ff18e272..67263fa449 100644 --- a/.travis.yml +++ b/.travis.yml @@ -52,7 +52,7 @@ env: - TEST_NGINX_SLEEP=0.006 jobs: - NGINX_VERSION=1.21.4 OPENSSL_VER=1.1.0l OPENSSL_PATCH_VER=1.1.0d - - NGINX_VERSION=1.21.4 OPENSSL_VER=1.1.1n OPENSSL_PATCH_VER=1.1.1f + - NGINX_VERSION=1.21.4 OPENSSL_VER=1.1.1p OPENSSL_PATCH_VER=1.1.1f services: - memcached From 1fd1e83c80612998647ee7ea933d3fdb2e9d9d9b Mon Sep 17 00:00:00 2001 From: lijunlong Date: Sun, 3 Jul 2022 20:24:34 +0800 Subject: [PATCH 045/254] bugfix: doesn't set flags for Darwin arm64. (#2071) --- config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config b/config index 0e572c8bea..c4068c852b 100644 --- a/config +++ b/config @@ -94,7 +94,7 @@ END case "$NGX_PLATFORM" in Darwin:*) case "$NGX_MACHINE" in - amd64 | x86_64 | i386) + amd64 | arm64 | x86_64 | i386) echo "adding extra linking options needed by LuaJIT on $NGX_MACHINE" luajit_ld_opt="$luajit_ld_opt -pagezero_size 10000 -image_base 100000000" ngx_feature_libs="$ngx_feature_libs -pagezero_size 10000 -image_base 100000000" From 99b29cd169c01274c127f812482b956abcad2d6e Mon Sep 17 00:00:00 2001 From: lijunlong Date: Sun, 10 Jul 2022 20:26:25 +0800 Subject: [PATCH 046/254] doc: clarify the ngx.req.set_uri_args api when using Lua table as the 'arg' argument. (#2073) --- README.markdown | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index 17563b5757..ed8bb658b1 100644 --- a/README.markdown +++ b/README.markdown @@ -4982,7 +4982,9 @@ Multi-value arguments are also supported: ngx.req.set_uri_args({ a = 3, b = {5, 6} }) ``` -which will result in a query string like `a=3&b=5&b=6`. +which will result in a query string like `a=3&b=5&b=6` or `b=5&b=6&a=3`. + +**Note that when using Lua table as the `arg` argument, the order of the arguments in the result query string which change from time to time. If you would like to get an ordered result, you need to use Lua string as the `arg` argument.** This interface was first introduced in the `v0.3.1rc13` release. From 44486a45f4de09122811a07c697a69513a60b24e Mon Sep 17 00:00:00 2001 From: jinhua luo Date: Tue, 12 Jul 2022 10:59:15 +0800 Subject: [PATCH 047/254] feature: add shdict APIs into worker thread (#2074) --- README.markdown | 1 + src/ngx_http_lua_worker_thread.c | 10 + t/166-worker-thread.t | 449 +++++++++++++++++++++++++++++++ 3 files changed, 460 insertions(+) diff --git a/README.markdown b/README.markdown index ed8bb658b1..14ad18c1eb 100644 --- a/README.markdown +++ b/README.markdown @@ -9287,6 +9287,7 @@ Only the following ngx_lua APIs could be used in `function_name` function of the * `ngx.config.nginx_configure` * `ngx.config.ngx_lua_version` +* `ngx.shared.DICT` The first argument `threadpool` specifies the Nginx thread pool name defined by [thread_pool](https://nginx.org/en/docs/ngx_core_module.html#thread_pool). diff --git a/src/ngx_http_lua_worker_thread.c b/src/ngx_http_lua_worker_thread.c index d3e9cbfd30..1512be4daf 100644 --- a/src/ngx_http_lua_worker_thread.c +++ b/src/ngx_http_lua_worker_thread.c @@ -16,6 +16,7 @@ #include "ngx_http_lua_util.h" #include "ngx_http_lua_string.h" #include "ngx_http_lua_config.h" +#include "ngx_http_lua_shdict.h" #if (NGX_THREADS) @@ -148,6 +149,7 @@ ngx_http_lua_get_task_ctx(lua_State *L, ngx_http_request_t *r) lua_newtable(vm); /* ngx.* */ ngx_http_lua_inject_string_api(vm); ngx_http_lua_inject_config_api(vm); + ngx_http_lua_inject_shdict_api(lmcf, vm); lua_setglobal(vm, "ngx"); /* inject API via ffi */ @@ -175,6 +177,14 @@ ngx_http_lua_get_task_ctx(lua_State *L, ngx_http_request_t *r) return NULL; } + lua_getglobal(vm, "require"); + lua_pushstring(vm, "resty.core.shdict"); + if (lua_pcall(vm, 1, 0, 0) != 0) { + lua_close(vm); + ngx_free(ctx); + return NULL; + } + } else { ctx = ctxpool->next; ctxpool->next = ctx->next; diff --git a/t/166-worker-thread.t b/t/166-worker-thread.t index 2762acde54..2b7258df7c 100644 --- a/t/166-worker-thread.t +++ b/t/166-worker-thread.t @@ -1246,3 +1246,452 @@ return {log=log} GET /write_log_file?str=hello --- response_body true + + + +=== TEST 40: shdict get, int value +--- main_config + thread_pool testpool threads=100; +--- http_config eval +" + lua_shared_dict dogs 10m; + lua_package_path '$::HtmlDir/?.lua;./?.lua;;'; +" +--- config +location /dictget { + default_type 'text/plain'; + + access_by_lua_block { + local dogs = ngx.shared.dogs + dogs:set("Jim", 8) + local ok, err = ngx.run_worker_thread("testpool", "test_shdict", "dictget") + ngx.say(ok, ",", err) + } +} +--- user_files +>>> test_shdict.lua +local function dictget(str) + local dogs = ngx.shared.dogs + return dogs:get("Jim") +end +return {dictget=dictget} +--- request +GET /dictget +--- response_body +true,8 + + + +=== TEST 41: shdict set nil in main thread +--- main_config + thread_pool testpool threads=100; +--- http_config eval +" + lua_shared_dict dogs 10m; + lua_package_path '$::HtmlDir/?.lua;./?.lua;;'; +" +--- config +location /dictget { + default_type 'text/plain'; + + access_by_lua_block { + local dogs = ngx.shared.dogs + dogs:set("Jim", 8) + local ok, err = ngx.run_worker_thread("testpool", "test_shdict", "dictget") + ngx.say(ok, ",", err) + dogs:set("Jim", nil) + local ok, err = ngx.run_worker_thread("testpool", "test_shdict", "dictget") + ngx.say(ok, ",", err) + } +} +--- user_files +>>> test_shdict.lua +local function dictget(str) + local dogs = ngx.shared.dogs + return dogs:get("Jim") +end +return {dictget=dictget} +--- request +GET /dictget +--- response_body +true,8 +true,nil + + + +=== TEST 42: shdict set nil in worker thread +--- main_config + thread_pool testpool threads=100; +--- http_config eval +" + lua_shared_dict dogs 10m; + lua_package_path '$::HtmlDir/?.lua;./?.lua;;'; +" +--- config +location /dictsetnil { + default_type 'text/plain'; + + access_by_lua_block { + local dogs = ngx.shared.dogs + dogs:set("Jim", 8) + local ok, err = ngx.run_worker_thread("testpool", "test_shdict", "dictsetnil") + ngx.say(ok, ",", err) + ngx.say(ok, ",", dogs:get("Jim")) + } +} +--- user_files +>>> test_shdict.lua +local function dictsetnil(str) + local dogs = ngx.shared.dogs + return dogs:set("Jim", nil) +end +return {dictsetnil=dictsetnil} +--- request +GET /dictsetnil +--- response_body +true,true +true,nil + + + +=== TEST 43: shdict get_stale +--- main_config + thread_pool testpool threads=100; +--- http_config eval +" + lua_shared_dict dogs 10m; + lua_package_path '$::HtmlDir/?.lua;./?.lua;;'; +" +--- config +location /dictget { + default_type 'text/plain'; + + access_by_lua_block { + local dogs = ngx.shared.dogs + dogs:set("Jim", 8, 1) + ngx.sleep(2) + local ok, err = ngx.run_worker_thread("testpool", "test_shdict", "dictget") + ngx.say(ok, ",", err) + } +} +--- user_files +>>> test_shdict.lua +local function dictget(str) + local dogs = ngx.shared.dogs + return dogs:get_stale("Jim") +end +return {dictget=dictget} +--- request +GET /dictget +--- response_body +true,8 + + + +=== TEST 44: shdict add failed +--- main_config + thread_pool testpool threads=100; +--- http_config eval +" + lua_shared_dict dogs 10m; + lua_package_path '$::HtmlDir/?.lua;./?.lua;;'; +" +--- config +location /dictadd { + default_type 'text/plain'; + + access_by_lua_block { + local dogs = ngx.shared.dogs + dogs:set("Jim", 8) + local ok, err, err2 = ngx.run_worker_thread("testpool", "test_shdict", "dictadd") + ngx.say(ok, ",", err, ",", err2) + } +} +--- user_files +>>> test_shdict.lua +local function dictadd(str) + local dogs = ngx.shared.dogs + local success, err = dogs:add("Jim", "hello") + return success, err +end +return {dictadd=dictadd} +--- request +GET /dictadd +--- response_body +true,false,exists + + + +=== TEST 45: shdict force add +--- main_config + thread_pool testpool threads=100; +--- http_config eval +" + lua_shared_dict dogs 6m; + lua_package_path '$::HtmlDir/?.lua;./?.lua;;'; +" +--- config +location /dictadd { + default_type 'text/plain'; + + access_by_lua_block { + local dogs = ngx.shared.dogs + local bigstr = string.rep("A", 1024*1024*3) + dogs:set("Jim", bigstr) + local ok, ret, err, forcible = ngx.run_worker_thread("testpool", "test_shdict", "dictadd") + ngx.say(ok, ",", ret, ",", forcible, ",", dogs:get("Jim")) + } +} +--- user_files +>>> test_shdict.lua +local function dictadd(str) + local dogs = ngx.shared.dogs + local bigstr = string.rep("A", 1024*1024*5) + local success, err, forcible = dogs:add("King", bigstr) + return success, err, forcible +end +return {dictadd=dictadd} +--- request +GET /dictadd +--- response_body +true,true,true,nil + + + +=== TEST 46: shdict replace +--- main_config + thread_pool testpool threads=100; +--- http_config eval +" + lua_shared_dict dogs 6m; + lua_package_path '$::HtmlDir/?.lua;./?.lua;;'; +" +--- config +location /dictreplace { + default_type 'text/plain'; + + access_by_lua_block { + local dogs = ngx.shared.dogs + local bigstr = string.rep("A", 1024*1024*3) + dogs:set("Jim", bigstr) + local ok, ret, err = ngx.run_worker_thread("testpool", "test_shdict", "dictreplace") + ngx.say(ok, ",", ret, ",", err, ",", dogs:get("Jim")) + } +} +--- user_files +>>> test_shdict.lua +local function dictreplace(str) + local dogs = ngx.shared.dogs + local success, err = dogs:replace("Jim", 8) + return success, err +end +return {dictreplace=dictreplace} +--- request +GET /dictreplace +--- response_body +true,true,nil,8 + + + +=== TEST 47: shdict replace not found +--- main_config + thread_pool testpool threads=100; +--- http_config eval +" + lua_shared_dict dogs 6m; + lua_package_path '$::HtmlDir/?.lua;./?.lua;;'; +" +--- config +location /dictreplace { + default_type 'text/plain'; + + access_by_lua_block { + local dogs = ngx.shared.dogs + local ok, ret, err = ngx.run_worker_thread("testpool", "test_shdict", "dictreplace") + ngx.say(ok, ",", ret, ",", err) + } +} +--- user_files +>>> test_shdict.lua +local function dictreplace(str) + local dogs = ngx.shared.dogs + local success, err = dogs:replace("Jim", 8) + return success, err +end +return {dictreplace=dictreplace} +--- request +GET /dictreplace +--- response_body +true,false,not found + + + +=== TEST 48: shdict incr +--- main_config + thread_pool testpool threads=100; +--- http_config eval +" + lua_shared_dict dogs 6m; + lua_package_path '$::HtmlDir/?.lua;./?.lua;;'; +" +--- config +location /dictincr { + default_type 'text/plain'; + + access_by_lua_block { + local dogs = ngx.shared.dogs + local success, err = dogs:set("Jim", 8) + local ok, ret, err = ngx.run_worker_thread("testpool", "test_shdict", "dictincr") + ngx.say(ok, ",", ret, ",", err, ",", dogs:get("Jim")) + } +} +--- user_files +>>> test_shdict.lua +local function dictincr(str) + local dogs = ngx.shared.dogs + local success, err = dogs:incr("Jim", 1) + return success, err +end +return {dictincr=dictincr} +--- request +GET /dictincr +--- response_body +true,9,nil,9 + + + +=== TEST 49: shdict lpush lpop +--- main_config + thread_pool testpool threads=100; +--- http_config eval +" + lua_shared_dict dogs 6m; + lua_package_path '$::HtmlDir/?.lua;./?.lua;;'; +" +--- config +location /dictlpush { + default_type 'text/plain'; + + access_by_lua_block { + local dogs = ngx.shared.dogs + dogs:lpush("Jim", 8) + dogs:lpush("Jim", 9) + local ok, val, len, err = ngx.run_worker_thread("testpool", "test_shdict", "dictlpush") + ngx.say(ok, ",", val, ",", len, ",", err, ",", dogs:lpop("Jim")) + } +} +--- user_files +>>> test_shdict.lua +local function dictlpush(str) + local dogs = ngx.shared.dogs + local val = dogs:lpop("Jim") + local len, err = dogs:lpush("Jim", 7) + return val, len, err +end +return {dictlpush=dictlpush} +--- request +GET /dictlpush +--- response_body +true,9,2,nil,7 + + + +=== TEST 50: shdict expire ttl +--- main_config + thread_pool testpool threads=100; +--- http_config eval +" + lua_shared_dict dogs 6m; + lua_package_path '$::HtmlDir/?.lua;./?.lua;;'; +" +--- config +location /dictexpire { + default_type 'text/plain'; + + access_by_lua_block { + local dogs = ngx.shared.dogs + dogs:set("Jim", 8) + local ok, success, err = ngx.run_worker_thread("testpool", "test_shdict", "dictexpire") + ngx.say(ok, ",", success, ",", err, ",", dogs:ttl("Jim") <= 1) + } +} +--- user_files +>>> test_shdict.lua +local function dictexpire(str) + local dogs = ngx.shared.dogs + local success, err = dogs:expire("Jim", 1) + return success, err +end +return {dictexpire=dictexpire} +--- request +GET /dictexpire +--- response_body +true,true,nil,true + + + +=== TEST 51: shdict flush_all +--- main_config + thread_pool testpool threads=100; +--- http_config eval +" + lua_shared_dict dogs 6m; + lua_package_path '$::HtmlDir/?.lua;./?.lua;;'; +" +--- config +location /dictexpire { + default_type 'text/plain'; + + access_by_lua_block { + local dogs = ngx.shared.dogs + dogs:set("Jim", 8) + dogs:set("King", 9) + local ok = ngx.run_worker_thread("testpool", "test_shdict", "dictexpire") + ngx.say(ok, ",", dogs:get("Jim"), ",", dogs:get("King")) + } +} +--- user_files +>>> test_shdict.lua +local function dictexpire(str) + local dogs = ngx.shared.dogs + dogs:flush_all() +end +return {dictexpire=dictexpire} +--- request +GET /dictexpire +--- response_body +true,nil,nil + + + +=== TEST 52: shdict get_keys +--- main_config + thread_pool testpool threads=100; +--- http_config eval +" + lua_shared_dict dogs 6m; + lua_package_path '$::HtmlDir/?.lua;./?.lua;;'; +" +--- config +location /dictgetkeys { + default_type 'text/plain'; + + access_by_lua_block { + local dogs = ngx.shared.dogs + dogs:set("Jim", 8) + dogs:set("King", 9) + local ok, keys = ngx.run_worker_thread("testpool", "test_shdict", "dictgetkeys") + ngx.say(ok, ",", table.concat(keys, ":")) + } +} +--- user_files +>>> test_shdict.lua +local function dictgetkeys(str) + local dogs = ngx.shared.dogs + return dogs:get_keys() +end +return {dictgetkeys=dictgetkeys} +--- request +GET /dictgetkeys +--- response_body +true,Jim:King From 9b7bde2e7986d2150606e33e303c6bd1c40271a6 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Wed, 13 Jul 2022 09:31:58 +0800 Subject: [PATCH 048/254] feature: added new API bind. Co-authored-by: doujiang24 Co-authored-by: lijunlong --- .travis.yml | 2 +- README.markdown | 38 ++++ doc/HttpLuaModule.wiki | 33 ++++ src/ngx_http_lua_socket_tcp.c | 71 ++++++- src/ngx_http_lua_util.c | 73 +++++++ src/ngx_http_lua_util.h | 2 + t/062-count.t | 2 +- t/168-tcp-socket-bind.t | 361 ++++++++++++++++++++++++++++++++++ 8 files changed, 579 insertions(+), 3 deletions(-) create mode 100644 t/168-tcp-socket-bind.t diff --git a/.travis.yml b/.travis.yml index 67263fa449..214420015e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -141,4 +141,4 @@ script: - dig +short myip.opendns.com @resolver1.opendns.com || exit 0 - dig +short @$TEST_NGINX_RESOLVER openresty.org || exit 0 - dig +short @$TEST_NGINX_RESOLVER agentzh.org || exit 0 - - prove -I. -Itest-nginx/lib -r t + - prove -I. -Itest-nginx/lib -r t/ diff --git a/README.markdown b/README.markdown index 14ad18c1eb..6466a1edff 100644 --- a/README.markdown +++ b/README.markdown @@ -3682,6 +3682,7 @@ Nginx API for Lua * [udpsock:settimeout](#udpsocksettimeout) * [ngx.socket.stream](#ngxsocketstream) * [ngx.socket.tcp](#ngxsockettcp) +* [tcpsock:bind](#tcpsockbind) * [tcpsock:connect](#tcpsockconnect) * [tcpsock:setclientcert](#tcpsocksetclientcert) * [tcpsock:sslhandshake](#tcpsocksslhandshake) @@ -7656,6 +7657,7 @@ ngx.socket.tcp Creates and returns a TCP or stream-oriented unix domain socket object (also known as one type of the "cosocket" objects). The following methods are supported on this object: +* [bind](#tcpsockbind) * [connect](#tcpsockconnect) * [setclientcert](#tcpsocksetclientcert) * [sslhandshake](#tcpsocksslhandshake) @@ -7695,6 +7697,42 @@ See also [ngx.socket.udp](#ngxsocketudp). [Back to TOC](#nginx-api-for-lua) +tcpsock:bind +------------ +**syntax:** *ok, err = tcpsock:bind(address)* + +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*,ssl_session_fetch_by_lua*,ssl_client_hello_by_lua** + +Just like the standard [proxy_bind](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_bind) directive, this api makes the outgoing connection to a upstream server originate from the specified local IP address. + +Only IP addresses can be specified as the `address` argument. + +Here is an example for connecting to a TCP server from the specified local IP address: + +```nginx + + location /test { + content_by_lua_block { + local sock = ngx.socket.tcp() + -- assume "192.168.1.10" is the local ip address + local ok, err = sock:bind("192.168.1.10") + if not ok then + ngx.say("failed to bind") + return + end + local ok, err = sock:connect("192.168.1.67", 80) + if not ok then + ngx.say("failed to connect server: ", err) + return + end + ngx.say("successfully connected!") + sock:close() + } + } +``` + +[Back to TOC](#nginx-api-for-lua) + tcpsock:connect --------------- diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 371b9cb84f..74e298df8f 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -6498,6 +6498,7 @@ This API function was first added to the v0.10.1 release. Creates and returns a TCP or stream-oriented unix domain socket object (also known as one type of the "cosocket" objects). The following methods are supported on this object: +* [[#tcpsock:bind|bind]] * [[#tcpsock:connect|connect]] * [[#tcpsock:setclientcert|setclientcert]] * [[#tcpsock:sslhandshake|sslhandshake]] @@ -6535,6 +6536,38 @@ This feature was first introduced in the v0.5.0rc1 release. See also [[#ngx.socket.udp|ngx.socket.udp]]. +== tcpsock:bind == +'''syntax:''' ''ok, err = tcpsock:bind(address)'' + +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*'' + +Just like the standard [[HttpProxyModule#proxy_bind|proxy_bind]] directive, this api makes the outgoing connection to a upstream server originate from the specified local IP address. + +Only IP addresses can be specified as the address argument. + +Here is an example for connecting to a TCP server from the specified local IP address: + + + location /test { + content_by_lua_block { + local sock = ngx.socket.tcp() + -- assume "192.168.1.10" is the local ip address + local ok, err = sock:bind("192.168.1.10") + if not ok then + ngx.say("failed to bind") + return + end + local ok, err = sock:connect("192.168.1.67", 80) + if not ok then + ngx.say("failed to connect server: ", err) + return + end + ngx.say("successfully connected!") + sock:close() + } + } + + == tcpsock:connect == '''syntax:''' ''ok, err = tcpsock:connect(host, port, options_table?)'' diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index d8f1d4d1c1..e40ecbb537 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -20,6 +20,7 @@ static int ngx_http_lua_socket_tcp(lua_State *L); +static int ngx_http_lua_socket_tcp_bind(lua_State *L); static int ngx_http_lua_socket_tcp_connect(lua_State *L); #if (NGX_HTTP_SSL) static void ngx_http_lua_ssl_handshake_handler(ngx_connection_t *c); @@ -162,6 +163,7 @@ enum { SOCKET_READ_TIMEOUT_INDEX = 5, SOCKET_CLIENT_CERT_INDEX = 6 , SOCKET_CLIENT_PKEY_INDEX = 7 , + SOCKET_BIND_INDEX = 8 /* only in upstream cosocket */ }; @@ -314,7 +316,10 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) /* {{{tcp object metatable */ lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( tcp_socket_metatable_key)); - lua_createtable(L, 0 /* narr */, 15 /* nrec */); + lua_createtable(L, 0 /* narr */, 16 /* nrec */); + + lua_pushcfunction(L, ngx_http_lua_socket_tcp_bind); + lua_setfield(L, -2, "bind"); lua_pushcfunction(L, ngx_http_lua_socket_tcp_connect); lua_setfield(L, -2, "connect"); @@ -827,6 +832,61 @@ ngx_http_lua_socket_tcp_connect_helper(lua_State *L, } +static int +ngx_http_lua_socket_tcp_bind(lua_State *L) +{ + ngx_http_request_t *r; + ngx_http_lua_ctx_t *ctx; + int n; + u_char *text; + size_t len; + ngx_addr_t *local; + + n = lua_gettop(L); + + if (n != 2) { + return luaL_error(L, "expecting 2 arguments, but got %d", + lua_gettop(L)); + } + + r = ngx_http_lua_get_req(L); + if (r == NULL) { + return luaL_error(L, "no request found"); + } + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx == NULL) { + return luaL_error(L, "no ctx found"); + } + + ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE + | NGX_HTTP_LUA_CONTEXT_ACCESS + | NGX_HTTP_LUA_CONTEXT_CONTENT + | NGX_HTTP_LUA_CONTEXT_TIMER + | NGX_HTTP_LUA_CONTEXT_SSL_CERT); + + luaL_checktype(L, 1, LUA_TTABLE); + + text = (u_char *) luaL_checklstring(L, 2, &len); + + local = ngx_http_lua_parse_addr(L, text, len); + if (local == NULL) { + lua_pushnil(L); + lua_pushfstring(L, "bad address"); + return 2; + } + + /* TODO: we may reuse the userdata here */ + lua_rawseti(L, 1, SOCKET_BIND_INDEX); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua tcp socket bind ip: %V", &local->name); + + lua_pushboolean(L, 1); + return 1; +} + + static int ngx_http_lua_socket_tcp_connect(lua_State *L) { @@ -838,6 +898,7 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) size_t len; ngx_http_lua_loc_conf_t *llcf; ngx_peer_connection_t *pc; + ngx_addr_t *local; int connect_timeout, send_timeout, read_timeout; unsigned custom_pool; int key_index; @@ -1068,6 +1129,14 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) dd("lua peer connection log: %p", pc->log); + lua_rawgeti(L, 1, SOCKET_BIND_INDEX); + local = lua_touserdata(L, -1); + lua_pop(L, 1); + + if (local) { + u->peer.local = local; + } + lua_rawgeti(L, 1, SOCKET_CONNECT_TIMEOUT_INDEX); lua_rawgeti(L, 1, SOCKET_SEND_TIMEOUT_INDEX); lua_rawgeti(L, 1, SOCKET_READ_TIMEOUT_INDEX); diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 39ba0b21fb..8fd26561a7 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -4396,4 +4396,77 @@ ngx_http_lua_copy_escaped_header(ngx_http_request_t *r, return NGX_OK; } + +ngx_addr_t * +ngx_http_lua_parse_addr(lua_State *L, u_char *text, size_t len) +{ + ngx_addr_t *addr; + size_t socklen; + in_addr_t inaddr; + ngx_uint_t family; + struct sockaddr_in *sin; +#if (NGX_HAVE_INET6) + struct in6_addr inaddr6; + struct sockaddr_in6 *sin6; + + /* + * prevent MSVC8 warning: + * potentially uninitialized local variable 'inaddr6' used + */ + ngx_memzero(&inaddr6, sizeof(struct in6_addr)); +#endif + + inaddr = ngx_inet_addr(text, len); + + if (inaddr != INADDR_NONE) { + family = AF_INET; + socklen = sizeof(struct sockaddr_in); + +#if (NGX_HAVE_INET6) + + } else if (ngx_inet6_addr(text, len, inaddr6.s6_addr) == NGX_OK) { + family = AF_INET6; + socklen = sizeof(struct sockaddr_in6); +#endif + + } else { + return NULL; + } + + addr = lua_newuserdata(L, sizeof(ngx_addr_t) + socklen + len); + if (addr == NULL) { + luaL_error(L, "no memory"); + return NULL; + } + + addr->sockaddr = (struct sockaddr *) ((u_char *) addr + sizeof(ngx_addr_t)); + + ngx_memzero(addr->sockaddr, socklen); + + addr->sockaddr->sa_family = (u_char) family; + addr->socklen = socklen; + + switch (family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + sin6 = (struct sockaddr_in6 *) addr->sockaddr; + ngx_memcpy(sin6->sin6_addr.s6_addr, inaddr6.s6_addr, 16); + break; +#endif + + default: /* AF_INET */ + sin = (struct sockaddr_in *) addr->sockaddr; + sin->sin_addr.s_addr = inaddr; + break; + } + + addr->name.data = (u_char *) addr->sockaddr + socklen; + addr->name.len = len; + ngx_memcpy(addr->name.data, text, len); + + return addr; +} + + /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_util.h b/src/ngx_http_lua_util.h index 4c4da976c5..faea7a072c 100644 --- a/src/ngx_http_lua_util.h +++ b/src/ngx_http_lua_util.h @@ -262,6 +262,8 @@ void ngx_http_lua_cleanup_free(ngx_http_request_t *r, void ngx_http_lua_set_sa_restart(ngx_log_t *log); #endif +ngx_addr_t *ngx_http_lua_parse_addr(lua_State *L, u_char *text, size_t len); + size_t ngx_http_lua_escape_log(u_char *dst, u_char *src, size_t size); diff --git a/t/062-count.t b/t/062-count.t index d977909bb6..d524da47d8 100644 --- a/t/062-count.t +++ b/t/062-count.t @@ -459,7 +459,7 @@ worker: 4 --- request GET /test --- response_body -n = 15 +n = 16 --- no_error_log [error] diff --git a/t/168-tcp-socket-bind.t b/t/168-tcp-socket-bind.t new file mode 100644 index 0000000000..6aca00c51e --- /dev/null +++ b/t/168-tcp-socket-bind.t @@ -0,0 +1,361 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use Test::Nginx::Socket::Lua; + +# more times than usual(2) for test case 6 +repeat_each(4); + +plan tests => repeat_each() * (blocks() * 3 + 7); + +our $HtmlDir = html_dir; + +# get ip address in the dev which is default route outgoing dev +my $dev = `ip route | awk '/default/ {printf "%s", \$5}'`; +my $local_ip = `ip route | grep $dev | grep -o "src .*" | head -n 1 | awk '{print \$2}'`; +chomp $local_ip; + +$ENV{TEST_NGINX_HTML_DIR} = $HtmlDir; +$ENV{TEST_NGINX_NOT_EXIST_IP} ||= '8.8.8.8'; +$ENV{TEST_NGINX_INVALID_IP} ||= '127.0.0.1:8899'; +$ENV{TEST_NGINX_SERVER_IP} ||= $local_ip; + +no_long_string(); +#no_diff(); + +#log_level 'warn'; +log_level 'debug'; + +no_shuffle(); + +run_tests(); + +__DATA__ + +=== TEST 1: upstream sockets bind 127.0.0.1 +--- config + server_tokens off; + location /t { + set $port $TEST_NGINX_SERVER_PORT; + content_by_lua_block { + local ip = "127.0.0.1" + local port = ngx.var.port + + local sock = ngx.socket.tcp() + local ok, err = sock:bind(ip) + if not ok then + ngx.say("failed to bind", err) + return + end + + local ok, err = sock:connect("127.0.0.1", port) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local bytes, err = sock:send("GET /foo HTTP/1.1\r\nHost: localhost\r\nConnection: keepalive\r\n\r\n") + if not bytes then + ngx.say("failed to send request: ", err) + return + end + + ngx.say("request sent") + + local reader = sock:receiveuntil("\r\n0\r\n\r\n") + local data, err = reader() + + if not data then + ngx.say("failed to receive response body: ", err) + return + end + + ngx.say("received response") + local remote_ip = string.match(data, "(bind: %d+%.%d+%.%d+%.%d+)") + ngx.say(remote_ip) + + ngx.say("done") + } + } + + location /foo { + echo bind: $remote_addr; + } +--- request +GET /t +--- response_body +connected: 1 +request sent +received response +bind: 127.0.0.1 +done +--- no_error_log +["[error]", +"bind(127.0.0.1) failed"] +--- error_log eval +"lua tcp socket bind ip: 127.0.0.1" + + + +=== TEST 2: upstream sockets bind server ip, not 127.0.0.1 +--- config + server_tokens off; + location /t { + set $port $TEST_NGINX_SERVER_PORT; + content_by_lua_block { + local ip = "$TEST_NGINX_SERVER_IP" + local port = ngx.var.port + + local sock = ngx.socket.tcp() + local ok, err = sock:bind(ip) + if not ok then + ngx.say("failed to bind", err) + return + end + + local ok, err = sock:connect("127.0.0.1", port) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local bytes, err = sock:send("GET /foo HTTP/1.1\r\nHost: localhost\r\nConnection: keepalive\r\n\r\n") + if not bytes then + ngx.say("failed to send request: ", err) + return + end + + ngx.say("request sent") + + local reader = sock:receiveuntil("\r\n0\r\n\r\n") + local data, err = reader() + + if not data then + ngx.say("failed to receive response body: ", err) + return + end + + ngx.say("received response") + local remote_ip = string.match(data, "(bind: %d+%.%d+%.%d+%.%d+)") + if remote_ip == "bind: $TEST_NGINX_SERVER_IP" then + ngx.say("ip matched") + end + + ngx.say("done") + } + } + + location /foo { + echo bind: $remote_addr; + } +--- request +GET /t +--- response_body +connected: 1 +request sent +received response +ip matched +done +--- no_error_log eval +["[error]", +"bind($ENV{TEST_NGINX_SERVER_IP}) failed"] +--- error_log eval +"lua tcp socket bind ip: $ENV{TEST_NGINX_SERVER_IP}" + + + +=== TEST 3: add setkeepalive +--- http_config eval + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" +--- config + server_tokens off; + location /t { + set $port $TEST_NGINX_SERVER_PORT; + content_by_lua_block { + local test = require "test" + local t1 = test.go() + local t2 = test.go() + ngx.say("t2 - t1: ", t2 - t1) + } + } +--- user_files +>>> test.lua +local _M = {} + +function _M.go() + local ip = "127.0.0.1" + local port = ngx.var.port + + local sock = ngx.socket.tcp() + local ok, err = sock:bind(ip) + if not ok then + ngx.say("failed to bind", err) + return + end + + ngx.say("bind: ", ip) + + local ok, err = sock:connect("127.0.0.1", port) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local reused = sock:getreusedtimes() + + local ok, err = sock:setkeepalive() + if not ok then + ngx.say("failed to set reusable: ", err) + end + + return reused +end + +return _M +--- request +GET /t +--- response_body +bind: 127.0.0.1 +connected: 1 +bind: 127.0.0.1 +connected: 1 +t2 - t1: 1 +--- no_error_log +["[error]", +"bind(127.0.0.1) failed"] +--- error_log eval +"lua tcp socket bind ip: 127.0.0.1" + + + +=== TEST 4: upstream sockets bind not exist ip +--- config + server_tokens off; + location /t { + set $port $TEST_NGINX_SERVER_PORT; + content_by_lua_block { + local ip = "$TEST_NGINX_NOT_EXIST_IP" + local port = ngx.var.port + + local sock = ngx.socket.tcp() + local ok, err = sock:bind(ip) + if not ok then + ngx.say("failed to bind", err) + return + end + + ngx.say("bind: ", ip) + + local ok, err = sock:connect("127.0.0.1", port) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + } + } +--- request +GET /t +--- response_body +bind: 8.8.8.8 +failed to connect: cannot assign requested address +--- error_log eval +["bind(8.8.8.8) failed", +"lua tcp socket bind ip: 8.8.8.8"] + + + +=== TEST 5: upstream sockets bind invalid ip +--- config + server_tokens off; + location /t { + set $port $TEST_NGINX_SERVER_PORT; + content_by_lua_block { + local ip = "$TEST_NGINX_INVALID_IP" + local port = ngx.var.port + + local sock = ngx.socket.tcp() + local ok, err = sock:bind(ip) + if not ok then + ngx.say("failed to bind: ", err) + return + end + + ngx.say("bind: ", ip) + + local ok, err = sock:connect("127.0.0.1", port) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + } + } +--- request +GET /t +--- response_body +failed to bind: bad address +--- no_error_log +[error] + + + +=== TEST 6: tcpsock across request after bind +--- http_config + init_worker_by_lua_block { + -- this is not the recommend way, just for test + local function tcp() + local sock = ngx.socket.tcp() + + ---[[ + local ok, err = sock:bind("127.0.0.1") + if not ok then + ngx.log(ngx.ERR, "failed to bind") + end + --]] + + package.loaded.share_sock = sock + end + + local ok, err = ngx.timer.at(0, tcp) + if not ok then + ngx.log(ngx.ERR, "failed to create timer") + end + } +--- config + server_tokens off; + location /t { + set $port $TEST_NGINX_SERVER_PORT; + content_by_lua_block { + local port = ngx.var.port + + -- make sure share_sock is created + ngx.sleep(0.002) + + local sock = package.loaded.share_sock + + local ok, err = sock:connect("127.0.0.1", port) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + sock:close() + collectgarbage("collect") + } + } +--- request +GET /t +--- response_body +connected: 1 +--- no_error_log +[error] From 73f2b3f6fe13b4852ad4ae02a62d33f41879eaf9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=81=AA?= Date: Thu, 4 Aug 2022 23:54:55 +0800 Subject: [PATCH 049/254] bugfix: typo in the debug message. (#2081) --- src/ngx_http_lua_uri.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ngx_http_lua_uri.c b/src/ngx_http_lua_uri.c index c37dde9cb2..c4d65f2905 100644 --- a/src/ngx_http_lua_uri.c +++ b/src/ngx_http_lua_uri.c @@ -93,7 +93,7 @@ ngx_http_lua_ngx_req_set_uri(lua_State *L) } dd("server_rewrite: %d, rewrite: %d, access: %d, content: %d", - (int) ctx->entered_serverrewrite_phase, + (int) ctx->entered_server_rewrite_phase, (int) ctx->entered_rewrite_phase, (int) ctx->entered_access_phase, (int) ctx->entered_content_phase); From a7e67a596f707c916b009b17b3d22b925e6f2e11 Mon Sep 17 00:00:00 2001 From: levy001 Date: Sun, 7 Aug 2022 08:59:34 +0800 Subject: [PATCH 050/254] doc: add more explanation for premature in ngx.timer.at. --- README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index 6466a1edff..fd2ab039b0 100644 --- a/README.markdown +++ b/README.markdown @@ -8749,7 +8749,7 @@ be any Lua function, which will be invoked later in a background called automatically by the Nginx core with the arguments `premature`, `user_arg1`, `user_arg2`, and etc, where the `premature` argument takes a boolean value indicating whether it is a premature timer -expiration or not, and `user_arg1`, `user_arg2`, and etc, are +expiration or not(for the `0` delay timer it is always `false`), and `user_arg1`, `user_arg2`, and etc, are those (extra) user arguments specified when calling `ngx.timer.at` as the remaining arguments. From 5eb7101d3307f82226b83209806cf90a483fd236 Mon Sep 17 00:00:00 2001 From: Jun Ouyang Date: Fri, 12 Aug 2022 09:23:35 +0800 Subject: [PATCH 051/254] doc: complete md5.lua example in run_worker_thread api (#2085) --- README.markdown | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.markdown b/README.markdown index fd2ab039b0..cf3fb87b1a 100644 --- a/README.markdown +++ b/README.markdown @@ -9377,6 +9377,8 @@ Example1: do md5 calculation. local function md5() return ngx.md5("hello") end + +return { md5=md5, } ``` Example2: write logs into the log file. From eb6d6cbf00bc4891ad2d8af0d42ec722ce8bec30 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Fri, 12 Aug 2022 12:52:10 +0800 Subject: [PATCH 052/254] tests: build with DDEBUG=1. (#2084) --- .travis.yml | 1 + util/build-with-dd.sh | 57 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100755 util/build-with-dd.sh diff --git a/.travis.yml b/.travis.yml index 214420015e..9c579ab75d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -131,6 +131,7 @@ script: - cd .. - export NGX_BUILD_CC=$CC - sh util/build-without-ssl.sh $NGINX_VERSION > build.log 2>&1 || (cat build.log && exit 1) + - sh util/build-with-dd.sh $NGINX_VERSION > build.log 2>&1 || (cat build.log && exit 1) - rm -fr buildroot - sh util/build.sh $NGINX_VERSION > build.log 2>&1 || (cat build.log && exit 1) - nginx -V diff --git a/util/build-with-dd.sh b/util/build-with-dd.sh new file mode 100755 index 0000000000..41ecc72685 --- /dev/null +++ b/util/build-with-dd.sh @@ -0,0 +1,57 @@ +#!/usr/bin/env bash + +# this script is for developers only. +# dependent on the ngx-build script from the nginx-devel-utils repository: +# https://github.com/openresty/nginx-devel-utils/blob/master/ngx-build +# the resulting nginx is located at ./work/nginx/sbin/nginx + +root=`pwd` +version=${1:-1.4.1} +home=~ +force=$2 + +add_fake_shm_module="--add-module=$root/t/data/fake-shm-module" + +time ngx-build $force $version \ + --with-threads \ + --with-pcre-jit \ + --with-ipv6 \ + --with-cc-opt="-DNGX_LUA_USE_ASSERT -I$PCRE_INC -I$OPENSSL_INC -DDDEBUG=1" \ + --with-http_v2_module \ + --with-http_realip_module \ + --with-http_ssl_module \ + --add-module=$root/../ndk-nginx-module \ + --add-module=$root/../set-misc-nginx-module \ + --with-ld-opt="-L$PCRE_LIB -L$OPENSSL_LIB -Wl,-rpath,$PCRE_LIB:$LIBDRIZZLE_LIB:$OPENSSL_LIB" \ + --without-mail_pop3_module \ + --without-mail_imap_module \ + --with-http_image_filter_module \ + --without-mail_smtp_module \ + --with-stream \ + --with-stream_ssl_module \ + --without-http_upstream_ip_hash_module \ + --without-http_memcached_module \ + --without-http_auth_basic_module \ + --without-http_userid_module \ + --with-http_auth_request_module \ + --add-module=$root/../echo-nginx-module \ + --add-module=$root/../memc-nginx-module \ + --add-module=$root/../srcache-nginx-module \ + --add-module=$root \ + --add-module=$root/../lua-upstream-nginx-module \ + --add-module=$root/../headers-more-nginx-module \ + --add-module=$root/../drizzle-nginx-module \ + --add-module=$root/../rds-json-nginx-module \ + --add-module=$root/../coolkit-nginx-module \ + --add-module=$root/../redis2-nginx-module \ + --add-module=$root/../stream-lua-nginx-module \ + --add-module=$root/t/data/fake-module \ + $add_fake_shm_module \ + --add-module=$root/t/data/fake-delayed-load-module \ + --with-http_gunzip_module \ + --with-http_dav_module \ + --with-select_module \ + --with-poll_module \ + $opts \ + --with-debug + From 3e2a7f459353a26d9475a54661c70a6e2c8cd27e Mon Sep 17 00:00:00 2001 From: fesily Date: Sun, 14 Aug 2022 11:53:45 +0800 Subject: [PATCH 053/254] bugfix: run_worker_thread arg is self-reference. Co-authored-by: lijunlong@openresty.com --- src/ngx_http_lua_worker_thread.c | 58 +++++++++++++++++++-------- t/166-worker-thread.t | 67 ++++++++++++++++++++++++++++++-- 2 files changed, 106 insertions(+), 19 deletions(-) diff --git a/src/ngx_http_lua_worker_thread.c b/src/ngx_http_lua_worker_thread.c index 1512be4daf..ed7b089295 100644 --- a/src/ngx_http_lua_worker_thread.c +++ b/src/ngx_http_lua_worker_thread.c @@ -18,6 +18,10 @@ #include "ngx_http_lua_config.h" #include "ngx_http_lua_shdict.h" +#ifndef STRINGIFY +#define TOSTRING(x) #x +#define STRINGIFY(x) TOSTRING(x) +#endif #if (NGX_THREADS) @@ -25,6 +29,7 @@ #include #include +#define LUA_COPY_MAX_DEPTH 100 typedef struct ngx_http_lua_task_ctx_s { lua_State *vm; @@ -208,7 +213,7 @@ ngx_http_lua_free_task_ctx(ngx_http_lua_task_ctx_t *ctx) static int ngx_http_lua_xcopy(lua_State *from, lua_State *to, int idx, - const int allow_nil) + const int allow_nil, const int depth, const char **err) { size_t len = 0; const char *str; @@ -235,6 +240,13 @@ ngx_http_lua_xcopy(lua_State *from, lua_State *to, int idx, return LUA_TSTRING; case LUA_TTABLE: + if (depth >= LUA_COPY_MAX_DEPTH) { + *err = "suspicious circular references, " + "table depth exceed max depth: " + STRINGIFY(LUA_COPY_MAX_DEPTH); + return LUA_TNONE; + } + top_from = lua_gettop(from); top_to = lua_gettop(to); @@ -248,8 +260,9 @@ ngx_http_lua_xcopy(lua_State *from, lua_State *to, int idx, lua_pushnil(from); while (lua_next(from, idx) != 0) { - if (ngx_http_lua_xcopy(from, to, -2, 0) != LUA_TNONE - && ngx_http_lua_xcopy(from, to, -1, 0) != LUA_TNONE) + if (ngx_http_lua_xcopy(from, to, -2, 0, depth + 1, err) != LUA_TNONE + && ngx_http_lua_xcopy(from, to, -1, 0, + depth + 1, err) != LUA_TNONE) { lua_rawset(to, -3); @@ -269,16 +282,24 @@ ngx_http_lua_xcopy(lua_State *from, lua_State *to, int idx, lua_pushnil(to); return LUA_TNIL; } - /* fall through */ - - /* - * ignore unsupported values: - * LUA_TNONE - * LUA_TFUNCTION - * LUA_TUSERDATA - * LUA_TTHREAD - */ + + *err = "unsupported Lua type: LUA_TNIL"; + return LUA_TNONE; + + case LUA_TFUNCTION: + *err = "unsupported Lua type: LUA_TFUNCTION"; + return LUA_TNONE; + + case LUA_TUSERDATA: + *err = "unsupported Lua type: LUA_TUSERDATA"; + return LUA_TNONE; + + case LUA_TTHREAD: + *err = "unsupported Lua type: LUA_TTHREAD"; + return LUA_TNONE; + default: + *err = "unsupported Lua type"; return LUA_TNONE; } } @@ -357,6 +378,7 @@ ngx_http_lua_worker_thread_event_handler(ngx_event_t *ev) ngx_http_lua_ctx_t *ctx; lua_State *vm; int saved_top; + const char *err; worker_thread_ctx = ev->data; @@ -392,10 +414,12 @@ ngx_http_lua_worker_thread_event_handler(ngx_event_t *ev) lua_pushboolean(L, 1); nresults = lua_gettop(vm) + 1; for (i = 1; i < nresults; i++) { - if (ngx_http_lua_xcopy(vm, L, i, 1) == LUA_TNONE) { + err = NULL; + if (ngx_http_lua_xcopy(vm, L, i, 1, 1, &err) == LUA_TNONE) { lua_settop(L, saved_top); lua_pushboolean(L, 0); - lua_pushstring(L, "unsupported return value"); + lua_pushfstring(L, "%s in the return value", + err != NULL ? err : "unsupoorted Lua type"); nresults = 2; break; } @@ -557,9 +581,11 @@ ngx_http_lua_run_worker_thread(lua_State *L) /* copying passed arguments */ for (i = 4; i <= n_args; i++) { - if (ngx_http_lua_xcopy(L, vm, i, 1) == LUA_TNONE) { + err = NULL; + if (ngx_http_lua_xcopy(L, vm, i, 1, 1, &err) == LUA_TNONE) { lua_pushboolean(L, 0); - lua_pushstring(L, "unsupported argument type"); + lua_pushfstring(L, "%s in the argument", + err != NULL ? err : "unsupoorted Lua type"); ngx_http_lua_free_task_ctx(tctx); return 2; } diff --git a/t/166-worker-thread.t b/t/166-worker-thread.t index 2b7258df7c..fd7fdd756e 100644 --- a/t/166-worker-thread.t +++ b/t/166-worker-thread.t @@ -229,7 +229,7 @@ return {hello=hello} --- request GET /hello --- response_body -false : unsupported argument type +false : unsupported Lua type: LUA_TFUNCTION in the argument @@ -491,7 +491,7 @@ return {hello=hello} --- request GET /hello --- response_body -false : unsupported argument type +false : unsupported Lua type: LUA_TFUNCTION in the argument @@ -524,7 +524,7 @@ return {hello=hello} --- request GET /hello --- response_body -false , unsupported return value +false , unsupported Lua type: LUA_TFUNCTION in the return value @@ -1695,3 +1695,64 @@ return {dictgetkeys=dictgetkeys} GET /dictgetkeys --- response_body true,Jim:King + + + +=== TEST 53: unsupported argument type in self-reference table +--- main_config + thread_pool testpool threads=100; +--- http_config eval + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" +--- config +location /hello { + default_type 'text/plain'; + + content_by_lua_block { + local t = {} + t.a = t + local ok, ok_or_err = ngx.run_worker_thread("testpool", "hello", "hello", t) + ngx.say(ok, " , ", ok_or_err) + } +} +--- user_files +>>> hello.lua +local function hello(arg1) + return true +end +return {hello=hello} +--- request +GET /hello +--- response_body +false , suspicious circular references, table depth exceed max depth: 100 in the argument + + + +=== TEST 54: unsupported argument type in circular-reference table +--- main_config + thread_pool testpool threads=100; +--- http_config eval + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" +--- config +location /hello { + default_type 'text/plain'; + + content_by_lua_block { + local t = {} + local s = {} + t.a = s + s.b = t + + local ok, ok_or_err = ngx.run_worker_thread("testpool", "hello", "hello", t) + ngx.say(ok, " , ", ok_or_err) + } +} +--- user_files +>>> hello.lua +local function hello(arg1) + return true +end +return {hello=hello} +--- request +GET /hello +--- response_body +false , suspicious circular references, table depth exceed max depth: 100 in the argument From edfa0f984ec60bd0658b80643c2fd253f3c5ad0b Mon Sep 17 00:00:00 2001 From: attenuation Date: Sun, 21 Aug 2022 21:59:28 +0800 Subject: [PATCH 054/254] feat: add ngx_http_lua_ffi_worker_pids to get all workers pid map --- README.markdown | 12 ++++++++++++ doc/HttpLuaModule.wiki | 7 +++++++ src/ngx_http_lua_worker.c | 31 +++++++++++++++++++++++++++++++ t/062-count.t | 2 +- t/122-worker.t | 32 +++++++++++++++++++++++++++++++- 5 files changed, 82 insertions(+), 2 deletions(-) diff --git a/README.markdown b/README.markdown index cf3fb87b1a..7a5ba6b295 100644 --- a/README.markdown +++ b/README.markdown @@ -3714,6 +3714,7 @@ Nginx API for Lua * [ngx.config.ngx_lua_version](#ngxconfigngx_lua_version) * [ngx.worker.exiting](#ngxworkerexiting) * [ngx.worker.pid](#ngxworkerpid) +* [ngx.worker.pids](#ngxworkerpids) * [ngx.worker.count](#ngxworkercount) * [ngx.worker.id](#ngxworkerid) * [ngx.semaphore](#ngxsemaphore) @@ -9025,6 +9026,17 @@ This API was first introduced in the `0.9.5` release. [Back to TOC](#nginx-api-for-lua) +ngx.worker.pids +-------------- + +**syntax:** *pids = ngx.worker.pids()* + +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, exit_worker_by_lua** + +This function returns a Lua table for all Nginx worker process ID (PID). Nginx uses channel to send the current worker PID to another worker in the worker process start or restart. So this API can get all current worker PID. + +[Back to TOC](#nginx-api-for-lua) + ngx.worker.count ---------------- diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 74e298df8f..6b2bb99476 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -7742,6 +7742,13 @@ This function returns a Lua number for the process ID (PID) of the current Nginx This API was first introduced in the 0.9.5 release. +== ngx.worker.pids == + +'''syntax:''' ''pid = ngx.worker.pids()'' + +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, exit_worker_by_lua*'' + +This function returns a Lua table for all Nginx worker process ID (PID). Nginx uses channel to send the current worker PID to another worker in the worker process start or restart. So this API can get all current worker PID. == ngx.worker.count == '''syntax:''' ''count = ngx.worker.count()'' diff --git a/src/ngx_http_lua_worker.c b/src/ngx_http_lua_worker.c index 0ca2d414e3..52ec34a844 100644 --- a/src/ngx_http_lua_worker.c +++ b/src/ngx_http_lua_worker.c @@ -8,6 +8,7 @@ #define DDEBUG 0 #endif #include "ddebug.h" +#include #define NGX_PROCESS_PRIVILEGED_AGENT 99 @@ -20,6 +21,36 @@ ngx_http_lua_ffi_worker_pid(void) } +int +ngx_http_lua_ffi_worker_pids(int *pids, size_t *pids_len) +{ + ngx_int_t i, n; + + n = 0; + for (i = 0; i < NGX_MAX_PROCESSES; i++) { + if (i != ngx_process_slot && ngx_processes[i].pid == 0) { + break; + } + + if (i == ngx_process_slot && ngx_processes[i].pid == 0) { + pids[n++] = ngx_pid; + } + + if (ngx_processes[i].pid > 0) { + pids[n++] = ngx_processes[i].pid; + } + } + + if (n == 0) { + return NGX_ERROR; + } + + *pids_len = n; + + return NGX_OK; +} + + int ngx_http_lua_ffi_worker_id(void) { diff --git a/t/062-count.t b/t/062-count.t index d524da47d8..ad464ba2de 100644 --- a/t/062-count.t +++ b/t/062-count.t @@ -438,7 +438,7 @@ thread: 3 --- request GET /test --- response_body -worker: 4 +worker: 5 --- no_error_log [error] diff --git a/t/122-worker.t b/t/122-worker.t index b74c81fbcd..244c3142d3 100644 --- a/t/122-worker.t +++ b/t/122-worker.t @@ -9,7 +9,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * (blocks() * 3); +plan tests => repeat_each() * (blocks() * 4 - 4); #no_diff(); no_long_string(); @@ -79,3 +79,33 @@ worker pid: \d+ worker pid is correct\. --- no_error_log [error] + + + +=== TEST 4: content_by_lua + ngx.worker.pids +--- config + location /lua { + content_by_lua ' + local pids = ngx.worker.pids() + local pid = ngx.worker.pid() + ngx.say("worker pid: ", pid) + local count = ngx.worker.count() + if count ~= #pids then + ngx.say("worker pids is wrong.") + end + for i = 1, count do + if pids[i] == pid then + ngx.say("worker pid is correct.") + return + end + end + ngx.say("worker pid is wrong.") + '; + } +--- request +GET /lua +--- response_body_like +worker pid: \d+ +worker pid is correct\. +--- no_error_log +[error] From cff86dd7f677e3b856fb7ca1de90746b24eb6411 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BD=97=E6=B3=BD=E8=BD=A9?= Date: Sun, 21 Aug 2022 22:56:32 +0800 Subject: [PATCH 055/254] doc: fix the version in README (#2089) --- README.markdown | 2 +- doc/HttpLuaModule.wiki | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.markdown b/README.markdown index 7a5ba6b295..f752fc33e8 100644 --- a/README.markdown +++ b/README.markdown @@ -4113,7 +4113,7 @@ Because HTTP request is created after SSL handshake, the `ngx.ctx` created in [ssl_certificate_by_lua*](#ssl_certificate_by_lua), [ssl_session_store_by_lua*](#ssl_session_store_by_lua), [ssl_session_fetch_by_lua*](#ssl_session_fetch_by_lua) and [ssl_client_hello_by_lua*](#ssl_client_hello_by_lua) is not available in the following phases like [rewrite_by_lua*](#rewrite_by_lua). -Since `dev`, the `ngx.ctx` created during a SSL handshake +Since `v0.10.18`, the `ngx.ctx` created during a SSL handshake will be inherited by the requests which share the same TCP connection established by the handshake. Note that overwrite values in `ngx.ctx` in the http request phases (like `rewrite_by_lua*`) will only take affect in the current http request. diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 6b2bb99476..34751144bd 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -3387,7 +3387,7 @@ Because HTTP request is created after SSL handshake, the ngx.ctx cr in [[#ssl_certificate_by_lua|ssl_certificate_by_lua*]], [[#ssl_session_store_by_lua|ssl_session_store_by_lua*]], [[#ssl_session_fetch_by_lua|ssl_session_fetch_by_lua*]] and [[#ssl_client_hello_by_lua|ssl_client_hello_by_lua*]] is not available in the following phases like [[#rewrite_by_lua|rewrite_by_lua*]]. -Since dev, the ngx.ctx created during a SSL handshake +Since v0.10.18, the ngx.ctx created during a SSL handshake will be inherited by the requests which share the same TCP connection established by the handshake. Note that overwrite values in ngx.ctx in the http request phases (like `rewrite_by_lua*`) will only take affect in the current http request. From 4add942393fbc487cd540a09f581a032f90be325 Mon Sep 17 00:00:00 2001 From: kingluo Date: Sat, 18 Jun 2022 22:50:55 +0800 Subject: [PATCH 056/254] bugfix: did not wakeup coroutine when worker thread finished. --- README.markdown | 41 +++--------------- doc/HttpLuaModule.wiki | 33 +++------------ src/ngx_http_lua_common.h | 4 ++ src/ngx_http_lua_worker_thread.c | 73 ++++++++++++++++++++++---------- t/166-worker-thread.t | 38 +++++++++++++++++ 5 files changed, 105 insertions(+), 84 deletions(-) diff --git a/README.markdown b/README.markdown index d8f28769d7..d6560185cf 100644 --- a/README.markdown +++ b/README.markdown @@ -1,8 +1,3 @@ - - Name ==== @@ -9194,42 +9189,18 @@ Example1: do md5 calculation. default_type 'text/plain'; content_by_lua_block { - local ok, ret, md5_or_err = ngx.run_worker_thread("testpool", "calc_md5", "md5", ngx.var.arg_str) - if not ok then - ngx.say(ret) - return - end - if not ret then - ngx.say(md5_or_err) - return - end - ngx.say(md5_or_err) + local ok, md5_or_err = ngx.run_worker_thread("testpool", "md5", "md5") + ngx.say(ok, " : ", md5_or_err) } } ``` -`calc_md5.lua` +`md5.lua` ```lua - - local resty_md5 = require "resty.md5" - local resty_str = require "resty.string" - - local function md5(str) - local md5 = resty_md5:new() - if not md5 then - return false, "md5 new error" - end - - local ok = md5:update(str) - if not ok then - return false, "md5 update error" - end - - local digest = md5:final() - return true, resty_str.to_hex(digest) - end - return {md5=md5} +local function md5() + return ngx.md5("hello") +end ``` Example2: write logs into the log file. diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 98f3c5879b..7b187bc6f0 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -7888,39 +7888,18 @@ location /calc_md5 { default_type 'text/plain'; content_by_lua_block { - local ok, ret, md5_or_err = ngx.run_worker_thread("testpool", "calc_md5", "md5", ngx.var.arg_str) - if not ok then - ngx.say(ret) - return - end - if not ret then - ngx.say(md5_or_err) - return - end - ngx.say(md5_or_err) + local ok, md5_or_err = ngx.run_worker_thread("testpool", "md5", "md5") + ngx.say(ok, " : ", md5_or_err) } } + -calc_md5.lua +md5.lua -local resty_md5 = require "resty.md5" -local resty_str = require "resty.string" - -local function md5(str) - local md5 = resty_md5:new() - if not md5 then - return false, "md5 new error" - end - - local ok = md5:update(str) - if not ok then - return false, "md5 update error" - end - - local digest = md5:final() - return true, resty_str.to_hex(digest) +local function md5() + return ngx.md5("hello") end return {md5=md5} diff --git a/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h index ed88f0a2f5..9f991d1aa0 100644 --- a/src/ngx_http_lua_common.h +++ b/src/ngx_http_lua_common.h @@ -469,6 +469,10 @@ struct ngx_http_lua_co_ctx_s { uint8_t *sr_flags; + unsigned nresults_from_worker_thread; /* number of results + * from worker + * thread callback */ + unsigned nsubreqs; /* number of subrequests of the * current request */ diff --git a/src/ngx_http_lua_worker_thread.c b/src/ngx_http_lua_worker_thread.c index 5133fa6e76..5f785ffb22 100644 --- a/src/ngx_http_lua_worker_thread.c +++ b/src/ngx_http_lua_worker_thread.c @@ -287,6 +287,50 @@ ngx_http_lua_worker_thread_handler(void *data, ngx_log_t *log) } +static ngx_int_t +ngx_http_lua_worker_thread_resume(ngx_http_request_t *r) +{ + lua_State *vm; + ngx_connection_t *c; + ngx_int_t rc; + ngx_uint_t nreqs; + ngx_http_lua_ctx_t *ctx; + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx == NULL) { + return NGX_ERROR; + } + + ctx->resume_handler = ngx_http_lua_wev_handler; + + c = r->connection; + vm = ngx_http_lua_get_lua_vm(r, ctx); + nreqs = c->requests; + + rc = ngx_http_lua_run_thread(vm, r, ctx, + ctx->cur_co_ctx->nresults_from_worker_thread); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua run thread returned %d", rc); + + if (rc == NGX_AGAIN) { + return ngx_http_lua_run_posted_threads(c, vm, r, ctx, nreqs); + } + + if (rc == NGX_DONE) { + ngx_http_lua_finalize_request(r, NGX_DONE); + return ngx_http_lua_run_posted_threads(c, vm, r, ctx, nreqs); + } + + if (ctx->entered_content_phase) { + ngx_http_lua_finalize_request(r, rc); + return NGX_DONE; + } + + return rc; +} + + /* executed in nginx event loop */ static void ngx_http_lua_worker_thread_event_handler(ngx_event_t *ev) @@ -299,7 +343,6 @@ ngx_http_lua_worker_thread_event_handler(ngx_event_t *ev) size_t len; const char *str; int i; - int rc; ngx_http_lua_ctx_t *ctx; lua_State *vm; int saved_top; @@ -349,6 +392,7 @@ ngx_http_lua_worker_thread_event_handler(ngx_event_t *ev) } ctx->cur_co_ctx = worker_thread_ctx->wait_co_ctx; + ctx->cur_co_ctx->nresults_from_worker_thread = nresults; ctx->cur_co_ctx->cleanup = NULL; ngx_http_lua_free_task_ctx(worker_thread_ctx->ctx); @@ -356,30 +400,15 @@ ngx_http_lua_worker_thread_event_handler(ngx_event_t *ev) /* resume the caller coroutine */ - vm = ngx_http_lua_get_lua_vm(r, ctx); - - rc = ngx_http_lua_run_thread(vm, r, ctx, nresults); - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua run thread returned %d", rc); - - if (rc == NGX_AGAIN) { - ngx_http_lua_run_posted_threads(c, vm, r, ctx, c->requests); - return; - } + if (ctx->entered_content_phase) { + (void) ngx_http_lua_worker_thread_resume(r); - if (rc == NGX_DONE) { - ngx_http_lua_finalize_request(r, NGX_DONE); - ngx_http_lua_run_posted_threads(c, vm, r, ctx, c->requests); - return; + } else { + ctx->resume_handler = ngx_http_lua_worker_thread_resume; + ngx_http_core_run_phases(r); } - /* rc == NGX_ERROR || rc >= NGX_OK */ - - if (ctx->entered_content_phase) { - ngx_http_lua_finalize_request(r, rc); - return; - } + ngx_http_run_posted_requests(c); return; diff --git a/t/166-worker-thread.t b/t/166-worker-thread.t index 8b874c55ad..3288f3a15b 100644 --- a/t/166-worker-thread.t +++ b/t/166-worker-thread.t @@ -1208,3 +1208,41 @@ return {hello=hello} GET /hello --- response_body_like chop ^true : \d+$ + + + +=== TEST 39: write_log_file +--- main_config + thread_pool testpool threads=100; +--- http_config eval + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" +--- config +location /write_log_file { + default_type 'text/plain'; + + content_by_lua_block { + local ok, err = ngx.run_worker_thread("testpool", "write_log_file", "log", ngx.var.arg_str) + if not ok then + ngx.say(ok, " : ", err) + return + end + ngx.say(ok) + } +} +--- user_files +>>> write_log_file.lua +local function log(str) + local file, err = io.open("/tmp/tmp.log", "w") + if not file then + return false, err + end + file:write(str) + file:flush() + file:close() + return true +end +return {log=log} +--- request +GET /write_log_file?str=hello +--- response_body +true From 8d9032298ef542aef058fa02940a6ecd9cf25423 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Thu, 15 Sep 2022 10:59:08 +0800 Subject: [PATCH 057/254] bumped the lua version to 0.10.22. --- src/api/ngx_http_lua_api.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/ngx_http_lua_api.h b/src/api/ngx_http_lua_api.h index ff23042250..a1ef1f7cb1 100644 --- a/src/api/ngx_http_lua_api.h +++ b/src/api/ngx_http_lua_api.h @@ -19,7 +19,7 @@ /* Public API for other Nginx modules */ -#define ngx_http_lua_version 10021 +#define ngx_http_lua_version 10022 typedef struct { From 4bbb57aa4a6995bd3efaf35c01e826de6f3cdf3a Mon Sep 17 00:00:00 2001 From: lijunlong Date: Fri, 30 Sep 2022 14:00:43 +0800 Subject: [PATCH 058/254] doc: add release description for ngx.worker.pids(). (#2104) --- README.markdown | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.markdown b/README.markdown index f752fc33e8..0c57cdc69f 100644 --- a/README.markdown +++ b/README.markdown @@ -9035,6 +9035,8 @@ ngx.worker.pids This function returns a Lua table for all Nginx worker process ID (PID). Nginx uses channel to send the current worker PID to another worker in the worker process start or restart. So this API can get all current worker PID. +This API was first introduced in the `0.10.23` release. + [Back to TOC](#nginx-api-for-lua) ngx.worker.count From a318d250f547c854ea2b091d0e06372ac0c00fd5 Mon Sep 17 00:00:00 2001 From: Wangchong Zhou Date: Thu, 13 Oct 2022 19:37:28 +0800 Subject: [PATCH 059/254] doc: add detail on explanation of a running timer (#2105) --- README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index 0c57cdc69f..860ec0084a 100644 --- a/README.markdown +++ b/README.markdown @@ -3529,7 +3529,7 @@ lua_max_running_timers Controls the maximum number of "running timers" allowed. -Running timers are those timers whose user callback functions are still running. +Running timers are those timers whose user callback functions are still running or `lightthreads` spawned in callback functions are still running. When exceeding this limit, Nginx will stop running the callbacks of newly expired timers and log an error message "N lua_max_running_timers are not enough" where "N" is the current value of this directive. From 3207da152a1cead67ade7b3d4234681f2c44ba77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BD=97=E6=B3=BD=E8=BD=A9?= Date: Thu, 20 Oct 2022 23:43:26 +0800 Subject: [PATCH 060/254] chore: add assertion to make linter happy (#2107) Signed-off-by: spacewander --- src/ngx_http_lua_regex.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ngx_http_lua_regex.c b/src/ngx_http_lua_regex.c index 03d1a4d320..5c17cfe09c 100644 --- a/src/ngx_http_lua_regex.c +++ b/src/ngx_http_lua_regex.c @@ -173,6 +173,8 @@ ngx_http_lua_ffi_set_jit_stack_size(int size, u_char *errstr, lmcf = ngx_http_cycle_get_module_main_conf(ngx_cycle, ngx_http_lua_module); + ngx_http_lua_assert(lmcf != NULL); + if (size < NGX_LUA_RE_MIN_JIT_STACK_SIZE) { size = NGX_LUA_RE_MIN_JIT_STACK_SIZE; } @@ -270,6 +272,8 @@ ngx_http_lua_ffi_compile_regex(const unsigned char *pat, size_t pat_len, lmcf = ngx_http_cycle_get_module_main_conf(ngx_cycle, ngx_http_lua_module); + ngx_http_lua_assert(lmcf != NULL); + #if (LUA_HAVE_PCRE_JIT) if (flags & NGX_LUA_RE_MODE_JIT) { From b754786bb507ab76f8bfae2fc88aa59a959908a1 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Thu, 27 Oct 2022 11:59:40 +0800 Subject: [PATCH 061/254] feature: add new ffi api ngx_http_lua_ffi_msec. (#2108) --- src/ngx_http_lua_time.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/ngx_http_lua_time.c b/src/ngx_http_lua_time.c index 61324f37a2..72704b23a2 100644 --- a/src/ngx_http_lua_time.c +++ b/src/ngx_http_lua_time.c @@ -39,6 +39,13 @@ ngx_http_lua_ffi_time(void) } +long +ngx_http_lua_ffi_monotonic_msec(void) +{ + return (long) ngx_current_msec; +} + + void ngx_http_lua_ffi_update_time(void) { From eb977111bbf47779410e7e2ad267b95faa374fc1 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Thu, 27 Oct 2022 20:23:46 +0800 Subject: [PATCH 062/254] bugfix: add a timed recycling child process as a last resort. (#2112) --- src/ngx_http_lua_pipe.c | 148 ++++++++++++++++++++++++---------------- 1 file changed, 90 insertions(+), 58 deletions(-) diff --git a/src/ngx_http_lua_pipe.c b/src/ngx_http_lua_pipe.c index c947d5599f..465d2bff69 100644 --- a/src/ngx_http_lua_pipe.c +++ b/src/ngx_http_lua_pipe.c @@ -78,12 +78,15 @@ static void ngx_http_lua_pipe_proc_read_stdout_cleanup(void *data); static void ngx_http_lua_pipe_proc_read_stderr_cleanup(void *data); static void ngx_http_lua_pipe_proc_write_cleanup(void *data); static void ngx_http_lua_pipe_proc_wait_cleanup(void *data); +static void ngx_http_lua_pipe_reap_pids(ngx_event_t *ev); +static void ngx_http_lua_pipe_reap_timer_handler(ngx_event_t *ev); void ngx_http_lua_ffi_pipe_proc_destroy( ngx_http_lua_ffi_pipe_proc_t *proc); static ngx_rbtree_t ngx_http_lua_pipe_rbtree; static ngx_rbtree_node_t ngx_http_lua_pipe_proc_sentinel; +static ngx_event_t ngx_reap_pid_event; #if (NGX_HTTP_LUA_HAVE_SIGNALFD) @@ -162,6 +165,15 @@ ngx_http_lua_pipe_add_signal_handler(ngx_cycle_t *cycle) struct sigaction sa; #endif + ngx_reap_pid_event.handler = ngx_http_lua_pipe_reap_timer_handler; + ngx_reap_pid_event.log = cycle->log; + ngx_reap_pid_event.data = cycle; + ngx_reap_pid_event.cancelable = 1; + + if (!ngx_reap_pid_event.timer_set) { + ngx_add_timer(&ngx_reap_pid_event, 1000); + } + #if (NGX_HTTP_LUA_HAVE_SIGNALFD) if (sigemptyset(&set) != 0) { ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno, @@ -353,11 +365,7 @@ static void ngx_http_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_http_lua_pipe_node_t *pipe_node; ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0, "lua pipe reaping children"); @@ -379,75 +387,99 @@ ngx_http_lua_pipe_sigchld_event_handler(ngx_event_t *ev) break; } - for ( ;; ) { - pid = waitpid(-1, &status, WNOHANG); + ngx_http_lua_pipe_reap_pids(ev); + } +} - if (pid == 0) { - break; - } - if (pid < 0) { - if (ngx_errno != NGX_ECHILD) { - ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, - "lua pipe waitpid failed"); - } +static void +ngx_http_lua_pipe_reap_pids(ngx_event_t *ev) +{ + int status; + ngx_pid_t pid; + ngx_rbtree_node_t *node; + ngx_http_lua_pipe_node_t *pipe_node; - break; - } + for ( ;; ) { + pid = waitpid(-1, &status, WNOHANG); - /* 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, - "signal %d (SIGCHLD) received from %P", - SIGCHLD, pid); + if (pid == 0) { + break; + } - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "lua pipe SIGCHLD fd read pid:%P status:%d", pid, - status); - - node = ngx_http_lua_pipe_lookup_pid(pid); - if (node != NULL) { - pipe_node = (ngx_http_lua_pipe_node_t *) &node->color; - if (pipe_node->wait_co_ctx != NULL) { - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "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); - } + if (pid < 0) { + if (ngx_errno != NGX_ECHILD) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, + "lua pipe waitpid failed"); + } - /* TODO: we should proactively close and free up the pipe after - * the user consume all the data in the pipe. - */ - pipe_node->proc->pipe->dead = 1; + break; + } - if (WIFSIGNALED(status)) { - pipe_node->status = WTERMSIG(status); - pipe_node->reason_code = REASON_SIGNAL_CODE; + /* 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, + "signal %d (SIGCHLD) received from %P", + SIGCHLD, pid); - } else if (WIFEXITED(status)) { - pipe_node->status = WEXITSTATUS(status); - pipe_node->reason_code = REASON_EXIT_CODE; + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe SIGCHLD fd read pid:%P status:%d", pid, + status); + + node = ngx_http_lua_pipe_lookup_pid(pid); + if (node != NULL) { + pipe_node = (ngx_http_lua_pipe_node_t *) &node->color; + if (pipe_node->wait_co_ctx != NULL) { + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "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); + } - } else { - ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, - "lua pipe unknown exit status %d from " - "process %P", status, pid); - pipe_node->status = status; - pipe_node->reason_code = REASON_UNKNOWN_CODE; - } + /* TODO: we should proactively close and free up the pipe after + * the user consume all the data in the pipe. + */ + 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, + "lua pipe unknown exit status %d from " + "process %P", status, pid); + pipe_node->status = status; + pipe_node->reason_code = REASON_UNKNOWN_CODE; } } } } +static void +ngx_http_lua_pipe_reap_timer_handler(ngx_event_t *ev) +{ + ngx_http_lua_pipe_reap_pids(ev); + + if (!ngx_exiting) { + ngx_add_timer(&ngx_reap_pid_event, 1000); + ngx_reap_pid_event.timedout = 0; + } +} + + static ssize_t ngx_http_lua_pipe_fd_read(ngx_connection_t *c, u_char *buf, size_t size) { From a31e9cf3377f2bfe0ddd18ccbf0b62b0baa47f30 Mon Sep 17 00:00:00 2001 From: jinhua luo Date: Tue, 1 Nov 2022 23:07:16 +0800 Subject: [PATCH 063/254] bugfix: avoid buf double free in ngx.print if lua body filter enabled (#2115) Fix #2110 Co-authored-by: lijunlong --- src/ngx_http_lua_bodyfilterby.c | 7 +++++-- t/185-ngx-buf-double-free.t | 25 +++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 t/185-ngx-buf-double-free.t diff --git a/src/ngx_http_lua_bodyfilterby.c b/src/ngx_http_lua_bodyfilterby.c index 632f5afea3..a8a382ac44 100644 --- a/src/ngx_http_lua_bodyfilterby.c +++ b/src/ngx_http_lua_bodyfilterby.c @@ -299,7 +299,7 @@ ngx_http_lua_body_filter(ngx_http_request_t *r, ngx_chain_t *in) out = NULL; ngx_chain_update_chains(r->pool, &ctx->free_bufs, &ctx->filter_busy_bufs, &out, - (ngx_buf_tag_t) &ngx_http_lua_module); + (ngx_buf_tag_t) &ngx_http_lua_body_filter); if (rc != NGX_OK && ctx->filter_busy_bufs != NULL && (r->connection->buffered @@ -378,7 +378,7 @@ ngx_http_lua_body_filter(ngx_http_request_t *r, ngx_chain_t *in) ngx_chain_update_chains(r->pool, &ctx->free_bufs, &ctx->filter_busy_bufs, &out, - (ngx_buf_tag_t) &ngx_http_lua_module); + (ngx_buf_tag_t) &ngx_http_lua_body_filter); return rc; } @@ -657,6 +657,7 @@ ngx_http_lua_body_filter_param_set(lua_State *L, ngx_http_request_t *r, return luaL_error(L, "no memory"); } + cl->buf->tag = (ngx_buf_tag_t) &ngx_http_lua_body_filter; if (type == LUA_TTABLE) { cl->buf->last = ngx_http_lua_copy_str_in_table(L, 3, cl->buf->last); @@ -674,6 +675,8 @@ ngx_http_lua_body_filter_param_set(lua_State *L, ngx_http_request_t *r, if (cl == NULL) { return luaL_error(L, "no memory"); } + + cl->buf->tag = (ngx_buf_tag_t) &ngx_http_lua_body_filter; } if (last) { diff --git a/t/185-ngx-buf-double-free.t b/t/185-ngx-buf-double-free.t new file mode 100644 index 0000000000..699083db27 --- /dev/null +++ b/t/185-ngx-buf-double-free.t @@ -0,0 +1,25 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use Test::Nginx::Socket 'no_plan'; + +repeat_each(2); + +run_tests(); + +__DATA__ + +=== TEST 1: one buf was linked to multiple ngx_chain_t nodes +--- config + location /t { + content_by_lua_block { + local str = string.rep(".", 1300) + ngx.print(str) + ngx.flush() + ngx.print("small chunk") + ngx.flush() + } + body_filter_by_lua_block {local dummy=1} + } +--- request +GET /t +--- response_body_like: small chunk From 0499e844305807b1126f5aaf1080bdf3ca9bbd87 Mon Sep 17 00:00:00 2001 From: Marcelo Parada Date: Wed, 2 Nov 2022 16:14:11 +0100 Subject: [PATCH 064/254] doc: add link to pre-defined Nginx variables (#2116) Closes Issue #2111 --- README.markdown | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index 860ec0084a..d85c6b6628 100644 --- a/README.markdown +++ b/README.markdown @@ -3838,7 +3838,8 @@ For example: } ``` -That is, Nginx variables cannot be created on-the-fly. +That is, Nginx variables cannot be created on-the-fly. Here is a list of pre-defined +[Nginx variables](http://nginx.org/en/docs/varindex.html). Some special Nginx variables like `$args` and `$limit_rate` can be assigned a value, many others are not, like `$query_string`, `$arg_PARAMETER`, and `$http_NAME`. From 56347d174dc3ca296fc436477a250f28f8bda84f Mon Sep 17 00:00:00 2001 From: lijunlong Date: Thu, 3 Nov 2022 09:15:01 +0800 Subject: [PATCH 065/254] tests: upgrade openssl to 1.1.1s. (#2117) --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 9c579ab75d..b651b525cd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -52,7 +52,7 @@ env: - TEST_NGINX_SLEEP=0.006 jobs: - NGINX_VERSION=1.21.4 OPENSSL_VER=1.1.0l OPENSSL_PATCH_VER=1.1.0d - - NGINX_VERSION=1.21.4 OPENSSL_VER=1.1.1p OPENSSL_PATCH_VER=1.1.1f + - NGINX_VERSION=1.21.4 OPENSSL_VER=1.1.1s OPENSSL_PATCH_VER=1.1.1f services: - memcached From 6e3b1c4fde47039f0ce2ee75fc678dab27944667 Mon Sep 17 00:00:00 2001 From: jinhua luo Date: Sun, 6 Nov 2022 09:39:13 +0800 Subject: [PATCH 066/254] bugfix: define busy_bufs per cosocket (#2119) Fix #2099 --- src/ngx_http_lua_socket_tcp.c | 2 +- src/ngx_http_lua_socket_tcp.h | 2 + t/186-cosocket-busy-bufs.t | 81 +++++++++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 t/186-cosocket-busy-bufs.t diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index e40ecbb537..d880377e4b 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -3457,7 +3457,7 @@ ngx_http_lua_socket_send(ngx_http_request_t *r, ngx_chain_update_chains(r->pool, - &ctx->free_bufs, &ctx->busy_bufs, + &ctx->free_bufs, &u->busy_bufs, &u->request_bufs, (ngx_buf_tag_t) &ngx_http_lua_module); diff --git a/src/ngx_http_lua_socket_tcp.h b/src/ngx_http_lua_socket_tcp.h index ee9411bc8d..0cc6641538 100644 --- a/src/ngx_http_lua_socket_tcp.h +++ b/src/ngx_http_lua_socket_tcp.h @@ -125,6 +125,8 @@ struct ngx_http_lua_socket_tcp_upstream_s { int openssl_error_code_ret; #endif + ngx_chain_t *busy_bufs; + unsigned ft_type:16; unsigned no_close:1; unsigned conn_waiting:1; diff --git a/t/186-cosocket-busy-bufs.t b/t/186-cosocket-busy-bufs.t new file mode 100644 index 0000000000..03afe58fc0 --- /dev/null +++ b/t/186-cosocket-busy-bufs.t @@ -0,0 +1,81 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use Test::Nginx::Socket 'no_plan'; +use Test::Nginx::Socket::Lua::Stream; + +log_level('warn'); +repeat_each(2); +run_tests(); + +__DATA__ + +=== TEST 1: ngx.say and cosocket +--- stream_server_config + content_by_lua_block { + local sock = assert(ngx.req.socket(true)) + sock:settimeout(1000) + while true do + local data = sock:receive(5) + if not data then + return + end + ngx.print(data) + ngx.flush(true) + end + } +--- config + location /test { + content_by_lua_block { + ngx.say("hello") + --ngx.flush(true) + + local sock = ngx.socket.tcp() + local ok, err = sock:connect("127.0.0.1", 1985) + assert(ok) + + local last_duration = 0 + local cnt = 0 + local t1, t2 + local err_cnt = 0 + local ERR_THRESHOLD_MS = 100 + + for i = 1,100000 do + if cnt == 0 then + ngx.update_time() + t1 = ngx.now() + end + + cnt = cnt + 1 + + local sent = sock:send("hello") + local data = sock:receive(5) + assert(data=="hello") + + if cnt == 1000 then + cnt = 0 + ngx.update_time() + t2 = ngx.now() + local duration = (t2 - t1) * 1000 + if last_duration > 0 and (duration - last_duration) > ERR_THRESHOLD_MS then + if err_cnt >= 3 then + ngx.log(ngx.ERR, + "more than ", err_cnt, " times, duration larger than ", + ERR_THRESHOLD_MS, " ms, ", + "last_duration: ", math.floor(duration), " ms") + return ngx.exit(500) + end + err_cnt = err_cnt + 1 + end + last_duration = duration + end + end + + sock:close() + ngx.exit(200) + } + } +--- no_error_log +[error] +--- timeout: 30 +--- request +GET /test From 4045ea8eb72c792de8465dfa6c9bbc638ff96bb8 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Fri, 9 Dec 2022 20:29:45 +0800 Subject: [PATCH 067/254] tests: test failed when running in randmonize mode. For example: TEST_NGINX_RANDOMIZE=1 prove -j8 -r -I. t/ --- t/086-init-by.t | 2 +- t/124-init-worker.t | 7 ++++++- t/162-exit-worker.t | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/t/086-init-by.t b/t/086-init-by.t index a998fc53d6..04f8160eb1 100644 --- a/t/086-init-by.t +++ b/t/086-init-by.t @@ -362,6 +362,6 @@ no_such_error_log --- must_die --- error_log eval -qr|init_by_lua_file error: .*lua-nginx-module/t/servroot/html/init.lua:3: '\)' expected \(to close '\(' at line 2\) near 'ngx'| +qr|init_by_lua_file error: .*?/t/servroot\w*?/html/init.lua:3: '\)' expected \(to close '\(' at line 2\) near 'ngx'| --- no_error_log no_such_error_log diff --git a/t/124-init-worker.t b/t/124-init-worker.t index d06ec9937b..57df4a5b3b 100644 --- a/t/124-init-worker.t +++ b/t/124-init-worker.t @@ -842,6 +842,11 @@ lua close the global Lua VM \3 in the cache helper process \d+ lua close the global Lua VM \3 lua close the global Lua VM \3 in the cache helper process \d+ )(?:lua close the global Lua VM [0-9A-F]+ +|lua close the global Lua VM ([0-9A-F]+) +lua close the global Lua VM \4 in the cache helper process \d+ +lua close the global Lua VM \4 in the cache helper process \d+ +lua close the global Lua VM \4 +lua close the global Lua VM \4 )*\z/ --- no_error_log [error] @@ -1022,6 +1027,6 @@ no_such_error_log --- response_body hello world --- error_log eval -qr|init_worker_by_lua_file error: .*lua-nginx-module/t/servroot/html/init.lua:3: '\)' expected \(to close '\(' at line 2\) near 'ngx'| +qr|init_worker_by_lua_file error: .*?t/servroot\w*/html/init.lua:3: '\)' expected \(to close '\(' at line 2\) near 'ngx'| --- no_error_log no_such_error_log diff --git a/t/162-exit-worker.t b/t/162-exit-worker.t index 60145ee737..7aff2a619b 100644 --- a/t/162-exit-worker.t +++ b/t/162-exit-worker.t @@ -239,4 +239,4 @@ exit_worker_by_lua error: exit_worker_by_lua(nginx.conf:25):4: ')' expected (to --- response_body hello world --- shutdown_error_log eval -qr|exit_worker_by_lua_file error: .*lua-nginx-module/t/servroot/html/exit.lua:3: '\)' expected \(to close '\(' at line 2\) near 'ngx'| +qr|exit_worker_by_lua_file error: .*?t/servroot\w*/html/exit.lua:3: '\)' expected \(to close '\(' at line 2\) near 'ngx'| From 3f4005fa879fc2ed329275c47e238bff1f8b890e Mon Sep 17 00:00:00 2001 From: ZongRun <1181591811hzr@gmail.com> Date: Mon, 19 Dec 2022 19:15:38 +0800 Subject: [PATCH 068/254] bugfix: fix receiveuntil rest bytes count. Co-authored-by: timzrhuang --- src/ngx_http_lua_socket_tcp.c | 10 +++-- t/066-socket-receiveuntil.t | 81 ++++++++++++++++++++++++++++++++-- t/084-inclusive-receiveuntil.t | 5 +-- 3 files changed, 85 insertions(+), 11 deletions(-) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index d880377e4b..4ee1103103 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -4864,11 +4864,13 @@ ngx_http_lua_socket_read_until(void *data, ssize_t bytes) /* matched */ - dd("adding pending data: %.*s", (int) (old_state + 1 - state), + int pending_bytes = old_state + 1 - state; + + dd("adding pending data: %.*s", (int) pending_bytes, (char *) pat); rc = ngx_http_lua_socket_add_pending_data(r, u, b->pos, i, pat, - old_state + 1 - state, + pending_bytes, old_state); if (rc != NGX_OK) { @@ -4879,14 +4881,14 @@ ngx_http_lua_socket_read_until(void *data, ssize_t bytes) i++; if (u->length) { - if (u->rest <= (size_t) state) { + if (u->rest <= (size_t) pending_bytes) { u->rest = 0; cp->state = state; b->pos += i; return NGX_OK; } else { - u->rest -= state; + u->rest -= pending_bytes; } } diff --git a/t/066-socket-receiveuntil.t b/t/066-socket-receiveuntil.t index 89d2abf373..1182a536c1 100644 --- a/t/066-socket-receiveuntil.t +++ b/t/066-socket-receiveuntil.t @@ -1027,7 +1027,7 @@ close: 1 nil local reader = sock:receiveuntil("--abc") - for i = 1, 7 do + for i = 1, 6 do local line, err, part = reader(4) if line then ngx.say("read: ", line) @@ -1055,7 +1055,6 @@ read: hell read: o, w read: orld read: -- -read: failed to read a line: nil [nil] failed to read a line: closed [ ] @@ -1104,7 +1103,7 @@ close: 1 nil local reader = sock:receiveuntil("--abc") - for i = 1, 7 do + for i = 1, 6 do local line, err, part = reader(4) if line then ngx.say("read: ", line) @@ -1132,7 +1131,6 @@ read: hell read: o, w read: orld read: -- -read: failed to read a line: nil [nil] failed to read a line: closed [ ] @@ -1329,3 +1327,78 @@ this exposed a memory leak in receiveuntil ok --- no_error_log [error] + + + +=== TEST 20: add pending bytes +--- config + server_tokens off; + location /t { + set $port $TEST_NGINX_SERVER_PORT; + lua_socket_buffer_size 1; + + content_by_lua ' + -- collectgarbage("collect") + + local sock = ngx.socket.tcp() + local port = ngx.var.port + + local ok, err = sock:connect("127.0.0.1", port) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local req = "GET /foo HTTP/1.0\\r\\nHost: localhost\\r\\nConnection: close\\r\\n\\r\\n" + + local bytes, err = sock:send(req) + if not bytes then + ngx.say("failed to send request: ", err) + return + end + ngx.say("request sent: ", bytes) + + local read_headers = sock:receiveuntil("\\r\\n\\r\\n") + local headers, err, part = read_headers() + if not headers then + ngx.say("failed to read headers: ", err, " [", part, "]") + end + + local reader = sock:receiveuntil("--abc") + + for i = 1, 4 do + local line, err, part = reader(2) + if line then + ngx.say("read: ", line) + + else + ngx.say("failed to read a line: ", err, " [", part, "]") + end + end + + ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + '; + } + + location /foo { + echo -- -----abc; + more_clear_headers Date; + } +--- request +GET /t + +--- response_body eval +qq{connected: 1 +request sent: 57 +read: -- +read: - +failed to read a line: nil [nil] +failed to read a line: closed [ +] +close: 1 nil +} +--- no_error_log +[error] diff --git a/t/084-inclusive-receiveuntil.t b/t/084-inclusive-receiveuntil.t index 66be893d5c..eb5aa1ecdf 100644 --- a/t/084-inclusive-receiveuntil.t +++ b/t/084-inclusive-receiveuntil.t @@ -619,7 +619,7 @@ bad "inclusive" option value type: string local reader = sock:receiveuntil("--abc", { inclusive = true }) - for i = 1, 7 do + for i = 1, 6 do local line, err, part = reader(4) if line then ngx.say("read: ", line) @@ -646,8 +646,7 @@ request sent: 57 read: hell read: o, w read: orld -read: -- -read: --abc +read: ----abc failed to read a line: nil [nil] failed to read a line: closed [ ] From f488965b89238e0bba11c13fdb9b11b4a0f20d67 Mon Sep 17 00:00:00 2001 From: "Yu.Zhu" Date: Wed, 28 Dec 2022 20:12:00 +0800 Subject: [PATCH 069/254] feature: added HTTP 3.0 support to ngx.req.http_version(). --- src/ngx_http_lua_headers.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/ngx_http_lua_headers.c b/src/ngx_http_lua_headers.c index 8098615dfc..9d03f4ed40 100644 --- a/src/ngx_http_lua_headers.c +++ b/src/ngx_http_lua_headers.c @@ -84,6 +84,12 @@ ngx_http_lua_ngx_req_http_version(lua_State *L) break; #endif +#ifdef NGX_HTTP_VERSION_30 + case NGX_HTTP_VERSION_30: + lua_pushnumber(L, 3.0); + break; +#endif + default: lua_pushnil(L); break; From 81bc96401edadc4a306152eb0ecfd3e68c4ce429 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Fri, 13 Jan 2023 17:25:24 +0800 Subject: [PATCH 070/254] tests: fixed some test cases in t/129-ssl-socket.t t/162-socket-tls-handshake.t t/186-cosocket-busy-bufs.t. --- t/129-ssl-socket.t | 10 +++++----- t/162-socket-tls-handshake.t | 10 +++++----- t/186-cosocket-busy-bufs.t | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/t/129-ssl-socket.t b/t/129-ssl-socket.t index cbbd679468..81ca51ca41 100644 --- a/t/129-ssl-socket.t +++ b/t/129-ssl-socket.t @@ -39,7 +39,7 @@ run_tests(); __DATA__ -=== TEST 1: www.google.com +=== TEST 1: www.bing.com --- config server_tokens off; resolver $TEST_NGINX_RESOLVER ipv6=off; @@ -48,7 +48,7 @@ __DATA__ set $port $TEST_NGINX_MEMCACHED_PORT; content_by_lua ' - -- avoid flushing google in "check leak" testing mode: + -- avoid flushing bing in "check leak" testing mode: local counter = package.loaded.counter if not counter then counter = 1 @@ -62,7 +62,7 @@ __DATA__ do local sock = ngx.socket.tcp() sock:settimeout(2000) - local ok, err = sock:connect("www.google.com", 443) + local ok, err = sock:connect("www.bing.com", 443) if not ok then ngx.say("failed to connect: ", err) return @@ -78,7 +78,7 @@ __DATA__ ngx.say("ssl handshake: ", type(sess)) - local req = "GET / HTTP/1.1\\r\\nHost: www.google.com\\r\\nConnection: close\\r\\n\\r\\n" + local req = "GET / HTTP/1.1\\r\\nHost: www.bing.com\\r\\nConnection: close\\r\\n\\r\\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) @@ -107,7 +107,7 @@ GET /t --- response_body_like chop \Aconnected: 1 ssl handshake: cdata -sent http request: 59 bytes. +sent http request: 57 bytes. received: HTTP/1.1 (?:200 OK|302 Found) close: 1 nil \z diff --git a/t/162-socket-tls-handshake.t b/t/162-socket-tls-handshake.t index 4474895c53..80fb2f9825 100644 --- a/t/162-socket-tls-handshake.t +++ b/t/162-socket-tls-handshake.t @@ -63,14 +63,14 @@ run_tests(); __DATA__ -=== TEST 1: sanity: www.google.com +=== TEST 1: sanity: www.bing.com --- config server_tokens off; resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { content_by_lua_block { - -- avoid flushing google in "check leak" testing mode: + -- avoid flushing bing in "check leak" testing mode: local counter = package.loaded.counter if not counter then counter = 1 @@ -86,7 +86,7 @@ __DATA__ local sock = ngx.socket.tcp() sock:settimeout(2000) - local ok, err = sock:connect("www.google.com", 443) + local ok, err = sock:connect("www.bing.com", 443) if not ok then ngx.say("failed to connect: ", err) return @@ -102,7 +102,7 @@ __DATA__ ngx.say("ssl handshake: ", type(sess)) - local req = "GET / HTTP/1.1\r\nHost: www.google.com\r\nConnection: close\r\n\r\n" + local req = "GET / HTTP/1.1\r\nHost: www.bing.com\r\nConnection: close\r\n\r\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) @@ -131,7 +131,7 @@ GET /t --- response_body_like chop \Aconnected: 1 ssl handshake: cdata -sent http request: 59 bytes. +sent http request: 57 bytes. received: HTTP/1.1 (?:200 OK|302 Found) close: 1 nil \z diff --git a/t/186-cosocket-busy-bufs.t b/t/186-cosocket-busy-bufs.t index 03afe58fc0..e50f62d9ee 100644 --- a/t/186-cosocket-busy-bufs.t +++ b/t/186-cosocket-busy-bufs.t @@ -30,7 +30,7 @@ __DATA__ --ngx.flush(true) local sock = ngx.socket.tcp() - local ok, err = sock:connect("127.0.0.1", 1985) + local ok, err = sock:connect("127.0.0.1", ngx.var.server_port + 1) assert(ok) local last_duration = 0 From 47f0a367626eefe912482fd931637d2e3b0d0374 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Fri, 13 Jan 2023 17:49:22 +0800 Subject: [PATCH 071/254] bugfix: cosocket did not exit when worker_shutdown_timeout handler is called. --- .travis.yml | 1 + src/ngx_http_lua_socket_tcp.c | 8 ++++++ t/014-bugs.t | 46 ++++++++++++++++++++++++++++++++++- util/nc_server.py | 25 +++++++++++++++++++ 4 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 util/nc_server.py diff --git a/.travis.yml b/.travis.yml index b651b525cd..54f2ab5b17 100644 --- a/.travis.yml +++ b/.travis.yml @@ -135,6 +135,7 @@ script: - rm -fr buildroot - sh util/build.sh $NGINX_VERSION > build.log 2>&1 || (cat build.log && exit 1) - nginx -V + - python3 ./util/nc_server.py & - ldd `which nginx`|grep -E 'luajit|ssl|pcre' - export LD_PRELOAD=$PWD/mockeagain/mockeagain.so - export LD_LIBRARY_PATH=$PWD/mockeagain:$LD_LIBRARY_PATH diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 4ee1103103..89fa133d28 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -2535,6 +2535,14 @@ ngx_http_lua_socket_tcp_read(ngx_http_request_t *r, "lua tcp socket read data: wait:%d", (int) u->read_waiting); + /* ngx_shutdown_timer_handler will set c->close and c->error on timeout + * when worker_shutdown_timeout is configured. + * The rev->ready is false at that time, so we need to set u->eof. + */ + if (c->close && c->error) { + u->eof = 1; + } + b = &u->buffer; read = 0; diff --git a/t/014-bugs.t b/t/014-bugs.t index 8c93920bc7..bfc86c9e9a 100644 --- a/t/014-bugs.t +++ b/t/014-bugs.t @@ -8,7 +8,8 @@ log_level('debug'); repeat_each(3); -plan tests => repeat_each() * (blocks() * 2 + 33); +# NB: the shutdown_error_log block is independent from repeat times +plan tests => repeat_each() * (blocks() * 2 + 33) + 1; our $HtmlDir = html_dir; #warn $html_dir; @@ -1239,3 +1240,46 @@ res: true --- must_die --- error_log eval qr/\[emerg\] \d+#\d+: unexpected "A" in/ + + + +=== TEST 47: cosocket does not exit on worker_shutdown_timeout +--- main_config +worker_shutdown_timeout 1; +--- config +location /t { + content_by_lua_block { + local function thread_func() + local sock = ngx.socket.tcp() + local ok, err = sock:connect("127.0.0.1", 65110) + local bytes, err = sock:send("hello") + if bytes ~= 5 then + sock:close() + return ngx.exit(500) + end + + local data, err = sock:receive(20) + local line, err, partial = sock:receive() + if not line then + ngx.log(ngx.ERR, "failed to read a line: ", err) + return + end + + ngx.log(ngx.ERR, "successfully read a line: ", line) + end + + local function timer_func() + ngx.thread.spawn(thread_func) + end + + ngx.timer.at(1, timer_func) + ngx.say("Hello world") + } +} +--- request + GET /t +--- response_body +Hello world +--- shutdown_error_log eval +qr|failed to read a line: closed| +--- timeout: 1.2 diff --git a/util/nc_server.py b/util/nc_server.py new file mode 100644 index 0000000000..48c6f4bf15 --- /dev/null +++ b/util/nc_server.py @@ -0,0 +1,25 @@ +import select, socket +server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +server.setblocking(0) +server.bind(('localhost', 65110)) +server.listen(5) +inputs = [server] + +while inputs: + outputs = [] + readable, writable, exceptional = select.select( + inputs, outputs, inputs) + for s in readable: + if s is server: + connection, client_address = s.accept() + connection.setblocking(0) + inputs.append(connection) + else: + data = s.recv(1024) + if not data: + inputs.remove(s) + s.close() + + for s in exceptional: + inputs.remove(s) + s.close() From 1a485992435771f354c09330c2706d53c8d9cbf4 Mon Sep 17 00:00:00 2001 From: jiahao Date: Thu, 19 Jan 2023 12:40:11 +0800 Subject: [PATCH 072/254] bumped the lua version to 0.10.23. --- src/api/ngx_http_lua_api.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/ngx_http_lua_api.h b/src/api/ngx_http_lua_api.h index a1ef1f7cb1..664698a727 100644 --- a/src/api/ngx_http_lua_api.h +++ b/src/api/ngx_http_lua_api.h @@ -19,7 +19,7 @@ /* Public API for other Nginx modules */ -#define ngx_http_lua_version 10022 +#define ngx_http_lua_version 10023 typedef struct { From 992bfc352a25cd7da25f86dc203f0dd6a3cd7926 Mon Sep 17 00:00:00 2001 From: ZongRun <1181591811hzr@gmail.com> Date: Fri, 27 Jan 2023 14:03:46 +0800 Subject: [PATCH 073/254] style: use forward declaration. Co-authored-by: timzrhuang --- src/ngx_http_lua_socket_tcp.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 89fa133d28..dcd27dc174 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -4744,6 +4744,7 @@ ngx_http_lua_socket_read_until(void *data, ssize_t bytes) u_char c; u_char *pat; size_t pat_len; + size_t pending_len; int i; int state; int old_state = 0; /* just to make old @@ -4872,13 +4873,12 @@ ngx_http_lua_socket_read_until(void *data, ssize_t bytes) /* matched */ - int pending_bytes = old_state + 1 - state; + pending_len = old_state + 1 - state; - dd("adding pending data: %.*s", (int) pending_bytes, - (char *) pat); + dd("adding pending data: %.*s", (int) pending_len, (char *) pat); rc = ngx_http_lua_socket_add_pending_data(r, u, b->pos, i, pat, - pending_bytes, + pending_len, old_state); if (rc != NGX_OK) { @@ -4889,14 +4889,14 @@ ngx_http_lua_socket_read_until(void *data, ssize_t bytes) i++; if (u->length) { - if (u->rest <= (size_t) pending_bytes) { + if (u->rest <= pending_len) { u->rest = 0; cp->state = state; b->pos += i; return NGX_OK; } else { - u->rest -= pending_bytes; + u->rest -= pending_len; } } From a6ee03abaaf1dd08e12a0292f60618d15623e0c7 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Mon, 6 Feb 2023 11:14:24 +0800 Subject: [PATCH 074/254] bugfix: cleanup of http request will not be callled for the request created by ngx_http_lua_create_fake_request. --- src/ngx_http_lua_pipe.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ngx_http_lua_pipe.c b/src/ngx_http_lua_pipe.c index 465d2bff69..8c0884bcc2 100644 --- a/src/ngx_http_lua_pipe.c +++ b/src/ngx_http_lua_pipe.c @@ -620,7 +620,7 @@ ngx_http_lua_ffi_pipe_spawn(ngx_http_request_t *r, ngx_http_lua_pipe_node_t *pipe_node; struct sigaction sa; ngx_http_lua_pipe_signal_t *sig; - ngx_http_cleanup_t *cln; + ngx_pool_cleanup_t *cln; sigset_t set; pool_size = ngx_align(NGX_MIN_POOL_SIZE + buffer_size * 2, @@ -909,7 +909,7 @@ ngx_http_lua_ffi_pipe_spawn(ngx_http_request_t *r, } if (pp->cleanup == NULL) { - cln = ngx_http_lua_cleanup_add(r, 0); + cln = ngx_pool_cleanup_add(r->pool, 0); if (cln == NULL) { *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "no memory") @@ -917,7 +917,7 @@ ngx_http_lua_ffi_pipe_spawn(ngx_http_request_t *r, goto close_in_out_err_fd; } - cln->handler = (ngx_http_cleanup_pt) ngx_http_lua_ffi_pipe_proc_destroy; + cln->handler = (ngx_pool_cleanup_pt) ngx_http_lua_ffi_pipe_proc_destroy; cln->data = proc; pp->cleanup = &cln->handler; pp->r = r; From 5e05fa3adb0d2492ecaaf2cb76498e23765aa6ab Mon Sep 17 00:00:00 2001 From: lijunlong Date: Mon, 6 Feb 2023 15:15:47 +0800 Subject: [PATCH 075/254] tests: cross requests cosocket can only be use one time. tests: cross requests cosocket can only be use one time. cross request cosocket can not be reuese after connect(). --- t/168-tcp-socket-bind.t | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/t/168-tcp-socket-bind.t b/t/168-tcp-socket-bind.t index 6aca00c51e..a2aa50b4e7 100644 --- a/t/168-tcp-socket-bind.t +++ b/t/168-tcp-socket-bind.t @@ -314,12 +314,10 @@ failed to bind: bad address local function tcp() local sock = ngx.socket.tcp() - ---[[ local ok, err = sock:bind("127.0.0.1") if not ok then ngx.log(ngx.ERR, "failed to bind") end - --]] package.loaded.share_sock = sock end @@ -340,17 +338,25 @@ failed to bind: bad address ngx.sleep(0.002) local sock = package.loaded.share_sock - - local ok, err = sock:connect("127.0.0.1", port) - if not ok then - ngx.say("failed to connect: ", err) - return + if sock ~= nil then + package.loaded.share_sock = nil + + local ok, err = sock:connect("127.0.0.1", port) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + sock:close() + collectgarbage("collect") + else + -- the sock from package.loaded.share_sock is just + -- for the first request after worker init + -- add following code to keep the same result for other request + ngx.say("connected: ", 1) end - - ngx.say("connected: ", ok) - - sock:close() - collectgarbage("collect") } } --- request From 6dbc4e1bd799c254f258687566fd899c322388c7 Mon Sep 17 00:00:00 2001 From: Johnny Wang Date: Wed, 22 Feb 2023 15:20:51 +0800 Subject: [PATCH 076/254] tests: use the specified perl to execute cpanm. (#2157) --- .travis.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 54f2ab5b17..a3dc4d2ffd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -64,8 +64,7 @@ before_install: - sudo apt install --only-upgrade ca-certificates - '! grep -n -P ''(?<=.{80}).+'' --color `find src -name ''*.c''` `find . -name ''*.h''` || (echo "ERROR: Found C source lines exceeding 80 columns." > /dev/stderr; exit 1)' - '! grep -n -P ''\t+'' --color `find src -name ''*.c''` `find . -name ''*.h''` || (echo "ERROR: Cannot use tabs." > /dev/stderr; exit 1)' - - sudo cpanm --notest Test::Nginx IPC::Run > build.log 2>&1 || (cat build.log && exit 1) - + - /usr/bin/env perl $(command -v cpanm) --sudo --notest Test::Nginx IPC::Run > build.log 2>&1 || (cat build.log && exit 1) install: - if [ ! -f download-cache/drizzle7-$DRIZZLE_VER.tar.gz ]; then wget -P download-cache http://openresty.org/download/drizzle7-$DRIZZLE_VER.tar.gz; fi - if [ ! -f download-cache/pcre-$PCRE_VER.tar.gz ]; then wget -P download-cache https://downloads.sourceforge.net/project/pcre/pcre/${PCRE_VER}/pcre-${PCRE_VER}.tar.gz; fi @@ -143,4 +142,4 @@ script: - dig +short myip.opendns.com @resolver1.opendns.com || exit 0 - dig +short @$TEST_NGINX_RESOLVER openresty.org || exit 0 - dig +short @$TEST_NGINX_RESOLVER agentzh.org || exit 0 - - prove -I. -Itest-nginx/lib -r t/ + - /usr/bin/env perl $(command -v prove) -I. -Itest-nginx/lib -r t/ From 14be603805c4273852c4076293261416b18b6392 Mon Sep 17 00:00:00 2001 From: Chrono Date: Tue, 28 Feb 2023 16:08:25 +0800 Subject: [PATCH 077/254] doc: setoption is already available now. --- README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index d85c6b6628..a8044cfe7c 100644 --- a/README.markdown +++ b/README.markdown @@ -8200,7 +8200,7 @@ tcpsock:setoption **context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_client_hello_by_lua** -This function is added for [LuaSocket](http://w3.impa.br/~diego/software/luasocket/tcp.html) API compatibility and does nothing for now. Its functionality is implemented `v0.10.18`. +This function is added for [LuaSocket](http://w3.impa.br/~diego/software/luasocket/tcp.html) API compatibility, its functionality is implemented `v0.10.18`. This feature was first introduced in the `v0.5.0rc1` release. From 6f7a9a3305ae2fa60e6c8472bb18d2a510fa9f58 Mon Sep 17 00:00:00 2001 From: Xiaobo Liu Date: Mon, 27 Dec 2021 08:43:18 +0800 Subject: [PATCH 078/254] feature: add four new apis to manipulate the coctx. ngx_http_lua_co_ctx_t *ngx_http_lua_get_cur_co_ctx(ngx_http_request_t *r); void ngx_http_lua_set_cur_co_ctx(ngx_http_request_t *r, ngx_http_lua_co_ctx_t *coctx); lua_State *ngx_http_lua_get_co_ctx_vm(ngx_http_lua_co_ctx_t *coctx); void ngx_http_lua_co_ctx_resume_helper(ngx_http_lua_co_ctx_t *coctx, int nrets); --- src/api/ngx_http_lua_api.h | 12 ++++ src/ngx_http_lua_api.c | 116 +++++++++++++++++++++++++++++++++++++ src/ngx_http_lua_common.h | 1 + 3 files changed, 129 insertions(+) diff --git a/src/api/ngx_http_lua_api.h b/src/api/ngx_http_lua_api.h index 664698a727..ebe971054a 100644 --- a/src/api/ngx_http_lua_api.h +++ b/src/api/ngx_http_lua_api.h @@ -22,6 +22,9 @@ #define ngx_http_lua_version 10023 +typedef struct ngx_http_lua_co_ctx_s ngx_http_lua_co_ctx_t; + + typedef struct { uint8_t type; @@ -56,6 +59,15 @@ ngx_shm_zone_t *ngx_http_lua_find_zone(u_char *name_data, size_t name_len); ngx_shm_zone_t *ngx_http_lua_shared_memory_add(ngx_conf_t *cf, ngx_str_t *name, size_t size, void *tag); +ngx_http_lua_co_ctx_t *ngx_http_lua_get_cur_co_ctx(ngx_http_request_t *r); + +void ngx_http_lua_set_cur_co_ctx(ngx_http_request_t *r, + ngx_http_lua_co_ctx_t *coctx); + +lua_State *ngx_http_lua_get_co_ctx_vm(ngx_http_lua_co_ctx_t *coctx); + +void ngx_http_lua_co_ctx_resume_helper(ngx_http_lua_co_ctx_t *coctx, int nrets); + #endif /* _NGX_HTTP_LUA_API_H_INCLUDED_ */ diff --git a/src/ngx_http_lua_api.c b/src/ngx_http_lua_api.c index b69d627dce..0f643c77d6 100644 --- a/src/ngx_http_lua_api.c +++ b/src/ngx_http_lua_api.c @@ -213,4 +213,120 @@ ngx_http_lua_shared_memory_init(ngx_shm_zone_t *shm_zone, void *data) return NGX_OK; } + +ngx_http_lua_co_ctx_t * +ngx_http_lua_get_cur_co_ctx(ngx_http_request_t *r) +{ + ngx_http_lua_ctx_t *ctx; + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + + return ctx->cur_co_ctx; +} + + +void +ngx_http_lua_set_cur_co_ctx(ngx_http_request_t *r, ngx_http_lua_co_ctx_t *coctx) +{ + ngx_http_lua_ctx_t *ctx; + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + + coctx->data = r; + + ctx->cur_co_ctx = coctx; +} + + +lua_State * +ngx_http_lua_get_co_ctx_vm(ngx_http_lua_co_ctx_t *coctx) +{ + return coctx->co; +} + + +static ngx_int_t +ngx_http_lua_co_ctx_resume(ngx_http_request_t *r) +{ + lua_State *vm; + ngx_connection_t *c; + ngx_int_t rc; + ngx_uint_t nreqs; + ngx_http_lua_ctx_t *ctx; + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx == NULL) { + return NGX_ERROR; + } + + ctx->resume_handler = ngx_http_lua_wev_handler; + + c = r->connection; + vm = ngx_http_lua_get_lua_vm(r, ctx); + nreqs = c->requests; + + rc = ngx_http_lua_run_thread(vm, r, ctx, ctx->cur_co_ctx->nrets); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua run thread returned %d", rc); + + if (rc == NGX_AGAIN) { + return ngx_http_lua_run_posted_threads(c, vm, r, ctx, nreqs); + } + + if (rc == NGX_DONE) { + ngx_http_lua_finalize_request(r, NGX_DONE); + return ngx_http_lua_run_posted_threads(c, vm, r, ctx, nreqs); + } + + if (ctx->entered_content_phase) { + ngx_http_lua_finalize_request(r, rc); + return NGX_DONE; + } + + return rc; +} + + +void +ngx_http_lua_co_ctx_resume_helper(ngx_http_lua_co_ctx_t *coctx, int nrets) +{ + ngx_connection_t *c; + ngx_http_request_t *r; + ngx_http_lua_ctx_t *ctx; + ngx_http_log_ctx_t *log_ctx; + + r = coctx->data; + c = r->connection; + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + + if (ctx == NULL) { + return; + } + + if (c->fd != (ngx_socket_t) -1) { /* not a fake connection */ + log_ctx = c->log->data; + log_ctx->current_request = r; + } + + coctx->nrets = nrets; + coctx->cleanup = NULL; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, + "lua coctx resume handler: \"%V?%V\"", &r->uri, &r->args); + + ctx->cur_co_ctx = coctx; + + if (ctx->entered_content_phase) { + (void) ngx_http_lua_co_ctx_resume(r); + + } else { + ctx->resume_handler = ngx_http_lua_co_ctx_resume; + ngx_http_core_run_phases(r); + } + + ngx_http_run_posted_requests(c); +} + /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h index dafa729f8e..d977ee8e3f 100644 --- a/src/ngx_http_lua_common.h +++ b/src/ngx_http_lua_common.h @@ -497,6 +497,7 @@ struct ngx_http_lua_co_ctx_s { unsigned nresults_from_worker_thread; /* number of results * from worker * thread callback */ + unsigned nrets; /* ngx_http_lua_run_thread nrets arg. */ unsigned nsubreqs; /* number of subrequests of the * current request */ From 644b98faa508c4fd6d5870dece10b4bbb8579bd0 Mon Sep 17 00:00:00 2001 From: Xiaobo Liu Date: Fri, 25 Feb 2022 09:21:35 +0800 Subject: [PATCH 079/254] feature: introduced ngx_http_lua_get_lua_http10_buffering. --- src/api/ngx_http_lua_api.h | 2 ++ src/ngx_http_lua_api.c | 12 ++++++++++++ 2 files changed, 14 insertions(+) diff --git a/src/api/ngx_http_lua_api.h b/src/api/ngx_http_lua_api.h index ebe971054a..ba8772f770 100644 --- a/src/api/ngx_http_lua_api.h +++ b/src/api/ngx_http_lua_api.h @@ -68,6 +68,8 @@ lua_State *ngx_http_lua_get_co_ctx_vm(ngx_http_lua_co_ctx_t *coctx); void ngx_http_lua_co_ctx_resume_helper(ngx_http_lua_co_ctx_t *coctx, int nrets); +int ngx_http_lua_get_lua_http10_buffering(ngx_http_request_t *r); + #endif /* _NGX_HTTP_LUA_API_H_INCLUDED_ */ diff --git a/src/ngx_http_lua_api.c b/src/ngx_http_lua_api.c index 0f643c77d6..0d3ec9c988 100644 --- a/src/ngx_http_lua_api.c +++ b/src/ngx_http_lua_api.c @@ -329,4 +329,16 @@ ngx_http_lua_co_ctx_resume_helper(ngx_http_lua_co_ctx_t *coctx, int nrets) ngx_http_run_posted_requests(c); } + +int +ngx_http_lua_get_lua_http10_buffering(ngx_http_request_t *r) +{ + ngx_http_lua_loc_conf_t *llcf; + + llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); + + return llcf->http10_buffering; +} + + /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ From ce30e2fb0aa86f9c29d42f906192627a373af6e6 Mon Sep 17 00:00:00 2001 From: Johnny Wang Date: Tue, 7 Mar 2023 15:19:27 +0800 Subject: [PATCH 080/254] Revert "bugfix: doesn't set flags for Darwin arm64. (#2071)" (#2163) This reverts commit 1fd1e83c80612998647ee7ea933d3fdb2e9d9d9b. --- config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config b/config index c4068c852b..0e572c8bea 100644 --- a/config +++ b/config @@ -94,7 +94,7 @@ END case "$NGX_PLATFORM" in Darwin:*) case "$NGX_MACHINE" in - amd64 | arm64 | x86_64 | i386) + amd64 | x86_64 | i386) echo "adding extra linking options needed by LuaJIT on $NGX_MACHINE" luajit_ld_opt="$luajit_ld_opt -pagezero_size 10000 -image_base 100000000" ngx_feature_libs="$ngx_feature_libs -pagezero_size 10000 -image_base 100000000" From 74786af9540841a2a6c11e7352a28c6c198fb05b Mon Sep 17 00:00:00 2001 From: lijunlong Date: Thu, 9 Mar 2023 09:03:01 +0800 Subject: [PATCH 081/254] bugfix: windows does not support ngx_http_lua_ffi_worker_pids. --- .travis.yml | 1 + src/ngx_http_lua_socket_tcp.c | 6 +++--- src/ngx_http_lua_worker.c | 10 ++++++++-- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index a3dc4d2ffd..a547a1d60e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -65,6 +65,7 @@ before_install: - '! grep -n -P ''(?<=.{80}).+'' --color `find src -name ''*.c''` `find . -name ''*.h''` || (echo "ERROR: Found C source lines exceeding 80 columns." > /dev/stderr; exit 1)' - '! grep -n -P ''\t+'' --color `find src -name ''*.c''` `find . -name ''*.h''` || (echo "ERROR: Cannot use tabs." > /dev/stderr; exit 1)' - /usr/bin/env perl $(command -v cpanm) --sudo --notest Test::Nginx IPC::Run > build.log 2>&1 || (cat build.log && exit 1) + - pyenv global 2.7 install: - if [ ! -f download-cache/drizzle7-$DRIZZLE_VER.tar.gz ]; then wget -P download-cache http://openresty.org/download/drizzle7-$DRIZZLE_VER.tar.gz; fi - if [ ! -f download-cache/pcre-$PCRE_VER.tar.gz ]; then wget -P download-cache https://downloads.sourceforge.net/project/pcre/pcre/${PCRE_VER}/pcre-${PCRE_VER}.tar.gz; fi diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index dcd27dc174..6d5c3d48c5 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -6483,7 +6483,7 @@ ngx_http_lua_ffi_socket_tcp_getoption(ngx_http_lua_socket_tcp_upstream_t *u, fd = u->peer.connection->fd; - if (fd == (ngx_socket_t) -1) { + if (fd == (int) -1) { *errlen = ngx_snprintf(err, *errlen, "invalid socket fd") - err; return NGX_ERROR; } @@ -6540,7 +6540,7 @@ ngx_http_lua_ffi_socket_tcp_setoption(ngx_http_lua_socket_tcp_upstream_t *u, fd = u->peer.connection->fd; - if (fd == (ngx_socket_t) -1) { + if (fd == (int) -1) { *errlen = ngx_snprintf(err, *errlen, "invalid socket fd") - err; return NGX_ERROR; } @@ -6601,7 +6601,7 @@ ngx_http_lua_ffi_socket_tcp_hack_fd(ngx_http_lua_socket_tcp_upstream_t *u, } rc = u->peer.connection->fd; - if (rc == (ngx_socket_t) -1) { + if (rc == (int) -1) { *errlen = ngx_snprintf(err, *errlen, "invalid socket fd") - err; return -1; } diff --git a/src/ngx_http_lua_worker.c b/src/ngx_http_lua_worker.c index 52ec34a844..6870495a1b 100644 --- a/src/ngx_http_lua_worker.c +++ b/src/ngx_http_lua_worker.c @@ -8,7 +8,10 @@ #define DDEBUG 0 #endif #include "ddebug.h" + +#if !(NGX_WIN32) #include +#endif #define NGX_PROCESS_PRIVILEGED_AGENT 99 @@ -21,13 +24,15 @@ ngx_http_lua_ffi_worker_pid(void) } +#if !(NGX_WIN32) int ngx_http_lua_ffi_worker_pids(int *pids, size_t *pids_len) { - ngx_int_t i, n; + size_t n; + ngx_int_t i; n = 0; - for (i = 0; i < NGX_MAX_PROCESSES; i++) { + for (i = 0; n < *pids_len && i < NGX_MAX_PROCESSES; i++) { if (i != ngx_process_slot && ngx_processes[i].pid == 0) { break; } @@ -49,6 +54,7 @@ ngx_http_lua_ffi_worker_pids(int *pids, size_t *pids_len) return NGX_OK; } +#endif int From 1953052a026eeec5dae9af96cc189d8725d72a5e Mon Sep 17 00:00:00 2001 From: lijunlong Date: Thu, 9 Mar 2023 16:32:17 +0800 Subject: [PATCH 082/254] bugfix: fixed warning of signed and unsigned. Signed-off-by: lijunlong --- src/ngx_http_lua_headers.c | 6 ++++-- src/ngx_http_lua_shdict.c | 11 +++++++---- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/ngx_http_lua_headers.c b/src/ngx_http_lua_headers.c index 9d03f4ed40..a2ce6e1452 100644 --- a/src/ngx_http_lua_headers.c +++ b/src/ngx_http_lua_headers.c @@ -1250,8 +1250,10 @@ ngx_http_lua_ngx_raw_header_cleanup(void *data) int ngx_http_lua_ffi_set_resp_header_macos(ngx_http_lua_set_resp_header_params_t *p) { - return ngx_http_lua_ffi_set_resp_header(p->r, p->key_data, p->key_len, - p->is_nil, p->sval, p->sval_len, + return ngx_http_lua_ffi_set_resp_header(p->r, (const u_char *) p->key_data, + p->key_len, p->is_nil, + (const u_char *) p->sval, + p->sval_len, p->mvals, p->mvals_len, p->override, p->errmsg); } diff --git a/src/ngx_http_lua_shdict.c b/src/ngx_http_lua_shdict.c index 27f3b100f3..2e0b044065 100644 --- a/src/ngx_http_lua_shdict.c +++ b/src/ngx_http_lua_shdict.c @@ -2096,7 +2096,8 @@ ngx_http_lua_ffi_shdict_free_space(ngx_shm_zone_t *zone) int ngx_http_lua_ffi_shdict_get_macos(ngx_http_lua_shdict_get_params_t *p) { - return ngx_http_lua_ffi_shdict_get(p->zone, p->key, p->key_len, + return ngx_http_lua_ffi_shdict_get(p->zone, + (u_char *) p->key, p->key_len, p->value_type, p->str_value_buf, p->str_value_len, p->num_value, p->user_flags, p->get_stale, @@ -2107,8 +2108,10 @@ ngx_http_lua_ffi_shdict_get_macos(ngx_http_lua_shdict_get_params_t *p) int ngx_http_lua_ffi_shdict_store_macos(ngx_http_lua_shdict_store_params_t *p) { - return ngx_http_lua_ffi_shdict_store(p->zone, p->op, p->key, p->key_len, - p->value_type, p->str_value_buf, + return ngx_http_lua_ffi_shdict_store(p->zone, p->op, + (u_char *) p->key, p->key_len, + p->value_type, + (u_char *) p->str_value_buf, p->str_value_len, p->num_value, p->exptime, p->user_flags, p->errmsg, p->forcible); @@ -2118,7 +2121,7 @@ ngx_http_lua_ffi_shdict_store_macos(ngx_http_lua_shdict_store_params_t *p) int ngx_http_lua_ffi_shdict_incr_macos(ngx_http_lua_shdict_incr_params_t *p) { - return ngx_http_lua_ffi_shdict_incr(p->zone, p->key, p->key_len, + return ngx_http_lua_ffi_shdict_incr(p->zone, (u_char *) p->key, p->key_len, p->num_value, p->errmsg, p->has_init, p->init, p->init_ttl, p->forcible); From 9bee7e7890987d2641e2e16c4685d99d2b769948 Mon Sep 17 00:00:00 2001 From: "user.tax" Date: Sat, 11 Mar 2023 00:11:27 +0800 Subject: [PATCH 083/254] bugfix : comparison of integer expressions of different signedness. Signed-off-by: lijunlong --- src/ngx_http_lua_socket_tcp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 6d5c3d48c5..9391569529 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -1744,7 +1744,7 @@ ngx_http_lua_ffi_socket_tcp_sslhandshake(ngx_http_request_t *r, /* read rest of the chain */ - for (i = 1; i < sk_X509_num(chain); i++) { + for (i = 1; i < (ngx_int_t) sk_X509_num(chain); i++) { x509 = sk_X509_value(chain, i); if (x509 == NULL) { ERR_clear_error(); From ec6df3249a554ec67200857cb9de58814ca48dc5 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Mon, 20 Mar 2023 17:39:53 +0800 Subject: [PATCH 084/254] bugfix: windows also need to support ngx_http_lua_ffi_worker_pids. --- README.markdown | 2 +- src/ngx_http_lua_worker.c | 5 ++-- t/122-worker-2.t | 49 +++++++++++++++++++++++++++++++++ t/122-worker-3.t | 58 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 111 insertions(+), 3 deletions(-) create mode 100644 t/122-worker-2.t create mode 100644 t/122-worker-3.t diff --git a/README.markdown b/README.markdown index a8044cfe7c..c0d0c079d4 100644 --- a/README.markdown +++ b/README.markdown @@ -9034,7 +9034,7 @@ ngx.worker.pids **context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, exit_worker_by_lua** -This function returns a Lua table for all Nginx worker process ID (PID). Nginx uses channel to send the current worker PID to another worker in the worker process start or restart. So this API can get all current worker PID. +This function returns a Lua table for all Nginx worker process IDs (PIDs). Nginx uses channel to send the current worker PID to another worker in the worker process start or restart. So this API can get all current worker PIDs. Windows does not have this API. This API was first introduced in the `0.10.23` release. diff --git a/src/ngx_http_lua_worker.c b/src/ngx_http_lua_worker.c index 6870495a1b..5fdf0b4760 100644 --- a/src/ngx_http_lua_worker.c +++ b/src/ngx_http_lua_worker.c @@ -37,11 +37,12 @@ ngx_http_lua_ffi_worker_pids(int *pids, size_t *pids_len) break; } - if (i == ngx_process_slot && ngx_processes[i].pid == 0) { + /* The current process */ + if (i == ngx_process_slot) { pids[n++] = ngx_pid; } - if (ngx_processes[i].pid > 0) { + if (ngx_processes[i].channel[0] > 0 && ngx_processes[i].pid > 0) { pids[n++] = ngx_processes[i].pid; } } diff --git a/t/122-worker-2.t b/t/122-worker-2.t new file mode 100644 index 0000000000..c4ad2aea2a --- /dev/null +++ b/t/122-worker-2.t @@ -0,0 +1,49 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use Test::Nginx::Socket::Lua; + +#worker_connections(1014); +master_on(); +workers(4); +#log_level('warn'); + +repeat_each(2); + +plan tests => repeat_each() * (blocks() * 3); + +#no_diff(); +no_long_string(); +run_tests(); + +__DATA__ + +=== TEST 1: get worker pids with multiple worker +--- config + location /lua { + content_by_lua_block { + local pids, err = ngx.worker.pids() + if err ~= nil then + return + end + local pid = ngx.worker.pid() + ngx.say("worker pid: ", pid) + local count = ngx.worker.count() + ngx.say("worker count: ", count) + ngx.say("worker pids count: ", #pids) + for i = 1, count do + if pids[i] == pid then + ngx.say("worker pid is correct.") + return + end + end + } + } +--- request +GET /lua +--- response_body_like +worker pid: \d+ +worker count: 4 +worker pids count: 4 +worker pid is correct\. +--- no_error_log +[error] diff --git a/t/122-worker-3.t b/t/122-worker-3.t new file mode 100644 index 0000000000..050486e532 --- /dev/null +++ b/t/122-worker-3.t @@ -0,0 +1,58 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: +our $SkipReason; + +BEGIN { + if ($ENV{TEST_NGINX_CHECK_LEAK}) { + $SkipReason = "unavailable for the hup tests"; + + } else { + $ENV{TEST_NGINX_USE_HUP} = 1; + undef $ENV{TEST_NGINX_USE_STAP}; + } +} + +use Test::Nginx::Socket::Lua 'no_plan'; + +#worker_connections(1014); +master_on(); +workers(4); +#log_level('warn'); + +repeat_each(2); + +#no_diff(); +no_long_string(); +run_tests(); + +__DATA__ + +=== TEST 1: get worker pids with multiple worker +--- config + location /lua { + content_by_lua_block { + local pids, err = ngx.worker.pids() + if err ~= nil then + return + end + local pid = ngx.worker.pid() + ngx.say("worker pid: ", pid) + local count = ngx.worker.count() + ngx.say("worker count: ", count) + ngx.say("worker pids count: ", #pids) + for i = 1, count do + if pids[i] == pid then + ngx.say("worker pid is correct.") + return + end + end + } + } +--- request +GET /lua +--- response_body_like +worker pid: \d+ +worker count: 4 +worker pids count: 4 +worker pid is correct\. +--- no_error_log +[error] From 68acad14e4a8f42e31d4a4bb5ed44d6f5b55fc1c Mon Sep 17 00:00:00 2001 From: jiahao Date: Tue, 21 Mar 2023 21:51:04 +0800 Subject: [PATCH 085/254] bumped the lua version to 0.10.24. --- src/api/ngx_http_lua_api.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/ngx_http_lua_api.h b/src/api/ngx_http_lua_api.h index ba8772f770..018184990d 100644 --- a/src/api/ngx_http_lua_api.h +++ b/src/api/ngx_http_lua_api.h @@ -19,7 +19,7 @@ /* Public API for other Nginx modules */ -#define ngx_http_lua_version 10023 +#define ngx_http_lua_version 10024 typedef struct ngx_http_lua_co_ctx_s ngx_http_lua_co_ctx_t; From 39941d4c9a8f94191084800471f6433c757a90df Mon Sep 17 00:00:00 2001 From: lijunlong Date: Mon, 3 Apr 2023 08:44:36 +0800 Subject: [PATCH 086/254] tests: add two more test cases for body_filter_by_lua*. --- .travis.yml | 4 +- t/000--init.t | 2 +- t/082-body-filter-2.t | 154 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 158 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index a547a1d60e..1a051b7120 100644 --- a/.travis.yml +++ b/.travis.yml @@ -91,12 +91,13 @@ install: - git clone https://github.com/openresty/lua-resty-core.git ../lua-resty-core - git clone https://github.com/openresty/lua-resty-lrucache.git ../lua-resty-lrucache - git clone https://github.com/openresty/lua-resty-mysql.git ../lua-resty-mysql + - git clone https://github.com/spacewander/lua-resty-rsa.git ../lua-resty-rsa - git clone https://github.com/openresty/lua-resty-string.git ../lua-resty-string - git clone https://github.com/openresty/stream-lua-nginx-module.git ../stream-lua-nginx-module - git clone -b v2.1-agentzh https://github.com/openresty/luajit2.git luajit2 before_script: - - mysql -uroot -e 'create database ngx_test; grant all on ngx_test.* to "ngx_test"@"%" identified by "ngx_test"; flush privileges;' + - mysql -uroot -e "create database ngx_test; CREATE USER 'ngx_test'@'%' IDENTIFIED BY 'ngx_test'; grant all on ngx_test.* to 'ngx_test'@'%'; flush privileges;" script: - export PATH=$PWD/work/nginx/sbin:$PWD/openresty-devel-utils:$PATH @@ -106,6 +107,7 @@ script: - sudo iptables -I OUTPUT -p tcp --dst 127.0.0.2 --dport 12345 -j DROP - sudo iptables -I OUTPUT -p udp --dst 127.0.0.2 --dport 12345 -j DROP - sudo ip route add prohibit 0.0.0.1/32 + - sudo sysctl -w kernel.pid_max=10000 - cd luajit2/ - make -j$JOBS CCDEBUG=-g Q= PREFIX=$LUAJIT_PREFIX CC=$CC XCFLAGS='-DLUA_USE_APICHECK -DLUA_USE_ASSERT -msse4.2' > build.log 2>&1 || (cat build.log && exit 1) - sudo make install PREFIX=$LUAJIT_PREFIX > build.log 2>&1 || (cat build.log && exit 1) diff --git a/t/000--init.t b/t/000--init.t index 0dd08fe188..0016e14486 100644 --- a/t/000--init.t +++ b/t/000--init.t @@ -11,7 +11,7 @@ $ENV{TEST_NGINX_MYSQL_PORT} ||= 3306; our $http_config = <<'_EOC_'; # lua-resty-string is required for lua-resty-mysql - lua_package_path "../lua-resty-mysql/lib/?.lua;../lua-resty-string/lib/?.lua;;"; + lua_package_path "../lua-resty-rsa/lib/?.lua;../lua-resty-mysql/lib/?.lua;../lua-resty-string/lib/?.lua;;"; _EOC_ no_shuffle(); diff --git a/t/082-body-filter-2.t b/t/082-body-filter-2.t index eafe7cf26a..99ed447f56 100644 --- a/t/082-body-filter-2.t +++ b/t/082-body-filter-2.t @@ -60,3 +60,157 @@ waiting body filter busy buffer to be sent lua say response has busy bufs --- no_error_log [error] + + + +=== TEST 2: arg[1] not change and say long string +--- config + location /t { + header_filter_by_lua_block {ngx.header.content_length = nil} + body_filter_by_lua_block { + local function anyting_not_change_arg1() + return + end + anyting_not_change_arg1() + } + content_by_lua_block { + for i = 1, 100 do + ngx.say("12345678901234567890") + end + } + } +--- request +GET /t +--- response_body eval +("12345678901234567890\n" x 100) +--- no_error_log +[error] +[alert] +[crit] + + + +=== TEST 3: arg[1] not change and chunked_transfer_encoding off +--- config + location /t { + header_filter_by_lua_block {ngx.header.content_length = nil} + body_filter_by_lua_block { + local function anyting_not_change_arg1() + return + end + anyting_not_change_arg1() + } + chunked_transfer_encoding off; + content_by_lua_block { + for i = 1, 100 do + ngx.say("12345678901234567890123456789012345678901234567890".."_"..tostring(i/3)) + end + } + } +--- request +GET /t +--- response_body +12345678901234567890123456789012345678901234567890_0.33333333333333 +12345678901234567890123456789012345678901234567890_0.66666666666667 +12345678901234567890123456789012345678901234567890_1 +12345678901234567890123456789012345678901234567890_1.3333333333333 +12345678901234567890123456789012345678901234567890_1.6666666666667 +12345678901234567890123456789012345678901234567890_2 +12345678901234567890123456789012345678901234567890_2.3333333333333 +12345678901234567890123456789012345678901234567890_2.6666666666667 +12345678901234567890123456789012345678901234567890_3 +12345678901234567890123456789012345678901234567890_3.3333333333333 +12345678901234567890123456789012345678901234567890_3.6666666666667 +12345678901234567890123456789012345678901234567890_4 +12345678901234567890123456789012345678901234567890_4.3333333333333 +12345678901234567890123456789012345678901234567890_4.6666666666667 +12345678901234567890123456789012345678901234567890_5 +12345678901234567890123456789012345678901234567890_5.3333333333333 +12345678901234567890123456789012345678901234567890_5.6666666666667 +12345678901234567890123456789012345678901234567890_6 +12345678901234567890123456789012345678901234567890_6.3333333333333 +12345678901234567890123456789012345678901234567890_6.6666666666667 +12345678901234567890123456789012345678901234567890_7 +12345678901234567890123456789012345678901234567890_7.3333333333333 +12345678901234567890123456789012345678901234567890_7.6666666666667 +12345678901234567890123456789012345678901234567890_8 +12345678901234567890123456789012345678901234567890_8.3333333333333 +12345678901234567890123456789012345678901234567890_8.6666666666667 +12345678901234567890123456789012345678901234567890_9 +12345678901234567890123456789012345678901234567890_9.3333333333333 +12345678901234567890123456789012345678901234567890_9.6666666666667 +12345678901234567890123456789012345678901234567890_10 +12345678901234567890123456789012345678901234567890_10.333333333333 +12345678901234567890123456789012345678901234567890_10.666666666667 +12345678901234567890123456789012345678901234567890_11 +12345678901234567890123456789012345678901234567890_11.333333333333 +12345678901234567890123456789012345678901234567890_11.666666666667 +12345678901234567890123456789012345678901234567890_12 +12345678901234567890123456789012345678901234567890_12.333333333333 +12345678901234567890123456789012345678901234567890_12.666666666667 +12345678901234567890123456789012345678901234567890_13 +12345678901234567890123456789012345678901234567890_13.333333333333 +12345678901234567890123456789012345678901234567890_13.666666666667 +12345678901234567890123456789012345678901234567890_14 +12345678901234567890123456789012345678901234567890_14.333333333333 +12345678901234567890123456789012345678901234567890_14.666666666667 +12345678901234567890123456789012345678901234567890_15 +12345678901234567890123456789012345678901234567890_15.333333333333 +12345678901234567890123456789012345678901234567890_15.666666666667 +12345678901234567890123456789012345678901234567890_16 +12345678901234567890123456789012345678901234567890_16.333333333333 +12345678901234567890123456789012345678901234567890_16.666666666667 +12345678901234567890123456789012345678901234567890_17 +12345678901234567890123456789012345678901234567890_17.333333333333 +12345678901234567890123456789012345678901234567890_17.666666666667 +12345678901234567890123456789012345678901234567890_18 +12345678901234567890123456789012345678901234567890_18.333333333333 +12345678901234567890123456789012345678901234567890_18.666666666667 +12345678901234567890123456789012345678901234567890_19 +12345678901234567890123456789012345678901234567890_19.333333333333 +12345678901234567890123456789012345678901234567890_19.666666666667 +12345678901234567890123456789012345678901234567890_20 +12345678901234567890123456789012345678901234567890_20.333333333333 +12345678901234567890123456789012345678901234567890_20.666666666667 +12345678901234567890123456789012345678901234567890_21 +12345678901234567890123456789012345678901234567890_21.333333333333 +12345678901234567890123456789012345678901234567890_21.666666666667 +12345678901234567890123456789012345678901234567890_22 +12345678901234567890123456789012345678901234567890_22.333333333333 +12345678901234567890123456789012345678901234567890_22.666666666667 +12345678901234567890123456789012345678901234567890_23 +12345678901234567890123456789012345678901234567890_23.333333333333 +12345678901234567890123456789012345678901234567890_23.666666666667 +12345678901234567890123456789012345678901234567890_24 +12345678901234567890123456789012345678901234567890_24.333333333333 +12345678901234567890123456789012345678901234567890_24.666666666667 +12345678901234567890123456789012345678901234567890_25 +12345678901234567890123456789012345678901234567890_25.333333333333 +12345678901234567890123456789012345678901234567890_25.666666666667 +12345678901234567890123456789012345678901234567890_26 +12345678901234567890123456789012345678901234567890_26.333333333333 +12345678901234567890123456789012345678901234567890_26.666666666667 +12345678901234567890123456789012345678901234567890_27 +12345678901234567890123456789012345678901234567890_27.333333333333 +12345678901234567890123456789012345678901234567890_27.666666666667 +12345678901234567890123456789012345678901234567890_28 +12345678901234567890123456789012345678901234567890_28.333333333333 +12345678901234567890123456789012345678901234567890_28.666666666667 +12345678901234567890123456789012345678901234567890_29 +12345678901234567890123456789012345678901234567890_29.333333333333 +12345678901234567890123456789012345678901234567890_29.666666666667 +12345678901234567890123456789012345678901234567890_30 +12345678901234567890123456789012345678901234567890_30.333333333333 +12345678901234567890123456789012345678901234567890_30.666666666667 +12345678901234567890123456789012345678901234567890_31 +12345678901234567890123456789012345678901234567890_31.333333333333 +12345678901234567890123456789012345678901234567890_31.666666666667 +12345678901234567890123456789012345678901234567890_32 +12345678901234567890123456789012345678901234567890_32.333333333333 +12345678901234567890123456789012345678901234567890_32.666666666667 +12345678901234567890123456789012345678901234567890_33 +12345678901234567890123456789012345678901234567890_33.333333333333 +--- no_error_log +[error] +[alert] +[crit] From 16de4bea620b6281f948b0d65341e31b2c90d597 Mon Sep 17 00:00:00 2001 From: A compound of Fe and O Date: Fri, 7 Apr 2023 01:47:27 +0100 Subject: [PATCH 087/254] bugfix: Fix handling of new list elements. Signed-off by: lijunlong --- .travis.yml | 1 + src/ngx_http_lua_control.c | 3 +++ src/ngx_http_lua_headers_in.c | 3 +++ src/ngx_http_lua_headers_out.c | 3 +++ src/ngx_http_lua_subrequest.c | 3 +++ 5 files changed, 13 insertions(+) diff --git a/.travis.yml b/.travis.yml index 1a051b7120..64d27d8529 100644 --- a/.travis.yml +++ b/.travis.yml @@ -50,6 +50,7 @@ env: - LD_LIBRARY_PATH=$LUAJIT_LIB:$LD_LIBRARY_PATH - DRIZZLE_VER=2011.07.21 - TEST_NGINX_SLEEP=0.006 + - MALLOC_PERTURB_=9 jobs: - NGINX_VERSION=1.21.4 OPENSSL_VER=1.1.0l OPENSSL_PATCH_VER=1.1.0d - NGINX_VERSION=1.21.4 OPENSSL_VER=1.1.1s OPENSSL_PATCH_VER=1.1.1f diff --git a/src/ngx_http_lua_control.c b/src/ngx_http_lua_control.c index 99460456c1..d7e427385d 100644 --- a/src/ngx_http_lua_control.c +++ b/src/ngx_http_lua_control.c @@ -280,6 +280,9 @@ ngx_http_lua_ngx_redirect(lua_State *L) h->value.len = len; h->value.data = uri; +#if defined(nginx_version) && nginx_version >= 1023000 + h->next = NULL; +#endif ngx_str_set(&h->key, "Location"); r->headers_out.status = rc; diff --git a/src/ngx_http_lua_headers_in.c b/src/ngx_http_lua_headers_in.c index 4405481408..960e2f85f6 100644 --- a/src/ngx_http_lua_headers_in.c +++ b/src/ngx_http_lua_headers_in.c @@ -280,6 +280,9 @@ ngx_http_set_header_helper(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, h->key = hv->key; h->value = *value; +#if defined(nginx_version) && nginx_version >= 1023000 + h->next = NULL; +#endif h->lowcase_key = ngx_pnalloc(r->pool, h->key.len); if (h->lowcase_key == NULL) { diff --git a/src/ngx_http_lua_headers_out.c b/src/ngx_http_lua_headers_out.c index 571723d9a6..c51146a3fc 100644 --- a/src/ngx_http_lua_headers_out.c +++ b/src/ngx_http_lua_headers_out.c @@ -229,6 +229,9 @@ ngx_http_set_header_helper(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, h->key = hv->key; h->value = *value; +#if defined(nginx_version) && nginx_version >= 1023000 + h->next = NULL; +#endif h->lowcase_key = ngx_pnalloc(r->pool, h->key.len); if (h->lowcase_key == NULL) { diff --git a/src/ngx_http_lua_subrequest.c b/src/ngx_http_lua_subrequest.c index f6638c2991..c09207417e 100644 --- a/src/ngx_http_lua_subrequest.c +++ b/src/ngx_http_lua_subrequest.c @@ -1667,6 +1667,9 @@ ngx_http_lua_copy_request_headers(ngx_http_request_t *sr, clh->hash = ngx_http_lua_content_length_hash; clh->key = ngx_http_lua_content_length_header_key; +#if defined(nginx_version) && nginx_version >= 1023000 + clh->next = NULL; +#endif clh->lowcase_key = ngx_pnalloc(sr->pool, clh->key.len); if (clh->lowcase_key == NULL) { return NGX_ERROR; From bf8c91d1116fe767ed4f0b1d9b0bbc4055faf31f Mon Sep 17 00:00:00 2001 From: willmafh Date: Wed, 10 May 2023 22:30:39 +0800 Subject: [PATCH 088/254] doc: fixed typo in error messages. --- src/ngx_http_lua_socket_tcp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 9391569529..119994d010 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -3261,7 +3261,7 @@ ngx_http_lua_socket_tcp_settimeouts(lua_State *L) n = lua_gettop(L); if (n != 4) { - return luaL_error(L, "ngx.socket settimeout: expecting 4 arguments " + return luaL_error(L, "ngx.socket settimeouts: expecting 4 arguments " "(including the object) but seen %d", lua_gettop(L)); } From 0090f3faf66e6870b3974e983ae4b47459c96fa3 Mon Sep 17 00:00:00 2001 From: Jun Ouyang Date: Thu, 11 May 2023 19:27:13 +0800 Subject: [PATCH 089/254] bugfix: disable http2 in body read due to http2 stream processing bug. --- README.markdown | 4 ++++ src/ngx_http_lua_accessby.c | 5 +++++ src/ngx_http_lua_contentby.c | 5 +++++ src/ngx_http_lua_req_body.c | 14 ++++++++++++++ src/ngx_http_lua_rewriteby.c | 5 +++++ src/ngx_http_lua_server_rewriteby.c | 7 ++++++- t/023-rewrite/request_body.t | 20 ++++++++++++++++++++ t/024-access/request_body.t | 20 ++++++++++++++++++++ t/044-req-body.t | 19 ++++++++++++++++++- 9 files changed, 97 insertions(+), 2 deletions(-) diff --git a/README.markdown b/README.markdown index c0d0c079d4..448fce86f5 100644 --- a/README.markdown +++ b/README.markdown @@ -2721,6 +2721,8 @@ lua_need_request_body **phase:** *depends on usage* +Due to the stream processing feature of HTTP2, it does not support HTTP2 connection. + Determines whether to force the request body data to be read before running rewrite/access/content_by_lua* or not. The Nginx core does not read the client request body by default and if request body data is required, then this directive should be turned `on` or the [ngx.req.read_body](#ngxreqread_body) function should be called within the Lua code. To read the request body data within the [$request_body](http://nginx.org/en/docs/http/ngx_http_core_module.html#var_request_body) variable, @@ -5384,6 +5386,8 @@ Reads the client request body synchronously without blocking the Nginx event loo local args = ngx.req.get_post_args() ``` +Due to the stream processing feature of HTTP2, it does not support HTTP2 connection. + If the request body is already read previously by turning on [lua_need_request_body](#lua_need_request_body) or by using other modules, then this function does not run and returns immediately. If the request body has already been explicitly discarded, either by the [ngx.req.discard_body](#ngxreqdiscard_body) function or other modules, this function does not run and returns immediately. diff --git a/src/ngx_http_lua_accessby.c b/src/ngx_http_lua_accessby.c index 58c251443e..8814b924bb 100644 --- a/src/ngx_http_lua_accessby.c +++ b/src/ngx_http_lua_accessby.c @@ -136,7 +136,12 @@ ngx_http_lua_access_handler(ngx_http_request_t *r) return NGX_DONE; } +/* http2 read body may break http2 stream process */ +#if (NGX_HTTP_V2) + if (llcf->force_read_body && !ctx->read_body_done && !r->main->stream) { +#else if (llcf->force_read_body && !ctx->read_body_done) { +#endif r->request_body_in_single_buf = 1; r->request_body_in_persistent_file = 1; r->request_body_in_clean_file = 1; diff --git a/src/ngx_http_lua_contentby.c b/src/ngx_http_lua_contentby.c index 76e6a074da..65067cd6a1 100644 --- a/src/ngx_http_lua_contentby.c +++ b/src/ngx_http_lua_contentby.c @@ -195,7 +195,12 @@ ngx_http_lua_content_handler(ngx_http_request_t *r) return rc; } +/* http2 read body may break http2 stream process */ +#if (NGX_HTTP_V2) + if (llcf->force_read_body && !ctx->read_body_done && !r->main->stream) { +#else if (llcf->force_read_body && !ctx->read_body_done) { +#endif r->request_body_in_single_buf = 1; r->request_body_in_persistent_file = 1; r->request_body_in_clean_file = 1; diff --git a/src/ngx_http_lua_req_body.c b/src/ngx_http_lua_req_body.c index 935fafc8a4..3c452b3051 100644 --- a/src/ngx_http_lua_req_body.c +++ b/src/ngx_http_lua_req_body.c @@ -85,6 +85,13 @@ ngx_http_lua_ngx_req_read_body(lua_State *L) return luaL_error(L, "request object not found"); } +/* http2 read body may break http2 stream process */ +#if (NGX_HTTP_V2) + if (r->main->stream) { + return luaL_error(L, "http2 requests are not supported yet"); + } +#endif + r->request_body_in_single_buf = 1; r->request_body_in_persistent_file = 1; r->request_body_in_clean_file = 1; @@ -312,6 +319,13 @@ ngx_http_lua_ngx_req_get_body_file(lua_State *L) return luaL_error(L, "request object not found"); } +/* http2 read body may break http2 stream process */ +#if (NGX_HTTP_V2) + if (r->main->stream) { + return luaL_error(L, "http2 requests are not supported yet"); + } +#endif + ngx_http_lua_check_fake_request(L, r); if (r->request_body == NULL || r->request_body->temp_file == NULL) { diff --git a/src/ngx_http_lua_rewriteby.c b/src/ngx_http_lua_rewriteby.c index d1eabeccdd..2e3065364e 100644 --- a/src/ngx_http_lua_rewriteby.c +++ b/src/ngx_http_lua_rewriteby.c @@ -140,7 +140,12 @@ ngx_http_lua_rewrite_handler(ngx_http_request_t *r) return NGX_DONE; } +/* http2 read body may break http2 stream process */ +#if (NGX_HTTP_V2) + if (llcf->force_read_body && !ctx->read_body_done && !r->main->stream) { +#else if (llcf->force_read_body && !ctx->read_body_done) { +#endif r->request_body_in_single_buf = 1; r->request_body_in_persistent_file = 1; r->request_body_in_clean_file = 1; diff --git a/src/ngx_http_lua_server_rewriteby.c b/src/ngx_http_lua_server_rewriteby.c index 22bb69e8c8..cc6192d925 100644 --- a/src/ngx_http_lua_server_rewriteby.c +++ b/src/ngx_http_lua_server_rewriteby.c @@ -102,8 +102,13 @@ ngx_http_lua_server_rewrite_handler(ngx_http_request_t *r) return NGX_DONE; } - /* TODO: lscf do not have force_read_body */ +/* TODO: lscf do not have force_read_body + * http2 read body may break http2 stream process */ +#if (NGX_HTTP_V2) + if (llcf->force_read_body && !ctx->read_body_done && !r->main->stream) { +#else if (llcf->force_read_body && !ctx->read_body_done) { +#endif r->request_body_in_single_buf = 1; r->request_body_in_persistent_file = 1; r->request_body_in_clean_file = 1; diff --git a/t/023-rewrite/request_body.t b/t/023-rewrite/request_body.t index b867d3a82c..f9af17236f 100644 --- a/t/023-rewrite/request_body.t +++ b/t/023-rewrite/request_body.t @@ -170,3 +170,23 @@ Expect: 100-Continue http finalize request: 500, "/echo_body?" a:1, c:2 http finalize request: 500, "/echo_body?" a:1, c:0 --- log_level: debug + + + +=== TEST 9: test HTTP2 reading request body was disabled +--- config + location /echo_body { + lua_need_request_body on; + rewrite_by_lua_block { + ngx.print(ngx.var.request_body or "nil") + } + content_by_lua 'ngx.exit(ngx.OK)'; + } +--- http2 +--- request eval +"POST /echo_body +hello\x00\x01\x02 +world\x03\x04\xff" +--- response_body eval +"nil" +--- no_error_log diff --git a/t/024-access/request_body.t b/t/024-access/request_body.t index fa03195272..4970e37aef 100644 --- a/t/024-access/request_body.t +++ b/t/024-access/request_body.t @@ -170,3 +170,23 @@ Expect: 100-Continue http finalize request: 500, "/echo_body?" a:1, c:2 http finalize request: 500, "/echo_body?" a:1, c:0 --- log_level: debug + + + +=== TEST 9: test HTTP2 reading request body was disabled +--- config + location /echo_body { + lua_need_request_body on; + access_by_lua_block { + ngx.print(ngx.var.request_body or "nil") + } + content_by_lua 'ngx.exit(ngx.OK)'; + } +--- http2 +--- request eval +"POST /echo_body +hello\x00\x01\x02 +world\x03\x04\xff" +--- response_body eval +"nil" +--- no_error_log diff --git a/t/044-req-body.t b/t/044-req-body.t index 2ef7e1d29e..d8a62c7dbe 100644 --- a/t/044-req-body.t +++ b/t/044-req-body.t @@ -7,7 +7,7 @@ log_level('warn'); repeat_each(2); -plan tests => repeat_each() * (blocks() * 4 + 52 ); +plan tests => repeat_each() * (blocks() * 4 + 50 ); #no_diff(); no_long_string(); @@ -1744,3 +1744,20 @@ content length: 5 --- no_error_log [error] [alert] + + + +=== TEST 53: HTTP2 read buffered body was discarded +--- config + location = /test { + content_by_lua_block { + local err = pcall(ngx.req.read_body()) + ngx.say(err) + } + } +--- http2 +--- request +POST /test +hello, world +--- error_code: 500 +--- error_log: http2 requests are not supported yet From c91fb13a8c168ce39a8dd434fc324c3b5f2cf985 Mon Sep 17 00:00:00 2001 From: willmafh Date: Thu, 11 May 2023 19:31:18 +0800 Subject: [PATCH 090/254] doc: fix typo in the comment. --- src/ngx_http_lua_clfactory.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ngx_http_lua_clfactory.c b/src/ngx_http_lua_clfactory.c index c13fd14dc1..9eab164661 100644 --- a/src/ngx_http_lua_clfactory.c +++ b/src/ngx_http_lua_clfactory.c @@ -91,7 +91,7 @@ * | Int | At which line this function is defined * | [linedefined] | * --------------------- - * | Int | At while line this function definition ended + * | Int | At which line this function definition ended * | [lastlinedefined] | * --------------------- * | Char | Number of upvalues referenced by this function @@ -128,7 +128,7 @@ * | Vector | Debug lineinfo vector * | [lineinfo] | Empty vector here if debug info is stripped * --------------------- - * | Int | Number of local variable in this function + * | Int | Number of local variables in this function * | [sizelocvars] | 0 if debug info is stripped * --------------------- * | String | ------------------------------------ From 4bf1b0b8d7614ba094a3e3d3619f1f52a83b03f7 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Fri, 14 Apr 2023 14:03:29 +0800 Subject: [PATCH 091/254] change: lua-ssl-protocols: Disabled SSLv3 and enable TLSv1.3 by default. --- README.markdown | 3 ++- src/ngx_http_lua_module.c | 4 ++-- t/025-codecache.t | 1 + t/129-ssl-socket.t | 2 ++ t/143-ssl-session-fetch.t | 19 +++++++++++++++++++ 5 files changed, 26 insertions(+), 3 deletions(-) diff --git a/README.markdown b/README.markdown index 448fce86f5..19fea19e64 100644 --- a/README.markdown +++ b/README.markdown @@ -3323,13 +3323,14 @@ lua_ssl_protocols **syntax:** *lua_ssl_protocols \[SSLv2\] \[SSLv3\] \[TLSv1\] [TLSv1.1] [TLSv1.2] [TLSv1.3]* -**default:** *lua_ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2* +**default:** *lua_ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3* **context:** *http, server, location* Enables the specified protocols for requests to a SSL/TLS server in the [tcpsock:sslhandshake](#tcpsocksslhandshake) method. The support for the `TLSv1.3` parameter requires version `v0.10.12` *and* OpenSSL 1.1.1. +From version v0.10.25, the default value change from `SSLV3 TLSv1 TLSv1.1 TLSv1.2` to `TLSv1 TLSv1.1 TLSv1.2 TLSv1.3`. This directive was first introduced in the `v0.9.11` release. diff --git a/src/ngx_http_lua_module.c b/src/ngx_http_lua_module.c index 16f442464c..8ea93e2a0e 100644 --- a/src/ngx_http_lua_module.c +++ b/src/ngx_http_lua_module.c @@ -1465,9 +1465,9 @@ ngx_http_lua_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) #if (NGX_HTTP_SSL) ngx_conf_merge_bitmask_value(conf->ssl_protocols, prev->ssl_protocols, - (NGX_CONF_BITMASK_SET|NGX_SSL_SSLv3 + (NGX_CONF_BITMASK_SET |NGX_SSL_TLSv1|NGX_SSL_TLSv1_1 - |NGX_SSL_TLSv1_2)); + |NGX_SSL_TLSv1_2|NGX_SSL_TLSv1_3)); ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers, "DEFAULT"); diff --git a/t/025-codecache.t b/t/025-codecache.t index ebe4f61b7b..2a3eeb3b08 100644 --- a/t/025-codecache.t +++ b/t/025-codecache.t @@ -1720,6 +1720,7 @@ grep me: b } --- config lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + lua_ssl_protocols TLSv1 TLSv1.1 TLSV1.2; location = /proxy { proxy_pass http://backend; diff --git a/t/129-ssl-socket.t b/t/129-ssl-socket.t index 81ca51ca41..7e48d59bca 100644 --- a/t/129-ssl-socket.t +++ b/t/129-ssl-socket.t @@ -1034,6 +1034,8 @@ SSL reused session --- config server_tokens off; resolver $TEST_NGINX_RESOLVER ipv6=off; + lua_ssl_protocols TLSv1 TLSv1.1 TLSV1.2; + location /t { #set $port 5000; set $port $TEST_NGINX_MEMCACHED_PORT; diff --git a/t/143-ssl-session-fetch.t b/t/143-ssl-session-fetch.t index 8c5174dd94..74f2e6e1bb 100644 --- a/t/143-ssl-session-fetch.t +++ b/t/143-ssl-session-fetch.t @@ -41,6 +41,7 @@ __DATA__ server_tokens off; resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + lua_ssl_protocols TLSv1 TLSv1.1 TLSV1.2; location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -141,6 +142,7 @@ ssl_session_fetch_by_lua\(nginx\.conf:25\):1: ssl fetch sess by lua is running!, server_tokens off; resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + lua_ssl_protocols TLSv1 TLSv1.1 TLSV1.2; location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -225,6 +227,7 @@ qr/elapsed in ssl fetch session by lua: 0.(?:09|1[01])\d+,/, server_tokens off; resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + lua_ssl_protocols TLSv1 TLSv1.1 TLSV1.2; location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -326,6 +329,7 @@ qr/my timer run!/s server_tokens off; resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + lua_ssl_protocols TLSv1 TLSv1.1 TLSV1.2; location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -407,6 +411,7 @@ qr/received memc reply: OK/s resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; lua_ssl_verify_depth 3; + lua_ssl_protocols TLSv1 TLSv1.1 TLSV1.2; location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -488,6 +493,7 @@ should never reached here resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; lua_ssl_verify_depth 3; + lua_ssl_protocols TLSv1 TLSv1.1 TLSV1.2; location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -570,6 +576,7 @@ should never reached here resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; lua_ssl_verify_depth 3; + lua_ssl_protocols TLSv1 TLSv1.1 TLSV1.2; location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -650,6 +657,7 @@ should never reached here server_tokens off; resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + lua_ssl_protocols TLSv1 TLSv1.1 TLSV1.2; lua_ssl_verify_depth 3; location /t { @@ -733,6 +741,7 @@ should never reached here server_tokens off; resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + lua_ssl_protocols TLSv1 TLSv1.1 TLSV1.2; lua_ssl_verify_depth 3; location /t { @@ -814,6 +823,7 @@ should never reached here server_tokens off; resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + lua_ssl_protocols TLSv1 TLSv1.1 TLSV1.2; location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -900,6 +910,7 @@ qr/get_phase: ssl_session_fetch/s server_tokens off; resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + lua_ssl_protocols TLSv1 TLSv1.1 TLSV1.2; location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -982,6 +993,7 @@ ssl store session by lua is running! --- config server_tokens off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + lua_ssl_protocols TLSv1 TLSv1.1 TLSV1.2; location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -1070,6 +1082,7 @@ qr/\S+:\d+: ssl fetch sess by lua is running!/s server_tokens off; resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + lua_ssl_protocols TLSv1 TLSv1.1 TLSV1.2; location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -1170,6 +1183,7 @@ qr/ssl_session_fetch_by_lua\(nginx.conf:\d+\):1: ssl fetch sess by lua is runnin --- config server_tokens off; lua_ssl_trusted_certificate ../../cert/test.crt; + lua_ssl_protocols TLSv1 TLSv1.1 TLSV1.2; location /t { content_by_lua_block { @@ -1249,6 +1263,7 @@ GET /t --- config server_tokens off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + lua_ssl_protocols TLSv1 TLSv1.1 TLSV1.2; location /t { content_by_lua_block { @@ -1406,6 +1421,7 @@ ssl_session_fetch_by_lua\(nginx\.conf:\d+\):1: ssl_session_fetch_by_lua\* is run --- config server_tokens off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + lua_ssl_protocols TLSv1 TLSv1.1 TLSV1.2; location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -1501,6 +1517,7 @@ qr/elapsed in ssl_session_fetch_by_lua\*: 0\.(?:09|1[01])\d+,/, --- config server_tokens off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + lua_ssl_protocols TLSv1 TLSv1.1 TLSV1.2; location /t { content_by_lua_block { @@ -1596,6 +1613,7 @@ close: 1 nil --- config server_tokens off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + lua_ssl_protocols TLSv1 TLSv1.1 TLSV1.2; location /t { content_by_lua_block { @@ -1696,6 +1714,7 @@ uthread: failed to kill: already waited or killed --- config server_tokens off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + lua_ssl_protocols TLSv1 TLSv1.1 TLSV1.2; location /t { content_by_lua_block { From 0c3853e124e6b06c47c3ad501087f74bf70f5c43 Mon Sep 17 00:00:00 2001 From: ZongRun <1181591811hzr@gmail.com> Date: Mon, 22 May 2023 23:22:26 +0800 Subject: [PATCH 092/254] bugfix: mixed recv api call causes unexpected result. Co-authored-by: timzrhuang --- src/ngx_http_lua_socket_tcp.c | 113 ++++++- t/066-socket-receiveuntil.t | 591 ++++++++++++++++++++++++++++++++++ 2 files changed, 697 insertions(+), 7 deletions(-) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 119994d010..e8a70a19b3 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -75,6 +75,8 @@ static void ngx_http_lua_socket_dummy_handler(ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u); static int ngx_http_lua_socket_tcp_receive_helper(ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u, lua_State *L); +static void ngx_http_lua_socket_tcp_read_prepare(ngx_http_request_t *r, + ngx_http_lua_socket_tcp_upstream_t *u, void *data, lua_State *L); static ngx_int_t ngx_http_lua_socket_tcp_read(ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u); static int ngx_http_lua_socket_tcp_receive_retval_handler(ngx_http_request_t *r, @@ -2163,8 +2165,6 @@ ngx_http_lua_socket_tcp_receive_helper(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx; ngx_http_lua_co_ctx_t *coctx; - u->input_filter_ctx = u; - ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (u->bufs_in == NULL) { @@ -2193,6 +2193,8 @@ ngx_http_lua_socket_tcp_receive_helper(ngx_http_request_t *r, u->read_waiting = 0; u->read_co_ctx = NULL; + ngx_http_lua_socket_tcp_read_prepare(r, u, u, L); + rc = ngx_http_lua_socket_tcp_read(r, u); if (rc == NGX_ERROR) { @@ -2514,6 +2516,87 @@ ngx_http_lua_socket_read_any(void *data, ssize_t bytes) } +static void +ngx_http_lua_socket_tcp_read_prepare(ngx_http_request_t *r, + ngx_http_lua_socket_tcp_upstream_t *u, void *data, lua_State *L) +{ + ngx_http_lua_ctx_t *ctx; + ngx_chain_t *new_cl; + ngx_buf_t *b; + off_t size; + + ngx_http_lua_socket_compiled_pattern_t *cp; + + /* input_filter_ctx doesn't change, no need recovering */ + if (u->input_filter_ctx == data) { + return; + } + + /* last input_filter_ctx is null or upstream, no data pending */ + if (u->input_filter_ctx == NULL || u->input_filter_ctx == u) { + u->input_filter_ctx = data; + return; + } + + /* compiled pattern may be with data pending */ + + cp = u->input_filter_ctx; + u->input_filter_ctx = data; + + cp->upstream = NULL; + + /* no data pending */ + if (cp->state <= 0) { + return; + } + + b = &u->buffer; + + if (b->pos - b->start >= cp->state) { + dd("pending data in one buffer"); + + b->pos -= cp->state; + + u->buf_in->buf->pos = b->pos; + u->buf_in->buf->last = b->pos; + + /* reset dfa state for future matching */ + cp->state = 0; + return; + } + + dd("pending data in multiple buffers"); + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + + size = ngx_buf_size(b); + + new_cl = + ngx_http_lua_chain_get_free_buf(r->connection->log, r->pool, + &ctx->free_recv_bufs, + cp->state + size); + + if (new_cl == NULL) { + luaL_error(L, "no memory"); + return; + } + + ngx_memcpy(b, new_cl->buf, sizeof(ngx_buf_t)); + + b->last = ngx_copy(b->last, cp->pattern.data, cp->state); + b->last = ngx_copy(b->last, u->buf_in->buf->pos, size); + + u->buf_in->next = ctx->free_recv_bufs; + ctx->free_recv_bufs = u->buf_in; + + u->bufs_in = new_cl; + u->buf_in = new_cl; + + /* reset dfa state for future matching */ + cp->state = 0; +} + + static ngx_int_t ngx_http_lua_socket_tcp_read(ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u) @@ -4243,6 +4326,11 @@ ngx_http_lua_socket_tcp_finalize(ngx_http_request_t *r, ngx_http_lua_socket_tcp_finalize_read_part(r, u); ngx_http_lua_socket_tcp_finalize_write_part(r, u); + if (u->input_filter_ctx != NULL && u->input_filter_ctx != u) { + ((ngx_http_lua_socket_compiled_pattern_t *) + u->input_filter_ctx)->upstream = NULL; + } + if (u->raw_downstream || u->body_downstream) { u->peer.connection = NULL; return; @@ -4559,8 +4647,6 @@ ngx_http_lua_socket_receiveuntil_iterator(lua_State *L) (u_char *) lua_tolstring(L, lua_upvalueindex(2), &cp->pattern.len); - u->input_filter_ctx = cp; - ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (u->bufs_in == NULL) { @@ -4587,6 +4673,8 @@ ngx_http_lua_socket_receiveuntil_iterator(lua_State *L) u->read_waiting = 0; u->read_co_ctx = NULL; + ngx_http_lua_socket_tcp_read_prepare(r, u, cp, L); + rc = ngx_http_lua_socket_tcp_read(r, u); if (rc == NGX_ERROR) { @@ -4915,13 +5003,24 @@ ngx_http_lua_socket_cleanup_compiled_pattern(lua_State *L) { ngx_http_lua_socket_compiled_pattern_t *cp; - ngx_http_lua_dfa_edge_t *edge, *p; - unsigned i; + ngx_http_lua_socket_tcp_upstream_t *u; + ngx_http_lua_dfa_edge_t *edge, *p; + unsigned i; dd("cleanup compiled pattern"); cp = lua_touserdata(L, 1); - if (cp == NULL || cp->recovering == NULL) { + if (cp == NULL) { + return 0; + } + + u = cp->upstream; + if (u != NULL) { + ngx_http_lua_socket_tcp_read_prepare(u->request, u, NULL, L); + u->input_filter_ctx = NULL; + } + + if (cp->recovering == NULL) { return 0; } diff --git a/t/066-socket-receiveuntil.t b/t/066-socket-receiveuntil.t index 1182a536c1..7fac6bfd0f 100644 --- a/t/066-socket-receiveuntil.t +++ b/t/066-socket-receiveuntil.t @@ -1402,3 +1402,594 @@ close: 1 nil } --- no_error_log [error] + + + +=== TEST 21: ambiguous boundary patterns (--abc), mixed by other reading calls consume boundary +--- config + server_tokens off; + location /t { + set $port $TEST_NGINX_SERVER_PORT; + + content_by_lua_block { + -- collectgarbage("collect") + + local sock = ngx.socket.tcp() + local port = ngx.var.port + + local ok, err = sock:connect("127.0.0.1", port) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local req = "GET /foo HTTP/1.0\r\nHost: localhost\r\nConnection: close\r\n\r\n" + + local bytes, err = sock:send(req) + if not bytes then + ngx.say("failed to send request: ", err) + return + end + ngx.say("request sent: ", bytes) + + local read_headers = sock:receiveuntil("\r\n\r\n") + local headers, err, part = read_headers() + if not headers then + ngx.say("failed to read headers: ", err, " [", part, "]") + end + + local reader = sock:receiveuntil("--abc") + + for i = 1, 5 do + local line, err, part = reader(2) + if not line then + ngx.say("failed to read a line: ", err, " [", part, "]") + break + + else + ngx.say("read: ", line) + end + + local data, err, part = sock:receive(1) + if not data then + ngx.say("failed to read a byte: ", err, " [", part, "]") + break + + else + ngx.say("read one byte: ", data) + end + end + + local line, err, part = reader(2) + if not line then + ngx.say("failed to read a line: ", err, " [", part, "]") + + else + ngx.say("read: ", line) + end + + ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + } + } + + location /foo { + echo -- ----abc----abc-; + more_clear_headers Date; + } +--- request +GET /t + +--- response_body eval +qq{connected: 1 +request sent: 57 +read: -- +read one byte: - +read: -a +read one byte: b +read: c- +read one byte: - +read: +read one byte: - +failed to read a line: nil [nil] +failed to read a line: closed [ +] +close: 1 nil +} +--- no_error_log +[error] + + + +=== TEST 22: ambiguous boundary patterns (--abc), mixed by other reading calls (including receiveuntil) consume boundary +--- config + server_tokens off; + location /t { + set $port $TEST_NGINX_SERVER_PORT; + + content_by_lua_block { + -- collectgarbage("collect") + + local sock = ngx.socket.tcp() + local port = ngx.var.port + + local ok, err = sock:connect("127.0.0.1", port) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local req = "GET /foo HTTP/1.0\r\nHost: localhost\r\nConnection: close\r\n\r\n" + + local bytes, err = sock:send(req) + if not bytes then + ngx.say("failed to send request: ", err) + return + end + ngx.say("request sent: ", bytes) + + local read_headers = sock:receiveuntil("\r\n\r\n") + local headers, err, part = read_headers() + if not headers then + ngx.say("failed to read headers: ", err, " [", part, "]") + end + + local reader1 = sock:receiveuntil("--abc") + local reader2 = sock:receiveuntil("-ab") + + local line, err, part = reader1(2) + if not line then + ngx.say("failed to read a line: ", err, " [", part, "]") + + else + ngx.say("read: ", line) + end + + local data, err, part = sock:receive(1) + if not data then + ngx.say("failed to read a byte: ", err, " [", part, "]") + + else + ngx.say("read one byte: ", data) + end + + local line, err, part = reader1(1) + if not line then + ngx.say("failed to read a line: ", err, " [", part, "]") + + else + ngx.say("read: ", line) + end + + local line, err, part = reader2(2) + if not line then + ngx.say("failed to read a line: ", err, " [", part, "]") + + else + ngx.say("read: ", line) + end + + local line, err, part = reader1() + if not line then + ngx.say("failed to read a line: ", err, " [", part, "]") + + else + ngx.say("read: ", line) + end + + local line, err, part = reader1() + if not line then + ngx.say("failed to read a line: ", err, " [", part, "]") + + else + ngx.say("read: ", line) + end + + ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + } + } + + location /foo { + echo -- ------abd----abc; + more_clear_headers Date; + } +--- request +GET /t + +--- response_body eval +qq{connected: 1 +request sent: 57 +read: -- +read one byte: - +read: - +read: - +read: d-- +failed to read a line: closed [ +] +close: 1 nil +} +--- no_error_log +[error] + + + +=== TEST 23: ambiguous boundary patterns (--abc), mixed by other reading calls consume boundary, small buffer +--- config + lua_socket_buffer_size 3; + server_tokens off; + location /t { + set $port $TEST_NGINX_SERVER_PORT; + + content_by_lua_block { + -- collectgarbage("collect") + + local sock = ngx.socket.tcp() + local port = ngx.var.port + + local ok, err = sock:connect("127.0.0.1", port) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local req = "GET /foo HTTP/1.0\r\nHost: localhost\r\nConnection: close\r\n\r\n" + + local bytes, err = sock:send(req) + if not bytes then + ngx.say("failed to send request: ", err) + return + end + ngx.say("request sent: ", bytes) + + local read_headers = sock:receiveuntil("\r\n\r\n") + local headers, err, part = read_headers() + if not headers then + ngx.say("failed to read headers: ", err, " [", part, "]") + end + + local reader = sock:receiveuntil("--abc") + + for i = 1, 5 do + local line, err, part = reader(2) + if not line then + ngx.say("failed to read a line: ", err, " [", part, "]") + break + + else + ngx.say("read: ", line) + end + + local data, err, part = sock:receive(1) + if not data then + ngx.say("failed to read a byte: ", err, " [", part, "]") + break + + else + ngx.say("read one byte: ", data) + end + end + + local line, err, part = reader(2) + if not line then + ngx.say("failed to read a line: ", err, " [", part, "]") + + else + ngx.say("read: ", line) + end + + ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + } + } + + location /foo { + echo -- ----abc----abc-; + more_clear_headers Date; + } +--- request +GET /t + +--- response_body eval +qq{connected: 1 +request sent: 57 +read: -- +read one byte: - +read: -a +read one byte: b +read: c- +read one byte: - +read: +read one byte: - +failed to read a line: nil [nil] +failed to read a line: closed [ +] +close: 1 nil +} +--- no_error_log +[error] + + + +=== TEST 24: ambiguous boundary patterns (--abc), mixed by other reading calls (including receiveuntil) consume boundary, small buffer +--- config + lua_socket_buffer_size 3; + server_tokens off; + location /t { + set $port $TEST_NGINX_SERVER_PORT; + + content_by_lua_block { + -- collectgarbage("collect") + + local sock = ngx.socket.tcp() + local port = ngx.var.port + + local ok, err = sock:connect("127.0.0.1", port) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local req = "GET /foo HTTP/1.0\r\nHost: localhost\r\nConnection: close\r\n\r\n" + + local bytes, err = sock:send(req) + if not bytes then + ngx.say("failed to send request: ", err) + return + end + ngx.say("request sent: ", bytes) + + local read_headers = sock:receiveuntil("\r\n\r\n") + local headers, err, part = read_headers() + if not headers then + ngx.say("failed to read headers: ", err, " [", part, "]") + end + + local reader1 = sock:receiveuntil("--abc") + local reader2 = sock:receiveuntil("-ab") + + local line, err, part = reader1(2) + if not line then + ngx.say("failed to read a line: ", err, " [", part, "]") + + else + ngx.say("read: ", line) + end + + local data, err, part = sock:receive(1) + if not data then + ngx.say("failed to read a byte: ", err, " [", part, "]") + + else + ngx.say("read one byte: ", data) + end + + local line, err, part = reader1(1) + if not line then + ngx.say("failed to read a line: ", err, " [", part, "]") + + else + ngx.say("read: ", line) + end + + local line, err, part = reader2(2) + if not line then + ngx.say("failed to read a line: ", err, " [", part, "]") + + else + ngx.say("read: ", line) + end + + local line, err, part = reader1() + if not line then + ngx.say("failed to read a line: ", err, " [", part, "]") + + else + ngx.say("read: ", line) + end + + local line, err, part = reader1() + if not line then + ngx.say("failed to read a line: ", err, " [", part, "]") + + else + ngx.say("read: ", line) + end + + ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + } + } + + location /foo { + echo -- ------abd----abc; + more_clear_headers Date; + } +--- request +GET /t + +--- response_body eval +qq{connected: 1 +request sent: 57 +read: -- +read one byte: - +read: - +read: - +read: d-- +failed to read a line: closed [ +] +close: 1 nil +} +--- no_error_log +[error] + + + +=== TEST 25: ambiguous boundary patterns (ab1ab2), ends half way +--- config + server_tokens off; + location /t { + set $port $TEST_NGINX_SERVER_PORT; + + content_by_lua_block { + -- collectgarbage("collect") + + local sock = ngx.socket.tcp() + local port = ngx.var.port + + local ok, err = sock:connect("127.0.0.1", port) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local req = "GET /foo HTTP/1.0\r\nHost: localhost\r\nConnection: close\r\n\r\n" + + local bytes, err = sock:send(req) + if not bytes then + ngx.say("failed to send request: ", err) + return + end + ngx.say("request sent: ", bytes) + + local read_headers = sock:receiveuntil("\r\n\r\n") + local headers, err, part = read_headers() + if not headers then + ngx.say("failed to read headers: ", err, " [", part, "]") + end + + if true then + local reader = sock:receiveuntil("ab1ab2") + + local line, err, part = reader(2) + if not line then + ngx.say("failed to read a line: ", err, " [", part, "]") + + else + ngx.say("read: ", line) + end + end + + collectgarbage("collect") + + local data, err, part = sock:receive(3) + if not data then + ngx.say("failed to read three bytes: ", err, " [", part, "]") + + else + ngx.say("read three bytes: ", data) + end + + ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + } + } + + location /foo { + echo -- ab1ab1; + more_clear_headers Date; + } +--- request +GET /t + +--- response_body eval +qq{connected: 1 +request sent: 57 +read: ab1 +read three bytes: ab1 +close: 1 nil +} +--- no_error_log +[error] + + + +=== TEST 26: ambiguous boundary patterns (ab1ab2), ends half way, small buffer +--- config + lua_socket_buffer_size 3; + server_tokens off; + location /t { + set $port $TEST_NGINX_SERVER_PORT; + + content_by_lua_block { + -- collectgarbage("collect") + + local sock = ngx.socket.tcp() + local port = ngx.var.port + + local ok, err = sock:connect("127.0.0.1", port) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local req = "GET /foo HTTP/1.0\r\nHost: localhost\r\nConnection: close\r\n\r\n" + + local bytes, err = sock:send(req) + if not bytes then + ngx.say("failed to send request: ", err) + return + end + ngx.say("request sent: ", bytes) + + local read_headers = sock:receiveuntil("\r\n\r\n") + local headers, err, part = read_headers() + if not headers then + ngx.say("failed to read headers: ", err, " [", part, "]") + end + + if true then + local reader = sock:receiveuntil("ab1ab2") + + local line, err, part = reader(2) + if not line then + ngx.say("failed to read a line: ", err, " [", part, "]") + + else + ngx.say("read: ", line) + end + end + + collectgarbage("collect") + + local data, err, part = sock:receive(3) + if not data then + ngx.say("failed to read three bytes: ", err, " [", part, "]") + + else + ngx.say("read three bytes: ", data) + end + + ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + } + } + + location /foo { + echo -- ab1ab1; + more_clear_headers Date; + } +--- request +GET /t + +--- response_body eval +qq{connected: 1 +request sent: 57 +read: ab1 +read three bytes: ab1 +close: 1 nil +} +--- no_error_log +[error] From c9a0808c89219f74e4d20cef44a322a1bbe72df3 Mon Sep 17 00:00:00 2001 From: willmafh Date: Mon, 22 May 2023 23:24:47 +0800 Subject: [PATCH 093/254] bugfix: when value type is SHDICT_TNUMBER, then it should get the number field instead of the bool field. --- src/ngx_http_lua_shdict.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ngx_http_lua_shdict.c b/src/ngx_http_lua_shdict.c index 2e0b044065..31bdcdb6a5 100644 --- a/src/ngx_http_lua_shdict.c +++ b/src/ngx_http_lua_shdict.c @@ -654,7 +654,7 @@ ngx_http_lua_shared_dict_get(ngx_shm_zone_t *zone, u_char *key_data, return NGX_ERROR; } - ngx_memcpy(&value->value.b, data, len); + ngx_memcpy(&value->value.n, data, len); break; case SHDICT_TBOOLEAN: From 64631297fbfe21a0d260b538285b8f53b067e1a5 Mon Sep 17 00:00:00 2001 From: mafh Date: Wed, 31 May 2023 13:40:22 +0800 Subject: [PATCH 094/254] bugfix: ssl_client_hello_by_lua generating chunk cache key and chunk name --- src/ngx_http_lua_ssl_client_helloby.c | 8 ++++--- t/166-ssl-client-hello.t | 30 +++++++++++++-------------- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/src/ngx_http_lua_ssl_client_helloby.c b/src/ngx_http_lua_ssl_client_helloby.c index 10500d89e3..1e68e07f4c 100644 --- a/src/ngx_http_lua_ssl_client_helloby.c +++ b/src/ngx_http_lua_ssl_client_helloby.c @@ -150,14 +150,16 @@ ngx_http_lua_ssl_client_hello_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, lscf->srv.ssl_client_hello_src.len = ngx_strlen(name); } else { - cache_key = ngx_http_lua_gen_file_cache_key(cf, value[1].data, - value[1].len); + cache_key = ngx_http_lua_gen_chunk_cache_key(cf, + "ssl_client_hello_by_lua", + value[1].data, + value[1].len); if (cache_key == NULL) { return NGX_CONF_ERROR; } chunkname = ngx_http_lua_gen_chunk_name(cf, "ssl_client_hello_by_lua", - sizeof("ssl_client_helloo_by_lua")- 1, + sizeof("ssl_client_hello_by_lua")- 1, &chunkname_len); if (chunkname == NULL) { return NGX_CONF_ERROR; diff --git a/t/166-ssl-client-hello.t b/t/166-ssl-client-hello.t index da021300af..850a0d6550 100644 --- a/t/166-ssl-client-hello.t +++ b/t/166-ssl-client-hello.t @@ -117,18 +117,18 @@ lua ssl server name: "test.com" --- no_error_log [error] [alert] ---- grep_error_log eval: qr/ssl_client_hello_by_lua:.*?,|\bssl client hello: connection reusable: \d+|\breusable connection: \d+/ +--- grep_error_log eval: qr/ssl_client_hello_by_lua\(.*?,|\bssl client hello: connection reusable: \d+|\breusable connection: \d+/ --- grep_error_log_out eval # Since nginx version 1.17.9, nginx call ngx_reusable_connection(c, 0) # before call ssl callback function $Test::Nginx::Util::NginxVersion >= 1.017009 ? qr/reusable connection: 0 ssl client hello: connection reusable: 0 -ssl_client_hello_by_lua:1: ssl client hello by lua is running!,/ +ssl_client_hello_by_lua\(nginx.conf:\d+\):1: ssl client hello by lua is running!,/ : qr /reusable connection: 1 ssl client hello: connection reusable: 1 reusable connection: 0 -ssl_client_hello_by_lua:1: ssl client hello by lua is running!,/ +ssl_client_hello_by_lua\(nginx.conf:\d+\):1: ssl client hello by lua is running!,/ @@ -789,7 +789,7 @@ failed to do SSL handshake: handshake failed --- error_log eval [ -'runtime error: ssl_client_hello_by_lua:2: bad bad bad', +'runtime error: ssl_client_hello_by_lua(nginx.conf:28):2: bad bad bad', 'lua_client_hello_by_lua: handler return value: 500, client hello cb exit code: 0', qr/\[info\] .*? SSL_do_handshake\(\) failed .*?callback failed/, qr/context: ssl_client_hello_by_lua\*, client: \d+\.\d+\.\d+\.\d+, server: \d+\.\d+\.\d+\.\d+:\d+/, @@ -861,7 +861,7 @@ failed to do SSL handshake: handshake failed --- error_log eval [ -'runtime error: ssl_client_hello_by_lua:3: bad bad bad', +'runtime error: ssl_client_hello_by_lua(nginx.conf:28):3: bad bad bad', 'lua_client_hello_by_lua: client hello cb exit code: 0', qr/\[info\] .*? SSL_do_handshake\(\) failed .*?callback failed/, ] @@ -1048,7 +1048,7 @@ failed to do SSL handshake: handshake failed --- error_log eval [ 'lua ssl server name: "test.com"', -'ssl_client_hello_by_lua:1: API disabled in the context of ssl_client_hello_by_lua*', +'ssl_client_hello_by_lua(nginx.conf:28):1: API disabled in the context of ssl_client_hello_by_lua*', qr/\[info\] .*?callback failed/, ] @@ -1479,7 +1479,7 @@ close: 1 nil --- error_log lua ssl server name: "test.com" -ssl_client_hello_by_lua:1: ssl client hello by lua is running! +ssl_client_hello_by_lua(nginx.conf:25):1: ssl client hello by lua is running! --- no_error_log [error] @@ -1574,7 +1574,7 @@ close: 1 nil --- error_log lua ssl server name: "test.com" -ssl_client_hello_by_lua:1: ssl client hello by lua on the server level is running! +ssl_client_hello_by_lua(nginx.conf:31):1: ssl client hello by lua on the server level is running! --- no_error_log [error] @@ -1657,7 +1657,7 @@ received: foo close: 1 nil --- no_error_log -ssl_client_hello_by_lua:1: ssl client hello by lua is running! +ssl client hello by lua is running! [error] [alert] @@ -1738,7 +1738,7 @@ received: foo close: 1 nil --- no_error_log -ssl_client_hello_by_lua:1: ssl client hello by lua is running! +ssl client hello by lua is running! [error] [alert] @@ -1830,7 +1830,7 @@ close: 1 nil --- error_log lua ssl server name: "test.com" -ssl_client_hello_by_lua:1: ssl client hello by lua is running! +ssl_client_hello_by_lua(nginx.conf:28):1: ssl client hello by lua is running! --- no_error_log [error] @@ -1915,7 +1915,7 @@ close: 1 nil --- no_error_log -ssl_client_hello_by_lua:1: ssl client hello by lua is running! +ssl client hello by lua is running! [error] [alert] @@ -2018,10 +2018,10 @@ close: 1 nil --- error_log lua ssl server name: "test.com" -ssl_client_hello_by_lua:1: ssl client hello by lua in server1 is running! +ssl_client_hello_by_lua(nginx.conf:29):1: ssl client hello by lua in server1 is running! --- no_error_log -ssl_client_hello_by_lua:1: ssl client hello by lua in server2 is running! +ssl client hello by lua in server2 is running! [error] [alert] @@ -2121,7 +2121,7 @@ qr/\[error\] .*? send\(\) failed/, ] --- no_error_log [alert] -ssl_client_hello_by_lua:1: ssl client hello by lua is running! +ssl client hello by lua is running! From 28aced45f6ab5dc801ad77e368f38af2e26f15b6 Mon Sep 17 00:00:00 2001 From: willmafh Date: Sun, 11 Jun 2023 23:44:25 +0800 Subject: [PATCH 095/254] bugfix: ngx_http_lua_socket_tcp_bind is also allowed in ssl_session_fetch_by and ssl_client_hello_by. --- src/ngx_http_lua_socket_tcp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index e8a70a19b3..5be85dcd46 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -865,7 +865,9 @@ ngx_http_lua_socket_tcp_bind(lua_State *L) | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT | NGX_HTTP_LUA_CONTEXT_TIMER - | NGX_HTTP_LUA_CONTEXT_SSL_CERT); + | NGX_HTTP_LUA_CONTEXT_SSL_CERT + | NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH + | NGX_HTTP_LUA_CONTEXT_SSL_CLIENT_HELLO); luaL_checktype(L, 1, LUA_TTABLE); From 992cae739d39eb8d4f270f2a68ee6d8a1d09b5f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BF=9E=E5=BF=97=E9=9B=B7?= Date: Sun, 11 Jun 2023 23:48:43 +0800 Subject: [PATCH 096/254] doc: fixed typo. --- README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index 19fea19e64..695e6b0a4b 100644 --- a/README.markdown +++ b/README.markdown @@ -9358,7 +9358,7 @@ The second argument `module_name` specifies the lua module name to execute in th The third argument `func_name` specifies the function field in the module table as the second argument. -The type of `arg`s must be one of type below: +The type of `args` must be one of type below: * boolean * number From 592a91c1ab4079c0942f1d2b2e804d3c6737be72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Pracha=C5=99?= Date: Sun, 11 Jun 2023 17:58:45 +0200 Subject: [PATCH 097/254] optimize: Optimized use of SSL contexts. Analogous to https://hg.nginx.org/nginx/rev/9d98d524bd02 --- src/ngx_http_lua_module.c | 60 +++++++++++++++++++++++++++++++++++---- 1 file changed, 55 insertions(+), 5 deletions(-) diff --git a/src/ngx_http_lua_module.c b/src/ngx_http_lua_module.c index 8ea93e2a0e..869cc91a82 100644 --- a/src/ngx_http_lua_module.c +++ b/src/ngx_http_lua_module.c @@ -48,6 +48,8 @@ static char *ngx_http_lua_merge_loc_conf(ngx_conf_t *cf, void *parent, static ngx_int_t ngx_http_lua_init(ngx_conf_t *cf); static char *ngx_http_lua_lowat_check(ngx_conf_t *cf, void *post, void *data); #if (NGX_HTTP_SSL) +static ngx_int_t ngx_http_lua_merge_ssl(ngx_conf_t *cf, + ngx_http_lua_loc_conf_t *conf, ngx_http_lua_loc_conf_t *prev); static ngx_int_t ngx_http_lua_set_ssl(ngx_conf_t *cf, ngx_http_lua_loc_conf_t *llcf); #if (nginx_version >= 1019004) @@ -1464,6 +1466,10 @@ ngx_http_lua_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) #if (NGX_HTTP_SSL) + if (ngx_http_lua_merge_ssl(cf, conf, prev) != NGX_OK) { + return NGX_CONF_ERROR; + } + ngx_conf_merge_bitmask_value(conf->ssl_protocols, prev->ssl_protocols, (NGX_CONF_BITMASK_SET |NGX_SSL_TLSv1|NGX_SSL_TLSv1_1 @@ -1528,16 +1534,60 @@ ngx_http_lua_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) #if (NGX_HTTP_SSL) static ngx_int_t -ngx_http_lua_set_ssl(ngx_conf_t *cf, ngx_http_lua_loc_conf_t *llcf) +ngx_http_lua_merge_ssl(ngx_conf_t *cf, + ngx_http_lua_loc_conf_t *conf, ngx_http_lua_loc_conf_t *prev) { - ngx_pool_cleanup_t *cln; + ngx_uint_t preserve; - llcf->ssl = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_t)); - if (llcf->ssl == NULL) { + if (conf->ssl_protocols == 0 + && conf->ssl_ciphers.data == NULL + && conf->ssl_verify_depth == NGX_CONF_UNSET_UINT + && conf->ssl_trusted_certificate.data == NULL + && conf->ssl_crl.data == NULL +#if (nginx_version >= 1019004) + && conf->ssl_conf_commands == NGX_CONF_UNSET_PTR +#endif + ) + { + if (prev->ssl) { + conf->ssl = prev->ssl; + return NGX_OK; + } + + preserve = 1; + + } else { + preserve = 0; + } + + conf->ssl = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_t)); + if (conf->ssl == NULL) { return NGX_ERROR; } - llcf->ssl->log = cf->log; + conf->ssl->log = cf->log; + + /* + * special handling to preserve conf->ssl_* in the "http" section + * to inherit it to all servers + */ + + if (preserve) { + prev->ssl = conf->ssl; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_lua_set_ssl(ngx_conf_t *cf, ngx_http_lua_loc_conf_t *llcf) +{ + ngx_pool_cleanup_t *cln; + + if (llcf->ssl->ctx) { + return NGX_OK; + } if (ngx_ssl_create(llcf->ssl, llcf->ssl_protocols, NULL) != NGX_OK) { return NGX_ERROR; From bba3db08e784c5b9a40c015fc8d9b5240cc26525 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Mon, 19 Jun 2023 09:27:51 +0800 Subject: [PATCH 098/254] bugfix: used after free when encountering invalid http IF-Match header. --- src/ngx_http_lua_accessby.c | 6 ++-- src/ngx_http_lua_bodyfilterby.c | 4 +-- src/ngx_http_lua_common.h | 2 +- src/ngx_http_lua_contentby.c | 4 +-- src/ngx_http_lua_directive.c | 4 +-- src/ngx_http_lua_headerfilterby.c | 4 +-- src/ngx_http_lua_rewriteby.c | 6 ++-- src/ngx_http_lua_server_rewriteby.c | 4 +-- src/ngx_http_lua_socket_udp.c | 4 +-- src/ngx_http_lua_ssl_certby.c | 4 +-- src/ngx_http_lua_ssl_client_helloby.c | 4 +-- src/ngx_http_lua_ssl_session_fetchby.c | 4 +-- src/ngx_http_lua_timer.c | 4 +-- t/014-bugs.t | 49 ++++++++++++++++++++++++++ 14 files changed, 76 insertions(+), 27 deletions(-) diff --git a/src/ngx_http_lua_accessby.c b/src/ngx_http_lua_accessby.c index 8814b924bb..fa6810d9ed 100644 --- a/src/ngx_http_lua_accessby.c +++ b/src/ngx_http_lua_accessby.c @@ -245,7 +245,7 @@ ngx_http_lua_access_by_chunk(lua_State *L, ngx_http_request_t *r) ngx_event_t *rev; ngx_connection_t *c; ngx_http_lua_ctx_t *ctx; - ngx_http_cleanup_t *cln; + ngx_pool_cleanup_t *cln; ngx_http_lua_loc_conf_t *llcf; @@ -296,9 +296,9 @@ ngx_http_lua_access_by_chunk(lua_State *L, ngx_http_request_t *r) /* }}} */ - /* {{{ register request cleanup hooks */ + /* {{{ register nginx pool cleanup hooks */ if (ctx->cleanup == NULL) { - cln = ngx_http_cleanup_add(r, 0); + cln = ngx_pool_cleanup_add(r->pool, 0); if (cln == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } diff --git a/src/ngx_http_lua_bodyfilterby.c b/src/ngx_http_lua_bodyfilterby.c index a8a382ac44..78e3b5c2d6 100644 --- a/src/ngx_http_lua_bodyfilterby.c +++ b/src/ngx_http_lua_bodyfilterby.c @@ -234,7 +234,7 @@ ngx_http_lua_body_filter(ngx_http_request_t *r, ngx_chain_t *in) ngx_http_lua_ctx_t *ctx; ngx_int_t rc; uint16_t old_context; - ngx_http_cleanup_t *cln; + ngx_pool_cleanup_t *cln; ngx_chain_t *out; ngx_chain_t *cl, *ln; ngx_http_lua_main_conf_t *lmcf; @@ -314,7 +314,7 @@ ngx_http_lua_body_filter(ngx_http_request_t *r, ngx_chain_t *in) } if (ctx->cleanup == NULL) { - cln = ngx_http_cleanup_add(r, 0); + cln = ngx_pool_cleanup_add(r->pool, 0); if (cln == NULL) { return NGX_ERROR; } diff --git a/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h index d977ee8e3f..843504549a 100644 --- a/src/ngx_http_lua_common.h +++ b/src/ngx_http_lua_common.h @@ -587,7 +587,7 @@ typedef struct ngx_http_lua_ctx_s { ngx_chain_t *filter_in_bufs; /* for the body filter */ ngx_chain_t *filter_busy_bufs; /* for the body filter */ - ngx_http_cleanup_pt *cleanup; + ngx_pool_cleanup_pt *cleanup; ngx_http_cleanup_t *free_cleanup; /* free list of cleanup records */ diff --git a/src/ngx_http_lua_contentby.c b/src/ngx_http_lua_contentby.c index 65067cd6a1..d1c3bc9fd9 100644 --- a/src/ngx_http_lua_contentby.c +++ b/src/ngx_http_lua_contentby.c @@ -29,7 +29,7 @@ ngx_http_lua_content_by_chunk(lua_State *L, ngx_http_request_t *r) lua_State *co; ngx_event_t *rev; ngx_http_lua_ctx_t *ctx; - ngx_http_cleanup_t *cln; + ngx_pool_cleanup_t *cln; ngx_http_lua_loc_conf_t *llcf; @@ -83,7 +83,7 @@ ngx_http_lua_content_by_chunk(lua_State *L, ngx_http_request_t *r) /* {{{ register request cleanup hooks */ if (ctx->cleanup == NULL) { - cln = ngx_http_cleanup_add(r, 0); + cln = ngx_pool_cleanup_add(r->pool, 0); if (cln == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } diff --git a/src/ngx_http_lua_directive.c b/src/ngx_http_lua_directive.c index f1623056b5..f42aae9d51 100644 --- a/src/ngx_http_lua_directive.c +++ b/src/ngx_http_lua_directive.c @@ -1436,7 +1436,7 @@ ngx_http_lua_set_by_lua_init(ngx_http_request_t *r) { lua_State *L; ngx_http_lua_ctx_t *ctx; - ngx_http_cleanup_t *cln; + ngx_pool_cleanup_t *cln; ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { @@ -1451,7 +1451,7 @@ ngx_http_lua_set_by_lua_init(ngx_http_request_t *r) } if (ctx->cleanup == NULL) { - cln = ngx_http_cleanup_add(r, 0); + cln = ngx_pool_cleanup_add(r->pool, 0); if (cln == NULL) { return NGX_ERROR; } diff --git a/src/ngx_http_lua_headerfilterby.c b/src/ngx_http_lua_headerfilterby.c index f2fe165bd5..71553558bb 100644 --- a/src/ngx_http_lua_headerfilterby.c +++ b/src/ngx_http_lua_headerfilterby.c @@ -231,7 +231,7 @@ ngx_http_lua_header_filter(ngx_http_request_t *r) ngx_http_lua_loc_conf_t *llcf; ngx_http_lua_ctx_t *ctx; ngx_int_t rc; - ngx_http_cleanup_t *cln; + ngx_pool_cleanup_t *cln; uint16_t old_context; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, @@ -260,7 +260,7 @@ ngx_http_lua_header_filter(ngx_http_request_t *r) } if (ctx->cleanup == NULL) { - cln = ngx_http_cleanup_add(r, 0); + cln = ngx_pool_cleanup_add(r->pool, 0); if (cln == NULL) { return NGX_ERROR; } diff --git a/src/ngx_http_lua_rewriteby.c b/src/ngx_http_lua_rewriteby.c index 2e3065364e..c56bba5d7f 100644 --- a/src/ngx_http_lua_rewriteby.c +++ b/src/ngx_http_lua_rewriteby.c @@ -246,7 +246,7 @@ ngx_http_lua_rewrite_by_chunk(lua_State *L, ngx_http_request_t *r) ngx_event_t *rev; ngx_connection_t *c; ngx_http_lua_ctx_t *ctx; - ngx_http_cleanup_t *cln; + ngx_pool_cleanup_t *cln; ngx_http_lua_loc_conf_t *llcf; @@ -296,9 +296,9 @@ ngx_http_lua_rewrite_by_chunk(lua_State *L, ngx_http_request_t *r) /* }}} */ - /* {{{ register request cleanup hooks */ + /* {{{ register nginx pool cleanup hooks */ if (ctx->cleanup == NULL) { - cln = ngx_http_cleanup_add(r, 0); + cln = ngx_pool_cleanup_add(r->pool, 0); if (cln == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } diff --git a/src/ngx_http_lua_server_rewriteby.c b/src/ngx_http_lua_server_rewriteby.c index cc6192d925..997262eeb7 100644 --- a/src/ngx_http_lua_server_rewriteby.c +++ b/src/ngx_http_lua_server_rewriteby.c @@ -204,7 +204,7 @@ ngx_http_lua_server_rewrite_by_chunk(lua_State *L, ngx_http_request_t *r) ngx_event_t *rev; ngx_connection_t *c; ngx_http_lua_ctx_t *ctx; - ngx_http_cleanup_t *cln; + ngx_pool_cleanup_t *cln; ngx_http_lua_loc_conf_t *llcf; @@ -256,7 +256,7 @@ ngx_http_lua_server_rewrite_by_chunk(lua_State *L, ngx_http_request_t *r) /* {{{ register request cleanup hooks */ if (ctx->cleanup == NULL) { - cln = ngx_http_cleanup_add(r, 0); + cln = ngx_pool_cleanup_add(r->pool, 0); if (cln == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } diff --git a/src/ngx_http_lua_socket_udp.c b/src/ngx_http_lua_socket_udp.c index cbb6621b47..10285f6d0a 100644 --- a/src/ngx_http_lua_socket_udp.c +++ b/src/ngx_http_lua_socket_udp.c @@ -591,7 +591,7 @@ ngx_http_lua_socket_resolve_retval_handler(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx; ngx_http_lua_co_ctx_t *coctx; ngx_connection_t *c; - ngx_http_cleanup_t *cln; + ngx_pool_cleanup_t *cln; ngx_http_upstream_resolved_t *ur; ngx_int_t rc; ngx_http_lua_udp_connection_t *uc; @@ -625,7 +625,7 @@ ngx_http_lua_socket_resolve_retval_handler(ngx_http_request_t *r, } if (u->cleanup == NULL) { - cln = ngx_http_cleanup_add(r, 0); + cln = ngx_pool_cleanup_add(r->pool, 0); if (cln == NULL) { u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_ERROR; lua_pushnil(L); diff --git a/src/ngx_http_lua_ssl_certby.c b/src/ngx_http_lua_ssl_certby.c index 0499bfb355..b8e70ddefa 100644 --- a/src/ngx_http_lua_ssl_certby.c +++ b/src/ngx_http_lua_ssl_certby.c @@ -453,7 +453,7 @@ ngx_http_lua_ssl_cert_by_chunk(lua_State *L, ngx_http_request_t *r) ngx_int_t rc; lua_State *co; ngx_http_lua_ctx_t *ctx; - ngx_http_cleanup_t *cln; + ngx_pool_cleanup_t *cln; ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); @@ -507,7 +507,7 @@ ngx_http_lua_ssl_cert_by_chunk(lua_State *L, ngx_http_request_t *r) /* register request cleanup hooks */ if (ctx->cleanup == NULL) { - cln = ngx_http_cleanup_add(r, 0); + cln = ngx_pool_cleanup_add(r->pool, 0); if (cln == NULL) { rc = NGX_ERROR; ngx_http_lua_finalize_request(r, rc); diff --git a/src/ngx_http_lua_ssl_client_helloby.c b/src/ngx_http_lua_ssl_client_helloby.c index 1e68e07f4c..a1dac61887 100644 --- a/src/ngx_http_lua_ssl_client_helloby.c +++ b/src/ngx_http_lua_ssl_client_helloby.c @@ -449,7 +449,7 @@ ngx_http_lua_ssl_client_hello_by_chunk(lua_State *L, ngx_http_request_t *r) ngx_int_t rc; lua_State *co; ngx_http_lua_ctx_t *ctx; - ngx_http_cleanup_t *cln; + ngx_pool_cleanup_t *cln; ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); @@ -503,7 +503,7 @@ ngx_http_lua_ssl_client_hello_by_chunk(lua_State *L, ngx_http_request_t *r) /* register request cleanup hooks */ if (ctx->cleanup == NULL) { - cln = ngx_http_cleanup_add(r, 0); + cln = ngx_pool_cleanup_add(r->pool, 0); if (cln == NULL) { rc = NGX_ERROR; ngx_http_lua_finalize_request(r, rc); diff --git a/src/ngx_http_lua_ssl_session_fetchby.c b/src/ngx_http_lua_ssl_session_fetchby.c index 66e9848550..ebce63ce28 100644 --- a/src/ngx_http_lua_ssl_session_fetchby.c +++ b/src/ngx_http_lua_ssl_session_fetchby.c @@ -477,7 +477,7 @@ ngx_http_lua_ssl_sess_fetch_by_chunk(lua_State *L, ngx_http_request_t *r) ngx_int_t rc; lua_State *co; ngx_http_lua_ctx_t *ctx; - ngx_http_cleanup_t *cln; + ngx_pool_cleanup_t *cln; ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); @@ -531,7 +531,7 @@ ngx_http_lua_ssl_sess_fetch_by_chunk(lua_State *L, ngx_http_request_t *r) /* register request cleanup hooks */ if (ctx->cleanup == NULL) { - cln = ngx_http_cleanup_add(r, 0); + cln = ngx_pool_cleanup_add(r->pool, 0); if (cln == NULL) { rc = NGX_ERROR; ngx_http_lua_finalize_request(r, rc); diff --git a/src/ngx_http_lua_timer.c b/src/ngx_http_lua_timer.c index 060cab543a..11d29349a5 100644 --- a/src/ngx_http_lua_timer.c +++ b/src/ngx_http_lua_timer.c @@ -519,7 +519,7 @@ ngx_http_lua_timer_handler(ngx_event_t *ev) ngx_connection_t *c = NULL; ngx_http_request_t *r = NULL; ngx_http_lua_ctx_t *ctx; - ngx_http_cleanup_t *cln; + ngx_pool_cleanup_t *cln; ngx_pool_cleanup_t *pcln; ngx_http_lua_timer_ctx_t tctx; @@ -620,7 +620,7 @@ ngx_http_lua_timer_handler(ngx_event_t *ev) L = ngx_http_lua_get_lua_vm(r, ctx); - cln = ngx_http_cleanup_add(r, 0); + cln = ngx_pool_cleanup_add(r->pool, 0); if (cln == NULL) { errmsg = "could not add request cleanup"; goto failed; diff --git a/t/014-bugs.t b/t/014-bugs.t index bfc86c9e9a..877aecfdb5 100644 --- a/t/014-bugs.t +++ b/t/014-bugs.t @@ -1283,3 +1283,52 @@ Hello world --- shutdown_error_log eval qr|failed to read a line: closed| --- timeout: 1.2 + + + +=== TEST 48: nginx crashes when encountering an illegal http if header +crash with ngx.send_headers() +--- main_config +--- config +error_page 412 /my_error_handler_412; + +location /t { + rewrite_by_lua_block { + ngx.send_headers() + -- ngx.print() -- this also triggers the bug + } +} +location = /my_error_handler_412 { + return 412 "hello"; +} +--- request + GET /t +--- more_headers +If-Match: 1 +--- error_code: 412 +--- response_body eval +qr/\Ahello\z/ + + + +=== TEST 49: nginx crashes when encountering an illegal http if header +crash with ngx.print() +--- main_config +--- config +error_page 412 /my_error_handler_412; + +location /t { + rewrite_by_lua_block { + ngx.print() + } +} +location = /my_error_handler_412 { + return 412 "hello"; +} +--- request + GET /t +--- more_headers +If-Match: 1 +--- error_code: 412 +--- response_body eval +qr/\Ahello\z/ From 6e9948dcdac5618da47223bec1f328e417ab0fcb Mon Sep 17 00:00:00 2001 From: mafh Date: Wed, 31 May 2023 13:40:22 +0800 Subject: [PATCH 099/254] bugfix: ssl_client_hello_by_lua generating chunk cache key and chunk name --- src/ngx_http_lua_ssl_client_helloby.c | 8 ++++--- t/166-ssl-client-hello.t | 30 +++++++++++++-------------- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/src/ngx_http_lua_ssl_client_helloby.c b/src/ngx_http_lua_ssl_client_helloby.c index 10500d89e3..1e68e07f4c 100644 --- a/src/ngx_http_lua_ssl_client_helloby.c +++ b/src/ngx_http_lua_ssl_client_helloby.c @@ -150,14 +150,16 @@ ngx_http_lua_ssl_client_hello_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, lscf->srv.ssl_client_hello_src.len = ngx_strlen(name); } else { - cache_key = ngx_http_lua_gen_file_cache_key(cf, value[1].data, - value[1].len); + cache_key = ngx_http_lua_gen_chunk_cache_key(cf, + "ssl_client_hello_by_lua", + value[1].data, + value[1].len); if (cache_key == NULL) { return NGX_CONF_ERROR; } chunkname = ngx_http_lua_gen_chunk_name(cf, "ssl_client_hello_by_lua", - sizeof("ssl_client_helloo_by_lua")- 1, + sizeof("ssl_client_hello_by_lua")- 1, &chunkname_len); if (chunkname == NULL) { return NGX_CONF_ERROR; diff --git a/t/166-ssl-client-hello.t b/t/166-ssl-client-hello.t index da021300af..850a0d6550 100644 --- a/t/166-ssl-client-hello.t +++ b/t/166-ssl-client-hello.t @@ -117,18 +117,18 @@ lua ssl server name: "test.com" --- no_error_log [error] [alert] ---- grep_error_log eval: qr/ssl_client_hello_by_lua:.*?,|\bssl client hello: connection reusable: \d+|\breusable connection: \d+/ +--- grep_error_log eval: qr/ssl_client_hello_by_lua\(.*?,|\bssl client hello: connection reusable: \d+|\breusable connection: \d+/ --- grep_error_log_out eval # Since nginx version 1.17.9, nginx call ngx_reusable_connection(c, 0) # before call ssl callback function $Test::Nginx::Util::NginxVersion >= 1.017009 ? qr/reusable connection: 0 ssl client hello: connection reusable: 0 -ssl_client_hello_by_lua:1: ssl client hello by lua is running!,/ +ssl_client_hello_by_lua\(nginx.conf:\d+\):1: ssl client hello by lua is running!,/ : qr /reusable connection: 1 ssl client hello: connection reusable: 1 reusable connection: 0 -ssl_client_hello_by_lua:1: ssl client hello by lua is running!,/ +ssl_client_hello_by_lua\(nginx.conf:\d+\):1: ssl client hello by lua is running!,/ @@ -789,7 +789,7 @@ failed to do SSL handshake: handshake failed --- error_log eval [ -'runtime error: ssl_client_hello_by_lua:2: bad bad bad', +'runtime error: ssl_client_hello_by_lua(nginx.conf:28):2: bad bad bad', 'lua_client_hello_by_lua: handler return value: 500, client hello cb exit code: 0', qr/\[info\] .*? SSL_do_handshake\(\) failed .*?callback failed/, qr/context: ssl_client_hello_by_lua\*, client: \d+\.\d+\.\d+\.\d+, server: \d+\.\d+\.\d+\.\d+:\d+/, @@ -861,7 +861,7 @@ failed to do SSL handshake: handshake failed --- error_log eval [ -'runtime error: ssl_client_hello_by_lua:3: bad bad bad', +'runtime error: ssl_client_hello_by_lua(nginx.conf:28):3: bad bad bad', 'lua_client_hello_by_lua: client hello cb exit code: 0', qr/\[info\] .*? SSL_do_handshake\(\) failed .*?callback failed/, ] @@ -1048,7 +1048,7 @@ failed to do SSL handshake: handshake failed --- error_log eval [ 'lua ssl server name: "test.com"', -'ssl_client_hello_by_lua:1: API disabled in the context of ssl_client_hello_by_lua*', +'ssl_client_hello_by_lua(nginx.conf:28):1: API disabled in the context of ssl_client_hello_by_lua*', qr/\[info\] .*?callback failed/, ] @@ -1479,7 +1479,7 @@ close: 1 nil --- error_log lua ssl server name: "test.com" -ssl_client_hello_by_lua:1: ssl client hello by lua is running! +ssl_client_hello_by_lua(nginx.conf:25):1: ssl client hello by lua is running! --- no_error_log [error] @@ -1574,7 +1574,7 @@ close: 1 nil --- error_log lua ssl server name: "test.com" -ssl_client_hello_by_lua:1: ssl client hello by lua on the server level is running! +ssl_client_hello_by_lua(nginx.conf:31):1: ssl client hello by lua on the server level is running! --- no_error_log [error] @@ -1657,7 +1657,7 @@ received: foo close: 1 nil --- no_error_log -ssl_client_hello_by_lua:1: ssl client hello by lua is running! +ssl client hello by lua is running! [error] [alert] @@ -1738,7 +1738,7 @@ received: foo close: 1 nil --- no_error_log -ssl_client_hello_by_lua:1: ssl client hello by lua is running! +ssl client hello by lua is running! [error] [alert] @@ -1830,7 +1830,7 @@ close: 1 nil --- error_log lua ssl server name: "test.com" -ssl_client_hello_by_lua:1: ssl client hello by lua is running! +ssl_client_hello_by_lua(nginx.conf:28):1: ssl client hello by lua is running! --- no_error_log [error] @@ -1915,7 +1915,7 @@ close: 1 nil --- no_error_log -ssl_client_hello_by_lua:1: ssl client hello by lua is running! +ssl client hello by lua is running! [error] [alert] @@ -2018,10 +2018,10 @@ close: 1 nil --- error_log lua ssl server name: "test.com" -ssl_client_hello_by_lua:1: ssl client hello by lua in server1 is running! +ssl_client_hello_by_lua(nginx.conf:29):1: ssl client hello by lua in server1 is running! --- no_error_log -ssl_client_hello_by_lua:1: ssl client hello by lua in server2 is running! +ssl client hello by lua in server2 is running! [error] [alert] @@ -2121,7 +2121,7 @@ qr/\[error\] .*? send\(\) failed/, ] --- no_error_log [alert] -ssl_client_hello_by_lua:1: ssl client hello by lua is running! +ssl client hello by lua is running! From 6d0a2c184703604d6245288ca9cf50addb95b178 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Mon, 19 Jun 2023 09:27:51 +0800 Subject: [PATCH 100/254] bugfix: used after free when encountering invalid http IF-Match header. --- src/ngx_http_lua_accessby.c | 6 ++-- src/ngx_http_lua_bodyfilterby.c | 4 +-- src/ngx_http_lua_common.h | 2 +- src/ngx_http_lua_contentby.c | 4 +-- src/ngx_http_lua_directive.c | 4 +-- src/ngx_http_lua_headerfilterby.c | 4 +-- src/ngx_http_lua_rewriteby.c | 6 ++-- src/ngx_http_lua_server_rewriteby.c | 4 +-- src/ngx_http_lua_socket_udp.c | 4 +-- src/ngx_http_lua_ssl_certby.c | 4 +-- src/ngx_http_lua_ssl_client_helloby.c | 4 +-- src/ngx_http_lua_ssl_session_fetchby.c | 4 +-- src/ngx_http_lua_timer.c | 4 +-- t/014-bugs.t | 49 ++++++++++++++++++++++++++ 14 files changed, 76 insertions(+), 27 deletions(-) diff --git a/src/ngx_http_lua_accessby.c b/src/ngx_http_lua_accessby.c index 58c251443e..d40eab123e 100644 --- a/src/ngx_http_lua_accessby.c +++ b/src/ngx_http_lua_accessby.c @@ -240,7 +240,7 @@ ngx_http_lua_access_by_chunk(lua_State *L, ngx_http_request_t *r) ngx_event_t *rev; ngx_connection_t *c; ngx_http_lua_ctx_t *ctx; - ngx_http_cleanup_t *cln; + ngx_pool_cleanup_t *cln; ngx_http_lua_loc_conf_t *llcf; @@ -291,9 +291,9 @@ ngx_http_lua_access_by_chunk(lua_State *L, ngx_http_request_t *r) /* }}} */ - /* {{{ register request cleanup hooks */ + /* {{{ register nginx pool cleanup hooks */ if (ctx->cleanup == NULL) { - cln = ngx_http_cleanup_add(r, 0); + cln = ngx_pool_cleanup_add(r->pool, 0); if (cln == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } diff --git a/src/ngx_http_lua_bodyfilterby.c b/src/ngx_http_lua_bodyfilterby.c index a8a382ac44..78e3b5c2d6 100644 --- a/src/ngx_http_lua_bodyfilterby.c +++ b/src/ngx_http_lua_bodyfilterby.c @@ -234,7 +234,7 @@ ngx_http_lua_body_filter(ngx_http_request_t *r, ngx_chain_t *in) ngx_http_lua_ctx_t *ctx; ngx_int_t rc; uint16_t old_context; - ngx_http_cleanup_t *cln; + ngx_pool_cleanup_t *cln; ngx_chain_t *out; ngx_chain_t *cl, *ln; ngx_http_lua_main_conf_t *lmcf; @@ -314,7 +314,7 @@ ngx_http_lua_body_filter(ngx_http_request_t *r, ngx_chain_t *in) } if (ctx->cleanup == NULL) { - cln = ngx_http_cleanup_add(r, 0); + cln = ngx_pool_cleanup_add(r->pool, 0); if (cln == NULL) { return NGX_ERROR; } diff --git a/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h index d977ee8e3f..843504549a 100644 --- a/src/ngx_http_lua_common.h +++ b/src/ngx_http_lua_common.h @@ -587,7 +587,7 @@ typedef struct ngx_http_lua_ctx_s { ngx_chain_t *filter_in_bufs; /* for the body filter */ ngx_chain_t *filter_busy_bufs; /* for the body filter */ - ngx_http_cleanup_pt *cleanup; + ngx_pool_cleanup_pt *cleanup; ngx_http_cleanup_t *free_cleanup; /* free list of cleanup records */ diff --git a/src/ngx_http_lua_contentby.c b/src/ngx_http_lua_contentby.c index 76e6a074da..5e2ae55209 100644 --- a/src/ngx_http_lua_contentby.c +++ b/src/ngx_http_lua_contentby.c @@ -29,7 +29,7 @@ ngx_http_lua_content_by_chunk(lua_State *L, ngx_http_request_t *r) lua_State *co; ngx_event_t *rev; ngx_http_lua_ctx_t *ctx; - ngx_http_cleanup_t *cln; + ngx_pool_cleanup_t *cln; ngx_http_lua_loc_conf_t *llcf; @@ -83,7 +83,7 @@ ngx_http_lua_content_by_chunk(lua_State *L, ngx_http_request_t *r) /* {{{ register request cleanup hooks */ if (ctx->cleanup == NULL) { - cln = ngx_http_cleanup_add(r, 0); + cln = ngx_pool_cleanup_add(r->pool, 0); if (cln == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } diff --git a/src/ngx_http_lua_directive.c b/src/ngx_http_lua_directive.c index f1623056b5..f42aae9d51 100644 --- a/src/ngx_http_lua_directive.c +++ b/src/ngx_http_lua_directive.c @@ -1436,7 +1436,7 @@ ngx_http_lua_set_by_lua_init(ngx_http_request_t *r) { lua_State *L; ngx_http_lua_ctx_t *ctx; - ngx_http_cleanup_t *cln; + ngx_pool_cleanup_t *cln; ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { @@ -1451,7 +1451,7 @@ ngx_http_lua_set_by_lua_init(ngx_http_request_t *r) } if (ctx->cleanup == NULL) { - cln = ngx_http_cleanup_add(r, 0); + cln = ngx_pool_cleanup_add(r->pool, 0); if (cln == NULL) { return NGX_ERROR; } diff --git a/src/ngx_http_lua_headerfilterby.c b/src/ngx_http_lua_headerfilterby.c index f2fe165bd5..71553558bb 100644 --- a/src/ngx_http_lua_headerfilterby.c +++ b/src/ngx_http_lua_headerfilterby.c @@ -231,7 +231,7 @@ ngx_http_lua_header_filter(ngx_http_request_t *r) ngx_http_lua_loc_conf_t *llcf; ngx_http_lua_ctx_t *ctx; ngx_int_t rc; - ngx_http_cleanup_t *cln; + ngx_pool_cleanup_t *cln; uint16_t old_context; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, @@ -260,7 +260,7 @@ ngx_http_lua_header_filter(ngx_http_request_t *r) } if (ctx->cleanup == NULL) { - cln = ngx_http_cleanup_add(r, 0); + cln = ngx_pool_cleanup_add(r->pool, 0); if (cln == NULL) { return NGX_ERROR; } diff --git a/src/ngx_http_lua_rewriteby.c b/src/ngx_http_lua_rewriteby.c index d1eabeccdd..4109f288e3 100644 --- a/src/ngx_http_lua_rewriteby.c +++ b/src/ngx_http_lua_rewriteby.c @@ -241,7 +241,7 @@ ngx_http_lua_rewrite_by_chunk(lua_State *L, ngx_http_request_t *r) ngx_event_t *rev; ngx_connection_t *c; ngx_http_lua_ctx_t *ctx; - ngx_http_cleanup_t *cln; + ngx_pool_cleanup_t *cln; ngx_http_lua_loc_conf_t *llcf; @@ -291,9 +291,9 @@ ngx_http_lua_rewrite_by_chunk(lua_State *L, ngx_http_request_t *r) /* }}} */ - /* {{{ register request cleanup hooks */ + /* {{{ register nginx pool cleanup hooks */ if (ctx->cleanup == NULL) { - cln = ngx_http_cleanup_add(r, 0); + cln = ngx_pool_cleanup_add(r->pool, 0); if (cln == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } diff --git a/src/ngx_http_lua_server_rewriteby.c b/src/ngx_http_lua_server_rewriteby.c index 22bb69e8c8..be860693f4 100644 --- a/src/ngx_http_lua_server_rewriteby.c +++ b/src/ngx_http_lua_server_rewriteby.c @@ -199,7 +199,7 @@ ngx_http_lua_server_rewrite_by_chunk(lua_State *L, ngx_http_request_t *r) ngx_event_t *rev; ngx_connection_t *c; ngx_http_lua_ctx_t *ctx; - ngx_http_cleanup_t *cln; + ngx_pool_cleanup_t *cln; ngx_http_lua_loc_conf_t *llcf; @@ -251,7 +251,7 @@ ngx_http_lua_server_rewrite_by_chunk(lua_State *L, ngx_http_request_t *r) /* {{{ register request cleanup hooks */ if (ctx->cleanup == NULL) { - cln = ngx_http_cleanup_add(r, 0); + cln = ngx_pool_cleanup_add(r->pool, 0); if (cln == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } diff --git a/src/ngx_http_lua_socket_udp.c b/src/ngx_http_lua_socket_udp.c index cbb6621b47..10285f6d0a 100644 --- a/src/ngx_http_lua_socket_udp.c +++ b/src/ngx_http_lua_socket_udp.c @@ -591,7 +591,7 @@ ngx_http_lua_socket_resolve_retval_handler(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx; ngx_http_lua_co_ctx_t *coctx; ngx_connection_t *c; - ngx_http_cleanup_t *cln; + ngx_pool_cleanup_t *cln; ngx_http_upstream_resolved_t *ur; ngx_int_t rc; ngx_http_lua_udp_connection_t *uc; @@ -625,7 +625,7 @@ ngx_http_lua_socket_resolve_retval_handler(ngx_http_request_t *r, } if (u->cleanup == NULL) { - cln = ngx_http_cleanup_add(r, 0); + cln = ngx_pool_cleanup_add(r->pool, 0); if (cln == NULL) { u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_ERROR; lua_pushnil(L); diff --git a/src/ngx_http_lua_ssl_certby.c b/src/ngx_http_lua_ssl_certby.c index 0499bfb355..b8e70ddefa 100644 --- a/src/ngx_http_lua_ssl_certby.c +++ b/src/ngx_http_lua_ssl_certby.c @@ -453,7 +453,7 @@ ngx_http_lua_ssl_cert_by_chunk(lua_State *L, ngx_http_request_t *r) ngx_int_t rc; lua_State *co; ngx_http_lua_ctx_t *ctx; - ngx_http_cleanup_t *cln; + ngx_pool_cleanup_t *cln; ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); @@ -507,7 +507,7 @@ ngx_http_lua_ssl_cert_by_chunk(lua_State *L, ngx_http_request_t *r) /* register request cleanup hooks */ if (ctx->cleanup == NULL) { - cln = ngx_http_cleanup_add(r, 0); + cln = ngx_pool_cleanup_add(r->pool, 0); if (cln == NULL) { rc = NGX_ERROR; ngx_http_lua_finalize_request(r, rc); diff --git a/src/ngx_http_lua_ssl_client_helloby.c b/src/ngx_http_lua_ssl_client_helloby.c index 1e68e07f4c..a1dac61887 100644 --- a/src/ngx_http_lua_ssl_client_helloby.c +++ b/src/ngx_http_lua_ssl_client_helloby.c @@ -449,7 +449,7 @@ ngx_http_lua_ssl_client_hello_by_chunk(lua_State *L, ngx_http_request_t *r) ngx_int_t rc; lua_State *co; ngx_http_lua_ctx_t *ctx; - ngx_http_cleanup_t *cln; + ngx_pool_cleanup_t *cln; ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); @@ -503,7 +503,7 @@ ngx_http_lua_ssl_client_hello_by_chunk(lua_State *L, ngx_http_request_t *r) /* register request cleanup hooks */ if (ctx->cleanup == NULL) { - cln = ngx_http_cleanup_add(r, 0); + cln = ngx_pool_cleanup_add(r->pool, 0); if (cln == NULL) { rc = NGX_ERROR; ngx_http_lua_finalize_request(r, rc); diff --git a/src/ngx_http_lua_ssl_session_fetchby.c b/src/ngx_http_lua_ssl_session_fetchby.c index 66e9848550..ebce63ce28 100644 --- a/src/ngx_http_lua_ssl_session_fetchby.c +++ b/src/ngx_http_lua_ssl_session_fetchby.c @@ -477,7 +477,7 @@ ngx_http_lua_ssl_sess_fetch_by_chunk(lua_State *L, ngx_http_request_t *r) ngx_int_t rc; lua_State *co; ngx_http_lua_ctx_t *ctx; - ngx_http_cleanup_t *cln; + ngx_pool_cleanup_t *cln; ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); @@ -531,7 +531,7 @@ ngx_http_lua_ssl_sess_fetch_by_chunk(lua_State *L, ngx_http_request_t *r) /* register request cleanup hooks */ if (ctx->cleanup == NULL) { - cln = ngx_http_cleanup_add(r, 0); + cln = ngx_pool_cleanup_add(r->pool, 0); if (cln == NULL) { rc = NGX_ERROR; ngx_http_lua_finalize_request(r, rc); diff --git a/src/ngx_http_lua_timer.c b/src/ngx_http_lua_timer.c index 060cab543a..11d29349a5 100644 --- a/src/ngx_http_lua_timer.c +++ b/src/ngx_http_lua_timer.c @@ -519,7 +519,7 @@ ngx_http_lua_timer_handler(ngx_event_t *ev) ngx_connection_t *c = NULL; ngx_http_request_t *r = NULL; ngx_http_lua_ctx_t *ctx; - ngx_http_cleanup_t *cln; + ngx_pool_cleanup_t *cln; ngx_pool_cleanup_t *pcln; ngx_http_lua_timer_ctx_t tctx; @@ -620,7 +620,7 @@ ngx_http_lua_timer_handler(ngx_event_t *ev) L = ngx_http_lua_get_lua_vm(r, ctx); - cln = ngx_http_cleanup_add(r, 0); + cln = ngx_pool_cleanup_add(r->pool, 0); if (cln == NULL) { errmsg = "could not add request cleanup"; goto failed; diff --git a/t/014-bugs.t b/t/014-bugs.t index bfc86c9e9a..877aecfdb5 100644 --- a/t/014-bugs.t +++ b/t/014-bugs.t @@ -1283,3 +1283,52 @@ Hello world --- shutdown_error_log eval qr|failed to read a line: closed| --- timeout: 1.2 + + + +=== TEST 48: nginx crashes when encountering an illegal http if header +crash with ngx.send_headers() +--- main_config +--- config +error_page 412 /my_error_handler_412; + +location /t { + rewrite_by_lua_block { + ngx.send_headers() + -- ngx.print() -- this also triggers the bug + } +} +location = /my_error_handler_412 { + return 412 "hello"; +} +--- request + GET /t +--- more_headers +If-Match: 1 +--- error_code: 412 +--- response_body eval +qr/\Ahello\z/ + + + +=== TEST 49: nginx crashes when encountering an illegal http if header +crash with ngx.print() +--- main_config +--- config +error_page 412 /my_error_handler_412; + +location /t { + rewrite_by_lua_block { + ngx.print() + } +} +location = /my_error_handler_412 { + return 412 "hello"; +} +--- request + GET /t +--- more_headers +If-Match: 1 +--- error_code: 412 +--- response_body eval +qr/\Ahello\z/ From c47084b5d719ce507d2419d8660f39544a9d1fea Mon Sep 17 00:00:00 2001 From: lijunlong Date: Mon, 19 Jun 2023 14:28:57 +0800 Subject: [PATCH 101/254] bumped version to 0.10.25. --- src/api/ngx_http_lua_api.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/ngx_http_lua_api.h b/src/api/ngx_http_lua_api.h index 018184990d..640e0c396b 100644 --- a/src/api/ngx_http_lua_api.h +++ b/src/api/ngx_http_lua_api.h @@ -19,7 +19,7 @@ /* Public API for other Nginx modules */ -#define ngx_http_lua_version 10024 +#define ngx_http_lua_version 10025 typedef struct ngx_http_lua_co_ctx_s ngx_http_lua_co_ctx_t; From b4c0450bbe36dba64e4adb0ff3bc8b773202b98a Mon Sep 17 00:00:00 2001 From: zhangjie <49422942+ZJfans@users.noreply.github.com> Date: Mon, 26 Jun 2023 18:29:48 +0800 Subject: [PATCH 102/254] feature: Support lua_ssl_certificate and lua_ssl_certificate_key. Signed-off-by: lijunlong --- doc/HttpLuaModule.wiki | 32 ++++++++ src/ngx_http_lua_common.h | 2 + src/ngx_http_lua_module.c | 46 +++++++++++ t/187-ssl-two-verification.t | 143 +++++++++++++++++++++++++++++++++++ 4 files changed, 223 insertions(+) create mode 100644 t/187-ssl-two-verification.t diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 34751144bd..118d60bbb0 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -2845,6 +2845,38 @@ The support for the TLSv1.3 parameter requires version v0.10. This directive was first introduced in the v0.9.11 release. +== lua_ssl_certificate == + +'''syntax:''' ''lua_ssl_certificate '' + +'''default:''' ''no'' + +'''context:''' ''http, server, location'' + +Specifies the file path to the SSL/TLS certificate in PEM format used for the [[#tcpsock:sslhandshake|tcpsock:sslhandshake]] method. + +This directive allows you to specify the SSL/TLS certificate that will be presented to server during the SSL/TLS handshake process. + +This directive was first introduced in the v0.10.26 release. + +See also [[#lua_ssl_certificate_key|lua_ssl_certificate_key]] and [[#lua_ssl_verify_depth|lua_ssl_verify_depth]]. + +== lua_ssl_certificate_key == + +'''syntax:''' ''lua_ssl_certificate_key '' + +'''default:''' ''no'' + +'''context:''' ''http, server, location'' + +Specifies the file path to the private key associated with the SSL/TLS certificate used in the [[#tcpsock:sslhandshake|tcpsock:sslhandshake]] method. + +This directive allows you to specify the private key file corresponding to the SSL/TLS certificate specified by lua_ssl_certificate. The private key should be in PEM format and must match the certificate. + +This directive was first introduced in the v0.10.26 release. + +See also [[#lua_ssl_certificate|lua_ssl_certificate]] and [[#lua_ssl_verify_depth|lua_ssl_verify_depth]]. + == lua_ssl_trusted_certificate == '''syntax:''' ''lua_ssl_trusted_certificate '' diff --git a/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h index 843504549a..7d9e10cea1 100644 --- a/src/ngx_http_lua_common.h +++ b/src/ngx_http_lua_common.h @@ -360,6 +360,8 @@ union ngx_http_lua_srv_conf_u { typedef struct { #if (NGX_HTTP_SSL) ngx_ssl_t *ssl; /* shared by SSL cosockets */ + ngx_array_t *ssl_certificates; + ngx_array_t *ssl_certificate_keys; ngx_uint_t ssl_protocols; ngx_str_t ssl_ciphers; ngx_uint_t ssl_verify_depth; diff --git a/src/ngx_http_lua_module.c b/src/ngx_http_lua_module.c index 869cc91a82..4d47e83e20 100644 --- a/src/ngx_http_lua_module.c +++ b/src/ngx_http_lua_module.c @@ -650,6 +650,20 @@ static ngx_command_t ngx_http_lua_cmds[] = { offsetof(ngx_http_lua_loc_conf_t, ssl_verify_depth), NULL }, + { ngx_string("lua_ssl_certificate"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_array_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_lua_loc_conf_t, ssl_certificates), + NULL }, + + { ngx_string("lua_ssl_certificate_key"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_array_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_lua_loc_conf_t, ssl_certificate_keys), + NULL }, + { ngx_string("lua_ssl_trusted_certificate"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_str_slot, @@ -1401,6 +1415,8 @@ ngx_http_lua_create_loc_conf(ngx_conf_t *cf) #if (NGX_HTTP_SSL) conf->ssl_verify_depth = NGX_CONF_UNSET_UINT; + conf->ssl_certificates = NGX_CONF_UNSET_PTR; + conf->ssl_certificate_keys = NGX_CONF_UNSET_PTR; #if (nginx_version >= 1019004) conf->ssl_conf_commands = NGX_CONF_UNSET_PTR; #endif @@ -1480,6 +1496,10 @@ ngx_http_lua_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_uint_value(conf->ssl_verify_depth, prev->ssl_verify_depth, 1); + ngx_conf_merge_ptr_value(conf->ssl_certificates, + prev->ssl_certificates, NULL); + ngx_conf_merge_ptr_value(conf->ssl_certificate_keys, + prev->ssl_certificate_keys, NULL); ngx_conf_merge_str_value(conf->ssl_trusted_certificate, prev->ssl_trusted_certificate, ""); ngx_conf_merge_str_value(conf->ssl_crl, prev->ssl_crl, ""); @@ -1542,6 +1562,8 @@ ngx_http_lua_merge_ssl(ngx_conf_t *cf, if (conf->ssl_protocols == 0 && conf->ssl_ciphers.data == NULL && conf->ssl_verify_depth == NGX_CONF_UNSET_UINT + && conf->ssl_certificates == NGX_CONF_UNSET_PTR + && conf->ssl_certificate_keys == NGX_CONF_UNSET_PTR && conf->ssl_trusted_certificate.data == NULL && conf->ssl_crl.data == NULL #if (nginx_version >= 1019004) @@ -1589,6 +1611,20 @@ ngx_http_lua_set_ssl(ngx_conf_t *cf, ngx_http_lua_loc_conf_t *llcf) return NGX_OK; } + if (llcf->ssl_certificates) { + if (llcf->ssl_certificate_keys == NULL + || llcf->ssl_certificate_keys->nelts + < llcf->ssl_certificates->nelts) + { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "no \"lua_ssl_certificate_key\" is defined " + "for certificate \"%V\"", + ((ngx_str_t *) llcf->ssl_certificates->elts) + + llcf->ssl_certificates->nelts - 1); + return NGX_ERROR; + } + } + if (ngx_ssl_create(llcf->ssl, llcf->ssl_protocols, NULL) != NGX_OK) { return NGX_ERROR; } @@ -1612,6 +1648,16 @@ ngx_http_lua_set_ssl(ngx_conf_t *cf, ngx_http_lua_loc_conf_t *llcf) return NGX_ERROR; } + if (llcf->ssl_certificates + && ngx_ssl_certificates(cf, llcf->ssl, + llcf->ssl_certificates, + llcf->ssl_certificate_keys, + NULL) + != NGX_OK) + { + return NGX_ERROR; + } + if (llcf->ssl_trusted_certificate.len && ngx_ssl_trusted_certificate(cf, llcf->ssl, &llcf->ssl_trusted_certificate, diff --git a/t/187-ssl-two-verification.t b/t/187-ssl-two-verification.t new file mode 100644 index 0000000000..527df7cbde --- /dev/null +++ b/t/187-ssl-two-verification.t @@ -0,0 +1,143 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use Test::Nginx::Socket::Lua; + +repeat_each(3); + +# All these tests need to have new openssl +my $NginxBinary = $ENV{'TEST_NGINX_BINARY'} || 'nginx'; +my $openssl_version = eval { `$NginxBinary -V 2>&1` }; + +if ($openssl_version =~ m/built with OpenSSL (0\S*|1\.0\S*|1\.1\.0\S*)/) { + plan(skip_all => "too old OpenSSL, need 1.1.1, was $1"); +} else { + plan tests => repeat_each() * (blocks() * 7); +} + +$ENV{TEST_NGINX_HTML_DIR} ||= html_dir(); +$ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; + +#log_level 'warn'; +log_level 'debug'; + +no_long_string(); +#no_diff(); + +run_tests(); + +__DATA__ + +=== TEST 1: simple logging +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + #listen 127.0.0.1:4433 ssl; + server_name test.com; + ssl_client_hello_by_lua_block { print("ssl client hello by lua is running!") } + ssl_certificate ../../cert/test.crt; + ssl_certificate_key ../../cert/test.key; + #ssl_trusted_certificate ../../cert/test.crt; + ssl_client_certificate ../../cert/test.crt; + ssl_verify_client on; + ssl_protocols TLSv1 TLSv1.1 TLSv1.2; + + server_tokens off; + location /foo { + default_type 'text/plain'; + content_by_lua_block { ngx.status = 201 ngx.say("foo") ngx.exit(201) } + log_by_lua_block { + ngx.log(ngx.INFO, "ssl_client_s_dn: ", ngx.var.ssl_client_s_dn) + } + more_clear_headers Date; + } + } +--- config + server_tokens off; + lua_ssl_certificate ../../cert/test.crt; + lua_ssl_certificate_key ../../cert/test.key; + lua_ssl_trusted_certificate ../../cert/test.crt; + + location /t { + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(2000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + -- local ok, err = sock:connect("127.0.0.1", 4433) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(nil, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + local req = "GET /foo HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n" + local bytes, err = sock:send(req) + if not bytes then + ngx.say("failed to send http request: ", err) + return + end + + ngx.say("sent http request: ", bytes, " bytes.") + + while true do + local line, err = sock:receive() + if not line then + -- ngx.say("failed to receive response status line: ", err) + break + end + + ngx.say("received: ", line) + end + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + -- collectgarbage() + } + } + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: cdata +sent http request: 56 bytes. +received: HTTP/1.1 201 Created +received: Server: nginx +received: Content-Type: text/plain +received: Content-Length: 4 +received: Connection: close +received: +received: foo +close: 1 nil + +--- error_log +lua ssl server name: "test.com" +ssl_client_s_dn: emailAddress=agentzh@gmail.com,CN=test.com,OU=OpenResty,O=OpenResty,L=San Francisco,ST=California,C=US + +--- no_error_log +[error] +[alert] +--- grep_error_log eval: qr/ssl_client_hello_by_lua\(.*?,|\bssl client hello: connection reusable: \d+|\breusable connection: \d+/ +--- grep_error_log_out eval +# Since nginx version 1.17.9, nginx call ngx_reusable_connection(c, 0) +# before call ssl callback function +$Test::Nginx::Util::NginxVersion >= 1.017009 ? +qr/reusable connection: 0 +ssl client hello: connection reusable: 0 +ssl_client_hello_by_lua\(nginx.conf:\d+\):1: ssl client hello by lua is running!,/ +: qr /reusable connection: 1 +ssl client hello: connection reusable: 1 +reusable connection: 0 +ssl_client_hello_by_lua\(nginx.conf:\d+\):1: ssl client hello by lua is running!,/ From 05da2493165845886a3d94515fd7651abf6d6705 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Thu, 20 Jul 2023 23:40:50 +0800 Subject: [PATCH 103/254] feature: allow get empty key for ngx.req.get_uri(). --- README.markdown | 11 +++++++- src/ngx_http_lua_args.c | 6 ++--- t/030-uri-args.t | 59 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+), 4 deletions(-) diff --git a/README.markdown b/README.markdown index 695e6b0a4b..96d8716b6a 100644 --- a/README.markdown +++ b/README.markdown @@ -5001,7 +5001,7 @@ See also [ngx.req.set_uri](#ngxreqset_uri). ngx.req.get_uri_args -------------------- -**syntax:** *args, err = ngx.req.get_uri_args(max_args?, tab?)* +**syntax:** *args, err = ngx.req.get_uri_args(max_args?, tab?, allow_empty_key?)* **context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, balancer_by_lua** @@ -5102,6 +5102,15 @@ This argument can be set to zero to remove the limit and to process all request Removing the `max_args` cap is strongly discouraged. +If the key of the argument is empty, the argument will be skipped by default. +For example, calling `ngx.req.get_uri_args()` against the HTTP request `https://example.com/q?a=b&=d` +will only get a=b. The optional `allow_empty_key` function argument can be used to override this limit: + + +```lua + local args, err = ngx.req.get_uri_args(nil, nil, true) +``` + [Back to TOC](#nginx-api-for-lua) ngx.req.get_post_args diff --git a/src/ngx_http_lua_args.c b/src/ngx_http_lua_args.c index 1280846545..b878602252 100644 --- a/src/ngx_http_lua_args.c +++ b/src/ngx_http_lua_args.c @@ -461,7 +461,7 @@ ngx_http_lua_ffi_req_get_uri_args_count(ngx_http_request_t *r, int max, int ngx_http_lua_ffi_req_get_uri_args(ngx_http_request_t *r, u_char *buf, - ngx_http_lua_ffi_table_elt_t *out, int count) + ngx_http_lua_ffi_table_elt_t *out, int count, int allow_empty_key) { int i, parsing_value = 0; u_char *last, *p, *q; @@ -511,7 +511,7 @@ ngx_http_lua_ffi_req_get_uri_args(ngx_http_request_t *r, u_char *buf, /* end of the current pair's value */ parsing_value = 0; - if (out[i].key.len) { + if (out[i].key.len > 0 || allow_empty_key) { out[i].value.data = q; out[i].value.len = (int) (dst - q); i++; @@ -553,7 +553,7 @@ ngx_http_lua_ffi_req_get_uri_args(ngx_http_request_t *r, u_char *buf, dd("pushing key or value %.*s", (int) (dst - q), q); if (parsing_value) { - if (out[i].key.len) { + if (out[i].key.len > 0 || allow_empty_key) { out[i].value.data = q; out[i].value.len = (int) (dst - q); i++; diff --git a/t/030-uri-args.t b/t/030-uri-args.t index 0633476c8d..334ca617a0 100644 --- a/t/030-uri-args.t +++ b/t/030-uri-args.t @@ -1767,3 +1767,62 @@ request_uri: /foo%20bar uri: /foo bar --- no_error_log [error] + + + +=== TEST 67: empty key in the end +--- config + location /lua { + content_by_lua_block { + local args, err = ngx.req.get_uri_args(nil, nil, true) + + if err then + ngx.say("err: ", err) + end + + local keys = {} + for key, val in pairs(args) do + table.insert(keys, key) + end + + table.sort(keys) + for i, key in ipairs(keys) do + ngx.say(key, " = ", args[key]) + end + } + } +--- request +GET /lua?ka=va&=vb +--- response_body + = vb +ka = va + + + +=== TEST 68: empty key in the middle +--- config + location /lua { + content_by_lua_block { + local args, err = ngx.req.get_uri_args(nil, nil, true) + + if err then + ngx.say("err: ", err) + end + + local keys = {} + for key, val in pairs(args) do + table.insert(keys, key) + end + + table.sort(keys) + for i, key in ipairs(keys) do + ngx.say(key, " = ", args[key]) + end + } + } +--- request +GET /lua?ka=va&=vb&kc=vc +--- response_body + = vb +ka = va +kc = vc From 4ca27c48f5239d310b2f6838673a4f1f87328327 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Fri, 21 Jul 2023 11:30:16 +0800 Subject: [PATCH 104/254] Revert "feature: allow get empty key for ngx.req.get_uri()." This reverts commit 05da2493165845886a3d94515fd7651abf6d6705. --- README.markdown | 11 +------- src/ngx_http_lua_args.c | 6 ++--- t/030-uri-args.t | 59 ----------------------------------------- 3 files changed, 4 insertions(+), 72 deletions(-) diff --git a/README.markdown b/README.markdown index 96d8716b6a..695e6b0a4b 100644 --- a/README.markdown +++ b/README.markdown @@ -5001,7 +5001,7 @@ See also [ngx.req.set_uri](#ngxreqset_uri). ngx.req.get_uri_args -------------------- -**syntax:** *args, err = ngx.req.get_uri_args(max_args?, tab?, allow_empty_key?)* +**syntax:** *args, err = ngx.req.get_uri_args(max_args?, tab?)* **context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, balancer_by_lua** @@ -5102,15 +5102,6 @@ This argument can be set to zero to remove the limit and to process all request Removing the `max_args` cap is strongly discouraged. -If the key of the argument is empty, the argument will be skipped by default. -For example, calling `ngx.req.get_uri_args()` against the HTTP request `https://example.com/q?a=b&=d` -will only get a=b. The optional `allow_empty_key` function argument can be used to override this limit: - - -```lua - local args, err = ngx.req.get_uri_args(nil, nil, true) -``` - [Back to TOC](#nginx-api-for-lua) ngx.req.get_post_args diff --git a/src/ngx_http_lua_args.c b/src/ngx_http_lua_args.c index b878602252..1280846545 100644 --- a/src/ngx_http_lua_args.c +++ b/src/ngx_http_lua_args.c @@ -461,7 +461,7 @@ ngx_http_lua_ffi_req_get_uri_args_count(ngx_http_request_t *r, int max, int ngx_http_lua_ffi_req_get_uri_args(ngx_http_request_t *r, u_char *buf, - ngx_http_lua_ffi_table_elt_t *out, int count, int allow_empty_key) + ngx_http_lua_ffi_table_elt_t *out, int count) { int i, parsing_value = 0; u_char *last, *p, *q; @@ -511,7 +511,7 @@ ngx_http_lua_ffi_req_get_uri_args(ngx_http_request_t *r, u_char *buf, /* end of the current pair's value */ parsing_value = 0; - if (out[i].key.len > 0 || allow_empty_key) { + if (out[i].key.len) { out[i].value.data = q; out[i].value.len = (int) (dst - q); i++; @@ -553,7 +553,7 @@ ngx_http_lua_ffi_req_get_uri_args(ngx_http_request_t *r, u_char *buf, dd("pushing key or value %.*s", (int) (dst - q), q); if (parsing_value) { - if (out[i].key.len > 0 || allow_empty_key) { + if (out[i].key.len) { out[i].value.data = q; out[i].value.len = (int) (dst - q); i++; diff --git a/t/030-uri-args.t b/t/030-uri-args.t index 334ca617a0..0633476c8d 100644 --- a/t/030-uri-args.t +++ b/t/030-uri-args.t @@ -1767,62 +1767,3 @@ request_uri: /foo%20bar uri: /foo bar --- no_error_log [error] - - - -=== TEST 67: empty key in the end ---- config - location /lua { - content_by_lua_block { - local args, err = ngx.req.get_uri_args(nil, nil, true) - - if err then - ngx.say("err: ", err) - end - - local keys = {} - for key, val in pairs(args) do - table.insert(keys, key) - end - - table.sort(keys) - for i, key in ipairs(keys) do - ngx.say(key, " = ", args[key]) - end - } - } ---- request -GET /lua?ka=va&=vb ---- response_body - = vb -ka = va - - - -=== TEST 68: empty key in the middle ---- config - location /lua { - content_by_lua_block { - local args, err = ngx.req.get_uri_args(nil, nil, true) - - if err then - ngx.say("err: ", err) - end - - local keys = {} - for key, val in pairs(args) do - table.insert(keys, key) - end - - table.sort(keys) - for i, key in ipairs(keys) do - ngx.say(key, " = ", args[key]) - end - } - } ---- request -GET /lua?ka=va&=vb&kc=vc ---- response_body - = vb -ka = va -kc = vc From caad24b355e8359edea089c2df7a6306410254f1 Mon Sep 17 00:00:00 2001 From: zhangjie <49422942+ZJfans@users.noreply.github.com> Date: Sat, 29 Jul 2023 16:29:32 +0800 Subject: [PATCH 105/254] doc: modified lua_ssl_certificate, lua_ssl_certificate_key and lua_ssl_trusted_certificate. --- README.markdown | 44 ++++++++++++++++++++++++++++++++++++++++-- doc/HttpLuaModule.wiki | 8 ++++---- 2 files changed, 46 insertions(+), 6 deletions(-) diff --git a/README.markdown b/README.markdown index 695e6b0a4b..daba4c8218 100644 --- a/README.markdown +++ b/README.markdown @@ -1166,6 +1166,8 @@ Directives * [lua_ssl_ciphers](#lua_ssl_ciphers) * [lua_ssl_crl](#lua_ssl_crl) * [lua_ssl_protocols](#lua_ssl_protocols) +* [lua_ssl_certificate](#lua_ssl_certificate) +* [lua_ssl_certificate_key](#lua_ssl_certificate_key) * [lua_ssl_trusted_certificate](#lua_ssl_trusted_certificate) * [lua_ssl_verify_depth](#lua_ssl_verify_depth) * [lua_ssl_conf_command](#lua_ssl_conf_command) @@ -3336,12 +3338,50 @@ This directive was first introduced in the `v0.9.11` release. [Back to TOC](#directives) +lua_ssl_certificate +------------------- + +**syntax:** *lua_ssl_certificate <file>* + +**default:** *none* + +**context:** *http, server, location* + +Specifies the file path to the SSL/TLS certificate in PEM format used for the [tcpsock:sslhandshake](#tcpsocksslhandshake) method. + +This directive allows you to specify the SSL/TLS certificate that will be presented to server during the SSL/TLS handshake process. + +This directive was first introduced in the `v0.10.26` release. + +See also [lua_ssl_certificate_key](#lua_ssl_certificate_key) and [lua_ssl_verify_depth](#lua_ssl_verify_depth). + +[Back to TOC](#directives) + +lua_ssl_certificate_key +----------------------- + +**syntax:** *lua_ssl_certificate_key <file>* + +**default:** *none* + +**context:** *http, server, location* + +Specifies the file path to the private key associated with the SSL/TLS certificate used in the [tcpsock:sslhandshake](#tcpsocksslhandshake) method. + +This directive allows you to specify the private key file corresponding to the SSL/TLS certificate specified by lua_ssl_certificate. The private key should be in PEM format and must match the certificate. + +This directive was first introduced in the `v0.10.26` release. + +See also [lua_ssl_certificate](#lua_ssl_certificate) and [lua_ssl_verify_depth](#lua_ssl_verify_depth). + +[Back to TOC](#directives) + lua_ssl_trusted_certificate --------------------------- **syntax:** *lua_ssl_trusted_certificate <file>* -**default:** *no* +**default:** *none* **context:** *http, server, location* @@ -3366,7 +3406,7 @@ Sets the verification depth in the server certificates chain. This directive was first introduced in the `v0.9.11` release. -See also [lua_ssl_trusted_certificate](#lua_ssl_trusted_certificate). +See also [lua_ssl_certificate](#lua_ssl_certificate), [lua_ssl_certificate_key](#lua_ssl_certificate_key) and [lua_ssl_trusted_certificate](#lua_ssl_trusted_certificate). [Back to TOC](#directives) diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 118d60bbb0..8d003bd602 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -2849,7 +2849,7 @@ This directive was first introduced in the v0.9.11 release. '''syntax:''' ''lua_ssl_certificate '' -'''default:''' ''no'' +'''default:''' ''none'' '''context:''' ''http, server, location'' @@ -2865,7 +2865,7 @@ See also [[#lua_ssl_certificate_key|lua_ssl_certificate_key]] and [[#lua_ssl_ver '''syntax:''' ''lua_ssl_certificate_key '' -'''default:''' ''no'' +'''default:''' ''none'' '''context:''' ''http, server, location'' @@ -2881,7 +2881,7 @@ See also [[#lua_ssl_certificate|lua_ssl_certificate]] and [[#lua_ssl_verify_dept '''syntax:''' ''lua_ssl_trusted_certificate '' -'''default:''' ''no'' +'''default:''' ''none'' '''context:''' ''http, server, location'' @@ -2903,7 +2903,7 @@ Sets the verification depth in the server certificates chain. This directive was first introduced in the v0.9.11 release. -See also [[#lua_ssl_trusted_certificate|lua_ssl_trusted_certificate]]. +See also [[#lua_ssl_certificate|lua_ssl_certificate]], [[#lua_ssl_certificate_key|lua_ssl_certificate_key]] and [[#lua_ssl_trusted_certificate|lua_ssl_trusted_certificate]]. == lua_ssl_conf_command == From f39e7e50fe871f27111218af06d4074059cd0e86 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Mon, 31 Jul 2023 22:11:09 +0800 Subject: [PATCH 106/254] change: remove ngx.re from ngx.run_worker_thread. lmcf->jit_stack shared by ngx.re cause nginx crash when multiple ngx.re instances are executed in parallel. --- README.markdown | 6 - src/ngx_http_lua_worker_thread.c | 9 -- t/166-worker-thread.t | 212 ++++--------------------------- 3 files changed, 26 insertions(+), 201 deletions(-) diff --git a/README.markdown b/README.markdown index daba4c8218..ac04585c5a 100644 --- a/README.markdown +++ b/README.markdown @@ -9366,12 +9366,6 @@ Only the following ngx_lua APIs could be used in `function_name` function of the * `ngx.decode_args` * `ngx.quote_sql_str` -* `ngx.re.match` -* `ngx.re.find` -* `ngx.re.gmatch` -* `ngx.re.sub` -* `ngx.re.gsub` - * `ngx.crc32_short` * `ngx.crc32_long` * `ngx.hmac_sha1` diff --git a/src/ngx_http_lua_worker_thread.c b/src/ngx_http_lua_worker_thread.c index ed7b089295..9de59def75 100644 --- a/src/ngx_http_lua_worker_thread.c +++ b/src/ngx_http_lua_worker_thread.c @@ -157,15 +157,6 @@ ngx_http_lua_get_task_ctx(lua_State *L, ngx_http_request_t *r) ngx_http_lua_inject_shdict_api(lmcf, vm); lua_setglobal(vm, "ngx"); - /* inject API via ffi */ - lua_getglobal(vm, "require"); - lua_pushstring(vm, "resty.core.regex"); - if (lua_pcall(vm, 1, 0, 0) != 0) { - lua_close(vm); - ngx_free(ctx); - return NULL; - } - lua_getglobal(vm, "require"); lua_pushstring(vm, "resty.core.hash"); if (lua_pcall(vm, 1, 0, 0) != 0) { diff --git a/t/166-worker-thread.t b/t/166-worker-thread.t index fd7fdd756e..c8ae62965f 100644 --- a/t/166-worker-thread.t +++ b/t/166-worker-thread.t @@ -777,167 +777,7 @@ true : 'a\Zb\Z' -=== TEST 24: ngx.re.match ---- main_config - thread_pool testpool threads=100; ---- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" ---- config -location /hello { - default_type 'text/plain'; - - content_by_lua_block { - local ok, a, b = ngx.run_worker_thread("testpool", "hello", "hello") - ngx.say(ok, " : ", a, " : ", b) - } -} ---- user_files ->>> hello.lua -local function hello() - local m, err = ngx.re.match("hello, 1234", "([0-9])[0-9]+") - return m[0], m[1] -end -return {hello=hello} ---- request -GET /hello ---- response_body -true : 1234 : 1 - - - -=== TEST 25: ngx.re.find ---- main_config - thread_pool testpool threads=100; ---- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" ---- config -location /hello { - default_type 'text/plain'; - - content_by_lua_block { - local ok, a = ngx.run_worker_thread("testpool", "hello", "hello") - ngx.say(ok, " : ", a) - } -} ---- user_files ->>> hello.lua -local function hello() - local str = "hello, 1234" - local from, to = ngx.re.find(str, "([0-9])([0-9]+)", "jo", nil, 2) - if from then - return string.sub(str, from, to) - end -end -return {hello=hello} ---- request -GET /hello ---- response_body -true : 234 - - - -=== TEST 26: ngx.re.gmatch ---- main_config - thread_pool testpool threads=100; ---- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" ---- config -location /hello { - default_type 'text/plain'; - - content_by_lua_block { - local ok, ret = ngx.run_worker_thread("testpool", "hello", "hello") - ngx.say(ok) - ngx.say(ret[1]) - ngx.say(ret[2]) - } -} ---- user_files ->>> hello.lua -local function hello() - local ret = {} - for m in ngx.re.gmatch("hello, world", "[a-z]+", "j") do - if m then - table.insert(ret, m[0]) - end - end - return ret -end -return {hello=hello} ---- request -GET /hello ---- response_body -true -hello -world - - - -=== TEST 27: ngx.re.sub ---- main_config - thread_pool testpool threads=100; ---- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" ---- config -location /hello { - default_type 'text/plain'; - - content_by_lua_block { - local ok, a, b = ngx.run_worker_thread("testpool", "hello", "hello") - ngx.say(ok) - ngx.say(a) - ngx.say(b) - } -} ---- user_files ->>> hello.lua -local function hello() - local newstr, n = ngx.re.sub("hello, 1234", "[0-9]", "$$") - return newstr, n -end -return {hello=hello} ---- request -GET /hello ---- response_body -true -hello, $234 -1 - - - -=== TEST 28: ngx.re.gsub ---- main_config - thread_pool testpool threads=100; ---- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" ---- config -location /hello { - default_type 'text/plain'; - - content_by_lua_block { - local ok, a, b = ngx.run_worker_thread("testpool", "hello", "hello") - ngx.say(ok) - ngx.say(a) - ngx.say(b) - } -} ---- user_files ->>> hello.lua -local function hello() - local newstr, n, err = ngx.re.gsub("hello, world", "([a-z])[a-z]+", "[$0,$1]", "i") - return newstr, n -end -return {hello=hello} ---- request -GET /hello ---- response_body -true -[hello,h], [world,w] -2 - - - -=== TEST 29: ngx.decode_base64 +=== TEST 24: ngx.decode_base64 --- main_config thread_pool testpool threads=100; --- http_config eval @@ -964,7 +804,7 @@ true : hello -=== TEST 30: ngx.crc32_short +=== TEST 25: ngx.crc32_short --- main_config thread_pool testpool threads=100; --- http_config eval @@ -991,7 +831,7 @@ true : 4289425978 -=== TEST 31: ngx.crc32_long +=== TEST 26: ngx.crc32_long --- main_config thread_pool testpool threads=100; --- http_config eval @@ -1018,7 +858,7 @@ true : 4289425978 -=== TEST 32: ngx.md5_bin +=== TEST 27: ngx.md5_bin --- main_config thread_pool testpool threads=100; --- http_config eval @@ -1049,7 +889,7 @@ true : 6c8349cc7260ae62e3b1396831a8398f -=== TEST 33: ngx.md5 +=== TEST 28: ngx.md5 --- main_config thread_pool testpool threads=100; --- http_config eval @@ -1076,7 +916,7 @@ true : 5d41402abc4b2a76b9719d911017c592 -=== TEST 34: ngx.config.debug +=== TEST 29: ngx.config.debug --- main_config thread_pool testpool threads=100; --- http_config eval @@ -1103,7 +943,7 @@ GET /hello -=== TEST 35: ngx.config.prefix +=== TEST 30: ngx.config.prefix --- main_config thread_pool testpool threads=100; --- http_config eval @@ -1130,7 +970,7 @@ GET /hello -=== TEST 36: ngx.config.nginx_version +=== TEST 31: ngx.config.nginx_version --- main_config thread_pool testpool threads=100; --- http_config eval @@ -1157,7 +997,7 @@ GET /hello -=== TEST 37: ngx.config.nginx_configure +=== TEST 32: ngx.config.nginx_configure --- main_config thread_pool testpool threads=100; --- http_config eval @@ -1184,7 +1024,7 @@ GET /hello -=== TEST 38: ngx.config.ngx_lua_version +=== TEST 33: ngx.config.ngx_lua_version --- main_config thread_pool testpool threads=100; --- http_config eval @@ -1211,7 +1051,7 @@ GET /hello -=== TEST 39: write_log_file +=== TEST 34: write_log_file --- main_config thread_pool testpool threads=100; --- http_config eval @@ -1249,7 +1089,7 @@ true -=== TEST 40: shdict get, int value +=== TEST 35: shdict get, int value --- main_config thread_pool testpool threads=100; --- http_config eval @@ -1282,7 +1122,7 @@ true,8 -=== TEST 41: shdict set nil in main thread +=== TEST 36: shdict set nil in main thread --- main_config thread_pool testpool threads=100; --- http_config eval @@ -1319,7 +1159,7 @@ true,nil -=== TEST 42: shdict set nil in worker thread +=== TEST 37: shdict set nil in worker thread --- main_config thread_pool testpool threads=100; --- http_config eval @@ -1354,7 +1194,7 @@ true,nil -=== TEST 43: shdict get_stale +=== TEST 38: shdict get_stale --- main_config thread_pool testpool threads=100; --- http_config eval @@ -1388,7 +1228,7 @@ true,8 -=== TEST 44: shdict add failed +=== TEST 39: shdict add failed --- main_config thread_pool testpool threads=100; --- http_config eval @@ -1422,7 +1262,7 @@ true,false,exists -=== TEST 45: shdict force add +=== TEST 40: shdict force add --- main_config thread_pool testpool threads=100; --- http_config eval @@ -1458,7 +1298,7 @@ true,true,true,nil -=== TEST 46: shdict replace +=== TEST 41: shdict replace --- main_config thread_pool testpool threads=100; --- http_config eval @@ -1493,7 +1333,7 @@ true,true,nil,8 -=== TEST 47: shdict replace not found +=== TEST 42: shdict replace not found --- main_config thread_pool testpool threads=100; --- http_config eval @@ -1526,7 +1366,7 @@ true,false,not found -=== TEST 48: shdict incr +=== TEST 43: shdict incr --- main_config thread_pool testpool threads=100; --- http_config eval @@ -1560,7 +1400,7 @@ true,9,nil,9 -=== TEST 49: shdict lpush lpop +=== TEST 44: shdict lpush lpop --- main_config thread_pool testpool threads=100; --- http_config eval @@ -1596,7 +1436,7 @@ true,9,2,nil,7 -=== TEST 50: shdict expire ttl +=== TEST 45: shdict expire ttl --- main_config thread_pool testpool threads=100; --- http_config eval @@ -1630,7 +1470,7 @@ true,true,nil,true -=== TEST 51: shdict flush_all +=== TEST 46: shdict flush_all --- main_config thread_pool testpool threads=100; --- http_config eval @@ -1664,7 +1504,7 @@ true,nil,nil -=== TEST 52: shdict get_keys +=== TEST 47: shdict get_keys --- main_config thread_pool testpool threads=100; --- http_config eval @@ -1698,7 +1538,7 @@ true,Jim:King -=== TEST 53: unsupported argument type in self-reference table +=== TEST 48: unsupported argument type in self-reference table --- main_config thread_pool testpool threads=100; --- http_config eval @@ -1727,7 +1567,7 @@ false , suspicious circular references, table depth exceed max depth: 100 in the -=== TEST 54: unsupported argument type in circular-reference table +=== TEST 49: unsupported argument type in circular-reference table --- main_config thread_pool testpool threads=100; --- http_config eval From e69fd3de281f31804857aa6dc0b8e79055716138 Mon Sep 17 00:00:00 2001 From: swananan Date: Sun, 6 Aug 2023 08:02:34 +0800 Subject: [PATCH 107/254] feature: upgrade nginx core to 1.25.1. --- .travis.yml | 2 ++ t/028-req-header.t | 10 +++++++-- t/129-ssl-socket.t | 8 +++---- t/142-ssl-session-store.t | 12 +++++++++++ t/162-socket-tls-handshake.t | 8 +++---- util/build-with-dd.sh | 14 ++++++++++++ util/build-without-ssl.sh | 7 ++++++ util/build.sh | 14 ++++++++++++ util/ver-ge | 41 ++++++++++++++++++++++++++++++++++++ 9 files changed, 106 insertions(+), 10 deletions(-) create mode 100755 util/ver-ge diff --git a/.travis.yml b/.travis.yml index 64d27d8529..19f560a4fe 100644 --- a/.travis.yml +++ b/.travis.yml @@ -54,6 +54,8 @@ env: jobs: - NGINX_VERSION=1.21.4 OPENSSL_VER=1.1.0l OPENSSL_PATCH_VER=1.1.0d - NGINX_VERSION=1.21.4 OPENSSL_VER=1.1.1s OPENSSL_PATCH_VER=1.1.1f + - NGINX_VERSION=1.25.1 OPENSSL_VER=1.1.0l OPENSSL_PATCH_VER=1.1.0d + - NGINX_VERSION=1.25.1 OPENSSL_VER=1.1.1s OPENSSL_PATCH_VER=1.1.1f services: - memcached diff --git a/t/028-req-header.t b/t/028-req-header.t index 8c8ff83fd8..f4c393977d 100644 --- a/t/028-req-header.t +++ b/t/028-req-header.t @@ -273,8 +273,14 @@ Content-Type: } --- request GET /bar ---- response_body -Foo: a +--- response_body eval +# Since nginx version 1.23.0, nginx combines same $http_* variable together +# wtf +$Test::Nginx::Util::NginxVersion >= 1.023000 ? + +"Foo: a, b\n" +: +"Foo: a\n" diff --git a/t/129-ssl-socket.t b/t/129-ssl-socket.t index 7e48d59bca..85d3a80985 100644 --- a/t/129-ssl-socket.t +++ b/t/129-ssl-socket.t @@ -39,7 +39,7 @@ run_tests(); __DATA__ -=== TEST 1: www.bing.com +=== TEST 1: www.google.com --- config server_tokens off; resolver $TEST_NGINX_RESOLVER ipv6=off; @@ -62,7 +62,7 @@ __DATA__ do local sock = ngx.socket.tcp() sock:settimeout(2000) - local ok, err = sock:connect("www.bing.com", 443) + local ok, err = sock:connect("www.google.com", 443) if not ok then ngx.say("failed to connect: ", err) return @@ -78,7 +78,7 @@ __DATA__ ngx.say("ssl handshake: ", type(sess)) - local req = "GET / HTTP/1.1\\r\\nHost: www.bing.com\\r\\nConnection: close\\r\\n\\r\\n" + local req = "GET / HTTP/1.1\\r\\nHost: www.google.com\\r\\nConnection: close\\r\\n\\r\\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) @@ -107,7 +107,7 @@ GET /t --- response_body_like chop \Aconnected: 1 ssl handshake: cdata -sent http request: 57 bytes. +sent http request: 59 bytes. received: HTTP/1.1 (?:200 OK|302 Found) close: 1 nil \z diff --git a/t/142-ssl-session-store.t b/t/142-ssl-session-store.t index 61598732be..ead2a167e5 100644 --- a/t/142-ssl-session-store.t +++ b/t/142-ssl-session-store.t @@ -40,6 +40,7 @@ __DATA__ server_tokens off; resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + lua_ssl_protocols TLSv1.2; location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -115,6 +116,7 @@ ssl_session_store_by_lua\(nginx\.conf:25\):1: ssl session store by lua is runnin server_tokens off; resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + lua_ssl_protocols TLSv1.2; location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -190,6 +192,7 @@ API disabled in the context of ssl_session_store_by_lua* server_tokens off; resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + lua_ssl_protocols TLSv1.2; location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -282,6 +285,7 @@ my timer run! server_tokens off; resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + lua_ssl_protocols TLSv1.2; location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -351,6 +355,7 @@ API disabled in the context of ssl_session_store_by_lua* resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; lua_ssl_verify_depth 3; + lua_ssl_protocols TLSv1.2; location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -423,6 +428,7 @@ ngx.exit does not yield and the error code is eaten. resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; lua_ssl_verify_depth 3; + lua_ssl_protocols TLSv1.2; location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -496,6 +502,7 @@ ssl_session_store_by_lua*: handler return value: 0, sess new cb exit code: 0 resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; lua_ssl_verify_depth 3; + lua_ssl_protocols TLSv1.2; location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -564,6 +571,7 @@ should never reached here resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; lua_ssl_verify_depth 3; + lua_ssl_protocols TLSv1.2; location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -634,6 +642,7 @@ get_phase: ssl_session_store server_tokens off; resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + lua_ssl_protocols TLSv1.2; location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -703,6 +712,7 @@ qr/elapsed in ssl cert by lua: 0.(?:09|1[01])\d+,/, server_tokens off; resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + lua_ssl_protocols TLSv1.2; location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -784,6 +794,7 @@ a.lua:1: ssl store session by lua is running! resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; lua_ssl_verify_depth 3; + lua_ssl_protocols TLSv1.2; location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -854,6 +865,7 @@ qr/\[emerg\] .*? "ssl_session_store_by_lua_block" directive is not allowed here server_tokens off; resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + lua_ssl_protocols TLSv1.2; location /t { set $port $TEST_NGINX_MEMCACHED_PORT; diff --git a/t/162-socket-tls-handshake.t b/t/162-socket-tls-handshake.t index 80fb2f9825..19ad67a749 100644 --- a/t/162-socket-tls-handshake.t +++ b/t/162-socket-tls-handshake.t @@ -63,7 +63,7 @@ run_tests(); __DATA__ -=== TEST 1: sanity: www.bing.com +=== TEST 1: sanity: www.google.com --- config server_tokens off; resolver $TEST_NGINX_RESOLVER ipv6=off; @@ -86,7 +86,7 @@ __DATA__ local sock = ngx.socket.tcp() sock:settimeout(2000) - local ok, err = sock:connect("www.bing.com", 443) + local ok, err = sock:connect("www.google.com", 443) if not ok then ngx.say("failed to connect: ", err) return @@ -102,7 +102,7 @@ __DATA__ ngx.say("ssl handshake: ", type(sess)) - local req = "GET / HTTP/1.1\r\nHost: www.bing.com\r\nConnection: close\r\n\r\n" + local req = "GET / HTTP/1.1\r\nHost: www.google.com\r\nConnection: close\r\n\r\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) @@ -131,7 +131,7 @@ GET /t --- response_body_like chop \Aconnected: 1 ssl handshake: cdata -sent http request: 57 bytes. +sent http request: 59 bytes. received: HTTP/1.1 (?:200 OK|302 Found) close: 1 nil \z diff --git a/util/build-with-dd.sh b/util/build-with-dd.sh index 41ecc72685..db318ce391 100755 --- a/util/build-with-dd.sh +++ b/util/build-with-dd.sh @@ -12,12 +12,26 @@ force=$2 add_fake_shm_module="--add-module=$root/t/data/fake-shm-module" +add_http3_module=--with-http_v3_module +answer=`$root/util/ver-ge "$NGINX_VERSION" 1.25.1` +if [ "$OPENSSL_VER" = "1.1.0l" ] || [ "$answer" = "N" ]; then + add_http3_module="" +fi + +disable_pcre2=--without-pcre2 +answer=`$root/util/ver-ge "$NGINX_VERSION" 1.25.1` +if [ "$answer" = "N" ]; then + disable_pcre2="" +fi + time ngx-build $force $version \ --with-threads \ --with-pcre-jit \ + $disable_pcre2 \ --with-ipv6 \ --with-cc-opt="-DNGX_LUA_USE_ASSERT -I$PCRE_INC -I$OPENSSL_INC -DDDEBUG=1" \ --with-http_v2_module \ + $add_http3_module \ --with-http_realip_module \ --with-http_ssl_module \ --add-module=$root/../ndk-nginx-module \ diff --git a/util/build-without-ssl.sh b/util/build-without-ssl.sh index 906be75706..97097daac0 100755 --- a/util/build-without-ssl.sh +++ b/util/build-without-ssl.sh @@ -24,9 +24,16 @@ force=$2 add_fake_shm_module="--add-module=$root/t/data/fake-shm-module" +disable_pcre2=--without-pcre2 +answer=`$root/util/ver-ge "$NGINX_VERSION" 1.25.1` +if [ "$answer" = "N" ]; then + disable_pcre2="" +fi + time ngx-build $force $version \ --with-threads \ --with-pcre-jit \ + $disable_pcre2 \ --with-ipv6 \ --with-cc-opt="-DNGX_LUA_USE_ASSERT -I$PCRE_INC" \ --with-http_v2_module \ diff --git a/util/build.sh b/util/build.sh index 713b8482d3..3a786a186f 100755 --- a/util/build.sh +++ b/util/build.sh @@ -24,12 +24,26 @@ force=$2 add_fake_shm_module="--add-module=$root/t/data/fake-shm-module" +add_http3_module=--with-http_v3_module +answer=`$root/util/ver-ge "$NGINX_VERSION" 1.25.1` +if [ "$OPENSSL_VER" = "1.1.0l" ] || [ "$answer" = "N" ]; then + add_http3_module="" +fi + +disable_pcre2=--without-pcre2 +answer=`$root/util/ver-ge "$NGINX_VERSION" 1.25.1` +if [ "$answer" = "N" ]; then + disable_pcre2="" +fi + time ngx-build $force $version \ --with-threads \ --with-pcre-jit \ + $disable_pcre2 \ --with-ipv6 \ --with-cc-opt="-DNGX_LUA_USE_ASSERT -I$PCRE_INC -I$OPENSSL_INC" \ --with-http_v2_module \ + $add_http3_module \ --with-http_realip_module \ --with-http_ssl_module \ --add-module=$root/../ndk-nginx-module \ diff --git a/util/ver-ge b/util/ver-ge new file mode 100755 index 0000000000..8d7a401e94 --- /dev/null +++ b/util/ver-ge @@ -0,0 +1,41 @@ +#!/usr/bin/env perl + +use strict; +use warnings; + +sub usage { + die "Usage: $0 \n"; +} + +my $a = shift or usage(); +my $b = shift or usage(); + +my @as = split /\./, $a; +my @bs = split /\./, $b; + +my $n = @as > @bs ? scalar(@as) : scalar(@bs); + +for (my $i = 0; $i < $n; $i++) { + my $x = $as[$i]; + my $y = $bs[$i]; + + if (!defined $x) { + $x = 0; + } + + if (!defined $y) { + $y = 0; + } + + if ($x > $y) { + print "Y\n"; + exit; + + } elsif ($x < $y) { + print "N\n"; + exit; + } +} + +print "Y\n"; + From 25b7959b29e73069823bbdeb466b49aa12194bb9 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Mon, 7 Aug 2023 21:48:50 +0800 Subject: [PATCH 108/254] bugfix: fixed compilation error: variable 'nelts' set but not used. --- src/ngx_http_lua_headers_in.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/ngx_http_lua_headers_in.c b/src/ngx_http_lua_headers_in.c index 960e2f85f6..e756700b06 100644 --- a/src/ngx_http_lua_headers_in.c +++ b/src/ngx_http_lua_headers_in.c @@ -591,19 +591,21 @@ ngx_http_set_builtin_multi_header(ngx_http_request_t *r, { #if defined(nginx_version) && nginx_version >= 1023000 ngx_table_elt_t **headers, **ph, *h; - int nelts; headers = (ngx_table_elt_t **) ((char *) &r->headers_in + hv->offset); if (!hv->no_override && *headers != NULL) { - nelts = 0; +#if defined(DDEBUG) && (DDEBUG) + int nelts = 0; + for (h = *headers; h; h = h->next) { nelts++; } - *headers = NULL; - dd("clear multi-value headers: %d", nelts); +#endif + + *headers = NULL; } if (ngx_http_set_header_helper(r, hv, value, &h) == NGX_ERROR) { From e2d0505955de189d55187c4bf24c400fa4215329 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Tue, 8 Aug 2023 16:02:11 +0800 Subject: [PATCH 109/254] doc: revise the description regarding Nginx compatibility. --- README.markdown | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.markdown b/README.markdown index ac04585c5a..021251dfce 100644 --- a/README.markdown +++ b/README.markdown @@ -309,6 +309,8 @@ Nginx Compatibility The latest version of this module is compatible with the following versions of Nginx: +* 1.25.x (last tested: 1.25.1) +* 1.21.x (last tested: 1.21.4) * 1.19.x (last tested: 1.19.3) * 1.17.x (last tested: 1.17.8) * 1.15.x (last tested: 1.15.8) From c89469e920713d17d703a5f3736c9335edac22bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BD=97=E6=B3=BD=E8=BD=A9?= Date: Sat, 19 Aug 2023 22:26:55 +0800 Subject: [PATCH 110/254] doc: update release date Signed-off-by: spacewander --- README.markdown | 4 ++-- doc/HttpLuaModule.wiki | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.markdown b/README.markdown index 021251dfce..29945d4997 100644 --- a/README.markdown +++ b/README.markdown @@ -65,8 +65,8 @@ Version ======= This document describes ngx_lua -[v0.10.19](https://github.com/openresty/lua-nginx-module/tags), which was released -on 3 Nov, 2020. +[v0.10.25](https://github.com/openresty/lua-nginx-module/tags), which was released +on 19 June 2023. Videos ====== diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 8d003bd602..678e60b47c 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -17,8 +17,8 @@ Production ready. = Version = This document describes ngx_lua -[https://github.com/openresty/lua-nginx-module/tags v0.10.19], which was released -on 3 Nov, 2020. +[https://github.com/openresty/lua-nginx-module/tags v0.10.25], which was released +on 19 June 2023. = Videos = From cb83e33e26579788be0fe0282fa5976de6dfa6e3 Mon Sep 17 00:00:00 2001 From: swananan Date: Sat, 23 Sep 2023 08:20:12 +0800 Subject: [PATCH 111/254] feature: support pcre2 Signed-off-by: lijunlong --- .travis.yml | 17 +- src/ngx_http_lua_common.h | 10 +- src/ngx_http_lua_module.c | 14 + src/ngx_http_lua_pcrefix.c | 88 +++++- src/ngx_http_lua_pcrefix.h | 9 +- src/ngx_http_lua_regex.c | 539 +++++++++++++++++++++++++++++++------ t/028-req-header.t | 1 - t/034-match.t | 32 ++- t/035-gmatch.t | 24 +- t/036-sub.t | 24 +- t/037-gsub.t | 17 +- t/038-match-o.t | 7 +- t/047-match-jit.t | 48 +++- t/049-gmatch-jit.t | 67 ++++- t/050-gmatch-dfa.t | 7 +- t/051-sub-jit.t | 44 ++- t/052-sub-dfa.t | 14 +- t/053-gsub-jit.t | 44 ++- t/054-gsub-dfa.t | 14 +- t/120-re-find.t | 25 +- t/cert/test.crt | 35 +-- t/cert/test.key | 43 +-- util/build-with-dd.sh | 6 +- util/build-without-ssl.sh | 6 +- util/build.sh | 6 +- valgrind.suppress | 70 +++++ 26 files changed, 998 insertions(+), 213 deletions(-) diff --git a/.travis.yml b/.travis.yml index 19f560a4fe..b29ab4cc2a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -38,9 +38,13 @@ env: - LUAJIT_INC=$LUAJIT_PREFIX/include/luajit-2.1 - LUA_INCLUDE_DIR=$LUAJIT_INC - PCRE_VER=8.45 + - PCRE2_VER=10.37 - PCRE_PREFIX=/opt/pcre + - PCRE2_PREFIX=/opt/pcre2 - PCRE_LIB=$PCRE_PREFIX/lib + - PCRE2_LIB=$PCRE2_PREFIX/lib - PCRE_INC=$PCRE_PREFIX/include + - PCRE2_INC=$PCRE2_PREFIX/include - OPENSSL_PREFIX=/opt/ssl - OPENSSL_LIB=$OPENSSL_PREFIX/lib - OPENSSL_INC=$OPENSSL_PREFIX/include @@ -55,7 +59,7 @@ env: - NGINX_VERSION=1.21.4 OPENSSL_VER=1.1.0l OPENSSL_PATCH_VER=1.1.0d - NGINX_VERSION=1.21.4 OPENSSL_VER=1.1.1s OPENSSL_PATCH_VER=1.1.1f - NGINX_VERSION=1.25.1 OPENSSL_VER=1.1.0l OPENSSL_PATCH_VER=1.1.0d - - NGINX_VERSION=1.25.1 OPENSSL_VER=1.1.1s OPENSSL_PATCH_VER=1.1.1f + - NGINX_VERSION=1.25.1 OPENSSL_VER=1.1.1s OPENSSL_PATCH_VER=1.1.1f USE_PCRE2=Y services: - memcached @@ -71,7 +75,8 @@ before_install: - pyenv global 2.7 install: - if [ ! -f download-cache/drizzle7-$DRIZZLE_VER.tar.gz ]; then wget -P download-cache http://openresty.org/download/drizzle7-$DRIZZLE_VER.tar.gz; fi - - if [ ! -f download-cache/pcre-$PCRE_VER.tar.gz ]; then wget -P download-cache https://downloads.sourceforge.net/project/pcre/pcre/${PCRE_VER}/pcre-${PCRE_VER}.tar.gz; fi + - if [ "$USE_PCRE2" != "Y" ] && [ ! -f download-cache/pcre-$PCRE_VER.tar.gz ]; then wget -P download-cache https://downloads.sourceforge.net/project/pcre/pcre/${PCRE_VER}/pcre-${PCRE_VER}.tar.gz; fi + - if [ "$USE_PCRE2" = "Y" ] && [ ! -f download-cache/pcre2-$PCRE2_VER.tar.gz ]; then wget -P download-cache https://downloads.sourceforge.net/project/pcre/pcre2/${PCRE2_VER}/pcre2-${PCRE2_VER}.tar.gz; fi - if [ ! -f download-cache/openssl-$OPENSSL_VER.tar.gz ]; then wget -P download-cache https://www.openssl.org/source/openssl-$OPENSSL_VER.tar.gz || wget -P download-cache https://www.openssl.org/source/old/${OPENSSL_VER//[a-z]/}/openssl-$OPENSSL_VER.tar.gz; fi - git clone https://github.com/openresty/test-nginx.git - git clone https://github.com/openresty/openresty.git ../openresty @@ -121,12 +126,8 @@ script: - sudo make install-libdrizzle-1.0 > build.log 2>&1 || (cat build.log && exit 1) - cd ../mockeagain/ && make CC=$CC -j$JOBS && cd .. - cd lua-cjson/ && make -j$JOBS && sudo make install && cd .. - - tar zxf download-cache/pcre-$PCRE_VER.tar.gz - - cd pcre-$PCRE_VER/ - - ./configure --prefix=$PCRE_PREFIX --enable-jit --enable-utf --enable-unicode-properties > build.log 2>&1 || (cat build.log && exit 1) - - make -j$JOBS > build.log 2>&1 || (cat build.log && exit 1) - - sudo PATH=$PATH make install > build.log 2>&1 || (cat build.log && exit 1) - - cd .. + - if [ "$USE_PCRE2" != "Y" ]; then tar zxf download-cache/pcre-$PCRE_VER.tar.gz; cd pcre-$PCRE_VER/; ./configure --prefix=$PCRE_PREFIX --enable-jit --enable-utf --enable-unicode-properties > build.log 2>&1 || (cat build.log && exit 1); make -j$JOBS > build.log 2>&1 || (cat build.log && exit 1); sudo PATH=$PATH make install > build.log 2>&1 || (cat build.log && exit 1); cd ..; fi + - if [ "$USE_PCRE2" = "Y" ]; then tar zxf download-cache/pcre2-$PCRE2_VER.tar.gz; cd pcre2-$PCRE2_VER/; ./configure --prefix=$PCRE2_PREFIX --enable-jit --enable-utf > build.log 2>&1 || (cat build.log && exit 1); make -j$JOBS > build.log 2>&1 || (cat build.log && exit 1); sudo PATH=$PATH make install > build.log 2>&1 || (cat build.log && exit 1); cd ..; fi - tar zxf download-cache/openssl-$OPENSSL_VER.tar.gz - cd openssl-$OPENSSL_VER/ - patch -p1 < ../../openresty/patches/openssl-$OPENSSL_PATCH_VER-sess_set_get_cb_yield.patch diff --git a/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h index 7d9e10cea1..541fa881db 100644 --- a/src/ngx_http_lua_common.h +++ b/src/ngx_http_lua_common.h @@ -63,6 +63,10 @@ typedef struct { # endif #endif +#if (NGX_PCRE2) +# define LUA_HAVE_PCRE_JIT 1 +#endif + #if (nginx_version < 1006000) # error at least nginx 1.6.0 is required but found an older version @@ -217,11 +221,13 @@ struct ngx_http_lua_main_conf_s { ngx_hash_t builtin_headers_out; -#if (NGX_PCRE) +#if (NGX_PCRE || NGX_PCRE2) ngx_int_t regex_cache_entries; ngx_int_t regex_cache_max_entries; ngx_int_t regex_match_limit; -# if (LUA_HAVE_PCRE_JIT) +#if (NGX_PCRE2) + pcre2_jit_stack *jit_stack; +#elif (LUA_HAVE_PCRE_JIT) pcre_jit_stack *jit_stack; # endif #endif diff --git a/src/ngx_http_lua_module.c b/src/ngx_http_lua_module.c index 4d47e83e20..6984fb087d 100644 --- a/src/ngx_http_lua_module.c +++ b/src/ngx_http_lua_module.c @@ -59,6 +59,9 @@ static char *ngx_http_lua_ssl_conf_command_check(ngx_conf_t *cf, void *post, #endif static char *ngx_http_lua_malloc_trim(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +#if (NGX_PCRE2) +extern void ngx_http_lua_regex_cleanup(void *data); +#endif static ngx_conf_post_t ngx_http_lua_lowat_post = @@ -855,6 +858,17 @@ ngx_http_lua_init(ngx_conf_t *cf) cln->data = lmcf; cln->handler = ngx_http_lua_sema_mm_cleanup; +#if (NGX_PCRE2) + /* add the cleanup of pcre2 regex */ + cln = ngx_pool_cleanup_add(cf->pool, 0); + if (cln == NULL) { + return NGX_ERROR; + } + + cln->data = lmcf; + cln->handler = ngx_http_lua_regex_cleanup; +#endif + #ifdef HAVE_NGX_LUA_PIPE ngx_http_lua_pipe_init(); #endif diff --git a/src/ngx_http_lua_pcrefix.c b/src/ngx_http_lua_pcrefix.c index 562847a639..76e745e6db 100644 --- a/src/ngx_http_lua_pcrefix.c +++ b/src/ngx_http_lua_pcrefix.c @@ -14,19 +14,65 @@ #include "ngx_http_lua_pcrefix.h" #include "stdio.h" -#if (NGX_PCRE) +#if (NGX_PCRE || NGX_PCRE2) static ngx_pool_t *ngx_http_lua_pcre_pool = NULL; + +#if (NGX_PCRE2) +static ngx_uint_t ngx_regex_direct_alloc; +#else static void *(*old_pcre_malloc)(size_t); static void (*old_pcre_free)(void *ptr); +#endif /* XXX: work-around to nginx regex subsystem, must init a memory pool * to use PCRE functions. As PCRE still has memory-leaking problems, * and nginx overwrote pcre_malloc/free hooks with its own static * functions, so nobody else can reuse nginx regex subsystem... */ -static void * +#if (NGX_PCRE2) + +void * +ngx_http_lua_pcre_malloc(size_t size, void *data) +{ + dd("lua pcre pool is %p", ngx_http_lua_pcre_pool); + + if (ngx_http_lua_pcre_pool) { + return ngx_palloc(ngx_http_lua_pcre_pool, size); + } + + if (ngx_regex_direct_alloc) { + return ngx_alloc(size, ngx_cycle->log); + } + + fprintf(stderr, "error: lua pcre malloc failed due to empty pcre pool"); + + return NULL; +} + + +void +ngx_http_lua_pcre_free(void *ptr, void *data) +{ + dd("lua pcre pool is %p", ngx_http_lua_pcre_pool); + + if (ngx_http_lua_pcre_pool) { + ngx_pfree(ngx_http_lua_pcre_pool, ptr); + return; + } + + if (ngx_regex_direct_alloc) { + ngx_free(ptr); + return; + } + + fprintf(stderr, "error: lua pcre free failed due to empty pcre pool"); +} + +#else + +void * ngx_http_lua_pcre_malloc(size_t size) { dd("lua pcre pool is %p", ngx_http_lua_pcre_pool); @@ -54,6 +100,41 @@ ngx_http_lua_pcre_free(void *ptr) fprintf(stderr, "error: lua pcre free failed due to empty pcre pool"); } +#endif + + +#if (NGX_PCRE2) + +ngx_pool_t * +ngx_http_lua_pcre_malloc_init(ngx_pool_t *pool) +{ + ngx_pool_t *old_pool; + + dd("lua pcre pool was %p", ngx_http_lua_pcre_pool); + + ngx_regex_direct_alloc = (pool == NULL) ? 1 : 0; + + old_pool = ngx_http_lua_pcre_pool; + ngx_http_lua_pcre_pool = pool; + + dd("lua pcre pool is %p", ngx_http_lua_pcre_pool); + + return old_pool; +} + + +void +ngx_http_lua_pcre_malloc_done(ngx_pool_t *old_pool) +{ + dd("lua pcre pool was %p", ngx_http_lua_pcre_pool); + + ngx_http_lua_pcre_pool = old_pool; + ngx_regex_direct_alloc = 0; + + dd("lua pcre pool is %p", ngx_http_lua_pcre_pool); +} + +#else ngx_pool_t * ngx_http_lua_pcre_malloc_init(ngx_pool_t *pool) @@ -101,6 +182,7 @@ ngx_http_lua_pcre_malloc_done(ngx_pool_t *old_pool) } } -#endif /* NGX_PCRE */ +#endif +#endif /* NGX_PCRE || NGX_PCRE2 */ /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_pcrefix.h b/src/ngx_http_lua_pcrefix.h index 80f29f9e75..ef09636313 100644 --- a/src/ngx_http_lua_pcrefix.h +++ b/src/ngx_http_lua_pcrefix.h @@ -12,9 +12,16 @@ #include "ngx_http_lua_common.h" -#if (NGX_PCRE) +#if (NGX_PCRE || NGX_PCRE2) + ngx_pool_t *ngx_http_lua_pcre_malloc_init(ngx_pool_t *pool); void ngx_http_lua_pcre_malloc_done(ngx_pool_t *old_pool); + +#if NGX_PCRE2 +void *ngx_http_lua_pcre_malloc(size_t size, void *data); +void ngx_http_lua_pcre_free(void *ptr, void *data); +#endif + #endif diff --git a/src/ngx_http_lua_regex.c b/src/ngx_http_lua_regex.c index 5c17cfe09c..7317451f65 100644 --- a/src/ngx_http_lua_regex.c +++ b/src/ngx_http_lua_regex.c @@ -9,21 +9,31 @@ #endif #include "ddebug.h" - -#if (NGX_PCRE) +#if (NGX_PCRE || NGX_PCRE2) #include "ngx_http_lua_pcrefix.h" #include "ngx_http_lua_script.h" #include "ngx_http_lua_util.h" -#if (PCRE_MAJOR >= 6) +#if (PCRE_MAJOR >= 6 || NGX_PCRE2) # define LUA_HAVE_PCRE_DFA 1 #else # define LUA_HAVE_PCRE_DFA 0 #endif +#if (NGX_PCRE2) +static pcre2_compile_context *ngx_regex_compile_context; +static pcre2_match_context *ngx_regex_match_context; +static pcre2_match_data *ngx_regex_match_data; +static ngx_uint_t ngx_regex_match_data_size = 0; + +#define PCRE2_VERSION_SIZE 64 +static char ngx_pcre2_version[PCRE2_VERSION_SIZE]; +#endif + + #define NGX_LUA_RE_MODE_DFA (1<<1) #define NGX_LUA_RE_MODE_JIT (1<<2) #define NGX_LUA_RE_NO_UTF8_CHECK (1<<4) @@ -42,8 +52,17 @@ typedef struct { int ncaptures; int *captures; +#if (NGX_PCRE2) + pcre2_code *regex; + /* + * pcre2 doesn't use pcre_extra any more, + * just for keeping same memory layout in the lua ffi cdef + */ + void *regex_sd; +#else pcre *regex; pcre_extra *regex_sd; +#endif ngx_http_lua_complex_value_t *replace; @@ -57,7 +76,11 @@ typedef struct { ngx_pool_t *pool; ngx_int_t options; +#if (NGX_PCRE2) + pcre2_code *regex; +#else pcre *regex; +#endif int captures; ngx_str_t err; } ngx_http_lua_regex_compile_t; @@ -65,8 +88,12 @@ typedef struct { typedef struct { ngx_http_request_t *request; +#if (NGX_PCRE2) + pcre2_code *regex; +#else pcre *regex; pcre_extra *regex_sd; +#endif int ncaptures; int *captures; int captures_len; @@ -74,8 +101,6 @@ typedef struct { } ngx_http_lua_regex_ctx_t; -static void ngx_http_lua_regex_free_study_data(ngx_pool_t *pool, - pcre_extra *sd); static ngx_int_t ngx_http_lua_regex_compile(ngx_http_lua_regex_compile_t *rc); @@ -91,21 +116,155 @@ static ngx_int_t ngx_http_lua_regex_compile(ngx_http_lua_regex_compile_t *rc); static void -ngx_http_lua_regex_free_study_data(ngx_pool_t *pool, pcre_extra *sd) +ngx_http_lua_regex_free_study_data(ngx_pool_t *pool, ngx_http_lua_regex_t *re) { - ngx_pool_t *old_pool; + ngx_pool_t *old_pool; - old_pool = ngx_http_lua_pcre_malloc_init(pool); +#if (NGX_PCRE2) + if (re && re->regex) { + old_pool = ngx_http_lua_pcre_malloc_init(pool); + + pcre2_code_free(re->regex); + + ngx_http_lua_pcre_malloc_done(old_pool); + re->regex = NULL; + } +#else + if (re && re->regex_sd) { + old_pool = ngx_http_lua_pcre_malloc_init(pool); #if LUA_HAVE_PCRE_JIT - pcre_free_study(sd); + pcre_free_study(re->regex_sd); #else - pcre_free(sd); + pcre_free(re->regex_sd); #endif + ngx_http_lua_pcre_malloc_done(old_pool); + + re->regex_sd = NULL; + } +#endif +} + + +#if (NGX_PCRE2) +static ngx_int_t +ngx_http_lua_regex_compile(ngx_http_lua_regex_compile_t *rc) +{ + int n, errcode; + char *p; + size_t erroff; + u_char errstr[128]; + pcre2_code *re; + ngx_pool_t *old_pool; + pcre2_general_context *gctx; + pcre2_compile_context *cctx; + + ngx_http_lua_main_conf_t *lmcf; + + if (ngx_regex_compile_context == NULL) { + /* + * Allocate a compile context if not yet allocated. This uses + * direct allocations from heap, so the result can be cached + * even at runtime. + */ + + old_pool = ngx_http_lua_pcre_malloc_init(NULL); + + gctx = pcre2_general_context_create(ngx_http_lua_pcre_malloc, + ngx_http_lua_pcre_free, + NULL); + if (gctx == NULL) { + ngx_http_lua_pcre_malloc_done(old_pool); + goto nomem; + } + + cctx = pcre2_compile_context_create(gctx); + if (cctx == NULL) { + pcre2_general_context_free(gctx); + ngx_http_lua_pcre_malloc_done(old_pool); + goto nomem; + } + + ngx_regex_compile_context = cctx; + + ngx_regex_match_context = pcre2_match_context_create(gctx); + if (ngx_regex_match_context == NULL) { + pcre2_general_context_free(gctx); + ngx_http_lua_pcre_malloc_done(old_pool); + goto nomem; + } + + lmcf = ngx_http_cycle_get_module_main_conf(ngx_cycle, + ngx_http_lua_module); + if (lmcf && lmcf->regex_match_limit > 0) { + pcre2_set_match_limit(ngx_regex_match_context, + lmcf->regex_match_limit); + } + + pcre2_general_context_free(gctx); + ngx_http_lua_pcre_malloc_done(old_pool); + } + + old_pool = ngx_http_lua_pcre_malloc_init(rc->pool); + + re = pcre2_compile(rc->pattern.data, + rc->pattern.len, rc->options, + &errcode, &erroff, ngx_regex_compile_context); ngx_http_lua_pcre_malloc_done(old_pool); + + if (re == NULL) { + pcre2_get_error_message(errcode, errstr, 128); + + if ((size_t) erroff == rc->pattern.len) { + rc->err.len = ngx_snprintf(rc->err.data, rc->err.len, + "pcre2_compile() failed: %s in \"%V\"", + errstr, &rc->pattern) + - rc->err.data; + + } else { + rc->err.len = ngx_snprintf(rc->err.data, rc->err.len, + "pcre2_compile() failed: %s in " + "\"%V\" at \"%s\"", errstr, &rc->pattern, + rc->pattern.data + erroff) + - rc->err.data; + } + + return NGX_ERROR; + } + + rc->regex = re; + + n = pcre2_pattern_info(re, PCRE2_INFO_CAPTURECOUNT, &rc->captures); + if (n < 0) { + p = "pcre2_pattern_info(\"%V\", PCRE_INFO_CAPTURECOUNT) failed: %d"; + goto failed; + } + +#if (NGX_DEBUG) + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "pcre2_compile: pattern[%V], options 0x%08Xd, ncaptures %d", + &rc->pattern, rc->options, rc->captures); +#endif + + return NGX_OK; + +failed: + + rc->err.len = ngx_snprintf(rc->err.data, rc->err.len, p, &rc->pattern, n) + - rc->err.data; + return NGX_ERROR; + +nomem: + + rc->err.len = ngx_snprintf(rc->err.data, rc->err.len, + "regex \"%V\" compilation failed: no memory", + &rc->pattern) + - rc->err.data; + return NGX_ERROR; } +#else static ngx_int_t ngx_http_lua_regex_compile(ngx_http_lua_regex_compile_t *rc) @@ -159,13 +318,14 @@ ngx_http_lua_regex_compile(ngx_http_lua_regex_compile_t *rc) - rc->err.data; return NGX_OK; } +#endif ngx_int_t ngx_http_lua_ffi_set_jit_stack_size(int size, u_char *errstr, size_t *errstr_size) { -#if LUA_HAVE_PCRE_JIT +#if (NGX_PCRE2 || LUA_HAVE_PCRE_JIT) ngx_http_lua_main_conf_t *lmcf; ngx_pool_t *pool, *old_pool; @@ -186,15 +346,24 @@ ngx_http_lua_ffi_set_jit_stack_size(int size, u_char *errstr, if (lmcf->jit_stack) { old_pool = ngx_http_lua_pcre_malloc_init(pool); +#if (NGX_PCRE2) + pcre2_jit_stack_free(lmcf->jit_stack); +#else pcre_jit_stack_free(lmcf->jit_stack); +#endif ngx_http_lua_pcre_malloc_done(old_pool); } old_pool = ngx_http_lua_pcre_malloc_init(pool); +#if (NGX_PCRE2) + lmcf->jit_stack = pcre2_jit_stack_create(NGX_LUA_RE_MIN_JIT_STACK_SIZE, + size, NULL); +#else lmcf->jit_stack = pcre_jit_stack_alloc(NGX_LUA_RE_MIN_JIT_STACK_SIZE, size); +#endif ngx_http_lua_pcre_malloc_done(old_pool); @@ -214,8 +383,148 @@ ngx_http_lua_ffi_set_jit_stack_size(int size, u_char *errstr, - errstr; return NGX_ERROR; +#endif +} + + +#if (NGX_PCRE2) +static void +ngx_http_lua_regex_jit_compile(ngx_http_lua_regex_t *re, int flags, + ngx_pool_t *pool, ngx_http_lua_main_conf_t *lmcf, + ngx_http_lua_regex_compile_t *re_comp) +{ + ngx_int_t ret; + ngx_pool_t *old_pool; + + if (flags & NGX_LUA_RE_MODE_JIT) { + old_pool = ngx_http_lua_pcre_malloc_init(pool); + ret = pcre2_jit_compile(re_comp->regex, PCRE2_JIT_COMPLETE); + + if (ret != 0) { + ngx_log_error(NGX_LOG_INFO, ngx_cycle->log, 0, + "pcre2_jit_compile() failed: %d in \"%V\", " + "ignored", + ret, &re_comp->pattern); + +#if (NGX_DEBUG) + + } else { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "pcre2 JIT compiled successfully"); +# endif /* !(NGX_DEBUG) */ + } + + ngx_http_lua_pcre_malloc_done(old_pool); + + } + + if (lmcf && lmcf->jit_stack) { + pcre2_jit_stack_assign(ngx_regex_match_context, NULL, + lmcf->jit_stack); + } + + return; +} + +#else + +static void +ngx_http_lua_regex_jit_compile(ngx_http_lua_regex_t *re, int flags, + ngx_pool_t *pool, ngx_http_lua_main_conf_t *lmcf, + ngx_http_lua_regex_compile_t *re_comp) +{ + const char *msg; + pcre_extra *sd = NULL; + ngx_pool_t *old_pool; + + +#if (LUA_HAVE_PCRE_JIT) + if (flags & NGX_LUA_RE_MODE_JIT) { + old_pool = ngx_http_lua_pcre_malloc_init(pool); + sd = pcre_study(re_comp->regex, PCRE_STUDY_JIT_COMPILE, &msg); + ngx_http_lua_pcre_malloc_done(old_pool); + +# if (NGX_DEBUG) + if (msg != NULL) { + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "pcre study failed with PCRE_STUDY_JIT_COMPILE: " + "%s (%p)", msg, sd); + } + + if (sd != NULL) { + int jitted; + + old_pool = ngx_http_lua_pcre_malloc_init(pool); + + pcre_fullinfo(re_comp->regex, sd, PCRE_INFO_JIT, &jitted); + + ngx_http_lua_pcre_malloc_done(old_pool); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "pcre JIT compiling result: %d", jitted); + } +# endif /* !(NGX_DEBUG) */ + + } else { + old_pool = ngx_http_lua_pcre_malloc_init(pool); + sd = pcre_study(re_comp->regex, 0, &msg); + ngx_http_lua_pcre_malloc_done(old_pool); + } + + if (sd && lmcf && lmcf->jit_stack) { + pcre_assign_jit_stack(sd, NULL, lmcf->jit_stack); + } + + if (sd + && lmcf && lmcf->regex_match_limit > 0 + && !(flags & NGX_LUA_RE_MODE_DFA)) + { + sd->flags |= PCRE_EXTRA_MATCH_LIMIT; + sd->match_limit = lmcf->regex_match_limit; + } + #endif /* LUA_HAVE_PCRE_JIT */ + + re->regex_sd = sd; } +#endif + + +#if (NGX_PCRE2) +void +ngx_http_lua_regex_cleanup(void *data) +{ + ngx_pool_t *old_pool; + ngx_http_lua_main_conf_t *lmcf; + + lmcf = data; + + if (ngx_regex_compile_context) { + old_pool = ngx_http_lua_pcre_malloc_init(NULL); + pcre2_compile_context_free(ngx_regex_compile_context); + ngx_regex_compile_context = NULL; + ngx_http_lua_pcre_malloc_done(old_pool); + } + + if (lmcf && lmcf->jit_stack) { + old_pool = ngx_http_lua_pcre_malloc_init(NULL); + + pcre2_jit_stack_free(lmcf->jit_stack); + lmcf->jit_stack = NULL; + + ngx_http_lua_pcre_malloc_done(old_pool); + } + + if (ngx_regex_match_data) { + old_pool = ngx_http_lua_pcre_malloc_init(NULL); + pcre2_match_data_free(ngx_regex_match_data); + ngx_regex_match_data = NULL; + ngx_regex_match_data_size = 0; + ngx_http_lua_pcre_malloc_done(old_pool); + } + +} +#endif ngx_http_lua_regex_t * @@ -228,8 +537,7 @@ ngx_http_lua_ffi_compile_regex(const unsigned char *pat, size_t pat_len, ngx_int_t rc; const char *msg; ngx_pool_t *pool, *old_pool; - pcre_extra *sd = NULL; - ngx_http_lua_regex_t *re; + ngx_http_lua_regex_t *re = NULL; ngx_http_lua_main_conf_t *lmcf; ngx_http_lua_regex_compile_t re_comp; @@ -251,6 +559,8 @@ ngx_http_lua_ffi_compile_regex(const unsigned char *pat, size_t pat_len, } re->pool = pool; + re->regex = NULL; + re->regex_sd = NULL; re_comp.options = pcre_opts; re_comp.pattern.data = (u_char *) pat; @@ -274,54 +584,7 @@ ngx_http_lua_ffi_compile_regex(const unsigned char *pat, size_t pat_len, ngx_http_lua_assert(lmcf != NULL); -#if (LUA_HAVE_PCRE_JIT) - - if (flags & NGX_LUA_RE_MODE_JIT) { - - old_pool = ngx_http_lua_pcre_malloc_init(pool); - sd = pcre_study(re_comp.regex, PCRE_STUDY_JIT_COMPILE, &msg); - ngx_http_lua_pcre_malloc_done(old_pool); - -# if (NGX_DEBUG) - if (msg != NULL) { - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "pcre study failed with PCRE_STUDY_JIT_COMPILE: " - "%s (%p)", msg, sd); - } - - if (sd != NULL) { - int jitted; - - old_pool = ngx_http_lua_pcre_malloc_init(pool); - - pcre_fullinfo(re_comp.regex, sd, PCRE_INFO_JIT, &jitted); - - ngx_http_lua_pcre_malloc_done(old_pool); - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "pcre JIT compiling result: %d", jitted); - } -# endif /* !(NGX_DEBUG) */ - - } else { - old_pool = ngx_http_lua_pcre_malloc_init(pool); - sd = pcre_study(re_comp.regex, 0, &msg); - ngx_http_lua_pcre_malloc_done(old_pool); - } - - if (sd && lmcf->jit_stack) { - pcre_assign_jit_stack(sd, NULL, lmcf->jit_stack); - } - -#endif /* LUA_HAVE_PCRE_JIT */ - - if (sd - && lmcf && lmcf->regex_match_limit > 0 - && !(flags & NGX_LUA_RE_MODE_DFA)) - { - sd->flags |= PCRE_EXTRA_MATCH_LIMIT; - sd->match_limit = lmcf->regex_match_limit; - } + ngx_http_lua_regex_jit_compile(re, flags, pool, lmcf, &re_comp); if (flags & NGX_LUA_RE_MODE_DFA) { ovecsize = 2; @@ -339,6 +602,31 @@ ngx_http_lua_ffi_compile_regex(const unsigned char *pat, size_t pat_len, goto error; } +#if (NGX_PCRE2) + if (pcre2_pattern_info(re_comp.regex, PCRE2_INFO_NAMECOUNT, + &re->name_count) < 0) + { + msg = "cannot acquire named subpattern count"; + goto error; + } + + if (re->name_count > 0) { + if (pcre2_pattern_info(re_comp.regex, PCRE2_INFO_NAMEENTRYSIZE, + &re->name_entry_size) != 0) + { + msg = "cannot acquire named subpattern entry size"; + goto error; + } + + if (pcre2_pattern_info(re_comp.regex, PCRE2_INFO_NAMETABLE, + &re->name_table) != 0) + { + msg = "cannot acquire named subpattern table"; + goto error; + } + } + +#else if (pcre_fullinfo(re_comp.regex, NULL, PCRE_INFO_NAMECOUNT, &re->name_count) != 0) { @@ -361,9 +649,9 @@ ngx_http_lua_ffi_compile_regex(const unsigned char *pat, size_t pat_len, goto error; } } +#endif re->regex = re_comp.regex; - re->regex_sd = sd; re->ncaptures = re_comp.captures; re->captures = cap; re->replace = NULL; @@ -379,9 +667,7 @@ ngx_http_lua_ffi_compile_regex(const unsigned char *pat, size_t pat_len, p = ngx_snprintf(errstr, errstr_size - 1, "%s", msg); *p = '\0'; - if (sd) { - ngx_http_lua_regex_free_study_data(pool, sd); - } + ngx_http_lua_regex_free_study_data(pool, re); if (pool) { ngx_destroy_pool(pool); @@ -391,6 +677,103 @@ ngx_http_lua_ffi_compile_regex(const unsigned char *pat, size_t pat_len, } +#if (NGX_PCRE2) +int +ngx_http_lua_ffi_exec_regex(ngx_http_lua_regex_t *re, int flags, + const u_char *s, size_t len, int pos) +{ + int rc, exec_opts = 0; + size_t *ov; + ngx_uint_t ovecsize, n, i; + ngx_pool_t *old_pool; + + if (flags & NGX_LUA_RE_MODE_DFA) { + ovecsize = 2; + re->ncaptures = 0; + + } else { + ovecsize = (re->ncaptures + 1) * 3; + } + + old_pool = ngx_http_lua_pcre_malloc_init(NULL); + + if (ngx_regex_match_data == NULL + || ovecsize > ngx_regex_match_data_size) + { + /* + * Allocate a match data if not yet allocated or smaller than + * needed. + */ + + if (ngx_regex_match_data) { + pcre2_match_data_free(ngx_regex_match_data); + } + + ngx_regex_match_data_size = ovecsize; + ngx_regex_match_data = pcre2_match_data_create(ovecsize / 3, NULL); + + if (ngx_regex_match_data == NULL) { + rc = PCRE2_ERROR_NOMEMORY; + goto failed; + } + } + + if (flags & NGX_LUA_RE_NO_UTF8_CHECK) { + exec_opts = PCRE2_NO_UTF_CHECK; + + } else { + exec_opts = 0; + } + + if (flags & NGX_LUA_RE_MODE_DFA) { + int ws[NGX_LUA_RE_DFA_MODE_WORKSPACE_COUNT]; + rc = pcre2_dfa_match(re->regex, s, len, pos, exec_opts, + ngx_regex_match_data, ngx_regex_match_context, + ws, sizeof(ws) / sizeof(ws[0])); + + + } else { + rc = pcre2_match(re->regex, s, len, pos, exec_opts, + ngx_regex_match_data, ngx_regex_match_context); + } + + if (rc < 0) { +#if (NGX_DEBUG) + ngx_log_debug4(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "pcre2_match failed: flags 0x%05Xd, options 0x%08Xd, " + "rc %d, ovecsize %ui", flags, exec_opts, rc, ovecsize); +#endif + + goto failed; + } + + n = pcre2_get_ovector_count(ngx_regex_match_data); + ov = pcre2_get_ovector_pointer(ngx_regex_match_data); + +#if (NGX_DEBUG) + ngx_log_debug5(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "pcre2_match: flags 0x%05Xd, options 0x%08Xd, rc %d, " + "n %ui, ovecsize %ui", flags, exec_opts, rc, n, ovecsize); +#endif + + if (!(flags & NGX_LUA_RE_MODE_DFA) && n > ovecsize / 3) { + n = ovecsize / 3; + } + + for (i = 0; i < n; i++) { + re->captures[i * 2] = ov[i * 2]; + re->captures[i * 2 + 1] = ov[i * 2 + 1]; + } + +failed: + + ngx_http_lua_pcre_malloc_done(old_pool); + + return rc; +} + +#else + int ngx_http_lua_ffi_exec_regex(ngx_http_lua_regex_t *re, int flags, const u_char *s, size_t len, int pos) @@ -427,7 +810,8 @@ ngx_http_lua_ffi_exec_regex(ngx_http_lua_regex_t *re, int flags, int ws[NGX_LUA_RE_DFA_MODE_WORKSPACE_COUNT]; rc = ngx_http_lua_regex_dfa_exec(re->regex, sd, &subj, (int) pos, cap, ovecsize, ws, - sizeof(ws)/sizeof(ws[0]), exec_opts); + sizeof(ws) / sizeof(ws[0]), + exec_opts); #else @@ -443,28 +827,19 @@ ngx_http_lua_ffi_exec_regex(ngx_http_lua_regex_t *re, int flags, return rc; } +#endif + void ngx_http_lua_ffi_destroy_regex(ngx_http_lua_regex_t *re) { - ngx_pool_t *old_pool; - dd("destroy regex called"); if (re == NULL || re->pool == NULL) { return; } - if (re->regex_sd) { - old_pool = ngx_http_lua_pcre_malloc_init(re->pool); -#if LUA_HAVE_PCRE_JIT - pcre_free_study(re->regex_sd); -#else - pcre_free(re->regex_sd); -#endif - ngx_http_lua_pcre_malloc_done(old_pool); - re->regex_sd = NULL; - } + ngx_http_lua_regex_free_study_data(re->pool, re); ngx_destroy_pool(re->pool); } @@ -592,11 +967,17 @@ ngx_http_lua_ffi_max_regex_cache_size(void) const char * ngx_http_lua_ffi_pcre_version(void) { +#if (NGX_PCRE2) + pcre2_config(PCRE2_CONFIG_VERSION, ngx_pcre2_version); + + return ngx_pcre2_version; +#else return pcre_version(); +#endif } -#endif /* NGX_PCRE */ +#endif /* NGX_PCRE || NGX_PCRE2 */ /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/t/028-req-header.t b/t/028-req-header.t index f4c393977d..18b991052b 100644 --- a/t/028-req-header.t +++ b/t/028-req-header.t @@ -275,7 +275,6 @@ Content-Type: GET /bar --- response_body eval # Since nginx version 1.23.0, nginx combines same $http_* variable together -# wtf $Test::Nginx::Util::NginxVersion >= 1.023000 ? "Foo: a, b\n" diff --git a/t/034-match.t b/t/034-match.t index 1bf45bce1a..fd4d9439e2 100644 --- a/t/034-match.t +++ b/t/034-match.t @@ -361,8 +361,11 @@ he } --- request GET /re ---- response_body -error: pcre_compile() failed: missing ) in "(abc" +--- response_body eval +$Test::Nginx::Util::PcreVersion == 2 ? +"error: pcre2_compile() failed: missing closing parenthesis in \"(abc\"\n" +: +"error: pcre_compile() failed: missing ) in \"(abc\"\n" --- no_error_log [error] @@ -648,8 +651,12 @@ regex: (?:>[\w\s]*) } --- request GET /re ---- response_body -error: pcre_compile() failed: missing ) in "([0-9]+" +--- response_body eval +$Test::Nginx::Util::PcreVersion == 2 ? +"error: pcre2_compile\(\) failed: missing closing parenthesis in \"\([0-9]+\"\n" +: +"error: pcre_compile\(\) failed: missing \) in \"\([0-9]+\"\n" + --- no_error_log [error] @@ -939,8 +946,11 @@ nil } --- request GET /t ---- response_body_like chop -^error: pcre_exec\(\) failed: -10$ +--- response_body eval +$Test::Nginx::Util::PcreVersion == 2 ? +"error: pcre_exec\(\) failed: -4\n" +: +"error: pcre_exec\(\) failed: -10\n" --- no_error_log [error] @@ -1050,8 +1060,14 @@ end --- request GET /re ---- response_body -error: pcre_exec() failed: -8 +--- response_body eval +# lua_regex_match_limit uses pcre_extra->match_limit in the PCRE, +# but PCRE2 replaces this with pcre2_set_match_limit interface, +# which has different effects. +$Test::Nginx::Util::PcreVersion == 2 ? +"failed to match\n" +: +"error: pcre_exec() failed: -8\n" diff --git a/t/035-gmatch.t b/t/035-gmatch.t index 0dfeaeaf39..0a4efd2b25 100644 --- a/t/035-gmatch.t +++ b/t/035-gmatch.t @@ -698,8 +698,11 @@ not matched! } --- request GET /re ---- response_body -error: pcre_compile() failed: missing ) in "(abc" +--- response_body eval +$Test::Nginx::Util::PcreVersion == 2 ? +"error: pcre2_compile() failed: missing closing parenthesis in \"(abc\"\n" +: +"error: pcre_compile() failed: missing ) in \"(abc\"\n" --- no_error_log [error] @@ -735,8 +738,11 @@ error: pcre_compile() failed: missing ) in "(abc" } --- request GET /t ---- response_body_like chop -error: pcre_exec\(\) failed: -10 +--- response_body eval +$Test::Nginx::Util::PcreVersion == 2 ? +"error: pcre_exec\(\) failed: -4\n" +: +"error: pcre_exec\(\) failed: -10\n" --- no_error_log [error] @@ -854,8 +860,14 @@ end --- request GET /re ---- response_body -error: pcre_exec() failed: -8 +--- response_body eval +# lua_regex_match_limit uses pcre_extra->match_limit in the PCRE, +# but PCRE2 replaces this with pcre2_set_match_limit interface, +# which has different effects. +$Test::Nginx::Util::PcreVersion == 2 ? +"failed to match\n" +: +"error: pcre_exec() failed: -8\n" diff --git a/t/036-sub.t b/t/036-sub.t index 3e88eba5a0..0657ebb2ca 100644 --- a/t/036-sub.t +++ b/t/036-sub.t @@ -480,8 +480,11 @@ a [b c] [b] [c] [] [] d } --- request GET /re ---- response_body -error: pcre_compile() failed: missing ) in "(abc" +--- response_body eval +$Test::Nginx::Util::PcreVersion == 2 ? +"error: pcre2_compile() failed: missing closing parenthesis in \"(abc\"\n" +: +"error: pcre_compile() failed: missing ) in \"(abc\"\n" --- no_error_log [error] @@ -506,8 +509,11 @@ error: pcre_compile() failed: missing ) in "(abc" } --- request GET /t ---- response_body_like chop -error: pcre_exec\(\) failed: -10 +--- response_body eval +$Test::Nginx::Util::PcreVersion == 2 ? +"error: pcre_exec\(\) failed: -4\n" +: +"error: pcre_exec\(\) failed: -10\n" --- no_error_log [error] @@ -610,8 +616,14 @@ ngx.say("sub: ", cnt) --- request GET /re ---- response_body -error: pcre_exec() failed: -8 +--- response_body eval +# lua_regex_match_limit uses pcre_extra->match_limit in the PCRE, +# but PCRE2 replaces this with pcre2_set_match_limit interface, +# which has different effects. +$Test::Nginx::Util::PcreVersion == 2 ? +"sub: 0\n" +: +"error: pcre_exec() failed: -8\n" diff --git a/t/037-gsub.t b/t/037-gsub.t index 41f86ac013..a6fe579bd4 100644 --- a/t/037-gsub.t +++ b/t/037-gsub.t @@ -423,8 +423,11 @@ n: 1 } --- request GET /t ---- response_body_like chop -error: pcre_exec\(\) failed: -10 +--- response_body eval +$Test::Nginx::Util::PcreVersion == 2 ? +"error: pcre_exec\(\) failed: -4\n" +: +"error: pcre_exec\(\) failed: -10\n" --- no_error_log [error] @@ -531,8 +534,14 @@ ngx.say("gsub: ", cnt) --- request GET /re ---- response_body -error: pcre_exec() failed: -8 +--- response_body eval +# lua_regex_match_limit uses pcre_extra->match_limit in the PCRE, +# but PCRE2 replaces this with pcre2_set_match_limit interface, +# which has different effects. +$Test::Nginx::Util::PcreVersion == 2 ? +"gsub: 0\n" +: +"error: pcre_exec() failed: -8\n" diff --git a/t/038-match-o.t b/t/038-match-o.t index f6ae0103fe..cc80244e82 100644 --- a/t/038-match-o.t +++ b/t/038-match-o.t @@ -336,8 +336,11 @@ he } --- request GET /re ---- response_body -error: pcre_compile() failed: missing ) in "(abc" +--- response_body eval +$Test::Nginx::Util::PcreVersion == 2 ? +"error: pcre2_compile() failed: missing closing parenthesis in \"(abc\"\n" +: +"error: pcre_compile() failed: missing ) in \"(abc\"\n" --- no_error_log [error] diff --git a/t/047-match-jit.t b/t/047-match-jit.t index f53a4083a2..9b40a889dc 100644 --- a/t/047-match-jit.t +++ b/t/047-match-jit.t @@ -32,8 +32,11 @@ __DATA__ GET /re --- response_body 1234 ---- error_log -pcre JIT compiling result: 1 +--- error_log eval +$Test::Nginx::Util::PcreVersion == 2 ? +"pcre2 JIT compiled successfully\n" +: +"pcre JIT compiling result: 1\n" @@ -53,8 +56,11 @@ pcre JIT compiling result: 1 GET /re --- response_body not matched! ---- error_log -pcre JIT compiling result: 1 +--- error_log eval +$Test::Nginx::Util::PcreVersion == 2 ? +"pcre2 JIT compiled successfully\n" +: +"pcre JIT compiling result: 1\n" @@ -76,9 +82,15 @@ pcre JIT compiling result: 1 1234 --- grep_error_log eval -qr/pcre JIT compiling result: \d+/ +$Test::Nginx::Util::PcreVersion == 2 ? +"pcre2 JIT compiled successfully" +: +"pcre JIT compiling result: 1" --- grep_error_log_out eval +$Test::Nginx::Util::PcreVersion == 2 ? +["pcre2 JIT compiled successfully\n", ""] +: ["pcre JIT compiling result: 1\n", ""] @@ -101,9 +113,15 @@ qr/pcre JIT compiling result: \d+/ not matched! --- grep_error_log eval -qr/pcre JIT compiling result: \d+/ +$Test::Nginx::Util::PcreVersion == 2 ? +"pcre2 JIT compiled successfully" +: +"pcre JIT compiling result: 1" --- grep_error_log_out eval +$Test::Nginx::Util::PcreVersion == 2 ? +["pcre2 JIT compiled successfully\n", ""] +: ["pcre JIT compiling result: 1\n", ""] @@ -128,8 +146,11 @@ qr/pcre JIT compiling result: \d+/ } --- request GET /re ---- response_body -error: pcre_compile() failed: missing ) in "(abc" +--- response_body eval +$Test::Nginx::Util::PcreVersion == 2 ? +"error: pcre2_compile() failed: missing closing parenthesis in \"(abc\"\n" +: +"error: pcre_compile() failed: missing ) in \"(abc\"\n" --- no_error_log [error] @@ -170,8 +191,15 @@ end --- request GET /re ---- response_body -error: pcre_exec() failed: -8 +--- response_body eval +# lua_regex_match_limit uses pcre_extra->match_limit in the PCRE, +# but PCRE2 replaces this with pcre2_set_match_limit interface, +# which has different effects. +$Test::Nginx::Util::PcreVersion == 2 ? +# PCRE2_ERROR_MATCHLIMIT (-47) +"error: pcre_exec() failed: -47\n" +: +"error: pcre_exec() failed: -8\n" diff --git a/t/049-gmatch-jit.t b/t/049-gmatch-jit.t index 5134d526b5..b76df35e98 100644 --- a/t/049-gmatch-jit.t +++ b/t/049-gmatch-jit.t @@ -34,8 +34,11 @@ __DATA__ --- response_body hello world ---- error_log -pcre JIT compiling result: 1 +--- error_log eval +$Test::Nginx::Util::PcreVersion == 2 ? +"pcre2 JIT compiled successfully\n" +: +"pcre JIT compiling result: 1\n" @@ -60,8 +63,11 @@ pcre JIT compiling result: 1 nil nil nil ---- error_log -pcre JIT compiling result: 1 +--- error_log eval +$Test::Nginx::Util::PcreVersion == 2 ? +"pcre2 JIT compiled successfully\n" +: +"pcre JIT compiling result: 1\n" @@ -77,8 +83,11 @@ pcre JIT compiling result: 1 GET /re --- response_body done ---- error_log -pcre JIT compiling result: 1 +--- error_log eval +$Test::Nginx::Util::PcreVersion == 2 ? +"pcre2 JIT compiled successfully\n" +: +"pcre JIT compiling result: 1\n" @@ -99,8 +108,11 @@ pcre JIT compiling result: 1 GET /re --- response_body hello ---- error_log -pcre JIT compiling result: 1 +--- error_log eval +$Test::Nginx::Util::PcreVersion == 2 ? +"pcre2 JIT compiled successfully\n" +: +"pcre JIT compiling result: 1\n" @@ -124,9 +136,15 @@ hello world --- grep_error_log eval -qr/pcre JIT compiling result: \d+/ +$Test::Nginx::Util::PcreVersion == 2 ? +"pcre2 JIT compiled successfully" +: +"pcre JIT compiling result: 1" --- grep_error_log_out eval +$Test::Nginx::Util::PcreVersion == 2 ? +["pcre2 JIT compiled successfully\n", ""] +: ["pcre JIT compiling result: 1\n", ""] @@ -154,9 +172,15 @@ nil nil --- grep_error_log eval -qr/pcre JIT compiling result: \d+/ +$Test::Nginx::Util::PcreVersion == 2 ? +"pcre2 JIT compiled successfully" +: +"pcre JIT compiling result: 1" --- grep_error_log_out eval +$Test::Nginx::Util::PcreVersion == 2 ? +["pcre2 JIT compiled successfully\n", ""] +: ["pcre JIT compiling result: 1\n", ""] @@ -175,9 +199,15 @@ qr/pcre JIT compiling result: \d+/ done --- grep_error_log eval -qr/pcre JIT compiling result: \d+/ +$Test::Nginx::Util::PcreVersion == 2 ? +"pcre2 JIT compiled successfully" +: +"pcre JIT compiling result: 1" --- grep_error_log_out eval +$Test::Nginx::Util::PcreVersion == 2 ? +["pcre2 JIT compiled successfully\n", ""] +: ["pcre JIT compiling result: 1\n", ""] @@ -201,9 +231,15 @@ qr/pcre JIT compiling result: \d+/ hello --- grep_error_log eval -qr/pcre JIT compiling result: \d+/ +$Test::Nginx::Util::PcreVersion == 2 ? +"pcre2 JIT compiled successfully" +: +"pcre JIT compiling result: 1" --- grep_error_log_out eval +$Test::Nginx::Util::PcreVersion == 2 ? +["pcre2 JIT compiled successfully\n", ""] +: ["pcre JIT compiling result: 1\n", ""] @@ -222,7 +258,10 @@ qr/pcre JIT compiling result: \d+/ } --- request GET /re ---- response_body -error: pcre_compile() failed: missing ) in "(abc" +--- response_body eval +$Test::Nginx::Util::PcreVersion == 2 ? +"error: pcre2_compile() failed: missing closing parenthesis in \"(abc\"\n" +: +"error: pcre_compile() failed: missing ) in \"(abc\"\n" --- no_error_log [error] diff --git a/t/050-gmatch-dfa.t b/t/050-gmatch-dfa.t index d2ac2bc666..4c5f820e49 100644 --- a/t/050-gmatch-dfa.t +++ b/t/050-gmatch-dfa.t @@ -214,8 +214,11 @@ hello } --- request GET /re ---- response_body -error: pcre_compile() failed: missing ) in "(abc" +--- response_body eval +$Test::Nginx::Util::PcreVersion == 2 ? +"error: pcre2_compile() failed: missing closing parenthesis in \"(abc\"\n" +: +"error: pcre_compile() failed: missing ) in \"(abc\"\n" --- no_error_log [error] diff --git a/t/051-sub-jit.t b/t/051-sub-jit.t index c8a49c0516..7aec7ccb79 100644 --- a/t/051-sub-jit.t +++ b/t/051-sub-jit.t @@ -32,8 +32,11 @@ __DATA__ GET /re --- response_body hello, world 5678: 1 ---- error_log -pcre JIT compiling result: 1 +--- error_log eval +$Test::Nginx::Util::PcreVersion == 2 ? +"pcre2 JIT compiled successfully\n" +: +"pcre JIT compiling result: 1\n" @@ -53,8 +56,11 @@ pcre JIT compiling result: 1 GET /re --- response_body hello, world: 0 ---- error_log -pcre JIT compiling result: 1 +--- error_log eval +$Test::Nginx::Util::PcreVersion == 2 ? +"pcre2 JIT compiled successfully\n" +: +"pcre JIT compiling result: 1\n" @@ -76,9 +82,15 @@ pcre JIT compiling result: 1 hello, world 5678: 1 --- grep_error_log eval -qr/pcre JIT compiling result: \d+/ +$Test::Nginx::Util::PcreVersion == 2 ? +"pcre2 JIT compiled successfully" +: +"pcre JIT compiling result: 1" --- grep_error_log_out eval +$Test::Nginx::Util::PcreVersion == 2 ? +["pcre2 JIT compiled successfully\n", ""] +: ["pcre JIT compiling result: 1\n", ""] @@ -101,9 +113,15 @@ qr/pcre JIT compiling result: \d+/ hello, world: 0 --- grep_error_log eval -qr/pcre JIT compiling result: \d+/ +$Test::Nginx::Util::PcreVersion == 2 ? +"pcre2 JIT compiled successfully" +: +"pcre JIT compiling result: 1" --- grep_error_log_out eval +$Test::Nginx::Util::PcreVersion == 2 ? +["pcre2 JIT compiled successfully\n", ""] +: ["pcre JIT compiling result: 1\n", ""] @@ -122,8 +140,11 @@ qr/pcre JIT compiling result: \d+/ } --- request GET /re ---- response_body -error: pcre_compile() failed: missing ) in "(abc" +--- response_body eval +$Test::Nginx::Util::PcreVersion == 2 ? +"error: pcre2_compile() failed: missing closing parenthesis in \"(abc\"\n" +: +"error: pcre_compile() failed: missing ) in \"(abc\"\n" --- no_error_log [error] @@ -143,7 +164,10 @@ error: pcre_compile() failed: missing ) in "(abc" } --- request GET /re ---- response_body -error: pcre_compile() failed: missing ) in "(abc" +--- response_body eval +$Test::Nginx::Util::PcreVersion == 2 ? +"error: pcre2_compile() failed: missing closing parenthesis in \"(abc\"\n" +: +"error: pcre_compile() failed: missing ) in \"(abc\"\n" --- no_error_log [error] diff --git a/t/052-sub-dfa.t b/t/052-sub-dfa.t index 254913b3e0..2329c77aa3 100644 --- a/t/052-sub-dfa.t +++ b/t/052-sub-dfa.t @@ -107,8 +107,11 @@ hello, world: 0 } --- request GET /re ---- response_body -error: pcre_compile() failed: missing ) in "(abc" +--- response_body eval +$Test::Nginx::Util::PcreVersion == 2 ? +"error: pcre2_compile() failed: missing closing parenthesis in \"(abc\"\n" +: +"error: pcre_compile() failed: missing ) in \"(abc\"\n" --- no_error_log [error] @@ -129,8 +132,11 @@ error: pcre_compile() failed: missing ) in "(abc" } --- request GET /re ---- response_body -error: pcre_compile() failed: missing ) in "(abc" +--- response_body eval +$Test::Nginx::Util::PcreVersion == 2 ? +"error: pcre2_compile() failed: missing closing parenthesis in \"(abc\"\n" +: +"error: pcre_compile() failed: missing ) in \"(abc\"\n" --- no_error_log [error] diff --git a/t/053-gsub-jit.t b/t/053-gsub-jit.t index 3efc0a24a5..c7c87ee29c 100644 --- a/t/053-gsub-jit.t +++ b/t/053-gsub-jit.t @@ -32,8 +32,11 @@ __DATA__ GET /re --- response_body hello, world world: 2 ---- error_log -pcre JIT compiling result: 1 +--- error_log eval +$Test::Nginx::Util::PcreVersion == 2 ? +"pcre2 JIT compiled successfully\n" +: +"pcre JIT compiling result: 1\n" @@ -53,8 +56,11 @@ pcre JIT compiling result: 1 GET /re --- response_body hello, world: 0 ---- error_log -pcre JIT compiling result: 1 +--- error_log eval +$Test::Nginx::Util::PcreVersion == 2 ? +"pcre2 JIT compiled successfully\n" +: +"pcre JIT compiling result: 1\n" @@ -76,9 +82,15 @@ pcre JIT compiling result: 1 hello, world world: 2 --- grep_error_log eval -qr/pcre JIT compiling result: \d+/ +$Test::Nginx::Util::PcreVersion == 2 ? +"pcre2 JIT compiled successfully" +: +"pcre JIT compiling result: 1" --- grep_error_log_out eval +$Test::Nginx::Util::PcreVersion == 2 ? +["pcre2 JIT compiled successfully\n", ""] +: ["pcre JIT compiling result: 1\n", ""] @@ -101,9 +113,15 @@ qr/pcre JIT compiling result: \d+/ hello, world: 0 --- grep_error_log eval -qr/pcre JIT compiling result: \d+/ +$Test::Nginx::Util::PcreVersion == 2 ? +"pcre2 JIT compiled successfully" +: +"pcre JIT compiling result: 1" --- grep_error_log_out eval +$Test::Nginx::Util::PcreVersion == 2 ? +["pcre2 JIT compiled successfully\n", ""] +: ["pcre JIT compiling result: 1\n", ""] @@ -122,8 +140,11 @@ qr/pcre JIT compiling result: \d+/ } --- request GET /re ---- response_body -error: pcre_compile() failed: missing ) in "(abc" +--- response_body eval +$Test::Nginx::Util::PcreVersion == 2 ? +"error: pcre2_compile() failed: missing closing parenthesis in \"(abc\"\n" +: +"error: pcre_compile() failed: missing ) in \"(abc\"\n" --- no_error_log [error] @@ -143,7 +164,10 @@ error: pcre_compile() failed: missing ) in "(abc" } --- request GET /re ---- response_body -error: pcre_compile() failed: missing ) in "(abc" +--- response_body eval +$Test::Nginx::Util::PcreVersion == 2 ? +"error: pcre2_compile() failed: missing closing parenthesis in \"(abc\"\n" +: +"error: pcre_compile() failed: missing ) in \"(abc\"\n" --- no_error_log [error] diff --git a/t/054-gsub-dfa.t b/t/054-gsub-dfa.t index 937aa1c421..bd0825d4ba 100644 --- a/t/054-gsub-dfa.t +++ b/t/054-gsub-dfa.t @@ -107,8 +107,11 @@ hello, world: 0 } --- request GET /re ---- response_body -error: pcre_compile() failed: missing ) in "(abc" +--- response_body eval +$Test::Nginx::Util::PcreVersion == 2 ? +"error: pcre2_compile() failed: missing closing parenthesis in \"(abc\"\n" +: +"error: pcre_compile() failed: missing ) in \"(abc\"\n" @@ -126,8 +129,11 @@ error: pcre_compile() failed: missing ) in "(abc" } --- request GET /re ---- response_body -error: pcre_compile() failed: missing ) in "(abc" +--- response_body eval +$Test::Nginx::Util::PcreVersion == 2 ? +"error: pcre2_compile() failed: missing closing parenthesis in \"(abc\"\n" +: +"error: pcre_compile() failed: missing ) in \"(abc\"\n" --- no_error_log [error] diff --git a/t/120-re-find.t b/t/120-re-find.t index ddf24a98e7..43ccece1ab 100644 --- a/t/120-re-find.t +++ b/t/120-re-find.t @@ -354,8 +354,11 @@ matched: he } --- request GET /re ---- response_body -error: pcre_compile() failed: missing ) in "(abc" +--- response_body eval +$Test::Nginx::Util::PcreVersion == 2 ? +"error: pcre2_compile() failed: missing closing parenthesis in \"(abc\"\n" +: +"error: pcre_compile() failed: missing ) in \"(abc\"\n" --- no_error_log [error] @@ -562,8 +565,11 @@ matched: hello, 1234 } --- request GET /t ---- response_body_like chop -^error: pcre_exec\(\) failed: -10$ +--- response_body eval +$Test::Nginx::Util::PcreVersion == 2 ? +"error: pcre_exec\(\) failed: -4\n" +: +"error: pcre_exec\(\) failed: -10\n" --- no_error_log [error] @@ -587,6 +593,7 @@ GET /t '; } --- stap +# TODO: PCRE2 use different option values from PCRE probe process("$LIBPCRE_PATH").function("pcre_compile") { printf("compile opts: %x\n", $options) } @@ -645,8 +652,14 @@ end --- request GET /re ---- response_body -error: pcre_exec() failed: -8 +--- response_body eval +# lua_regex_match_limit uses pcre_extra->match_limit in the PCRE, +# but PCRE2 replaces this with pcre2_set_match_limit interface, +# which has different effects. +$Test::Nginx::Util::PcreVersion == 2 ? +"failed to match.\n" +: +"error: pcre_exec() failed: -8\n" --- no_error_log [error] diff --git a/t/cert/test.crt b/t/cert/test.crt index a69a01141a..9fed1bc3b4 100644 --- a/t/cert/test.crt +++ b/t/cert/test.crt @@ -1,17 +1,22 @@ -----BEGIN CERTIFICATE----- -MIICqTCCAhICCQClDm1WkreW4jANBgkqhkiG9w0BAQUFADCBlzELMAkGA1UEBhMC -VVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28x -EjAQBgNVBAoMCU9wZW5SZXN0eTESMBAGA1UECwwJT3BlblJlc3R5MREwDwYDVQQD -DAh0ZXN0LmNvbTEgMB4GCSqGSIb3DQEJARYRYWdlbnR6aEBnbWFpbC5jb20wIBcN -MTQwNzIxMDMyMzQ3WhgPMjE1MTA2MTMwMzIzNDdaMIGXMQswCQYDVQQGEwJVUzET -MBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzESMBAG -A1UECgwJT3BlblJlc3R5MRIwEAYDVQQLDAlPcGVuUmVzdHkxETAPBgNVBAMMCHRl -c3QuY29tMSAwHgYJKoZIhvcNAQkBFhFhZ2VudHpoQGdtYWlsLmNvbTCBnzANBgkq -hkiG9w0BAQEFAAOBjQAwgYkCgYEA6P18zUvtmaKQK2xePy8ZbFwSyTLw+jW6t9eZ -aiTec8X3ibN9WemrxHzkTRikxP3cAQoITRuZiQvF4Q7DO6wMkz/b0zwfgX5uedGq -047AJP6n/mwlDOjGSNomBLoXQzo7tVe60ikEm3ZyDUqnJPJMt3hImO5XSop4MPMu -Za9WhFcCAwEAATANBgkqhkiG9w0BAQUFAAOBgQA4OBb9bOyWB1//93nSXX1mdENZ -IQeyTK0Dd6My76lnZxnZ4hTWrvvd0b17KLDU6JnS2N5ee3ATVkojPidRLWLIhnh5 -0eXrcKalbO2Ce6nShoFvQCQKXN2Txmq2vO/Mud2bHAWwJALg+qi1Iih/gVYB9sct -FLg8zFOzRlYiU+6Mmw== +MIIDtzCCAp8CFCJnLifDCaXjYb2ARKBBhs+aAgYOMA0GCSqGSIb3DQEBCwUAMIGX +MQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2Fu +IEZyYW5jaXNjbzESMBAGA1UECgwJT3BlblJlc3R5MRIwEAYDVQQLDAlPcGVuUmVz +dHkxETAPBgNVBAMMCHRlc3QuY29tMSAwHgYJKoZIhvcNAQkBFhFhZ2VudHpoQGdt +YWlsLmNvbTAeFw0yMzA5MDUwNDE5MjhaFw0zMzA5MDIwNDE5MjhaMIGXMQswCQYD +VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5j +aXNjbzESMBAGA1UECgwJT3BlblJlc3R5MRIwEAYDVQQLDAlPcGVuUmVzdHkxETAP +BgNVBAMMCHRlc3QuY29tMSAwHgYJKoZIhvcNAQkBFhFhZ2VudHpoQGdtYWlsLmNv +bTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJzRMFoLDuYOwJ8szrS4 +nOibtiimiXZJGx3I/RcFZxaH4nL/WcEb1fwftMQxx73IBJnqnDYkDOzUmzItPMn0 +t2WrNYesC5GqLNRm87m6PVt010tZvq/WxTn6+9qruiGm1PhFxzLQfrClpEeOshlG +UeoQjPOMrhCmofDM2NQo3D4wIQT0kCJxIPq6wCZt22/Yqz1EmR0UnF/R3ZtiB8O+ +SQGcsUKy4se3919xq+ZkzBdMxLneO5sofUiDC9MgRfiU960tbHPGX9I9P+kLK89S +yajPEYaRUkSBFjV5kdDK3+L6XckdMbY2pvwhAnVXSmd13Bf2V9XisUrX2Mr4YlnS +sy0CAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAVPY/z6Mvjg5EGHzU8bXyuXqxrx8Q +GBwf3PY25aDF6ofRrTCzMdIhthv8eRtGwHinkpgaK34D7hI/dPB7aswQTzED5c+l +S2au5OzzCj454oXdhSRA5Rt0mu/+pxmQ+iNk+7XJxgTN0mk1dYQqodyZ+vC4NIYb +javMlU4zDm4JPtwDs0Mz/d7gf14MU60jppF2vl6AYFHKYBLMHBmqxjy6H9YHjRjQ +oe4TNpn0zxJAPu5LqMkfB2+eLOe6ced7DcLLbbeVJ4Xtqj6Y5KsAyVojWQxrk4vW +3WO/953pHofO5F2ricS/rsf+5ivTmfiP8mQYTtp7k3T11sIZ4DOmtNwO4A== -----END CERTIFICATE----- diff --git a/t/cert/test.key b/t/cert/test.key index 6c13527117..4c8c905b2f 100644 --- a/t/cert/test.key +++ b/t/cert/test.key @@ -1,15 +1,28 @@ ------BEGIN RSA PRIVATE KEY----- -MIICXgIBAAKBgQDo/XzNS+2ZopArbF4/LxlsXBLJMvD6Nbq315lqJN5zxfeJs31Z -6avEfORNGKTE/dwBCghNG5mJC8XhDsM7rAyTP9vTPB+Bfm550arTjsAk/qf+bCUM -6MZI2iYEuhdDOju1V7rSKQSbdnINSqck8ky3eEiY7ldKingw8y5lr1aEVwIDAQAB -AoGBANgB66sKMga2SKN5nQdHS3LDCkevCutu1OWM5ZcbB4Kej5kC57xsf+tzPtab -emeIVGhCPOAALqB4YcT+QtMX967oM1MjcFbtH7si5oq6UYyp3i0G9Si6jIoVHz3+ -8yOUaqwKbK+bRX8VS0YsHZmBsPK5ryN50iUwsU08nemoA94BAkEA9GS9Q5OPeFkM -tFxsIQ1f2FSsZAuN/1cpZgJqY+YaAN7MSPGTWyfd7nWG/Zgk3GO9/2ihh4gww+7B -To09GkmW4QJBAPQOHC2V+t2TA98+6Lj6+TYwcGEkhOENfVpH25mQ+kXgF/1Bd6rA -nosT1bdAY+SnmWXbSw6Kv5C20Em+bEX8WjcCQCSRRjhsRdVODbaW9Z7kb2jhEoJN -sEt6cTlQNzcHYPCsZYisjM3g4zYg47fiIfHQAsfKkhDDcfh/KvFj9LaQOEECQQCH -eBWYEDpSJ7rsfqT7mQQgWj7nDThdG/nK1TxGP71McBmg0Gg2dfkLRhVJRQqt74Is -kc9V4Rp4n6F6baL4Lh19AkEA6pZZer0kg3Kv9hjhaITIKUYdfIp9vYnDRWbQlBmR -atV8V9u9q2ETZvqfHpN+9Lu6NYR4yXIEIRf1bnIZ/mr9eQ== ------END RSA PRIVATE KEY----- +-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCc0TBaCw7mDsCf +LM60uJzom7Yopol2SRsdyP0XBWcWh+Jy/1nBG9X8H7TEMce9yASZ6pw2JAzs1Jsy +LTzJ9LdlqzWHrAuRqizUZvO5uj1bdNdLWb6v1sU5+vvaq7ohptT4Rccy0H6wpaRH +jrIZRlHqEIzzjK4QpqHwzNjUKNw+MCEE9JAicSD6usAmbdtv2Ks9RJkdFJxf0d2b +YgfDvkkBnLFCsuLHt/dfcavmZMwXTMS53jubKH1IgwvTIEX4lPetLWxzxl/SPT/p +CyvPUsmozxGGkVJEgRY1eZHQyt/i+l3JHTG2Nqb8IQJ1V0pnddwX9lfV4rFK19jK ++GJZ0rMtAgMBAAECggEABjaOkcllis1o/yrVZMPPabLpAHV6tZ5MuKfNiUOMSPr+ +HfF1OFQL7MxCdfyFQ1prqOp/9nAut+puMgp99wAfDQ7qanNGq7vgQKkfPSD+dy4V +rUquELBJH6nh9SZqfpSqKaJgHlNe6vehHuRYikJRkrJwVzegGjuekm3B+y6Zl/gc +e0p5Ha3MTLTFjocwYzgTjJlxD40wlbjpuVnmzKjo8AKNv1F1azMaqBmt1VfPiDn0 +Xyq4SPEsWKnEAl2kZdaIBR6zIx7Z3zNUwkfb32QwNoSyo8wS7lCgf2GVS7r1Eul6 +iiCE/Gd7w10alW4Pu96shVqkvKn7ROF2nBP9xOSPwQKBgQDCuD6mlNpA07iOX364 +aAzIAYookceVA0I9L/fbOQW7RgpvYpM8lxr31TQ3fBDkXSgjzMMYjnk4kz+xN+BB +WFdjb4raUBtrvip8Q8QZ53DVQK/LodHh0XhipbOxZrDm+6o5nQD0fTqHCBIHSVFF +tXX2Y90t1cxWMMleRhfNEuzkQQKBgQDOK0rs7mf04Xhc4ZIRIxOtNFnthGp4Kqp7 +SD8VQpbPOLV8iqZEtXIy/hvoTpfQW30c1931KgDQ3Pv5MZYpI7PLqrqkj4tGCQ91 +DJ03GWkSXcMwlPmJRbvgWIeCLgShU5PLxmQu3mH2DP+uGFUBq5/6miDDVjF9z6vb +BwYlG66j7QKBgA0n/bOrowN2SqXz9c/n19U7pWYQU3fR/Iu9zfVV6Pk6RkI4WtJh +M0VDdn+5Njr3wFqK3zOtjKsx57/FkrVXjq/9PVh6yR+CfcRfn8RQSuNdt4L+r/ud +95BSuc1mrtUsc9for8PVIjs1ZGJxpbgcBphbLvqF04SPT0u7WKhWewMBAoGAcJO/ +RAUiitsbaExcADORKQDvIf0uThOuJ8dZevhzdQ/YOftTsy0JAMM05fMUfteWR8uw +DZE0BNjGVlo3TpuKL+o4JGele0azRAzxRAcCEt9UGBEg+U40utpclD8glB8ZEypv +xg/0mfCbJKtwr4rRvnuu7DsCp1pg0ybQui6VfDkCgYBXHwcrZwmv7kgr4pUG6oZj +fzjFenQFqibvb2h7QESyCW13O885GxU13DKv4zg1yi6EqPIopz16qCiUNCvWr5Us +6sI74wEVI3MzmzG0Htgl29q5yWpeY+7libC/fbZYG8GFgdINq58ko9be1u/8644S +t2hoKM9/vrVFh9p9qGzckg== +-----END PRIVATE KEY----- diff --git a/util/build-with-dd.sh b/util/build-with-dd.sh index db318ce391..a56a89119b 100755 --- a/util/build-with-dd.sh +++ b/util/build-with-dd.sh @@ -20,9 +20,13 @@ fi disable_pcre2=--without-pcre2 answer=`$root/util/ver-ge "$NGINX_VERSION" 1.25.1` -if [ "$answer" = "N" ]; then +if [ "$answer" = "N" ] || [ "$USE_PCRE2" = "Y" ]; then disable_pcre2="" fi +if [ "$USE_PCRE2" = "Y" ]; then + PCRE_INC=$PCRE2_INC + PCRE_LIB=$PCRE2_LIB +fi time ngx-build $force $version \ --with-threads \ diff --git a/util/build-without-ssl.sh b/util/build-without-ssl.sh index 97097daac0..c52d5873f6 100755 --- a/util/build-without-ssl.sh +++ b/util/build-without-ssl.sh @@ -26,9 +26,13 @@ add_fake_shm_module="--add-module=$root/t/data/fake-shm-module" disable_pcre2=--without-pcre2 answer=`$root/util/ver-ge "$NGINX_VERSION" 1.25.1` -if [ "$answer" = "N" ]; then +if [ "$answer" = "N" ] || [ "$USE_PCRE2" = "Y" ]; then disable_pcre2="" fi +if [ "$USE_PCRE2" = "Y" ]; then + PCRE_INC=$PCRE2_INC + PCRE_LIB=$PCRE2_LIB +fi time ngx-build $force $version \ --with-threads \ diff --git a/util/build.sh b/util/build.sh index 3a786a186f..41896f2c7e 100755 --- a/util/build.sh +++ b/util/build.sh @@ -32,9 +32,13 @@ fi disable_pcre2=--without-pcre2 answer=`$root/util/ver-ge "$NGINX_VERSION" 1.25.1` -if [ "$answer" = "N" ]; then +if [ "$answer" = "N" ] || [ "$USE_PCRE2" = "Y" ]; then disable_pcre2="" fi +if [ "$USE_PCRE2" = "Y" ]; then + PCRE_INC=$PCRE2_INC + PCRE_LIB=$PCRE2_LIB +fi time ngx-build $force $version \ --with-threads \ diff --git a/valgrind.suppress b/valgrind.suppress index 8761fb350e..743fb67d77 100644 --- a/valgrind.suppress +++ b/valgrind.suppress @@ -234,3 +234,73 @@ fun:ngx_pass_open_channel fun:ngx_start_privileged_agent_processes } +{ + + Memcheck:Leak + match-leak-kinds: definite + fun:malloc + fun:ngx_alloc + fun:ngx_regex_malloc + fun:pcre2_compile_context_create_8 + fun:ngx_regex_compile + fun:ngx_http_regex_compile + fun:ngx_http_core_regex_location + fun:ngx_http_core_location + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_core_server + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} +{ + + Memcheck:Leak + match-leak-kinds: definite + fun:malloc + fun:ngx_alloc + fun:ngx_regex_malloc + fun:pcre2_compile_context_create_8 + fun:ngx_regex_compile + fun:ngx_http_regex_compile + fun:ngx_http_rewrite + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_core_location + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_core_server + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} +{ + + Memcheck:Leak + match-leak-kinds: definite + fun:malloc + fun:ngx_alloc + fun:ngx_regex_malloc + fun:pcre2_compile_context_create_8 + fun:ngx_regex_compile + fun:ngx_http_regex_compile + fun:ngx_http_rewrite + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_core_server + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_http_block + fun:ngx_conf_handler + fun:ngx_conf_parse + fun:ngx_init_cycle + fun:main +} From f29e8487b298acd30ee30aa58b7ed65ec80b3bc5 Mon Sep 17 00:00:00 2001 From: willmafh Date: Sat, 23 Sep 2023 20:41:56 +0800 Subject: [PATCH 112/254] doc: update TODO list since tcpsock:bind is already implemented. --- README.markdown | 1 - 1 file changed, 1 deletion(-) diff --git a/README.markdown b/README.markdown index 29945d4997..aaf53b1459 100644 --- a/README.markdown +++ b/README.markdown @@ -966,7 +966,6 @@ TODO * cosocket: implement LuaSocket's unconnected UDP API. * cosocket: add support in the context of [init_by_lua*](#init_by_lua). -* cosocket: implement the `bind()` method for stream-typed cosockets. * cosocket: review and merge aviramc's [patch](https://github.com/openresty/lua-nginx-module/pull/290) for adding the `bsdrecv` method. * cosocket: add configure options for different strategies of handling the cosocket connection exceeding in the pools. * review and apply vadim-pavlov's patch for [ngx.location.capture](#ngxlocationcapture)'s `extra_headers` option From 2448743b6862d63c2005d75544d9071b1210d67a Mon Sep 17 00:00:00 2001 From: lijunlong Date: Fri, 6 Oct 2023 14:32:53 +0800 Subject: [PATCH 113/254] tests: update t/cert/test.crl. --- t/cert/test.crl | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/t/cert/test.crl b/t/cert/test.crl index 098fd54bf9..7ce2f6dc7c 100644 --- a/t/cert/test.crl +++ b/t/cert/test.crl @@ -1,11 +1,14 @@ -----BEGIN X509 CRL----- -MIIBjzCB+QIBATANBgkqhkiG9w0BAQUFADCBlzELMAkGA1UEBhMCVVMxEzARBgNV -BAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28xEjAQBgNVBAoM -CU9wZW5SZXN0eTESMBAGA1UECwwJT3BlblJlc3R5MREwDwYDVQQDDAh0ZXN0LmNv -bTEgMB4GCSqGSIb3DQEJARYRYWdlbnR6aEBnbWFpbC5jb20XDTE0MDcyMTIxNDEy -MloXDTE0MDgyMDIxNDEyMlowHDAaAgkApQ5tVpK3luIXDTE0MDcyMTIxNDEwMlqg -DzANMAsGA1UdFAQEAgIQATANBgkqhkiG9w0BAQUFAAOBgQBDZ6UY0Qg7qDoLrXXl -gJElFilZ7LiKPqjE3+Rfx7XkgdbPxjGCr77TfMm+smdvawk7WHv1AOvRH7kGrgGT -kGJZwqJ4vKa/NpEWJIMAZ1Gq9BIH/Ig6ffmPk+S9ozcVHKJDW7x4nMuotyj1hILN -EePv78DZCYMZgf8WwMElNgz6Hw== +MIICGzCCAQMCAQEwDQYJKoZIhvcNAQELBQAwgZcxCzAJBgNVBAYTAlVTMRMwEQYD +VQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNpc2NvMRIwEAYDVQQK +DAlPcGVuUmVzdHkxEjAQBgNVBAsMCU9wZW5SZXN0eTERMA8GA1UEAwwIdGVzdC5j +b20xIDAeBgkqhkiG9w0BCQEWEWFnZW50emhAZ21haWwuY29tFw0yMzEwMDYwNjMw +MTlaFw0yMzExMDUwNjMwMTlaMCcwJQIUImcuJ8MJpeNhvYBEoEGGz5oCBg4XDTIz +MTAwNjA2MjkyNVqgDjAMMAoGA1UdFAQDAgECMA0GCSqGSIb3DQEBCwUAA4IBAQBw +bqXCiJyDh804u7n4g1QrHpuiP9tdqCyxmvRVx34U51THGsLhkSufOzlaT2okTG0s +Oj0KiThRcwfjUpSBu1Lg81XtImEpZ1E97Doq/7QfH6P5D7co5U9MCdtzfNuWWKFD +likVmARV4aAl0VF0+Rqk+yvmh8yN1p9gLzM0AFoALVv2doU2oLid/DVuzxfMfRqC +Kr6OxEV/5umm1K72m8DaVtGjpX+M/wdLoTeX5r1bFp5q0QMPPZb8ciW+/9ovIG+I +EzJwrxMRMbi5DEnFgnkNHghUUDUlqZVVgdIIxR3un5gKrsmg7ZHrevF/iiJtKHAj +vgmsV9XKo4AUjcVtXrqx -----END X509 CRL----- From 8e9c33a9efcde74f30f53993b208f8c3d6b37a3c Mon Sep 17 00:00:00 2001 From: lijunlong Date: Fri, 6 Oct 2023 14:41:24 +0800 Subject: [PATCH 114/254] tests: update t/cert/test.crl. --- t/cert/test.crl | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/t/cert/test.crl b/t/cert/test.crl index 7ce2f6dc7c..0abfa77ac2 100644 --- a/t/cert/test.crl +++ b/t/cert/test.crl @@ -2,13 +2,13 @@ MIICGzCCAQMCAQEwDQYJKoZIhvcNAQELBQAwgZcxCzAJBgNVBAYTAlVTMRMwEQYD VQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNpc2NvMRIwEAYDVQQK DAlPcGVuUmVzdHkxEjAQBgNVBAsMCU9wZW5SZXN0eTERMA8GA1UEAwwIdGVzdC5j -b20xIDAeBgkqhkiG9w0BCQEWEWFnZW50emhAZ21haWwuY29tFw0yMzEwMDYwNjMw -MTlaFw0yMzExMDUwNjMwMTlaMCcwJQIUImcuJ8MJpeNhvYBEoEGGz5oCBg4XDTIz -MTAwNjA2MjkyNVqgDjAMMAoGA1UdFAQDAgECMA0GCSqGSIb3DQEBCwUAA4IBAQBw -bqXCiJyDh804u7n4g1QrHpuiP9tdqCyxmvRVx34U51THGsLhkSufOzlaT2okTG0s -Oj0KiThRcwfjUpSBu1Lg81XtImEpZ1E97Doq/7QfH6P5D7co5U9MCdtzfNuWWKFD -likVmARV4aAl0VF0+Rqk+yvmh8yN1p9gLzM0AFoALVv2doU2oLid/DVuzxfMfRqC -Kr6OxEV/5umm1K72m8DaVtGjpX+M/wdLoTeX5r1bFp5q0QMPPZb8ciW+/9ovIG+I -EzJwrxMRMbi5DEnFgnkNHghUUDUlqZVVgdIIxR3un5gKrsmg7ZHrevF/iiJtKHAj -vgmsV9XKo4AUjcVtXrqx +b20xIDAeBgkqhkiG9w0BCQEWEWFnZW50emhAZ21haWwuY29tFw0yMzEwMDYwNjM4 +MzlaFw0zMTEyMjMwNjM4MzlaMCcwJQIUImcuJ8MJpeNhvYBEoEGGz5oCBg4XDTIz +MTAwNjA2MjkyNVqgDjAMMAoGA1UdFAQDAgEEMA0GCSqGSIb3DQEBCwUAA4IBAQBj +FciorrAuXxn1ULW0XJ7PElwTxZtBrb838EHYvkZ5OdT5tZcucYR6XTZpfT1Up/Px +rC9EZ1/aZ0wSQfYEQuctafyVCJoPN71IV9IWpPTWm8JyEvnE1W3SgHJujItanyZ3 +aMDihljxV9eKyEQnZPQZkaOjAKhj8d2/XZLQ3uIrjWy+/OxcaBQK4a8bDoSM3GZT +J6YCD2UBVYKSiROMZZAj3m1thLAGm1RM7A6vjEcH7rPyoxhok5SdxXH5ERY94/ro +McjNCv6zV8/Ue5/+ajz5pu/48T901mlIicHry8uImJvlnqAXlH8ReJ+hiSfGhbZ5 +WYNf0wN81NXwTxPIb+v2 -----END X509 CRL----- From 03ec7f1d71b53aef91e7f42cc7ea675ca5ccd5c0 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Tue, 17 Oct 2023 17:35:45 +0200 Subject: [PATCH 115/254] bugfix: don't include pcre.h with PCRE2 used. pcre.h is a PCRE header and is not exposed by PCRE2 library causing compilation error as the header is not found. Don't include pcre.h if nginx is compiled with PCRE2 support enabled. Fixes: cb83e33e2657 ("feature: support pcre2") Signed-off-by: Christian Marangi --- src/ngx_http_lua_common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h index 541fa881db..4bbfd8c780 100644 --- a/src/ngx_http_lua_common.h +++ b/src/ngx_http_lua_common.h @@ -54,7 +54,7 @@ typedef struct { #endif -#if (NGX_PCRE) +#if defined(NGX_PCRE) && !defined(NGX_PCRE2) #include # if (PCRE_MAJOR > 8) || (PCRE_MAJOR == 8 && PCRE_MINOR >= 21) # define LUA_HAVE_PCRE_JIT 1 From 309edb6832903b88644eff94f278e75bcf188a2b Mon Sep 17 00:00:00 2001 From: lijunlong Date: Tue, 9 Nov 2021 12:43:23 +0800 Subject: [PATCH 116/254] tests: fixed test for http3. --- .travis.yml | 15 +- src/ngx_http_lua_socket_tcp.c | 6 + t/001-set.t | 12 +- t/005-exit.t | 5 +- t/014-bugs.t | 23 ++- t/015-status.t | 1 + t/016-resp-header.t | 82 ++++++-- t/020-subrequest.t | 4 + t/022-redirect.t | 11 +- t/023-rewrite/client-abort.t | 6 +- t/023-rewrite/exit.t | 3 + t/023-rewrite/on-abort.t | 6 +- t/023-rewrite/redirect.t | 11 +- t/023-rewrite/req-socket.t | 10 +- t/023-rewrite/sleep.t | 3 + t/023-rewrite/socket-keepalive.t | 8 + t/023-rewrite/tcp-socket.t | 6 + t/023-rewrite/uthread-exit.t | 2 + t/023-rewrite/uthread-spawn.t | 1 + t/024-access/client-abort.t | 10 +- t/024-access/exit.t | 3 + t/024-access/on-abort.t | 6 +- t/024-access/redirect.t | 11 +- t/024-access/sleep.t | 3 + t/024-access/uthread-exit.t | 2 + t/024-access/uthread-spawn.t | 1 + t/025-codecache.t | 3 + t/026-mysql.t | 1 + t/028-req-header.t | 315 ++++++++++++++++++++++++++----- t/033-ctx.t | 2 + t/041-header-filter.t | 50 ++++- t/043-shdict.t | 4 + t/044-req-body.t | 44 ++++- t/045-ngx-var.t | 18 +- t/056-flush.t | 1 + t/057-flush-timeout.t | 6 +- t/058-tcp-socket.t | 6 + t/062-count.t | 4 + t/065-tcp-socket-timeout.t | 1 + t/066-socket-receiveuntil.t | 2 + t/067-req-socket.t | 10 +- t/068-socket-keepalive.t | 13 ++ t/075-logby.t | 12 +- t/077-sleep.t | 3 + t/082-body-filter-2.t | 12 +- t/082-body-filter.t | 7 + t/083-bad-sock-self.t | 2 + t/084-inclusive-receiveuntil.t | 4 + t/087-udp-socket.t | 9 +- t/088-req-method.t | 4 + t/091-coroutine.t | 6 + t/093-uthread-spawn.t | 2 + t/094-uthread-exit.t | 10 + t/095-uthread-exec.t | 2 + t/096-uthread-redirect.t | 2 + t/100-client-abort.t | 8 +- t/101-on-abort.t | 8 +- t/103-req-http-ver.t | 11 +- t/104-req-raw-header.t | 11 +- t/105-pressure.t | 4 +- t/106-timer.t | 1 + t/109-timer-hup.t | 4 + t/116-raw-req-socket.t | 10 +- t/129-ssl-socket.t | 7 + t/131-duplex-req-socket.t | 8 +- t/151-initby-hup.t | 4 +- t/152-timer-every.t | 1 + t/153-semaphore-hup.t | 2 + t/157-socket-keepalive-hup.t | 4 + t/162-static-module-location.t | 16 +- t/163-signal.t | 2 + t/166-ssl-client-hello.t | 94 +++++++-- t/166-worker-thread.t | 2 + t/cert/http3/http3.crt | 29 +++ t/cert/http3/http3.key | 52 +++++ 75 files changed, 954 insertions(+), 130 deletions(-) create mode 100644 t/cert/http3/http3.crt create mode 100644 t/cert/http3/http3.key diff --git a/.travis.yml b/.travis.yml index b29ab4cc2a..f70f825574 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,4 @@ -dist: bionic +dist: focal branches: only: @@ -24,6 +24,14 @@ addons: - libtest-longstring-perl - liblist-moreutils-perl - libgd-dev + - time + - cmake + - curl + - libunwind-dev + - libpsl0 + - wget + - libldap-2.4-2 + - libbrotli1 cache: directories: @@ -60,6 +68,7 @@ env: - NGINX_VERSION=1.21.4 OPENSSL_VER=1.1.1s OPENSSL_PATCH_VER=1.1.1f - NGINX_VERSION=1.25.1 OPENSSL_VER=1.1.0l OPENSSL_PATCH_VER=1.1.0d - NGINX_VERSION=1.25.1 OPENSSL_VER=1.1.1s OPENSSL_PATCH_VER=1.1.1f USE_PCRE2=Y + - NGINX_VERSION=1.25.1 BORINGSSL=1 TEST_NGINX_USE_HTTP3=1 USE_PCRE2=Y services: - memcached @@ -67,8 +76,6 @@ services: - mysql before_install: - - sudo apt update - - sudo apt install --only-upgrade ca-certificates - '! grep -n -P ''(?<=.{80}).+'' --color `find src -name ''*.c''` `find . -name ''*.h''` || (echo "ERROR: Found C source lines exceeding 80 columns." > /dev/stderr; exit 1)' - '! grep -n -P ''\t+'' --color `find src -name ''*.c''` `find . -name ''*.h''` || (echo "ERROR: Cannot use tabs." > /dev/stderr; exit 1)' - /usr/bin/env perl $(command -v cpanm) --sudo --notest Test::Nginx IPC::Run > build.log 2>&1 || (cat build.log && exit 1) @@ -145,6 +152,8 @@ script: - ldd `which nginx`|grep -E 'luajit|ssl|pcre' - export LD_PRELOAD=$PWD/mockeagain/mockeagain.so - export LD_LIBRARY_PATH=$PWD/mockeagain:$LD_LIBRARY_PATH + - export TEST_NGINX_HTTP3_CRT=$PWD/t/cert/http3/http3.crt + - export TEST_NGINX_HTTP3_KEY=$PWD/t/cert/http3/http3.key - export TEST_NGINX_RESOLVER=8.8.4.4 - dig +short myip.opendns.com @resolver1.opendns.com || exit 0 - dig +short @$TEST_NGINX_RESOLVER openresty.org || exit 0 diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 5be85dcd46..88fe923eb1 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -5099,6 +5099,12 @@ ngx_http_lua_req_socket(lua_State *L) } #endif +#if (NGX_HTTP_V3) + if (r->http_version == NGX_HTTP_VERSION_30) { + return luaL_error(L, "http v3 not supported yet"); + } +#endif + if (!raw && r->headers_in.chunked) { lua_pushnil(L); lua_pushliteral(L, "chunked request bodies not supported yet"); diff --git a/t/001-set.t b/t/001-set.t index db18f0258c..abbee72121 100644 --- a/t/001-set.t +++ b/t/001-set.t @@ -404,8 +404,16 @@ API disabled in the context of set_by_lua* GET /lua --- response_body_like: 500 Internal Server Error --- error_code: 500 ---- error_log -API disabled in the context of set_by_lua* +--- error_log eval +my $err_log; + +if (defined $ENV{TEST_NGINX_USE_HTTP3}) { + $err_log = "http v3 not supported yet"; +} else { + $err_log = "API disabled in the context of set_by_lua*"; +} + +$err_log; diff --git a/t/005-exit.t b/t/005-exit.t index eb123bd179..e057fe1c69 100644 --- a/t/005-exit.t +++ b/t/005-exit.t @@ -65,7 +65,7 @@ GET /lua --- error_log attempt to set status 404 via ngx.exit after sending out the response status 200 --- no_error_log -alert +[alert] --- response_body hi @@ -123,6 +123,7 @@ GET /api?user=agentz === TEST 6: working with ngx_auth_request (simplest form, w/o ngx_memc) +--- skip_eval: 3:$ENV{TEST_NGINX_USE_HTTP3} --- http_config eval " lua_package_cpath '$::LuaCpath'; @@ -195,6 +196,7 @@ Logged in 56 === TEST 7: working with ngx_auth_request (simplest form) +--- skip_eval: 3:$ENV{TEST_NGINX_USE_HTTP3} --- http_config eval " lua_package_cpath '$::LuaCpath'; @@ -267,6 +269,7 @@ Logged in 56 === TEST 8: working with ngx_auth_request +--- skip_eval: 3:$ENV{TEST_NGINX_USE_HTTP3} --- http_config eval " lua_package_cpath '$::LuaCpath'; diff --git a/t/014-bugs.t b/t/014-bugs.t index 877aecfdb5..1f140be51d 100644 --- a/t/014-bugs.t +++ b/t/014-bugs.t @@ -194,6 +194,14 @@ Hi" === TEST 8: github issue 37: header bug https://github.com/chaoslawful/lua-nginx-module/issues/37 + +https://datatracker.ietf.org/doc/html/rfc7540#section-8.1.2 + Just as in HTTP/1.x, header field names are strings of ASCII + characters that are compared in a case-insensitive fashion. However, + header field names MUST be converted to lowercase prior to their + encoding in HTTP/2. A request or response containing uppercase + header field names MUST be treated as malformed + --- config location /sub { content_by_lua ' @@ -220,8 +228,17 @@ https://github.com/chaoslawful/lua-nginx-module/issues/37 --- request GET /lua --- raw_response_headers_like eval -".*Set-Cookie: TestCookie1=foo\r +my $headers; + +if (defined $ENV{TEST_NGINX_USE_HTTP3}) { + $headers = ".*set-cookie: TestCookie1=foo\r +set-cookie: TestCookie2=bar.*" +} else { + $headers = ".*Set-Cookie: TestCookie1=foo\r Set-Cookie: TestCookie2=bar.*" +} + +$headers; @@ -770,6 +787,10 @@ eof found in body stream === TEST 34: testing a segfault when using ngx_poll_module + ngx_resolver See more details here: http://mailman.nginx.org/pipermail/nginx-devel/2013-January/003275.html + +http3 may cache the dns result. +so need to skip for http3 +--- skip_eval: 2:$ENV{TEST_NGINX_USE_HTTP3} --- config location /t { set $myserver nginx.org; diff --git a/t/015-status.t b/t/015-status.t index a69c59377b..43faa204a7 100644 --- a/t/015-status.t +++ b/t/015-status.t @@ -233,6 +233,7 @@ GET /t --- error_code: 101 --- no_error_log [error] +--- skip_eval: 3:$ENV{TEST_NGINX_USE_HTTP3} diff --git a/t/016-resp-header.t b/t/016-resp-header.t index 65c5d75a8e..60c63929ae 100644 --- a/t/016-resp-header.t +++ b/t/016-resp-header.t @@ -65,6 +65,7 @@ GET /read Content-Length: 3 --- response_body chop Hel +--- skip_eval: 3:$ENV{TEST_NGINX_USE_HTTP3} @@ -113,8 +114,16 @@ Hello } --- request GET /read ---- raw_response_headers_like chomp -X-Foo: a\r\n.*?X-Foo: bc\r\n +--- raw_response_headers_like eval +my $headers; + +if (defined $ENV{TEST_NGINX_USE_HTTP3}) { + $headers = qr/x-foo: a\r\n.*?x-foo: bc\r\n/ +} else { + $headers = qr/X-Foo: a\r\n.*?X-Foo: bc\r\n/ +} + +$headers; --- response_body Hello @@ -184,8 +193,16 @@ Hello } --- request GET /read ---- raw_response_headers_like chomp -X-Foo: a\r\n.*?X-Foo: abc\r\n +--- raw_response_headers_like eval +my $headers; + +if (defined $ENV{TEST_NGINX_USE_HTTP3}) { + $headers = "x-foo: a\r\n.*?x-foo: abc\r\n" +} else { + $headers = "X-Foo: a\r\n.*?X-Foo: abc\r\n" +} + +$headers; --- response_body Hello @@ -203,8 +220,17 @@ Hello --- request GET /lua --- raw_response_headers_like eval -".*Foo: a\r -Foo: b.*" +my $headers; + +if (defined $ENV{TEST_NGINX_USE_HTTP3}) { + $headers = ".*foo: a\r +foo: b.*"; +} else { + $headers = ".*Foo: a\r +Foo: b.*"; +} + +$headers; --- response_body @@ -222,8 +248,17 @@ Foo: b.*" --- request GET /lua --- raw_response_headers_like eval -".*Foo: a\r -Foo: b.*" +my $headers; + +if (defined $ENV{TEST_NGINX_USE_HTTP3}) { + $headers = ".*foo: a\r +foo: b.*"; +} else { + $headers = ".*Foo: a\r +Foo: b.*"; +} + +$headers; --- response_body @@ -278,7 +313,7 @@ hello --- error_log attempt to set ngx.header.HEADER after sending out response headers --- no_error_log eval -["alert", "warn"] +["[alert]", "[warn]"] @@ -1071,8 +1106,8 @@ GET /t --- more_headers Foo: bar Bah: baz ---- response_headers -Location: http://localhost:$ServerPort/t/ +--- response_headers_like +Location: https?://localhost:\d+/t/ --- response_body_like: 301 Moved Permanently --- error_code: 301 --- no_error_log @@ -1094,8 +1129,8 @@ GET /t Foo: bar Bah: baz --- response_body_like: 301 Moved Permanently ---- response_headers -Location: http://localhost:$ServerPort/t/ +--- response_headers_like +Location: https?://localhost:\d+/t/ --- error_code: 301 --- no_error_log [error] @@ -1115,8 +1150,8 @@ GET /t --- more_headers Foo: bar Bah: baz ---- response_headers -Location: http://localhost:$ServerPort/t/ +--- response_headers_like +Location: https?://localhost:\d+/t/ Foo: /t/ --- response_body_like: 301 Moved Permanently --- error_code: 301 @@ -1139,8 +1174,8 @@ GET /t --- more_headers Foo: bar Bah: baz ---- response_headers -Location: http://localhost:$ServerPort/t/ +--- response_headers_like +Location: https?://localhost:\d+/t/ Foo: /t/ --- response_body_like: 301 Moved Permanently --- error_code: 301 @@ -1159,8 +1194,16 @@ Foo: /t/ } --- request GET /lua ---- raw_response_headers_like chop -cache-Control: private +--- raw_response_headers_like eval +my $headers; + +if (defined $ENV{TEST_NGINX_USE_HTTP3}) { + $headers = "cache-control: private" +} else { + $headers = "cache-Control: private" +} + +$headers; --- response_body Cache-Control: private @@ -1509,6 +1552,7 @@ hi --- error_log my Transfer-Encoding: chunked my transfer-encoding: chunked +--- skip_eval: 6:$ENV{TEST_NGINX_USE_HTTP3} diff --git a/t/020-subrequest.t b/t/020-subrequest.t index 844b64794f..f629ca8754 100644 --- a/t/020-subrequest.t +++ b/t/020-subrequest.t @@ -1227,6 +1227,8 @@ F(ngx_http_finalize_request) { --- error_code --- no_error_log [error] +--- curl_error +curl: (52) Empty reply from server @@ -2622,6 +2624,7 @@ pr: Host: localhost --- no_error_log [error] +--- skip_eval: 3:$ENV{TEST_NGINX_USE_HTTP3} @@ -2655,6 +2658,7 @@ pr: Host: localhost --- no_error_log [error] +--- skip_eval: 3:$ENV{TEST_NGINX_USE_HTTP3} diff --git a/t/022-redirect.t b/t/022-redirect.t index ef80174ca5..197c76e1d7 100644 --- a/t/022-redirect.t +++ b/t/022-redirect.t @@ -122,7 +122,16 @@ GET /read } --- request GET /read ---- raw_response_headers_like: Location: /echo\r\n +--- raw_response_headers_like eval +my $headers; + +if (defined $ENV{TEST_NGINX_USE_HTTP3}) { + $headers = "location: /echo\r\n" +} else { + $headers = "Location: /echo\r\n" +} + +$headers; --- response_body_like: 302 Found --- error_code: 302 diff --git a/t/023-rewrite/client-abort.t b/t/023-rewrite/client-abort.t index 0d6f2b39b3..963717b012 100644 --- a/t/023-rewrite/client-abort.t +++ b/t/023-rewrite/client-abort.t @@ -19,7 +19,11 @@ our $StapScript = $t::StapThread::StapScript; repeat_each(2); -plan tests => repeat_each() * (blocks() * 3 - 1); +if (defined $ENV{TEST_NGINX_USE_HTTP3}) { + plan(skip_all => "HTTP3 does not support client abort"); +} else { + plan tests => repeat_each() * (blocks() * 3 - 1); +} $ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; $ENV{TEST_NGINX_MEMCACHED_PORT} ||= '11211'; diff --git a/t/023-rewrite/exit.t b/t/023-rewrite/exit.t index 39ea5cbd62..9add80441c 100644 --- a/t/023-rewrite/exit.t +++ b/t/023-rewrite/exit.t @@ -187,6 +187,7 @@ ngx.var.uid = res[1].uid; GET /api?uid=32 --- response_body Logged in 56 +--- skip_eval: 2:$ENV{TEST_NGINX_USE_HTTP3} @@ -258,6 +259,7 @@ ngx.var.uid = res[1].uid; GET /api?uid=32 --- response_body Logged in 56 +--- skip_eval: 2:$ENV{TEST_NGINX_USE_HTTP3} @@ -342,6 +344,7 @@ GET /api?uid=32 Logged in 56 --- no_error_log [error] +--- skip_eval: 3:$ENV{TEST_NGINX_USE_HTTP3} diff --git a/t/023-rewrite/on-abort.t b/t/023-rewrite/on-abort.t index 59c5df1167..d0bae78ee8 100644 --- a/t/023-rewrite/on-abort.t +++ b/t/023-rewrite/on-abort.t @@ -19,7 +19,11 @@ our $StapScript = $t::StapThread::StapScript; repeat_each(2); -plan tests => repeat_each() * (blocks() * 4 + 15); +if (defined $ENV{TEST_NGINX_USE_HTTP3}) { + plan(skip_all => "HTTP3 does not support on_abort"); +} else { + plan tests => repeat_each() * (blocks() * 4 + 15); +} $ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; $ENV{TEST_NGINX_MEMCACHED_PORT} ||= '11211'; diff --git a/t/023-rewrite/redirect.t b/t/023-rewrite/redirect.t index 8fa9aa2e79..e387ee8fb7 100644 --- a/t/023-rewrite/redirect.t +++ b/t/023-rewrite/redirect.t @@ -119,7 +119,16 @@ GET /read } --- request GET /read ---- raw_response_headers_like: Location: /foo\r\n +--- raw_response_headers_like eval +my $headers; + +if (defined $ENV{TEST_NGINX_USE_HTTP3}) { + $headers = "location: /foo\r\n" +} else { + $headers = "Location: /foo\r\n" +} + +$headers; --- response_body_like: 302 Found --- error_code: 302 diff --git a/t/023-rewrite/req-socket.t b/t/023-rewrite/req-socket.t index 9292385265..f4dd6f4e18 100644 --- a/t/023-rewrite/req-socket.t +++ b/t/023-rewrite/req-socket.t @@ -1,6 +1,14 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use Test::Nginx::Socket::Lua; +our $SkipReason; + +BEGIN { + if ($ENV{TEST_NGINX_USE_HTTP3}) { + $SkipReason = "http3 does not support ngx.req.socket"; + } +} + +use Test::Nginx::Socket::Lua $SkipReason ? (skip_all => $SkipReason) : (); repeat_each(2); diff --git a/t/023-rewrite/sleep.t b/t/023-rewrite/sleep.t index 8d4c2da2ea..0135d5e440 100644 --- a/t/023-rewrite/sleep.t +++ b/t/023-rewrite/sleep.t @@ -110,6 +110,7 @@ bad argument #1 to 'sleep' === TEST 5: sleep 0.5 - multi-times +--- quic_max_idle_timeout: 1.0 --- config location /test { rewrite_by_lua ' @@ -135,6 +136,7 @@ lua sleep timer expired: "/test?" === TEST 6: sleep 0.5 - interleaved by ngx.say() - ended by ngx.sleep +--- quic_max_idle_timeout: 2.05 --- config location /test { rewrite_by_lua ' @@ -163,6 +165,7 @@ lua sleep timer expired: "/test?" === TEST 7: sleep 0.5 - interleaved by ngx.say() - not ended by ngx.sleep +--- quic_max_idle_timeout: 0.85 --- config location /test { rewrite_by_lua ' diff --git a/t/023-rewrite/socket-keepalive.t b/t/023-rewrite/socket-keepalive.t index c943e44616..5316af6be5 100644 --- a/t/023-rewrite/socket-keepalive.t +++ b/t/023-rewrite/socket-keepalive.t @@ -176,6 +176,7 @@ received: OK === TEST 3: upstream sockets close prematurely +--- quic_max_idle_timeout: 1.1 --- http_config eval "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config @@ -253,6 +254,7 @@ done === TEST 4: http keepalive +--- quic_max_idle_timeout: 1.1 --- http_config eval "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config @@ -330,6 +332,7 @@ done === TEST 5: lua_socket_keepalive_timeout +--- quic_max_idle_timeout: 1.1 --- config server_tokens off; location /t { @@ -409,6 +412,7 @@ qr/lua tcp socket connection pool size: 30\b/] === TEST 6: lua_socket_pool_size +--- quic_max_idle_timeout: 1.1 --- config server_tokens off; location /t { @@ -489,6 +493,7 @@ qr/lua tcp socket connection pool size: 1\b/] === TEST 7: "lua_socket_keepalive_timeout 0" means unlimited +--- quic_max_idle_timeout: 1.1 --- config server_tokens off; location /t { @@ -571,6 +576,7 @@ lua tcp socket keepalive timeout: unlimited === TEST 8: setkeepalive(timeout) overrides lua_socket_keepalive_timeout +--- quic_max_idle_timeout: 1.1 --- config server_tokens off; location /t { @@ -650,6 +656,7 @@ qr/lua tcp socket connection pool size: 30\b/] === TEST 9: sock:setkeepalive(timeout, size) overrides lua_socket_pool_size +--- quic_max_idle_timeout: 1.1 --- config server_tokens off; location /t { @@ -730,6 +737,7 @@ qr/lua tcp socket connection pool size: 25\b/] === TEST 10: sock:keepalive_timeout(0) means unlimited +--- quic_max_idle_timeout: 1.1 --- config server_tokens off; location /t { diff --git a/t/023-rewrite/tcp-socket.t b/t/023-rewrite/tcp-socket.t index 5258487eba..b4bf7a6b78 100644 --- a/t/023-rewrite/tcp-socket.t +++ b/t/023-rewrite/tcp-socket.t @@ -1654,6 +1654,8 @@ GET /t --- ignore_response --- error_log bad argument #1 to 'send' (bad data type nil found) +--- curl_error +curl: (52) Empty reply from server @@ -1715,6 +1717,8 @@ GET /t --- ignore_response --- error_log bad argument #1 to 'send' (bad data type boolean found) +--- curl_error +curl: (52) Empty reply from server @@ -1776,6 +1780,8 @@ GET /t --- ignore_response --- error_log bad argument #1 to 'send' (bad data type userdata found) +--- curl_error +curl: (52) Empty reply from server diff --git a/t/023-rewrite/uthread-exit.t b/t/023-rewrite/uthread-exit.t index e25f7f8b0c..87f850ce8b 100644 --- a/t/023-rewrite/uthread-exit.t +++ b/t/023-rewrite/uthread-exit.t @@ -987,6 +987,7 @@ hello in thread after --- no_error_log [error] +--- skip_eval: 4:$ENV{TEST_NGINX_USE_HTTP3} @@ -1072,6 +1073,7 @@ hello in thread after --- no_error_log [error] +--- skip_eval: 4:$ENV{TEST_NGINX_USE_HTTP3} diff --git a/t/023-rewrite/uthread-spawn.t b/t/023-rewrite/uthread-spawn.t index dccef87dac..62d837cff7 100644 --- a/t/023-rewrite/uthread-spawn.t +++ b/t/023-rewrite/uthread-spawn.t @@ -1120,6 +1120,7 @@ body: hello world)$ --- no_error_log [error] +--- skip_eval: 4:$ENV{TEST_NGINX_USE_HTTP3} diff --git a/t/024-access/client-abort.t b/t/024-access/client-abort.t index 83bf0a4df1..99f1b810fd 100644 --- a/t/024-access/client-abort.t +++ b/t/024-access/client-abort.t @@ -1,6 +1,14 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use Test::Nginx::Socket::Lua; +our $SkipReason; + +BEGIN { + if ($ENV{TEST_NGINX_USE_HTTP3}) { + $SkipReason = "http3 does not support ngx.req.socket and lua_check_client_abort"; + } +} + +use Test::Nginx::Socket::Lua $SkipReason ? (skip_all => $SkipReason) : (); use t::StapThread; our $GCScript = <<_EOC_; diff --git a/t/024-access/exit.t b/t/024-access/exit.t index d6d66b8cfe..b77778213a 100644 --- a/t/024-access/exit.t +++ b/t/024-access/exit.t @@ -177,6 +177,7 @@ GET /api?uid=32 --- response_body Logged in 56 --- timeout: 3 +--- skip_eval: 2:$ENV{TEST_NGINX_USE_HTTP3} @@ -243,6 +244,7 @@ ngx.var.uid = res[1].uid; GET /api?uid=32 --- response_body Logged in 56 +--- skip_eval: 2:$ENV{TEST_NGINX_USE_HTTP3} @@ -320,6 +322,7 @@ ngx.var.uid = res[1].uid; GET /api?uid=32 --- response_body Logged in 56 +--- skip_eval: 2:$ENV{TEST_NGINX_USE_HTTP3} diff --git a/t/024-access/on-abort.t b/t/024-access/on-abort.t index b9532aea3f..4d58779742 100644 --- a/t/024-access/on-abort.t +++ b/t/024-access/on-abort.t @@ -19,7 +19,11 @@ our $StapScript = $t::StapThread::StapScript; repeat_each(2); -plan tests => repeat_each() * (blocks() * 4 + 15); +if (defined $ENV{TEST_NGINX_USE_HTTP3}) { + plan(skip_all => "HTTP3 does not support on_abort"); +} else { + plan tests => repeat_each() * (blocks() * 4 + 15); +} $ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; $ENV{TEST_NGINX_MEMCACHED_PORT} ||= '11211'; diff --git a/t/024-access/redirect.t b/t/024-access/redirect.t index b45fac718b..84b64c5f0b 100644 --- a/t/024-access/redirect.t +++ b/t/024-access/redirect.t @@ -119,6 +119,15 @@ GET /read } --- request GET /read ---- raw_response_headers_like: Location: /foo\r\n +--- raw_response_headers_like eval +my $headers; + +if (defined $ENV{TEST_NGINX_USE_HTTP3}) { + $headers = "location: /foo\r\n" +} else { + $headers = "Location: /foo\r\n" +} + +$headers; --- response_body_like: 302 Found --- error_code: 302 diff --git a/t/024-access/sleep.t b/t/024-access/sleep.t index fc1fc024b5..c7aa0b65a4 100644 --- a/t/024-access/sleep.t +++ b/t/024-access/sleep.t @@ -110,6 +110,7 @@ bad argument #1 to 'sleep' === TEST 5: sleep 0.5 - multi-times +--- quic_max_idle_timeout: 1.0 --- config location /test { access_by_lua ' @@ -135,6 +136,7 @@ lua sleep timer expired: "/test?" === TEST 6: sleep 0.5 - interleaved by ngx.say() - ended by ngx.sleep +--- quic_max_idle_timeout: 2.2 --- config location /test { access_by_lua ' @@ -163,6 +165,7 @@ lua sleep timer expired: "/test?" === TEST 7: sleep 0.5 - interleaved by ngx.say() - not ended by ngx.sleep +--- quic_max_idle_timeout: 0.85 --- config location /test { access_by_lua ' diff --git a/t/024-access/uthread-exit.t b/t/024-access/uthread-exit.t index 27572370d5..bd165ae708 100644 --- a/t/024-access/uthread-exit.t +++ b/t/024-access/uthread-exit.t @@ -880,6 +880,7 @@ after === TEST 11: exit in user thread (entry thread is still pending on reqsock:receive) +--- skip_eval: 5:$ENV{TEST_NGINX_USE_HTTP3} --- config location /lua { access_by_lua ' @@ -973,6 +974,7 @@ after === TEST 12: exit in user thread (entry thread is still pending on ngx.req.read_body) +--- skip_eval: 3:$ENV{TEST_NGINX_USE_HTTP3} --- config location /lua { client_body_timeout 12000ms; diff --git a/t/024-access/uthread-spawn.t b/t/024-access/uthread-spawn.t index bc92ccd32c..b31edbcb1e 100644 --- a/t/024-access/uthread-spawn.t +++ b/t/024-access/uthread-spawn.t @@ -1120,3 +1120,4 @@ body: hello world)$ --- no_error_log [error] +--- skip_eval: 4:$ENV{TEST_NGINX_USE_HTTP3} diff --git a/t/025-codecache.t b/t/025-codecache.t index 2a3eeb3b08..5be94d8ce7 100644 --- a/t/025-codecache.t +++ b/t/025-codecache.t @@ -966,6 +966,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/, === TEST 27: GC issue with the on_abort thread object +curl: (52) Empty reply from server --- config lua_code_cache off; location = /t { @@ -991,6 +992,8 @@ decrementing the reference count for Lua VM: 3 qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/, "lua close the global Lua VM", ] +--- curl_error eval +qr/curl: \(\d+\) Empty reply from server/ diff --git a/t/026-mysql.t b/t/026-mysql.t index 569f96fbc9..02e14b9382 100644 --- a/t/026-mysql.t +++ b/t/026-mysql.t @@ -69,6 +69,7 @@ kill status = 200 kill body = \{"errcode":0\}$ --- error_log eval qr{upstream timed out \(\d+: Connection timed out\) while sending query to drizzle upstream} +--- skip_eval: 3:$ENV{TEST_NGINX_USE_HTTP3} diff --git a/t/028-req-header.t b/t/028-req-header.t index 18b991052b..b9c5e97fe0 100644 --- a/t/028-req-header.t +++ b/t/028-req-header.t @@ -59,8 +59,13 @@ lua exceeding request header limit for k, v in pairs(headers) do h[k] = v end - ngx.say("Foo: ", h["Foo"] or "nil") - ngx.say("Bar: ", h["Bar"] or "nil") + if (ngx.req.http_version() == 3) then + ngx.say("Foo: ", h["foo"] or "nil") + ngx.say("Bar: ", h["bar"] or "nil") + else + ngx.say("Foo: ", h["Foo"] or "nil") + ngx.say("Bar: ", h["Bar"] or "nil") + end '; } --- request @@ -127,6 +132,7 @@ Foo: --- response_body eval "a" x 2048 --- timeout: 15 +--- skip_eval: 2:$ENV{TEST_NGINX_USE_HTTP3} @@ -145,6 +151,7 @@ Foo: --- response_body eval "a" x 2048 --- timeout: 15 +--- skip_eval: 2:$ENV{TEST_NGINX_USE_HTTP3} @@ -485,6 +492,7 @@ for my $k (@k) { --- timeout: 4 --- error_log lua exceeding request header limit 101 > 100 +--- skip_eval: 3:$ENV{TEST_NGINX_USE_HTTP3} @@ -523,20 +531,30 @@ while ($i <= 98) { $s --- response_body eval my @k; + +if (defined $ENV{TEST_NGINX_USE_HTTP3}) { + push @k, "host: localhost\n"; +} my $i = 1; while ($i <= 98) { push @k, "x-$i"; $i++; } -push @k, "connection: close\n"; -push @k, "host: localhost\n"; + +my $found_headers = "found 99 headers\n"; +if (!defined $ENV{TEST_NGINX_USE_HTTP3}) { + push @k, "connection: close\n"; + push @k, "host: localhost\n"; + $found_headers = "found 100 headers\n"; +} @k = sort @k; for my $k (@k) { if ($k =~ /\d+/) { $k .= ": $&\n"; } } -CORE::join("", @k) . "found 100 headers\n"; + +CORE::join("", @k) . $found_headers; --- timeout: 4 --- no_error_log [error] @@ -576,6 +594,9 @@ while ($i <= 101) { $s --- response_body eval my @k; +if (defined $ENV{TEST_NGINX_USE_HTTP3}) { + push @k, "host: localhost\n"; +} my $i = 1; while ($i <= 100) { push @k, "x-$i"; @@ -593,6 +614,7 @@ for my $k (@k) { --- timeout: 4 --- error_log lua exceeding request header limit 103 > 102 +--- skip_eval: 3:$ENV{TEST_NGINX_USE_HTTP3} @@ -628,13 +650,20 @@ while ($i <= 100) { $s --- response_body eval my @k; +if (defined $ENV{TEST_NGINX_USE_HTTP3}) { + push @k, "host: localhost\n"; +} my $i = 1; while ($i <= 100) { push @k, "x-$i"; $i++; } -push @k, "connection: close\n"; -push @k, "host: localhost\n"; + +if (!defined($ENV{TEST_NGINX_USE_HTTP3})) { + push @k, "connection: close\n"; + push @k, "host: localhost\n"; +} + @k = sort @k; for my $k (@k) { if ($k =~ /\d+/) { @@ -681,13 +710,18 @@ while ($i <= 105) { $s --- response_body eval my @k; +if (defined $ENV{TEST_NGINX_USE_HTTP3}) { + push @k, "host: localhost\n"; +} my $i = 1; while ($i <= 105) { push @k, "x-$i"; $i++; } -push @k, "connection: close\n"; -push @k, "host: localhost\n"; +if (!defined($ENV{TEST_NGINX_USE_HTTP3})) { + push @k, "connection: close\n"; + push @k, "host: localhost\n"; +} @k = sort @k; for my $k (@k) { if ($k =~ /\d+/) { @@ -830,10 +864,21 @@ hello world Content-Type: application/ocsp-request Test-Header: 1 --- response_body_like eval -qr/Connection: close\r +my $body; + +if (defined $ENV{TEST_NGINX_USE_HTTP3}) { + $body = qr/Connection: close\r +test-header: 1\r +\r +$/; +} else { + $body = qr/Connection: close\r Test-Header: 1\r \r -$/ +$/; +} + +$body; --- no_error_log [error] @@ -881,7 +926,36 @@ Foo20: foo20 Foo21: foo21 Foo22: foo22 --- response_body_like eval -qr/Bah: bah\r +my $headers; + +if (defined $ENV{TEST_NGINX_USE_HTTP3}) { + $headers = qr/bah: bah\r +test-header: 1\r +foo1: foo1\r +foo2: foo2\r +foo3: foo3\r +foo4: foo4\r +foo5: foo5\r +foo6: foo6\r +foo7: foo7\r +foo8: foo8\r +foo9: foo9\r +foo10: foo10\r +foo11: foo11\r +foo12: foo12\r +foo13: foo13\r +foo14: foo14\r +foo15: foo15\r +foo16: foo16\r +foo17: foo17\r +foo18: foo18\r +foo19: foo19\r +foo20: foo20\r +foo21: foo21\r +foo22: foo22\r +/; +} else { + $headers = qr/Bah: bah\r Test-Header: 1\r Foo1: foo1\r Foo2: foo2\r @@ -905,7 +979,10 @@ Foo19: foo19\r Foo20: foo20\r Foo21: foo21\r Foo22: foo22\r -/ +/; +} + +$headers; @@ -936,11 +1013,21 @@ GET /t --- more_headers My-Foo: bar Bar: baz ---- response_body -Bar: baz +--- response_body eval +my $body; +if ($ENV{TEST_NGINX_USE_HTTP3}) { + $body = "bar: baz +host: localhost +my-foo: bar +"; +} else { + $body = "Bar: baz Connection: close Host: localhost My-Foo: bar +"; +} +$body; @@ -1010,29 +1097,23 @@ for my $i ('a' .. 'r') { } $s --- response_body eval -"GET /back HTTP/1.0\r +my $s = "GET /back HTTP/1.0\r Host: foo\r -Connection: close\r -User-Agent: curl\r -A: a\r -B: b\r -C: c\r -D: d\r -E: e\r -F: f\r -G: g\r -H: h\r -I: i\r -J: j\r -K: k\r -L: l\r -M: m\r -N: n\r -O: o\r -P: p\r -Q: q\r -\r -" +Connection: close\r\n"; + +if (defined ($ENV{TEST_NGINX_USE_HTTP3})) { + $s .= "user-agent: curl\r\n"; + for my $i ('a' .. 'q') { + $s .= $i . ": " . "$i\r\n" + } +} else { + $s .= "User-Agent: curl\r\n"; + for my $i ('a' .. 'q') { + $s .= uc($i) . ": " . "$i\r\n" + } +} + +$s . "\r\n"; @@ -1063,7 +1144,55 @@ for my $i ('a' .. 'r') { } $s --- response_body eval -"GET /back HTTP/1.0\r +my $body; + +if (defined $ENV{TEST_NGINX_USE_HTTP3}) { + $body = "GET /back HTTP/1.0\r +Host: foo\r +Connection: close\r +user-agent: curl\r +a: a\r +b: b\r +c: c\r +d: d\r +e: e\r +f: f\r +g: g\r +h: h\r +i: i\r +j: j\r +k: k\r +l: l\r +m: m\r +n: n\r +o: o\r +p: p\r +q: q\r +foo-1: 1\r +foo-2: 2\r +foo-3: 3\r +foo-4: 4\r +foo-5: 5\r +foo-6: 6\r +foo-7: 7\r +foo-8: 8\r +foo-9: 9\r +foo-10: 10\r +foo-11: 11\r +foo-12: 12\r +foo-13: 13\r +foo-14: 14\r +foo-15: 15\r +foo-16: 16\r +foo-17: 17\r +foo-18: 18\r +foo-19: 19\r +foo-20: 20\r +foo-21: 21\r +\r +"; +} else { + $body = "GET /back HTTP/1.0\r Host: foo\r Connection: close\r User-Agent: curl\r @@ -1106,7 +1235,10 @@ foo-19: 19\r foo-20: 20\r foo-21: 21\r \r -" +"; +} + +$body; @@ -1135,7 +1267,34 @@ for my $i ('a' .. 'r') { } $s --- response_body eval -"GET /back HTTP/1.0\r +my $body; + +if (defined $ENV{TEST_NGINX_USE_HTTP3}) { + $body = "GET /back HTTP/1.0\r +Host: foo\r +Connection: close\r +user-agent: curl\r +bah: bah\r +a: a\r +b: b\r +c: c\r +d: d\r +e: e\r +f: f\r +g: g\r +h: h\r +i: i\r +j: j\r +k: k\r +l: l\r +m: m\r +n: n\r +o: o\r +p: p\r +\r +" +} else { +$body = "GET /back HTTP/1.0\r Host: foo\r Connection: close\r User-Agent: curl\r @@ -1158,6 +1317,9 @@ O: o\r P: p\r \r " +} + +$body; @@ -1189,7 +1351,55 @@ for my $i ('a' .. 'r') { } $s --- response_body eval -"GET /back HTTP/1.0\r +my $body; + +if (defined $ENV{TEST_NGINX_USE_HTTP3}) { + $body = "GET /back HTTP/1.0\r +Host: foo\r +Connection: close\r +user-agent: curl\r +bah: bah\r +a: a\r +b: b\r +c: c\r +d: d\r +e: e\r +f: f\r +g: g\r +h: h\r +i: i\r +j: j\r +k: k\r +l: l\r +m: m\r +n: n\r +o: o\r +p: p\r +foo-1: 1\r +foo-2: 2\r +foo-3: 3\r +foo-4: 4\r +foo-5: 5\r +foo-6: 6\r +foo-7: 7\r +foo-8: 8\r +foo-9: 9\r +foo-10: 10\r +foo-11: 11\r +foo-12: 12\r +foo-13: 13\r +foo-14: 14\r +foo-15: 15\r +foo-16: 16\r +foo-17: 17\r +foo-18: 18\r +foo-19: 19\r +foo-20: 20\r +foo-21: 21\r +\r +"; +} else { + $body = "GET /back HTTP/1.0\r Host: foo\r Connection: close\r User-Agent: curl\r @@ -1233,6 +1443,9 @@ foo-20: 20\r foo-21: 21\r \r " +} + +$body; @@ -1264,11 +1477,23 @@ GET /t --- more_headers My-Foo: bar Bar: baz ---- response_body -Bar: baz +--- response_body eval +my $body; + +if (defined $ENV{TEST_NGINX_USE_HTTP3}) { + $body="bar: baz +host: localhost +my-foo: bar +"; +} else { + $body="Bar: baz Connection: close Host: localhost My-Foo: bar +"; +} + +$body; --- no_error_log [error] @@ -1903,6 +2128,7 @@ found 3 headers. lua exceeding request header limit 4 > 3 --- no_error_log [error] +--- skip_eval: 4:$ENV{TEST_NGINX_USE_HTTP3} @@ -1939,6 +2165,7 @@ found 3 headers. --- no_error_log lua exceeding request header limit [error] +--- skip_eval: 4: $ENV{TEST_NGINX_USE_HTTP3} @@ -1977,6 +2204,7 @@ found 3 headers. lua exceeding request header limit 4 > 3 --- no_error_log [error] +--- skip_eval: 4: $ENV{TEST_NGINX_USE_HTTP3} @@ -2013,6 +2241,7 @@ found 3 headers. --- no_error_log lua exceeding request header limit [error] +--- skip_eval: 4: $ENV{TEST_NGINX_USE_HTTP3} diff --git a/t/033-ctx.t b/t/033-ctx.t index 8fc50aa7a0..1f879191b3 100644 --- a/t/033-ctx.t +++ b/t/033-ctx.t @@ -278,6 +278,8 @@ GET /t [error] --- error_log ngx.ctx = 32 +--- curl_error +curl: (52) Empty reply from server diff --git a/t/041-header-filter.t b/t/041-header-filter.t index be390b3259..a6ee25c8b2 100644 --- a/t/041-header-filter.t +++ b/t/041-header-filter.t @@ -124,6 +124,8 @@ Hi GET /read --- error_code --- response_body +--- curl_error +curl: (52) Empty reply from server @@ -465,6 +467,8 @@ GET /lua failed to run header_filter_by_lua*: header_filter_by_lua(nginx.conf:47):2: Something bad --- no_error_log [alert] +--- curl_error +curl: (56) Failure when receiving data from the peer @@ -487,6 +491,8 @@ GET /lua failed to run header_filter_by_lua*: unknown reason --- no_error_log [alert] +--- curl_error +curl: (56) Failure when receiving data from the peer @@ -501,6 +507,8 @@ GET /lua --- ignore_response --- error_log API disabled in the context of header_filter_by_lua* +--- curl_error +curl: (52) Empty reply from server @@ -515,6 +523,8 @@ GET /lua --- ignore_response --- error_log API disabled in the context of header_filter_by_lua* +--- curl_error +curl: (52) Empty reply from server @@ -529,6 +539,8 @@ GET /lua --- ignore_response --- error_log API disabled in the context of header_filter_by_lua* +--- curl_error +curl: (52) Empty reply from server @@ -543,6 +555,8 @@ GET /lua --- ignore_response --- error_log API disabled in the context of header_filter_by_lua* +--- curl_error +curl: (52) Empty reply from server @@ -557,6 +571,8 @@ GET /lua --- ignore_response --- error_log API disabled in the context of header_filter_by_lua* +--- curl_error +curl: (52) Empty reply from server @@ -575,6 +591,8 @@ GET /lua --- ignore_response --- error_log API disabled in the context of header_filter_by_lua* +--- curl_error +curl: (52) Empty reply from server @@ -593,6 +611,8 @@ GET /lua --- ignore_response --- error_log API disabled in the context of header_filter_by_lua* +--- curl_error +curl: (52) Empty reply from server @@ -607,6 +627,8 @@ GET /lua --- ignore_response --- error_log API disabled in the context of header_filter_by_lua* +--- curl_error +curl: (52) Empty reply from server @@ -621,6 +643,8 @@ GET /lua --- ignore_response --- error_log API disabled in the context of header_filter_by_lua* +--- curl_error +curl: (52) Empty reply from server @@ -635,6 +659,8 @@ GET /lua --- ignore_response --- error_log API disabled in the context of header_filter_by_lua* +--- curl_error +curl: (52) Empty reply from server @@ -667,6 +693,8 @@ GET /lua --- ignore_response --- error_log API disabled in the context of header_filter_by_lua* +--- curl_error +curl: (52) Empty reply from server @@ -679,8 +707,18 @@ API disabled in the context of header_filter_by_lua* --- request GET /lua --- ignore_response ---- error_log -API disabled in the context of header_filter_by_lua* +--- error_log eval +my $err_log; + +if (defined $ENV{TEST_NGINX_USE_HTTP3}) { + $err_log = "http v3 not supported yet"; +} else { + $err_log = "API disabled in the context of header_filter_by_lua*"; +} + +$err_log; +--- curl_error +curl: (52) Empty reply from server @@ -695,6 +733,8 @@ GET /lua --- ignore_response --- error_log API disabled in the context of header_filter_by_lua* +--- curl_error +curl: (52) Empty reply from server @@ -709,6 +749,8 @@ GET /lua --- ignore_response --- error_log API disabled in the context of header_filter_by_lua* +--- curl_error +curl: (52) Empty reply from server @@ -756,6 +798,8 @@ stack traceback: in function 'error' in function 'bar' in function 'foo' +--- curl_error +curl: (52) Empty reply from server @@ -774,6 +818,8 @@ GET /lua?a=1&b=2 --- ignore_response --- error_log eval qr/failed to load external Lua file ".*?test2\.lua": cannot open .*? No such file or directory/ +--- curl_error +curl: (52) Empty reply from server diff --git a/t/043-shdict.t b/t/043-shdict.t index b0528e5cc7..4fcdcb33b6 100644 --- a/t/043-shdict.t +++ b/t/043-shdict.t @@ -1184,6 +1184,7 @@ nil nil === TEST 45: flush_expires +--- quic_max_idle_timeout: 1.6 --- http_config lua_shared_dict dogs 1m; --- config @@ -1210,6 +1211,7 @@ GET /t === TEST 46: flush_expires with number +--- quic_max_idle_timeout: 1.6 --- http_config lua_shared_dict dogs 1m; --- config @@ -1337,6 +1339,7 @@ GET /t === TEST 51: list all keys in a shdict with expires +--- quic_max_idle_timeout: 1.6 --- http_config lua_shared_dict dogs 1m; --- config @@ -1426,6 +1429,7 @@ GET /t === TEST 55: list all keys in a shdict with all keys expired +--- quic_max_idle_timeout: 1.6 --- http_config lua_shared_dict dogs 1m; --- config diff --git a/t/044-req-body.t b/t/044-req-body.t index d8a62c7dbe..0c378c44aa 100644 --- a/t/044-req-body.t +++ b/t/044-req-body.t @@ -351,9 +351,18 @@ hello, world --- user_files >>> a.txt Will you change this world? ---- raw_response_headers_like -X-Old: \S+/client_body_temp/\d+\r -.*?X-New: \S+/html/a\.txt\r +--- raw_response_headers_like eval +my $headers; + +if (defined $ENV{TEST_NGINX_USE_HTTP3}) { + $headers = qr#x-old: \S+/client_body_temp/\d+\r +.*?x-new: \S+/html/a\.txt\r#; +} else { + $headers = qr#X-Old: \S+/client_body_temp/\d+\r +.*?X-New: \S+/html/a\.txt\r#; +} + +$headers; --- response_body Will you change this world? --- no_error_log @@ -390,9 +399,18 @@ hello, world! --- user_files >>> a.txt Will you change this world? ---- raw_response_headers_like -X-Old: \S+/client_body_temp/\d+\r -.*?X-New: \S+/html/a\.txt\r +--- raw_response_headers_like eval +my $headers; + +if (defined $ENV{TEST_NGINX_USE_HTTP3}) { + $headers = qr#x-old: \S+/client_body_temp/\d+\r +.*?x-new: \S+/html/a\.txt\r#; +} else { + $headers = qr#X-Old: \S+/client_body_temp/\d+\r +.*?X-New: \S+/html/a\.txt\r#; +} + +$headers; --- response_body Will you change this world? --- no_error_log @@ -1243,6 +1261,7 @@ body: hello, my dear friend! [alert] --- no_error_log a client request body is buffered to a temporary file +--- skip_eval: 3:$ENV{TEST_NGINX_USE_HTTP3} @@ -1384,6 +1403,7 @@ failed to get req socket: request body already exists [alert] --- no_error_log a client request body is buffered to a temporary file +--- skip_eval: 3:$ENV{TEST_NGINX_USE_HTTP3} @@ -1480,8 +1500,16 @@ probe syscall.fcntl { --- stap_out_unlike fcntl\(O_DIRECT\) ---- raw_response_headers_like -.*?X-New: \S+/html/a\.txt\r +--- raw_response_headers_like eval +my $headers; + +if (defined $ENV{TEST_NGINX_USE_HTTP3}) { + $headers = qr#.*?x-new: \S+/html/a\.txt\r#; +} else { + $headers = qr#.*?X-New: \S+/html/a\.txt\r#; +} + +$headers; --- response_body Will you change this world? --- no_error_log diff --git a/t/045-ngx-var.t b/t/045-ngx-var.t index 81fcef6458..f0f9f415c6 100644 --- a/t/045-ngx-var.t +++ b/t/045-ngx-var.t @@ -170,10 +170,22 @@ invalid referer: 1 } --- request GET /t ---- raw_response_headers_like -Proxy-Host: 127.0.0.1\:\d+\r +--- raw_response_headers_like eval +my $headers; + +if (defined $ENV{TEST_NGINX_USE_HTTP3}) { + $headers = +qr/proxy-host: 127.0.0.1\:\d+\r +proxy-port: \d+\r +proxy-add-x-forwarded-for: 127.0.0.1\r/; +} else { + $headers = +qr/Proxy-Host: 127.0.0.1\:\d+\r Proxy-Port: \d+\r -Proxy-Add-X-Forwarded-For: 127.0.0.1\r +Proxy-Add-X-Forwarded-For: 127.0.0.1\r/; +} + +$headers; --- response_body hello --- no_error_log diff --git a/t/056-flush.t b/t/056-flush.t index bdd33d4f9a..aa409ad51c 100644 --- a/t/056-flush.t +++ b/t/056-flush.t @@ -491,6 +491,7 @@ GET /test === TEST 17: limit_rate +--- quic_max_idle_timeout: 2 --- config location /test { limit_rate 150; diff --git a/t/057-flush-timeout.t b/t/057-flush-timeout.t index 1f8cfaadf9..4ef104f707 100644 --- a/t/057-flush-timeout.t +++ b/t/057-flush-timeout.t @@ -19,9 +19,13 @@ BEGIN { $ENV{TEST_NGINX_EVENT_TYPE} = 'poll'; $ENV{MOCKEAGAIN_WRITE_TIMEOUT_PATTERN} = 'hello, world'; $ENV{TEST_NGINX_POSTPONE_OUTPUT} = 1; + + if ($ENV{TEST_NGINX_USE_HTTP3}) { + $SkipReason = "HTTP3 does not support mockeagain"; + } } -use Test::Nginx::Socket::Lua; +use Test::Nginx::Socket::Lua $SkipReason ? (skip_all => $SkipReason) : (); use t::StapThread; our $GCScript = $t::StapThread::GCScript; diff --git a/t/058-tcp-socket.t b/t/058-tcp-socket.t index 6ffb32f584..14995bf9fe 100644 --- a/t/058-tcp-socket.t +++ b/t/058-tcp-socket.t @@ -1619,6 +1619,8 @@ GET /t --- ignore_response --- error_log bad argument #1 to 'send' (bad data type nil found) +--- curl_error +curl: (52) Empty reply from server @@ -1678,6 +1680,8 @@ GET /t --- ignore_response --- error_log bad argument #1 to 'send' (bad data type boolean found) +--- curl_error +curl: (52) Empty reply from server @@ -1737,6 +1741,8 @@ GET /t --- ignore_response --- error_log bad argument #1 to 'send' (bad data type userdata found) +--- curl_error +curl: (52) Empty reply from server diff --git a/t/062-count.t b/t/062-count.t index ad464ba2de..07605f95b9 100644 --- a/t/062-count.t +++ b/t/062-count.t @@ -262,6 +262,7 @@ hello world n = 6 --- no_error_log [error] +--- skip_eval: 3: $ENV{TEST_NGINX_USE_HTTP3} @@ -515,6 +516,7 @@ GET /test n = 7 --- no_error_log [error] +--- skip_eval: 3:$ENV{TEST_NGINX_USE_HTTP3} @@ -554,6 +556,7 @@ narr = 2 nrec = 3 --- no_error_log [error] +--- skip_eval: 3:$ENV{TEST_NGINX_USE_HTTP3} @@ -589,3 +592,4 @@ narr = 2 nrec = 3 --- no_error_log [error] +--- skip_eval: 3: $ENV{TEST_NGINX_USE_HTTP3} diff --git a/t/065-tcp-socket-timeout.t b/t/065-tcp-socket-timeout.t index 092094a3c9..e06dfb1fc8 100644 --- a/t/065-tcp-socket-timeout.t +++ b/t/065-tcp-socket-timeout.t @@ -873,6 +873,7 @@ quitting request now --- no_error_log lua tcp socket write timed out [alert] +--- skip_eval: 4: $ENV{TEST_NGINX_USE_HTTP3} diff --git a/t/066-socket-receiveuntil.t b/t/066-socket-receiveuntil.t index 7fac6bfd0f..2d38fb5c37 100644 --- a/t/066-socket-receiveuntil.t +++ b/t/066-socket-receiveuntil.t @@ -1327,6 +1327,7 @@ this exposed a memory leak in receiveuntil ok --- no_error_log [error] +<<<<<<< HEAD @@ -1993,3 +1994,4 @@ close: 1 nil } --- no_error_log [error] +--- skip_eval: 3:$ENV{TEST_NGINX_USE_HTTP3} diff --git a/t/067-req-socket.t b/t/067-req-socket.t index c5b2631e5e..fbaa0b3f41 100644 --- a/t/067-req-socket.t +++ b/t/067-req-socket.t @@ -1,6 +1,14 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use Test::Nginx::Socket::Lua; +our $SkipReason; + +BEGIN { + if ($ENV{TEST_NGINX_USE_HTTP3}) { + $SkipReason = "http3 does not support ngx.req.socket"; + } +} + +use Test::Nginx::Socket::Lua $SkipReason ? (skip_all => $SkipReason) : (); repeat_each(2); diff --git a/t/068-socket-keepalive.t b/t/068-socket-keepalive.t index cf8bc25acb..fe8dab152f 100644 --- a/t/068-socket-keepalive.t +++ b/t/068-socket-keepalive.t @@ -168,6 +168,7 @@ received: OK === TEST 3: upstream sockets close prematurely +--- quic_max_idle_timeout: 1.2 --- http_config eval "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config @@ -243,6 +244,7 @@ done === TEST 4: http keepalive +--- quic_max_idle_timeout: 1.2 --- http_config eval "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config @@ -318,6 +320,7 @@ done === TEST 5: lua_socket_keepalive_timeout +--- quic_max_idle_timeout: 1.2 --- config server_tokens off; location /t { @@ -395,6 +398,7 @@ qr/lua tcp socket connection pool size: 30\b/] === TEST 6: lua_socket_pool_size +--- quic_max_idle_timeout: 1.2 --- config server_tokens off; location /t { @@ -473,6 +477,7 @@ qr/lua tcp socket connection pool size: 1\b/] === TEST 7: "lua_socket_keepalive_timeout 0" means unlimited +--- quic_max_idle_timeout: 1.2 --- config server_tokens off; location /t { @@ -548,6 +553,7 @@ qr/lua tcp socket connection pool size: 30\b/] === TEST 8: setkeepalive(timeout) overrides lua_socket_keepalive_timeout +--- quic_max_idle_timeout: 1.2 --- config server_tokens off; location /t { @@ -625,6 +631,7 @@ qr/lua tcp socket connection pool size: 30\b/] === TEST 9: sock:setkeepalive(timeout, size) overrides lua_socket_pool_size +--- quic_max_idle_timeout: 1.2 --- config server_tokens off; location /t { @@ -731,6 +738,7 @@ bad argument #3 to '?' (bad "pool_size" option value: 0) === TEST 11: sock:keepalive_timeout(0) means unlimited +--- quic_max_idle_timeout: 1.2 --- config server_tokens off; location /t { @@ -1508,6 +1516,7 @@ done === TEST 25: setkeepalive() with explicit nil args +--- quic_max_idle_timeout: 1.2 --- config server_tokens off; location /t { @@ -1919,6 +1928,7 @@ too many waiting connect operations === TEST 32: conn queuing: once 'pool_size' is reached and pool has 'backlog' +--- quic_max_idle_timeout: 1.2 --- config location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -2536,6 +2546,8 @@ GET /t --- abort --- no_error_log [error] +--- curl_error eval +qr/curl: \(28\) Operation timed out after \d+ milliseconds with 0 bytes received/ @@ -2643,6 +2655,7 @@ lua tcp socket connect timed out, when connecting to === TEST 46: conn queuing: resume connect operation if resumed connect failed (could not be resolved) +--- quic_max_idle_timeout: 1.2 --- config resolver 127.0.0.2:12345 ipv6=off; resolver_timeout 1s; diff --git a/t/075-logby.t b/t/075-logby.t index 8eece698ec..de662d0fb4 100644 --- a/t/075-logby.t +++ b/t/075-logby.t @@ -457,8 +457,16 @@ API disabled in the context of log_by_lua* GET /lua --- response_body ok ---- error_log -API disabled in the context of log_by_lua* +--- error_log eval +my $err_log; + +if (defined $ENV{TEST_NGINX_USE_HTTP3}) { + $err_log = "http v3 not supported yet"; +} else { + $err_log = "API disabled in the context of log_by_lua*"; +} + +$err_log; diff --git a/t/077-sleep.t b/t/077-sleep.t index 96f04bd98e..4867b9ca7f 100644 --- a/t/077-sleep.t +++ b/t/077-sleep.t @@ -105,6 +105,7 @@ bad argument #1 to 'sleep' === TEST 5: sleep 0.33 - multi-times in content +--- quic_max_idle_timeout: 1.1 --- config location /test { content_by_lua ' @@ -129,6 +130,7 @@ lua sleep timer expired: "/test?" === TEST 6: sleep 0.5 - interleaved by ngx.say() - ended by ngx.sleep +--- quic_max_idle_timeout: 2.2 --- config location /test { content_by_lua ' @@ -156,6 +158,7 @@ lua sleep timer expired: "/test?" === TEST 7: sleep 0.5 - interleaved by ngx.say() - not ended by ngx.sleep +--- quic_max_idle_timeout: 0.9 --- config location /test { content_by_lua ' diff --git a/t/082-body-filter-2.t b/t/082-body-filter-2.t index 99ed447f56..d19f46f660 100644 --- a/t/082-body-filter-2.t +++ b/t/082-body-filter-2.t @@ -3,13 +3,11 @@ our $SkipReason; BEGIN { - if ($ENV{TEST_NGINX_EVENT_TYPE} && $ENV{TEST_NGINX_EVENT_TYPE} ne 'poll') { - $SkipReason = "unavailable for the event type '$ENV{TEST_NGINX_EVENT_TYPE}'"; - - } else { - $ENV{TEST_NGINX_POSTPONE_OUTPUT} = 1; - $ENV{TEST_NGINX_EVENT_TYPE} = 'poll'; - $ENV{MOCKEAGAIN}='w' + $ENV{TEST_NGINX_POSTPONE_OUTPUT} = 1; + $ENV{TEST_NGINX_EVENT_TYPE} = 'poll'; + $ENV{MOCKEAGAIN}='w'; + if ($ENV{TEST_NGINX_USE_HTTP3}) { + $SkipReason = "http3 has bug about the hup reload"; } } diff --git a/t/082-body-filter.t b/t/082-body-filter.t index a69c78fa70..54e7414cb8 100644 --- a/t/082-body-filter.t +++ b/t/082-body-filter.t @@ -482,6 +482,8 @@ stack traceback: in function 'error' in function 'bar' in function 'foo' +--- curl_error +curl: (52) Empty reply from server @@ -524,6 +526,8 @@ GET /lua?a=1&b=2 --- ignore_response --- error_log eval qr/failed to load external Lua file ".*?test2\.lua": cannot open .*? No such file or directory/ +--- curl_error +curl: (52) Empty reply from server @@ -838,6 +842,7 @@ GET /lua --- ignore_response --- error_log API disabled in the context of body_filter_by_lua* +<<<<<<< HEAD @@ -890,3 +895,5 @@ failed to load inlined Lua code: body_filter_by_lua(nginx.conf:49):2: unexpected --- no_error_log no_such_error1 no_such_error2 +--- curl_error +curl: (52) Empty reply from server diff --git a/t/083-bad-sock-self.t b/t/083-bad-sock-self.t index 7a76752d9f..206de8b990 100644 --- a/t/083-bad-sock-self.t +++ b/t/083-bad-sock-self.t @@ -33,6 +33,7 @@ __DATA__ --- error_code: 500 --- error_log bad argument #1 to 'receive' (table expected, got string) +--- skip_eval: 3:$ENV{TEST_NGINX_USE_HTTP3} @@ -51,6 +52,7 @@ bad argument #1 to 'receive' (table expected, got string) --- error_code: 500 --- error_log bad argument #1 to 'receiveuntil' (table expected, got number) +--- skip_eval: 3:$ENV{TEST_NGINX_USE_HTTP3} diff --git a/t/084-inclusive-receiveuntil.t b/t/084-inclusive-receiveuntil.t index eb5aa1ecdf..95d898501c 100644 --- a/t/084-inclusive-receiveuntil.t +++ b/t/084-inclusive-receiveuntil.t @@ -511,6 +511,8 @@ bad "inclusive" option value type: string --- no_error_log [alert] [warn] +--- curl_error +curl: (52) Empty reply from server @@ -578,6 +580,8 @@ bad "inclusive" option value type: string --- no_error_log [alert] [warn] +--- curl_error +curl: (52) Empty reply from server diff --git a/t/087-udp-socket.t b/t/087-udp-socket.t index 6c26b93876..ffe6b13e92 100644 --- a/t/087-udp-socket.t +++ b/t/087-udp-socket.t @@ -143,12 +143,15 @@ GET /t === TEST 3: access a TCP interface +test-nginx use the same port for tcp(http) and udp(http3) +so need to change to a port that is not listen by any app. +default port range: +net.ipv4.ip_local_port_range = 32768 60999 +choose a port greater than 61000 should be less race. --- config server_tokens off; location /t { - #set $port 5000; - set $port $TEST_NGINX_SERVER_PORT; - #set $port 1234; + set $port 65432; content_by_lua ' local socket = ngx.socket diff --git a/t/088-req-method.t b/t/088-req-method.t index 198b3b3492..de3421662c 100644 --- a/t/088-req-method.t +++ b/t/088-req-method.t @@ -209,6 +209,7 @@ main: GET === TEST 10: set HEAD to GET +XXX: does http3 do not support set HEAD to GET?? --- config location /t { rewrite_by_lua ' @@ -223,10 +224,12 @@ main: GET method: GET --- no_error_log [error] +--- skip_eval: 3:$ENV{TEST_NGINX_USE_HTTP3} === TEST 11: set GET to WebDAV methods +XXX: does http3 do not support change HEAD method? --- config location /t { content_by_lua ' @@ -262,3 +265,4 @@ method: PATCH method: TRACE --- no_error_log [error] +--- skip_eval: 3:$ENV{TEST_NGINX_USE_HTTP3} diff --git a/t/091-coroutine.t b/t/091-coroutine.t index fafc5a45cc..e8761045b8 100644 --- a/t/091-coroutine.t +++ b/t/091-coroutine.t @@ -159,6 +159,8 @@ cc3: 2 === TEST 3: basic coroutine and cosocket +access the public network is unstable, need a bigger timeout +--- quic_max_idle_timeout: 4 --- config resolver $TEST_NGINX_RESOLVER ipv6=off; location /lua { @@ -760,6 +762,8 @@ GET /lua --- ignore_response --- error_log API disabled in the context of header_filter_by_lua* +--- curl_error +curl: (52) Empty reply from server @@ -1695,6 +1699,8 @@ GET /t "stack traceback:", "in function 'co'" ] +--- curl_error +curl: (52) Empty reply from server diff --git a/t/093-uthread-spawn.t b/t/093-uthread-spawn.t index ab6db2ff26..d905c100c5 100644 --- a/t/093-uthread-spawn.t +++ b/t/093-uthread-spawn.t @@ -1064,6 +1064,8 @@ body: hello world)$ === TEST 23: simple user thread with ngx.req.socket() +ngx.req.socket() does not support in http3 +--- skip_eval: 4:$ENV{TEST_NGINX_USE_HTTP3} --- config location /lua { content_by_lua ' diff --git a/t/094-uthread-exit.t b/t/094-uthread-exit.t index 58d8d0b7db..39b1f22b55 100644 --- a/t/094-uthread-exit.t +++ b/t/094-uthread-exit.t @@ -966,6 +966,7 @@ hello in thread after --- no_error_log [error] +--- skip_eval: 4:$ENV{TEST_NGINX_USE_HTTP3} @@ -1051,6 +1052,7 @@ hello in thread after --- no_error_log [error] +--- skip_eval: 4:$ENV{TEST_NGINX_USE_HTTP3} @@ -1399,6 +1401,8 @@ attempt to abort with pending subrequests --- no_error_log [alert] [warn] +--- curl_error +curl: (52) Empty reply from server @@ -1482,6 +1486,8 @@ free request [alert] [error] [warn] +--- curl_error +curl: (52) Empty reply from server @@ -1565,6 +1571,8 @@ free request [alert] [error] [warn] +--- curl_error +curl: (52) Empty reply from server @@ -1648,3 +1656,5 @@ free request [alert] [error] [warn] +--- curl_error +curl: (52) Empty reply from server diff --git a/t/095-uthread-exec.t b/t/095-uthread-exec.t index 7bf37c0e8d..6e18c844ea 100644 --- a/t/095-uthread-exec.t +++ b/t/095-uthread-exec.t @@ -423,3 +423,5 @@ attempt to abort with pending subrequests --- no_error_log [alert] [warn] +--- curl_error +curl: (52) Empty reply from server diff --git a/t/096-uthread-redirect.t b/t/096-uthread-redirect.t index 95bff01f3a..2da84bd7aa 100644 --- a/t/096-uthread-redirect.t +++ b/t/096-uthread-redirect.t @@ -277,3 +277,5 @@ attempt to abort with pending subrequests --- no_error_log [alert] [warn] +--- curl_error +curl: (52) Empty reply from server diff --git a/t/100-client-abort.t b/t/100-client-abort.t index f5713874e7..fed01176c7 100644 --- a/t/100-client-abort.t +++ b/t/100-client-abort.t @@ -1,6 +1,12 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use Test::Nginx::Socket::Lua; +BEGIN { +if ($ENV{TEST_NGINX_USE_HTTP3}) { + $SkipReason = "client abort detect does not support in http3" + } +} + +use Test::Nginx::Socket::Lua $SkipReason ? (skip_all => $SkipReason) : (); use t::StapThread; our $GCScript = <<_EOC_; diff --git a/t/101-on-abort.t b/t/101-on-abort.t index ee1e41e3a8..f10027a47a 100644 --- a/t/101-on-abort.t +++ b/t/101-on-abort.t @@ -1,6 +1,12 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use Test::Nginx::Socket::Lua; +BEGIN { +if ($ENV{TEST_NGINX_USE_HTTP3}) { + $SkipReason = "client abort detect does not support in http3" + } +} + +use Test::Nginx::Socket::Lua $SkipReason ? (skip_all => $SkipReason) : (); use t::StapThread; our $GCScript = <<_EOC_; diff --git a/t/103-req-http-ver.t b/t/103-req-http-ver.t index e6de2388c5..ebc65c9d38 100644 --- a/t/103-req-http-ver.t +++ b/t/103-req-http-ver.t @@ -26,8 +26,15 @@ __DATA__ } --- request GET /t ---- response_body -1.1 +--- response_body eval +my $body; +if (defined $ENV{TEST_NGINX_USE_HTTP3}) { + $body="3\n"; +} else { + $body="1.1\n"; +} + +$body; --- no_error_log [error] diff --git a/t/104-req-raw-header.t b/t/104-req-raw-header.t index aa66630485..459d190ac7 100644 --- a/t/104-req-raw-header.t +++ b/t/104-req-raw-header.t @@ -1,5 +1,14 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use Test::Nginx::Socket::Lua; + +our $SkipReason; + +BEGIN { + if ($ENV{TEST_NGINX_USE_HTTP3}) { + $SkipReason = "http3 does not support ngx.req.raw_header()"; + } +} + +use Test::Nginx::Socket::Lua $SkipReason ? (skip_all => $SkipReason) : (); #worker_connections(1014); #master_on(); diff --git a/t/105-pressure.t b/t/105-pressure.t index 9d1ba1ff1a..2fc130d09b 100644 --- a/t/105-pressure.t +++ b/t/105-pressure.t @@ -2,7 +2,7 @@ use Test::Nginx::Socket::Lua; -#worker_connections(1014); +worker_connections(1014); #master_on(); #log_level('debug'); @@ -28,6 +28,8 @@ run_tests(); __DATA__ === TEST 1: memory issue in the "args" string option for ngx.location.capture +the default worker_connections is 64, HTTP3 will keep the connection when curl +request finished. So need to change the worker_connection. --- config location /test1 { content_by_lua ' diff --git a/t/106-timer.t b/t/106-timer.t index acd6e4c800..d455ea2add 100644 --- a/t/106-timer.t +++ b/t/106-timer.t @@ -1332,6 +1332,7 @@ API disabled === TEST 19: exit in user thread (entry thread is still pending on ngx.sleep) +--- quic_max_idle_timeout: 1.3 --- config location /t { content_by_lua ' diff --git a/t/109-timer-hup.t b/t/109-timer-hup.t index bff1b33466..551dd486c7 100644 --- a/t/109-timer-hup.t +++ b/t/109-timer-hup.t @@ -6,6 +6,10 @@ BEGIN { if ($ENV{TEST_NGINX_CHECK_LEAK}) { $SkipReason = "unavailable for the hup tests"; + } elsif (defined $ENV{TEST_NGINX_USE_HTTP3}) { + #os.execute("kill -HUP " .. pid) + $SkipReason = "send HUP relaod signal by self make two workers with same id"; + } else { $ENV{TEST_NGINX_USE_HUP} = 1; undef $ENV{TEST_NGINX_USE_STAP}; diff --git a/t/116-raw-req-socket.t b/t/116-raw-req-socket.t index 4dfb92664e..6704a92084 100644 --- a/t/116-raw-req-socket.t +++ b/t/116-raw-req-socket.t @@ -1,6 +1,14 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use Test::Nginx::Socket::Lua; +our $SkipReason; + +BEGIN { + if ($ENV{TEST_NGINX_USE_HTTP3}) { + $SkipReason = "http3 does not support ngx.req.socket(true)"; + } +} + +use Test::Nginx::Socket::Lua $SkipReason ? (skip_all => $SkipReason) : (); repeat_each(2); diff --git a/t/129-ssl-socket.t b/t/129-ssl-socket.t index 85d3a80985..f89a538fd0 100644 --- a/t/129-ssl-socket.t +++ b/t/129-ssl-socket.t @@ -40,6 +40,8 @@ run_tests(); __DATA__ === TEST 1: www.google.com +access the public network is unstable, need a bigger timeout value. +--- quic_max_idle_timeout: 3 --- config server_tokens off; resolver $TEST_NGINX_RESOLVER ipv6=off; @@ -293,6 +295,8 @@ SSL reused session === TEST 4: ssl session reuse +access the public network is unstable, need a bigger timeout value. +--- quic_max_idle_timeout: 3 --- config server_tokens off; resolver $TEST_NGINX_RESOLVER ipv6=off; @@ -1564,6 +1568,7 @@ attempt to call method 'sslhandshake' (a nil value) --- no_error_log [alert] --- timeout: 3 +--- skip_eval: 5:$ENV{TEST_NGINX_USE_HTTP3} @@ -2563,6 +2568,8 @@ qr/\[error\] .* ngx.socket sslhandshake: expecting 1 ~ 5 arguments \(including t --- no_error_log [alert] --- timeout: 10 +--- curl_error +curl: (52) Empty reply from server diff --git a/t/131-duplex-req-socket.t b/t/131-duplex-req-socket.t index 5d698b9344..f88649b8d8 100644 --- a/t/131-duplex-req-socket.t +++ b/t/131-duplex-req-socket.t @@ -1,5 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: +our $SkipReason; + BEGIN { if (!defined $ENV{LD_PRELOAD}) { $ENV{LD_PRELOAD} = ''; @@ -18,9 +20,13 @@ BEGIN { $ENV{TEST_NGINX_EVENT_TYPE} = 'poll'; $ENV{MOCKEAGAIN_WRITE_TIMEOUT_PATTERN} = 'slow'; + + if ($ENV{TEST_NGINX_USE_HTTP3}) { + $SkipReason = "http3 does not support ngx.req.socket()"; + } } -use Test::Nginx::Socket::Lua; +use Test::Nginx::Socket::Lua $SkipReason ? (skip_all => $SkipReason) : (); log_level('debug'); diff --git a/t/151-initby-hup.t b/t/151-initby-hup.t index f2788670db..a37db9fe43 100644 --- a/t/151-initby-hup.t +++ b/t/151-initby-hup.t @@ -12,7 +12,7 @@ BEGIN { } } -use Test::Nginx::Socket::Lua 'no_plan'; +use Test::Nginx::Socket::Lua $SkipReason ? (skip_all => $SkipReason) : (); #worker_connections(1014); #master_on(); @@ -21,7 +21,7 @@ use Test::Nginx::Socket::Lua 'no_plan'; repeat_each(1); -#plan tests => repeat_each() * (blocks() * 3 + 3); +plan tests => repeat_each() * (blocks() * 3); #no_diff(); #no_long_string(); diff --git a/t/152-timer-every.t b/t/152-timer-every.t index 7b42d2d724..374e80e04b 100644 --- a/t/152-timer-every.t +++ b/t/152-timer-every.t @@ -224,6 +224,7 @@ registered timer === TEST 6: memory leak check +--- quic_max_idle_timeout: 8 --- config location /t { content_by_lua_block { diff --git a/t/153-semaphore-hup.t b/t/153-semaphore-hup.t index 5c271a48e7..496db6862e 100644 --- a/t/153-semaphore-hup.t +++ b/t/153-semaphore-hup.t @@ -104,6 +104,7 @@ run_tests(); __DATA__ === TEST 1: timer + reload +--- quic_max_idle_timeout: 1.1 --- config location /test { content_by_lua_block { @@ -129,6 +130,7 @@ created semaphore object === TEST 2: timer + reload (lua code cache off) +--- quic_max_idle_timeout: 1.1 --- http_config lua_code_cache off; --- config diff --git a/t/157-socket-keepalive-hup.t b/t/157-socket-keepalive-hup.t index d9436b3b73..4ebf637a33 100644 --- a/t/157-socket-keepalive-hup.t +++ b/t/157-socket-keepalive-hup.t @@ -6,6 +6,10 @@ BEGIN { if ($ENV{TEST_NGINX_CHECK_LEAK}) { $SkipReason = "unavailable for the hup tests"; + } elsif (defined $ENV{TEST_NGINX_USE_HTTP3}) { + #os.execute("kill -HUP " .. pid) + $SkipReason = "send HUP relaod signal by self make two workers with same id"; + } else { $ENV{TEST_NGINX_USE_HUP} = 1; undef $ENV{TEST_NGINX_USE_STAP}; diff --git a/t/162-static-module-location.t b/t/162-static-module-location.t index fde93c71ba..9f09dbe631 100644 --- a/t/162-static-module-location.t +++ b/t/162-static-module-location.t @@ -40,9 +40,11 @@ Location: %00%0A%0Dset-cookie:1234567/ Hello, world --- request GET /t/中文 +--- more_headers +host: localhost --- error_code: 301 --- response_headers_like -Location: http:\/\/localhost:\d+\/t\/%E4%B8%AD%E6%96%87\/ +Location: https?:\/\/localhost:\d+\/t\/%E4%B8%AD%E6%96%87\/ --- response_body_like .*301 Moved Permanently.* @@ -56,9 +58,11 @@ Location: http:\/\/localhost:\d+\/t\/%E4%B8%AD%E6%96%87\/ Hello, world --- request GET /t/中文?q=name +--- more_headers +host: localhost --- error_code: 301 --- response_headers_like -Location: http:\/\/localhost:\d+\/t\/%E4%B8%AD%E6%96%87\/\?q=name +Location: https?:\/\/localhost:\d+\/t\/%E4%B8%AD%E6%96%87\/\?q=name --- response_body_like .*301 Moved Permanently.* @@ -72,9 +76,11 @@ Location: http:\/\/localhost:\d+\/t\/%E4%B8%AD%E6%96%87\/\?q=name Hello, world --- request GET /t/%E4%B8%AD%E6%96%87 +--- more_headers +host: localhost --- error_code: 301 --- response_headers_like -Location: http:\/\/localhost:\d+\/t\/%E4%B8%AD%E6%96%87\/ +Location: https?:\/\/localhost:\d+\/t\/%E4%B8%AD%E6%96%87\/ --- response_body_like .*301 Moved Permanently.* @@ -88,8 +94,10 @@ Location: http:\/\/localhost:\d+\/t\/%E4%B8%AD%E6%96%87\/ Hello, world --- request GET /t/%E4%B8%AD%E6%96%87?q=name +--- more_headers +host: localhost --- error_code: 301 --- response_headers_like -Location: http://localhost:\d+\/t\/%E4%B8%AD%E6%96%87\/\?q=name +Location: https?://localhost:\d+\/t\/%E4%B8%AD%E6%96%87\/\?q=name --- response_body_like .*301 Moved Permanently.* diff --git a/t/163-signal.t b/t/163-signal.t index 5a6b880b09..2b85e12482 100644 --- a/t/163-signal.t +++ b/t/163-signal.t @@ -38,6 +38,8 @@ GET /t qr/\[notice\] \d+#\d+: exit$/ --- no_error_log eval qr/\[notice\] \d+#\d+: reconfiguring/ +--- curl_error eval +qr/curl: \(28\) Operation timed out after 3\d+ milliseconds with 0 bytes received/ diff --git a/t/166-ssl-client-hello.t b/t/166-ssl-client-hello.t index 850a0d6550..445434289a 100644 --- a/t/166-ssl-client-hello.t +++ b/t/166-ssl-client-hello.t @@ -456,7 +456,7 @@ received memc reply: OK === TEST 5: ngx.exit(0) - no yield --- http_config server { - listen 127.0.0.2:8080 ssl; + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_client_hello_by_lua_block { ngx.exit(0) @@ -484,7 +484,7 @@ received memc reply: OK sock:settimeout(2000) - local ok, err = sock:connect("127.0.0.2", 8080) + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return @@ -523,7 +523,7 @@ should never reached here === TEST 6: ngx.exit(ngx.ERROR) - no yield --- http_config server { - listen 127.0.0.2:8080 ssl; + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_client_hello_by_lua_block { ngx.exit(ngx.ERROR) @@ -551,7 +551,7 @@ should never reached here sock:settimeout(2000) - local ok, err = sock:connect("127.0.0.2", 8080) + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return @@ -593,7 +593,7 @@ should never reached here === TEST 7: ngx.exit(0) - yield --- http_config server { - listen 127.0.0.2:8080 ssl; + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_client_hello_by_lua_block { ngx.sleep(0.001) @@ -623,7 +623,7 @@ should never reached here sock:settimeout(2000) - local ok, err = sock:connect("127.0.0.2", 8080) + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return @@ -662,7 +662,7 @@ should never reached here === TEST 8: ngx.exit(ngx.ERROR) - yield --- http_config server { - listen 127.0.0.2:8080 ssl; + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_client_hello_by_lua_block { ngx.sleep(0.001) @@ -692,7 +692,7 @@ should never reached here sock:settimeout(2000) - local ok, err = sock:connect("127.0.0.2", 8080) + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return @@ -805,7 +805,7 @@ should never reached here === TEST 10: lua exception - yield --- http_config server { - listen 127.0.0.2:8080 ssl; + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_client_hello_by_lua_block { ngx.sleep(0.001) @@ -834,7 +834,7 @@ should never reached here sock:settimeout(2000) - local ok, err = sock:connect("127.0.0.2", 8080) + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return @@ -1741,6 +1741,7 @@ close: 1 nil ssl client hello by lua is running! [error] [alert] +--- skip_eval: 5:$ENV{TEST_NGINX_USE_HTTP3} @@ -2130,7 +2131,7 @@ ssl client hello by lua is running! lua_package_path "../lua-resty-core/lib/?.lua;;"; server { - listen 127.0.0.1:12345 ssl; + listen 127.0.0.1:12346 ssl; server_name test.com; ssl_client_hello_by_lua_block { @@ -2162,7 +2163,7 @@ ssl client hello by lua is running! sock:settimeout(2000) - local ok, err = sock:connect("127.0.0.1", 12345) + local ok, err = sock:connect("127.0.0.1", 12346) if not ok then ngx.say("failed to connect: ", err) return @@ -2565,3 +2566,72 @@ ssl handshake: cdata uthread: hello from f() uthread: killed uthread: failed to kill: already waited or killed + + + +=== TEST 30: ngx.exit(ngx.OK) - no yield +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + ssl_client_hello_by_lua_block { + ngx.exit(ngx.OK) + ngx.log(ngx.ERR, "should never reached here...") + } + ssl_certificate ../../cert/test.crt; + ssl_certificate_key ../../cert/test.key; + + server_tokens off; + location /foo { + default_type 'text/plain'; + content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} + more_clear_headers Date; + } + } +--- config + server_tokens off; + lua_ssl_trusted_certificate ../../cert/test.crt; + lua_ssl_verify_depth 3; + + location /t { + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(2000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(false, nil, true, false) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + end -- do + } + } + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: boolean + +--- error_log eval +[ +'lua_client_hello_by_lua: handler return value: 0, client hello cb exit code: 1', +qr/\[debug\] .*? SSL_do_handshake: 1/, +'lua exit with code 0', +] +--- no_error_log +should never reached here +[alert] +[emerg] diff --git a/t/166-worker-thread.t b/t/166-worker-thread.t index c8ae62965f..afe7f3c410 100644 --- a/t/166-worker-thread.t +++ b/t/166-worker-thread.t @@ -282,6 +282,7 @@ false : module 'hello' not found.* === TEST 10: the number of Lua VM exceeds the pool size +--- quic_max_idle_timeout: 5 --- main_config thread_pool testpool threads=100; --- http_config eval: $::HttpConfig @@ -359,6 +360,7 @@ GET /t === TEST 11: kill uthread before worker thread callback +--- quic_max_idle_timeout: 10 --- main_config thread_pool testpool threads=100; --- http_config eval: $::HttpConfig diff --git a/t/cert/http3/http3.crt b/t/cert/http3/http3.crt new file mode 100644 index 0000000000..8683f41adf --- /dev/null +++ b/t/cert/http3/http3.crt @@ -0,0 +1,29 @@ +-----BEGIN CERTIFICATE----- +MIIFCTCCAvGgAwIBAgIUHLeNm7JwH368JWXBYJ1Dv+xcL6kwDQYJKoZIhvcNAQEL +BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTIxMTEwNTA2NTQxNVoXDTQxMDEw +NDA2NTQxNVowFDESMBAGA1UEAwwJbG9jYWxob3N0MIICIjANBgkqhkiG9w0BAQEF +AAOCAg8AMIICCgKCAgEAx5/M18tKWKfacgldf9gBguTdLA3JWiblRWM/38fSZGKL +Mcb1vLErY/qQyLYxoLKBht0FUZAEZ08y/iheYFZT7H082b8bNvwY+v6bScOQOvcX +hkTWNlSQORDH4qIFxVXq0soXga+0ukSZ2RQRcCUWeKUaZwhGCYNIj04/FB9Lef95 +Ku7LkNauTBmRGIwXgQWhfnoPM21o9D9i54R9L2RHU7fGeTGhiS0nCe1nPPB7KBgO +s9rBHMXV9qHxCNMWWiVNsMX049S7aD9yvRrV7NAHssVQdaRR234IPJxb7BYSUPi8 +5U+8l43Ornd+cY/R/sXDQluFidlnZvHT+akdy0ObWDK0lMUweDWvFVLY3ZvMvsGR +rQE8RR5/fy83y7w//0734EBk4ttEzlilmjA8UvnumOpK0UYaW8LkikvxB+48e89s +NOEKZf3Mfw/fDRz0tO+cr4cIgUPQ4ru6KNVnGH/ZiD97AVMPXJO9nPOUIRVH9aXM +wC74CSt5idWOwpTKy+sLg7anM235NvZ9bTiS+V5CTzBlqL/wKzEI0Injds3kBc1a +Y8Lk/cIdNhuwlN01fYluA8XyB3DWoeQYbySEoHC5ksvaFLBM3yPomWrmyM5lJrj5 +QbWa46b0bONJQ2qmrQa5KREVvDthHQvKELsabHX1qbCShSxoG45aclqpmKy2AjcC +AwEAAaNTMFEwHQYDVR0OBBYEFA2T9Sgv31hCl3INL5MB++NrMu0iMB8GA1UdIwQY +MBaAFA2T9Sgv31hCl3INL5MB++NrMu0iMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI +hvcNAQELBQADggIBAJdxtUq4T/sh5Ww7pMOB4+JF5zsxEBpZiFMzT2hYZ+6a2mYh +UTy7ff1lNfNl0BfslaOD404Qt0SSgI2TByLs838/sKpVk+QePcw6kl6IFIPERUBO +uxq/+QXqsDHOXb6m4qpEBmrknUa65dThdUw5r4sHo0XD2l/y2/zEZtd4e3ZGAWts +spdjPBk4UHPtG3p29eY/8ehw+zDXuWG4nlJYjn+6PRnLhvpgt2/E/Wr9PeYcv3IC +UgavxXVtk9fnclg8BuKlnZYki7txn8+F9Rh03CVVZ9R16Q/aVALI2iTs8T4gCt7Z +eexfLGfBkLBkLvpL7wpzxNsvOC2b5bJZCDUTprLVmdpmMQu75qLg1mOfubMo983H +8G91V4XOokRoCRub/SLKA16/gpEwnE2aDsVMUVSxwpRu2Rjw4GpzbCNAHUzmblrh +zYMSAsEuTcsZEAdZQrzmhGc1Yg5Q88V4o+qyywzkgd86O65QUozhnkCs+eS9ikMV +cPLXoW5SDIsrrcoTR6bH5MdDjS7ILKUUC5+x0qo6EhK94Fx49TkRBNIYk3o0fG7j +o/0YvozXjqTRnodYegL4LKoGZyfL4qbuh3t8ZGQ/Z0ECmvjcmJzPyObIiMe2InT3 +GRY+ypPTyeiumjHFFVO0zx+DAv+HFPtq1XaygWvxKY1DTP6FNN0BzQdzAgKm +-----END CERTIFICATE----- diff --git a/t/cert/http3/http3.key b/t/cert/http3/http3.key new file mode 100644 index 0000000000..5825540f58 --- /dev/null +++ b/t/cert/http3/http3.key @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +MIIJQgIBADANBgkqhkiG9w0BAQEFAASCCSwwggkoAgEAAoICAQDHn8zXy0pYp9py +CV1/2AGC5N0sDclaJuVFYz/fx9JkYosxxvW8sStj+pDItjGgsoGG3QVRkARnTzL+ +KF5gVlPsfTzZvxs2/Bj6/ptJw5A69xeGRNY2VJA5EMfiogXFVerSyheBr7S6RJnZ +FBFwJRZ4pRpnCEYJg0iPTj8UH0t5/3kq7suQ1q5MGZEYjBeBBaF+eg8zbWj0P2Ln +hH0vZEdTt8Z5MaGJLScJ7Wc88HsoGA6z2sEcxdX2ofEI0xZaJU2wxfTj1LtoP3K9 +GtXs0AeyxVB1pFHbfgg8nFvsFhJQ+LzlT7yXjc6ud35xj9H+xcNCW4WJ2Wdm8dP5 +qR3LQ5tYMrSUxTB4Na8VUtjdm8y+wZGtATxFHn9/LzfLvD//TvfgQGTi20TOWKWa +MDxS+e6Y6krRRhpbwuSKS/EH7jx7z2w04Qpl/cx/D98NHPS075yvhwiBQ9Diu7oo +1WcYf9mIP3sBUw9ck72c85QhFUf1pczALvgJK3mJ1Y7ClMrL6wuDtqczbfk29n1t +OJL5XkJPMGWov/ArMQjQieN2zeQFzVpjwuT9wh02G7CU3TV9iW4DxfIHcNah5Bhv +JISgcLmSy9oUsEzfI+iZaubIzmUmuPlBtZrjpvRs40lDaqatBrkpERW8O2EdC8oQ +uxpsdfWpsJKFLGgbjlpyWqmYrLYCNwIDAQABAoICAENb1qESRbn4matVIamb15a1 +ZzQQStsSuNZbERiPspyQ6+sV+aF8HuoTiHtRjxlsYmyBc+P7tqCthsVgFchoGNV5 +xOispaA+HKfE9d1EEgzzh4qU+7tFeYzn7qq4hT37KcuKybfG9DLOJyOqs9+lhBmd +jHUrw4Y+OGOywXImxS8bV2V3QlVTO2kOT3l6/AtbPQ0SXsK5rmqMYPFCMYOmULMd +FembJ6jEBaJB604Sz1vOElf5/qOY1gPszQpvP+GXKMn3YhTmmX4puqu4vGq2H4Lh +Na8cjUqFEn5xPEtDf1a3N/Ygm8B/5zfTtmTXZMKVNLfVbg//vfZsr1xVBmqqG2Zk +PUxZ9pyRn25zAYIgIC6DBgmM32S5Zl0axeoWIHdgOTAOwqLLF/ZFozdVSN+skJhl +q1ndTw+MmVHi19HDUt8YfIICn8g+Dw9NRdX+VjXrRMBweCL41JzHzP6YKo73VJty +WIVt/LwH2sxdGH0QeP6+Dajel3/ouXAcS31ZpeWZ0QUfa5I0DOn50mvZSuaC0m7Z +baHBGqawq9EKdjbU5WN6popOCWCx23BZDorKmPGBQ4x54LxfUeet0HAYjsvzUZ0q +a/AC6pMMHUjG4i5dPhOAhjxkpwfhLjIBTC8VrelGfap50Mlst5InCjClUsSKg43w +tsRg0HQflxYsPXUGtBqxAoIBAQD29Q6gPNsd7JMzmVzK7fy5YaKq7aI/vOU/tp7U +LQqhBfsy70U3UNsclsQQ/1RG2cgpFVctlpE8ITpFqSlUDRtlvrK9NaIPEYBV84Xn +bWPqFjGiRowuXiCR8axbPnsEquO2+VHNuVD/PsCocvbpqtpbfEGmcuyWiO4uFMyW +beOcRxEsn3U7ABZGDIhxYjpmkiVMu1pRjj+ddqtNMia398K86c3ETRg+zrHnpzio +kuhxv6TjtnXT1ibI0yKzdQ5sKpa3DYUN/wJgeFVHsSuCZjCzufcMdjCjG3kTTljT +FrMbweISSTJNs6KsbCqzmc6dmpwuU1ySX07F9sgdJ/7lBCXTAoIBAQDO7wy9Zr8C +Ridte1EaMP04OSfqc2Jha/U2te47R1VDyHKzpFHvHwWHqFng6J181M9iubUsh/63 +d12uyjZoToMgT7AJ7PMwbEKJbMxpIjqF7Dp1aM11TjRq0mQbZ3wkeuYdK7jYc92j +X4hF+tJpCYo/0lMA0UFYhMyUPbi33xqlJKLghVncBYmKHluf3k0g73eRg4MGlYHG +tZ5qVdgwFTztpBb4ySJMOYmjb/OoYPdfoLC8P4ZoHiax4MU30R8b/oGCmYzwOsMC +dNz9dZgeCFo3+lrzMUnIh3y+YcGo2JJ9ZW1LxGvEIU0aEQ7mSPV8k7m3QiH2MiPQ +P0t17w1hQP+NAoIBAHJch1pi9CGGZaB2e8cpsGf0s8yt4P3dLthzbFfbR9nLmEk9 +DnOQSPeTRdaNNuzce1mzHTzqRfVvebm6nX3j1/Uk+0atqI+Lzj9/V1oViThk8LUy +MEZkpnaPUP6sD3HY5TzddilrkPuyhqs7GeaZjSbigtBe1frcDFhgn2FmIApFysk8 +SqB46NelhCXllB/du9ItzKSJ2CHGS4ujFtUIsjCjoPsvrHOhajdZc950sZnDYstk +umnP+QP06lPqeDRVAJhidWRG3EXqU6uwevKW+iSwkJw/u0Q9O7NaC74s++J1xYgs +R1Q+RK3OJXQoXMsVRxAY4HyUEDmSj5cY52wMoKsCggEAQMXu9PJOY8XV3Z02G76t +5IVviyGm79u9G+0Cryd69watcLHEu9a4AmieCZqGgWaTq9F5doDzKDaC6o19TlUV +Em4fKlwzGzsn8KBPs7D1JKp2+f1eIpPiMHW+xB02bKzTjtn6uDY8cEEdBNqoNhy4 +W5XYSW82xyB6cQSI53U8f+jh2umi4Q4SqVsrTvVkqySKBtBlmQ//WVXMSniofRSI +x9IPJry+saFpBfGrEU+Y3yQLbkFsLvcRIai70ubwl/CoVVr/FMsv83rlGalPfkcb +Bl6lTW5mLBDM6ULsPY/c+sde2NKY8QGDgt9IDKlVvjL3dPeMbeXv8+V8F2RGieSw +mQKCAQEA1n4t4CLKZMWZ4oonBEp8u9rjK23ObCSxANsfoIw94v2zHTFqLraFg9aH +s+DIc6M/XWX+Ie55v1QuYt8LrMtc9/rtOJdISybAtnheSqjQ+IkTEvBab/8pqhYg +Jhv/RxmBnCLwiIzRGVpxv9/5bbKXq1JKgdQKO3RBG53lcFFMO1O5srhKqj2KgAHv +XCQxBmtj83e6gp6hvUOU4YC2aKyL9QqNVndGzPJikEguyvJPUFw6RoB0StVQnzLY +UOgIH+8VTjzL90nQ/JitVT8uGdw1Ge5xJfCXDe/PEYpDsY65DKPrIMWFeQs6T/Mb +nvNeBReQOuYYpcCc2GM96RMUz3iyoA== +-----END PRIVATE KEY----- From 7c8a9d53e74f5192b54cce577d685b81487c1a60 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Sat, 26 Aug 2023 08:58:57 +0800 Subject: [PATCH 117/254] test3: more http3 tests fixes. --- .travis.yml | 5 +++-- t/023-rewrite/socket-keepalive.t | 4 ++-- t/068-socket-keepalive.t | 2 +- t/163-exit-worker-hup.t | 3 +++ 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index f70f825574..f8558c1ea0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,7 +26,6 @@ addons: - libgd-dev - time - cmake - - curl - libunwind-dev - libpsl0 - wget @@ -85,6 +84,7 @@ install: - if [ "$USE_PCRE2" != "Y" ] && [ ! -f download-cache/pcre-$PCRE_VER.tar.gz ]; then wget -P download-cache https://downloads.sourceforge.net/project/pcre/pcre/${PCRE_VER}/pcre-${PCRE_VER}.tar.gz; fi - if [ "$USE_PCRE2" = "Y" ] && [ ! -f download-cache/pcre2-$PCRE2_VER.tar.gz ]; then wget -P download-cache https://downloads.sourceforge.net/project/pcre/pcre2/${PCRE2_VER}/pcre2-${PCRE2_VER}.tar.gz; fi - if [ ! -f download-cache/openssl-$OPENSSL_VER.tar.gz ]; then wget -P download-cache https://www.openssl.org/source/openssl-$OPENSSL_VER.tar.gz || wget -P download-cache https://www.openssl.org/source/old/${OPENSSL_VER//[a-z]/}/openssl-$OPENSSL_VER.tar.gz; fi + - wget https://github.com/zhuizhuhaomeng/curl-http3/releases/download/v1.0.0/curl-h3.tar.gz - git clone https://github.com/openresty/test-nginx.git - git clone https://github.com/openresty/openresty.git ../openresty - git clone https://github.com/openresty/no-pool-nginx.git ../no-pool-nginx @@ -115,7 +115,8 @@ before_script: - mysql -uroot -e "create database ngx_test; CREATE USER 'ngx_test'@'%' IDENTIFIED BY 'ngx_test'; grant all on ngx_test.* to 'ngx_test'@'%'; flush privileges;" script: - - export PATH=$PWD/work/nginx/sbin:$PWD/openresty-devel-utils:$PATH + - sudo tar -C / -xf curl-h3.tar.gz + - export PATH=$PWD/work/nginx/sbin:$PWD/openresty-devel-utils:/opt/curl-h3/bin:$PATH - ngx-releng > check.txt || true - lines=`wc -l check.txt | awk '{print $1}'`; if [ $lines -gt 5 ]; then cat check.txt; exit 1; fi - sudo iptables -I OUTPUT 1 -p udp --dport 10086 -j REJECT diff --git a/t/023-rewrite/socket-keepalive.t b/t/023-rewrite/socket-keepalive.t index 5316af6be5..5884c02b8e 100644 --- a/t/023-rewrite/socket-keepalive.t +++ b/t/023-rewrite/socket-keepalive.t @@ -176,7 +176,7 @@ received: OK === TEST 3: upstream sockets close prematurely ---- quic_max_idle_timeout: 1.1 +--- no_http3 --- http_config eval "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config @@ -254,7 +254,7 @@ done === TEST 4: http keepalive ---- quic_max_idle_timeout: 1.1 +--- no_http3 --- http_config eval "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config diff --git a/t/068-socket-keepalive.t b/t/068-socket-keepalive.t index fe8dab152f..5ca94e4b72 100644 --- a/t/068-socket-keepalive.t +++ b/t/068-socket-keepalive.t @@ -168,7 +168,7 @@ received: OK === TEST 3: upstream sockets close prematurely ---- quic_max_idle_timeout: 1.2 +--- no_http3 --- http_config eval "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config diff --git a/t/163-exit-worker-hup.t b/t/163-exit-worker-hup.t index a54d81db14..cd2e5ce649 100644 --- a/t/163-exit-worker-hup.t +++ b/t/163-exit-worker-hup.t @@ -6,6 +6,9 @@ BEGIN { if ($ENV{TEST_NGINX_CHECK_LEAK}) { $SkipReason = "unavailable for the hup tests"; + } elsif ($ENV{TEST_NGINX_USE_HTTP3}) { + $SkipReason = "http3 does not support hub reload"; + } else { $ENV{TEST_NGINX_USE_HUP} = 1; undef $ENV{TEST_NGINX_USE_STAP}; From c27df5c6ba842c3edc764cc1480b94d0203621a9 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Fri, 3 Dec 2021 23:05:59 +0800 Subject: [PATCH 118/254] tests: fixed test cases for http2 when running with TEST_NGINX_USE_HTTP2=1. (#62) --- .travis.yml | 9 +- t/014-bugs.t | 3 + t/015-status.t | 1 + t/016-resp-header.t | 14 +-- t/023-rewrite/client-abort.t | 2 + t/023-rewrite/on-abort.t | 2 + t/023-rewrite/redirect.t | 2 +- t/023-rewrite/tcp-socket-timeout.t | 1 + t/023-rewrite/tcp-socket.t | 22 +++++ t/024-access/client-abort.t | 2 + t/024-access/on-abort.t | 2 + t/024-access/redirect.t | 2 +- t/028-req-header.t | 42 ++++++--- t/033-ctx.t | 4 +- t/041-header-filter.t | 76 ++++++++-------- t/056-flush.t | 13 ++- t/057-flush-timeout.t | 1 + t/058-tcp-socket.t | 54 +++++++++++ t/065-tcp-socket-timeout.t | 1 + t/066-socket-receiveuntil.t | 17 ++++ t/067-req-socket.t | 2 + t/082-body-filter-2.t | 18 +++- t/084-inclusive-receiveuntil.t | 10 ++ t/088-req-method.t | 3 + t/091-coroutine.t | 8 +- t/100-client-abort.t | 6 +- t/101-on-abort.t | 6 +- t/103-req-http-ver.t | 2 + t/106-timer.t | 1 + t/108-timer-safe.t | 1 + t/132-lua-blocks.t | 1 + t/138-balancer-upstream-bind.t | 141 +++++++++++++++++++++++++++++ t/138-balancer.t | 1 + t/147-tcp-socket-timeouts.t | 1 + t/156-slow-network.t | 1 + t/163-signal.t | 2 +- t/166-worker-thread.t | 2 + 37 files changed, 394 insertions(+), 82 deletions(-) create mode 100644 t/138-balancer-upstream-bind.t diff --git a/.travis.yml b/.travis.yml index f8558c1ea0..48d92855c0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -63,11 +63,12 @@ env: - TEST_NGINX_SLEEP=0.006 - MALLOC_PERTURB_=9 jobs: - - NGINX_VERSION=1.21.4 OPENSSL_VER=1.1.0l OPENSSL_PATCH_VER=1.1.0d - - NGINX_VERSION=1.21.4 OPENSSL_VER=1.1.1s OPENSSL_PATCH_VER=1.1.1f - - NGINX_VERSION=1.25.1 OPENSSL_VER=1.1.0l OPENSSL_PATCH_VER=1.1.0d + #- NGINX_VERSION=1.21.4 OPENSSL_VER=1.1.0l OPENSSL_PATCH_VER=1.1.0d + #- NGINX_VERSION=1.21.4 OPENSSL_VER=1.1.1s OPENSSL_PATCH_VER=1.1.1f + #- NGINX_VERSION=1.25.1 OPENSSL_VER=1.1.0l OPENSSL_PATCH_VER=1.1.0d - NGINX_VERSION=1.25.1 OPENSSL_VER=1.1.1s OPENSSL_PATCH_VER=1.1.1f USE_PCRE2=Y - NGINX_VERSION=1.25.1 BORINGSSL=1 TEST_NGINX_USE_HTTP3=1 USE_PCRE2=Y + #- NGINX_VERSION=1.25.1 OPENSSL_VER=1.1.1s TEST_NGINX_USE_HTTP2=1 services: - memcached @@ -80,10 +81,10 @@ before_install: - /usr/bin/env perl $(command -v cpanm) --sudo --notest Test::Nginx IPC::Run > build.log 2>&1 || (cat build.log && exit 1) - pyenv global 2.7 install: - - if [ ! -f download-cache/drizzle7-$DRIZZLE_VER.tar.gz ]; then wget -P download-cache http://openresty.org/download/drizzle7-$DRIZZLE_VER.tar.gz; fi - if [ "$USE_PCRE2" != "Y" ] && [ ! -f download-cache/pcre-$PCRE_VER.tar.gz ]; then wget -P download-cache https://downloads.sourceforge.net/project/pcre/pcre/${PCRE_VER}/pcre-${PCRE_VER}.tar.gz; fi - if [ "$USE_PCRE2" = "Y" ] && [ ! -f download-cache/pcre2-$PCRE2_VER.tar.gz ]; then wget -P download-cache https://downloads.sourceforge.net/project/pcre/pcre2/${PCRE2_VER}/pcre2-${PCRE2_VER}.tar.gz; fi - if [ ! -f download-cache/openssl-$OPENSSL_VER.tar.gz ]; then wget -P download-cache https://www.openssl.org/source/openssl-$OPENSSL_VER.tar.gz || wget -P download-cache https://www.openssl.org/source/old/${OPENSSL_VER//[a-z]/}/openssl-$OPENSSL_VER.tar.gz; fi + - if [ -n "$OPENSSL_VER" ] && [ ! -f download-cache/openssl-$OPENSSL_VER.tar.gz ]; then wget -P download-cache https://www.openssl.org/source/openssl-$OPENSSL_VER.tar.gz || wget -P download-cache https://www.openssl.org/source/old/${OPENSSL_VER//[a-z]/}/openssl-$OPENSSL_VER.tar.gz; fi - wget https://github.com/zhuizhuhaomeng/curl-http3/releases/download/v1.0.0/curl-h3.tar.gz - git clone https://github.com/openresty/test-nginx.git - git clone https://github.com/openresty/openresty.git ../openresty diff --git a/t/014-bugs.t b/t/014-bugs.t index 1f140be51d..f4e596640e 100644 --- a/t/014-bugs.t +++ b/t/014-bugs.t @@ -731,6 +731,7 @@ Content-Type: application/json; charset=utf-8 === TEST 32: hang on upstream_next (from kindy) +--- no_http2 --- no_check_leak --- http_config upstream xx { @@ -807,6 +808,8 @@ so need to skip for http3 [alert] --- error_log eval qr/(?:send|recv)\(\) failed \(\d+: Connection refused\) while resolving/ +--- curl_error eval +qr/curl: \(28\) Operation timed out after \d+ milliseconds with 0 bytes received/ diff --git a/t/015-status.t b/t/015-status.t index 43faa204a7..aa816c08d6 100644 --- a/t/015-status.t +++ b/t/015-status.t @@ -234,6 +234,7 @@ GET /t --- no_error_log [error] --- skip_eval: 3:$ENV{TEST_NGINX_USE_HTTP3} +--- no_http2 diff --git a/t/016-resp-header.t b/t/016-resp-header.t index 60c63929ae..ac0c52eeef 100644 --- a/t/016-resp-header.t +++ b/t/016-resp-header.t @@ -65,7 +65,7 @@ GET /read Content-Length: 3 --- response_body chop Hel ---- skip_eval: 3:$ENV{TEST_NGINX_USE_HTTP3} +--- skip_eval: 3:defined($ENV{TEST_NGINX_USE_HTTP3}) || defined($ENV{TEST_NGINX_USE_HTTP2}) @@ -117,7 +117,7 @@ GET /read --- raw_response_headers_like eval my $headers; -if (defined $ENV{TEST_NGINX_USE_HTTP3}) { +if (defined($ENV{TEST_NGINX_USE_HTTP3}) || defined($ENV{TEST_NGINX_USE_HTTP2})) { $headers = qr/x-foo: a\r\n.*?x-foo: bc\r\n/ } else { $headers = qr/X-Foo: a\r\n.*?X-Foo: bc\r\n/ @@ -196,7 +196,7 @@ GET /read --- raw_response_headers_like eval my $headers; -if (defined $ENV{TEST_NGINX_USE_HTTP3}) { +if (defined($ENV{TEST_NGINX_USE_HTTP3}) || defined($ENV{TEST_NGINX_USE_HTTP2})) { $headers = "x-foo: a\r\n.*?x-foo: abc\r\n" } else { $headers = "X-Foo: a\r\n.*?X-Foo: abc\r\n" @@ -222,7 +222,7 @@ Hello --- raw_response_headers_like eval my $headers; -if (defined $ENV{TEST_NGINX_USE_HTTP3}) { +if (defined($ENV{TEST_NGINX_USE_HTTP3}) || defined($ENV{TEST_NGINX_USE_HTTP2})) { $headers = ".*foo: a\r foo: b.*"; } else { @@ -250,7 +250,7 @@ $headers; --- raw_response_headers_like eval my $headers; -if (defined $ENV{TEST_NGINX_USE_HTTP3}) { +if (defined($ENV{TEST_NGINX_USE_HTTP3}) || defined($ENV{TEST_NGINX_USE_HTTP2})) { $headers = ".*foo: a\r foo: b.*"; } else { @@ -1197,7 +1197,7 @@ Foo: /t/ --- raw_response_headers_like eval my $headers; -if (defined $ENV{TEST_NGINX_USE_HTTP3}) { +if (defined($ENV{TEST_NGINX_USE_HTTP3}) || defined($ENV{TEST_NGINX_USE_HTTP2})) { $headers = "cache-control: private" } else { $headers = "cache-Control: private" @@ -1552,7 +1552,7 @@ hi --- error_log my Transfer-Encoding: chunked my transfer-encoding: chunked ---- skip_eval: 6:$ENV{TEST_NGINX_USE_HTTP3} +--- skip_eval: 6:defined($ENV{TEST_NGINX_USE_HTTP3}) || defined($ENV{TEST_NGINX_USE_HTTP2}) diff --git a/t/023-rewrite/client-abort.t b/t/023-rewrite/client-abort.t index 963717b012..61ada3a1b0 100644 --- a/t/023-rewrite/client-abort.t +++ b/t/023-rewrite/client-abort.t @@ -21,6 +21,8 @@ repeat_each(2); if (defined $ENV{TEST_NGINX_USE_HTTP3}) { plan(skip_all => "HTTP3 does not support client abort"); +} elsif (defined $ENV{TEST_NGINX_USE_HTTP2}) { + plan(skip_all => "HTTP2 does not support client abort"); } else { plan tests => repeat_each() * (blocks() * 3 - 1); } diff --git a/t/023-rewrite/on-abort.t b/t/023-rewrite/on-abort.t index d0bae78ee8..0535732a0b 100644 --- a/t/023-rewrite/on-abort.t +++ b/t/023-rewrite/on-abort.t @@ -21,6 +21,8 @@ repeat_each(2); if (defined $ENV{TEST_NGINX_USE_HTTP3}) { plan(skip_all => "HTTP3 does not support on_abort"); +} elsif (defined $ENV{TEST_NGINX_USE_HTTP2}) { + plan(skip_all => "HTTP2 does not support on_abort"); } else { plan tests => repeat_each() * (blocks() * 4 + 15); } diff --git a/t/023-rewrite/redirect.t b/t/023-rewrite/redirect.t index e387ee8fb7..2b3dccb0c0 100644 --- a/t/023-rewrite/redirect.t +++ b/t/023-rewrite/redirect.t @@ -122,7 +122,7 @@ GET /read --- raw_response_headers_like eval my $headers; -if (defined $ENV{TEST_NGINX_USE_HTTP3}) { +if (defined($ENV{TEST_NGINX_USE_HTTP3}) || defined($ENV{TEST_NGINX_USE_HTTP2})) { $headers = "location: /foo\r\n" } else { $headers = "Location: /foo\r\n" diff --git a/t/023-rewrite/tcp-socket-timeout.t b/t/023-rewrite/tcp-socket-timeout.t index e713bb5755..9be8081321 100644 --- a/t/023-rewrite/tcp-socket-timeout.t +++ b/t/023-rewrite/tcp-socket-timeout.t @@ -16,6 +16,7 @@ BEGIN { $ENV{MOCKEAGAIN} = 'w'; } + delete($ENV{TEST_NGINX_USE_HTTP2}); $ENV{TEST_NGINX_EVENT_TYPE} = 'poll'; $ENV{MOCKEAGAIN_WRITE_TIMEOUT_PATTERN} = 'get helloworld'; } diff --git a/t/023-rewrite/tcp-socket.t b/t/023-rewrite/tcp-socket.t index b4bf7a6b78..9ca66c64bb 100644 --- a/t/023-rewrite/tcp-socket.t +++ b/t/023-rewrite/tcp-socket.t @@ -86,6 +86,7 @@ failed to receive a line: closed [] close: 1 nil --- no_error_log [error] +--- no_http2 @@ -155,6 +156,7 @@ failed to receive a line: closed [foo] closed --- no_error_log [error] +--- no_http2 @@ -197,6 +199,7 @@ connected: nil failed to send request: closed --- error_log attempt to send data on a closed socket: +--- no_http2 @@ -521,6 +524,7 @@ failed to receive a line: closed close: 1 nil --- no_error_log [error] +--- no_http2 @@ -591,6 +595,7 @@ close: 1 nil " --- no_error_log [error] +--- no_http2 @@ -672,6 +677,7 @@ close: 1 nil " --- no_error_log [error] +--- no_http2 @@ -749,6 +755,7 @@ close: 1 nil " --- no_error_log [error] +--- no_http2 @@ -827,6 +834,7 @@ close: 1 nil " --- no_error_log [error] +--- no_http2 @@ -898,6 +906,7 @@ failed to receive a line: closed [] close: 1 nil --- no_error_log [error] +--- no_http2 @@ -967,6 +976,7 @@ failed to receive a line: closed [] close: 1 nil --- no_error_log [error] +--- no_http2 @@ -1077,6 +1087,7 @@ close: 1 nil " --- no_error_log [error] +--- no_http2 @@ -1521,6 +1532,7 @@ GET /t 2: close: 1 nil --- no_error_log [error] +--- no_http2 @@ -1593,6 +1605,7 @@ failed to receive a line: closed [] close: 1 nil --- no_error_log [error] +--- no_http2 @@ -1656,6 +1669,7 @@ GET /t bad argument #1 to 'send' (bad data type nil found) --- curl_error curl: (52) Empty reply from server +--- no_http2 @@ -1719,6 +1733,7 @@ GET /t bad argument #1 to 'send' (bad data type boolean found) --- curl_error curl: (52) Empty reply from server +--- no_http2 @@ -1782,6 +1797,7 @@ GET /t bad argument #1 to 'send' (bad data type userdata found) --- curl_error curl: (52) Empty reply from server +--- no_http2 @@ -1851,6 +1867,7 @@ subrequest: 200, OK\r " --- no_error_log [error] +--- no_http2 @@ -1922,6 +1939,7 @@ close: 1 nil --- no_error_log [error] --- SKIP +--- no_http2 @@ -1982,6 +2000,7 @@ receive(0): [] close: 1 nil --- no_error_log [error] +--- no_http2 @@ -2042,6 +2061,7 @@ send(""): 0 close: 1 nil --- no_error_log [error] +--- no_http2 @@ -2098,6 +2118,7 @@ qr/runtime error: rewrite_by_lua\(nginx\.conf:\d+\):7: bad request/ --- no_error_log [alert] +--- no_http2 @@ -2157,6 +2178,7 @@ qr/runtime error: rewrite_by_lua\(nginx\.conf:\d+\):14: bad request/ --- no_error_log [alert] +--- no_http2 diff --git a/t/024-access/client-abort.t b/t/024-access/client-abort.t index 99f1b810fd..e4abb4ebd9 100644 --- a/t/024-access/client-abort.t +++ b/t/024-access/client-abort.t @@ -5,6 +5,8 @@ our $SkipReason; BEGIN { if ($ENV{TEST_NGINX_USE_HTTP3}) { $SkipReason = "http3 does not support ngx.req.socket and lua_check_client_abort"; + } elsif ($ENV{TEST_NGINX_USE_HTTP2}) { + $SkipReason = "http2 does not support ngx.req.socket and lua_check_client_abort"; } } diff --git a/t/024-access/on-abort.t b/t/024-access/on-abort.t index 4d58779742..70637ba862 100644 --- a/t/024-access/on-abort.t +++ b/t/024-access/on-abort.t @@ -21,6 +21,8 @@ repeat_each(2); if (defined $ENV{TEST_NGINX_USE_HTTP3}) { plan(skip_all => "HTTP3 does not support on_abort"); +} elsif (defined $ENV{TEST_NGINX_USE_HTTP2}) { + plan(skip_all => "HTTP2 does not support on_abort"); } else { plan tests => repeat_each() * (blocks() * 4 + 15); } diff --git a/t/024-access/redirect.t b/t/024-access/redirect.t index 84b64c5f0b..e8609af060 100644 --- a/t/024-access/redirect.t +++ b/t/024-access/redirect.t @@ -122,7 +122,7 @@ GET /read --- raw_response_headers_like eval my $headers; -if (defined $ENV{TEST_NGINX_USE_HTTP3}) { +if (defined($ENV{TEST_NGINX_USE_HTTP3}) || defined($ENV{TEST_NGINX_USE_HTTP2})) { $headers = "location: /foo\r\n" } else { $headers = "Location: /foo\r\n" diff --git a/t/028-req-header.t b/t/028-req-header.t index b9c5e97fe0..21da3fc1ad 100644 --- a/t/028-req-header.t +++ b/t/028-req-header.t @@ -59,7 +59,7 @@ lua exceeding request header limit for k, v in pairs(headers) do h[k] = v end - if (ngx.req.http_version() == 3) then + if (ngx.req.http_version() == 3 or ngx.req.http_version() == 2) then ngx.say("Foo: ", h["foo"] or "nil") ngx.say("Bar: ", h["bar"] or "nil") else @@ -133,6 +133,7 @@ Foo: "a" x 2048 --- timeout: 15 --- skip_eval: 2:$ENV{TEST_NGINX_USE_HTTP3} +--- no_http2 @@ -152,6 +153,7 @@ Foo: "a" x 2048 --- timeout: 15 --- skip_eval: 2:$ENV{TEST_NGINX_USE_HTTP3} +--- no_http2 @@ -493,6 +495,7 @@ for my $k (@k) { --- error_log lua exceeding request header limit 101 > 100 --- skip_eval: 3:$ENV{TEST_NGINX_USE_HTTP3} +--- no_http2 @@ -532,7 +535,7 @@ $s --- response_body eval my @k; -if (defined $ENV{TEST_NGINX_USE_HTTP3}) { +if (defined($ENV{TEST_NGINX_USE_HTTP3}) || defined($ENV{TEST_NGINX_USE_HTTP2})) { push @k, "host: localhost\n"; } my $i = 1; @@ -542,7 +545,7 @@ while ($i <= 98) { } my $found_headers = "found 99 headers\n"; -if (!defined $ENV{TEST_NGINX_USE_HTTP3}) { +if (!defined($ENV{TEST_NGINX_USE_HTTP3}) && !defined($ENV{TEST_NGINX_USE_HTTP2})) { push @k, "connection: close\n"; push @k, "host: localhost\n"; $found_headers = "found 100 headers\n"; @@ -615,6 +618,7 @@ for my $k (@k) { --- error_log lua exceeding request header limit 103 > 102 --- skip_eval: 3:$ENV{TEST_NGINX_USE_HTTP3} +--- no_http2 @@ -650,7 +654,7 @@ while ($i <= 100) { $s --- response_body eval my @k; -if (defined $ENV{TEST_NGINX_USE_HTTP3}) { +if (defined($ENV{TEST_NGINX_USE_HTTP3}) || defined($ENV{TEST_NGINX_USE_HTTP2})) { push @k, "host: localhost\n"; } my $i = 1; @@ -659,7 +663,7 @@ while ($i <= 100) { $i++; } -if (!defined($ENV{TEST_NGINX_USE_HTTP3})) { +if (!defined($ENV{TEST_NGINX_USE_HTTP3}) && !defined($ENV{TEST_NGINX_USE_HTTP2})) { push @k, "connection: close\n"; push @k, "host: localhost\n"; } @@ -710,7 +714,7 @@ while ($i <= 105) { $s --- response_body eval my @k; -if (defined $ENV{TEST_NGINX_USE_HTTP3}) { +if (defined($ENV{TEST_NGINX_USE_HTTP3}) || defined($ENV{TEST_NGINX_USE_HTTP2})) { push @k, "host: localhost\n"; } my $i = 1; @@ -718,7 +722,7 @@ while ($i <= 105) { push @k, "x-$i"; $i++; } -if (!defined($ENV{TEST_NGINX_USE_HTTP3})) { +if (!defined($ENV{TEST_NGINX_USE_HTTP3}) && !defined($ENV{TEST_NGINX_USE_HTTP2})) { push @k, "connection: close\n"; push @k, "host: localhost\n"; } @@ -1015,7 +1019,7 @@ My-Foo: bar Bar: baz --- response_body eval my $body; -if ($ENV{TEST_NGINX_USE_HTTP3}) { +if ($ENV{TEST_NGINX_USE_HTTP3} || $ENV{TEST_NGINX_USE_HTTP2}) { $body = "bar: baz host: localhost my-foo: bar @@ -1101,7 +1105,7 @@ my $s = "GET /back HTTP/1.0\r Host: foo\r Connection: close\r\n"; -if (defined ($ENV{TEST_NGINX_USE_HTTP3})) { +if (defined $ENV{TEST_NGINX_USE_HTTP3}) { $s .= "user-agent: curl\r\n"; for my $i ('a' .. 'q') { $s .= $i . ": " . "$i\r\n" @@ -1269,7 +1273,7 @@ $s --- response_body eval my $body; -if (defined $ENV{TEST_NGINX_USE_HTTP3}) { +if ($ENV{TEST_NGINX_USE_HTTP3}) { $body = "GET /back HTTP/1.0\r Host: foo\r Connection: close\r @@ -1480,7 +1484,7 @@ Bar: baz --- response_body eval my $body; -if (defined $ENV{TEST_NGINX_USE_HTTP3}) { +if (defined($ENV{TEST_NGINX_USE_HTTP3})|| defined($ENV{TEST_NGINX_USE_HTTP2})) { $body="bar: baz host: localhost my-foo: bar @@ -2129,6 +2133,7 @@ lua exceeding request header limit 4 > 3 --- no_error_log [error] --- skip_eval: 4:$ENV{TEST_NGINX_USE_HTTP3} +--- no_http2 @@ -2166,6 +2171,7 @@ found 3 headers. lua exceeding request header limit [error] --- skip_eval: 4: $ENV{TEST_NGINX_USE_HTTP3} +--- no_http2 @@ -2205,6 +2211,7 @@ lua exceeding request header limit 4 > 3 --- no_error_log [error] --- skip_eval: 4: $ENV{TEST_NGINX_USE_HTTP3} +--- no_http2 @@ -2235,8 +2242,17 @@ while ($i <= 1) { $i++; } $s ---- response_body -found 3 headers. +--- response_body eval +my $body; +if (!defined $ENV{TEST_NGINX_USE_HTTP2}) { + $body = "found 3 headers. +"; +} else { + $body = "found 2 headers. +"; +} + +$body; --- timeout: 4 --- no_error_log lua exceeding request header limit diff --git a/t/033-ctx.t b/t/033-ctx.t index 1f879191b3..6133cee2bb 100644 --- a/t/033-ctx.t +++ b/t/033-ctx.t @@ -278,8 +278,8 @@ GET /t [error] --- error_log ngx.ctx = 32 ---- curl_error -curl: (52) Empty reply from server +--- curl_error eval +qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly/ diff --git a/t/041-header-filter.t b/t/041-header-filter.t index a6ee25c8b2..d36d3e025c 100644 --- a/t/041-header-filter.t +++ b/t/041-header-filter.t @@ -124,8 +124,8 @@ Hi GET /read --- error_code --- response_body ---- curl_error -curl: (52) Empty reply from server +--- curl_error eval +qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly/ @@ -467,8 +467,8 @@ GET /lua failed to run header_filter_by_lua*: header_filter_by_lua(nginx.conf:47):2: Something bad --- no_error_log [alert] ---- curl_error -curl: (56) Failure when receiving data from the peer +--- curl_error eval +qr/curl: \(56\) Failure when receiving data from the peer|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly|curl: \(52\) Empty reply from server/ @@ -491,8 +491,8 @@ GET /lua failed to run header_filter_by_lua*: unknown reason --- no_error_log [alert] ---- curl_error -curl: (56) Failure when receiving data from the peer +--- curl_error eval +qr/curl: \(56\) Failure when receiving data from the peer|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly|curl: \(52\) Empty reply from server/ @@ -507,8 +507,8 @@ GET /lua --- ignore_response --- error_log API disabled in the context of header_filter_by_lua* ---- curl_error -curl: (52) Empty reply from server +--- curl_error eval +qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly/ @@ -523,8 +523,8 @@ GET /lua --- ignore_response --- error_log API disabled in the context of header_filter_by_lua* ---- curl_error -curl: (52) Empty reply from server +--- curl_error eval +qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly/ @@ -539,8 +539,8 @@ GET /lua --- ignore_response --- error_log API disabled in the context of header_filter_by_lua* ---- curl_error -curl: (52) Empty reply from server +--- curl_error eval +qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly/ @@ -555,8 +555,8 @@ GET /lua --- ignore_response --- error_log API disabled in the context of header_filter_by_lua* ---- curl_error -curl: (52) Empty reply from server +--- curl_error eval +qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly/ @@ -571,8 +571,8 @@ GET /lua --- ignore_response --- error_log API disabled in the context of header_filter_by_lua* ---- curl_error -curl: (52) Empty reply from server +--- curl_error eval +qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly/ @@ -591,8 +591,8 @@ GET /lua --- ignore_response --- error_log API disabled in the context of header_filter_by_lua* ---- curl_error -curl: (52) Empty reply from server +--- curl_error eval +qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly/ @@ -611,8 +611,8 @@ GET /lua --- ignore_response --- error_log API disabled in the context of header_filter_by_lua* ---- curl_error -curl: (52) Empty reply from server +--- curl_error eval +qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly/ @@ -627,8 +627,8 @@ GET /lua --- ignore_response --- error_log API disabled in the context of header_filter_by_lua* ---- curl_error -curl: (52) Empty reply from server +--- curl_error eval +qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly/ @@ -643,8 +643,8 @@ GET /lua --- ignore_response --- error_log API disabled in the context of header_filter_by_lua* ---- curl_error -curl: (52) Empty reply from server +--- curl_error eval +qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly/ @@ -659,8 +659,8 @@ GET /lua --- ignore_response --- error_log API disabled in the context of header_filter_by_lua* ---- curl_error -curl: (52) Empty reply from server +--- curl_error eval +qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly/ @@ -693,8 +693,8 @@ GET /lua --- ignore_response --- error_log API disabled in the context of header_filter_by_lua* ---- curl_error -curl: (52) Empty reply from server +--- curl_error eval +qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly/ @@ -717,8 +717,8 @@ if (defined $ENV{TEST_NGINX_USE_HTTP3}) { } $err_log; ---- curl_error -curl: (52) Empty reply from server +--- curl_error eval +qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly/ @@ -733,8 +733,8 @@ GET /lua --- ignore_response --- error_log API disabled in the context of header_filter_by_lua* ---- curl_error -curl: (52) Empty reply from server +--- curl_error eval +qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly/ @@ -749,8 +749,8 @@ GET /lua --- ignore_response --- error_log API disabled in the context of header_filter_by_lua* ---- curl_error -curl: (52) Empty reply from server +--- curl_error eval +qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly/ @@ -798,8 +798,8 @@ stack traceback: in function 'error' in function 'bar' in function 'foo' ---- curl_error -curl: (52) Empty reply from server +--- curl_error eval +qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly/ @@ -818,8 +818,8 @@ GET /lua?a=1&b=2 --- ignore_response --- error_log eval qr/failed to load external Lua file ".*?test2\.lua": cannot open .*? No such file or directory/ ---- curl_error -curl: (52) Empty reply from server +--- curl_error eval +qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly/ diff --git a/t/056-flush.t b/t/056-flush.t index aa409ad51c..4376b18930 100644 --- a/t/056-flush.t +++ b/t/056-flush.t @@ -513,10 +513,19 @@ GET /test --- response_body eval "a" x 200 --- error_log eval -[ +my @errlog; +if (defined $ENV{TEST_NGINX_USE_HTTP2}) { + @errlog = [ +qr/lua writes elapsed 0\.[7-9]\d+ sec/, +qr/lua flush requires waiting: buffered 0x[0-9a-f]+, delayed:1/, +]; +} else { + @errlog = [ qr/lua writes elapsed [12](?:\.\d+)? sec/, qr/lua flush requires waiting: buffered 0x[0-9a-f]+, delayed:1/, -] +]; +} +@errlog; --- no_error_log [error] diff --git a/t/057-flush-timeout.t b/t/057-flush-timeout.t index 4ef104f707..8f0b7790a0 100644 --- a/t/057-flush-timeout.t +++ b/t/057-flush-timeout.t @@ -19,6 +19,7 @@ BEGIN { $ENV{TEST_NGINX_EVENT_TYPE} = 'poll'; $ENV{MOCKEAGAIN_WRITE_TIMEOUT_PATTERN} = 'hello, world'; $ENV{TEST_NGINX_POSTPONE_OUTPUT} = 1; + delete($ENV{TEST_NGINX_USE_HTTP2}); if ($ENV{TEST_NGINX_USE_HTTP3}) { $SkipReason = "HTTP3 does not support mockeagain"; diff --git a/t/058-tcp-socket.t b/t/058-tcp-socket.t index 14995bf9fe..5602140fe1 100644 --- a/t/058-tcp-socket.t +++ b/t/058-tcp-socket.t @@ -21,6 +21,7 @@ run_tests(); __DATA__ === TEST 1: sanity +--- no_http2 --- config server_tokens off; location /t { @@ -90,6 +91,7 @@ close: 1 nil === TEST 2: no trailing newline +--- no_http2 --- config server_tokens off; location /t { @@ -257,6 +259,7 @@ second line received: (?:Date|Server): .*? === TEST 5: connection refused (tcp) +--- no_http2 --- config location /test { content_by_lua ' @@ -327,6 +330,7 @@ lua tcp socket connect timed out, when connecting to 127.0.0.2:12345 === TEST 7: not closed manually +--- no_http2 --- config server_tokens off; location /t { @@ -441,6 +445,7 @@ attempt to send data on a closed socket === TEST 10: explicit *l pattern for receive +--- no_http2 --- config server_tokens off; location /t { @@ -509,6 +514,7 @@ close: 1 nil === TEST 11: *a pattern for receive +--- no_http2 --- config server_tokens off; location /t { @@ -577,6 +583,7 @@ close: 1 nil === TEST 12: mixing *a and *l patterns for receive +--- no_http2 --- config server_tokens off; location /t { @@ -656,6 +663,7 @@ close: 1 nil === TEST 13: receive by chunks +--- no_http2 --- timeout: 5 --- config server_tokens off; @@ -731,6 +739,7 @@ close: 1 nil === TEST 14: receive by chunks (very small buffer) +--- no_http2 --- timeout: 5 --- config server_tokens off; @@ -807,6 +816,7 @@ close: 1 nil === TEST 15: line reading (very small buffer) +--- no_http2 --- config server_tokens off; lua_socket_buffer_size 1; @@ -876,6 +886,7 @@ close: 1 nil === TEST 16: ngx.socket.connect (working) +--- no_http2 --- config server_tokens off; location /t { @@ -982,6 +993,7 @@ qr/connect\(\) failed \(\d+: Connection refused\)/ === TEST 18: receive by chunks (stringified size) +--- no_http2 --- config server_tokens off; location /t { @@ -1056,6 +1068,7 @@ close: 1 nil === TEST 19: cannot survive across request boundary (send) +--- no_http2 --- http_config eval "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config @@ -1115,6 +1128,7 @@ received: OK|failed to send request: closed)\$" === TEST 20: cannot survive across request boundary (receive) +--- no_http2 --- http_config eval "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config @@ -1190,6 +1204,7 @@ received: OK|failed to receive a line: closed \[nil\])$/ === TEST 21: cannot survive across request boundary (close) +--- no_http2 --- http_config eval "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config @@ -1259,6 +1274,7 @@ received: OK|failed to close: closed)$/ === TEST 22: cannot survive across request boundary (connect) +--- no_http2 --- http_config eval "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config @@ -1335,6 +1351,7 @@ lua reuse socket upstream ctx === TEST 23: connect again immediately +--- no_http2 --- config server_tokens off; location /t { @@ -1403,6 +1420,7 @@ close: 1 nil === TEST 24: two sockets mix together +--- no_http2 --- config server_tokens off; location /t { @@ -1494,6 +1512,7 @@ GET /t === TEST 25: send tables of string fragments (with integers too) +--- no_http2 --- config server_tokens off; location /t { @@ -1564,6 +1583,7 @@ close: 1 nil === TEST 26: send tables of string fragments (bad type "nil") +--- no_http2 --- config server_tokens off; location /t { @@ -1625,6 +1645,7 @@ curl: (52) Empty reply from server === TEST 27: send tables of string fragments (bad type "boolean") +--- no_http2 --- config server_tokens off; location /t { @@ -1686,6 +1707,7 @@ curl: (52) Empty reply from server === TEST 28: send tables of string fragments (bad type ngx.null) +--- no_http2 --- config server_tokens off; location /t { @@ -1747,6 +1769,7 @@ curl: (52) Empty reply from server === TEST 29: cosocket before location capture (tcpsock:send did not clear u->waiting) +--- no_http2 --- config server_tokens off; location /t { @@ -1814,6 +1837,7 @@ subrequest: 200, OK\r === TEST 30: CR in a line +--- no_http2 --- config server_tokens off; location /t { @@ -1883,6 +1907,7 @@ close: nil closed === TEST 31: receive(0) +--- no_http2 --- config server_tokens off; location /t { @@ -1941,6 +1966,7 @@ close: 1 nil === TEST 32: send("") +--- no_http2 --- config server_tokens off; location /t { @@ -2182,6 +2208,7 @@ lua tcp socket read timed out === TEST 37: successful reread after a read time out happen (receive -> receive) +--- no_http2 --- config server_tokens off; resolver $TEST_NGINX_RESOLVER ipv6=off; @@ -2259,6 +2286,7 @@ lua tcp socket read timed out === TEST 38: successful reread after a read time out happen (receive -> receiveuntil) +--- no_http2 --- config server_tokens off; resolver $TEST_NGINX_RESOLVER ipv6=off; @@ -2339,6 +2367,7 @@ lua tcp socket read timed out === TEST 39: successful reread after a read time out happen (receiveuntil -> receiveuntil) +--- no_http2 --- config server_tokens off; resolver $TEST_NGINX_RESOLVER ipv6=off; @@ -2421,6 +2450,7 @@ lua tcp socket read timed out === TEST 40: successful reread after a read time out happen (receiveuntil -> receive) +--- no_http2 --- config server_tokens off; resolver $TEST_NGINX_RESOLVER ipv6=off; @@ -2501,6 +2531,7 @@ lua tcp socket read timed out === TEST 41: receive(0) +--- no_http2 --- config server_tokens off; location /t { @@ -2548,6 +2579,7 @@ close: 1 nil === TEST 42: empty options table +--- no_http2 --- config server_tokens off; location /t { @@ -2586,6 +2618,7 @@ close: 1 nil === TEST 43: u->coctx left over bug +--- no_http2 --- config server_tokens off; location = /t { @@ -2677,6 +2710,7 @@ lua clean up the timer for pending ngx.sleep === TEST 44: bad request tries to connect +--- no_http2 --- http_config eval "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config @@ -2731,6 +2765,7 @@ qr/runtime error: content_by_lua\(nginx\.conf:\d+\):7: bad request/ === TEST 45: bad request tries to receive +--- no_http2 --- http_config eval "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config @@ -2788,6 +2823,7 @@ qr/runtime error: content_by_lua\(nginx\.conf:\d+\):14: bad request/ === TEST 46: bad request tries to send +--- no_http2 --- http_config eval "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config @@ -2845,6 +2881,7 @@ qr/runtime error: content_by_lua\(nginx\.conf:\d+\):14: bad request/ === TEST 47: bad request tries to close +--- no_http2 --- http_config eval "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config @@ -2902,6 +2939,7 @@ qr/runtime error: content_by_lua\(nginx\.conf:\d+\):14: bad request/ === TEST 48: bad request tries to set keepalive +--- no_http2 --- http_config eval "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config @@ -2959,6 +2997,7 @@ qr/runtime error: content_by_lua\(nginx\.conf:\d+\):14: bad request/ === TEST 49: bad request tries to receiveuntil +--- no_http2 --- http_config eval "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config @@ -3090,6 +3129,7 @@ could not cancel === TEST 52: tcp_nodelay on +--- no_http2 --- config tcp_nodelay on; server_tokens off; @@ -3163,6 +3203,7 @@ lua socket tcp_nodelay === TEST 53: tcp_nodelay off +--- no_http2 --- config tcp_nodelay off; server_tokens off; @@ -3354,6 +3395,7 @@ lua tcp socket connect timeout: 100 === TEST 56: reuse cleanup +--- no_http2 --- config server_tokens off; location /t { @@ -3418,6 +3460,7 @@ lua http cleanup reuse === TEST 57: reuse cleanup in ngx.timer (fake_request) +--- no_http2 --- config server_tokens off; location /t { @@ -3501,6 +3544,7 @@ lua http cleanup reuse === TEST 58: free cleanup in ngx.timer (without sock:close) +--- no_http2 --- config server_tokens off; location /t { @@ -3582,6 +3626,7 @@ total_send_bytes: 114 === TEST 59: reuse cleanup in subrequest +--- no_http2 --- config server_tokens off; location /t { @@ -3650,6 +3695,7 @@ lua http cleanup reuse === TEST 60: setkeepalive on socket already shutdown +--- no_http2 --- config location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -3688,6 +3734,7 @@ failed to setkeepalive: closed === TEST 61: options_table is nil +--- no_http2 --- config location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -3794,6 +3841,7 @@ failed to connect: bad port number: 65536 === TEST 64: send boolean and nil +--- no_http2 --- config location /t { set $port $TEST_NGINX_SERVER_PORT; @@ -3856,6 +3904,7 @@ received: truefalsenil === TEST 65: receiveany method in cosocket +--- no_http2 --- config server_tokens off; location = /t { @@ -3989,6 +4038,7 @@ GET /t === TEST 67: receiveany with limited, max <= 0 +--- no_http2 --- config location = /t { set $port $TEST_NGINX_SERVER_PORT; @@ -4025,6 +4075,7 @@ GET /t === TEST 68: receiveany with limited, max is larger than data +--- no_http2 --- config server_tokens off; location = /t { @@ -4094,6 +4145,7 @@ lua tcp socket calling receiveany() method to read at most 128 bytes === TEST 69: receiveany with limited, max is smaller than data +--- no_http2 --- config server_tokens off; location = /t { @@ -4168,6 +4220,7 @@ lua tcp socket calling receiveany() method to read at most 7 bytes === TEST 70: send tables of string fragments (with floating point number too) +--- no_http2 --- config server_tokens off; location /t { @@ -4242,6 +4295,7 @@ close: 1 nil === TEST 71: send numbers the maximum number of significant digits is 14 in lua +--- no_http2 --- config server_tokens off; location /t { diff --git a/t/065-tcp-socket-timeout.t b/t/065-tcp-socket-timeout.t index e06dfb1fc8..14563f70c6 100644 --- a/t/065-tcp-socket-timeout.t +++ b/t/065-tcp-socket-timeout.t @@ -16,6 +16,7 @@ BEGIN { $ENV{MOCKEAGAIN} = 'w'; } + delete($ENV{TEST_NGINX_USE_HTTP2}); $ENV{TEST_NGINX_EVENT_TYPE} = 'poll'; $ENV{MOCKEAGAIN_WRITE_TIMEOUT_PATTERN} = 'get helloworld'; } diff --git a/t/066-socket-receiveuntil.t b/t/066-socket-receiveuntil.t index 2d38fb5c37..9d9f2804b4 100644 --- a/t/066-socket-receiveuntil.t +++ b/t/066-socket-receiveuntil.t @@ -71,6 +71,7 @@ close: 1 nil === TEST 2: http read lines +--- no_http2 --- config server_tokens off; location /t { @@ -140,6 +141,7 @@ close: 1 nil === TEST 3: http read all the headers in a single run +--- no_http2 --- config server_tokens off; location /t { @@ -208,6 +210,7 @@ close: 1 nil === TEST 4: ambiguous boundary patterns (abcabd) +--- no_http2 --- config server_tokens off; location /t { @@ -279,6 +282,7 @@ close: 1 nil === TEST 5: ambiguous boundary patterns (aa) +--- no_http2 --- config server_tokens off; location /t { @@ -350,6 +354,7 @@ close: 1 nil === TEST 6: ambiguous boundary patterns (aaa) +--- no_http2 --- config server_tokens off; location /t { @@ -421,6 +426,7 @@ close: 1 nil === TEST 7: ambiguous boundary patterns (aaaaad) +--- no_http2 --- config server_tokens off; location /t { @@ -492,6 +498,7 @@ close: 1 nil === TEST 8: ambiguous boundary patterns (aaaaad), small buffer, 2 bytes +--- no_http2 --- config server_tokens off; lua_socket_buffer_size 2; @@ -564,6 +571,7 @@ close: 1 nil === TEST 9: ambiguous boundary patterns (aaaaad), small buffer, 1 byte +--- no_http2 --- config server_tokens off; lua_socket_buffer_size 1; @@ -636,6 +644,7 @@ close: 1 nil === TEST 10: ambiguous boundary patterns (abcabdabcabe) +--- no_http2 --- config server_tokens off; location /t { @@ -707,6 +716,7 @@ close: 1 nil === TEST 11: ambiguous boundary patterns (abcabdabcabe 2) +--- no_http2 --- config server_tokens off; location /t { @@ -778,6 +788,7 @@ close: 1 nil === TEST 12: ambiguous boundary patterns (abcabdabcabe 3) +--- no_http2 --- config server_tokens off; location /t { @@ -849,6 +860,7 @@ close: 1 nil === TEST 13: ambiguous boundary patterns (abcabdabcabe 4) +--- no_http2 --- config server_tokens off; location /t { @@ -920,6 +932,7 @@ close: 1 nil === TEST 14: ambiguous boundary patterns (--abc) +--- no_http2 --- config server_tokens off; location /t { @@ -991,6 +1004,7 @@ close: 1 nil === TEST 15: ambiguous boundary patterns (--abc) +--- no_http2 --- config server_tokens off; location /t { @@ -1066,6 +1080,7 @@ close: 1 nil === TEST 16: ambiguous boundary patterns (--abc), small buffer +--- no_http2 --- config server_tokens off; location /t { @@ -1142,6 +1157,7 @@ close: 1 nil === TEST 17: ambiguous boundary patterns (--abc), small buffer, mixed by other reading calls +--- no_http2 --- config server_tokens off; location /t { @@ -1230,6 +1246,7 @@ close: 1 nil === TEST 18: ambiguous boundary patterns (abcabd), small buffer +--- no_http2 --- config server_tokens off; lua_socket_buffer_size 3; diff --git a/t/067-req-socket.t b/t/067-req-socket.t index fbaa0b3f41..9aff58b647 100644 --- a/t/067-req-socket.t +++ b/t/067-req-socket.t @@ -5,6 +5,8 @@ our $SkipReason; BEGIN { if ($ENV{TEST_NGINX_USE_HTTP3}) { $SkipReason = "http3 does not support ngx.req.socket"; + } elsif ($ENV{TEST_NGINX_USE_HTTP2}) { + $SkipReason = "http2 does not support ngx.req.socket"; } } diff --git a/t/082-body-filter-2.t b/t/082-body-filter-2.t index d19f46f660..ee4fe56ece 100644 --- a/t/082-body-filter-2.t +++ b/t/082-body-filter-2.t @@ -3,11 +3,19 @@ our $SkipReason; BEGIN { - $ENV{TEST_NGINX_POSTPONE_OUTPUT} = 1; - $ENV{TEST_NGINX_EVENT_TYPE} = 'poll'; - $ENV{MOCKEAGAIN}='w'; - if ($ENV{TEST_NGINX_USE_HTTP3}) { - $SkipReason = "http3 has bug about the hup reload"; + if ($ENV{TEST_NGINX_EVENT_TYPE} && $ENV{TEST_NGINX_EVENT_TYPE} ne 'poll') { + $SkipReason = "unavailable for the event type '$ENV{TEST_NGINX_EVENT_TYPE}'"; + + } elsif ($ENV{TEST_NGINX_USE_HTTP3}) { + $SkipReason = "http3 does not support mockeagain"; + + } elsif ($ENV{TEST_NGINX_USE_HTTP2}) { + $SkipReason = "http2 does not support mockeagain"; + + } else { + $ENV{TEST_NGINX_POSTPONE_OUTPUT} = 1; + $ENV{TEST_NGINX_EVENT_TYPE} = 'poll'; + $ENV{MOCKEAGAIN}='w' } } diff --git a/t/084-inclusive-receiveuntil.t b/t/084-inclusive-receiveuntil.t index 95d898501c..5921044b49 100644 --- a/t/084-inclusive-receiveuntil.t +++ b/t/084-inclusive-receiveuntil.t @@ -19,6 +19,7 @@ run_tests(); __DATA__ === TEST 1: ambiguous boundary patterns (abcabd) - inclusive mode +--- no_http2 --- config server_tokens off; location /t { @@ -91,6 +92,7 @@ close: 1 nil === TEST 2: ambiguous boundary patterns (abcabdabcabe 4) - inclusive mode +--- no_http2 --- config server_tokens off; location /t { @@ -162,6 +164,7 @@ close: 1 nil === TEST 3: ambiguous boundary patterns (abcabd) - inclusive mode - small buffers +--- no_http2 --- config server_tokens off; lua_socket_buffer_size 1; @@ -235,6 +238,7 @@ close: 1 nil === TEST 4: inclusive option value nil +--- no_http2 --- config server_tokens off; location /t { @@ -306,6 +310,7 @@ close: 1 nil === TEST 5: inclusive option value false +--- no_http2 --- config server_tokens off; location /t { @@ -377,6 +382,7 @@ close: 1 nil === TEST 6: inclusive option value true (aa) +--- no_http2 --- config server_tokens off; location /t { @@ -448,6 +454,7 @@ close: 1 nil === TEST 7: bad inclusive option value type +--- no_http2 --- config server_tokens off; location /t { @@ -517,6 +524,7 @@ curl: (52) Empty reply from server === TEST 8: bad option table +--- no_http2 --- config server_tokens off; location /t { @@ -586,6 +594,7 @@ curl: (52) Empty reply from server === TEST 9: ambiguous boundary patterns (--abc), small buffer +--- no_http2 --- config server_tokens off; location /t { @@ -662,6 +671,7 @@ close: 1 nil === TEST 10: ambiguous boundary patterns (--abc), small buffer, mixed by other reading calls +--- no_http2 --- config server_tokens off; location /t { diff --git a/t/088-req-method.t b/t/088-req-method.t index de3421662c..9e1499fb86 100644 --- a/t/088-req-method.t +++ b/t/088-req-method.t @@ -164,6 +164,7 @@ PUT === TEST 8: set GET to HEAD +--- no_http2 --- config location /t { rewrite_by_lua ' @@ -210,6 +211,7 @@ main: GET === TEST 10: set HEAD to GET XXX: does http3 do not support set HEAD to GET?? +--- no_http2 --- config location /t { rewrite_by_lua ' @@ -230,6 +232,7 @@ method: GET === TEST 11: set GET to WebDAV methods XXX: does http3 do not support change HEAD method? +--- no_http2 --- config location /t { content_by_lua ' diff --git a/t/091-coroutine.t b/t/091-coroutine.t index e8761045b8..2c10d54209 100644 --- a/t/091-coroutine.t +++ b/t/091-coroutine.t @@ -762,8 +762,8 @@ GET /lua --- ignore_response --- error_log API disabled in the context of header_filter_by_lua* ---- curl_error -curl: (52) Empty reply from server +--- curl_error eval +qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly/ @@ -1699,8 +1699,8 @@ GET /t "stack traceback:", "in function 'co'" ] ---- curl_error -curl: (52) Empty reply from server +--- curl_error eval +qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly/ diff --git a/t/100-client-abort.t b/t/100-client-abort.t index fed01176c7..39d3244b16 100644 --- a/t/100-client-abort.t +++ b/t/100-client-abort.t @@ -1,8 +1,10 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: BEGIN { -if ($ENV{TEST_NGINX_USE_HTTP3}) { - $SkipReason = "client abort detect does not support in http3" + if ($ENV{TEST_NGINX_USE_HTTP3}) { + $SkipReason = "client abort detect does not support in http3"; + } elsif ($ENV{TEST_NGINX_USE_HTTP2}) { + $SkipReason = "client abort detect does not support in http2"; } } diff --git a/t/101-on-abort.t b/t/101-on-abort.t index f10027a47a..784f244e04 100644 --- a/t/101-on-abort.t +++ b/t/101-on-abort.t @@ -1,8 +1,10 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: BEGIN { -if ($ENV{TEST_NGINX_USE_HTTP3}) { - $SkipReason = "client abort detect does not support in http3" + if ($ENV{TEST_NGINX_USE_HTTP3}) { + $SkipReason = "client abort detect does not support in http3"; + } elsif ($ENV{TEST_NGINX_USE_HTTP2}) { + $SkipReason = "client abort detect does not support in http2"; } } diff --git a/t/103-req-http-ver.t b/t/103-req-http-ver.t index ebc65c9d38..73ecccae28 100644 --- a/t/103-req-http-ver.t +++ b/t/103-req-http-ver.t @@ -30,6 +30,8 @@ GET /t my $body; if (defined $ENV{TEST_NGINX_USE_HTTP3}) { $body="3\n"; +} elsif (defined $ENV{TEST_NGINX_USE_HTTP2}) { + $body="2\n"; } else { $body="1.1\n"; } diff --git a/t/106-timer.t b/t/106-timer.t index d455ea2add..a9b4aed7bd 100644 --- a/t/106-timer.t +++ b/t/106-timer.t @@ -228,6 +228,7 @@ qr/\[lua\] content_by_lua\(nginx\.conf:\d+\):\d+: elapsed: 0\.(?:1[4-9]|2[0-6]?) === TEST 5: tcp cosocket in timer handler (short connections) +--- no_http2 --- config server_tokens off; diff --git a/t/108-timer-safe.t b/t/108-timer-safe.t index 387f203c3d..a23634cd3b 100644 --- a/t/108-timer-safe.t +++ b/t/108-timer-safe.t @@ -124,6 +124,7 @@ qr/\[lua\] content_by_lua\(nginx\.conf:\d+\):\d+: elapsed: 0\.(?:6[4-9]|7[0-6])/ === TEST 3: tcp cosocket in timer handler (short connections) +--- no_http2 --- config server_tokens off; location = /t { diff --git a/t/132-lua-blocks.t b/t/132-lua-blocks.t index 2a1644e532..35638a8489 100644 --- a/t/132-lua-blocks.t +++ b/t/132-lua-blocks.t @@ -166,6 +166,7 @@ ok === TEST 8: content_by_lua_block (cosockets) +--- no_http2 --- config server_tokens off; location = /t { diff --git a/t/138-balancer-upstream-bind.t b/t/138-balancer-upstream-bind.t new file mode 100644 index 0000000000..dc2c9665f3 --- /dev/null +++ b/t/138-balancer-upstream-bind.t @@ -0,0 +1,141 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use Test::Nginx::Socket::Lua; + +#worker_connections(1014); +#master_on(); +#workers(2); +#log_level('warn'); + +repeat_each(2); + +plan tests => repeat_each() * (blocks() * 3); + +#no_diff(); +no_long_string(); +run_tests(); + +__DATA__ + +=== TEST 1: bind to empty +--- no_http2 +--- http_config + lua_package_path "$TEST_NGINX_SERVER_ROOT/html/?.lua;;"; + + upstream backend { + server 127.0.0.1:$TEST_NGINX_SERVER_PORT; + } +--- config + set $proxy_local_addr ""; + proxy_bind $proxy_local_addr; + + location = /t { + proxy_pass http://backend/back; + } + + location = /back { + echo ok; + } + +--- request + GET /t +--- response_body +ok +--- no_error_log +[cirt] + + + +=== TEST 2: bind to 127.0.0.1 +--- no_http2 +--- http_config + lua_package_path "$TEST_NGINX_SERVER_ROOT/html/?.lua;;"; + + upstream backend { + server 127.0.0.1:$TEST_NGINX_SERVER_PORT; + } +--- config + set $proxy_local_addr ""; + proxy_bind $proxy_local_addr; + + location = /t { + access_by_lua_block { + ngx.var.proxy_local_addr="127.0.0.1" + } + proxy_pass http://backend/back; + } + + location = /back { + echo ok; + } + +--- request + GET /t +--- response_body +ok +--- no_error_log +[cirt] + + + +=== TEST 3: bind to 127.0.0.10 +--- no_http2 +--- http_config + lua_package_path "$TEST_NGINX_SERVER_ROOT/html/?.lua;;"; + + upstream backend { + server 127.0.0.1:$TEST_NGINX_SERVER_PORT; + } +--- config + set $proxy_local_addr ""; + proxy_bind $proxy_local_addr; + + location = /t { + access_by_lua_block { + ngx.var.proxy_local_addr="127.0.0.10" + } + proxy_pass http://backend/back; + } + + location = /back { + echo ok; + } + +--- request + GET /t +--- response_body +ok +--- no_error_log +[cirt] + + + +=== TEST 4: bind to not exist addr 100.100.100.100 +--- no_http2 +--- http_config + lua_package_path "$TEST_NGINX_SERVER_ROOT/html/?.lua;;"; + + upstream backend { + server 127.0.0.1:$TEST_NGINX_SERVER_PORT; + } +--- config + set $proxy_local_addr ""; + proxy_bind $proxy_local_addr; + + location = /t { + access_by_lua_block { + ngx.var.proxy_local_addr="100.100.100.100" + } + proxy_pass http://backend/back; + } + + location = /back { + echo ok; + } + +--- request + GET /t +--- response_body +ok +--- error_log +bind(100.100.100.100) failed (99: Cannot assign requested address) diff --git a/t/138-balancer.t b/t/138-balancer.t index d9c943388e..8ccdee76c4 100644 --- a/t/138-balancer.t +++ b/t/138-balancer.t @@ -309,6 +309,7 @@ qr{\[crit\] .*? connect\(\) to 0\.0\.0\.1:80 failed .*?, upstream: "http://0\.0\ === TEST 12: code cache off +--- no_http2 --- http_config lua_package_path "$TEST_NGINX_SERVER_ROOT/html/?.lua;;"; diff --git a/t/147-tcp-socket-timeouts.t b/t/147-tcp-socket-timeouts.t index 8566c0ba6f..ceddb61dcc 100644 --- a/t/147-tcp-socket-timeouts.t +++ b/t/147-tcp-socket-timeouts.t @@ -17,6 +17,7 @@ BEGIN { } $ENV{TEST_NGINX_EVENT_TYPE} = 'poll'; + delete($ENV{TEST_NGINX_USE_HTTP2}); $ENV{MOCKEAGAIN_WRITE_TIMEOUT_PATTERN} = 'slowdata'; } diff --git a/t/156-slow-network.t b/t/156-slow-network.t index 2d80506085..d5897fb33e 100644 --- a/t/156-slow-network.t +++ b/t/156-slow-network.t @@ -15,6 +15,7 @@ BEGIN { } $ENV{TEST_NGINX_EVENT_TYPE} = 'poll'; + delete($ENV{TEST_NGINX_USE_HTTP2}); } use Test::Nginx::Socket::Lua; diff --git a/t/163-signal.t b/t/163-signal.t index 2b85e12482..ec3a418d90 100644 --- a/t/163-signal.t +++ b/t/163-signal.t @@ -39,7 +39,7 @@ qr/\[notice\] \d+#\d+: exit$/ --- no_error_log eval qr/\[notice\] \d+#\d+: reconfiguring/ --- curl_error eval -qr/curl: \(28\) Operation timed out after 3\d+ milliseconds with 0 bytes received/ +qr/curl: \(28\) Operation timed out after \d+ milliseconds with 0 bytes received|curl: \(56\) Recv failure: Connection reset by peer/ diff --git a/t/166-worker-thread.t b/t/166-worker-thread.t index afe7f3c410..15e9d762eb 100644 --- a/t/166-worker-thread.t +++ b/t/166-worker-thread.t @@ -282,6 +282,7 @@ false : module 'hello' not found.* === TEST 10: the number of Lua VM exceeds the pool size +--- no_http2 --- quic_max_idle_timeout: 5 --- main_config thread_pool testpool threads=100; @@ -360,6 +361,7 @@ GET /t === TEST 11: kill uthread before worker thread callback +--- no_http2 --- quic_max_idle_timeout: 10 --- main_config thread_pool testpool threads=100; From 028852c1564d9f1ea5e395509c44b2825b77dfb7 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Sat, 2 Sep 2023 19:12:32 +0800 Subject: [PATCH 119/254] enable http3 test. --- .travis.yml | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/.travis.yml b/.travis.yml index 48d92855c0..5c366f0b96 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,9 +27,7 @@ addons: - time - cmake - libunwind-dev - - libpsl0 - wget - - libldap-2.4-2 - libbrotli1 cache: @@ -66,7 +64,7 @@ env: #- NGINX_VERSION=1.21.4 OPENSSL_VER=1.1.0l OPENSSL_PATCH_VER=1.1.0d #- NGINX_VERSION=1.21.4 OPENSSL_VER=1.1.1s OPENSSL_PATCH_VER=1.1.1f #- NGINX_VERSION=1.25.1 OPENSSL_VER=1.1.0l OPENSSL_PATCH_VER=1.1.0d - - NGINX_VERSION=1.25.1 OPENSSL_VER=1.1.1s OPENSSL_PATCH_VER=1.1.1f USE_PCRE2=Y + #- NGINX_VERSION=1.25.1 OPENSSL_VER=1.1.1s OPENSSL_PATCH_VER=1.1.1f USE_PCRE2=Y - NGINX_VERSION=1.25.1 BORINGSSL=1 TEST_NGINX_USE_HTTP3=1 USE_PCRE2=Y #- NGINX_VERSION=1.25.1 OPENSSL_VER=1.1.1s TEST_NGINX_USE_HTTP2=1 @@ -81,11 +79,13 @@ before_install: - /usr/bin/env perl $(command -v cpanm) --sudo --notest Test::Nginx IPC::Run > build.log 2>&1 || (cat build.log && exit 1) - pyenv global 2.7 install: + - if [ ! -f download-cache/drizzle7-$DRIZZLE_VER.tar.gz ]; then wget -P download-cache http://openresty.org/download/drizzle7-$DRIZZLE_VER.tar.gz; fi - if [ "$USE_PCRE2" != "Y" ] && [ ! -f download-cache/pcre-$PCRE_VER.tar.gz ]; then wget -P download-cache https://downloads.sourceforge.net/project/pcre/pcre/${PCRE_VER}/pcre-${PCRE_VER}.tar.gz; fi - if [ "$USE_PCRE2" = "Y" ] && [ ! -f download-cache/pcre2-$PCRE2_VER.tar.gz ]; then wget -P download-cache https://downloads.sourceforge.net/project/pcre/pcre2/${PCRE2_VER}/pcre2-${PCRE2_VER}.tar.gz; fi - if [ ! -f download-cache/openssl-$OPENSSL_VER.tar.gz ]; then wget -P download-cache https://www.openssl.org/source/openssl-$OPENSSL_VER.tar.gz || wget -P download-cache https://www.openssl.org/source/old/${OPENSSL_VER//[a-z]/}/openssl-$OPENSSL_VER.tar.gz; fi - if [ -n "$OPENSSL_VER" ] && [ ! -f download-cache/openssl-$OPENSSL_VER.tar.gz ]; then wget -P download-cache https://www.openssl.org/source/openssl-$OPENSSL_VER.tar.gz || wget -P download-cache https://www.openssl.org/source/old/${OPENSSL_VER//[a-z]/}/openssl-$OPENSSL_VER.tar.gz; fi - - wget https://github.com/zhuizhuhaomeng/curl-http3/releases/download/v1.0.0/curl-h3.tar.gz + - wget https://github.com/openresty/openresty-deps-prebuild/releases/download/v20230902/boringssl-20230902-x64-focal.tar.gz + - wget https://github.com/openresty/openresty-deps-prebuild/releases/download/v20230902/curl-h3-x64-focal.tar.gz - git clone https://github.com/openresty/test-nginx.git - git clone https://github.com/openresty/openresty.git ../openresty - git clone https://github.com/openresty/no-pool-nginx.git ../no-pool-nginx @@ -116,7 +116,7 @@ before_script: - mysql -uroot -e "create database ngx_test; CREATE USER 'ngx_test'@'%' IDENTIFIED BY 'ngx_test'; grant all on ngx_test.* to 'ngx_test'@'%'; flush privileges;" script: - - sudo tar -C / -xf curl-h3.tar.gz + - sudo tar -C / -xf curl-h3-x64-focal.tar.gz - export PATH=$PWD/work/nginx/sbin:$PWD/openresty-devel-utils:/opt/curl-h3/bin:$PATH - ngx-releng > check.txt || true - lines=`wc -l check.txt | awk '{print $1}'`; if [ $lines -gt 5 ]; then cat check.txt; exit 1; fi @@ -137,13 +137,8 @@ script: - cd lua-cjson/ && make -j$JOBS && sudo make install && cd .. - if [ "$USE_PCRE2" != "Y" ]; then tar zxf download-cache/pcre-$PCRE_VER.tar.gz; cd pcre-$PCRE_VER/; ./configure --prefix=$PCRE_PREFIX --enable-jit --enable-utf --enable-unicode-properties > build.log 2>&1 || (cat build.log && exit 1); make -j$JOBS > build.log 2>&1 || (cat build.log && exit 1); sudo PATH=$PATH make install > build.log 2>&1 || (cat build.log && exit 1); cd ..; fi - if [ "$USE_PCRE2" = "Y" ]; then tar zxf download-cache/pcre2-$PCRE2_VER.tar.gz; cd pcre2-$PCRE2_VER/; ./configure --prefix=$PCRE2_PREFIX --enable-jit --enable-utf > build.log 2>&1 || (cat build.log && exit 1); make -j$JOBS > build.log 2>&1 || (cat build.log && exit 1); sudo PATH=$PATH make install > build.log 2>&1 || (cat build.log && exit 1); cd ..; fi - - tar zxf download-cache/openssl-$OPENSSL_VER.tar.gz - - cd openssl-$OPENSSL_VER/ - - patch -p1 < ../../openresty/patches/openssl-$OPENSSL_PATCH_VER-sess_set_get_cb_yield.patch - - ./config shared enable-ssl3 enable-ssl3-method -g --prefix=$OPENSSL_PREFIX -DPURIFY > build.log 2>&1 || (cat build.log && exit 1) - - make -j$JOBS > build.log 2>&1 || (cat build.log && exit 1) - - sudo make PATH=$PATH install_sw > build.log 2>&1 || (cat build.log && exit 1) - - cd .. + - if [ -n "$OPENSSL_VER" ]; then tar zxf download-cache/openssl-$OPENSSL_VER.tar.gz; cd openssl-$OPENSSL_VER/; patch -p1 < ../../openresty/patches/openssl-$OPENSSL_PATCH_VER-sess_set_get_cb_yield.patch; ./config shared enable-ssl3 enable-ssl3-method -g --prefix=$OPENSSL_PREFIX -DPURIFY > build.log 2>&1 || (cat build.log && exit 1); make -j$JOBS > build.log 2>&1 || (cat build.log && exit 1); sudo make PATH=$PATH install_sw > build.log 2>&1 || (cat build.log && exit 1); cd ..; fi + - if [ -n "$BORINGSSL" ]; then sudo mkdir -p /opt/ssl && sudo tar -C /opt/ssl -xf boringssl-20230902-x64-focal.tar.gz --strip-components=1; fi - export NGX_BUILD_CC=$CC - sh util/build-without-ssl.sh $NGINX_VERSION > build.log 2>&1 || (cat build.log && exit 1) - sh util/build-with-dd.sh $NGINX_VERSION > build.log 2>&1 || (cat build.log && exit 1) From 488ba271109fb19ce5bfb901ec2fc638a9e1de9c Mon Sep 17 00:00:00 2001 From: lijunlong Date: Wed, 18 Oct 2023 19:32:30 +0800 Subject: [PATCH 120/254] bugfix: failed to compile with clang. ``` src/ngx_http_lua_worker_thread.c:454:57: error: implicit truncation from 'int' to a one-bit wide bit-field changes value from 1 to -1 [-Werror,-Wsingle-bit-bitfield-constant-conversion] worker_thread_ctx->is_abort = 1; ^ ~ ``` --- src/ngx_http_lua_worker_thread.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ngx_http_lua_worker_thread.c b/src/ngx_http_lua_worker_thread.c index 9de59def75..3820d6377c 100644 --- a/src/ngx_http_lua_worker_thread.c +++ b/src/ngx_http_lua_worker_thread.c @@ -42,7 +42,7 @@ typedef struct { ngx_http_lua_co_ctx_t *wait_co_ctx; int n_args; int rc; - int is_abort:1; + ngx_uint_t is_abort:1; } ngx_http_lua_worker_thread_ctx_t; From 5ae767d504179fe1d2ca848fb65c321e22b082b3 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Mon, 23 Oct 2023 16:32:15 +0800 Subject: [PATCH 121/254] tests: build drizzle with python3. --- .travis.yml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5c366f0b96..2fd8a03509 100644 --- a/.travis.yml +++ b/.travis.yml @@ -62,9 +62,9 @@ env: - MALLOC_PERTURB_=9 jobs: #- NGINX_VERSION=1.21.4 OPENSSL_VER=1.1.0l OPENSSL_PATCH_VER=1.1.0d - #- NGINX_VERSION=1.21.4 OPENSSL_VER=1.1.1s OPENSSL_PATCH_VER=1.1.1f + - NGINX_VERSION=1.21.4 OPENSSL_VER=1.1.1s OPENSSL_PATCH_VER=1.1.1f #- NGINX_VERSION=1.25.1 OPENSSL_VER=1.1.0l OPENSSL_PATCH_VER=1.1.0d - #- NGINX_VERSION=1.25.1 OPENSSL_VER=1.1.1s OPENSSL_PATCH_VER=1.1.1f USE_PCRE2=Y + - NGINX_VERSION=1.25.1 OPENSSL_VER=1.1.1s OPENSSL_PATCH_VER=1.1.1f USE_PCRE2=Y - NGINX_VERSION=1.25.1 BORINGSSL=1 TEST_NGINX_USE_HTTP3=1 USE_PCRE2=Y #- NGINX_VERSION=1.25.1 OPENSSL_VER=1.1.1s TEST_NGINX_USE_HTTP2=1 @@ -77,9 +77,8 @@ before_install: - '! grep -n -P ''(?<=.{80}).+'' --color `find src -name ''*.c''` `find . -name ''*.h''` || (echo "ERROR: Found C source lines exceeding 80 columns." > /dev/stderr; exit 1)' - '! grep -n -P ''\t+'' --color `find src -name ''*.c''` `find . -name ''*.h''` || (echo "ERROR: Cannot use tabs." > /dev/stderr; exit 1)' - /usr/bin/env perl $(command -v cpanm) --sudo --notest Test::Nginx IPC::Run > build.log 2>&1 || (cat build.log && exit 1) - - pyenv global 2.7 install: - - if [ ! -f download-cache/drizzle7-$DRIZZLE_VER.tar.gz ]; then wget -P download-cache http://openresty.org/download/drizzle7-$DRIZZLE_VER.tar.gz; fi + - if [ ! -f download-cache/drizzle7-$DRIZZLE_VER.tar.gz ]; then wget -P download-cache https://github.com/openresty/openresty-deps-prebuild/releases/download/v20230902/drizzle7-$DRIZZLE_VER.tar.gz; fi - if [ "$USE_PCRE2" != "Y" ] && [ ! -f download-cache/pcre-$PCRE_VER.tar.gz ]; then wget -P download-cache https://downloads.sourceforge.net/project/pcre/pcre/${PCRE_VER}/pcre-${PCRE_VER}.tar.gz; fi - if [ "$USE_PCRE2" = "Y" ] && [ ! -f download-cache/pcre2-$PCRE2_VER.tar.gz ]; then wget -P download-cache https://downloads.sourceforge.net/project/pcre/pcre2/${PCRE2_VER}/pcre2-${PCRE2_VER}.tar.gz; fi - if [ ! -f download-cache/openssl-$OPENSSL_VER.tar.gz ]; then wget -P download-cache https://www.openssl.org/source/openssl-$OPENSSL_VER.tar.gz || wget -P download-cache https://www.openssl.org/source/old/${OPENSSL_VER//[a-z]/}/openssl-$OPENSSL_VER.tar.gz; fi @@ -113,7 +112,7 @@ install: - git clone -b v2.1-agentzh https://github.com/openresty/luajit2.git luajit2 before_script: - - mysql -uroot -e "create database ngx_test; CREATE USER 'ngx_test'@'%' IDENTIFIED BY 'ngx_test'; grant all on ngx_test.* to 'ngx_test'@'%'; flush privileges;" + - mysql -uroot -e "create database ngx_test; CREATE USER 'ngx_test'@'%' IDENTIFIED WITH mysql_native_password BY 'ngx_test'; grant all on ngx_test.* to 'ngx_test'@'%'; flush privileges;" script: - sudo tar -C / -xf curl-h3-x64-focal.tar.gz From 51984aea047a3aaefb1c382e077a23d7f1952db5 Mon Sep 17 00:00:00 2001 From: Johnny Wang Date: Wed, 25 Oct 2023 18:09:15 +0800 Subject: [PATCH 122/254] tests: check if the version number has been specified before downloading OpenSSL. (#2240) --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 2fd8a03509..60e1a053d9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -77,11 +77,12 @@ before_install: - '! grep -n -P ''(?<=.{80}).+'' --color `find src -name ''*.c''` `find . -name ''*.h''` || (echo "ERROR: Found C source lines exceeding 80 columns." > /dev/stderr; exit 1)' - '! grep -n -P ''\t+'' --color `find src -name ''*.c''` `find . -name ''*.h''` || (echo "ERROR: Cannot use tabs." > /dev/stderr; exit 1)' - /usr/bin/env perl $(command -v cpanm) --sudo --notest Test::Nginx IPC::Run > build.log 2>&1 || (cat build.log && exit 1) + install: - if [ ! -f download-cache/drizzle7-$DRIZZLE_VER.tar.gz ]; then wget -P download-cache https://github.com/openresty/openresty-deps-prebuild/releases/download/v20230902/drizzle7-$DRIZZLE_VER.tar.gz; fi - if [ "$USE_PCRE2" != "Y" ] && [ ! -f download-cache/pcre-$PCRE_VER.tar.gz ]; then wget -P download-cache https://downloads.sourceforge.net/project/pcre/pcre/${PCRE_VER}/pcre-${PCRE_VER}.tar.gz; fi - if [ "$USE_PCRE2" = "Y" ] && [ ! -f download-cache/pcre2-$PCRE2_VER.tar.gz ]; then wget -P download-cache https://downloads.sourceforge.net/project/pcre/pcre2/${PCRE2_VER}/pcre2-${PCRE2_VER}.tar.gz; fi - - if [ ! -f download-cache/openssl-$OPENSSL_VER.tar.gz ]; then wget -P download-cache https://www.openssl.org/source/openssl-$OPENSSL_VER.tar.gz || wget -P download-cache https://www.openssl.org/source/old/${OPENSSL_VER//[a-z]/}/openssl-$OPENSSL_VER.tar.gz; fi + - if [ -n "$OPENSSL_VER" ] && [ ! -f download-cache/openssl-$OPENSSL_VER.tar.gz ]; then wget -P download-cache https://www.openssl.org/source/openssl-$OPENSSL_VER.tar.gz || wget -P download-cache https://www.openssl.org/source/old/${OPENSSL_VER//[a-z]/}/openssl-$OPENSSL_VER.tar.gz; fi - if [ -n "$OPENSSL_VER" ] && [ ! -f download-cache/openssl-$OPENSSL_VER.tar.gz ]; then wget -P download-cache https://www.openssl.org/source/openssl-$OPENSSL_VER.tar.gz || wget -P download-cache https://www.openssl.org/source/old/${OPENSSL_VER//[a-z]/}/openssl-$OPENSSL_VER.tar.gz; fi - wget https://github.com/openresty/openresty-deps-prebuild/releases/download/v20230902/boringssl-20230902-x64-focal.tar.gz - wget https://github.com/openresty/openresty-deps-prebuild/releases/download/v20230902/curl-h3-x64-focal.tar.gz From 25c9643cf42b71046fda31ec3b491a4ab9fe4868 Mon Sep 17 00:00:00 2001 From: Michael McQuade Date: Wed, 25 Oct 2023 05:13:22 -0500 Subject: [PATCH 123/254] docs: remove duplicated sentence. --- README.markdown | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.markdown b/README.markdown index aaf53b1459..3aa9f592d8 100644 --- a/README.markdown +++ b/README.markdown @@ -4,13 +4,11 @@ Name ngx_http_lua_module - Embed the power of Lua into Nginx HTTP Servers. This module is a core component of [OpenResty](https://openresty.org). If you are using this module, -then you are essentially using OpenResty. +then you are essentially using OpenResty :) *This module is not distributed with the Nginx source.* See [the installation instructions](#installation). -This is a core component of OpenResty. If you are using this module, then you are essentially using OpenResty :) - Table of Contents ================= From 87f41a9545c43e94a1d582e1db4eb65a7124a903 Mon Sep 17 00:00:00 2001 From: menglei Date: Thu, 26 Oct 2023 10:05:05 +0800 Subject: [PATCH 124/254] bugfix: fix some failed test case. --- t/066-socket-receiveuntil.t | 1 - t/082-body-filter.t | 1 - t/138-balancer-upstream-bind.t | 5 +++-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/t/066-socket-receiveuntil.t b/t/066-socket-receiveuntil.t index 9d9f2804b4..3b1f280c29 100644 --- a/t/066-socket-receiveuntil.t +++ b/t/066-socket-receiveuntil.t @@ -1344,7 +1344,6 @@ this exposed a memory leak in receiveuntil ok --- no_error_log [error] -<<<<<<< HEAD diff --git a/t/082-body-filter.t b/t/082-body-filter.t index 54e7414cb8..49a1d76397 100644 --- a/t/082-body-filter.t +++ b/t/082-body-filter.t @@ -842,7 +842,6 @@ GET /lua --- ignore_response --- error_log API disabled in the context of body_filter_by_lua* -<<<<<<< HEAD diff --git a/t/138-balancer-upstream-bind.t b/t/138-balancer-upstream-bind.t index dc2c9665f3..442f37c8f3 100644 --- a/t/138-balancer-upstream-bind.t +++ b/t/138-balancer-upstream-bind.t @@ -135,7 +135,8 @@ ok --- request GET /t ---- response_body -ok +--- response_body_like chomp +500 Internal Server Error +--- error_code: 500 --- error_log bind(100.100.100.100) failed (99: Cannot assign requested address) From 7661f9b48a89ecc803ebd59a7b465e9c53c26ab8 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Thu, 26 Oct 2023 10:14:50 +0800 Subject: [PATCH 125/254] tests: t/166-ssl-client-hello.t: fixed test plan. --- t/166-ssl-client-hello.t | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/166-ssl-client-hello.t b/t/166-ssl-client-hello.t index 445434289a..102cd2e303 100644 --- a/t/166-ssl-client-hello.t +++ b/t/166-ssl-client-hello.t @@ -11,7 +11,7 @@ my $openssl_version = eval { `$NginxBinary -V 2>&1` }; if ($openssl_version =~ m/built with OpenSSL (0\S*|1\.0\S*|1\.1\.0\S*)/) { plan(skip_all => "too old OpenSSL, need 1.1.1, was $1"); } else { - plan tests => repeat_each() * (blocks() * 6 + 6); + plan tests => repeat_each() * (blocks() * 6 + 8); } $ENV{TEST_NGINX_HTML_DIR} ||= html_dir(); From db80075e0a318d719ff105808f2e69c07c5b4fb6 Mon Sep 17 00:00:00 2001 From: willmafh Date: Thu, 26 Oct 2023 21:34:11 +0800 Subject: [PATCH 126/254] doc: more accurate error messages. --- src/ngx_http_lua_socket_tcp.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 88fe923eb1..505614c47f 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -2413,7 +2413,7 @@ ngx_http_lua_socket_tcp_receive(lua_State *L) case LUA_TNUMBER: bytes = lua_tointeger(L, 2); if (bytes < 0) { - return luaL_argerror(L, 2, "bad pattern argument"); + return luaL_argerror(L, 2, "bad number argument"); } #if 1 @@ -2430,7 +2430,7 @@ ngx_http_lua_socket_tcp_receive(lua_State *L) break; default: - return luaL_argerror(L, 2, "bad pattern argument"); + return luaL_argerror(L, 2, "bad argument"); break; } @@ -4586,7 +4586,7 @@ ngx_http_lua_socket_receiveuntil_iterator(lua_State *L) n = lua_gettop(L); if (n > 1) { - return luaL_error(L, "expecting 0 or 1 arguments, " + return luaL_error(L, "expecting 0 or 1 argument, " "but seen %d", n); } @@ -5076,7 +5076,7 @@ ngx_http_lua_req_socket(lua_State *L) lua_pop(L, 1); } else { - return luaL_error(L, "expecting zero arguments, but got %d", + return luaL_error(L, "expecting 0 or 1 argument, but got %d", lua_gettop(L)); } From 86bea01b244938e0ab6eda780906c06fa62c3b5c Mon Sep 17 00:00:00 2001 From: swananan Date: Sun, 5 Nov 2023 20:52:20 +0800 Subject: [PATCH 127/254] changes: modify read body api limitation for HTTP/2 or HTTP/3 requests. --- README.markdown | 4 ++-- src/ngx_http_lua_accessby.c | 25 +++++++++++++++++++++---- src/ngx_http_lua_contentby.c | 25 +++++++++++++++++++++---- src/ngx_http_lua_req_body.c | 28 ++++++++++++++++++++++++---- t/023-rewrite/request_body.t | 2 ++ t/024-access/request_body.t | 2 ++ t/044-req-body.t | 4 +++- 7 files changed, 75 insertions(+), 15 deletions(-) diff --git a/README.markdown b/README.markdown index 3aa9f592d8..b6ccecf8a8 100644 --- a/README.markdown +++ b/README.markdown @@ -2722,7 +2722,7 @@ lua_need_request_body **phase:** *depends on usage* -Due to the stream processing feature of HTTP2, it does not support HTTP2 connection. +Due to the stream processing feature of HTTP/2 or HTTP/3, this configuration could potentially block the entire request. Therefore, this configuration is effective only when HTTP/2 or HTTP/3 requests send content-length header. For requests with versions lower than HTTP/2, this configuration can still be used without any problems. Determines whether to force the request body data to be read before running rewrite/access/content_by_lua* or not. The Nginx core does not read the client request body by default and if request body data is required, then this directive should be turned `on` or the [ngx.req.read_body](#ngxreqread_body) function should be called within the Lua code. @@ -5426,7 +5426,7 @@ Reads the client request body synchronously without blocking the Nginx event loo local args = ngx.req.get_post_args() ``` -Due to the stream processing feature of HTTP2, it does not support HTTP2 connection. +Due to the stream processing feature of HTTP/2 or HTTP/3, this api could potentially block the entire request. Therefore, this api is effective only when HTTP/2 or HTTP/3 requests send content-length header. For requests with versions lower than HTTP/2, this api can still be used without any problems. If the request body is already read previously by turning on [lua_need_request_body](#lua_need_request_body) or by using other modules, then this function does not run and returns immediately. diff --git a/src/ngx_http_lua_accessby.c b/src/ngx_http_lua_accessby.c index fa6810d9ed..1669f161d6 100644 --- a/src/ngx_http_lua_accessby.c +++ b/src/ngx_http_lua_accessby.c @@ -136,11 +136,26 @@ ngx_http_lua_access_handler(ngx_http_request_t *r) return NGX_DONE; } -/* http2 read body may break http2 stream process */ -#if (NGX_HTTP_V2) - if (llcf->force_read_body && !ctx->read_body_done && !r->main->stream) { -#else if (llcf->force_read_body && !ctx->read_body_done) { + +#if (NGX_HTTP_V2) + if (r->main->stream && r->headers_in.content_length_n < 0) { + ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, + "disable lua_need_request_body, since " + "http2 read_body may break http2 stream process"); + goto done; + } +#endif + +#if (NGX_HTTP_V3) + if (r->http_version == NGX_HTTP_VERSION_30 + && r->headers_in.content_length_n < 0) + { + ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, + "disable lua_need_request_body, since " + "http2 read_body may break http2 stream process"); + goto done; + } #endif r->request_body_in_single_buf = 1; r->request_body_in_persistent_file = 1; @@ -159,6 +174,8 @@ ngx_http_lua_access_handler(ngx_http_request_t *r) } } +done: + dd("calling access handler"); return llcf->access_handler(r); } diff --git a/src/ngx_http_lua_contentby.c b/src/ngx_http_lua_contentby.c index d1c3bc9fd9..38aebc3bb2 100644 --- a/src/ngx_http_lua_contentby.c +++ b/src/ngx_http_lua_contentby.c @@ -195,11 +195,26 @@ ngx_http_lua_content_handler(ngx_http_request_t *r) return rc; } -/* http2 read body may break http2 stream process */ -#if (NGX_HTTP_V2) - if (llcf->force_read_body && !ctx->read_body_done && !r->main->stream) { -#else if (llcf->force_read_body && !ctx->read_body_done) { + +#if (NGX_HTTP_V2) + if (r->main->stream && r->headers_in.content_length_n < 0) { + ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, + "disable lua_need_request_body, since " + "http2 read_body may break http2 stream process"); + goto done; + } +#endif + +#if (NGX_HTTP_V3) + if (r->http_version == NGX_HTTP_VERSION_30 + && r->headers_in.content_length_n < 0) + { + ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, + "disable lua_need_request_body, since " + "http2 read_body may break http2 stream process"); + goto done; + } #endif r->request_body_in_single_buf = 1; r->request_body_in_persistent_file = 1; @@ -219,6 +234,8 @@ ngx_http_lua_content_handler(ngx_http_request_t *r) } } +done: + dd("setting entered"); ctx->entered_content_phase = 1; diff --git a/src/ngx_http_lua_req_body.c b/src/ngx_http_lua_req_body.c index 3c452b3051..4dd105e144 100644 --- a/src/ngx_http_lua_req_body.c +++ b/src/ngx_http_lua_req_body.c @@ -87,8 +87,18 @@ ngx_http_lua_ngx_req_read_body(lua_State *L) /* http2 read body may break http2 stream process */ #if (NGX_HTTP_V2) - if (r->main->stream) { - return luaL_error(L, "http2 requests are not supported yet"); + if (r->main->stream && r->headers_in.content_length_n < 0) { + return luaL_error(L, "http2 requests are not supported" + " without content-length header"); + } +#endif + +#if (NGX_HTTP_V3) + if (r->http_version == NGX_HTTP_VERSION_30 + && r->headers_in.content_length_n < 0) + { + return luaL_error(L, "http3 requests are not supported" + " without content-length header"); } #endif @@ -321,8 +331,18 @@ ngx_http_lua_ngx_req_get_body_file(lua_State *L) /* http2 read body may break http2 stream process */ #if (NGX_HTTP_V2) - if (r->main->stream) { - return luaL_error(L, "http2 requests are not supported yet"); + if (r->main->stream && r->headers_in.content_length_n < 0) { + return luaL_error(L, "http2 requests are not supported" + " without content-length header"); + } +#endif + +#if (NGX_HTTP_V3) + if (r->http_version == NGX_HTTP_VERSION_30 + && r->headers_in.content_length_n < 0) + { + return luaL_error(L, "http3 requests are not supported" + " without content-length header"); } #endif diff --git a/t/023-rewrite/request_body.t b/t/023-rewrite/request_body.t index f9af17236f..a721eba31e 100644 --- a/t/023-rewrite/request_body.t +++ b/t/023-rewrite/request_body.t @@ -187,6 +187,8 @@ http finalize request: 500, "/echo_body?" a:1, c:0 "POST /echo_body hello\x00\x01\x02 world\x03\x04\xff" +--- more_headers +Content-Length: --- response_body eval "nil" --- no_error_log diff --git a/t/024-access/request_body.t b/t/024-access/request_body.t index 4970e37aef..9086bf9e36 100644 --- a/t/024-access/request_body.t +++ b/t/024-access/request_body.t @@ -187,6 +187,8 @@ http finalize request: 500, "/echo_body?" a:1, c:0 "POST /echo_body hello\x00\x01\x02 world\x03\x04\xff" +--- more_headers +Content-Length: --- response_body eval "nil" --- no_error_log diff --git a/t/044-req-body.t b/t/044-req-body.t index 0c378c44aa..29cb914257 100644 --- a/t/044-req-body.t +++ b/t/044-req-body.t @@ -1787,5 +1787,7 @@ content length: 5 --- request POST /test hello, world +--- more_headers +Content-Length: --- error_code: 500 ---- error_log: http2 requests are not supported yet +--- error_log: http2 requests are not supported without content-length header From 187ad5c0509b152b4bceff388f38b02ae9395d01 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Thu, 9 Nov 2023 23:05:47 +0800 Subject: [PATCH 128/254] bugfix: failed to build when building without http2&http3 modules. --- src/ngx_http_lua_accessby.c | 4 ++++ src/ngx_http_lua_contentby.c | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/src/ngx_http_lua_accessby.c b/src/ngx_http_lua_accessby.c index 1669f161d6..2bf40aaa87 100644 --- a/src/ngx_http_lua_accessby.c +++ b/src/ngx_http_lua_accessby.c @@ -174,8 +174,12 @@ ngx_http_lua_access_handler(ngx_http_request_t *r) } } +#if defined(NGX_HTTP_V3) || defined(NGX_HTTP_V2) + done: +#endif + dd("calling access handler"); return llcf->access_handler(r); } diff --git a/src/ngx_http_lua_contentby.c b/src/ngx_http_lua_contentby.c index 38aebc3bb2..2014d52d8d 100644 --- a/src/ngx_http_lua_contentby.c +++ b/src/ngx_http_lua_contentby.c @@ -234,8 +234,12 @@ ngx_http_lua_content_handler(ngx_http_request_t *r) } } +#if defined(NGX_HTTP_V3) || defined(NGX_HTTP_V2) + done: +#endif + dd("setting entered"); ctx->entered_content_phase = 1; From 339b08a4be9f98d3b88da5a88a478d359db01023 Mon Sep 17 00:00:00 2001 From: menglei Date: Sun, 12 Nov 2023 22:10:11 +0800 Subject: [PATCH 129/254] doc: make some debug message and comments accurate. --- src/ngx_http_lua_module.c | 16 ++++++++-------- src/ngx_http_lua_ssl_client_helloby.c | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/ngx_http_lua_module.c b/src/ngx_http_lua_module.c index 6984fb087d..fb10bf933e 100644 --- a/src/ngx_http_lua_module.c +++ b/src/ngx_http_lua_module.c @@ -1178,15 +1178,15 @@ ngx_http_lua_create_srv_conf(ngx_conf_t *cf) * lscf->srv.ssl_cert_chunkname = NULL; * lscf->srv.ssl_cert_src_key = NULL; * - * lscf->srv.ssl_session_store_handler = NULL; - * lscf->srv.ssl_session_store_src = { 0, NULL }; - * lscf->srv.ssl_session_store_chunkname = NULL; - * lscf->srv.ssl_session_store_src_key = NULL; + * lscf->srv.ssl_sess_store_handler = NULL; + * lscf->srv.ssl_sess_store_src = { 0, NULL }; + * lscf->srv.ssl_sess_store_chunkname = NULL; + * lscf->srv.ssl_sess_store_src_key = NULL; * - * lscf->srv.ssl_session_fetch_handler = NULL; - * lscf->srv.ssl_session_fetch_src = { 0, NULL }; - * lscf->srv.ssl_session_fetch_chunkname = NULL; - * lscf->srv.ssl_session_fetch_src_key = NULL; + * lscf->srv.ssl_sess_fetch_handler = NULL; + * lscf->srv.ssl_sess_fetch_src = { 0, NULL }; + * lscf->srv.ssl_sess_fetch_chunkname = NULL; + * lscf->srv.ssl_sess_fetch_src_key = NULL; * * lscf->balancer.handler = NULL; * lscf->balancer.src = { 0, NULL }; diff --git a/src/ngx_http_lua_ssl_client_helloby.c b/src/ngx_http_lua_ssl_client_helloby.c index a1dac61887..03ac430ef2 100644 --- a/src/ngx_http_lua_ssl_client_helloby.c +++ b/src/ngx_http_lua_ssl_client_helloby.c @@ -390,7 +390,7 @@ ngx_http_lua_ssl_client_hello_aborted(void *data) { ngx_http_lua_ssl_ctx_t *cctx = data; - dd("lua ssl client hello done"); + dd("lua ssl client hello aborted"); if (cctx->done) { /* completed successfully already */ From 577dfebba4f05796662f2be3b14a884a922a87ba Mon Sep 17 00:00:00 2001 From: masterlvng Date: Tue, 14 Nov 2023 21:17:45 +0800 Subject: [PATCH 130/254] feature: add max_bytes argument for get_body_data() function. --- README.markdown | 4 +++- doc/HttpLuaModule.wiki | 4 +++- src/ngx_http_lua_req_body.c | 32 ++++++++++++++++++++++++++------ t/010-request_body.t | 17 +++++++++++++++++ 4 files changed, 49 insertions(+), 8 deletions(-) diff --git a/README.markdown b/README.markdown index b6ccecf8a8..dce83887fa 100644 --- a/README.markdown +++ b/README.markdown @@ -5467,12 +5467,14 @@ See also [ngx.req.read_body](#ngxreqread_body). ngx.req.get_body_data --------------------- -**syntax:** *data = ngx.req.get_body_data()* +**syntax:** *data = ngx.req.get_body_data(max_bytes?)* **context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, log_by_lua** Retrieves in-memory request body data. It returns a Lua string rather than a Lua table holding all the parsed query arguments. Use the [ngx.req.get_post_args](#ngxreqget_post_args) function instead if a Lua table is required. +The optional `max_bytes` argument can be used when you don't need the entire body. + This function returns `nil` if 1. the request body has not been read, diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 678e60b47c..551f804992 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -4587,12 +4587,14 @@ See also [[#ngx.req.read_body|ngx.req.read_body]]. == ngx.req.get_body_data == -'''syntax:''' ''data = ngx.req.get_body_data()'' +'''syntax:''' ''data = ngx.req.get_body_data(max_bytes?)'' '''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, log_by_lua*'' Retrieves in-memory request body data. It returns a Lua string rather than a Lua table holding all the parsed query arguments. Use the [[#ngx.req.get_post_args|ngx.req.get_post_args]] function instead if a Lua table is required. +The optional max_bytes function argument can be used when you don't need the entire body. + This function returns nil if # the request body has not been read, diff --git a/src/ngx_http_lua_req_body.c b/src/ngx_http_lua_req_body.c index 4dd105e144..61ab999045 100644 --- a/src/ngx_http_lua_req_body.c +++ b/src/ngx_http_lua_req_body.c @@ -246,15 +246,21 @@ ngx_http_lua_ngx_req_get_body_data(lua_State *L) { ngx_http_request_t *r; int n; - size_t len; + size_t len, max; + size_t size, rest; ngx_chain_t *cl; u_char *p; u_char *buf; n = lua_gettop(L); - if (n != 0) { - return luaL_error(L, "expecting 0 arguments but seen %d", n); + if (n != 0 && n != 1) { + return luaL_error(L, "expecting 0 or 1 arguments but seen %d", n); + } + + max = 0; + if (n == 1) { + max = (size_t) luaL_checknumber(L, 1); } r = ngx_http_lua_get_req(L); @@ -282,6 +288,7 @@ ngx_http_lua_ngx_req_get_body_data(lua_State *L) return 1; } + len = (max > 0 && len > max) ? max : len; lua_pushlstring(L, (char *) cl->buf->pos, len); return 1; } @@ -292,7 +299,13 @@ ngx_http_lua_ngx_req_get_body_data(lua_State *L) for (; cl; cl = cl->next) { dd("body chunk len: %d", (int) ngx_buf_size(cl->buf)); - len += cl->buf->last - cl->buf->pos; + size = cl->buf->last - cl->buf->pos; + if (max > 0 && (len + size > max)) { + len = max; + break; + } + + len += size; } if (len == 0) { @@ -303,8 +316,15 @@ ngx_http_lua_ngx_req_get_body_data(lua_State *L) buf = (u_char *) lua_newuserdata(L, len); p = buf; - for (cl = r->request_body->bufs; cl; cl = cl->next) { - p = ngx_copy(p, cl->buf->pos, cl->buf->last - cl->buf->pos); + rest = len; + for (cl = r->request_body->bufs; cl != NULL && rest > 0; cl = cl->next) { + size = ngx_buf_size(cl->buf); + if (size > rest) { /* reach limit*/ + size = rest; + } + + p = ngx_copy(p, cl->buf->pos, size); + rest -= size; } lua_pushlstring(L, (char *) buf, len); diff --git a/t/010-request_body.t b/t/010-request_body.t index e669d9480e..5e4d96d0e9 100644 --- a/t/010-request_body.t +++ b/t/010-request_body.t @@ -270,3 +270,20 @@ Expect: 100-Continue http finalize request: 500, "/echo_body?" a:1, c:2 http finalize request: 500, "/echo_body?" a:1, c:0 --- log_level: debug + + + +=== TEST 13: test reading the first n bytes of request body +--- config + location /echo_body { + lua_need_request_body on; + content_by_lua_block { + local data = ngx.req.get_body_data(1) + ngx.say(data) + } + } +--- request +POST /echo_body +hello +--- response_body +h From 3a0b823d9fe5e9eb9cf3b41afd5497192ae57110 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Tue, 14 Nov 2023 21:23:09 +0800 Subject: [PATCH 131/254] feature: make HTTP3 authority as http_host header. --- src/ngx_http_lua_headers.c | 73 ++++++++++++++++++++++++++++++++ src/ngx_http_lua_subrequest.c | 13 ++++++ src/ngx_http_lua_variable.c | 12 ++++++ t/001-set.t | 4 +- t/005-exit.t | 4 ++ t/010-request_body.t | 4 +- t/014-bugs.t | 12 +++++- t/016-resp-header.t | 8 ++-- t/020-subrequest.t | 5 ++- t/023-rewrite/req-body.t | 1 + t/023-rewrite/request_body.t | 1 + t/023-rewrite/socket-keepalive.t | 2 +- t/023-rewrite/tcp-socket.t | 12 +++--- t/024-access/req-body.t | 1 + t/024-access/request_body.t | 1 + t/025-codecache.t | 3 +- t/031-post-args.t | 1 + t/033-ctx.t | 2 +- t/041-header-filter.t | 48 ++++++++++++--------- t/043-shdict.t | 4 +- t/044-req-body.t | 17 +++++--- t/058-tcp-socket.t | 13 +++--- t/066-socket-receiveuntil.t | 1 + t/075-logby.t | 1 + t/082-body-filter.t | 16 ++++--- t/084-inclusive-receiveuntil.t | 8 ++-- t/091-coroutine.t | 4 +- t/094-uthread-exit.t | 16 +++---- t/095-uthread-exec.t | 4 +- t/096-uthread-redirect.t | 4 +- t/124-init-worker.t | 1 + t/129-ssl-socket.t | 12 +++++- t/139-ssl-cert-by.t | 10 ++--- t/142-ssl-session-store.t | 1 + t/143-ssl-session-fetch.t | 17 ++++++++ t/163-signal.t | 2 +- t/166-ssl-client-hello.t | 2 + t/166-worker-thread.t | 2 + t/167-server-rewrite.t | 4 +- t/186-cosocket-busy-bufs.t | 12 +++++- t/187-ssl-two-verification.t | 2 + 41 files changed, 271 insertions(+), 89 deletions(-) diff --git a/src/ngx_http_lua_headers.c b/src/ngx_http_lua_headers.c index a2ce6e1452..85836a1289 100644 --- a/src/ngx_http_lua_headers.c +++ b/src/ngx_http_lua_headers.c @@ -782,6 +782,11 @@ ngx_http_lua_ffi_req_get_headers_count(ngx_http_request_t *r, int max, { int count; ngx_list_part_t *part; +#if (NGX_HTTP_V3) + int has_host = 0; + ngx_uint_t i; + ngx_table_elt_t *header; +#endif if (r->connection->fd == (ngx_socket_t) -1) { return NGX_HTTP_LUA_FFI_BAD_CONTEXT; @@ -794,11 +799,54 @@ ngx_http_lua_ffi_req_get_headers_count(ngx_http_request_t *r, int max, } part = &r->headers_in.headers.part; + +#if (NGX_HTTP_V3) + count = 0; + header = part->elts; + + if (r->http_version == NGX_HTTP_VERSION_30 + && r->headers_in.server.data != NULL) + { + has_host = 1; + count++; + } + + if (has_host == 1) { + for (i = 0; /* void */; i++) { + if (i >= part->nelts) { + if (part->next == NULL) { + break; + } + + part = part->next; + header = part->elts; + i = 0; + } + + if (header[i].key.len == 4 + && ngx_strncasecmp(header[i].key.data, + (u_char *) "host", 4) == 0) + { + continue; + } + + count++; + } + + } else { + count = part->nelts; + while (part->next != NULL) { + part = part->next; + count += part->nelts; + } + } +#else count = part->nelts; while (part->next != NULL) { part = part->next; count += part->nelts; } +#endif if (max > 0 && count > max) { *truncated = 1; @@ -821,12 +869,29 @@ ngx_http_lua_ffi_req_get_headers(ngx_http_request_t *r, ngx_uint_t i; ngx_list_part_t *part; ngx_table_elt_t *header; +#if (NGX_HTTP_V3) + int has_host = 0; +#endif if (count <= 0) { return NGX_OK; } n = 0; + +#if (NGX_HTTP_V3) + if (r->http_version == NGX_HTTP_VERSION_30 + && r->headers_in.server.data != NULL) + { + out[n].key.data = (u_char *) "host"; + out[n].key.len = sizeof("host") - 1; + out[n].value.len = r->headers_in.server.len; + out[n].value.data = r->headers_in.server.data; + has_host = 1; + ++n; + } +#endif + part = &r->headers_in.headers.part; header = part->elts; @@ -842,6 +907,14 @@ ngx_http_lua_ffi_req_get_headers(ngx_http_request_t *r, i = 0; } +#if (NGX_HTTP_V3) + if (has_host == 1 && header[i].key.len == 4 + && ngx_strncasecmp(header[i].key.data, (u_char *) "host", 4) == 0) + { + continue; + } +#endif + if (raw) { out[n].key.data = header[i].key.data; out[n].key.len = (int) header[i].key.len; diff --git a/src/ngx_http_lua_subrequest.c b/src/ngx_http_lua_subrequest.c index c09207417e..f4db9aaf6c 100644 --- a/src/ngx_http_lua_subrequest.c +++ b/src/ngx_http_lua_subrequest.c @@ -52,6 +52,8 @@ ngx_str_t ngx_http_lua_patch_method = ngx_str_t ngx_http_lua_trace_method = ngx_http_lua_method_name("TRACE"); +ngx_str_t host_header = ngx_string("host"); + static ngx_str_t ngx_http_lua_content_length_header_key = ngx_string("Content-Length"); @@ -1699,6 +1701,17 @@ ngx_http_lua_copy_request_headers(ngx_http_request_t *sr, part = &pr->headers_in.headers.part; header = part->elts; +#if (NGX_HTTP_V3) + if (pr->headers_in.server.data != NULL) { + if (ngx_http_lua_set_input_header(sr, host_header, + pr->headers_in.server, 0) + == NGX_ERROR) + { + return NGX_ERROR; + } + } +#endif + for (i = 0; /* void */; i++) { if (i >= part->nelts) { diff --git a/src/ngx_http_lua_variable.c b/src/ngx_http_lua_variable.c index 573629ad21..2c6c6233bd 100644 --- a/src/ngx_http_lua_variable.c +++ b/src/ngx_http_lua_variable.c @@ -70,6 +70,18 @@ ngx_http_lua_ffi_var_get(ngx_http_request_t *r, u_char *name_data, } #endif +#if (NGX_HTTP_V3) + if (name_len == 9 + && r->http_version == NGX_HTTP_VERSION_30 + && ngx_strncasecmp(name_data, (u_char *) "http_host", 9) == 0 + && r->headers_in.server.data != NULL) + { + *value = r->headers_in.server.data; + *value_len = r->headers_in.server.len; + return NGX_OK; + } +#endif + hash = ngx_hash_strlow(lowcase_buf, name_data, name_len); name.data = lowcase_buf; diff --git a/t/001-set.t b/t/001-set.t index abbee72121..009159e484 100644 --- a/t/001-set.t +++ b/t/001-set.t @@ -389,8 +389,8 @@ GET /lua GET /lua --- response_body_like: 500 Internal Server Error --- error_code: 500 ---- error_log -API disabled in the context of set_by_lua* +--- error_log eval +qr/(?:API disabled in the context of set_by_lua\*|http3 requests are not supported without content-length header)/ms diff --git a/t/005-exit.t b/t/005-exit.t index e057fe1c69..0783c69295 100644 --- a/t/005-exit.t +++ b/t/005-exit.t @@ -774,6 +774,8 @@ GET /t --- response_body --- no_error_log [error] +--- curl_error +curl: (95) HTTP/3 stream 0 reset by server @@ -790,6 +792,8 @@ GET /t --- response_body --- no_error_log [error] +--- curl_error +curl: (95) HTTP/3 stream 0 reset by server diff --git a/t/010-request_body.t b/t/010-request_body.t index 5e4d96d0e9..c47f9fc13d 100644 --- a/t/010-request_body.t +++ b/t/010-request_body.t @@ -270,6 +270,7 @@ Expect: 100-Continue http finalize request: 500, "/echo_body?" a:1, c:2 http finalize request: 500, "/echo_body?" a:1, c:0 --- log_level: debug +--- skip_eval: 4:$ENV{TEST_NGINX_USE_HTTP3} @@ -281,9 +282,10 @@ http finalize request: 500, "/echo_body?" a:1, c:0 local data = ngx.req.get_body_data(1) ngx.say(data) } - } + } --- request POST /echo_body hello --- response_body h +--- skip_eval: 2:$ENV{TEST_NGINX_USE_HTTP3} diff --git a/t/014-bugs.t b/t/014-bugs.t index f4e596640e..ff85ca3558 100644 --- a/t/014-bugs.t +++ b/t/014-bugs.t @@ -885,6 +885,7 @@ GET /t --- no_error_log [error] --- timeout: 10 +--- skip_eval: 3:$ENV{TEST_NGINX_USE_HTTP3} @@ -1305,8 +1306,17 @@ location /t { --- response_body Hello world --- shutdown_error_log eval -qr|failed to read a line: closed| +my $expr; + +if ($ENV{TEST_NGINX_USE_HTTP3}) { + $expr = qr|lua close the global Lua VM| +} else { + $expr = qr|failed to read a line: closed| +} + +$expr; --- timeout: 1.2 +--- skip_eval: 2:$ENV{TEST_NGINX_USE_HTTP3} diff --git a/t/016-resp-header.t b/t/016-resp-header.t index ac0c52eeef..6cf699d88e 100644 --- a/t/016-resp-header.t +++ b/t/016-resp-header.t @@ -2209,8 +2209,8 @@ upstream prematurely closed connection while sending to client Foo --- request GET /a.txt ---- raw_response_headers_like chomp -Age: \d\r\n +--- raw_response_headers_like eval +qr/^(a|A)ge: \d\r\n/ms --- no_error_log [error] @@ -2240,8 +2240,8 @@ Age: \d\r\n Foo --- request GET /test/a.txt ---- raw_response_headers_like chomp -Age: \d\r\n +--- raw_response_headers_like eval +qr/^(a|A)ge: \d\r\n/ms --- no_error_log [error] diff --git a/t/020-subrequest.t b/t/020-subrequest.t index f629ca8754..d8aa34d7e8 100644 --- a/t/020-subrequest.t +++ b/t/020-subrequest.t @@ -1227,8 +1227,8 @@ F(ngx_http_finalize_request) { --- error_code --- no_error_log [error] ---- curl_error -curl: (52) Empty reply from server +--- curl_error eval +qr{(\Qcurl: (52) Empty reply from server\E|\Qcurl: (95) HTTP/3 stream 0 reset by server\E)}ms @@ -2340,6 +2340,7 @@ hello world nil --- no_error_log [error] +--- skip_eval: 3:$ENV{TEST_NGINX_USE_HTTP3} diff --git a/t/023-rewrite/req-body.t b/t/023-rewrite/req-body.t index 13bdcb2511..0c1857384e 100644 --- a/t/023-rewrite/req-body.t +++ b/t/023-rewrite/req-body.t @@ -125,6 +125,7 @@ Expect: 100-Continue [alert] [error] http finalize request: 500, "/test?" a:1, c:0 +--- skip_eval: 3:$ENV{TEST_NGINX_USE_HTTP3} diff --git a/t/023-rewrite/request_body.t b/t/023-rewrite/request_body.t index a721eba31e..32c02e151f 100644 --- a/t/023-rewrite/request_body.t +++ b/t/023-rewrite/request_body.t @@ -170,6 +170,7 @@ Expect: 100-Continue http finalize request: 500, "/echo_body?" a:1, c:2 http finalize request: 500, "/echo_body?" a:1, c:0 --- log_level: debug +--- skip_eval: 4:$ENV{TEST_NGINX_USE_HTTP3} diff --git a/t/023-rewrite/socket-keepalive.t b/t/023-rewrite/socket-keepalive.t index 5884c02b8e..9ce8d5e290 100644 --- a/t/023-rewrite/socket-keepalive.t +++ b/t/023-rewrite/socket-keepalive.t @@ -493,7 +493,7 @@ qr/lua tcp socket connection pool size: 1\b/] === TEST 7: "lua_socket_keepalive_timeout 0" means unlimited ---- quic_max_idle_timeout: 1.1 +--- quic_max_idle_timeout: 1.2 --- config server_tokens off; location /t { diff --git a/t/023-rewrite/tcp-socket.t b/t/023-rewrite/tcp-socket.t index 9ca66c64bb..966365f906 100644 --- a/t/023-rewrite/tcp-socket.t +++ b/t/023-rewrite/tcp-socket.t @@ -1667,8 +1667,8 @@ GET /t --- ignore_response --- error_log bad argument #1 to 'send' (bad data type nil found) ---- curl_error -curl: (52) Empty reply from server +--- curl_error eval +qr#curl: \(52\) Empty reply from server|curl: \(95\) HTTP/3 stream 0 reset by server# --- no_http2 @@ -1731,8 +1731,8 @@ GET /t --- ignore_response --- error_log bad argument #1 to 'send' (bad data type boolean found) ---- curl_error -curl: (52) Empty reply from server +--- curl_error eval +qr#curl: \(52\) Empty reply from server|curl: \(95\) HTTP/3 stream 0 reset by server# --- no_http2 @@ -1795,8 +1795,8 @@ GET /t --- ignore_response --- error_log bad argument #1 to 'send' (bad data type userdata found) ---- curl_error -curl: (52) Empty reply from server +--- curl_error eval +qr#curl: \(52\) Empty reply from server|curl: \(95\) HTTP/3 stream 0 reset by server# --- no_http2 diff --git a/t/024-access/req-body.t b/t/024-access/req-body.t index 70db85c1c2..48caeb9001 100644 --- a/t/024-access/req-body.t +++ b/t/024-access/req-body.t @@ -122,6 +122,7 @@ Expect: 100-Continue [alert] [error] http finalize request: 500, "/test?" a:1, c:0 +--- skip_eval: 3:$ENV{TEST_NGINX_USE_HTTP3} diff --git a/t/024-access/request_body.t b/t/024-access/request_body.t index 9086bf9e36..0aa12c8b55 100644 --- a/t/024-access/request_body.t +++ b/t/024-access/request_body.t @@ -170,6 +170,7 @@ Expect: 100-Continue http finalize request: 500, "/echo_body?" a:1, c:2 http finalize request: 500, "/echo_body?" a:1, c:0 --- log_level: debug +--- skip_eval: 4:$ENV{TEST_NGINX_USE_HTTP3} diff --git a/t/025-codecache.t b/t/025-codecache.t index 5be94d8ce7..cd56cf57aa 100644 --- a/t/025-codecache.t +++ b/t/025-codecache.t @@ -993,7 +993,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/, "lua close the global Lua VM", ] --- curl_error eval -qr/curl: \(\d+\) Empty reply from server/ +qr/curl: \(\d+\) Empty reply from server|curl: \(28\) Operation timed out after \d+ milliseconds with 0 bytes received/ @@ -1881,3 +1881,4 @@ qr/log_by_lua\(nginx.conf:\d+\):\d+: hello/, --- log_level: debug --- no_error_log [error] +--- skip_eval: 14:$ENV{TEST_NGINX_USE_HTTP3} diff --git a/t/031-post-args.t b/t/031-post-args.t index 4659f059fc..78805d3723 100644 --- a/t/031-post-args.t +++ b/t/031-post-args.t @@ -108,6 +108,7 @@ a=3&b=4&c --- request POST /lua --- response_body +--- skip_eval: 2:$ENV{TEST_NGINX_USE_HTTP3} diff --git a/t/033-ctx.t b/t/033-ctx.t index 6133cee2bb..782a0fab6e 100644 --- a/t/033-ctx.t +++ b/t/033-ctx.t @@ -279,7 +279,7 @@ GET /t --- error_log ngx.ctx = 32 --- curl_error eval -qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly/ +qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly|curl: \(95\) HTTP\/3 stream 0 reset by server/ diff --git a/t/041-header-filter.t b/t/041-header-filter.t index d36d3e025c..23fdac02cd 100644 --- a/t/041-header-filter.t +++ b/t/041-header-filter.t @@ -125,7 +125,7 @@ GET /read --- error_code --- response_body --- curl_error eval -qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly/ +qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly|curl: \(95\) HTTP\/3 stream 0 reset by server/ @@ -468,7 +468,7 @@ failed to run header_filter_by_lua*: header_filter_by_lua(nginx.conf:47):2: Some --- no_error_log [alert] --- curl_error eval -qr/curl: \(56\) Failure when receiving data from the peer|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly|curl: \(52\) Empty reply from server/ +qr/curl: \(56\) Failure when receiving data from the peer|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly|curl: \(52\) Empty reply from server|curl: \(95\) HTTP\/3 stream 0 reset by server/ @@ -492,7 +492,7 @@ failed to run header_filter_by_lua*: unknown reason --- no_error_log [alert] --- curl_error eval -qr/curl: \(56\) Failure when receiving data from the peer|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly|curl: \(52\) Empty reply from server/ +qr/curl: \(56\) Failure when receiving data from the peer|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly|curl: \(52\) Empty reply from server|curl: \(95\) HTTP\/3 stream 0 reset by server/ @@ -508,7 +508,7 @@ GET /lua --- error_log API disabled in the context of header_filter_by_lua* --- curl_error eval -qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly/ +qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly|curl: \(95\) HTTP\/3 stream 0 reset by server/ @@ -524,7 +524,7 @@ GET /lua --- error_log API disabled in the context of header_filter_by_lua* --- curl_error eval -qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly/ +qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly|curl: \(95\) HTTP\/3 stream 0 reset by server/ @@ -540,7 +540,7 @@ GET /lua --- error_log API disabled in the context of header_filter_by_lua* --- curl_error eval -qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly/ +qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly|curl: \(95\) HTTP\/3 stream 0 reset by server/ @@ -556,7 +556,7 @@ GET /lua --- error_log API disabled in the context of header_filter_by_lua* --- curl_error eval -qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly/ +qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly|curl: \(95\) HTTP\/3 stream 0 reset by server/ @@ -572,7 +572,7 @@ GET /lua --- error_log API disabled in the context of header_filter_by_lua* --- curl_error eval -qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly/ +qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly|curl: \(95\) HTTP\/3 stream 0 reset by server/ @@ -592,7 +592,7 @@ GET /lua --- error_log API disabled in the context of header_filter_by_lua* --- curl_error eval -qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly/ +qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly|curl: \(95\) HTTP\/3 stream 0 reset by server/ @@ -612,7 +612,7 @@ GET /lua --- error_log API disabled in the context of header_filter_by_lua* --- curl_error eval -qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly/ +qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly|curl: \(95\) HTTP\/3 stream 0 reset by server/ @@ -628,7 +628,7 @@ GET /lua --- error_log API disabled in the context of header_filter_by_lua* --- curl_error eval -qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly/ +qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly|curl: \(95\) HTTP\/3 stream 0 reset by server/ @@ -644,7 +644,7 @@ GET /lua --- error_log API disabled in the context of header_filter_by_lua* --- curl_error eval -qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly/ +qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly|curl: \(95\) HTTP\/3 stream 0 reset by server/ @@ -660,7 +660,7 @@ GET /lua --- error_log API disabled in the context of header_filter_by_lua* --- curl_error eval -qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly/ +qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly|curl: \(95\) HTTP\/3 stream 0 reset by server/ @@ -691,10 +691,10 @@ uri: /blah --- request GET /lua --- ignore_response ---- error_log -API disabled in the context of header_filter_by_lua* +--- error_log eval +qr/API disabled in the context of header_filter_by_lua\*|http3 requests are not supported without content-length header/ms --- curl_error eval -qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly/ +qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly|curl: \(95\) HTTP\/3 stream 0 reset by server/ @@ -718,7 +718,7 @@ if (defined $ENV{TEST_NGINX_USE_HTTP3}) { $err_log; --- curl_error eval -qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly/ +qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly|curl: \(95\) HTTP\/3 stream 0 reset by server/ @@ -734,7 +734,7 @@ GET /lua --- error_log API disabled in the context of header_filter_by_lua* --- curl_error eval -qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly/ +qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly|curl: \(95\) HTTP\/3 stream 0 reset by server/ @@ -750,7 +750,7 @@ GET /lua --- error_log API disabled in the context of header_filter_by_lua* --- curl_error eval -qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly/ +qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly|curl: \(95\) HTTP\/3 stream 0 reset by server/ @@ -799,7 +799,7 @@ in function 'error' in function 'bar' in function 'foo' --- curl_error eval -qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly/ +qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly|curl: \(95\) HTTP\/3 stream 0 reset by server/ @@ -819,7 +819,7 @@ GET /lua?a=1&b=2 --- error_log eval qr/failed to load external Lua file ".*?test2\.lua": cannot open .*? No such file or directory/ --- curl_error eval -qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly/ +qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly|curl: \(95\) HTTP\/3 stream 0 reset by server/ @@ -866,6 +866,8 @@ GET /lua failed to load inlined Lua code: header_filter_by_lua(nginx.conf:41):2: unexpected symbol near ''for end'' --- no_error_log no_such_error +--- curl_error eval +qr/curl: \(56\) Failure when receiving data from the peer/ @@ -895,6 +897,8 @@ GET /lua failed to load inlined Lua code: header_filter_by_lua(nginx.conf:49):2: unexpected symbol near ''for end'' --- no_error_log no_such_error +--- curl_error eval +qr/curl: \(56\) Failure when receiving data from the peer/ @@ -919,3 +923,5 @@ GET /lua failed to load inlined Lua code: header_filter_by_lua(...901234567890123456789012345.conf:1):2: unexpected symbol near ''for end'' --- no_error_log [alert] +--- curl_error eval +qr/curl: \(56\) Failure when receiving data from the peer/ diff --git a/t/043-shdict.t b/t/043-shdict.t index 4fcdcb33b6..649683b9fe 100644 --- a/t/043-shdict.t +++ b/t/043-shdict.t @@ -768,7 +768,7 @@ foo = 10502 dogs:set("bar", 32, 0.001) dogs:set("baz", 32, 0.001) dogs:set("foo", 32, 0.001) - ngx.location.capture("/sleep/0.002") + ngx.location.capture("/sleep/0.003") local res, err, forcible = dogs:add("foo", 10502) ngx.say("add: ", res, " ", err, " ", forcible) ngx.say("foo = ", dogs:get("foo")) @@ -797,7 +797,7 @@ foo = 10502 dogs:set("bar", 32, 0.001) dogs:set("baz", 32, 0.001) dogs:set("foo", "hi", 0.001) - ngx.location.capture("/sleep/0.002") + ngx.location.capture("/sleep/0.003") local res, err, forcible = dogs:add("foo", "hello") ngx.say("add: ", res, " ", err, " ", forcible) ngx.say("foo = ", dogs:get("foo")) diff --git a/t/044-req-body.t b/t/044-req-body.t index 29cb914257..f4509e1497 100644 --- a/t/044-req-body.t +++ b/t/044-req-body.t @@ -7,7 +7,7 @@ log_level('warn'); repeat_each(2); -plan tests => repeat_each() * (blocks() * 4 + 50 ); +plan tests => repeat_each() * (blocks() * 4 + 56); #no_diff(); no_long_string(); @@ -916,6 +916,7 @@ body: hell --- no_error_log [error] [alert] +--- skip_eval: 4:$ENV{TEST_NGINX_USE_HTTP3} @@ -977,6 +978,7 @@ body file: hello [alert] --- error_log a client request body is buffered to a temporary file +--- skip_eval: 5:$ENV{TEST_NGINX_USE_HTTP3} @@ -1003,9 +1005,9 @@ a client request body is buffered to a temporary file --- error_code: 500 --- error_log eval qr/lua entry thread aborted: runtime error: content_by_lua\(nginx\.conf:\d+\):2: request body not read yet/ - --- no_error_log [alert] +--- skip_eval: 4:$ENV{TEST_NGINX_USE_HTTP3} @@ -1035,8 +1037,8 @@ body: hell --- no_error_log [error] [alert] ---- no_error_log a client request body is buffered to a temporary file +--- skip_eval: 5:$ENV{TEST_NGINX_USE_HTTP3} @@ -1259,9 +1261,8 @@ body: hello, my dear friend! --- no_error_log [error] [alert] ---- no_error_log a client request body is buffered to a temporary file ---- skip_eval: 3:$ENV{TEST_NGINX_USE_HTTP3} +--- skip_eval: 5:$ENV{TEST_NGINX_USE_HTTP3} @@ -1401,9 +1402,8 @@ failed to get req socket: request body already exists --- no_error_log [error] [alert] ---- no_error_log a client request body is buffered to a temporary file ---- skip_eval: 3:$ENV{TEST_NGINX_USE_HTTP3} +--- skip_eval: 5:$ENV{TEST_NGINX_USE_HTTP3} @@ -1425,6 +1425,7 @@ Expect: 100-Continue [alert] [error] http finalize request: 500, "/test?" a:1, c:0 +--- skip_eval: 3:$ENV{TEST_NGINX_USE_HTTP3} @@ -1515,6 +1516,7 @@ Will you change this world? --- no_error_log [error] [alert] +--- skip_eval: 6:$ENV{TEST_NGINX_USE_HTTP3} @@ -1772,6 +1774,7 @@ content length: 5 --- no_error_log [error] [alert] +--- skip_eval: 4:$ENV{TEST_NGINX_USE_HTTP3} diff --git a/t/058-tcp-socket.t b/t/058-tcp-socket.t index 5602140fe1..b5cf58ec5b 100644 --- a/t/058-tcp-socket.t +++ b/t/058-tcp-socket.t @@ -255,6 +255,7 @@ second line received: (?:Date|Server): .*? --- no_error_log [error] --- timeout: 10 +--- skip_eval: 3:$ENV{TEST_NGINX_USE_HTTP3} @@ -1639,8 +1640,8 @@ GET /t --- ignore_response --- error_log bad argument #1 to 'send' (bad data type nil found) ---- curl_error -curl: (52) Empty reply from server +--- curl_error eval +qr#curl: \(52\) Empty reply from server|curl: \(95\) HTTP/3 stream 0 reset by server# @@ -1701,8 +1702,8 @@ GET /t --- ignore_response --- error_log bad argument #1 to 'send' (bad data type boolean found) ---- curl_error -curl: (52) Empty reply from server +--- curl_error eval +qr#curl: \(52\) Empty reply from server|curl: \(95\) HTTP/3 stream 0 reset by server# @@ -1763,8 +1764,8 @@ GET /t --- ignore_response --- error_log bad argument #1 to 'send' (bad data type userdata found) ---- curl_error -curl: (52) Empty reply from server +--- curl_error eval +qr#curl: \(52\) Empty reply from server|curl: \(95\) HTTP/3 stream 0 reset by server# diff --git a/t/066-socket-receiveuntil.t b/t/066-socket-receiveuntil.t index 3b1f280c29..43744a3721 100644 --- a/t/066-socket-receiveuntil.t +++ b/t/066-socket-receiveuntil.t @@ -1344,6 +1344,7 @@ this exposed a memory leak in receiveuntil ok --- no_error_log [error] +--- skip_eval: 3:$ENV{TEST_NGINX_USE_HTTP3} diff --git a/t/075-logby.t b/t/075-logby.t index de662d0fb4..3e9743584a 100644 --- a/t/075-logby.t +++ b/t/075-logby.t @@ -444,6 +444,7 @@ GET /lua ok --- error_log API disabled in the context of log_by_lua* +--- skip_eval: 3:$ENV{TEST_NGINX_USE_HTTP3} diff --git a/t/082-body-filter.t b/t/082-body-filter.t index 49a1d76397..4033bac8ce 100644 --- a/t/082-body-filter.t +++ b/t/082-body-filter.t @@ -482,8 +482,8 @@ stack traceback: in function 'error' in function 'bar' in function 'foo' ---- curl_error -curl: (52) Empty reply from server +--- curl_error eval +qr#curl: \(52\) Empty reply from server|curl: \(95\) HTTP\/3 stream 0 reset by server# @@ -526,8 +526,8 @@ GET /lua?a=1&b=2 --- ignore_response --- error_log eval qr/failed to load external Lua file ".*?test2\.lua": cannot open .*? No such file or directory/ ---- curl_error -curl: (52) Empty reply from server +--- curl_error eval +qr#curl: \(52\) Empty reply from server|curl: \(95\) HTTP\/3 stream 0 reset by server# @@ -842,6 +842,8 @@ GET /lua --- ignore_response --- error_log API disabled in the context of body_filter_by_lua* +--- curl_error eval +qr#curl: \(52\) Empty reply from server|curl: \(95\) HTTP\/3 stream 0 reset by server# @@ -864,6 +866,8 @@ failed to load inlined Lua code: body_filter_by_lua(nginx.conf:41):2: unexpected --- no_error_log no_such_error1 no_such_error2 +--- curl_error eval +qr#curl: \(52\) Empty reply from server|curl: \(95\) HTTP\/3 stream 0 reset by server# @@ -894,5 +898,5 @@ failed to load inlined Lua code: body_filter_by_lua(nginx.conf:49):2: unexpected --- no_error_log no_such_error1 no_such_error2 ---- curl_error -curl: (52) Empty reply from server +--- curl_error eval +qr#curl: \(52\) Empty reply from server|curl: \(95\) HTTP\/3 stream 0 reset by server# diff --git a/t/084-inclusive-receiveuntil.t b/t/084-inclusive-receiveuntil.t index 5921044b49..60f8363f92 100644 --- a/t/084-inclusive-receiveuntil.t +++ b/t/084-inclusive-receiveuntil.t @@ -518,8 +518,8 @@ bad "inclusive" option value type: string --- no_error_log [alert] [warn] ---- curl_error -curl: (52) Empty reply from server +--- curl_error eval +qr#curl: \(52\) Empty reply from server|curl: \(95\) HTTP\/3 stream 0 reset by server# @@ -588,8 +588,8 @@ bad "inclusive" option value type: string --- no_error_log [alert] [warn] ---- curl_error -curl: (52) Empty reply from server +--- curl_error eval +qr#curl: \(52\) Empty reply from server|curl: \(95\) HTTP\/3 stream 0 reset by server# diff --git a/t/091-coroutine.t b/t/091-coroutine.t index 2c10d54209..bfbdb38937 100644 --- a/t/091-coroutine.t +++ b/t/091-coroutine.t @@ -763,7 +763,7 @@ GET /lua --- error_log API disabled in the context of header_filter_by_lua* --- curl_error eval -qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly/ +qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly|curl: \(95\) HTTP\/3 stream 0 reset by server/ @@ -1700,7 +1700,7 @@ GET /t "in function 'co'" ] --- curl_error eval -qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly/ +qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly|curl: \(95\) HTTP\/3 stream 0 reset by server/ diff --git a/t/094-uthread-exit.t b/t/094-uthread-exit.t index 39b1f22b55..0194e44b31 100644 --- a/t/094-uthread-exit.t +++ b/t/094-uthread-exit.t @@ -1401,8 +1401,8 @@ attempt to abort with pending subrequests --- no_error_log [alert] [warn] ---- curl_error -curl: (52) Empty reply from server +--- curl_error eval +qr#curl: \(52\) Empty reply from server|curl: \(95\) HTTP/3 stream 0 reset by server# @@ -1486,8 +1486,8 @@ free request [alert] [error] [warn] ---- curl_error -curl: (52) Empty reply from server +--- curl_error eval +qr#curl: \(52\) Empty reply from server|curl: \(95\) HTTP/3 stream 0 reset by server# @@ -1571,8 +1571,8 @@ free request [alert] [error] [warn] ---- curl_error -curl: (52) Empty reply from server +--- curl_error eval +qr#curl: \(52\) Empty reply from server|curl: \(95\) HTTP/3 stream 0 reset by server# @@ -1656,5 +1656,5 @@ free request [alert] [error] [warn] ---- curl_error -curl: (52) Empty reply from server +--- curl_error eval +qr#curl: \(52\) Empty reply from server|curl: \(95\) HTTP/3 stream 0 reset by server# diff --git a/t/095-uthread-exec.t b/t/095-uthread-exec.t index 6e18c844ea..4cd121da1e 100644 --- a/t/095-uthread-exec.t +++ b/t/095-uthread-exec.t @@ -423,5 +423,5 @@ attempt to abort with pending subrequests --- no_error_log [alert] [warn] ---- curl_error -curl: (52) Empty reply from server +--- curl_error eval +qr#curl: \(52\) Empty reply from server|curl: \(95\) HTTP/3 stream 0 reset by server# diff --git a/t/096-uthread-redirect.t b/t/096-uthread-redirect.t index 2da84bd7aa..62909b944c 100644 --- a/t/096-uthread-redirect.t +++ b/t/096-uthread-redirect.t @@ -277,5 +277,5 @@ attempt to abort with pending subrequests --- no_error_log [alert] [warn] ---- curl_error -curl: (52) Empty reply from server +--- curl_error eval +qr#curl: \(52\) Empty reply from server|curl: \(95\) HTTP/3 stream 0 reset by server# diff --git a/t/124-init-worker.t b/t/124-init-worker.t index 57df4a5b3b..07c2658f06 100644 --- a/t/124-init-worker.t +++ b/t/124-init-worker.t @@ -529,6 +529,7 @@ second line received: (?:Date|Server): .*? --- no_error_log [error] --- timeout: 10 +--- skip_eval: 3:$ENV{TEST_NGINX_USE_HTTP3} diff --git a/t/129-ssl-socket.t b/t/129-ssl-socket.t index f89a538fd0..329e7145d6 100644 --- a/t/129-ssl-socket.t +++ b/t/129-ssl-socket.t @@ -14,6 +14,12 @@ $ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; $ENV{TEST_NGINX_SERVER_SSL_PORT} ||= 12345; $ENV{TEST_NGINX_CERT_DIR} ||= dirname(realpath(abs_path(__FILE__))); +my $NginxBinary = $ENV{'TEST_NGINX_BINARY'} || 'nginx'; +my $openssl_version = eval { `$NginxBinary -V 2>&1` }; +if ($openssl_version =~ m/BoringSSL/) { + $ENV{TEST_NGINX_USE_BORINGSSL} = 1; +} + #log_level 'warn'; log_level 'debug'; @@ -2568,8 +2574,8 @@ qr/\[error\] .* ngx.socket sslhandshake: expecting 1 ~ 5 arguments \(including t --- no_error_log [alert] --- timeout: 10 ---- curl_error -curl: (52) Empty reply from server +--- curl_error eval +qr#curl: \(52\) Empty reply from server|curl: \(95\) HTTP/3 stream 0 reset by server# @@ -2667,6 +2673,7 @@ SSL reused session === TEST 33: explicit cipher configuration - TLSv1.3 --- skip_openssl: 8: < 1.1.1 --- skip_nginx: 8: < 1.19.4 +--- skip_eval: 8:$ENV{TEST_NGINX_USE_BORINGSSL} --- http_config server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; @@ -2760,6 +2767,7 @@ SSL reused session === TEST 34: explicit cipher configuration not in the default list - TLSv1.3 --- skip_openssl: 8: < 1.1.1 --- skip_nginx: 8: < 1.19.4 +--- skip_eval: 8:$ENV{TEST_NGINX_USE_BORINGSSL} --- http_config server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; diff --git a/t/139-ssl-cert-by.t b/t/139-ssl-cert-by.t index 2180466907..3fd6413307 100644 --- a/t/139-ssl-cert-by.t +++ b/t/139-ssl-cert-by.t @@ -579,7 +579,7 @@ failed to do SSL handshake: handshake failed --- error_log eval [ 'lua_certificate_by_lua: handler return value: -1, cert cb exit code: 0', -qr/\[info\] .*? SSL_do_handshake\(\) failed .*?cert cb error/, +qr/(\[info\] .*? SSL_do_handshake\(\) failed .*?cert cb error|routines:OPENSSL_internal:CERT_CB_ERROR)/, 'lua exit with code -1', ] @@ -720,7 +720,7 @@ failed to do SSL handshake: handshake failed --- error_log eval [ 'lua_certificate_by_lua: cert cb exit code: 0', -qr/\[info\] .*? SSL_do_handshake\(\) failed .*?cert cb error/, +qr/(\[info\] .*? SSL_do_handshake\(\) failed .*?cert cb error|routines:OPENSSL_internal:CERT_CB_ERROR)/, 'lua exit with code -1', ] @@ -791,7 +791,7 @@ failed to do SSL handshake: handshake failed [ 'runtime error: ssl_certificate_by_lua(nginx.conf:28):2: bad bad bad', 'lua_certificate_by_lua: handler return value: 500, cert cb exit code: 0', -qr/\[info\] .*? SSL_do_handshake\(\) failed .*?cert cb error/, +qr/(\[info\] .*? SSL_do_handshake\(\) failed .*?cert cb error|routines:OPENSSL_internal:CERT_CB_ERROR)/, qr/context: ssl_certificate_by_lua\*, client: \d+\.\d+\.\d+\.\d+, server: \d+\.\d+\.\d+\.\d+:\d+/, ] @@ -863,7 +863,7 @@ failed to do SSL handshake: handshake failed [ 'runtime error: ssl_certificate_by_lua(nginx.conf:28):3: bad bad bad', 'lua_certificate_by_lua: cert cb exit code: 0', -qr/\[info\] .*? SSL_do_handshake\(\) failed .*?cert cb error/, +qr/(\[info\] .*? SSL_do_handshake\(\) failed .*?cert cb error|routines:OPENSSL_internal:CERT_CB_ERROR)/, ] --- no_error_log @@ -1051,7 +1051,7 @@ failed to do SSL handshake: handshake failed [ 'lua ssl server name: "test.com"', 'ssl_certificate_by_lua(nginx.conf:28):1: API disabled in the context of ssl_certificate_by_lua*', -qr/\[info\] .*?cert cb error/, +qr/(\[info\] .*? SSL_do_handshake\(\) failed .*?cert cb error|routines:OPENSSL_internal:CERT_CB_ERROR)/, ] --- no_error_log diff --git a/t/142-ssl-session-store.t b/t/142-ssl-session-store.t index ead2a167e5..11deb83207 100644 --- a/t/142-ssl-session-store.t +++ b/t/142-ssl-session-store.t @@ -975,3 +975,4 @@ qr/ssl_session_store_by_lua\*: skipped since TLS version >= 1\.3 \(\d+\)/ [error] [alert] [emerg] +--- skip_eval: 6:$ENV{TEST_NGINX_USE_HTTP3} diff --git a/t/143-ssl-session-fetch.t b/t/143-ssl-session-fetch.t index 74f2e6e1bb..2f988ded9c 100644 --- a/t/143-ssl-session-fetch.t +++ b/t/143-ssl-session-fetch.t @@ -957,6 +957,21 @@ close: 1 nil qr/ssl ((fetch|store) session|cert) by lua is running!/s --- grep_error_log_out eval +if ($ENV{TEST_NGINX_USE_HTTP3}) { +[ +'ssl cert by lua is running! +ssl store session by lua is running! +', +'ssl cert by lua is running! +ssl fetch session by lua is running! +ssl store session by lua is running! +', +'ssl cert by lua is running! +ssl fetch session by lua is running! +ssl store session by lua is running! +', +] +} else { [ 'ssl cert by lua is running! ssl store session by lua is running! @@ -970,6 +985,7 @@ ssl cert by lua is running! ssl store session by lua is running! ', ] +} --- no_error_log [error] @@ -1397,6 +1413,7 @@ ssl_session_fetch_by_lua\(nginx\.conf:\d+\):1: ssl_session_fetch_by_lua\* is run [error] [alert] [emerg] +--- skip_eval: 6:$ENV{TEST_NGINX_USE_HTTP3} diff --git a/t/163-signal.t b/t/163-signal.t index ec3a418d90..15f41e2200 100644 --- a/t/163-signal.t +++ b/t/163-signal.t @@ -39,7 +39,7 @@ qr/\[notice\] \d+#\d+: exit$/ --- no_error_log eval qr/\[notice\] \d+#\d+: reconfiguring/ --- curl_error eval -qr/curl: \(28\) Operation timed out after \d+ milliseconds with 0 bytes received|curl: \(56\) Recv failure: Connection reset by peer/ +qr/curl: \(28\) Operation timed out after \d+ milliseconds with 0 bytes received|curl: \(56\) Recv failure: Connection reset by peer|curl: \(55\) sendmsg\(\) returned -1 \(errno 111\)/ diff --git a/t/166-ssl-client-hello.t b/t/166-ssl-client-hello.t index 102cd2e303..a9d8ac8d2a 100644 --- a/t/166-ssl-client-hello.t +++ b/t/166-ssl-client-hello.t @@ -10,6 +10,8 @@ my $openssl_version = eval { `$NginxBinary -V 2>&1` }; if ($openssl_version =~ m/built with OpenSSL (0\S*|1\.0\S*|1\.1\.0\S*)/) { plan(skip_all => "too old OpenSSL, need 1.1.1, was $1"); +} elsif ($openssl_version =~ m/running with BoringSSL/) { + plan(skip_all => "does not support BoringSSL"); } else { plan tests => repeat_each() * (blocks() * 6 + 8); } diff --git a/t/166-worker-thread.t b/t/166-worker-thread.t index 15e9d762eb..925a060949 100644 --- a/t/166-worker-thread.t +++ b/t/166-worker-thread.t @@ -1199,6 +1199,8 @@ true,nil === TEST 38: shdict get_stale +For http3: curl: (55) ngtcp2_conn_handle_expiry returned error: ERR_IDLE_CLOSE +--- skip_eval: 2:$ENV{TEST_NGINX_USE_HTTP3} --- main_config thread_pool testpool threads=100; --- http_config eval diff --git a/t/167-server-rewrite.t b/t/167-server-rewrite.t index 152c5ce35d..6aea288ef8 100644 --- a/t/167-server-rewrite.t +++ b/t/167-server-rewrite.t @@ -79,7 +79,8 @@ server_rewrite_by_lua_block in server } --- request GET /lua ---- raw_response_headers_like: Location: /foo\r\n +--- raw_response_headers_like eval +qr{[Ll]ocation: /foo\r\n} --- response_body_like: 302 Found --- error_code: 302 --- no_error_log @@ -198,6 +199,7 @@ delete thread 1 --- ignore_response --- no_error_log [error] +--- skip_eval: 2:$ENV{TEST_NGINX_USE_HTTP3} diff --git a/t/186-cosocket-busy-bufs.t b/t/186-cosocket-busy-bufs.t index e50f62d9ee..7439443761 100644 --- a/t/186-cosocket-busy-bufs.t +++ b/t/186-cosocket-busy-bufs.t @@ -1,10 +1,20 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use Test::Nginx::Socket 'no_plan'; + +use Test::Nginx::Socket; use Test::Nginx::Socket::Lua::Stream; log_level('warn'); repeat_each(2); + +if (defined $ENV{TEST_NGINX_USE_HTTP3}) { + plan(skip_all => "HTTP3 does not support client abort"); +} elsif (defined $ENV{TEST_NGINX_USE_HTTP2}) { + plan(skip_all => "HTTP2 does not support client abort"); +} else { + plan tests => repeat_each() * (blocks() * 2); +} + run_tests(); __DATA__ diff --git a/t/187-ssl-two-verification.t b/t/187-ssl-two-verification.t index 527df7cbde..312847252c 100644 --- a/t/187-ssl-two-verification.t +++ b/t/187-ssl-two-verification.t @@ -10,6 +10,8 @@ my $openssl_version = eval { `$NginxBinary -V 2>&1` }; if ($openssl_version =~ m/built with OpenSSL (0\S*|1\.0\S*|1\.1\.0\S*)/) { plan(skip_all => "too old OpenSSL, need 1.1.1, was $1"); +} elsif ($openssl_version =~ m/running with BoringSSL/) { + plan(skip_all => "does not support BoringSSL"); } else { plan tests => repeat_each() * (blocks() * 7); } From 0c3675ff4d5ecbfdcdeeb661a4bf0f5a8e10e51c Mon Sep 17 00:00:00 2001 From: lijunlong Date: Tue, 21 Nov 2023 22:55:32 +0800 Subject: [PATCH 132/254] tests: adjust some test cases for HTTP3. --- t/102-req-start-time.t | 4 ++-- t/129-ssl-socket.t | 11 ++++++++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/t/102-req-start-time.t b/t/102-req-start-time.t index 3b041afda7..d54b19941d 100644 --- a/t/102-req-start-time.t +++ b/t/102-req-start-time.t @@ -59,7 +59,7 @@ GET /start --- request GET /req_time --- response_body_like chop -^(?:0\.[12]|0\.099)\d* +^(?:0\.[12]|0\.099|0\.098)\d* true$ --- no_error_log [error] @@ -88,7 +88,7 @@ true$ --- request GET /req_time --- response_body_like chomp -^(?:0\.[12]|0\.099)\d* +^(?:0\.[12]|0\.099|0\.098)\d* 0\.\d+ true$ --- no_error_log diff --git a/t/129-ssl-socket.t b/t/129-ssl-socket.t index 329e7145d6..3aea20bc08 100644 --- a/t/129-ssl-socket.t +++ b/t/129-ssl-socket.t @@ -1,6 +1,15 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use Test::Nginx::Socket::Lua; +our $SkipReason; +BEGIN { + if (defined $ENV{TEST_NGINX_USE_HTTP3}) { + # FIXME: we still need to enable this test file for HTTP3. + $SkipReason = "the test cases are very unstable, skip for now."; + } +} + +use Test::Nginx::Socket::Lua $SkipReason ? (skip_all => $SkipReason) : (); + use Cwd qw(abs_path realpath); use File::Basename; From 75ab35d3c49df4f63310609ac9817c510b81583c Mon Sep 17 00:00:00 2001 From: oowl Date: Tue, 21 Nov 2023 22:56:32 +0800 Subject: [PATCH 133/254] doc: add http2 and http3 limitation doc comment for ngx.req.socket API. --- README.markdown | 2 ++ doc/HttpLuaModule.wiki | 2 ++ 2 files changed, 4 insertions(+) diff --git a/README.markdown b/README.markdown index dce83887fa..d6ec8c94be 100644 --- a/README.markdown +++ b/README.markdown @@ -5643,6 +5643,8 @@ Returns a read-only cosocket object that wraps the downstream connection. Only [ In case of error, `nil` will be returned as well as a string describing the error. +Due to the streaming nature of HTTP2 and HTTP3, this API cannot be used when the downstream connection is HTTP2 and HTTP3. + The socket object returned by this method is usually used to read the current request's body in a streaming fashion. Do not turn on the [lua_need_request_body](#lua_need_request_body) directive, and do not mix this call with [ngx.req.read_body](#ngxreqread_body) and [ngx.req.discard_body](#ngxreqdiscard_body). If any request body data has been pre-read into the Nginx core request header buffer, the resulting cosocket object will take care of this to avoid potential data loss resulting from such pre-reading. diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 551f804992..305626c767 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -4741,6 +4741,8 @@ Returns a read-only cosocket object that wraps the downstream connection. Only [ In case of error, nil will be returned as well as a string describing the error. +Due to the streaming nature of HTTP2 and HTTP3, this API cannot be used when the downstream connection is HTTP2 and HTTP3. + The socket object returned by this method is usually used to read the current request's body in a streaming fashion. Do not turn on the [[#lua_need_request_body|lua_need_request_body]] directive, and do not mix this call with [[#ngx.req.read_body|ngx.req.read_body]] and [[#ngx.req.discard_body|ngx.req.discard_body]]. If any request body data has been pre-read into the Nginx core request header buffer, the resulting cosocket object will take care of this to avoid potential data loss resulting from such pre-reading. From 2d32c7c8d6d7270163201f0790489451675ec259 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Thu, 23 Nov 2023 21:58:23 +0800 Subject: [PATCH 134/254] bumped version of lua-nginx-module to 10026. --- src/api/ngx_http_lua_api.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/ngx_http_lua_api.h b/src/api/ngx_http_lua_api.h index 640e0c396b..193c44e3a8 100644 --- a/src/api/ngx_http_lua_api.h +++ b/src/api/ngx_http_lua_api.h @@ -19,7 +19,7 @@ /* Public API for other Nginx modules */ -#define ngx_http_lua_version 10025 +#define ngx_http_lua_version 10026 typedef struct ngx_http_lua_co_ctx_s ngx_http_lua_co_ctx_t; From ff96d75a49dd4bc9f3009332973f2b2cfc6326a3 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Tue, 28 Nov 2023 10:16:27 +0800 Subject: [PATCH 135/254] tests: update openssl to 1.1.1w. --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 60e1a053d9..d6742ed52b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -62,11 +62,11 @@ env: - MALLOC_PERTURB_=9 jobs: #- NGINX_VERSION=1.21.4 OPENSSL_VER=1.1.0l OPENSSL_PATCH_VER=1.1.0d - - NGINX_VERSION=1.21.4 OPENSSL_VER=1.1.1s OPENSSL_PATCH_VER=1.1.1f #- NGINX_VERSION=1.25.1 OPENSSL_VER=1.1.0l OPENSSL_PATCH_VER=1.1.0d - - NGINX_VERSION=1.25.1 OPENSSL_VER=1.1.1s OPENSSL_PATCH_VER=1.1.1f USE_PCRE2=Y + - NGINX_VERSION=1.21.4 OPENSSL_VER=1.1.1w OPENSSL_PATCH_VER=1.1.1f + - NGINX_VERSION=1.25.1 OPENSSL_VER=1.1.1w OPENSSL_PATCH_VER=1.1.1f USE_PCRE2=Y - NGINX_VERSION=1.25.1 BORINGSSL=1 TEST_NGINX_USE_HTTP3=1 USE_PCRE2=Y - #- NGINX_VERSION=1.25.1 OPENSSL_VER=1.1.1s TEST_NGINX_USE_HTTP2=1 + #- NGINX_VERSION=1.25.1 OPENSSL_VER=1.1.1w TEST_NGINX_USE_HTTP2=1 services: - memcached From 0d054a57f453d822a4800bf42cc1161adebe8e30 Mon Sep 17 00:00:00 2001 From: Johnny Wang Date: Wed, 20 Dec 2023 10:43:40 +0800 Subject: [PATCH 136/254] tests: t/128-duplex-tcp-socket: replacing constant port 7658 with a random port. (#2268) --- t/058-tcp-socket.t | 7 +++++-- t/128-duplex-tcp-socket.t | 8 ++++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/t/058-tcp-socket.t b/t/058-tcp-socket.t index b5cf58ec5b..ef2b05f0d0 100644 --- a/t/058-tcp-socket.t +++ b/t/058-tcp-socket.t @@ -3998,10 +3998,13 @@ lua tcp socket read any --- config server_tokens off; location = /t { + set $port $TEST_NGINX_RAND_PORT_1; + content_by_lua_block { local sock = ngx.socket.tcp() + local port = ngx.var.port sock:settimeout(500) - assert(sock:connect("127.0.0.1", 7658)) + assert(sock:connect("127.0.0.1", port)) while true do local data, err = sock:receiveany(1024) @@ -4028,7 +4031,7 @@ lua tcp socket read any --- request GET /t ---- tcp_listen: 7658 +--- tcp_listen: $TEST_NGINX_RAND_PORT_1 --- tcp_shutdown: 1 --- tcp_query eval: "send data after read side closed" --- tcp_query_len: 32 diff --git a/t/128-duplex-tcp-socket.t b/t/128-duplex-tcp-socket.t index 22b9f036dd..511cc20bfc 100644 --- a/t/128-duplex-tcp-socket.t +++ b/t/128-duplex-tcp-socket.t @@ -193,7 +193,7 @@ close: 1 nil$ lua_socket_log_errors off; location /t { #set $port 5000; - set $port 7658; + set $port $TEST_NGINX_RAND_PORT_1; content_by_lua ' local sock = ngx.socket.tcp() @@ -258,7 +258,7 @@ received: OK! close: (?:nil socket busy writing|1 nil failed to send request: closed)$ ---- tcp_listen: 7658 +--- tcp_listen: $TEST_NGINX_RAND_PORT_1 --- tcp_shutdown: 0 --- tcp_reply: OK! --- tcp_no_close: 1 @@ -273,7 +273,7 @@ failed to send request: closed)$ lua_socket_log_errors off; location /t { #set $port 5000; - set $port 7658; + set $port $TEST_NGINX_RAND_PORT_1; content_by_lua ' local sock = ngx.socket.tcp() @@ -349,7 +349,7 @@ F(ngx_http_lua_socket_tcp_finalize_write_part) { print_ubacktrace() } --- stap_out2 ---- tcp_listen: 7658 +--- tcp_listen: $TEST_NGINX_RAND_PORT_1 --- tcp_shutdown: 1 --- tcp_query eval: "flush_all\r\n" --- tcp_query_len: 11 From 8c7f9bf46a43ecf378c446b0fd2c06bc8c848f57 Mon Sep 17 00:00:00 2001 From: Johnny Wang Date: Wed, 20 Dec 2023 10:44:07 +0800 Subject: [PATCH 137/254] tests: t/129-ssl-socket.t: use the same IP to ensure that the ssl session can be reused. (#2267) --- t/129-ssl-socket.t | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/t/129-ssl-socket.t b/t/129-ssl-socket.t index 3aea20bc08..cc3f243c07 100644 --- a/t/129-ssl-socket.t +++ b/t/129-ssl-socket.t @@ -15,6 +15,8 @@ use File::Basename; repeat_each(2); +sub resolve($$); + plan tests => repeat_each() * (blocks() * 7 - 3); $ENV{TEST_NGINX_HTML_DIR} ||= html_dir(); @@ -22,6 +24,7 @@ $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; $ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; $ENV{TEST_NGINX_SERVER_SSL_PORT} ||= 12345; $ENV{TEST_NGINX_CERT_DIR} ||= dirname(realpath(abs_path(__FILE__))); +$ENV{TEST_NGINX_OPENRESTY_ORG_IP} ||= resolve("openresty.org", $ENV{TEST_NGINX_RESOLVER}); my $NginxBinary = $ENV{'TEST_NGINX_BINARY'} || 'nginx'; my $openssl_version = eval { `$NginxBinary -V 2>&1` }; @@ -44,6 +47,19 @@ sub read_file { $cert; } +sub resolve ($$) { + my ($domain, $resolver) = @_; + my $ips = qx/dig \@$resolver +short $domain/; + + my $exit_code = $? >> 8; + if (!$ips || $exit_code != 0) { + die "failed to resolve '$domain' using '$resolver' as resolver"; + } + + my ($ip) = split /\n/, $ips; + return $ip; +} + our $DSTRootCertificate = read_file("t/cert/dst-ca.crt"); our $EquifaxRootCertificate = read_file("t/cert/equifax.crt"); our $TestCertificate = read_file("t/cert/test.crt"); @@ -1397,6 +1413,7 @@ SSL reused session location /t { #set $port 5000; set $port $TEST_NGINX_MEMCACHED_PORT; + set $openresty_org_ip $TEST_NGINX_OPENRESTY_ORG_IP; content_by_lua ' local sock = ngx.socket.tcp() @@ -1406,7 +1423,8 @@ SSL reused session local session for i = 1, 3 do - local ok, err = sock:connect("openresty.org", 443) + -- Use the same IP to ensure that the connection can be reused + local ok, err = sock:connect(ngx.var.openresty_org_ip, 443) if not ok then ngx.say("failed to connect: ", err) return @@ -1473,6 +1491,7 @@ SSL reused session lua_ssl_verify_depth 2; location /t { #set $port 5000; + set $openresty_org_ip $TEST_NGINX_OPENRESTY_ORG_IP; set $port $TEST_NGINX_MEMCACHED_PORT; content_by_lua ' @@ -1482,7 +1501,8 @@ SSL reused session do for i = 1, 3 do - local ok, err = sock:connect("openresty.org", 443) + -- Use the same IP to ensure that the connection can be reused + local ok, err = sock:connect(ngx.var.openresty_org_ip, 443) if not ok then ngx.say("failed to connect: ", err) return From f249fa9b7ed877e7ae88bcc1f1074bc8b26cc97b Mon Sep 17 00:00:00 2001 From: Johnny Wang Date: Wed, 20 Dec 2023 10:46:17 +0800 Subject: [PATCH 138/254] bugfix: fixed memory leak in the case of connection in dubious. (#2270) Can be reproduced in valgrind mode in t/129-ssl-socket.t: ==55579== 13 bytes in 1 blocks are definitely lost in loss record 3 of 19 ==55579== at 0x483A809: malloc (vg_replace_malloc.c:307) ==55579== by 0x44F522: ngx_alloc (ngx_alloc.c:22) ==55579== by 0x549DDD: ngx_http_lua_ffi_socket_tcp_sslhandshake (ngx_http_lua_socket_tcp.c:1828) ==55579== by 0x4897FEA: lj_vm_ffi_call (in /opt/luajit21/lib/libluajit-5.1.so.2.1.1700206165) ==55579== by 0x48F7980: lj_ccall_func (lj_ccall.c:1402) ==55579== by 0x4910E74: lj_cf_ffi_meta___call (lib_ffi.c:230) ==55579== by 0x4895B7D: lj_BC_FUNCC (in /opt/luajit21/lib/libluajit-5.1.so.2.1.1700206165) ==55579== by 0x5360E6: ngx_http_lua_run_thread (ngx_http_lua_util.c:1184) ==55579== by 0x54203E: ngx_http_lua_socket_tcp_resume_helper (ngx_http_lua_socket_tcp.c:6207) ==55579== by 0x542123: ngx_http_lua_socket_tcp_conn_resume (ngx_http_lua_socket_tcp.c:6113) ==55579== by 0x5393B1: ngx_http_lua_content_wev_handler (ngx_http_lua_contentby.c:152) ==55579== by 0x54014B: ngx_http_lua_socket_handle_conn_success (ngx_http_lua_socket_tcp.c:3638) ==55579== by 0x54504E: ngx_http_lua_socket_connected_handler (ngx_http_lua_socket_tcp.c:3906) ==55579== by 0x5405A7: ngx_http_lua_socket_tcp_handler (ngx_http_lua_socket_tcp.c:3426) ==55579== by 0x4567C0: ngx_epoll_process_events (ngx_epoll_module.c:930) ==55579== by 0x44AAB3: ngx_process_events_and_timers (ngx_event.c:258) ==55579== by 0x454623: ngx_worker_process_cycle (ngx_process_cycle.c:793) ==55579== by 0x45295B: ngx_spawn_process (ngx_process.c:199) ==55579== by 0x45340E: ngx_start_worker_processes (ngx_process_cycle.c:382) ==55579== by 0x4551F1: ngx_master_process_cycle (ngx_process_cycle.c:241) ==55579== by 0x429DD6: main (nginx.c:387) --- src/ngx_http_lua_socket_tcp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 505614c47f..230679fa7d 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -5601,6 +5601,7 @@ ngx_http_lua_socket_tcp_setkeepalive(lua_State *L) if (c->read->ready) { rc = ngx_http_lua_socket_keepalive_close_handler(c->read); if (rc != NGX_OK) { + ngx_http_lua_socket_tcp_finalize(r, u); lua_pushnil(L); lua_pushliteral(L, "connection in dubious state"); return 2; From e8da8781c9a014d2eac3425f63516cd3f2a0047a Mon Sep 17 00:00:00 2001 From: lynch Date: Fri, 22 Dec 2023 11:44:55 +0800 Subject: [PATCH 139/254] optimize: Make the use of NGX_PCRE2 clearer. --- src/ngx_http_lua_common.h | 27 ++++++++++++++++----------- src/ngx_http_lua_pcrefix.c | 4 ++-- src/ngx_http_lua_pcrefix.h | 2 +- src/ngx_http_lua_regex.c | 6 +++--- 4 files changed, 22 insertions(+), 17 deletions(-) diff --git a/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h index 4bbfd8c780..4c946297f6 100644 --- a/src/ngx_http_lua_common.h +++ b/src/ngx_http_lua_common.h @@ -54,17 +54,19 @@ typedef struct { #endif -#if defined(NGX_PCRE) && !defined(NGX_PCRE2) -#include -# if (PCRE_MAJOR > 8) || (PCRE_MAJOR == 8 && PCRE_MINOR >= 21) +#if (NGX_PCRE) +# if (NGX_PCRE2) # define LUA_HAVE_PCRE_JIT 1 # else -# define LUA_HAVE_PCRE_JIT 0 -# endif -#endif -#if (NGX_PCRE2) -# define LUA_HAVE_PCRE_JIT 1 +#include + +# if (PCRE_MAJOR > 8) || (PCRE_MAJOR == 8 && PCRE_MINOR >= 21) +# define LUA_HAVE_PCRE_JIT 1 +# else +# define LUA_HAVE_PCRE_JIT 0 +# endif +# endif #endif @@ -221,15 +223,18 @@ struct ngx_http_lua_main_conf_s { ngx_hash_t builtin_headers_out; -#if (NGX_PCRE || NGX_PCRE2) +#if (NGX_PCRE) ngx_int_t regex_cache_entries; ngx_int_t regex_cache_max_entries; ngx_int_t regex_match_limit; +#endif + +#if (LUA_HAVE_PCRE_JIT) #if (NGX_PCRE2) pcre2_jit_stack *jit_stack; -#elif (LUA_HAVE_PCRE_JIT) +#else pcre_jit_stack *jit_stack; -# endif +#endif #endif ngx_array_t *shm_zones; /* of ngx_shm_zone_t* */ diff --git a/src/ngx_http_lua_pcrefix.c b/src/ngx_http_lua_pcrefix.c index 76e745e6db..5693b5495c 100644 --- a/src/ngx_http_lua_pcrefix.c +++ b/src/ngx_http_lua_pcrefix.c @@ -14,7 +14,7 @@ #include "ngx_http_lua_pcrefix.h" #include "stdio.h" -#if (NGX_PCRE || NGX_PCRE2) +#if (NGX_PCRE) static ngx_pool_t *ngx_http_lua_pcre_pool = NULL; @@ -183,6 +183,6 @@ ngx_http_lua_pcre_malloc_done(ngx_pool_t *old_pool) } #endif -#endif /* NGX_PCRE || NGX_PCRE2 */ +#endif /* NGX_PCRE */ /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_pcrefix.h b/src/ngx_http_lua_pcrefix.h index ef09636313..e1097b72eb 100644 --- a/src/ngx_http_lua_pcrefix.h +++ b/src/ngx_http_lua_pcrefix.h @@ -12,7 +12,7 @@ #include "ngx_http_lua_common.h" -#if (NGX_PCRE || NGX_PCRE2) +#if (NGX_PCRE) ngx_pool_t *ngx_http_lua_pcre_malloc_init(ngx_pool_t *pool); void ngx_http_lua_pcre_malloc_done(ngx_pool_t *old_pool); diff --git a/src/ngx_http_lua_regex.c b/src/ngx_http_lua_regex.c index 7317451f65..1b52fa233d 100644 --- a/src/ngx_http_lua_regex.c +++ b/src/ngx_http_lua_regex.c @@ -9,7 +9,7 @@ #endif #include "ddebug.h" -#if (NGX_PCRE || NGX_PCRE2) +#if (NGX_PCRE) #include "ngx_http_lua_pcrefix.h" #include "ngx_http_lua_script.h" @@ -325,7 +325,7 @@ ngx_int_t ngx_http_lua_ffi_set_jit_stack_size(int size, u_char *errstr, size_t *errstr_size) { -#if (NGX_PCRE2 || LUA_HAVE_PCRE_JIT) +#if (LUA_HAVE_PCRE_JIT) ngx_http_lua_main_conf_t *lmcf; ngx_pool_t *pool, *old_pool; @@ -977,7 +977,7 @@ ngx_http_lua_ffi_pcre_version(void) } -#endif /* NGX_PCRE || NGX_PCRE2 */ +#endif /* NGX_PCRE */ /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ From bf5d9d3b5c2801034e15e579704d4ef8f2cd6d38 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Fri, 22 Dec 2023 17:03:25 +0800 Subject: [PATCH 140/254] change: don't move the expired item to the lru queue head when lookup. --- src/ngx_http_lua_shdict.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ngx_http_lua_shdict.c b/src/ngx_http_lua_shdict.c index 31bdcdb6a5..c63eb3c107 100644 --- a/src/ngx_http_lua_shdict.c +++ b/src/ngx_http_lua_shdict.c @@ -198,9 +198,6 @@ ngx_http_lua_shdict_lookup(ngx_shm_zone_t *shm_zone, ngx_uint_t hash, rc = ngx_memn2cmp(kdata, sd->data, klen, (size_t) sd->key_len); if (rc == 0) { - ngx_queue_remove(&sd->queue); - ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); - *sdp = sd; dd("node expires: %lld", (long long) sd->expires); @@ -219,6 +216,9 @@ ngx_http_lua_shdict_lookup(ngx_shm_zone_t *shm_zone, ngx_uint_t hash, } } + ngx_queue_remove(&sd->queue); + ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); + return NGX_OK; } From 766b7a8add2327bef6bc3b5af15b111161745586 Mon Sep 17 00:00:00 2001 From: Johnny Wang Date: Mon, 25 Dec 2023 11:19:39 +0800 Subject: [PATCH 141/254] tests: use random ports instead of constant ports to prevent conflicts during testing. (#2274) --- t/014-bugs.t | 4 +-- t/020-subrequest.t | 56 ++++++++++++++++++++-------------------- t/045-ngx-var.t | 12 ++++----- t/093-uthread-spawn.t | 4 +-- t/106-timer.t | 4 +-- t/124-init-worker.t | 4 +-- t/129-ssl-socket.t | 4 +-- t/139-ssl-cert-by.t | 4 +-- t/163-exit-worker-hup.t | 4 +-- t/166-ssl-client-hello.t | 8 +++--- 10 files changed, 51 insertions(+), 53 deletions(-) diff --git a/t/014-bugs.t b/t/014-bugs.t index ff85ca3558..1b79aa4c59 100644 --- a/t/014-bugs.t +++ b/t/014-bugs.t @@ -893,7 +893,7 @@ GET /t --- http_config eval "lua_package_path '$::HtmlDir/?.lua;./?.lua;;'; server { - listen 12354; + listen \$TEST_NGINX_RAND_PORT_1; location = /t { echo 'args: \$args'; @@ -903,7 +903,7 @@ GET /t --- config location = /t { set $args "foo=1&bar=2"; - proxy_pass http://127.0.0.1:12354; + proxy_pass http://127.0.0.1:$TEST_NGINX_RAND_PORT_1; } --- request diff --git a/t/020-subrequest.t b/t/020-subrequest.t index d8aa34d7e8..c731f1e61c 100644 --- a/t/020-subrequest.t +++ b/t/020-subrequest.t @@ -1240,7 +1240,7 @@ qr{(\Qcurl: (52) Empty reply from server\E|\Qcurl: (95) HTTP/3 stream 0 reset by set $memc_key 'foo'; #set $memc_exptime 300; - memc_pass 127.0.0.1:19112; #$TEST_NGINX_MEMCACHED_PORT; + memc_pass 127.0.0.1:$TEST_NGINX_RAND_PORT_1; #$TEST_NGINX_MEMCACHED_PORT; } location /main { @@ -1253,7 +1253,7 @@ qr{(\Qcurl: (52) Empty reply from server\E|\Qcurl: (95) HTTP/3 stream 0 reset by } --- request GET /main ---- tcp_listen: 19112 +--- tcp_listen: $TEST_NGINX_RAND_PORT_1 --- tcp_query_len: 9 --- tcp_reply eval "VALUE foo 0 1024\r\nhello world" @@ -1310,7 +1310,7 @@ upstream prematurely closed connection set $memc_key 'foo'; #set $memc_exptime 300; - memc_pass 127.0.0.1:19112; #$TEST_NGINX_MEMCACHED_PORT; + memc_pass 127.0.0.1:$TEST_NGINX_RAND_PORT_1; #$TEST_NGINX_MEMCACHED_PORT; } location /main { @@ -1323,7 +1323,7 @@ upstream prematurely closed connection } --- request GET /main ---- tcp_listen: 19112 +--- tcp_listen: $TEST_NGINX_RAND_PORT_1 --- tcp_no_close --- tcp_reply eval "VALUE foo 0 1024\r\nhello world" @@ -1383,7 +1383,7 @@ upstream timed out #proxy_read_timeout 100ms; proxy_buffering on; - proxy_pass http://127.0.0.1:19113; + proxy_pass http://127.0.0.1:$TEST_NGINX_RAND_PORT_2; } location /main { @@ -1396,7 +1396,7 @@ upstream timed out } --- request GET /main ---- tcp_listen: 19113 +--- tcp_listen: $TEST_NGINX_RAND_PORT_2 --- tcp_query_len: 65 --- tcp_reply eval "HTTP/1.0 200 OK\r\nContent-Length: 1024\r\n\r\nhello world" @@ -1443,7 +1443,7 @@ upstream prematurely closed connection proxy_read_timeout 100ms; proxy_buffering on; - proxy_pass http://127.0.0.1:19113; + proxy_pass http://127.0.0.1:$TEST_NGINX_RAND_PORT_2; } location /main { @@ -1456,7 +1456,7 @@ upstream prematurely closed connection } --- request GET /main ---- tcp_listen: 19113 +--- tcp_listen: $TEST_NGINX_RAND_PORT_2 --- tcp_no_close --- tcp_reply eval "HTTP/1.0 200 OK\r\nContent-Length: 1024\r\n\r\nhello world" @@ -1505,7 +1505,7 @@ upstream timed out #proxy_read_timeout 100ms; proxy_buffering on; - proxy_pass http://127.0.0.1:19113; + proxy_pass http://127.0.0.1:$TEST_NGINX_RAND_PORT_2; } location /main { @@ -1518,7 +1518,7 @@ upstream timed out } --- request GET /main ---- tcp_listen: 19113 +--- tcp_listen: $TEST_NGINX_RAND_PORT_2 --- tcp_query_len: 65 --- tcp_reply eval "HTTP/1.0 200 OK\r\n\r\nhello world" @@ -1565,7 +1565,7 @@ truncated: false proxy_read_timeout 100ms; proxy_buffering on; - proxy_pass http://127.0.0.1:19113; + proxy_pass http://127.0.0.1:$TEST_NGINX_RAND_PORT_2; } location /main { @@ -1578,7 +1578,7 @@ truncated: false } --- request GET /main ---- tcp_listen: 19113 +--- tcp_listen: $TEST_NGINX_RAND_PORT_2 --- tcp_no_close --- tcp_reply eval "HTTP/1.0 200 OK\r\n\r\nhello world" @@ -1628,7 +1628,7 @@ upstream timed out #proxy_read_timeout 100ms; proxy_buffering off; - proxy_pass http://127.0.0.1:19113; + proxy_pass http://127.0.0.1:$TEST_NGINX_RAND_PORT_2; } location /main { @@ -1641,7 +1641,7 @@ upstream timed out } --- request GET /main ---- tcp_listen: 19113 +--- tcp_listen: $TEST_NGINX_RAND_PORT_2 --- tcp_query_len: 65 --- tcp_reply eval "HTTP/1.0 200 OK\r\n\r\nhello world" @@ -1688,7 +1688,7 @@ truncated: false proxy_read_timeout 500ms; proxy_buffering off; - proxy_pass http://127.0.0.1:19113; + proxy_pass http://127.0.0.1:$TEST_NGINX_RAND_PORT_2; } location /main { @@ -1701,7 +1701,7 @@ truncated: false } --- request GET /main ---- tcp_listen: 19113 +--- tcp_listen: $TEST_NGINX_RAND_PORT_2 --- tcp_no_close --- tcp_reply eval "HTTP/1.0 200 OK\r\n\r\nhello world" @@ -1914,7 +1914,7 @@ a client request body is buffered to a temporary file #proxy_read_timeout 100ms; proxy_http_version 1.1; proxy_buffering on; - proxy_pass http://127.0.0.1:19113; + proxy_pass http://127.0.0.1:$TEST_NGINX_RAND_PORT_2; } location /main { @@ -1927,7 +1927,7 @@ a client request body is buffered to a temporary file } --- request GET /main ---- tcp_listen: 19113 +--- tcp_listen: $TEST_NGINX_RAND_PORT_2 --- tcp_query_len: 65 --- tcp_reply eval "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\nb\r\nhello world\r" @@ -1977,7 +1977,7 @@ upstream prematurely closed connection #proxy_read_timeout 100ms; proxy_http_version 1.1; proxy_buffering off; - proxy_pass http://127.0.0.1:19113; + proxy_pass http://127.0.0.1:$TEST_NGINX_RAND_PORT_2; } location /main { @@ -1990,7 +1990,7 @@ upstream prematurely closed connection } --- request GET /main ---- tcp_listen: 19113 +--- tcp_listen: $TEST_NGINX_RAND_PORT_2 --- tcp_query_len: 65 --- tcp_reply eval "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\nb\r\nhello world\r" @@ -2038,7 +2038,7 @@ upstream prematurely closed connection proxy_read_timeout 100ms; proxy_buffering on; proxy_http_version 1.1; - proxy_pass http://127.0.0.1:19113; + proxy_pass http://127.0.0.1:$TEST_NGINX_RAND_PORT_2; } location /main { @@ -2051,7 +2051,7 @@ upstream prematurely closed connection } --- request GET /main ---- tcp_listen: 19113 +--- tcp_listen: $TEST_NGINX_RAND_PORT_2 --- tcp_no_close --- tcp_reply eval "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\nb\r\nhello world\r" @@ -2100,7 +2100,7 @@ upstream timed out #proxy_read_timeout 100ms; proxy_buffering on; proxy_http_version 1.1; - proxy_pass http://127.0.0.1:19113; + proxy_pass http://127.0.0.1:$TEST_NGINX_RAND_PORT_2; } location /main { @@ -2113,7 +2113,7 @@ upstream timed out } --- request GET /main ---- tcp_listen: 19113 +--- tcp_listen: $TEST_NGINX_RAND_PORT_2 --- tcp_no_close --- tcp_reply eval "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n5\r\nhello\r\n0\r\n\r\n" @@ -2158,7 +2158,7 @@ truncated: false #proxy_read_timeout 100ms; proxy_buffering off; proxy_http_version 1.1; - proxy_pass http://127.0.0.1:19113; + proxy_pass http://127.0.0.1:$TEST_NGINX_RAND_PORT_2; } location /main { @@ -2171,7 +2171,7 @@ truncated: false } --- request GET /main ---- tcp_listen: 19113 +--- tcp_listen: $TEST_NGINX_RAND_PORT_2 --- tcp_no_close --- tcp_reply eval "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n5\r\nhello\r\n0\r\n\r\n" @@ -2217,7 +2217,7 @@ truncated: false #proxy_read_timeout 100ms; proxy_buffering off; - proxy_pass http://127.0.0.1:19113; + proxy_pass http://127.0.0.1:$TEST_NGINX_RAND_PORT_2; } location /main { @@ -2230,7 +2230,7 @@ truncated: false } --- request GET /main ---- tcp_listen: 19113 +--- tcp_listen: $TEST_NGINX_RAND_PORT_2 --- tcp_query_len: 65 --- tcp_reply eval "HTTP/1.0 200 OK\r\nContent-Length: 1024\r\n\r\nhello world" diff --git a/t/045-ngx-var.t b/t/045-ngx-var.t index f0f9f415c6..6fe5590d99 100644 --- a/t/045-ngx-var.t +++ b/t/045-ngx-var.t @@ -260,19 +260,19 @@ variable "query_string" not changeable } server { # this is the real entry point - listen 8091; + listen $TEST_NGINX_RAND_PORT_1; location / { content_by_lua_block{ - ngx.print("this is backend peer 8091") + ngx.print("this is backend peer $TEST_NGINX_RAND_PORT_1") } } } server { # this is the real entry point - listen 8092; + listen $TEST_NGINX_RAND_PORT_2; location / { content_by_lua_block{ - ngx.print("this is backend peer 8092") + ngx.print("this is backend peer $TEST_NGINX_RAND_PORT_2") } } } @@ -287,6 +287,6 @@ variable "query_string" not changeable proxy_pass http://balancer; } --- pipelined_requests eval -["GET /balancer?port=8091", "GET /balancer?port=8092"] +["GET /balancer?port=\$TEST_NGINX_RAND_PORT_1", "GET /balancer?port=\$TEST_NGINX_RAND_PORT_2"] --- response_body eval -["this is backend peer 8091", "this is backend peer 8092"] +["this is backend peer \$TEST_NGINX_RAND_PORT_1", "this is backend peer \$TEST_NGINX_RAND_PORT_2"] diff --git a/t/093-uthread-spawn.t b/t/093-uthread-spawn.t index d905c100c5..99750d3c0b 100644 --- a/t/093-uthread-spawn.t +++ b/t/093-uthread-spawn.t @@ -962,7 +962,7 @@ received: OK content_by_lua ' local function f() local sock = ngx.socket.udp() - local ok, err = sock:setpeername("127.0.0.1", 12345) + local ok, err = sock:setpeername("127.0.0.1", $TEST_NGINX_RAND_PORT_1) local bytes, err = sock:send("blah") if not bytes then ngx.say("failed to send query: ", err) @@ -1002,7 +1002,7 @@ delete thread 2 delete thread 1 )$ ---- udp_listen: 12345 +--- udp_listen: $TEST_NGINX_RAND_PORT_1 --- udp_query: blah --- udp_reply: hello udp --- response_body_like chop diff --git a/t/106-timer.t b/t/106-timer.t index a9b4aed7bd..513e1e5b45 100644 --- a/t/106-timer.t +++ b/t/106-timer.t @@ -2210,8 +2210,8 @@ qr/\[lua\] content_by_lua\(nginx\.conf:\d+\):\d+: elapsed: .*?, context: ngx\.ti '; } --- log_level: error ---- error_log_file: syslog:server=127.0.0.1:12345 ---- udp_listen: 12345 +--- error_log_file: syslog:server=127.0.0.1:$TEST_NGINX_RAND_PORT_1 +--- udp_listen: $TEST_NGINX_RAND_PORT_1 --- udp_query eval: qr/Bad bad bad/ --- udp_reply: hello --- wait: 0.1 diff --git a/t/124-init-worker.t b/t/124-init-worker.t index 07c2658f06..c68d74bb18 100644 --- a/t/124-init-worker.t +++ b/t/124-init-worker.t @@ -730,8 +730,8 @@ ok '; } --- log_level: error ---- error_log_file: syslog:server=127.0.0.1:12345 ---- udp_listen: 12345 +--- error_log_file: syslog:server=127.0.0.1:$TEST_NGINX_RAND_PORT_1 +--- udp_listen: $TEST_NGINX_RAND_PORT_1 --- udp_query eval: qr/Bad bad bad/ --- udp_reply: hello --- wait: 0.1 diff --git a/t/129-ssl-socket.t b/t/129-ssl-socket.t index cc3f243c07..ccfa19fffb 100644 --- a/t/129-ssl-socket.t +++ b/t/129-ssl-socket.t @@ -17,7 +17,7 @@ repeat_each(2); sub resolve($$); -plan tests => repeat_each() * (blocks() * 7 - 3); +plan tests => repeat_each() * (blocks() * 7 - 4); $ENV{TEST_NGINX_HTML_DIR} ||= html_dir(); $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; @@ -2141,8 +2141,6 @@ failed to do SSL handshake: timeout --- log_level: debug --- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+/ --- grep_error_log_out ---- error_log -lua ssl server name: "openresty.org" --- no_error_log SSL reused session [error] diff --git a/t/139-ssl-cert-by.t b/t/139-ssl-cert-by.t index 3fd6413307..abf447856d 100644 --- a/t/139-ssl-cert-by.t +++ b/t/139-ssl-cert-by.t @@ -1885,7 +1885,7 @@ qr/\[info\] .*? SSL_do_handshake\(\) failed\b/, lua_package_path "../lua-resty-core/lib/?.lua;;"; server { - listen 127.0.0.1:12345 ssl; + listen 127.0.0.1:$TEST_NGINX_RAND_PORT_1 ssl; server_name test.com; ssl_certificate_by_lua_block { @@ -1917,7 +1917,7 @@ qr/\[info\] .*? SSL_do_handshake\(\) failed\b/, sock:settimeout(2000) - local ok, err = sock:connect("127.0.0.1", 12345) + local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_RAND_PORT_1) if not ok then ngx.say("failed to connect: ", err) return diff --git a/t/163-exit-worker-hup.t b/t/163-exit-worker-hup.t index cd2e5ce649..136efdc7ff 100644 --- a/t/163-exit-worker-hup.t +++ b/t/163-exit-worker-hup.t @@ -57,7 +57,7 @@ log from exit_worker_by_lua_block } server { - listen 12345; + listen $TEST_NGINX_RAND_PORT_1; location = /t { echo 'hello world'; @@ -68,7 +68,7 @@ log from exit_worker_by_lua_block content_by_lua_block { ngx.timer.at(0, function () local sock = ngx.socket.tcp() - sock:connect("127.0.0.1", 12345) + sock:connect("127.0.0.1", $TEST_NGINX_RAND_PORT_1) local reader = sock:receiveuntil("unknow") ngx.log(ngx.NOTICE, "reading to block the exiting") reader() diff --git a/t/166-ssl-client-hello.t b/t/166-ssl-client-hello.t index a9d8ac8d2a..a356b6eeaa 100644 --- a/t/166-ssl-client-hello.t +++ b/t/166-ssl-client-hello.t @@ -736,7 +736,7 @@ should never reached here === TEST 9: lua exception - no yield --- http_config server { - listen 127.0.0.2:8080 ssl; + listen 127.0.0.2:$TEST_NGINX_RAND_PORT_2 ssl; server_name test.com; ssl_client_hello_by_lua_block { error("bad bad bad") @@ -764,7 +764,7 @@ should never reached here sock:settimeout(2000) - local ok, err = sock:connect("127.0.0.2", 8080) + local ok, err = sock:connect("127.0.0.2", $TEST_NGINX_RAND_PORT_2) if not ok then ngx.say("failed to connect: ", err) return @@ -2133,7 +2133,7 @@ ssl client hello by lua is running! lua_package_path "../lua-resty-core/lib/?.lua;;"; server { - listen 127.0.0.1:12346 ssl; + listen 127.0.0.1:$TEST_NGINX_RAND_PORT_1 ssl; server_name test.com; ssl_client_hello_by_lua_block { @@ -2165,7 +2165,7 @@ ssl client hello by lua is running! sock:settimeout(2000) - local ok, err = sock:connect("127.0.0.1", 12346) + local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_RAND_PORT_1) if not ok then ngx.say("failed to connect: ", err) return From 0e769b76432df91e5f10aa56a56858e8a190faf7 Mon Sep 17 00:00:00 2001 From: Johnny Wang Date: Wed, 27 Dec 2023 18:23:53 +0800 Subject: [PATCH 142/254] tests: 082-body-filter-2.t: skip this test if mockeagain is not loaded correctly. (#2275) --- t/082-body-filter-2.t | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/t/082-body-filter-2.t b/t/082-body-filter-2.t index ee4fe56ece..ffccad28ab 100644 --- a/t/082-body-filter-2.t +++ b/t/082-body-filter-2.t @@ -13,9 +13,14 @@ BEGIN { $SkipReason = "http2 does not support mockeagain"; } else { - $ENV{TEST_NGINX_POSTPONE_OUTPUT} = 1; - $ENV{TEST_NGINX_EVENT_TYPE} = 'poll'; - $ENV{MOCKEAGAIN}='w' + if ($ENV{LD_PRELOAD} && $ENV{LD_PRELOAD} =~ /\bmockeagain\.so\b/) { + $ENV{TEST_NGINX_POSTPONE_OUTPUT} = 1; + $ENV{TEST_NGINX_EVENT_TYPE} = 'poll'; + $ENV{MOCKEAGAIN}='w' + } else { + $SkipReason = "'mockeagain.so' does not appear to be preloaded " + . "with 'LD_PRELOAD'"; + } } } From 7598ff389ef5a1a3e8949c48a6e13292fa9adc9e Mon Sep 17 00:00:00 2001 From: Brian Rak Date: Sat, 20 Jan 2024 14:11:31 +0800 Subject: [PATCH 143/254] feature: add ngx_http_lua_ffi_parse_der_cert and ngx_http_lua_ffi_parse_der_key functions. --- .travis.yml | 4 +- README.markdown | 4 +- src/ngx_http_lua_ssl_certby.c | 109 ++++++++++++++++++++++++ t/140-ssl-c-api.t | 156 ++++++++++++++++++++++++++++++++++ t/cert/test_der.crt | Bin 0 -> 955 bytes t/cert/test_der.key | Bin 0 -> 1216 bytes 6 files changed, 269 insertions(+), 4 deletions(-) create mode 100644 t/cert/test_der.crt create mode 100644 t/cert/test_der.key diff --git a/.travis.yml b/.travis.yml index d6742ed52b..d3b973c80d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -43,7 +43,7 @@ env: - LUAJIT_INC=$LUAJIT_PREFIX/include/luajit-2.1 - LUA_INCLUDE_DIR=$LUAJIT_INC - PCRE_VER=8.45 - - PCRE2_VER=10.37 + - PCRE2_VER=10.42 - PCRE_PREFIX=/opt/pcre - PCRE2_PREFIX=/opt/pcre2 - PCRE_LIB=$PCRE_PREFIX/lib @@ -81,7 +81,7 @@ before_install: install: - if [ ! -f download-cache/drizzle7-$DRIZZLE_VER.tar.gz ]; then wget -P download-cache https://github.com/openresty/openresty-deps-prebuild/releases/download/v20230902/drizzle7-$DRIZZLE_VER.tar.gz; fi - if [ "$USE_PCRE2" != "Y" ] && [ ! -f download-cache/pcre-$PCRE_VER.tar.gz ]; then wget -P download-cache https://downloads.sourceforge.net/project/pcre/pcre/${PCRE_VER}/pcre-${PCRE_VER}.tar.gz; fi - - if [ "$USE_PCRE2" = "Y" ] && [ ! -f download-cache/pcre2-$PCRE2_VER.tar.gz ]; then wget -P download-cache https://downloads.sourceforge.net/project/pcre/pcre2/${PCRE2_VER}/pcre2-${PCRE2_VER}.tar.gz; fi + - if [ "$USE_PCRE2" = "Y" ] && [ ! -f download-cache/pcre2-$PCRE2_VER.tar.gz ]; then wget -P download-cache https://github.com/PCRE2Project/pcre2/releases/download/pcre2-${PCRE2_VER}/pcre2-${PCRE2_VER}.tar.gz; fi - if [ -n "$OPENSSL_VER" ] && [ ! -f download-cache/openssl-$OPENSSL_VER.tar.gz ]; then wget -P download-cache https://www.openssl.org/source/openssl-$OPENSSL_VER.tar.gz || wget -P download-cache https://www.openssl.org/source/old/${OPENSSL_VER//[a-z]/}/openssl-$OPENSSL_VER.tar.gz; fi - if [ -n "$OPENSSL_VER" ] && [ ! -f download-cache/openssl-$OPENSSL_VER.tar.gz ]; then wget -P download-cache https://www.openssl.org/source/openssl-$OPENSSL_VER.tar.gz || wget -P download-cache https://www.openssl.org/source/old/${OPENSSL_VER//[a-z]/}/openssl-$OPENSSL_VER.tar.gz; fi - wget https://github.com/openresty/openresty-deps-prebuild/releases/download/v20230902/boringssl-20230902-x64-focal.tar.gz diff --git a/README.markdown b/README.markdown index d6ec8c94be..56fb0565bf 100644 --- a/README.markdown +++ b/README.markdown @@ -7916,11 +7916,11 @@ Set client certificate chain and corresponding private key to the TCP socket obj The certificate chain and private key provided will be used later by the [tcpsock:sslhandshake](#tcpsocksslhandshake) method. * `cert` specify a client certificate chain cdata object that will be used while handshaking with -remote server. These objects can be created using [ngx.ssl.parse\_pem\_cert](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ssl.md#parse_pem_cert) +remote server. These objects can be created using [ngx.ssl.parse\_pem\_cert](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ssl.md#parse_pem_cert) or [ngx.ssl.parse\_der\_cert](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ssl.md#parse_der_cert) function provided by lua-resty-core. Note that specifying the `cert` option requires corresponding `pkey` be provided too. See below. * `pkey` specify a private key corresponds to the `cert` option above. -These objects can be created using [ngx.ssl.parse\_pem\_priv\_key](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ssl.md#parse_pem_priv_key) +These objects can be created using [ngx.ssl.parse\_pem\_priv\_key](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ssl.md#parse_pem_priv_key) or [ngx.ssl.parse\_der\_priv\_key](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ssl.md#parse_der_priv_key) function provided by lua-resty-core. If both of `cert` and `pkey` are `nil`, this method will clear any existing client certificate and private key diff --git a/src/ngx_http_lua_ssl_certby.c b/src/ngx_http_lua_ssl_certby.c index b8e70ddefa..d775f2b311 100644 --- a/src/ngx_http_lua_ssl_certby.c +++ b/src/ngx_http_lua_ssl_certby.c @@ -1172,6 +1172,81 @@ ngx_http_lua_ffi_parse_pem_cert(const u_char *pem, size_t pem_len, } +void * +ngx_http_lua_ffi_parse_der_cert(const char *data, size_t len, + char **err) +{ + BIO *bio; + X509 *x509; + STACK_OF(X509) *chain; + + if (data == NULL || len == 0) { + *err = "invalid argument"; + ERR_clear_error(); + return NULL; + } + + bio = BIO_new_mem_buf((char *) data, len); + if (bio == NULL) { + *err = "BIO_new_mem_buf() failed"; + ERR_clear_error(); + return NULL; + } + + x509 = d2i_X509_bio(bio, NULL); + if (x509 == NULL) { + *err = "d2i_X509_bio() failed"; + BIO_free(bio); + ERR_clear_error(); + return NULL; + } + + chain = sk_X509_new_null(); + if (chain == NULL) { + *err = "sk_X509_new_null() failed"; + X509_free(x509); + BIO_free(bio); + ERR_clear_error(); + return NULL; + } + + if (sk_X509_push(chain, x509) == 0) { + *err = "sk_X509_push() failed"; + sk_X509_free(chain); + X509_free(x509); + BIO_free(bio); + ERR_clear_error(); + return NULL; + } + + /* read rest of the chain */ + + while (!BIO_eof(bio)) { + x509 = d2i_X509_bio(bio, NULL); + if (x509 == NULL) { + *err = "d2i_X509_bio() failed in rest of chain"; + sk_X509_pop_free(chain, X509_free); + BIO_free(bio); + ERR_clear_error(); + return NULL; + } + + if (sk_X509_push(chain, x509) == 0) { + *err = "sk_X509_push() failed in rest of chain"; + sk_X509_pop_free(chain, X509_free); + X509_free(x509); + BIO_free(bio); + ERR_clear_error(); + return NULL; + } + } + + BIO_free(bio); + + return chain; +} + + void ngx_http_lua_ffi_free_cert(void *cdata) { @@ -1209,6 +1284,40 @@ ngx_http_lua_ffi_parse_pem_priv_key(const u_char *pem, size_t pem_len, } +void * +ngx_http_lua_ffi_parse_der_priv_key(const char *data, size_t len, + char **err) +{ + BIO *bio = NULL; + EVP_PKEY *pkey = NULL; + + if (data == NULL || len == 0) { + *err = "invalid argument"; + ERR_clear_error(); + return NULL; + } + + bio = BIO_new_mem_buf((char *) data, len); + if (bio == NULL) { + *err = "BIO_new_mem_buf() failed"; + ERR_clear_error(); + return NULL; + } + + pkey = d2i_PrivateKey_bio(bio, NULL); + if (pkey == NULL) { + *err = "d2i_PrivateKey_bio() failed"; + BIO_free(bio); + ERR_clear_error(); + return NULL; + } + + BIO_free(bio); + + return pkey; +} + + void ngx_http_lua_ffi_free_priv_key(void *cdata) { diff --git a/t/140-ssl-c-api.t b/t/140-ssl-c-api.t index 5b2ae018fe..6b5ff2f8ca 100644 --- a/t/140-ssl-c-api.t +++ b/t/140-ssl-c-api.t @@ -53,6 +53,12 @@ ffi.cdef[[ void *ngx_http_lua_ffi_parse_pem_priv_key(const unsigned char *pem, size_t pem_len, char **err); + void *ngx_http_lua_ffi_parse_der_cert(const char *data, size_t len, + char **err); + + void *ngx_http_lua_ffi_parse_der_priv_key(const char *data, size_t len, + char **err); + int ngx_http_lua_ffi_set_cert(void *r, void *cdata, char **err); @@ -1323,3 +1329,153 @@ SNI is test.com --- no_error_log [error] [alert] + + + +=== TEST 11: DER cert + private key cdata +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + + ssl_certificate_by_lua_block { + collectgarbage() + + local ffi = require "ffi" + require "defines" + + local errmsg = ffi.new("char *[1]") + + local r = require "resty.core.base" .get_request() + if r == nil then + ngx.log(ngx.ERR, "no request found") + return + end + + ffi.C.ngx_http_lua_ffi_ssl_clear_certs(r, errmsg) + + local f = assert(io.open("t/cert/test_der.crt", "rb")) + local cert_data = f:read("*all") + f:close() + + local cert = ffi.C.ngx_http_lua_ffi_parse_der_cert(cert_data, #cert_data, errmsg) + if not cert then + ngx.log(ngx.ERR, "failed to parse DER cert: ", + ffi.string(errmsg[0])) + return + end + + local rc = ffi.C.ngx_http_lua_ffi_set_cert(r, cert, errmsg) + if rc ~= 0 then + ngx.log(ngx.ERR, "failed to set cdata cert: ", + ffi.string(errmsg[0])) + return + end + + ffi.C.ngx_http_lua_ffi_free_cert(cert) + + f = assert(io.open("t/cert/test_der.key", "rb")) + local pkey_data = f:read("*all") + f:close() + + local pkey = ffi.C.ngx_http_lua_ffi_parse_der_priv_key(pkey_data, #pkey_data, errmsg) + if pkey == nil then + ngx.log(ngx.ERR, "failed to parse DER priv key: ", + ffi.string(errmsg[0])) + return + end + + local rc = ffi.C.ngx_http_lua_ffi_set_priv_key(r, pkey, errmsg) + if rc ~= 0 then + ngx.log(ngx.ERR, "failed to set cdata priv key: ", + ffi.string(errmsg[0])) + return + end + + ffi.C.ngx_http_lua_ffi_free_priv_key(pkey) + } + + ssl_certificate ../../cert/test2.crt; + ssl_certificate_key ../../cert/test2.key; + + server_tokens off; + location /foo { + default_type 'text/plain'; + content_by_lua_block { ngx.status = 201 ngx.say("foo") ngx.exit(201) } + more_clear_headers Date; + } + } +--- config + server_tokens off; + lua_ssl_trusted_certificate ../../cert/test.crt; + + location /t { + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(2000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(nil, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + local req = "GET /foo HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n" + local bytes, err = sock:send(req) + if not bytes then + ngx.say("failed to send http request: ", err) + return + end + + ngx.say("sent http request: ", bytes, " bytes.") + + while true do + local line, err = sock:receive() + if not line then + -- ngx.say("failed to receive response status line: ", err) + break + end + + ngx.say("received: ", line) + end + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + -- collectgarbage() + } + } + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: cdata +sent http request: 56 bytes. +received: HTTP/1.1 201 Created +received: Server: nginx +received: Content-Type: text/plain +received: Content-Length: 4 +received: Connection: close +received: +received: foo +close: 1 nil + +--- error_log +lua ssl server name: "test.com" + +--- no_error_log +[error] +[alert] diff --git a/t/cert/test_der.crt b/t/cert/test_der.crt new file mode 100644 index 0000000000000000000000000000000000000000..273b98638f7853e003f7d68d084b30f143a748a1 GIT binary patch literal 955 zcmXqLV%~1h#5A8tL@8ZQ{V?a!$BBCzToyRCou9?T#%I9G#;Mij(e|B}k&&B~!Ju)v zA-4f18*?ZNn=n&ou%WPlAc(`k!{wZqlbM!Zl$V)kC}to65@hG$4NlBca4Sm8OU^7# z&Nmb?5CDmD@o@SVq~-;s7ME1Q#JG{g1P%B>>X>;rN`PwglJj#76%6Fy4&h`J6HH7` z%`2(Oa7fQh%*+9)Fpv}HH8M7^G%z(VF|;(Yh!W>D262s`+(GQ}CPpRXU}j`xU~XdM zXE11DDrw9vORURY5N-PiK}$3qShn!PnHyI$?${Y9vV57KRH*Q4 z*8#QM+xa(E+q%q@6`2!%@$T#-_QU%;8Ru+t+Vtr7_V4k9tDmKu5%)Q=^Pcr=jarXp z?#l|UKc;+NtD94NEdG+M{Y!4`^Fb$9oEL1H8069@W?DJ%!m0a@e#M@YHQZ*l?2jT- zX}DK<=^gQJ;a4AR^tyiI)Q_adOPh6>m>C%ukwXZW5P>1Y$Pn_){`_M7K0X(Tnkyf- ze%e{JalO2NgpB;1Z)Q&y9DUV(ajn5-!%K?Wr2kY(yB(-lK52%Ob{+FOA^VaK)mdi* z{0*6(o?q&nw(iNB&s=tvk6Q1xsyIBAE}8ZI-*U+bzm!vcZ#{X8KO}cmWnW=upe0iL9cbGRj8~?rcpgxW#c&+lXiDmoZ8WI9eB?z67kz94mW|#am z_Fjn#3*QNw&HQp+$ieQN_llG9?D_L_p6@DrUd?;xbnf=4>aA~A+0A&en&D)WawJdo z_YVok#YsJO1yP_T`yB`ah*e_}!|WT=MnWA;|~E%eLI%djJ5* CVRZTc literal 0 HcmV?d00001 diff --git a/t/cert/test_der.key b/t/cert/test_der.key new file mode 100644 index 0000000000000000000000000000000000000000..14e9fa5821954099040a8490a1f344be65228cc9 GIT binary patch literal 1216 zcmV;x1V8&Qf&{z*0RS)!1_>&LNQUrrZ9p8q5=T`0)hbn0G!bJW_cjII!-q43Pu)F|9OFd+o=kRov)`ntd-ZQF0yt35=S9Tc2j(cPP32gANe0i3Zy zvf{_L_g`_V=48wlOvJg~JDVtdNP`R0AVv6;_pL2#bH-oNJwNFSE6-BNsLv6Gky1o~ z7BzX1(8}N9`d!H#F}60Q{2>B$S4wAf+!yv&)#9;A*VxMVVp-C&Edm1p009Dm0RRRz zj*-b_ip^;MD%E7e&uOyh0Cjq`o=mu>&51*dNc#RA@pU*<3+&87b^L`xT5G84fA(-L zx9V;(3Vrtg9}N!bYI8=byWl{nA3Y%ccP;Lm>i3}@ zGkHG?gfdIm| zKBkn~K-0L6Uw*h~49EeBD3QmN142D7_uDxIyG9CcVv{_V8u!&SH+&G}T__{W!x)Zv zIFmoIH{d~7S7UFA+E5#7zAAh}#2M#s)j+Syq0!;dcw(iqv1YL5`>Hve0Q7x2hX@h} zNl`_$b@pT3E!E6cFv(s<7tIpvqb62@iD)oi`b2 z5?#YEl=+E8yWm)df-VH1Q!e_6+~77*zqQpZc00!&WhU&#T)91|=J=qwNBL zfDI@8v#X;6c1or5_0Q+m)jOqT5L0*2{ENNK^;PKkIz~b`TGC-NMMHLfxi&iYz*>sm zGp&rPG3UR07! zC&yWO_;Ym+*g5-Cvn>e#!!+gd6n@v1N6WAcku(I@##UN4PMeA^>Nq54rF%xRL=5pn z2Lck`R2UH;`A#&t+FX=BAe0{&6Dn`U5A>Pvny|0;gJF(69|tRE39s%*E8>*~>V{)~IK_H&1*#_RZ)kf!M6wBOcRSBH8x=L&GOyz}HOel8 zsPZVMJ$k4plr$^Wuazw7!aL&u6(e&qn=!N=*d^QAxyfo?WA5dNu)lq_SR28Gfzl1D epCqH!-q!E@>y8q)XlN+Uf4;RvhuVFpY}}FtKTk3M literal 0 HcmV?d00001 From e0d19f787e74ce3ffbb9b9c5abad02fd6ea81f41 Mon Sep 17 00:00:00 2001 From: Jun Ouyang Date: Wed, 28 Feb 2024 11:57:06 +0800 Subject: [PATCH 144/254] Revert "changes: modify read body api limitation for HTTP/2 or HTTP/3 requests." This reverts commit 86bea01b244938e0ab6eda780906c06fa62c3b5c. --- README.markdown | 4 ++-- src/ngx_http_lua_accessby.c | 29 ++++------------------------- src/ngx_http_lua_contentby.c | 29 ++++------------------------- src/ngx_http_lua_req_body.c | 28 ++++------------------------ t/023-rewrite/request_body.t | 2 -- t/024-access/request_body.t | 2 -- t/044-req-body.t | 4 +--- 7 files changed, 15 insertions(+), 83 deletions(-) diff --git a/README.markdown b/README.markdown index 56fb0565bf..d59a1b5818 100644 --- a/README.markdown +++ b/README.markdown @@ -2722,7 +2722,7 @@ lua_need_request_body **phase:** *depends on usage* -Due to the stream processing feature of HTTP/2 or HTTP/3, this configuration could potentially block the entire request. Therefore, this configuration is effective only when HTTP/2 or HTTP/3 requests send content-length header. For requests with versions lower than HTTP/2, this configuration can still be used without any problems. +Due to the stream processing feature of HTTP2, it does not support HTTP2 connection. Determines whether to force the request body data to be read before running rewrite/access/content_by_lua* or not. The Nginx core does not read the client request body by default and if request body data is required, then this directive should be turned `on` or the [ngx.req.read_body](#ngxreqread_body) function should be called within the Lua code. @@ -5426,7 +5426,7 @@ Reads the client request body synchronously without blocking the Nginx event loo local args = ngx.req.get_post_args() ``` -Due to the stream processing feature of HTTP/2 or HTTP/3, this api could potentially block the entire request. Therefore, this api is effective only when HTTP/2 or HTTP/3 requests send content-length header. For requests with versions lower than HTTP/2, this api can still be used without any problems. +Due to the stream processing feature of HTTP2, it does not support HTTP2 connection. If the request body is already read previously by turning on [lua_need_request_body](#lua_need_request_body) or by using other modules, then this function does not run and returns immediately. diff --git a/src/ngx_http_lua_accessby.c b/src/ngx_http_lua_accessby.c index 2bf40aaa87..fa6810d9ed 100644 --- a/src/ngx_http_lua_accessby.c +++ b/src/ngx_http_lua_accessby.c @@ -136,26 +136,11 @@ ngx_http_lua_access_handler(ngx_http_request_t *r) return NGX_DONE; } - if (llcf->force_read_body && !ctx->read_body_done) { - +/* http2 read body may break http2 stream process */ #if (NGX_HTTP_V2) - if (r->main->stream && r->headers_in.content_length_n < 0) { - ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, - "disable lua_need_request_body, since " - "http2 read_body may break http2 stream process"); - goto done; - } -#endif - -#if (NGX_HTTP_V3) - if (r->http_version == NGX_HTTP_VERSION_30 - && r->headers_in.content_length_n < 0) - { - ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, - "disable lua_need_request_body, since " - "http2 read_body may break http2 stream process"); - goto done; - } + if (llcf->force_read_body && !ctx->read_body_done && !r->main->stream) { +#else + if (llcf->force_read_body && !ctx->read_body_done) { #endif r->request_body_in_single_buf = 1; r->request_body_in_persistent_file = 1; @@ -174,12 +159,6 @@ ngx_http_lua_access_handler(ngx_http_request_t *r) } } -#if defined(NGX_HTTP_V3) || defined(NGX_HTTP_V2) - -done: - -#endif - dd("calling access handler"); return llcf->access_handler(r); } diff --git a/src/ngx_http_lua_contentby.c b/src/ngx_http_lua_contentby.c index 2014d52d8d..d1c3bc9fd9 100644 --- a/src/ngx_http_lua_contentby.c +++ b/src/ngx_http_lua_contentby.c @@ -195,26 +195,11 @@ ngx_http_lua_content_handler(ngx_http_request_t *r) return rc; } - if (llcf->force_read_body && !ctx->read_body_done) { - +/* http2 read body may break http2 stream process */ #if (NGX_HTTP_V2) - if (r->main->stream && r->headers_in.content_length_n < 0) { - ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, - "disable lua_need_request_body, since " - "http2 read_body may break http2 stream process"); - goto done; - } -#endif - -#if (NGX_HTTP_V3) - if (r->http_version == NGX_HTTP_VERSION_30 - && r->headers_in.content_length_n < 0) - { - ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, - "disable lua_need_request_body, since " - "http2 read_body may break http2 stream process"); - goto done; - } + if (llcf->force_read_body && !ctx->read_body_done && !r->main->stream) { +#else + if (llcf->force_read_body && !ctx->read_body_done) { #endif r->request_body_in_single_buf = 1; r->request_body_in_persistent_file = 1; @@ -234,12 +219,6 @@ ngx_http_lua_content_handler(ngx_http_request_t *r) } } -#if defined(NGX_HTTP_V3) || defined(NGX_HTTP_V2) - -done: - -#endif - dd("setting entered"); ctx->entered_content_phase = 1; diff --git a/src/ngx_http_lua_req_body.c b/src/ngx_http_lua_req_body.c index 61ab999045..32c75796d9 100644 --- a/src/ngx_http_lua_req_body.c +++ b/src/ngx_http_lua_req_body.c @@ -87,18 +87,8 @@ ngx_http_lua_ngx_req_read_body(lua_State *L) /* http2 read body may break http2 stream process */ #if (NGX_HTTP_V2) - if (r->main->stream && r->headers_in.content_length_n < 0) { - return luaL_error(L, "http2 requests are not supported" - " without content-length header"); - } -#endif - -#if (NGX_HTTP_V3) - if (r->http_version == NGX_HTTP_VERSION_30 - && r->headers_in.content_length_n < 0) - { - return luaL_error(L, "http3 requests are not supported" - " without content-length header"); + if (r->main->stream) { + return luaL_error(L, "http2 requests are not supported yet"); } #endif @@ -351,18 +341,8 @@ ngx_http_lua_ngx_req_get_body_file(lua_State *L) /* http2 read body may break http2 stream process */ #if (NGX_HTTP_V2) - if (r->main->stream && r->headers_in.content_length_n < 0) { - return luaL_error(L, "http2 requests are not supported" - " without content-length header"); - } -#endif - -#if (NGX_HTTP_V3) - if (r->http_version == NGX_HTTP_VERSION_30 - && r->headers_in.content_length_n < 0) - { - return luaL_error(L, "http3 requests are not supported" - " without content-length header"); + if (r->main->stream) { + return luaL_error(L, "http2 requests are not supported yet"); } #endif diff --git a/t/023-rewrite/request_body.t b/t/023-rewrite/request_body.t index 32c02e151f..7383a1cebc 100644 --- a/t/023-rewrite/request_body.t +++ b/t/023-rewrite/request_body.t @@ -188,8 +188,6 @@ http finalize request: 500, "/echo_body?" a:1, c:0 "POST /echo_body hello\x00\x01\x02 world\x03\x04\xff" ---- more_headers -Content-Length: --- response_body eval "nil" --- no_error_log diff --git a/t/024-access/request_body.t b/t/024-access/request_body.t index 0aa12c8b55..3a3fbd1486 100644 --- a/t/024-access/request_body.t +++ b/t/024-access/request_body.t @@ -188,8 +188,6 @@ http finalize request: 500, "/echo_body?" a:1, c:0 "POST /echo_body hello\x00\x01\x02 world\x03\x04\xff" ---- more_headers -Content-Length: --- response_body eval "nil" --- no_error_log diff --git a/t/044-req-body.t b/t/044-req-body.t index f4509e1497..31b4b59586 100644 --- a/t/044-req-body.t +++ b/t/044-req-body.t @@ -1790,7 +1790,5 @@ content length: 5 --- request POST /test hello, world ---- more_headers -Content-Length: --- error_code: 500 ---- error_log: http2 requests are not supported without content-length header +--- error_log: http2 requests are not supported yet From 6e29c1a96e641ea3e3498b1524baeaa28d3ab58c Mon Sep 17 00:00:00 2001 From: Jun Ouyang Date: Wed, 28 Feb 2024 11:59:10 +0800 Subject: [PATCH 145/254] Revert "bugfix: disable http2 in body read due to http2 stream processing bug." This reverts commit 0090f3faf66e6870b3974e983ae4b47459c96fa3. --- README.markdown | 4 ---- src/ngx_http_lua_accessby.c | 5 ----- src/ngx_http_lua_contentby.c | 5 ----- src/ngx_http_lua_req_body.c | 14 -------------- src/ngx_http_lua_rewriteby.c | 5 ----- src/ngx_http_lua_server_rewriteby.c | 7 +------ t/023-rewrite/request_body.t | 21 --------------------- t/024-access/request_body.t | 21 --------------------- t/044-req-body.t | 20 +------------------- 9 files changed, 2 insertions(+), 100 deletions(-) diff --git a/README.markdown b/README.markdown index d59a1b5818..11c7b64f8e 100644 --- a/README.markdown +++ b/README.markdown @@ -2722,8 +2722,6 @@ lua_need_request_body **phase:** *depends on usage* -Due to the stream processing feature of HTTP2, it does not support HTTP2 connection. - Determines whether to force the request body data to be read before running rewrite/access/content_by_lua* or not. The Nginx core does not read the client request body by default and if request body data is required, then this directive should be turned `on` or the [ngx.req.read_body](#ngxreqread_body) function should be called within the Lua code. To read the request body data within the [$request_body](http://nginx.org/en/docs/http/ngx_http_core_module.html#var_request_body) variable, @@ -5426,8 +5424,6 @@ Reads the client request body synchronously without blocking the Nginx event loo local args = ngx.req.get_post_args() ``` -Due to the stream processing feature of HTTP2, it does not support HTTP2 connection. - If the request body is already read previously by turning on [lua_need_request_body](#lua_need_request_body) or by using other modules, then this function does not run and returns immediately. If the request body has already been explicitly discarded, either by the [ngx.req.discard_body](#ngxreqdiscard_body) function or other modules, this function does not run and returns immediately. diff --git a/src/ngx_http_lua_accessby.c b/src/ngx_http_lua_accessby.c index fa6810d9ed..d40eab123e 100644 --- a/src/ngx_http_lua_accessby.c +++ b/src/ngx_http_lua_accessby.c @@ -136,12 +136,7 @@ ngx_http_lua_access_handler(ngx_http_request_t *r) return NGX_DONE; } -/* http2 read body may break http2 stream process */ -#if (NGX_HTTP_V2) - if (llcf->force_read_body && !ctx->read_body_done && !r->main->stream) { -#else if (llcf->force_read_body && !ctx->read_body_done) { -#endif r->request_body_in_single_buf = 1; r->request_body_in_persistent_file = 1; r->request_body_in_clean_file = 1; diff --git a/src/ngx_http_lua_contentby.c b/src/ngx_http_lua_contentby.c index d1c3bc9fd9..5e2ae55209 100644 --- a/src/ngx_http_lua_contentby.c +++ b/src/ngx_http_lua_contentby.c @@ -195,12 +195,7 @@ ngx_http_lua_content_handler(ngx_http_request_t *r) return rc; } -/* http2 read body may break http2 stream process */ -#if (NGX_HTTP_V2) - if (llcf->force_read_body && !ctx->read_body_done && !r->main->stream) { -#else if (llcf->force_read_body && !ctx->read_body_done) { -#endif r->request_body_in_single_buf = 1; r->request_body_in_persistent_file = 1; r->request_body_in_clean_file = 1; diff --git a/src/ngx_http_lua_req_body.c b/src/ngx_http_lua_req_body.c index 32c75796d9..5d69735cde 100644 --- a/src/ngx_http_lua_req_body.c +++ b/src/ngx_http_lua_req_body.c @@ -85,13 +85,6 @@ ngx_http_lua_ngx_req_read_body(lua_State *L) return luaL_error(L, "request object not found"); } -/* http2 read body may break http2 stream process */ -#if (NGX_HTTP_V2) - if (r->main->stream) { - return luaL_error(L, "http2 requests are not supported yet"); - } -#endif - r->request_body_in_single_buf = 1; r->request_body_in_persistent_file = 1; r->request_body_in_clean_file = 1; @@ -339,13 +332,6 @@ ngx_http_lua_ngx_req_get_body_file(lua_State *L) return luaL_error(L, "request object not found"); } -/* http2 read body may break http2 stream process */ -#if (NGX_HTTP_V2) - if (r->main->stream) { - return luaL_error(L, "http2 requests are not supported yet"); - } -#endif - ngx_http_lua_check_fake_request(L, r); if (r->request_body == NULL || r->request_body->temp_file == NULL) { diff --git a/src/ngx_http_lua_rewriteby.c b/src/ngx_http_lua_rewriteby.c index c56bba5d7f..4109f288e3 100644 --- a/src/ngx_http_lua_rewriteby.c +++ b/src/ngx_http_lua_rewriteby.c @@ -140,12 +140,7 @@ ngx_http_lua_rewrite_handler(ngx_http_request_t *r) return NGX_DONE; } -/* http2 read body may break http2 stream process */ -#if (NGX_HTTP_V2) - if (llcf->force_read_body && !ctx->read_body_done && !r->main->stream) { -#else if (llcf->force_read_body && !ctx->read_body_done) { -#endif r->request_body_in_single_buf = 1; r->request_body_in_persistent_file = 1; r->request_body_in_clean_file = 1; diff --git a/src/ngx_http_lua_server_rewriteby.c b/src/ngx_http_lua_server_rewriteby.c index 997262eeb7..be860693f4 100644 --- a/src/ngx_http_lua_server_rewriteby.c +++ b/src/ngx_http_lua_server_rewriteby.c @@ -102,13 +102,8 @@ ngx_http_lua_server_rewrite_handler(ngx_http_request_t *r) return NGX_DONE; } -/* TODO: lscf do not have force_read_body - * http2 read body may break http2 stream process */ -#if (NGX_HTTP_V2) - if (llcf->force_read_body && !ctx->read_body_done && !r->main->stream) { -#else + /* TODO: lscf do not have force_read_body */ if (llcf->force_read_body && !ctx->read_body_done) { -#endif r->request_body_in_single_buf = 1; r->request_body_in_persistent_file = 1; r->request_body_in_clean_file = 1; diff --git a/t/023-rewrite/request_body.t b/t/023-rewrite/request_body.t index 7383a1cebc..b867d3a82c 100644 --- a/t/023-rewrite/request_body.t +++ b/t/023-rewrite/request_body.t @@ -170,24 +170,3 @@ Expect: 100-Continue http finalize request: 500, "/echo_body?" a:1, c:2 http finalize request: 500, "/echo_body?" a:1, c:0 --- log_level: debug ---- skip_eval: 4:$ENV{TEST_NGINX_USE_HTTP3} - - - -=== TEST 9: test HTTP2 reading request body was disabled ---- config - location /echo_body { - lua_need_request_body on; - rewrite_by_lua_block { - ngx.print(ngx.var.request_body or "nil") - } - content_by_lua 'ngx.exit(ngx.OK)'; - } ---- http2 ---- request eval -"POST /echo_body -hello\x00\x01\x02 -world\x03\x04\xff" ---- response_body eval -"nil" ---- no_error_log diff --git a/t/024-access/request_body.t b/t/024-access/request_body.t index 3a3fbd1486..fa03195272 100644 --- a/t/024-access/request_body.t +++ b/t/024-access/request_body.t @@ -170,24 +170,3 @@ Expect: 100-Continue http finalize request: 500, "/echo_body?" a:1, c:2 http finalize request: 500, "/echo_body?" a:1, c:0 --- log_level: debug ---- skip_eval: 4:$ENV{TEST_NGINX_USE_HTTP3} - - - -=== TEST 9: test HTTP2 reading request body was disabled ---- config - location /echo_body { - lua_need_request_body on; - access_by_lua_block { - ngx.print(ngx.var.request_body or "nil") - } - content_by_lua 'ngx.exit(ngx.OK)'; - } ---- http2 ---- request eval -"POST /echo_body -hello\x00\x01\x02 -world\x03\x04\xff" ---- response_body eval -"nil" ---- no_error_log diff --git a/t/044-req-body.t b/t/044-req-body.t index 31b4b59586..e2b9374a05 100644 --- a/t/044-req-body.t +++ b/t/044-req-body.t @@ -7,7 +7,7 @@ log_level('warn'); repeat_each(2); -plan tests => repeat_each() * (blocks() * 4 + 56); +plan tests => repeat_each() * (blocks() * 4 + 52 ); #no_diff(); no_long_string(); @@ -1774,21 +1774,3 @@ content length: 5 --- no_error_log [error] [alert] ---- skip_eval: 4:$ENV{TEST_NGINX_USE_HTTP3} - - - -=== TEST 53: HTTP2 read buffered body was discarded ---- config - location = /test { - content_by_lua_block { - local err = pcall(ngx.req.read_body()) - ngx.say(err) - } - } ---- http2 ---- request -POST /test -hello, world ---- error_code: 500 ---- error_log: http2 requests are not supported yet From 8dec675832574bdaf33e59258545b38633821137 Mon Sep 17 00:00:00 2001 From: Jun Ouyang Date: Wed, 28 Feb 2024 12:27:58 +0800 Subject: [PATCH 146/254] docs: docs about ngx.read_body() API limitations in stream HTTP2 and HTTP3 processing case --- README.markdown | 2 +- doc/HttpLuaModule.wiki | 3 +-- t/044-req-body.t | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/README.markdown b/README.markdown index 11c7b64f8e..960c3a19fa 100644 --- a/README.markdown +++ b/README.markdown @@ -5639,7 +5639,7 @@ Returns a read-only cosocket object that wraps the downstream connection. Only [ In case of error, `nil` will be returned as well as a string describing the error. -Due to the streaming nature of HTTP2 and HTTP3, this API cannot be used when the downstream connection is HTTP2 and HTTP3. +**Note:** This method will block while waiting for client request body to be fully received. Block time depends on the [client_body_timeout](http://nginx.org/en/docs/http/ngx_http_core_module.html#client_body_timeout) directive and maximum body size specified by the [client_max_body_size](http://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size) directive. If read timeout occurs or client body size exceeds the defined limit, this function will not return and `408 Request Time-out` or `413 Request Entity Too Large` response will be returned to the client instead. The socket object returned by this method is usually used to read the current request's body in a streaming fashion. Do not turn on the [lua_need_request_body](#lua_need_request_body) directive, and do not mix this call with [ngx.req.read_body](#ngxreqread_body) and [ngx.req.discard_body](#ngxreqdiscard_body). diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 305626c767..0db9dd52b0 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -4741,8 +4741,7 @@ Returns a read-only cosocket object that wraps the downstream connection. Only [ In case of error, nil will be returned as well as a string describing the error. -Due to the streaming nature of HTTP2 and HTTP3, this API cannot be used when the downstream connection is HTTP2 and HTTP3. - +'''Note:''' This method will block while waiting for client request body to be fully received. Block time depends on the [http://nginx.org/en/docs/http/ngx_http_core_module.html#client_body_timeout client_body_timeout] directive and maximum body size specified by the [http://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size client_max_body_size] directive. If read timeout occurs or client body size exceeds the defined limit, this function will not return and 408 Request Time-out or 413 Request Entity Too Large response will be returned to the client instead. The socket object returned by this method is usually used to read the current request's body in a streaming fashion. Do not turn on the [[#lua_need_request_body|lua_need_request_body]] directive, and do not mix this call with [[#ngx.req.read_body|ngx.req.read_body]] and [[#ngx.req.discard_body|ngx.req.discard_body]]. If any request body data has been pre-read into the Nginx core request header buffer, the resulting cosocket object will take care of this to avoid potential data loss resulting from such pre-reading. diff --git a/t/044-req-body.t b/t/044-req-body.t index e2b9374a05..d72b1eb632 100644 --- a/t/044-req-body.t +++ b/t/044-req-body.t @@ -7,7 +7,7 @@ log_level('warn'); repeat_each(2); -plan tests => repeat_each() * (blocks() * 4 + 52 ); +plan tests => repeat_each() * (blocks() * 4 + 58); #no_diff(); no_long_string(); From 1c77f025faf0413b17bfc3bdcda284ac031286a4 Mon Sep 17 00:00:00 2001 From: Zhongwei Yao Date: Mon, 4 Mar 2024 22:45:01 +0800 Subject: [PATCH 147/254] bugfix: fix memory corruption in consecutive regex calls. This memory corruption will cause nginx crash and can reproduce under "--with-no-pool-patch" build by running t/048-match-dfa.t TEST 9. test log: ok 1 - t/048-match-dfa.t TEST 9: multiple match calls with captures and DFA. - status code ok ok 2 - t/048-match-dfa.t TEST 9: multiple match calls with captures and DFA. - response_body - response is expected (repeated req 0, req 0) t/048-match-dfa.t TEST 9: multiple match calls with captures and DFA. - Can't connect to 127.0.0.1:1984: Connection refused Retry connecting after 0.675 sec t/048-match-dfa.t TEST 9: multiple match calls with captures and DFA. - Can't connect to 127.0.0.1:1984: Connection refused Retry connecting after 0.825 sec error.log [notice] 1683757#0: using the "epoll" event method [notice] 1683757#0: openresty/1.25.3.1 (no pool) [notice] 1683757#0: built by gcc 13.2.1 20231011 (Red Hat 13.2.1-4) (GCC) [notice] 1683757#0: OS: Linux 6.7.4-100.fc38.x86_64 [notice] 1683757#0: getrlimit(RLIMIT_NOFILE): 1024:524288 free(): invalid next size (fast) Co-author-by: lijunlong --- src/ngx_http_lua_regex.c | 10 +++++----- t/048-match-dfa.t | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/src/ngx_http_lua_regex.c b/src/ngx_http_lua_regex.c index 1b52fa233d..30c1650653 100644 --- a/src/ngx_http_lua_regex.c +++ b/src/ngx_http_lua_regex.c @@ -688,11 +688,11 @@ ngx_http_lua_ffi_exec_regex(ngx_http_lua_regex_t *re, int flags, ngx_pool_t *old_pool; if (flags & NGX_LUA_RE_MODE_DFA) { - ovecsize = 2; + ovecsize = 1; re->ncaptures = 0; } else { - ovecsize = (re->ncaptures + 1) * 3; + ovecsize = re->ncaptures + 1; } old_pool = ngx_http_lua_pcre_malloc_init(NULL); @@ -710,7 +710,7 @@ ngx_http_lua_ffi_exec_regex(ngx_http_lua_regex_t *re, int flags, } ngx_regex_match_data_size = ovecsize; - ngx_regex_match_data = pcre2_match_data_create(ovecsize / 3, NULL); + ngx_regex_match_data = pcre2_match_data_create(ovecsize, NULL); if (ngx_regex_match_data == NULL) { rc = PCRE2_ERROR_NOMEMORY; @@ -756,8 +756,8 @@ ngx_http_lua_ffi_exec_regex(ngx_http_lua_regex_t *re, int flags, "n %ui, ovecsize %ui", flags, exec_opts, rc, n, ovecsize); #endif - if (!(flags & NGX_LUA_RE_MODE_DFA) && n > ovecsize / 3) { - n = ovecsize / 3; + if (n > ovecsize) { + n = ovecsize; } for (i = 0; i < n; i++) { diff --git a/t/048-match-dfa.t b/t/048-match-dfa.t index edf3662d4f..023231b5c0 100644 --- a/t/048-match-dfa.t +++ b/t/048-match-dfa.t @@ -207,3 +207,41 @@ exec opts: 0 你 --- no_error_log [error] + + + +=== TEST 9: matched with do +--- config + location /re { + content_by_lua ' + local m = ngx.re.match("hello", "(h)(e)(l)", "jo") + if m then + ngx.say(m[0]) + ngx.say(m[1]) + ngx.say(m[2]) + ngx.say(m[3]) + else + ngx.say("not matched!") + end + local m = ngx.re.match("horld", "(h)(e)?(l)?", "jo") + if m then + ngx.say(m[0]) + ngx.say(m[1]) + ngx.say(m[2]) + ngx.say(m[3]) + else + ngx.say("not matched!") + end + '; + } +--- request + GET /re +--- response_body +hel +h +e +l +h +h +false +false From 54e5cb09d3685c0d805644482cb28be43786ebf6 Mon Sep 17 00:00:00 2001 From: Ruidong-X Date: Wed, 6 Mar 2024 12:15:06 +0800 Subject: [PATCH 148/254] feature: add ngx_http_lua_ffi_ssl_client_random. --- src/ngx_http_lua_ssl_certby.c | 23 ++++++ t/140-ssl-c-api.t | 144 ++++++++++++++++++++++++++++++++++ 2 files changed, 167 insertions(+) diff --git a/src/ngx_http_lua_ssl_certby.c b/src/ngx_http_lua_ssl_certby.c index d775f2b311..996c3d62a3 100644 --- a/src/ngx_http_lua_ssl_certby.c +++ b/src/ngx_http_lua_ssl_certby.c @@ -1609,4 +1609,27 @@ ngx_http_lua_ffi_get_req_ssl_pointer(ngx_http_request_t *r) } +int +ngx_http_lua_ffi_ssl_client_random(ngx_http_request_t *r, + unsigned char *out, size_t *outlen, char **err) +{ + ngx_ssl_conn_t *ssl_conn; + + if (r->connection == NULL || r->connection->ssl == NULL) { + *err = "bad request"; + return NGX_ERROR; + } + + ssl_conn = r->connection->ssl->connection; + if (ssl_conn == NULL) { + *err = "bad ssl conn"; + return NGX_ERROR; + } + + *outlen = SSL_get_client_random(ssl_conn, out, *outlen); + + return NGX_OK; +} + + #endif /* NGX_HTTP_SSL */ diff --git a/t/140-ssl-c-api.t b/t/140-ssl-c-api.t index 6b5ff2f8ca..001d26ae31 100644 --- a/t/140-ssl-c-api.t +++ b/t/140-ssl-c-api.t @@ -74,6 +74,9 @@ ffi.cdef[[ int ngx_http_lua_ffi_ssl_verify_client(void *r, void *cdata, int depth, char **err); + int ngx_http_lua_ffi_ssl_client_random(ngx_http_request_t *r, + unsigned char *out, size_t *outlen, char **err); + ]] _EOC_ } @@ -1479,3 +1482,144 @@ lua ssl server name: "test.com" --- no_error_log [error] [alert] + + + +=== TEST 12: client random +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + + ssl_certificate_by_lua_block { + collectgarbage() + + local ffi = require "ffi" + require "defines" + + local errmsg = ffi.new("char *[1]") + + local r = require "resty.core.base" .get_request() + if r == nil then + ngx.log(ngx.ERR, "no request found") + return + end + + -- test client random length + local out = ffi.new("unsigned char[?]", 0) + local sizep = ffi.new("size_t[1]", 0) + + local rc = ffi.C.ngx_http_lua_ffi_ssl_client_random(r, out, sizep, errmsg) + if rc ~= 0 then + ngx.log(ngx.ERR, "failed to get client random length: ", + ffi.string(errmsg[0])) + return + end + + if tonumber(sizep[0]) ~= 32 then + ngx.log(ngx.ERR, "client random length does not equal 32") + return + end + + -- test client random value + out = ffi.new("unsigned char[?]", 50) + sizep = ffi.new("size_t[1]", 50) + + rc = ffi.C.ngx_http_lua_ffi_ssl_client_random(r, out, sizep, errmsg) + if rc ~= 0 then + ngx.log(ngx.ERR, "failed to get client random: ", + ffi.string(errmsg[0])) + return + end + + local init_v = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + if ffi.string(out, sizep[0]) == init_v then + ngx.log(ngx.ERR, "maybe the client random value is incorrect") + return + end + } + + ssl_certificate ../../cert/test.crt; + ssl_certificate_key ../../cert/test.key; + + server_tokens off; + location /foo { + default_type 'text/plain'; + content_by_lua_block { ngx.status = 201 ngx.say("foo") ngx.exit(201) } + more_clear_headers Date; + } + } +--- config + server_tokens off; + lua_ssl_trusted_certificate ../../cert/test.crt; + + location /t { + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(2000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(nil, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + local req = "GET /foo HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n" + local bytes, err = sock:send(req) + if not bytes then + ngx.say("failed to send http request: ", err) + return + end + + ngx.say("sent http request: ", bytes, " bytes.") + + while true do + local line, err = sock:receive() + if not line then + -- ngx.say("failed to receive response status line: ", err) + break + end + + ngx.say("received: ", line) + end + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + -- collectgarbage() + } + } + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: cdata +sent http request: 56 bytes. +received: HTTP/1.1 201 Created +received: Server: nginx +received: Content-Type: text/plain +received: Content-Length: 4 +received: Connection: close +received: +received: foo +close: 1 nil + +--- error_log +lua ssl server name: "test.com" + +--- no_error_log +[error] +[alert] From 9e59105fd9fd49aa3a34f8023afa1826c7a57f95 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Thu, 7 Mar 2024 10:31:25 +0800 Subject: [PATCH 149/254] tests: fixed typo. --- t/138-balancer.t | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/138-balancer.t b/t/138-balancer.t index 8ccdee76c4..679744a9e1 100644 --- a/t/138-balancer.t +++ b/t/138-balancer.t @@ -571,7 +571,7 @@ upstream sent more data than specified in "Content-Length" header while reading -=== TEST 18: error in balancer_by_llua_block +=== TEST 18: error in balancer_by_lua_block --- http_config upstream backend { server 0.0.0.1; From 6df2b6f01c2f75cafae122a5832f194c71280a15 Mon Sep 17 00:00:00 2001 From: Zhongwei Yao Date: Thu, 7 Mar 2024 23:59:06 -0800 Subject: [PATCH 150/254] bugfix: correct offset vector memory allocation size for PCRE2. --- src/ngx_http_lua_regex.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/ngx_http_lua_regex.c b/src/ngx_http_lua_regex.c index 30c1650653..646b483e1f 100644 --- a/src/ngx_http_lua_regex.c +++ b/src/ngx_http_lua_regex.c @@ -591,7 +591,11 @@ ngx_http_lua_ffi_compile_regex(const unsigned char *pat, size_t pat_len, re_comp.captures = 0; } else { +#if (NGX_PCRE2) + ovecsize = (re_comp.captures + 1) * 2; +#else ovecsize = (re_comp.captures + 1) * 3; +#endif } dd("allocating cap with size: %d", (int) ovecsize); @@ -684,21 +688,21 @@ ngx_http_lua_ffi_exec_regex(ngx_http_lua_regex_t *re, int flags, { int rc, exec_opts = 0; size_t *ov; - ngx_uint_t ovecsize, n, i; + ngx_uint_t ovecpair, n, i; ngx_pool_t *old_pool; if (flags & NGX_LUA_RE_MODE_DFA) { - ovecsize = 1; + ovecpair = 1; re->ncaptures = 0; } else { - ovecsize = re->ncaptures + 1; + ovecpair = re->ncaptures + 1; } old_pool = ngx_http_lua_pcre_malloc_init(NULL); if (ngx_regex_match_data == NULL - || ovecsize > ngx_regex_match_data_size) + || ovecpair > ngx_regex_match_data_size) { /* * Allocate a match data if not yet allocated or smaller than @@ -709,8 +713,8 @@ ngx_http_lua_ffi_exec_regex(ngx_http_lua_regex_t *re, int flags, pcre2_match_data_free(ngx_regex_match_data); } - ngx_regex_match_data_size = ovecsize; - ngx_regex_match_data = pcre2_match_data_create(ovecsize, NULL); + ngx_regex_match_data_size = ovecpair; + ngx_regex_match_data = pcre2_match_data_create(ovecpair, NULL); if (ngx_regex_match_data == NULL) { rc = PCRE2_ERROR_NOMEMORY; @@ -741,7 +745,7 @@ ngx_http_lua_ffi_exec_regex(ngx_http_lua_regex_t *re, int flags, #if (NGX_DEBUG) ngx_log_debug4(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, "pcre2_match failed: flags 0x%05Xd, options 0x%08Xd, " - "rc %d, ovecsize %ui", flags, exec_opts, rc, ovecsize); + "rc %d, ovecpair %ui", flags, exec_opts, rc, ovecpair); #endif goto failed; @@ -753,11 +757,11 @@ ngx_http_lua_ffi_exec_regex(ngx_http_lua_regex_t *re, int flags, #if (NGX_DEBUG) ngx_log_debug5(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, "pcre2_match: flags 0x%05Xd, options 0x%08Xd, rc %d, " - "n %ui, ovecsize %ui", flags, exec_opts, rc, n, ovecsize); + "n %ui, ovecpair %ui", flags, exec_opts, rc, n, ovecpair); #endif - if (n > ovecsize) { - n = ovecsize; + if (n > ovecpair) { + n = ovecpair; } for (i = 0; i < n; i++) { From 1654cc6a4da6806aa4688625db494fa0438d9841 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Fri, 8 Mar 2024 16:10:54 +0800 Subject: [PATCH 151/254] feature: add FFI function for balancer.disable_ssl. This is a rewrite PR https://github.com/openresty/lua-nginx-module/pull/1687 from vislee --- src/ngx_http_lua_balancer.c | 36 +++++++++++++++++++++++++++++ t/138-balancer.t | 46 +++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) diff --git a/src/ngx_http_lua_balancer.c b/src/ngx_http_lua_balancer.c index af4da73388..146545bbd8 100644 --- a/src/ngx_http_lua_balancer.c +++ b/src/ngx_http_lua_balancer.c @@ -809,4 +809,40 @@ ngx_http_lua_ffi_balancer_recreate_request(ngx_http_request_t *r, } +int +ngx_http_lua_ffi_balancer_disable_ssl(ngx_http_request_t *r, char **err) +{ + ngx_http_lua_ctx_t *ctx; + ngx_http_upstream_t *u; + + if (r == NULL) { + *err = "no request found"; + return NGX_ERROR; + } + + u = r->upstream; + + if (u == NULL) { + *err = "no upstream found"; + return NGX_ERROR; + } + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx == NULL) { + *err = "no ctx found"; + return NGX_ERROR; + } + + if ((ctx->context & NGX_HTTP_LUA_CONTEXT_BALANCER) == 0) { + *err = "API disabled in the current context"; + return NGX_ERROR; + } + + u->ssl = 0; + u->schema.len = sizeof("http://") - 1; + + return NGX_OK; +} + + /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/t/138-balancer.t b/t/138-balancer.t index 679744a9e1..515168883e 100644 --- a/t/138-balancer.t +++ b/t/138-balancer.t @@ -591,3 +591,49 @@ upstream sent more data than specified in "Content-Length" header while reading "failed to load inlined Lua code: balancer_by_lua(nginx.conf:27):3: ')' expected (to close '(' at line 2) near ''", --- no_error_log [warn] + + + +=== TEST 19: disable ssl +--- http_config + lua_package_path "$TEST_NGINX_SERVER_ROOT/html/?.lua;;"; + + upstream backend { + server 127.0.0.1:$TEST_NGINX_SERVER_PORT; + balancer_by_lua_block { + local ffi = require "ffi" + local C = ffi.C +ffi.cdef[[ +int +ngx_http_lua_ffi_balancer_disable_ssl(ngx_http_request_t *r, char **err); +]] + local errmsg = ffi.new("char *[1]") + local r = require "resty.core.base" .get_request() + if r == nil then + ngx.log(ngx.ERR, "no request found") + return + end + + local rc = C.ngx_http_lua_ffi_balancer_disable_ssl(r, errmsg) + if rc < 0 then + ngx.log(ngx.ERR, "failed to disable ssl: ", ffi.string(errmsg[0])) + return + end + } + } +--- config + location = /t { + proxy_pass https://backend/back; + } + + location = /back { + echo ok; + } + +--- request + GET /t +--- response_body +ok +--- no_error_log +[error] +[cirt] From 6394debe28079d8516dfd58305244bd480c82bc6 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Fri, 8 Mar 2024 18:59:51 +0800 Subject: [PATCH 152/254] optimize: allow to reenable the tls for the upstream. --- src/ngx_http_lua_balancer.c | 13 ++++++++++--- t/138-balancer.t | 4 ++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/ngx_http_lua_balancer.c b/src/ngx_http_lua_balancer.c index 146545bbd8..a8192db038 100644 --- a/src/ngx_http_lua_balancer.c +++ b/src/ngx_http_lua_balancer.c @@ -810,7 +810,8 @@ ngx_http_lua_ffi_balancer_recreate_request(ngx_http_request_t *r, int -ngx_http_lua_ffi_balancer_disable_ssl(ngx_http_request_t *r, char **err) +ngx_http_lua_ffi_balancer_set_upstream_tls(ngx_http_request_t *r, int on, + char **err) { ngx_http_lua_ctx_t *ctx; ngx_http_upstream_t *u; @@ -838,8 +839,14 @@ ngx_http_lua_ffi_balancer_disable_ssl(ngx_http_request_t *r, char **err) return NGX_ERROR; } - u->ssl = 0; - u->schema.len = sizeof("http://") - 1; + if (on == 0) { + u->ssl = 0; + u->schema.len = sizeof("http://") - 1; + + } else { + u->ssl = 1; + u->schema.len = sizeof("https://") - 1; + } return NGX_OK; } diff --git a/t/138-balancer.t b/t/138-balancer.t index 515168883e..5ea94df96d 100644 --- a/t/138-balancer.t +++ b/t/138-balancer.t @@ -605,7 +605,7 @@ upstream sent more data than specified in "Content-Length" header while reading local C = ffi.C ffi.cdef[[ int -ngx_http_lua_ffi_balancer_disable_ssl(ngx_http_request_t *r, char **err); +ngx_http_lua_ffi_balancer_set_upstream_tls(ngx_http_request_t *r, int on, char **err); ]] local errmsg = ffi.new("char *[1]") local r = require "resty.core.base" .get_request() @@ -614,7 +614,7 @@ ngx_http_lua_ffi_balancer_disable_ssl(ngx_http_request_t *r, char **err); return end - local rc = C.ngx_http_lua_ffi_balancer_disable_ssl(r, errmsg) + local rc = C.ngx_http_lua_ffi_balancer_set_upstream_tls(r, 0, errmsg) if rc < 0 then ngx.log(ngx.ERR, "failed to disable ssl: ", ffi.string(errmsg[0])) return From e5248aa8203d3e0075822a577c1cdd19f5f1f831 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Sat, 9 Mar 2024 12:30:14 +0800 Subject: [PATCH 153/254] bugfix: fixed HTTP HEAD request smuggling issue. --- src/ngx_http_lua_util.c | 6 ++++ t/020-subrequest.t | 80 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+) diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 8fd26561a7..727ca3da39 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -599,6 +599,12 @@ ngx_http_lua_send_chain_link(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx, if (r->header_only) { ctx->eof = 1; + if (!r->request_body && r == r->main) { + if (ngx_http_discard_request_body(r) != NGX_OK) { + return NGX_ERROR; + } + } + if (ctx->buffering) { return ngx_http_lua_send_http10_headers(r, ctx); } diff --git a/t/020-subrequest.t b/t/020-subrequest.t index c731f1e61c..59b9f61a34 100644 --- a/t/020-subrequest.t +++ b/t/020-subrequest.t @@ -3527,3 +3527,83 @@ HTTP/1.1 400 Bad Request [error] --- skip_nginx 3: < 1.21.1 + + + +=== TEST 83: avoid request smuggling of HEAD req +--- config + location /capture { + server_tokens off; + more_clear_headers Date; + + content_by_lua_block { + ngx.say("Hello") + } + } + + location /t { + content_by_lua_block { + local req = [[ +HEAD /capture HTTP/1.1 +Host: test.com +Content-Length: 63 + +GET /capture HTTP/1.1 +Host: test.com +X: GET /bar HTTP/1.0 + +]] + + local sock = ngx.socket.tcp() + sock:settimeout(1000) + + local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_SERVER_PORT) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + local bytes, err = sock:send(req) + if not bytes then + ngx.say("failed to send req: ", err) + return + end + + ngx.say("req bytes: ", bytes) + + local n_resp = 0 + + local reader = sock:receiveuntil("\r\n") + while true do + local line, err = reader() + if line then + ngx.say(line) + if line == "0" then + n_resp = n_resp + 1 + end + + if n_resp >= 2 then + break + end + + else + ngx.say("err: ", err) + break + end + end + + sock:close() + } + } +--- request +GET /t +--- response_body +req bytes: 117 +HTTP/1.1 200 OK +Server: nginx +Content-Type: text/plain +Connection: keep-alive + +err: timeout +--- error_log +lua tcp socket read timed out From ca942b698404ba3012ecbc220d75442d74074ff5 Mon Sep 17 00:00:00 2001 From: syz Date: Sun, 10 Mar 2024 18:03:43 +0800 Subject: [PATCH 154/254] feature: add udp cosocket bind api. Co-authored-by: lijunlong --- README.markdown | 32 ++++++++++ src/ngx_http_lua_socket_tcp.c | 8 +-- src/ngx_http_lua_socket_udp.c | 81 +++++++++++++++++++++++- src/ngx_http_lua_socket_udp.h | 4 +- t/062-count.t | 2 +- t/087-udp-socket.t | 112 +++++++++++++++++++++++++++++++++- 6 files changed, 226 insertions(+), 13 deletions(-) diff --git a/README.markdown b/README.markdown index 960c3a19fa..dc0380159e 100644 --- a/README.markdown +++ b/README.markdown @@ -3715,6 +3715,7 @@ Nginx API for Lua * [ngx.shared.DICT.capacity](#ngxshareddictcapacity) * [ngx.shared.DICT.free_space](#ngxshareddictfree_space) * [ngx.socket.udp](#ngxsocketudp) +* [udpsock:bind](#udpsockbind) * [udpsock:setpeername](#udpsocksetpeername) * [udpsock:send](#udpsocksend) * [udpsock:receive](#udpsockreceive) @@ -7522,6 +7523,7 @@ ngx.socket.udp Creates and returns a UDP or datagram-oriented unix domain socket object (also known as one type of the "cosocket" objects). The following methods are supported on this object: +* [bind](#udpsockbind) * [setpeername](#udpsocksetpeername) * [send](#udpsocksend) * [receive](#udpsockreceive) @@ -7536,6 +7538,36 @@ See also [ngx.socket.tcp](#ngxsockettcp). [Back to TOC](#nginx-api-for-lua) +udpsock:bind +------------ +**syntax:** *ok, err = udpsock:bind(address)* + +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*,ssl_session_fetch_by_lua*,ssl_client_hello_by_lua** + +Just like the standard [proxy_bind](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_bind) directive, this api makes the outgoing connection to a upstream server originate from the specified local IP address. + +Only IP addresses can be specified as the `address` argument. + +Here is an example for connecting to a TCP server from the specified local IP address: + +```nginx + + location /test { + content_by_lua_block { + local sock = ngx.socket.udp() + -- assume "192.168.1.10" is the local ip address + local ok, err = sock:bind("192.168.1.10") + if not ok then + ngx.say("failed to bind: ", err) + return + end + sock:close() + } + } +``` + +[Back to TOC](#nginx-api-for-lua) + udpsock:setpeername ------------------- diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 230679fa7d..0aa7109758 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -861,13 +861,7 @@ ngx_http_lua_socket_tcp_bind(lua_State *L) return luaL_error(L, "no ctx found"); } - ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE - | NGX_HTTP_LUA_CONTEXT_ACCESS - | NGX_HTTP_LUA_CONTEXT_CONTENT - | NGX_HTTP_LUA_CONTEXT_TIMER - | NGX_HTTP_LUA_CONTEXT_SSL_CERT - | NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH - | NGX_HTTP_LUA_CONTEXT_SSL_CLIENT_HELLO); + ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_YIELDABLE); luaL_checktype(L, 1, LUA_TTABLE); diff --git a/src/ngx_http_lua_socket_udp.c b/src/ngx_http_lua_socket_udp.c index 10285f6d0a..e2ba790fc5 100644 --- a/src/ngx_http_lua_socket_udp.c +++ b/src/ngx_http_lua_socket_udp.c @@ -54,16 +54,19 @@ static void ngx_http_lua_socket_udp_read_handler(ngx_http_request_t *r, ngx_http_lua_socket_udp_upstream_t *u); static void ngx_http_lua_socket_udp_handle_success(ngx_http_request_t *r, ngx_http_lua_socket_udp_upstream_t *u); -static ngx_int_t ngx_http_lua_udp_connect(ngx_http_lua_udp_connection_t *uc); +static ngx_int_t ngx_http_lua_udp_connect(ngx_http_lua_udp_connection_t *uc, + ngx_addr_t *local); static int ngx_http_lua_socket_udp_close(lua_State *L); static ngx_int_t ngx_http_lua_socket_udp_resume(ngx_http_request_t *r); static void ngx_http_lua_udp_resolve_cleanup(void *data); static void ngx_http_lua_udp_socket_cleanup(void *data); +static int ngx_http_lua_socket_udp_bind(lua_State *L); enum { SOCKET_CTX_INDEX = 1, SOCKET_TIMEOUT_INDEX = 2, + SOCKET_BIND_INDEX = 3, }; @@ -100,6 +103,9 @@ ngx_http_lua_inject_socket_udp_api(ngx_log_t *log, lua_State *L) lua_pushcfunction(L, ngx_http_lua_socket_udp_close); lua_setfield(L, -2, "close"); /* ngx socket mt */ + lua_pushcfunction(L, ngx_http_lua_socket_udp_bind); + lua_setfield(L, -2, "bind"); + lua_pushvalue(L, -1); lua_setfield(L, -2, "__index"); lua_rawset(L, LUA_REGISTRYINDEX); @@ -159,6 +165,7 @@ ngx_http_lua_socket_udp_setpeername(lua_State *L) ngx_http_request_t *r; ngx_http_lua_ctx_t *ctx; ngx_str_t host; + ngx_addr_t *local; int port; ngx_resolver_ctx_t *rctx, temp; ngx_http_core_loc_conf_t *clcf; @@ -291,6 +298,13 @@ ngx_http_lua_socket_udp_setpeername(lua_State *L) u->read_timeout = u->conf->read_timeout; } + lua_rawgeti(L, 1, SOCKET_BIND_INDEX); + local = lua_touserdata(L, -1); + lua_pop(L, 1); + if (local != NULL) { + u->local = local; + } + ngx_memzero(&url, sizeof(ngx_url_t)); url.url.len = host.len; @@ -618,7 +632,7 @@ ngx_http_lua_socket_resolve_retval_handler(ngx_http_request_t *r, return 2; } - rc = ngx_http_lua_udp_connect(uc); + rc = ngx_http_lua_udp_connect(uc, u->local); if (rc != NGX_OK) { u->socket_errno = ngx_socket_errno; @@ -721,6 +735,56 @@ ngx_http_lua_socket_error_retval_handler(ngx_http_request_t *r, } +static int +ngx_http_lua_socket_udp_bind(lua_State *L) +{ + ngx_http_request_t *r; + ngx_http_lua_ctx_t *ctx; + int n; + u_char *text; + size_t len; + ngx_addr_t *local; + + n = lua_gettop(L); + + if (n != 2) { + return luaL_error(L, "expecting 2 arguments, but got %d", + lua_gettop(L)); + } + + r = ngx_http_lua_get_req(L); + if (r == NULL) { + return luaL_error(L, "no request found"); + } + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx == NULL) { + return luaL_error(L, "no ctx found"); + } + + ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_YIELDABLE); + + luaL_checktype(L, 1, LUA_TTABLE); + + text = (u_char *) luaL_checklstring(L, 2, &len); + + local = ngx_http_lua_parse_addr(L, text, len); + if (local == NULL) { + lua_pushnil(L); + lua_pushfstring(L, "bad address"); + return 2; + } + + lua_rawseti(L, 1, SOCKET_BIND_INDEX); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua udp socket bind ip: %V", &local->name); + + lua_pushinteger(L, 1); + return 1; +} + + static int ngx_http_lua_socket_udp_send(lua_State *L) { @@ -1340,7 +1404,7 @@ ngx_http_lua_socket_udp_handle_success(ngx_http_request_t *r, static ngx_int_t -ngx_http_lua_udp_connect(ngx_http_lua_udp_connection_t *uc) +ngx_http_lua_udp_connect(ngx_http_lua_udp_connection_t *uc, ngx_addr_t *local) { int rc; ngx_int_t event; @@ -1413,8 +1477,19 @@ ngx_http_lua_udp_connect(ngx_http_lua_udp_connection_t *uc) return NGX_ERROR; } } + #endif + if (local != NULL) { + fprintf(stderr, "=== have local address\n"); + if (bind(s, local->sockaddr, local->socklen) == -1) { + ngx_log_error(NGX_LOG_CRIT, &uc->log, ngx_socket_errno, + "bind(%V) failed", &local->name); + + return NGX_ERROR; + } + } + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, &uc->log, 0, "connect to %V, fd:%d #%d", &uc->server, s, c->number); diff --git a/src/ngx_http_lua_socket_udp.h b/src/ngx_http_lua_socket_udp.h index 83333461db..61245b3647 100644 --- a/src/ngx_http_lua_socket_udp.h +++ b/src/ngx_http_lua_socket_udp.h @@ -42,6 +42,8 @@ struct ngx_http_lua_socket_udp_upstream_s { ngx_http_request_t *request; ngx_http_lua_udp_connection_t udp_connection; + ngx_addr_t *local; + ngx_msec_t read_timeout; ngx_http_upstream_resolved_t *resolved; @@ -53,7 +55,7 @@ struct ngx_http_lua_socket_udp_upstream_s { ngx_http_lua_co_ctx_t *co_ctx; - unsigned waiting; /* :1 */ + unsigned waiting:1; /* :1 */ }; diff --git a/t/062-count.t b/t/062-count.t index 07605f95b9..957590292b 100644 --- a/t/062-count.t +++ b/t/062-count.t @@ -481,7 +481,7 @@ n = 16 --- request GET /test --- response_body -n = 6 +n = 7 --- no_error_log [error] diff --git a/t/087-udp-socket.t b/t/087-udp-socket.t index ffe6b13e92..d1bc654365 100644 --- a/t/087-udp-socket.t +++ b/t/087-udp-socket.t @@ -4,7 +4,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * (3 * blocks() + 15); +plan tests => repeat_each() * (3 * blocks() + 16); our $HtmlDir = html_dir; @@ -1222,3 +1222,113 @@ qr/send: fd:\d+ 22 of 22 send: fd:\d+ 16 of 16 send: fd:\d+ 22 of 22/ --- log_level: debug + + + +=== TEST 23: udp bind +--- config + server_tokens off; + location /t { + #set $port 5000; + set $port $TEST_NGINX_MEMCACHED_PORT; + #set $port 1234; + + content_by_lua_block { + local socket = ngx.socket + local udp = socket.udp() + + local port = ngx.var.port + udp:settimeout(1000) -- 1 sec + + local ok, err = udp:bind("127.0.0.10") + if not ok then + ngx.say("failed to bind: ", err) + return + end + + local ok, err = udp:setpeername("127.0.0.1", port) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected") + + local req = "\0\1\0\0\0\1\0\0flush_all\r\n" + local ok, err = udp:send(req) + if not ok then + ngx.say("failed to send: ", err) + return + end + + local data, err = udp:receive() + if not data then + ngx.say("failed to receive data: ", err) + return + end + ngx.print("received ", #data, " bytes: ", data) + } + } +--- request +GET /t +--- response_body eval +"connected\nreceived 12 bytes: \x{00}\x{01}\x{00}\x{00}\x{00}\x{01}\x{00}\x{00}OK\x{0d}\x{0a}" +--- no_error_log +[error] +--- log_level: debug +--- error_log +lua udp socket receive buffer size: 65536 + + + +=== TEST 24: udp bind failed +--- config + server_tokens off; + location /t { + #set $port 5000; + set $port $TEST_NGINX_MEMCACHED_PORT; + #set $port 1234; + + content_by_lua_block { + local socket = ngx.socket + local udp = socket.udp() + + local port = ngx.var.port + udp:settimeout(1000) -- 1 sec + + local ok, err = udp:bind("127.0.0.1000") + if not ok then + ngx.say("failed to bind: ", err) + return + end + + local ok, err = udp:setpeername("127.0.0.1", port) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected") + + local req = "\0\1\0\0\0\1\0\0flush_all\r\n" + local ok, err = udp:send(req) + if not ok then + ngx.say("failed to send: ", err) + return + end + + local data, err = udp:receive() + if not data then + ngx.say("failed to receive data: ", err) + return + end + ngx.print("received ", #data, " bytes: ", data) + } + } +--- request +GET /t +--- response_body +failed to bind: bad address +--- no_error_log +[error] +--- log_level: debug From 0189eb14f694a7c1f57a4f6efeec90fa0298f368 Mon Sep 17 00:00:00 2001 From: bas-vk Date: Sun, 10 Mar 2024 13:53:59 +0100 Subject: [PATCH 155/254] feature: add suport for deriving key from tls master secret. Co-authored-by: Bas van Kervel Co-authored-by: lijunlong --- config | 2 + src/ngx_http_lua_ssl_export_keying_material.c | 113 ++++++++++++++++++ src/ngx_http_lua_ssl_export_keying_material.h | 24 ++++ 3 files changed, 139 insertions(+) create mode 100644 src/ngx_http_lua_ssl_export_keying_material.c create mode 100644 src/ngx_http_lua_ssl_export_keying_material.h diff --git a/config b/config index 0e572c8bea..0266e308a5 100644 --- a/config +++ b/config @@ -289,6 +289,7 @@ HTTP_LUA_SRCS=" \ $ngx_addon_dir/src/ngx_http_lua_worker.c \ $ngx_addon_dir/src/ngx_http_lua_ssl_client_helloby.c \ $ngx_addon_dir/src/ngx_http_lua_ssl_certby.c \ + $ngx_addon_dir/src/ngx_http_lua_ssl_export_keying_material.c \ $ngx_addon_dir/src/ngx_http_lua_ssl_ocsp.c \ $ngx_addon_dir/src/ngx_http_lua_lex.c \ $ngx_addon_dir/src/ngx_http_lua_balancer.c \ @@ -354,6 +355,7 @@ HTTP_LUA_DEPS=" \ $ngx_addon_dir/src/ngx_http_lua_ssl_certby.h \ $ngx_addon_dir/src/ngx_http_lua_lex.h \ $ngx_addon_dir/src/ngx_http_lua_balancer.h \ + $ngx_addon_dir/src/ngx_http_lua_ssl_export_keying_material.h \ $ngx_addon_dir/src/ngx_http_lua_ssl_session_storeby.h \ $ngx_addon_dir/src/ngx_http_lua_ssl_session_fetchby.h \ $ngx_addon_dir/src/ngx_http_lua_ssl.h \ diff --git a/src/ngx_http_lua_ssl_export_keying_material.c b/src/ngx_http_lua_ssl_export_keying_material.c new file mode 100644 index 0000000000..45c791bb2b --- /dev/null +++ b/src/ngx_http_lua_ssl_export_keying_material.c @@ -0,0 +1,113 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef DDEBUG +#define DDEBUG 0 +#endif + + +#include "ddebug.h" + +#if (NGX_HTTP_SSL) + +#include + +#include "ngx_http_lua_cache.h" +#include "ngx_http_lua_initworkerby.h" +#include "ngx_http_lua_util.h" +#include "ngx_http_ssl_module.h" +#include "ngx_http_lua_contentby.h" +#include "ngx_http_lua_ssl_session_fetchby.h" +#include "ngx_http_lua_ssl.h" +#include "ngx_http_lua_directive.h" +#include "ngx_http_lua_ssl_export_keying_material.h" + + +ngx_int_t +ngx_http_lua_ffi_ssl_export_keying_material(ngx_http_request_t *r, + u_char *out, size_t out_size, const char *label, size_t llen, + const u_char *context, size_t ctxlen, int use_ctx, char **err) +{ +#if OPENSSL_VERSION_NUMBER < 0x10101000L + *err = "OpenSSL too old"; + return NGX_ERROR; +#else + ngx_connection_t *c; + ngx_ssl_conn_t *ssl_conn; + int rc; + + c = r->connection; + if (c == NULL || c->ssl == NULL) { + *err = "bad request"; + return NGX_ERROR; + } + + ssl_conn = c->ssl->connection; + if (ssl_conn == NULL) { + *err = "bad ssl connection"; + return NGX_ERROR; + } + + rc = SSL_export_keying_material(ssl_conn, out, out_size, label, llen, + context, ctxlen, use_ctx); + if (rc == 1) { + return NGX_OK; + } + + ngx_ssl_error(NGX_LOG_INFO, c->log, 0, + "SSL_export_keying_material rc: %d, error: %s", + rc, ERR_error_string(ERR_get_error(), NULL)); + + *err = "SSL_export_keying_material() failed"; + + return NGX_ERROR; +#endif +} + + +ngx_int_t +ngx_http_lua_ffi_ssl_export_keying_material_early(ngx_http_request_t *r, + u_char *out, size_t out_size, const char *label, size_t llen, + const u_char *context, size_t ctxlen, char **err) +{ +#if OPENSSL_VERSION_NUMBER < 0x10101000L + *err = "OpenSSL too old"; + return NGX_ERROR; +#else + int rc; + ngx_ssl_conn_t *ssl_conn; + ngx_connection_t *c; + + c = r->connection; + if (c == NULL || c->ssl == NULL) { + *err = "bad request"; + return NGX_ERROR; + } + + ssl_conn = c->ssl->connection; + if (ssl_conn == NULL) { + *err = "bad ssl connection"; + return NGX_ERROR; + } + + rc = SSL_export_keying_material_early(ssl_conn, out, out_size, + label, llen, context, ctxlen); + + if (rc == 1) { + return NGX_OK; + } + + ngx_ssl_error(NGX_LOG_INFO, c->log, 0, + "SSL_export_keying_material_early rc: %d, error: %s", + rc, ERR_error_string(ERR_get_error(), NULL)); + + *err = "SSL_export_keying_material_early() failed"; + + return NGX_ERROR; +#endif +} + +#endif /* NGX_HTTP_SSL */ diff --git a/src/ngx_http_lua_ssl_export_keying_material.h b/src/ngx_http_lua_ssl_export_keying_material.h new file mode 100644 index 0000000000..7a54bcda35 --- /dev/null +++ b/src/ngx_http_lua_ssl_export_keying_material.h @@ -0,0 +1,24 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef _NGX_HTTP_LUA_SSL_EXPORT_KEYING_MATERIAL_H_INCLUDED_ +#define _NGX_HTTP_LUA_SSL_EXPORT_KEYING_MATERIAL_H_INCLUDED_ + +#include "ngx_http_lua_common.h" + +#if (NGX_HTTP_SSL) +ngx_int_t ngx_http_lua_ffi_ssl_export_keying_material(ngx_http_request_t *r, + u_char *out, size_t out_size, const char *label, size_t llen, + const u_char *ctx, size_t ctxlen, int use_ctx, char **err); + +ngx_int_t ngx_http_lua_ffi_ssl_export_keying_material_early( + ngx_http_request_t *r, u_char *out, size_t out_size, const char *label, + size_t llen, const u_char *ctx, size_t ctxlen, char **err); +#endif + +#endif /* _NGX_HTTP_LUA_SSL_EXPORT_KEYING_MATERIAL_H_INCLUDED_ */ + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ From 76e3d67a0498bd44d7e0c1c4eb60b60629ff1260 Mon Sep 17 00:00:00 2001 From: Elvin Efendi Date: Sun, 10 Mar 2024 10:36:00 -0400 Subject: [PATCH 156/254] feature: validate and expose nextUpdate field in OCSP response. --- src/ngx_http_lua_ssl_ocsp.c | 49 +++++++++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/src/ngx_http_lua_ssl_ocsp.c b/src/ngx_http_lua_ssl_ocsp.c index d1805b23dd..c9f24cd281 100644 --- a/src/ngx_http_lua_ssl_ocsp.c +++ b/src/ngx_http_lua_ssl_ocsp.c @@ -19,8 +19,9 @@ #ifdef NGX_HTTP_LUA_USE_OCSP static int ngx_http_lua_ssl_empty_status_callback(ngx_ssl_conn_t *ssl_conn, void *data); -#endif +static long ngx_http_lua_ssl_stapling_time(ASN1_GENERALIZEDTIME *asn1time); +#endif int ngx_http_lua_ffi_ssl_get_ocsp_responder_from_der_chain( @@ -262,7 +263,7 @@ ngx_http_lua_ffi_ssl_create_ocsp_request(const char *chain_data, int ngx_http_lua_ffi_ssl_validate_ocsp_response(const u_char *resp, size_t resp_len, const char *chain_data, size_t chain_len, - u_char *errbuf, size_t *errbuf_size) + u_char *errbuf, size_t *errbuf_size, long *valid) { #ifndef NGX_HTTP_LUA_USE_OCSP @@ -383,6 +384,16 @@ ngx_http_lua_ffi_ssl_validate_ocsp_response(const u_char *resp, goto error; } + if (nextupdate) { + *valid = ngx_http_lua_ssl_stapling_time(nextupdate); + if (*valid == NGX_ERROR) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, + "invalid nextUpdate time " + "in certificate status") - errbuf; + goto error; + } + } + sk_X509_free(chain); X509_free(cert); X509_free(issuer); @@ -437,6 +448,40 @@ ngx_http_lua_ssl_empty_status_callback(ngx_ssl_conn_t *ssl_conn, void *data) { return SSL_TLSEXT_ERR_OK; } + + +static long +ngx_http_lua_ssl_stapling_time(ASN1_GENERALIZEDTIME *asn1time) +{ + BIO *bio; + char *value; + size_t len; + time_t time; + + /* + * OpenSSL doesn't provide a way to convert ASN1_GENERALIZEDTIME + * into long. To do this, we use ASN1_GENERALIZEDTIME_print(), + * which uses the "MMM DD HH:MM:SS YYYY [GMT]" format (e.g., + * "Feb 3 00:55:52 2015 GMT"), and parse the result. + */ + + bio = BIO_new(BIO_s_mem()); + if (bio == NULL) { + return NGX_ERROR; + } + + /* fake weekday prepended to match C asctime() format */ + + BIO_write(bio, "Tue ", sizeof("Tue ") - 1); + ASN1_GENERALIZEDTIME_print(bio, asn1time); + len = BIO_get_mem_data(bio, &value); + + time = ngx_parse_http_time((u_char *) value, len); + + BIO_free(bio); + + return time; +} #endif From f725c60ea0e580b046e51e9bc8ee4cdec5eb6b40 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Sun, 10 Mar 2024 22:56:57 +0800 Subject: [PATCH 157/254] bugfix: Fixing compatibility issues with BoringSSL. --- src/ngx_http_lua_ssl_export_keying_material.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/ngx_http_lua_ssl_export_keying_material.c b/src/ngx_http_lua_ssl_export_keying_material.c index 45c791bb2b..ec64c049a9 100644 --- a/src/ngx_http_lua_ssl_export_keying_material.c +++ b/src/ngx_http_lua_ssl_export_keying_material.c @@ -31,7 +31,13 @@ ngx_http_lua_ffi_ssl_export_keying_material(ngx_http_request_t *r, u_char *out, size_t out_size, const char *label, size_t llen, const u_char *context, size_t ctxlen, int use_ctx, char **err) { -#if OPENSSL_VERSION_NUMBER < 0x10101000L +#if defined(OPENSSL_IS_BORINGSSL) || OPENSSL_VERSION_NUMBER < 0x10101000L + *err = "BoringSSL does not support SSL_export_keying_material"; + return NGX_ERROR; +#elif defined(LIBRESSL_VERSION_NUMBER) + *err = "LibreSSL does not support SSL_export_keying_material"; + return NGX_ERROR; +#elif OPENSSL_VERSION_NUMBER < 0x10101000L *err = "OpenSSL too old"; return NGX_ERROR; #else @@ -73,7 +79,13 @@ ngx_http_lua_ffi_ssl_export_keying_material_early(ngx_http_request_t *r, u_char *out, size_t out_size, const char *label, size_t llen, const u_char *context, size_t ctxlen, char **err) { -#if OPENSSL_VERSION_NUMBER < 0x10101000L +#if defined(OPENSSL_IS_BORINGSSL) || OPENSSL_VERSION_NUMBER < 0x10101000L + *err = "BoringSSL does not support SSL_export_keying_material"; + return NGX_ERROR; +#elif defined(LIBRESSL_VERSION_NUMBER) + *err = "LibreSSL does not support SSL_export_keying_material"; + return NGX_ERROR; +#elif OPENSSL_VERSION_NUMBER < 0x10101000L *err = "OpenSSL too old"; return NGX_ERROR; #else From e2067ddd2b2897d3c6fa6f91ce4e8169fe8c97c6 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Wed, 20 Mar 2024 12:02:38 +0800 Subject: [PATCH 158/254] bugfix: wrong arguments of setkeepalive() result in the compromise of data integrity. ==338736== Invalid read of size 8 ==338736== at 0x209890: ngx_http_lua_socket_tcp_handler (ngx_http_lua_socket_tcp.c:3341) ==338736== by 0x16CB21: ngx_epoll_process_events (ngx_epoll_module.c:1001) ==338736== by 0x160213: ngx_process_events_and_timers (ngx_event.c:262) ==338736== by 0x16B772: ngx_single_process_cycle (ngx_process_cycle.c:338) ==338736== by 0x13E8B7: main (nginx.c:394) ==338736== Address 0x68c8678 is 8 bytes inside a block of size 1,488 free'd ==338736== at 0x48472AC: free (vg_replace_malloc.c:974) ==338736== by 0x14035D: ngx_destroy_pool (ngx_palloc.c:76) ==338736== by 0x18694E: ngx_http_free_request (ngx_http_request.c:3799) ==338736== by 0x186AE0: ngx_http_close_request (ngx_http_request.c:3708) ==338736== by 0x187A6A: ngx_http_finalize_connection (ngx_http_request.c:2812) ==338736== by 0x1887C7: ngx_http_finalize_request (ngx_http_request.c:2685) ==338736== by 0x1883CC: ngx_http_finalize_request (ngx_http_request.c:2571) ==338736== by 0x2010B2: ngx_http_lua_finalize_request (ngx_http_lua_util.c:3706) ==338736== by 0x20B6A1: ngx_http_lua_socket_tcp_resume_helper (ngx_http_lua_socket_tcp.c:6132) ==338736== by 0x20BA75: ngx_http_lua_socket_tcp_read_resume (ngx_http_lua_socket_tcp.c:6030) ==338736== by 0x20356B: ngx_http_lua_content_wev_handler (ngx_http_lua_contentby.c:152) ==338736== by 0x20CA9F: ngx_http_lua_socket_handle_read_success (ngx_http_lua_socket_tcp.c:3602) ==338736== by 0x20CA9F: ngx_http_lua_socket_tcp_read (ngx_http_lua_socket_tcp.c:2607) ==338736== by 0x20D289: ngx_http_lua_socket_read_handler (ngx_http_lua_socket_tcp.c:3405) ==338736== by 0x20991D: ngx_http_lua_socket_tcp_handler (ngx_http_lua_socket_tcp.c:3356) ==338736== by 0x16C970: ngx_epoll_process_events (ngx_epoll_module.c:968) ==338736== by 0x160213: ngx_process_events_and_timers (ngx_event.c:262) ==338736== by 0x16B772: ngx_single_process_cycle (ngx_process_cycle.c:338) ==338736== by 0x13E8B7: main (nginx.c:394) ==338736== Block was alloc'd at ==338736== at 0x484482F: malloc (vg_replace_malloc.c:431) ==338736== by 0x165448: ngx_alloc (ngx_alloc.c:22) ==338736== by 0x1401B2: ngx_malloc (ngx_palloc.c:137) ==338736== by 0x1403EC: ngx_palloc (ngx_palloc.c:120) ==338736== by 0x140503: ngx_pcalloc (ngx_palloc.c:215) ==338736== by 0x185BC9: ngx_http_alloc_request (ngx_http_request.c:580) ==338736== by 0x186356: ngx_http_create_request (ngx_http_request.c:536) ==338736== by 0x189F2A: ngx_http_wait_request_handler (ngx_http_request.c:518) ==338736== by 0x16C970: ngx_epoll_process_events (ngx_epoll_module.c:968) ==338736== by 0x160213: ngx_process_events_and_timers (ngx_event.c:262) ==338736== by 0x16B772: ngx_single_process_cycle (ngx_process_cycle.c:338) ==338736== by 0x13E8B7: main (nginx.c:394) ==338736== --- src/ngx_http_lua_socket_tcp.c | 50 ++++++----- t/068-socket-keepalive.t | 160 ++++++++++++++++++++++++++++++++++ 2 files changed, 188 insertions(+), 22 deletions(-) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 0aa7109758..214e78329e 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -5379,6 +5379,34 @@ ngx_http_lua_socket_tcp_setkeepalive(lua_State *L) luaL_checktype(L, 1, LUA_TTABLE); + r = ngx_http_lua_get_req(L); + if (r == NULL) { + return luaL_error(L, "no request found"); + } + + llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); + + /* luaL_checkinteger will throw error if the argument is not a number. + * e.g.: bad argument \#2 to '?' (number expected, got string) + * + * We should check the argument in advance; otherwise, + * throwing an exception in the middle can compromise data integrity. + * e.g.: set pc->connection to NULL without following cleanup. + */ + if (n >= 2 && !lua_isnil(L, 2)) { + timeout = (ngx_msec_t) luaL_checkinteger(L, 2); + + } else { + timeout = llcf->keepalive_timeout; + } + + if (n >= 3 && !lua_isnil(L, 3)) { + pool_size = luaL_checkinteger(L, 3); + + } else { + pool_size = llcf->pool_size; + } + lua_rawgeti(L, 1, SOCKET_CTX_INDEX); u = lua_touserdata(L, -1); lua_pop(L, 1); @@ -5405,11 +5433,6 @@ ngx_http_lua_socket_tcp_setkeepalive(lua_State *L) return 2; } - r = ngx_http_lua_get_req(L); - if (r == NULL) { - return luaL_error(L, "no request found"); - } - if (u->request != r) { return luaL_error(L, "bad request"); } @@ -5480,18 +5503,8 @@ ngx_http_lua_socket_tcp_setkeepalive(lua_State *L) /* stack: obj timeout? size? pools cache_key */ - llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); - if (spool == NULL) { /* create a new socket pool for the current peer key */ - - if (n >= 3 && !lua_isnil(L, 3)) { - pool_size = luaL_checkinteger(L, 3); - - } else { - pool_size = llcf->pool_size; - } - if (pool_size <= 0) { msg = lua_pushfstring(L, "bad \"pool_size\" option value: %d", pool_size); @@ -5555,13 +5568,6 @@ ngx_http_lua_socket_tcp_setkeepalive(lua_State *L) ngx_del_timer(c->write); } - if (n >= 2 && !lua_isnil(L, 2)) { - timeout = (ngx_msec_t) luaL_checkinteger(L, 2); - - } else { - timeout = llcf->keepalive_timeout; - } - #if (NGX_DEBUG) if (timeout == 0) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, diff --git a/t/068-socket-keepalive.t b/t/068-socket-keepalive.t index 5ca94e4b72..1660a3a361 100644 --- a/t/068-socket-keepalive.t +++ b/t/068-socket-keepalive.t @@ -3029,3 +3029,163 @@ connected: 1, reused: 0 --- error_log lua tcp socket keepalive create connection pool for key "A" lua tcp socket keepalive create connection pool for key "B" + + + +=== TEST 54: wrong first argument for setkeepalive +--- quic_max_idle_timeout: 1.2 +--- http_config eval + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" +--- config + server_tokens off; + location /t { + keepalive_timeout 60s; + + set $port $TEST_NGINX_SERVER_PORT; + content_by_lua_block { + local port = ngx.var.port + + local sock = ngx.socket.tcp() + + local ok, err = sock:connect("127.0.0.1", port) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local req = "GET /foo HTTP/1.1\r\nHost: localhost\r\nConnection: keepalive\r\n\r\n" + + local bytes, err = sock:send(req) + if not bytes then + ngx.say("failed to send request: ", err) + return + end + + ngx.say("request sent: ", bytes) + + local reader = sock:receiveuntil("\r\n0\r\n\r\n") + local data, err = reader() + + if not data then + ngx.say("failed to receive response body: ", err) + return + end + + ngx.say("received response of ", #data, " bytes") + + ok, err = sock:setkeepalive() + if not ok then + ngx.say("failed to set reusable: ", err) + end + + ok, err = sock:connect("127.0.0.1", port) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ok, err = sock:setkeepalive("not a number", "not a number") + if not ok then + ngx.say("failed to set reusable: ", err) + end + } + } + + location /foo { + echo foo; + } + + location /sleep { + echo_sleep 1; + } +--- request +GET /t +--- error_code: +--- response_body +--- error_log eval +qr/\Qbad argument #1 to 'setkeepalive' (number expected, got string)\E/ +--- no_error_log +[crit] +--- timeout: 4 + + + +=== TEST 55: wrong second argument for setkeepalive +--- quic_max_idle_timeout: 1.2 +--- http_config eval + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" +--- config + server_tokens off; + location /t { + keepalive_timeout 60s; + + set $port $TEST_NGINX_SERVER_PORT; + content_by_lua_block { + local port = ngx.var.port + + local sock = ngx.socket.tcp() + + local ok, err = sock:connect("127.0.0.1", port) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local req = "GET /foo HTTP/1.1\r\nHost: localhost\r\nConnection: keepalive\r\n\r\n" + + local bytes, err = sock:send(req) + if not bytes then + ngx.say("failed to send request: ", err) + return + end + + ngx.say("request sent: ", bytes) + + local reader = sock:receiveuntil("\r\n0\r\n\r\n") + local data, err = reader() + + if not data then + ngx.say("failed to receive response body: ", err) + return + end + + ngx.say("received response of ", #data, " bytes") + + ok, err = sock:setkeepalive() + if not ok then + ngx.say("failed to set reusable: ", err) + end + + ok, err = sock:connect("127.0.0.1", port) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ok, err = sock:setkeepalive(10, "not a number") + if not ok then + ngx.say("failed to set reusable: ", err) + end + } + } + + location /foo { + echo foo; + } + + location /sleep { + echo_sleep 1; + } +--- request +GET /t +--- error_code: +--- response_body +--- error_log eval +qr/\Qbad argument #2 to 'setkeepalive' (number expected, got string)\E/ +--- no_error_log +[crit] +--- timeout: 4 From 6c00bd4765ec5f7bf090a2c6424d11845fc4ab72 Mon Sep 17 00:00:00 2001 From: Liu Wei <375636559@qq.com> Date: Thu, 11 Apr 2024 20:54:19 +0800 Subject: [PATCH 159/254] bugfix: the connection won't be closed normally when set arg[1] = "" before arg[2] = true. --- src/ngx_http_lua_bodyfilterby.c | 18 ++++++++++++-- t/082-body-filter-2.t | 44 +++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 2 deletions(-) diff --git a/src/ngx_http_lua_bodyfilterby.c b/src/ngx_http_lua_bodyfilterby.c index 78e3b5c2d6..c0484c8de0 100644 --- a/src/ngx_http_lua_bodyfilterby.c +++ b/src/ngx_http_lua_bodyfilterby.c @@ -532,9 +532,23 @@ ngx_http_lua_body_filter_param_set(lua_State *L, ngx_http_request_t *r, if (last) { ctx->seen_last_in_filter = 1; - /* the "in" chain cannot be NULL and we set the "last_buf" or - * "last_in_chain" flag in the last buf of "in" */ + /* the "in" chain cannot be NULL except that we set arg[1] = "" + * before arg[2] = true + */ + if (in == NULL) { + in = ngx_http_lua_chain_get_free_buf(r->connection->log, + r->pool, + &ctx->free_bufs, 0); + if (in == NULL) { + return luaL_error(L, "no memory"); + } + + in->buf->tag = (ngx_buf_tag_t) &ngx_http_lua_body_filter; + lmcf->body_filter_chain = in; + } + /* we set the "last_buf" or "last_in_chain" flag + * in the last buf of "in" */ for (cl = in; cl; cl = cl->next) { if (cl->next == NULL) { if (r == r->main) { diff --git a/t/082-body-filter-2.t b/t/082-body-filter-2.t index ffccad28ab..3c9b9797d5 100644 --- a/t/082-body-filter-2.t +++ b/t/082-body-filter-2.t @@ -225,3 +225,47 @@ GET /t [error] [alert] [crit] + + + +=== TEST 4: set resp body nil with ngx.arg[1] first +--- config + location /t { + content_by_lua_block { + ngx.say("Hello World!") + } + + body_filter_by_lua_block { + ngx.arg[1] = "" + ngx.arg[2] = true + } + } +--- request +GET /t +--- response_body +--- no_error_log +[error] +[alert] +[crit] + + + +=== TEST 5: set resp body nil with ngx.arg[2] first +--- config + location /t { + content_by_lua_block { + ngx.say("Hello World!") + } + + body_filter_by_lua_block { + ngx.arg[2] = true + ngx.arg[1] = "" + } + } +--- request +GET /t +--- response_body +--- no_error_log +[error] +[alert] +[crit] From c1d309284d26e7ba44c155758a85ef793505b2b2 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Mon, 27 May 2024 11:40:03 +0800 Subject: [PATCH 160/254] bugfix: worker thread Lua VM may take lots of memory. --- README.markdown | 4 +- src/ngx_http_lua_module.c | 2 +- src/ngx_http_lua_worker_thread.c | 12 +++++- t/166-worker-thread.t | 71 ++++++++++++++++++++++++++++++++ 4 files changed, 86 insertions(+), 3 deletions(-) diff --git a/README.markdown b/README.markdown index dc0380159e..51607e7f36 100644 --- a/README.markdown +++ b/README.markdown @@ -3599,7 +3599,7 @@ lua_worker_thread_vm_pool_size **syntax:** *lua_worker_thread_vm_pool_size <size>* -**default:** *lua_worker_thread_vm_pool_size 100* +**default:** *lua_worker_thread_vm_pool_size 10* **context:** *http* @@ -3611,6 +3611,8 @@ The Lua VM in the VM pool is used to execute Lua code in separate thread. The pool is global at Nginx worker level. And it is used to reuse Lua VMs between requests. +**Warning:** Each worker thread uses a separate Lua VM and caches the Lua VM for reuse in subsequent operations. Configuring too many worker threads can result in consuming a lot of memory. + [Back to TOC](#directives) Nginx API for Lua diff --git a/src/ngx_http_lua_module.c b/src/ngx_http_lua_module.c index fb10bf933e..f64ab89315 100644 --- a/src/ngx_http_lua_module.c +++ b/src/ngx_http_lua_module.c @@ -1141,7 +1141,7 @@ ngx_http_lua_init_main_conf(ngx_conf_t *cf, void *conf) #endif if (lmcf->worker_thread_vm_pool_size == NGX_CONF_UNSET_UINT) { - lmcf->worker_thread_vm_pool_size = 100; + lmcf->worker_thread_vm_pool_size = 10; } if (ngx_http_lua_init_builtin_headers_out(cf, lmcf) != NGX_OK) { diff --git a/src/ngx_http_lua_worker_thread.c b/src/ngx_http_lua_worker_thread.c index 3820d6377c..ad747e8104 100644 --- a/src/ngx_http_lua_worker_thread.c +++ b/src/ngx_http_lua_worker_thread.c @@ -194,11 +194,21 @@ ngx_http_lua_get_task_ctx(lua_State *L, ngx_http_request_t *r) static void ngx_http_lua_free_task_ctx(ngx_http_lua_task_ctx_t *ctx) { + lua_State *vm; + ctx->next = ctxpool->next; ctxpool->next = ctx; /* clean Lua stack */ - lua_settop(ctx->vm, 0); + vm = ctx->vm; + + /* call collectgarbage("collect") */ + lua_settop(vm, 0); + lua_getglobal(vm, "collectgarbage"); + lua_pushstring(vm, "collect"); + lua_pcall(vm, 1, 1, 0); + + lua_settop(vm, 0); } diff --git a/t/166-worker-thread.t b/t/166-worker-thread.t index 925a060949..1cbeec5eba 100644 --- a/t/166-worker-thread.t +++ b/t/166-worker-thread.t @@ -1602,3 +1602,74 @@ return {hello=hello} GET /hello --- response_body false , suspicious circular references, table depth exceed max depth: 100 in the argument + + + +=== TEST 50: call run_worker_thread twice +--- main_config + thread_pool testpool threads=1; +--- http_config eval + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" +--- config +location /hello { + default_type 'text/plain'; + + content_by_lua_block { + local ok, hello_or_err = ngx.run_worker_thread("testpool", "hello", "hello") + ngx.say(ok, " : ", hello_or_err) + + ok, hello_or_err = ngx.run_worker_thread("testpool", "hello", "hello") + ngx.say(ok, " : ", hello_or_err) + } +} +--- user_files +>>> hello.lua +local function hello() + return "hello" +end +return {hello=hello} +--- request +GET /hello +--- response_body +true : hello +true : hello + + + +=== TEST 51: big object +--- main_config + thread_pool testpool threads=1; +--- http_config eval + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" +--- config +location /hello { + default_type 'text/plain'; + + content_by_lua_block { + local ok, hello_or_err = ngx.run_worker_thread("testpool", "hello", "hello") + ngx.say(ok, " : ", #hello_or_err) + + local ok, gcsize_or_err = ngx.run_worker_thread("testpool", "hello", "gcsize") + ngx.say(ok, " : ", gcsize_or_err) + } +} +--- user_files +>>> hello.lua +local function hello() + return string.rep("helloworld", 1000000) +end + +local function gcsize() + return collectgarbage("count") +end + +return { + hello = hello, + gcsize = gcsize +} +--- request +GET /hello +--- response_body eval +qr/\Atrue : 10000000 +true : \d{3,4}\.\d+ +\z/ms From 5bf876104cabbc02aeb59c79ddfebb0a52cff6d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BE=90=E7=91=9E=E4=B8=9C?= Date: Wed, 29 May 2024 22:07:23 +0800 Subject: [PATCH 161/254] doc: update doc for 'ngx.req.http_version'. --- README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index 51607e7f36..ba1e5bfb5f 100644 --- a/README.markdown +++ b/README.markdown @@ -4789,7 +4789,7 @@ ngx.req.http_version Returns the HTTP version number for the current request as a Lua number. -Current possible values are 2.0, 1.0, 1.1, and 0.9. Returns `nil` for unrecognized values. +Current possible values are 3.0, 2.0, 1.0, 1.1, and 0.9. Returns `nil` for unrecognized values. This method was first introduced in the `v0.7.17` release. From b5d1688ae722538ba4dc8a7ec08820a08abfb93d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ji=C5=99=C3=AD=20Setni=C4=8Dka?= Date: Wed, 5 Jun 2024 08:14:59 +0200 Subject: [PATCH 162/254] bugfix: fix config test for signalfd with gcc 11. Without the initialization, the feature test ends with: error: 'set' may be used uninitialized [-Werror=maybe-uninitialized] --- config | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/config b/config index 0266e308a5..24ebd126d6 100644 --- a/config +++ b/config @@ -462,7 +462,8 @@ ngx_feature_libs= ngx_feature_name="NGX_HTTP_LUA_HAVE_SIGNALFD" ngx_feature_run=no ngx_feature_incs="#include " -ngx_feature_test="sigset_t set; signalfd(-1, &set, SFD_NONBLOCK|SFD_CLOEXEC);" +ngx_feature_test="sigset_t set = { 0 }; + signalfd(-1, &set, SFD_NONBLOCK|SFD_CLOEXEC);" SAVED_CC_TEST_FLAGS="$CC_TEST_FLAGS" CC_TEST_FLAGS="-Werror -Wall $CC_TEST_FLAGS" From 892b7ee5e84e7e24e5976de45e6fdfdbc08233e2 Mon Sep 17 00:00:00 2001 From: Jun Ouyang Date: Fri, 28 Jun 2024 08:46:45 +0800 Subject: [PATCH 163/254] bugfix: lua-nginx-module context was clear when ngx.send_header() trigger filter_finalize case. --- src/ngx_http_lua_util.c | 4 ++++ t/002-content.t | 22 ++++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 727ca3da39..f1e0cd08f5 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -549,6 +549,10 @@ ngx_http_lua_send_header_if_needed(ngx_http_request_t *r, if (!ctx->buffering) { dd("sending headers"); rc = ngx_http_send_header(r); + if (r->filter_finalize) { + ngx_http_set_ctx(r, ctx, ngx_http_lua_module); + } + ctx->header_sent = 1; return rc; } diff --git a/t/002-content.t b/t/002-content.t index 54de40ebd5..eb9d587f89 100644 --- a/t/002-content.t +++ b/t/002-content.t @@ -1098,3 +1098,25 @@ failed to load inlined Lua code: content_by_lua(...45678901234567890123456789012 GET /lua --- response_body_like: 503 Service Temporarily Unavailable --- error_code: 503 + + + +=== TEST 52: send_header trigger filter finalize does not clear the ctx +--- config + location /lua { + content_by_lua_block { + ngx.header["Last-Modified"] = ngx.http_time(ngx.time()) + ngx.send_headers() + local phase = ngx.get_phase() + } + header_filter_by_lua_block { + ngx.header["X-Hello-World"] = "Hello World" + } + } +--- request +GET /lua +--- more_headers +If-Unmodified-Since: Wed, 01 Jan 2020 07:28:00 GMT +--- error_code: 412 +--- no_error_log +unknown phase: 0 From 4f8b94375983a47ecce4810a203e56b5ef4ed6c5 Mon Sep 17 00:00:00 2001 From: fesily Date: Mon, 1 Jul 2024 14:03:12 +0800 Subject: [PATCH 164/254] bugfix:main thread access free fake request. --- src/ngx_http_lua_initworkerby.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ngx_http_lua_initworkerby.c b/src/ngx_http_lua_initworkerby.c index 449e604ace..edb68df08a 100644 --- a/src/ngx_http_lua_initworkerby.c +++ b/src/ngx_http_lua_initworkerby.c @@ -297,6 +297,8 @@ ngx_http_lua_init_worker(ngx_cycle_t *cycle) (void) lmcf->init_worker_handler(cycle->log, lmcf, lmcf->lua); + ngx_http_lua_set_req(lmcf->lua, NULL); + ngx_destroy_pool(c->pool); return NGX_OK; From 7b6fa21abc41b86f0bd59b377fa354b8556d9f54 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Mon, 1 Jul 2024 14:43:39 +0800 Subject: [PATCH 165/254] feature: implemented keepalive pooling in 'balancer_by_lua*'. Co-authored-by: Thibault Charbonnier --- README.markdown | 24 ++ doc/HttpLuaModule.wiki | 20 + src/ngx_http_lua_balancer.c | 736 +++++++++++++++++++++++++++++++----- src/ngx_http_lua_balancer.h | 2 + src/ngx_http_lua_common.h | 19 +- src/ngx_http_lua_module.c | 13 +- 6 files changed, 709 insertions(+), 105 deletions(-) diff --git a/README.markdown b/README.markdown index ba1e5bfb5f..4957e50059 100644 --- a/README.markdown +++ b/README.markdown @@ -1144,6 +1144,7 @@ Directives * [log_by_lua_file](#log_by_lua_file) * [balancer_by_lua_block](#balancer_by_lua_block) * [balancer_by_lua_file](#balancer_by_lua_file) +* [balancer_keepalive](#balancer_keepalive) * [lua_need_request_body](#lua_need_request_body) * [ssl_client_hello_by_lua_block](#ssl_client_hello_by_lua_block) * [ssl_client_hello_by_lua_file](#ssl_client_hello_by_lua_file) @@ -2711,6 +2712,29 @@ This directive was first introduced in the `v0.10.0` release. [Back to TOC](#directives) +balancer_keepalive +------------------ + +**syntax:** *balancer_keepalive <total-connections>* + +**context:** *upstream* + +**phase:** *loading-config* + +The `total-connections` parameter sets the maximum number of idle +keepalive connections to upstream servers that are preserved in the cache of +each worker process. When this number is exceeded, the least recently used +connections are closed. + +It should be particularly noted that the keepalive directive does not limit the +total number of connections to upstream servers that an nginx worker process +can open. The connections parameter should be set to a number small enough to +let upstream servers process new incoming connections as well. + +This directive was first introduced in the `v0.10.21` release. + +[Back to TOC](#directives) + lua_need_request_body --------------------- diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 0db9dd52b0..89cf1ca707 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -2288,6 +2288,26 @@ When a relative path like foo/bar.lua is given, they will be turned This directive was first introduced in the v0.10.0 release. +== balancer_keepalive == + +'''syntax:''' ''balancer_keepalive '' + +'''context:''' ''upstream'' + +'''phase:''' ''loading-config'' + +The total-connections parameter sets the maximum number of idle +keepalive connections to upstream servers that are preserved in the cache of +each worker process. When this number is exceeded, the least recently used +connections are closed. + +It should be particularly noted that the keepalive directive does not limit the +total number of connections to upstream servers that an nginx worker process +can open. The connections parameter should be set to a number small enough to +let upstream servers process new incoming connections as well. + +This directive was first introduced in the v0.10.21 release. + == lua_need_request_body == '''syntax:''' ''lua_need_request_body '' diff --git a/src/ngx_http_lua_balancer.c b/src/ngx_http_lua_balancer.c index a8192db038..9bb770c8e6 100644 --- a/src/ngx_http_lua_balancer.c +++ b/src/ngx_http_lua_balancer.c @@ -15,10 +15,34 @@ #include "ngx_http_lua_util.h" #include "ngx_http_lua_directive.h" +#define NGX_BALANCER_DEF_HOST_LEN 32 +typedef struct { + ngx_queue_t queue; + ngx_queue_t hnode; + ngx_uint_t hash; + ngx_http_lua_srv_conf_t *lscf; + ngx_connection_t *connection; + socklen_t socklen; + ngx_sockaddr_t sockaddr; + ngx_str_t host; + /* try to avoid allocating memory from the connection pool */ + u_char host_data[NGX_BALANCER_DEF_HOST_LEN]; +} ngx_http_lua_balancer_ka_item_t; /*balancer keepalive item*/ + struct ngx_http_lua_balancer_peer_data_s { - /* the round robin data must be first */ - ngx_http_upstream_rr_peer_data_t rrp; + ngx_uint_t keepalive_requests; + ngx_msec_t keepalive_timeout; + + void *data; + + ngx_event_get_peer_pt original_get_peer; + ngx_event_free_peer_pt original_free_peer; + +#if (NGX_HTTP_SSL) + ngx_event_set_peer_session_pt original_set_session; + ngx_event_save_peer_session_pt original_save_session; +#endif ngx_http_lua_srv_conf_t *conf; ngx_http_request_t *request; @@ -29,14 +53,16 @@ struct ngx_http_lua_balancer_peer_data_s { struct sockaddr *sockaddr; socklen_t socklen; - ngx_str_t *host; - in_port_t port; + ngx_str_t host; + ngx_str_t *addr_text; int last_peer_state; #if !(HAVE_NGX_UPSTREAM_TIMEOUT_FIELDS) - unsigned cloned_upstream_conf; /* :1 */ + unsigned cloned_upstream_conf:1; #endif + + unsigned keepalive:1; }; @@ -45,6 +71,9 @@ static ngx_int_t ngx_http_lua_balancer_set_session(ngx_peer_connection_t *pc, void *data); static void ngx_http_lua_balancer_save_session(ngx_peer_connection_t *pc, void *data); +static ngx_int_t +ngx_http_lua_upstream_get_ssl_name(ngx_http_request_t *r, + ngx_http_upstream_t *u); #endif static ngx_int_t ngx_http_lua_balancer_init(ngx_conf_t *cf, ngx_http_upstream_srv_conf_t *us); @@ -56,6 +85,16 @@ static ngx_int_t ngx_http_lua_balancer_by_chunk(lua_State *L, ngx_http_request_t *r); static void ngx_http_lua_balancer_free_peer(ngx_peer_connection_t *pc, void *data, ngx_uint_t state); +static void ngx_http_lua_balancer_close(ngx_connection_t *c); +static void ngx_http_lua_balancer_dummy_handler(ngx_event_t *ev); +static void ngx_http_lua_balancer_close_handler(ngx_event_t *ev); +static ngx_connection_t *ngx_http_lua_balancer_get_cached_item( + ngx_http_lua_srv_conf_t *lscf, ngx_peer_connection_t *pc, ngx_str_t *name); +static ngx_uint_t ngx_http_lua_balancer_calc_hash(ngx_str_t *name, + struct sockaddr *sockaddr, socklen_t socklen); + + +static struct sockaddr *ngx_http_lua_balancer_default_server_sockaddr; ngx_int_t @@ -131,8 +170,10 @@ ngx_http_lua_balancer_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, u_char *name; ngx_str_t *value; ngx_http_lua_srv_conf_t *lscf = conf; + ngx_url_t url; ngx_http_upstream_srv_conf_t *uscf; + ngx_http_upstream_server_t *us; dd("enter"); @@ -188,11 +229,42 @@ ngx_http_lua_balancer_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, lscf->balancer.src_key = cache_key; + /* balancer setup */ + uscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_upstream_module); + if (uscf->servers->nelts == 0) { + us = ngx_array_push(uscf->servers); + if (us == NULL) { + return NGX_CONF_ERROR; + } + + ngx_memzero(us, sizeof(ngx_http_upstream_server_t)); + ngx_memzero(&url, sizeof(ngx_url_t)); + + ngx_str_set(&url.url, "0.0.0.1"); + url.default_port = 80; + + if (ngx_parse_url(cf->pool, &url) != NGX_OK) { + return NGX_CONF_ERROR; + } + + us->name = url.url; + us->addrs = url.addrs; + us->naddrs = url.naddrs; + + ngx_http_lua_balancer_default_server_sockaddr = us->addrs[0].sockaddr; + } + if (uscf->peer.init_upstream) { ngx_conf_log_error(NGX_LOG_WARN, cf, 0, "load balancing method redefined"); + + lscf->balancer.original_init_upstream = uscf->peer.init_upstream; + + } else { + lscf->balancer.original_init_upstream = + ngx_http_upstream_init_round_robin; } uscf->peer.init_upstream = ngx_http_lua_balancer_init; @@ -208,16 +280,58 @@ ngx_http_lua_balancer_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, static ngx_int_t -ngx_http_lua_balancer_init(ngx_conf_t *cf, - ngx_http_upstream_srv_conf_t *us) +ngx_http_lua_balancer_init(ngx_conf_t *cf, ngx_http_upstream_srv_conf_t *us) { - if (ngx_http_upstream_init_round_robin(cf, us) != NGX_OK) { + ngx_uint_t i; + ngx_uint_t bucket_cnt; + ngx_queue_t *buckets; + ngx_http_lua_srv_conf_t *lscf; + ngx_http_lua_balancer_ka_item_t *cached; + + lscf = ngx_http_conf_upstream_srv_conf(us, ngx_http_lua_module); + + ngx_conf_init_uint_value(lscf->balancer.max_cached, 32); + + if (lscf->balancer.original_init_upstream(cf, us) != NGX_OK) { return NGX_ERROR; } - /* this callback is called upon individual requests */ + lscf->balancer.original_init_peer = us->peer.init; + us->peer.init = ngx_http_lua_balancer_init_peer; + /* allocate cache items and add to free queue */ + + cached = ngx_pcalloc(cf->pool, + sizeof(ngx_http_lua_balancer_ka_item_t) + * lscf->balancer.max_cached); + if (cached == NULL) { + return NGX_ERROR; + } + + ngx_queue_init(&lscf->balancer.cache); + ngx_queue_init(&lscf->balancer.free); + + for (i = 0; i < lscf->balancer.max_cached; i++) { + ngx_queue_insert_head(&lscf->balancer.free, &cached[i].queue); + cached[i].lscf = lscf; + } + + bucket_cnt = lscf->balancer.max_cached / 2; + bucket_cnt = bucket_cnt > 0 ? bucket_cnt : 1; + buckets = ngx_pcalloc(cf->pool, sizeof(ngx_queue_t) * bucket_cnt); + + if (buckets == NULL) { + return NGX_ERROR; + } + + for (i = 0; i < bucket_cnt; i++) { + ngx_queue_init(&buckets[i]); + } + + lscf->balancer.buckets = buckets; + lscf->balancer.bucket_cnt = bucket_cnt; + return NGX_OK; } @@ -226,33 +340,38 @@ static ngx_int_t ngx_http_lua_balancer_init_peer(ngx_http_request_t *r, ngx_http_upstream_srv_conf_t *us) { - ngx_http_lua_srv_conf_t *bcf; + ngx_http_lua_srv_conf_t *lscf; ngx_http_lua_balancer_peer_data_t *bp; - bp = ngx_pcalloc(r->pool, sizeof(ngx_http_lua_balancer_peer_data_t)); - if (bp == NULL) { + lscf = ngx_http_conf_upstream_srv_conf(us, ngx_http_lua_module); + + if (lscf->balancer.original_init_peer(r, us) != NGX_OK) { return NGX_ERROR; } - r->upstream->peer.data = &bp->rrp; - - if (ngx_http_upstream_init_round_robin_peer(r, us) != NGX_OK) { + bp = ngx_pcalloc(r->pool, sizeof(ngx_http_lua_balancer_peer_data_t)); + if (bp == NULL) { return NGX_ERROR; } + bp->conf = lscf; + bp->request = r; + bp->data = r->upstream->peer.data; + bp->original_get_peer = r->upstream->peer.get; + bp->original_free_peer = r->upstream->peer.free; + + r->upstream->peer.data = bp; r->upstream->peer.get = ngx_http_lua_balancer_get_peer; r->upstream->peer.free = ngx_http_lua_balancer_free_peer; #if (NGX_HTTP_SSL) + bp->original_set_session = r->upstream->peer.set_session; + bp->original_save_session = r->upstream->peer.save_session; + r->upstream->peer.set_session = ngx_http_lua_balancer_set_session; r->upstream->peer.save_session = ngx_http_lua_balancer_save_session; #endif - bcf = ngx_http_conf_upstream_srv_conf(us, ngx_http_lua_module); - - bp->conf = bcf; - bp->request = r; - return NGX_OK; } @@ -260,25 +379,26 @@ ngx_http_lua_balancer_init_peer(ngx_http_request_t *r, static ngx_int_t ngx_http_lua_balancer_get_peer(ngx_peer_connection_t *pc, void *data) { + void *pdata; lua_State *L; ngx_int_t rc; + ngx_connection_t *c; ngx_http_request_t *r; + ngx_http_upstream_t *u; ngx_http_lua_ctx_t *ctx; ngx_http_lua_srv_conf_t *lscf; - ngx_http_lua_main_conf_t *lmcf; ngx_http_lua_balancer_peer_data_t *bp = data; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, - "lua balancer peer, tries: %ui", pc->tries); - - lscf = bp->conf; + "lua balancer: get peer, tries: %ui", pc->tries); r = bp->request; + u = r->upstream; + lscf = bp->conf; ngx_http_lua_assert(lscf->balancer.handler && r); ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); - if (ctx == NULL) { ctx = ngx_http_lua_create_ctx(r); if (ctx == NULL) { @@ -299,18 +419,18 @@ ngx_http_lua_balancer_get_peer(ngx_peer_connection_t *pc, void *data) bp->sockaddr = NULL; bp->socklen = 0; bp->more_tries = 0; + bp->keepalive_requests = 0; + bp->keepalive_timeout = 0; + bp->keepalive = 0; bp->total_tries++; - lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); - - /* balancer_by_lua does not support yielding and - * there cannot be any conflicts among concurrent requests, - * thus it is safe to store the peer data in the main conf. - */ - lmcf->balancer_peer_data = bp; + pdata = r->upstream->peer.data; + r->upstream->peer.data = bp; rc = lscf->balancer.handler(r, lscf, L); + r->upstream->peer.data = pdata; + if (rc == NGX_ERROR) { return NGX_ERROR; } @@ -335,22 +455,53 @@ ngx_http_lua_balancer_get_peer(ngx_peer_connection_t *pc, void *data) if (bp->sockaddr && bp->socklen) { pc->sockaddr = bp->sockaddr; pc->socklen = bp->socklen; + pc->name = bp->addr_text; pc->cached = 0; pc->connection = NULL; - pc->name = bp->host; - - bp->rrp.peers->single = 0; if (bp->more_tries) { r->upstream->peer.tries += bp->more_tries; } - dd("tries: %d", (int) r->upstream->peer.tries); + if (bp->keepalive) { +#if (NGX_HTTP_SSL) + if (bp->host.len == 0 && u->ssl) { + ngx_http_lua_upstream_get_ssl_name(r, u); + bp->host = u->ssl_name; + } +#endif + + c = ngx_http_lua_balancer_get_cached_item(lscf, pc, &bp->host); + + if (c) { + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, pc->log, 0, + "lua balancer: keepalive reusing connection %p," + " host: %V, name: %V", + c, bp->addr_text, &bp->host); + return NGX_DONE; + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0, + "lua balancer: keepalive no free connection, " + "host: %V, name: %v", bp->addr_text, &bp->host); + } return NGX_OK; } - return ngx_http_upstream_get_round_robin_peer(pc, &bp->rrp); + rc = bp->original_get_peer(pc, bp->data); + if (rc == NGX_ERROR) { + return rc; + } + + if (pc->sockaddr == ngx_http_lua_balancer_default_server_sockaddr) { + ngx_log_error(NGX_LOG_ERR, pc->log, 0, + "lua balancer: no peer set"); + + return NGX_ERROR; + } + + return rc; } @@ -413,10 +564,20 @@ static void ngx_http_lua_balancer_free_peer(ngx_peer_connection_t *pc, void *data, ngx_uint_t state) { - ngx_http_lua_balancer_peer_data_t *bp = data; + ngx_uint_t hash; + ngx_str_t *host; + ngx_queue_t *q; + ngx_connection_t *c; + ngx_http_upstream_t *u; + ngx_http_lua_balancer_ka_item_t *item; + ngx_http_lua_balancer_peer_data_t *bp = data; + ngx_http_lua_srv_conf_t *lscf = bp->conf; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, - "lua balancer free peer, tries: %ui", pc->tries); + "lua balancer: free peer, tries: %ui", pc->tries); + + u = bp->request->upstream; + c = pc->connection; if (bp->sockaddr && bp->socklen) { bp->last_peer_state = (int) state; @@ -425,12 +586,206 @@ ngx_http_lua_balancer_free_peer(ngx_peer_connection_t *pc, void *data, pc->tries--; } + if (bp->keepalive) { + if (state & NGX_PEER_FAILED + || c == NULL + || c->read->eof + || c->read->error + || c->read->timedout + || c->write->error + || c->write->timedout) + { + goto invalid; + } + + if (bp->keepalive_requests + && c->requests >= bp->keepalive_requests) + { + goto invalid; + } + + if (!u->keepalive) { + goto invalid; + } + + if (!u->request_body_sent) { + goto invalid; + } + + if (ngx_terminate || ngx_exiting) { + goto invalid; + } + + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + goto invalid; + } + + if (ngx_queue_empty(&lscf->balancer.free)) { + q = ngx_queue_last(&lscf->balancer.cache); + + item = ngx_queue_data(q, ngx_http_lua_balancer_ka_item_t, + queue); + ngx_queue_remove(q); + ngx_queue_remove(&item->hnode); + + ngx_http_lua_balancer_close(item->connection); + + } else { + q = ngx_queue_head(&lscf->balancer.free); + ngx_queue_remove(q); + + item = ngx_queue_data(q, ngx_http_lua_balancer_ka_item_t, + queue); + } + + host = &bp->host; + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, pc->log, 0, + "lua balancer: keepalive saving connection %p, " + "host: %V, name: %V", + c, bp->addr_text, host); + + ngx_queue_insert_head(&lscf->balancer.cache, q); + hash = ngx_http_lua_balancer_calc_hash(host, + bp->sockaddr, bp->socklen); + item->hash = hash; + hash %= lscf->balancer.bucket_cnt; + ngx_queue_insert_head(&lscf->balancer.buckets[hash], &item->hnode); + item->connection = c; + pc->connection = NULL; + + c->read->delayed = 0; + ngx_add_timer(c->read, bp->keepalive_timeout); + + if (c->write->timer_set) { + ngx_del_timer(c->write); + } + + c->write->handler = ngx_http_lua_balancer_dummy_handler; + c->read->handler = ngx_http_lua_balancer_close_handler; + + c->data = item; + c->idle = 1; + c->log = ngx_cycle->log; + c->read->log = ngx_cycle->log; + c->write->log = ngx_cycle->log; + c->pool->log = ngx_cycle->log; + + item->socklen = pc->socklen; + ngx_memcpy(&item->sockaddr, pc->sockaddr, pc->socklen); + if (host->data && host->len) { + if (host->len <= sizeof(item->host_data)) { + ngx_memcpy(item->host_data, host->data, host->len); + item->host.data = item->host_data; + item->host.len = host->len; + + } else { + item->host.data = ngx_pstrdup(c->pool, bp->addr_text); + if (item->host.data == NULL) { + ngx_http_lua_balancer_close(c); + + ngx_queue_remove(&item->queue); + ngx_queue_remove(&item->hnode); + ngx_queue_insert_head(&item->lscf->balancer.free, + &item->queue); + return; + } + + item->host.len = bp->addr_text->len; + } + + } else { + ngx_str_null(&item->host); + } + + if (c->read->ready) { + ngx_http_lua_balancer_close_handler(c->read); + } + + return; + +invalid: + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, + "lua balancer: keepalive not saving connection %p", + c); + } + return; } - /* fallback */ + bp->original_free_peer(pc, bp->data, state); +} + + +static void +ngx_http_lua_balancer_close(ngx_connection_t *c) +{ +#if (NGX_HTTP_SSL) + if (c->ssl) { + c->ssl->no_wait_shutdown = 1; + c->ssl->no_send_shutdown = 1; + + if (ngx_ssl_shutdown(c) == NGX_AGAIN) { + c->ssl->handler = ngx_http_lua_balancer_close; + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "lua balancer: keepalive shutdown " + "connection %p failed", c); + return; + } + } +#endif + + ngx_destroy_pool(c->pool); + ngx_close_connection(c); - ngx_http_upstream_free_round_robin_peer(pc, data, state); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "lua balancer: keepalive closing connection %p", c); +} + + +static void +ngx_http_lua_balancer_dummy_handler(ngx_event_t *ev) +{ + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ev->log, 0, + "lua balancer: dummy handler"); +} + + +static void +ngx_http_lua_balancer_close_handler(ngx_event_t *ev) +{ + ngx_http_lua_balancer_ka_item_t *item; + + int n; + char buf[1]; + ngx_connection_t *c; + + c = ev->data; + if (c->close || c->read->timedout) { + goto close; + } + + n = recv(c->fd, buf, 1, MSG_PEEK); + + if (n == -1 && ngx_socket_errno == NGX_EAGAIN) { + ev->ready = 0; + + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + goto close; + } + + return; + } + +close: + + item = c->data; + c->log = ev->log; + + ngx_http_lua_balancer_close(c); + + ngx_queue_remove(&item->queue); + ngx_queue_remove(&item->hnode); + ngx_queue_insert_head(&item->lscf->balancer.free, &item->queue); } @@ -446,7 +801,7 @@ ngx_http_lua_balancer_set_session(ngx_peer_connection_t *pc, void *data) return NGX_OK; } - return ngx_http_upstream_set_round_robin_peer_session(pc, &bp->rrp); + return bp->original_set_session(pc, bp->data); } @@ -460,8 +815,7 @@ ngx_http_lua_balancer_save_session(ngx_peer_connection_t *pc, void *data) return; } - ngx_http_upstream_save_round_robin_peer_session(pc, &bp->rrp); - return; + bp->original_save_session(pc, bp->data); } #endif @@ -469,13 +823,14 @@ ngx_http_lua_balancer_save_session(ngx_peer_connection_t *pc, void *data) int ngx_http_lua_ffi_balancer_set_current_peer(ngx_http_request_t *r, - const u_char *addr, size_t addr_len, int port, char **err) + const u_char *addr, size_t addr_len, int port, + const u_char *host, size_t host_len, + char **err) { ngx_url_t url; ngx_http_lua_ctx_t *ctx; ngx_http_upstream_t *u; - ngx_http_lua_main_conf_t *lmcf; ngx_http_lua_balancer_peer_data_t *bp; if (r == NULL) { @@ -501,18 +856,6 @@ ngx_http_lua_ffi_balancer_set_current_peer(ngx_http_request_t *r, return NGX_ERROR; } - lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); - - /* we cannot read r->upstream->peer.data here directly because - * it could be overridden by other modules like - * ngx_http_upstream_keepalive_module. - */ - bp = lmcf->balancer_peer_data; - if (bp == NULL) { - *err = "no upstream peer data found"; - return NGX_ERROR; - } - ngx_memzero(&url, sizeof(ngx_url_t)); url.url.data = ngx_palloc(r->pool, addr_len); @@ -536,16 +879,84 @@ ngx_http_lua_ffi_balancer_set_current_peer(ngx_http_request_t *r, return NGX_ERROR; } + bp = (ngx_http_lua_balancer_peer_data_t *) u->peer.data; + if (url.addrs && url.addrs[0].sockaddr) { bp->sockaddr = url.addrs[0].sockaddr; bp->socklen = url.addrs[0].socklen; - bp->host = &url.addrs[0].name; + bp->addr_text = &url.addrs[0].name; } else { *err = "no host allowed"; return NGX_ERROR; } + if (host && host_len) { + bp->host.data = ngx_palloc(r->pool, host_len); + if (bp->host.data == NULL) { + *err = "no memory"; + return NGX_ERROR; + } + + ngx_memcpy(bp->host.data, host, host_len); + bp->host.len = host_len; + +#if (NGX_HTTP_SSL) + if (u->ssl) { + u->ssl_name = bp->host; + } +#endif + + } else { + ngx_str_null(&bp->host); + } + + return NGX_OK; +} + + +int +ngx_http_lua_ffi_balancer_enable_keepalive(ngx_http_request_t *r, + unsigned long timeout, unsigned int max_requests, char **err) +{ + ngx_http_upstream_t *u; + ngx_http_lua_ctx_t *ctx; + ngx_http_lua_balancer_peer_data_t *bp; + + if (r == NULL) { + *err = "no request found"; + return NGX_ERROR; + } + + u = r->upstream; + + if (u == NULL) { + *err = "no upstream found"; + return NGX_ERROR; + } + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx == NULL) { + *err = "no ctx found"; + return NGX_ERROR; + } + + if ((ctx->context & NGX_HTTP_LUA_CONTEXT_BALANCER) == 0) { + *err = "API disabled in the current context"; + return NGX_ERROR; + } + + bp = (ngx_http_lua_balancer_peer_data_t *) u->peer.data; + + if (!(bp->sockaddr && bp->socklen)) { + *err = "no current peer set"; + return NGX_ERROR; + } + + bp->keepalive_timeout = (ngx_msec_t) timeout; + bp->keepalive_requests = (ngx_uint_t) max_requests; + bp->keepalive = 1; + return NGX_OK; } @@ -555,14 +966,13 @@ ngx_http_lua_ffi_balancer_set_timeouts(ngx_http_request_t *r, long connect_timeout, long send_timeout, long read_timeout, char **err) { - ngx_http_lua_ctx_t *ctx; - ngx_http_upstream_t *u; + ngx_http_lua_ctx_t *ctx; + ngx_http_upstream_t *u; #if !(HAVE_NGX_UPSTREAM_TIMEOUT_FIELDS) ngx_http_upstream_conf_t *ucf; -#endif - ngx_http_lua_main_conf_t *lmcf; ngx_http_lua_balancer_peer_data_t *bp; +#endif if (r == NULL) { *err = "no request found"; @@ -587,15 +997,9 @@ ngx_http_lua_ffi_balancer_set_timeouts(ngx_http_request_t *r, return NGX_ERROR; } - lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); - - bp = lmcf->balancer_peer_data; - if (bp == NULL) { - *err = "no upstream peer data found"; - return NGX_ERROR; - } - #if !(HAVE_NGX_UPSTREAM_TIMEOUT_FIELDS) + bp = (ngx_http_lua_balancer_peer_data_t *) u->peer.data; + if (!bp->cloned_upstream_conf) { /* we clone the upstream conf for the current request so that * we do not affect other requests at all. */ @@ -650,12 +1054,10 @@ ngx_http_lua_ffi_balancer_set_more_tries(ngx_http_request_t *r, int count, char **err) { #if (nginx_version >= 1007005) - ngx_uint_t max_tries, total; + ngx_uint_t max_tries, total; #endif - ngx_http_lua_ctx_t *ctx; - ngx_http_upstream_t *u; - - ngx_http_lua_main_conf_t *lmcf; + ngx_http_lua_ctx_t *ctx; + ngx_http_upstream_t *u; ngx_http_lua_balancer_peer_data_t *bp; if (r == NULL) { @@ -681,13 +1083,7 @@ ngx_http_lua_ffi_balancer_set_more_tries(ngx_http_request_t *r, return NGX_ERROR; } - lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); - - bp = lmcf->balancer_peer_data; - if (bp == NULL) { - *err = "no upstream peer data found"; - return NGX_ERROR; - } + bp = (ngx_http_lua_balancer_peer_data_t *) u->peer.data; #if (nginx_version >= 1007005) max_tries = r->upstream->conf->next_upstream_tries; @@ -713,12 +1109,10 @@ int ngx_http_lua_ffi_balancer_get_last_failure(ngx_http_request_t *r, int *status, char **err) { - ngx_http_lua_ctx_t *ctx; - ngx_http_upstream_t *u; - ngx_http_upstream_state_t *state; - + ngx_http_lua_ctx_t *ctx; + ngx_http_upstream_t *u; + ngx_http_upstream_state_t *state; ngx_http_lua_balancer_peer_data_t *bp; - ngx_http_lua_main_conf_t *lmcf; if (r == NULL) { *err = "no request found"; @@ -743,13 +1137,7 @@ ngx_http_lua_ffi_balancer_get_last_failure(ngx_http_request_t *r, return NGX_ERROR; } - lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); - - bp = lmcf->balancer_peer_data; - if (bp == NULL) { - *err = "no upstream peer data found"; - return NGX_ERROR; - } + bp = (ngx_http_lua_balancer_peer_data_t *) u->peer.data; if (r->upstream_states && r->upstream_states->nelts > 1) { state = r->upstream_states->elts; @@ -852,4 +1240,162 @@ ngx_http_lua_ffi_balancer_set_upstream_tls(ngx_http_request_t *r, int on, } +char * +ngx_http_lua_balancer_keepalive(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_int_t n; + ngx_str_t *value; + +#if 0 + ngx_http_upstream_srv_conf_t *uscf; +#endif + ngx_http_lua_srv_conf_t *lscf = conf; + + if (lscf->balancer.max_cached != NGX_CONF_UNSET_UINT) { + return "is duplicate"; + } + + /* read options */ + + value = cf->args->elts; + + n = ngx_atoi(value[1].data, value[1].len); + + if (n == NGX_ERROR || n == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid value \"%V\" in \"%V\" directive", + &value[1], &cmd->name); + return NGX_CONF_ERROR; + } + + lscf->balancer.max_cached = n; + + return NGX_CONF_OK; +} + + +#if (NGX_HTTP_SSL) +static ngx_int_t +ngx_http_lua_upstream_get_ssl_name(ngx_http_request_t *r, + ngx_http_upstream_t *u) +{ + u_char *p, *last; + ngx_str_t name; + + if (u->conf->ssl_name) { + if (ngx_http_complex_value(r, u->conf->ssl_name, &name) != NGX_OK) { + return NGX_ERROR; + } + + } else { + name = u->ssl_name; + } + + if (name.len == 0) { + goto done; + } + + /* + * ssl name here may contain port, notably if derived from $proxy_host + * or $http_host; we have to strip it. eg: www.example.com:443 + */ + + p = name.data; + last = name.data + name.len; + + if (*p == '[') { + p = ngx_strlchr(p, last, ']'); + + if (p == NULL) { + p = name.data; + } + } + + p = ngx_strlchr(p, last, ':'); + + if (p != NULL) { + name.len = p - name.data; + } + +done: + + u->ssl_name = name; + + return NGX_OK; +} +#endif + + +static ngx_uint_t +ngx_http_lua_balancer_calc_hash(ngx_str_t *name, + struct sockaddr *sockaddr, socklen_t socklen) +{ + ngx_uint_t hash; + + hash = ngx_hash_key_lc(name->data, name->len); + hash ^= ngx_hash_key((u_char *) sockaddr, socklen); + + return hash; +} + + +static ngx_connection_t * +ngx_http_lua_balancer_get_cached_item(ngx_http_lua_srv_conf_t *lscf, + ngx_peer_connection_t *pc, ngx_str_t *name) +{ + ngx_uint_t hash; + ngx_queue_t *q; + ngx_queue_t *head; + ngx_connection_t *c; + struct sockaddr *sockaddr; + socklen_t socklen; + ngx_http_lua_balancer_ka_item_t *item; + + sockaddr = pc->sockaddr; + socklen = pc->socklen; + + hash = ngx_http_lua_balancer_calc_hash(name, sockaddr, socklen); + head = &lscf->balancer.buckets[hash % lscf->balancer.bucket_cnt]; + + c = NULL; + for (q = ngx_queue_head(head); + q != ngx_queue_sentinel(head); + q = ngx_queue_next(q)) + { + item = ngx_queue_data(q, ngx_http_lua_balancer_ka_item_t, hnode); + if (item->hash != hash) { + continue; + } + + if (name->len == item->host.len + && ngx_memn2cmp((u_char *) &item->sockaddr, + (u_char *) sockaddr, + item->socklen, socklen) == 0 + && ngx_strncasecmp(name->data, + item->host.data, name->len) == 0) + { + c = item->connection; + ngx_queue_remove(q); + ngx_queue_remove(&item->queue); + ngx_queue_insert_head(&lscf->balancer.free, &item->queue); + c->idle = 0; + c->sent = 0; + c->log = pc->log; + c->read->log = pc->log; + c->write->log = pc->log; + c->pool->log = pc->log; + + if (c->read->timer_set) { + ngx_del_timer(c->read); + } + + pc->cached = 1; + pc->connection = c; + return c; + } + } + + return NULL; +} + /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_balancer.h b/src/ngx_http_lua_balancer.h index bb49dc02ca..34db2fe82f 100644 --- a/src/ngx_http_lua_balancer.h +++ b/src/ngx_http_lua_balancer.h @@ -23,5 +23,7 @@ char *ngx_http_lua_balancer_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, char *ngx_http_lua_balancer_by_lua_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +char *ngx_http_lua_balancer_keepalive(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); #endif /* _NGX_HTTP_LUA_BALANCER_H_INCLUDED_ */ diff --git a/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h index 4c946297f6..cc2d36a386 100644 --- a/src/ngx_http_lua_common.h +++ b/src/ngx_http_lua_common.h @@ -167,7 +167,7 @@ typedef struct ngx_http_lua_co_ctx_s ngx_http_lua_co_ctx_t; typedef struct ngx_http_lua_sema_mm_s ngx_http_lua_sema_mm_t; -typedef union ngx_http_lua_srv_conf_u ngx_http_lua_srv_conf_t; +typedef struct ngx_http_lua_srv_conf_s ngx_http_lua_srv_conf_t; typedef struct ngx_http_lua_main_conf_s ngx_http_lua_main_conf_t; @@ -258,13 +258,6 @@ struct ngx_http_lua_main_conf_s { ngx_str_t exit_worker_src; u_char *exit_worker_chunkname; - ngx_http_lua_balancer_peer_data_t *balancer_peer_data; - /* neither yielding nor recursion is possible in - * balancer_by_lua*, so there cannot be any races among - * concurrent requests and it is safe to store the peer - * data pointer in the main conf. - */ - ngx_chain_t *body_filter_chain; /* neither yielding nor recursion is possible in * body_filter_by_lua*, so there cannot be any races among @@ -323,7 +316,7 @@ struct ngx_http_lua_main_conf_s { }; -union ngx_http_lua_srv_conf_u { +struct ngx_http_lua_srv_conf_s { struct { #if (NGX_HTTP_SSL) ngx_http_lua_srv_conf_handler_pt ssl_cert_handler; @@ -359,6 +352,14 @@ union ngx_http_lua_srv_conf_u { } srv; struct { + ngx_uint_t max_cached; + ngx_queue_t cache; + ngx_queue_t free; + ngx_queue_t *buckets; + ngx_uint_t bucket_cnt; + ngx_http_upstream_init_pt original_init_upstream; + ngx_http_upstream_init_peer_pt original_init_peer; + ngx_http_lua_srv_conf_handler_pt handler; ngx_str_t src; u_char *src_key; diff --git a/src/ngx_http_lua_module.c b/src/ngx_http_lua_module.c index f64ab89315..14ed235838 100644 --- a/src/ngx_http_lua_module.c +++ b/src/ngx_http_lua_module.c @@ -33,7 +33,9 @@ #include "ngx_http_lua_ssl_session_fetchby.h" #include "ngx_http_lua_headers.h" #include "ngx_http_lua_headers_out.h" +#if !(NGX_WIN32) #include "ngx_http_lua_pipe.h" +#endif static void *ngx_http_lua_create_main_conf(ngx_conf_t *cf); @@ -494,6 +496,13 @@ static ngx_command_t ngx_http_lua_cmds[] = { 0, (void *) ngx_http_lua_balancer_handler_file }, + { ngx_string("balancer_keepalive"), + NGX_HTTP_UPS_CONF|NGX_CONF_TAKE1, + ngx_http_lua_balancer_keepalive, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_http_lua_srv_conf_t, balancer.max_cached), + NULL }, + { ngx_string("lua_socket_keepalive_timeout"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF |NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1, @@ -1188,6 +1197,8 @@ ngx_http_lua_create_srv_conf(ngx_conf_t *cf) * lscf->srv.ssl_sess_fetch_chunkname = NULL; * lscf->srv.ssl_sess_fetch_src_key = NULL; * + * lscf->balancer.original_init_upstream = NULL; + * lscf->balancer.original_init_peer = NULL; * lscf->balancer.handler = NULL; * lscf->balancer.src = { 0, NULL }; * lscf->balancer.chunkname = NULL; @@ -1202,7 +1213,7 @@ ngx_http_lua_create_srv_conf(ngx_conf_t *cf) #endif lscf->balancer.src_ref = LUA_REFNIL; - + lscf->balancer.max_cached = NGX_CONF_UNSET_UINT; return lscf; } From 6738c3a3b0d62b98ff35acf7f7c4a191207da918 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Wed, 23 Nov 2022 14:20:26 +0800 Subject: [PATCH 166/254] change: should match the local address when get connection from the keepalive pool. --- src/ngx_http_lua_balancer.c | 98 +++++++++++++++++++++++++++++++++++-- 1 file changed, 93 insertions(+), 5 deletions(-) diff --git a/src/ngx_http_lua_balancer.c b/src/ngx_http_lua_balancer.c index 9bb770c8e6..79f0e7a9c7 100644 --- a/src/ngx_http_lua_balancer.c +++ b/src/ngx_http_lua_balancer.c @@ -24,6 +24,7 @@ typedef struct { ngx_connection_t *connection; socklen_t socklen; ngx_sockaddr_t sockaddr; + ngx_sockaddr_t local_sockaddr; ngx_str_t host; /* try to avoid allocating memory from the connection pool */ u_char host_data[NGX_BALANCER_DEF_HOST_LEN]; @@ -52,6 +53,7 @@ struct ngx_http_lua_balancer_peer_data_s { struct sockaddr *sockaddr; socklen_t socklen; + ngx_addr_t *local; ngx_str_t host; ngx_str_t *addr_text; @@ -91,7 +93,7 @@ static void ngx_http_lua_balancer_close_handler(ngx_event_t *ev); static ngx_connection_t *ngx_http_lua_balancer_get_cached_item( ngx_http_lua_srv_conf_t *lscf, ngx_peer_connection_t *pc, ngx_str_t *name); static ngx_uint_t ngx_http_lua_balancer_calc_hash(ngx_str_t *name, - struct sockaddr *sockaddr, socklen_t socklen); + struct sockaddr *sockaddr, socklen_t socklen, ngx_addr_t *local); static struct sockaddr *ngx_http_lua_balancer_default_server_sockaddr; @@ -452,6 +454,10 @@ ngx_http_lua_balancer_get_peer(ngx_peer_connection_t *pc, void *data) } } + if (bp->local != NULL) { + pc->local = bp->local; + } + if (bp->sockaddr && bp->socklen) { pc->sockaddr = bp->sockaddr; pc->socklen = bp->socklen; @@ -646,7 +652,8 @@ ngx_http_lua_balancer_free_peer(ngx_peer_connection_t *pc, void *data, ngx_queue_insert_head(&lscf->balancer.cache, q); hash = ngx_http_lua_balancer_calc_hash(host, - bp->sockaddr, bp->socklen); + bp->sockaddr, bp->socklen, + bp->local); item->hash = hash; hash %= lscf->balancer.bucket_cnt; ngx_queue_insert_head(&lscf->balancer.buckets[hash], &item->hnode); @@ -672,6 +679,15 @@ ngx_http_lua_balancer_free_peer(ngx_peer_connection_t *pc, void *data, item->socklen = pc->socklen; ngx_memcpy(&item->sockaddr, pc->sockaddr, pc->socklen); + if (pc->local) { + ngx_memcpy(&item->local_sockaddr, + pc->local->sockaddr, pc->local->socklen); + + } else { + ngx_memzero(&item->local_sockaddr, + sizeof(item->local_sockaddr)); + } + if (host->data && host->len) { if (host->len <= sizeof(item->host_data)) { ngx_memcpy(item->host_data, host->data, host->len); @@ -704,6 +720,7 @@ ngx_http_lua_balancer_free_peer(ngx_peer_connection_t *pc, void *data, return; invalid: + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, "lua balancer: keepalive not saving connection %p", c); @@ -915,6 +932,68 @@ ngx_http_lua_ffi_balancer_set_current_peer(ngx_http_request_t *r, } +int +ngx_http_lua_ffi_balancer_bind_to_local_addr(ngx_http_request_t *r, + const u_char *addr, size_t addr_len, + u_char *errbuf, size_t *errbuf_size) +{ + u_char *p; + ngx_http_lua_ctx_t *ctx; + ngx_http_upstream_t *u; + ngx_int_t rc; + + ngx_http_lua_balancer_peer_data_t *bp; + + if (r == NULL) { + p = ngx_snprintf(errbuf, *errbuf_size, "no request found"); + *errbuf_size = p - errbuf; + return NGX_ERROR; + } + + u = r->upstream; + + if (u == NULL) { + p = ngx_snprintf(errbuf, *errbuf_size, "no upstream found"); + *errbuf_size = p - errbuf; + return NGX_ERROR; + } + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx == NULL) { + p = ngx_snprintf(errbuf, *errbuf_size, "no ctx found"); + *errbuf_size = p - errbuf; + return NGX_ERROR; + } + + if ((ctx->context & NGX_HTTP_LUA_CONTEXT_BALANCER) == 0) { + p = ngx_snprintf(errbuf, *errbuf_size, + "API disabled in the current context"); + *errbuf_size = p - errbuf; + return NGX_ERROR; + } + + bp = (ngx_http_lua_balancer_peer_data_t *) u->peer.data; + + if (bp->local == NULL) { + bp->local = ngx_palloc(r->pool, sizeof(ngx_addr_t)); + if (bp->local == NULL) { + p = ngx_snprintf(errbuf, *errbuf_size, "no memory"); + *errbuf_size = p - errbuf; + return NGX_ERROR; + } + } + + rc = ngx_parse_addr_port(r->pool, bp->local, (u_char *) addr, addr_len); + if (rc == NGX_ERROR) { + p = ngx_snprintf(errbuf, *errbuf_size, "invalid addr %s", addr); + *errbuf_size = p - errbuf; + return NGX_ERROR; + } + + return NGX_OK; +} + + int ngx_http_lua_ffi_balancer_enable_keepalive(ngx_http_request_t *r, unsigned long timeout, unsigned int max_requests, char **err) @@ -1328,12 +1407,15 @@ ngx_http_lua_upstream_get_ssl_name(ngx_http_request_t *r, static ngx_uint_t ngx_http_lua_balancer_calc_hash(ngx_str_t *name, - struct sockaddr *sockaddr, socklen_t socklen) + struct sockaddr *sockaddr, socklen_t socklen, ngx_addr_t *local) { ngx_uint_t hash; hash = ngx_hash_key_lc(name->data, name->len); hash ^= ngx_hash_key((u_char *) sockaddr, socklen); + if (local != NULL) { + hash ^= ngx_hash_key((u_char *) local->sockaddr, local->socklen); + } return hash; } @@ -1349,12 +1431,14 @@ ngx_http_lua_balancer_get_cached_item(ngx_http_lua_srv_conf_t *lscf, ngx_connection_t *c; struct sockaddr *sockaddr; socklen_t socklen; + ngx_addr_t *local; ngx_http_lua_balancer_ka_item_t *item; sockaddr = pc->sockaddr; socklen = pc->socklen; + local = pc->local; - hash = ngx_http_lua_balancer_calc_hash(name, sockaddr, socklen); + hash = ngx_http_lua_balancer_calc_hash(name, sockaddr, socklen, pc->local); head = &lscf->balancer.buckets[hash % lscf->balancer.bucket_cnt]; c = NULL; @@ -1372,7 +1456,11 @@ ngx_http_lua_balancer_get_cached_item(ngx_http_lua_srv_conf_t *lscf, (u_char *) sockaddr, item->socklen, socklen) == 0 && ngx_strncasecmp(name->data, - item->host.data, name->len) == 0) + item->host.data, name->len) == 0 + && (local == NULL + || ngx_memn2cmp((u_char *) &item->local_sockaddr, + (u_char *) local->sockaddr, + socklen, local->socklen) == 0)) { c = item->connection; ngx_queue_remove(q); From 6477a7b46d78e9ad841f2f3b2e1d37161b748669 Mon Sep 17 00:00:00 2001 From: Johnny Wang Date: Wed, 3 Jul 2024 22:40:36 +0800 Subject: [PATCH 167/254] bugfix: fixed compilation errors when building without SSL. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit lua-nginx-module/src/ngx_http_lua_balancer.c: In function ‘ngx_http_lua_balancer_get_peer’: lua-nginx-module/src/ngx_http_lua_balancer.c:389:41: error: variable ‘u’ set but not used [-Werror=unused-but-set-variable] 389 | ngx_http_upstream_t *u; | --- src/ngx_http_lua_balancer.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ngx_http_lua_balancer.c b/src/ngx_http_lua_balancer.c index 79f0e7a9c7..3469c36ad1 100644 --- a/src/ngx_http_lua_balancer.c +++ b/src/ngx_http_lua_balancer.c @@ -386,7 +386,9 @@ ngx_http_lua_balancer_get_peer(ngx_peer_connection_t *pc, void *data) ngx_int_t rc; ngx_connection_t *c; ngx_http_request_t *r; +#if (NGX_HTTP_SSL) ngx_http_upstream_t *u; +#endif ngx_http_lua_ctx_t *ctx; ngx_http_lua_srv_conf_t *lscf; ngx_http_lua_balancer_peer_data_t *bp = data; @@ -395,7 +397,9 @@ ngx_http_lua_balancer_get_peer(ngx_peer_connection_t *pc, void *data) "lua balancer: get peer, tries: %ui", pc->tries); r = bp->request; +#if (NGX_HTTP_SSL) u = r->upstream; +#endif lscf = bp->conf; ngx_http_lua_assert(lscf->balancer.handler && r); From 39d165ca411887604aca03869e00051fc718896d Mon Sep 17 00:00:00 2001 From: lijunlong Date: Sun, 7 Jul 2024 11:39:10 +0800 Subject: [PATCH 168/254] bugfix: undefined symbol SSL_client_hello_get0_ext when linking against libressl. --- src/ngx_http_lua_ssl_client_helloby.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/ngx_http_lua_ssl_client_helloby.c b/src/ngx_http_lua_ssl_client_helloby.c index 03ac430ef2..b808f98ed7 100644 --- a/src/ngx_http_lua_ssl_client_helloby.c +++ b/src/ngx_http_lua_ssl_client_helloby.c @@ -541,6 +541,10 @@ int ngx_http_lua_ffi_ssl_get_client_hello_server_name(ngx_http_request_t *r, const char **name, size_t *namelen, char **err) { +#ifdef LIBRESSL_VERSION_NUMBER + *err = "LibreSSL does not support by ssl_client_hello_by_lua*"; + return NGX_ERROR; +#else ngx_ssl_conn_t *ssl_conn; #ifdef SSL_ERROR_WANT_CLIENT_HELLO_CB const unsigned char *p; @@ -619,6 +623,7 @@ ngx_http_lua_ffi_ssl_get_client_hello_server_name(ngx_http_request_t *r, *err = "no TLS extension support"; return NGX_ERROR; #endif +#endif /* LIBRESSL_VERSION_NUMBER */ } @@ -626,6 +631,10 @@ int ngx_http_lua_ffi_ssl_get_client_hello_ext(ngx_http_request_t *r, unsigned int type, const unsigned char **out, size_t *outlen, char **err) { +#ifdef LIBRESSL_VERSION_NUMBER + *err = "LibreSSL does not support by ssl_client_hello_by_lua*"; + return NGX_ERROR; +#else ngx_ssl_conn_t *ssl_conn; if (r->connection == NULL || r->connection->ssl == NULL) { @@ -649,7 +658,7 @@ ngx_http_lua_ffi_ssl_get_client_hello_ext(ngx_http_request_t *r, *err = "OpenSSL too old to support this function"; return NGX_ERROR; #endif - +#endif /* LIBRESSL_VERSION_NUMBER */ } From 0a1c704c2eb30aa3f76f2fdd7a584514050be814 Mon Sep 17 00:00:00 2001 From: Tinglong Yang Date: Sun, 7 Jul 2024 12:22:30 +0800 Subject: [PATCH 169/254] feature: support ngx.location.capture and ngx.location.capture_multi with `headers` option. --- README.markdown | 30 ++++++++++++++- src/ngx_http_lua_subrequest.c | 66 +++++++++++++++++++++++++++----- t/027-multi-capture.t | 72 +++++++++++++++++++++++++++++++++++ 3 files changed, 158 insertions(+), 10 deletions(-) diff --git a/README.markdown b/README.markdown index 4957e50059..af9555f80b 100644 --- a/README.markdown +++ b/README.markdown @@ -966,7 +966,6 @@ TODO * cosocket: add support in the context of [init_by_lua*](#init_by_lua). * cosocket: review and merge aviramc's [patch](https://github.com/openresty/lua-nginx-module/pull/290) for adding the `bsdrecv` method. * cosocket: add configure options for different strategies of handling the cosocket connection exceeding in the pools. -* review and apply vadim-pavlov's patch for [ngx.location.capture](#ngxlocationcapture)'s `extra_headers` option * use `ngx_hash_t` to optimize the built-in header look-up process for [ngx.req.set_header](#ngxreqset_header), and etc. * add `ignore_resp_headers`, `ignore_resp_body`, and `ignore_resp` options to [ngx.location.capture](#ngxlocationcapture) and [ngx.location.capture_multi](#ngxlocationcapture_multi) methods, to allow micro performance tuning on the user side. * add automatic Lua code time slicing support by yielding and resuming the Lua VM actively via Lua's debug hooks. @@ -4305,6 +4304,8 @@ argument, which supports the options: specify the subrequest's request body (string value only). * `args` specify the subrequest's URI query arguments (both string value and Lua tables are accepted) +* `headers` + specify the subrequest's request headers (Lua table only). this headers will override the original headers of the subrequest. * `ctx` specify a Lua table to be the [ngx.ctx](#ngxctx) table for the subrequest. It can be the current request's [ngx.ctx](#ngxctx) table, which effectively makes the parent and its subrequest to share exactly the same context table. This option was first introduced in the `v0.3.1rc25` release. * `vars` @@ -4456,6 +4457,33 @@ Accessing `/lua` will yield the output dog = hello cat = 32 +The `headers` option can be used to specify the request headers for the subrequest. The value of this option should be a Lua table where the keys are the header names and the values are the header values. For example, + +```lua + +location /foo { + content_by_lua_block { + ngx.print(ngx.var.http_x_test) + } +} + +location /lua { + content_by_lua_block { + local res = ngx.location.capture("/foo", { + headers = { + ["X-Test"] = "aa", + } + }) + ngx.print(res.body) + } +} +``` + +Accessing `/lua` will yield the output + + + aa + The `ctx` option can be used to specify a custom Lua table to serve as the [ngx.ctx](#ngxctx) table for the subrequest. diff --git a/src/ngx_http_lua_subrequest.c b/src/ngx_http_lua_subrequest.c index f4db9aaf6c..2ccd271a90 100644 --- a/src/ngx_http_lua_subrequest.c +++ b/src/ngx_http_lua_subrequest.c @@ -62,10 +62,10 @@ static ngx_str_t ngx_http_lua_content_length_header_key = static ngx_int_t ngx_http_lua_adjust_subrequest(ngx_http_request_t *sr, ngx_uint_t method, int forward_body, ngx_http_request_body_t *body, unsigned vars_action, - ngx_array_t *extra_vars); + ngx_array_t *extra_vars, ngx_array_t *extra_headers); static int ngx_http_lua_ngx_location_capture(lua_State *L); static int ngx_http_lua_ngx_location_capture_multi(lua_State *L); -static void ngx_http_lua_process_vars_option(ngx_http_request_t *r, +static void ngx_http_lua_process_keyval_option(ngx_http_request_t *r, lua_State *L, int table, ngx_array_t **varsp); static ngx_int_t ngx_http_lua_subrequest_add_extra_vars(ngx_http_request_t *r, ngx_array_t *extra_vars); @@ -79,7 +79,7 @@ static void ngx_http_lua_cancel_subreq(ngx_http_request_t *r); static ngx_int_t ngx_http_post_request_to_head(ngx_http_request_t *r); static ngx_int_t ngx_http_lua_copy_in_file_request_body(ngx_http_request_t *r); static ngx_int_t ngx_http_lua_copy_request_headers(ngx_http_request_t *sr, - ngx_http_request_t *pr, int pr_not_chunked); + ngx_http_request_t *pr, int pr_not_chunked, ngx_array_t *extra_headers); enum { @@ -127,6 +127,7 @@ ngx_http_lua_ngx_location_capture_multi(lua_State *L) ngx_http_lua_ctx_t *sr_ctx; ngx_http_lua_ctx_t *ctx; ngx_array_t *extra_vars; + ngx_array_t *extra_headers; ngx_str_t uri; ngx_str_t args; ngx_str_t extra_args; @@ -224,6 +225,7 @@ ngx_http_lua_ngx_location_capture_multi(lua_State *L) coctx->pending_subreqs = 0; extra_vars = NULL; + extra_headers = NULL; for (index = 0; index < nsubreqs; index++) { coctx->pending_subreqs++; @@ -263,6 +265,11 @@ ngx_http_lua_ngx_location_capture_multi(lua_State *L) extra_vars->nelts = 0; } + if (extra_headers != NULL) { + /* flush out existing elements in the array */ + extra_headers->nelts = 0; + } + vars_action = 0; custom_ctx = 0; @@ -318,7 +325,7 @@ ngx_http_lua_ngx_location_capture_multi(lua_State *L) switch (lua_type(L, -1)) { case LUA_TTABLE: - ngx_http_lua_process_vars_option(r, L, -1, &extra_vars); + ngx_http_lua_process_keyval_option(r, L, -1, &extra_vars); dd("post process vars top: %d", lua_gettop(L)); break; @@ -335,6 +342,29 @@ ngx_http_lua_ngx_location_capture_multi(lua_State *L) dd("queries query uri opts: %d", lua_gettop(L)); + /* check the headers option */ + + lua_getfield(L, 4, "headers"); + + switch (lua_type(L, -1)) { + case LUA_TTABLE: + ngx_http_lua_process_keyval_option(r, L, -1, &extra_headers); + + dd("post process vars top: %d", lua_gettop(L)); + break; + + case LUA_TNIL: + /* do nothing */ + break; + + default: + return luaL_error(L, "Bad headers option value"); + } + + lua_pop(L, 1); /* pop the headers */ + + dd("queries query uri opts: %d", lua_gettop(L)); + /* check the share_all_vars option */ lua_getfield(L, 4, "share_all_vars"); @@ -595,7 +625,8 @@ ngx_http_lua_ngx_location_capture_multi(lua_State *L) ngx_http_set_ctx(sr, sr_ctx, ngx_http_lua_module); rc = ngx_http_lua_adjust_subrequest(sr, method, always_forward_body, - body, vars_action, extra_vars); + body, vars_action, extra_vars, + extra_headers); if (rc != NGX_OK) { ngx_http_lua_cancel_subreq(sr); @@ -631,7 +662,7 @@ ngx_http_lua_ngx_location_capture_multi(lua_State *L) static ngx_int_t ngx_http_lua_adjust_subrequest(ngx_http_request_t *sr, ngx_uint_t method, int always_forward_body, ngx_http_request_body_t *body, - unsigned vars_action, ngx_array_t *extra_vars) + unsigned vars_action, ngx_array_t *extra_vars, ngx_array_t *extra_headers) { ngx_http_request_t *r; ngx_http_core_main_conf_t *cmcf; @@ -667,7 +698,9 @@ ngx_http_lua_adjust_subrequest(ngx_http_request_t *sr, ngx_uint_t method, } } - if (ngx_http_lua_copy_request_headers(sr, r, pr_not_chunked) != NGX_OK) { + if (ngx_http_lua_copy_request_headers(sr, r, pr_not_chunked, extra_headers) + != NGX_OK) + { return NGX_ERROR; } @@ -882,7 +915,7 @@ ngx_http_lua_subrequest_add_extra_vars(ngx_http_request_t *sr, static void -ngx_http_lua_process_vars_option(ngx_http_request_t *r, lua_State *L, +ngx_http_lua_process_keyval_option(ngx_http_request_t *r, lua_State *L, int table, ngx_array_t **varsp) { ngx_array_t *vars; @@ -1635,10 +1668,11 @@ ngx_http_lua_copy_in_file_request_body(ngx_http_request_t *r) static ngx_int_t ngx_http_lua_copy_request_headers(ngx_http_request_t *sr, - ngx_http_request_t *pr, int pr_not_chunked) + ngx_http_request_t *pr, int pr_not_chunked, ngx_array_t *extra_headers) { ngx_table_elt_t *clh, *header; ngx_list_part_t *part; + ngx_keyval_t *header_keyval; ngx_chain_t *in; ngx_uint_t i; u_char *p; @@ -1742,6 +1776,20 @@ ngx_http_lua_copy_request_headers(ngx_http_request_t *sr, } } + if (extra_headers && extra_headers->nelts > 0) { + + header_keyval = extra_headers->elts; + + for (i = 0; i < extra_headers->nelts; i++, header_keyval++) { + + if (ngx_http_lua_set_input_header(sr, header_keyval->key, + header_keyval->value, 1) == NGX_ERROR) + { + return NGX_ERROR; + } + } + } + dd("after: parent req headers count: %d", (int) pr->headers_in.headers.part.nelts); diff --git a/t/027-multi-capture.t b/t/027-multi-capture.t index 9299561687..b3cdbaff09 100644 --- a/t/027-multi-capture.t +++ b/t/027-multi-capture.t @@ -752,3 +752,75 @@ proxy_cache_path conf/cache levels=1:2 keys_zone=STATIC:10m inactive=10m max_siz GET /foo --- response_body ok + + + +=== TEST 14: capture multi with headers +--- config + location /foo { + content_by_lua_block { + local res1, res2, res3 = ngx.location.capture_multi{ + {"/test", { headers = { ["X-Test-Header"] = "aa"} } }, + {"/test", { headers = { ["X-Test-Header"] = "bb"} } }, + {"/test"}, + } + ngx.say("res1.status = " .. res1.status) + ngx.say("res1.body = " .. res1.body) + ngx.say("res2.status = " .. res2.status) + ngx.say("res2.body = " .. res2.body) + ngx.say("res3.status = " .. res3.status) + ngx.say("res3.body = " .. res3.body) + } + } + + location = /test { + content_by_lua_block { + ngx.print(ngx.var.http_x_test_header) + } + } +--- request + GET /foo +--- response_body +res1.status = 200 +res1.body = aa +res2.status = 200 +res2.body = bb +res3.status = 200 +res3.body = nil + + + +=== TEST 15: capture multi with headers override +--- config + location /foo { + content_by_lua_block { + local res1, res2, res3 = ngx.location.capture_multi{ + {"/test", { headers = { ["X-Test-Header"] = "aa"} } }, + {"/test", { headers = { ["X-Test-Header"] = "bb"} } }, + {"/test"}, + } + ngx.say("res1.status = " .. res1.status) + ngx.say("res1.body = " .. res1.body) + ngx.say("res2.status = " .. res2.status) + ngx.say("res2.body = " .. res2.body) + ngx.say("res3.status = " .. res3.status) + ngx.say("res3.body = " .. res3.body) + } + } + + location = /test { + content_by_lua_block { + ngx.print(ngx.var.http_x_test_header) + } + } +--- request + GET /foo +--- more_headers +X-Test-Header: cc +--- response_body +res1.status = 200 +res1.body = aa +res2.status = 200 +res2.body = bb +res3.status = 200 +res3.body = cc From 94f55f7a4d493f627d545e890592c49a27c4a3bc Mon Sep 17 00:00:00 2001 From: kurt Date: Tue, 9 Jul 2024 12:10:08 +0800 Subject: [PATCH 170/254] bugfix: respect max retry after using balancer pool. In the balancer phase, when obtaining a connection from the upstream connection pool, the `cached` attribute of the peer connection is set to 1(`pc->cached = 1;`), indicating that the connection is obtained from the cache. If an error occurs during the use of this connection, such as "upstream prematurely closed connection" the system will increase the `tries` attribute of the peer connection by executing `u->peer.tries++`. This PR restores tries by callbacks to the balancer when `u->peer.tries++` is unexpectedly set. Signed-off-by: tzssangglass --- src/ngx_http_lua_balancer.c | 15 ++++ t/188-balancer_keepalive_pool_max_retry.t | 89 +++++++++++++++++++++++ 2 files changed, 104 insertions(+) create mode 100644 t/188-balancer_keepalive_pool_max_retry.t diff --git a/src/ngx_http_lua_balancer.c b/src/ngx_http_lua_balancer.c index 3469c36ad1..620f71eea0 100644 --- a/src/ngx_http_lua_balancer.c +++ b/src/ngx_http_lua_balancer.c @@ -87,6 +87,8 @@ static ngx_int_t ngx_http_lua_balancer_by_chunk(lua_State *L, ngx_http_request_t *r); static void ngx_http_lua_balancer_free_peer(ngx_peer_connection_t *pc, void *data, ngx_uint_t state); +static void ngx_http_lua_balancer_notify_peer(ngx_peer_connection_t *pc, + void *data, ngx_uint_t type); static void ngx_http_lua_balancer_close(ngx_connection_t *c); static void ngx_http_lua_balancer_dummy_handler(ngx_event_t *ev); static void ngx_http_lua_balancer_close_handler(ngx_event_t *ev); @@ -365,6 +367,7 @@ ngx_http_lua_balancer_init_peer(ngx_http_request_t *r, r->upstream->peer.data = bp; r->upstream->peer.get = ngx_http_lua_balancer_get_peer; r->upstream->peer.free = ngx_http_lua_balancer_free_peer; + r->upstream->peer.notify = ngx_http_lua_balancer_notify_peer; #if (NGX_HTTP_SSL) bp->original_set_session = r->upstream->peer.set_session; @@ -737,6 +740,18 @@ ngx_http_lua_balancer_free_peer(ngx_peer_connection_t *pc, void *data, } +static void +ngx_http_lua_balancer_notify_peer(ngx_peer_connection_t *pc, void *data, + ngx_uint_t type) +{ +#ifdef NGX_HTTP_UPSTREAM_NOTIFY_CACHED_CONNECTION_ERROR + if (type == NGX_HTTP_UPSTREAM_NOTIFY_CACHED_CONNECTION_ERROR) { + pc->tries--; + } +#endif +} + + static void ngx_http_lua_balancer_close(ngx_connection_t *c) { diff --git a/t/188-balancer_keepalive_pool_max_retry.t b/t/188-balancer_keepalive_pool_max_retry.t new file mode 100644 index 0000000000..456ea794c9 --- /dev/null +++ b/t/188-balancer_keepalive_pool_max_retry.t @@ -0,0 +1,89 @@ +# vim:set ft= ts=4 sw=4 et: + +use Test::Nginx::Socket::Lua; +use Cwd qw(cwd); + +log_level('info'); +repeat_each(1); + +plan tests => repeat_each() * (blocks() * 6); + +my $pwd = cwd(); + +no_long_string(); + +check_accum_error_log(); +run_tests(); + +__DATA__ + +=== TEST 1: sanity +--- http_config + lua_shared_dict request_counter 1m; + upstream my_upstream { + server 127.0.0.1; + balancer_by_lua_block { + local balancer = require "ngx.balancer" + + if not ngx.ctx.tries then + ngx.ctx.tries = 0 + end + + ngx.ctx.tries = ngx.ctx.tries + 1 + ngx.log(ngx.INFO, "tries ", ngx.ctx.tries) + + if ngx.ctx.tries == 1 then + balancer.set_more_tries(5) + end + + local host = "127.0.0.1" + local port = 8090; + + local ok, err = balancer.set_current_peer(host, port) + if not ok then + ngx.log(ngx.ERR, "failed to set the current peer: ", err) + return ngx.exit(500) + end + + balancer.set_timeouts(60000, 60000, 60000) + + local ok, err = balancer.enable_keepalive(60, 100) + if not ok then + ngx.log(ngx.ERR, "failed to enable keepalive: ", err) + return ngx.exit(500) + end + } + } + + server { + listen 0.0.0.0:8090; + location /hello { + content_by_lua_block{ + local request_counter = ngx.shared.request_counter + local first_request = request_counter:get("first_request") + if first_request == nil then + request_counter:set("first_request", "yes") + ngx.print("hello") + else + ngx.exit(ngx.HTTP_CLOSE) + end + } + } + } +--- config + location = /t { + proxy_pass http://my_upstream; + proxy_set_header Connection "keep-alive"; + + rewrite_by_lua_block { + ngx.req.set_uri("/hello") + } + } +--- pipelined_requests eval +["GET /t HTTP/1.1" , "GET /t HTTP/1.1"] +--- response_body eval +["hello", qr/502/] +--- error_code eval +[200, 502] +--- no_error_log eval +qr/tries 7/ From 45c63cda4170728ec7561c102849eb7ea28e0720 Mon Sep 17 00:00:00 2001 From: xiangwei <1031205858@qq.com> Date: Tue, 9 Jul 2024 12:10:49 +0800 Subject: [PATCH 171/254] feature: add ssl trusted certificate. --- src/ngx_http_lua_ssl_certby.c | 84 ++++++++++------ t/140-ssl-c-api.t | 180 +++++++++++++++++++++++++++++++--- 2 files changed, 220 insertions(+), 44 deletions(-) diff --git a/src/ngx_http_lua_ssl_certby.c b/src/ngx_http_lua_ssl_certby.c index 996c3d62a3..0901f06eab 100644 --- a/src/ngx_http_lua_ssl_certby.c +++ b/src/ngx_http_lua_ssl_certby.c @@ -1468,8 +1468,8 @@ ngx_http_lua_ssl_verify_callback(int ok, X509_STORE_CTX *x509_store) int -ngx_http_lua_ffi_ssl_verify_client(ngx_http_request_t *r, void *ca_certs, - int depth, char **err) +ngx_http_lua_ffi_ssl_verify_client(ngx_http_request_t *r, void *client_certs, + void *trusted_certs, int depth, char **err) { #ifdef LIBRESSL_VERSION_NUMBER @@ -1481,7 +1481,8 @@ ngx_http_lua_ffi_ssl_verify_client(ngx_http_request_t *r, void *ca_certs, ngx_http_lua_ctx_t *ctx; ngx_ssl_conn_t *ssl_conn; ngx_http_ssl_srv_conf_t *sscf; - STACK_OF(X509) *chain = ca_certs; + STACK_OF(X509) *client_chain = client_certs; + STACK_OF(X509) *trusted_chain = trusted_certs; STACK_OF(X509_NAME) *name_chain = NULL; X509 *x509 = NULL; X509_NAME *subject = NULL; @@ -1535,54 +1536,75 @@ ngx_http_lua_ffi_ssl_verify_client(ngx_http_request_t *r, void *ca_certs, /* set CA chain */ - if (chain != NULL) { + if (client_chain != NULL || trusted_chain != NULL) { + ca_store = X509_STORE_new(); if (ca_store == NULL) { *err = "X509_STORE_new() failed"; return NGX_ERROR; } - /* construct name chain */ + if (client_chain != NULL) { - name_chain = sk_X509_NAME_new_null(); - if (name_chain == NULL) { - *err = "sk_X509_NAME_new_null() failed"; - goto failed; - } - - for (i = 0; i < sk_X509_num(chain); i++) { - x509 = sk_X509_value(chain, i); - if (x509 == NULL) { - *err = "sk_X509_value() failed"; + /* construct name chain */ + name_chain = sk_X509_NAME_new_null(); + if (name_chain == NULL) { + *err = "sk_X509_NAME_new_null() failed"; goto failed; } - /* add subject to name chain, which will be sent to client */ - subject = X509_NAME_dup(X509_get_subject_name(x509)); - if (subject == NULL) { - *err = "X509_get_subject_name() failed"; - goto failed; + for (i = 0; i < sk_X509_num(client_chain); i++) { + x509 = sk_X509_value(client_chain, i); + if (x509 == NULL) { + *err = "sk_X509_value() failed"; + goto failed; + } + + /* add subject to name chain, which will be sent to client */ + subject = X509_NAME_dup(X509_get_subject_name(x509)); + if (subject == NULL) { + *err = "X509_get_subject_name() failed"; + goto failed; + } + + if (!sk_X509_NAME_push(name_chain, subject)) { + *err = "sk_X509_NAME_push() failed"; + X509_NAME_free(subject); + goto failed; + } + + /* add to trusted CA store */ + if (X509_STORE_add_cert(ca_store, x509) == 0) { + *err = "X509_STORE_add_cert() failed"; + goto failed; + } } - if (!sk_X509_NAME_push(name_chain, subject)) { - *err = "sk_X509_NAME_push() failed"; - X509_NAME_free(subject); - goto failed; - } + /* clean subject name list, and set it for send to client */ + SSL_set_client_CA_list(ssl_conn, name_chain); + } - /* add to trusted CA store */ - if (X509_STORE_add_cert(ca_store, x509) == 0) { - *err = "X509_STORE_add_cert() failed"; - goto failed; + if (trusted_chain != NULL) { + for (i = 0; i < sk_X509_num(trusted_chain); i++) { + x509 = sk_X509_value(trusted_chain, i); + if (x509 == NULL) { + *err = "sk_X509_value() failed"; + goto failed; + } + + /* add to trusted CA store */ + if (X509_STORE_add_cert(ca_store, x509) == 0) { + *err = "X509_STORE_add_cert() failed"; + goto failed; + } } } + /* clean ca_store, and store new ca_store */ if (SSL_set0_verify_cert_store(ssl_conn, ca_store) == 0) { *err = "SSL_set0_verify_cert_store() failed"; goto failed; } - - SSL_set_client_CA_list(ssl_conn, name_chain); } return NGX_OK; diff --git a/t/140-ssl-c-api.t b/t/140-ssl-c-api.t index 001d26ae31..4c81b4f05a 100644 --- a/t/140-ssl-c-api.t +++ b/t/140-ssl-c-api.t @@ -12,7 +12,7 @@ if ($openssl_version =~ m/built with OpenSSL (0|1\.0\.(?:0|1[^\d]|2[a-d]).*)/) { plan(skip_all => "too old OpenSSL, need 1.0.2e, was $1"); } else { - plan tests => repeat_each() * (blocks() * 5 + 1); + plan tests => repeat_each() * (blocks() * 5 - 1); } $ENV{TEST_NGINX_HTML_DIR} ||= html_dir(); @@ -72,7 +72,7 @@ ffi.cdef[[ void ngx_http_lua_ffi_free_priv_key(void *cdata); int ngx_http_lua_ffi_ssl_verify_client(void *r, void *cdata, - int depth, char **err); + void *cdata, int depth, char **err); int ngx_http_lua_ffi_ssl_client_random(ngx_http_request_t *r, unsigned char *out, size_t *outlen, char **err); @@ -853,21 +853,21 @@ lua ssl server name: "test.com" local cert_data = f:read("*all") f:close() - local cert = ffi.C.ngx_http_lua_ffi_parse_pem_cert(cert_data, #cert_data, errmsg) - if not cert then - ngx.log(ngx.ERR, "failed to parse PEM cert: ", + local client_cert = ffi.C.ngx_http_lua_ffi_parse_pem_cert(cert_data, #cert_data, errmsg) + if not client_cert then + ngx.log(ngx.ERR, "failed to parse PEM client cert: ", ffi.string(errmsg[0])) return end - local rc = ffi.C.ngx_http_lua_ffi_ssl_verify_client(r, cert, 1, errmsg) + local rc = ffi.C.ngx_http_lua_ffi_ssl_verify_client(r, client_cert, nil, 1, errmsg) if rc ~= 0 then ngx.log(ngx.ERR, "failed to verify client: ", ffi.string(errmsg[0])) return end - ffi.C.ngx_http_lua_ffi_free_cert(cert) + ffi.C.ngx_http_lua_ffi_free_cert(client_cert) } ssl_certificate ../../cert/test2.crt; @@ -924,7 +924,7 @@ client certificate subject: emailAddress=agentzh@gmail.com,CN=test.com return end - local rc = ffi.C.ngx_http_lua_ffi_ssl_verify_client(r, nil, -1, errmsg) + local rc = ffi.C.ngx_http_lua_ffi_ssl_verify_client(r, nil, nil, -1, errmsg) if rc ~= 0 then ngx.log(ngx.ERR, "failed to verify client: ", ffi.string(errmsg[0])) @@ -990,21 +990,21 @@ client certificate subject: emailAddress=agentzh@gmail.com,CN=test.com local cert_data = f:read("*all") f:close() - local cert = ffi.C.ngx_http_lua_ffi_parse_pem_cert(cert_data, #cert_data, errmsg) - if not cert then - ngx.log(ngx.ERR, "failed to parse PEM cert: ", + local client_cert = ffi.C.ngx_http_lua_ffi_parse_pem_cert(cert_data, #cert_data, errmsg) + if not client_cert then + ngx.log(ngx.ERR, "failed to parse PEM client cert: ", ffi.string(errmsg[0])) return end - local rc = ffi.C.ngx_http_lua_ffi_ssl_verify_client(r, cert, 1, errmsg) + local rc = ffi.C.ngx_http_lua_ffi_ssl_verify_client(r, client_cert, nil, 1, errmsg) if rc ~= 0 then ngx.log(ngx.ERR, "failed to verify client: ", ffi.string(errmsg[0])) return end - ffi.C.ngx_http_lua_ffi_free_cert(cert) + ffi.C.ngx_http_lua_ffi_free_cert(client_cert) } ssl_certificate ../../cert/test2.crt; @@ -1623,3 +1623,157 @@ lua ssl server name: "test.com" --- no_error_log [error] [alert] + + + +=== TEST 13: verify client, but server don't trust root ca +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name example.com; + + ssl_certificate_by_lua_block { + collectgarbage() + + require "defines" + local ffi = require "ffi" + + local errmsg = ffi.new("char *[1]") + + local r = require "resty.core.base" .get_request() + if r == nil then + ngx.log(ngx.ERR, "no request found") + return + end + + local f = assert(io.open("t/cert/mtls_server.crt", "rb")) + local cert_data = f:read("*all") + f:close() + + local client_cert = ffi.C.ngx_http_lua_ffi_parse_pem_cert(cert_data, #cert_data, errmsg) + if not client_cert then + ngx.log(ngx.ERR, "failed to parse PEM client cert: ", + ffi.string(errmsg[0])) + return + end + + local rc = ffi.C.ngx_http_lua_ffi_ssl_verify_client(r, client_cert, nil, 2, errmsg) + if rc ~= 0 then + ngx.log(ngx.ERR, "failed to verify client: ", + ffi.string(errmsg[0])) + return + end + + ffi.C.ngx_http_lua_ffi_free_cert(client_cert) + } + + ssl_certificate ../../cert/mtls_server.crt; + ssl_certificate_key ../../cert/mtls_server.key; + + location / { + default_type 'text/plain'; + content_by_lua_block { + ngx.say(ngx.var.ssl_client_verify) + } + more_clear_headers Date; + } + } +--- config + location /t { + proxy_pass https://unix:$TEST_NGINX_HTML_DIR/nginx.sock; + proxy_ssl_certificate ../../cert/mtls_client.crt; + proxy_ssl_certificate_key ../../cert/mtls_client.key; + proxy_ssl_session_reuse off; + } + +--- request +GET /t +--- response_body +FAILED:unable to verify the first certificate + +--- no_error_log +[error] +[alert] + + + +=== TEST 14: verify client and server trust root ca +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name example.com; + + ssl_certificate_by_lua_block { + collectgarbage() + + require "defines" + local ffi = require "ffi" + + local errmsg = ffi.new("char *[1]") + + local r = require "resty.core.base" .get_request() + if r == nil then + ngx.log(ngx.ERR, "no request found") + return + end + + local f = assert(io.open("t/cert/mtls_server.crt", "rb")) + local cert_data = f:read("*all") + f:close() + + local client_cert = ffi.C.ngx_http_lua_ffi_parse_pem_cert(cert_data, #cert_data, errmsg) + if not client_cert then + ngx.log(ngx.ERR, "failed to parse PEM client cert: ", + ffi.string(errmsg[0])) + return + end + + local f = assert(io.open("t/cert/mtls_ca.crt", "rb")) + local cert_data = f:read("*all") + f:close() + + local trusted_cert = ffi.C.ngx_http_lua_ffi_parse_pem_cert(cert_data, #cert_data, errmsg) + if not trusted_cert then + ngx.log(ngx.ERR, "failed to parse PEM trusted cert: ", + ffi.string(errmsg[0])) + return + end + + local rc = ffi.C.ngx_http_lua_ffi_ssl_verify_client(r, cert, trusted_cert, 2, errmsg) + if rc ~= 0 then + ngx.log(ngx.ERR, "failed to verify client: ", + ffi.string(errmsg[0])) + return + end + + ffi.C.ngx_http_lua_ffi_free_cert(client_cert) + ffi.C.ngx_http_lua_ffi_free_cert(trusted_cert) + } + + ssl_certificate ../../cert/mtls_server.crt; + ssl_certificate_key ../../cert/mtls_server.key; + + location / { + default_type 'text/plain'; + content_by_lua_block { + ngx.say(ngx.var.ssl_client_verify) + } + more_clear_headers Date; + } + } +--- config + location /t { + proxy_pass https://unix:$TEST_NGINX_HTML_DIR/nginx.sock; + proxy_ssl_certificate ../../cert/mtls_client.crt; + proxy_ssl_certificate_key ../../cert/mtls_client.key; + proxy_ssl_session_reuse off; + } + +--- request +GET /t +--- response_body +SUCCESS + +--- no_error_log +[error] +[alert] From 8670e53ea7da7d445b3c1907d2c406b1077a1dcd Mon Sep 17 00:00:00 2001 From: Jun Ouyang Date: Fri, 12 Jul 2024 21:11:05 +0800 Subject: [PATCH 172/254] bugfix: let `balancer.recreate_request` API work for body data changed case. --- README.markdown | 8 +++++-- doc/HttpLuaModule.wiki | 8 +++++-- src/ngx_http_lua_balancer.c | 2 +- t/138-balancer.t | 42 ++++++++++++++++++++++++++++++++++++- 4 files changed, 54 insertions(+), 6 deletions(-) diff --git a/README.markdown b/README.markdown index af9555f80b..e14d302bfb 100644 --- a/README.markdown +++ b/README.markdown @@ -5563,6 +5563,8 @@ If the request body has been read into memory, try calling the [ngx.req.get_body To force in-file request bodies, try turning on [client_body_in_file_only](http://nginx.org/en/docs/http/ngx_http_core_module.html#client_body_in_file_only). +Note that this function is also work for balancer phase but it needs to call [balancer.recreate_request](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/balancer.md#recreate_request) to make the change take effect after set the request body data or headers. + This function was first introduced in the `v0.3.1rc17` release. See also [ngx.req.get_body_data](#ngxreqget_body_data). @@ -5574,7 +5576,7 @@ ngx.req.set_body_data **syntax:** *ngx.req.set_body_data(data)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, balancer_by_lua*,* Set the current request's request body using the in-memory data specified by the `data` argument. @@ -5582,6 +5584,8 @@ If the request body has not been read yet, call [ngx.req.read_body](#ngxreqread_ Whether the previous request body has been read into memory or buffered into a disk file, it will be freed or the disk file will be cleaned up immediately, respectively. +Note that this function is also work for balancer phase but it needs to call [balancer.recreate_request](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/balancer.md#recreate_request) to make the change take effect after set the request body data or headers. + This function was first introduced in the `v0.3.1rc18` release. See also [ngx.req.set_body_file](#ngxreqset_body_file). @@ -5593,7 +5597,7 @@ ngx.req.set_body_file **syntax:** *ngx.req.set_body_file(file_name, auto_clean?)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, balancer_by_lua*,* Set the current request's request body using the in-file data specified by the `file_name` argument. diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 89cf1ca707..a0e6d28fac 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -4657,7 +4657,7 @@ See also [[#ngx.req.get_body_data|ngx.req.get_body_data]]. '''syntax:''' ''ngx.req.set_body_data(data)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, balancer_by_lua*'' Set the current request's request body using the in-memory data specified by the data argument. @@ -4665,6 +4665,8 @@ If the request body has not been read yet, call [[#ngx.req.read_body|ngx.req.rea Whether the previous request body has been read into memory or buffered into a disk file, it will be freed or the disk file will be cleaned up immediately, respectively. +Note that this function is also work for balancer phase but it needs to call [https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/balancer.md#recreate_request balancer.recreate_request] to make the change take effect after set the request body data or headers. + This function was first introduced in the v0.3.1rc18 release. See also [[#ngx.req.set_body_file|ngx.req.set_body_file]]. @@ -4673,7 +4675,7 @@ See also [[#ngx.req.set_body_file|ngx.req.set_body_file]]. '''syntax:''' ''ngx.req.set_body_file(file_name, auto_clean?)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, balancer_by_lua*'' Set the current request's request body using the in-file data specified by the file_name argument. @@ -4685,6 +4687,8 @@ Please ensure that the file specified by the file_name argument exi Whether the previous request body has been read into memory or buffered into a disk file, it will be freed or the disk file will be cleaned up immediately, respectively. +Note that this function is also work for balancer phase but it needs to call [https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/balancer.md#recreate_request balancer.recreate_request] to make the change take effect after set the request body data or headers. + This function was first introduced in the v0.3.1rc18 release. See also [[#ngx.req.set_body_data|ngx.req.set_body_data]]. diff --git a/src/ngx_http_lua_balancer.c b/src/ngx_http_lua_balancer.c index 620f71eea0..5401a1ac88 100644 --- a/src/ngx_http_lua_balancer.c +++ b/src/ngx_http_lua_balancer.c @@ -1288,7 +1288,7 @@ ngx_http_lua_ffi_balancer_recreate_request(ngx_http_request_t *r, /* u->request_bufs already contains a valid request buffer * remove it from chain first */ - u->request_bufs = u->request_bufs->next; + u->request_bufs = r->request_body->bufs; } return u->create_request(r); diff --git a/t/138-balancer.t b/t/138-balancer.t index 5ea94df96d..df63a03cda 100644 --- a/t/138-balancer.t +++ b/t/138-balancer.t @@ -12,7 +12,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * (blocks() * 4 + 9); +plan tests => repeat_each() * (blocks() * 4 + 7); #no_diff(); no_long_string(); @@ -637,3 +637,43 @@ ok --- no_error_log [error] [cirt] + + +=== TEST 20: recreate_request refresh body buffer when ngx.req.set_body_data is used in balancer phase +--- http_config + lua_package_path "../lua-resty-core/lib/?.lua;;"; + + server { + listen 127.0.0.1:$TEST_NGINX_RAND_PORT_1; + + location / { + content_by_lua_block { + ngx.req.read_body() + local body = ngx.req.get_body_data() + ngx.log(ngx.ERR, "body: ", body) + ngx.say(body) + } + } + } + + upstream foo { + server 127.0.0.1:$TEST_NGINX_RAND_PORT_1 max_fails=0; + + balancer_by_lua_block { + local bal = require "ngx.balancer" + ngx.req.set_body_data("hello world") + assert(bal.recreate_request()) + } + } + +--- config + location = /t { + proxy_http_version 1.1; + proxy_set_header Connection ""; + proxy_pass http://foo; + } +--- request +GET /t +--- error_code: 200 +--- response_body +hello world From 6f311f82c3eac71bc6cfb537b303b5fe4f424653 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Fri, 12 Jul 2024 21:12:48 +0800 Subject: [PATCH 173/254] tests: update ngixn to 1.25.3. --- .travis.yml | 4 ++-- t/138-balancer.t | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index d3b973c80d..e6321c453d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -64,8 +64,8 @@ env: #- NGINX_VERSION=1.21.4 OPENSSL_VER=1.1.0l OPENSSL_PATCH_VER=1.1.0d #- NGINX_VERSION=1.25.1 OPENSSL_VER=1.1.0l OPENSSL_PATCH_VER=1.1.0d - NGINX_VERSION=1.21.4 OPENSSL_VER=1.1.1w OPENSSL_PATCH_VER=1.1.1f - - NGINX_VERSION=1.25.1 OPENSSL_VER=1.1.1w OPENSSL_PATCH_VER=1.1.1f USE_PCRE2=Y - - NGINX_VERSION=1.25.1 BORINGSSL=1 TEST_NGINX_USE_HTTP3=1 USE_PCRE2=Y + - NGINX_VERSION=1.25.3 OPENSSL_VER=1.1.1w OPENSSL_PATCH_VER=1.1.1f USE_PCRE2=Y + - NGINX_VERSION=1.25.3 BORINGSSL=1 TEST_NGINX_USE_HTTP3=1 USE_PCRE2=Y #- NGINX_VERSION=1.25.1 OPENSSL_VER=1.1.1w TEST_NGINX_USE_HTTP2=1 services: diff --git a/t/138-balancer.t b/t/138-balancer.t index df63a03cda..41be75fcdc 100644 --- a/t/138-balancer.t +++ b/t/138-balancer.t @@ -639,6 +639,7 @@ ok [cirt] + === TEST 20: recreate_request refresh body buffer when ngx.req.set_body_data is used in balancer phase --- http_config lua_package_path "../lua-resty-core/lib/?.lua;;"; From ed8cb8fe302734a4d66c83348369785c3d57470c Mon Sep 17 00:00:00 2001 From: lijunlong Date: Tue, 16 Jul 2024 14:27:17 +0800 Subject: [PATCH 174/254] bugfix: treat shdict entries with ttl equal to 0 as expired. --- src/ngx_http_lua_shdict.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ngx_http_lua_shdict.c b/src/ngx_http_lua_shdict.c index c63eb3c107..146974d954 100644 --- a/src/ngx_http_lua_shdict.c +++ b/src/ngx_http_lua_shdict.c @@ -210,7 +210,7 @@ ngx_http_lua_shdict_lookup(ngx_shm_zone_t *shm_zone, ngx_uint_t hash, dd("time to live: %lld", (long long) ms); - if (ms < 0) { + if (ms <= 0) { dd("node already expired"); return NGX_DONE; } From 676872125514dbe02e2cf0b4c522e87e6e5db3d4 Mon Sep 17 00:00:00 2001 From: leslie Date: Thu, 25 Jul 2024 10:45:12 +0800 Subject: [PATCH 175/254] doc: update lua-cjson ref link. --- README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index e14d302bfb..29a81c1ca4 100644 --- a/README.markdown +++ b/README.markdown @@ -1011,7 +1011,7 @@ The order in which these modules are added during configuration is important bec filtering chain determines the final output, for example. The correct adding order is shown above. * 3rd-party Lua libraries: - * [lua-cjson](http://www.kyne.com.au/~mark/software/lua-cjson.php) + * [lua-cjson](https://www.kyne.au/~mark/software/lua-cjson.php) * Applications: * mysql: create database 'ngx_test', grant all privileges to user 'ngx_test', password is 'ngx_test' From 29fe7a504f843e270049d16277ca117f681d20ba Mon Sep 17 00:00:00 2001 From: Johnny Wang Date: Wed, 31 Jul 2024 08:38:06 +0800 Subject: [PATCH 176/254] dev: util/build.sh: fixed command line argument validation and environment variable usage. --- util/build.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/util/build.sh b/util/build.sh index 41896f2c7e..fdf5c4d53d 100755 --- a/util/build.sh +++ b/util/build.sh @@ -25,13 +25,13 @@ force=$2 add_fake_shm_module="--add-module=$root/t/data/fake-shm-module" add_http3_module=--with-http_v3_module -answer=`$root/util/ver-ge "$NGINX_VERSION" 1.25.1` +answer=`$root/util/ver-ge "$version" 1.25.1` if [ "$OPENSSL_VER" = "1.1.0l" ] || [ "$answer" = "N" ]; then add_http3_module="" fi disable_pcre2=--without-pcre2 -answer=`$root/util/ver-ge "$NGINX_VERSION" 1.25.1` +answer=`$root/util/ver-ge "$version" 1.25.1` if [ "$answer" = "N" ] || [ "$USE_PCRE2" = "Y" ]; then disable_pcre2="" fi From d535753f5421c66715bf71f3df65b11e255407e2 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Thu, 1 Aug 2024 16:34:36 +0800 Subject: [PATCH 177/254] bugfix: nginx crashed when binding local address failed from lua. * bugfix: nginx crashed when binding local address failed from lua. 0 0x00007f10b0b16c59 in __memcpy_ssse3_back () from /lib64/libc.so.6 1 0x000000000042e2ba in ngx_sprintf_str (buf=, last=last@entry=0x7fff82779250 "P\251#\002", src=, len=192, hexadecimal=hexadecimal@entry=0) at src/core/ngx_string.c:586 2 0x000000000042e824 in ngx_vslprintf (buf=, buf@entry=0x7fff82778279 "bind() failed (\347(G\300\a", last=last@entry=0x7fff82779250 "P\251#\002", fmt=0x59c7fc "V) failed", fmt@entry=0x59c7f6 "bind(%V) failed", args=args@entry=0x7fff82779258) at src/core/ngx_string.c:255 3 0x000000000042a243 in ngx_log_error_core (level=level@entry=3, log=log@entry=0x2263360, err=98, fmt=fmt@entry=0x59c7f6 "bind(%V) failed") at src/core/ngx_log.c:137 4 0x000000000044c4fc in ngx_event_connect_peer (pc=pc@entry=0x223a950) at src/event/ngx_event_connect.c:169 5 0x000000000049af8c in ngx_http_upstream_connect (r=r@entry=0x22923b0, u=u@entry=0x223a940) at src/http/ngx_http_upstream.c:1562 6 0x000000000049c410 in ngx_http_upstream_init_request (r=r@entry=0x22923b0) at src/http/ngx_http_upstream.c:826 7 0x000000000049ee79 in ngx_http_upstream_init (r=0x22923b0) at src/http/ngx_http_upstream.c:554 8 0x00000000004906ad in ngx_http_read_client_request_body (r=r@entry=0x22923b0, post_handler=0x49ed31 ) at src/http/ngx_http_request_body.c:47 9 0x00000000004dba84 in ngx_http_proxy_handler (r=0x22923b0) at src/http/modules/ngx_http_proxy_module.c:1023 10 0x00000000004822f4 in ngx_http_core_content_phase (r=0x22923b0, ph=) at src/http/ngx_http_core_module.c:1271 11 0x000000000047cb13 in ngx_http_core_run_phases (r=0x22923b0) at src/http/ngx_http_core_module.c:885 12 0x000000000047cc1e in ngx_http_handler (r=) at src/http/ngx_http_core_module.c:868 13 0x0000000000485f0e in ngx_http_run_posted_requests (c=c@entry=0x227c8f0) at src/http/ngx_http_request.c:2470 14 0x0000000000488b8b in ngx_http_process_request_headers (rev=rev@entry=0x22204f0) at src/http/ngx_http_request.c:1552 15 0x0000000000488e83 in ngx_http_process_request_line (rev=rev@entry=0x22204f0) at src/http/ngx_http_request.c:1196 16 0x0000000000489b82 in ngx_http_keepalive_handler (rev=0x22204f0) at src/http/ngx_http_request.c:3441 17 0x00000000004556e1 in ngx_epoll_process_events (cycle=0x2213ce0, timer=, flags=) at src/event/modules/ngx_epoll_module.c:901 18 0x000000000044a286 in ngx_process_events_and_timers (cycle=cycle@entry=0x2213ce0) at src/event/ngx_event.c:258 19 0x00000000004546a1 in ngx_single_process_cycle (cycle=cycle@entry=0x2213ce0) at src/os/unix/ngx_process_cycle.c:323 20 0x0000000000429793 in main (argc=, argv=) at src/core/nginx.c:384 --- src/ngx_http_lua_balancer.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/ngx_http_lua_balancer.c b/src/ngx_http_lua_balancer.c index 5401a1ac88..ae0f1380b5 100644 --- a/src/ngx_http_lua_balancer.c +++ b/src/ngx_http_lua_balancer.c @@ -994,7 +994,7 @@ ngx_http_lua_ffi_balancer_bind_to_local_addr(ngx_http_request_t *r, bp = (ngx_http_lua_balancer_peer_data_t *) u->peer.data; if (bp->local == NULL) { - bp->local = ngx_palloc(r->pool, sizeof(ngx_addr_t)); + bp->local = ngx_palloc(r->pool, sizeof(ngx_addr_t) + addr_len); if (bp->local == NULL) { p = ngx_snprintf(errbuf, *errbuf_size, "no memory"); *errbuf_size = p - errbuf; @@ -1009,6 +1009,10 @@ ngx_http_lua_ffi_balancer_bind_to_local_addr(ngx_http_request_t *r, return NGX_ERROR; } + bp->local->name.len = addr_len; + bp->local->name.data = (u_char *) (bp->local + 1); + ngx_memcpy(bp->local->name.data, addr, addr_len); + return NGX_OK; } From 0b5507a25553e1d4271535d2efce29ad67c60bfe Mon Sep 17 00:00:00 2001 From: lijunlong Date: Thu, 1 Aug 2024 13:54:53 +0800 Subject: [PATCH 178/254] bugfix: added initialization. --- src/ngx_http_lua_ssl_ocsp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ngx_http_lua_ssl_ocsp.c b/src/ngx_http_lua_ssl_ocsp.c index c9f24cd281..73e1b9c7f5 100644 --- a/src/ngx_http_lua_ssl_ocsp.c +++ b/src/ngx_http_lua_ssl_ocsp.c @@ -280,7 +280,7 @@ ngx_http_lua_ffi_ssl_validate_ocsp_response(const u_char *resp, OCSP_RESPONSE *ocsp = NULL; OCSP_BASICRESP *basic = NULL; STACK_OF(X509) *chain = NULL; - ASN1_GENERALIZEDTIME *thisupdate, *nextupdate; + ASN1_GENERALIZEDTIME *thisupdate = NULL, *nextupdate = NULL; ocsp = d2i_OCSP_RESPONSE(NULL, &resp, resp_len); if (ocsp == NULL) { From 5777a36a93fe7520d958dd512a14d553e50b807b Mon Sep 17 00:00:00 2001 From: lijunlong Date: Thu, 1 Aug 2024 18:51:09 +0800 Subject: [PATCH 179/254] bugfix: failed to build on the old nginx version. --- src/ngx_http_lua_module.c | 6 +++++- src/ngx_http_lua_ssl_client_helloby.c | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/ngx_http_lua_module.c b/src/ngx_http_lua_module.c index 14ed235838..63367f46b3 100644 --- a/src/ngx_http_lua_module.c +++ b/src/ngx_http_lua_module.c @@ -1514,7 +1514,11 @@ ngx_http_lua_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_bitmask_value(conf->ssl_protocols, prev->ssl_protocols, (NGX_CONF_BITMASK_SET |NGX_SSL_TLSv1|NGX_SSL_TLSv1_1 - |NGX_SSL_TLSv1_2|NGX_SSL_TLSv1_3)); + |NGX_SSL_TLSv1_2 +#ifdef NGX_SSL_TLSv1_3 + |NGX_SSL_TLSv1_3 +#endif + )); ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers, "DEFAULT"); diff --git a/src/ngx_http_lua_ssl_client_helloby.c b/src/ngx_http_lua_ssl_client_helloby.c index b808f98ed7..9800f7d41f 100644 --- a/src/ngx_http_lua_ssl_client_helloby.c +++ b/src/ngx_http_lua_ssl_client_helloby.c @@ -712,7 +712,7 @@ ngx_http_lua_ffi_ssl_set_protocols(ngx_http_request_t *r, } #endif -#ifdef SSL_OP_NO_TLSv1_3 +#if defined(NGX_SSL_TLSv1_3) && defined( SSL_OP_NO_TLSv1_3) SSL_clear_options(ssl_conn, SSL_OP_NO_TLSv1_3); if (!(protocols & NGX_SSL_TLSv1_3)) { SSL_set_options(ssl_conn, SSL_OP_NO_TLSv1_3); From bf4bdcd5b299fc5680eb7d6fd594d4a49983de21 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Tue, 6 Aug 2024 12:36:58 +0800 Subject: [PATCH 180/254] bugfix: fixed keepalive error in cosocket. This bug was found in t/129-ssl-socket.t Test 18 when TEST_NGINX_EVENT_TYPE=poll enabled. --- src/ngx_http_lua_socket_tcp.c | 10 +++++ t/129-ssl-socket.t | 76 ++++++++++++++++++++++++++++++++--- 2 files changed, 81 insertions(+), 5 deletions(-) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 214e78329e..5010dfa6ed 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -5747,6 +5747,16 @@ ngx_http_lua_socket_keepalive_close_handler(ngx_event_t *ev) "lua tcp socket keepalive close handler check stale events"); n = recv(c->fd, buf, 1, MSG_PEEK); +#if (NGX_HTTP_SSL) + /* ignore ssl protocol data like change cipher spec */ + if (n == 1 && c->ssl != NULL) { + n = c->recv(c, (unsigned char *) buf, 1); + if (n == NGX_AGAIN) { + n = -1; + ngx_socket_errno = NGX_EAGAIN; + } + } +#endif if (n == -1 && ngx_socket_errno == NGX_EAGAIN) { /* stale event */ diff --git a/t/129-ssl-socket.t b/t/129-ssl-socket.t index ccfa19fffb..ca8d5a49e6 100644 --- a/t/129-ssl-socket.t +++ b/t/129-ssl-socket.t @@ -1484,6 +1484,72 @@ SSL reused session === TEST 18: openresty.org: passing SSL verify: keepalive (no reusing the ssl session) +The session returned by SSL_get1_session maybe different. +After function tls_process_new_session_ticket, the session saved in SSL->session +will be replace by a new one. + +ngx_ssl_session_t * +ngx_ssl_get_session(ngx_connection_t *c) +{ +#ifdef TLS1_3_VERSION + if (c->ssl->session) { + SSL_SESSION_up_ref(c->ssl->session); + return c->ssl->session; + } +#endif + + return SSL_get1_session(c->ssl->connection); +} + +SSL_SESSION *SSL_get1_session(SSL *ssl) +/* variant of SSL_get_session: caller really gets something */ +{ + SSL_SESSION *sess; + /* + * Need to lock this all up rather than just use CRYPTO_add so that + * somebody doesn't free ssl->session between when we check it's non-null + * and when we up the reference count. + */ + CRYPTO_THREAD_read_lock(ssl->lock); + sess = ssl->session; + if (sess) + SSL_SESSION_up_ref(sess); + CRYPTO_THREAD_unlock(ssl->lock); + return sess; +} + +#0 tls_process_new_session_ticket (s=0x7e6ea0, pkt=0x7fffffffc820) at ssl/statem/statem_clnt.c:2650 +#1 0x00007ffff7af50fd in read_state_machine (s=0x7e6ea0) at ssl/statem/statem.c:636 +#2 state_machine (s=0x7e6ea0, server=0) at ssl/statem/statem.c:434 +#3 0x00007ffff7aca6b3 in ssl3_read_bytes (s=, type=23, recvd_type=0x0, buf=0x7fffffffc9d7 "\027\320\355t", len=1, + peek=0, readbytes=0x7fffffffc978) at ssl/record/rec_layer_s3.c:1677 +#4 0x00007ffff7ad2250 in ssl3_read_internal (readbytes=0x7fffffffc978, peek=0, len=1, buf=0x7fffffffc9d7, s=0x7e6ea0) + at ssl/s3_lib.c:4477 +#5 ssl3_read (s=0x7e6ea0, buf=0x7fffffffc9d7, len=1, readbytes=0x7fffffffc978) at ssl/s3_lib.c:4500 +#6 0x00007ffff7ade695 in SSL_read (s=, buf=buf@entry=0x7fffffffc9d7, num=num@entry=1) at ssl/ssl_lib.c:1799 +#7 0x000000000045a965 in ngx_ssl_recv (c=0x72c3b0, buf=0x7fffffffc9d7 "\027\320\355t", size=1) + at src/event/ngx_event_openssl.c:2337 +#8 0x0000000000533b17 in ngx_http_lua_socket_keepalive_close_handler (ev=0x7e2f20) + at /var/code/openresty/lua-nginx-module/src/ngx_http_lua_socket_tcp.c:5753 +#9 0x000000000052cf40 in ngx_http_lua_socket_tcp_setkeepalive (L=0x74edd0) + at /var/code/openresty/lua-nginx-module/src/ngx_http_lua_socket_tcp.c:5602 +#10 0x00007ffff7f0fabe in lj_BC_FUNCC () + from /tmp/undodb.72729.1722915526.2470007.80d50d088e818fd4/debuggee-1-zwqz8svp/symbol-files/opt/luajit-sysm/lib/libluajit-5.1.so.2 +#11 0x000000000051f2b2 in ngx_http_lua_run_thread (L=L@entry=0x767670, r=r@entry=0x7edf80, ctx=ctx@entry=0x750e40, nrets=0) + at /var/code/openresty/lua-nginx-module/src/ngx_http_lua_util.c:1194 +#12 0x0000000000524347 in ngx_http_lua_content_by_chunk (L=0x767670, r=0x7edf80) + at /var/code/openresty/lua-nginx-module/src/ngx_http_lua_contentby.c:124 +#13 0x000000000047c663 in ngx_http_core_content_phase (r=0x7edf80, ph=0x7b4470) at src/http/ngx_http_core_module.c:1271 +#14 0x000000000047b80d in ngx_http_core_run_phases (r=0x7edf80) at src/http/ngx_http_core_module.c:885 +#15 ngx_http_handler (r=r@entry=0x7edf80) at src/http/ngx_http_core_module.c:868 +#16 0x00000000004854ad in ngx_http_process_request (r=r@entry=0x7edf80) at src/http/ngx_http_request.c:2140 +#17 0x00000000004868e8 in ngx_http_process_request_headers (rev=rev@entry=0x7e2f80) at src/http/ngx_http_request.c:1529 +#18 0x0000000000486468 in ngx_http_process_request_line (rev=0x7e2f80) at src/http/ngx_http_request.c:1196 +#19 0x000000000044b338 in ngx_event_process_posted (cycle=cycle@entry=0x721690, posted=0x62f250 ) + at src/event/ngx_event_posted.c:35 +#20 0x000000000044a522 in ngx_process_events_and_timers (cycle=cycle@entry=0x721690) at src/event/ngx_event.c:273 +#21 0x0000000000453819 in ngx_single_process_cycle (cycle=cycle@entry=0x721690) at src/os/unix/ngx_process_cycle.c:323 +#22 0x0000000000429dee in main (argc=argc@entry=5, argv=argv@entry=0x7fffffffd1a8) at src/core/nginx.c:384 --- config server_tokens off; resolver $TEST_NGINX_RESOLVER ipv6=off; @@ -1548,11 +1614,11 @@ set keepalive: 1 nil --- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+/ --- grep_error_log_out eval qr/^lua ssl save session: ([0-9A-F]+) -lua ssl save session: \1 -lua ssl save session: \1 -lua ssl free session: \1 -lua ssl free session: \1 -lua ssl free session: \1 +lua ssl save session: ([0-9A-F]+) +lua ssl save session: ([0-9A-F]+) +lua ssl free session: ([0-9A-F]+) +lua ssl free session: ([0-9A-F]+) +lua ssl free session: ([0-9A-F]+) $/ --- error_log From b3c6aebcc79528c69794441d55cf228c9fd64af0 Mon Sep 17 00:00:00 2001 From: jiahao Date: Thu, 30 May 2024 11:43:06 +0800 Subject: [PATCH 181/254] travis: bumped the NGINX core to 1.27.0. --- .travis.yml | 6 +++--- t/014-bugs.t | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index e6321c453d..24902f8168 100644 --- a/.travis.yml +++ b/.travis.yml @@ -64,8 +64,8 @@ env: #- NGINX_VERSION=1.21.4 OPENSSL_VER=1.1.0l OPENSSL_PATCH_VER=1.1.0d #- NGINX_VERSION=1.25.1 OPENSSL_VER=1.1.0l OPENSSL_PATCH_VER=1.1.0d - NGINX_VERSION=1.21.4 OPENSSL_VER=1.1.1w OPENSSL_PATCH_VER=1.1.1f - - NGINX_VERSION=1.25.3 OPENSSL_VER=1.1.1w OPENSSL_PATCH_VER=1.1.1f USE_PCRE2=Y - - NGINX_VERSION=1.25.3 BORINGSSL=1 TEST_NGINX_USE_HTTP3=1 USE_PCRE2=Y + - NGINX_VERSION=1.27.0 OPENSSL_VER=1.1.1w OPENSSL_PATCH_VER=1.1.1f USE_PCRE2=Y TEST_NGINX_TIMEOUT=5 + - NGINX_VERSION=1.27.0 BORINGSSL=1 TEST_NGINX_USE_HTTP3=1 USE_PCRE2=Y TEST_NGINX_QUIC_IDLE_TIMEOUT=3 #- NGINX_VERSION=1.25.1 OPENSSL_VER=1.1.1w TEST_NGINX_USE_HTTP2=1 services: @@ -87,7 +87,7 @@ install: - wget https://github.com/openresty/openresty-deps-prebuild/releases/download/v20230902/boringssl-20230902-x64-focal.tar.gz - wget https://github.com/openresty/openresty-deps-prebuild/releases/download/v20230902/curl-h3-x64-focal.tar.gz - git clone https://github.com/openresty/test-nginx.git - - git clone https://github.com/openresty/openresty.git ../openresty + - git clone -b bump-1.27.0 https://github.com/xiaocang/openresty.git ../openresty - git clone https://github.com/openresty/no-pool-nginx.git ../no-pool-nginx - git clone https://github.com/openresty/openresty-devel-utils.git - git clone https://github.com/openresty/mockeagain.git diff --git a/t/014-bugs.t b/t/014-bugs.t index 1b79aa4c59..d34f42e23d 100644 --- a/t/014-bugs.t +++ b/t/014-bugs.t @@ -828,7 +828,7 @@ qr/curl: \(28\) Operation timed out after \d+ milliseconds with 0 bytes received rewrite ^/myproxy/(.*) /$1 break; resolver_timeout 3s; #resolver 172.16.0.23; # AWS DNS resolver address is the same in all regions - 172.16.0.23 - resolver 8.8.8.8; + resolver $TEST_NGINX_RESOLVER; proxy_read_timeout 1s; proxy_send_timeout 1s; proxy_connect_timeout 1s; From 0ea5e94a80fe92213891942b16f0e4db20d48407 Mon Sep 17 00:00:00 2001 From: jiahao Date: Tue, 4 Jun 2024 18:44:26 +0800 Subject: [PATCH 182/254] tests: added curl_error for http/3. --- t/068-socket-keepalive.t | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/t/068-socket-keepalive.t b/t/068-socket-keepalive.t index 1660a3a361..626b441678 100644 --- a/t/068-socket-keepalive.t +++ b/t/068-socket-keepalive.t @@ -3109,6 +3109,8 @@ qr/\Qbad argument #1 to 'setkeepalive' (number expected, got string)\E/ --- no_error_log [crit] --- timeout: 4 +--- curl_error eval +qr{HTTP/3 stream 0 reset by server} @@ -3189,3 +3191,5 @@ qr/\Qbad argument #2 to 'setkeepalive' (number expected, got string)\E/ --- no_error_log [crit] --- timeout: 4 +--- curl_error eval +qr{HTTP/3 stream 0 reset by server} From f1cbe4ae945b2005c38147e14431c766a2146eec Mon Sep 17 00:00:00 2001 From: jiahao Date: Wed, 3 Jul 2024 18:10:49 +0800 Subject: [PATCH 183/254] tests: t/020-subrequest.t: replace the random port with an unused five-digit port. --- .travis.yml | 2 +- t/020-subrequest.t | 59 +++++++++++++++++++++++++++------------------- 2 files changed, 36 insertions(+), 25 deletions(-) diff --git a/.travis.yml b/.travis.yml index 24902f8168..6033ee185f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -87,7 +87,7 @@ install: - wget https://github.com/openresty/openresty-deps-prebuild/releases/download/v20230902/boringssl-20230902-x64-focal.tar.gz - wget https://github.com/openresty/openresty-deps-prebuild/releases/download/v20230902/curl-h3-x64-focal.tar.gz - git clone https://github.com/openresty/test-nginx.git - - git clone -b bump-1.27.0 https://github.com/xiaocang/openresty.git ../openresty + - git clone https://github.com/openresty/openresty.git ../openresty - git clone https://github.com/openresty/no-pool-nginx.git ../no-pool-nginx - git clone https://github.com/openresty/openresty-devel-utils.git - git clone https://github.com/openresty/mockeagain.git diff --git a/t/020-subrequest.t b/t/020-subrequest.t index 59b9f61a34..37914be061 100644 --- a/t/020-subrequest.t +++ b/t/020-subrequest.t @@ -1,6 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use Test::Nginx::Socket::Lua; +use Test::Nginx::Util 'is_tcp_port_used'; #master_on(); #workers(1); @@ -16,6 +17,16 @@ plan tests => repeat_each() * (blocks() * 3 + 23); $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; $ENV{TEST_NGINX_HTML_DIR} ||= html_dir(); +# NB: tcp_listen_port needs to be greater than 10000, +# because the test cases expect it to be a 5-digit number +my $tcp_listen_port = 19113; +while (++$tcp_listen_port < 65535) { + if (!is_tcp_port_used $tcp_listen_port) { + last; + } +} +$ENV{TEST_NGINX_TCP_LISTEN_PORT} = $tcp_listen_port; + #no_diff(); no_long_string(); #no_shuffle(); @@ -1383,7 +1394,7 @@ upstream timed out #proxy_read_timeout 100ms; proxy_buffering on; - proxy_pass http://127.0.0.1:$TEST_NGINX_RAND_PORT_2; + proxy_pass http://127.0.0.1:$TEST_NGINX_TCP_LISTEN_PORT; } location /main { @@ -1396,7 +1407,7 @@ upstream timed out } --- request GET /main ---- tcp_listen: $TEST_NGINX_RAND_PORT_2 +--- tcp_listen: $TEST_NGINX_TCP_LISTEN_PORT --- tcp_query_len: 65 --- tcp_reply eval "HTTP/1.0 200 OK\r\nContent-Length: 1024\r\n\r\nhello world" @@ -1443,7 +1454,7 @@ upstream prematurely closed connection proxy_read_timeout 100ms; proxy_buffering on; - proxy_pass http://127.0.0.1:$TEST_NGINX_RAND_PORT_2; + proxy_pass http://127.0.0.1:$TEST_NGINX_TCP_LISTEN_PORT; } location /main { @@ -1456,7 +1467,7 @@ upstream prematurely closed connection } --- request GET /main ---- tcp_listen: $TEST_NGINX_RAND_PORT_2 +--- tcp_listen: $TEST_NGINX_TCP_LISTEN_PORT --- tcp_no_close --- tcp_reply eval "HTTP/1.0 200 OK\r\nContent-Length: 1024\r\n\r\nhello world" @@ -1505,7 +1516,7 @@ upstream timed out #proxy_read_timeout 100ms; proxy_buffering on; - proxy_pass http://127.0.0.1:$TEST_NGINX_RAND_PORT_2; + proxy_pass http://127.0.0.1:$TEST_NGINX_TCP_LISTEN_PORT; } location /main { @@ -1518,7 +1529,7 @@ upstream timed out } --- request GET /main ---- tcp_listen: $TEST_NGINX_RAND_PORT_2 +--- tcp_listen: $TEST_NGINX_TCP_LISTEN_PORT --- tcp_query_len: 65 --- tcp_reply eval "HTTP/1.0 200 OK\r\n\r\nhello world" @@ -1565,7 +1576,7 @@ truncated: false proxy_read_timeout 100ms; proxy_buffering on; - proxy_pass http://127.0.0.1:$TEST_NGINX_RAND_PORT_2; + proxy_pass http://127.0.0.1:$TEST_NGINX_TCP_LISTEN_PORT; } location /main { @@ -1578,7 +1589,7 @@ truncated: false } --- request GET /main ---- tcp_listen: $TEST_NGINX_RAND_PORT_2 +--- tcp_listen: $TEST_NGINX_TCP_LISTEN_PORT --- tcp_no_close --- tcp_reply eval "HTTP/1.0 200 OK\r\n\r\nhello world" @@ -1628,7 +1639,7 @@ upstream timed out #proxy_read_timeout 100ms; proxy_buffering off; - proxy_pass http://127.0.0.1:$TEST_NGINX_RAND_PORT_2; + proxy_pass http://127.0.0.1:$TEST_NGINX_TCP_LISTEN_PORT; } location /main { @@ -1641,7 +1652,7 @@ upstream timed out } --- request GET /main ---- tcp_listen: $TEST_NGINX_RAND_PORT_2 +--- tcp_listen: $TEST_NGINX_TCP_LISTEN_PORT --- tcp_query_len: 65 --- tcp_reply eval "HTTP/1.0 200 OK\r\n\r\nhello world" @@ -1688,7 +1699,7 @@ truncated: false proxy_read_timeout 500ms; proxy_buffering off; - proxy_pass http://127.0.0.1:$TEST_NGINX_RAND_PORT_2; + proxy_pass http://127.0.0.1:$TEST_NGINX_TCP_LISTEN_PORT; } location /main { @@ -1701,7 +1712,7 @@ truncated: false } --- request GET /main ---- tcp_listen: $TEST_NGINX_RAND_PORT_2 +--- tcp_listen: $TEST_NGINX_TCP_LISTEN_PORT --- tcp_no_close --- tcp_reply eval "HTTP/1.0 200 OK\r\n\r\nhello world" @@ -1914,7 +1925,7 @@ a client request body is buffered to a temporary file #proxy_read_timeout 100ms; proxy_http_version 1.1; proxy_buffering on; - proxy_pass http://127.0.0.1:$TEST_NGINX_RAND_PORT_2; + proxy_pass http://127.0.0.1:$TEST_NGINX_TCP_LISTEN_PORT; } location /main { @@ -1927,7 +1938,7 @@ a client request body is buffered to a temporary file } --- request GET /main ---- tcp_listen: $TEST_NGINX_RAND_PORT_2 +--- tcp_listen: $TEST_NGINX_TCP_LISTEN_PORT --- tcp_query_len: 65 --- tcp_reply eval "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\nb\r\nhello world\r" @@ -1977,7 +1988,7 @@ upstream prematurely closed connection #proxy_read_timeout 100ms; proxy_http_version 1.1; proxy_buffering off; - proxy_pass http://127.0.0.1:$TEST_NGINX_RAND_PORT_2; + proxy_pass http://127.0.0.1:$TEST_NGINX_TCP_LISTEN_PORT; } location /main { @@ -1990,7 +2001,7 @@ upstream prematurely closed connection } --- request GET /main ---- tcp_listen: $TEST_NGINX_RAND_PORT_2 +--- tcp_listen: $TEST_NGINX_TCP_LISTEN_PORT --- tcp_query_len: 65 --- tcp_reply eval "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\nb\r\nhello world\r" @@ -2038,7 +2049,7 @@ upstream prematurely closed connection proxy_read_timeout 100ms; proxy_buffering on; proxy_http_version 1.1; - proxy_pass http://127.0.0.1:$TEST_NGINX_RAND_PORT_2; + proxy_pass http://127.0.0.1:$TEST_NGINX_TCP_LISTEN_PORT; } location /main { @@ -2051,7 +2062,7 @@ upstream prematurely closed connection } --- request GET /main ---- tcp_listen: $TEST_NGINX_RAND_PORT_2 +--- tcp_listen: $TEST_NGINX_TCP_LISTEN_PORT --- tcp_no_close --- tcp_reply eval "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\nb\r\nhello world\r" @@ -2100,7 +2111,7 @@ upstream timed out #proxy_read_timeout 100ms; proxy_buffering on; proxy_http_version 1.1; - proxy_pass http://127.0.0.1:$TEST_NGINX_RAND_PORT_2; + proxy_pass http://127.0.0.1:$TEST_NGINX_TCP_LISTEN_PORT; } location /main { @@ -2113,7 +2124,7 @@ upstream timed out } --- request GET /main ---- tcp_listen: $TEST_NGINX_RAND_PORT_2 +--- tcp_listen: $TEST_NGINX_TCP_LISTEN_PORT --- tcp_no_close --- tcp_reply eval "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n5\r\nhello\r\n0\r\n\r\n" @@ -2158,7 +2169,7 @@ truncated: false #proxy_read_timeout 100ms; proxy_buffering off; proxy_http_version 1.1; - proxy_pass http://127.0.0.1:$TEST_NGINX_RAND_PORT_2; + proxy_pass http://127.0.0.1:$TEST_NGINX_TCP_LISTEN_PORT; } location /main { @@ -2171,7 +2182,7 @@ truncated: false } --- request GET /main ---- tcp_listen: $TEST_NGINX_RAND_PORT_2 +--- tcp_listen: $TEST_NGINX_TCP_LISTEN_PORT --- tcp_no_close --- tcp_reply eval "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n5\r\nhello\r\n0\r\n\r\n" @@ -2217,7 +2228,7 @@ truncated: false #proxy_read_timeout 100ms; proxy_buffering off; - proxy_pass http://127.0.0.1:$TEST_NGINX_RAND_PORT_2; + proxy_pass http://127.0.0.1:$TEST_NGINX_TCP_LISTEN_PORT; } location /main { @@ -2230,7 +2241,7 @@ truncated: false } --- request GET /main ---- tcp_listen: $TEST_NGINX_RAND_PORT_2 +--- tcp_listen: $TEST_NGINX_TCP_LISTEN_PORT --- tcp_query_len: 65 --- tcp_reply eval "HTTP/1.0 200 OK\r\nContent-Length: 1024\r\n\r\nhello world" From 2d8fcbe6435b0bf4b0ae91dd84002cce9fe20c8c Mon Sep 17 00:00:00 2001 From: jiahao Date: Thu, 1 Aug 2024 23:12:49 +0800 Subject: [PATCH 184/254] tests: skip t/163-signal.t in check leak mode. --- t/163-signal.t | 3 +++ 1 file changed, 3 insertions(+) diff --git a/t/163-signal.t b/t/163-signal.t index 15f41e2200..0ce8fa2613 100644 --- a/t/163-signal.t +++ b/t/163-signal.t @@ -5,6 +5,9 @@ our $SkipReason; BEGIN { if ($ENV{TEST_NGINX_USE_HUP}) { $SkipReason = "unavailable under hup test mode"; + + } elsif ($ENV{TEST_NGINX_CHECK_LEAK}) { + $SkipReason = "unavailable under check leak test mode"; } } From 0cc05a6090886880d4e04ab6a5cdebbfa7da2ccc Mon Sep 17 00:00:00 2001 From: jiahao Date: Fri, 2 Aug 2024 16:37:00 +0800 Subject: [PATCH 185/254] tests: t/188-*.t: use random port instead of 8090 port. --- t/188-balancer_keepalive_pool_max_retry.t | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/t/188-balancer_keepalive_pool_max_retry.t b/t/188-balancer_keepalive_pool_max_retry.t index 456ea794c9..679ee680f8 100644 --- a/t/188-balancer_keepalive_pool_max_retry.t +++ b/t/188-balancer_keepalive_pool_max_retry.t @@ -35,9 +35,9 @@ __DATA__ if ngx.ctx.tries == 1 then balancer.set_more_tries(5) end - + local host = "127.0.0.1" - local port = 8090; + local port = $TEST_NGINX_RAND_PORT_1; local ok, err = balancer.set_current_peer(host, port) if not ok then @@ -56,9 +56,9 @@ __DATA__ } server { - listen 0.0.0.0:8090; + listen 127.0.0.1:$TEST_NGINX_RAND_PORT_1; location /hello { - content_by_lua_block{ + content_by_lua_block{ local request_counter = ngx.shared.request_counter local first_request = request_counter:get("first_request") if first_request == nil then @@ -74,7 +74,7 @@ __DATA__ location = /t { proxy_pass http://my_upstream; proxy_set_header Connection "keep-alive"; - + rewrite_by_lua_block { ngx.req.set_uri("/hello") } From f44c18859050be5af314bae8f05660478af5e31d Mon Sep 17 00:00:00 2001 From: Johnny Wang Date: Thu, 8 Aug 2024 23:41:21 +0800 Subject: [PATCH 186/254] bumped version of lua-nginx-module to 10027. --- src/api/ngx_http_lua_api.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/ngx_http_lua_api.h b/src/api/ngx_http_lua_api.h index 193c44e3a8..4b374f56ee 100644 --- a/src/api/ngx_http_lua_api.h +++ b/src/api/ngx_http_lua_api.h @@ -19,7 +19,7 @@ /* Public API for other Nginx modules */ -#define ngx_http_lua_version 10026 +#define ngx_http_lua_version 10027 typedef struct ngx_http_lua_co_ctx_s ngx_http_lua_co_ctx_t; From d6cf113d6b80946b9d440fd1d43d0795edcbfb63 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Sat, 17 Aug 2024 18:29:38 +0800 Subject: [PATCH 187/254] feature: update nginx to v1.27.1. --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6033ee185f..177d6488ca 100644 --- a/.travis.yml +++ b/.travis.yml @@ -64,8 +64,8 @@ env: #- NGINX_VERSION=1.21.4 OPENSSL_VER=1.1.0l OPENSSL_PATCH_VER=1.1.0d #- NGINX_VERSION=1.25.1 OPENSSL_VER=1.1.0l OPENSSL_PATCH_VER=1.1.0d - NGINX_VERSION=1.21.4 OPENSSL_VER=1.1.1w OPENSSL_PATCH_VER=1.1.1f - - NGINX_VERSION=1.27.0 OPENSSL_VER=1.1.1w OPENSSL_PATCH_VER=1.1.1f USE_PCRE2=Y TEST_NGINX_TIMEOUT=5 - - NGINX_VERSION=1.27.0 BORINGSSL=1 TEST_NGINX_USE_HTTP3=1 USE_PCRE2=Y TEST_NGINX_QUIC_IDLE_TIMEOUT=3 + - NGINX_VERSION=1.27.1 OPENSSL_VER=1.1.1w OPENSSL_PATCH_VER=1.1.1f USE_PCRE2=Y TEST_NGINX_TIMEOUT=5 + - NGINX_VERSION=1.27.1 BORINGSSL=1 TEST_NGINX_USE_HTTP3=1 USE_PCRE2=Y TEST_NGINX_QUIC_IDLE_TIMEOUT=3 #- NGINX_VERSION=1.25.1 OPENSSL_VER=1.1.1w TEST_NGINX_USE_HTTP2=1 services: From aad278bc8c37d55023cf2e6c3b3040c01bf0083a Mon Sep 17 00:00:00 2001 From: Johnny Wang Date: Sat, 17 Aug 2024 20:23:35 +0800 Subject: [PATCH 188/254] tests: bumped the NGINX core to 1.27.1. From ea09d92adf835e30cab8d79343c7b8266e888128 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Tue, 20 Aug 2024 16:13:59 +0800 Subject: [PATCH 189/254] bugfix: failed to build on windows. --- src/ngx_http_lua_socket_tcp.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 5010dfa6ed..a0e041b017 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -5725,6 +5725,7 @@ ngx_http_lua_socket_keepalive_close_handler(ngx_event_t *ev) ngx_http_lua_socket_pool_t *spool; int n; + int err; char buf[1]; ngx_connection_t *c; @@ -5747,18 +5748,19 @@ ngx_http_lua_socket_keepalive_close_handler(ngx_event_t *ev) "lua tcp socket keepalive close handler check stale events"); n = recv(c->fd, buf, 1, MSG_PEEK); + err = ngx_socket_errno; #if (NGX_HTTP_SSL) /* ignore ssl protocol data like change cipher spec */ if (n == 1 && c->ssl != NULL) { n = c->recv(c, (unsigned char *) buf, 1); if (n == NGX_AGAIN) { n = -1; - ngx_socket_errno = NGX_EAGAIN; + err = NGX_EAGAIN; } } #endif - if (n == -1 && ngx_socket_errno == NGX_EAGAIN) { + if (n == -1 && err == NGX_EAGAIN) { /* stale event */ if (ngx_handle_read_event(c->read, 0) != NGX_OK) { From 55f55efbd159f7376aba6e388983b96c20b5698c Mon Sep 17 00:00:00 2001 From: Josh Soref <2119212+jsoref@users.noreply.github.com> Date: Fri, 23 Aug 2024 20:45:17 -0400 Subject: [PATCH 190/254] doc: improve grammar. --- README.markdown | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.markdown b/README.markdown index 29a81c1ca4..4d09757015 100644 --- a/README.markdown +++ b/README.markdown @@ -269,7 +269,7 @@ memory use. Request contexts are segregated using lightweight Lua coroutines. Loaded Lua modules persist in the Nginx worker process level resulting in a small memory footprint in Lua even when under heavy loads. -This module is plugged into Nginx's "http" subsystem so it can only speaks +This module is plugged into Nginx's "http" subsystem so it can only speak downstream communication protocols in the HTTP family (HTTP 0.9/1.0/1.1/2.0, WebSockets, etc...). If you want to do generic TCP communications with the downstream clients, then you should use the @@ -283,7 +283,7 @@ Typical Uses Just to name a few: -* Mashup'ing and processing outputs of various Nginx upstream outputs (proxy, drizzle, postgres, redis, memcached, and etc) in Lua, +* Mashup'ing and processing outputs of various Nginx upstream outputs (proxy, drizzle, postgres, redis, memcached, etc.) in Lua, * doing arbitrarily complex access control and security checks in Lua before requests actually reach the upstream backends, * manipulating response headers in an arbitrary way (by Lua) * fetching backend information from external storage backends (like redis, memcached, mysql, postgresql) and use that information to choose which upstream backend to access on-the-fly, @@ -337,7 +337,7 @@ It is discouraged to build this module with Nginx yourself since it is tricky to set up exactly right. Note that Nginx, LuaJIT, and OpenSSL official releases have various limitations -and long standing bugs that can cause some of this module's features to be +and long-standing bugs that can cause some of this module's features to be disabled, not work properly, or run slower. Official OpenResty releases are recommended because they bundle [OpenResty's optimized LuaJIT 2.1 fork](https://github.com/openresty/luajit2) and [Nginx/OpenSSL @@ -421,7 +421,7 @@ While building this module either via OpenResty or with the Nginx core, you can * `NGX_LUA_USE_ASSERT` When defined, will enable assertions in the ngx_lua C code base. Recommended for debugging or testing builds. It can introduce some (small) runtime overhead when enabled. This macro was first introduced in the `v0.9.10` release. * `NGX_LUA_ABORT_AT_PANIC` - When the LuaJIT VM panics, ngx_lua will instruct the current nginx worker process to quit gracefully by default. By specifying this C macro, ngx_lua will abort the current nginx worker process (which usually result in a core dump file) immediately. This option is useful for debugging VM panics. This option was first introduced in the `v0.9.8` release. + When the LuaJIT VM panics, ngx_lua will instruct the current nginx worker process to quit gracefully by default. By specifying this C macro, ngx_lua will abort the current nginx worker process (which usually results in a core dump file) immediately. This option is useful for debugging VM panics. This option was first introduced in the `v0.9.8` release. To enable one or more of these macros, just pass extra C compiler options to the `./configure` script of either Nginx or OpenResty. For instance, @@ -4149,7 +4149,7 @@ Then `GET /main` will give the output Here, modification of the `ngx.ctx.blah` entry in the subrequest does not affect the one in the parent request. This is because they have two separate versions of `ngx.ctx.blah`. -Internal redirects (triggered by nginx configuration directives like `error_page`, `try_files`, `index` and etc) will destroy the original request `ngx.ctx` data (if any) and the new request will have an empty `ngx.ctx` table. For instance, +Internal redirects (triggered by nginx configuration directives like `error_page`, `try_files`, `index`, etc.) will destroy the original request `ngx.ctx` data (if any) and the new request will have an empty `ngx.ctx` table. For instance, ```nginx @@ -8996,7 +8996,7 @@ this context. You must notice that each timer will be based on a fake request (this fake request is also based on a fake connection). Because Nginx's memory release is based on the connection closure, if you run a lot of APIs that apply for memory resources in a timer, such as [tcpsock:connect](#tcpsockconnect), will cause the accumulation of memory resources. So it is recommended to create a new timer after running several times to release memory resources. -You can pass most of the standard Lua values (nils, booleans, numbers, strings, tables, closures, file handles, and etc) into the timer callback, either explicitly as user arguments or implicitly as upvalues for the callback closure. There are several exceptions, however: you *cannot* pass any thread objects returned by [coroutine.create](#coroutinecreate) and [ngx.thread.spawn](#ngxthreadspawn) or any cosocket objects returned by [ngx.socket.tcp](#ngxsockettcp), [ngx.socket.udp](#ngxsocketudp), and [ngx.req.socket](#ngxreqsocket) because these objects' lifetime is bound to the request context creating them while the timer callback is detached from the creating request's context (by design) and runs in its own (fake) request context. If you try to share the thread or cosocket objects across the boundary of the creating request, then you will get the "no co ctx found" error (for threads) or "bad request" (for cosockets). It is fine, however, to create all these objects inside your timer callback. +You can pass most of the standard Lua values (nils, booleans, numbers, strings, tables, closures, file handles, etc.) into the timer callback, either explicitly as user arguments or implicitly as upvalues for the callback closure. There are several exceptions, however: you *cannot* pass any thread objects returned by [coroutine.create](#coroutinecreate) and [ngx.thread.spawn](#ngxthreadspawn) or any cosocket objects returned by [ngx.socket.tcp](#ngxsockettcp), [ngx.socket.udp](#ngxsocketudp), and [ngx.req.socket](#ngxreqsocket) because these objects' lifetime is bound to the request context creating them while the timer callback is detached from the creating request's context (by design) and runs in its own (fake) request context. If you try to share the thread or cosocket objects across the boundary of the creating request, then you will get the "no co ctx found" error (for threads) or "bad request" (for cosockets). It is fine, however, to create all these objects inside your timer callback. Please note that the timer Lua handler has its own copy of the `ngx.ctx` magic table. It won't share the same `ngx.ctx` with the Lua handler creating the timer. @@ -9489,7 +9489,7 @@ The type of `args` must be one of type below: * nil * table (the table may be recursive, and contains members of types above.) -The `ok` is in boolean type, which indicate the C land error (failed to get thread from thread pool, pcall the module function failed, .etc). If `ok` is `false`, the `res1` is the error string. +The `ok` is in boolean type, which indicate the C land error (failed to get thread from thread pool, pcall the module function failed, etc.). If `ok` is `false`, the `res1` is the error string. The return values (res1, ...) are returned by invocation of the module function. Normally, the `res1` should be in boolean type, so that the caller could inspect the error. From 8ec4f0b5bde37532c4725dcf88579823a8e5f7a3 Mon Sep 17 00:00:00 2001 From: xiaobiaozhao <52393536+xiaobiaozhao@users.noreply.github.com> Date: Fri, 30 Aug 2024 10:27:50 +0800 Subject: [PATCH 191/254] doc: Redraw directives png (#2353) --- README.markdown | 2 +- .../lua_nginx_modules_directives.drawio.png | Bin 0 -> 145387 bytes 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 doc/images/lua_nginx_modules_directives.drawio.png diff --git a/README.markdown b/README.markdown index 4d09757015..25d1383f36 100644 --- a/README.markdown +++ b/README.markdown @@ -1184,7 +1184,7 @@ Directives The basic building blocks of scripting Nginx with Lua are directives. Directives are used to specify when the user Lua code is run and how the result will be used. Below is a diagram showing the order in which directives are executed. -![Lua Nginx Modules Directives](https://cloud.githubusercontent.com/assets/2137369/15272097/77d1c09e-1a37-11e6-97ef-d9767035fc3e.png) +![Lua Nginx Modules Directives](./doc/images/lua_nginx_modules_directives.drawio.png) [Back to TOC](#table-of-contents) diff --git a/doc/images/lua_nginx_modules_directives.drawio.png b/doc/images/lua_nginx_modules_directives.drawio.png new file mode 100644 index 0000000000000000000000000000000000000000..41112147f2fb1320c9ce132cdb334a1ef94109f7 GIT binary patch literal 145387 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�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 Date: Fri, 6 Sep 2024 13:05:16 +0800 Subject: [PATCH 192/254] bugfix: `setkeepalive` failure on TLSv1.3 When TLSv1.3 is used, the server may send a NewSessionTicket message after the handshake. While this message is ssl-layer data, `tcpsock:sslhandshake` does not consume it. In the implementation of `setkeepalive`, `recv` is used to confirm the connection is still open and there is no unread data in the buffer. But it treats the NewSessionTicket message as application layer data and then `setkeepalive` fails with this error `connection in dubious state`. In fact we don't need to peek here, because if the application data is read successfully then the connection is going to be closed anyway. Therefore, `c->recv` can be used instead which will consume the ssl-layer data implicitly. --- src/ngx_http_lua_socket_tcp.c | 19 +++------- t/058-tcp-socket.t | 66 +++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 15 deletions(-) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index a0e041b017..998881d1ca 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -5725,8 +5725,7 @@ ngx_http_lua_socket_keepalive_close_handler(ngx_event_t *ev) ngx_http_lua_socket_pool_t *spool; int n; - int err; - char buf[1]; + unsigned char buf[1]; ngx_connection_t *c; c = ev->data; @@ -5747,20 +5746,10 @@ ngx_http_lua_socket_keepalive_close_handler(ngx_event_t *ev) ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ev->log, 0, "lua tcp socket keepalive close handler check stale events"); - n = recv(c->fd, buf, 1, MSG_PEEK); - err = ngx_socket_errno; -#if (NGX_HTTP_SSL) - /* ignore ssl protocol data like change cipher spec */ - if (n == 1 && c->ssl != NULL) { - n = c->recv(c, (unsigned char *) buf, 1); - if (n == NGX_AGAIN) { - n = -1; - err = NGX_EAGAIN; - } - } -#endif + /* consume the possible ssl-layer data implicitly */ + n = c->recv(c, buf, 1); - if (n == -1 && err == NGX_EAGAIN) { + if (n == NGX_AGAIN) { /* stale event */ if (ngx_handle_read_event(c->read, 0) != NGX_OK) { diff --git a/t/058-tcp-socket.t b/t/058-tcp-socket.t index ef2b05f0d0..db5cb60e84 100644 --- a/t/058-tcp-socket.t +++ b/t/058-tcp-socket.t @@ -1,6 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use Test::Nginx::Socket::Lua; +use Test::Nginx::Socket::Lua::Stream; repeat_each(2); @@ -10,6 +11,7 @@ our $HtmlDir = html_dir; $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; $ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; +$ENV{TEST_NGINX_HTML_DIR} ||= html_dir(); #log_level 'warn'; log_level 'debug'; @@ -4497,3 +4499,67 @@ reused times: 3, setkeepalive err: closed --- no_error_log [error] --- skip_eval: 3: $ENV{TEST_NGINX_EVENT_TYPE} && $ENV{TEST_NGINX_EVENT_TYPE} ne 'epoll' + + + +=== TEST 74: setkeepalive with TLSv1.3 +--- skip_openssl: 3: < 1.1.1 +--- stream_server_config + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + ssl_certificate ../../cert/test.crt; + ssl_certificate_key ../../cert/test.key; + ssl_protocols TLSv1.3; + + content_by_lua_block { + local sock = assert(ngx.req.socket(true)) + local data + while true do + data = assert(sock:receive()) + assert(data == "hello") + end + } +--- config + location /test { + lua_ssl_protocols TLSv1.3; + content_by_lua_block { + local sock = ngx.socket.tcp() + sock:settimeout(2000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local ok, err = sock:sslhandshake(false, nil, false) + if not ok then + ngx.say("failed to sslhandshake: ", err) + return + end + + local ok, err = sock:send("hello\n") + if not ok then + ngx.say("failed to send: ", err) + return + end + + -- sleep a while to make sure the NewSessionTicket message has arrived + ngx.sleep(1) + + local ok, err = sock:setkeepalive() + if not ok then + ngx.say("failed to setkeepalive: ", err) + else + ngx.say("setkeepalive: ", ok) + end + } + } +--- request +GET /test +--- response_body +connected: 1 +setkeepalive: 1 +--- no_error_log +[error] From dfeaab4fdac09e1056873c920c42d70f99342777 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Sun, 15 Sep 2024 09:18:17 +0800 Subject: [PATCH 193/254] optimize: removed unreachable code in ngx_http_lua_send_http10_headers(). --- src/ngx_http_lua_util.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index f1e0cd08f5..5d871241db 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -764,10 +764,6 @@ ngx_http_lua_send_http10_headers(ngx_http_request_t *r, } r->headers_out.content_length_n = size; - - if (r->headers_out.content_length) { - r->headers_out.content_length->hash = 0; - } } send: From b190a9e3629b408d6c5da9e403041cc6200f54de Mon Sep 17 00:00:00 2001 From: lijunlong Date: Wed, 18 Sep 2024 18:01:06 +0800 Subject: [PATCH 194/254] tests: add support for openssl3.0. --- .travis.yml | 10 ++-- t/129-ssl-socket.t | 24 +++++----- t/140-ssl-c-api.t | 4 +- t/143-ssl-session-fetch.t | 99 ++------------------------------------- 4 files changed, 23 insertions(+), 114 deletions(-) diff --git a/.travis.yml b/.travis.yml index 177d6488ca..c37d3751c2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -63,9 +63,10 @@ env: jobs: #- NGINX_VERSION=1.21.4 OPENSSL_VER=1.1.0l OPENSSL_PATCH_VER=1.1.0d #- NGINX_VERSION=1.25.1 OPENSSL_VER=1.1.0l OPENSSL_PATCH_VER=1.1.0d - - NGINX_VERSION=1.21.4 OPENSSL_VER=1.1.1w OPENSSL_PATCH_VER=1.1.1f - - NGINX_VERSION=1.27.1 OPENSSL_VER=1.1.1w OPENSSL_PATCH_VER=1.1.1f USE_PCRE2=Y TEST_NGINX_TIMEOUT=5 - - NGINX_VERSION=1.27.1 BORINGSSL=1 TEST_NGINX_USE_HTTP3=1 USE_PCRE2=Y TEST_NGINX_QUIC_IDLE_TIMEOUT=3 + #- NGINX_VERSION=1.21.4 OPENSSL_VER=1.1.1w OPENSSL_PATCH_VER=1.1.1f + #- NGINX_VERSION=1.27.1 OPENSSL_VER=1.1.1w OPENSSL_PATCH_VER=1.1.1f USE_PCRE2=Y TEST_NGINX_TIMEOUT=5 + #- NGINX_VERSION=1.27.1 BORINGSSL=1 TEST_NGINX_USE_HTTP3=1 USE_PCRE2=Y TEST_NGINX_QUIC_IDLE_TIMEOUT=3 + - NGINX_VERSION=1.27.1 OPENSSL_VER=3.0.15 OPENSSL_PATCH_VER=3.0.12 USE_PCRE2=Y TEST_NGINX_TIMEOUT=5 #- NGINX_VERSION=1.25.1 OPENSSL_VER=1.1.1w TEST_NGINX_USE_HTTP2=1 services: @@ -82,8 +83,7 @@ install: - if [ ! -f download-cache/drizzle7-$DRIZZLE_VER.tar.gz ]; then wget -P download-cache https://github.com/openresty/openresty-deps-prebuild/releases/download/v20230902/drizzle7-$DRIZZLE_VER.tar.gz; fi - if [ "$USE_PCRE2" != "Y" ] && [ ! -f download-cache/pcre-$PCRE_VER.tar.gz ]; then wget -P download-cache https://downloads.sourceforge.net/project/pcre/pcre/${PCRE_VER}/pcre-${PCRE_VER}.tar.gz; fi - if [ "$USE_PCRE2" = "Y" ] && [ ! -f download-cache/pcre2-$PCRE2_VER.tar.gz ]; then wget -P download-cache https://github.com/PCRE2Project/pcre2/releases/download/pcre2-${PCRE2_VER}/pcre2-${PCRE2_VER}.tar.gz; fi - - if [ -n "$OPENSSL_VER" ] && [ ! -f download-cache/openssl-$OPENSSL_VER.tar.gz ]; then wget -P download-cache https://www.openssl.org/source/openssl-$OPENSSL_VER.tar.gz || wget -P download-cache https://www.openssl.org/source/old/${OPENSSL_VER//[a-z]/}/openssl-$OPENSSL_VER.tar.gz; fi - - if [ -n "$OPENSSL_VER" ] && [ ! -f download-cache/openssl-$OPENSSL_VER.tar.gz ]; then wget -P download-cache https://www.openssl.org/source/openssl-$OPENSSL_VER.tar.gz || wget -P download-cache https://www.openssl.org/source/old/${OPENSSL_VER//[a-z]/}/openssl-$OPENSSL_VER.tar.gz; fi + - if [ -n "$OPENSSL_VER" ] && [ ! -f download-cache/openssl-$OPENSSL_VER.tar.gz ]; then wget -P download-cache https://github.com/openssl/openssl/releases/download/openssl-$OPENSSL_VER/openssl-$OPENSSL_VER.tar.gz || wget -P download-cache https://www.openssl.org/source/openssl-$OPENSSL_VER.tar.gz || wget -P download-cache https://www.openssl.org/source/old/${OPENSSL_VER//[a-z]/}/openssl-$OPENSSL_VER.tar.gz; fi - wget https://github.com/openresty/openresty-deps-prebuild/releases/download/v20230902/boringssl-20230902-x64-focal.tar.gz - wget https://github.com/openresty/openresty-deps-prebuild/releases/download/v20230902/curl-h3-x64-focal.tar.gz - git clone https://github.com/openresty/test-nginx.git diff --git a/t/129-ssl-socket.t b/t/129-ssl-socket.t index ca8d5a49e6..611e72ab2f 100644 --- a/t/129-ssl-socket.t +++ b/t/129-ssl-socket.t @@ -1155,7 +1155,7 @@ SSL reused session server_name test.com; ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; - ssl_protocols TLSv1; + ssl_protocols TLSv1.2; location / { content_by_lua_block { @@ -1165,7 +1165,7 @@ SSL reused session } --- config server_tokens off; - lua_ssl_ciphers ECDHE-RSA-AES256-SHA; + lua_ssl_ciphers ECDHE-RSA-AES256-GCM-SHA384; location /t { content_by_lua ' @@ -1229,7 +1229,7 @@ lua ssl free session: ([0-9A-F]+) $/ --- error_log eval ['lua ssl server name: "test.com"', -qr/SSL: TLSv\d(?:\.\d)?, cipher: "ECDHE-RSA-AES256-SHA (SSLv3|TLSv1)/] +qr/SSL: TLSv\d(?:\.\d)?, cipher: "ECDHE-RSA-AES256-GCM-SHA384 (SSLv3|TLSv1\.2)/] --- no_error_log SSL reused session [error] @@ -1245,7 +1245,7 @@ SSL reused session server_name test.com; ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; - ssl_protocols TLSv1; + ssl_protocols TLSv1.2; location / { content_by_lua_block { @@ -1255,7 +1255,7 @@ SSL reused session } --- config server_tokens off; - lua_ssl_protocols TLSv1; + lua_ssl_protocols TLSv1.2; location /t { content_by_lua ' @@ -1319,7 +1319,7 @@ lua ssl free session: ([0-9A-F]+) $/ --- error_log eval ['lua ssl server name: "test.com"', -qr/SSL: TLSv1, cipher: "ECDHE-RSA-AES256-SHA (SSLv3|TLSv1)/] +qr/SSL: TLSv1\.2, cipher: "ECDHE-RSA-AES256-GCM-SHA384 TLSv1\.2/] --- no_error_log SSL reused session [error] @@ -2614,10 +2614,10 @@ SSL reused session --- request GET /t ---- response_body -connected: 1 -failed to do SSL handshake: 18: self signed certificate - +--- response_body eval +qr/connected: 1 +failed to do SSL handshake: 18: self[- ]signed certificate +/ms --- user_files eval ">>> test.key $::TestCertificateKey @@ -2626,8 +2626,8 @@ $::TestCertificate" --- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+/ --- grep_error_log_out ---- error_log -lua ssl certificate verify error: (18: self signed certificate) +--- error_log eval +qr/lua ssl certificate verify error: \(18: self[- ]signed certificate\)/ --- no_error_log SSL reused session [alert] diff --git a/t/140-ssl-c-api.t b/t/140-ssl-c-api.t index 4c81b4f05a..81d8375bb5 100644 --- a/t/140-ssl-c-api.t +++ b/t/140-ssl-c-api.t @@ -954,8 +954,8 @@ client certificate subject: emailAddress=agentzh@gmail.com,CN=test.com --- request GET /t ---- response_body -FAILED:self signed certificate +--- response_body eval +qr/FAILED:self[- ]signed certificate/ --- error_log client certificate subject: emailAddress=agentzh@gmail.com,CN=test.com diff --git a/t/143-ssl-session-fetch.t b/t/143-ssl-session-fetch.t index 2f988ded9c..b8ca095aa0 100644 --- a/t/143-ssl-session-fetch.t +++ b/t/143-ssl-session-fetch.t @@ -1326,98 +1326,7 @@ close: 1 nil -=== TEST 16: ssl_session_fetch_by_lua* always runs when using SSLv3 (SSLv3 does not support session tickets) ---- http_config - ssl_session_fetch_by_lua_block { print("ssl_session_fetch_by_lua* is running!") } - server { - listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; - server_name test.com; - ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; - ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; - ssl_protocols SSLv3; - server_tokens off; - } ---- config - server_tokens off; - lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; - lua_ssl_protocols SSLv3; - - location /t { - content_by_lua_block { - do - local sock = ngx.socket.tcp() - - sock:settimeout(5000) - - local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") - if not ok then - ngx.say("failed to connect: ", err) - return - end - - ngx.say("connected: ", ok) - - local sess, err = sock:sslhandshake(package.loaded.session, "test.com", true) - if not sess then - ngx.say("failed to do SSL handshake: ", err) - return - end - - ngx.say("ssl handshake: ", type(sess)) - - package.loaded.session = sess - - local ok, err = sock:close() - ngx.say("close: ", ok, " ", err) - end -- do - -- collectgarbage() - } - } ---- request -GET /t ---- response_body -connected: 1 -ssl handshake: cdata -close: 1 nil ---- grep_error_log eval: qr/ssl_session_fetch_by_lua\(nginx\.conf:\d+\):.*?,|\bssl session fetch: connection reusable: \d+|\breusable connection: \d+/ ---- grep_error_log_out eval -# Since nginx version 1.17.9, nginx call ngx_reusable_connection(c, 0) -# before call ssl callback function -$Test::Nginx::Util::NginxVersion >= 1.017009 ? -[ -qr/\A(?:reusable connection: [01]\n)+\z/s, -qr/^reusable connection: 0 -ssl session fetch: connection reusable: 0 -ssl_session_fetch_by_lua\(nginx\.conf:\d+\):1: ssl_session_fetch_by_lua\* is running!, -/m, -qr/^reusable connection: 0 -ssl session fetch: connection reusable: 0 -ssl_session_fetch_by_lua\(nginx\.conf:\d+\):1: ssl_session_fetch_by_lua\* is running!, -/m, -] -: -[ -qr/\A(?:reusable connection: [01]\n)+\z/s, -qr/^reusable connection: 1 -ssl session fetch: connection reusable: 1 -reusable connection: 0 -ssl_session_fetch_by_lua\(nginx\.conf:\d+\):1: ssl_session_fetch_by_lua\* is running!, -/m, -qr/^reusable connection: 1 -ssl session fetch: connection reusable: 1 -reusable connection: 0 -ssl_session_fetch_by_lua\(nginx\.conf:\d+\):1: ssl_session_fetch_by_lua\* is running!, -/m, -] ---- no_error_log -[error] -[alert] -[emerg] ---- skip_eval: 6:$ENV{TEST_NGINX_USE_HTTP3} - - - -=== TEST 17: ssl_session_fetch_by_lua* can yield when reading early data +=== TEST 16: ssl_session_fetch_by_lua* can yield when reading early data --- skip_openssl: 6: < 1.1.1 --- http_config ssl_session_fetch_by_lua_block { @@ -1494,7 +1403,7 @@ qr/elapsed in ssl_session_fetch_by_lua\*: 0\.(?:09|1[01])\d+,/, -=== TEST 18: cosocket (UDP) +=== TEST 17: cosocket (UDP) --- http_config ssl_session_fetch_by_lua_block { local sock = ngx.socket.udp() @@ -1589,7 +1498,7 @@ close: 1 nil -=== TEST 19: uthread (kill) +=== TEST 18: uthread (kill) --- http_config ssl_session_fetch_by_lua_block { local function f() @@ -1689,7 +1598,7 @@ uthread: failed to kill: already waited or killed -=== TEST 20: uthread (wait) +=== TEST 19: uthread (wait) --- http_config ssl_session_fetch_by_lua_block { local function f() From 24cafc638c3596f81cdba370371f024486ff0bee Mon Sep 17 00:00:00 2001 From: lijunlong Date: Thu, 19 Sep 2024 07:27:14 +0800 Subject: [PATCH 195/254] tests: fixed CI. --- .travis.yml | 29 ++++++++++++++++------------- util/build-without-ssl.sh | 4 ++-- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/.travis.yml b/.travis.yml index c37d3751c2..d73f3fbdc3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -42,8 +42,6 @@ env: - LUAJIT_LIB=$LUAJIT_PREFIX/lib - LUAJIT_INC=$LUAJIT_PREFIX/include/luajit-2.1 - LUA_INCLUDE_DIR=$LUAJIT_INC - - PCRE_VER=8.45 - - PCRE2_VER=10.42 - PCRE_PREFIX=/opt/pcre - PCRE2_PREFIX=/opt/pcre2 - PCRE_LIB=$PCRE_PREFIX/lib @@ -61,13 +59,12 @@ env: - TEST_NGINX_SLEEP=0.006 - MALLOC_PERTURB_=9 jobs: - #- NGINX_VERSION=1.21.4 OPENSSL_VER=1.1.0l OPENSSL_PATCH_VER=1.1.0d - #- NGINX_VERSION=1.25.1 OPENSSL_VER=1.1.0l OPENSSL_PATCH_VER=1.1.0d #- NGINX_VERSION=1.21.4 OPENSSL_VER=1.1.1w OPENSSL_PATCH_VER=1.1.1f - #- NGINX_VERSION=1.27.1 OPENSSL_VER=1.1.1w OPENSSL_PATCH_VER=1.1.1f USE_PCRE2=Y TEST_NGINX_TIMEOUT=5 - #- NGINX_VERSION=1.27.1 BORINGSSL=1 TEST_NGINX_USE_HTTP3=1 USE_PCRE2=Y TEST_NGINX_QUIC_IDLE_TIMEOUT=3 - - NGINX_VERSION=1.27.1 OPENSSL_VER=3.0.15 OPENSSL_PATCH_VER=3.0.12 USE_PCRE2=Y TEST_NGINX_TIMEOUT=5 #- NGINX_VERSION=1.25.1 OPENSSL_VER=1.1.1w TEST_NGINX_USE_HTTP2=1 + - NGINX_VERSION=1.27.1 OPENSSL_VER=1.1.1w OPENSSL_PATCH_VER=1.1.1f TEST_NGINX_TIMEOUT=5 PCRE_VER=8.45 + - NGINX_VERSION=1.27.1 OPENSSL_VER=3.0.15 OPENSSL_PATCH_VER=3.0.15 TEST_NGINX_TIMEOUT=5 PCRE2_VER=10.42 + - NGINX_VERSION=1.27.1 OPENSSL_VER=3.0.15 OPENSSL_PATCH_VER=3.0.15 TEST_NGINX_USE_HTTP3=1 TEST_NGINX_QUIC_IDLE_TIMEOUT=3 PCRE2_VER=10.42 + - NGINX_VERSION=1.27.1 BORINGSSL=1 TEST_NGINX_USE_HTTP3=1 TEST_NGINX_QUIC_IDLE_TIMEOUT=3 PCRE2_VER=10.42 services: - memcached @@ -81,9 +78,12 @@ before_install: install: - if [ ! -f download-cache/drizzle7-$DRIZZLE_VER.tar.gz ]; then wget -P download-cache https://github.com/openresty/openresty-deps-prebuild/releases/download/v20230902/drizzle7-$DRIZZLE_VER.tar.gz; fi - - if [ "$USE_PCRE2" != "Y" ] && [ ! -f download-cache/pcre-$PCRE_VER.tar.gz ]; then wget -P download-cache https://downloads.sourceforge.net/project/pcre/pcre/${PCRE_VER}/pcre-${PCRE_VER}.tar.gz; fi - - if [ "$USE_PCRE2" = "Y" ] && [ ! -f download-cache/pcre2-$PCRE2_VER.tar.gz ]; then wget -P download-cache https://github.com/PCRE2Project/pcre2/releases/download/pcre2-${PCRE2_VER}/pcre2-${PCRE2_VER}.tar.gz; fi - - if [ -n "$OPENSSL_VER" ] && [ ! -f download-cache/openssl-$OPENSSL_VER.tar.gz ]; then wget -P download-cache https://github.com/openssl/openssl/releases/download/openssl-$OPENSSL_VER/openssl-$OPENSSL_VER.tar.gz || wget -P download-cache https://www.openssl.org/source/openssl-$OPENSSL_VER.tar.gz || wget -P download-cache https://www.openssl.org/source/old/${OPENSSL_VER//[a-z]/}/openssl-$OPENSSL_VER.tar.gz; fi + #- if [ -n "$PCRE_VER" ] && [ ! -f download-cache/pcre-$PCRE_VER.tar.gz ]; then wget -P download-cache https://downloads.sourceforge.net/project/pcre/pcre/${PCRE_VER}/pcre-${PCRE_VER}.tar.gz; fi + #- if [ -n "$PCRE2_VER" ] && [ ! -f download-cache/pcre2-$PCRE2_VER.tar.gz ]; then wget -P download-cache https://github.com/PCRE2Project/pcre2/releases/download/pcre2-${PCRE2_VER}/pcre2-${PCRE2_VER}.tar.gz; fi + #- if [ -n "$OPENSSL_VER" ] && [ ! -f download-cache/openssl-$OPENSSL_VER.tar.gz ]; then wget -P download-cache https://github.com/openssl/openssl/releases/download/openssl-$OPENSSL_VER/openssl-$OPENSSL_VER.tar.gz || wget -P download-cache https://www.openssl.org/source/openssl-$OPENSSL_VER.tar.gz || wget -P download-cache https://www.openssl.org/source/old/${OPENSSL_VER//[a-z]/}/openssl-$OPENSSL_VER.tar.gz; fi + - if [ -n "$OPENSSL_VER" ]; then wget https://github.com/openresty/openresty-deps-prebuild/releases/download/v1.0.0/openssl-${OPENSSL_VER}-x64-focal.tar.gz; fi + - if [ -n "$PCRE_VER" ]; then wget https://github.com/openresty/openresty-deps-prebuild/releases/download/v1.0.0/pcre-${PCRE_VER}-x64-focal.tar.gz; fi + - if [ -n "$PCRE2_VER" ]; then wget https://github.com/openresty/openresty-deps-prebuild/releases/download/v1.0.0/pcre2-${PCRE2_VER}-x64-focal.tar.gz; fi - wget https://github.com/openresty/openresty-deps-prebuild/releases/download/v20230902/boringssl-20230902-x64-focal.tar.gz - wget https://github.com/openresty/openresty-deps-prebuild/releases/download/v20230902/curl-h3-x64-focal.tar.gz - git clone https://github.com/openresty/test-nginx.git @@ -135,10 +135,13 @@ script: - sudo make install-libdrizzle-1.0 > build.log 2>&1 || (cat build.log && exit 1) - cd ../mockeagain/ && make CC=$CC -j$JOBS && cd .. - cd lua-cjson/ && make -j$JOBS && sudo make install && cd .. - - if [ "$USE_PCRE2" != "Y" ]; then tar zxf download-cache/pcre-$PCRE_VER.tar.gz; cd pcre-$PCRE_VER/; ./configure --prefix=$PCRE_PREFIX --enable-jit --enable-utf --enable-unicode-properties > build.log 2>&1 || (cat build.log && exit 1); make -j$JOBS > build.log 2>&1 || (cat build.log && exit 1); sudo PATH=$PATH make install > build.log 2>&1 || (cat build.log && exit 1); cd ..; fi - - if [ "$USE_PCRE2" = "Y" ]; then tar zxf download-cache/pcre2-$PCRE2_VER.tar.gz; cd pcre2-$PCRE2_VER/; ./configure --prefix=$PCRE2_PREFIX --enable-jit --enable-utf > build.log 2>&1 || (cat build.log && exit 1); make -j$JOBS > build.log 2>&1 || (cat build.log && exit 1); sudo PATH=$PATH make install > build.log 2>&1 || (cat build.log && exit 1); cd ..; fi - - if [ -n "$OPENSSL_VER" ]; then tar zxf download-cache/openssl-$OPENSSL_VER.tar.gz; cd openssl-$OPENSSL_VER/; patch -p1 < ../../openresty/patches/openssl-$OPENSSL_PATCH_VER-sess_set_get_cb_yield.patch; ./config shared enable-ssl3 enable-ssl3-method -g --prefix=$OPENSSL_PREFIX -DPURIFY > build.log 2>&1 || (cat build.log && exit 1); make -j$JOBS > build.log 2>&1 || (cat build.log && exit 1); sudo make PATH=$PATH install_sw > build.log 2>&1 || (cat build.log && exit 1); cd ..; fi + #- if [ -n "PCRE_VER" ]; then tar zxf download-cache/pcre-$PCRE_VER.tar.gz; cd pcre-$PCRE_VER/; ./configure --prefix=$PCRE_PREFIX --enable-jit --enable-utf --enable-unicode-properties > build.log 2>&1 || (cat build.log && exit 1); make -j$JOBS > build.log 2>&1 || (cat build.log && exit 1); sudo PATH=$PATH make install > build.log 2>&1 || (cat build.log && exit 1); cd ..; fi + #- if [ -n "$PCRE2_VER" ]; then tar zxf download-cache/pcre2-$PCRE2_VER.tar.gz; cd pcre2-$PCRE2_VER/; ./configure --prefix=$PCRE2_PREFIX --enable-jit --enable-utf > build.log 2>&1 || (cat build.log && exit 1); make -j$JOBS > build.log 2>&1 || (cat build.log && exit 1); sudo PATH=$PATH make install > build.log 2>&1 || (cat build.log && exit 1); cd ..; fi + #- if [ -n "$OPENSSL_VER" ]; then tar zxf download-cache/openssl-$OPENSSL_VER.tar.gz; cd openssl-$OPENSSL_VER/; patch -p1 < ../../openresty/patches/openssl-$OPENSSL_PATCH_VER-sess_set_get_cb_yield.patch; ./config shared enable-ssl3 enable-ssl3-method -g --prefix=$OPENSSL_PREFIX --libdir=lib -DPURIFY > build.log 2>&1 || (cat build.log && exit 1); make -j$JOBS > build.log 2>&1 || (cat build.log && exit 1); sudo make PATH=$PATH install_sw > build.log 2>&1 || (cat build.log && exit 1); cd ..; fi - if [ -n "$BORINGSSL" ]; then sudo mkdir -p /opt/ssl && sudo tar -C /opt/ssl -xf boringssl-20230902-x64-focal.tar.gz --strip-components=1; fi + - if [ -n "$OPENSSL_VER" ]; then sudo mkdir -p /opt/ssl && sudo tar -C /opt/ssl -xf openssl-$OPENSSL_VER-x64-focal.tar.gz --strip-components=2; fi + - if [ -n "$PCRE_VER" ]; then sudo mkdir -p $PCRE_PREFIX && sudo tar -C $PCRE_PREFIX -xf pcre-$PCRE_VER-x64-focal.tar.gz --strip-components=2; fi + - if [ -n "$PCRE2_VER" ]; then sudo mkdir -p $PCRE2_PREFIX && sudo tar -C $PCRE2_PREFIX -xf pcre2-$PCRE2_VER-x64-focal.tar.gz --strip-components=2; fi - export NGX_BUILD_CC=$CC - sh util/build-without-ssl.sh $NGINX_VERSION > build.log 2>&1 || (cat build.log && exit 1) - sh util/build-with-dd.sh $NGINX_VERSION > build.log 2>&1 || (cat build.log && exit 1) diff --git a/util/build-without-ssl.sh b/util/build-without-ssl.sh index c52d5873f6..2a998e3c79 100755 --- a/util/build-without-ssl.sh +++ b/util/build-without-ssl.sh @@ -26,10 +26,10 @@ add_fake_shm_module="--add-module=$root/t/data/fake-shm-module" disable_pcre2=--without-pcre2 answer=`$root/util/ver-ge "$NGINX_VERSION" 1.25.1` -if [ "$answer" = "N" ] || [ "$USE_PCRE2" = "Y" ]; then +if [ "$answer" = "N" ] || [ -n "$PCRE2_VER" ]; then disable_pcre2="" fi -if [ "$USE_PCRE2" = "Y" ]; then +if [ -n "$PCRE2_VER" ]; then PCRE_INC=$PCRE2_INC PCRE_LIB=$PCRE2_LIB fi From 34167407fa2c912c8d3f701503a54443f7439e06 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Thu, 19 Sep 2024 09:36:56 +0800 Subject: [PATCH 196/254] feature: add ngx.resp.set_status(status, reason). --- src/ngx_http_lua_misc.c | 32 +++++++++++++++++++++++- t/015-status.t | 54 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 84 insertions(+), 2 deletions(-) diff --git a/src/ngx_http_lua_misc.c b/src/ngx_http_lua_misc.c index 4e93f68f1e..2fed53f7ad 100644 --- a/src/ngx_http_lua_misc.c +++ b/src/ngx_http_lua_misc.c @@ -64,8 +64,11 @@ ngx_http_lua_ffi_get_resp_status(ngx_http_request_t *r) int -ngx_http_lua_ffi_set_resp_status(ngx_http_request_t *r, int status) +ngx_http_lua_ffi_set_resp_status_and_reason(ngx_http_request_t *r, int status, + const char *reason, size_t reason_len) { + u_char *buf; + if (r->connection->fd == (ngx_socket_t) -1) { return NGX_HTTP_LUA_FFI_BAD_CONTEXT; } @@ -77,6 +80,14 @@ ngx_http_lua_ffi_set_resp_status(ngx_http_request_t *r, int status) return NGX_DECLINED; } + /* per RFC-7230 sec 3.1.2, the status line must be 3 digits, it also makes + * buffer size calculation easier */ + if (status < 100 || status > 999) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "invalid HTTP status code %d", status); + return NGX_DECLINED; + } + r->headers_out.status = status; if (r->err_status) { @@ -91,6 +102,18 @@ ngx_http_lua_ffi_set_resp_status(ngx_http_request_t *r, int status) ngx_str_set(&r->headers_out.status_line, "101 Switching Protocols"); + } else if (reason != NULL && reason_len > 0) { + reason_len += 5; /* "ddd \0" */ + buf = ngx_palloc(r->pool, reason_len); + if (buf == NULL) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "no memory"); + return NGX_DECLINED; + } + + ngx_snprintf(buf, reason_len, "%d %s", status, reason); + r->headers_out.status_line.len = reason_len; + r->headers_out.status_line.data = buf; + } else { r->headers_out.status_line.len = 0; } @@ -99,6 +122,13 @@ ngx_http_lua_ffi_set_resp_status(ngx_http_request_t *r, int status) } +int +ngx_http_lua_ffi_set_resp_status(ngx_http_request_t *r, int status) +{ + return ngx_http_lua_ffi_set_resp_status_and_reason(r, status, NULL, 0); +} + + int ngx_http_lua_ffi_req_is_internal(ngx_http_request_t *r) { diff --git a/t/015-status.t b/t/015-status.t index aa816c08d6..c768aebcea 100644 --- a/t/015-status.t +++ b/t/015-status.t @@ -9,7 +9,7 @@ log_level('warn'); #repeat_each(120); repeat_each(2); -plan tests => repeat_each() * (blocks() * 2 + 9); +plan tests => repeat_each() * (blocks() * 2 + 10); #no_diff(); #no_long_string(); @@ -293,3 +293,55 @@ ngx.status: 654 --- no_error_log [error] --- error_code: 654 + + + +=== TEST 17: set status and reason +--- config +location = /upstream { + content_by_lua_block { + local resp = require "ngx.resp" + resp.set_status(500, "user defined reason") + ngx.say("set_status_and_reason") + } +} + +location /t { + content_by_lua_block { + local sock = ngx.socket.tcp() + local port = ngx.var.server_port + local ok, err = sock:connect("127.0.0.1", port) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + local req = "GET /upstream HTTP/1.0\r\nHost: localhost\r\nConnection: close\r\n\r\n" + + local bytes, err = sock:send(req) + if not bytes then + ngx.say("failed to send request: ", err) + return + end + + local found = false + while true do + local line, err, part = sock:receive() + if line then + if ngx.re.find(line, "HTTP/1.1 500 user defined reason") then + ngx.say("match") + end + else + break + end + end + + sock:close() + } +} +--- request +GET /t +--- response_body +match +--- no_error_log +[error] From de1b896999c95bcbfc2b60c4a2247092d9c7fe40 Mon Sep 17 00:00:00 2001 From: spacewander Date: Tue, 7 Feb 2017 21:04:18 +0800 Subject: [PATCH 197/254] style: remove duplicate check in ngx.send_headers --- src/ngx_http_lua_output.c | 16 +++++++--------- src/ngx_http_lua_util.c | 9 +++------ 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/src/ngx_http_lua_output.c b/src/ngx_http_lua_output.c index b2a98d133a..2648e4e952 100644 --- a/src/ngx_http_lua_output.c +++ b/src/ngx_http_lua_output.c @@ -722,16 +722,14 @@ ngx_http_lua_ngx_send_headers(lua_State *L) | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT); - if (!r->header_sent && !ctx->header_sent) { - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua send headers"); + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua send headers"); - rc = ngx_http_lua_send_header_if_needed(r, ctx); - if (rc == NGX_ERROR || rc > NGX_OK) { - lua_pushnil(L); - lua_pushliteral(L, "nginx output filter error"); - return 2; - } + rc = ngx_http_lua_send_header_if_needed(r, ctx); + if (rc == NGX_ERROR || rc > NGX_OK) { + lua_pushnil(L); + lua_pushliteral(L, "nginx output filter error"); + return 2; } lua_pushinteger(L, 1); diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 5d871241db..4e6204c79d 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -535,13 +535,10 @@ ngx_http_lua_send_header_if_needed(ngx_http_request_t *r, r->headers_out.status = NGX_HTTP_OK; } - if (!ctx->mime_set - && ngx_http_lua_set_content_type(r, ctx) != NGX_OK) - { - return NGX_ERROR; - } - if (!ctx->headers_set) { + if (ngx_http_lua_set_content_type(r) != NGX_OK) { + return NGX_ERROR; + } ngx_http_clear_content_length(r); ngx_http_clear_accept_ranges(r); } From 408819422433ece1904e4851e2c859dcd4cbb823 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Thu, 19 Sep 2024 10:57:28 +0800 Subject: [PATCH 198/254] style: fixed coding style. --- src/ngx_http_lua_output.c | 2 +- src/ngx_http_lua_util.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ngx_http_lua_output.c b/src/ngx_http_lua_output.c index 2648e4e952..8681947263 100644 --- a/src/ngx_http_lua_output.c +++ b/src/ngx_http_lua_output.c @@ -723,7 +723,7 @@ ngx_http_lua_ngx_send_headers(lua_State *L) | NGX_HTTP_LUA_CONTEXT_CONTENT); ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua send headers"); + "lua send headers"); rc = ngx_http_lua_send_header_if_needed(r, ctx); if (rc == NGX_ERROR || rc > NGX_OK) { diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 4e6204c79d..4e9a8946ef 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -539,6 +539,7 @@ ngx_http_lua_send_header_if_needed(ngx_http_request_t *r, if (ngx_http_lua_set_content_type(r) != NGX_OK) { return NGX_ERROR; } + ngx_http_clear_content_length(r); ngx_http_clear_accept_ranges(r); } From a634f1028af51ee3c70e94ba8f5176d7f781b3dd Mon Sep 17 00:00:00 2001 From: lijunlong Date: Sat, 21 Sep 2024 15:25:36 +0800 Subject: [PATCH 199/254] bugfix: build failure introduced by commit de1b896999c95. --- src/ngx_http_lua_util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 4e9a8946ef..4386bc67d6 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -536,7 +536,7 @@ ngx_http_lua_send_header_if_needed(ngx_http_request_t *r, } if (!ctx->headers_set) { - if (ngx_http_lua_set_content_type(r) != NGX_OK) { + if (ngx_http_lua_set_content_type(r, ctx) != NGX_OK) { return NGX_ERROR; } From a7eebb4793668eaab015647749469f25a3d37038 Mon Sep 17 00:00:00 2001 From: WenMing Date: Thu, 26 Jul 2018 20:02:22 +0800 Subject: [PATCH 200/254] feature: implemented ngx_http_lua_ffi_decode_base64mime. --- README.markdown | 20 +++++++++- doc/HttpLuaModule.wiki | 16 +++++++- src/ngx_http_lua_string.c | 20 ++++++++++ src/ngx_http_lua_util.c | 80 +++++++++++++++++++++++++++++++++++++++ src/ngx_http_lua_util.h | 1 + 5 files changed, 135 insertions(+), 2 deletions(-) diff --git a/README.markdown b/README.markdown index 25d1383f36..2b2d2b251d 100644 --- a/README.markdown +++ b/README.markdown @@ -3695,6 +3695,7 @@ Nginx API for Lua * [ngx.decode_args](#ngxdecode_args) * [ngx.encode_base64](#ngxencode_base64) * [ngx.decode_base64](#ngxdecode_base64) +* [ngx.decode_base64mime](#ngxdecode_base64mime) * [ngx.crc32_short](#ngxcrc32_short) * [ngx.crc32_long](#ngxcrc32_long) * [ngx.hmac_sha1](#ngxhmac_sha1) @@ -6267,7 +6268,24 @@ ngx.decode_base64 **context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, ssl_client_hello_by_lua** -Decodes the `str` argument as a base64 digest to the raw form. Returns `nil` if `str` is not well formed. +Decodes the `str` argument as a base64 digest to the raw form. +The `str` should be standard 'base64' encoding for RFC 3548 or RFC 4648, and will returns `nil` if is not well formed or any characters not in the base encoding alphabet. + +[Back to TOC](#nginx-api-for-lua) + +ngx.decode_base64mime +--------------------- +**syntax:** *newstr = ngx.decode_base64mime(str)* + +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** + +**requires:** `resty.core.base64` or `resty.core` + +Decodes the `str` argument as a base64 digest to the raw form. +The `str` follows base64 transfer encoding for MIME (RFC 2045), and will discard characters outside the base encoding alphabet. +Returns `nil` if `str` is not well formed. + + '''Note:''' This method requires the resty.core.base64 or resty.core modules from the [lua-resty-core](https://github.com/openresty/lua-resty-core) library. [Back to TOC](#nginx-api-for-lua) diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index a0e6d28fac..733f11dc66 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -5256,7 +5256,21 @@ Since the 0.9.16 release, an optional boolean-typed no_paddin '''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, ssl_client_hello_by_lua*'' -Decodes the str argument as a base64 digest to the raw form. Returns nil if str is not well formed. +Decodes the str argument as a base64 digest to the raw form. +The str should be standard 'base64' encoding for RFC 3548 or RFC 4648, and will returns nil if is not well formed or any characters not in the base encoding alphabet. + +== ngx.decode_base64mime == +'''syntax:''' ''newstr = ngx.decode_base64mime(str)'' + +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' + +'''requires:''' resty.core.base64 or resty.core + +Decodes the str argument as a base64 digest to the raw form. +The str follows base64 transfer encoding for MIME (RFC 2045), and will discard characters outside the base encoding alphabet. +Returns nil if str is not well formed. + + '''Note:''' This method requires the resty.core.base64 or resty.core modules from the [https://github.com/openresty/lua-resty-core lua-resty-core] library. == ngx.crc32_short == diff --git a/src/ngx_http_lua_string.c b/src/ngx_http_lua_string.c index 4c755f67f3..3028483609 100644 --- a/src/ngx_http_lua_string.c +++ b/src/ngx_http_lua_string.c @@ -424,6 +424,26 @@ ngx_http_lua_ffi_decode_base64(const u_char *src, size_t slen, u_char *dst, } +int +ngx_http_lua_ffi_decode_base64mime(const u_char *src, size_t slen, u_char *dst, + size_t *dlen) +{ + ngx_int_t rc; + ngx_str_t in, out; + + in.data = (u_char *) src; + in.len = slen; + + out.data = dst; + + rc = ngx_http_lua_decode_base64mime(&out, &in); + + *dlen = out.len; + + return rc == NGX_OK; +} + + size_t ngx_http_lua_ffi_unescape_uri(const u_char *src, size_t len, u_char *dst) { diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 4386bc67d6..e3d46db788 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -4401,6 +4401,86 @@ ngx_http_lua_copy_escaped_header(ngx_http_request_t *r, } +ngx_int_t +ngx_http_lua_decode_base64mime(ngx_str_t *dst, ngx_str_t *src) +{ + size_t i; + u_char *d, *s, ch; + size_t data_len = 0; + u_char buf[4]; + size_t buf_len = 0; + static u_char basis[] = { + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 62, 77, 77, 77, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 77, 77, 77, 77, 77, 77, + 77, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 77, 77, 77, 77, 77, + 77, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 77, 77, 77, 77, 77, + + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77 + }; + + for (i = 0; i < src->len; i++) { + ch = src->data[i]; + if (ch == '=') { + break; + } + + if (basis[ch] == 77) { + continue; + } + + data_len++; + } + + if (data_len % 4 == 1) { + return NGX_ERROR; + } + + s = src->data; + d = dst->data; + + for (i = 0; i < src->len; i++) { + if (s[i] == '=') { + break; + } + + if (basis[s[i]] == 77) { + continue; + } + + buf[buf_len++] = s[i]; + if (buf_len == 4) { + *d++ = (u_char) (basis[buf[0]] << 2 | basis[buf[1]] >> 4); + *d++ = (u_char) (basis[buf[1]] << 4 | basis[buf[2]] >> 2); + *d++ = (u_char) (basis[buf[2]] << 6 | basis[buf[3]]); + buf_len = 0; + } + } + + if (buf_len > 1) { + *d++ = (u_char) (basis[buf[0]] << 2 | basis[buf[1]] >> 4); + } + + if (buf_len > 2) { + *d++ = (u_char) (basis[buf[1]] << 4 | basis[buf[2]] >> 2); + } + + dst->len = d - dst->data; + + return NGX_OK; +} + + ngx_addr_t * ngx_http_lua_parse_addr(lua_State *L, u_char *text, size_t len) { diff --git a/src/ngx_http_lua_util.h b/src/ngx_http_lua_util.h index faea7a072c..85c6e614d6 100644 --- a/src/ngx_http_lua_util.h +++ b/src/ngx_http_lua_util.h @@ -261,6 +261,7 @@ void ngx_http_lua_cleanup_free(ngx_http_request_t *r, #if (NGX_HTTP_LUA_HAVE_SA_RESTART) void ngx_http_lua_set_sa_restart(ngx_log_t *log); #endif +ngx_int_t ngx_http_lua_decode_base64mime(ngx_str_t *dst, ngx_str_t *src); ngx_addr_t *ngx_http_lua_parse_addr(lua_State *L, u_char *text, size_t len); From 0d9f578070388f58d8e74f10897a2e05fd919e1a Mon Sep 17 00:00:00 2001 From: lijunlong Date: Sat, 21 Sep 2024 17:24:51 +0800 Subject: [PATCH 201/254] tests: fixed t/062-count.t --- t/062-count.t | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/t/062-count.t b/t/062-count.t index 957590292b..d0eabb1f2d 100644 --- a/t/062-count.t +++ b/t/062-count.t @@ -34,7 +34,7 @@ __DATA__ --- request GET /test --- response_body -ngx: 116 +ngx: 117 --- no_error_log [error] @@ -55,7 +55,7 @@ ngx: 116 --- request GET /test --- response_body -116 +117 --- no_error_log [error] @@ -83,7 +83,7 @@ GET /test --- request GET /test --- response_body -n = 116 +n = 117 --- no_error_log [error] @@ -306,7 +306,7 @@ GET /t --- response_body_like: 404 Not Found --- error_code: 404 --- error_log -ngx. entry count: 116 +ngx. entry count: 117 From 2e1718e15d8450c8c5ef6bb2a4a29d9332a7ca9a Mon Sep 17 00:00:00 2001 From: lijunlong Date: Sat, 21 Sep 2024 17:33:03 +0800 Subject: [PATCH 202/254] bugfix: missing the content-type header introduced by commit de1b896999c9. --- src/ngx_http_lua_util.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index e3d46db788..c73bddc609 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -535,11 +535,13 @@ ngx_http_lua_send_header_if_needed(ngx_http_request_t *r, r->headers_out.status = NGX_HTTP_OK; } - if (!ctx->headers_set) { - if (ngx_http_lua_set_content_type(r, ctx) != NGX_OK) { - return NGX_ERROR; - } + if (!ctx->mime_set + && ngx_http_lua_set_content_type(r, ctx) != NGX_OK) + { + return NGX_ERROR; + } + if (!ctx->headers_set) { ngx_http_clear_content_length(r); ngx_http_clear_accept_ranges(r); } From e1ff117183c25a20a35c59c536a882820296a5cf Mon Sep 17 00:00:00 2001 From: n-bes Date: Wed, 25 Sep 2024 03:29:15 +0300 Subject: [PATCH 203/254] fix: removed null terminator. --- src/ngx_http_lua_misc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ngx_http_lua_misc.c b/src/ngx_http_lua_misc.c index 2fed53f7ad..8b74167161 100644 --- a/src/ngx_http_lua_misc.c +++ b/src/ngx_http_lua_misc.c @@ -103,7 +103,7 @@ ngx_http_lua_ffi_set_resp_status_and_reason(ngx_http_request_t *r, int status, ngx_str_set(&r->headers_out.status_line, "101 Switching Protocols"); } else if (reason != NULL && reason_len > 0) { - reason_len += 5; /* "ddd \0" */ + reason_len += 4; /* "ddd " */ buf = ngx_palloc(r->pool, reason_len); if (buf == NULL) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "no memory"); From e6219b05283ed26c7ee1d58777bf252cc614819d Mon Sep 17 00:00:00 2001 From: Thijs Schreijer Date: Thu, 3 Oct 2024 13:53:25 +0200 Subject: [PATCH 204/254] doc: clarify the backlog option (#2367) --- README.markdown | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.markdown b/README.markdown index 2b2d2b251d..d85a1f0753 100644 --- a/README.markdown +++ b/README.markdown @@ -7989,14 +7989,14 @@ An optional Lua table can be specified as the last argument to this method to sp * `backlog` if specified, this module will limit the total number of opened connections for this pool. No more connections than `pool_size` can be opened - for this pool at any time. If the connection pool is full, subsequent - connect operations will be queued into a queue equal to this option's - value (the "backlog" queue). + for this pool at any time. If `pool_size` number of connections are in use, + subsequent connect operations will be queued into a queue equal to this + option's value (the "backlog" queue). If the number of queued connect operations is equal to `backlog`, subsequent connect operations will fail and return `nil` plus the error string `"too many waiting connect operations"`. - The queued connect operations will be resumed once the number of connections - in the pool is less than `pool_size`. + The queued connect operations will be resumed once the number of active + connections becomes less than `pool_size`. The queued connect operation will abort once they have been queued for more than `connect_timeout`, controlled by [settimeouts](#tcpsocksettimeouts), and will return `nil` plus From 9a871ddad3f7919740c4d026d0f6c21e7f7a1a0f Mon Sep 17 00:00:00 2001 From: Thijs Schreijer Date: Tue, 15 Oct 2024 13:03:50 +0200 Subject: [PATCH 205/254] doc: clarify base64 for url encoding and padding. --- README.markdown | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.markdown b/README.markdown index d85a1f0753..35c0b83e58 100644 --- a/README.markdown +++ b/README.markdown @@ -6255,7 +6255,7 @@ ngx.encode_base64 **context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, ssl_client_hello_by_lua** -Encodes `str` to a base64 digest. +Encodes `str` to a base64 digest. For base64url encoding use [`base64.encode_base64url`](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/base64.md#encode_base64url). Since the `0.9.16` release, an optional boolean-typed `no_padding` argument can be specified to control whether the base64 padding should be appended to the resulting digest (default to `false`, i.e., with padding enabled). @@ -6268,8 +6268,9 @@ ngx.decode_base64 **context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, ssl_client_hello_by_lua** -Decodes the `str` argument as a base64 digest to the raw form. -The `str` should be standard 'base64' encoding for RFC 3548 or RFC 4648, and will returns `nil` if is not well formed or any characters not in the base encoding alphabet. +Decodes the `str` argument as a base64 digest to the raw form. For base64url decoding use [`base64.decode_base64url`](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/base64.md#decode_base64url). + +The `str` should be standard 'base64' encoding for RFC 3548 or RFC 4648, and will returns `nil` if is not well formed or any characters not in the base encoding alphabet. Padding may be omitted from the input. [Back to TOC](#nginx-api-for-lua) From 501ebacd731a3a27bf76c2514b3e45cdca380605 Mon Sep 17 00:00:00 2001 From: willmafh Date: Sun, 27 Oct 2024 08:51:17 +0800 Subject: [PATCH 206/254] chore: more accurate error message. --- src/ngx_http_lua_ssl_certby.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ngx_http_lua_ssl_certby.c b/src/ngx_http_lua_ssl_certby.c index 0901f06eab..72a651bdbf 100644 --- a/src/ngx_http_lua_ssl_certby.c +++ b/src/ngx_http_lua_ssl_certby.c @@ -1433,7 +1433,7 @@ ngx_http_lua_ffi_set_priv_key(ngx_http_request_t *r, pkey = cdata; if (pkey == NULL) { - *err = "invalid private key failed"; + *err = "invalid private key"; goto failed; } From 950b1fb2010c8847a1e0bc7f079741ec47a08f17 Mon Sep 17 00:00:00 2001 From: Jun Ouyang Date: Wed, 6 Nov 2024 10:12:11 +0800 Subject: [PATCH 207/254] bugfix: remove http2 hardcode limitation in `ngx.location` subrequest API. --- .travis.yml | 2 ++ src/ngx_http_lua_subrequest.c | 6 ----- t/005-exit.t | 5 ++++ t/014-bugs.t | 2 +- t/016-resp-header.t | 1 + t/020-subrequest.t | 1 + t/023-rewrite/exit.t | 3 +++ t/024-access/exit.t | 3 +++ t/026-mysql.t | 1 + t/033-ctx.t | 2 +- t/041-header-filter.t | 46 ++++++++++++++++++----------------- t/056-flush.t | 3 +-- t/068-socket-keepalive.t | 3 +++ t/091-coroutine.t | 5 ++-- t/094-uthread-exit.t | 8 +++--- t/095-uthread-exec.t | 1 + t/096-uthread-redirect.t | 1 + t/138-balancer.t | 22 ++--------------- t/143-ssl-session-fetch.t | 3 +-- t/163-signal.t | 2 +- 20 files changed, 60 insertions(+), 60 deletions(-) diff --git a/.travis.yml b/.travis.yml index d73f3fbdc3..4eb8d3e5ce 100644 --- a/.travis.yml +++ b/.travis.yml @@ -63,6 +63,8 @@ env: #- NGINX_VERSION=1.25.1 OPENSSL_VER=1.1.1w TEST_NGINX_USE_HTTP2=1 - NGINX_VERSION=1.27.1 OPENSSL_VER=1.1.1w OPENSSL_PATCH_VER=1.1.1f TEST_NGINX_TIMEOUT=5 PCRE_VER=8.45 - NGINX_VERSION=1.27.1 OPENSSL_VER=3.0.15 OPENSSL_PATCH_VER=3.0.15 TEST_NGINX_TIMEOUT=5 PCRE2_VER=10.42 + - NGINX_VERSION=1.27.1 OPENSSL_VER=1.1.1w OPENSSL_PATCH_VER=1.1.1f TEST_NGINX_TIMEOUT=5 PCRE_VER=8.45 TEST_NGINX_USE_HTTP2=1 + - NGINX_VERSION=1.27.1 OPENSSL_VER=3.0.15 OPENSSL_PATCH_VER=3.0.15 TEST_NGINX_TIMEOUT=5 PCRE2_VER=10.42 TEST_NGINX_USE_HTTP2=1 - NGINX_VERSION=1.27.1 OPENSSL_VER=3.0.15 OPENSSL_PATCH_VER=3.0.15 TEST_NGINX_USE_HTTP3=1 TEST_NGINX_QUIC_IDLE_TIMEOUT=3 PCRE2_VER=10.42 - NGINX_VERSION=1.27.1 BORINGSSL=1 TEST_NGINX_USE_HTTP3=1 TEST_NGINX_QUIC_IDLE_TIMEOUT=3 PCRE2_VER=10.42 diff --git a/src/ngx_http_lua_subrequest.c b/src/ngx_http_lua_subrequest.c index 2ccd271a90..edb24e9c0d 100644 --- a/src/ngx_http_lua_subrequest.c +++ b/src/ngx_http_lua_subrequest.c @@ -173,12 +173,6 @@ ngx_http_lua_ngx_location_capture_multi(lua_State *L) return luaL_error(L, "no request object found"); } -#if (NGX_HTTP_V2) - if (r->main->stream) { - return luaL_error(L, "http2 requests not supported yet"); - } -#endif - ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { return luaL_error(L, "no ctx found"); diff --git a/t/005-exit.t b/t/005-exit.t index 0783c69295..bbaeda517e 100644 --- a/t/005-exit.t +++ b/t/005-exit.t @@ -124,6 +124,7 @@ GET /api?user=agentz === TEST 6: working with ngx_auth_request (simplest form, w/o ngx_memc) --- skip_eval: 3:$ENV{TEST_NGINX_USE_HTTP3} +--- no_http2 --- http_config eval " lua_package_cpath '$::LuaCpath'; @@ -197,6 +198,7 @@ Logged in 56 === TEST 7: working with ngx_auth_request (simplest form) --- skip_eval: 3:$ENV{TEST_NGINX_USE_HTTP3} +--- no_http2 --- http_config eval " lua_package_cpath '$::LuaCpath'; @@ -269,6 +271,7 @@ Logged in 56 === TEST 8: working with ngx_auth_request +--- no_http2 --- skip_eval: 3:$ENV{TEST_NGINX_USE_HTTP3} --- http_config eval " @@ -762,6 +765,7 @@ GET /t === TEST 27: accepts NGX_ERROR +--- no_http2 --- config location = /t { content_by_lua_block { @@ -780,6 +784,7 @@ curl: (95) HTTP/3 stream 0 reset by server === TEST 28: accepts NGX_DECLINED +--- no_http2 --- config location = /t { content_by_lua_block { diff --git a/t/014-bugs.t b/t/014-bugs.t index d34f42e23d..303187929f 100644 --- a/t/014-bugs.t +++ b/t/014-bugs.t @@ -201,7 +201,7 @@ https://datatracker.ietf.org/doc/html/rfc7540#section-8.1.2 header field names MUST be converted to lowercase prior to their encoding in HTTP/2. A request or response containing uppercase header field names MUST be treated as malformed - +--- no_http2 --- config location /sub { content_by_lua ' diff --git a/t/016-resp-header.t b/t/016-resp-header.t index 6cf699d88e..b30090812c 100644 --- a/t/016-resp-header.t +++ b/t/016-resp-header.t @@ -298,6 +298,7 @@ Fooy: cony1, cony2 === TEST 15: set header after ngx.print +--- no_http2 --- config location /lua { default_type "text/plain"; diff --git a/t/020-subrequest.t b/t/020-subrequest.t index 37914be061..e91f3f6253 100644 --- a/t/020-subrequest.t +++ b/t/020-subrequest.t @@ -1198,6 +1198,7 @@ body: === TEST 43: subrequests with an output body filter returning NGX_ERROR +--- no_http2 --- config location /sub { echo hello world; diff --git a/t/023-rewrite/exit.t b/t/023-rewrite/exit.t index 9add80441c..7f01717eb6 100644 --- a/t/023-rewrite/exit.t +++ b/t/023-rewrite/exit.t @@ -120,6 +120,7 @@ GET /api?user=agentz === TEST 6: working with ngx_auth_request (simplest form, w/o ngx_memc) +--- no_http2 --- http_config eval " lua_package_cpath '$::LuaCpath'; @@ -192,6 +193,7 @@ Logged in 56 === TEST 7: working with ngx_auth_request (simplest form) +--- no_http2 --- http_config eval " lua_package_cpath '$::LuaCpath'; @@ -264,6 +266,7 @@ Logged in 56 === TEST 8: working with ngx_auth_request +--- no_http2 --- http_config eval " lua_package_cpath '$::LuaCpath'; diff --git a/t/024-access/exit.t b/t/024-access/exit.t index b77778213a..661ee2d8bc 100644 --- a/t/024-access/exit.t +++ b/t/024-access/exit.t @@ -114,6 +114,7 @@ GET /api?user=agentz === TEST 6: working with ngx_auth_request (simplest form, w/o ngx_memc) +--- no_http2 --- http_config eval " lua_package_cpath '$::LuaCpath'; @@ -182,6 +183,7 @@ Logged in 56 === TEST 7: working with ngx_auth_request (simplest form) +--- no_http2 --- http_config eval " lua_package_cpath '$::LuaCpath'; @@ -249,6 +251,7 @@ Logged in 56 === TEST 8: working with ngx_auth_request +--- no_http2 --- http_config eval " lua_package_cpath '$::LuaCpath'; diff --git a/t/026-mysql.t b/t/026-mysql.t index 02e14b9382..e7ab170600 100644 --- a/t/026-mysql.t +++ b/t/026-mysql.t @@ -16,6 +16,7 @@ run_tests(); __DATA__ === TEST 1: when mysql query timed out, kill that query by Lua +--- no_http2 --- http_config upstream backend { drizzle_server 127.0.0.1:$TEST_NGINX_MYSQL_PORT protocol=mysql diff --git a/t/033-ctx.t b/t/033-ctx.t index 782a0fab6e..77bd15f8c1 100644 --- a/t/033-ctx.t +++ b/t/033-ctx.t @@ -279,7 +279,7 @@ GET /t --- error_log ngx.ctx = 32 --- curl_error eval -qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly|curl: \(95\) HTTP\/3 stream 0 reset by server/ +qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 1 was not closed cleanly|curl: \(95\) HTTP\/3 stream 0 reset by server/ diff --git a/t/041-header-filter.t b/t/041-header-filter.t index 23fdac02cd..84bb39fba2 100644 --- a/t/041-header-filter.t +++ b/t/041-header-filter.t @@ -125,7 +125,7 @@ GET /read --- error_code --- response_body --- curl_error eval -qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly|curl: \(95\) HTTP\/3 stream 0 reset by server/ +qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 1 was not closed cleanly|curl: \(95\) HTTP\/3 stream 0 reset by server/ @@ -449,6 +449,7 @@ GET /lua === TEST 21: lua error (string) +--- no_http2 --- config location /lua { set $foo ''; @@ -468,11 +469,12 @@ failed to run header_filter_by_lua*: header_filter_by_lua(nginx.conf:47):2: Some --- no_error_log [alert] --- curl_error eval -qr/curl: \(56\) Failure when receiving data from the peer|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly|curl: \(52\) Empty reply from server|curl: \(95\) HTTP\/3 stream 0 reset by server/ +qr/curl: \(56\) Failure when receiving data from the peer|curl: \(92\) HTTP\/2 stream 1 was not closed cleanly|curl: \(28\) Remote peer returned unexpected data|curl: \(52\) Empty reply from server|curl: \(95\) HTTP\/3 stream 0 reset by server/ === TEST 22: lua error (nil) +--- no_http2 --- config location /lua { set $foo ''; @@ -492,7 +494,7 @@ failed to run header_filter_by_lua*: unknown reason --- no_error_log [alert] --- curl_error eval -qr/curl: \(56\) Failure when receiving data from the peer|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly|curl: \(52\) Empty reply from server|curl: \(95\) HTTP\/3 stream 0 reset by server/ +qr/curl: \(56\) Failure when receiving data from the peer|curl: \(92\) HTTP\/2 stream 1 was not closed cleanly|curl: \(28\) Remote peer returned unexpected data|curl: \(52\) Empty reply from server|curl: \(95\) HTTP\/3 stream 0 reset by server/ @@ -508,7 +510,7 @@ GET /lua --- error_log API disabled in the context of header_filter_by_lua* --- curl_error eval -qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly|curl: \(95\) HTTP\/3 stream 0 reset by server/ +qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 1 was not closed cleanly|curl: \(95\) HTTP\/3 stream 0 reset by server/ @@ -524,7 +526,7 @@ GET /lua --- error_log API disabled in the context of header_filter_by_lua* --- curl_error eval -qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly|curl: \(95\) HTTP\/3 stream 0 reset by server/ +qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 1 was not closed cleanly|curl: \(95\) HTTP\/3 stream 0 reset by server/ @@ -540,7 +542,7 @@ GET /lua --- error_log API disabled in the context of header_filter_by_lua* --- curl_error eval -qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly|curl: \(95\) HTTP\/3 stream 0 reset by server/ +qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 1 was not closed cleanly|curl: \(95\) HTTP\/3 stream 0 reset by server/ @@ -556,7 +558,7 @@ GET /lua --- error_log API disabled in the context of header_filter_by_lua* --- curl_error eval -qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly|curl: \(95\) HTTP\/3 stream 0 reset by server/ +qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 1 was not closed cleanly|curl: \(95\) HTTP\/3 stream 0 reset by server/ @@ -572,7 +574,7 @@ GET /lua --- error_log API disabled in the context of header_filter_by_lua* --- curl_error eval -qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly|curl: \(95\) HTTP\/3 stream 0 reset by server/ +qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 1 was not closed cleanly|curl: \(95\) HTTP\/3 stream 0 reset by server/ @@ -592,7 +594,7 @@ GET /lua --- error_log API disabled in the context of header_filter_by_lua* --- curl_error eval -qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly|curl: \(95\) HTTP\/3 stream 0 reset by server/ +qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 1 was not closed cleanly|curl: \(95\) HTTP\/3 stream 0 reset by server/ @@ -612,7 +614,7 @@ GET /lua --- error_log API disabled in the context of header_filter_by_lua* --- curl_error eval -qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly|curl: \(95\) HTTP\/3 stream 0 reset by server/ +qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 1 was not closed cleanly|curl: \(95\) HTTP\/3 stream 0 reset by server/ @@ -628,7 +630,7 @@ GET /lua --- error_log API disabled in the context of header_filter_by_lua* --- curl_error eval -qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly|curl: \(95\) HTTP\/3 stream 0 reset by server/ +qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 1 was not closed cleanly|curl: \(95\) HTTP\/3 stream 0 reset by server/ @@ -644,7 +646,7 @@ GET /lua --- error_log API disabled in the context of header_filter_by_lua* --- curl_error eval -qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly|curl: \(95\) HTTP\/3 stream 0 reset by server/ +qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 1 was not closed cleanly|curl: \(95\) HTTP\/3 stream 0 reset by server/ @@ -660,7 +662,7 @@ GET /lua --- error_log API disabled in the context of header_filter_by_lua* --- curl_error eval -qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly|curl: \(95\) HTTP\/3 stream 0 reset by server/ +qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 1 was not closed cleanly|curl: \(95\) HTTP\/3 stream 0 reset by server/ @@ -694,7 +696,7 @@ GET /lua --- error_log eval qr/API disabled in the context of header_filter_by_lua\*|http3 requests are not supported without content-length header/ms --- curl_error eval -qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly|curl: \(95\) HTTP\/3 stream 0 reset by server/ +qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 1 was not closed cleanly|curl: \(95\) HTTP\/3 stream 0 reset by server/ @@ -718,7 +720,7 @@ if (defined $ENV{TEST_NGINX_USE_HTTP3}) { $err_log; --- curl_error eval -qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly|curl: \(95\) HTTP\/3 stream 0 reset by server/ +qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 1 was not closed cleanly|curl: \(95\) HTTP\/3 stream 0 reset by server/ @@ -734,7 +736,7 @@ GET /lua --- error_log API disabled in the context of header_filter_by_lua* --- curl_error eval -qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly|curl: \(95\) HTTP\/3 stream 0 reset by server/ +qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 1 was not closed cleanly|curl: \(95\) HTTP\/3 stream 0 reset by server/ @@ -750,7 +752,7 @@ GET /lua --- error_log API disabled in the context of header_filter_by_lua* --- curl_error eval -qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly|curl: \(95\) HTTP\/3 stream 0 reset by server/ +qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 1 was not closed cleanly|curl: \(95\) HTTP\/3 stream 0 reset by server/ @@ -799,7 +801,7 @@ in function 'error' in function 'bar' in function 'foo' --- curl_error eval -qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly|curl: \(95\) HTTP\/3 stream 0 reset by server/ +qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 1 was not closed cleanly|curl: \(95\) HTTP\/3 stream 0 reset by server/ @@ -819,7 +821,7 @@ GET /lua?a=1&b=2 --- error_log eval qr/failed to load external Lua file ".*?test2\.lua": cannot open .*? No such file or directory/ --- curl_error eval -qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly|curl: \(95\) HTTP\/3 stream 0 reset by server/ +qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 1 was not closed cleanly|curl: \(95\) HTTP\/3 stream 0 reset by server/ @@ -867,7 +869,7 @@ failed to load inlined Lua code: header_filter_by_lua(nginx.conf:41):2: unexpect --- no_error_log no_such_error --- curl_error eval -qr/curl: \(56\) Failure when receiving data from the peer/ +qr/curl: \(56\) Failure when receiving data from the peer|curl: \(92\) HTTP\/2 stream 1 was not closed cleanly: INTERNAL_ERROR \(err 2\)/ @@ -898,7 +900,7 @@ failed to load inlined Lua code: header_filter_by_lua(nginx.conf:49):2: unexpect --- no_error_log no_such_error --- curl_error eval -qr/curl: \(56\) Failure when receiving data from the peer/ +qr/curl: \(56\) Failure when receiving data from the peer|curl: \(92\) HTTP\/2 stream 1 was not closed cleanly: INTERNAL_ERROR \(err 2\)/ @@ -924,4 +926,4 @@ failed to load inlined Lua code: header_filter_by_lua(...90123456789012345678901 --- no_error_log [alert] --- curl_error eval -qr/curl: \(56\) Failure when receiving data from the peer/ +qr/curl: \(56\) Failure when receiving data from the peer|curl: \(56\) Failure when receiving data from the peer|curl: \(92\) HTTP\/2 stream 1 was not closed cleanly: INTERNAL_ERROR \(err 2\)/ diff --git a/t/056-flush.t b/t/056-flush.t index 4376b18930..d2b107c754 100644 --- a/t/056-flush.t +++ b/t/056-flush.t @@ -516,7 +516,7 @@ GET /test my @errlog; if (defined $ENV{TEST_NGINX_USE_HTTP2}) { @errlog = [ -qr/lua writes elapsed 0\.[7-9]\d+ sec/, +qr/lua writes elapsed (?:0\.[7-9]\d+|[12]\.\d+) sec/, qr/lua flush requires waiting: buffered 0x[0-9a-f]+, delayed:1/, ]; } else { @@ -526,7 +526,6 @@ qr/lua flush requires waiting: buffered 0x[0-9a-f]+, delayed:1/, ]; } @errlog; - --- no_error_log [error] --- timeout: 4 diff --git a/t/068-socket-keepalive.t b/t/068-socket-keepalive.t index 626b441678..423d391799 100644 --- a/t/068-socket-keepalive.t +++ b/t/068-socket-keepalive.t @@ -1384,6 +1384,7 @@ bad argument #3 to 'connect' (bad "pool" option type: boolean) === TEST 23: clear the redis store +--- no_http2 --- config location /t { redis2_query flushall; @@ -3033,6 +3034,7 @@ lua tcp socket keepalive create connection pool for key "B" === TEST 54: wrong first argument for setkeepalive +--- no_http2 --- quic_max_idle_timeout: 1.2 --- http_config eval "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" @@ -3115,6 +3117,7 @@ qr{HTTP/3 stream 0 reset by server} === TEST 55: wrong second argument for setkeepalive +--- no_http2 --- quic_max_idle_timeout: 1.2 --- http_config eval "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" diff --git a/t/091-coroutine.t b/t/091-coroutine.t index bfbdb38937..16930ed3c0 100644 --- a/t/091-coroutine.t +++ b/t/091-coroutine.t @@ -763,7 +763,7 @@ GET /lua --- error_log API disabled in the context of header_filter_by_lua* --- curl_error eval -qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly|curl: \(95\) HTTP\/3 stream 0 reset by server/ +qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 1 was not closed cleanly|curl: \(95\) HTTP\/3 stream 0 reset by server/ @@ -1423,6 +1423,7 @@ GET /t === TEST 35: coroutine.wrap runtime errors do not log errors +--- no_http2 --- config location = /t { content_by_lua_block { @@ -1700,7 +1701,7 @@ GET /t "in function 'co'" ] --- curl_error eval -qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 0 was not closed cleanly|curl: \(95\) HTTP\/3 stream 0 reset by server/ +qr/curl: \(52\) Empty reply from server|curl: \(92\) HTTP\/2 stream 1 was not closed cleanly|curl: \(95\) HTTP\/3 stream 0 reset by server/ diff --git a/t/094-uthread-exit.t b/t/094-uthread-exit.t index 0194e44b31..375d8d6023 100644 --- a/t/094-uthread-exit.t +++ b/t/094-uthread-exit.t @@ -8,7 +8,7 @@ our $StapScript = $t::StapThread::StapScript; repeat_each(2); -plan tests => repeat_each() * (blocks() * 4); +plan tests => repeat_each() * (blocks() * 4 - 2); $ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; $ENV{TEST_NGINX_MEMCACHED_PORT} ||= '11211'; @@ -1135,7 +1135,6 @@ free request attempt to abort with pending subrequests --- no_error_log [alert] -[warn] @@ -1313,6 +1312,7 @@ attempt to abort with pending subrequests === TEST 16: exit in entry thread (user thread is still pending on ngx.location.capture_multi), without pending output +--- no_http2 --- config location /lua { client_body_timeout 12000ms; @@ -1407,6 +1407,7 @@ qr#curl: \(52\) Empty reply from server|curl: \(95\) HTTP/3 stream 0 reset by se === TEST 17: exit(444) in user thread (entry thread is still pending on ngx.location.capture), with pending output +--- no_http2 --- config location /lua { client_body_timeout 12000ms; @@ -1492,6 +1493,7 @@ qr#curl: \(52\) Empty reply from server|curl: \(95\) HTTP/3 stream 0 reset by se === TEST 18: exit(408) in user thread (entry thread is still pending on ngx.location.capture), with pending output +--- no_http2 --- config location /lua { client_body_timeout 12000ms; @@ -1655,6 +1657,6 @@ free request --- no_error_log [alert] [error] -[warn] + --- curl_error eval qr#curl: \(52\) Empty reply from server|curl: \(95\) HTTP/3 stream 0 reset by server# diff --git a/t/095-uthread-exec.t b/t/095-uthread-exec.t index 4cd121da1e..9ef6356090 100644 --- a/t/095-uthread-exec.t +++ b/t/095-uthread-exec.t @@ -344,6 +344,7 @@ attempt to abort with pending subrequests === TEST 6: exec in entry thread (user thread is still pending on ngx.location.capture), without pending output +--- no_http2 --- config location /lua { client_body_timeout 12000ms; diff --git a/t/096-uthread-redirect.t b/t/096-uthread-redirect.t index 62909b944c..5df5ecfb09 100644 --- a/t/096-uthread-redirect.t +++ b/t/096-uthread-redirect.t @@ -190,6 +190,7 @@ free request === TEST 3: ngx.redirect() in entry thread (user thread is still pending on ngx.location.capture_multi), without pending output +--- no_http2 --- config location /lua { client_body_timeout 12000ms; diff --git a/t/138-balancer.t b/t/138-balancer.t index 41be75fcdc..f48c7fa41d 100644 --- a/t/138-balancer.t +++ b/t/138-balancer.t @@ -12,7 +12,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * (blocks() * 4 + 7); +plan tests => repeat_each() * (blocks() * 4 - 3); #no_diff(); no_long_string(); @@ -41,8 +41,6 @@ __DATA__ '[lua] balancer_by_lua(nginx.conf:27):2: hello from balancer by lua! while connecting to upstream,', qr{\[crit\] .*? connect\(\) to 0\.0\.0\.1:80 failed .*?, upstream: "http://0\.0\.0\.1:80/t"}, ] ---- no_error_log -[warn] @@ -67,7 +65,6 @@ qr{\[crit\] .*? connect\(\) to 0\.0\.0\.1:80 failed .*?, upstream: "http://0\.0\ [lua] balancer_by_lua(nginx.conf:27):2: hello from balancer by lua! while connecting to upstream, --- no_error_log eval [ -'[warn]', qr{\[crit\] .*? connect\(\) to 0\.0\.0\.1:80 failed .*?, upstream: "http://0\.0\.0\.1:80/t"}, ] @@ -95,8 +92,6 @@ qr{\[crit\] .*? connect\(\) to 0\.0\.0\.1:80 failed .*?, upstream: "http://0\.0\ '[lua] balancer_by_lua(nginx.conf:27):2: hello from balancer by lua! while connecting to upstream,', qr{\[crit\] .*? connect\(\) to 0\.0\.0\.1:80 failed .*?, upstream: "http://0\.0\.0\.1:80/t"}, ] ---- no_error_log -[warn] @@ -125,8 +120,6 @@ qr{\[crit\] .*? connect\(\) to 0\.0\.0\.1:80 failed .*?, upstream: "http://0\.0\ "2: variable foo = 33", qr/\[crit\] .* connect\(\) .*? failed/, ] ---- no_error_log -[warn] @@ -153,8 +146,6 @@ Foo: bar "header foo: bar", qr/\[crit\] .* connect\(\) .*? failed/, ] ---- no_error_log -[warn] @@ -180,12 +171,11 @@ Foo: bar ["arg foo: bar", qr/\[crit\] .* connect\(\) .*? failed/, ] ---- no_error_log -[warn] === TEST 7: ngx.req.get_method() works +--- no_http2 --- http_config upstream backend { server 0.0.0.1; @@ -208,8 +198,6 @@ Foo: bar "method: GET", qr/\[crit\] .* connect\(\) .*? failed/, ] ---- no_error_log -[warn] @@ -235,8 +223,6 @@ print("hello from balancer by lua!") '[lua] a.lua:1: hello from balancer by lua! while connecting to upstream,', qr{\[crit\] .*? connect\(\) to 0\.0\.0\.1:80 failed .*?, upstream: "http://0\.0\.0\.1:80/t"}, ] ---- no_error_log -[warn] @@ -431,8 +417,6 @@ ctx counter: nil '[lua] balancer_by_lua(nginx.conf:27):2: hello from balancer by lua! while connecting to upstream,', qr{\[crit\] .*? connect\(\) to 0\.0\.0\.1:80 failed .*?, upstream: "http://0\.0\.0\.1:80/t"}, ] ---- no_error_log -[warn] @@ -589,8 +573,6 @@ upstream sent more data than specified in "Content-Length" header while reading --- error_code: 500 --- error_log eval "failed to load inlined Lua code: balancer_by_lua(nginx.conf:27):3: ')' expected (to close '(' at line 2) near ''", ---- no_error_log -[warn] diff --git a/t/143-ssl-session-fetch.t b/t/143-ssl-session-fetch.t index b8ca095aa0..8e09a52d64 100644 --- a/t/143-ssl-session-fetch.t +++ b/t/143-ssl-session-fetch.t @@ -7,7 +7,7 @@ use File::Basename; repeat_each(3); -plan tests => repeat_each() * (blocks() * 6); +plan tests => repeat_each() * (blocks() * 6) - 3; $ENV{TEST_NGINX_HTML_DIR} ||= html_dir(); @@ -1319,7 +1319,6 @@ connected: 1 ssl handshake: cdata close: 1 nil --- no_error_log -[warn] [error] [alert] [emerg] diff --git a/t/163-signal.t b/t/163-signal.t index 0ce8fa2613..a0c2ee8082 100644 --- a/t/163-signal.t +++ b/t/163-signal.t @@ -42,7 +42,7 @@ qr/\[notice\] \d+#\d+: exit$/ --- no_error_log eval qr/\[notice\] \d+#\d+: reconfiguring/ --- curl_error eval -qr/curl: \(28\) Operation timed out after \d+ milliseconds with 0 bytes received|curl: \(56\) Recv failure: Connection reset by peer|curl: \(55\) sendmsg\(\) returned -1 \(errno 111\)/ +qr/curl: \(28\) Operation timed out after \d+ milliseconds with 0 bytes received|curl: \(56\) Recv failure: Connection reset by peer|curl: \(56\) Failure when receiving data from the peer|curl: \(55\) sendmsg\(\) returned -1 \(errno 111\)/ From 5bd471a4bce6c02dd68b1ca72fbabb09fb2041d8 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Fri, 17 Jan 2025 13:24:35 +0800 Subject: [PATCH 208/254] bumped version of lua-nginx-module to 10028. --- src/api/ngx_http_lua_api.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/ngx_http_lua_api.h b/src/api/ngx_http_lua_api.h index 4b374f56ee..021044eb87 100644 --- a/src/api/ngx_http_lua_api.h +++ b/src/api/ngx_http_lua_api.h @@ -19,7 +19,7 @@ /* Public API for other Nginx modules */ -#define ngx_http_lua_version 10027 +#define ngx_http_lua_version 10028 typedef struct ngx_http_lua_co_ctx_s ngx_http_lua_co_ctx_t; From 004922e1cf95eabde001203e2010365ff5d3e70d Mon Sep 17 00:00:00 2001 From: lijunlong Date: Thu, 13 Feb 2025 17:35:03 +0800 Subject: [PATCH 209/254] feature: Export three functions for manipulating ngx_http_lua_co_ctx_t structures. --- src/api/ngx_http_lua_api.h | 8 ++++++++ src/ngx_http_lua_api.c | 25 ++++++++++++++++++++++++- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/api/ngx_http_lua_api.h b/src/api/ngx_http_lua_api.h index 021044eb87..fa59095c6a 100644 --- a/src/api/ngx_http_lua_api.h +++ b/src/api/ngx_http_lua_api.h @@ -20,6 +20,7 @@ #define ngx_http_lua_version 10028 +#define NGX_HTTP_LUA_EXPORT_CO_CTX_CLEANUP 1 typedef struct ngx_http_lua_co_ctx_s ngx_http_lua_co_ctx_t; @@ -66,6 +67,13 @@ void ngx_http_lua_set_cur_co_ctx(ngx_http_request_t *r, lua_State *ngx_http_lua_get_co_ctx_vm(ngx_http_lua_co_ctx_t *coctx); + +void *ngx_http_lua_get_co_ctx_data(ngx_http_lua_co_ctx_t *coctx); +void ngx_http_lua_set_co_ctx_cleanup(ngx_http_lua_co_ctx_t *coctx, + ngx_http_cleanup_pt cleanup, void *data); +void ngx_http_lua_cleanup_co_ctx_pending_operation( + ngx_http_lua_co_ctx_t *coctx); + void ngx_http_lua_co_ctx_resume_helper(ngx_http_lua_co_ctx_t *coctx, int nrets); int ngx_http_lua_get_lua_http10_buffering(ngx_http_request_t *r); diff --git a/src/ngx_http_lua_api.c b/src/ngx_http_lua_api.c index 0d3ec9c988..2478f0da80 100644 --- a/src/ngx_http_lua_api.c +++ b/src/ngx_http_lua_api.c @@ -221,7 +221,7 @@ ngx_http_lua_get_cur_co_ctx(ngx_http_request_t *r) ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); - return ctx->cur_co_ctx; + return ctx == NULL ? NULL : ctx->cur_co_ctx; } @@ -245,6 +245,29 @@ ngx_http_lua_get_co_ctx_vm(ngx_http_lua_co_ctx_t *coctx) } +void * +ngx_http_lua_get_co_ctx_data(ngx_http_lua_co_ctx_t *coctx) +{ + return coctx ? coctx->data : NULL; +} + + +void +ngx_http_lua_set_co_ctx_cleanup(ngx_http_lua_co_ctx_t *coctx, + ngx_http_cleanup_pt cleanup, void *data) +{ + coctx->cleanup = cleanup; + coctx->data = data; +} + + +void +ngx_http_lua_cleanup_co_ctx_pending_operation(ngx_http_lua_co_ctx_t *coctx) +{ + ngx_http_lua_cleanup_pending_operation(coctx); +} + + static ngx_int_t ngx_http_lua_co_ctx_resume(ngx_http_request_t *r) { From e8f65dc53d6a4f20c6e9eb4fad3b8f2eae3cca59 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Sat, 15 Feb 2025 18:13:21 +0800 Subject: [PATCH 210/254] bugfix: didn't flush send buffer after lua phase(access/rewrite/server_rewrite) done. --- src/ngx_http_lua_accessby.c | 5 +- src/ngx_http_lua_rewriteby.c | 4 +- src/ngx_http_lua_server_rewriteby.c | 4 +- t/015-status.t | 186 +++++++++++++++++++++++++++- 4 files changed, 192 insertions(+), 7 deletions(-) diff --git a/src/ngx_http_lua_accessby.c b/src/ngx_http_lua_accessby.c index d40eab123e..b8c26605cf 100644 --- a/src/ngx_http_lua_accessby.c +++ b/src/ngx_http_lua_accessby.c @@ -95,6 +95,7 @@ ngx_http_lua_access_handler(ngx_http_request_t *r) dd("entered? %d", (int) ctx->entered_access_phase); + if (ctx->entered_access_phase) { dd("calling wev handler"); rc = ctx->resume_handler(r); @@ -105,7 +106,7 @@ ngx_http_lua_access_handler(ngx_http_request_t *r) } if (rc == NGX_OK) { - if (r->header_sent) { + if (r->header_sent || r->headers_out.status!= 0) { dd("header already sent"); /* response header was already generated in access_by_lua*, @@ -369,7 +370,7 @@ ngx_http_lua_access_by_chunk(lua_State *L, ngx_http_request_t *r) #if 1 if (rc == NGX_OK) { - if (r->header_sent) { + if (r->header_sent || r->headers_out.status != 0) { dd("header already sent"); /* response header was already generated in access_by_lua*, diff --git a/src/ngx_http_lua_rewriteby.c b/src/ngx_http_lua_rewriteby.c index 4109f288e3..091d765e41 100644 --- a/src/ngx_http_lua_rewriteby.c +++ b/src/ngx_http_lua_rewriteby.c @@ -107,7 +107,7 @@ ngx_http_lua_rewrite_handler(ngx_http_request_t *r) } if (rc == NGX_DECLINED) { - if (r->header_sent) { + if (r->header_sent || r->headers_out.status != 0) { dd("header already sent"); /* response header was already generated in rewrite_by_lua*, @@ -349,7 +349,7 @@ ngx_http_lua_rewrite_by_chunk(lua_State *L, ngx_http_request_t *r) } if (rc == NGX_OK || rc == NGX_DECLINED) { - if (r->header_sent) { + if (r->header_sent || r->headers_out.status != 0) { dd("header already sent"); /* response header was already generated in rewrite_by_lua*, diff --git a/src/ngx_http_lua_server_rewriteby.c b/src/ngx_http_lua_server_rewriteby.c index be860693f4..ed37f03efa 100644 --- a/src/ngx_http_lua_server_rewriteby.c +++ b/src/ngx_http_lua_server_rewriteby.c @@ -69,7 +69,7 @@ ngx_http_lua_server_rewrite_handler(ngx_http_request_t *r) } if (rc == NGX_DECLINED) { - if (r->header_sent) { + if (r->header_sent || r->headers_out.status != 0) { dd("header already sent"); /* response header was already generated in rewrite_by_lua*, @@ -307,7 +307,7 @@ ngx_http_lua_server_rewrite_by_chunk(lua_State *L, ngx_http_request_t *r) } if (rc == NGX_OK || rc == NGX_DECLINED) { - if (r->header_sent) { + if (r->header_sent || r->headers_out.status != 0) { dd("header already sent"); /* response header was already generated in rewrite_by_lua*, diff --git a/t/015-status.t b/t/015-status.t index c768aebcea..d3f6a3b4cf 100644 --- a/t/015-status.t +++ b/t/015-status.t @@ -9,7 +9,7 @@ log_level('warn'); #repeat_each(120); repeat_each(2); -plan tests => repeat_each() * (blocks() * 2 + 10); +plan tests => repeat_each() * (blocks() * 3 + 2); #no_diff(); #no_long_string(); @@ -29,6 +29,8 @@ __DATA__ GET /nil --- response_body nil +--- no_error_log +[error] @@ -43,6 +45,8 @@ nil GET /nil --- response_body not nil +--- no_error_log +[error] @@ -57,6 +61,8 @@ not nil GET /nil --- response_body 0 +--- no_error_log +[error] @@ -73,6 +79,8 @@ GET /nil --- response_body blah 200 +--- no_error_log +[error] @@ -89,6 +97,8 @@ GET /201 --- response_body created --- error_code: 201 +--- no_error_log +[error] @@ -105,6 +115,8 @@ GET /201 --- response_body created --- error_code: 201 +--- no_error_log +[error] @@ -121,6 +133,8 @@ GET /201 --- response_body created --- error_code: 201 +--- no_error_log +[error] @@ -136,6 +150,8 @@ created GET /201 --- response_body_like: 500 Internal Server Error --- error_code: 500 +--- no_error_log +[crit] @@ -248,6 +264,8 @@ GET /t --- http09 --- response_body status = 9 +--- no_error_log +[error] @@ -345,3 +363,169 @@ GET /t match --- no_error_log [error] + + + +=== TEST 18: set ngx.status in server_rewrite_by_lua_block +don't proxy_pass to upstream +--- config + server_rewrite_by_lua_block { + if ngx.var.uri == "/t" then + ngx.status = 403 + ngx.say("Hello World") + end + } + + location /t { + proxy_pass http://127.0.0.1:$TEST_NGINX_SERVER_PORT/u; + } + + location /u { + content_by_lua_block { + ngx.say("From upstream") + } + } +--- request +GET /t HTTP/1.0 +--- response_body +Hello World +--- error_code: 403 +--- no_error_log +[error] + + + +=== TEST 19: set ngx.status in rewrite_by_lua_block +don't proxy_pass to upstream +--- config + location /t { + rewrite_by_lua_block { + ngx.status = 403 + ngx.say("Hello World") + } + proxy_pass http://127.0.0.1:$TEST_NGINX_SERVER_PORT/u; + } + + location /u { + content_by_lua_block { + ngx.say("From upstream") + } + } +--- request +GET /t HTTP/1.0 +--- response_body +Hello World +--- error_code: 403 +--- no_error_log +[error] + + + +=== TEST 20: set ngx.status in access_by_lua_block +don't proxy_pass to upstream +--- config + location /t { + access_by_lua_block { + ngx.status = 403 + ngx.say("Hello World") + } + proxy_pass http://127.0.0.1:$TEST_NGINX_SERVER_PORT/u; + } + + location /u { + content_by_lua_block { + ngx.say("From upstream") + } + } +--- request +GET /t HTTP/1.0 +--- response_body +Hello World +--- error_code: 403 +--- no_error_log +[error] + + + +=== TEST 21: set ngx.status in server_rewrite_by_lua_block with sleep +don't proxy_pass to upstream +--- config + server_rewrite_by_lua_block { + if ngx.var.uri == "/t" then + ngx.sleep(0.001) + ngx.status = 403 + ngx.say("Hello World") + end + } + + location /t { + proxy_pass http://127.0.0.1:$TEST_NGINX_SERVER_PORT/u; + } + + location /u { + content_by_lua_block { + ngx.say("From upstream") + } + } +--- request +GET /t HTTP/1.0 +--- response_body +Hello World +--- error_code: 403 +--- no_error_log +[error] + + + +=== TEST 22: set ngx.status in rewrite_by_lua_block with sleep +don't proxy_pass to upstream +--- config + location /t { + rewrite_by_lua_block { + ngx.sleep(0.001) + ngx.status = 403 + ngx.say("Hello World") + } + + proxy_pass http://127.0.0.1:$TEST_NGINX_SERVER_PORT/u; + } + + location /u { + content_by_lua_block { + ngx.say("From upstream") + } + } +--- request +GET /t HTTP/1.0 +--- response_body +Hello World +--- error_code: 403 +--- no_error_log +[error] + + + +=== TEST 23: set ngx.status in access_by_lua_block +don't proxy_pass to upstream +--- config + location /t { + access_by_lua_block { + ngx.sleep(0.001) + ngx.status = 403 + ngx.say("Hello World") + } + proxy_pass http://127.0.0.1:$TEST_NGINX_SERVER_PORT/u; + } + + location /u { + content_by_lua_block { + ngx.say("From upstream") + } + } +--- request +GET /t HTTP/1.0 +--- response_body +Hello World +--- error_code: 403 +--- no_error_log +[error] From 53588e986bad6a0edec465da1e42f14a918d5500 Mon Sep 17 00:00:00 2001 From: willmafh Date: Sun, 2 Mar 2025 13:34:47 +0800 Subject: [PATCH 211/254] style: add missing space. --- src/ngx_http_lua_accessby.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ngx_http_lua_accessby.c b/src/ngx_http_lua_accessby.c index b8c26605cf..206f32ec1e 100644 --- a/src/ngx_http_lua_accessby.c +++ b/src/ngx_http_lua_accessby.c @@ -106,7 +106,7 @@ ngx_http_lua_access_handler(ngx_http_request_t *r) } if (rc == NGX_OK) { - if (r->header_sent || r->headers_out.status!= 0) { + if (r->header_sent || r->headers_out.status != 0) { dd("header already sent"); /* response header was already generated in access_by_lua*, From ee3dd989fda7c6a70d0a61250685a902a3f79f92 Mon Sep 17 00:00:00 2001 From: willmafh Date: Sun, 2 Mar 2025 15:13:05 +0800 Subject: [PATCH 212/254] bugfix: unnecessary to do error check. --- src/ngx_http_lua_socket_tcp.c | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 998881d1ca..5f2255e7eb 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -128,7 +128,7 @@ static int ngx_http_lua_socket_tcp_conn_op_resume_retval_handler( ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u, lua_State *L); static int ngx_http_lua_socket_tcp_upstream_destroy(lua_State *L); static int ngx_http_lua_socket_downstream_destroy(lua_State *L); -static ngx_int_t ngx_http_lua_socket_push_input_data(ngx_http_request_t *r, +static void ngx_http_lua_socket_push_input_data(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx, ngx_http_lua_socket_tcp_upstream_t *u, lua_State *L); static ngx_int_t ngx_http_lua_socket_add_pending_data(ngx_http_request_t *r, @@ -3153,7 +3153,6 @@ ngx_http_lua_socket_tcp_receive_retval_handler(ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u, lua_State *L) { int n; - ngx_int_t rc; ngx_http_lua_ctx_t *ctx; ngx_event_t *ev; @@ -3200,12 +3199,7 @@ ngx_http_lua_socket_tcp_receive_retval_handler(ngx_http_request_t *r, dd("u->bufs_in: %p", u->bufs_in); if (u->bufs_in) { - rc = ngx_http_lua_socket_push_input_data(r, ctx, u, L); - if (rc == NGX_ERROR) { - lua_pushnil(L); - lua_pushliteral(L, "no memory"); - return 2; - } + ngx_http_lua_socket_push_input_data(r, ctx, u, L); (void) ngx_http_lua_socket_read_error_retval_handler(r, u, L); @@ -3219,12 +3213,7 @@ ngx_http_lua_socket_tcp_receive_retval_handler(ngx_http_request_t *r, return n + 1; } - rc = ngx_http_lua_socket_push_input_data(r, ctx, u, L); - if (rc == NGX_ERROR) { - lua_pushnil(L); - lua_pushliteral(L, "no memory"); - return 2; - } + ngx_http_lua_socket_push_input_data(r, ctx, u, L); return 1; } @@ -5908,7 +5897,7 @@ ngx_http_lua_socket_downstream_destroy(lua_State *L) } -static ngx_int_t +static void ngx_http_lua_socket_push_input_data(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx, ngx_http_lua_socket_tcp_upstream_t *u, lua_State *L) @@ -5980,8 +5969,6 @@ ngx_http_lua_socket_push_input_data(ngx_http_request_t *r, u->buf_in->buf->last = u->buffer.pos; u->buf_in->buf->pos = u->buffer.pos; } - - return NGX_OK; } From cb0b22d3868bb3e060aa23bd640592eaf09ad016 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Tue, 4 Mar 2025 10:03:22 +0800 Subject: [PATCH 213/254] tests: update SSL certificates. --- t/129-ssl-socket.t | 2 +- t/cert/gen-test-passphrase.sh | 23 +++++++++++++++++ t/cert/gen-test2.sh | 3 +++ t/cert/test2.crt | 36 ++++++++++++++++---------- t/cert/test2.key | 43 ++++++++++++++++++++----------- t/cert/test_passphrase.crt | 37 ++++++++++++++++----------- t/cert/test_passphrase.key | 48 ++++++++++++++++++++++------------- 7 files changed, 129 insertions(+), 63 deletions(-) create mode 100755 t/cert/gen-test-passphrase.sh create mode 100755 t/cert/gen-test2.sh diff --git a/t/129-ssl-socket.t b/t/129-ssl-socket.t index 611e72ab2f..8a05306ab0 100644 --- a/t/129-ssl-socket.t +++ b/t/129-ssl-socket.t @@ -1963,7 +1963,7 @@ $::TestCertificate" --- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+/ --- grep_error_log_out --- error_log eval -qr/SSL_do_handshake\(\) failed .*?(unknown protocol|wrong version number)/ +qr/SSL_do_handshake\(\) failed .*?(unknown protocol|wrong version number|routines::record layer failure)/ --- no_error_log lua ssl server name: SSL reused session diff --git a/t/cert/gen-test-passphrase.sh b/t/cert/gen-test-passphrase.sh new file mode 100755 index 0000000000..45e6806a39 --- /dev/null +++ b/t/cert/gen-test-passphrase.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +# Set variables +SUBJECT="/C=CN/ST=Guangdong/L=ShenZhen/O=OpenResty/OU=OpenResty/CN=test.com/emailAddress=guanglinlv@gmail.com" +DAYS=49000 # Approximately 134 years +KEY_FILE="test_passphrase.key" +CERT_FILE="test_passphrase.crt" +PASSWORD="123456" + +# Generate a new 2048-bit RSA private key, encrypted with the password +openssl genrsa -aes256 -passout pass:$PASSWORD -out $KEY_FILE 2048 + +# Generate a new self-signed certificate +openssl req -x509 -new -nodes -key $KEY_FILE -sha256 -days $DAYS \ + -out $CERT_FILE -subj "$SUBJECT" -passin pass:$PASSWORD + +# Display information about the new certificate +openssl x509 -in $CERT_FILE -text -noout + +echo "New 2048-bit certificate generated successfully!" +echo "Private key (encrypted): $KEY_FILE" +echo "Certificate: $CERT_FILE" + diff --git a/t/cert/gen-test2.sh b/t/cert/gen-test2.sh new file mode 100755 index 0000000000..ed7a9de398 --- /dev/null +++ b/t/cert/gen-test2.sh @@ -0,0 +1,3 @@ +openssl req -new -newkey rsa:2048 -days 3650 -nodes -x509 \ + -subj "/C=US/ST=California/L=San Francisco/O=OpenResty/CN=test2.com/emailAddress=openresty@gmail.com" \ + -keyout test2.key -out test2.crt diff --git a/t/cert/test2.crt b/t/cert/test2.crt index edc3b0df3b..6ba864c3fe 100644 --- a/t/cert/test2.crt +++ b/t/cert/test2.crt @@ -1,16 +1,24 @@ -----BEGIN CERTIFICATE----- -MIIChzCCAfACCQDjCkJpJUtZmjANBgkqhkiG9w0BAQUFADCBhjELMAkGA1UEBhMC -VVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28x -EjAQBgNVBAoMCU9wZW5SZXN0eTESMBAGA1UEAwwJdGVzdDIuY29tMSIwIAYJKoZI -hvcNAQkBFhNvcGVucmVzdHlAZ21haWwuY29tMCAXDTE0MDkxMzAwMTgxMFoYDzIx -MTQwODIwMDAxODEwWjCBhjELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3Ju -aWExFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28xEjAQBgNVBAoMCU9wZW5SZXN0eTES -MBAGA1UEAwwJdGVzdDIuY29tMSIwIAYJKoZIhvcNAQkBFhNvcGVucmVzdHlAZ21h -aWwuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDy+OVI2u5NBOeB2Cyz -Gnwy9b7Ao4CSi05XtUxh2IoVdzYZz6c4PFb9C1ad52LDdRStiQT5A7+RKLj6Kr7f -JrKFziJxMy4g4Kdn9G659vE7CWu/UAVjRUtc+mTBAEfjdbumizmHLG7DmnNhGl3R -NGiVNLsUInSMGfUlJRzZJXhI4QIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAEMmRvyN -N7uE24Tc6TR19JadNHK8g3YGktRoXWiqd/y0HY4NRPgvnK/nX7CY/wXa1j+uDO8K -e6/Ldm5RZrjtvfHJmTSAu8zkqTJz8bqRDH7kzL5Ni2Ky2x8r9dtB0ImpOiSlwvZN -snMvbrxEdwBiqlC9prV2f9aG+ACo1KnPL0j6 +MIID7zCCAtegAwIBAgIUS1f/CoGJaRaJvBgrXEXeTSm7kM4wDQYJKoZIhvcNAQEL +BQAwgYYxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQH +DA1TYW4gRnJhbmNpc2NvMRIwEAYDVQQKDAlPcGVuUmVzdHkxEjAQBgNVBAMMCXRl +c3QyLmNvbTEiMCAGCSqGSIb3DQEJARYTb3BlbnJlc3R5QGdtYWlsLmNvbTAeFw0y +NDAzMjQxMDI1NDhaFw0zNDAzMjIxMDI1NDhaMIGGMQswCQYDVQQGEwJVUzETMBEG +A1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzESMBAGA1UE +CgwJT3BlblJlc3R5MRIwEAYDVQQDDAl0ZXN0Mi5jb20xIjAgBgkqhkiG9w0BCQEW +E29wZW5yZXN0eUBnbWFpbC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQChXBMRP5X9Y0l5NogyIZatou1YDT2BDE9tza6dYKUdraJlGo1T4DZf7LoD +mKFvIpVqLedppZ9z9SrlrsZ8Be6OUbw3kxSyUPDvpauI4XXBR2ZuAHIzTy/Uare1 +1iZSjbT0KATiWviMWCWWblyBU5QPMFJJOmcjRDAZocfIUs4CzglRaDorl5qUFJHr +mROaIsag/10nnClTwaGwj1pHmFitKRHTIrYICYd5wGgstte9mDFz15s9a3f/Dwhc +/7neEHYaryRVhR627aDGVHHpcMRWr+FC8QmZTTkiFmO80eeaiyGGTS0AEW51EPI9 +Nr142PEaQETpjQaQnfNhZGnwTZHTAgMBAAGjUzBRMB0GA1UdDgQWBBQb73HlJHF7 +B4a1PWRkb3aovk7EtDAfBgNVHSMEGDAWgBQb73HlJHF7B4a1PWRkb3aovk7EtDAP +BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCQJcLh7+NzAukTG4hV +nVd572U4sCnlXwTN4lnRIkSGbQxOWwbuI7p05iAT9HJrFLm+rV0EOzxyl/fYkPgR +DKYfj7sGPp4Lo0NyQ3xhoVypqDDmv7Wm9CLy2mVTJ07khW5tV8GHg9mFwgb/XBTQ +c+RnNalIapqdlkQbxms5HLzKzTVRuDt+wvqcAsiKFwKDAL9DFrp36TP1t023w+vd +Vb6Ms+l+xFFcxMCxFEOkSPc7szwSce9Q+Hk2C6JdCU30gJPyEBUMl6vD+0l0IFG0 +ZEw1BhBp4d92xHiYgdnDEH1RdLPI0q1r7LJL+5ic+VFWycgbC0KRHCarduYgvMYy +GbRG -----END CERTIFICATE----- diff --git a/t/cert/test2.key b/t/cert/test2.key index 82ce6ce91d..3bd546da0e 100644 --- a/t/cert/test2.key +++ b/t/cert/test2.key @@ -1,15 +1,28 @@ ------BEGIN RSA PRIVATE KEY----- -MIICXAIBAAKBgQDy+OVI2u5NBOeB2CyzGnwy9b7Ao4CSi05XtUxh2IoVdzYZz6c4 -PFb9C1ad52LDdRStiQT5A7+RKLj6Kr7fJrKFziJxMy4g4Kdn9G659vE7CWu/UAVj -RUtc+mTBAEfjdbumizmHLG7DmnNhGl3RNGiVNLsUInSMGfUlJRzZJXhI4QIDAQAB -AoGAEqBB83PVENJvbOTFiHVfUAjGtr3R/Wnwd4jOcjHHZB3fZ9sjVoxJntxfp3s1 -dwZir2rxlqVS6i3VAFiGiVTOGo2Vvzhw2J7f58twCECmnLb2f863AkGEYe4dAndD -GHGD0WI0CBMD1sT18YCj561o0Wol5deWH0gM9pr2N3HkeIECQQD6hUKFlFhrpaHP -WNJsl6BxgE6pB5kxLcMcpIQ7P+kHUvtyvCJl5QZJqPrpPGjRsAI5Ph92rpsp/zDp -/IZNWGVjAkEA+Ele31Rt+XbV32MrLKZgBDBk+Pzss5LTn9fZ5v1k/7hrMk2VVWvk -AD6n5QiGe/g59woANpPb1T9l956SBf0d6wJABTXOS17pc9uvANP1FGMW6CVl/Wf2 -DKrJ+weE5IKQwyE7r4gwIvRfbBrClSU3fNzvPueG2f4JphbzmnoxBNzIxwJAYivY -mGNwzHehXx99/byXMHDWK+EN0n8WsBgP75Z3rekEcbJdfpYXY8Via1vwmOnwOW65 -4NqbzHix37PSNw37GwJBALxaGNpREO2Tk+oWOvsD2QyviMVae3mXAJHc6nLVdKDM -q0YvDT6VdeNYYFTkAuzJacsVXOpn6AnUMFj0OBedMhc= ------END RSA PRIVATE KEY----- +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQChXBMRP5X9Y0l5 +NogyIZatou1YDT2BDE9tza6dYKUdraJlGo1T4DZf7LoDmKFvIpVqLedppZ9z9Srl +rsZ8Be6OUbw3kxSyUPDvpauI4XXBR2ZuAHIzTy/Uare11iZSjbT0KATiWviMWCWW +blyBU5QPMFJJOmcjRDAZocfIUs4CzglRaDorl5qUFJHrmROaIsag/10nnClTwaGw +j1pHmFitKRHTIrYICYd5wGgstte9mDFz15s9a3f/Dwhc/7neEHYaryRVhR627aDG +VHHpcMRWr+FC8QmZTTkiFmO80eeaiyGGTS0AEW51EPI9Nr142PEaQETpjQaQnfNh +ZGnwTZHTAgMBAAECggEAAhemuvqx8A25YQQsgvM9jXXckbTmPxtQ7QcVmb6BlZ9v +834DJtB0VA0b97pNyZpPXrJGsG+F4E6QZlcRsCpcMWXs72Q4Xfw/tj6AjsSsWWZw +H8K2Dbqb+lYB7i6J463TvWDGzhqeOM+seRq9l1hlRfHQogN1spbf8CJ8Fo8VqHf3 +OyId5db0nRUFYV9ciPvJSnk8xi+0aJ2LWVAkCaXQkntbI3529x8KPQm9bGUjdMgo +A+HXAKZTZL7GtGZoSU4jjyymGLM4hPtzXBExbkX7s7HOP1AeWGom4reOC6XNScQq +ysfs0wVzJAVSl0vFbQfUT6GZ2ZsaTdkT+JgXrYwp5QKBgQDIzY1O/Hj2koVgfKmS +2+1JVehX8+yjgz3rSNVUauISLoMaYN4hipsKb7Vi6aDFl+Db296Qql7kIzzd/nFk +UwdBjShUi/xbewGcrYEXbdcXSIxt9ius76eJ9INfa4EmLrZoiX/3Am1u+CcdtcKm +jkqy1o9zoIPbD6lc242zGFK2nQKBgQDNtukEZop/PngCX0yDGWLxisrvFYSrHxnW +x9/Fw0B56qmyG2FpFg5WDlErenHXh+KSlQ3pV1sWK/+3pVzgGP2ZK+nv3ThEQJmg +IbI32dABmUG9+HckxgOuAzfqGW6Y4m5I8YpODjn26V6GeS+xQj0bolr4lZ00QSEG +R5BxxLLHLwKBgQDAzYzWwFgs+HaUNF5lokFt3syeVplqTsOPPHmI+q9iocJD+6qN +Lha7qJLTDFvQHYpL0AsdgFhoWOVCieK6X3ZiHHUS6O4/sBXWKEoBAvg5ZPFhS7KX +8+w768iQQBrbXJLMQOnbdDs7B44XWsQxRAK5QIawkPjJx3norO6bfck9iQKBgA05 +Ze9ffCXD6UkVwUBoQGEQsA0AkB/EBxA0lyEKdTmhKTmG4xMzVMaZcwRdgbX+SUVt +CZDnibZ6K50tpzPMx3iyRv6hdP2GPZn6sI9AlEuWA5DnyRj3FcN49344FlEDtV1B +EcgEyBskU2xHnBZEENOW80wpqgpy6WGS9ikqIOgHAoGAeAUetHWIdZZ+Qt6SS1s2 +R17YAiZe88QFAo3uK/dyApLgY7wvbM0n7Cor/3tbpzpzAujUb/qNqTdTXsZIeRfq +bI767g4/pNl7+jhDUKmDI001YdfHvcRSwjzyjshuSinJY9rydXLUIEWtkTG3f9v8 +d+yLXD2Dz9gF6l2Msj+C3To= +-----END PRIVATE KEY----- diff --git a/t/cert/test_passphrase.crt b/t/cert/test_passphrase.crt index f4d516ba9e..78d57577b0 100644 --- a/t/cert/test_passphrase.crt +++ b/t/cert/test_passphrase.crt @@ -1,17 +1,24 @@ -----BEGIN CERTIFICATE----- -MIICozCCAgwCCQDEutRdSs3vZjANBgkqhkiG9w0BAQUFADCBlDELMAkGA1UEBhMC -Q04xEjAQBgNVBAgMCUd1YW5nZG9uZzERMA8GA1UEBwwIU2hlblpoZW4xEjAQBgNV -BAoMCU9wZW5SZXN0eTESMBAGA1UECwwJT3BlblJlc3R5MREwDwYDVQQDDAh0ZXN0 -LmNvbTEjMCEGCSqGSIb3DQEJARYUZ3VhbmdsaW5sdkBnbWFpbC5jb20wIBcNMTYw -NDI4MTQ0MzI4WhgPMjE1MTAzMjcxNDQzMjhaMIGUMQswCQYDVQQGEwJDTjESMBAG -A1UECAwJR3Vhbmdkb25nMREwDwYDVQQHDAhTaGVuWmhlbjESMBAGA1UECgwJT3Bl -blJlc3R5MRIwEAYDVQQLDAlPcGVuUmVzdHkxETAPBgNVBAMMCHRlc3QuY29tMSMw -IQYJKoZIhvcNAQkBFhRndWFuZ2xpbmx2QGdtYWlsLmNvbTCBnzANBgkqhkiG9w0B -AQEFAAOBjQAwgYkCgYEA2KZ+HdH9R2tarxD8PKqu5EYq2BNGlFRg1xJmrw0XZBRM -UP/VPb+sIeioooz36uhiXfQjExlpBCA/0zNAN+HbFyqpPPTf1qLGrj/dqeE4MJaN -Bwzxiv3fZnENT65u2qbiFWIY+ATNHgA20d50nxNNjPTzLbkx/nYXL92r4kuAGk0C -AwEAATANBgkqhkiG9w0BAQUFAAOBgQCfMo0qbcs3kwl1tcNBO5hCcUUJRzyv041V -ff/nZ/JPIMo/LSZd12K82G/dLRN7uRT9nzqtm+JRkHALHWWWFKi6bdg1vcdOTWqC -08bCkJHQoXJQQLvvA6gNvnR+0b7L4CrCmrcyYgKDLXVGNP9Wv/PqSWWbxsmqngkA -Mvy6CVytFw== +MIIEDTCCAvWgAwIBAgIUZn0PL6eNqoKWughHd0SFO4aE/UswDQYJKoZIhvcNAQEL +BQAwgZQxCzAJBgNVBAYTAkNOMRIwEAYDVQQIDAlHdWFuZ2RvbmcxETAPBgNVBAcM +CFNoZW5aaGVuMRIwEAYDVQQKDAlPcGVuUmVzdHkxEjAQBgNVBAsMCU9wZW5SZXN0 +eTERMA8GA1UEAwwIdGVzdC5jb20xIzAhBgkqhkiG9w0BCQEWFGd1YW5nbGlubHZA +Z21haWwuY29tMCAXDTI1MDMwNDAxNDkwNFoYDzIxNTkwNTAxMDE0OTA0WjCBlDEL +MAkGA1UEBhMCQ04xEjAQBgNVBAgMCUd1YW5nZG9uZzERMA8GA1UEBwwIU2hlblpo +ZW4xEjAQBgNVBAoMCU9wZW5SZXN0eTESMBAGA1UECwwJT3BlblJlc3R5MREwDwYD +VQQDDAh0ZXN0LmNvbTEjMCEGCSqGSIb3DQEJARYUZ3VhbmdsaW5sdkBnbWFpbC5j +b20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCmsvo9t9/lhfavK6S8 +7lqP8lfpV1gZE4ahyRCQI0vgQitlhGjEzvBc7qTtkunQpSWkuHSczOR1WuKzO+PG +ubH0gjeyvEE2X/cipQ1kjiO9Mv8w2qOm9BkC9Wrob01X4mOhGZUgthfwRs0QFSUh +tzvjg+aApWyIlpmgE/T8bnCwtPS7BuzwEpTt5a51q8JKOr4AMTy64mrMFQRqtcIk +GYL9CnoxAjYT6NAcEqoapSLDm1xJ7w2RDL1mqkAdXYUQeNPwMivrtb+rCDD4p99A +TZ8rOuKQzDSxZ3BdCmR5WUXp9z+NeQE5SBu+vkOYMTvEN+e9ApRRnZTO8UHeRB0+ +6vJZAgMBAAGjUzBRMB0GA1UdDgQWBBSmnXGC+KOqNzyGXoujr3TMe3pepDAfBgNV +HSMEGDAWgBSmnXGC+KOqNzyGXoujr3TMe3pepDAPBgNVHRMBAf8EBTADAQH/MA0G +CSqGSIb3DQEBCwUAA4IBAQAokEqnbJNDUICvbsRQBFrDBZXjZaEPu69GrTg9OceB +N9Qu4CKRTL4WsV6uSbdj+Ox/r21UtCI1590oBpC3RiJ+WnGmpdUGVytGIODt/vJ7 +/R03EBy0o9e7XdlR4GfKMC7FVBsP/kkeacR2fswHYXtQrNlyuLhZW04HTDdYNNqb +LNCnsmwQ4WR4ek9PdcpeFfMY1Up6hTYZ441K8b6xSzMV0/LjzfmHXWoT3U1rQrfM +esm9t/R3sOvB/wBWQaRe0BbLYpkS7pcq8NQsWvSUFNl5TzrGtUf8KTyvEEdcUcZf +im48Ea7WYpE3RYs0laLBk/D3sz7vsK5wfiD0R/ASLE+s -----END CERTIFICATE----- diff --git a/t/cert/test_passphrase.key b/t/cert/test_passphrase.key index b8fc97634a..2cabedfb57 100644 --- a/t/cert/test_passphrase.key +++ b/t/cert/test_passphrase.key @@ -1,18 +1,30 @@ ------BEGIN RSA PRIVATE KEY----- -Proc-Type: 4,ENCRYPTED -DEK-Info: DES-EDE3-CBC,679ACC8E69ACAA92 - -Ssrjp3VU4somCNPiXkWqcudDnvnwbyj/Q0pS07at3lXKbhQSgI1Tzhg9Pm3BXXj5 -mkLdeGG5ocrj1Q9dhtmZgZeHHQIiynZBhjBu1Y+HPef8jXOWLrCOi8EKiWkJ2qG3 -V1KFM/95CcDt0mRLykUXEL3IpUst05SFb9XwiLokB7ypeu3NhgNUHjL6G+ubB4ri -TOUjCW4pEoNHjdC22IiqSncwCVhluYSGhr6ktHKehZMhYIXmL1wmSLdhTlsPXCQl -xvYILQ2vJcKIR1BkeYYPD/OQC6zCZlXIErzfgeZiz2+NTudKYpb9VmsQKsO+R8L7 -tZ/fNaR0vk8bbimMHgStAV4acVsC/7WxsqOjMJ8VTq1iqhYPl6N7kRdR3H3kSSOm -cN9T3SrOHDVaHbnWgToaOE4mKFjvFSLIOcWgus0iOHWXmY+SLG+Ndag3oVB6R9oB -cAHX19mq99+GhzA8IV4I0En2UCKQhnGPvkM+9mcCDxhRETlwncDjlMGOHpQ65J9r -eReVPIpnDkvHxPGTtsR3ZHTdWTZb+C0W2N3QIlJKrOzxFmfoj++yG3tMX42aDY0g -DVkrXgcKobiWN0AVrJNAwfG7uObKSCFYgz/0RRMCO4cjXRW99nxdjVDZhyc6R0Te -jzuF04okkOLNb25n2hP+yIULrn+6Nv/uHtFI0j0n3hOzcKh//dNbACSAKgkHni9g -JKDFJXgLJxf+Wc3So0DF9gYMKJJ+WbcdVT9gkC7RyQHlC90Pn7kNXzHr0ZawUsNI -ZxSkL4dMhYAfA4lUBJbOkwbSurv97LinOSRffpM0Nmf7VNw/Ue15eg== ------END RSA PRIVATE KEY----- +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIIFNTBfBgkqhkiG9w0BBQ0wUjAxBgkqhkiG9w0BBQwwJAQQ2v8WxwirSc2M7jaZ +mrWsPgICCAAwDAYIKoZIhvcNAgkFADAdBglghkgBZQMEASoEEAlDrk7LLHI/jJqN +QJ6z8MYEggTQtV86xHehGFn/Qkn5qSZicJ/sDLXQ+m4dFXgw9KMnm0zLG8kzEmb7 +sobUJ4CnwmpBv/GmpPxgy5v1fuvc8HXRJWr7xwv1FoD4lwVOWVFv/qTaII4TfcC6 +3vKqO7MbRaksyI/NmmepGKTGhbzW6XlEdE1TCG7tO02I3puSN0MbJACTpop53TG9 +g+b8HXegPXkLJ2p+ECjUqPwA+h6jZi2pIAztMHQpIizokomrLJ4+2ol3czJpA5nn +n8JbuYt1XWekq+PBi4l0+lAbk/RiLLK1PCN/Njp7iBBAtNtz9+yJd2Ev7wNDDxKk +dW73s8uTGde/n6hR4sl/akK8HLaw9tDcWsaHbIMl8zn3WZXksVUfb6CZVOU+BjBa +yZu3CnP1JTda16HgdZ5dGSNPNbrUeLLIRzM/OxK0yTtmkexOVIgSW0hGE1BXxFXk +v+mnzrjFrHNRQFhoCFciPqv+WfXsecSASeN0aLWP/RP6CLz6QXWQaK68Dn92v/WP +xc1NKk8l54wNCLqGaSXadUoTqEdHQH3GV5EkXP7MTb+fYi9/Y/S8wcXJtjUi3ABe +W+XCOh4zuuQPG7C3i6l/jLIL1ogQNYldad7MoM8eBU8u+TF+NqiJjTLCB1Quycqn +sN5oVS1VZfsx8XCFsvUAZgxzhjeXViBfwxKSKyT0b1drQZaY58LnyzjmzGkOpRfO +uzGzWPvHRxkGb9071XaRxD8YDLIngHCw3F2USto88efzmvBfB8ZIxk90S9TZZDeJ +rqIKpNXsfM4nCR07DW48n3IoiHLCtRFinfpboS5/47ZN4XBE7Q/QNJrWa2P07aWR +HdOBdD/N3DnM5bbSz7m+5TA+xC4/hEWLXt7Au+vnnhVyDdU80a3+3JY7y4vScHLS +Fn2grTk5F9pqieNhwawpXUCYNGFtJOY8LOQpUZdMpy6n6N5qzSjZ+vgE1Nwr0G/S ++n8ORUcJzF3s8h+u+SN8OC9W6chnftSIWKiqGsU4oM0FFkr2nOrfNNKqAQo2OU3W ++5lJovyqAcxtj+4qQsBrYzH7vRzdkigXhb/R7tRDnBRWBpWlMmnUhkaWG8EI0JLs +gjKNOUFCT1HgTSfonRxScDE5IAg3JxieNz9ppDCphvc0ii3wwdS7uwstKGZCC+Wr +lQsiV0Wa4WlWVMfLCONI13+zeOli4BmwepgkjJc+YogvLodblcHN14kTTCDvhDMp +KZglwFT+3zkxH9ArnO7/a8WQCWZV6bJ29HFUfAioE8Sie04WD4zgYEfU02r9A+vq +wl/w5UK6eXOO6Hz2OrfYh2dZXiCOLp+DhftKq6MKIIAcqFuAzrPvzxd7Uup/fxyX +n2Ub4YKmUV89RzJ2ipZRjiBcQo+9h4O9dIh4+2I0m7NPALqirutCFBe2cHu/Fwho +SzacLI21OzWLKbyZ2D6ueH4NrhnOZ10bo/lKbc5d3JzuGv6KW1NmGo32qiKeKNzG +Q52+sm0/TLiLxy2RlqJ1p7R9NLLZTY8bZTD125n2RtNaJWT564vseY8SaiUW62r8 +ksU5aPINa7Qkf4xgsmkSJymFs/9AjXfSCS/aZ13PQMUuI5A4fY9IZjSoiUlSx1bX ++2B91azW4yfHcAJrluIjZ13LvBU08ooPKPm2TazDi89/8GjBMpHUQN4= +-----END ENCRYPTED PRIVATE KEY----- From 8f3987f6bf48c8788b5c88c676086849d59342f9 Mon Sep 17 00:00:00 2001 From: kurt Date: Fri, 7 Mar 2025 19:24:50 +0800 Subject: [PATCH 214/254] feature: add function to bypass HTTP conditional request checks (#2401) I hereby granted the copyright of the changes in this pull request to the authors of this lua-nginx-module project. releated: https://github.com/openresty/lua-nginx-module/issues/2397 refer: https://github.com/nginx/nginx/commit/d9887ee2ae9069843eed67d5b5ea625a7faeedb1 Signed-off-by: tzssangglass * refactor: modify bypass_if_checks function to return void Signed-off-by: tzssangglass --------- Signed-off-by: tzssangglass --- src/ngx_http_lua_util.c | 6 ++++++ t/014-bugs.t | 30 ++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index c73bddc609..61f56cb7c0 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -4555,4 +4555,10 @@ ngx_http_lua_parse_addr(lua_State *L, u_char *text, size_t len) } +void +ngx_http_lua_ffi_bypass_if_checks(ngx_http_request_t *r) +{ + r->disable_not_modified = 1; +} + /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/t/014-bugs.t b/t/014-bugs.t index 303187929f..9d57afe134 100644 --- a/t/014-bugs.t +++ b/t/014-bugs.t @@ -1366,3 +1366,33 @@ If-Match: 1 --- error_code: 412 --- response_body eval qr/\Ahello\z/ + + + +=== TEST 50: nginx crashes when encountering an illegal http if header +crash with ngx.print() +--- main_config +--- config +error_page 412 /my_error_handler_412; + +location /t { + access_by_lua_block { + local ngx_resp = require "ngx.resp" + ngx_resp.bypass_if_checks() + ngx.print("hello") + ngx.exit(200) + } +} +location = /my_error_handler_412 { + content_by_lua_block { + ngx.sleep(0.002) + ngx.header["Content-Type"] = "text/plain" + } +} +--- request + GET /t +--- more_headers +If-Match: 1 +--- error_code: 200 +--- response_body eval +qr/\Ahello\z/ From 18ce5fbd58171a5faec966a5f7099ce930c812c2 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Fri, 21 Mar 2025 12:34:43 +0800 Subject: [PATCH 215/254] bugfix: didn't use right hostname when the length of hostname is greater than 32. --- src/ngx_http_lua_balancer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ngx_http_lua_balancer.c b/src/ngx_http_lua_balancer.c index ae0f1380b5..aa26a4a07a 100644 --- a/src/ngx_http_lua_balancer.c +++ b/src/ngx_http_lua_balancer.c @@ -702,7 +702,7 @@ ngx_http_lua_balancer_free_peer(ngx_peer_connection_t *pc, void *data, item->host.len = host->len; } else { - item->host.data = ngx_pstrdup(c->pool, bp->addr_text); + item->host.data = ngx_pstrdup(c->pool, host); if (item->host.data == NULL) { ngx_http_lua_balancer_close(c); @@ -713,7 +713,7 @@ ngx_http_lua_balancer_free_peer(ngx_peer_connection_t *pc, void *data, return; } - item->host.len = bp->addr_text->len; + item->host.len = host->len; } } else { From bdba93c3543a083f737c20fc067f4ad539d1942a Mon Sep 17 00:00:00 2001 From: lijunlong Date: Mon, 24 Mar 2025 23:37:16 +0800 Subject: [PATCH 216/254] bugfix: the modifications in this PR are to supplement the overlooked changes in the commit e8f65dc53. --- src/ngx_http_lua_accessby.c | 7 +++++-- src/ngx_http_lua_rewriteby.c | 8 ++++++-- src/ngx_http_lua_server_rewriteby.c | 8 ++++++-- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/ngx_http_lua_accessby.c b/src/ngx_http_lua_accessby.c index 206f32ec1e..31ee82fd93 100644 --- a/src/ngx_http_lua_accessby.c +++ b/src/ngx_http_lua_accessby.c @@ -106,7 +106,9 @@ ngx_http_lua_access_handler(ngx_http_request_t *r) } if (rc == NGX_OK) { - if (r->header_sent || r->headers_out.status != 0) { + if (r->header_sent + || (r->headers_out.status != 0 && ctx->out != NULL)) + { dd("header already sent"); /* response header was already generated in access_by_lua*, @@ -370,7 +372,8 @@ ngx_http_lua_access_by_chunk(lua_State *L, ngx_http_request_t *r) #if 1 if (rc == NGX_OK) { - if (r->header_sent || r->headers_out.status != 0) { + if (r->header_sent || (r->headers_out.status != 0 && ctx->out != NULL)) + { dd("header already sent"); /* response header was already generated in access_by_lua*, diff --git a/src/ngx_http_lua_rewriteby.c b/src/ngx_http_lua_rewriteby.c index 091d765e41..2c1cc04c7a 100644 --- a/src/ngx_http_lua_rewriteby.c +++ b/src/ngx_http_lua_rewriteby.c @@ -107,7 +107,9 @@ ngx_http_lua_rewrite_handler(ngx_http_request_t *r) } if (rc == NGX_DECLINED) { - if (r->header_sent || r->headers_out.status != 0) { + if (r->header_sent + || (r->headers_out.status != 0 && ctx->out != NULL)) + { dd("header already sent"); /* response header was already generated in rewrite_by_lua*, @@ -349,7 +351,9 @@ ngx_http_lua_rewrite_by_chunk(lua_State *L, ngx_http_request_t *r) } if (rc == NGX_OK || rc == NGX_DECLINED) { - if (r->header_sent || r->headers_out.status != 0) { + if (r->header_sent + || (r->headers_out.status != 0 && ctx->out != NULL)) + { dd("header already sent"); /* response header was already generated in rewrite_by_lua*, diff --git a/src/ngx_http_lua_server_rewriteby.c b/src/ngx_http_lua_server_rewriteby.c index ed37f03efa..d012a8e341 100644 --- a/src/ngx_http_lua_server_rewriteby.c +++ b/src/ngx_http_lua_server_rewriteby.c @@ -69,7 +69,9 @@ ngx_http_lua_server_rewrite_handler(ngx_http_request_t *r) } if (rc == NGX_DECLINED) { - if (r->header_sent || r->headers_out.status != 0) { + if (r->header_sent + || (r->headers_out.status != 0 && ctx->out != NULL)) + { dd("header already sent"); /* response header was already generated in rewrite_by_lua*, @@ -307,7 +309,9 @@ ngx_http_lua_server_rewrite_by_chunk(lua_State *L, ngx_http_request_t *r) } if (rc == NGX_OK || rc == NGX_DECLINED) { - if (r->header_sent || r->headers_out.status != 0) { + if (r->header_sent + || (r->headers_out.status != 0 && ctx->out != NULL)) + { dd("header already sent"); /* response header was already generated in rewrite_by_lua*, From 0547c254f4166aa0c8df569020046b7c99eed587 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Sun, 4 May 2025 11:41:37 +0800 Subject: [PATCH 217/254] feature: add sock:getfd(). --- README.markdown | 16 +++++++ src/ngx_http_lua_socket_tcp.c | 38 +++++++++++++++ src/ngx_http_lua_socket_udp.c | 2 +- t/058-tcp-socket.t | 76 ++++++++++++++++++++++++++++++ t/062-count.t | 6 +-- t/067-req-socket.t | 28 +++++++++++ t/116-raw-req-socket.t | 88 ++++++++++++++++++++++++++++++++++- 7 files changed, 249 insertions(+), 5 deletions(-) diff --git a/README.markdown b/README.markdown index 35c0b83e58..fa8f2c92ba 100644 --- a/README.markdown +++ b/README.markdown @@ -3751,6 +3751,7 @@ Nginx API for Lua * [ngx.socket.tcp](#ngxsockettcp) * [tcpsock:bind](#tcpsockbind) * [tcpsock:connect](#tcpsockconnect) +* [tcpsock:getfd](#getfd) * [tcpsock:setclientcert](#tcpsocksetclientcert) * [tcpsock:sslhandshake](#tcpsocksslhandshake) * [tcpsock:send](#tcpsocksend) @@ -8010,6 +8011,21 @@ This method was first introduced in the `v0.5.0rc1` release. [Back to TOC](#nginx-api-for-lua) + +tcpsock:getfd +-------------------- + +**syntax:** *fd, err = tcpsock:getfd()* + +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_client_hello_by_lua** + +Get the file describer of the current tcp socket. + +This method was first introduced in the `v0.10.29` release. + +[Back to TOC](#nginx-api-for-lua) + + tcpsock:setclientcert --------------------- diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 5f2255e7eb..b943c8ece4 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -227,6 +227,10 @@ static char ngx_http_lua_pattern_udata_metatable_key; #define ngx_http_lua_tcp_socket_metatable_literal_key "__tcp_cosocket_mt" +#define ngx_http_lua_tcp_req_socket_metatable_literal_key \ + "__tcp_req_cosocket_mt" +#define ngx_http_lua_tcp_raw_req_socket_metatable_literal_key \ + "__tcp_raw_req_cosocket_mt" void @@ -283,6 +287,12 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) lua_pushvalue(L, -1); lua_setfield(L, -2, "__index"); + lua_rawset(L, LUA_REGISTRYINDEX); + + lua_pushliteral(L, ngx_http_lua_tcp_req_socket_metatable_literal_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + req_socket_metatable_key)); + lua_rawget(L, LUA_REGISTRYINDEX); lua_rawset(L, LUA_REGISTRYINDEX); /* }}} */ @@ -312,6 +322,12 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) lua_pushvalue(L, -1); lua_setfield(L, -2, "__index"); + lua_rawset(L, LUA_REGISTRYINDEX); + + lua_pushliteral(L, ngx_http_lua_tcp_raw_req_socket_metatable_literal_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + raw_req_socket_metatable_key)); + lua_rawget(L, LUA_REGISTRYINDEX); lua_rawset(L, LUA_REGISTRYINDEX); /* }}} */ @@ -6684,6 +6700,28 @@ ngx_http_lua_ffi_socket_tcp_setoption(ngx_http_lua_socket_tcp_upstream_t *u, } +int +ngx_http_lua_ffi_socket_tcp_getfd(ngx_http_request_t *r, + ngx_http_lua_socket_tcp_upstream_t *u, const char **errmsg) +{ + int fd; + + *errmsg = NULL; + + if (u == NULL || u->peer.connection == NULL) { + *errmsg = "closed"; + return -1; + } + + fd = u->peer.connection->fd; + if (fd == -1) { + *errmsg = "faked connection"; + } + + return fd; +} + + /* just hack the fd for testing bad case, it will also return the original fd */ int ngx_http_lua_ffi_socket_tcp_hack_fd(ngx_http_lua_socket_tcp_upstream_t *u, diff --git a/src/ngx_http_lua_socket_udp.c b/src/ngx_http_lua_socket_udp.c index e2ba790fc5..3297cbbeca 100644 --- a/src/ngx_http_lua_socket_udp.c +++ b/src/ngx_http_lua_socket_udp.c @@ -1207,7 +1207,7 @@ ngx_http_lua_socket_udp_read(ngx_http_request_t *r, ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "lua udp socket read data: waiting: %d", (int) u->waiting); - n = ngx_udp_recv(u->udp_connection.connection, + n = ngx_udp_recv(c, ngx_http_lua_socket_udp_buffer, u->recv_buf_size); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, diff --git a/t/058-tcp-socket.t b/t/058-tcp-socket.t index db5cb60e84..e17d038038 100644 --- a/t/058-tcp-socket.t +++ b/t/058-tcp-socket.t @@ -4563,3 +4563,79 @@ connected: 1 setkeepalive: 1 --- no_error_log [error] + + + +=== TEST 75: getfd() +--- no_http2 +--- http_config + lua_package_path "../lua-resty-core/lib/?.lua;;"; +--- config + server_tokens off; + location /t { + #set $port 5000; + set $port $TEST_NGINX_SERVER_PORT; + + content_by_lua_block { + local sock = ngx.socket.tcp() + local port = ngx.var.port + local ok, err = sock:connect("127.0.0.1", port) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + local s, err = sock:getfd() + ngx.say("fd: ", s) + ngx.say("connected: ", ok) + + local req = "GET /foo HTTP/1.0\r\nHost: localhost\r\nConnection: close\r\n\r\n" + -- req = "OK" + + local bytes, err = sock:send(req) + if not bytes then + ngx.say("failed to send request: ", err) + return + end + + ngx.say("request sent: ", bytes) + + while true do + local line, err, part = sock:receive() + if line then + ngx.say("received: ", line) + + else + ngx.say("failed to receive a line: ", err, " [", part, "]") + break + end + end + + ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + } + } + + location /foo { + content_by_lua 'ngx.say("foo")'; + more_clear_headers Date; + } + +--- request +GET /t +--- response_body eval +qr/fd: \d+ +connected: 1 +request sent: 57 +received: HTTP\/1.1 200 OK +received: Server: nginx +received: Content-Type: text\/plain +received: Content-Length: 4 +received: Connection: close +received: +received: foo +failed to receive a line: closed \[\] +close: 1 nil +/ms +--- no_error_log +[error] diff --git a/t/062-count.t b/t/062-count.t index d0eabb1f2d..3fda3b9547 100644 --- a/t/062-count.t +++ b/t/062-count.t @@ -259,7 +259,7 @@ n = 10 POST /test hello world --- response_body -n = 6 +n = 7 --- no_error_log [error] --- skip_eval: 3: $ENV{TEST_NGINX_USE_HTTP3} @@ -460,7 +460,7 @@ worker: 5 --- request GET /test --- response_body -n = 16 +n = 17 --- no_error_log [error] @@ -513,7 +513,7 @@ n = 7 --- request GET /test --- response_body -n = 7 +n = 8 --- no_error_log [error] --- skip_eval: 3:$ENV{TEST_NGINX_USE_HTTP3} diff --git a/t/067-req-socket.t b/t/067-req-socket.t index 9aff58b647..54d59841f9 100644 --- a/t/067-req-socket.t +++ b/t/067-req-socket.t @@ -1176,3 +1176,31 @@ GET /t received: received: abc --- no_error_log [error] + + + +=== TEST 19: getfd +--- http_config + lua_package_path "../lua-resty-core/lib/?.lua;;"; +--- config + location /t { + content_by_lua_block { + local sock, err = ngx.req.socket() + if sock then + ngx.say("got the request socket") + else + ngx.say("failed to get the request socket: ", err) + end + + ngx.say(sock:getfd()) + } + } +--- request +POST /t +hello world +--- response_body eval +qr/\Agot the request socket +\d+ +\z/ms +--- no_error_log +[error] diff --git a/t/116-raw-req-socket.t b/t/116-raw-req-socket.t index 6704a92084..94ef077c41 100644 --- a/t/116-raw-req-socket.t +++ b/t/116-raw-req-socket.t @@ -12,7 +12,7 @@ use Test::Nginx::Socket::Lua $SkipReason ? (skip_all => $SkipReason) : (); repeat_each(2); -plan tests => repeat_each() * 43; +plan tests => repeat_each() * 46; our $HtmlDir = html_dir; @@ -977,3 +977,89 @@ GET /t msg: 1: received: hello --- no_error_log [error] + + + +=== TEST 17: getfd() +--- config + server_tokens off; + location = /t { + #set $port 5000; + set $port $TEST_NGINX_SERVER_PORT; + + content_by_lua_block { + local sock = ngx.socket.tcp() + local port = ngx.var.port + local ok, err = sock:connect("127.0.0.1", port) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + local req = "GET /mysock HTTP/1.1\r\nUpgrade: mysock\r\nHost: localhost\r\nConnection: close\r\n\r\nhello" + -- req = "OK" + + local bytes, err = sock:send(req) + if not bytes then + ngx.say("failed to send request: ", err) + return + end + + local reader = sock:receiveuntil("\r\n\r\n") + local data, err, partial = reader() + if not data then + ngx.say("no response header found") + return + end + + local msg, err = sock:receive() + if not msg then + ngx.say("failed to receive: ", err) + return + end + + ngx.say("msg: ", msg) + + ok, err = sock:close() + if not ok then + ngx.say("failed to close socket: ", err) + return + end + } + } + + location = /mysock { + content_by_lua_block { + ngx.status = 101 + ngx.send_headers() + ngx.flush(true) + ngx.req.read_body() + local sock, err = ngx.req.socket(true) + if not sock then + ngx.log(ngx.ERR, "server: failed to get raw req socket: ", err) + return + end + + local s = sock:getfd() + local data, err = sock:receive(5) + if not data then + ngx.log(ngx.ERR, "server: failed to receive: ", err) + return + end + + local bytes, err = sock:send("fd: " .. tostring(s) .. " 1: received: " .. data .. "\n") + if not bytes then + ngx.log(ngx.ERR, "server: failed to send: ", err) + return + end + } + more_clear_headers Date; + } + +--- request +GET /t +--- response_body eval +qr/\Amsg: fd: \d+ 1: received: hello +/ms +--- no_error_log +[error] From 02b5e4919fef3d457b8ee749afdefc73390ed985 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Sun, 4 May 2025 12:25:49 +0800 Subject: [PATCH 218/254] style: fixed coding style. --- src/ngx_http_lua_socket_tcp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index b943c8ece4..db3fea507c 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -227,9 +227,9 @@ static char ngx_http_lua_pattern_udata_metatable_key; #define ngx_http_lua_tcp_socket_metatable_literal_key "__tcp_cosocket_mt" -#define ngx_http_lua_tcp_req_socket_metatable_literal_key \ +#define ngx_http_lua_tcp_req_socket_metatable_literal_key \ "__tcp_req_cosocket_mt" -#define ngx_http_lua_tcp_raw_req_socket_metatable_literal_key \ +#define ngx_http_lua_tcp_raw_req_socket_metatable_literal_key \ "__tcp_raw_req_cosocket_mt" From bf94a7a054497f395f47040ebdc8371216b36fef Mon Sep 17 00:00:00 2001 From: willmafh Date: Mon, 5 May 2025 23:24:11 +0800 Subject: [PATCH 219/254] chore: code style consistency. --- src/ngx_http_lua_module.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/ngx_http_lua_module.c b/src/ngx_http_lua_module.c index 63367f46b3..0f23c2d769 100644 --- a/src/ngx_http_lua_module.c +++ b/src/ngx_http_lua_module.c @@ -1030,6 +1030,13 @@ ngx_http_lua_create_main_conf(ngx_conf_t *cf) * lmcf->shm_zones = NULL; * lmcf->init_handler = NULL; * lmcf->init_src = { 0, NULL }; + * lmcf->init_chunkname = NULL; + * lmcf->init_worker_handler = NULL; + * lmcf->init_worker_src = { 0, NULL }; + * lmcf->init_worker_chunkname = NULL; + * lmcf->exit_worker_handler = NULL; + * lmcf->exit_worker_src = { 0, NULL }; + * lmcf->exit_worker_chunkname = NULL; * lmcf->shm_zones_inited = 0; * lmcf->shdict_zones = NULL; * lmcf->preload_hooks = NULL; @@ -1197,6 +1204,11 @@ ngx_http_lua_create_srv_conf(ngx_conf_t *cf) * lscf->srv.ssl_sess_fetch_chunkname = NULL; * lscf->srv.ssl_sess_fetch_src_key = NULL; * + * lscf->srv.server_rewrite_handler = NULL; + * lscf->srv.server_rewrite_src = { 0, NULL }; + * lscf->srv.server_rewrite_chunkname = NULL; + * lscf->srv.server_rewrite_src_key = NULL; + * * lscf->balancer.original_init_upstream = NULL; * lscf->balancer.original_init_peer = NULL; * lscf->balancer.handler = NULL; @@ -1212,6 +1224,7 @@ ngx_http_lua_create_srv_conf(ngx_conf_t *cf) lscf->srv.ssl_sess_fetch_src_ref = LUA_REFNIL; #endif + lscf->srv.server_rewrite_src_ref = LUA_REFNIL; lscf->balancer.src_ref = LUA_REFNIL; lscf->balancer.max_cached = NGX_CONF_UNSET_UINT; return lscf; @@ -1387,25 +1400,33 @@ ngx_http_lua_create_loc_conf(ngx_conf_t *cf) /* set by ngx_pcalloc: * conf->access_src = {{ 0, NULL }, NULL, NULL, NULL}; * conf->access_src_key = NULL + * conf->access_handler = NULL; + * conf->access_chunkname = NULL; + * * conf->rewrite_src = {{ 0, NULL }, NULL, NULL, NULL}; * conf->rewrite_src_key = NULL; * conf->rewrite_handler = NULL; + * conf->rewrite_chunkname = NULL; * * conf->content_src = {{ 0, NULL }, NULL, NULL, NULL}; * conf->content_src_key = NULL; * conf->content_handler = NULL; + * conf->content_chunkname = NULL; * * conf->log_src = {{ 0, NULL }, NULL, NULL, NULL}; * conf->log_src_key = NULL; * conf->log_handler = NULL; + * conf->log_chunkname = NULL; * * conf->header_filter_src = {{ 0, NULL }, NULL, NULL, NULL}; * conf->header_filter_src_key = NULL; * conf->header_filter_handler = NULL; + * conf->header_filter_chunkname = NULL; * * conf->body_filter_src = {{ 0, NULL }, NULL, NULL, NULL}; * conf->body_filter_src_key = NULL; * conf->body_filter_handler = NULL; + * conf->body_filter_chunkname = NULL; * * conf->ssl = 0; * conf->ssl_protocols = 0; From 058126221710f79e2aa68ac6e42b7a19602a5b48 Mon Sep 17 00:00:00 2001 From: Zeping Bai Date: Mon, 5 May 2025 23:31:09 +0800 Subject: [PATCH 220/254] bugfix: ensure context is restorable on fd writable events. --- src/ngx_http_lua_bodyfilterby.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ngx_http_lua_bodyfilterby.c b/src/ngx_http_lua_bodyfilterby.c index c0484c8de0..179a501a59 100644 --- a/src/ngx_http_lua_bodyfilterby.c +++ b/src/ngx_http_lua_bodyfilterby.c @@ -368,6 +368,7 @@ ngx_http_lua_body_filter(ngx_http_request_t *r, ngx_chain_t *in) } } else { + ctx->context = old_context; out = NULL; } From d1d5b7375db0b4ca14269157bbf5194cda741eec Mon Sep 17 00:00:00 2001 From: Gabriel Clima Date: Tue, 6 May 2025 14:31:51 +0300 Subject: [PATCH 221/254] feature: added ngx_http_lua_ffi_ssl_get_client_hello_ext_present(). --- src/ngx_http_lua_ssl_client_helloby.c | 45 +++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/src/ngx_http_lua_ssl_client_helloby.c b/src/ngx_http_lua_ssl_client_helloby.c index 9800f7d41f..26c84345d9 100644 --- a/src/ngx_http_lua_ssl_client_helloby.c +++ b/src/ngx_http_lua_ssl_client_helloby.c @@ -662,6 +662,51 @@ ngx_http_lua_ffi_ssl_get_client_hello_ext(ngx_http_request_t *r, } +int +ngx_http_lua_ffi_ssl_get_client_hello_ext_present(ngx_http_request_t *r, + int **extensions, size_t *extensions_len, char **err) +{ + ngx_ssl_conn_t *ssl_conn; + int got_extensions; + size_t ext_len; + int *ext_out; + /* OPENSSL will allocate memory for us and make the ext_out point to it */ + + + if (r->connection == NULL || r->connection->ssl == NULL) { + *err = "bad request"; + return NGX_ERROR; + } + + ssl_conn = r->connection->ssl->connection; + if (ssl_conn == NULL) { + *err = "bad ssl conn"; + return NGX_ERROR; + } + +#ifdef SSL_ERROR_WANT_CLIENT_HELLO_CB + got_extensions = SSL_client_hello_get1_extensions_present(ssl_conn, + &ext_out, &ext_len); + if (!got_extensions || !ext_out || !ext_len) { + *err = "failed SSL_client_hello_get1_extensions_present()"; + return NGX_DECLINED; + } + + *extensions = ngx_palloc(r->connection->pool, sizeof(int) * ext_len); + if (*extensions != NULL) { + ngx_memcpy(*extensions, ext_out, sizeof(int) * ext_len); + *extensions_len = ext_len; + } + + OPENSSL_free(ext_out); + return NGX_OK; +#else + *err = "OpenSSL too old to support this function"; + return NGX_ERROR; +#endif +} + + int ngx_http_lua_ffi_ssl_set_protocols(ngx_http_request_t *r, int protocols, char **err) From b328ac17e20c562ec707c0e719b1c76394621643 Mon Sep 17 00:00:00 2001 From: ElvaLiu Date: Sun, 1 Dec 2024 18:23:11 -0800 Subject: [PATCH 222/254] fix: support tcp binding ip:port or ip of ipv4 or ipv6 --- README.markdown | 5 +-- src/ngx_http_lua_socket_tcp.c | 35 +++++++++++++++++--- t/168-tcp-socket-bind.t | 61 +++++++++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+), 6 deletions(-) diff --git a/README.markdown b/README.markdown index fa8f2c92ba..117a9e484b 100644 --- a/README.markdown +++ b/README.markdown @@ -7855,13 +7855,14 @@ See also [ngx.socket.udp](#ngxsocketudp). tcpsock:bind ------------ -**syntax:** *ok, err = tcpsock:bind(address)* +**syntax:** *ok, err = tcpsock:bind(address, port?)* **context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*,ssl_session_fetch_by_lua*,ssl_client_hello_by_lua** Just like the standard [proxy_bind](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_bind) directive, this api makes the outgoing connection to a upstream server originate from the specified local IP address. -Only IP addresses can be specified as the `address` argument. +IP addresses can be specified as the `address` argument. +The optional `port` argument is usually used in the transparent proxy. Here is an example for connecting to a TCP server from the specified local IP address: diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index db3fea507c..9b8c224624 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -862,8 +862,9 @@ ngx_http_lua_socket_tcp_bind(lua_State *L) n = lua_gettop(L); - if (n != 2) { - return luaL_error(L, "expecting 2 arguments, but got %d", + /* Correct the parameter check and allow 2 or 3 parameters */ + if (n != 2 && n != 3) { + return luaL_error(L, "expecting 2 or 3 arguments, but got %d", lua_gettop(L)); } @@ -881,6 +882,26 @@ ngx_http_lua_socket_tcp_bind(lua_State *L) luaL_checktype(L, 1, LUA_TTABLE); + port = 0; + /* handle case: host:port */ + /* Hit the following parameter combination: + * sock:bind("127.0.0.1", port) */ + if (n == 3) { + if (!lua_isnumber(L, 3)) { + lua_pushnil(L); + lua_pushfstring(L, "expecting port to be a" + "number but got type: %s", luaL_typename(L, 3)); + return 2; + } + + port = (int) lua_tointeger(L, 3); + if (port < 0 || port > 65535) { + lua_pushnil(L); + lua_pushfstring(L, "bad port number: %d", port); + return 2; + } + } + text = (u_char *) luaL_checklstring(L, 2, &len); local = ngx_http_lua_parse_addr(L, text, len); @@ -890,9 +911,11 @@ ngx_http_lua_socket_tcp_bind(lua_State *L) return 2; } + if (port > 0) { + ngx_inet_set_port(local->sockaddr, (in_port_t) port); + } /* TODO: we may reuse the userdata here */ lua_rawseti(L, 1, SOCKET_BIND_INDEX); - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua tcp socket bind ip: %V", &local->name); @@ -1145,6 +1168,10 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) lua_rawgeti(L, 1, SOCKET_BIND_INDEX); local = lua_touserdata(L, -1); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua tcp socket sock:connect ip: %V", &local->name); + lua_pop(L, 1); if (local) { @@ -3435,7 +3462,7 @@ ngx_http_lua_socket_tcp_handler(ngx_event_t *ev) static ngx_int_t ngx_http_lua_socket_tcp_get_peer(ngx_peer_connection_t *pc, void *data) { - /* empty */ + pc->type = SOCK_STREAM; return NGX_OK; } diff --git a/t/168-tcp-socket-bind.t b/t/168-tcp-socket-bind.t index a2aa50b4e7..123b525fe3 100644 --- a/t/168-tcp-socket-bind.t +++ b/t/168-tcp-socket-bind.t @@ -365,3 +365,64 @@ GET /t connected: 1 --- no_error_log [error] + + + +=== TEST 7: upstream sockets bind with ip port +--- config + server_tokens off; + location /t { + set $port $TEST_NGINX_SERVER_PORT; + content_by_lua_block { + local ip = "127.0.0.1" + local port = ngx.var.port + + local sock = ngx.socket.tcp() + + local ok, err = sock:bind(ip, 12345) + if not ok then + ngx.say("failed to bind", err) + return + end + + local ok, err = sock:connect("127.0.0.1", port) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + local ok, err = sock:setoption("reuseaddr", 1) + if not ok then + ngx.say("setoption reuseaddr failed: ", err) + end + + ngx.say("connected: ", ok) + + local bytes, err = sock:send("GET /foo HTTP/1.1\r\nHost: localhost\r\nConnection: keepalive\r\n\r\n") + if not bytes then + ngx.say("failed to send request: ", err) + return + end + + local reader = sock:receiveuntil("\r\n0\r\n\r\n") + local data, err = reader() + + if not data then + ngx.say("failed to receive response body: ", err) + return + end + sock:close() + ngx.say(data) + + } + } + + location /foo { + echo bind: $remote_addr:$remote_port; + } +--- request +GET /t +--- response_body eval +qr/bind:\s127\.0\.0\.1:12345|failed\s+to\s+connect:\s+address\s+already\s+in\s+use/ +--- error_log eval +"lua tcp socket bind ip: 127.0.0.1" From edd1b6a5998f6fe63cde72cef45c1d89e814b0e4 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Wed, 7 May 2025 23:33:46 +0800 Subject: [PATCH 223/254] bugfix: fixed typo. --- src/ngx_http_lua_socket_tcp.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 9b8c224624..85cf49069e 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -853,6 +853,7 @@ ngx_http_lua_socket_tcp_connect_helper(lua_State *L, static int ngx_http_lua_socket_tcp_bind(lua_State *L) { + int port; ngx_http_request_t *r; ngx_http_lua_ctx_t *ctx; int n; @@ -1169,8 +1170,10 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) lua_rawgeti(L, 1, SOCKET_BIND_INDEX); local = lua_touserdata(L, -1); - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua tcp socket sock:connect ip: %V", &local->name); + if (local != NULL) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua tcp socket sock:connect ip: %V", &local->name); + } lua_pop(L, 1); From 1f4d846f02cd3980d1f64fbc3e5359fd0e7716f6 Mon Sep 17 00:00:00 2001 From: Gabriel Clima Date: Sat, 24 May 2025 15:29:14 +0300 Subject: [PATCH 224/254] feature: ngx_http_lua_ffi_ssl_get_client_hello_ciphers(). Co-authored-by: lijunlong --- src/ngx_http_lua_ssl_client_helloby.c | 49 +++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/src/ngx_http_lua_ssl_client_helloby.c b/src/ngx_http_lua_ssl_client_helloby.c index 26c84345d9..b92fc46b5d 100644 --- a/src/ngx_http_lua_ssl_client_helloby.c +++ b/src/ngx_http_lua_ssl_client_helloby.c @@ -707,6 +707,55 @@ ngx_http_lua_ffi_ssl_get_client_hello_ext_present(ngx_http_request_t *r, } +int ngx_http_lua_ffi_ssl_get_client_hello_ciphers(ngx_http_request_t *r, + unsigned short *ciphers, size_t ciphers_size, char **err) +{ + int i; + size_t ciphers_cnt; + size_t ciphersuites_bytes; + ngx_ssl_conn_t *ssl_conn; + const unsigned char *ciphers_raw; + + if (r->connection == NULL || r->connection->ssl == NULL) { + *err = "bad request"; + return NGX_ERROR; + } + + ssl_conn = r->connection->ssl->connection; + if (ssl_conn == NULL) { + *err = "bad ssl conn"; + return NGX_ERROR; + } + + +#ifdef SSL_ERROR_WANT_CLIENT_HELLO_CB + ciphersuites_bytes = SSL_client_hello_get0_ciphers(ssl_conn, &ciphers_raw); + + if (ciphersuites_bytes == 0) { + *err = "failed SSL_client_hello_get0_ciphers()"; + return NGX_DECLINED; + } + + if (ciphersuites_bytes % 2 != 0) { + *err = "SSL_client_hello_get0_ciphers() odd ciphersuites_bytes"; + return NGX_DECLINED; + } + + ciphers_cnt = ciphersuites_bytes / 2; + ciphers_cnt = ciphers_cnt > ciphers_size ? ciphers_size : ciphers_cnt; + + for (i = 0 ; i < (int) ciphers_cnt ; i++) { + ciphers[i] = (ciphers_raw[i * 2] << 8) | ciphers_raw[i * 2 + 1]; + } + + return ciphers_cnt; +#else + *err = "OpenSSL too old to support this function"; + return NGX_ERROR; +#endif +} + + int ngx_http_lua_ffi_ssl_set_protocols(ngx_http_request_t *r, int protocols, char **err) From 9688812a4eba47c1f43892c998e50b988d740f5d Mon Sep 17 00:00:00 2001 From: lijunlong Date: Mon, 9 Jun 2025 08:19:02 +0800 Subject: [PATCH 225/254] tests: bumped openssl to v3.4.1. --- .travis.yml | 40 +++++++++++++++++---------------------- t/143-ssl-session-fetch.t | 10 +++++++++- util/build-with-dd.sh | 19 +------------------ util/build-without-ssl.sh | 24 +---------------------- util/build.sh | 9 --------- 5 files changed, 28 insertions(+), 74 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4eb8d3e5ce..8eb5abd914 100644 --- a/.travis.yml +++ b/.travis.yml @@ -29,6 +29,10 @@ addons: - libunwind-dev - wget - libbrotli1 + - lsb-release + - wget + - gnupg + - ca-certificates cache: directories: @@ -42,13 +46,10 @@ env: - LUAJIT_LIB=$LUAJIT_PREFIX/lib - LUAJIT_INC=$LUAJIT_PREFIX/include/luajit-2.1 - LUA_INCLUDE_DIR=$LUAJIT_INC - - PCRE_PREFIX=/opt/pcre - - PCRE2_PREFIX=/opt/pcre2 + - PCRE_PREFIX=/usr/local/openresty/pcre2 - PCRE_LIB=$PCRE_PREFIX/lib - - PCRE2_LIB=$PCRE2_PREFIX/lib - PCRE_INC=$PCRE_PREFIX/include - - PCRE2_INC=$PCRE2_PREFIX/include - - OPENSSL_PREFIX=/opt/ssl + - OPENSSL_PREFIX=/usr/local/openresty/openssl3 - OPENSSL_LIB=$OPENSSL_PREFIX/lib - OPENSSL_INC=$OPENSSL_PREFIX/include - LIBDRIZZLE_PREFIX=/opt/drizzle @@ -59,14 +60,10 @@ env: - TEST_NGINX_SLEEP=0.006 - MALLOC_PERTURB_=9 jobs: - #- NGINX_VERSION=1.21.4 OPENSSL_VER=1.1.1w OPENSSL_PATCH_VER=1.1.1f - #- NGINX_VERSION=1.25.1 OPENSSL_VER=1.1.1w TEST_NGINX_USE_HTTP2=1 - - NGINX_VERSION=1.27.1 OPENSSL_VER=1.1.1w OPENSSL_PATCH_VER=1.1.1f TEST_NGINX_TIMEOUT=5 PCRE_VER=8.45 - - NGINX_VERSION=1.27.1 OPENSSL_VER=3.0.15 OPENSSL_PATCH_VER=3.0.15 TEST_NGINX_TIMEOUT=5 PCRE2_VER=10.42 - - NGINX_VERSION=1.27.1 OPENSSL_VER=1.1.1w OPENSSL_PATCH_VER=1.1.1f TEST_NGINX_TIMEOUT=5 PCRE_VER=8.45 TEST_NGINX_USE_HTTP2=1 - - NGINX_VERSION=1.27.1 OPENSSL_VER=3.0.15 OPENSSL_PATCH_VER=3.0.15 TEST_NGINX_TIMEOUT=5 PCRE2_VER=10.42 TEST_NGINX_USE_HTTP2=1 - - NGINX_VERSION=1.27.1 OPENSSL_VER=3.0.15 OPENSSL_PATCH_VER=3.0.15 TEST_NGINX_USE_HTTP3=1 TEST_NGINX_QUIC_IDLE_TIMEOUT=3 PCRE2_VER=10.42 - - NGINX_VERSION=1.27.1 BORINGSSL=1 TEST_NGINX_USE_HTTP3=1 TEST_NGINX_QUIC_IDLE_TIMEOUT=3 PCRE2_VER=10.42 + - NGINX_VERSION=1.27.1 OPENSSL_VER=3.4.1 OPENSSL_PATCH_VER=3.4.1 TEST_NGINX_TIMEOUT=5 PCRE2_VER=10.45 + - NGINX_VERSION=1.27.1 OPENSSL_VER=3.4.1 OPENSSL_PATCH_VER=3.4.1 TEST_NGINX_TIMEOUT=5 PCRE2_VER=10.45 TEST_NGINX_USE_HTTP2=1 + - NGINX_VERSION=1.27.1 OPENSSL_VER=3.4.1 OPENSSL_PATCH_VER=3.4.1 TEST_NGINX_USE_HTTP3=1 TEST_NGINX_QUIC_IDLE_TIMEOUT=3 PCRE2_VER=10.45 + - NGINX_VERSION=1.27.1 BORINGSSL=1 TEST_NGINX_USE_HTTP3=1 TEST_NGINX_QUIC_IDLE_TIMEOUT=3 PCRE2_VER=10.45 services: - memcached @@ -77,15 +74,16 @@ before_install: - '! grep -n -P ''(?<=.{80}).+'' --color `find src -name ''*.c''` `find . -name ''*.h''` || (echo "ERROR: Found C source lines exceeding 80 columns." > /dev/stderr; exit 1)' - '! grep -n -P ''\t+'' --color `find src -name ''*.c''` `find . -name ''*.h''` || (echo "ERROR: Cannot use tabs." > /dev/stderr; exit 1)' - /usr/bin/env perl $(command -v cpanm) --sudo --notest Test::Nginx IPC::Run > build.log 2>&1 || (cat build.log && exit 1) + - wget -O - https://openresty.org/package/pubkey.gpg | sudo apt-key add - + - echo "deb http://openresty.org/package/ubuntu $(lsb_release -sc) main" | sudo tee /etc/apt/sources.list.d/openresty.list + - sudo apt-get update + - sudo DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends openresty-pcre2 openresty-openssl3 openresty-pcre2-dev openresty-openssl3-dev + install: - if [ ! -f download-cache/drizzle7-$DRIZZLE_VER.tar.gz ]; then wget -P download-cache https://github.com/openresty/openresty-deps-prebuild/releases/download/v20230902/drizzle7-$DRIZZLE_VER.tar.gz; fi - #- if [ -n "$PCRE_VER" ] && [ ! -f download-cache/pcre-$PCRE_VER.tar.gz ]; then wget -P download-cache https://downloads.sourceforge.net/project/pcre/pcre/${PCRE_VER}/pcre-${PCRE_VER}.tar.gz; fi #- if [ -n "$PCRE2_VER" ] && [ ! -f download-cache/pcre2-$PCRE2_VER.tar.gz ]; then wget -P download-cache https://github.com/PCRE2Project/pcre2/releases/download/pcre2-${PCRE2_VER}/pcre2-${PCRE2_VER}.tar.gz; fi #- if [ -n "$OPENSSL_VER" ] && [ ! -f download-cache/openssl-$OPENSSL_VER.tar.gz ]; then wget -P download-cache https://github.com/openssl/openssl/releases/download/openssl-$OPENSSL_VER/openssl-$OPENSSL_VER.tar.gz || wget -P download-cache https://www.openssl.org/source/openssl-$OPENSSL_VER.tar.gz || wget -P download-cache https://www.openssl.org/source/old/${OPENSSL_VER//[a-z]/}/openssl-$OPENSSL_VER.tar.gz; fi - - if [ -n "$OPENSSL_VER" ]; then wget https://github.com/openresty/openresty-deps-prebuild/releases/download/v1.0.0/openssl-${OPENSSL_VER}-x64-focal.tar.gz; fi - - if [ -n "$PCRE_VER" ]; then wget https://github.com/openresty/openresty-deps-prebuild/releases/download/v1.0.0/pcre-${PCRE_VER}-x64-focal.tar.gz; fi - - if [ -n "$PCRE2_VER" ]; then wget https://github.com/openresty/openresty-deps-prebuild/releases/download/v1.0.0/pcre2-${PCRE2_VER}-x64-focal.tar.gz; fi - wget https://github.com/openresty/openresty-deps-prebuild/releases/download/v20230902/boringssl-20230902-x64-focal.tar.gz - wget https://github.com/openresty/openresty-deps-prebuild/releases/download/v20230902/curl-h3-x64-focal.tar.gz - git clone https://github.com/openresty/test-nginx.git @@ -137,13 +135,9 @@ script: - sudo make install-libdrizzle-1.0 > build.log 2>&1 || (cat build.log && exit 1) - cd ../mockeagain/ && make CC=$CC -j$JOBS && cd .. - cd lua-cjson/ && make -j$JOBS && sudo make install && cd .. - #- if [ -n "PCRE_VER" ]; then tar zxf download-cache/pcre-$PCRE_VER.tar.gz; cd pcre-$PCRE_VER/; ./configure --prefix=$PCRE_PREFIX --enable-jit --enable-utf --enable-unicode-properties > build.log 2>&1 || (cat build.log && exit 1); make -j$JOBS > build.log 2>&1 || (cat build.log && exit 1); sudo PATH=$PATH make install > build.log 2>&1 || (cat build.log && exit 1); cd ..; fi #- if [ -n "$PCRE2_VER" ]; then tar zxf download-cache/pcre2-$PCRE2_VER.tar.gz; cd pcre2-$PCRE2_VER/; ./configure --prefix=$PCRE2_PREFIX --enable-jit --enable-utf > build.log 2>&1 || (cat build.log && exit 1); make -j$JOBS > build.log 2>&1 || (cat build.log && exit 1); sudo PATH=$PATH make install > build.log 2>&1 || (cat build.log && exit 1); cd ..; fi #- if [ -n "$OPENSSL_VER" ]; then tar zxf download-cache/openssl-$OPENSSL_VER.tar.gz; cd openssl-$OPENSSL_VER/; patch -p1 < ../../openresty/patches/openssl-$OPENSSL_PATCH_VER-sess_set_get_cb_yield.patch; ./config shared enable-ssl3 enable-ssl3-method -g --prefix=$OPENSSL_PREFIX --libdir=lib -DPURIFY > build.log 2>&1 || (cat build.log && exit 1); make -j$JOBS > build.log 2>&1 || (cat build.log && exit 1); sudo make PATH=$PATH install_sw > build.log 2>&1 || (cat build.log && exit 1); cd ..; fi - - if [ -n "$BORINGSSL" ]; then sudo mkdir -p /opt/ssl && sudo tar -C /opt/ssl -xf boringssl-20230902-x64-focal.tar.gz --strip-components=1; fi - - if [ -n "$OPENSSL_VER" ]; then sudo mkdir -p /opt/ssl && sudo tar -C /opt/ssl -xf openssl-$OPENSSL_VER-x64-focal.tar.gz --strip-components=2; fi - - if [ -n "$PCRE_VER" ]; then sudo mkdir -p $PCRE_PREFIX && sudo tar -C $PCRE_PREFIX -xf pcre-$PCRE_VER-x64-focal.tar.gz --strip-components=2; fi - - if [ -n "$PCRE2_VER" ]; then sudo mkdir -p $PCRE2_PREFIX && sudo tar -C $PCRE2_PREFIX -xf pcre2-$PCRE2_VER-x64-focal.tar.gz --strip-components=2; fi + - if [ -n "$BORINGSSL" ]; then sudo rm -fr /usr/local/openresty/openssl3/ && sudo tar -C /usr/local/openresty/openssl3 -xf boringssl-20230902-x64-focal.tar.gz --strip-components=1; fi - export NGX_BUILD_CC=$CC - sh util/build-without-ssl.sh $NGINX_VERSION > build.log 2>&1 || (cat build.log && exit 1) - sh util/build-with-dd.sh $NGINX_VERSION > build.log 2>&1 || (cat build.log && exit 1) @@ -160,4 +154,4 @@ script: - dig +short myip.opendns.com @resolver1.opendns.com || exit 0 - dig +short @$TEST_NGINX_RESOLVER openresty.org || exit 0 - dig +short @$TEST_NGINX_RESOLVER agentzh.org || exit 0 - - /usr/bin/env perl $(command -v prove) -I. -Itest-nginx/lib -r t/ + - /usr/bin/env perl $(command -v prove) -I. -Itest-nginx/inc -Itest-nginx/lib -r t/ diff --git a/t/143-ssl-session-fetch.t b/t/143-ssl-session-fetch.t index 8e09a52d64..8c7c156ede 100644 --- a/t/143-ssl-session-fetch.t +++ b/t/143-ssl-session-fetch.t @@ -142,7 +142,7 @@ ssl_session_fetch_by_lua\(nginx\.conf:25\):1: ssl fetch sess by lua is running!, server_tokens off; resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; - lua_ssl_protocols TLSv1 TLSv1.1 TLSV1.2; + lua_ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -199,6 +199,7 @@ qr/elapsed in ssl fetch session by lua: 0.(?:09|1[01])\d+,/, [error] [alert] [emerg] +--- skip_openssl: 6: > 1.1.1w @@ -388,6 +389,7 @@ qr/received memc reply: OK/s [alert] [error] [emerg] +--- skip_openssl: 6: > 1.1.1w @@ -635,6 +637,7 @@ qr/ssl_session_fetch_by_lua\*: sess get cb exit code: 0/s should never reached here [alert] [emerg] +--- skip_openssl: 6: > 1.1.1w @@ -804,6 +807,7 @@ ssl_session_fetch_by_lua*: sess get cb exit code: 0 should never reached here [alert] [emerg] +--- skip_openssl: 6: > 1.1.1w @@ -991,6 +995,7 @@ ssl store session by lua is running! [error] [alert] [emerg] +--- skip_openssl: 6: > 1.1.1w @@ -1399,6 +1404,7 @@ qr/elapsed in ssl_session_fetch_by_lua\*: 0\.(?:09|1[01])\d+,/, [error] [alert] [emerg] +--- skip_openssl: 6: > 1.1.1w @@ -1494,6 +1500,7 @@ close: 1 nil [alert] [error] [emerg] +--- skip_openssl: 6: > 1.1.1w @@ -1695,3 +1702,4 @@ uthread: failed to kill: already waited or killed [alert] [error] [emerg] +--- skip_openssl: 6: > 1.1.1w diff --git a/util/build-with-dd.sh b/util/build-with-dd.sh index a56a89119b..92ca6da328 100755 --- a/util/build-with-dd.sh +++ b/util/build-with-dd.sh @@ -12,30 +12,13 @@ force=$2 add_fake_shm_module="--add-module=$root/t/data/fake-shm-module" -add_http3_module=--with-http_v3_module -answer=`$root/util/ver-ge "$NGINX_VERSION" 1.25.1` -if [ "$OPENSSL_VER" = "1.1.0l" ] || [ "$answer" = "N" ]; then - add_http3_module="" -fi - -disable_pcre2=--without-pcre2 -answer=`$root/util/ver-ge "$NGINX_VERSION" 1.25.1` -if [ "$answer" = "N" ] || [ "$USE_PCRE2" = "Y" ]; then - disable_pcre2="" -fi -if [ "$USE_PCRE2" = "Y" ]; then - PCRE_INC=$PCRE2_INC - PCRE_LIB=$PCRE2_LIB -fi - time ngx-build $force $version \ --with-threads \ --with-pcre-jit \ - $disable_pcre2 \ --with-ipv6 \ --with-cc-opt="-DNGX_LUA_USE_ASSERT -I$PCRE_INC -I$OPENSSL_INC -DDDEBUG=1" \ --with-http_v2_module \ - $add_http3_module \ + --with-http_v3_module \ --with-http_realip_module \ --with-http_ssl_module \ --add-module=$root/../ndk-nginx-module \ diff --git a/util/build-without-ssl.sh b/util/build-without-ssl.sh index 2a998e3c79..0bab08c8b6 100755 --- a/util/build-without-ssl.sh +++ b/util/build-without-ssl.sh @@ -10,34 +10,12 @@ version=${1:-1.4.1} home=~ force=$2 -# the ngx-build script is from https://github.com/agentzh/nginx-devel-utils - - #--add-module=$home/work/nginx_upload_module-2.2.0 \ - - #--without-pcre \ - #--without-http_rewrite_module \ - #--without-http_autoindex_module \ - #--with-cc=gcc46 \ - #--with-cc=clang \ - #--without-http_referer_module \ - #--with-http_spdy_module \ - add_fake_shm_module="--add-module=$root/t/data/fake-shm-module" -disable_pcre2=--without-pcre2 -answer=`$root/util/ver-ge "$NGINX_VERSION" 1.25.1` -if [ "$answer" = "N" ] || [ -n "$PCRE2_VER" ]; then - disable_pcre2="" -fi -if [ -n "$PCRE2_VER" ]; then - PCRE_INC=$PCRE2_INC - PCRE_LIB=$PCRE2_LIB -fi - +rm -fr buildroot time ngx-build $force $version \ --with-threads \ --with-pcre-jit \ - $disable_pcre2 \ --with-ipv6 \ --with-cc-opt="-DNGX_LUA_USE_ASSERT -I$PCRE_INC" \ --with-http_v2_module \ diff --git a/util/build.sh b/util/build.sh index fdf5c4d53d..a901c03cd3 100755 --- a/util/build.sh +++ b/util/build.sh @@ -30,20 +30,11 @@ if [ "$OPENSSL_VER" = "1.1.0l" ] || [ "$answer" = "N" ]; then add_http3_module="" fi -disable_pcre2=--without-pcre2 answer=`$root/util/ver-ge "$version" 1.25.1` -if [ "$answer" = "N" ] || [ "$USE_PCRE2" = "Y" ]; then - disable_pcre2="" -fi -if [ "$USE_PCRE2" = "Y" ]; then - PCRE_INC=$PCRE2_INC - PCRE_LIB=$PCRE2_LIB -fi time ngx-build $force $version \ --with-threads \ --with-pcre-jit \ - $disable_pcre2 \ --with-ipv6 \ --with-cc-opt="-DNGX_LUA_USE_ASSERT -I$PCRE_INC -I$OPENSSL_INC" \ --with-http_v2_module \ From 4e40c1314f316e5ba4bf538213a2312daa950a8a Mon Sep 17 00:00:00 2001 From: lijunlong Date: Sat, 21 Jun 2025 17:14:40 +0800 Subject: [PATCH 226/254] tests: update openssl to 3.5.0. --- .travis.yml | 12 +++--- t/014-bugs.t | 12 +++--- util/build-with-dd.sh | 4 +- util/build-without-ssl.sh | 4 +- util/build.sh | 82 ++++++++++++++++++--------------------- 5 files changed, 54 insertions(+), 60 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8eb5abd914..b65a9d528f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -46,9 +46,9 @@ env: - LUAJIT_LIB=$LUAJIT_PREFIX/lib - LUAJIT_INC=$LUAJIT_PREFIX/include/luajit-2.1 - LUA_INCLUDE_DIR=$LUAJIT_INC - - PCRE_PREFIX=/usr/local/openresty/pcre2 - - PCRE_LIB=$PCRE_PREFIX/lib - - PCRE_INC=$PCRE_PREFIX/include + - PCRE2_PREFIX=/usr/local/openresty/pcre2 + - PCRE2_LIB=$PCRE2_PREFIX/lib + - PCRE2_INC=$PCRE2_PREFIX/include - OPENSSL_PREFIX=/usr/local/openresty/openssl3 - OPENSSL_LIB=$OPENSSL_PREFIX/lib - OPENSSL_INC=$OPENSSL_PREFIX/include @@ -60,9 +60,9 @@ env: - TEST_NGINX_SLEEP=0.006 - MALLOC_PERTURB_=9 jobs: - - NGINX_VERSION=1.27.1 OPENSSL_VER=3.4.1 OPENSSL_PATCH_VER=3.4.1 TEST_NGINX_TIMEOUT=5 PCRE2_VER=10.45 - - NGINX_VERSION=1.27.1 OPENSSL_VER=3.4.1 OPENSSL_PATCH_VER=3.4.1 TEST_NGINX_TIMEOUT=5 PCRE2_VER=10.45 TEST_NGINX_USE_HTTP2=1 - - NGINX_VERSION=1.27.1 OPENSSL_VER=3.4.1 OPENSSL_PATCH_VER=3.4.1 TEST_NGINX_USE_HTTP3=1 TEST_NGINX_QUIC_IDLE_TIMEOUT=3 PCRE2_VER=10.45 + - NGINX_VERSION=1.27.1 OPENSSL_VER=3.5.0 OPENSSL_PATCH_VER=3.5.0 TEST_NGINX_TIMEOUT=5 PCRE2_VER=10.45 + - NGINX_VERSION=1.27.1 OPENSSL_VER=3.5.0 OPENSSL_PATCH_VER=3.5.0 TEST_NGINX_TIMEOUT=5 PCRE2_VER=10.45 TEST_NGINX_USE_HTTP2=1 + - NGINX_VERSION=1.27.1 OPENSSL_VER=3.5.0 OPENSSL_PATCH_VER=3.5.0 TEST_NGINX_USE_HTTP3=1 TEST_NGINX_QUIC_IDLE_TIMEOUT=3 PCRE2_VER=10.45 - NGINX_VERSION=1.27.1 BORINGSSL=1 TEST_NGINX_USE_HTTP3=1 TEST_NGINX_QUIC_IDLE_TIMEOUT=3 PCRE2_VER=10.45 services: diff --git a/t/014-bugs.t b/t/014-bugs.t index 9d57afe134..a89efec3c1 100644 --- a/t/014-bugs.t +++ b/t/014-bugs.t @@ -1274,9 +1274,9 @@ worker_shutdown_timeout 1; --- config location /t { content_by_lua_block { - local function thread_func() + local function thread_func(port) local sock = ngx.socket.tcp() - local ok, err = sock:connect("127.0.0.1", 65110) + local ok, err = sock:connect("127.0.0.1", port) local bytes, err = sock:send("hello") if bytes ~= 5 then sock:close() @@ -1293,11 +1293,11 @@ location /t { ngx.log(ngx.ERR, "successfully read a line: ", line) end - local function timer_func() - ngx.thread.spawn(thread_func) + local function timer_func(port) + ngx.thread.spawn(thread_func, port) end - ngx.timer.at(1, timer_func) + ngx.timer.at(1, timer_func, ngx.var.server_port) ngx.say("Hello world") } } @@ -1311,7 +1311,7 @@ my $expr; if ($ENV{TEST_NGINX_USE_HTTP3}) { $expr = qr|lua close the global Lua VM| } else { - $expr = qr|failed to read a line: closed| + $expr = qr/failed to read a line: closed|attempt to send data on a closed socket/ } $expr; diff --git a/util/build-with-dd.sh b/util/build-with-dd.sh index 92ca6da328..4f4e785f53 100755 --- a/util/build-with-dd.sh +++ b/util/build-with-dd.sh @@ -16,14 +16,14 @@ time ngx-build $force $version \ --with-threads \ --with-pcre-jit \ --with-ipv6 \ - --with-cc-opt="-DNGX_LUA_USE_ASSERT -I$PCRE_INC -I$OPENSSL_INC -DDDEBUG=1" \ + --with-cc-opt="-DNGX_LUA_USE_ASSERT -I$PCRE2_INC -I$OPENSSL_INC -DDDEBUG=1" \ --with-http_v2_module \ --with-http_v3_module \ --with-http_realip_module \ --with-http_ssl_module \ --add-module=$root/../ndk-nginx-module \ --add-module=$root/../set-misc-nginx-module \ - --with-ld-opt="-L$PCRE_LIB -L$OPENSSL_LIB -Wl,-rpath,$PCRE_LIB:$LIBDRIZZLE_LIB:$OPENSSL_LIB" \ + --with-ld-opt="-L$PCRE2_LIB -L$OPENSSL_LIB -Wl,-rpath,$PCRE2_LIB:$LIBDRIZZLE_LIB:$OPENSSL_LIB" \ --without-mail_pop3_module \ --without-mail_imap_module \ --with-http_image_filter_module \ diff --git a/util/build-without-ssl.sh b/util/build-without-ssl.sh index 0bab08c8b6..022d9617e2 100755 --- a/util/build-without-ssl.sh +++ b/util/build-without-ssl.sh @@ -17,12 +17,12 @@ time ngx-build $force $version \ --with-threads \ --with-pcre-jit \ --with-ipv6 \ - --with-cc-opt="-DNGX_LUA_USE_ASSERT -I$PCRE_INC" \ + --with-cc-opt="-DNGX_LUA_USE_ASSERT -I$PCRE2_INC" \ --with-http_v2_module \ --with-http_realip_module \ --add-module=$root/../ndk-nginx-module \ --add-module=$root/../set-misc-nginx-module \ - --with-ld-opt="-L$PCRE_LIB -Wl,-rpath,$PCRE_LIB:$LIBDRIZZLE_LIB" \ + --with-ld-opt="-L$PCRE2_LIB -Wl,-rpath,$PCRE2_LIB:$LIBDRIZZLE_LIB" \ --without-mail_pop3_module \ --without-mail_imap_module \ --with-http_image_filter_module \ diff --git a/util/build.sh b/util/build.sh index a901c03cd3..9dda855223 100755 --- a/util/build.sh +++ b/util/build.sh @@ -24,53 +24,47 @@ force=$2 add_fake_shm_module="--add-module=$root/t/data/fake-shm-module" -add_http3_module=--with-http_v3_module -answer=`$root/util/ver-ge "$version" 1.25.1` -if [ "$OPENSSL_VER" = "1.1.0l" ] || [ "$answer" = "N" ]; then - add_http3_module="" -fi - answer=`$root/util/ver-ge "$version" 1.25.1` time ngx-build $force $version \ - --with-threads \ - --with-pcre-jit \ - --with-ipv6 \ - --with-cc-opt="-DNGX_LUA_USE_ASSERT -I$PCRE_INC -I$OPENSSL_INC" \ - --with-http_v2_module \ - $add_http3_module \ - --with-http_realip_module \ - --with-http_ssl_module \ - --add-module=$root/../ndk-nginx-module \ - --add-module=$root/../set-misc-nginx-module \ - --with-ld-opt="-L$PCRE_LIB -L$OPENSSL_LIB -Wl,-rpath,$PCRE_LIB:$LIBDRIZZLE_LIB:$OPENSSL_LIB" \ - --without-mail_pop3_module \ - --without-mail_imap_module \ - --with-http_image_filter_module \ - --without-mail_smtp_module \ - --with-stream \ - --with-stream_ssl_module \ - --without-http_upstream_ip_hash_module \ - --without-http_memcached_module \ - --without-http_auth_basic_module \ - --without-http_userid_module \ - --with-http_auth_request_module \ - --add-module=$root/../echo-nginx-module \ - --add-module=$root/../memc-nginx-module \ - --add-module=$root/../srcache-nginx-module \ - --add-module=$root \ - --add-module=$root/../lua-upstream-nginx-module \ - --add-module=$root/../headers-more-nginx-module \ - --add-module=$root/../drizzle-nginx-module \ - --add-module=$root/../rds-json-nginx-module \ - --add-module=$root/../coolkit-nginx-module \ - --add-module=$root/../redis2-nginx-module \ - --add-module=$root/../stream-lua-nginx-module \ - --add-module=$root/t/data/fake-module \ - $add_fake_shm_module \ - --add-module=$root/t/data/fake-delayed-load-module \ - --with-http_gunzip_module \ - --with-http_dav_module \ + --with-threads \ + --with-pcre-jit \ + --with-ipv6 \ + --with-cc-opt="-DNGX_LUA_USE_ASSERT -I$PCRE2_INC -I$OPENSSL_INC" \ + --with-http_v2_module \ + --with-http_v3_module \ + --with-http_realip_module \ + --with-http_ssl_module \ + --add-module=$root/../ndk-nginx-module \ + --add-module=$root/../set-misc-nginx-module \ + --with-ld-opt="-L$PCRE2_LIB -L$OPENSSL_LIB -Wl,-rpath,$PCRE2_LIB:$LIBDRIZZLE_LIB:$OPENSSL_LIB" \ + --without-mail_pop3_module \ + --without-mail_imap_module \ + --with-http_image_filter_module \ + --without-mail_smtp_module \ + --with-stream \ + --with-stream_ssl_module \ + --without-http_upstream_ip_hash_module \ + --without-http_memcached_module \ + --without-http_auth_basic_module \ + --without-http_userid_module \ + --with-http_auth_request_module \ + --add-module=$root/../echo-nginx-module \ + --add-module=$root/../memc-nginx-module \ + --add-module=$root/../srcache-nginx-module \ + --add-module=$root \ + --add-module=$root/../lua-upstream-nginx-module \ + --add-module=$root/../headers-more-nginx-module \ + --add-module=$root/../drizzle-nginx-module \ + --add-module=$root/../rds-json-nginx-module \ + --add-module=$root/../coolkit-nginx-module \ + --add-module=$root/../redis2-nginx-module \ + --add-module=$root/../stream-lua-nginx-module \ + --add-module=$root/t/data/fake-module \ + $add_fake_shm_module \ + --add-module=$root/t/data/fake-delayed-load-module \ + --with-http_gunzip_module \ + --with-http_dav_module \ --with-select_module \ --with-poll_module \ $opts \ From 1793b3b88af4de1128db4ff7d30fe3e47a9e5459 Mon Sep 17 00:00:00 2001 From: swananan Date: Tue, 1 Jul 2025 11:48:33 +0800 Subject: [PATCH 227/254] bugfix: improve HTTP/3 SSL Lua callback yield handling. --- .travis.yml | 2 +- src/ngx_http_lua_ssl_certby.c | 12 +- src/ngx_http_lua_ssl_client_helloby.c | 17 +- src/ngx_http_lua_util.c | 79 ++- src/ngx_http_lua_util.h | 4 + t/139-ssl-cert-by.t | 448 +++++++++++++- t/143-ssl-session-fetch.t | 9 +- t/166-ssl-client-hello.t | 822 +++++++++++++++++++++++++- 8 files changed, 1371 insertions(+), 22 deletions(-) diff --git a/.travis.yml b/.travis.yml index b65a9d528f..f48c9a75bc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -137,7 +137,7 @@ script: - cd lua-cjson/ && make -j$JOBS && sudo make install && cd .. #- if [ -n "$PCRE2_VER" ]; then tar zxf download-cache/pcre2-$PCRE2_VER.tar.gz; cd pcre2-$PCRE2_VER/; ./configure --prefix=$PCRE2_PREFIX --enable-jit --enable-utf > build.log 2>&1 || (cat build.log && exit 1); make -j$JOBS > build.log 2>&1 || (cat build.log && exit 1); sudo PATH=$PATH make install > build.log 2>&1 || (cat build.log && exit 1); cd ..; fi #- if [ -n "$OPENSSL_VER" ]; then tar zxf download-cache/openssl-$OPENSSL_VER.tar.gz; cd openssl-$OPENSSL_VER/; patch -p1 < ../../openresty/patches/openssl-$OPENSSL_PATCH_VER-sess_set_get_cb_yield.patch; ./config shared enable-ssl3 enable-ssl3-method -g --prefix=$OPENSSL_PREFIX --libdir=lib -DPURIFY > build.log 2>&1 || (cat build.log && exit 1); make -j$JOBS > build.log 2>&1 || (cat build.log && exit 1); sudo make PATH=$PATH install_sw > build.log 2>&1 || (cat build.log && exit 1); cd ..; fi - - if [ -n "$BORINGSSL" ]; then sudo rm -fr /usr/local/openresty/openssl3/ && sudo tar -C /usr/local/openresty/openssl3 -xf boringssl-20230902-x64-focal.tar.gz --strip-components=1; fi + - if [ -n "$BORINGSSL" ]; then sudo rm -fr /usr/local/openresty/openssl3/ && sudo mkdir -p /usr/local/openresty/openssl3 && sudo tar -C /usr/local/openresty/openssl3 -xf boringssl-20230902-x64-focal.tar.gz --strip-components=1; fi - export NGX_BUILD_CC=$CC - sh util/build-without-ssl.sh $NGINX_VERSION > build.log 2>&1 || (cat build.log && exit 1) - sh util/build-with-dd.sh $NGINX_VERSION > build.log 2>&1 || (cat build.log && exit 1) diff --git a/src/ngx_http_lua_ssl_certby.c b/src/ngx_http_lua_ssl_certby.c index 72a651bdbf..0c13af91c4 100644 --- a/src/ngx_http_lua_ssl_certby.c +++ b/src/ngx_http_lua_ssl_certby.c @@ -346,7 +346,6 @@ ngx_http_lua_ssl_cert_handler(ngx_ssl_conn_t *ssl_conn, void *data) return -1; -#if 1 failed: if (r && r->pool) { @@ -358,15 +357,14 @@ ngx_http_lua_ssl_cert_handler(ngx_ssl_conn_t *ssl_conn, void *data) } return 0; -#endif } static void ngx_http_lua_ssl_cert_done(void *data) { - ngx_connection_t *c; - ngx_http_lua_ssl_ctx_t *cctx = data; + ngx_connection_t *c; + ngx_http_lua_ssl_ctx_t *cctx = data; dd("lua ssl cert done"); @@ -387,6 +385,12 @@ ngx_http_lua_ssl_cert_done(void *data) c->log->action = "SSL handshaking"; ngx_post_event(c->write, &ngx_posted_events); + +#if (NGX_HTTP_V3) && OPENSSL_VERSION_NUMBER >= 0x1000205fL +# if (NGX_QUIC_OPENSSL_COMPAT) + ngx_http_lua_resume_quic_ssl_handshake(c); +# endif +#endif } diff --git a/src/ngx_http_lua_ssl_client_helloby.c b/src/ngx_http_lua_ssl_client_helloby.c index b92fc46b5d..b4377f2f1b 100644 --- a/src/ngx_http_lua_ssl_client_helloby.c +++ b/src/ngx_http_lua_ssl_client_helloby.c @@ -341,7 +341,6 @@ ngx_http_lua_ssl_client_hello_handler(ngx_ssl_conn_t *ssl_conn, return -1; -#if 1 failed: if (r && r->pool) { @@ -353,15 +352,14 @@ ngx_http_lua_ssl_client_hello_handler(ngx_ssl_conn_t *ssl_conn, } return 0; -#endif } static void ngx_http_lua_ssl_client_hello_done(void *data) { - ngx_connection_t *c; - ngx_http_lua_ssl_ctx_t *cctx = data; + ngx_connection_t *c; + ngx_http_lua_ssl_ctx_t *cctx = data; dd("lua ssl client hello done"); @@ -382,6 +380,12 @@ ngx_http_lua_ssl_client_hello_done(void *data) c->log->action = "SSL handshaking"; ngx_post_event(c->write, &ngx_posted_events); + +#if (NGX_HTTP_V3) && defined(SSL_ERROR_WANT_CLIENT_HELLO_CB) +# if (NGX_QUIC_OPENSSL_COMPAT) + ngx_http_lua_resume_quic_ssl_handshake(c); +# endif +#endif } @@ -666,6 +670,7 @@ int ngx_http_lua_ffi_ssl_get_client_hello_ext_present(ngx_http_request_t *r, int **extensions, size_t *extensions_len, char **err) { +#ifdef SSL_ERROR_WANT_CLIENT_HELLO_CB ngx_ssl_conn_t *ssl_conn; int got_extensions; size_t ext_len; @@ -684,7 +689,6 @@ ngx_http_lua_ffi_ssl_get_client_hello_ext_present(ngx_http_request_t *r, return NGX_ERROR; } -#ifdef SSL_ERROR_WANT_CLIENT_HELLO_CB got_extensions = SSL_client_hello_get1_extensions_present(ssl_conn, &ext_out, &ext_len); if (!got_extensions || !ext_out || !ext_len) { @@ -710,6 +714,7 @@ ngx_http_lua_ffi_ssl_get_client_hello_ext_present(ngx_http_request_t *r, int ngx_http_lua_ffi_ssl_get_client_hello_ciphers(ngx_http_request_t *r, unsigned short *ciphers, size_t ciphers_size, char **err) { +#ifdef SSL_ERROR_WANT_CLIENT_HELLO_CB int i; size_t ciphers_cnt; size_t ciphersuites_bytes; @@ -727,8 +732,6 @@ int ngx_http_lua_ffi_ssl_get_client_hello_ciphers(ngx_http_request_t *r, return NGX_ERROR; } - -#ifdef SSL_ERROR_WANT_CLIENT_HELLO_CB ciphersuites_bytes = SSL_client_hello_get0_ciphers(ssl_conn, &ciphers_raw); if (ciphersuites_bytes == 0) { diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 61f56cb7c0..d47c691000 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -49,6 +49,10 @@ #if (NGX_THREADS) #include "ngx_http_lua_worker_thread.h" #endif +#if (NGX_HTTP_V3) +#include +#include +#endif #if 1 @@ -3826,6 +3830,18 @@ ngx_http_lua_close_fake_connection(ngx_connection_t *c) c->read->closed = 1; c->write->closed = 1; + /* When destroying the pool, the registered clean callbacks will be + * executed. If the ngx_connection_t is freed before these callbacks are + * run, and a new ngx_connection_t is created within a clean callback, + * it is possible for the freed ngx_connection_t to be reused again. + * If this reused ngx_connection_t is destroyed again within the clean + * callback logic, it may result in other clean callbacks holding a + * ngx_connection_t that has already been destroyed. + */ + if (pool) { + ngx_destroy_pool(pool); + } + /* we temporarily use a valid fd (0) to make ngx_free_connection happy */ c->fd = 0; @@ -3841,10 +3857,6 @@ ngx_http_lua_close_fake_connection(ngx_connection_t *c) if (ngx_cycle->files) { ngx_cycle->files[0] = saved_c; } - - if (pool) { - ngx_destroy_pool(pool); - } } @@ -4561,4 +4573,63 @@ ngx_http_lua_ffi_bypass_if_checks(ngx_http_request_t *r) r->disable_not_modified = 1; } + +#if (NGX_HTTP_V3) +void +ngx_http_lua_resume_quic_ssl_handshake(ngx_connection_t *c) +{ + ngx_int_t rc, sslerr; + ngx_ssl_conn_t *ssl_conn; + + if (c == NULL || c->ssl == NULL || c->ssl->connection == NULL) { + return; + } + + if (!c->udp || c->read == NULL + || c->read->handler != ngx_quic_input_handler) + { + return; + } + + ssl_conn = c->ssl->connection; + + /* Openresty ssl lua scripts are triggered by registering callbacks into + * openssl. If a lua script calls a yield api during execution, openssl's + * SSL_do_handshake will return a specific error code. The application + * should not treat these codes as fatal. The lua script will resume on + * yield-related events until it finishes. After completion, + * SSL_do_handshake should be called again to advance openssl's state + * machine. + * + * Note that nginx quic and openresty ssl lua scripts are independent. When + * openresty ssl lua runs, the client is waiting for a server response, so + * nginx quic does not affect the execution of the lua script. After the lua + * script finishes, SSL_do_handshake is called again, and nginx quic's + * registered callback continues the handshake. + */ + rc = SSL_do_handshake(ssl_conn); + sslerr = SSL_get_error(ssl_conn, rc); + + if (rc <= 0 && sslerr != SSL_ERROR_WANT_READ +#if OPENSSL_VERSION_NUMBER >= 0x10002000L + && sslerr != SSL_ERROR_WANT_X509_LOOKUP +#endif +#ifdef SSL_ERROR_WANT_CLIENT_HELLO_CB + && sslerr != SSL_ERROR_WANT_CLIENT_HELLO_CB +#endif + ) { + /* If a fatal error occurs or lua script exits with error during quic + * handshake, the quic connection will be closed immediately. + */ + ngx_quic_close_connection(c, NGX_ERROR); + + } else { + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, + "lua resuming quic ssl handshake: rc %d, err %d, will " + "continue driving handshake or next lua script phase", + rc, sslerr); + } +} +#endif + /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_util.h b/src/ngx_http_lua_util.h index 85c6e614d6..d76508868c 100644 --- a/src/ngx_http_lua_util.h +++ b/src/ngx_http_lua_util.h @@ -267,6 +267,10 @@ ngx_addr_t *ngx_http_lua_parse_addr(lua_State *L, u_char *text, size_t len); size_t ngx_http_lua_escape_log(u_char *dst, u_char *src, size_t size); +#if (NGX_HTTP_V3) +void ngx_http_lua_resume_quic_ssl_handshake(ngx_connection_t *c); +#endif + static ngx_inline void ngx_http_lua_init_ctx(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx) diff --git a/t/139-ssl-cert-by.t b/t/139-ssl-cert-by.t index abf447856d..c5b1665046 100644 --- a/t/139-ssl-cert-by.t +++ b/t/139-ssl-cert-by.t @@ -7,6 +7,9 @@ repeat_each(3); # All these tests need to have new openssl my $NginxBinary = $ENV{'TEST_NGINX_BINARY'} || 'nginx'; my $openssl_version = eval { `$NginxBinary -V 2>&1` }; +if ($openssl_version =~ m/BoringSSL/) { + $ENV{TEST_NGINX_USE_BORINGSSL} = 1; +} if ($openssl_version =~ m/built with OpenSSL (0|1\.0\.(?:0|1[^\d]|2[a-d]).*)/) { plan(skip_all => "too old OpenSSL, need 1.0.2e, was $1"); @@ -16,6 +19,7 @@ if ($openssl_version =~ m/built with OpenSSL (0|1\.0\.(?:0|1[^\d]|2[a-d]).*)/) { $ENV{TEST_NGINX_HTML_DIR} ||= html_dir(); $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; +$ENV{TEST_NGINX_QUIC_IDLE_TIMEOUT} ||= 0.6; #log_level 'warn'; log_level 'debug'; @@ -2075,7 +2079,7 @@ received: foo close: 1 nil --- error_log -client socket file: +client socket file: --- no_error_log [error] @@ -2321,3 +2325,445 @@ ssl handshake: cdata uthread: hello from f() uthread: killed uthread: failed to kill: already waited or killed + + + +=== TEST 27: ssl_certificate_by_lua* with TCP cosocket (yield API) +--- skip_eval: 6:!$ENV{TEST_NGINX_USE_HTTP3} || $ENV{TEST_NGINX_USE_BORINGSSL} +--- config + server_tokens off; + lua_ssl_trusted_certificate ../../cert/test.crt; + lua_ssl_verify_depth 3; + + ssl_certificate_by_lua_block { + print("ssl certificate: TCP cosocket test start") + + local sock = ngx.socket.tcp() + sock:settimeout(2000) + + local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_MEMCACHED_PORT) + if not ok then + ngx.log(ngx.ERR, "failed to connect to memc: ", err) + return + end + + local bytes, err = sock:send("flush_all\r\n") + if not bytes then + ngx.log(ngx.ERR, "failed to send flush_all command: ", err) + return + end + + local res, err = sock:receive() + if not res then + ngx.log(ngx.ERR, "failed to receive memc reply: ", err) + return + end + + print("ssl certificate: received TCP memc reply: ", res) + sock:close() + print("ssl certificate: TCP cosocket test done") + } + + location /t { + content_by_lua_block { + print("test completed") + ngx.say("test completed") + } + } +--- request +GET /t +--- response_body +test completed + +--- grep_error_log eval: qr/(ssl certificate: TCP cosocket test start|ssl certificate: received TCP memc reply: OK|ssl certificate: TCP cosocket test done|test completed)/ +--- grep_error_log_out +ssl certificate: TCP cosocket test start +ssl certificate: received TCP memc reply: OK +ssl certificate: TCP cosocket test done +test completed + +--- no_error_log +[error] +[alert] +[emerg] + + + +=== TEST 28: ssl_certificate_by_lua* with UDP cosocket (yield API) +--- skip_eval: 6:!$ENV{TEST_NGINX_USE_HTTP3} || $ENV{TEST_NGINX_USE_BORINGSSL} +--- config + server_tokens off; + lua_ssl_trusted_certificate ../../cert/test.crt; + lua_ssl_verify_depth 3; + + ssl_certificate_by_lua_block { + print("ssl certificate: UDP cosocket test start") + + local sock = ngx.socket.udp() + sock:settimeout(1000) + + local ok, err = sock:setpeername("127.0.0.1", $TEST_NGINX_MEMCACHED_PORT) + if not ok then + ngx.log(ngx.ERR, "failed to connect to memc: ", err) + return + end + + local req = "\0\1\0\0\0\1\0\0flush_all\r\n" + local ok, err = sock:send(req) + if not ok then + ngx.log(ngx.ERR, "failed to send flush_all to memc: ", err) + return + end + + local res, err = sock:receive() + if not res then + ngx.log(ngx.ERR, "failed to receive memc reply: ", err) + return + end + + print("ssl certificate: received UDP memc reply of ", #res, " bytes") + sock:close() + print("ssl certificate: UDP cosocket test done") + } + + location /t { + content_by_lua_block { + print("test completed") + ngx.say("test completed") + } + } +--- request +GET /t +--- response_body +test completed + +--- grep_error_log eval: qr/(ssl certificate: UDP cosocket test start|ssl certificate: received UDP memc reply of \d+ bytes|ssl certificate: UDP cosocket test done|test completed)/ +--- grep_error_log_out eval +[ +qr/ssl certificate: UDP cosocket test start/, +qr/ssl certificate: received UDP memc reply of 12 bytes/, +qr/ssl certificate: UDP cosocket test done/, +qr/test completed/, +] + +--- no_error_log +[error] +[alert] +[emerg] + + + +=== TEST 29: ssl_certificate_by_lua* with ngx.timer (yield API) +--- skip_eval: 6:!$ENV{TEST_NGINX_USE_HTTP3} || $ENV{TEST_NGINX_USE_BORINGSSL} +--- config + server_tokens off; + lua_ssl_trusted_certificate ../../cert/test.crt; + lua_ssl_verify_depth 3; + + ssl_certificate_by_lua_block { + print("ssl certificate: timer test start") + + local function timer_handler() + print("ssl certificate: timer executed") + end + + local ok, err = ngx.timer.at(0, timer_handler) + if not ok then + ngx.log(ngx.ERR, "failed to create timer: ", err) + return + end + + print("ssl certificate: timer created") + print("ssl certificate: timer test done") + } + + location /t { + content_by_lua_block { + print("test completed") + ngx.say("test completed") + } + } +--- request +GET /t +--- response_body +test completed + +--- grep_error_log eval: qr/(ssl certificate: timer test start|ssl certificate: timer created|ssl certificate: timer test done|ssl certificate: timer executed|test completed)/ +--- grep_error_log_out +ssl certificate: timer test start +ssl certificate: timer created +ssl certificate: timer test done +ssl certificate: timer executed +test completed + +--- no_error_log +[error] +[alert] +[emerg] + + + +=== TEST 30: ssl_certificate_by_lua* with user threads (yield API) +--- skip_eval: 6:!$ENV{TEST_NGINX_USE_HTTP3} || $ENV{TEST_NGINX_USE_BORINGSSL} +--- config + server_tokens off; + lua_ssl_trusted_certificate ../../cert/test.crt; + lua_ssl_verify_depth 3; + + ssl_certificate_by_lua_block { + print("ssl certificate: uthread test start") + + local function worker() + ngx.sleep(0.01) + print("ssl certificate: uthread worker executed") + return "worker_result" + end + + local t, err = ngx.thread.spawn(worker) + if not t then + ngx.log(ngx.ERR, "failed to spawn thread: ", err) + return + end + + print("ssl certificate: uthread spawned") + + local ok, res = ngx.thread.wait(t) + if not ok then + ngx.log(ngx.ERR, "failed to wait thread: ", res) + return + end + + print("ssl certificate: uthread result: ", res) + print("ssl certificate: uthread test done") + } + + location /t { + content_by_lua_block { + print("test completed") + ngx.say("test completed") + } + } +--- request +GET /t +--- response_body +test completed + +--- grep_error_log eval: qr/(ssl certificate: uthread test start|ssl certificate: uthread spawned|ssl certificate: uthread worker executed|ssl certificate: uthread result: worker_result|ssl certificate: uthread test done|test completed)/ +--- grep_error_log_out +ssl certificate: uthread test start +ssl certificate: uthread spawned +ssl certificate: uthread worker executed +ssl certificate: uthread result: worker_result +ssl certificate: uthread test done +test completed + +--- no_error_log +[error] +[alert] +[emerg] + + + +=== TEST 31: ssl_certificate_by_lua* with coroutines (yield API) +--- skip_eval: 6:!$ENV{TEST_NGINX_USE_HTTP3} || $ENV{TEST_NGINX_USE_BORINGSSL} +--- config + server_tokens off; + lua_ssl_trusted_certificate ../../cert/test.crt; + lua_ssl_verify_depth 3; + + ssl_certificate_by_lua_block { + print("ssl certificate: coroutine test start") + + local cc, cr, cy = coroutine.create, coroutine.resume, coroutine.yield + + local function coro_func() + local cnt = 0 + for i = 1, 3 do + print("ssl certificate: coro yield: ", cnt) + cy() + cnt = cnt + 1 + end + return "coro_done" + end + + local c = cc(coro_func) + for i = 1, 4 do + print("ssl certificate: coro resume, status: ", coroutine.status(c)) + local ok, res = cr(c) + if not ok then + print("ssl certificate: coro error: ", res) + break + end + if coroutine.status(c) == "dead" then + print("ssl certificate: coro result: ", res) + break + end + end + + print("ssl certificate: coroutine test done") + } + + location /t { + content_by_lua_block { + print("test completed") + ngx.say("test completed") + } + } +--- request +GET /t +--- response_body +test completed + +--- grep_error_log eval: qr/(ssl certificate: coroutine test start|ssl certificate: coro resume, status: \w+|ssl certificate: coro yield: \d+|ssl certificate: coro result: coro_done|ssl certificate: coroutine test done|test completed)/ +--- grep_error_log_out +ssl certificate: coroutine test start +ssl certificate: coro resume, status: suspended +ssl certificate: coro yield: 0 +ssl certificate: coro resume, status: suspended +ssl certificate: coro yield: 1 +ssl certificate: coro resume, status: suspended +ssl certificate: coro yield: 2 +ssl certificate: coro resume, status: suspended +ssl certificate: coro result: coro_done +ssl certificate: coroutine test done +test completed + +--- no_error_log +[error] +[alert] +[emerg] + + + +=== TEST 32: ssl_certificate_by_lua* without yield API (simple logic) +--- skip_eval: 6:!$ENV{TEST_NGINX_USE_HTTP3} || $ENV{TEST_NGINX_USE_BORINGSSL} +--- config + server_tokens off; + lua_ssl_trusted_certificate ../../cert/test.crt; + lua_ssl_verify_depth 3; + + ssl_certificate_by_lua_block { + print("ssl certificate: simple test start") + + -- Simple calculations without yield + local sum = 0 + for i = 1, 10 do + sum = sum + i + end + + print("ssl certificate: calculated sum: ", sum) + + -- String operations + local str = "hello" + str = str .. " world" + print("ssl certificate: concatenated string: ", str) + + -- Table operations + local t = {a = 1, b = 2, c = 3} + local count = 0 + for k, v in pairs(t) do + count = count + v + end + print("ssl certificate: table sum: ", count) + + print("ssl certificate: simple test done") + } + + location /t { + content_by_lua_block { + print("test completed") + ngx.say("test completed") + } + } +--- request +GET /t +--- response_body +test completed + +--- grep_error_log eval: qr/(ssl certificate: simple test start|ssl certificate: calculated sum: 55|ssl certificate: concatenated string: hello world|ssl certificate: table sum: 6|ssl certificate: simple test done|test completed)/ +--- grep_error_log_out +ssl certificate: simple test start +ssl certificate: calculated sum: 55 +ssl certificate: concatenated string: hello world +ssl certificate: table sum: 6 +ssl certificate: simple test done +test completed + +--- no_error_log +[error] +[alert] +[emerg] + + + +=== TEST 33: ssl_certificate_by_lua* with multiple network operations (yield API) +--- skip_eval: 6:!$ENV{TEST_NGINX_USE_HTTP3} || $ENV{TEST_NGINX_USE_BORINGSSL} +--- config + server_tokens off; + lua_ssl_trusted_certificate ../../cert/test.crt; + lua_ssl_verify_depth 3; + + ssl_certificate_by_lua_block { + print("ssl certificate: multiple network test start") + + -- First TCP operation + local sock1 = ngx.socket.tcp() + sock1:settimeout(2000) + local ok, err = sock1:connect("127.0.0.1", $TEST_NGINX_MEMCACHED_PORT) + if ok then + local bytes, err = sock1:send("version\r\n") + if bytes then + local res, err = sock1:receive() + if res then + print("ssl certificate: TCP1 version: ", res) + end + end + sock1:close() + end + + ngx.sleep(0.01) -- Small delay + + -- Second UDP operation + local sock2 = ngx.socket.udp() + sock2:settimeout(1000) + local ok, err = sock2:setpeername("127.0.0.1", $TEST_NGINX_MEMCACHED_PORT) + if ok then + local req = "\0\1\0\0\0\1\0\0version\r\n" + local ok, err = sock2:send(req) + if ok then + local res, err = sock2:receive() + if res then + print("ssl certificate: UDP version reply length: ", #res) + end + end + sock2:close() + end + + print("ssl certificate: multiple network test done") + } + + location /t { + content_by_lua_block { + print("test completed") + ngx.say("test completed") + } + } +--- request +GET /t +--- response_body +test completed + +--- grep_error_log eval: qr/(ssl certificate: multiple network test start|ssl certificate: TCP1 version: VERSION|ssl certificate: UDP version reply length: \d+|ssl certificate: multiple network test done|test completed)/ +--- grep_error_log_out eval +[ +qr/ssl certificate: multiple network test start/, +qr/ssl certificate: TCP1 version: VERSION/, +qr/ssl certificate: UDP version reply length: \d+/, +qr/ssl certificate: multiple network test done/, +qr/test completed/, +] + +--- no_error_log +[error] +[alert] +[emerg] diff --git a/t/143-ssl-session-fetch.t b/t/143-ssl-session-fetch.t index 8c7c156ede..9cc1870a87 100644 --- a/t/143-ssl-session-fetch.t +++ b/t/143-ssl-session-fetch.t @@ -9,6 +9,12 @@ repeat_each(3); plan tests => repeat_each() * (blocks() * 6) - 3; +my $NginxBinary = $ENV{'TEST_NGINX_BINARY'} || 'nginx'; +my $openssl_version = eval { `$NginxBinary -V 2>&1` }; +if ($openssl_version =~ m/BoringSSL/) { + $ENV{TEST_NGINX_USE_BORINGSSL} = 1; +} + $ENV{TEST_NGINX_HTML_DIR} ||= html_dir(); $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; @@ -138,11 +144,12 @@ ssl_session_fetch_by_lua\(nginx\.conf:25\):1: ssl fetch sess by lua is running!, server_tokens off; } +--- skip_eval: 6:$ENV{TEST_NGINX_USE_BORINGSSL} --- config server_tokens off; resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; - lua_ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; + lua_ssl_protocols TLSv1 TLSv1.1 TLSV1.2 TLSv1.3; location /t { set $port $TEST_NGINX_MEMCACHED_PORT; diff --git a/t/166-ssl-client-hello.t b/t/166-ssl-client-hello.t index a356b6eeaa..680011d091 100644 --- a/t/166-ssl-client-hello.t +++ b/t/166-ssl-client-hello.t @@ -12,12 +12,15 @@ if ($openssl_version =~ m/built with OpenSSL (0\S*|1\.0\S*|1\.1\.0\S*)/) { plan(skip_all => "too old OpenSSL, need 1.1.1, was $1"); } elsif ($openssl_version =~ m/running with BoringSSL/) { plan(skip_all => "does not support BoringSSL"); +} elsif ($ENV{TEST_NGINX_USE_HTTP3}) { + plan tests => repeat_each() * (blocks() * 6 + 6); } else { - plan tests => repeat_each() * (blocks() * 6 + 8); + plan tests => repeat_each() * (blocks() * 6 + 10); } $ENV{TEST_NGINX_HTML_DIR} ||= html_dir(); $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; +$ENV{TEST_NGINX_QUIC_IDLE_TIMEOUT} ||= 0.6; #log_level 'warn'; log_level 'debug'; @@ -1667,11 +1670,11 @@ ssl client hello by lua is running! === TEST 20: use ssl_client_hello_by_lua* on the http {} level with non-ssl server --- http_config - ssl_client_hello_by_lua_block { print("ssl client hello by lua is running!") } ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock; + ssl_client_hello_by_lua_block { print("ssl client hello by lua is running!") } server_name test.com; server_tokens off; location /foo { @@ -1743,7 +1746,6 @@ close: 1 nil ssl client hello by lua is running! [error] [alert] ---- skip_eval: 5:$ENV{TEST_NGINX_USE_HTTP3} @@ -2323,7 +2325,7 @@ received: foo close: 1 nil --- error_log -client socket file: +client socket file: --- no_error_log [error] @@ -2637,3 +2639,815 @@ qr/\[debug\] .*? SSL_do_handshake: 1/, should never reached here [alert] [emerg] + + + +=== TEST 31: ssl_client_hello_by_lua* can yield when reading early data +--- skip_eval: 6:!$ENV{TEST_NGINX_USE_HTTP3} +--- config + server_tokens off; + lua_ssl_trusted_certificate ../../cert/test.crt; + lua_ssl_verify_depth 3; + + ssl_client_hello_by_lua_block { + print("ssl client hello by lua is running!") + ngx.sleep(0.1) + print("ssl client hello by lua is done") + } + + location /t { + content_by_lua_block { + print("test completed") + ngx.say("test completed") + } + } +--- request +GET /t +--- response_body +test completed + +--- grep_error_log eval: qr/(ssl client hello by lua is running!|ssl client hello by lua is done|test completed)/ +--- grep_error_log_out +ssl client hello by lua is running! +ssl client hello by lua is done +test completed +--- no_error_log +[error] +[alert] +[emerg] + + + +=== TEST 32: ssl_client_hello_by_lua* with TCP cosocket (yield API) +--- skip_eval: 6:!$ENV{TEST_NGINX_USE_HTTP3} +--- config + server_tokens off; + lua_ssl_trusted_certificate ../../cert/test.crt; + lua_ssl_verify_depth 3; + + ssl_client_hello_by_lua_block { + print("ssl client hello: TCP cosocket test start") + + local sock = ngx.socket.tcp() + sock:settimeout(2000) + + local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_MEMCACHED_PORT) + if not ok then + ngx.log(ngx.ERR, "failed to connect to memc: ", err) + return + end + + local bytes, err = sock:send("flush_all\r\n") + if not bytes then + ngx.log(ngx.ERR, "failed to send flush_all command: ", err) + return + end + + local res, err = sock:receive() + if not res then + ngx.log(ngx.ERR, "failed to receive memc reply: ", err) + return + end + + print("ssl client hello: received TCP memc reply: ", res) + sock:close() + print("ssl client hello: TCP cosocket test done") + } + + location /t { + content_by_lua_block { + print("test completed") + ngx.say("test completed") + } + } +--- request +GET /t +--- response_body +test completed + +--- grep_error_log eval: qr/(ssl client hello: TCP cosocket test start|ssl client hello: received TCP memc reply: OK|ssl client hello: TCP cosocket test done|test completed)/ +--- grep_error_log_out +ssl client hello: TCP cosocket test start +ssl client hello: received TCP memc reply: OK +ssl client hello: TCP cosocket test done +test completed + +--- no_error_log +[error] +[alert] +[emerg] + + + +=== TEST 33: ssl_client_hello_by_lua* with UDP cosocket (yield API) +--- skip_eval: 6:!$ENV{TEST_NGINX_USE_HTTP3} +--- config + server_tokens off; + lua_ssl_trusted_certificate ../../cert/test.crt; + lua_ssl_verify_depth 3; + + ssl_client_hello_by_lua_block { + print("ssl client hello: UDP cosocket test start") + + local sock = ngx.socket.udp() + sock:settimeout(1000) + + local ok, err = sock:setpeername("127.0.0.1", $TEST_NGINX_MEMCACHED_PORT) + if not ok then + ngx.log(ngx.ERR, "failed to connect to memc: ", err) + return + end + + local req = "\0\1\0\0\0\1\0\0flush_all\r\n" + local ok, err = sock:send(req) + if not ok then + ngx.log(ngx.ERR, "failed to send flush_all to memc: ", err) + return + end + + local res, err = sock:receive() + if not res then + ngx.log(ngx.ERR, "failed to receive memc reply: ", err) + return + end + + print("ssl client hello: received UDP memc reply of ", #res, " bytes") + sock:close() + print("ssl client hello: UDP cosocket test done") + } + + location /t { + content_by_lua_block { + print("test completed") + ngx.say("test completed") + } + } +--- request +GET /t +--- response_body +test completed + +--- grep_error_log eval: qr/(ssl client hello: UDP cosocket test start|ssl client hello: received UDP memc reply of \d+ bytes|ssl client hello: UDP cosocket test done|test completed)/ +--- grep_error_log_out +ssl client hello: UDP cosocket test start +ssl client hello: received UDP memc reply of 12 bytes +ssl client hello: UDP cosocket test done +test completed + +--- no_error_log +[error] +[alert] +[emerg] + + + +=== TEST 34: ssl_client_hello_by_lua* with ngx.timer (yield API) +--- skip_eval: 6:!$ENV{TEST_NGINX_USE_HTTP3} +--- config + server_tokens off; + lua_ssl_trusted_certificate ../../cert/test.crt; + lua_ssl_verify_depth 3; + + ssl_client_hello_by_lua_block { + print("ssl client hello: timer test start") + + local function timer_handler() + print("ssl client hello: timer executed") + end + + local ok, err = ngx.timer.at(0, timer_handler) + if not ok then + ngx.log(ngx.ERR, "failed to create timer: ", err) + return + end + + print("ssl client hello: timer created") + print("ssl client hello: timer test done") + } + + location /t { + content_by_lua_block { + print("test completed") + ngx.say("test completed") + } + } +--- request +GET /t +--- response_body +test completed + +--- grep_error_log eval: qr/(ssl client hello: timer test start|ssl client hello: timer created|ssl client hello: timer test done|ssl client hello: timer executed|test completed)/ +--- grep_error_log_out +ssl client hello: timer test start +ssl client hello: timer created +ssl client hello: timer test done +ssl client hello: timer executed +test completed + +--- no_error_log +[error] +[alert] +[emerg] + + + +=== TEST 35: ssl_client_hello_by_lua* with user threads (yield API) +--- skip_eval: 6:!$ENV{TEST_NGINX_USE_HTTP3} +--- config + server_tokens off; + lua_ssl_trusted_certificate ../../cert/test.crt; + lua_ssl_verify_depth 3; + + ssl_client_hello_by_lua_block { + print("ssl client hello: uthread test start") + + local function worker() + ngx.sleep(0.01) + print("ssl client hello: uthread worker executed") + return "worker_result" + end + + local t, err = ngx.thread.spawn(worker) + if not t then + ngx.log(ngx.ERR, "failed to spawn thread: ", err) + return + end + + print("ssl client hello: uthread spawned") + + local ok, res = ngx.thread.wait(t) + if not ok then + ngx.log(ngx.ERR, "failed to wait thread: ", res) + return + end + + print("ssl client hello: uthread result: ", res) + print("ssl client hello: uthread test done") + } + + location /t { + content_by_lua_block { + print("test completed") + ngx.say("test completed") + } + } +--- request +GET /t +--- response_body +test completed + +--- grep_error_log eval: qr/(ssl client hello: uthread test start|ssl client hello: uthread spawned|ssl client hello: uthread worker executed|ssl client hello: uthread result: worker_result|ssl client hello: uthread test done|test completed)/ +--- grep_error_log_out +ssl client hello: uthread test start +ssl client hello: uthread spawned +ssl client hello: uthread worker executed +ssl client hello: uthread result: worker_result +ssl client hello: uthread test done +test completed + +--- no_error_log +[error] +[alert] +[emerg] + + + +=== TEST 36: ssl_client_hello_by_lua* with coroutines (yield API) +--- skip_eval: 6:!$ENV{TEST_NGINX_USE_HTTP3} +--- config + server_tokens off; + lua_ssl_trusted_certificate ../../cert/test.crt; + lua_ssl_verify_depth 3; + + ssl_client_hello_by_lua_block { + print("ssl client hello: coroutine test start") + + local cc, cr, cy = coroutine.create, coroutine.resume, coroutine.yield + + local function coro_func() + local cnt = 0 + for i = 1, 3 do + print("ssl client hello: coro yield: ", cnt) + cy() + cnt = cnt + 1 + end + return "coro_done" + end + + local c = cc(coro_func) + for i = 1, 4 do + print("ssl client hello: coro resume, status: ", coroutine.status(c)) + local ok, res = cr(c) + if not ok then + print("ssl client hello: coro error: ", res) + break + end + if coroutine.status(c) == "dead" then + print("ssl client hello: coro result: ", res) + break + end + end + + print("ssl client hello: coroutine test done") + } + + location /t { + content_by_lua_block { + print("test completed") + ngx.say("test completed") + } + } +--- request +GET /t +--- response_body +test completed + +--- grep_error_log eval: qr/(ssl client hello: coroutine test start|ssl client hello: coro resume, status: \w+|ssl client hello: coro yield: \d+|ssl client hello: coro result: coro_done|ssl client hello: coroutine test done|test completed)/ +--- grep_error_log_out +ssl client hello: coroutine test start +ssl client hello: coro resume, status: suspended +ssl client hello: coro yield: 0 +ssl client hello: coro resume, status: suspended +ssl client hello: coro yield: 1 +ssl client hello: coro resume, status: suspended +ssl client hello: coro yield: 2 +ssl client hello: coro resume, status: suspended +ssl client hello: coro result: coro_done +ssl client hello: coroutine test done +test completed + +--- no_error_log +[error] +[alert] +[emerg] + + + +=== TEST 37: ssl_client_hello_by_lua* without yield API (simple logic) +--- skip_eval: 6:!$ENV{TEST_NGINX_USE_HTTP3} +--- config + server_tokens off; + lua_ssl_trusted_certificate ../../cert/test.crt; + lua_ssl_verify_depth 3; + + ssl_client_hello_by_lua_block { + print("ssl client hello: simple test start") + + -- Simple calculations without yield + local sum = 0 + for i = 1, 10 do + sum = sum + i + end + + print("ssl client hello: calculated sum: ", sum) + + -- String operations + local str = "hello" + str = str .. " world" + print("ssl client hello: concatenated string: ", str) + + -- Table operations + local t = {a = 1, b = 2, c = 3} + local count = 0 + for k, v in pairs(t) do + count = count + v + end + print("ssl client hello: table sum: ", count) + + print("ssl client hello: simple test done") + } + + location /t { + content_by_lua_block { + print("test completed") + ngx.say("test completed") + } + } +--- request +GET /t +--- response_body +test completed + +--- grep_error_log eval: qr/(ssl client hello: simple test start|ssl client hello: calculated sum: 55|ssl client hello: concatenated string: hello world|ssl client hello: table sum: 6|ssl client hello: simple test done|test completed)/ +--- grep_error_log_out +ssl client hello: simple test start +ssl client hello: calculated sum: 55 +ssl client hello: concatenated string: hello world +ssl client hello: table sum: 6 +ssl client hello: simple test done +test completed + +--- no_error_log +[error] +[alert] +[emerg] + + + +=== TEST 38: ssl_client_hello_by_lua* with multiple network operations (yield API) +--- skip_eval: 6:!$ENV{TEST_NGINX_USE_HTTP3} +--- config + server_tokens off; + lua_ssl_trusted_certificate ../../cert/test.crt; + lua_ssl_verify_depth 3; + + ssl_client_hello_by_lua_block { + print("ssl client hello: multiple network test start") + + -- First TCP operation + local sock1 = ngx.socket.tcp() + sock1:settimeout(2000) + local ok, err = sock1:connect("127.0.0.1", $TEST_NGINX_MEMCACHED_PORT) + if ok then + local bytes, err = sock1:send("version\r\n") + if bytes then + local res, err = sock1:receive() + if res then + print("ssl client hello: TCP1 version: ", res) + end + end + sock1:close() + end + + ngx.sleep(0.01) -- Small delay + + -- Second UDP operation + local sock2 = ngx.socket.udp() + sock2:settimeout(1000) + local ok, err = sock2:setpeername("127.0.0.1", $TEST_NGINX_MEMCACHED_PORT) + if ok then + local req = "\0\1\0\0\0\1\0\0version\r\n" + local ok, err = sock2:send(req) + if ok then + local res, err = sock2:receive() + if res then + print("ssl client hello: UDP version reply length: ", #res) + end + end + sock2:close() + end + + print("ssl client hello: multiple network test done") + } + + location /t { + content_by_lua_block { + print("test completed") + ngx.say("test completed") + } + } +--- request +GET /t +--- response_body +test completed + +--- grep_error_log eval: qr/(ssl client hello: multiple network test start|ssl client hello: TCP1 version: VERSION|ssl client hello: UDP version reply length: \d+|ssl client hello: multiple network test done|test completed)/ +--- grep_error_log_out eval +[ +qr/ssl client hello: multiple network test start/, +qr/ssl client hello: TCP1 version: VERSION/, +qr/ssl client hello: UDP version reply length: \d+/, +qr/ssl client hello: multiple network test done/, +qr/test completed/, +] + +--- no_error_log +[error] +[alert] +[emerg] + + + +=== TEST 39: ssl_cert_by_lua* and ssl_client_hello_by_lua* with sleep (yield API) +--- skip_eval: 6:!$ENV{TEST_NGINX_USE_HTTP3} +--- http_config + ssl_certificate_by_lua_block { + print("cert by: starting with sleep") + local begin = ngx.now() + ngx.sleep(0.05) + print("cert by: slept for ", ngx.now() - begin, " seconds") + } + +--- config + server_tokens off; + lua_ssl_trusted_certificate ../../cert/test.crt; + lua_ssl_verify_depth 3; + + ssl_client_hello_by_lua_block { + print("client hello: starting with sleep") + local begin = ngx.now() + ngx.sleep(0.1) + print("client hello: slept for ", ngx.now() - begin, " seconds") + } + + location /t { + content_by_lua_block { + print("test completed") + ngx.say("test completed") + } + } +--- request +GET /t +--- response_body +test completed + +--- grep_error_log eval: qr/(client hello: starting with sleep|client hello: slept for 0\.\d+|cert by: starting with sleep|cert by: slept for 0\.\d+|test completed)/ +--- grep_error_log_out eval +[ +qr/client hello: starting with sleep/, +qr/client hello: slept for 0\.(?:09|1\d)\d+/, +qr/cert by: starting with sleep/, +qr/cert by: slept for 0\.0[4-6]\d+/, +qr/test completed/, +] + +--- no_error_log +[error] +[alert] +[emerg] + + + +=== TEST 40: ssl_cert_by_lua* and ssl_client_hello_by_lua* with cosocket (yield API) +--- skip_eval: 6:!$ENV{TEST_NGINX_USE_HTTP3} +--- http_config + ssl_certificate_by_lua_block { + print("cert by: cosocket test start") + + local sock = ngx.socket.udp() + sock:settimeout(1000) + + local ok, err = sock:setpeername("127.0.0.1", $TEST_NGINX_MEMCACHED_PORT) + if not ok then + ngx.log(ngx.ERR, "cert by: failed to connect to memc: ", err) + return + end + + local req = "\0\1\0\0\0\1\0\0flush_all\r\n" + local ok, err = sock:send(req) + if not ok then + ngx.log(ngx.ERR, "cert by: failed to send flush_all to memc: ", err) + return + end + + local res, err = sock:receive() + if not res then + ngx.log(ngx.ERR, "cert by: failed to receive memc reply: ", err) + return + end + + print("cert by: received UDP memc reply of ", #res, " bytes") + sock:close() + print("cert by: cosocket test done") + } +--- config + server_tokens off; + lua_ssl_trusted_certificate ../../cert/test.crt; + lua_ssl_verify_depth 3; + + ssl_client_hello_by_lua_block { + print("client hello: cosocket test start") + + local sock = ngx.socket.tcp() + sock:settimeout(2000) + + local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_MEMCACHED_PORT) + if not ok then + ngx.log(ngx.ERR, "client hello: failed to connect to memc: ", err) + return + end + + local bytes, err = sock:send("version\r\n") + if not bytes then + ngx.log(ngx.ERR, "client hello: failed to send version command: ", err) + return + end + + local res, err = sock:receive() + if not res then + ngx.log(ngx.ERR, "client hello: failed to receive memc reply: ", err) + return + end + + print("client hello: received memc reply: ", res) + sock:close() + print("client hello: cosocket test done") + } + + location /t { + content_by_lua_block { + print("test completed") + ngx.say("test completed") + } + } +--- request +GET /t +--- response_body +test completed + +--- grep_error_log eval: qr/(client hello: cosocket test start|client hello: received memc reply: VERSION|client hello: cosocket test done|cert by: cosocket test start|cert by: received UDP memc reply of \d+ bytes|cert by: cosocket test done|test completed)/ +--- grep_error_log_out eval +[ +qr/client hello: cosocket test start/, +qr/client hello: received memc reply: VERSION/, +qr/client hello: cosocket test done/, +qr/cert by: cosocket test start/, +qr/cert by: received UDP memc reply of \d+ bytes/, +qr/cert by: cosocket test done/, +qr/test completed/, +] + +--- no_error_log +[error] +[alert] +[emerg] + + + +=== TEST 41: ssl_cert_by_lua* and ssl_client_hello_by_lua* with timer and uthread (yield API) +--- skip_eval: 6:!$ENV{TEST_NGINX_USE_HTTP3} +--- http_config + ssl_certificate_by_lua_block { + print("cert by: coroutine test start") + + local cc, cr, cy = coroutine.create, coroutine.resume, coroutine.yield + + local function coro_func() + local cnt = 0 + for i = 1, 2 do + print("cert by: coro yield: ", cnt) + cy() + cnt = cnt + 1 + end + return "cert_by_coro_done" + end + + local c = cc(coro_func) + for i = 1, 3 do + print("cert by: coro resume, status: ", coroutine.status(c)) + local ok, res = cr(c) + if not ok then + print("cert by: coro error: ", res) + break + end + if coroutine.status(c) == "dead" then + print("cert by: coro result: ", res) + break + end + end + + -- Small sleep to allow timer to execute + ngx.sleep(0.01) + print("cert by: coroutine test done") + } + +--- config + server_tokens off; + lua_ssl_trusted_certificate ../../cert/test.crt; + lua_ssl_verify_depth 3; + + ssl_client_hello_by_lua_block { + print("client hello: timer and uthread test start") + + -- Timer test + local function timer_handler() + print("client hello: timer executed") + end + + local ok, err = ngx.timer.at(0, timer_handler) + if not ok then + ngx.log(ngx.ERR, "client hello: failed to create timer: ", err) + return + end + + print("client hello: timer created") + + -- User thread test + local function worker() + ngx.sleep(0.01) + print("client hello: uthread worker executed") + return "client_hello_result" + end + + local t, err = ngx.thread.spawn(worker) + if not t then + ngx.log(ngx.ERR, "client hello: failed to spawn thread: ", err) + return + end + + print("client hello: uthread spawned") + + local ok, res = ngx.thread.wait(t) + if not ok then + ngx.log(ngx.ERR, "client hello: failed to wait thread: ", res) + return + end + + print("client hello: uthread result: ", res) + print("client hello: timer and uthread test done") + } + + location /t { + content_by_lua_block { + print("test completed") + ngx.say("test completed") + } + } +--- request +GET /t +--- response_body +test completed + +--- grep_error_log eval: qr/(client hello: timer and uthread test start|client hello: timer created|client hello: uthread spawned|client hello: uthread worker executed|client hello: uthread result: client_hello_result|client hello: timer and uthread test done|cert by: coroutine test start|cert by: coro resume, status: \w+|cert by: coro yield: \d+|cert by: coro result: cert_by_coro_done|cert by: coroutine test done|client hello: timer executed|test completed)/ +--- grep_error_log_out eval +[ +qr/client hello: timer and uthread test start/, +qr/client hello: timer created/, +qr/client hello: uthread spawned/, +qr/client hello: uthread worker executed/, +qr/client hello: uthread result: client_hello_result/, +qr/client hello: timer and uthread test done/, +qr/cert by: coroutine test start/, +qr/cert by: coro resume, status: suspended/, +qr/cert by: coro yield: 0/, +qr/cert by: coro resume, status: suspended/, +qr/cert by: coro yield: 1/, +qr/cert by: coro resume, status: suspended/, +qr/cert by: coro result: cert_by_coro_done/, +qr/cert by: coroutine test done/, +qr/client hello: timer executed/, +qr/test completed/, +] + +--- no_error_log +[error] +[alert] +[emerg] + + + +=== TEST 42: ssl_cert_by_lua* with cosocket (yield API) and ssl_client_hello_by_lua* failure +--- skip_eval: 8:!$ENV{TEST_NGINX_USE_HTTP3} +--- http_config + ssl_certificate_by_lua_block { + print("cert by: test start") + ngx.exit(500) + } +--- config + server_tokens off; + lua_ssl_trusted_certificate ../../cert/test.crt; + lua_ssl_verify_depth 3; + + ssl_client_hello_by_lua_block { + print("client hello: cosocket test start") + + local sock = ngx.socket.tcp() + sock:settimeout(2000) + + local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_MEMCACHED_PORT) + if not ok then + ngx.log(ngx.ERR, "client hello: failed to connect to memc: ", err) + return + end + + local bytes, err = sock:send("version\r\n") + if not bytes then + ngx.log(ngx.ERR, "client hello: failed to send version command: ", err) + return + end + + local res, err = sock:receive() + if not res then + ngx.log(ngx.ERR, "client hello: failed to receive memc reply: ", err) + return + end + + print("client hello: received memc reply: ", res) + sock:close() + print("client hello: cosocket test done") + } + + location /t { + content_by_lua_block { + print("test completed") + ngx.say("test completed") + } + } +--- request +GET /t +--- ignore_response +--- curl_error eval +qr/Connection time/ +--- grep_error_log eval: qr/(client hello: cosocket test start|client hello: received memc reply: VERSION|client hello: cosocket test done|cert by: test start)/ +--- grep_error_log_out eval +[ +qr/client hello: cosocket test start/, +qr/client hello: received memc reply: VERSION/, +qr/client hello: cosocket test done/, +qr/cert by: test start/, +] + +--- no_error_log +[error] +[alert] +[emerg] From 25ebf2072de6065dc1e2f5bfe97801fa9a9adeb6 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Mon, 30 Jun 2025 23:37:16 +0800 Subject: [PATCH 228/254] tests: add utility script run-ci.sh --- README.markdown | 19 ++++- util/run-ci.sh | 193 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 211 insertions(+), 1 deletion(-) create mode 100755 util/run-ci.sh diff --git a/README.markdown b/README.markdown index 117a9e484b..2db20f3e05 100644 --- a/README.markdown +++ b/README.markdown @@ -45,6 +45,7 @@ Table of Contents * [Missing data on short circuited requests](#missing-data-on-short-circuited-requests) * [TODO](#todo) * [Changes](#changes) +* [Build And Test](#build-and-test) * [Test Suite](#test-suite) * [Copyright and License](#copyright-and-license) * [See Also](#see-also) @@ -982,6 +983,23 @@ The changes made in every release of this module are listed in the change logs o [Back to TOC](#table-of-contents) +Build And Test +============== + +This module uses `.travis.yml` as the CI configuration. +You can always check `.travis.yml` for the latest CI configuration. + +For developers, you need to run tests locally. You can use `util/run-ci.sh` +to easily set up the environment and execute the test suite. + +To run the Test from the beginning: + +```shell +git clone https://github.com/openresty/lua-nginx-module.git +cd lua-nginx-module +bash util/run-ci.sh +``` + Test Suite ========== @@ -1026,7 +1044,6 @@ To run the whole test suite in the default testing mode: export PATH=/path/to/your/nginx/sbin:$PATH prove -I/path/to/test-nginx/lib -r t - To run specific test files: cd /path/to/lua-nginx-module diff --git a/util/run-ci.sh b/util/run-ci.sh new file mode 100755 index 0000000000..b5e5407c17 --- /dev/null +++ b/util/run-ci.sh @@ -0,0 +1,193 @@ +#!/bin/bash + +#export CC=clang +export CC=gcc +export NGX_BUILD_CC=$CC + +mkdir -p download-cache + +export JOBS=$(nproc) +export NGX_BUILD_JOBS=$JOBS +export VALGRIND_INC=/usr/include/valgrind/ + +export LUAJIT_PREFIX=/opt/luajit21 +export LUAJIT_LIB=$LUAJIT_PREFIX/lib +export LUAJIT_INC=$LUAJIT_PREFIX/include/luajit-2.1 +export LUA_INCLUDE_DIR=$LUAJIT_INC + +export PCRE2_VER=10.45 +export PCRE2_PREFIX=/opt/pcre2 +export PCRE2_LIB=$PCRE2_PREFIX/lib +export PCRE2_INC=$PCRE2_PREFIX/include + +export OPENSSL_VER=3.5.0 +export OPENSSL_PATCH_VER=3.5.0 +export OPENSSL_PREFIX=/opt/ssl3 +export OPENSSL_LIB=$OPENSSL_PREFIX/lib +export OPENSSL_INC=$OPENSSL_PREFIX/include + +export LIBDRIZZLE_PREFIX=/opt/drizzle +export LIBDRIZZLE_INC=$LIBDRIZZLE_PREFIX/include/libdrizzle-1.0 +export LIBDRIZZLE_LIB=$LIBDRIZZLE_PREFIX/lib +export DRIZZLE_VER=2011.07.21 + +#export TEST_NGINX_SLEEP=0.006 +export NGINX_VERSION=1.27.1 +#export NGX_BUILD_ASAN=1 + +export PATH=/opt/bin:$PWD/work/nginx/sbin:$PWD/openresty-devel-utils:$PATH + +if [ ! -f /opt/bin/curl ]; then + wget https://github.com/stunnel/static-curl/releases/download/8.14.1/curl-linux-x86_64-glibc-8.14.1.tar.xz + tar -xf curl-linux-x86_64-glibc-8.14.1.tar.xz + tar -xf curl-linux-x86_64-glibc-8.14.1.tar.xz + sudo mkdir -p /opt/bin + sudo mv curl /opt/bin/ +fi + +function git_download() +{ + dir=${!#} + if [ ! -d $dir ]; then + git clone $@ + fi +} + +function download_deps() +{ + if [ ! -f download-cache/drizzle7-$DRIZZLE_VER.tar.gz ]; then + wget -P download-cache https://github.com/openresty/openresty-deps-prebuild/releases/download/v20230902/drizzle7-$DRIZZLE_VER.tar.gz + fi + + if [ ! -f download-cache/pcre2-$PCRE2_VER.tar.gz ]; then + wget -P download-cache https://github.com/PCRE2Project/pcre2/releases/download/pcre2-${PCRE2_VER}/pcre2-${PCRE2_VER}.tar.gz + fi + + if [ ! -f download-cache/openssl-$OPENSSL_VER.tar.gz ]; then + wget -P download-cache https://github.com/openssl/openssl/releases/download/openssl-$OPENSSL_VER/openssl-$OPENSSL_VER.tar.gz + fi + + git_download clone https://github.com/openresty/test-nginx.git + git_download clone https://github.com/openresty/openresty.git ../openresty + git_download clone https://github.com/openresty/no-pool-nginx.git ../no-pool-nginx + git_download clone https://github.com/openresty/openresty-devel-utils.git + git_download clone https://github.com/openresty/mockeagain.git + git_download clone https://github.com/openresty/lua-cjson.git lua-cjson + git_download clone https://github.com/openresty/lua-upstream-nginx-module.git ../lua-upstream-nginx-module + git_download clone https://github.com/openresty/echo-nginx-module.git ../echo-nginx-module + git_download clone https://github.com/openresty/nginx-eval-module.git ../nginx-eval-module + git_download clone https://github.com/simpl/ngx_devel_kit.git ../ndk-nginx-module + git_download clone https://github.com/FRiCKLE/ngx_coolkit.git ../coolkit-nginx-module + git_download clone https://github.com/openresty/headers-more-nginx-module.git ../headers-more-nginx-module + git_download clone https://github.com/openresty/drizzle-nginx-module.git ../drizzle-nginx-module + git_download clone https://github.com/openresty/set-misc-nginx-module.git ../set-misc-nginx-module + git_download clone https://github.com/openresty/memc-nginx-module.git ../memc-nginx-module + git_download clone https://github.com/openresty/rds-json-nginx-module.git ../rds-json-nginx-module + git_download clone https://github.com/openresty/srcache-nginx-module.git ../srcache-nginx-module + git_download clone https://github.com/openresty/redis2-nginx-module.git ../redis2-nginx-module + git_download clone https://github.com/openresty/lua-resty-core.git ../lua-resty-core + git_download clone https://github.com/openresty/lua-resty-lrucache.git ../lua-resty-lrucache + git_download clone https://github.com/openresty/lua-resty-mysql.git ../lua-resty-mysql + git_download clone https://github.com/openresty/lua-resty-string.git ../lua-resty-string + git_download clone https://github.com/openresty/stream-lua-nginx-module.git ../stream-lua-nginx-module + git_download clone -b v2.1-agentzh https://github.com/openresty/luajit2.git luajit2 +} + +function make_deps() +{ + if [ "$TEST_NGINX_BUILD_DEPS" = "n" ]; then + return + fi + + cd luajit2/ + make clean + make -j"$JOBS" CCDEBUG=-g Q= PREFIX=$LUAJIT_PREFIX CC=$CC XCFLAGS="-DLUAJIT_USE_VALGRIND -I$VALGRIND_INC -DLUAJIT_USE_SYSMALLOC -DLUA_USE_APICHECK -DLUA_USE_ASSERT -msse4.2" > build.log 2>&1 || (cat build.log && exit 1) + sudo make install PREFIX=$LUAJIT_PREFIX + cd .. + + tar zxf download-cache/openssl-$OPENSSL_VER.tar.gz + cd openssl-$OPENSSL_VER/ + patch -p1 < ../../openresty/patches/openssl-$OPENSSL_PATCH_VER-sess_set_get_cb_yield.patch > ssl.log + ./config -DOPENSSL_TLS_SECURITY_LEVEL=1 shared enable-ssl3 enable-ssl3-method -g -O2 --prefix=$OPENSSL_PREFIX --libdir=lib -DPURIFY >> ssl.log + make -j$JOBS >> ssl.log + sudo make PATH=$PATH install_sw >> ssl.log + cd .. + + tar zxf download-cache/pcre2-$PCRE2_VER.tar.gz; + cd pcre2-$PCRE2_VER/; + ./configure --prefix=$PCRE2_PREFIX --enable-jit --enable-utf + sudo PATH=$PATH make install + cd .. + + tar xzf download-cache/drizzle7-$DRIZZLE_VER.tar.gz && cd drizzle7-$DRIZZLE_VER + ./configure --prefix=$LIBDRIZZLE_PREFIX --without-server + make libdrizzle-1.0 -j$JOBS + sudo make install-libdrizzle-1.0 + cd .. + + cd mockeagain/ && make CC=$CC -j$JOBS + cd .. + + cd lua-cjson/ && make -j$JOBS && sudo make install + cd .. +} + +function make_ngx() +{ + if [ "$TEST_NGINX_FRESH_BUILD" = "y" ]; then + rm -fr buildroot + fi + + sh util/build.sh $NGINX_VERSION 2>&1 | tee build.log +} + +download_deps +make_deps +make_ngx + +find t -name "*.t" | xargs reindex >/dev/null 2>&1 + +#nginx -V + +export LD_PRELOAD=$PWD/mockeagain/mockeagain.so +export LD_LIBRARY_PATH=$PWD/mockeagain:$LD_LIBRARY_PATH + +#export ASAN_OPTIONS=detect_leaks=0,log_path=/tmp/asan/asan,log_exe_name=true +#export LD_PRELOAD=/lib64/libasan.so.5:$PWD/mockeagain/mockeagain.so + +export LD_LIBRARY_PATH=$LUAJIT_LIB:$OPENSSL_LIB:$LD_LIBRARY_PATH +export TEST_NGINX_RESOLVER=8.8.4.4 + +#export TEST_NGINX_NO_CLEAN=1 +#export TEST_NGINX_CHECK_LEAK=1 +#export TEST_NGINX_CHECK_LEAK_COUNT=100 +#export TEST_NGINX_TIMEOUT=5 + +#export TEST_NGINX_USE_VALGRIND=1 +#export TEST_NGINX_VALGRIND_EXIT_ON_FIRST_ERR=1 +#export TEST_NGINX_USE_HTTP2=1 + +export MALLOC_PERTURB_=33 +export TEST_NGINX_HTTP3_CRT=$PWD/t/cert/http3/http3.crt +export TEST_NGINX_HTTP3_KEY=$PWD/t/cert/http3/http3.key +#export TEST_NGINX_USE_HTTP3=1 + +#export TEST_NGINX_VERBOSE=1 + +#export TEST_NGINX_EVENT_TYPE=poll +#export TEST_NGINX_POSTPONE_OUTPUT=1 +#export MOCKEAGAIN=r +#export MOCKEAGAIN=w +#export MOCKEAGAIN=rw +#export MOCKEAGAIN_VERBOSE=1 + +ldd `which nginx`|grep -E 'luajit|ssl|pcre' +which nginx +nginx -V + +#export TEST_NGINX_INIT_BY_LUA="debug.sethook(function () collectgarbage() end, 'l') jit.off() package.path = '/usr/share/lua/5.1/?.lua;$PWD/../lua-resty-core/lib/?.lua;$PWD/../lua-resty-lrucache/lib/?.lua;' .. (package.path or '') require 'resty.core' require('resty.core.base').set_string_buf_size(1) require('resty.core.regex').set_buf_grow_ratio(1)" + + +# comment out TEST_NGINX_RANDOMIZE when debugging one test case +export TEST_NGINX_RANDOMIZE=1 +prove -j$JOBS -I. -Itest-nginx/inc -Itest-nginx/lib -r t/ From 9aed90f4707bfdc2df443aec5d6bbcd3489def12 Mon Sep 17 00:00:00 2001 From: willmafh Date: Tue, 1 Jul 2025 21:40:19 +0800 Subject: [PATCH 229/254] feature: add lua_ssl_key_log directive. --- README.markdown | 14 +++++ doc/HttpLuaModule.wiki | 10 ++++ src/ngx_http_lua_common.h | 1 + src/ngx_http_lua_module.c | 117 ++++++++++++++++++++++++++++++++++++++ src/ngx_http_lua_ssl.c | 12 ++++ src/ngx_http_lua_ssl.h | 8 +++ t/129-ssl-socket.t | 102 +++++++++++++++++++++++++++++++++ 7 files changed, 264 insertions(+) diff --git a/README.markdown b/README.markdown index 2db20f3e05..1565487d93 100644 --- a/README.markdown +++ b/README.markdown @@ -1186,6 +1186,7 @@ Directives * [lua_ssl_certificate_key](#lua_ssl_certificate_key) * [lua_ssl_trusted_certificate](#lua_ssl_trusted_certificate) * [lua_ssl_verify_depth](#lua_ssl_verify_depth) +* [lua_ssl_key_log](#lua_ssl_key_log) * [lua_ssl_conf_command](#lua_ssl_conf_command) * [lua_http10_buffering](#lua_http10_buffering) * [rewrite_by_lua_no_postpone](#rewrite_by_lua_no_postpone) @@ -3447,6 +3448,19 @@ See also [lua_ssl_certificate](#lua_ssl_certificate), [lua_ssl_certificate_key]( [Back to TOC](#directives) +lua_ssl_key_log +--------------- + +**syntax:** *lua_ssl_key_log <file>* + +**default:** *none* + +**context:** *http, server, location* + +Enables logging of client connection SSL keys in the [tcpsock:sslhandshake](#tcpsocksslhandshake) method and specifies the path to the key log file. Keys are logged in the SSLKEYLOGFILE format compatible with Wireshark. + +[Back to TOC](#directives) + lua_ssl_conf_command -------------------- diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 733f11dc66..69e1a86303 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -2925,6 +2925,16 @@ This directive was first introduced in the v0.9.11 release. See also [[#lua_ssl_certificate|lua_ssl_certificate]], [[#lua_ssl_certificate_key|lua_ssl_certificate_key]] and [[#lua_ssl_trusted_certificate|lua_ssl_trusted_certificate]]. +== lua_ssl_key_log == + +'''syntax:''' ''lua_ssl_key_log '' + +'''default:''' ''none'' + +'''context:''' ''http, server, location'' + +Enables logging of client connection SSL keys in the [[#tcpsock:sslhandshake|tcpsock:sslhandshake]] method and specifies the path to the key log file. Keys are logged in the SSLKEYLOGFILE format compatible with Wireshark. + == lua_ssl_conf_command == '''syntax:''' ''lua_ssl_conf_command '' diff --git a/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h index cc2d36a386..9db3e19ce5 100644 --- a/src/ngx_http_lua_common.h +++ b/src/ngx_http_lua_common.h @@ -379,6 +379,7 @@ typedef struct { ngx_uint_t ssl_verify_depth; ngx_str_t ssl_trusted_certificate; ngx_str_t ssl_crl; + ngx_str_t ssl_key_log; #if (nginx_version >= 1019004) ngx_array_t *ssl_conf_commands; #endif diff --git a/src/ngx_http_lua_module.c b/src/ngx_http_lua_module.c index 0f23c2d769..cae92b21ee 100644 --- a/src/ngx_http_lua_module.c +++ b/src/ngx_http_lua_module.c @@ -54,6 +54,11 @@ static ngx_int_t ngx_http_lua_merge_ssl(ngx_conf_t *cf, ngx_http_lua_loc_conf_t *conf, ngx_http_lua_loc_conf_t *prev); static ngx_int_t ngx_http_lua_set_ssl(ngx_conf_t *cf, ngx_http_lua_loc_conf_t *llcf); +static void key_log_callback(const ngx_ssl_conn_t *ssl_conn, + const char *line); +static void ngx_http_lua_ssl_cleanup_key_log(void *data); +static ngx_int_t ngx_http_lua_ssl_key_log(ngx_conf_t *cf, ngx_ssl_t *ssl, + ngx_str_t *file); #if (nginx_version >= 1019004) static char *ngx_http_lua_ssl_conf_command_check(ngx_conf_t *cf, void *post, void *data); @@ -690,6 +695,13 @@ static ngx_command_t ngx_http_lua_cmds[] = { offsetof(ngx_http_lua_loc_conf_t, ssl_crl), NULL }, + { ngx_string("lua_ssl_key_log"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_lua_loc_conf_t, ssl_key_log), + NULL }, + #if (nginx_version >= 1019004) { ngx_string("lua_ssl_conf_command"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2, @@ -1433,6 +1445,7 @@ ngx_http_lua_create_loc_conf(ngx_conf_t *cf) * conf->ssl_ciphers = { 0, NULL }; * conf->ssl_trusted_certificate = { 0, NULL }; * conf->ssl_crl = { 0, NULL }; + * conf->ssl_key_log = { 0, NULL }; */ conf->force_read_body = NGX_CONF_UNSET; @@ -1553,6 +1566,7 @@ ngx_http_lua_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_str_value(conf->ssl_trusted_certificate, prev->ssl_trusted_certificate, ""); ngx_conf_merge_str_value(conf->ssl_crl, prev->ssl_crl, ""); + ngx_conf_merge_str_value(conf->ssl_key_log, prev->ssl_key_log, ""); #if (nginx_version >= 1019004) ngx_conf_merge_ptr_value(conf->ssl_conf_commands, prev->ssl_conf_commands, @@ -1616,6 +1630,7 @@ ngx_http_lua_merge_ssl(ngx_conf_t *cf, && conf->ssl_certificate_keys == NGX_CONF_UNSET_PTR && conf->ssl_trusted_certificate.data == NULL && conf->ssl_crl.data == NULL + && conf->ssl_key_log.data == NULL #if (nginx_version >= 1019004) && conf->ssl_conf_commands == NGX_CONF_UNSET_PTR #endif @@ -1723,6 +1738,12 @@ ngx_http_lua_set_ssl(ngx_conf_t *cf, ngx_http_lua_loc_conf_t *llcf) return NGX_ERROR; } + if (ngx_http_lua_ssl_key_log(cf, llcf->ssl, &llcf->ssl_key_log) + != NGX_OK) + { + return NGX_ERROR; + } + #if (nginx_version >= 1019004) if (ngx_ssl_conf_commands(cf, llcf->ssl, llcf->ssl_conf_commands) != NGX_OK) @@ -1734,6 +1755,102 @@ ngx_http_lua_set_ssl(ngx_conf_t *cf, ngx_http_lua_loc_conf_t *llcf) return NGX_OK; } + +static void +key_log_callback(const ngx_ssl_conn_t *ssl_conn, const char *line) +{ + ngx_http_lua_ssl_key_log_t *ssl_key_log; + ngx_connection_t *c; + + ssl_key_log = SSL_CTX_get_ex_data(SSL_get_SSL_CTX(ssl_conn), + ngx_http_lua_ssl_key_log_index); + if (ssl_key_log == NULL) { + c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn); + ngx_ssl_error(NGX_LOG_DEBUG, c->log, 0, "get ssl key log failed"); + + return; + } + + (void) ngx_write_fd(ssl_key_log->fd, (void *) line, ngx_strlen(line)); + (void) ngx_write_fd(ssl_key_log->fd, (void *) "\n", 1); +} + + +static void +ngx_http_lua_ssl_cleanup_key_log(void *data) +{ + ngx_http_lua_ssl_key_log_t *ssl_key_log = data; + + if (ngx_close_file(ssl_key_log->fd) == NGX_FILE_ERROR) { + ngx_ssl_error(NGX_LOG_ALERT, ssl_key_log->ssl->log, 0, + ngx_close_file_n "(\"%V\") failed", ssl_key_log->name); + } +} + + +static ngx_int_t +ngx_http_lua_ssl_key_log(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file) +{ + ngx_fd_t fd; + ngx_http_lua_ssl_key_log_t *ssl_key_log; + ngx_pool_cleanup_t *cln; + + if (!file->len) { + return NGX_OK; + } + + if (ngx_conf_full_name(cf->cycle, file, 1) != NGX_OK) { + return NGX_ERROR; + } + + if (ngx_http_lua_ssl_init(cf->log) != NGX_OK) { + return NGX_ERROR; + } + + /* + * append so that existing keylog file contents can be preserved + */ + fd = ngx_open_file(file->data, NGX_FILE_APPEND, NGX_FILE_CREATE_OR_OPEN, + NGX_FILE_DEFAULT_ACCESS); + if (fd == NGX_INVALID_FILE) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, ngx_open_file_n + "(\"%V\") failed", file); + return NGX_ERROR; + } + + ssl_key_log = ngx_palloc(cf->pool, sizeof(ngx_http_lua_ssl_key_log_t)); + if (ssl_key_log == NULL) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "ngx_pcalloc() failed"); + return NGX_ERROR; + } + + ssl_key_log->ssl = ssl; + ssl_key_log->fd = fd; + ssl_key_log->name = *file; + + if (SSL_CTX_set_ex_data(ssl->ctx, ngx_http_lua_ssl_key_log_index, + ssl_key_log) == 0) + { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "SSL_CTX_set_ex_data() failed"); + return NGX_ERROR; + } + + cln = ngx_pool_cleanup_add(cf->pool, 0); + if (cln == NULL) { + ngx_http_lua_ssl_cleanup_key_log(ssl_key_log); + return NGX_ERROR; + } + + cln->handler = ngx_http_lua_ssl_cleanup_key_log; + cln->data = ssl_key_log; + + SSL_CTX_set_keylog_callback(ssl->ctx, key_log_callback); + + return NGX_OK; +} + + #if (nginx_version >= 1019004) static char * ngx_http_lua_ssl_conf_command_check(ngx_conf_t *cf, void *post, void *data) diff --git a/src/ngx_http_lua_ssl.c b/src/ngx_http_lua_ssl.c index 8ed7b95417..25e4f1b456 100644 --- a/src/ngx_http_lua_ssl.c +++ b/src/ngx_http_lua_ssl.c @@ -14,6 +14,7 @@ int ngx_http_lua_ssl_ctx_index = -1; +int ngx_http_lua_ssl_key_log_index = -1; ngx_int_t @@ -30,6 +31,17 @@ ngx_http_lua_ssl_init(ngx_log_t *log) } } + if (ngx_http_lua_ssl_key_log_index == -1) { + ngx_http_lua_ssl_key_log_index = SSL_get_ex_new_index(0, NULL, NULL, + NULL, NULL); + + if (ngx_http_lua_ssl_key_log_index == -1) { + ngx_ssl_error(NGX_LOG_ALERT, log, 0, + "lua: SSL_get_ex_new_index() for key log failed"); + return NGX_ERROR; + } + } + return NGX_OK; } diff --git a/src/ngx_http_lua_ssl.h b/src/ngx_http_lua_ssl.h index 3d577c61fb..1ee0a3626c 100644 --- a/src/ngx_http_lua_ssl.h +++ b/src/ngx_http_lua_ssl.h @@ -41,10 +41,18 @@ typedef struct { } ngx_http_lua_ssl_ctx_t; +typedef struct { + ngx_ssl_t *ssl; + ngx_fd_t fd; + ngx_str_t name; +} ngx_http_lua_ssl_key_log_t; + + ngx_int_t ngx_http_lua_ssl_init(ngx_log_t *log); extern int ngx_http_lua_ssl_ctx_index; +extern int ngx_http_lua_ssl_key_log_index; #endif diff --git a/t/129-ssl-socket.t b/t/129-ssl-socket.t index 8a05306ab0..5651f3f817 100644 --- a/t/129-ssl-socket.t +++ b/t/129-ssl-socket.t @@ -2944,3 +2944,105 @@ SSL reused session [alert] [emerg] --- timeout: 10 + + + +=== TEST 35: lua_ssl_key_log directive +--- skip_openssl: 8: < 1.1.1 +--- http_config + server { + listen $TEST_NGINX_SERVER_SSL_PORT ssl; + server_name test.com; + ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; + ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; + ssl_protocols TLSv1.3; + + location / { + content_by_lua_block { + ngx.exit(200) + } + } + } +--- config + server_tokens off; + lua_ssl_protocols TLSv1.3; + lua_ssl_key_log sslkey.log; + + location /t { + content_by_lua_block { + local sock = ngx.socket.tcp() + sock:settimeout(2000) + + do + local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_SERVER_SSL_PORT) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local session, err = sock:sslhandshake(nil, "test.com") + if not session then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(session)) + + local req = "GET / HTTP/1.1\r\nHost: test.com\r\nConnection: close\r\n\r\n" + local bytes, err = sock:send(req) + if not bytes then + ngx.say("failed to send http request: ", err) + return + end + + ngx.say("sent http request: ", bytes, " bytes.") + + local line, err = sock:receive() + if not line then + ngx.say("failed to receive response status line: ", err) + return + end + + ngx.say("received: ", line) + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + + local f, err = io.open("$TEST_NGINX_SERVER_ROOT/conf/sslkey.log", "r") + if not f then + ngx.log(ngx.ERR, "failed to open sslkey.log: ", err) + return + end + + local key_log = f:read("*a") + ngx.say(key_log) + f:close() + end -- do + collectgarbage() + } + } +--- request +GET /t +--- response_body_like +connected: 1 +ssl handshake: cdata +sent http request: 53 bytes. +received: HTTP/1.1 200 OK +close: 1 nil +SERVER_HANDSHAKE_TRAFFIC_SECRET [0-9a-z\s]+ +EXPORTER_SECRET [0-9a-z\s]+ +SERVER_TRAFFIC_SECRET_0 [0-9a-z\s]+ +CLIENT_HANDSHAKE_TRAFFIC_SECRET [0-9a-z\s]+ +CLIENT_TRAFFIC_SECRET_0 [0-9a-z\s]+ + +--- log_level: debug +--- error_log eval +['lua ssl server name: "test.com"', +qr/SSL: TLSv1.3, cipher: "TLS_AES_256_GCM_SHA384 TLSv1.3/] +--- no_error_log +SSL reused session +[error] +[alert] +--- timeout: 10 From 83ae875b306cd94bd4759ded06e1a60b08cd2481 Mon Sep 17 00:00:00 2001 From: Sunny Chan Date: Wed, 2 Jul 2025 14:46:00 +0800 Subject: [PATCH 230/254] feature: add ngx_http_lua_ffi_req_shared_ssl_ciphers(). MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This function returns a uint16_t array of tls_protocol_id supported by both server and client. Co-author-by: Bjørnar Ness . --- src/ngx_http_lua_ssl_certby.c | 80 +++++++++ t/140-ssl-c-api.t | 305 +++++++++++++++++++++++++++++++++- 2 files changed, 383 insertions(+), 2 deletions(-) diff --git a/src/ngx_http_lua_ssl_certby.c b/src/ngx_http_lua_ssl_certby.c index 0c13af91c4..c5426da565 100644 --- a/src/ngx_http_lua_ssl_certby.c +++ b/src/ngx_http_lua_ssl_certby.c @@ -37,6 +37,10 @@ static u_char *ngx_http_lua_log_ssl_cert_error(ngx_log_t *log, u_char *buf, static ngx_int_t ngx_http_lua_ssl_cert_by_chunk(lua_State *L, ngx_http_request_t *r); +#ifndef OPENSSL_IS_BORINGSSL +static int ngx_http_lua_is_grease_cipher(uint16_t cipher_id); +#endif + ngx_int_t ngx_http_lua_ssl_cert_handler_file(ngx_http_request_t *r, @@ -450,6 +454,18 @@ ngx_http_lua_log_ssl_cert_error(ngx_log_t *log, u_char *buf, size_t len) } +#ifndef OPENSSL_IS_BORINGSSL +static int +ngx_http_lua_is_grease_cipher(uint16_t cipher_id) +{ + /* GREASE values follow pattern: 0x?A?A where ? can be any hex digit */ + /* and both ? must be the same */ + /* Check if both bytes follow ?A pattern and high nibbles match */ + return (cipher_id & 0x0F0F) == 0x0A0A; +} +#endif + + static ngx_int_t ngx_http_lua_ssl_cert_by_chunk(lua_State *L, ngx_http_request_t *r) { @@ -837,6 +853,70 @@ ngx_http_lua_ffi_ssl_raw_server_addr(ngx_http_request_t *r, char **addr, } +int +ngx_http_lua_ffi_req_shared_ssl_ciphers(ngx_http_request_t *r, + uint16_t *ciphers, uint16_t *nciphers, int filter_grease, char **err) +{ +#ifdef OPENSSL_IS_BORINGSSL + + *err = "BoringSSL is not supported for SSL cipher operations"; + return NGX_ERROR; + +#else + ngx_ssl_conn_t *ssl_conn; + STACK_OF(SSL_CIPHER) *sk, *ck; + int sn, cn, i, n; + uint16_t cipher; + + if (r == NULL || r->connection == NULL || r->connection->ssl == NULL) { + *err = "bad request"; + return NGX_ERROR; + } + + ssl_conn = r->connection->ssl->connection; + if (ssl_conn == NULL) { + *err = "bad ssl conn"; + return NGX_ERROR; + } + + sk = SSL_get1_supported_ciphers(ssl_conn); + ck = SSL_get_client_ciphers(ssl_conn); + sn = sk_SSL_CIPHER_num(sk); + cn = sk_SSL_CIPHER_num(ck); + + if (sn > *nciphers) { + *err = "buffer too small"; + *nciphers = 0; + sk_SSL_CIPHER_free(sk); + return NGX_ERROR; + } + + for (*nciphers = 0, i = 0; i < sn; i++) { + cipher = SSL_CIPHER_get_protocol_id(sk_SSL_CIPHER_value(sk, i)); + + /* Skip GREASE ciphers if filtering is enabled */ + if (filter_grease && ngx_http_lua_is_grease_cipher(cipher)) { + continue; + } + + for (n = 0; n < cn; n++) { + if (SSL_CIPHER_get_protocol_id(sk_SSL_CIPHER_value(ck, n)) + == cipher) + { + ciphers[(*nciphers)++] = cipher; + break; + } + } + } + + sk_SSL_CIPHER_free(sk); + + return NGX_OK; +#endif + +} + + int ngx_http_lua_ffi_ssl_server_name(ngx_http_request_t *r, char **name, size_t *namelen, char **err) diff --git a/t/140-ssl-c-api.t b/t/140-ssl-c-api.t index 81d8375bb5..15ed8abfcf 100644 --- a/t/140-ssl-c-api.t +++ b/t/140-ssl-c-api.t @@ -10,9 +10,12 @@ my $openssl_version = eval { `$NginxBinary -V 2>&1` }; if ($openssl_version =~ m/built with OpenSSL (0|1\.0\.(?:0|1[^\d]|2[a-d]).*)/) { plan(skip_all => "too old OpenSSL, need 1.0.2e, was $1"); - +} elsif ($openssl_version =~ m/BoringSSL/) { + $ENV{TEST_NGINX_USE_BORINGSSL} = 1; + plan tests => repeat_each() * (blocks() * 6 - 8); } else { - plan tests => repeat_each() * (blocks() * 5 - 1); + plan tests => repeat_each() * (blocks() * 5 - 5); + $ENV{TEST_NGINX_USE_OPENSSL} = 1; } $ENV{TEST_NGINX_HTML_DIR} ||= html_dir(); @@ -77,6 +80,8 @@ ffi.cdef[[ int ngx_http_lua_ffi_ssl_client_random(ngx_http_request_t *r, unsigned char *out, size_t *outlen, char **err); + int ngx_http_lua_ffi_req_shared_ssl_ciphers(void *r, uint16_t *ciphers, + uint16_t *nciphers, int filter_grease, char **err); ]] _EOC_ } @@ -1212,6 +1217,7 @@ lua ssl server name: "test.com" === TEST 10: Raw SSL pointer +--- skip_eval: 8:$ENV{TEST_NGINX_USE_BORINGSSL} --- http_config server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; @@ -1777,3 +1783,298 @@ SUCCESS --- no_error_log [error] [alert] + + + +=== TEST 15: Get supported ciphers +--- skip_eval: 8:$ENV{TEST_NGINX_USE_BORINGSSL} +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + ssl_certificate ../../cert/test.crt; + ssl_certificate_key ../../cert/test.key; + ssl_protocols TLSv1.2; + ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384; + + server_tokens off; + + location /ciphers { + content_by_lua_block { + require "defines" + local ffi = require "ffi" + local cjson = require "cjson.safe" + local base = require "resty.core.base" + local get_request = base.get_request + + local MAX_CIPHERS = 64 + local ciphers = ffi.new("uint16_t[?]", MAX_CIPHERS) + local nciphers = ffi.new("uint16_t[1]", MAX_CIPHERS) + local err = ffi.new("char*[1]") + + local r = get_request() + local ret = ffi.C.ngx_http_lua_ffi_req_shared_ssl_ciphers(r, ciphers, nciphers, 0, err) + + if ret ~= 0 then + ngx.log(ngx.ERR, "error: ", ffi.string(err[0])) + return + end + + local res = {} + for i = 0, nciphers[0] - 1 do + local cipher_id = string.format("%04x", ciphers[i]) + table.insert(res, cipher_id) + end + + ngx.say(cjson.encode(res)) + } + } + } +--- config + server_tokens off; + location /t { + proxy_ssl_protocols TLSv1.2; + proxy_ssl_session_reuse off; + proxy_ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256; + proxy_pass https://unix:$TEST_NGINX_HTML_DIR/nginx.sock:/ciphers; + } +--- request +GET /t +--- response_body_like +\["c02f","c02b"\] +--- error_log chomp +TLSv1.2, cipher: "ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(128) Mac=AEAD" + + + +=== TEST 16: SSL cipher API error handling (no SSL) +--- skip_eval: 8:$ENV{TEST_NGINX_USE_BORINGSSL} +--- config + location /t { + content_by_lua_block { + require "defines" + local ffi = require "ffi" + + local ciphers = ffi.new("uint16_t[64]") + local nciphers = ffi.new("uint16_t[1]", 64) + local err = ffi.new("char*[1]") + + -- use nil request to trigger error + local ret = ffi.C.ngx_http_lua_ffi_req_shared_ssl_ciphers(nil, ciphers, nciphers, 0, err) + + ngx.say("ret: ", ret) + if err[0] ~= nil then + ngx.say("err: ", ffi.string(err[0])) + end + } + } +--- request +GET /t +--- response_body +ret: -1 +err: bad request + +--- no_error_log +[error] +[alert] + + + +=== TEST 17: Buffer overflow handling +--- skip_eval: 8:$ENV{TEST_NGINX_USE_BORINGSSL} +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + ssl_certificate ../../cert/test.crt; + ssl_certificate_key ../../cert/test.key; + ssl_protocols TLSv1.2; + ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384; + + server_tokens off; + + + location /ciphers { + content_by_lua_block { + require "defines" + local ffi = require "ffi" + local base = require "resty.core.base" + local get_request = base.get_request + local cjson = require "cjson.safe" + + local MAX_CIPHERS = 64 + local ciphers = ffi.new("uint16_t[?]", MAX_CIPHERS) + local nciphers = ffi.new("uint16_t[1]", MAX_CIPHERS) + local err = ffi.new("char*[1]") + + local r = get_request() + local ret = ffi.C.ngx_http_lua_ffi_req_shared_ssl_ciphers(r, ciphers, nciphers, 0, err) + + if ret ~= 0 then + ngx.log(ngx.ERR, "error: ", ffi.string(err[0])) + return + end + local res = {} + for i = 0, nciphers[0] - 1 do + local cipher_id = string.format("%04x", ciphers[i]) + + table.insert(res, cipher_id) + end + ngx.say(cjson.encode(res)) + } + } + } +--- config + server_tokens off; + location /t { + proxy_ssl_protocols TLSv1.2; + proxy_ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256; + proxy_ssl_session_reuse off; + proxy_pass https://unix:$TEST_NGINX_HTML_DIR/nginx.sock:/ciphers; + } +--- request +GET /t +--- response_body_like +\["c02f"\] +--- error_code: 200 +--- error_log chomp +TLSv1.2, cipher: "ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(128) Mac=AEAD" + + + +=== TEST 18: BORINGSSL error handling +--- skip_eval: 8:$ENV{TEST_NGINX_USE_OPENSSL} +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + ssl_certificate ../../cert/test.crt; + ssl_certificate_key ../../cert/test.key; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384; + + server_tokens off; + + + location /ciphers { + content_by_lua_block { + require "defines" + local ffi = require "ffi" + local base = require "resty.core.base" + local get_request = base.get_request + + local MAX_CIPHERS = 64 + local ciphers = ffi.new("uint16_t[?]", MAX_CIPHERS) + local nciphers = ffi.new("uint16_t[1]", MAX_CIPHERS) + local err = ffi.new("char*[1]") + + local r = get_request() + local ret = ffi.C.ngx_http_lua_ffi_req_shared_ssl_ciphers(r, ciphers, nciphers, 0, err) + + if ret ~= 0 then + ngx.say("Error: ", ffi.string(err[0])) + return + end + + } + } + } +--- config + server_tokens off; + location /t { + proxy_ssl_protocols TLSv1.2 TLSv1.3; + proxy_ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256; + proxy_pass https://unix:$TEST_NGINX_HTML_DIR/nginx.sock:/ciphers; + } +--- request +GET /t +--- response_body_like chomp +Error: BoringSSL is not supported for SSL cipher operations +--- error_code: 200 + +--- no_error_log +[error] +[alert] + + + +=== TEST 19: Get supported ciphers with GREASE filtering +--- skip_eval: 8:$ENV{TEST_NGINX_USE_BORINGSSL} +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + ssl_certificate ../../cert/test.crt; + ssl_certificate_key ../../cert/test.key; + ssl_protocols TLSv1.2; + ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384; + + server_tokens off; + + location /ciphers { + content_by_lua_block { + require "defines" + local ffi = require "ffi" + local cjson = require "cjson.safe" + local base = require "resty.core.base" + local get_request = base.get_request + + local MAX_CIPHERS = 64 + local ciphers = ffi.new("uint16_t[?]", MAX_CIPHERS) + local nciphers = ffi.new("uint16_t[1]", MAX_CIPHERS) + local err = ffi.new("char*[1]") + + local r = get_request() + -- Test without GREASE filtering + local ret = ffi.C.ngx_http_lua_ffi_req_shared_ssl_ciphers(r, ciphers, nciphers, 0, err) + if ret ~= 0 then + ngx.log(ngx.ERR, "error without filtering: ", ffi.string(err[0])) + return + end + + local res_no_filter = {} + for i = 0, nciphers[0] - 1 do + local cipher_id = string.format("%04x", ciphers[i]) + table.insert(res_no_filter, cipher_id) + end + + -- Reset buffers + nciphers[0] = MAX_CIPHERS + + -- Test with GREASE filtering + local ret = ffi.C.ngx_http_lua_ffi_req_shared_ssl_ciphers(r, ciphers, nciphers, 1, err) + if ret ~= 0 then + ngx.log(ngx.ERR, "error with filtering: ", ffi.string(err[0])) + return + end + + local res_with_filter = {} + for i = 0, nciphers[0] - 1 do + local cipher_id = string.format("%04x", ciphers[i]) + table.insert(res_with_filter, cipher_id) + end + + ngx.say("without_filter:", cjson.encode(res_no_filter)) + ngx.say("with_filter:", cjson.encode(res_with_filter)) + } + } + } +--- config + server_tokens off; + location /t { + proxy_ssl_protocols TLSv1.2; + proxy_ssl_session_reuse off; + proxy_ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256; + proxy_pass https://unix:$TEST_NGINX_HTML_DIR/nginx.sock:/ciphers; + } +--- request +GET /t +--- response_body_like +without_filter:\[.*\] +with_filter:\[.*\] +--- error_log chomp +TLSv1.2, cipher: "ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(128) Mac=AEAD" + + + + From 715e636d22108cd8ef67a2d9db816b132fb08e3b Mon Sep 17 00:00:00 2001 From: lijunlong Date: Wed, 9 Jul 2025 09:04:06 +0800 Subject: [PATCH 231/254] tests: update t/142-ssl-session-store.t. --- t/142-ssl-session-store.t | 1 - 1 file changed, 1 deletion(-) diff --git a/t/142-ssl-session-store.t b/t/142-ssl-session-store.t index 11deb83207..ead2a167e5 100644 --- a/t/142-ssl-session-store.t +++ b/t/142-ssl-session-store.t @@ -975,4 +975,3 @@ qr/ssl_session_store_by_lua\*: skipped since TLS version >= 1\.3 \(\d+\)/ [error] [alert] [emerg] ---- skip_eval: 6:$ENV{TEST_NGINX_USE_HTTP3} From 5337179b2f4afa7e2842cd02bd293d2b9bc17665 Mon Sep 17 00:00:00 2001 From: willmafh Date: Wed, 16 Jul 2025 21:21:02 +0800 Subject: [PATCH 232/254] refactor: typo fixes. --- src/ngx_http_lua_ssl_client_helloby.c | 8 ++++---- t/166-ssl-client-hello.t | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/ngx_http_lua_ssl_client_helloby.c b/src/ngx_http_lua_ssl_client_helloby.c index b4377f2f1b..81b7a01f51 100644 --- a/src/ngx_http_lua_ssl_client_helloby.c +++ b/src/ngx_http_lua_ssl_client_helloby.c @@ -159,7 +159,7 @@ ngx_http_lua_ssl_client_hello_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, } chunkname = ngx_http_lua_gen_chunk_name(cf, "ssl_client_hello_by_lua", - sizeof("ssl_client_hello_by_lua")- 1, + sizeof("ssl_client_hello_by_lua") - 1, &chunkname_len); if (chunkname == NULL) { return NGX_CONF_ERROR; @@ -207,7 +207,7 @@ ngx_http_lua_ssl_client_hello_handler(ngx_ssl_conn_t *ssl_conn, if (cctx->done) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, - "lua_client_hello_by_lua: " + "ssl_client_hello_by_lua: " "client hello cb exit code: %d", cctx->exit_code); @@ -310,7 +310,7 @@ ngx_http_lua_ssl_client_hello_handler(ngx_ssl_conn_t *ssl_conn, } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, - "lua_client_hello_by_lua: handler return value: %i, " + "ssl_client_hello_by_lua: handler return value: %i, " "client hello cb exit code: %d", rc, cctx->exit_code); c->log->action = "SSL handshaking"; @@ -402,7 +402,7 @@ ngx_http_lua_ssl_client_hello_aborted(void *data) } ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cctx->connection->log, 0, - "lua_client_hello_by_lua: client hello cb aborted"); + "ssl_client_hello_by_lua: client hello cb aborted"); cctx->aborted = 1; cctx->request->connection->ssl = NULL; diff --git a/t/166-ssl-client-hello.t b/t/166-ssl-client-hello.t index 680011d091..53109ac3df 100644 --- a/t/166-ssl-client-hello.t +++ b/t/166-ssl-client-hello.t @@ -583,7 +583,7 @@ failed to do SSL handshake: handshake failed --- error_log eval [ -'lua_client_hello_by_lua: handler return value: -1, client hello cb exit code: 0', +'ssl_client_hello_by_lua: handler return value: -1, client hello cb exit code: 0', qr/\[info\] .*? SSL_do_handshake\(\) failed .*?callback failed/, 'lua exit with code -1', ] @@ -724,7 +724,7 @@ failed to do SSL handshake: handshake failed --- error_log eval [ -'lua_client_hello_by_lua: client hello cb exit code: 0', +'ssl_client_hello_by_lua: client hello cb exit code: 0', qr/\[info\] .*? SSL_do_handshake\(\) failed .*?callback failed/, 'lua exit with code -1', ] @@ -795,7 +795,7 @@ failed to do SSL handshake: handshake failed --- error_log eval [ 'runtime error: ssl_client_hello_by_lua(nginx.conf:28):2: bad bad bad', -'lua_client_hello_by_lua: handler return value: 500, client hello cb exit code: 0', +'ssl_client_hello_by_lua: handler return value: 500, client hello cb exit code: 0', qr/\[info\] .*? SSL_do_handshake\(\) failed .*?callback failed/, qr/context: ssl_client_hello_by_lua\*, client: \d+\.\d+\.\d+\.\d+, server: \d+\.\d+\.\d+\.\d+:\d+/, ] @@ -867,7 +867,7 @@ failed to do SSL handshake: handshake failed --- error_log eval [ 'runtime error: ssl_client_hello_by_lua(nginx.conf:28):3: bad bad bad', -'lua_client_hello_by_lua: client hello cb exit code: 0', +'ssl_client_hello_by_lua: client hello cb exit code: 0', qr/\[info\] .*? SSL_do_handshake\(\) failed .*?callback failed/, ] @@ -2631,7 +2631,7 @@ ssl handshake: boolean --- error_log eval [ -'lua_client_hello_by_lua: handler return value: 0, client hello cb exit code: 1', +'ssl_client_hello_by_lua: handler return value: 0, client hello cb exit code: 1', qr/\[debug\] .*? SSL_do_handshake: 1/, 'lua exit with code 0', ] From d34d3c545e80bccbd8110235d73474c11895bd2e Mon Sep 17 00:00:00 2001 From: lijunlong Date: Wed, 23 Jul 2025 21:43:04 +0800 Subject: [PATCH 233/254] change: ngx_http_lua_ffi_get_req_ssl_pointer() add err argument. --- src/ngx_http_lua_ssl_certby.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/ngx_http_lua_ssl_certby.c b/src/ngx_http_lua_ssl_certby.c index c5426da565..2abee0ef4b 100644 --- a/src/ngx_http_lua_ssl_certby.c +++ b/src/ngx_http_lua_ssl_certby.c @@ -1705,9 +1705,15 @@ ngx_http_lua_ffi_ssl_verify_client(ngx_http_request_t *r, void *client_certs, ngx_ssl_conn_t * -ngx_http_lua_ffi_get_req_ssl_pointer(ngx_http_request_t *r) +ngx_http_lua_ffi_get_req_ssl_pointer(ngx_http_request_t *r, const char **err) { if (r->connection == NULL || r->connection->ssl == NULL) { + *err = "bad request"; + return NULL; + } + + if (r->connection->ssl->connection == NULL) { + *err = "bad ssl connection"; return NULL; } From 96db53ea64949ed3be35b0c98576b9e2b5007d0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BD=97=E6=B3=BD=E8=BD=A9?= Date: Sun, 27 Jul 2025 20:35:00 +0800 Subject: [PATCH 234/254] doc: update version info. --- README.markdown | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.markdown b/README.markdown index 1565487d93..3d5b46cac3 100644 --- a/README.markdown +++ b/README.markdown @@ -64,8 +64,8 @@ Version ======= This document describes ngx_lua -[v0.10.25](https://github.com/openresty/lua-nginx-module/tags), which was released -on 19 June 2023. +[v0.10.28](https://github.com/openresty/lua-nginx-module/tags), which was released +on 17 Jan, 2025. Videos ====== @@ -308,6 +308,7 @@ Nginx Compatibility The latest version of this module is compatible with the following versions of Nginx: +* 1.27.x (last tested: 1.27.1) * 1.25.x (last tested: 1.25.1) * 1.21.x (last tested: 1.21.4) * 1.19.x (last tested: 1.19.3) From 9600893c310f6865efa7f799b1e6426bfd73b220 Mon Sep 17 00:00:00 2001 From: swananan Date: Sun, 27 Jul 2025 22:13:44 +0800 Subject: [PATCH 235/254] tests: fix CI configuration and SSL test issues. --- t/043-shdict.t | 4 ++-- t/140-ssl-c-api.t | 6 +---- t/142-ssl-session-store.t | 1 + util/run-ci.sh | 48 +++++++++++++++++++-------------------- 4 files changed, 28 insertions(+), 31 deletions(-) diff --git a/t/043-shdict.t b/t/043-shdict.t index 649683b9fe..3c0cc7961a 100644 --- a/t/043-shdict.t +++ b/t/043-shdict.t @@ -158,7 +158,7 @@ hello content_by_lua ' local dogs = ngx.shared.dogs dogs:set("foo", 32, 0.01) - ngx.location.capture("/sleep/0.01") + ngx.location.capture("/sleep/0.011") ngx.say(dogs:get("foo")) '; } @@ -1131,7 +1131,7 @@ nil nil content_by_lua ' local dogs = ngx.shared.dogs dogs:set("foo", 32, 0.01, 255) - ngx.location.capture("/sleep/0.01") + ngx.location.capture("/sleep/0.011") local res, flags = dogs:get("foo") ngx.say("res = ", res, ", flags = ", flags) '; diff --git a/t/140-ssl-c-api.t b/t/140-ssl-c-api.t index 15ed8abfcf..ca04a87528 100644 --- a/t/140-ssl-c-api.t +++ b/t/140-ssl-c-api.t @@ -12,7 +12,7 @@ if ($openssl_version =~ m/built with OpenSSL (0|1\.0\.(?:0|1[^\d]|2[a-d]).*)/) { plan(skip_all => "too old OpenSSL, need 1.0.2e, was $1"); } elsif ($openssl_version =~ m/BoringSSL/) { $ENV{TEST_NGINX_USE_BORINGSSL} = 1; - plan tests => repeat_each() * (blocks() * 6 - 8); + plan tests => repeat_each() * (blocks() * 6 - 6); } else { plan tests => repeat_each() * (blocks() * 5 - 5); $ENV{TEST_NGINX_USE_OPENSSL} = 1; @@ -2074,7 +2074,3 @@ without_filter:\[.*\] with_filter:\[.*\] --- error_log chomp TLSv1.2, cipher: "ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(128) Mac=AEAD" - - - - diff --git a/t/142-ssl-session-store.t b/t/142-ssl-session-store.t index ead2a167e5..11deb83207 100644 --- a/t/142-ssl-session-store.t +++ b/t/142-ssl-session-store.t @@ -975,3 +975,4 @@ qr/ssl_session_store_by_lua\*: skipped since TLS version >= 1\.3 \(\d+\)/ [error] [alert] [emerg] +--- skip_eval: 6:$ENV{TEST_NGINX_USE_HTTP3} diff --git a/util/run-ci.sh b/util/run-ci.sh index b5e5407c17..bb23926165 100755 --- a/util/run-ci.sh +++ b/util/run-ci.sh @@ -67,30 +67,30 @@ function download_deps() wget -P download-cache https://github.com/openssl/openssl/releases/download/openssl-$OPENSSL_VER/openssl-$OPENSSL_VER.tar.gz fi - git_download clone https://github.com/openresty/test-nginx.git - git_download clone https://github.com/openresty/openresty.git ../openresty - git_download clone https://github.com/openresty/no-pool-nginx.git ../no-pool-nginx - git_download clone https://github.com/openresty/openresty-devel-utils.git - git_download clone https://github.com/openresty/mockeagain.git - git_download clone https://github.com/openresty/lua-cjson.git lua-cjson - git_download clone https://github.com/openresty/lua-upstream-nginx-module.git ../lua-upstream-nginx-module - git_download clone https://github.com/openresty/echo-nginx-module.git ../echo-nginx-module - git_download clone https://github.com/openresty/nginx-eval-module.git ../nginx-eval-module - git_download clone https://github.com/simpl/ngx_devel_kit.git ../ndk-nginx-module - git_download clone https://github.com/FRiCKLE/ngx_coolkit.git ../coolkit-nginx-module - git_download clone https://github.com/openresty/headers-more-nginx-module.git ../headers-more-nginx-module - git_download clone https://github.com/openresty/drizzle-nginx-module.git ../drizzle-nginx-module - git_download clone https://github.com/openresty/set-misc-nginx-module.git ../set-misc-nginx-module - git_download clone https://github.com/openresty/memc-nginx-module.git ../memc-nginx-module - git_download clone https://github.com/openresty/rds-json-nginx-module.git ../rds-json-nginx-module - git_download clone https://github.com/openresty/srcache-nginx-module.git ../srcache-nginx-module - git_download clone https://github.com/openresty/redis2-nginx-module.git ../redis2-nginx-module - git_download clone https://github.com/openresty/lua-resty-core.git ../lua-resty-core - git_download clone https://github.com/openresty/lua-resty-lrucache.git ../lua-resty-lrucache - git_download clone https://github.com/openresty/lua-resty-mysql.git ../lua-resty-mysql - git_download clone https://github.com/openresty/lua-resty-string.git ../lua-resty-string - git_download clone https://github.com/openresty/stream-lua-nginx-module.git ../stream-lua-nginx-module - git_download clone -b v2.1-agentzh https://github.com/openresty/luajit2.git luajit2 + git_download https://github.com/openresty/test-nginx.git + git_download https://github.com/openresty/openresty.git ../openresty + git_download https://github.com/openresty/no-pool-nginx.git ../no-pool-nginx + git_download https://github.com/openresty/openresty-devel-utils.git + git_download https://github.com/openresty/mockeagain.git + git_download https://github.com/openresty/lua-cjson.git lua-cjson + git_download https://github.com/openresty/lua-upstream-nginx-module.git ../lua-upstream-nginx-module + git_download https://github.com/openresty/echo-nginx-module.git ../echo-nginx-module + git_download https://github.com/openresty/nginx-eval-module.git ../nginx-eval-module + git_download https://github.com/simpl/ngx_devel_kit.git ../ndk-nginx-module + git_download https://github.com/FRiCKLE/ngx_coolkit.git ../coolkit-nginx-module + git_download https://github.com/openresty/headers-more-nginx-module.git ../headers-more-nginx-module + git_download https://github.com/openresty/drizzle-nginx-module.git ../drizzle-nginx-module + git_download https://github.com/openresty/set-misc-nginx-module.git ../set-misc-nginx-module + git_download https://github.com/openresty/memc-nginx-module.git ../memc-nginx-module + git_download https://github.com/openresty/rds-json-nginx-module.git ../rds-json-nginx-module + git_download https://github.com/openresty/srcache-nginx-module.git ../srcache-nginx-module + git_download https://github.com/openresty/redis2-nginx-module.git ../redis2-nginx-module + git_download https://github.com/openresty/lua-resty-core.git ../lua-resty-core + git_download https://github.com/openresty/lua-resty-lrucache.git ../lua-resty-lrucache + git_download https://github.com/openresty/lua-resty-mysql.git ../lua-resty-mysql + git_download https://github.com/openresty/lua-resty-string.git ../lua-resty-string + git_download https://github.com/openresty/stream-lua-nginx-module.git ../stream-lua-nginx-module + git_download -b v2.1-agentzh https://github.com/openresty/luajit2.git luajit2 } function make_deps() From f40ced17f780ea6f5f479c881bda305891cc8db4 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Fri, 5 Sep 2025 17:04:20 +0800 Subject: [PATCH 236/254] bugfix: remove debugging code. --- src/ngx_http_lua_socket_udp.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ngx_http_lua_socket_udp.c b/src/ngx_http_lua_socket_udp.c index 3297cbbeca..d57a55e123 100644 --- a/src/ngx_http_lua_socket_udp.c +++ b/src/ngx_http_lua_socket_udp.c @@ -1481,7 +1481,6 @@ ngx_http_lua_udp_connect(ngx_http_lua_udp_connection_t *uc, ngx_addr_t *local) #endif if (local != NULL) { - fprintf(stderr, "=== have local address\n"); if (bind(s, local->sockaddr, local->socklen) == -1) { ngx_log_error(NGX_LOG_CRIT, &uc->log, ngx_socket_errno, "bind(%V) failed", &local->name); From 94c578a071a9c30dc57db14b927822d65251e590 Mon Sep 17 00:00:00 2001 From: swananan Date: Sun, 14 Sep 2025 18:51:47 +0800 Subject: [PATCH 237/254] bugfix: add HTTP/3 QUIC SSL Lua yield patch macro protection. --- .travis.yml | 2 +- README.markdown | 8 ++++++++ src/ngx_http_lua_ssl_certby.c | 6 ++++-- src/ngx_http_lua_ssl_client_helloby.c | 6 ++++-- src/ngx_http_lua_util.c | 2 +- src/ngx_http_lua_util.h | 2 +- 6 files changed, 19 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index f48c9a75bc..fc39846390 100644 --- a/.travis.yml +++ b/.travis.yml @@ -87,7 +87,7 @@ install: - wget https://github.com/openresty/openresty-deps-prebuild/releases/download/v20230902/boringssl-20230902-x64-focal.tar.gz - wget https://github.com/openresty/openresty-deps-prebuild/releases/download/v20230902/curl-h3-x64-focal.tar.gz - git clone https://github.com/openresty/test-nginx.git - - git clone https://github.com/openresty/openresty.git ../openresty + - git clone https://github.com/openresty/openresty.git - git clone https://github.com/openresty/no-pool-nginx.git ../no-pool-nginx - git clone https://github.com/openresty/openresty-devel-utils.git - git clone https://github.com/openresty/mockeagain.git diff --git a/README.markdown b/README.markdown index 3d5b46cac3..03a9a66055 100644 --- a/README.markdown +++ b/README.markdown @@ -2879,6 +2879,8 @@ patches to the standard Nginx core: +**Note for HTTP/3 (QUIC) users**: When using this directive with HTTP/3 connections, certain yield operations may fail if the QUIC SSL Lua yield patch is not applied to your OpenSSL installation. OpenResty packages include this patch by default, but if you are building lua-nginx-module separately, you may need to apply the patch manually to ensure proper yield/resume functionality for HTTP/3 connections in SSL Lua phases. The patch can be found at: [nginx-1.27.1-quic_ssl_lua_yield.patch](https://github.com/openresty/openresty/blob/master/patches/nginx/1.27.1/nginx-1.27.1-quic_ssl_lua_yield.patch) + This directive was first introduced in the `v0.10.21` release. [Back to TOC](#directives) @@ -2896,6 +2898,8 @@ Equivalent to [ssl_client_hello_by_lua_block](#ssl_client_hello_by_lua_block), e When a relative path like `foo/bar.lua` is given, they will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option while starting the Nginx server. +**Note for HTTP/3 (QUIC) users**: When using this directive with HTTP/3 connections, certain yield operations may fail if the QUIC SSL Lua yield patch is not applied to your OpenSSL installation. OpenResty packages include this patch by default, but if you are building lua-nginx-module separately, you may need to apply the patch manually to ensure proper yield/resume functionality for HTTP/3 connections in SSL Lua phases. The patch can be found at: [nginx-1.27.1-quic_ssl_lua_yield.patch](https://github.com/openresty/openresty/blob/master/patches/nginx/1.27.1/nginx-1.27.1-quic_ssl_lua_yield.patch) + This directive was first introduced in the `v0.10.21` release. [Back to TOC](#directives) @@ -2989,6 +2993,8 @@ patches to the standard Nginx core: +**Note for HTTP/3 (QUIC) users**: When using this directive with HTTP/3 connections, certain yield operations may fail if the QUIC SSL Lua yield patch is not applied to your OpenSSL installation. OpenResty packages include this patch by default, but if you are building lua-nginx-module separately, you may need to apply the patch manually to ensure proper yield/resume functionality for HTTP/3 connections in SSL Lua phases. The patch can be found at: [nginx-1.27.1-quic_ssl_lua_yield.patch](https://github.com/openresty/openresty/blob/master/patches/nginx/1.27.1/nginx-1.27.1-quic_ssl_lua_yield.patch) + This directive was first introduced in the `v0.10.0` release. [Back to TOC](#directives) @@ -3006,6 +3012,8 @@ Equivalent to [ssl_certificate_by_lua_block](#ssl_certificate_by_lua_block), exc When a relative path like `foo/bar.lua` is given, they will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option while starting the Nginx server. +**Note for HTTP/3 (QUIC) users**: When using this directive with HTTP/3 connections, certain yield operations may fail if the QUIC SSL Lua yield patch is not applied to your OpenSSL installation. OpenResty packages include this patch by default, but if you are building lua-nginx-module separately, you may need to apply the patch manually to ensure proper yield/resume functionality for HTTP/3 connections in SSL Lua phases. The patch can be found at: [nginx-1.27.1-quic_ssl_lua_yield.patch](https://github.com/openresty/openresty/blob/master/patches/nginx/1.27.1/nginx-1.27.1-quic_ssl_lua_yield.patch) + This directive was first introduced in the `v0.10.0` release. [Back to TOC](#directives) diff --git a/src/ngx_http_lua_ssl_certby.c b/src/ngx_http_lua_ssl_certby.c index 2abee0ef4b..9a2d63fcf0 100644 --- a/src/ngx_http_lua_ssl_certby.c +++ b/src/ngx_http_lua_ssl_certby.c @@ -390,9 +390,11 @@ ngx_http_lua_ssl_cert_done(void *data) ngx_post_event(c->write, &ngx_posted_events); -#if (NGX_HTTP_V3) && OPENSSL_VERSION_NUMBER >= 0x1000205fL -# if (NGX_QUIC_OPENSSL_COMPAT) +#if (HAVE_QUIC_SSL_LUA_YIELD_PATCH && NGX_HTTP_V3) +# if OPENSSL_VERSION_NUMBER >= 0x1000205fL +# if (NGX_QUIC_OPENSSL_COMPAT) ngx_http_lua_resume_quic_ssl_handshake(c); +# endif # endif #endif } diff --git a/src/ngx_http_lua_ssl_client_helloby.c b/src/ngx_http_lua_ssl_client_helloby.c index 81b7a01f51..42a91c1604 100644 --- a/src/ngx_http_lua_ssl_client_helloby.c +++ b/src/ngx_http_lua_ssl_client_helloby.c @@ -381,9 +381,11 @@ ngx_http_lua_ssl_client_hello_done(void *data) ngx_post_event(c->write, &ngx_posted_events); -#if (NGX_HTTP_V3) && defined(SSL_ERROR_WANT_CLIENT_HELLO_CB) -# if (NGX_QUIC_OPENSSL_COMPAT) +#if (HAVE_QUIC_SSL_LUA_YIELD_PATCH && NGX_HTTP_V3) +# if defined(SSL_ERROR_WANT_CLIENT_HELLO_CB) +# if (NGX_QUIC_OPENSSL_COMPAT) ngx_http_lua_resume_quic_ssl_handshake(c); +# endif # endif #endif } diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index d47c691000..5bc3b02807 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -4574,7 +4574,7 @@ ngx_http_lua_ffi_bypass_if_checks(ngx_http_request_t *r) } -#if (NGX_HTTP_V3) +#if (HAVE_QUIC_SSL_LUA_YIELD_PATCH && NGX_HTTP_V3) void ngx_http_lua_resume_quic_ssl_handshake(ngx_connection_t *c) { diff --git a/src/ngx_http_lua_util.h b/src/ngx_http_lua_util.h index d76508868c..eab4d4eba2 100644 --- a/src/ngx_http_lua_util.h +++ b/src/ngx_http_lua_util.h @@ -267,7 +267,7 @@ ngx_addr_t *ngx_http_lua_parse_addr(lua_State *L, u_char *text, size_t len); size_t ngx_http_lua_escape_log(u_char *dst, u_char *src, size_t size); -#if (NGX_HTTP_V3) +#if (HAVE_QUIC_SSL_LUA_YIELD_PATCH && NGX_HTTP_V3) void ngx_http_lua_resume_quic_ssl_handshake(ngx_connection_t *c); #endif From cc8b0672d7c655b2f2ad10c6b033df7c614077f4 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Mon, 13 Oct 2025 15:56:21 +0800 Subject: [PATCH 238/254] feature: add support for nginx-1.29.2. --- .travis.yml | 22 ++++++++++++---------- src/ngx_http_lua_ssl_client_helloby.c | 10 ++++++++++ t/014-bugs.t | 5 +++-- 3 files changed, 25 insertions(+), 12 deletions(-) diff --git a/.travis.yml b/.travis.yml index fc39846390..66997c1acc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -46,10 +46,12 @@ env: - LUAJIT_LIB=$LUAJIT_PREFIX/lib - LUAJIT_INC=$LUAJIT_PREFIX/include/luajit-2.1 - LUA_INCLUDE_DIR=$LUAJIT_INC - - PCRE2_PREFIX=/usr/local/openresty/pcre2 + #- PCRE2_PREFIX=/usr/local/openresty/pcre2 + - PCRE2_PREFIX=/opt/pcre2 - PCRE2_LIB=$PCRE2_PREFIX/lib - PCRE2_INC=$PCRE2_PREFIX/include - - OPENSSL_PREFIX=/usr/local/openresty/openssl3 + #- OPENSSL_PREFIX=/usr/local/openresty/openssl3 + - OPENSSL_PREFIX=/opt/openssl3 - OPENSSL_LIB=$OPENSSL_PREFIX/lib - OPENSSL_INC=$OPENSSL_PREFIX/include - LIBDRIZZLE_PREFIX=/opt/drizzle @@ -60,10 +62,10 @@ env: - TEST_NGINX_SLEEP=0.006 - MALLOC_PERTURB_=9 jobs: - - NGINX_VERSION=1.27.1 OPENSSL_VER=3.5.0 OPENSSL_PATCH_VER=3.5.0 TEST_NGINX_TIMEOUT=5 PCRE2_VER=10.45 - - NGINX_VERSION=1.27.1 OPENSSL_VER=3.5.0 OPENSSL_PATCH_VER=3.5.0 TEST_NGINX_TIMEOUT=5 PCRE2_VER=10.45 TEST_NGINX_USE_HTTP2=1 - - NGINX_VERSION=1.27.1 OPENSSL_VER=3.5.0 OPENSSL_PATCH_VER=3.5.0 TEST_NGINX_USE_HTTP3=1 TEST_NGINX_QUIC_IDLE_TIMEOUT=3 PCRE2_VER=10.45 - - NGINX_VERSION=1.27.1 BORINGSSL=1 TEST_NGINX_USE_HTTP3=1 TEST_NGINX_QUIC_IDLE_TIMEOUT=3 PCRE2_VER=10.45 + - NGINX_VERSION=1.29.2 OPENSSL_VER=3.5.4 OPENSSL_PATCH_VER=3.5.4 TEST_NGINX_TIMEOUT=5 PCRE2_VER=10.46 + - NGINX_VERSION=1.29.2 OPENSSL_VER=3.5.4 OPENSSL_PATCH_VER=3.5.4 TEST_NGINX_TIMEOUT=5 PCRE2_VER=10.46 TEST_NGINX_USE_HTTP2=1 + - NGINX_VERSION=1.29.2 OPENSSL_VER=3.5.4 OPENSSL_PATCH_VER=3.5.4 TEST_NGINX_USE_HTTP3=1 TEST_NGINX_QUIC_IDLE_TIMEOUT=3 PCRE2_VER=10.46 + - NGINX_VERSION=1.29.2 BORINGSSL=1 TEST_NGINX_USE_HTTP3=1 TEST_NGINX_QUIC_IDLE_TIMEOUT=3 PCRE2_VER=10.46 services: - memcached @@ -82,8 +84,8 @@ before_install: install: - if [ ! -f download-cache/drizzle7-$DRIZZLE_VER.tar.gz ]; then wget -P download-cache https://github.com/openresty/openresty-deps-prebuild/releases/download/v20230902/drizzle7-$DRIZZLE_VER.tar.gz; fi - #- if [ -n "$PCRE2_VER" ] && [ ! -f download-cache/pcre2-$PCRE2_VER.tar.gz ]; then wget -P download-cache https://github.com/PCRE2Project/pcre2/releases/download/pcre2-${PCRE2_VER}/pcre2-${PCRE2_VER}.tar.gz; fi - #- if [ -n "$OPENSSL_VER" ] && [ ! -f download-cache/openssl-$OPENSSL_VER.tar.gz ]; then wget -P download-cache https://github.com/openssl/openssl/releases/download/openssl-$OPENSSL_VER/openssl-$OPENSSL_VER.tar.gz || wget -P download-cache https://www.openssl.org/source/openssl-$OPENSSL_VER.tar.gz || wget -P download-cache https://www.openssl.org/source/old/${OPENSSL_VER//[a-z]/}/openssl-$OPENSSL_VER.tar.gz; fi + - if [ -n "$PCRE2_VER" ] && [ ! -f download-cache/pcre2-$PCRE2_VER.tar.gz ]; then wget -P download-cache https://github.com/PCRE2Project/pcre2/releases/download/pcre2-${PCRE2_VER}/pcre2-${PCRE2_VER}.tar.gz; fi + - if [ -n "$OPENSSL_VER" ] && [ ! -f download-cache/openssl-$OPENSSL_VER.tar.gz ]; then wget -P download-cache https://github.com/openssl/openssl/releases/download/openssl-$OPENSSL_VER/openssl-$OPENSSL_VER.tar.gz || wget -P download-cache https://www.openssl.org/source/openssl-$OPENSSL_VER.tar.gz || wget -P download-cache https://www.openssl.org/source/old/${OPENSSL_VER//[a-z]/}/openssl-$OPENSSL_VER.tar.gz; fi - wget https://github.com/openresty/openresty-deps-prebuild/releases/download/v20230902/boringssl-20230902-x64-focal.tar.gz - wget https://github.com/openresty/openresty-deps-prebuild/releases/download/v20230902/curl-h3-x64-focal.tar.gz - git clone https://github.com/openresty/test-nginx.git @@ -135,8 +137,8 @@ script: - sudo make install-libdrizzle-1.0 > build.log 2>&1 || (cat build.log && exit 1) - cd ../mockeagain/ && make CC=$CC -j$JOBS && cd .. - cd lua-cjson/ && make -j$JOBS && sudo make install && cd .. - #- if [ -n "$PCRE2_VER" ]; then tar zxf download-cache/pcre2-$PCRE2_VER.tar.gz; cd pcre2-$PCRE2_VER/; ./configure --prefix=$PCRE2_PREFIX --enable-jit --enable-utf > build.log 2>&1 || (cat build.log && exit 1); make -j$JOBS > build.log 2>&1 || (cat build.log && exit 1); sudo PATH=$PATH make install > build.log 2>&1 || (cat build.log && exit 1); cd ..; fi - #- if [ -n "$OPENSSL_VER" ]; then tar zxf download-cache/openssl-$OPENSSL_VER.tar.gz; cd openssl-$OPENSSL_VER/; patch -p1 < ../../openresty/patches/openssl-$OPENSSL_PATCH_VER-sess_set_get_cb_yield.patch; ./config shared enable-ssl3 enable-ssl3-method -g --prefix=$OPENSSL_PREFIX --libdir=lib -DPURIFY > build.log 2>&1 || (cat build.log && exit 1); make -j$JOBS > build.log 2>&1 || (cat build.log && exit 1); sudo make PATH=$PATH install_sw > build.log 2>&1 || (cat build.log && exit 1); cd ..; fi + - if [ -n "$PCRE2_VER" ]; then tar zxf download-cache/pcre2-$PCRE2_VER.tar.gz; cd pcre2-$PCRE2_VER/; ./configure --prefix=$PCRE2_PREFIX --enable-jit --enable-utf > build.log 2>&1 || (cat build.log && exit 1); make -j$JOBS > build.log 2>&1 || (cat build.log && exit 1); sudo PATH=$PATH make install > build.log 2>&1 || (cat build.log && exit 1); cd ..; fi + - if [ -n "$OPENSSL_VER" ]; then tar zxf download-cache/openssl-$OPENSSL_VER.tar.gz; cd openssl-$OPENSSL_VER/; patch -p1 < ../../openresty/patches/openssl-$OPENSSL_PATCH_VER-sess_set_get_cb_yield.patch; ./config shared enable-ssl3 enable-ssl3-method -g --prefix=$OPENSSL_PREFIX --libdir=lib -DPURIFY > build.log 2>&1 || (cat build.log && exit 1); make -j$JOBS > build.log 2>&1 || (cat build.log && exit 1); sudo make PATH=$PATH install_sw > build.log 2>&1 || (cat build.log && exit 1); cd ..; fi - if [ -n "$BORINGSSL" ]; then sudo rm -fr /usr/local/openresty/openssl3/ && sudo mkdir -p /usr/local/openresty/openssl3 && sudo tar -C /usr/local/openresty/openssl3 -xf boringssl-20230902-x64-focal.tar.gz --strip-components=1; fi - export NGX_BUILD_CC=$CC - sh util/build-without-ssl.sh $NGINX_VERSION > build.log 2>&1 || (cat build.log && exit 1) diff --git a/src/ngx_http_lua_ssl_client_helloby.c b/src/ngx_http_lua_ssl_client_helloby.c index 42a91c1604..c56e830636 100644 --- a/src/ngx_http_lua_ssl_client_helloby.c +++ b/src/ngx_http_lua_ssl_client_helloby.c @@ -193,6 +193,7 @@ ngx_http_lua_ssl_client_hello_handler(ngx_ssl_conn_t *ssl_conn, ngx_http_lua_ssl_ctx_t *cctx; ngx_http_core_srv_conf_t *cscf; + c = ngx_ssl_get_connection(ssl_conn); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, @@ -220,6 +221,15 @@ ngx_http_lua_ssl_client_hello_handler(ngx_ssl_conn_t *ssl_conn, dd("first time"); +#if (nginx_version > 1029000) + /* see commit 0373fe5d98c1515640 for more details */ + rc = ngx_ssl_client_hello_callback(ssl_conn, al, arg); + + if (rc == 0) { + return rc; + } +#endif + #if (nginx_version < 1017009) ngx_reusable_connection(c, 0); #endif diff --git a/t/014-bugs.t b/t/014-bugs.t index a89efec3c1..cef20733c2 100644 --- a/t/014-bugs.t +++ b/t/014-bugs.t @@ -9,7 +9,7 @@ log_level('debug'); repeat_each(3); # NB: the shutdown_error_log block is independent from repeat times -plan tests => repeat_each() * (blocks() * 2 + 33) + 1; +plan tests => repeat_each() * (blocks() * 2 + 33); our $HtmlDir = html_dir; #warn $html_dir; @@ -1269,6 +1269,8 @@ qr/\[emerg\] \d+#\d+: unexpected "A" in/ === TEST 47: cosocket does not exit on worker_shutdown_timeout +This test must enable master process +--- SKIP --- main_config worker_shutdown_timeout 1; --- config @@ -1316,7 +1318,6 @@ if ($ENV{TEST_NGINX_USE_HTTP3}) { $expr; --- timeout: 1.2 ---- skip_eval: 2:$ENV{TEST_NGINX_USE_HTTP3} From eb2b57f859b28f13c7e549a1dbface311dba56ea Mon Sep 17 00:00:00 2001 From: lijunlong Date: Tue, 14 Oct 2025 11:38:17 +0800 Subject: [PATCH 239/254] tests: fixed CI. --- .travis.yml | 2 +- src/ngx_http_lua_ssl_client_helloby.c | 1 - util/build.sh | 4 ++-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 66997c1acc..4aebcf6996 100644 --- a/.travis.yml +++ b/.travis.yml @@ -89,7 +89,7 @@ install: - wget https://github.com/openresty/openresty-deps-prebuild/releases/download/v20230902/boringssl-20230902-x64-focal.tar.gz - wget https://github.com/openresty/openresty-deps-prebuild/releases/download/v20230902/curl-h3-x64-focal.tar.gz - git clone https://github.com/openresty/test-nginx.git - - git clone https://github.com/openresty/openresty.git + - git clone https://github.com/openresty/openresty.git ../openresty - git clone https://github.com/openresty/no-pool-nginx.git ../no-pool-nginx - git clone https://github.com/openresty/openresty-devel-utils.git - git clone https://github.com/openresty/mockeagain.git diff --git a/src/ngx_http_lua_ssl_client_helloby.c b/src/ngx_http_lua_ssl_client_helloby.c index c56e830636..b600ab3636 100644 --- a/src/ngx_http_lua_ssl_client_helloby.c +++ b/src/ngx_http_lua_ssl_client_helloby.c @@ -193,7 +193,6 @@ ngx_http_lua_ssl_client_hello_handler(ngx_ssl_conn_t *ssl_conn, ngx_http_lua_ssl_ctx_t *cctx; ngx_http_core_srv_conf_t *cscf; - c = ngx_ssl_get_connection(ssl_conn); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, diff --git a/util/build.sh b/util/build.sh index 9dda855223..501f74bdb9 100755 --- a/util/build.sh +++ b/util/build.sh @@ -67,6 +67,6 @@ time ngx-build $force $version \ --with-http_dav_module \ --with-select_module \ --with-poll_module \ - $opts \ - --with-debug + $opts \ + --with-debug From 03d88830de4f7578c530e2a647c82e9d5904ec4d Mon Sep 17 00:00:00 2001 From: willmafh Date: Tue, 14 Oct 2025 13:15:45 +0800 Subject: [PATCH 240/254] feature: proxy_ssl_verify_by_lua directives. --- README.markdown | 96 ++ config | 2 + doc/HttpLuaModule.wiki | 13 + src/ngx_http_lua_common.h | 59 +- src/ngx_http_lua_control.c | 6 + src/ngx_http_lua_module.c | 57 ++ src/ngx_http_lua_proxy_ssl_verifyby.c | 754 ++++++++++++++ src/ngx_http_lua_proxy_ssl_verifyby.h | 41 + src/ngx_http_lua_ssl.h | 17 +- src/ngx_http_lua_util.c | 45 + src/ngx_http_lua_util.h | 46 + t/169-proxy-ssl-verify.t | 1332 +++++++++++++++++++++++++ 12 files changed, 2446 insertions(+), 22 deletions(-) create mode 100644 src/ngx_http_lua_proxy_ssl_verifyby.c create mode 100644 src/ngx_http_lua_proxy_ssl_verifyby.h create mode 100644 t/169-proxy-ssl-verify.t diff --git a/README.markdown b/README.markdown index 03a9a66055..8c6edec844 100644 --- a/README.markdown +++ b/README.markdown @@ -1171,6 +1171,8 @@ Directives * [ssl_session_fetch_by_lua_file](#ssl_session_fetch_by_lua_file) * [ssl_session_store_by_lua_block](#ssl_session_store_by_lua_block) * [ssl_session_store_by_lua_file](#ssl_session_store_by_lua_file) +* [proxy_ssl_verify_by_lua_block](#proxy_ssl_verify_by_lua_block) +* [proxy_ssl_verify_by_lua_file](#proxy_ssl_verify_by_lua_file) * [lua_shared_dict](#lua_shared_dict) * [lua_socket_connect_timeout](#lua_socket_connect_timeout) * [lua_socket_send_timeout](#lua_socket_send_timeout) @@ -1189,6 +1191,7 @@ Directives * [lua_ssl_verify_depth](#lua_ssl_verify_depth) * [lua_ssl_key_log](#lua_ssl_key_log) * [lua_ssl_conf_command](#lua_ssl_conf_command) +* [lua_upstream_skip_openssl_default_verify](#lua_upstream_skip_openssl_default_verify) * [lua_http10_buffering](#lua_http10_buffering) * [rewrite_by_lua_no_postpone](#rewrite_by_lua_no_postpone) * [access_by_lua_no_postpone](#access_by_lua_no_postpone) @@ -3165,6 +3168,84 @@ Note that: this directive is only allowed to used in **http context** from the ` [Back to TOC](#directives) +proxy_ssl_verify_by_lua_block +----------------------------- + +**syntax:** *proxy_ssl_verify_by_lua_block { lua-script }* + +**context:** *location* + +**phase:** *right-after-server-certificate-message-was-processed* + +This directive runs user Lua code when Nginx is about to post-process the SSL server certificate message for the upstream SSL (https) connections. + +It is particularly useful to parse upstream server certificate and do some custom operations in pure lua. + +The [ngx.ssl.proxysslverify](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ssl/proxysslverify.md) Lua modules provided by the [lua-resty-core](https://github.com/openresty/lua-resty-core/#readme) +library are particularly useful in this context. + +Below is a trivial example using the +[ngx.ssl.proxysslverify](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ssl/proxysslverify.md) module +at the same time: + +```nginx + + server { + listen 443 ssl; + server_name test.com; + ssl_certificate /path/to/cert.crt; + ssl_certificate_key /path/to/key.key; + + location /t { + proxy_ssl_certificate /path/to/cert.crt; + proxy_ssl_certificate_key /path/to/key.key; + proxy_pass https://upstream; + + proxy_ssl_verify_by_lua_block { + local proxy_ssl_vfy = require "ngx.ssl.proxysslverify" + local cert = proxy_ssl_vfy.get_verify_cert() + + -- ocsp to verify cert + -- check crl + proxy_ssl_vfy.set_verify_result() + ... + } + } + ... + } +``` + +See more information in the [ngx.ssl.proxysslverify](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ssl/proxysslverify.md) +Lua modules' official documentation. + +Uncaught Lua exceptions in the user Lua code immediately abort the current SSL session, so does the +[ngx.exit](#ngxexit) call with an error code like `ngx.ERROR`. + +This Lua code execution context *does* support yielding, so Lua APIs that may yield +(like cosockets, sleeping, and "light threads") +are enabled in this context + +Note, `ngx.ctx` in proxy_ssl_verify_by_lua_block is belonging to upstream connection, not downstream connection, so it's different from `ngx.ctx` in contexts like ssl_certificate_by_lua etc. + +This directive requires OpenSSL 3.0.2 or greater. + +[Back to TOC](#directives) + +proxy_ssl_verify_by_lua_file +---------------------------- + +**syntax:** *proxy_ssl_verify_by_lua_file <path-to-lua-script-file>* + +**context:** *location* + +**phase:** *right-after-server-certificate-message-was-processed* + +Equivalent to [proxy_ssl_verify_by_lua_block](#proxy_ssl_verify_by_lua_block), except that the file specified by `` contains the Lua code, or, as from the `v0.5.0rc32` release, the [LuaJIT bytecode](#luajit-bytecode-support) to be executed. + +When a relative path like `foo/bar.lua` is given, they will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option while starting the Nginx server. + +[Back to TOC](#directives) + lua_shared_dict --------------- @@ -3499,6 +3580,21 @@ This directive was first introduced in the `v0.10.21` release. +[Back to TOC](#directives) + +lua_upstream_skip_openssl_default_verify +-------------------- + +**syntax:** *lua_upstream_skip_openssl_default_verify on|off* + +**default:** *lua_upstream_skip_openssl_default_verify off* + +**context:** *location, location-if* + +When using proxy_ssl_verify_by_lua directive, `lua_upstream_skip_openssl_default_verify` controls whether to skip default openssl's verify function, that means using pure Lua code to verify upstream server certificate. + +This directive is turned `off` by default. + [Back to TOC](#directives) lua_http10_buffering diff --git a/config b/config index 24ebd126d6..7b1b061362 100644 --- a/config +++ b/config @@ -296,6 +296,7 @@ HTTP_LUA_SRCS=" \ $ngx_addon_dir/src/ngx_http_lua_ssl_session_storeby.c \ $ngx_addon_dir/src/ngx_http_lua_ssl_session_fetchby.c \ $ngx_addon_dir/src/ngx_http_lua_ssl.c \ + $ngx_addon_dir/src/ngx_http_lua_proxy_ssl_verifyby.c \ $ngx_addon_dir/src/ngx_http_lua_log_ringbuf.c \ $ngx_addon_dir/src/ngx_http_lua_input_filters.c \ $ngx_addon_dir/src/ngx_http_lua_pipe.c \ @@ -359,6 +360,7 @@ HTTP_LUA_DEPS=" \ $ngx_addon_dir/src/ngx_http_lua_ssl_session_storeby.h \ $ngx_addon_dir/src/ngx_http_lua_ssl_session_fetchby.h \ $ngx_addon_dir/src/ngx_http_lua_ssl.h \ + $ngx_addon_dir/src/ngx_http_lua_proxy_ssl_verifyby.h \ $ngx_addon_dir/src/ngx_http_lua_log_ringbuf.h \ $ngx_addon_dir/src/ngx_http_lua_input_filters.h \ $ngx_addon_dir/src/ngx_http_lua_pipe.h \ diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 69e1a86303..09af86f771 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -2960,6 +2960,19 @@ Note though that configuring OpenSSL directly with lua_ssl_conf_commandv0.10.21 release. +== lua_upstream_skip_openssl_default_verify == + +'''syntax:''' ''lua_upstream_skip_openssl_default_verify on|off'' + +'''default:''' ''lua_upstream_skip_openssl_default_verify off'' + +'''context:''' ''location, location-if'' + +When using proxy_ssl_verify_by_lua directive, `lua_upstream_skip_openssl_default_verify` controls whether to skip default openssl's verify function, that means using pure Lua code to verify upstream server certificate. + +This directive is turned off by default. + +[Back to TOC](#directives) == lua_http10_buffering == diff --git a/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h index 9db3e19ce5..40c330baff 100644 --- a/src/ngx_http_lua_common.h +++ b/src/ngx_http_lua_common.h @@ -131,23 +131,27 @@ typedef struct { (NGX_HTTP_LUA_FILE_TAG_LEN + 2 * MD5_DIGEST_LENGTH) -/* must be within 16 bit */ -#define NGX_HTTP_LUA_CONTEXT_SET 0x0001 -#define NGX_HTTP_LUA_CONTEXT_REWRITE 0x0002 -#define NGX_HTTP_LUA_CONTEXT_ACCESS 0x0004 -#define NGX_HTTP_LUA_CONTEXT_CONTENT 0x0008 -#define NGX_HTTP_LUA_CONTEXT_LOG 0x0010 -#define NGX_HTTP_LUA_CONTEXT_HEADER_FILTER 0x0020 -#define NGX_HTTP_LUA_CONTEXT_BODY_FILTER 0x0040 -#define NGX_HTTP_LUA_CONTEXT_TIMER 0x0080 -#define NGX_HTTP_LUA_CONTEXT_INIT_WORKER 0x0100 -#define NGX_HTTP_LUA_CONTEXT_BALANCER 0x0200 -#define NGX_HTTP_LUA_CONTEXT_SSL_CERT 0x0400 -#define NGX_HTTP_LUA_CONTEXT_SSL_SESS_STORE 0x0800 -#define NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH 0x1000 -#define NGX_HTTP_LUA_CONTEXT_EXIT_WORKER 0x2000 -#define NGX_HTTP_LUA_CONTEXT_SSL_CLIENT_HELLO 0x4000 -#define NGX_HTTP_LUA_CONTEXT_SERVER_REWRITE 0x8000 +/* must be within 32 bits */ +#define NGX_HTTP_LUA_CONTEXT_SET 0x00000001 +#define NGX_HTTP_LUA_CONTEXT_REWRITE 0x00000002 +#define NGX_HTTP_LUA_CONTEXT_ACCESS 0x00000004 +#define NGX_HTTP_LUA_CONTEXT_CONTENT 0x00000008 +#define NGX_HTTP_LUA_CONTEXT_LOG 0x00000010 +#define NGX_HTTP_LUA_CONTEXT_HEADER_FILTER 0x00000020 +#define NGX_HTTP_LUA_CONTEXT_BODY_FILTER 0x00000040 +#define NGX_HTTP_LUA_CONTEXT_TIMER 0x00000080 +#define NGX_HTTP_LUA_CONTEXT_INIT_WORKER 0x00000100 +#define NGX_HTTP_LUA_CONTEXT_BALANCER 0x00000200 +#define NGX_HTTP_LUA_CONTEXT_SSL_CERT 0x00000400 +#define NGX_HTTP_LUA_CONTEXT_SSL_SESS_STORE 0x00000800 +#define NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH 0x00001000 +#define NGX_HTTP_LUA_CONTEXT_EXIT_WORKER 0x00002000 +#define NGX_HTTP_LUA_CONTEXT_SSL_CLIENT_HELLO 0x00004000 +#define NGX_HTTP_LUA_CONTEXT_SERVER_REWRITE 0x00008000 + +#ifdef HAVE_PROXY_SSL_PATCH +#define NGX_HTTP_LUA_CONTEXT_PROXY_SSL_VERIFY 0x00010000 +#endif #define NGX_HTTP_LUA_FFI_NO_REQ_CTX -100 @@ -171,6 +175,8 @@ typedef struct ngx_http_lua_srv_conf_s ngx_http_lua_srv_conf_t; typedef struct ngx_http_lua_main_conf_s ngx_http_lua_main_conf_t; +typedef struct ngx_http_lua_loc_conf_s ngx_http_lua_loc_conf_t; + typedef struct ngx_http_lua_header_val_s ngx_http_lua_header_val_t; typedef struct ngx_http_lua_posted_thread_s ngx_http_lua_posted_thread_t; @@ -184,6 +190,9 @@ typedef ngx_int_t (*ngx_http_lua_main_conf_handler_pt)(ngx_log_t *log, typedef ngx_int_t (*ngx_http_lua_srv_conf_handler_pt)(ngx_http_request_t *r, ngx_http_lua_srv_conf_t *lscf, lua_State *L); +typedef ngx_int_t (*ngx_http_lua_loc_conf_handler_pt)(ngx_http_request_t *r, + ngx_http_lua_loc_conf_t *llcf, lua_State *L); + typedef ngx_int_t (*ngx_http_lua_set_header_pt)(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, ngx_str_t *value); @@ -369,7 +378,7 @@ struct ngx_http_lua_srv_conf_s { }; -typedef struct { +struct ngx_http_lua_loc_conf_s { #if (NGX_HTTP_SSL) ngx_ssl_t *ssl; /* shared by SSL cosockets */ ngx_array_t *ssl_certificates; @@ -383,6 +392,16 @@ typedef struct { #if (nginx_version >= 1019004) ngx_array_t *ssl_conf_commands; #endif + +#ifdef HAVE_PROXY_SSL_PATCH + ngx_http_lua_loc_conf_handler_pt proxy_ssl_verify_handler; + ngx_str_t proxy_ssl_verify_src; + u_char *proxy_ssl_verify_src_key; + u_char *proxy_ssl_verify_chunkname; + int proxy_ssl_verify_src_ref; + ngx_flag_t upstream_skip_openssl_default_verify; +#endif + #endif ngx_flag_t force_read_body; /* whether force request body to @@ -464,7 +483,7 @@ typedef struct { ngx_flag_t log_socket_errors; ngx_flag_t check_client_abort; ngx_flag_t use_default_type; -} ngx_http_lua_loc_conf_t; +}; typedef enum { @@ -628,7 +647,7 @@ typedef struct ngx_http_lua_ctx_s { int uthreads; /* number of active user threads */ - uint16_t context; /* the current running directive context + uint32_t context; /* the current running directive context (or running phase) for the current Lua chunk */ diff --git a/src/ngx_http_lua_control.c b/src/ngx_http_lua_control.c index d7e427385d..8358abcbb6 100644 --- a/src/ngx_http_lua_control.c +++ b/src/ngx_http_lua_control.c @@ -384,6 +384,9 @@ ngx_http_lua_ffi_exit(ngx_http_request_t *r, int status, u_char *err, | NGX_HTTP_LUA_CONTEXT_TIMER | NGX_HTTP_LUA_CONTEXT_HEADER_FILTER | NGX_HTTP_LUA_CONTEXT_BALANCER +#ifdef HAVE_PROXY_SSL_PATCH + | NGX_HTTP_LUA_CONTEXT_PROXY_SSL_VERIFY +#endif | NGX_HTTP_LUA_CONTEXT_SSL_CLIENT_HELLO | NGX_HTTP_LUA_CONTEXT_SSL_CERT | NGX_HTTP_LUA_CONTEXT_SSL_SESS_STORE @@ -395,6 +398,9 @@ ngx_http_lua_ffi_exit(ngx_http_request_t *r, int status, u_char *err, } if (ctx->context & (NGX_HTTP_LUA_CONTEXT_SSL_CERT +#ifdef HAVE_PROXY_SSL_PATCH + | NGX_HTTP_LUA_CONTEXT_PROXY_SSL_VERIFY +#endif | NGX_HTTP_LUA_CONTEXT_SSL_CLIENT_HELLO | NGX_HTTP_LUA_CONTEXT_SSL_SESS_STORE | NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH)) diff --git a/src/ngx_http_lua_module.c b/src/ngx_http_lua_module.c index cae92b21ee..16726abbe1 100644 --- a/src/ngx_http_lua_module.c +++ b/src/ngx_http_lua_module.c @@ -31,6 +31,11 @@ #include "ngx_http_lua_ssl_certby.h" #include "ngx_http_lua_ssl_session_storeby.h" #include "ngx_http_lua_ssl_session_fetchby.h" + +#ifdef HAVE_PROXY_SSL_PATCH +#include "ngx_http_lua_proxy_ssl_verifyby.h" +#endif + #include "ngx_http_lua_headers.h" #include "ngx_http_lua_headers_out.h" #if !(NGX_WIN32) @@ -660,6 +665,30 @@ static ngx_command_t ngx_http_lua_cmds[] = { 0, (void *) ngx_http_lua_ssl_sess_fetch_handler_file }, +#ifdef HAVE_PROXY_SSL_PATCH + /* same context as proxy_pass directive */ + { ngx_string("proxy_ssl_verify_by_lua_block"), + NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS, + ngx_http_lua_proxy_ssl_verify_by_lua_block, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + (void *) ngx_http_lua_proxy_ssl_verify_handler_inline }, + + { ngx_string("proxy_ssl_verify_by_lua_file"), + NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1, + ngx_http_lua_proxy_ssl_verify_by_lua, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + (void *) ngx_http_lua_proxy_ssl_verify_handler_file }, + + { ngx_string("lua_upstream_skip_openssl_default_verify"), + NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_lua_loc_conf_t, upstream_skip_openssl_default_verify), + NULL }, +#endif + { ngx_string("lua_ssl_verify_depth"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_num_slot, @@ -1446,6 +1475,11 @@ ngx_http_lua_create_loc_conf(ngx_conf_t *cf) * conf->ssl_trusted_certificate = { 0, NULL }; * conf->ssl_crl = { 0, NULL }; * conf->ssl_key_log = { 0, NULL }; + * + * conf->proxy_ssl_verify_handler = NULL; + * conf->proxy_ssl_verify_src = { 0, NULL }; + * conf->proxy_ssl_verify_chunkname = NULL; + * conf->proxy_ssl_verify_src_key = NULL; */ conf->force_read_body = NGX_CONF_UNSET; @@ -1479,6 +1513,10 @@ ngx_http_lua_create_loc_conf(ngx_conf_t *cf) #if (nginx_version >= 1019004) conf->ssl_conf_commands = NGX_CONF_UNSET_PTR; #endif +#ifdef HAVE_PROXY_SSL_PATCH + conf->proxy_ssl_verify_src_ref = LUA_REFNIL; + conf->upstream_skip_openssl_default_verify = NGX_CONF_UNSET; +#endif #endif return conf; @@ -1573,6 +1611,25 @@ ngx_http_lua_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) NULL); #endif +#ifdef HAVE_PROXY_SSL_PATCH + if (conf->proxy_ssl_verify_src.len == 0) { + conf->proxy_ssl_verify_src = prev->proxy_ssl_verify_src; + conf->proxy_ssl_verify_handler = prev->proxy_ssl_verify_handler; + conf->proxy_ssl_verify_src_ref = prev->proxy_ssl_verify_src_ref; + conf->proxy_ssl_verify_src_key = prev->proxy_ssl_verify_src_key; + conf->proxy_ssl_verify_chunkname = prev->proxy_ssl_verify_chunkname; + } + + if (conf->proxy_ssl_verify_src.len) { + if (ngx_http_lua_proxy_ssl_verify_set_callback(cf) != NGX_OK) { + return NGX_CONF_ERROR; + } + } + + ngx_conf_merge_value(conf->upstream_skip_openssl_default_verify, + prev->upstream_skip_openssl_default_verify, 0); +#endif + if (ngx_http_lua_set_ssl(cf, conf) != NGX_OK) { return NGX_CONF_ERROR; } diff --git a/src/ngx_http_lua_proxy_ssl_verifyby.c b/src/ngx_http_lua_proxy_ssl_verifyby.c new file mode 100644 index 0000000000..1695e56ffb --- /dev/null +++ b/src/ngx_http_lua_proxy_ssl_verifyby.c @@ -0,0 +1,754 @@ +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + + +#if (NGX_HTTP_SSL) + + +#include "ngx_http_lua_cache.h" +#include "ngx_http_lua_initworkerby.h" +#include "ngx_http_lua_util.h" +#include "ngx_http_ssl_module.h" +#include "ngx_http_lua_contentby.h" +#include "ngx_http_lua_directive.h" +#include "ngx_http_lua_ssl.h" + +#ifdef HAVE_PROXY_SSL_PATCH +#include "ngx_http_lua_proxy_ssl_verifyby.h" + + +static void ngx_http_lua_proxy_ssl_verify_done(void *data); +static void ngx_http_lua_proxy_ssl_verify_aborted(void *data); +static ngx_int_t ngx_http_lua_proxy_ssl_verify_by_chunk(lua_State *L, + ngx_http_request_t *r); + + +ngx_int_t +ngx_http_lua_proxy_ssl_verify_set_callback(ngx_conf_t *cf) +{ + +#ifdef LIBRESSL_VERSION_NUMBER + + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "LibreSSL does not support by proxy_ssl_verify_by_lua*"); + + return NGX_ERROR; + +#else + + void *plcf; + ngx_http_upstream_conf_t *ucf; + ngx_ssl_t *ssl; + + /* + * Nginx doesn't export ngx_http_proxy_loc_conf_t, so we can't directly + * get plcf here, but the first member of plcf is ngx_http_upstream_conf_t + */ + plcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_proxy_module); + ucf = plcf; + + ssl = ucf->ssl; + + if (!ssl->ctx) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "proxy_ssl_verify_by_lua* " + "should be used with proxy_pass https url"); + + return NGX_ERROR; + } + +#if (!defined SSL_ERROR_WANT_RETRY_VERIFY \ + || OPENSSL_VERSION_NUMBER < 0x30000020L) + + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "OpenSSL too old to support " + "proxy_ssl_verify_by_lua*"); + + return NGX_ERROR; + +#else + + SSL_CTX_set_cert_verify_callback(ssl->ctx, + ngx_http_lua_proxy_ssl_verify_handler, + NULL); + return NGX_OK; + +#endif + +#endif +} + + +ngx_int_t +ngx_http_lua_proxy_ssl_verify_handler_file(ngx_http_request_t *r, + ngx_http_lua_loc_conf_t *llcf, lua_State *L) +{ + ngx_int_t rc; + + rc = ngx_http_lua_cache_loadfile(r->connection->log, L, + llcf->proxy_ssl_verify_src.data, + &llcf->proxy_ssl_verify_src_ref, + llcf->proxy_ssl_verify_src_key); + if (rc != NGX_OK) { + return rc; + } + + /* make sure we have a valid code chunk */ + ngx_http_lua_assert(lua_isfunction(L, -1)); + + return ngx_http_lua_proxy_ssl_verify_by_chunk(L, r); +} + + +ngx_int_t +ngx_http_lua_proxy_ssl_verify_handler_inline(ngx_http_request_t *r, + ngx_http_lua_loc_conf_t *llcf, lua_State *L) +{ + ngx_int_t rc; + + rc = ngx_http_lua_cache_loadbuffer(r->connection->log, L, + llcf->proxy_ssl_verify_src.data, + llcf->proxy_ssl_verify_src.len, + &llcf->proxy_ssl_verify_src_ref, + llcf->proxy_ssl_verify_src_key, + (const char *) llcf->proxy_ssl_verify_chunkname); + if (rc != NGX_OK) { + return rc; + } + + /* make sure we have a valid code chunk */ + ngx_http_lua_assert(lua_isfunction(L, -1)); + + return ngx_http_lua_proxy_ssl_verify_by_chunk(L, r); +} + + +char * +ngx_http_lua_proxy_ssl_verify_by_lua_block(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + char *rv; + ngx_conf_t save; + + save = *cf; + cf->handler = ngx_http_lua_proxy_ssl_verify_by_lua; + cf->handler_conf = conf; + + rv = ngx_http_lua_conf_lua_block_parse(cf, cmd); + + *cf = save; + + return rv; +} + + +char * +ngx_http_lua_proxy_ssl_verify_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ +#if (!defined SSL_ERROR_WANT_RETRY_VERIFY \ + || OPENSSL_VERSION_NUMBER < 0x30000020L) + + /* SSL_set_retry_verify() was added in OpenSSL 3.0.2 */ + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "at least OpenSSL 3.0.2 required but found " + OPENSSL_VERSION_TEXT); + + return NGX_CONF_ERROR; + +#else + + size_t chunkname_len; + u_char *chunkname; + u_char *cache_key = NULL; + u_char *name; + ngx_str_t *value; + ngx_http_lua_loc_conf_t *llcf = conf; + + /* must specify a concrete handler */ + if (cmd->post == NULL) { + return NGX_CONF_ERROR; + } + + if (llcf->proxy_ssl_verify_handler) { + return "is duplicate"; + } + + if (ngx_http_lua_ssl_init(cf->log) != NGX_OK) { + return NGX_CONF_ERROR; + } + + value = cf->args->elts; + + llcf->proxy_ssl_verify_handler = + (ngx_http_lua_loc_conf_handler_pt) cmd->post; + + if (cmd->post == ngx_http_lua_proxy_ssl_verify_handler_file) { + /* Lua code in an external file */ + + name = ngx_http_lua_rebase_path(cf->pool, value[1].data, + value[1].len); + if (name == NULL) { + return NGX_CONF_ERROR; + } + + cache_key = ngx_http_lua_gen_file_cache_key(cf, value[1].data, + value[1].len); + if (cache_key == NULL) { + return NGX_CONF_ERROR; + } + + llcf->proxy_ssl_verify_src.data = name; + llcf->proxy_ssl_verify_src.len = ngx_strlen(name); + + } else { + cache_key = ngx_http_lua_gen_chunk_cache_key(cf, + "proxy_ssl_verify_by_lua", + value[1].data, + value[1].len); + if (cache_key == NULL) { + return NGX_CONF_ERROR; + } + + chunkname = ngx_http_lua_gen_chunk_name(cf, "proxy_ssl_verify_by_lua", + sizeof("proxy_ssl_verify_by_lua") - 1, + &chunkname_len); + if (chunkname == NULL) { + return NGX_CONF_ERROR; + } + + /* Don't eval nginx variables for inline lua code */ + llcf->proxy_ssl_verify_src = value[1]; + llcf->proxy_ssl_verify_chunkname = chunkname; + } + + llcf->proxy_ssl_verify_src_key = cache_key; + + return NGX_CONF_OK; + +#endif /* SSL_ERROR_WANT_RETRY_VERIFY */ +} + + +int +ngx_http_lua_proxy_ssl_verify_handler(X509_STORE_CTX *x509_store, void *arg) +{ + lua_State *L; + ngx_int_t rc; + ngx_connection_t *c; + ngx_http_request_t *r = NULL; + ngx_pool_cleanup_t *cln; + ngx_http_lua_loc_conf_t *llcf; + ngx_http_lua_ssl_ctx_t *cctx; + ngx_ssl_conn_t *ssl_conn; + + ssl_conn = X509_STORE_CTX_get_ex_data(x509_store, + SSL_get_ex_data_X509_STORE_CTX_idx()); + + c = ngx_ssl_get_connection(ssl_conn); /* upstream connection */ + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "proxy ssl verify: connection reusable: %ud", c->reusable); + + cctx = ngx_http_lua_ssl_get_ctx(c->ssl->connection); + + dd("proxy ssl verify handler, cert-verify-ctx=%p", cctx); + + if (cctx && cctx->entered_proxy_ssl_verify_handler) { + /* not the first time */ + + if (cctx->done) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "proxy_ssl_verify_by_lua: " + "cert verify callback exit code: %d", + cctx->exit_code); + + dd("lua proxy ssl verify done, finally"); + return cctx->exit_code; + } + + return SSL_set_retry_verify(ssl_conn); + } + + dd("first time"); + +#if (nginx_version < 1017009) + ngx_reusable_connection(c, 0); +#endif + + r = c->data; + + if (cctx == NULL) { + cctx = ngx_pcalloc(c->pool, sizeof(ngx_http_lua_ssl_ctx_t)); + if (cctx == NULL) { + goto failed; /* error */ + } + + cctx->ctx_ref = LUA_NOREF; + } + + cctx->connection = c; + cctx->request = r; + cctx->x509_store = x509_store; + cctx->exit_code = 1; /* successful by default */ + cctx->original_request_count = r->main->count; + cctx->done = 0; + cctx->entered_proxy_ssl_verify_handler = 1; + cctx->pool = ngx_create_pool(128, c->log); + if (cctx->pool == NULL) { + goto failed; + } + + dd("setting cctx"); + + if (SSL_set_ex_data(c->ssl->connection, ngx_http_lua_ssl_ctx_index, + cctx) == 0) + { + ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "SSL_set_ex_data() failed"); + goto failed; + } + + llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); + if (llcf->upstream_skip_openssl_default_verify == 0) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, + "proxy_ssl_verify_by_lua: openssl default verify"); + + rc = X509_verify_cert(x509_store); + if (rc == 0) { + goto failed; + } + } + + /* TODO honor lua_code_cache off */ + L = ngx_http_lua_get_lua_vm(r, NULL); + + c->log->action = "loading proxy ssl verify by lua"; + + rc = llcf->proxy_ssl_verify_handler(r, llcf, L); + + if (rc >= NGX_OK || rc == NGX_ERROR) { + cctx->done = 1; + + if (cctx->cleanup) { + *cctx->cleanup = NULL; + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, + "proxy_ssl_verify_by_lua: handler return value: %i, " + "cert verify callback exit code: %d", rc, cctx->exit_code); + + c->log->action = "proxy pass SSL handshaking"; + return cctx->exit_code; + } + + /* rc == NGX_DONE */ + + cln = ngx_pool_cleanup_add(cctx->pool, 0); + if (cln == NULL) { + goto failed; + } + + cln->handler = ngx_http_lua_proxy_ssl_verify_done; + cln->data = cctx; + + if (cctx->cleanup == NULL) { + cln = ngx_pool_cleanup_add(c->pool, 0); + if (cln == NULL) { + goto failed; + } + + cln->data = cctx; + cctx->cleanup = &cln->handler; + } + + *cctx->cleanup = ngx_http_lua_proxy_ssl_verify_aborted; + + return SSL_set_retry_verify(ssl_conn); + +failed: + if (cctx && cctx->pool) { + ngx_destroy_pool(cctx->pool); + } + + return 0; /* verify failure or error */ +} + + +static void +ngx_http_lua_proxy_ssl_verify_done(void *data) +{ + ngx_connection_t *c; + ngx_http_lua_ssl_ctx_t *cctx = data; + + dd("lua proxy ssl verify done"); + + if (cctx->aborted) { + return; + } + + ngx_http_lua_assert(cctx->done == 0); + + cctx->done = 1; + + if (cctx->cleanup) { + *cctx->cleanup = NULL; + } + + c = cctx->connection; + + if (c->read->timer_set) { + ngx_del_timer(c->read); + } + + if (c->write->timer_set) { + ngx_del_timer(c->write); + } + + c->log->action = "proxy pass SSL handshaking"; + + ngx_post_event(c->write, &ngx_posted_events); +} + + +static void +ngx_http_lua_proxy_ssl_verify_aborted(void *data) +{ + ngx_http_lua_ssl_ctx_t *cctx = data; + + dd("lua proxy ssl verify aborted"); + + if (cctx->done) { + /* completed successfully already */ + return; + } + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cctx->connection->log, 0, + "proxy_ssl_verify_by_lua: cert verify callback aborted"); + + cctx->aborted = 1; + cctx->connection->ssl = NULL; + cctx->exit_code = 0; + if (cctx->pool) { + ngx_destroy_pool(cctx->pool); + cctx->pool = NULL; + } +} + + +static ngx_int_t +ngx_http_lua_proxy_ssl_verify_by_chunk(lua_State *L, ngx_http_request_t *r) +{ + int co_ref; + ngx_int_t rc; + lua_State *co; + ngx_http_lua_ctx_t *ctx; + ngx_pool_cleanup_t *cln; + ngx_http_upstream_t *u; + ngx_connection_t *c; + ngx_http_lua_ssl_ctx_t *cctx; + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + + if (ctx == NULL) { + ctx = ngx_http_lua_create_ctx(r); + if (ctx == NULL) { + rc = NGX_ERROR; + ngx_http_lua_finalize_request(r, rc); + return rc; + } + + } else { + dd("reset ctx"); + ngx_http_lua_reset_ctx(r, L, ctx); + } + + ctx->entered_content_phase = 1; + + /* {{{ new coroutine to handle request */ + co = ngx_http_lua_new_thread(r, L, &co_ref); + + if (co == NULL) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "lua: failed to create new coroutine to handle request"); + + rc = NGX_ERROR; + ngx_http_lua_finalize_request(r, rc); + return rc; + } + + /* move code closure to new coroutine */ + lua_xmove(L, co, 1); + +#ifndef OPENRESTY_LUAJIT + /* set closure's env table to new coroutine's globals table */ + ngx_http_lua_get_globals_table(co); + lua_setfenv(co, -2); +#endif + + /* save nginx request in coroutine globals table */ + ngx_http_lua_set_req(co, r); + + ctx->cur_co_ctx = &ctx->entry_co_ctx; + ctx->cur_co_ctx->co = co; + ctx->cur_co_ctx->co_ref = co_ref; +#ifdef NGX_LUA_USE_ASSERT + ctx->cur_co_ctx->co_top = 1; +#endif + + ngx_http_lua_attach_co_ctx_to_L(co, ctx->cur_co_ctx); + + /* register request cleanup hooks */ + if (ctx->cleanup == NULL) { + u = r->upstream; + c = u->peer.connection; + cctx = ngx_http_lua_ssl_get_ctx(c->ssl->connection); + + cln = ngx_pool_cleanup_add(cctx->pool, 0); + if (cln == NULL) { + rc = NGX_ERROR; + ngx_http_lua_finalize_request(r, rc); + return rc; + } + + cln->handler = ngx_http_lua_request_cleanup_handler; + cln->data = ctx; + ctx->cleanup = &cln->handler; + } + + ctx->context = NGX_HTTP_LUA_CONTEXT_PROXY_SSL_VERIFY; + + rc = ngx_http_lua_run_thread(L, r, ctx, 0); + + if (rc == NGX_ERROR || rc >= NGX_OK) { + /* do nothing */ + + } else if (rc == NGX_AGAIN) { + rc = ngx_http_lua_content_run_posted_threads(L, r, ctx, 0); + + } else if (rc == NGX_DONE) { + rc = ngx_http_lua_content_run_posted_threads(L, r, ctx, 1); + + } else { + rc = NGX_OK; + } + + ngx_http_lua_finalize_request(r, rc); + return rc; +} + + +/* + * openssl's doc of SSL_CTX_set_cert_verify_callback: + * In any case a viable verification result value must + * be reflected in the error member of x509_store_ctx, + * which can be done using X509_STORE_CTX_set_error. + */ +int +ngx_http_lua_ffi_proxy_ssl_set_verify_result(ngx_http_request_t *r, + int verify_result, char **err) +{ +#ifdef SSL_ERROR_WANT_RETRY_VERIFY + ngx_http_upstream_t *u; + ngx_ssl_conn_t *ssl_conn; + ngx_connection_t *c; + ngx_http_lua_ssl_ctx_t *cctx; + X509_STORE_CTX *x509_store; + + u = r->upstream; + if (u == NULL) { + *err = "bad request"; + return NGX_ERROR; + } + + c = u->peer.connection; + if (c == NULL || c->ssl == NULL) { + *err = "bad upstream connection"; + return NGX_ERROR; + } + + ssl_conn = c->ssl->connection; + if (ssl_conn == NULL) { + *err = "bad ssl conn"; + return NGX_ERROR; + } + + dd("get cctx session"); + + c = ngx_ssl_get_connection(ssl_conn); + + cctx = ngx_http_lua_ssl_get_ctx(c->ssl->connection); + if (cctx == NULL) { + *err = "bad lua context"; + return NGX_ERROR; + } + + x509_store = cctx->x509_store; + + X509_STORE_CTX_set_error(x509_store, verify_result); + + return NGX_OK; +#else + *err = "OpenSSL too old to support this function"; + + return NGX_ERROR; +#endif +} + + +int +ngx_http_lua_ffi_proxy_ssl_get_verify_result(ngx_http_request_t *r, char **err) +{ +#ifdef SSL_ERROR_WANT_RETRY_VERIFY + ngx_http_upstream_t *u; + ngx_ssl_conn_t *ssl_conn; + ngx_connection_t *c; + ngx_http_lua_ssl_ctx_t *cctx; + X509_STORE_CTX *x509_store; + + u = r->upstream; + if (u == NULL) { + *err = "bad request"; + return NGX_ERROR; + } + + c = u->peer.connection; + if (c == NULL || c->ssl == NULL) { + *err = "bad upstream connection"; + return NGX_ERROR; + } + + ssl_conn = c->ssl->connection; + if (ssl_conn == NULL) { + *err = "bad ssl conn"; + return NGX_ERROR; + } + + dd("get cctx session"); + + c = ngx_ssl_get_connection(ssl_conn); + + cctx = ngx_http_lua_ssl_get_ctx(c->ssl->connection); + if (cctx == NULL) { + *err = "bad lua context"; + return NGX_ERROR; + } + + x509_store = cctx->x509_store; + + return X509_STORE_CTX_get_error(x509_store); +#else + *err = "OpenSSL too old to support this function"; + + return NGX_ERROR; +#endif +} + + +void +ngx_http_lua_ffi_proxy_ssl_free_verify_cert(void *cdata) +{ + X509 *cert = cdata; + + X509_free(cert); +} + + +void * +ngx_http_lua_ffi_proxy_ssl_get_verify_cert(ngx_http_request_t *r, char **err) +{ +#ifdef SSL_ERROR_WANT_RETRY_VERIFY + ngx_http_upstream_t *u; + ngx_ssl_conn_t *ssl_conn; + ngx_connection_t *c; + ngx_http_lua_ssl_ctx_t *cctx; + X509_STORE_CTX *x509_store; + X509 *x509; + + u = r->upstream; + if (u == NULL) { + *err = "bad request"; + return NULL; + } + + c = u->peer.connection; + if (c == NULL || c->ssl == NULL) { + *err = "bad upstream connection"; + return NULL; + } + + ssl_conn = c->ssl->connection; + if (ssl_conn == NULL) { + *err = "bad ssl conn"; + return NULL; + } + + dd("get cctx session"); + + c = ngx_ssl_get_connection(ssl_conn); + + cctx = ngx_http_lua_ssl_get_ctx(c->ssl->connection); + if (cctx == NULL) { + *err = "bad lua context"; + return NULL; + } + + x509_store = cctx->x509_store; + + x509 = X509_STORE_CTX_get0_cert(x509_store); + + if (!X509_up_ref(x509)) { + *err = "get verify result failed"; + return NULL; + } + + return x509; +#else + *err = "OpenSSL too old to support this function"; + + return NULL; +#endif +} + + +#else /* HAVE_PROXY_SSL_PATCH */ + + +int +ngx_http_lua_ffi_proxy_ssl_set_verify_result(ngx_http_request_t *r, + int verify_result, char **err) +{ + *err = "Does not have HAVE_PROXY_SSL_PATCH to support this function"; + + return NGX_ERROR; +} + + +int +ngx_http_lua_ffi_proxy_ssl_get_verify_result(ngx_http_request_t *r, char **err) +{ + *err = "Does not have HAVE_PROXY_SSL_PATCH to support this function"; + + return NGX_ERROR; +} + + +void +ngx_http_lua_ffi_proxy_ssl_free_verify_cert(void *cdata) +{ +} + + +void * +ngx_http_lua_ffi_proxy_ssl_get_verify_cert(ngx_http_request_t *r, char **err) +{ + *err = "Does not have HAVE_PROXY_SSL_PATCH to support this function"; + + return NULL; +} + +#endif /* HAVE_PROXY_SSL_PATCH */ +#endif /* NGX_HTTP_SSL */ diff --git a/src/ngx_http_lua_proxy_ssl_verifyby.h b/src/ngx_http_lua_proxy_ssl_verifyby.h new file mode 100644 index 0000000000..3e0b178dee --- /dev/null +++ b/src/ngx_http_lua_proxy_ssl_verifyby.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + +#ifndef _NGX_HTTP_LUA_PROXY_SSL_VERIFYBY_H_INCLUDED_ +#define _NGX_HTTP_LUA_PROXY_SSL_VERIFYBY_H_INCLUDED_ + + +#include "ngx_http_lua_common.h" + + +#if (NGX_HTTP_SSL) +#ifdef HAVE_PROXY_SSL_PATCH + +/* do not introduce ngx_http_proxy_module to pollute ngx_http_lua_module.c */ +extern ngx_module_t ngx_http_proxy_module; + +ngx_int_t ngx_http_lua_proxy_ssl_verify_handler_inline(ngx_http_request_t *r, + ngx_http_lua_loc_conf_t *llcf, lua_State *L); + +ngx_int_t ngx_http_lua_proxy_ssl_verify_handler_file(ngx_http_request_t *r, + ngx_http_lua_loc_conf_t *llcf, lua_State *L); + +char *ngx_http_lua_proxy_ssl_verify_by_lua_block(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); + +char *ngx_http_lua_proxy_ssl_verify_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); + +int ngx_http_lua_proxy_ssl_verify_handler(X509_STORE_CTX *x509_store, + void *arg); + +ngx_int_t ngx_http_lua_proxy_ssl_verify_set_callback(ngx_conf_t *cf); + +#endif /* HAVE_PROXY_SSL_PATCH */ +#endif /* NGX_HTTP_SSL */ + + +#endif /* _NGX_HTTP_LUA_PROXY_SSL_VERIFYBY_H_INCLUDED_ */ + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_ssl.h b/src/ngx_http_lua_ssl.h index 1ee0a3626c..f709e6530f 100644 --- a/src/ngx_http_lua_ssl.h +++ b/src/ngx_http_lua_ssl.h @@ -16,7 +16,7 @@ typedef struct { ngx_connection_t *connection; /* original true connection */ - ngx_http_request_t *request; /* fake request */ + ngx_http_request_t *request; ngx_pool_cleanup_pt *cleanup; ngx_ssl_session_t *session; /* return value for openssl's @@ -24,20 +24,33 @@ typedef struct { ngx_str_t session_id; +#ifdef HAVE_PROXY_SSL_PATCH + X509_STORE_CTX *x509_store; + ngx_pool_t *pool; +#endif + int exit_code; /* exit code for openssl's set_client_hello_cb or - set_cert_cb callback */ + set_cert_cb callback or + SSL_CTX_set_cert_verify_callback */ int ctx_ref; /* reference to anchor request ctx data in lua registry */ +#ifdef HAVE_PROXY_SSL_PATCH + /* same size as count field of ngx_http_request_t */ + unsigned original_request_count:16; +#endif unsigned done:1; unsigned aborted:1; unsigned entered_client_hello_handler:1; unsigned entered_cert_handler:1; unsigned entered_sess_fetch_handler:1; +#ifdef HAVE_PROXY_SSL_PATCH + unsigned entered_proxy_ssl_verify_handler:1; +#endif } ngx_http_lua_ssl_ctx_t; diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 5bc3b02807..928a15beed 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -1682,6 +1682,11 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, NGX_ERROR : NGX_HTTP_INTERNAL_SERVER_ERROR; done: +#ifdef HAVE_PROXY_SSL_PATCH + if (ctx->context == NGX_HTTP_LUA_CONTEXT_PROXY_SSL_VERIFY) { + return NGX_OK; + } +#endif if (ctx->entered_content_phase && r->connection->fd != (ngx_socket_t) -1) @@ -2438,6 +2443,12 @@ ngx_http_lua_handle_exit(lua_State *L, ngx_http_request_t *r, return ctx->exit_code; } +#ifdef HAVE_PROXY_SSL_PATCH + if (ctx->context == NGX_HTTP_LUA_CONTEXT_PROXY_SSL_VERIFY) { + return ctx->exit_code; + } +#endif + #if 1 if (!r->header_sent && !ctx->header_sent @@ -3673,12 +3684,46 @@ void ngx_http_lua_finalize_request(ngx_http_request_t *r, ngx_int_t rc) { ngx_http_lua_ctx_t *ctx; +#if (NGX_HTTP_SSL) +#ifdef HAVE_PROXY_SSL_PATCH + ngx_http_upstream_t *u; + ngx_connection_t *c; + ngx_http_lua_ssl_ctx_t *cctx; +#endif +#endif ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx && ctx->cur_co_ctx) { ngx_http_lua_cleanup_pending_operation(ctx->cur_co_ctx); } +#if (NGX_HTTP_SSL) +#ifdef HAVE_PROXY_SSL_PATCH + u = r->upstream; + if (u) { + c = u->peer.connection; + if (c && c->ssl) { + cctx = ngx_http_lua_ssl_get_ctx(c->ssl->connection); + if (cctx && cctx->pool) { + if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { + cctx->exit_code = 0; + } + + if (r->main->count > cctx->original_request_count) { + r->main->count--; + return; + } + + ngx_destroy_pool(cctx->pool); + cctx->pool = NULL; + + return; + } + } + } +#endif +#endif + if (r->connection->fd != (ngx_socket_t) -1) { ngx_http_finalize_request(r, rc); return; diff --git a/src/ngx_http_lua_util.h b/src/ngx_http_lua_util.h index eab4d4eba2..9d7a0bd1a3 100644 --- a/src/ngx_http_lua_util.h +++ b/src/ngx_http_lua_util.h @@ -32,6 +32,20 @@ #define NGX_HTTP_LUA_ESCAPE_HEADER_VALUE 8 +#ifdef HAVE_PROXY_SSL_PATCH + +#define NGX_HTTP_LUA_CONTEXT_YIELDABLE (NGX_HTTP_LUA_CONTEXT_REWRITE \ + | NGX_HTTP_LUA_CONTEXT_SERVER_REWRITE \ + | NGX_HTTP_LUA_CONTEXT_ACCESS \ + | NGX_HTTP_LUA_CONTEXT_CONTENT \ + | NGX_HTTP_LUA_CONTEXT_TIMER \ + | NGX_HTTP_LUA_CONTEXT_PROXY_SSL_VERIFY \ + | NGX_HTTP_LUA_CONTEXT_SSL_CLIENT_HELLO \ + | NGX_HTTP_LUA_CONTEXT_SSL_CERT \ + | NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH) + +#else + #define NGX_HTTP_LUA_CONTEXT_YIELDABLE (NGX_HTTP_LUA_CONTEXT_REWRITE \ | NGX_HTTP_LUA_CONTEXT_SERVER_REWRITE \ | NGX_HTTP_LUA_CONTEXT_ACCESS \ @@ -41,11 +55,15 @@ | NGX_HTTP_LUA_CONTEXT_SSL_CERT \ | NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH) +#endif /* HAVE_PROXY_SSL_PATCH */ + /* key in Lua vm registry for all the "ngx.ctx" tables */ #define ngx_http_lua_ctx_tables_key "ngx_lua_ctx_tables" +#ifdef HAVE_PROXY_SSL_PATCH + #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*" \ @@ -59,6 +77,8 @@ : (c) == NGX_HTTP_LUA_CONTEXT_INIT_WORKER ? "init_worker_by_lua*" \ : (c) == NGX_HTTP_LUA_CONTEXT_EXIT_WORKER ? "exit_worker_by_lua*" \ : (c) == NGX_HTTP_LUA_CONTEXT_BALANCER ? "balancer_by_lua*" \ + : (c) == NGX_HTTP_LUA_CONTEXT_PROXY_SSL_VERIFY ? \ + "proxy_ssl_verify_by_lua*" \ : (c) == NGX_HTTP_LUA_CONTEXT_SSL_CLIENT_HELLO ? \ "ssl_client_hello_by_lua*" \ : (c) == NGX_HTTP_LUA_CONTEXT_SSL_CERT ? "ssl_certificate_by_lua*" \ @@ -68,6 +88,32 @@ "ssl_session_fetch_by_lua*" \ : "(unknown)") +#else + +#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*" \ + : (c) == NGX_HTTP_LUA_CONTEXT_SERVER_REWRITE ? "server_rewrite_by_lua*" \ + : (c) == NGX_HTTP_LUA_CONTEXT_ACCESS ? "access_by_lua*" \ + : (c) == NGX_HTTP_LUA_CONTEXT_CONTENT ? "content_by_lua*" \ + : (c) == NGX_HTTP_LUA_CONTEXT_LOG ? "log_by_lua*" \ + : (c) == NGX_HTTP_LUA_CONTEXT_HEADER_FILTER ? "header_filter_by_lua*" \ + : (c) == NGX_HTTP_LUA_CONTEXT_BODY_FILTER ? "body_filter_by_lua*" \ + : (c) == NGX_HTTP_LUA_CONTEXT_TIMER ? "ngx.timer" \ + : (c) == NGX_HTTP_LUA_CONTEXT_INIT_WORKER ? "init_worker_by_lua*" \ + : (c) == NGX_HTTP_LUA_CONTEXT_EXIT_WORKER ? "exit_worker_by_lua*" \ + : (c) == NGX_HTTP_LUA_CONTEXT_BALANCER ? "balancer_by_lua*" \ + : (c) == NGX_HTTP_LUA_CONTEXT_SSL_CLIENT_HELLO ? \ + "ssl_client_hello_by_lua*" \ + : (c) == NGX_HTTP_LUA_CONTEXT_SSL_CERT ? "ssl_certificate_by_lua*" \ + : (c) == NGX_HTTP_LUA_CONTEXT_SSL_SESS_STORE ? \ + "ssl_session_store_by_lua*" \ + : (c) == NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH ? \ + "ssl_session_fetch_by_lua*" \ + : "(unknown)") + +#endif /* HAVE_PROXY_SSL_PATCH */ + #define ngx_http_lua_check_context(L, ctx, flags) \ if (!((ctx)->context & (flags))) { \ diff --git a/t/169-proxy-ssl-verify.t b/t/169-proxy-ssl-verify.t new file mode 100644 index 0000000000..4c44a8b9be --- /dev/null +++ b/t/169-proxy-ssl-verify.t @@ -0,0 +1,1332 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use Test::Nginx::Socket::Lua; + +repeat_each(3); + +# All these tests need to have new openssl +my $NginxBinary = $ENV{'TEST_NGINX_BINARY'} || 'nginx'; +my $openssl_version = eval { `$NginxBinary -V 2>&1` }; + +if ($openssl_version =~ m/built with OpenSSL (0\S*|1\.0\S*|1\.1\.0\S*)/) { + plan(skip_all => "too old OpenSSL, need 1.1.1, was $1"); +} elsif ($openssl_version =~ m/running with BoringSSL/) { + plan(skip_all => "does not support BoringSSL"); +} elsif ($ENV{TEST_NGINX_USE_HTTP3}) { + plan tests => repeat_each() * (blocks() * 6 + 6); +} else { + plan tests => repeat_each() * (blocks() * 5 + 10); +} + +$ENV{TEST_NGINX_HTML_DIR} ||= html_dir(); +$ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; +$ENV{TEST_NGINX_QUIC_IDLE_TIMEOUT} ||= 0.6; + +#log_level 'warn'; +log_level 'debug'; + +no_long_string(); +#no_diff(); + +run_tests(); + +__DATA__ + +=== TEST 1: invalid proxy_pass url +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock; + + location / { + default_type 'text/plain'; + + content_by_lua_block { + ngx.say("hello world") + } + + more_clear_headers Date; + } + } +--- config + location /t { + proxy_pass http://unix:$TEST_NGINX_HTML_DIR/nginx.sock; + + proxy_ssl_verify_by_lua_block { + ngx.log(ngx.INFO, "hello world") + } + } +--- request +GET /t +--- error_log +proxy_ssl_verify_by_lua* should be used with proxy_pass https url +--- must_die + + + +=== TEST 2: proxy_ssl_verify_by_lua in http {} block +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock; + + location / { + default_type 'text/plain'; + + content_by_lua_block { + ngx.say("hello world") + } + + more_clear_headers Date; + } + } + + proxy_ssl_verify_by_lua_block { + ngx.log(ngx.INFO, "hello world") + } +--- config + location /t { + proxy_pass http://unix:$TEST_NGINX_HTML_DIR/nginx.sock; + } +--- request +GET /t +--- error_log +"proxy_ssl_verify_by_lua_block" directive is not allowed here +--- must_die + + + +=== TEST 3: proxy_ssl_verify_by_lua in server {} block +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock; + + location / { + default_type 'text/plain'; + + content_by_lua_block { + ngx.say("hello world") + } + + more_clear_headers Date; + } + } + +--- config + proxy_ssl_verify_by_lua_block { + ngx.log(ngx.INFO, "hello world") + } + + location /t { + proxy_pass http://unix:$TEST_NGINX_HTML_DIR/nginx.sock; + } +--- request +GET /t +--- error_log +"proxy_ssl_verify_by_lua_block" directive is not allowed here +--- must_die + + + +=== TEST 4: simple logging +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + + ssl_certificate ../../cert/mtls_server.crt; + ssl_certificate_key ../../cert/mtls_server.key; + + location / { + default_type 'text/plain'; + + content_by_lua_block { + ngx.say("simple logging return") + } + + more_clear_headers Date; + } + } +--- config + location /t { + proxy_pass https://unix:$TEST_NGINX_HTML_DIR/nginx.sock; + proxy_ssl_verify on; + proxy_ssl_name example.com; + proxy_ssl_certificate ../../cert/mtls_client.crt; + proxy_ssl_certificate_key ../../cert/mtls_client.key; + proxy_ssl_trusted_certificate ../../cert/mtls_ca.crt; + proxy_ssl_session_reuse off; + + proxy_ssl_verify_by_lua_block { + ngx.log(ngx.INFO, "proxy ssl verify by lua is running!") + } + } +--- request +GET /t +--- response_body +simple logging return +--- error_log +proxy ssl verify by lua is running! +--- no_error_log +[error] +[alert] + + + +=== TEST 5: sleep +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + + ssl_certificate ../../cert/mtls_server.crt; + ssl_certificate_key ../../cert/mtls_server.key; + + location / { + default_type 'text/plain'; + + content_by_lua_block { + ngx.say("sleep") + } + + more_clear_headers Date; + } + } +--- config + location /t { + proxy_pass https://unix:$TEST_NGINX_HTML_DIR/nginx.sock; + proxy_ssl_verify on; + proxy_ssl_name example.com; + proxy_ssl_certificate ../../cert/mtls_client.crt; + proxy_ssl_certificate_key ../../cert/mtls_client.key; + proxy_ssl_trusted_certificate ../../cert/mtls_ca.crt; + proxy_ssl_session_reuse off; + + proxy_ssl_verify_by_lua_block { + local begin = ngx.now() + ngx.sleep(0.1) + print("elapsed in proxy ssl verify by lua: ", ngx.now() - begin) + } + } +--- request +GET /t +--- response_body +sleep +--- error_log eval +qr/elapsed in proxy ssl verify by lua: 0.(?:09|1\d)\d+ while loading proxy ssl verify by lua,/, +--- no_error_log +[error] +[alert] + + + +=== TEST 6: timer +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + + ssl_certificate ../../cert/mtls_server.crt; + ssl_certificate_key ../../cert/mtls_server.key; + + location / { + default_type 'text/plain'; + + content_by_lua_block { + ngx.say("timer") + } + + more_clear_headers Date; + } + } +--- config + location /t { + proxy_pass https://unix:$TEST_NGINX_HTML_DIR/nginx.sock; + proxy_ssl_verify on; + proxy_ssl_name example.com; + proxy_ssl_certificate ../../cert/mtls_client.crt; + proxy_ssl_certificate_key ../../cert/mtls_client.key; + proxy_ssl_trusted_certificate ../../cert/mtls_ca.crt; + proxy_ssl_session_reuse off; + + proxy_ssl_verify_by_lua_block { + local function f() + print("my timer run!") + end + local ok, err = ngx.timer.at(0, f) + if not ok then + ngx.log(ngx.ERR, "failed to create timer: ", err) + return + end + } + } +--- request +GET /t +--- response_body +timer +--- error_log +my timer run! +--- no_error_log +[error] +[alert] + + + +=== TEST 7: ngx.exit(0) - no yield +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + + ssl_certificate ../../cert/mtls_server.crt; + ssl_certificate_key ../../cert/mtls_server.key; + + location / { + default_type 'text/plain'; + + content_by_lua_block { + ngx.say("ngx.exit(0) no yield") + } + + more_clear_headers Date; + } + } +--- config + location /t { + proxy_pass https://unix:$TEST_NGINX_HTML_DIR/nginx.sock; + proxy_ssl_verify on; + proxy_ssl_name example.com; + proxy_ssl_certificate ../../cert/mtls_client.crt; + proxy_ssl_certificate_key ../../cert/mtls_client.key; + proxy_ssl_trusted_certificate ../../cert/mtls_ca.crt; + proxy_ssl_session_reuse off; + + proxy_ssl_verify_by_lua_block { + ngx.exit(0) + ngx.log(ngx.ERR, "should never reached here...") + } + } +--- request +GET /t +--- response_body +ngx.exit(0) no yield +--- error_log +lua exit with code 0 +--- no_error_log +should never reached here +[error] +[alert] +[emerg] + + + +=== TEST 8: ngx.exit(ngx.ERROR) - no yield +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + + ssl_certificate ../../cert/mtls_server.crt; + ssl_certificate_key ../../cert/mtls_server.key; + + location / { + default_type 'text/plain'; + + content_by_lua_block { + ngx.say("ngx.exit(ngx.ERROR) no yield") + } + + more_clear_headers Date; + } + } +--- config + location /t { + proxy_pass https://unix:$TEST_NGINX_HTML_DIR/nginx.sock; + proxy_ssl_verify on; + proxy_ssl_name example.com; + proxy_ssl_certificate ../../cert/mtls_client.crt; + proxy_ssl_certificate_key ../../cert/mtls_client.key; + proxy_ssl_trusted_certificate ../../cert/mtls_ca.crt; + proxy_ssl_session_reuse off; + proxy_ssl_conf_command VerifyMode Peer; + + proxy_ssl_verify_by_lua_block { + ngx.exit(ngx.ERROR) + ngx.log(ngx.ERR, "should never reached here...") + } + } +--- request +GET /t +--- error_code: 502 +--- error_log eval +[ +'lua exit with code -1', +'proxy_ssl_verify_by_lua: handler return value: -1, cert verify callback exit code: 0', +qr/.*? SSL_do_handshake\(\) failed .*?certificate verify failed/, +] +--- no_error_log +should never reached here +[error] +[alert] +[emerg] + + + +=== TEST 9: ngx.exit(0) - yield +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + + ssl_certificate ../../cert/mtls_server.crt; + ssl_certificate_key ../../cert/mtls_server.key; + + location / { + default_type 'text/plain'; + + content_by_lua_block { + ngx.say("ngx.exit(0) yield") + } + + more_clear_headers Date; + } + } +--- config + location /t { + proxy_pass https://unix:$TEST_NGINX_HTML_DIR/nginx.sock; + proxy_ssl_verify on; + proxy_ssl_name example.com; + proxy_ssl_certificate ../../cert/mtls_client.crt; + proxy_ssl_certificate_key ../../cert/mtls_client.key; + proxy_ssl_trusted_certificate ../../cert/mtls_ca.crt; + proxy_ssl_session_reuse off; + proxy_ssl_conf_command VerifyMode Peer; + + proxy_ssl_verify_by_lua_block { + ngx.sleep(0.001) + ngx.exit(0) + + ngx.log(ngx.ERR, "should never reached here...") + } + } +--- request +GET /t +--- response_body +ngx.exit(0) yield +--- error_log +lua exit with code 0 +--- no_error_log +should never reached here +[error] +[alert] +[emerg] + + + +=== TEST 10: ngx.exit(ngx.ERROR) - yield +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + + ssl_certificate ../../cert/mtls_server.crt; + ssl_certificate_key ../../cert/mtls_server.key; + + location / { + default_type 'text/plain'; + + content_by_lua_block { + ngx.say("ngx.exit(ngx.ERROR) yield") + } + + more_clear_headers Date; + } + } +--- config + location /t { + proxy_pass https://unix:$TEST_NGINX_HTML_DIR/nginx.sock; + proxy_ssl_verify on; + proxy_ssl_name example.com; + proxy_ssl_certificate ../../cert/mtls_client.crt; + proxy_ssl_certificate_key ../../cert/mtls_client.key; + proxy_ssl_trusted_certificate ../../cert/mtls_ca.crt; + proxy_ssl_session_reuse off; + proxy_ssl_conf_command VerifyMode Peer; + + proxy_ssl_verify_by_lua_block { + ngx.sleep(0.001) + ngx.exit(ngx.ERROR) + + ngx.log(ngx.ERR, "should never reached here...") + } + } +--- request +GET /t +--- error_code: 502 +--- error_log eval +[ +'lua exit with code -1', +'proxy_ssl_verify_by_lua: cert verify callback exit code: 0', +qr/.*? SSL_do_handshake\(\) failed .*?certificate verify failed/, +] +--- no_error_log +should never reached here +[error] +[alert] +[emerg] + + + +=== TEST 11: lua exception - no yield +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + + ssl_certificate ../../cert/mtls_server.crt; + ssl_certificate_key ../../cert/mtls_server.key; + + location / { + default_type 'text/plain'; + + content_by_lua_block { + ngx.say("lua exception - no yield") + } + + more_clear_headers Date; + } + } +--- config + location /t { + proxy_pass https://unix:$TEST_NGINX_HTML_DIR/nginx.sock; + proxy_ssl_verify on; + proxy_ssl_name example.com; + proxy_ssl_certificate ../../cert/mtls_client.crt; + proxy_ssl_certificate_key ../../cert/mtls_client.key; + proxy_ssl_trusted_certificate ../../cert/mtls_ca.crt; + proxy_ssl_session_reuse off; + proxy_ssl_conf_command VerifyMode Peer; + + proxy_ssl_verify_by_lua_block { + error("bad bad bad") + ngx.log(ngx.ERR, "should never reached here...") + } + } +--- request +GET /t +--- error_code: 502 +--- error_log eval +[ +'runtime error: proxy_ssl_verify_by_lua(nginx.conf:65):2: bad bad bad', +'proxy_ssl_verify_by_lua: handler return value: 500, cert verify callback exit code: 0', +qr/.*? SSL_do_handshake\(\) failed .*?certificate verify failed/, +] +--- no_error_log +should never reached here +[alert] +[emerg] + + + +=== TEST 12: lua exception - yield +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + + ssl_certificate ../../cert/mtls_server.crt; + ssl_certificate_key ../../cert/mtls_server.key; + + location / { + default_type 'text/plain'; + + content_by_lua_block { + ngx.say("lua exception - yield") + } + + more_clear_headers Date; + } + } +--- config + location /t { + proxy_pass https://unix:$TEST_NGINX_HTML_DIR/nginx.sock; + proxy_ssl_verify on; + proxy_ssl_name example.com; + proxy_ssl_certificate ../../cert/mtls_client.crt; + proxy_ssl_certificate_key ../../cert/mtls_client.key; + proxy_ssl_trusted_certificate ../../cert/mtls_ca.crt; + proxy_ssl_session_reuse off; + proxy_ssl_conf_command VerifyMode Peer; + + proxy_ssl_verify_by_lua_block { + ngx.sleep(0.001) + error("bad bad bad") + ngx.log(ngx.ERR, "should never reached here...") + } + } +--- request +GET /t +--- error_code: 502 +--- error_log eval +[ +'runtime error: proxy_ssl_verify_by_lua(nginx.conf:65):3: bad bad bad', +'proxy_ssl_verify_by_lua: cert verify callback exit code: 0', +qr/.*? SSL_do_handshake\(\) failed .*?certificate verify failed/, +] +--- no_error_log +should never reached here +[alert] +[emerg] + + + +=== TEST 13: get phase +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + + ssl_certificate ../../cert/mtls_server.crt; + ssl_certificate_key ../../cert/mtls_server.key; + + location / { + default_type 'text/plain'; + + content_by_lua_block { + ngx.say("get phase return") + } + + more_clear_headers Date; + } + } +--- config + location /t { + proxy_pass https://unix:$TEST_NGINX_HTML_DIR/nginx.sock; + proxy_ssl_verify on; + proxy_ssl_name example.com; + proxy_ssl_certificate ../../cert/mtls_client.crt; + proxy_ssl_certificate_key ../../cert/mtls_client.key; + proxy_ssl_trusted_certificate ../../cert/mtls_ca.crt; + proxy_ssl_session_reuse off; + proxy_ssl_conf_command VerifyMode Peer; + + proxy_ssl_verify_by_lua_block { + print("get_phase: ", ngx.get_phase()) + } + } +--- request +GET /t +--- response_body +get phase return +--- error_log +get_phase: proxy_ssl_verify +--- no_error_log +[error] +[alert] + + + +=== TEST 14: subrequests disabled +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + + ssl_certificate ../../cert/mtls_server.crt; + ssl_certificate_key ../../cert/mtls_server.key; + + location / { + default_type 'text/plain'; + + content_by_lua_block { + ngx.say("subrequests disabled") + } + + more_clear_headers Date; + } + } +--- config + location /t { + proxy_pass https://unix:$TEST_NGINX_HTML_DIR/nginx.sock; + proxy_ssl_verify on; + proxy_ssl_name example.com; + proxy_ssl_certificate ../../cert/mtls_client.crt; + proxy_ssl_certificate_key ../../cert/mtls_client.key; + proxy_ssl_trusted_certificate ../../cert/mtls_ca.crt; + proxy_ssl_session_reuse off; + proxy_ssl_conf_command VerifyMode Peer; + + proxy_ssl_verify_by_lua_block { + ngx.location.capture("/foo") + } + } +--- request +GET /t +--- error_code: 502 +--- error_log eval +[ +'proxy_ssl_verify_by_lua(nginx.conf:65):2: API disabled in the context of proxy_ssl_verify_by_lua*', +'proxy_ssl_verify_by_lua: handler return value: 500, cert verify callback exit code: 0', +qr/.*? SSL_do_handshake\(\) failed .*?certificate verify failed/, +] +--- no_error_log +[alert] + + + +=== TEST 15: simple logging (by_lua_file) +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + + ssl_certificate ../../cert/mtls_server.crt; + ssl_certificate_key ../../cert/mtls_server.key; + + location / { + default_type 'text/plain'; + + content_by_lua_block { + ngx.say("simple logging by lua file") + } + + more_clear_headers Date; + } + } +--- user_files +>>> a.lua +print("proxy ssl verify by lua is running!") + +--- config + location /t { + proxy_pass https://unix:$TEST_NGINX_HTML_DIR/nginx.sock; + proxy_ssl_verify on; + proxy_ssl_name example.com; + proxy_ssl_certificate ../../cert/mtls_client.crt; + proxy_ssl_certificate_key ../../cert/mtls_client.key; + proxy_ssl_trusted_certificate ../../cert/mtls_ca.crt; + proxy_ssl_session_reuse off; + proxy_ssl_conf_command VerifyMode Peer; + + proxy_ssl_verify_by_lua_file html/a.lua; + } +--- request +GET /t +--- response_body +simple logging by lua file +--- error_log +a.lua:1: proxy ssl verify by lua is running! +--- no_error_log +[error] +[alert] + + + +=== TEST 16: coroutine API +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + + ssl_certificate ../../cert/mtls_server.crt; + ssl_certificate_key ../../cert/mtls_server.key; + + location / { + default_type 'text/plain'; + + content_by_lua_block { + ngx.say("coroutine API") + } + + more_clear_headers Date; + } + } +--- config + location /t { + proxy_pass https://unix:$TEST_NGINX_HTML_DIR/nginx.sock; + proxy_ssl_verify on; + proxy_ssl_name example.com; + proxy_ssl_certificate ../../cert/mtls_client.crt; + proxy_ssl_certificate_key ../../cert/mtls_client.key; + proxy_ssl_trusted_certificate ../../cert/mtls_ca.crt; + proxy_ssl_session_reuse off; + proxy_ssl_conf_command VerifyMode Peer; + + proxy_ssl_verify_by_lua_block { + local cc, cr, cy = coroutine.create, coroutine.resume, coroutine.yield + + local function f() + local cnt = 0 + for i = 1, 20 do + print("co yield: ", cnt) + cy() + cnt = cnt + 1 + end + end + + local c = cc(f) + for i = 1, 3 do + print("co resume, status: ", coroutine.status(c)) + cr(c) + end + } + } +--- request +GET /t +--- response_body +coroutine API +--- grep_error_log eval: qr/co (?:yield: \d+|resume, status: \w+)/ +--- grep_error_log_out +co resume, status: suspended +co yield: 0 +co resume, status: suspended +co yield: 1 +co resume, status: suspended +co yield: 2 +--- no_error_log +[error] +[alert] + + + +=== TEST 17: simple user thread wait with yielding +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + + ssl_certificate ../../cert/mtls_server.crt; + ssl_certificate_key ../../cert/mtls_server.key; + + location / { + default_type 'text/plain'; + + content_by_lua_block { + ngx.say("simple user thread wait with yielding") + } + + more_clear_headers Date; + } + } +--- config + location /t { + proxy_pass https://unix:$TEST_NGINX_HTML_DIR/nginx.sock; + proxy_ssl_verify on; + proxy_ssl_name example.com; + proxy_ssl_certificate ../../cert/mtls_client.crt; + proxy_ssl_certificate_key ../../cert/mtls_client.key; + proxy_ssl_trusted_certificate ../../cert/mtls_ca.crt; + proxy_ssl_session_reuse off; + proxy_ssl_conf_command VerifyMode Peer; + + proxy_ssl_verify_by_lua_block { + local function f() + ngx.sleep(0.01) + print("uthread: hello in thread") + return "done" + end + + local t, err = ngx.thread.spawn(f) + if not t then + ngx.log(ngx.ERR, "uthread: failed to spawn thread: ", err) + return ngx.exit(ngx.ERROR) + end + + print("uthread: thread created: ", coroutine.status(t)) + + local ok, res = ngx.thread.wait(t) + if not ok then + print("uthread: failed to wait thread: ", res) + return + end + + print("uthread: ", res) + } + } +--- request +GET /t +--- response_body +simple user thread wait with yielding +--- no_error_log +[error] +[alert] +--- grep_error_log eval: qr/uthread: [^.,]+/ +--- grep_error_log_out +uthread: thread created: running while loading proxy ssl verify by lua +uthread: hello in thread while loading proxy ssl verify by lua +uthread: done while loading proxy ssl verify by lua + + + +=== TEST 18: uthread (kill) +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + + ssl_certificate ../../cert/mtls_server.crt; + ssl_certificate_key ../../cert/mtls_server.key; + + location / { + default_type 'text/plain'; + + content_by_lua_block { + ngx.say("uthread (kill)") + } + + more_clear_headers Date; + } + } +--- config + location /t { + proxy_pass https://unix:$TEST_NGINX_HTML_DIR/nginx.sock; + proxy_ssl_verify on; + proxy_ssl_name example.com; + proxy_ssl_certificate ../../cert/mtls_client.crt; + proxy_ssl_certificate_key ../../cert/mtls_client.key; + proxy_ssl_trusted_certificate ../../cert/mtls_ca.crt; + proxy_ssl_session_reuse off; + proxy_ssl_conf_command VerifyMode Peer; + + proxy_ssl_verify_by_lua_block { + local function f() + ngx.log(ngx.INFO, "uthread: hello from f()") + ngx.sleep(1) + end + + local t, err = ngx.thread.spawn(f) + if not t then + ngx.log(ngx.ERR, "failed to spawn thread: ", err) + return ngx.exit(ngx.ERROR) + end + + local ok, res = ngx.thread.kill(t) + if not ok then + ngx.log(ngx.ERR, "failed to kill thread: ", res) + return + end + + ngx.log(ngx.INFO, "uthread: killed") + + local ok, err = ngx.thread.kill(t) + if not ok then + ngx.log(ngx.INFO, "uthread: failed to kill: ", err) + end + } + } +--- request +GET /t +--- response_body +uthread (kill) +--- no_error_log +[error] +[alert] +[emerg] +--- grep_error_log eval: qr/uthread: [^.,]+/ +--- grep_error_log_out +uthread: hello from f() while loading proxy ssl verify by lua +uthread: killed while loading proxy ssl verify by lua +uthread: failed to kill: already waited or killed while loading proxy ssl verify by lua + + + +=== TEST 19: ngx.exit(ngx.OK) - no yield +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + + ssl_certificate ../../cert/mtls_server.crt; + ssl_certificate_key ../../cert/mtls_server.key; + + location / { + default_type 'text/plain'; + + content_by_lua_block { + ngx.say("ngx.exit(ngx.OK) - no yield") + } + + more_clear_headers Date; + } + } +--- config + location /t { + proxy_pass https://unix:$TEST_NGINX_HTML_DIR/nginx.sock; + proxy_ssl_verify on; + proxy_ssl_name example.com; + proxy_ssl_certificate ../../cert/mtls_client.crt; + proxy_ssl_certificate_key ../../cert/mtls_client.key; + proxy_ssl_trusted_certificate ../../cert/mtls_ca.crt; + proxy_ssl_session_reuse off; + proxy_ssl_conf_command VerifyMode Peer; + + proxy_ssl_verify_by_lua_block { + ngx.exit(ngx.OK) + ngx.log(ngx.ERR, "should never reached here...") + } + } +--- request +GET /t +--- response_body +ngx.exit(ngx.OK) - no yield +--- error_log eval +[ +'proxy_ssl_verify_by_lua: handler return value: 0, cert verify callback exit code: 1', +qr/\[debug\] .*? SSL_do_handshake: 1/, +'lua exit with code 0', +] +--- no_error_log +should never reached here +[alert] +[emerg] + + + +=== TEST 20: proxy_ssl_verify_by_lua* without yield API (simple logic) +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + + ssl_certificate ../../cert/mtls_server.crt; + ssl_certificate_key ../../cert/mtls_server.key; + + location / { + default_type 'text/plain'; + + content_by_lua_block { + ngx.say("without yield API, simple logic") + } + + more_clear_headers Date; + } + } +--- config + location /t { + proxy_pass https://unix:$TEST_NGINX_HTML_DIR/nginx.sock; + proxy_ssl_verify on; + proxy_ssl_name example.com; + proxy_ssl_certificate ../../cert/mtls_client.crt; + proxy_ssl_certificate_key ../../cert/mtls_client.key; + proxy_ssl_trusted_certificate ../../cert/mtls_ca.crt; + proxy_ssl_session_reuse off; + proxy_ssl_conf_command VerifyMode Peer; + + proxy_ssl_verify_by_lua_block { + print("proxy ssl verify: simple test start") + + -- Simple calculations without yield + local sum = 0 + for i = 1, 10 do + sum = sum + i + end + + print("proxy ssl verify: calculated sum: ", sum) + + -- String operations + local str = "hello" + str = str .. " world" + print("proxy ssl verify: concatenated string: ", str) + + -- Table operations + local t = {a = 1, b = 2, c = 3} + local count = 0 + for k, v in pairs(t) do + count = count + v + end + print("proxy ssl verify: table sum: ", count) + + print("proxy ssl verify: simple test done") + } + } +--- request +GET /t +--- response_body +without yield API, simple logic +--- grep_error_log eval: qr/(proxy ssl verify: simple test start|proxy ssl verify: calculated sum: 55|proxy ssl verify: concatenated string: hello world|proxy ssl verify: table sum: 6|proxy ssl verify: simple test done)/ +--- grep_error_log_out +proxy ssl verify: simple test start +proxy ssl verify: calculated sum: 55 +proxy ssl verify: concatenated string: hello world +proxy ssl verify: table sum: 6 +proxy ssl verify: simple test done + +--- no_error_log +[error] +[alert] +[emerg] + + + +=== TEST 21: lua_upstream_skip_openssl_default_verify default off +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + + ssl_certificate ../../cert/mtls_server.crt; + ssl_certificate_key ../../cert/mtls_server.key; + + location / { + default_type 'text/plain'; + + content_by_lua_block { + ngx.say("lua_upstream_skip_openssl_default_verify default off") + } + + more_clear_headers Date; + } + } +--- config + location /t { + proxy_pass https://unix:$TEST_NGINX_HTML_DIR/nginx.sock; + proxy_ssl_verify on; + proxy_ssl_name example.com; + proxy_ssl_certificate ../../cert/mtls_client.crt; + proxy_ssl_certificate_key ../../cert/mtls_client.key; + proxy_ssl_trusted_certificate ../../cert/mtls_ca.crt; + proxy_ssl_session_reuse off; + proxy_ssl_conf_command VerifyMode Peer; + + proxy_ssl_verify_by_lua_block { + ngx.log(ngx.INFO, "proxy ssl verify by lua is running!") + } + } +--- request +GET /t +--- error_log +proxy_ssl_verify_by_lua: openssl default verify +--- no_error_log +[error] +[alert] + + + +=== TEST 22: lua_upstream_skip_openssl_default_verify on +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + + ssl_certificate ../../cert/mtls_server.crt; + ssl_certificate_key ../../cert/mtls_server.key; + + location / { + default_type 'text/plain'; + + content_by_lua_block { + ngx.say("lua_upstream_skip_openssl_default_verify default off") + } + + more_clear_headers Date; + } + } +--- config + location /t { + proxy_pass https://unix:$TEST_NGINX_HTML_DIR/nginx.sock; + proxy_ssl_verify on; + proxy_ssl_name example.com; + proxy_ssl_certificate ../../cert/mtls_client.crt; + proxy_ssl_certificate_key ../../cert/mtls_client.key; + proxy_ssl_trusted_certificate ../../cert/mtls_ca.crt; + proxy_ssl_session_reuse off; + proxy_ssl_conf_command VerifyMode Peer; + + lua_upstream_skip_openssl_default_verify on; + + proxy_ssl_verify_by_lua_block { + ngx.log(ngx.INFO, "proxy ssl verify by lua is running!") + } + } +--- request +GET /t +--- response_body +lua_upstream_skip_openssl_default_verify default off +--- error_log +proxy ssl verify by lua is running! +--- no_error_log +proxy_ssl_verify_by_lua: openssl default verify +[error] +[alert] + + + +=== TEST 23: ngx.ctx to pass data from downstream phase to upstream phase +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + + ssl_certificate ../../cert/mtls_server.crt; + ssl_certificate_key ../../cert/mtls_server.key; + + location / { + default_type 'text/plain'; + + content_by_lua_block { + ngx.say("simple logging return") + } + + more_clear_headers Date; + } + } +--- config + location /t { + proxy_pass https://unix:$TEST_NGINX_HTML_DIR/nginx.sock; + proxy_ssl_verify on; + proxy_ssl_name example.com; + proxy_ssl_certificate ../../cert/mtls_client.crt; + proxy_ssl_certificate_key ../../cert/mtls_client.key; + proxy_ssl_trusted_certificate ../../cert/mtls_ca.crt; + proxy_ssl_session_reuse off; + + rewrite_by_lua_block { + ngx.ctx.greeting = "I am from rewrite phase" + } + + proxy_ssl_verify_by_lua_block { + ngx.log(ngx.INFO, "greeting: ", ngx.ctx.greeting) + } + } +--- request +GET /t +--- response_body +simple logging return +--- error_log +greeting: I am from rewrite phase +--- no_error_log +[error] +[alert] + + + +=== TEST 24: upstream connection aborted +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + + ssl_certificate ../../cert/mtls_server.crt; + ssl_certificate_key ../../cert/mtls_server.key; + + location / { + default_type 'text/plain'; + + content_by_lua_block { + ngx.say("hello world") + } + + more_clear_headers Date; + } + } +--- config + location /t { + proxy_pass https://unix:$TEST_NGINX_HTML_DIR/nginx.sock; + proxy_ssl_verify on; + proxy_ssl_name example.com; + proxy_ssl_certificate ../../cert/mtls_client.crt; + proxy_ssl_certificate_key ../../cert/mtls_client.key; + proxy_ssl_trusted_certificate ../../cert/mtls_ca.crt; + proxy_ssl_session_reuse off; + proxy_connect_timeout 100ms; + + proxy_ssl_verify_by_lua_block { + ngx.sleep(0.2) + } + } +--- request +GET /t +--- error_code: 504 +--- response_body_like: 504 Gateway Time-out +--- error_log +upstream timed out (110: Connection timed out) while loading proxy ssl verify by lua +proxy_ssl_verify_by_lua: cert verify callback aborted +--- no_error_log +[alert] +--- wait: 0.5 + + + +=== TEST 25: cosocket +--- http_config + server { + listen *:80; + server_name test.com; + + server_tokens off; + location /foo { + default_type 'text/plain'; + content_by_lua_block { + ngx.sleep(0.1) + + ngx.status = 201 + ngx.say("foo") + ngx.exit(201) + } + more_clear_headers Date; + } + } + + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + + ssl_certificate ../../cert/mtls_server.crt; + ssl_certificate_key ../../cert/mtls_server.key; + + location / { + default_type 'text/plain'; + + content_by_lua_block { + ngx.say("simple logging return") + } + + more_clear_headers Date; + } + } +--- config + location /t { + proxy_pass https://unix:$TEST_NGINX_HTML_DIR/nginx.sock; + proxy_ssl_verify on; + proxy_ssl_name example.com; + proxy_ssl_certificate ../../cert/mtls_client.crt; + proxy_ssl_certificate_key ../../cert/mtls_client.key; + proxy_ssl_trusted_certificate ../../cert/mtls_ca.crt; + proxy_ssl_session_reuse off; + + proxy_ssl_verify_by_lua_block { + do + local sock = ngx.socket.tcp() + sock:settimeout(2000) + + local ok, err = sock:connect("127.0.0.1", "80") + if not ok then + ngx.log(ngx.ERR, "failed to connect: ", err) + return + end + + ngx.log(ngx.INFO, "connected: ", ok) + + local req = "GET /foo HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n" + local bytes, err = sock:send(req) + if not bytes then + ngx.log(ngx.ERR, "failed to send http request: ", err) + return + end + + ngx.log(ngx.INFO, "sent http request: ", bytes, " bytes.") + + while true do + local line, err = sock:receive() + if not line then + -- ngx.log(ngx.ERR, "failed to receive response status line: ", err) + break + end + + ngx.log(ngx.INFO, "received: ", line) + end + + local ok, err = sock:close() + ngx.log(ngx.INFO, "close: ", ok, " ", err) + end -- do + -- collectgarbage() + } + } +--- request +GET /t +--- response_body +simple logging return +--- error_log +connected: 1 +sent http request: 56 bytes. +received: HTTP/1.1 201 Created +received: Server: openresty +received: Content-Type: text/plain +received: Content-Length: 4 +received: Connection: close +received: +received: foo +close: 1 nil +--- no_error_log +[error] +[alert] From dc8de6ef3f075f04ed2ab8a5dbbb13f3b8d22227 Mon Sep 17 00:00:00 2001 From: swananan Date: Sat, 18 Oct 2025 13:13:48 +0800 Subject: [PATCH 241/254] bugfix: resume QUIC handshake for OpenSSL external QUIC API builds --- src/ngx_http_lua_proxy_ssl_verifyby.c | 8 +++++--- src/ngx_http_lua_ssl_certby.c | 2 +- src/ngx_http_lua_ssl_client_helloby.c | 2 +- src/ngx_http_lua_util.c | 1 + 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/ngx_http_lua_proxy_ssl_verifyby.c b/src/ngx_http_lua_proxy_ssl_verifyby.c index 1695e56ffb..339522bab3 100644 --- a/src/ngx_http_lua_proxy_ssl_verifyby.c +++ b/src/ngx_http_lua_proxy_ssl_verifyby.c @@ -62,7 +62,7 @@ ngx_http_lua_proxy_ssl_verify_set_callback(ngx_conf_t *cf) return NGX_ERROR; } -#if (!defined SSL_ERROR_WANT_RETRY_VERIFY \ +#if (!defined SSL_ERROR_WANT_RETRY_VERIFY \ || OPENSSL_VERSION_NUMBER < 0x30000020L) ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "OpenSSL too old to support " @@ -150,7 +150,7 @@ char * ngx_http_lua_proxy_ssl_verify_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { -#if (!defined SSL_ERROR_WANT_RETRY_VERIFY \ +#if (!defined SSL_ERROR_WANT_RETRY_VERIFY \ || OPENSSL_VERSION_NUMBER < 0x30000020L) /* SSL_set_retry_verify() was added in OpenSSL 3.0.2 */ @@ -339,7 +339,8 @@ ngx_http_lua_proxy_ssl_verify_handler(X509_STORE_CTX *x509_store, void *arg) ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, "proxy_ssl_verify_by_lua: handler return value: %i, " - "cert verify callback exit code: %d", rc, cctx->exit_code); + "cert verify callback exit code: %d", rc, + cctx->exit_code); c->log->action = "proxy pass SSL handshaking"; return cctx->exit_code; @@ -370,6 +371,7 @@ ngx_http_lua_proxy_ssl_verify_handler(X509_STORE_CTX *x509_store, void *arg) return SSL_set_retry_verify(ssl_conn); failed: + if (cctx && cctx->pool) { ngx_destroy_pool(cctx->pool); } diff --git a/src/ngx_http_lua_ssl_certby.c b/src/ngx_http_lua_ssl_certby.c index 9a2d63fcf0..0667ec4293 100644 --- a/src/ngx_http_lua_ssl_certby.c +++ b/src/ngx_http_lua_ssl_certby.c @@ -392,7 +392,7 @@ ngx_http_lua_ssl_cert_done(void *data) #if (HAVE_QUIC_SSL_LUA_YIELD_PATCH && NGX_HTTP_V3) # if OPENSSL_VERSION_NUMBER >= 0x1000205fL -# if (NGX_QUIC_OPENSSL_COMPAT) +# if (NGX_QUIC_OPENSSL_COMPAT || NGX_QUIC_OPENSSL_API) ngx_http_lua_resume_quic_ssl_handshake(c); # endif # endif diff --git a/src/ngx_http_lua_ssl_client_helloby.c b/src/ngx_http_lua_ssl_client_helloby.c index b600ab3636..d1f86414af 100644 --- a/src/ngx_http_lua_ssl_client_helloby.c +++ b/src/ngx_http_lua_ssl_client_helloby.c @@ -392,7 +392,7 @@ ngx_http_lua_ssl_client_hello_done(void *data) #if (HAVE_QUIC_SSL_LUA_YIELD_PATCH && NGX_HTTP_V3) # if defined(SSL_ERROR_WANT_CLIENT_HELLO_CB) -# if (NGX_QUIC_OPENSSL_COMPAT) +# if (NGX_QUIC_OPENSSL_COMPAT || NGX_QUIC_OPENSSL_API) ngx_http_lua_resume_quic_ssl_handshake(c); # endif # endif diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 928a15beed..96e9ae5b20 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -1682,6 +1682,7 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, NGX_ERROR : NGX_HTTP_INTERNAL_SERVER_ERROR; done: + #ifdef HAVE_PROXY_SSL_PATCH if (ctx->context == NGX_HTTP_LUA_CONTEXT_PROXY_SSL_VERIFY) { return NGX_OK; From 8d553f059e61182e3c6a08d723fc3b5e688a8693 Mon Sep 17 00:00:00 2001 From: willmafh Date: Sun, 19 Oct 2025 14:21:42 +0800 Subject: [PATCH 242/254] bugfix: Nginx introduces ssl client hello callback in version 1.29.2. so we need to change nginx_version value to 1029001 here --- src/ngx_http_lua_ssl_client_helloby.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ngx_http_lua_ssl_client_helloby.c b/src/ngx_http_lua_ssl_client_helloby.c index d1f86414af..283d1017f0 100644 --- a/src/ngx_http_lua_ssl_client_helloby.c +++ b/src/ngx_http_lua_ssl_client_helloby.c @@ -220,7 +220,7 @@ ngx_http_lua_ssl_client_hello_handler(ngx_ssl_conn_t *ssl_conn, dd("first time"); -#if (nginx_version > 1029000) +#if (nginx_version > 1029001) /* see commit 0373fe5d98c1515640 for more details */ rc = ngx_ssl_client_hello_callback(ssl_conn, al, arg); From 13ba02a046854812294ae6ce5d0b38ff24d38c3c Mon Sep 17 00:00:00 2001 From: willmafh Date: Mon, 20 Oct 2025 09:22:18 +0800 Subject: [PATCH 243/254] tests: fixed CI. Co-authored-by: lijunlong --- src/ngx_http_lua_proxy_ssl_verifyby.c | 93 ++++++++++++++++++++++++++- t/169-proxy-ssl-verify.t | 21 +++--- 2 files changed, 105 insertions(+), 9 deletions(-) diff --git a/src/ngx_http_lua_proxy_ssl_verifyby.c b/src/ngx_http_lua_proxy_ssl_verifyby.c index 339522bab3..1cb1d980e4 100644 --- a/src/ngx_http_lua_proxy_ssl_verifyby.c +++ b/src/ngx_http_lua_proxy_ssl_verifyby.c @@ -33,13 +33,20 @@ ngx_int_t ngx_http_lua_proxy_ssl_verify_set_callback(ngx_conf_t *cf) { -#ifdef LIBRESSL_VERSION_NUMBER +#if defined(LIBRESSL_VERSION_NUMBER) ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "LibreSSL does not support by proxy_ssl_verify_by_lua*"); return NGX_ERROR; +#elif defined(OPENSSL_IS_BORINGSSL) + + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "BoringSSL does not support by proxy_ssl_verify_by_lua*"); + + return NGX_ERROR; + #else void *plcf; @@ -150,6 +157,22 @@ char * ngx_http_lua_proxy_ssl_verify_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { +#if defined(LIBRESSL_VERSION_NUMBER) + + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "LibreSSL does not support by proxy_ssl_verify_by_lua*"); + + return NGX_CONF_ERROR; + +#elif defined(OPENSSL_IS_BORINGSSL) + + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "BoringSSL does not support by proxy_ssl_verify_by_lua*"); + + return NGX_CONF_ERROR; + +#else + #if (!defined SSL_ERROR_WANT_RETRY_VERIFY \ || OPENSSL_VERSION_NUMBER < 0x30000020L) @@ -231,12 +254,30 @@ ngx_http_lua_proxy_ssl_verify_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, return NGX_CONF_OK; #endif /* SSL_ERROR_WANT_RETRY_VERIFY */ + +#endif } int ngx_http_lua_proxy_ssl_verify_handler(X509_STORE_CTX *x509_store, void *arg) { +#if defined(LIBRESSL_VERSION_NUMBER) + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, + "LibreSSL does not support by proxy_ssl_verify_by_lua*"); + + return 1; + +#elif defined(OPENSSL_IS_BORINGSSL) + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, + "BoringSSL does not support by proxy_ssl_verify_by_lua*"); + + return 1; + +#else + lua_State *L; ngx_int_t rc; ngx_connection_t *c; @@ -377,6 +418,8 @@ ngx_http_lua_proxy_ssl_verify_handler(X509_STORE_CTX *x509_store, void *arg) } return 0; /* verify failure or error */ + +#endif } @@ -553,6 +596,20 @@ int ngx_http_lua_ffi_proxy_ssl_set_verify_result(ngx_http_request_t *r, int verify_result, char **err) { +#if defined(LIBRESSL_VERSION_NUMBER) + + *err = "LibreSSL does not support this function"; + + return NGX_ERROR; + +#elif defined(OPENSSL_IS_BORINGSSL) + + *err = "BoringSSL does not support this function"; + + return NGX_ERROR; + +#else + #ifdef SSL_ERROR_WANT_RETRY_VERIFY ngx_http_upstream_t *u; ngx_ssl_conn_t *ssl_conn; @@ -598,12 +655,28 @@ ngx_http_lua_ffi_proxy_ssl_set_verify_result(ngx_http_request_t *r, return NGX_ERROR; #endif + +#endif } int ngx_http_lua_ffi_proxy_ssl_get_verify_result(ngx_http_request_t *r, char **err) { +#if defined(LIBRESSL_VERSION_NUMBER) + + *err = "LibreSSL does not support this function"; + + return NGX_ERROR; + +#elif defined(OPENSSL_IS_BORINGSSL) + + *err = "BoringSSL does not support this function"; + + return NGX_ERROR; + +#else + #ifdef SSL_ERROR_WANT_RETRY_VERIFY ngx_http_upstream_t *u; ngx_ssl_conn_t *ssl_conn; @@ -647,6 +720,8 @@ ngx_http_lua_ffi_proxy_ssl_get_verify_result(ngx_http_request_t *r, char **err) return NGX_ERROR; #endif + +#endif } @@ -662,6 +737,20 @@ ngx_http_lua_ffi_proxy_ssl_free_verify_cert(void *cdata) void * ngx_http_lua_ffi_proxy_ssl_get_verify_cert(ngx_http_request_t *r, char **err) { +#if defined(LIBRESSL_VERSION_NUMBER) + + *err = "LibreSSL does not support this function"; + + return NGX_ERROR; + +#elif defined(OPENSSL_IS_BORINGSSL) + + *err = "BoringSSL does not support this function"; + + return NGX_ERROR; + +#else + #ifdef SSL_ERROR_WANT_RETRY_VERIFY ngx_http_upstream_t *u; ngx_ssl_conn_t *ssl_conn; @@ -713,6 +802,8 @@ ngx_http_lua_ffi_proxy_ssl_get_verify_cert(ngx_http_request_t *r, char **err) return NULL; #endif + +#endif } diff --git a/t/169-proxy-ssl-verify.t b/t/169-proxy-ssl-verify.t index 4c44a8b9be..95ecc1f3a7 100644 --- a/t/169-proxy-ssl-verify.t +++ b/t/169-proxy-ssl-verify.t @@ -8,14 +8,19 @@ repeat_each(3); my $NginxBinary = $ENV{'TEST_NGINX_BINARY'} || 'nginx'; my $openssl_version = eval { `$NginxBinary -V 2>&1` }; -if ($openssl_version =~ m/built with OpenSSL (0\S*|1\.0\S*|1\.1\.0\S*)/) { - plan(skip_all => "too old OpenSSL, need 1.1.1, was $1"); +if ($openssl_version =~ m/built with OpenSSL (\d+)\.(\d+)\.(\d+)/) { + my ($major, $minor, $patch) = ($1, $2, $3); + + if ($major < 3 || ($major == 3 && $minor == 0 && $patch < 2)) { + plan(skip_all => "too old OpenSSL, need >= 3.0.2, was " . + "$major.$minor.$patch"); + } else { + plan tests => repeat_each() * (blocks() * 5 + 19); + } } elsif ($openssl_version =~ m/running with BoringSSL/) { plan(skip_all => "does not support BoringSSL"); -} elsif ($ENV{TEST_NGINX_USE_HTTP3}) { - plan tests => repeat_each() * (blocks() * 6 + 6); } else { - plan tests => repeat_each() * (blocks() * 5 + 10); + die "unknown SSL"; } $ENV{TEST_NGINX_HTML_DIR} ||= html_dir(); @@ -1230,7 +1235,7 @@ proxy_ssl_verify_by_lua: cert verify callback aborted === TEST 25: cosocket --- http_config server { - listen *:80; + listen 127.0.0.1:$TEST_NGINX_RAND_PORT_1; server_name test.com; server_tokens off; @@ -1279,7 +1284,7 @@ proxy_ssl_verify_by_lua: cert verify callback aborted local sock = ngx.socket.tcp() sock:settimeout(2000) - local ok, err = sock:connect("127.0.0.1", "80") + local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_RAND_PORT_1) if not ok then ngx.log(ngx.ERR, "failed to connect: ", err) return @@ -1320,7 +1325,7 @@ simple logging return connected: 1 sent http request: 56 bytes. received: HTTP/1.1 201 Created -received: Server: openresty +received: Server: nginx received: Content-Type: text/plain received: Content-Length: 4 received: Connection: close From 529dc7ae028f5adb80e069be7404d671bd8da7aa Mon Sep 17 00:00:00 2001 From: lijunlong Date: Tue, 21 Oct 2025 08:32:45 +0800 Subject: [PATCH 244/254] feature: bumped api version to 0.10.29. --- src/api/ngx_http_lua_api.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/ngx_http_lua_api.h b/src/api/ngx_http_lua_api.h index fa59095c6a..51a9e7b714 100644 --- a/src/api/ngx_http_lua_api.h +++ b/src/api/ngx_http_lua_api.h @@ -19,7 +19,7 @@ /* Public API for other Nginx modules */ -#define ngx_http_lua_version 10028 +#define ngx_http_lua_version 10029 #define NGX_HTTP_LUA_EXPORT_CO_CTX_CLEANUP 1 From 9f1b459b9fc4a7ece7ec24397afa4fc886a15f85 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Wed, 22 Oct 2025 09:28:22 +0800 Subject: [PATCH 245/254] bugfix: failed to build with openssl < 3.0.2. --- src/ngx_http_lua_proxy_ssl_verifyby.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/ngx_http_lua_proxy_ssl_verifyby.c b/src/ngx_http_lua_proxy_ssl_verifyby.c index 1cb1d980e4..9d4107359a 100644 --- a/src/ngx_http_lua_proxy_ssl_verifyby.c +++ b/src/ngx_http_lua_proxy_ssl_verifyby.c @@ -23,8 +23,10 @@ #include "ngx_http_lua_proxy_ssl_verifyby.h" +#if defined(OPENSSL_VERSION_NUMBER) && (OPENSSL_VERSION_NUMBER >= 0x30000020uL) static void ngx_http_lua_proxy_ssl_verify_done(void *data); static void ngx_http_lua_proxy_ssl_verify_aborted(void *data); +#endif static ngx_int_t ngx_http_lua_proxy_ssl_verify_by_chunk(lua_State *L, ngx_http_request_t *r); @@ -275,6 +277,12 @@ ngx_http_lua_proxy_ssl_verify_handler(X509_STORE_CTX *x509_store, void *arg) "BoringSSL does not support by proxy_ssl_verify_by_lua*"); return 1; +#elif defined(OPENSSL_VERSION_NUMBER) && (OPENSSL_VERSION_NUMBER < 0x30000020uL) + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, + "OpenSSL(< 3.0.2) does not support by proxy_ssl_verify_by_lua*"); + + return 1; #else @@ -423,6 +431,7 @@ ngx_http_lua_proxy_ssl_verify_handler(X509_STORE_CTX *x509_store, void *arg) } +#if defined(OPENSSL_VERSION_NUMBER) && (OPENSSL_VERSION_NUMBER >= 0x30000020uL) static void ngx_http_lua_proxy_ssl_verify_done(void *data) { @@ -482,6 +491,7 @@ ngx_http_lua_proxy_ssl_verify_aborted(void *data) cctx->pool = NULL; } } +#endif static ngx_int_t From 9d930a7c2bfafe34b14b6664cdb5b5eabfcd372d Mon Sep 17 00:00:00 2001 From: lijunlong Date: Wed, 22 Oct 2025 10:46:21 +0800 Subject: [PATCH 246/254] bugfix: failed to build with openssl 1.x.x/boringssl/libressl. --- src/ngx_http_lua_proxy_ssl_verifyby.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/ngx_http_lua_proxy_ssl_verifyby.c b/src/ngx_http_lua_proxy_ssl_verifyby.c index 9d4107359a..c8d783ab4b 100644 --- a/src/ngx_http_lua_proxy_ssl_verifyby.c +++ b/src/ngx_http_lua_proxy_ssl_verifyby.c @@ -265,13 +265,26 @@ int ngx_http_lua_proxy_ssl_verify_handler(X509_STORE_CTX *x509_store, void *arg) { #if defined(LIBRESSL_VERSION_NUMBER) + ngx_connection_t *c; + c = ngx_ssl_get_connection(ssl_conn); /* upstream connection */ + ngx_ssl_conn_t *ssl_conn; + + ssl_conn = X509_STORE_CTX_get_ex_data(x509_store, + SSL_get_ex_data_X509_STORE_CTX_idx()); ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "LibreSSL does not support by proxy_ssl_verify_by_lua*"); return 1; #elif defined(OPENSSL_IS_BORINGSSL) + ngx_connection_t *c; + ngx_ssl_conn_t *ssl_conn; + + ssl_conn = X509_STORE_CTX_get_ex_data(x509_store, + SSL_get_ex_data_X509_STORE_CTX_idx()); + c = ngx_ssl_get_connection(ssl_conn); /* upstream connection */ + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "BoringSSL does not support by proxy_ssl_verify_by_lua*"); @@ -279,6 +292,13 @@ ngx_http_lua_proxy_ssl_verify_handler(X509_STORE_CTX *x509_store, void *arg) return 1; #elif defined(OPENSSL_VERSION_NUMBER) && (OPENSSL_VERSION_NUMBER < 0x30000020uL) + ngx_connection_t *c; + ngx_ssl_conn_t *ssl_conn; + + ssl_conn = X509_STORE_CTX_get_ex_data(x509_store, + SSL_get_ex_data_X509_STORE_CTX_idx()); + c = ngx_ssl_get_connection(ssl_conn); /* upstream connection */ + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "OpenSSL(< 3.0.2) does not support by proxy_ssl_verify_by_lua*"); From 1a71cc8ea859abcbe551c7d4c052dcf582f5be9c Mon Sep 17 00:00:00 2001 From: willmafh Date: Thu, 23 Oct 2025 13:39:48 +0800 Subject: [PATCH 247/254] bugfix: typo fixes. --- src/ngx_http_lua_ssl_certby.c | 8 ++++---- src/ngx_http_lua_ssl_session_fetchby.c | 2 +- t/139-ssl-cert-by.t | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/ngx_http_lua_ssl_certby.c b/src/ngx_http_lua_ssl_certby.c index 0667ec4293..5d16834212 100644 --- a/src/ngx_http_lua_ssl_certby.c +++ b/src/ngx_http_lua_ssl_certby.c @@ -217,7 +217,7 @@ ngx_http_lua_ssl_cert_handler(ngx_ssl_conn_t *ssl_conn, void *data) if (cctx->done) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, - "lua_certificate_by_lua: cert cb exit code: %d", + "ssl_certificate_by_lua: cert cb exit code: %d", cctx->exit_code); dd("lua ssl cert done, finally"); @@ -319,7 +319,7 @@ ngx_http_lua_ssl_cert_handler(ngx_ssl_conn_t *ssl_conn, void *data) } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, - "lua_certificate_by_lua: handler return value: %i, " + "ssl_certificate_by_lua: handler return value: %i, " "cert cb exit code: %d", rc, cctx->exit_code); c->log->action = "SSL handshaking"; @@ -405,7 +405,7 @@ ngx_http_lua_ssl_cert_aborted(void *data) { ngx_http_lua_ssl_ctx_t *cctx = data; - dd("lua ssl cert done"); + dd("lua ssl cert aborted"); if (cctx->done) { /* completed successfully already */ @@ -413,7 +413,7 @@ ngx_http_lua_ssl_cert_aborted(void *data) } ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cctx->connection->log, 0, - "lua_certificate_by_lua: cert cb aborted"); + "ssl_certificate_by_lua: cert cb aborted"); cctx->aborted = 1; cctx->request->connection->ssl = NULL; diff --git a/src/ngx_http_lua_ssl_session_fetchby.c b/src/ngx_http_lua_ssl_session_fetchby.c index ebce63ce28..fee039fca8 100644 --- a/src/ngx_http_lua_ssl_session_fetchby.c +++ b/src/ngx_http_lua_ssl_session_fetchby.c @@ -416,7 +416,7 @@ ngx_http_lua_ssl_sess_fetch_aborted(void *data) { ngx_http_lua_ssl_ctx_t *cctx = data; - dd("lua ssl sess_fetch done"); + dd("lua ssl sess_fetch aborted"); if (cctx->done) { /* completed successfully already */ diff --git a/t/139-ssl-cert-by.t b/t/139-ssl-cert-by.t index c5b1665046..82ae791787 100644 --- a/t/139-ssl-cert-by.t +++ b/t/139-ssl-cert-by.t @@ -582,7 +582,7 @@ failed to do SSL handshake: handshake failed --- error_log eval [ -'lua_certificate_by_lua: handler return value: -1, cert cb exit code: 0', +'ssl_certificate_by_lua: handler return value: -1, cert cb exit code: 0', qr/(\[info\] .*? SSL_do_handshake\(\) failed .*?cert cb error|routines:OPENSSL_internal:CERT_CB_ERROR)/, 'lua exit with code -1', ] @@ -723,7 +723,7 @@ failed to do SSL handshake: handshake failed --- error_log eval [ -'lua_certificate_by_lua: cert cb exit code: 0', +'ssl_certificate_by_lua: cert cb exit code: 0', qr/(\[info\] .*? SSL_do_handshake\(\) failed .*?cert cb error|routines:OPENSSL_internal:CERT_CB_ERROR)/, 'lua exit with code -1', ] @@ -794,7 +794,7 @@ failed to do SSL handshake: handshake failed --- error_log eval [ 'runtime error: ssl_certificate_by_lua(nginx.conf:28):2: bad bad bad', -'lua_certificate_by_lua: handler return value: 500, cert cb exit code: 0', +'ssl_certificate_by_lua: handler return value: 500, cert cb exit code: 0', qr/(\[info\] .*? SSL_do_handshake\(\) failed .*?cert cb error|routines:OPENSSL_internal:CERT_CB_ERROR)/, qr/context: ssl_certificate_by_lua\*, client: \d+\.\d+\.\d+\.\d+, server: \d+\.\d+\.\d+\.\d+:\d+/, ] @@ -866,7 +866,7 @@ failed to do SSL handshake: handshake failed --- error_log eval [ 'runtime error: ssl_certificate_by_lua(nginx.conf:28):3: bad bad bad', -'lua_certificate_by_lua: cert cb exit code: 0', +'ssl_certificate_by_lua: cert cb exit code: 0', qr/(\[info\] .*? SSL_do_handshake\(\) failed .*?cert cb error|routines:OPENSSL_internal:CERT_CB_ERROR)/, ] From a47ad5201d9cd7ab2256fd628b6a0ac04b1615bd Mon Sep 17 00:00:00 2001 From: "zhuo.z" Date: Thu, 23 Oct 2025 13:48:25 +0800 Subject: [PATCH 248/254] bugfix: resolve subrequest cycle issue when Lua code cache is disabled. Co-authored-by: zhuo.zhang --- src/ngx_http_lua_accessby.c | 8 +++++ src/ngx_http_lua_bodyfilterby.c | 8 +++++ src/ngx_http_lua_contentby.c | 8 +++++ src/ngx_http_lua_headerfilterby.c | 8 +++++ src/ngx_http_lua_logby.c | 8 +++++ src/ngx_http_lua_rewriteby.c | 8 +++++ t/014-bugs.t | 60 ++++++++++++++++++++++++++++++- 7 files changed, 107 insertions(+), 1 deletion(-) diff --git a/src/ngx_http_lua_accessby.c b/src/ngx_http_lua_accessby.c index 31ee82fd93..39bdcda2bf 100644 --- a/src/ngx_http_lua_accessby.c +++ b/src/ngx_http_lua_accessby.c @@ -173,6 +173,10 @@ ngx_http_lua_access_handler_inline(ngx_http_request_t *r) L = ngx_http_lua_get_lua_vm(r, NULL); + if (!llcf->enable_code_cache) { + llcf->access_src_ref = LUA_REFNIL; + } + /* load Lua inline script (w/ cache) sp = 1 */ rc = ngx_http_lua_cache_loadbuffer(r->connection->log, L, llcf->access_src.value.data, @@ -214,6 +218,10 @@ ngx_http_lua_access_handler_file(ngx_http_request_t *r) L = ngx_http_lua_get_lua_vm(r, NULL); + if (!llcf->enable_code_cache) { + llcf->access_src_ref = LUA_REFNIL; + } + /* load Lua script file (w/ cache) sp = 1 */ rc = ngx_http_lua_cache_loadfile(r->connection->log, L, script_path, &llcf->access_src_ref, diff --git a/src/ngx_http_lua_bodyfilterby.c b/src/ngx_http_lua_bodyfilterby.c index 179a501a59..cb5f7eb608 100644 --- a/src/ngx_http_lua_bodyfilterby.c +++ b/src/ngx_http_lua_bodyfilterby.c @@ -155,6 +155,10 @@ ngx_http_lua_body_filter_inline(ngx_http_request_t *r, ngx_chain_t *in) L = ngx_http_lua_get_lua_vm(r, NULL); + if (!llcf->enable_code_cache) { + llcf->body_filter_src_ref = LUA_REFNIL; + } + /* load Lua inline script (w/ cache) sp = 1 */ rc = ngx_http_lua_cache_loadbuffer(r->connection->log, L, llcf->body_filter_src.value.data, @@ -206,6 +210,10 @@ ngx_http_lua_body_filter_file(ngx_http_request_t *r, ngx_chain_t *in) L = ngx_http_lua_get_lua_vm(r, NULL); + if (!llcf->enable_code_cache) { + llcf->body_filter_src_ref = LUA_REFNIL; + } + /* load Lua script file (w/ cache) sp = 1 */ rc = ngx_http_lua_cache_loadfile(r->connection->log, L, script_path, &llcf->body_filter_src_ref, diff --git a/src/ngx_http_lua_contentby.c b/src/ngx_http_lua_contentby.c index 5e2ae55209..039f23ffcd 100644 --- a/src/ngx_http_lua_contentby.c +++ b/src/ngx_http_lua_contentby.c @@ -267,6 +267,10 @@ ngx_http_lua_content_handler_file(ngx_http_request_t *r) L = ngx_http_lua_get_lua_vm(r, NULL); + if (!llcf->enable_code_cache) { + llcf->content_src_ref = LUA_REFNIL; + } + /* load Lua script file (w/ cache) sp = 1 */ rc = ngx_http_lua_cache_loadfile(r->connection->log, L, script_path, &llcf->content_src_ref, @@ -297,6 +301,10 @@ ngx_http_lua_content_handler_inline(ngx_http_request_t *r) L = ngx_http_lua_get_lua_vm(r, NULL); + if (!llcf->enable_code_cache) { + llcf->content_src_ref = LUA_REFNIL; + } + /* load Lua inline script (w/ cache) sp = 1 */ rc = ngx_http_lua_cache_loadbuffer(r->connection->log, L, llcf->content_src.value.data, diff --git a/src/ngx_http_lua_headerfilterby.c b/src/ngx_http_lua_headerfilterby.c index 71553558bb..d41c055ef5 100644 --- a/src/ngx_http_lua_headerfilterby.c +++ b/src/ngx_http_lua_headerfilterby.c @@ -165,6 +165,10 @@ ngx_http_lua_header_filter_inline(ngx_http_request_t *r) L = ngx_http_lua_get_lua_vm(r, NULL); + if (!llcf->enable_code_cache) { + llcf->header_filter_src_ref = LUA_REFNIL; + } + /* load Lua inline script (w/ cache) sp = 1 */ rc = ngx_http_lua_cache_loadbuffer(r->connection->log, L, llcf->header_filter_src.value.data, @@ -210,6 +214,10 @@ ngx_http_lua_header_filter_file(ngx_http_request_t *r) L = ngx_http_lua_get_lua_vm(r, NULL); + if (!llcf->enable_code_cache) { + llcf->header_filter_src_ref = LUA_REFNIL; + } + /* load Lua script file (w/ cache) sp = 1 */ rc = ngx_http_lua_cache_loadfile(r->connection->log, L, script_path, &llcf->header_filter_src_ref, diff --git a/src/ngx_http_lua_logby.c b/src/ngx_http_lua_logby.c index b47058be19..cded8d8d04 100644 --- a/src/ngx_http_lua_logby.c +++ b/src/ngx_http_lua_logby.c @@ -149,6 +149,10 @@ ngx_http_lua_log_handler_inline(ngx_http_request_t *r) L = ngx_http_lua_get_lua_vm(r, NULL); + if (!llcf->enable_code_cache) { + llcf->log_src_ref = LUA_REFNIL; + } + /* load Lua inline script (w/ cache) sp = 1 */ rc = ngx_http_lua_cache_loadbuffer(r->connection->log, L, llcf->log_src.value.data, @@ -188,6 +192,10 @@ ngx_http_lua_log_handler_file(ngx_http_request_t *r) L = ngx_http_lua_get_lua_vm(r, NULL); + if (!llcf->enable_code_cache) { + llcf->log_src_ref = LUA_REFNIL; + } + /* load Lua script file (w/ cache) sp = 1 */ rc = ngx_http_lua_cache_loadfile(r->connection->log, L, script_path, &llcf->log_src_ref, diff --git a/src/ngx_http_lua_rewriteby.c b/src/ngx_http_lua_rewriteby.c index 2c1cc04c7a..69302ba523 100644 --- a/src/ngx_http_lua_rewriteby.c +++ b/src/ngx_http_lua_rewriteby.c @@ -177,6 +177,10 @@ ngx_http_lua_rewrite_handler_inline(ngx_http_request_t *r) llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); L = ngx_http_lua_get_lua_vm(r, NULL); + if (!llcf->enable_code_cache) { + llcf->rewrite_src_ref = LUA_REFNIL; + } + /* load Lua inline script (w/ cache) sp = 1 */ rc = ngx_http_lua_cache_loadbuffer(r->connection->log, L, llcf->rewrite_src.value.data, @@ -217,6 +221,10 @@ ngx_http_lua_rewrite_handler_file(ngx_http_request_t *r) L = ngx_http_lua_get_lua_vm(r, NULL); + if (!llcf->enable_code_cache) { + llcf->rewrite_src_ref = LUA_REFNIL; + } + /* load Lua script file (w/ cache) sp = 1 */ rc = ngx_http_lua_cache_loadfile(r->connection->log, L, script_path, &llcf->rewrite_src_ref, diff --git a/t/014-bugs.t b/t/014-bugs.t index cef20733c2..b1c7d442ae 100644 --- a/t/014-bugs.t +++ b/t/014-bugs.t @@ -9,7 +9,7 @@ log_level('debug'); repeat_each(3); # NB: the shutdown_error_log block is independent from repeat times -plan tests => repeat_each() * (blocks() * 2 + 33); +plan tests => repeat_each() * (blocks() * 2 + 41); our $HtmlDir = html_dir; #warn $html_dir; @@ -1397,3 +1397,61 @@ If-Match: 1 --- error_code: 200 --- response_body eval qr/\Ahello\z/ + + + +=== TEST 51: subrequest cycle problem in rewrite_by_lua_file +--- http_config + lua_code_cache off; +--- config + set $main "foo"; + set $sub "bar"; + location = /main { + rewrite_by_lua_file html/main.lua; + echo $main; + } + + location = /sub { + rewrite_by_lua_file html/sub.lua; + echo $sub; + } +--- user_files +>>> main.lua +local res = ngx.location.capture("/sub") +ngx.var.main = "main " .. res.body +>>> sub.lua +ngx.var.sub = "sub" + +--- pipelined_requests eval +["GET /sub", "GET /main"] +--- response_body eval +["sub\n", "main sub\n\n"] +--- no_error_log +[error] + + + +=== TEST 52: subrequest cycle problem in content_by_lua_file +--- http_config + lua_code_cache off; +--- config + location = /main { + content_by_lua_file html/main.lua; + } + + location = /sub { + content_by_lua_file html/sub.lua; + } +--- user_files +>>> main.lua +local res = ngx.location.capture("/sub") +ngx.print("main " .. res.body) +>>> sub.lua +ngx.print("sub") + +--- pipelined_requests eval +["GET /sub", "GET /main"] +--- response_body eval +["sub", "main sub"] +--- no_error_log +[error] From 90491ed33eacdbe0db92f19ccf92e1e4d67563d9 Mon Sep 17 00:00:00 2001 From: Zeping Bai Date: Thu, 23 Oct 2025 13:49:30 +0800 Subject: [PATCH 249/254] doc: tcpsock getfd typo. --- README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index 8c6edec844..eb378ac0cd 100644 --- a/README.markdown +++ b/README.markdown @@ -8156,7 +8156,7 @@ tcpsock:getfd **context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_client_hello_by_lua** -Get the file describer of the current tcp socket. +Get the file descriptor of the current tcp socket. This method was first introduced in the `v0.10.29` release. From 47e8d8b485e12cb7cb4a17da0dc828ee83a67b45 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Thu, 23 Oct 2025 14:25:16 +0800 Subject: [PATCH 250/254] doc: update latest compatible nginx version. --- README.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/README.markdown b/README.markdown index eb378ac0cd..72d59d6131 100644 --- a/README.markdown +++ b/README.markdown @@ -308,6 +308,7 @@ Nginx Compatibility The latest version of this module is compatible with the following versions of Nginx: +* 1.29.x (last tested: 1.29.2) * 1.27.x (last tested: 1.27.1) * 1.25.x (last tested: 1.25.1) * 1.21.x (last tested: 1.21.4) From a1ec138e98801400832fee6030120777bf9bb435 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Fri, 24 Oct 2025 22:51:31 +0800 Subject: [PATCH 251/254] bugfix: didn't free ngx_regex_match_context. --- src/ngx_http_lua_regex.c | 5 +++++ t/002-content.t | 1 + t/005-exit.t | 4 ++++ t/016-resp-header.t | 6 +++--- t/023-rewrite/req-socket.t | 1 + t/025-codecache.t | 2 ++ t/041-header-filter.t | 1 + t/056-flush.t | 1 + t/058-tcp-socket.t | 3 +++ t/067-req-socket.t | 2 ++ t/071-idle-socket.t | 1 + t/072-conditional-get.t | 1 + t/100-client-abort.t | 4 ++++ t/116-raw-req-socket.t | 1 + t/167-server-rewrite.t | 1 + 15 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/ngx_http_lua_regex.c b/src/ngx_http_lua_regex.c index 646b483e1f..35fe2a055c 100644 --- a/src/ngx_http_lua_regex.c +++ b/src/ngx_http_lua_regex.c @@ -501,6 +501,11 @@ ngx_http_lua_regex_cleanup(void *data) if (ngx_regex_compile_context) { old_pool = ngx_http_lua_pcre_malloc_init(NULL); + if (ngx_regex_match_context != NULL) { + pcre2_match_context_free(ngx_regex_match_context); + ngx_regex_match_context = NULL; + } + pcre2_compile_context_free(ngx_regex_compile_context); ngx_regex_compile_context = NULL; ngx_http_lua_pcre_malloc_done(old_pool); diff --git a/t/002-content.t b/t/002-content.t index eb9d587f89..26070f5287 100644 --- a/t/002-content.t +++ b/t/002-content.t @@ -1120,3 +1120,4 @@ If-Unmodified-Since: Wed, 01 Jan 2020 07:28:00 GMT --- error_code: 412 --- no_error_log unknown phase: 0 +--- skip_eval: 2:defined($ENV{MOCKEAGAIN}) && ($ENV{MOCKEAGAIN} =~ /w/) diff --git a/t/005-exit.t b/t/005-exit.t index bbaeda517e..7b82a81e4c 100644 --- a/t/005-exit.t +++ b/t/005-exit.t @@ -659,6 +659,7 @@ GET /t --- response_body_like: 403 Forbidden --- no_error_log [error] +--- skip_eval: 3:defined($ENV{MOCKEAGAIN}) && ($ENV{MOCKEAGAIN} =~ /w/) @@ -677,6 +678,7 @@ GET /t --- response_body --- no_error_log [error] +--- skip_eval: 3:defined($ENV{MOCKEAGAIN}) && ($ENV{MOCKEAGAIN} =~ /w/) @@ -713,6 +715,7 @@ F(ngx_http_lua_header_filter_by_chunk).return { --- no_error_log [error] [alert] +--- skip_eval: 4:defined($ENV{MOCKEAGAIN}) && ($ENV{MOCKEAGAIN} =~ /w/) @@ -730,6 +733,7 @@ GET /t --- response_body --- no_error_log [error] +--- skip_eval: 3:defined($ENV{MOCKEAGAIN}) && ($ENV{MOCKEAGAIN} =~ /w/) diff --git a/t/016-resp-header.t b/t/016-resp-header.t index b30090812c..f5c58fa855 100644 --- a/t/016-resp-header.t +++ b/t/016-resp-header.t @@ -2183,9 +2183,9 @@ foo: foo%0Axx:bar\r\nfoo: bar%0Dxxx:foo\r\n hi --- no_error_log [alert] ---- error_log -my Content-Length: 8589934591 -upstream prematurely closed connection while sending to client +--- error_log eval +[ "my Content-Length: 8589934591", +qr/upstream prematurely closed connection while sending to client|upstream prematurely closed connection while reading upstream/] diff --git a/t/023-rewrite/req-socket.t b/t/023-rewrite/req-socket.t index f4dd6f4e18..280001578d 100644 --- a/t/023-rewrite/req-socket.t +++ b/t/023-rewrite/req-socket.t @@ -540,3 +540,4 @@ Expect: 100-Continue \breceived: hello\b.*?\breceived: worl\b --- no_error_log [error] +--- skip_eval: 3:defined($ENV{MOCKEAGAIN}) && ($ENV{MOCKEAGAIN} =~ /w/) diff --git a/t/025-codecache.t b/t/025-codecache.t index cd56cf57aa..6e3e335097 100644 --- a/t/025-codecache.t +++ b/t/025-codecache.t @@ -855,6 +855,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/, "decrementing the reference count for Lua VM: 2", "decrementing the reference count for Lua VM: 1", ] +--- skip_eval: 11:defined($ENV{MOCKEAGAIN}) && ($ENV{MOCKEAGAIN} =~ /w/) @@ -1120,6 +1121,7 @@ qq{lua tcp socket keepalive create connection pool for key "127.0.0.1:$ENV{TEST_ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/, qr/\blua tcp socket keepalive: free connection pool [0-9A-F]+ for "127.0.0.1:/, ] +--- skip_eval: 7:defined($ENV{MOCKEAGAIN}) && ($ENV{MOCKEAGAIN} =~ /w/) diff --git a/t/041-header-filter.t b/t/041-header-filter.t index 84bb39fba2..23730815da 100644 --- a/t/041-header-filter.t +++ b/t/041-header-filter.t @@ -847,6 +847,7 @@ GET /t --- error_code: 302 --- no_error_log [error] +--- skip_eval: 3:defined($ENV{MOCKEAGAIN}) && ($ENV{MOCKEAGAIN} =~ /w/) diff --git a/t/056-flush.t b/t/056-flush.t index d2b107c754..bb81c1ecf3 100644 --- a/t/056-flush.t +++ b/t/056-flush.t @@ -43,6 +43,7 @@ hiya [error] --- error_log lua reuse free buf chain, but reallocate memory because 5 >= 0 +--- skip_eval: 4:defined($ENV{MOCKEAGAIN}) && ($ENV{MOCKEAGAIN} =~ /w/) diff --git a/t/058-tcp-socket.t b/t/058-tcp-socket.t index e17d038038..45d3073f5e 100644 --- a/t/058-tcp-socket.t +++ b/t/058-tcp-socket.t @@ -3993,6 +3993,7 @@ hello world [error] --- error_log lua tcp socket read any +--- skip_eval: 4:defined($ENV{MOCKEAGAIN}) && ($ENV{MOCKEAGAIN} ne "") @@ -4147,6 +4148,7 @@ hello world [error] --- error_log lua tcp socket calling receiveany() method to read at most 128 bytes +--- skip_eval: 4:defined($ENV{MOCKEAGAIN}) && ($ENV{MOCKEAGAIN} ne "") @@ -4222,6 +4224,7 @@ orld [error] --- error_log lua tcp socket calling receiveany() method to read at most 7 bytes +--- skip_eval: 4:defined($ENV{MOCKEAGAIN}) && ($ENV{MOCKEAGAIN} ne "") diff --git a/t/067-req-socket.t b/t/067-req-socket.t index 54d59841f9..ae6bc3f3b6 100644 --- a/t/067-req-socket.t +++ b/t/067-req-socket.t @@ -529,6 +529,7 @@ Expect: 100-Continue \breceived: hello\b.*?\breceived: worl\b --- no_error_log [error] +--- skip_eval: 3:defined($ENV{MOCKEAGAIN}) && ($ENV{MOCKEAGAIN} =~ /w/) @@ -1176,6 +1177,7 @@ GET /t received: received: abc --- no_error_log [error] +--- skip_eval: 3:defined($ENV{MOCKEAGAIN}) && ($ENV{MOCKEAGAIN} ne "") diff --git a/t/071-idle-socket.t b/t/071-idle-socket.t index 49d45a1b54..46ad84f317 100644 --- a/t/071-idle-socket.t +++ b/t/071-idle-socket.t @@ -431,3 +431,4 @@ failed to set keepalive: unread data in buffer } --- no_error_log [error] +--- skip_eval: 3:defined($ENV{MOCKEAGAIN}) && ($ENV{MOCKEAGAIN} ne "") diff --git a/t/072-conditional-get.t b/t/072-conditional-get.t index 7cf2dcd22d..d3400c613a 100644 --- a/t/072-conditional-get.t +++ b/t/072-conditional-get.t @@ -88,3 +88,4 @@ delete thread 1 say failed: nginx output filter error --- no_error_log [error] +--- skip_eval: 5:defined($ENV{MOCKEAGAIN}) && ($ENV{MOCKEAGAIN} =~ /w/) diff --git a/t/100-client-abort.t b/t/100-client-abort.t index 39d3244b16..f1f6894beb 100644 --- a/t/100-client-abort.t +++ b/t/100-client-abort.t @@ -955,6 +955,7 @@ GET /t [alert] --- error_log say failed: nginx output filter error +--- skip_eval: 3:defined($ENV{MOCKEAGAIN}) && ($ENV{MOCKEAGAIN} =~ /w/) @@ -983,6 +984,7 @@ GET /t [alert] --- error_log print failed: nginx output filter error +--- skip_eval: 3:defined($ENV{MOCKEAGAIN}) && ($ENV{MOCKEAGAIN} =~ /w/) @@ -1042,6 +1044,7 @@ GET /t [alert] --- error_log flush succeeded +--- skip_eval: 3:defined($ENV{MOCKEAGAIN}) && ($ENV{MOCKEAGAIN} =~ /w/) @@ -1072,3 +1075,4 @@ GET /t eof succeeded --- error_log eof failed: nginx output filter error +--- skip_eval: 4:defined($ENV{MOCKEAGAIN}) && ($ENV{MOCKEAGAIN} =~ /w/) diff --git a/t/116-raw-req-socket.t b/t/116-raw-req-socket.t index 94ef077c41..78a0e8d5ce 100644 --- a/t/116-raw-req-socket.t +++ b/t/116-raw-req-socket.t @@ -977,6 +977,7 @@ GET /t msg: 1: received: hello --- no_error_log [error] +--- skip_eval: 3:defined($ENV{MOCKEAGAIN}) && ($ENV{MOCKEAGAIN} ne "") diff --git a/t/167-server-rewrite.t b/t/167-server-rewrite.t index 6aea288ef8..33a30f3842 100644 --- a/t/167-server-rewrite.t +++ b/t/167-server-rewrite.t @@ -468,6 +468,7 @@ GET /lua failed to load inlined Lua code: server_rewrite_by_lua(nginx.conf:25):2: unexpected symbol near ''for end'' --- no_error_log no_such_error +--- skip_eval: 2:$ENV{TEST_NGINX_USE_HUP} From 54e813547c54fe38697672f40a8793dc57c27cbf Mon Sep 17 00:00:00 2001 From: willmafh Date: Sun, 26 Oct 2025 12:21:13 +0800 Subject: [PATCH 252/254] tests: improve openssl version check in test cases. --- t/139-ssl-cert-by.t | 2 +- t/140-ssl-c-api.t | 2 +- t/155-tls13.t | 2 +- t/166-ssl-client-hello.t | 2 +- t/187-ssl-two-verification.t | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/t/139-ssl-cert-by.t b/t/139-ssl-cert-by.t index 82ae791787..d905cb3f16 100644 --- a/t/139-ssl-cert-by.t +++ b/t/139-ssl-cert-by.t @@ -12,7 +12,7 @@ if ($openssl_version =~ m/BoringSSL/) { } if ($openssl_version =~ m/built with OpenSSL (0|1\.0\.(?:0|1[^\d]|2[a-d]).*)/) { - plan(skip_all => "too old OpenSSL, need 1.0.2e, was $1"); + plan(skip_all => "too old OpenSSL, need >= 1.0.2e, was $1"); } else { plan tests => repeat_each() * (blocks() * 6 + 4); } diff --git a/t/140-ssl-c-api.t b/t/140-ssl-c-api.t index ca04a87528..9f647c41bc 100644 --- a/t/140-ssl-c-api.t +++ b/t/140-ssl-c-api.t @@ -9,7 +9,7 @@ my $NginxBinary = $ENV{'TEST_NGINX_BINARY'} || 'nginx'; my $openssl_version = eval { `$NginxBinary -V 2>&1` }; if ($openssl_version =~ m/built with OpenSSL (0|1\.0\.(?:0|1[^\d]|2[a-d]).*)/) { - plan(skip_all => "too old OpenSSL, need 1.0.2e, was $1"); + plan(skip_all => "too old OpenSSL, need >= 1.0.2e, was $1"); } elsif ($openssl_version =~ m/BoringSSL/) { $ENV{TEST_NGINX_USE_BORINGSSL} = 1; plan tests => repeat_each() * (blocks() * 6 - 6); diff --git a/t/155-tls13.t b/t/155-tls13.t index 4e684cd335..54379e4412 100644 --- a/t/155-tls13.t +++ b/t/155-tls13.t @@ -9,7 +9,7 @@ my $NginxBinary = $ENV{'TEST_NGINX_BINARY'} || 'nginx'; my $openssl_version = eval { `$NginxBinary -V 2>&1` }; if ($openssl_version =~ m/built with OpenSSL (0\S*|1\.0\S*|1\.1\.0\S*)/) { - plan(skip_all => "too old OpenSSL, need 1.1.1, was $1"); + plan(skip_all => "too old OpenSSL, need >= 1.1.1, was $1"); } else { plan tests => repeat_each() * (blocks() * 5); } diff --git a/t/166-ssl-client-hello.t b/t/166-ssl-client-hello.t index 53109ac3df..4372d0d1f8 100644 --- a/t/166-ssl-client-hello.t +++ b/t/166-ssl-client-hello.t @@ -9,7 +9,7 @@ my $NginxBinary = $ENV{'TEST_NGINX_BINARY'} || 'nginx'; my $openssl_version = eval { `$NginxBinary -V 2>&1` }; if ($openssl_version =~ m/built with OpenSSL (0\S*|1\.0\S*|1\.1\.0\S*)/) { - plan(skip_all => "too old OpenSSL, need 1.1.1, was $1"); + plan(skip_all => "too old OpenSSL, need >= 1.1.1, was $1"); } elsif ($openssl_version =~ m/running with BoringSSL/) { plan(skip_all => "does not support BoringSSL"); } elsif ($ENV{TEST_NGINX_USE_HTTP3}) { diff --git a/t/187-ssl-two-verification.t b/t/187-ssl-two-verification.t index 312847252c..bea4aaee0f 100644 --- a/t/187-ssl-two-verification.t +++ b/t/187-ssl-two-verification.t @@ -9,7 +9,7 @@ my $NginxBinary = $ENV{'TEST_NGINX_BINARY'} || 'nginx'; my $openssl_version = eval { `$NginxBinary -V 2>&1` }; if ($openssl_version =~ m/built with OpenSSL (0\S*|1\.0\S*|1\.1\.0\S*)/) { - plan(skip_all => "too old OpenSSL, need 1.1.1, was $1"); + plan(skip_all => "too old OpenSSL, need >= 1.1.1, was $1"); } elsif ($openssl_version =~ m/running with BoringSSL/) { plan(skip_all => "does not support BoringSSL"); } else { From de02114acc8bbd4b17da933d513f736b7f45728b Mon Sep 17 00:00:00 2001 From: "Sergey A. Osokin" Date: Sun, 2 Nov 2025 21:46:46 -0500 Subject: [PATCH 253/254] optimize: add compatibility for freenginx. Commit freenginx/nginx@3329aa9 updated the ngx_http_request_t structure with the start_time; the start_sec and start_msec were removed. --- src/ngx_http_lua_subrequest.c | 6 ++++++ src/ngx_http_lua_time.c | 14 ++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/src/ngx_http_lua_subrequest.c b/src/ngx_http_lua_subrequest.c index edb24e9c0d..c9a5c08622 100644 --- a/src/ngx_http_lua_subrequest.c +++ b/src/ngx_http_lua_subrequest.c @@ -1373,7 +1373,9 @@ ngx_http_lua_subrequest(ngx_http_request_t *r, ngx_str_t *uri, ngx_str_t *args, ngx_http_request_t **psr, ngx_http_post_subrequest_t *ps, ngx_uint_t flags) { +#if !defined freenginx ngx_time_t *tp; +#endif ngx_connection_t *c; ngx_http_request_t *sr; ngx_http_core_srv_conf_t *cscf; @@ -1501,9 +1503,13 @@ ngx_http_lua_subrequest(ngx_http_request_t *r, sr->subrequests = r->subrequests - 1; #endif +#if (defined freenginx && nginx_version >= 1029000) + sr->start_time = ngx_current_msec; +#else tp = ngx_timeofday(); sr->start_sec = tp->sec; sr->start_msec = tp->msec; +#endif r->main->count++; diff --git a/src/ngx_http_lua_time.c b/src/ngx_http_lua_time.c index 72704b23a2..fa63115c4c 100644 --- a/src/ngx_http_lua_time.c +++ b/src/ngx_http_lua_time.c @@ -28,7 +28,21 @@ ngx_http_lua_ffi_now(void) double ngx_http_lua_ffi_req_start_time(ngx_http_request_t *r) { +#if (defined freenginx && nginx_version >= 1029000) + ngx_time_t *tp; + + tp = ngx_timeofday(); + tp->sec -= (ngx_current_msec - r->start_time) / 1000; + tp->msec -= (ngx_current_msec - r->start_time) % 1000; + if (tp->msec > NGX_MAX_INT_T_VALUE) { + tp->msec += 1000; + tp->sec -= 1; + } + + return tp->sec + tp->msec / 1000.0; +#else return r->start_sec + r->start_msec / 1000.0; +#endif } From 562e10690a9ce2bb8ac04cedbf18a28de64b9970 Mon Sep 17 00:00:00 2001 From: leslie Date: Sat, 8 Nov 2025 15:08:22 +0800 Subject: [PATCH 254/254] doc: fixed typo. --- README.markdown | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.markdown b/README.markdown index 72d59d6131..24f012f1c8 100644 --- a/README.markdown +++ b/README.markdown @@ -1385,7 +1385,7 @@ A zero value of `` disables the cache. Note that this feature requires OpenResty's LuaJIT with the new C API `lua_resetthread`. -This feature was first introduced in verson `v0.10.9`. +This feature was first introduced in version `v0.10.9`. [Back to TOC](#directives) @@ -6668,7 +6668,7 @@ ngx.http_time **context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, exit_worker_by_lua*, ssl_client_hello_by_lua** -Returns a formated string can be used as the http header time (for example, being used in `Last-Modified` header). The parameter `sec` is the time stamp in seconds (like those returned from [ngx.time](#ngxtime)). +Returns a formatted string can be used as the http header time (for example, being used in `Last-Modified` header). The parameter `sec` is the time stamp in seconds (like those returned from [ngx.time](#ngxtime)). ```nginx @@ -8763,9 +8763,9 @@ By default, the corresponding Nginx handler (e.g., [rewrite_by_lua](#rewrite_by_ When the user "light thread" terminates with a Lua error, however, it will not abort other running "light threads" like the "entry thread" does. -Due to the limitation in the Nginx subrequest model, it is not allowed to abort a running Nginx subrequest in general. So it is also prohibited to abort a running "light thread" that is pending on one ore more Nginx subrequests. You must call [ngx.thread.wait](#ngxthreadwait) to wait for those "light thread" to terminate before quitting the "world". A notable exception here is that you can abort pending subrequests by calling [ngx.exit](#ngxexit) with and only with the status code `ngx.ERROR` (-1), `408`, `444`, or `499`. +Due to the limitation in the Nginx subrequest model, it is not allowed to abort a running Nginx subrequest in general. So it is also prohibited to abort a running "light thread" that is pending on one or more Nginx subrequests. You must call [ngx.thread.wait](#ngxthreadwait) to wait for those "light thread" to terminate before quitting the "world". A notable exception here is that you can abort pending subrequests by calling [ngx.exit](#ngxexit) with and only with the status code `ngx.ERROR` (-1), `408`, `444`, or `499`. -The "light threads" are not scheduled in a pre-emptive way. In other words, no time-slicing is performed automatically. A "light thread" will keep running exclusively on the CPU until +The "light threads" are not scheduled in a preemptive way. In other words, no time-slicing is performed automatically. A "light thread" will keep running exclusively on the CPU until 1. a (nonblocking) I/O operation cannot be completed in a single run, 1. it calls [coroutine.yield](#coroutineyield) to actively give up execution, or