From 214580d479a6ed6f923f6b985b97aa88bad59438 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Thu, 27 Dec 2018 14:44:09 +0200 Subject: [PATCH 001/329] Add missing changelog entries Those were forgotten during the upload, but let's add them for completeness. --- debian/changelog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/debian/changelog b/debian/changelog index be5df64..93a36f2 100644 --- a/debian/changelog +++ b/debian/changelog @@ -7,6 +7,8 @@ nginx (1.14.2-2) unstable; urgency=medium [ Christos Trochalakis ] * http-dav-ext: Upgrade to 3.0.0 (Closes: #851651) + * Use a minimal export of the upstream signing key + * Bump Standards-Version, no changes needed -- Christos Trochalakis Thu, 27 Dec 2018 12:49:34 +0200 From e3f6ed2d6547bf910fe5e6a21ea660ea83b0e7b7 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Thu, 27 Dec 2018 14:44:09 +0200 Subject: [PATCH 002/329] Add missing changelog entries Those were forgotten during the upload, but let's add them for completeness. Gbp-Dch: Ignore --- debian/changelog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/debian/changelog b/debian/changelog index be5df64..93a36f2 100644 --- a/debian/changelog +++ b/debian/changelog @@ -7,6 +7,8 @@ nginx (1.14.2-2) unstable; urgency=medium [ Christos Trochalakis ] * http-dav-ext: Upgrade to 3.0.0 (Closes: #851651) + * Use a minimal export of the upstream signing key + * Bump Standards-Version, no changes needed -- Christos Trochalakis Thu, 27 Dec 2018 12:49:34 +0200 From ccedd1185b2471d7b50d5617b5383fb021001888 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Tue, 13 Aug 2019 21:04:39 +0300 Subject: [PATCH 003/329] gbp: setup for buster Gbp-Dch: Ignore --- debian/gbp.conf | 2 ++ 1 file changed, 2 insertions(+) diff --git a/debian/gbp.conf b/debian/gbp.conf index a14a699..b5fb2c9 100644 --- a/debian/gbp.conf +++ b/debian/gbp.conf @@ -2,3 +2,5 @@ pristine-tar = True upstream-branch = upstream upstream-tag = upstream/%(version)s +dist=buster +debian-branch=buster From d2bacdb1cf1068437e9ac89e334c4fe130f0107c Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Mon, 19 Aug 2019 11:33:14 +0300 Subject: [PATCH 004/329] Handle CVE-2019-9511 CVE-2019-9513 CVE-2019-9516 Several security issues were identified in nginx HTTP/2 implementation, which might cause excessive memory consumption and CPU usage (CVE-2019-9511, CVE-2019-9513, CVE-2019-9516). The issues affect nginx compiled with the ngx_http_v2_module (not compiled by default) if the "http2" option of the "listen" directive is used in a configuration file. The issues affect nginx 1.9.5 - 1.17.2. The issues are fixed in nginx 1.17.3, 1.16.1. Thanks to Jonathan Looney from Netflix for discovering these issues. --- debian/patches/CVE-2019-9511.patch | 87 ++++++++++++++++++++++++++++++ debian/patches/CVE-2019-9513.patch | 62 +++++++++++++++++++++ debian/patches/CVE-2019-9516.patch | 45 ++++++++++++++++ debian/patches/series | 3 ++ 4 files changed, 197 insertions(+) create mode 100644 debian/patches/CVE-2019-9511.patch create mode 100644 debian/patches/CVE-2019-9513.patch create mode 100644 debian/patches/CVE-2019-9516.patch diff --git a/debian/patches/CVE-2019-9511.patch b/debian/patches/CVE-2019-9511.patch new file mode 100644 index 0000000..3b48e0c --- /dev/null +++ b/debian/patches/CVE-2019-9511.patch @@ -0,0 +1,87 @@ +From 3f64486e0c15414dc6368139453dcaca338ddf3e Mon Sep 17 00:00:00 2001 +From: Ruslan Ermilov +Date: Tue, 13 Aug 2019 15:43:36 +0300 +Subject: [PATCH 2/3] HTTP/2: limited number of DATA frames. + +Fixed excessive memory growth and CPU usage if stream windows are +manipulated in a way that results in generating many small DATA frames. +Fix is to limit the number of simultaneously allocated DATA frames. +--- + src/http/v2/ngx_http_v2.c | 2 ++ + src/http/v2/ngx_http_v2.h | 2 ++ + src/http/v2/ngx_http_v2_filter_module.c | 22 +++++++++++++++++----- + 3 files changed, 21 insertions(+), 5 deletions(-) + +diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c +index be2ef82b..1b01f271 100644 +--- a/src/http/v2/ngx_http_v2.c ++++ b/src/http/v2/ngx_http_v2.c +@@ -4339,6 +4339,8 @@ ngx_http_v2_close_stream(ngx_http_v2_stream_t *stream, ngx_int_t rc) + */ + pool = stream->pool; + ++ h2c->frames -= stream->frames; ++ + ngx_http_free_request(stream->request, rc); + + if (pool != h2c->state.pool) { +diff --git a/src/http/v2/ngx_http_v2.h b/src/http/v2/ngx_http_v2.h +index bec22160..715b7d30 100644 +--- a/src/http/v2/ngx_http_v2.h ++++ b/src/http/v2/ngx_http_v2.h +@@ -192,6 +192,8 @@ struct ngx_http_v2_stream_s { + + ngx_buf_t *preread; + ++ ngx_uint_t frames; ++ + ngx_http_v2_out_frame_t *free_frames; + ngx_chain_t *free_frame_headers; + ngx_chain_t *free_bufs; +diff --git a/src/http/v2/ngx_http_v2_filter_module.c b/src/http/v2/ngx_http_v2_filter_module.c +index 029e8ece..c7ee5536 100644 +--- a/src/http/v2/ngx_http_v2_filter_module.c ++++ b/src/http/v2/ngx_http_v2_filter_module.c +@@ -1661,22 +1661,34 @@ static ngx_http_v2_out_frame_t * + ngx_http_v2_filter_get_data_frame(ngx_http_v2_stream_t *stream, + size_t len, ngx_chain_t *first, ngx_chain_t *last) + { +- u_char flags; +- ngx_buf_t *buf; +- ngx_chain_t *cl; +- ngx_http_v2_out_frame_t *frame; ++ u_char flags; ++ ngx_buf_t *buf; ++ ngx_chain_t *cl; ++ ngx_http_v2_out_frame_t *frame; ++ ngx_http_v2_connection_t *h2c; + + frame = stream->free_frames; ++ h2c = stream->connection; + + if (frame) { + stream->free_frames = frame->next; + +- } else { ++ } else if (h2c->frames < 10000) { + frame = ngx_palloc(stream->request->pool, + sizeof(ngx_http_v2_out_frame_t)); + if (frame == NULL) { + return NULL; + } ++ ++ stream->frames++; ++ h2c->frames++; ++ ++ } else { ++ ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, ++ "http2 flood detected"); ++ ++ h2c->connection->error = 1; ++ return NULL; + } + + flags = last->buf->last_buf ? NGX_HTTP_V2_END_STREAM_FLAG : 0; +-- +2.20.1 + diff --git a/debian/patches/CVE-2019-9513.patch b/debian/patches/CVE-2019-9513.patch new file mode 100644 index 0000000..edc1c2b --- /dev/null +++ b/debian/patches/CVE-2019-9513.patch @@ -0,0 +1,62 @@ +From bbdc81631b6d322785d8e92788fd400e25a931e6 Mon Sep 17 00:00:00 2001 +From: Ruslan Ermilov +Date: Tue, 13 Aug 2019 15:43:40 +0300 +Subject: [PATCH 3/3] HTTP/2: limited number of PRIORITY frames. + +Fixed excessive CPU usage caused by a peer that continuously shuffles +priority of streams. Fix is to limit the number of PRIORITY frames. +--- + src/http/v2/ngx_http_v2.c | 10 ++++++++++ + src/http/v2/ngx_http_v2.h | 1 + + 2 files changed, 11 insertions(+) + +diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c +index 1b01f271..fd6ecb05 100644 +--- a/src/http/v2/ngx_http_v2.c ++++ b/src/http/v2/ngx_http_v2.c +@@ -275,6 +275,7 @@ ngx_http_v2_init(ngx_event_t *rev) + h2scf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_v2_module); + + h2c->concurrent_pushes = h2scf->concurrent_pushes; ++ h2c->priority_limit = h2scf->concurrent_streams; + + h2c->pool = ngx_create_pool(h2scf->pool_size, h2c->connection->log); + if (h2c->pool == NULL) { +@@ -1806,6 +1807,13 @@ ngx_http_v2_state_priority(ngx_http_v2_connection_t *h2c, u_char *pos, + return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR); + } + ++ if (--h2c->priority_limit == 0) { ++ ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, ++ "client sent too many PRIORITY frames"); ++ ++ return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_ENHANCE_YOUR_CALM); ++ } ++ + if (end - pos < NGX_HTTP_V2_PRIORITY_SIZE) { + return ngx_http_v2_state_save(h2c, pos, end, + ngx_http_v2_state_priority); +@@ -3120,6 +3128,8 @@ ngx_http_v2_create_stream(ngx_http_v2_connection_t *h2c, ngx_uint_t push) + h2c->processing++; + } + ++ h2c->priority_limit += h2scf->concurrent_streams; ++ + return stream; + } + +diff --git a/src/http/v2/ngx_http_v2.h b/src/http/v2/ngx_http_v2.h +index 715b7d30..69d55d1c 100644 +--- a/src/http/v2/ngx_http_v2.h ++++ b/src/http/v2/ngx_http_v2.h +@@ -122,6 +122,7 @@ struct ngx_http_v2_connection_s { + ngx_uint_t processing; + ngx_uint_t frames; + ngx_uint_t idle; ++ ngx_uint_t priority_limit; + + ngx_uint_t pushing; + ngx_uint_t concurrent_pushes; +-- +2.20.1 + diff --git a/debian/patches/CVE-2019-9516.patch b/debian/patches/CVE-2019-9516.patch new file mode 100644 index 0000000..0d5ec77 --- /dev/null +++ b/debian/patches/CVE-2019-9516.patch @@ -0,0 +1,45 @@ +From 840d8a3e2f126384eb4ee3e5dd7ffe875a5634c5 Mon Sep 17 00:00:00 2001 +From: Sergey Kandaurov +Date: Tue, 13 Aug 2019 15:43:32 +0300 +Subject: [PATCH 1/3] HTTP/2: reject zero length headers with PROTOCOL_ERROR. + +Fixed uncontrolled memory growth if peer sends a stream of +headers with a 0-length header name and 0-length header value. +Fix is to reject headers with zero name length. +--- + src/http/v2/ngx_http_v2.c | 12 ++++++++---- + 1 file changed, 8 insertions(+), 4 deletions(-) + +diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c +index 12214e15..be2ef82b 100644 +--- a/src/http/v2/ngx_http_v2.c ++++ b/src/http/v2/ngx_http_v2.c +@@ -1548,6 +1548,14 @@ ngx_http_v2_state_process_header(ngx_http_v2_connection_t *h2c, u_char *pos, + header->name.len = h2c->state.field_end - h2c->state.field_start; + header->name.data = h2c->state.field_start; + ++ if (header->name.len == 0) { ++ ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, ++ "client sent zero header name length"); ++ ++ return ngx_http_v2_connection_error(h2c, ++ NGX_HTTP_V2_PROTOCOL_ERROR); ++ } ++ + return ngx_http_v2_state_field_len(h2c, pos, end); + } + +@@ -3249,10 +3257,6 @@ ngx_http_v2_validate_header(ngx_http_request_t *r, ngx_http_v2_header_t *header) + ngx_uint_t i; + ngx_http_core_srv_conf_t *cscf; + +- if (header->name.len == 0) { +- return NGX_ERROR; +- } +- + r->invalid_header = 0; + + cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); +-- +2.20.1 + diff --git a/debian/patches/series b/debian/patches/series index 5b6b799..dfc20c1 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -1,2 +1,5 @@ 0002-Make-sure-signature-stays-the-same-in-all-nginx-buil.patch 0003-define_gnu_source-on-other-glibc-based-platforms.patch +CVE-2019-9516.patch +CVE-2019-9511.patch +CVE-2019-9513.patch From 71e4915c0fcf970abed0d8c66a3cf86870ea0976 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Mon, 19 Aug 2019 11:33:27 +0300 Subject: [PATCH 005/329] Release 1.14.2-3 --- debian/changelog | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/debian/changelog b/debian/changelog index 93a36f2..509cc2b 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,12 @@ +nginx (1.14.2-3) unstable; urgency=high + + * Backport upstream fixes for 3 CVEs (Closes: #935037) + Those fixes affect Nginx HTTP/2 implementation, which might cause + excessive memory consumption and CPU usage. + (CVE-2019-9511, CVE-2019-9513, CVE-2019-9516). + + -- Christos Trochalakis Mon, 19 Aug 2019 11:30:08 +0300 + nginx (1.14.2-2) unstable; urgency=medium [ Kartik Mistry ] From fce697b5bc7fca3b89cfc8ebd941f8dfc5b13388 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Mon, 19 Aug 2019 11:33:14 +0300 Subject: [PATCH 006/329] Handle CVE-2019-9511 CVE-2019-9513 CVE-2019-9516 Several security issues were identified in nginx HTTP/2 implementation, which might cause excessive memory consumption and CPU usage (CVE-2019-9511, CVE-2019-9513, CVE-2019-9516). The issues affect nginx compiled with the ngx_http_v2_module (not compiled by default) if the "http2" option of the "listen" directive is used in a configuration file. The issues affect nginx 1.9.5 - 1.17.2. The issues are fixed in nginx 1.17.3, 1.16.1. Thanks to Jonathan Looney from Netflix for discovering these issues. --- debian/patches/CVE-2019-9511.patch | 87 ++++++++++++++++++++++++++++++ debian/patches/CVE-2019-9513.patch | 62 +++++++++++++++++++++ debian/patches/CVE-2019-9516.patch | 45 ++++++++++++++++ debian/patches/series | 3 ++ 4 files changed, 197 insertions(+) create mode 100644 debian/patches/CVE-2019-9511.patch create mode 100644 debian/patches/CVE-2019-9513.patch create mode 100644 debian/patches/CVE-2019-9516.patch diff --git a/debian/patches/CVE-2019-9511.patch b/debian/patches/CVE-2019-9511.patch new file mode 100644 index 0000000..3b48e0c --- /dev/null +++ b/debian/patches/CVE-2019-9511.patch @@ -0,0 +1,87 @@ +From 3f64486e0c15414dc6368139453dcaca338ddf3e Mon Sep 17 00:00:00 2001 +From: Ruslan Ermilov +Date: Tue, 13 Aug 2019 15:43:36 +0300 +Subject: [PATCH 2/3] HTTP/2: limited number of DATA frames. + +Fixed excessive memory growth and CPU usage if stream windows are +manipulated in a way that results in generating many small DATA frames. +Fix is to limit the number of simultaneously allocated DATA frames. +--- + src/http/v2/ngx_http_v2.c | 2 ++ + src/http/v2/ngx_http_v2.h | 2 ++ + src/http/v2/ngx_http_v2_filter_module.c | 22 +++++++++++++++++----- + 3 files changed, 21 insertions(+), 5 deletions(-) + +diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c +index be2ef82b..1b01f271 100644 +--- a/src/http/v2/ngx_http_v2.c ++++ b/src/http/v2/ngx_http_v2.c +@@ -4339,6 +4339,8 @@ ngx_http_v2_close_stream(ngx_http_v2_stream_t *stream, ngx_int_t rc) + */ + pool = stream->pool; + ++ h2c->frames -= stream->frames; ++ + ngx_http_free_request(stream->request, rc); + + if (pool != h2c->state.pool) { +diff --git a/src/http/v2/ngx_http_v2.h b/src/http/v2/ngx_http_v2.h +index bec22160..715b7d30 100644 +--- a/src/http/v2/ngx_http_v2.h ++++ b/src/http/v2/ngx_http_v2.h +@@ -192,6 +192,8 @@ struct ngx_http_v2_stream_s { + + ngx_buf_t *preread; + ++ ngx_uint_t frames; ++ + ngx_http_v2_out_frame_t *free_frames; + ngx_chain_t *free_frame_headers; + ngx_chain_t *free_bufs; +diff --git a/src/http/v2/ngx_http_v2_filter_module.c b/src/http/v2/ngx_http_v2_filter_module.c +index 029e8ece..c7ee5536 100644 +--- a/src/http/v2/ngx_http_v2_filter_module.c ++++ b/src/http/v2/ngx_http_v2_filter_module.c +@@ -1661,22 +1661,34 @@ static ngx_http_v2_out_frame_t * + ngx_http_v2_filter_get_data_frame(ngx_http_v2_stream_t *stream, + size_t len, ngx_chain_t *first, ngx_chain_t *last) + { +- u_char flags; +- ngx_buf_t *buf; +- ngx_chain_t *cl; +- ngx_http_v2_out_frame_t *frame; ++ u_char flags; ++ ngx_buf_t *buf; ++ ngx_chain_t *cl; ++ ngx_http_v2_out_frame_t *frame; ++ ngx_http_v2_connection_t *h2c; + + frame = stream->free_frames; ++ h2c = stream->connection; + + if (frame) { + stream->free_frames = frame->next; + +- } else { ++ } else if (h2c->frames < 10000) { + frame = ngx_palloc(stream->request->pool, + sizeof(ngx_http_v2_out_frame_t)); + if (frame == NULL) { + return NULL; + } ++ ++ stream->frames++; ++ h2c->frames++; ++ ++ } else { ++ ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, ++ "http2 flood detected"); ++ ++ h2c->connection->error = 1; ++ return NULL; + } + + flags = last->buf->last_buf ? NGX_HTTP_V2_END_STREAM_FLAG : 0; +-- +2.20.1 + diff --git a/debian/patches/CVE-2019-9513.patch b/debian/patches/CVE-2019-9513.patch new file mode 100644 index 0000000..edc1c2b --- /dev/null +++ b/debian/patches/CVE-2019-9513.patch @@ -0,0 +1,62 @@ +From bbdc81631b6d322785d8e92788fd400e25a931e6 Mon Sep 17 00:00:00 2001 +From: Ruslan Ermilov +Date: Tue, 13 Aug 2019 15:43:40 +0300 +Subject: [PATCH 3/3] HTTP/2: limited number of PRIORITY frames. + +Fixed excessive CPU usage caused by a peer that continuously shuffles +priority of streams. Fix is to limit the number of PRIORITY frames. +--- + src/http/v2/ngx_http_v2.c | 10 ++++++++++ + src/http/v2/ngx_http_v2.h | 1 + + 2 files changed, 11 insertions(+) + +diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c +index 1b01f271..fd6ecb05 100644 +--- a/src/http/v2/ngx_http_v2.c ++++ b/src/http/v2/ngx_http_v2.c +@@ -275,6 +275,7 @@ ngx_http_v2_init(ngx_event_t *rev) + h2scf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_v2_module); + + h2c->concurrent_pushes = h2scf->concurrent_pushes; ++ h2c->priority_limit = h2scf->concurrent_streams; + + h2c->pool = ngx_create_pool(h2scf->pool_size, h2c->connection->log); + if (h2c->pool == NULL) { +@@ -1806,6 +1807,13 @@ ngx_http_v2_state_priority(ngx_http_v2_connection_t *h2c, u_char *pos, + return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR); + } + ++ if (--h2c->priority_limit == 0) { ++ ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, ++ "client sent too many PRIORITY frames"); ++ ++ return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_ENHANCE_YOUR_CALM); ++ } ++ + if (end - pos < NGX_HTTP_V2_PRIORITY_SIZE) { + return ngx_http_v2_state_save(h2c, pos, end, + ngx_http_v2_state_priority); +@@ -3120,6 +3128,8 @@ ngx_http_v2_create_stream(ngx_http_v2_connection_t *h2c, ngx_uint_t push) + h2c->processing++; + } + ++ h2c->priority_limit += h2scf->concurrent_streams; ++ + return stream; + } + +diff --git a/src/http/v2/ngx_http_v2.h b/src/http/v2/ngx_http_v2.h +index 715b7d30..69d55d1c 100644 +--- a/src/http/v2/ngx_http_v2.h ++++ b/src/http/v2/ngx_http_v2.h +@@ -122,6 +122,7 @@ struct ngx_http_v2_connection_s { + ngx_uint_t processing; + ngx_uint_t frames; + ngx_uint_t idle; ++ ngx_uint_t priority_limit; + + ngx_uint_t pushing; + ngx_uint_t concurrent_pushes; +-- +2.20.1 + diff --git a/debian/patches/CVE-2019-9516.patch b/debian/patches/CVE-2019-9516.patch new file mode 100644 index 0000000..0d5ec77 --- /dev/null +++ b/debian/patches/CVE-2019-9516.patch @@ -0,0 +1,45 @@ +From 840d8a3e2f126384eb4ee3e5dd7ffe875a5634c5 Mon Sep 17 00:00:00 2001 +From: Sergey Kandaurov +Date: Tue, 13 Aug 2019 15:43:32 +0300 +Subject: [PATCH 1/3] HTTP/2: reject zero length headers with PROTOCOL_ERROR. + +Fixed uncontrolled memory growth if peer sends a stream of +headers with a 0-length header name and 0-length header value. +Fix is to reject headers with zero name length. +--- + src/http/v2/ngx_http_v2.c | 12 ++++++++---- + 1 file changed, 8 insertions(+), 4 deletions(-) + +diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c +index 12214e15..be2ef82b 100644 +--- a/src/http/v2/ngx_http_v2.c ++++ b/src/http/v2/ngx_http_v2.c +@@ -1548,6 +1548,14 @@ ngx_http_v2_state_process_header(ngx_http_v2_connection_t *h2c, u_char *pos, + header->name.len = h2c->state.field_end - h2c->state.field_start; + header->name.data = h2c->state.field_start; + ++ if (header->name.len == 0) { ++ ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, ++ "client sent zero header name length"); ++ ++ return ngx_http_v2_connection_error(h2c, ++ NGX_HTTP_V2_PROTOCOL_ERROR); ++ } ++ + return ngx_http_v2_state_field_len(h2c, pos, end); + } + +@@ -3249,10 +3257,6 @@ ngx_http_v2_validate_header(ngx_http_request_t *r, ngx_http_v2_header_t *header) + ngx_uint_t i; + ngx_http_core_srv_conf_t *cscf; + +- if (header->name.len == 0) { +- return NGX_ERROR; +- } +- + r->invalid_header = 0; + + cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); +-- +2.20.1 + diff --git a/debian/patches/series b/debian/patches/series index 5b6b799..dfc20c1 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -1,2 +1,5 @@ 0002-Make-sure-signature-stays-the-same-in-all-nginx-buil.patch 0003-define_gnu_source-on-other-glibc-based-platforms.patch +CVE-2019-9516.patch +CVE-2019-9511.patch +CVE-2019-9513.patch From 117fc2156ffdf628d28bb469b920f7d4cbf19d2c Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Mon, 19 Aug 2019 13:03:31 +0300 Subject: [PATCH 007/329] Release 1.14.2-2+deb10u1 --- debian/changelog | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/debian/changelog b/debian/changelog index 93a36f2..b2c8dc3 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,12 @@ +nginx (1.14.2-2+deb10u1) buster-security; urgency=high + + * Backport upstream fixes for 3 CVEs (Closes: #935037) + Those fixes affect Nginx HTTP/2 implementation, which might cause + excessive memory consumption and CPU usage. + (CVE-2019-9511, CVE-2019-9513, CVE-2019-9516). + + -- Christos Trochalakis Tue, 13 Aug 2019 21:10:28 +0300 + nginx (1.14.2-2) unstable; urgency=medium [ Kartik Mistry ] From deba07f09f0f530f083263c966e72331911a28a4 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Sun, 8 Sep 2019 10:33:34 +0300 Subject: [PATCH 008/329] Follow stable 1.16 releases --- debian/watch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/watch b/debian/watch index 42f4680..1aeff3e 100644 --- a/debian/watch +++ b/debian/watch @@ -1,3 +1,3 @@ version=3 opts=pgpsigurlmangle=s/$/.asc/ \ -https://nginx.org/download/nginx-(1\.14\.\d+)\.tar\.gz +https://nginx.org/download/nginx-(1\.16\.\d+)\.tar\.gz From c717ecb9266f65e0bd1579588710a2782bbb8e1f Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Sun, 8 Sep 2019 10:36:13 +0300 Subject: [PATCH 009/329] New upstream version 1.16.1 --- CHANGES | 254 +++- CHANGES.ru | 260 +++- LICENSE | 4 +- auto/cc/clang | 3 +- auto/cc/msvc | 2 +- auto/lib/google-perftools/conf | 3 +- auto/lib/libgd/conf | 6 +- auto/lib/libxslt/conf | 4 +- auto/make | 2 +- auto/modules | 21 + auto/options | 10 + auto/os/linux | 2 + auto/os/win32 | 8 +- auto/sources | 2 + conf/mime.types | 4 +- contrib/vim/syntax/nginx.vim | 79 +- html/50x.html | 2 +- src/core/nginx.h | 4 +- src/core/ngx_buf.c | 1 + src/core/ngx_conf_file.c | 9 +- src/core/ngx_connection.c | 71 +- src/core/ngx_connection.h | 7 +- src/core/ngx_core.h | 1 + src/core/ngx_cycle.c | 67 +- src/core/ngx_file.c | 27 +- src/core/ngx_inet.c | 468 +++--- src/core/ngx_inet.h | 2 + src/core/ngx_output_chain.c | 64 +- src/core/ngx_resolver.c | 133 +- src/core/ngx_slab.c | 3 +- src/core/ngx_string.c | 10 +- src/core/ngx_string.h | 2 + src/core/ngx_syslog.c | 38 +- src/core/ngx_syslog.h | 1 - src/core/ngx_times.h | 4 +- src/event/modules/ngx_eventport_module.c | 2 - src/event/modules/ngx_poll_module.c | 2 +- src/event/modules/ngx_win32_poll_module.c | 435 ++++++ src/event/modules/ngx_win32_select_module.c | 17 +- src/event/ngx_event.c | 40 + src/event/ngx_event.h | 9 +- src/event/ngx_event_accept.c | 346 +---- src/event/ngx_event_connect.c | 16 +- src/event/ngx_event_connect.h | 2 + src/event/ngx_event_openssl.c | 1267 ++++++++++++++--- src/event/ngx_event_openssl.h | 27 +- src/event/ngx_event_openssl_stapling.c | 7 +- src/event/ngx_event_udp.c | 663 +++++++++ src/http/modules/ngx_http_autoindex_module.c | 70 +- src/http/modules/ngx_http_dav_module.c | 4 +- src/http/modules/ngx_http_fastcgi_module.c | 13 +- src/http/modules/ngx_http_geo_module.c | 13 + src/http/modules/ngx_http_grpc_module.c | 21 +- src/http/modules/ngx_http_limit_req_module.c | 63 +- src/http/modules/ngx_http_memcached_module.c | 13 +- src/http/modules/ngx_http_proxy_module.c | 21 +- .../modules/ngx_http_random_index_module.c | 2 +- src/http/modules/ngx_http_rewrite_module.c | 10 +- src/http/modules/ngx_http_scgi_module.c | 13 +- src/http/modules/ngx_http_ssl_module.c | 190 ++- src/http/modules/ngx_http_ssl_module.h | 4 + .../modules/ngx_http_upstream_hash_module.c | 8 +- .../ngx_http_upstream_ip_hash_module.c | 8 +- .../ngx_http_upstream_keepalive_module.c | 41 +- .../modules/ngx_http_upstream_random_module.c | 502 +++++++ .../modules/ngx_http_userid_filter_module.c | 7 + src/http/modules/ngx_http_uwsgi_module.c | 31 +- src/http/ngx_http.c | 38 +- src/http/ngx_http.h | 4 + src/http/ngx_http_core_module.c | 87 +- src/http/ngx_http_core_module.h | 8 +- src/http/ngx_http_file_cache.c | 44 +- src/http/ngx_http_parse.c | 5 + src/http/ngx_http_request.c | 252 +++- src/http/ngx_http_request.h | 5 + src/http/ngx_http_script.c | 28 + src/http/ngx_http_script.h | 2 + src/http/ngx_http_special_response.c | 68 +- src/http/ngx_http_upstream.c | 89 +- src/http/ngx_http_upstream.h | 4 +- src/http/ngx_http_upstream_round_robin.c | 2 +- src/http/ngx_http_variables.c | 4 +- src/http/ngx_http_write_filter_module.c | 40 +- src/http/v2/ngx_http_v2.c | 96 +- src/http/v2/ngx_http_v2.h | 3 + src/http/v2/ngx_http_v2_filter_module.c | 48 +- src/mail/ngx_mail.c | 42 +- src/mail/ngx_mail.h | 3 +- src/mail/ngx_mail_core_module.c | 92 +- src/mail/ngx_mail_handler.c | 18 +- src/mail/ngx_mail_ssl_module.c | 96 +- src/mail/ngx_mail_ssl_module.h | 1 + src/os/unix/ngx_file_aio_read.c | 2 +- src/os/unix/ngx_files.h | 3 - src/os/unix/ngx_freebsd_config.h | 6 + src/os/unix/ngx_thread.h | 4 +- src/stream/ngx_stream.c | 46 +- src/stream/ngx_stream.h | 3 +- src/stream/ngx_stream_core_module.c | 121 +- src/stream/ngx_stream_geo_module.c | 13 + src/stream/ngx_stream_proxy_module.c | 279 +++- src/stream/ngx_stream_ssl_module.c | 238 +++- src/stream/ngx_stream_ssl_module.h | 7 + src/stream/ngx_stream_ssl_preread_module.c | 111 +- src/stream/ngx_stream_upstream.c | 16 +- src/stream/ngx_stream_upstream.h | 2 + src/stream/ngx_stream_upstream_hash_module.c | 8 +- .../ngx_stream_upstream_random_module.c | 502 +++++++ src/stream/ngx_stream_upstream_round_robin.c | 2 +- src/stream/ngx_stream_write_filter_module.c | 40 +- 110 files changed, 6258 insertions(+), 1669 deletions(-) create mode 100644 src/event/modules/ngx_win32_poll_module.c create mode 100644 src/event/ngx_event_udp.c create mode 100644 src/http/modules/ngx_http_upstream_random_module.c create mode 100644 src/stream/ngx_stream_upstream_random_module.c diff --git a/CHANGES b/CHANGES index 597c270..8e7382b 100644 --- a/CHANGES +++ b/CHANGES @@ -1,38 +1,99 @@ -Changes with nginx 1.14.2 04 Dec 2018 +Changes with nginx 1.16.1 13 Aug 2019 - *) Bugfix: nginx could not be built by gcc 8.1. + *) Security: when using HTTP/2 a client might cause excessive memory + consumption and CPU usage (CVE-2019-9511, CVE-2019-9513, + CVE-2019-9516). - *) Bugfix: nginx could not be built on Fedora 28 Linux. - *) Bugfix: in handling of client addresses when using unix domain listen - sockets to work with datagrams on Linux. +Changes with nginx 1.16.0 23 Apr 2019 - *) Change: the logging level of the "http request", "https proxy - request", "unsupported protocol", "version too low", "no suitable key - share", and "no suitable signature algorithm" SSL errors has been - lowered from "crit" to "info". + *) 1.16.x stable branch. - *) Bugfix: when using OpenSSL 1.1.0 or newer it was not possible to - switch off "ssl_prefer_server_ciphers" in a virtual server if it was - switched on in the default server. - *) Bugfix: nginx could not be built with LibreSSL 2.8.0. +Changes with nginx 1.15.12 16 Apr 2019 - *) Bugfix: if nginx was built with OpenSSL 1.1.0 and used with OpenSSL - 1.1.1, the TLS 1.3 protocol was always enabled. + *) Bugfix: a segmentation fault might occur in a worker process if + variables were used in the "ssl_certificate" or "ssl_certificate_key" + directives and OCSP stapling was enabled. - *) Bugfix: sending a disk-buffered request body to a gRPC backend might - fail. - *) Bugfix: connections with some gRPC backends might not be cached when - using the "keepalive" directive. +Changes with nginx 1.15.11 09 Apr 2019 + + *) Bugfix: in the "ssl_stapling_file" directive on Windows. + + +Changes with nginx 1.15.10 26 Mar 2019 + + *) Change: when using a hostname in the "listen" directive nginx now + creates listening sockets for all addresses the hostname resolves to + (previously, only the first address was used). + + *) Feature: port ranges in the "listen" directive. + + *) Feature: loading of SSL certificates and secret keys from variables. + + *) Workaround: the $ssl_server_name variable might be empty when using + OpenSSL 1.1.1. + + *) Bugfix: nginx/Windows could not be built with Visual Studio 2015 or + newer; the bug had appeared in 1.15.9. + + +Changes with nginx 1.15.9 26 Feb 2019 + + *) Feature: variables support in the "ssl_certificate" and + "ssl_certificate_key" directives. + + *) Feature: the "poll" method is now available on Windows when using + Windows Vista or newer. + + *) Bugfix: if the "select" method was used on Windows and an error + occurred while establishing a backend connection, nginx waited for + the connection establishment timeout to expire. + + *) Bugfix: the "proxy_upload_rate" and "proxy_download_rate" directives + in the stream module worked incorrectly when proxying UDP datagrams. + + +Changes with nginx 1.15.8 25 Dec 2018 + + *) Feature: the $upstream_bytes_sent variable. + Thanks to Piotr Sikora. + + *) Feature: new directives in vim syntax highlighting scripts. + Thanks to Gena Makhomed. + + *) Bugfix: in the "proxy_cache_background_update" directive. + + *) Bugfix: in the "geo" directive when using unix domain listen sockets. + + *) Workaround: the "ignoring stale global SSL error ... bad length" + alerts might appear in logs when using the "ssl_early_data" directive + with OpenSSL. + + *) Bugfix: in nginx/Windows. + + *) Bugfix: in the ngx_http_autoindex_module on 32-bit platforms. + + +Changes with nginx 1.15.7 27 Nov 2018 + + *) Feature: the "proxy_requests" directive in the stream module. + + *) Feature: the "delay" parameter of the "limit_req" directive. + Thanks to Vladislav Shabanov and Peter Shchuchkin. + + *) Bugfix: memory leak on errors during reconfiguration. + + *) Bugfix: in the $upstream_response_time, $upstream_connect_time, and + $upstream_header_time variables. *) Bugfix: a segmentation fault might occur in a worker process if the ngx_http_mp4_module was used on 32-bit platforms. -Changes with nginx 1.14.1 06 Nov 2018 +Changes with nginx 1.15.6 06 Nov 2018 *) Security: when using HTTP/2 a client might cause excessive memory consumption (CVE-2018-16843) and CPU usage (CVE-2018-16844). @@ -41,13 +102,162 @@ Changes with nginx 1.14.1 06 Nov 2018 ngx_http_mp4_module might result in worker process memory disclosure (CVE-2018-16845). + *) Feature: the "proxy_socket_keepalive", "fastcgi_socket_keepalive", + "grpc_socket_keepalive", "memcached_socket_keepalive", + "scgi_socket_keepalive", and "uwsgi_socket_keepalive" directives. + + *) Bugfix: if nginx was built with OpenSSL 1.1.0 and used with OpenSSL + 1.1.1, the TLS 1.3 protocol was always enabled. + *) Bugfix: working with gRPC backends might result in excessive memory consumption. -Changes with nginx 1.14.0 17 Apr 2018 +Changes with nginx 1.15.5 02 Oct 2018 - *) 1.14.x stable branch. + *) Bugfix: a segmentation fault might occur in a worker process when + using OpenSSL 1.1.0h or newer; the bug had appeared in 1.15.4. + + *) Bugfix: of minor potential bugs. + + +Changes with nginx 1.15.4 25 Sep 2018 + + *) Feature: now the "ssl_early_data" directive can be used with OpenSSL. + + *) Bugfix: in the ngx_http_uwsgi_module. + Thanks to Chris Caputo. + + *) Bugfix: connections with some gRPC backends might not be cached when + using the "keepalive" directive. + + *) Bugfix: a socket leak might occur when using the "error_page" + directive to redirect early request processing errors, notably errors + with code 400. + + *) Bugfix: the "return" directive did not change the response code when + returning errors if the request was redirected by the "error_page" + directive. + + *) Bugfix: standard error pages and responses of the + ngx_http_autoindex_module module used the "bgcolor" attribute, and + might be displayed incorrectly when using custom color settings in + browsers. + Thanks to Nova DasSarma. + + *) Change: the logging level of the "no suitable key share" and "no + suitable signature algorithm" SSL errors has been lowered from "crit" + to "info". + + +Changes with nginx 1.15.3 28 Aug 2018 + + *) Feature: now TLSv1.3 can be used with BoringSSL. + + *) Feature: the "ssl_early_data" directive, currently available with + BoringSSL. + + *) Feature: the "keepalive_timeout" and "keepalive_requests" directives + in the "upstream" block. + + *) Bugfix: the ngx_http_dav_module did not truncate destination file + when copying a file over an existing one with the COPY method. + + *) Bugfix: the ngx_http_dav_module used zero access rights on the + destination file and did not preserve file modification time when + moving a file between different file systems with the MOVE method. + + *) Bugfix: the ngx_http_dav_module used default access rights when + copying a file with the COPY method. + + *) Workaround: some clients might not work when using HTTP/2; the bug + had appeared in 1.13.5. + + *) Bugfix: nginx could not be built with LibreSSL 2.8.0. + + +Changes with nginx 1.15.2 24 Jul 2018 + + *) Feature: the $ssl_preread_protocol variable in the + ngx_stream_ssl_preread_module. + + *) Feature: now when using the "reset_timedout_connection" directive + nginx will reset connections being closed with the 444 code. + + *) Change: a logging level of the "http request", "https proxy request", + "unsupported protocol", and "version too low" SSL errors has been + lowered from "crit" to "info". + + *) Bugfix: DNS requests were not resent if initial sending of a request + failed. + + *) Bugfix: the "reuseport" parameter of the "listen" directive was + ignored if the number of worker processes was specified after the + "listen" directive. + + *) Bugfix: when using OpenSSL 1.1.0 or newer it was not possible to + switch off "ssl_prefer_server_ciphers" in a virtual server if it was + switched on in the default server. + + *) Bugfix: SSL session reuse with upstream servers did not work with the + TLS 1.3 protocol. + + +Changes with nginx 1.15.1 03 Jul 2018 + + *) Feature: the "random" directive inside the "upstream" block. + + *) Feature: improved performance when using the "hash" and "ip_hash" + directives with the "zone" directive. + + *) Feature: the "reuseport" parameter of the "listen" directive now uses + SO_REUSEPORT_LB on FreeBSD 12. + + *) Bugfix: HTTP/2 server push did not work if SSL was terminated by a + proxy server in front of nginx. + + *) Bugfix: the "tcp_nopush" directive was always used on backend + connections. + + *) Bugfix: sending a disk-buffered request body to a gRPC backend might + fail. + + +Changes with nginx 1.15.0 05 Jun 2018 + + *) Change: the "ssl" directive is deprecated; the "ssl" parameter of the + "listen" directive should be used instead. + + *) Change: now nginx detects missing SSL certificates during + configuration testing when using the "ssl" parameter of the "listen" + directive. + + *) Feature: now the stream module can handle multiple incoming UDP + datagrams from a client within a single session. + + *) Bugfix: it was possible to specify an incorrect response code in the + "proxy_cache_valid" directive. + + *) Bugfix: nginx could not be built by gcc 8.1. + + *) Bugfix: logging to syslog stopped on local IP address changes. + + *) Bugfix: nginx could not be built by clang with CUDA SDK installed; + the bug had appeared in 1.13.8. + + *) Bugfix: "getsockopt(TCP_FASTOPEN) ... failed" messages might appear + in logs during binary upgrade when using unix domain listen sockets + on FreeBSD. + + *) Bugfix: nginx could not be built on Fedora 28 Linux. + + *) Bugfix: request processing rate might exceed configured rate when + using the "limit_req" directive. + + *) Bugfix: in handling of client addresses when using unix domain listen + sockets to work with datagrams on Linux. + + *) Bugfix: in memory allocation error handling. Changes with nginx 1.13.12 10 Apr 2018 diff --git a/CHANGES.ru b/CHANGES.ru index 8c260fe..5d60f41 100644 --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,39 +1,103 @@ -Изменения в nginx 1.14.2 04.12.2018 +Изменения в nginx 1.16.1 13.08.2019 - *) Исправление: nginx не собирался gcc 8.1. + *) Безопасность: при использовании HTTP/2 клиент мог вызвать чрезмерное + потребление памяти и ресурсов процессора (CVE-2019-9511, + CVE-2019-9513, CVE-2019-9516). - *) Исправление: nginx не собирался на Fedora 28 Linux. - *) Исправление: в обработке адресов клиентов при использовании unix - domain listen-сокетов для работы с датаграммами на Linux. +Изменения в nginx 1.16.0 23.04.2019 - *) Изменение: уровень логгирования ошибок SSL "http request", "https - proxy request", "unsupported protocol", "version too low", "no - suitable key share" и "no suitable signature algorithm" понижен с - уровня crit до info. + *) Стабильная ветка 1.16.x. - *) Исправление: при использовании OpenSSL 1.1.0 и новее директиву - ssl_prefer_server_ciphers нельзя было выключить в виртуальном - сервере, если она была включена в сервере по умолчанию. - *) Исправление: nginx не собирался с LibreSSL 2.8.0. +Изменения в nginx 1.15.12 16.04.2019 - *) Исправление: если nginx был собран с OpenSSL 1.1.0, а использовался с - OpenSSL 1.1.1, протокол TLS 1.3 всегда был разрешён. + *) Исправление: в рабочем процессе мог произойти segmentation fault, + если в директивах ssl_certificate или ssl_certificate_key + использовались переменные и был включён OCSP stapling. - *) Исправление: при отправке сохранённого на диск тела запроса на - gRPC-бэкенд могли возникать ошибки. - *) Исправление: соединения к некоторым gRPC-бэкендам могли не - кэшироваться при использовании директивы keepalive. +Изменения в nginx 1.15.11 09.04.2019 + + *) Исправление: в директиве ssl_stapling_file на Windows. + + +Изменения в nginx 1.15.10 26.03.2019 + + *) Изменение: теперь при использовании имени хоста в директиве listen + nginx создаёт listen-сокеты для всех адресов, соответствующих этому + имени (ранее использовался только первый адрес). + + *) Добавление: диапазоны портов в директиве listen. + + *) Добавление: возможность загрузки SSL-сертификатов и секретных ключей + из переменных. + + *) Изменение: переменная $ssl_server_name могла быть пустой при + использовании OpenSSL 1.1.1. + + *) Исправление: nginx/Windows не собирался с Visual Studio 2015 и новее; + ошибка появилась в 1.15.9. + + +Изменения в nginx 1.15.9 26.02.2019 + + *) Добавление: директивы ssl_certificate и ssl_certificate_key + поддерживают переменные. + + *) Добавление: метод poll теперь доступен на Windows при использовании + Windows Vista и новее. + + *) Исправление: если при использовании метода select на Windows + происходила ошибка при установлении соединения с бэкендом, nginx + ожидал истечения таймаута на установление соединения. + + *) Исправление: директивы proxy_upload_rate и proxy_download_rate в + модуле stream работали некорректно при проксировании UDP-пакетов. + + +Изменения в nginx 1.15.8 25.12.2018 + + *) Добавление: переменная $upstream_bytes_sent. + Спасибо Piotr Sikora. + + *) Добавление: новые директивы в скриптах подсветки синтаксиса для vim. + Спасибо Геннадию Махомеду. + + *) Исправление: в директиве proxy_cache_background_update. + + *) Исправление: в директиве geo при использовании unix domain + listen-сокетов. + + *) Изменение: при использовании директивы ssl_early_data с OpenSSL в + логах могли появляться сообщения "ignoring stale global SSL error ... + bad length". + + *) Исправление: в nginx/Windows. + + *) Исправление: в модуле ngx_http_autoindex_module на 32-битных + платформах. + + +Изменения в nginx 1.15.7 27.11.2018 + + *) Добавление: директива proxy_requests в модуле stream. + + *) Добавление: параметр "delay" директивы "limit_req". + Спасибо Владиславу Шабанову и Петру Щучкину. + + *) Исправление: утечки памяти в случае ошибок при переконфигурации. + + *) Исправление: в переменных $upstream_response_time, + $upstream_connect_time и $upstream_header_time. *) Исправление: в рабочем процессе мог произойти segmentation fault, если использовался модуль ngx_http_mp4_module на 32-битных платформах. -Изменения в nginx 1.14.1 06.11.2018 +Изменения в nginx 1.15.6 06.11.2018 *) Безопасность: при использовании HTTP/2 клиент мог вызвать чрезмерное потреблению памяти (CVE-2018-16843) и ресурсов процессора @@ -43,13 +107,165 @@ ngx_http_mp4_module содержимое памяти рабочего процесса могло быть отправлено клиенту (CVE-2018-16845). + *) Добавление: директивы proxy_socket_keepalive, + fastcgi_socket_keepalive, grpc_socket_keepalive, + memcached_socket_keepalive, scgi_socket_keepalive и + uwsgi_socket_keepalive. + + *) Исправление: если nginx был собран с OpenSSL 1.1.0, а использовался с + OpenSSL 1.1.1, протокол TLS 1.3 всегда был разрешён. + *) Исправление: при работе с gRPC-бэкендами могло расходоваться большое количество памяти. -Изменения в nginx 1.14.0 17.04.2018 +Изменения в nginx 1.15.5 02.10.2018 - *) Стабильная ветка 1.14.x. + *) Исправление: при использовании OpenSSL 1.1.0h и новее в рабочем + процессе мог произойти segmentation fault; ошибка появилась в 1.15.4. + + *) Исправление: незначительных потенциальных ошибок. + + +Изменения в nginx 1.15.4 25.09.2018 + + *) Добавление: теперь директиву ssl_early_data можно использовать с + OpenSSL. + + *) Исправление: в модуле ngx_http_uwsgi_module. + Спасибо Chris Caputo. + + *) Исправление: соединения к некоторым gRPC-бэкендам могли не + кэшироваться при использовании директивы keepalive. + + *) Исправление: при использовании директивы error_page для + перенаправления ошибок, возникающих на ранних этапах обработки + запроса, в частности ошибок с кодом 400, могла происходить утечка + сокетов. + + *) Исправление: директива return при возврате ошибок не изменяла код + ответа, если запрос был перенаправлен с помощью директивы error_page. + + *) Исправление: стандартные сообщения об ошибках и ответы модуля + ngx_http_autoindex_module содержали атрибут bgcolor, что могло + приводить к их некорректному отображению при использовании + пользовательских настроек цветов в браузерах. + Спасибо Nova DasSarma. + + *) Изменение: уровень логгирования ошибок SSL "no suitable key share" и + "no suitable signature algorithm" понижен с уровня crit до info. + + +Изменения в nginx 1.15.3 28.08.2018 + + *) Добавление: теперь TLSv1.3 можно использовать с BoringSSL. + + *) Добавление: директива ssl_early_data, сейчас доступна при + использовании BoringSSL. + + *) Добавление: директивы keepalive_timeout и keepalive_requests в блоке + upstream. + + *) Исправление: модуль ngx_http_dav_module при копировании файла поверх + существующего файла с помощью метода COPY не обнулял целевой файл. + + *) Исправление: модуль ngx_http_dav_module при перемещении файла между + файловыми системами с помощью метода MOVE устанавливал нулевые права + доступа на результирующий файл и не сохранял время изменения файла. + + *) Исправление: модуль ngx_http_dav_module при копировании файла с + помощью метода COPY для результирующего файла использовал права + доступа по умолчанию. + + *) Изменение: некоторые клиенты могли не работать при использовании + HTTP/2; ошибка появилась в 1.13.5. + + *) Исправление: nginx не собирался с LibreSSL 2.8.0. + + +Изменения в nginx 1.15.2 24.07.2018 + + *) Добавление: переменная $ssl_preread_protocol в модуле + ngx_stream_ssl_preread_module. + + *) Добавление: теперь при использовании директивы + reset_timedout_connection nginx сбрасывает соединения, закрываемые с + кодом 444. + + *) Изменение: уровень логгирования ошибок SSL "http request", "https + proxy request", "unsupported protocol" и "version too low" понижен с + уровня crit до info. + + *) Исправление: запросы к DNS-серверу не отправлялись повторно, если при + первой попытке отправки происходила ошибка. + + *) Исправление: параметр reuseport директивы listen игнорировался, если + количество рабочих процессов было задано после директивы listen. + + *) Исправление: при использовании OpenSSL 1.1.0 и новее директиву + ssl_prefer_server_ciphers нельзя было выключить в виртуальном + сервере, если она была включена в сервере по умолчанию. + + *) Исправление: повторное использование SSL-сессий к бэкендам не + работало с протоколом TLS 1.3. + + +Изменения в nginx 1.15.1 03.07.2018 + + *) Добавление: директива random в блоке upstream. + + *) Добавление: улучшена производительность при использовании директив + hash и ip_hash совместно с директивой zone. + + *) Добавление: параметр reuseport директивы listen теперь использует + SO_REUSEPORT_LB на FreeBSD 12. + + *) Исправление: HTTP/2 server push не работал, если SSL терминировался + прокси-сервером перед nginx'ом. + + *) Исправление: директива tcp_nopush всегда использовалась для + соединений к бэкендам. + + *) Исправление: при отправке сохранённого на диск тела запроса на + gRPC-бэкенд могли возникать ошибки. + + +Изменения в nginx 1.15.0 05.06.2018 + + *) Изменение: директива "ssl" теперь считается устаревшей; вместо неё + следует использовать параметр ssl директивы listen. + + *) Изменение: теперь при использовании директивы listen с параметром ssl + nginx определяет отсутствие SSL-сертификатов при тестировании + конфигурации. + + *) Добавление: теперь модуль stream умеет обрабатывать несколько + входящих UDP-пакетов от клиента в рамках одной сессии. + + *) Исправление: в директиве proxy_cache_valid можно было указать + некорректный код ответа. + + *) Исправление: nginx не собирался gcc 8.1. + + *) Исправление: логгирование в syslog останавливалось при изменении + локального IP-адреса. + + *) Исправление: nginx не собирался компилятором clang, если был + установлен CUDA SDK; ошибка появилась в 1.13.8. + + *) Исправление: при использовании unix domain listen-сокетов на FreeBSD + в процессе обновления исполняемого файла в логе могли появляться + сообщения "getsockopt(TCP_FASTOPEN) ... failed". + + *) Исправление: nginx не собирался на Fedora 28 Linux. + + *) Исправление: при использовании директивы limit_req заданная скорость + обработки запросов могла не соблюдаться. + + *) Исправление: в обработке адресов клиентов при использовании unix + domain listen-сокетов для работы с датаграммами на Linux. + + *) Исправление: в обработке ошибок выделения памяти. Изменения в nginx 1.13.12 10.04.2018 diff --git a/LICENSE b/LICENSE index 9401174..c63e0ba 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ /* - * Copyright (C) 2002-2018 Igor Sysoev - * Copyright (C) 2011-2018 Nginx, Inc. + * Copyright (C) 2002-2019 Igor Sysoev + * Copyright (C) 2011-2019 Nginx, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/auto/cc/clang b/auto/cc/clang index 9d900c2..a962ee2 100644 --- a/auto/cc/clang +++ b/auto/cc/clang @@ -6,7 +6,8 @@ NGX_CLANG_VER=`$CC -v 2>&1 | grep 'version' 2>&1 \ - | sed -e 's/^.* version \(.*\)/\1/'` + | sed -n -e 's/^.*clang version \(.*\)/\1/p' \ + -e 's/^.*LLVM version \(.*\)/\1/p'` echo " + clang version: $NGX_CLANG_VER" diff --git a/auto/cc/msvc b/auto/cc/msvc index 8257252..68435ff 100644 --- a/auto/cc/msvc +++ b/auto/cc/msvc @@ -108,7 +108,7 @@ CORE_LIBS="$CORE_LIBS kernel32.lib user32.lib" # msvc under Wine issues # C1902: Program database manager mismatch; please check your installation if [ -z "$NGX_WINE" ]; then - CFLAGS="$CFLAGS -Zi" + CFLAGS="$CFLAGS -Zi -Fd$NGX_OBJS/nginx.pdb" CORE_LINK="$CORE_LINK -debug" fi diff --git a/auto/lib/google-perftools/conf b/auto/lib/google-perftools/conf index 5d5ddae..7f1a911 100644 --- a/auto/lib/google-perftools/conf +++ b/auto/lib/google-perftools/conf @@ -9,7 +9,8 @@ ngx_feature_incs= ngx_feature_path= ngx_feature_libs="-lprofiler" - ngx_feature_test="ProfilerStop()" + ngx_feature_test="void ProfilerStop(void); + ProfilerStop()" . auto/feature diff --git a/auto/lib/libgd/conf b/auto/lib/libgd/conf index 87761f1..6786397 100644 --- a/auto/lib/libgd/conf +++ b/auto/lib/libgd/conf @@ -9,7 +9,8 @@ ngx_feature_incs="#include " ngx_feature_path= ngx_feature_libs="-lgd" - ngx_feature_test="gdImagePtr img = gdImageCreateFromGifPtr(1, NULL);" + ngx_feature_test="gdImagePtr img = gdImageCreateFromGifPtr(1, NULL); + (void) img" . auto/feature @@ -76,7 +77,8 @@ if [ $ngx_found = yes ]; then ngx_feature="GD WebP support" ngx_feature_name="NGX_HAVE_GD_WEBP" - ngx_feature_test="gdImagePtr img = gdImageCreateFromWebpPtr(1, NULL);" + ngx_feature_test="gdImagePtr img = gdImageCreateFromWebpPtr(1, NULL); + (void) img" . auto/feature else diff --git a/auto/lib/libxslt/conf b/auto/lib/libxslt/conf index 3a0f37b..3063ac7 100644 --- a/auto/lib/libxslt/conf +++ b/auto/lib/libxslt/conf @@ -16,8 +16,8 @@ ngx_feature_libs="-lxml2 -lxslt" ngx_feature_test="xmlParserCtxtPtr ctxt = NULL; xsltStylesheetPtr sheet = NULL; - xmlDocPtr doc; - doc = xmlParseChunk(ctxt, NULL, 0, 0); + xmlDocPtr doc = NULL; + xmlParseChunk(ctxt, NULL, 0, 0); xsltApplyStylesheet(sheet, doc, NULL);" . auto/feature diff --git a/auto/make b/auto/make index 7ddd100..34c40cd 100644 --- a/auto/make +++ b/auto/make @@ -229,7 +229,7 @@ build: binary modules manpage binary: $NGX_OBJS${ngx_dirsep}nginx$ngx_binext $NGX_OBJS${ngx_dirsep}nginx$ngx_binext: $ngx_deps$ngx_spacer - \$(LINK) $ngx_long_start$ngx_binout$NGX_OBJS${ngx_dirsep}nginx$ngx_long_cont$ngx_objs$ngx_libs$ngx_link$ngx_main_link + \$(LINK) $ngx_long_start$ngx_binout$NGX_OBJS${ngx_dirsep}nginx$ngx_binext$ngx_long_cont$ngx_objs$ngx_libs$ngx_link$ngx_main_link $ngx_rcc $ngx_long_end diff --git a/auto/modules b/auto/modules index 73a9bae..09bfcb0 100644 --- a/auto/modules +++ b/auto/modules @@ -878,6 +878,17 @@ if [ $HTTP = YES ]; then . auto/module fi + if [ $HTTP_UPSTREAM_RANDOM = YES ]; then + ngx_module_name=ngx_http_upstream_random_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs=src/http/modules/ngx_http_upstream_random_module.c + ngx_module_libs= + ngx_module_link=$HTTP_UPSTREAM_RANDOM + + . auto/module + fi + if [ $HTTP_UPSTREAM_KEEPALIVE = YES ]; then ngx_module_name=ngx_http_upstream_keepalive_module ngx_module_incs= @@ -1143,6 +1154,16 @@ if [ $STREAM != NO ]; then . auto/module fi + if [ $STREAM_UPSTREAM_RANDOM = YES ]; then + ngx_module_name=ngx_stream_upstream_random_module + ngx_module_deps= + ngx_module_srcs=src/stream/ngx_stream_upstream_random_module.c + ngx_module_libs= + ngx_module_link=$STREAM_UPSTREAM_RANDOM + + . auto/module + fi + if [ $STREAM_UPSTREAM_ZONE = YES ]; then have=NGX_STREAM_UPSTREAM_ZONE . auto/have diff --git a/auto/options b/auto/options index 59f0449..d8b421b 100644 --- a/auto/options +++ b/auto/options @@ -102,6 +102,7 @@ HTTP_GZIP_STATIC=NO HTTP_UPSTREAM_HASH=YES HTTP_UPSTREAM_IP_HASH=YES HTTP_UPSTREAM_LEAST_CONN=YES +HTTP_UPSTREAM_RANDOM=YES HTTP_UPSTREAM_KEEPALIVE=YES HTTP_UPSTREAM_ZONE=YES @@ -126,6 +127,7 @@ STREAM_SPLIT_CLIENTS=YES STREAM_RETURN=YES STREAM_UPSTREAM_HASH=YES STREAM_UPSTREAM_LEAST_CONN=YES +STREAM_UPSTREAM_RANDOM=YES STREAM_UPSTREAM_ZONE=YES STREAM_SSL_PREREAD=NO @@ -273,6 +275,8 @@ $0: warning: the \"--with-ipv6\" option is deprecated" --without-http_upstream_ip_hash_module) HTTP_UPSTREAM_IP_HASH=NO ;; --without-http_upstream_least_conn_module) HTTP_UPSTREAM_LEAST_CONN=NO ;; + --without-http_upstream_random_module) + HTTP_UPSTREAM_RANDOM=NO ;; --without-http_upstream_keepalive_module) HTTP_UPSTREAM_KEEPALIVE=NO ;; --without-http_upstream_zone_module) HTTP_UPSTREAM_ZONE=NO ;; @@ -325,6 +329,8 @@ use the \"--with-mail_ssl_module\" option instead" STREAM_UPSTREAM_HASH=NO ;; --without-stream_upstream_least_conn_module) STREAM_UPSTREAM_LEAST_CONN=NO ;; + --without-stream_upstream_random_module) + STREAM_UPSTREAM_RANDOM=NO ;; --without-stream_upstream_zone_module) STREAM_UPSTREAM_ZONE=NO ;; @@ -485,6 +491,8 @@ cat << END disable ngx_http_upstream_ip_hash_module --without-http_upstream_least_conn_module disable ngx_http_upstream_least_conn_module + --without-http_upstream_random_module + disable ngx_http_upstream_random_module --without-http_upstream_keepalive_module disable ngx_http_upstream_keepalive_module --without-http_upstream_zone_module @@ -535,6 +543,8 @@ cat << END disable ngx_stream_upstream_hash_module --without-stream_upstream_least_conn_module disable ngx_stream_upstream_least_conn_module + --without-stream_upstream_random_module + disable ngx_stream_upstream_random_module --without-stream_upstream_zone_module disable ngx_stream_upstream_zone_module diff --git a/auto/os/linux b/auto/os/linux index 2c8a9bb..5e280ec 100644 --- a/auto/os/linux +++ b/auto/os/linux @@ -185,6 +185,8 @@ ngx_feature_test="struct __user_cap_data_struct data; data.effective = CAP_TO_MASK(CAP_NET_RAW); data.permitted = 0; + (void) header; + (void) data; (void) SYS_capset" . auto/feature diff --git a/auto/os/win32 b/auto/os/win32 index 7a82774..b821ae6 100644 --- a/auto/os/win32 +++ b/auto/os/win32 @@ -11,6 +11,7 @@ CORE_SRCS="$WIN32_SRCS $IOCP_SRCS" OS_CONFIG="$WIN32_CONFIG" NGX_ICONS="$NGX_WIN32_ICONS" SELECT_SRCS=$WIN32_SELECT_SRCS +POLL_SRCS=$WIN32_POLL_SRCS ngx_pic_opt= ngx_binext=".exe" @@ -31,12 +32,7 @@ case "$NGX_CC_NAME" in esac EVENT_MODULES="$EVENT_MODULES $IOCP_MODULE" -EVENT_FOUND=YES - -if [ $EVENT_SELECT = NO ]; then - CORE_SRCS="$CORE_SRCS $SELECT_SRCS" - EVENT_MODULES="$EVENT_MODULES $SELECT_MODULE" -fi +#EVENT_FOUND=YES have=NGX_HAVE_INET6 . auto/have diff --git a/auto/sources b/auto/sources index 1398147..3dad111 100644 --- a/auto/sources +++ b/auto/sources @@ -95,6 +95,7 @@ EVENT_SRCS="src/event/ngx_event.c \ src/event/ngx_event_timer.c \ src/event/ngx_event_posted.c \ src/event/ngx_event_accept.c \ + src/event/ngx_event_udp.c \ src/event/ngx_event_connect.c \ src/event/ngx_event_pipe.c" @@ -105,6 +106,7 @@ WIN32_SELECT_SRCS=src/event/modules/ngx_win32_select_module.c POLL_MODULE=ngx_poll_module POLL_SRCS=src/event/modules/ngx_poll_module.c +WIN32_POLL_SRCS=src/event/modules/ngx_win32_poll_module.c KQUEUE_MODULE=ngx_kqueue_module KQUEUE_SRCS=src/event/modules/ngx_kqueue_module.c diff --git a/conf/mime.types b/conf/mime.types index 8a2348a..2961256 100644 --- a/conf/mime.types +++ b/conf/mime.types @@ -24,7 +24,9 @@ types { image/x-jng jng; image/x-ms-bmp bmp; - application/font-woff woff; + font/woff woff; + font/woff2 woff2; + application/java-archive jar war ear; application/json json; application/mac-binhex40 hqx; diff --git a/contrib/vim/syntax/nginx.vim b/contrib/vim/syntax/nginx.vim index 075b19a..6bee7a2 100644 --- a/contrib/vim/syntax/nginx.vim +++ b/contrib/vim/syntax/nginx.vim @@ -108,6 +108,7 @@ syn keyword ngxDirectiveControl contained set syn keyword ngxDirectiveError contained error_page syn keyword ngxDirectiveError contained post_action +syn keyword ngxDirectiveDeprecated contained limit_zone syn keyword ngxDirectiveDeprecated contained proxy_downstream_buffer syn keyword ngxDirectiveDeprecated contained proxy_upstream_buffer syn keyword ngxDirectiveDeprecated contained spdy_chunk_size @@ -118,6 +119,7 @@ syn keyword ngxDirectiveDeprecated contained spdy_pool_size syn keyword ngxDirectiveDeprecated contained spdy_recv_buffer_size syn keyword ngxDirectiveDeprecated contained spdy_recv_timeout syn keyword ngxDirectiveDeprecated contained spdy_streams_index_size +syn keyword ngxDirectiveDeprecated contained ssl syn keyword ngxDirectiveDeprecated contained upstream_conf syn keyword ngxDirective contained absolute_redirect @@ -136,6 +138,7 @@ syn keyword ngxDirective contained alias syn keyword ngxDirective contained allow syn keyword ngxDirective contained ancient_browser syn keyword ngxDirective contained ancient_browser_value +syn keyword ngxDirective contained api syn keyword ngxDirective contained auth_basic syn keyword ngxDirective contained auth_basic_user_file syn keyword ngxDirective contained auth_http @@ -143,7 +146,11 @@ syn keyword ngxDirective contained auth_http_header syn keyword ngxDirective contained auth_http_pass_client_cert syn keyword ngxDirective contained auth_http_timeout syn keyword ngxDirective contained auth_jwt +syn keyword ngxDirective contained auth_jwt_claim_set +syn keyword ngxDirective contained auth_jwt_header_set syn keyword ngxDirective contained auth_jwt_key_file +syn keyword ngxDirective contained auth_jwt_key_request +syn keyword ngxDirective contained auth_jwt_leeway syn keyword ngxDirective contained auth_request syn keyword ngxDirective contained auth_request_set syn keyword ngxDirective contained autoindex @@ -229,6 +236,7 @@ syn keyword ngxDirective contained fastcgi_read_timeout syn keyword ngxDirective contained fastcgi_request_buffering syn keyword ngxDirective contained fastcgi_send_lowat syn keyword ngxDirective contained fastcgi_send_timeout +syn keyword ngxDirective contained fastcgi_socket_keepalive syn keyword ngxDirective contained fastcgi_split_path_info syn keyword ngxDirective contained fastcgi_store syn keyword ngxDirective contained fastcgi_store_access @@ -255,6 +263,7 @@ syn keyword ngxDirective contained grpc_pass_header syn keyword ngxDirective contained grpc_read_timeout syn keyword ngxDirective contained grpc_send_timeout syn keyword ngxDirective contained grpc_set_header +syn keyword ngxDirective contained grpc_socket_keepalive syn keyword ngxDirective contained grpc_ssl_certificate syn keyword ngxDirective contained grpc_ssl_certificate_key syn keyword ngxDirective contained grpc_ssl_ciphers @@ -330,6 +339,8 @@ syn keyword ngxDirective contained keepalive syn keyword ngxDirective contained keepalive_disable syn keyword ngxDirective contained keepalive_requests syn keyword ngxDirective contained keepalive_timeout +syn keyword ngxDirective contained keyval +syn keyword ngxDirective contained keyval_zone syn keyword ngxDirective contained kqueue_changes syn keyword ngxDirective contained kqueue_events syn keyword ngxDirective contained large_client_header_buffers @@ -367,6 +378,7 @@ syn keyword ngxDirective contained memcached_next_upstream_timeout syn keyword ngxDirective contained memcached_next_upstream_tries syn keyword ngxDirective contained memcached_read_timeout syn keyword ngxDirective contained memcached_send_timeout +syn keyword ngxDirective contained memcached_socket_keepalive syn keyword ngxDirective contained merge_slashes syn keyword ngxDirective contained min_delete_depth syn keyword ngxDirective contained mirror @@ -375,9 +387,9 @@ syn keyword ngxDirective contained modern_browser syn keyword ngxDirective contained modern_browser_value syn keyword ngxDirective contained mp4 syn keyword ngxDirective contained mp4_buffer_size -syn keyword ngxDirective contained mp4_max_buffer_size syn keyword ngxDirective contained mp4_limit_rate syn keyword ngxDirective contained mp4_limit_rate_after +syn keyword ngxDirective contained mp4_max_buffer_size syn keyword ngxDirective contained msie_padding syn keyword ngxDirective contained msie_refresh syn keyword ngxDirective contained multi_accept @@ -456,11 +468,13 @@ syn keyword ngxDirective contained proxy_protocol_timeout syn keyword ngxDirective contained proxy_read_timeout syn keyword ngxDirective contained proxy_redirect syn keyword ngxDirective contained proxy_request_buffering +syn keyword ngxDirective contained proxy_requests syn keyword ngxDirective contained proxy_responses syn keyword ngxDirective contained proxy_send_lowat syn keyword ngxDirective contained proxy_send_timeout syn keyword ngxDirective contained proxy_set_body syn keyword ngxDirective contained proxy_set_header +syn keyword ngxDirective contained proxy_socket_keepalive syn keyword ngxDirective contained proxy_ssl syn keyword ngxDirective contained proxy_ssl_certificate syn keyword ngxDirective contained proxy_ssl_certificate_key @@ -481,6 +495,7 @@ syn keyword ngxDirective contained proxy_temp_path syn keyword ngxDirective contained proxy_timeout syn keyword ngxDirective contained proxy_upload_rate syn keyword ngxDirective contained queue +syn keyword ngxDirective contained random syn keyword ngxDirective contained random_index syn keyword ngxDirective contained read_ahead syn keyword ngxDirective contained real_ip_header @@ -533,6 +548,7 @@ syn keyword ngxDirective contained scgi_pass_request_headers syn keyword ngxDirective contained scgi_read_timeout syn keyword ngxDirective contained scgi_request_buffering syn keyword ngxDirective contained scgi_send_timeout +syn keyword ngxDirective contained scgi_socket_keepalive syn keyword ngxDirective contained scgi_store syn keyword ngxDirective contained scgi_store_access syn keyword ngxDirective contained scgi_temp_file_write_size @@ -565,7 +581,6 @@ syn keyword ngxDirective contained ssi_min_file_chunk syn keyword ngxDirective contained ssi_silent_errors syn keyword ngxDirective contained ssi_types syn keyword ngxDirective contained ssi_value_length -syn keyword ngxDirective contained ssl syn keyword ngxDirective contained ssl_buffer_size syn keyword ngxDirective contained ssl_certificate syn keyword ngxDirective contained ssl_certificate_key @@ -573,6 +588,7 @@ syn keyword ngxDirective contained ssl_ciphers syn keyword ngxDirective contained ssl_client_certificate syn keyword ngxDirective contained ssl_crl syn keyword ngxDirective contained ssl_dhparam +syn keyword ngxDirective contained ssl_early_data syn keyword ngxDirective contained ssl_ecdh_curve syn keyword ngxDirective contained ssl_engine syn keyword ngxDirective contained ssl_handshake_timeout @@ -664,6 +680,7 @@ syn keyword ngxDirective contained uwsgi_pass_request_headers syn keyword ngxDirective contained uwsgi_read_timeout syn keyword ngxDirective contained uwsgi_request_buffering syn keyword ngxDirective contained uwsgi_send_timeout +syn keyword ngxDirective contained uwsgi_socket_keepalive syn keyword ngxDirective contained uwsgi_ssl_certificate syn keyword ngxDirective contained uwsgi_ssl_certificate_key syn keyword ngxDirective contained uwsgi_ssl_ciphers @@ -701,6 +718,26 @@ syn keyword ngxDirective contained xslt_string_param syn keyword ngxDirective contained xslt_stylesheet syn keyword ngxDirective contained xslt_types syn keyword ngxDirective contained zone +syn keyword ngxDirective contained zone_sync +syn keyword ngxDirective contained zone_sync_buffers +syn keyword ngxDirective contained zone_sync_connect_retry_interval +syn keyword ngxDirective contained zone_sync_connect_timeout +syn keyword ngxDirective contained zone_sync_interval +syn keyword ngxDirective contained zone_sync_recv_buffer_size +syn keyword ngxDirective contained zone_sync_server +syn keyword ngxDirective contained zone_sync_ssl +syn keyword ngxDirective contained zone_sync_ssl_certificate +syn keyword ngxDirective contained zone_sync_ssl_certificate_key +syn keyword ngxDirective contained zone_sync_ssl_ciphers +syn keyword ngxDirective contained zone_sync_ssl_crl +syn keyword ngxDirective contained zone_sync_ssl_name +syn keyword ngxDirective contained zone_sync_ssl_password_file +syn keyword ngxDirective contained zone_sync_ssl_protocols +syn keyword ngxDirective contained zone_sync_ssl_server_name +syn keyword ngxDirective contained zone_sync_ssl_trusted_certificate +syn keyword ngxDirective contained zone_sync_ssl_verify +syn keyword ngxDirective contained zone_sync_ssl_verify_depth +syn keyword ngxDirective contained zone_sync_timeout " 3rd party modules list taken from " https://github.com/freebsd/freebsd-ports/blob/master/www/nginx-devel/Makefile @@ -876,6 +913,8 @@ syn keyword ngxDirectiveThirdParty contained more_set_input_headers " NGINX WebDAV missing commands support (PROPFIND & OPTIONS) " https://github.com/arut/nginx-dav-ext-module +syn keyword ngxDirectiveThirdParty contained dav_ext_lock +syn keyword ngxDirectiveThirdParty contained dav_ext_lock_zone syn keyword ngxDirectiveThirdParty contained dav_ext_methods " ngx_eval @@ -895,6 +934,7 @@ syn keyword ngxDirectiveThirdParty contained fancyindex_directories_first syn keyword ngxDirectiveThirdParty contained fancyindex_exact_size syn keyword ngxDirectiveThirdParty contained fancyindex_footer syn keyword ngxDirectiveThirdParty contained fancyindex_header +syn keyword ngxDirectiveThirdParty contained fancyindex_hide_parent_dir syn keyword ngxDirectiveThirdParty contained fancyindex_hide_symlinks syn keyword ngxDirectiveThirdParty contained fancyindex_ignore syn keyword ngxDirectiveThirdParty contained fancyindex_localtime @@ -937,8 +977,17 @@ syn keyword ngxDirectiveThirdParty contained notice_type " nchan " https://github.com/slact/nchan +syn keyword ngxDirectiveThirdParty contained nchan_access_control_allow_credentials syn keyword ngxDirectiveThirdParty contained nchan_access_control_allow_origin syn keyword ngxDirectiveThirdParty contained nchan_authorize_request +syn keyword ngxDirectiveThirdParty contained nchan_benchmark +syn keyword ngxDirectiveThirdParty contained nchan_benchmark_channels +syn keyword ngxDirectiveThirdParty contained nchan_benchmark_message_padding_bytes +syn keyword ngxDirectiveThirdParty contained nchan_benchmark_messages_per_channel_per_minute +syn keyword ngxDirectiveThirdParty contained nchan_benchmark_publisher_distribution +syn keyword ngxDirectiveThirdParty contained nchan_benchmark_subscriber_distribution +syn keyword ngxDirectiveThirdParty contained nchan_benchmark_subscribers_per_channel +syn keyword ngxDirectiveThirdParty contained nchan_benchmark_time syn keyword ngxDirectiveThirdParty contained nchan_channel_event_string syn keyword ngxDirectiveThirdParty contained nchan_channel_events_channel_id syn keyword ngxDirectiveThirdParty contained nchan_channel_group @@ -974,15 +1023,19 @@ syn keyword ngxDirectiveThirdParty contained nchan_publisher_upstream_request syn keyword ngxDirectiveThirdParty contained nchan_pubsub syn keyword ngxDirectiveThirdParty contained nchan_pubsub_channel_id syn keyword ngxDirectiveThirdParty contained nchan_pubsub_location +syn keyword ngxDirectiveThirdParty contained nchan_redis_connect_timeout syn keyword ngxDirectiveThirdParty contained nchan_redis_fakesub_timer_interval syn keyword ngxDirectiveThirdParty contained nchan_redis_idle_channel_cache_timeout syn keyword ngxDirectiveThirdParty contained nchan_redis_namespace +syn keyword ngxDirectiveThirdParty contained nchan_redis_nostore_fastpublish +syn keyword ngxDirectiveThirdParty contained nchan_redis_optimize_target syn keyword ngxDirectiveThirdParty contained nchan_redis_pass syn keyword ngxDirectiveThirdParty contained nchan_redis_pass_inheritable syn keyword ngxDirectiveThirdParty contained nchan_redis_ping_interval syn keyword ngxDirectiveThirdParty contained nchan_redis_publish_msgpacked_max_size syn keyword ngxDirectiveThirdParty contained nchan_redis_server syn keyword ngxDirectiveThirdParty contained nchan_redis_storage_mode +syn keyword ngxDirectiveThirdParty contained nchan_redis_subscribe_weights syn keyword ngxDirectiveThirdParty contained nchan_redis_url syn keyword ngxDirectiveThirdParty contained nchan_redis_wait_after_connecting syn keyword ngxDirectiveThirdParty contained nchan_shared_memory_size @@ -1280,6 +1333,7 @@ syn keyword ngxDirectiveThirdParty contained lua_package_cpath syn keyword ngxDirectiveThirdParty contained lua_package_path syn keyword ngxDirectiveThirdParty contained lua_regex_cache_max_entries syn keyword ngxDirectiveThirdParty contained lua_regex_match_limit +syn keyword ngxDirectiveThirdParty contained lua_sa_restart syn keyword ngxDirectiveThirdParty contained lua_shared_dict syn keyword ngxDirectiveThirdParty contained lua_socket_buffer_size syn keyword ngxDirectiveThirdParty contained lua_socket_connect_timeout @@ -1355,9 +1409,15 @@ syn keyword ngxDirectiveThirdParty contained rules_enabled " https://www.phusionpassenger.com/library/config/nginx/reference/ syn keyword ngxDirectiveThirdParty contained passenger_abort_on_startup_error syn keyword ngxDirectiveThirdParty contained passenger_abort_websockets_on_process_shutdown +syn keyword ngxDirectiveThirdParty contained passenger_admin_panel_auth_type +syn keyword ngxDirectiveThirdParty contained passenger_admin_panel_password +syn keyword ngxDirectiveThirdParty contained passenger_admin_panel_url +syn keyword ngxDirectiveThirdParty contained passenger_admin_panel_username +syn keyword ngxDirectiveThirdParty contained passenger_anonymous_telemetry_proxy syn keyword ngxDirectiveThirdParty contained passenger_app_env syn keyword ngxDirectiveThirdParty contained passenger_app_file_descriptor_ulimit syn keyword ngxDirectiveThirdParty contained passenger_app_group_name +syn keyword ngxDirectiveThirdParty contained passenger_app_log_file syn keyword ngxDirectiveThirdParty contained passenger_app_rights syn keyword ngxDirectiveThirdParty contained passenger_app_root syn keyword ngxDirectiveThirdParty contained passenger_app_type @@ -1373,8 +1433,10 @@ syn keyword ngxDirectiveThirdParty contained passenger_data_buffer_dir syn keyword ngxDirectiveThirdParty contained passenger_debugger syn keyword ngxDirectiveThirdParty contained passenger_default_group syn keyword ngxDirectiveThirdParty contained passenger_default_user +syn keyword ngxDirectiveThirdParty contained passenger_disable_anonymous_telemetry syn keyword ngxDirectiveThirdParty contained passenger_disable_security_update_check syn keyword ngxDirectiveThirdParty contained passenger_document_root +syn keyword ngxDirectiveThirdParty contained passenger_dump_config_manifest syn keyword ngxDirectiveThirdParty contained passenger_enabled syn keyword ngxDirectiveThirdParty contained passenger_env_var syn keyword ngxDirectiveThirdParty contained passenger_file_descriptor_log_file @@ -1402,6 +1464,7 @@ syn keyword ngxDirectiveThirdParty contained passenger_max_requests syn keyword ngxDirectiveThirdParty contained passenger_memory_limit syn keyword ngxDirectiveThirdParty contained passenger_meteor_app_settings syn keyword ngxDirectiveThirdParty contained passenger_min_instances +syn keyword ngxDirectiveThirdParty contained passenger_monitor_log_file syn keyword ngxDirectiveThirdParty contained passenger_nodejs syn keyword ngxDirectiveThirdParty contained passenger_pass_header syn keyword ngxDirectiveThirdParty contained passenger_pool_idle_time @@ -1778,6 +1841,8 @@ syn keyword ngxDirectiveThirdParty contained vhost_traffic_status_filter syn keyword ngxDirectiveThirdParty contained vhost_traffic_status_filter_by_host syn keyword ngxDirectiveThirdParty contained vhost_traffic_status_filter_by_set_key syn keyword ngxDirectiveThirdParty contained vhost_traffic_status_filter_check_duplicate +syn keyword ngxDirectiveThirdParty contained vhost_traffic_status_filter_max_node +syn keyword ngxDirectiveThirdParty contained vhost_traffic_status_histogram_buckets syn keyword ngxDirectiveThirdParty contained vhost_traffic_status_limit syn keyword ngxDirectiveThirdParty contained vhost_traffic_status_limit_check_duplicate syn keyword ngxDirectiveThirdParty contained vhost_traffic_status_limit_traffic @@ -1899,11 +1964,11 @@ syn keyword ngxDirectiveThirdParty contained form_auth_remote_user " ngx_http_accounting_module " https://github.com/Lax/ngx_http_accounting_module -syn keyword ngxDirectiveThirdParty contained http_accounting -syn keyword ngxDirectiveThirdParty contained http_accounting_id -syn keyword ngxDirectiveThirdParty contained http_accounting_interval -syn keyword ngxDirectiveThirdParty contained http_accounting_log -syn keyword ngxDirectiveThirdParty contained http_accounting_perturb +syn keyword ngxDirectiveThirdParty contained accounting +syn keyword ngxDirectiveThirdParty contained accounting_id +syn keyword ngxDirectiveThirdParty contained accounting_interval +syn keyword ngxDirectiveThirdParty contained accounting_log +syn keyword ngxDirectiveThirdParty contained accounting_perturb " concatenating files in a given context: CSS and JS files usually " https://github.com/alibaba/nginx-http-concat diff --git a/html/50x.html b/html/50x.html index f60f5e7..9071e0a 100644 --- a/html/50x.html +++ b/html/50x.html @@ -15,7 +15,7 @@

Sorry, the page you are looking for is currently unavailable.
Please try again later.

If you are the system administrator of this resource then you should check -the error log for details.

+the error log for details.

Faithfully yours, nginx.

diff --git a/src/core/nginx.h b/src/core/nginx.h index 4fc92ac..c59a0e7 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1014002 -#define NGINX_VERSION "1.14.2" +#define nginx_version 1016001 +#define NGINX_VERSION "1.16.1" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD diff --git a/src/core/ngx_buf.c b/src/core/ngx_buf.c index 1862a06..c3783c4 100644 --- a/src/core/ngx_buf.c +++ b/src/core/ngx_buf.c @@ -137,6 +137,7 @@ ngx_chain_add_copy(ngx_pool_t *pool, ngx_chain_t **chain, ngx_chain_t *in) while (in) { cl = ngx_alloc_chain_link(pool); if (cl == NULL) { + *ll = NULL; return NGX_ERROR; } diff --git a/src/core/ngx_conf_file.c b/src/core/ngx_conf_file.c index ba454de..6d1629e 100644 --- a/src/core/ngx_conf_file.c +++ b/src/core/ngx_conf_file.c @@ -310,7 +310,7 @@ ngx_conf_parse(ngx_conf_t *cf, ngx_str_t *filename) goto failed; } - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, rv); + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%s", rv); goto failed; } @@ -656,13 +656,14 @@ ngx_conf_read_token(ngx_conf_t *cf) } if (last_space) { - if (ch == ' ' || ch == '\t' || ch == CR || ch == LF) { - continue; - } start = b->pos - 1; start_line = cf->conf_file->line; + if (ch == ' ' || ch == '\t' || ch == CR || ch == LF) { + continue; + } + switch (ch) { case ';': diff --git a/src/core/ngx_connection.c b/src/core/ngx_connection.c index 9a74758..3368253 100644 --- a/src/core/ngx_connection.c +++ b/src/core/ngx_connection.c @@ -72,6 +72,10 @@ ngx_create_listening(ngx_conf_t *cf, struct sockaddr *sockaddr, ngx_memcpy(ls->addr_text.data, text, len); +#if !(NGX_WIN32) + ngx_rbtree_init(&ls->rbtree, &ls->sentinel, ngx_udp_rbtree_insert_value); +#endif + ls->fd = (ngx_socket_t) -1; ls->type = SOCK_STREAM; @@ -92,7 +96,7 @@ ngx_create_listening(ngx_conf_t *cf, struct sockaddr *sockaddr, ngx_int_t -ngx_clone_listening(ngx_conf_t *cf, ngx_listening_t *ls) +ngx_clone_listening(ngx_cycle_t *cycle, ngx_listening_t *ls) { #if (NGX_HAVE_REUSEPORT) @@ -100,20 +104,19 @@ ngx_clone_listening(ngx_conf_t *cf, ngx_listening_t *ls) ngx_core_conf_t *ccf; ngx_listening_t ols; - if (!ls->reuseport) { + if (!ls->reuseport || ls->worker != 0) { return NGX_OK; } ols = *ls; - ccf = (ngx_core_conf_t *) ngx_get_conf(cf->cycle->conf_ctx, - ngx_core_module); + ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); for (n = 1; n < ccf->worker_processes; n++) { /* create a socket for each worker process */ - ls = ngx_array_push(&cf->cycle->listening); + ls = ngx_array_push(&cycle->listening); if (ls == NULL) { return NGX_ERROR; } @@ -277,6 +280,22 @@ ngx_set_inherited_sockets(ngx_cycle_t *cycle) reuseport = 0; olen = sizeof(int); +#ifdef SO_REUSEPORT_LB + + if (getsockopt(ls[i].fd, SOL_SOCKET, SO_REUSEPORT_LB, + (void *) &reuseport, &olen) + == -1) + { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno, + "getsockopt(SO_REUSEPORT_LB) %V failed, ignored", + &ls[i].addr_text); + + } else { + ls[i].reuseport = reuseport ? 1 : 0; + } + +#else + if (getsockopt(ls[i].fd, SOL_SOCKET, SO_REUSEPORT, (void *) &reuseport, &olen) == -1) @@ -288,6 +307,7 @@ ngx_set_inherited_sockets(ngx_cycle_t *cycle) } else { ls[i].reuseport = reuseport ? 1 : 0; } +#endif #endif @@ -305,7 +325,9 @@ ngx_set_inherited_sockets(ngx_cycle_t *cycle) { err = ngx_socket_errno; - if (err != NGX_EOPNOTSUPP && err != NGX_ENOPROTOOPT) { + if (err != NGX_EOPNOTSUPP && err != NGX_ENOPROTOOPT + && err != NGX_EINVAL) + { ngx_log_error(NGX_LOG_NOTICE, cycle->log, err, "getsockopt(TCP_FASTOPEN) %V failed, ignored", &ls[i].addr_text); @@ -424,6 +446,20 @@ ngx_open_listening_sockets(ngx_cycle_t *cycle) int reuseport = 1; +#ifdef SO_REUSEPORT_LB + + if (setsockopt(ls[i].fd, SOL_SOCKET, SO_REUSEPORT_LB, + (const void *) &reuseport, sizeof(int)) + == -1) + { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno, + "setsockopt(SO_REUSEPORT_LB) %V failed, " + "ignored", + &ls[i].addr_text); + } + +#else + if (setsockopt(ls[i].fd, SOL_SOCKET, SO_REUSEPORT, (const void *) &reuseport, sizeof(int)) == -1) @@ -432,6 +468,7 @@ ngx_open_listening_sockets(ngx_cycle_t *cycle) "setsockopt(SO_REUSEPORT) %V failed, ignored", &ls[i].addr_text); } +#endif ls[i].add_reuseport = 0; } @@ -482,6 +519,27 @@ ngx_open_listening_sockets(ngx_cycle_t *cycle) reuseport = 1; +#ifdef SO_REUSEPORT_LB + + if (setsockopt(s, SOL_SOCKET, SO_REUSEPORT_LB, + (const void *) &reuseport, sizeof(int)) + == -1) + { + ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, + "setsockopt(SO_REUSEPORT_LB) %V failed", + &ls[i].addr_text); + + if (ngx_close_socket(s) == -1) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, + ngx_close_socket_n " %V failed", + &ls[i].addr_text); + } + + return NGX_ERROR; + } + +#else + if (setsockopt(s, SOL_SOCKET, SO_REUSEPORT, (const void *) &reuseport, sizeof(int)) == -1) @@ -498,6 +556,7 @@ ngx_open_listening_sockets(ngx_cycle_t *cycle) return NGX_ERROR; } +#endif } #endif diff --git a/src/core/ngx_connection.h b/src/core/ngx_connection.h index e4dfe58..5405962 100644 --- a/src/core/ngx_connection.h +++ b/src/core/ngx_connection.h @@ -51,6 +51,9 @@ struct ngx_listening_s { ngx_listening_t *previous; ngx_connection_t *connection; + ngx_rbtree_t rbtree; + ngx_rbtree_node_t sentinel; + ngx_uint_t worker; unsigned open:1; @@ -151,6 +154,8 @@ struct ngx_connection_s { ngx_ssl_connection_t *ssl; #endif + ngx_udp_connection_t *udp; + struct sockaddr *local_sockaddr; socklen_t local_socklen; @@ -205,7 +210,7 @@ struct ngx_connection_s { ngx_listening_t *ngx_create_listening(ngx_conf_t *cf, struct sockaddr *sockaddr, socklen_t socklen); -ngx_int_t ngx_clone_listening(ngx_conf_t *cf, ngx_listening_t *ls); +ngx_int_t ngx_clone_listening(ngx_cycle_t *cycle, ngx_listening_t *ls); ngx_int_t ngx_set_inherited_sockets(ngx_cycle_t *cycle); ngx_int_t ngx_open_listening_sockets(ngx_cycle_t *cycle); void ngx_configure_listening_sockets(ngx_cycle_t *cycle); diff --git a/src/core/ngx_core.h b/src/core/ngx_core.h index 2069373..93ca917 100644 --- a/src/core/ngx_core.h +++ b/src/core/ngx_core.h @@ -27,6 +27,7 @@ typedef struct ngx_connection_s ngx_connection_t; typedef struct ngx_thread_task_s ngx_thread_task_t; typedef struct ngx_ssl_s ngx_ssl_t; typedef struct ngx_ssl_connection_s ngx_ssl_connection_t; +typedef struct ngx_udp_connection_s ngx_udp_connection_t; typedef void (*ngx_event_handler_pt)(ngx_event_t *ev); typedef void (*ngx_connection_handler_pt)(ngx_connection_t *c); diff --git a/src/core/ngx_cycle.c b/src/core/ngx_cycle.c index f3ac24d..95f4bdf 100644 --- a/src/core/ngx_cycle.c +++ b/src/core/ngx_cycle.c @@ -843,6 +843,69 @@ failed: } } + /* free the newly created shared memory */ + + part = &cycle->shared_memory.part; + shm_zone = part->elts; + + for (i = 0; /* void */ ; i++) { + + if (i >= part->nelts) { + if (part->next == NULL) { + break; + } + part = part->next; + shm_zone = part->elts; + i = 0; + } + + if (shm_zone[i].shm.addr == NULL) { + continue; + } + + opart = &old_cycle->shared_memory.part; + oshm_zone = opart->elts; + + for (n = 0; /* void */ ; n++) { + + if (n >= opart->nelts) { + if (opart->next == NULL) { + break; + } + opart = opart->next; + oshm_zone = opart->elts; + n = 0; + } + + if (shm_zone[i].shm.name.len != oshm_zone[n].shm.name.len) { + continue; + } + + if (ngx_strncmp(shm_zone[i].shm.name.data, + oshm_zone[n].shm.name.data, + shm_zone[i].shm.name.len) + != 0) + { + continue; + } + + if (shm_zone[i].tag == oshm_zone[n].tag + && shm_zone[i].shm.size == oshm_zone[n].shm.size + && !shm_zone[i].noreuse) + { + goto old_shm_zone_found; + } + + break; + } + + ngx_shm_free(&shm_zone[i].shm); + + old_shm_zone_found: + + continue; + } + if (ngx_test_config) { ngx_destroy_cycle_pools(&conf); return NULL; @@ -921,7 +984,8 @@ ngx_init_zone_pool(ngx_cycle_t *cycle, ngx_shm_zone_t *zn) #else - file = ngx_pnalloc(cycle->pool, cycle->lock_file.len + zn->shm.name.len); + file = ngx_pnalloc(cycle->pool, + cycle->lock_file.len + zn->shm.name.len + 1); if (file == NULL) { return NGX_ERROR; } @@ -1273,6 +1337,7 @@ ngx_shared_memory_add(ngx_conf_t *cf, ngx_str_t *name, size_t size, void *tag) shm_zone->data = NULL; shm_zone->shm.log = cf->cycle->log; + shm_zone->shm.addr = NULL; shm_zone->shm.size = size; shm_zone->shm.name = *name; shm_zone->shm.exists = 0; diff --git a/src/core/ngx_file.c b/src/core/ngx_file.c index 3a94089..63ada85 100644 --- a/src/core/ngx_file.c +++ b/src/core/ngx_file.c @@ -796,10 +796,12 @@ ngx_copy_file(u_char *from, u_char *to, ngx_copy_file_t *cf) { char *buf; off_t size; + time_t time; size_t len; ssize_t n; ngx_fd_t fd, nfd; ngx_int_t rc; + ngx_uint_t access; ngx_file_info_t fi; rc = NGX_ERROR; @@ -814,8 +816,10 @@ ngx_copy_file(u_char *from, u_char *to, ngx_copy_file_t *cf) goto failed; } - if (cf->size != -1) { + if (cf->size != -1 && cf->access != 0 && cf->time != -1) { size = cf->size; + access = cf->access; + time = cf->time; } else { if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) { @@ -825,7 +829,9 @@ ngx_copy_file(u_char *from, u_char *to, ngx_copy_file_t *cf) goto failed; } - size = ngx_file_size(&fi); + size = (cf->size != -1) ? cf->size : ngx_file_size(&fi); + access = cf->access ? cf->access : ngx_file_access(&fi); + time = (cf->time != -1) ? cf->time : ngx_file_mtime(&fi); } len = cf->buf_size ? cf->buf_size : 65536; @@ -839,8 +845,7 @@ ngx_copy_file(u_char *from, u_char *to, ngx_copy_file_t *cf) goto failed; } - nfd = ngx_open_file(to, NGX_FILE_WRONLY, NGX_FILE_CREATE_OR_OPEN, - cf->access); + nfd = ngx_open_file(to, NGX_FILE_WRONLY, NGX_FILE_TRUNCATE, access); if (nfd == NGX_INVALID_FILE) { ngx_log_error(NGX_LOG_CRIT, cf->log, ngx_errno, @@ -887,12 +892,10 @@ ngx_copy_file(u_char *from, u_char *to, ngx_copy_file_t *cf) size -= n; } - if (cf->time != -1) { - if (ngx_set_file_time(to, nfd, cf->time) != NGX_OK) { - ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, - ngx_set_file_time_n " \"%s\" failed", to); - goto failed; - } + if (ngx_set_file_time(to, nfd, time) != NGX_OK) { + ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, + ngx_set_file_time_n " \"%s\" failed", to); + goto failed; } rc = NGX_OK; @@ -1014,13 +1017,13 @@ ngx_walk_tree(ngx_tree_ctx_t *ctx, ngx_str_t *tree) file.len = tree->len + 1 + len; - if (file.len + NGX_DIR_MASK_LEN > buf.len) { + if (file.len > buf.len) { if (buf.len) { ngx_free(buf.data); } - buf.len = tree->len + 1 + len + NGX_DIR_MASK_LEN; + buf.len = tree->len + 1 + len; buf.data = ngx_alloc(buf.len + 1, ctx->log); if (buf.data == NULL) { diff --git a/src/core/ngx_inet.c b/src/core/ngx_inet.c index db48b93..4228504 100644 --- a/src/core/ngx_inet.c +++ b/src/core/ngx_inet.c @@ -12,6 +12,8 @@ static ngx_int_t ngx_parse_unix_domain_url(ngx_pool_t *pool, ngx_url_t *u); static ngx_int_t ngx_parse_inet_url(ngx_pool_t *pool, ngx_url_t *u); static ngx_int_t ngx_parse_inet6_url(ngx_pool_t *pool, ngx_url_t *u); +static ngx_int_t ngx_inet_add_addr(ngx_pool_t *pool, ngx_url_t *u, + struct sockaddr *sockaddr, socklen_t socklen, ngx_uint_t total); in_addr_t @@ -780,13 +782,10 @@ ngx_parse_unix_domain_url(ngx_pool_t *pool, ngx_url_t *u) static ngx_int_t ngx_parse_inet_url(ngx_pool_t *pool, ngx_url_t *u) { - u_char *p, *host, *port, *last, *uri, *args; - size_t len; - ngx_int_t n; - struct sockaddr_in *sin; -#if (NGX_HAVE_INET6) - struct sockaddr_in6 *sin6; -#endif + u_char *host, *port, *last, *uri, *args, *dash; + size_t len; + ngx_int_t n; + struct sockaddr_in *sin; u->socklen = sizeof(struct sockaddr_in); sin = (struct sockaddr_in *) &u->sockaddr; @@ -831,6 +830,25 @@ ngx_parse_inet_url(ngx_pool_t *pool, ngx_url_t *u) len = last - port; + if (u->listen) { + dash = ngx_strlchr(port, last, '-'); + + if (dash) { + dash++; + + n = ngx_atoi(dash, last - dash); + + if (n < 1 || n > 65535) { + u->err = "invalid port"; + return NGX_ERROR; + } + + u->last_port = (in_port_t) n; + + len = dash - port - 1; + } + } + n = ngx_atoi(port, len); if (n < 1 || n > 65535) { @@ -838,10 +856,15 @@ ngx_parse_inet_url(ngx_pool_t *pool, ngx_url_t *u) return NGX_ERROR; } + if (u->last_port && n > u->last_port) { + u->err = "invalid port range"; + return NGX_ERROR; + } + u->port = (in_port_t) n; sin->sin_port = htons((in_port_t) n); - u->port_text.len = len; + u->port_text.len = last - port; u->port_text.data = port; last = port - 1; @@ -853,31 +876,69 @@ ngx_parse_inet_url(ngx_pool_t *pool, ngx_url_t *u) /* test value as port only */ - n = ngx_atoi(host, last - host); + len = last - host; + + dash = ngx_strlchr(host, last, '-'); + + if (dash) { + dash++; + + n = ngx_atoi(dash, last - dash); + + if (n == NGX_ERROR) { + goto no_port; + } + + if (n < 1 || n > 65535) { + u->err = "invalid port"; + + } else { + u->last_port = (in_port_t) n; + } + + len = dash - host - 1; + } + + n = ngx_atoi(host, len); if (n != NGX_ERROR) { + if (u->err) { + return NGX_ERROR; + } + if (n < 1 || n > 65535) { u->err = "invalid port"; return NGX_ERROR; } + if (u->last_port && n > u->last_port) { + u->err = "invalid port range"; + return NGX_ERROR; + } + u->port = (in_port_t) n; sin->sin_port = htons((in_port_t) n); + sin->sin_addr.s_addr = INADDR_ANY; u->port_text.len = last - host; u->port_text.data = host; u->wildcard = 1; - return NGX_OK; + return ngx_inet_add_addr(pool, u, &u->sockaddr.sockaddr, + u->socklen, 1); } } } +no_port: + + u->err = NULL; u->no_port = 1; u->port = u->default_port; sin->sin_port = htons(u->default_port); + u->last_port = 0; } len = last - host; @@ -893,7 +954,7 @@ ngx_parse_inet_url(ngx_pool_t *pool, ngx_url_t *u) if (u->listen && len == 1 && *host == '*') { sin->sin_addr.s_addr = INADDR_ANY; u->wildcard = 1; - return NGX_OK; + return ngx_inet_add_addr(pool, u, &u->sockaddr.sockaddr, u->socklen, 1); } sin->sin_addr.s_addr = ngx_inet_addr(host, len); @@ -904,33 +965,7 @@ ngx_parse_inet_url(ngx_pool_t *pool, ngx_url_t *u) u->wildcard = 1; } - u->naddrs = 1; - - u->addrs = ngx_pcalloc(pool, sizeof(ngx_addr_t)); - if (u->addrs == NULL) { - return NGX_ERROR; - } - - sin = ngx_pcalloc(pool, sizeof(struct sockaddr_in)); - if (sin == NULL) { - return NGX_ERROR; - } - - ngx_memcpy(sin, &u->sockaddr, sizeof(struct sockaddr_in)); - - u->addrs[0].sockaddr = (struct sockaddr *) sin; - u->addrs[0].socklen = sizeof(struct sockaddr_in); - - p = ngx_pnalloc(pool, u->host.len + sizeof(":65535") - 1); - if (p == NULL) { - return NGX_ERROR; - } - - u->addrs[0].name.len = ngx_sprintf(p, "%V:%d", - &u->host, u->port) - p; - u->addrs[0].name.data = p; - - return NGX_OK; + return ngx_inet_add_addr(pool, u, &u->sockaddr.sockaddr, u->socklen, 1); } if (u->no_resolve) { @@ -944,29 +979,7 @@ ngx_parse_inet_url(ngx_pool_t *pool, ngx_url_t *u) u->family = u->addrs[0].sockaddr->sa_family; u->socklen = u->addrs[0].socklen; ngx_memcpy(&u->sockaddr, u->addrs[0].sockaddr, u->addrs[0].socklen); - - switch (u->family) { - -#if (NGX_HAVE_INET6) - case AF_INET6: - sin6 = (struct sockaddr_in6 *) &u->sockaddr; - - if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { - u->wildcard = 1; - } - - break; -#endif - - default: /* AF_INET */ - sin = (struct sockaddr_in *) &u->sockaddr; - - if (sin->sin_addr.s_addr == INADDR_ANY) { - u->wildcard = 1; - } - - break; - } + u->wildcard = ngx_inet_wildcard(&u->sockaddr.sockaddr); return NGX_OK; } @@ -976,7 +989,7 @@ static ngx_int_t ngx_parse_inet6_url(ngx_pool_t *pool, ngx_url_t *u) { #if (NGX_HAVE_INET6) - u_char *p, *host, *port, *last, *uri; + u_char *p, *host, *port, *last, *uri, *dash; size_t len; ngx_int_t n; struct sockaddr_in6 *sin6; @@ -1022,6 +1035,25 @@ ngx_parse_inet6_url(ngx_pool_t *pool, ngx_url_t *u) len = last - port; + if (u->listen) { + dash = ngx_strlchr(port, last, '-'); + + if (dash) { + dash++; + + n = ngx_atoi(dash, last - dash); + + if (n < 1 || n > 65535) { + u->err = "invalid port"; + return NGX_ERROR; + } + + u->last_port = (in_port_t) n; + + len = dash - port - 1; + } + } + n = ngx_atoi(port, len); if (n < 1 || n > 65535) { @@ -1029,10 +1061,15 @@ ngx_parse_inet6_url(ngx_pool_t *pool, ngx_url_t *u) return NGX_ERROR; } + if (u->last_port && n > u->last_port) { + u->err = "invalid port range"; + return NGX_ERROR; + } + u->port = (in_port_t) n; sin6->sin6_port = htons((in_port_t) n); - u->port_text.len = len; + u->port_text.len = last - port; u->port_text.data = port; } else { @@ -1061,33 +1098,8 @@ ngx_parse_inet6_url(ngx_pool_t *pool, ngx_url_t *u) } u->family = AF_INET6; - u->naddrs = 1; - u->addrs = ngx_pcalloc(pool, sizeof(ngx_addr_t)); - if (u->addrs == NULL) { - return NGX_ERROR; - } - - sin6 = ngx_pcalloc(pool, sizeof(struct sockaddr_in6)); - if (sin6 == NULL) { - return NGX_ERROR; - } - - ngx_memcpy(sin6, &u->sockaddr, sizeof(struct sockaddr_in6)); - - u->addrs[0].sockaddr = (struct sockaddr *) sin6; - u->addrs[0].socklen = sizeof(struct sockaddr_in6); - - p = ngx_pnalloc(pool, u->host.len + sizeof(":65535") - 1); - if (p == NULL) { - return NGX_ERROR; - } - - u->addrs[0].name.len = ngx_sprintf(p, "%V:%d", - &u->host, u->port) - p; - u->addrs[0].name.data = p; - - return NGX_OK; + return ngx_inet_add_addr(pool, u, &u->sockaddr.sockaddr, u->socklen, 1); #else @@ -1104,15 +1116,9 @@ ngx_parse_inet6_url(ngx_pool_t *pool, ngx_url_t *u) ngx_int_t ngx_inet_resolve_host(ngx_pool_t *pool, ngx_url_t *u) { - u_char *p, *host; - size_t len; - in_port_t port; - ngx_uint_t i; - struct addrinfo hints, *res, *rp; - struct sockaddr_in *sin; - struct sockaddr_in6 *sin6; - - port = htons(u->port); + u_char *host; + ngx_uint_t n; + struct addrinfo hints, *res, *rp; host = ngx_alloc(u->host.len + 1, pool->log); if (host == NULL) { @@ -1136,7 +1142,7 @@ ngx_inet_resolve_host(ngx_pool_t *pool, ngx_url_t *u) ngx_free(host); - for (i = 0, rp = res; rp != NULL; rp = rp->ai_next) { + for (n = 0, rp = res; rp != NULL; rp = rp->ai_next) { switch (rp->ai_family) { @@ -1148,92 +1154,33 @@ ngx_inet_resolve_host(ngx_pool_t *pool, ngx_url_t *u) continue; } - i++; + n++; } - if (i == 0) { + if (n == 0) { u->err = "host not found"; goto failed; } /* MP: ngx_shared_palloc() */ - u->addrs = ngx_pcalloc(pool, i * sizeof(ngx_addr_t)); - if (u->addrs == NULL) { - goto failed; - } - - u->naddrs = i; - - i = 0; - - /* AF_INET addresses first */ - for (rp = res; rp != NULL; rp = rp->ai_next) { - if (rp->ai_family != AF_INET) { + switch (rp->ai_family) { + + case AF_INET: + case AF_INET6: + break; + + default: continue; } - sin = ngx_pcalloc(pool, rp->ai_addrlen); - if (sin == NULL) { + if (ngx_inet_add_addr(pool, u, rp->ai_addr, rp->ai_addrlen, n) + != NGX_OK) + { goto failed; } - - ngx_memcpy(sin, rp->ai_addr, rp->ai_addrlen); - - sin->sin_port = port; - - u->addrs[i].sockaddr = (struct sockaddr *) sin; - u->addrs[i].socklen = rp->ai_addrlen; - - len = NGX_INET_ADDRSTRLEN + sizeof(":65535") - 1; - - p = ngx_pnalloc(pool, len); - if (p == NULL) { - goto failed; - } - - len = ngx_sock_ntop((struct sockaddr *) sin, rp->ai_addrlen, p, len, 1); - - u->addrs[i].name.len = len; - u->addrs[i].name.data = p; - - i++; - } - - for (rp = res; rp != NULL; rp = rp->ai_next) { - - if (rp->ai_family != AF_INET6) { - continue; - } - - sin6 = ngx_pcalloc(pool, rp->ai_addrlen); - if (sin6 == NULL) { - goto failed; - } - - ngx_memcpy(sin6, rp->ai_addr, rp->ai_addrlen); - - sin6->sin6_port = port; - - u->addrs[i].sockaddr = (struct sockaddr *) sin6; - u->addrs[i].socklen = rp->ai_addrlen; - - len = NGX_INET6_ADDRSTRLEN + sizeof("[]:65535") - 1; - - p = ngx_pnalloc(pool, len); - if (p == NULL) { - goto failed; - } - - len = ngx_sock_ntop((struct sockaddr *) sin6, rp->ai_addrlen, p, - len, 1); - - u->addrs[i].name.len = len; - u->addrs[i].name.data = p; - - i++; } freeaddrinfo(res); @@ -1250,21 +1197,19 @@ failed: ngx_int_t ngx_inet_resolve_host(ngx_pool_t *pool, ngx_url_t *u) { - u_char *p, *host; - size_t len; - in_port_t port; - in_addr_t in_addr; - ngx_uint_t i; + u_char *host; + ngx_uint_t i, n; struct hostent *h; - struct sockaddr_in *sin; + struct sockaddr_in sin; /* AF_INET only */ - port = htons(u->port); + ngx_memzero(&sin, sizeof(struct sockaddr_in)); - in_addr = ngx_inet_addr(u->host.data, u->host.len); + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = ngx_inet_addr(u->host.data, u->host.len); - if (in_addr == INADDR_NONE) { + if (sin.sin_addr.s_addr == INADDR_NONE) { host = ngx_alloc(u->host.len + 1, pool->log); if (host == NULL) { return NGX_ERROR; @@ -1281,76 +1226,31 @@ ngx_inet_resolve_host(ngx_pool_t *pool, ngx_url_t *u) return NGX_ERROR; } - for (i = 0; h->h_addr_list[i] != NULL; i++) { /* void */ } + for (n = 0; h->h_addr_list[n] != NULL; n++) { /* void */ } /* MP: ngx_shared_palloc() */ - u->addrs = ngx_pcalloc(pool, i * sizeof(ngx_addr_t)); - if (u->addrs == NULL) { - return NGX_ERROR; - } + for (i = 0; i < n; i++) { + sin.sin_addr.s_addr = *(in_addr_t *) (h->h_addr_list[i]); - u->naddrs = i; - - for (i = 0; i < u->naddrs; i++) { - - sin = ngx_pcalloc(pool, sizeof(struct sockaddr_in)); - if (sin == NULL) { + if (ngx_inet_add_addr(pool, u, (struct sockaddr *) &sin, + sizeof(struct sockaddr_in), n) + != NGX_OK) + { return NGX_ERROR; } - - sin->sin_family = AF_INET; - sin->sin_port = port; - sin->sin_addr.s_addr = *(in_addr_t *) (h->h_addr_list[i]); - - u->addrs[i].sockaddr = (struct sockaddr *) sin; - u->addrs[i].socklen = sizeof(struct sockaddr_in); - - len = NGX_INET_ADDRSTRLEN + sizeof(":65535") - 1; - - p = ngx_pnalloc(pool, len); - if (p == NULL) { - return NGX_ERROR; - } - - len = ngx_sock_ntop((struct sockaddr *) sin, - sizeof(struct sockaddr_in), p, len, 1); - - u->addrs[i].name.len = len; - u->addrs[i].name.data = p; } } else { /* MP: ngx_shared_palloc() */ - u->addrs = ngx_pcalloc(pool, sizeof(ngx_addr_t)); - if (u->addrs == NULL) { + if (ngx_inet_add_addr(pool, u, (struct sockaddr *) &sin, + sizeof(struct sockaddr_in), 1) + != NGX_OK) + { return NGX_ERROR; } - - sin = ngx_pcalloc(pool, sizeof(struct sockaddr_in)); - if (sin == NULL) { - return NGX_ERROR; - } - - u->naddrs = 1; - - sin->sin_family = AF_INET; - sin->sin_port = port; - sin->sin_addr.s_addr = in_addr; - - u->addrs[0].sockaddr = (struct sockaddr *) sin; - u->addrs[0].socklen = sizeof(struct sockaddr_in); - - p = ngx_pnalloc(pool, u->host.len + sizeof(":65535") - 1); - if (p == NULL) { - return NGX_ERROR; - } - - u->addrs[0].name.len = ngx_sprintf(p, "%V:%d", - &u->host, ntohs(port)) - p; - u->addrs[0].name.data = p; } return NGX_OK; @@ -1359,6 +1259,67 @@ ngx_inet_resolve_host(ngx_pool_t *pool, ngx_url_t *u) #endif /* NGX_HAVE_GETADDRINFO && NGX_HAVE_INET6 */ +static ngx_int_t +ngx_inet_add_addr(ngx_pool_t *pool, ngx_url_t *u, struct sockaddr *sockaddr, + socklen_t socklen, ngx_uint_t total) +{ + u_char *p; + size_t len; + ngx_uint_t i, nports; + ngx_addr_t *addr; + struct sockaddr *sa; + + nports = u->last_port ? u->last_port - u->port + 1 : 1; + + if (u->addrs == NULL) { + u->addrs = ngx_palloc(pool, total * nports * sizeof(ngx_addr_t)); + if (u->addrs == NULL) { + return NGX_ERROR; + } + } + + for (i = 0; i < nports; i++) { + sa = ngx_pcalloc(pool, socklen); + if (sa == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(sa, sockaddr, socklen); + + ngx_inet_set_port(sa, u->port + i); + + switch (sa->sa_family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + len = NGX_INET6_ADDRSTRLEN + sizeof("[]:65536") - 1; + break; +#endif + + default: /* AF_INET */ + len = NGX_INET_ADDRSTRLEN + sizeof(":65535") - 1; + } + + p = ngx_pnalloc(pool, len); + if (p == NULL) { + return NGX_ERROR; + } + + len = ngx_sock_ntop(sa, socklen, p, len, 1); + + addr = &u->addrs[u->naddrs++]; + + addr->sockaddr = sa; + addr->socklen = socklen; + + addr->name.len = len; + addr->name.data = p; + } + + return NGX_OK; +} + + ngx_int_t ngx_cmp_sockaddr(struct sockaddr *sa1, socklen_t slen1, struct sockaddr *sa2, socklen_t slen2, ngx_uint_t cmp_port) @@ -1495,3 +1456,40 @@ ngx_inet_set_port(struct sockaddr *sa, in_port_t port) break; } } + + +ngx_uint_t +ngx_inet_wildcard(struct sockaddr *sa) +{ + struct sockaddr_in *sin; +#if (NGX_HAVE_INET6) + struct sockaddr_in6 *sin6; +#endif + + switch (sa->sa_family) { + + case AF_INET: + sin = (struct sockaddr_in *) sa; + + if (sin->sin_addr.s_addr == INADDR_ANY) { + return 1; + } + + break; + +#if (NGX_HAVE_INET6) + + case AF_INET6: + sin6 = (struct sockaddr_in6 *) sa; + + if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { + return 1; + } + + break; + +#endif + } + + return 0; +} diff --git a/src/core/ngx_inet.h b/src/core/ngx_inet.h index a3b392e..19050fc 100644 --- a/src/core/ngx_inet.h +++ b/src/core/ngx_inet.h @@ -86,6 +86,7 @@ typedef struct { in_port_t port; in_port_t default_port; + in_port_t last_port; int family; unsigned listen:1; @@ -125,6 +126,7 @@ ngx_int_t ngx_cmp_sockaddr(struct sockaddr *sa1, socklen_t slen1, struct sockaddr *sa2, socklen_t slen2, ngx_uint_t cmp_port); in_port_t ngx_inet_get_port(struct sockaddr *sa); void ngx_inet_set_port(struct sockaddr *sa, in_port_t port); +ngx_uint_t ngx_inet_wildcard(struct sockaddr *sa); #endif /* _NGX_INET_H_INCLUDED_ */ diff --git a/src/core/ngx_output_chain.c b/src/core/ngx_output_chain.c index 7f5dc78..5c3dbe8 100644 --- a/src/core/ngx_output_chain.c +++ b/src/core/ngx_output_chain.c @@ -126,6 +126,26 @@ ngx_output_chain(ngx_output_chain_ctx_t *ctx, ngx_chain_t *in) continue; } + if (bsize < 0) { + + ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, 0, + "negative size buf in output " + "t:%d r:%d f:%d %p %p-%p %p %O-%O", + ctx->in->buf->temporary, + ctx->in->buf->recycled, + ctx->in->buf->in_file, + ctx->in->buf->start, + ctx->in->buf->pos, + ctx->in->buf->last, + ctx->in->buf->file, + ctx->in->buf->file_pos, + ctx->in->buf->file_last); + + ngx_debug_point(); + + return NGX_ERROR; + } + if (ngx_output_chain_as_is(ctx, ctx->in->buf)) { /* move the chain link to the output chain */ @@ -665,7 +685,6 @@ ngx_chain_writer(void *data, ngx_chain_t *in) for (size = 0; in; in = in->next) { -#if 1 if (ngx_buf_size(in->buf) == 0 && !ngx_buf_special(in->buf)) { ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, 0, @@ -685,7 +704,26 @@ ngx_chain_writer(void *data, ngx_chain_t *in) continue; } -#endif + + if (ngx_buf_size(in->buf) < 0) { + + ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, 0, + "negative size buf in chain writer " + "t:%d r:%d f:%d %p %p-%p %p %O-%O", + in->buf->temporary, + in->buf->recycled, + in->buf->in_file, + in->buf->start, + in->buf->pos, + in->buf->last, + in->buf->file, + in->buf->file_pos, + in->buf->file_last); + + ngx_debug_point(); + + return NGX_ERROR; + } size += ngx_buf_size(in->buf); @@ -709,7 +747,6 @@ ngx_chain_writer(void *data, ngx_chain_t *in) for (cl = ctx->out; cl; cl = cl->next) { -#if 1 if (ngx_buf_size(cl->buf) == 0 && !ngx_buf_special(cl->buf)) { ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, 0, @@ -729,7 +766,26 @@ ngx_chain_writer(void *data, ngx_chain_t *in) continue; } -#endif + + if (ngx_buf_size(cl->buf) < 0) { + + ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, 0, + "negative size buf in chain writer " + "t:%d r:%d f:%d %p %p-%p %p %O-%O", + cl->buf->temporary, + cl->buf->recycled, + cl->buf->in_file, + cl->buf->start, + cl->buf->pos, + cl->buf->last, + cl->buf->file, + cl->buf->file_pos, + cl->buf->file_last); + + ngx_debug_point(); + + return NGX_ERROR; + } size += ngx_buf_size(cl->buf); } diff --git a/src/core/ngx_resolver.c b/src/core/ngx_resolver.c index cd55520..593645d 100644 --- a/src/core/ngx_resolver.c +++ b/src/core/ngx_resolver.c @@ -141,25 +141,24 @@ ngx_resolver_create(ngx_conf_t *cf, ngx_str_t *names, ngx_uint_t n) ngx_pool_cleanup_t *cln; ngx_resolver_connection_t *rec; + r = ngx_pcalloc(cf->pool, sizeof(ngx_resolver_t)); + if (r == NULL) { + return NULL; + } + + r->event = ngx_pcalloc(cf->pool, sizeof(ngx_event_t)); + if (r->event == NULL) { + return NULL; + } + cln = ngx_pool_cleanup_add(cf->pool, 0); if (cln == NULL) { return NULL; } cln->handler = ngx_resolver_cleanup; - - r = ngx_calloc(sizeof(ngx_resolver_t), cf->log); - if (r == NULL) { - return NULL; - } - cln->data = r; - r->event = ngx_calloc(sizeof(ngx_event_t), cf->log); - if (r->event == NULL) { - return NULL; - } - ngx_rbtree_init(&r->name_rbtree, &r->name_sentinel, ngx_resolver_rbtree_insert_value); @@ -276,6 +275,11 @@ ngx_resolver_create(ngx_conf_t *cf, ngx_str_t *names, ngx_uint_t n) } } + if (n && r->connections.nelts == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "no name servers defined"); + return NULL; + } + return r; } @@ -288,52 +292,42 @@ ngx_resolver_cleanup(void *data) ngx_uint_t i; ngx_resolver_connection_t *rec; - if (r) { - ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0, - "cleanup resolver"); + ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0, "cleanup resolver"); - ngx_resolver_cleanup_tree(r, &r->name_rbtree); + ngx_resolver_cleanup_tree(r, &r->name_rbtree); - ngx_resolver_cleanup_tree(r, &r->srv_rbtree); + ngx_resolver_cleanup_tree(r, &r->srv_rbtree); - ngx_resolver_cleanup_tree(r, &r->addr_rbtree); + ngx_resolver_cleanup_tree(r, &r->addr_rbtree); #if (NGX_HAVE_INET6) - ngx_resolver_cleanup_tree(r, &r->addr6_rbtree); + ngx_resolver_cleanup_tree(r, &r->addr6_rbtree); #endif - if (r->event) { - if (r->event->timer_set) { - ngx_del_timer(r->event); - } + if (r->event->timer_set) { + ngx_del_timer(r->event); + } - ngx_free(r->event); + rec = r->connections.elts; + + for (i = 0; i < r->connections.nelts; i++) { + if (rec[i].udp) { + ngx_close_connection(rec[i].udp); } - - rec = r->connections.elts; - - for (i = 0; i < r->connections.nelts; i++) { - if (rec[i].udp) { - ngx_close_connection(rec[i].udp); - } - - if (rec[i].tcp) { - ngx_close_connection(rec[i].tcp); - } - - if (rec[i].read_buf) { - ngx_resolver_free(r, rec[i].read_buf->start); - ngx_resolver_free(r, rec[i].read_buf); - } - - if (rec[i].write_buf) { - ngx_resolver_free(r, rec[i].write_buf->start); - ngx_resolver_free(r, rec[i].write_buf); - } + if (rec[i].tcp) { + ngx_close_connection(rec[i].tcp); } - ngx_free(r); + if (rec[i].read_buf) { + ngx_resolver_free(r, rec[i].read_buf->start); + ngx_resolver_free(r, rec[i].read_buf); + } + + if (rec[i].write_buf) { + ngx_resolver_free(r, rec[i].write_buf->start); + ngx_resolver_free(r, rec[i].write_buf); + } } } @@ -853,7 +847,15 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx, rn->nsrvs = 0; if (ngx_resolver_send_query(r, rn) != NGX_OK) { - goto failed; + + /* immediately retry once on failure */ + + rn->last_connection++; + if (rn->last_connection == r->connections.nelts) { + rn->last_connection = 0; + } + + (void) ngx_resolver_send_query(r, rn); } if (ngx_resolver_set_timeout(r, ctx) != NGX_OK) { @@ -1057,7 +1059,15 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx) rn->nsrvs = 0; if (ngx_resolver_send_query(r, rn) != NGX_OK) { - goto failed; + + /* immediately retry once on failure */ + + rn->last_connection++; + if (rn->last_connection == r->connections.nelts) { + rn->last_connection = 0; + } + + (void) ngx_resolver_send_query(r, rn); } if (ngx_resolver_set_timeout(r, ctx) != NGX_OK) { @@ -1299,16 +1309,23 @@ ngx_resolver_send_udp_query(ngx_resolver_t *r, ngx_resolver_connection_t *rec, n = ngx_send(rec->udp, query, qlen); - if (n == -1) { - return NGX_ERROR; + if (n == NGX_ERROR) { + goto failed; } if ((size_t) n != (size_t) qlen) { ngx_log_error(NGX_LOG_CRIT, &rec->log, 0, "send() incomplete"); - return NGX_ERROR; + goto failed; } return NGX_OK; + +failed: + + ngx_close_connection(rec->udp); + rec->udp = NULL; + + return NGX_ERROR; } @@ -4249,7 +4266,15 @@ ngx_resolver_report_srv(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx) } if (naddrs == 0) { - ctx->state = NGX_RESOLVE_NXDOMAIN; + ctx->state = srvs[0].state; + + for (i = 0; i < nsrvs; i++) { + if (srvs[i].state == NGX_RESOLVE_NXDOMAIN) { + ctx->state = NGX_RESOLVE_NXDOMAIN; + break; + } + } + ctx->valid = ngx_time() + (r->valid ? r->valid : 10); ctx->handler(ctx); @@ -4395,7 +4420,7 @@ ngx_udp_connect(ngx_resolver_connection_t *rec) if (c == NULL) { if (ngx_close_socket(s) == -1) { ngx_log_error(NGX_LOG_ALERT, &rec->log, ngx_socket_errno, - ngx_close_socket_n "failed"); + ngx_close_socket_n " failed"); } return NGX_ERROR; @@ -4481,7 +4506,7 @@ ngx_tcp_connect(ngx_resolver_connection_t *rec) if (c == NULL) { if (ngx_close_socket(s) == -1) { ngx_log_error(NGX_LOG_ALERT, &rec->log, ngx_socket_errno, - ngx_close_socket_n "failed"); + ngx_close_socket_n " failed"); } return NGX_ERROR; @@ -4546,7 +4571,7 @@ ngx_tcp_connect(ngx_resolver_connection_t *rec) level = NGX_LOG_CRIT; } - ngx_log_error(level, c->log, err, "connect() to %V failed", + ngx_log_error(level, &rec->log, err, "connect() to %V failed", &rec->server); ngx_close_connection(c); diff --git a/src/core/ngx_slab.c b/src/core/ngx_slab.c index 4023870..b8577ce 100644 --- a/src/core/ngx_slab.c +++ b/src/core/ngx_slab.c @@ -635,10 +635,9 @@ ngx_slab_free_locked(ngx_slab_pool_t *pool, void *p) goto fail; } - n = ((u_char *) p - pool->start) >> ngx_pagesize_shift; size = slab & ~NGX_SLAB_PAGE_START; - ngx_slab_free_pages(pool, &pool->pages[n], size); + ngx_slab_free_pages(pool, page, size); ngx_slab_junk(p, size << ngx_pagesize_shift); diff --git a/src/core/ngx_string.c b/src/core/ngx_string.c index 2ee07bf..468e960 100644 --- a/src/core/ngx_string.c +++ b/src/core/ngx_string.c @@ -1381,7 +1381,7 @@ ngx_utf8_length(u_char *p, size_t n) continue; } - if (ngx_utf8_decode(&p, n) > 0x10ffff) { + if (ngx_utf8_decode(&p, last - p) > 0x10ffff) { /* invalid UTF-8 */ return n; } @@ -2013,6 +2013,14 @@ ngx_sort(void *base, size_t n, size_t size, } +void +ngx_explicit_memzero(void *buf, size_t n) +{ + ngx_memzero(buf, n); + ngx_memory_barrier(); +} + + #if (NGX_MEMCPY_LIMIT) void * diff --git a/src/core/ngx_string.h b/src/core/ngx_string.h index 882ae7c..0fb9be7 100644 --- a/src/core/ngx_string.h +++ b/src/core/ngx_string.h @@ -88,6 +88,8 @@ ngx_strlchr(u_char *p, u_char *last, u_char c) #define ngx_memzero(buf, n) (void) memset(buf, 0, n) #define ngx_memset(buf, c, n) (void) memset(buf, c, n) +void ngx_explicit_memzero(void *buf, size_t n); + #if (NGX_MEMCPY_LIMIT) diff --git a/src/core/ngx_syslog.c b/src/core/ngx_syslog.c index 0a67928..3c7b63a 100644 --- a/src/core/ngx_syslog.c +++ b/src/core/ngx_syslog.c @@ -39,7 +39,8 @@ static ngx_event_t ngx_syslog_dummy_event; char * ngx_syslog_process_conf(ngx_conf_t *cf, ngx_syslog_peer_t *peer) { - peer->pool = cf->pool; + ngx_pool_cleanup_t *cln; + peer->facility = NGX_CONF_UNSET_UINT; peer->severity = NGX_CONF_UNSET_UINT; @@ -67,6 +68,19 @@ ngx_syslog_process_conf(ngx_conf_t *cf, ngx_syslog_peer_t *peer) peer->conn.fd = (ngx_socket_t) -1; + peer->conn.read = &ngx_syslog_dummy_event; + peer->conn.write = &ngx_syslog_dummy_event; + + ngx_syslog_dummy_event.log = &ngx_syslog_dummy_log; + + cln = ngx_pool_cleanup_add(cf->pool, 0); + if (cln == NULL) { + return NGX_CONF_ERROR; + } + + cln->data = peer; + cln->handler = ngx_syslog_cleanup; + return NGX_CONF_OK; } @@ -289,9 +303,7 @@ ngx_syslog_send(ngx_syslog_peer_t *peer, u_char *buf, size_t len) n = ngx_os_io.send(&peer->conn, buf, len); } -#if (NGX_HAVE_UNIX_DOMAIN) - - if (n == NGX_ERROR && peer->server.sockaddr->sa_family == AF_UNIX) { + if (n == NGX_ERROR) { if (ngx_close_socket(peer->conn.fd) == -1) { ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno, @@ -301,8 +313,6 @@ ngx_syslog_send(ngx_syslog_peer_t *peer, u_char *buf, size_t len) peer->conn.fd = (ngx_socket_t) -1; } -#endif - return n; } @@ -310,13 +320,7 @@ ngx_syslog_send(ngx_syslog_peer_t *peer, u_char *buf, size_t len) static ngx_int_t ngx_syslog_init_peer(ngx_syslog_peer_t *peer) { - ngx_socket_t fd; - ngx_pool_cleanup_t *cln; - - peer->conn.read = &ngx_syslog_dummy_event; - peer->conn.write = &ngx_syslog_dummy_event; - - ngx_syslog_dummy_event.log = &ngx_syslog_dummy_log; + ngx_socket_t fd; fd = ngx_socket(peer->server.sockaddr->sa_family, SOCK_DGRAM, 0); if (fd == (ngx_socket_t) -1) { @@ -337,14 +341,6 @@ ngx_syslog_init_peer(ngx_syslog_peer_t *peer) goto failed; } - cln = ngx_pool_cleanup_add(peer->pool, 0); - if (cln == NULL) { - goto failed; - } - - cln->data = peer; - cln->handler = ngx_syslog_cleanup; - peer->conn.fd = fd; /* UDP sockets are always ready to write */ diff --git a/src/core/ngx_syslog.h b/src/core/ngx_syslog.h index cc4c842..50dcd35 100644 --- a/src/core/ngx_syslog.h +++ b/src/core/ngx_syslog.h @@ -9,7 +9,6 @@ typedef struct { - ngx_pool_t *pool; ngx_uint_t facility; ngx_uint_t severity; ngx_str_t tag; diff --git a/src/core/ngx_times.h b/src/core/ngx_times.h index 94aedcd..49e0a8c 100644 --- a/src/core/ngx_times.h +++ b/src/core/ngx_times.h @@ -43,8 +43,8 @@ extern volatile ngx_str_t ngx_cached_http_log_iso8601; extern volatile ngx_str_t ngx_cached_syslog_time; /* - * milliseconds elapsed since epoch and truncated to ngx_msec_t, - * used in event timers + * milliseconds elapsed since some unspecified point in the past + * and truncated to ngx_msec_t, used in event timers */ extern volatile ngx_msec_t ngx_current_msec; diff --git a/src/event/modules/ngx_eventport_module.c b/src/event/modules/ngx_eventport_module.c index 01cfc97..11ad093 100644 --- a/src/event/modules/ngx_eventport_module.c +++ b/src/event/modules/ngx_eventport_module.c @@ -250,9 +250,7 @@ ngx_eventport_init(ngx_cycle_t *cycle, ngx_msec_t timer) ngx_memzero(&sev, sizeof(struct sigevent)); sev.sigev_notify = SIGEV_PORT; -#if !(NGX_TEST_BUILD_EVENTPORT) sev.sigev_value.sival_ptr = &pn; -#endif if (timer_create(CLOCK_REALTIME, &sev, &event_timer) == -1) { ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, diff --git a/src/event/modules/ngx_poll_module.c b/src/event/modules/ngx_poll_module.c index 4e03dab..b46ab53 100644 --- a/src/event/modules/ngx_poll_module.c +++ b/src/event/modules/ngx_poll_module.c @@ -84,7 +84,7 @@ ngx_poll_init(ngx_cycle_t *cycle, ngx_msec_t timer) } if (event_list) { - ngx_memcpy(list, event_list, sizeof(ngx_event_t *) * nevents); + ngx_memcpy(list, event_list, sizeof(struct pollfd) * nevents); ngx_free(event_list); } diff --git a/src/event/modules/ngx_win32_poll_module.c b/src/event/modules/ngx_win32_poll_module.c new file mode 100644 index 0000000..9fe867f --- /dev/null +++ b/src/event/modules/ngx_win32_poll_module.c @@ -0,0 +1,435 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Maxim Dounin + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include + + +static ngx_int_t ngx_poll_init(ngx_cycle_t *cycle, ngx_msec_t timer); +static void ngx_poll_done(ngx_cycle_t *cycle); +static ngx_int_t ngx_poll_add_event(ngx_event_t *ev, ngx_int_t event, + ngx_uint_t flags); +static ngx_int_t ngx_poll_del_event(ngx_event_t *ev, ngx_int_t event, + ngx_uint_t flags); +static ngx_int_t ngx_poll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, + ngx_uint_t flags); +static char *ngx_poll_init_conf(ngx_cycle_t *cycle, void *conf); + + +static struct pollfd *event_list; +static ngx_connection_t **event_index; +static ngx_uint_t nevents; + + +static ngx_str_t poll_name = ngx_string("poll"); + +static ngx_event_module_t ngx_poll_module_ctx = { + &poll_name, + NULL, /* create configuration */ + ngx_poll_init_conf, /* init configuration */ + + { + ngx_poll_add_event, /* add an event */ + ngx_poll_del_event, /* delete an event */ + ngx_poll_add_event, /* enable an event */ + ngx_poll_del_event, /* disable an event */ + NULL, /* add an connection */ + NULL, /* delete an connection */ + NULL, /* trigger a notify */ + ngx_poll_process_events, /* process the events */ + ngx_poll_init, /* init the events */ + ngx_poll_done /* done the events */ + } + +}; + +ngx_module_t ngx_poll_module = { + NGX_MODULE_V1, + &ngx_poll_module_ctx, /* module context */ + NULL, /* module directives */ + NGX_EVENT_MODULE, /* module type */ + NULL, /* init master */ + NULL, /* init module */ + NULL, /* init process */ + NULL, /* init thread */ + NULL, /* exit thread */ + NULL, /* exit process */ + NULL, /* exit master */ + NGX_MODULE_V1_PADDING +}; + + + +static ngx_int_t +ngx_poll_init(ngx_cycle_t *cycle, ngx_msec_t timer) +{ + struct pollfd *list; + ngx_connection_t **index; + + if (event_list == NULL) { + nevents = 0; + } + + if (ngx_process >= NGX_PROCESS_WORKER + || cycle->old_cycle == NULL + || cycle->old_cycle->connection_n < cycle->connection_n) + { + list = ngx_alloc(sizeof(struct pollfd) * cycle->connection_n, + cycle->log); + if (list == NULL) { + return NGX_ERROR; + } + + if (event_list) { + ngx_memcpy(list, event_list, sizeof(struct pollfd) * nevents); + ngx_free(event_list); + } + + event_list = list; + + index = ngx_alloc(sizeof(ngx_connection_t *) * cycle->connection_n, + cycle->log); + if (index == NULL) { + return NGX_ERROR; + } + + if (event_index) { + ngx_memcpy(index, event_index, + sizeof(ngx_connection_t *) * nevents); + ngx_free(event_index); + } + + event_index = index; + } + + ngx_io = ngx_os_io; + + ngx_event_actions = ngx_poll_module_ctx.actions; + + ngx_event_flags = NGX_USE_LEVEL_EVENT; + + return NGX_OK; +} + + +static void +ngx_poll_done(ngx_cycle_t *cycle) +{ + ngx_free(event_list); + ngx_free(event_index); + + event_list = NULL; + event_index = NULL; +} + + +static ngx_int_t +ngx_poll_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags) +{ + ngx_event_t *e; + ngx_connection_t *c; + + c = ev->data; + + ev->active = 1; + + if (ev->index != NGX_INVALID_INDEX) { + ngx_log_error(NGX_LOG_ALERT, ev->log, 0, + "poll event fd:%d ev:%i is already set", c->fd, event); + return NGX_OK; + } + + if (event == NGX_READ_EVENT) { + e = c->write; +#if (NGX_READ_EVENT != POLLIN) + event = POLLIN; +#endif + + } else { + e = c->read; +#if (NGX_WRITE_EVENT != POLLOUT) + event = POLLOUT; +#endif + } + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0, + "poll add event: fd:%d ev:%i", c->fd, event); + + if (e == NULL || e->index == NGX_INVALID_INDEX) { + + event_list[nevents].fd = c->fd; + event_list[nevents].events = (short) event; + event_list[nevents].revents = 0; + + event_index[nevents] = c; + + ev->index = nevents; + nevents++; + + } else { + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ev->log, 0, + "poll add index: %i", e->index); + + event_list[e->index].events |= (short) event; + ev->index = e->index; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_poll_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags) +{ + ngx_event_t *e; + ngx_connection_t *c; + + c = ev->data; + + ev->active = 0; + + if (ev->index == NGX_INVALID_INDEX) { + ngx_log_error(NGX_LOG_ALERT, ev->log, 0, + "poll event fd:%d ev:%i is already deleted", + c->fd, event); + return NGX_OK; + } + + if (event == NGX_READ_EVENT) { + e = c->write; +#if (NGX_READ_EVENT != POLLIN) + event = POLLIN; +#endif + + } else { + e = c->read; +#if (NGX_WRITE_EVENT != POLLOUT) + event = POLLOUT; +#endif + } + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0, + "poll del event: fd:%d ev:%i", c->fd, event); + + if (e == NULL || e->index == NGX_INVALID_INDEX) { + nevents--; + + if (ev->index < nevents) { + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0, + "index: copy event %ui to %i", nevents, ev->index); + + event_list[ev->index] = event_list[nevents]; + event_index[ev->index] = event_index[nevents]; + + c = event_index[ev->index]; + + if (c->fd == (ngx_socket_t) -1) { + ngx_log_error(NGX_LOG_ALERT, ev->log, 0, + "unexpected last event"); + + } else { + if (c->read->index == nevents) { + c->read->index = ev->index; + } + + if (c->write->index == nevents) { + c->write->index = ev->index; + } + } + } + + } else { + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ev->log, 0, + "poll del index: %i", e->index); + + event_list[e->index].events &= (short) ~event; + } + + ev->index = NGX_INVALID_INDEX; + + return NGX_OK; +} + + +static ngx_int_t +ngx_poll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags) +{ + int ready, revents; + ngx_err_t err; + ngx_uint_t i, found; + ngx_event_t *ev; + ngx_queue_t *queue; + ngx_connection_t *c; + + /* NGX_TIMER_INFINITE == INFTIM */ + +#if (NGX_DEBUG0) + if (cycle->log->log_level & NGX_LOG_DEBUG_ALL) { + for (i = 0; i < nevents; i++) { + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, cycle->log, 0, + "poll: %ui: fd:%d ev:%04Xd", + i, event_list[i].fd, event_list[i].events); + } + } +#endif + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "poll timer: %M", timer); + + ready = WSAPoll(event_list, (u_int) nevents, (int) timer); + + err = (ready == -1) ? ngx_errno : 0; + + if (flags & NGX_UPDATE_TIME || ngx_event_timer_alarm) { + ngx_time_update(); + } + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0, + "poll ready %d of %ui", ready, nevents); + + if (err) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, err, "WSAPoll() failed"); + return NGX_ERROR; + } + + if (ready == 0) { + if (timer != NGX_TIMER_INFINITE) { + return NGX_OK; + } + + ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, + "WSAPoll() returned no events without timeout"); + return NGX_ERROR; + } + + for (i = 0; i < nevents && ready; i++) { + + revents = event_list[i].revents; + +#if 1 + ngx_log_debug4(NGX_LOG_DEBUG_EVENT, cycle->log, 0, + "poll: %ui: fd:%d ev:%04Xd rev:%04Xd", + i, event_list[i].fd, event_list[i].events, revents); +#else + if (revents) { + ngx_log_debug4(NGX_LOG_DEBUG_EVENT, cycle->log, 0, + "poll: %ui: fd:%d ev:%04Xd rev:%04Xd", + i, event_list[i].fd, event_list[i].events, revents); + } +#endif + + if (revents & POLLNVAL) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, + "poll() error fd:%d ev:%04Xd rev:%04Xd", + event_list[i].fd, event_list[i].events, revents); + } + + if (revents & ~(POLLIN|POLLOUT|POLLERR|POLLHUP|POLLNVAL)) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, + "strange poll() events fd:%d ev:%04Xd rev:%04Xd", + event_list[i].fd, event_list[i].events, revents); + } + + if (event_list[i].fd == (ngx_socket_t) -1) { + /* + * the disabled event, a workaround for our possible bug, + * see the comment below + */ + continue; + } + + c = event_index[i]; + + if (c->fd == (ngx_socket_t) -1) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "unexpected event"); + + /* + * it is certainly our fault and it should be investigated, + * in the meantime we disable this event to avoid a CPU spinning + */ + + if (i == nevents - 1) { + nevents--; + } else { + event_list[i].fd = (ngx_socket_t) -1; + } + + continue; + } + + if (revents & (POLLERR|POLLHUP|POLLNVAL)) { + + /* + * if the error events were returned, add POLLIN and POLLOUT + * to handle the events at least in one active handler + */ + + revents |= POLLIN|POLLOUT; + } + + found = 0; + + if ((revents & POLLIN) && c->read->active) { + found = 1; + + ev = c->read; + ev->ready = 1; + + queue = ev->accept ? &ngx_posted_accept_events + : &ngx_posted_events; + + ngx_post_event(ev, queue); + } + + if ((revents & POLLOUT) && c->write->active) { + found = 1; + + ev = c->write; + ev->ready = 1; + + ngx_post_event(ev, &ngx_posted_events); + } + + if (found) { + ready--; + continue; + } + } + + if (ready != 0) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "poll ready != events"); + } + + return NGX_OK; +} + + +static char * +ngx_poll_init_conf(ngx_cycle_t *cycle, void *conf) +{ + ngx_event_conf_t *ecf; + + ecf = ngx_event_get_conf(cycle->conf_ctx, ngx_event_core_module); + + if (ecf->use != ngx_poll_module.ctx_index) { + return NGX_CONF_OK; + } + +#if (NGX_LOAD_WSAPOLL) + + if (!ngx_have_wsapoll) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, + "poll is not available on this platform"); + return NGX_CONF_ERROR; + } + +#endif + + return NGX_CONF_OK; +} diff --git a/src/event/modules/ngx_win32_select_module.c b/src/event/modules/ngx_win32_select_module.c index a98a83f..8093a60 100644 --- a/src/event/modules/ngx_win32_select_module.c +++ b/src/event/modules/ngx_win32_select_module.c @@ -26,6 +26,7 @@ static fd_set master_read_fd_set; static fd_set master_write_fd_set; static fd_set work_read_fd_set; static fd_set work_write_fd_set; +static fd_set work_except_fd_set; static ngx_uint_t max_read; static ngx_uint_t max_write; @@ -251,9 +252,11 @@ ngx_select_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, work_read_fd_set = master_read_fd_set; work_write_fd_set = master_write_fd_set; + work_except_fd_set = master_write_fd_set; if (max_read || max_write) { - ready = select(0, &work_read_fd_set, &work_write_fd_set, NULL, tp); + ready = select(0, &work_read_fd_set, &work_write_fd_set, + &work_except_fd_set, tp); } else { @@ -306,14 +309,20 @@ ngx_select_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, if (ev->write) { if (FD_ISSET(c->fd, &work_write_fd_set)) { - found = 1; + found++; ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "select write %d", c->fd); } + if (FD_ISSET(c->fd, &work_except_fd_set)) { + found++; + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, + "select except %d", c->fd); + } + } else { if (FD_ISSET(c->fd, &work_read_fd_set)) { - found = 1; + found++; ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "select read %d", c->fd); } @@ -327,7 +336,7 @@ ngx_select_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_post_event(ev, queue); - nready++; + nready += found; } } diff --git a/src/event/ngx_event.c b/src/event/ngx_event.c index 57af813..69c55d7 100644 --- a/src/event/ngx_event.c +++ b/src/event/ngx_event.c @@ -410,12 +410,52 @@ ngx_handle_write_event(ngx_event_t *wev, size_t lowat) static char * ngx_event_init_conf(ngx_cycle_t *cycle, void *conf) { +#if (NGX_HAVE_REUSEPORT) + ngx_uint_t i; + ngx_listening_t *ls; +#endif + if (ngx_get_conf(cycle->conf_ctx, ngx_events_module) == NULL) { ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, "no \"events\" section in configuration"); return NGX_CONF_ERROR; } + if (cycle->connection_n < cycle->listening.nelts + 1) { + + /* + * there should be at least one connection for each listening + * socket, plus an additional connection for channel + */ + + ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, + "%ui worker_connections are not enough " + "for %ui listening sockets", + cycle->connection_n, cycle->listening.nelts); + + return NGX_CONF_ERROR; + } + +#if (NGX_HAVE_REUSEPORT) + + ls = cycle->listening.elts; + for (i = 0; i < cycle->listening.nelts; i++) { + + if (!ls[i].reuseport || ls[i].worker != 0) { + continue; + } + + if (ngx_clone_listening(cycle, &ls[i]) != NGX_OK) { + return NGX_CONF_ERROR; + } + + /* cloning may change cycle->listening.elts */ + + ls = cycle->listening.elts; + } + +#endif + return NGX_CONF_OK; } diff --git a/src/event/ngx_event.h b/src/event/ngx_event.h index 19fec68..bb77c4a 100644 --- a/src/event/ngx_event.h +++ b/src/event/ngx_event.h @@ -499,16 +499,23 @@ extern ngx_module_t ngx_event_core_module; #define ngx_event_get_conf(conf_ctx, module) \ - (*(ngx_get_conf(conf_ctx, ngx_events_module))) [module.ctx_index]; + (*(ngx_get_conf(conf_ctx, ngx_events_module))) [module.ctx_index] void ngx_event_accept(ngx_event_t *ev); #if !(NGX_WIN32) void ngx_event_recvmsg(ngx_event_t *ev); +void ngx_udp_rbtree_insert_value(ngx_rbtree_node_t *temp, + ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); #endif +void ngx_delete_udp_connection(void *data); ngx_int_t ngx_trylock_accept_mutex(ngx_cycle_t *cycle); +ngx_int_t ngx_enable_accept_events(ngx_cycle_t *cycle); u_char *ngx_accept_log_error(ngx_log_t *log, u_char *buf, size_t len); +#if (NGX_DEBUG) +void ngx_debug_accepted_connection(ngx_event_conf_t *ecf, ngx_connection_t *c); +#endif void ngx_process_events_and_timers(ngx_cycle_t *cycle); diff --git a/src/event/ngx_event_accept.c b/src/event/ngx_event_accept.c index 7e9f742..4364240 100644 --- a/src/event/ngx_event_accept.c +++ b/src/event/ngx_event_accept.c @@ -10,13 +10,8 @@ #include -static ngx_int_t ngx_enable_accept_events(ngx_cycle_t *cycle); static ngx_int_t ngx_disable_accept_events(ngx_cycle_t *cycle, ngx_uint_t all); static void ngx_close_accepted_connection(ngx_connection_t *c); -#if (NGX_DEBUG) -static void ngx_debug_accepted_connection(ngx_event_conf_t *ecf, - ngx_connection_t *c); -#endif void @@ -320,341 +315,6 @@ ngx_event_accept(ngx_event_t *ev) } -#if !(NGX_WIN32) - -void -ngx_event_recvmsg(ngx_event_t *ev) -{ - ssize_t n; - ngx_log_t *log; - ngx_err_t err; - ngx_event_t *rev, *wev; - struct iovec iov[1]; - struct msghdr msg; - ngx_sockaddr_t sa; - ngx_listening_t *ls; - ngx_event_conf_t *ecf; - ngx_connection_t *c, *lc; - static u_char buffer[65535]; - -#if (NGX_HAVE_MSGHDR_MSG_CONTROL) - -#if (NGX_HAVE_IP_RECVDSTADDR) - u_char msg_control[CMSG_SPACE(sizeof(struct in_addr))]; -#elif (NGX_HAVE_IP_PKTINFO) - u_char msg_control[CMSG_SPACE(sizeof(struct in_pktinfo))]; -#endif - -#if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO) - u_char msg_control6[CMSG_SPACE(sizeof(struct in6_pktinfo))]; -#endif - -#endif - - if (ev->timedout) { - if (ngx_enable_accept_events((ngx_cycle_t *) ngx_cycle) != NGX_OK) { - return; - } - - ev->timedout = 0; - } - - ecf = ngx_event_get_conf(ngx_cycle->conf_ctx, ngx_event_core_module); - - if (!(ngx_event_flags & NGX_USE_KQUEUE_EVENT)) { - ev->available = ecf->multi_accept; - } - - lc = ev->data; - ls = lc->listening; - ev->ready = 0; - - ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0, - "recvmsg on %V, ready: %d", &ls->addr_text, ev->available); - - do { - ngx_memzero(&msg, sizeof(struct msghdr)); - - iov[0].iov_base = (void *) buffer; - iov[0].iov_len = sizeof(buffer); - - msg.msg_name = &sa; - msg.msg_namelen = sizeof(ngx_sockaddr_t); - msg.msg_iov = iov; - msg.msg_iovlen = 1; - -#if (NGX_HAVE_MSGHDR_MSG_CONTROL) - - if (ls->wildcard) { - -#if (NGX_HAVE_IP_RECVDSTADDR || NGX_HAVE_IP_PKTINFO) - if (ls->sockaddr->sa_family == AF_INET) { - msg.msg_control = &msg_control; - msg.msg_controllen = sizeof(msg_control); - } -#endif - -#if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO) - if (ls->sockaddr->sa_family == AF_INET6) { - msg.msg_control = &msg_control6; - msg.msg_controllen = sizeof(msg_control6); - } -#endif - } - -#endif - - n = recvmsg(lc->fd, &msg, 0); - - if (n == -1) { - err = ngx_socket_errno; - - if (err == NGX_EAGAIN) { - ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, err, - "recvmsg() not ready"); - return; - } - - ngx_log_error(NGX_LOG_ALERT, ev->log, err, "recvmsg() failed"); - - return; - } - -#if (NGX_STAT_STUB) - (void) ngx_atomic_fetch_add(ngx_stat_accepted, 1); -#endif - -#if (NGX_HAVE_MSGHDR_MSG_CONTROL) - if (msg.msg_flags & (MSG_TRUNC|MSG_CTRUNC)) { - ngx_log_error(NGX_LOG_ALERT, ev->log, 0, - "recvmsg() truncated data"); - continue; - } -#endif - - ngx_accept_disabled = ngx_cycle->connection_n / 8 - - ngx_cycle->free_connection_n; - - c = ngx_get_connection(lc->fd, ev->log); - if (c == NULL) { - return; - } - - c->shared = 1; - c->type = SOCK_DGRAM; - c->socklen = msg.msg_namelen; - - if (c->socklen > (socklen_t) sizeof(ngx_sockaddr_t)) { - c->socklen = sizeof(ngx_sockaddr_t); - } - - if (c->socklen == 0) { - - /* - * on Linux recvmsg() returns zero msg_namelen - * when receiving packets from unbound AF_UNIX sockets - */ - - c->socklen = sizeof(struct sockaddr); - ngx_memzero(&sa, sizeof(struct sockaddr)); - sa.sockaddr.sa_family = ls->sockaddr->sa_family; - } - -#if (NGX_STAT_STUB) - (void) ngx_atomic_fetch_add(ngx_stat_active, 1); -#endif - - c->pool = ngx_create_pool(ls->pool_size, ev->log); - if (c->pool == NULL) { - ngx_close_accepted_connection(c); - return; - } - - c->sockaddr = ngx_palloc(c->pool, c->socklen); - if (c->sockaddr == NULL) { - ngx_close_accepted_connection(c); - return; - } - - ngx_memcpy(c->sockaddr, msg.msg_name, c->socklen); - - log = ngx_palloc(c->pool, sizeof(ngx_log_t)); - if (log == NULL) { - ngx_close_accepted_connection(c); - return; - } - - *log = ls->log; - - c->send = ngx_udp_send; - c->send_chain = ngx_udp_send_chain; - - c->log = log; - c->pool->log = log; - - c->listening = ls; - c->local_sockaddr = ls->sockaddr; - c->local_socklen = ls->socklen; - -#if (NGX_HAVE_MSGHDR_MSG_CONTROL) - - if (ls->wildcard) { - struct cmsghdr *cmsg; - struct sockaddr *sockaddr; - - sockaddr = ngx_palloc(c->pool, c->local_socklen); - if (sockaddr == NULL) { - ngx_close_accepted_connection(c); - return; - } - - ngx_memcpy(sockaddr, c->local_sockaddr, c->local_socklen); - c->local_sockaddr = sockaddr; - - for (cmsg = CMSG_FIRSTHDR(&msg); - cmsg != NULL; - cmsg = CMSG_NXTHDR(&msg, cmsg)) - { - -#if (NGX_HAVE_IP_RECVDSTADDR) - - if (cmsg->cmsg_level == IPPROTO_IP - && cmsg->cmsg_type == IP_RECVDSTADDR - && sockaddr->sa_family == AF_INET) - { - struct in_addr *addr; - struct sockaddr_in *sin; - - addr = (struct in_addr *) CMSG_DATA(cmsg); - sin = (struct sockaddr_in *) sockaddr; - sin->sin_addr = *addr; - - break; - } - -#elif (NGX_HAVE_IP_PKTINFO) - - if (cmsg->cmsg_level == IPPROTO_IP - && cmsg->cmsg_type == IP_PKTINFO - && sockaddr->sa_family == AF_INET) - { - struct in_pktinfo *pkt; - struct sockaddr_in *sin; - - pkt = (struct in_pktinfo *) CMSG_DATA(cmsg); - sin = (struct sockaddr_in *) sockaddr; - sin->sin_addr = pkt->ipi_addr; - - break; - } - -#endif - -#if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO) - - if (cmsg->cmsg_level == IPPROTO_IPV6 - && cmsg->cmsg_type == IPV6_PKTINFO - && sockaddr->sa_family == AF_INET6) - { - struct in6_pktinfo *pkt6; - struct sockaddr_in6 *sin6; - - pkt6 = (struct in6_pktinfo *) CMSG_DATA(cmsg); - sin6 = (struct sockaddr_in6 *) sockaddr; - sin6->sin6_addr = pkt6->ipi6_addr; - - break; - } - -#endif - - } - } - -#endif - - c->buffer = ngx_create_temp_buf(c->pool, n); - if (c->buffer == NULL) { - ngx_close_accepted_connection(c); - return; - } - - c->buffer->last = ngx_cpymem(c->buffer->last, buffer, n); - - rev = c->read; - wev = c->write; - - wev->ready = 1; - - rev->log = log; - wev->log = log; - - /* - * TODO: MT: - ngx_atomic_fetch_add() - * or protection by critical section or light mutex - * - * TODO: MP: - allocated in a shared memory - * - ngx_atomic_fetch_add() - * or protection by critical section or light mutex - */ - - c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1); - -#if (NGX_STAT_STUB) - (void) ngx_atomic_fetch_add(ngx_stat_handled, 1); -#endif - - if (ls->addr_ntop) { - c->addr_text.data = ngx_pnalloc(c->pool, ls->addr_text_max_len); - if (c->addr_text.data == NULL) { - ngx_close_accepted_connection(c); - return; - } - - c->addr_text.len = ngx_sock_ntop(c->sockaddr, c->socklen, - c->addr_text.data, - ls->addr_text_max_len, 0); - if (c->addr_text.len == 0) { - ngx_close_accepted_connection(c); - return; - } - } - -#if (NGX_DEBUG) - { - ngx_str_t addr; - u_char text[NGX_SOCKADDR_STRLEN]; - - ngx_debug_accepted_connection(ecf, c); - - if (log->log_level & NGX_LOG_DEBUG_EVENT) { - addr.data = text; - addr.len = ngx_sock_ntop(c->sockaddr, c->socklen, text, - NGX_SOCKADDR_STRLEN, 1); - - ngx_log_debug4(NGX_LOG_DEBUG_EVENT, log, 0, - "*%uA recvmsg: %V fd:%d n:%z", - c->number, &addr, c->fd, n); - } - - } -#endif - - log->data = NULL; - log->handler = NULL; - - ls->handler(c); - - if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { - ev->available -= n; - } - - } while (ev->available); -} - -#endif - - ngx_int_t ngx_trylock_accept_mutex(ngx_cycle_t *cycle) { @@ -693,7 +353,7 @@ ngx_trylock_accept_mutex(ngx_cycle_t *cycle) } -static ngx_int_t +ngx_int_t ngx_enable_accept_events(ngx_cycle_t *cycle) { ngx_uint_t i; @@ -768,7 +428,7 @@ ngx_close_accepted_connection(ngx_connection_t *c) fd = c->fd; c->fd = (ngx_socket_t) -1; - if (!c->shared && ngx_close_socket(fd) == -1) { + if (ngx_close_socket(fd) == -1) { ngx_log_error(NGX_LOG_ALERT, c->log, ngx_socket_errno, ngx_close_socket_n " failed"); } @@ -793,7 +453,7 @@ ngx_accept_log_error(ngx_log_t *log, u_char *buf, size_t len) #if (NGX_DEBUG) -static void +void ngx_debug_accepted_connection(ngx_event_conf_t *ecf, ngx_connection_t *c) { struct sockaddr_in *sin; diff --git a/src/event/ngx_event_connect.c b/src/event/ngx_event_connect.c index e7f28c9..1ffa798 100644 --- a/src/event/ngx_event_connect.c +++ b/src/event/ngx_event_connect.c @@ -20,7 +20,7 @@ static ngx_int_t ngx_event_connect_set_transparent(ngx_peer_connection_t *pc, ngx_int_t ngx_event_connect_peer(ngx_peer_connection_t *pc) { - int rc, type; + int rc, type, value; #if (NGX_HAVE_IP_BIND_ADDRESS_NO_PORT || NGX_LINUX) in_port_t port; #endif @@ -55,7 +55,7 @@ ngx_event_connect_peer(ngx_peer_connection_t *pc) if (c == NULL) { if (ngx_close_socket(s) == -1) { ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno, - ngx_close_socket_n "failed"); + ngx_close_socket_n " failed"); } return NGX_ERROR; @@ -73,6 +73,18 @@ ngx_event_connect_peer(ngx_peer_connection_t *pc) } } + if (pc->so_keepalive) { + value = 1; + + if (setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, + (const void *) &value, sizeof(int)) + == -1) + { + ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno, + "setsockopt(SO_KEEPALIVE) failed, ignored"); + } + } + if (ngx_nonblocking(s) == -1) { ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno, ngx_nonblocking_n " failed"); diff --git a/src/event/ngx_event_connect.h b/src/event/ngx_event_connect.h index 72d21d7..d3b2378 100644 --- a/src/event/ngx_event_connect.h +++ b/src/event/ngx_event_connect.h @@ -62,6 +62,8 @@ struct ngx_peer_connection_s { unsigned cached:1; unsigned transparent:1; + unsigned so_keepalive:1; + unsigned down:1; /* ngx_connection_log_error_e */ unsigned log_error:2; diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c index c4b51b5..7be4fb4 100644 --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -18,15 +18,35 @@ typedef struct { } ngx_openssl_conf_t; +static X509 *ngx_ssl_load_certificate(ngx_pool_t *pool, char **err, + ngx_str_t *cert, STACK_OF(X509) **chain); +static EVP_PKEY *ngx_ssl_load_certificate_key(ngx_pool_t *pool, char **err, + ngx_str_t *key, ngx_array_t *passwords); static int ngx_ssl_password_callback(char *buf, int size, int rwflag, void *userdata); static int ngx_ssl_verify_callback(int ok, X509_STORE_CTX *x509_store); static void ngx_ssl_info_callback(const ngx_ssl_conn_t *ssl_conn, int where, int ret); static void ngx_ssl_passwords_cleanup(void *data); +static int ngx_ssl_new_client_session(ngx_ssl_conn_t *ssl_conn, + ngx_ssl_session_t *sess); +#ifdef SSL_READ_EARLY_DATA_SUCCESS +static ngx_int_t ngx_ssl_try_early_data(ngx_connection_t *c); +#endif +#if (NGX_DEBUG) +static void ngx_ssl_handshake_log(ngx_connection_t *c); +#endif static void ngx_ssl_handshake_handler(ngx_event_t *ev); +#ifdef SSL_READ_EARLY_DATA_SUCCESS +static ssize_t ngx_ssl_recv_early(ngx_connection_t *c, u_char *buf, + size_t size); +#endif static ngx_int_t ngx_ssl_handle_recv(ngx_connection_t *c, int n); static void ngx_ssl_write_handler(ngx_event_t *wev); +#ifdef SSL_READ_EARLY_DATA_SUCCESS +static ssize_t ngx_ssl_write_early(ngx_connection_t *c, u_char *data, + size_t size); +#endif static void ngx_ssl_read_handler(ngx_event_t *rev); static void ngx_ssl_shutdown_handler(ngx_event_t *ev); static void ngx_ssl_connection_error(ngx_connection_t *c, int sslerr, @@ -34,8 +54,7 @@ static void ngx_ssl_connection_error(ngx_connection_t *c, int sslerr, static void ngx_ssl_clear_error(ngx_log_t *log); static ngx_int_t ngx_ssl_session_id_context(ngx_ssl_t *ssl, - ngx_str_t *sess_ctx); -ngx_int_t ngx_ssl_session_cache_init(ngx_shm_zone_t *shm_zone, void *data); + ngx_str_t *sess_ctx, ngx_array_t *certificates); static int ngx_ssl_new_session(ngx_ssl_conn_t *ssl_conn, ngx_ssl_session_t *sess); static ngx_ssl_session_t *ngx_ssl_get_cached_session(ngx_ssl_conn_t *ssl_conn, @@ -53,6 +72,7 @@ static void ngx_ssl_session_rbtree_insert_value(ngx_rbtree_node_t *temp, static int ngx_ssl_session_ticket_key_callback(ngx_ssl_conn_t *ssl_conn, unsigned char *name, unsigned char *iv, EVP_CIPHER_CTX *ectx, HMAC_CTX *hctx, int enc); +static void ngx_ssl_session_ticket_keys_cleanup(void *data); #endif #ifndef X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT @@ -344,6 +364,14 @@ ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_t protocols, void *data) SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_COMPRESSION); #endif +#ifdef SSL_OP_NO_ANTI_REPLAY + SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_ANTI_REPLAY); +#endif + +#ifdef SSL_OP_NO_CLIENT_RENEGOTIATION + SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_CLIENT_RENEGOTIATION); +#endif + #ifdef SSL_MODE_RELEASE_BUFFERS SSL_CTX_set_mode(ssl->ctx, SSL_MODE_RELEASE_BUFFERS); #endif @@ -387,34 +415,19 @@ ngx_int_t ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert, ngx_str_t *key, ngx_array_t *passwords) { - BIO *bio; - X509 *x509; - u_long n; - ngx_str_t *pwd; - ngx_uint_t tries; + char *err; + X509 *x509; + EVP_PKEY *pkey; + STACK_OF(X509) *chain; - if (ngx_conf_full_name(cf->cycle, cert, 1) != NGX_OK) { - return NGX_ERROR; - } - - /* - * we can't use SSL_CTX_use_certificate_chain_file() as it doesn't - * allow to access certificate later from SSL_CTX, so we reimplement - * it here - */ - - bio = BIO_new_file((char *) cert->data, "r"); - if (bio == NULL) { - ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, - "BIO_new_file(\"%s\") failed", cert->data); - return NGX_ERROR; - } - - x509 = PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL); + x509 = ngx_ssl_load_certificate(cf->pool, &err, cert, &chain); if (x509 == NULL) { - ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, - "PEM_read_bio_X509_AUX(\"%s\") failed", cert->data); - BIO_free(bio); + if (err != NULL) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "cannot load certificate \"%s\": %s", + cert->data, err); + } + return NGX_ERROR; } @@ -422,7 +435,7 @@ ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert, ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "SSL_CTX_use_certificate(\"%s\") failed", cert->data); X509_free(x509); - BIO_free(bio); + sk_X509_pop_free(chain, X509_free); return NGX_ERROR; } @@ -431,7 +444,7 @@ ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert, { ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "X509_set_ex_data() failed"); X509_free(x509); - BIO_free(bio); + sk_X509_pop_free(chain, X509_free); return NGX_ERROR; } @@ -441,26 +454,211 @@ ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert, { ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "X509_set_ex_data() failed"); X509_free(x509); - BIO_free(bio); + sk_X509_pop_free(chain, X509_free); return NGX_ERROR; } - if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_certificate_index, x509) - == 0) - { + if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_certificate_index, x509) == 0) { ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "SSL_CTX_set_ex_data() failed"); X509_free(x509); - BIO_free(bio); + sk_X509_pop_free(chain, X509_free); return NGX_ERROR; } - /* read rest of the chain */ + /* + * Note that x509 is not freed here, but will be instead freed in + * ngx_ssl_cleanup_ctx(). This is because we need to preserve all + * certificates to be able to iterate all of them through exdata + * (ngx_ssl_certificate_index, ngx_ssl_next_certificate_index), + * while OpenSSL can free a certificate if it is replaced with another + * certificate of the same type. + */ + +#ifdef SSL_CTX_set0_chain + + if (SSL_CTX_set0_chain(ssl->ctx, chain) == 0) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "SSL_CTX_set0_chain(\"%s\") failed", cert->data); + sk_X509_pop_free(chain, X509_free); + return NGX_ERROR; + } + +#else + { + int n; + + /* SSL_CTX_set0_chain() is only available in OpenSSL 1.0.2+ */ + + n = sk_X509_num(chain); + + while (n--) { + x509 = sk_X509_shift(chain); + + if (SSL_CTX_add_extra_chain_cert(ssl->ctx, x509) == 0) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "SSL_CTX_add_extra_chain_cert(\"%s\") failed", + cert->data); + sk_X509_pop_free(chain, X509_free); + return NGX_ERROR; + } + } + + sk_X509_free(chain); + } +#endif + + pkey = ngx_ssl_load_certificate_key(cf->pool, &err, key, passwords); + if (pkey == NULL) { + if (err != NULL) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "cannot load certificate key \"%s\": %s", + key->data, err); + } + + return NGX_ERROR; + } + + if (SSL_CTX_use_PrivateKey(ssl->ctx, pkey) == 0) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "SSL_CTX_use_PrivateKey(\"%s\") failed", key->data); + EVP_PKEY_free(pkey); + return NGX_ERROR; + } + + EVP_PKEY_free(pkey); + + return NGX_OK; +} + + +ngx_int_t +ngx_ssl_connection_certificate(ngx_connection_t *c, ngx_pool_t *pool, + ngx_str_t *cert, ngx_str_t *key, ngx_array_t *passwords) +{ + char *err; + X509 *x509; + EVP_PKEY *pkey; + STACK_OF(X509) *chain; + + x509 = ngx_ssl_load_certificate(pool, &err, cert, &chain); + if (x509 == NULL) { + if (err != NULL) { + ngx_ssl_error(NGX_LOG_ERR, c->log, 0, + "cannot load certificate \"%s\": %s", + cert->data, err); + } + + return NGX_ERROR; + } + + if (SSL_use_certificate(c->ssl->connection, x509) == 0) { + ngx_ssl_error(NGX_LOG_ERR, c->log, 0, + "SSL_use_certificate(\"%s\") failed", cert->data); + X509_free(x509); + sk_X509_pop_free(chain, X509_free); + return NGX_ERROR; + } + + X509_free(x509); + +#ifdef SSL_set0_chain + + /* + * SSL_set0_chain() is only available in OpenSSL 1.0.2+, + * but this function is only called via certificate callback, + * which is only available in OpenSSL 1.0.2+ as well + */ + + if (SSL_set0_chain(c->ssl->connection, chain) == 0) { + ngx_ssl_error(NGX_LOG_ERR, c->log, 0, + "SSL_set0_chain(\"%s\") failed", cert->data); + sk_X509_pop_free(chain, X509_free); + return NGX_ERROR; + } + +#endif + + pkey = ngx_ssl_load_certificate_key(pool, &err, key, passwords); + if (pkey == NULL) { + if (err != NULL) { + ngx_ssl_error(NGX_LOG_ERR, c->log, 0, + "cannot load certificate key \"%s\": %s", + key->data, err); + } + + return NGX_ERROR; + } + + if (SSL_use_PrivateKey(c->ssl->connection, pkey) == 0) { + ngx_ssl_error(NGX_LOG_ERR, c->log, 0, + "SSL_use_PrivateKey(\"%s\") failed", key->data); + EVP_PKEY_free(pkey); + return NGX_ERROR; + } + + EVP_PKEY_free(pkey); + + return NGX_OK; +} + + +static X509 * +ngx_ssl_load_certificate(ngx_pool_t *pool, char **err, ngx_str_t *cert, + STACK_OF(X509) **chain) +{ + BIO *bio; + X509 *x509, *temp; + u_long n; + + if (ngx_strncmp(cert->data, "data:", sizeof("data:") - 1) == 0) { + + bio = BIO_new_mem_buf(cert->data + sizeof("data:") - 1, + cert->len - (sizeof("data:") - 1)); + if (bio == NULL) { + *err = "BIO_new_mem_buf() failed"; + return NULL; + } + + } else { + + if (ngx_get_full_name(pool, (ngx_str_t *) &ngx_cycle->conf_prefix, cert) + != NGX_OK) + { + *err = NULL; + return NULL; + } + + bio = BIO_new_file((char *) cert->data, "r"); + if (bio == NULL) { + *err = "BIO_new_file() failed"; + return NULL; + } + } + + /* certificate itself */ + + x509 = PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL); + if (x509 == NULL) { + *err = "PEM_read_bio_X509_AUX() failed"; + BIO_free(bio); + return NULL; + } + + /* rest of the chain */ + + *chain = sk_X509_new_null(); + if (*chain == NULL) { + *err = "sk_X509_new_null() failed"; + BIO_free(bio); + X509_free(x509); + return NULL; + } for ( ;; ) { - x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL); - if (x509 == NULL) { + temp = PEM_read_bio_X509(bio, NULL, NULL, NULL); + if (temp == NULL) { n = ERR_peek_last_error(); if (ERR_GET_LIB(n) == ERR_LIB_PEM @@ -473,58 +671,51 @@ ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert, /* some real error */ - ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, - "PEM_read_bio_X509(\"%s\") failed", cert->data); + *err = "PEM_read_bio_X509() failed"; BIO_free(bio); - return NGX_ERROR; - } - -#ifdef SSL_CTRL_CHAIN_CERT - - /* - * SSL_CTX_add0_chain_cert() is needed to add chain to - * a particular certificate when multiple certificates are used; - * only available in OpenSSL 1.0.2+ - */ - - if (SSL_CTX_add0_chain_cert(ssl->ctx, x509) == 0) { - ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, - "SSL_CTX_add0_chain_cert(\"%s\") failed", - cert->data); X509_free(x509); - BIO_free(bio); - return NGX_ERROR; + sk_X509_pop_free(*chain, X509_free); + return NULL; } -#else - if (SSL_CTX_add_extra_chain_cert(ssl->ctx, x509) == 0) { - ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, - "SSL_CTX_add_extra_chain_cert(\"%s\") failed", - cert->data); - X509_free(x509); + if (sk_X509_push(*chain, temp) == 0) { + *err = "sk_X509_push() failed"; BIO_free(bio); - return NGX_ERROR; + X509_free(x509); + sk_X509_pop_free(*chain, X509_free); + return NULL; } -#endif } BIO_free(bio); + return x509; +} + + +static EVP_PKEY * +ngx_ssl_load_certificate_key(ngx_pool_t *pool, char **err, + ngx_str_t *key, ngx_array_t *passwords) +{ + BIO *bio; + EVP_PKEY *pkey; + ngx_str_t *pwd; + ngx_uint_t tries; + pem_password_cb *cb; + if (ngx_strncmp(key->data, "engine:", sizeof("engine:") - 1) == 0) { #ifndef OPENSSL_NO_ENGINE - u_char *p, *last; - ENGINE *engine; - EVP_PKEY *pkey; + u_char *p, *last; + ENGINE *engine; p = key->data + sizeof("engine:") - 1; last = (u_char *) ngx_strchr(p, ':'); if (last == NULL) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid syntax in \"%V\"", key); - return NGX_ERROR; + *err = "invalid syntax"; + return NULL; } *last = '\0'; @@ -532,9 +723,8 @@ ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert, engine = ENGINE_by_id((char *) p); if (engine == NULL) { - ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, - "ENGINE_by_id(\"%s\") failed", p); - return NGX_ERROR; + *err = "ENGINE_by_id() failed"; + return NULL; } *last++ = ':'; @@ -542,76 +732,81 @@ ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert, pkey = ENGINE_load_private_key(engine, (char *) last, 0, 0); if (pkey == NULL) { - ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, - "ENGINE_load_private_key(\"%s\") failed", last); + *err = "ENGINE_load_private_key() failed"; ENGINE_free(engine); - return NGX_ERROR; + return NULL; } ENGINE_free(engine); - if (SSL_CTX_use_PrivateKey(ssl->ctx, pkey) == 0) { - ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, - "SSL_CTX_use_PrivateKey(\"%s\") failed", last); - EVP_PKEY_free(pkey); - return NGX_ERROR; - } - - EVP_PKEY_free(pkey); - - return NGX_OK; + return pkey; #else - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "loading \"engine:...\" certificate keys " - "is not supported"); - return NGX_ERROR; + *err = "loading \"engine:...\" certificate keys is not supported"; + return NULL; #endif } - if (ngx_conf_full_name(cf->cycle, key, 1) != NGX_OK) { - return NGX_ERROR; + if (ngx_strncmp(key->data, "data:", sizeof("data:") - 1) == 0) { + + bio = BIO_new_mem_buf(key->data + sizeof("data:") - 1, + key->len - (sizeof("data:") - 1)); + if (bio == NULL) { + *err = "BIO_new_mem_buf() failed"; + return NULL; + } + + } else { + + if (ngx_get_full_name(pool, (ngx_str_t *) &ngx_cycle->conf_prefix, key) + != NGX_OK) + { + *err = NULL; + return NULL; + } + + bio = BIO_new_file((char *) key->data, "r"); + if (bio == NULL) { + *err = "BIO_new_file() failed"; + return NULL; + } } if (passwords) { tries = passwords->nelts; pwd = passwords->elts; - - SSL_CTX_set_default_passwd_cb(ssl->ctx, ngx_ssl_password_callback); - SSL_CTX_set_default_passwd_cb_userdata(ssl->ctx, pwd); + cb = ngx_ssl_password_callback; } else { tries = 1; -#if (NGX_SUPPRESS_WARN) pwd = NULL; -#endif + cb = NULL; } for ( ;; ) { - if (SSL_CTX_use_PrivateKey_file(ssl->ctx, (char *) key->data, - SSL_FILETYPE_PEM) - != 0) - { + pkey = PEM_read_bio_PrivateKey(bio, NULL, cb, pwd); + if (pkey != NULL) { break; } - if (--tries) { + if (tries-- > 1) { ERR_clear_error(); - SSL_CTX_set_default_passwd_cb_userdata(ssl->ctx, ++pwd); + (void) BIO_reset(bio); + pwd++; continue; } - ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, - "SSL_CTX_use_PrivateKey_file(\"%s\") failed", key->data); - return NGX_ERROR; + *err = "PEM_read_bio_PrivateKey() failed"; + BIO_free(bio); + return NULL; } - SSL_CTX_set_default_passwd_cb(ssl->ctx, NULL); + BIO_free(bio); - return NGX_OK; + return pkey; } @@ -626,6 +821,10 @@ ngx_ssl_password_callback(char *buf, int size, int rwflag, void *userdata) return 0; } + if (pwd == NULL) { + return 0; + } + if (pwd->len > (size_t) size) { ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "password is truncated to %d bytes", size); @@ -847,6 +1046,8 @@ ngx_ssl_info_callback(const ngx_ssl_conn_t *ssl_conn, int where, int ret) BIO *rbio, *wbio; ngx_connection_t *c; +#ifndef SSL_OP_NO_RENEGOTIATION + if ((where & SSL_CB_HANDSHAKE_START) && SSL_is_server((ngx_ssl_conn_t *) ssl_conn)) { @@ -858,6 +1059,8 @@ ngx_ssl_info_callback(const ngx_ssl_conn_t *ssl_conn, int where, int ret) } } +#endif + if ((where & SSL_CB_ACCEPT_LOOP) == SSL_CB_ACCEPT_LOOP) { c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn); @@ -923,10 +1126,13 @@ ngx_ssl_read_password_file(ngx_conf_t *cf, ngx_str_t *file) return NULL; } - cln = ngx_pool_cleanup_add(cf->temp_pool, 0); passwords = ngx_array_create(cf->temp_pool, 4, sizeof(ngx_str_t)); + if (passwords == NULL) { + return NULL; + } - if (cln == NULL || passwords == NULL) { + cln = ngx_pool_cleanup_add(cf->temp_pool, 0); + if (cln == NULL) { return NULL; } @@ -1028,12 +1234,75 @@ cleanup: ngx_close_file_n " \"%s\" failed", file->data); } - ngx_memzero(buf, NGX_SSL_PASSWORD_BUFFER_SIZE); + ngx_explicit_memzero(buf, NGX_SSL_PASSWORD_BUFFER_SIZE); return passwords; } +ngx_array_t * +ngx_ssl_preserve_passwords(ngx_conf_t *cf, ngx_array_t *passwords) +{ + ngx_str_t *opwd, *pwd; + ngx_uint_t i; + ngx_array_t *pwds; + ngx_pool_cleanup_t *cln; + static ngx_array_t empty_passwords; + + if (passwords == NULL) { + + /* + * If there are no passwords, an empty array is used + * to make sure OpenSSL's default password callback + * won't block on reading from stdin. + */ + + return &empty_passwords; + } + + /* + * Passwords are normally allocated from the temporary pool + * and cleared after parsing configuration. To be used at + * runtime they have to be copied to the configuration pool. + */ + + pwds = ngx_array_create(cf->pool, passwords->nelts, sizeof(ngx_str_t)); + if (pwds == NULL) { + return NULL; + } + + cln = ngx_pool_cleanup_add(cf->pool, 0); + if (cln == NULL) { + return NULL; + } + + cln->handler = ngx_ssl_passwords_cleanup; + cln->data = pwds; + + opwd = passwords->elts; + + for (i = 0; i < passwords->nelts; i++) { + + pwd = ngx_array_push(pwds); + if (pwd == NULL) { + return NULL; + } + + pwd->len = opwd[i].len; + pwd->data = ngx_pnalloc(cf->pool, pwd->len); + + if (pwd->data == NULL) { + pwds->nelts--; + return NULL; + } + + ngx_memcpy(pwd->data, opwd[i].data, opwd[i].len); + } + + return pwds; +} + + static void ngx_ssl_passwords_cleanup(void *data) { @@ -1045,7 +1314,7 @@ ngx_ssl_passwords_cleanup(void *data) pwd = passwords->elts; for (i = 0; i < passwords->nelts; i++) { - ngx_memzero(pwd[i].data, pwd[i].len); + ngx_explicit_memzero(pwd[i].data, pwd[i].len); } } @@ -1172,6 +1441,71 @@ ngx_ssl_ecdh_curve(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *name) } +ngx_int_t +ngx_ssl_early_data(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_uint_t enable) +{ + if (!enable) { + return NGX_OK; + } + +#ifdef SSL_ERROR_EARLY_DATA_REJECTED + + /* BoringSSL */ + + SSL_CTX_set_early_data_enabled(ssl->ctx, 1); + +#elif defined SSL_READ_EARLY_DATA_SUCCESS + + /* OpenSSL */ + + SSL_CTX_set_max_early_data(ssl->ctx, NGX_SSL_BUFSIZE); + +#else + ngx_log_error(NGX_LOG_WARN, ssl->log, 0, + "\"ssl_early_data\" is not supported on this platform, " + "ignored"); +#endif + + return NGX_OK; +} + + +ngx_int_t +ngx_ssl_client_session_cache(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_uint_t enable) +{ + if (!enable) { + return NGX_OK; + } + + SSL_CTX_set_session_cache_mode(ssl->ctx, + SSL_SESS_CACHE_CLIENT + |SSL_SESS_CACHE_NO_INTERNAL); + + SSL_CTX_sess_set_new_cb(ssl->ctx, ngx_ssl_new_client_session); + + return NGX_OK; +} + + +static int +ngx_ssl_new_client_session(ngx_ssl_conn_t *ssl_conn, ngx_ssl_session_t *sess) +{ + ngx_connection_t *c; + + c = ngx_ssl_get_connection(ssl_conn); + + if (c->ssl->save_session) { + c->ssl->session = sess; + + c->ssl->save_session(c); + + c->ssl->session = NULL; + } + + return 0; +} + + ngx_int_t ngx_ssl_create_connection(ngx_ssl_t *ssl, ngx_connection_t *c, ngx_uint_t flags) { @@ -1187,6 +1521,12 @@ ngx_ssl_create_connection(ngx_ssl_t *ssl, ngx_connection_t *c, ngx_uint_t flags) sc->session_ctx = ssl->ctx; +#ifdef SSL_READ_EARLY_DATA_SUCCESS + if (SSL_CTX_get_max_early_data(ssl->ctx)) { + sc->try_early_data = 1; + } +#endif + sc->connection = SSL_new(ssl->ctx); if (sc->connection == NULL) { @@ -1204,6 +1544,10 @@ ngx_ssl_create_connection(ngx_ssl_t *ssl, ngx_connection_t *c, ngx_uint_t flags) } else { SSL_set_accept_state(sc->connection); + +#ifdef SSL_OP_NO_RENEGOTIATION + SSL_set_options(sc->connection, SSL_OP_NO_RENEGOTIATION); +#endif } if (SSL_set_ex_data(sc->connection, ngx_ssl_connection_index, c) == 0) { @@ -1217,6 +1561,31 @@ ngx_ssl_create_connection(ngx_ssl_t *ssl, ngx_connection_t *c, ngx_uint_t flags) } +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); +} + + +ngx_ssl_session_t * +ngx_ssl_get0_session(ngx_connection_t *c) +{ + if (c->ssl->session) { + return c->ssl->session; + } + + return SSL_get0_session(c->ssl->connection); +} + + ngx_int_t ngx_ssl_set_session(ngx_connection_t *c, ngx_ssl_session_t *session) { @@ -1237,6 +1606,12 @@ ngx_ssl_handshake(ngx_connection_t *c) int n, sslerr; ngx_err_t err; +#ifdef SSL_READ_EARLY_DATA_SUCCESS + if (c->ssl->try_early_data) { + return ngx_ssl_try_early_data(c); + } +#endif + ngx_ssl_clear_error(c->log); n = SSL_do_handshake(c->ssl->connection); @@ -1254,50 +1629,7 @@ ngx_ssl_handshake(ngx_connection_t *c) } #if (NGX_DEBUG) - { - char buf[129], *s, *d; -#if OPENSSL_VERSION_NUMBER >= 0x10000000L - const -#endif - SSL_CIPHER *cipher; - - cipher = SSL_get_current_cipher(c->ssl->connection); - - if (cipher) { - SSL_CIPHER_description(cipher, &buf[1], 128); - - for (s = &buf[1], d = buf; *s; s++) { - if (*s == ' ' && *d == ' ') { - continue; - } - - if (*s == LF || *s == CR) { - continue; - } - - *++d = *s; - } - - if (*d != ' ') { - d++; - } - - *d = '\0'; - - ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, - "SSL: %s, cipher: \"%s\"", - SSL_get_version(c->ssl->connection), &buf[1]); - - if (SSL_session_reused(c->ssl->connection)) { - ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, - "SSL reused session"); - } - - } else { - ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, - "SSL no shared ciphers"); - } - } + ngx_ssl_handshake_log(c); #endif c->ssl->handshaked = 1; @@ -1307,6 +1639,7 @@ ngx_ssl_handshake(ngx_connection_t *c) c->recv_chain = ngx_ssl_recv_chain; c->send_chain = ngx_ssl_send_chain; +#ifndef SSL_OP_NO_RENEGOTIATION #if OPENSSL_VERSION_NUMBER < 0x10100000L #ifdef SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS @@ -1315,6 +1648,7 @@ ngx_ssl_handshake(ngx_connection_t *c) c->ssl->connection->s3->flags |= SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS; } +#endif #endif #endif @@ -1378,6 +1712,173 @@ ngx_ssl_handshake(ngx_connection_t *c) } +#ifdef SSL_READ_EARLY_DATA_SUCCESS + +static ngx_int_t +ngx_ssl_try_early_data(ngx_connection_t *c) +{ + int n, sslerr; + u_char buf; + size_t readbytes; + ngx_err_t err; + + ngx_ssl_clear_error(c->log); + + readbytes = 0; + + n = SSL_read_early_data(c->ssl->connection, &buf, 1, &readbytes); + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "SSL_read_early_data: %d, %uz", n, readbytes); + + if (n == SSL_READ_EARLY_DATA_FINISH) { + c->ssl->try_early_data = 0; + return ngx_ssl_handshake(c); + } + + if (n == SSL_READ_EARLY_DATA_SUCCESS) { + + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + return NGX_ERROR; + } + + if (ngx_handle_write_event(c->write, 0) != NGX_OK) { + return NGX_ERROR; + } + +#if (NGX_DEBUG) + ngx_ssl_handshake_log(c); +#endif + + c->ssl->try_early_data = 0; + + c->ssl->early_buf = buf; + c->ssl->early_preread = 1; + + c->ssl->handshaked = 1; + c->ssl->in_early = 1; + + c->recv = ngx_ssl_recv; + c->send = ngx_ssl_write; + c->recv_chain = ngx_ssl_recv_chain; + c->send_chain = ngx_ssl_send_chain; + + return NGX_OK; + } + + /* SSL_READ_EARLY_DATA_ERROR */ + + sslerr = SSL_get_error(c->ssl->connection, n); + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_get_error: %d", sslerr); + + if (sslerr == SSL_ERROR_WANT_READ) { + c->read->ready = 0; + c->read->handler = ngx_ssl_handshake_handler; + c->write->handler = ngx_ssl_handshake_handler; + + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + return NGX_ERROR; + } + + if (ngx_handle_write_event(c->write, 0) != NGX_OK) { + return NGX_ERROR; + } + + return NGX_AGAIN; + } + + if (sslerr == SSL_ERROR_WANT_WRITE) { + c->write->ready = 0; + c->read->handler = ngx_ssl_handshake_handler; + c->write->handler = ngx_ssl_handshake_handler; + + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + return NGX_ERROR; + } + + if (ngx_handle_write_event(c->write, 0) != NGX_OK) { + return NGX_ERROR; + } + + return NGX_AGAIN; + } + + err = (sslerr == SSL_ERROR_SYSCALL) ? ngx_errno : 0; + + c->ssl->no_wait_shutdown = 1; + c->ssl->no_send_shutdown = 1; + c->read->eof = 1; + + if (sslerr == SSL_ERROR_ZERO_RETURN || ERR_peek_error() == 0) { + ngx_connection_error(c, err, + "peer closed connection in SSL handshake"); + + return NGX_ERROR; + } + + c->read->error = 1; + + ngx_ssl_connection_error(c, sslerr, err, "SSL_read_early_data() failed"); + + return NGX_ERROR; +} + +#endif + + +#if (NGX_DEBUG) + +static void +ngx_ssl_handshake_log(ngx_connection_t *c) +{ + char buf[129], *s, *d; +#if OPENSSL_VERSION_NUMBER >= 0x10000000L + const +#endif + SSL_CIPHER *cipher; + + cipher = SSL_get_current_cipher(c->ssl->connection); + + if (cipher) { + SSL_CIPHER_description(cipher, &buf[1], 128); + + for (s = &buf[1], d = buf; *s; s++) { + if (*s == ' ' && *d == ' ') { + continue; + } + + if (*s == LF || *s == CR) { + continue; + } + + *++d = *s; + } + + if (*d != ' ') { + d++; + } + + *d = '\0'; + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "SSL: %s, cipher: \"%s\"", + SSL_get_version(c->ssl->connection), &buf[1]); + + if (SSL_session_reused(c->ssl->connection)) { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, + "SSL reused session"); + } + + } else { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, + "SSL no shared ciphers"); + } +} + +#endif + + static void ngx_ssl_handshake_handler(ngx_event_t *ev) { @@ -1465,6 +1966,12 @@ ngx_ssl_recv(ngx_connection_t *c, u_char *buf, size_t size) { int n, bytes; +#ifdef SSL_READ_EARLY_DATA_SUCCESS + if (c->ssl->in_early) { + return ngx_ssl_recv_early(c, buf, size); + } +#endif + if (c->ssl->last == NGX_ERROR) { c->read->error = 1; return NGX_ERROR; @@ -1538,12 +2045,135 @@ ngx_ssl_recv(ngx_connection_t *c, u_char *buf, size_t size) } +#ifdef SSL_READ_EARLY_DATA_SUCCESS + +static ssize_t +ngx_ssl_recv_early(ngx_connection_t *c, u_char *buf, size_t size) +{ + int n, bytes; + size_t readbytes; + + if (c->ssl->last == NGX_ERROR) { + c->read->error = 1; + return NGX_ERROR; + } + + if (c->ssl->last == NGX_DONE) { + c->read->ready = 0; + c->read->eof = 1; + return 0; + } + + bytes = 0; + + ngx_ssl_clear_error(c->log); + + if (c->ssl->early_preread) { + + if (size == 0) { + c->read->ready = 0; + c->read->eof = 1; + return 0; + } + + *buf = c->ssl->early_buf; + + c->ssl->early_preread = 0; + + bytes = 1; + size -= 1; + buf += 1; + } + + if (c->ssl->write_blocked) { + return NGX_AGAIN; + } + + /* + * SSL_read_early_data() may return data in parts, so try to read + * until SSL_read_early_data() would return no data + */ + + for ( ;; ) { + + readbytes = 0; + + n = SSL_read_early_data(c->ssl->connection, buf, size, &readbytes); + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "SSL_read_early_data: %d, %uz", n, readbytes); + + if (n == SSL_READ_EARLY_DATA_SUCCESS) { + + c->ssl->last = ngx_ssl_handle_recv(c, 1); + + bytes += readbytes; + size -= readbytes; + + if (size == 0) { + c->read->ready = 1; + return bytes; + } + + buf += readbytes; + + continue; + } + + if (n == SSL_READ_EARLY_DATA_FINISH) { + + c->ssl->last = ngx_ssl_handle_recv(c, 1); + c->ssl->in_early = 0; + + if (bytes) { + c->read->ready = 1; + return bytes; + } + + return ngx_ssl_recv(c, buf, size); + } + + /* SSL_READ_EARLY_DATA_ERROR */ + + c->ssl->last = ngx_ssl_handle_recv(c, 0); + + if (bytes) { + if (c->ssl->last != NGX_AGAIN) { + c->read->ready = 1; + } + + return bytes; + } + + switch (c->ssl->last) { + + case NGX_DONE: + c->read->ready = 0; + c->read->eof = 1; + return 0; + + case NGX_ERROR: + c->read->error = 1; + + /* fall through */ + + case NGX_AGAIN: + return c->ssl->last; + } + } +} + +#endif + + static ngx_int_t ngx_ssl_handle_recv(ngx_connection_t *c, int n) { int sslerr; ngx_err_t err; +#ifndef SSL_OP_NO_RENEGOTIATION + if (c->ssl->renegotiation) { /* * disable renegotiation (CVE-2009-3555): @@ -1566,6 +2196,8 @@ ngx_ssl_handle_recv(ngx_connection_t *c, int n) return NGX_ERROR; } +#endif + if (n > 0) { if (c->ssl->saved_write_handler) { @@ -1591,14 +2223,28 @@ ngx_ssl_handle_recv(ngx_connection_t *c, int n) ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_get_error: %d", sslerr); if (sslerr == SSL_ERROR_WANT_READ) { + + if (c->ssl->saved_write_handler) { + + c->write->handler = c->ssl->saved_write_handler; + c->ssl->saved_write_handler = NULL; + c->write->ready = 1; + + if (ngx_handle_write_event(c->write, 0) != NGX_OK) { + return NGX_ERROR; + } + + ngx_post_event(c->write, &ngx_posted_events); + } + c->read->ready = 0; return NGX_AGAIN; } if (sslerr == SSL_ERROR_WANT_WRITE) { - ngx_log_error(NGX_LOG_INFO, c->log, 0, - "peer started SSL renegotiation"); + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, + "SSL_read: want write"); c->write->ready = 0; @@ -1640,6 +2286,8 @@ ngx_ssl_write_handler(ngx_event_t *wev) c = wev->data; + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL write handler"); + c->read->handler(c->read); } @@ -1813,6 +2461,12 @@ ngx_ssl_write(ngx_connection_t *c, u_char *data, size_t size) int n, sslerr; ngx_err_t err; +#ifdef SSL_READ_EARLY_DATA_SUCCESS + if (c->ssl->in_early) { + return ngx_ssl_write_early(c, data, size); + } +#endif + ngx_ssl_clear_error(c->log); ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL to write: %uz", size); @@ -1848,14 +2502,28 @@ ngx_ssl_write(ngx_connection_t *c, u_char *data, size_t size) ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_get_error: %d", sslerr); if (sslerr == SSL_ERROR_WANT_WRITE) { + + if (c->ssl->saved_read_handler) { + + c->read->handler = c->ssl->saved_read_handler; + c->ssl->saved_read_handler = NULL; + c->read->ready = 1; + + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + return NGX_ERROR; + } + + ngx_post_event(c->read, &ngx_posted_events); + } + c->write->ready = 0; return NGX_AGAIN; } if (sslerr == SSL_ERROR_WANT_READ) { - ngx_log_error(NGX_LOG_INFO, c->log, 0, - "peer started SSL renegotiation"); + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, + "SSL_write: want read"); c->read->ready = 0; @@ -1886,6 +2554,123 @@ ngx_ssl_write(ngx_connection_t *c, u_char *data, size_t size) } +#ifdef SSL_READ_EARLY_DATA_SUCCESS + +ssize_t +ngx_ssl_write_early(ngx_connection_t *c, u_char *data, size_t size) +{ + int n, sslerr; + size_t written; + ngx_err_t err; + + ngx_ssl_clear_error(c->log); + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL to write: %uz", size); + + written = 0; + + n = SSL_write_early_data(c->ssl->connection, data, size, &written); + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "SSL_write_early_data: %d, %uz", n, written); + + if (n > 0) { + + if (c->ssl->saved_read_handler) { + + c->read->handler = c->ssl->saved_read_handler; + c->ssl->saved_read_handler = NULL; + c->read->ready = 1; + + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + return NGX_ERROR; + } + + ngx_post_event(c->read, &ngx_posted_events); + } + + if (c->ssl->write_blocked) { + c->ssl->write_blocked = 0; + ngx_post_event(c->read, &ngx_posted_events); + } + + c->sent += written; + + return written; + } + + sslerr = SSL_get_error(c->ssl->connection, n); + + err = (sslerr == SSL_ERROR_SYSCALL) ? ngx_errno : 0; + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_get_error: %d", sslerr); + + if (sslerr == SSL_ERROR_WANT_WRITE) { + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, + "SSL_write_early_data: want write"); + + if (c->ssl->saved_read_handler) { + + c->read->handler = c->ssl->saved_read_handler; + c->ssl->saved_read_handler = NULL; + c->read->ready = 1; + + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + return NGX_ERROR; + } + + ngx_post_event(c->read, &ngx_posted_events); + } + + /* + * OpenSSL 1.1.1a fails to handle SSL_read_early_data() + * if an SSL_write_early_data() call blocked on writing, + * see https://github.com/openssl/openssl/issues/7757 + */ + + c->ssl->write_blocked = 1; + + c->write->ready = 0; + return NGX_AGAIN; + } + + if (sslerr == SSL_ERROR_WANT_READ) { + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, + "SSL_write_early_data: want read"); + + c->read->ready = 0; + + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + return NGX_ERROR; + } + + /* + * we do not set the timer because there is already + * the write event timer + */ + + if (c->ssl->saved_read_handler == NULL) { + c->ssl->saved_read_handler = c->read->handler; + c->read->handler = ngx_ssl_read_handler; + } + + return NGX_AGAIN; + } + + c->ssl->no_wait_shutdown = 1; + c->ssl->no_send_shutdown = 1; + c->write->error = 1; + + ngx_ssl_connection_error(c, sslerr, err, "SSL_write_early_data() failed"); + + return NGX_ERROR; +} + +#endif + + static void ngx_ssl_read_handler(ngx_event_t *rev) { @@ -1893,6 +2678,8 @@ ngx_ssl_read_handler(ngx_event_t *rev) c = rev->data; + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL read handler"); + c->write->handler(c->write); } @@ -2089,8 +2876,14 @@ ngx_ssl_connection_error(ngx_connection_t *c, int sslerr, ngx_err_t err, || n == SSL_R_NO_COMPRESSION_SPECIFIED /* 187 */ || n == SSL_R_NO_SHARED_CIPHER /* 193 */ || n == SSL_R_RECORD_LENGTH_MISMATCH /* 213 */ +#ifdef SSL_R_CLIENTHELLO_TLSEXT + || n == SSL_R_CLIENTHELLO_TLSEXT /* 226 */ +#endif #ifdef SSL_R_PARSE_TLSEXT || n == SSL_R_PARSE_TLSEXT /* 227 */ +#endif +#ifdef SSL_R_CALLBACK_FAILED + || n == SSL_R_CALLBACK_FAILED /* 234 */ #endif || n == SSL_R_UNEXPECTED_MESSAGE /* 244 */ || n == SSL_R_UNEXPECTED_RECORD /* 245 */ @@ -2119,6 +2912,9 @@ ngx_ssl_connection_error(ngx_connection_t *c, int sslerr, ngx_err_t err, #ifdef SSL_R_INAPPROPRIATE_FALLBACK || n == SSL_R_INAPPROPRIATE_FALLBACK /* 373 */ #endif +#ifdef SSL_R_CERT_CB_ERROR + || n == SSL_R_CERT_CB_ERROR /* 377 */ +#endif #ifdef SSL_R_VERSION_TOO_LOW || n == SSL_R_VERSION_TOO_LOW /* 396 */ #endif @@ -2198,53 +2994,60 @@ ngx_ssl_error(ngx_uint_t level, ngx_log_t *log, ngx_err_t err, char *fmt, ...) p = ngx_vslprintf(errstr, last - 1, fmt, args); va_end(args); - p = ngx_cpystrn(p, (u_char *) " (SSL:", last - p); + if (ERR_peek_error()) { + p = ngx_cpystrn(p, (u_char *) " (SSL:", last - p); - for ( ;; ) { + for ( ;; ) { - n = ERR_peek_error_line_data(NULL, NULL, &data, &flags); + n = ERR_peek_error_line_data(NULL, NULL, &data, &flags); - if (n == 0) { - break; + if (n == 0) { + break; + } + + /* ERR_error_string_n() requires at least one byte */ + + if (p >= last - 1) { + goto next; + } + + *p++ = ' '; + + ERR_error_string_n(n, (char *) p, last - p); + + while (p < last && *p) { + p++; + } + + if (p < last && *data && (flags & ERR_TXT_STRING)) { + *p++ = ':'; + p = ngx_cpystrn(p, (u_char *) data, last - p); + } + + next: + + (void) ERR_get_error(); } - /* ERR_error_string_n() requires at least one byte */ - - if (p >= last - 1) { - goto next; + if (p < last) { + *p++ = ')'; } - - *p++ = ' '; - - ERR_error_string_n(n, (char *) p, last - p); - - while (p < last && *p) { - p++; - } - - if (p < last && *data && (flags & ERR_TXT_STRING)) { - *p++ = ':'; - p = ngx_cpystrn(p, (u_char *) data, last - p); - } - - next: - - (void) ERR_get_error(); } - ngx_log_error(level, log, err, "%*s)", p - errstr, errstr); + ngx_log_error(level, log, err, "%*s", p - errstr, errstr); } ngx_int_t ngx_ssl_session_cache(ngx_ssl_t *ssl, ngx_str_t *sess_ctx, - ssize_t builtin_session_cache, ngx_shm_zone_t *shm_zone, time_t timeout) + ngx_array_t *certificates, ssize_t builtin_session_cache, + ngx_shm_zone_t *shm_zone, time_t timeout) { long cache_mode; SSL_CTX_set_timeout(ssl->ctx, (long) timeout); - if (ngx_ssl_session_id_context(ssl, sess_ctx) != NGX_OK) { + if (ngx_ssl_session_id_context(ssl, sess_ctx, certificates) != NGX_OK) { return NGX_ERROR; } @@ -2310,11 +3113,14 @@ ngx_ssl_session_cache(ngx_ssl_t *ssl, ngx_str_t *sess_ctx, static ngx_int_t -ngx_ssl_session_id_context(ngx_ssl_t *ssl, ngx_str_t *sess_ctx) +ngx_ssl_session_id_context(ngx_ssl_t *ssl, ngx_str_t *sess_ctx, + ngx_array_t *certificates) { int n, i; X509 *cert; X509_NAME *name; + ngx_str_t *certs; + ngx_uint_t k; EVP_MD_CTX *md; unsigned int len; STACK_OF(X509_NAME) *list; @@ -2359,6 +3165,24 @@ ngx_ssl_session_id_context(ngx_ssl_t *ssl, ngx_str_t *sess_ctx) } } + if (SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_certificate_index) == NULL) { + + /* + * If certificates are loaded dynamically, we use certificate + * names as specified in the configuration (with variables). + */ + + certs = certificates->elts; + for (k = 0; k < certificates->nelts; k++) { + + if (EVP_DigestUpdate(md, certs[k].data, certs[k].len) == 0) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "EVP_DigestUpdate() failed"); + goto failed; + } + } + } + list = SSL_CTX_get_client_CA_list(ssl->ctx); if (list != NULL) { @@ -2383,7 +3207,7 @@ ngx_ssl_session_id_context(ngx_ssl_t *ssl, ngx_str_t *sess_ctx) if (EVP_DigestFinal_ex(md, buf, &len) == 0) { ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, - "EVP_DigestUpdate() failed"); + "EVP_DigestFinal_ex() failed"); goto failed; } @@ -2630,6 +3454,7 @@ ngx_ssl_get_cached_session(ngx_ssl_conn_t *ssl_conn, const #endif u_char *p; + size_t slen; uint32_t hash; ngx_int_t rc; ngx_shm_zone_t *shm_zone; @@ -2685,12 +3510,14 @@ ngx_ssl_get_cached_session(ngx_ssl_conn_t *ssl_conn, if (rc == 0) { if (sess_id->expire > ngx_time()) { - ngx_memcpy(buf, sess_id->session, sess_id->len); + slen = sess_id->len; + + ngx_memcpy(buf, sess_id->session, slen); ngx_shmtx_unlock(&shpool->mutex); p = buf; - sess = d2i_SSL_SESSION(NULL, &p, sess_id->len); + sess = d2i_SSL_SESSION(NULL, &p, slen); return sess; } @@ -2911,6 +3738,7 @@ ngx_ssl_session_ticket_keys(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_array_t *paths) ngx_uint_t i; ngx_array_t *keys; ngx_file_info_t fi; + ngx_pool_cleanup_t *cln; ngx_ssl_session_ticket_key_t *key; if (paths == NULL) { @@ -2923,6 +3751,14 @@ ngx_ssl_session_ticket_keys(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_array_t *paths) return NGX_ERROR; } + cln = ngx_pool_cleanup_add(cf->pool, 0); + if (cln == NULL) { + return NGX_ERROR; + } + + cln->handler = ngx_ssl_session_ticket_keys_cleanup; + cln->data = keys; + path = paths->elts; for (i = 0; i < paths->nelts; i++) { @@ -2994,6 +3830,8 @@ ngx_ssl_session_ticket_keys(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_array_t *paths) ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, ngx_close_file_n " \"%V\" failed", &file.name); } + + ngx_explicit_memzero(&buf, 80); } if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_session_ticket_keys_index, keys) @@ -3024,6 +3862,8 @@ failed: ngx_close_file_n " \"%V\" failed", &file.name); } + ngx_explicit_memzero(&buf, 80); + return NGX_ERROR; } @@ -3152,6 +3992,16 @@ ngx_ssl_session_ticket_key_callback(ngx_ssl_conn_t *ssl_conn, } } + +static void +ngx_ssl_session_ticket_keys_cleanup(void *data) +{ + ngx_array_t *keys = data; + + ngx_explicit_memzero(keys->elts, + keys->nelts * sizeof(ngx_ssl_session_ticket_key_t)); +} + #else ngx_int_t @@ -3574,6 +4424,33 @@ ngx_ssl_get_session_reused(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) } +ngx_int_t +ngx_ssl_get_early_data(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) +{ + s->len = 0; + +#ifdef SSL_ERROR_EARLY_DATA_REJECTED + + /* BoringSSL */ + + if (SSL_in_early_data(c->ssl->connection)) { + ngx_str_set(s, "1"); + } + +#elif defined SSL_READ_EARLY_DATA_SUCCESS + + /* OpenSSL */ + + if (!SSL_is_init_finished(c->ssl->connection)) { + ngx_str_set(s, "1"); + } + +#endif + + return NGX_OK; +} + + ngx_int_t ngx_ssl_get_server_name(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) { @@ -3745,6 +4622,7 @@ ngx_ssl_get_subject_dn(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) name = X509_get_subject_name(cert); if (name == NULL) { + X509_free(cert); return NGX_ERROR; } @@ -3796,6 +4674,7 @@ ngx_ssl_get_issuer_dn(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) name = X509_get_issuer_name(cert); if (name == NULL) { + X509_free(cert); return NGX_ERROR; } diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h index 05d3291..61da0c5 100644 --- a/src/event/ngx_event_openssl.h +++ b/src/event/ngx_event_openssl.h @@ -81,15 +81,24 @@ struct ngx_ssl_connection_s { ngx_connection_handler_pt handler; + ngx_ssl_session_t *session; + ngx_connection_handler_pt save_session; + ngx_event_handler_pt saved_read_handler; ngx_event_handler_pt saved_write_handler; + u_char early_buf; + unsigned handshaked:1; unsigned renegotiation:1; unsigned buffer:1; unsigned no_wait_shutdown:1; unsigned no_send_shutdown:1; unsigned handshake_buffer_set:1; + unsigned try_early_data:1; + unsigned in_early:1; + unsigned early_preread:1; + unsigned write_blocked:1; }; @@ -152,10 +161,14 @@ typedef struct { ngx_int_t ngx_ssl_init(ngx_log_t *log); ngx_int_t ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_t protocols, void *data); + ngx_int_t ngx_ssl_certificates(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_array_t *certs, ngx_array_t *keys, ngx_array_t *passwords); ngx_int_t ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert, ngx_str_t *key, ngx_array_t *passwords); +ngx_int_t ngx_ssl_connection_certificate(ngx_connection_t *c, ngx_pool_t *pool, + ngx_str_t *cert, ngx_str_t *key, ngx_array_t *passwords); + ngx_int_t ngx_ssl_ciphers(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *ciphers, ngx_uint_t prefer_server_ciphers); ngx_int_t ngx_ssl_client_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, @@ -170,10 +183,17 @@ ngx_int_t ngx_ssl_stapling_resolver(ngx_conf_t *cf, ngx_ssl_t *ssl, RSA *ngx_ssl_rsa512_key_callback(ngx_ssl_conn_t *ssl_conn, int is_export, int key_length); ngx_array_t *ngx_ssl_read_password_file(ngx_conf_t *cf, ngx_str_t *file); +ngx_array_t *ngx_ssl_preserve_passwords(ngx_conf_t *cf, + ngx_array_t *passwords); ngx_int_t ngx_ssl_dhparam(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file); ngx_int_t ngx_ssl_ecdh_curve(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *name); +ngx_int_t ngx_ssl_early_data(ngx_conf_t *cf, ngx_ssl_t *ssl, + ngx_uint_t enable); +ngx_int_t ngx_ssl_client_session_cache(ngx_conf_t *cf, ngx_ssl_t *ssl, + ngx_uint_t enable); ngx_int_t ngx_ssl_session_cache(ngx_ssl_t *ssl, ngx_str_t *sess_ctx, - ssize_t builtin_session_cache, ngx_shm_zone_t *shm_zone, time_t timeout); + ngx_array_t *certificates, ssize_t builtin_session_cache, + ngx_shm_zone_t *shm_zone, time_t timeout); ngx_int_t ngx_ssl_session_ticket_keys(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_array_t *paths); ngx_int_t ngx_ssl_session_cache_init(ngx_shm_zone_t *shm_zone, void *data); @@ -182,7 +202,8 @@ ngx_int_t ngx_ssl_create_connection(ngx_ssl_t *ssl, ngx_connection_t *c, void ngx_ssl_remove_cached_session(SSL_CTX *ssl, ngx_ssl_session_t *sess); ngx_int_t ngx_ssl_set_session(ngx_connection_t *c, ngx_ssl_session_t *session); -#define ngx_ssl_get_session(c) SSL_get1_session(c->ssl->connection) +ngx_ssl_session_t *ngx_ssl_get_session(ngx_connection_t *c); +ngx_ssl_session_t *ngx_ssl_get0_session(ngx_connection_t *c); #define ngx_ssl_free_session SSL_SESSION_free #define ngx_ssl_get_connection(ssl_conn) \ SSL_get_ex_data(ssl_conn, ngx_ssl_connection_index) @@ -211,6 +232,8 @@ ngx_int_t ngx_ssl_get_session_id(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s); ngx_int_t ngx_ssl_get_session_reused(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s); +ngx_int_t ngx_ssl_get_early_data(ngx_connection_t *c, ngx_pool_t *pool, + ngx_str_t *s); ngx_int_t ngx_ssl_get_server_name(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s); ngx_int_t ngx_ssl_get_raw_certificate(ngx_connection_t *c, ngx_pool_t *pool, diff --git a/src/event/ngx_event_openssl_stapling.c b/src/event/ngx_event_openssl_stapling.c index 0bea5e7..c832aa0 100644 --- a/src/event/ngx_event_openssl_stapling.c +++ b/src/event/ngx_event_openssl_stapling.c @@ -227,7 +227,7 @@ ngx_ssl_stapling_file(ngx_conf_t *cf, ngx_ssl_t *ssl, return NGX_ERROR; } - bio = BIO_new_file((char *) file->data, "r"); + bio = BIO_new_file((char *) file->data, "rb"); if (bio == NULL) { ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "BIO_new_file(\"%s\") failed", file->data); @@ -511,6 +511,11 @@ ngx_ssl_certificate_status_callback(ngx_ssl_conn_t *ssl_conn, void *data) rc = SSL_TLSEXT_ERR_NOACK; cert = SSL_get_certificate(ssl_conn); + + if (cert == NULL) { + return rc; + } + staple = X509_get_ex_data(cert, ngx_ssl_stapling_index); if (staple == NULL) { diff --git a/src/event/ngx_event_udp.c b/src/event/ngx_event_udp.c new file mode 100644 index 0000000..5572830 --- /dev/null +++ b/src/event/ngx_event_udp.c @@ -0,0 +1,663 @@ + +/* + * Copyright (C) Roman Arutyunyan + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include + + +#if !(NGX_WIN32) + +struct ngx_udp_connection_s { + ngx_rbtree_node_t node; + ngx_connection_t *connection; + ngx_buf_t *buffer; +}; + + +static void ngx_close_accepted_udp_connection(ngx_connection_t *c); +static ssize_t ngx_udp_shared_recv(ngx_connection_t *c, u_char *buf, + size_t size); +static ngx_int_t ngx_insert_udp_connection(ngx_connection_t *c); +static ngx_connection_t *ngx_lookup_udp_connection(ngx_listening_t *ls, + struct sockaddr *sockaddr, socklen_t socklen, + struct sockaddr *local_sockaddr, socklen_t local_socklen); + + +void +ngx_event_recvmsg(ngx_event_t *ev) +{ + ssize_t n; + ngx_buf_t buf; + ngx_log_t *log; + ngx_err_t err; + socklen_t socklen, local_socklen; + ngx_event_t *rev, *wev; + struct iovec iov[1]; + struct msghdr msg; + ngx_sockaddr_t sa, lsa; + struct sockaddr *sockaddr, *local_sockaddr; + ngx_listening_t *ls; + ngx_event_conf_t *ecf; + ngx_connection_t *c, *lc; + static u_char buffer[65535]; + +#if (NGX_HAVE_MSGHDR_MSG_CONTROL) + +#if (NGX_HAVE_IP_RECVDSTADDR) + u_char msg_control[CMSG_SPACE(sizeof(struct in_addr))]; +#elif (NGX_HAVE_IP_PKTINFO) + u_char msg_control[CMSG_SPACE(sizeof(struct in_pktinfo))]; +#endif + +#if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO) + u_char msg_control6[CMSG_SPACE(sizeof(struct in6_pktinfo))]; +#endif + +#endif + + if (ev->timedout) { + if (ngx_enable_accept_events((ngx_cycle_t *) ngx_cycle) != NGX_OK) { + return; + } + + ev->timedout = 0; + } + + ecf = ngx_event_get_conf(ngx_cycle->conf_ctx, ngx_event_core_module); + + if (!(ngx_event_flags & NGX_USE_KQUEUE_EVENT)) { + ev->available = ecf->multi_accept; + } + + lc = ev->data; + ls = lc->listening; + ev->ready = 0; + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0, + "recvmsg on %V, ready: %d", &ls->addr_text, ev->available); + + do { + ngx_memzero(&msg, sizeof(struct msghdr)); + + iov[0].iov_base = (void *) buffer; + iov[0].iov_len = sizeof(buffer); + + msg.msg_name = &sa; + msg.msg_namelen = sizeof(ngx_sockaddr_t); + msg.msg_iov = iov; + msg.msg_iovlen = 1; + +#if (NGX_HAVE_MSGHDR_MSG_CONTROL) + + if (ls->wildcard) { + +#if (NGX_HAVE_IP_RECVDSTADDR || NGX_HAVE_IP_PKTINFO) + if (ls->sockaddr->sa_family == AF_INET) { + msg.msg_control = &msg_control; + msg.msg_controllen = sizeof(msg_control); + } +#endif + +#if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO) + if (ls->sockaddr->sa_family == AF_INET6) { + msg.msg_control = &msg_control6; + msg.msg_controllen = sizeof(msg_control6); + } +#endif + } + +#endif + + n = recvmsg(lc->fd, &msg, 0); + + if (n == -1) { + err = ngx_socket_errno; + + if (err == NGX_EAGAIN) { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, err, + "recvmsg() not ready"); + return; + } + + ngx_log_error(NGX_LOG_ALERT, ev->log, err, "recvmsg() failed"); + + return; + } + +#if (NGX_HAVE_MSGHDR_MSG_CONTROL) + if (msg.msg_flags & (MSG_TRUNC|MSG_CTRUNC)) { + ngx_log_error(NGX_LOG_ALERT, ev->log, 0, + "recvmsg() truncated data"); + continue; + } +#endif + + sockaddr = msg.msg_name; + socklen = msg.msg_namelen; + + if (socklen > (socklen_t) sizeof(ngx_sockaddr_t)) { + socklen = sizeof(ngx_sockaddr_t); + } + + if (socklen == 0) { + + /* + * on Linux recvmsg() returns zero msg_namelen + * when receiving packets from unbound AF_UNIX sockets + */ + + socklen = sizeof(struct sockaddr); + ngx_memzero(&sa, sizeof(struct sockaddr)); + sa.sockaddr.sa_family = ls->sockaddr->sa_family; + } + + local_sockaddr = ls->sockaddr; + local_socklen = ls->socklen; + +#if (NGX_HAVE_MSGHDR_MSG_CONTROL) + + if (ls->wildcard) { + struct cmsghdr *cmsg; + + ngx_memcpy(&lsa, local_sockaddr, local_socklen); + local_sockaddr = &lsa.sockaddr; + + for (cmsg = CMSG_FIRSTHDR(&msg); + cmsg != NULL; + cmsg = CMSG_NXTHDR(&msg, cmsg)) + { + +#if (NGX_HAVE_IP_RECVDSTADDR) + + if (cmsg->cmsg_level == IPPROTO_IP + && cmsg->cmsg_type == IP_RECVDSTADDR + && local_sockaddr->sa_family == AF_INET) + { + struct in_addr *addr; + struct sockaddr_in *sin; + + addr = (struct in_addr *) CMSG_DATA(cmsg); + sin = (struct sockaddr_in *) local_sockaddr; + sin->sin_addr = *addr; + + break; + } + +#elif (NGX_HAVE_IP_PKTINFO) + + if (cmsg->cmsg_level == IPPROTO_IP + && cmsg->cmsg_type == IP_PKTINFO + && local_sockaddr->sa_family == AF_INET) + { + struct in_pktinfo *pkt; + struct sockaddr_in *sin; + + pkt = (struct in_pktinfo *) CMSG_DATA(cmsg); + sin = (struct sockaddr_in *) local_sockaddr; + sin->sin_addr = pkt->ipi_addr; + + break; + } + +#endif + +#if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO) + + if (cmsg->cmsg_level == IPPROTO_IPV6 + && cmsg->cmsg_type == IPV6_PKTINFO + && local_sockaddr->sa_family == AF_INET6) + { + struct in6_pktinfo *pkt6; + struct sockaddr_in6 *sin6; + + pkt6 = (struct in6_pktinfo *) CMSG_DATA(cmsg); + sin6 = (struct sockaddr_in6 *) local_sockaddr; + sin6->sin6_addr = pkt6->ipi6_addr; + + break; + } + +#endif + + } + } + +#endif + + c = ngx_lookup_udp_connection(ls, sockaddr, socklen, local_sockaddr, + local_socklen); + + if (c) { + +#if (NGX_DEBUG) + if (c->log->log_level & NGX_LOG_DEBUG_EVENT) { + ngx_log_handler_pt handler; + + handler = c->log->handler; + c->log->handler = NULL; + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "recvmsg: fd:%d n:%z", c->fd, n); + + c->log->handler = handler; + } +#endif + + ngx_memzero(&buf, sizeof(ngx_buf_t)); + + buf.pos = buffer; + buf.last = buffer + n; + + rev = c->read; + + c->udp->buffer = &buf; + + rev->ready = 1; + rev->active = 0; + + rev->handler(rev); + + if (c->udp) { + c->udp->buffer = NULL; + } + + rev->ready = 0; + rev->active = 1; + + goto next; + } + +#if (NGX_STAT_STUB) + (void) ngx_atomic_fetch_add(ngx_stat_accepted, 1); +#endif + + ngx_accept_disabled = ngx_cycle->connection_n / 8 + - ngx_cycle->free_connection_n; + + c = ngx_get_connection(lc->fd, ev->log); + if (c == NULL) { + return; + } + + c->shared = 1; + c->type = SOCK_DGRAM; + c->socklen = socklen; + +#if (NGX_STAT_STUB) + (void) ngx_atomic_fetch_add(ngx_stat_active, 1); +#endif + + c->pool = ngx_create_pool(ls->pool_size, ev->log); + if (c->pool == NULL) { + ngx_close_accepted_udp_connection(c); + return; + } + + c->sockaddr = ngx_palloc(c->pool, socklen); + if (c->sockaddr == NULL) { + ngx_close_accepted_udp_connection(c); + return; + } + + ngx_memcpy(c->sockaddr, sockaddr, socklen); + + log = ngx_palloc(c->pool, sizeof(ngx_log_t)); + if (log == NULL) { + ngx_close_accepted_udp_connection(c); + return; + } + + *log = ls->log; + + c->recv = ngx_udp_shared_recv; + c->send = ngx_udp_send; + c->send_chain = ngx_udp_send_chain; + + c->log = log; + c->pool->log = log; + c->listening = ls; + + if (local_sockaddr == &lsa.sockaddr) { + local_sockaddr = ngx_palloc(c->pool, local_socklen); + if (local_sockaddr == NULL) { + ngx_close_accepted_udp_connection(c); + return; + } + + ngx_memcpy(local_sockaddr, &lsa, local_socklen); + } + + c->local_sockaddr = local_sockaddr; + c->local_socklen = local_socklen; + + c->buffer = ngx_create_temp_buf(c->pool, n); + if (c->buffer == NULL) { + ngx_close_accepted_udp_connection(c); + return; + } + + c->buffer->last = ngx_cpymem(c->buffer->last, buffer, n); + + rev = c->read; + wev = c->write; + + rev->active = 1; + wev->ready = 1; + + rev->log = log; + wev->log = log; + + /* + * TODO: MT: - ngx_atomic_fetch_add() + * or protection by critical section or light mutex + * + * TODO: MP: - allocated in a shared memory + * - ngx_atomic_fetch_add() + * or protection by critical section or light mutex + */ + + c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1); + +#if (NGX_STAT_STUB) + (void) ngx_atomic_fetch_add(ngx_stat_handled, 1); +#endif + + if (ls->addr_ntop) { + c->addr_text.data = ngx_pnalloc(c->pool, ls->addr_text_max_len); + if (c->addr_text.data == NULL) { + ngx_close_accepted_udp_connection(c); + return; + } + + c->addr_text.len = ngx_sock_ntop(c->sockaddr, c->socklen, + c->addr_text.data, + ls->addr_text_max_len, 0); + if (c->addr_text.len == 0) { + ngx_close_accepted_udp_connection(c); + return; + } + } + +#if (NGX_DEBUG) + { + ngx_str_t addr; + u_char text[NGX_SOCKADDR_STRLEN]; + + ngx_debug_accepted_connection(ecf, c); + + if (log->log_level & NGX_LOG_DEBUG_EVENT) { + addr.data = text; + addr.len = ngx_sock_ntop(c->sockaddr, c->socklen, text, + NGX_SOCKADDR_STRLEN, 1); + + ngx_log_debug4(NGX_LOG_DEBUG_EVENT, log, 0, + "*%uA recvmsg: %V fd:%d n:%z", + c->number, &addr, c->fd, n); + } + + } +#endif + + if (ngx_insert_udp_connection(c) != NGX_OK) { + ngx_close_accepted_udp_connection(c); + return; + } + + log->data = NULL; + log->handler = NULL; + + ls->handler(c); + + next: + + if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { + ev->available -= n; + } + + } while (ev->available); +} + + +static void +ngx_close_accepted_udp_connection(ngx_connection_t *c) +{ + ngx_free_connection(c); + + c->fd = (ngx_socket_t) -1; + + if (c->pool) { + ngx_destroy_pool(c->pool); + } + +#if (NGX_STAT_STUB) + (void) ngx_atomic_fetch_add(ngx_stat_active, -1); +#endif +} + + +static ssize_t +ngx_udp_shared_recv(ngx_connection_t *c, u_char *buf, size_t size) +{ + ssize_t n; + ngx_buf_t *b; + + if (c->udp == NULL || c->udp->buffer == NULL) { + return NGX_AGAIN; + } + + b = c->udp->buffer; + + n = ngx_min(b->last - b->pos, (ssize_t) size); + + ngx_memcpy(buf, b->pos, n); + + c->udp->buffer = NULL; + + c->read->ready = 0; + c->read->active = 1; + + return n; +} + + +void +ngx_udp_rbtree_insert_value(ngx_rbtree_node_t *temp, + ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel) +{ + ngx_int_t rc; + ngx_connection_t *c, *ct; + ngx_rbtree_node_t **p; + ngx_udp_connection_t *udp, *udpt; + + for ( ;; ) { + + if (node->key < temp->key) { + + p = &temp->left; + + } else if (node->key > temp->key) { + + p = &temp->right; + + } else { /* node->key == temp->key */ + + udp = (ngx_udp_connection_t *) node; + c = udp->connection; + + udpt = (ngx_udp_connection_t *) temp; + ct = udpt->connection; + + rc = ngx_cmp_sockaddr(c->sockaddr, c->socklen, + ct->sockaddr, ct->socklen, 1); + + if (rc == 0 && c->listening->wildcard) { + rc = ngx_cmp_sockaddr(c->local_sockaddr, c->local_socklen, + ct->local_sockaddr, ct->local_socklen, 1); + } + + p = (rc < 0) ? &temp->left : &temp->right; + } + + if (*p == sentinel) { + break; + } + + temp = *p; + } + + *p = node; + node->parent = temp; + node->left = sentinel; + node->right = sentinel; + ngx_rbt_red(node); +} + + +static ngx_int_t +ngx_insert_udp_connection(ngx_connection_t *c) +{ + uint32_t hash; + ngx_pool_cleanup_t *cln; + ngx_udp_connection_t *udp; + + if (c->udp) { + return NGX_OK; + } + + udp = ngx_pcalloc(c->pool, sizeof(ngx_udp_connection_t)); + if (udp == NULL) { + return NGX_ERROR; + } + + udp->connection = c; + + ngx_crc32_init(hash); + ngx_crc32_update(&hash, (u_char *) c->sockaddr, c->socklen); + + if (c->listening->wildcard) { + ngx_crc32_update(&hash, (u_char *) c->local_sockaddr, c->local_socklen); + } + + ngx_crc32_final(hash); + + udp->node.key = hash; + + cln = ngx_pool_cleanup_add(c->pool, 0); + if (cln == NULL) { + return NGX_ERROR; + } + + cln->data = c; + cln->handler = ngx_delete_udp_connection; + + ngx_rbtree_insert(&c->listening->rbtree, &udp->node); + + c->udp = udp; + + return NGX_OK; +} + + +void +ngx_delete_udp_connection(void *data) +{ + ngx_connection_t *c = data; + + if (c->udp == NULL) { + return; + } + + ngx_rbtree_delete(&c->listening->rbtree, &c->udp->node); + + c->udp = NULL; +} + + +static ngx_connection_t * +ngx_lookup_udp_connection(ngx_listening_t *ls, struct sockaddr *sockaddr, + socklen_t socklen, struct sockaddr *local_sockaddr, socklen_t local_socklen) +{ + uint32_t hash; + ngx_int_t rc; + ngx_connection_t *c; + ngx_rbtree_node_t *node, *sentinel; + ngx_udp_connection_t *udp; + +#if (NGX_HAVE_UNIX_DOMAIN) + + if (sockaddr->sa_family == AF_UNIX) { + struct sockaddr_un *saun = (struct sockaddr_un *) sockaddr; + + if (socklen <= (socklen_t) offsetof(struct sockaddr_un, sun_path) + || saun->sun_path[0] == '\0') + { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0, + "unbound unix socket"); + return NULL; + } + } + +#endif + + node = ls->rbtree.root; + sentinel = ls->rbtree.sentinel; + + ngx_crc32_init(hash); + ngx_crc32_update(&hash, (u_char *) sockaddr, socklen); + + if (ls->wildcard) { + ngx_crc32_update(&hash, (u_char *) local_sockaddr, local_socklen); + } + + ngx_crc32_final(hash); + + while (node != sentinel) { + + if (hash < node->key) { + node = node->left; + continue; + } + + if (hash > node->key) { + node = node->right; + continue; + } + + /* hash == node->key */ + + udp = (ngx_udp_connection_t *) node; + + c = udp->connection; + + rc = ngx_cmp_sockaddr(sockaddr, socklen, + c->sockaddr, c->socklen, 1); + + if (rc == 0 && ls->wildcard) { + rc = ngx_cmp_sockaddr(local_sockaddr, local_socklen, + c->local_sockaddr, c->local_socklen, 1); + } + + if (rc == 0) { + return c; + } + + node = (rc < 0) ? node->left : node->right; + } + + return NULL; +} + +#else + +void +ngx_delete_udp_connection(void *data) +{ + return; +} + +#endif diff --git a/src/http/modules/ngx_http_autoindex_module.c b/src/http/modules/ngx_http_autoindex_module.c index 94b91db..082bcb5 100644 --- a/src/http/modules/ngx_http_autoindex_module.c +++ b/src/http/modules/ngx_http_autoindex_module.c @@ -186,8 +186,6 @@ ngx_http_autoindex_handler(ngx_http_request_t *r) return rc; } - /* NGX_DIR_MASK_LEN is lesser than NGX_HTTP_AUTOINDEX_PREALLOCATE */ - last = ngx_http_map_uri_to_path(r, &path, &root, NGX_HTTP_AUTOINDEX_PREALLOCATE); if (last == NULL) { @@ -436,7 +434,7 @@ ngx_http_autoindex_html(ngx_http_request_t *r, ngx_array_t *entries) { u_char *last, scale; off_t length; - size_t len, char_len, escape_html; + size_t len, entry_len, char_len, escape_html; ngx_tm_t tm; ngx_buf_t *b; ngx_int_t size; @@ -452,7 +450,7 @@ ngx_http_autoindex_html(ngx_http_request_t *r, ngx_array_t *entries) static u_char header[] = "" CRLF - "" CRLF + "" CRLF "

Index of " ; @@ -501,17 +499,23 @@ ngx_http_autoindex_html(ngx_http_request_t *r, ngx_array_t *entries) entry[i].utf_len = entry[i].name.len; } - len += sizeof("") - 1 - + entry[i].name.len - entry[i].utf_len - + entry[i].escape_html - + NGX_HTTP_AUTOINDEX_NAME_LEN + sizeof(">") - 2 - + sizeof("") - 1 - + sizeof(" 28-Sep-1970 12:00 ") - 1 - + 20 /* the file size */ - + 2; + entry_len = sizeof("") - 1 + + entry[i].name.len - entry[i].utf_len + + entry[i].escape_html + + NGX_HTTP_AUTOINDEX_NAME_LEN + sizeof(">") - 2 + + sizeof("") - 1 + + sizeof(" 28-Sep-1970 12:00 ") - 1 + + 20 /* the file size */ + + 2; + + if (len > NGX_MAX_SIZE_T_VALUE - entry_len) { + return NULL; + } + + len += entry_len; } b = ngx_create_temp_buf(r->pool, len); @@ -699,7 +703,7 @@ static ngx_buf_t * ngx_http_autoindex_json(ngx_http_request_t *r, ngx_array_t *entries, ngx_str_t *callback) { - size_t len; + size_t len, entry_len; ngx_buf_t *b; ngx_uint_t i; ngx_http_autoindex_entry_t *entry; @@ -716,15 +720,21 @@ ngx_http_autoindex_json(ngx_http_request_t *r, ngx_array_t *entries, entry[i].escape = ngx_escape_json(NULL, entry[i].name.data, entry[i].name.len); - len += sizeof("{ }," CRLF) - 1 - + sizeof("\"name\":\"\"") - 1 - + entry[i].name.len + entry[i].escape - + sizeof(", \"type\":\"directory\"") - 1 - + sizeof(", \"mtime\":\"Wed, 31 Dec 1986 10:00:00 GMT\"") - 1; + entry_len = sizeof("{ }," CRLF) - 1 + + sizeof("\"name\":\"\"") - 1 + + entry[i].name.len + entry[i].escape + + sizeof(", \"type\":\"directory\"") - 1 + + sizeof(", \"mtime\":\"Wed, 31 Dec 1986 10:00:00 GMT\"") - 1; if (entry[i].file) { - len += sizeof(", \"size\":") - 1 + NGX_OFF_T_LEN; + entry_len += sizeof(", \"size\":") - 1 + NGX_OFF_T_LEN; } + + if (len > NGX_MAX_SIZE_T_VALUE - entry_len) { + return NULL; + } + + len += entry_len; } b = ngx_create_temp_buf(r->pool, len); @@ -843,7 +853,7 @@ ngx_http_autoindex_jsonp_callback(ngx_http_request_t *r, ngx_str_t *callback) static ngx_buf_t * ngx_http_autoindex_xml(ngx_http_request_t *r, ngx_array_t *entries) { - size_t len; + size_t len, entry_len; ngx_tm_t tm; ngx_buf_t *b; ngx_str_t type; @@ -861,13 +871,19 @@ ngx_http_autoindex_xml(ngx_http_request_t *r, ngx_array_t *entries) entry[i].escape = ngx_escape_html(NULL, entry[i].name.data, entry[i].name.len); - len += sizeof("" CRLF) - 1 - + entry[i].name.len + entry[i].escape - + sizeof(" mtime=\"1986-12-31T10:00:00Z\"") - 1; + entry_len = sizeof("" CRLF) - 1 + + entry[i].name.len + entry[i].escape + + sizeof(" mtime=\"1986-12-31T10:00:00Z\"") - 1; if (entry[i].file) { - len += sizeof(" size=\"\"") - 1 + NGX_OFF_T_LEN; + entry_len += sizeof(" size=\"\"") - 1 + NGX_OFF_T_LEN; } + + if (len > NGX_MAX_SIZE_T_VALUE - entry_len) { + return NULL; + } + + len += entry_len; } b = ngx_create_temp_buf(r->pool, len); diff --git a/src/http/modules/ngx_http_dav_module.c b/src/http/modules/ngx_http_dav_module.c index 55ad9eb..95c7b32 100644 --- a/src/http/modules/ngx_http_dav_module.c +++ b/src/http/modules/ngx_http_dav_module.c @@ -841,11 +841,9 @@ overwrite_done: return NGX_HTTP_INTERNAL_SERVER_ERROR; } - dlcf = ngx_http_get_module_loc_conf(r, ngx_http_dav_module); - cf.size = ngx_file_size(&fi); cf.buf_size = 0; - cf.access = dlcf->access; + cf.access = ngx_file_access(&fi); cf.time = ngx_file_mtime(&fi); cf.log = r->connection->log; diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c index 3eec1b7..2be0672 100644 --- a/src/http/modules/ngx_http_fastcgi_module.c +++ b/src/http/modules/ngx_http_fastcgi_module.c @@ -286,6 +286,13 @@ static ngx_command_t ngx_http_fastcgi_commands[] = { offsetof(ngx_http_fastcgi_loc_conf_t, upstream.local), NULL }, + { ngx_string("fastcgi_socket_keepalive"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_fastcgi_loc_conf_t, upstream.socket_keepalive), + NULL }, + { ngx_string("fastcgi_connect_timeout"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_msec_slot, @@ -2721,6 +2728,7 @@ ngx_http_fastcgi_create_loc_conf(ngx_conf_t *cf) conf->upstream.force_ranges = NGX_CONF_UNSET; conf->upstream.local = NGX_CONF_UNSET_PTR; + conf->upstream.socket_keepalive = NGX_CONF_UNSET; conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC; conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC; @@ -2824,6 +2832,9 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_ptr_value(conf->upstream.local, prev->upstream.local, NULL); + ngx_conf_merge_value(conf->upstream.socket_keepalive, + prev->upstream.socket_keepalive, 0); + ngx_conf_merge_msec_value(conf->upstream.connect_timeout, prev->upstream.connect_timeout, 60000); @@ -3501,7 +3512,7 @@ ngx_http_fastcgi_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) clcf->handler = ngx_http_fastcgi_handler; - if (clcf->name.data[clcf->name.len - 1] == '/') { + if (clcf->name.len && clcf->name.data[clcf->name.len - 1] == '/') { clcf->auto_redirect = 1; } diff --git a/src/http/modules/ngx_http_geo_module.c b/src/http/modules/ngx_http_geo_module.c index c11bafa..153b6aa 100644 --- a/src/http/modules/ngx_http_geo_module.c +++ b/src/http/modules/ngx_http_geo_module.c @@ -215,6 +215,13 @@ ngx_http_geo_cidr_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, break; #endif +#if (NGX_HAVE_UNIX_DOMAIN) + case AF_UNIX: + vv = (ngx_http_variable_value_t *) + ngx_radix32tree_find(ctx->u.trees.tree, INADDR_NONE); + break; +#endif + default: /* AF_INET */ sin = (struct sockaddr_in *) addr.sockaddr; inaddr = ntohl(sin->sin_addr.s_addr); @@ -277,6 +284,12 @@ ngx_http_geo_range_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, break; #endif +#if (NGX_HAVE_UNIX_DOMAIN) + case AF_UNIX: + inaddr = INADDR_NONE; + break; +#endif + default: /* AF_INET */ sin = (struct sockaddr_in *) addr.sockaddr; inaddr = ntohl(sin->sin_addr.s_addr); diff --git a/src/http/modules/ngx_http_grpc_module.c b/src/http/modules/ngx_http_grpc_module.c index 62b33fd..f59ecbd 100644 --- a/src/http/modules/ngx_http_grpc_module.c +++ b/src/http/modules/ngx_http_grpc_module.c @@ -251,6 +251,13 @@ static ngx_command_t ngx_http_grpc_commands[] = { offsetof(ngx_http_grpc_loc_conf_t, upstream.local), NULL }, + { ngx_string("grpc_socket_keepalive"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_grpc_loc_conf_t, upstream.socket_keepalive), + NULL }, + { ngx_string("grpc_connect_timeout"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_msec_slot, @@ -4165,6 +4172,7 @@ ngx_http_grpc_create_loc_conf(ngx_conf_t *cf) */ conf->upstream.local = NGX_CONF_UNSET_PTR; + conf->upstream.socket_keepalive = NGX_CONF_UNSET; conf->upstream.next_upstream_tries = NGX_CONF_UNSET_UINT; conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC; conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC; @@ -4220,6 +4228,9 @@ ngx_http_grpc_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_ptr_value(conf->upstream.local, prev->upstream.local, NULL); + ngx_conf_merge_value(conf->upstream.socket_keepalive, + prev->upstream.socket_keepalive, 0); + ngx_conf_merge_uint_value(conf->upstream.next_upstream_tries, prev->upstream.next_upstream_tries, 0); @@ -4586,7 +4597,7 @@ ngx_http_grpc_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) clcf->handler = ngx_http_grpc_handler; - if (clcf->name.data[clcf->name.len - 1] == '/') { + if (clcf->name.len && clcf->name.data[clcf->name.len - 1] == '/') { clcf->auto_redirect = 1; } @@ -4639,6 +4650,7 @@ ngx_http_grpc_set_ssl(ngx_conf_t *cf, ngx_http_grpc_loc_conf_t *glcf) cln = ngx_pool_cleanup_add(cf->pool, 0); if (cln == NULL) { + ngx_ssl_cleanup_ctx(glcf->upstream.ssl); return NGX_ERROR; } @@ -4688,6 +4700,13 @@ ngx_http_grpc_set_ssl(ngx_conf_t *cf, ngx_http_grpc_loc_conf_t *glcf) } } + if (ngx_ssl_client_session_cache(cf, glcf->upstream.ssl, + glcf->upstream.ssl_session_reuse) + != NGX_OK) + { + return NGX_ERROR; + } + #ifdef TLSEXT_TYPE_application_layer_protocol_negotiation if (SSL_CTX_set_alpn_protos(glcf->upstream.ssl->ctx, diff --git a/src/http/modules/ngx_http_limit_req_module.c b/src/http/modules/ngx_http_limit_req_module.c index 579b13c..e81d57f 100644 --- a/src/http/modules/ngx_http_limit_req_module.c +++ b/src/http/modules/ngx_http_limit_req_module.c @@ -44,7 +44,7 @@ typedef struct { ngx_shm_zone_t *shm_zone; /* integer value, 1 corresponds to 0.001 r/s */ ngx_uint_t burst; - ngx_uint_t nodelay; /* unsigned nodelay:1 */ + ngx_uint_t delay; } ngx_http_limit_req_limit_t; @@ -399,7 +399,14 @@ ngx_http_limit_req_lookup(ngx_http_limit_req_limit_t *limit, ngx_uint_t hash, ms = (ngx_msec_int_t) (now - lr->last); - excess = lr->excess - ctx->rate * ngx_abs(ms) / 1000 + 1000; + if (ms < -60000) { + ms = 1; + + } else if (ms < 0) { + ms = 0; + } + + excess = lr->excess - ctx->rate * ms / 1000 + 1000; if (excess < 0) { excess = 0; @@ -413,7 +420,11 @@ ngx_http_limit_req_lookup(ngx_http_limit_req_limit_t *limit, ngx_uint_t hash, if (account) { lr->excess = excess; - lr->last = now; + + if (ms) { + lr->last = now; + } + return NGX_OK; } @@ -488,12 +499,12 @@ ngx_http_limit_req_account(ngx_http_limit_req_limit_t *limits, ngx_uint_t n, excess = *ep; - if (excess == 0 || (*limit)->nodelay) { + if ((ngx_uint_t) excess <= (*limit)->delay) { max_delay = 0; } else { ctx = (*limit)->shm_zone->data; - max_delay = excess * 1000 / ctx->rate; + max_delay = (excess - (*limit)->delay) * 1000 / ctx->rate; } while (n--) { @@ -509,13 +520,23 @@ ngx_http_limit_req_account(ngx_http_limit_req_limit_t *limits, ngx_uint_t n, now = ngx_current_msec; ms = (ngx_msec_int_t) (now - lr->last); - excess = lr->excess - ctx->rate * ngx_abs(ms) / 1000 + 1000; + if (ms < -60000) { + ms = 1; + + } else if (ms < 0) { + ms = 0; + } + + excess = lr->excess - ctx->rate * ms / 1000 + 1000; if (excess < 0) { excess = 0; } - lr->last = now; + if (ms) { + lr->last = now; + } + lr->excess = excess; lr->count--; @@ -523,11 +544,11 @@ ngx_http_limit_req_account(ngx_http_limit_req_limit_t *limits, ngx_uint_t n, ctx->node = NULL; - if (limits[n].nodelay) { + if ((ngx_uint_t) excess <= limits[n].delay) { continue; } - delay = excess * 1000 / ctx->rate; + delay = (excess - limits[n].delay) * 1000 / ctx->rate; if (delay > max_delay) { max_delay = delay; @@ -854,9 +875,9 @@ ngx_http_limit_req(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_http_limit_req_conf_t *lrcf = conf; - ngx_int_t burst; + ngx_int_t burst, delay; ngx_str_t *value, s; - ngx_uint_t i, nodelay; + ngx_uint_t i; ngx_shm_zone_t *shm_zone; ngx_http_limit_req_limit_t *limit, *limits; @@ -864,7 +885,7 @@ ngx_http_limit_req(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) shm_zone = NULL; burst = 0; - nodelay = 0; + delay = 0; for (i = 1; i < cf->args->nelts; i++) { @@ -887,7 +908,19 @@ ngx_http_limit_req(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) burst = ngx_atoi(value[i].data + 6, value[i].len - 6); if (burst <= 0) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid burst rate \"%V\"", &value[i]); + "invalid burst value \"%V\"", &value[i]); + return NGX_CONF_ERROR; + } + + continue; + } + + if (ngx_strncmp(value[i].data, "delay=", 6) == 0) { + + delay = ngx_atoi(value[i].data + 6, value[i].len - 6); + if (delay <= 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid delay value \"%V\"", &value[i]); return NGX_CONF_ERROR; } @@ -895,7 +928,7 @@ ngx_http_limit_req(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } if (ngx_strcmp(value[i].data, "nodelay") == 0) { - nodelay = 1; + delay = NGX_MAX_INT_T_VALUE / 1000; continue; } @@ -935,7 +968,7 @@ ngx_http_limit_req(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) limit->shm_zone = shm_zone; limit->burst = burst * 1000; - limit->nodelay = nodelay; + limit->delay = delay * 1000; return NGX_CONF_OK; } diff --git a/src/http/modules/ngx_http_memcached_module.c b/src/http/modules/ngx_http_memcached_module.c index 82fa713..775bd7e 100644 --- a/src/http/modules/ngx_http_memcached_module.c +++ b/src/http/modules/ngx_http_memcached_module.c @@ -67,6 +67,13 @@ static ngx_command_t ngx_http_memcached_commands[] = { offsetof(ngx_http_memcached_loc_conf_t, upstream.local), NULL }, + { ngx_string("memcached_socket_keepalive"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_memcached_loc_conf_t, upstream.socket_keepalive), + NULL }, + { ngx_string("memcached_connect_timeout"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_msec_slot, @@ -595,6 +602,7 @@ ngx_http_memcached_create_loc_conf(ngx_conf_t *cf) */ conf->upstream.local = NGX_CONF_UNSET_PTR; + conf->upstream.socket_keepalive = NGX_CONF_UNSET; conf->upstream.next_upstream_tries = NGX_CONF_UNSET_UINT; conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC; conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC; @@ -634,6 +642,9 @@ ngx_http_memcached_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_ptr_value(conf->upstream.local, prev->upstream.local, NULL); + ngx_conf_merge_value(conf->upstream.socket_keepalive, + prev->upstream.socket_keepalive, 0); + ngx_conf_merge_uint_value(conf->upstream.next_upstream_tries, prev->upstream.next_upstream_tries, 0); @@ -707,7 +718,7 @@ ngx_http_memcached_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) clcf->handler = ngx_http_memcached_handler; - if (clcf->name.data[clcf->name.len - 1] == '/') { + if (clcf->name.len && clcf->name.data[clcf->name.len - 1] == '/') { clcf->auto_redirect = 1; } diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c index e7f829d..3aafb99 100644 --- a/src/http/modules/ngx_http_proxy_module.c +++ b/src/http/modules/ngx_http_proxy_module.c @@ -324,6 +324,13 @@ static ngx_command_t ngx_http_proxy_commands[] = { offsetof(ngx_http_proxy_loc_conf_t, upstream.local), NULL }, + { ngx_string("proxy_socket_keepalive"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_proxy_loc_conf_t, upstream.socket_keepalive), + NULL }, + { ngx_string("proxy_connect_timeout"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_msec_slot, @@ -2833,6 +2840,7 @@ ngx_http_proxy_create_loc_conf(ngx_conf_t *cf) conf->upstream.force_ranges = NGX_CONF_UNSET; conf->upstream.local = NGX_CONF_UNSET_PTR; + conf->upstream.socket_keepalive = NGX_CONF_UNSET; conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC; conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC; @@ -2953,6 +2961,9 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_ptr_value(conf->upstream.local, prev->upstream.local, NULL); + ngx_conf_merge_value(conf->upstream.socket_keepalive, + prev->upstream.socket_keepalive, 0); + ngx_conf_merge_msec_value(conf->upstream.connect_timeout, prev->upstream.connect_timeout, 60000); @@ -3580,7 +3591,7 @@ ngx_http_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) clcf->handler = ngx_http_proxy_handler; - if (clcf->name.data[clcf->name.len - 1] == '/') { + if (clcf->name.len && clcf->name.data[clcf->name.len - 1] == '/') { clcf->auto_redirect = 1; } @@ -4259,6 +4270,7 @@ ngx_http_proxy_set_ssl(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *plcf) cln = ngx_pool_cleanup_add(cf->pool, 0); if (cln == NULL) { + ngx_ssl_cleanup_ctx(plcf->upstream.ssl); return NGX_ERROR; } @@ -4308,6 +4320,13 @@ ngx_http_proxy_set_ssl(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *plcf) } } + if (ngx_ssl_client_session_cache(cf, plcf->upstream.ssl, + plcf->upstream.ssl_session_reuse) + != NGX_OK) + { + return NGX_ERROR; + } + return NGX_OK; } diff --git a/src/http/modules/ngx_http_random_index_module.c b/src/http/modules/ngx_http_random_index_module.c index b47ee4f..ed00ad5 100644 --- a/src/http/modules/ngx_http_random_index_module.c +++ b/src/http/modules/ngx_http_random_index_module.c @@ -98,7 +98,7 @@ ngx_http_random_index_handler(ngx_http_request_t *r) } #if (NGX_HAVE_D_TYPE) - len = NGX_DIR_MASK_LEN; + len = 0; #else len = NGX_HTTP_RANDOM_INDEX_PREALLOCATE; #endif diff --git a/src/http/modules/ngx_http_rewrite_module.c b/src/http/modules/ngx_http_rewrite_module.c index a6f1fc8..3b49c45 100644 --- a/src/http/modules/ngx_http_rewrite_module.c +++ b/src/http/modules/ngx_http_rewrite_module.c @@ -180,15 +180,7 @@ ngx_http_rewrite_handler(ngx_http_request_t *r) code(e); } - if (e->status < NGX_HTTP_BAD_REQUEST) { - return e->status; - } - - if (r->err_status == 0) { - return e->status; - } - - return r->err_status; + return e->status; } diff --git a/src/http/modules/ngx_http_scgi_module.c b/src/http/modules/ngx_http_scgi_module.c index 9bd45bd..7216f78 100644 --- a/src/http/modules/ngx_http_scgi_module.c +++ b/src/http/modules/ngx_http_scgi_module.c @@ -143,6 +143,13 @@ static ngx_command_t ngx_http_scgi_commands[] = { offsetof(ngx_http_scgi_loc_conf_t, upstream.local), NULL }, + { ngx_string("scgi_socket_keepalive"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_scgi_loc_conf_t, upstream.socket_keepalive), + NULL }, + { ngx_string("scgi_connect_timeout"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_msec_slot, @@ -1200,6 +1207,7 @@ ngx_http_scgi_create_loc_conf(ngx_conf_t *cf) conf->upstream.force_ranges = NGX_CONF_UNSET; conf->upstream.local = NGX_CONF_UNSET_PTR; + conf->upstream.socket_keepalive = NGX_CONF_UNSET; conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC; conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC; @@ -1298,6 +1306,9 @@ ngx_http_scgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_ptr_value(conf->upstream.local, prev->upstream.local, NULL); + ngx_conf_merge_value(conf->upstream.socket_keepalive, + prev->upstream.socket_keepalive, 0); + ngx_conf_merge_msec_value(conf->upstream.connect_timeout, prev->upstream.connect_timeout, 60000); @@ -1857,7 +1868,7 @@ ngx_http_scgi_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return NGX_CONF_ERROR; } - if (clcf->name.data[clcf->name.len - 1] == '/') { + if (clcf->name.len && clcf->name.data[clcf->name.len - 1] == '/') { clcf->auto_redirect = 1; } diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c index 7d62176..b3f8f47 100644 --- a/src/http/modules/ngx_http_ssl_module.c +++ b/src/http/modules/ngx_http_ssl_module.c @@ -41,6 +41,9 @@ static void *ngx_http_ssl_create_srv_conf(ngx_conf_t *cf); static char *ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child); +static ngx_int_t ngx_http_ssl_compile_certificates(ngx_conf_t *cf, + ngx_http_ssl_srv_conf_t *conf); + static char *ngx_http_ssl_enable(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static char *ngx_http_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, @@ -71,6 +74,11 @@ static ngx_conf_enum_t ngx_http_ssl_verify[] = { }; +static ngx_conf_deprecated_t ngx_http_ssl_deprecated = { + ngx_conf_deprecated, "ssl", "listen ... ssl" +}; + + static ngx_command_t ngx_http_ssl_commands[] = { { ngx_string("ssl"), @@ -78,7 +86,7 @@ static ngx_command_t ngx_http_ssl_commands[] = { ngx_http_ssl_enable, NGX_HTTP_SRV_CONF_OFFSET, offsetof(ngx_http_ssl_srv_conf_t, enable), - NULL }, + &ngx_http_ssl_deprecated }, { ngx_string("ssl_certificate"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, @@ -234,6 +242,13 @@ static ngx_command_t ngx_http_ssl_commands[] = { offsetof(ngx_http_ssl_srv_conf_t, stapling_verify), NULL }, + { ngx_string("ssl_early_data"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_http_ssl_srv_conf_t, early_data), + NULL }, + ngx_null_command }; @@ -289,6 +304,10 @@ static ngx_http_variable_t ngx_http_ssl_vars[] = { { ngx_string("ssl_session_reused"), NULL, ngx_http_ssl_variable, (uintptr_t) ngx_ssl_get_session_reused, NGX_HTTP_VAR_CHANGEABLE, 0 }, + { ngx_string("ssl_early_data"), NULL, ngx_http_ssl_variable, + (uintptr_t) ngx_ssl_get_early_data, + NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE, 0 }, + { ngx_string("ssl_server_name"), NULL, ngx_http_ssl_variable, (uintptr_t) ngx_ssl_get_server_name, NGX_HTTP_VAR_CHANGEABLE, 0 }, @@ -534,6 +553,7 @@ ngx_http_ssl_create_srv_conf(ngx_conf_t *cf) * set by ngx_pcalloc(): * * sscf->protocols = 0; + * sscf->certificate_values = NULL; * sscf->dhparam = { 0, NULL }; * sscf->ecdh_curve = { 0, NULL }; * sscf->client_certificate = { 0, NULL }; @@ -547,6 +567,7 @@ ngx_http_ssl_create_srv_conf(ngx_conf_t *cf) sscf->enable = NGX_CONF_UNSET; sscf->prefer_server_ciphers = NGX_CONF_UNSET; + sscf->early_data = NGX_CONF_UNSET; sscf->buffer_size = NGX_CONF_UNSET_SIZE; sscf->verify = NGX_CONF_UNSET_UINT; sscf->verify_depth = NGX_CONF_UNSET_UINT; @@ -589,6 +610,8 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_value(conf->prefer_server_ciphers, prev->prefer_server_ciphers, 0); + ngx_conf_merge_value(conf->early_data, prev->early_data, 0); + ngx_conf_merge_bitmask_value(conf->protocols, prev->protocols, (NGX_CONF_BITMASK_SET|NGX_SSL_TLSv1 |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2)); @@ -677,6 +700,15 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) return NGX_CONF_ERROR; } + cln = ngx_pool_cleanup_add(cf->pool, 0); + if (cln == NULL) { + ngx_ssl_cleanup_ctx(&conf->ssl); + return NGX_CONF_ERROR; + } + + cln->handler = ngx_ssl_cleanup_ctx; + cln->data = &conf->ssl; + #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME if (SSL_CTX_set_tlsext_servername_callback(conf->ssl.ctx, @@ -700,19 +732,36 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) ngx_http_ssl_npn_advertised, NULL); #endif - cln = ngx_pool_cleanup_add(cf->pool, 0); - if (cln == NULL) { + if (ngx_http_ssl_compile_certificates(cf, conf) != NGX_OK) { return NGX_CONF_ERROR; } - cln->handler = ngx_ssl_cleanup_ctx; - cln->data = &conf->ssl; + if (conf->certificate_values) { - if (ngx_ssl_certificates(cf, &conf->ssl, conf->certificates, - conf->certificate_keys, conf->passwords) - != NGX_OK) - { +#ifdef SSL_R_CERT_CB_ERROR + + /* install callback to lookup certificates */ + + SSL_CTX_set_cert_cb(conf->ssl.ctx, ngx_http_ssl_certificate, conf); + +#else + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "variables in " + "\"ssl_certificate\" and \"ssl_certificate_key\" " + "directives are not supported on this platform"); return NGX_CONF_ERROR; +#endif + + } else { + + /* configure certificates */ + + if (ngx_ssl_certificates(cf, &conf->ssl, conf->certificates, + conf->certificate_keys, conf->passwords) + != NGX_OK) + { + return NGX_CONF_ERROR; + } } if (ngx_ssl_ciphers(cf, &conf->ssl, &conf->ciphers, @@ -769,7 +818,7 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) } if (ngx_ssl_session_cache(&conf->ssl, &ngx_http_ssl_sess_id_ctx, - conf->builtin_session_cache, + conf->certificates, conf->builtin_session_cache, conf->shm_zone, conf->session_timeout) != NGX_OK) { @@ -804,10 +853,98 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) } + if (ngx_ssl_early_data(cf, &conf->ssl, conf->early_data) != NGX_OK) { + return NGX_CONF_ERROR; + } + return NGX_CONF_OK; } +static ngx_int_t +ngx_http_ssl_compile_certificates(ngx_conf_t *cf, + ngx_http_ssl_srv_conf_t *conf) +{ + ngx_str_t *cert, *key; + ngx_uint_t i, nelts; + ngx_http_complex_value_t *cv; + ngx_http_compile_complex_value_t ccv; + + cert = conf->certificates->elts; + key = conf->certificate_keys->elts; + nelts = conf->certificates->nelts; + + for (i = 0; i < nelts; i++) { + + if (ngx_http_script_variables_count(&cert[i])) { + goto found; + } + + if (ngx_http_script_variables_count(&key[i])) { + goto found; + } + } + + return NGX_OK; + +found: + + conf->certificate_values = ngx_array_create(cf->pool, nelts, + sizeof(ngx_http_complex_value_t)); + if (conf->certificate_values == NULL) { + return NGX_ERROR; + } + + conf->certificate_key_values = ngx_array_create(cf->pool, nelts, + sizeof(ngx_http_complex_value_t)); + if (conf->certificate_key_values == NULL) { + return NGX_ERROR; + } + + for (i = 0; i < nelts; i++) { + + cv = ngx_array_push(conf->certificate_values); + if (cv == NULL) { + return NGX_ERROR; + } + + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &cert[i]; + ccv.complex_value = cv; + ccv.zero = 1; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_ERROR; + } + + cv = ngx_array_push(conf->certificate_key_values); + if (cv == NULL) { + return NGX_ERROR; + } + + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &key[i]; + ccv.complex_value = cv; + ccv.zero = 1; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_ERROR; + } + } + + conf->passwords = ngx_ssl_preserve_passwords(cf, conf->passwords); + if (conf->passwords == NULL) { + return NGX_ERROR; + } + + return NGX_OK; +} + + static char * ngx_http_ssl_enable(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { @@ -966,10 +1103,12 @@ invalid: static ngx_int_t ngx_http_ssl_init(ngx_conf_t *cf) { - ngx_uint_t s; + ngx_uint_t a, p, s; + ngx_http_conf_addr_t *addr; + ngx_http_conf_port_t *port; ngx_http_ssl_srv_conf_t *sscf; ngx_http_core_loc_conf_t *clcf; - ngx_http_core_srv_conf_t **cscfp; + ngx_http_core_srv_conf_t **cscfp, *cscf; ngx_http_core_main_conf_t *cmcf; cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); @@ -993,5 +1132,32 @@ ngx_http_ssl_init(ngx_conf_t *cf) } } + if (cmcf->ports == NULL) { + return NGX_OK; + } + + port = cmcf->ports->elts; + for (p = 0; p < cmcf->ports->nelts; p++) { + + addr = port[p].addrs.elts; + for (a = 0; a < port[p].addrs.nelts; a++) { + + if (!addr[a].opt.ssl) { + continue; + } + + cscf = addr[a].default_server; + sscf = cscf->ctx->srv_conf[ngx_http_ssl_module.ctx_index]; + + if (sscf->certificates == NULL) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "no \"ssl_certificate\" is defined for " + "the \"listen ... ssl\" directive in %s:%ui", + cscf->file_name, cscf->line); + return NGX_ERROR; + } + } + } + return NGX_OK; } diff --git a/src/http/modules/ngx_http_ssl_module.h b/src/http/modules/ngx_http_ssl_module.h index 57f5941..26fdccf 100644 --- a/src/http/modules/ngx_http_ssl_module.h +++ b/src/http/modules/ngx_http_ssl_module.h @@ -20,6 +20,7 @@ typedef struct { ngx_ssl_t ssl; ngx_flag_t prefer_server_ciphers; + ngx_flag_t early_data; ngx_uint_t protocols; @@ -35,6 +36,9 @@ typedef struct { ngx_array_t *certificates; ngx_array_t *certificate_keys; + ngx_array_t *certificate_values; + ngx_array_t *certificate_key_values; + ngx_str_t dhparam; ngx_str_t ecdh_curve; ngx_str_t client_certificate; diff --git a/src/http/modules/ngx_http_upstream_hash_module.c b/src/http/modules/ngx_http_upstream_hash_module.c index d67f34d..6c247b5 100644 --- a/src/http/modules/ngx_http_upstream_hash_module.c +++ b/src/http/modules/ngx_http_upstream_hash_module.c @@ -176,7 +176,7 @@ ngx_http_upstream_get_hash_peer(ngx_peer_connection_t *pc, void *data) ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, "get hash peer, try: %ui", pc->tries); - ngx_http_upstream_rr_peers_wlock(hp->rrp.peers); + ngx_http_upstream_rr_peers_rlock(hp->rrp.peers); if (hp->tries > 20 || hp->rrp.peers->single) { ngx_http_upstream_rr_peers_unlock(hp->rrp.peers); @@ -228,10 +228,13 @@ ngx_http_upstream_get_hash_peer(ngx_peer_connection_t *pc, void *data) goto next; } + ngx_http_upstream_rr_peer_lock(hp->rrp.peers, peer); + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0, "get hash peer, value:%uD, peer:%ui", hp->hash, p); if (peer->down) { + ngx_http_upstream_rr_peer_unlock(hp->rrp.peers, peer); goto next; } @@ -239,10 +242,12 @@ ngx_http_upstream_get_hash_peer(ngx_peer_connection_t *pc, void *data) && peer->fails >= peer->max_fails && now - peer->checked <= peer->fail_timeout) { + ngx_http_upstream_rr_peer_unlock(hp->rrp.peers, peer); goto next; } if (peer->max_conns && peer->conns >= peer->max_conns) { + ngx_http_upstream_rr_peer_unlock(hp->rrp.peers, peer); goto next; } @@ -268,6 +273,7 @@ ngx_http_upstream_get_hash_peer(ngx_peer_connection_t *pc, void *data) peer->checked = now; } + ngx_http_upstream_rr_peer_unlock(hp->rrp.peers, peer); ngx_http_upstream_rr_peers_unlock(hp->rrp.peers); hp->rrp.tried[n] |= m; diff --git a/src/http/modules/ngx_http_upstream_ip_hash_module.c b/src/http/modules/ngx_http_upstream_ip_hash_module.c index 296108f..1fa01d9 100644 --- a/src/http/modules/ngx_http_upstream_ip_hash_module.c +++ b/src/http/modules/ngx_http_upstream_ip_hash_module.c @@ -161,7 +161,7 @@ ngx_http_upstream_get_ip_hash_peer(ngx_peer_connection_t *pc, void *data) /* TODO: cached */ - ngx_http_upstream_rr_peers_wlock(iphp->rrp.peers); + ngx_http_upstream_rr_peers_rlock(iphp->rrp.peers); if (iphp->tries > 20 || iphp->rrp.peers->single) { ngx_http_upstream_rr_peers_unlock(iphp->rrp.peers); @@ -201,7 +201,10 @@ ngx_http_upstream_get_ip_hash_peer(ngx_peer_connection_t *pc, void *data) ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0, "get ip hash peer, hash: %ui %04XL", p, (uint64_t) m); + ngx_http_upstream_rr_peer_lock(iphp->rrp.peers, peer); + if (peer->down) { + ngx_http_upstream_rr_peer_unlock(iphp->rrp.peers, peer); goto next; } @@ -209,10 +212,12 @@ ngx_http_upstream_get_ip_hash_peer(ngx_peer_connection_t *pc, void *data) && peer->fails >= peer->max_fails && now - peer->checked <= peer->fail_timeout) { + ngx_http_upstream_rr_peer_unlock(iphp->rrp.peers, peer); goto next; } if (peer->max_conns && peer->conns >= peer->max_conns) { + ngx_http_upstream_rr_peer_unlock(iphp->rrp.peers, peer); goto next; } @@ -238,6 +243,7 @@ ngx_http_upstream_get_ip_hash_peer(ngx_peer_connection_t *pc, void *data) peer->checked = now; } + ngx_http_upstream_rr_peer_unlock(iphp->rrp.peers, peer); ngx_http_upstream_rr_peers_unlock(iphp->rrp.peers); iphp->rrp.tried[n] |= m; diff --git a/src/http/modules/ngx_http_upstream_keepalive_module.c b/src/http/modules/ngx_http_upstream_keepalive_module.c index 90a226d..bdc4ae5 100644 --- a/src/http/modules/ngx_http_upstream_keepalive_module.c +++ b/src/http/modules/ngx_http_upstream_keepalive_module.c @@ -12,6 +12,8 @@ typedef struct { ngx_uint_t max_cached; + ngx_uint_t requests; + ngx_msec_t timeout; ngx_queue_t cache; ngx_queue_t free; @@ -84,6 +86,20 @@ static ngx_command_t ngx_http_upstream_keepalive_commands[] = { 0, NULL }, + { ngx_string("keepalive_timeout"), + NGX_HTTP_UPS_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_http_upstream_keepalive_srv_conf_t, timeout), + NULL }, + + { ngx_string("keepalive_requests"), + NGX_HTTP_UPS_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_http_upstream_keepalive_srv_conf_t, requests), + NULL }, + ngx_null_command }; @@ -133,6 +149,9 @@ ngx_http_upstream_init_keepalive(ngx_conf_t *cf, kcf = ngx_http_conf_upstream_srv_conf(us, ngx_http_upstream_keepalive_module); + ngx_conf_init_msec_value(kcf->timeout, 60000); + ngx_conf_init_uint_value(kcf->requests, 100); + if (kcf->original_init_upstream(cf, us) != NGX_OK) { return NGX_ERROR; } @@ -261,6 +280,10 @@ found: c->write->log = pc->log; c->pool->log = pc->log; + if (c->read->timer_set) { + ngx_del_timer(c->read); + } + pc->connection = c; pc->cached = 1; @@ -298,6 +321,10 @@ ngx_http_upstream_free_keepalive_peer(ngx_peer_connection_t *pc, void *data, goto invalid; } + if (c->requests >= kp->conf->requests) { + goto invalid; + } + if (!u->keepalive) { goto invalid; } @@ -339,10 +366,9 @@ ngx_http_upstream_free_keepalive_peer(ngx_peer_connection_t *pc, void *data, pc->connection = NULL; - if (c->read->timer_set) { - c->read->delayed = 0; - ngx_del_timer(c->read); - } + c->read->delayed = 0; + ngx_add_timer(c->read, kp->conf->timeout); + if (c->write->timer_set) { ngx_del_timer(c->write); } @@ -393,7 +419,7 @@ ngx_http_upstream_keepalive_close_handler(ngx_event_t *ev) c = ev->data; - if (c->close) { + if (c->close || c->read->timedout) { goto close; } @@ -486,6 +512,9 @@ ngx_http_upstream_keepalive_create_conf(ngx_conf_t *cf) * conf->max_cached = 0; */ + conf->timeout = NGX_CONF_UNSET_MSEC; + conf->requests = NGX_CONF_UNSET_UINT; + return conf; } @@ -518,6 +547,8 @@ ngx_http_upstream_keepalive(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) kcf->max_cached = n; + /* init upstream handler */ + uscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_upstream_module); kcf->original_init_upstream = uscf->peer.init_upstream diff --git a/src/http/modules/ngx_http_upstream_random_module.c b/src/http/modules/ngx_http_upstream_random_module.c new file mode 100644 index 0000000..6f169c8 --- /dev/null +++ b/src/http/modules/ngx_http_upstream_random_module.c @@ -0,0 +1,502 @@ + +/* + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include + + +typedef struct { + ngx_http_upstream_rr_peer_t *peer; + ngx_uint_t range; +} ngx_http_upstream_random_range_t; + + +typedef struct { + ngx_uint_t two; + ngx_http_upstream_random_range_t *ranges; +} ngx_http_upstream_random_srv_conf_t; + + +typedef struct { + /* the round robin data must be first */ + ngx_http_upstream_rr_peer_data_t rrp; + + ngx_http_upstream_random_srv_conf_t *conf; + u_char tries; +} ngx_http_upstream_random_peer_data_t; + + +static ngx_int_t ngx_http_upstream_init_random(ngx_conf_t *cf, + ngx_http_upstream_srv_conf_t *us); +static ngx_int_t ngx_http_upstream_update_random(ngx_pool_t *pool, + ngx_http_upstream_srv_conf_t *us); + +static ngx_int_t ngx_http_upstream_init_random_peer(ngx_http_request_t *r, + ngx_http_upstream_srv_conf_t *us); +static ngx_int_t ngx_http_upstream_get_random_peer(ngx_peer_connection_t *pc, + void *data); +static ngx_int_t ngx_http_upstream_get_random2_peer(ngx_peer_connection_t *pc, + void *data); +static ngx_uint_t ngx_http_upstream_peek_random_peer( + ngx_http_upstream_rr_peers_t *peers, + ngx_http_upstream_random_peer_data_t *rp); +static void *ngx_http_upstream_random_create_conf(ngx_conf_t *cf); +static char *ngx_http_upstream_random(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); + + +static ngx_command_t ngx_http_upstream_random_commands[] = { + + { ngx_string("random"), + NGX_HTTP_UPS_CONF|NGX_CONF_NOARGS|NGX_CONF_TAKE12, + ngx_http_upstream_random, + NGX_HTTP_SRV_CONF_OFFSET, + 0, + NULL }, + + ngx_null_command +}; + + +static ngx_http_module_t ngx_http_upstream_random_module_ctx = { + NULL, /* preconfiguration */ + NULL, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + ngx_http_upstream_random_create_conf, /* create server configuration */ + NULL, /* merge server configuration */ + + NULL, /* create location configuration */ + NULL /* merge location configuration */ +}; + + +ngx_module_t ngx_http_upstream_random_module = { + NGX_MODULE_V1, + &ngx_http_upstream_random_module_ctx, /* module context */ + ngx_http_upstream_random_commands, /* module directives */ + NGX_HTTP_MODULE, /* module type */ + NULL, /* init master */ + NULL, /* init module */ + NULL, /* init process */ + NULL, /* init thread */ + NULL, /* exit thread */ + NULL, /* exit process */ + NULL, /* exit master */ + NGX_MODULE_V1_PADDING +}; + + +static ngx_int_t +ngx_http_upstream_init_random(ngx_conf_t *cf, ngx_http_upstream_srv_conf_t *us) +{ + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0, "init random"); + + if (ngx_http_upstream_init_round_robin(cf, us) != NGX_OK) { + return NGX_ERROR; + } + + us->peer.init = ngx_http_upstream_init_random_peer; + +#if (NGX_HTTP_UPSTREAM_ZONE) + if (us->shm_zone) { + return NGX_OK; + } +#endif + + return ngx_http_upstream_update_random(cf->pool, us); +} + + +static ngx_int_t +ngx_http_upstream_update_random(ngx_pool_t *pool, + ngx_http_upstream_srv_conf_t *us) +{ + size_t size; + ngx_uint_t i, total_weight; + ngx_http_upstream_rr_peer_t *peer; + ngx_http_upstream_rr_peers_t *peers; + ngx_http_upstream_random_range_t *ranges; + ngx_http_upstream_random_srv_conf_t *rcf; + + rcf = ngx_http_conf_upstream_srv_conf(us, ngx_http_upstream_random_module); + + peers = us->peer.data; + + size = peers->number * sizeof(ngx_http_upstream_random_range_t); + + ranges = pool ? ngx_palloc(pool, size) : ngx_alloc(size, ngx_cycle->log); + if (ranges == NULL) { + return NGX_ERROR; + } + + total_weight = 0; + + for (peer = peers->peer, i = 0; peer; peer = peer->next, i++) { + ranges[i].peer = peer; + ranges[i].range = total_weight; + total_weight += peer->weight; + } + + rcf->ranges = ranges; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_upstream_init_random_peer(ngx_http_request_t *r, + ngx_http_upstream_srv_conf_t *us) +{ + ngx_http_upstream_random_srv_conf_t *rcf; + ngx_http_upstream_random_peer_data_t *rp; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "init random peer"); + + rcf = ngx_http_conf_upstream_srv_conf(us, ngx_http_upstream_random_module); + + rp = ngx_palloc(r->pool, sizeof(ngx_http_upstream_random_peer_data_t)); + if (rp == NULL) { + return NGX_ERROR; + } + + r->upstream->peer.data = &rp->rrp; + + if (ngx_http_upstream_init_round_robin_peer(r, us) != NGX_OK) { + return NGX_ERROR; + } + + if (rcf->two) { + r->upstream->peer.get = ngx_http_upstream_get_random2_peer; + + } else { + r->upstream->peer.get = ngx_http_upstream_get_random_peer; + } + + rp->conf = rcf; + rp->tries = 0; + + ngx_http_upstream_rr_peers_rlock(rp->rrp.peers); + +#if (NGX_HTTP_UPSTREAM_ZONE) + if (rp->rrp.peers->shpool && rcf->ranges == NULL) { + if (ngx_http_upstream_update_random(NULL, us) != NGX_OK) { + ngx_http_upstream_rr_peers_unlock(rp->rrp.peers); + return NGX_ERROR; + } + } +#endif + + ngx_http_upstream_rr_peers_unlock(rp->rrp.peers); + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_upstream_get_random_peer(ngx_peer_connection_t *pc, void *data) +{ + ngx_http_upstream_random_peer_data_t *rp = data; + + time_t now; + uintptr_t m; + ngx_uint_t i, n; + ngx_http_upstream_rr_peer_t *peer; + ngx_http_upstream_rr_peers_t *peers; + ngx_http_upstream_rr_peer_data_t *rrp; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, + "get random peer, try: %ui", pc->tries); + + rrp = &rp->rrp; + peers = rrp->peers; + + ngx_http_upstream_rr_peers_rlock(peers); + + if (rp->tries > 20 || peers->single) { + ngx_http_upstream_rr_peers_unlock(peers); + return ngx_http_upstream_get_round_robin_peer(pc, rrp); + } + + pc->cached = 0; + pc->connection = NULL; + + now = ngx_time(); + + for ( ;; ) { + + i = ngx_http_upstream_peek_random_peer(peers, rp); + + peer = rp->conf->ranges[i].peer; + + n = i / (8 * sizeof(uintptr_t)); + m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t)); + + if (rrp->tried[n] & m) { + goto next; + } + + ngx_http_upstream_rr_peer_lock(peers, peer); + + if (peer->down) { + ngx_http_upstream_rr_peer_unlock(peers, peer); + goto next; + } + + if (peer->max_fails + && peer->fails >= peer->max_fails + && now - peer->checked <= peer->fail_timeout) + { + ngx_http_upstream_rr_peer_unlock(peers, peer); + goto next; + } + + if (peer->max_conns && peer->conns >= peer->max_conns) { + ngx_http_upstream_rr_peer_unlock(peers, peer); + goto next; + } + + break; + + next: + + if (++rp->tries > 20) { + ngx_http_upstream_rr_peers_unlock(peers); + return ngx_http_upstream_get_round_robin_peer(pc, rrp); + } + } + + rrp->current = peer; + + if (now - peer->checked > peer->fail_timeout) { + peer->checked = now; + } + + pc->sockaddr = peer->sockaddr; + pc->socklen = peer->socklen; + pc->name = &peer->name; + + peer->conns++; + + ngx_http_upstream_rr_peer_unlock(peers, peer); + ngx_http_upstream_rr_peers_unlock(peers); + + rrp->tried[n] |= m; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_upstream_get_random2_peer(ngx_peer_connection_t *pc, void *data) +{ + ngx_http_upstream_random_peer_data_t *rp = data; + + time_t now; + uintptr_t m; + ngx_uint_t i, n, p; + ngx_http_upstream_rr_peer_t *peer, *prev; + ngx_http_upstream_rr_peers_t *peers; + ngx_http_upstream_rr_peer_data_t *rrp; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, + "get random2 peer, try: %ui", pc->tries); + + rrp = &rp->rrp; + peers = rrp->peers; + + ngx_http_upstream_rr_peers_wlock(peers); + + if (rp->tries > 20 || peers->single) { + ngx_http_upstream_rr_peers_unlock(peers); + return ngx_http_upstream_get_round_robin_peer(pc, rrp); + } + + pc->cached = 0; + pc->connection = NULL; + + now = ngx_time(); + + prev = NULL; + +#if (NGX_SUPPRESS_WARN) + p = 0; +#endif + + for ( ;; ) { + + i = ngx_http_upstream_peek_random_peer(peers, rp); + + peer = rp->conf->ranges[i].peer; + + if (peer == prev) { + goto next; + } + + n = i / (8 * sizeof(uintptr_t)); + m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t)); + + if (rrp->tried[n] & m) { + goto next; + } + + if (peer->down) { + goto next; + } + + if (peer->max_fails + && peer->fails >= peer->max_fails + && now - peer->checked <= peer->fail_timeout) + { + goto next; + } + + if (peer->max_conns && peer->conns >= peer->max_conns) { + goto next; + } + + if (prev) { + if (peer->conns * prev->weight > prev->conns * peer->weight) { + peer = prev; + n = p / (8 * sizeof(uintptr_t)); + m = (uintptr_t) 1 << p % (8 * sizeof(uintptr_t)); + } + + break; + } + + prev = peer; + p = i; + + next: + + if (++rp->tries > 20) { + ngx_http_upstream_rr_peers_unlock(peers); + return ngx_http_upstream_get_round_robin_peer(pc, rrp); + } + } + + rrp->current = peer; + + if (now - peer->checked > peer->fail_timeout) { + peer->checked = now; + } + + pc->sockaddr = peer->sockaddr; + pc->socklen = peer->socklen; + pc->name = &peer->name; + + peer->conns++; + + ngx_http_upstream_rr_peers_unlock(peers); + + rrp->tried[n] |= m; + + return NGX_OK; +} + + +static ngx_uint_t +ngx_http_upstream_peek_random_peer(ngx_http_upstream_rr_peers_t *peers, + ngx_http_upstream_random_peer_data_t *rp) +{ + ngx_uint_t i, j, k, x; + + x = ngx_random() % peers->total_weight; + + i = 0; + j = peers->number; + + while (j - i > 1) { + k = (i + j) / 2; + + if (x < rp->conf->ranges[k].range) { + j = k; + + } else { + i = k; + } + } + + return i; +} + + +static void * +ngx_http_upstream_random_create_conf(ngx_conf_t *cf) +{ + ngx_http_upstream_random_srv_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_random_srv_conf_t)); + if (conf == NULL) { + return NULL; + } + + /* + * set by ngx_pcalloc(): + * + * conf->two = 0; + */ + + return conf; +} + + +static char * +ngx_http_upstream_random(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_upstream_random_srv_conf_t *rcf = conf; + + ngx_str_t *value; + ngx_http_upstream_srv_conf_t *uscf; + + uscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_upstream_module); + + if (uscf->peer.init_upstream) { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "load balancing method redefined"); + } + + uscf->peer.init_upstream = ngx_http_upstream_init_random; + + uscf->flags = NGX_HTTP_UPSTREAM_CREATE + |NGX_HTTP_UPSTREAM_WEIGHT + |NGX_HTTP_UPSTREAM_MAX_CONNS + |NGX_HTTP_UPSTREAM_MAX_FAILS + |NGX_HTTP_UPSTREAM_FAIL_TIMEOUT + |NGX_HTTP_UPSTREAM_DOWN; + + if (cf->args->nelts == 1) { + return NGX_CONF_OK; + } + + value = cf->args->elts; + + if (ngx_strcmp(value[1].data, "two") == 0) { + rcf->two = 1; + + } else { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid parameter \"%V\"", &value[1]); + return NGX_CONF_ERROR; + } + + if (cf->args->nelts == 2) { + return NGX_CONF_OK; + } + + if (ngx_strcmp(value[2].data, "least_conn") != 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid parameter \"%V\"", &value[2]); + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} diff --git a/src/http/modules/ngx_http_userid_filter_module.c b/src/http/modules/ngx_http_userid_filter_module.c index a1a5493..31cf402 100644 --- a/src/http/modules/ngx_http_userid_filter_module.c +++ b/src/http/modules/ngx_http_userid_filter_module.c @@ -545,6 +545,13 @@ ngx_http_userid_create_uid(ngx_http_request_t *r, ngx_http_userid_ctx_t *ctx, break; #endif + +#if (NGX_HAVE_UNIX_DOMAIN) + case AF_UNIX: + ctx->uid_set[0] = 0; + break; +#endif + default: /* AF_INET */ sin = (struct sockaddr_in *) c->local_sockaddr; ctx->uid_set[0] = sin->sin_addr.s_addr; diff --git a/src/http/modules/ngx_http_uwsgi_module.c b/src/http/modules/ngx_http_uwsgi_module.c index 238bcf8..56dc236 100644 --- a/src/http/modules/ngx_http_uwsgi_module.c +++ b/src/http/modules/ngx_http_uwsgi_module.c @@ -204,6 +204,13 @@ static ngx_command_t ngx_http_uwsgi_commands[] = { offsetof(ngx_http_uwsgi_loc_conf_t, upstream.local), NULL }, + { ngx_string("uwsgi_socket_keepalive"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_uwsgi_loc_conf_t, upstream.socket_keepalive), + NULL }, + { ngx_string("uwsgi_connect_timeout"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_msec_slot, @@ -954,12 +961,18 @@ ngx_http_uwsgi_create_request(ngx_http_request_t *r) #if 0 /* allow custom uwsgi packet */ if (len > 0 && len < 2) { - ngx_log_error (NGX_LOG_ALERT, r->connection->log, 0, - "uwsgi request is too little: %uz", len); + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "uwsgi request is too little: %uz", len); return NGX_ERROR; } #endif + if (len > 65535) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "uwsgi request is too big: %uz", len); + return NGX_ERROR; + } + b = ngx_create_temp_buf(r->pool, len + 4); if (b == NULL) { return NGX_ERROR; @@ -1407,6 +1420,7 @@ ngx_http_uwsgi_create_loc_conf(ngx_conf_t *cf) conf->upstream.force_ranges = NGX_CONF_UNSET; conf->upstream.local = NGX_CONF_UNSET_PTR; + conf->upstream.socket_keepalive = NGX_CONF_UNSET; conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC; conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC; @@ -1513,6 +1527,9 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_ptr_value(conf->upstream.local, prev->upstream.local, NULL); + ngx_conf_merge_value(conf->upstream.socket_keepalive, + prev->upstream.socket_keepalive, 0); + ngx_conf_merge_msec_value(conf->upstream.connect_timeout, prev->upstream.connect_timeout, 60000); @@ -2144,7 +2161,7 @@ ngx_http_uwsgi_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return NGX_CONF_ERROR; } - if (clcf->name.data[clcf->name.len - 1] == '/') { + if (clcf->name.len && clcf->name.data[clcf->name.len - 1] == '/') { clcf->auto_redirect = 1; } @@ -2342,6 +2359,7 @@ ngx_http_uwsgi_set_ssl(ngx_conf_t *cf, ngx_http_uwsgi_loc_conf_t *uwcf) cln = ngx_pool_cleanup_add(cf->pool, 0); if (cln == NULL) { + ngx_ssl_cleanup_ctx(uwcf->upstream.ssl); return NGX_ERROR; } @@ -2391,6 +2409,13 @@ ngx_http_uwsgi_set_ssl(ngx_conf_t *cf, ngx_http_uwsgi_loc_conf_t *uwcf) } } + if (ngx_ssl_client_session_cache(cf, uwcf->upstream.ssl, + uwcf->upstream.ssl_session_reuse) + != NGX_OK) + { + return NGX_ERROR; + } + return NGX_OK; } diff --git a/src/http/ngx_http.c b/src/http/ngx_http.c index 9d8b6d7..79ef9c6 100644 --- a/src/http/ngx_http.c +++ b/src/http/ngx_http.c @@ -1157,7 +1157,7 @@ ngx_http_add_listen(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, } } - sa = &lsopt->sockaddr.sockaddr; + sa = lsopt->sockaddr; p = ngx_inet_get_port(sa); port = cmcf->ports->elts; @@ -1209,8 +1209,8 @@ ngx_http_add_addresses(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, for (i = 0; i < port->addrs.nelts; i++) { - if (ngx_cmp_sockaddr(&lsopt->sockaddr.sockaddr, lsopt->socklen, - &addr[i].opt.sockaddr.sockaddr, + if (ngx_cmp_sockaddr(lsopt->sockaddr, lsopt->socklen, + addr[i].opt.sockaddr, addr[i].opt.socklen, 0) != NGX_OK) { @@ -1239,7 +1239,8 @@ ngx_http_add_addresses(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, if (addr[i].opt.set) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "duplicate listen options for %s", addr[i].opt.addr); + "duplicate listen options for %V", + &addr[i].opt.addr_text); return NGX_ERROR; } @@ -1252,7 +1253,8 @@ ngx_http_add_addresses(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, if (default_server) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "a duplicate default server for %s", addr[i].opt.addr); + "a duplicate default server for %V", + &addr[i].opt.addr_text); return NGX_ERROR; } @@ -1305,8 +1307,8 @@ ngx_http_add_address(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, if (lsopt->http2 && lsopt->ssl) { ngx_conf_log_error(NGX_LOG_WARN, cf, 0, "nginx was built with OpenSSL that lacks ALPN " - "and NPN support, HTTP/2 is not enabled for %s", - lsopt->addr); + "and NPN support, HTTP/2 is not enabled for %V", + &lsopt->addr_text); } #endif @@ -1354,7 +1356,8 @@ ngx_http_add_server(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, for (i = 0; i < addr->servers.nelts; i++) { if (server[i] == cscf) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "a duplicate listen %s", addr->opt.addr); + "a duplicate listen %V", + &addr->opt.addr_text); return NGX_ERROR; } } @@ -1471,15 +1474,15 @@ ngx_http_server_names(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf, if (rc == NGX_DECLINED) { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, - "invalid server name or wildcard \"%V\" on %s", - &name[n].name, addr->opt.addr); + "invalid server name or wildcard \"%V\" on %V", + &name[n].name, &addr->opt.addr_text); return NGX_ERROR; } if (rc == NGX_BUSY) { ngx_log_error(NGX_LOG_WARN, cf->log, 0, - "conflicting server name \"%V\" on %s, ignored", - &name[n].name, addr->opt.addr); + "conflicting server name \"%V\" on %V, ignored", + &name[n].name, &addr->opt.addr_text); } } } @@ -1685,10 +1688,6 @@ ngx_http_init_listening(ngx_conf_t *cf, ngx_http_conf_port_t *port) break; } - if (ngx_clone_listening(cf, ls) != NGX_OK) { - return NGX_ERROR; - } - addr++; last--; } @@ -1704,8 +1703,7 @@ ngx_http_add_listening(ngx_conf_t *cf, ngx_http_conf_addr_t *addr) ngx_http_core_loc_conf_t *clcf; ngx_http_core_srv_conf_t *cscf; - ls = ngx_create_listening(cf, &addr->opt.sockaddr.sockaddr, - addr->opt.socklen); + ls = ngx_create_listening(cf, addr->opt.sockaddr, addr->opt.socklen); if (ls == NULL) { return NULL; } @@ -1795,7 +1793,7 @@ ngx_http_add_addrs(ngx_conf_t *cf, ngx_http_port_t *hport, for (i = 0; i < hport->naddrs; i++) { - sin = &addr[i].opt.sockaddr.sockaddr_in; + sin = (struct sockaddr_in *) addr[i].opt.sockaddr; addrs[i].addr = sin->sin_addr.s_addr; addrs[i].conf.default_server = addr[i].default_server; #if (NGX_HTTP_SSL) @@ -1860,7 +1858,7 @@ ngx_http_add_addrs6(ngx_conf_t *cf, ngx_http_port_t *hport, for (i = 0; i < hport->naddrs; i++) { - sin6 = &addr[i].opt.sockaddr.sockaddr_in6; + sin6 = (struct sockaddr_in6 *) addr[i].opt.sockaddr; addrs6[i].addr6 = sin6->sin6_addr; addrs6[i].conf.default_server = addr[i].default_server; #if (NGX_HTTP_SSL) diff --git a/src/http/ngx_http.h b/src/http/ngx_http.h index afab4f6..8b43857 100644 --- a/src/http/ngx_http.h +++ b/src/http/ngx_http.h @@ -88,6 +88,10 @@ void ngx_http_close_connection(ngx_connection_t *c); #if (NGX_HTTP_SSL && defined SSL_CTRL_SET_TLSEXT_HOSTNAME) int ngx_http_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg); #endif +#if (NGX_HTTP_SSL && defined SSL_R_CERT_CB_ERROR) +int ngx_http_ssl_certificate(ngx_ssl_conn_t *ssl_conn, void *arg); +#endif + ngx_int_t ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b); ngx_int_t ngx_http_parse_uri(ngx_http_request_t *r); diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c index 6b318dd..cb49ef7 100644 --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -2318,6 +2318,7 @@ ngx_http_subrequest(ngx_http_request_t *r, sr->unparsed_uri = r->unparsed_uri; sr->method_name = ngx_http_core_get_method; sr->http_protocol = r->http_protocol; + sr->schema = r->schema; ngx_http_set_exten(sr); @@ -2385,6 +2386,14 @@ ngx_http_subrequest(ngx_http_request_t *r, sr->phase_handler = r->phase_handler; sr->write_event_handler = ngx_http_core_run_phases; +#if (NGX_PCRE) + sr->ncaptures = r->ncaptures; + sr->captures = r->captures; + sr->captures_data = r->captures_data; + sr->realloc_captures = 1; + r->realloc_captures = 1; +#endif + ngx_http_update_location_config(sr); } @@ -2706,6 +2715,8 @@ ngx_http_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy) { char *rv; void *mconf; + size_t len; + u_char *p; ngx_uint_t i; ngx_conf_t pcf; ngx_http_module_t *module; @@ -2793,7 +2804,14 @@ ngx_http_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy) if (rv == NGX_CONF_OK && !cscf->listen) { ngx_memzero(&lsopt, sizeof(ngx_http_listen_opt_t)); - sin = &lsopt.sockaddr.sockaddr_in; + p = ngx_pcalloc(cf->pool, sizeof(struct sockaddr_in)); + if (p == NULL) { + return NGX_CONF_ERROR; + } + + lsopt.sockaddr = (struct sockaddr *) p; + + sin = (struct sockaddr_in *) p; sin->sin_family = AF_INET; #if (NGX_WIN32) @@ -2816,8 +2834,16 @@ ngx_http_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy) #endif lsopt.wildcard = 1; - (void) ngx_sock_ntop(&lsopt.sockaddr.sockaddr, lsopt.socklen, - lsopt.addr, NGX_SOCKADDR_STRLEN, 1); + len = NGX_INET_ADDRSTRLEN + sizeof(":65535") - 1; + + p = ngx_pnalloc(cf->pool, len); + if (p == NULL) { + return NGX_CONF_ERROR; + } + + lsopt.addr_text.data = p; + lsopt.addr_text.len = ngx_sock_ntop(lsopt.sockaddr, lsopt.socklen, p, + len, 1); if (ngx_http_add_listen(cf, cscf, &lsopt) != NGX_OK) { return NGX_CONF_ERROR; @@ -3256,6 +3282,9 @@ ngx_http_core_create_srv_conf(ngx_conf_t *cf) cscf->merge_slashes = NGX_CONF_UNSET; cscf->underscores_in_headers = NGX_CONF_UNSET; + cscf->file_name = cf->conf_file->file.name.data; + cscf->line = cf->conf_file->line; + return cscf; } @@ -3767,9 +3796,6 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_memzero(&lsopt, sizeof(ngx_http_listen_opt_t)); - ngx_memcpy(&lsopt.sockaddr.sockaddr, &u.sockaddr, u.socklen); - - lsopt.socklen = u.socklen; lsopt.backlog = NGX_LISTEN_BACKLOG; lsopt.rcvbuf = -1; lsopt.sndbuf = -1; @@ -3779,14 +3805,10 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) #if (NGX_HAVE_TCP_FASTOPEN) lsopt.fastopen = -1; #endif - lsopt.wildcard = u.wildcard; #if (NGX_HAVE_INET6) lsopt.ipv6only = 1; #endif - (void) ngx_sock_ntop(&lsopt.sockaddr.sockaddr, lsopt.socklen, lsopt.addr, - NGX_SOCKADDR_STRLEN, 1); - for (n = 2; n < cf->args->nelts; n++) { if (ngx_strcmp(value[n].data, "default_server") == 0 @@ -3911,34 +3933,22 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) if (ngx_strncmp(value[n].data, "ipv6only=o", 10) == 0) { #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) - struct sockaddr *sa; + if (ngx_strcmp(&value[n].data[10], "n") == 0) { + lsopt.ipv6only = 1; - sa = &lsopt.sockaddr.sockaddr; - - if (sa->sa_family == AF_INET6) { - - if (ngx_strcmp(&value[n].data[10], "n") == 0) { - lsopt.ipv6only = 1; - - } else if (ngx_strcmp(&value[n].data[10], "ff") == 0) { - lsopt.ipv6only = 0; - - } else { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid ipv6only flags \"%s\"", - &value[n].data[9]); - return NGX_CONF_ERROR; - } - - lsopt.set = 1; - lsopt.bind = 1; + } else if (ngx_strcmp(&value[n].data[10], "ff") == 0) { + lsopt.ipv6only = 0; } else { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "ipv6only is not supported " - "on addr \"%s\", ignored", lsopt.addr); + "invalid ipv6only flags \"%s\"", + &value[n].data[9]); + return NGX_CONF_ERROR; } + lsopt.set = 1; + lsopt.bind = 1; + continue; #else ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, @@ -4094,11 +4104,18 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return NGX_CONF_ERROR; } - if (ngx_http_add_listen(cf, cscf, &lsopt) == NGX_OK) { - return NGX_CONF_OK; + for (n = 0; n < u.naddrs; n++) { + lsopt.sockaddr = u.addrs[n].sockaddr; + lsopt.socklen = u.addrs[n].socklen; + lsopt.addr_text = u.addrs[n].name; + lsopt.wildcard = ngx_inet_wildcard(lsopt.sockaddr); + + if (ngx_http_add_listen(cf, cscf, &lsopt) != NGX_OK) { + return NGX_CONF_ERROR; + } } - return NGX_CONF_ERROR; + return NGX_CONF_OK; } diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h index d798504..85f6d66 100644 --- a/src/http/ngx_http_core_module.h +++ b/src/http/ngx_http_core_module.h @@ -65,8 +65,9 @@ typedef struct ngx_http_core_loc_conf_s ngx_http_core_loc_conf_t; typedef struct { - ngx_sockaddr_t sockaddr; + struct sockaddr *sockaddr; socklen_t socklen; + ngx_str_t addr_text; unsigned set:1; unsigned default_server:1; @@ -100,8 +101,6 @@ typedef struct { #if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER) char *accept_filter; #endif - - u_char addr[NGX_SOCKADDR_STRLEN + 1]; } ngx_http_listen_opt_t; @@ -184,6 +183,9 @@ typedef struct { /* server ctx */ ngx_http_conf_ctx_t *ctx; + u_char *file_name; + ngx_uint_t line; + ngx_str_t server_name; size_t connection_pool_size; diff --git a/src/http/ngx_http_file_cache.c b/src/http/ngx_http_file_cache.c index 3b2b68a..ecdf11e 100644 --- a/src/http/ngx_http_file_cache.c +++ b/src/http/ngx_http_file_cache.c @@ -2418,23 +2418,32 @@ ngx_http_file_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) p = (u_char *) ngx_strchr(name.data, ':'); - if (p) { - name.len = p - name.data; - - p++; - - s.len = value[i].data + value[i].len - p; - s.data = p; - - size = ngx_parse_size(&s); - if (size > 8191) { - continue; - } + if (p == NULL) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid keys zone size \"%V\"", &value[i]); + return NGX_CONF_ERROR; } - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid keys zone size \"%V\"", &value[i]); - return NGX_CONF_ERROR; + name.len = p - name.data; + + s.data = p + 1; + s.len = value[i].data + value[i].len - s.data; + + size = ngx_parse_size(&s); + + if (size == NGX_ERROR) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid keys zone size \"%V\"", &value[i]); + return NGX_CONF_ERROR; + } + + if (size < (ssize_t) (2 * ngx_pagesize)) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "keys zone \"%V\" is too small", &value[i]); + return NGX_CONF_ERROR; + } + + continue; } if (ngx_strncmp(value[i].data, "inactive=", 9) == 0) { @@ -2620,7 +2629,8 @@ ngx_http_file_cache_valid_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, time_t valid; ngx_str_t *value; - ngx_uint_t i, n, status; + ngx_int_t status; + ngx_uint_t i, n; ngx_array_t **a; ngx_http_cache_valid_t *v; static ngx_uint_t statuses[] = { 200, 301, 302 }; @@ -2668,7 +2678,7 @@ ngx_http_file_cache_valid_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, } else { status = ngx_atoi(value[i].data, value[i].len); - if (status < 100) { + if (status < 100 || status > 599) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid status \"%V\"", &value[i]); return NGX_CONF_ERROR; diff --git a/src/http/ngx_http_parse.c b/src/http/ngx_http_parse.c index 844054c..d9a1dbe 100644 --- a/src/http/ngx_http_parse.c +++ b/src/http/ngx_http_parse.c @@ -307,6 +307,11 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) break; } + if ((ch >= '0' && ch <= '9') || ch == '+' || ch == '-' || ch == '.') + { + break; + } + switch (ch) { case ':': r->schema_end = p; diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index c88c271..80c1965 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -11,6 +11,7 @@ static void ngx_http_wait_request_handler(ngx_event_t *ev); +static ngx_http_request_t *ngx_http_alloc_request(ngx_connection_t *c); static void ngx_http_process_request_line(ngx_event_t *rev); static void ngx_http_process_request_headers(ngx_event_t *rev); static ssize_t ngx_http_read_request_header(ngx_http_request_t *r); @@ -336,19 +337,8 @@ ngx_http_init_connection(ngx_connection_t *c) sscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_ssl_module); if (sscf->enable || hc->addr_conf->ssl) { - - c->log->action = "SSL handshaking"; - - if (hc->addr_conf->ssl && sscf->ssl.ctx == NULL) { - ngx_log_error(NGX_LOG_ERR, c->log, 0, - "no \"ssl_certificate\" is defined " - "in server listening on SSL port"); - ngx_http_close_connection(c); - return; - } - hc->ssl = 1; - + c->log->action = "SSL handshaking"; rev->handler = ngx_http_ssl_handshake; } } @@ -513,18 +503,46 @@ ngx_http_wait_request_handler(ngx_event_t *rev) ngx_http_request_t * ngx_http_create_request(ngx_connection_t *c) +{ + ngx_http_request_t *r; + ngx_http_log_ctx_t *ctx; + ngx_http_core_loc_conf_t *clcf; + + r = ngx_http_alloc_request(c); + if (r == NULL) { + return NULL; + } + + c->requests++; + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + ngx_set_connection_log(c, clcf->error_log); + + ctx = c->log->data; + ctx->request = r; + ctx->current_request = r; + +#if (NGX_STAT_STUB) + (void) ngx_atomic_fetch_add(ngx_stat_reading, 1); + r->stat_reading = 1; + (void) ngx_atomic_fetch_add(ngx_stat_requests, 1); +#endif + + return r; +} + + +static ngx_http_request_t * +ngx_http_alloc_request(ngx_connection_t *c) { ngx_pool_t *pool; ngx_time_t *tp; ngx_http_request_t *r; - ngx_http_log_ctx_t *ctx; ngx_http_connection_t *hc; ngx_http_core_srv_conf_t *cscf; - ngx_http_core_loc_conf_t *clcf; ngx_http_core_main_conf_t *cmcf; - c->requests++; - hc = c->data; cscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_core_module); @@ -552,10 +570,6 @@ ngx_http_create_request(ngx_connection_t *c) r->read_event_handler = ngx_http_block_reading; - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - - ngx_set_connection_log(r->connection, clcf->error_log); - r->header_in = hc->busy ? hc->busy->buf : c->buffer; if (ngx_list_init(&r->headers_out.headers, r->pool, 20, @@ -615,17 +629,8 @@ ngx_http_create_request(ngx_connection_t *c) r->http_state = NGX_HTTP_READING_REQUEST_STATE; - ctx = c->log->data; - ctx->request = r; - ctx->current_request = r; r->log_handler = ngx_http_log_error_handler; -#if (NGX_STAT_STUB) - (void) ngx_atomic_fetch_add(ngx_stat_reading, 1); - r->stat_reading = 1; - (void) ngx_atomic_fetch_add(ngx_stat_requests, 1); -#endif - return r; } @@ -844,11 +849,13 @@ ngx_http_ssl_handshake_handler(ngx_connection_t *c) ngx_http_close_connection(c); } + #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME int ngx_http_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg) { + ngx_int_t rc; ngx_str_t host; const char *servername; ngx_connection_t *c; @@ -857,16 +864,17 @@ ngx_http_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg) ngx_http_core_loc_conf_t *clcf; ngx_http_core_srv_conf_t *cscf; + c = ngx_ssl_get_connection(ssl_conn); + + if (c->ssl->handshaked) { + *ad = SSL_AD_NO_RENEGOTIATION; + return SSL_TLSEXT_ERR_ALERT_FATAL; + } + servername = SSL_get_servername(ssl_conn, TLSEXT_NAMETYPE_host_name); if (servername == NULL) { - return SSL_TLSEXT_ERR_NOACK; - } - - c = ngx_ssl_get_connection(ssl_conn); - - if (c->ssl->renegotiation) { - return SSL_TLSEXT_ERR_NOACK; + return SSL_TLSEXT_ERR_OK; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, @@ -875,27 +883,40 @@ ngx_http_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg) host.len = ngx_strlen(servername); if (host.len == 0) { - return SSL_TLSEXT_ERR_NOACK; + return SSL_TLSEXT_ERR_OK; } host.data = (u_char *) servername; - if (ngx_http_validate_host(&host, c->pool, 1) != NGX_OK) { - return SSL_TLSEXT_ERR_NOACK; + rc = ngx_http_validate_host(&host, c->pool, 1); + + if (rc == NGX_ERROR) { + *ad = SSL_AD_INTERNAL_ERROR; + return SSL_TLSEXT_ERR_ALERT_FATAL; + } + + if (rc == NGX_DECLINED) { + return SSL_TLSEXT_ERR_OK; } hc = c->data; - if (ngx_http_find_virtual_server(c, hc->addr_conf->virtual_names, &host, - NULL, &cscf) - != NGX_OK) - { - return SSL_TLSEXT_ERR_NOACK; + rc = ngx_http_find_virtual_server(c, hc->addr_conf->virtual_names, &host, + NULL, &cscf); + + if (rc == NGX_ERROR) { + *ad = SSL_AD_INTERNAL_ERROR; + return SSL_TLSEXT_ERR_ALERT_FATAL; + } + + if (rc == NGX_DECLINED) { + return SSL_TLSEXT_ERR_OK; } hc->ssl_servername = ngx_palloc(c->pool, sizeof(ngx_str_t)); if (hc->ssl_servername == NULL) { - return SSL_TLSEXT_ERR_NOACK; + *ad = SSL_AD_INTERNAL_ERROR; + return SSL_TLSEXT_ERR_ALERT_FATAL; } *hc->ssl_servername = host; @@ -930,6 +951,10 @@ ngx_http_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg) #endif SSL_set_options(ssl_conn, SSL_CTX_get_options(sscf->ssl.ctx)); + +#ifdef SSL_OP_NO_RENEGOTIATION + SSL_set_options(ssl_conn, SSL_OP_NO_RENEGOTIATION); +#endif } return SSL_TLSEXT_ERR_OK; @@ -937,6 +962,75 @@ ngx_http_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg) #endif + +#ifdef SSL_R_CERT_CB_ERROR + +int +ngx_http_ssl_certificate(ngx_ssl_conn_t *ssl_conn, void *arg) +{ + ngx_str_t cert, key; + ngx_uint_t i, nelts; + ngx_connection_t *c; + ngx_http_request_t *r; + ngx_http_ssl_srv_conf_t *sscf; + ngx_http_complex_value_t *certs, *keys; + + c = ngx_ssl_get_connection(ssl_conn); + + if (c->ssl->handshaked) { + return 0; + } + + r = ngx_http_alloc_request(c); + if (r == NULL) { + return 0; + } + + r->logged = 1; + + sscf = arg; + + nelts = sscf->certificate_values->nelts; + certs = sscf->certificate_values->elts; + keys = sscf->certificate_key_values->elts; + + for (i = 0; i < nelts; i++) { + + if (ngx_http_complex_value(r, &certs[i], &cert) != NGX_OK) { + goto failed; + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "ssl cert: \"%s\"", cert.data); + + if (ngx_http_complex_value(r, &keys[i], &key) != NGX_OK) { + goto failed; + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "ssl key: \"%s\"", key.data); + + if (ngx_ssl_connection_certificate(c, r->pool, &cert, &key, + sscf->passwords) + != NGX_OK) + { + goto failed; + } + } + + ngx_http_free_request(r, 0); + c->destroyed = 0; + return 1; + +failed: + + ngx_http_free_request(r, 0); + c->destroyed = 0; + return 0; +} + +#endif + #endif @@ -970,7 +1064,7 @@ ngx_http_process_request_line(ngx_event_t *rev) n = ngx_http_read_request_header(r); if (n == NGX_AGAIN || n == NGX_ERROR) { - return; + break; } } @@ -995,10 +1089,15 @@ ngx_http_process_request_line(ngx_event_t *rev) } if (ngx_http_process_request_uri(r) != NGX_OK) { - return; + break; } - if (r->host_start && r->host_end) { + if (r->schema_end) { + r->schema.len = r->schema_end - r->schema_start; + r->schema.data = r->schema_start; + } + + if (r->host_end) { host.len = r->host_end - r->host_start; host.data = r->host_start; @@ -1009,16 +1108,16 @@ ngx_http_process_request_line(ngx_event_t *rev) ngx_log_error(NGX_LOG_INFO, c->log, 0, "client sent invalid host in request line"); ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); - return; + break; } if (rc == NGX_ERROR) { ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); - return; + break; } if (ngx_http_set_virtual_server(r, &host) == NGX_ERROR) { - return; + break; } r->headers_in.server = host; @@ -1030,11 +1129,11 @@ ngx_http_process_request_line(ngx_event_t *rev) && ngx_http_set_virtual_server(r, &r->headers_in.server) == NGX_ERROR) { - return; + break; } ngx_http_process_request(r); - return; + break; } @@ -1043,7 +1142,7 @@ ngx_http_process_request_line(ngx_event_t *rev) != NGX_OK) { ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); - return; + break; } c->log->action = "reading client request headers"; @@ -1051,7 +1150,7 @@ ngx_http_process_request_line(ngx_event_t *rev) rev->handler = ngx_http_process_request_headers; ngx_http_process_request_headers(rev); - return; + break; } if (rc != NGX_AGAIN) { @@ -1068,7 +1167,7 @@ ngx_http_process_request_line(ngx_event_t *rev) ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); } - return; + break; } /* NGX_AGAIN: a request line parsing is still incomplete */ @@ -1079,7 +1178,7 @@ ngx_http_process_request_line(ngx_event_t *rev) if (rv == NGX_ERROR) { ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); - return; + break; } if (rv == NGX_DECLINED) { @@ -1089,10 +1188,12 @@ ngx_http_process_request_line(ngx_event_t *rev) ngx_log_error(NGX_LOG_INFO, c->log, 0, "client sent too long URI"); ngx_http_finalize_request(r, NGX_HTTP_REQUEST_URI_TOO_LARGE); - return; + break; } } } + + ngx_http_run_posted_requests(c); } @@ -1254,7 +1355,7 @@ ngx_http_process_request_headers(ngx_event_t *rev) if (rv == NGX_ERROR) { ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); - return; + break; } if (rv == NGX_DECLINED) { @@ -1267,7 +1368,7 @@ ngx_http_process_request_headers(ngx_event_t *rev) "client sent too large request"); ngx_http_finalize_request(r, NGX_HTTP_REQUEST_HEADER_TOO_LARGE); - return; + break; } len = r->header_in->end - p; @@ -1282,14 +1383,14 @@ ngx_http_process_request_headers(ngx_event_t *rev) ngx_http_finalize_request(r, NGX_HTTP_REQUEST_HEADER_TOO_LARGE); - return; + break; } } n = ngx_http_read_request_header(r); if (n == NGX_AGAIN || n == NGX_ERROR) { - return; + break; } } @@ -1319,7 +1420,7 @@ ngx_http_process_request_headers(ngx_event_t *rev) h = ngx_list_push(&r->headers_in.headers); if (h == NULL) { ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); - return; + break; } h->hash = r->header_hash; @@ -1335,7 +1436,7 @@ ngx_http_process_request_headers(ngx_event_t *rev) h->lowcase_key = ngx_pnalloc(r->pool, h->key.len); if (h->lowcase_key == NULL) { ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); - return; + break; } if (h->key.len == r->lowcase_index) { @@ -1349,7 +1450,7 @@ ngx_http_process_request_headers(ngx_event_t *rev) h->lowcase_key, h->key.len); if (hh && hh->handler(r, h, hh->offset) != NGX_OK) { - return; + break; } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, @@ -1373,12 +1474,12 @@ ngx_http_process_request_headers(ngx_event_t *rev) rc = ngx_http_process_request_header(r); if (rc != NGX_OK) { - return; + break; } ngx_http_process_request(r); - return; + break; } if (rc == NGX_AGAIN) { @@ -1394,8 +1495,10 @@ ngx_http_process_request_headers(ngx_event_t *rev) "client sent invalid header line"); ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); - return; + break; } + + ngx_http_run_posted_requests(c); } @@ -1950,8 +2053,6 @@ ngx_http_process_request(ngx_http_request_t *r) r->read_event_handler = ngx_http_block_reading; ngx_http_handler(r); - - ngx_http_run_posted_requests(c); } @@ -2359,6 +2460,7 @@ ngx_http_finalize_request(ngx_http_request_t *r, ngx_int_t rc) || rc == NGX_HTTP_NO_CONTENT) { if (rc == NGX_HTTP_CLOSE) { + c->timedout = 1; ngx_http_terminate_request(r, rc); return; } @@ -3316,6 +3418,10 @@ ngx_http_lingering_close_handler(ngx_event_t *rev) ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "lingering read: %z", n); + if (n == NGX_AGAIN) { + break; + } + if (n == NGX_ERROR || n == 0) { ngx_http_close_request(r, 0); return; @@ -3508,9 +3614,11 @@ ngx_http_free_request(ngx_http_request_t *r, ngx_int_t rc) r->headers_out.status = rc; } - log->action = "logging request"; + if (!r->logged) { + log->action = "logging request"; - ngx_http_log_request(r); + ngx_http_log_request(r); + } log->action = "closing request"; diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h index 39baa0f..fce70ef 100644 --- a/src/http/ngx_http_request.h +++ b/src/http/ngx_http_request.h @@ -412,6 +412,7 @@ struct ngx_http_request_s { ngx_str_t method_name; ngx_str_t http_protocol; + ngx_str_t schema; ngx_chain_t *out; ngx_http_request_t *main; @@ -498,6 +499,10 @@ struct ngx_http_request_s { unsigned gzip_vary:1; #endif +#if (NGX_PCRE) + unsigned realloc_captures:1; +#endif + unsigned proxy:1; unsigned bypass_cache:1; unsigned no_cache:1; diff --git a/src/http/ngx_http_script.c b/src/http/ngx_http_script.c index 1a87735..4153889 100644 --- a/src/http/ngx_http_script.c +++ b/src/http/ngx_http_script.c @@ -271,6 +271,34 @@ ngx_http_test_predicates(ngx_http_request_t *r, ngx_array_t *predicates) } +ngx_int_t +ngx_http_test_required_predicates(ngx_http_request_t *r, + ngx_array_t *predicates) +{ + ngx_str_t val; + ngx_uint_t i; + ngx_http_complex_value_t *cv; + + if (predicates == NULL) { + return NGX_OK; + } + + cv = predicates->elts; + + for (i = 0; i < predicates->nelts; i++) { + if (ngx_http_complex_value(r, &cv[i], &val) != NGX_OK) { + return NGX_ERROR; + } + + if (val.len == 0 || (val.len == 1 && val.data[0] == '0')) { + return NGX_DECLINED; + } + } + + return NGX_OK; +} + + char * ngx_http_set_predicate_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { diff --git a/src/http/ngx_http_script.h b/src/http/ngx_http_script.h index a5116d7..25bb6d7 100644 --- a/src/http/ngx_http_script.h +++ b/src/http/ngx_http_script.h @@ -214,6 +214,8 @@ char *ngx_http_set_complex_value_slot(ngx_conf_t *cf, ngx_command_t *cmd, ngx_int_t ngx_http_test_predicates(ngx_http_request_t *r, ngx_array_t *predicates); +ngx_int_t ngx_http_test_required_predicates(ngx_http_request_t *r, + ngx_array_t *predicates); char *ngx_http_set_predicate_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); diff --git a/src/http/ngx_http_special_response.c b/src/http/ngx_http_special_response.c index 2c1ff17..4ffb2cc 100644 --- a/src/http/ngx_http_special_response.c +++ b/src/http/ngx_http_special_response.c @@ -60,7 +60,7 @@ static u_char ngx_http_msie_refresh_tail[] = static char ngx_http_error_301_page[] = "" CRLF "301 Moved Permanently" CRLF -"" CRLF +"" CRLF "

301 Moved Permanently

" CRLF ; @@ -68,7 +68,7 @@ static char ngx_http_error_301_page[] = static char ngx_http_error_302_page[] = "" CRLF "302 Found" CRLF -"" CRLF +"" CRLF "

302 Found

" CRLF ; @@ -76,7 +76,7 @@ static char ngx_http_error_302_page[] = static char ngx_http_error_303_page[] = "" CRLF "303 See Other" CRLF -"" CRLF +"" CRLF "

303 See Other

" CRLF ; @@ -84,7 +84,7 @@ static char ngx_http_error_303_page[] = static char ngx_http_error_307_page[] = "" CRLF "307 Temporary Redirect" CRLF -"" CRLF +"" CRLF "

307 Temporary Redirect

" CRLF ; @@ -92,7 +92,7 @@ static char ngx_http_error_307_page[] = static char ngx_http_error_308_page[] = "" CRLF "308 Permanent Redirect" CRLF -"" CRLF +"" CRLF "

308 Permanent Redirect

" CRLF ; @@ -100,7 +100,7 @@ static char ngx_http_error_308_page[] = static char ngx_http_error_400_page[] = "" CRLF "400 Bad Request" CRLF -"" CRLF +"" CRLF "

400 Bad Request

" CRLF ; @@ -108,7 +108,7 @@ static char ngx_http_error_400_page[] = static char ngx_http_error_401_page[] = "" CRLF "401 Authorization Required" CRLF -"" CRLF +"" CRLF "

401 Authorization Required

" CRLF ; @@ -116,7 +116,7 @@ static char ngx_http_error_401_page[] = static char ngx_http_error_402_page[] = "" CRLF "402 Payment Required" CRLF -"" CRLF +"" CRLF "

402 Payment Required

" CRLF ; @@ -124,7 +124,7 @@ static char ngx_http_error_402_page[] = static char ngx_http_error_403_page[] = "" CRLF "403 Forbidden" CRLF -"" CRLF +"" CRLF "

403 Forbidden

" CRLF ; @@ -132,7 +132,7 @@ static char ngx_http_error_403_page[] = static char ngx_http_error_404_page[] = "" CRLF "404 Not Found" CRLF -"" CRLF +"" CRLF "

404 Not Found

" CRLF ; @@ -140,7 +140,7 @@ static char ngx_http_error_404_page[] = static char ngx_http_error_405_page[] = "" CRLF "405 Not Allowed" CRLF -"" CRLF +"" CRLF "

405 Not Allowed

" CRLF ; @@ -148,7 +148,7 @@ static char ngx_http_error_405_page[] = static char ngx_http_error_406_page[] = "" CRLF "406 Not Acceptable" CRLF -"" CRLF +"" CRLF "

406 Not Acceptable

" CRLF ; @@ -156,7 +156,7 @@ static char ngx_http_error_406_page[] = static char ngx_http_error_408_page[] = "" CRLF "408 Request Time-out" CRLF -"" CRLF +"" CRLF "

408 Request Time-out

" CRLF ; @@ -164,7 +164,7 @@ static char ngx_http_error_408_page[] = static char ngx_http_error_409_page[] = "" CRLF "409 Conflict" CRLF -"" CRLF +"" CRLF "

409 Conflict

" CRLF ; @@ -172,7 +172,7 @@ static char ngx_http_error_409_page[] = static char ngx_http_error_410_page[] = "" CRLF "410 Gone" CRLF -"" CRLF +"" CRLF "

410 Gone

" CRLF ; @@ -180,7 +180,7 @@ static char ngx_http_error_410_page[] = static char ngx_http_error_411_page[] = "" CRLF "411 Length Required" CRLF -"" CRLF +"" CRLF "

411 Length Required

" CRLF ; @@ -188,7 +188,7 @@ static char ngx_http_error_411_page[] = static char ngx_http_error_412_page[] = "" CRLF "412 Precondition Failed" CRLF -"" CRLF +"" CRLF "

412 Precondition Failed

" CRLF ; @@ -196,7 +196,7 @@ static char ngx_http_error_412_page[] = static char ngx_http_error_413_page[] = "" CRLF "413 Request Entity Too Large" CRLF -"" CRLF +"" CRLF "

413 Request Entity Too Large

" CRLF ; @@ -204,7 +204,7 @@ static char ngx_http_error_413_page[] = static char ngx_http_error_414_page[] = "" CRLF "414 Request-URI Too Large" CRLF -"" CRLF +"" CRLF "

414 Request-URI Too Large

" CRLF ; @@ -212,7 +212,7 @@ static char ngx_http_error_414_page[] = static char ngx_http_error_415_page[] = "" CRLF "415 Unsupported Media Type" CRLF -"" CRLF +"" CRLF "

415 Unsupported Media Type

" CRLF ; @@ -220,7 +220,7 @@ static char ngx_http_error_415_page[] = static char ngx_http_error_416_page[] = "" CRLF "416 Requested Range Not Satisfiable" CRLF -"" CRLF +"" CRLF "

416 Requested Range Not Satisfiable

" CRLF ; @@ -228,7 +228,7 @@ static char ngx_http_error_416_page[] = static char ngx_http_error_421_page[] = "" CRLF "421 Misdirected Request" CRLF -"" CRLF +"" CRLF "

421 Misdirected Request

" CRLF ; @@ -236,7 +236,7 @@ static char ngx_http_error_421_page[] = static char ngx_http_error_429_page[] = "" CRLF "429 Too Many Requests" CRLF -"" CRLF +"" CRLF "

429 Too Many Requests

" CRLF ; @@ -245,7 +245,7 @@ static char ngx_http_error_494_page[] = "" CRLF "400 Request Header Or Cookie Too Large" CRLF -"" CRLF +"" CRLF "

400 Bad Request

" CRLF "
Request Header Or Cookie Too Large
" CRLF ; @@ -255,7 +255,7 @@ static char ngx_http_error_495_page[] = "" CRLF "400 The SSL certificate error" CRLF -"" CRLF +"" CRLF "

400 Bad Request

" CRLF "
The SSL certificate error
" CRLF ; @@ -265,7 +265,7 @@ static char ngx_http_error_496_page[] = "" CRLF "400 No required SSL certificate was sent" CRLF -"" CRLF +"" CRLF "

400 Bad Request

" CRLF "
No required SSL certificate was sent
" CRLF ; @@ -275,7 +275,7 @@ static char ngx_http_error_497_page[] = "" CRLF "400 The plain HTTP request was sent to HTTPS port" CRLF -"" CRLF +"" CRLF "

400 Bad Request

" CRLF "
The plain HTTP request was sent to HTTPS port
" CRLF ; @@ -284,7 +284,7 @@ CRLF static char ngx_http_error_500_page[] = "" CRLF "500 Internal Server Error" CRLF -"" CRLF +"" CRLF "

500 Internal Server Error

" CRLF ; @@ -292,7 +292,7 @@ static char ngx_http_error_500_page[] = static char ngx_http_error_501_page[] = "" CRLF "501 Not Implemented" CRLF -"" CRLF +"" CRLF "

501 Not Implemented

" CRLF ; @@ -300,7 +300,7 @@ static char ngx_http_error_501_page[] = static char ngx_http_error_502_page[] = "" CRLF "502 Bad Gateway" CRLF -"" CRLF +"" CRLF "

502 Bad Gateway

" CRLF ; @@ -308,7 +308,7 @@ static char ngx_http_error_502_page[] = static char ngx_http_error_503_page[] = "" CRLF "503 Service Temporarily Unavailable" CRLF -"" CRLF +"" CRLF "

503 Service Temporarily Unavailable

" CRLF ; @@ -316,7 +316,7 @@ static char ngx_http_error_503_page[] = static char ngx_http_error_504_page[] = "" CRLF "504 Gateway Time-out" CRLF -"" CRLF +"" CRLF "

504 Gateway Time-out

" CRLF ; @@ -324,7 +324,7 @@ static char ngx_http_error_504_page[] = static char ngx_http_error_505_page[] = "" CRLF "505 HTTP Version Not Supported" CRLF -"" CRLF +"" CRLF "

505 HTTP Version Not Supported

" CRLF ; @@ -332,7 +332,7 @@ static char ngx_http_error_505_page[] = static char ngx_http_error_507_page[] = "" CRLF "507 Insufficient Storage" CRLF -"" CRLF +"" CRLF "

507 Insufficient Storage

" CRLF ; diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c index 0760dc2..a7391d0 100644 --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -187,6 +187,7 @@ static void ngx_http_upstream_ssl_init_connection(ngx_http_request_t *, static void ngx_http_upstream_ssl_handshake_handler(ngx_connection_t *c); static void ngx_http_upstream_ssl_handshake(ngx_http_request_t *, ngx_http_upstream_t *u, ngx_connection_t *c); +static void ngx_http_upstream_ssl_save_session(ngx_connection_t *c); static ngx_int_t ngx_http_upstream_ssl_name(ngx_http_request_t *r, ngx_http_upstream_t *u, ngx_connection_t *c); #endif @@ -408,6 +409,10 @@ static ngx_http_variable_t ngx_http_upstream_vars[] = { ngx_http_upstream_response_length_variable, 1, NGX_HTTP_VAR_NOCACHEABLE, 0 }, + { ngx_string("upstream_bytes_sent"), NULL, + ngx_http_upstream_response_length_variable, 2, + NGX_HTTP_VAR_NOCACHEABLE, 0 }, + #if (NGX_HTTP_CACHE) { ngx_string("upstream_cache_status"), NULL, @@ -627,6 +632,10 @@ ngx_http_upstream_init_request(ngx_http_request_t *r) return; } + if (u->conf->socket_keepalive) { + u->peer.so_keepalive = 1; + } + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); u->output.alignment = clcf->directio_alignment; @@ -841,7 +850,7 @@ ngx_http_upstream_cache(ngx_http_request_t *r, ngx_http_upstream_t *u) ngx_http_file_cache_create_key(r); - if (r->cache->header_start + 256 >= u->conf->buffer_size) { + if (r->cache->header_start + 256 > u->conf->buffer_size) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "%V_buffer_size %uz is not enough for cache key, " "it should be increased to at least %uz", @@ -1500,8 +1509,8 @@ ngx_http_upstream_connect(ngx_http_request_t *r, ngx_http_upstream_t *u) r->connection->log->action = "connecting to upstream"; - if (u->state && u->state->response_time) { - u->state->response_time = ngx_current_msec - u->state->response_time; + if (u->state && u->state->response_time == (ngx_msec_t) -1) { + u->state->response_time = ngx_current_msec - u->start_time; } u->state = ngx_array_push(r->upstream_states); @@ -1513,7 +1522,9 @@ ngx_http_upstream_connect(ngx_http_request_t *r, ngx_http_upstream_t *u) ngx_memzero(u->state, sizeof(ngx_http_upstream_state_t)); - u->state->response_time = ngx_current_msec; + u->start_time = ngx_current_msec; + + u->state->response_time = (ngx_msec_t) -1; u->state->connect_time = (ngx_msec_t) -1; u->state->header_time = (ngx_msec_t) -1; @@ -1545,6 +1556,8 @@ ngx_http_upstream_connect(ngx_http_request_t *r, ngx_http_upstream_t *u) c = u->peer.connection; + c->requests++; + c->data = r; c->write->handler = ngx_http_upstream_handler; @@ -1556,6 +1569,10 @@ ngx_http_upstream_connect(ngx_http_request_t *r, ngx_http_upstream_t *u) c->sendfile &= r->connection->sendfile; u->output.sendfile = c->sendfile; + if (r->connection->tcp_nopush == NGX_TCP_NOPUSH_DISABLED) { + c->tcp_nopush = NGX_TCP_NOPUSH_DISABLED; + } + if (c->pool == NULL) { /* we need separate pool here to be able to cache SSL connections */ @@ -1671,6 +1688,8 @@ ngx_http_upstream_ssl_init_connection(ngx_http_request_t *r, } if (u->conf->ssl_session_reuse) { + c->ssl->save_session = ngx_http_upstream_ssl_save_session; + if (u->peer.set_session(&u->peer, u->peer.data) != NGX_OK) { ngx_http_upstream_finalize_request(r, u, NGX_HTTP_INTERNAL_SERVER_ERROR); @@ -1755,10 +1774,6 @@ ngx_http_upstream_ssl_handshake(ngx_http_request_t *r, ngx_http_upstream_t *u, } } - if (u->conf->ssl_session_reuse) { - u->peer.save_session(&u->peer, u->peer.data); - } - c->write->handler = ngx_http_upstream_handler; c->read->handler = ngx_http_upstream_handler; @@ -1778,6 +1793,27 @@ failed: } +static void +ngx_http_upstream_ssl_save_session(ngx_connection_t *c) +{ + ngx_http_request_t *r; + ngx_http_upstream_t *u; + + if (c->idle) { + return; + } + + r = c->data; + + u = r->upstream; + c = r->connection; + + ngx_http_set_log_request(c->log, r); + + u->peer.save_session(&u->peer, u->peer.data); +} + + static ngx_int_t ngx_http_upstream_ssl_name(ngx_http_request_t *r, ngx_http_upstream_t *u, ngx_connection_t *c) @@ -1972,7 +2008,7 @@ ngx_http_upstream_send_request(ngx_http_request_t *r, ngx_http_upstream_t *u, "http upstream send request"); if (u->state->connect_time == (ngx_msec_t) -1) { - u->state->connect_time = ngx_current_msec - u->state->response_time; + u->state->connect_time = ngx_current_msec - u->start_time; } if (!u->request_sent && ngx_http_upstream_test_connect(c) != NGX_OK) { @@ -2109,7 +2145,7 @@ ngx_http_upstream_send_request_body(ngx_http_request_t *r, out = u->request_bufs; if (r->request_body->bufs) { - for (cl = out; cl->next; cl = out->next) { /* void */ } + for (cl = out; cl->next; cl = cl->next) { /* void */ } cl->next = r->request_body->bufs; r->request_body->bufs = NULL; } @@ -2383,7 +2419,7 @@ ngx_http_upstream_process_header(ngx_http_request_t *r, ngx_http_upstream_t *u) /* rc == NGX_OK */ - u->state->header_time = ngx_current_msec - u->state->response_time; + u->state->header_time = ngx_current_msec - u->start_time; if (u->headers_in.status_n >= NGX_HTTP_SPECIAL_RESPONSE) { @@ -4104,6 +4140,10 @@ ngx_http_upstream_next(ngx_http_request_t *r, ngx_http_upstream_t *u, if (u->peer.sockaddr) { + if (u->peer.connection) { + u->state->bytes_sent = u->peer.connection->sent; + } + if (ft_type == NGX_HTTP_UPSTREAM_FT_HTTP_403 || ft_type == NGX_HTTP_UPSTREAM_FT_HTTP_404) { @@ -4279,14 +4319,18 @@ ngx_http_upstream_finalize_request(ngx_http_request_t *r, u->resolved->ctx = NULL; } - if (u->state && u->state->response_time) { - u->state->response_time = ngx_current_msec - u->state->response_time; + if (u->state && u->state->response_time == (ngx_msec_t) -1) { + u->state->response_time = ngx_current_msec - u->start_time; if (u->pipe && u->pipe->read_length) { u->state->bytes_received += u->pipe->read_length - u->pipe->preread_size; u->state->response_length = u->pipe->read_length; } + + if (u->peer.connection) { + u->state->bytes_sent = u->peer.connection->sent; + } } u->finalize_request(r, rc); @@ -5389,18 +5433,18 @@ ngx_http_upstream_response_time_variable(ngx_http_request_t *r, state = r->upstream_states->elts; for ( ;; ) { - if (state[i].status) { - if (data == 1 && state[i].header_time != (ngx_msec_t) -1) { - ms = state[i].header_time; + if (data == 1) { + ms = state[i].header_time; - } else if (data == 2 && state[i].connect_time != (ngx_msec_t) -1) { - ms = state[i].connect_time; + } else if (data == 2) { + ms = state[i].connect_time; - } else { - ms = state[i].response_time; - } + } else { + ms = state[i].response_time; + } + if (ms != -1) { ms = ngx_max(ms, 0); p = ngx_sprintf(p, "%T.%03M", (time_t) ms / 1000, ms % 1000); @@ -5470,6 +5514,9 @@ ngx_http_upstream_response_length_variable(ngx_http_request_t *r, if (data == 1) { p = ngx_sprintf(p, "%O", state[i].bytes_received); + } else if (data == 2) { + p = ngx_sprintf(p, "%O", state[i].bytes_sent); + } else { p = ngx_sprintf(p, "%O", state[i].response_length); } diff --git a/src/http/ngx_http_upstream.h b/src/http/ngx_http_upstream.h index c2f4dc0..6079d72 100644 --- a/src/http/ngx_http_upstream.h +++ b/src/http/ngx_http_upstream.h @@ -64,6 +64,7 @@ typedef struct { ngx_msec_t queue_time; off_t response_length; off_t bytes_received; + off_t bytes_sent; ngx_str_t *peer; } ngx_http_upstream_state_t; @@ -188,6 +189,7 @@ typedef struct { ngx_array_t *pass_headers; ngx_http_upstream_local_t *local; + ngx_flag_t socket_keepalive; #if (NGX_HTTP_CACHE) ngx_shm_zone_t *cache_zone; @@ -364,7 +366,7 @@ struct ngx_http_upstream_s { ngx_int_t (*rewrite_cookie)(ngx_http_request_t *r, ngx_table_elt_t *h); - ngx_msec_t timeout; + ngx_msec_t start_time; ngx_http_upstream_state_t *state; diff --git a/src/http/ngx_http_upstream_round_robin.c b/src/http/ngx_http_upstream_round_robin.c index f6051ae..f72de3e 100644 --- a/src/http/ngx_http_upstream_round_robin.c +++ b/src/http/ngx_http_upstream_round_robin.c @@ -744,7 +744,7 @@ ngx_http_upstream_save_round_robin_peer_session(ngx_peer_connection_t *pc, if (peers->shpool) { - ssl_session = SSL_get0_session(pc->connection->ssl->connection); + ssl_session = ngx_ssl_get0_session(pc->connection); if (ssl_session == NULL) { return; diff --git a/src/http/ngx_http_variables.c b/src/http/ngx_http_variables.c index 2deb968..31321b2 100644 --- a/src/http/ngx_http_variables.c +++ b/src/http/ngx_http_variables.c @@ -2504,7 +2504,9 @@ ngx_http_regex_exec(ngx_http_request_t *r, ngx_http_regex_t *re, ngx_str_t *s) if (re->ncaptures) { len = cmcf->ncaptures; - if (r->captures == NULL) { + if (r->captures == NULL || r->realloc_captures) { + r->realloc_captures = 0; + r->captures = ngx_palloc(r->pool, len * sizeof(int)); if (r->captures == NULL) { return NGX_ERROR; diff --git a/src/http/ngx_http_write_filter_module.c b/src/http/ngx_http_write_filter_module.c index 0036231..3f18d76 100644 --- a/src/http/ngx_http_write_filter_module.c +++ b/src/http/ngx_http_write_filter_module.c @@ -80,7 +80,6 @@ ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in) cl->buf->file_pos, cl->buf->file_last - cl->buf->file_pos); -#if 1 if (ngx_buf_size(cl->buf) == 0 && !ngx_buf_special(cl->buf)) { ngx_log_error(NGX_LOG_ALERT, c->log, 0, "zero size buf in writer " @@ -98,7 +97,24 @@ ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in) ngx_debug_point(); return NGX_ERROR; } -#endif + + if (ngx_buf_size(cl->buf) < 0) { + ngx_log_error(NGX_LOG_ALERT, c->log, 0, + "negative size buf in writer " + "t:%d r:%d f:%d %p %p-%p %p %O-%O", + cl->buf->temporary, + cl->buf->recycled, + cl->buf->in_file, + cl->buf->start, + cl->buf->pos, + cl->buf->last, + cl->buf->file, + cl->buf->file_pos, + cl->buf->file_last); + + ngx_debug_point(); + return NGX_ERROR; + } size += ngx_buf_size(cl->buf); @@ -136,7 +152,6 @@ ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in) cl->buf->file_pos, cl->buf->file_last - cl->buf->file_pos); -#if 1 if (ngx_buf_size(cl->buf) == 0 && !ngx_buf_special(cl->buf)) { ngx_log_error(NGX_LOG_ALERT, c->log, 0, "zero size buf in writer " @@ -154,7 +169,24 @@ ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in) ngx_debug_point(); return NGX_ERROR; } -#endif + + if (ngx_buf_size(cl->buf) < 0) { + ngx_log_error(NGX_LOG_ALERT, c->log, 0, + "negative size buf in writer " + "t:%d r:%d f:%d %p %p-%p %p %O-%O", + cl->buf->temporary, + cl->buf->recycled, + cl->buf->in_file, + cl->buf->start, + cl->buf->pos, + cl->buf->last, + cl->buf->file, + cl->buf->file_pos, + cl->buf->file_last); + + ngx_debug_point(); + return NGX_ERROR; + } size += ngx_buf_size(cl->buf); diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c index 12214e1..e55f9ba 100644 --- a/src/http/v2/ngx_http_v2.c +++ b/src/http/v2/ngx_http_v2.c @@ -270,11 +270,10 @@ ngx_http_v2_init(ngx_event_t *rev) h2c->frame_size = NGX_HTTP_V2_DEFAULT_FRAME_SIZE; - h2c->table_update = 1; - h2scf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_v2_module); h2c->concurrent_pushes = h2scf->concurrent_pushes; + h2c->priority_limit = h2scf->concurrent_streams; h2c->pool = ngx_create_pool(h2scf->pool_size, h2c->connection->log); if (h2c->pool == NULL) { @@ -1548,6 +1547,14 @@ ngx_http_v2_state_process_header(ngx_http_v2_connection_t *h2c, u_char *pos, header->name.len = h2c->state.field_end - h2c->state.field_start; header->name.data = h2c->state.field_start; + if (header->name.len == 0) { + ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, + "client sent zero header name length"); + + return ngx_http_v2_connection_error(h2c, + NGX_HTTP_V2_PROTOCOL_ERROR); + } + return ngx_http_v2_state_field_len(h2c, pos, end); } @@ -1798,6 +1805,13 @@ ngx_http_v2_state_priority(ngx_http_v2_connection_t *h2c, u_char *pos, return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR); } + if (--h2c->priority_limit == 0) { + ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, + "client sent too many PRIORITY frames"); + + return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_ENHANCE_YOUR_CALM); + } + if (end - pos < NGX_HTTP_V2_PRIORITY_SIZE) { return ngx_http_v2_state_save(h2c, pos, end, ngx_http_v2_state_priority); @@ -2076,6 +2090,11 @@ ngx_http_v2_state_settings_params(ngx_http_v2_connection_t *h2c, u_char *pos, h2c->concurrent_pushes = ngx_min(value, h2scf->concurrent_pushes); break; + case NGX_HTTP_V2_HEADER_TABLE_SIZE_SETTING: + + h2c->table_update = 1; + break; + default: break; } @@ -2617,18 +2636,13 @@ ngx_http_v2_push_stream(ngx_http_v2_stream_t *parent, ngx_str_t *path) r->method_name = ngx_http_core_get_method; r->method = NGX_HTTP_GET; - r->schema_start = (u_char *) "https"; - -#if (NGX_HTTP_SSL) - if (fc->ssl) { - r->schema_end = r->schema_start + 5; - - } else -#endif - { - r->schema_end = r->schema_start + 4; + r->schema.data = ngx_pstrdup(pool, &parent->request->schema); + if (r->schema.data == NULL) { + goto close; } + r->schema.len = parent->request->schema.len; + value.data = ngx_pstrdup(pool, path); if (value.data == NULL) { goto close; @@ -2676,11 +2690,13 @@ error: if (rc == NGX_ABORT) { /* header handler has already finalized request */ + ngx_http_run_posted_requests(fc); return NULL; } if (rc == NGX_DECLINED) { ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); + ngx_http_run_posted_requests(fc); return NULL; } @@ -3112,6 +3128,8 @@ ngx_http_v2_create_stream(ngx_http_v2_connection_t *h2c, ngx_uint_t push) h2c->processing++; } + h2c->priority_limit += h2scf->concurrent_streams; + return stream; } @@ -3249,10 +3267,6 @@ ngx_http_v2_validate_header(ngx_http_request_t *r, ngx_http_v2_header_t *header) ngx_uint_t i; ngx_http_core_srv_conf_t *cscf; - if (header->name.len == 0) { - return NGX_ERROR; - } - r->invalid_header = 0; cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); @@ -3484,7 +3498,10 @@ ngx_http_v2_parse_method(ngx_http_request_t *r, ngx_str_t *value) static ngx_int_t ngx_http_v2_parse_scheme(ngx_http_request_t *r, ngx_str_t *value) { - if (r->schema_start) { + u_char c, ch; + ngx_uint_t i; + + if (r->schema.len) { ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "client sent duplicate :scheme header"); @@ -3498,8 +3515,27 @@ ngx_http_v2_parse_scheme(ngx_http_request_t *r, ngx_str_t *value) return NGX_DECLINED; } - r->schema_start = value->data; - r->schema_end = value->data + value->len; + for (i = 0; i < value->len; i++) { + ch = value->data[i]; + + c = (u_char) (ch | 0x20); + if (c >= 'a' && c <= 'z') { + continue; + } + + if (((ch >= '0' && ch <= '9') || ch == '+' || ch == '-' || ch == '.') + && i > 0) + { + continue; + } + + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent invalid :scheme header: \"%V\"", value); + + return NGX_DECLINED; + } + + r->schema = *value; return NGX_OK; } @@ -3562,14 +3598,14 @@ ngx_http_v2_construct_request_line(ngx_http_request_t *r) static const u_char ending[] = " HTTP/2.0"; if (r->method_name.len == 0 - || r->schema_start == NULL + || r->schema.len == 0 || r->unparsed_uri.len == 0) { if (r->method_name.len == 0) { ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "client sent no :method header"); - } else if (r->schema_start == NULL) { + } else if (r->schema.len == 0) { ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "client sent no :scheme header"); @@ -3732,18 +3768,22 @@ ngx_http_v2_construct_cookie_header(ngx_http_request_t *r) static void ngx_http_v2_run_request(ngx_http_request_t *r) { + ngx_connection_t *fc; + + fc = r->connection; + if (ngx_http_v2_construct_request_line(r) != NGX_OK) { - return; + goto failed; } if (ngx_http_v2_construct_cookie_header(r) != NGX_OK) { - return; + goto failed; } r->http_state = NGX_HTTP_PROCESS_REQUEST_STATE; if (ngx_http_process_request_header(r) != NGX_OK) { - return; + goto failed; } if (r->headers_in.content_length_n > 0 && r->stream->in_closed) { @@ -3753,7 +3793,7 @@ ngx_http_v2_run_request(ngx_http_request_t *r) r->stream->skip_data = 1; ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); - return; + goto failed; } if (r->headers_in.content_length_n == -1 && !r->stream->in_closed) { @@ -3761,6 +3801,10 @@ ngx_http_v2_run_request(ngx_http_request_t *r) } ngx_http_process_request(r); + +failed: + + ngx_http_run_posted_requests(fc); } @@ -4335,6 +4379,8 @@ ngx_http_v2_close_stream(ngx_http_v2_stream_t *stream, ngx_int_t rc) */ pool = stream->pool; + h2c->frames -= stream->frames; + ngx_http_free_request(stream->request, rc); if (pool != h2c->state.pool) { diff --git a/src/http/v2/ngx_http_v2.h b/src/http/v2/ngx_http_v2.h index bec2216..69d55d1 100644 --- a/src/http/v2/ngx_http_v2.h +++ b/src/http/v2/ngx_http_v2.h @@ -122,6 +122,7 @@ struct ngx_http_v2_connection_s { ngx_uint_t processing; ngx_uint_t frames; ngx_uint_t idle; + ngx_uint_t priority_limit; ngx_uint_t pushing; ngx_uint_t concurrent_pushes; @@ -192,6 +193,8 @@ struct ngx_http_v2_stream_s { ngx_buf_t *preread; + ngx_uint_t frames; + ngx_http_v2_out_frame_t *free_frames; ngx_chain_t *free_frame_headers; ngx_chain_t *free_bufs; diff --git a/src/http/v2/ngx_http_v2_filter_module.c b/src/http/v2/ngx_http_v2_filter_module.c index 029e8ec..7735b5b 100644 --- a/src/http/v2/ngx_http_v2_filter_module.c +++ b/src/http/v2/ngx_http_v2_filter_module.c @@ -944,15 +944,15 @@ ngx_http_v2_push_resource(ngx_http_request_t *r, ngx_str_t *path, ph = ngx_http_v2_push_headers; + len = ngx_max(r->schema.len, path->len); + if (binary[0].len) { - tmp = ngx_palloc(r->pool, path->len); + tmp = ngx_palloc(r->pool, len); if (tmp == NULL) { return NGX_ERROR; } } else { - len = path->len; - for (i = 0; i < NGX_HTTP_V2_PUSH_HEADERS; i++) { h = (ngx_table_elt_t **) ((char *) &r->headers_in + ph[i].offset); @@ -994,7 +994,7 @@ ngx_http_v2_push_resource(ngx_http_request_t *r, ngx_str_t *path, len = (h2c->table_update ? 1 : 0) + 1 + 1 + NGX_HTTP_V2_INT_OCTETS + path->len - + 1; + + 1 + NGX_HTTP_V2_INT_OCTETS + r->schema.len; for (i = 0; i < NGX_HTTP_V2_PUSH_HEADERS; i++) { len += binary[i].len; @@ -1025,18 +1025,20 @@ ngx_http_v2_push_resource(ngx_http_request_t *r, ngx_str_t *path, *pos++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_PATH_INDEX); pos = ngx_http_v2_write_value(pos, path->data, path->len, tmp); -#if (NGX_HTTP_SSL) - if (fc->ssl) { - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, fc->log, 0, - "http2 push header: \":scheme: https\""); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0, + "http2 push header: \":scheme: %V\"", &r->schema); + + if (r->schema.len == 5 && ngx_strncmp(r->schema.data, "https", 5) == 0) { *pos++ = ngx_http_v2_indexed(NGX_HTTP_V2_SCHEME_HTTPS_INDEX); - } else -#endif + } else if (r->schema.len == 4 + && ngx_strncmp(r->schema.data, "http", 4) == 0) { - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, fc->log, 0, - "http2 push header: \":scheme: http\""); *pos++ = ngx_http_v2_indexed(NGX_HTTP_V2_SCHEME_HTTP_INDEX); + + } else { + *pos++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_SCHEME_HTTP_INDEX); + pos = ngx_http_v2_write_value(pos, r->schema.data, r->schema.len, tmp); } for (i = 0; i < NGX_HTTP_V2_PUSH_HEADERS; i++) { @@ -1661,22 +1663,34 @@ static ngx_http_v2_out_frame_t * ngx_http_v2_filter_get_data_frame(ngx_http_v2_stream_t *stream, size_t len, ngx_chain_t *first, ngx_chain_t *last) { - u_char flags; - ngx_buf_t *buf; - ngx_chain_t *cl; - ngx_http_v2_out_frame_t *frame; + u_char flags; + ngx_buf_t *buf; + ngx_chain_t *cl; + ngx_http_v2_out_frame_t *frame; + ngx_http_v2_connection_t *h2c; frame = stream->free_frames; + h2c = stream->connection; if (frame) { stream->free_frames = frame->next; - } else { + } else if (h2c->frames < 10000) { frame = ngx_palloc(stream->request->pool, sizeof(ngx_http_v2_out_frame_t)); if (frame == NULL) { return NULL; } + + stream->frames++; + h2c->frames++; + + } else { + ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, + "http2 flood detected"); + + h2c->connection->error = 1; + return NULL; } flags = last->buf->last_buf ? NGX_HTTP_V2_END_STREAM_FLAG : 0; diff --git a/src/mail/ngx_mail.c b/src/mail/ngx_mail.c index 5fd5fa0..f17c2cc 100644 --- a/src/mail/ngx_mail.c +++ b/src/mail/ngx_mail.c @@ -231,7 +231,7 @@ ngx_mail_add_ports(ngx_conf_t *cf, ngx_array_t *ports, ngx_mail_conf_port_t *port; ngx_mail_conf_addr_t *addr; - sa = &listen->sockaddr.sockaddr; + sa = listen->sockaddr; p = ngx_inet_get_port(sa); port = ports->elts; @@ -316,7 +316,7 @@ ngx_mail_optimize_servers(ngx_conf_t *cf, ngx_array_t *ports) continue; } - ls = ngx_create_listening(cf, &addr[i].opt.sockaddr.sockaddr, + ls = ngx_create_listening(cf, addr[i].opt.sockaddr, addr[i].opt.socklen); if (ls == NULL) { return NGX_CONF_ERROR; @@ -384,12 +384,9 @@ static ngx_int_t ngx_mail_add_addrs(ngx_conf_t *cf, ngx_mail_port_t *mport, ngx_mail_conf_addr_t *addr) { - u_char *p; - size_t len; ngx_uint_t i; ngx_mail_in_addr_t *addrs; struct sockaddr_in *sin; - u_char buf[NGX_SOCKADDR_STRLEN]; mport->addrs = ngx_pcalloc(cf->pool, mport->naddrs * sizeof(ngx_mail_in_addr_t)); @@ -401,26 +398,14 @@ ngx_mail_add_addrs(ngx_conf_t *cf, ngx_mail_port_t *mport, for (i = 0; i < mport->naddrs; i++) { - sin = &addr[i].opt.sockaddr.sockaddr_in; + sin = (struct sockaddr_in *) addr[i].opt.sockaddr; addrs[i].addr = sin->sin_addr.s_addr; addrs[i].conf.ctx = addr[i].opt.ctx; #if (NGX_MAIL_SSL) addrs[i].conf.ssl = addr[i].opt.ssl; #endif - - len = ngx_sock_ntop(&addr[i].opt.sockaddr.sockaddr, addr[i].opt.socklen, - buf, NGX_SOCKADDR_STRLEN, 1); - - p = ngx_pnalloc(cf->pool, len); - if (p == NULL) { - return NGX_ERROR; - } - - ngx_memcpy(p, buf, len); - - addrs[i].conf.addr_text.len = len; - addrs[i].conf.addr_text.data = p; + addrs[i].conf.addr_text = addr[i].opt.addr_text; } return NGX_OK; @@ -433,12 +418,9 @@ static ngx_int_t ngx_mail_add_addrs6(ngx_conf_t *cf, ngx_mail_port_t *mport, ngx_mail_conf_addr_t *addr) { - u_char *p; - size_t len; ngx_uint_t i; ngx_mail_in6_addr_t *addrs6; struct sockaddr_in6 *sin6; - u_char buf[NGX_SOCKADDR_STRLEN]; mport->addrs = ngx_pcalloc(cf->pool, mport->naddrs * sizeof(ngx_mail_in6_addr_t)); @@ -450,26 +432,14 @@ ngx_mail_add_addrs6(ngx_conf_t *cf, ngx_mail_port_t *mport, for (i = 0; i < mport->naddrs; i++) { - sin6 = &addr[i].opt.sockaddr.sockaddr_in6; + sin6 = (struct sockaddr_in6 *) addr[i].opt.sockaddr; addrs6[i].addr6 = sin6->sin6_addr; addrs6[i].conf.ctx = addr[i].opt.ctx; #if (NGX_MAIL_SSL) addrs6[i].conf.ssl = addr[i].opt.ssl; #endif - - len = ngx_sock_ntop(&addr[i].opt.sockaddr.sockaddr, addr[i].opt.socklen, - buf, NGX_SOCKADDR_STRLEN, 1); - - p = ngx_pnalloc(cf->pool, len); - if (p == NULL) { - return NGX_ERROR; - } - - ngx_memcpy(p, buf, len); - - addrs6[i].conf.addr_text.len = len; - addrs6[i].conf.addr_text.data = p; + addrs6[i].conf.addr_text = addr[i].opt.addr_text; } return NGX_OK; diff --git a/src/mail/ngx_mail.h b/src/mail/ngx_mail.h index 6ecfefc..d904f25 100644 --- a/src/mail/ngx_mail.h +++ b/src/mail/ngx_mail.h @@ -27,8 +27,9 @@ typedef struct { typedef struct { - ngx_sockaddr_t sockaddr; + struct sockaddr *sockaddr; socklen_t socklen; + ngx_str_t addr_text; /* server ctx */ ngx_mail_conf_ctx_t *ctx; diff --git a/src/mail/ngx_mail_core_module.c b/src/mail/ngx_mail_core_module.c index 276b8ee..e16d702 100644 --- a/src/mail/ngx_mail_core_module.c +++ b/src/mail/ngx_mail_core_module.c @@ -297,8 +297,8 @@ ngx_mail_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_str_t *value, size; ngx_url_t u; - ngx_uint_t i, m; - ngx_mail_listen_t *ls; + ngx_uint_t i, n, m; + ngx_mail_listen_t *ls, *als; ngx_mail_module_t *module; ngx_mail_core_main_conf_t *cmcf; @@ -323,36 +323,16 @@ ngx_mail_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) cmcf = ngx_mail_conf_get_module_main_conf(cf, ngx_mail_core_module); - ls = cmcf->listen.elts; - - for (i = 0; i < cmcf->listen.nelts; i++) { - - if (ngx_cmp_sockaddr(&ls[i].sockaddr.sockaddr, ls[i].socklen, - (struct sockaddr *) &u.sockaddr, u.socklen, 1) - != NGX_OK) - { - continue; - } - - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "duplicate \"%V\" address and port pair", &u.url); - return NGX_CONF_ERROR; - } - - ls = ngx_array_push(&cmcf->listen); + ls = ngx_array_push_n(&cmcf->listen, u.naddrs); if (ls == NULL) { return NGX_CONF_ERROR; } ngx_memzero(ls, sizeof(ngx_mail_listen_t)); - ngx_memcpy(&ls->sockaddr.sockaddr, &u.sockaddr, u.socklen); - - ls->socklen = u.socklen; ls->backlog = NGX_LISTEN_BACKLOG; ls->rcvbuf = -1; ls->sndbuf = -1; - ls->wildcard = u.wildcard; ls->ctx = cf->ctx; #if (NGX_HAVE_INET6) @@ -434,35 +414,20 @@ ngx_mail_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) if (ngx_strncmp(value[i].data, "ipv6only=o", 10) == 0) { #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) - size_t len; - u_char buf[NGX_SOCKADDR_STRLEN]; + if (ngx_strcmp(&value[i].data[10], "n") == 0) { + ls->ipv6only = 1; - if (ls->sockaddr.sockaddr.sa_family == AF_INET6) { - - if (ngx_strcmp(&value[i].data[10], "n") == 0) { - ls->ipv6only = 1; - - } else if (ngx_strcmp(&value[i].data[10], "ff") == 0) { - ls->ipv6only = 0; - - } else { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid ipv6only flags \"%s\"", - &value[i].data[9]); - return NGX_CONF_ERROR; - } - - ls->bind = 1; + } else if (ngx_strcmp(&value[i].data[10], "ff") == 0) { + ls->ipv6only = 0; } else { - len = ngx_sock_ntop(&ls->sockaddr.sockaddr, ls->socklen, buf, - NGX_SOCKADDR_STRLEN, 1); - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "ipv6only is not supported " - "on addr \"%*s\", ignored", len, buf); + "invalid ipv6only flags \"%s\"", + &value[i].data[9]); + return NGX_CONF_ERROR; } + ls->bind = 1; continue; #else ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, @@ -474,7 +439,16 @@ ngx_mail_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) if (ngx_strcmp(value[i].data, "ssl") == 0) { #if (NGX_MAIL_SSL) + ngx_mail_ssl_conf_t *sslcf; + + sslcf = ngx_mail_conf_get_module_srv_conf(cf, ngx_mail_ssl_module); + + sslcf->listen = 1; + sslcf->file = cf->conf_file->file.name.data; + sslcf->line = cf->conf_file->line; + ls->ssl = 1; + continue; #else ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, @@ -579,6 +553,32 @@ ngx_mail_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return NGX_CONF_ERROR; } + als = cmcf->listen.elts; + + for (n = 0; n < u.naddrs; n++) { + ls[n] = ls[0]; + + ls[n].sockaddr = u.addrs[n].sockaddr; + ls[n].socklen = u.addrs[n].socklen; + ls[n].addr_text = u.addrs[n].name; + ls[n].wildcard = ngx_inet_wildcard(ls[n].sockaddr); + + for (i = 0; i < cmcf->listen.nelts - u.naddrs + n; i++) { + + if (ngx_cmp_sockaddr(als[i].sockaddr, als[i].socklen, + ls[n].sockaddr, ls[n].socklen, 1) + != NGX_OK) + { + continue; + } + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "duplicate \"%V\" address and port pair", + &ls[n].addr_text); + return NGX_CONF_ERROR; + } + } + return NGX_CONF_OK; } diff --git a/src/mail/ngx_mail_handler.c b/src/mail/ngx_mail_handler.c index bc3e6b9..803a247 100644 --- a/src/mail/ngx_mail_handler.c +++ b/src/mail/ngx_mail_handler.c @@ -165,29 +165,13 @@ ngx_mail_init_connection(ngx_connection_t *c) sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module); - if (sslcf->enable) { + if (sslcf->enable || addr_conf->ssl) { c->log->action = "SSL handshaking"; ngx_mail_ssl_init_connection(&sslcf->ssl, c); return; } - if (addr_conf->ssl) { - - c->log->action = "SSL handshaking"; - - if (sslcf->ssl.ctx == NULL) { - ngx_log_error(NGX_LOG_ERR, c->log, 0, - "no \"ssl_certificate\" is defined " - "in server listening on SSL port"); - ngx_mail_close_connection(c); - return; - } - - ngx_mail_ssl_init_connection(&sslcf->ssl, c); - return; - } - } #endif diff --git a/src/mail/ngx_mail_ssl_module.c b/src/mail/ngx_mail_ssl_module.c index aebd179..5544f75 100644 --- a/src/mail/ngx_mail_ssl_module.c +++ b/src/mail/ngx_mail_ssl_module.c @@ -56,6 +56,11 @@ static ngx_conf_enum_t ngx_mail_ssl_verify[] = { }; +static ngx_conf_deprecated_t ngx_mail_ssl_deprecated = { + ngx_conf_deprecated, "ssl", "listen ... ssl" +}; + + static ngx_command_t ngx_mail_ssl_commands[] = { { ngx_string("ssl"), @@ -63,7 +68,7 @@ static ngx_command_t ngx_mail_ssl_commands[] = { ngx_mail_ssl_enable, NGX_MAIL_SRV_CONF_OFFSET, offsetof(ngx_mail_ssl_conf_t, enable), - NULL }, + &ngx_mail_ssl_deprecated }, { ngx_string("starttls"), NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, @@ -238,6 +243,7 @@ ngx_mail_ssl_create_conf(ngx_conf_t *cf) /* * set by ngx_pcalloc(): * + * scf->listen = 0; * scf->protocols = 0; * scf->dhparam = { 0, NULL }; * scf->ecdh_curve = { 0, NULL }; @@ -313,14 +319,17 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) conf->ssl.log = cf->log; - if (conf->enable) { + if (conf->listen) { + mode = "listen ... ssl"; + + } else if (conf->enable) { mode = "ssl"; } else if (conf->starttls != NGX_MAIL_STARTTLS_OFF) { mode = "starttls"; } else { - mode = ""; + return NGX_CONF_OK; } if (conf->file == NULL) { @@ -328,51 +337,31 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) conf->line = prev->line; } - if (*mode) { + if (conf->certificates == NULL) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "no \"ssl_certificate\" is defined for " + "the \"%s\" directive in %s:%ui", + mode, conf->file, conf->line); + return NGX_CONF_ERROR; + } - if (conf->certificates == NULL) { - ngx_log_error(NGX_LOG_EMERG, cf->log, 0, - "no \"ssl_certificate\" is defined for " - "the \"%s\" directive in %s:%ui", - mode, conf->file, conf->line); - return NGX_CONF_ERROR; - } + if (conf->certificate_keys == NULL) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "no \"ssl_certificate_key\" is defined for " + "the \"%s\" directive in %s:%ui", + mode, conf->file, conf->line); + return NGX_CONF_ERROR; + } - if (conf->certificate_keys == NULL) { - ngx_log_error(NGX_LOG_EMERG, cf->log, 0, - "no \"ssl_certificate_key\" is defined for " - "the \"%s\" directive in %s:%ui", - mode, conf->file, conf->line); - return NGX_CONF_ERROR; - } - - if (conf->certificate_keys->nelts < conf->certificates->nelts) { - ngx_log_error(NGX_LOG_EMERG, cf->log, 0, - "no \"ssl_certificate_key\" is defined " - "for certificate \"%V\" and " - "the \"ssl\" directive in %s:%ui", - ((ngx_str_t *) conf->certificates->elts) - + conf->certificates->nelts - 1, - conf->file, conf->line); - return NGX_CONF_ERROR; - } - - } else { - - if (conf->certificates == NULL) { - return NGX_CONF_OK; - } - - if (conf->certificate_keys == NULL - || conf->certificate_keys->nelts < conf->certificates->nelts) - { - ngx_log_error(NGX_LOG_EMERG, cf->log, 0, - "no \"ssl_certificate_key\" is defined " - "for certificate \"%V\"", - ((ngx_str_t *) conf->certificates->elts) - + conf->certificates->nelts - 1); - return NGX_CONF_ERROR; - } + if (conf->certificate_keys->nelts < conf->certificates->nelts) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "no \"ssl_certificate_key\" is defined " + "for certificate \"%V\" and " + "the \"%s\" directive in %s:%ui", + ((ngx_str_t *) conf->certificates->elts) + + conf->certificates->nelts - 1, + mode, conf->file, conf->line); + return NGX_CONF_ERROR; } if (ngx_ssl_create(&conf->ssl, conf->protocols, NULL) != NGX_OK) { @@ -381,6 +370,7 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) cln = ngx_pool_cleanup_add(cf->pool, 0); if (cln == NULL) { + ngx_ssl_cleanup_ctx(&conf->ssl); return NGX_CONF_ERROR; } @@ -446,7 +436,7 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) } if (ngx_ssl_session_cache(&conf->ssl, &ngx_mail_ssl_sess_id_ctx, - conf->builtin_session_cache, + conf->certificates, conf->builtin_session_cache, conf->shm_zone, conf->session_timeout) != NGX_OK) { @@ -494,8 +484,10 @@ ngx_mail_ssl_enable(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return NGX_CONF_ERROR; } - scf->file = cf->conf_file->file.name.data; - scf->line = cf->conf_file->line; + if (!scf->listen) { + scf->file = cf->conf_file->file.name.data; + scf->line = cf->conf_file->line; + } return NGX_CONF_OK; } @@ -520,8 +512,10 @@ ngx_mail_ssl_starttls(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return NGX_CONF_ERROR; } - scf->file = cf->conf_file->file.name.data; - scf->line = cf->conf_file->line; + if (!scf->listen) { + scf->file = cf->conf_file->file.name.data; + scf->line = cf->conf_file->line; + } return NGX_CONF_OK; } diff --git a/src/mail/ngx_mail_ssl_module.h b/src/mail/ngx_mail_ssl_module.h index 26628d5..d6b0b8e 100644 --- a/src/mail/ngx_mail_ssl_module.h +++ b/src/mail/ngx_mail_ssl_module.h @@ -26,6 +26,7 @@ typedef struct { ngx_ssl_t ssl; ngx_uint_t starttls; + ngx_uint_t listen; ngx_uint_t protocols; ngx_uint_t verify; diff --git a/src/os/unix/ngx_file_aio_read.c b/src/os/unix/ngx_file_aio_read.c index aedc3c9..bb60ee8 100644 --- a/src/os/unix/ngx_file_aio_read.c +++ b/src/os/unix/ngx_file_aio_read.c @@ -110,7 +110,7 @@ ngx_file_aio_read(ngx_file_t *file, u_char *buf, size_t size, off_t offset, #if (NGX_HAVE_KQUEUE) aio->aiocb.aio_sigevent.sigev_notify_kqueue = ngx_kqueue; aio->aiocb.aio_sigevent.sigev_notify = SIGEV_KEVENT; - aio->aiocb.aio_sigevent.sigev_value.sigval_ptr = ev; + aio->aiocb.aio_sigevent.sigev_value.sival_ptr = ev; #endif ev->handler = ngx_file_aio_event_handler; diff --git a/src/os/unix/ngx_files.h b/src/os/unix/ngx_files.h index 07872b1..383e38e 100644 --- a/src/os/unix/ngx_files.h +++ b/src/os/unix/ngx_files.h @@ -213,9 +213,6 @@ void ngx_close_file_mapping(ngx_file_mapping_t *fm); #endif -#define NGX_DIR_MASK_LEN 0 - - ngx_int_t ngx_open_dir(ngx_str_t *name, ngx_dir_t *dir); #define ngx_open_dir_n "opendir()" diff --git a/src/os/unix/ngx_freebsd_config.h b/src/os/unix/ngx_freebsd_config.h index b7da48c..c641108 100644 --- a/src/os/unix/ngx_freebsd_config.h +++ b/src/os/unix/ngx_freebsd_config.h @@ -89,8 +89,14 @@ #if (NGX_HAVE_FILE_AIO) + #include typedef struct aiocb ngx_aiocb_t; + +#if (__FreeBSD_version < 700005 && !defined __DragonFly__) +#define sival_ptr sigval_ptr +#endif + #endif diff --git a/src/os/unix/ngx_thread.h b/src/os/unix/ngx_thread.h index 1b52dd7..e3b5e81 100644 --- a/src/os/unix/ngx_thread.h +++ b/src/os/unix/ngx_thread.h @@ -47,12 +47,12 @@ typedef uint32_t ngx_tid_t; #elif (NGX_DARWIN) typedef uint64_t ngx_tid_t; -#define NGX_TID_T_FMT "%uA" +#define NGX_TID_T_FMT "%uL" #else typedef uint64_t ngx_tid_t; -#define NGX_TID_T_FMT "%uA" +#define NGX_TID_T_FMT "%uL" #endif diff --git a/src/stream/ngx_stream.c b/src/stream/ngx_stream.c index 0efbda8..7835675 100644 --- a/src/stream/ngx_stream.c +++ b/src/stream/ngx_stream.c @@ -387,7 +387,7 @@ ngx_stream_add_ports(ngx_conf_t *cf, ngx_array_t *ports, ngx_stream_conf_port_t *port; ngx_stream_conf_addr_t *addr; - sa = &listen->sockaddr.sockaddr; + sa = listen->sockaddr; p = ngx_inet_get_port(sa); port = ports->elts; @@ -476,7 +476,7 @@ ngx_stream_optimize_servers(ngx_conf_t *cf, ngx_array_t *ports) continue; } - ls = ngx_create_listening(cf, &addr[i].opt.sockaddr.sockaddr, + ls = ngx_create_listening(cf, addr[i].opt.sockaddr, addr[i].opt.socklen); if (ls == NULL) { return NGX_CONF_ERROR; @@ -538,10 +538,6 @@ ngx_stream_optimize_servers(ngx_conf_t *cf, ngx_array_t *ports) break; } - if (ngx_clone_listening(cf, ls) != NGX_OK) { - return NGX_CONF_ERROR; - } - addr++; last--; } @@ -555,12 +551,9 @@ static ngx_int_t ngx_stream_add_addrs(ngx_conf_t *cf, ngx_stream_port_t *stport, ngx_stream_conf_addr_t *addr) { - u_char *p; - size_t len; ngx_uint_t i; struct sockaddr_in *sin; ngx_stream_in_addr_t *addrs; - u_char buf[NGX_SOCKADDR_STRLEN]; stport->addrs = ngx_pcalloc(cf->pool, stport->naddrs * sizeof(ngx_stream_in_addr_t)); @@ -572,7 +565,7 @@ ngx_stream_add_addrs(ngx_conf_t *cf, ngx_stream_port_t *stport, for (i = 0; i < stport->naddrs; i++) { - sin = &addr[i].opt.sockaddr.sockaddr_in; + sin = (struct sockaddr_in *) addr[i].opt.sockaddr; addrs[i].addr = sin->sin_addr.s_addr; addrs[i].conf.ctx = addr[i].opt.ctx; @@ -580,19 +573,7 @@ ngx_stream_add_addrs(ngx_conf_t *cf, ngx_stream_port_t *stport, addrs[i].conf.ssl = addr[i].opt.ssl; #endif addrs[i].conf.proxy_protocol = addr[i].opt.proxy_protocol; - - len = ngx_sock_ntop(&addr[i].opt.sockaddr.sockaddr, addr[i].opt.socklen, - buf, NGX_SOCKADDR_STRLEN, 1); - - p = ngx_pnalloc(cf->pool, len); - if (p == NULL) { - return NGX_ERROR; - } - - ngx_memcpy(p, buf, len); - - addrs[i].conf.addr_text.len = len; - addrs[i].conf.addr_text.data = p; + addrs[i].conf.addr_text = addr[i].opt.addr_text; } return NGX_OK; @@ -605,12 +586,9 @@ static ngx_int_t ngx_stream_add_addrs6(ngx_conf_t *cf, ngx_stream_port_t *stport, ngx_stream_conf_addr_t *addr) { - u_char *p; - size_t len; ngx_uint_t i; struct sockaddr_in6 *sin6; ngx_stream_in6_addr_t *addrs6; - u_char buf[NGX_SOCKADDR_STRLEN]; stport->addrs = ngx_pcalloc(cf->pool, stport->naddrs * sizeof(ngx_stream_in6_addr_t)); @@ -622,7 +600,7 @@ ngx_stream_add_addrs6(ngx_conf_t *cf, ngx_stream_port_t *stport, for (i = 0; i < stport->naddrs; i++) { - sin6 = &addr[i].opt.sockaddr.sockaddr_in6; + sin6 = (struct sockaddr_in6 *) addr[i].opt.sockaddr; addrs6[i].addr6 = sin6->sin6_addr; addrs6[i].conf.ctx = addr[i].opt.ctx; @@ -630,19 +608,7 @@ ngx_stream_add_addrs6(ngx_conf_t *cf, ngx_stream_port_t *stport, addrs6[i].conf.ssl = addr[i].opt.ssl; #endif addrs6[i].conf.proxy_protocol = addr[i].opt.proxy_protocol; - - len = ngx_sock_ntop(&addr[i].opt.sockaddr.sockaddr, addr[i].opt.socklen, - buf, NGX_SOCKADDR_STRLEN, 1); - - p = ngx_pnalloc(cf->pool, len); - if (p == NULL) { - return NGX_ERROR; - } - - ngx_memcpy(p, buf, len); - - addrs6[i].conf.addr_text.len = len; - addrs6[i].conf.addr_text.data = p; + addrs6[i].conf.addr_text = addr[i].opt.addr_text; } return NGX_OK; diff --git a/src/stream/ngx_stream.h b/src/stream/ngx_stream.h index 09d2459..57e73e0 100644 --- a/src/stream/ngx_stream.h +++ b/src/stream/ngx_stream.h @@ -41,8 +41,9 @@ typedef struct { typedef struct { - ngx_sockaddr_t sockaddr; + struct sockaddr *sockaddr; socklen_t socklen; + ngx_str_t addr_text; /* server ctx */ ngx_stream_conf_ctx_t *ctx; diff --git a/src/stream/ngx_stream_core_module.c b/src/stream/ngx_stream_core_module.c index 272708d..9b6afe9 100644 --- a/src/stream/ngx_stream_core_module.c +++ b/src/stream/ngx_stream_core_module.c @@ -249,34 +249,40 @@ ngx_stream_core_preread_phase(ngx_stream_session_t *s, } if (!c->read->ready) { - if (ngx_handle_read_event(c->read, 0) != NGX_OK) { - rc = NGX_ERROR; - break; - } - - if (!c->read->timer_set) { - ngx_add_timer(c->read, cscf->preread_timeout); - } - - c->read->handler = ngx_stream_session_handler; - - return NGX_OK; + break; } n = c->recv(c, c->buffer->last, size); - if (n == NGX_ERROR) { + if (n == NGX_ERROR || n == 0) { rc = NGX_STREAM_OK; break; } - if (n > 0) { - c->buffer->last += n; + if (n == NGX_AGAIN) { + break; } + c->buffer->last += n; + rc = ph->handler(s); } + if (rc == NGX_AGAIN) { + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + ngx_stream_finalize_session(s, NGX_STREAM_INTERNAL_SERVER_ERROR); + return NGX_OK; + } + + if (!c->read->timer_set) { + ngx_add_timer(c->read, cscf->preread_timeout); + } + + c->read->handler = ngx_stream_session_handler; + + return NGX_OK; + } + if (c->read->timer_set) { ngx_del_timer(c->read); } @@ -571,7 +577,7 @@ ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_str_t *value, size; ngx_url_t u; - ngx_uint_t i, backlog; + ngx_uint_t i, n, backlog; ngx_stream_listen_t *ls, *als; ngx_stream_core_main_conf_t *cmcf; @@ -596,21 +602,17 @@ ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module); - ls = ngx_array_push(&cmcf->listen); + ls = ngx_array_push_n(&cmcf->listen, u.naddrs); if (ls == NULL) { return NGX_CONF_ERROR; } ngx_memzero(ls, sizeof(ngx_stream_listen_t)); - ngx_memcpy(&ls->sockaddr.sockaddr, &u.sockaddr, u.socklen); - - ls->socklen = u.socklen; ls->backlog = NGX_LISTEN_BACKLOG; ls->rcvbuf = -1; ls->sndbuf = -1; ls->type = SOCK_STREAM; - ls->wildcard = u.wildcard; ls->ctx = cf->ctx; #if (NGX_HAVE_INET6) @@ -682,35 +684,20 @@ ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) if (ngx_strncmp(value[i].data, "ipv6only=o", 10) == 0) { #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) - size_t len; - u_char buf[NGX_SOCKADDR_STRLEN]; + if (ngx_strcmp(&value[i].data[10], "n") == 0) { + ls->ipv6only = 1; - if (ls->sockaddr.sockaddr.sa_family == AF_INET6) { - - if (ngx_strcmp(&value[i].data[10], "n") == 0) { - ls->ipv6only = 1; - - } else if (ngx_strcmp(&value[i].data[10], "ff") == 0) { - ls->ipv6only = 0; - - } else { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid ipv6only flags \"%s\"", - &value[i].data[9]); - return NGX_CONF_ERROR; - } - - ls->bind = 1; + } else if (ngx_strcmp(&value[i].data[10], "ff") == 0) { + ls->ipv6only = 0; } else { - len = ngx_sock_ntop(&ls->sockaddr.sockaddr, ls->socklen, buf, - NGX_SOCKADDR_STRLEN, 1); - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "ipv6only is not supported " - "on addr \"%*s\", ignored", len, buf); + "invalid ipv6only flags \"%s\"", + &value[i].data[9]); + return NGX_CONF_ERROR; } + ls->bind = 1; continue; #else ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, @@ -734,7 +721,17 @@ ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) if (ngx_strcmp(value[i].data, "ssl") == 0) { #if (NGX_STREAM_SSL) + ngx_stream_ssl_conf_t *sslcf; + + sslcf = ngx_stream_conf_get_module_srv_conf(cf, + ngx_stream_ssl_module); + + sslcf->listen = 1; + sslcf->file = cf->conf_file->file.name.data; + sslcf->line = cf->conf_file->line; + ls->ssl = 1; + continue; #else ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, @@ -866,21 +863,31 @@ ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) als = cmcf->listen.elts; - for (i = 0; i < cmcf->listen.nelts - 1; i++) { - if (ls->type != als[i].type) { - continue; - } + for (n = 0; n < u.naddrs; n++) { + ls[n] = ls[0]; - if (ngx_cmp_sockaddr(&als[i].sockaddr.sockaddr, als[i].socklen, - &ls->sockaddr.sockaddr, ls->socklen, 1) - != NGX_OK) - { - continue; - } + ls[n].sockaddr = u.addrs[n].sockaddr; + ls[n].socklen = u.addrs[n].socklen; + ls[n].addr_text = u.addrs[n].name; + ls[n].wildcard = ngx_inet_wildcard(ls[n].sockaddr); - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "duplicate \"%V\" address and port pair", &u.url); - return NGX_CONF_ERROR; + for (i = 0; i < cmcf->listen.nelts - u.naddrs + n; i++) { + if (ls[n].type != als[i].type) { + continue; + } + + if (ngx_cmp_sockaddr(als[i].sockaddr, als[i].socklen, + ls[n].sockaddr, ls[n].socklen, 1) + != NGX_OK) + { + continue; + } + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "duplicate \"%V\" address and port pair", + &ls[n].addr_text); + return NGX_CONF_ERROR; + } } return NGX_CONF_OK; diff --git a/src/stream/ngx_stream_geo_module.c b/src/stream/ngx_stream_geo_module.c index 83f7fb4..4b4cad8 100644 --- a/src/stream/ngx_stream_geo_module.c +++ b/src/stream/ngx_stream_geo_module.c @@ -206,6 +206,13 @@ ngx_stream_geo_cidr_variable(ngx_stream_session_t *s, break; #endif +#if (NGX_HAVE_UNIX_DOMAIN) + case AF_UNIX: + vv = (ngx_stream_variable_value_t *) + ngx_radix32tree_find(ctx->u.trees.tree, INADDR_NONE); + break; +#endif + default: /* AF_INET */ sin = (struct sockaddr_in *) addr.sockaddr; inaddr = ntohl(sin->sin_addr.s_addr); @@ -268,6 +275,12 @@ ngx_stream_geo_range_variable(ngx_stream_session_t *s, break; #endif +#if (NGX_HAVE_UNIX_DOMAIN) + case AF_UNIX: + inaddr = INADDR_NONE; + break; +#endif + default: /* AF_INET */ sin = (struct sockaddr_in *) addr.sockaddr; inaddr = ntohl(sin->sin_addr.s_addr); diff --git a/src/stream/ngx_stream_proxy_module.c b/src/stream/ngx_stream_proxy_module.c index 30572cd..127c8a4 100644 --- a/src/stream/ngx_stream_proxy_module.c +++ b/src/stream/ngx_stream_proxy_module.c @@ -26,11 +26,13 @@ typedef struct { size_t buffer_size; size_t upload_rate; size_t download_rate; + ngx_uint_t requests; ngx_uint_t responses; ngx_uint_t next_upstream_tries; ngx_flag_t next_upstream; ngx_flag_t proxy_protocol; ngx_stream_upstream_local_t *local; + ngx_flag_t socket_keepalive; #if (NGX_STREAM_SSL) ngx_flag_t ssl_enable; @@ -72,6 +74,8 @@ static void ngx_stream_proxy_connect_handler(ngx_event_t *ev); static ngx_int_t ngx_stream_proxy_test_connect(ngx_connection_t *c); static void ngx_stream_proxy_process(ngx_stream_session_t *s, ngx_uint_t from_upstream, ngx_uint_t do_write); +static ngx_int_t ngx_stream_proxy_test_finalize(ngx_stream_session_t *s, + ngx_uint_t from_upstream); static void ngx_stream_proxy_next_upstream(ngx_stream_session_t *s); static void ngx_stream_proxy_finalize(ngx_stream_session_t *s, ngx_uint_t rc); static u_char *ngx_stream_proxy_log_error(ngx_log_t *log, u_char *buf, @@ -92,6 +96,7 @@ static char *ngx_stream_proxy_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static void ngx_stream_proxy_ssl_init_connection(ngx_stream_session_t *s); static void ngx_stream_proxy_ssl_handshake(ngx_connection_t *pc); +static void ngx_stream_proxy_ssl_save_session(ngx_connection_t *c); static ngx_int_t ngx_stream_proxy_ssl_name(ngx_stream_session_t *s); static ngx_int_t ngx_stream_proxy_set_ssl(ngx_conf_t *cf, ngx_stream_proxy_srv_conf_t *pscf); @@ -135,6 +140,13 @@ static ngx_command_t ngx_stream_proxy_commands[] = { 0, NULL }, + { ngx_string("proxy_socket_keepalive"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_STREAM_SRV_CONF_OFFSET, + offsetof(ngx_stream_proxy_srv_conf_t, socket_keepalive), + NULL }, + { ngx_string("proxy_connect_timeout"), NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, ngx_conf_set_msec_slot, @@ -184,6 +196,13 @@ static ngx_command_t ngx_stream_proxy_commands[] = { offsetof(ngx_stream_proxy_srv_conf_t, download_rate), NULL }, + { ngx_string("proxy_requests"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_STREAM_SRV_CONF_OFFSET, + offsetof(ngx_stream_proxy_srv_conf_t, requests), + NULL }, + { ngx_string("proxy_responses"), NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, ngx_conf_set_num_slot, @@ -377,6 +396,8 @@ ngx_stream_proxy_handler(ngx_stream_session_t *s) s->log_handler = ngx_stream_proxy_log_error; + u->requests = 1; + u->peer.log = c->log; u->peer.log_error = NGX_ERROR_ERR; @@ -385,6 +406,10 @@ ngx_stream_proxy_handler(ngx_stream_session_t *s) return; } + if (pscf->socket_keepalive) { + u->peer.so_keepalive = 1; + } + u->peer.type = c->type; u->start_sec = ngx_time(); @@ -398,21 +423,19 @@ ngx_stream_proxy_handler(ngx_stream_session_t *s) return; } - if (c->type == SOCK_STREAM) { - p = ngx_pnalloc(c->pool, pscf->buffer_size); - if (p == NULL) { - ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); - return; - } + p = ngx_pnalloc(c->pool, pscf->buffer_size); + if (p == NULL) { + ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); + return; + } - u->downstream_buf.start = p; - u->downstream_buf.end = p + pscf->buffer_size; - u->downstream_buf.pos = p; - u->downstream_buf.last = p; + u->downstream_buf.start = p; + u->downstream_buf.end = p + pscf->buffer_size; + u->downstream_buf.pos = p; + u->downstream_buf.last = p; - if (c->read->ready) { - ngx_post_event(c->read, &ngx_posted_events); - } + if (c->read->ready) { + ngx_post_event(c->read, &ngx_posted_events); } if (pscf->upstream_value) { @@ -667,7 +690,7 @@ ngx_stream_proxy_connect(ngx_stream_session_t *s) u->proxy_protocol = pscf->proxy_protocol; if (u->state) { - u->state->response_time = ngx_current_msec - u->state->response_time; + u->state->response_time = ngx_current_msec - u->start_time; } u->state = ngx_array_push(s->upstream_states); @@ -678,9 +701,11 @@ ngx_stream_proxy_connect(ngx_stream_session_t *s) ngx_memzero(u->state, sizeof(ngx_stream_upstream_state_t)); + u->start_time = ngx_current_msec; + u->state->connect_time = (ngx_msec_t) -1; u->state->first_byte_time = (ngx_msec_t) -1; - u->state->response_time = ngx_current_msec; + u->state->response_time = (ngx_msec_t) -1; rc = ngx_event_connect_peer(&u->peer); @@ -794,7 +819,7 @@ ngx_stream_proxy_init_upstream(ngx_stream_session_t *s) } } - u->state->connect_time = ngx_current_msec - u->state->response_time; + u->state->connect_time = ngx_current_msec - u->start_time; if (u->peer.notify) { u->peer.notify(&u->peer, u->peer.data, @@ -829,7 +854,6 @@ ngx_stream_proxy_init_upstream(ngx_stream_session_t *s) cl->buf->tag = (ngx_buf_tag_t) &ngx_stream_proxy_module; cl->buf->flush = 1; - cl->buf->last_buf = (c->type == SOCK_DGRAM); cl->next = u->upstream_out; u->upstream_out = cl; @@ -871,17 +895,12 @@ ngx_stream_proxy_init_upstream(ngx_stream_session_t *s) u->proxy_protocol = 0; } - if (c->type == SOCK_DGRAM && pscf->responses == 0) { - pc->read->ready = 0; - pc->read->eof = 1; - } - u->connected = 1; pc->read->handler = ngx_stream_proxy_upstream_handler; pc->write->handler = ngx_stream_proxy_upstream_handler; - if (pc->read->ready || pc->read->eof) { + if (pc->read->ready) { ngx_post_event(pc->read, &ngx_posted_events); } @@ -1014,6 +1033,8 @@ ngx_stream_proxy_ssl_init_connection(ngx_stream_session_t *s) } if (pscf->ssl_session_reuse) { + pc->ssl->save_session = ngx_stream_proxy_ssl_save_session; + if (u->peer.set_session(&u->peer, u->peer.data) != NGX_OK) { ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); return; @@ -1072,11 +1093,6 @@ ngx_stream_proxy_ssl_handshake(ngx_connection_t *pc) } } - if (pscf->ssl_session_reuse) { - u = s->upstream; - u->peer.save_session(&u->peer, u->peer.data); - } - if (pc->write->timer_set) { ngx_del_timer(pc->write); } @@ -1092,6 +1108,19 @@ failed: } +static void +ngx_stream_proxy_ssl_save_session(ngx_connection_t *c) +{ + ngx_stream_session_t *s; + ngx_stream_upstream_t *u; + + s = c->data; + u = s->upstream; + + u->peer.save_session(&u->peer, u->peer.data); +} + + static ngx_int_t ngx_stream_proxy_ssl_name(ngx_stream_session_t *s) { @@ -1280,6 +1309,7 @@ static void ngx_stream_proxy_process_connection(ngx_event_t *ev, ngx_uint_t from_upstream) { ngx_connection_t *c, *pc; + ngx_log_handler_pt handler; ngx_stream_session_t *s; ngx_stream_upstream_t *u; ngx_stream_proxy_srv_conf_t *pscf; @@ -1321,32 +1351,47 @@ ngx_stream_proxy_process_connection(ngx_event_t *ev, ngx_uint_t from_upstream) } else { if (s->connection->type == SOCK_DGRAM) { - if (pscf->responses == NGX_MAX_INT32_VALUE) { + + if (pscf->responses == NGX_MAX_INT32_VALUE + || (u->responses >= pscf->responses * u->requests)) + { /* * successfully terminate timed out UDP session - * with unspecified number of responses + * if expected number of responses was received */ - pc->read->ready = 0; - pc->read->eof = 1; + handler = c->log->handler; + c->log->handler = NULL; - ngx_stream_proxy_process(s, 1, 0); + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "udp timed out" + ", packets from/to client:%ui/%ui" + ", bytes from/to client:%O/%O" + ", bytes from/to upstream:%O/%O", + u->requests, u->responses, + s->received, c->sent, u->received, + pc ? pc->sent : 0); + + c->log->handler = handler; + + ngx_stream_proxy_finalize(s, NGX_STREAM_OK); return; } ngx_connection_error(pc, NGX_ETIMEDOUT, "upstream timed out"); - if (u->received == 0) { - ngx_stream_proxy_next_upstream(s); - return; - } + pc->read->error = 1; - } else { - ngx_connection_error(c, NGX_ETIMEDOUT, "connection timed out"); + ngx_stream_proxy_finalize(s, NGX_STREAM_BAD_GATEWAY); + + return; } + ngx_connection_error(c, NGX_ETIMEDOUT, "connection timed out"); + ngx_stream_proxy_finalize(s, NGX_STREAM_OK); + return; } @@ -1453,7 +1498,7 @@ ngx_stream_proxy_process(ngx_stream_session_t *s, ngx_uint_t from_upstream, ssize_t n; ngx_buf_t *b; ngx_int_t rc; - ngx_uint_t flags; + ngx_uint_t flags, *packets; ngx_msec_t delay; ngx_chain_t *cl, **ll, **out, **busy; ngx_connection_t *c, *pc, *src, *dst; @@ -1489,6 +1534,7 @@ ngx_stream_proxy_process(ngx_stream_session_t *s, ngx_uint_t from_upstream, b = &u->upstream_buf; limit_rate = pscf->download_rate; received = &u->received; + packets = &u->responses; out = &u->downstream_out; busy = &u->downstream_busy; recv_action = "proxying and reading from upstream"; @@ -1500,6 +1546,7 @@ ngx_stream_proxy_process(ngx_stream_session_t *s, ngx_uint_t from_upstream, b = &u->downstream_buf; limit_rate = pscf->upload_rate; received = &s->received; + packets = &u->requests; out = &u->upstream_out; busy = &u->upstream_busy; recv_action = "proxying and reading from client"; @@ -1516,11 +1563,6 @@ ngx_stream_proxy_process(ngx_stream_session_t *s, ngx_uint_t from_upstream, rc = ngx_stream_top_filter(s, *out, from_upstream); if (rc == NGX_ERROR) { - if (c->type == SOCK_DGRAM && !from_upstream) { - ngx_stream_proxy_next_upstream(s); - return; - } - ngx_stream_proxy_finalize(s, NGX_STREAM_OK); return; } @@ -1551,7 +1593,7 @@ ngx_stream_proxy_process(ngx_stream_session_t *s, ngx_uint_t from_upstream, break; } - if ((off_t) size > limit) { + if (c->type == SOCK_STREAM && (off_t) size > limit) { size = (size_t) limit; } } @@ -1565,11 +1607,6 @@ ngx_stream_proxy_process(ngx_stream_session_t *s, ngx_uint_t from_upstream, } if (n == NGX_ERROR) { - if (c->type == SOCK_DGRAM && u->received == 0) { - ngx_stream_proxy_next_upstream(s); - return; - } - src->read->eof = 1; n = 0; } @@ -1587,16 +1624,10 @@ ngx_stream_proxy_process(ngx_stream_session_t *s, ngx_uint_t from_upstream, if (from_upstream) { if (u->state->first_byte_time == (ngx_msec_t) -1) { u->state->first_byte_time = ngx_current_msec - - u->state->response_time; + - u->start_time; } } - if (c->type == SOCK_DGRAM && ++u->responses == pscf->responses) - { - src->read->ready = 0; - src->read->eof = 1; - } - for (ll = out; *ll; ll = &(*ll)->next) { /* void */ } cl = ngx_chain_get_free_buf(c->pool, &u->free); @@ -1616,6 +1647,7 @@ ngx_stream_proxy_process(ngx_stream_session_t *s, ngx_uint_t from_upstream, cl->buf->last_buf = src->read->eof; cl->buf->flush = 1; + (*packets)++; *received += n; b->last += n; do_write = 1; @@ -1629,33 +1661,19 @@ ngx_stream_proxy_process(ngx_stream_session_t *s, ngx_uint_t from_upstream, c->log->action = "proxying connection"; - if (src->read->eof && dst && (dst->read->eof || !dst->buffered)) { - handler = c->log->handler; - c->log->handler = NULL; - - ngx_log_error(NGX_LOG_INFO, c->log, 0, - "%s%s disconnected" - ", bytes from/to client:%O/%O" - ", bytes from/to upstream:%O/%O", - src->type == SOCK_DGRAM ? "udp " : "", - from_upstream ? "upstream" : "client", - s->received, c->sent, u->received, pc ? pc->sent : 0); - - c->log->handler = handler; - - ngx_stream_proxy_finalize(s, NGX_STREAM_OK); + if (ngx_stream_proxy_test_finalize(s, from_upstream) == NGX_OK) { return; } flags = src->read->eof ? NGX_CLOSE_EVENT : 0; - if (!src->shared && ngx_handle_read_event(src->read, flags) != NGX_OK) { + if (ngx_handle_read_event(src->read, flags) != NGX_OK) { ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); return; } if (dst) { - if (!dst->shared && ngx_handle_write_event(dst->write, 0) != NGX_OK) { + if (ngx_handle_write_event(dst->write, 0) != NGX_OK) { ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); return; } @@ -1670,6 +1688,87 @@ ngx_stream_proxy_process(ngx_stream_session_t *s, ngx_uint_t from_upstream, } +static ngx_int_t +ngx_stream_proxy_test_finalize(ngx_stream_session_t *s, + ngx_uint_t from_upstream) +{ + ngx_connection_t *c, *pc; + ngx_log_handler_pt handler; + ngx_stream_upstream_t *u; + ngx_stream_proxy_srv_conf_t *pscf; + + pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module); + + c = s->connection; + u = s->upstream; + pc = u->connected ? u->peer.connection : NULL; + + if (c->type == SOCK_DGRAM) { + + if (pscf->requests && u->requests < pscf->requests) { + return NGX_DECLINED; + } + + if (pscf->requests) { + ngx_delete_udp_connection(c); + } + + if (pscf->responses == NGX_MAX_INT32_VALUE + || u->responses < pscf->responses * u->requests) + { + return NGX_DECLINED; + } + + if (pc == NULL || c->buffered || pc->buffered) { + return NGX_DECLINED; + } + + handler = c->log->handler; + c->log->handler = NULL; + + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "udp done" + ", packets from/to client:%ui/%ui" + ", bytes from/to client:%O/%O" + ", bytes from/to upstream:%O/%O", + u->requests, u->responses, + s->received, c->sent, u->received, pc ? pc->sent : 0); + + c->log->handler = handler; + + ngx_stream_proxy_finalize(s, NGX_STREAM_OK); + + return NGX_OK; + } + + /* c->type == SOCK_STREAM */ + + if (pc == NULL + || (!c->read->eof && !pc->read->eof) + || (!c->read->eof && c->buffered) + || (!pc->read->eof && pc->buffered)) + { + return NGX_DECLINED; + } + + handler = c->log->handler; + c->log->handler = NULL; + + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "%s disconnected" + ", bytes from/to client:%O/%O" + ", bytes from/to upstream:%O/%O", + from_upstream ? "upstream" : "client", + s->received, c->sent, u->received, pc ? pc->sent : 0); + + c->log->handler = handler; + + ngx_stream_proxy_finalize(s, NGX_STREAM_OK); + + return NGX_OK; +} + + static void ngx_stream_proxy_next_upstream(ngx_stream_session_t *s) { @@ -1739,6 +1838,7 @@ ngx_stream_proxy_next_upstream(ngx_stream_session_t *s) static void ngx_stream_proxy_finalize(ngx_stream_session_t *s, ngx_uint_t rc) { + ngx_uint_t state; ngx_connection_t *pc; ngx_stream_upstream_t *u; @@ -1759,7 +1859,9 @@ ngx_stream_proxy_finalize(ngx_stream_session_t *s, ngx_uint_t rc) pc = u->peer.connection; if (u->state) { - u->state->response_time = ngx_current_msec - u->state->response_time; + if (u->state->response_time == (ngx_msec_t) -1) { + u->state->response_time = ngx_current_msec - u->start_time; + } if (pc) { u->state->bytes_received = u->received; @@ -1768,7 +1870,15 @@ ngx_stream_proxy_finalize(ngx_stream_session_t *s, ngx_uint_t rc) } if (u->peer.free && u->peer.sockaddr) { - u->peer.free(&u->peer, u->peer.data, 0); + state = 0; + + if (pc && pc->type == SOCK_DGRAM + && (pc->read->error || pc->write->error)) + { + state = NGX_PEER_FAILED; + } + + u->peer.free(&u->peer, u->peer.data, state); u->peer.sockaddr = NULL; } @@ -1856,11 +1966,13 @@ ngx_stream_proxy_create_srv_conf(ngx_conf_t *cf) conf->buffer_size = NGX_CONF_UNSET_SIZE; conf->upload_rate = NGX_CONF_UNSET_SIZE; conf->download_rate = NGX_CONF_UNSET_SIZE; + conf->requests = NGX_CONF_UNSET_UINT; conf->responses = NGX_CONF_UNSET_UINT; conf->next_upstream_tries = NGX_CONF_UNSET_UINT; conf->next_upstream = NGX_CONF_UNSET; conf->proxy_protocol = NGX_CONF_UNSET; conf->local = NGX_CONF_UNSET_PTR; + conf->socket_keepalive = NGX_CONF_UNSET; #if (NGX_STREAM_SSL) conf->ssl_enable = NGX_CONF_UNSET; @@ -1899,6 +2011,9 @@ ngx_stream_proxy_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_size_value(conf->download_rate, prev->download_rate, 0); + ngx_conf_merge_uint_value(conf->requests, + prev->requests, 0); + ngx_conf_merge_uint_value(conf->responses, prev->responses, NGX_MAX_INT32_VALUE); @@ -1911,6 +2026,9 @@ ngx_stream_proxy_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_ptr_value(conf->local, prev->local, NULL); + ngx_conf_merge_value(conf->socket_keepalive, + prev->socket_keepalive, 0); + #if (NGX_STREAM_SSL) ngx_conf_merge_value(conf->ssl_enable, prev->ssl_enable, 0); @@ -1978,6 +2096,7 @@ ngx_stream_proxy_set_ssl(ngx_conf_t *cf, ngx_stream_proxy_srv_conf_t *pscf) cln = ngx_pool_cleanup_add(cf->pool, 0); if (cln == NULL) { + ngx_ssl_cleanup_ctx(pscf->ssl); return NGX_ERROR; } @@ -2025,6 +2144,12 @@ ngx_stream_proxy_set_ssl(ngx_conf_t *cf, ngx_stream_proxy_srv_conf_t *pscf) } } + if (ngx_ssl_client_session_cache(cf, pscf->ssl, pscf->ssl_session_reuse) + != NGX_OK) + { + return NGX_ERROR; + } + return NGX_OK; } diff --git a/src/stream/ngx_stream_ssl_module.c b/src/stream/ngx_stream_ssl_module.c index 3e5a1f2..ec9524e 100644 --- a/src/stream/ngx_stream_ssl_module.c +++ b/src/stream/ngx_stream_ssl_module.c @@ -22,6 +22,12 @@ static ngx_int_t ngx_stream_ssl_handler(ngx_stream_session_t *s); static ngx_int_t ngx_stream_ssl_init_connection(ngx_ssl_t *ssl, ngx_connection_t *c); static void ngx_stream_ssl_handshake_handler(ngx_connection_t *c); +#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME +int ngx_stream_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg); +#endif +#ifdef SSL_R_CERT_CB_ERROR +static int ngx_stream_ssl_certificate(ngx_ssl_conn_t *ssl_conn, void *arg); +#endif static ngx_int_t ngx_stream_ssl_static_variable(ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_stream_ssl_variable(ngx_stream_session_t *s, @@ -32,6 +38,9 @@ static void *ngx_stream_ssl_create_conf(ngx_conf_t *cf); static char *ngx_stream_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child); +static ngx_int_t ngx_stream_ssl_compile_certificates(ngx_conf_t *cf, + ngx_stream_ssl_conf_t *conf); + static char *ngx_stream_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static char *ngx_stream_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, @@ -304,13 +313,6 @@ ngx_stream_ssl_handler(ngx_stream_session_t *s) if (c->ssl == NULL) { c->log->action = "SSL handshaking"; - if (sslcf->ssl.ctx == NULL) { - ngx_log_error(NGX_LOG_ERR, c->log, 0, - "no \"ssl_certificate\" is defined " - "in server listening on SSL port"); - return NGX_ERROR; - } - rv = ngx_stream_ssl_init_connection(&sslcf->ssl, c); if (rv != NGX_OK) { @@ -415,6 +417,73 @@ ngx_stream_ssl_handshake_handler(ngx_connection_t *c) } +#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME + +int +ngx_stream_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg) +{ + return SSL_TLSEXT_ERR_OK; +} + +#endif + + +#ifdef SSL_R_CERT_CB_ERROR + +int +ngx_stream_ssl_certificate(ngx_ssl_conn_t *ssl_conn, void *arg) +{ + ngx_str_t cert, key; + ngx_uint_t i, nelts; + ngx_connection_t *c; + ngx_stream_session_t *s; + ngx_stream_ssl_conf_t *sslcf; + ngx_stream_complex_value_t *certs, *keys; + + c = ngx_ssl_get_connection(ssl_conn); + + if (c->ssl->handshaked) { + return 0; + } + + s = c->data; + + sslcf = arg; + + nelts = sslcf->certificate_values->nelts; + certs = sslcf->certificate_values->elts; + keys = sslcf->certificate_key_values->elts; + + for (i = 0; i < nelts; i++) { + + if (ngx_stream_complex_value(s, &certs[i], &cert) != NGX_OK) { + return 0; + } + + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0, + "ssl cert: \"%s\"", cert.data); + + if (ngx_stream_complex_value(s, &keys[i], &key) != NGX_OK) { + return 0; + } + + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0, + "ssl key: \"%s\"", key.data); + + if (ngx_ssl_connection_certificate(c, c->pool, &cert, &key, + sslcf->passwords) + != NGX_OK) + { + return 0; + } + } + + return 1; +} + +#endif + + static ngx_int_t ngx_stream_ssl_static_variable(ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data) @@ -510,7 +579,9 @@ ngx_stream_ssl_create_conf(ngx_conf_t *cf) /* * set by ngx_pcalloc(): * + * scf->listen = 0; * scf->protocols = 0; + * scf->certificate_values = NULL; * scf->dhparam = { 0, NULL }; * scf->ecdh_curve = { 0, NULL }; * scf->client_certificate = { 0, NULL }; @@ -582,18 +653,34 @@ ngx_stream_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) conf->ssl.log = cf->log; - if (conf->certificates == NULL) { + if (!conf->listen) { return NGX_CONF_OK; } - if (conf->certificate_keys == NULL - || conf->certificate_keys->nelts < conf->certificates->nelts) - { + if (conf->certificates == NULL) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "no \"ssl_certificate\" is defined for " + "the \"listen ... ssl\" directive in %s:%ui", + conf->file, conf->line); + return NGX_CONF_ERROR; + } + + if (conf->certificate_keys == NULL) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "no \"ssl_certificate_key\" is defined for " + "the \"listen ... ssl\" directive in %s:%ui", + conf->file, conf->line); + return NGX_CONF_ERROR; + } + + if (conf->certificate_keys->nelts < conf->certificates->nelts) { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "no \"ssl_certificate_key\" is defined " - "for certificate \"%V\"", + "for certificate \"%V\" and " + "the \"listen ... ssl\" directive in %s:%ui", ((ngx_str_t *) conf->certificates->elts) - + conf->certificates->nelts - 1); + + conf->certificates->nelts - 1, + conf->file, conf->line); return NGX_CONF_ERROR; } @@ -603,19 +690,50 @@ ngx_stream_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) cln = ngx_pool_cleanup_add(cf->pool, 0); if (cln == NULL) { + ngx_ssl_cleanup_ctx(&conf->ssl); return NGX_CONF_ERROR; } cln->handler = ngx_ssl_cleanup_ctx; cln->data = &conf->ssl; - if (ngx_ssl_certificates(cf, &conf->ssl, conf->certificates, - conf->certificate_keys, conf->passwords) - != NGX_OK) - { +#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME + SSL_CTX_set_tlsext_servername_callback(conf->ssl.ctx, + ngx_stream_ssl_servername); +#endif + + if (ngx_stream_ssl_compile_certificates(cf, conf) != NGX_OK) { return NGX_CONF_ERROR; } + if (conf->certificate_values) { + +#ifdef SSL_R_CERT_CB_ERROR + + /* install callback to lookup certificates */ + + SSL_CTX_set_cert_cb(conf->ssl.ctx, ngx_stream_ssl_certificate, conf); + +#else + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "variables in " + "\"ssl_certificate\" and \"ssl_certificate_key\" " + "directives are not supported on this platform"); + return NGX_CONF_ERROR; +#endif + + } else { + + /* configure certificates */ + + if (ngx_ssl_certificates(cf, &conf->ssl, conf->certificates, + conf->certificate_keys, conf->passwords) + != NGX_OK) + { + return NGX_CONF_ERROR; + } + } + if (ngx_ssl_ciphers(cf, &conf->ssl, &conf->ciphers, conf->prefer_server_ciphers) != NGX_OK) @@ -668,7 +786,7 @@ ngx_stream_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) } if (ngx_ssl_session_cache(&conf->ssl, &ngx_stream_ssl_sess_id_ctx, - conf->builtin_session_cache, + conf->certificates, conf->builtin_session_cache, conf->shm_zone, conf->session_timeout) != NGX_OK) { @@ -697,6 +815,90 @@ ngx_stream_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) } +static ngx_int_t +ngx_stream_ssl_compile_certificates(ngx_conf_t *cf, + ngx_stream_ssl_conf_t *conf) +{ + ngx_str_t *cert, *key; + ngx_uint_t i, nelts; + ngx_stream_complex_value_t *cv; + ngx_stream_compile_complex_value_t ccv; + + cert = conf->certificates->elts; + key = conf->certificate_keys->elts; + nelts = conf->certificates->nelts; + + for (i = 0; i < nelts; i++) { + + if (ngx_stream_script_variables_count(&cert[i])) { + goto found; + } + + if (ngx_stream_script_variables_count(&key[i])) { + goto found; + } + } + + return NGX_OK; + +found: + + conf->certificate_values = ngx_array_create(cf->pool, nelts, + sizeof(ngx_stream_complex_value_t)); + if (conf->certificate_values == NULL) { + return NGX_ERROR; + } + + conf->certificate_key_values = ngx_array_create(cf->pool, nelts, + sizeof(ngx_stream_complex_value_t)); + if (conf->certificate_key_values == NULL) { + return NGX_ERROR; + } + + for (i = 0; i < nelts; i++) { + + cv = ngx_array_push(conf->certificate_values); + if (cv == NULL) { + return NGX_ERROR; + } + + ngx_memzero(&ccv, sizeof(ngx_stream_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &cert[i]; + ccv.complex_value = cv; + ccv.zero = 1; + + if (ngx_stream_compile_complex_value(&ccv) != NGX_OK) { + return NGX_ERROR; + } + + cv = ngx_array_push(conf->certificate_key_values); + if (cv == NULL) { + return NGX_ERROR; + } + + ngx_memzero(&ccv, sizeof(ngx_stream_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &key[i]; + ccv.complex_value = cv; + ccv.zero = 1; + + if (ngx_stream_compile_complex_value(&ccv) != NGX_OK) { + return NGX_ERROR; + } + } + + conf->passwords = ngx_ssl_preserve_passwords(cf, conf->passwords); + if (conf->passwords == NULL) { + return NGX_ERROR; + } + + return NGX_OK; +} + + static char * ngx_stream_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { diff --git a/src/stream/ngx_stream_ssl_module.h b/src/stream/ngx_stream_ssl_module.h index 65f5d45..6cb4140 100644 --- a/src/stream/ngx_stream_ssl_module.h +++ b/src/stream/ngx_stream_ssl_module.h @@ -21,6 +21,7 @@ typedef struct { ngx_ssl_t ssl; + ngx_uint_t listen; ngx_uint_t protocols; ngx_uint_t verify; @@ -33,6 +34,9 @@ typedef struct { ngx_array_t *certificates; ngx_array_t *certificate_keys; + ngx_array_t *certificate_values; + ngx_array_t *certificate_key_values; + ngx_str_t dhparam; ngx_str_t ecdh_curve; ngx_str_t client_certificate; @@ -47,6 +51,9 @@ typedef struct { ngx_flag_t session_tickets; ngx_array_t *session_ticket_keys; + + u_char *file; + ngx_uint_t line; } ngx_stream_ssl_conf_t; diff --git a/src/stream/ngx_stream_ssl_preread_module.c b/src/stream/ngx_stream_ssl_preread_module.c index 62d6524..a236fc5 100644 --- a/src/stream/ngx_stream_ssl_preread_module.c +++ b/src/stream/ngx_stream_ssl_preread_module.c @@ -21,6 +21,7 @@ typedef struct { u_char *pos; u_char *dst; u_char buf[4]; + u_char version[2]; ngx_str_t host; ngx_str_t alpn; ngx_log_t *log; @@ -32,6 +33,8 @@ typedef struct { static ngx_int_t ngx_stream_ssl_preread_handler(ngx_stream_session_t *s); static ngx_int_t ngx_stream_ssl_preread_parse_record( ngx_stream_ssl_preread_ctx_t *ctx, u_char *pos, u_char *last); +static ngx_int_t ngx_stream_ssl_preread_protocol_variable( + ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_stream_ssl_preread_server_name_variable( ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_stream_ssl_preread_alpn_protocols_variable( @@ -86,6 +89,9 @@ ngx_module_t ngx_stream_ssl_preread_module = { static ngx_stream_variable_t ngx_stream_ssl_preread_vars[] = { + { ngx_string("ssl_preread_protocol"), NULL, + ngx_stream_ssl_preread_protocol_variable, 0, 0, 0 }, + { ngx_string("ssl_preread_server_name"), NULL, ngx_stream_ssl_preread_server_name_variable, 0, 0, 0 }, @@ -143,6 +149,14 @@ ngx_stream_ssl_preread_handler(ngx_stream_session_t *s) while (last - p >= 5) { + if ((p[0] & 0x80) && p[2] == 1 && (p[3] == 0 || p[3] == 3)) { + ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0, + "ssl preread: version 2 ClientHello"); + ctx->version[0] = p[3]; + ctx->version[1] = p[4]; + return NGX_OK; + } + if (p[0] != 0x16) { ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0, "ssl preread: not a handshake"); @@ -196,7 +210,8 @@ ngx_stream_ssl_preread_parse_record(ngx_stream_ssl_preread_ctx_t *ctx, enum { sw_start = 0, sw_header, /* handshake msg_type, length */ - sw_head_tail, /* version, random */ + sw_version, /* client_version */ + sw_random, /* random */ sw_sid_len, /* session_id length */ sw_sid, /* session_id */ sw_cs_len, /* cipher_suites length */ @@ -210,7 +225,8 @@ ngx_stream_ssl_preread_parse_record(ngx_stream_ssl_preread_ctx_t *ctx, sw_sni_host, /* SNI host_name */ sw_alpn_len, /* ALPN length */ sw_alpn_proto_len, /* ALPN protocol_name length */ - sw_alpn_proto_data /* ALPN protocol_name */ + sw_alpn_proto_data, /* ALPN protocol_name */ + sw_supver_len /* supported_versions length */ } state; ngx_log_debug2(NGX_LOG_DEBUG_STREAM, ctx->log, 0, @@ -254,13 +270,19 @@ ngx_stream_ssl_preread_parse_record(ngx_stream_ssl_preread_ctx_t *ctx, return NGX_DECLINED; } - state = sw_head_tail; - dst = NULL; - size = 34; + state = sw_version; + dst = ctx->version; + size = 2; left = (p[1] << 16) + (p[2] << 8) + p[3]; break; - case sw_head_tail: + case sw_version: + state = sw_random; + dst = NULL; + size = 32; + break; + + case sw_random: state = sw_sid_len; dst = p; size = 1; @@ -334,6 +356,14 @@ ngx_stream_ssl_preread_parse_record(ngx_stream_ssl_preread_ctx_t *ctx, break; } + if (p[0] == 0 && p[1] == 43) { + /* supported_versions extension */ + state = sw_supver_len; + dst = p; + size = 1; + break; + } + state = sw_ext; dst = NULL; size = (p[2] << 8) + p[3]; @@ -434,6 +464,19 @@ ngx_stream_ssl_preread_parse_record(ngx_stream_ssl_preread_ctx_t *ctx, dst = NULL; size = 0; break; + + case sw_supver_len: + ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0, + "ssl preread: supported_versions"); + + /* set TLSv1.3 */ + ctx->version[0] = 3; + ctx->version[1] = 4; + + state = sw_ext; + dst = NULL; + size = p[0]; + break; } if (left < size) { @@ -453,6 +496,62 @@ ngx_stream_ssl_preread_parse_record(ngx_stream_ssl_preread_ctx_t *ctx, } +static ngx_int_t +ngx_stream_ssl_preread_protocol_variable(ngx_stream_session_t *s, + ngx_variable_value_t *v, uintptr_t data) +{ + ngx_str_t version; + ngx_stream_ssl_preread_ctx_t *ctx; + + ctx = ngx_stream_get_module_ctx(s, ngx_stream_ssl_preread_module); + + if (ctx == NULL) { + v->not_found = 1; + return NGX_OK; + } + + /* SSL_get_version() format */ + + ngx_str_null(&version); + + switch (ctx->version[0]) { + case 0: + switch (ctx->version[1]) { + case 2: + ngx_str_set(&version, "SSLv2"); + break; + } + break; + case 3: + switch (ctx->version[1]) { + case 0: + ngx_str_set(&version, "SSLv3"); + break; + case 1: + ngx_str_set(&version, "TLSv1"); + break; + case 2: + ngx_str_set(&version, "TLSv1.1"); + break; + case 3: + ngx_str_set(&version, "TLSv1.2"); + break; + case 4: + ngx_str_set(&version, "TLSv1.3"); + break; + } + } + + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->len = version.len; + v->data = version.data; + + return NGX_OK; +} + + static ngx_int_t ngx_stream_ssl_preread_server_name_variable(ngx_stream_session_t *s, ngx_variable_value_t *v, uintptr_t data) diff --git a/src/stream/ngx_stream_upstream.c b/src/stream/ngx_stream_upstream.c index 7feac43..eadcf9f 100644 --- a/src/stream/ngx_stream_upstream.c +++ b/src/stream/ngx_stream_upstream.c @@ -267,24 +267,22 @@ ngx_stream_upstream_response_time_variable(ngx_stream_session_t *s, for ( ;; ) { if (data == 1) { - if (state[i].first_byte_time == (ngx_msec_t) -1) { - *p++ = '-'; - goto next; - } - ms = state[i].first_byte_time; - } else if (data == 2 && state[i].connect_time != (ngx_msec_t) -1) { + } else if (data == 2) { ms = state[i].connect_time; } else { ms = state[i].response_time; } - ms = ngx_max(ms, 0); - p = ngx_sprintf(p, "%T.%03M", (time_t) ms / 1000, ms % 1000); + if (ms != -1) { + ms = ngx_max(ms, 0); + p = ngx_sprintf(p, "%T.%03M", (time_t) ms / 1000, ms % 1000); - next: + } else { + *p++ = '-'; + } if (++i == s->upstream_states->nelts) { break; diff --git a/src/stream/ngx_stream_upstream.h b/src/stream/ngx_stream_upstream.h index 73947f4..0fe416b 100644 --- a/src/stream/ngx_stream_upstream.h +++ b/src/stream/ngx_stream_upstream.h @@ -128,7 +128,9 @@ typedef struct { off_t received; time_t start_sec; + ngx_uint_t requests; ngx_uint_t responses; + ngx_msec_t start_time; ngx_str_t ssl_name; diff --git a/src/stream/ngx_stream_upstream_hash_module.c b/src/stream/ngx_stream_upstream_hash_module.c index 79ad742..4fa9a2d 100644 --- a/src/stream/ngx_stream_upstream_hash_module.c +++ b/src/stream/ngx_stream_upstream_hash_module.c @@ -176,7 +176,7 @@ ngx_stream_upstream_get_hash_peer(ngx_peer_connection_t *pc, void *data) ngx_log_debug1(NGX_LOG_DEBUG_STREAM, pc->log, 0, "get hash peer, try: %ui", pc->tries); - ngx_stream_upstream_rr_peers_wlock(hp->rrp.peers); + ngx_stream_upstream_rr_peers_rlock(hp->rrp.peers); if (hp->tries > 20 || hp->rrp.peers->single) { ngx_stream_upstream_rr_peers_unlock(hp->rrp.peers); @@ -227,10 +227,13 @@ ngx_stream_upstream_get_hash_peer(ngx_peer_connection_t *pc, void *data) goto next; } + ngx_stream_upstream_rr_peer_lock(hp->rrp.peers, peer); + ngx_log_debug2(NGX_LOG_DEBUG_STREAM, pc->log, 0, "get hash peer, value:%uD, peer:%ui", hp->hash, p); if (peer->down) { + ngx_stream_upstream_rr_peer_unlock(hp->rrp.peers, peer); goto next; } @@ -238,10 +241,12 @@ ngx_stream_upstream_get_hash_peer(ngx_peer_connection_t *pc, void *data) && peer->fails >= peer->max_fails && now - peer->checked <= peer->fail_timeout) { + ngx_stream_upstream_rr_peer_unlock(hp->rrp.peers, peer); goto next; } if (peer->max_conns && peer->conns >= peer->max_conns) { + ngx_stream_upstream_rr_peer_unlock(hp->rrp.peers, peer); goto next; } @@ -267,6 +272,7 @@ ngx_stream_upstream_get_hash_peer(ngx_peer_connection_t *pc, void *data) peer->checked = now; } + ngx_stream_upstream_rr_peer_unlock(hp->rrp.peers, peer); ngx_stream_upstream_rr_peers_unlock(hp->rrp.peers); hp->rrp.tried[n] |= m; diff --git a/src/stream/ngx_stream_upstream_random_module.c b/src/stream/ngx_stream_upstream_random_module.c new file mode 100644 index 0000000..402c1b2 --- /dev/null +++ b/src/stream/ngx_stream_upstream_random_module.c @@ -0,0 +1,502 @@ + +/* + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include + + +typedef struct { + ngx_stream_upstream_rr_peer_t *peer; + ngx_uint_t range; +} ngx_stream_upstream_random_range_t; + + +typedef struct { + ngx_uint_t two; + ngx_stream_upstream_random_range_t *ranges; +} ngx_stream_upstream_random_srv_conf_t; + + +typedef struct { + /* the round robin data must be first */ + ngx_stream_upstream_rr_peer_data_t rrp; + + ngx_stream_upstream_random_srv_conf_t *conf; + u_char tries; +} ngx_stream_upstream_random_peer_data_t; + + +static ngx_int_t ngx_stream_upstream_init_random(ngx_conf_t *cf, + ngx_stream_upstream_srv_conf_t *us); +static ngx_int_t ngx_stream_upstream_update_random(ngx_pool_t *pool, + ngx_stream_upstream_srv_conf_t *us); + +static ngx_int_t ngx_stream_upstream_init_random_peer(ngx_stream_session_t *s, + ngx_stream_upstream_srv_conf_t *us); +static ngx_int_t ngx_stream_upstream_get_random_peer(ngx_peer_connection_t *pc, + void *data); +static ngx_int_t ngx_stream_upstream_get_random2_peer(ngx_peer_connection_t *pc, + void *data); +static ngx_uint_t ngx_stream_upstream_peek_random_peer( + ngx_stream_upstream_rr_peers_t *peers, + ngx_stream_upstream_random_peer_data_t *rp); +static void *ngx_stream_upstream_random_create_conf(ngx_conf_t *cf); +static char *ngx_stream_upstream_random(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); + + +static ngx_command_t ngx_stream_upstream_random_commands[] = { + + { ngx_string("random"), + NGX_STREAM_UPS_CONF|NGX_CONF_NOARGS|NGX_CONF_TAKE12, + ngx_stream_upstream_random, + NGX_STREAM_SRV_CONF_OFFSET, + 0, + NULL }, + + ngx_null_command +}; + + +static ngx_stream_module_t ngx_stream_upstream_random_module_ctx = { + NULL, /* preconfiguration */ + NULL, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + ngx_stream_upstream_random_create_conf, /* create server configuration */ + NULL /* merge server configuration */ +}; + + +ngx_module_t ngx_stream_upstream_random_module = { + NGX_MODULE_V1, + &ngx_stream_upstream_random_module_ctx, /* module context */ + ngx_stream_upstream_random_commands, /* module directives */ + NGX_STREAM_MODULE, /* module type */ + NULL, /* init master */ + NULL, /* init module */ + NULL, /* init process */ + NULL, /* init thread */ + NULL, /* exit thread */ + NULL, /* exit process */ + NULL, /* exit master */ + NGX_MODULE_V1_PADDING +}; + + +static ngx_int_t +ngx_stream_upstream_init_random(ngx_conf_t *cf, + ngx_stream_upstream_srv_conf_t *us) +{ + ngx_log_debug0(NGX_LOG_DEBUG_STREAM, cf->log, 0, "init random"); + + if (ngx_stream_upstream_init_round_robin(cf, us) != NGX_OK) { + return NGX_ERROR; + } + + us->peer.init = ngx_stream_upstream_init_random_peer; + +#if (NGX_STREAM_UPSTREAM_ZONE) + if (us->shm_zone) { + return NGX_OK; + } +#endif + + return ngx_stream_upstream_update_random(cf->pool, us); +} + + +static ngx_int_t +ngx_stream_upstream_update_random(ngx_pool_t *pool, + ngx_stream_upstream_srv_conf_t *us) +{ + size_t size; + ngx_uint_t i, total_weight; + ngx_stream_upstream_rr_peer_t *peer; + ngx_stream_upstream_rr_peers_t *peers; + ngx_stream_upstream_random_range_t *ranges; + ngx_stream_upstream_random_srv_conf_t *rcf; + + rcf = ngx_stream_conf_upstream_srv_conf(us, + ngx_stream_upstream_random_module); + peers = us->peer.data; + + size = peers->number * sizeof(ngx_stream_upstream_random_range_t); + + ranges = pool ? ngx_palloc(pool, size) : ngx_alloc(size, ngx_cycle->log); + if (ranges == NULL) { + return NGX_ERROR; + } + + total_weight = 0; + + for (peer = peers->peer, i = 0; peer; peer = peer->next, i++) { + ranges[i].peer = peer; + ranges[i].range = total_weight; + total_weight += peer->weight; + } + + rcf->ranges = ranges; + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_upstream_init_random_peer(ngx_stream_session_t *s, + ngx_stream_upstream_srv_conf_t *us) +{ + ngx_stream_upstream_random_srv_conf_t *rcf; + ngx_stream_upstream_random_peer_data_t *rp; + + ngx_log_debug0(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, + "init random peer"); + + rcf = ngx_stream_conf_upstream_srv_conf(us, + ngx_stream_upstream_random_module); + + rp = ngx_palloc(s->connection->pool, + sizeof(ngx_stream_upstream_random_peer_data_t)); + if (rp == NULL) { + return NGX_ERROR; + } + + s->upstream->peer.data = &rp->rrp; + + if (ngx_stream_upstream_init_round_robin_peer(s, us) != NGX_OK) { + return NGX_ERROR; + } + + if (rcf->two) { + s->upstream->peer.get = ngx_stream_upstream_get_random2_peer; + + } else { + s->upstream->peer.get = ngx_stream_upstream_get_random_peer; + } + + rp->conf = rcf; + rp->tries = 0; + + ngx_stream_upstream_rr_peers_rlock(rp->rrp.peers); + +#if (NGX_STREAM_UPSTREAM_ZONE) + if (rp->rrp.peers->shpool && rcf->ranges == NULL) { + if (ngx_stream_upstream_update_random(NULL, us) != NGX_OK) { + ngx_stream_upstream_rr_peers_unlock(rp->rrp.peers); + return NGX_ERROR; + } + } +#endif + + ngx_stream_upstream_rr_peers_unlock(rp->rrp.peers); + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_upstream_get_random_peer(ngx_peer_connection_t *pc, void *data) +{ + ngx_stream_upstream_random_peer_data_t *rp = data; + + time_t now; + uintptr_t m; + ngx_uint_t i, n; + ngx_stream_upstream_rr_peer_t *peer; + ngx_stream_upstream_rr_peers_t *peers; + ngx_stream_upstream_rr_peer_data_t *rrp; + + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, pc->log, 0, + "get random peer, try: %ui", pc->tries); + + rrp = &rp->rrp; + peers = rrp->peers; + + ngx_stream_upstream_rr_peers_rlock(peers); + + if (rp->tries > 20 || peers->single) { + ngx_stream_upstream_rr_peers_unlock(peers); + return ngx_stream_upstream_get_round_robin_peer(pc, rrp); + } + + pc->cached = 0; + pc->connection = NULL; + + now = ngx_time(); + + for ( ;; ) { + + i = ngx_stream_upstream_peek_random_peer(peers, rp); + + peer = rp->conf->ranges[i].peer; + + n = i / (8 * sizeof(uintptr_t)); + m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t)); + + if (rrp->tried[n] & m) { + goto next; + } + + ngx_stream_upstream_rr_peer_lock(peers, peer); + + if (peer->down) { + ngx_stream_upstream_rr_peer_unlock(peers, peer); + goto next; + } + + if (peer->max_fails + && peer->fails >= peer->max_fails + && now - peer->checked <= peer->fail_timeout) + { + ngx_stream_upstream_rr_peer_unlock(peers, peer); + goto next; + } + + if (peer->max_conns && peer->conns >= peer->max_conns) { + ngx_stream_upstream_rr_peer_unlock(peers, peer); + goto next; + } + + break; + + next: + + if (++rp->tries > 20) { + ngx_stream_upstream_rr_peers_unlock(peers); + return ngx_stream_upstream_get_round_robin_peer(pc, rrp); + } + } + + rrp->current = peer; + + if (now - peer->checked > peer->fail_timeout) { + peer->checked = now; + } + + pc->sockaddr = peer->sockaddr; + pc->socklen = peer->socklen; + pc->name = &peer->name; + + peer->conns++; + + ngx_stream_upstream_rr_peer_unlock(peers, peer); + ngx_stream_upstream_rr_peers_unlock(peers); + + rrp->tried[n] |= m; + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_upstream_get_random2_peer(ngx_peer_connection_t *pc, void *data) +{ + ngx_stream_upstream_random_peer_data_t *rp = data; + + time_t now; + uintptr_t m; + ngx_uint_t i, n, p; + ngx_stream_upstream_rr_peer_t *peer, *prev; + ngx_stream_upstream_rr_peers_t *peers; + ngx_stream_upstream_rr_peer_data_t *rrp; + + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, pc->log, 0, + "get random2 peer, try: %ui", pc->tries); + + rrp = &rp->rrp; + peers = rrp->peers; + + ngx_stream_upstream_rr_peers_wlock(peers); + + if (rp->tries > 20 || peers->single) { + ngx_stream_upstream_rr_peers_unlock(peers); + return ngx_stream_upstream_get_round_robin_peer(pc, rrp); + } + + pc->cached = 0; + pc->connection = NULL; + + now = ngx_time(); + + prev = NULL; + +#if (NGX_SUPPRESS_WARN) + p = 0; +#endif + + for ( ;; ) { + + i = ngx_stream_upstream_peek_random_peer(peers, rp); + + peer = rp->conf->ranges[i].peer; + + if (peer == prev) { + goto next; + } + + n = i / (8 * sizeof(uintptr_t)); + m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t)); + + if (rrp->tried[n] & m) { + goto next; + } + + if (peer->down) { + goto next; + } + + if (peer->max_fails + && peer->fails >= peer->max_fails + && now - peer->checked <= peer->fail_timeout) + { + goto next; + } + + if (peer->max_conns && peer->conns >= peer->max_conns) { + goto next; + } + + if (prev) { + if (peer->conns * prev->weight > prev->conns * peer->weight) { + peer = prev; + n = p / (8 * sizeof(uintptr_t)); + m = (uintptr_t) 1 << p % (8 * sizeof(uintptr_t)); + } + + break; + } + + prev = peer; + p = i; + + next: + + if (++rp->tries > 20) { + ngx_stream_upstream_rr_peers_unlock(peers); + return ngx_stream_upstream_get_round_robin_peer(pc, rrp); + } + } + + rrp->current = peer; + + if (now - peer->checked > peer->fail_timeout) { + peer->checked = now; + } + + pc->sockaddr = peer->sockaddr; + pc->socklen = peer->socklen; + pc->name = &peer->name; + + peer->conns++; + + ngx_stream_upstream_rr_peers_unlock(peers); + + rrp->tried[n] |= m; + + return NGX_OK; +} + + +static ngx_uint_t +ngx_stream_upstream_peek_random_peer(ngx_stream_upstream_rr_peers_t *peers, + ngx_stream_upstream_random_peer_data_t *rp) +{ + ngx_uint_t i, j, k, x; + + x = ngx_random() % peers->total_weight; + + i = 0; + j = peers->number; + + while (j - i > 1) { + k = (i + j) / 2; + + if (x < rp->conf->ranges[k].range) { + j = k; + + } else { + i = k; + } + } + + return i; +} + + +static void * +ngx_stream_upstream_random_create_conf(ngx_conf_t *cf) +{ + ngx_stream_upstream_random_srv_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_stream_upstream_random_srv_conf_t)); + if (conf == NULL) { + return NULL; + } + + /* + * set by ngx_pcalloc(): + * + * conf->two = 0; + */ + + return conf; +} + + +static char * +ngx_stream_upstream_random(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_stream_upstream_random_srv_conf_t *rcf = conf; + + ngx_str_t *value; + ngx_stream_upstream_srv_conf_t *uscf; + + uscf = ngx_stream_conf_get_module_srv_conf(cf, ngx_stream_upstream_module); + + if (uscf->peer.init_upstream) { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "load balancing method redefined"); + } + + uscf->peer.init_upstream = ngx_stream_upstream_init_random; + + uscf->flags = NGX_STREAM_UPSTREAM_CREATE + |NGX_STREAM_UPSTREAM_WEIGHT + |NGX_STREAM_UPSTREAM_MAX_CONNS + |NGX_STREAM_UPSTREAM_MAX_FAILS + |NGX_STREAM_UPSTREAM_FAIL_TIMEOUT + |NGX_STREAM_UPSTREAM_DOWN; + + if (cf->args->nelts == 1) { + return NGX_CONF_OK; + } + + value = cf->args->elts; + + if (ngx_strcmp(value[1].data, "two") == 0) { + rcf->two = 1; + + } else { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid parameter \"%V\"", &value[1]); + return NGX_CONF_ERROR; + } + + if (cf->args->nelts == 2) { + return NGX_CONF_OK; + } + + if (ngx_strcmp(value[2].data, "least_conn") != 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid parameter \"%V\"", &value[2]); + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} diff --git a/src/stream/ngx_stream_upstream_round_robin.c b/src/stream/ngx_stream_upstream_round_robin.c index 526de3a..36e2ec5 100644 --- a/src/stream/ngx_stream_upstream_round_robin.c +++ b/src/stream/ngx_stream_upstream_round_robin.c @@ -776,7 +776,7 @@ ngx_stream_upstream_save_round_robin_peer_session(ngx_peer_connection_t *pc, if (peers->shpool) { - ssl_session = SSL_get0_session(pc->connection->ssl->connection); + ssl_session = ngx_ssl_get0_session(pc->connection); if (ssl_session == NULL) { return; diff --git a/src/stream/ngx_stream_write_filter_module.c b/src/stream/ngx_stream_write_filter_module.c index 8fdcd37..24326c6 100644 --- a/src/stream/ngx_stream_write_filter_module.c +++ b/src/stream/ngx_stream_write_filter_module.c @@ -104,7 +104,6 @@ ngx_stream_write_filter(ngx_stream_session_t *s, ngx_chain_t *in, cl->buf->file_pos, cl->buf->file_last - cl->buf->file_pos); -#if 1 if (ngx_buf_size(cl->buf) == 0 && !ngx_buf_special(cl->buf)) { ngx_log_error(NGX_LOG_ALERT, c->log, 0, "zero size buf in writer " @@ -122,7 +121,24 @@ ngx_stream_write_filter(ngx_stream_session_t *s, ngx_chain_t *in, ngx_debug_point(); return NGX_ERROR; } -#endif + + if (ngx_buf_size(cl->buf) < 0) { + ngx_log_error(NGX_LOG_ALERT, c->log, 0, + "negative size buf in writer " + "t:%d r:%d f:%d %p %p-%p %p %O-%O", + cl->buf->temporary, + cl->buf->recycled, + cl->buf->in_file, + cl->buf->start, + cl->buf->pos, + cl->buf->last, + cl->buf->file, + cl->buf->file_pos, + cl->buf->file_last); + + ngx_debug_point(); + return NGX_ERROR; + } size += ngx_buf_size(cl->buf); @@ -160,7 +176,6 @@ ngx_stream_write_filter(ngx_stream_session_t *s, ngx_chain_t *in, cl->buf->file_pos, cl->buf->file_last - cl->buf->file_pos); -#if 1 if (ngx_buf_size(cl->buf) == 0 && !ngx_buf_special(cl->buf)) { ngx_log_error(NGX_LOG_ALERT, c->log, 0, "zero size buf in writer " @@ -178,7 +193,24 @@ ngx_stream_write_filter(ngx_stream_session_t *s, ngx_chain_t *in, ngx_debug_point(); return NGX_ERROR; } -#endif + + if (ngx_buf_size(cl->buf) < 0) { + ngx_log_error(NGX_LOG_ALERT, c->log, 0, + "negative size buf in writer " + "t:%d r:%d f:%d %p %p-%p %p %O-%O", + cl->buf->temporary, + cl->buf->recycled, + cl->buf->in_file, + cl->buf->start, + cl->buf->pos, + cl->buf->last, + cl->buf->file, + cl->buf->file_pos, + cl->buf->file_last); + + ngx_debug_point(); + return NGX_ERROR; + } size += ngx_buf_size(cl->buf); From b2a3e22c477fc51206c2f0823b00684b6f1c2b92 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Sun, 8 Sep 2019 10:44:49 +0300 Subject: [PATCH 010/329] Drop debian CVE patches already included in 1.16.1 --- debian/patches/CVE-2019-9511.patch | 87 ------------------------------ debian/patches/CVE-2019-9513.patch | 62 --------------------- debian/patches/CVE-2019-9516.patch | 45 ---------------- debian/patches/series | 3 -- 4 files changed, 197 deletions(-) delete mode 100644 debian/patches/CVE-2019-9511.patch delete mode 100644 debian/patches/CVE-2019-9513.patch delete mode 100644 debian/patches/CVE-2019-9516.patch diff --git a/debian/patches/CVE-2019-9511.patch b/debian/patches/CVE-2019-9511.patch deleted file mode 100644 index 3b48e0c..0000000 --- a/debian/patches/CVE-2019-9511.patch +++ /dev/null @@ -1,87 +0,0 @@ -From 3f64486e0c15414dc6368139453dcaca338ddf3e Mon Sep 17 00:00:00 2001 -From: Ruslan Ermilov -Date: Tue, 13 Aug 2019 15:43:36 +0300 -Subject: [PATCH 2/3] HTTP/2: limited number of DATA frames. - -Fixed excessive memory growth and CPU usage if stream windows are -manipulated in a way that results in generating many small DATA frames. -Fix is to limit the number of simultaneously allocated DATA frames. ---- - src/http/v2/ngx_http_v2.c | 2 ++ - src/http/v2/ngx_http_v2.h | 2 ++ - src/http/v2/ngx_http_v2_filter_module.c | 22 +++++++++++++++++----- - 3 files changed, 21 insertions(+), 5 deletions(-) - -diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c -index be2ef82b..1b01f271 100644 ---- a/src/http/v2/ngx_http_v2.c -+++ b/src/http/v2/ngx_http_v2.c -@@ -4339,6 +4339,8 @@ ngx_http_v2_close_stream(ngx_http_v2_stream_t *stream, ngx_int_t rc) - */ - pool = stream->pool; - -+ h2c->frames -= stream->frames; -+ - ngx_http_free_request(stream->request, rc); - - if (pool != h2c->state.pool) { -diff --git a/src/http/v2/ngx_http_v2.h b/src/http/v2/ngx_http_v2.h -index bec22160..715b7d30 100644 ---- a/src/http/v2/ngx_http_v2.h -+++ b/src/http/v2/ngx_http_v2.h -@@ -192,6 +192,8 @@ struct ngx_http_v2_stream_s { - - ngx_buf_t *preread; - -+ ngx_uint_t frames; -+ - ngx_http_v2_out_frame_t *free_frames; - ngx_chain_t *free_frame_headers; - ngx_chain_t *free_bufs; -diff --git a/src/http/v2/ngx_http_v2_filter_module.c b/src/http/v2/ngx_http_v2_filter_module.c -index 029e8ece..c7ee5536 100644 ---- a/src/http/v2/ngx_http_v2_filter_module.c -+++ b/src/http/v2/ngx_http_v2_filter_module.c -@@ -1661,22 +1661,34 @@ static ngx_http_v2_out_frame_t * - ngx_http_v2_filter_get_data_frame(ngx_http_v2_stream_t *stream, - size_t len, ngx_chain_t *first, ngx_chain_t *last) - { -- u_char flags; -- ngx_buf_t *buf; -- ngx_chain_t *cl; -- ngx_http_v2_out_frame_t *frame; -+ u_char flags; -+ ngx_buf_t *buf; -+ ngx_chain_t *cl; -+ ngx_http_v2_out_frame_t *frame; -+ ngx_http_v2_connection_t *h2c; - - frame = stream->free_frames; -+ h2c = stream->connection; - - if (frame) { - stream->free_frames = frame->next; - -- } else { -+ } else if (h2c->frames < 10000) { - frame = ngx_palloc(stream->request->pool, - sizeof(ngx_http_v2_out_frame_t)); - if (frame == NULL) { - return NULL; - } -+ -+ stream->frames++; -+ h2c->frames++; -+ -+ } else { -+ ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, -+ "http2 flood detected"); -+ -+ h2c->connection->error = 1; -+ return NULL; - } - - flags = last->buf->last_buf ? NGX_HTTP_V2_END_STREAM_FLAG : 0; --- -2.20.1 - diff --git a/debian/patches/CVE-2019-9513.patch b/debian/patches/CVE-2019-9513.patch deleted file mode 100644 index edc1c2b..0000000 --- a/debian/patches/CVE-2019-9513.patch +++ /dev/null @@ -1,62 +0,0 @@ -From bbdc81631b6d322785d8e92788fd400e25a931e6 Mon Sep 17 00:00:00 2001 -From: Ruslan Ermilov -Date: Tue, 13 Aug 2019 15:43:40 +0300 -Subject: [PATCH 3/3] HTTP/2: limited number of PRIORITY frames. - -Fixed excessive CPU usage caused by a peer that continuously shuffles -priority of streams. Fix is to limit the number of PRIORITY frames. ---- - src/http/v2/ngx_http_v2.c | 10 ++++++++++ - src/http/v2/ngx_http_v2.h | 1 + - 2 files changed, 11 insertions(+) - -diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c -index 1b01f271..fd6ecb05 100644 ---- a/src/http/v2/ngx_http_v2.c -+++ b/src/http/v2/ngx_http_v2.c -@@ -275,6 +275,7 @@ ngx_http_v2_init(ngx_event_t *rev) - h2scf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_v2_module); - - h2c->concurrent_pushes = h2scf->concurrent_pushes; -+ h2c->priority_limit = h2scf->concurrent_streams; - - h2c->pool = ngx_create_pool(h2scf->pool_size, h2c->connection->log); - if (h2c->pool == NULL) { -@@ -1806,6 +1807,13 @@ ngx_http_v2_state_priority(ngx_http_v2_connection_t *h2c, u_char *pos, - return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR); - } - -+ if (--h2c->priority_limit == 0) { -+ ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, -+ "client sent too many PRIORITY frames"); -+ -+ return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_ENHANCE_YOUR_CALM); -+ } -+ - if (end - pos < NGX_HTTP_V2_PRIORITY_SIZE) { - return ngx_http_v2_state_save(h2c, pos, end, - ngx_http_v2_state_priority); -@@ -3120,6 +3128,8 @@ ngx_http_v2_create_stream(ngx_http_v2_connection_t *h2c, ngx_uint_t push) - h2c->processing++; - } - -+ h2c->priority_limit += h2scf->concurrent_streams; -+ - return stream; - } - -diff --git a/src/http/v2/ngx_http_v2.h b/src/http/v2/ngx_http_v2.h -index 715b7d30..69d55d1c 100644 ---- a/src/http/v2/ngx_http_v2.h -+++ b/src/http/v2/ngx_http_v2.h -@@ -122,6 +122,7 @@ struct ngx_http_v2_connection_s { - ngx_uint_t processing; - ngx_uint_t frames; - ngx_uint_t idle; -+ ngx_uint_t priority_limit; - - ngx_uint_t pushing; - ngx_uint_t concurrent_pushes; --- -2.20.1 - diff --git a/debian/patches/CVE-2019-9516.patch b/debian/patches/CVE-2019-9516.patch deleted file mode 100644 index 0d5ec77..0000000 --- a/debian/patches/CVE-2019-9516.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 840d8a3e2f126384eb4ee3e5dd7ffe875a5634c5 Mon Sep 17 00:00:00 2001 -From: Sergey Kandaurov -Date: Tue, 13 Aug 2019 15:43:32 +0300 -Subject: [PATCH 1/3] HTTP/2: reject zero length headers with PROTOCOL_ERROR. - -Fixed uncontrolled memory growth if peer sends a stream of -headers with a 0-length header name and 0-length header value. -Fix is to reject headers with zero name length. ---- - src/http/v2/ngx_http_v2.c | 12 ++++++++---- - 1 file changed, 8 insertions(+), 4 deletions(-) - -diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c -index 12214e15..be2ef82b 100644 ---- a/src/http/v2/ngx_http_v2.c -+++ b/src/http/v2/ngx_http_v2.c -@@ -1548,6 +1548,14 @@ ngx_http_v2_state_process_header(ngx_http_v2_connection_t *h2c, u_char *pos, - header->name.len = h2c->state.field_end - h2c->state.field_start; - header->name.data = h2c->state.field_start; - -+ if (header->name.len == 0) { -+ ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, -+ "client sent zero header name length"); -+ -+ return ngx_http_v2_connection_error(h2c, -+ NGX_HTTP_V2_PROTOCOL_ERROR); -+ } -+ - return ngx_http_v2_state_field_len(h2c, pos, end); - } - -@@ -3249,10 +3257,6 @@ ngx_http_v2_validate_header(ngx_http_request_t *r, ngx_http_v2_header_t *header) - ngx_uint_t i; - ngx_http_core_srv_conf_t *cscf; - -- if (header->name.len == 0) { -- return NGX_ERROR; -- } -- - r->invalid_header = 0; - - cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); --- -2.20.1 - diff --git a/debian/patches/series b/debian/patches/series index dfc20c1..5b6b799 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -1,5 +1,2 @@ 0002-Make-sure-signature-stays-the-same-in-all-nginx-buil.patch 0003-define_gnu_source-on-other-glibc-based-platforms.patch -CVE-2019-9516.patch -CVE-2019-9511.patch -CVE-2019-9513.patch From 85ba84543384c260ee728b14c2b68eec6cd7a118 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Mon, 9 Sep 2019 17:31:40 +0300 Subject: [PATCH 011/329] http-ndk: Upgrade to 0.3.1 --- debian/modules/control | 2 +- debian/modules/http-ndk/.gitignore | 4 ++ debian/modules/http-ndk/LICENSE | 2 +- debian/modules/http-ndk/README.md | 30 ++++++++++--- .../{README_AUTO_LIB => README_AUTO_LIB.md} | 43 +++++++++---------- debian/modules/http-ndk/TODO | 1 - debian/modules/http-ndk/src/ndk_regex.c | 4 +- 7 files changed, 52 insertions(+), 34 deletions(-) create mode 100644 debian/modules/http-ndk/.gitignore rename debian/modules/http-ndk/{README_AUTO_LIB => README_AUTO_LIB.md} (96%) delete mode 100644 debian/modules/http-ndk/TODO diff --git a/debian/modules/control b/debian/modules/control index a5d65a8..f27ca7c 100644 --- a/debian/modules/control +++ b/debian/modules/control @@ -5,7 +5,7 @@ Files-Excluded: .gitignore .gitattributes .travis.yml Module: http-ndk Homepage: https://github.com/simpl/ngx_devel_kit/ -Version: 0.3.0 +Version: 0.3.1 Module: http-auth-pam Homepage: https://github.com/stogh/ngx_http_auth_pam_module diff --git a/debian/modules/http-ndk/.gitignore b/debian/modules/http-ndk/.gitignore new file mode 100644 index 0000000..0fd79d0 --- /dev/null +++ b/debian/modules/http-ndk/.gitignore @@ -0,0 +1,4 @@ +tags +cscope.* +*~ +*.swp diff --git a/debian/modules/http-ndk/LICENSE b/debian/modules/http-ndk/LICENSE index ee54448..e1a5221 100644 --- a/debian/modules/http-ndk/LICENSE +++ b/debian/modules/http-ndk/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2010-2015, Marcus Clyne +Copyright (c) 2010-2018, Marcus Clyne All rights reserved. diff --git a/debian/modules/http-ndk/README.md b/debian/modules/http-ndk/README.md index e0ed4eb..d9d3972 100644 --- a/debian/modules/http-ndk/README.md +++ b/debian/modules/http-ndk/README.md @@ -1,7 +1,7 @@ Name ==== -NDK - Nginx Development Kit +Nginx Development Kit (NDK) Table of Contents ================= @@ -21,7 +21,8 @@ Table of Contents * [TODO](#todo) * [License](#license) * [Contributing / Feedback](#contributing--feedback) -* [Author](#author) +* [Authors](#authors) +* [Special Thanks](#special-thanks) Synopsis ======== @@ -42,11 +43,15 @@ their own modules which features of the NDK they wish to use (explained below). If you are not an Nginx module developer, then the only useful part of this project will be the 'usage for users' section below. +[Back to TOC](#table-of-contents) + Status ====== The NDK is now considered to be stable. It is already being used in quite a few third -party modules. +party modules (see list below). + +[Back to TOC](#table-of-contents) Features ======== @@ -151,7 +156,7 @@ displayed when compiling Nginx. [Back to TOC](#table-of-contents) -Warning: using NDK_ALL +Warning: Using NDK_ALL ---------------------- You can also set `NDK_ALL` to include all the NDK modules. This is primarily as @@ -177,6 +182,8 @@ The following 3rd-party modules make use of NDK. * [ngx_http_iconv_module](https://github.com/calio/iconv-nginx-module#readme) * [ngx_http_array_var_module](https://github.com/openresty/array-var-nginx-module#readme) +If you would like to add your module to this list, please let us know. + [Back to TOC](#table-of-contents) TODO @@ -186,13 +193,14 @@ TODO * additional phase-handler functions * generically testing for needing to add a handler * remove dependency of set_var on OpenSSL being compiled in +* for backward compatability, add the ndk_macros [Back to TOC](#table-of-contents) License ======= -Copyright (c) 2010-2016, Marcus Clyne +Copyright (c) 2010-2018, Marcus Clyne All rights reserved. @@ -225,14 +233,22 @@ Contributing / Feedback If you are an Nginx module developer, and have developed some functions that are generic in nature (or would be easily adapted to be so), then please send them to -me at the address below, and I'll add them to the kit. +me at the address below, and I'll addmclyne to the kit. [Back to TOC](#table-of-contents) Author ====== -Marcus Clyne (contact at simpl dot it) +[Marcus Clyne](https://github.com/mclyne) [Back to TOC](#table-of-contents) + +Special Thanks +============== + +A special thanks goes to [Yichun Zhang](https://github.com/agentzh) for helping to maintain +this module. + +[Back to TOC](#table-of-contents) diff --git a/debian/modules/http-ndk/README_AUTO_LIB b/debian/modules/http-ndk/README_AUTO_LIB.md similarity index 96% rename from debian/modules/http-ndk/README_AUTO_LIB rename to debian/modules/http-ndk/README_AUTO_LIB.md index fd2776f..f2c3371 100644 --- a/debian/modules/http-ndk/README_AUTO_LIB +++ b/debian/modules/http-ndk/README_AUTO_LIB.md @@ -10,7 +10,7 @@ cross-platform way to include external libraries. Any developers of Nginx modules are encouraged to use Auto Lib Core to handle library dependencies for their modules rather than writing their own custom handler from scratch. -Note : the latest version can be found at github.com/simpl/ngx_auto_lib +Note : The latest version can be found [here](https://github.com/simplresty/ngx_auto_lib). Information for end users @@ -68,7 +68,7 @@ Specifying a path to find a library If the version of a library you wish to include is in any of the standard paths (e.g. /usr/local, /usr ...), you will not need to specify a path to include the library. -If you do wish to specify a specific path, in most cases just specifying +If you do wish to specify a specific path, in most cases just specifying [PFX]=/path/to/library will be sufficient. e.g. $ export MOZJS=/path/to/mozjs @@ -106,8 +106,8 @@ searched. When searching under [PFX]_BASE no prefix is added to the search, but when searching under the directory that the Nginx source is located in, the prefix [pfx]- is automatically added. -Note : there is currently a minor bug (due to the implementation of the 'sort' command) -means versions that include hyphens (e.g. 1.0.0-beta5) are checked before versions like +Note : there is currently a minor bug (due to the implementation of the 'sort' command) +means versions that include hyphens (e.g. 1.0.0-beta5) are checked before versions like 1.0.0a. This will be fixed soon, and searching of -build folders before normal source ones will be added too. @@ -119,7 +119,7 @@ Shared or static? The default for most libraries is to look for shared libraries, though this can be overridden by the user by setting [PFX]_SHARED=NO. -In the near future the default action will be to look for shared libraries then to look +In the near future the default action will be to look for shared libraries then to look for static libraries in each directory searched unless one of [PFX]_SHARED and/or [PFX]_STATIC = NO. If both are set to NO, then Auto Lib will not be used at all. @@ -154,7 +154,7 @@ How Auto Lib Core works ----------------------- Auto Lib Core works as an interface layer between the module and the auto/feature part of -the Nginx source. This is the file that results in the 'checking for ...' lines that you +the Nginx source. This is the file that results in the 'checking for ...' lines that you see when you call ./configure. auto/feature works by using a few key variables (see below) to generate some C code, trying @@ -162,8 +162,8 @@ to compile it to see if it works and optionally running the code. This output fi autotest.c (located under the objs/ directory whilst configure is running, but is deleted after each call to auto/feature). -Normally, whenever an external library is required, a module developer will write a number -of calls to auto/feature manually in their config files - e.g. to check under a range of +Normally, whenever an external library is required, a module developer will write a number +of calls to auto/feature manually in their config files - e.g. to check under a range of different possible locations to find a library. Apart from being tedious, this is obviously potentially error-prone. @@ -180,7 +180,7 @@ Option 1 : located - add the following line to your config file - . $ngx_addon_dir/ngx_auto_lib_core + . $ngx_addon_dir/ngx_auto_lib_core NOTE : if you want to include the file in a different directory to your config file, you will need to change both the include line in your config file AND @@ -189,7 +189,7 @@ has $ngx_addon_dir/ngx_auto_lib_core in it) Option 2 : -- make the Nginx Development Kit (github.com/simpl-it/ngx_devel_kit) a dependency +- make the Nginx Development Kit (github.com/simpl-it/ngx_devel_kit) a dependency for your module (Auto Lib Core is included automatically with it) @@ -229,10 +229,10 @@ Calling ngx_auto_lib_init() and ngx_auto_lib_run() You can pass either one or two variables to ngx_auto_lib_init(). The first is the name of the library as it will appear when running ./configure, the second is the prefix that is -used for internal variables and looking for directory prefixes. If the second is not +used for internal variables and looking for directory prefixes. If the second is not specified, it defaults to the first. -The init function resets all key variables and functions, so it must be called before +The init function resets all key variables and functions, so it must be called before setting any other variables or functions that are to be used as hooks (see the notes below). ngx_auto_lib_run() should be called in the config files after all the variables and hooks @@ -315,9 +315,9 @@ Hooks To facilitate using Auto Lib Core in a flexible way, a number of 'hooks' have been placed in the testing cycle. These hooks are implemented as functions that you define -in your config file which are called if required by the core library. In the core +in your config file which are called if required by the core library. In the core library they are left as empty functions that return either 0 or 1. Any functions -you write will +you write will Note : ngx_auto_lib_init() resets the variables and functions each time it is called, so you must DEFINE HOOKS AFTER YOU CALL ngx_auto_lib_init. @@ -337,7 +337,7 @@ Although in most cases Auto Lib Core will be used where external libraries are definitely required (for a module to work), this may not always be the case. In the standard Nginx Auto Lib module (github.com/simpl-it/ngx_auto_lib) - which is designed to improve the inclusion of OpenSSL, PCRE and Zlib libraries and increase compilation -speed where possible - the libraries are not always required, so checks are made to +speed where possible - the libraries are not always required, so checks are made to see if it is necessary. @@ -348,11 +348,11 @@ How Auto Lib Core checks if a library is required - ngx_auto_lib_check_require() - search for USE_[PFX]=YES (it is set to YES by default for most modules) - search for any external libraries that have been included in the CORE_LIBS or ADDON_LIBS variables that use the same lib name as any set in ngx_feature_lib_names -- search for any macros that have been defined either in the CFLAGS variable or using - auto/have or auto/define as set in the ngx_feature_check_macros_defined and +- search for any macros that have been defined either in the CFLAGS variable or using + auto/have or auto/define as set in the ngx_feature_check_macros_defined and ngx_feature_ngx_macros_non_zero variables - any custom checks implemented by creating an ngx_auto_lib_check hook function (which - should return 0 if the library is required and return 1 at the end if the module is + should return 0 if the library is required and return 1 at the end if the module is not required) @@ -378,8 +378,8 @@ that the linker links to is the same as the one specified. This is done because To do ----- -- change how library paths are searched to include both shared and static libraries -- touch up documentation +- Change how library paths are searched to include both shared and static libraries +- Touch up documentation License @@ -391,5 +391,4 @@ License Copyright --------- - Marcus Clyne (c) 2010 (http://simpl.it) - + [Marcus Clyne](https://github.com/mclyne) (c) 2010 diff --git a/debian/modules/http-ndk/TODO b/debian/modules/http-ndk/TODO deleted file mode 100644 index 0acf8bf..0000000 --- a/debian/modules/http-ndk/TODO +++ /dev/null @@ -1 +0,0 @@ -- for backward compatability, add the ndk_macros diff --git a/debian/modules/http-ndk/src/ndk_regex.c b/debian/modules/http-ndk/src/ndk_regex.c index d5893df..c1efd86 100644 --- a/debian/modules/http-ndk/src/ndk_regex.c +++ b/debian/modules/http-ndk/src/ndk_regex.c @@ -100,7 +100,7 @@ ndk_conf_set_regex_array_slot (ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_array_t **a; ngx_regex_elt_t *re; ngx_regex_compile_t rc; - ngx_uint_t i, n; + ngx_uint_t i, n = 0; u_char errstr[NGX_MAX_CONF_ERRSTR]; a = (ngx_array_t **) (p + cmd->offset); @@ -162,7 +162,7 @@ ndk_conf_set_regex_array_caseless_slot (ngx_conf_t *cf, ngx_command_t *cmd, void ngx_array_t **a; ngx_regex_elt_t *re; ngx_regex_compile_t rc; - ngx_uint_t i, n; + ngx_uint_t i, n = 0; u_char errstr[NGX_MAX_CONF_ERRSTR]; a = (ngx_array_t **) (p + cmd->offset); From 132704ab76aa72ce29d00e4acd50d3218693558b Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Mon, 9 Sep 2019 17:32:06 +0300 Subject: [PATCH 012/329] http-lua: Upgrade to 0.10.15 --- debian/modules/control | 2 +- debian/modules/http-lua/README.markdown | 235 +- debian/modules/http-lua/config | 45 + .../modules/http-lua/doc/HttpLuaModule.wiki | 213 +- .../http-lua/src/api/ngx_http_lua_api.h | 2 +- .../http-lua/src/ngx_http_lua_accessby.c | 4 +- .../modules/http-lua/src/ngx_http_lua_api.c | 2 +- .../http-lua/src/ngx_http_lua_balancer.c | 3 + .../http-lua/src/ngx_http_lua_bodyfilterby.c | 50 +- .../http-lua/src/ngx_http_lua_bodyfilterby.h | 2 +- .../modules/http-lua/src/ngx_http_lua_cache.c | 23 +- .../http-lua/src/ngx_http_lua_clfactory.c | 45 +- .../http-lua/src/ngx_http_lua_common.h | 49 +- .../http-lua/src/ngx_http_lua_contentby.c | 2 + .../http-lua/src/ngx_http_lua_control.c | 3 +- .../http-lua/src/ngx_http_lua_coroutine.c | 18 +- .../http-lua/src/ngx_http_lua_directive.c | 11 +- .../src/ngx_http_lua_headerfilterby.c | 3 +- .../http-lua/src/ngx_http_lua_headers.c | 83 +- .../http-lua/src/ngx_http_lua_headers_in.c | 10 +- .../http-lua/src/ngx_http_lua_headers_out.c | 20 +- .../http-lua/src/ngx_http_lua_headers_out.h | 6 +- .../http-lua/src/ngx_http_lua_initworkerby.c | 19 + .../http-lua/src/ngx_http_lua_input_filters.c | 137 + .../http-lua/src/ngx_http_lua_input_filters.h | 29 + .../modules/http-lua/src/ngx_http_lua_logby.c | 3 +- .../modules/http-lua/src/ngx_http_lua_misc.c | 27 + .../http-lua/src/ngx_http_lua_module.c | 56 + .../modules/http-lua/src/ngx_http_lua_ndk.c | 41 + .../modules/http-lua/src/ngx_http_lua_pipe.c | 2475 +++++++++++++++++ .../modules/http-lua/src/ngx_http_lua_pipe.h | 95 + .../modules/http-lua/src/ngx_http_lua_regex.c | 10 +- .../http-lua/src/ngx_http_lua_rewriteby.c | 4 +- .../http-lua/src/ngx_http_lua_script.c | 4 +- .../modules/http-lua/src/ngx_http_lua_setby.c | 34 +- .../modules/http-lua/src/ngx_http_lua_setby.h | 2 +- .../http-lua/src/ngx_http_lua_shdict.c | 44 +- .../http-lua/src/ngx_http_lua_socket_tcp.c | 1608 +++++++---- .../http-lua/src/ngx_http_lua_socket_tcp.h | 29 +- .../http-lua/src/ngx_http_lua_socket_udp.c | 12 +- .../http-lua/src/ngx_http_lua_ssl_certby.c | 2 + .../src/ngx_http_lua_ssl_session_fetchby.c | 2 + .../src/ngx_http_lua_ssl_session_storeby.c | 3 + .../http-lua/src/ngx_http_lua_string.c | 14 + .../http-lua/src/ngx_http_lua_subrequest.c | 8 + .../modules/http-lua/src/ngx_http_lua_timer.c | 44 +- .../http-lua/src/ngx_http_lua_uthread.c | 3 +- .../modules/http-lua/src/ngx_http_lua_util.c | 168 +- .../modules/http-lua/src/ngx_http_lua_util.h | 28 +- .../http-lua/src/ngx_http_lua_worker.c | 11 + debian/modules/http-lua/t/000--init.t | 5 - debian/modules/http-lua/t/001-set.t | 23 +- debian/modules/http-lua/t/002-content.t | 38 +- debian/modules/http-lua/t/004-require.t | 12 +- debian/modules/http-lua/t/005-exit.t | 2 +- debian/modules/http-lua/t/009-log.t | 12 +- debian/modules/http-lua/t/011-md5_bin.t | 2 +- debian/modules/http-lua/t/013-base64.t | 2 +- debian/modules/http-lua/t/014-bugs.t | 49 +- debian/modules/http-lua/t/016-resp-header.t | 504 +++- debian/modules/http-lua/t/017-exec.t | 4 +- debian/modules/http-lua/t/020-subrequest.t | 134 +- .../http-lua/t/023-rewrite/client-abort.t | 6 +- debian/modules/http-lua/t/023-rewrite/exec.t | 4 +- debian/modules/http-lua/t/023-rewrite/mixed.t | 4 +- .../http-lua/t/023-rewrite/multi-capture.t | 2 +- .../http-lua/t/023-rewrite/req-socket.t | 6 +- .../modules/http-lua/t/023-rewrite/sanity.t | 28 +- .../http-lua/t/023-rewrite/socket-keepalive.t | 12 +- .../http-lua/t/023-rewrite/subrequest.t | 42 +- .../t/023-rewrite/tcp-socket-timeout.t | 12 +- .../http-lua/t/023-rewrite/tcp-socket.t | 32 +- .../http-lua/t/023-rewrite/uthread-exec.t | 12 +- .../http-lua/t/023-rewrite/uthread-exit.t | 40 +- .../http-lua/t/023-rewrite/uthread-redirect.t | 4 +- .../http-lua/t/023-rewrite/uthread-spawn.t | 62 +- .../http-lua/t/024-access/client-abort.t | 6 +- debian/modules/http-lua/t/024-access/exec.t | 2 +- debian/modules/http-lua/t/024-access/mixed.t | 10 +- .../http-lua/t/024-access/multi-capture.t | 2 +- debian/modules/http-lua/t/024-access/sanity.t | 30 +- .../http-lua/t/024-access/subrequest.t | 42 +- .../http-lua/t/024-access/uthread-exec.t | 12 +- .../http-lua/t/024-access/uthread-exit.t | 38 +- .../http-lua/t/024-access/uthread-redirect.t | 4 +- .../http-lua/t/024-access/uthread-spawn.t | 62 +- debian/modules/http-lua/t/025-codecache.t | 174 +- debian/modules/http-lua/t/027-multi-capture.t | 4 +- debian/modules/http-lua/t/028-req-header.t | 24 +- debian/modules/http-lua/t/030-uri-args.t | 23 +- debian/modules/http-lua/t/034-match.t | 65 +- debian/modules/http-lua/t/035-gmatch.t | 22 +- debian/modules/http-lua/t/036-sub.t | 4 +- debian/modules/http-lua/t/037-gsub.t | 2 +- debian/modules/http-lua/t/038-match-o.t | 44 +- debian/modules/http-lua/t/041-header-filter.t | 15 +- debian/modules/http-lua/t/043-shdict.t | 4 +- debian/modules/http-lua/t/047-match-jit.t | 12 +- debian/modules/http-lua/t/048-match-dfa.t | 12 +- debian/modules/http-lua/t/055-subreq-vars.t | 18 +- debian/modules/http-lua/t/056-flush.t | 2 +- debian/modules/http-lua/t/057-flush-timeout.t | 2 +- debian/modules/http-lua/t/058-tcp-socket.t | 364 ++- debian/modules/http-lua/t/062-count.t | 31 +- debian/modules/http-lua/t/063-abort.t | 62 +- debian/modules/http-lua/t/064-pcall.t | 14 +- .../http-lua/t/065-tcp-socket-timeout.t | 24 +- .../http-lua/t/066-socket-receiveuntil.t | 30 +- debian/modules/http-lua/t/067-req-socket.t | 6 +- .../modules/http-lua/t/068-socket-keepalive.t | 1467 +++++++++- debian/modules/http-lua/t/073-backtrace.t | 14 +- debian/modules/http-lua/t/075-logby.t | 11 +- debian/modules/http-lua/t/081-bytecode.t | 45 +- debian/modules/http-lua/t/082-body-filter.t | 3 +- .../http-lua/t/084-inclusive-receiveuntil.t | 20 +- debian/modules/http-lua/t/087-udp-socket.t | 12 +- .../http-lua/t/090-log-socket-errors.t | 10 +- debian/modules/http-lua/t/091-coroutine.t | 81 +- debian/modules/http-lua/t/093-uthread-spawn.t | 66 +- debian/modules/http-lua/t/094-uthread-exit.t | 46 +- debian/modules/http-lua/t/095-uthread-exec.t | 14 +- .../modules/http-lua/t/096-uthread-redirect.t | 6 +- .../modules/http-lua/t/097-uthread-rewrite.t | 12 +- debian/modules/http-lua/t/098-uthread-wait.t | 74 +- debian/modules/http-lua/t/099-c-api.t | 10 +- debian/modules/http-lua/t/100-client-abort.t | 6 +- debian/modules/http-lua/t/106-timer.t | 18 +- debian/modules/http-lua/t/108-timer-safe.t | 16 +- debian/modules/http-lua/t/109-timer-hup.t | 18 +- debian/modules/http-lua/t/120-re-find.t | 4 +- debian/modules/http-lua/t/123-lua-path.t | 10 +- debian/modules/http-lua/t/124-init-worker.t | 10 +- debian/modules/http-lua/t/126-shdict-frag.t | 4 +- debian/modules/http-lua/t/127-uthread-kill.t | 26 +- .../http-lua/t/128-duplex-tcp-socket.t | 6 +- debian/modules/http-lua/t/129-ssl-socket.t | 16 +- debian/modules/http-lua/t/130-internal-api.t | 17 +- .../modules/http-lua/t/134-worker-count-5.t | 4 +- debian/modules/http-lua/t/138-balancer.t | 2 - debian/modules/http-lua/t/139-ssl-cert-by.t | 2 +- debian/modules/http-lua/t/140-ssl-c-api.t | 23 +- .../http-lua/t/143-ssl-session-fetch.t | 105 + .../http-lua/t/147-tcp-socket-timeouts.t | 8 +- debian/modules/http-lua/t/152-timer-every.t | 4 +- debian/modules/http-lua/t/153-semaphore-hup.t | 2 +- debian/modules/http-lua/t/156-slow-network.t | 138 + .../http-lua/t/157-socket-keepalive-hup.t | 91 + debian/modules/http-lua/t/158-global-var.t | 508 ++++ debian/modules/http-lua/t/159-sa-restart.t | 180 ++ .../http-lua/t/160-disable-init-by-lua.t | 194 ++ .../modules/http-lua/t/161-load-resty-core.t | 68 + .../ngx_http_lua_fake_shm_module.c | 22 +- debian/modules/http-lua/util/build.sh | 4 +- 153 files changed, 9493 insertions(+), 1866 deletions(-) create mode 100644 debian/modules/http-lua/src/ngx_http_lua_input_filters.c create mode 100644 debian/modules/http-lua/src/ngx_http_lua_input_filters.h create mode 100644 debian/modules/http-lua/src/ngx_http_lua_pipe.c create mode 100644 debian/modules/http-lua/src/ngx_http_lua_pipe.h create mode 100644 debian/modules/http-lua/t/156-slow-network.t create mode 100644 debian/modules/http-lua/t/157-socket-keepalive-hup.t create mode 100644 debian/modules/http-lua/t/158-global-var.t create mode 100644 debian/modules/http-lua/t/159-sa-restart.t create mode 100644 debian/modules/http-lua/t/160-disable-init-by-lua.t create mode 100644 debian/modules/http-lua/t/161-load-resty-core.t diff --git a/debian/modules/control b/debian/modules/control index f27ca7c..8331ff5 100644 --- a/debian/modules/control +++ b/debian/modules/control @@ -18,7 +18,7 @@ Files-Excluded: .gitignore .gitattributes .travis.yml Module: http-lua Homepage: https://github.com/openresty/lua-nginx-module -Version: 0.10.13 +Version: 0.10.15 Patch: openssl-1.1.0.patch discover-luajit-2.1.patch diff --git a/debian/modules/http-lua/README.markdown b/debian/modules/http-lua/README.markdown index 15ad00e..ed0c72d 100644 --- a/debian/modules/http-lua/README.markdown +++ b/debian/modules/http-lua/README.markdown @@ -8,6 +8,8 @@ Name ngx_http_lua_module - Embed the power of Lua into Nginx HTTP Servers. +This module is a core component of OpenResty. If you are using this module, then you are essentially using OpenResty :) + *This module is not distributed with the Nginx source.* See [the installation instructions](#installation). Table of Contents @@ -23,7 +25,6 @@ Table of Contents * [Installation](#installation) * [Building as a dynamic module](#building-as-a-dynamic-module) * [C Macro Configurations](#c-macro-configurations) - * [Installation on Ubuntu 11.10](#installation-on-ubuntu-1110) * [Community](#community) * [English Mailing List](#english-mailing-list) * [Chinese Mailing List](#chinese-mailing-list) @@ -62,7 +63,7 @@ Production ready. Version ======= -This document describes ngx_lua [v0.10.13](https://github.com/openresty/lua-nginx-module/tags) released on 22 April 2018. +This document describes ngx_lua [v0.10.15](https://github.com/openresty/lua-nginx-module/tags) released on March 14th, 2019. Synopsis ======== @@ -187,7 +188,9 @@ Synopsis Description =========== -This module embeds Lua, via the standard Lua 5.1 interpreter or [LuaJIT 2.0/2.1](http://luajit.org/luajit.html), into Nginx and by leveraging Nginx's subrequests, allows the integration of the powerful Lua threads (Lua coroutines) into the Nginx event model. +This module is a core component of OpenResty. If you are using this module, then you are essentially using OpenResty :) + +This module embeds Lua, via [LuaJIT 2.0/2.1](http://luajit.org/luajit.html), into Nginx and by leveraging Nginx's subrequests, allows the integration of the powerful Lua threads (Lua coroutines) into the Nginx event model. Unlike [Apache's mod_lua](https://httpd.apache.org/docs/trunk/mod/mod_lua.html) and [Lighttpd's mod_magnet](http://redmine.lighttpd.net/wiki/1/Docs:ModMagnet), Lua code executed using this module can be *100% non-blocking* on network traffic as long as the [Nginx API for Lua](#nginx-api-for-lua) provided by this module is used to handle requests to upstream services such as MySQL, PostgreSQL, Memcached, Redis, or upstream HTTP web services. @@ -265,11 +268,11 @@ Nginx cores older than 1.6.0 (exclusive) are *not* supported. Installation ============ -It is *highly* recommended to use [OpenResty releases](http://openresty.org) which integrate Nginx, ngx_lua, LuaJIT 2.1, as well as other powerful companion Nginx modules and Lua libraries. It is discouraged to build this module with nginx yourself since it is tricky to set up exactly right. Also, the stock nginx cores have various limitations and long standing bugs that can make some of this modules' features become disabled, not work properly, or run slower. The same applies to LuaJIT as well. OpenResty includes its own version of LuaJIT which gets specifically optimized and enhanced for the OpenResty environment. +It is *highly* recommended to use [OpenResty releases](http://openresty.org) which integrate Nginx, ngx_lua, OpenResty's LuaJIT 2.1 branch version, as well as other powerful companion Nginx modules and Lua libraries. It is discouraged to build this module with nginx yourself since it is tricky to set up exactly right. Also, the stock nginx cores have various limitations and long standing bugs that can make some of this modules' features become disabled, not work properly, or run slower. The same applies to LuaJIT as well. OpenResty includes its own version of LuaJIT which gets specifically optimized and enhanced for the OpenResty environment. Alternatively, ngx_lua can be manually compiled into Nginx: -1. Install LuaJIT 2.0 or 2.1 (recommended) or Lua 5.1 (Lua 5.2 is *not* supported yet). LuaJIT can be downloaded from the [LuaJIT project website](http://luajit.org/download.html) and Lua 5.1, from the [Lua project website](http://www.lua.org/). Some distribution package managers also distribute LuaJIT and/or Lua. +1. LuaJIT can be downloaded from the [latest release of OpenResty's LuaJIT branch version](https://github.com/openresty/luajit2/releases). The official LuaJIT 2.0 and 2.1 releases are also supported, although the performance will be significantly lower in many cases. 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 version of Nginx [HERE](http://nginx.org/) (See [Nginx Compatibility](#nginx-compatibility)) @@ -345,29 +348,6 @@ To enable one or more of these macros, just pass extra C compiler options to the ./configure --with-cc-opt="-DNGX_LUA_USE_ASSERT -DNGX_LUA_ABORT_AT_PANIC" -[Back to TOC](#table-of-contents) - -Installation on Ubuntu 11.10 ----------------------------- - -Note that it is recommended to use LuaJIT 2.0 or LuaJIT 2.1 instead of the standard Lua 5.1 interpreter wherever possible. - -If the standard Lua 5.1 interpreter is required however, run the following command to install it from the Ubuntu repository: - -```bash - - apt-get install -y lua5.1 liblua5.1-0 liblua5.1-0-dev -``` - -Everything should be installed correctly, except for one small tweak. - -Library name `liblua.so` has been changed in liblua5.1 package, it only comes with `liblua5.1.so`, which needs to be symlinked to `/usr/lib` so it could be found during the configuration process. - -```bash - - ln -s /usr/lib/x86_64-linux-gnu/liblua5.1.so /usr/lib/liblua.so -``` - [Back to TOC](#table-of-contents) Community @@ -411,7 +391,7 @@ Lua/LuaJIT bytecode support As from the `v0.5.0rc32` release, all `*_by_lua_file` configure directives (such as [content_by_lua_file](#content_by_lua_file)) support loading Lua 5.1 and LuaJIT 2.0/2.1 raw bytecode files directly. -Please note that the bytecode format used by LuaJIT 2.0/2.1 is not compatible with that used by the standard Lua 5.1 interpreter. So if using LuaJIT 2.0/2.1 with ngx_lua, LuaJIT compatible bytecode files must be generated as shown: +Please note that the bytecode format used by LuaJIT 2.0/2.1 is not compatible with that used by the standard Lua 5.1 interpreter. So if you are using LuaJIT 2.0/2.1 with ngx_lua, LuaJIT compatible bytecode files must be generated as shown: ```bash @@ -431,20 +411,6 @@ Please refer to the official LuaJIT documentation on the `-b` option for more de Also, the bytecode files generated by LuaJIT 2.1 is *not* compatible with LuaJIT 2.0, and vice versa. The support for LuaJIT 2.1 bytecode was first added in ngx_lua v0.9.3. -Similarly, if using the standard Lua 5.1 interpreter with ngx_lua, Lua compatible bytecode files must be generated using the `luac` commandline utility as shown: - -```bash - - luac -o /path/to/output_file.luac /path/to/input_file.lua -``` - -Unlike as with LuaJIT, debug information is included in standard Lua 5.1 bytecode files by default. This can be striped out by specifying the `-s` option as shown: - -```bash - - luac -s -o /path/to/output_file.luac /path/to/input_file.lua -``` - Attempts to load standard Lua 5.1 bytecode files into ngx_lua instances linked to LuaJIT 2.0/2.1 or vice versa, will result in an error message, such as that below, being logged into the Nginx `error.log` file: @@ -642,8 +608,7 @@ This issue is due to limitations in the Nginx event model and only appears to af Lua Coroutine Yielding/Resuming ------------------------------- -* Because Lua's `dofile` and `require` builtins are currently implemented as C functions in both Lua 5.1 and LuaJIT 2.0/2.1, if the Lua file being loaded by `dofile` or `require` invokes [ngx.location.capture*](#ngxlocationcapture), [ngx.exec](#ngxexec), [ngx.exit](#ngxexit), or other API functions requiring yielding in the *top-level* scope of the Lua file, then the Lua error "attempt to yield across C-call boundary" will be raised. To avoid this, put these calls requiring yielding into your own Lua functions in the Lua file instead of the top-level scope of the file. -* As the standard Lua 5.1 interpreter's VM is not fully resumable, the methods [ngx.location.capture](#ngxlocationcapture), [ngx.location.capture_multi](#ngxlocationcapture_multi), [ngx.redirect](#ngxredirect), [ngx.exec](#ngxexec), and [ngx.exit](#ngxexit) cannot be used within the context of a Lua [pcall()](http://www.lua.org/manual/5.1/manual.html#pdf-pcall) or [xpcall()](http://www.lua.org/manual/5.1/manual.html#pdf-xpcall) or even the first line of the `for ... in ...` statement when the standard Lua 5.1 interpreter is used and the `attempt to yield across metamethod/C-call boundary` error will be produced. Please use LuaJIT 2.x, which supports a fully resumable VM, to avoid this. +* Because Lua's `dofile` and `require` builtins are currently implemented as C functions in LuaJIT 2.0/2.1, if the Lua file being loaded by `dofile` or `require` invokes [ngx.location.capture*](#ngxlocationcapture), [ngx.exec](#ngxexec), [ngx.exit](#ngxexit), or other API functions requiring yielding in the *top-level* scope of the Lua file, then the Lua error "attempt to yield across C-call boundary" will be raised. To avoid this, put these calls requiring yielding into your own Lua functions in the Lua file instead of the top-level scope of the file. [Back to TOC](#table-of-contents) @@ -995,7 +960,7 @@ This module is licensed under the BSD license. Copyright (C) 2009-2017, by Xiaozhe Wang (chaoslawful) . -Copyright (C) 2009-2018, by Yichun "agentzh" Zhang (章亦春) , OpenResty Inc. +Copyright (C) 2009-2019, by Yichun "agentzh" Zhang (章亦春) , OpenResty Inc. All rights reserved. @@ -1039,6 +1004,7 @@ See Also Directives ========== +* [lua_load_resty_core](#lua_load_resty_core) * [lua_capture_error_log](#lua_capture_error_log) * [lua_use_default_type](#lua_use_default_type) * [lua_malloc_trim](#lua_malloc_trim) @@ -1104,6 +1070,7 @@ Directives * [lua_check_client_abort](#lua_check_client_abort) * [lua_max_pending_timers](#lua_max_pending_timers) * [lua_max_running_timers](#lua_max_running_timers) +* [lua_sa_restart](#lua_sa_restart) The basic building blocks of scripting Nginx with Lua are directives. Directives are used to specify when the user Lua code is run and @@ -1113,6 +1080,38 @@ how the result will be used. Below is a diagram showing the order in which direc [Back to TOC](#table-of-contents) +lua_load_resty_core +------------------- + +**syntax:** *lua_load_resty_core on|off* + +**default:** *lua_load_resty_core on* + +**context:** *http* + +Controls whether the `resty.core` module (from +[lua-resty-core](https://github.com/openresty/lua-resty-core)) should be loaded +or not. When enabled, this directive is equivalent to executing the following +when the Lua VM is created: + +```lua + + require "resty.core" +``` + +Note that usage of the `resty.core` module is recommended, as its +FFI implementation is both faster, safer, and more complete than the Lua C API +of the ngx_lua module. + +It must also be noted that the Lua C API of the ngx_lua module will eventually +be removed, and usage of the FFI-based API (i.e. the `resty.core` +module) will become mandatory. This directive only aims at providing a +temporary backwards-compatibility mode in case of edge-cases. + +This directive was first introduced in the `v0.10.15` release. + +[Back to TOC](#directives) + lua_capture_error_log --------------------- **syntax:** *lua_capture_error_log size* @@ -2602,14 +2601,14 @@ SSL session resumption can then get immediately initiated and bypass the full SS Please note that TLS session tickets are very different and it is the clients' responsibility to cache the SSL session state when session tickets are used. SSL session resumptions based on TLS session tickets would happen automatically without going through this hook (nor the -[ssl_session_store_by_lua_block](#ssl_session_store_by_lua) hook). This hook is mainly +[ssl_session_store_by_lua*](#ssl_session_store_by_lua_block) hook). This hook is mainly for older or less capable SSL clients that can only do SSL sessions by session IDs. When [ssl_certificate_by_lua*](#ssl_certificate_by_lua_block) is specified at the same time, this hook usually runs before [ssl_certificate_by_lua*](#ssl_certificate_by_lua_block). When the SSL session is found and successfully loaded for the current SSL connection, SSL session resumption will happen and thus bypass the [ssl_certificate_by_lua*](#ssl_certificate_by_lua_block) -hook completely. In this case, NGINX also bypasses the [ssl_session_store_by_lua_block](#ssl_session_store_by_lua) +hook completely. In this case, NGINX also bypasses the [ssl_session_store_by_lua*](#ssl_session_store_by_lua_block) hook, for obvious reasons. To easily test this hook locally with a modern web browser, you can temporarily put the following line @@ -3108,6 +3107,23 @@ This directive was first introduced in the `v0.8.0` release. [Back to TOC](#directives) +lua_sa_restart +-------------- + +**syntax:** *lua_sa_restart on|off* + +**default:** *lua_sa_restart on* + +**context:** *http* + +When enabled, this module will set the `SA_RESTART` flag on nginx workers signal dispositions. + +This allows Lua I/O primitives to not be interrupted by nginx's handling of various signals. + +This directive was first introduced in the `v0.10.14` release. + +[Back to TOC](#directives) + Nginx API for Lua ================= @@ -3221,6 +3237,7 @@ Nginx API for Lua * [tcpsock:sslhandshake](#tcpsocksslhandshake) * [tcpsock:send](#tcpsocksend) * [tcpsock:receive](#tcpsockreceive) +* [tcpsock:receiveany](#tcpsockreceiveany) * [tcpsock:receiveuntil](#tcpsockreceiveuntil) * [tcpsock:close](#tcpsockclose) * [tcpsock:settimeout](#tcpsocksettimeout) @@ -4302,7 +4319,7 @@ ngx.req.get_method ------------------ **syntax:** *method_name = ngx.req.get_method()* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, balancer_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, balancer_by_lua*, log_by_lua** Retrieves the current request's request method name. Strings like `"GET"` and `"POST"` are returned instead of numerical [method constants](#http-method-constants). @@ -4887,7 +4904,7 @@ This function returns `nil` if 1. the request body has been read into disk temporary files, 1. or the request body has zero size. -If the request body has not been read yet, call [ngx.req.read_body](#ngxreqread_body) first (or turned on [lua_need_request_body](#lua_need_request_body) to force this module to read the request body. This is not recommended however). +If the request body has not been read yet, call [ngx.req.read_body](#ngxreqread_body) first (or turn on [lua_need_request_body](#lua_need_request_body) to force this module to read the request body. This is not recommended however). If the request body has been read into disk files, try calling the [ngx.req.get_body_file](#ngxreqget_body_file) function instead. @@ -4911,7 +4928,7 @@ Retrieves the file name for the in-file request body data. Returns `nil` if the The returned file is read only and is usually cleaned up by Nginx's memory pool. It should not be manually modified, renamed, or removed in Lua code. -If the request body has not been read yet, call [ngx.req.read_body](#ngxreqread_body) first (or turned on [lua_need_request_body](#lua_need_request_body) to force this module to read the request body. This is not recommended however). +If the request body has not been read yet, call [ngx.req.read_body](#ngxreqread_body) first (or turn on [lua_need_request_body](#lua_need_request_body) to force this module to read the request body. This is not recommended however). If the request body has been read into memory, try calling the [ngx.req.get_body_data](#ngxreqget_body_data) function instead. @@ -4931,7 +4948,9 @@ ngx.req.set_body_data Set the current request's request body using the in-memory data specified by the `data` argument. -If the current request's request body has not been read, then it will be properly discarded. When the current request's request body has been read into memory or buffered into a disk file, then the old request body's memory will be freed or the disk file will be cleaned up immediately, respectively. +If the request body has not been read yet, call [ngx.req.read_body](#ngxreqread_body) first (or turn on [lua_need_request_body](#lua_need_request_body) to force this module to read the request body. This is not recommended however). Additionally, the request body must not have been previously discarded by [ngx.req.discard_body](#ngxreqdiscard_body). + +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. This function was first introduced in the `v0.3.1rc18` release. @@ -4947,11 +4966,13 @@ ngx.req.set_body_file Set the current request's request body using the in-file data specified by the `file_name` argument. +If the request body has not been read yet, call [ngx.req.read_body](#ngxreqread_body) first (or turn on [lua_need_request_body](#lua_need_request_body) to force this module to read the request body. This is not recommended however). Additionally, the request body must not have been previously discarded by [ngx.req.discard_body](#ngxreqdiscard_body). + If the optional `auto_clean` argument is given a `true` value, then this file will be removed at request completion or the next time this function or [ngx.req.set_body_data](#ngxreqset_body_data) are called in the same request. The `auto_clean` is default to `false`. Please ensure that the file specified by the `file_name` argument exists and is readable by an Nginx worker process by setting its permission properly to avoid Lua exception errors. -If the current request's request body has not been read, then it will be properly discarded. When the current request's request body has been read into memory or buffered into a disk file, then the old request body's memory will be freed or the disk file will be cleaned up immediately, respectively. +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. This function was first introduced in the `v0.3.1rc18` release. @@ -6717,7 +6738,7 @@ ngx.shared.DICT.flush_expired Flushes out the expired items in the dictionary, up to the maximal number specified by the optional `max_count` argument. When the `max_count` argument is given `0` or not given at all, then it means unlimited. Returns the number of items that have actually been flushed. -Unlike the [flush_all](#ngxshareddictflush_all) method, this method actually free up the memory used by the expired items. +Unlike the [flush_all](#ngxshareddictflush_all) method, this method actually frees up the memory used by the expired items. This feature was first introduced in the `v0.6.3` release. @@ -7002,6 +7023,7 @@ Creates and returns a TCP or stream-oriented unix domain socket object (also kno * [settimeout](#tcpsocksettimeout) * [settimeouts](#tcpsocksettimeouts) * [setoption](#tcpsocksetoption) +* [receiveany](#tcpsockreceiveany) * [receiveuntil](#tcpsockreceiveuntil) * [setkeepalive](#tcpsocksetkeepalive) * [getreusedtimes](#tcpsockgetreusedtimes) @@ -7106,6 +7128,43 @@ An optional Lua table can be specified as the last argument to this method to sp * `pool` specify a custom name for the connection pool being used. If omitted, then the connection pool name will be generated from the string template `":"` or `""`. +* `pool_size` + specify the size of the connection pool. If omitted and no + `backlog` option was provided, no pool will be created. If omitted + but `backlog` was provided, the pool will be created with a default + size equal to the value of the [lua_socket_pool_size](#lua_socket_pool_size) + directive. + The connection pool holds up to `pool_size` alive connections + ready to be reused by subsequent calls to [connect](#tcpsockconnect), but + note that there is no upper limit to the total number of opened connections + outside of the pool. If you need to restrict the total number of opened + connections, specify the `backlog` option. + When the connection pool would exceed its size limit, the least recently used + (kept-alive) connection already in the pool will be closed to make room for + the current connection. + Note that the cosocket connection pool is per Nginx worker process rather + than per Nginx server instance, so the size limit specified here also applies + to every single Nginx worker process. Also note that the size of the connection + pool cannot be changed once it has been created. + This option was first introduced in the `v0.10.14` release. + +* `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). + 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 operation will abort once they have been queued for more + than `connect_timeout`, controlled by + [settimeouts](#tcpsocksettimeouts), and will return `nil` plus + the error string `"timeout"`. + This option was first introduced in the `v0.10.14` release. + The support for the options table argument was first introduced in the `v0.5.7` release. This method was first introduced in the `v0.5.0rc1` release. @@ -7231,6 +7290,40 @@ This feature was first introduced in the `v0.5.0rc1` release. [Back to TOC](#nginx-api-for-lua) +tcpsock:receiveany +------------------ +**syntax:** *data, err = tcpsock:receiveany(max)* + +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua** + +Returns any data received by the connected socket, at most `max` bytes. + +This method is a synchronous operation just like the [send](#tcpsocksend) method and is 100% nonblocking. + +In case of success, it returns the data received; in case of error, it returns `nil` with a string describing the error. + +If the received data is more than this size, this method will return with exactly this size of data. +The remaining data in the underlying receive buffer could be returned in the next reading operation. + +Timeout for the reading operation is controlled by the [lua_socket_read_timeout](#lua_socket_read_timeout) config directive and the [settimeouts](#tcpsocksettimeouts) method. And the latter takes priority. For example: + +```lua + + sock:settimeouts(1000, 1000, 1000) -- one second timeout for connect/read/write + local data, err = sock:receiveany(10 * 1024 * 1024) -- read any data, at most 10K + if not data then + ngx.say("failed to read any data: ", err) + return + end + ngx.say("successfully read: ", data) +``` + +This method doesn't automatically close the current connection when the read timeout error occurs. For other connection errors, this method always automatically closes the connection. + +This feature was first introduced in the `v0.10.14` release. + +[Back to TOC](#nginx-api-for-lua) + tcpsock:receiveuntil -------------------- **syntax:** *iterator = tcpsock:receiveuntil(pattern, options?)* @@ -7403,13 +7496,31 @@ Puts the current socket's connection immediately into the cosocket built-in conn The first optional argument, `timeout`, can be used to specify the maximal idle timeout (in milliseconds) for the current connection. If omitted, the default setting in the [lua_socket_keepalive_timeout](#lua_socket_keepalive_timeout) config directive will be used. If the `0` value is given, then the timeout interval is unlimited. -The second optional argument, `size`, can be used to specify the maximal number of connections allowed in the connection pool for the current server (i.e., the current host-port pair or the unix domain socket file path). Note that the size of the connection pool cannot be changed once the pool is created. When this argument is omitted, the default setting in the [lua_socket_pool_size](#lua_socket_pool_size) config directive will be used. - -When the connection pool exceeds the available size limit, the least recently used (idle) connection already in the pool will be closed to make room for the current connection. - -Note that the cosocket connection pool is per Nginx worker process rather than per Nginx server instance, so the size limit specified here also applies to every single Nginx worker process. - -Idle connections in the pool will be monitored for any exceptional events like connection abortion or unexpected incoming data on the line, in which cases the connection in question will be closed and removed from the pool. +The second optional argument `size` is considered deprecated since +the `v0.10.14` release of this module, in favor of the +`pool_size` option of the [connect](#tcpsockconnect) method. +Since the `v0.10.14` release, this option will only take effect if +the call to [connect](#tcpsockconnect) did not already create a connection +pool. +When this option takes effect (no connection pool was previously created by +[connect](#tcpsockconnect)), it will specify the size of the connection pool, +and create it. +If omitted (and no pool was previously created), the default size is the value +of the [lua_socket_pool_size](#lua_socket_pool_size) directive. +The connection pool holds up to `size` alive connections ready to be +reused by subsequent calls to [connect](#tcpsockconnect), but note that there +is no upper limit to the total number of opened connections outside of the +pool. +When the connection pool would exceed its size limit, the least recently used +(kept-alive) connection already in the pool will be closed to make room for +the current connection. +Note that the cosocket connection pool is per Nginx worker process rather +than per Nginx server instance, so the size limit specified here also applies +to every single Nginx worker process. Also note that the size of the connection +pool cannot be changed once it has been created. +If you need to restrict the total number of opened connections, specify both +the `pool_size` and `backlog` option in the call to +[connect](#tcpsockconnect). In case of success, this method returns `1`; otherwise, it returns `nil` and a string describing the error. @@ -8181,7 +8292,7 @@ This Lua module does not ship with this ngx_lua module itself rather it is shipp the [lua-resty-core](https://github.com/openresty/lua-resty-core) library. -Please refer to the [documentation](https://github.com/openresty/lua-resty-core/blob/ocsp-cert-by-lua-2/lib/ngx/ocsp.md) +Please refer to the [documentation](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ocsp.md) for this `ngx.ocsp` Lua module for more details. This feature requires at least ngx_lua `v0.10.0`. diff --git a/debian/modules/http-lua/config b/debian/modules/http-lua/config index 044deb9..e1d5e35 100644 --- a/debian/modules/http-lua/config +++ b/debian/modules/http-lua/config @@ -361,6 +361,8 @@ HTTP_LUA_SRCS=" \ $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_log_ringbuf.c \ + $ngx_addon_dir/src/ngx_http_lua_input_filters.c \ + $ngx_addon_dir/src/ngx_http_lua_pipe.c \ " HTTP_LUA_DEPS=" \ @@ -422,6 +424,8 @@ HTTP_LUA_DEPS=" \ $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_log_ringbuf.h \ + $ngx_addon_dir/src/ngx_http_lua_input_filters.h \ + $ngx_addon_dir/src/ngx_http_lua_pipe.h \ " CFLAGS="$CFLAGS -DNDK_SET_VAR" @@ -474,6 +478,17 @@ ngx_feature_test='setsockopt(1, SOL_SOCKET, SO_PASSCRED, NULL, 0);' . auto/feature +ngx_feature="SA_RESTART" +ngx_feature_libs= +ngx_feature_name="NGX_HTTP_LUA_HAVE_SA_RESTART" +ngx_feature_run=no +ngx_feature_incs="#include " +ngx_feature_path= +ngx_feature_test='struct sigaction act; + act.sa_flags |= SA_RESTART;' + +. auto/feature + ngx_feature="__attribute__(constructor)" ngx_feature_libs= ngx_feature_name="NGX_HTTP_LUA_HAVE_CONSTRUCTOR" @@ -512,6 +527,36 @@ CC_TEST_FLAGS="$SAVED_CC_TEST_FLAGS" # ---------------------------------------- +ngx_feature="pipe2" +ngx_feature_libs= +ngx_feature_name="NGX_HTTP_LUA_HAVE_PIPE2" +ngx_feature_run=no +ngx_feature_incs="#include " +ngx_feature_test="int fd[2]; pipe2(fd, O_CLOEXEC|O_NONBLOCK);" +SAVED_CC_TEST_FLAGS="$CC_TEST_FLAGS" +CC_TEST_FLAGS="-Werror -Wall $CC_TEST_FLAGS" + +. auto/feature + +CC_TEST_FLAGS="$SAVED_CC_TEST_FLAGS" + +# ---------------------------------------- + +ngx_feature="signalfd" +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);" +SAVED_CC_TEST_FLAGS="$CC_TEST_FLAGS" +CC_TEST_FLAGS="-Werror -Wall $CC_TEST_FLAGS" + +. auto/feature + +CC_TEST_FLAGS="$SAVED_CC_TEST_FLAGS" + +# ---------------------------------------- + if test -n "$ngx_module_link"; then ngx_module_type=HTTP_AUX_FILTER ngx_module_name=$ngx_addon_name diff --git a/debian/modules/http-lua/doc/HttpLuaModule.wiki b/debian/modules/http-lua/doc/HttpLuaModule.wiki index e3c61e2..ff9b269 100644 --- a/debian/modules/http-lua/doc/HttpLuaModule.wiki +++ b/debian/modules/http-lua/doc/HttpLuaModule.wiki @@ -2,6 +2,8 @@ ngx_http_lua_module - Embed the power of Lua into Nginx HTTP Servers. +This module is a core component of OpenResty. If you are using this module, then you are essentially using OpenResty :) + ''This module is not distributed with the Nginx source.'' See [[#Installation|the installation instructions]]. = Status = @@ -10,7 +12,7 @@ Production ready. = Version = -This document describes ngx_lua [https://github.com/openresty/lua-nginx-module/tags v0.10.13] released on 22 April 2018. +This document describes ngx_lua [https://github.com/openresty/lua-nginx-module/tags v0.10.15] released on March 14th, 2019. = Synopsis = @@ -130,7 +132,9 @@ This document describes ngx_lua [https://github.com/openresty/lua-nginx-module/t = Description = -This module embeds Lua, via the standard Lua 5.1 interpreter or [http://luajit.org/luajit.html LuaJIT 2.0/2.1], into Nginx and by leveraging Nginx's subrequests, allows the integration of the powerful Lua threads (Lua coroutines) into the Nginx event model. +This module is a core component of OpenResty. If you are using this module, then you are essentially using OpenResty :) + +This module embeds Lua, via [http://luajit.org/luajit.html LuaJIT 2.0/2.1], into Nginx and by leveraging Nginx's subrequests, allows the integration of the powerful Lua threads (Lua coroutines) into the Nginx event model. Unlike [https://httpd.apache.org/docs/trunk/mod/mod_lua.html Apache's mod_lua] and [http://redmine.lighttpd.net/wiki/1/Docs:ModMagnet Lighttpd's mod_magnet], Lua code executed using this module can be ''100% non-blocking'' on network traffic as long as the [[#Nginx API for Lua|Nginx API for Lua]] provided by this module is used to handle requests to upstream services such as MySQL, PostgreSQL, Memcached, Redis, or upstream HTTP web services. @@ -199,11 +203,11 @@ Nginx cores older than 1.6.0 (exclusive) are *not* supported. = Installation = -It is *highly* recommended to use [http://openresty.org OpenResty releases] which integrate Nginx, ngx_lua, LuaJIT 2.1, as well as other powerful companion Nginx modules and Lua libraries. It is discouraged to build this module with nginx yourself since it is tricky to set up exactly right. Also, the stock nginx cores have various limitations and long standing bugs that can make some of this modules' features become disabled, not work properly, or run slower. The same applies to LuaJIT as well. OpenResty includes its own version of LuaJIT which gets specifically optimized and enhanced for the OpenResty environment. +It is *highly* recommended to use [http://openresty.org OpenResty releases] which integrate Nginx, ngx_lua, OpenResty's LuaJIT 2.1 branch version, as well as other powerful companion Nginx modules and Lua libraries. It is discouraged to build this module with nginx yourself since it is tricky to set up exactly right. Also, the stock nginx cores have various limitations and long standing bugs that can make some of this modules' features become disabled, not work properly, or run slower. The same applies to LuaJIT as well. OpenResty includes its own version of LuaJIT which gets specifically optimized and enhanced for the OpenResty environment. Alternatively, ngx_lua can be manually compiled into Nginx: -# Install LuaJIT 2.0 or 2.1 (recommended) or Lua 5.1 (Lua 5.2 is ''not'' supported yet). LuaJIT can be downloaded from the [http://luajit.org/download.html LuaJIT project website] and Lua 5.1, from the [http://www.lua.org/ Lua project website]. Some distribution package managers also distribute LuaJIT and/or Lua. +# LuaJIT can be downloaded from the [https://github.com/openresty/luajit2/releases latest release of OpenResty's LuaJIT branch version]. The official LuaJIT 2.0 and 2.1 releases are also supported, although the performance will be significantly lower in many cases. # 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 version of Nginx [http://nginx.org/ HERE] (See [[#Nginx Compatibility|Nginx Compatibility]]) @@ -271,24 +275,6 @@ To enable one or more of these macros, just pass extra C compiler options to the ./configure --with-cc-opt="-DNGX_LUA_USE_ASSERT -DNGX_LUA_ABORT_AT_PANIC" -== Installation on Ubuntu 11.10 == - -Note that it is recommended to use LuaJIT 2.0 or LuaJIT 2.1 instead of the standard Lua 5.1 interpreter wherever possible. - -If the standard Lua 5.1 interpreter is required however, run the following command to install it from the Ubuntu repository: - - -apt-get install -y lua5.1 liblua5.1-0 liblua5.1-0-dev - - -Everything should be installed correctly, except for one small tweak. - -Library name liblua.so has been changed in liblua5.1 package, it only comes with liblua5.1.so, which needs to be symlinked to /usr/lib so it could be found during the configuration process. - - -ln -s /usr/lib/x86_64-linux-gnu/liblua5.1.so /usr/lib/liblua.so - - = Community = == English Mailing List == @@ -314,7 +300,7 @@ Please submit bug reports, wishlists, or patches by As from the v0.5.0rc32 release, all *_by_lua_file configure directives (such as [[#content_by_lua_file|content_by_lua_file]]) support loading Lua 5.1 and LuaJIT 2.0/2.1 raw bytecode files directly. -Please note that the bytecode format used by LuaJIT 2.0/2.1 is not compatible with that used by the standard Lua 5.1 interpreter. So if using LuaJIT 2.0/2.1 with ngx_lua, LuaJIT compatible bytecode files must be generated as shown: +Please note that the bytecode format used by LuaJIT 2.0/2.1 is not compatible with that used by the standard Lua 5.1 interpreter. So if you are using LuaJIT 2.0/2.1 with ngx_lua, LuaJIT compatible bytecode files must be generated as shown: /path/to/luajit/bin/luajit -b /path/to/input_file.lua /path/to/output_file.ljbc @@ -332,18 +318,6 @@ http://luajit.org/running.html#opt_b Also, the bytecode files generated by LuaJIT 2.1 is ''not'' compatible with LuaJIT 2.0, and vice versa. The support for LuaJIT 2.1 bytecode was first added in ngx_lua v0.9.3. -Similarly, if using the standard Lua 5.1 interpreter with ngx_lua, Lua compatible bytecode files must be generated using the luac commandline utility as shown: - - - luac -o /path/to/output_file.luac /path/to/input_file.lua - - -Unlike as with LuaJIT, debug information is included in standard Lua 5.1 bytecode files by default. This can be striped out by specifying the -s option as shown: - - - luac -s -o /path/to/output_file.luac /path/to/input_file.lua - - Attempts to load standard Lua 5.1 bytecode files into ngx_lua instances linked to LuaJIT 2.0/2.1 or vice versa, will result in an error message, such as that below, being logged into the Nginx error.log file: @@ -510,8 +484,7 @@ However, later attempts to manipulate the cosocket object will fail and return t This issue is due to limitations in the Nginx event model and only appears to affect Mac OS X. == Lua Coroutine Yielding/Resuming == -* Because Lua's dofile and require builtins are currently implemented as C functions in both Lua 5.1 and LuaJIT 2.0/2.1, if the Lua file being loaded by dofile or require invokes [[#ngx.location.capture|ngx.location.capture*]], [[#ngx.exec|ngx.exec]], [[#ngx.exit|ngx.exit]], or other API functions requiring yielding in the *top-level* scope of the Lua file, then the Lua error "attempt to yield across C-call boundary" will be raised. To avoid this, put these calls requiring yielding into your own Lua functions in the Lua file instead of the top-level scope of the file. -* As the standard Lua 5.1 interpreter's VM is not fully resumable, the methods [[#ngx.location.capture|ngx.location.capture]], [[#ngx.location.capture_multi|ngx.location.capture_multi]], [[#ngx.redirect|ngx.redirect]], [[#ngx.exec|ngx.exec]], and [[#ngx.exit|ngx.exit]] cannot be used within the context of a Lua [http://www.lua.org/manual/5.1/manual.html#pdf-pcall pcall()] or [http://www.lua.org/manual/5.1/manual.html#pdf-xpcall xpcall()] or even the first line of the for ... in ... statement when the standard Lua 5.1 interpreter is used and the attempt to yield across metamethod/C-call boundary error will be produced. Please use LuaJIT 2.x, which supports a fully resumable VM, to avoid this. +* Because Lua's dofile and require builtins are currently implemented as C functions in LuaJIT 2.0/2.1, if the Lua file being loaded by dofile or require invokes [[#ngx.location.capture|ngx.location.capture*]], [[#ngx.exec|ngx.exec]], [[#ngx.exit|ngx.exit]], or other API functions requiring yielding in the *top-level* scope of the Lua file, then the Lua error "attempt to yield across C-call boundary" will be raised. To avoid this, put these calls requiring yielding into your own Lua functions in the Lua file instead of the top-level scope of the file. == Lua Variable Scope == Care must be taken when importing modules and this form should be used: @@ -817,7 +790,7 @@ This module is licensed under the BSD license. Copyright (C) 2009-2017, by Xiaozhe Wang (chaoslawful) . -Copyright (C) 2009-2018, by Yichun "agentzh" Zhang (章亦春) , OpenResty Inc. +Copyright (C) 2009-2019, by Yichun "agentzh" Zhang (章亦春) , OpenResty Inc. All rights reserved. @@ -862,6 +835,34 @@ how the result will be used. Below is a diagram showing the order in which direc ![Lua Nginx Modules Directives](https://cloud.githubusercontent.com/assets/2137369/15272097/77d1c09e-1a37-11e6-97ef-d9767035fc3e.png) +== lua_load_resty_core == + +'''syntax:''' ''lua_load_resty_core on|off'' + +'''default:''' ''lua_load_resty_core on'' + +'''context:''' ''http'' + +Controls whether the resty.core module (from +[https://github.com/openresty/lua-resty-core lua-resty-core]) should be loaded +or not. When enabled, this directive is equivalent to executing the following +when the Lua VM is created: + + + require "resty.core" + + +Note that usage of the resty.core module is recommended, as its +FFI implementation is both faster, safer, and more complete than the Lua C API +of the ngx_lua module. + +It must also be noted that the Lua C API of the ngx_lua module will eventually +be removed, and usage of the FFI-based API (i.e. the resty.core +module) will become mandatory. This directive only aims at providing a +temporary backwards-compatibility mode in case of edge-cases. + +This directive was first introduced in the v0.10.15 release. + == lua_capture_error_log == '''syntax:''' ''lua_capture_error_log size'' @@ -2196,14 +2197,14 @@ SSL session resumption can then get immediately initiated and bypass the full SS Please note that TLS session tickets are very different and it is the clients' responsibility to cache the SSL session state when session tickets are used. SSL session resumptions based on TLS session tickets would happen automatically without going through this hook (nor the -[[#ssl_session_store_by_lua*|ssl_session_store_by_lua_block]] hook). This hook is mainly +[[#ssl_session_store_by_lua_block|ssl_session_store_by_lua*]] hook). This hook is mainly for older or less capable SSL clients that can only do SSL sessions by session IDs. When [[#ssl_certificate_by_lua_block|ssl_certificate_by_lua*]] is specified at the same time, this hook usually runs before [[#ssl_certificate_by_lua_block|ssl_certificate_by_lua*]]. When the SSL session is found and successfully loaded for the current SSL connection, SSL session resumption will happen and thus bypass the [[#ssl_certificate_by_lua_block|ssl_certificate_by_lua*]] -hook completely. In this case, NGINX also bypasses the [[#ssl_session_store_by_lua*|ssl_session_store_by_lua_block]] +hook completely. In this case, NGINX also bypasses the [[#ssl_session_store_by_lua_block|ssl_session_store_by_lua*]] hook, for obvious reasons. To easily test this hook locally with a modern web browser, you can temporarily put the following line @@ -2626,6 +2627,20 @@ When exceeding this limit, Nginx will stop running the callbacks of newly expire This directive was first introduced in the v0.8.0 release. +== lua_sa_restart == + +'''syntax:''' ''lua_sa_restart on|off'' + +'''default:''' ''lua_sa_restart on'' + +'''context:''' ''http'' + +When enabled, this module will set the `SA_RESTART` flag on nginx workers signal dispositions. + +This allows Lua I/O primitives to not be interrupted by nginx's handling of various signals. + +This directive was first introduced in the v0.10.14 release. + = Nginx API for Lua = @@ -3563,7 +3578,7 @@ This method does not work in HTTP/2 requests yet. == ngx.req.get_method == '''syntax:''' ''method_name = ngx.req.get_method()'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, balancer_by_lua*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, balancer_by_lua*, log_by_lua*'' Retrieves the current request's request method name. Strings like "GET" and "POST" are returned instead of numerical [[#HTTP method constants|method constants]]. @@ -4071,7 +4086,7 @@ This function returns nil if # the request body has been read into disk temporary files, # or the request body has zero size. -If the request body has not been read yet, call [[#ngx.req.read_body|ngx.req.read_body]] first (or turned on [[#lua_need_request_body|lua_need_request_body]] to force this module to read the request body. This is not recommended however). +If the request body has not been read yet, call [[#ngx.req.read_body|ngx.req.read_body]] first (or turn on [[#lua_need_request_body|lua_need_request_body]] to force this module to read the request body. This is not recommended however). If the request body has been read into disk files, try calling the [[#ngx.req.get_body_file|ngx.req.get_body_file]] function instead. @@ -4092,7 +4107,7 @@ Retrieves the file name for the in-file request body data. Returns nildata argument. -If the current request's request body has not been read, then it will be properly discarded. When the current request's request body has been read into memory or buffered into a disk file, then the old request body's memory will be freed or the disk file will be cleaned up immediately, respectively. +If the request body has not been read yet, call [[#ngx.req.read_body|ngx.req.read_body]] first (or turn on [[#lua_need_request_body|lua_need_request_body]] to force this module to read the request body. This is not recommended however). Additionally, the request body must not have been previously discarded by [[#ngx.req.discard_body|ngx.req.discard_body]]. + +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. This function was first introduced in the v0.3.1rc18 release. @@ -4122,11 +4139,13 @@ See also [[#ngx.req.set_body_file|ngx.req.set_body_file]]. Set the current request's request body using the in-file data specified by the file_name argument. +If the request body has not been read yet, call [[#ngx.req.read_body|ngx.req.read_body]] first (or turn on [[#lua_need_request_body|lua_need_request_body]] to force this module to read the request body. This is not recommended however). Additionally, the request body must not have been previously discarded by [[#ngx.req.discard_body|ngx.req.discard_body]]. + If the optional auto_clean argument is given a true value, then this file will be removed at request completion or the next time this function or [[#ngx.req.set_body_data|ngx.req.set_body_data]] are called in the same request. The auto_clean is default to false. Please ensure that the file specified by the file_name argument exists and is readable by an Nginx worker process by setting its permission properly to avoid Lua exception errors. -If the current request's request body has not been read, then it will be properly discarded. When the current request's request body has been read into memory or buffered into a disk file, then the old request body's memory will be freed or the disk file will be cleaned up immediately, respectively. +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. This function was first introduced in the v0.3.1rc18 release. @@ -5648,7 +5667,7 @@ See also [[#ngx.shared.DICT.flush_expired|ngx.shared.DICT.flush_expired]] and [[ Flushes out the expired items in the dictionary, up to the maximal number specified by the optional max_count argument. When the max_count argument is given 0 or not given at all, then it means unlimited. Returns the number of items that have actually been flushed. -Unlike the [[#ngx.shared.DICT.flush_all|flush_all]] method, this method actually free up the memory used by the expired items. +Unlike the [[#ngx.shared.DICT.flush_all|flush_all]] method, this method actually frees up the memory used by the expired items. This feature was first introduced in the v0.6.3 release. @@ -5894,6 +5913,7 @@ Creates and returns a TCP or stream-oriented unix domain socket object (also kno * [[#tcpsock:settimeout|settimeout]] * [[#tcpsock:settimeouts|settimeouts]] * [[#tcpsock:setoption|setoption]] +* [[#tcpsock:receiveany|receiveany]] * [[#tcpsock:receiveuntil|receiveuntil]] * [[#tcpsock:setkeepalive|setkeepalive]] * [[#tcpsock:getreusedtimes|getreusedtimes]] @@ -5991,6 +6011,43 @@ An optional Lua table can be specified as the last argument to this method to sp * pool : specify a custom name for the connection pool being used. If omitted, then the connection pool name will be generated from the string template ":" or "". +* pool_size +: specify the size of the connection pool. If omitted and no +: backlog option was provided, no pool will be created. If omitted +: but backlog was provided, the pool will be created with a default +: size equal to the value of the [[#lua_socket_pool_size|lua_socket_pool_size]] +: directive. +: The connection pool holds up to pool_size alive connections +: ready to be reused by subsequent calls to [[#tcpsock:connect|connect]], but +: note that there is no upper limit to the total number of opened connections +: outside of the pool. If you need to restrict the total number of opened +: connections, specify the backlog option. +: When the connection pool would exceed its size limit, the least recently used +: (kept-alive) connection already in the pool will be closed to make room for +: the current connection. +: Note that the cosocket connection pool is per Nginx worker process rather +: than per Nginx server instance, so the size limit specified here also applies +: to every single Nginx worker process. Also note that the size of the connection +: pool cannot be changed once it has been created. +: This option was first introduced in the v0.10.14 release. + +* 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). +: 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 operation will abort once they have been queued for more +: than connect_timeout, controlled by +: [[#tcpsock:settimeouts|settimeouts]], and will return nil plus +: the error string "timeout". +: This option was first introduced in the v0.10.14 release. + The support for the options table argument was first introduced in the v0.5.7 release. This method was first introduced in the v0.5.0rc1 release. @@ -6103,6 +6160,36 @@ Since the v0.8.8 release, this method no longer automatically close This feature was first introduced in the v0.5.0rc1 release. +== tcpsock:receiveany == +'''syntax:''' ''data, err = tcpsock:receiveany(max)'' + +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*'' + +Returns any data received by the connected socket, at most max bytes. + +This method is a synchronous operation just like the [[#tcpsock:send|send]] method and is 100% nonblocking. + +In case of success, it returns the data received; in case of error, it returns nil with a string describing the error. + +If the received data is more than this size, this method will return with exactly this size of data. +The remaining data in the underlying receive buffer could be returned in the next reading operation. + +Timeout for the reading operation is controlled by the [[#lua_socket_read_timeout|lua_socket_read_timeout]] config directive and the [[#tcpsock:settimeouts|settimeouts]] method. And the latter takes priority. For example: + + + sock:settimeouts(1000, 1000, 1000) -- one second timeout for connect/read/write + local data, err = sock:receiveany(10 * 1024 * 1024) -- read any data, at most 10K + if not data then + ngx.say("failed to read any data: ", err) + return + end + ngx.say("successfully read: ", data) + + +This method doesn't automatically close the current connection when the read timeout error occurs. For other connection errors, this method always automatically closes the connection. + +This feature was first introduced in the v0.10.14 release. + == tcpsock:receiveuntil == '''syntax:''' ''iterator = tcpsock:receiveuntil(pattern, options?)'' @@ -6255,13 +6342,31 @@ Puts the current socket's connection immediately into the cosocket built-in conn The first optional argument, timeout, can be used to specify the maximal idle timeout (in milliseconds) for the current connection. If omitted, the default setting in the [[#lua_socket_keepalive_timeout|lua_socket_keepalive_timeout]] config directive will be used. If the 0 value is given, then the timeout interval is unlimited. -The second optional argument, size, can be used to specify the maximal number of connections allowed in the connection pool for the current server (i.e., the current host-port pair or the unix domain socket file path). Note that the size of the connection pool cannot be changed once the pool is created. When this argument is omitted, the default setting in the [[#lua_socket_pool_size|lua_socket_pool_size]] config directive will be used. - -When the connection pool exceeds the available size limit, the least recently used (idle) connection already in the pool will be closed to make room for the current connection. - -Note that the cosocket connection pool is per Nginx worker process rather than per Nginx server instance, so the size limit specified here also applies to every single Nginx worker process. - -Idle connections in the pool will be monitored for any exceptional events like connection abortion or unexpected incoming data on the line, in which cases the connection in question will be closed and removed from the pool. +The second optional argument size is considered deprecated since +the v0.10.14 release of this module, in favor of the +pool_size option of the [[#tcpsock:connect|connect]] method. +Since the v0.10.14 release, this option will only take effect if +the call to [[#tcpsock:connect|connect]] did not already create a connection +pool. +When this option takes effect (no connection pool was previously created by +[[#tcpsock:connect|connect]]), it will specify the size of the connection pool, +and create it. +If omitted (and no pool was previously created), the default size is the value +of the [[#lua_socket_pool_size|lua_socket_pool_size]] directive. +The connection pool holds up to size alive connections ready to be +reused by subsequent calls to [[#tcpsock:connect|connect]], but note that there +is no upper limit to the total number of opened connections outside of the +pool. +When the connection pool would exceed its size limit, the least recently used +(kept-alive) connection already in the pool will be closed to make room for +the current connection. +Note that the cosocket connection pool is per Nginx worker process rather +than per Nginx server instance, so the size limit specified here also applies +to every single Nginx worker process. Also note that the size of the connection +pool cannot be changed once it has been created. +If you need to restrict the total number of opened connections, specify both +the pool_size and backlog option in the call to +[[#tcpsock:connect|connect]]. In case of success, this method returns 1; otherwise, it returns nil and a string describing the error. @@ -6950,7 +7055,7 @@ This Lua module does not ship with this ngx_lua module itself rather it is shipp the [https://github.com/openresty/lua-resty-core lua-resty-core] library. -Please refer to the [https://github.com/openresty/lua-resty-core/blob/ocsp-cert-by-lua-2/lib/ngx/ocsp.md documentation] +Please refer to the [https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ocsp.md documentation] for this ngx.ocsp Lua module for more details. This feature requires at least ngx_lua v0.10.0. diff --git a/debian/modules/http-lua/src/api/ngx_http_lua_api.h b/debian/modules/http-lua/src/api/ngx_http_lua_api.h index c7c0e6b..129eb99 100644 --- a/debian/modules/http-lua/src/api/ngx_http_lua_api.h +++ b/debian/modules/http-lua/src/api/ngx_http_lua_api.h @@ -19,7 +19,7 @@ /* Public API for other Nginx modules */ -#define ngx_http_lua_version 10013 +#define ngx_http_lua_version 10015 typedef struct { diff --git a/debian/modules/http-lua/src/ngx_http_lua_accessby.c b/debian/modules/http-lua/src/ngx_http_lua_accessby.c index 56bf0fa..d3fe294 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_accessby.c +++ b/debian/modules/http-lua/src/ngx_http_lua_accessby.c @@ -60,7 +60,7 @@ ngx_http_lua_access_handler(ngx_http_request_t *r) #endif if (cur_ph < last_ph) { - dd("swaping the contents of cur_ph and last_ph..."); + dd("swapping the contents of cur_ph and last_ph..."); tmp = *cur_ph; @@ -261,9 +261,11 @@ ngx_http_lua_access_by_chunk(lua_State *L, ngx_http_request_t *r) /* 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); diff --git a/debian/modules/http-lua/src/ngx_http_lua_api.c b/debian/modules/http-lua/src/ngx_http_lua_api.c index 7b590e7..ac014f2 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_api.c +++ b/debian/modules/http-lua/src/ngx_http_lua_api.c @@ -195,7 +195,7 @@ ngx_http_lua_shared_memory_init(ngx_shm_zone_t *shm_zone, void *data) lmcf->shm_zones_inited++; if (lmcf->shm_zones_inited == lmcf->shm_zones->nelts - && lmcf->init_handler) + && lmcf->init_handler && !ngx_test_config) { saved_cycle = ngx_cycle; ngx_cycle = ctx->cycle; diff --git a/debian/modules/http-lua/src/ngx_http_lua_balancer.c b/debian/modules/http-lua/src/ngx_http_lua_balancer.c index fdf2af3..3ecd592 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_balancer.c +++ b/debian/modules/http-lua/src/ngx_http_lua_balancer.c @@ -362,6 +362,8 @@ ngx_http_lua_balancer_by_chunk(lua_State *L, ngx_http_request_t *r) /* init nginx context in Lua VM */ ngx_http_lua_set_req(L, r); + +#ifndef OPENRESTY_LUAJIT ngx_http_lua_create_new_globals_table(L, 0 /* narr */, 1 /* nrec */); /* {{{ make new env inheriting main thread's globals table */ @@ -372,6 +374,7 @@ ngx_http_lua_balancer_by_chunk(lua_State *L, ngx_http_request_t *r) /* }}} */ lua_setfenv(L, -2); /* set new running env for the code closure */ +#endif /* OPENRESTY_LUAJIT */ lua_pushcfunction(L, ngx_http_lua_traceback); lua_insert(L, 1); /* put it under chunk and args */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_bodyfilterby.c b/debian/modules/http-lua/src/ngx_http_lua_bodyfilterby.c index 2b3c38f..f3af14c 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_bodyfilterby.c +++ b/debian/modules/http-lua/src/ngx_http_lua_bodyfilterby.c @@ -32,10 +32,6 @@ static void ngx_http_lua_body_filter_by_lua_env(lua_State *L, static ngx_http_output_body_filter_pt ngx_http_next_body_filter; -/* key for the ngx_chain_t *in pointer in the Lua thread */ -#define ngx_http_lua_chain_key "__ngx_cl" - - /** * Set environment table for the given code closure. * @@ -51,12 +47,14 @@ static void ngx_http_lua_body_filter_by_lua_env(lua_State *L, ngx_http_request_t *r, ngx_chain_t *in) { - /* set nginx request pointer to current lua thread's globals table */ + ngx_http_lua_main_conf_t *lmcf; + ngx_http_lua_set_req(L, r); - lua_pushlightuserdata(L, in); - lua_setglobal(L, ngx_http_lua_chain_key); + lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); + lmcf->body_filter_chain = in; +#ifndef OPENRESTY_LUAJIT /** * we want to create empty environment for current script * @@ -79,6 +77,7 @@ ngx_http_lua_body_filter_by_lua_env(lua_State *L, ngx_http_request_t *r, /* }}} */ lua_setfenv(L, -2); /* set new running env for the code closure */ +#endif /* OPENRESTY_LUAJIT */ } @@ -236,8 +235,8 @@ ngx_http_lua_body_filter(ngx_http_request_t *r, ngx_chain_t *in) ngx_int_t rc; uint16_t old_context; ngx_http_cleanup_t *cln; - lua_State *L; ngx_chain_t *out; + ngx_http_lua_main_conf_t *lmcf; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua body filter for user lua code, uri \"%V\"", &r->uri); @@ -299,11 +298,8 @@ ngx_http_lua_body_filter(ngx_http_request_t *r, ngx_chain_t *in) return NGX_ERROR; } - L = ngx_http_lua_get_lua_vm(r, ctx); - - lua_getglobal(L, ngx_http_lua_chain_key); - out = lua_touserdata(L, -1); - lua_pop(L, 1); + lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); + out = lmcf->body_filter_chain; if (in == out) { return ngx_http_next_body_filter(r, in); @@ -345,7 +341,7 @@ ngx_http_lua_body_filter_init(void) int -ngx_http_lua_body_filter_param_get(lua_State *L) +ngx_http_lua_body_filter_param_get(lua_State *L, ngx_http_request_t *r) { u_char *data, *p; size_t size; @@ -354,6 +350,8 @@ ngx_http_lua_body_filter_param_get(lua_State *L) int idx; ngx_chain_t *in; + ngx_http_lua_main_conf_t *lmcf; + idx = luaL_checkint(L, 2); dd("index: %d", idx); @@ -363,8 +361,8 @@ ngx_http_lua_body_filter_param_get(lua_State *L) return 1; } - lua_getglobal(L, ngx_http_lua_chain_key); - in = lua_touserdata(L, -1); + lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); + in = lmcf->body_filter_chain; if (idx == 2) { /* asking for the eof argument */ @@ -442,6 +440,8 @@ ngx_http_lua_body_filter_param_set(lua_State *L, ngx_http_request_t *r, ngx_chain_t *cl; ngx_chain_t *in; + ngx_http_lua_main_conf_t *lmcf; + idx = luaL_checkint(L, 2); dd("index: %d", idx); @@ -450,13 +450,13 @@ ngx_http_lua_body_filter_param_set(lua_State *L, ngx_http_request_t *r, return luaL_error(L, "bad index: %d", idx); } + lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); + if (idx == 2) { /* overwriting the eof flag */ last = lua_toboolean(L, 3); - lua_getglobal(L, ngx_http_lua_chain_key); - in = lua_touserdata(L, -1); - lua_pop(L, 1); + in = lmcf->body_filter_chain; if (last) { ctx->seen_last_in_filter = 1; @@ -521,9 +521,7 @@ ngx_http_lua_body_filter_param_set(lua_State *L, ngx_http_request_t *r, case LUA_TNIL: /* discard the buffers */ - lua_getglobal(L, ngx_http_lua_chain_key); /* key val */ - in = lua_touserdata(L, -1); - lua_pop(L, 1); + in = lmcf->body_filter_chain; last = 0; @@ -557,9 +555,7 @@ ngx_http_lua_body_filter_param_set(lua_State *L, ngx_http_request_t *r, lua_typename(L, type)); } - lua_getglobal(L, ngx_http_lua_chain_key); - in = lua_touserdata(L, -1); - lua_pop(L, 1); + in = lmcf->body_filter_chain; last = 0; @@ -625,8 +621,8 @@ done: } } - lua_pushlightuserdata(L, cl); - lua_setglobal(L, ngx_http_lua_chain_key); + lmcf->body_filter_chain = cl; + return 0; } diff --git a/debian/modules/http-lua/src/ngx_http_lua_bodyfilterby.h b/debian/modules/http-lua/src/ngx_http_lua_bodyfilterby.h index 6a4b306..b108202 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_bodyfilterby.h +++ b/debian/modules/http-lua/src/ngx_http_lua_bodyfilterby.h @@ -21,7 +21,7 @@ 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); +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/debian/modules/http-lua/src/ngx_http_lua_cache.c b/debian/modules/http-lua/src/ngx_http_lua_cache.c index 5ea3069..5b29527 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_cache.c +++ b/debian/modules/http-lua/src/ngx_http_lua_cache.c @@ -35,11 +35,14 @@ static ngx_int_t ngx_http_lua_cache_load_code(ngx_log_t *log, lua_State *L, const char *key) { +#ifndef OPENRESTY_LUAJIT int rc; u_char *err; +#endif /* get code cache table */ - lua_pushlightuserdata(L, &ngx_http_lua_code_cache_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + code_cache_key)); lua_rawget(L, LUA_REGISTRYINDEX); /* sp++ */ dd("Code cache table to load: %p", lua_topointer(L, -1)); @@ -52,6 +55,10 @@ ngx_http_lua_cache_load_code(ngx_log_t *log, lua_State *L, lua_getfield(L, -1, key); /* sp++ */ if (lua_isfunction(L, -1)) { +#ifdef OPENRESTY_LUAJIT + lua_remove(L, -2); /* sp-- */ + return NGX_OK; +#else /* call closure factory to gen new closure */ rc = lua_pcall(L, 0, 1, 0); if (rc == 0) { @@ -73,6 +80,7 @@ ngx_http_lua_cache_load_code(ngx_log_t *log, lua_State *L, key, err); lua_pop(L, 2); return NGX_ERROR; +#endif /* OPENRESTY_LUAJIT */ } dd("Value associated with given key in code cache table is not code " @@ -102,10 +110,13 @@ ngx_http_lua_cache_load_code(ngx_log_t *log, lua_State *L, static ngx_int_t ngx_http_lua_cache_store_code(lua_State *L, const char *key) { +#ifndef OPENRESTY_LUAJIT int rc; +#endif /* get code cache table */ - lua_pushlightuserdata(L, &ngx_http_lua_code_cache_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + code_cache_key)); lua_rawget(L, LUA_REGISTRYINDEX); dd("Code cache table to store: %p", lua_topointer(L, -1)); @@ -121,12 +132,14 @@ ngx_http_lua_cache_store_code(lua_State *L, const char *key) /* remove cache table, leave closure factory at top of stack */ lua_pop(L, 1); /* closure */ +#ifndef OPENRESTY_LUAJIT /* call closure factory to generate new closure */ rc = lua_pcall(L, 0, 1, 0); if (rc != 0) { dd("Error: failed to call closure factory!!"); return NGX_ERROR; } +#endif return NGX_OK; } @@ -143,7 +156,8 @@ ngx_http_lua_cache_loadbuffer(ngx_log_t *log, lua_State *L, n = lua_gettop(L); - dd("XXX cache key: [%s]", cache_key); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, + "looking up Lua code cache with key '%s'", cache_key); rc = ngx_http_lua_cache_load_code(log, L, (char *) cache_key); if (rc == NGX_OK) { @@ -227,7 +241,8 @@ ngx_http_lua_cache_loadfile(ngx_log_t *log, lua_State *L, dd("CACHE file key already pre-calculated"); } - dd("XXX cache key for file: [%s]", cache_key); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, + "looking up Lua code cache with key '%s'", cache_key); rc = ngx_http_lua_cache_load_code(log, L, (char *) cache_key); if (rc == NGX_OK) { diff --git a/debian/modules/http-lua/src/ngx_http_lua_clfactory.c b/debian/modules/http-lua/src/ngx_http_lua_clfactory.c index 041f046..754ed8d 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_clfactory.c +++ b/debian/modules/http-lua/src/ngx_http_lua_clfactory.c @@ -15,11 +15,13 @@ #include "ngx_http_lua_clfactory.h" +#ifndef OPENRESTY_LUAJIT #define CLFACTORY_BEGIN_CODE "return function() " #define CLFACTORY_BEGIN_SIZE (sizeof(CLFACTORY_BEGIN_CODE) - 1) #define CLFACTORY_END_CODE "\nend" #define CLFACTORY_END_SIZE (sizeof(CLFACTORY_END_CODE) - 1) +#endif /* @@ -59,6 +61,7 @@ * length(Instruction) = 4 or 8 * little endian or big endian */ +#ifndef OPENRESTY_LUAJIT #define LUA_LITTLE_ENDIAN_4BYTES_CODE \ "\x24\x00\x00\x00\x1e\x00\x00\x01\x1e\x00\x80\x00" #define LUA_LITTLE_ENDIAN_8BYTES_CODE \ @@ -75,6 +78,7 @@ #define LUA_BIG_ENDIAN_8BYTES_CODE_LEN (8 + 8 + 8) #define LUAC_HEADERSIZE 12 #define LUAC_VERSION 0x51 +#endif /* OPENRESTY_LUAJIT */ /* @@ -147,6 +151,7 @@ * --------------------- */ +#ifndef OPENRESTY_LUAJIT #define POS_SOURCE_STR_LEN LUAC_HEADERSIZE #define POS_START_LINE (POS_SOURCE_STR_LEN + sizeof(size_t)) #define POS_LAST_LINE (POS_START_LINE + sizeof(int)) @@ -160,6 +165,7 @@ (POS_BYTECODE + LUA_LITTLE_ENDIAN_8BYTES_CODE_LEN \ + sizeof(int) + sizeof(int)) #define MAX_END_CODE_SIZE (sizeof(int) + sizeof(int) + sizeof(int)) +#endif /* OPENRESTY_LUAJIT */ /* * taken from chaoslawful: @@ -225,6 +231,7 @@ /* bytecode for luajit 2.0 */ +#ifndef OPENRESTY_LUAJIT #define LJ20_LITTLE_ENDIAN_CODE_STRIPPED \ "\x14\x03\x00\x01\x00\x01\x00\x03" \ "\x31\x00\x00\x00\x30\x00\x00\x80\x48\x00\x02\x00" \ @@ -275,6 +282,7 @@ #define LJ21_BCDUMP_VERSION 2 #define LJ20_BCDUMP_VERSION 1 #define LJ_SIGNATURE "\x1b\x4c\x4a" +#endif /* OPENRESTY_LUAJIT */ typedef enum { @@ -292,10 +300,11 @@ enum { typedef struct { ngx_http_lua_clfactory_file_type_e file_type; - int sent_begin; - int sent_end; int extraline; FILE *f; +#ifndef OPENRESTY_LUAJIT + int sent_begin; + int sent_end; size_t begin_code_len; size_t end_code_len; size_t rest_len; @@ -307,13 +316,16 @@ typedef struct { char *ptr; char str[MAX_END_CODE_SIZE]; } end_code; +#endif /* OPENRESTY_LUAJIT */ char buff[NGX_LUA_READER_BUFSIZE]; } ngx_http_lua_clfactory_file_ctx_t; typedef struct { +#ifndef OPENRESTY_LUAJIT int sent_begin; int sent_end; +#endif const char *s; size_t size; } ngx_http_lua_clfactory_buffer_ctx_t; @@ -325,9 +337,12 @@ static int ngx_http_lua_clfactory_errfile(lua_State *L, const char *what, int fname_index); static const char *ngx_http_lua_clfactory_getS(lua_State *L, void *ud, size_t *size); +#ifndef OPENRESTY_LUAJIT static long ngx_http_lua_clfactory_file_size(FILE *f); +#endif +#ifndef OPENRESTY_LUAJIT int ngx_http_lua_clfactory_bytecode_prepare(lua_State *L, ngx_http_lua_clfactory_file_ctx_t *lf, int fname_index) @@ -593,6 +608,7 @@ error: return LUA_ERRFILE; } +#endif /* OPENRESTY_LUAJIT */ ngx_int_t @@ -612,10 +628,12 @@ ngx_http_lua_clfactory_loadfile(lua_State *L, const char *filename) lf.extraline = 0; lf.file_type = NGX_LUA_TEXT_FILE; +#ifndef OPENRESTY_LUAJIT lf.begin_code.ptr = CLFACTORY_BEGIN_CODE; lf.begin_code_len = CLFACTORY_BEGIN_SIZE; lf.end_code.ptr = CLFACTORY_END_CODE; lf.end_code_len = CLFACTORY_END_SIZE; +#endif lua_pushfstring(L, "@%s", filename); @@ -683,20 +701,27 @@ ngx_http_lua_clfactory_loadfile(lua_State *L, const char *filename) /* skip eventual `#!...' */ } +#ifndef OPENRESTY_LUAJIT status = ngx_http_lua_clfactory_bytecode_prepare(L, &lf, fname_index); if (status != 0) { return status; } +#endif lf.extraline = 0; } +#ifndef OPENRESTY_LUAJIT if (lf.file_type == NGX_LUA_TEXT_FILE) { ungetc(c, lf.f); } lf.sent_begin = lf.sent_end = 0; + +#else + ungetc(c, lf.f); +#endif status = lua_load(L, ngx_http_lua_clfactory_getF, &lf, lua_tostring(L, -1)); @@ -725,8 +750,10 @@ ngx_http_lua_clfactory_loadbuffer(lua_State *L, const char *buff, ls.s = buff; ls.size = size; +#ifndef OPENRESTY_LUAJIT ls.sent_begin = 0; ls.sent_end = 0; +#endif return lua_load(L, ngx_http_lua_clfactory_getS, &ls, name); } @@ -735,7 +762,9 @@ ngx_http_lua_clfactory_loadbuffer(lua_State *L, const char *buff, static const char * ngx_http_lua_clfactory_getF(lua_State *L, void *ud, size_t *size) { +#ifndef OPENRESTY_LUAJIT char *buf; +#endif size_t num; ngx_http_lua_clfactory_file_ctx_t *lf; @@ -748,6 +777,7 @@ ngx_http_lua_clfactory_getF(lua_State *L, void *ud, size_t *size) return "\n"; } +#ifndef OPENRESTY_LUAJIT if (lf->sent_begin == 0) { lf->sent_begin = 1; *size = lf->begin_code_len; @@ -761,12 +791,14 @@ ngx_http_lua_clfactory_getF(lua_State *L, void *ud, size_t *size) return buf; } +#endif /* OPENRESTY_LUAJIT */ num = fread(lf->buff, 1, sizeof(lf->buff), lf->f); dd("fread returned %d", (int) num); if (num == 0) { +#ifndef OPENRESTY_LUAJIT if (lf->sent_end == 0) { lf->sent_end = 1; *size = lf->end_code_len; @@ -780,11 +812,13 @@ ngx_http_lua_clfactory_getF(lua_State *L, void *ud, size_t *size) return buf; } +#endif /* OPENRESTY_LUAJIT */ *size = 0; return NULL; } +#ifndef OPENRESTY_LUAJIT if (lf->file_type == NGX_LUA_BT_LJ) { /* skip the footer(\x00) in luajit */ @@ -800,6 +834,7 @@ ngx_http_lua_clfactory_getF(lua_State *L, void *ud, size_t *size) } } } +#endif /* OPENRESTY_LUAJIT */ *size = num; return lf->buff; @@ -833,19 +868,23 @@ ngx_http_lua_clfactory_getS(lua_State *L, void *ud, size_t *size) { ngx_http_lua_clfactory_buffer_ctx_t *ls = ud; +#ifndef OPENRESTY_LUAJIT if (ls->sent_begin == 0) { ls->sent_begin = 1; *size = CLFACTORY_BEGIN_SIZE; return CLFACTORY_BEGIN_CODE; } +#endif if (ls->size == 0) { +#ifndef OPENRESTY_LUAJIT if (ls->sent_end == 0) { ls->sent_end = 1; *size = CLFACTORY_END_SIZE; return CLFACTORY_END_CODE; } +#endif return NULL; } @@ -857,6 +896,7 @@ ngx_http_lua_clfactory_getS(lua_State *L, void *ud, size_t *size) } +#ifndef OPENRESTY_LUAJIT static long ngx_http_lua_clfactory_file_size(FILE *f) { @@ -882,6 +922,7 @@ ngx_http_lua_clfactory_file_size(FILE *f) return len; } +#endif /* OPENRESTY_LUAJIT */ /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_common.h b/debian/modules/http-lua/src/ngx_http_lua_common.h index 01ef2be..dae5245 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_common.h +++ b/debian/modules/http-lua/src/ngx_http_lua_common.h @@ -17,7 +17,7 @@ #include #include -#include +#include #include #include @@ -140,6 +140,15 @@ typedef struct { #endif +#if (NGX_PTR_SIZE >= 8 && !defined(_WIN64)) +#define ngx_http_lua_lightudata_mask(ludata) \ + ((void *) ((uintptr_t) (&ngx_http_lua_##ludata) & ((1UL << 47) - 1))) + +#else +#define ngx_http_lua_lightudata_mask(ludata) (&ngx_http_lua_##ludata) +#endif + + typedef struct ngx_http_lua_main_conf_s ngx_http_lua_main_conf_t; typedef union ngx_http_lua_srv_conf_u ngx_http_lua_srv_conf_t; @@ -173,6 +182,8 @@ struct ngx_http_lua_main_conf_s { ngx_cycle_t *cycle; ngx_pool_t *pool; + ngx_flag_t load_resty_core; + ngx_int_t max_pending_timers; ngx_int_t pending_timers; @@ -208,9 +219,31 @@ struct ngx_http_lua_main_conf_s { ngx_str_t init_worker_src; ngx_http_lua_balancer_peer_data_t *balancer_peer_data; - /* 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. + /* 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 + * concurrent requests when storing the chain + * data pointer in the main conf. + */ + + ngx_http_variable_value_t *setby_args; + /* neither yielding nor recursion is possible in + * set_by_lua*, so there cannot be any races among + * concurrent requests when storing the args pointer + * in the main conf. + */ + + size_t setby_nargs; + /* neither yielding nor recursion is possible in + * set_by_lua*, so there cannot be any races among + * concurrent requests when storing the nargs in the + * main conf. */ ngx_uint_t shm_zones_inited; @@ -227,6 +260,10 @@ struct ngx_http_lua_main_conf_s { ngx_int_t busy_buf_ptr_count; #endif + ngx_int_t host_var_index; + + ngx_flag_t set_sa_restart; + unsigned requires_header_filter:1; unsigned requires_body_filter:1; unsigned requires_capture_filter:1; @@ -444,7 +481,7 @@ typedef struct { typedef struct ngx_http_lua_ctx_s { - /* for lua_coce_cache off: */ + /* for lua_code_cache off: */ ngx_http_lua_vm_state_t *vm_state; ngx_http_request_t *request; @@ -531,6 +568,8 @@ typedef struct ngx_http_lua_ctx_s { unsigned headers_set:1; /* whether the user has set custom response headers */ + unsigned mime_set:1; /* whether the user has set Content-Type + response header */ unsigned entered_rewrite_phase:1; unsigned entered_access_phase:1; diff --git a/debian/modules/http-lua/src/ngx_http_lua_contentby.c b/debian/modules/http-lua/src/ngx_http_lua_contentby.c index ecd6c0e..274c9ad 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_contentby.c +++ b/debian/modules/http-lua/src/ngx_http_lua_contentby.c @@ -63,9 +63,11 @@ ngx_http_lua_content_by_chunk(lua_State *L, ngx_http_request_t *r) /* 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); diff --git a/debian/modules/http-lua/src/ngx_http_lua_control.c b/debian/modules/http-lua/src/ngx_http_lua_control.c index 6ac2cbf..5cd1d64 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_control.c +++ b/debian/modules/http-lua/src/ngx_http_lua_control.c @@ -432,7 +432,8 @@ ngx_http_lua_on_abort(lua_State *L) ngx_http_lua_coroutine_create_helper(L, r, ctx, &coctx); - lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + coroutines_key)); lua_rawget(L, LUA_REGISTRYINDEX); lua_pushvalue(L, -2); diff --git a/debian/modules/http-lua/src/ngx_http_lua_coroutine.c b/debian/modules/http-lua/src/ngx_http_lua_coroutine.c index b790814..99a2423 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_coroutine.c +++ b/debian/modules/http-lua/src/ngx_http_lua_coroutine.c @@ -104,11 +104,15 @@ ngx_http_lua_coroutine_create_helper(lua_State *L, ngx_http_request_t *r, coctx->co = co; coctx->co_status = NGX_HTTP_LUA_CO_SUSPENDED; +#ifdef OPENRESTY_LUAJIT + ngx_http_lua_set_req(co, r); +#else /* make new coroutine share globals of the parent coroutine. * NOTE: globals don't have to be separated! */ ngx_http_lua_get_globals_table(L); lua_xmove(L, co, 1); ngx_http_lua_set_globals_table(co); +#endif lua_xmove(vm, L, 1); /* move coroutine from main thread to L */ @@ -288,15 +292,27 @@ ngx_http_lua_inject_coroutine_api(ngx_log_t *log, lua_State *L) { const char buf[] = "local keys = {'create', 'yield', 'resume', 'status'}\n" +#ifdef OPENRESTY_LUAJIT + "local get_req = require 'thread.exdata'\n" +#else "local getfenv = getfenv\n" +#endif "for _, key in ipairs(keys) do\n" "local std = coroutine['_' .. key]\n" "local ours = coroutine['__' .. key]\n" "local raw_ctx = ngx._phase_ctx\n" "coroutine[key] = function (...)\n" +#ifdef OPENRESTY_LUAJIT + "local r = get_req()\n" +#else "local r = getfenv(0).__ngx_req\n" - "if r then\n" +#endif + "if r ~= nil then\n" +#ifdef OPENRESTY_LUAJIT + "local ctx = raw_ctx()\n" +#else "local ctx = raw_ctx(r)\n" +#endif /* ignore header and body filters */ "if ctx ~= 0x020 and ctx ~= 0x040 then\n" "return ours(...)\n" diff --git a/debian/modules/http-lua/src/ngx_http_lua_directive.c b/debian/modules/http-lua/src/ngx_http_lua_directive.c index fb8c6dc..a989c26 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_directive.c +++ b/debian/modules/http-lua/src/ngx_http_lua_directive.c @@ -1304,11 +1304,12 @@ ngx_http_lua_gen_chunk_name(ngx_conf_t *cf, const char *tag, size_t tag_len, found: - ngx_snprintf(out, len, "=%*s(%*s:%d)%Z", - tag_len, tag, cf->conf_file->file.name.data - + cf->conf_file->file.name.len - p, - p, cf->conf_file->line); - *chunkname_len = len; + p = ngx_snprintf(out, len, "=%*s(%*s:%d)%Z", + tag_len, tag, cf->conf_file->file.name.data + + cf->conf_file->file.name.len - p, + p, cf->conf_file->line); + + *chunkname_len = p - out - 1; /* exclude the trailing '\0' byte */ return out; } diff --git a/debian/modules/http-lua/src/ngx_http_lua_headerfilterby.c b/debian/modules/http-lua/src/ngx_http_lua_headerfilterby.c index b504530..a0acd4a 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_headerfilterby.c +++ b/debian/modules/http-lua/src/ngx_http_lua_headerfilterby.c @@ -42,9 +42,9 @@ static ngx_http_output_header_filter_pt ngx_http_next_header_filter; static void ngx_http_lua_header_filter_by_lua_env(lua_State *L, ngx_http_request_t *r) { - /* set nginx request pointer to current lua thread's globals table */ ngx_http_lua_set_req(L, r); +#ifndef OPENRESTY_LUAJIT /** * we want to create empty environment for current script * @@ -68,6 +68,7 @@ ngx_http_lua_header_filter_by_lua_env(lua_State *L, ngx_http_request_t *r) /* }}} */ lua_setfenv(L, -2); /* set new running env for the code closure */ +#endif /* OPENRESTY_LUAJIT */ } diff --git a/debian/modules/http-lua/src/ngx_http_lua_headers.c b/debian/modules/http-lua/src/ngx_http_lua_headers.c index b833577..e3f48bc 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_headers.c +++ b/debian/modules/http-lua/src/ngx_http_lua_headers.c @@ -442,7 +442,8 @@ ngx_http_lua_ngx_req_get_headers(lua_State *L) lua_createtable(L, 0, count); if (!raw) { - lua_pushlightuserdata(L, &ngx_http_lua_headers_metatable_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + headers_metatable_key)); lua_rawget(L, LUA_REGISTRYINDEX); lua_setmetatable(L, -2); } @@ -504,7 +505,6 @@ ngx_http_lua_ngx_resp_get_headers(lua_State *L) ngx_table_elt_t *header; ngx_http_request_t *r; ngx_http_lua_ctx_t *ctx; - ngx_int_t rc; u_char *lowcase_key = NULL; size_t lowcase_key_sz = 0; ngx_uint_t i; @@ -543,17 +543,6 @@ ngx_http_lua_ngx_resp_get_headers(lua_State *L) return luaL_error(L, "no ctx found"); } - if (!ctx->headers_set) { - rc = ngx_http_lua_set_content_type(r); - if (rc != NGX_OK) { - return luaL_error(L, - "failed to set default content type: %d", - (int) rc); - } - - ctx->headers_set = 1; - } - ngx_http_lua_check_fake_request(L, r); part = &r->headers_out.headers.part; @@ -566,7 +555,8 @@ ngx_http_lua_ngx_resp_get_headers(lua_State *L) lua_createtable(L, 0, count + 2); if (!raw) { - lua_pushlightuserdata(L, &ngx_http_lua_headers_metatable_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + headers_metatable_key)); lua_rawget(L, LUA_REGISTRYINDEX); lua_setmetatable(L, -2); } @@ -694,7 +684,6 @@ ngx_http_lua_ngx_header_get(lua_State *L) size_t len; ngx_http_lua_loc_conf_t *llcf; ngx_http_lua_ctx_t *ctx; - ngx_int_t rc; r = ngx_http_lua_get_req(L); if (r == NULL) { @@ -737,18 +726,7 @@ ngx_http_lua_ngx_header_get(lua_State *L) key.len = len; - if (!ctx->headers_set) { - rc = ngx_http_lua_set_content_type(r); - if (rc != NGX_OK) { - return luaL_error(L, - "failed to set default content type: %d", - (int) rc); - } - - ctx->headers_set = 1; - } - - return ngx_http_lua_get_output_header(L, r, &key); + return ngx_http_lua_get_output_header(L, r, ctx, &key); } @@ -811,16 +789,7 @@ ngx_http_lua_ngx_header_set(lua_State *L) } } - if (!ctx->headers_set) { - rc = ngx_http_lua_set_content_type(r); - if (rc != NGX_OK) { - return luaL_error(L, - "failed to set default content type: %d", - (int) rc); - } - - ctx->headers_set = 1; - } + ctx->headers_set = 1; if (lua_type(L, 3) == LUA_TNIL) { ngx_str_null(&value); @@ -845,7 +814,7 @@ ngx_http_lua_ngx_header_set(lua_State *L) ngx_memcpy(value.data, p, len); value.len = len; - rc = ngx_http_lua_set_output_header(r, key, value, + rc = ngx_http_lua_set_output_header(r, ctx, key, value, i == 1 /* override */); if (rc == NGX_ERROR) { @@ -872,7 +841,7 @@ ngx_http_lua_ngx_header_set(lua_State *L) dd("key: %.*s, value: %.*s", (int) key.len, key.data, (int) value.len, value.data); - rc = ngx_http_lua_set_output_header(r, key, value, 1 /* override */); + rc = ngx_http_lua_set_output_header(r, ctx, key, value, 1 /* override */); if (rc == NGX_ERROR) { return luaL_error(L, "failed to set header %s (error: %d)", @@ -1081,7 +1050,8 @@ ngx_http_lua_create_headers_metatable(ngx_log_t *log, lua_State *L) "local new_key = string.gsub(string.lower(key), '_', '-')\n" "if new_key ~= key then return tb[new_key] else return nil end"; - lua_pushlightuserdata(L, &ngx_http_lua_headers_metatable_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + headers_metatable_key)); /* metatable for ngx.req.get_headers(_, true) and * ngx.resp.get_headers(_, true) */ @@ -1241,15 +1211,7 @@ ngx_http_lua_ffi_set_resp_header(ngx_http_request_t *r, const u_char *key_data, } } - if (!ctx->headers_set) { - rc = ngx_http_lua_set_content_type(r); - if (rc != NGX_OK) { - *errmsg = "failed to set default content type"; - return NGX_ERROR; - } - - ctx->headers_set = 1; - } + ctx->headers_set = 1; if (is_nil) { value.data = NULL; @@ -1276,7 +1238,7 @@ ngx_http_lua_ffi_set_resp_header(ngx_http_request_t *r, const u_char *key_data, ngx_memcpy(value.data, p, len); value.len = len; - rc = ngx_http_lua_set_output_header(r, key, value, + rc = ngx_http_lua_set_output_header(r, ctx, key, value, override && i == 0); if (rc == NGX_ERROR) { @@ -1302,7 +1264,7 @@ ngx_http_lua_ffi_set_resp_header(ngx_http_request_t *r, const u_char *key_data, dd("key: %.*s, value: %.*s", (int) key.len, key.data, (int) value.len, value.data); - rc = ngx_http_lua_set_output_header(r, key, value, override); + rc = ngx_http_lua_set_output_header(r, ctx, key, value, override); if (rc == NGX_ERROR) { *errmsg = "failed to set header"; @@ -1370,7 +1332,8 @@ ngx_http_lua_ffi_req_header_set_single_value(ngx_http_request_t *r, int ngx_http_lua_ffi_get_resp_header(ngx_http_request_t *r, const u_char *key, size_t key_len, - u_char *key_buf, ngx_http_lua_ffi_str_t *values, int max_nvalues) + u_char *key_buf, ngx_http_lua_ffi_str_t *values, int max_nvalues, + char **errmsg) { int found; u_char c, *p; @@ -1387,19 +1350,10 @@ ngx_http_lua_ffi_get_resp_header(ngx_http_request_t *r, ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { - /* *errmsg = "no ctx found"; */ + *errmsg = "no ctx found"; return NGX_ERROR; } - if (!ctx->headers_set) { - if (ngx_http_lua_set_content_type(r) != NGX_OK) { - /* *errmsg = "failed to set default content type"; */ - return NGX_ERROR; - } - - ctx->headers_set = 1; - } - llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); if (llcf->transform_underscores_in_resp_headers && memchr(key, '_', key_len) != NULL) @@ -1425,6 +1379,7 @@ ngx_http_lua_ffi_get_resp_header(ngx_http_request_t *r, { p = ngx_palloc(r->pool, NGX_OFF_T_LEN); if (p == NULL) { + *errmsg = "no memory"; return NGX_ERROR; } @@ -1438,8 +1393,8 @@ ngx_http_lua_ffi_get_resp_header(ngx_http_request_t *r, break; case 12: - if (r->headers_out.content_type.len - && ngx_strncasecmp(key_buf, (u_char *) "Content-Type", 12) == 0) + if (ngx_strncasecmp(key_buf, (u_char *) "Content-Type", 12) == 0 + && r->headers_out.content_type.len) { values[0].data = r->headers_out.content_type.data; values[0].len = r->headers_out.content_type.len; diff --git a/debian/modules/http-lua/src/ngx_http_lua_headers_in.c b/debian/modules/http-lua/src/ngx_http_lua_headers_in.c index 4852b2f..c52cd13 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_headers_in.c +++ b/debian/modules/http-lua/src/ngx_http_lua_headers_in.c @@ -432,10 +432,14 @@ static ngx_int_t ngx_http_set_host_header(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, ngx_str_t *value) { - ngx_str_t host; + ngx_str_t host; + ngx_http_lua_main_conf_t *lmcf; + ngx_http_variable_value_t *var; dd("server new value len: %d", (int) value->len); + lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); + if (value->len) { host= *value; @@ -449,6 +453,10 @@ ngx_http_set_host_header(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, r->headers_in.server = *value; } + var = &r->variables[lmcf->host_var_index]; + var->valid = 0; + var->not_found = 0; + return ngx_http_set_builtin_header(r, hv, value); } diff --git a/debian/modules/http-lua/src/ngx_http_lua_headers_out.c b/debian/modules/http-lua/src/ngx_http_lua_headers_out.c index b908eae..cf94bd0 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_headers_out.c +++ b/debian/modules/http-lua/src/ngx_http_lua_headers_out.c @@ -106,6 +106,12 @@ static ngx_http_lua_set_header_t ngx_http_lua_set_handlers[] = { offsetof(ngx_http_headers_out_t, cache_control), ngx_http_set_builtin_multi_header }, +#if defined(nginx_version) && nginx_version >= 1013009 + { ngx_string("Link"), + offsetof(ngx_http_headers_out_t, link), + ngx_http_set_builtin_multi_header }, +#endif + { ngx_null_string, 0, ngx_http_set_header } }; @@ -476,8 +482,8 @@ ngx_http_clear_builtin_header(ngx_http_request_t *r, ngx_int_t -ngx_http_lua_set_output_header(ngx_http_request_t *r, ngx_str_t key, - ngx_str_t value, unsigned override) +ngx_http_lua_set_output_header(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx, + ngx_str_t key, ngx_str_t value, unsigned override) { ngx_http_lua_header_val_t hv; ngx_http_lua_set_header_t *handlers = ngx_http_lua_set_handlers; @@ -508,6 +514,10 @@ ngx_http_lua_set_output_header(ngx_http_request_t *r, ngx_str_t key, hv.offset = handlers[i].offset; hv.handler = handlers[i].handler; + if (hv.handler == ngx_http_set_content_type_header) { + ctx->mime_set = 1; + } + break; } @@ -528,7 +538,7 @@ ngx_http_lua_set_output_header(ngx_http_request_t *r, ngx_str_t key, int ngx_http_lua_get_output_header(lua_State *L, ngx_http_request_t *r, - ngx_str_t *key) + ngx_http_lua_ctx_t *ctx, ngx_str_t *key) { ngx_table_elt_t *h; ngx_list_part_t *part; @@ -550,8 +560,8 @@ ngx_http_lua_get_output_header(lua_State *L, ngx_http_request_t *r, break; case 12: - if (r->headers_out.content_type.len - && ngx_strncasecmp(key->data, (u_char *) "Content-Type", 12) == 0) + if (ngx_strncasecmp(key->data, (u_char *) "Content-Type", 12) == 0 + && r->headers_out.content_type.len) { lua_pushlstring(L, (char *) r->headers_out.content_type.data, r->headers_out.content_type.len); diff --git a/debian/modules/http-lua/src/ngx_http_lua_headers_out.h b/debian/modules/http-lua/src/ngx_http_lua_headers_out.h index ef5e6d4..6ec1fe3 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_headers_out.h +++ b/debian/modules/http-lua/src/ngx_http_lua_headers_out.h @@ -12,10 +12,10 @@ #include "ngx_http_lua_common.h" -ngx_int_t ngx_http_lua_set_output_header(ngx_http_request_t *r, ngx_str_t key, - ngx_str_t value, unsigned override); +ngx_int_t ngx_http_lua_set_output_header(ngx_http_request_t *r, + ngx_http_lua_ctx_t *ctx, ngx_str_t key, ngx_str_t value, unsigned override); int ngx_http_lua_get_output_header(lua_State *L, ngx_http_request_t *r, - ngx_str_t *key); + ngx_http_lua_ctx_t *ctx, ngx_str_t *key); #endif /* _NGX_HTTP_LUA_HEADERS_OUT_H_INCLUDED_ */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_initworkerby.c b/debian/modules/http-lua/src/ngx_http_lua_initworkerby.c index 4a722a0..76acdc3 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_initworkerby.c +++ b/debian/modules/http-lua/src/ngx_http_lua_initworkerby.c @@ -12,6 +12,7 @@ #include "ngx_http_lua_initworkerby.h" #include "ngx_http_lua_util.h" +#include "ngx_http_lua_pipe.h" static u_char *ngx_http_lua_log_init_worker_error(ngx_log_t *log, @@ -25,6 +26,7 @@ ngx_http_lua_init_worker(ngx_cycle_t *cycle) void *cur, *prev; ngx_uint_t i; ngx_conf_t conf; + ngx_conf_file_t cf_file; ngx_cycle_t *fake_cycle; ngx_module_t **modules; ngx_open_file_t *file, *ofile; @@ -64,8 +66,21 @@ ngx_http_lua_init_worker(ngx_cycle_t *cycle) return NGX_OK; } + +#ifdef HAVE_NGX_LUA_PIPE + if (ngx_http_lua_pipe_add_signal_handler(cycle) != NGX_OK) { + return NGX_ERROR; + } +#endif + #endif /* NGX_WIN32 */ +#if (NGX_HTTP_LUA_HAVE_SA_RESTART) + if (lmcf->set_sa_restart) { + ngx_http_lua_set_sa_restart(ngx_cycle->log); + } +#endif + if (lmcf->init_worker_handler == NULL) { return NGX_OK; } @@ -166,6 +181,10 @@ ngx_http_lua_init_worker(ngx_cycle_t *cycle) conf.pool = fake_cycle->pool; conf.log = cycle->log; + ngx_memzero(&cf_file, sizeof(cf_file)); + cf_file.file.name = cycle->conf_file; + conf.conf_file = &cf_file; + http_ctx.loc_conf = ngx_pcalloc(conf.pool, sizeof(void *) * ngx_http_max_module); if (http_ctx.loc_conf == NULL) { diff --git a/debian/modules/http-lua/src/ngx_http_lua_input_filters.c b/debian/modules/http-lua/src/ngx_http_lua_input_filters.c new file mode 100644 index 0000000..87a9d8c --- /dev/null +++ b/debian/modules/http-lua/src/ngx_http_lua_input_filters.c @@ -0,0 +1,137 @@ + +/* + * Copyright (C) by OpenResty Inc. + */ + + +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + + +#include "ngx_http_lua_common.h" + + +ngx_int_t +ngx_http_lua_read_bytes(ngx_buf_t *src, ngx_chain_t *buf_in, size_t *rest, + ssize_t bytes, ngx_log_t *log) +{ + if (bytes == 0) { + return NGX_ERROR; + } + + if ((size_t) bytes >= *rest) { + + buf_in->buf->last += *rest; + src->pos += *rest; + *rest = 0; + + return NGX_OK; + } + + /* bytes < *rest */ + + buf_in->buf->last += bytes; + src->pos += bytes; + *rest -= bytes; + + return NGX_AGAIN; +} + + +ngx_int_t +ngx_http_lua_read_all(ngx_buf_t *src, ngx_chain_t *buf_in, ssize_t bytes, + ngx_log_t *log) +{ + if (bytes == 0) { + return NGX_OK; + } + + buf_in->buf->last += bytes; + src->pos += bytes; + + return NGX_AGAIN; +} + + +ngx_int_t +ngx_http_lua_read_any(ngx_buf_t *src, ngx_chain_t *buf_in, size_t *max, + ssize_t bytes, ngx_log_t *log) +{ + if (bytes == 0) { + return NGX_ERROR; + } + + if (bytes >= (ssize_t) *max) { + bytes = (ssize_t) *max; + } + + buf_in->buf->last += bytes; + src->pos += bytes; + + return NGX_OK; +} + + +ngx_int_t +ngx_http_lua_read_line(ngx_buf_t *src, ngx_chain_t *buf_in, ssize_t bytes, + ngx_log_t *log) +{ + u_char *dst; + u_char c; +#if (NGX_DEBUG) + u_char *begin; +#endif + +#if (NGX_DEBUG) + begin = src->pos; +#endif + + if (bytes == 0) { + return NGX_ERROR; + } + + dd("already read: %p: %.*s", buf_in, + (int) (buf_in->buf->last - buf_in->buf->pos), buf_in->buf->pos); + + dd("data read: %.*s", (int) bytes, src->pos); + + dst = buf_in->buf->last; + + while (bytes--) { + + c = *src->pos++; + + switch (c) { + case '\n': + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, log, 0, + "lua read the final line part: \"%*s\"", + src->pos - 1 - begin, begin); + + buf_in->buf->last = dst; + + dd("read a line: %p: %.*s", buf_in, + (int) (buf_in->buf->last - buf_in->buf->pos), buf_in->buf->pos); + + return NGX_OK; + + case '\r': + /* ignore it */ + break; + + default: + *dst++ = c; + break; + } + } + +#if (NGX_DEBUG) + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, log, 0, + "lua read partial line data: %*s", dst - begin, begin); +#endif + + buf_in->buf->last = dst; + + return NGX_AGAIN; +} diff --git a/debian/modules/http-lua/src/ngx_http_lua_input_filters.h b/debian/modules/http-lua/src/ngx_http_lua_input_filters.h new file mode 100644 index 0000000..046d40f --- /dev/null +++ b/debian/modules/http-lua/src/ngx_http_lua_input_filters.h @@ -0,0 +1,29 @@ + +/* + * Copyright (C) by OpenResty Inc. + */ + + +#ifndef _NGX_HTTP_LUA_INPUT_FILTERS_H_INCLUDED_ +#define _NGX_HTTP_LUA_INPUT_FILTERS_H_INCLUDED_ + + +#include "ngx_http_lua_common.h" + + +ngx_int_t ngx_http_lua_read_bytes(ngx_buf_t *src, ngx_chain_t *buf_in, + size_t *rest, ssize_t bytes, ngx_log_t *log); + +ngx_int_t ngx_http_lua_read_all(ngx_buf_t *src, ngx_chain_t *buf_in, + ssize_t bytes, ngx_log_t *log); + +ngx_int_t ngx_http_lua_read_any(ngx_buf_t *src, ngx_chain_t *buf_in, + size_t *max, ssize_t bytes, ngx_log_t *log); + +ngx_int_t ngx_http_lua_read_line(ngx_buf_t *src, ngx_chain_t *buf_in, + ssize_t bytes, ngx_log_t *log); + + +#endif /* _NGX_HTTP_LUA_INPUT_FILTERS_H_INCLUDED_ */ + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_logby.c b/debian/modules/http-lua/src/ngx_http_lua_logby.c index 0f1d2f3..32d1cba 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_logby.c +++ b/debian/modules/http-lua/src/ngx_http_lua_logby.c @@ -38,9 +38,9 @@ static ngx_int_t ngx_http_lua_log_by_chunk(lua_State *L, ngx_http_request_t *r); static void ngx_http_lua_log_by_lua_env(lua_State *L, ngx_http_request_t *r) { - /* set nginx request pointer to current lua thread's globals table */ ngx_http_lua_set_req(L, r); +#ifndef OPENRESTY_LUAJIT /** * we want to create empty environment for current script * @@ -64,6 +64,7 @@ ngx_http_lua_log_by_lua_env(lua_State *L, ngx_http_request_t *r) /* }}} */ lua_setfenv(L, -2); /* set new running env for the code closure */ +#endif /* OPENRESTY_LUAJIT */ } diff --git a/debian/modules/http-lua/src/ngx_http_lua_misc.c b/debian/modules/http-lua/src/ngx_http_lua_misc.c index f96e2f2..145ca9b 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_misc.c +++ b/debian/modules/http-lua/src/ngx_http_lua_misc.c @@ -286,6 +286,33 @@ ngx_http_lua_ffi_headers_sent(ngx_http_request_t *r) return r->header_sent ? 1 : 0; } + + +int +ngx_http_lua_ffi_get_conf_env(u_char *name, u_char **env_buf, size_t *name_len) +{ + ngx_uint_t i; + ngx_str_t *var; + ngx_core_conf_t *ccf; + + ccf = (ngx_core_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx, + ngx_core_module); + + var = ccf->env.elts; + + for (i = 0; i < ccf->env.nelts; i++) { + if (var[i].data[var[i].len] == '=' + && ngx_strncmp(name, var[i].data, var[i].len) == 0) + { + *env_buf = var[i].data; + *name_len = var[i].len; + + return NGX_OK; + } + } + + return NGX_DECLINED; +} #endif /* NGX_LUA_NO_FFI_API */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_module.c b/debian/modules/http-lua/src/ngx_http_lua_module.c index ae8bc0e..2a3f5d5 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_module.c +++ b/debian/modules/http-lua/src/ngx_http_lua_module.c @@ -29,6 +29,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_pipe.h" static void *ngx_http_lua_create_main_conf(ngx_conf_t *cf); @@ -76,6 +77,13 @@ static ngx_conf_bitmask_t ngx_http_lua_ssl_protocols[] = { static ngx_command_t ngx_http_lua_cmds[] = { + { ngx_string("lua_load_resty_core"), + NGX_HTTP_MAIN_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_MAIN_CONF_OFFSET, + offsetof(ngx_http_lua_main_conf_t, load_resty_core), + NULL }, + { ngx_string("lua_max_running_timers"), NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1, ngx_conf_set_num_slot, @@ -104,6 +112,13 @@ static ngx_command_t ngx_http_lua_cmds[] = { 0, NULL }, + { ngx_string("lua_sa_restart"), + NGX_HTTP_MAIN_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_MAIN_CONF_OFFSET, + offsetof(ngx_http_lua_main_conf_t, set_sa_restart), + NULL }, + #if (NGX_PCRE) { ngx_string("lua_regex_cache_max_entries"), NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1, @@ -638,9 +653,19 @@ ngx_http_lua_init(ngx_conf_t *cf) #if !defined(NGX_LUA_NO_FFI_API) || nginx_version >= 1011011 ngx_pool_cleanup_t *cln; #endif + ngx_str_t name = ngx_string("host"); + + if (ngx_process == NGX_PROCESS_SIGNALLER || ngx_test_config) { + return NGX_OK; + } lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_lua_module); + lmcf->host_var_index = ngx_http_get_variable_index(cf, &name); + if (lmcf->host_var_index == NGX_ERROR) { + return NGX_ERROR; + } + if (ngx_http_lua_prev_cycle != ngx_cycle) { ngx_http_lua_prev_cycle = ngx_cycle; multi_http_blocks = 0; @@ -725,6 +750,11 @@ ngx_http_lua_init(ngx_conf_t *cf) cln->data = lmcf; cln->handler = ngx_http_lua_sema_mm_cleanup; + +#ifdef HAVE_NGX_LUA_PIPE + ngx_http_lua_pipe_init(); +#endif + #endif #if nginx_version >= 1011011 @@ -740,6 +770,19 @@ ngx_http_lua_init(ngx_conf_t *cf) if (lmcf->lua == NULL) { dd("initializing lua vm"); +#ifndef OPENRESTY_LUAJIT + if (ngx_process != NGX_PROCESS_SIGNALLER && !ngx_test_config) { + ngx_log_error(NGX_LOG_ALERT, cf->log, 0, + "detected a LuaJIT version which is not OpenResty's" + "; many optimizations will be disabled and " + "performance will be compromised (see " + "https://github.com/openresty/luajit2 for " + "OpenResty's LuaJIT or, even better, consider using " + "the OpenResty releases from https://openresty.org/" + "en/download.html)"); + } +#endif + ngx_http_lua_content_length_hash = ngx_http_lua_hash_literal("content-length"); ngx_http_lua_location_hash = ngx_http_lua_hash_literal("location"); @@ -841,6 +884,7 @@ ngx_http_lua_create_main_conf(ngx_conf_t *cf) */ lmcf->pool = cf->pool; + lmcf->load_resty_core = NGX_CONF_UNSET; lmcf->max_pending_timers = NGX_CONF_UNSET; lmcf->max_running_timers = NGX_CONF_UNSET; #if (NGX_PCRE) @@ -850,6 +894,8 @@ ngx_http_lua_create_main_conf(ngx_conf_t *cf) lmcf->postponed_to_rewrite_phase_end = NGX_CONF_UNSET; lmcf->postponed_to_access_phase_end = NGX_CONF_UNSET; + lmcf->set_sa_restart = NGX_CONF_UNSET; + #if (NGX_HTTP_LUA_HAVE_MALLOC_TRIM) lmcf->malloc_trim_cycle = NGX_CONF_UNSET_UINT; #endif @@ -872,6 +918,10 @@ ngx_http_lua_init_main_conf(ngx_conf_t *cf, void *conf) { ngx_http_lua_main_conf_t *lmcf = conf; + if (lmcf->load_resty_core == NGX_CONF_UNSET) { + lmcf->load_resty_core = 1; + } + #if (NGX_PCRE) if (lmcf->regex_cache_max_entries == NGX_CONF_UNSET) { lmcf->regex_cache_max_entries = 1024; @@ -890,6 +940,12 @@ ngx_http_lua_init_main_conf(ngx_conf_t *cf, void *conf) lmcf->max_running_timers = 256; } +#if (NGX_HTTP_LUA_HAVE_SA_RESTART) + if (lmcf->set_sa_restart == NGX_CONF_UNSET) { + lmcf->set_sa_restart = 1; + } +#endif + #if (NGX_HTTP_LUA_HAVE_MALLOC_TRIM) if (lmcf->malloc_trim_cycle == NGX_CONF_UNSET_UINT) { lmcf->malloc_trim_cycle = 1000; /* number of reqs */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_ndk.c b/debian/modules/http-lua/src/ngx_http_lua_ndk.c index 24b80b4..6344183 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_ndk.c +++ b/debian/modules/http-lua/src/ngx_http_lua_ndk.c @@ -186,6 +186,47 @@ ngx_http_lua_inject_ndk_api(lua_State *L) } +int +ngx_http_lua_ffi_ndk_lookup_directive(const u_char *var_data, + size_t var_len, ndk_set_var_value_pt *func) +{ + *func = ngx_http_lookup_ndk_set_var_directive((u_char *) var_data, var_len); + + if (*func == NULL) { + return NGX_ERROR; + } + + return NGX_OK; +} + + +int +ngx_http_lua_ffi_ndk_set_var_get(ngx_http_request_t *r, + ndk_set_var_value_pt func, const u_char *arg_data, size_t arg_len, + ngx_http_lua_ffi_str_t *value) +{ + ngx_int_t rc; + ngx_str_t res; + ngx_http_variable_value_t arg; + + ngx_memzero(&arg, sizeof(ngx_http_variable_value_t)); + arg.valid = 1; + + arg.data = (u_char *) arg_data; + arg.len = arg_len; + + rc = func(r, &res, &arg); + + if (rc != NGX_OK) { + return rc; + } + + value->data = res.data; + value->len = res.len; + return NGX_OK; +} + + #endif /* defined(NDK) && NDK */ /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_pipe.c b/debian/modules/http-lua/src/ngx_http_lua_pipe.c new file mode 100644 index 0000000..8c8221f --- /dev/null +++ b/debian/modules/http-lua/src/ngx_http_lua_pipe.c @@ -0,0 +1,2475 @@ + +/* + * Copyright (C) by OpenResty Inc. + */ + + +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + + +#include "ngx_http_lua_common.h" +#include "ngx_http_lua_input_filters.h" +#include "ngx_http_lua_util.h" +#include "ngx_http_lua_pipe.h" +#if (NGX_HTTP_LUA_HAVE_SIGNALFD) +#include +#endif + + +#ifdef HAVE_NGX_LUA_PIPE +static ngx_rbtree_node_t *ngx_http_lua_pipe_lookup_pid(ngx_rbtree_key_t key); +#if !(NGX_HTTP_LUA_HAVE_SIGNALFD) +static void ngx_http_lua_pipe_sigchld_handler(int signo, siginfo_t *siginfo, + void *ucontext); +#endif +static void ngx_http_lua_pipe_sigchld_event_handler(ngx_event_t *ev); +static ssize_t ngx_http_lua_pipe_fd_read(ngx_connection_t *c, u_char *buf, + size_t size); +static ssize_t ngx_http_lua_pipe_fd_write(ngx_connection_t *c, u_char *buf, + size_t size); +static ngx_int_t ngx_http_lua_pipe_close_helper( + ngx_http_lua_pipe_ctx_t *pipe_ctx, ngx_event_t *ev, int forced); +static ngx_int_t ngx_http_lua_pipe_close_stdin(ngx_http_lua_pipe_t *pipe, + int forced); +static ngx_int_t ngx_http_lua_pipe_close_stdout(ngx_http_lua_pipe_t *pipe, + int forced); +static ngx_int_t ngx_http_lua_pipe_close_stderr(ngx_http_lua_pipe_t *pipe, + int forced); +static void ngx_http_lua_pipe_proc_finalize(ngx_http_lua_ffi_pipe_proc_t *proc, + int forced); +static ngx_int_t ngx_http_lua_pipe_get_lua_ctx(ngx_http_request_t *r, + ngx_http_lua_ctx_t **ctx, u_char *errbuf, size_t *errbuf_size); +static void ngx_http_lua_pipe_put_error(ngx_http_lua_pipe_ctx_t *pipe_ctx, + u_char *errbuf, size_t *errbuf_size); +static void ngx_http_lua_pipe_put_data(ngx_http_lua_pipe_t *pipe, + ngx_http_lua_pipe_ctx_t *pipe_ctx, u_char **buf, size_t *buf_size); +static ngx_int_t ngx_http_lua_pipe_add_input_buffer(ngx_http_lua_pipe_t *pipe, + ngx_http_lua_pipe_ctx_t *pipe_ctx); +static ngx_int_t ngx_http_lua_pipe_read_all(void *data, ssize_t bytes); +static ngx_int_t ngx_http_lua_pipe_read_bytes(void *data, ssize_t bytes); +static ngx_int_t ngx_http_lua_pipe_read_line(void *data, ssize_t bytes); +static ngx_int_t ngx_http_lua_pipe_read_any(void *data, ssize_t bytes); +static ngx_int_t ngx_http_lua_pipe_read(ngx_http_lua_pipe_t *pipe, + ngx_http_lua_pipe_ctx_t *pipe_ctx); +static ngx_int_t ngx_http_lua_pipe_init_ctx( + ngx_http_lua_pipe_ctx_t **pipe_ctx_pt, int fd, ngx_pool_t *pool, + u_char *errbuf, size_t *errbuf_size); +static ngx_int_t ngx_http_lua_pipe_write(ngx_http_lua_pipe_t *pipe, + ngx_http_lua_pipe_ctx_t *pipe_ctx); +static int ngx_http_lua_pipe_read_stdout_retval( + ngx_http_lua_ffi_pipe_proc_t *proc, lua_State *L); +static int ngx_http_lua_pipe_read_stderr_retval( + ngx_http_lua_ffi_pipe_proc_t *proc, lua_State *L); +static int ngx_http_lua_pipe_read_retval_helper( + ngx_http_lua_ffi_pipe_proc_t *proc, lua_State *L, int from_stderr); +static int ngx_http_lua_pipe_write_retval(ngx_http_lua_ffi_pipe_proc_t *proc, + lua_State *L); +static int ngx_http_lua_pipe_wait_retval(ngx_http_lua_ffi_pipe_proc_t *proc, + lua_State *L); +static void ngx_http_lua_pipe_resume_helper(ngx_event_t *ev, + ngx_http_lua_co_ctx_t *wait_co_ctx); +static void ngx_http_lua_pipe_resume_read_stdout_handler(ngx_event_t *ev); +static void ngx_http_lua_pipe_resume_read_stderr_handler(ngx_event_t *ev); +static void ngx_http_lua_pipe_resume_write_handler(ngx_event_t *ev); +static void ngx_http_lua_pipe_resume_wait_handler(ngx_event_t *ev); +static ngx_int_t ngx_http_lua_pipe_resume(ngx_http_request_t *r); +static void ngx_http_lua_pipe_dummy_event_handler(ngx_event_t *ev); +static void ngx_http_lua_pipe_clear_event(ngx_event_t *ev); +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 ngx_rbtree_t ngx_http_lua_pipe_rbtree; +static ngx_rbtree_node_t ngx_http_lua_pipe_proc_sentinel; + + +#if (NGX_HTTP_LUA_HAVE_SIGNALFD) +static int ngx_http_lua_signalfd; +static struct signalfd_siginfo ngx_http_lua_pipe_notification; + +#define ngx_http_lua_read_sigfd ngx_http_lua_signalfd + +#else +static int ngx_http_lua_sigchldfd[2]; +static u_char ngx_http_lua_pipe_notification[1]; + +#define ngx_http_lua_read_sigfd ngx_http_lua_sigchldfd[0] +#define ngx_http_lua_write_sigfd ngx_http_lua_sigchldfd[1] +#endif + + +static ngx_connection_t *ngx_http_lua_sigfd_conn = NULL; + + +/* The below signals are ignored by Nginx. + * We need to reset them for the spawned child processes. */ +ngx_http_lua_pipe_signal_t ngx_signals[] = { + { SIGSYS, "SIGSYS" }, + { SIGPIPE, "SIGPIPE" }, + { 0, NULL } +}; + + +enum { + PIPE_ERR_CLOSED = 1, + PIPE_ERR_SYSCALL, + PIPE_ERR_NOMEM, + PIPE_ERR_TIMEOUT, + PIPE_ERR_ADD_READ_EV, + PIPE_ERR_ADD_WRITE_EV +}; + + +enum { + PIPE_READ_ALL = 0, + PIPE_READ_BYTES, + PIPE_READ_LINE, + PIPE_READ_ANY +}; + + +#define REASON_EXIT "exit" +#define REASON_SIGNAL "signal" +#define REASON_UNKNOWN "unknown" + +#define REASON_RUNNING_CODE 0 +#define REASON_EXIT_CODE 1 +#define REASON_SIGNAL_CODE 2 +#define REASON_UNKNOWN_CODE 3 + + +void +ngx_http_lua_pipe_init(void) +{ + ngx_rbtree_init(&ngx_http_lua_pipe_rbtree, + &ngx_http_lua_pipe_proc_sentinel, ngx_rbtree_insert_value); +} + + +ngx_int_t +ngx_http_lua_pipe_add_signal_handler(ngx_cycle_t *cycle) +{ + ngx_event_t *rev; +#if (NGX_HTTP_LUA_HAVE_SIGNALFD) + sigset_t set; + +#else + int rc; + struct sigaction sa; +#endif + +#if (NGX_HTTP_LUA_HAVE_SIGNALFD) + if (sigemptyset(&set) != 0) { + ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno, + "lua pipe init signal set failed"); + return NGX_ERROR; + } + + if (sigaddset(&set, SIGCHLD) != 0) { + ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno, + "lua pipe add SIGCHLD to signal set failed"); + return NGX_ERROR; + } + + if (sigprocmask(SIG_BLOCK, &set, NULL) != 0) { + ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno, + "lua pipe block SIGCHLD failed"); + return NGX_ERROR; + } + + ngx_http_lua_signalfd = signalfd(-1, &set, SFD_NONBLOCK|SFD_CLOEXEC); + if (ngx_http_lua_signalfd < 0) { + ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno, + "lua pipe create signalfd instance failed"); + return NGX_ERROR; + } + +#else /* !(NGX_HTTP_LUA_HAVE_SIGNALFD) */ +# if (NGX_HTTP_LUA_HAVE_PIPE2) + rc = pipe2(ngx_http_lua_sigchldfd, O_NONBLOCK|O_CLOEXEC); +# else + rc = pipe(ngx_http_lua_sigchldfd); +# endif + + if (rc == -1) { + ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno, + "lua pipe init SIGCHLD fd failed"); + return NGX_ERROR; + } + +# if !(NGX_HTTP_LUA_HAVE_PIPE2) + if (ngx_nonblocking(ngx_http_lua_read_sigfd) == -1) { + ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno, "lua pipe " + ngx_nonblocking_n " SIGCHLD read fd failed"); + goto failed; + } + + if (ngx_nonblocking(ngx_http_lua_write_sigfd) == -1) { + ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno, "lua pipe " + ngx_nonblocking_n " SIGCHLD write fd failed"); + goto failed; + } + + /* it's ok not to set the pipe fd with O_CLOEXEC. This requires + * extra syscall */ +# endif /* !(NGX_HTTP_LUA_HAVE_PIPE2) */ +#endif /* NGX_HTTP_LUA_HAVE_SIGNALFD */ + + ngx_http_lua_sigfd_conn = ngx_get_connection(ngx_http_lua_read_sigfd, + cycle->log); + if (ngx_http_lua_sigfd_conn == NULL) { + goto failed; + } + + ngx_http_lua_sigfd_conn->log = cycle->log; + ngx_http_lua_sigfd_conn->recv = ngx_http_lua_pipe_fd_read; + rev = ngx_http_lua_sigfd_conn->read; + rev->log = ngx_http_lua_sigfd_conn->log; + rev->handler = ngx_http_lua_pipe_sigchld_event_handler; + +#ifdef HAVE_SOCKET_CLOEXEC_PATCH + rev->skip_socket_leak_check = 1; +#endif + + if (ngx_handle_read_event(rev, 0) == NGX_ERROR) { + goto failed; + } + +#if !(NGX_HTTP_LUA_HAVE_SIGNALFD) + ngx_memzero(&sa, sizeof(struct sigaction)); + sa.sa_sigaction = ngx_http_lua_pipe_sigchld_handler; + sa.sa_flags = SA_SIGINFO; + + if (sigemptyset(&sa.sa_mask) != 0) { + ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno, + "lua pipe init signal mask failed"); + goto failed; + } + + if (sigaction(SIGCHLD, &sa, NULL) == -1) { + ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno, + "lua pipe sigaction(SIGCHLD) failed"); + goto failed; + } +#endif + + return NGX_OK; + +failed: + + if (ngx_http_lua_sigfd_conn != NULL) { + ngx_close_connection(ngx_http_lua_sigfd_conn); + ngx_http_lua_sigfd_conn = NULL; + } + + if (close(ngx_http_lua_read_sigfd) == -1) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, + "lua pipe close the read sigfd failed"); + } + +#if !(NGX_HTTP_LUA_HAVE_SIGNALFD) + if (close(ngx_http_lua_write_sigfd) == -1) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, + "lua pipe close the write sigfd failed"); + } +#endif + + return NGX_ERROR; +} + + +static ngx_rbtree_node_t * +ngx_http_lua_pipe_lookup_pid(ngx_rbtree_key_t key) +{ + ngx_rbtree_node_t *node, *sentinel; + + node = ngx_http_lua_pipe_rbtree.root; + sentinel = ngx_http_lua_pipe_rbtree.sentinel; + + while (node != sentinel) { + if (key < node->key) { + node = node->left; + continue; + } + + if (key > node->key) { + node = node->right; + continue; + } + + return node; + } + + return NULL; +} + + +#if !(NGX_HTTP_LUA_HAVE_SIGNALFD) +static void +ngx_http_lua_pipe_sigchld_handler(int signo, siginfo_t *siginfo, + void *ucontext) +{ + ngx_err_t err, saved_err; + ngx_int_t n; + + saved_err = ngx_errno; + + for ( ;; ) { + n = write(ngx_http_lua_write_sigfd, ngx_http_lua_pipe_notification, + sizeof(ngx_http_lua_pipe_notification)); + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0, + "lua pipe SIGCHLD fd write siginfo:%p", siginfo); + + if (n >= 0) { + break; + } + + err = ngx_errno; + + if (err != NGX_EINTR) { + if (err != NGX_EAGAIN) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, err, + "lua pipe SIGCHLD fd write failed"); + } + + break; + } + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, err, + "lua pipe SIGCHLD fd write was interrupted"); + } + + ngx_set_errno(saved_err); +} +#endif + + +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"); + + for ( ;; ) { +#if (NGX_HTTP_LUA_HAVE_SIGNALFD) + n = c->recv(c, (u_char *) &ngx_http_lua_pipe_notification, +#else + n = c->recv(c, ngx_http_lua_pipe_notification, +#endif + sizeof(ngx_http_lua_pipe_notification)); + + if (n <= 0) { + if (n == NGX_ERROR) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, + "lua pipe SIGCHLD fd read failed"); + } + + break; + } + + for ( ;; ) { + pid = waitpid(-1, &status, WNOHANG); + + if (pid == 0) { + break; + } + + if (pid < 0) { + if (ngx_errno != NGX_ECHILD) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, + "lua pipe waitpid failed"); + } + + break; + } + + /* This log is ported from Nginx's signal handler since we override + * or block it in this implementation. */ + ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0, + "signal %d (SIGCHLD) received from %P", + SIGCHLD, pid); + + 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); + } + + 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 ssize_t +ngx_http_lua_pipe_fd_read(ngx_connection_t *c, u_char *buf, size_t size) +{ + ssize_t n; + ngx_err_t err; + ngx_event_t *rev; + + rev = c->read; + + do { + n = read(c->fd, buf, size); + + err = ngx_errno; + + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, + "read: fd:%d %z of %uz", c->fd, n, size); + + if (n == 0) { + rev->ready = 0; + rev->eof = 1; + return 0; + } + + if (n > 0) { + if ((size_t) n < size + && !(ngx_event_flags & NGX_USE_GREEDY_EVENT)) + { + rev->ready = 0; + } + + return n; + } + + if (err == NGX_EAGAIN || err == NGX_EINTR) { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, + "read() not ready"); + n = NGX_AGAIN; + + } else { + n = ngx_connection_error(c, err, "read() failed"); + break; + } + + } while (err == NGX_EINTR); + + rev->ready = 0; + + if (n == NGX_ERROR) { + rev->error = 1; + } + + return n; +} + + +static ssize_t +ngx_http_lua_pipe_fd_write(ngx_connection_t *c, u_char *buf, size_t size) +{ + ssize_t n; + ngx_err_t err; + ngx_event_t *wev; + + wev = c->write; + + do { + n = write(c->fd, buf, size); + + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, + "write: fd:%d %z of %uz", c->fd, n, size); + + if (n >= 0) { + if ((size_t) n != size) { + wev->ready = 0; + } + + return n; + } + + err = ngx_errno; + + if (err == NGX_EAGAIN || err == NGX_EINTR) { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, + "write() not ready"); + n = NGX_AGAIN; + + } else if (err != NGX_EPIPE) { + n = ngx_connection_error(c, err, "write() failed"); + break; + } + + } while (err == NGX_EINTR); + + wev->ready = 0; + + if (n == NGX_ERROR) { + wev->error = 1; + } + + return n; +} + + +int +ngx_http_lua_ffi_pipe_spawn(ngx_http_lua_ffi_pipe_proc_t *proc, + const char *file, const char **argv, int merge_stderr, size_t buffer_size, + u_char *errbuf, size_t *errbuf_size) +{ + int rc; + int in[2]; + int out[2]; + int err[2]; + int stdin_fd, stdout_fd, stderr_fd; + int errlog_fd, temp_errlog_fd; + ngx_pid_t pid; + ssize_t pool_size; + ngx_pool_t *pool; + ngx_uint_t i; + ngx_listening_t *ls; + ngx_http_lua_pipe_t *pp; + ngx_rbtree_node_t *node; + ngx_http_lua_pipe_node_t *pipe_node; + struct sigaction sa; + ngx_http_lua_pipe_signal_t *sig; + sigset_t set; + + pool_size = ngx_align(NGX_MIN_POOL_SIZE + buffer_size * 2, + NGX_POOL_ALIGNMENT); + + pool = ngx_create_pool(pool_size, ngx_cycle->log); + if (pool == NULL) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "no memory") + - errbuf; + return NGX_ERROR; + } + + pp = ngx_pcalloc(pool, sizeof(ngx_http_lua_pipe_t) + + offsetof(ngx_rbtree_node_t, color) + + sizeof(ngx_http_lua_pipe_node_t)); + if (pp == NULL) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "no memory") + - errbuf; + goto free_pool; + } + + rc = pipe(in); + if (rc == -1) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "pipe failed: %s", + strerror(errno)) + - errbuf; + goto free_pool; + } + + rc = pipe(out); + if (rc == -1) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "pipe failed: %s", + strerror(errno)) + - errbuf; + goto close_in_fd; + } + + if (!merge_stderr) { + rc = pipe(err); + if (rc == -1) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, + "pipe failed: %s", strerror(errno)) + - errbuf; + goto close_in_out_fd; + } + } + + pid = fork(); + if (pid == -1) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "fork failed: %s", + strerror(errno)) + - errbuf; + goto close_in_out_err_fd; + } + + if (pid == 0) { + +#if (NGX_HAVE_CPU_AFFINITY) + /* reset the CPU affinity mask */ + ngx_uint_t log_level; + ngx_cpuset_t child_cpu_affinity; + + if (ngx_process == NGX_PROCESS_WORKER + && ngx_get_cpu_affinity(ngx_worker) != NULL) + { + CPU_ZERO(&child_cpu_affinity); + + for (i = 0; i < (ngx_uint_t) ngx_min(ngx_ncpu, CPU_SETSIZE); i++) { + CPU_SET(i, &child_cpu_affinity); + } + + log_level = ngx_cycle->log->log_level; + ngx_cycle->log->log_level = NGX_LOG_WARN; + ngx_setaffinity(&child_cpu_affinity, ngx_cycle->log); + ngx_cycle->log->log_level = log_level; + } +#endif + + /* reset the handler of ignored signals to the default */ + for (sig = ngx_signals; sig->signo != 0; sig++) { + ngx_memzero(&sa, sizeof(struct sigaction)); + sa.sa_handler = SIG_DFL; + + if (sigemptyset(&sa.sa_mask) != 0) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, + "lua pipe child init signal mask failed"); + exit(EXIT_FAILURE); + } + + if (sigaction(sig->signo, &sa, NULL) == -1) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, + "lua pipe child reset signal handler for %s " + "failed", sig->signame); + exit(EXIT_FAILURE); + } + } + + /* reset signal mask */ + if (sigemptyset(&set) != 0) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, + "lua pipe child init signal set failed"); + exit(EXIT_FAILURE); + } + + if (sigprocmask(SIG_SETMASK, &set, NULL) != 0) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, + "lua pipe child reset signal mask failed"); + exit(EXIT_FAILURE); + } + + /* close listening socket fd */ + ls = ngx_cycle->listening.elts; + for (i = 0; i < ngx_cycle->listening.nelts; i++) { + if (ngx_close_socket(ls[i].fd) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_socket_errno, + "lua pipe child " ngx_close_socket_n + " %V failed", &ls[i].addr_text); + } + } + + /* close and dup pipefd */ + if (close(in[1]) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, + "lua pipe child failed to close the in[1] " + "pipe fd"); + } + + if (close(out[0]) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, + "lua pipe child failed to close the out[0] " + "pipe fd"); + } + + if (ngx_cycle->log->file && ngx_cycle->log->file->fd == STDERR_FILENO) { + errlog_fd = ngx_cycle->log->file->fd; + temp_errlog_fd = dup(errlog_fd); + + if (temp_errlog_fd == -1) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, + "lua pipe child dup errlog fd failed"); + exit(EXIT_FAILURE); + } + + if (ngx_cloexec(temp_errlog_fd) == -1) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, + "lua pipe child new errlog fd " ngx_cloexec_n + " failed"); + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe child dup old errlog fd %d to new fd %d", + ngx_cycle->log->file->fd, temp_errlog_fd); + + ngx_cycle->log->file->fd = temp_errlog_fd; + } + + if (dup2(in[0], STDIN_FILENO) == -1) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, + "lua pipe child dup2 stdin failed"); + exit(EXIT_FAILURE); + } + + if (dup2(out[1], STDOUT_FILENO) == -1) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, + "lua pipe child dup2 stdout failed"); + exit(EXIT_FAILURE); + } + + if (merge_stderr) { + if (dup2(STDOUT_FILENO, STDERR_FILENO) == -1) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, + "lua pipe child dup2 stderr failed"); + exit(EXIT_FAILURE); + } + + } else { + if (close(err[0]) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, + "lua pipe child failed to close the err[0] " + "pipe fd"); + } + + if (dup2(err[1], STDERR_FILENO) == -1) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, + "lua pipe child dup2 stderr failed"); + exit(EXIT_FAILURE); + } + } + + if (execvp(file, (char * const *) argv) == -1) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, + "lua pipe child execvp() failed while executing %s", + file); + } + + exit(EXIT_FAILURE); + } + + /* parent process */ + if (close(in[0]) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, + "lua pipe: failed to close the in[0] pipe fd"); + } + + stdin_fd = in[1]; + + if (ngx_nonblocking(stdin_fd) == -1) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, + ngx_nonblocking_n " failed: %s", + strerror(errno)) + - errbuf; + goto close_in_out_err_fd; + } + + pp->stdin_fd = stdin_fd; + + if (close(out[1]) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, + "lua pipe: failed to close the out[1] pipe fd"); + } + + stdout_fd = out[0]; + + if (ngx_nonblocking(stdout_fd) == -1) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, + ngx_nonblocking_n " failed: %s", + strerror(errno)) + - errbuf; + goto close_in_out_err_fd; + } + + pp->stdout_fd = stdout_fd; + + if (!merge_stderr) { + if (close(err[1]) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, + "lua pipe: failed to close the err[1] pipe fd"); + } + + stderr_fd = err[0]; + + if (ngx_nonblocking(stderr_fd) == -1) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, + ngx_nonblocking_n " failed: %s", + strerror(errno)) + - errbuf; + goto close_in_out_err_fd; + } + + pp->stderr_fd = stderr_fd; + } + + node = (ngx_rbtree_node_t *) (pp + 1); + node->key = pid; + pipe_node = (ngx_http_lua_pipe_node_t *) &node->color; + pipe_node->proc = proc; + ngx_rbtree_insert(&ngx_http_lua_pipe_rbtree, node); + + pp->node = node; + pp->pool = pool; + pp->merge_stderr = merge_stderr; + pp->buffer_size = buffer_size; + + proc->_pid = pid; + proc->write_timeout = 10000; + proc->stdout_read_timeout = 10000; + proc->stderr_read_timeout = 10000; + proc->wait_timeout = 10000; + proc->pipe = pp; + + ngx_log_debug4(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe spawn process:%p pid:%P merge_stderr:%d " + "buffer_size:%uz", proc, pid, merge_stderr, buffer_size); + return NGX_OK; + +close_in_out_err_fd: + + if (!merge_stderr) { + if (close(err[0]) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, + "failed to close the err[0] pipe fd"); + } + + if (close(err[1]) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, + "failed to close the err[1] pipe fd"); + } + } + +close_in_out_fd: + + if (close(out[0]) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, + "failed to close the out[0] pipe fd"); + } + + if (close(out[1]) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, + "failed to close the out[1] pipe fd"); + } + +close_in_fd: + + if (close(in[0]) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, + "failed to close the in[0] pipe fd"); + } + + if (close(in[1]) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, + "failed to close the in[1] pipe fd"); + } + +free_pool: + + ngx_destroy_pool(pool); + return NGX_ERROR; +} + + +static ngx_int_t +ngx_http_lua_pipe_close_helper(ngx_http_lua_pipe_ctx_t *pipe_ctx, + ngx_event_t *ev, int forced) +{ + if (ev->handler != ngx_http_lua_pipe_dummy_event_handler && !forced) { + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe cannot close fd:%d without " + "forced pipe:%p ev:%p", pipe_ctx->c->fd, pipe_ctx, ev); + return NGX_ERROR; + } + + ngx_close_connection(pipe_ctx->c); + pipe_ctx->c = NULL; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_lua_pipe_close_stdin(ngx_http_lua_pipe_t *pipe, int forced) +{ + ngx_event_t *wev; + + if (pipe->stdin_ctx == NULL) { + if (pipe->stdin_fd != -1) { + if (close(pipe->stdin_fd) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, + "failed to close the stdin pipe fd"); + } + + pipe->stdin_fd = -1; + } + + } else if (pipe->stdin_ctx->c != NULL) { + wev = pipe->stdin_ctx->c->write; + return ngx_http_lua_pipe_close_helper(pipe->stdin_ctx, wev, forced); + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_lua_pipe_close_stdout(ngx_http_lua_pipe_t *pipe, int forced) +{ + ngx_event_t *rev; + + if (pipe->stdout_ctx == NULL) { + if (pipe->stdout_fd != -1) { + if (close(pipe->stdout_fd) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, + "failed to close the stdout pipe fd"); + } + + pipe->stdout_fd = -1; + } + + } else if (pipe->stdout_ctx->c != NULL) { + rev = pipe->stdout_ctx->c->read; + return ngx_http_lua_pipe_close_helper(pipe->stdout_ctx, rev, forced); + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_lua_pipe_close_stderr(ngx_http_lua_pipe_t *pipe, int forced) +{ + ngx_event_t *rev; + + if (pipe->stderr_ctx == NULL) { + if (pipe->stderr_fd != -1) { + if (close(pipe->stderr_fd) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, + "failed to close the stderr pipe fd"); + } + + pipe->stderr_fd = -1; + } + + } else if (pipe->stderr_ctx->c != NULL) { + rev = pipe->stderr_ctx->c->read; + return ngx_http_lua_pipe_close_helper(pipe->stderr_ctx, rev, forced); + } + + return NGX_OK; +} + + +int +ngx_http_lua_ffi_pipe_proc_shutdown_stdin(ngx_http_lua_ffi_pipe_proc_t *proc, + u_char *errbuf, size_t *errbuf_size) +{ + ngx_int_t rc; + ngx_http_lua_pipe_t *pipe; + + pipe = proc->pipe; + if (pipe == NULL || pipe->closed) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "closed") - errbuf; + return NGX_ERROR; + } + + rc = ngx_http_lua_pipe_close_stdin(pipe, 0); + if (rc != NGX_OK) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "pipe busy writing") + - errbuf; + return NGX_ERROR; + } + + return NGX_OK; +} + + +int +ngx_http_lua_ffi_pipe_proc_shutdown_stdout(ngx_http_lua_ffi_pipe_proc_t *proc, + u_char *errbuf, size_t *errbuf_size) +{ + ngx_int_t rc; + ngx_http_lua_pipe_t *pipe; + + pipe = proc->pipe; + if (pipe == NULL || pipe->closed) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "closed") - errbuf; + return NGX_ERROR; + } + + rc = ngx_http_lua_pipe_close_stdout(pipe, 0); + if (rc != NGX_OK) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "pipe busy reading") + - errbuf; + return NGX_ERROR; + } + + return NGX_OK; +} + + +int +ngx_http_lua_ffi_pipe_proc_shutdown_stderr(ngx_http_lua_ffi_pipe_proc_t *proc, + u_char *errbuf, size_t *errbuf_size) +{ + ngx_http_lua_pipe_t *pipe; + + pipe = proc->pipe; + if (pipe == NULL || pipe->closed) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "closed") - errbuf; + return NGX_ERROR; + } + + if (pipe->merge_stderr) { + /* stdout is used internally as stderr when merge_stderr is true */ + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "merged to stdout") + - errbuf; + return NGX_ERROR; + } + + if (ngx_http_lua_pipe_close_stderr(pipe, 0) != NGX_OK) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "pipe busy reading") + - errbuf; + return NGX_ERROR; + } + + return NGX_OK; +} + + +static void +ngx_http_lua_pipe_proc_finalize(ngx_http_lua_ffi_pipe_proc_t *proc, int forced) +{ + ngx_http_lua_pipe_t *pipe; + + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe finalize process:%p pid:%P forced:%d", proc, + proc->_pid, forced); + pipe = proc->pipe; + + if (pipe->node) { + ngx_rbtree_delete(&ngx_http_lua_pipe_rbtree, pipe->node); + pipe->node = NULL; + } + + pipe->dead = 1; + + ngx_http_lua_pipe_close_stdin(pipe, forced); + ngx_http_lua_pipe_close_stdout(pipe, forced); + + if (!pipe->merge_stderr) { + ngx_http_lua_pipe_close_stderr(pipe, forced); + } + + pipe->closed = 1; +} + + +void +ngx_http_lua_ffi_pipe_proc_destroy(ngx_http_lua_ffi_pipe_proc_t *proc) +{ + ngx_http_lua_pipe_t *pipe; + + pipe = proc->pipe; + if (pipe == NULL) { + return; + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe destroy process:%p pid:%P", proc, proc->_pid); + + if (!pipe->dead) { + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe kill process:%p pid:%P", proc, proc->_pid); + + if (kill(proc->_pid, SIGKILL) == -1) { + if (ngx_errno != ESRCH) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, + "lua pipe failed to kill process:%p pid:%P"); + } + } + } + + ngx_http_lua_pipe_proc_finalize(proc, 1); + ngx_destroy_pool(pipe->pool); + proc->pipe = NULL; +} + + +static ngx_int_t +ngx_http_lua_pipe_get_lua_ctx(ngx_http_request_t *r, + ngx_http_lua_ctx_t **ctx, u_char *errbuf, size_t *errbuf_size) +{ + int rc; + + *ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx == NULL) { + return NGX_HTTP_LUA_FFI_NO_REQ_CTX; + } + + rc = ngx_http_lua_ffi_check_context(*ctx, NGX_HTTP_LUA_CONTEXT_REWRITE + | NGX_HTTP_LUA_CONTEXT_ACCESS + | NGX_HTTP_LUA_CONTEXT_CONTENT + | NGX_HTTP_LUA_CONTEXT_TIMER + | NGX_HTTP_LUA_CONTEXT_SSL_CERT + | NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH, + errbuf, errbuf_size); + if (rc != NGX_OK) { + return NGX_HTTP_LUA_FFI_BAD_CONTEXT; + } + + return NGX_OK; +} + + +static void +ngx_http_lua_pipe_put_error(ngx_http_lua_pipe_ctx_t *pipe_ctx, u_char *errbuf, + size_t *errbuf_size) +{ + switch (pipe_ctx->err_type) { + + case PIPE_ERR_CLOSED: + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "closed") - errbuf; + break; + + case PIPE_ERR_SYSCALL: + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "%s", + strerror(pipe_ctx->pipe_errno)) + - errbuf; + break; + + case PIPE_ERR_NOMEM: + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "no memory") + - errbuf; + break; + + case PIPE_ERR_TIMEOUT: + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "timeout") + - errbuf; + break; + + case PIPE_ERR_ADD_READ_EV: + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, + "failed to add read event") + - errbuf; + break; + + case PIPE_ERR_ADD_WRITE_EV: + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, + "failed to add write event") + - errbuf; + break; + + default: + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, + "unexpected err type: %d", pipe_ctx->err_type); + ngx_http_lua_assert(NULL); + } +} + + +static void +ngx_http_lua_pipe_put_data(ngx_http_lua_pipe_t *pipe, + ngx_http_lua_pipe_ctx_t *pipe_ctx, u_char **buf, size_t *buf_size) +{ + size_t size = 0; + size_t chunk_size; + size_t nbufs; + u_char *p; + ngx_buf_t *b; + ngx_chain_t *cl; + ngx_chain_t **ll; + + nbufs = 0; + ll = NULL; + + for (cl = pipe_ctx->bufs_in; cl; cl = cl->next) { + b = cl->buf; + chunk_size = b->last - b->pos; + + if (cl->next) { + ll = &cl->next; + } + + size += chunk_size; + + nbufs++; + } + + if (*buf_size < size) { + *buf = NULL; + *buf_size = size; + + return; + } + + *buf_size = size; + + p = *buf; + for (cl = pipe_ctx->bufs_in; cl; cl = cl->next) { + b = cl->buf; + chunk_size = b->last - b->pos; + p = ngx_cpymem(p, b->pos, chunk_size); + } + + if (nbufs > 1 && ll) { + *ll = pipe->free_bufs; + pipe->free_bufs = pipe_ctx->bufs_in; + pipe_ctx->bufs_in = pipe_ctx->buf_in; + } + + if (pipe_ctx->buffer.pos == pipe_ctx->buffer.last) { + pipe_ctx->buffer.pos = pipe_ctx->buffer.start; + pipe_ctx->buffer.last = pipe_ctx->buffer.start; + } + + if (pipe_ctx->bufs_in) { + pipe_ctx->buf_in->buf->last = pipe_ctx->buffer.pos; + pipe_ctx->buf_in->buf->pos = pipe_ctx->buffer.pos; + } +} + + +static ngx_int_t +ngx_http_lua_pipe_add_input_buffer(ngx_http_lua_pipe_t *pipe, + ngx_http_lua_pipe_ctx_t *pipe_ctx) +{ + ngx_chain_t *cl; + + cl = ngx_http_lua_chain_get_free_buf(ngx_cycle->log, pipe->pool, + &pipe->free_bufs, + pipe->buffer_size); + + if (cl == NULL) { + pipe_ctx->err_type = PIPE_ERR_NOMEM; + return NGX_ERROR; + } + + pipe_ctx->buf_in->next = cl; + pipe_ctx->buf_in = cl; + pipe_ctx->buffer = *cl->buf; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_lua_pipe_read_all(void *data, ssize_t bytes) +{ + ngx_http_lua_pipe_ctx_t *pipe_ctx = data; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, "lua pipe read all"); + return ngx_http_lua_read_all(&pipe_ctx->buffer, pipe_ctx->buf_in, bytes, + ngx_cycle->log); +} + + +static ngx_int_t +ngx_http_lua_pipe_read_bytes(void *data, ssize_t bytes) +{ + ngx_int_t rc; + ngx_http_lua_pipe_ctx_t *pipe_ctx = data; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe read bytes %z", bytes); + + rc = ngx_http_lua_read_bytes(&pipe_ctx->buffer, pipe_ctx->buf_in, + &pipe_ctx->rest, bytes, ngx_cycle->log); + if (rc == NGX_ERROR) { + pipe_ctx->err_type = PIPE_ERR_CLOSED; + return NGX_ERROR; + } + + return rc; +} + + +static ngx_int_t +ngx_http_lua_pipe_read_line(void *data, ssize_t bytes) +{ + ngx_int_t rc; + ngx_http_lua_pipe_ctx_t *pipe_ctx = data; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe read line"); + rc = ngx_http_lua_read_line(&pipe_ctx->buffer, pipe_ctx->buf_in, bytes, + ngx_cycle->log); + if (rc == NGX_ERROR) { + pipe_ctx->err_type = PIPE_ERR_CLOSED; + return NGX_ERROR; + } + + return rc; +} + + +static ngx_int_t +ngx_http_lua_pipe_read_any(void *data, ssize_t bytes) +{ + ngx_int_t rc; + ngx_http_lua_pipe_ctx_t *pipe_ctx = data; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, "lua pipe read any"); + rc = ngx_http_lua_read_any(&pipe_ctx->buffer, pipe_ctx->buf_in, + &pipe_ctx->rest, bytes, ngx_cycle->log); + if (rc == NGX_ERROR) { + pipe_ctx->err_type = PIPE_ERR_CLOSED; + return NGX_ERROR; + } + + return rc; +} + + +static ngx_int_t +ngx_http_lua_pipe_read(ngx_http_lua_pipe_t *pipe, + ngx_http_lua_pipe_ctx_t *pipe_ctx) +{ + int rc; + int read; + size_t size; + ssize_t n; + ngx_buf_t *b; + ngx_event_t *rev; + ngx_connection_t *c; + + c = pipe_ctx->c; + rev = c->read; + b = &pipe_ctx->buffer; + read = 0; + + for ( ;; ) { + size = b->last - b->pos; + + if (size || pipe_ctx->eof) { + rc = pipe_ctx->input_filter(pipe_ctx->input_filter_ctx, size); + if (rc == NGX_ERROR) { + return NGX_ERROR; + } + + if (rc == NGX_OK) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe read done pipe:%p", pipe_ctx); + return NGX_OK; + } + + /* rc == NGX_AGAIN */ + continue; + } + + if (read && !rev->ready) { + break; + } + + size = b->end - b->last; + + if (size == 0) { + rc = ngx_http_lua_pipe_add_input_buffer(pipe, pipe_ctx); + if (rc == NGX_ERROR) { + return NGX_ERROR; + } + + b = &pipe_ctx->buffer; + size = (size_t) (b->end - b->last); + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe try to read data %uz pipe:%p", + size, pipe_ctx); + + n = c->recv(c, b->last, size); + read = 1; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe read data returned %z pipe:%p", n, pipe_ctx); + + if (n == NGX_AGAIN) { + break; + } + + if (n == 0) { + pipe_ctx->eof = 1; + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe closed pipe:%p", pipe_ctx); + continue; + } + + if (n == NGX_ERROR) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, ngx_errno, + "lua pipe read data error pipe:%p", pipe_ctx); + + pipe_ctx->err_type = PIPE_ERR_SYSCALL; + pipe_ctx->pipe_errno = ngx_errno; + return NGX_ERROR; + } + + b->last += n; + } + + return NGX_AGAIN; +} + + +static ngx_int_t +ngx_http_lua_pipe_init_ctx(ngx_http_lua_pipe_ctx_t **pipe_ctx_pt, int fd, + ngx_pool_t *pool, u_char *errbuf, size_t *errbuf_size) +{ + ngx_connection_t *c; + + if (fd == -1) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "closed") - errbuf; + return NGX_ERROR; + } + + *pipe_ctx_pt = ngx_pcalloc(pool, sizeof(ngx_http_lua_pipe_ctx_t)); + if (*pipe_ctx_pt == NULL) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "no memory") + - errbuf; + return NGX_ERROR; + } + + c = ngx_get_connection(fd, ngx_cycle->log); + if (c == NULL) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "no connection") + - errbuf; + return NGX_ERROR; + } + + c->log = ngx_cycle->log; + c->recv = ngx_http_lua_pipe_fd_read; + c->read->handler = ngx_http_lua_pipe_dummy_event_handler; + c->read->log = c->log; + +#ifdef HAVE_SOCKET_CLOEXEC_PATCH + c->read->skip_socket_leak_check = 1; +#endif + + c->send = ngx_http_lua_pipe_fd_write; + c->write->handler = ngx_http_lua_pipe_dummy_event_handler; + c->write->log = c->log; + (*pipe_ctx_pt)->c = c; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe init pipe ctx:%p fd:*%d", *pipe_ctx_pt, fd); + + return NGX_OK; +} + + +int +ngx_http_lua_ffi_pipe_proc_read(ngx_http_request_t *r, + ngx_http_lua_ffi_pipe_proc_t *proc, int from_stderr, int reader_type, + size_t length, u_char **buf, size_t *buf_size, u_char *errbuf, + size_t *errbuf_size) +{ + int rc; + ngx_msec_t timeout; + ngx_event_t *rev; + ngx_connection_t *c; + ngx_http_lua_ctx_t *ctx; + ngx_http_lua_pipe_t *pipe; + ngx_http_lua_co_ctx_t *wait_co_ctx; + ngx_http_lua_pipe_ctx_t *pipe_ctx; + + rc = ngx_http_lua_pipe_get_lua_ctx(r, &ctx, errbuf, errbuf_size); + if (rc != NGX_OK) { + return rc; + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua pipe read process:%p pid:%P", proc, proc->_pid); + + pipe = proc->pipe; + if (pipe == NULL || pipe->closed) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "closed") - errbuf; + return NGX_ERROR; + } + + if (pipe->merge_stderr && from_stderr) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "merged to stdout") + - errbuf; + return NGX_ERROR; + } + + if (from_stderr) { + if (pipe->stderr_ctx == NULL) { + if (ngx_http_lua_pipe_init_ctx(&pipe->stderr_ctx, pipe->stderr_fd, + pipe->pool, errbuf, + errbuf_size) + != NGX_OK) + { + return NGX_ERROR; + } + + } else { + pipe->stderr_ctx->err_type = 0; + } + + pipe_ctx = pipe->stderr_ctx; + + } else { + if (pipe->stdout_ctx == NULL) { + if (ngx_http_lua_pipe_init_ctx(&pipe->stdout_ctx, pipe->stdout_fd, + pipe->pool, errbuf, + errbuf_size) + != NGX_OK) + { + return NGX_ERROR; + } + + } else { + pipe->stdout_ctx->err_type = 0; + } + + pipe_ctx = pipe->stdout_ctx; + } + + c = pipe_ctx->c; + if (c == NULL) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "closed") - errbuf; + return NGX_ERROR; + } + + rev = c->read; + if (rev->handler != ngx_http_lua_pipe_dummy_event_handler) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "pipe busy reading") + - errbuf; + return NGX_ERROR; + } + + pipe_ctx->input_filter_ctx = pipe_ctx; + + switch (reader_type) { + + case PIPE_READ_ALL: + pipe_ctx->input_filter = ngx_http_lua_pipe_read_all; + break; + + case PIPE_READ_BYTES: + pipe_ctx->input_filter = ngx_http_lua_pipe_read_bytes; + break; + + case PIPE_READ_LINE: + pipe_ctx->input_filter = ngx_http_lua_pipe_read_line; + break; + + case PIPE_READ_ANY: + pipe_ctx->input_filter = ngx_http_lua_pipe_read_any; + break; + + default: + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, + "unexpected reader_type: %d", reader_type); + ngx_http_lua_assert(NULL); + } + + pipe_ctx->rest = length; + + if (pipe_ctx->bufs_in == NULL) { + pipe_ctx->bufs_in = + ngx_http_lua_chain_get_free_buf(ngx_cycle->log, pipe->pool, + &pipe->free_bufs, + pipe->buffer_size); + + if (pipe_ctx->bufs_in == NULL) { + pipe_ctx->err_type = PIPE_ERR_NOMEM; + goto error; + } + + pipe_ctx->buf_in = pipe_ctx->bufs_in; + pipe_ctx->buffer = *pipe_ctx->buf_in->buf; + } + + rc = ngx_http_lua_pipe_read(pipe, pipe_ctx); + if (rc == NGX_ERROR) { + goto error; + } + + if (rc == NGX_OK) { + ngx_http_lua_pipe_put_data(pipe, pipe_ctx, buf, buf_size); + return NGX_OK; + } + + /* rc == NGX_AGAIN */ + wait_co_ctx = ctx->cur_co_ctx; + + c->data = wait_co_ctx; + if (ngx_handle_read_event(rev, 0) != NGX_OK) { + pipe_ctx->err_type = PIPE_ERR_ADD_READ_EV; + goto error; + } + + wait_co_ctx->data = proc; + + if (from_stderr) { + rev->handler = ngx_http_lua_pipe_resume_read_stderr_handler; + wait_co_ctx->cleanup = ngx_http_lua_pipe_proc_read_stderr_cleanup; + timeout = proc->stderr_read_timeout; + + } else { + rev->handler = ngx_http_lua_pipe_resume_read_stdout_handler; + wait_co_ctx->cleanup = ngx_http_lua_pipe_proc_read_stdout_cleanup; + timeout = proc->stdout_read_timeout; + } + + if (timeout > 0) { + ngx_add_timer(rev, timeout); + ngx_log_debug5(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua pipe add timer for reading: %d(ms) process:%p " + "pid:%P pipe:%p ev:%p", timeout, proc, proc->_pid, pipe, + rev); + } + + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua pipe read yielding process:%p pid:%P pipe:%p", proc, + proc->_pid, pipe); + + return NGX_AGAIN; + +error: + + if (pipe_ctx->bufs_in) { + ngx_http_lua_pipe_put_data(pipe, pipe_ctx, buf, buf_size); + ngx_http_lua_pipe_put_error(pipe_ctx, errbuf, errbuf_size); + return NGX_DECLINED; + } + + ngx_http_lua_pipe_put_error(pipe_ctx, errbuf, errbuf_size); + + return NGX_ERROR; +} + + +/* + * ngx_http_lua_ffi_pipe_get_read_result should only be called just after + * ngx_http_lua_ffi_pipe_proc_read, so we omit most of the sanity check already + * done in ngx_http_lua_ffi_pipe_proc_read. + */ +int +ngx_http_lua_ffi_pipe_get_read_result(ngx_http_request_t *r, + ngx_http_lua_ffi_pipe_proc_t *proc, int from_stderr, u_char **buf, + size_t *buf_size, u_char *errbuf, size_t *errbuf_size) +{ + ngx_http_lua_pipe_t *pipe; + ngx_http_lua_pipe_ctx_t *pipe_ctx; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua pipe get read result process:%p pid:%P", proc, + proc->_pid); + + pipe = proc->pipe; + pipe_ctx = from_stderr ? pipe->stderr_ctx : pipe->stdout_ctx; + + if (!pipe_ctx->err_type) { + ngx_http_lua_pipe_put_data(pipe, pipe_ctx, buf, buf_size); + return NGX_OK; + } + + if (pipe_ctx->bufs_in) { + ngx_http_lua_pipe_put_data(pipe, pipe_ctx, buf, buf_size); + ngx_http_lua_pipe_put_error(pipe_ctx, errbuf, errbuf_size); + return NGX_DECLINED; + } + + ngx_http_lua_pipe_put_error(pipe_ctx, errbuf, errbuf_size); + + return NGX_ERROR; +} + + +static ngx_int_t +ngx_http_lua_pipe_write(ngx_http_lua_pipe_t *pipe, + ngx_http_lua_pipe_ctx_t *pipe_ctx) +{ + size_t size; + ngx_int_t n; + ngx_buf_t *b; + ngx_connection_t *c; + + c = pipe_ctx->c; + b = pipe_ctx->buf_in->buf; + + for ( ;; ) { + size = b->last - b->pos; + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe try to write data %uz pipe:%p", size, + pipe_ctx); + + n = c->send(c, b->pos, size); + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe write returned %i pipe:%p", n, pipe_ctx); + + if (n >= 0) { + b->pos += n; + + if (b->pos == b->last) { + b->pos = b->start; + b->last = b->start; + + if (!pipe->free_bufs) { + pipe->free_bufs = pipe_ctx->buf_in; + + } else { + pipe->free_bufs->next = pipe_ctx->buf_in; + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe write done pipe:%p", pipe_ctx); + return NGX_OK; + } + + continue; + } + + /* NGX_ERROR || NGX_AGAIN */ + break; + } + + if (n == NGX_ERROR) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, ngx_errno, + "lua pipe write data error pipe:%p", pipe_ctx); + + if (ngx_errno == NGX_EPIPE) { + pipe_ctx->err_type = PIPE_ERR_CLOSED; + + } else { + pipe_ctx->err_type = PIPE_ERR_SYSCALL; + pipe_ctx->pipe_errno = ngx_errno; + } + + return NGX_ERROR; + } + + return NGX_AGAIN; +} + + +ssize_t +ngx_http_lua_ffi_pipe_proc_write(ngx_http_request_t *r, + ngx_http_lua_ffi_pipe_proc_t *proc, const u_char *data, size_t len, + u_char *errbuf, size_t *errbuf_size) +{ + int rc; + ngx_buf_t *b; + ngx_msec_t timeout; + ngx_chain_t *cl; + ngx_event_t *wev; + ngx_http_lua_ctx_t *ctx; + ngx_http_lua_pipe_t *pipe; + ngx_http_lua_co_ctx_t *wait_co_ctx; + ngx_http_lua_pipe_ctx_t *pipe_ctx; + + rc = ngx_http_lua_pipe_get_lua_ctx(r, &ctx, errbuf, errbuf_size); + if (rc != NGX_OK) { + return rc; + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua pipe write process:%p pid:%P", proc, proc->_pid); + + pipe = proc->pipe; + if (pipe == NULL || pipe->closed) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "closed") - errbuf; + return NGX_ERROR; + } + + if (pipe->stdin_ctx == NULL) { + if (ngx_http_lua_pipe_init_ctx(&pipe->stdin_ctx, pipe->stdin_fd, + pipe->pool, errbuf, + errbuf_size) + != NGX_OK) + { + return NGX_ERROR; + } + + } else { + pipe->stdin_ctx->err_type = 0; + } + + pipe_ctx = pipe->stdin_ctx; + if (pipe_ctx->c == NULL) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "closed") - errbuf; + return NGX_ERROR; + } + + wev = pipe_ctx->c->write; + if (wev->handler != ngx_http_lua_pipe_dummy_event_handler) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "pipe busy writing") + - errbuf; + return NGX_ERROR; + } + + pipe_ctx->rest = len; + + cl = ngx_http_lua_chain_get_free_buf(ngx_cycle->log, pipe->pool, + &pipe->free_bufs, len); + if (cl == NULL) { + pipe_ctx->err_type = PIPE_ERR_NOMEM; + goto error; + } + + pipe_ctx->buf_in = cl; + b = pipe_ctx->buf_in->buf; + b->last = ngx_copy(b->last, data, len); + + rc = ngx_http_lua_pipe_write(pipe, pipe_ctx); + if (rc == NGX_ERROR) { + goto error; + } + + if (rc == NGX_OK) { + return len; + } + + /* rc == NGX_AGAIN */ + wait_co_ctx = ctx->cur_co_ctx; + pipe_ctx->c->data = wait_co_ctx; + + wev->handler = ngx_http_lua_pipe_resume_write_handler; + if (ngx_handle_write_event(wev, 0) != NGX_OK) { + pipe_ctx->err_type = PIPE_ERR_ADD_WRITE_EV; + goto error; + } + + wait_co_ctx->data = proc; + wait_co_ctx->cleanup = ngx_http_lua_pipe_proc_write_cleanup; + timeout = proc->write_timeout; + + if (timeout > 0) { + ngx_add_timer(wev, timeout); + ngx_log_debug5(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua pipe add timer for writing: %d(ms) process:%p " + "pid:%P pipe:%p ev:%p", timeout, proc, proc->_pid, pipe, + wev); + } + + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua pipe write yielding process:%p pid:%P pipe:%p", proc, + proc->_pid, pipe); + + return NGX_AGAIN; + +error: + + ngx_http_lua_pipe_put_error(pipe_ctx, errbuf, errbuf_size); + return NGX_ERROR; +} + + +/* + * ngx_http_lua_ffi_pipe_get_write_result should only be called just after + * ngx_http_lua_ffi_pipe_proc_write, so we omit most of the sanity check + * already done in ngx_http_lua_ffi_pipe_proc_write. + */ +ssize_t +ngx_http_lua_ffi_pipe_get_write_result(ngx_http_request_t *r, + ngx_http_lua_ffi_pipe_proc_t *proc, u_char *errbuf, size_t *errbuf_size) +{ + ngx_http_lua_pipe_t *pipe; + ngx_http_lua_pipe_ctx_t *pipe_ctx; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua pipe get write result process:%p pid:%P", proc, + proc->_pid); + + pipe = proc->pipe; + pipe_ctx = pipe->stdin_ctx; + + if (pipe_ctx->err_type) { + ngx_http_lua_pipe_put_error(pipe_ctx, errbuf, errbuf_size); + return NGX_ERROR; + } + + return pipe_ctx->rest; +} + + +int +ngx_http_lua_ffi_pipe_proc_wait(ngx_http_request_t *r, + ngx_http_lua_ffi_pipe_proc_t *proc, char **reason, int *status, + u_char *errbuf, size_t *errbuf_size) +{ + int rc; + ngx_rbtree_node_t *node; + ngx_http_lua_ctx_t *ctx; + ngx_http_lua_pipe_t *pipe; + ngx_http_lua_co_ctx_t *wait_co_ctx; + ngx_http_lua_pipe_node_t *pipe_node; + + rc = ngx_http_lua_pipe_get_lua_ctx(r, &ctx, errbuf, errbuf_size); + if (rc != NGX_OK) { + return rc; + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua pipe wait process:%p pid:%P", proc, proc->_pid); + + pipe = proc->pipe; + if (pipe == NULL || pipe->closed) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "exited") - errbuf; + return NGX_ERROR; + } + + node = pipe->node; + pipe_node = (ngx_http_lua_pipe_node_t *) &node->color; + if (pipe_node->wait_co_ctx) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "pipe busy waiting") + - errbuf; + return NGX_ERROR; + } + + if (pipe_node->reason_code == REASON_RUNNING_CODE) { + wait_co_ctx = ctx->cur_co_ctx; + wait_co_ctx->data = proc; + ngx_memzero(&wait_co_ctx->sleep, sizeof(ngx_event_t)); + wait_co_ctx->sleep.handler = ngx_http_lua_pipe_resume_wait_handler; + wait_co_ctx->sleep.data = wait_co_ctx; + wait_co_ctx->sleep.log = r->connection->log; + wait_co_ctx->cleanup = ngx_http_lua_pipe_proc_wait_cleanup; + + pipe_node->wait_co_ctx = wait_co_ctx; + + if (proc->wait_timeout > 0) { + ngx_add_timer(&wait_co_ctx->sleep, proc->wait_timeout); + ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua pipe add timer for waiting: %d(ms) process:%p " + "pid:%P ev:%p", proc->wait_timeout, proc, + proc->_pid, &wait_co_ctx->sleep); + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua pipe wait yielding process:%p pid:%P", proc, + proc->_pid); + + return NGX_AGAIN; + } + + *status = pipe_node->status; + + switch (pipe_node->reason_code) { + + case REASON_EXIT_CODE: + *reason = REASON_EXIT; + break; + + case REASON_SIGNAL_CODE: + *reason = REASON_SIGNAL; + break; + + default: + *reason = REASON_UNKNOWN; + } + + ngx_http_lua_pipe_proc_finalize(proc, 0); + + if (*status == 0) { + return NGX_OK; + } + + return NGX_DECLINED; +} + + +int +ngx_http_lua_ffi_pipe_proc_kill(ngx_http_lua_ffi_pipe_proc_t *proc, int signal, + u_char *errbuf, size_t *errbuf_size) +{ + ngx_pid_t pid; + ngx_http_lua_pipe_t *pipe; + + pipe = proc->pipe; + + if (pipe == NULL || pipe->dead) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "exited") - errbuf; + return NGX_ERROR; + } + + pid = proc->_pid; + + if (kill(pid, signal) == -1) { + switch (ngx_errno) { + case EINVAL: + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "invalid signal") + - errbuf; + break; + + case ESRCH: + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "exited") + - errbuf; + break; + + default: + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "%s", + strerror(ngx_errno)) + - errbuf; + } + + return NGX_ERROR; + } + + return NGX_OK; +} + + +static int +ngx_http_lua_pipe_read_stdout_retval(ngx_http_lua_ffi_pipe_proc_t *proc, + lua_State *L) +{ + return ngx_http_lua_pipe_read_retval_helper(proc, L, 0); +} + + +static int +ngx_http_lua_pipe_read_stderr_retval(ngx_http_lua_ffi_pipe_proc_t *proc, + lua_State *L) +{ + return ngx_http_lua_pipe_read_retval_helper(proc, L, 1); +} + + +static int +ngx_http_lua_pipe_read_retval_helper(ngx_http_lua_ffi_pipe_proc_t *proc, + lua_State *L, int from_stderr) +{ + int rc; + ngx_msec_t timeout; + ngx_event_t *rev; + ngx_http_lua_pipe_t *pipe; + ngx_http_lua_pipe_ctx_t *pipe_ctx; + + pipe = proc->pipe; + if (from_stderr) { + pipe_ctx = pipe->stderr_ctx; + + } else { + pipe_ctx = pipe->stdout_ctx; + } + + if (pipe->timeout) { + pipe->timeout = 0; + pipe_ctx->err_type = PIPE_ERR_TIMEOUT; + return 0; + } + + rc = ngx_http_lua_pipe_read(pipe, pipe_ctx); + if (rc != NGX_AGAIN) { + return 0; + } + + rev = pipe_ctx->c->read; + + if (from_stderr) { + rev->handler = ngx_http_lua_pipe_resume_read_stderr_handler; + timeout = proc->stderr_read_timeout; + + } else { + rev->handler = ngx_http_lua_pipe_resume_read_stdout_handler; + timeout = proc->stdout_read_timeout; + } + + if (timeout > 0) { + ngx_add_timer(rev, timeout); + ngx_log_debug5(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe add timer for reading: %d(ms) proc:%p " + "pid:%P pipe:%p ev:%p", timeout, proc, proc->_pid, pipe, + rev); + } + + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe read yielding process:%p pid:%P pipe:%p", proc, + proc->_pid, pipe); + + return NGX_AGAIN; +} + + +static int +ngx_http_lua_pipe_write_retval(ngx_http_lua_ffi_pipe_proc_t *proc, + lua_State *L) +{ + int rc; + ngx_msec_t timeout; + ngx_event_t *wev; + ngx_http_lua_pipe_t *pipe; + ngx_http_lua_pipe_ctx_t *pipe_ctx; + + pipe = proc->pipe; + pipe_ctx = pipe->stdin_ctx; + + if (pipe->timeout) { + pipe->timeout = 0; + pipe_ctx->err_type = PIPE_ERR_TIMEOUT; + return 0; + } + + rc = ngx_http_lua_pipe_write(pipe, pipe_ctx); + if (rc != NGX_AGAIN) { + return 0; + } + + wev = pipe_ctx->c->write; + wev->handler = ngx_http_lua_pipe_resume_write_handler; + timeout = proc->write_timeout; + + if (timeout > 0) { + ngx_add_timer(wev, timeout); + ngx_log_debug5(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe add timer for writing: %d(ms) proc:%p " + "pid:%P pipe:%p ev:%p", timeout, proc, proc->_pid, pipe, + wev); + } + + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe write yielding process:%p pid:%P pipe:%p", proc, + proc->_pid, pipe); + + return NGX_AGAIN; +} + + +static int +ngx_http_lua_pipe_wait_retval(ngx_http_lua_ffi_pipe_proc_t *proc, lua_State *L) +{ + int nret; + ngx_rbtree_node_t *node; + ngx_http_lua_pipe_t *pipe; + ngx_http_lua_pipe_node_t *pipe_node; + + pipe = proc->pipe; + node = pipe->node; + pipe_node = (ngx_http_lua_pipe_node_t *) &node->color; + pipe_node->wait_co_ctx = NULL; + + if (pipe->timeout) { + pipe->timeout = 0; + lua_pushnil(L); + lua_pushliteral(L, "timeout"); + return 2; + } + + ngx_http_lua_pipe_proc_finalize(pipe_node->proc, 0); + + if (pipe_node->status == 0) { + lua_pushboolean(L, 1); + lua_pushliteral(L, REASON_EXIT); + lua_pushinteger(L, pipe_node->status); + nret = 3; + + } else { + lua_pushboolean(L, 0); + + switch (pipe_node->reason_code) { + + case REASON_EXIT_CODE: + lua_pushliteral(L, REASON_EXIT); + break; + + case REASON_SIGNAL_CODE: + lua_pushliteral(L, REASON_SIGNAL); + break; + + default: + lua_pushliteral(L, REASON_UNKNOWN); + } + + lua_pushinteger(L, pipe_node->status); + nret = 3; + } + + return nret; +} + + +static void +ngx_http_lua_pipe_resume_helper(ngx_event_t *ev, + ngx_http_lua_co_ctx_t *wait_co_ctx) +{ + ngx_connection_t *c; + ngx_http_request_t *r; + ngx_http_lua_ctx_t *ctx; + ngx_http_lua_pipe_t *pipe; + ngx_http_lua_ffi_pipe_proc_t *proc; + + if (ev->timedout) { + proc = wait_co_ctx->data; + pipe = proc->pipe; + pipe->timeout = 1; + ev->timedout = 0; + } + + ngx_http_lua_pipe_clear_event(ev); + + r = ngx_http_lua_get_req(wait_co_ctx->co); + c = r->connection; + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + ngx_http_lua_assert(ctx != NULL); + + ctx->cur_co_ctx = wait_co_ctx; + + if (ctx->entered_content_phase) { + (void) ngx_http_lua_pipe_resume(r); + + } else { + ctx->resume_handler = ngx_http_lua_pipe_resume; + ngx_http_core_run_phases(r); + } + + ngx_http_run_posted_requests(c); +} + + +static void +ngx_http_lua_pipe_resume_read_stdout_handler(ngx_event_t *ev) +{ + ngx_connection_t *c = ev->data; + ngx_http_lua_co_ctx_t *wait_co_ctx; + ngx_http_lua_pipe_t *pipe; + ngx_http_lua_ffi_pipe_proc_t *proc; + + wait_co_ctx = c->data; + proc = wait_co_ctx->data; + pipe = proc->pipe; + pipe->retval_handler = ngx_http_lua_pipe_read_stdout_retval; + ngx_http_lua_pipe_resume_helper(ev, wait_co_ctx); +} + + +static void +ngx_http_lua_pipe_resume_read_stderr_handler(ngx_event_t *ev) +{ + ngx_connection_t *c = ev->data; + ngx_http_lua_co_ctx_t *wait_co_ctx; + ngx_http_lua_pipe_t *pipe; + ngx_http_lua_ffi_pipe_proc_t *proc; + + wait_co_ctx = c->data; + proc = wait_co_ctx->data; + pipe = proc->pipe; + pipe->retval_handler = ngx_http_lua_pipe_read_stderr_retval; + ngx_http_lua_pipe_resume_helper(ev, wait_co_ctx); +} + + +static void +ngx_http_lua_pipe_resume_write_handler(ngx_event_t *ev) +{ + ngx_connection_t *c = ev->data; + ngx_http_lua_co_ctx_t *wait_co_ctx; + ngx_http_lua_pipe_t *pipe; + ngx_http_lua_ffi_pipe_proc_t *proc; + + wait_co_ctx = c->data; + proc = wait_co_ctx->data; + pipe = proc->pipe; + pipe->retval_handler = ngx_http_lua_pipe_write_retval; + ngx_http_lua_pipe_resume_helper(ev, wait_co_ctx); +} + + +static void +ngx_http_lua_pipe_resume_wait_handler(ngx_event_t *ev) +{ + ngx_http_lua_co_ctx_t *wait_co_ctx = ev->data; + ngx_http_lua_pipe_t *pipe; + ngx_http_lua_ffi_pipe_proc_t *proc; + + proc = wait_co_ctx->data; + pipe = proc->pipe; + pipe->retval_handler = ngx_http_lua_pipe_wait_retval; + ngx_http_lua_pipe_resume_helper(ev, wait_co_ctx); +} + + +static ngx_int_t +ngx_http_lua_pipe_resume(ngx_http_request_t *r) +{ + int nret; + lua_State *vm; + ngx_int_t rc; + ngx_uint_t nreqs; + ngx_connection_t *c; + ngx_http_lua_ctx_t *ctx; + ngx_http_lua_pipe_t *pipe; + ngx_http_lua_ffi_pipe_proc_t *proc; + + 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; + ctx->cur_co_ctx->cleanup = NULL; + + proc = ctx->cur_co_ctx->data; + pipe = proc->pipe; + nret = pipe->retval_handler(proc, ctx->cur_co_ctx->co); + if (nret == NGX_AGAIN) { + return NGX_DONE; + } + + c = r->connection; + vm = ngx_http_lua_get_lua_vm(r, ctx); + nreqs = c->requests; + + rc = ngx_http_lua_run_thread(vm, r, ctx, nret); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua run thread returned %d", rc); + + if (rc == NGX_AGAIN) { + return ngx_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); + } + + /* rc == NGX_ERROR || rc >= NGX_OK */ + + if (ctx->entered_content_phase) { + ngx_http_lua_finalize_request(r, rc); + return NGX_DONE; + } + + return rc; +} + + +static void +ngx_http_lua_pipe_dummy_event_handler(ngx_event_t *ev) +{ + /* do nothing */ +} + + +static void +ngx_http_lua_pipe_clear_event(ngx_event_t *ev) +{ + ev->handler = ngx_http_lua_pipe_dummy_event_handler; + + if (ev->timer_set) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ev->log, 0, + "lua pipe del timer for ev:%p", ev); + ngx_del_timer(ev); + } + + if (ev->posted) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ev->log, 0, + "lua pipe del posted event for ev:%p", ev); + ngx_delete_posted_event(ev); + } +} + + +static void +ngx_http_lua_pipe_proc_read_stdout_cleanup(void *data) +{ + ngx_event_t *rev; + ngx_connection_t *c; + ngx_http_lua_co_ctx_t *wait_co_ctx = data; + ngx_http_lua_ffi_pipe_proc_t *proc; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe proc read stdout cleanup"); + + proc = wait_co_ctx->data; + c = proc->pipe->stdout_ctx->c; + if (c) { + rev = c->read; + ngx_http_lua_pipe_clear_event(rev); + } + + wait_co_ctx->cleanup = NULL; +} + + +static void +ngx_http_lua_pipe_proc_read_stderr_cleanup(void *data) +{ + ngx_event_t *rev; + ngx_connection_t *c; + ngx_http_lua_co_ctx_t *wait_co_ctx = data; + ngx_http_lua_ffi_pipe_proc_t *proc; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe proc read stderr cleanup"); + + proc = wait_co_ctx->data; + c = proc->pipe->stderr_ctx->c; + if (c) { + rev = c->read; + ngx_http_lua_pipe_clear_event(rev); + } + + wait_co_ctx->cleanup = NULL; +} + + +static void +ngx_http_lua_pipe_proc_write_cleanup(void *data) +{ + ngx_event_t *wev; + ngx_connection_t *c; + ngx_http_lua_co_ctx_t *wait_co_ctx = data; + ngx_http_lua_ffi_pipe_proc_t *proc; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe proc write cleanup"); + + proc = wait_co_ctx->data; + c = proc->pipe->stdin_ctx->c; + if (c) { + wev = c->write; + ngx_http_lua_pipe_clear_event(wev); + } + + wait_co_ctx->cleanup = NULL; +} + + +static void +ngx_http_lua_pipe_proc_wait_cleanup(void *data) +{ + ngx_rbtree_node_t *node; + ngx_http_lua_co_ctx_t *wait_co_ctx = data; + ngx_http_lua_pipe_node_t *pipe_node; + ngx_http_lua_ffi_pipe_proc_t *proc; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe proc wait cleanup"); + + proc = wait_co_ctx->data; + node = proc->pipe->node; + pipe_node = (ngx_http_lua_pipe_node_t *) &node->color; + pipe_node->wait_co_ctx = NULL; + + ngx_http_lua_pipe_clear_event(&wait_co_ctx->sleep); + + wait_co_ctx->cleanup = NULL; +} + + +#endif /* HAVE_NGX_LUA_PIPE */ + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_pipe.h b/debian/modules/http-lua/src/ngx_http_lua_pipe.h new file mode 100644 index 0000000..b5cea89 --- /dev/null +++ b/debian/modules/http-lua/src/ngx_http_lua_pipe.h @@ -0,0 +1,95 @@ + +/* + * Copyright (C) by OpenResty Inc. + */ + + +#ifndef _NGX_HTTP_LUA_PIPE_H_INCLUDED_ +#define _NGX_HTTP_LUA_PIPE_H_INCLUDED_ + + +#include "ngx_http_lua_common.h" + + +typedef ngx_int_t (*ngx_http_lua_pipe_input_filter)(void *data, ssize_t bytes); + + +typedef struct { + ngx_connection_t *c; + ngx_http_lua_pipe_input_filter input_filter; + void *input_filter_ctx; + size_t rest; + ngx_chain_t *buf_in; + ngx_chain_t *bufs_in; + ngx_buf_t buffer; + ngx_err_t pipe_errno; + unsigned err_type:16; + unsigned eof:1; +} ngx_http_lua_pipe_ctx_t; + + +typedef struct ngx_http_lua_pipe_s ngx_http_lua_pipe_t; + + +typedef struct { + ngx_pid_t _pid; + ngx_msec_t write_timeout; + ngx_msec_t stdout_read_timeout; + ngx_msec_t stderr_read_timeout; + ngx_msec_t wait_timeout; + /* pipe hides the implementation from the Lua binding */ + ngx_http_lua_pipe_t *pipe; +} ngx_http_lua_ffi_pipe_proc_t; + + +typedef int (*ngx_http_lua_pipe_retval_handler)( + ngx_http_lua_ffi_pipe_proc_t *proc, lua_State *L); + + +struct ngx_http_lua_pipe_s { + ngx_pool_t *pool; + ngx_chain_t *free_bufs; + ngx_rbtree_node_t *node; + int stdin_fd; + int stdout_fd; + int stderr_fd; + ngx_http_lua_pipe_ctx_t *stdin_ctx; + ngx_http_lua_pipe_ctx_t *stdout_ctx; + ngx_http_lua_pipe_ctx_t *stderr_ctx; + ngx_http_lua_pipe_retval_handler retval_handler; + size_t buffer_size; + unsigned closed:1; + unsigned dead:1; + unsigned timeout:1; + unsigned merge_stderr:1; +}; + + +typedef struct { + u_char color; + u_char reason_code; + int status; + ngx_http_lua_co_ctx_t *wait_co_ctx; + ngx_http_lua_ffi_pipe_proc_t *proc; +} ngx_http_lua_pipe_node_t; + + +typedef struct { + int signo; + char *signame; +} ngx_http_lua_pipe_signal_t; + + +#if !(NGX_WIN32) && !defined(NGX_LUA_NO_FFI_API) \ + && defined(HAVE_SOCKET_CLOEXEC_PATCH) +#define HAVE_NGX_LUA_PIPE 1 + + +void ngx_http_lua_pipe_init(void); +ngx_int_t ngx_http_lua_pipe_add_signal_handler(ngx_cycle_t *cycle); +#endif + + +#endif /* _NGX_HTTP_LUA_PIPE_H_INCLUDED_ */ + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_regex.c b/debian/modules/http-lua/src/ngx_http_lua_regex.c index 843d1e4..8f3373b 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_regex.c +++ b/debian/modules/http-lua/src/ngx_http_lua_regex.c @@ -15,7 +15,6 @@ #include "ngx_http_lua_regex.h" #include "ngx_http_lua_pcrefix.h" #include "ngx_http_lua_script.h" -#include "ngx_http_lua_pcrefix.h" #include "ngx_http_lua_util.h" @@ -249,7 +248,8 @@ ngx_http_lua_ngx_re_match_helper(lua_State *L, int wantcaps) dd("server pool %p", lmcf->pool); - lua_pushlightuserdata(L, &ngx_http_lua_regex_cache_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + regex_cache_key)); lua_rawget(L, LUA_REGISTRYINDEX); /* table */ lua_pushliteral(L, "m"); @@ -720,7 +720,8 @@ ngx_http_lua_ngx_re_gmatch(lua_State *L) dd("server pool %p", lmcf->pool); - lua_pushlightuserdata(L, &ngx_http_lua_regex_cache_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + regex_cache_key)); lua_rawget(L, LUA_REGISTRYINDEX); /* table */ lua_pushliteral(L, "m"); @@ -1388,7 +1389,8 @@ ngx_http_lua_ngx_re_sub_helper(lua_State *L, unsigned global) dd("server pool %p", lmcf->pool); - lua_pushlightuserdata(L, &ngx_http_lua_regex_cache_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + regex_cache_key)); lua_rawget(L, LUA_REGISTRYINDEX); /* table */ lua_pushliteral(L, "s"); diff --git a/debian/modules/http-lua/src/ngx_http_lua_rewriteby.c b/debian/modules/http-lua/src/ngx_http_lua_rewriteby.c index 1bbe87c..1de9968 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_rewriteby.c +++ b/debian/modules/http-lua/src/ngx_http_lua_rewriteby.c @@ -62,7 +62,7 @@ ngx_http_lua_rewrite_handler(ngx_http_request_t *r) #endif if (cur_ph < last_ph) { - dd("swaping the contents of cur_ph and last_ph..."); + dd("swapping the contents of cur_ph and last_ph..."); tmp = *cur_ph; @@ -261,9 +261,11 @@ ngx_http_lua_rewrite_by_chunk(lua_State *L, ngx_http_request_t *r) /* 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); diff --git a/debian/modules/http-lua/src/ngx_http_lua_script.c b/debian/modules/http-lua/src/ngx_http_lua_script.c index 95ebadf..c675a16 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_script.c +++ b/debian/modules/http-lua/src/ngx_http_lua_script.c @@ -329,7 +329,7 @@ ngx_http_lua_script_add_copy_code(ngx_http_lua_script_compile_t *sc, return NGX_ERROR; } - code->code = (ngx_http_lua_script_code_pt) + code->code = (ngx_http_lua_script_code_pt) (void *) ngx_http_lua_script_copy_len_code; code->len = len; @@ -399,7 +399,7 @@ ngx_http_lua_script_add_capture_code(ngx_http_lua_script_compile_t *sc, return NGX_ERROR; } - code->code = (ngx_http_lua_script_code_pt) + code->code = (ngx_http_lua_script_code_pt) (void *) ngx_http_lua_script_copy_capture_len_code; code->n = 2 * n; diff --git a/debian/modules/http-lua/src/ngx_http_lua_setby.c b/debian/modules/http-lua/src/ngx_http_lua_setby.c index 2e8762a..d4288b5 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_setby.c +++ b/debian/modules/http-lua/src/ngx_http_lua_setby.c @@ -30,13 +30,6 @@ static void ngx_http_lua_set_by_lua_env(lua_State *L, ngx_http_request_t *r, size_t nargs, ngx_http_variable_value_t *args); -/* keys in Lua thread for fetching args and nargs in set_by_lua* */ - -#define ngx_http_lua_nargs_key "__ngx_nargs" - -#define ngx_http_lua_args_key "__ngx_args" - - ngx_int_t 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) @@ -134,23 +127,24 @@ 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_lua_setby_param_get(lua_State *L, ngx_http_request_t *r) { int idx; int n; ngx_http_variable_value_t *v; + ngx_http_lua_main_conf_t *lmcf; idx = luaL_checkint(L, 2); idx--; - /* get number of args from globals */ - lua_getglobal(L, ngx_http_lua_nargs_key); - n = (int) lua_tointeger(L, -1); + lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); - /* get args from globals */ - lua_getglobal(L, ngx_http_lua_args_key); - v = lua_touserdata(L, -1); + /* get number of args from lmcf */ + n = lmcf->setby_nargs; + + /* get args from lmcf */ + v = lmcf->setby_args; if (idx < 0 || idx > n - 1) { lua_pushnil(L); @@ -178,15 +172,16 @@ static void ngx_http_lua_set_by_lua_env(lua_State *L, ngx_http_request_t *r, size_t nargs, ngx_http_variable_value_t *args) { - /* set nginx request pointer to current lua thread's globals table */ + ngx_http_lua_main_conf_t *lmcf; + ngx_http_lua_set_req(L, r); - lua_pushinteger(L, nargs); - lua_setglobal(L, ngx_http_lua_nargs_key); + lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); - lua_pushlightuserdata(L, args); - lua_setglobal(L, ngx_http_lua_args_key); + lmcf->setby_nargs = nargs; + lmcf->setby_args = args; +#ifndef OPENRESTY_LUAJIT /** * we want to create empty environment for current script * @@ -211,6 +206,7 @@ ngx_http_lua_set_by_lua_env(lua_State *L, ngx_http_request_t *r, size_t nargs, /* }}} */ lua_setfenv(L, -2); /* set new running env for the code closure */ +#endif } /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_setby.h b/debian/modules/http-lua/src/ngx_http_lua_setby.h index da71753..f43eef7 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_setby.h +++ b/debian/modules/http-lua/src/ngx_http_lua_setby.h @@ -7,7 +7,7 @@ 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); +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/debian/modules/http-lua/src/ngx_http_lua_shdict.c b/debian/modules/http-lua/src/ngx_http_lua_shdict.c index 5fb7930..b017bea 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_shdict.c +++ b/debian/modules/http-lua/src/ngx_http_lua_shdict.c @@ -325,6 +325,7 @@ ngx_http_lua_inject_shdict_api(ngx_http_lua_main_conf_t *lmcf, lua_State *L) ngx_http_lua_shdict_ctx_t *ctx; ngx_uint_t i; ngx_shm_zone_t **zone; + ngx_shm_zone_t **zone_udata; if (lmcf->shdict_zones != NULL) { lua_createtable(L, 0, lmcf->shdict_zones->nelts /* nrec */); @@ -396,7 +397,9 @@ ngx_http_lua_inject_shdict_api(ngx_http_lua_main_conf_t *lmcf, lua_State *L) lua_createtable(L, 1 /* narr */, 0 /* nrec */); /* table of zone[i] */ - lua_pushlightuserdata(L, zone[i]); /* shared mt key ud */ + zone_udata = lua_newuserdata(L, sizeof(ngx_shm_zone_t *)); + /* shared mt key ud */ + *zone_udata = zone[i]; lua_rawseti(L, -2, SHDICT_USERDATA_INDEX); /* {zone[i]} */ lua_pushvalue(L, -3); /* shared mt key ud mt */ lua_setmetatable(L, -2); /* shared mt key ud */ @@ -431,11 +434,17 @@ static ngx_inline ngx_shm_zone_t * ngx_http_lua_shdict_get_zone(lua_State *L, int index) { ngx_shm_zone_t *zone; + ngx_shm_zone_t **zone_udata; lua_rawgeti(L, index, SHDICT_USERDATA_INDEX); - zone = lua_touserdata(L, -1); + zone_udata = lua_touserdata(L, -1); lua_pop(L, 1); + if (zone_udata == NULL) { + return NULL; + } + + zone = *zone_udata; return zone; } @@ -2209,6 +2218,17 @@ ngx_http_lua_find_zone(u_char *name_data, size_t name_len) #ifndef NGX_LUA_NO_FFI_API +ngx_shm_zone_t * +ngx_http_lua_ffi_shdict_udata_to_zone(void *zone_udata) +{ + if (zone_udata == NULL) { + return NULL; + } + + return *(ngx_shm_zone_t **) zone_udata; +} + + int ngx_http_lua_ffi_shdict_store(ngx_shm_zone_t *zone, int op, u_char *key, size_t key_len, int value_type, u_char *str_value_buf, @@ -2225,10 +2245,6 @@ ngx_http_lua_ffi_shdict_store(ngx_shm_zone_t *zone, int op, u_char *key, ngx_http_lua_shdict_ctx_t *ctx; ngx_http_lua_shdict_node_t *sd; - if (zone == NULL) { - return NGX_ERROR; - } - dd("exptime: %ld", exptime); ctx = zone->data; @@ -2490,10 +2506,6 @@ ngx_http_lua_ffi_shdict_get(ngx_shm_zone_t *zone, u_char *key, ngx_http_lua_shdict_node_t *sd; ngx_str_t value; - if (zone == NULL) { - return NGX_ERROR; - } - *err = NULL; ctx = zone->data; @@ -2636,10 +2648,6 @@ ngx_http_lua_ffi_shdict_incr(ngx_shm_zone_t *zone, u_char *key, u_char *p; ngx_queue_t *queue, *q; - if (zone == NULL) { - return NGX_ERROR; - } - if (init_ttl > 0) { tp = ngx_timeofday(); } @@ -2915,10 +2923,6 @@ ngx_http_lua_ffi_shdict_get_ttl(ngx_shm_zone_t *zone, u_char *key, ngx_http_lua_shdict_ctx_t *ctx; ngx_http_lua_shdict_node_t *sd; - if (zone == NULL) { - return NGX_ERROR; - } - ctx = zone->data; hash = ngx_crc32_short(key, key_len); @@ -2959,10 +2963,6 @@ ngx_http_lua_ffi_shdict_set_expire(ngx_shm_zone_t *zone, u_char *key, ngx_http_lua_shdict_ctx_t *ctx; ngx_http_lua_shdict_node_t *sd; - if (zone == NULL) { - return NGX_ERROR; - } - if (exptime > 0) { tp = ngx_timeofday(); } diff --git a/debian/modules/http-lua/src/ngx_http_lua_socket_tcp.c b/debian/modules/http-lua/src/ngx_http_lua_socket_tcp.c index efdf427..87461e6 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_socket_tcp.c +++ b/debian/modules/http-lua/src/ngx_http_lua_socket_tcp.c @@ -11,6 +11,7 @@ #include "ngx_http_lua_socket_tcp.h" +#include "ngx_http_lua_input_filters.h" #include "ngx_http_lua_util.h" #include "ngx_http_lua_uthread.h" #include "ngx_http_lua_output.h" @@ -24,6 +25,7 @@ static int ngx_http_lua_socket_tcp_connect(lua_State *L); static int ngx_http_lua_socket_tcp_sslhandshake(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); static int ngx_http_lua_socket_tcp_send(lua_State *L); static int ngx_http_lua_socket_tcp_close(lua_State *L); static int ngx_http_lua_socket_tcp_setoption(lua_State *L); @@ -69,6 +71,8 @@ static int ngx_http_lua_socket_tcp_conn_retval_handler(ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u, lua_State *L); 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 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, @@ -86,6 +90,7 @@ static int ngx_http_lua_socket_write_error_retval_handler(ngx_http_request_t *r, static ngx_int_t ngx_http_lua_socket_read_all(void *data, ssize_t bytes); static ngx_int_t ngx_http_lua_socket_read_until(void *data, ssize_t bytes); static ngx_int_t ngx_http_lua_socket_read_chunk(void *data, ssize_t bytes); +static ngx_int_t ngx_http_lua_socket_read_any(void *data, ssize_t bytes); static int ngx_http_lua_socket_tcp_receiveuntil(lua_State *L); static int ngx_http_lua_socket_receiveuntil_iterator(lua_State *L); static ngx_int_t ngx_http_lua_socket_compile_pattern(u_char *data, size_t len, @@ -95,12 +100,28 @@ static int ngx_http_lua_req_socket(lua_State *L); static void ngx_http_lua_req_socket_rev_handler(ngx_http_request_t *r); static int ngx_http_lua_socket_tcp_getreusedtimes(lua_State *L); static int ngx_http_lua_socket_tcp_setkeepalive(lua_State *L); +static void ngx_http_lua_socket_tcp_create_socket_pool(lua_State *L, + ngx_http_request_t *r, ngx_str_t key, ngx_int_t pool_size, + ngx_int_t backlog, ngx_http_lua_socket_pool_t **spool); static ngx_int_t ngx_http_lua_get_keepalive_peer(ngx_http_request_t *r, - lua_State *L, int key_index, ngx_http_lua_socket_tcp_upstream_t *u); static void ngx_http_lua_socket_keepalive_dummy_handler(ngx_event_t *ev); +static int ngx_http_lua_socket_tcp_connect_helper(lua_State *L, + ngx_http_lua_socket_tcp_upstream_t *u, ngx_http_request_t *r, + ngx_http_lua_ctx_t *ctx, u_char *host_ref, size_t host_len, in_port_t port, + unsigned resuming); +static void ngx_http_lua_socket_tcp_conn_op_timeout_handler( + ngx_event_t *ev); +static int ngx_http_lua_socket_tcp_conn_op_timeout_retval_handler( + ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u, lua_State *L); +static void ngx_http_lua_socket_tcp_resume_conn_op( + ngx_http_lua_socket_pool_t *spool); +static void ngx_http_lua_socket_tcp_conn_op_ctx_cleanup(void *data); +static void ngx_http_lua_socket_tcp_conn_op_resume_handler(ngx_event_t *ev); static ngx_int_t ngx_http_lua_socket_keepalive_close_handler(ngx_event_t *ev); static void ngx_http_lua_socket_keepalive_rev_handler(ngx_event_t *ev); +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, @@ -113,11 +134,13 @@ static ngx_int_t ngx_http_lua_socket_add_input_buffer(ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u); static ngx_int_t ngx_http_lua_socket_insert_buffer(ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u, u_char *pat, size_t prefix); +static ngx_int_t ngx_http_lua_socket_tcp_conn_op_resume(ngx_http_request_t *r); static ngx_int_t ngx_http_lua_socket_tcp_conn_resume(ngx_http_request_t *r); static ngx_int_t ngx_http_lua_socket_tcp_read_resume(ngx_http_request_t *r); static ngx_int_t ngx_http_lua_socket_tcp_write_resume(ngx_http_request_t *r); static ngx_int_t ngx_http_lua_socket_tcp_resume_helper(ngx_http_request_t *r, int socket_op); +static void ngx_http_lua_tcp_queue_conn_op_cleanup(void *data); static void ngx_http_lua_tcp_resolve_cleanup(void *data); static void ngx_http_lua_coctx_cleanup(void *data); static void ngx_http_lua_socket_free_pool(ngx_log_t *log, @@ -150,7 +173,8 @@ enum { enum { SOCKET_OP_CONNECT, SOCKET_OP_READ, - SOCKET_OP_WRITE + SOCKET_OP_WRITE, + SOCKET_OP_RESUME_CONN }; @@ -229,7 +253,8 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) lua_setfield(L, -2, "socket"); /* {{{req socket object metatable */ - lua_pushlightuserdata(L, &ngx_http_lua_req_socket_metatable_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + req_socket_metatable_key)); lua_createtable(L, 0 /* narr */, 5 /* nrec */); lua_pushcfunction(L, ngx_http_lua_socket_tcp_receive); @@ -251,7 +276,8 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) /* }}} */ /* {{{raw req socket object metatable */ - lua_pushlightuserdata(L, &ngx_http_lua_raw_req_socket_metatable_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + raw_req_socket_metatable_key)); lua_createtable(L, 0 /* narr */, 6 /* nrec */); lua_pushcfunction(L, ngx_http_lua_socket_tcp_receive); @@ -276,7 +302,8 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) /* }}} */ /* {{{tcp object metatable */ - lua_pushlightuserdata(L, &ngx_http_lua_tcp_socket_metatable_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + tcp_socket_metatable_key)); lua_createtable(L, 0 /* narr */, 12 /* nrec */); lua_pushcfunction(L, ngx_http_lua_socket_tcp_connect); @@ -292,6 +319,9 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) lua_pushcfunction(L, ngx_http_lua_socket_tcp_receive); lua_setfield(L, -2, "receive"); + lua_pushcfunction(L, ngx_http_lua_socket_tcp_receiveany); + lua_setfield(L, -2, "receiveany"); + lua_pushcfunction(L, ngx_http_lua_socket_tcp_receiveuntil); lua_setfield(L, -2, "receiveuntil"); @@ -322,7 +352,8 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) /* }}} */ /* {{{upstream userdata metatable */ - lua_pushlightuserdata(L, &ngx_http_lua_upstream_udata_metatable_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + upstream_udata_metatable_key)); lua_createtable(L, 0 /* narr */, 1 /* nrec */); /* metatable */ lua_pushcfunction(L, ngx_http_lua_socket_tcp_upstream_destroy); lua_setfield(L, -2, "__gc"); @@ -330,7 +361,8 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) /* }}} */ /* {{{downstream userdata metatable */ - lua_pushlightuserdata(L, &ngx_http_lua_downstream_udata_metatable_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + downstream_udata_metatable_key)); lua_createtable(L, 0 /* narr */, 1 /* nrec */); /* metatable */ lua_pushcfunction(L, ngx_http_lua_socket_downstream_destroy); lua_setfield(L, -2, "__gc"); @@ -338,7 +370,8 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) /* }}} */ /* {{{socket pool userdata metatable */ - lua_pushlightuserdata(L, &ngx_http_lua_pool_udata_metatable_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + pool_udata_metatable_key)); lua_createtable(L, 0, 1); /* metatable */ lua_pushcfunction(L, ngx_http_lua_socket_shutdown_pool); lua_setfield(L, -2, "__gc"); @@ -346,7 +379,8 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) /* }}} */ /* {{{socket compiled pattern userdata metatable */ - lua_pushlightuserdata(L, &ngx_http_lua_pattern_udata_metatable_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + pattern_udata_metatable_key)); lua_createtable(L, 0 /* narr */, 1 /* nrec */); /* metatable */ lua_pushcfunction(L, ngx_http_lua_socket_cleanup_compiled_pattern); lua_setfield(L, -2, "__gc"); @@ -356,7 +390,8 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) #if (NGX_HTTP_SSL) /* {{{ssl session userdata metatable */ - lua_pushlightuserdata(L, &ngx_http_lua_ssl_session_metatable_key); + 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"); @@ -404,7 +439,8 @@ ngx_http_lua_socket_tcp(lua_State *L) | NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH); lua_createtable(L, 5 /* narr */, 1 /* nrec */); - lua_pushlightuserdata(L, &ngx_http_lua_tcp_socket_metatable_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + tcp_socket_metatable_key)); lua_rawget(L, LUA_REGISTRYINDEX); lua_setmetatable(L, -2); @@ -414,31 +450,421 @@ ngx_http_lua_socket_tcp(lua_State *L) } +static void +ngx_http_lua_socket_tcp_create_socket_pool(lua_State *L, ngx_http_request_t *r, + ngx_str_t key, ngx_int_t pool_size, ngx_int_t backlog, + ngx_http_lua_socket_pool_t **spool) +{ + u_char *p; + size_t size, key_len; + ngx_int_t i; + ngx_http_lua_socket_pool_t *sp; + ngx_http_lua_socket_pool_item_t *items; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua tcp socket connection pool size: %i, backlog: %i", + pool_size, backlog); + + key_len = ngx_align(key.len + 1, sizeof(void *)); + + size = sizeof(ngx_http_lua_socket_pool_t) - 1 + key_len + + sizeof(ngx_http_lua_socket_pool_item_t) * pool_size; + + /* before calling this function, the Lua stack is: + * -1 key + * -2 pools + */ + sp = lua_newuserdata(L, size); + if (sp == NULL) { + luaL_error(L, "no memory"); + return; + } + + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + pool_udata_metatable_key)); + lua_rawget(L, LUA_REGISTRYINDEX); + lua_setmetatable(L, -2); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua tcp socket keepalive create connection pool for key" + " \"%V\"", &key); + + /* a new socket pool with metatable is push to the stack, so now we have: + * -1 sp + * -2 key + * -3 pools + * + * it is time to set pools[key] to sp. + */ + lua_rawset(L, -3); + + /* clean up the stack for consistency's sake */ + lua_pop(L, 1); + + sp->backlog = backlog; + sp->size = pool_size; + sp->connections = 0; + sp->lua_vm = ngx_http_lua_get_lua_vm(r, NULL); + + ngx_queue_init(&sp->cache_connect_op); + ngx_queue_init(&sp->wait_connect_op); + ngx_queue_init(&sp->cache); + ngx_queue_init(&sp->free); + + p = ngx_copy(sp->key, key.data, key.len); + *p++ = '\0'; + + items = (ngx_http_lua_socket_pool_item_t *) (sp->key + key_len); + + dd("items: %p", items); + + ngx_http_lua_assert((void *) items == ngx_align_ptr(items, sizeof(void *))); + + for (i = 0; i < pool_size; i++) { + ngx_queue_insert_head(&sp->free, &items[i].queue); + items[i].socket_pool = sp; + } + + *spool = sp; +} + + +static int +ngx_http_lua_socket_tcp_connect_helper(lua_State *L, + ngx_http_lua_socket_tcp_upstream_t *u, ngx_http_request_t *r, + ngx_http_lua_ctx_t *ctx, u_char *host_ref, size_t host_len, in_port_t port, + unsigned resuming) +{ + int n; + int host_size; + int saved_top; + ngx_int_t rc; + ngx_str_t host; + ngx_str_t *conn_op_host; + ngx_url_t url; + ngx_queue_t *q; + ngx_resolver_ctx_t *rctx, temp; + ngx_http_lua_co_ctx_t *coctx; + ngx_http_core_loc_conf_t *clcf; + ngx_http_lua_socket_pool_t *spool; + ngx_http_lua_socket_tcp_conn_op_ctx_t *conn_op_ctx; + + spool = u->socket_pool; + if (spool != NULL) { + rc = ngx_http_lua_get_keepalive_peer(r, u); + + if (rc == NGX_OK) { + lua_pushinteger(L, 1); + return 1; + } + + /* rc == NGX_DECLINED */ + + spool->connections++; + + /* check if backlog is enabled and + * don't queue resuming connection operation */ + if (spool->backlog >= 0 && !resuming) { + + dd("lua tcp socket %s connections %ld", + spool->key, spool->connections); + + if (spool->connections > spool->size + spool->backlog) { + spool->connections--; + lua_pushnil(L); + lua_pushliteral(L, "too many waiting connect operations"); + return 2; + } + + if (spool->connections > spool->size) { + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, u->peer.log, 0, + "lua tcp socket queue connect operation for " + "connection pool \"%s\", connections: %i", + spool->key, spool->connections); + + host_size = sizeof(u_char) * + (ngx_max(host_len, NGX_INET_ADDRSTRLEN) + 1); + + if (!ngx_queue_empty(&spool->cache_connect_op)) { + q = ngx_queue_last(&spool->cache_connect_op); + ngx_queue_remove(q); + conn_op_ctx = ngx_queue_data( + q, ngx_http_lua_socket_tcp_conn_op_ctx_t, queue); + + conn_op_host = &conn_op_ctx->host; + if (host_len > conn_op_host->len + && host_len > NGX_INET_ADDRSTRLEN) + { + ngx_free(conn_op_host->data); + conn_op_host->data = ngx_alloc(host_size, + ngx_cycle->log); + if (conn_op_host->data == NULL) { + ngx_free(conn_op_ctx); + goto no_memory_and_not_resuming; + } + } + + } else { + conn_op_ctx = ngx_alloc( + sizeof(ngx_http_lua_socket_tcp_conn_op_ctx_t), + ngx_cycle->log); + if (conn_op_ctx == NULL) { + goto no_memory_and_not_resuming; + } + + conn_op_host = &conn_op_ctx->host; + conn_op_host->data = ngx_alloc(host_size, ngx_cycle->log); + if (conn_op_host->data == NULL) { + ngx_free(conn_op_ctx); + goto no_memory_and_not_resuming; + } + } + + conn_op_ctx->cleanup = NULL; + + ngx_memcpy(conn_op_host->data, host_ref, host_len); + conn_op_host->data[host_len] = '\0'; + conn_op_host->len = host_len; + + conn_op_ctx->port = port; + + u->write_co_ctx = ctx->cur_co_ctx; + + conn_op_ctx->u = u; + ctx->cur_co_ctx->cleanup = + ngx_http_lua_tcp_queue_conn_op_cleanup; + ctx->cur_co_ctx->data = conn_op_ctx; + + ngx_memzero(&conn_op_ctx->event, sizeof(ngx_event_t)); + conn_op_ctx->event.handler = + ngx_http_lua_socket_tcp_conn_op_timeout_handler; + conn_op_ctx->event.data = conn_op_ctx; + conn_op_ctx->event.log = ngx_cycle->log; + + ngx_add_timer(&conn_op_ctx->event, u->connect_timeout); + + ngx_queue_insert_tail(&spool->wait_connect_op, + &conn_op_ctx->queue); + + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua tcp socket queued connect operation for " + "%d(ms), u: %p, ctx: %p", + u->connect_timeout, conn_op_ctx->u, conn_op_ctx); + + return lua_yield(L, 0); + } + } + + } /* end spool != NULL */ + + host.data = ngx_palloc(r->pool, host_len + 1); + if (host.data == NULL) { + return luaL_error(L, "no memory"); + } + + host.len = host_len; + + ngx_memcpy(host.data, host_ref, host_len); + host.data[host_len] = '\0'; + + ngx_memzero(&url, sizeof(ngx_url_t)); + url.url = host; + url.default_port = port; + url.no_resolve = 1; + + coctx = ctx->cur_co_ctx; + + if (ngx_parse_url(r->pool, &url) != NGX_OK) { + lua_pushnil(L); + + if (url.err) { + lua_pushfstring(L, "failed to parse host name \"%s\": %s", + url.url.data, url.err); + + } else { + lua_pushfstring(L, "failed to parse host name \"%s\"", + url.url.data); + } + + goto failed; + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua tcp socket connect timeout: %M", u->connect_timeout); + + u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t)); + if (u->resolved == NULL) { + if (resuming) { + lua_pushnil(L); + lua_pushliteral(L, "no memory"); + goto failed; + } + + goto no_memory_and_not_resuming; + } + + if (url.addrs && url.addrs[0].sockaddr) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua tcp socket network address given directly"); + + u->resolved->sockaddr = url.addrs[0].sockaddr; + u->resolved->socklen = url.addrs[0].socklen; + u->resolved->naddrs = 1; + u->resolved->host = url.addrs[0].name; + + } else { + u->resolved->host = host; + u->resolved->port = url.default_port; + } + + if (u->resolved->sockaddr) { + rc = ngx_http_lua_socket_resolve_retval_handler(r, u, L); + if (rc == NGX_AGAIN && !resuming) { + return lua_yield(L, 0); + } + + if (rc > 1) { + goto failed; + } + + return rc; + } + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + temp.name = host; + rctx = ngx_resolve_start(clcf->resolver, &temp); + if (rctx == NULL) { + u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_RESOLVER; + lua_pushnil(L); + lua_pushliteral(L, "failed to start the resolver"); + goto failed; + } + + if (rctx == NGX_NO_RESOLVER) { + u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_RESOLVER; + lua_pushnil(L); + lua_pushfstring(L, "no resolver defined to resolve \"%s\"", host.data); + goto failed; + } + + rctx->name = host; +#if !defined(nginx_version) || nginx_version < 1005008 + rctx->type = NGX_RESOLVE_A; +#endif + rctx->handler = ngx_http_lua_socket_resolve_handler; + rctx->data = u; + rctx->timeout = clcf->resolver_timeout; + + u->resolved->ctx = rctx; + u->write_co_ctx = ctx->cur_co_ctx; + + ngx_http_lua_cleanup_pending_operation(coctx); + coctx->cleanup = ngx_http_lua_tcp_resolve_cleanup; + coctx->data = u; + + saved_top = lua_gettop(L); + + if (ngx_resolve_name(rctx) != NGX_OK) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua tcp socket fail to run resolver immediately"); + + u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_RESOLVER; + + coctx->cleanup = NULL; + coctx->data = NULL; + + u->resolved->ctx = NULL; + lua_pushnil(L); + lua_pushfstring(L, "%s could not be resolved", host.data); + goto failed; + } + + if (u->conn_waiting) { + dd("resolved and already connecting"); + + if (resuming) { + return NGX_AGAIN; + } + + return lua_yield(L, 0); + } + + n = lua_gettop(L) - saved_top; + if (n) { + dd("errors occurred during resolving or connecting" + "or already connected"); + + if (n > 1) { + goto failed; + } + + return n; + } + + /* still resolving */ + + u->conn_waiting = 1; + u->write_prepare_retvals = ngx_http_lua_socket_resolve_retval_handler; + + dd("setting data to %p", u); + + if (ctx->entered_content_phase) { + r->write_event_handler = ngx_http_lua_content_wev_handler; + + } else { + r->write_event_handler = ngx_http_core_run_phases; + } + + if (resuming) { + return NGX_AGAIN; + } + + return lua_yield(L, 0); + +failed: + + if (spool != NULL) { + spool->connections--; + ngx_http_lua_socket_tcp_resume_conn_op(spool); + } + + return 2; + +no_memory_and_not_resuming: + + if (spool != NULL) { + spool->connections--; + ngx_http_lua_socket_tcp_resume_conn_op(spool); + } + + return luaL_error(L, "no memory"); +} + + static int ngx_http_lua_socket_tcp_connect(lua_State *L) { ngx_http_request_t *r; ngx_http_lua_ctx_t *ctx; - ngx_str_t host; int port; - ngx_resolver_ctx_t *rctx, temp; - ngx_http_core_loc_conf_t *clcf; - int saved_top; int n; u_char *p; size_t len; - ngx_url_t url; - ngx_int_t rc; ngx_http_lua_loc_conf_t *llcf; ngx_peer_connection_t *pc; int connect_timeout, send_timeout, read_timeout; unsigned custom_pool; int key_index; + ngx_int_t backlog; + ngx_int_t pool_size; + ngx_str_t key; const char *msg; - ngx_http_lua_co_ctx_t *coctx; ngx_http_lua_socket_tcp_upstream_t *u; + ngx_http_lua_socket_pool_t *spool; + n = lua_gettop(L); if (n != 2 && n != 3 && n != 4) { return luaL_error(L, "ngx.socket connect: expecting 2, 3, or 4 " @@ -466,13 +892,54 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) p = (u_char *) luaL_checklstring(L, 2, &len); + backlog = -1; key_index = 2; + pool_size = 0; custom_pool = 0; + llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); if (lua_type(L, n) == LUA_TTABLE) { /* found the last optional option table */ + lua_getfield(L, n, "pool_size"); + + if (lua_isnumber(L, -1)) { + pool_size = (ngx_int_t) lua_tointeger(L, -1); + + if (pool_size <= 0) { + msg = lua_pushfstring(L, "bad \"pool_size\" option value: %i", + pool_size); + return luaL_argerror(L, n, msg); + } + + } else if (!lua_isnil(L, -1)) { + msg = lua_pushfstring(L, "bad \"pool_size\" option type: %s", + lua_typename(L, lua_type(L, -1))); + return luaL_argerror(L, n, msg); + } + + lua_pop(L, 1); + + lua_getfield(L, n, "backlog"); + + if (lua_isnumber(L, -1)) { + backlog = (ngx_int_t) lua_tointeger(L, -1); + + if (backlog < 0) { + msg = lua_pushfstring(L, "bad \"backlog\" option value: %i", + backlog); + return luaL_argerror(L, n, msg); + } + + /* use default value for pool size if only backlog specified */ + if (pool_size == 0) { + pool_size = llcf->pool_size; + } + } + + lua_pop(L, 1); + lua_getfield(L, n, "pool"); switch (lua_type(L, -1)) { @@ -572,7 +1039,8 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) } #if 1 - lua_pushlightuserdata(L, &ngx_http_lua_upstream_udata_metatable_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + upstream_udata_metatable_key)); lua_rawget(L, LUA_REGISTRYINDEX); lua_setmetatable(L, -2); #endif @@ -582,12 +1050,8 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) ngx_memzero(u, sizeof(ngx_http_lua_socket_tcp_upstream_t)); - coctx = ctx->cur_co_ctx; - u->request = r; /* set the controlling request */ - llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); - u->conf = llcf; pc = &u->peer; @@ -628,163 +1092,28 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) u->read_timeout = u->conf->read_timeout; } - rc = ngx_http_lua_get_keepalive_peer(r, L, key_index, u); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask(socket_pool_key)); + lua_rawget(L, LUA_REGISTRYINDEX); /* table */ + lua_pushvalue(L, key_index); /* key */ - if (rc == NGX_OK) { - lua_pushinteger(L, 1); - return 1; + lua_rawget(L, -2); + spool = lua_touserdata(L, -1); + lua_pop(L, 1); + + if (spool != NULL) { + u->socket_pool = spool; + + } else if (pool_size > 0) { + lua_pushvalue(L, key_index); + key.data = (u_char *) lua_tolstring(L, -1, &key.len); + + ngx_http_lua_socket_tcp_create_socket_pool(L, r, key, pool_size, + backlog, &spool); + u->socket_pool = spool; } - if (rc == NGX_ERROR) { - lua_pushnil(L); - lua_pushliteral(L, "error in get keepalive peer"); - return 2; - } - - /* rc == NGX_DECLINED */ - - /* TODO: we should avoid this in-pool allocation */ - - host.data = ngx_palloc(r->pool, len + 1); - if (host.data == NULL) { - return luaL_error(L, "no memory"); - } - - host.len = len; - - ngx_memcpy(host.data, p, len); - host.data[len] = '\0'; - - ngx_memzero(&url, sizeof(ngx_url_t)); - - url.url.len = host.len; - url.url.data = host.data; - url.default_port = (in_port_t) port; - url.no_resolve = 1; - - if (ngx_parse_url(r->pool, &url) != NGX_OK) { - lua_pushnil(L); - - if (url.err) { - lua_pushfstring(L, "failed to parse host name \"%s\": %s", - host.data, url.err); - - } else { - lua_pushfstring(L, "failed to parse host name \"%s\"", host.data); - } - - return 2; - } - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua tcp socket connect timeout: %M", u->connect_timeout); - - u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t)); - if (u->resolved == NULL) { - return luaL_error(L, "no memory"); - } - - if (url.addrs && url.addrs[0].sockaddr) { - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua tcp socket network address given directly"); - - u->resolved->sockaddr = url.addrs[0].sockaddr; - u->resolved->socklen = url.addrs[0].socklen; - u->resolved->naddrs = 1; - u->resolved->host = url.addrs[0].name; - - } else { - u->resolved->host = host; - u->resolved->port = (in_port_t) port; - } - - if (u->resolved->sockaddr) { - rc = ngx_http_lua_socket_resolve_retval_handler(r, u, L); - if (rc == NGX_AGAIN) { - return lua_yield(L, 0); - } - - return rc; - } - - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - - temp.name = host; - rctx = ngx_resolve_start(clcf->resolver, &temp); - if (rctx == NULL) { - u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_RESOLVER; - lua_pushnil(L); - lua_pushliteral(L, "failed to start the resolver"); - return 2; - } - - if (rctx == NGX_NO_RESOLVER) { - u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_RESOLVER; - lua_pushnil(L); - lua_pushfstring(L, "no resolver defined to resolve \"%s\"", host.data); - return 2; - } - - rctx->name = host; -#if !defined(nginx_version) || nginx_version < 1005008 - rctx->type = NGX_RESOLVE_A; -#endif - rctx->handler = ngx_http_lua_socket_resolve_handler; - rctx->data = u; - rctx->timeout = clcf->resolver_timeout; - - u->resolved->ctx = rctx; - u->write_co_ctx = ctx->cur_co_ctx; - - ngx_http_lua_cleanup_pending_operation(coctx); - coctx->cleanup = ngx_http_lua_tcp_resolve_cleanup; - coctx->data = u; - - saved_top = lua_gettop(L); - - if (ngx_resolve_name(rctx) != NGX_OK) { - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua tcp socket fail to run resolver immediately"); - - u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_RESOLVER; - - coctx->cleanup = NULL; - coctx->data = NULL; - - u->resolved->ctx = NULL; - lua_pushnil(L); - lua_pushfstring(L, "%s could not be resolved", host.data); - - return 2; - } - - if (u->conn_waiting) { - dd("resolved and already connecting"); - return lua_yield(L, 0); - } - - n = lua_gettop(L) - saved_top; - if (n) { - dd("errors occurred during resolving or connecting" - "or already connected"); - return n; - } - - /* still resolving */ - - u->conn_waiting = 1; - u->write_prepare_retvals = ngx_http_lua_socket_resolve_retval_handler; - - dd("setting data to %p", u); - - if (ctx->entered_content_phase) { - r->write_event_handler = ngx_http_lua_content_wev_handler; - - } else { - r->write_event_handler = ngx_http_core_run_phases; - } - - return lua_yield(L, 0); + return ngx_http_lua_socket_tcp_connect_helper(L, u, r, ctx, p, + len, port, 0); } @@ -1638,7 +1967,8 @@ ngx_http_lua_ssl_handshake_retval_handler(ngx_http_request_t *r, "lua ssl save session: %p", ssl_session); /* set up the __gc metamethod */ - lua_pushlightuserdata(L, &ngx_http_lua_ssl_session_metatable_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + ssl_session_metatable_key)); lua_rawget(L, LUA_REGISTRYINDEX); lua_setmetatable(L, -2); } @@ -1755,20 +2085,173 @@ ngx_http_lua_socket_tcp_conn_retval_handler(ngx_http_request_t *r, } +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) +{ + ngx_int_t rc; + 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) { + u->bufs_in = + ngx_http_lua_chain_get_free_buf(r->connection->log, r->pool, + &ctx->free_recv_bufs, + u->conf->buffer_size); + + if (u->bufs_in == NULL) { + return luaL_error(L, "no memory"); + } + + u->buf_in = u->bufs_in; + u->buffer = *u->buf_in->buf; + } + + dd("tcp receive: buf_in: %p, bufs_in: %p", u->buf_in, u->bufs_in); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua tcp socket read timeout: %M", u->read_timeout); + + if (u->raw_downstream || u->body_downstream) { + r->read_event_handler = ngx_http_lua_req_socket_rev_handler; + } + + u->read_waiting = 0; + u->read_co_ctx = NULL; + + rc = ngx_http_lua_socket_tcp_read(r, u); + + if (rc == NGX_ERROR) { + dd("read failed: %d", (int) u->ft_type); + rc = ngx_http_lua_socket_tcp_receive_retval_handler(r, u, L); + dd("tcp receive retval returned: %d", (int) rc); + return rc; + } + + if (rc == NGX_OK) { + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua tcp socket receive done in a single run"); + + return ngx_http_lua_socket_tcp_receive_retval_handler(r, u, L); + } + + /* rc == NGX_AGAIN */ + + u->read_event_handler = ngx_http_lua_socket_read_handler; + + coctx = ctx->cur_co_ctx; + + ngx_http_lua_cleanup_pending_operation(coctx); + coctx->cleanup = ngx_http_lua_coctx_cleanup; + coctx->data = u; + + if (ctx->entered_content_phase) { + r->write_event_handler = ngx_http_lua_content_wev_handler; + + } else { + r->write_event_handler = ngx_http_core_run_phases; + } + + u->read_co_ctx = coctx; + u->read_waiting = 1; + u->read_prepare_retvals = ngx_http_lua_socket_tcp_receive_retval_handler; + + dd("setting data to %p, coctx:%p", u, coctx); + + if (u->raw_downstream || u->body_downstream) { + ctx->downstream = u; + } + + return lua_yield(L, 0); +} + + +static int +ngx_http_lua_socket_tcp_receiveany(lua_State *L) +{ + int n; + lua_Integer bytes; + ngx_http_request_t *r; + ngx_http_lua_loc_conf_t *llcf; + ngx_http_lua_socket_tcp_upstream_t *u; + + n = lua_gettop(L); + if (n != 2) { + return luaL_error(L, "expecting 2 arguments " + "(including the object), but got %d", n); + } + + r = ngx_http_lua_get_req(L); + if (r == NULL) { + return luaL_error(L, "no request found"); + } + + luaL_checktype(L, 1, LUA_TTABLE); + + lua_rawgeti(L, 1, SOCKET_CTX_INDEX); + u = lua_touserdata(L, -1); + + if (u == NULL || u->peer.connection == NULL || u->read_closed) { + + llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); + + if (llcf->log_socket_errors) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "attempt to receive data on a closed socket: u:%p, " + "c:%p, ft:%d eof:%d", + u, u ? u->peer.connection : NULL, + u ? (int) u->ft_type : 0, u ? (int) u->eof : 0); + } + + lua_pushnil(L); + lua_pushliteral(L, "closed"); + return 2; + } + + if (u->request != r) { + return luaL_error(L, "bad request"); + } + + ngx_http_lua_socket_check_busy_connecting(r, u, L); + ngx_http_lua_socket_check_busy_reading(r, u, L); + + if (!lua_isnumber(L, 2)) { + return luaL_argerror(L, 2, "bad max argument"); + } + + bytes = lua_tointeger(L, 2); + if (bytes <= 0) { + return luaL_argerror(L, 2, "bad max argument"); + } + + u->input_filter = ngx_http_lua_socket_read_any; + u->rest = (size_t) bytes; + u->length = u->rest; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua tcp socket calling receiveany() method to read at " + "most %uz bytes", u->rest); + + return ngx_http_lua_socket_tcp_receive_helper(r, u, L); +} + + static int ngx_http_lua_socket_tcp_receive(lua_State *L) { ngx_http_request_t *r; ngx_http_lua_socket_tcp_upstream_t *u; - ngx_int_t rc; - ngx_http_lua_ctx_t *ctx; int n; ngx_str_t pat; lua_Integer bytes; char *p; int typ; ngx_http_lua_loc_conf_t *llcf; - ngx_http_lua_co_ctx_t *coctx; n = lua_gettop(L); if (n != 1 && n != 2) { @@ -1883,119 +2366,27 @@ ngx_http_lua_socket_tcp_receive(lua_State *L) u->rest = 0; } - u->input_filter_ctx = u; - - ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); - - if (u->bufs_in == NULL) { - u->bufs_in = - ngx_http_lua_chain_get_free_buf(r->connection->log, r->pool, - &ctx->free_recv_bufs, - u->conf->buffer_size); - - if (u->bufs_in == NULL) { - return luaL_error(L, "no memory"); - } - - u->buf_in = u->bufs_in; - u->buffer = *u->buf_in->buf; - } - - dd("tcp receive: buf_in: %p, bufs_in: %p", u->buf_in, u->bufs_in); - - if (u->raw_downstream || u->body_downstream) { - r->read_event_handler = ngx_http_lua_req_socket_rev_handler; - } - - u->read_waiting = 0; - u->read_co_ctx = NULL; - - rc = ngx_http_lua_socket_tcp_read(r, u); - - if (rc == NGX_ERROR) { - dd("read failed: %d", (int) u->ft_type); - rc = ngx_http_lua_socket_tcp_receive_retval_handler(r, u, L); - dd("tcp receive retval returned: %d", (int) rc); - return rc; - } - - if (rc == NGX_OK) { - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua tcp socket receive done in a single run"); - - return ngx_http_lua_socket_tcp_receive_retval_handler(r, u, L); - } - - /* rc == NGX_AGAIN */ - - u->read_event_handler = ngx_http_lua_socket_read_handler; - - coctx = ctx->cur_co_ctx; - - ngx_http_lua_cleanup_pending_operation(coctx); - coctx->cleanup = ngx_http_lua_coctx_cleanup; - coctx->data = u; - - if (ctx->entered_content_phase) { - r->write_event_handler = ngx_http_lua_content_wev_handler; - - } else { - r->write_event_handler = ngx_http_core_run_phases; - } - - u->read_co_ctx = coctx; - u->read_waiting = 1; - u->read_prepare_retvals = ngx_http_lua_socket_tcp_receive_retval_handler; - - dd("setting data to %p, coctx:%p", u, coctx); - - if (u->raw_downstream || u->body_downstream) { - ctx->downstream = u; - } - - return lua_yield(L, 0); + return ngx_http_lua_socket_tcp_receive_helper(r, u, L); } static ngx_int_t ngx_http_lua_socket_read_chunk(void *data, ssize_t bytes) { + ngx_int_t rc; ngx_http_lua_socket_tcp_upstream_t *u = data; - ngx_buf_t *b; -#if (NGX_DEBUG) - ngx_http_request_t *r; - - r = u->request; -#endif - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, u->request->connection->log, 0, "lua tcp socket read chunk %z", bytes); - if (bytes == 0) { + rc = ngx_http_lua_read_bytes(&u->buffer, u->buf_in, &u->rest, + bytes, u->request->connection->log); + if (rc == NGX_ERROR) { u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_CLOSED; return NGX_ERROR; } - b = &u->buffer; - - if (bytes >= (ssize_t) u->rest) { - - u->buf_in->buf->last += u->rest; - b->pos += u->rest; - u->rest = 0; - - return NGX_OK; - } - - /* bytes < u->rest */ - - u->buf_in->buf->last += bytes; - b->pos += bytes; - u->rest -= bytes; - - return NGX_AGAIN; + return rc; } @@ -2004,26 +2395,10 @@ ngx_http_lua_socket_read_all(void *data, ssize_t bytes) { ngx_http_lua_socket_tcp_upstream_t *u = data; - ngx_buf_t *b; -#if (NGX_DEBUG) - ngx_http_request_t *r; - - r = u->request; -#endif - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, u->request->connection->log, 0, "lua tcp socket read all"); - - if (bytes == 0) { - return NGX_OK; - } - - b = &u->buffer; - - u->buf_in->buf->last += bytes; - b->pos += bytes; - - return NGX_AGAIN; + return ngx_http_lua_read_all(&u->buffer, u->buf_in, bytes, + u->request->connection->log); } @@ -2032,72 +2407,40 @@ ngx_http_lua_socket_read_line(void *data, ssize_t bytes) { ngx_http_lua_socket_tcp_upstream_t *u = data; - ngx_buf_t *b; - u_char *dst; - u_char c; -#if (NGX_DEBUG) - u_char *begin; -#endif + ngx_int_t rc; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, u->request->connection->log, 0, "lua tcp socket read line"); - if (bytes == 0) { + rc = ngx_http_lua_read_line(&u->buffer, u->buf_in, bytes, + u->request->connection->log); + if (rc == NGX_ERROR) { u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_CLOSED; return NGX_ERROR; } - b = &u->buffer; + return rc; +} -#if (NGX_DEBUG) - begin = b->pos; -#endif - dd("already read: %p: %.*s", u->buf_in, - (int) (u->buf_in->buf->last - u->buf_in->buf->pos), - u->buf_in->buf->pos); +static ngx_int_t +ngx_http_lua_socket_read_any(void *data, ssize_t bytes) +{ + ngx_http_lua_socket_tcp_upstream_t *u = data; - dd("data read: %.*s", (int) bytes, b->pos); + ngx_int_t rc; - dst = u->buf_in->buf->last; + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, u->request->connection->log, 0, + "lua tcp socket read any"); - while (bytes--) { - - c = *b->pos++; - - switch (c) { - case '\n': - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, u->request->connection->log, 0, - "lua tcp socket read the final line part: \"%*s\"", - b->pos - 1 - begin, begin); - - u->buf_in->buf->last = dst; - - dd("read a line: %p: %.*s", u->buf_in, - (int) (u->buf_in->buf->last - u->buf_in->buf->pos), - u->buf_in->buf->pos); - - return NGX_OK; - - case '\r': - /* ignore it */ - break; - - default: - *dst++ = c; - break; - } + rc = ngx_http_lua_read_any(&u->buffer, u->buf_in, &u->rest, bytes, + u->request->connection->log); + if (rc == NGX_ERROR) { + u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_CLOSED; + return NGX_ERROR; } -#if (NGX_DEBUG) - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, u->request->connection->log, 0, - "lua tcp socket read partial line data: %*s", - dst - begin, begin); -#endif - - u->buf_in->buf->last = dst; - - return NGX_AGAIN; + return rc; } @@ -3539,6 +3882,267 @@ ngx_http_lua_socket_tcp_finalize_write_part(ngx_http_request_t *r, } +static void +ngx_http_lua_socket_tcp_conn_op_timeout_handler(ngx_event_t *ev) +{ + ngx_http_lua_socket_tcp_upstream_t *u; + ngx_http_lua_ctx_t *ctx; + ngx_connection_t *c; + ngx_http_request_t *r; + ngx_http_lua_co_ctx_t *coctx; + ngx_http_lua_loc_conf_t *llcf; + ngx_http_lua_socket_tcp_conn_op_ctx_t *conn_op_ctx; + + conn_op_ctx = ev->data; + ngx_queue_remove(&conn_op_ctx->queue); + + u = conn_op_ctx->u; + r = u->request; + + coctx = u->write_co_ctx; + coctx->cleanup = NULL; + /* note that we store conn_op_ctx in coctx->data instead of u */ + coctx->data = conn_op_ctx; + u->write_co_ctx = NULL; + + llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); + + if (llcf->log_socket_errors) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "lua tcp socket queued connect timed out," + " when trying to connect to %V:%ud", + &conn_op_ctx->host, conn_op_ctx->port); + } + + ngx_queue_insert_head(&u->socket_pool->cache_connect_op, + &conn_op_ctx->queue); + u->socket_pool->connections--; + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx == NULL) { + return; + } + + ctx->cur_co_ctx = coctx; + + ngx_http_lua_assert(coctx && (!ngx_http_lua_is_thread(ctx) + || coctx->co_ref >= 0)); + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua tcp socket waking up the current request"); + + u->write_prepare_retvals = + ngx_http_lua_socket_tcp_conn_op_timeout_retval_handler; + + c = r->connection; + + if (ctx->entered_content_phase) { + (void) ngx_http_lua_socket_tcp_conn_op_resume(r); + + } else { + ctx->resume_handler = ngx_http_lua_socket_tcp_conn_op_resume; + ngx_http_core_run_phases(r); + } + + ngx_http_run_posted_requests(c); +} + + +static int +ngx_http_lua_socket_tcp_conn_op_timeout_retval_handler(ngx_http_request_t *r, + ngx_http_lua_socket_tcp_upstream_t *u, lua_State *L) +{ + lua_pushnil(L); + lua_pushliteral(L, "timeout"); + return 2; +} + + +static void +ngx_http_lua_socket_tcp_resume_conn_op(ngx_http_lua_socket_pool_t *spool) +{ + ngx_queue_t *q; + ngx_http_lua_socket_tcp_conn_op_ctx_t *conn_op_ctx; + +#if (NGX_DEBUG) + ngx_http_lua_assert(spool->connections >= 0); + +#else + if (spool->connections < 0) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, + "lua tcp socket connections count mismatched for " + "connection pool \"%s\", connections: %i, size: %i", + spool->key, spool->connections, spool->size); + spool->connections = 0; + } +#endif + + /* we manually destroy wait_connect_op before triggering connect + * operation resumption, so that there is no resumption happens when Nginx + * is exiting. + */ + if (ngx_queue_empty(&spool->wait_connect_op)) { + return; + } + + q = ngx_queue_head(&spool->wait_connect_op); + conn_op_ctx = ngx_queue_data(q, ngx_http_lua_socket_tcp_conn_op_ctx_t, + queue); + ngx_log_debug4(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua tcp socket post connect operation resumption " + "u: %p, ctx: %p for connection pool \"%s\", " + "connections: %i", + conn_op_ctx->u, conn_op_ctx, spool->key, spool->connections); + + if (conn_op_ctx->event.timer_set) { + ngx_del_timer(&conn_op_ctx->event); + } + + conn_op_ctx->event.handler = + ngx_http_lua_socket_tcp_conn_op_resume_handler; + + ngx_post_event((&conn_op_ctx->event), &ngx_posted_events); +} + + +static void +ngx_http_lua_socket_tcp_conn_op_ctx_cleanup(void *data) +{ + ngx_http_lua_socket_tcp_upstream_t *u; + ngx_http_lua_socket_tcp_conn_op_ctx_t *conn_op_ctx = data; + + u = conn_op_ctx->u; + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, u->request->connection->log, 0, + "cleanup lua tcp socket conn_op_ctx: \"%V\"", + &u->request->uri); + + ngx_queue_insert_head(&u->socket_pool->cache_connect_op, + &conn_op_ctx->queue); +} + + +static void +ngx_http_lua_socket_tcp_conn_op_resume_handler(ngx_event_t *ev) +{ + ngx_queue_t *q; + ngx_connection_t *c; + ngx_http_lua_ctx_t *ctx; + ngx_http_request_t *r; + ngx_http_cleanup_t *cln; + ngx_http_lua_co_ctx_t *coctx; + ngx_http_lua_socket_pool_t *spool; + ngx_http_lua_socket_tcp_upstream_t *u; + ngx_http_lua_socket_tcp_conn_op_ctx_t *conn_op_ctx; + + conn_op_ctx = ev->data; + u = conn_op_ctx->u; + r = u->request; + spool = u->socket_pool; + + if (ngx_queue_empty(&spool->wait_connect_op)) { +#if (NGX_DEBUG) + ngx_http_lua_assert(!(spool->backlog >= 0 + && spool->connections > spool->size)); + +#else + if (spool->backlog >= 0 && spool->connections > spool->size) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, + "lua tcp socket connections count mismatched for " + "connection pool \"%s\", connections: %i, size: %i", + spool->key, spool->connections, spool->size); + spool->connections = spool->size; + } +#endif + + return; + } + + q = ngx_queue_head(&spool->wait_connect_op); + ngx_queue_remove(q); + + coctx = u->write_co_ctx; + coctx->cleanup = NULL; + /* note that we store conn_op_ctx in coctx->data instead of u */ + coctx->data = conn_op_ctx; + /* clear ngx_http_lua_tcp_queue_conn_op_cleanup */ + u->write_co_ctx = NULL; + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx == NULL) { + ngx_queue_insert_head(&spool->cache_connect_op, + &conn_op_ctx->queue); + return; + } + + ctx->cur_co_ctx = coctx; + + ngx_http_lua_assert(coctx && (!ngx_http_lua_is_thread(ctx) + || coctx->co_ref >= 0)); + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua tcp socket waking up the current request"); + + u->write_prepare_retvals = + ngx_http_lua_socket_tcp_conn_op_resume_retval_handler; + + c = r->connection; + + if (ctx->entered_content_phase) { + (void) ngx_http_lua_socket_tcp_conn_op_resume(r); + + } else { + cln = ngx_http_lua_cleanup_add(r, 0); + if (cln != NULL) { + cln->handler = ngx_http_lua_socket_tcp_conn_op_ctx_cleanup; + cln->data = conn_op_ctx; + conn_op_ctx->cleanup = &cln->handler; + } + + ctx->resume_handler = ngx_http_lua_socket_tcp_conn_op_resume; + ngx_http_core_run_phases(r); + } + + ngx_http_run_posted_requests(c); +} + + +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) +{ + int nret; + ngx_http_lua_ctx_t *ctx; + ngx_http_lua_co_ctx_t *coctx; + ngx_http_lua_socket_tcp_conn_op_ctx_t *conn_op_ctx; + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx == NULL) { + return NGX_ERROR; + } + + coctx = ctx->cur_co_ctx; + dd("coctx: %p", coctx); + conn_op_ctx = coctx->data; + if (conn_op_ctx->cleanup != NULL) { + *conn_op_ctx->cleanup = NULL; + ngx_http_lua_cleanup_free(r, conn_op_ctx->cleanup); + conn_op_ctx->cleanup = NULL; + } + + /* decrease pending connect operation counter */ + u->socket_pool->connections--; + + nret = ngx_http_lua_socket_tcp_connect_helper(L, u, r, ctx, + conn_op_ctx->host.data, + conn_op_ctx->host.len, + conn_op_ctx->port, 1); + ngx_queue_insert_head(&u->socket_pool->cache_connect_op, + &conn_op_ctx->queue); + + return nret; +} + + static void ngx_http_lua_socket_tcp_finalize(ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u) @@ -3589,21 +4193,21 @@ ngx_http_lua_socket_tcp_finalize(ngx_http_request_t *r, ngx_http_lua_socket_tcp_close_connection(c); u->peer.connection = NULL; - - if (!u->reused) { - return; - } + u->conn_closed = 1; spool = u->socket_pool; if (spool == NULL) { return; } - spool->active_connections--; + spool->connections--; - if (spool->active_connections == 0) { + if (spool->connections == 0) { ngx_http_lua_socket_free_pool(r->connection->log, spool); + return; } + + ngx_http_lua_socket_tcp_resume_conn_op(spool); } } @@ -3775,7 +4379,8 @@ ngx_http_lua_socket_tcp_receiveuntil(lua_State *L) return luaL_error(L, "no memory"); } - lua_pushlightuserdata(L, &ngx_http_lua_pattern_udata_metatable_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + pattern_udata_metatable_key)); lua_rawget(L, LUA_REGISTRYINDEX); lua_setmetatable(L, -2); @@ -4430,10 +5035,12 @@ ngx_http_lua_req_socket(lua_State *L) lua_createtable(L, 2 /* narr */, 3 /* nrec */); /* the object */ if (raw) { - lua_pushlightuserdata(L, &ngx_http_lua_raw_req_socket_metatable_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + raw_req_socket_metatable_key)); } else { - lua_pushlightuserdata(L, &ngx_http_lua_req_socket_metatable_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + req_socket_metatable_key)); } lua_rawget(L, LUA_REGISTRYINDEX); @@ -4445,7 +5052,8 @@ ngx_http_lua_req_socket(lua_State *L) } #if 1 - lua_pushlightuserdata(L, &ngx_http_lua_downstream_udata_metatable_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + downstream_udata_metatable_key)); lua_rawget(L, LUA_REGISTRYINDEX); lua_setmetatable(L, -2); #endif @@ -4572,20 +5180,18 @@ ngx_http_lua_socket_tcp_setkeepalive(lua_State *L) ngx_http_lua_socket_tcp_upstream_t *u; ngx_connection_t *c; ngx_http_lua_socket_pool_t *spool; - size_t size, key_len; ngx_str_t key; - ngx_uint_t i; ngx_queue_t *q; ngx_peer_connection_t *pc; - u_char *p; ngx_http_request_t *r; ngx_msec_t timeout; - ngx_uint_t pool_size; + ngx_int_t pool_size; int n; ngx_int_t rc; ngx_buf_t *b; + const char *msg; - ngx_http_lua_socket_pool_item_t *items, *item; + ngx_http_lua_socket_pool_item_t *item; n = lua_gettop(L); @@ -4596,17 +5202,6 @@ ngx_http_lua_socket_tcp_setkeepalive(lua_State *L) luaL_checktype(L, 1, LUA_TTABLE); - lua_pushlightuserdata(L, &ngx_http_lua_socket_pool_key); - lua_rawget(L, LUA_REGISTRYINDEX); - - lua_rawgeti(L, 1, SOCKET_KEY_INDEX); - key.data = (u_char *) lua_tolstring(L, -1, &key.len); - if (key.data == NULL) { - lua_pushnil(L); - lua_pushliteral(L, "key not found"); - return 2; - } - lua_rawgeti(L, 1, SOCKET_CTX_INDEX); u = lua_touserdata(L, -1); lua_pop(L, 1); @@ -4617,7 +5212,7 @@ ngx_http_lua_socket_tcp_setkeepalive(lua_State *L) return 2; } - /* stack: obj cache key */ + /* stack: obj timeout? size? */ pc = &u->peer; c = pc->connection; @@ -4669,9 +5264,32 @@ ngx_http_lua_socket_tcp_setkeepalive(lua_State *L) return 2; } + if (ngx_terminate || ngx_exiting) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, + "lua tcp socket set keepalive while process exiting, " + "closing connection %p", c); + + ngx_http_lua_socket_tcp_finalize(r, u); + lua_pushinteger(L, 1); + return 1; + } + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, "lua tcp socket set keepalive: saving connection %p", c); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask(socket_pool_key)); + lua_rawget(L, LUA_REGISTRYINDEX); + + /* stack: obj timeout? size? pools */ + + lua_rawgeti(L, 1, SOCKET_KEY_INDEX); + key.data = (u_char *) lua_tolstring(L, -1, &key.len); + if (key.data == NULL) { + lua_pushnil(L); + lua_pushliteral(L, "key not found"); + return 2; + } + dd("saving connection to key %s", lua_tostring(L, -1)); lua_pushvalue(L, -1); @@ -4679,7 +5297,7 @@ ngx_http_lua_socket_tcp_setkeepalive(lua_State *L) spool = lua_touserdata(L, -1); lua_pop(L, 1); - /* stack: obj timeout? size? cache key */ + /* stack: obj timeout? size? pools cache_key */ llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); @@ -4693,82 +5311,49 @@ ngx_http_lua_socket_tcp_setkeepalive(lua_State *L) pool_size = llcf->pool_size; } - if (pool_size == 0) { - lua_pushnil(L); - lua_pushliteral(L, "zero pool size"); - return 2; + if (pool_size <= 0) { + msg = lua_pushfstring(L, "bad \"pool_size\" option value: %i", + pool_size); + return luaL_argerror(L, n, msg); } - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua tcp socket connection pool size: %ui", pool_size); - - key_len = ngx_align(key.len + 1, sizeof(void *)); - - size = sizeof(ngx_http_lua_socket_pool_t) + key_len - 1 - + sizeof(ngx_http_lua_socket_pool_item_t) - * pool_size; - - spool = lua_newuserdata(L, size); - if (spool == NULL) { - return luaL_error(L, "no memory"); - } - - lua_pushlightuserdata(L, &ngx_http_lua_pool_udata_metatable_key); - lua_rawget(L, LUA_REGISTRYINDEX); - lua_setmetatable(L, -2); - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, - "lua tcp socket keepalive create connection pool for key" - " \"%s\"", lua_tostring(L, -2)); - - lua_rawset(L, -3); - - spool->active_connections = 0; - spool->lua_vm = ngx_http_lua_get_lua_vm(r, NULL); - - ngx_queue_init(&spool->cache); - ngx_queue_init(&spool->free); - - p = ngx_copy(spool->key, key.data, key.len); - *p++ = '\0'; - - items = (ngx_http_lua_socket_pool_item_t *) (spool->key + key_len); - - dd("items: %p", items); - - ngx_http_lua_assert((void *) items == ngx_align_ptr(items, - sizeof(void *))); - - for (i = 0; i < pool_size; i++) { - ngx_queue_insert_head(&spool->free, &items[i].queue); - items[i].socket_pool = spool; - } + ngx_http_lua_socket_tcp_create_socket_pool(L, r, key, pool_size, -1, + &spool); } if (ngx_queue_empty(&spool->free)) { q = ngx_queue_last(&spool->cache); ngx_queue_remove(q); - spool->active_connections--; item = ngx_queue_data(q, ngx_http_lua_socket_pool_item_t, queue); ngx_http_lua_socket_tcp_close_connection(item->connection); + /* only decrease the counter for connections which were counted */ + if (u->socket_pool != NULL) { + u->socket_pool->connections--; + } + } else { q = ngx_queue_head(&spool->free); ngx_queue_remove(q); item = ngx_queue_data(q, ngx_http_lua_socket_pool_item_t, queue); + + /* we should always increase connections after getting connected, + * and decrease connections after getting closed. + * however, we don't create connection pool in previous connect method. + * so we increase connections here for backward compatibility. + */ + if (u->socket_pool == NULL) { + spool->connections++; + } } item->connection = c; ngx_queue_insert_head(&spool->cache, q); - if (!u->reused) { - spool->active_connections++; - } - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0, "lua tcp socket clear current socket connection"); @@ -4837,48 +5422,33 @@ ngx_http_lua_socket_tcp_setkeepalive(lua_State *L) ngx_http_lua_socket_tcp_finalize(r, u); #endif + /* since we set u->peer->connection to NULL previously, the connect + * operation won't be resumed in the ngx_http_lua_socket_tcp_finalize. + * Therefore we need to resume it here. + */ + ngx_http_lua_socket_tcp_resume_conn_op(spool); + lua_pushinteger(L, 1); return 1; } static ngx_int_t -ngx_http_lua_get_keepalive_peer(ngx_http_request_t *r, lua_State *L, - int key_index, ngx_http_lua_socket_tcp_upstream_t *u) +ngx_http_lua_get_keepalive_peer(ngx_http_request_t *r, + ngx_http_lua_socket_tcp_upstream_t *u) { ngx_http_lua_socket_pool_item_t *item; ngx_http_lua_socket_pool_t *spool; ngx_http_cleanup_t *cln; ngx_queue_t *q; - int top; ngx_peer_connection_t *pc; ngx_connection_t *c; - top = lua_gettop(L); - - if (key_index < 0) { - key_index = top + key_index + 1; - } - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua tcp socket pool get keepalive peer"); pc = &u->peer; - - lua_pushlightuserdata(L, &ngx_http_lua_socket_pool_key); - lua_rawget(L, LUA_REGISTRYINDEX); /* table */ - lua_pushvalue(L, key_index); /* key */ - lua_rawget(L, -2); - - spool = lua_touserdata(L, -1); - if (spool == NULL) { - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0, - "lua tcp socket keepalive connection pool not found"); - lua_settop(L, top); - return NGX_DECLINED; - } - - u->socket_pool = spool; + spool = u->socket_pool; if (!ngx_queue_empty(&spool->cache)) { q = ngx_queue_head(&spool->cache); @@ -4923,7 +5493,6 @@ ngx_http_lua_get_keepalive_peer(ngx_http_request_t *r, lua_State *L, cln = ngx_http_lua_cleanup_add(r, 0); if (cln == NULL) { u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_ERROR; - lua_settop(L, top); return NGX_ERROR; } @@ -4932,16 +5501,12 @@ ngx_http_lua_get_keepalive_peer(ngx_http_request_t *r, lua_State *L, u->cleanup = &cln->handler; } - lua_settop(L, top); - return NGX_OK; } ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0, "lua tcp socket keepalive: connection pool empty"); - lua_settop(L, top); - return NGX_DECLINED; } @@ -5013,13 +5578,15 @@ close: ngx_queue_remove(&item->queue); ngx_queue_insert_head(&spool->free, &item->queue); - spool->active_connections--; + spool->connections--; - dd("keepalive: active connections: %u", - (unsigned) spool->active_connections); + dd("keepalive: connections: %u", (unsigned) spool->connections); - if (spool->active_connections == 0) { + if (spool->connections == 0) { ngx_http_lua_socket_free_pool(ev->log, spool); + + } else { + ngx_http_lua_socket_tcp_resume_conn_op(spool); } return NGX_DECLINED; @@ -5037,7 +5604,7 @@ ngx_http_lua_socket_free_pool(ngx_log_t *log, ngx_http_lua_socket_pool_t *spool) L = spool->lua_vm; - lua_pushlightuserdata(L, &ngx_http_lua_socket_pool_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask(socket_pool_key)); lua_rawget(L, LUA_REGISTRYINDEX); lua_pushstring(L, (char *) spool->key); lua_pushnil(L); @@ -5049,9 +5616,10 @@ ngx_http_lua_socket_free_pool(ngx_log_t *log, ngx_http_lua_socket_pool_t *spool) static void ngx_http_lua_socket_shutdown_pool_helper(ngx_http_lua_socket_pool_t *spool) { - ngx_queue_t *q; - ngx_connection_t *c; - ngx_http_lua_socket_pool_item_t *item; + ngx_queue_t *q; + ngx_connection_t *c; + ngx_http_lua_socket_pool_item_t *item; + ngx_http_lua_socket_tcp_conn_op_ctx_t *conn_op_ctx; while (!ngx_queue_empty(&spool->cache)) { q = ngx_queue_head(&spool->cache); @@ -5065,7 +5633,29 @@ ngx_http_lua_socket_shutdown_pool_helper(ngx_http_lua_socket_pool_t *spool) ngx_queue_insert_head(&spool->free, q); } - spool->active_connections = 0; + while (!ngx_queue_empty(&spool->cache_connect_op)) { + q = ngx_queue_head(&spool->cache_connect_op); + ngx_queue_remove(q); + conn_op_ctx = ngx_queue_data(q, ngx_http_lua_socket_tcp_conn_op_ctx_t, + queue); + ngx_http_lua_socket_tcp_free_conn_op_ctx(conn_op_ctx); + } + + while (!ngx_queue_empty(&spool->wait_connect_op)) { + q = ngx_queue_head(&spool->wait_connect_op); + ngx_queue_remove(q); + conn_op_ctx = ngx_queue_data(q, ngx_http_lua_socket_tcp_conn_op_ctx_t, + queue); + + if (conn_op_ctx->event.timer_set) { + ngx_del_timer(&conn_op_ctx->event); + } + + ngx_http_lua_socket_tcp_free_conn_op_ctx(conn_op_ctx); + } + + /* spool->connections will be decreased down to zero in + * ngx_http_lua_socket_tcp_finalize */ } @@ -5319,6 +5909,13 @@ static ngx_int_t ngx_http_lua_socket_insert_buffer(ngx_http_request_t *r, } +static ngx_int_t +ngx_http_lua_socket_tcp_conn_op_resume(ngx_http_request_t *r) +{ + return ngx_http_lua_socket_tcp_resume_helper(r, SOCKET_OP_RESUME_CONN); +} + + static ngx_int_t ngx_http_lua_socket_tcp_conn_resume(ngx_http_request_t *r) { @@ -5343,13 +5940,14 @@ ngx_http_lua_socket_tcp_write_resume(ngx_http_request_t *r) static ngx_int_t ngx_http_lua_socket_tcp_resume_helper(ngx_http_request_t *r, int socket_op) { - int nret; - lua_State *vm; - ngx_int_t rc; - ngx_uint_t nreqs; - ngx_connection_t *c; - ngx_http_lua_ctx_t *ctx; - ngx_http_lua_co_ctx_t *coctx; + int nret; + lua_State *vm; + ngx_int_t rc; + ngx_uint_t nreqs; + ngx_connection_t *c; + ngx_http_lua_ctx_t *ctx; + ngx_http_lua_co_ctx_t *coctx; + ngx_http_lua_socket_tcp_conn_op_ctx_t *conn_op_ctx; ngx_http_lua_socket_tcp_retval_handler prepare_retvals; @@ -5369,15 +5967,22 @@ ngx_http_lua_socket_tcp_resume_helper(ngx_http_request_t *r, int socket_op) dd("coctx: %p", coctx); - u = coctx->data; - switch (socket_op) { + + case SOCKET_OP_RESUME_CONN: + conn_op_ctx = coctx->data; + u = conn_op_ctx->u; + prepare_retvals = u->write_prepare_retvals; + break; + case SOCKET_OP_CONNECT: case SOCKET_OP_WRITE: + u = coctx->data; prepare_retvals = u->write_prepare_retvals; break; case SOCKET_OP_READ: + u = coctx->data; prepare_retvals = u->read_prepare_retvals; break; @@ -5391,6 +5996,15 @@ ngx_http_lua_socket_tcp_resume_helper(ngx_http_request_t *r, int socket_op) "u:%p", prepare_retvals, u); nret = prepare_retvals(r, u, ctx->cur_co_ctx->co); + if (socket_op == SOCKET_OP_CONNECT + && nret > 1 + && !u->conn_closed + && u->socket_pool != NULL) + { + u->socket_pool->connections--; + ngx_http_lua_socket_tcp_resume_conn_op(u->socket_pool); + } + if (nret == NGX_AGAIN) { return NGX_DONE; } @@ -5422,6 +6036,36 @@ ngx_http_lua_socket_tcp_resume_helper(ngx_http_request_t *r, int socket_op) } +static void +ngx_http_lua_tcp_queue_conn_op_cleanup(void *data) +{ + ngx_http_lua_co_ctx_t *coctx = data; + ngx_http_lua_socket_tcp_upstream_t *u; + ngx_http_lua_socket_tcp_conn_op_ctx_t *conn_op_ctx; + + conn_op_ctx = coctx->data; + u = conn_op_ctx->u; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua tcp socket abort queueing, conn_op_ctx: %p, u: %p", + conn_op_ctx, u); + + if (conn_op_ctx->event.posted) { + ngx_delete_posted_event(&conn_op_ctx->event); + + } else if (conn_op_ctx->event.timer_set) { + ngx_del_timer(&conn_op_ctx->event); + } + + ngx_queue_remove(&conn_op_ctx->queue); + ngx_queue_insert_head(&u->socket_pool->cache_connect_op, + &conn_op_ctx->queue); + + u->socket_pool->connections--; + ngx_http_lua_socket_tcp_resume_conn_op(u->socket_pool); +} + + static void ngx_http_lua_tcp_resolve_cleanup(void *data) { @@ -5437,6 +6081,11 @@ ngx_http_lua_tcp_resolve_cleanup(void *data) return; } + if (u->socket_pool != NULL) { + u->socket_pool->connections--; + ngx_http_lua_socket_tcp_resume_conn_op(u->socket_pool); + } + rctx = u->resolved->ctx; if (rctx == NULL) { return; @@ -5496,7 +6145,8 @@ ngx_http_lua_cleanup_conn_pools(lua_State *L) { ngx_http_lua_socket_pool_t *spool; - lua_pushlightuserdata(L, &ngx_http_lua_socket_pool_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + socket_pool_key)); lua_rawget(L, LUA_REGISTRYINDEX); /* table */ lua_pushnil(L); /* first key */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_socket_tcp.h b/debian/modules/http-lua/src/ngx_http_lua_socket_tcp.h index dbdee41..091e437 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_socket_tcp.h +++ b/debian/modules/http-lua/src/ngx_http_lua_socket_tcp.h @@ -35,17 +35,39 @@ typedef void (*ngx_http_lua_socket_tcp_upstream_handler_pt) (ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u); +typedef struct { + ngx_event_t event; + ngx_queue_t queue; + ngx_str_t host; + ngx_http_cleanup_pt *cleanup; + ngx_http_lua_socket_tcp_upstream_t *u; + in_port_t port; +} ngx_http_lua_socket_tcp_conn_op_ctx_t; + + +#define ngx_http_lua_socket_tcp_free_conn_op_ctx(conn_op_ctx) \ + ngx_free(conn_op_ctx->host.data); \ + ngx_free(conn_op_ctx) + + typedef struct { lua_State *lua_vm; - /* active connections == out-of-pool reused connections - * + in-pool connections */ - ngx_uint_t active_connections; + ngx_int_t size; + ngx_queue_t cache_connect_op; + ngx_queue_t wait_connect_op; + + /* connections == active connections + pending connect operations, + * while active connections == out-of-pool reused connections + * + in-pool connections */ + ngx_int_t connections; /* queues of ngx_http_lua_socket_pool_item_t: */ ngx_queue_t cache; ngx_queue_t free; + ngx_int_t backlog; + u_char key[1]; } ngx_http_lua_socket_pool_t; @@ -104,6 +126,7 @@ struct ngx_http_lua_socket_tcp_upstream_s { unsigned raw_downstream:1; unsigned read_closed:1; unsigned write_closed:1; + unsigned conn_closed:1; #if (NGX_HTTP_SSL) unsigned ssl_verify:1; unsigned ssl_session_reuse:1; diff --git a/debian/modules/http-lua/src/ngx_http_lua_socket_udp.c b/debian/modules/http-lua/src/ngx_http_lua_socket_udp.c index 8927f41..cbc32d6 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_socket_udp.c +++ b/debian/modules/http-lua/src/ngx_http_lua_socket_udp.c @@ -81,7 +81,8 @@ ngx_http_lua_inject_socket_udp_api(ngx_log_t *log, lua_State *L) lua_setfield(L, -2, "udp"); /* ngx socket */ /* udp socket object metatable */ - lua_pushlightuserdata(L, &ngx_http_lua_socket_udp_metatable_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + socket_udp_metatable_key)); lua_createtable(L, 0 /* narr */, 6 /* nrec */); lua_pushcfunction(L, ngx_http_lua_socket_udp_setpeername); @@ -105,7 +106,8 @@ ngx_http_lua_inject_socket_udp_api(ngx_log_t *log, lua_State *L) /* }}} */ /* udp socket object metatable */ - lua_pushlightuserdata(L, &ngx_http_lua_udp_udata_metatable_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + udp_udata_metatable_key)); lua_createtable(L, 0 /* narr */, 1 /* nrec */); /* metatable */ lua_pushcfunction(L, ngx_http_lua_socket_udp_upstream_destroy); lua_setfield(L, -2, "__gc"); @@ -144,7 +146,8 @@ ngx_http_lua_socket_udp(lua_State *L) | NGX_HTTP_LUA_CONTEXT_SSL_CERT); lua_createtable(L, 3 /* narr */, 1 /* nrec */); - lua_pushlightuserdata(L, &ngx_http_lua_socket_udp_metatable_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + socket_udp_metatable_key)); lua_rawget(L, LUA_REGISTRYINDEX); lua_setmetatable(L, -2); @@ -263,7 +266,8 @@ ngx_http_lua_socket_udp_setpeername(lua_State *L) } #if 1 - lua_pushlightuserdata(L, &ngx_http_lua_udp_udata_metatable_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + udp_udata_metatable_key)); lua_rawget(L, LUA_REGISTRYINDEX); lua_setmetatable(L, -2); #endif diff --git a/debian/modules/http-lua/src/ngx_http_lua_ssl_certby.c b/debian/modules/http-lua/src/ngx_http_lua_ssl_certby.c index 453a5c7..622d0a5 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_ssl_certby.c +++ b/debian/modules/http-lua/src/ngx_http_lua_ssl_certby.c @@ -498,9 +498,11 @@ ngx_http_lua_ssl_cert_by_chunk(lua_State *L, ngx_http_request_t *r) /* 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); diff --git a/debian/modules/http-lua/src/ngx_http_lua_ssl_session_fetchby.c b/debian/modules/http-lua/src/ngx_http_lua_ssl_session_fetchby.c index 0b88a87..303efb4 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_ssl_session_fetchby.c +++ b/debian/modules/http-lua/src/ngx_http_lua_ssl_session_fetchby.c @@ -505,9 +505,11 @@ ngx_http_lua_ssl_sess_fetch_by_chunk(lua_State *L, ngx_http_request_t *r) /* 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); diff --git a/debian/modules/http-lua/src/ngx_http_lua_ssl_session_storeby.c b/debian/modules/http-lua/src/ngx_http_lua_ssl_session_storeby.c index 7609c39..a02f729 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_ssl_session_storeby.c +++ b/debian/modules/http-lua/src/ngx_http_lua_ssl_session_storeby.c @@ -380,6 +380,8 @@ ngx_http_lua_ssl_sess_store_by_chunk(lua_State *L, ngx_http_request_t *r) /* init nginx context in Lua VM */ ngx_http_lua_set_req(L, r); + +#ifndef OPENRESTY_LUAJIT ngx_http_lua_create_new_globals_table(L, 0 /* narr */, 1 /* nrec */); /* {{{ make new env inheriting main thread's globals table */ @@ -390,6 +392,7 @@ ngx_http_lua_ssl_sess_store_by_chunk(lua_State *L, ngx_http_request_t *r) /* }}} */ lua_setfenv(L, -2); /* set new running env for the code closure */ +#endif lua_pushcfunction(L, ngx_http_lua_traceback); lua_insert(L, 1); /* put it under chunk and args */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_string.c b/debian/modules/http-lua/src/ngx_http_lua_string.c index 239b232..bdadeb4 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_string.c +++ b/debian/modules/http-lua/src/ngx_http_lua_string.c @@ -762,6 +762,20 @@ ngx_http_lua_ffi_escape_uri(const u_char *src, size_t len, u_char *dst) ngx_http_lua_escape_uri(dst, (u_char *) src, len, NGX_ESCAPE_URI_COMPONENT); } + +void +ngx_http_lua_ffi_str_replace_char(u_char *buf, size_t len, const u_char find, + const u_char replace) +{ + while (len) { + if (*buf == find) { + *buf = replace; + } + + buf++; + len--; + } +} #endif /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_subrequest.c b/debian/modules/http-lua/src/ngx_http_lua_subrequest.c index 826a43c..f312b65 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_subrequest.c +++ b/debian/modules/http-lua/src/ngx_http_lua_subrequest.c @@ -1031,6 +1031,14 @@ ngx_http_lua_post_subrequest(ngx_http_request_t *r, void *data, ngx_int_t rc) dd("pr_coctx status: %d", (int) pr_coctx->sr_statuses[ctx->index]); /* copy subrequest response headers */ + if (ctx->headers_set) { + rc = ngx_http_lua_set_content_type(r, ctx); + if (rc != NGX_OK) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "failed to set default content type: %i", rc); + return NGX_ERROR; + } + } pr_coctx->sr_headers[ctx->index] = &r->headers_out; diff --git a/debian/modules/http-lua/src/ngx_http_lua_timer.c b/debian/modules/http-lua/src/ngx_http_lua_timer.c index 596b2f7..e92c211 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_timer.c +++ b/debian/modules/http-lua/src/ngx_http_lua_timer.c @@ -220,6 +220,7 @@ ngx_http_lua_ngx_timer_helper(lua_State *L, int every) ngx_http_lua_probe_user_coroutine_create(r, L, co); +#ifndef OPENRESTY_LUAJIT lua_createtable(co, 0, 0); /* the new globals table */ /* co stack: global_tb */ @@ -232,6 +233,7 @@ ngx_http_lua_ngx_timer_helper(lua_State *L, int every) /* co stack: global_tb */ ngx_http_lua_set_globals_table(co); +#endif /* co stack: */ @@ -251,12 +253,15 @@ ngx_http_lua_ngx_timer_helper(lua_State *L, int every) /* L stack: time func [args] thread */ /* co stack: func */ +#ifndef OPENRESTY_LUAJIT ngx_http_lua_get_globals_table(co); lua_setfenv(co, -2); +#endif /* co stack: func */ - lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + coroutines_key)); lua_rawget(L, LUA_REGISTRYINDEX); /* L stack: time func [args] thread coroutines */ @@ -345,6 +350,9 @@ ngx_http_lua_ngx_timer_helper(lua_State *L, int every) ngx_add_timer(ev, delay); + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "created timer (co: %p delay: %M ms)", tctx->co, delay); + lua_pushinteger(L, 1); return 1; @@ -358,7 +366,8 @@ nomem: ngx_free(ev); } - lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + coroutines_key)); lua_rawget(L, LUA_REGISTRYINDEX); luaL_unref(L, -1, co_ref); @@ -387,6 +396,7 @@ ngx_http_lua_timer_copy(ngx_http_lua_timer_ctx_t *old_tctx) co = lua_newthread(vm); +#ifndef OPENRESTY_LUAJIT lua_createtable(co, 0, 0); /* the new globals table */ /* co stack: global_tb */ @@ -399,6 +409,7 @@ ngx_http_lua_timer_copy(ngx_http_lua_timer_ctx_t *old_tctx) /* co stack: global_tb */ ngx_http_lua_set_globals_table(co); +#endif /* co stack: */ @@ -418,12 +429,15 @@ ngx_http_lua_timer_copy(ngx_http_lua_timer_ctx_t *old_tctx) /* L stack: func [args] thread */ /* co stack: func */ +#ifndef OPENRESTY_LUAJIT ngx_http_lua_get_globals_table(co); lua_setfenv(co, -2); +#endif /* co stack: func */ - lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + coroutines_key)); lua_rawget(L, LUA_REGISTRYINDEX); /* L stack: func [args] thread coroutines */ @@ -498,6 +512,10 @@ ngx_http_lua_timer_copy(ngx_http_lua_timer_ctx_t *old_tctx) ngx_add_timer(ev, tctx->delay); + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "created next timer (co: %p delay: %M ms)", tctx->co, + tctx->delay); + return NGX_OK; nomem: @@ -512,7 +530,8 @@ nomem: /* L stack: func [args] */ - lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + coroutines_key)); lua_rawget(L, LUA_REGISTRYINDEX); luaL_unref(L, -1, co_ref); @@ -568,6 +587,9 @@ ngx_http_lua_timer_handler(ngx_event_t *ev) c = ngx_http_lua_create_fake_connection(tctx.pool); if (c == NULL) { + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, + "failed to create fake connection to run timer (co: %p)", + tctx.co); goto failed; } @@ -579,6 +601,9 @@ ngx_http_lua_timer_handler(ngx_event_t *ev) r = ngx_http_lua_create_fake_request(c); if (r == NULL) { + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, + "failed to create fake request to run timer (co: %p)", + tctx.co); goto failed; } @@ -614,6 +639,8 @@ ngx_http_lua_timer_handler(ngx_event_t *ev) ctx = ngx_http_lua_create_ctx(r); if (ctx == NULL) { + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, + "failed to create ctx to run timer (co: %p)", tctx.co); goto failed; } @@ -622,6 +649,9 @@ ngx_http_lua_timer_handler(ngx_event_t *ev) pcln = ngx_pool_cleanup_add(r->pool, 0); if (pcln == NULL) { + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, + "failed to add vm cleanup to run timer (co: %p)", + tctx.co); goto failed; } @@ -635,6 +665,9 @@ ngx_http_lua_timer_handler(ngx_event_t *ev) cln = ngx_http_cleanup_add(r, 0); if (cln == NULL) { + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, + "failed to add request cleanup to run timer (co: %p)", + tctx.co); goto failed; } @@ -692,7 +725,8 @@ ngx_http_lua_timer_handler(ngx_event_t *ev) failed: if (tctx.co_ref && tctx.co) { - lua_pushlightuserdata(tctx.co, &ngx_http_lua_coroutines_key); + lua_pushlightuserdata(tctx.co, ngx_http_lua_lightudata_mask( + coroutines_key)); lua_rawget(tctx.co, LUA_REGISTRYINDEX); luaL_unref(tctx.co, -1, tctx.co_ref); lua_settop(tctx.co, 0); diff --git a/debian/modules/http-lua/src/ngx_http_lua_uthread.c b/debian/modules/http-lua/src/ngx_http_lua_uthread.c index 8195ec0..43517a0 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_uthread.c +++ b/debian/modules/http-lua/src/ngx_http_lua_uthread.c @@ -70,7 +70,8 @@ ngx_http_lua_uthread_spawn(lua_State *L) /* anchor the newly created coroutine into the Lua registry */ - lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + coroutines_key)); lua_rawget(L, LUA_REGISTRYINDEX); lua_pushvalue(L, -2); coctx->co_ref = luaL_ref(L, -2); diff --git a/debian/modules/http-lua/src/ngx_http_lua_util.c b/debian/modules/http-lua/src/ngx_http_lua_util.c index f7a537e..c12262e 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_util.c +++ b/debian/modules/http-lua/src/ngx_http_lua_util.c @@ -70,6 +70,25 @@ #endif +#if (NGX_HTTP_LUA_HAVE_SA_RESTART) +#define NGX_HTTP_LUA_SA_RESTART_SIGS { \ + ngx_signal_value(NGX_RECONFIGURE_SIGNAL), \ + ngx_signal_value(NGX_REOPEN_SIGNAL), \ + ngx_signal_value(NGX_NOACCEPT_SIGNAL), \ + ngx_signal_value(NGX_TERMINATE_SIGNAL), \ + ngx_signal_value(NGX_SHUTDOWN_SIGNAL), \ + ngx_signal_value(NGX_CHANGEBIN_SIGNAL), \ + SIGALRM, \ + SIGINT, \ + SIGIO, \ + SIGCHLD, \ + SIGSYS, \ + SIGPIPE, \ + 0 \ +}; +#endif + + char ngx_http_lua_code_cache_key; char ngx_http_lua_regex_cache_key; char ngx_http_lua_socket_pool_key; @@ -128,6 +147,13 @@ static int ngx_http_lua_get_raw_phase_context(lua_State *L); #define LUA_PATH_SEP ";" #endif + +#if !defined(LUA_DEFAULT_PATH) && (NGX_DEBUG) +#define LUA_DEFAULT_PATH "../lua-resty-core/lib/?.lua;" \ + "../lua-resty-lrucache/lib/?.lua" +#endif + + #define AUX_MARK "\1" @@ -171,6 +197,7 @@ ngx_http_lua_set_path(ngx_cycle_t *cycle, lua_State *L, int tab_idx, } +#ifndef OPENRESTY_LUAJIT /** * Create new table and set _G field to itself. * @@ -185,6 +212,7 @@ ngx_http_lua_create_new_globals_table(lua_State *L, int narr, int nrec) lua_pushvalue(L, -1); lua_setfield(L, -2, "_G"); } +#endif /* OPENRESTY_LUAJIT */ static lua_State * @@ -313,11 +341,13 @@ ngx_http_lua_new_thread(ngx_http_request_t *r, lua_State *L, int *ref) base = lua_gettop(L); - lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + coroutines_key)); lua_rawget(L, LUA_REGISTRYINDEX); co = lua_newthread(L); +#ifndef OPENRESTY_LUAJIT /* {{{ inherit coroutine's globals to main thread's globals table * for print() function will try to find tostring() in current * globals table. @@ -332,6 +362,7 @@ ngx_http_lua_new_thread(ngx_http_request_t *r, lua_State *L, int *ref) ngx_http_lua_set_globals_table(co); /* }}} */ +#endif /* OPENRESTY_LUAJIT */ *ref = luaL_ref(L, -2); @@ -356,7 +387,8 @@ ngx_http_lua_del_thread(ngx_http_request_t *r, lua_State *L, ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua deleting light thread"); - lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + coroutines_key)); lua_rawget(L, LUA_REGISTRYINDEX); ngx_http_lua_probe_thread_delete(r, coctx->co, ctx); @@ -408,7 +440,9 @@ ngx_http_lua_send_header_if_needed(ngx_http_request_t *r, r->headers_out.status = NGX_HTTP_OK; } - if (!ctx->headers_set && ngx_http_lua_set_content_type(r) != NGX_OK) { + if (!ctx->mime_set + && ngx_http_lua_set_content_type(r, ctx) != NGX_OK) + { return NGX_ERROR; } @@ -657,7 +691,8 @@ ngx_http_lua_init_registry(lua_State *L, ngx_log_t *log) /* {{{ register a table to anchor lua coroutines reliably: * {([int]ref) = [cort]} */ - lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + coroutines_key)); lua_createtable(L, 0, 32 /* nrec */); lua_rawset(L, LUA_REGISTRYINDEX); /* }}} */ @@ -668,20 +703,23 @@ ngx_http_lua_init_registry(lua_State *L, ngx_log_t *log) lua_rawset(L, LUA_REGISTRYINDEX); /* create the registry entry for the Lua socket connection pool table */ - lua_pushlightuserdata(L, &ngx_http_lua_socket_pool_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + socket_pool_key)); lua_createtable(L, 0, 8 /* nrec */); lua_rawset(L, LUA_REGISTRYINDEX); #if (NGX_PCRE) /* create the registry entry for the Lua precompiled regex object cache */ - lua_pushlightuserdata(L, &ngx_http_lua_regex_cache_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + regex_cache_key)); lua_createtable(L, 0, 16 /* nrec */); lua_rawset(L, LUA_REGISTRYINDEX); #endif /* {{{ register table to cache user code: * { [(string)cache_key] = } */ - lua_pushlightuserdata(L, &ngx_http_lua_code_cache_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + code_cache_key)); lua_createtable(L, 0, 8 /* nrec */); lua_rawset(L, LUA_REGISTRYINDEX); /* }}} */ @@ -695,9 +733,6 @@ ngx_http_lua_init_globals(lua_State *L, ngx_cycle_t *cycle, ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "lua initializing lua globals"); - lua_pushlightuserdata(L, cycle); - lua_setglobal(L, "__ngx_cycle"); - #if defined(NDK) && NDK ngx_http_lua_inject_ndk_api(L); #endif /* defined(NDK) && NDK */ @@ -756,6 +791,52 @@ ngx_http_lua_inject_ngx_api(lua_State *L, ngx_http_lua_main_conf_t *lmcf, lua_setglobal(L, "ngx"); ngx_http_lua_inject_coroutine_api(log, L); + +#ifdef OPENRESTY_LUAJIT + { + int rc; + + const char buf[] = + "local ngx_log = ngx.log\n" + "local ngx_WARN = ngx.WARN\n" + "local tostring = tostring\n" + "local ngx_get_phase = ngx.get_phase\n" + "local traceback = require 'debug'.traceback\n" + "local function newindex(table, key, value)\n" + "rawset(table, key, value)\n" + "local phase = ngx_get_phase()\n" + "if phase == 'init_worker' or phase == 'init' then\n" + "return\n" + "end\n" + "ngx_log(ngx_WARN, 'writing a global lua variable " + "(\\'', tostring(key), '\\') which may lead to " + "race conditions between concurrent requests, so " + "prefer the use of \\'local\\' variables', " + "traceback('', 2))\n" + "end\n" + "setmetatable(_G, { __newindex = newindex })\n" + ; + + rc = luaL_loadbuffer(L, buf, sizeof(buf) - 1, "=_G write guard"); + + if (rc != 0) { + ngx_log_error(NGX_LOG_ERR, log, 0, + "failed to load Lua code (%i): %s", + rc, lua_tostring(L, -1)); + + lua_pop(L, 1); + return; + } + + rc = lua_pcall(L, 0, 0, 0); + if (rc != 0) { + ngx_log_error(NGX_LOG_ERR, log, 0, + "failed to run Lua code (%i): %s", + rc, lua_tostring(L, -1)); + lua_pop(L, 1); + } + } +#endif } @@ -2954,12 +3035,12 @@ ngx_http_lua_param_get(lua_State *L) | NGX_HTTP_LUA_CONTEXT_BODY_FILTER); if (ctx->context & (NGX_HTTP_LUA_CONTEXT_SET)) { - return ngx_http_lua_setby_param_get(L); + 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); + return ngx_http_lua_body_filter_param_get(L, r); } @@ -3156,7 +3237,8 @@ ngx_http_lua_finalize_threads(ngx_http_request_t *r, ngx_http_lua_probe_thread_delete(r, coctx->co, ctx); - lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + coroutines_key)); lua_rawget(L, LUA_REGISTRYINDEX); inited = 1; @@ -3194,7 +3276,8 @@ ngx_http_lua_finalize_threads(ngx_http_request_t *r, ngx_http_lua_probe_thread_delete(r, coctx->co, ctx); if (!inited) { - lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + coroutines_key)); lua_rawget(L, LUA_REGISTRYINDEX); inited = 1; } @@ -3223,7 +3306,8 @@ ngx_http_lua_finalize_threads(ngx_http_request_t *r, ngx_http_lua_probe_thread_delete(r, coctx->co, ctx); if (!inited) { - lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + coroutines_key)); lua_rawget(L, LUA_REGISTRYINDEX); inited = 1; } @@ -3736,6 +3820,7 @@ ngx_http_lua_init_vm(lua_State *parent_vm, ngx_cycle_t *cycle, ngx_pool_t *pool, ngx_http_lua_main_conf_t *lmcf, ngx_log_t *log, ngx_pool_cleanup_t **pcln) { + int rc; lua_State *L; ngx_uint_t i; ngx_pool_cleanup_t *cln; @@ -3778,6 +3863,11 @@ ngx_http_lua_init_vm(lua_State *parent_vm, ngx_cycle_t *cycle, *pcln = cln; } +#ifdef OPENRESTY_LUAJIT + /* load FFI library first since cdata needs it */ + luaopen_ffi(L); +#endif + if (lmcf->preload_hooks) { /* register the 3rd-party module's preload hooks */ @@ -3798,6 +3888,21 @@ ngx_http_lua_init_vm(lua_State *parent_vm, ngx_cycle_t *cycle, lua_pop(L, 2); } + if (lmcf->load_resty_core) { + lua_getglobal(L, "require"); + lua_pushstring(L, "resty.core"); + + rc = lua_pcall(L, 1, 1, 0); + if (rc != 0) { + ngx_log_error(NGX_LOG_ERR, log, 0, + "lua_load_resty_core failed to load the resty.core " + "module from https://github.com/openresty/lua-resty" + "-core; ensure you are using an OpenResty release " + "from https://openresty.org/en/download.html " + "(rc: %i, reason: %s)", rc, lua_tostring(L, -1)); + } + } + return L; } @@ -4041,7 +4146,12 @@ ngx_http_lua_get_raw_phase_context(lua_State *L) ngx_http_request_t *r; ngx_http_lua_ctx_t *ctx; +#ifdef OPENRESTY_LUAJIT + r = lua_getexdata(L); +#else r = lua_touserdata(L, 1); +#endif + if (r == NULL) { return 0; } @@ -4129,4 +4239,32 @@ ngx_http_lua_cleanup_free(ngx_http_request_t *r, ngx_http_cleanup_pt *cleanup) } +#if (NGX_HTTP_LUA_HAVE_SA_RESTART) +void +ngx_http_lua_set_sa_restart(ngx_log_t *log) +{ + int *signo; + int sigs[] = NGX_HTTP_LUA_SA_RESTART_SIGS; + struct sigaction act; + + for (signo = sigs; *signo != 0; signo++) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, + "setting SA_RESTART for signal %d", *signo); + + if (sigaction(*signo, NULL, &act) != 0) { + ngx_log_error(NGX_LOG_WARN, log, ngx_errno, "failed to get " + "sigaction for signal %d", *signo); + } + + act.sa_flags |= SA_RESTART; + + if (sigaction(*signo, &act, NULL) != 0) { + ngx_log_error(NGX_LOG_WARN, log, ngx_errno, "failed to set " + "sigaction for signal %d", *signo); + } + } +} +#endif + + /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_util.h b/debian/modules/http-lua/src/ngx_http_lua_util.h index 7dcc6f7..f08f481 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_util.h +++ b/debian/modules/http-lua/src/ngx_http_lua_util.h @@ -9,6 +9,11 @@ #define _NGX_HTTP_LUA_UTIL_H_INCLUDED_ +#ifdef DDEBUG +#include "ddebug.h" +#endif + + #include "ngx_http_lua_common.h" #include "ngx_http_lua_api.h" @@ -188,7 +193,9 @@ ngx_int_t ngx_http_lua_open_and_stat_file(u_char *name, ngx_chain_t *ngx_http_lua_chain_get_free_buf(ngx_log_t *log, ngx_pool_t *p, ngx_chain_t **free, size_t len); +#ifndef OPENRESTY_LUAJIT void ngx_http_lua_create_new_globals_table(lua_State *L, int narr, int nrec); +#endif int ngx_http_lua_traceback(lua_State *L); @@ -243,6 +250,9 @@ ngx_http_cleanup_t *ngx_http_lua_cleanup_add(ngx_http_request_t *r, void ngx_http_lua_cleanup_free(ngx_http_request_t *r, ngx_http_cleanup_pt *cleanup); +#if (NGX_HTTP_LUA_HAVE_SA_RESTART) +void ngx_http_lua_set_sa_restart(ngx_log_t *log); +#endif #define ngx_http_lua_check_if_abortable(L, ctx) \ if ((ctx)->no_abort) { \ @@ -282,7 +292,9 @@ ngx_http_lua_create_ctx(ngx_http_request_t *r) if (!llcf->enable_code_cache && r->connection->fd != (ngx_socket_t) -1) { lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); +#ifdef DDEBUG dd("lmcf: %p", lmcf); +#endif L = ngx_http_lua_init_vm(lmcf->lua, lmcf->cycle, r->pool, lmcf, r->connection->log, &cln); @@ -323,7 +335,11 @@ ngx_http_lua_get_lua_vm(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx) } lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); + +#ifdef DDEBUG dd("lmcf->lua: %p", lmcf->lua); +#endif + return lmcf->lua; } @@ -334,6 +350,9 @@ ngx_http_lua_get_lua_vm(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx) static ngx_inline ngx_http_request_t * ngx_http_lua_get_req(lua_State *L) { +#ifdef OPENRESTY_LUAJIT + return lua_getexdata(L); +#else ngx_http_request_t *r; lua_getglobal(L, ngx_http_lua_req_key); @@ -341,14 +360,19 @@ ngx_http_lua_get_req(lua_State *L) lua_pop(L, 1); return r; +#endif } static ngx_inline void ngx_http_lua_set_req(lua_State *L, ngx_http_request_t *r) { +#ifdef OPENRESTY_LUAJIT + lua_setexdata(L, (void *) r); +#else lua_pushlightuserdata(L, r); lua_setglobal(L, ngx_http_lua_req_key); +#endif } @@ -387,10 +411,12 @@ ngx_http_lua_hash_str(u_char *src, size_t n) static ngx_inline ngx_int_t -ngx_http_lua_set_content_type(ngx_http_request_t *r) +ngx_http_lua_set_content_type(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx) { ngx_http_lua_loc_conf_t *llcf; + ctx->mime_set = 1; + llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); if (llcf->use_default_type && r->headers_out.status != NGX_HTTP_NOT_MODIFIED) diff --git a/debian/modules/http-lua/src/ngx_http_lua_worker.c b/debian/modules/http-lua/src/ngx_http_lua_worker.c index 461509b..33cfa11 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_worker.c +++ b/debian/modules/http-lua/src/ngx_http_lua_worker.c @@ -153,6 +153,8 @@ ngx_http_lua_ffi_master_pid(void) int ngx_http_lua_ffi_get_process_type(void) { + ngx_core_conf_t *ccf; + #if defined(HAVE_PRIVILEGED_PROCESS_PATCH) && !NGX_WIN32 if (ngx_process == NGX_PROCESS_HELPER) { if (ngx_is_privileged_agent) { @@ -161,6 +163,15 @@ ngx_http_lua_ffi_get_process_type(void) } #endif + if (ngx_process == NGX_PROCESS_SINGLE) { + ccf = (ngx_core_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx, + ngx_core_module); + + if (ccf->master) { + return NGX_PROCESS_MASTER; + } + } + return ngx_process; } diff --git a/debian/modules/http-lua/t/000--init.t b/debian/modules/http-lua/t/000--init.t index dbe2c33..5865755 100644 --- a/debian/modules/http-lua/t/000--init.t +++ b/debian/modules/http-lua/t/000--init.t @@ -10,11 +10,6 @@ $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; $ENV{TEST_NGINX_MYSQL_PORT} ||= 3306; our $http_config = <<'_EOC_'; - upstream database { - drizzle_server 127.0.0.1:$TEST_NGINX_MYSQL_PORT protocol=mysql - dbname=ngx_test user=ngx_test password=ngx_test; - } - lua_package_path "../lua-resty-mysql/lib/?.lua;;"; _EOC_ diff --git a/debian/modules/http-lua/t/001-set.t b/debian/modules/http-lua/t/001-set.t index ba8f22c..9e8ee7b 100644 --- a/debian/modules/http-lua/t/001-set.t +++ b/debian/modules/http-lua/t/001-set.t @@ -4,7 +4,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * (blocks() * 3 + 4); +plan tests => repeat_each() * (blocks() * 3 + 5); #log_level("warn"); no_long_string(); @@ -46,7 +46,7 @@ helloworld === TEST 3: internal only --- config location /lua { - set_by_lua $res "function fib(n) if n > 2 then return fib(n-1)+fib(n-2) else return 1 end end return fib(10)"; + set_by_lua $res "local function fib(n) if n > 2 then return fib(n-1)+fib(n-2) else return 1 end end return fib(10)"; echo $res; } --- request @@ -76,7 +76,7 @@ GET /lua?a=1&b=2 === TEST 5: fib by arg --- config location /fib { - set_by_lua $res "function fib(n) if n > 2 then return fib(n-1)+fib(n-2) else return 1 end end return fib(tonumber(ngx.arg[1]))" $arg_n; + set_by_lua $res "local function fib(n) if n > 2 then return fib(n-1)+fib(n-2) else return 1 end end return fib(tonumber(ngx.arg[1]))" $arg_n; echo $res; } --- request @@ -592,25 +592,30 @@ failed to run set_by_lua*: unknown reason -=== TEST 37: globals get cleared for every single request +=== TEST 37: globals are shared in all requests. --- config location /lua { - set_by_lua $res ' + set_by_lua_block $res { if not foo then foo = 1 else + ngx.log(ngx.INFO, "old foo: ", foo) foo = foo + 1 end return foo - '; + } echo $res; } --- request GET /lua ---- response_body -1 +--- response_body_like chomp +\A[12] +\z --- no_error_log [error] +--- grep_error_log eval: qr/(old foo: \d+|writing a global lua variable \('\w+'\))/ +--- grep_error_log_out eval +["writing a global lua variable \('foo'\)\n", "old foo: 1\n"] @@ -755,6 +760,8 @@ GET /lua?name=jim --- config location /t { set_by_lua $a ' + local bar + local foo function foo() bar() end diff --git a/debian/modules/http-lua/t/002-content.t b/debian/modules/http-lua/t/002-content.t index cc92d6f..bb569f5 100644 --- a/debian/modules/http-lua/t/002-content.t +++ b/debian/modules/http-lua/t/002-content.t @@ -86,7 +86,7 @@ qr/content_by_lua\(nginx\.conf:\d+\):1: attempt to call field 'echo' \(a nil val location /lua { # NOTE: the newline escape sequence must be double-escaped, as nginx config # parser will unescape first! - content_by_lua 'v = ngx.var["request_uri"] ngx.print("request_uri: ", v, "\\n")'; + content_by_lua 'local v = ngx.var["request_uri"] ngx.print("request_uri: ", v, "\\n")'; } --- request GET /lua?a=1&b=2 @@ -102,7 +102,7 @@ request_uri: /lua?a=1&b=2 } --- user_files >>> test.lua -v = ngx.var["request_uri"] +local v = ngx.var["request_uri"] ngx.print("request_uri: ", v, "\n") --- request GET /lua?a=1&b=2 @@ -154,7 +154,7 @@ result: -0.4090441561579 === TEST 7: read $arg_xxx --- config location = /lua { - content_by_lua 'who = ngx.var.arg_who + content_by_lua 'local who = ngx.var.arg_who ngx.print("Hello, ", who, "!")'; } --- request @@ -171,7 +171,7 @@ Hello, agentzh! } location /lua { - content_by_lua 'res = ngx.location.capture("/other"); ngx.print("status=", res.status, " "); ngx.print("body=", res.body)'; + content_by_lua 'local res = ngx.location.capture("/other"); ngx.print("status=", res.status, " "); ngx.print("body=", res.body)'; } --- request GET /lua @@ -183,7 +183,7 @@ status=200 body=hello, world ei= TEST 9: capture non-existed location --- config location /lua { - content_by_lua 'res = ngx.location.capture("/other"); ngx.print("status=", res.status)'; + content_by_lua 'local res = ngx.location.capture("/other"); ngx.print("status=", res.status)'; } --- request GET /lua @@ -194,7 +194,7 @@ GET /lua === TEST 9: invalid capture location (not as expected...) --- config location /lua { - content_by_lua 'res = ngx.location.capture("*(#*"); ngx.say("res=", res.status)'; + content_by_lua 'local res = ngx.location.capture("*(#*"); ngx.say("res=", res.status)'; } --- request GET /lua @@ -247,7 +247,7 @@ GET /lua ngx.print("num is: ", num, "\\n"); if (num > 0) then - res = ngx.location.capture("/recur?num="..tostring(num - 1)); + local res = ngx.location.capture("/recur?num="..tostring(num - 1)); ngx.print("status=", res.status, " "); ngx.print("body=", res.body, "\\n"); else @@ -271,7 +271,7 @@ end ngx.print("num is: ", num, "\\n"); if (num > 0) then - res = ngx.location.capture("/recur?num="..tostring(num - 1)); + local res = ngx.location.capture("/recur?num="..tostring(num - 1)); ngx.print("status=", res.status, " "); ngx.print("body=", res.body); else @@ -353,7 +353,7 @@ location /sub { } location /parent { set $a 12; - content_by_lua 'res = ngx.location.capture("/sub"); ngx.print(res.body)'; + content_by_lua 'local res = ngx.location.capture("/sub"); ngx.print(res.body)'; } --- request GET /parent @@ -369,7 +369,7 @@ location /sub { location /parent { set $a 12; content_by_lua ' - res = ngx.location.capture( + local res = ngx.location.capture( "/sub", { share_all_vars = true } ); @@ -390,7 +390,7 @@ location /sub { } location /parent { content_by_lua ' - res = ngx.location.capture("/sub", { share_all_vars = true }); + local res = ngx.location.capture("/sub", { share_all_vars = true }); ngx.say(ngx.var.a) '; } @@ -408,7 +408,7 @@ location /sub { } location /parent { content_by_lua ' - res = ngx.location.capture("/sub", { share_all_vars = false }); + local res = ngx.location.capture("/sub", { share_all_vars = false }); ngx.say(ngx.var.a) '; } @@ -427,7 +427,7 @@ GET /parent location /lua { content_by_lua ' - res = ngx.location.capture("/other"); + local res = ngx.location.capture("/other"); ngx.say("type: ", res.header["Content-Type"]); '; } @@ -454,7 +454,7 @@ type: foo/bar location /lua { content_by_lua ' - res = ngx.location.capture("/other"); + local res = ngx.location.capture("/other"); ngx.say("type: ", type(res.header["Set-Cookie"])); ngx.say("len: ", #res.header["Set-Cookie"]); ngx.say("value: ", table.concat(res.header["Set-Cookie"], "|")) @@ -482,7 +482,7 @@ value: a|hello, world|foo location /lua { content_by_lua ' - res = ngx.location.capture("/other"); + local res = ngx.location.capture("/other"); ngx.say("type: ", res.header["Content-Type"]); ngx.say("Bar: ", res.header["Bar"]); '; @@ -507,7 +507,7 @@ Bar: Bah location /lua { content_by_lua ' - res = ngx.location.capture("/other"); + local res = ngx.location.capture("/other"); ngx.say("type: ", res.header["Content-Type"]); ngx.say("Bar: ", res.header["Bar"] or "nil"); '; @@ -524,7 +524,7 @@ Bar: nil --- config location /lua { content_by_lua ' - data = "hello, world" + local data = "hello, world" -- ngx.header["Content-Length"] = #data -- ngx.header.content_length = #data ngx.print(data) @@ -742,7 +742,7 @@ true --- config location /lua { content_by_lua ' - data = "hello,\\nworld\\n" + local data = "hello,\\nworld\\n" ngx.header["Content-Length"] = #data ngx.say("hello,") ngx.flush() @@ -801,7 +801,7 @@ world } --- user_files >>> test.lua -v = ngx.var["request_uri"] +local v = ngx.var["request_uri"] ngx.print("request_uri: ", v, "\n") --- request GET /lua?a=1&b=2 diff --git a/debian/modules/http-lua/t/004-require.t b/debian/modules/http-lua/t/004-require.t index 35e04db..17e1d57 100644 --- a/debian/modules/http-lua/t/004-require.t +++ b/debian/modules/http-lua/t/004-require.t @@ -24,7 +24,7 @@ __DATA__ === TEST 1: sanity --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /main { echo_location /load; @@ -85,7 +85,7 @@ hello, foo --- request GET /main --- user_files ---- response_body_like: ^[^;]+/servroot/html/\?.so$ +--- response_body_like: ^[^;]+/servroot(_\d+)?/html/\?\.so$ @@ -100,7 +100,7 @@ GET /main } --- request GET /main ---- response_body_like: ^[^;]+/servroot/html/\?.lua;.+\.lua;$ +--- response_body_like: ^[^;]+/servroot(_\d+)?/html/\?\.lua;(.+\.lua)?;*$ @@ -115,7 +115,7 @@ GET /main } --- request GET /main ---- response_body_like: ^[^;]+/servroot/html/\?.so;.+\.so;$ +--- response_body_like: ^[^;]+/servroot(_\d+)?/html/\?\.so;(.+\.so)?;*$ @@ -130,7 +130,7 @@ GET /main } --- request GET /main ---- response_body_like: ^.+\.lua;[^;]+/servroot/html/\?.lua$ +--- response_body_like: ^(.+\.lua)?;*?[^;]+/servroot(_\d+)?/html/\?\.lua$ @@ -145,7 +145,7 @@ GET /main } --- request GET /main ---- response_body_like: ^.+\.so;[^;]+/servroot/html/\?.so$ +--- response_body_like: ^(.+\.so)?;*?[^;]+/servroot(_\d+)?/html/\?\.so$ diff --git a/debian/modules/http-lua/t/005-exit.t b/debian/modules/http-lua/t/005-exit.t index a5a28b3..a416a75 100644 --- a/debian/modules/http-lua/t/005-exit.t +++ b/debian/modules/http-lua/t/005-exit.t @@ -452,7 +452,7 @@ Hi --- config location /lua { content_by_lua ' - function f () + local function f () ngx.say("hello") ngx.exit(200) end diff --git a/debian/modules/http-lua/t/009-log.t b/debian/modules/http-lua/t/009-log.t index 68c057f..cb3895b 100644 --- a/debian/modules/http-lua/t/009-log.t +++ b/debian/modules/http-lua/t/009-log.t @@ -414,6 +414,8 @@ GET /log --- config location /log { content_by_lua ' + local foo + local bar function foo() bar() end @@ -431,7 +433,7 @@ GET /log --- response_body done --- error_log eval -qr/\[error\] \S+: \S+ \[lua\] content_by_lua\(nginx\.conf:\d+\):7: bar\(\): hello, log12343.14159/ +qr/\[error\] \S+: \S+ \[lua\] content_by_lua\(nginx\.conf:\d+\):9: bar\(\): hello, log12343.14159/ @@ -439,6 +441,8 @@ qr/\[error\] \S+: \S+ \[lua\] content_by_lua\(nginx\.conf:\d+\):7: bar\(\): hell --- config location /log { content_by_lua ' + local foo + local bar function foo() return bar(5) end @@ -461,7 +465,7 @@ GET /log --- response_body done --- error_log eval -qr/\[error\] \S+: \S+ \[lua\] content_by_lua\(nginx\.conf:\d+\):8:(?: foo\(\):)? hello, log12343.14159/ +qr/\[error\] \S+: \S+ \[lua\] content_by_lua\(nginx\.conf:\d+\):10:(?: foo\(\):)? hello, log12343.14159/ @@ -472,6 +476,8 @@ qr/\[error\] \S+: \S+ \[lua\] content_by_lua\(nginx\.conf:\d+\):8:(?: foo\(\):)? } --- user_files >>> test.lua +local foo +local bar function foo() bar() end @@ -488,7 +494,7 @@ GET /log --- response_body done --- error_log eval -qr/\[error\] \S+: \S+ \[lua\] test.lua:6: bar\(\): hello, log12343.14159/ +qr/\[error\] \S+: \S+ \[lua\] test.lua:8: bar\(\): hello, log12343.14159/ diff --git a/debian/modules/http-lua/t/011-md5_bin.t b/debian/modules/http-lua/t/011-md5_bin.t index ae7c974..dc0fd9c 100644 --- a/debian/modules/http-lua/t/011-md5_bin.t +++ b/debian/modules/http-lua/t/011-md5_bin.t @@ -156,7 +156,7 @@ d41d8cd98f00b204e9800998ecf8427e --- config location = /t { content_by_lua ' - s = ngx.md5_bin(45) + local s = ngx.md5_bin(45) s = string.gsub(s, ".", function (c) return string.format("%02x", string.byte(c)) end) diff --git a/debian/modules/http-lua/t/013-base64.t b/debian/modules/http-lua/t/013-base64.t index 1cc27de..d1a8d8b 100644 --- a/debian/modules/http-lua/t/013-base64.t +++ b/debian/modules/http-lua/t/013-base64.t @@ -242,4 +242,4 @@ GET /t --- response_body_like: 500 Internal Server Error --- error_code: 500 --- error_log eval -qr/bad argument \#2 to 'encode_base64' \(boolean expected, got number\)|\[error\] .*? boolean argument only/ +qr/bad argument \#2 to 'encode_base64' \(boolean expected, got number\)|\[error\] .*? bad no_padding: boolean expected, got number/ diff --git a/debian/modules/http-lua/t/014-bugs.t b/debian/modules/http-lua/t/014-bugs.t index 9aadff0..dad084e 100644 --- a/debian/modules/http-lua/t/014-bugs.t +++ b/debian/modules/http-lua/t/014-bugs.t @@ -43,7 +43,7 @@ __DATA__ === TEST 1: sanity --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /load { content_by_lua ' @@ -69,7 +69,7 @@ end === TEST 2: sanity --- http_config -lua_package_path '/home/agentz/rpm/BUILD/lua-yajl-1.1/build/?.so;/home/lz/luax/?.so;./?.so'; +lua_package_cpath '/home/agentz/rpm/BUILD/lua-yajl-1.1/build/?.so;/home/lz/luax/?.so;./?.so'; --- config location = '/report/listBidwordPrices4lzExtra.htm' { content_by_lua ' @@ -112,7 +112,7 @@ GET /report/listBidwordPrices4lzExtra.htm?words=123,156,2532 } location = /main { content_by_lua ' - res = ngx.location.capture("/memc?c=get&k=foo&v=") + local res = ngx.location.capture("/memc?c=get&k=foo&v=") ngx.say("1: ", res.body) res = ngx.location.capture("/memc?c=set&k=foo&v=bar"); @@ -204,7 +204,7 @@ https://github.com/chaoslawful/lua-nginx-module/issues/37 content_by_lua ' -- local yajl = require "yajl" ngx.header["Set-Cookie"] = {} - res = ngx.location.capture("/sub") + local res = ngx.location.capture("/sub") for i,j in pairs(res.header) do ngx.header[i] = j @@ -231,7 +231,7 @@ Set-Cookie: TestCookie2=bar.*" } --- user_files >>> foo.lua -res = {} +local res = {} res = {'good 1', 'good 2', 'good 3'} return ngx.redirect("/somedir/" .. ngx.escape_uri(res[math.random(1,#res)])) --- request @@ -579,7 +579,7 @@ $s -=== TEST 26: unexpected globals sharing by using _G +=== TEST 26: globals sharing by using _G --- config location /test { content_by_lua ' @@ -593,12 +593,12 @@ $s } --- pipelined_requests eval ["GET /test", "GET /test", "GET /test"] ---- response_body eval -["0", "0", "0"] +--- response_body_like eval +[qr/\A[036]\z/, qr/\A[147]\z/, qr/\A[258]\z/] -=== TEST 27: unexpected globals sharing by using _G (set_by_lua*) +=== TEST 27: globals sharing by using _G (set_by_lua*) --- config location /test { set_by_lua $a ' @@ -613,12 +613,12 @@ $s } --- pipelined_requests eval ["GET /test", "GET /test", "GET /test"] ---- response_body eval -["0", "0", "0"] +--- response_body_like eval +[qr/\A[036]\z/, qr/\A[147]\z/, qr/\A[258]\z/] -=== TEST 28: unexpected globals sharing by using _G (log_by_lua*) +=== TEST 28: globals sharing by using _G (log_by_lua*) --- http_config lua_shared_dict log_dict 100k; --- config @@ -633,19 +633,19 @@ $s if _G.t then _G.t = _G.t + 1 else - _G.t = 0 + _G.t = 1 end log_dict:set("cnt", t) '; } --- pipelined_requests eval ["GET /test", "GET /test", "GET /test"] ---- response_body eval -["0", "0", "0"] +--- response_body_like eval +[qr/\A[036]\z/, qr/\A[147]\z/, qr/\A[258]\z/] -=== TEST 29: unexpected globals sharing by using _G (header_filter_by_lua*) +=== TEST 29: globals sharing by using _G (header_filter_by_lua*) --- config location /test { header_filter_by_lua ' @@ -663,12 +663,12 @@ $s } --- pipelined_requests eval ["GET /test", "GET /test", "GET /test"] ---- response_body eval -["0", "0", "0"] +--- response_body_like eval +[qr/\A[036]\z/, qr/\A[147]\z/, qr/\A[258]\z/] -=== TEST 30: unexpected globals sharing by using _G (body_filter_by_lua*) +=== TEST 30: globals sharing by using _G (body_filter_by_lua*) --- config location /test { body_filter_by_lua ' @@ -686,8 +686,9 @@ $s } --- request GET /test ---- response_body -a0 +--- response_body_like eval +qr/\Aa[036] +\z/ --- no_error_log [error] @@ -846,7 +847,7 @@ ok === TEST 37: resolving names with a trailing dot --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /t { resolver $TEST_NGINX_RESOLVER ipv6=off; @@ -864,7 +865,7 @@ GET /t === TEST 38: resolving names with a trailing dot --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua'; + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;'; server { listen 12354; @@ -891,7 +892,7 @@ args: foo=1&bar=2 === TEST 39: lua_code_cache off + setkeepalive --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config lua_code_cache off; location = /t { diff --git a/debian/modules/http-lua/t/016-resp-header.t b/debian/modules/http-lua/t/016-resp-header.t index 72c1e05..e38202b 100644 --- a/debian/modules/http-lua/t/016-resp-header.t +++ b/debian/modules/http-lua/t/016-resp-header.t @@ -8,7 +8,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * (blocks() * 3 + 46); +plan tests => repeat_each() * (blocks() * 3 + 59); #no_diff(); no_long_string(); @@ -630,7 +630,46 @@ Cache-Control: private, no-store -=== TEST 32: set multi values to cache-control and override it with a single value +=== TEST 32: set single value to Link header +--- config + location = /t { + content_by_lua_block { + ngx.header.link = "; rel=preload" + ngx.say("Link: ", ngx.var.sent_http_link) + } + } +--- request +GET /t +--- response_headers +Link: ; rel=preload +--- response_body +Link: ; rel=preload + + + +=== TEST 33: set multi values to Link header +--- config + location = /t { + content_by_lua_block { + ngx.header.link = { + "; rel=preload", + "; rel=preload; as=style" + } + + ngx.say("Link: ", ngx.var.sent_http_link) + } + } +--- request +GET /t +--- response_headers +Link: ; rel=preload, ; rel=preload; as=style +--- response_body_like chop +^Link: ; rel=preload[;,] ; rel=preload; as=style$ +--- skip_nginx: 3: < 1.13.9 + + + +=== TEST 34: set multi values to cache-control and override it with a single value --- config location /lua { content_by_lua ' @@ -650,7 +689,30 @@ Cache-Control: no-cache -=== TEST 33: set multi values to cache-control and override it with multiple values +=== TEST 35: set multi values to Link header and override it with a single value +--- config + location /lua { + content_by_lua_block { + ngx.header.link = { + "; rel=preload", + "; rel=preload; as=style" + } + ngx.header.link = "; rel=preload" + ngx.say("Link: ", ngx.var.sent_http_link) + ngx.say("Link: ", ngx.header.link) + } + } +--- request + GET /lua +--- response_headers +Link: ; rel=preload +--- response_body +Link: ; rel=preload +Link: ; rel=preload + + + +=== TEST 36: set multi values to cache-control and override it with multiple values --- config location /lua { content_by_lua ' @@ -672,7 +734,37 @@ Cache-Control: no-cache[;,] blah[;,] foo$ -=== TEST 34: set the www-authenticate response header +=== TEST 37: set multi values to Link header and override it with multiple values +--- config + location /lua { + content_by_lua_block { + ngx.header.link = { + "; rel=preload", + "; rel=preload; as=style" + } + ngx.header.link = { + "; rel=preload", + "; rel=preload", + "; rel=preload; as=style" + } + ngx.say("Link: ", ngx.var.sent_http_link) + ngx.say("Link: ", table.concat(ngx.header.link, ", ")) + } + } +--- request + GET /lua +--- response_headers +Link: ; rel=preload, ; rel=preload, ; rel=preload; as=style +--- response_body_like chop +^Link: ; rel=preload[;,] ; rel=preload[;,] ; rel=preload; as=style +Link: ; rel=preload[;,] ; rel=preload[;,] ; rel=preload; as=style$ +--- no_error_log +[error] +--- skip_nginx: 4: < 1.13.9 + + + +=== TEST 38: set the www-authenticate response header --- config location /lua { content_by_lua ' @@ -689,7 +781,7 @@ WWW-Authenticate: blah -=== TEST 35: set and clear the www-authenticate response header +=== TEST 39: set and clear the www-authenticate response header --- config location /lua { content_by_lua ' @@ -707,7 +799,7 @@ Foo: nil -=== TEST 36: set multi values to cache-control and override it with multiple values (to reproduce a bug) +=== TEST 40: set multi values to cache-control and override it with multiple values (to reproduce a bug) --- config location /lua { content_by_lua ' @@ -727,7 +819,7 @@ Cache-Control: blah -=== TEST 37: set last-modified and return 304 +=== TEST 41: set last-modified and return 304 --- config location /lua { content_by_lua ' @@ -745,7 +837,7 @@ Last-Modified: Thu, 18 Nov 2010 11:27:35 GMT -=== TEST 38: set last-modified and return 200 +=== TEST 42: set last-modified and return 200 --- config location /lua { content_by_lua ' @@ -764,7 +856,7 @@ Thu, 18 Nov 2010 11:27:35 GMT -=== TEST 39: set response content-encoding header should bypass ngx_http_gzip_filter_module +=== TEST 43: set response content-encoding header should bypass ngx_http_gzip_filter_module --- config default_type text/plain; gzip on; @@ -781,13 +873,16 @@ GET /read --- more_headers Accept-Encoding: gzip --- response_headers -Content-Type: text/plain +Content-Encoding: gzip +--- no_error_log +[error] +http gzip filter --- response_body Hello, world, my dear friend! -=== TEST 40: no transform underscores (write) +=== TEST 44: no transform underscores (write) --- config lua_transform_underscores_in_response_headers off; location = /t { @@ -807,7 +902,7 @@ nil -=== TEST 41: with transform underscores (write) +=== TEST 45: with transform underscores (write) --- config lua_transform_underscores_in_response_headers on; location = /t { @@ -827,7 +922,7 @@ Hello -=== TEST 42: github issue #199: underscores in lua variables +=== TEST 46: github issue #199: underscores in lua variables --- config location /read { content_by_lua ' @@ -860,7 +955,7 @@ something: hello -=== TEST 43: set multiple response header +=== TEST 47: set multiple response header --- config location /read { content_by_lua ' @@ -880,7 +975,7 @@ text/my-plain-50 -=== TEST 44: set multiple response header and then reset and then clear +=== TEST 48: set multiple response header and then reset and then clear --- config location /read { content_by_lua ' @@ -909,7 +1004,7 @@ ok -=== TEST 45: set response content-type header for multiple times +=== TEST 49: set response content-type header for multiple times --- config location /read { content_by_lua ' @@ -927,7 +1022,7 @@ Hi -=== TEST 46: set Last-Modified response header for multiple times +=== TEST 50: set Last-Modified response header for multiple times --- config location /read { content_by_lua ' @@ -945,7 +1040,7 @@ ok -=== TEST 47: set Last-Modified response header and then clear +=== TEST 51: set Last-Modified response header and then clear --- config location /read { content_by_lua ' @@ -963,7 +1058,7 @@ ok -=== TEST 48: github #20: segfault caused by the nasty optimization in the nginx core (write) +=== TEST 52: github #20: segfault caused by the nasty optimization in the nginx core (write) --- config location = /t/ { header_filter_by_lua ' @@ -985,7 +1080,7 @@ Location: http://localhost:$ServerPort/t/ -=== TEST 49: github #20: segfault caused by the nasty optimization in the nginx core (read) +=== TEST 53: github #20: segfault caused by the nasty optimization in the nginx core (read) --- config location = /t/ { header_filter_by_lua ' @@ -1007,7 +1102,7 @@ Location: http://localhost:$ServerPort/t/ -=== TEST 50: github #20: segfault caused by the nasty optimization in the nginx core (read Location) +=== TEST 54: github #20: segfault caused by the nasty optimization in the nginx core (read Location) --- config location = /t/ { header_filter_by_lua ' @@ -1030,7 +1125,7 @@ Foo: /t/ -=== TEST 51: github #20: segfault caused by the nasty optimization in the nginx core (set Foo and read Location) +=== TEST 55: github #20: segfault caused by the nasty optimization in the nginx core (set Foo and read Location) --- config location = /t/ { header_filter_by_lua ' @@ -1054,7 +1149,7 @@ Foo: /t/ -=== TEST 52: case sensitive cache-control header +=== TEST 56: case sensitive cache-control header --- config location /lua { content_by_lua ' @@ -1071,7 +1166,24 @@ Cache-Control: private -=== TEST 53: clear Cache-Control when there was no Cache-Control +=== TEST 57: case sensitive Link header +--- config + location /lua { + content_by_lua_block { + ngx.header["link"] = "; rel=preload" + ngx.say("Link: ", ngx.var.sent_http_link) + } + } +--- request + GET /lua +--- raw_response_headers_like chop +link: ; rel=preload +--- response_body +Link: ; rel=preload + + + +=== TEST 58: clear Cache-Control when there was no Cache-Control --- config location /lua { content_by_lua ' @@ -1088,7 +1200,24 @@ Cache-Control: nil -=== TEST 54: set response content-type header +=== TEST 59: clear Link header when there was no Link +--- config + location /lua { + content_by_lua_block { + ngx.header["Link"] = nil + ngx.say("Link: ", ngx.var.sent_http_link) + } + } +--- request + GET /lua +--- raw_response_headers_unlike eval +qr/Link/i +--- response_body +Link: nil + + + +=== TEST 60: set response content-type header --- config location /read { content_by_lua ' @@ -1107,7 +1236,7 @@ s = content_type -=== TEST 55: set a number header name +=== TEST 61: set a number header name --- config location /lua { content_by_lua ' @@ -1126,7 +1255,7 @@ s = content_type -=== TEST 56: set a number header name (in a table value) +=== TEST 62: set a number header name (in a table value) --- config location /lua { content_by_lua ' @@ -1145,7 +1274,7 @@ foo: 32 -=== TEST 57: random access resp headers +=== TEST 63: random access resp headers --- config location /resp-header { content_by_lua ' @@ -1185,7 +1314,7 @@ bar: baz -=== TEST 58: iterating through raw resp headers +=== TEST 64: iterating through raw resp headers --- config location /resp-header { content_by_lua ' @@ -1221,7 +1350,7 @@ bar: nil -=== TEST 59: removed response headers +=== TEST 65: removed response headers --- config location /resp-header { content_by_lua ' @@ -1254,7 +1383,7 @@ bar: baz -=== TEST 60: built-in Content-Type header +=== TEST 66: built-in Content-Type header --- config location = /t { content_by_lua ' @@ -1287,7 +1416,7 @@ my content_type: text/plain -=== TEST 61: built-in Content-Length header +=== TEST 67: built-in Content-Length header --- config location = /t { content_by_lua ' @@ -1320,7 +1449,7 @@ my content_length: 3 -=== TEST 62: built-in Connection header +=== TEST 68: built-in Connection header --- config location = /t { content_by_lua ' @@ -1351,7 +1480,7 @@ my connection: close -=== TEST 63: built-in Transfer-Encoding header (chunked) +=== TEST 69: built-in Transfer-Encoding header (chunked) --- config location = /t { content_by_lua ' @@ -1383,7 +1512,7 @@ my transfer-encoding: chunked -=== TEST 64: built-in Transfer-Encoding header (none) +=== TEST 70: built-in Transfer-Encoding header (none) --- config location = /t { content_by_lua ' @@ -1416,7 +1545,7 @@ my transfer_encoding: nil -=== TEST 65: set Location (no host) +=== TEST 71: set Location (no host) --- config location = /t { content_by_lua ' @@ -1435,7 +1564,7 @@ Location: /foo/bar -=== TEST 66: set Location (with host) +=== TEST 72: set Location (with host) --- config location = /t { content_by_lua ' @@ -1454,7 +1583,7 @@ Location: http://test.com/foo/bar -=== TEST 67: ngx.header["Content-Type"] with ngx_gzip +=== TEST 73: ngx.header["Content-Type"] with ngx_gzip --- config gzip on; gzip_min_length 1; @@ -1478,7 +1607,7 @@ Content-Type: text/html; charset=utf-8 -=== TEST 68: ngx.header["Content-Type"] with "; blah" +=== TEST 74: ngx.header["Content-Type"] with "; blah" --- config location = /test2 { content_by_lua ' @@ -1498,84 +1627,11 @@ test -=== TEST 69: return the matched content-type instead of default_type ---- http_config -types { - image/png png; -} ---- config -location /set/ { - default_type text/html; - content_by_lua_block { - ngx.say(ngx.header["content-type"]) - } -} ---- request -GET /set/hello.png ---- response_headers -Content-Type: image/png ---- response_body -image/png ---- no_error_log -[error] - - - -=== TEST 70: always return the matched content-type ---- config - location /set/ { - default_type "image/png"; - content_by_lua_block { - ngx.say(ngx.header["content-type"]) - ngx.say(ngx.header["content-type"]) - } - } ---- request -GET /set/hello.png ---- response_headers -Content-Type: image/png ---- response_body -image/png -image/png ---- no_error_log -[error] - - - -=== TEST 71: return the matched content-type after ngx.resp.get_headers() ---- http_config -types { - image/png png; -} ---- config - location /set/ { - default_type text/html; - content_by_lua_block { - local h, err = ngx.resp.get_headers() - if err then - ngx.log(ngx.ERR, "err: ", err) - return ngx.exit(500) - end - - ngx.say(h["content-type"]) - } - } ---- request -GET /set/hello.png ---- response_headers -Content-Type: image/png ---- response_body -image/png ---- no_error_log -[error] - - - -=== TEST 72: exceeding max header limit (default 100) +=== TEST 75: exceeding max header limit (default 100) --- config location /resp-header { content_by_lua_block { - for i = 1, 99 do + for i = 1, 100 do ngx.header["Foo" .. i] = "Foo" end @@ -1605,11 +1661,11 @@ lua exceeding response header limit 101 > 100 -=== TEST 73: NOT exceeding max header limit (default 100) +=== TEST 76: NOT exceeding max header limit (default 100) --- config location /resp-header { content_by_lua_block { - for i = 1, 98 do + for i = 1, 99 do ngx.header["Foo" .. i] = "Foo" end @@ -1637,11 +1693,11 @@ lua exceeding response header limit -=== TEST 74: exceeding max header limit (custom limit, 3) +=== TEST 77: exceeding max header limit (custom limit, 3) --- config location /resp-header { content_by_lua_block { - for i = 1, 2 do + for i = 1, 3 do ngx.header["Foo" .. i] = "Foo" end @@ -1671,11 +1727,11 @@ lua exceeding response header limit 4 > 3 -=== TEST 75: NOT exceeding max header limit (custom limit, 3) +=== TEST 78: NOT exceeding max header limit (custom limit, 3) --- config location /resp-header { content_by_lua_block { - for i = 1, 1 do + for i = 1, 2 do ngx.header["Foo" .. i] = "Foo" end @@ -1699,3 +1755,211 @@ found 3 resp headers --- no_error_log [error] lua exceeding response header limit + + + +=== TEST 79: return nil if Content-Type is not set yet +--- config + location /t { + default_type text/html; + content_by_lua_block { + ngx.log(ngx.WARN, "Content-Type: ", ngx.header["content-type"]) + ngx.say("Content-Type: ", ngx.header["content-type"]) + } + } +--- request +GET /t +--- response_headers +Content-Type: text/html +--- response_body +Content-Type: nil +--- no_error_log +[error] +--- error_log +Content-Type: nil + + + +=== TEST 80: don't generate Content-Type when setting other response header +--- config + location = /backend { + content_by_lua_block { + ngx.say("foo") + } + header_filter_by_lua_block { + ngx.header.content_type = nil + } + } + + location = /t { + default_type text/html; + rewrite_by_lua_block { + ngx.header.blah = "foo" + } + proxy_pass http://127.0.0.1:$TEST_NGINX_SERVER_PORT/backend; + } +--- request +GET /t +--- response_body +foo +--- response_headers +blah: foo +!Content-Type +--- no_error_log +[error] + + + +=== TEST 81: don't generate Content-Type when getting other response header +--- config + location = /backend { + content_by_lua_block { + ngx.say("foo") + } + header_filter_by_lua_block { + ngx.header.content_type = nil + } + } + + location = /t { + default_type text/html; + rewrite_by_lua_block { + local h = ngx.header.content_length + } + proxy_pass http://127.0.0.1:$TEST_NGINX_SERVER_PORT/backend; + } +--- request +GET /t +--- response_body +foo +--- response_headers +!Content-Type +--- no_error_log +[error] + + + +=== TEST 82: don't generate Content-Type when getting it +--- config + location = /backend { + content_by_lua_block { + ngx.say("foo") + } + header_filter_by_lua_block { + ngx.header.content_type = nil + } + } + + location /t { + proxy_pass http://127.0.0.1:$TEST_NGINX_SERVER_PORT/backend; + header_filter_by_lua_block { + ngx.log(ngx.WARN, "Content-Type: ", ngx.header["content-type"]) + } + } +--- request +GET /t +--- response_body +foo +--- response_headers +!Content-Type +--- no_error_log +[error] +--- error_log +Content-Type: nil + + + +=== TEST 83: generate default Content-Type when setting other response header +--- config + location = /t { + default_type text/html; + content_by_lua_block { + ngx.header.blah = "foo" + ngx.say("foo") + } + } +--- request +GET /t +--- response_body +foo +--- response_headers +blah: foo +Content-Type: text/html +--- no_error_log +[error] + + + +=== TEST 84: don't generate Content-Type when calling ngx.resp.get_headers() +--- config + location = /backend { + content_by_lua_block { + ngx.say("foo") + } + header_filter_by_lua_block { + ngx.header.content_type = nil + } + } + + location /t { + proxy_pass http://127.0.0.1:$TEST_NGINX_SERVER_PORT/backend; + header_filter_by_lua_block { + local h, err = ngx.resp.get_headers() + if err then + ngx.log(ngx.ERR, "err: ", err) + return + end + + ngx.log(ngx.WARN, "Content-Type: ", h["content-type"]) + } + } +--- request +GET /t +--- response_body +foo +--- response_headers +!Content-Type +--- no_error_log +[error] +--- error_log +Content-Type: nil + + + +=== TEST 85: don't generate default Content-Type when Content-Type is cleared +--- config + location = /t { + default_type text/html; + content_by_lua_block { + ngx.header["Content-Type"] = nil + ngx.say("foo") + } + } +--- request +GET /t +--- response_body +foo +--- response_headers +!Content-Type +--- no_error_log +[error] + + + +=== TEST 86: don't generate default Content-Type when Content-Type is set +--- config + location = /t { + default_type text/html; + content_by_lua_block { + ngx.header["Content-Type"] = "application/json" + ngx.say("foo") + } + } +--- request +GET /t +--- response_body +foo +--- response_headers +Content-Type: application/json +--- no_error_log +[error] diff --git a/debian/modules/http-lua/t/017-exec.t b/debian/modules/http-lua/t/017-exec.t index 544b8bb..a73e93e 100644 --- a/debian/modules/http-lua/t/017-exec.t +++ b/debian/modules/http-lua/t/017-exec.t @@ -382,7 +382,7 @@ hello --- config location /lua { content_by_lua ' - function f () + local function f () ngx.exec("/hi") end @@ -524,7 +524,7 @@ hello --- config location /main { rewrite_by_lua ' - res = ngx.location.capture("/test_loc"); + local res = ngx.location.capture("/test_loc"); ngx.print("hello, ", res.body) '; content_by_lua return; diff --git a/debian/modules/http-lua/t/020-subrequest.t b/debian/modules/http-lua/t/020-subrequest.t index 658a1d2..5a386db 100644 --- a/debian/modules/http-lua/t/020-subrequest.t +++ b/debian/modules/http-lua/t/020-subrequest.t @@ -32,7 +32,7 @@ __DATA__ location /lua { content_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { method = ngx.HTTP_DELETE }); ngx.print(res.body) @@ -62,7 +62,7 @@ lua http subrequest "/other?" location /lua { content_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { method = ngx.HTTP_DELETE }); ngx.print(res.body) @@ -90,7 +90,7 @@ DELETE location /t { content_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { method = ngx.HTTP_POST }); ngx.print(res.body) @@ -114,7 +114,7 @@ POST location /lua { content_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { method = ngx.HTTP_HEAD }); ngx.print(res.body) @@ -141,7 +141,7 @@ GET /lua location /lua { content_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { method = ngx.HTTP_GET }); ngx.print(res.body) @@ -169,7 +169,7 @@ GET location /lua { content_by_lua ' - res = ngx.location.capture("/foo") + local res = ngx.location.capture("/foo") ngx.print(res.body) '; @@ -196,7 +196,7 @@ GET location /lua { content_by_lua ' - res = ngx.location.capture("/foo", {}) + local res = ngx.location.capture("/foo", {}) ngx.print(res.body) '; @@ -226,7 +226,7 @@ GET location /lua { content_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { method = ngx.HTTP_PUT, body = "hello" }); ngx.print(res.body) @@ -255,7 +255,7 @@ hello location /lua { content_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { method = ngx.HTTP_PUT, body = "hello" }); ngx.print(res.body) @@ -291,7 +291,7 @@ hello location /lua { content_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { method = ngx.HTTP_PUT, body = "hello" }); ngx.print(res.body) @@ -329,7 +329,7 @@ GET location /lua { content_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { method = ngx.HTTP_POST, body = "hello" }); ngx.print(res.body) @@ -362,7 +362,7 @@ hello content_by_lua ' ngx.location.capture("/flush"); - res = ngx.location.capture("/memc"); + local res = ngx.location.capture("/memc"); ngx.say("GET: " .. res.status); res = ngx.location.capture("/memc", @@ -404,7 +404,7 @@ cached: hello ngx.location.capture("/flush", { share_all_vars = true }); - res = ngx.location.capture("/memc", + local res = ngx.location.capture("/memc", { share_all_vars = true }); ngx.say("GET: " .. res.status); @@ -435,7 +435,7 @@ cached: hello location /lua { content_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { args = {} }) ngx.print(res.body) '; @@ -456,7 +456,7 @@ GET /lua location /lua { content_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { args = { ["fo="] = "=>" } }) ngx.print(res.body) '; @@ -478,7 +478,7 @@ fo%3D=%3D%3E location /lua { content_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { args = { ["fo="] = "=>", ["="] = ":" } }) ngx.print(res.body) @@ -503,7 +503,7 @@ GET /lua location /lua { content_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { args = { foo = 3, bar = "hello" } }) ngx.print(res.body) @@ -526,7 +526,7 @@ GET /lua location /lua { content_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { args = { [57] = "hi" } }) ngx.print(res.body) '; @@ -548,7 +548,7 @@ attempt to use a non-string key in the "args" option table location /lua { content_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { args = { "hi" } }) ngx.print(res.body) '; @@ -570,7 +570,7 @@ attempt to use a non-string key in the "args" option table location /lua { content_by_lua ' - res = ngx.location.capture("/foo?a=3", + local res = ngx.location.capture("/foo?a=3", { args = { b = 4 } }) ngx.print(res.body) '; @@ -592,7 +592,7 @@ a=3&b=4 location /lua { content_by_lua ' - res = ngx.location.capture("/foo?a=3", + local res = ngx.location.capture("/foo?a=3", { args = "b=4" }) ngx.print(res.body) '; @@ -685,7 +685,7 @@ https://github.com/chaoslawful/lua-nginx-module/issues/38 location /lua { content_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { method = ngx.HTTP_GET }); ngx.say("header foo: [", res.body, "]") '; @@ -711,7 +711,7 @@ https://github.com/chaoslawful/lua-nginx-module/issues/38 location /lua { content_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { body = "abc" }); ngx.say("header foo: [", res.body, "]") '; @@ -746,8 +746,8 @@ header foo: [bar] } location /main { content_by_lua ' - res1, res2 = ngx.location.capture_multi({{"/a"}, {"/b"}}) - res3 = ngx.location.capture("/c") + local res1, res2 = ngx.location.capture_multi({{"/a"}, {"/b"}}) + local res3 = ngx.location.capture("/c") ngx.print(res1.body, res2.body, res3.body) '; } @@ -780,7 +780,7 @@ lua reuse free buf memory location /lua { content_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { method = ngx.HTTP_POST, body = "hello" }); ngx.print(res.body) @@ -801,7 +801,7 @@ hello --- config location /lua { content_by_lua ' - res = ngx.location.capture("/foo.html") + local res = ngx.location.capture("/foo.html") ngx.say(res.status) ngx.say(res.header["Last-Modified"]) @@ -832,7 +832,7 @@ hello, static file$ location /lua { content_by_lua ' local ctx = {} - res = ngx.location.capture("/sub", { ctx = ctx }) + local res = ngx.location.capture("/sub", { ctx = ctx }) ngx.say(ctx.foo); ngx.say(ngx.ctx.foo); @@ -857,7 +857,7 @@ nil } location /lua { content_by_lua ' - res = ngx.location.capture("/sub", { ctx = ngx.ctx }) + local res = ngx.location.capture("/sub", { ctx = ngx.ctx }) ngx.say(ngx.ctx.foo); '; } @@ -885,7 +885,7 @@ bar location /t { content_by_lua ' - res = ngx.location.capture("/memc", + local res = ngx.location.capture("/memc", { method = ngx.HTTP_PUT, body = "hello 1234" }); -- ngx.say("PUT: " .. res.status); @@ -922,7 +922,7 @@ lua reuse free buf chain, but reallocate memory because location /lua { content_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { method = ngx.HTTP_GET }); ngx.print(res.body) @@ -959,7 +959,7 @@ nil content_by_lua ' ngx.req.read_body() - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { method = ngx.HTTP_GET }); ngx.print(res.body) @@ -996,7 +996,7 @@ nil content_by_lua ' ngx.req.read_body() - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { method = ngx.HTTP_POST }); ngx.print(res.body) @@ -1033,7 +1033,7 @@ hello, world content_by_lua ' ngx.req.read_body() - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { method = ngx.HTTP_PUT }); ngx.print(res.body) @@ -1074,7 +1074,7 @@ lua subrequests cycle while processing "/t" location /lua { content_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { method = ngx.HTTP_OPTIONS }); ngx.print(res.body) @@ -1099,7 +1099,7 @@ OPTIONS location /lua { content_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { method = ngx.HTTP_OPTIONS, body = "hello world" }); ngx.print(res.body) @@ -1151,7 +1151,7 @@ r%5B%5D=http%3A%2F%2Fajax.googleapis.com%3A80%2Fajax%2Flibs%2Fjquery%2F1.7.2%2Fj location /main { content_by_lua ' - res = ngx.location.capture("/sub") + local res = ngx.location.capture("/sub") ngx.say("status: ", res.status) ngx.say("body: ", res.body) '; @@ -1172,7 +1172,7 @@ body: location /main { content_by_lua ' - res = ngx.location.capture("/sub") + local res = ngx.location.capture("/sub") ngx.say("status: ", res.status) ngx.say("body: ", res.body) '; @@ -1196,7 +1196,7 @@ body: location /main { content_by_lua ' - res = ngx.location.capture("/sub") + local res = ngx.location.capture("/sub") ngx.say("status: ", res.status) ngx.say("body: ", res.body) '; @@ -1242,7 +1242,7 @@ F(ngx_http_finalize_request) { location /main { content_by_lua ' - res = ngx.location.capture("/memc") + local res = ngx.location.capture("/memc") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -1312,7 +1312,7 @@ upstream prematurely closed connection location /main { content_by_lua ' - res = ngx.location.capture("/memc") + local res = ngx.location.capture("/memc") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -1385,7 +1385,7 @@ upstream timed out location /main { content_by_lua ' - res = ngx.location.capture("/proxy") + local res = ngx.location.capture("/proxy") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -1445,7 +1445,7 @@ upstream prematurely closed connection location /main { content_by_lua ' - res = ngx.location.capture("/proxy") + local res = ngx.location.capture("/proxy") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -1507,7 +1507,7 @@ upstream timed out location /main { content_by_lua ' - res = ngx.location.capture("/proxy") + local res = ngx.location.capture("/proxy") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -1567,7 +1567,7 @@ truncated: false location /main { content_by_lua ' - res = ngx.location.capture("/proxy") + local res = ngx.location.capture("/proxy") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -1630,7 +1630,7 @@ upstream timed out location /main { content_by_lua ' - res = ngx.location.capture("/proxy") + local res = ngx.location.capture("/proxy") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -1690,7 +1690,7 @@ truncated: false location /main { content_by_lua ' - res = ngx.location.capture("/proxy") + local res = ngx.location.capture("/proxy") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -1756,7 +1756,7 @@ upstream timed out ngx.req.read_body() for i = 1, 2 do - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { method = ngx.HTTP_POST }); ngx.say(res.body) @@ -1796,7 +1796,7 @@ hello world ngx.req.read_body() for i = 1, 2 do - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { method = ngx.HTTP_POST }); ngx.say(res.body) @@ -1836,7 +1836,7 @@ hello world ngx.req.read_body() for i = 1, 2 do - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { method = ngx.HTTP_POST }); ngx.say(res.body) @@ -1916,7 +1916,7 @@ a client request body is buffered to a temporary file location /main { content_by_lua ' - res = ngx.location.capture("/proxy") + local res = ngx.location.capture("/proxy") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -1979,7 +1979,7 @@ upstream prematurely closed connection location /main { content_by_lua ' - res = ngx.location.capture("/proxy") + local res = ngx.location.capture("/proxy") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -2040,7 +2040,7 @@ upstream prematurely closed connection location /main { content_by_lua ' - res = ngx.location.capture("/proxy") + local res = ngx.location.capture("/proxy") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -2102,7 +2102,7 @@ upstream timed out location /main { content_by_lua ' - res = ngx.location.capture("/proxy") + local res = ngx.location.capture("/proxy") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -2160,7 +2160,7 @@ truncated: false location /main { content_by_lua ' - res = ngx.location.capture("/proxy") + local res = ngx.location.capture("/proxy") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -2219,7 +2219,7 @@ truncated: false location /main { content_by_lua ' - res = ngx.location.capture("/proxy") + local res = ngx.location.capture("/proxy") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -2288,7 +2288,7 @@ upstream prematurely closed connection } for i, method in ipairs(methods) do - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { method = method }) ngx.print(res.body) end @@ -2324,7 +2324,7 @@ method: TRACE location /lua { content_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { method = ngx.HTTP_DELETE }); ngx.print(res.body) @@ -2353,7 +2353,7 @@ nil location /lua { content_by_lua ' ngx.req.read_body() - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { method = ngx.HTTP_DELETE, always_forward_body = true }); ngx.print(res.body) @@ -2382,7 +2382,7 @@ hello world location /lua { content_by_lua ' ngx.req.read_body() - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { method = ngx.HTTP_DELETE, always_forward_body = true }); ngx.print(res.body) @@ -2410,7 +2410,7 @@ hello world --- config location = /t { content_by_lua ' - res = ngx.location.capture("/sub") + local res = ngx.location.capture("/sub") ngx.print(res.body) '; } @@ -2603,7 +2603,7 @@ qr/Assertion .*? failed/ location = /t { content_by_lua ' - res = ngx.location.capture("/sub") + local res = ngx.location.capture("/sub") ngx.print(res.body) ngx.say("pr: User-Agent: ", ngx.var.http_user_agent) ngx.say("pr: Host: ", ngx.var.http_host) @@ -2636,7 +2636,7 @@ pr: Host: localhost location = /t { content_by_lua ' - res = ngx.location.capture("/sub") + local res = ngx.location.capture("/sub") ngx.print(res.body) ngx.say("pr: User-Agent: ", ngx.var.http_user_agent) ngx.say("pr: Host: ", ngx.var.http_host) @@ -2669,7 +2669,7 @@ pr: Host: localhost location = /t { content_by_lua ' - res = ngx.location.capture("/sub") + local res = ngx.location.capture("/sub") ngx.print(res.body) ngx.say("pr: User-Agent: ", ngx.var.http_user_agent) ngx.say("pr: Host: ", ngx.var.http_host) @@ -2699,7 +2699,7 @@ pr: Host: localhost location = /t { content_by_lua ' - res = ngx.location.capture("/sub") + local res = ngx.location.capture("/sub") ngx.print(res.body) ngx.say("pr: Cookie: ", ngx.var.http_cookie) '; @@ -2727,7 +2727,7 @@ pr: Cookie: foo; bar location = /t { content_by_lua ' - res = ngx.location.capture("/sub") + local res = ngx.location.capture("/sub") ngx.print(res.body) ngx.say("pr: Cookie: ", ngx.var.http_cookie) '; @@ -2750,7 +2750,7 @@ pr: Cookie: foo; bar --- config location /lua { content_by_lua ' - res = ngx.location.capture("/index.html", + local res = ngx.location.capture("/index.html", { method = ngx.HTTP_HEAD }); ngx.say("content-length: ", res.header["Content-Length"]) ngx.say("body: [", res.body, "]") diff --git a/debian/modules/http-lua/t/023-rewrite/client-abort.t b/debian/modules/http-lua/t/023-rewrite/client-abort.t index 117d17e..0d6f2b3 100644 --- a/debian/modules/http-lua/t/023-rewrite/client-abort.t +++ b/debian/modules/http-lua/t/023-rewrite/client-abort.t @@ -199,7 +199,7 @@ bad things happen location = /sub { proxy_ignore_client_abort on; - proxy_pass http://agentzh.org:12345/; + proxy_pass http://127.0.0.2:12345/; } location = /sleep { @@ -240,7 +240,7 @@ client prematurely closed connection location = /sub { proxy_ignore_client_abort off; - proxy_pass http://agentzh.org:12345/; + proxy_pass http://127.0.0.2:12345/; } --- request GET /t @@ -545,7 +545,7 @@ client prematurely closed connection return end - ok, err = sock:connect("127.0.0.1", $TEST_NGINX_REDIS_PORT) + local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_REDIS_PORT) if not ok then ngx.log(ngx.ERR, "failed to connect: ", err) return diff --git a/debian/modules/http-lua/t/023-rewrite/exec.t b/debian/modules/http-lua/t/023-rewrite/exec.t index edd4607..59691cb 100644 --- a/debian/modules/http-lua/t/023-rewrite/exec.t +++ b/debian/modules/http-lua/t/023-rewrite/exec.t @@ -326,7 +326,7 @@ hello --- config location /main { rewrite_by_lua ' - res = ngx.location.capture("/test_loc"); + local res = ngx.location.capture("/test_loc"); ngx.print("hello, ", res.body) '; content_by_lua return; @@ -354,7 +354,7 @@ hello, bah --- config location /main { rewrite_by_lua ' - res = ngx.location.capture("/test_loc"); + local res = ngx.location.capture("/test_loc"); ngx.print("hello, ", res.body) '; content_by_lua return; diff --git a/debian/modules/http-lua/t/023-rewrite/mixed.t b/debian/modules/http-lua/t/023-rewrite/mixed.t index 0f742b2..5b38d3f 100644 --- a/debian/modules/http-lua/t/023-rewrite/mixed.t +++ b/debian/modules/http-lua/t/023-rewrite/mixed.t @@ -35,7 +35,7 @@ __DATA__ rewrite_by_lua ' ngx.location.capture("/flush"); - res = ngx.location.capture("/memc"); + local res = ngx.location.capture("/memc"); print("rewrite GET: " .. res.status); res = ngx.location.capture("/memc", @@ -49,7 +49,7 @@ __DATA__ content_by_lua ' ngx.location.capture("/flush"); - res = ngx.location.capture("/memc"); + local res = ngx.location.capture("/memc"); ngx.say("content GET: " .. res.status); res = ngx.location.capture("/memc", diff --git a/debian/modules/http-lua/t/023-rewrite/multi-capture.t b/debian/modules/http-lua/t/023-rewrite/multi-capture.t index 083ec78..a0a02b7 100644 --- a/debian/modules/http-lua/t/023-rewrite/multi-capture.t +++ b/debian/modules/http-lua/t/023-rewrite/multi-capture.t @@ -154,7 +154,7 @@ res2.body = b location /main { rewrite_by_lua ' - res = ngx.location.capture("/foo?n=1") + local res = ngx.location.capture("/foo?n=1") ngx.say("top res.status = " .. res.status) ngx.say("top res.body = [" .. res.body .. "]") '; diff --git a/debian/modules/http-lua/t/023-rewrite/req-socket.t b/debian/modules/http-lua/t/023-rewrite/req-socket.t index 87cbbbe..9292385 100644 --- a/debian/modules/http-lua/t/023-rewrite/req-socket.t +++ b/debian/modules/http-lua/t/023-rewrite/req-socket.t @@ -325,7 +325,7 @@ found the end of the stream === TEST 4: attempt to use the req socket across request boundary --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /t { rewrite_by_lua ' @@ -376,7 +376,7 @@ hello world === TEST 5: receive until on request_body - receiveuntil(1) on the last byte of the body See https://groups.google.com/group/openresty/browse_thread/thread/43cf01da3c681aba for details --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /t { rewrite_by_lua ' @@ -440,7 +440,7 @@ done === TEST 6: pipelined POST requests --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /t { rewrite_by_lua ' diff --git a/debian/modules/http-lua/t/023-rewrite/sanity.t b/debian/modules/http-lua/t/023-rewrite/sanity.t index b90aa0e..73a85dc 100644 --- a/debian/modules/http-lua/t/023-rewrite/sanity.t +++ b/debian/modules/http-lua/t/023-rewrite/sanity.t @@ -69,7 +69,7 @@ GET /lua location /lua { # NOTE: the newline escape sequence must be double-escaped, as nginx config # parser will unescape first! - rewrite_by_lua 'v = ngx.var["request_uri"] ngx.print("request_uri: ", v, "\\n")'; + rewrite_by_lua 'local v = ngx.var["request_uri"] ngx.print("request_uri: ", v, "\\n")'; content_by_lua 'ngx.exit(ngx.OK)'; } --- request @@ -87,7 +87,7 @@ request_uri: /lua?a=1&b=2 } --- user_files >>> test.lua -v = ngx.var["request_uri"] +local v = ngx.var["request_uri"] ngx.print("request_uri: ", v, "\n") --- request GET /lua?a=1&b=2 @@ -140,7 +140,7 @@ result: -0.4090441561579 === TEST 7: read $arg_xxx --- config location = /lua { - rewrite_by_lua 'who = ngx.var.arg_who + rewrite_by_lua 'local who = ngx.var.arg_who ngx.print("Hello, ", who, "!")'; content_by_lua 'ngx.exit(ngx.OK)'; } @@ -159,7 +159,7 @@ Hello, agentzh! location /lua { rewrite_by_lua ' -res = ngx.location.capture("/other") +local res = ngx.location.capture("/other") ngx.print("status=", res.status, " ") ngx.print("body=", res.body) '; @@ -175,7 +175,7 @@ status=200 body=hello, world === TEST 9: capture non-existed location --- config location /lua { - rewrite_by_lua 'res = ngx.location.capture("/other"); ngx.print("status=", res.status)'; + rewrite_by_lua 'local res = ngx.location.capture("/other"); ngx.print("status=", res.status)'; content_by_lua 'ngx.exit(ngx.OK)'; } --- request @@ -187,7 +187,7 @@ GET /lua === TEST 10: invalid capture location (not as expected...) --- config location /lua { - rewrite_by_lua 'res = ngx.location.capture("*(#*"); ngx.say("res=", res.status)'; + rewrite_by_lua 'local res = ngx.location.capture("*(#*"); ngx.say("res=", res.status)'; content_by_lua 'ngx.exit(ngx.OK)'; } --- request @@ -270,7 +270,7 @@ end ngx.print("num is: ", num, "\\n"); if (num > 0) then - res = ngx.location.capture("/recur?num="..tostring(num - 1)); + local res = ngx.location.capture("/recur?num="..tostring(num - 1)); ngx.print("status=", res.status, " "); ngx.print("body=", res.body); else @@ -359,7 +359,7 @@ location /sub { } location /parent { set $a 12; - rewrite_by_lua 'res = ngx.location.capture("/sub"); ngx.print(res.body)'; + rewrite_by_lua 'local res = ngx.location.capture("/sub"); ngx.print(res.body)'; content_by_lua 'ngx.exit(ngx.OK)'; } --- request @@ -377,7 +377,7 @@ location /parent { set $a ''; rewrite_by_lua ' ngx.var.a = 12; - res = ngx.location.capture( + local res = ngx.location.capture( "/sub", { share_all_vars = true } ); @@ -399,7 +399,7 @@ location /sub { } location /parent { rewrite_by_lua ' - res = ngx.location.capture("/sub", { share_all_vars = true }); + local res = ngx.location.capture("/sub", { share_all_vars = true }); ngx.say(ngx.var.a) '; @@ -421,7 +421,7 @@ location /sub { location /parent { rewrite_by_lua ' - res = ngx.location.capture("/sub", { share_all_vars = false }); + local res = ngx.location.capture("/sub", { share_all_vars = false }); ngx.say(ngx.var.a) '; content_by_lua return; @@ -441,7 +441,7 @@ GET /parent location /lua { rewrite_by_lua ' - res = ngx.location.capture("/other"); + local res = ngx.location.capture("/other"); ngx.say("type: ", res.header["Content-Type"]); '; @@ -466,7 +466,7 @@ type: foo/bar location /lua { rewrite_by_lua ' - res = ngx.location.capture("/other"); + local res = ngx.location.capture("/other"); ngx.say("type: ", res.header["Content-Type"]); ngx.say("Bar: ", res.header["Bar"]); '; @@ -494,7 +494,7 @@ Bar: Bah location /lua { rewrite_by_lua ' - res = ngx.location.capture("/other"); + local res = ngx.location.capture("/other"); ngx.say("type: ", res.header["Content-Type"]); ngx.say("Bar: ", res.header["Bar"] or "nil"); '; diff --git a/debian/modules/http-lua/t/023-rewrite/socket-keepalive.t b/debian/modules/http-lua/t/023-rewrite/socket-keepalive.t index 489a70f..8b532ea 100644 --- a/debian/modules/http-lua/t/023-rewrite/socket-keepalive.t +++ b/debian/modules/http-lua/t/023-rewrite/socket-keepalive.t @@ -27,7 +27,7 @@ __DATA__ === TEST 1: sanity --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -104,7 +104,7 @@ lua tcp socket get keepalive peer: using connection === TEST 2: free up the whole connection pool if no active connections --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -177,7 +177,7 @@ received: OK === TEST 3: upstream sockets close prematurely --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; keepalive_timeout 100ms; @@ -254,7 +254,7 @@ done === TEST 4: http keepalive --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location /t { @@ -815,7 +815,7 @@ lua tcp socket keepalive timeout: unlimited === TEST 11: sanity (uds) --- http_config eval " - lua_package_path '$::HtmlDir/?.lua;./?.lua'; + lua_package_path '$::HtmlDir/?.lua;./?.lua;;'; server { listen unix:$::HtmlDir/nginx.sock; default_type 'text/plain'; @@ -953,7 +953,7 @@ lua tcp socket get keepalive peer: using connection === TEST 13: github issue #110: ngx.exit with HTTP_NOT_FOUND causes worker process to exit --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config error_page 404 /404.html; location /t { diff --git a/debian/modules/http-lua/t/023-rewrite/subrequest.t b/debian/modules/http-lua/t/023-rewrite/subrequest.t index 5d1e8f0..cb8523c 100644 --- a/debian/modules/http-lua/t/023-rewrite/subrequest.t +++ b/debian/modules/http-lua/t/023-rewrite/subrequest.t @@ -27,7 +27,7 @@ __DATA__ location /lua { rewrite_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { method = ngx.HTTP_DELETE }); ngx.print(res.body) @@ -54,7 +54,7 @@ DELETE location /lua { rewrite_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { method = ngx.HTTP_DELETE }); ngx.print(res.body) @@ -82,7 +82,7 @@ DELETE location /lua { rewrite_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { method = ngx.HTTP_POST }); ngx.print(res.body) @@ -105,7 +105,7 @@ POST location /lua { rewrite_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { method = ngx.HTTP_HEAD }); ngx.print(res.body) @@ -131,7 +131,7 @@ GET /lua location /lua { rewrite_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { method = ngx.HTTP_GET }); ngx.print(res.body) @@ -158,7 +158,7 @@ GET location /lua { rewrite_by_lua ' - res = ngx.location.capture("/foo") + local res = ngx.location.capture("/foo") ngx.print(res.body) '; @@ -184,7 +184,7 @@ GET location /lua { rewrite_by_lua ' - res = ngx.location.capture("/foo", {}) + local res = ngx.location.capture("/foo", {}) ngx.print(res.body) '; @@ -213,7 +213,7 @@ GET location /lua { rewrite_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { method = ngx.HTTP_PUT, body = "hello" }); ngx.print(res.body) @@ -241,7 +241,7 @@ hello location /lua { rewrite_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { method = ngx.HTTP_PUT, body = "hello" }); ngx.print(res.body) @@ -276,7 +276,7 @@ hello location /lua { rewrite_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { method = ngx.HTTP_PUT, body = "hello" }); ngx.print(res.body) @@ -313,7 +313,7 @@ GET location /lua { rewrite_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { method = ngx.HTTP_POST, body = "hello" }); ngx.print(res.body) @@ -345,7 +345,7 @@ hello rewrite_by_lua ' ngx.location.capture("/flush"); - res = ngx.location.capture("/memc"); + local res = ngx.location.capture("/memc"); ngx.say("GET: " .. res.status); res = ngx.location.capture("/memc", @@ -386,7 +386,7 @@ cached: hello ngx.location.capture("/flush", { share_all_vars = true }); - res = ngx.location.capture("/memc", + local res = ngx.location.capture("/memc", { share_all_vars = true }); ngx.say("GET: " .. res.status); @@ -417,7 +417,7 @@ cached: hello location /lua { rewrite_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { args = {} }) ngx.print(res.body) '; @@ -437,7 +437,7 @@ GET /lua location /lua { rewrite_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { args = { ["fo="] = "=>" } }) ngx.print(res.body) '; @@ -458,7 +458,7 @@ fo%3D=%3D%3E location /lua { rewrite_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { args = { ["fo="] = "=>", ["="] = ":" } }) ngx.print(res.body) @@ -480,7 +480,7 @@ GET /lua location /lua { rewrite_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { args = { foo = 3, bar = "hello" } }) ngx.print(res.body) @@ -502,7 +502,7 @@ GET /lua location /lua { rewrite_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { args = { [57] = "hi" } }) ngx.print(res.body) '; @@ -523,7 +523,7 @@ GET /lua location /lua { rewrite_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { args = { "hi" } }) ngx.print(res.body) '; @@ -544,7 +544,7 @@ GET /lua location /lua { rewrite_by_lua ' - res = ngx.location.capture("/foo?a=3", + local res = ngx.location.capture("/foo?a=3", { args = { b = 4 } }) ngx.print(res.body) '; @@ -565,7 +565,7 @@ a=3&b=4 location /lua { rewrite_by_lua ' - res = ngx.location.capture("/foo?a=3", + local res = ngx.location.capture("/foo?a=3", { args = "b=4" }) ngx.print(res.body) '; diff --git a/debian/modules/http-lua/t/023-rewrite/tcp-socket-timeout.t b/debian/modules/http-lua/t/023-rewrite/tcp-socket-timeout.t index 329c045..e713bb5 100644 --- a/debian/modules/http-lua/t/023-rewrite/tcp-socket-timeout.t +++ b/debian/modules/http-lua/t/023-rewrite/tcp-socket-timeout.t @@ -46,7 +46,7 @@ __DATA__ location /t1 { rewrite_by_lua ' local sock = ngx.socket.tcp() - local ok, err = sock:connect("agentzh.org", 12345) + local ok, err = sock:connect("127.0.0.2", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -63,7 +63,7 @@ GET /t1 failed to connect: timeout --- error_log lua tcp socket connect timeout: 100 -lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 +lua tcp socket connect timed out, when connecting to 127.0.0.2:12345 --- timeout: 10 @@ -79,7 +79,7 @@ lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 rewrite_by_lua ' local sock = ngx.socket.tcp() sock:settimeout(150) - local ok, err = sock:connect("agentzh.org", 12345) + local ok, err = sock:connect("127.0.0.2", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -114,7 +114,7 @@ lua tcp socket connect timeout: 150 rewrite_by_lua ' local sock = ngx.socket.tcp() sock:settimeout(nil) - local ok, err = sock:connect("agentzh.org", 12345) + local ok, err = sock:connect("127.0.0.2", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -149,7 +149,7 @@ lua tcp socket connect timeout: 102 rewrite_by_lua ' local sock = ngx.socket.tcp() sock:settimeout(0) - local ok, err = sock:connect("agentzh.org", 12345) + local ok, err = sock:connect("127.0.0.2", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -185,7 +185,7 @@ lua tcp socket connect timeout: 102 rewrite_by_lua ' local sock = ngx.socket.tcp() sock:settimeout(-1) - local ok, err = sock:connect("agentzh.org", 12345) + local ok, err = sock:connect("127.0.0.2", 12345) if not ok then ngx.say("failed to connect: ", err) return diff --git a/debian/modules/http-lua/t/023-rewrite/tcp-socket.t b/debian/modules/http-lua/t/023-rewrite/tcp-socket.t index 41aeab7..5258487 100644 --- a/debian/modules/http-lua/t/023-rewrite/tcp-socket.t +++ b/debian/modules/http-lua/t/023-rewrite/tcp-socket.t @@ -250,11 +250,11 @@ attempt to send data on a closed socket: } --- request GET /t ---- response_body +--- response_body_like connected: 1 request sent: 56 -first line received: HTTP/1.1 200 OK -second line received: Server: openresty +first line received: HTTP\/1\.1 200 OK +second line received: (?:Date|Server): .*? --- no_error_log [error] @@ -304,7 +304,7 @@ qr/connect\(\) failed \(\d+: Connection refused\)/ location /test { rewrite_by_lua ' local sock = ngx.socket.tcp() - local ok, err = sock:connect("agentzh.org", 12345) + local ok, err = sock:connect("127.0.0.2", 12345) ngx.say("connect: ", ok, " ", err) local bytes @@ -329,7 +329,7 @@ send: nil closed receive: nil closed close: nil closed --- error_log -lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 +lua tcp socket connect timed out, when connecting to 127.0.0.2:12345 --- timeout: 10 @@ -940,7 +940,7 @@ close: 1 nil end end - ok, err = sock:close() + local ok, err = sock:close() ngx.say("close: ", ok, " ", err) '; @@ -1082,7 +1082,7 @@ close: 1 nil === TEST 19: cannot survive across request boundary (send) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location /t { @@ -1143,7 +1143,7 @@ received: OK|failed to send request: closed)\$" === TEST 20: cannot survive across request boundary (receive) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location /t { @@ -1214,7 +1214,7 @@ received: OK|failed to receive a line: closed \[nil\])$/ === TEST 21: cannot survive across request boundary (close) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location /t { @@ -1285,7 +1285,7 @@ received: OK|failed to close: closed)$/ === TEST 22: cannot survive across request boundary (connect) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location /t { @@ -2041,7 +2041,7 @@ close: 1 nil === TEST 33: bad request tries to connect --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location = /main { @@ -2097,7 +2097,7 @@ qr/runtime error: rewrite_by_lua\(nginx\.conf:\d+\):7: bad request/ === TEST 34: bad request tries to receive --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location = /main { @@ -2156,7 +2156,7 @@ qr/runtime error: rewrite_by_lua\(nginx\.conf:\d+\):14: bad request/ === TEST 35: bad request tries to send --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location = /main { @@ -2215,7 +2215,7 @@ qr/runtime error: rewrite_by_lua\(nginx\.conf:\d+\):14: bad request/ === TEST 36: bad request tries to close --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location = /main { @@ -2274,7 +2274,7 @@ qr/runtime error: rewrite_by_lua\(nginx\.conf:\d+\):14: bad request/ === TEST 37: bad request tries to set keepalive --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location = /main { @@ -2333,7 +2333,7 @@ qr/runtime error: rewrite_by_lua\(nginx\.conf:\d+\):14: bad request/ === TEST 38: bad request tries to receiveuntil --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location = /main { diff --git a/debian/modules/http-lua/t/023-rewrite/uthread-exec.t b/debian/modules/http-lua/t/023-rewrite/uthread-exec.t index 2bea7e7..9428bd6 100644 --- a/debian/modules/http-lua/t/023-rewrite/uthread-exec.t +++ b/debian/modules/http-lua/t/023-rewrite/uthread-exec.t @@ -23,7 +23,7 @@ __DATA__ --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.exec("/foo") end @@ -59,7 +59,7 @@ i am foo --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.exec("/foo") end @@ -95,7 +95,7 @@ i am foo --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.exec("/foo") end @@ -178,12 +178,12 @@ hello foo --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.exec("/foo") end - function g() + local function g() ngx.sleep(1) end @@ -270,7 +270,7 @@ hello foo location /lua { client_body_timeout 12000ms; rewrite_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.exec("/foo") end diff --git a/debian/modules/http-lua/t/023-rewrite/uthread-exit.t b/debian/modules/http-lua/t/023-rewrite/uthread-exit.t index 6ebbb67..e25f7f8 100644 --- a/debian/modules/http-lua/t/023-rewrite/uthread-exit.t +++ b/debian/modules/http-lua/t/023-rewrite/uthread-exit.t @@ -24,7 +24,7 @@ __DATA__ --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.exit(0) end @@ -87,7 +87,7 @@ hello in thread --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -172,13 +172,13 @@ after --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.say("f") ngx.exit(0) end - function g() + local function g() ngx.sleep(1) ngx.say("g") end @@ -262,7 +262,7 @@ f --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.say("exiting the user thread") ngx.exit(0) @@ -298,10 +298,10 @@ exiting the user thread === TEST 5: exit in user thread (entry thread is still pending on the DNS resolver for ngx.socket.tcp) --- config location /lua { - resolver agentzh.org; + resolver 127.0.0.2:12345; resolver_timeout 12s; rewrite_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.001) ngx.exit(0) @@ -311,7 +311,7 @@ exiting the user thread ngx.thread.spawn(f) ngx.say("after") local sock = ngx.socket.tcp() - local ok, err = sock:connect("agentzh.org", 12345) + local ok, err = sock:connect("127.0.0.2", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -403,11 +403,11 @@ after === TEST 6: exit in user thread (entry thread is still pending on the DNS resolver for ngx.socket.udp) --- config location /lua { - resolver agentzh.org; + resolver 127.0.0.2:12345; #resolver 127.0.0.1; resolver_timeout 12s; rewrite_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.001) ngx.exit(0) @@ -510,7 +510,7 @@ after --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -521,7 +521,7 @@ after ngx.say("after") local sock = ngx.socket.tcp() sock:settimeout(12000) - local ok, err = sock:connect("172.105.207.225", 12345) + local ok, err = sock:connect("127.0.0.2", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -600,7 +600,7 @@ after --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -700,7 +700,7 @@ after --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -806,7 +806,7 @@ after --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -901,7 +901,7 @@ after --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -995,7 +995,7 @@ after location /lua { client_body_timeout 12000ms; rewrite_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -1080,7 +1080,7 @@ after location /lua { client_body_timeout 12000ms; rewrite_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -1164,7 +1164,7 @@ attempt to abort with pending subrequests location /lua { client_body_timeout 12000ms; rewrite_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.exit(0) end @@ -1247,7 +1247,7 @@ attempt to abort with pending subrequests location /lua { client_body_timeout 12000ms; rewrite_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.exit(0) end diff --git a/debian/modules/http-lua/t/023-rewrite/uthread-redirect.t b/debian/modules/http-lua/t/023-rewrite/uthread-redirect.t index 83de1a3..0e636f7 100644 --- a/debian/modules/http-lua/t/023-rewrite/uthread-redirect.t +++ b/debian/modules/http-lua/t/023-rewrite/uthread-redirect.t @@ -25,7 +25,7 @@ __DATA__ location /lua { client_body_timeout 12000ms; rewrite_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.redirect(301) end @@ -113,7 +113,7 @@ attempt to abort with pending subrequests --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.redirect(301) end diff --git a/debian/modules/http-lua/t/023-rewrite/uthread-spawn.t b/debian/modules/http-lua/t/023-rewrite/uthread-spawn.t index 5552107..dccef87 100644 --- a/debian/modules/http-lua/t/023-rewrite/uthread-spawn.t +++ b/debian/modules/http-lua/t/023-rewrite/uthread-spawn.t @@ -23,7 +23,7 @@ __DATA__ --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.say("hello in thread") end @@ -68,11 +68,11 @@ after --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.say("in thread 1") end - function g() + local function g() ngx.say("in thread 2") end @@ -117,7 +117,7 @@ after 2 --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.say("before sleep") ngx.sleep(0.1) ngx.say("after sleep") @@ -154,13 +154,13 @@ after sleep --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.say("1: before sleep") ngx.sleep(0.2) ngx.say("1: after sleep") end - function g() + local function g() ngx.say("2: before sleep") ngx.sleep(0.1) ngx.say("2: after sleep") @@ -210,7 +210,7 @@ delete thread 2 --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.blah() end @@ -241,9 +241,9 @@ qr/lua user thread aborted: runtime error: rewrite_by_lua\(nginx\.conf:\d+\):3: --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.say("before capture") - res = ngx.location.capture("/proxy") + local res = ngx.location.capture("/proxy") ngx.say("after capture: ", res.body) end @@ -287,7 +287,7 @@ after capture: hello world --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.say("before capture") local res = ngx.location.capture("/proxy?foo") ngx.say("after capture: ", res.body) @@ -340,7 +340,7 @@ after capture: hello foo --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.say("before capture") local res = ngx.location.capture("/proxy?foo") ngx.say("after capture: ", res.body) @@ -394,13 +394,13 @@ capture: hello bar --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.say("f: before capture") local res = ngx.location.capture("/proxy?foo") ngx.say("f: after capture: ", res.body) end - function g() + local function g() ngx.say("g: before capture") local res = ngx.location.capture("/proxy?bah") ngx.say("g: after capture: ", res.body) @@ -472,7 +472,8 @@ g: after capture: hello bah --- config location /lua { rewrite_by_lua ' - function f() + local g + local function f() ngx.say("before g") ngx.thread.spawn(g) ngx.say("after g") @@ -518,7 +519,8 @@ after g --- config location /lua { rewrite_by_lua ' - function f() + local g + local function f() ngx.say("before g") ngx.thread.spawn(g) ngx.say("after g") @@ -566,7 +568,7 @@ hello in g() location /lua { rewrite_by_lua ' local co - function f() + local function f() co = coroutine.running() ngx.sleep(0.1) end @@ -599,7 +601,7 @@ status: running location /lua { rewrite_by_lua ' local co - function f() + local function f() co = coroutine.running() end @@ -631,7 +633,8 @@ status: zombie location /lua { rewrite_by_lua ' local co - function f() + local g + local function f() co = coroutine.running() local co2 = coroutine.create(g) coroutine.resume(co2) @@ -670,7 +673,8 @@ status: normal --- config location /lua { rewrite_by_lua ' - function f() + local g + local function f() ngx.say("before g") ngx.thread.spawn(g) ngx.say("after g") @@ -717,7 +721,7 @@ after f rewrite_by_lua ' local yield = coroutine.yield - function f() + local function f() local self = coroutine.running() ngx.say("f 1") yield(self) @@ -770,7 +774,7 @@ f 3 rewrite_by_lua ' local yield = coroutine.yield - function f() + local function f() local self = coroutine.running() ngx.say("f 1") yield(self) @@ -779,7 +783,7 @@ f 3 ngx.say("f 3") end - function g() + local function g() local self = coroutine.running() ngx.say("g 1") yield(self) @@ -826,7 +830,7 @@ g 3 --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.say("hello in thread") coroutine.yield(coroutine.running) ngx.flush(true) @@ -863,12 +867,12 @@ after --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.say("hello from f") ngx.flush(true) end - function g() + local function g() ngx.say("hello from g") ngx.flush(true) end @@ -914,7 +918,7 @@ hello from g --- config location /lua { rewrite_by_lua ' - function f() + local function f() local sock = ngx.socket.tcp() local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_MEMCACHED_PORT) if not ok then @@ -966,7 +970,7 @@ received: OK --- config location /lua { rewrite_by_lua ' - function f() + local function f() local sock = ngx.socket.udp() local ok, err = sock:setpeername("127.0.0.1", 12345) local bytes, err = sock:send("blah") @@ -1027,7 +1031,7 @@ after)$ --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.req.read_body() local body = ngx.req.get_body_data() ngx.say("body: ", body) @@ -1073,7 +1077,7 @@ body: hello world)$ --- config location /lua { rewrite_by_lua ' - function f() + local function f() local sock = ngx.req.socket() local body, err = sock:receive(11) if not body then diff --git a/debian/modules/http-lua/t/024-access/client-abort.t b/debian/modules/http-lua/t/024-access/client-abort.t index c16f4ea..83bf0a4 100644 --- a/debian/modules/http-lua/t/024-access/client-abort.t +++ b/debian/modules/http-lua/t/024-access/client-abort.t @@ -200,7 +200,7 @@ bad things happen location = /sub { proxy_ignore_client_abort on; - proxy_pass http://agentzh.org:12345/; + proxy_pass http://127.0.0.2:12345/; } location = /sleep { @@ -241,7 +241,7 @@ client prematurely closed connection location = /sub { proxy_ignore_client_abort off; - proxy_pass http://agentzh.org:12345/; + proxy_pass http://127.0.0.2:12345/; } --- request GET /t @@ -546,7 +546,7 @@ client prematurely closed connection return end - ok, err = sock:connect("127.0.0.1", $TEST_NGINX_REDIS_PORT) + local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_REDIS_PORT) if not ok then ngx.log(ngx.ERR, "failed to connect: ", err) return diff --git a/debian/modules/http-lua/t/024-access/exec.t b/debian/modules/http-lua/t/024-access/exec.t index 43c1a77..d168a47 100644 --- a/debian/modules/http-lua/t/024-access/exec.t +++ b/debian/modules/http-lua/t/024-access/exec.t @@ -326,7 +326,7 @@ hello --- config location /main { access_by_lua ' - res = ngx.location.capture("/test_loc"); + local res = ngx.location.capture("/test_loc"); ngx.print("hello, ", res.body) '; content_by_lua return; diff --git a/debian/modules/http-lua/t/024-access/mixed.t b/debian/modules/http-lua/t/024-access/mixed.t index a9f8039..22f0037 100644 --- a/debian/modules/http-lua/t/024-access/mixed.t +++ b/debian/modules/http-lua/t/024-access/mixed.t @@ -35,7 +35,7 @@ __DATA__ access_by_lua ' ngx.location.capture("/flush"); - res = ngx.location.capture("/memc"); + local res = ngx.location.capture("/memc"); print("access GET: ", res.status); res = ngx.location.capture("/memc", @@ -49,7 +49,7 @@ __DATA__ content_by_lua ' ngx.location.capture("/flush"); - res = ngx.location.capture("/memc"); + local res = ngx.location.capture("/memc"); ngx.say("content GET: " .. res.status); res = ngx.location.capture("/memc", @@ -187,7 +187,7 @@ world\x03\x04\xff rewrite_by_lua ' ngx.location.capture("/flush"); - res = ngx.location.capture("/memc"); + local res = ngx.location.capture("/memc"); print("rewrite GET: " .. res.status); res = ngx.location.capture("/memc", @@ -201,7 +201,7 @@ world\x03\x04\xff access_by_lua ' ngx.location.capture("/flush"); - res = ngx.location.capture("/memc"); + local res = ngx.location.capture("/memc"); print("access GET: " .. res.status); res = ngx.location.capture("/memc", @@ -215,7 +215,7 @@ world\x03\x04\xff content_by_lua ' ngx.location.capture("/flush"); - res = ngx.location.capture("/memc"); + local res = ngx.location.capture("/memc"); ngx.say("content GET: " .. res.status); res = ngx.location.capture("/memc", diff --git a/debian/modules/http-lua/t/024-access/multi-capture.t b/debian/modules/http-lua/t/024-access/multi-capture.t index 930b74d..b1757dd 100644 --- a/debian/modules/http-lua/t/024-access/multi-capture.t +++ b/debian/modules/http-lua/t/024-access/multi-capture.t @@ -154,7 +154,7 @@ res2.body = b location /main { access_by_lua ' - res = ngx.location.capture("/foo?n=1") + local res = ngx.location.capture("/foo?n=1") ngx.say("top res.status = " .. res.status) ngx.say("top res.body = [" .. res.body .. "]") '; diff --git a/debian/modules/http-lua/t/024-access/sanity.t b/debian/modules/http-lua/t/024-access/sanity.t index 7ff177f..e5612a8 100644 --- a/debian/modules/http-lua/t/024-access/sanity.t +++ b/debian/modules/http-lua/t/024-access/sanity.t @@ -69,7 +69,7 @@ GET /lua location /lua { # NOTE: the newline escape sequence must be double-escaped, as nginx config # parser will unescape first! - access_by_lua 'v = ngx.var["request_uri"] ngx.print("request_uri: ", v, "\\n")'; + access_by_lua 'local v = ngx.var["request_uri"] ngx.print("request_uri: ", v, "\\n")'; content_by_lua 'ngx.exit(ngx.OK)'; } --- request @@ -87,7 +87,7 @@ request_uri: /lua?a=1&b=2 } --- user_files >>> test.lua -v = ngx.var["request_uri"] +local v = ngx.var["request_uri"] ngx.print("request_uri: ", v, "\n") --- request GET /lua?a=1&b=2 @@ -140,7 +140,7 @@ result: -0.4090441561579 === TEST 7: read $arg_xxx --- config location = /lua { - access_by_lua 'who = ngx.var.arg_who + access_by_lua 'local who = ngx.var.arg_who ngx.print("Hello, ", who, "!")'; content_by_lua 'ngx.exit(ngx.OK)'; } @@ -159,7 +159,7 @@ Hello, agentzh! location /lua { access_by_lua ' -res = ngx.location.capture("/other") +local res = ngx.location.capture("/other") ngx.print("status=", res.status, " ") ngx.print("body=", res.body) '; @@ -175,7 +175,7 @@ status=200 body=hello, world === TEST 9: capture non-existed location --- config location /lua { - access_by_lua 'res = ngx.location.capture("/other"); ngx.print("status=", res.status)'; + access_by_lua 'local res = ngx.location.capture("/other"); ngx.print("status=", res.status)'; content_by_lua 'ngx.exit(ngx.OK)'; } --- request @@ -187,7 +187,7 @@ GET /lua === TEST 10: invalid capture location (not as expected...) --- config location /lua { - access_by_lua 'res = ngx.location.capture("*(#*"); ngx.say("res=", res.status)'; + access_by_lua 'local res = ngx.location.capture("*(#*"); ngx.say("res=", res.status)'; content_by_lua 'ngx.exit(ngx.OK)'; } --- request @@ -244,7 +244,7 @@ GET /lua ngx.print("num is: ", num, "\\n"); if (num > 0) then - res = ngx.location.capture("/recur?num="..tostring(num - 1)); + local res = ngx.location.capture("/recur?num="..tostring(num - 1)); ngx.print("status=", res.status, " "); ngx.print("body=", res.body, "\\n"); else @@ -271,7 +271,7 @@ access phase not running in subrequests ngx.print("num is: ", num, "\\n"); if (num > 0) then - res = ngx.location.capture("/recur?num="..tostring(num - 1)); + local res = ngx.location.capture("/recur?num="..tostring(num - 1)); ngx.print("status=", res.status, " "); ngx.print("body=", res.body); else @@ -357,7 +357,7 @@ location /sub { } location /parent { set $a 12; - access_by_lua 'res = ngx.location.capture("/sub"); ngx.print(res.body)'; + access_by_lua 'local res = ngx.location.capture("/sub"); ngx.print(res.body)'; content_by_lua 'ngx.exit(ngx.OK)'; } --- request @@ -375,7 +375,7 @@ location /parent { set $a ''; access_by_lua ' ngx.var.a = 12; - res = ngx.location.capture( + local res = ngx.location.capture( "/sub", { share_all_vars = true } ); @@ -397,7 +397,7 @@ location /sub { } location /parent { access_by_lua ' - res = ngx.location.capture("/sub", { share_all_vars = true }); + local res = ngx.location.capture("/sub", { share_all_vars = true }); ngx.say(ngx.var.a) '; @@ -419,7 +419,7 @@ location /sub { location /parent { access_by_lua ' - res = ngx.location.capture("/sub", { share_all_vars = false }); + local res = ngx.location.capture("/sub", { share_all_vars = false }); ngx.say(ngx.var.a) '; content_by_lua return; @@ -439,7 +439,7 @@ GET /parent location /lua { access_by_lua ' - res = ngx.location.capture("/other"); + local res = ngx.location.capture("/other"); ngx.say("type: ", res.header["Content-Type"]); '; @@ -464,7 +464,7 @@ type: foo/bar location /lua { access_by_lua ' - res = ngx.location.capture("/other"); + local res = ngx.location.capture("/other"); ngx.say("type: ", res.header["Content-Type"]); ngx.say("Bar: ", res.header["Bar"]); '; @@ -492,7 +492,7 @@ Bar: Bah location /lua { access_by_lua ' - res = ngx.location.capture("/other"); + local res = ngx.location.capture("/other"); ngx.say("type: ", res.header["Content-Type"]); ngx.say("Bar: ", res.header["Bar"] or "nil"); '; diff --git a/debian/modules/http-lua/t/024-access/subrequest.t b/debian/modules/http-lua/t/024-access/subrequest.t index b6ccf11..665780a 100644 --- a/debian/modules/http-lua/t/024-access/subrequest.t +++ b/debian/modules/http-lua/t/024-access/subrequest.t @@ -27,7 +27,7 @@ __DATA__ location /lua { access_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { method = ngx.HTTP_DELETE }); ngx.print(res.body) @@ -54,7 +54,7 @@ DELETE location /lua { access_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { method = ngx.HTTP_DELETE }); ngx.print(res.body) @@ -82,7 +82,7 @@ DELETE location /lua { access_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { method = ngx.HTTP_POST }); ngx.print(res.body) @@ -105,7 +105,7 @@ POST location /lua { access_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { method = ngx.HTTP_HEAD }); ngx.print(res.body) @@ -131,7 +131,7 @@ GET /lua location /lua { access_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { method = ngx.HTTP_GET }); ngx.print(res.body) @@ -158,7 +158,7 @@ GET location /lua { access_by_lua ' - res = ngx.location.capture("/foo") + local res = ngx.location.capture("/foo") ngx.print(res.body) '; @@ -184,7 +184,7 @@ GET location /lua { access_by_lua ' - res = ngx.location.capture("/foo", {}) + local res = ngx.location.capture("/foo", {}) ngx.print(res.body) '; @@ -213,7 +213,7 @@ GET location /lua { access_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { method = ngx.HTTP_PUT, body = "hello" }); ngx.print(res.body) @@ -241,7 +241,7 @@ hello location /lua { access_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { method = ngx.HTTP_PUT, body = "hello" }); ngx.print(res.body) @@ -276,7 +276,7 @@ hello location /lua { access_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { method = ngx.HTTP_PUT, body = "hello" }); ngx.print(res.body) @@ -313,7 +313,7 @@ GET location /lua { access_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { method = ngx.HTTP_POST, body = "hello" }); ngx.print(res.body) @@ -345,7 +345,7 @@ hello access_by_lua ' ngx.location.capture("/flush"); - res = ngx.location.capture("/memc"); + local res = ngx.location.capture("/memc"); ngx.say("GET: " .. res.status); res = ngx.location.capture("/memc", @@ -386,7 +386,7 @@ cached: hello ngx.location.capture("/flush", { share_all_vars = true }); - res = ngx.location.capture("/memc", + local res = ngx.location.capture("/memc", { share_all_vars = true }); ngx.say("GET: " .. res.status); @@ -417,7 +417,7 @@ cached: hello location /lua { access_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { args = {} }) ngx.print(res.body) '; @@ -437,7 +437,7 @@ GET /lua location /lua { access_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { args = { ["fo="] = "=>" } }) ngx.print(res.body) '; @@ -458,7 +458,7 @@ fo%3D=%3D%3E location /lua { access_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { args = { ["fo="] = "=>", ["="] = ":" } }) ngx.print(res.body) @@ -480,7 +480,7 @@ GET /lua location /lua { access_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { args = { foo = 3, bar = "hello" } }) ngx.print(res.body) @@ -502,7 +502,7 @@ GET /lua location /lua { access_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { args = { [57] = "hi" } }) ngx.print(res.body) '; @@ -523,7 +523,7 @@ GET /lua location /lua { access_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { args = { "hi" } }) ngx.print(res.body) '; @@ -544,7 +544,7 @@ GET /lua location /lua { access_by_lua ' - res = ngx.location.capture("/foo?a=3", + local res = ngx.location.capture("/foo?a=3", { args = { b = 4 } }) ngx.print(res.body) '; @@ -565,7 +565,7 @@ a=3&b=4 location /lua { access_by_lua ' - res = ngx.location.capture("/foo?a=3", + local res = ngx.location.capture("/foo?a=3", { args = "b=4" }) ngx.print(res.body) '; diff --git a/debian/modules/http-lua/t/024-access/uthread-exec.t b/debian/modules/http-lua/t/024-access/uthread-exec.t index 7add3d4..9c88eb3 100644 --- a/debian/modules/http-lua/t/024-access/uthread-exec.t +++ b/debian/modules/http-lua/t/024-access/uthread-exec.t @@ -23,7 +23,7 @@ __DATA__ --- config location /lua { access_by_lua ' - function f() + local function f() ngx.exec("/foo") end @@ -59,7 +59,7 @@ i am foo --- config location /lua { access_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.exec("/foo") end @@ -95,7 +95,7 @@ i am foo --- config location /lua { access_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.exec("/foo") end @@ -179,12 +179,12 @@ hello foo --- config location /lua { access_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.exec("/foo") end - function g() + local function g() ngx.sleep(1) end @@ -271,7 +271,7 @@ hello foo location /lua { client_body_timeout 12000ms; access_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.exec("/foo") end diff --git a/debian/modules/http-lua/t/024-access/uthread-exit.t b/debian/modules/http-lua/t/024-access/uthread-exit.t index 02c2a1f..2757237 100644 --- a/debian/modules/http-lua/t/024-access/uthread-exit.t +++ b/debian/modules/http-lua/t/024-access/uthread-exit.t @@ -24,7 +24,7 @@ __DATA__ --- config location /lua { access_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.exit(0) end @@ -87,7 +87,7 @@ hello in thread --- config location /lua { access_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -172,13 +172,13 @@ after --- config location /lua { access_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.say("f") ngx.exit(0) end - function g() + local function g() ngx.sleep(1) ngx.say("g") end @@ -262,7 +262,7 @@ f --- config location /lua { access_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.say("exiting the user thread") ngx.exit(0) @@ -298,10 +298,10 @@ exiting the user thread === TEST 5: exit in user thread (entry thread is still pending on the DNS resolver for ngx.socket.tcp) --- config location /lua { - resolver agentzh.org; + resolver 127.0.0.2:12345; resolver_timeout 12s; access_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.001) ngx.exit(0) @@ -394,10 +394,10 @@ after === TEST 6: exit in user thread (entry thread is still pending on the DNS resolver for ngx.socket.udp) --- config location /lua { - resolver agentzh.org; + resolver 127.0.0.2:12345; resolver_timeout 12s; access_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.001) ngx.exit(0) @@ -491,7 +491,7 @@ after --- config location /lua { access_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -502,7 +502,7 @@ after ngx.say("after") local sock = ngx.socket.tcp() sock:settimeout(12000) - local ok, err = sock:connect("172.105.207.225", 12345) + local ok, err = sock:connect("127.0.0.2", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -582,7 +582,7 @@ after --- config location /lua { access_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -682,7 +682,7 @@ after --- config location /lua { access_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -788,7 +788,7 @@ after --- config location /lua { access_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -883,7 +883,7 @@ after --- config location /lua { access_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -977,7 +977,7 @@ after location /lua { client_body_timeout 12000ms; access_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -1062,7 +1062,7 @@ after location /lua { client_body_timeout 12000ms; access_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -1146,7 +1146,7 @@ attempt to abort with pending subrequests location /lua { client_body_timeout 12000ms; access_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.exit(0) end @@ -1229,7 +1229,7 @@ attempt to abort with pending subrequests location /lua { client_body_timeout 12000ms; access_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.exit(0) end diff --git a/debian/modules/http-lua/t/024-access/uthread-redirect.t b/debian/modules/http-lua/t/024-access/uthread-redirect.t index 4eb4759..cb99a35 100644 --- a/debian/modules/http-lua/t/024-access/uthread-redirect.t +++ b/debian/modules/http-lua/t/024-access/uthread-redirect.t @@ -25,7 +25,7 @@ __DATA__ location /lua { client_body_timeout 12000ms; access_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.redirect(301) end @@ -113,7 +113,7 @@ attempt to abort with pending subrequests --- config location /lua { access_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.redirect(301) end diff --git a/debian/modules/http-lua/t/024-access/uthread-spawn.t b/debian/modules/http-lua/t/024-access/uthread-spawn.t index 7c7ba3b..bc92ccd 100644 --- a/debian/modules/http-lua/t/024-access/uthread-spawn.t +++ b/debian/modules/http-lua/t/024-access/uthread-spawn.t @@ -23,7 +23,7 @@ __DATA__ --- config location /lua { access_by_lua ' - function f() + local function f() ngx.say("hello in thread") end @@ -68,11 +68,11 @@ after --- config location /lua { access_by_lua ' - function f() + local function f() ngx.say("in thread 1") end - function g() + local function g() ngx.say("in thread 2") end @@ -117,7 +117,7 @@ after 2 --- config location /lua { access_by_lua ' - function f() + local function f() ngx.say("before sleep") ngx.sleep(0.1) ngx.say("after sleep") @@ -154,13 +154,13 @@ after sleep --- config location /lua { access_by_lua ' - function f() + local function f() ngx.say("1: before sleep") ngx.sleep(0.2) ngx.say("1: after sleep") end - function g() + local function g() ngx.say("2: before sleep") ngx.sleep(0.1) ngx.say("2: after sleep") @@ -210,7 +210,7 @@ delete thread 2 --- config location /lua { access_by_lua ' - function f() + local function f() ngx.blah() end @@ -241,9 +241,9 @@ qr/lua user thread aborted: runtime error: access_by_lua\(nginx\.conf:\d+\):3: a --- config location /lua { access_by_lua ' - function f() + local function f() ngx.say("before capture") - res = ngx.location.capture("/proxy") + local res = ngx.location.capture("/proxy") ngx.say("after capture: ", res.body) end @@ -287,7 +287,7 @@ after capture: hello world --- config location /lua { access_by_lua ' - function f() + local function f() ngx.say("before capture") local res = ngx.location.capture("/proxy?foo") ngx.say("after capture: ", res.body) @@ -340,7 +340,7 @@ after capture: hello foo --- config location /lua { access_by_lua ' - function f() + local function f() ngx.say("before capture") local res = ngx.location.capture("/proxy?foo") ngx.say("after capture: ", res.body) @@ -395,13 +395,13 @@ capture: hello bar --- config location /lua { access_by_lua ' - function f() + local function f() ngx.say("f: before capture") local res = ngx.location.capture("/proxy?foo") ngx.say("f: after capture: ", res.body) end - function g() + local function g() ngx.say("g: before capture") local res = ngx.location.capture("/proxy?bah") ngx.say("g: after capture: ", res.body) @@ -473,7 +473,8 @@ g: after capture: hello bah --- config location /lua { access_by_lua ' - function f() + local g + local function f() ngx.say("before g") ngx.thread.spawn(g) ngx.say("after g") @@ -519,7 +520,8 @@ after g --- config location /lua { access_by_lua ' - function f() + local g + local function f() ngx.say("before g") ngx.thread.spawn(g) ngx.say("after g") @@ -567,7 +569,7 @@ hello in g() location /lua { access_by_lua ' local co - function f() + local function f() co = coroutine.running() ngx.sleep(0.1) end @@ -600,7 +602,7 @@ status: running location /lua { access_by_lua ' local co - function f() + local function f() co = coroutine.running() end @@ -632,7 +634,8 @@ status: zombie location /lua { access_by_lua ' local co - function f() + local g + local function f() co = coroutine.running() local co2 = coroutine.create(g) coroutine.resume(co2) @@ -671,7 +674,8 @@ status: normal --- config location /lua { access_by_lua ' - function f() + local g + local function f() ngx.say("before g") ngx.thread.spawn(g) ngx.say("after g") @@ -718,7 +722,7 @@ after f access_by_lua ' local yield = coroutine.yield - function f() + local function f() local self = coroutine.running() ngx.say("f 1") yield(self) @@ -771,7 +775,7 @@ f 3 access_by_lua ' local yield = coroutine.yield - function f() + local function f() local self = coroutine.running() ngx.say("f 1") yield(self) @@ -780,7 +784,7 @@ f 3 ngx.say("f 3") end - function g() + local function g() local self = coroutine.running() ngx.say("g 1") yield(self) @@ -827,7 +831,7 @@ g 3 --- config location /lua { access_by_lua ' - function f() + local function f() ngx.say("hello in thread") coroutine.yield(coroutine.running) ngx.flush(true) @@ -864,12 +868,12 @@ after --- config location /lua { access_by_lua ' - function f() + local function f() ngx.say("hello from f") ngx.flush(true) end - function g() + local function g() ngx.say("hello from g") ngx.flush(true) end @@ -915,7 +919,7 @@ hello from g --- config location /lua { access_by_lua ' - function f() + local function f() local sock = ngx.socket.tcp() local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_MEMCACHED_PORT) if not ok then @@ -967,7 +971,7 @@ received: OK --- config location /lua { access_by_lua ' - function f() + local function f() local sock = ngx.socket.udp() local ok, err = sock:setpeername("127.0.0.1", 12345) local bytes, err = sock:send("blah") @@ -1028,7 +1032,7 @@ after)$ --- config location /lua { access_by_lua ' - function f() + local function f() ngx.req.read_body() local body = ngx.req.get_body_data() ngx.say("body: ", body) @@ -1073,7 +1077,7 @@ body: hello world)$ --- config location /lua { access_by_lua ' - function f() + local function f() local sock = ngx.req.socket() local body, err = sock:receive(11) if not body then diff --git a/debian/modules/http-lua/t/025-codecache.t b/debian/modules/http-lua/t/025-codecache.t index 20791d7..22b78b2 100644 --- a/debian/modules/http-lua/t/025-codecache.t +++ b/debian/modules/http-lua/t/025-codecache.t @@ -4,7 +4,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * 155; +plan tests => repeat_each() * 163; #$ENV{LUA_PATH} = $ENV{HOME} . '/work/JSON4Lua-0.9.30/json/?.lua'; @@ -27,7 +27,7 @@ __DATA__ location /update { content_by_lua ' -- os.execute("(echo HERE; pwd) > /dev/stderr") - local f = assert(io.open("t/servroot/html/test.lua", "w")) + local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/test.lua", "w")) f:write("ngx.say(101)") f:close() ngx.say("updated") @@ -61,7 +61,7 @@ updated location /update { content_by_lua ' -- os.execute("(echo HERE; pwd) > /dev/stderr") - local f = assert(io.open("t/servroot/html/test.lua", "w")) + local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/test.lua", "w")) f:write("ngx.say(101)") f:close() ngx.say("updated") @@ -95,7 +95,7 @@ updated location /update { content_by_lua ' -- os.execute("(echo HERE; pwd) > /dev/stderr") - local f = assert(io.open("t/servroot/html/test.lua", "w")) + local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/test.lua", "w")) f:write("ngx.say(101)") f:close() ngx.say("updated") @@ -130,7 +130,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ location /update { content_by_lua ' -- os.execute("(echo HERE; pwd) > /dev/stderr") - local f = assert(io.open("t/servroot/html/test.lua", "w")) + local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/test.lua", "w")) f:write("ngx.say(101)") f:close() ngx.say("updated") @@ -166,7 +166,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ location /update { content_by_lua ' -- os.execute("(echo HERE; pwd) > /dev/stderr") - local f = assert(io.open("t/servroot/html/test.lua", "w")) + local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/test.lua", "w")) f:write("ngx.say(101)") f:close() ngx.say("updated") @@ -193,7 +193,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ === TEST 6: code cache explicitly off (affects require) + content_by_lua --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /lua { lua_code_cache off; @@ -204,7 +204,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ location /update { content_by_lua ' -- os.execute("(echo HERE; pwd) > /dev/stderr") - local f = assert(io.open("t/servroot/html/foo.lua", "w")) + local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/foo.lua", "w")) f:write("module(..., package.seeall); ngx.say(102);") f:close() ngx.say("updated") @@ -231,7 +231,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ === TEST 7: code cache explicitly off (affects require) + content_by_lua_file --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /lua { lua_code_cache off; @@ -240,7 +240,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ location /update { content_by_lua ' -- os.execute("(echo HERE; pwd) > /dev/stderr") - local f = assert(io.open("t/servroot/html/foo.lua", "w")) + local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/foo.lua", "w")) f:write("module(..., package.seeall); ngx.say(102);") f:close() ngx.say("updated") @@ -269,7 +269,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ === TEST 8: code cache explicitly off (affects require) + set_by_lua_file --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /lua { lua_code_cache off; @@ -279,7 +279,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ location /update { content_by_lua ' -- os.execute("(echo HERE; pwd) > /dev/stderr") - local f = assert(io.open("t/servroot/html/foo.lua", "w")) + local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/foo.lua", "w")) f:write("module(..., package.seeall); return 102;") f:close() ngx.say("updated") @@ -308,7 +308,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ === TEST 9: code cache explicitly on (affects require) + set_by_lua_file --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /lua { lua_code_cache on; @@ -318,7 +318,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ location /update { content_by_lua ' -- os.execute("(echo HERE; pwd) > /dev/stderr") - local f = assert(io.open("t/servroot/html/foo.lua", "w")) + local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/foo.lua", "w")) f:write("module(..., package.seeall); return 102;") f:close() ngx.say("updated") @@ -355,7 +355,7 @@ updated location /update { content_by_lua ' -- os.execute("(echo HERE; pwd) > /dev/stderr") - local f = assert(io.open("t/servroot/html/test.lua", "w")) + local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/test.lua", "w")) f:write("return 101") f:close() ngx.say("updated") @@ -390,7 +390,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ location /update { content_by_lua ' -- os.execute("(echo HERE; pwd) > /dev/stderr") - local f = assert(io.open("t/servroot/html/test.lua", "w")) + local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/test.lua", "w")) f:write("return 101") f:close() ngx.say("updated") @@ -468,7 +468,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ === TEST 14: no clear builtin lib "string" --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config lua_code_cache off; location /lua { @@ -504,7 +504,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ === TEST 15: do not skip luarocks --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua'; + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;'; lua_code_cache off;" --- config location /main { @@ -554,7 +554,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ === TEST 16: do not skip luarocks* --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua'; + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;'; lua_code_cache off;" --- config location /main { @@ -604,7 +604,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ === TEST 17: clear _G table --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config lua_code_cache off; location /t { @@ -1050,7 +1050,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/, === TEST 29: cosocket connection pool timeout (after Lua VM destroys) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config lua_code_cache off; location = /t { @@ -1118,7 +1118,7 @@ qr/\blua tcp socket keepalive: free connection pool [0-9A-F]+ for "127.0.0.1:/, === TEST 30: cosocket connection pool timeout (before Lua VM destroys) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config lua_code_cache off; location = /t { @@ -1244,3 +1244,133 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/, "decrementing the reference count for Lua VM: 1", "lua close the global Lua VM", ] + + + +=== TEST 32: make sure inline code keys are correct +GitHub issue #1428 +--- config +include ../html/a/proxy.conf; +include ../html/b/proxy.conf; +include ../html/c/proxy.conf; + +location /t { + echo_location /a/; + echo_location /b/; + echo_location /a/; + echo_location /c/; +} + +--- user_files +>>> a/proxy.conf +location /a/ { + content_by_lua_block { ngx.say("/a/ is called") } +} + +>>> b/proxy.conf +location /b/ { + content_by_lua_block { ngx.say("/b/ is called") } +} + +>>> c/proxy.conf +location /c/ { + content_by_lua_block { ngx.say("/b/ is called") } +} + +--- request +GET /t +--- response_body +/a/ is called +/b/ is called +/a/ is called +/b/ is called +--- grep_error_log eval: qr/looking up Lua code cache with key '.*?'/ +--- grep_error_log_out eval +[ +"looking up Lua code cache with key '=content_by_lua(proxy.conf:2)nhli_3c7137b8371d10bc148c8f8bb3042ee6' +looking up Lua code cache with key '=content_by_lua(proxy.conf:2)nhli_1dfe09105792ef65c8d576cc486d5e04' +looking up Lua code cache with key '=content_by_lua(proxy.conf:2)nhli_3c7137b8371d10bc148c8f8bb3042ee6' +looking up Lua code cache with key '=content_by_lua(proxy.conf:2)nhli_1dfe09105792ef65c8d576cc486d5e04' +", +"looking up Lua code cache with key '=content_by_lua(proxy.conf:2)nhli_3c7137b8371d10bc148c8f8bb3042ee6' +looking up Lua code cache with key '=content_by_lua(proxy.conf:2)nhli_1dfe09105792ef65c8d576cc486d5e04' +looking up Lua code cache with key '=content_by_lua(proxy.conf:2)nhli_3c7137b8371d10bc148c8f8bb3042ee6' +looking up Lua code cache with key '=content_by_lua(proxy.conf:2)nhli_1dfe09105792ef65c8d576cc486d5e04' +looking up Lua code cache with key '=content_by_lua(proxy.conf:2)nhli_3c7137b8371d10bc148c8f8bb3042ee6' +looking up Lua code cache with key '=content_by_lua(proxy.conf:2)nhli_1dfe09105792ef65c8d576cc486d5e04' +looking up Lua code cache with key '=content_by_lua(proxy.conf:2)nhli_3c7137b8371d10bc148c8f8bb3042ee6' +looking up Lua code cache with key '=content_by_lua(proxy.conf:2)nhli_1dfe09105792ef65c8d576cc486d5e04' +"] +--- log_level: debug +--- no_error_log +[error] + + + +=== TEST 33: make sure Lua code file keys are correct +GitHub issue #1428 +--- config +include ../html/a/proxy.conf; +include ../html/b/proxy.conf; +include ../html/c/proxy.conf; + +location /t { + echo_location /a/; + echo_location /b/; + echo_location /a/; + echo_location /c/; +} + +--- user_files +>>> a.lua +ngx.say("/a/ is called") + +>>> b.lua +ngx.say("/b/ is called") + +>>> c.lua +ngx.say("/b/ is called") + +>>> a/proxy.conf +location /a/ { + content_by_lua_file html/a.lua; +} + +>>> b/proxy.conf +location /b/ { + content_by_lua_file html/b.lua; +} + +>>> c/proxy.conf +location /c/ { + content_by_lua_file html/c.lua; +} + +--- request +GET /t +--- response_body +/a/ is called +/b/ is called +/a/ is called +/b/ is called +--- grep_error_log eval: qr/looking up Lua code cache with key '.*?'/ +--- grep_error_log_out eval +[ +"looking up Lua code cache with key 'nhlf_48a9a7def61143c003a7de1644e026e4' +looking up Lua code cache with key 'nhlf_68f5f4e946c3efd1cc206452b807e8b6' +looking up Lua code cache with key 'nhlf_48a9a7def61143c003a7de1644e026e4' +looking up Lua code cache with key 'nhlf_042c9b3a136fbacbbd0e4b9ad10896b7' +", +"looking up Lua code cache with key 'nhlf_48a9a7def61143c003a7de1644e026e4' +looking up Lua code cache with key 'nhlf_68f5f4e946c3efd1cc206452b807e8b6' +looking up Lua code cache with key 'nhlf_48a9a7def61143c003a7de1644e026e4' +looking up Lua code cache with key 'nhlf_042c9b3a136fbacbbd0e4b9ad10896b7' +looking up Lua code cache with key 'nhlf_48a9a7def61143c003a7de1644e026e4' +looking up Lua code cache with key 'nhlf_68f5f4e946c3efd1cc206452b807e8b6' +looking up Lua code cache with key 'nhlf_48a9a7def61143c003a7de1644e026e4' +looking up Lua code cache with key 'nhlf_042c9b3a136fbacbbd0e4b9ad10896b7' +" +] +--- log_level: debug +--- no_error_log +[error] diff --git a/debian/modules/http-lua/t/027-multi-capture.t b/debian/modules/http-lua/t/027-multi-capture.t index 9227fe5..9299561 100644 --- a/debian/modules/http-lua/t/027-multi-capture.t +++ b/debian/modules/http-lua/t/027-multi-capture.t @@ -151,7 +151,7 @@ res2.body = b location /main { content_by_lua ' - res = ngx.location.capture("/foo?n=1") + local res = ngx.location.capture("/foo?n=1") ngx.say("top res.status = " .. res.status) ngx.say("top res.body = [" .. res.body .. "]") '; @@ -743,7 +743,7 @@ proxy_cache_path conf/cache levels=1:2 keys_zone=STATIC:10m inactive=10m max_siz location = /proxy { proxy_cache STATIC; - proxy_pass http://agentzh.org:12345; + proxy_pass http://127.0.0.2:12345; proxy_cache_key $proxy_host$uri$args; proxy_cache_valid any 1s; #proxy_http_version 1.1; diff --git a/debian/modules/http-lua/t/028-req-header.t b/debian/modules/http-lua/t/028-req-header.t index ca92daa..8ddbb29 100644 --- a/debian/modules/http-lua/t/028-req-header.t +++ b/debian/modules/http-lua/t/028-req-header.t @@ -8,7 +8,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * (2 * blocks() + 43); +plan tests => repeat_each() * (2 * blocks() + 44); #no_diff(); no_long_string(); @@ -2008,3 +2008,25 @@ found 3 headers. --- no_error_log lua exceeding request header limit [error] + + + +=== TEST 61: setting Host header clears cached $host variable +--- config + location /req-header { + # this makes $host indexed and cacheable + set $foo $host; + + content_by_lua_block { + ngx.say(ngx.var.host) + ngx.req.set_header("Host", "new"); + ngx.say(ngx.var.host) + } + } +--- request +GET /req-header +--- response_body +localhost +new +--- no_error_log +[error] diff --git a/debian/modules/http-lua/t/030-uri-args.t b/debian/modules/http-lua/t/030-uri-args.t index a9d46ff..7af63c4 100644 --- a/debian/modules/http-lua/t/030-uri-args.t +++ b/debian/modules/http-lua/t/030-uri-args.t @@ -421,7 +421,7 @@ done ngx.req.set_uri_args("hello") ngx.req.set_uri("/bar", true); '; - proxy_pass http://agentzh.org:12345; + proxy_pass http://127.0.0.2:12345; } --- request GET /foo?world @@ -568,7 +568,7 @@ HTTP/1.0 ca%20t=%25 ngx.req.set_uri("/bar", true); ngx.exit(503) '; - proxy_pass http://agentzh.org:12345; + proxy_pass http://127.0.0.2:12345; } --- request GET /foo?world @@ -586,7 +586,7 @@ hello #set $args 'hello'; set $err ''; access_by_lua ' - res, err = pcall(ngx.req.set_uri, "/bar", true); + local res, err = pcall(ngx.req.set_uri, "/bar", true); ngx.var.err = err '; echo "err: $err"; @@ -626,7 +626,7 @@ uri: /bar location /foo { #set $args 'hello'; content_by_lua ' - res, err = pcall(ngx.req.set_uri, "/bar", true); + local res, err = pcall(ngx.req.set_uri, "/bar", true); ngx.say("err: ", err) '; } @@ -665,7 +665,7 @@ uri: /bar location /foo { #set $args 'hello'; set_by_lua $err ' - res, err = pcall(ngx.req.set_uri, "/bar", true); + local res, err = pcall(ngx.req.set_uri, "/bar", true); return err '; echo "err: $err"; @@ -788,7 +788,7 @@ GET /lua location /lua { content_by_lua ' local t = {bar = ngx.shared.dogs, foo = 3} - rc, err = pcall(ngx.encode_args, t) + local rc, err = pcall(ngx.encode_args, t) ngx.say("rc: ", rc, ", err: ", err) '; } @@ -1112,6 +1112,7 @@ HTTP/1.0 a=3&b=5&b=6 --- config location /lua { content_by_lua ' + local err local args = "a=bar&b=foo" args, err = ngx.decode_args(args) @@ -1135,6 +1136,7 @@ b = foo --- config location /lua { content_by_lua ' + local err local args = "a=bar&b=foo&a=baz" args, err = ngx.decode_args(args) @@ -1158,6 +1160,7 @@ b = foo --- config location /lua { content_by_lua ' + local err local args = "" args, err = ngx.decode_args(args) if err then @@ -1178,6 +1181,7 @@ n = 0 --- config location /lua { content_by_lua ' + local err local args = "a&b" args, err = ngx.decode_args(args) if err then @@ -1200,6 +1204,7 @@ b = true --- config location /lua { content_by_lua ' + local err local args = "a=&b=" args, err = ngx.decode_args(args) @@ -1223,6 +1228,7 @@ b = --- config location /lua { content_by_lua ' + local err local args = "a=bar&b=foo" args, err = ngx.decode_args(args, 1) if err then @@ -1246,6 +1252,7 @@ b = nil --- config location /lua { content_by_lua ' + local err local args = "a=bar&b=foo" args, err = ngx.decode_args(args, -1) @@ -1270,7 +1277,7 @@ b = foo location /lua { content_by_lua ' local s = "f+f=bar&B=foo" - args, err = ngx.decode_args(s) + local args, err = ngx.decode_args(s) if err then ngx.say("err: ", err) end @@ -1302,7 +1309,7 @@ s = f+f=bar&B=foo lua_need_request_body on; location /t { content_by_lua ' - function split(s, delimiter) + local function split(s, delimiter) local result = {} local from = 1 local delim_from, delim_to = string.find(s, delimiter, from) diff --git a/debian/modules/http-lua/t/034-match.t b/debian/modules/http-lua/t/034-match.t index ebe5762..473a11f 100644 --- a/debian/modules/http-lua/t/034-match.t +++ b/debian/modules/http-lua/t/034-match.t @@ -21,7 +21,7 @@ __DATA__ --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "([0-9]+)") + local m = ngx.re.match("hello, 1234", "([0-9]+)") if m then ngx.say(m[0]) else @@ -40,7 +40,7 @@ __DATA__ --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "(\\\\d+)") + local m = ngx.re.match("hello, 1234", "(\\\\d+)") if m then ngx.say(m[0]) else @@ -59,7 +59,7 @@ __DATA__ --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "(\\d+)") + local m = ngx.re.match("hello, 1234", "(\\d+)") if m then ngx.say(m[0]) else @@ -80,7 +80,7 @@ __DATA__ --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "[[\\d+]]") + local m = ngx.re.match("hello, 1234", "[[\\d+]]") if m then ngx.say(m[0]) else @@ -101,7 +101,7 @@ __DATA__ --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "([0-9]{2})[0-9]+") + local m = ngx.re.match("hello, 1234", "([0-9]{2})[0-9]+") if m then ngx.say(m[0]) ngx.say(m[1]) @@ -122,7 +122,7 @@ __DATA__ --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "([a-z]+).*?([0-9]{2})[0-9]+", "") + local m = ngx.re.match("hello, 1234", "([a-z]+).*?([0-9]{2})[0-9]+", "") if m then ngx.say(m[0]) ngx.say(m[1]) @@ -145,7 +145,7 @@ hello --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "([a-z]+).*?([0-9]{2})[0-9]+", "o") + local m = ngx.re.match("hello, 1234", "([a-z]+).*?([0-9]{2})[0-9]+", "o") if m then ngx.say(m[0]) ngx.say(m[1]) @@ -168,7 +168,7 @@ hello --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "foo") + local m = ngx.re.match("hello, 1234", "foo") if m then ngx.say(m[0]) else @@ -187,7 +187,7 @@ not matched: nil --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "HELLO") + local m = ngx.re.match("hello, 1234", "HELLO") if m then ngx.say(m[0]) else @@ -206,7 +206,7 @@ not matched: nil --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "HELLO", "i") + local m = ngx.re.match("hello, 1234", "HELLO", "i") if m then ngx.say(m[0]) else @@ -225,7 +225,7 @@ hello --- config location /re { content_by_lua ' - rc, err = pcall(ngx.re.match, "hello章亦春", "HELLO.{2}", "iu") + local rc, err = pcall(ngx.re.match, "hello章亦春", "HELLO.{2}", "iu") if not rc then ngx.say("FAIL: ", err) return @@ -249,7 +249,7 @@ hello --- config location /re { content_by_lua ' - m = ngx.re.match("hello\\nworld", "^world", "m") + local m = ngx.re.match("hello\\nworld", "^world", "m") if m then ngx.say(m[0]) else @@ -268,7 +268,7 @@ world --- config location /re { content_by_lua ' - m = ngx.re.match("hello\\nworld", ".*", "m") + local m = ngx.re.match("hello\\nworld", ".*", "m") if m then ngx.say(m[0]) else @@ -287,7 +287,7 @@ hello --- config location /re { content_by_lua ' - m = ngx.re.match("hello\\nworld", "^world", "s") + local m = ngx.re.match("hello\\nworld", "^world", "s") if m then ngx.say(m[0]) else @@ -306,7 +306,7 @@ not matched: nil --- config location /re { content_by_lua ' - m = ngx.re.match("hello\\nworld", ".*", "s") + local m = ngx.re.match("hello\\nworld", ".*", "s") if m then ngx.say(m[0]) else @@ -326,7 +326,7 @@ world --- config location /re { content_by_lua ' - m = ngx.re.match("hello\\nworld", "\\\\w \\\\w", "x") + local m = ngx.re.match("hello\\nworld", "\\\\w \\\\w", "x") if m then ngx.say(m[0]) else @@ -372,7 +372,7 @@ error: pcre_compile() failed: missing ) in "(abc" --- config location /re { content_by_lua ' - rc, m = pcall(ngx.re.match, "hello\\nworld", ".*", "Hm") + local rc, m = pcall(ngx.re.match, "hello\\nworld", ".*", "Hm") if rc then if m then ngx.say(m[0]) @@ -395,7 +395,7 @@ error: .*?unknown flag "H" \(flags "Hm"\) --- config location /re { content_by_lua ' - m = ngx.re.match("hello, world", "(world)|(hello)", "x") + local m = ngx.re.match("hello, world", "(world)|(hello)", "x") if m then ngx.say(m[0]) ngx.say(m[1]) @@ -418,7 +418,7 @@ hello --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "([0-9]+)(h?)") + local m = ngx.re.match("hello, 1234", "([0-9]+)(h?)") if m then ngx.say(m[0]) ngx.say(m[1]) @@ -442,7 +442,7 @@ hello --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "([0-9]+)", "a") + local m = ngx.re.match("hello, 1234", "([0-9]+)", "a") if m then ngx.say(m[0]) else @@ -461,7 +461,7 @@ not matched! --- config location /re { content_by_lua ' - m = ngx.re.match("1234, hello", "([0-9]+)", "a") + local m = ngx.re.match("1234, hello", "([0-9]+)", "a") if m then ngx.say(m[0]) else @@ -481,7 +481,7 @@ not matched! location /re { content_by_lua ' local ctx = {} - m = ngx.re.match("1234, hello", "([0-9]+)", "", ctx) + local m = ngx.re.match("1234, hello", "([0-9]+)", "", ctx) if m then ngx.say(m[0]) ngx.say(ctx.pos) @@ -504,7 +504,7 @@ not matched! location /re { content_by_lua ' local ctx = { pos = 3 } - m = ngx.re.match("1234, hello", "([0-9]+)", "", ctx) + local m = ngx.re.match("1234, hello", "([0-9]+)", "", ctx) if m then ngx.say(m[0]) ngx.say(ctx.pos) @@ -526,7 +526,7 @@ not matched! --- config location /re { set_by_lua $res ' - m = ngx.re.match("hello, 1234", "([0-9]+)") + local m = ngx.re.match("hello, 1234", "([0-9]+)") if m then return m[0] else @@ -569,7 +569,7 @@ baz } --- user_files >>> a.lua -m = ngx.re.match("hello, 1234", "(\\\s+)") +local m = ngx.re.match("hello, 1234", "(\\\s+)") if m then ngx.say("[", m[0], "]") else @@ -595,7 +595,7 @@ end local uri = "2" local regex = '(?:>[\\w\\s]*)'; ngx.say("regex: ", regex) -m = ngx.re.match(uri, regex, "oi") +local m = ngx.re.match(uri, regex, "oi") if m then ngx.say("[", m[0], "]") else @@ -613,7 +613,7 @@ regex: (?:>[\w\s]*) --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", [[\\d+]]) + local m = ngx.re.match("hello, 1234", [[\\d+]]) if m then ngx.say(m[0]) else @@ -660,7 +660,7 @@ error: pcre_compile() failed: missing ) in "([0-9]+" --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", [[([0-9]+)]]) + local m = ngx.re.match("hello, 1234", [[([0-9]+)]]) if m then ngx.say(m[0]) else @@ -1027,7 +1027,7 @@ exec opts: 0 >>> a.lua local re = [==[(?i:([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:=|<=>|r?like|sounds\s+like|regexp)([\s'\"`´’‘\(\)]*)?\2|([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp)([\s'\"`´’‘\(\)]*)?(?!\6)([\d\w]+))]==] -s = string.rep([[ABCDEFG]], 10) +local s = string.rep([[ABCDEFG]], 10) local start = ngx.now() @@ -1067,7 +1067,7 @@ error: pcre_exec() failed: -8 >>> a.lua local re = [==[(?i:([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:=|<=>|r?like|sounds\s+like|regexp)([\s'\"`´’‘\(\)]*)?\2|([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp)([\s'\"`´’‘\(\)]*)?(?!\6)([\d\w]+))]==] -s = string.rep([[ABCDEFG]], 10) +local s = string.rep([[ABCDEFG]], 10) local start = ngx.now() @@ -1101,7 +1101,7 @@ failed to match content_by_lua ' local res = {} local s = "hello, 1234" - m = ngx.re.match(s, [[(\\d)(\\d)]], "o", nil, res) + local m = ngx.re.match(s, [[(\\d)(\\d)]], "o", nil, res) if m then ngx.say("1: m size: ", #m) ngx.say("1: res size: ", #res) @@ -1132,11 +1132,12 @@ failed to match === TEST 48: init_by_lua --- http_config init_by_lua ' - m = ngx.re.match("hello, 1234", "(\\\\d+)") + package.loaded.m = ngx.re.match("hello, 1234", "(\\\\d+)") '; --- config location /re { content_by_lua ' + local m = package.loaded.m if m then ngx.say(m[0]) else diff --git a/debian/modules/http-lua/t/035-gmatch.t b/debian/modules/http-lua/t/035-gmatch.t index 0426997..0dfeaea 100644 --- a/debian/modules/http-lua/t/035-gmatch.t +++ b/debian/modules/http-lua/t/035-gmatch.t @@ -123,7 +123,7 @@ nil --- config location /re { content_by_lua ' - it = ngx.re.gmatch("hello, 1234", "([0-9]+)", "a") + local it = ngx.re.gmatch("hello, 1234", "([0-9]+)", "a") ngx.say(it()) '; } @@ -418,7 +418,7 @@ hello content_by_lua ' local a = {} for i = 1, 3 do - it = ngx.re.gmatch("hello, world", "[a-z]+") + local it = ngx.re.gmatch("hello, world", "[a-z]+") it() collectgarbage() table.insert(a, {"hello", "world"}) @@ -482,9 +482,9 @@ end GET /main --- response_body matched -sr failed: 500 ---- error_log -attempt to use ngx.re.gmatch iterator in a request that did not create it +matched +--- no_error_log +[error] @@ -518,7 +518,7 @@ matched: [] location /re { content_by_lua ' local it = ngx.re.gmatch("1234, 1234", "(?[0-9]+)") - m = it() + local m = it() if m then ngx.say(m[0]) ngx.say(m[1]) @@ -555,7 +555,7 @@ matched: [] content_by_lua ' local it = ngx.re.gmatch("1234, abcd, 1234", "(?[0-9]+)|(?[a-z]+)") - m = it() + local m = it() if m then ngx.say(m[0]) ngx.say(m[1]) @@ -599,7 +599,7 @@ abcd location /re { content_by_lua ' local it = ngx.re.gmatch("hello, 1234", "(?[a-z]+), (?[0-9]+)", "D") - m = it() + local m = it() if m then ngx.say(m[0]) ngx.say(m[1]) @@ -825,7 +825,7 @@ exec opts: 0 >>> a.lua local re = [==[(?i:([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:=|<=>|r?like|sounds\s+like|regexp)([\s'\"`´’‘\(\)]*)?\2|([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp)([\s'\"`´’‘\(\)]*)?(?!\6)([\d\w]+))]==] -s = string.rep([[ABCDEFG]], 10) +local s = string.rep([[ABCDEFG]], 10) local start = ngx.now() @@ -871,7 +871,7 @@ error: pcre_exec() failed: -8 >>> a.lua local re = [==[(?i:([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:=|<=>|r?like|sounds\s+like|regexp)([\s'\"`´’‘\(\)]*)?\2|([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp)([\s'\"`´’‘\(\)]*)?(?!\6)([\d\w]+))]==] -s = string.rep([[ABCDEFG]], 10) +local s = string.rep([[ABCDEFG]], 10) local start = ngx.now() @@ -881,7 +881,7 @@ if not it then return end -res, err = it() +local res, err = it() --[[ ngx.update_time() diff --git a/debian/modules/http-lua/t/036-sub.t b/debian/modules/http-lua/t/036-sub.t index 2b4b075..3e88eba 100644 --- a/debian/modules/http-lua/t/036-sub.t +++ b/debian/modules/http-lua/t/036-sub.t @@ -590,7 +590,7 @@ s: a好 >>> a.lua local re = [==[(?i:([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:=|<=>|r?like|sounds\s+like|regexp)([\s'\"`´’‘\(\)]*)?\2|([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp)([\s'\"`´’‘\(\)]*)?(?!\6)([\d\w]+))]==] -s = string.rep([[ABCDEFG]], 10) +local s = string.rep([[ABCDEFG]], 10) local start = ngx.now() @@ -693,7 +693,7 @@ ab.cd location = /t { content_by_lua ' - function test() + local function test() local data = [[ OUTER {FIRST} ]] diff --git a/debian/modules/http-lua/t/037-gsub.t b/debian/modules/http-lua/t/037-gsub.t index 4c5810d..41f86ac 100644 --- a/debian/modules/http-lua/t/037-gsub.t +++ b/debian/modules/http-lua/t/037-gsub.t @@ -511,7 +511,7 @@ s: aa >>> a.lua local re = [==[(?i:([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:=|<=>|r?like|sounds\s+like|regexp)([\s'\"`´’‘\(\)]*)?\2|([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp)([\s'\"`´’‘\(\)]*)?(?!\6)([\d\w]+))]==] -s = string.rep([[ABCDEFG]], 10) +local s = string.rep([[ABCDEFG]], 10) local start = ngx.now() diff --git a/debian/modules/http-lua/t/038-match-o.t b/debian/modules/http-lua/t/038-match-o.t index d61ff1f..f6ae010 100644 --- a/debian/modules/http-lua/t/038-match-o.t +++ b/debian/modules/http-lua/t/038-match-o.t @@ -20,7 +20,7 @@ __DATA__ --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "([0-9]+)", "o") + local m = ngx.re.match("hello, 1234", "([0-9]+)", "o") if m then ngx.say(m[0]) else @@ -39,7 +39,7 @@ __DATA__ --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "(\\\\d+)", "o") + local m = ngx.re.match("hello, 1234", "(\\\\d+)", "o") if m then ngx.say(m[0]) else @@ -58,7 +58,7 @@ __DATA__ --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "(\\d+)", "o") + local m = ngx.re.match("hello, 1234", "(\\d+)", "o") if m then ngx.say(m[0]) else @@ -79,7 +79,7 @@ __DATA__ --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "[[\\d+]]", "o") + local m = ngx.re.match("hello, 1234", "[[\\d+]]", "o") if m then ngx.say(m[0]) else @@ -100,7 +100,7 @@ __DATA__ --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "([0-9]{2})[0-9]+", "o") + local m = ngx.re.match("hello, 1234", "([0-9]{2})[0-9]+", "o") if m then ngx.say(m[0]) ngx.say(m[1]) @@ -121,7 +121,7 @@ __DATA__ --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "([a-z]+).*?([0-9]{2})[0-9]+", "o") + local m = ngx.re.match("hello, 1234", "([a-z]+).*?([0-9]{2})[0-9]+", "o") if m then ngx.say(m[0]) ngx.say(m[1]) @@ -144,7 +144,7 @@ hello --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "foo", "o") + local m = ngx.re.match("hello, 1234", "foo", "o") if m then ngx.say(m[0]) else @@ -163,7 +163,7 @@ not matched: nil --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "HELLO", "o") + local m = ngx.re.match("hello, 1234", "HELLO", "o") if m then ngx.say(m[0]) else @@ -182,7 +182,7 @@ not matched: nil --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "HELLO", "oi") + local m = ngx.re.match("hello, 1234", "HELLO", "oi") if m then ngx.say(m[0]) else @@ -224,7 +224,7 @@ this version of PCRE is not compiled with PCRE_UTF8 support|^hello章亦$ --- config location /re { content_by_lua ' - m = ngx.re.match("hello\\nworld", "^world", "mo") + local m = ngx.re.match("hello\\nworld", "^world", "mo") if m then ngx.say(m[0]) else @@ -243,7 +243,7 @@ world --- config location /re { content_by_lua ' - m = ngx.re.match("hello\\nworld", ".*", "om") + local m = ngx.re.match("hello\\nworld", ".*", "om") if m then ngx.say(m[0]) else @@ -262,7 +262,7 @@ hello --- config location /re { content_by_lua ' - m = ngx.re.match("hello\\nworld", "^world", "so") + local m = ngx.re.match("hello\\nworld", "^world", "so") if m then ngx.say(m[0]) else @@ -281,7 +281,7 @@ not matched: nil --- config location /re { content_by_lua ' - m = ngx.re.match("hello\\nworld", ".*", "os") + local m = ngx.re.match("hello\\nworld", ".*", "os") if m then ngx.say(m[0]) else @@ -301,7 +301,7 @@ world --- config location /re { content_by_lua ' - m = ngx.re.match("hello\\nworld", "\\\\w \\\\w", "xo") + local m = ngx.re.match("hello\\nworld", "\\\\w \\\\w", "xo") if m then ngx.say(m[0]) else @@ -347,7 +347,7 @@ error: pcre_compile() failed: missing ) in "(abc" --- config location /re { content_by_lua ' - rc, m = pcall(ngx.re.match, "hello\\nworld", ".*", "Ho") + local rc, m = pcall(ngx.re.match, "hello\\nworld", ".*", "Ho") if rc then if m then ngx.say(m[0]) @@ -370,7 +370,7 @@ error: pcre_compile() failed: missing ) in "(abc" --- config location /re { content_by_lua ' - m = ngx.re.match("hello, world", "(world)|(hello)", "xo") + local m = ngx.re.match("hello, world", "(world)|(hello)", "xo") if m then ngx.say(m[0]) ngx.say(m[1]) @@ -393,7 +393,7 @@ hello --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "([0-9]+)(h?)", "o") + local m = ngx.re.match("hello, 1234", "([0-9]+)(h?)", "o") if m then ngx.say(m[0]) ngx.say(m[1]) @@ -417,7 +417,7 @@ hello --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "([0-9]+)", "oa") + local m = ngx.re.match("hello, 1234", "([0-9]+)", "oa") if m then ngx.say(m[0]) else @@ -436,7 +436,7 @@ not matched! --- config location /re { content_by_lua ' - m = ngx.re.match("1234, hello", "([0-9]+)", "ao") + local m = ngx.re.match("1234, hello", "([0-9]+)", "ao") if m then ngx.say(m[0]) else @@ -456,7 +456,7 @@ not matched! location /re { content_by_lua ' local ctx = {} - m = ngx.re.match("1234, hello", "([0-9]+)", "o", ctx) + local m = ngx.re.match("1234, hello", "([0-9]+)", "o", ctx) if m then ngx.say(m[0]) ngx.say(ctx.pos) @@ -479,7 +479,7 @@ not matched! location /re { content_by_lua ' local ctx = { pos = 3 } - m = ngx.re.match("1234, hello", "([0-9]+)", "o", ctx) + local m = ngx.re.match("1234, hello", "([0-9]+)", "o", ctx) if m then ngx.say(m[0]) ngx.say(ctx.pos) @@ -501,7 +501,7 @@ not matched! --- config location /re { set_by_lua $res ' - m = ngx.re.match("hello, 1234", "([0-9]+)", "o") + local m = ngx.re.match("hello, 1234", "([0-9]+)", "o") if m then return m[0] else diff --git a/debian/modules/http-lua/t/041-header-filter.t b/debian/modules/http-lua/t/041-header-filter.t index 7d8ee74..0adc699 100644 --- a/debian/modules/http-lua/t/041-header-filter.t +++ b/debian/modules/http-lua/t/041-header-filter.t @@ -10,7 +10,7 @@ log_level('debug'); repeat_each(2); -plan tests => repeat_each() * 94; +plan tests => repeat_each() * (blocks() * 2 + 13); #no_diff(); #no_long_string(); @@ -416,7 +416,7 @@ lua release ngx.ctx -=== TEST 20: global got cleared for each single request +=== TEST 20: globals are shared by all requests --- config location /lua { set $foo ''; @@ -428,6 +428,7 @@ lua release ngx.ctx if not foo then foo = 1 else + ngx.log(ngx.INFO, "old foo: ", foo) foo = foo + 1 end ngx.var.foo = foo @@ -435,10 +436,13 @@ lua release ngx.ctx } --- request GET /lua ---- response_body -1 +--- response_body_like +^[12]$ --- no_error_log [error] +--- grep_error_log eval: qr/old foo: \d+/ +--- grep_error_log_out eval +["", "old foo: 1\n"] @@ -730,7 +734,8 @@ hello world --- config location /t { header_filter_by_lua ' - function foo() + local bar + local function foo() bar() end diff --git a/debian/modules/http-lua/t/043-shdict.t b/debian/modules/http-lua/t/043-shdict.t index 9183bf5..b0528e5 100644 --- a/debian/modules/http-lua/t/043-shdict.t +++ b/debian/modules/http-lua/t/043-shdict.t @@ -420,7 +420,7 @@ ngx_slab_alloc() failed: no memory in lua_shared_dict zone ngx.say(dogs:get(key)) key = string.rep("a", 65536) - ok, err = dogs:set(key, "world") + local ok, err = dogs:set(key, "world") if not ok then ngx.say("not ok: ", err) return @@ -2048,7 +2048,7 @@ get_stale ok: false, stale: false ngx.say("get not ok: ", err) return end - flags = err + local flags = err ngx.say("get_stale ok: ", data, ", flags: ", flags, ", stale: ", stale) diff --git a/debian/modules/http-lua/t/047-match-jit.t b/debian/modules/http-lua/t/047-match-jit.t index 2417a63..f53a408 100644 --- a/debian/modules/http-lua/t/047-match-jit.t +++ b/debian/modules/http-lua/t/047-match-jit.t @@ -20,7 +20,7 @@ __DATA__ --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "([0-9]+)", "j") + local m = ngx.re.match("hello, 1234", "([0-9]+)", "j") if m then ngx.say(m[0]) else @@ -41,7 +41,7 @@ pcre JIT compiling result: 1 --- config location /re { content_by_lua ' - m = ngx.re.match("hello, world", "([0-9]+)", "j") + local m = ngx.re.match("hello, world", "([0-9]+)", "j") if m then ngx.say(m[0]) else @@ -62,7 +62,7 @@ pcre JIT compiling result: 1 --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "([0-9]+)", "jo") + local m = ngx.re.match("hello, 1234", "([0-9]+)", "jo") if m then ngx.say(m[0]) else @@ -87,7 +87,7 @@ qr/pcre JIT compiling result: \d+/ --- config location /re { content_by_lua ' - m = ngx.re.match("hello, world", "([0-9]+)", "jo") + local m = ngx.re.match("hello, world", "([0-9]+)", "jo") if m then ngx.say(m[0]) else @@ -147,7 +147,7 @@ error: pcre_compile() failed: missing ) in "(abc" >>> a.lua local re = [==[(?i:([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:=|<=>|r?like|sounds\s+like|regexp)([\s'\"`´’‘\(\)]*)?\2|([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp)([\s'\"`´’‘\(\)]*)?(?!\6)([\d\w]+))]==] -s = string.rep([[ABCDEFG]], 21) +local s = string.rep([[ABCDEFG]], 21) local start = ngx.now() @@ -187,7 +187,7 @@ error: pcre_exec() failed: -8 >>> a.lua local re = [==[(?i:([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:=|<=>|r?like|sounds\s+like|regexp)([\s'\"`´’‘\(\)]*)?\2|([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp)([\s'\"`´’‘\(\)]*)?(?!\6)([\d\w]+))]==] -s = string.rep([[ABCDEFG]], 21) +local s = string.rep([[ABCDEFG]], 21) local start = ngx.now() diff --git a/debian/modules/http-lua/t/048-match-dfa.t b/debian/modules/http-lua/t/048-match-dfa.t index 28b5a60..edf3662 100644 --- a/debian/modules/http-lua/t/048-match-dfa.t +++ b/debian/modules/http-lua/t/048-match-dfa.t @@ -20,7 +20,7 @@ __DATA__ --- config location /re { content_by_lua ' - m = ngx.re.match("hello", "(he|hell)", "d") + local m = ngx.re.match("hello", "(he|hell)", "d") if m then ngx.say(m[0]) ngx.say(m[1]) @@ -43,7 +43,7 @@ nil --- config location /re { content_by_lua ' - m = ngx.re.match("hello", "(he|hell)", "do") + local m = ngx.re.match("hello", "(he|hell)", "do") if m then ngx.say(m[0]) ngx.say(m[1]) @@ -66,7 +66,7 @@ nil --- config location /re { content_by_lua ' - m = ngx.re.match("hello", "(he|hell)", "jd") + local m = ngx.re.match("hello", "(he|hell)", "jd") if m then ngx.say(m[0]) else @@ -85,7 +85,7 @@ hell --- config location /re { content_by_lua ' - m = ngx.re.match("world", "(he|hell)", "d") + local m = ngx.re.match("world", "(he|hell)", "d") if m then ngx.say(m[0]) else @@ -104,7 +104,7 @@ not matched! --- config location /re { content_by_lua ' - m = ngx.re.match("hello", "he|hell", "do") + local m = ngx.re.match("hello", "he|hell", "do") if m then ngx.say(m[0]) ngx.say(m[1]) @@ -127,7 +127,7 @@ nil --- config location /re { content_by_lua ' - m = ngx.re.match("world", "([0-9]+)", "do") + local m = ngx.re.match("world", "([0-9]+)", "do") if m then ngx.say(m[0]) else diff --git a/debian/modules/http-lua/t/055-subreq-vars.t b/debian/modules/http-lua/t/055-subreq-vars.t index eb5e24d..1369992 100644 --- a/debian/modules/http-lua/t/055-subreq-vars.t +++ b/debian/modules/http-lua/t/055-subreq-vars.t @@ -28,7 +28,7 @@ __DATA__ location /lua { content_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { vars = { dog = "hello", cat = 32 }}); ngx.print(res.body) @@ -82,7 +82,7 @@ qr/variable "(dog|cat)" cannot be assigned a value \(maybe you forgot to define location /lua { set $dog ''; content_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { vars = { dog = "hello", cat = 32 }}); ngx.print(res.body) @@ -110,7 +110,7 @@ variable "cat" cannot be assigned a value (maybe you forgot to define it first?) set $dog ''; set $cat ''; content_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { vars = { dog = "hello", cat = 32 }}); ngx.print(res.body) @@ -137,7 +137,7 @@ cat = 32 set $dog ''; set $cat ''; content_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { vars = "hello" }); ngx.print(res.body) @@ -165,7 +165,7 @@ Bad vars option value set $dog ''; set $cat ''; content_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { vars = { cat = true } }); ngx.print(res.body) @@ -188,7 +188,7 @@ attempt to use bad variable value type boolean location /lua { content_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { vars = { args = "a=hello&b=32" }}); ngx.print(res.body) @@ -234,7 +234,7 @@ variable "query_string" not changeable location /lua { set $dog 'hello'; content_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { copy_all_vars = true }); ngx.print(res.body) @@ -259,7 +259,7 @@ GET /lua location /lua { set $dog 'hello'; content_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { share_all_vars = true }); ngx.print(res.body) @@ -284,7 +284,7 @@ GET /lua location /lua { set $dog 'hello'; content_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { vars = { dog = "hiya" }, copy_all_vars = true }); ngx.print(res.body) diff --git a/debian/modules/http-lua/t/056-flush.t b/debian/modules/http-lua/t/056-flush.t index 6b697a4..bdd33d4 100644 --- a/debian/modules/http-lua/t/056-flush.t +++ b/debian/modules/http-lua/t/056-flush.t @@ -317,7 +317,7 @@ lua http 1.0 buffering makes ngx.flush() a no-op --- config location /test { content_by_lua ' - function f() + local function f() ngx.say("hello, world") ngx.flush(true) coroutine.yield() diff --git a/debian/modules/http-lua/t/057-flush-timeout.t b/debian/modules/http-lua/t/057-flush-timeout.t index a046539..1f8cfaa 100644 --- a/debian/modules/http-lua/t/057-flush-timeout.t +++ b/debian/modules/http-lua/t/057-flush-timeout.t @@ -127,7 +127,7 @@ del timer 1234 send_timeout 200ms; location /lua { content_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) diff --git a/debian/modules/http-lua/t/058-tcp-socket.t b/debian/modules/http-lua/t/058-tcp-socket.t index 354a876..837006c 100644 --- a/debian/modules/http-lua/t/058-tcp-socket.t +++ b/debian/modules/http-lua/t/058-tcp-socket.t @@ -4,7 +4,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * 199; +plan tests => repeat_each() * 219; our $HtmlDir = html_dir; @@ -245,11 +245,11 @@ attempt to send data on a closed socket: --- request GET /t ---- response_body +--- response_body_like connected: 1 request sent: 56 -first line received: HTTP/1.1 200 OK -second line received: Server: openresty +first line received: HTTP\/1\.1 200 OK +second line received: (?:Date|Server): .*? --- no_error_log [error] --- timeout: 10 @@ -298,7 +298,7 @@ qr/connect\(\) failed \(\d+: Connection refused\)/ location /test { content_by_lua ' local sock = ngx.socket.tcp() - local ok, err = sock:connect("agentzh.org", 12345) + local ok, err = sock:connect("127.0.0.2", 12345) ngx.say("connect: ", ok, " ", err) local bytes @@ -321,7 +321,7 @@ send: nil closed receive: nil closed close: nil closed --- error_log -lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 +lua tcp socket connect timed out, when connecting to 127.0.0.2:12345 --- timeout: 10 @@ -914,7 +914,7 @@ close: 1 nil end end - ok, err = sock:close() + local ok, err = sock:close() ngx.say("close: ", ok, " ", err) '; } @@ -961,7 +961,7 @@ close: 1 nil line, err = sock:receive() ngx.say("receive: ", line, " ", err) - ok, err = sock:close() + local ok, err = sock:close() ngx.say("close: ", ok, " ", err) '; } @@ -1057,7 +1057,7 @@ close: 1 nil === TEST 19: cannot survive across request boundary (send) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location /t { @@ -1116,7 +1116,7 @@ received: OK|failed to send request: closed)\$" === TEST 20: cannot survive across request boundary (receive) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location /t { @@ -1191,7 +1191,7 @@ received: OK|failed to receive a line: closed \[nil\])$/ === TEST 21: cannot survive across request boundary (close) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location /t { @@ -1260,7 +1260,7 @@ received: OK|failed to close: closed)$/ === TEST 22: cannot survive across request boundary (connect) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location /t { @@ -2611,7 +2611,7 @@ close: 1 nil local ready = false local fatal = false - function f() + local function f() local line, err, part = sock:receive() if not line then ngx.say("failed to receive the 1st line: ", err, " [", part, "]") @@ -2672,7 +2672,7 @@ lua clean up the timer for pending ngx.sleep === TEST 44: bad request tries to connect --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location = /main { @@ -2726,7 +2726,7 @@ qr/runtime error: content_by_lua\(nginx\.conf:\d+\):7: bad request/ === TEST 45: bad request tries to receive --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location = /main { @@ -2783,7 +2783,7 @@ qr/runtime error: content_by_lua\(nginx\.conf:\d+\):14: bad request/ === TEST 46: bad request tries to send --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location = /main { @@ -2840,7 +2840,7 @@ qr/runtime error: content_by_lua\(nginx\.conf:\d+\):14: bad request/ === TEST 47: bad request tries to close --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location = /main { @@ -2897,7 +2897,7 @@ qr/runtime error: content_by_lua\(nginx\.conf:\d+\):14: bad request/ === TEST 48: bad request tries to set keepalive --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location = /main { @@ -2954,7 +2954,7 @@ qr/runtime error: content_by_lua\(nginx\.conf:\d+\):14: bad request/ === TEST 49: bad request tries to receiveuntil --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location = /main { @@ -3315,7 +3315,7 @@ close: 1 nil local thr = ngx.thread.spawn(function () sock = ngx.socket.tcp() - local ok, err = sock:connect("agentzh.org", 12345) + local ok, err = sock:connect("127.0.0.2", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -3464,7 +3464,7 @@ lua http cleanup reuse ngx.say("failed to create timer: ", err) end - i = 1 + local i = 1 while not done do local time = 0.005 * i if time > 0.1 then @@ -3545,7 +3545,7 @@ lua http cleanup reuse ngx.say("failed to create timer: ", err) end - i = 1 + local i = 1 while not done do local time = 0.005 * i if time > 0.1 then @@ -3720,10 +3720,10 @@ sudo iptables -I OUTPUT 1 -p udp --dport 10086 -j REJECT } --- request GET /t ---- response_body -failed to connect: www.google.com could not be resolved -failed to connect: www.google.com could not be resolved -failed to connect: www.google.com could not be resolved +--- response_body_like +failed to connect: www.google.com could not be resolved(?: \(\d+: Operation timed out\))? +failed to connect: www.google.com could not be resolved(?: \(\d+: Operation timed out\))? +failed to connect: www.google.com could not be resolved(?: \(\d+: Operation timed out\))? hello! --- error_log eval qr{\[alert\] .*? send\(\) failed \(\d+: Operation not permitted\) while resolving} @@ -3808,3 +3808,315 @@ received: received: truefalsenil --- no_error_log [error] + + + +=== TEST 64: receiveany method in cosocket +--- config + server_tokens off; + location = /t { + set $port $TEST_NGINX_SERVER_PORT; + content_by_lua_block { + local sock = ngx.socket.tcp() + sock:settimeout(500) + assert(sock:connect("127.0.0.1", ngx.var.port)) + local req = { + 'GET /foo HTTP/1.0\r\n', + 'Host: localhost\r\n', + 'Connection: close\r\n\r\n', + } + local ok, err = sock:send(req) + if not ok then + ngx.say("send request failed: ", err) + return + end + + -- skip http header + while true do + local data, err, _ = sock:receive('*l') + if err then + ngx.say('unexpected error occurs when receiving http head: ', err) + return + end + + if #data == 0 then -- read last line of head + break + end + end + + -- receive http body + while true do + local data, err = sock:receiveany(1024) + if err then + if err ~= 'closed' then + ngx.say('unexpected err: ', err) + end + break + end + ngx.say(data) + end + + sock:close() + } + } + + location = /foo { + content_by_lua_block { + local resp = { + '1', + '22', + 'hello world', + } + + local length = 0 + for _, v in ipairs(resp) do + length = length + #v + end + + -- flush http header + ngx.header['Content-Length'] = length + ngx.flush(true) + ngx.sleep(0.01) + + -- send http body + for _, v in ipairs(resp) do + ngx.print(v) + ngx.flush(true) + ngx.sleep(0.01) + end + } + } + +--- request +GET /t +--- response_body +1 +22 +hello world +--- no_error_log +[error] +--- error_log +lua tcp socket read any + + + +=== TEST 65: receiveany send data after read side closed +--- config + server_tokens off; + location = /t { + content_by_lua_block { + local sock = ngx.socket.tcp() + sock:settimeout(500) + assert(sock:connect("127.0.0.1", 7658)) + + while true do + local data, err = sock:receiveany(1024) + if err then + if err ~= 'closed' then + ngx.say('unexpected err: ', err) + break + end + + local data = "send data after read side closed" + local bytes, err = sock:send(data) + if not bytes then + ngx.say(err) + end + + break + end + ngx.say(data) + end + + sock:close() + } + } + +--- request +GET /t +--- tcp_listen: 7658 +--- tcp_shutdown: 1 +--- tcp_query eval: "send data after read side closed" +--- tcp_query_len: 32 +--- response_body +--- no_error_log +[error] + + + +=== TEST 66: receiveany with limited, max <= 0 +--- config + location = /t { + set $port $TEST_NGINX_SERVER_PORT; + content_by_lua_block { + local sock = ngx.socket.tcp() + sock:settimeout(500) + assert(sock:connect("127.0.0.1", ngx.var.port)) + + local function receiveany_say_err(...) + local ok, err = pcall(sock.receiveany, sock, ...) + if not ok then + ngx.say(err) + end + end + + + receiveany_say_err(0) + receiveany_say_err(-1) + receiveany_say_err() + receiveany_say_err(nil) + } + } + +--- response_body +bad argument #2 to '?' (bad max argument) +bad argument #2 to '?' (bad max argument) +expecting 2 arguments (including the object), but got 1 +bad argument #2 to '?' (bad max argument) +--- request +GET /t +--- no_error_log +[error] + + + +=== TEST 67: receiveany with limited, max is larger than data +--- config + server_tokens off; + location = /t { + set $port $TEST_NGINX_SERVER_PORT; + content_by_lua_block { + local sock = ngx.socket.tcp() + sock:settimeout(500) + assert(sock:connect("127.0.0.1", ngx.var.port)) + local req = { + 'GET /foo HTTP/1.0\r\n', + 'Host: localhost\r\n', + 'Connection: close\r\n\r\n', + } + local ok, err = sock:send(req) + if not ok then + ngx.say("send request failed: ", err) + return + end + + while true do + local data, err, _ = sock:receive('*l') + if err then + ngx.say('unexpected error occurs when receiving http head: ', err) + return + end + + if #data == 0 then -- read last line of head + break + end + end + + local data, err = sock:receiveany(128) + if err then + if err ~= 'closed' then + ngx.say('unexpected err: ', err) + end + else + ngx.say(data) + end + + sock:close() + } + } + + location = /foo { + content_by_lua_block { + local resp = 'hello world' + local length = #resp + + ngx.header['Content-Length'] = length + ngx.flush(true) + ngx.sleep(0.01) + + ngx.print(resp) + } + } + +--- request +GET /t +--- response_body +hello world +--- no_error_log +[error] +--- error_log +lua tcp socket calling receiveany() method to read at most 128 bytes + + + +=== TEST 68: receiveany with limited, max is smaller than data +--- config + server_tokens off; + location = /t { + set $port $TEST_NGINX_SERVER_PORT; + content_by_lua_block { + local sock = ngx.socket.tcp() + sock:settimeout(500) + assert(sock:connect("127.0.0.1", ngx.var.port)) + local req = { + 'GET /foo HTTP/1.0\r\n', + 'Host: localhost\r\n', + 'Connection: close\r\n\r\n', + } + local ok, err = sock:send(req) + if not ok then + ngx.say("send request failed: ", err) + return + end + + while true do + local data, err, _ = sock:receive('*l') + if err then + ngx.say('unexpected error occurs when receiving http head: ', err) + return + end + + if #data == 0 then -- read last line of head + break + end + end + + while true do + local data, err = sock:receiveany(7) + if err then + if err ~= 'closed' then + ngx.say('unexpected err: ', err) + end + break + + else + ngx.say(data) + end + end + + sock:close() + } + } + + location = /foo { + content_by_lua_block { + local resp = 'hello world' + local length = #resp + + ngx.header['Content-Length'] = length + ngx.flush(true) + ngx.sleep(0.01) + + ngx.print(resp) + } + } + +--- request +GET /t +--- response_body +hello w +orld +--- no_error_log +[error] +--- error_log +lua tcp socket calling receiveany() method to read at most 7 bytes diff --git a/debian/modules/http-lua/t/062-count.t b/debian/modules/http-lua/t/062-count.t index 2ad2f9f..9b0afe8 100644 --- a/debian/modules/http-lua/t/062-count.t +++ b/debian/modules/http-lua/t/062-count.t @@ -283,7 +283,7 @@ n = 5 --- request GET /test --- response_body -n = 18 +n = 22 --- no_error_log [error] @@ -444,7 +444,28 @@ worker: 4 -=== TEST 20: entries under the metatable of udp sockets +=== TEST 20: entries under the metatable of tcp sockets +--- config + location = /test { + content_by_lua_block { + local n = 0 + local sock = ngx.socket.tcp() + for k, v in pairs(getmetatable(sock)) do + n = n + 1 + end + ngx.say("n = ", n) + } + } +--- request +GET /test +--- response_body +n = 13 +--- no_error_log +[error] + + + +=== TEST 21: entries under the metatable of udp sockets --- config location = /test { content_by_lua ' @@ -465,7 +486,7 @@ n = 6 -=== TEST 21: entries under the metatable of req raw sockets +=== TEST 22: entries under the metatable of req raw sockets --- config location = /test { content_by_lua ' @@ -497,7 +518,7 @@ n = 6 -=== TEST 22: entries under the req raw sockets +=== TEST 23: entries under the req raw sockets --- config location = /test { content_by_lua_block { @@ -536,7 +557,7 @@ nrec = 3 -=== TEST 23: entries under the req sockets +=== TEST 24: entries under the req sockets --- config location = /test { content_by_lua_block { diff --git a/debian/modules/http-lua/t/063-abort.t b/debian/modules/http-lua/t/063-abort.t index 411a07e..7c90eaa 100644 --- a/debian/modules/http-lua/t/063-abort.t +++ b/debian/modules/http-lua/t/063-abort.t @@ -22,7 +22,7 @@ __DATA__ === TEST 1: ngx.exit(400) should abort print --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /memc_query { internal; @@ -68,7 +68,7 @@ GET /test?a === TEST 2: ngx.exit(400) should abort ngx.log --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /memc_query { internal; @@ -116,7 +116,7 @@ GET /test?a === TEST 3: ngx.exit(400) should abort ngx.location.capture --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /memc_query { internal; @@ -161,7 +161,7 @@ the "$memc_key" variable is not set === TEST 4: ngx.exit(400) should abort ngx.location.capture_multi --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /memc_query { internal; @@ -206,7 +206,7 @@ the "$memc_key" variable is not set === TEST 5: ngx.exit(400) should abort ngx.redirect --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -233,7 +233,7 @@ lua redirect to "/blah" with code 302 === TEST 6: ngx.exit(400) should abort ngx.exit --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -260,7 +260,7 @@ lua exit with code 503 === TEST 7: ngx.exit(400) should abort ngx.exec --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -287,7 +287,7 @@ lua exec "/blah?" === TEST 8: ngx.exit(400) should abort ngx.send_headers --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -314,7 +314,7 @@ lua send headers === TEST 9: ngx.exit(400) should abort ngx.print --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -341,7 +341,7 @@ lua print response === TEST 10: ngx.exit(400) should abort ngx.say --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -368,7 +368,7 @@ lua say response === TEST 11: ngx.exit(400) should abort ngx.flush --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -395,7 +395,7 @@ lua flush asynchronously === TEST 12: ngx.exit(400) should abort ngx.eof --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -422,7 +422,7 @@ lua send eof === TEST 13: ngx.exit(400) should abort ngx.re.match --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -449,7 +449,7 @@ lua compiling match regex "a" with options "jo" === TEST 14: ngx.exit(400) should abort ngx.re.gmatch --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -476,7 +476,7 @@ lua compiling gmatch regex "a" with options "jo" === TEST 15: ngx.exit(400) should abort ngx.re.sub --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -503,7 +503,7 @@ lua compiling sub regex "a" with options "jo" === TEST 16: ngx.exit(400) should abort ngx.re.gsub --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -530,7 +530,7 @@ lua compiling gsub regex "a" with options "jo" === TEST 17: ngx.exit(400) should abort ngx.shared.DICT (set) --- http_config eval - "lua_shared_dict dogs 1m; lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_shared_dict dogs 1m; lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -560,7 +560,7 @@ foo = 56 === TEST 18: ngx.exit(400) should abort ngx.shared.DICT (replace) --- http_config eval - "lua_shared_dict dogs 1m; lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_shared_dict dogs 1m; lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -590,7 +590,7 @@ foo = 56 === TEST 19: ngx.exit(400) should abort ngx.shared.DICT (incr) --- http_config eval - "lua_shared_dict dogs 1m; lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_shared_dict dogs 1m; lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -620,7 +620,7 @@ foo = 88 === TEST 20: ngx.exit(400) should abort ngx.shared.DICT (get) --- http_config eval - "lua_shared_dict dogs 1m; lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_shared_dict dogs 1m; lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -649,7 +649,7 @@ fetching key "foo" in shared dict "dogs" === TEST 21: ngx.exit(400) should skip os.execute --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -679,7 +679,7 @@ GET /test === TEST 22: ngx.exit(400) should break pcall and skip os.execute --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -709,7 +709,7 @@ fetching key "foo" in shared dict "dogs" === TEST 23: ngx.exit(400) should break pcall and skip os.execute (all in user module) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -739,7 +739,7 @@ GET /test === TEST 24: ngx.redirect() should break pcall and skip os.execute (all in user module) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -769,7 +769,7 @@ GET /test === TEST 25: ngx.redirect() should skip os.execute (all in user module) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -799,7 +799,7 @@ GET /test === TEST 26: ngx.exec() should break pcall and skip os.execute (all in user module) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -832,7 +832,7 @@ foo === TEST 27: ngx.exec() should skip os.execute (all in user module) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -865,7 +865,7 @@ foo === TEST 28: ngx.set_uri(uri, true) should break pcall and skip os.execute (all in user module) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { rewrite_by_lua ' @@ -921,7 +921,7 @@ hello world === TEST 30: ngx.exit(400) should break xpcall and skip os.execute (all in user module) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -955,7 +955,7 @@ GET /test === TEST 31: ngx.exec() should skip os.execute (all in user module) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -988,7 +988,7 @@ foo === TEST 32: ngx.exec() should break pcall and skip os.execute (all in user module) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' diff --git a/debian/modules/http-lua/t/064-pcall.t b/debian/modules/http-lua/t/064-pcall.t index 3011f3e..9af2de7 100644 --- a/debian/modules/http-lua/t/064-pcall.t +++ b/debian/modules/http-lua/t/064-pcall.t @@ -22,11 +22,11 @@ __DATA__ === TEST 1: pcall works --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' - function f(a, b) + local function f(a, b) if a == 0 and b == 0 then error("zero error") end @@ -58,11 +58,11 @@ $/s === TEST 2: xpcall works --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' - function f(a, b) + local function f(a, b) if a == 0 and b == 0 then error("zero error") end @@ -70,15 +70,15 @@ $/s return 23, "hello", true end - function g() + local function g() return f(0, 0) end - function h() + local function h() return f(0) end - function err(...) + local function err(...) ngx.say("error handler called: ", ...) return "this is the new err" end diff --git a/debian/modules/http-lua/t/065-tcp-socket-timeout.t b/debian/modules/http-lua/t/065-tcp-socket-timeout.t index 78b8cff..092094a 100644 --- a/debian/modules/http-lua/t/065-tcp-socket-timeout.t +++ b/debian/modules/http-lua/t/065-tcp-socket-timeout.t @@ -51,7 +51,7 @@ __DATA__ location /t { content_by_lua ' local sock = ngx.socket.tcp() - local ok, err = sock:connect("agentzh.org", 12345) + local ok, err = sock:connect("127.0.0.2", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -66,7 +66,7 @@ GET /t failed to connect: timeout --- error_log lua tcp socket connect timeout: 100 -lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 +lua tcp socket connect timed out, when connecting to 127.0.0.2:12345 --- timeout: 10 @@ -81,7 +81,7 @@ lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 content_by_lua ' local sock = ngx.socket.tcp() sock:settimeout(150) - local ok, err = sock:connect("agentzh.org", 12345) + local ok, err = sock:connect("127.0.0.2", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -96,7 +96,7 @@ GET /t failed to connect: timeout --- error_log lua tcp socket connect timeout: 150 -lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 +lua tcp socket connect timed out, when connecting to 127.0.0.2:12345 --- timeout: 10 @@ -110,7 +110,7 @@ lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 content_by_lua ' local sock = ngx.socket.tcp() sock:settimeout(nil) - local ok, err = sock:connect("agentzh.org", 12345) + local ok, err = sock:connect("127.0.0.2", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -125,7 +125,7 @@ GET /t failed to connect: timeout --- error_log lua tcp socket connect timeout: 102 -lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 +lua tcp socket connect timed out, when connecting to 127.0.0.2:12345 @@ -139,7 +139,7 @@ lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 content_by_lua ' local sock = ngx.socket.tcp() sock:settimeout(0) - local ok, err = sock:connect("agentzh.org", 12345) + local ok, err = sock:connect("127.0.0.2", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -154,7 +154,7 @@ GET /t failed to connect: timeout --- error_log lua tcp socket connect timeout: 102 -lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 +lua tcp socket connect timed out, when connecting to 127.0.0.2:12345 --- timeout: 10 @@ -168,7 +168,7 @@ lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 content_by_lua ' local sock = ngx.socket.tcp() sock:settimeout(-1) - local ok, err = sock:connect("agentzh.org", 12345) + local ok, err = sock:connect("127.0.0.2", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -584,7 +584,7 @@ bad timeout value --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -683,7 +683,7 @@ after location /t { content_by_lua ' local sock = ngx.socket.tcp() - local ok, err = sock:connect("agentzh.org", 12345) + local ok, err = sock:connect("127.0.0.2", 12345) if not ok then ngx.say("1: failed to connect: ", err) @@ -707,7 +707,7 @@ GET /t 2: connected: 1 --- error_log lua tcp socket connect timeout: 100 -lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 +lua tcp socket connect timed out, when connecting to 127.0.0.2:12345 --- timeout: 10 diff --git a/debian/modules/http-lua/t/066-socket-receiveuntil.t b/debian/modules/http-lua/t/066-socket-receiveuntil.t index ffe74aa..89d2abf 100644 --- a/debian/modules/http-lua/t/066-socket-receiveuntil.t +++ b/debian/modules/http-lua/t/066-socket-receiveuntil.t @@ -245,7 +245,7 @@ close: 1 nil local reader = sock:receiveuntil("abcabd") for i = 1, 2 do - line, err, part = reader() + local line, err, part = reader() if line then ngx.say("read: ", line) @@ -316,7 +316,7 @@ close: 1 nil local reader = sock:receiveuntil("aa") for i = 1, 2 do - line, err, part = reader() + local line, err, part = reader() if line then ngx.say("read: ", line) @@ -387,7 +387,7 @@ close: 1 nil local reader = sock:receiveuntil("aaa") for i = 1, 2 do - line, err, part = reader() + local line, err, part = reader() if line then ngx.say("read: ", line) @@ -458,7 +458,7 @@ close: 1 nil local reader = sock:receiveuntil("aaaaad") for i = 1, 2 do - line, err, part = reader() + local line, err, part = reader() if line then ngx.say("read: ", line) @@ -530,7 +530,7 @@ close: 1 nil local reader = sock:receiveuntil("aaaaad") for i = 1, 2 do - line, err, part = reader() + local line, err, part = reader() if line then ngx.say("read: ", line) @@ -602,7 +602,7 @@ close: 1 nil local reader = sock:receiveuntil("aaaaad") for i = 1, 2 do - line, err, part = reader() + local line, err, part = reader() if line then ngx.say("read: ", line) @@ -673,7 +673,7 @@ close: 1 nil local reader = sock:receiveuntil("abcabdabcabe") for i = 1, 2 do - line, err, part = reader() + local line, err, part = reader() if line then ngx.say("read: ", line) @@ -744,7 +744,7 @@ close: 1 nil local reader = sock:receiveuntil("abcabdabcabe") for i = 1, 2 do - line, err, part = reader() + local line, err, part = reader() if line then ngx.say("read: ", line) @@ -815,7 +815,7 @@ close: 1 nil local reader = sock:receiveuntil("abcabdabcabe") for i = 1, 2 do - line, err, part = reader() + local line, err, part = reader() if line then ngx.say("read: ", line) @@ -886,7 +886,7 @@ close: 1 nil local reader = sock:receiveuntil("abcabdabcabe") for i = 1, 2 do - line, err, part = reader() + local line, err, part = reader() if line then ngx.say("read: ", line) @@ -957,7 +957,7 @@ close: 1 nil local reader = sock:receiveuntil("--abc") for i = 1, 2 do - line, err, part = reader() + local line, err, part = reader() if line then ngx.say("read: ", line) @@ -1028,7 +1028,7 @@ close: 1 nil local reader = sock:receiveuntil("--abc") for i = 1, 7 do - line, err, part = reader(4) + local line, err, part = reader(4) if line then ngx.say("read: ", line) @@ -1105,7 +1105,7 @@ close: 1 nil local reader = sock:receiveuntil("--abc") for i = 1, 7 do - line, err, part = reader(4) + local line, err, part = reader(4) if line then ngx.say("read: ", line) @@ -1182,7 +1182,7 @@ close: 1 nil local reader = sock:receiveuntil("--abc") for i = 1, 7 do - line, err, part = reader(4) + local line, err, part = reader(4) if line then ngx.say("read: ", line) @@ -1270,7 +1270,7 @@ close: 1 nil local reader = sock:receiveuntil("abcabd") for i = 1, 2 do - line, err, part = reader() + local line, err, part = reader() if line then ngx.say("read: ", line) diff --git a/debian/modules/http-lua/t/067-req-socket.t b/debian/modules/http-lua/t/067-req-socket.t index 229d5cc..6593360 100644 --- a/debian/modules/http-lua/t/067-req-socket.t +++ b/debian/modules/http-lua/t/067-req-socket.t @@ -320,7 +320,7 @@ found the end of the stream === TEST 4: attempt to use the req socket across request boundary --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /t { content_by_lua ' @@ -369,7 +369,7 @@ hello world === TEST 5: receive until on request_body - receiveuntil(1) on the last byte of the body See https://groups.google.com/group/openresty/browse_thread/thread/43cf01da3c681aba for details --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /t { content_by_lua ' @@ -431,7 +431,7 @@ done === TEST 6: pipelined POST requests --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /t { content_by_lua ' diff --git a/debian/modules/http-lua/t/068-socket-keepalive.t b/debian/modules/http-lua/t/068-socket-keepalive.t index f052e9a..e4c6988 100644 --- a/debian/modules/http-lua/t/068-socket-keepalive.t +++ b/debian/modules/http-lua/t/068-socket-keepalive.t @@ -4,13 +4,14 @@ use Test::Nginx::Socket::Lua; #repeat_each(2); -plan tests => repeat_each() * (blocks() * 5 + 9); +plan tests => repeat_each() * (blocks() * 4 + 31); our $HtmlDir = html_dir; $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; $ENV{TEST_NGINX_HTML_DIR} = $HtmlDir; $ENV{TEST_NGINX_REDIS_PORT} ||= 6379; +$ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; $ENV{LUA_PATH} ||= '/usr/local/openresty-debug/lualib/?.lua;/usr/local/openresty/lualib/?.lua;;'; @@ -29,7 +30,7 @@ __DATA__ === TEST 1: sanity --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -97,7 +98,7 @@ lua tcp socket keepalive create connection pool for key "127.0.0.1:$ENV{TEST_NGI === TEST 2: free up the whole connection pool if no active connections --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -168,7 +169,7 @@ received: OK === TEST 3: upstream sockets close prematurely --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; keepalive_timeout 100ms; @@ -243,7 +244,7 @@ done === TEST 4: http keepalive --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location /t { @@ -701,7 +702,35 @@ qr/lua tcp socket connection pool size: 25\b/] -=== TEST 10: sock:keepalive_timeout(0) means unlimited +=== TEST 10: setkeepalive() 'pool_size' should be greater than zero +--- config + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + content_by_lua_block { + local sock, err = ngx.socket.connect("127.0.0.1", ngx.var.port) + if not sock then + ngx.say(err) + return + end + + local ok, err = pcall(sock.setkeepalive, sock, 0, 0) + if not ok then + ngx.say(err) + return + end + ngx.say(ok) + } + } +--- request +GET /t +--- response_body +bad argument #3 to '?' (bad "pool_size" option value: 0) +--- no_error_log +[error] + + + +=== TEST 11: sock:keepalive_timeout(0) means unlimited --- config server_tokens off; location /t { @@ -776,10 +805,10 @@ qr/lua tcp socket connection pool size: 30\b/] -=== TEST 11: sanity (uds) +=== TEST 12: sanity (uds) --- http_config eval " - lua_package_path '$::HtmlDir/?.lua;./?.lua'; + lua_package_path '$::HtmlDir/?.lua;./?.lua;;'; server { listen unix:$::HtmlDir/nginx.sock; default_type 'text/plain'; @@ -858,7 +887,7 @@ received response of 119 bytes -=== TEST 12: github issue #108: ngx.locaiton.capture + redis.set_keepalive +=== TEST 13: github issue #108: ngx.locaiton.capture + redis.set_keepalive --- http_config eval qq{ lua_package_path "$::HtmlDir/?.lua;;"; @@ -905,9 +934,9 @@ lua tcp socket get keepalive peer: using connection -=== TEST 13: github issue #110: ngx.exit with HTTP_NOT_FOUND causes worker process to exit +=== TEST 14: github issue #110: ngx.exit with HTTP_NOT_FOUND causes worker process to exit --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config error_page 404 /404.html; location /t { @@ -964,9 +993,9 @@ Not found, dear... -=== TEST 14: custom pools (different pool for the same host:port) - tcp +=== TEST 15: custom pools (different pool for the same host:port) - tcp --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -1012,9 +1041,9 @@ lua tcp socket keepalive create connection pool for key "B" -=== TEST 15: custom pools (same pool for different host:port) - tcp +=== TEST 16: custom pools (same pool for different host:port) - tcp --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -1059,10 +1088,10 @@ lua tcp socket get keepalive peer: using connection -=== TEST 16: custom pools (different pool for the same host:port) - unix +=== TEST 17: custom pools (different pool for the same host:port) - unix --- http_config eval " - lua_package_path '$::HtmlDir/?.lua;./?.lua'; + lua_package_path '$::HtmlDir/?.lua;./?.lua;;'; server { listen unix:$::HtmlDir/nginx.sock; default_type 'text/plain'; @@ -1119,10 +1148,10 @@ lua tcp socket keepalive create connection pool for key "B" -=== TEST 17: custom pools (same pool for the same path) - unix +=== TEST 18: custom pools (same pool for the same path) - unix --- http_config eval " - lua_package_path '$::HtmlDir/?.lua;./?.lua'; + lua_package_path '$::HtmlDir/?.lua;./?.lua;;'; server { listen unix:$::HtmlDir/nginx.sock; default_type 'text/plain'; @@ -1174,9 +1203,9 @@ lua tcp socket get keepalive peer: using connection -=== TEST 18: numeric pool option value +=== TEST 19: numeric pool option value --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -1221,9 +1250,9 @@ lua tcp socket get keepalive peer: using connection -=== TEST 19: nil pool option value +=== TEST 20: nil pool option value --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -1264,9 +1293,9 @@ connected: 1, reused: 0 -=== TEST 20: (bad) table pool option value +=== TEST 21: (bad) table pool option value --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -1305,9 +1334,9 @@ bad argument #3 to 'connect' (bad "pool" option type: table) -=== TEST 21: (bad) boolean pool option value +=== TEST 22: (bad) boolean pool option value --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -1346,7 +1375,7 @@ bad argument #3 to 'connect' (bad "pool" option type: boolean) -=== TEST 22: clear the redis store +=== TEST 23: clear the redis store --- config location /t { redis2_query flushall; @@ -1363,9 +1392,9 @@ bad argument #3 to 'connect' (bad "pool" option type: boolean) -=== TEST 23: bug in send(): clear the chain writer ctx +=== TEST 24: bug in send(): clear the chain writer ctx --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /t { set $port $TEST_NGINX_REDIS_PORT; @@ -1478,7 +1507,7 @@ done -=== TEST 24: setkeepalive() with explicit nil args +=== TEST 25: setkeepalive() with explicit nil args --- config server_tokens off; location /t { @@ -1551,3 +1580,1379 @@ done "lua tcp socket keepalive timeout: 100 ms", qr/lua tcp socket connection pool size: 30\b/] --- timeout: 4 + + + +=== TEST 26: conn queuing: connect() verifies the options for connection pool +--- config + location /t { + set $port $TEST_NGINX_SERVER_PORT; + + content_by_lua_block { + local sock = ngx.socket.tcp() + local function check_opts_for_connect(opts) + local ok, err = pcall(function() + sock:connect("127.0.0.1", ngx.var.port, opts) + end) + if not ok then + ngx.say(err) + else + ngx.say("ok") + end + end + + check_opts_for_connect({pool_size = 'a'}) + check_opts_for_connect({pool_size = 0}) + check_opts_for_connect({backlog = -1}) + check_opts_for_connect({backlog = 0}) + } + } +--- request +GET /t +--- response_body_like +.+ 'connect' \(bad "pool_size" option type: string\) +.+ 'connect' \(bad "pool_size" option value: 0\) +.+ 'connect' \(bad "backlog" option value: -1\) +ok +--- no_error_log +[error] + + + +=== TEST 27: conn queuing: connect() can specify 'pool_size' which overrides setkeepalive() +--- config + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + local port = ngx.var.port + local function go() + local sock = ngx.socket.tcp() + local ok, err = sock:connect("127.0.0.1", port, {pool_size = 1}) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok, ", reused: ", sock:getreusedtimes()) + + local req = "flush_all\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 line, err, part = sock:receive() + if line then + ngx.say("received: ", line) + else + ngx.say("failed to receive a line: ", err, " [", part, "]") + end + + local ok, err = sock:setkeepalive(0, 20) + if not ok then + ngx.say("failed to set reusable: ", err) + end + end + + -- reuse ok + go() + go() + + local sock1 = ngx.socket.connect("127.0.0.1", port) + local sock2 = ngx.socket.connect("127.0.0.1", port) + local ok, err = sock1:setkeepalive(0, 20) + if not ok then + ngx.say(err) + end + local ok, err = sock2:setkeepalive(0, 20) + if not ok then + ngx.say(err) + end + + -- the pool_size is 1 instead of 20 + sock1 = ngx.socket.connect("127.0.0.1", port) + sock2 = ngx.socket.connect("127.0.0.1", port) + ngx.say("reused: ", sock1:getreusedtimes()) + ngx.say("reused: ", sock2:getreusedtimes()) + sock1:setkeepalive(0, 20) + sock2:setkeepalive(0, 20) + } + } +--- request +GET /t +--- response_body +connected: 1, reused: 0 +request sent: 11 +received: OK +connected: 1, reused: 1 +request sent: 11 +received: OK +reused: 1 +reused: 0 +--- no_error_log eval +["[error]", +"lua tcp socket keepalive: free connection pool for ", +"lua tcp socket connection pool size: 20"] +--- error_log eval +[qq{lua tcp socket keepalive create connection pool for key "127.0.0.1:$ENV{TEST_NGINX_MEMCACHED_PORT}"}, +"lua tcp socket connection pool size: 1", +] + + + +=== TEST 28: conn queuing: connect() can specify 'pool_size' for unix domain socket +--- http_config eval +" + server { + listen unix:$::HtmlDir/nginx.sock; + } +" +--- config + location /t { + content_by_lua_block { + local path = "unix:" .. "$TEST_NGINX_HTML_DIR/nginx.sock"; + local function go() + local sock = ngx.socket.tcp() + local ok, err = sock:connect(path, {pool_size = 1}) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok, ", reused: ", sock:getreusedtimes()) + + local ok, err = sock:setkeepalive(0, 20) + if not ok then + ngx.say("failed to set reusable: ", err) + end + end + + go() + go() + + local sock1 = ngx.socket.connect(path) + local sock2 = ngx.socket.connect(path) + local ok, err = sock1:setkeepalive(0, 20) + if not ok then + ngx.say(err) + end + local ok, err = sock2:setkeepalive(0, 20) + if not ok then + ngx.say(err) + end + + -- the pool_size is 1 instead of 20 + sock1 = ngx.socket.connect(path) + sock2 = ngx.socket.connect(path) + ngx.say("reused: ", sock1:getreusedtimes()) + ngx.say("reused: ", sock2:getreusedtimes()) + sock1:setkeepalive(0, 20) + sock2:setkeepalive(0, 20) + } + } +--- request +GET /t +--- response_body +connected: 1, reused: 0 +connected: 1, reused: 1 +reused: 1 +reused: 0 +--- no_error_log eval +["[error]", +"lua tcp socket keepalive: free connection pool for ", +"lua tcp socket connection pool size: 20"] +--- error_log eval +["lua tcp socket get keepalive peer: using connection", +'lua tcp socket keepalive create connection pool for key "unix:', +"lua tcp socket connection pool size: 1", +] + + + +=== TEST 29: conn queuing: connect() can specify 'pool_size' for custom pool +--- config + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + local port = ngx.var.port + local function go(pool) + local sock = ngx.socket.tcp() + local ok, err = sock:connect("127.0.0.1", port, {pool = pool, pool_size = 1}) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", pool, ", reused: ", sock:getreusedtimes()) + + local ok, err = sock:setkeepalive(0, 20) + if not ok then + ngx.say("failed to set reusable: ", err) + end + end + + go('A') + go('B') + go('A') + go('B') + + local sock1 = ngx.socket.connect("127.0.0.1", port, {pool = 'A'}) + local sock2 = ngx.socket.connect("127.0.0.1", port, {pool = 'A'}) + local ok, err = sock1:setkeepalive(0, 20) + if not ok then + ngx.say(err) + end + local ok, err = sock2:setkeepalive(0, 20) + if not ok then + ngx.say(err) + end + + -- the pool_size is 1 instead of 20 + sock1 = ngx.socket.connect("127.0.0.1", port, {pool = 'A'}) + sock2 = ngx.socket.connect("127.0.0.1", port, {pool = 'A'}) + ngx.say("reused: ", sock1:getreusedtimes()) + ngx.say("reused: ", sock2:getreusedtimes()) + sock1:setkeepalive(0, 20) + sock2:setkeepalive(0, 20) + } + } +--- request +GET /t +--- response_body +connected: A, reused: 0 +connected: B, reused: 0 +connected: A, reused: 1 +connected: B, reused: 1 +reused: 1 +reused: 0 +--- no_error_log eval +["[error]", +"lua tcp socket keepalive: free connection pool for ", +"lua tcp socket connection pool size: 20"] +--- error_log eval +[qq{lua tcp socket keepalive create connection pool for key "A"}, +qq{lua tcp socket keepalive create connection pool for key "B"}, +"lua tcp socket connection pool size: 1", +] + + + +=== TEST 30: conn queuing: connect() uses lua_socket_pool_size as default if 'backlog' is given +--- config + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + lua_socket_pool_size 1234; + + content_by_lua_block { + local port = ngx.var.port + local opts = {backlog = 0} + local sock, err = ngx.socket.connect("127.0.0.1", port, opts) + if not sock then + ngx.say(err) + else + ngx.say("ok") + end + } + } +--- request +GET /t +--- response_body +ok +--- error_log +lua tcp socket connection pool size: 1234 +--- no_error_log +[error] + + + +=== TEST 31: conn queuing: more connect operations than 'backlog' size +--- config + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + local port = ngx.var.port + local opts = {pool_size = 2, backlog = 0} + local sock = ngx.socket.connect("127.0.0.1", port, opts) + local not_reused_socket, err = ngx.socket.connect("127.0.0.1", port, opts) + if not not_reused_socket then + ngx.say(err) + return + end + -- burst + local ok, err = ngx.socket.connect("127.0.0.1", port, opts) + if not ok then + ngx.say(err) + end + + local ok, err = sock:setkeepalive() + if not ok then + ngx.say(err) + return + end + + ok, err = sock:connect("127.0.0.1", port, opts) + if not ok then + ngx.say(err) + end + ngx.say("reused: ", sock:getreusedtimes()) + -- both queue and pool is full + ok, err = ngx.socket.connect("127.0.0.1", port, opts) + if not ok then + ngx.say(err) + end + } + } +--- request +GET /t +--- response_body +too many waiting connect operations +reused: 1 +too many waiting connect operations +--- no_error_log +[error] + + + +=== TEST 32: conn queuing: once 'pool_size' is reached and pool has 'backlog' +--- config + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + local port = ngx.var.port + local opts = {pool_size = 2, backlog = 2} + local sock1 = ngx.socket.connect("127.0.0.1", port, opts) + + ngx.timer.at(0, function(premature) + local sock2, err = ngx.socket.connect("127.0.0.1", port, opts) + if not sock2 then + ngx.log(ngx.ERR, err) + return + end + + ngx.log(ngx.WARN, "start to handle timer") + ngx.sleep(0.1) + sock2:close() + -- resume connect operation + ngx.log(ngx.WARN, "continue to handle timer") + end) + + ngx.sleep(0.05) + ngx.log(ngx.WARN, "start to handle cosocket") + local sock3, err = ngx.socket.connect("127.0.0.1", port, opts) + if not sock3 then + ngx.say(err) + return + end + ngx.log(ngx.WARN, "continue to handle cosocket") + + local req = "flush_all\r\n" + local bytes, err = sock3:send(req) + if not bytes then + ngx.say("failed to send request: ", err) + return + end + ngx.say("request sent: ", bytes) + + local line, err, part = sock3:receive() + if line then + ngx.say("received: ", line) + else + ngx.say("failed to receive a line: ", err, " [", part, "]") + end + + local ok, err = sock3:setkeepalive() + if not ok then + ngx.say("failed to set reusable: ", err) + end + ngx.say("setkeepalive: OK") + } + } +--- request +GET /t +--- response_body +request sent: 11 +received: OK +setkeepalive: OK +--- no_error_log +[error] +--- error_log +lua tcp socket queue connect operation for connection pool "127.0.0.1 +--- grep_error_log eval: qr/(start|continue) to handle \w+/ +--- grep_error_log_out +start to handle timer +start to handle cosocket +continue to handle timer +continue to handle cosocket + + + +=== TEST 33: conn queuing: do not count failed connect operations +--- config + resolver $TEST_NGINX_RESOLVER ipv6=off; + resolver_timeout 3s; + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + local port = ngx.var.port + local opts = {pool = "test", pool_size = 1, backlog = 0} + + local sock = ngx.socket.tcp() + sock:settimeouts(100, 3000, 3000) + local ok, err = sock:connect("127.0.0.2", 12345, opts) + if not ok then + ngx.say(err) + end + + local sock, err = ngx.socket.connect("127.0.0.1", port, opts) + if not sock then + ngx.say(err) + end + ngx.say("ok") + } + } +--- request +GET /t +--- error_log +lua tcp socket connect timed out, when connecting to +--- response_body +timeout +ok + + + +=== TEST 34: conn queuing: connect until backlog is reached +--- config + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + local port = ngx.var.port + local opts = {pool_size = 1, backlog = 1} + local sock1 = ngx.socket.connect("127.0.0.1", port, opts) + + ngx.timer.at(0.01, function(premature) + ngx.log(ngx.WARN, "start to handle timer") + local sock2, err = ngx.socket.connect("127.0.0.1", port, opts) + if not sock2 then + ngx.log(ngx.ERR, err) + return + end + + ngx.sleep(0.02) + local ok, err = sock2:close() + if not ok then + ngx.log(ngx.ERR, err) + end + ngx.log(ngx.WARN, "continue to handle timer") + end) + + ngx.sleep(0.02) + local sock3, err = ngx.socket.connect("127.0.0.1", port, opts) + if not sock3 then + ngx.say(err) + end + local ok, err = sock1:setkeepalive() + if not ok then + ngx.say(err) + return + end + ngx.sleep(0.01) -- run sock2 + + ngx.log(ngx.WARN, "start to handle cosocket") + local sock3, err = ngx.socket.connect("127.0.0.1", port, opts) + if not sock3 then + ngx.say(err) + return + end + ngx.log(ngx.WARN, "continue to handle cosocket") + + local ok, err = sock3:setkeepalive() + if not ok then + ngx.say(err) + end + } + } +--- request +GET /t +--- response_body +too many waiting connect operations +--- no_error_log +[error] +--- error_log +lua tcp socket queue connect operation for connection pool "127.0.0.1 +--- grep_error_log eval: qr/queue connect operation for connection pool|(start|continue) to handle \w+/ +--- grep_error_log_out +start to handle timer +queue connect operation for connection pool +start to handle cosocket +queue connect operation for connection pool +continue to handle timer +continue to handle cosocket + + + +=== TEST 35: conn queuing: memory reuse for host in queueing connect operation ctx +--- config + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + local port = ngx.var.port + local opts = {pool = "test", pool_size = 1, backlog = 3} + local sock = ngx.socket.connect("127.0.0.1", port, opts) + + ngx.timer.at(0.01, function(premature) + local sock, err = ngx.socket.connect("0.0.0.0", port, opts) + if not sock then + ngx.log(ngx.ERR, err) + return + end + + local ok, err = sock:close() + if not ok then + ngx.log(ngx.ERR, err) + end + end) + + ngx.timer.at(0.015, function(premature) + local sock, err = ngx.socket.connect("127.0.0.1", port, opts) + if not sock then + ngx.log(ngx.ERR, err) + return + end + + local ok, err = sock:close() + if not ok then + ngx.log(ngx.ERR, err) + end + end) + + ngx.timer.at(0.02, function(premature) + local sock, err = ngx.socket.connect("0.0.0.0", port, opts) + if not sock then + ngx.log(ngx.ERR, err) + return + end + + local ok, err = sock:close() + if not ok then + ngx.log(ngx.ERR, err) + end + end) + + ngx.sleep(0.03) + local ok, err = sock:setkeepalive() + if not ok then + ngx.say(err) + return + end + ngx.say("ok") + } + } +--- request +GET /t +--- response_body +ok +--- no_error_log +[error] +--- grep_error_log eval: qr/queue connect operation for connection pool/ +--- grep_error_log_out +queue connect operation for connection pool +queue connect operation for connection pool +queue connect operation for connection pool + + + +=== TEST 36: conn queuing: connect() returns error after connect operation resumed +--- config + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + local port = ngx.var.port + local opts = {pool = "test", pool_size = 1, backlog = 1} + local sock = ngx.socket.connect("127.0.0.1", port, opts) + + ngx.timer.at(0, function(premature) + local sock, err = ngx.socket.connect("", port, opts) + if not sock then + ngx.log(ngx.WARN, err) + end + end) + + ngx.sleep(0.01) + -- use 'close' to force parsing host instead of reusing conn + local ok, err = sock:close() + if not ok then + ngx.say(err) + return + end + ngx.say("ok") + } + } +--- request +GET /t +--- response_body +ok +--- no_error_log +[error] +--- error_log +failed to parse host name +--- grep_error_log eval: qr/queue connect operation for connection pool/ +--- grep_error_log_out +queue connect operation for connection pool + + + +=== TEST 37: conn queuing: in uthread +--- config + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + local port = ngx.var.port + local opts = {pool_size = 1, backlog = 2} + + local conn_sock = function() + local sock, err = ngx.socket.connect("127.0.0.1", port, opts) + if not sock then + ngx.say(err) + return + end + ngx.say("start to handle uthread") + + ngx.sleep(0.01) + sock:close() + ngx.say("continue to handle other uthread") + end + + local sock, err = ngx.socket.connect("127.0.0.1", port, opts) + if not sock then + ngx.log(ngx.ERR, err) + return + end + + local co1 = ngx.thread.spawn(conn_sock) + local co2 = ngx.thread.spawn(conn_sock) + local co3 = ngx.thread.spawn(conn_sock) + + local ok, err = sock:setkeepalive() + if not ok then + ngx.log(ngx.ERR, err) + end + + ngx.thread.wait(co1) + ngx.thread.wait(co2) + ngx.thread.wait(co3) + ngx.say("all uthreads ok") + } + } +--- request +GET /t +--- response_body +too many waiting connect operations +start to handle uthread +continue to handle other uthread +start to handle uthread +continue to handle other uthread +all uthreads ok +--- no_error_log +[error] +--- grep_error_log eval: qr/queue connect operation for connection pool/ +--- grep_error_log_out +queue connect operation for connection pool +queue connect operation for connection pool + + + +=== TEST 38: conn queuing: in access_by_lua +--- config + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + access_by_lua_block { + local port = ngx.var.port + local opts = {pool_size = 1, backlog = 2} + + local conn_sock = function() + local sock, err = ngx.socket.connect("127.0.0.1", port, opts) + if not sock then + ngx.say(err) + return + end + ngx.say("start to handle uthread") + + ngx.sleep(0.01) + sock:close() + ngx.say("continue to handle other uthread") + end + + local sock, err = ngx.socket.connect("127.0.0.1", port, opts) + if not sock then + ngx.log(ngx.ERR, err) + return + end + + local co1 = ngx.thread.spawn(conn_sock) + local co2 = ngx.thread.spawn(conn_sock) + local co3 = ngx.thread.spawn(conn_sock) + + local ok, err = sock:setkeepalive() + if not ok then + ngx.log(ngx.ERR, err) + end + + ngx.thread.wait(co1) + ngx.thread.wait(co2) + ngx.thread.wait(co3) + ngx.say("all uthreads ok") + } + } +--- request +GET /t +--- response_body +too many waiting connect operations +start to handle uthread +continue to handle other uthread +start to handle uthread +continue to handle other uthread +all uthreads ok +--- no_error_log +[error] +--- grep_error_log eval: qr/queue connect operation for connection pool/ +--- grep_error_log_out +queue connect operation for connection pool +queue connect operation for connection pool + + + +=== TEST 39: conn queuing: in rewrite_by_lua +--- config + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + rewrite_by_lua_block { + local port = ngx.var.port + local opts = {pool_size = 1, backlog = 2} + + local conn_sock = function() + local sock, err = ngx.socket.connect("127.0.0.1", port, opts) + if not sock then + ngx.say(err) + return + end + ngx.say("start to handle uthread") + + ngx.sleep(0.01) + sock:close() + ngx.say("continue to handle other uthread") + end + + local sock, err = ngx.socket.connect("127.0.0.1", port, opts) + if not sock then + ngx.log(ngx.ERR, err) + return + end + + local co1 = ngx.thread.spawn(conn_sock) + local co2 = ngx.thread.spawn(conn_sock) + local co3 = ngx.thread.spawn(conn_sock) + + local ok, err = sock:setkeepalive() + if not ok then + ngx.log(ngx.ERR, err) + end + + ngx.thread.wait(co1) + ngx.thread.wait(co2) + ngx.thread.wait(co3) + ngx.say("all uthreads ok") + } + } +--- request +GET /t +--- response_body +too many waiting connect operations +start to handle uthread +continue to handle other uthread +start to handle uthread +continue to handle other uthread +all uthreads ok +--- no_error_log +[error] +--- grep_error_log eval: qr/queue connect operation for connection pool/ +--- grep_error_log_out +queue connect operation for connection pool +queue connect operation for connection pool + + + +=== TEST 40: conn queuing: in subrequest +--- config + set $port $TEST_NGINX_MEMCACHED_PORT; + + location /t { + content_by_lua_block { + local port = ngx.var.port + ngx.timer.at(0, function() + local opts = {pool_size = 1, backlog = 2} + local sock, err = ngx.socket.connect("127.0.0.1", port, opts) + if not sock then + ngx.log(ngx.ERR, err) + return + end + + ngx.sleep(0.1) + local ok, err = sock:setkeepalive() + if not ok then + ngx.log(ngx.ERR, err) + end + end) + + ngx.sleep(0.01) + local res1, res2, res3 = ngx.location.capture_multi{ + {"/conn"}, {"/conn"}, {"/conn"} + } + ngx.say(res1.body) + ngx.say(res2.body) + ngx.say(res3.body) + } + } + + location /conn { + content_by_lua_block { + local port = ngx.var.port + local sock, err = ngx.socket.connect("127.0.0.1", port) + if not sock then + ngx.print(err) + return + end + local ok, err = sock:setkeepalive() + if not ok then + ngx.print(err) + else + ngx.print("ok") + end + } + } +--- request +GET /t +--- response_body +ok +ok +too many waiting connect operations +--- no_error_log +[error] +--- grep_error_log eval: qr/queue connect operation for connection pool/ +--- grep_error_log_out +queue connect operation for connection pool +queue connect operation for connection pool + + + +=== TEST 41: conn queuing: timeouts when 'connect_timeout' is reached +--- config + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + local port = ngx.var.port + local opts = {pool_size = 1, backlog = 1} + local sock1 = ngx.socket.connect("127.0.0.1", port, opts) + + local sock2 = ngx.socket.tcp() + sock2:settimeouts(10, 3000, 3000) + local ok, err = sock2:connect("127.0.0.1", port, opts) + if not ok then + ngx.say(err) + end + } + } +--- request +GET /t +--- response_body +timeout +--- error_log eval +"lua tcp socket queued connect timed out, when trying to connect to 127.0.0.1:$ENV{TEST_NGINX_MEMCACHED_PORT}" + + + +=== TEST 42: conn queuing: set timeout via lua_socket_connect_timeout +--- config + lua_socket_connect_timeout 10ms; + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + local port = ngx.var.port + local opts = {pool_size = 1, backlog = 1} + local sock1 = ngx.socket.connect("127.0.0.1", port, opts) + + local sock2 = ngx.socket.tcp() + local ok, err = sock2:connect("127.0.0.1", port, opts) + if not ok then + ngx.say(err) + end + } + } +--- request +GET /t +--- response_body +timeout +--- error_log eval +"lua tcp socket queued connect timed out, when trying to connect to 127.0.0.1:$ENV{TEST_NGINX_MEMCACHED_PORT}" + + + +=== TEST 43: conn queuing: client aborting while connect operation is queued +--- config + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + local port = ngx.var.port + local opts = {pool_size = 1, backlog = 1} + local sock1 = ngx.socket.connect("127.0.0.1", port, opts) + + local sock2 = ngx.socket.tcp() + sock2:settimeouts(3000, 3000, 3000) + local ok, err = sock2:connect("127.0.0.1", port, opts) + if not ok then + ngx.say(err) + end + } + } +--- request +GET /t +--- ignore_response +--- timeout: 0.1 +--- abort +--- no_error_log +[error] + + + +=== TEST 44: conn queuing: resume next connect operation if resumed connect failed immediately +--- config + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + local port = ngx.var.port + local opts = {pool = "test", pool_size = 1, backlog = 2} + + local conn_sock = function(should_timeout) + local sock = ngx.socket.tcp() + local ok, err + if should_timeout then + ok, err = sock:connect("", port, opts) + else + ok, err = sock:connect("127.0.0.1", port, opts) + end + if not ok then + ngx.say(err) + return + end + ngx.say("connected in uthread") + sock:close() + end + + local sock, err = ngx.socket.connect("127.0.0.1", port, opts) + if not sock then + ngx.log(ngx.ERR, err) + return + end + + local co1 = ngx.thread.spawn(conn_sock, true) + local co2 = ngx.thread.spawn(conn_sock) + + local ok, err = sock:close() + if not ok then + ngx.log(ngx.ERR, err) + end + + ngx.thread.wait(co1) + ngx.thread.wait(co2) + ngx.say("ok") + } + } +--- request +GET /t +--- response_body +failed to parse host name "": no host +connected in uthread +ok +--- no_error_log +[error] + + + +=== TEST 45: conn queuing: resume connect operation if resumed connect failed (timeout) +--- config + resolver $TEST_NGINX_RESOLVER ipv6=off; + resolver_timeout 3s; + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + local port = ngx.var.port + local opts = {pool = "test", pool_size = 1, backlog = 1} + + local conn_sock = function(should_timeout) + local sock = ngx.socket.tcp() + local ok, err + if should_timeout then + sock:settimeouts(100, 3000, 3000) + ok, err = sock:connect("127.0.0.2", 12345, opts) + else + ok, err = sock:connect("127.0.0.1", port, opts) + end + if not ok then + ngx.say(err) + return + end + ngx.say("connected in uthread") + sock:close() + end + + local co1 = ngx.thread.spawn(conn_sock, true) + local co2 = ngx.thread.spawn(conn_sock) + + ngx.thread.wait(co1) + ngx.thread.wait(co2) + ngx.say("ok") + } + } +--- request +GET /t +--- response_body +timeout +connected in uthread +ok +--- error_log +queue connect operation for connection pool "test" +lua tcp socket connect timed out, when connecting to + + + +=== TEST 46: conn queuing: resume connect operation if resumed connect failed (could not be resolved) +--- config + resolver 127.0.0.2:12345 ipv6=off; + resolver_timeout 1s; + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + local port = ngx.var.port + local opts = {pool = "test", pool_size = 1, backlog = 1} + + local conn_sock = function(should_timeout) + local sock = ngx.socket.tcp() + local ok, err + if should_timeout then + sock:settimeouts(1, 3000, 3000) + ok, err = sock:connect("agentzh.org", 80, opts) + else + ok, err = sock:connect("127.0.0.1", port, opts) + end + if not ok then + ngx.say(err) + return + end + ngx.say("connected in uthread") + sock:close() + end + + local co1 = ngx.thread.spawn(conn_sock, true) + local co2 = ngx.thread.spawn(conn_sock) + + ngx.thread.wait(co1) + ngx.thread.wait(co2) + ngx.say("ok") + } + } +--- request +GET /t +--- response_body +agentzh.org could not be resolved (110: Operation timed out) +connected in uthread +ok +--- error_log +queue connect operation for connection pool "test" + + + +=== TEST 47: conn queuing: resume connect operation if resumed connect failed (connection refused) +--- config + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + local port = ngx.var.port + local opts = {pool = "test", pool_size = 1, backlog = 1} + + local conn_sock = function(should_timeout) + local sock = ngx.socket.tcp() + local ok, err + if should_timeout then + sock:settimeouts(100, 3000, 3000) + ok, err = sock:connect("127.0.0.1", 62345, opts) + else + ok, err = sock:connect("127.0.0.1", port, opts) + end + if not ok then + ngx.say(err) + return + end + ngx.say("connected in uthread") + sock:close() + end + + local co1 = ngx.thread.spawn(conn_sock, true) + local co2 = ngx.thread.spawn(conn_sock) + + ngx.thread.wait(co1) + ngx.thread.wait(co2) + ngx.say("ok") + } + } +--- request +GET /t +--- response_body +connection refused +connected in uthread +ok +--- error_log +queue connect operation for connection pool "test" + + + +=== TEST 48: conn queuing: resume connect operation if resumed connect failed (uthread aborted while resolving) +--- http_config + lua_package_path '../lua-resty-core/lib/?.lua;../lua-resty-lrucache/lib/?.lua;;'; +--- config + resolver 127.0.0.1 ipv6=off; + resolver_timeout 100s; + set $port $TEST_NGINX_MEMCACHED_PORT; + + location /sub { + content_by_lua_block { + local semaphore = require "ngx.semaphore" + local sem = semaphore.new() + + local function f() + sem:wait(0.1) + ngx.exit(0) + end + + local opts = {pool = "test", pool_size = 1, backlog = 1} + local port = ngx.var.port + ngx.timer.at(0, function() + sem:post() + local sock2, err = ngx.socket.connect("127.0.0.1", port, opts) + package.loaded.for_timer_to_resume:post() + if not sock2 then + ngx.log(ngx.ALERT, "resume connect failed: ", err) + return + end + + ngx.log(ngx.INFO, "resume success") + end) + + ngx.thread.spawn(f) + local sock1, err = ngx.socket.connect("openresty.org", 80, opts) + if not sock1 then + ngx.say(err) + return + end + } + } + + location /t { + content_by_lua_block { + local semaphore = require "ngx.semaphore" + local for_timer_to_resume = semaphore.new() + package.loaded.for_timer_to_resume = for_timer_to_resume + + ngx.location.capture("/sub") + for_timer_to_resume:wait(0.1) + } + } +--- request +GET /t +--- no_error_log +[alert] +--- error_log +resume success + + + +=== TEST 49: conn queuing: resume connect operation if resumed connect failed (uthread killed while resolving) +--- config + resolver 127.0.0.1 ipv6=off; + resolver_timeout 100s; + set $port $TEST_NGINX_MEMCACHED_PORT; + + location /t { + content_by_lua_block { + local opts = {pool = "test", pool_size = 1, backlog = 1} + local port = ngx.var.port + + local function resolve() + local sock1, err = ngx.socket.connect("openresty.org", 80, opts) + if not sock1 then + ngx.say(err) + return + end + end + + local th = ngx.thread.spawn(resolve) + local ok, err = ngx.thread.kill(th) + if not ok then + ngx.log(ngx.ALERT, "kill thread failed: ", err) + return + end + + local sock2, err = ngx.socket.connect("127.0.0.1", port, opts) + if not sock2 then + ngx.log(ngx.ALERT, "resume connect failed: ", err) + return + end + + ngx.log(ngx.INFO, "resume success") + } + } +--- request +GET /t +--- no_error_log +[alert] +--- error_log +resume success + + + +=== TEST 50: conn queuing: increase the counter for connections created before creating the pool with setkeepalive() +--- config + set $port $TEST_NGINX_MEMCACHED_PORT; + + location /t { + content_by_lua_block { + local function connect() + local sock, err = ngx.socket.connect("127.0.0.1", ngx.var.port) + if not sock then + error("connect failed: " .. err) + end + + return sock + end + + local sock1 = connect() + local sock2 = connect() + assert(sock1:setkeepalive()) + assert(sock2:setkeepalive()) + + local sock1 = connect() + local sock2 = connect() + assert(sock1:close()) + assert(sock2:close()) + + ngx.say("ok") + } + } +--- request +GET /t +--- no_error_log +[error] +--- response_body +ok + + + +=== TEST 51: conn queuing: only decrease the counter for connections which were counted by the pool +--- config + set $port $TEST_NGINX_MEMCACHED_PORT; + + location /t { + content_by_lua_block { + local function connect() + local sock, err = ngx.socket.connect("127.0.0.1", ngx.var.port) + if not sock then + error("connect failed: " .. err) + end + + return sock + end + + local sock1 = connect() + local sock2 = connect() + assert(sock1:setkeepalive(1000, 1)) + assert(sock2:setkeepalive(1000, 1)) + + local sock1 = connect() + local sock2 = connect() + assert(sock1:close()) + assert(sock2:close()) + + ngx.say("ok") + } + } +--- request +GET /t +--- no_error_log +[error] +--- response_body +ok + + + +=== TEST 52: conn queuing: clean up pending connect operations which are in queue +--- config + set $port $TEST_NGINX_MEMCACHED_PORT; + + location /sub { + content_by_lua_block { + local opts = {pool = "test", pool_size = 1, backlog = 1} + local sock, err = ngx.socket.connect("127.0.0.1", ngx.var.port, opts) + if not sock then + ngx.say("connect failed: " .. err) + return + end + + local function f() + assert(ngx.socket.connect("127.0.0.1", ngx.var.port, opts)) + end + + local th = ngx.thread.spawn(f) + local ok, err = ngx.thread.kill(th) + if not ok then + ngx.log(ngx.ERR, "kill thread failed: ", err) + return + end + + sock:close() + } + } + + location /t { + content_by_lua_block { + ngx.location.capture("/sub") + -- let pending connect operation resumes first + ngx.sleep(0) + ngx.say("ok") + } + } +--- request +GET /t +--- no_error_log +[error] +--- error_log +lua tcp socket abort queueing +--- response_body +ok diff --git a/debian/modules/http-lua/t/073-backtrace.t b/debian/modules/http-lua/t/073-backtrace.t index 6c54692..663c3af 100644 --- a/debian/modules/http-lua/t/073-backtrace.t +++ b/debian/modules/http-lua/t/073-backtrace.t @@ -21,10 +21,10 @@ __DATA__ --- config location /lua { content_by_lua - ' function bar() + ' local function bar() return lua_concat(3) end - function foo() + local function foo() bar() end foo() @@ -37,7 +37,7 @@ GET /lua attempt to call global 'lua_concat' : in function 'bar' :5: in function 'foo' -:7: in function +:7: in main chunk @@ -45,10 +45,10 @@ attempt to call global 'lua_concat' --- config location /lua { content_by_lua - ' function bar() + ' local function bar() error(nil) end - function foo() + local function foo() bar() end foo() @@ -64,7 +64,7 @@ GET /lua " in function 'error'", ": in function 'bar'", ":5: in function 'foo'", -qr/:7: in function /, +qr/:7: in main chunk/, ] @@ -125,7 +125,7 @@ probe process("$LIBLUA_PATH").function("lua_concat") { :63: in function 'func16' :67: in function 'func17' :71: in function 'func18' -:74: in function +:74: in main chunk diff --git a/debian/modules/http-lua/t/075-logby.t b/debian/modules/http-lua/t/075-logby.t index 520c62e..8eece69 100644 --- a/debian/modules/http-lua/t/075-logby.t +++ b/debian/modules/http-lua/t/075-logby.t @@ -220,7 +220,7 @@ failed to run log_by_lua*: unknown reason -=== TEST 11: globals get cleared for every single request +=== TEST 11: globals sharing --- config location /lua { echo ok; @@ -228,6 +228,7 @@ failed to run log_by_lua*: unknown reason if not foo then foo = 1 else + ngx.log(ngx.INFO, "old foo: ", foo) foo = foo + 1 end ngx.log(ngx.WARN, "foo = ", foo) @@ -237,8 +238,9 @@ failed to run log_by_lua*: unknown reason GET /lua --- response_body ok ---- error_log -foo = 1 +--- grep_error_log eval: qr/old foo: \d+/ +--- grep_error_log_out eval +["", "old foo: 1\n"] @@ -495,7 +497,8 @@ API disabled in the context of log_by_lua* location /t { echo ok; log_by_lua ' - function foo() + local bar + local function foo() bar() end diff --git a/debian/modules/http-lua/t/081-bytecode.t b/debian/modules/http-lua/t/081-bytecode.t index cb50e94..92383bc 100644 --- a/debian/modules/http-lua/t/081-bytecode.t +++ b/debian/modules/http-lua/t/081-bytecode.t @@ -24,7 +24,7 @@ __DATA__ content_by_lua ' ngx.req.read_body(); local b = ngx.req.get_body_data(); - f = io.open(ngx.var.realpath_root.."/test.lua", "w"); + local f = io.open(ngx.var.realpath_root.."/test.lua", "w"); -- luajit bytecode: sub(149,-1), lua bytecode: sub(1,147) if jit then if not string.find(jit.version, "LuaJIT 2.0") then @@ -35,7 +35,8 @@ __DATA__ else f:write(string.sub(b, 1, 147)); end - f:close(); res = ngx.location.capture("/call"); + f:close(); + local res = ngx.location.capture("/call"); ngx.print(res.body) '; } @@ -60,14 +61,15 @@ __DATA__ content_by_lua ' ngx.req.read_body(); local b = ngx.req.get_body_data(); - f = io.open(ngx.var.realpath_root.."/test.lua", "w"); + local f = io.open(ngx.var.realpath_root.."/test.lua", "w"); -- luajit bytecode: sub(149,-1), lua bytecode: sub(1,147) if not package.loaded["jit"] then f:write(string.sub(b, 149)); else f:write(string.sub(b, 1, 147)); end - f:close(); res = ngx.location.capture("/call"); + f:close(); + local res = ngx.location.capture("/call"); if res.status == 200 then ngx.print(res.body) else @@ -85,7 +87,7 @@ __DATA__ --- response_body error --- error_log eval -qr/failed to load external Lua file ".*?test\.lua": bad byte-code header/ +qr/failed to load external Lua file ".*?test\.lua": .* cannot load incompatible bytecode/ @@ -96,14 +98,15 @@ qr/failed to load external Lua file ".*?test\.lua": bad byte-code header/ content_by_lua ' ngx.req.read_body(); local b = ngx.req.get_body_data(); - f = io.open(ngx.var.realpath_root.."/test.lua", "w"); + local f = io.open(ngx.var.realpath_root.."/test.lua", "w"); -- luajit bytecode: sub(149,-1), lua bytecode: sub(1,147) if package.loaded["jit"] then f:write(string.sub(b, 149)); else f:write(string.sub(b, 1, 147)); end - f:close(); res = ngx.location.capture("/call"); + f:close(); + local res = ngx.location.capture("/call"); if res.status == 200 then ngx.print(res.body) else @@ -121,7 +124,7 @@ qr/failed to load external Lua file ".*?test\.lua": bad byte-code header/ --- response_body error --- error_log -bytecode format version unsupported +cannot load incompatible bytecode @@ -132,7 +135,7 @@ bytecode format version unsupported content_by_lua ' ngx.req.read_body(); local b = ngx.req.get_body_data(); - f = io.open(ngx.var.realpath_root.."/test.lua", "w"); + local f = io.open(ngx.var.realpath_root.."/test.lua", "w"); -- luajit bytecode: sub(149,-1), lua bytecode: sub(1,147) local do_jit if jit then @@ -176,7 +179,7 @@ bytecode format version unsupported content_by_lua ' ngx.req.read_body(); local b = ngx.req.get_body_data(); - f = io.open(ngx.var.realpath_root.."/test.lua", "w"); + local f = io.open(ngx.var.realpath_root.."/test.lua", "w"); -- luajit bytecode: sub(149,-1), lua bytecode: sub(1,147) local jit; if package.loaded["jit"] then @@ -220,7 +223,7 @@ error content_by_lua ' ngx.req.read_body(); local b = ngx.req.get_body_data(); - f = io.open(ngx.var.realpath_root.."/test.lua", "w"); + local f = io.open(ngx.var.realpath_root.."/test.lua", "w"); -- luajit bytecode: sub(149,-1), lua bytecode: sub(1,147) if jit then if not string.find(jit.version, "LuaJIT 2.0") then @@ -256,9 +259,9 @@ error content_by_lua ' local bcsave = require "jit.bcsave" if jit then - local prefix = ngx.config.prefix() - local infile = prefix .. "html/a.lua" - local outfile = prefix .. "html/a.luac" + local prefix = "$TEST_NGINX_SERVER_ROOT" + local infile = prefix .. "/html/a.lua" + local outfile = prefix .. "/html/a.luac" bcsave.start("-s", infile, outfile) return ngx.exec("/call") end @@ -289,9 +292,9 @@ ngx.status = 201 ngx.say("hello from Lua!") content_by_lua ' local bcsave = require "jit.bcsave" if jit then - local prefix = ngx.config.prefix() - local infile = prefix .. "html/a.lua" - local outfile = prefix .. "html/a.luac" + local prefix = "$TEST_NGINX_SERVER_ROOT" + local infile = prefix .. "/html/a.lua" + local outfile = prefix .. "/html/a.luac" bcsave.start("-g", infile, outfile) return ngx.exec("/call") end @@ -320,9 +323,9 @@ ngx.status = 201 ngx.say("hello from Lua!") --- config location = /t { content_by_lua_block { - local f = assert(loadstring("a = a and a + 1 or 1 ngx.say('a = ', a)", "=code")) + local f = assert(loadstring("local a = 1 ngx.say('a = ', a)", "=code")) local bc = string.dump(f) - local f = assert(io.open("t/servroot/html/a.luac", "w")) + local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/a.luac", "w")) f:write(bc) f:close() } @@ -349,9 +352,9 @@ a = 1 --- config location = /t { content_by_lua_block { - local f = assert(loadstring("a = a and a + 1 or 1 ngx.say('a = ', a)", "=code")) + local f = assert(loadstring("local a = 1 ngx.say('a = ', a)", "=code")) local bc = string.dump(f, true) - local f = assert(io.open("t/servroot/html/a.luac", "w")) + local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/a.luac", "w")) f:write(bc) f:close() } diff --git a/debian/modules/http-lua/t/082-body-filter.t b/debian/modules/http-lua/t/082-body-filter.t index 98efa84..5f765fa 100644 --- a/debian/modules/http-lua/t/082-body-filter.t +++ b/debian/modules/http-lua/t/082-body-filter.t @@ -460,7 +460,8 @@ GET /t --- config location /t { body_filter_by_lua ' - function foo() + local bar + local function foo() bar() end diff --git a/debian/modules/http-lua/t/084-inclusive-receiveuntil.t b/debian/modules/http-lua/t/084-inclusive-receiveuntil.t index f7d5d3d..66be893 100644 --- a/debian/modules/http-lua/t/084-inclusive-receiveuntil.t +++ b/debian/modules/http-lua/t/084-inclusive-receiveuntil.t @@ -56,7 +56,7 @@ __DATA__ local reader = sock:receiveuntil("abcabd", { inclusive = true }) for i = 1, 3 do - line, err, part = reader() + local line, err, part = reader() if line then ngx.say("read: ", line) @@ -128,7 +128,7 @@ close: 1 nil local reader = sock:receiveuntil("abcabdabcabe", { inclusive = true }) for i = 1, 2 do - line, err, part = reader() + local line, err, part = reader() if line then ngx.say("read: ", line) @@ -200,7 +200,7 @@ close: 1 nil local reader = sock:receiveuntil("abcabd", { inclusive = true }) for i = 1, 3 do - line, err, part = reader() + local line, err, part = reader() if line then ngx.say("read: ", line) @@ -272,7 +272,7 @@ close: 1 nil local reader = sock:receiveuntil("aa", { inclusive = nil }) for i = 1, 2 do - line, err, part = reader() + local line, err, part = reader() if line then ngx.say("read: ", line) @@ -343,7 +343,7 @@ close: 1 nil local reader = sock:receiveuntil("aa", { inclusive = false }) for i = 1, 2 do - line, err, part = reader() + local line, err, part = reader() if line then ngx.say("read: ", line) @@ -414,7 +414,7 @@ close: 1 nil local reader = sock:receiveuntil("aa", { inclusive = true }) for i = 1, 2 do - line, err, part = reader() + local line, err, part = reader() if line then ngx.say("read: ", line) @@ -485,7 +485,7 @@ close: 1 nil local reader = sock:receiveuntil("aa", { inclusive = "true" }) for i = 1, 2 do - line, err, part = reader() + local line, err, part = reader() if line then ngx.say("read: ", line) @@ -552,7 +552,7 @@ bad "inclusive" option value type: string local reader = sock:receiveuntil("aa", { inclusive = "true" }) for i = 1, 2 do - line, err, part = reader() + local line, err, part = reader() if line then ngx.say("read: ", line) @@ -620,7 +620,7 @@ bad "inclusive" option value type: string local reader = sock:receiveuntil("--abc", { inclusive = true }) for i = 1, 7 do - line, err, part = reader(4) + local line, err, part = reader(4) if line then ngx.say("read: ", line) @@ -697,7 +697,7 @@ close: 1 nil local reader = sock:receiveuntil("--abc", { inclusive = true }) for i = 1, 7 do - line, err, part = reader(4) + local line, err, part = reader(4) if line then ngx.say("read: ", line) diff --git a/debian/modules/http-lua/t/087-udp-socket.t b/debian/modules/http-lua/t/087-udp-socket.t index 8bedc32..dc6cad5 100644 --- a/debian/modules/http-lua/t/087-udp-socket.t +++ b/debian/modules/http-lua/t/087-udp-socket.t @@ -555,7 +555,7 @@ lua udp socket read timed out local udp = socket.udp() - udp:settimeout(2000) -- 2 sec + udp:settimeout(5000) -- 5 sec local ok, err = udp:setpeername("$TEST_NGINX_RESOLVER", 53) if not ok then @@ -824,7 +824,7 @@ probe syscall.socket.return, syscall.connect.return { === TEST 15: bad request tries to setpeer --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location = /main { @@ -881,7 +881,7 @@ qr/runtime error: content_by_lua\(nginx\.conf:\d+\):14: bad request/ === TEST 16: bad request tries to send --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location = /main { @@ -938,7 +938,7 @@ qr/runtime error: content_by_lua\(nginx\.conf:\d+\):14: bad request/ === TEST 17: bad request tries to receive --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location = /main { @@ -995,7 +995,7 @@ qr/runtime error: content_by_lua\(nginx\.conf:\d+\):14: bad request/ === TEST 18: bad request tries to close --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location = /main { @@ -1052,7 +1052,7 @@ qr/runtime error: content_by_lua\(nginx\.conf:\d+\):14: bad request/ === TEST 19: bad request tries to receive --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location = /main { diff --git a/debian/modules/http-lua/t/090-log-socket-errors.t b/debian/modules/http-lua/t/090-log-socket-errors.t index 16576b6..f5a9f80 100644 --- a/debian/modules/http-lua/t/090-log-socket-errors.t +++ b/debian/modules/http-lua/t/090-log-socket-errors.t @@ -28,7 +28,7 @@ __DATA__ lua_socket_log_errors off; content_by_lua ' local sock = ngx.socket.tcp() - local ok, err = sock:connect("agentzh.org", 12345) + local ok, err = sock:connect("127.0.0.2", 12345) ngx.say(err) '; } @@ -50,7 +50,7 @@ timeout lua_socket_log_errors on; content_by_lua ' local sock = ngx.socket.tcp() - local ok, err = sock:connect("agentzh.org", 12345) + local ok, err = sock:connect("127.0.0.2", 12345) ngx.say(err) '; } @@ -59,7 +59,7 @@ GET /t --- response_body timeout --- error_log -lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 +lua tcp socket connect timed out, when connecting to 127.0.0.2:12345 @@ -72,7 +72,7 @@ lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 lua_socket_read_timeout 1ms; content_by_lua ' local sock = ngx.socket.udp() - local ok, err = sock:setpeername("agentzh.org", 12345) + local ok, err = sock:setpeername("127.0.0.2", 12345) ok, err = sock:receive() ngx.say(err) '; @@ -95,7 +95,7 @@ lua udp socket read timed out lua_socket_read_timeout 1ms; content_by_lua ' local sock = ngx.socket.udp() - local ok, err = sock:setpeername("agentzh.org", 12345) + local ok, err = sock:setpeername("127.0.0.2", 12345) ok, err = sock:receive() ngx.say(err) '; diff --git a/debian/modules/http-lua/t/091-coroutine.t b/debian/modules/http-lua/t/091-coroutine.t index bceb512..7cf60f9 100644 --- a/debian/modules/http-lua/t/091-coroutine.t +++ b/debian/modules/http-lua/t/091-coroutine.t @@ -85,7 +85,7 @@ __DATA__ content_by_lua ' local cc, cr, cy = coroutine.create, coroutine.resume, coroutine.yield - function f() + local function f() local cnt = 0 for i = 1, 20 do ngx.say("Hello, ", cnt) @@ -120,7 +120,7 @@ Hello, 2 --- config location /lua { content_by_lua ' - function f(fid) + local function f(fid) local cnt = 0 while true do ngx.say("cc", fid, ": ", cnt) @@ -163,7 +163,7 @@ cc3: 2 resolver $TEST_NGINX_RESOLVER ipv6=off; location /lua { content_by_lua ' - function worker(url) + local function worker(url) local sock = ngx.socket.tcp() local ok, err = sock:connect(url, 80) coroutine.yield() @@ -178,7 +178,7 @@ cc3: 2 local urls = { "agentzh.org", - "iscribblet.org", + "openresty.com", "openresty.org" } @@ -204,7 +204,7 @@ cc3: 2 GET /lua --- response_body successfully connected to: agentzh.org -successfully connected to: iscribblet.org +successfully connected to: openresty.com successfully connected to: openresty.org *** All Done *** --- no_error_log @@ -218,14 +218,14 @@ successfully connected to: openresty.org location /lua { content_by_lua ' -- generate all the numbers from 2 to n - function gen (n) + local function gen (n) return coroutine.wrap(function () for i=2,n do coroutine.yield(i) end end) end -- filter the numbers generated by g, removing multiples of p - function filter (p, g) + local function filter (p, g) return coroutine.wrap(function () while 1 do local n = g() @@ -235,8 +235,8 @@ successfully connected to: openresty.org end) end - N = 10 - x = gen(N) -- generate primes up to N + local N = 10 + local x = gen(N) -- generate primes up to N while 1 do local n = x() -- pick a number until done if n == nil then break end @@ -264,14 +264,14 @@ GET /lua coroutine.create = nil coroutine.resume = nil -- generate all the numbers from 2 to n - function gen (n) + local function gen (n) return coroutine.wrap(function () for i=2,n do coroutine.yield(i) end end) end -- filter the numbers generated by g, removing multiples of p - function filter (p, g) + local function filter (p, g) return coroutine.wrap(function () while 1 do local n = g() @@ -281,8 +281,8 @@ GET /lua end) end - N = 10 - x = gen(N) -- generate primes up to N + local N = 10 + local x = gen(N) -- generate primes up to N while 1 do local n = x() -- pick a number until done if n == nil then break end @@ -307,7 +307,7 @@ GET /lua --- config location /lua { content_by_lua ' - function generatefib (n) + local function generatefib (n) return coroutine.wrap(function () local a,b = 1, 1 while a <= n do @@ -362,7 +362,7 @@ GET /lua resolver $TEST_NGINX_RESOLVER ipv6=off; location /lua { content_by_lua ' - function worker(url) + local function worker(url) local sock = ngx.socket.tcp() local ok, err = sock:connect(url, 80) coroutine.yield() @@ -377,7 +377,7 @@ GET /lua local urls = { "agentzh.org", - "iscribblet.org", + "openresty.com", "openresty.org" } @@ -398,7 +398,7 @@ GET /lua GET /lua --- response_body successfully connected to: agentzh.org -successfully connected to: iscribblet.org +successfully connected to: openresty.com successfully connected to: openresty.org *** All Done *** --- no_error_log @@ -414,7 +414,7 @@ successfully connected to: openresty.org local cc, cr, cy = coroutine.create, coroutine.resume, coroutine.yield local st, rn = coroutine.status, coroutine.running - function f(self) + local function f(self) local cnt = 0 if rn() ~= self then ngx.say("error"); return end ngx.say("running: ", st(self)) --running @@ -509,7 +509,7 @@ GET /lua --- config location /lua { content_by_lua ' - function print(...) + local function print(...) local args = {...} local is_first = true for i,v in ipairs(args) do @@ -523,12 +523,12 @@ GET /lua ngx.print("\\\n") end - function foo (a) + local function foo (a) print("foo", a) return coroutine.yield(2*a) end - co = coroutine.create(function (a,b) + local co = coroutine.create(function (a,b) print("co-body", a, b) local r = foo(a+1) print("co-body", r) @@ -566,7 +566,8 @@ main false cannot resume dead coroutine local create = coroutine.create local resume = coroutine.resume local yield = coroutine.yield - function f() + local g + local function f() ngx.say("f begin") yield() local c2 = create(g) @@ -627,8 +628,9 @@ main done local yield = coroutine.yield local code = 400 + local g - function f() + local function f() local c2 = create(g) yield() code = code + 1 @@ -683,8 +685,9 @@ exit local yield = coroutine.yield local code = 0 + local g - function f() + local function f() local c2 = create(g) yield() code = code + 1 @@ -740,7 +743,7 @@ num: 3 location /lua { echo hello; header_filter_by_lua ' - function f() + local function f() yield() end @@ -764,13 +767,13 @@ API disabled in the context of header_filter_by_lua* local c1, c2 - function f() + local function f() print("f 1") print(coroutine.resume(c2)) print("f 2") end - function g() + local function g() print("g 1") -- print(coroutine.resume(c1)) print("g 2") @@ -803,13 +806,13 @@ f 2 local c1, c2 - function f() + local function f() print("f 1") print(coroutine.resume(c2)) print("f 2") end - function g() + local function g() print("g 1") print(coroutine.resume(c1)) print("g 2") @@ -859,7 +862,7 @@ falsecannot resume running coroutine location /t { content_by_lua ' local co - function f() + local function f() ngx.say("f: ", coroutine.status(co)) ngx.say("f: ", coroutine.resume(co)) end @@ -885,7 +888,7 @@ chunk: true location /t { content_by_lua ' local co - function f() + local function f() error("bad") end co = coroutine.create(f) @@ -990,7 +993,7 @@ test10 resolver $TEST_NGINX_RESOLVER ipv6=off; location /lua { content_by_lua ' - function worker(url) + local function worker(url) local sock = ngx.socket.tcp() local ok, err = sock:connect(url, 80) coroutine.yield() @@ -1044,7 +1047,7 @@ successfully connected to: agentzh.org resolver $TEST_NGINX_RESOLVER ipv6=off; location /lua { content_by_lua ' - function worker(url) + local function worker(url) local sock = ngx.socket.tcp() local ok, err = sock:connect(url, 80) coroutine.yield() @@ -1104,7 +1107,7 @@ successfully connected to: agentzh.org --- config location /cotest { content_by_lua ' - function generator() + local function generator() return co_wrap(function() co_yield("data") end) @@ -1133,7 +1136,7 @@ data --- config location /cotest { content_by_lua ' - function generator() + local function generator() return co_wrap(function() co_yield("data") end) @@ -1166,7 +1169,7 @@ data content_by_lua ' local cc, cr, cy = coroutine.create, coroutine.resume, coroutine.yield - function f() + local function f() return 3 end @@ -1199,7 +1202,7 @@ ok local coroutine = require "coroutine" local cc, cr, cy = coroutine.create, coroutine.resume, coroutine.yield - function f() + local function f() local cnt = 0 for i = 1, 20 do ngx.say("Hello, ", cnt) @@ -1238,7 +1241,7 @@ Hello, 2 header_filter_by_lua ' local cc, cr, cy = coroutine.create, coroutine.resume, coroutine.yield - function f() + local function f() local cnt = 0 for i = 1, 20 do print("co yield: ", cnt) @@ -1278,7 +1281,7 @@ co yield: 2 body_filter_by_lua ' local cc, cr, cy = coroutine.create, coroutine.resume, coroutine.yield - function f() + local function f() local cnt = 0 for i = 1, 20 do print("co yield: ", cnt) diff --git a/debian/modules/http-lua/t/093-uthread-spawn.t b/debian/modules/http-lua/t/093-uthread-spawn.t index b622d30..ab6db2f 100644 --- a/debian/modules/http-lua/t/093-uthread-spawn.t +++ b/debian/modules/http-lua/t/093-uthread-spawn.t @@ -24,7 +24,7 @@ __DATA__ --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("hello in thread") end @@ -58,11 +58,11 @@ after --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("in thread 1") end - function g() + local function g() ngx.say("in thread 2") end @@ -107,7 +107,7 @@ after 2 --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("before sleep") ngx.sleep(0.1) ngx.say("after sleep") @@ -144,13 +144,13 @@ after sleep --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("1: before sleep") ngx.sleep(0.2) ngx.say("1: after sleep") end - function g() + local function g() ngx.say("2: before sleep") ngx.sleep(0.1) ngx.say("2: after sleep") @@ -200,7 +200,7 @@ delete thread 2 --- config location /lua { content_by_lua ' - function f() + local function f() ngx.blah() end @@ -231,9 +231,9 @@ qr/lua user thread aborted: runtime error: content_by_lua\(nginx\.conf:\d+\):3: --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("before capture") - res = ngx.location.capture("/proxy") + local res = ngx.location.capture("/proxy") ngx.say("after capture: ", res.body) end @@ -277,7 +277,7 @@ after capture: hello world --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("before capture") local res = ngx.location.capture("/proxy?foo") ngx.say("after capture: ", res.body) @@ -330,7 +330,7 @@ after capture: hello foo --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("before capture") local res = ngx.location.capture("/proxy?foo") ngx.say("after capture: ", res.body) @@ -384,13 +384,13 @@ capture: hello bar --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("f: before capture") local res = ngx.location.capture("/proxy?foo") ngx.say("f: after capture: ", res.body) end - function g() + local function g() ngx.say("g: before capture") local res = ngx.location.capture("/proxy?bah") ngx.say("g: after capture: ", res.body) @@ -462,7 +462,8 @@ g: after capture: hello bah --- config location /lua { content_by_lua ' - function f() + local g + local function f() ngx.say("before g") ngx.thread.spawn(g) ngx.say("after g") @@ -508,7 +509,8 @@ after g --- config location /lua { content_by_lua ' - function f() + local g + local function f() ngx.say("before g") ngx.thread.spawn(g) ngx.say("after g") @@ -556,7 +558,7 @@ hello in g() location /lua { content_by_lua ' local co - function f() + local function f() co = coroutine.running() ngx.sleep(0.1) end @@ -589,7 +591,7 @@ status: running location /lua { content_by_lua ' local co - function f() + local function f() co = coroutine.running() end @@ -621,7 +623,8 @@ status: zombie location /lua { content_by_lua ' local co - function f() + local g + local function f() co = coroutine.running() local co2 = coroutine.create(g) coroutine.resume(co2) @@ -660,7 +663,8 @@ status: normal --- config location /lua { content_by_lua ' - function f() + local g + local function f() ngx.say("before g") ngx.thread.spawn(g) ngx.say("after g") @@ -707,7 +711,7 @@ after f content_by_lua ' local yield = coroutine.yield - function f() + local function f() local self = coroutine.running() ngx.say("f 1") yield(self) @@ -760,7 +764,7 @@ f 3 content_by_lua ' local yield = coroutine.yield - function f() + local function f() local self = coroutine.running() ngx.say("f 1") yield(self) @@ -769,7 +773,7 @@ f 3 ngx.say("f 3") end - function g() + local function g() local self = coroutine.running() ngx.say("g 1") yield(self) @@ -816,7 +820,7 @@ g 3 --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("hello in thread") coroutine.yield(coroutine.running) ngx.flush(true) @@ -853,12 +857,12 @@ after --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("hello from f") ngx.flush(true) end - function g() + local function g() ngx.say("hello from g") ngx.flush(true) end @@ -904,7 +908,7 @@ hello from g --- config location /lua { content_by_lua ' - function f() + local function f() local sock = ngx.socket.tcp() local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_MEMCACHED_PORT) if not ok then @@ -956,7 +960,7 @@ received: OK --- config location /lua { content_by_lua ' - function f() + local function f() local sock = ngx.socket.udp() local ok, err = sock:setpeername("127.0.0.1", 12345) local bytes, err = sock:send("blah") @@ -1018,7 +1022,7 @@ after)$ --- config location /lua { content_by_lua ' - function f() + local function f() ngx.req.read_body() local body = ngx.req.get_body_data() ngx.say("body: ", body) @@ -1063,7 +1067,7 @@ body: hello world)$ --- config location /lua { content_by_lua ' - function f() + local function f() local sock = ngx.req.socket() local body, err = sock:receive(11) if not body then @@ -1113,7 +1117,7 @@ body: hello world)$ --- config location /lua { content_by_lua ' - function f(a, b) + local function f(a, b) ngx.say("hello ", a, " and ", b) end @@ -1647,7 +1651,7 @@ ok --- config location /lua { content_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.say("f") end diff --git a/debian/modules/http-lua/t/094-uthread-exit.t b/debian/modules/http-lua/t/094-uthread-exit.t index 2f7d9ba..58d8d0b 100644 --- a/debian/modules/http-lua/t/094-uthread-exit.t +++ b/debian/modules/http-lua/t/094-uthread-exit.t @@ -24,7 +24,7 @@ __DATA__ --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.exit(0) end @@ -87,7 +87,7 @@ hello in thread --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -171,13 +171,13 @@ after --- config location /lua { content_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.say("f") ngx.exit(0) end - function g() + local function g() ngx.sleep(1) ngx.say("g") end @@ -261,7 +261,7 @@ f --- config location /lua { content_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.say("exiting the user thread") ngx.exit(0) @@ -297,10 +297,10 @@ exiting the user thread === TEST 5: exit in user thread (entry thread is still pending on the DNS resolver for ngx.socket.tcp) --- config location /lua { - resolver agentzh.org; + resolver 127.0.0.2:12345; resolver_timeout 12s; content_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.001) ngx.exit(0) @@ -393,10 +393,10 @@ after === TEST 6: exit in user thread (entry thread is still pending on the DNS resolver for ngx.socket.udp) --- config location /lua { - resolver agentzh.org; + resolver 127.0.0.2:12345; resolver_timeout 12s; content_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.001) ngx.exit(0) @@ -490,7 +490,7 @@ after --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -501,7 +501,7 @@ after ngx.say("after") local sock = ngx.socket.tcp() sock:settimeout(12000) - local ok, err = sock:connect("172.105.207.225", 12345) + local ok, err = sock:connect("127.0.0.2", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -580,7 +580,7 @@ after --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -680,7 +680,7 @@ after --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -786,7 +786,7 @@ after --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -881,7 +881,7 @@ after --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -974,7 +974,7 @@ after location /lua { client_body_timeout 12000ms; content_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -1059,7 +1059,7 @@ after location /lua { client_body_timeout 12000ms; content_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -1142,7 +1142,7 @@ attempt to abort with pending subrequests location /lua { client_body_timeout 12000ms; content_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.exit(0) end @@ -1225,7 +1225,7 @@ attempt to abort with pending subrequests location /lua { client_body_timeout 12000ms; content_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.exit(0) end @@ -1315,7 +1315,7 @@ attempt to abort with pending subrequests location /lua { client_body_timeout 12000ms; content_by_lua ' - function f() + local function f() ngx.location.capture_multi{ {"/echo"}, {"/sleep"} @@ -1407,7 +1407,7 @@ attempt to abort with pending subrequests location /lua { client_body_timeout 12000ms; content_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(444) @@ -1490,7 +1490,7 @@ free request location /lua { client_body_timeout 12000ms; content_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(408) @@ -1573,7 +1573,7 @@ free request location /lua { client_body_timeout 12000ms; content_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(499) diff --git a/debian/modules/http-lua/t/095-uthread-exec.t b/debian/modules/http-lua/t/095-uthread-exec.t index 56156c4..7bf37c0 100644 --- a/debian/modules/http-lua/t/095-uthread-exec.t +++ b/debian/modules/http-lua/t/095-uthread-exec.t @@ -23,7 +23,7 @@ __DATA__ --- config location /lua { content_by_lua ' - function f() + local function f() ngx.exec("/foo") end @@ -58,7 +58,7 @@ i am foo --- config location /lua { content_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.exec("/foo") end @@ -93,7 +93,7 @@ i am foo --- config location /lua { content_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.exec("/foo") end @@ -175,12 +175,12 @@ hello foo --- config location /lua { content_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.exec("/foo") end - function g() + local function g() ngx.sleep(1) end @@ -267,7 +267,7 @@ hello foo location /lua { client_body_timeout 12000ms; content_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.exec("/foo") end @@ -348,7 +348,7 @@ attempt to abort with pending subrequests location /lua { client_body_timeout 12000ms; content_by_lua ' - function f() + local function f() ngx.location.capture("/sleep") ngx.say("end") end diff --git a/debian/modules/http-lua/t/096-uthread-redirect.t b/debian/modules/http-lua/t/096-uthread-redirect.t index 003c642..95bff01 100644 --- a/debian/modules/http-lua/t/096-uthread-redirect.t +++ b/debian/modules/http-lua/t/096-uthread-redirect.t @@ -25,7 +25,7 @@ __DATA__ location /lua { client_body_timeout 12000ms; content_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.redirect(301) end @@ -114,7 +114,7 @@ attempt to abort with pending subrequests --- config location /lua { content_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.redirect(301) end @@ -194,7 +194,7 @@ free request location /lua { client_body_timeout 12000ms; content_by_lua ' - function f() + local function f() ngx.location.capture_multi{ {"/echo"}, {"/sleep"} diff --git a/debian/modules/http-lua/t/097-uthread-rewrite.t b/debian/modules/http-lua/t/097-uthread-rewrite.t index 2f0c06f..998e256 100644 --- a/debian/modules/http-lua/t/097-uthread-rewrite.t +++ b/debian/modules/http-lua/t/097-uthread-rewrite.t @@ -23,7 +23,7 @@ __DATA__ --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.req.set_uri("/foo", true) end @@ -58,7 +58,7 @@ i am foo --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.req.set_uri("/foo", true) end @@ -93,7 +93,7 @@ i am foo --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.req.set_uri("/foo", true) end @@ -175,12 +175,12 @@ hello foo --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.req.set_uri("/foo", true) end - function g() + local function g() ngx.sleep(1) end @@ -267,7 +267,7 @@ hello foo location /lua { client_body_timeout 12000ms; rewrite_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.req.set_uri("/foo", true) end diff --git a/debian/modules/http-lua/t/098-uthread-wait.t b/debian/modules/http-lua/t/098-uthread-wait.t index 4948596..c2819ae 100644 --- a/debian/modules/http-lua/t/098-uthread-wait.t +++ b/debian/modules/http-lua/t/098-uthread-wait.t @@ -23,7 +23,7 @@ __DATA__ --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("hello in thread") return "done" end @@ -72,7 +72,7 @@ done --- config location /lua { content_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.say("hello in thread") return "done" @@ -120,13 +120,13 @@ done --- config location /lua { content_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.say("f: hello") return "done" end - function g() + local function g() ngx.sleep(0.2) ngx.say("g: hello") return "done" @@ -200,13 +200,13 @@ f: done --- config location /lua { content_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.say("f: hello") return "done" end - function g() + local function g() ngx.sleep(0.2) ngx.say("g: hello") return "done" @@ -228,7 +228,7 @@ f: done ngx.say("g thread created: ", coroutine.status(tg)) - ok, res = ngx.thread.wait(tf) + local ok, res = ngx.thread.wait(tf) if not ok then ngx.say("failed to wait f: ", res) return @@ -281,7 +281,7 @@ g: done --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("hello in thread") return "done", 3.14 end @@ -330,7 +330,7 @@ res: done 3.14 --- config location /lua { content_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.say("hello in thread") return "done", 3.14 @@ -378,7 +378,7 @@ res: done 3.14 --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("hello in thread") error("bad bad!") end @@ -427,7 +427,7 @@ qr/lua user thread aborted: runtime error: content_by_lua\(nginx\.conf:\d+\):4: --- config location /lua { content_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.say("hello in thread") error("bad bad!") @@ -477,12 +477,12 @@ qr/lua user thread aborted: runtime error: content_by_lua\(nginx\.conf:\d+\):5: --- config location /lua { content_by_lua ' - function g() + local function g() ngx.say("hello in thread") return "done" end - function f() + local function f() local t, err = ngx.thread.spawn(g) if not t then ngx.say("failed to spawn thread: ", err) @@ -533,13 +533,13 @@ done --- config location /lua { content_by_lua ' - function g() + local function g() ngx.sleep(0.1) ngx.say("hello in thread") return "done" end - function f() + local function f() local t, err = ngx.thread.spawn(g) if not t then ngx.say("failed to spawn thread: ", err) @@ -593,12 +593,12 @@ done -- local out = function (...) ngx.log(ngx.ERR, ...) end local out = ngx.say - function f() + local function f() out("f: hello") return "f done" end - function g() + local function g() out("g: hello") return "g done" end @@ -668,13 +668,13 @@ g status: zombie -- local out = function (...) ngx.log(ngx.ERR, ...) end local out = ngx.say - function f() + local function f() ngx.sleep(0.1) out("f: hello") return "f done" end - function g() + local function g() ngx.sleep(0.2) out("g: hello") return "g done" @@ -745,13 +745,13 @@ g: hello -- local out = function (...) ngx.log(ngx.ERR, ...) end local out = ngx.say - function f() + local function f() ngx.sleep(0.2) out("f: hello") return "f done" end - function g() + local function g() ngx.sleep(0.1) out("g: hello") return "g done" @@ -822,12 +822,12 @@ f: hello -- local out = function (...) ngx.log(ngx.ERR, ...) end local out = ngx.say - function f() + local function f() out("f: hello") error("f done") end - function g() + local function g() out("g: hello") error("g done") end @@ -896,13 +896,13 @@ qr/lua user thread aborted: runtime error: content_by_lua\(nginx\.conf:\d+\):7: -- local out = function (...) ngx.log(ngx.ERR, ...) end local out = ngx.say - function f() + local function f() ngx.sleep(0.1) out("f: hello") error("f done") end - function g() + local function g() ngx.sleep(0.2) out("g: hello") error("g done") @@ -969,13 +969,13 @@ qr/lua user thread aborted: runtime error: content_by_lua\(nginx\.conf:\d+\):8: --- config location /lua { content_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.say("f: hello") return "done" end - function g() + local function g() ngx.sleep(0.2) ngx.say("g: hello") return "done" @@ -997,7 +997,7 @@ qr/lua user thread aborted: runtime error: content_by_lua\(nginx\.conf:\d+\):8: ngx.say("g thread created: ", coroutine.status(tg)) - ok, res = ngx.thread.wait(tf, tg) + local ok, res = ngx.thread.wait(tf, tg) if not ok then ngx.say("failed to wait: ", res) return @@ -1038,13 +1038,13 @@ res: done --- config location /lua { content_by_lua ' - function f() + local function f() ngx.sleep(0.2) ngx.say("f: hello") return "f done" end - function g() + local function g() ngx.sleep(0.1) ngx.say("g: hello") return "g done" @@ -1066,7 +1066,7 @@ res: done ngx.say("g thread created: ", coroutine.status(tg)) - ok, res = ngx.thread.wait(tf, tg) + local ok, res = ngx.thread.wait(tf, tg) if not ok then ngx.say("failed to wait: ", res) return @@ -1109,12 +1109,12 @@ res: g done content_by_lua ' local t - function f() + local function f() ngx.sleep(0.1) return "done" end - function g() + local function g() t = ngx.thread.spawn(f) end @@ -1154,7 +1154,7 @@ only the parent coroutine can wait on the thread --- config location /lua { content_by_lua ' - function f() + local function f() ngx.sleep(0.1) coroutine.yield() return "done" @@ -1192,7 +1192,7 @@ qr/lua entry thread aborted: runtime error: content_by_lua\(nginx\.conf:\d+\):11 --- config location /lua { content_by_lua ' - function f() + local function f() ngx.sleep(0.1) collectgarbage() error("f done") @@ -1228,7 +1228,7 @@ qr/lua user thread aborted: runtime error: content_by_lua\(nginx\.conf:\d+\):5: --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("hello in thread") return "done" end @@ -1283,7 +1283,7 @@ failed to run thread: already waited or killed --- config location /lua { content_by_lua ' - function f() + local function f() -- ngx.say("hello in thread") return "done" end diff --git a/debian/modules/http-lua/t/099-c-api.t b/debian/modules/http-lua/t/099-c-api.t index a0b375c..5033462 100644 --- a/debian/modules/http-lua/t/099-c-api.t +++ b/debian/modules/http-lua/t/099-c-api.t @@ -86,7 +86,7 @@ dogs zone: defined local buf = ffi.new("char[?]", 4) ffi.copy(buf, "dogs", 4) - zone = ffi.C.ngx_http_lua_find_zone(buf, 4) + local zone = ffi.C.ngx_http_lua_find_zone(buf, 4) local val = ffi.new("ngx_http_lua_value_t[?]", 1) @@ -149,7 +149,7 @@ bar: rc=0, type=3, val=3.14159 local buf = ffi.new("char[?]", 4) ffi.copy(buf, "dogs", 4) - zone = ffi.C.ngx_http_lua_find_zone(buf, 4) + local zone = ffi.C.ngx_http_lua_find_zone(buf, 4) local val = ffi.new("ngx_http_lua_value_t[?]", 1) @@ -212,7 +212,7 @@ bar: rc=0, type=1, val=0 local buf = ffi.new("char[?]", 4) ffi.copy(buf, "dogs", 4) - zone = ffi.C.ngx_http_lua_find_zone(buf, 4) + local zone = ffi.C.ngx_http_lua_find_zone(buf, 4) local val = ffi.new("ngx_http_lua_value_t[?]", 1) @@ -272,7 +272,7 @@ bar: rc=-5 local buf = ffi.new("char[?]", 4) ffi.copy(buf, "dogs", 4) - zone = ffi.C.ngx_http_lua_find_zone(buf, 4) + local zone = ffi.C.ngx_http_lua_find_zone(buf, 4) local s = ffi.new("char[?]", 20) @@ -344,7 +344,7 @@ bar: rc=0, type=4, val=, len=0 local buf = ffi.new("char[?]", 4) ffi.copy(buf, "dogs", 4) - zone = ffi.C.ngx_http_lua_find_zone(buf, 4) + local zone = ffi.C.ngx_http_lua_find_zone(buf, 4) local val = ffi.new("ngx_http_lua_value_t[?]", 1) diff --git a/debian/modules/http-lua/t/100-client-abort.t b/debian/modules/http-lua/t/100-client-abort.t index 89c1f6a..f571387 100644 --- a/debian/modules/http-lua/t/100-client-abort.t +++ b/debian/modules/http-lua/t/100-client-abort.t @@ -195,7 +195,7 @@ bad things happen location = /sub { proxy_ignore_client_abort on; - proxy_pass http://agentzh.org:12345/; + proxy_pass http://127.0.0.2:12345/; } location = /sleep { @@ -236,7 +236,7 @@ client prematurely closed connection location = /sub { proxy_ignore_client_abort off; - proxy_pass http://agentzh.org:12345/; + proxy_pass http://127.0.0.2:12345/; } --- request GET /t @@ -540,7 +540,7 @@ client prematurely closed connection return end - ok, err = sock:connect("127.0.0.1", $TEST_NGINX_REDIS_PORT) + local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_REDIS_PORT) if not ok then ngx.log(ngx.ERR, "failed to connect: ", err) return diff --git a/debian/modules/http-lua/t/106-timer.t b/debian/modules/http-lua/t/106-timer.t index 3e4741e..7b7c85e 100644 --- a/debian/modules/http-lua/t/106-timer.t +++ b/debian/modules/http-lua/t/106-timer.t @@ -76,7 +76,7 @@ qr/\[lua\] content_by_lua\(nginx\.conf:\d+\):\d+: elapsed: 0\.0(?:4[4-9]|5[0-6]) -=== TEST 2: separated global env +=== TEST 2: globals are shared --- config location /t { content_by_lua ' @@ -104,7 +104,7 @@ F(ngx_http_lua_timer_handler) { --- response_body registered timer -foo = nil +foo = 3 --- wait: 0.1 --- no_error_log @@ -320,7 +320,7 @@ qr/received: Server: \S+/, === TEST 6: tcp cosocket in timer handler (keep-alive connections) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /t { @@ -596,7 +596,7 @@ qr/\[lua\] log_by_lua\(nginx\.conf:\d+\):\d+: elapsed: 0\.0(?:6[4-9]|7[0-6])/, === TEST 10: tcp cosocket in timer handler (keep-alive connections) - log_by_lua --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /t { @@ -693,7 +693,7 @@ qr/go\(\): connected: 1, reused: \d+/, === TEST 11: tcp cosocket in timer handler (keep-alive connections) - header_filter_by_lua --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /t { @@ -799,7 +799,7 @@ qr/go\(\): connected: 1, reused: \d+/, === TEST 12: tcp cosocket in timer handler (keep-alive connections) - body_filter_by_lua --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /t { @@ -912,7 +912,7 @@ qr/go\(\): connected: 1, reused: \d+/, === TEST 13: tcp cosocket in timer handler (keep-alive connections) - set_by_lua --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /t { @@ -1023,7 +1023,7 @@ qr/go\(\): connected: 1, reused: \d+/, content_by_lua ' local cc, cr, cy = coroutine.create, coroutine.resume, coroutine.yield local function f() - function f() + local function f() local cnt = 0 for i = 1, 20 do print("cnt = ", cnt) @@ -1090,7 +1090,7 @@ registered timer ngx.log(ngx.ERR, ...) end local function handle() - function f() + local function f() print("hello in thread") return "done" end diff --git a/debian/modules/http-lua/t/108-timer-safe.t b/debian/modules/http-lua/t/108-timer-safe.t index 2795998..758d01a 100644 --- a/debian/modules/http-lua/t/108-timer-safe.t +++ b/debian/modules/http-lua/t/108-timer-safe.t @@ -229,7 +229,7 @@ qr/received: Server: \S+/, === TEST 4: tcp cosocket in timer handler (keep-alive connections) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /t { @@ -489,7 +489,7 @@ delete thread 2 --- response_body hello world ---- wait: 0.1 +--- wait: 0.15 --- no_error_log [error] [alert] @@ -499,7 +499,7 @@ hello world [ "registered timer", qr/\[lua\] .*? my lua timer handler/, -qr/\[lua\] log_by_lua\(nginx\.conf:\d+\):\d+: elapsed: 0\.0(?:6[4-9]|7[0-6])/, +qr/\[lua\] log_by_lua\(nginx\.conf:\d+\):\d+: elapsed: 0\.0(?:6[4-9]|7[0-9]|8[0-6])/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -508,7 +508,7 @@ qr/\[lua\] log_by_lua\(nginx\.conf:\d+\):\d+: elapsed: 0\.0(?:6[4-9]|7[0-6])/, === TEST 8: tcp cosocket in timer handler (keep-alive connections) - log_by_lua --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /t { @@ -606,7 +606,7 @@ qr/go\(\): connected: 1, reused: \d+/, === TEST 9: tcp cosocket in timer handler (keep-alive connections) - header_filter_by_lua --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /t { @@ -713,7 +713,7 @@ qr/go\(\): connected: 1, reused: \d+/, === TEST 10: tcp cosocket in timer handler (keep-alive connections) - body_filter_by_lua --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /t { @@ -827,7 +827,7 @@ qr/go\(\): connected: 1, reused: \d+/, === TEST 11: tcp cosocket in timer handler (keep-alive connections) - set_by_lua --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /t { @@ -1007,7 +1007,7 @@ registered timer ngx.log(ngx.ERR, ...) end local function handle() - function f() + local function f() print("hello in thread") return "done" end diff --git a/debian/modules/http-lua/t/109-timer-hup.t b/debian/modules/http-lua/t/109-timer-hup.t index 0864046..2c197c2 100644 --- a/debian/modules/http-lua/t/109-timer-hup.t +++ b/debian/modules/http-lua/t/109-timer-hup.t @@ -46,7 +46,7 @@ __DATA__ --- config location /t { content_by_lua ' - local f, err = io.open("t/servroot/logs/nginx.pid", "r") + local f, err = io.open("$TEST_NGINX_SERVER_ROOT/logs/nginx.pid", "r") if not f then ngx.say("failed to open nginx.pid: ", err) return @@ -99,7 +99,7 @@ timer prematurely expired: true --- config location /t { content_by_lua ' - local f, err = io.open("t/servroot/logs/nginx.pid", "r") + local f, err = io.open("$TEST_NGINX_SERVER_ROOT/logs/nginx.pid", "r") if not f then ngx.say("failed to open nginx.pid: ", err) return @@ -163,7 +163,7 @@ timer prematurely expired: true --- config location /t { content_by_lua ' - local f, err = io.open("t/servroot/logs/nginx.pid", "r") + local f, err = io.open("$TEST_NGINX_SERVER_ROOT/logs/nginx.pid", "r") if not f then ngx.say("failed to open nginx.pid: ", err) return @@ -219,7 +219,7 @@ failed to register a new timer after reload: process exiting, context: ngx.timer --- config location /t { content_by_lua ' - local f, err = io.open("t/servroot/logs/nginx.pid", "r") + local f, err = io.open("$TEST_NGINX_SERVER_ROOT/logs/nginx.pid", "r") if not f then ngx.say("failed to open nginx.pid: ", err) return @@ -284,7 +284,7 @@ g: exiting=true --- config location /t { content_by_lua ' - local f, err = io.open("t/servroot/logs/nginx.pid", "r") + local f, err = io.open("$TEST_NGINX_SERVER_ROOT/logs/nginx.pid", "r") if not f then ngx.say("failed to open nginx.pid: ", err) return @@ -363,7 +363,7 @@ lua found 100 pending timers local line, err = sock:receive("*l") until not line or string.find(line, "^%s*$") - function foo() + local function foo() repeat -- Get and read chunk local line, err = sock:receive("*l") @@ -379,7 +379,7 @@ lua found 100 pending timers until len == 0 end - co = coroutine.create(foo) + local co = coroutine.create(foo) repeat local chunk = select(2,coroutine.resume(co)) until chunk == nil @@ -399,7 +399,7 @@ lua found 100 pending timers end local ok, err = ngx.timer.at(1, background_thread) - local f, err = io.open("t/servroot/logs/nginx.pid", "r") + local f, err = io.open("$TEST_NGINX_SERVER_ROOT/logs/nginx.pid", "r") if not f then ngx.say("failed to open nginx.pid: ", err) return @@ -453,7 +453,7 @@ lua found 1 pending timers end if kill then - local f, err = io.open("t/servroot/logs/nginx.pid", "r") + local f, err = io.open("$TEST_NGINX_SERVER_ROOT/logs/nginx.pid", "r") if not f then ngx.log(ngx.ERR, "failed to open nginx.pid: ", err) return diff --git a/debian/modules/http-lua/t/120-re-find.t b/debian/modules/http-lua/t/120-re-find.t index 73e6134..f80ca4f 100644 --- a/debian/modules/http-lua/t/120-re-find.t +++ b/debian/modules/http-lua/t/120-re-find.t @@ -622,7 +622,7 @@ matched: 你 >>> a.lua local re = [==[(?i:([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:=|<=>|r?like|sounds\s+like|regexp)([\s'\"`´’‘\(\)]*)?\2|([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp)([\s'\"`´’‘\(\)]*)?(?!\6)([\d\w]+))]==] -s = string.rep([[ABCDEFG]], 10) +local s = string.rep([[ABCDEFG]], 10) local start = ngx.now() @@ -664,7 +664,7 @@ error: pcre_exec() failed: -8 >>> a.lua local re = [==[(?i:([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:=|<=>|r?like|sounds\s+like|regexp)([\s'\"`´’‘\(\)]*)?\2|([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp)([\s'\"`´’‘\(\)]*)?(?!\6)([\d\w]+))]==] -s = string.rep([[ABCDEFG]], 10) +local s = string.rep([[ABCDEFG]], 10) local start = ngx.now() diff --git a/debian/modules/http-lua/t/123-lua-path.t b/debian/modules/http-lua/t/123-lua-path.t index 23681a9..e30132f 100644 --- a/debian/modules/http-lua/t/123-lua-path.t +++ b/debian/modules/http-lua/t/123-lua-path.t @@ -11,7 +11,7 @@ repeat_each(2); plan tests => repeat_each() * (blocks() * 3 + 1); -$ENV{LUA_PATH} = "/foo/bar/baz"; +$ENV{LUA_PATH} = "../lua-resty-core/lib/?.lua;../lua-resty-lrucache/lib/?.lua;/foo/bar/baz"; $ENV{LUA_CPATH} = "/baz/bar/foo"; #no_diff(); #no_long_string(); @@ -36,8 +36,8 @@ env LUA_CPATH; } --- request GET /lua ---- response_body -/foo/bar/baz +--- response_body_like +(?:\.\.\/lua-resty-core\/lib\/\?\.lua;\.\.\/lua-resty-lrucache\/lib\/\?\.lua;){1,2}\/foo\/bar\/baz /baz/bar/foo --- no_error_log @@ -60,8 +60,8 @@ env LUA_CPATH; } --- request GET /lua ---- response_body -/foo/bar/baz +--- response_body_like +(?:\.\.\/lua-resty-core\/lib\/\?\.lua;\.\.\/lua-resty-lrucache\/lib\/\?\.lua;){1,2}\/foo\/bar\/baz /baz/bar/foo --- no_error_log diff --git a/debian/modules/http-lua/t/124-init-worker.t b/debian/modules/http-lua/t/124-init-worker.t index 9b2a91f..b648d55 100644 --- a/debian/modules/http-lua/t/124-init-worker.t +++ b/debian/modules/http-lua/t/124-init-worker.t @@ -521,12 +521,11 @@ warn(): Thu, 01 Jan 1970 01:34:38 GMT } --- request GET /t ---- response_body -timer created +--- response_body_like connected: 1 request sent: 56 -first line received: HTTP/1.1 200 OK -second line received: Server: openresty +first line received: HTTP\/1\.1 200 OK +second line received: (?:Date|Server): .*? --- no_error_log [error] --- timeout: 10 @@ -550,6 +549,7 @@ second line received: Server: openresty else say("connect: ", ok, " ", err) end + done = true end local ok, err = ngx.timer.at(0, handler) @@ -600,6 +600,7 @@ qr/connect\(\) failed \(\d+: Connection refused\), context: ngx\.timer$/ else say("connect: ", ok, " ", err) end + done = true end local ok, err = ngx.timer.at(0, handler) @@ -650,6 +651,7 @@ qr/connect\(\) failed \(\d+: Connection refused\)/ else say("connect: ", ok, " ", err) end + done = true end local ok, err = ngx.timer.at(0, handler) diff --git a/debian/modules/http-lua/t/126-shdict-frag.t b/debian/modules/http-lua/t/126-shdict-frag.t index 5a2aff8..33646d1 100644 --- a/debian/modules/http-lua/t/126-shdict-frag.t +++ b/debian/modules/http-lua/t/126-shdict-frag.t @@ -1240,8 +1240,8 @@ failed to safe set baz: no memory local key = "mylittlekey" .. rand(maxkeyidx) local ok, err = dogs:get(key) if not ok or rand() > 0.6 then - sz = rand(maxsz) - val = rep("a", sz) + local sz = rand(maxsz) + local val = rep("a", sz) local ok, err, forcible = dogs:set(key, val) if err then ngx.log(ngx.ERR, "failed to set key: ", err) diff --git a/debian/modules/http-lua/t/127-uthread-kill.t b/debian/modules/http-lua/t/127-uthread-kill.t index cc43c62..5542153 100644 --- a/debian/modules/http-lua/t/127-uthread-kill.t +++ b/debian/modules/http-lua/t/127-uthread-kill.t @@ -23,7 +23,7 @@ __DATA__ --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("hello from f()") ngx.sleep(1) end @@ -81,7 +81,7 @@ lua clean up the timer for pending ngx.sleep --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("hello from f()") ngx.sleep(0.001) return 32 @@ -138,12 +138,12 @@ lua clean up the timer for pending ngx.sleep === TEST 3: kill pending resolver --- config - resolver agentzh.org:12345; + resolver 127.0.0.2:12345; location /lua { content_by_lua ' - function f() + local function f() local sock = ngx.socket.tcp() - sock:connect("some.agentzh.org", 12345) + sock:connect("some.127.0.0.2", 12345) end local t, err = ngx.thread.spawn(f) @@ -194,13 +194,13 @@ resolve name done: -2 location /lua { content_by_lua ' local ready = false - function f() + local function f() local sock = ngx.socket.tcp() sock:connect("agentzh.org", 80) sock:close() ready = true sock:settimeout(10000) - sock:connect("agentzh.org", 12345) + sock:connect("127.0.0.2", 12345) end local t, err = ngx.thread.spawn(f) @@ -262,7 +262,7 @@ lua finalize socket location = /t { content_by_lua ' - function f() + local function f() ngx.location.capture("/sub") end @@ -309,11 +309,11 @@ lua tcp socket abort resolver location = /t { content_by_lua ' - function f() + local function f() ngx.location.capture("/sub") end - function g() + local function g() ngx.sleep(0.3) end @@ -376,7 +376,7 @@ lua tcp socket abort resolver location = /t { content_by_lua ' local ready = false - function f() + local function f() ngx.location.capture("/sub") ready = true ngx.sleep(0.5) @@ -424,7 +424,7 @@ lua tcp socket abort resolver --- config location = /t { content_by_lua ' - function f() + local function f() return end @@ -473,7 +473,7 @@ lua tcp socket abort resolver ngx.say("killed main thread.") end - function f() + local function f() local ok, err = ngx.thread.kill(coroutine.running()) if not ok then ngx.say("failed to kill user thread: ", err) diff --git a/debian/modules/http-lua/t/128-duplex-tcp-socket.t b/debian/modules/http-lua/t/128-duplex-tcp-socket.t index aed560c..22b9f03 100644 --- a/debian/modules/http-lua/t/128-duplex-tcp-socket.t +++ b/debian/modules/http-lua/t/128-duplex-tcp-socket.t @@ -396,7 +396,7 @@ F(ngx_http_lua_socket_tcp_finalize_write_part) { end sock:settimeout(300) - local ok, err = sock:connect("172.105.207.225", 12345) + local ok, err = sock:connect("127.0.0.2", 12345) ngx.say("connect: ", ok, " ", err) local ok, err = sock:close() @@ -425,7 +425,7 @@ close: nil closed --- config server_tokens off; lua_socket_log_errors off; - resolver agentzh.org:12345; + resolver 127.0.0.2:12345; resolver_timeout 300ms; location /t { content_by_lua ' @@ -459,7 +459,7 @@ close: nil closed end sock:settimeout(300) - local ok, err = sock:connect("some2.agentzh.org", 12345) + local ok, err = sock:connect("some2.agentzh.org", 80) ngx.say("connect: ", ok, " ", err) local ok, err = sock:close() diff --git a/debian/modules/http-lua/t/129-ssl-socket.t b/debian/modules/http-lua/t/129-ssl-socket.t index 3f05640..f2fa26b 100644 --- a/debian/modules/http-lua/t/129-ssl-socket.t +++ b/debian/modules/http-lua/t/129-ssl-socket.t @@ -301,7 +301,7 @@ SSL reused session content_by_lua ' local sock = ngx.socket.tcp() - sock:settimeout(2000) + sock:settimeout(7000) do @@ -380,7 +380,7 @@ lua ssl free session --- no_error_log [error] [alert] ---- timeout: 5 +--- timeout: 10 @@ -573,7 +573,7 @@ SSL reused session ngx.say("ssl handshake: ", type(session)) - local req = "GET / HTTP/1.1\\r\\nHost: agentzh.org\\r\\nConnection: close\\r\\n\\r\\n" + local req = "GET /en/linux-packages.html HTTP/1.1\\r\\nHost: openresty.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) @@ -602,7 +602,7 @@ GET /t --- response_body connected: 1 ssl handshake: userdata -sent http request: 56 bytes. +sent http request: 80 bytes. received: HTTP/1.1 404 Not Found close: 1 nil @@ -1333,13 +1333,13 @@ failed to send http request: closed --- grep_error_log_out --- error_log eval [ -qr/\[crit\] .*?SSL_do_handshake\(\) failed .*?(unsupported protocol|no protocols available)/, +qr/\[(crit|error)\] .*?SSL_do_handshake\(\) failed .*?(unsupported protocol|no protocols available)/, 'lua ssl server name: "openresty.org"', ] --- no_error_log SSL reused session -[error] [alert] +[emerg] --- timeout: 5 @@ -2508,7 +2508,7 @@ SSL reused session content_by_lua_block { local sock = ngx.socket.tcp() - sock:settimeout(2000) + sock:settimeout(7000) local ok, err = sock:connect("openresty.org", 443) if not ok then @@ -2529,4 +2529,4 @@ GET /t qr/\[error\] .* ngx.socket sslhandshake: expecting 1 ~ 5 arguments \(including the object\), but seen 0/ --- no_error_log [alert] ---- timeout: 5 +--- timeout: 10 diff --git a/debian/modules/http-lua/t/130-internal-api.t b/debian/modules/http-lua/t/130-internal-api.t index eba0980..2158e87 100644 --- a/debian/modules/http-lua/t/130-internal-api.t +++ b/debian/modules/http-lua/t/130-internal-api.t @@ -8,7 +8,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * 3; +plan tests => repeat_each() * blocks() * 3; #no_diff(); no_long_string(); @@ -19,12 +19,7 @@ run_tests(); __DATA__ -=== TEST 1: __ngx_req and __ngx_cycle ---- http_config - init_by_lua ' - my_cycle = __ngx_cycle - '; - +=== TEST 1: req --- config location = /t { content_by_lua ' @@ -32,18 +27,14 @@ __DATA__ local function tonum(ud) return tonumber(ffi.cast("uintptr_t", ud)) end - ngx.say(string.format("init: cycle=%#x", tonum(my_cycle))) - ngx.say(string.format("content cycle=%#x", tonum(__ngx_cycle))) - ngx.say(string.format("content req=%#x", tonum(__ngx_req))) + ngx.say(string.format("content req=%#x", tonum(exdata()))) '; } --- request GET /t --- response_body_like chop -^init: cycle=(0x[a-f0-9]{4,}) -content cycle=\1 -content req=0x[a-f0-9]{4,} +^content req=0x[a-f0-9]{4,} $ --- no_error_log [error] diff --git a/debian/modules/http-lua/t/134-worker-count-5.t b/debian/modules/http-lua/t/134-worker-count-5.t index b257c12..ec6d0e7 100644 --- a/debian/modules/http-lua/t/134-worker-count-5.t +++ b/debian/modules/http-lua/t/134-worker-count-5.t @@ -3,7 +3,7 @@ use Test::Nginx::Socket::Lua; #worker_connections(1014); -#master_on(); +master_on(); workers(5); #log_level('warn'); @@ -55,7 +55,7 @@ workers: 5 === TEST 3: init_by_lua + module (github #681) --- http_config - lua_package_path "t/servroot/html/?.lua;;"; + lua_package_path "$TEST_NGINX_SERVER_ROOT/html/?.lua;;"; init_by_lua_block { local blah = require "file" diff --git a/debian/modules/http-lua/t/138-balancer.t b/debian/modules/http-lua/t/138-balancer.t index 0aba66d..151db7b 100644 --- a/debian/modules/http-lua/t/138-balancer.t +++ b/debian/modules/http-lua/t/138-balancer.t @@ -362,8 +362,6 @@ me: 101 === TEST 13: lua subrequests --- http_config - lua_package_path "t/servroot/html/?.lua;;"; - lua_code_cache off; upstream backend { diff --git a/debian/modules/http-lua/t/139-ssl-cert-by.t b/debian/modules/http-lua/t/139-ssl-cert-by.t index a65d703..bebbdb2 100644 --- a/debian/modules/http-lua/t/139-ssl-cert-by.t +++ b/debian/modules/http-lua/t/139-ssl-cert-by.t @@ -1278,7 +1278,7 @@ lua ssl server name: "test.com" listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_certificate_by_lua_block { - function f() + local function f() ngx.sleep(0.01) print("uthread: hello in thread") return "done" diff --git a/debian/modules/http-lua/t/140-ssl-c-api.t b/debian/modules/http-lua/t/140-ssl-c-api.t index 8734d14..a77f5d4 100644 --- a/debian/modules/http-lua/t/140-ssl-c-api.t +++ b/debian/modules/http-lua/t/140-ssl-c-api.t @@ -10,6 +10,7 @@ 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"); + } else { plan tests => repeat_each() * (blocks() * 5 + 1); } @@ -68,7 +69,7 @@ _EOC_ my $http_config = $block->http_config || ''; $http_config .= <<'_EOC_'; -lua_package_path "$prefix/html/?.lua;;"; +lua_package_path "$prefix/html/?.lua;../lua-resty-core/lib/?.lua;;"; _EOC_ $block->set_value("http_config", $http_config); }); @@ -91,8 +92,8 @@ __DATA__ local errmsg = ffi.new("char *[1]") - local r = getfenv(0).__ngx_req - if not r then + local r = require "resty.core.base" .get_request() + if r == nil then ngx.log(ngx.ERR, "no request found") return end @@ -245,8 +246,8 @@ lua ssl server name: "test.com" local errmsg = ffi.new("char *[1]") - local r = getfenv(0).__ngx_req - if not r then + local r = require "resty.core.base" .get_request() + if r == nil then ngx.log(ngx.ERR, "no request found") return end @@ -399,8 +400,8 @@ lua ssl server name: "test.com" local errmsg = ffi.new("char *[1]") - local r = getfenv(0).__ngx_req - if not r then + local r = require "resty.core.base" .get_request() + if r == nil then ngx.log(ngx.ERR, "no request found") return end @@ -528,8 +529,8 @@ failed to parse PEM priv key: PEM_read_bio_PrivateKey() failed local errmsg = ffi.new("char *[1]") - local r = getfenv(0).__ngx_req - if not r then + local r = require "resty.core.base" .get_request() + if r == nil then ngx.log(ngx.ERR, "no request found") return end @@ -678,8 +679,8 @@ lua ssl server name: "test.com" local errmsg = ffi.new("char *[1]") - local r = getfenv(0).__ngx_req - if not r then + local r = require "resty.core.base" .get_request() + if r == nil then ngx.log(ngx.ERR, "no request found") return end diff --git a/debian/modules/http-lua/t/143-ssl-session-fetch.t b/debian/modules/http-lua/t/143-ssl-session-fetch.t index 4dc992d..78a66cf 100644 --- a/debian/modules/http-lua/t/143-ssl-session-fetch.t +++ b/debian/modules/http-lua/t/143-ssl-session-fetch.t @@ -1114,3 +1114,108 @@ qr/ssl_session_fetch_by_lua_block:1: ssl fetch sess by lua is running!/s [error] [alert] [emerg] + + + +=== TEST 14: keep global variable in ssl_session_(store|fetch)_by_lua when OpenResty LuaJIT is used +--- http_config + ssl_session_store_by_lua_block { + ngx.log(ngx.WARN, "new foo: ", foo) + if not foo then + foo = 1 + else + ngx.log(ngx.WARN, "old foo: ", foo) + foo = foo + 1 + end + } + ssl_session_fetch_by_lua_block { + ngx.log(ngx.WARN, "new bar: ", foo) + if not bar then + bar = 1 + else + ngx.log(ngx.WARN, "old bar: ", bar) + bar = bar + 1 + end + } + + 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_session_tickets off; + + server_tokens off; + location /foo { + content_by_lua_block { + ngx.say("foo: ", foo) + ngx.say("bar: ", bar) + } + } + } +--- 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 + + 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 + + package.loaded.session = 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 + + while true do + local line, err = sock:receive() + if not line then + -- ngx.say("failed to receive response status line: ", err) + break + end + + local m, err = ngx.re.match(line, "^foo: (.*)$", "jo") + if err then + ngx.say("failed to match line: ", err) + end + + if m and m[1] then + ngx.print(m[1]) + end + end + + local ok, err = sock:close() + ngx.say("done") + end -- do + } + } + +--- request +GET /t +--- response_body_like chomp +\A[123]done\n\z +--- grep_error_log eval: qr/old (foo|bar): \d+/ +--- grep_error_log_out eval +["", "old foo: 1\n", "old bar: 1\nold foo: 2\n"] +--- no_error_log +[error] +[alert] +[emerg] diff --git a/debian/modules/http-lua/t/147-tcp-socket-timeouts.t b/debian/modules/http-lua/t/147-tcp-socket-timeouts.t index 4ebc8f3..8566c0b 100644 --- a/debian/modules/http-lua/t/147-tcp-socket-timeouts.t +++ b/debian/modules/http-lua/t/147-tcp-socket-timeouts.t @@ -323,7 +323,7 @@ lua tcp socket write timed out sock:settimeouts(100, 100, 100) - local ok, err = sock:connect("agentzh.org", 12345) + local ok, err = sock:connect("127.0.0.2", 12345) ngx.say("connect: ", ok, " ", err) local bytes @@ -346,7 +346,7 @@ send: nil closed receive: nil closed close: nil closed --- error_log -lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 +lua tcp socket connect timed out, when connecting to 127.0.0.2:12345 --- timeout: 10 @@ -411,7 +411,7 @@ lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 local chunk = 4 - function read() + local function read() sock:settimeout(200) -- read: 200 ms local data, err = sock:receive(content_length) @@ -506,7 +506,7 @@ failed to receive data: timeout local chunk = 4 - function read() + local function read() local data, err = sock:receive(content_length) if not data then ngx.log(ngx.ERR, "failed to receive data: ", err) diff --git a/debian/modules/http-lua/t/152-timer-every.t b/debian/modules/http-lua/t/152-timer-every.t index c8d62e7..7b42d2d 100644 --- a/debian/modules/http-lua/t/152-timer-every.t +++ b/debian/modules/http-lua/t/152-timer-every.t @@ -63,7 +63,7 @@ qr/\[lua\] content_by_lua\(nginx\.conf:\d+\):\d+: elapsed: 0\.(?:09|10)\d*, cont -=== TEST 2: separated global env +=== TEST 2: shared global env --- config location /t { content_by_lua_block { @@ -84,7 +84,7 @@ qr/\[lua\] content_by_lua\(nginx\.conf:\d+\):\d+: elapsed: 0\.(?:09|10)\d*, cont --- request GET /t --- response_body -foo = nil +foo = 3 --- wait: 0.12 --- no_error_log [error] diff --git a/debian/modules/http-lua/t/153-semaphore-hup.t b/debian/modules/http-lua/t/153-semaphore-hup.t index c85a21d..5c271a4 100644 --- a/debian/modules/http-lua/t/153-semaphore-hup.t +++ b/debian/modules/http-lua/t/153-semaphore-hup.t @@ -67,7 +67,7 @@ add_block_preprocessor(sub { return end - shdict = ngx.shared.shdict + local shdict = ngx.shared.shdict local success = shdict:add("reloaded", 1) if not success then return diff --git a/debian/modules/http-lua/t/156-slow-network.t b/debian/modules/http-lua/t/156-slow-network.t new file mode 100644 index 0000000..2d80506 --- /dev/null +++ b/debian/modules/http-lua/t/156-slow-network.t @@ -0,0 +1,138 @@ +BEGIN { + if (!defined $ENV{LD_PRELOAD}) { + $ENV{LD_PRELOAD} = ''; + } + + if ($ENV{LD_PRELOAD} !~ /\bmockeagain\.so\b/) { + $ENV{LD_PRELOAD} = "mockeagain.so $ENV{LD_PRELOAD}"; + } + + if ($ENV{MOCKEAGAIN} eq 'r') { + $ENV{MOCKEAGAIN} = 'rw'; + + } else { + $ENV{MOCKEAGAIN} = 'w'; + } + + $ENV{TEST_NGINX_EVENT_TYPE} = 'poll'; +} + +use Test::Nginx::Socket::Lua; + +repeat_each(2); + +plan tests => repeat_each() * (blocks() * 4); + +add_block_preprocessor(sub { + my $block = shift; + + if (!defined $block->error_log) { + $block->set_value("no_error_log", "[error]"); + } + + if (!defined $block->request) { + $block->set_value("request", "GET /t"); + } + +}); + + +log_level("debug"); +no_long_string(); +#no_diff(); +run_tests(); + +__DATA__ + +=== TEST 1: receiveany returns anything once socket receives +--- config + server_tokens off; + location = /t { + set $port $TEST_NGINX_SERVER_PORT; + content_by_lua_block { + local sock = ngx.socket.tcp() + sock:settimeout(500) + assert(sock:connect("127.0.0.1", ngx.var.port)) + local req = { + 'GET /foo HTTP/1.0\r\n', + 'Host: localhost\r\n', + 'Connection: close\r\n\r\n', + } + local ok, err = sock:send(req) + if not ok then + ngx.say("send request failed: ", err) + return + end + + + -- skip http header + while true do + local data, err, _ = sock:receive('*l') + if err then + ngx.say('unexpected error occurs when receiving http head: ' .. err) + return + end + if #data == 0 then -- read last line of head + break + end + end + + -- receive http body + while true do + local data, err = sock:receiveany(1024) + if err then + if err ~= 'closed' then + ngx.say('unexpected err: ', err) + end + break + end + ngx.say(data) + end + + sock:close() + } + } + + location = /foo { + content_by_lua_block { + local resp = { + '1', + 'hello', + } + + local length = 0 + for _, v in ipairs(resp) do + length = length + #v + end + + -- flush http header + ngx.header['Content-Length'] = length + ngx.flush(true) + ngx.sleep(0.01) + + -- send http body bytes by bytes + for _, v in ipairs(resp) do + ngx.print(v) + ngx.flush(true) + ngx.sleep(0.01) + end + } + } + +--- response_body +1 +h +e +l +l +o +--- grep_error_log eval +qr/lua tcp socket read any/ +--- grep_error_log_out +lua tcp socket read any +lua tcp socket read any +lua tcp socket read any +lua tcp socket read any +lua tcp socket read any +lua tcp socket read any +lua tcp socket read any diff --git a/debian/modules/http-lua/t/157-socket-keepalive-hup.t b/debian/modules/http-lua/t/157-socket-keepalive-hup.t new file mode 100644 index 0000000..357bb59 --- /dev/null +++ b/debian/modules/http-lua/t/157-socket-keepalive-hup.t @@ -0,0 +1,91 @@ +# 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 $SkipReason ? (skip_all => $SkipReason) : (); + +repeat_each(2); + +plan tests => repeat_each() * (blocks() * 8); + +#no_diff(); +no_long_string(); + +worker_connections(1024); +run_tests(); + +__DATA__ + +=== TEST 1: exiting +--- config + location /t { + set $port $TEST_NGINX_SERVER_PORT; + + content_by_lua_block { + local f, err = io.open("$TEST_NGINX_SERVER_ROOT/logs/nginx.pid", "r") + if not f then + ngx.say("failed to open nginx.pid: ", err) + return + end + + local pid = f:read() + -- ngx.say("master pid: [", pid, "]") + + f:close() + + local i = 0 + local port = ngx.var.port + + local function f(premature) + print("timer prematurely expired: ", premature) + + local sock = ngx.socket.tcp() + + local ok, err = sock:connect("127.0.0.1", port) + if not ok then + print("failed to connect: ", err) + return + end + + local ok, err = sock:setkeepalive() + if not ok then + print("failed to setkeepalive: ", err) + return + end + + print("setkeepalive successfully") + end + local ok, err = ngx.timer.at(3, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + os.execute("kill -HUP " .. pid) + } + } +--- request +GET /t + +--- response_body +registered timer + +--- wait: 0.3 +--- no_error_log +[error] +[alert] +[crit] +--- error_log +timer prematurely expired: true +setkeepalive successfully +lua tcp socket set keepalive while process exiting, closing connection diff --git a/debian/modules/http-lua/t/158-global-var.t b/debian/modules/http-lua/t/158-global-var.t new file mode 100644 index 0000000..414a43a --- /dev/null +++ b/debian/modules/http-lua/t/158-global-var.t @@ -0,0 +1,508 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use Test::Nginx::Socket::Lua; + +log_level('debug'); + +repeat_each(2); + +plan tests => repeat_each() * (blocks() * 3 + 14); + +our $HtmlDir = html_dir; + +$ENV{TEST_NGINX_HTML_DIR} ||= html_dir(); + +no_long_string(); + +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 $TestCertificate = read_file("t/cert/test.crt"); +our $TestCertificateKey = read_file("t/cert/test.key"); + +add_block_preprocessor(sub { + my $block = shift; + + if (!defined $block->error_log) { + $block->set_value("no_error_log", "[error]"); + } + + if (!defined $block->request) { + $block->set_value("request", "GET /t"); + } + +}); + +run_tests(); + +__DATA__ + +=== TEST 1: set_by_lua +--- config + location /t { + set_by_lua_block $res { + if not foo then + foo = 1 + else + ngx.log(ngx.WARN, "old foo: ", foo) + foo = foo + 1 + end + return foo + } + echo $res; + } +--- 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, )/ +--- 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"] + + + +=== TEST 2: rewrite_by_lua +--- config + location /t { + rewrite_by_lua_block { + if not foo then + foo = 1 + else + ngx.log(ngx.WARN, "old foo: ", foo) + foo = foo + 1 + end + ngx.say(foo) + } + } +--- response_body_like chomp +\A[12]\n\z +--- grep_error_log eval +qr/(old foo: \d+|\[\w+\].*?writing a global lua variable \('[^'\s]+'\)|\w+_by_lua\(.*?\):\d+: in main chunk, )/ +--- grep_error_log_out eval +[qr/\A\[warn\] .*?writing a global lua variable \('foo'\) +rewrite_by_lua\(nginx\.conf:48\):3: in main chunk, \n\z/, "old foo: 1\n"] + + + +=== TEST 3: access_by_lua +--- config + location /t { + access_by_lua_block { + if not foo then + foo = 1 + else + ngx.log(ngx.WARN, "old foo: ", foo) + foo = foo + 1 + end + ngx.say(foo) + } + } +--- response_body_like chomp +\A[12]\n\z +--- grep_error_log eval +qr/(old foo: \d+|\[\w+\].*?writing a global lua variable \('[^'\s]+'\)|\w+_by_lua\(.*?\):\d+: in main chunk, )/ +--- grep_error_log_out eval +[qr/\A\[warn\] .*?writing a global lua variable \('foo'\) +access_by_lua\(nginx\.conf:48\):3: in main chunk, \n\z/, "old foo: 1\n"] + + + +=== TEST 4: content_by_lua +--- config + location /t { + content_by_lua_block { + if not foo then + foo = 1 + else + ngx.log(ngx.WARN, "old foo: ", foo) + foo = foo + 1 + end + ngx.say(foo) + } + } +--- response_body_like chomp +\A[12]\n\z +--- grep_error_log eval +qr/(old foo: \d+|\[\w+\].*?writing a global lua variable \('[^'\s]+'\)|\w+_by_lua\(.*?\):\d+: in main chunk, )/ +--- grep_error_log_out eval +[qr/\A\[warn\] .*?writing a global lua variable \('foo'\) +content_by_lua\(nginx\.conf:48\):3: in main chunk, \n\z/, "old foo: 1\n"] + + + +=== TEST 5: header_filter_by_lua +--- config + location /t { + content_by_lua_block { + ngx.say(foo) + } + header_filter_by_lua_block { + if not foo then + foo = 1 + else + ngx.log(ngx.WARN, "old foo: ", foo) + foo = foo + 1 + end + } + } +--- 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, )/ +--- 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"] + + + +=== TEST 6: body_filter_by_lua +--- config + location /t { + content_by_lua_block { + ngx.say(foo) + } + body_filter_by_lua_block { + if not foo then + foo = 1 + else + ngx.log(ngx.WARN, "old foo: ", foo) + foo = foo + 1 + end + } + } +--- 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, )/ +--- grep_error_log_out eval +[qr/\[warn\] .*?writing a global lua variable \('foo'\) +body_filter_by_lua:3: in main chunk, +old foo: 1\n\z/, "old foo: 2\nold foo: 3\n"] + + + +=== TEST 7: log_by_lua +--- config + location /t { + content_by_lua_block { + ngx.say(foo) + } + log_by_lua_block { + if not foo then + foo = 1 + else + ngx.log(ngx.WARN, "old foo: ", foo) + foo = foo + 1 + end + } + } +--- 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)/ +--- grep_error_log_out eval +[qr/\A\[warn\] .*?writing a global lua variable \('foo'\) +log_by_lua\(nginx\.conf:50\):3: in main chunk\n\z/, "old foo: 1\n"] + + + +=== TEST 8: ssl_certificate_by_lua +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + ssl_certificate_by_lua_block { + if not foo then + foo = 1 + else + ngx.log(ngx.WARN, "old foo: ", foo) + foo = foo + 1 + end + } + ssl_certificate ../../cert/test.crt; + ssl_certificate_key ../../cert/test.key; + + server_tokens off; + location /foo { + content_by_lua_block { + ngx.say("foo: ", foo) + } + } + } +--- 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 + + local m, err = ngx.re.match(line, "^foo: (.*)$", "jo") + if err then + ngx.say("failed to match line: ", err) + end + + if m and m[1] then + ngx.print(m[1]) + end + end + + local ok, err = sock:close() + ngx.say("done") + end -- do + } + } + +--- 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)/ +--- 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"] + + + +=== TEST 9: timer +--- config + location /t { + content_by_lua_block { + local function f() + if not foo then + foo = 1 + else + ngx.log(ngx.WARN, "old foo: ", foo) + foo = foo + 1 + end + end + local ok, err = ngx.timer.at(0, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.sleep(0.01) + ngx.say(foo) + } + } +--- response_body_like chomp +\A[12]\n\z +--- grep_error_log eval +qr/(old foo: \d+|\[\w+\].*?writing a global lua variable \('[^'\s]+'\)|\w+_by_lua\(.*?\):\d+: in\b)/ +--- grep_error_log_out eval +[qr/\A\[warn\] .*?writing a global lua variable \('foo'\) +content_by_lua\(nginx\.conf:56\):4: in\n\z/, "old foo: 1\n"] + + + +=== TEST 10: init_by_lua +--- http_config + init_by_lua_block { + foo = 1 + } +--- config + location /t { + content_by_lua_block { + if not foo then + foo = 1 + else + ngx.log(ngx.WARN, "old foo: ", foo) + foo = foo + 1 + end + ngx.say(foo) + } + } +--- response_body_like chomp +\A[23]\n\z +--- grep_error_log eval: qr/old foo: \d+/ +--- grep_error_log_out eval +["old foo: 1\n", "old foo: 2\n"] + + + +=== TEST 11: init_worker_by_lua +--- http_config + init_worker_by_lua_block { + if not foo then + foo = 1 + else + ngx.log(ngx.WARN, "old foo: ", foo) + foo = foo + 1 + end + } +--- config + location /t { + content_by_lua_block { + if not foo then + foo = 1 + else + ngx.log(ngx.WARN, "old foo: ", foo) + foo = foo + 1 + end + ngx.say(foo) + } + } +--- response_body_like chomp +\A[23]\n\z +--- grep_error_log eval: qr/old foo: \d+/ +--- grep_error_log_out eval +["old foo: 1\n", "old foo: 2\n"] + + + +=== TEST 12: init_by_lua + init_worker_by_lua +--- http_config + init_by_lua_block { + if not foo then + foo = 1 + else + ngx.log(ngx.WARN, "old foo: ", foo) + foo = foo + 1 + end + } + init_worker_by_lua_block { + if not foo then + foo = 1 + else + ngx.log(ngx.WARN, "old foo: ", foo) + foo = foo + 1 + end + } +--- config + location /t { + content_by_lua_block { + if not foo then + foo = 1 + else + ngx.log(ngx.WARN, "old foo: ", foo) + foo = foo + 1 + end + ngx.say(foo) + } + } +--- response_body_like chomp +\A[34]\n\z +--- grep_error_log eval: qr/old foo: \d+/ +--- grep_error_log_out eval +["old foo: 1\nold foo: 2\n", "old foo: 3\n"] + + + +=== TEST 13: don't show warn messages in init/init_worker +--- http_config + init_by_lua_block { + foo = 1 + } + + init_worker_by_lua_block { + bar = 2 + } +--- config + location /t { + content_by_lua_block { + ngx.say(foo) + ngx.say(bar) + } + } +--- response_body +1 +2 +--- no_error_log +setting global variable + + + +=== TEST 14: uthread +--- config + location /t { + content_by_lua_block { + local function f() + if not foo then + foo = 1 + else + ngx.log(ngx.WARN, "old foo: ", foo) + foo = foo + 1 + end + end + local ok, err = ngx.thread.spawn(f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.sleep(0.01) + ngx.say(foo) + } + } +--- response_body_like chomp +\A[12]\n\z +--- grep_error_log eval +qr/(old foo: \d+|writing a global lua variable \('\w+'\))/ +--- grep_error_log_out eval +["writing a global lua variable \('foo'\)\n", "old foo: 1\n"] + + + +=== TEST 15: balancer_by_lua +--- http_config + upstream backend { + server 0.0.0.1; + balancer_by_lua_block { + if not foo then + foo = 1 + else + ngx.log(ngx.WARN, "old foo: ", foo) + foo = foo + 1 + end + } + } +--- config + location = /t { + proxy_pass http://backend; + } +--- response_body_like: 502 Bad Gateway +--- error_code: 502 +--- error_log eval +qr/\[crit\].*?\Qconnect() to 0.0.0.1:80 failed\E/ +--- grep_error_log eval: qr/(old foo: \d+|writing a global lua variable \('\w+'\))/ +--- grep_error_log_out eval +["writing a global lua variable \('foo'\)\n", "old foo: 1\n"] diff --git a/debian/modules/http-lua/t/159-sa-restart.t b/debian/modules/http-lua/t/159-sa-restart.t new file mode 100644 index 0000000..a0f0c0e --- /dev/null +++ b/debian/modules/http-lua/t/159-sa-restart.t @@ -0,0 +1,180 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use Test::Nginx::Socket::Lua; + +add_block_preprocessor(sub { + my $block = shift; + + my $http_config = $block->http_config || ''; + + $http_config .= <<_EOC_; + init_by_lua_block { + function test_sa_restart() + local signals = { + --"HUP", + --"INFO", + --"XCPU", + --"USR1", + --"USR2", + "ALRM", + --"INT", + "IO", + "CHLD", + --"WINCH", + } + + for _, signame in ipairs(signals) do + local cmd = string.format("kill -s %s %d && sleep 0.01", + signame, ngx.worker.pid()) + local err = select(2, io.popen(cmd):read("*a")) + if err then + error("SIG" .. signame .. " caused: " .. err) + end + end + end + } +_EOC_ + + $block->set_value("http_config", $http_config); + + if (!defined $block->config) { + my $config = <<_EOC_; + location /t { + echo ok; + } +_EOC_ + + $block->set_value("config", $config); + } + + if (!defined $block->request) { + $block->set_value("request", "GET /t"); + } + + if (!defined $block->response_body) { + $block->set_value("ignore_response_body"); + } + + if (!defined $block->no_error_log) { + $block->set_value("no_error_log", "[error]"); + } +}); + +plan tests => repeat_each() * (blocks() * 2 + 1); + +no_long_string(); +run_tests(); + +__DATA__ + +=== TEST 1: lua_sa_restart default - sets SA_RESTART in init_worker_by_lua* +--- http_config + init_worker_by_lua_block { + test_sa_restart() + } + + + +=== TEST 2: lua_sa_restart off - does not set SA_RESTART +--- http_config + lua_sa_restart off; + + init_worker_by_lua_block { + test_sa_restart() + } +--- no_error_log +[crit] +--- error_log +Interrupted system call + + + +=== TEST 3: lua_sa_restart on (default) - sets SA_RESTART if no init_worker_by_lua* phase is defined +--- config + location /t { + content_by_lua_block { + test_sa_restart() + } + } + + + +=== TEST 4: lua_sa_restart on (default) - SA_RESTART is effective in rewrite_by_lua* +--- config + location /t { + rewrite_by_lua_block { + test_sa_restart() + } + + echo ok; + } + + + +=== TEST 5: lua_sa_restart on (default) - SA_RESTART is effective in access_by_lua* +--- config + location /t { + access_by_lua_block { + test_sa_restart() + } + + echo ok; + } + + + +=== TEST 6: lua_sa_restart on (default) - SA_RESTART is effective in content_by_lua* +--- config + location /t { + content_by_lua_block { + test_sa_restart() + } + } + + + +=== TEST 7: lua_sa_restart on (default) - SA_RESTART is effective in header_filter_by_lua* +--- config + location /t { + echo ok; + + header_filter_by_lua_block { + test_sa_restart() + } + } + + + +=== TEST 8: lua_sa_restart on (default) - SA_RESTART is effective in body_filter_by_lua* +--- config + location /t { + echo ok; + + body_filter_by_lua_block { + test_sa_restart() + } + } + + + +=== TEST 9: lua_sa_restart on (default) - SA_RESTART is effective in log_by_lua* +--- config + location /t { + echo ok; + + log_by_lua_block { + test_sa_restart() + } + } + + + +=== TEST 10: lua_sa_restart on (default) - SA_RESTART is effective in timer phase +--- config + location /t { + echo ok; + + log_by_lua_block { + ngx.timer.at(0, test_sa_restart) + } + } diff --git a/debian/modules/http-lua/t/160-disable-init-by-lua.t b/debian/modules/http-lua/t/160-disable-init-by-lua.t new file mode 100644 index 0000000..541771e --- /dev/null +++ b/debian/modules/http-lua/t/160-disable-init-by-lua.t @@ -0,0 +1,194 @@ +use Test::Nginx::Socket::Lua; + +repeat_each(2); + +plan tests => repeat_each() * (blocks() * 3); + +$ENV{TEST_NGINX_HTML_DIR} ||= html_dir(); + +my $html_dir = $ENV{TEST_NGINX_HTML_DIR}; +my $http_config = <<_EOC_; + init_by_lua_block { + function set_up_ngx_tmp_conf(conf) + if conf == nil then + conf = [[ + events { + worker_connections 64; + } + http { + init_by_lua_block { + ngx.log(ngx.ERR, "run init_by_lua") + } + } + ]] + end + + assert(os.execute("mkdir -p $html_dir/logs")) + + local conf_file = "$html_dir/nginx.conf" + local f, err = io.open(conf_file, "w") + if not f then + ngx.log(ngx.ERR, err) + return + end + + assert(f:write(conf)) + + return conf_file + end + + function get_ngx_bin_path() + local ffi = require "ffi" + ffi.cdef[[char **ngx_argv;]] + return ffi.string(ffi.C.ngx_argv[0]) + end + } +_EOC_ + +add_block_preprocessor(sub { + my $block = shift; + + if (!defined $block->http_config) { + $block->set_value("http_config", $http_config); + } + + if (!defined $block->request) { + $block->set_value("request", "GET /t"); + } +}); + +env_to_nginx("PATH"); +log_level("warn"); +no_long_string(); +run_tests(); + +__DATA__ + +=== TEST 1: ensure init_by_lua* is not run in signaller process +--- config + location = /t { + content_by_lua_block { + local conf_file = set_up_ngx_tmp_conf() + local nginx = get_ngx_bin_path() + + local cmd = nginx .. " -p $TEST_NGINX_HTML_DIR -c " .. conf_file .. " -s reopen" + local p, err = io.popen(cmd) + if not p then + ngx.log(ngx.ERR, err) + return + end + + local out, err = p:read("*a") + if not out then + ngx.log(ngx.ERR, err) + + else + ngx.log(ngx.WARN, out) + end + } + } +--- error_log +failed (2: No such file or directory) +--- no_error_log eval +qr/\[error\] .*? init_by_lua:\d+: run init_by_lua/ + + + +=== TEST 2: init_by_lua* does not run when testing Nginx configuration +--- config + location = /t { + content_by_lua_block { + local conf_file = set_up_ngx_tmp_conf() + local nginx = get_ngx_bin_path() + + local cmd = nginx .. " -p $TEST_NGINX_HTML_DIR -c " .. conf_file .. " -t" + local p, err = io.popen(cmd) + if not p then + ngx.log(ngx.ERR, err) + return + end + + local out, err = p:read("*a") + if not out then + ngx.log(ngx.ERR, err) + + else + ngx.log(ngx.WARN, out) + end + + local cmd = nginx .. " -p $TEST_NGINX_HTML_DIR -c " .. conf_file .. " -T" + local p, err = io.popen(cmd) + if not p then + ngx.log(ngx.ERR, err) + return + end + + local out, err = p:read("*a") + if not out then + ngx.log(ngx.ERR, err) + + else + ngx.log(ngx.WARN, out) + end + } + } +--- error_log +test is successful +--- no_error_log eval +qr/\[error\] .*? init_by_lua:\d+: run init_by_lua/ + + + +=== TEST 3: init_by_lua* does not run when testing Nginx configuration which contains 'lua_shared_dict' (GitHub #1462) +--- config + location = /t { + content_by_lua_block { + local conf = [[ + events { + worker_connections 64; + } + http { + lua_shared_dict test 64k; + init_by_lua_block { + ngx.log(ngx.ERR, "run init_by_lua with lua_shared_dict") + } + } + ]] + local conf_file = set_up_ngx_tmp_conf(conf) + local nginx = get_ngx_bin_path() + + local cmd = nginx .. " -p $TEST_NGINX_HTML_DIR -c " .. conf_file .. " -t" + local p, err = io.popen(cmd) + if not p then + ngx.log(ngx.ERR, err) + return + end + + local out, err = p:read("*a") + if not out then + ngx.log(ngx.ERR, err) + + else + ngx.log(ngx.WARN, out) + end + + local cmd = nginx .. " -p $TEST_NGINX_HTML_DIR -c " .. conf_file .. " -T" + local p, err = io.popen(cmd) + if not p then + ngx.log(ngx.ERR, err) + return + end + + local out, err = p:read("*a") + if not out then + ngx.log(ngx.ERR, err) + + else + ngx.log(ngx.WARN, out) + end + } + } +--- error_log +test is successful +--- no_error_log eval +qr/\[error\] .*? init_by_lua:\d+: run init_by_lua with lua_shared_dict/ diff --git a/debian/modules/http-lua/t/161-load-resty-core.t b/debian/modules/http-lua/t/161-load-resty-core.t new file mode 100644 index 0000000..41b18f0 --- /dev/null +++ b/debian/modules/http-lua/t/161-load-resty-core.t @@ -0,0 +1,68 @@ +use Test::Nginx::Socket::Lua; + +repeat_each(2); + +plan tests => repeat_each() * (blocks() * 3); + +add_block_preprocessor(sub { + my $block = shift; + + if (!defined $block->request) { + $block->set_value("request", "GET /t"); + } + + if (!defined $block->no_error_log) { + $block->set_value("no_error_log", "[error]"); + } +}); + +no_long_string(); +run_tests(); + +__DATA__ + +=== TEST 1: lua_load_resty_core is enabled by default +--- config + location = /t { + content_by_lua_block { + local loaded_resty_core = package.loaded["resty.core"] + local resty_core = require "resty.core" + + ngx.say("resty.core loaded: ", loaded_resty_core == resty_core) + } + } +--- response_body +resty.core loaded: true + + + +=== TEST 2: lua_load_resty_core can be disabled +--- http_config + lua_load_resty_core off; +--- config + location = /t { + content_by_lua_block { + local loaded_resty_core = package.loaded["resty.core"] + + ngx.say("resty.core loaded: ", loaded_resty_core ~= nil) + } + } +--- response_body +resty.core loaded: false + + + +=== TEST 3: lua_load_resty_core is effective when using lua_shared_dict +--- http_config + lua_shared_dict dogs 128k; +--- config + location = /t { + content_by_lua_block { + local loaded_resty_core = package.loaded["resty.core"] + local resty_core = require "resty.core" + + ngx.say("resty.core loaded: ", loaded_resty_core == resty_core) + } + } +--- response_body +resty.core loaded: true diff --git a/debian/modules/http-lua/t/data/fake-shm-module/ngx_http_lua_fake_shm_module.c b/debian/modules/http-lua/t/data/fake-shm-module/ngx_http_lua_fake_shm_module.c index 0286853..ffc32f5 100644 --- a/debian/modules/http-lua/t/data/fake-shm-module/ngx_http_lua_fake_shm_module.c +++ b/debian/modules/http-lua/t/data/fake-shm-module/ngx_http_lua_fake_shm_module.c @@ -213,10 +213,9 @@ ngx_http_lua_fake_shm_preload(lua_State *L) ngx_uint_t i; ngx_shm_zone_t **zone; + ngx_shm_zone_t **zone_udata; - lua_getglobal(L, "__ngx_cycle"); - cycle = lua_touserdata(L, -1); - lua_pop(L, 1); + cycle = (ngx_cycle_t *) ngx_cycle; hmcf_ctx = (ngx_http_conf_ctx_t *) cycle->conf_ctx[ngx_http_module.index]; lfsmcf = hmcf_ctx->main_conf[ngx_http_lua_fake_shm_module.ctx_index]; @@ -242,7 +241,9 @@ ngx_http_lua_fake_shm_preload(lua_State *L) lua_createtable(L, 1 /* narr */, 0 /* nrec */); /* table of zone[i] */ - lua_pushlightuserdata(L, zone[i]); /* shared mt key ud */ + zone_udata = lua_newuserdata(L, sizeof(ngx_shm_zone_t *)); + /* shared mt key ud */ + *zone_udata = zone[i]; lua_rawseti(L, -2, 1); /* {zone[i]} */ lua_pushvalue(L, -3); /* shared mt key ud mt */ lua_setmetatable(L, -2); /* shared mt key ud */ @@ -262,9 +263,10 @@ ngx_http_lua_fake_shm_preload(lua_State *L) static int ngx_http_lua_fake_shm_get_info(lua_State *L) { - ngx_int_t n; - ngx_shm_zone_t *zone; - ngx_http_lua_fake_shm_ctx_t *ctx; + ngx_int_t n; + ngx_shm_zone_t *zone; + ngx_shm_zone_t **zone_udata; + ngx_http_lua_fake_shm_ctx_t *ctx; n = lua_gettop(L); @@ -276,13 +278,15 @@ ngx_http_lua_fake_shm_get_info(lua_State *L) luaL_checktype(L, 1, LUA_TTABLE); lua_rawgeti(L, 1, 1); - zone = lua_touserdata(L, -1); + zone_udata = lua_touserdata(L, -1); lua_pop(L, 1); - if (zone == NULL) { + if (zone_udata == NULL) { return luaL_error(L, "bad \"zone\" argument"); } + zone = *zone_udata; + ctx = (ngx_http_lua_fake_shm_ctx_t *) zone->data; lua_pushlstring(L, (char *) zone->shm.name.data, zone->shm.name.len); diff --git a/debian/modules/http-lua/util/build.sh b/debian/modules/http-lua/util/build.sh index 164bf9f..14e9fd4 100755 --- a/debian/modules/http-lua/util/build.sh +++ b/debian/modules/http-lua/util/build.sh @@ -22,6 +22,8 @@ force=$2 #--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-pcre-jit \ --with-ipv6 \ @@ -55,7 +57,7 @@ time ngx-build $force $version \ --add-module=$root/../redis2-nginx-module \ --add-module=$root/../stream-lua-nginx-module \ --add-module=$root/t/data/fake-module \ - --add-module=$root/t/data/fake-shm-module \ + $add_fake_shm_module \ --add-module=$root/t/data/fake-delayed-load-module \ --with-http_gunzip_module \ --with-http_dav_module \ From 07d0cb5b7152a38029139c8a6a22e12cd02eb614 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Mon, 9 Sep 2019 18:25:14 +0300 Subject: [PATCH 013/329] Release 1.16.1-1 --- debian/changelog | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/debian/changelog b/debian/changelog index 509cc2b..0b0b75b 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,13 @@ +nginx (1.16.1-1) unstable; urgency=medium + + * New upstream version (Closes: #929200) + * Follow stable 1.16 releases (Closes: #929199) + * Drop already included debian patches + * http-ndk: Upgrade to 0.3.1 + * http-lua: Upgrade to 0.10.15 + + -- Christos Trochalakis Mon, 09 Sep 2019 18:24:43 +0300 + nginx (1.14.2-3) unstable; urgency=high * Backport upstream fixes for 3 CVEs (Closes: #935037) From bfd112b793a68d11e9b1a9bd7209f7acfac22995 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Sat, 12 Oct 2019 17:24:11 +0300 Subject: [PATCH 014/329] http-lua: Downgrade to 0.10.13 This a temporary fix for the FTBFS on arches where liblua5.1-0-dev is used instead of libluajit-5.1-dev. The regression was introduce in 0.10.14, see: https://github.com/openresty/lua-nginx-module/commit/7286812116940216344ade33722c49ae47037605 This reverts commit 132704ab76aa72ce29d00e4acd50d3218693558b. Closes: 941917 --- debian/modules/control | 2 +- debian/modules/http-lua/README.markdown | 235 +- debian/modules/http-lua/config | 45 - .../modules/http-lua/doc/HttpLuaModule.wiki | 213 +- .../http-lua/src/api/ngx_http_lua_api.h | 2 +- .../http-lua/src/ngx_http_lua_accessby.c | 4 +- .../modules/http-lua/src/ngx_http_lua_api.c | 2 +- .../http-lua/src/ngx_http_lua_balancer.c | 3 - .../http-lua/src/ngx_http_lua_bodyfilterby.c | 50 +- .../http-lua/src/ngx_http_lua_bodyfilterby.h | 2 +- .../modules/http-lua/src/ngx_http_lua_cache.c | 23 +- .../http-lua/src/ngx_http_lua_clfactory.c | 45 +- .../http-lua/src/ngx_http_lua_common.h | 49 +- .../http-lua/src/ngx_http_lua_contentby.c | 2 - .../http-lua/src/ngx_http_lua_control.c | 3 +- .../http-lua/src/ngx_http_lua_coroutine.c | 18 +- .../http-lua/src/ngx_http_lua_directive.c | 11 +- .../src/ngx_http_lua_headerfilterby.c | 3 +- .../http-lua/src/ngx_http_lua_headers.c | 83 +- .../http-lua/src/ngx_http_lua_headers_in.c | 10 +- .../http-lua/src/ngx_http_lua_headers_out.c | 20 +- .../http-lua/src/ngx_http_lua_headers_out.h | 6 +- .../http-lua/src/ngx_http_lua_initworkerby.c | 19 - .../http-lua/src/ngx_http_lua_input_filters.c | 137 - .../http-lua/src/ngx_http_lua_input_filters.h | 29 - .../modules/http-lua/src/ngx_http_lua_logby.c | 3 +- .../modules/http-lua/src/ngx_http_lua_misc.c | 27 - .../http-lua/src/ngx_http_lua_module.c | 56 - .../modules/http-lua/src/ngx_http_lua_ndk.c | 41 - .../modules/http-lua/src/ngx_http_lua_pipe.c | 2475 ----------------- .../modules/http-lua/src/ngx_http_lua_pipe.h | 95 - .../modules/http-lua/src/ngx_http_lua_regex.c | 10 +- .../http-lua/src/ngx_http_lua_rewriteby.c | 4 +- .../http-lua/src/ngx_http_lua_script.c | 4 +- .../modules/http-lua/src/ngx_http_lua_setby.c | 34 +- .../modules/http-lua/src/ngx_http_lua_setby.h | 2 +- .../http-lua/src/ngx_http_lua_shdict.c | 44 +- .../http-lua/src/ngx_http_lua_socket_tcp.c | 1608 ++++------- .../http-lua/src/ngx_http_lua_socket_tcp.h | 29 +- .../http-lua/src/ngx_http_lua_socket_udp.c | 12 +- .../http-lua/src/ngx_http_lua_ssl_certby.c | 2 - .../src/ngx_http_lua_ssl_session_fetchby.c | 2 - .../src/ngx_http_lua_ssl_session_storeby.c | 3 - .../http-lua/src/ngx_http_lua_string.c | 14 - .../http-lua/src/ngx_http_lua_subrequest.c | 8 - .../modules/http-lua/src/ngx_http_lua_timer.c | 44 +- .../http-lua/src/ngx_http_lua_uthread.c | 3 +- .../modules/http-lua/src/ngx_http_lua_util.c | 168 +- .../modules/http-lua/src/ngx_http_lua_util.h | 28 +- .../http-lua/src/ngx_http_lua_worker.c | 11 - debian/modules/http-lua/t/000--init.t | 5 + debian/modules/http-lua/t/001-set.t | 23 +- debian/modules/http-lua/t/002-content.t | 38 +- debian/modules/http-lua/t/004-require.t | 12 +- debian/modules/http-lua/t/005-exit.t | 2 +- debian/modules/http-lua/t/009-log.t | 12 +- debian/modules/http-lua/t/011-md5_bin.t | 2 +- debian/modules/http-lua/t/013-base64.t | 2 +- debian/modules/http-lua/t/014-bugs.t | 49 +- debian/modules/http-lua/t/016-resp-header.t | 504 +--- debian/modules/http-lua/t/017-exec.t | 4 +- debian/modules/http-lua/t/020-subrequest.t | 134 +- .../http-lua/t/023-rewrite/client-abort.t | 6 +- debian/modules/http-lua/t/023-rewrite/exec.t | 4 +- debian/modules/http-lua/t/023-rewrite/mixed.t | 4 +- .../http-lua/t/023-rewrite/multi-capture.t | 2 +- .../http-lua/t/023-rewrite/req-socket.t | 6 +- .../modules/http-lua/t/023-rewrite/sanity.t | 28 +- .../http-lua/t/023-rewrite/socket-keepalive.t | 12 +- .../http-lua/t/023-rewrite/subrequest.t | 42 +- .../t/023-rewrite/tcp-socket-timeout.t | 12 +- .../http-lua/t/023-rewrite/tcp-socket.t | 32 +- .../http-lua/t/023-rewrite/uthread-exec.t | 12 +- .../http-lua/t/023-rewrite/uthread-exit.t | 40 +- .../http-lua/t/023-rewrite/uthread-redirect.t | 4 +- .../http-lua/t/023-rewrite/uthread-spawn.t | 62 +- .../http-lua/t/024-access/client-abort.t | 6 +- debian/modules/http-lua/t/024-access/exec.t | 2 +- debian/modules/http-lua/t/024-access/mixed.t | 10 +- .../http-lua/t/024-access/multi-capture.t | 2 +- debian/modules/http-lua/t/024-access/sanity.t | 30 +- .../http-lua/t/024-access/subrequest.t | 42 +- .../http-lua/t/024-access/uthread-exec.t | 12 +- .../http-lua/t/024-access/uthread-exit.t | 38 +- .../http-lua/t/024-access/uthread-redirect.t | 4 +- .../http-lua/t/024-access/uthread-spawn.t | 62 +- debian/modules/http-lua/t/025-codecache.t | 174 +- debian/modules/http-lua/t/027-multi-capture.t | 4 +- debian/modules/http-lua/t/028-req-header.t | 24 +- debian/modules/http-lua/t/030-uri-args.t | 23 +- debian/modules/http-lua/t/034-match.t | 65 +- debian/modules/http-lua/t/035-gmatch.t | 22 +- debian/modules/http-lua/t/036-sub.t | 4 +- debian/modules/http-lua/t/037-gsub.t | 2 +- debian/modules/http-lua/t/038-match-o.t | 44 +- debian/modules/http-lua/t/041-header-filter.t | 15 +- debian/modules/http-lua/t/043-shdict.t | 4 +- debian/modules/http-lua/t/047-match-jit.t | 12 +- debian/modules/http-lua/t/048-match-dfa.t | 12 +- debian/modules/http-lua/t/055-subreq-vars.t | 18 +- debian/modules/http-lua/t/056-flush.t | 2 +- debian/modules/http-lua/t/057-flush-timeout.t | 2 +- debian/modules/http-lua/t/058-tcp-socket.t | 364 +-- debian/modules/http-lua/t/062-count.t | 31 +- debian/modules/http-lua/t/063-abort.t | 62 +- debian/modules/http-lua/t/064-pcall.t | 14 +- .../http-lua/t/065-tcp-socket-timeout.t | 24 +- .../http-lua/t/066-socket-receiveuntil.t | 30 +- debian/modules/http-lua/t/067-req-socket.t | 6 +- .../modules/http-lua/t/068-socket-keepalive.t | 1467 +--------- debian/modules/http-lua/t/073-backtrace.t | 14 +- debian/modules/http-lua/t/075-logby.t | 11 +- debian/modules/http-lua/t/081-bytecode.t | 45 +- debian/modules/http-lua/t/082-body-filter.t | 3 +- .../http-lua/t/084-inclusive-receiveuntil.t | 20 +- debian/modules/http-lua/t/087-udp-socket.t | 12 +- .../http-lua/t/090-log-socket-errors.t | 10 +- debian/modules/http-lua/t/091-coroutine.t | 81 +- debian/modules/http-lua/t/093-uthread-spawn.t | 66 +- debian/modules/http-lua/t/094-uthread-exit.t | 46 +- debian/modules/http-lua/t/095-uthread-exec.t | 14 +- .../modules/http-lua/t/096-uthread-redirect.t | 6 +- .../modules/http-lua/t/097-uthread-rewrite.t | 12 +- debian/modules/http-lua/t/098-uthread-wait.t | 74 +- debian/modules/http-lua/t/099-c-api.t | 10 +- debian/modules/http-lua/t/100-client-abort.t | 6 +- debian/modules/http-lua/t/106-timer.t | 18 +- debian/modules/http-lua/t/108-timer-safe.t | 16 +- debian/modules/http-lua/t/109-timer-hup.t | 18 +- debian/modules/http-lua/t/120-re-find.t | 4 +- debian/modules/http-lua/t/123-lua-path.t | 10 +- debian/modules/http-lua/t/124-init-worker.t | 10 +- debian/modules/http-lua/t/126-shdict-frag.t | 4 +- debian/modules/http-lua/t/127-uthread-kill.t | 26 +- .../http-lua/t/128-duplex-tcp-socket.t | 6 +- debian/modules/http-lua/t/129-ssl-socket.t | 16 +- debian/modules/http-lua/t/130-internal-api.t | 17 +- .../modules/http-lua/t/134-worker-count-5.t | 4 +- debian/modules/http-lua/t/138-balancer.t | 2 + debian/modules/http-lua/t/139-ssl-cert-by.t | 2 +- debian/modules/http-lua/t/140-ssl-c-api.t | 23 +- .../http-lua/t/143-ssl-session-fetch.t | 105 - .../http-lua/t/147-tcp-socket-timeouts.t | 8 +- debian/modules/http-lua/t/152-timer-every.t | 4 +- debian/modules/http-lua/t/153-semaphore-hup.t | 2 +- debian/modules/http-lua/t/156-slow-network.t | 138 - .../http-lua/t/157-socket-keepalive-hup.t | 91 - debian/modules/http-lua/t/158-global-var.t | 508 ---- debian/modules/http-lua/t/159-sa-restart.t | 180 -- .../http-lua/t/160-disable-init-by-lua.t | 194 -- .../modules/http-lua/t/161-load-resty-core.t | 68 - .../ngx_http_lua_fake_shm_module.c | 22 +- debian/modules/http-lua/util/build.sh | 4 +- 153 files changed, 1866 insertions(+), 9493 deletions(-) delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_input_filters.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_input_filters.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_pipe.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_pipe.h delete mode 100644 debian/modules/http-lua/t/156-slow-network.t delete mode 100644 debian/modules/http-lua/t/157-socket-keepalive-hup.t delete mode 100644 debian/modules/http-lua/t/158-global-var.t delete mode 100644 debian/modules/http-lua/t/159-sa-restart.t delete mode 100644 debian/modules/http-lua/t/160-disable-init-by-lua.t delete mode 100644 debian/modules/http-lua/t/161-load-resty-core.t diff --git a/debian/modules/control b/debian/modules/control index 8331ff5..f27ca7c 100644 --- a/debian/modules/control +++ b/debian/modules/control @@ -18,7 +18,7 @@ Files-Excluded: .gitignore .gitattributes .travis.yml Module: http-lua Homepage: https://github.com/openresty/lua-nginx-module -Version: 0.10.15 +Version: 0.10.13 Patch: openssl-1.1.0.patch discover-luajit-2.1.patch diff --git a/debian/modules/http-lua/README.markdown b/debian/modules/http-lua/README.markdown index ed0c72d..15ad00e 100644 --- a/debian/modules/http-lua/README.markdown +++ b/debian/modules/http-lua/README.markdown @@ -8,8 +8,6 @@ Name ngx_http_lua_module - Embed the power of Lua into Nginx HTTP Servers. -This module is a core component of OpenResty. If you are using this module, then you are essentially using OpenResty :) - *This module is not distributed with the Nginx source.* See [the installation instructions](#installation). Table of Contents @@ -25,6 +23,7 @@ Table of Contents * [Installation](#installation) * [Building as a dynamic module](#building-as-a-dynamic-module) * [C Macro Configurations](#c-macro-configurations) + * [Installation on Ubuntu 11.10](#installation-on-ubuntu-1110) * [Community](#community) * [English Mailing List](#english-mailing-list) * [Chinese Mailing List](#chinese-mailing-list) @@ -63,7 +62,7 @@ Production ready. Version ======= -This document describes ngx_lua [v0.10.15](https://github.com/openresty/lua-nginx-module/tags) released on March 14th, 2019. +This document describes ngx_lua [v0.10.13](https://github.com/openresty/lua-nginx-module/tags) released on 22 April 2018. Synopsis ======== @@ -188,9 +187,7 @@ Synopsis Description =========== -This module is a core component of OpenResty. If you are using this module, then you are essentially using OpenResty :) - -This module embeds Lua, via [LuaJIT 2.0/2.1](http://luajit.org/luajit.html), into Nginx and by leveraging Nginx's subrequests, allows the integration of the powerful Lua threads (Lua coroutines) into the Nginx event model. +This module embeds Lua, via the standard Lua 5.1 interpreter or [LuaJIT 2.0/2.1](http://luajit.org/luajit.html), into Nginx and by leveraging Nginx's subrequests, allows the integration of the powerful Lua threads (Lua coroutines) into the Nginx event model. Unlike [Apache's mod_lua](https://httpd.apache.org/docs/trunk/mod/mod_lua.html) and [Lighttpd's mod_magnet](http://redmine.lighttpd.net/wiki/1/Docs:ModMagnet), Lua code executed using this module can be *100% non-blocking* on network traffic as long as the [Nginx API for Lua](#nginx-api-for-lua) provided by this module is used to handle requests to upstream services such as MySQL, PostgreSQL, Memcached, Redis, or upstream HTTP web services. @@ -268,11 +265,11 @@ Nginx cores older than 1.6.0 (exclusive) are *not* supported. Installation ============ -It is *highly* recommended to use [OpenResty releases](http://openresty.org) which integrate Nginx, ngx_lua, OpenResty's LuaJIT 2.1 branch version, as well as other powerful companion Nginx modules and Lua libraries. It is discouraged to build this module with nginx yourself since it is tricky to set up exactly right. Also, the stock nginx cores have various limitations and long standing bugs that can make some of this modules' features become disabled, not work properly, or run slower. The same applies to LuaJIT as well. OpenResty includes its own version of LuaJIT which gets specifically optimized and enhanced for the OpenResty environment. +It is *highly* recommended to use [OpenResty releases](http://openresty.org) which integrate Nginx, ngx_lua, LuaJIT 2.1, as well as other powerful companion Nginx modules and Lua libraries. It is discouraged to build this module with nginx yourself since it is tricky to set up exactly right. Also, the stock nginx cores have various limitations and long standing bugs that can make some of this modules' features become disabled, not work properly, or run slower. The same applies to LuaJIT as well. OpenResty includes its own version of LuaJIT which gets specifically optimized and enhanced for the OpenResty environment. Alternatively, ngx_lua can be manually compiled into Nginx: -1. LuaJIT can be downloaded from the [latest release of OpenResty's LuaJIT branch version](https://github.com/openresty/luajit2/releases). The official LuaJIT 2.0 and 2.1 releases are also supported, although the performance will be significantly lower in many cases. +1. Install LuaJIT 2.0 or 2.1 (recommended) or Lua 5.1 (Lua 5.2 is *not* supported yet). LuaJIT can be downloaded from the [LuaJIT project website](http://luajit.org/download.html) and Lua 5.1, from the [Lua project website](http://www.lua.org/). Some distribution package managers also distribute LuaJIT and/or Lua. 1. Download the latest version of the ngx_devel_kit (NDK) module [HERE](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 version of Nginx [HERE](http://nginx.org/) (See [Nginx Compatibility](#nginx-compatibility)) @@ -348,6 +345,29 @@ To enable one or more of these macros, just pass extra C compiler options to the ./configure --with-cc-opt="-DNGX_LUA_USE_ASSERT -DNGX_LUA_ABORT_AT_PANIC" +[Back to TOC](#table-of-contents) + +Installation on Ubuntu 11.10 +---------------------------- + +Note that it is recommended to use LuaJIT 2.0 or LuaJIT 2.1 instead of the standard Lua 5.1 interpreter wherever possible. + +If the standard Lua 5.1 interpreter is required however, run the following command to install it from the Ubuntu repository: + +```bash + + apt-get install -y lua5.1 liblua5.1-0 liblua5.1-0-dev +``` + +Everything should be installed correctly, except for one small tweak. + +Library name `liblua.so` has been changed in liblua5.1 package, it only comes with `liblua5.1.so`, which needs to be symlinked to `/usr/lib` so it could be found during the configuration process. + +```bash + + ln -s /usr/lib/x86_64-linux-gnu/liblua5.1.so /usr/lib/liblua.so +``` + [Back to TOC](#table-of-contents) Community @@ -391,7 +411,7 @@ Lua/LuaJIT bytecode support As from the `v0.5.0rc32` release, all `*_by_lua_file` configure directives (such as [content_by_lua_file](#content_by_lua_file)) support loading Lua 5.1 and LuaJIT 2.0/2.1 raw bytecode files directly. -Please note that the bytecode format used by LuaJIT 2.0/2.1 is not compatible with that used by the standard Lua 5.1 interpreter. So if you are using LuaJIT 2.0/2.1 with ngx_lua, LuaJIT compatible bytecode files must be generated as shown: +Please note that the bytecode format used by LuaJIT 2.0/2.1 is not compatible with that used by the standard Lua 5.1 interpreter. So if using LuaJIT 2.0/2.1 with ngx_lua, LuaJIT compatible bytecode files must be generated as shown: ```bash @@ -411,6 +431,20 @@ Please refer to the official LuaJIT documentation on the `-b` option for more de Also, the bytecode files generated by LuaJIT 2.1 is *not* compatible with LuaJIT 2.0, and vice versa. The support for LuaJIT 2.1 bytecode was first added in ngx_lua v0.9.3. +Similarly, if using the standard Lua 5.1 interpreter with ngx_lua, Lua compatible bytecode files must be generated using the `luac` commandline utility as shown: + +```bash + + luac -o /path/to/output_file.luac /path/to/input_file.lua +``` + +Unlike as with LuaJIT, debug information is included in standard Lua 5.1 bytecode files by default. This can be striped out by specifying the `-s` option as shown: + +```bash + + luac -s -o /path/to/output_file.luac /path/to/input_file.lua +``` + Attempts to load standard Lua 5.1 bytecode files into ngx_lua instances linked to LuaJIT 2.0/2.1 or vice versa, will result in an error message, such as that below, being logged into the Nginx `error.log` file: @@ -608,7 +642,8 @@ This issue is due to limitations in the Nginx event model and only appears to af Lua Coroutine Yielding/Resuming ------------------------------- -* Because Lua's `dofile` and `require` builtins are currently implemented as C functions in LuaJIT 2.0/2.1, if the Lua file being loaded by `dofile` or `require` invokes [ngx.location.capture*](#ngxlocationcapture), [ngx.exec](#ngxexec), [ngx.exit](#ngxexit), or other API functions requiring yielding in the *top-level* scope of the Lua file, then the Lua error "attempt to yield across C-call boundary" will be raised. To avoid this, put these calls requiring yielding into your own Lua functions in the Lua file instead of the top-level scope of the file. +* Because Lua's `dofile` and `require` builtins are currently implemented as C functions in both Lua 5.1 and LuaJIT 2.0/2.1, if the Lua file being loaded by `dofile` or `require` invokes [ngx.location.capture*](#ngxlocationcapture), [ngx.exec](#ngxexec), [ngx.exit](#ngxexit), or other API functions requiring yielding in the *top-level* scope of the Lua file, then the Lua error "attempt to yield across C-call boundary" will be raised. To avoid this, put these calls requiring yielding into your own Lua functions in the Lua file instead of the top-level scope of the file. +* As the standard Lua 5.1 interpreter's VM is not fully resumable, the methods [ngx.location.capture](#ngxlocationcapture), [ngx.location.capture_multi](#ngxlocationcapture_multi), [ngx.redirect](#ngxredirect), [ngx.exec](#ngxexec), and [ngx.exit](#ngxexit) cannot be used within the context of a Lua [pcall()](http://www.lua.org/manual/5.1/manual.html#pdf-pcall) or [xpcall()](http://www.lua.org/manual/5.1/manual.html#pdf-xpcall) or even the first line of the `for ... in ...` statement when the standard Lua 5.1 interpreter is used and the `attempt to yield across metamethod/C-call boundary` error will be produced. Please use LuaJIT 2.x, which supports a fully resumable VM, to avoid this. [Back to TOC](#table-of-contents) @@ -960,7 +995,7 @@ This module is licensed under the BSD license. Copyright (C) 2009-2017, by Xiaozhe Wang (chaoslawful) . -Copyright (C) 2009-2019, by Yichun "agentzh" Zhang (章亦春) , OpenResty Inc. +Copyright (C) 2009-2018, by Yichun "agentzh" Zhang (章亦春) , OpenResty Inc. All rights reserved. @@ -1004,7 +1039,6 @@ See Also Directives ========== -* [lua_load_resty_core](#lua_load_resty_core) * [lua_capture_error_log](#lua_capture_error_log) * [lua_use_default_type](#lua_use_default_type) * [lua_malloc_trim](#lua_malloc_trim) @@ -1070,7 +1104,6 @@ Directives * [lua_check_client_abort](#lua_check_client_abort) * [lua_max_pending_timers](#lua_max_pending_timers) * [lua_max_running_timers](#lua_max_running_timers) -* [lua_sa_restart](#lua_sa_restart) The basic building blocks of scripting Nginx with Lua are directives. Directives are used to specify when the user Lua code is run and @@ -1080,38 +1113,6 @@ how the result will be used. Below is a diagram showing the order in which direc [Back to TOC](#table-of-contents) -lua_load_resty_core -------------------- - -**syntax:** *lua_load_resty_core on|off* - -**default:** *lua_load_resty_core on* - -**context:** *http* - -Controls whether the `resty.core` module (from -[lua-resty-core](https://github.com/openresty/lua-resty-core)) should be loaded -or not. When enabled, this directive is equivalent to executing the following -when the Lua VM is created: - -```lua - - require "resty.core" -``` - -Note that usage of the `resty.core` module is recommended, as its -FFI implementation is both faster, safer, and more complete than the Lua C API -of the ngx_lua module. - -It must also be noted that the Lua C API of the ngx_lua module will eventually -be removed, and usage of the FFI-based API (i.e. the `resty.core` -module) will become mandatory. This directive only aims at providing a -temporary backwards-compatibility mode in case of edge-cases. - -This directive was first introduced in the `v0.10.15` release. - -[Back to TOC](#directives) - lua_capture_error_log --------------------- **syntax:** *lua_capture_error_log size* @@ -2601,14 +2602,14 @@ SSL session resumption can then get immediately initiated and bypass the full SS Please note that TLS session tickets are very different and it is the clients' responsibility to cache the SSL session state when session tickets are used. SSL session resumptions based on TLS session tickets would happen automatically without going through this hook (nor the -[ssl_session_store_by_lua*](#ssl_session_store_by_lua_block) hook). This hook is mainly +[ssl_session_store_by_lua_block](#ssl_session_store_by_lua) hook). This hook is mainly for older or less capable SSL clients that can only do SSL sessions by session IDs. When [ssl_certificate_by_lua*](#ssl_certificate_by_lua_block) is specified at the same time, this hook usually runs before [ssl_certificate_by_lua*](#ssl_certificate_by_lua_block). When the SSL session is found and successfully loaded for the current SSL connection, SSL session resumption will happen and thus bypass the [ssl_certificate_by_lua*](#ssl_certificate_by_lua_block) -hook completely. In this case, NGINX also bypasses the [ssl_session_store_by_lua*](#ssl_session_store_by_lua_block) +hook completely. In this case, NGINX also bypasses the [ssl_session_store_by_lua_block](#ssl_session_store_by_lua) hook, for obvious reasons. To easily test this hook locally with a modern web browser, you can temporarily put the following line @@ -3107,23 +3108,6 @@ This directive was first introduced in the `v0.8.0` release. [Back to TOC](#directives) -lua_sa_restart --------------- - -**syntax:** *lua_sa_restart on|off* - -**default:** *lua_sa_restart on* - -**context:** *http* - -When enabled, this module will set the `SA_RESTART` flag on nginx workers signal dispositions. - -This allows Lua I/O primitives to not be interrupted by nginx's handling of various signals. - -This directive was first introduced in the `v0.10.14` release. - -[Back to TOC](#directives) - Nginx API for Lua ================= @@ -3237,7 +3221,6 @@ Nginx API for Lua * [tcpsock:sslhandshake](#tcpsocksslhandshake) * [tcpsock:send](#tcpsocksend) * [tcpsock:receive](#tcpsockreceive) -* [tcpsock:receiveany](#tcpsockreceiveany) * [tcpsock:receiveuntil](#tcpsockreceiveuntil) * [tcpsock:close](#tcpsockclose) * [tcpsock:settimeout](#tcpsocksettimeout) @@ -4319,7 +4302,7 @@ ngx.req.get_method ------------------ **syntax:** *method_name = ngx.req.get_method()* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, balancer_by_lua*, log_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, balancer_by_lua** Retrieves the current request's request method name. Strings like `"GET"` and `"POST"` are returned instead of numerical [method constants](#http-method-constants). @@ -4904,7 +4887,7 @@ This function returns `nil` if 1. the request body has been read into disk temporary files, 1. or the request body has zero size. -If the request body has not been read yet, call [ngx.req.read_body](#ngxreqread_body) first (or turn on [lua_need_request_body](#lua_need_request_body) to force this module to read the request body. This is not recommended however). +If the request body has not been read yet, call [ngx.req.read_body](#ngxreqread_body) first (or turned on [lua_need_request_body](#lua_need_request_body) to force this module to read the request body. This is not recommended however). If the request body has been read into disk files, try calling the [ngx.req.get_body_file](#ngxreqget_body_file) function instead. @@ -4928,7 +4911,7 @@ Retrieves the file name for the in-file request body data. Returns `nil` if the The returned file is read only and is usually cleaned up by Nginx's memory pool. It should not be manually modified, renamed, or removed in Lua code. -If the request body has not been read yet, call [ngx.req.read_body](#ngxreqread_body) first (or turn on [lua_need_request_body](#lua_need_request_body) to force this module to read the request body. This is not recommended however). +If the request body has not been read yet, call [ngx.req.read_body](#ngxreqread_body) first (or turned on [lua_need_request_body](#lua_need_request_body) to force this module to read the request body. This is not recommended however). If the request body has been read into memory, try calling the [ngx.req.get_body_data](#ngxreqget_body_data) function instead. @@ -4948,9 +4931,7 @@ ngx.req.set_body_data Set the current request's request body using the in-memory data specified by the `data` argument. -If the request body has not been read yet, call [ngx.req.read_body](#ngxreqread_body) first (or turn on [lua_need_request_body](#lua_need_request_body) to force this module to read the request body. This is not recommended however). Additionally, the request body must not have been previously discarded by [ngx.req.discard_body](#ngxreqdiscard_body). - -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. +If the current request's request body has not been read, then it will be properly discarded. When the current request's request body has been read into memory or buffered into a disk file, then the old request body's memory will be freed or the disk file will be cleaned up immediately, respectively. This function was first introduced in the `v0.3.1rc18` release. @@ -4966,13 +4947,11 @@ ngx.req.set_body_file Set the current request's request body using the in-file data specified by the `file_name` argument. -If the request body has not been read yet, call [ngx.req.read_body](#ngxreqread_body) first (or turn on [lua_need_request_body](#lua_need_request_body) to force this module to read the request body. This is not recommended however). Additionally, the request body must not have been previously discarded by [ngx.req.discard_body](#ngxreqdiscard_body). - If the optional `auto_clean` argument is given a `true` value, then this file will be removed at request completion or the next time this function or [ngx.req.set_body_data](#ngxreqset_body_data) are called in the same request. The `auto_clean` is default to `false`. Please ensure that the file specified by the `file_name` argument exists and is readable by an Nginx worker process by setting its permission properly to avoid Lua exception errors. -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. +If the current request's request body has not been read, then it will be properly discarded. When the current request's request body has been read into memory or buffered into a disk file, then the old request body's memory will be freed or the disk file will be cleaned up immediately, respectively. This function was first introduced in the `v0.3.1rc18` release. @@ -6738,7 +6717,7 @@ ngx.shared.DICT.flush_expired Flushes out the expired items in the dictionary, up to the maximal number specified by the optional `max_count` argument. When the `max_count` argument is given `0` or not given at all, then it means unlimited. Returns the number of items that have actually been flushed. -Unlike the [flush_all](#ngxshareddictflush_all) method, this method actually frees up the memory used by the expired items. +Unlike the [flush_all](#ngxshareddictflush_all) method, this method actually free up the memory used by the expired items. This feature was first introduced in the `v0.6.3` release. @@ -7023,7 +7002,6 @@ Creates and returns a TCP or stream-oriented unix domain socket object (also kno * [settimeout](#tcpsocksettimeout) * [settimeouts](#tcpsocksettimeouts) * [setoption](#tcpsocksetoption) -* [receiveany](#tcpsockreceiveany) * [receiveuntil](#tcpsockreceiveuntil) * [setkeepalive](#tcpsocksetkeepalive) * [getreusedtimes](#tcpsockgetreusedtimes) @@ -7128,43 +7106,6 @@ An optional Lua table can be specified as the last argument to this method to sp * `pool` specify a custom name for the connection pool being used. If omitted, then the connection pool name will be generated from the string template `":"` or `""`. -* `pool_size` - specify the size of the connection pool. If omitted and no - `backlog` option was provided, no pool will be created. If omitted - but `backlog` was provided, the pool will be created with a default - size equal to the value of the [lua_socket_pool_size](#lua_socket_pool_size) - directive. - The connection pool holds up to `pool_size` alive connections - ready to be reused by subsequent calls to [connect](#tcpsockconnect), but - note that there is no upper limit to the total number of opened connections - outside of the pool. If you need to restrict the total number of opened - connections, specify the `backlog` option. - When the connection pool would exceed its size limit, the least recently used - (kept-alive) connection already in the pool will be closed to make room for - the current connection. - Note that the cosocket connection pool is per Nginx worker process rather - than per Nginx server instance, so the size limit specified here also applies - to every single Nginx worker process. Also note that the size of the connection - pool cannot be changed once it has been created. - This option was first introduced in the `v0.10.14` release. - -* `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). - 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 operation will abort once they have been queued for more - than `connect_timeout`, controlled by - [settimeouts](#tcpsocksettimeouts), and will return `nil` plus - the error string `"timeout"`. - This option was first introduced in the `v0.10.14` release. - The support for the options table argument was first introduced in the `v0.5.7` release. This method was first introduced in the `v0.5.0rc1` release. @@ -7290,40 +7231,6 @@ This feature was first introduced in the `v0.5.0rc1` release. [Back to TOC](#nginx-api-for-lua) -tcpsock:receiveany ------------------- -**syntax:** *data, err = tcpsock:receiveany(max)* - -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua** - -Returns any data received by the connected socket, at most `max` bytes. - -This method is a synchronous operation just like the [send](#tcpsocksend) method and is 100% nonblocking. - -In case of success, it returns the data received; in case of error, it returns `nil` with a string describing the error. - -If the received data is more than this size, this method will return with exactly this size of data. -The remaining data in the underlying receive buffer could be returned in the next reading operation. - -Timeout for the reading operation is controlled by the [lua_socket_read_timeout](#lua_socket_read_timeout) config directive and the [settimeouts](#tcpsocksettimeouts) method. And the latter takes priority. For example: - -```lua - - sock:settimeouts(1000, 1000, 1000) -- one second timeout for connect/read/write - local data, err = sock:receiveany(10 * 1024 * 1024) -- read any data, at most 10K - if not data then - ngx.say("failed to read any data: ", err) - return - end - ngx.say("successfully read: ", data) -``` - -This method doesn't automatically close the current connection when the read timeout error occurs. For other connection errors, this method always automatically closes the connection. - -This feature was first introduced in the `v0.10.14` release. - -[Back to TOC](#nginx-api-for-lua) - tcpsock:receiveuntil -------------------- **syntax:** *iterator = tcpsock:receiveuntil(pattern, options?)* @@ -7496,31 +7403,13 @@ Puts the current socket's connection immediately into the cosocket built-in conn The first optional argument, `timeout`, can be used to specify the maximal idle timeout (in milliseconds) for the current connection. If omitted, the default setting in the [lua_socket_keepalive_timeout](#lua_socket_keepalive_timeout) config directive will be used. If the `0` value is given, then the timeout interval is unlimited. -The second optional argument `size` is considered deprecated since -the `v0.10.14` release of this module, in favor of the -`pool_size` option of the [connect](#tcpsockconnect) method. -Since the `v0.10.14` release, this option will only take effect if -the call to [connect](#tcpsockconnect) did not already create a connection -pool. -When this option takes effect (no connection pool was previously created by -[connect](#tcpsockconnect)), it will specify the size of the connection pool, -and create it. -If omitted (and no pool was previously created), the default size is the value -of the [lua_socket_pool_size](#lua_socket_pool_size) directive. -The connection pool holds up to `size` alive connections ready to be -reused by subsequent calls to [connect](#tcpsockconnect), but note that there -is no upper limit to the total number of opened connections outside of the -pool. -When the connection pool would exceed its size limit, the least recently used -(kept-alive) connection already in the pool will be closed to make room for -the current connection. -Note that the cosocket connection pool is per Nginx worker process rather -than per Nginx server instance, so the size limit specified here also applies -to every single Nginx worker process. Also note that the size of the connection -pool cannot be changed once it has been created. -If you need to restrict the total number of opened connections, specify both -the `pool_size` and `backlog` option in the call to -[connect](#tcpsockconnect). +The second optional argument, `size`, can be used to specify the maximal number of connections allowed in the connection pool for the current server (i.e., the current host-port pair or the unix domain socket file path). Note that the size of the connection pool cannot be changed once the pool is created. When this argument is omitted, the default setting in the [lua_socket_pool_size](#lua_socket_pool_size) config directive will be used. + +When the connection pool exceeds the available size limit, the least recently used (idle) connection already in the pool will be closed to make room for the current connection. + +Note that the cosocket connection pool is per Nginx worker process rather than per Nginx server instance, so the size limit specified here also applies to every single Nginx worker process. + +Idle connections in the pool will be monitored for any exceptional events like connection abortion or unexpected incoming data on the line, in which cases the connection in question will be closed and removed from the pool. In case of success, this method returns `1`; otherwise, it returns `nil` and a string describing the error. @@ -8292,7 +8181,7 @@ This Lua module does not ship with this ngx_lua module itself rather it is shipp the [lua-resty-core](https://github.com/openresty/lua-resty-core) library. -Please refer to the [documentation](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ocsp.md) +Please refer to the [documentation](https://github.com/openresty/lua-resty-core/blob/ocsp-cert-by-lua-2/lib/ngx/ocsp.md) for this `ngx.ocsp` Lua module for more details. This feature requires at least ngx_lua `v0.10.0`. diff --git a/debian/modules/http-lua/config b/debian/modules/http-lua/config index e1d5e35..044deb9 100644 --- a/debian/modules/http-lua/config +++ b/debian/modules/http-lua/config @@ -361,8 +361,6 @@ HTTP_LUA_SRCS=" \ $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_log_ringbuf.c \ - $ngx_addon_dir/src/ngx_http_lua_input_filters.c \ - $ngx_addon_dir/src/ngx_http_lua_pipe.c \ " HTTP_LUA_DEPS=" \ @@ -424,8 +422,6 @@ HTTP_LUA_DEPS=" \ $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_log_ringbuf.h \ - $ngx_addon_dir/src/ngx_http_lua_input_filters.h \ - $ngx_addon_dir/src/ngx_http_lua_pipe.h \ " CFLAGS="$CFLAGS -DNDK_SET_VAR" @@ -478,17 +474,6 @@ ngx_feature_test='setsockopt(1, SOL_SOCKET, SO_PASSCRED, NULL, 0);' . auto/feature -ngx_feature="SA_RESTART" -ngx_feature_libs= -ngx_feature_name="NGX_HTTP_LUA_HAVE_SA_RESTART" -ngx_feature_run=no -ngx_feature_incs="#include " -ngx_feature_path= -ngx_feature_test='struct sigaction act; - act.sa_flags |= SA_RESTART;' - -. auto/feature - ngx_feature="__attribute__(constructor)" ngx_feature_libs= ngx_feature_name="NGX_HTTP_LUA_HAVE_CONSTRUCTOR" @@ -527,36 +512,6 @@ CC_TEST_FLAGS="$SAVED_CC_TEST_FLAGS" # ---------------------------------------- -ngx_feature="pipe2" -ngx_feature_libs= -ngx_feature_name="NGX_HTTP_LUA_HAVE_PIPE2" -ngx_feature_run=no -ngx_feature_incs="#include " -ngx_feature_test="int fd[2]; pipe2(fd, O_CLOEXEC|O_NONBLOCK);" -SAVED_CC_TEST_FLAGS="$CC_TEST_FLAGS" -CC_TEST_FLAGS="-Werror -Wall $CC_TEST_FLAGS" - -. auto/feature - -CC_TEST_FLAGS="$SAVED_CC_TEST_FLAGS" - -# ---------------------------------------- - -ngx_feature="signalfd" -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);" -SAVED_CC_TEST_FLAGS="$CC_TEST_FLAGS" -CC_TEST_FLAGS="-Werror -Wall $CC_TEST_FLAGS" - -. auto/feature - -CC_TEST_FLAGS="$SAVED_CC_TEST_FLAGS" - -# ---------------------------------------- - if test -n "$ngx_module_link"; then ngx_module_type=HTTP_AUX_FILTER ngx_module_name=$ngx_addon_name diff --git a/debian/modules/http-lua/doc/HttpLuaModule.wiki b/debian/modules/http-lua/doc/HttpLuaModule.wiki index ff9b269..e3c61e2 100644 --- a/debian/modules/http-lua/doc/HttpLuaModule.wiki +++ b/debian/modules/http-lua/doc/HttpLuaModule.wiki @@ -2,8 +2,6 @@ ngx_http_lua_module - Embed the power of Lua into Nginx HTTP Servers. -This module is a core component of OpenResty. If you are using this module, then you are essentially using OpenResty :) - ''This module is not distributed with the Nginx source.'' See [[#Installation|the installation instructions]]. = Status = @@ -12,7 +10,7 @@ Production ready. = Version = -This document describes ngx_lua [https://github.com/openresty/lua-nginx-module/tags v0.10.15] released on March 14th, 2019. +This document describes ngx_lua [https://github.com/openresty/lua-nginx-module/tags v0.10.13] released on 22 April 2018. = Synopsis = @@ -132,9 +130,7 @@ This document describes ngx_lua [https://github.com/openresty/lua-nginx-module/t = Description = -This module is a core component of OpenResty. If you are using this module, then you are essentially using OpenResty :) - -This module embeds Lua, via [http://luajit.org/luajit.html LuaJIT 2.0/2.1], into Nginx and by leveraging Nginx's subrequests, allows the integration of the powerful Lua threads (Lua coroutines) into the Nginx event model. +This module embeds Lua, via the standard Lua 5.1 interpreter or [http://luajit.org/luajit.html LuaJIT 2.0/2.1], into Nginx and by leveraging Nginx's subrequests, allows the integration of the powerful Lua threads (Lua coroutines) into the Nginx event model. Unlike [https://httpd.apache.org/docs/trunk/mod/mod_lua.html Apache's mod_lua] and [http://redmine.lighttpd.net/wiki/1/Docs:ModMagnet Lighttpd's mod_magnet], Lua code executed using this module can be ''100% non-blocking'' on network traffic as long as the [[#Nginx API for Lua|Nginx API for Lua]] provided by this module is used to handle requests to upstream services such as MySQL, PostgreSQL, Memcached, Redis, or upstream HTTP web services. @@ -203,11 +199,11 @@ Nginx cores older than 1.6.0 (exclusive) are *not* supported. = Installation = -It is *highly* recommended to use [http://openresty.org OpenResty releases] which integrate Nginx, ngx_lua, OpenResty's LuaJIT 2.1 branch version, as well as other powerful companion Nginx modules and Lua libraries. It is discouraged to build this module with nginx yourself since it is tricky to set up exactly right. Also, the stock nginx cores have various limitations and long standing bugs that can make some of this modules' features become disabled, not work properly, or run slower. The same applies to LuaJIT as well. OpenResty includes its own version of LuaJIT which gets specifically optimized and enhanced for the OpenResty environment. +It is *highly* recommended to use [http://openresty.org OpenResty releases] which integrate Nginx, ngx_lua, LuaJIT 2.1, as well as other powerful companion Nginx modules and Lua libraries. It is discouraged to build this module with nginx yourself since it is tricky to set up exactly right. Also, the stock nginx cores have various limitations and long standing bugs that can make some of this modules' features become disabled, not work properly, or run slower. The same applies to LuaJIT as well. OpenResty includes its own version of LuaJIT which gets specifically optimized and enhanced for the OpenResty environment. Alternatively, ngx_lua can be manually compiled into Nginx: -# LuaJIT can be downloaded from the [https://github.com/openresty/luajit2/releases latest release of OpenResty's LuaJIT branch version]. The official LuaJIT 2.0 and 2.1 releases are also supported, although the performance will be significantly lower in many cases. +# Install LuaJIT 2.0 or 2.1 (recommended) or Lua 5.1 (Lua 5.2 is ''not'' supported yet). LuaJIT can be downloaded from the [http://luajit.org/download.html LuaJIT project website] and Lua 5.1, from the [http://www.lua.org/ Lua project website]. Some distribution package managers also distribute LuaJIT and/or Lua. # Download the latest version of the ngx_devel_kit (NDK) module [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 version of Nginx [http://nginx.org/ HERE] (See [[#Nginx Compatibility|Nginx Compatibility]]) @@ -275,6 +271,24 @@ To enable one or more of these macros, just pass extra C compiler options to the ./configure --with-cc-opt="-DNGX_LUA_USE_ASSERT -DNGX_LUA_ABORT_AT_PANIC" +== Installation on Ubuntu 11.10 == + +Note that it is recommended to use LuaJIT 2.0 or LuaJIT 2.1 instead of the standard Lua 5.1 interpreter wherever possible. + +If the standard Lua 5.1 interpreter is required however, run the following command to install it from the Ubuntu repository: + + +apt-get install -y lua5.1 liblua5.1-0 liblua5.1-0-dev + + +Everything should be installed correctly, except for one small tweak. + +Library name liblua.so has been changed in liblua5.1 package, it only comes with liblua5.1.so, which needs to be symlinked to /usr/lib so it could be found during the configuration process. + + +ln -s /usr/lib/x86_64-linux-gnu/liblua5.1.so /usr/lib/liblua.so + + = Community = == English Mailing List == @@ -300,7 +314,7 @@ Please submit bug reports, wishlists, or patches by As from the v0.5.0rc32 release, all *_by_lua_file configure directives (such as [[#content_by_lua_file|content_by_lua_file]]) support loading Lua 5.1 and LuaJIT 2.0/2.1 raw bytecode files directly. -Please note that the bytecode format used by LuaJIT 2.0/2.1 is not compatible with that used by the standard Lua 5.1 interpreter. So if you are using LuaJIT 2.0/2.1 with ngx_lua, LuaJIT compatible bytecode files must be generated as shown: +Please note that the bytecode format used by LuaJIT 2.0/2.1 is not compatible with that used by the standard Lua 5.1 interpreter. So if using LuaJIT 2.0/2.1 with ngx_lua, LuaJIT compatible bytecode files must be generated as shown: /path/to/luajit/bin/luajit -b /path/to/input_file.lua /path/to/output_file.ljbc @@ -318,6 +332,18 @@ http://luajit.org/running.html#opt_b Also, the bytecode files generated by LuaJIT 2.1 is ''not'' compatible with LuaJIT 2.0, and vice versa. The support for LuaJIT 2.1 bytecode was first added in ngx_lua v0.9.3. +Similarly, if using the standard Lua 5.1 interpreter with ngx_lua, Lua compatible bytecode files must be generated using the luac commandline utility as shown: + + + luac -o /path/to/output_file.luac /path/to/input_file.lua + + +Unlike as with LuaJIT, debug information is included in standard Lua 5.1 bytecode files by default. This can be striped out by specifying the -s option as shown: + + + luac -s -o /path/to/output_file.luac /path/to/input_file.lua + + Attempts to load standard Lua 5.1 bytecode files into ngx_lua instances linked to LuaJIT 2.0/2.1 or vice versa, will result in an error message, such as that below, being logged into the Nginx error.log file: @@ -484,7 +510,8 @@ However, later attempts to manipulate the cosocket object will fail and return t This issue is due to limitations in the Nginx event model and only appears to affect Mac OS X. == Lua Coroutine Yielding/Resuming == -* Because Lua's dofile and require builtins are currently implemented as C functions in LuaJIT 2.0/2.1, if the Lua file being loaded by dofile or require invokes [[#ngx.location.capture|ngx.location.capture*]], [[#ngx.exec|ngx.exec]], [[#ngx.exit|ngx.exit]], or other API functions requiring yielding in the *top-level* scope of the Lua file, then the Lua error "attempt to yield across C-call boundary" will be raised. To avoid this, put these calls requiring yielding into your own Lua functions in the Lua file instead of the top-level scope of the file. +* Because Lua's dofile and require builtins are currently implemented as C functions in both Lua 5.1 and LuaJIT 2.0/2.1, if the Lua file being loaded by dofile or require invokes [[#ngx.location.capture|ngx.location.capture*]], [[#ngx.exec|ngx.exec]], [[#ngx.exit|ngx.exit]], or other API functions requiring yielding in the *top-level* scope of the Lua file, then the Lua error "attempt to yield across C-call boundary" will be raised. To avoid this, put these calls requiring yielding into your own Lua functions in the Lua file instead of the top-level scope of the file. +* As the standard Lua 5.1 interpreter's VM is not fully resumable, the methods [[#ngx.location.capture|ngx.location.capture]], [[#ngx.location.capture_multi|ngx.location.capture_multi]], [[#ngx.redirect|ngx.redirect]], [[#ngx.exec|ngx.exec]], and [[#ngx.exit|ngx.exit]] cannot be used within the context of a Lua [http://www.lua.org/manual/5.1/manual.html#pdf-pcall pcall()] or [http://www.lua.org/manual/5.1/manual.html#pdf-xpcall xpcall()] or even the first line of the for ... in ... statement when the standard Lua 5.1 interpreter is used and the attempt to yield across metamethod/C-call boundary error will be produced. Please use LuaJIT 2.x, which supports a fully resumable VM, to avoid this. == Lua Variable Scope == Care must be taken when importing modules and this form should be used: @@ -790,7 +817,7 @@ This module is licensed under the BSD license. Copyright (C) 2009-2017, by Xiaozhe Wang (chaoslawful) . -Copyright (C) 2009-2019, by Yichun "agentzh" Zhang (章亦春) , OpenResty Inc. +Copyright (C) 2009-2018, by Yichun "agentzh" Zhang (章亦春) , OpenResty Inc. All rights reserved. @@ -835,34 +862,6 @@ how the result will be used. Below is a diagram showing the order in which direc ![Lua Nginx Modules Directives](https://cloud.githubusercontent.com/assets/2137369/15272097/77d1c09e-1a37-11e6-97ef-d9767035fc3e.png) -== lua_load_resty_core == - -'''syntax:''' ''lua_load_resty_core on|off'' - -'''default:''' ''lua_load_resty_core on'' - -'''context:''' ''http'' - -Controls whether the resty.core module (from -[https://github.com/openresty/lua-resty-core lua-resty-core]) should be loaded -or not. When enabled, this directive is equivalent to executing the following -when the Lua VM is created: - - - require "resty.core" - - -Note that usage of the resty.core module is recommended, as its -FFI implementation is both faster, safer, and more complete than the Lua C API -of the ngx_lua module. - -It must also be noted that the Lua C API of the ngx_lua module will eventually -be removed, and usage of the FFI-based API (i.e. the resty.core -module) will become mandatory. This directive only aims at providing a -temporary backwards-compatibility mode in case of edge-cases. - -This directive was first introduced in the v0.10.15 release. - == lua_capture_error_log == '''syntax:''' ''lua_capture_error_log size'' @@ -2197,14 +2196,14 @@ SSL session resumption can then get immediately initiated and bypass the full SS Please note that TLS session tickets are very different and it is the clients' responsibility to cache the SSL session state when session tickets are used. SSL session resumptions based on TLS session tickets would happen automatically without going through this hook (nor the -[[#ssl_session_store_by_lua_block|ssl_session_store_by_lua*]] hook). This hook is mainly +[[#ssl_session_store_by_lua*|ssl_session_store_by_lua_block]] hook). This hook is mainly for older or less capable SSL clients that can only do SSL sessions by session IDs. When [[#ssl_certificate_by_lua_block|ssl_certificate_by_lua*]] is specified at the same time, this hook usually runs before [[#ssl_certificate_by_lua_block|ssl_certificate_by_lua*]]. When the SSL session is found and successfully loaded for the current SSL connection, SSL session resumption will happen and thus bypass the [[#ssl_certificate_by_lua_block|ssl_certificate_by_lua*]] -hook completely. In this case, NGINX also bypasses the [[#ssl_session_store_by_lua_block|ssl_session_store_by_lua*]] +hook completely. In this case, NGINX also bypasses the [[#ssl_session_store_by_lua*|ssl_session_store_by_lua_block]] hook, for obvious reasons. To easily test this hook locally with a modern web browser, you can temporarily put the following line @@ -2627,20 +2626,6 @@ When exceeding this limit, Nginx will stop running the callbacks of newly expire This directive was first introduced in the v0.8.0 release. -== lua_sa_restart == - -'''syntax:''' ''lua_sa_restart on|off'' - -'''default:''' ''lua_sa_restart on'' - -'''context:''' ''http'' - -When enabled, this module will set the `SA_RESTART` flag on nginx workers signal dispositions. - -This allows Lua I/O primitives to not be interrupted by nginx's handling of various signals. - -This directive was first introduced in the v0.10.14 release. - = Nginx API for Lua = @@ -3578,7 +3563,7 @@ This method does not work in HTTP/2 requests yet. == ngx.req.get_method == '''syntax:''' ''method_name = ngx.req.get_method()'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, balancer_by_lua*, log_by_lua*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, balancer_by_lua*'' Retrieves the current request's request method name. Strings like "GET" and "POST" are returned instead of numerical [[#HTTP method constants|method constants]]. @@ -4086,7 +4071,7 @@ This function returns nil if # the request body has been read into disk temporary files, # or the request body has zero size. -If the request body has not been read yet, call [[#ngx.req.read_body|ngx.req.read_body]] first (or turn on [[#lua_need_request_body|lua_need_request_body]] to force this module to read the request body. This is not recommended however). +If the request body has not been read yet, call [[#ngx.req.read_body|ngx.req.read_body]] first (or turned on [[#lua_need_request_body|lua_need_request_body]] to force this module to read the request body. This is not recommended however). If the request body has been read into disk files, try calling the [[#ngx.req.get_body_file|ngx.req.get_body_file]] function instead. @@ -4107,7 +4092,7 @@ Retrieves the file name for the in-file request body data. Returns nildata argument. -If the request body has not been read yet, call [[#ngx.req.read_body|ngx.req.read_body]] first (or turn on [[#lua_need_request_body|lua_need_request_body]] to force this module to read the request body. This is not recommended however). Additionally, the request body must not have been previously discarded by [[#ngx.req.discard_body|ngx.req.discard_body]]. - -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. +If the current request's request body has not been read, then it will be properly discarded. When the current request's request body has been read into memory or buffered into a disk file, then the old request body's memory will be freed or the disk file will be cleaned up immediately, respectively. This function was first introduced in the v0.3.1rc18 release. @@ -4139,13 +4122,11 @@ See also [[#ngx.req.set_body_file|ngx.req.set_body_file]]. Set the current request's request body using the in-file data specified by the file_name argument. -If the request body has not been read yet, call [[#ngx.req.read_body|ngx.req.read_body]] first (or turn on [[#lua_need_request_body|lua_need_request_body]] to force this module to read the request body. This is not recommended however). Additionally, the request body must not have been previously discarded by [[#ngx.req.discard_body|ngx.req.discard_body]]. - If the optional auto_clean argument is given a true value, then this file will be removed at request completion or the next time this function or [[#ngx.req.set_body_data|ngx.req.set_body_data]] are called in the same request. The auto_clean is default to false. Please ensure that the file specified by the file_name argument exists and is readable by an Nginx worker process by setting its permission properly to avoid Lua exception errors. -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. +If the current request's request body has not been read, then it will be properly discarded. When the current request's request body has been read into memory or buffered into a disk file, then the old request body's memory will be freed or the disk file will be cleaned up immediately, respectively. This function was first introduced in the v0.3.1rc18 release. @@ -5667,7 +5648,7 @@ See also [[#ngx.shared.DICT.flush_expired|ngx.shared.DICT.flush_expired]] and [[ Flushes out the expired items in the dictionary, up to the maximal number specified by the optional max_count argument. When the max_count argument is given 0 or not given at all, then it means unlimited. Returns the number of items that have actually been flushed. -Unlike the [[#ngx.shared.DICT.flush_all|flush_all]] method, this method actually frees up the memory used by the expired items. +Unlike the [[#ngx.shared.DICT.flush_all|flush_all]] method, this method actually free up the memory used by the expired items. This feature was first introduced in the v0.6.3 release. @@ -5913,7 +5894,6 @@ Creates and returns a TCP or stream-oriented unix domain socket object (also kno * [[#tcpsock:settimeout|settimeout]] * [[#tcpsock:settimeouts|settimeouts]] * [[#tcpsock:setoption|setoption]] -* [[#tcpsock:receiveany|receiveany]] * [[#tcpsock:receiveuntil|receiveuntil]] * [[#tcpsock:setkeepalive|setkeepalive]] * [[#tcpsock:getreusedtimes|getreusedtimes]] @@ -6011,43 +5991,6 @@ An optional Lua table can be specified as the last argument to this method to sp * pool : specify a custom name for the connection pool being used. If omitted, then the connection pool name will be generated from the string template ":" or "". -* pool_size -: specify the size of the connection pool. If omitted and no -: backlog option was provided, no pool will be created. If omitted -: but backlog was provided, the pool will be created with a default -: size equal to the value of the [[#lua_socket_pool_size|lua_socket_pool_size]] -: directive. -: The connection pool holds up to pool_size alive connections -: ready to be reused by subsequent calls to [[#tcpsock:connect|connect]], but -: note that there is no upper limit to the total number of opened connections -: outside of the pool. If you need to restrict the total number of opened -: connections, specify the backlog option. -: When the connection pool would exceed its size limit, the least recently used -: (kept-alive) connection already in the pool will be closed to make room for -: the current connection. -: Note that the cosocket connection pool is per Nginx worker process rather -: than per Nginx server instance, so the size limit specified here also applies -: to every single Nginx worker process. Also note that the size of the connection -: pool cannot be changed once it has been created. -: This option was first introduced in the v0.10.14 release. - -* 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). -: 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 operation will abort once they have been queued for more -: than connect_timeout, controlled by -: [[#tcpsock:settimeouts|settimeouts]], and will return nil plus -: the error string "timeout". -: This option was first introduced in the v0.10.14 release. - The support for the options table argument was first introduced in the v0.5.7 release. This method was first introduced in the v0.5.0rc1 release. @@ -6160,36 +6103,6 @@ Since the v0.8.8 release, this method no longer automatically close This feature was first introduced in the v0.5.0rc1 release. -== tcpsock:receiveany == -'''syntax:''' ''data, err = tcpsock:receiveany(max)'' - -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*'' - -Returns any data received by the connected socket, at most max bytes. - -This method is a synchronous operation just like the [[#tcpsock:send|send]] method and is 100% nonblocking. - -In case of success, it returns the data received; in case of error, it returns nil with a string describing the error. - -If the received data is more than this size, this method will return with exactly this size of data. -The remaining data in the underlying receive buffer could be returned in the next reading operation. - -Timeout for the reading operation is controlled by the [[#lua_socket_read_timeout|lua_socket_read_timeout]] config directive and the [[#tcpsock:settimeouts|settimeouts]] method. And the latter takes priority. For example: - - - sock:settimeouts(1000, 1000, 1000) -- one second timeout for connect/read/write - local data, err = sock:receiveany(10 * 1024 * 1024) -- read any data, at most 10K - if not data then - ngx.say("failed to read any data: ", err) - return - end - ngx.say("successfully read: ", data) - - -This method doesn't automatically close the current connection when the read timeout error occurs. For other connection errors, this method always automatically closes the connection. - -This feature was first introduced in the v0.10.14 release. - == tcpsock:receiveuntil == '''syntax:''' ''iterator = tcpsock:receiveuntil(pattern, options?)'' @@ -6342,31 +6255,13 @@ Puts the current socket's connection immediately into the cosocket built-in conn The first optional argument, timeout, can be used to specify the maximal idle timeout (in milliseconds) for the current connection. If omitted, the default setting in the [[#lua_socket_keepalive_timeout|lua_socket_keepalive_timeout]] config directive will be used. If the 0 value is given, then the timeout interval is unlimited. -The second optional argument size is considered deprecated since -the v0.10.14 release of this module, in favor of the -pool_size option of the [[#tcpsock:connect|connect]] method. -Since the v0.10.14 release, this option will only take effect if -the call to [[#tcpsock:connect|connect]] did not already create a connection -pool. -When this option takes effect (no connection pool was previously created by -[[#tcpsock:connect|connect]]), it will specify the size of the connection pool, -and create it. -If omitted (and no pool was previously created), the default size is the value -of the [[#lua_socket_pool_size|lua_socket_pool_size]] directive. -The connection pool holds up to size alive connections ready to be -reused by subsequent calls to [[#tcpsock:connect|connect]], but note that there -is no upper limit to the total number of opened connections outside of the -pool. -When the connection pool would exceed its size limit, the least recently used -(kept-alive) connection already in the pool will be closed to make room for -the current connection. -Note that the cosocket connection pool is per Nginx worker process rather -than per Nginx server instance, so the size limit specified here also applies -to every single Nginx worker process. Also note that the size of the connection -pool cannot be changed once it has been created. -If you need to restrict the total number of opened connections, specify both -the pool_size and backlog option in the call to -[[#tcpsock:connect|connect]]. +The second optional argument, size, can be used to specify the maximal number of connections allowed in the connection pool for the current server (i.e., the current host-port pair or the unix domain socket file path). Note that the size of the connection pool cannot be changed once the pool is created. When this argument is omitted, the default setting in the [[#lua_socket_pool_size|lua_socket_pool_size]] config directive will be used. + +When the connection pool exceeds the available size limit, the least recently used (idle) connection already in the pool will be closed to make room for the current connection. + +Note that the cosocket connection pool is per Nginx worker process rather than per Nginx server instance, so the size limit specified here also applies to every single Nginx worker process. + +Idle connections in the pool will be monitored for any exceptional events like connection abortion or unexpected incoming data on the line, in which cases the connection in question will be closed and removed from the pool. In case of success, this method returns 1; otherwise, it returns nil and a string describing the error. @@ -7055,7 +6950,7 @@ This Lua module does not ship with this ngx_lua module itself rather it is shipp the [https://github.com/openresty/lua-resty-core lua-resty-core] library. -Please refer to the [https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ocsp.md documentation] +Please refer to the [https://github.com/openresty/lua-resty-core/blob/ocsp-cert-by-lua-2/lib/ngx/ocsp.md documentation] for this ngx.ocsp Lua module for more details. This feature requires at least ngx_lua v0.10.0. diff --git a/debian/modules/http-lua/src/api/ngx_http_lua_api.h b/debian/modules/http-lua/src/api/ngx_http_lua_api.h index 129eb99..c7c0e6b 100644 --- a/debian/modules/http-lua/src/api/ngx_http_lua_api.h +++ b/debian/modules/http-lua/src/api/ngx_http_lua_api.h @@ -19,7 +19,7 @@ /* Public API for other Nginx modules */ -#define ngx_http_lua_version 10015 +#define ngx_http_lua_version 10013 typedef struct { diff --git a/debian/modules/http-lua/src/ngx_http_lua_accessby.c b/debian/modules/http-lua/src/ngx_http_lua_accessby.c index d3fe294..56bf0fa 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_accessby.c +++ b/debian/modules/http-lua/src/ngx_http_lua_accessby.c @@ -60,7 +60,7 @@ ngx_http_lua_access_handler(ngx_http_request_t *r) #endif if (cur_ph < last_ph) { - dd("swapping the contents of cur_ph and last_ph..."); + dd("swaping the contents of cur_ph and last_ph..."); tmp = *cur_ph; @@ -261,11 +261,9 @@ ngx_http_lua_access_by_chunk(lua_State *L, ngx_http_request_t *r) /* 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); diff --git a/debian/modules/http-lua/src/ngx_http_lua_api.c b/debian/modules/http-lua/src/ngx_http_lua_api.c index ac014f2..7b590e7 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_api.c +++ b/debian/modules/http-lua/src/ngx_http_lua_api.c @@ -195,7 +195,7 @@ ngx_http_lua_shared_memory_init(ngx_shm_zone_t *shm_zone, void *data) lmcf->shm_zones_inited++; if (lmcf->shm_zones_inited == lmcf->shm_zones->nelts - && lmcf->init_handler && !ngx_test_config) + && lmcf->init_handler) { saved_cycle = ngx_cycle; ngx_cycle = ctx->cycle; diff --git a/debian/modules/http-lua/src/ngx_http_lua_balancer.c b/debian/modules/http-lua/src/ngx_http_lua_balancer.c index 3ecd592..fdf2af3 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_balancer.c +++ b/debian/modules/http-lua/src/ngx_http_lua_balancer.c @@ -362,8 +362,6 @@ ngx_http_lua_balancer_by_chunk(lua_State *L, ngx_http_request_t *r) /* init nginx context in Lua VM */ ngx_http_lua_set_req(L, r); - -#ifndef OPENRESTY_LUAJIT ngx_http_lua_create_new_globals_table(L, 0 /* narr */, 1 /* nrec */); /* {{{ make new env inheriting main thread's globals table */ @@ -374,7 +372,6 @@ ngx_http_lua_balancer_by_chunk(lua_State *L, ngx_http_request_t *r) /* }}} */ lua_setfenv(L, -2); /* set new running env for the code closure */ -#endif /* OPENRESTY_LUAJIT */ lua_pushcfunction(L, ngx_http_lua_traceback); lua_insert(L, 1); /* put it under chunk and args */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_bodyfilterby.c b/debian/modules/http-lua/src/ngx_http_lua_bodyfilterby.c index f3af14c..2b3c38f 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_bodyfilterby.c +++ b/debian/modules/http-lua/src/ngx_http_lua_bodyfilterby.c @@ -32,6 +32,10 @@ static void ngx_http_lua_body_filter_by_lua_env(lua_State *L, static ngx_http_output_body_filter_pt ngx_http_next_body_filter; +/* key for the ngx_chain_t *in pointer in the Lua thread */ +#define ngx_http_lua_chain_key "__ngx_cl" + + /** * Set environment table for the given code closure. * @@ -47,14 +51,12 @@ static void ngx_http_lua_body_filter_by_lua_env(lua_State *L, ngx_http_request_t *r, ngx_chain_t *in) { - ngx_http_lua_main_conf_t *lmcf; - + /* set nginx request pointer to current lua thread's globals table */ ngx_http_lua_set_req(L, r); - lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); - lmcf->body_filter_chain = in; + lua_pushlightuserdata(L, in); + lua_setglobal(L, ngx_http_lua_chain_key); -#ifndef OPENRESTY_LUAJIT /** * we want to create empty environment for current script * @@ -77,7 +79,6 @@ ngx_http_lua_body_filter_by_lua_env(lua_State *L, ngx_http_request_t *r, /* }}} */ lua_setfenv(L, -2); /* set new running env for the code closure */ -#endif /* OPENRESTY_LUAJIT */ } @@ -235,8 +236,8 @@ ngx_http_lua_body_filter(ngx_http_request_t *r, ngx_chain_t *in) ngx_int_t rc; uint16_t old_context; ngx_http_cleanup_t *cln; + lua_State *L; ngx_chain_t *out; - ngx_http_lua_main_conf_t *lmcf; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua body filter for user lua code, uri \"%V\"", &r->uri); @@ -298,8 +299,11 @@ ngx_http_lua_body_filter(ngx_http_request_t *r, ngx_chain_t *in) return NGX_ERROR; } - lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); - out = lmcf->body_filter_chain; + L = ngx_http_lua_get_lua_vm(r, ctx); + + lua_getglobal(L, ngx_http_lua_chain_key); + out = lua_touserdata(L, -1); + lua_pop(L, 1); if (in == out) { return ngx_http_next_body_filter(r, in); @@ -341,7 +345,7 @@ 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_body_filter_param_get(lua_State *L) { u_char *data, *p; size_t size; @@ -350,8 +354,6 @@ ngx_http_lua_body_filter_param_get(lua_State *L, ngx_http_request_t *r) int idx; ngx_chain_t *in; - ngx_http_lua_main_conf_t *lmcf; - idx = luaL_checkint(L, 2); dd("index: %d", idx); @@ -361,8 +363,8 @@ ngx_http_lua_body_filter_param_get(lua_State *L, ngx_http_request_t *r) return 1; } - lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); - in = lmcf->body_filter_chain; + lua_getglobal(L, ngx_http_lua_chain_key); + in = lua_touserdata(L, -1); if (idx == 2) { /* asking for the eof argument */ @@ -440,8 +442,6 @@ ngx_http_lua_body_filter_param_set(lua_State *L, ngx_http_request_t *r, ngx_chain_t *cl; ngx_chain_t *in; - ngx_http_lua_main_conf_t *lmcf; - idx = luaL_checkint(L, 2); dd("index: %d", idx); @@ -450,13 +450,13 @@ ngx_http_lua_body_filter_param_set(lua_State *L, ngx_http_request_t *r, return luaL_error(L, "bad index: %d", idx); } - lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); - if (idx == 2) { /* overwriting the eof flag */ last = lua_toboolean(L, 3); - in = lmcf->body_filter_chain; + lua_getglobal(L, ngx_http_lua_chain_key); + in = lua_touserdata(L, -1); + lua_pop(L, 1); if (last) { ctx->seen_last_in_filter = 1; @@ -521,7 +521,9 @@ ngx_http_lua_body_filter_param_set(lua_State *L, ngx_http_request_t *r, case LUA_TNIL: /* discard the buffers */ - in = lmcf->body_filter_chain; + lua_getglobal(L, ngx_http_lua_chain_key); /* key val */ + in = lua_touserdata(L, -1); + lua_pop(L, 1); last = 0; @@ -555,7 +557,9 @@ ngx_http_lua_body_filter_param_set(lua_State *L, ngx_http_request_t *r, lua_typename(L, type)); } - in = lmcf->body_filter_chain; + lua_getglobal(L, ngx_http_lua_chain_key); + in = lua_touserdata(L, -1); + lua_pop(L, 1); last = 0; @@ -621,8 +625,8 @@ done: } } - lmcf->body_filter_chain = cl; - + lua_pushlightuserdata(L, cl); + lua_setglobal(L, ngx_http_lua_chain_key); return 0; } diff --git a/debian/modules/http-lua/src/ngx_http_lua_bodyfilterby.h b/debian/modules/http-lua/src/ngx_http_lua_bodyfilterby.h index b108202..6a4b306 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_bodyfilterby.h +++ b/debian/modules/http-lua/src/ngx_http_lua_bodyfilterby.h @@ -21,7 +21,7 @@ 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_get(lua_State *L); int ngx_http_lua_body_filter_param_set(lua_State *L, ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx); diff --git a/debian/modules/http-lua/src/ngx_http_lua_cache.c b/debian/modules/http-lua/src/ngx_http_lua_cache.c index 5b29527..5ea3069 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_cache.c +++ b/debian/modules/http-lua/src/ngx_http_lua_cache.c @@ -35,14 +35,11 @@ static ngx_int_t ngx_http_lua_cache_load_code(ngx_log_t *log, lua_State *L, const char *key) { -#ifndef OPENRESTY_LUAJIT int rc; u_char *err; -#endif /* get code cache table */ - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - code_cache_key)); + lua_pushlightuserdata(L, &ngx_http_lua_code_cache_key); lua_rawget(L, LUA_REGISTRYINDEX); /* sp++ */ dd("Code cache table to load: %p", lua_topointer(L, -1)); @@ -55,10 +52,6 @@ ngx_http_lua_cache_load_code(ngx_log_t *log, lua_State *L, lua_getfield(L, -1, key); /* sp++ */ if (lua_isfunction(L, -1)) { -#ifdef OPENRESTY_LUAJIT - lua_remove(L, -2); /* sp-- */ - return NGX_OK; -#else /* call closure factory to gen new closure */ rc = lua_pcall(L, 0, 1, 0); if (rc == 0) { @@ -80,7 +73,6 @@ ngx_http_lua_cache_load_code(ngx_log_t *log, lua_State *L, key, err); lua_pop(L, 2); return NGX_ERROR; -#endif /* OPENRESTY_LUAJIT */ } dd("Value associated with given key in code cache table is not code " @@ -110,13 +102,10 @@ ngx_http_lua_cache_load_code(ngx_log_t *log, lua_State *L, static ngx_int_t ngx_http_lua_cache_store_code(lua_State *L, const char *key) { -#ifndef OPENRESTY_LUAJIT int rc; -#endif /* get code cache table */ - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - code_cache_key)); + lua_pushlightuserdata(L, &ngx_http_lua_code_cache_key); lua_rawget(L, LUA_REGISTRYINDEX); dd("Code cache table to store: %p", lua_topointer(L, -1)); @@ -132,14 +121,12 @@ ngx_http_lua_cache_store_code(lua_State *L, const char *key) /* remove cache table, leave closure factory at top of stack */ lua_pop(L, 1); /* closure */ -#ifndef OPENRESTY_LUAJIT /* call closure factory to generate new closure */ rc = lua_pcall(L, 0, 1, 0); if (rc != 0) { dd("Error: failed to call closure factory!!"); return NGX_ERROR; } -#endif return NGX_OK; } @@ -156,8 +143,7 @@ ngx_http_lua_cache_loadbuffer(ngx_log_t *log, lua_State *L, n = lua_gettop(L); - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, - "looking up Lua code cache with key '%s'", cache_key); + dd("XXX cache key: [%s]", cache_key); rc = ngx_http_lua_cache_load_code(log, L, (char *) cache_key); if (rc == NGX_OK) { @@ -241,8 +227,7 @@ ngx_http_lua_cache_loadfile(ngx_log_t *log, lua_State *L, dd("CACHE file key already pre-calculated"); } - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, - "looking up Lua code cache with key '%s'", cache_key); + dd("XXX cache key for file: [%s]", cache_key); rc = ngx_http_lua_cache_load_code(log, L, (char *) cache_key); if (rc == NGX_OK) { diff --git a/debian/modules/http-lua/src/ngx_http_lua_clfactory.c b/debian/modules/http-lua/src/ngx_http_lua_clfactory.c index 754ed8d..041f046 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_clfactory.c +++ b/debian/modules/http-lua/src/ngx_http_lua_clfactory.c @@ -15,13 +15,11 @@ #include "ngx_http_lua_clfactory.h" -#ifndef OPENRESTY_LUAJIT #define CLFACTORY_BEGIN_CODE "return function() " #define CLFACTORY_BEGIN_SIZE (sizeof(CLFACTORY_BEGIN_CODE) - 1) #define CLFACTORY_END_CODE "\nend" #define CLFACTORY_END_SIZE (sizeof(CLFACTORY_END_CODE) - 1) -#endif /* @@ -61,7 +59,6 @@ * length(Instruction) = 4 or 8 * little endian or big endian */ -#ifndef OPENRESTY_LUAJIT #define LUA_LITTLE_ENDIAN_4BYTES_CODE \ "\x24\x00\x00\x00\x1e\x00\x00\x01\x1e\x00\x80\x00" #define LUA_LITTLE_ENDIAN_8BYTES_CODE \ @@ -78,7 +75,6 @@ #define LUA_BIG_ENDIAN_8BYTES_CODE_LEN (8 + 8 + 8) #define LUAC_HEADERSIZE 12 #define LUAC_VERSION 0x51 -#endif /* OPENRESTY_LUAJIT */ /* @@ -151,7 +147,6 @@ * --------------------- */ -#ifndef OPENRESTY_LUAJIT #define POS_SOURCE_STR_LEN LUAC_HEADERSIZE #define POS_START_LINE (POS_SOURCE_STR_LEN + sizeof(size_t)) #define POS_LAST_LINE (POS_START_LINE + sizeof(int)) @@ -165,7 +160,6 @@ (POS_BYTECODE + LUA_LITTLE_ENDIAN_8BYTES_CODE_LEN \ + sizeof(int) + sizeof(int)) #define MAX_END_CODE_SIZE (sizeof(int) + sizeof(int) + sizeof(int)) -#endif /* OPENRESTY_LUAJIT */ /* * taken from chaoslawful: @@ -231,7 +225,6 @@ /* bytecode for luajit 2.0 */ -#ifndef OPENRESTY_LUAJIT #define LJ20_LITTLE_ENDIAN_CODE_STRIPPED \ "\x14\x03\x00\x01\x00\x01\x00\x03" \ "\x31\x00\x00\x00\x30\x00\x00\x80\x48\x00\x02\x00" \ @@ -282,7 +275,6 @@ #define LJ21_BCDUMP_VERSION 2 #define LJ20_BCDUMP_VERSION 1 #define LJ_SIGNATURE "\x1b\x4c\x4a" -#endif /* OPENRESTY_LUAJIT */ typedef enum { @@ -300,11 +292,10 @@ enum { typedef struct { ngx_http_lua_clfactory_file_type_e file_type; - int extraline; - FILE *f; -#ifndef OPENRESTY_LUAJIT int sent_begin; int sent_end; + int extraline; + FILE *f; size_t begin_code_len; size_t end_code_len; size_t rest_len; @@ -316,16 +307,13 @@ typedef struct { char *ptr; char str[MAX_END_CODE_SIZE]; } end_code; -#endif /* OPENRESTY_LUAJIT */ char buff[NGX_LUA_READER_BUFSIZE]; } ngx_http_lua_clfactory_file_ctx_t; typedef struct { -#ifndef OPENRESTY_LUAJIT int sent_begin; int sent_end; -#endif const char *s; size_t size; } ngx_http_lua_clfactory_buffer_ctx_t; @@ -337,12 +325,9 @@ static int ngx_http_lua_clfactory_errfile(lua_State *L, const char *what, int fname_index); static const char *ngx_http_lua_clfactory_getS(lua_State *L, void *ud, size_t *size); -#ifndef OPENRESTY_LUAJIT static long ngx_http_lua_clfactory_file_size(FILE *f); -#endif -#ifndef OPENRESTY_LUAJIT int ngx_http_lua_clfactory_bytecode_prepare(lua_State *L, ngx_http_lua_clfactory_file_ctx_t *lf, int fname_index) @@ -608,7 +593,6 @@ error: return LUA_ERRFILE; } -#endif /* OPENRESTY_LUAJIT */ ngx_int_t @@ -628,12 +612,10 @@ ngx_http_lua_clfactory_loadfile(lua_State *L, const char *filename) lf.extraline = 0; lf.file_type = NGX_LUA_TEXT_FILE; -#ifndef OPENRESTY_LUAJIT lf.begin_code.ptr = CLFACTORY_BEGIN_CODE; lf.begin_code_len = CLFACTORY_BEGIN_SIZE; lf.end_code.ptr = CLFACTORY_END_CODE; lf.end_code_len = CLFACTORY_END_SIZE; -#endif lua_pushfstring(L, "@%s", filename); @@ -701,27 +683,20 @@ ngx_http_lua_clfactory_loadfile(lua_State *L, const char *filename) /* skip eventual `#!...' */ } -#ifndef OPENRESTY_LUAJIT status = ngx_http_lua_clfactory_bytecode_prepare(L, &lf, fname_index); if (status != 0) { return status; } -#endif lf.extraline = 0; } -#ifndef OPENRESTY_LUAJIT if (lf.file_type == NGX_LUA_TEXT_FILE) { ungetc(c, lf.f); } lf.sent_begin = lf.sent_end = 0; - -#else - ungetc(c, lf.f); -#endif status = lua_load(L, ngx_http_lua_clfactory_getF, &lf, lua_tostring(L, -1)); @@ -750,10 +725,8 @@ ngx_http_lua_clfactory_loadbuffer(lua_State *L, const char *buff, ls.s = buff; ls.size = size; -#ifndef OPENRESTY_LUAJIT ls.sent_begin = 0; ls.sent_end = 0; -#endif return lua_load(L, ngx_http_lua_clfactory_getS, &ls, name); } @@ -762,9 +735,7 @@ ngx_http_lua_clfactory_loadbuffer(lua_State *L, const char *buff, static const char * ngx_http_lua_clfactory_getF(lua_State *L, void *ud, size_t *size) { -#ifndef OPENRESTY_LUAJIT char *buf; -#endif size_t num; ngx_http_lua_clfactory_file_ctx_t *lf; @@ -777,7 +748,6 @@ ngx_http_lua_clfactory_getF(lua_State *L, void *ud, size_t *size) return "\n"; } -#ifndef OPENRESTY_LUAJIT if (lf->sent_begin == 0) { lf->sent_begin = 1; *size = lf->begin_code_len; @@ -791,14 +761,12 @@ ngx_http_lua_clfactory_getF(lua_State *L, void *ud, size_t *size) return buf; } -#endif /* OPENRESTY_LUAJIT */ num = fread(lf->buff, 1, sizeof(lf->buff), lf->f); dd("fread returned %d", (int) num); if (num == 0) { -#ifndef OPENRESTY_LUAJIT if (lf->sent_end == 0) { lf->sent_end = 1; *size = lf->end_code_len; @@ -812,13 +780,11 @@ ngx_http_lua_clfactory_getF(lua_State *L, void *ud, size_t *size) return buf; } -#endif /* OPENRESTY_LUAJIT */ *size = 0; return NULL; } -#ifndef OPENRESTY_LUAJIT if (lf->file_type == NGX_LUA_BT_LJ) { /* skip the footer(\x00) in luajit */ @@ -834,7 +800,6 @@ ngx_http_lua_clfactory_getF(lua_State *L, void *ud, size_t *size) } } } -#endif /* OPENRESTY_LUAJIT */ *size = num; return lf->buff; @@ -868,23 +833,19 @@ ngx_http_lua_clfactory_getS(lua_State *L, void *ud, size_t *size) { ngx_http_lua_clfactory_buffer_ctx_t *ls = ud; -#ifndef OPENRESTY_LUAJIT if (ls->sent_begin == 0) { ls->sent_begin = 1; *size = CLFACTORY_BEGIN_SIZE; return CLFACTORY_BEGIN_CODE; } -#endif if (ls->size == 0) { -#ifndef OPENRESTY_LUAJIT if (ls->sent_end == 0) { ls->sent_end = 1; *size = CLFACTORY_END_SIZE; return CLFACTORY_END_CODE; } -#endif return NULL; } @@ -896,7 +857,6 @@ ngx_http_lua_clfactory_getS(lua_State *L, void *ud, size_t *size) } -#ifndef OPENRESTY_LUAJIT static long ngx_http_lua_clfactory_file_size(FILE *f) { @@ -922,7 +882,6 @@ ngx_http_lua_clfactory_file_size(FILE *f) return len; } -#endif /* OPENRESTY_LUAJIT */ /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_common.h b/debian/modules/http-lua/src/ngx_http_lua_common.h index dae5245..01ef2be 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_common.h +++ b/debian/modules/http-lua/src/ngx_http_lua_common.h @@ -17,7 +17,7 @@ #include #include -#include +#include #include #include @@ -140,15 +140,6 @@ typedef struct { #endif -#if (NGX_PTR_SIZE >= 8 && !defined(_WIN64)) -#define ngx_http_lua_lightudata_mask(ludata) \ - ((void *) ((uintptr_t) (&ngx_http_lua_##ludata) & ((1UL << 47) - 1))) - -#else -#define ngx_http_lua_lightudata_mask(ludata) (&ngx_http_lua_##ludata) -#endif - - typedef struct ngx_http_lua_main_conf_s ngx_http_lua_main_conf_t; typedef union ngx_http_lua_srv_conf_u ngx_http_lua_srv_conf_t; @@ -182,8 +173,6 @@ struct ngx_http_lua_main_conf_s { ngx_cycle_t *cycle; ngx_pool_t *pool; - ngx_flag_t load_resty_core; - ngx_int_t max_pending_timers; ngx_int_t pending_timers; @@ -219,31 +208,9 @@ struct ngx_http_lua_main_conf_s { ngx_str_t init_worker_src; 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 - * concurrent requests when storing the chain - * data pointer in the main conf. - */ - - ngx_http_variable_value_t *setby_args; - /* neither yielding nor recursion is possible in - * set_by_lua*, so there cannot be any races among - * concurrent requests when storing the args pointer - * in the main conf. - */ - - size_t setby_nargs; - /* neither yielding nor recursion is possible in - * set_by_lua*, so there cannot be any races among - * concurrent requests when storing the nargs in the - * main conf. + /* 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. */ ngx_uint_t shm_zones_inited; @@ -260,10 +227,6 @@ struct ngx_http_lua_main_conf_s { ngx_int_t busy_buf_ptr_count; #endif - ngx_int_t host_var_index; - - ngx_flag_t set_sa_restart; - unsigned requires_header_filter:1; unsigned requires_body_filter:1; unsigned requires_capture_filter:1; @@ -481,7 +444,7 @@ typedef struct { typedef struct ngx_http_lua_ctx_s { - /* for lua_code_cache off: */ + /* for lua_coce_cache off: */ ngx_http_lua_vm_state_t *vm_state; ngx_http_request_t *request; @@ -568,8 +531,6 @@ typedef struct ngx_http_lua_ctx_s { unsigned headers_set:1; /* whether the user has set custom response headers */ - unsigned mime_set:1; /* whether the user has set Content-Type - response header */ unsigned entered_rewrite_phase:1; unsigned entered_access_phase:1; diff --git a/debian/modules/http-lua/src/ngx_http_lua_contentby.c b/debian/modules/http-lua/src/ngx_http_lua_contentby.c index 274c9ad..ecd6c0e 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_contentby.c +++ b/debian/modules/http-lua/src/ngx_http_lua_contentby.c @@ -63,11 +63,9 @@ ngx_http_lua_content_by_chunk(lua_State *L, ngx_http_request_t *r) /* 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); diff --git a/debian/modules/http-lua/src/ngx_http_lua_control.c b/debian/modules/http-lua/src/ngx_http_lua_control.c index 5cd1d64..6ac2cbf 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_control.c +++ b/debian/modules/http-lua/src/ngx_http_lua_control.c @@ -432,8 +432,7 @@ ngx_http_lua_on_abort(lua_State *L) ngx_http_lua_coroutine_create_helper(L, r, ctx, &coctx); - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - coroutines_key)); + lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); lua_rawget(L, LUA_REGISTRYINDEX); lua_pushvalue(L, -2); diff --git a/debian/modules/http-lua/src/ngx_http_lua_coroutine.c b/debian/modules/http-lua/src/ngx_http_lua_coroutine.c index 99a2423..b790814 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_coroutine.c +++ b/debian/modules/http-lua/src/ngx_http_lua_coroutine.c @@ -104,15 +104,11 @@ ngx_http_lua_coroutine_create_helper(lua_State *L, ngx_http_request_t *r, coctx->co = co; coctx->co_status = NGX_HTTP_LUA_CO_SUSPENDED; -#ifdef OPENRESTY_LUAJIT - ngx_http_lua_set_req(co, r); -#else /* make new coroutine share globals of the parent coroutine. * NOTE: globals don't have to be separated! */ ngx_http_lua_get_globals_table(L); lua_xmove(L, co, 1); ngx_http_lua_set_globals_table(co); -#endif lua_xmove(vm, L, 1); /* move coroutine from main thread to L */ @@ -292,27 +288,15 @@ ngx_http_lua_inject_coroutine_api(ngx_log_t *log, lua_State *L) { const char buf[] = "local keys = {'create', 'yield', 'resume', 'status'}\n" -#ifdef OPENRESTY_LUAJIT - "local get_req = require 'thread.exdata'\n" -#else "local getfenv = getfenv\n" -#endif "for _, key in ipairs(keys) do\n" "local std = coroutine['_' .. key]\n" "local ours = coroutine['__' .. key]\n" "local raw_ctx = ngx._phase_ctx\n" "coroutine[key] = function (...)\n" -#ifdef OPENRESTY_LUAJIT - "local r = get_req()\n" -#else "local r = getfenv(0).__ngx_req\n" -#endif - "if r ~= nil then\n" -#ifdef OPENRESTY_LUAJIT - "local ctx = raw_ctx()\n" -#else + "if r then\n" "local ctx = raw_ctx(r)\n" -#endif /* ignore header and body filters */ "if ctx ~= 0x020 and ctx ~= 0x040 then\n" "return ours(...)\n" diff --git a/debian/modules/http-lua/src/ngx_http_lua_directive.c b/debian/modules/http-lua/src/ngx_http_lua_directive.c index a989c26..fb8c6dc 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_directive.c +++ b/debian/modules/http-lua/src/ngx_http_lua_directive.c @@ -1304,12 +1304,11 @@ ngx_http_lua_gen_chunk_name(ngx_conf_t *cf, const char *tag, size_t tag_len, found: - p = ngx_snprintf(out, len, "=%*s(%*s:%d)%Z", - tag_len, tag, cf->conf_file->file.name.data - + cf->conf_file->file.name.len - p, - p, cf->conf_file->line); - - *chunkname_len = p - out - 1; /* exclude the trailing '\0' byte */ + ngx_snprintf(out, len, "=%*s(%*s:%d)%Z", + tag_len, tag, cf->conf_file->file.name.data + + cf->conf_file->file.name.len - p, + p, cf->conf_file->line); + *chunkname_len = len; return out; } diff --git a/debian/modules/http-lua/src/ngx_http_lua_headerfilterby.c b/debian/modules/http-lua/src/ngx_http_lua_headerfilterby.c index a0acd4a..b504530 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_headerfilterby.c +++ b/debian/modules/http-lua/src/ngx_http_lua_headerfilterby.c @@ -42,9 +42,9 @@ static ngx_http_output_header_filter_pt ngx_http_next_header_filter; static void ngx_http_lua_header_filter_by_lua_env(lua_State *L, ngx_http_request_t *r) { + /* set nginx request pointer to current lua thread's globals table */ ngx_http_lua_set_req(L, r); -#ifndef OPENRESTY_LUAJIT /** * we want to create empty environment for current script * @@ -68,7 +68,6 @@ ngx_http_lua_header_filter_by_lua_env(lua_State *L, ngx_http_request_t *r) /* }}} */ lua_setfenv(L, -2); /* set new running env for the code closure */ -#endif /* OPENRESTY_LUAJIT */ } diff --git a/debian/modules/http-lua/src/ngx_http_lua_headers.c b/debian/modules/http-lua/src/ngx_http_lua_headers.c index e3f48bc..b833577 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_headers.c +++ b/debian/modules/http-lua/src/ngx_http_lua_headers.c @@ -442,8 +442,7 @@ ngx_http_lua_ngx_req_get_headers(lua_State *L) lua_createtable(L, 0, count); if (!raw) { - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - headers_metatable_key)); + lua_pushlightuserdata(L, &ngx_http_lua_headers_metatable_key); lua_rawget(L, LUA_REGISTRYINDEX); lua_setmetatable(L, -2); } @@ -505,6 +504,7 @@ ngx_http_lua_ngx_resp_get_headers(lua_State *L) ngx_table_elt_t *header; ngx_http_request_t *r; ngx_http_lua_ctx_t *ctx; + ngx_int_t rc; u_char *lowcase_key = NULL; size_t lowcase_key_sz = 0; ngx_uint_t i; @@ -543,6 +543,17 @@ ngx_http_lua_ngx_resp_get_headers(lua_State *L) return luaL_error(L, "no ctx found"); } + if (!ctx->headers_set) { + rc = ngx_http_lua_set_content_type(r); + if (rc != NGX_OK) { + return luaL_error(L, + "failed to set default content type: %d", + (int) rc); + } + + ctx->headers_set = 1; + } + ngx_http_lua_check_fake_request(L, r); part = &r->headers_out.headers.part; @@ -555,8 +566,7 @@ ngx_http_lua_ngx_resp_get_headers(lua_State *L) lua_createtable(L, 0, count + 2); if (!raw) { - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - headers_metatable_key)); + lua_pushlightuserdata(L, &ngx_http_lua_headers_metatable_key); lua_rawget(L, LUA_REGISTRYINDEX); lua_setmetatable(L, -2); } @@ -684,6 +694,7 @@ ngx_http_lua_ngx_header_get(lua_State *L) size_t len; ngx_http_lua_loc_conf_t *llcf; ngx_http_lua_ctx_t *ctx; + ngx_int_t rc; r = ngx_http_lua_get_req(L); if (r == NULL) { @@ -726,7 +737,18 @@ ngx_http_lua_ngx_header_get(lua_State *L) key.len = len; - return ngx_http_lua_get_output_header(L, r, ctx, &key); + if (!ctx->headers_set) { + rc = ngx_http_lua_set_content_type(r); + if (rc != NGX_OK) { + return luaL_error(L, + "failed to set default content type: %d", + (int) rc); + } + + ctx->headers_set = 1; + } + + return ngx_http_lua_get_output_header(L, r, &key); } @@ -789,7 +811,16 @@ ngx_http_lua_ngx_header_set(lua_State *L) } } - ctx->headers_set = 1; + if (!ctx->headers_set) { + rc = ngx_http_lua_set_content_type(r); + if (rc != NGX_OK) { + return luaL_error(L, + "failed to set default content type: %d", + (int) rc); + } + + ctx->headers_set = 1; + } if (lua_type(L, 3) == LUA_TNIL) { ngx_str_null(&value); @@ -814,7 +845,7 @@ ngx_http_lua_ngx_header_set(lua_State *L) ngx_memcpy(value.data, p, len); value.len = len; - rc = ngx_http_lua_set_output_header(r, ctx, key, value, + rc = ngx_http_lua_set_output_header(r, key, value, i == 1 /* override */); if (rc == NGX_ERROR) { @@ -841,7 +872,7 @@ ngx_http_lua_ngx_header_set(lua_State *L) dd("key: %.*s, value: %.*s", (int) key.len, key.data, (int) value.len, value.data); - rc = ngx_http_lua_set_output_header(r, ctx, key, value, 1 /* override */); + rc = ngx_http_lua_set_output_header(r, key, value, 1 /* override */); if (rc == NGX_ERROR) { return luaL_error(L, "failed to set header %s (error: %d)", @@ -1050,8 +1081,7 @@ ngx_http_lua_create_headers_metatable(ngx_log_t *log, lua_State *L) "local new_key = string.gsub(string.lower(key), '_', '-')\n" "if new_key ~= key then return tb[new_key] else return nil end"; - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - headers_metatable_key)); + lua_pushlightuserdata(L, &ngx_http_lua_headers_metatable_key); /* metatable for ngx.req.get_headers(_, true) and * ngx.resp.get_headers(_, true) */ @@ -1211,7 +1241,15 @@ ngx_http_lua_ffi_set_resp_header(ngx_http_request_t *r, const u_char *key_data, } } - ctx->headers_set = 1; + if (!ctx->headers_set) { + rc = ngx_http_lua_set_content_type(r); + if (rc != NGX_OK) { + *errmsg = "failed to set default content type"; + return NGX_ERROR; + } + + ctx->headers_set = 1; + } if (is_nil) { value.data = NULL; @@ -1238,7 +1276,7 @@ ngx_http_lua_ffi_set_resp_header(ngx_http_request_t *r, const u_char *key_data, ngx_memcpy(value.data, p, len); value.len = len; - rc = ngx_http_lua_set_output_header(r, ctx, key, value, + rc = ngx_http_lua_set_output_header(r, key, value, override && i == 0); if (rc == NGX_ERROR) { @@ -1264,7 +1302,7 @@ ngx_http_lua_ffi_set_resp_header(ngx_http_request_t *r, const u_char *key_data, dd("key: %.*s, value: %.*s", (int) key.len, key.data, (int) value.len, value.data); - rc = ngx_http_lua_set_output_header(r, ctx, key, value, override); + rc = ngx_http_lua_set_output_header(r, key, value, override); if (rc == NGX_ERROR) { *errmsg = "failed to set header"; @@ -1332,8 +1370,7 @@ ngx_http_lua_ffi_req_header_set_single_value(ngx_http_request_t *r, int ngx_http_lua_ffi_get_resp_header(ngx_http_request_t *r, const u_char *key, size_t key_len, - u_char *key_buf, ngx_http_lua_ffi_str_t *values, int max_nvalues, - char **errmsg) + u_char *key_buf, ngx_http_lua_ffi_str_t *values, int max_nvalues) { int found; u_char c, *p; @@ -1350,10 +1387,19 @@ ngx_http_lua_ffi_get_resp_header(ngx_http_request_t *r, ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { - *errmsg = "no ctx found"; + /* *errmsg = "no ctx found"; */ return NGX_ERROR; } + if (!ctx->headers_set) { + if (ngx_http_lua_set_content_type(r) != NGX_OK) { + /* *errmsg = "failed to set default content type"; */ + return NGX_ERROR; + } + + ctx->headers_set = 1; + } + llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); if (llcf->transform_underscores_in_resp_headers && memchr(key, '_', key_len) != NULL) @@ -1379,7 +1425,6 @@ ngx_http_lua_ffi_get_resp_header(ngx_http_request_t *r, { p = ngx_palloc(r->pool, NGX_OFF_T_LEN); if (p == NULL) { - *errmsg = "no memory"; return NGX_ERROR; } @@ -1393,8 +1438,8 @@ ngx_http_lua_ffi_get_resp_header(ngx_http_request_t *r, break; case 12: - if (ngx_strncasecmp(key_buf, (u_char *) "Content-Type", 12) == 0 - && r->headers_out.content_type.len) + if (r->headers_out.content_type.len + && ngx_strncasecmp(key_buf, (u_char *) "Content-Type", 12) == 0) { values[0].data = r->headers_out.content_type.data; values[0].len = r->headers_out.content_type.len; diff --git a/debian/modules/http-lua/src/ngx_http_lua_headers_in.c b/debian/modules/http-lua/src/ngx_http_lua_headers_in.c index c52cd13..4852b2f 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_headers_in.c +++ b/debian/modules/http-lua/src/ngx_http_lua_headers_in.c @@ -432,14 +432,10 @@ static ngx_int_t ngx_http_set_host_header(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, ngx_str_t *value) { - ngx_str_t host; - ngx_http_lua_main_conf_t *lmcf; - ngx_http_variable_value_t *var; + ngx_str_t host; dd("server new value len: %d", (int) value->len); - lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); - if (value->len) { host= *value; @@ -453,10 +449,6 @@ ngx_http_set_host_header(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, r->headers_in.server = *value; } - var = &r->variables[lmcf->host_var_index]; - var->valid = 0; - var->not_found = 0; - return ngx_http_set_builtin_header(r, hv, value); } diff --git a/debian/modules/http-lua/src/ngx_http_lua_headers_out.c b/debian/modules/http-lua/src/ngx_http_lua_headers_out.c index cf94bd0..b908eae 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_headers_out.c +++ b/debian/modules/http-lua/src/ngx_http_lua_headers_out.c @@ -106,12 +106,6 @@ static ngx_http_lua_set_header_t ngx_http_lua_set_handlers[] = { offsetof(ngx_http_headers_out_t, cache_control), ngx_http_set_builtin_multi_header }, -#if defined(nginx_version) && nginx_version >= 1013009 - { ngx_string("Link"), - offsetof(ngx_http_headers_out_t, link), - ngx_http_set_builtin_multi_header }, -#endif - { ngx_null_string, 0, ngx_http_set_header } }; @@ -482,8 +476,8 @@ ngx_http_clear_builtin_header(ngx_http_request_t *r, ngx_int_t -ngx_http_lua_set_output_header(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx, - ngx_str_t key, ngx_str_t value, unsigned override) +ngx_http_lua_set_output_header(ngx_http_request_t *r, 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; @@ -514,10 +508,6 @@ ngx_http_lua_set_output_header(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx, hv.offset = handlers[i].offset; hv.handler = handlers[i].handler; - if (hv.handler == ngx_http_set_content_type_header) { - ctx->mime_set = 1; - } - break; } @@ -538,7 +528,7 @@ ngx_http_lua_set_output_header(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx, 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_str_t *key) { ngx_table_elt_t *h; ngx_list_part_t *part; @@ -560,8 +550,8 @@ ngx_http_lua_get_output_header(lua_State *L, ngx_http_request_t *r, break; case 12: - if (ngx_strncasecmp(key->data, (u_char *) "Content-Type", 12) == 0 - && r->headers_out.content_type.len) + if (r->headers_out.content_type.len + && ngx_strncasecmp(key->data, (u_char *) "Content-Type", 12) == 0) { lua_pushlstring(L, (char *) r->headers_out.content_type.data, r->headers_out.content_type.len); diff --git a/debian/modules/http-lua/src/ngx_http_lua_headers_out.h b/debian/modules/http-lua/src/ngx_http_lua_headers_out.h index 6ec1fe3..ef5e6d4 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_headers_out.h +++ b/debian/modules/http-lua/src/ngx_http_lua_headers_out.h @@ -12,10 +12,10 @@ #include "ngx_http_lua_common.h" -ngx_int_t ngx_http_lua_set_output_header(ngx_http_request_t *r, - ngx_http_lua_ctx_t *ctx, ngx_str_t key, ngx_str_t value, unsigned override); +ngx_int_t ngx_http_lua_set_output_header(ngx_http_request_t *r, ngx_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_str_t *key); #endif /* _NGX_HTTP_LUA_HEADERS_OUT_H_INCLUDED_ */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_initworkerby.c b/debian/modules/http-lua/src/ngx_http_lua_initworkerby.c index 76acdc3..4a722a0 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_initworkerby.c +++ b/debian/modules/http-lua/src/ngx_http_lua_initworkerby.c @@ -12,7 +12,6 @@ #include "ngx_http_lua_initworkerby.h" #include "ngx_http_lua_util.h" -#include "ngx_http_lua_pipe.h" static u_char *ngx_http_lua_log_init_worker_error(ngx_log_t *log, @@ -26,7 +25,6 @@ ngx_http_lua_init_worker(ngx_cycle_t *cycle) void *cur, *prev; ngx_uint_t i; ngx_conf_t conf; - ngx_conf_file_t cf_file; ngx_cycle_t *fake_cycle; ngx_module_t **modules; ngx_open_file_t *file, *ofile; @@ -66,21 +64,8 @@ ngx_http_lua_init_worker(ngx_cycle_t *cycle) return NGX_OK; } - -#ifdef HAVE_NGX_LUA_PIPE - if (ngx_http_lua_pipe_add_signal_handler(cycle) != NGX_OK) { - return NGX_ERROR; - } -#endif - #endif /* NGX_WIN32 */ -#if (NGX_HTTP_LUA_HAVE_SA_RESTART) - if (lmcf->set_sa_restart) { - ngx_http_lua_set_sa_restart(ngx_cycle->log); - } -#endif - if (lmcf->init_worker_handler == NULL) { return NGX_OK; } @@ -181,10 +166,6 @@ ngx_http_lua_init_worker(ngx_cycle_t *cycle) conf.pool = fake_cycle->pool; conf.log = cycle->log; - ngx_memzero(&cf_file, sizeof(cf_file)); - cf_file.file.name = cycle->conf_file; - conf.conf_file = &cf_file; - http_ctx.loc_conf = ngx_pcalloc(conf.pool, sizeof(void *) * ngx_http_max_module); if (http_ctx.loc_conf == NULL) { diff --git a/debian/modules/http-lua/src/ngx_http_lua_input_filters.c b/debian/modules/http-lua/src/ngx_http_lua_input_filters.c deleted file mode 100644 index 87a9d8c..0000000 --- a/debian/modules/http-lua/src/ngx_http_lua_input_filters.c +++ /dev/null @@ -1,137 +0,0 @@ - -/* - * Copyright (C) by OpenResty Inc. - */ - - -#ifndef DDEBUG -#define DDEBUG 0 -#endif -#include "ddebug.h" - - -#include "ngx_http_lua_common.h" - - -ngx_int_t -ngx_http_lua_read_bytes(ngx_buf_t *src, ngx_chain_t *buf_in, size_t *rest, - ssize_t bytes, ngx_log_t *log) -{ - if (bytes == 0) { - return NGX_ERROR; - } - - if ((size_t) bytes >= *rest) { - - buf_in->buf->last += *rest; - src->pos += *rest; - *rest = 0; - - return NGX_OK; - } - - /* bytes < *rest */ - - buf_in->buf->last += bytes; - src->pos += bytes; - *rest -= bytes; - - return NGX_AGAIN; -} - - -ngx_int_t -ngx_http_lua_read_all(ngx_buf_t *src, ngx_chain_t *buf_in, ssize_t bytes, - ngx_log_t *log) -{ - if (bytes == 0) { - return NGX_OK; - } - - buf_in->buf->last += bytes; - src->pos += bytes; - - return NGX_AGAIN; -} - - -ngx_int_t -ngx_http_lua_read_any(ngx_buf_t *src, ngx_chain_t *buf_in, size_t *max, - ssize_t bytes, ngx_log_t *log) -{ - if (bytes == 0) { - return NGX_ERROR; - } - - if (bytes >= (ssize_t) *max) { - bytes = (ssize_t) *max; - } - - buf_in->buf->last += bytes; - src->pos += bytes; - - return NGX_OK; -} - - -ngx_int_t -ngx_http_lua_read_line(ngx_buf_t *src, ngx_chain_t *buf_in, ssize_t bytes, - ngx_log_t *log) -{ - u_char *dst; - u_char c; -#if (NGX_DEBUG) - u_char *begin; -#endif - -#if (NGX_DEBUG) - begin = src->pos; -#endif - - if (bytes == 0) { - return NGX_ERROR; - } - - dd("already read: %p: %.*s", buf_in, - (int) (buf_in->buf->last - buf_in->buf->pos), buf_in->buf->pos); - - dd("data read: %.*s", (int) bytes, src->pos); - - dst = buf_in->buf->last; - - while (bytes--) { - - c = *src->pos++; - - switch (c) { - case '\n': - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, log, 0, - "lua read the final line part: \"%*s\"", - src->pos - 1 - begin, begin); - - buf_in->buf->last = dst; - - dd("read a line: %p: %.*s", buf_in, - (int) (buf_in->buf->last - buf_in->buf->pos), buf_in->buf->pos); - - return NGX_OK; - - case '\r': - /* ignore it */ - break; - - default: - *dst++ = c; - break; - } - } - -#if (NGX_DEBUG) - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, log, 0, - "lua read partial line data: %*s", dst - begin, begin); -#endif - - buf_in->buf->last = dst; - - return NGX_AGAIN; -} diff --git a/debian/modules/http-lua/src/ngx_http_lua_input_filters.h b/debian/modules/http-lua/src/ngx_http_lua_input_filters.h deleted file mode 100644 index 046d40f..0000000 --- a/debian/modules/http-lua/src/ngx_http_lua_input_filters.h +++ /dev/null @@ -1,29 +0,0 @@ - -/* - * Copyright (C) by OpenResty Inc. - */ - - -#ifndef _NGX_HTTP_LUA_INPUT_FILTERS_H_INCLUDED_ -#define _NGX_HTTP_LUA_INPUT_FILTERS_H_INCLUDED_ - - -#include "ngx_http_lua_common.h" - - -ngx_int_t ngx_http_lua_read_bytes(ngx_buf_t *src, ngx_chain_t *buf_in, - size_t *rest, ssize_t bytes, ngx_log_t *log); - -ngx_int_t ngx_http_lua_read_all(ngx_buf_t *src, ngx_chain_t *buf_in, - ssize_t bytes, ngx_log_t *log); - -ngx_int_t ngx_http_lua_read_any(ngx_buf_t *src, ngx_chain_t *buf_in, - size_t *max, ssize_t bytes, ngx_log_t *log); - -ngx_int_t ngx_http_lua_read_line(ngx_buf_t *src, ngx_chain_t *buf_in, - ssize_t bytes, ngx_log_t *log); - - -#endif /* _NGX_HTTP_LUA_INPUT_FILTERS_H_INCLUDED_ */ - -/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_logby.c b/debian/modules/http-lua/src/ngx_http_lua_logby.c index 32d1cba..0f1d2f3 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_logby.c +++ b/debian/modules/http-lua/src/ngx_http_lua_logby.c @@ -38,9 +38,9 @@ static ngx_int_t ngx_http_lua_log_by_chunk(lua_State *L, ngx_http_request_t *r); static void ngx_http_lua_log_by_lua_env(lua_State *L, ngx_http_request_t *r) { + /* set nginx request pointer to current lua thread's globals table */ ngx_http_lua_set_req(L, r); -#ifndef OPENRESTY_LUAJIT /** * we want to create empty environment for current script * @@ -64,7 +64,6 @@ ngx_http_lua_log_by_lua_env(lua_State *L, ngx_http_request_t *r) /* }}} */ lua_setfenv(L, -2); /* set new running env for the code closure */ -#endif /* OPENRESTY_LUAJIT */ } diff --git a/debian/modules/http-lua/src/ngx_http_lua_misc.c b/debian/modules/http-lua/src/ngx_http_lua_misc.c index 145ca9b..f96e2f2 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_misc.c +++ b/debian/modules/http-lua/src/ngx_http_lua_misc.c @@ -286,33 +286,6 @@ ngx_http_lua_ffi_headers_sent(ngx_http_request_t *r) return r->header_sent ? 1 : 0; } - - -int -ngx_http_lua_ffi_get_conf_env(u_char *name, u_char **env_buf, size_t *name_len) -{ - ngx_uint_t i; - ngx_str_t *var; - ngx_core_conf_t *ccf; - - ccf = (ngx_core_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx, - ngx_core_module); - - var = ccf->env.elts; - - for (i = 0; i < ccf->env.nelts; i++) { - if (var[i].data[var[i].len] == '=' - && ngx_strncmp(name, var[i].data, var[i].len) == 0) - { - *env_buf = var[i].data; - *name_len = var[i].len; - - return NGX_OK; - } - } - - return NGX_DECLINED; -} #endif /* NGX_LUA_NO_FFI_API */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_module.c b/debian/modules/http-lua/src/ngx_http_lua_module.c index 2a3f5d5..ae8bc0e 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_module.c +++ b/debian/modules/http-lua/src/ngx_http_lua_module.c @@ -29,7 +29,6 @@ #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_pipe.h" static void *ngx_http_lua_create_main_conf(ngx_conf_t *cf); @@ -77,13 +76,6 @@ static ngx_conf_bitmask_t ngx_http_lua_ssl_protocols[] = { static ngx_command_t ngx_http_lua_cmds[] = { - { ngx_string("lua_load_resty_core"), - NGX_HTTP_MAIN_CONF|NGX_CONF_FLAG, - ngx_conf_set_flag_slot, - NGX_HTTP_MAIN_CONF_OFFSET, - offsetof(ngx_http_lua_main_conf_t, load_resty_core), - NULL }, - { ngx_string("lua_max_running_timers"), NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1, ngx_conf_set_num_slot, @@ -112,13 +104,6 @@ static ngx_command_t ngx_http_lua_cmds[] = { 0, NULL }, - { ngx_string("lua_sa_restart"), - NGX_HTTP_MAIN_CONF|NGX_CONF_FLAG, - ngx_conf_set_flag_slot, - NGX_HTTP_MAIN_CONF_OFFSET, - offsetof(ngx_http_lua_main_conf_t, set_sa_restart), - NULL }, - #if (NGX_PCRE) { ngx_string("lua_regex_cache_max_entries"), NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1, @@ -653,19 +638,9 @@ ngx_http_lua_init(ngx_conf_t *cf) #if !defined(NGX_LUA_NO_FFI_API) || nginx_version >= 1011011 ngx_pool_cleanup_t *cln; #endif - ngx_str_t name = ngx_string("host"); - - if (ngx_process == NGX_PROCESS_SIGNALLER || ngx_test_config) { - return NGX_OK; - } lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_lua_module); - lmcf->host_var_index = ngx_http_get_variable_index(cf, &name); - if (lmcf->host_var_index == NGX_ERROR) { - return NGX_ERROR; - } - if (ngx_http_lua_prev_cycle != ngx_cycle) { ngx_http_lua_prev_cycle = ngx_cycle; multi_http_blocks = 0; @@ -750,11 +725,6 @@ ngx_http_lua_init(ngx_conf_t *cf) cln->data = lmcf; cln->handler = ngx_http_lua_sema_mm_cleanup; - -#ifdef HAVE_NGX_LUA_PIPE - ngx_http_lua_pipe_init(); -#endif - #endif #if nginx_version >= 1011011 @@ -770,19 +740,6 @@ ngx_http_lua_init(ngx_conf_t *cf) if (lmcf->lua == NULL) { dd("initializing lua vm"); -#ifndef OPENRESTY_LUAJIT - if (ngx_process != NGX_PROCESS_SIGNALLER && !ngx_test_config) { - ngx_log_error(NGX_LOG_ALERT, cf->log, 0, - "detected a LuaJIT version which is not OpenResty's" - "; many optimizations will be disabled and " - "performance will be compromised (see " - "https://github.com/openresty/luajit2 for " - "OpenResty's LuaJIT or, even better, consider using " - "the OpenResty releases from https://openresty.org/" - "en/download.html)"); - } -#endif - ngx_http_lua_content_length_hash = ngx_http_lua_hash_literal("content-length"); ngx_http_lua_location_hash = ngx_http_lua_hash_literal("location"); @@ -884,7 +841,6 @@ ngx_http_lua_create_main_conf(ngx_conf_t *cf) */ lmcf->pool = cf->pool; - lmcf->load_resty_core = NGX_CONF_UNSET; lmcf->max_pending_timers = NGX_CONF_UNSET; lmcf->max_running_timers = NGX_CONF_UNSET; #if (NGX_PCRE) @@ -894,8 +850,6 @@ ngx_http_lua_create_main_conf(ngx_conf_t *cf) lmcf->postponed_to_rewrite_phase_end = NGX_CONF_UNSET; lmcf->postponed_to_access_phase_end = NGX_CONF_UNSET; - lmcf->set_sa_restart = NGX_CONF_UNSET; - #if (NGX_HTTP_LUA_HAVE_MALLOC_TRIM) lmcf->malloc_trim_cycle = NGX_CONF_UNSET_UINT; #endif @@ -918,10 +872,6 @@ ngx_http_lua_init_main_conf(ngx_conf_t *cf, void *conf) { ngx_http_lua_main_conf_t *lmcf = conf; - if (lmcf->load_resty_core == NGX_CONF_UNSET) { - lmcf->load_resty_core = 1; - } - #if (NGX_PCRE) if (lmcf->regex_cache_max_entries == NGX_CONF_UNSET) { lmcf->regex_cache_max_entries = 1024; @@ -940,12 +890,6 @@ ngx_http_lua_init_main_conf(ngx_conf_t *cf, void *conf) lmcf->max_running_timers = 256; } -#if (NGX_HTTP_LUA_HAVE_SA_RESTART) - if (lmcf->set_sa_restart == NGX_CONF_UNSET) { - lmcf->set_sa_restart = 1; - } -#endif - #if (NGX_HTTP_LUA_HAVE_MALLOC_TRIM) if (lmcf->malloc_trim_cycle == NGX_CONF_UNSET_UINT) { lmcf->malloc_trim_cycle = 1000; /* number of reqs */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_ndk.c b/debian/modules/http-lua/src/ngx_http_lua_ndk.c index 6344183..24b80b4 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_ndk.c +++ b/debian/modules/http-lua/src/ngx_http_lua_ndk.c @@ -186,47 +186,6 @@ ngx_http_lua_inject_ndk_api(lua_State *L) } -int -ngx_http_lua_ffi_ndk_lookup_directive(const u_char *var_data, - size_t var_len, ndk_set_var_value_pt *func) -{ - *func = ngx_http_lookup_ndk_set_var_directive((u_char *) var_data, var_len); - - if (*func == NULL) { - return NGX_ERROR; - } - - return NGX_OK; -} - - -int -ngx_http_lua_ffi_ndk_set_var_get(ngx_http_request_t *r, - ndk_set_var_value_pt func, const u_char *arg_data, size_t arg_len, - ngx_http_lua_ffi_str_t *value) -{ - ngx_int_t rc; - ngx_str_t res; - ngx_http_variable_value_t arg; - - ngx_memzero(&arg, sizeof(ngx_http_variable_value_t)); - arg.valid = 1; - - arg.data = (u_char *) arg_data; - arg.len = arg_len; - - rc = func(r, &res, &arg); - - if (rc != NGX_OK) { - return rc; - } - - value->data = res.data; - value->len = res.len; - return NGX_OK; -} - - #endif /* defined(NDK) && NDK */ /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_pipe.c b/debian/modules/http-lua/src/ngx_http_lua_pipe.c deleted file mode 100644 index 8c8221f..0000000 --- a/debian/modules/http-lua/src/ngx_http_lua_pipe.c +++ /dev/null @@ -1,2475 +0,0 @@ - -/* - * Copyright (C) by OpenResty Inc. - */ - - -#ifndef DDEBUG -#define DDEBUG 0 -#endif -#include "ddebug.h" - - -#include "ngx_http_lua_common.h" -#include "ngx_http_lua_input_filters.h" -#include "ngx_http_lua_util.h" -#include "ngx_http_lua_pipe.h" -#if (NGX_HTTP_LUA_HAVE_SIGNALFD) -#include -#endif - - -#ifdef HAVE_NGX_LUA_PIPE -static ngx_rbtree_node_t *ngx_http_lua_pipe_lookup_pid(ngx_rbtree_key_t key); -#if !(NGX_HTTP_LUA_HAVE_SIGNALFD) -static void ngx_http_lua_pipe_sigchld_handler(int signo, siginfo_t *siginfo, - void *ucontext); -#endif -static void ngx_http_lua_pipe_sigchld_event_handler(ngx_event_t *ev); -static ssize_t ngx_http_lua_pipe_fd_read(ngx_connection_t *c, u_char *buf, - size_t size); -static ssize_t ngx_http_lua_pipe_fd_write(ngx_connection_t *c, u_char *buf, - size_t size); -static ngx_int_t ngx_http_lua_pipe_close_helper( - ngx_http_lua_pipe_ctx_t *pipe_ctx, ngx_event_t *ev, int forced); -static ngx_int_t ngx_http_lua_pipe_close_stdin(ngx_http_lua_pipe_t *pipe, - int forced); -static ngx_int_t ngx_http_lua_pipe_close_stdout(ngx_http_lua_pipe_t *pipe, - int forced); -static ngx_int_t ngx_http_lua_pipe_close_stderr(ngx_http_lua_pipe_t *pipe, - int forced); -static void ngx_http_lua_pipe_proc_finalize(ngx_http_lua_ffi_pipe_proc_t *proc, - int forced); -static ngx_int_t ngx_http_lua_pipe_get_lua_ctx(ngx_http_request_t *r, - ngx_http_lua_ctx_t **ctx, u_char *errbuf, size_t *errbuf_size); -static void ngx_http_lua_pipe_put_error(ngx_http_lua_pipe_ctx_t *pipe_ctx, - u_char *errbuf, size_t *errbuf_size); -static void ngx_http_lua_pipe_put_data(ngx_http_lua_pipe_t *pipe, - ngx_http_lua_pipe_ctx_t *pipe_ctx, u_char **buf, size_t *buf_size); -static ngx_int_t ngx_http_lua_pipe_add_input_buffer(ngx_http_lua_pipe_t *pipe, - ngx_http_lua_pipe_ctx_t *pipe_ctx); -static ngx_int_t ngx_http_lua_pipe_read_all(void *data, ssize_t bytes); -static ngx_int_t ngx_http_lua_pipe_read_bytes(void *data, ssize_t bytes); -static ngx_int_t ngx_http_lua_pipe_read_line(void *data, ssize_t bytes); -static ngx_int_t ngx_http_lua_pipe_read_any(void *data, ssize_t bytes); -static ngx_int_t ngx_http_lua_pipe_read(ngx_http_lua_pipe_t *pipe, - ngx_http_lua_pipe_ctx_t *pipe_ctx); -static ngx_int_t ngx_http_lua_pipe_init_ctx( - ngx_http_lua_pipe_ctx_t **pipe_ctx_pt, int fd, ngx_pool_t *pool, - u_char *errbuf, size_t *errbuf_size); -static ngx_int_t ngx_http_lua_pipe_write(ngx_http_lua_pipe_t *pipe, - ngx_http_lua_pipe_ctx_t *pipe_ctx); -static int ngx_http_lua_pipe_read_stdout_retval( - ngx_http_lua_ffi_pipe_proc_t *proc, lua_State *L); -static int ngx_http_lua_pipe_read_stderr_retval( - ngx_http_lua_ffi_pipe_proc_t *proc, lua_State *L); -static int ngx_http_lua_pipe_read_retval_helper( - ngx_http_lua_ffi_pipe_proc_t *proc, lua_State *L, int from_stderr); -static int ngx_http_lua_pipe_write_retval(ngx_http_lua_ffi_pipe_proc_t *proc, - lua_State *L); -static int ngx_http_lua_pipe_wait_retval(ngx_http_lua_ffi_pipe_proc_t *proc, - lua_State *L); -static void ngx_http_lua_pipe_resume_helper(ngx_event_t *ev, - ngx_http_lua_co_ctx_t *wait_co_ctx); -static void ngx_http_lua_pipe_resume_read_stdout_handler(ngx_event_t *ev); -static void ngx_http_lua_pipe_resume_read_stderr_handler(ngx_event_t *ev); -static void ngx_http_lua_pipe_resume_write_handler(ngx_event_t *ev); -static void ngx_http_lua_pipe_resume_wait_handler(ngx_event_t *ev); -static ngx_int_t ngx_http_lua_pipe_resume(ngx_http_request_t *r); -static void ngx_http_lua_pipe_dummy_event_handler(ngx_event_t *ev); -static void ngx_http_lua_pipe_clear_event(ngx_event_t *ev); -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 ngx_rbtree_t ngx_http_lua_pipe_rbtree; -static ngx_rbtree_node_t ngx_http_lua_pipe_proc_sentinel; - - -#if (NGX_HTTP_LUA_HAVE_SIGNALFD) -static int ngx_http_lua_signalfd; -static struct signalfd_siginfo ngx_http_lua_pipe_notification; - -#define ngx_http_lua_read_sigfd ngx_http_lua_signalfd - -#else -static int ngx_http_lua_sigchldfd[2]; -static u_char ngx_http_lua_pipe_notification[1]; - -#define ngx_http_lua_read_sigfd ngx_http_lua_sigchldfd[0] -#define ngx_http_lua_write_sigfd ngx_http_lua_sigchldfd[1] -#endif - - -static ngx_connection_t *ngx_http_lua_sigfd_conn = NULL; - - -/* The below signals are ignored by Nginx. - * We need to reset them for the spawned child processes. */ -ngx_http_lua_pipe_signal_t ngx_signals[] = { - { SIGSYS, "SIGSYS" }, - { SIGPIPE, "SIGPIPE" }, - { 0, NULL } -}; - - -enum { - PIPE_ERR_CLOSED = 1, - PIPE_ERR_SYSCALL, - PIPE_ERR_NOMEM, - PIPE_ERR_TIMEOUT, - PIPE_ERR_ADD_READ_EV, - PIPE_ERR_ADD_WRITE_EV -}; - - -enum { - PIPE_READ_ALL = 0, - PIPE_READ_BYTES, - PIPE_READ_LINE, - PIPE_READ_ANY -}; - - -#define REASON_EXIT "exit" -#define REASON_SIGNAL "signal" -#define REASON_UNKNOWN "unknown" - -#define REASON_RUNNING_CODE 0 -#define REASON_EXIT_CODE 1 -#define REASON_SIGNAL_CODE 2 -#define REASON_UNKNOWN_CODE 3 - - -void -ngx_http_lua_pipe_init(void) -{ - ngx_rbtree_init(&ngx_http_lua_pipe_rbtree, - &ngx_http_lua_pipe_proc_sentinel, ngx_rbtree_insert_value); -} - - -ngx_int_t -ngx_http_lua_pipe_add_signal_handler(ngx_cycle_t *cycle) -{ - ngx_event_t *rev; -#if (NGX_HTTP_LUA_HAVE_SIGNALFD) - sigset_t set; - -#else - int rc; - struct sigaction sa; -#endif - -#if (NGX_HTTP_LUA_HAVE_SIGNALFD) - if (sigemptyset(&set) != 0) { - ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno, - "lua pipe init signal set failed"); - return NGX_ERROR; - } - - if (sigaddset(&set, SIGCHLD) != 0) { - ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno, - "lua pipe add SIGCHLD to signal set failed"); - return NGX_ERROR; - } - - if (sigprocmask(SIG_BLOCK, &set, NULL) != 0) { - ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno, - "lua pipe block SIGCHLD failed"); - return NGX_ERROR; - } - - ngx_http_lua_signalfd = signalfd(-1, &set, SFD_NONBLOCK|SFD_CLOEXEC); - if (ngx_http_lua_signalfd < 0) { - ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno, - "lua pipe create signalfd instance failed"); - return NGX_ERROR; - } - -#else /* !(NGX_HTTP_LUA_HAVE_SIGNALFD) */ -# if (NGX_HTTP_LUA_HAVE_PIPE2) - rc = pipe2(ngx_http_lua_sigchldfd, O_NONBLOCK|O_CLOEXEC); -# else - rc = pipe(ngx_http_lua_sigchldfd); -# endif - - if (rc == -1) { - ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno, - "lua pipe init SIGCHLD fd failed"); - return NGX_ERROR; - } - -# if !(NGX_HTTP_LUA_HAVE_PIPE2) - if (ngx_nonblocking(ngx_http_lua_read_sigfd) == -1) { - ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno, "lua pipe " - ngx_nonblocking_n " SIGCHLD read fd failed"); - goto failed; - } - - if (ngx_nonblocking(ngx_http_lua_write_sigfd) == -1) { - ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno, "lua pipe " - ngx_nonblocking_n " SIGCHLD write fd failed"); - goto failed; - } - - /* it's ok not to set the pipe fd with O_CLOEXEC. This requires - * extra syscall */ -# endif /* !(NGX_HTTP_LUA_HAVE_PIPE2) */ -#endif /* NGX_HTTP_LUA_HAVE_SIGNALFD */ - - ngx_http_lua_sigfd_conn = ngx_get_connection(ngx_http_lua_read_sigfd, - cycle->log); - if (ngx_http_lua_sigfd_conn == NULL) { - goto failed; - } - - ngx_http_lua_sigfd_conn->log = cycle->log; - ngx_http_lua_sigfd_conn->recv = ngx_http_lua_pipe_fd_read; - rev = ngx_http_lua_sigfd_conn->read; - rev->log = ngx_http_lua_sigfd_conn->log; - rev->handler = ngx_http_lua_pipe_sigchld_event_handler; - -#ifdef HAVE_SOCKET_CLOEXEC_PATCH - rev->skip_socket_leak_check = 1; -#endif - - if (ngx_handle_read_event(rev, 0) == NGX_ERROR) { - goto failed; - } - -#if !(NGX_HTTP_LUA_HAVE_SIGNALFD) - ngx_memzero(&sa, sizeof(struct sigaction)); - sa.sa_sigaction = ngx_http_lua_pipe_sigchld_handler; - sa.sa_flags = SA_SIGINFO; - - if (sigemptyset(&sa.sa_mask) != 0) { - ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno, - "lua pipe init signal mask failed"); - goto failed; - } - - if (sigaction(SIGCHLD, &sa, NULL) == -1) { - ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno, - "lua pipe sigaction(SIGCHLD) failed"); - goto failed; - } -#endif - - return NGX_OK; - -failed: - - if (ngx_http_lua_sigfd_conn != NULL) { - ngx_close_connection(ngx_http_lua_sigfd_conn); - ngx_http_lua_sigfd_conn = NULL; - } - - if (close(ngx_http_lua_read_sigfd) == -1) { - ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, - "lua pipe close the read sigfd failed"); - } - -#if !(NGX_HTTP_LUA_HAVE_SIGNALFD) - if (close(ngx_http_lua_write_sigfd) == -1) { - ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, - "lua pipe close the write sigfd failed"); - } -#endif - - return NGX_ERROR; -} - - -static ngx_rbtree_node_t * -ngx_http_lua_pipe_lookup_pid(ngx_rbtree_key_t key) -{ - ngx_rbtree_node_t *node, *sentinel; - - node = ngx_http_lua_pipe_rbtree.root; - sentinel = ngx_http_lua_pipe_rbtree.sentinel; - - while (node != sentinel) { - if (key < node->key) { - node = node->left; - continue; - } - - if (key > node->key) { - node = node->right; - continue; - } - - return node; - } - - return NULL; -} - - -#if !(NGX_HTTP_LUA_HAVE_SIGNALFD) -static void -ngx_http_lua_pipe_sigchld_handler(int signo, siginfo_t *siginfo, - void *ucontext) -{ - ngx_err_t err, saved_err; - ngx_int_t n; - - saved_err = ngx_errno; - - for ( ;; ) { - n = write(ngx_http_lua_write_sigfd, ngx_http_lua_pipe_notification, - sizeof(ngx_http_lua_pipe_notification)); - - ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0, - "lua pipe SIGCHLD fd write siginfo:%p", siginfo); - - if (n >= 0) { - break; - } - - err = ngx_errno; - - if (err != NGX_EINTR) { - if (err != NGX_EAGAIN) { - ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, err, - "lua pipe SIGCHLD fd write failed"); - } - - break; - } - - ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, err, - "lua pipe SIGCHLD fd write was interrupted"); - } - - ngx_set_errno(saved_err); -} -#endif - - -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"); - - for ( ;; ) { -#if (NGX_HTTP_LUA_HAVE_SIGNALFD) - n = c->recv(c, (u_char *) &ngx_http_lua_pipe_notification, -#else - n = c->recv(c, ngx_http_lua_pipe_notification, -#endif - sizeof(ngx_http_lua_pipe_notification)); - - if (n <= 0) { - if (n == NGX_ERROR) { - ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, - "lua pipe SIGCHLD fd read failed"); - } - - break; - } - - for ( ;; ) { - pid = waitpid(-1, &status, WNOHANG); - - if (pid == 0) { - break; - } - - if (pid < 0) { - if (ngx_errno != NGX_ECHILD) { - ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, - "lua pipe waitpid failed"); - } - - break; - } - - /* This log is ported from Nginx's signal handler since we override - * or block it in this implementation. */ - ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0, - "signal %d (SIGCHLD) received from %P", - SIGCHLD, pid); - - 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); - } - - 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 ssize_t -ngx_http_lua_pipe_fd_read(ngx_connection_t *c, u_char *buf, size_t size) -{ - ssize_t n; - ngx_err_t err; - ngx_event_t *rev; - - rev = c->read; - - do { - n = read(c->fd, buf, size); - - err = ngx_errno; - - ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, - "read: fd:%d %z of %uz", c->fd, n, size); - - if (n == 0) { - rev->ready = 0; - rev->eof = 1; - return 0; - } - - if (n > 0) { - if ((size_t) n < size - && !(ngx_event_flags & NGX_USE_GREEDY_EVENT)) - { - rev->ready = 0; - } - - return n; - } - - if (err == NGX_EAGAIN || err == NGX_EINTR) { - ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, - "read() not ready"); - n = NGX_AGAIN; - - } else { - n = ngx_connection_error(c, err, "read() failed"); - break; - } - - } while (err == NGX_EINTR); - - rev->ready = 0; - - if (n == NGX_ERROR) { - rev->error = 1; - } - - return n; -} - - -static ssize_t -ngx_http_lua_pipe_fd_write(ngx_connection_t *c, u_char *buf, size_t size) -{ - ssize_t n; - ngx_err_t err; - ngx_event_t *wev; - - wev = c->write; - - do { - n = write(c->fd, buf, size); - - ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, - "write: fd:%d %z of %uz", c->fd, n, size); - - if (n >= 0) { - if ((size_t) n != size) { - wev->ready = 0; - } - - return n; - } - - err = ngx_errno; - - if (err == NGX_EAGAIN || err == NGX_EINTR) { - ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, - "write() not ready"); - n = NGX_AGAIN; - - } else if (err != NGX_EPIPE) { - n = ngx_connection_error(c, err, "write() failed"); - break; - } - - } while (err == NGX_EINTR); - - wev->ready = 0; - - if (n == NGX_ERROR) { - wev->error = 1; - } - - return n; -} - - -int -ngx_http_lua_ffi_pipe_spawn(ngx_http_lua_ffi_pipe_proc_t *proc, - const char *file, const char **argv, int merge_stderr, size_t buffer_size, - u_char *errbuf, size_t *errbuf_size) -{ - int rc; - int in[2]; - int out[2]; - int err[2]; - int stdin_fd, stdout_fd, stderr_fd; - int errlog_fd, temp_errlog_fd; - ngx_pid_t pid; - ssize_t pool_size; - ngx_pool_t *pool; - ngx_uint_t i; - ngx_listening_t *ls; - ngx_http_lua_pipe_t *pp; - ngx_rbtree_node_t *node; - ngx_http_lua_pipe_node_t *pipe_node; - struct sigaction sa; - ngx_http_lua_pipe_signal_t *sig; - sigset_t set; - - pool_size = ngx_align(NGX_MIN_POOL_SIZE + buffer_size * 2, - NGX_POOL_ALIGNMENT); - - pool = ngx_create_pool(pool_size, ngx_cycle->log); - if (pool == NULL) { - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "no memory") - - errbuf; - return NGX_ERROR; - } - - pp = ngx_pcalloc(pool, sizeof(ngx_http_lua_pipe_t) - + offsetof(ngx_rbtree_node_t, color) - + sizeof(ngx_http_lua_pipe_node_t)); - if (pp == NULL) { - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "no memory") - - errbuf; - goto free_pool; - } - - rc = pipe(in); - if (rc == -1) { - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "pipe failed: %s", - strerror(errno)) - - errbuf; - goto free_pool; - } - - rc = pipe(out); - if (rc == -1) { - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "pipe failed: %s", - strerror(errno)) - - errbuf; - goto close_in_fd; - } - - if (!merge_stderr) { - rc = pipe(err); - if (rc == -1) { - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, - "pipe failed: %s", strerror(errno)) - - errbuf; - goto close_in_out_fd; - } - } - - pid = fork(); - if (pid == -1) { - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "fork failed: %s", - strerror(errno)) - - errbuf; - goto close_in_out_err_fd; - } - - if (pid == 0) { - -#if (NGX_HAVE_CPU_AFFINITY) - /* reset the CPU affinity mask */ - ngx_uint_t log_level; - ngx_cpuset_t child_cpu_affinity; - - if (ngx_process == NGX_PROCESS_WORKER - && ngx_get_cpu_affinity(ngx_worker) != NULL) - { - CPU_ZERO(&child_cpu_affinity); - - for (i = 0; i < (ngx_uint_t) ngx_min(ngx_ncpu, CPU_SETSIZE); i++) { - CPU_SET(i, &child_cpu_affinity); - } - - log_level = ngx_cycle->log->log_level; - ngx_cycle->log->log_level = NGX_LOG_WARN; - ngx_setaffinity(&child_cpu_affinity, ngx_cycle->log); - ngx_cycle->log->log_level = log_level; - } -#endif - - /* reset the handler of ignored signals to the default */ - for (sig = ngx_signals; sig->signo != 0; sig++) { - ngx_memzero(&sa, sizeof(struct sigaction)); - sa.sa_handler = SIG_DFL; - - if (sigemptyset(&sa.sa_mask) != 0) { - ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, - "lua pipe child init signal mask failed"); - exit(EXIT_FAILURE); - } - - if (sigaction(sig->signo, &sa, NULL) == -1) { - ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, - "lua pipe child reset signal handler for %s " - "failed", sig->signame); - exit(EXIT_FAILURE); - } - } - - /* reset signal mask */ - if (sigemptyset(&set) != 0) { - ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, - "lua pipe child init signal set failed"); - exit(EXIT_FAILURE); - } - - if (sigprocmask(SIG_SETMASK, &set, NULL) != 0) { - ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, - "lua pipe child reset signal mask failed"); - exit(EXIT_FAILURE); - } - - /* close listening socket fd */ - ls = ngx_cycle->listening.elts; - for (i = 0; i < ngx_cycle->listening.nelts; i++) { - if (ngx_close_socket(ls[i].fd) == -1) { - ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_socket_errno, - "lua pipe child " ngx_close_socket_n - " %V failed", &ls[i].addr_text); - } - } - - /* close and dup pipefd */ - if (close(in[1]) == -1) { - ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, - "lua pipe child failed to close the in[1] " - "pipe fd"); - } - - if (close(out[0]) == -1) { - ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, - "lua pipe child failed to close the out[0] " - "pipe fd"); - } - - if (ngx_cycle->log->file && ngx_cycle->log->file->fd == STDERR_FILENO) { - errlog_fd = ngx_cycle->log->file->fd; - temp_errlog_fd = dup(errlog_fd); - - if (temp_errlog_fd == -1) { - ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, - "lua pipe child dup errlog fd failed"); - exit(EXIT_FAILURE); - } - - if (ngx_cloexec(temp_errlog_fd) == -1) { - ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, - "lua pipe child new errlog fd " ngx_cloexec_n - " failed"); - } - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "lua pipe child dup old errlog fd %d to new fd %d", - ngx_cycle->log->file->fd, temp_errlog_fd); - - ngx_cycle->log->file->fd = temp_errlog_fd; - } - - if (dup2(in[0], STDIN_FILENO) == -1) { - ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, - "lua pipe child dup2 stdin failed"); - exit(EXIT_FAILURE); - } - - if (dup2(out[1], STDOUT_FILENO) == -1) { - ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, - "lua pipe child dup2 stdout failed"); - exit(EXIT_FAILURE); - } - - if (merge_stderr) { - if (dup2(STDOUT_FILENO, STDERR_FILENO) == -1) { - ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, - "lua pipe child dup2 stderr failed"); - exit(EXIT_FAILURE); - } - - } else { - if (close(err[0]) == -1) { - ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, - "lua pipe child failed to close the err[0] " - "pipe fd"); - } - - if (dup2(err[1], STDERR_FILENO) == -1) { - ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, - "lua pipe child dup2 stderr failed"); - exit(EXIT_FAILURE); - } - } - - if (execvp(file, (char * const *) argv) == -1) { - ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, - "lua pipe child execvp() failed while executing %s", - file); - } - - exit(EXIT_FAILURE); - } - - /* parent process */ - if (close(in[0]) == -1) { - ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, - "lua pipe: failed to close the in[0] pipe fd"); - } - - stdin_fd = in[1]; - - if (ngx_nonblocking(stdin_fd) == -1) { - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, - ngx_nonblocking_n " failed: %s", - strerror(errno)) - - errbuf; - goto close_in_out_err_fd; - } - - pp->stdin_fd = stdin_fd; - - if (close(out[1]) == -1) { - ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, - "lua pipe: failed to close the out[1] pipe fd"); - } - - stdout_fd = out[0]; - - if (ngx_nonblocking(stdout_fd) == -1) { - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, - ngx_nonblocking_n " failed: %s", - strerror(errno)) - - errbuf; - goto close_in_out_err_fd; - } - - pp->stdout_fd = stdout_fd; - - if (!merge_stderr) { - if (close(err[1]) == -1) { - ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, - "lua pipe: failed to close the err[1] pipe fd"); - } - - stderr_fd = err[0]; - - if (ngx_nonblocking(stderr_fd) == -1) { - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, - ngx_nonblocking_n " failed: %s", - strerror(errno)) - - errbuf; - goto close_in_out_err_fd; - } - - pp->stderr_fd = stderr_fd; - } - - node = (ngx_rbtree_node_t *) (pp + 1); - node->key = pid; - pipe_node = (ngx_http_lua_pipe_node_t *) &node->color; - pipe_node->proc = proc; - ngx_rbtree_insert(&ngx_http_lua_pipe_rbtree, node); - - pp->node = node; - pp->pool = pool; - pp->merge_stderr = merge_stderr; - pp->buffer_size = buffer_size; - - proc->_pid = pid; - proc->write_timeout = 10000; - proc->stdout_read_timeout = 10000; - proc->stderr_read_timeout = 10000; - proc->wait_timeout = 10000; - proc->pipe = pp; - - ngx_log_debug4(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "lua pipe spawn process:%p pid:%P merge_stderr:%d " - "buffer_size:%uz", proc, pid, merge_stderr, buffer_size); - return NGX_OK; - -close_in_out_err_fd: - - if (!merge_stderr) { - if (close(err[0]) == -1) { - ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, - "failed to close the err[0] pipe fd"); - } - - if (close(err[1]) == -1) { - ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, - "failed to close the err[1] pipe fd"); - } - } - -close_in_out_fd: - - if (close(out[0]) == -1) { - ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, - "failed to close the out[0] pipe fd"); - } - - if (close(out[1]) == -1) { - ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, - "failed to close the out[1] pipe fd"); - } - -close_in_fd: - - if (close(in[0]) == -1) { - ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, - "failed to close the in[0] pipe fd"); - } - - if (close(in[1]) == -1) { - ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, - "failed to close the in[1] pipe fd"); - } - -free_pool: - - ngx_destroy_pool(pool); - return NGX_ERROR; -} - - -static ngx_int_t -ngx_http_lua_pipe_close_helper(ngx_http_lua_pipe_ctx_t *pipe_ctx, - ngx_event_t *ev, int forced) -{ - if (ev->handler != ngx_http_lua_pipe_dummy_event_handler && !forced) { - ngx_log_debug3(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "lua pipe cannot close fd:%d without " - "forced pipe:%p ev:%p", pipe_ctx->c->fd, pipe_ctx, ev); - return NGX_ERROR; - } - - ngx_close_connection(pipe_ctx->c); - pipe_ctx->c = NULL; - - return NGX_OK; -} - - -static ngx_int_t -ngx_http_lua_pipe_close_stdin(ngx_http_lua_pipe_t *pipe, int forced) -{ - ngx_event_t *wev; - - if (pipe->stdin_ctx == NULL) { - if (pipe->stdin_fd != -1) { - if (close(pipe->stdin_fd) == -1) { - ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, - "failed to close the stdin pipe fd"); - } - - pipe->stdin_fd = -1; - } - - } else if (pipe->stdin_ctx->c != NULL) { - wev = pipe->stdin_ctx->c->write; - return ngx_http_lua_pipe_close_helper(pipe->stdin_ctx, wev, forced); - } - - return NGX_OK; -} - - -static ngx_int_t -ngx_http_lua_pipe_close_stdout(ngx_http_lua_pipe_t *pipe, int forced) -{ - ngx_event_t *rev; - - if (pipe->stdout_ctx == NULL) { - if (pipe->stdout_fd != -1) { - if (close(pipe->stdout_fd) == -1) { - ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, - "failed to close the stdout pipe fd"); - } - - pipe->stdout_fd = -1; - } - - } else if (pipe->stdout_ctx->c != NULL) { - rev = pipe->stdout_ctx->c->read; - return ngx_http_lua_pipe_close_helper(pipe->stdout_ctx, rev, forced); - } - - return NGX_OK; -} - - -static ngx_int_t -ngx_http_lua_pipe_close_stderr(ngx_http_lua_pipe_t *pipe, int forced) -{ - ngx_event_t *rev; - - if (pipe->stderr_ctx == NULL) { - if (pipe->stderr_fd != -1) { - if (close(pipe->stderr_fd) == -1) { - ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, - "failed to close the stderr pipe fd"); - } - - pipe->stderr_fd = -1; - } - - } else if (pipe->stderr_ctx->c != NULL) { - rev = pipe->stderr_ctx->c->read; - return ngx_http_lua_pipe_close_helper(pipe->stderr_ctx, rev, forced); - } - - return NGX_OK; -} - - -int -ngx_http_lua_ffi_pipe_proc_shutdown_stdin(ngx_http_lua_ffi_pipe_proc_t *proc, - u_char *errbuf, size_t *errbuf_size) -{ - ngx_int_t rc; - ngx_http_lua_pipe_t *pipe; - - pipe = proc->pipe; - if (pipe == NULL || pipe->closed) { - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "closed") - errbuf; - return NGX_ERROR; - } - - rc = ngx_http_lua_pipe_close_stdin(pipe, 0); - if (rc != NGX_OK) { - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "pipe busy writing") - - errbuf; - return NGX_ERROR; - } - - return NGX_OK; -} - - -int -ngx_http_lua_ffi_pipe_proc_shutdown_stdout(ngx_http_lua_ffi_pipe_proc_t *proc, - u_char *errbuf, size_t *errbuf_size) -{ - ngx_int_t rc; - ngx_http_lua_pipe_t *pipe; - - pipe = proc->pipe; - if (pipe == NULL || pipe->closed) { - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "closed") - errbuf; - return NGX_ERROR; - } - - rc = ngx_http_lua_pipe_close_stdout(pipe, 0); - if (rc != NGX_OK) { - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "pipe busy reading") - - errbuf; - return NGX_ERROR; - } - - return NGX_OK; -} - - -int -ngx_http_lua_ffi_pipe_proc_shutdown_stderr(ngx_http_lua_ffi_pipe_proc_t *proc, - u_char *errbuf, size_t *errbuf_size) -{ - ngx_http_lua_pipe_t *pipe; - - pipe = proc->pipe; - if (pipe == NULL || pipe->closed) { - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "closed") - errbuf; - return NGX_ERROR; - } - - if (pipe->merge_stderr) { - /* stdout is used internally as stderr when merge_stderr is true */ - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "merged to stdout") - - errbuf; - return NGX_ERROR; - } - - if (ngx_http_lua_pipe_close_stderr(pipe, 0) != NGX_OK) { - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "pipe busy reading") - - errbuf; - return NGX_ERROR; - } - - return NGX_OK; -} - - -static void -ngx_http_lua_pipe_proc_finalize(ngx_http_lua_ffi_pipe_proc_t *proc, int forced) -{ - ngx_http_lua_pipe_t *pipe; - - ngx_log_debug3(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "lua pipe finalize process:%p pid:%P forced:%d", proc, - proc->_pid, forced); - pipe = proc->pipe; - - if (pipe->node) { - ngx_rbtree_delete(&ngx_http_lua_pipe_rbtree, pipe->node); - pipe->node = NULL; - } - - pipe->dead = 1; - - ngx_http_lua_pipe_close_stdin(pipe, forced); - ngx_http_lua_pipe_close_stdout(pipe, forced); - - if (!pipe->merge_stderr) { - ngx_http_lua_pipe_close_stderr(pipe, forced); - } - - pipe->closed = 1; -} - - -void -ngx_http_lua_ffi_pipe_proc_destroy(ngx_http_lua_ffi_pipe_proc_t *proc) -{ - ngx_http_lua_pipe_t *pipe; - - pipe = proc->pipe; - if (pipe == NULL) { - return; - } - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "lua pipe destroy process:%p pid:%P", proc, proc->_pid); - - if (!pipe->dead) { - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "lua pipe kill process:%p pid:%P", proc, proc->_pid); - - if (kill(proc->_pid, SIGKILL) == -1) { - if (ngx_errno != ESRCH) { - ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, - "lua pipe failed to kill process:%p pid:%P"); - } - } - } - - ngx_http_lua_pipe_proc_finalize(proc, 1); - ngx_destroy_pool(pipe->pool); - proc->pipe = NULL; -} - - -static ngx_int_t -ngx_http_lua_pipe_get_lua_ctx(ngx_http_request_t *r, - ngx_http_lua_ctx_t **ctx, u_char *errbuf, size_t *errbuf_size) -{ - int rc; - - *ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); - if (ctx == NULL) { - return NGX_HTTP_LUA_FFI_NO_REQ_CTX; - } - - rc = ngx_http_lua_ffi_check_context(*ctx, NGX_HTTP_LUA_CONTEXT_REWRITE - | NGX_HTTP_LUA_CONTEXT_ACCESS - | NGX_HTTP_LUA_CONTEXT_CONTENT - | NGX_HTTP_LUA_CONTEXT_TIMER - | NGX_HTTP_LUA_CONTEXT_SSL_CERT - | NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH, - errbuf, errbuf_size); - if (rc != NGX_OK) { - return NGX_HTTP_LUA_FFI_BAD_CONTEXT; - } - - return NGX_OK; -} - - -static void -ngx_http_lua_pipe_put_error(ngx_http_lua_pipe_ctx_t *pipe_ctx, u_char *errbuf, - size_t *errbuf_size) -{ - switch (pipe_ctx->err_type) { - - case PIPE_ERR_CLOSED: - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "closed") - errbuf; - break; - - case PIPE_ERR_SYSCALL: - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "%s", - strerror(pipe_ctx->pipe_errno)) - - errbuf; - break; - - case PIPE_ERR_NOMEM: - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "no memory") - - errbuf; - break; - - case PIPE_ERR_TIMEOUT: - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "timeout") - - errbuf; - break; - - case PIPE_ERR_ADD_READ_EV: - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, - "failed to add read event") - - errbuf; - break; - - case PIPE_ERR_ADD_WRITE_EV: - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, - "failed to add write event") - - errbuf; - break; - - default: - ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, - "unexpected err type: %d", pipe_ctx->err_type); - ngx_http_lua_assert(NULL); - } -} - - -static void -ngx_http_lua_pipe_put_data(ngx_http_lua_pipe_t *pipe, - ngx_http_lua_pipe_ctx_t *pipe_ctx, u_char **buf, size_t *buf_size) -{ - size_t size = 0; - size_t chunk_size; - size_t nbufs; - u_char *p; - ngx_buf_t *b; - ngx_chain_t *cl; - ngx_chain_t **ll; - - nbufs = 0; - ll = NULL; - - for (cl = pipe_ctx->bufs_in; cl; cl = cl->next) { - b = cl->buf; - chunk_size = b->last - b->pos; - - if (cl->next) { - ll = &cl->next; - } - - size += chunk_size; - - nbufs++; - } - - if (*buf_size < size) { - *buf = NULL; - *buf_size = size; - - return; - } - - *buf_size = size; - - p = *buf; - for (cl = pipe_ctx->bufs_in; cl; cl = cl->next) { - b = cl->buf; - chunk_size = b->last - b->pos; - p = ngx_cpymem(p, b->pos, chunk_size); - } - - if (nbufs > 1 && ll) { - *ll = pipe->free_bufs; - pipe->free_bufs = pipe_ctx->bufs_in; - pipe_ctx->bufs_in = pipe_ctx->buf_in; - } - - if (pipe_ctx->buffer.pos == pipe_ctx->buffer.last) { - pipe_ctx->buffer.pos = pipe_ctx->buffer.start; - pipe_ctx->buffer.last = pipe_ctx->buffer.start; - } - - if (pipe_ctx->bufs_in) { - pipe_ctx->buf_in->buf->last = pipe_ctx->buffer.pos; - pipe_ctx->buf_in->buf->pos = pipe_ctx->buffer.pos; - } -} - - -static ngx_int_t -ngx_http_lua_pipe_add_input_buffer(ngx_http_lua_pipe_t *pipe, - ngx_http_lua_pipe_ctx_t *pipe_ctx) -{ - ngx_chain_t *cl; - - cl = ngx_http_lua_chain_get_free_buf(ngx_cycle->log, pipe->pool, - &pipe->free_bufs, - pipe->buffer_size); - - if (cl == NULL) { - pipe_ctx->err_type = PIPE_ERR_NOMEM; - return NGX_ERROR; - } - - pipe_ctx->buf_in->next = cl; - pipe_ctx->buf_in = cl; - pipe_ctx->buffer = *cl->buf; - - return NGX_OK; -} - - -static ngx_int_t -ngx_http_lua_pipe_read_all(void *data, ssize_t bytes) -{ - ngx_http_lua_pipe_ctx_t *pipe_ctx = data; - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, "lua pipe read all"); - return ngx_http_lua_read_all(&pipe_ctx->buffer, pipe_ctx->buf_in, bytes, - ngx_cycle->log); -} - - -static ngx_int_t -ngx_http_lua_pipe_read_bytes(void *data, ssize_t bytes) -{ - ngx_int_t rc; - ngx_http_lua_pipe_ctx_t *pipe_ctx = data; - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "lua pipe read bytes %z", bytes); - - rc = ngx_http_lua_read_bytes(&pipe_ctx->buffer, pipe_ctx->buf_in, - &pipe_ctx->rest, bytes, ngx_cycle->log); - if (rc == NGX_ERROR) { - pipe_ctx->err_type = PIPE_ERR_CLOSED; - return NGX_ERROR; - } - - return rc; -} - - -static ngx_int_t -ngx_http_lua_pipe_read_line(void *data, ssize_t bytes) -{ - ngx_int_t rc; - ngx_http_lua_pipe_ctx_t *pipe_ctx = data; - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "lua pipe read line"); - rc = ngx_http_lua_read_line(&pipe_ctx->buffer, pipe_ctx->buf_in, bytes, - ngx_cycle->log); - if (rc == NGX_ERROR) { - pipe_ctx->err_type = PIPE_ERR_CLOSED; - return NGX_ERROR; - } - - return rc; -} - - -static ngx_int_t -ngx_http_lua_pipe_read_any(void *data, ssize_t bytes) -{ - ngx_int_t rc; - ngx_http_lua_pipe_ctx_t *pipe_ctx = data; - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, "lua pipe read any"); - rc = ngx_http_lua_read_any(&pipe_ctx->buffer, pipe_ctx->buf_in, - &pipe_ctx->rest, bytes, ngx_cycle->log); - if (rc == NGX_ERROR) { - pipe_ctx->err_type = PIPE_ERR_CLOSED; - return NGX_ERROR; - } - - return rc; -} - - -static ngx_int_t -ngx_http_lua_pipe_read(ngx_http_lua_pipe_t *pipe, - ngx_http_lua_pipe_ctx_t *pipe_ctx) -{ - int rc; - int read; - size_t size; - ssize_t n; - ngx_buf_t *b; - ngx_event_t *rev; - ngx_connection_t *c; - - c = pipe_ctx->c; - rev = c->read; - b = &pipe_ctx->buffer; - read = 0; - - for ( ;; ) { - size = b->last - b->pos; - - if (size || pipe_ctx->eof) { - rc = pipe_ctx->input_filter(pipe_ctx->input_filter_ctx, size); - if (rc == NGX_ERROR) { - return NGX_ERROR; - } - - if (rc == NGX_OK) { - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "lua pipe read done pipe:%p", pipe_ctx); - return NGX_OK; - } - - /* rc == NGX_AGAIN */ - continue; - } - - if (read && !rev->ready) { - break; - } - - size = b->end - b->last; - - if (size == 0) { - rc = ngx_http_lua_pipe_add_input_buffer(pipe, pipe_ctx); - if (rc == NGX_ERROR) { - return NGX_ERROR; - } - - b = &pipe_ctx->buffer; - size = (size_t) (b->end - b->last); - } - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "lua pipe try to read data %uz pipe:%p", - size, pipe_ctx); - - n = c->recv(c, b->last, size); - read = 1; - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "lua pipe read data returned %z pipe:%p", n, pipe_ctx); - - if (n == NGX_AGAIN) { - break; - } - - if (n == 0) { - pipe_ctx->eof = 1; - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "lua pipe closed pipe:%p", pipe_ctx); - continue; - } - - if (n == NGX_ERROR) { - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, ngx_errno, - "lua pipe read data error pipe:%p", pipe_ctx); - - pipe_ctx->err_type = PIPE_ERR_SYSCALL; - pipe_ctx->pipe_errno = ngx_errno; - return NGX_ERROR; - } - - b->last += n; - } - - return NGX_AGAIN; -} - - -static ngx_int_t -ngx_http_lua_pipe_init_ctx(ngx_http_lua_pipe_ctx_t **pipe_ctx_pt, int fd, - ngx_pool_t *pool, u_char *errbuf, size_t *errbuf_size) -{ - ngx_connection_t *c; - - if (fd == -1) { - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "closed") - errbuf; - return NGX_ERROR; - } - - *pipe_ctx_pt = ngx_pcalloc(pool, sizeof(ngx_http_lua_pipe_ctx_t)); - if (*pipe_ctx_pt == NULL) { - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "no memory") - - errbuf; - return NGX_ERROR; - } - - c = ngx_get_connection(fd, ngx_cycle->log); - if (c == NULL) { - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "no connection") - - errbuf; - return NGX_ERROR; - } - - c->log = ngx_cycle->log; - c->recv = ngx_http_lua_pipe_fd_read; - c->read->handler = ngx_http_lua_pipe_dummy_event_handler; - c->read->log = c->log; - -#ifdef HAVE_SOCKET_CLOEXEC_PATCH - c->read->skip_socket_leak_check = 1; -#endif - - c->send = ngx_http_lua_pipe_fd_write; - c->write->handler = ngx_http_lua_pipe_dummy_event_handler; - c->write->log = c->log; - (*pipe_ctx_pt)->c = c; - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "lua pipe init pipe ctx:%p fd:*%d", *pipe_ctx_pt, fd); - - return NGX_OK; -} - - -int -ngx_http_lua_ffi_pipe_proc_read(ngx_http_request_t *r, - ngx_http_lua_ffi_pipe_proc_t *proc, int from_stderr, int reader_type, - size_t length, u_char **buf, size_t *buf_size, u_char *errbuf, - size_t *errbuf_size) -{ - int rc; - ngx_msec_t timeout; - ngx_event_t *rev; - ngx_connection_t *c; - ngx_http_lua_ctx_t *ctx; - ngx_http_lua_pipe_t *pipe; - ngx_http_lua_co_ctx_t *wait_co_ctx; - ngx_http_lua_pipe_ctx_t *pipe_ctx; - - rc = ngx_http_lua_pipe_get_lua_ctx(r, &ctx, errbuf, errbuf_size); - if (rc != NGX_OK) { - return rc; - } - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua pipe read process:%p pid:%P", proc, proc->_pid); - - pipe = proc->pipe; - if (pipe == NULL || pipe->closed) { - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "closed") - errbuf; - return NGX_ERROR; - } - - if (pipe->merge_stderr && from_stderr) { - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "merged to stdout") - - errbuf; - return NGX_ERROR; - } - - if (from_stderr) { - if (pipe->stderr_ctx == NULL) { - if (ngx_http_lua_pipe_init_ctx(&pipe->stderr_ctx, pipe->stderr_fd, - pipe->pool, errbuf, - errbuf_size) - != NGX_OK) - { - return NGX_ERROR; - } - - } else { - pipe->stderr_ctx->err_type = 0; - } - - pipe_ctx = pipe->stderr_ctx; - - } else { - if (pipe->stdout_ctx == NULL) { - if (ngx_http_lua_pipe_init_ctx(&pipe->stdout_ctx, pipe->stdout_fd, - pipe->pool, errbuf, - errbuf_size) - != NGX_OK) - { - return NGX_ERROR; - } - - } else { - pipe->stdout_ctx->err_type = 0; - } - - pipe_ctx = pipe->stdout_ctx; - } - - c = pipe_ctx->c; - if (c == NULL) { - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "closed") - errbuf; - return NGX_ERROR; - } - - rev = c->read; - if (rev->handler != ngx_http_lua_pipe_dummy_event_handler) { - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "pipe busy reading") - - errbuf; - return NGX_ERROR; - } - - pipe_ctx->input_filter_ctx = pipe_ctx; - - switch (reader_type) { - - case PIPE_READ_ALL: - pipe_ctx->input_filter = ngx_http_lua_pipe_read_all; - break; - - case PIPE_READ_BYTES: - pipe_ctx->input_filter = ngx_http_lua_pipe_read_bytes; - break; - - case PIPE_READ_LINE: - pipe_ctx->input_filter = ngx_http_lua_pipe_read_line; - break; - - case PIPE_READ_ANY: - pipe_ctx->input_filter = ngx_http_lua_pipe_read_any; - break; - - default: - ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, - "unexpected reader_type: %d", reader_type); - ngx_http_lua_assert(NULL); - } - - pipe_ctx->rest = length; - - if (pipe_ctx->bufs_in == NULL) { - pipe_ctx->bufs_in = - ngx_http_lua_chain_get_free_buf(ngx_cycle->log, pipe->pool, - &pipe->free_bufs, - pipe->buffer_size); - - if (pipe_ctx->bufs_in == NULL) { - pipe_ctx->err_type = PIPE_ERR_NOMEM; - goto error; - } - - pipe_ctx->buf_in = pipe_ctx->bufs_in; - pipe_ctx->buffer = *pipe_ctx->buf_in->buf; - } - - rc = ngx_http_lua_pipe_read(pipe, pipe_ctx); - if (rc == NGX_ERROR) { - goto error; - } - - if (rc == NGX_OK) { - ngx_http_lua_pipe_put_data(pipe, pipe_ctx, buf, buf_size); - return NGX_OK; - } - - /* rc == NGX_AGAIN */ - wait_co_ctx = ctx->cur_co_ctx; - - c->data = wait_co_ctx; - if (ngx_handle_read_event(rev, 0) != NGX_OK) { - pipe_ctx->err_type = PIPE_ERR_ADD_READ_EV; - goto error; - } - - wait_co_ctx->data = proc; - - if (from_stderr) { - rev->handler = ngx_http_lua_pipe_resume_read_stderr_handler; - wait_co_ctx->cleanup = ngx_http_lua_pipe_proc_read_stderr_cleanup; - timeout = proc->stderr_read_timeout; - - } else { - rev->handler = ngx_http_lua_pipe_resume_read_stdout_handler; - wait_co_ctx->cleanup = ngx_http_lua_pipe_proc_read_stdout_cleanup; - timeout = proc->stdout_read_timeout; - } - - if (timeout > 0) { - ngx_add_timer(rev, timeout); - ngx_log_debug5(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua pipe add timer for reading: %d(ms) process:%p " - "pid:%P pipe:%p ev:%p", timeout, proc, proc->_pid, pipe, - rev); - } - - ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua pipe read yielding process:%p pid:%P pipe:%p", proc, - proc->_pid, pipe); - - return NGX_AGAIN; - -error: - - if (pipe_ctx->bufs_in) { - ngx_http_lua_pipe_put_data(pipe, pipe_ctx, buf, buf_size); - ngx_http_lua_pipe_put_error(pipe_ctx, errbuf, errbuf_size); - return NGX_DECLINED; - } - - ngx_http_lua_pipe_put_error(pipe_ctx, errbuf, errbuf_size); - - return NGX_ERROR; -} - - -/* - * ngx_http_lua_ffi_pipe_get_read_result should only be called just after - * ngx_http_lua_ffi_pipe_proc_read, so we omit most of the sanity check already - * done in ngx_http_lua_ffi_pipe_proc_read. - */ -int -ngx_http_lua_ffi_pipe_get_read_result(ngx_http_request_t *r, - ngx_http_lua_ffi_pipe_proc_t *proc, int from_stderr, u_char **buf, - size_t *buf_size, u_char *errbuf, size_t *errbuf_size) -{ - ngx_http_lua_pipe_t *pipe; - ngx_http_lua_pipe_ctx_t *pipe_ctx; - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua pipe get read result process:%p pid:%P", proc, - proc->_pid); - - pipe = proc->pipe; - pipe_ctx = from_stderr ? pipe->stderr_ctx : pipe->stdout_ctx; - - if (!pipe_ctx->err_type) { - ngx_http_lua_pipe_put_data(pipe, pipe_ctx, buf, buf_size); - return NGX_OK; - } - - if (pipe_ctx->bufs_in) { - ngx_http_lua_pipe_put_data(pipe, pipe_ctx, buf, buf_size); - ngx_http_lua_pipe_put_error(pipe_ctx, errbuf, errbuf_size); - return NGX_DECLINED; - } - - ngx_http_lua_pipe_put_error(pipe_ctx, errbuf, errbuf_size); - - return NGX_ERROR; -} - - -static ngx_int_t -ngx_http_lua_pipe_write(ngx_http_lua_pipe_t *pipe, - ngx_http_lua_pipe_ctx_t *pipe_ctx) -{ - size_t size; - ngx_int_t n; - ngx_buf_t *b; - ngx_connection_t *c; - - c = pipe_ctx->c; - b = pipe_ctx->buf_in->buf; - - for ( ;; ) { - size = b->last - b->pos; - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "lua pipe try to write data %uz pipe:%p", size, - pipe_ctx); - - n = c->send(c, b->pos, size); - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "lua pipe write returned %i pipe:%p", n, pipe_ctx); - - if (n >= 0) { - b->pos += n; - - if (b->pos == b->last) { - b->pos = b->start; - b->last = b->start; - - if (!pipe->free_bufs) { - pipe->free_bufs = pipe_ctx->buf_in; - - } else { - pipe->free_bufs->next = pipe_ctx->buf_in; - } - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "lua pipe write done pipe:%p", pipe_ctx); - return NGX_OK; - } - - continue; - } - - /* NGX_ERROR || NGX_AGAIN */ - break; - } - - if (n == NGX_ERROR) { - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, ngx_errno, - "lua pipe write data error pipe:%p", pipe_ctx); - - if (ngx_errno == NGX_EPIPE) { - pipe_ctx->err_type = PIPE_ERR_CLOSED; - - } else { - pipe_ctx->err_type = PIPE_ERR_SYSCALL; - pipe_ctx->pipe_errno = ngx_errno; - } - - return NGX_ERROR; - } - - return NGX_AGAIN; -} - - -ssize_t -ngx_http_lua_ffi_pipe_proc_write(ngx_http_request_t *r, - ngx_http_lua_ffi_pipe_proc_t *proc, const u_char *data, size_t len, - u_char *errbuf, size_t *errbuf_size) -{ - int rc; - ngx_buf_t *b; - ngx_msec_t timeout; - ngx_chain_t *cl; - ngx_event_t *wev; - ngx_http_lua_ctx_t *ctx; - ngx_http_lua_pipe_t *pipe; - ngx_http_lua_co_ctx_t *wait_co_ctx; - ngx_http_lua_pipe_ctx_t *pipe_ctx; - - rc = ngx_http_lua_pipe_get_lua_ctx(r, &ctx, errbuf, errbuf_size); - if (rc != NGX_OK) { - return rc; - } - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua pipe write process:%p pid:%P", proc, proc->_pid); - - pipe = proc->pipe; - if (pipe == NULL || pipe->closed) { - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "closed") - errbuf; - return NGX_ERROR; - } - - if (pipe->stdin_ctx == NULL) { - if (ngx_http_lua_pipe_init_ctx(&pipe->stdin_ctx, pipe->stdin_fd, - pipe->pool, errbuf, - errbuf_size) - != NGX_OK) - { - return NGX_ERROR; - } - - } else { - pipe->stdin_ctx->err_type = 0; - } - - pipe_ctx = pipe->stdin_ctx; - if (pipe_ctx->c == NULL) { - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "closed") - errbuf; - return NGX_ERROR; - } - - wev = pipe_ctx->c->write; - if (wev->handler != ngx_http_lua_pipe_dummy_event_handler) { - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "pipe busy writing") - - errbuf; - return NGX_ERROR; - } - - pipe_ctx->rest = len; - - cl = ngx_http_lua_chain_get_free_buf(ngx_cycle->log, pipe->pool, - &pipe->free_bufs, len); - if (cl == NULL) { - pipe_ctx->err_type = PIPE_ERR_NOMEM; - goto error; - } - - pipe_ctx->buf_in = cl; - b = pipe_ctx->buf_in->buf; - b->last = ngx_copy(b->last, data, len); - - rc = ngx_http_lua_pipe_write(pipe, pipe_ctx); - if (rc == NGX_ERROR) { - goto error; - } - - if (rc == NGX_OK) { - return len; - } - - /* rc == NGX_AGAIN */ - wait_co_ctx = ctx->cur_co_ctx; - pipe_ctx->c->data = wait_co_ctx; - - wev->handler = ngx_http_lua_pipe_resume_write_handler; - if (ngx_handle_write_event(wev, 0) != NGX_OK) { - pipe_ctx->err_type = PIPE_ERR_ADD_WRITE_EV; - goto error; - } - - wait_co_ctx->data = proc; - wait_co_ctx->cleanup = ngx_http_lua_pipe_proc_write_cleanup; - timeout = proc->write_timeout; - - if (timeout > 0) { - ngx_add_timer(wev, timeout); - ngx_log_debug5(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua pipe add timer for writing: %d(ms) process:%p " - "pid:%P pipe:%p ev:%p", timeout, proc, proc->_pid, pipe, - wev); - } - - ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua pipe write yielding process:%p pid:%P pipe:%p", proc, - proc->_pid, pipe); - - return NGX_AGAIN; - -error: - - ngx_http_lua_pipe_put_error(pipe_ctx, errbuf, errbuf_size); - return NGX_ERROR; -} - - -/* - * ngx_http_lua_ffi_pipe_get_write_result should only be called just after - * ngx_http_lua_ffi_pipe_proc_write, so we omit most of the sanity check - * already done in ngx_http_lua_ffi_pipe_proc_write. - */ -ssize_t -ngx_http_lua_ffi_pipe_get_write_result(ngx_http_request_t *r, - ngx_http_lua_ffi_pipe_proc_t *proc, u_char *errbuf, size_t *errbuf_size) -{ - ngx_http_lua_pipe_t *pipe; - ngx_http_lua_pipe_ctx_t *pipe_ctx; - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua pipe get write result process:%p pid:%P", proc, - proc->_pid); - - pipe = proc->pipe; - pipe_ctx = pipe->stdin_ctx; - - if (pipe_ctx->err_type) { - ngx_http_lua_pipe_put_error(pipe_ctx, errbuf, errbuf_size); - return NGX_ERROR; - } - - return pipe_ctx->rest; -} - - -int -ngx_http_lua_ffi_pipe_proc_wait(ngx_http_request_t *r, - ngx_http_lua_ffi_pipe_proc_t *proc, char **reason, int *status, - u_char *errbuf, size_t *errbuf_size) -{ - int rc; - ngx_rbtree_node_t *node; - ngx_http_lua_ctx_t *ctx; - ngx_http_lua_pipe_t *pipe; - ngx_http_lua_co_ctx_t *wait_co_ctx; - ngx_http_lua_pipe_node_t *pipe_node; - - rc = ngx_http_lua_pipe_get_lua_ctx(r, &ctx, errbuf, errbuf_size); - if (rc != NGX_OK) { - return rc; - } - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua pipe wait process:%p pid:%P", proc, proc->_pid); - - pipe = proc->pipe; - if (pipe == NULL || pipe->closed) { - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "exited") - errbuf; - return NGX_ERROR; - } - - node = pipe->node; - pipe_node = (ngx_http_lua_pipe_node_t *) &node->color; - if (pipe_node->wait_co_ctx) { - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "pipe busy waiting") - - errbuf; - return NGX_ERROR; - } - - if (pipe_node->reason_code == REASON_RUNNING_CODE) { - wait_co_ctx = ctx->cur_co_ctx; - wait_co_ctx->data = proc; - ngx_memzero(&wait_co_ctx->sleep, sizeof(ngx_event_t)); - wait_co_ctx->sleep.handler = ngx_http_lua_pipe_resume_wait_handler; - wait_co_ctx->sleep.data = wait_co_ctx; - wait_co_ctx->sleep.log = r->connection->log; - wait_co_ctx->cleanup = ngx_http_lua_pipe_proc_wait_cleanup; - - pipe_node->wait_co_ctx = wait_co_ctx; - - if (proc->wait_timeout > 0) { - ngx_add_timer(&wait_co_ctx->sleep, proc->wait_timeout); - ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua pipe add timer for waiting: %d(ms) process:%p " - "pid:%P ev:%p", proc->wait_timeout, proc, - proc->_pid, &wait_co_ctx->sleep); - } - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua pipe wait yielding process:%p pid:%P", proc, - proc->_pid); - - return NGX_AGAIN; - } - - *status = pipe_node->status; - - switch (pipe_node->reason_code) { - - case REASON_EXIT_CODE: - *reason = REASON_EXIT; - break; - - case REASON_SIGNAL_CODE: - *reason = REASON_SIGNAL; - break; - - default: - *reason = REASON_UNKNOWN; - } - - ngx_http_lua_pipe_proc_finalize(proc, 0); - - if (*status == 0) { - return NGX_OK; - } - - return NGX_DECLINED; -} - - -int -ngx_http_lua_ffi_pipe_proc_kill(ngx_http_lua_ffi_pipe_proc_t *proc, int signal, - u_char *errbuf, size_t *errbuf_size) -{ - ngx_pid_t pid; - ngx_http_lua_pipe_t *pipe; - - pipe = proc->pipe; - - if (pipe == NULL || pipe->dead) { - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "exited") - errbuf; - return NGX_ERROR; - } - - pid = proc->_pid; - - if (kill(pid, signal) == -1) { - switch (ngx_errno) { - case EINVAL: - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "invalid signal") - - errbuf; - break; - - case ESRCH: - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "exited") - - errbuf; - break; - - default: - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "%s", - strerror(ngx_errno)) - - errbuf; - } - - return NGX_ERROR; - } - - return NGX_OK; -} - - -static int -ngx_http_lua_pipe_read_stdout_retval(ngx_http_lua_ffi_pipe_proc_t *proc, - lua_State *L) -{ - return ngx_http_lua_pipe_read_retval_helper(proc, L, 0); -} - - -static int -ngx_http_lua_pipe_read_stderr_retval(ngx_http_lua_ffi_pipe_proc_t *proc, - lua_State *L) -{ - return ngx_http_lua_pipe_read_retval_helper(proc, L, 1); -} - - -static int -ngx_http_lua_pipe_read_retval_helper(ngx_http_lua_ffi_pipe_proc_t *proc, - lua_State *L, int from_stderr) -{ - int rc; - ngx_msec_t timeout; - ngx_event_t *rev; - ngx_http_lua_pipe_t *pipe; - ngx_http_lua_pipe_ctx_t *pipe_ctx; - - pipe = proc->pipe; - if (from_stderr) { - pipe_ctx = pipe->stderr_ctx; - - } else { - pipe_ctx = pipe->stdout_ctx; - } - - if (pipe->timeout) { - pipe->timeout = 0; - pipe_ctx->err_type = PIPE_ERR_TIMEOUT; - return 0; - } - - rc = ngx_http_lua_pipe_read(pipe, pipe_ctx); - if (rc != NGX_AGAIN) { - return 0; - } - - rev = pipe_ctx->c->read; - - if (from_stderr) { - rev->handler = ngx_http_lua_pipe_resume_read_stderr_handler; - timeout = proc->stderr_read_timeout; - - } else { - rev->handler = ngx_http_lua_pipe_resume_read_stdout_handler; - timeout = proc->stdout_read_timeout; - } - - if (timeout > 0) { - ngx_add_timer(rev, timeout); - ngx_log_debug5(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "lua pipe add timer for reading: %d(ms) proc:%p " - "pid:%P pipe:%p ev:%p", timeout, proc, proc->_pid, pipe, - rev); - } - - ngx_log_debug3(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "lua pipe read yielding process:%p pid:%P pipe:%p", proc, - proc->_pid, pipe); - - return NGX_AGAIN; -} - - -static int -ngx_http_lua_pipe_write_retval(ngx_http_lua_ffi_pipe_proc_t *proc, - lua_State *L) -{ - int rc; - ngx_msec_t timeout; - ngx_event_t *wev; - ngx_http_lua_pipe_t *pipe; - ngx_http_lua_pipe_ctx_t *pipe_ctx; - - pipe = proc->pipe; - pipe_ctx = pipe->stdin_ctx; - - if (pipe->timeout) { - pipe->timeout = 0; - pipe_ctx->err_type = PIPE_ERR_TIMEOUT; - return 0; - } - - rc = ngx_http_lua_pipe_write(pipe, pipe_ctx); - if (rc != NGX_AGAIN) { - return 0; - } - - wev = pipe_ctx->c->write; - wev->handler = ngx_http_lua_pipe_resume_write_handler; - timeout = proc->write_timeout; - - if (timeout > 0) { - ngx_add_timer(wev, timeout); - ngx_log_debug5(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "lua pipe add timer for writing: %d(ms) proc:%p " - "pid:%P pipe:%p ev:%p", timeout, proc, proc->_pid, pipe, - wev); - } - - ngx_log_debug3(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "lua pipe write yielding process:%p pid:%P pipe:%p", proc, - proc->_pid, pipe); - - return NGX_AGAIN; -} - - -static int -ngx_http_lua_pipe_wait_retval(ngx_http_lua_ffi_pipe_proc_t *proc, lua_State *L) -{ - int nret; - ngx_rbtree_node_t *node; - ngx_http_lua_pipe_t *pipe; - ngx_http_lua_pipe_node_t *pipe_node; - - pipe = proc->pipe; - node = pipe->node; - pipe_node = (ngx_http_lua_pipe_node_t *) &node->color; - pipe_node->wait_co_ctx = NULL; - - if (pipe->timeout) { - pipe->timeout = 0; - lua_pushnil(L); - lua_pushliteral(L, "timeout"); - return 2; - } - - ngx_http_lua_pipe_proc_finalize(pipe_node->proc, 0); - - if (pipe_node->status == 0) { - lua_pushboolean(L, 1); - lua_pushliteral(L, REASON_EXIT); - lua_pushinteger(L, pipe_node->status); - nret = 3; - - } else { - lua_pushboolean(L, 0); - - switch (pipe_node->reason_code) { - - case REASON_EXIT_CODE: - lua_pushliteral(L, REASON_EXIT); - break; - - case REASON_SIGNAL_CODE: - lua_pushliteral(L, REASON_SIGNAL); - break; - - default: - lua_pushliteral(L, REASON_UNKNOWN); - } - - lua_pushinteger(L, pipe_node->status); - nret = 3; - } - - return nret; -} - - -static void -ngx_http_lua_pipe_resume_helper(ngx_event_t *ev, - ngx_http_lua_co_ctx_t *wait_co_ctx) -{ - ngx_connection_t *c; - ngx_http_request_t *r; - ngx_http_lua_ctx_t *ctx; - ngx_http_lua_pipe_t *pipe; - ngx_http_lua_ffi_pipe_proc_t *proc; - - if (ev->timedout) { - proc = wait_co_ctx->data; - pipe = proc->pipe; - pipe->timeout = 1; - ev->timedout = 0; - } - - ngx_http_lua_pipe_clear_event(ev); - - r = ngx_http_lua_get_req(wait_co_ctx->co); - c = r->connection; - - ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); - ngx_http_lua_assert(ctx != NULL); - - ctx->cur_co_ctx = wait_co_ctx; - - if (ctx->entered_content_phase) { - (void) ngx_http_lua_pipe_resume(r); - - } else { - ctx->resume_handler = ngx_http_lua_pipe_resume; - ngx_http_core_run_phases(r); - } - - ngx_http_run_posted_requests(c); -} - - -static void -ngx_http_lua_pipe_resume_read_stdout_handler(ngx_event_t *ev) -{ - ngx_connection_t *c = ev->data; - ngx_http_lua_co_ctx_t *wait_co_ctx; - ngx_http_lua_pipe_t *pipe; - ngx_http_lua_ffi_pipe_proc_t *proc; - - wait_co_ctx = c->data; - proc = wait_co_ctx->data; - pipe = proc->pipe; - pipe->retval_handler = ngx_http_lua_pipe_read_stdout_retval; - ngx_http_lua_pipe_resume_helper(ev, wait_co_ctx); -} - - -static void -ngx_http_lua_pipe_resume_read_stderr_handler(ngx_event_t *ev) -{ - ngx_connection_t *c = ev->data; - ngx_http_lua_co_ctx_t *wait_co_ctx; - ngx_http_lua_pipe_t *pipe; - ngx_http_lua_ffi_pipe_proc_t *proc; - - wait_co_ctx = c->data; - proc = wait_co_ctx->data; - pipe = proc->pipe; - pipe->retval_handler = ngx_http_lua_pipe_read_stderr_retval; - ngx_http_lua_pipe_resume_helper(ev, wait_co_ctx); -} - - -static void -ngx_http_lua_pipe_resume_write_handler(ngx_event_t *ev) -{ - ngx_connection_t *c = ev->data; - ngx_http_lua_co_ctx_t *wait_co_ctx; - ngx_http_lua_pipe_t *pipe; - ngx_http_lua_ffi_pipe_proc_t *proc; - - wait_co_ctx = c->data; - proc = wait_co_ctx->data; - pipe = proc->pipe; - pipe->retval_handler = ngx_http_lua_pipe_write_retval; - ngx_http_lua_pipe_resume_helper(ev, wait_co_ctx); -} - - -static void -ngx_http_lua_pipe_resume_wait_handler(ngx_event_t *ev) -{ - ngx_http_lua_co_ctx_t *wait_co_ctx = ev->data; - ngx_http_lua_pipe_t *pipe; - ngx_http_lua_ffi_pipe_proc_t *proc; - - proc = wait_co_ctx->data; - pipe = proc->pipe; - pipe->retval_handler = ngx_http_lua_pipe_wait_retval; - ngx_http_lua_pipe_resume_helper(ev, wait_co_ctx); -} - - -static ngx_int_t -ngx_http_lua_pipe_resume(ngx_http_request_t *r) -{ - int nret; - lua_State *vm; - ngx_int_t rc; - ngx_uint_t nreqs; - ngx_connection_t *c; - ngx_http_lua_ctx_t *ctx; - ngx_http_lua_pipe_t *pipe; - ngx_http_lua_ffi_pipe_proc_t *proc; - - 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; - ctx->cur_co_ctx->cleanup = NULL; - - proc = ctx->cur_co_ctx->data; - pipe = proc->pipe; - nret = pipe->retval_handler(proc, ctx->cur_co_ctx->co); - if (nret == NGX_AGAIN) { - return NGX_DONE; - } - - c = r->connection; - vm = ngx_http_lua_get_lua_vm(r, ctx); - nreqs = c->requests; - - rc = ngx_http_lua_run_thread(vm, r, ctx, nret); - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua run thread returned %d", rc); - - if (rc == NGX_AGAIN) { - return ngx_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); - } - - /* rc == NGX_ERROR || rc >= NGX_OK */ - - if (ctx->entered_content_phase) { - ngx_http_lua_finalize_request(r, rc); - return NGX_DONE; - } - - return rc; -} - - -static void -ngx_http_lua_pipe_dummy_event_handler(ngx_event_t *ev) -{ - /* do nothing */ -} - - -static void -ngx_http_lua_pipe_clear_event(ngx_event_t *ev) -{ - ev->handler = ngx_http_lua_pipe_dummy_event_handler; - - if (ev->timer_set) { - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ev->log, 0, - "lua pipe del timer for ev:%p", ev); - ngx_del_timer(ev); - } - - if (ev->posted) { - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ev->log, 0, - "lua pipe del posted event for ev:%p", ev); - ngx_delete_posted_event(ev); - } -} - - -static void -ngx_http_lua_pipe_proc_read_stdout_cleanup(void *data) -{ - ngx_event_t *rev; - ngx_connection_t *c; - ngx_http_lua_co_ctx_t *wait_co_ctx = data; - ngx_http_lua_ffi_pipe_proc_t *proc; - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "lua pipe proc read stdout cleanup"); - - proc = wait_co_ctx->data; - c = proc->pipe->stdout_ctx->c; - if (c) { - rev = c->read; - ngx_http_lua_pipe_clear_event(rev); - } - - wait_co_ctx->cleanup = NULL; -} - - -static void -ngx_http_lua_pipe_proc_read_stderr_cleanup(void *data) -{ - ngx_event_t *rev; - ngx_connection_t *c; - ngx_http_lua_co_ctx_t *wait_co_ctx = data; - ngx_http_lua_ffi_pipe_proc_t *proc; - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "lua pipe proc read stderr cleanup"); - - proc = wait_co_ctx->data; - c = proc->pipe->stderr_ctx->c; - if (c) { - rev = c->read; - ngx_http_lua_pipe_clear_event(rev); - } - - wait_co_ctx->cleanup = NULL; -} - - -static void -ngx_http_lua_pipe_proc_write_cleanup(void *data) -{ - ngx_event_t *wev; - ngx_connection_t *c; - ngx_http_lua_co_ctx_t *wait_co_ctx = data; - ngx_http_lua_ffi_pipe_proc_t *proc; - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "lua pipe proc write cleanup"); - - proc = wait_co_ctx->data; - c = proc->pipe->stdin_ctx->c; - if (c) { - wev = c->write; - ngx_http_lua_pipe_clear_event(wev); - } - - wait_co_ctx->cleanup = NULL; -} - - -static void -ngx_http_lua_pipe_proc_wait_cleanup(void *data) -{ - ngx_rbtree_node_t *node; - ngx_http_lua_co_ctx_t *wait_co_ctx = data; - ngx_http_lua_pipe_node_t *pipe_node; - ngx_http_lua_ffi_pipe_proc_t *proc; - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "lua pipe proc wait cleanup"); - - proc = wait_co_ctx->data; - node = proc->pipe->node; - pipe_node = (ngx_http_lua_pipe_node_t *) &node->color; - pipe_node->wait_co_ctx = NULL; - - ngx_http_lua_pipe_clear_event(&wait_co_ctx->sleep); - - wait_co_ctx->cleanup = NULL; -} - - -#endif /* HAVE_NGX_LUA_PIPE */ - -/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_pipe.h b/debian/modules/http-lua/src/ngx_http_lua_pipe.h deleted file mode 100644 index b5cea89..0000000 --- a/debian/modules/http-lua/src/ngx_http_lua_pipe.h +++ /dev/null @@ -1,95 +0,0 @@ - -/* - * Copyright (C) by OpenResty Inc. - */ - - -#ifndef _NGX_HTTP_LUA_PIPE_H_INCLUDED_ -#define _NGX_HTTP_LUA_PIPE_H_INCLUDED_ - - -#include "ngx_http_lua_common.h" - - -typedef ngx_int_t (*ngx_http_lua_pipe_input_filter)(void *data, ssize_t bytes); - - -typedef struct { - ngx_connection_t *c; - ngx_http_lua_pipe_input_filter input_filter; - void *input_filter_ctx; - size_t rest; - ngx_chain_t *buf_in; - ngx_chain_t *bufs_in; - ngx_buf_t buffer; - ngx_err_t pipe_errno; - unsigned err_type:16; - unsigned eof:1; -} ngx_http_lua_pipe_ctx_t; - - -typedef struct ngx_http_lua_pipe_s ngx_http_lua_pipe_t; - - -typedef struct { - ngx_pid_t _pid; - ngx_msec_t write_timeout; - ngx_msec_t stdout_read_timeout; - ngx_msec_t stderr_read_timeout; - ngx_msec_t wait_timeout; - /* pipe hides the implementation from the Lua binding */ - ngx_http_lua_pipe_t *pipe; -} ngx_http_lua_ffi_pipe_proc_t; - - -typedef int (*ngx_http_lua_pipe_retval_handler)( - ngx_http_lua_ffi_pipe_proc_t *proc, lua_State *L); - - -struct ngx_http_lua_pipe_s { - ngx_pool_t *pool; - ngx_chain_t *free_bufs; - ngx_rbtree_node_t *node; - int stdin_fd; - int stdout_fd; - int stderr_fd; - ngx_http_lua_pipe_ctx_t *stdin_ctx; - ngx_http_lua_pipe_ctx_t *stdout_ctx; - ngx_http_lua_pipe_ctx_t *stderr_ctx; - ngx_http_lua_pipe_retval_handler retval_handler; - size_t buffer_size; - unsigned closed:1; - unsigned dead:1; - unsigned timeout:1; - unsigned merge_stderr:1; -}; - - -typedef struct { - u_char color; - u_char reason_code; - int status; - ngx_http_lua_co_ctx_t *wait_co_ctx; - ngx_http_lua_ffi_pipe_proc_t *proc; -} ngx_http_lua_pipe_node_t; - - -typedef struct { - int signo; - char *signame; -} ngx_http_lua_pipe_signal_t; - - -#if !(NGX_WIN32) && !defined(NGX_LUA_NO_FFI_API) \ - && defined(HAVE_SOCKET_CLOEXEC_PATCH) -#define HAVE_NGX_LUA_PIPE 1 - - -void ngx_http_lua_pipe_init(void); -ngx_int_t ngx_http_lua_pipe_add_signal_handler(ngx_cycle_t *cycle); -#endif - - -#endif /* _NGX_HTTP_LUA_PIPE_H_INCLUDED_ */ - -/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_regex.c b/debian/modules/http-lua/src/ngx_http_lua_regex.c index 8f3373b..843d1e4 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_regex.c +++ b/debian/modules/http-lua/src/ngx_http_lua_regex.c @@ -15,6 +15,7 @@ #include "ngx_http_lua_regex.h" #include "ngx_http_lua_pcrefix.h" #include "ngx_http_lua_script.h" +#include "ngx_http_lua_pcrefix.h" #include "ngx_http_lua_util.h" @@ -248,8 +249,7 @@ ngx_http_lua_ngx_re_match_helper(lua_State *L, int wantcaps) dd("server pool %p", lmcf->pool); - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - regex_cache_key)); + lua_pushlightuserdata(L, &ngx_http_lua_regex_cache_key); lua_rawget(L, LUA_REGISTRYINDEX); /* table */ lua_pushliteral(L, "m"); @@ -720,8 +720,7 @@ ngx_http_lua_ngx_re_gmatch(lua_State *L) dd("server pool %p", lmcf->pool); - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - regex_cache_key)); + lua_pushlightuserdata(L, &ngx_http_lua_regex_cache_key); lua_rawget(L, LUA_REGISTRYINDEX); /* table */ lua_pushliteral(L, "m"); @@ -1389,8 +1388,7 @@ ngx_http_lua_ngx_re_sub_helper(lua_State *L, unsigned global) dd("server pool %p", lmcf->pool); - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - regex_cache_key)); + lua_pushlightuserdata(L, &ngx_http_lua_regex_cache_key); lua_rawget(L, LUA_REGISTRYINDEX); /* table */ lua_pushliteral(L, "s"); diff --git a/debian/modules/http-lua/src/ngx_http_lua_rewriteby.c b/debian/modules/http-lua/src/ngx_http_lua_rewriteby.c index 1de9968..1bbe87c 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_rewriteby.c +++ b/debian/modules/http-lua/src/ngx_http_lua_rewriteby.c @@ -62,7 +62,7 @@ ngx_http_lua_rewrite_handler(ngx_http_request_t *r) #endif if (cur_ph < last_ph) { - dd("swapping the contents of cur_ph and last_ph..."); + dd("swaping the contents of cur_ph and last_ph..."); tmp = *cur_ph; @@ -261,11 +261,9 @@ ngx_http_lua_rewrite_by_chunk(lua_State *L, ngx_http_request_t *r) /* 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); diff --git a/debian/modules/http-lua/src/ngx_http_lua_script.c b/debian/modules/http-lua/src/ngx_http_lua_script.c index c675a16..95ebadf 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_script.c +++ b/debian/modules/http-lua/src/ngx_http_lua_script.c @@ -329,7 +329,7 @@ ngx_http_lua_script_add_copy_code(ngx_http_lua_script_compile_t *sc, return NGX_ERROR; } - code->code = (ngx_http_lua_script_code_pt) (void *) + code->code = (ngx_http_lua_script_code_pt) ngx_http_lua_script_copy_len_code; code->len = len; @@ -399,7 +399,7 @@ ngx_http_lua_script_add_capture_code(ngx_http_lua_script_compile_t *sc, return NGX_ERROR; } - code->code = (ngx_http_lua_script_code_pt) (void *) + code->code = (ngx_http_lua_script_code_pt) ngx_http_lua_script_copy_capture_len_code; code->n = 2 * n; diff --git a/debian/modules/http-lua/src/ngx_http_lua_setby.c b/debian/modules/http-lua/src/ngx_http_lua_setby.c index d4288b5..2e8762a 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_setby.c +++ b/debian/modules/http-lua/src/ngx_http_lua_setby.c @@ -30,6 +30,13 @@ static void ngx_http_lua_set_by_lua_env(lua_State *L, ngx_http_request_t *r, size_t nargs, ngx_http_variable_value_t *args); +/* keys in Lua thread for fetching args and nargs in set_by_lua* */ + +#define ngx_http_lua_nargs_key "__ngx_nargs" + +#define ngx_http_lua_args_key "__ngx_args" + + ngx_int_t 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) @@ -127,24 +134,23 @@ 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) +ngx_http_lua_setby_param_get(lua_State *L) { 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); + /* get number of args from globals */ + lua_getglobal(L, ngx_http_lua_nargs_key); + n = (int) lua_tointeger(L, -1); - /* get number of args from lmcf */ - n = lmcf->setby_nargs; - - /* get args from lmcf */ - v = lmcf->setby_args; + /* get args from globals */ + lua_getglobal(L, ngx_http_lua_args_key); + v = lua_touserdata(L, -1); if (idx < 0 || idx > n - 1) { lua_pushnil(L); @@ -172,16 +178,15 @@ static void ngx_http_lua_set_by_lua_env(lua_State *L, ngx_http_request_t *r, size_t nargs, ngx_http_variable_value_t *args) { - ngx_http_lua_main_conf_t *lmcf; - + /* set nginx request pointer to current lua thread's globals table */ ngx_http_lua_set_req(L, r); - lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); + lua_pushinteger(L, nargs); + lua_setglobal(L, ngx_http_lua_nargs_key); - lmcf->setby_nargs = nargs; - lmcf->setby_args = args; + lua_pushlightuserdata(L, args); + lua_setglobal(L, ngx_http_lua_args_key); -#ifndef OPENRESTY_LUAJIT /** * we want to create empty environment for current script * @@ -206,7 +211,6 @@ ngx_http_lua_set_by_lua_env(lua_State *L, ngx_http_request_t *r, size_t nargs, /* }}} */ lua_setfenv(L, -2); /* set new running env for the code closure */ -#endif } /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_setby.h b/debian/modules/http-lua/src/ngx_http_lua_setby.h index f43eef7..da71753 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_setby.h +++ b/debian/modules/http-lua/src/ngx_http_lua_setby.h @@ -7,7 +7,7 @@ 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); +int ngx_http_lua_setby_param_get(lua_State *L); #endif /* _NGX_HTTP_LUA_SET_BY_H_INCLUDED_ */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_shdict.c b/debian/modules/http-lua/src/ngx_http_lua_shdict.c index b017bea..5fb7930 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_shdict.c +++ b/debian/modules/http-lua/src/ngx_http_lua_shdict.c @@ -325,7 +325,6 @@ ngx_http_lua_inject_shdict_api(ngx_http_lua_main_conf_t *lmcf, lua_State *L) ngx_http_lua_shdict_ctx_t *ctx; ngx_uint_t i; ngx_shm_zone_t **zone; - ngx_shm_zone_t **zone_udata; if (lmcf->shdict_zones != NULL) { lua_createtable(L, 0, lmcf->shdict_zones->nelts /* nrec */); @@ -397,9 +396,7 @@ ngx_http_lua_inject_shdict_api(ngx_http_lua_main_conf_t *lmcf, lua_State *L) lua_createtable(L, 1 /* narr */, 0 /* nrec */); /* table of zone[i] */ - zone_udata = lua_newuserdata(L, sizeof(ngx_shm_zone_t *)); - /* shared mt key ud */ - *zone_udata = zone[i]; + lua_pushlightuserdata(L, zone[i]); /* shared mt key ud */ lua_rawseti(L, -2, SHDICT_USERDATA_INDEX); /* {zone[i]} */ lua_pushvalue(L, -3); /* shared mt key ud mt */ lua_setmetatable(L, -2); /* shared mt key ud */ @@ -434,17 +431,11 @@ static ngx_inline ngx_shm_zone_t * ngx_http_lua_shdict_get_zone(lua_State *L, int index) { ngx_shm_zone_t *zone; - ngx_shm_zone_t **zone_udata; lua_rawgeti(L, index, SHDICT_USERDATA_INDEX); - zone_udata = lua_touserdata(L, -1); + zone = lua_touserdata(L, -1); lua_pop(L, 1); - if (zone_udata == NULL) { - return NULL; - } - - zone = *zone_udata; return zone; } @@ -2218,17 +2209,6 @@ ngx_http_lua_find_zone(u_char *name_data, size_t name_len) #ifndef NGX_LUA_NO_FFI_API -ngx_shm_zone_t * -ngx_http_lua_ffi_shdict_udata_to_zone(void *zone_udata) -{ - if (zone_udata == NULL) { - return NULL; - } - - return *(ngx_shm_zone_t **) zone_udata; -} - - int ngx_http_lua_ffi_shdict_store(ngx_shm_zone_t *zone, int op, u_char *key, size_t key_len, int value_type, u_char *str_value_buf, @@ -2245,6 +2225,10 @@ ngx_http_lua_ffi_shdict_store(ngx_shm_zone_t *zone, int op, u_char *key, ngx_http_lua_shdict_ctx_t *ctx; ngx_http_lua_shdict_node_t *sd; + if (zone == NULL) { + return NGX_ERROR; + } + dd("exptime: %ld", exptime); ctx = zone->data; @@ -2506,6 +2490,10 @@ ngx_http_lua_ffi_shdict_get(ngx_shm_zone_t *zone, u_char *key, ngx_http_lua_shdict_node_t *sd; ngx_str_t value; + if (zone == NULL) { + return NGX_ERROR; + } + *err = NULL; ctx = zone->data; @@ -2648,6 +2636,10 @@ ngx_http_lua_ffi_shdict_incr(ngx_shm_zone_t *zone, u_char *key, u_char *p; ngx_queue_t *queue, *q; + if (zone == NULL) { + return NGX_ERROR; + } + if (init_ttl > 0) { tp = ngx_timeofday(); } @@ -2923,6 +2915,10 @@ ngx_http_lua_ffi_shdict_get_ttl(ngx_shm_zone_t *zone, u_char *key, ngx_http_lua_shdict_ctx_t *ctx; ngx_http_lua_shdict_node_t *sd; + if (zone == NULL) { + return NGX_ERROR; + } + ctx = zone->data; hash = ngx_crc32_short(key, key_len); @@ -2963,6 +2959,10 @@ ngx_http_lua_ffi_shdict_set_expire(ngx_shm_zone_t *zone, u_char *key, ngx_http_lua_shdict_ctx_t *ctx; ngx_http_lua_shdict_node_t *sd; + if (zone == NULL) { + return NGX_ERROR; + } + if (exptime > 0) { tp = ngx_timeofday(); } diff --git a/debian/modules/http-lua/src/ngx_http_lua_socket_tcp.c b/debian/modules/http-lua/src/ngx_http_lua_socket_tcp.c index 87461e6..efdf427 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_socket_tcp.c +++ b/debian/modules/http-lua/src/ngx_http_lua_socket_tcp.c @@ -11,7 +11,6 @@ #include "ngx_http_lua_socket_tcp.h" -#include "ngx_http_lua_input_filters.h" #include "ngx_http_lua_util.h" #include "ngx_http_lua_uthread.h" #include "ngx_http_lua_output.h" @@ -25,7 +24,6 @@ static int ngx_http_lua_socket_tcp_connect(lua_State *L); static int ngx_http_lua_socket_tcp_sslhandshake(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); static int ngx_http_lua_socket_tcp_send(lua_State *L); static int ngx_http_lua_socket_tcp_close(lua_State *L); static int ngx_http_lua_socket_tcp_setoption(lua_State *L); @@ -71,8 +69,6 @@ static int ngx_http_lua_socket_tcp_conn_retval_handler(ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u, lua_State *L); 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 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, @@ -90,7 +86,6 @@ static int ngx_http_lua_socket_write_error_retval_handler(ngx_http_request_t *r, static ngx_int_t ngx_http_lua_socket_read_all(void *data, ssize_t bytes); static ngx_int_t ngx_http_lua_socket_read_until(void *data, ssize_t bytes); static ngx_int_t ngx_http_lua_socket_read_chunk(void *data, ssize_t bytes); -static ngx_int_t ngx_http_lua_socket_read_any(void *data, ssize_t bytes); static int ngx_http_lua_socket_tcp_receiveuntil(lua_State *L); static int ngx_http_lua_socket_receiveuntil_iterator(lua_State *L); static ngx_int_t ngx_http_lua_socket_compile_pattern(u_char *data, size_t len, @@ -100,28 +95,12 @@ static int ngx_http_lua_req_socket(lua_State *L); static void ngx_http_lua_req_socket_rev_handler(ngx_http_request_t *r); static int ngx_http_lua_socket_tcp_getreusedtimes(lua_State *L); static int ngx_http_lua_socket_tcp_setkeepalive(lua_State *L); -static void ngx_http_lua_socket_tcp_create_socket_pool(lua_State *L, - ngx_http_request_t *r, ngx_str_t key, ngx_int_t pool_size, - ngx_int_t backlog, ngx_http_lua_socket_pool_t **spool); static ngx_int_t ngx_http_lua_get_keepalive_peer(ngx_http_request_t *r, + lua_State *L, int key_index, ngx_http_lua_socket_tcp_upstream_t *u); static void ngx_http_lua_socket_keepalive_dummy_handler(ngx_event_t *ev); -static int ngx_http_lua_socket_tcp_connect_helper(lua_State *L, - ngx_http_lua_socket_tcp_upstream_t *u, ngx_http_request_t *r, - ngx_http_lua_ctx_t *ctx, u_char *host_ref, size_t host_len, in_port_t port, - unsigned resuming); -static void ngx_http_lua_socket_tcp_conn_op_timeout_handler( - ngx_event_t *ev); -static int ngx_http_lua_socket_tcp_conn_op_timeout_retval_handler( - ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u, lua_State *L); -static void ngx_http_lua_socket_tcp_resume_conn_op( - ngx_http_lua_socket_pool_t *spool); -static void ngx_http_lua_socket_tcp_conn_op_ctx_cleanup(void *data); -static void ngx_http_lua_socket_tcp_conn_op_resume_handler(ngx_event_t *ev); static ngx_int_t ngx_http_lua_socket_keepalive_close_handler(ngx_event_t *ev); static void ngx_http_lua_socket_keepalive_rev_handler(ngx_event_t *ev); -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, @@ -134,13 +113,11 @@ static ngx_int_t ngx_http_lua_socket_add_input_buffer(ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u); static ngx_int_t ngx_http_lua_socket_insert_buffer(ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u, u_char *pat, size_t prefix); -static ngx_int_t ngx_http_lua_socket_tcp_conn_op_resume(ngx_http_request_t *r); static ngx_int_t ngx_http_lua_socket_tcp_conn_resume(ngx_http_request_t *r); static ngx_int_t ngx_http_lua_socket_tcp_read_resume(ngx_http_request_t *r); static ngx_int_t ngx_http_lua_socket_tcp_write_resume(ngx_http_request_t *r); static ngx_int_t ngx_http_lua_socket_tcp_resume_helper(ngx_http_request_t *r, int socket_op); -static void ngx_http_lua_tcp_queue_conn_op_cleanup(void *data); static void ngx_http_lua_tcp_resolve_cleanup(void *data); static void ngx_http_lua_coctx_cleanup(void *data); static void ngx_http_lua_socket_free_pool(ngx_log_t *log, @@ -173,8 +150,7 @@ enum { enum { SOCKET_OP_CONNECT, SOCKET_OP_READ, - SOCKET_OP_WRITE, - SOCKET_OP_RESUME_CONN + SOCKET_OP_WRITE }; @@ -253,8 +229,7 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) lua_setfield(L, -2, "socket"); /* {{{req socket object metatable */ - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - req_socket_metatable_key)); + lua_pushlightuserdata(L, &ngx_http_lua_req_socket_metatable_key); lua_createtable(L, 0 /* narr */, 5 /* nrec */); lua_pushcfunction(L, ngx_http_lua_socket_tcp_receive); @@ -276,8 +251,7 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) /* }}} */ /* {{{raw req socket object metatable */ - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - raw_req_socket_metatable_key)); + lua_pushlightuserdata(L, &ngx_http_lua_raw_req_socket_metatable_key); lua_createtable(L, 0 /* narr */, 6 /* nrec */); lua_pushcfunction(L, ngx_http_lua_socket_tcp_receive); @@ -302,8 +276,7 @@ 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_pushlightuserdata(L, &ngx_http_lua_tcp_socket_metatable_key); lua_createtable(L, 0 /* narr */, 12 /* nrec */); lua_pushcfunction(L, ngx_http_lua_socket_tcp_connect); @@ -319,9 +292,6 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) lua_pushcfunction(L, ngx_http_lua_socket_tcp_receive); lua_setfield(L, -2, "receive"); - lua_pushcfunction(L, ngx_http_lua_socket_tcp_receiveany); - lua_setfield(L, -2, "receiveany"); - lua_pushcfunction(L, ngx_http_lua_socket_tcp_receiveuntil); lua_setfield(L, -2, "receiveuntil"); @@ -352,8 +322,7 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) /* }}} */ /* {{{upstream userdata metatable */ - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - upstream_udata_metatable_key)); + lua_pushlightuserdata(L, &ngx_http_lua_upstream_udata_metatable_key); lua_createtable(L, 0 /* narr */, 1 /* nrec */); /* metatable */ lua_pushcfunction(L, ngx_http_lua_socket_tcp_upstream_destroy); lua_setfield(L, -2, "__gc"); @@ -361,8 +330,7 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) /* }}} */ /* {{{downstream userdata metatable */ - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - downstream_udata_metatable_key)); + lua_pushlightuserdata(L, &ngx_http_lua_downstream_udata_metatable_key); lua_createtable(L, 0 /* narr */, 1 /* nrec */); /* metatable */ lua_pushcfunction(L, ngx_http_lua_socket_downstream_destroy); lua_setfield(L, -2, "__gc"); @@ -370,8 +338,7 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) /* }}} */ /* {{{socket pool userdata metatable */ - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - pool_udata_metatable_key)); + lua_pushlightuserdata(L, &ngx_http_lua_pool_udata_metatable_key); lua_createtable(L, 0, 1); /* metatable */ lua_pushcfunction(L, ngx_http_lua_socket_shutdown_pool); lua_setfield(L, -2, "__gc"); @@ -379,8 +346,7 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) /* }}} */ /* {{{socket compiled pattern userdata metatable */ - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - pattern_udata_metatable_key)); + lua_pushlightuserdata(L, &ngx_http_lua_pattern_udata_metatable_key); lua_createtable(L, 0 /* narr */, 1 /* nrec */); /* metatable */ lua_pushcfunction(L, ngx_http_lua_socket_cleanup_compiled_pattern); lua_setfield(L, -2, "__gc"); @@ -390,8 +356,7 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) #if (NGX_HTTP_SSL) /* {{{ssl session userdata metatable */ - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - ssl_session_metatable_key)); + lua_pushlightuserdata(L, &ngx_http_lua_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"); @@ -439,8 +404,7 @@ ngx_http_lua_socket_tcp(lua_State *L) | NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH); lua_createtable(L, 5 /* narr */, 1 /* nrec */); - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - tcp_socket_metatable_key)); + lua_pushlightuserdata(L, &ngx_http_lua_tcp_socket_metatable_key); lua_rawget(L, LUA_REGISTRYINDEX); lua_setmetatable(L, -2); @@ -450,421 +414,31 @@ ngx_http_lua_socket_tcp(lua_State *L) } -static void -ngx_http_lua_socket_tcp_create_socket_pool(lua_State *L, ngx_http_request_t *r, - ngx_str_t key, ngx_int_t pool_size, ngx_int_t backlog, - ngx_http_lua_socket_pool_t **spool) -{ - u_char *p; - size_t size, key_len; - ngx_int_t i; - ngx_http_lua_socket_pool_t *sp; - ngx_http_lua_socket_pool_item_t *items; - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua tcp socket connection pool size: %i, backlog: %i", - pool_size, backlog); - - key_len = ngx_align(key.len + 1, sizeof(void *)); - - size = sizeof(ngx_http_lua_socket_pool_t) - 1 + key_len - + sizeof(ngx_http_lua_socket_pool_item_t) * pool_size; - - /* before calling this function, the Lua stack is: - * -1 key - * -2 pools - */ - sp = lua_newuserdata(L, size); - if (sp == NULL) { - luaL_error(L, "no memory"); - return; - } - - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - pool_udata_metatable_key)); - lua_rawget(L, LUA_REGISTRYINDEX); - lua_setmetatable(L, -2); - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua tcp socket keepalive create connection pool for key" - " \"%V\"", &key); - - /* a new socket pool with metatable is push to the stack, so now we have: - * -1 sp - * -2 key - * -3 pools - * - * it is time to set pools[key] to sp. - */ - lua_rawset(L, -3); - - /* clean up the stack for consistency's sake */ - lua_pop(L, 1); - - sp->backlog = backlog; - sp->size = pool_size; - sp->connections = 0; - sp->lua_vm = ngx_http_lua_get_lua_vm(r, NULL); - - ngx_queue_init(&sp->cache_connect_op); - ngx_queue_init(&sp->wait_connect_op); - ngx_queue_init(&sp->cache); - ngx_queue_init(&sp->free); - - p = ngx_copy(sp->key, key.data, key.len); - *p++ = '\0'; - - items = (ngx_http_lua_socket_pool_item_t *) (sp->key + key_len); - - dd("items: %p", items); - - ngx_http_lua_assert((void *) items == ngx_align_ptr(items, sizeof(void *))); - - for (i = 0; i < pool_size; i++) { - ngx_queue_insert_head(&sp->free, &items[i].queue); - items[i].socket_pool = sp; - } - - *spool = sp; -} - - -static int -ngx_http_lua_socket_tcp_connect_helper(lua_State *L, - ngx_http_lua_socket_tcp_upstream_t *u, ngx_http_request_t *r, - ngx_http_lua_ctx_t *ctx, u_char *host_ref, size_t host_len, in_port_t port, - unsigned resuming) -{ - int n; - int host_size; - int saved_top; - ngx_int_t rc; - ngx_str_t host; - ngx_str_t *conn_op_host; - ngx_url_t url; - ngx_queue_t *q; - ngx_resolver_ctx_t *rctx, temp; - ngx_http_lua_co_ctx_t *coctx; - ngx_http_core_loc_conf_t *clcf; - ngx_http_lua_socket_pool_t *spool; - ngx_http_lua_socket_tcp_conn_op_ctx_t *conn_op_ctx; - - spool = u->socket_pool; - if (spool != NULL) { - rc = ngx_http_lua_get_keepalive_peer(r, u); - - if (rc == NGX_OK) { - lua_pushinteger(L, 1); - return 1; - } - - /* rc == NGX_DECLINED */ - - spool->connections++; - - /* check if backlog is enabled and - * don't queue resuming connection operation */ - if (spool->backlog >= 0 && !resuming) { - - dd("lua tcp socket %s connections %ld", - spool->key, spool->connections); - - if (spool->connections > spool->size + spool->backlog) { - spool->connections--; - lua_pushnil(L); - lua_pushliteral(L, "too many waiting connect operations"); - return 2; - } - - if (spool->connections > spool->size) { - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, u->peer.log, 0, - "lua tcp socket queue connect operation for " - "connection pool \"%s\", connections: %i", - spool->key, spool->connections); - - host_size = sizeof(u_char) * - (ngx_max(host_len, NGX_INET_ADDRSTRLEN) + 1); - - if (!ngx_queue_empty(&spool->cache_connect_op)) { - q = ngx_queue_last(&spool->cache_connect_op); - ngx_queue_remove(q); - conn_op_ctx = ngx_queue_data( - q, ngx_http_lua_socket_tcp_conn_op_ctx_t, queue); - - conn_op_host = &conn_op_ctx->host; - if (host_len > conn_op_host->len - && host_len > NGX_INET_ADDRSTRLEN) - { - ngx_free(conn_op_host->data); - conn_op_host->data = ngx_alloc(host_size, - ngx_cycle->log); - if (conn_op_host->data == NULL) { - ngx_free(conn_op_ctx); - goto no_memory_and_not_resuming; - } - } - - } else { - conn_op_ctx = ngx_alloc( - sizeof(ngx_http_lua_socket_tcp_conn_op_ctx_t), - ngx_cycle->log); - if (conn_op_ctx == NULL) { - goto no_memory_and_not_resuming; - } - - conn_op_host = &conn_op_ctx->host; - conn_op_host->data = ngx_alloc(host_size, ngx_cycle->log); - if (conn_op_host->data == NULL) { - ngx_free(conn_op_ctx); - goto no_memory_and_not_resuming; - } - } - - conn_op_ctx->cleanup = NULL; - - ngx_memcpy(conn_op_host->data, host_ref, host_len); - conn_op_host->data[host_len] = '\0'; - conn_op_host->len = host_len; - - conn_op_ctx->port = port; - - u->write_co_ctx = ctx->cur_co_ctx; - - conn_op_ctx->u = u; - ctx->cur_co_ctx->cleanup = - ngx_http_lua_tcp_queue_conn_op_cleanup; - ctx->cur_co_ctx->data = conn_op_ctx; - - ngx_memzero(&conn_op_ctx->event, sizeof(ngx_event_t)); - conn_op_ctx->event.handler = - ngx_http_lua_socket_tcp_conn_op_timeout_handler; - conn_op_ctx->event.data = conn_op_ctx; - conn_op_ctx->event.log = ngx_cycle->log; - - ngx_add_timer(&conn_op_ctx->event, u->connect_timeout); - - ngx_queue_insert_tail(&spool->wait_connect_op, - &conn_op_ctx->queue); - - ngx_log_debug3(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "lua tcp socket queued connect operation for " - "%d(ms), u: %p, ctx: %p", - u->connect_timeout, conn_op_ctx->u, conn_op_ctx); - - return lua_yield(L, 0); - } - } - - } /* end spool != NULL */ - - host.data = ngx_palloc(r->pool, host_len + 1); - if (host.data == NULL) { - return luaL_error(L, "no memory"); - } - - host.len = host_len; - - ngx_memcpy(host.data, host_ref, host_len); - host.data[host_len] = '\0'; - - ngx_memzero(&url, sizeof(ngx_url_t)); - url.url = host; - url.default_port = port; - url.no_resolve = 1; - - coctx = ctx->cur_co_ctx; - - if (ngx_parse_url(r->pool, &url) != NGX_OK) { - lua_pushnil(L); - - if (url.err) { - lua_pushfstring(L, "failed to parse host name \"%s\": %s", - url.url.data, url.err); - - } else { - lua_pushfstring(L, "failed to parse host name \"%s\"", - url.url.data); - } - - goto failed; - } - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua tcp socket connect timeout: %M", u->connect_timeout); - - u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t)); - if (u->resolved == NULL) { - if (resuming) { - lua_pushnil(L); - lua_pushliteral(L, "no memory"); - goto failed; - } - - goto no_memory_and_not_resuming; - } - - if (url.addrs && url.addrs[0].sockaddr) { - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua tcp socket network address given directly"); - - u->resolved->sockaddr = url.addrs[0].sockaddr; - u->resolved->socklen = url.addrs[0].socklen; - u->resolved->naddrs = 1; - u->resolved->host = url.addrs[0].name; - - } else { - u->resolved->host = host; - u->resolved->port = url.default_port; - } - - if (u->resolved->sockaddr) { - rc = ngx_http_lua_socket_resolve_retval_handler(r, u, L); - if (rc == NGX_AGAIN && !resuming) { - return lua_yield(L, 0); - } - - if (rc > 1) { - goto failed; - } - - return rc; - } - - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - - temp.name = host; - rctx = ngx_resolve_start(clcf->resolver, &temp); - if (rctx == NULL) { - u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_RESOLVER; - lua_pushnil(L); - lua_pushliteral(L, "failed to start the resolver"); - goto failed; - } - - if (rctx == NGX_NO_RESOLVER) { - u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_RESOLVER; - lua_pushnil(L); - lua_pushfstring(L, "no resolver defined to resolve \"%s\"", host.data); - goto failed; - } - - rctx->name = host; -#if !defined(nginx_version) || nginx_version < 1005008 - rctx->type = NGX_RESOLVE_A; -#endif - rctx->handler = ngx_http_lua_socket_resolve_handler; - rctx->data = u; - rctx->timeout = clcf->resolver_timeout; - - u->resolved->ctx = rctx; - u->write_co_ctx = ctx->cur_co_ctx; - - ngx_http_lua_cleanup_pending_operation(coctx); - coctx->cleanup = ngx_http_lua_tcp_resolve_cleanup; - coctx->data = u; - - saved_top = lua_gettop(L); - - if (ngx_resolve_name(rctx) != NGX_OK) { - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua tcp socket fail to run resolver immediately"); - - u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_RESOLVER; - - coctx->cleanup = NULL; - coctx->data = NULL; - - u->resolved->ctx = NULL; - lua_pushnil(L); - lua_pushfstring(L, "%s could not be resolved", host.data); - goto failed; - } - - if (u->conn_waiting) { - dd("resolved and already connecting"); - - if (resuming) { - return NGX_AGAIN; - } - - return lua_yield(L, 0); - } - - n = lua_gettop(L) - saved_top; - if (n) { - dd("errors occurred during resolving or connecting" - "or already connected"); - - if (n > 1) { - goto failed; - } - - return n; - } - - /* still resolving */ - - u->conn_waiting = 1; - u->write_prepare_retvals = ngx_http_lua_socket_resolve_retval_handler; - - dd("setting data to %p", u); - - if (ctx->entered_content_phase) { - r->write_event_handler = ngx_http_lua_content_wev_handler; - - } else { - r->write_event_handler = ngx_http_core_run_phases; - } - - if (resuming) { - return NGX_AGAIN; - } - - return lua_yield(L, 0); - -failed: - - if (spool != NULL) { - spool->connections--; - ngx_http_lua_socket_tcp_resume_conn_op(spool); - } - - return 2; - -no_memory_and_not_resuming: - - if (spool != NULL) { - spool->connections--; - ngx_http_lua_socket_tcp_resume_conn_op(spool); - } - - return luaL_error(L, "no memory"); -} - - static int ngx_http_lua_socket_tcp_connect(lua_State *L) { ngx_http_request_t *r; ngx_http_lua_ctx_t *ctx; + ngx_str_t host; int port; + ngx_resolver_ctx_t *rctx, temp; + ngx_http_core_loc_conf_t *clcf; + int saved_top; int n; u_char *p; size_t len; + ngx_url_t url; + ngx_int_t rc; ngx_http_lua_loc_conf_t *llcf; ngx_peer_connection_t *pc; int connect_timeout, send_timeout, read_timeout; unsigned custom_pool; int key_index; - ngx_int_t backlog; - ngx_int_t pool_size; - ngx_str_t key; const char *msg; + ngx_http_lua_co_ctx_t *coctx; ngx_http_lua_socket_tcp_upstream_t *u; - ngx_http_lua_socket_pool_t *spool; - n = lua_gettop(L); if (n != 2 && n != 3 && n != 4) { return luaL_error(L, "ngx.socket connect: expecting 2, 3, or 4 " @@ -892,54 +466,13 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) p = (u_char *) luaL_checklstring(L, 2, &len); - backlog = -1; key_index = 2; - pool_size = 0; custom_pool = 0; - llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); if (lua_type(L, n) == LUA_TTABLE) { /* found the last optional option table */ - lua_getfield(L, n, "pool_size"); - - if (lua_isnumber(L, -1)) { - pool_size = (ngx_int_t) lua_tointeger(L, -1); - - if (pool_size <= 0) { - msg = lua_pushfstring(L, "bad \"pool_size\" option value: %i", - pool_size); - return luaL_argerror(L, n, msg); - } - - } else if (!lua_isnil(L, -1)) { - msg = lua_pushfstring(L, "bad \"pool_size\" option type: %s", - lua_typename(L, lua_type(L, -1))); - return luaL_argerror(L, n, msg); - } - - lua_pop(L, 1); - - lua_getfield(L, n, "backlog"); - - if (lua_isnumber(L, -1)) { - backlog = (ngx_int_t) lua_tointeger(L, -1); - - if (backlog < 0) { - msg = lua_pushfstring(L, "bad \"backlog\" option value: %i", - backlog); - return luaL_argerror(L, n, msg); - } - - /* use default value for pool size if only backlog specified */ - if (pool_size == 0) { - pool_size = llcf->pool_size; - } - } - - lua_pop(L, 1); - lua_getfield(L, n, "pool"); switch (lua_type(L, -1)) { @@ -1039,8 +572,7 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) } #if 1 - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - upstream_udata_metatable_key)); + lua_pushlightuserdata(L, &ngx_http_lua_upstream_udata_metatable_key); lua_rawget(L, LUA_REGISTRYINDEX); lua_setmetatable(L, -2); #endif @@ -1050,8 +582,12 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) ngx_memzero(u, sizeof(ngx_http_lua_socket_tcp_upstream_t)); + coctx = ctx->cur_co_ctx; + u->request = r; /* set the controlling request */ + llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); + u->conf = llcf; pc = &u->peer; @@ -1092,28 +628,163 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) u->read_timeout = u->conf->read_timeout; } - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask(socket_pool_key)); - lua_rawget(L, LUA_REGISTRYINDEX); /* table */ - lua_pushvalue(L, key_index); /* key */ + rc = ngx_http_lua_get_keepalive_peer(r, L, key_index, u); - lua_rawget(L, -2); - spool = lua_touserdata(L, -1); - lua_pop(L, 1); - - if (spool != NULL) { - u->socket_pool = spool; - - } else if (pool_size > 0) { - lua_pushvalue(L, key_index); - key.data = (u_char *) lua_tolstring(L, -1, &key.len); - - ngx_http_lua_socket_tcp_create_socket_pool(L, r, key, pool_size, - backlog, &spool); - u->socket_pool = spool; + if (rc == NGX_OK) { + lua_pushinteger(L, 1); + return 1; } - return ngx_http_lua_socket_tcp_connect_helper(L, u, r, ctx, p, - len, port, 0); + if (rc == NGX_ERROR) { + lua_pushnil(L); + lua_pushliteral(L, "error in get keepalive peer"); + return 2; + } + + /* rc == NGX_DECLINED */ + + /* TODO: we should avoid this in-pool allocation */ + + host.data = ngx_palloc(r->pool, len + 1); + if (host.data == NULL) { + return luaL_error(L, "no memory"); + } + + host.len = len; + + ngx_memcpy(host.data, p, len); + host.data[len] = '\0'; + + ngx_memzero(&url, sizeof(ngx_url_t)); + + url.url.len = host.len; + url.url.data = host.data; + url.default_port = (in_port_t) port; + url.no_resolve = 1; + + if (ngx_parse_url(r->pool, &url) != NGX_OK) { + lua_pushnil(L); + + if (url.err) { + lua_pushfstring(L, "failed to parse host name \"%s\": %s", + host.data, url.err); + + } else { + lua_pushfstring(L, "failed to parse host name \"%s\"", host.data); + } + + return 2; + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua tcp socket connect timeout: %M", u->connect_timeout); + + u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t)); + if (u->resolved == NULL) { + return luaL_error(L, "no memory"); + } + + if (url.addrs && url.addrs[0].sockaddr) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua tcp socket network address given directly"); + + u->resolved->sockaddr = url.addrs[0].sockaddr; + u->resolved->socklen = url.addrs[0].socklen; + u->resolved->naddrs = 1; + u->resolved->host = url.addrs[0].name; + + } else { + u->resolved->host = host; + u->resolved->port = (in_port_t) port; + } + + if (u->resolved->sockaddr) { + rc = ngx_http_lua_socket_resolve_retval_handler(r, u, L); + if (rc == NGX_AGAIN) { + return lua_yield(L, 0); + } + + return rc; + } + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + temp.name = host; + rctx = ngx_resolve_start(clcf->resolver, &temp); + if (rctx == NULL) { + u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_RESOLVER; + lua_pushnil(L); + lua_pushliteral(L, "failed to start the resolver"); + return 2; + } + + if (rctx == NGX_NO_RESOLVER) { + u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_RESOLVER; + lua_pushnil(L); + lua_pushfstring(L, "no resolver defined to resolve \"%s\"", host.data); + return 2; + } + + rctx->name = host; +#if !defined(nginx_version) || nginx_version < 1005008 + rctx->type = NGX_RESOLVE_A; +#endif + rctx->handler = ngx_http_lua_socket_resolve_handler; + rctx->data = u; + rctx->timeout = clcf->resolver_timeout; + + u->resolved->ctx = rctx; + u->write_co_ctx = ctx->cur_co_ctx; + + ngx_http_lua_cleanup_pending_operation(coctx); + coctx->cleanup = ngx_http_lua_tcp_resolve_cleanup; + coctx->data = u; + + saved_top = lua_gettop(L); + + if (ngx_resolve_name(rctx) != NGX_OK) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua tcp socket fail to run resolver immediately"); + + u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_RESOLVER; + + coctx->cleanup = NULL; + coctx->data = NULL; + + u->resolved->ctx = NULL; + lua_pushnil(L); + lua_pushfstring(L, "%s could not be resolved", host.data); + + return 2; + } + + if (u->conn_waiting) { + dd("resolved and already connecting"); + return lua_yield(L, 0); + } + + n = lua_gettop(L) - saved_top; + if (n) { + dd("errors occurred during resolving or connecting" + "or already connected"); + return n; + } + + /* still resolving */ + + u->conn_waiting = 1; + u->write_prepare_retvals = ngx_http_lua_socket_resolve_retval_handler; + + dd("setting data to %p", u); + + if (ctx->entered_content_phase) { + r->write_event_handler = ngx_http_lua_content_wev_handler; + + } else { + r->write_event_handler = ngx_http_core_run_phases; + } + + return lua_yield(L, 0); } @@ -1967,8 +1638,7 @@ ngx_http_lua_ssl_handshake_retval_handler(ngx_http_request_t *r, "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_pushlightuserdata(L, &ngx_http_lua_ssl_session_metatable_key); lua_rawget(L, LUA_REGISTRYINDEX); lua_setmetatable(L, -2); } @@ -2085,173 +1755,20 @@ ngx_http_lua_socket_tcp_conn_retval_handler(ngx_http_request_t *r, } -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) -{ - ngx_int_t rc; - 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) { - u->bufs_in = - ngx_http_lua_chain_get_free_buf(r->connection->log, r->pool, - &ctx->free_recv_bufs, - u->conf->buffer_size); - - if (u->bufs_in == NULL) { - return luaL_error(L, "no memory"); - } - - u->buf_in = u->bufs_in; - u->buffer = *u->buf_in->buf; - } - - dd("tcp receive: buf_in: %p, bufs_in: %p", u->buf_in, u->bufs_in); - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua tcp socket read timeout: %M", u->read_timeout); - - if (u->raw_downstream || u->body_downstream) { - r->read_event_handler = ngx_http_lua_req_socket_rev_handler; - } - - u->read_waiting = 0; - u->read_co_ctx = NULL; - - rc = ngx_http_lua_socket_tcp_read(r, u); - - if (rc == NGX_ERROR) { - dd("read failed: %d", (int) u->ft_type); - rc = ngx_http_lua_socket_tcp_receive_retval_handler(r, u, L); - dd("tcp receive retval returned: %d", (int) rc); - return rc; - } - - if (rc == NGX_OK) { - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua tcp socket receive done in a single run"); - - return ngx_http_lua_socket_tcp_receive_retval_handler(r, u, L); - } - - /* rc == NGX_AGAIN */ - - u->read_event_handler = ngx_http_lua_socket_read_handler; - - coctx = ctx->cur_co_ctx; - - ngx_http_lua_cleanup_pending_operation(coctx); - coctx->cleanup = ngx_http_lua_coctx_cleanup; - coctx->data = u; - - if (ctx->entered_content_phase) { - r->write_event_handler = ngx_http_lua_content_wev_handler; - - } else { - r->write_event_handler = ngx_http_core_run_phases; - } - - u->read_co_ctx = coctx; - u->read_waiting = 1; - u->read_prepare_retvals = ngx_http_lua_socket_tcp_receive_retval_handler; - - dd("setting data to %p, coctx:%p", u, coctx); - - if (u->raw_downstream || u->body_downstream) { - ctx->downstream = u; - } - - return lua_yield(L, 0); -} - - -static int -ngx_http_lua_socket_tcp_receiveany(lua_State *L) -{ - int n; - lua_Integer bytes; - ngx_http_request_t *r; - ngx_http_lua_loc_conf_t *llcf; - ngx_http_lua_socket_tcp_upstream_t *u; - - n = lua_gettop(L); - if (n != 2) { - return luaL_error(L, "expecting 2 arguments " - "(including the object), but got %d", n); - } - - r = ngx_http_lua_get_req(L); - if (r == NULL) { - return luaL_error(L, "no request found"); - } - - luaL_checktype(L, 1, LUA_TTABLE); - - lua_rawgeti(L, 1, SOCKET_CTX_INDEX); - u = lua_touserdata(L, -1); - - if (u == NULL || u->peer.connection == NULL || u->read_closed) { - - llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); - - if (llcf->log_socket_errors) { - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "attempt to receive data on a closed socket: u:%p, " - "c:%p, ft:%d eof:%d", - u, u ? u->peer.connection : NULL, - u ? (int) u->ft_type : 0, u ? (int) u->eof : 0); - } - - lua_pushnil(L); - lua_pushliteral(L, "closed"); - return 2; - } - - if (u->request != r) { - return luaL_error(L, "bad request"); - } - - ngx_http_lua_socket_check_busy_connecting(r, u, L); - ngx_http_lua_socket_check_busy_reading(r, u, L); - - if (!lua_isnumber(L, 2)) { - return luaL_argerror(L, 2, "bad max argument"); - } - - bytes = lua_tointeger(L, 2); - if (bytes <= 0) { - return luaL_argerror(L, 2, "bad max argument"); - } - - u->input_filter = ngx_http_lua_socket_read_any; - u->rest = (size_t) bytes; - u->length = u->rest; - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua tcp socket calling receiveany() method to read at " - "most %uz bytes", u->rest); - - return ngx_http_lua_socket_tcp_receive_helper(r, u, L); -} - - static int ngx_http_lua_socket_tcp_receive(lua_State *L) { ngx_http_request_t *r; ngx_http_lua_socket_tcp_upstream_t *u; + ngx_int_t rc; + ngx_http_lua_ctx_t *ctx; int n; ngx_str_t pat; lua_Integer bytes; char *p; int typ; ngx_http_lua_loc_conf_t *llcf; + ngx_http_lua_co_ctx_t *coctx; n = lua_gettop(L); if (n != 1 && n != 2) { @@ -2366,27 +1883,119 @@ ngx_http_lua_socket_tcp_receive(lua_State *L) u->rest = 0; } - return ngx_http_lua_socket_tcp_receive_helper(r, u, L); + u->input_filter_ctx = u; + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + + if (u->bufs_in == NULL) { + u->bufs_in = + ngx_http_lua_chain_get_free_buf(r->connection->log, r->pool, + &ctx->free_recv_bufs, + u->conf->buffer_size); + + if (u->bufs_in == NULL) { + return luaL_error(L, "no memory"); + } + + u->buf_in = u->bufs_in; + u->buffer = *u->buf_in->buf; + } + + dd("tcp receive: buf_in: %p, bufs_in: %p", u->buf_in, u->bufs_in); + + if (u->raw_downstream || u->body_downstream) { + r->read_event_handler = ngx_http_lua_req_socket_rev_handler; + } + + u->read_waiting = 0; + u->read_co_ctx = NULL; + + rc = ngx_http_lua_socket_tcp_read(r, u); + + if (rc == NGX_ERROR) { + dd("read failed: %d", (int) u->ft_type); + rc = ngx_http_lua_socket_tcp_receive_retval_handler(r, u, L); + dd("tcp receive retval returned: %d", (int) rc); + return rc; + } + + if (rc == NGX_OK) { + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua tcp socket receive done in a single run"); + + return ngx_http_lua_socket_tcp_receive_retval_handler(r, u, L); + } + + /* rc == NGX_AGAIN */ + + u->read_event_handler = ngx_http_lua_socket_read_handler; + + coctx = ctx->cur_co_ctx; + + ngx_http_lua_cleanup_pending_operation(coctx); + coctx->cleanup = ngx_http_lua_coctx_cleanup; + coctx->data = u; + + if (ctx->entered_content_phase) { + r->write_event_handler = ngx_http_lua_content_wev_handler; + + } else { + r->write_event_handler = ngx_http_core_run_phases; + } + + u->read_co_ctx = coctx; + u->read_waiting = 1; + u->read_prepare_retvals = ngx_http_lua_socket_tcp_receive_retval_handler; + + dd("setting data to %p, coctx:%p", u, coctx); + + if (u->raw_downstream || u->body_downstream) { + ctx->downstream = u; + } + + return lua_yield(L, 0); } static ngx_int_t ngx_http_lua_socket_read_chunk(void *data, ssize_t bytes) { - ngx_int_t rc; ngx_http_lua_socket_tcp_upstream_t *u = data; - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, u->request->connection->log, 0, + ngx_buf_t *b; +#if (NGX_DEBUG) + ngx_http_request_t *r; + + r = u->request; +#endif + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua tcp socket read chunk %z", bytes); - rc = ngx_http_lua_read_bytes(&u->buffer, u->buf_in, &u->rest, - bytes, u->request->connection->log); - if (rc == NGX_ERROR) { + if (bytes == 0) { u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_CLOSED; return NGX_ERROR; } - return rc; + b = &u->buffer; + + if (bytes >= (ssize_t) u->rest) { + + u->buf_in->buf->last += u->rest; + b->pos += u->rest; + u->rest = 0; + + return NGX_OK; + } + + /* bytes < u->rest */ + + u->buf_in->buf->last += bytes; + b->pos += bytes; + u->rest -= bytes; + + return NGX_AGAIN; } @@ -2395,10 +2004,26 @@ ngx_http_lua_socket_read_all(void *data, ssize_t bytes) { ngx_http_lua_socket_tcp_upstream_t *u = data; - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, u->request->connection->log, 0, + ngx_buf_t *b; +#if (NGX_DEBUG) + ngx_http_request_t *r; + + r = u->request; +#endif + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua tcp socket read all"); - return ngx_http_lua_read_all(&u->buffer, u->buf_in, bytes, - u->request->connection->log); + + if (bytes == 0) { + return NGX_OK; + } + + b = &u->buffer; + + u->buf_in->buf->last += bytes; + b->pos += bytes; + + return NGX_AGAIN; } @@ -2407,40 +2032,72 @@ ngx_http_lua_socket_read_line(void *data, ssize_t bytes) { ngx_http_lua_socket_tcp_upstream_t *u = data; - ngx_int_t rc; + ngx_buf_t *b; + u_char *dst; + u_char c; +#if (NGX_DEBUG) + u_char *begin; +#endif ngx_log_debug0(NGX_LOG_DEBUG_HTTP, u->request->connection->log, 0, "lua tcp socket read line"); - rc = ngx_http_lua_read_line(&u->buffer, u->buf_in, bytes, - u->request->connection->log); - if (rc == NGX_ERROR) { + if (bytes == 0) { u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_CLOSED; return NGX_ERROR; } - return rc; -} + b = &u->buffer; +#if (NGX_DEBUG) + begin = b->pos; +#endif -static ngx_int_t -ngx_http_lua_socket_read_any(void *data, ssize_t bytes) -{ - ngx_http_lua_socket_tcp_upstream_t *u = data; + dd("already read: %p: %.*s", u->buf_in, + (int) (u->buf_in->buf->last - u->buf_in->buf->pos), + u->buf_in->buf->pos); - ngx_int_t rc; + dd("data read: %.*s", (int) bytes, b->pos); - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, u->request->connection->log, 0, - "lua tcp socket read any"); + dst = u->buf_in->buf->last; - rc = ngx_http_lua_read_any(&u->buffer, u->buf_in, &u->rest, bytes, - u->request->connection->log); - if (rc == NGX_ERROR) { - u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_CLOSED; - return NGX_ERROR; + while (bytes--) { + + c = *b->pos++; + + switch (c) { + case '\n': + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, u->request->connection->log, 0, + "lua tcp socket read the final line part: \"%*s\"", + b->pos - 1 - begin, begin); + + u->buf_in->buf->last = dst; + + dd("read a line: %p: %.*s", u->buf_in, + (int) (u->buf_in->buf->last - u->buf_in->buf->pos), + u->buf_in->buf->pos); + + return NGX_OK; + + case '\r': + /* ignore it */ + break; + + default: + *dst++ = c; + break; + } } - return rc; +#if (NGX_DEBUG) + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, u->request->connection->log, 0, + "lua tcp socket read partial line data: %*s", + dst - begin, begin); +#endif + + u->buf_in->buf->last = dst; + + return NGX_AGAIN; } @@ -3882,267 +3539,6 @@ ngx_http_lua_socket_tcp_finalize_write_part(ngx_http_request_t *r, } -static void -ngx_http_lua_socket_tcp_conn_op_timeout_handler(ngx_event_t *ev) -{ - ngx_http_lua_socket_tcp_upstream_t *u; - ngx_http_lua_ctx_t *ctx; - ngx_connection_t *c; - ngx_http_request_t *r; - ngx_http_lua_co_ctx_t *coctx; - ngx_http_lua_loc_conf_t *llcf; - ngx_http_lua_socket_tcp_conn_op_ctx_t *conn_op_ctx; - - conn_op_ctx = ev->data; - ngx_queue_remove(&conn_op_ctx->queue); - - u = conn_op_ctx->u; - r = u->request; - - coctx = u->write_co_ctx; - coctx->cleanup = NULL; - /* note that we store conn_op_ctx in coctx->data instead of u */ - coctx->data = conn_op_ctx; - u->write_co_ctx = NULL; - - llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); - - if (llcf->log_socket_errors) { - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "lua tcp socket queued connect timed out," - " when trying to connect to %V:%ud", - &conn_op_ctx->host, conn_op_ctx->port); - } - - ngx_queue_insert_head(&u->socket_pool->cache_connect_op, - &conn_op_ctx->queue); - u->socket_pool->connections--; - - ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); - if (ctx == NULL) { - return; - } - - ctx->cur_co_ctx = coctx; - - ngx_http_lua_assert(coctx && (!ngx_http_lua_is_thread(ctx) - || coctx->co_ref >= 0)); - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua tcp socket waking up the current request"); - - u->write_prepare_retvals = - ngx_http_lua_socket_tcp_conn_op_timeout_retval_handler; - - c = r->connection; - - if (ctx->entered_content_phase) { - (void) ngx_http_lua_socket_tcp_conn_op_resume(r); - - } else { - ctx->resume_handler = ngx_http_lua_socket_tcp_conn_op_resume; - ngx_http_core_run_phases(r); - } - - ngx_http_run_posted_requests(c); -} - - -static int -ngx_http_lua_socket_tcp_conn_op_timeout_retval_handler(ngx_http_request_t *r, - ngx_http_lua_socket_tcp_upstream_t *u, lua_State *L) -{ - lua_pushnil(L); - lua_pushliteral(L, "timeout"); - return 2; -} - - -static void -ngx_http_lua_socket_tcp_resume_conn_op(ngx_http_lua_socket_pool_t *spool) -{ - ngx_queue_t *q; - ngx_http_lua_socket_tcp_conn_op_ctx_t *conn_op_ctx; - -#if (NGX_DEBUG) - ngx_http_lua_assert(spool->connections >= 0); - -#else - if (spool->connections < 0) { - ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, - "lua tcp socket connections count mismatched for " - "connection pool \"%s\", connections: %i, size: %i", - spool->key, spool->connections, spool->size); - spool->connections = 0; - } -#endif - - /* we manually destroy wait_connect_op before triggering connect - * operation resumption, so that there is no resumption happens when Nginx - * is exiting. - */ - if (ngx_queue_empty(&spool->wait_connect_op)) { - return; - } - - q = ngx_queue_head(&spool->wait_connect_op); - conn_op_ctx = ngx_queue_data(q, ngx_http_lua_socket_tcp_conn_op_ctx_t, - queue); - ngx_log_debug4(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "lua tcp socket post connect operation resumption " - "u: %p, ctx: %p for connection pool \"%s\", " - "connections: %i", - conn_op_ctx->u, conn_op_ctx, spool->key, spool->connections); - - if (conn_op_ctx->event.timer_set) { - ngx_del_timer(&conn_op_ctx->event); - } - - conn_op_ctx->event.handler = - ngx_http_lua_socket_tcp_conn_op_resume_handler; - - ngx_post_event((&conn_op_ctx->event), &ngx_posted_events); -} - - -static void -ngx_http_lua_socket_tcp_conn_op_ctx_cleanup(void *data) -{ - ngx_http_lua_socket_tcp_upstream_t *u; - ngx_http_lua_socket_tcp_conn_op_ctx_t *conn_op_ctx = data; - - u = conn_op_ctx->u; - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, u->request->connection->log, 0, - "cleanup lua tcp socket conn_op_ctx: \"%V\"", - &u->request->uri); - - ngx_queue_insert_head(&u->socket_pool->cache_connect_op, - &conn_op_ctx->queue); -} - - -static void -ngx_http_lua_socket_tcp_conn_op_resume_handler(ngx_event_t *ev) -{ - ngx_queue_t *q; - ngx_connection_t *c; - ngx_http_lua_ctx_t *ctx; - ngx_http_request_t *r; - ngx_http_cleanup_t *cln; - ngx_http_lua_co_ctx_t *coctx; - ngx_http_lua_socket_pool_t *spool; - ngx_http_lua_socket_tcp_upstream_t *u; - ngx_http_lua_socket_tcp_conn_op_ctx_t *conn_op_ctx; - - conn_op_ctx = ev->data; - u = conn_op_ctx->u; - r = u->request; - spool = u->socket_pool; - - if (ngx_queue_empty(&spool->wait_connect_op)) { -#if (NGX_DEBUG) - ngx_http_lua_assert(!(spool->backlog >= 0 - && spool->connections > spool->size)); - -#else - if (spool->backlog >= 0 && spool->connections > spool->size) { - ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, - "lua tcp socket connections count mismatched for " - "connection pool \"%s\", connections: %i, size: %i", - spool->key, spool->connections, spool->size); - spool->connections = spool->size; - } -#endif - - return; - } - - q = ngx_queue_head(&spool->wait_connect_op); - ngx_queue_remove(q); - - coctx = u->write_co_ctx; - coctx->cleanup = NULL; - /* note that we store conn_op_ctx in coctx->data instead of u */ - coctx->data = conn_op_ctx; - /* clear ngx_http_lua_tcp_queue_conn_op_cleanup */ - u->write_co_ctx = NULL; - - ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); - if (ctx == NULL) { - ngx_queue_insert_head(&spool->cache_connect_op, - &conn_op_ctx->queue); - return; - } - - ctx->cur_co_ctx = coctx; - - ngx_http_lua_assert(coctx && (!ngx_http_lua_is_thread(ctx) - || coctx->co_ref >= 0)); - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua tcp socket waking up the current request"); - - u->write_prepare_retvals = - ngx_http_lua_socket_tcp_conn_op_resume_retval_handler; - - c = r->connection; - - if (ctx->entered_content_phase) { - (void) ngx_http_lua_socket_tcp_conn_op_resume(r); - - } else { - cln = ngx_http_lua_cleanup_add(r, 0); - if (cln != NULL) { - cln->handler = ngx_http_lua_socket_tcp_conn_op_ctx_cleanup; - cln->data = conn_op_ctx; - conn_op_ctx->cleanup = &cln->handler; - } - - ctx->resume_handler = ngx_http_lua_socket_tcp_conn_op_resume; - ngx_http_core_run_phases(r); - } - - ngx_http_run_posted_requests(c); -} - - -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) -{ - int nret; - ngx_http_lua_ctx_t *ctx; - ngx_http_lua_co_ctx_t *coctx; - ngx_http_lua_socket_tcp_conn_op_ctx_t *conn_op_ctx; - - ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); - if (ctx == NULL) { - return NGX_ERROR; - } - - coctx = ctx->cur_co_ctx; - dd("coctx: %p", coctx); - conn_op_ctx = coctx->data; - if (conn_op_ctx->cleanup != NULL) { - *conn_op_ctx->cleanup = NULL; - ngx_http_lua_cleanup_free(r, conn_op_ctx->cleanup); - conn_op_ctx->cleanup = NULL; - } - - /* decrease pending connect operation counter */ - u->socket_pool->connections--; - - nret = ngx_http_lua_socket_tcp_connect_helper(L, u, r, ctx, - conn_op_ctx->host.data, - conn_op_ctx->host.len, - conn_op_ctx->port, 1); - ngx_queue_insert_head(&u->socket_pool->cache_connect_op, - &conn_op_ctx->queue); - - return nret; -} - - static void ngx_http_lua_socket_tcp_finalize(ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u) @@ -4193,21 +3589,21 @@ ngx_http_lua_socket_tcp_finalize(ngx_http_request_t *r, ngx_http_lua_socket_tcp_close_connection(c); u->peer.connection = NULL; - u->conn_closed = 1; + + if (!u->reused) { + return; + } spool = u->socket_pool; if (spool == NULL) { return; } - spool->connections--; + spool->active_connections--; - if (spool->connections == 0) { + if (spool->active_connections == 0) { ngx_http_lua_socket_free_pool(r->connection->log, spool); - return; } - - ngx_http_lua_socket_tcp_resume_conn_op(spool); } } @@ -4379,8 +3775,7 @@ ngx_http_lua_socket_tcp_receiveuntil(lua_State *L) return luaL_error(L, "no memory"); } - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - pattern_udata_metatable_key)); + lua_pushlightuserdata(L, &ngx_http_lua_pattern_udata_metatable_key); lua_rawget(L, LUA_REGISTRYINDEX); lua_setmetatable(L, -2); @@ -5035,12 +4430,10 @@ ngx_http_lua_req_socket(lua_State *L) lua_createtable(L, 2 /* narr */, 3 /* nrec */); /* the object */ if (raw) { - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - raw_req_socket_metatable_key)); + lua_pushlightuserdata(L, &ngx_http_lua_raw_req_socket_metatable_key); } else { - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - req_socket_metatable_key)); + lua_pushlightuserdata(L, &ngx_http_lua_req_socket_metatable_key); } lua_rawget(L, LUA_REGISTRYINDEX); @@ -5052,8 +4445,7 @@ ngx_http_lua_req_socket(lua_State *L) } #if 1 - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - downstream_udata_metatable_key)); + lua_pushlightuserdata(L, &ngx_http_lua_downstream_udata_metatable_key); lua_rawget(L, LUA_REGISTRYINDEX); lua_setmetatable(L, -2); #endif @@ -5180,18 +4572,20 @@ ngx_http_lua_socket_tcp_setkeepalive(lua_State *L) ngx_http_lua_socket_tcp_upstream_t *u; ngx_connection_t *c; ngx_http_lua_socket_pool_t *spool; + size_t size, key_len; ngx_str_t key; + ngx_uint_t i; ngx_queue_t *q; ngx_peer_connection_t *pc; + u_char *p; ngx_http_request_t *r; ngx_msec_t timeout; - ngx_int_t pool_size; + ngx_uint_t pool_size; int n; ngx_int_t rc; ngx_buf_t *b; - const char *msg; - ngx_http_lua_socket_pool_item_t *item; + ngx_http_lua_socket_pool_item_t *items, *item; n = lua_gettop(L); @@ -5202,6 +4596,17 @@ ngx_http_lua_socket_tcp_setkeepalive(lua_State *L) luaL_checktype(L, 1, LUA_TTABLE); + lua_pushlightuserdata(L, &ngx_http_lua_socket_pool_key); + lua_rawget(L, LUA_REGISTRYINDEX); + + lua_rawgeti(L, 1, SOCKET_KEY_INDEX); + key.data = (u_char *) lua_tolstring(L, -1, &key.len); + if (key.data == NULL) { + lua_pushnil(L); + lua_pushliteral(L, "key not found"); + return 2; + } + lua_rawgeti(L, 1, SOCKET_CTX_INDEX); u = lua_touserdata(L, -1); lua_pop(L, 1); @@ -5212,7 +4617,7 @@ ngx_http_lua_socket_tcp_setkeepalive(lua_State *L) return 2; } - /* stack: obj timeout? size? */ + /* stack: obj cache key */ pc = &u->peer; c = pc->connection; @@ -5264,32 +4669,9 @@ ngx_http_lua_socket_tcp_setkeepalive(lua_State *L) return 2; } - if (ngx_terminate || ngx_exiting) { - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, - "lua tcp socket set keepalive while process exiting, " - "closing connection %p", c); - - ngx_http_lua_socket_tcp_finalize(r, u); - lua_pushinteger(L, 1); - return 1; - } - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, "lua tcp socket set keepalive: saving connection %p", c); - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask(socket_pool_key)); - lua_rawget(L, LUA_REGISTRYINDEX); - - /* stack: obj timeout? size? pools */ - - lua_rawgeti(L, 1, SOCKET_KEY_INDEX); - key.data = (u_char *) lua_tolstring(L, -1, &key.len); - if (key.data == NULL) { - lua_pushnil(L); - lua_pushliteral(L, "key not found"); - return 2; - } - dd("saving connection to key %s", lua_tostring(L, -1)); lua_pushvalue(L, -1); @@ -5297,7 +4679,7 @@ ngx_http_lua_socket_tcp_setkeepalive(lua_State *L) spool = lua_touserdata(L, -1); lua_pop(L, 1); - /* stack: obj timeout? size? pools cache_key */ + /* stack: obj timeout? size? cache key */ llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); @@ -5311,49 +4693,82 @@ ngx_http_lua_socket_tcp_setkeepalive(lua_State *L) pool_size = llcf->pool_size; } - if (pool_size <= 0) { - msg = lua_pushfstring(L, "bad \"pool_size\" option value: %i", - pool_size); - return luaL_argerror(L, n, msg); + if (pool_size == 0) { + lua_pushnil(L); + lua_pushliteral(L, "zero pool size"); + return 2; } - ngx_http_lua_socket_tcp_create_socket_pool(L, r, key, pool_size, -1, - &spool); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua tcp socket connection pool size: %ui", pool_size); + + key_len = ngx_align(key.len + 1, sizeof(void *)); + + size = sizeof(ngx_http_lua_socket_pool_t) + key_len - 1 + + sizeof(ngx_http_lua_socket_pool_item_t) + * pool_size; + + spool = lua_newuserdata(L, size); + if (spool == NULL) { + return luaL_error(L, "no memory"); + } + + lua_pushlightuserdata(L, &ngx_http_lua_pool_udata_metatable_key); + lua_rawget(L, LUA_REGISTRYINDEX); + lua_setmetatable(L, -2); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, + "lua tcp socket keepalive create connection pool for key" + " \"%s\"", lua_tostring(L, -2)); + + lua_rawset(L, -3); + + spool->active_connections = 0; + spool->lua_vm = ngx_http_lua_get_lua_vm(r, NULL); + + ngx_queue_init(&spool->cache); + ngx_queue_init(&spool->free); + + p = ngx_copy(spool->key, key.data, key.len); + *p++ = '\0'; + + items = (ngx_http_lua_socket_pool_item_t *) (spool->key + key_len); + + dd("items: %p", items); + + ngx_http_lua_assert((void *) items == ngx_align_ptr(items, + sizeof(void *))); + + for (i = 0; i < pool_size; i++) { + ngx_queue_insert_head(&spool->free, &items[i].queue); + items[i].socket_pool = spool; + } } if (ngx_queue_empty(&spool->free)) { q = ngx_queue_last(&spool->cache); ngx_queue_remove(q); + spool->active_connections--; item = ngx_queue_data(q, ngx_http_lua_socket_pool_item_t, queue); ngx_http_lua_socket_tcp_close_connection(item->connection); - /* only decrease the counter for connections which were counted */ - if (u->socket_pool != NULL) { - u->socket_pool->connections--; - } - } else { q = ngx_queue_head(&spool->free); ngx_queue_remove(q); item = ngx_queue_data(q, ngx_http_lua_socket_pool_item_t, queue); - - /* we should always increase connections after getting connected, - * and decrease connections after getting closed. - * however, we don't create connection pool in previous connect method. - * so we increase connections here for backward compatibility. - */ - if (u->socket_pool == NULL) { - spool->connections++; - } } item->connection = c; ngx_queue_insert_head(&spool->cache, q); + if (!u->reused) { + spool->active_connections++; + } + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0, "lua tcp socket clear current socket connection"); @@ -5422,33 +4837,48 @@ ngx_http_lua_socket_tcp_setkeepalive(lua_State *L) ngx_http_lua_socket_tcp_finalize(r, u); #endif - /* since we set u->peer->connection to NULL previously, the connect - * operation won't be resumed in the ngx_http_lua_socket_tcp_finalize. - * Therefore we need to resume it here. - */ - ngx_http_lua_socket_tcp_resume_conn_op(spool); - lua_pushinteger(L, 1); return 1; } static ngx_int_t -ngx_http_lua_get_keepalive_peer(ngx_http_request_t *r, - ngx_http_lua_socket_tcp_upstream_t *u) +ngx_http_lua_get_keepalive_peer(ngx_http_request_t *r, lua_State *L, + int key_index, ngx_http_lua_socket_tcp_upstream_t *u) { ngx_http_lua_socket_pool_item_t *item; ngx_http_lua_socket_pool_t *spool; ngx_http_cleanup_t *cln; ngx_queue_t *q; + int top; ngx_peer_connection_t *pc; ngx_connection_t *c; + top = lua_gettop(L); + + if (key_index < 0) { + key_index = top + key_index + 1; + } + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua tcp socket pool get keepalive peer"); pc = &u->peer; - spool = u->socket_pool; + + lua_pushlightuserdata(L, &ngx_http_lua_socket_pool_key); + lua_rawget(L, LUA_REGISTRYINDEX); /* table */ + lua_pushvalue(L, key_index); /* key */ + lua_rawget(L, -2); + + spool = lua_touserdata(L, -1); + if (spool == NULL) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0, + "lua tcp socket keepalive connection pool not found"); + lua_settop(L, top); + return NGX_DECLINED; + } + + u->socket_pool = spool; if (!ngx_queue_empty(&spool->cache)) { q = ngx_queue_head(&spool->cache); @@ -5493,6 +4923,7 @@ ngx_http_lua_get_keepalive_peer(ngx_http_request_t *r, cln = ngx_http_lua_cleanup_add(r, 0); if (cln == NULL) { u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_ERROR; + lua_settop(L, top); return NGX_ERROR; } @@ -5501,12 +4932,16 @@ ngx_http_lua_get_keepalive_peer(ngx_http_request_t *r, u->cleanup = &cln->handler; } + lua_settop(L, top); + return NGX_OK; } ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0, "lua tcp socket keepalive: connection pool empty"); + lua_settop(L, top); + return NGX_DECLINED; } @@ -5578,15 +5013,13 @@ close: ngx_queue_remove(&item->queue); ngx_queue_insert_head(&spool->free, &item->queue); - spool->connections--; + spool->active_connections--; - dd("keepalive: connections: %u", (unsigned) spool->connections); + dd("keepalive: active connections: %u", + (unsigned) spool->active_connections); - if (spool->connections == 0) { + if (spool->active_connections == 0) { ngx_http_lua_socket_free_pool(ev->log, spool); - - } else { - ngx_http_lua_socket_tcp_resume_conn_op(spool); } return NGX_DECLINED; @@ -5604,7 +5037,7 @@ ngx_http_lua_socket_free_pool(ngx_log_t *log, ngx_http_lua_socket_pool_t *spool) L = spool->lua_vm; - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask(socket_pool_key)); + lua_pushlightuserdata(L, &ngx_http_lua_socket_pool_key); lua_rawget(L, LUA_REGISTRYINDEX); lua_pushstring(L, (char *) spool->key); lua_pushnil(L); @@ -5616,10 +5049,9 @@ ngx_http_lua_socket_free_pool(ngx_log_t *log, ngx_http_lua_socket_pool_t *spool) static void ngx_http_lua_socket_shutdown_pool_helper(ngx_http_lua_socket_pool_t *spool) { - ngx_queue_t *q; - ngx_connection_t *c; - ngx_http_lua_socket_pool_item_t *item; - ngx_http_lua_socket_tcp_conn_op_ctx_t *conn_op_ctx; + ngx_queue_t *q; + ngx_connection_t *c; + ngx_http_lua_socket_pool_item_t *item; while (!ngx_queue_empty(&spool->cache)) { q = ngx_queue_head(&spool->cache); @@ -5633,29 +5065,7 @@ ngx_http_lua_socket_shutdown_pool_helper(ngx_http_lua_socket_pool_t *spool) ngx_queue_insert_head(&spool->free, q); } - while (!ngx_queue_empty(&spool->cache_connect_op)) { - q = ngx_queue_head(&spool->cache_connect_op); - ngx_queue_remove(q); - conn_op_ctx = ngx_queue_data(q, ngx_http_lua_socket_tcp_conn_op_ctx_t, - queue); - ngx_http_lua_socket_tcp_free_conn_op_ctx(conn_op_ctx); - } - - while (!ngx_queue_empty(&spool->wait_connect_op)) { - q = ngx_queue_head(&spool->wait_connect_op); - ngx_queue_remove(q); - conn_op_ctx = ngx_queue_data(q, ngx_http_lua_socket_tcp_conn_op_ctx_t, - queue); - - if (conn_op_ctx->event.timer_set) { - ngx_del_timer(&conn_op_ctx->event); - } - - ngx_http_lua_socket_tcp_free_conn_op_ctx(conn_op_ctx); - } - - /* spool->connections will be decreased down to zero in - * ngx_http_lua_socket_tcp_finalize */ + spool->active_connections = 0; } @@ -5909,13 +5319,6 @@ static ngx_int_t ngx_http_lua_socket_insert_buffer(ngx_http_request_t *r, } -static ngx_int_t -ngx_http_lua_socket_tcp_conn_op_resume(ngx_http_request_t *r) -{ - return ngx_http_lua_socket_tcp_resume_helper(r, SOCKET_OP_RESUME_CONN); -} - - static ngx_int_t ngx_http_lua_socket_tcp_conn_resume(ngx_http_request_t *r) { @@ -5940,14 +5343,13 @@ ngx_http_lua_socket_tcp_write_resume(ngx_http_request_t *r) static ngx_int_t ngx_http_lua_socket_tcp_resume_helper(ngx_http_request_t *r, int socket_op) { - int nret; - lua_State *vm; - ngx_int_t rc; - ngx_uint_t nreqs; - ngx_connection_t *c; - ngx_http_lua_ctx_t *ctx; - ngx_http_lua_co_ctx_t *coctx; - ngx_http_lua_socket_tcp_conn_op_ctx_t *conn_op_ctx; + int nret; + lua_State *vm; + ngx_int_t rc; + ngx_uint_t nreqs; + ngx_connection_t *c; + ngx_http_lua_ctx_t *ctx; + ngx_http_lua_co_ctx_t *coctx; ngx_http_lua_socket_tcp_retval_handler prepare_retvals; @@ -5967,22 +5369,15 @@ ngx_http_lua_socket_tcp_resume_helper(ngx_http_request_t *r, int socket_op) dd("coctx: %p", coctx); + u = coctx->data; + switch (socket_op) { - - case SOCKET_OP_RESUME_CONN: - conn_op_ctx = coctx->data; - u = conn_op_ctx->u; - prepare_retvals = u->write_prepare_retvals; - break; - case SOCKET_OP_CONNECT: case SOCKET_OP_WRITE: - u = coctx->data; prepare_retvals = u->write_prepare_retvals; break; case SOCKET_OP_READ: - u = coctx->data; prepare_retvals = u->read_prepare_retvals; break; @@ -5996,15 +5391,6 @@ ngx_http_lua_socket_tcp_resume_helper(ngx_http_request_t *r, int socket_op) "u:%p", prepare_retvals, u); nret = prepare_retvals(r, u, ctx->cur_co_ctx->co); - if (socket_op == SOCKET_OP_CONNECT - && nret > 1 - && !u->conn_closed - && u->socket_pool != NULL) - { - u->socket_pool->connections--; - ngx_http_lua_socket_tcp_resume_conn_op(u->socket_pool); - } - if (nret == NGX_AGAIN) { return NGX_DONE; } @@ -6036,36 +5422,6 @@ ngx_http_lua_socket_tcp_resume_helper(ngx_http_request_t *r, int socket_op) } -static void -ngx_http_lua_tcp_queue_conn_op_cleanup(void *data) -{ - ngx_http_lua_co_ctx_t *coctx = data; - ngx_http_lua_socket_tcp_upstream_t *u; - ngx_http_lua_socket_tcp_conn_op_ctx_t *conn_op_ctx; - - conn_op_ctx = coctx->data; - u = conn_op_ctx->u; - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "lua tcp socket abort queueing, conn_op_ctx: %p, u: %p", - conn_op_ctx, u); - - if (conn_op_ctx->event.posted) { - ngx_delete_posted_event(&conn_op_ctx->event); - - } else if (conn_op_ctx->event.timer_set) { - ngx_del_timer(&conn_op_ctx->event); - } - - ngx_queue_remove(&conn_op_ctx->queue); - ngx_queue_insert_head(&u->socket_pool->cache_connect_op, - &conn_op_ctx->queue); - - u->socket_pool->connections--; - ngx_http_lua_socket_tcp_resume_conn_op(u->socket_pool); -} - - static void ngx_http_lua_tcp_resolve_cleanup(void *data) { @@ -6081,11 +5437,6 @@ ngx_http_lua_tcp_resolve_cleanup(void *data) return; } - if (u->socket_pool != NULL) { - u->socket_pool->connections--; - ngx_http_lua_socket_tcp_resume_conn_op(u->socket_pool); - } - rctx = u->resolved->ctx; if (rctx == NULL) { return; @@ -6145,8 +5496,7 @@ ngx_http_lua_cleanup_conn_pools(lua_State *L) { ngx_http_lua_socket_pool_t *spool; - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - socket_pool_key)); + lua_pushlightuserdata(L, &ngx_http_lua_socket_pool_key); lua_rawget(L, LUA_REGISTRYINDEX); /* table */ lua_pushnil(L); /* first key */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_socket_tcp.h b/debian/modules/http-lua/src/ngx_http_lua_socket_tcp.h index 091e437..dbdee41 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_socket_tcp.h +++ b/debian/modules/http-lua/src/ngx_http_lua_socket_tcp.h @@ -35,39 +35,17 @@ typedef void (*ngx_http_lua_socket_tcp_upstream_handler_pt) (ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u); -typedef struct { - ngx_event_t event; - ngx_queue_t queue; - ngx_str_t host; - ngx_http_cleanup_pt *cleanup; - ngx_http_lua_socket_tcp_upstream_t *u; - in_port_t port; -} ngx_http_lua_socket_tcp_conn_op_ctx_t; - - -#define ngx_http_lua_socket_tcp_free_conn_op_ctx(conn_op_ctx) \ - ngx_free(conn_op_ctx->host.data); \ - ngx_free(conn_op_ctx) - - typedef struct { lua_State *lua_vm; - ngx_int_t size; - ngx_queue_t cache_connect_op; - ngx_queue_t wait_connect_op; - - /* connections == active connections + pending connect operations, - * while active connections == out-of-pool reused connections - * + in-pool connections */ - ngx_int_t connections; + /* active connections == out-of-pool reused connections + * + in-pool connections */ + ngx_uint_t active_connections; /* queues of ngx_http_lua_socket_pool_item_t: */ ngx_queue_t cache; ngx_queue_t free; - ngx_int_t backlog; - u_char key[1]; } ngx_http_lua_socket_pool_t; @@ -126,7 +104,6 @@ struct ngx_http_lua_socket_tcp_upstream_s { unsigned raw_downstream:1; unsigned read_closed:1; unsigned write_closed:1; - unsigned conn_closed:1; #if (NGX_HTTP_SSL) unsigned ssl_verify:1; unsigned ssl_session_reuse:1; diff --git a/debian/modules/http-lua/src/ngx_http_lua_socket_udp.c b/debian/modules/http-lua/src/ngx_http_lua_socket_udp.c index cbc32d6..8927f41 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_socket_udp.c +++ b/debian/modules/http-lua/src/ngx_http_lua_socket_udp.c @@ -81,8 +81,7 @@ ngx_http_lua_inject_socket_udp_api(ngx_log_t *log, lua_State *L) lua_setfield(L, -2, "udp"); /* ngx socket */ /* udp socket object metatable */ - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - socket_udp_metatable_key)); + lua_pushlightuserdata(L, &ngx_http_lua_socket_udp_metatable_key); lua_createtable(L, 0 /* narr */, 6 /* nrec */); lua_pushcfunction(L, ngx_http_lua_socket_udp_setpeername); @@ -106,8 +105,7 @@ ngx_http_lua_inject_socket_udp_api(ngx_log_t *log, lua_State *L) /* }}} */ /* udp socket object metatable */ - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - udp_udata_metatable_key)); + lua_pushlightuserdata(L, &ngx_http_lua_udp_udata_metatable_key); lua_createtable(L, 0 /* narr */, 1 /* nrec */); /* metatable */ lua_pushcfunction(L, ngx_http_lua_socket_udp_upstream_destroy); lua_setfield(L, -2, "__gc"); @@ -146,8 +144,7 @@ ngx_http_lua_socket_udp(lua_State *L) | NGX_HTTP_LUA_CONTEXT_SSL_CERT); lua_createtable(L, 3 /* narr */, 1 /* nrec */); - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - socket_udp_metatable_key)); + lua_pushlightuserdata(L, &ngx_http_lua_socket_udp_metatable_key); lua_rawget(L, LUA_REGISTRYINDEX); lua_setmetatable(L, -2); @@ -266,8 +263,7 @@ ngx_http_lua_socket_udp_setpeername(lua_State *L) } #if 1 - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - udp_udata_metatable_key)); + lua_pushlightuserdata(L, &ngx_http_lua_udp_udata_metatable_key); lua_rawget(L, LUA_REGISTRYINDEX); lua_setmetatable(L, -2); #endif diff --git a/debian/modules/http-lua/src/ngx_http_lua_ssl_certby.c b/debian/modules/http-lua/src/ngx_http_lua_ssl_certby.c index 622d0a5..453a5c7 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_ssl_certby.c +++ b/debian/modules/http-lua/src/ngx_http_lua_ssl_certby.c @@ -498,11 +498,9 @@ ngx_http_lua_ssl_cert_by_chunk(lua_State *L, ngx_http_request_t *r) /* 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); diff --git a/debian/modules/http-lua/src/ngx_http_lua_ssl_session_fetchby.c b/debian/modules/http-lua/src/ngx_http_lua_ssl_session_fetchby.c index 303efb4..0b88a87 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_ssl_session_fetchby.c +++ b/debian/modules/http-lua/src/ngx_http_lua_ssl_session_fetchby.c @@ -505,11 +505,9 @@ ngx_http_lua_ssl_sess_fetch_by_chunk(lua_State *L, ngx_http_request_t *r) /* 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); diff --git a/debian/modules/http-lua/src/ngx_http_lua_ssl_session_storeby.c b/debian/modules/http-lua/src/ngx_http_lua_ssl_session_storeby.c index a02f729..7609c39 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_ssl_session_storeby.c +++ b/debian/modules/http-lua/src/ngx_http_lua_ssl_session_storeby.c @@ -380,8 +380,6 @@ ngx_http_lua_ssl_sess_store_by_chunk(lua_State *L, ngx_http_request_t *r) /* init nginx context in Lua VM */ ngx_http_lua_set_req(L, r); - -#ifndef OPENRESTY_LUAJIT ngx_http_lua_create_new_globals_table(L, 0 /* narr */, 1 /* nrec */); /* {{{ make new env inheriting main thread's globals table */ @@ -392,7 +390,6 @@ ngx_http_lua_ssl_sess_store_by_chunk(lua_State *L, ngx_http_request_t *r) /* }}} */ lua_setfenv(L, -2); /* set new running env for the code closure */ -#endif lua_pushcfunction(L, ngx_http_lua_traceback); lua_insert(L, 1); /* put it under chunk and args */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_string.c b/debian/modules/http-lua/src/ngx_http_lua_string.c index bdadeb4..239b232 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_string.c +++ b/debian/modules/http-lua/src/ngx_http_lua_string.c @@ -762,20 +762,6 @@ ngx_http_lua_ffi_escape_uri(const u_char *src, size_t len, u_char *dst) ngx_http_lua_escape_uri(dst, (u_char *) src, len, NGX_ESCAPE_URI_COMPONENT); } - -void -ngx_http_lua_ffi_str_replace_char(u_char *buf, size_t len, const u_char find, - const u_char replace) -{ - while (len) { - if (*buf == find) { - *buf = replace; - } - - buf++; - len--; - } -} #endif /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_subrequest.c b/debian/modules/http-lua/src/ngx_http_lua_subrequest.c index f312b65..826a43c 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_subrequest.c +++ b/debian/modules/http-lua/src/ngx_http_lua_subrequest.c @@ -1031,14 +1031,6 @@ ngx_http_lua_post_subrequest(ngx_http_request_t *r, void *data, ngx_int_t rc) dd("pr_coctx status: %d", (int) pr_coctx->sr_statuses[ctx->index]); /* copy subrequest response headers */ - if (ctx->headers_set) { - rc = ngx_http_lua_set_content_type(r, ctx); - if (rc != NGX_OK) { - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "failed to set default content type: %i", rc); - return NGX_ERROR; - } - } pr_coctx->sr_headers[ctx->index] = &r->headers_out; diff --git a/debian/modules/http-lua/src/ngx_http_lua_timer.c b/debian/modules/http-lua/src/ngx_http_lua_timer.c index e92c211..596b2f7 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_timer.c +++ b/debian/modules/http-lua/src/ngx_http_lua_timer.c @@ -220,7 +220,6 @@ ngx_http_lua_ngx_timer_helper(lua_State *L, int every) ngx_http_lua_probe_user_coroutine_create(r, L, co); -#ifndef OPENRESTY_LUAJIT lua_createtable(co, 0, 0); /* the new globals table */ /* co stack: global_tb */ @@ -233,7 +232,6 @@ ngx_http_lua_ngx_timer_helper(lua_State *L, int every) /* co stack: global_tb */ ngx_http_lua_set_globals_table(co); -#endif /* co stack: */ @@ -253,15 +251,12 @@ ngx_http_lua_ngx_timer_helper(lua_State *L, int every) /* L stack: time func [args] thread */ /* co stack: func */ -#ifndef OPENRESTY_LUAJIT ngx_http_lua_get_globals_table(co); lua_setfenv(co, -2); -#endif /* co stack: func */ - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - coroutines_key)); + lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); lua_rawget(L, LUA_REGISTRYINDEX); /* L stack: time func [args] thread coroutines */ @@ -350,9 +345,6 @@ ngx_http_lua_ngx_timer_helper(lua_State *L, int every) ngx_add_timer(ev, delay); - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "created timer (co: %p delay: %M ms)", tctx->co, delay); - lua_pushinteger(L, 1); return 1; @@ -366,8 +358,7 @@ nomem: ngx_free(ev); } - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - coroutines_key)); + lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); lua_rawget(L, LUA_REGISTRYINDEX); luaL_unref(L, -1, co_ref); @@ -396,7 +387,6 @@ ngx_http_lua_timer_copy(ngx_http_lua_timer_ctx_t *old_tctx) co = lua_newthread(vm); -#ifndef OPENRESTY_LUAJIT lua_createtable(co, 0, 0); /* the new globals table */ /* co stack: global_tb */ @@ -409,7 +399,6 @@ ngx_http_lua_timer_copy(ngx_http_lua_timer_ctx_t *old_tctx) /* co stack: global_tb */ ngx_http_lua_set_globals_table(co); -#endif /* co stack: */ @@ -429,15 +418,12 @@ ngx_http_lua_timer_copy(ngx_http_lua_timer_ctx_t *old_tctx) /* L stack: func [args] thread */ /* co stack: func */ -#ifndef OPENRESTY_LUAJIT ngx_http_lua_get_globals_table(co); lua_setfenv(co, -2); -#endif /* co stack: func */ - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - coroutines_key)); + lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); lua_rawget(L, LUA_REGISTRYINDEX); /* L stack: func [args] thread coroutines */ @@ -512,10 +498,6 @@ ngx_http_lua_timer_copy(ngx_http_lua_timer_ctx_t *old_tctx) ngx_add_timer(ev, tctx->delay); - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "created next timer (co: %p delay: %M ms)", tctx->co, - tctx->delay); - return NGX_OK; nomem: @@ -530,8 +512,7 @@ nomem: /* L stack: func [args] */ - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - coroutines_key)); + lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); lua_rawget(L, LUA_REGISTRYINDEX); luaL_unref(L, -1, co_ref); @@ -587,9 +568,6 @@ ngx_http_lua_timer_handler(ngx_event_t *ev) c = ngx_http_lua_create_fake_connection(tctx.pool); if (c == NULL) { - ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, - "failed to create fake connection to run timer (co: %p)", - tctx.co); goto failed; } @@ -601,9 +579,6 @@ ngx_http_lua_timer_handler(ngx_event_t *ev) r = ngx_http_lua_create_fake_request(c); if (r == NULL) { - ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, - "failed to create fake request to run timer (co: %p)", - tctx.co); goto failed; } @@ -639,8 +614,6 @@ ngx_http_lua_timer_handler(ngx_event_t *ev) ctx = ngx_http_lua_create_ctx(r); if (ctx == NULL) { - ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, - "failed to create ctx to run timer (co: %p)", tctx.co); goto failed; } @@ -649,9 +622,6 @@ ngx_http_lua_timer_handler(ngx_event_t *ev) pcln = ngx_pool_cleanup_add(r->pool, 0); if (pcln == NULL) { - ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, - "failed to add vm cleanup to run timer (co: %p)", - tctx.co); goto failed; } @@ -665,9 +635,6 @@ ngx_http_lua_timer_handler(ngx_event_t *ev) cln = ngx_http_cleanup_add(r, 0); if (cln == NULL) { - ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, - "failed to add request cleanup to run timer (co: %p)", - tctx.co); goto failed; } @@ -725,8 +692,7 @@ ngx_http_lua_timer_handler(ngx_event_t *ev) failed: if (tctx.co_ref && tctx.co) { - lua_pushlightuserdata(tctx.co, ngx_http_lua_lightudata_mask( - coroutines_key)); + lua_pushlightuserdata(tctx.co, &ngx_http_lua_coroutines_key); lua_rawget(tctx.co, LUA_REGISTRYINDEX); luaL_unref(tctx.co, -1, tctx.co_ref); lua_settop(tctx.co, 0); diff --git a/debian/modules/http-lua/src/ngx_http_lua_uthread.c b/debian/modules/http-lua/src/ngx_http_lua_uthread.c index 43517a0..8195ec0 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_uthread.c +++ b/debian/modules/http-lua/src/ngx_http_lua_uthread.c @@ -70,8 +70,7 @@ ngx_http_lua_uthread_spawn(lua_State *L) /* anchor the newly created coroutine into the Lua registry */ - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - coroutines_key)); + lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); lua_rawget(L, LUA_REGISTRYINDEX); lua_pushvalue(L, -2); coctx->co_ref = luaL_ref(L, -2); diff --git a/debian/modules/http-lua/src/ngx_http_lua_util.c b/debian/modules/http-lua/src/ngx_http_lua_util.c index c12262e..f7a537e 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_util.c +++ b/debian/modules/http-lua/src/ngx_http_lua_util.c @@ -70,25 +70,6 @@ #endif -#if (NGX_HTTP_LUA_HAVE_SA_RESTART) -#define NGX_HTTP_LUA_SA_RESTART_SIGS { \ - ngx_signal_value(NGX_RECONFIGURE_SIGNAL), \ - ngx_signal_value(NGX_REOPEN_SIGNAL), \ - ngx_signal_value(NGX_NOACCEPT_SIGNAL), \ - ngx_signal_value(NGX_TERMINATE_SIGNAL), \ - ngx_signal_value(NGX_SHUTDOWN_SIGNAL), \ - ngx_signal_value(NGX_CHANGEBIN_SIGNAL), \ - SIGALRM, \ - SIGINT, \ - SIGIO, \ - SIGCHLD, \ - SIGSYS, \ - SIGPIPE, \ - 0 \ -}; -#endif - - char ngx_http_lua_code_cache_key; char ngx_http_lua_regex_cache_key; char ngx_http_lua_socket_pool_key; @@ -147,13 +128,6 @@ static int ngx_http_lua_get_raw_phase_context(lua_State *L); #define LUA_PATH_SEP ";" #endif - -#if !defined(LUA_DEFAULT_PATH) && (NGX_DEBUG) -#define LUA_DEFAULT_PATH "../lua-resty-core/lib/?.lua;" \ - "../lua-resty-lrucache/lib/?.lua" -#endif - - #define AUX_MARK "\1" @@ -197,7 +171,6 @@ ngx_http_lua_set_path(ngx_cycle_t *cycle, lua_State *L, int tab_idx, } -#ifndef OPENRESTY_LUAJIT /** * Create new table and set _G field to itself. * @@ -212,7 +185,6 @@ ngx_http_lua_create_new_globals_table(lua_State *L, int narr, int nrec) lua_pushvalue(L, -1); lua_setfield(L, -2, "_G"); } -#endif /* OPENRESTY_LUAJIT */ static lua_State * @@ -341,13 +313,11 @@ ngx_http_lua_new_thread(ngx_http_request_t *r, lua_State *L, int *ref) base = lua_gettop(L); - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - coroutines_key)); + lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); lua_rawget(L, LUA_REGISTRYINDEX); co = lua_newthread(L); -#ifndef OPENRESTY_LUAJIT /* {{{ inherit coroutine's globals to main thread's globals table * for print() function will try to find tostring() in current * globals table. @@ -362,7 +332,6 @@ ngx_http_lua_new_thread(ngx_http_request_t *r, lua_State *L, int *ref) ngx_http_lua_set_globals_table(co); /* }}} */ -#endif /* OPENRESTY_LUAJIT */ *ref = luaL_ref(L, -2); @@ -387,8 +356,7 @@ ngx_http_lua_del_thread(ngx_http_request_t *r, lua_State *L, ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua deleting light thread"); - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - coroutines_key)); + lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); lua_rawget(L, LUA_REGISTRYINDEX); ngx_http_lua_probe_thread_delete(r, coctx->co, ctx); @@ -440,9 +408,7 @@ 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) - { + if (!ctx->headers_set && ngx_http_lua_set_content_type(r) != NGX_OK) { return NGX_ERROR; } @@ -691,8 +657,7 @@ ngx_http_lua_init_registry(lua_State *L, ngx_log_t *log) /* {{{ register a table to anchor lua coroutines reliably: * {([int]ref) = [cort]} */ - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - coroutines_key)); + lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); lua_createtable(L, 0, 32 /* nrec */); lua_rawset(L, LUA_REGISTRYINDEX); /* }}} */ @@ -703,23 +668,20 @@ ngx_http_lua_init_registry(lua_State *L, ngx_log_t *log) lua_rawset(L, LUA_REGISTRYINDEX); /* create the registry entry for the Lua socket connection pool table */ - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - socket_pool_key)); + lua_pushlightuserdata(L, &ngx_http_lua_socket_pool_key); lua_createtable(L, 0, 8 /* nrec */); lua_rawset(L, LUA_REGISTRYINDEX); #if (NGX_PCRE) /* create the registry entry for the Lua precompiled regex object cache */ - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - regex_cache_key)); + lua_pushlightuserdata(L, &ngx_http_lua_regex_cache_key); lua_createtable(L, 0, 16 /* nrec */); lua_rawset(L, LUA_REGISTRYINDEX); #endif /* {{{ register table to cache user code: * { [(string)cache_key] = } */ - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - code_cache_key)); + lua_pushlightuserdata(L, &ngx_http_lua_code_cache_key); lua_createtable(L, 0, 8 /* nrec */); lua_rawset(L, LUA_REGISTRYINDEX); /* }}} */ @@ -733,6 +695,9 @@ ngx_http_lua_init_globals(lua_State *L, ngx_cycle_t *cycle, ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "lua initializing lua globals"); + lua_pushlightuserdata(L, cycle); + lua_setglobal(L, "__ngx_cycle"); + #if defined(NDK) && NDK ngx_http_lua_inject_ndk_api(L); #endif /* defined(NDK) && NDK */ @@ -791,52 +756,6 @@ ngx_http_lua_inject_ngx_api(lua_State *L, ngx_http_lua_main_conf_t *lmcf, lua_setglobal(L, "ngx"); ngx_http_lua_inject_coroutine_api(log, L); - -#ifdef OPENRESTY_LUAJIT - { - int rc; - - const char buf[] = - "local ngx_log = ngx.log\n" - "local ngx_WARN = ngx.WARN\n" - "local tostring = tostring\n" - "local ngx_get_phase = ngx.get_phase\n" - "local traceback = require 'debug'.traceback\n" - "local function newindex(table, key, value)\n" - "rawset(table, key, value)\n" - "local phase = ngx_get_phase()\n" - "if phase == 'init_worker' or phase == 'init' then\n" - "return\n" - "end\n" - "ngx_log(ngx_WARN, 'writing a global lua variable " - "(\\'', tostring(key), '\\') which may lead to " - "race conditions between concurrent requests, so " - "prefer the use of \\'local\\' variables', " - "traceback('', 2))\n" - "end\n" - "setmetatable(_G, { __newindex = newindex })\n" - ; - - rc = luaL_loadbuffer(L, buf, sizeof(buf) - 1, "=_G write guard"); - - if (rc != 0) { - ngx_log_error(NGX_LOG_ERR, log, 0, - "failed to load Lua code (%i): %s", - rc, lua_tostring(L, -1)); - - lua_pop(L, 1); - return; - } - - rc = lua_pcall(L, 0, 0, 0); - if (rc != 0) { - ngx_log_error(NGX_LOG_ERR, log, 0, - "failed to run Lua code (%i): %s", - rc, lua_tostring(L, -1)); - lua_pop(L, 1); - } - } -#endif } @@ -3035,12 +2954,12 @@ ngx_http_lua_param_get(lua_State *L) | NGX_HTTP_LUA_CONTEXT_BODY_FILTER); if (ctx->context & (NGX_HTTP_LUA_CONTEXT_SET)) { - return ngx_http_lua_setby_param_get(L, r); + return ngx_http_lua_setby_param_get(L); } /* ctx->context & (NGX_HTTP_LUA_CONTEXT_BODY_FILTER) */ - return ngx_http_lua_body_filter_param_get(L, r); + return ngx_http_lua_body_filter_param_get(L); } @@ -3237,8 +3156,7 @@ ngx_http_lua_finalize_threads(ngx_http_request_t *r, ngx_http_lua_probe_thread_delete(r, coctx->co, ctx); - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - coroutines_key)); + lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); lua_rawget(L, LUA_REGISTRYINDEX); inited = 1; @@ -3276,8 +3194,7 @@ ngx_http_lua_finalize_threads(ngx_http_request_t *r, ngx_http_lua_probe_thread_delete(r, coctx->co, ctx); if (!inited) { - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - coroutines_key)); + lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); lua_rawget(L, LUA_REGISTRYINDEX); inited = 1; } @@ -3306,8 +3223,7 @@ ngx_http_lua_finalize_threads(ngx_http_request_t *r, ngx_http_lua_probe_thread_delete(r, coctx->co, ctx); if (!inited) { - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - coroutines_key)); + lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); lua_rawget(L, LUA_REGISTRYINDEX); inited = 1; } @@ -3820,7 +3736,6 @@ ngx_http_lua_init_vm(lua_State *parent_vm, ngx_cycle_t *cycle, ngx_pool_t *pool, ngx_http_lua_main_conf_t *lmcf, ngx_log_t *log, ngx_pool_cleanup_t **pcln) { - int rc; lua_State *L; ngx_uint_t i; ngx_pool_cleanup_t *cln; @@ -3863,11 +3778,6 @@ ngx_http_lua_init_vm(lua_State *parent_vm, ngx_cycle_t *cycle, *pcln = cln; } -#ifdef OPENRESTY_LUAJIT - /* load FFI library first since cdata needs it */ - luaopen_ffi(L); -#endif - if (lmcf->preload_hooks) { /* register the 3rd-party module's preload hooks */ @@ -3888,21 +3798,6 @@ ngx_http_lua_init_vm(lua_State *parent_vm, ngx_cycle_t *cycle, lua_pop(L, 2); } - if (lmcf->load_resty_core) { - lua_getglobal(L, "require"); - lua_pushstring(L, "resty.core"); - - rc = lua_pcall(L, 1, 1, 0); - if (rc != 0) { - ngx_log_error(NGX_LOG_ERR, log, 0, - "lua_load_resty_core failed to load the resty.core " - "module from https://github.com/openresty/lua-resty" - "-core; ensure you are using an OpenResty release " - "from https://openresty.org/en/download.html " - "(rc: %i, reason: %s)", rc, lua_tostring(L, -1)); - } - } - return L; } @@ -4146,12 +4041,7 @@ ngx_http_lua_get_raw_phase_context(lua_State *L) ngx_http_request_t *r; ngx_http_lua_ctx_t *ctx; -#ifdef OPENRESTY_LUAJIT - r = lua_getexdata(L); -#else r = lua_touserdata(L, 1); -#endif - if (r == NULL) { return 0; } @@ -4239,32 +4129,4 @@ ngx_http_lua_cleanup_free(ngx_http_request_t *r, ngx_http_cleanup_pt *cleanup) } -#if (NGX_HTTP_LUA_HAVE_SA_RESTART) -void -ngx_http_lua_set_sa_restart(ngx_log_t *log) -{ - int *signo; - int sigs[] = NGX_HTTP_LUA_SA_RESTART_SIGS; - struct sigaction act; - - for (signo = sigs; *signo != 0; signo++) { - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, - "setting SA_RESTART for signal %d", *signo); - - if (sigaction(*signo, NULL, &act) != 0) { - ngx_log_error(NGX_LOG_WARN, log, ngx_errno, "failed to get " - "sigaction for signal %d", *signo); - } - - act.sa_flags |= SA_RESTART; - - if (sigaction(*signo, &act, NULL) != 0) { - ngx_log_error(NGX_LOG_WARN, log, ngx_errno, "failed to set " - "sigaction for signal %d", *signo); - } - } -} -#endif - - /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_util.h b/debian/modules/http-lua/src/ngx_http_lua_util.h index f08f481..7dcc6f7 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_util.h +++ b/debian/modules/http-lua/src/ngx_http_lua_util.h @@ -9,11 +9,6 @@ #define _NGX_HTTP_LUA_UTIL_H_INCLUDED_ -#ifdef DDEBUG -#include "ddebug.h" -#endif - - #include "ngx_http_lua_common.h" #include "ngx_http_lua_api.h" @@ -193,9 +188,7 @@ ngx_int_t ngx_http_lua_open_and_stat_file(u_char *name, ngx_chain_t *ngx_http_lua_chain_get_free_buf(ngx_log_t *log, ngx_pool_t *p, ngx_chain_t **free, size_t len); -#ifndef OPENRESTY_LUAJIT void ngx_http_lua_create_new_globals_table(lua_State *L, int narr, int nrec); -#endif int ngx_http_lua_traceback(lua_State *L); @@ -250,9 +243,6 @@ ngx_http_cleanup_t *ngx_http_lua_cleanup_add(ngx_http_request_t *r, void ngx_http_lua_cleanup_free(ngx_http_request_t *r, ngx_http_cleanup_pt *cleanup); -#if (NGX_HTTP_LUA_HAVE_SA_RESTART) -void ngx_http_lua_set_sa_restart(ngx_log_t *log); -#endif #define ngx_http_lua_check_if_abortable(L, ctx) \ if ((ctx)->no_abort) { \ @@ -292,9 +282,7 @@ ngx_http_lua_create_ctx(ngx_http_request_t *r) if (!llcf->enable_code_cache && r->connection->fd != (ngx_socket_t) -1) { lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); -#ifdef DDEBUG dd("lmcf: %p", lmcf); -#endif L = ngx_http_lua_init_vm(lmcf->lua, lmcf->cycle, r->pool, lmcf, r->connection->log, &cln); @@ -335,11 +323,7 @@ ngx_http_lua_get_lua_vm(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx) } lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); - -#ifdef DDEBUG dd("lmcf->lua: %p", lmcf->lua); -#endif - return lmcf->lua; } @@ -350,9 +334,6 @@ ngx_http_lua_get_lua_vm(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx) static ngx_inline ngx_http_request_t * ngx_http_lua_get_req(lua_State *L) { -#ifdef OPENRESTY_LUAJIT - return lua_getexdata(L); -#else ngx_http_request_t *r; lua_getglobal(L, ngx_http_lua_req_key); @@ -360,19 +341,14 @@ ngx_http_lua_get_req(lua_State *L) lua_pop(L, 1); return r; -#endif } static ngx_inline void ngx_http_lua_set_req(lua_State *L, ngx_http_request_t *r) { -#ifdef OPENRESTY_LUAJIT - lua_setexdata(L, (void *) r); -#else lua_pushlightuserdata(L, r); lua_setglobal(L, ngx_http_lua_req_key); -#endif } @@ -411,12 +387,10 @@ ngx_http_lua_hash_str(u_char *src, size_t n) static ngx_inline ngx_int_t -ngx_http_lua_set_content_type(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx) +ngx_http_lua_set_content_type(ngx_http_request_t *r) { ngx_http_lua_loc_conf_t *llcf; - ctx->mime_set = 1; - llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); if (llcf->use_default_type && r->headers_out.status != NGX_HTTP_NOT_MODIFIED) diff --git a/debian/modules/http-lua/src/ngx_http_lua_worker.c b/debian/modules/http-lua/src/ngx_http_lua_worker.c index 33cfa11..461509b 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_worker.c +++ b/debian/modules/http-lua/src/ngx_http_lua_worker.c @@ -153,8 +153,6 @@ ngx_http_lua_ffi_master_pid(void) int ngx_http_lua_ffi_get_process_type(void) { - ngx_core_conf_t *ccf; - #if defined(HAVE_PRIVILEGED_PROCESS_PATCH) && !NGX_WIN32 if (ngx_process == NGX_PROCESS_HELPER) { if (ngx_is_privileged_agent) { @@ -163,15 +161,6 @@ ngx_http_lua_ffi_get_process_type(void) } #endif - if (ngx_process == NGX_PROCESS_SINGLE) { - ccf = (ngx_core_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx, - ngx_core_module); - - if (ccf->master) { - return NGX_PROCESS_MASTER; - } - } - return ngx_process; } diff --git a/debian/modules/http-lua/t/000--init.t b/debian/modules/http-lua/t/000--init.t index 5865755..dbe2c33 100644 --- a/debian/modules/http-lua/t/000--init.t +++ b/debian/modules/http-lua/t/000--init.t @@ -10,6 +10,11 @@ $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; $ENV{TEST_NGINX_MYSQL_PORT} ||= 3306; our $http_config = <<'_EOC_'; + upstream database { + drizzle_server 127.0.0.1:$TEST_NGINX_MYSQL_PORT protocol=mysql + dbname=ngx_test user=ngx_test password=ngx_test; + } + lua_package_path "../lua-resty-mysql/lib/?.lua;;"; _EOC_ diff --git a/debian/modules/http-lua/t/001-set.t b/debian/modules/http-lua/t/001-set.t index 9e8ee7b..ba8f22c 100644 --- a/debian/modules/http-lua/t/001-set.t +++ b/debian/modules/http-lua/t/001-set.t @@ -4,7 +4,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * (blocks() * 3 + 5); +plan tests => repeat_each() * (blocks() * 3 + 4); #log_level("warn"); no_long_string(); @@ -46,7 +46,7 @@ helloworld === TEST 3: internal only --- config location /lua { - set_by_lua $res "local function fib(n) if n > 2 then return fib(n-1)+fib(n-2) else return 1 end end return fib(10)"; + set_by_lua $res "function fib(n) if n > 2 then return fib(n-1)+fib(n-2) else return 1 end end return fib(10)"; echo $res; } --- request @@ -76,7 +76,7 @@ GET /lua?a=1&b=2 === TEST 5: fib by arg --- config location /fib { - set_by_lua $res "local function fib(n) if n > 2 then return fib(n-1)+fib(n-2) else return 1 end end return fib(tonumber(ngx.arg[1]))" $arg_n; + set_by_lua $res "function fib(n) if n > 2 then return fib(n-1)+fib(n-2) else return 1 end end return fib(tonumber(ngx.arg[1]))" $arg_n; echo $res; } --- request @@ -592,30 +592,25 @@ failed to run set_by_lua*: unknown reason -=== TEST 37: globals are shared in all requests. +=== TEST 37: globals get cleared for every single request --- config location /lua { - set_by_lua_block $res { + set_by_lua $res ' if not foo then foo = 1 else - ngx.log(ngx.INFO, "old foo: ", foo) foo = foo + 1 end return foo - } + '; echo $res; } --- request GET /lua ---- response_body_like chomp -\A[12] -\z +--- response_body +1 --- no_error_log [error] ---- grep_error_log eval: qr/(old foo: \d+|writing a global lua variable \('\w+'\))/ ---- grep_error_log_out eval -["writing a global lua variable \('foo'\)\n", "old foo: 1\n"] @@ -760,8 +755,6 @@ GET /lua?name=jim --- config location /t { set_by_lua $a ' - local bar - local foo function foo() bar() end diff --git a/debian/modules/http-lua/t/002-content.t b/debian/modules/http-lua/t/002-content.t index bb569f5..cc92d6f 100644 --- a/debian/modules/http-lua/t/002-content.t +++ b/debian/modules/http-lua/t/002-content.t @@ -86,7 +86,7 @@ qr/content_by_lua\(nginx\.conf:\d+\):1: attempt to call field 'echo' \(a nil val location /lua { # NOTE: the newline escape sequence must be double-escaped, as nginx config # parser will unescape first! - content_by_lua 'local v = ngx.var["request_uri"] ngx.print("request_uri: ", v, "\\n")'; + content_by_lua 'v = ngx.var["request_uri"] ngx.print("request_uri: ", v, "\\n")'; } --- request GET /lua?a=1&b=2 @@ -102,7 +102,7 @@ request_uri: /lua?a=1&b=2 } --- user_files >>> test.lua -local v = ngx.var["request_uri"] +v = ngx.var["request_uri"] ngx.print("request_uri: ", v, "\n") --- request GET /lua?a=1&b=2 @@ -154,7 +154,7 @@ result: -0.4090441561579 === TEST 7: read $arg_xxx --- config location = /lua { - content_by_lua 'local who = ngx.var.arg_who + content_by_lua 'who = ngx.var.arg_who ngx.print("Hello, ", who, "!")'; } --- request @@ -171,7 +171,7 @@ Hello, agentzh! } location /lua { - content_by_lua 'local res = ngx.location.capture("/other"); ngx.print("status=", res.status, " "); ngx.print("body=", res.body)'; + content_by_lua 'res = ngx.location.capture("/other"); ngx.print("status=", res.status, " "); ngx.print("body=", res.body)'; } --- request GET /lua @@ -183,7 +183,7 @@ status=200 body=hello, world ei= TEST 9: capture non-existed location --- config location /lua { - content_by_lua 'local res = ngx.location.capture("/other"); ngx.print("status=", res.status)'; + content_by_lua 'res = ngx.location.capture("/other"); ngx.print("status=", res.status)'; } --- request GET /lua @@ -194,7 +194,7 @@ GET /lua === TEST 9: invalid capture location (not as expected...) --- config location /lua { - content_by_lua 'local res = ngx.location.capture("*(#*"); ngx.say("res=", res.status)'; + content_by_lua 'res = ngx.location.capture("*(#*"); ngx.say("res=", res.status)'; } --- request GET /lua @@ -247,7 +247,7 @@ GET /lua ngx.print("num is: ", num, "\\n"); if (num > 0) then - local res = ngx.location.capture("/recur?num="..tostring(num - 1)); + res = ngx.location.capture("/recur?num="..tostring(num - 1)); ngx.print("status=", res.status, " "); ngx.print("body=", res.body, "\\n"); else @@ -271,7 +271,7 @@ end ngx.print("num is: ", num, "\\n"); if (num > 0) then - local res = ngx.location.capture("/recur?num="..tostring(num - 1)); + res = ngx.location.capture("/recur?num="..tostring(num - 1)); ngx.print("status=", res.status, " "); ngx.print("body=", res.body); else @@ -353,7 +353,7 @@ location /sub { } location /parent { set $a 12; - content_by_lua 'local res = ngx.location.capture("/sub"); ngx.print(res.body)'; + content_by_lua 'res = ngx.location.capture("/sub"); ngx.print(res.body)'; } --- request GET /parent @@ -369,7 +369,7 @@ location /sub { location /parent { set $a 12; content_by_lua ' - local res = ngx.location.capture( + res = ngx.location.capture( "/sub", { share_all_vars = true } ); @@ -390,7 +390,7 @@ location /sub { } location /parent { content_by_lua ' - local res = ngx.location.capture("/sub", { share_all_vars = true }); + res = ngx.location.capture("/sub", { share_all_vars = true }); ngx.say(ngx.var.a) '; } @@ -408,7 +408,7 @@ location /sub { } location /parent { content_by_lua ' - local res = ngx.location.capture("/sub", { share_all_vars = false }); + res = ngx.location.capture("/sub", { share_all_vars = false }); ngx.say(ngx.var.a) '; } @@ -427,7 +427,7 @@ GET /parent location /lua { content_by_lua ' - local res = ngx.location.capture("/other"); + res = ngx.location.capture("/other"); ngx.say("type: ", res.header["Content-Type"]); '; } @@ -454,7 +454,7 @@ type: foo/bar location /lua { content_by_lua ' - local res = ngx.location.capture("/other"); + res = ngx.location.capture("/other"); ngx.say("type: ", type(res.header["Set-Cookie"])); ngx.say("len: ", #res.header["Set-Cookie"]); ngx.say("value: ", table.concat(res.header["Set-Cookie"], "|")) @@ -482,7 +482,7 @@ value: a|hello, world|foo location /lua { content_by_lua ' - local res = ngx.location.capture("/other"); + res = ngx.location.capture("/other"); ngx.say("type: ", res.header["Content-Type"]); ngx.say("Bar: ", res.header["Bar"]); '; @@ -507,7 +507,7 @@ Bar: Bah location /lua { content_by_lua ' - local res = ngx.location.capture("/other"); + res = ngx.location.capture("/other"); ngx.say("type: ", res.header["Content-Type"]); ngx.say("Bar: ", res.header["Bar"] or "nil"); '; @@ -524,7 +524,7 @@ Bar: nil --- config location /lua { content_by_lua ' - local data = "hello, world" + data = "hello, world" -- ngx.header["Content-Length"] = #data -- ngx.header.content_length = #data ngx.print(data) @@ -742,7 +742,7 @@ true --- config location /lua { content_by_lua ' - local data = "hello,\\nworld\\n" + data = "hello,\\nworld\\n" ngx.header["Content-Length"] = #data ngx.say("hello,") ngx.flush() @@ -801,7 +801,7 @@ world } --- user_files >>> test.lua -local v = ngx.var["request_uri"] +v = ngx.var["request_uri"] ngx.print("request_uri: ", v, "\n") --- request GET /lua?a=1&b=2 diff --git a/debian/modules/http-lua/t/004-require.t b/debian/modules/http-lua/t/004-require.t index 17e1d57..35e04db 100644 --- a/debian/modules/http-lua/t/004-require.t +++ b/debian/modules/http-lua/t/004-require.t @@ -24,7 +24,7 @@ __DATA__ === TEST 1: sanity --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location /main { echo_location /load; @@ -85,7 +85,7 @@ hello, foo --- request GET /main --- user_files ---- response_body_like: ^[^;]+/servroot(_\d+)?/html/\?\.so$ +--- response_body_like: ^[^;]+/servroot/html/\?.so$ @@ -100,7 +100,7 @@ GET /main } --- request GET /main ---- response_body_like: ^[^;]+/servroot(_\d+)?/html/\?\.lua;(.+\.lua)?;*$ +--- response_body_like: ^[^;]+/servroot/html/\?.lua;.+\.lua;$ @@ -115,7 +115,7 @@ GET /main } --- request GET /main ---- response_body_like: ^[^;]+/servroot(_\d+)?/html/\?\.so;(.+\.so)?;*$ +--- response_body_like: ^[^;]+/servroot/html/\?.so;.+\.so;$ @@ -130,7 +130,7 @@ GET /main } --- request GET /main ---- response_body_like: ^(.+\.lua)?;*?[^;]+/servroot(_\d+)?/html/\?\.lua$ +--- response_body_like: ^.+\.lua;[^;]+/servroot/html/\?.lua$ @@ -145,7 +145,7 @@ GET /main } --- request GET /main ---- response_body_like: ^(.+\.so)?;*?[^;]+/servroot(_\d+)?/html/\?\.so$ +--- response_body_like: ^.+\.so;[^;]+/servroot/html/\?.so$ diff --git a/debian/modules/http-lua/t/005-exit.t b/debian/modules/http-lua/t/005-exit.t index a416a75..a5a28b3 100644 --- a/debian/modules/http-lua/t/005-exit.t +++ b/debian/modules/http-lua/t/005-exit.t @@ -452,7 +452,7 @@ Hi --- config location /lua { content_by_lua ' - local function f () + function f () ngx.say("hello") ngx.exit(200) end diff --git a/debian/modules/http-lua/t/009-log.t b/debian/modules/http-lua/t/009-log.t index cb3895b..68c057f 100644 --- a/debian/modules/http-lua/t/009-log.t +++ b/debian/modules/http-lua/t/009-log.t @@ -414,8 +414,6 @@ GET /log --- config location /log { content_by_lua ' - local foo - local bar function foo() bar() end @@ -433,7 +431,7 @@ GET /log --- response_body done --- error_log eval -qr/\[error\] \S+: \S+ \[lua\] content_by_lua\(nginx\.conf:\d+\):9: bar\(\): hello, log12343.14159/ +qr/\[error\] \S+: \S+ \[lua\] content_by_lua\(nginx\.conf:\d+\):7: bar\(\): hello, log12343.14159/ @@ -441,8 +439,6 @@ qr/\[error\] \S+: \S+ \[lua\] content_by_lua\(nginx\.conf:\d+\):9: bar\(\): hell --- config location /log { content_by_lua ' - local foo - local bar function foo() return bar(5) end @@ -465,7 +461,7 @@ GET /log --- response_body done --- error_log eval -qr/\[error\] \S+: \S+ \[lua\] content_by_lua\(nginx\.conf:\d+\):10:(?: foo\(\):)? hello, log12343.14159/ +qr/\[error\] \S+: \S+ \[lua\] content_by_lua\(nginx\.conf:\d+\):8:(?: foo\(\):)? hello, log12343.14159/ @@ -476,8 +472,6 @@ qr/\[error\] \S+: \S+ \[lua\] content_by_lua\(nginx\.conf:\d+\):10:(?: foo\(\):) } --- user_files >>> test.lua -local foo -local bar function foo() bar() end @@ -494,7 +488,7 @@ GET /log --- response_body done --- error_log eval -qr/\[error\] \S+: \S+ \[lua\] test.lua:8: bar\(\): hello, log12343.14159/ +qr/\[error\] \S+: \S+ \[lua\] test.lua:6: bar\(\): hello, log12343.14159/ diff --git a/debian/modules/http-lua/t/011-md5_bin.t b/debian/modules/http-lua/t/011-md5_bin.t index dc0fd9c..ae7c974 100644 --- a/debian/modules/http-lua/t/011-md5_bin.t +++ b/debian/modules/http-lua/t/011-md5_bin.t @@ -156,7 +156,7 @@ d41d8cd98f00b204e9800998ecf8427e --- config location = /t { content_by_lua ' - local s = ngx.md5_bin(45) + s = ngx.md5_bin(45) s = string.gsub(s, ".", function (c) return string.format("%02x", string.byte(c)) end) diff --git a/debian/modules/http-lua/t/013-base64.t b/debian/modules/http-lua/t/013-base64.t index d1a8d8b..1cc27de 100644 --- a/debian/modules/http-lua/t/013-base64.t +++ b/debian/modules/http-lua/t/013-base64.t @@ -242,4 +242,4 @@ GET /t --- response_body_like: 500 Internal Server Error --- error_code: 500 --- error_log eval -qr/bad argument \#2 to 'encode_base64' \(boolean expected, got number\)|\[error\] .*? bad no_padding: boolean expected, got number/ +qr/bad argument \#2 to 'encode_base64' \(boolean expected, got number\)|\[error\] .*? boolean argument only/ diff --git a/debian/modules/http-lua/t/014-bugs.t b/debian/modules/http-lua/t/014-bugs.t index dad084e..9aadff0 100644 --- a/debian/modules/http-lua/t/014-bugs.t +++ b/debian/modules/http-lua/t/014-bugs.t @@ -43,7 +43,7 @@ __DATA__ === TEST 1: sanity --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location /load { content_by_lua ' @@ -69,7 +69,7 @@ end === TEST 2: sanity --- http_config -lua_package_cpath '/home/agentz/rpm/BUILD/lua-yajl-1.1/build/?.so;/home/lz/luax/?.so;./?.so'; +lua_package_path '/home/agentz/rpm/BUILD/lua-yajl-1.1/build/?.so;/home/lz/luax/?.so;./?.so'; --- config location = '/report/listBidwordPrices4lzExtra.htm' { content_by_lua ' @@ -112,7 +112,7 @@ GET /report/listBidwordPrices4lzExtra.htm?words=123,156,2532 } location = /main { content_by_lua ' - local res = ngx.location.capture("/memc?c=get&k=foo&v=") + res = ngx.location.capture("/memc?c=get&k=foo&v=") ngx.say("1: ", res.body) res = ngx.location.capture("/memc?c=set&k=foo&v=bar"); @@ -204,7 +204,7 @@ https://github.com/chaoslawful/lua-nginx-module/issues/37 content_by_lua ' -- local yajl = require "yajl" ngx.header["Set-Cookie"] = {} - local res = ngx.location.capture("/sub") + res = ngx.location.capture("/sub") for i,j in pairs(res.header) do ngx.header[i] = j @@ -231,7 +231,7 @@ Set-Cookie: TestCookie2=bar.*" } --- user_files >>> foo.lua -local res = {} +res = {} res = {'good 1', 'good 2', 'good 3'} return ngx.redirect("/somedir/" .. ngx.escape_uri(res[math.random(1,#res)])) --- request @@ -579,7 +579,7 @@ $s -=== TEST 26: globals sharing by using _G +=== TEST 26: unexpected globals sharing by using _G --- config location /test { content_by_lua ' @@ -593,12 +593,12 @@ $s } --- pipelined_requests eval ["GET /test", "GET /test", "GET /test"] ---- response_body_like eval -[qr/\A[036]\z/, qr/\A[147]\z/, qr/\A[258]\z/] +--- response_body eval +["0", "0", "0"] -=== TEST 27: globals sharing by using _G (set_by_lua*) +=== TEST 27: unexpected globals sharing by using _G (set_by_lua*) --- config location /test { set_by_lua $a ' @@ -613,12 +613,12 @@ $s } --- pipelined_requests eval ["GET /test", "GET /test", "GET /test"] ---- response_body_like eval -[qr/\A[036]\z/, qr/\A[147]\z/, qr/\A[258]\z/] +--- response_body eval +["0", "0", "0"] -=== TEST 28: globals sharing by using _G (log_by_lua*) +=== TEST 28: unexpected globals sharing by using _G (log_by_lua*) --- http_config lua_shared_dict log_dict 100k; --- config @@ -633,19 +633,19 @@ $s if _G.t then _G.t = _G.t + 1 else - _G.t = 1 + _G.t = 0 end log_dict:set("cnt", t) '; } --- pipelined_requests eval ["GET /test", "GET /test", "GET /test"] ---- response_body_like eval -[qr/\A[036]\z/, qr/\A[147]\z/, qr/\A[258]\z/] +--- response_body eval +["0", "0", "0"] -=== TEST 29: globals sharing by using _G (header_filter_by_lua*) +=== TEST 29: unexpected globals sharing by using _G (header_filter_by_lua*) --- config location /test { header_filter_by_lua ' @@ -663,12 +663,12 @@ $s } --- pipelined_requests eval ["GET /test", "GET /test", "GET /test"] ---- response_body_like eval -[qr/\A[036]\z/, qr/\A[147]\z/, qr/\A[258]\z/] +--- response_body eval +["0", "0", "0"] -=== TEST 30: globals sharing by using _G (body_filter_by_lua*) +=== TEST 30: unexpected globals sharing by using _G (body_filter_by_lua*) --- config location /test { body_filter_by_lua ' @@ -686,9 +686,8 @@ $s } --- request GET /test ---- response_body_like eval -qr/\Aa[036] -\z/ +--- response_body +a0 --- no_error_log [error] @@ -847,7 +846,7 @@ ok === TEST 37: resolving names with a trailing dot --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location /t { resolver $TEST_NGINX_RESOLVER ipv6=off; @@ -865,7 +864,7 @@ GET /t === TEST 38: resolving names with a trailing dot --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;'; + "lua_package_path '$::HtmlDir/?.lua;./?.lua'; server { listen 12354; @@ -892,7 +891,7 @@ args: foo=1&bar=2 === TEST 39: lua_code_cache off + setkeepalive --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config lua_code_cache off; location = /t { diff --git a/debian/modules/http-lua/t/016-resp-header.t b/debian/modules/http-lua/t/016-resp-header.t index e38202b..72c1e05 100644 --- a/debian/modules/http-lua/t/016-resp-header.t +++ b/debian/modules/http-lua/t/016-resp-header.t @@ -8,7 +8,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * (blocks() * 3 + 59); +plan tests => repeat_each() * (blocks() * 3 + 46); #no_diff(); no_long_string(); @@ -630,46 +630,7 @@ Cache-Control: private, no-store -=== TEST 32: set single value to Link header ---- config - location = /t { - content_by_lua_block { - ngx.header.link = "; rel=preload" - ngx.say("Link: ", ngx.var.sent_http_link) - } - } ---- request -GET /t ---- response_headers -Link: ; rel=preload ---- response_body -Link: ; rel=preload - - - -=== TEST 33: set multi values to Link header ---- config - location = /t { - content_by_lua_block { - ngx.header.link = { - "; rel=preload", - "; rel=preload; as=style" - } - - ngx.say("Link: ", ngx.var.sent_http_link) - } - } ---- request -GET /t ---- response_headers -Link: ; rel=preload, ; rel=preload; as=style ---- response_body_like chop -^Link: ; rel=preload[;,] ; rel=preload; as=style$ ---- skip_nginx: 3: < 1.13.9 - - - -=== TEST 34: set multi values to cache-control and override it with a single value +=== TEST 32: set multi values to cache-control and override it with a single value --- config location /lua { content_by_lua ' @@ -689,30 +650,7 @@ Cache-Control: no-cache -=== TEST 35: set multi values to Link header and override it with a single value ---- config - location /lua { - content_by_lua_block { - ngx.header.link = { - "; rel=preload", - "; rel=preload; as=style" - } - ngx.header.link = "; rel=preload" - ngx.say("Link: ", ngx.var.sent_http_link) - ngx.say("Link: ", ngx.header.link) - } - } ---- request - GET /lua ---- response_headers -Link: ; rel=preload ---- response_body -Link: ; rel=preload -Link: ; rel=preload - - - -=== TEST 36: set multi values to cache-control and override it with multiple values +=== TEST 33: set multi values to cache-control and override it with multiple values --- config location /lua { content_by_lua ' @@ -734,37 +672,7 @@ Cache-Control: no-cache[;,] blah[;,] foo$ -=== TEST 37: set multi values to Link header and override it with multiple values ---- config - location /lua { - content_by_lua_block { - ngx.header.link = { - "; rel=preload", - "; rel=preload; as=style" - } - ngx.header.link = { - "; rel=preload", - "; rel=preload", - "; rel=preload; as=style" - } - ngx.say("Link: ", ngx.var.sent_http_link) - ngx.say("Link: ", table.concat(ngx.header.link, ", ")) - } - } ---- request - GET /lua ---- response_headers -Link: ; rel=preload, ; rel=preload, ; rel=preload; as=style ---- response_body_like chop -^Link: ; rel=preload[;,] ; rel=preload[;,] ; rel=preload; as=style -Link: ; rel=preload[;,] ; rel=preload[;,] ; rel=preload; as=style$ ---- no_error_log -[error] ---- skip_nginx: 4: < 1.13.9 - - - -=== TEST 38: set the www-authenticate response header +=== TEST 34: set the www-authenticate response header --- config location /lua { content_by_lua ' @@ -781,7 +689,7 @@ WWW-Authenticate: blah -=== TEST 39: set and clear the www-authenticate response header +=== TEST 35: set and clear the www-authenticate response header --- config location /lua { content_by_lua ' @@ -799,7 +707,7 @@ Foo: nil -=== TEST 40: set multi values to cache-control and override it with multiple values (to reproduce a bug) +=== TEST 36: set multi values to cache-control and override it with multiple values (to reproduce a bug) --- config location /lua { content_by_lua ' @@ -819,7 +727,7 @@ Cache-Control: blah -=== TEST 41: set last-modified and return 304 +=== TEST 37: set last-modified and return 304 --- config location /lua { content_by_lua ' @@ -837,7 +745,7 @@ Last-Modified: Thu, 18 Nov 2010 11:27:35 GMT -=== TEST 42: set last-modified and return 200 +=== TEST 38: set last-modified and return 200 --- config location /lua { content_by_lua ' @@ -856,7 +764,7 @@ Thu, 18 Nov 2010 11:27:35 GMT -=== TEST 43: set response content-encoding header should bypass ngx_http_gzip_filter_module +=== TEST 39: set response content-encoding header should bypass ngx_http_gzip_filter_module --- config default_type text/plain; gzip on; @@ -873,16 +781,13 @@ GET /read --- more_headers Accept-Encoding: gzip --- response_headers -Content-Encoding: gzip ---- no_error_log -[error] -http gzip filter +Content-Type: text/plain --- response_body Hello, world, my dear friend! -=== TEST 44: no transform underscores (write) +=== TEST 40: no transform underscores (write) --- config lua_transform_underscores_in_response_headers off; location = /t { @@ -902,7 +807,7 @@ nil -=== TEST 45: with transform underscores (write) +=== TEST 41: with transform underscores (write) --- config lua_transform_underscores_in_response_headers on; location = /t { @@ -922,7 +827,7 @@ Hello -=== TEST 46: github issue #199: underscores in lua variables +=== TEST 42: github issue #199: underscores in lua variables --- config location /read { content_by_lua ' @@ -955,7 +860,7 @@ something: hello -=== TEST 47: set multiple response header +=== TEST 43: set multiple response header --- config location /read { content_by_lua ' @@ -975,7 +880,7 @@ text/my-plain-50 -=== TEST 48: set multiple response header and then reset and then clear +=== TEST 44: set multiple response header and then reset and then clear --- config location /read { content_by_lua ' @@ -1004,7 +909,7 @@ ok -=== TEST 49: set response content-type header for multiple times +=== TEST 45: set response content-type header for multiple times --- config location /read { content_by_lua ' @@ -1022,7 +927,7 @@ Hi -=== TEST 50: set Last-Modified response header for multiple times +=== TEST 46: set Last-Modified response header for multiple times --- config location /read { content_by_lua ' @@ -1040,7 +945,7 @@ ok -=== TEST 51: set Last-Modified response header and then clear +=== TEST 47: set Last-Modified response header and then clear --- config location /read { content_by_lua ' @@ -1058,7 +963,7 @@ ok -=== TEST 52: github #20: segfault caused by the nasty optimization in the nginx core (write) +=== TEST 48: github #20: segfault caused by the nasty optimization in the nginx core (write) --- config location = /t/ { header_filter_by_lua ' @@ -1080,7 +985,7 @@ Location: http://localhost:$ServerPort/t/ -=== TEST 53: github #20: segfault caused by the nasty optimization in the nginx core (read) +=== TEST 49: github #20: segfault caused by the nasty optimization in the nginx core (read) --- config location = /t/ { header_filter_by_lua ' @@ -1102,7 +1007,7 @@ Location: http://localhost:$ServerPort/t/ -=== TEST 54: github #20: segfault caused by the nasty optimization in the nginx core (read Location) +=== TEST 50: github #20: segfault caused by the nasty optimization in the nginx core (read Location) --- config location = /t/ { header_filter_by_lua ' @@ -1125,7 +1030,7 @@ Foo: /t/ -=== TEST 55: github #20: segfault caused by the nasty optimization in the nginx core (set Foo and read Location) +=== TEST 51: github #20: segfault caused by the nasty optimization in the nginx core (set Foo and read Location) --- config location = /t/ { header_filter_by_lua ' @@ -1149,7 +1054,7 @@ Foo: /t/ -=== TEST 56: case sensitive cache-control header +=== TEST 52: case sensitive cache-control header --- config location /lua { content_by_lua ' @@ -1166,24 +1071,7 @@ Cache-Control: private -=== TEST 57: case sensitive Link header ---- config - location /lua { - content_by_lua_block { - ngx.header["link"] = "; rel=preload" - ngx.say("Link: ", ngx.var.sent_http_link) - } - } ---- request - GET /lua ---- raw_response_headers_like chop -link: ; rel=preload ---- response_body -Link: ; rel=preload - - - -=== TEST 58: clear Cache-Control when there was no Cache-Control +=== TEST 53: clear Cache-Control when there was no Cache-Control --- config location /lua { content_by_lua ' @@ -1200,24 +1088,7 @@ Cache-Control: nil -=== TEST 59: clear Link header when there was no Link ---- config - location /lua { - content_by_lua_block { - ngx.header["Link"] = nil - ngx.say("Link: ", ngx.var.sent_http_link) - } - } ---- request - GET /lua ---- raw_response_headers_unlike eval -qr/Link/i ---- response_body -Link: nil - - - -=== TEST 60: set response content-type header +=== TEST 54: set response content-type header --- config location /read { content_by_lua ' @@ -1236,7 +1107,7 @@ s = content_type -=== TEST 61: set a number header name +=== TEST 55: set a number header name --- config location /lua { content_by_lua ' @@ -1255,7 +1126,7 @@ s = content_type -=== TEST 62: set a number header name (in a table value) +=== TEST 56: set a number header name (in a table value) --- config location /lua { content_by_lua ' @@ -1274,7 +1145,7 @@ foo: 32 -=== TEST 63: random access resp headers +=== TEST 57: random access resp headers --- config location /resp-header { content_by_lua ' @@ -1314,7 +1185,7 @@ bar: baz -=== TEST 64: iterating through raw resp headers +=== TEST 58: iterating through raw resp headers --- config location /resp-header { content_by_lua ' @@ -1350,7 +1221,7 @@ bar: nil -=== TEST 65: removed response headers +=== TEST 59: removed response headers --- config location /resp-header { content_by_lua ' @@ -1383,7 +1254,7 @@ bar: baz -=== TEST 66: built-in Content-Type header +=== TEST 60: built-in Content-Type header --- config location = /t { content_by_lua ' @@ -1416,7 +1287,7 @@ my content_type: text/plain -=== TEST 67: built-in Content-Length header +=== TEST 61: built-in Content-Length header --- config location = /t { content_by_lua ' @@ -1449,7 +1320,7 @@ my content_length: 3 -=== TEST 68: built-in Connection header +=== TEST 62: built-in Connection header --- config location = /t { content_by_lua ' @@ -1480,7 +1351,7 @@ my connection: close -=== TEST 69: built-in Transfer-Encoding header (chunked) +=== TEST 63: built-in Transfer-Encoding header (chunked) --- config location = /t { content_by_lua ' @@ -1512,7 +1383,7 @@ my transfer-encoding: chunked -=== TEST 70: built-in Transfer-Encoding header (none) +=== TEST 64: built-in Transfer-Encoding header (none) --- config location = /t { content_by_lua ' @@ -1545,7 +1416,7 @@ my transfer_encoding: nil -=== TEST 71: set Location (no host) +=== TEST 65: set Location (no host) --- config location = /t { content_by_lua ' @@ -1564,7 +1435,7 @@ Location: /foo/bar -=== TEST 72: set Location (with host) +=== TEST 66: set Location (with host) --- config location = /t { content_by_lua ' @@ -1583,7 +1454,7 @@ Location: http://test.com/foo/bar -=== TEST 73: ngx.header["Content-Type"] with ngx_gzip +=== TEST 67: ngx.header["Content-Type"] with ngx_gzip --- config gzip on; gzip_min_length 1; @@ -1607,7 +1478,7 @@ Content-Type: text/html; charset=utf-8 -=== TEST 74: ngx.header["Content-Type"] with "; blah" +=== TEST 68: ngx.header["Content-Type"] with "; blah" --- config location = /test2 { content_by_lua ' @@ -1627,11 +1498,84 @@ test -=== TEST 75: exceeding max header limit (default 100) +=== TEST 69: return the matched content-type instead of default_type +--- http_config +types { + image/png png; +} +--- config +location /set/ { + default_type text/html; + content_by_lua_block { + ngx.say(ngx.header["content-type"]) + } +} +--- request +GET /set/hello.png +--- response_headers +Content-Type: image/png +--- response_body +image/png +--- no_error_log +[error] + + + +=== TEST 70: always return the matched content-type +--- config + location /set/ { + default_type "image/png"; + content_by_lua_block { + ngx.say(ngx.header["content-type"]) + ngx.say(ngx.header["content-type"]) + } + } +--- request +GET /set/hello.png +--- response_headers +Content-Type: image/png +--- response_body +image/png +image/png +--- no_error_log +[error] + + + +=== TEST 71: return the matched content-type after ngx.resp.get_headers() +--- http_config +types { + image/png png; +} +--- config + location /set/ { + default_type text/html; + content_by_lua_block { + local h, err = ngx.resp.get_headers() + if err then + ngx.log(ngx.ERR, "err: ", err) + return ngx.exit(500) + end + + ngx.say(h["content-type"]) + } + } +--- request +GET /set/hello.png +--- response_headers +Content-Type: image/png +--- response_body +image/png +--- no_error_log +[error] + + + +=== TEST 72: exceeding max header limit (default 100) --- config location /resp-header { content_by_lua_block { - for i = 1, 100 do + for i = 1, 99 do ngx.header["Foo" .. i] = "Foo" end @@ -1661,11 +1605,11 @@ lua exceeding response header limit 101 > 100 -=== TEST 76: NOT exceeding max header limit (default 100) +=== TEST 73: NOT exceeding max header limit (default 100) --- config location /resp-header { content_by_lua_block { - for i = 1, 99 do + for i = 1, 98 do ngx.header["Foo" .. i] = "Foo" end @@ -1693,11 +1637,11 @@ lua exceeding response header limit -=== TEST 77: exceeding max header limit (custom limit, 3) +=== TEST 74: exceeding max header limit (custom limit, 3) --- config location /resp-header { content_by_lua_block { - for i = 1, 3 do + for i = 1, 2 do ngx.header["Foo" .. i] = "Foo" end @@ -1727,11 +1671,11 @@ lua exceeding response header limit 4 > 3 -=== TEST 78: NOT exceeding max header limit (custom limit, 3) +=== TEST 75: NOT exceeding max header limit (custom limit, 3) --- config location /resp-header { content_by_lua_block { - for i = 1, 2 do + for i = 1, 1 do ngx.header["Foo" .. i] = "Foo" end @@ -1755,211 +1699,3 @@ found 3 resp headers --- no_error_log [error] lua exceeding response header limit - - - -=== TEST 79: return nil if Content-Type is not set yet ---- config - location /t { - default_type text/html; - content_by_lua_block { - ngx.log(ngx.WARN, "Content-Type: ", ngx.header["content-type"]) - ngx.say("Content-Type: ", ngx.header["content-type"]) - } - } ---- request -GET /t ---- response_headers -Content-Type: text/html ---- response_body -Content-Type: nil ---- no_error_log -[error] ---- error_log -Content-Type: nil - - - -=== TEST 80: don't generate Content-Type when setting other response header ---- config - location = /backend { - content_by_lua_block { - ngx.say("foo") - } - header_filter_by_lua_block { - ngx.header.content_type = nil - } - } - - location = /t { - default_type text/html; - rewrite_by_lua_block { - ngx.header.blah = "foo" - } - proxy_pass http://127.0.0.1:$TEST_NGINX_SERVER_PORT/backend; - } ---- request -GET /t ---- response_body -foo ---- response_headers -blah: foo -!Content-Type ---- no_error_log -[error] - - - -=== TEST 81: don't generate Content-Type when getting other response header ---- config - location = /backend { - content_by_lua_block { - ngx.say("foo") - } - header_filter_by_lua_block { - ngx.header.content_type = nil - } - } - - location = /t { - default_type text/html; - rewrite_by_lua_block { - local h = ngx.header.content_length - } - proxy_pass http://127.0.0.1:$TEST_NGINX_SERVER_PORT/backend; - } ---- request -GET /t ---- response_body -foo ---- response_headers -!Content-Type ---- no_error_log -[error] - - - -=== TEST 82: don't generate Content-Type when getting it ---- config - location = /backend { - content_by_lua_block { - ngx.say("foo") - } - header_filter_by_lua_block { - ngx.header.content_type = nil - } - } - - location /t { - proxy_pass http://127.0.0.1:$TEST_NGINX_SERVER_PORT/backend; - header_filter_by_lua_block { - ngx.log(ngx.WARN, "Content-Type: ", ngx.header["content-type"]) - } - } ---- request -GET /t ---- response_body -foo ---- response_headers -!Content-Type ---- no_error_log -[error] ---- error_log -Content-Type: nil - - - -=== TEST 83: generate default Content-Type when setting other response header ---- config - location = /t { - default_type text/html; - content_by_lua_block { - ngx.header.blah = "foo" - ngx.say("foo") - } - } ---- request -GET /t ---- response_body -foo ---- response_headers -blah: foo -Content-Type: text/html ---- no_error_log -[error] - - - -=== TEST 84: don't generate Content-Type when calling ngx.resp.get_headers() ---- config - location = /backend { - content_by_lua_block { - ngx.say("foo") - } - header_filter_by_lua_block { - ngx.header.content_type = nil - } - } - - location /t { - proxy_pass http://127.0.0.1:$TEST_NGINX_SERVER_PORT/backend; - header_filter_by_lua_block { - local h, err = ngx.resp.get_headers() - if err then - ngx.log(ngx.ERR, "err: ", err) - return - end - - ngx.log(ngx.WARN, "Content-Type: ", h["content-type"]) - } - } ---- request -GET /t ---- response_body -foo ---- response_headers -!Content-Type ---- no_error_log -[error] ---- error_log -Content-Type: nil - - - -=== TEST 85: don't generate default Content-Type when Content-Type is cleared ---- config - location = /t { - default_type text/html; - content_by_lua_block { - ngx.header["Content-Type"] = nil - ngx.say("foo") - } - } ---- request -GET /t ---- response_body -foo ---- response_headers -!Content-Type ---- no_error_log -[error] - - - -=== TEST 86: don't generate default Content-Type when Content-Type is set ---- config - location = /t { - default_type text/html; - content_by_lua_block { - ngx.header["Content-Type"] = "application/json" - ngx.say("foo") - } - } ---- request -GET /t ---- response_body -foo ---- response_headers -Content-Type: application/json ---- no_error_log -[error] diff --git a/debian/modules/http-lua/t/017-exec.t b/debian/modules/http-lua/t/017-exec.t index a73e93e..544b8bb 100644 --- a/debian/modules/http-lua/t/017-exec.t +++ b/debian/modules/http-lua/t/017-exec.t @@ -382,7 +382,7 @@ hello --- config location /lua { content_by_lua ' - local function f () + function f () ngx.exec("/hi") end @@ -524,7 +524,7 @@ hello --- config location /main { rewrite_by_lua ' - local res = ngx.location.capture("/test_loc"); + res = ngx.location.capture("/test_loc"); ngx.print("hello, ", res.body) '; content_by_lua return; diff --git a/debian/modules/http-lua/t/020-subrequest.t b/debian/modules/http-lua/t/020-subrequest.t index 5a386db..658a1d2 100644 --- a/debian/modules/http-lua/t/020-subrequest.t +++ b/debian/modules/http-lua/t/020-subrequest.t @@ -32,7 +32,7 @@ __DATA__ location /lua { content_by_lua ' - local res = ngx.location.capture("/other", + res = ngx.location.capture("/other", { method = ngx.HTTP_DELETE }); ngx.print(res.body) @@ -62,7 +62,7 @@ lua http subrequest "/other?" location /lua { content_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { method = ngx.HTTP_DELETE }); ngx.print(res.body) @@ -90,7 +90,7 @@ DELETE location /t { content_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { method = ngx.HTTP_POST }); ngx.print(res.body) @@ -114,7 +114,7 @@ POST location /lua { content_by_lua ' - local res = ngx.location.capture("/other", + res = ngx.location.capture("/other", { method = ngx.HTTP_HEAD }); ngx.print(res.body) @@ -141,7 +141,7 @@ GET /lua location /lua { content_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { method = ngx.HTTP_GET }); ngx.print(res.body) @@ -169,7 +169,7 @@ GET location /lua { content_by_lua ' - local res = ngx.location.capture("/foo") + res = ngx.location.capture("/foo") ngx.print(res.body) '; @@ -196,7 +196,7 @@ GET location /lua { content_by_lua ' - local res = ngx.location.capture("/foo", {}) + res = ngx.location.capture("/foo", {}) ngx.print(res.body) '; @@ -226,7 +226,7 @@ GET location /lua { content_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { method = ngx.HTTP_PUT, body = "hello" }); ngx.print(res.body) @@ -255,7 +255,7 @@ hello location /lua { content_by_lua ' - local res = ngx.location.capture("/other", + res = ngx.location.capture("/other", { method = ngx.HTTP_PUT, body = "hello" }); ngx.print(res.body) @@ -291,7 +291,7 @@ hello location /lua { content_by_lua ' - local res = ngx.location.capture("/other", + res = ngx.location.capture("/other", { method = ngx.HTTP_PUT, body = "hello" }); ngx.print(res.body) @@ -329,7 +329,7 @@ GET location /lua { content_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { method = ngx.HTTP_POST, body = "hello" }); ngx.print(res.body) @@ -362,7 +362,7 @@ hello content_by_lua ' ngx.location.capture("/flush"); - local res = ngx.location.capture("/memc"); + res = ngx.location.capture("/memc"); ngx.say("GET: " .. res.status); res = ngx.location.capture("/memc", @@ -404,7 +404,7 @@ cached: hello ngx.location.capture("/flush", { share_all_vars = true }); - local res = ngx.location.capture("/memc", + res = ngx.location.capture("/memc", { share_all_vars = true }); ngx.say("GET: " .. res.status); @@ -435,7 +435,7 @@ cached: hello location /lua { content_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { args = {} }) ngx.print(res.body) '; @@ -456,7 +456,7 @@ GET /lua location /lua { content_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { args = { ["fo="] = "=>" } }) ngx.print(res.body) '; @@ -478,7 +478,7 @@ fo%3D=%3D%3E location /lua { content_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { args = { ["fo="] = "=>", ["="] = ":" } }) ngx.print(res.body) @@ -503,7 +503,7 @@ GET /lua location /lua { content_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { args = { foo = 3, bar = "hello" } }) ngx.print(res.body) @@ -526,7 +526,7 @@ GET /lua location /lua { content_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { args = { [57] = "hi" } }) ngx.print(res.body) '; @@ -548,7 +548,7 @@ attempt to use a non-string key in the "args" option table location /lua { content_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { args = { "hi" } }) ngx.print(res.body) '; @@ -570,7 +570,7 @@ attempt to use a non-string key in the "args" option table location /lua { content_by_lua ' - local res = ngx.location.capture("/foo?a=3", + res = ngx.location.capture("/foo?a=3", { args = { b = 4 } }) ngx.print(res.body) '; @@ -592,7 +592,7 @@ a=3&b=4 location /lua { content_by_lua ' - local res = ngx.location.capture("/foo?a=3", + res = ngx.location.capture("/foo?a=3", { args = "b=4" }) ngx.print(res.body) '; @@ -685,7 +685,7 @@ https://github.com/chaoslawful/lua-nginx-module/issues/38 location /lua { content_by_lua ' - local res = ngx.location.capture("/other", + res = ngx.location.capture("/other", { method = ngx.HTTP_GET }); ngx.say("header foo: [", res.body, "]") '; @@ -711,7 +711,7 @@ https://github.com/chaoslawful/lua-nginx-module/issues/38 location /lua { content_by_lua ' - local res = ngx.location.capture("/other", + res = ngx.location.capture("/other", { body = "abc" }); ngx.say("header foo: [", res.body, "]") '; @@ -746,8 +746,8 @@ header foo: [bar] } location /main { content_by_lua ' - local res1, res2 = ngx.location.capture_multi({{"/a"}, {"/b"}}) - local res3 = ngx.location.capture("/c") + res1, res2 = ngx.location.capture_multi({{"/a"}, {"/b"}}) + res3 = ngx.location.capture("/c") ngx.print(res1.body, res2.body, res3.body) '; } @@ -780,7 +780,7 @@ lua reuse free buf memory location /lua { content_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { method = ngx.HTTP_POST, body = "hello" }); ngx.print(res.body) @@ -801,7 +801,7 @@ hello --- config location /lua { content_by_lua ' - local res = ngx.location.capture("/foo.html") + res = ngx.location.capture("/foo.html") ngx.say(res.status) ngx.say(res.header["Last-Modified"]) @@ -832,7 +832,7 @@ hello, static file$ location /lua { content_by_lua ' local ctx = {} - local res = ngx.location.capture("/sub", { ctx = ctx }) + res = ngx.location.capture("/sub", { ctx = ctx }) ngx.say(ctx.foo); ngx.say(ngx.ctx.foo); @@ -857,7 +857,7 @@ nil } location /lua { content_by_lua ' - local res = ngx.location.capture("/sub", { ctx = ngx.ctx }) + res = ngx.location.capture("/sub", { ctx = ngx.ctx }) ngx.say(ngx.ctx.foo); '; } @@ -885,7 +885,7 @@ bar location /t { content_by_lua ' - local res = ngx.location.capture("/memc", + res = ngx.location.capture("/memc", { method = ngx.HTTP_PUT, body = "hello 1234" }); -- ngx.say("PUT: " .. res.status); @@ -922,7 +922,7 @@ lua reuse free buf chain, but reallocate memory because location /lua { content_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { method = ngx.HTTP_GET }); ngx.print(res.body) @@ -959,7 +959,7 @@ nil content_by_lua ' ngx.req.read_body() - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { method = ngx.HTTP_GET }); ngx.print(res.body) @@ -996,7 +996,7 @@ nil content_by_lua ' ngx.req.read_body() - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { method = ngx.HTTP_POST }); ngx.print(res.body) @@ -1033,7 +1033,7 @@ hello, world content_by_lua ' ngx.req.read_body() - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { method = ngx.HTTP_PUT }); ngx.print(res.body) @@ -1074,7 +1074,7 @@ lua subrequests cycle while processing "/t" location /lua { content_by_lua ' - local res = ngx.location.capture("/other", + res = ngx.location.capture("/other", { method = ngx.HTTP_OPTIONS }); ngx.print(res.body) @@ -1099,7 +1099,7 @@ OPTIONS location /lua { content_by_lua ' - local res = ngx.location.capture("/other", + res = ngx.location.capture("/other", { method = ngx.HTTP_OPTIONS, body = "hello world" }); ngx.print(res.body) @@ -1151,7 +1151,7 @@ r%5B%5D=http%3A%2F%2Fajax.googleapis.com%3A80%2Fajax%2Flibs%2Fjquery%2F1.7.2%2Fj location /main { content_by_lua ' - local res = ngx.location.capture("/sub") + res = ngx.location.capture("/sub") ngx.say("status: ", res.status) ngx.say("body: ", res.body) '; @@ -1172,7 +1172,7 @@ body: location /main { content_by_lua ' - local res = ngx.location.capture("/sub") + res = ngx.location.capture("/sub") ngx.say("status: ", res.status) ngx.say("body: ", res.body) '; @@ -1196,7 +1196,7 @@ body: location /main { content_by_lua ' - local res = ngx.location.capture("/sub") + res = ngx.location.capture("/sub") ngx.say("status: ", res.status) ngx.say("body: ", res.body) '; @@ -1242,7 +1242,7 @@ F(ngx_http_finalize_request) { location /main { content_by_lua ' - local res = ngx.location.capture("/memc") + res = ngx.location.capture("/memc") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -1312,7 +1312,7 @@ upstream prematurely closed connection location /main { content_by_lua ' - local res = ngx.location.capture("/memc") + res = ngx.location.capture("/memc") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -1385,7 +1385,7 @@ upstream timed out location /main { content_by_lua ' - local res = ngx.location.capture("/proxy") + res = ngx.location.capture("/proxy") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -1445,7 +1445,7 @@ upstream prematurely closed connection location /main { content_by_lua ' - local res = ngx.location.capture("/proxy") + res = ngx.location.capture("/proxy") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -1507,7 +1507,7 @@ upstream timed out location /main { content_by_lua ' - local res = ngx.location.capture("/proxy") + res = ngx.location.capture("/proxy") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -1567,7 +1567,7 @@ truncated: false location /main { content_by_lua ' - local res = ngx.location.capture("/proxy") + res = ngx.location.capture("/proxy") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -1630,7 +1630,7 @@ upstream timed out location /main { content_by_lua ' - local res = ngx.location.capture("/proxy") + res = ngx.location.capture("/proxy") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -1690,7 +1690,7 @@ truncated: false location /main { content_by_lua ' - local res = ngx.location.capture("/proxy") + res = ngx.location.capture("/proxy") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -1756,7 +1756,7 @@ upstream timed out ngx.req.read_body() for i = 1, 2 do - local res = ngx.location.capture("/other", + res = ngx.location.capture("/other", { method = ngx.HTTP_POST }); ngx.say(res.body) @@ -1796,7 +1796,7 @@ hello world ngx.req.read_body() for i = 1, 2 do - local res = ngx.location.capture("/other", + res = ngx.location.capture("/other", { method = ngx.HTTP_POST }); ngx.say(res.body) @@ -1836,7 +1836,7 @@ hello world ngx.req.read_body() for i = 1, 2 do - local res = ngx.location.capture("/other", + res = ngx.location.capture("/other", { method = ngx.HTTP_POST }); ngx.say(res.body) @@ -1916,7 +1916,7 @@ a client request body is buffered to a temporary file location /main { content_by_lua ' - local res = ngx.location.capture("/proxy") + res = ngx.location.capture("/proxy") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -1979,7 +1979,7 @@ upstream prematurely closed connection location /main { content_by_lua ' - local res = ngx.location.capture("/proxy") + res = ngx.location.capture("/proxy") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -2040,7 +2040,7 @@ upstream prematurely closed connection location /main { content_by_lua ' - local res = ngx.location.capture("/proxy") + res = ngx.location.capture("/proxy") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -2102,7 +2102,7 @@ upstream timed out location /main { content_by_lua ' - local res = ngx.location.capture("/proxy") + res = ngx.location.capture("/proxy") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -2160,7 +2160,7 @@ truncated: false location /main { content_by_lua ' - local res = ngx.location.capture("/proxy") + res = ngx.location.capture("/proxy") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -2219,7 +2219,7 @@ truncated: false location /main { content_by_lua ' - local res = ngx.location.capture("/proxy") + res = ngx.location.capture("/proxy") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -2288,7 +2288,7 @@ upstream prematurely closed connection } for i, method in ipairs(methods) do - local res = ngx.location.capture("/other", + res = ngx.location.capture("/other", { method = method }) ngx.print(res.body) end @@ -2324,7 +2324,7 @@ method: TRACE location /lua { content_by_lua ' - local res = ngx.location.capture("/other", + res = ngx.location.capture("/other", { method = ngx.HTTP_DELETE }); ngx.print(res.body) @@ -2353,7 +2353,7 @@ nil location /lua { content_by_lua ' ngx.req.read_body() - local res = ngx.location.capture("/other", + res = ngx.location.capture("/other", { method = ngx.HTTP_DELETE, always_forward_body = true }); ngx.print(res.body) @@ -2382,7 +2382,7 @@ hello world location /lua { content_by_lua ' ngx.req.read_body() - local res = ngx.location.capture("/other", + res = ngx.location.capture("/other", { method = ngx.HTTP_DELETE, always_forward_body = true }); ngx.print(res.body) @@ -2410,7 +2410,7 @@ hello world --- config location = /t { content_by_lua ' - local res = ngx.location.capture("/sub") + res = ngx.location.capture("/sub") ngx.print(res.body) '; } @@ -2603,7 +2603,7 @@ qr/Assertion .*? failed/ location = /t { content_by_lua ' - local res = ngx.location.capture("/sub") + res = ngx.location.capture("/sub") ngx.print(res.body) ngx.say("pr: User-Agent: ", ngx.var.http_user_agent) ngx.say("pr: Host: ", ngx.var.http_host) @@ -2636,7 +2636,7 @@ pr: Host: localhost location = /t { content_by_lua ' - local res = ngx.location.capture("/sub") + res = ngx.location.capture("/sub") ngx.print(res.body) ngx.say("pr: User-Agent: ", ngx.var.http_user_agent) ngx.say("pr: Host: ", ngx.var.http_host) @@ -2669,7 +2669,7 @@ pr: Host: localhost location = /t { content_by_lua ' - local res = ngx.location.capture("/sub") + res = ngx.location.capture("/sub") ngx.print(res.body) ngx.say("pr: User-Agent: ", ngx.var.http_user_agent) ngx.say("pr: Host: ", ngx.var.http_host) @@ -2699,7 +2699,7 @@ pr: Host: localhost location = /t { content_by_lua ' - local res = ngx.location.capture("/sub") + res = ngx.location.capture("/sub") ngx.print(res.body) ngx.say("pr: Cookie: ", ngx.var.http_cookie) '; @@ -2727,7 +2727,7 @@ pr: Cookie: foo; bar location = /t { content_by_lua ' - local res = ngx.location.capture("/sub") + res = ngx.location.capture("/sub") ngx.print(res.body) ngx.say("pr: Cookie: ", ngx.var.http_cookie) '; @@ -2750,7 +2750,7 @@ pr: Cookie: foo; bar --- config location /lua { content_by_lua ' - local res = ngx.location.capture("/index.html", + res = ngx.location.capture("/index.html", { method = ngx.HTTP_HEAD }); ngx.say("content-length: ", res.header["Content-Length"]) ngx.say("body: [", res.body, "]") diff --git a/debian/modules/http-lua/t/023-rewrite/client-abort.t b/debian/modules/http-lua/t/023-rewrite/client-abort.t index 0d6f2b3..117d17e 100644 --- a/debian/modules/http-lua/t/023-rewrite/client-abort.t +++ b/debian/modules/http-lua/t/023-rewrite/client-abort.t @@ -199,7 +199,7 @@ bad things happen location = /sub { proxy_ignore_client_abort on; - proxy_pass http://127.0.0.2:12345/; + proxy_pass http://agentzh.org:12345/; } location = /sleep { @@ -240,7 +240,7 @@ client prematurely closed connection location = /sub { proxy_ignore_client_abort off; - proxy_pass http://127.0.0.2:12345/; + proxy_pass http://agentzh.org:12345/; } --- request GET /t @@ -545,7 +545,7 @@ client prematurely closed connection return end - local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_REDIS_PORT) + ok, err = sock:connect("127.0.0.1", $TEST_NGINX_REDIS_PORT) if not ok then ngx.log(ngx.ERR, "failed to connect: ", err) return diff --git a/debian/modules/http-lua/t/023-rewrite/exec.t b/debian/modules/http-lua/t/023-rewrite/exec.t index 59691cb..edd4607 100644 --- a/debian/modules/http-lua/t/023-rewrite/exec.t +++ b/debian/modules/http-lua/t/023-rewrite/exec.t @@ -326,7 +326,7 @@ hello --- config location /main { rewrite_by_lua ' - local res = ngx.location.capture("/test_loc"); + res = ngx.location.capture("/test_loc"); ngx.print("hello, ", res.body) '; content_by_lua return; @@ -354,7 +354,7 @@ hello, bah --- config location /main { rewrite_by_lua ' - local res = ngx.location.capture("/test_loc"); + res = ngx.location.capture("/test_loc"); ngx.print("hello, ", res.body) '; content_by_lua return; diff --git a/debian/modules/http-lua/t/023-rewrite/mixed.t b/debian/modules/http-lua/t/023-rewrite/mixed.t index 5b38d3f..0f742b2 100644 --- a/debian/modules/http-lua/t/023-rewrite/mixed.t +++ b/debian/modules/http-lua/t/023-rewrite/mixed.t @@ -35,7 +35,7 @@ __DATA__ rewrite_by_lua ' ngx.location.capture("/flush"); - local res = ngx.location.capture("/memc"); + res = ngx.location.capture("/memc"); print("rewrite GET: " .. res.status); res = ngx.location.capture("/memc", @@ -49,7 +49,7 @@ __DATA__ content_by_lua ' ngx.location.capture("/flush"); - local res = ngx.location.capture("/memc"); + res = ngx.location.capture("/memc"); ngx.say("content GET: " .. res.status); res = ngx.location.capture("/memc", diff --git a/debian/modules/http-lua/t/023-rewrite/multi-capture.t b/debian/modules/http-lua/t/023-rewrite/multi-capture.t index a0a02b7..083ec78 100644 --- a/debian/modules/http-lua/t/023-rewrite/multi-capture.t +++ b/debian/modules/http-lua/t/023-rewrite/multi-capture.t @@ -154,7 +154,7 @@ res2.body = b location /main { rewrite_by_lua ' - local res = ngx.location.capture("/foo?n=1") + res = ngx.location.capture("/foo?n=1") ngx.say("top res.status = " .. res.status) ngx.say("top res.body = [" .. res.body .. "]") '; diff --git a/debian/modules/http-lua/t/023-rewrite/req-socket.t b/debian/modules/http-lua/t/023-rewrite/req-socket.t index 9292385..87cbbbe 100644 --- a/debian/modules/http-lua/t/023-rewrite/req-socket.t +++ b/debian/modules/http-lua/t/023-rewrite/req-socket.t @@ -325,7 +325,7 @@ found the end of the stream === TEST 4: attempt to use the req socket across request boundary --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location /t { rewrite_by_lua ' @@ -376,7 +376,7 @@ hello world === TEST 5: receive until on request_body - receiveuntil(1) on the last byte of the body See https://groups.google.com/group/openresty/browse_thread/thread/43cf01da3c681aba for details --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location /t { rewrite_by_lua ' @@ -440,7 +440,7 @@ done === TEST 6: pipelined POST requests --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location /t { rewrite_by_lua ' diff --git a/debian/modules/http-lua/t/023-rewrite/sanity.t b/debian/modules/http-lua/t/023-rewrite/sanity.t index 73a85dc..b90aa0e 100644 --- a/debian/modules/http-lua/t/023-rewrite/sanity.t +++ b/debian/modules/http-lua/t/023-rewrite/sanity.t @@ -69,7 +69,7 @@ GET /lua location /lua { # NOTE: the newline escape sequence must be double-escaped, as nginx config # parser will unescape first! - rewrite_by_lua 'local v = ngx.var["request_uri"] ngx.print("request_uri: ", v, "\\n")'; + rewrite_by_lua 'v = ngx.var["request_uri"] ngx.print("request_uri: ", v, "\\n")'; content_by_lua 'ngx.exit(ngx.OK)'; } --- request @@ -87,7 +87,7 @@ request_uri: /lua?a=1&b=2 } --- user_files >>> test.lua -local v = ngx.var["request_uri"] +v = ngx.var["request_uri"] ngx.print("request_uri: ", v, "\n") --- request GET /lua?a=1&b=2 @@ -140,7 +140,7 @@ result: -0.4090441561579 === TEST 7: read $arg_xxx --- config location = /lua { - rewrite_by_lua 'local who = ngx.var.arg_who + rewrite_by_lua 'who = ngx.var.arg_who ngx.print("Hello, ", who, "!")'; content_by_lua 'ngx.exit(ngx.OK)'; } @@ -159,7 +159,7 @@ Hello, agentzh! location /lua { rewrite_by_lua ' -local res = ngx.location.capture("/other") +res = ngx.location.capture("/other") ngx.print("status=", res.status, " ") ngx.print("body=", res.body) '; @@ -175,7 +175,7 @@ status=200 body=hello, world === TEST 9: capture non-existed location --- config location /lua { - rewrite_by_lua 'local res = ngx.location.capture("/other"); ngx.print("status=", res.status)'; + rewrite_by_lua 'res = ngx.location.capture("/other"); ngx.print("status=", res.status)'; content_by_lua 'ngx.exit(ngx.OK)'; } --- request @@ -187,7 +187,7 @@ GET /lua === TEST 10: invalid capture location (not as expected...) --- config location /lua { - rewrite_by_lua 'local res = ngx.location.capture("*(#*"); ngx.say("res=", res.status)'; + rewrite_by_lua 'res = ngx.location.capture("*(#*"); ngx.say("res=", res.status)'; content_by_lua 'ngx.exit(ngx.OK)'; } --- request @@ -270,7 +270,7 @@ end ngx.print("num is: ", num, "\\n"); if (num > 0) then - local res = ngx.location.capture("/recur?num="..tostring(num - 1)); + res = ngx.location.capture("/recur?num="..tostring(num - 1)); ngx.print("status=", res.status, " "); ngx.print("body=", res.body); else @@ -359,7 +359,7 @@ location /sub { } location /parent { set $a 12; - rewrite_by_lua 'local res = ngx.location.capture("/sub"); ngx.print(res.body)'; + rewrite_by_lua 'res = ngx.location.capture("/sub"); ngx.print(res.body)'; content_by_lua 'ngx.exit(ngx.OK)'; } --- request @@ -377,7 +377,7 @@ location /parent { set $a ''; rewrite_by_lua ' ngx.var.a = 12; - local res = ngx.location.capture( + res = ngx.location.capture( "/sub", { share_all_vars = true } ); @@ -399,7 +399,7 @@ location /sub { } location /parent { rewrite_by_lua ' - local res = ngx.location.capture("/sub", { share_all_vars = true }); + res = ngx.location.capture("/sub", { share_all_vars = true }); ngx.say(ngx.var.a) '; @@ -421,7 +421,7 @@ location /sub { location /parent { rewrite_by_lua ' - local res = ngx.location.capture("/sub", { share_all_vars = false }); + res = ngx.location.capture("/sub", { share_all_vars = false }); ngx.say(ngx.var.a) '; content_by_lua return; @@ -441,7 +441,7 @@ GET /parent location /lua { rewrite_by_lua ' - local res = ngx.location.capture("/other"); + res = ngx.location.capture("/other"); ngx.say("type: ", res.header["Content-Type"]); '; @@ -466,7 +466,7 @@ type: foo/bar location /lua { rewrite_by_lua ' - local res = ngx.location.capture("/other"); + res = ngx.location.capture("/other"); ngx.say("type: ", res.header["Content-Type"]); ngx.say("Bar: ", res.header["Bar"]); '; @@ -494,7 +494,7 @@ Bar: Bah location /lua { rewrite_by_lua ' - local res = ngx.location.capture("/other"); + res = ngx.location.capture("/other"); ngx.say("type: ", res.header["Content-Type"]); ngx.say("Bar: ", res.header["Bar"] or "nil"); '; diff --git a/debian/modules/http-lua/t/023-rewrite/socket-keepalive.t b/debian/modules/http-lua/t/023-rewrite/socket-keepalive.t index 8b532ea..489a70f 100644 --- a/debian/modules/http-lua/t/023-rewrite/socket-keepalive.t +++ b/debian/modules/http-lua/t/023-rewrite/socket-keepalive.t @@ -27,7 +27,7 @@ __DATA__ === TEST 1: sanity --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -104,7 +104,7 @@ lua tcp socket get keepalive peer: using connection === TEST 2: free up the whole connection pool if no active connections --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -177,7 +177,7 @@ received: OK === TEST 3: upstream sockets close prematurely --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config server_tokens off; keepalive_timeout 100ms; @@ -254,7 +254,7 @@ done === TEST 4: http keepalive --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config server_tokens off; location /t { @@ -815,7 +815,7 @@ lua tcp socket keepalive timeout: unlimited === TEST 11: sanity (uds) --- http_config eval " - lua_package_path '$::HtmlDir/?.lua;./?.lua;;'; + lua_package_path '$::HtmlDir/?.lua;./?.lua'; server { listen unix:$::HtmlDir/nginx.sock; default_type 'text/plain'; @@ -953,7 +953,7 @@ lua tcp socket get keepalive peer: using connection === TEST 13: github issue #110: ngx.exit with HTTP_NOT_FOUND causes worker process to exit --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config error_page 404 /404.html; location /t { diff --git a/debian/modules/http-lua/t/023-rewrite/subrequest.t b/debian/modules/http-lua/t/023-rewrite/subrequest.t index cb8523c..5d1e8f0 100644 --- a/debian/modules/http-lua/t/023-rewrite/subrequest.t +++ b/debian/modules/http-lua/t/023-rewrite/subrequest.t @@ -27,7 +27,7 @@ __DATA__ location /lua { rewrite_by_lua ' - local res = ngx.location.capture("/other", + res = ngx.location.capture("/other", { method = ngx.HTTP_DELETE }); ngx.print(res.body) @@ -54,7 +54,7 @@ DELETE location /lua { rewrite_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { method = ngx.HTTP_DELETE }); ngx.print(res.body) @@ -82,7 +82,7 @@ DELETE location /lua { rewrite_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { method = ngx.HTTP_POST }); ngx.print(res.body) @@ -105,7 +105,7 @@ POST location /lua { rewrite_by_lua ' - local res = ngx.location.capture("/other", + res = ngx.location.capture("/other", { method = ngx.HTTP_HEAD }); ngx.print(res.body) @@ -131,7 +131,7 @@ GET /lua location /lua { rewrite_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { method = ngx.HTTP_GET }); ngx.print(res.body) @@ -158,7 +158,7 @@ GET location /lua { rewrite_by_lua ' - local res = ngx.location.capture("/foo") + res = ngx.location.capture("/foo") ngx.print(res.body) '; @@ -184,7 +184,7 @@ GET location /lua { rewrite_by_lua ' - local res = ngx.location.capture("/foo", {}) + res = ngx.location.capture("/foo", {}) ngx.print(res.body) '; @@ -213,7 +213,7 @@ GET location /lua { rewrite_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { method = ngx.HTTP_PUT, body = "hello" }); ngx.print(res.body) @@ -241,7 +241,7 @@ hello location /lua { rewrite_by_lua ' - local res = ngx.location.capture("/other", + res = ngx.location.capture("/other", { method = ngx.HTTP_PUT, body = "hello" }); ngx.print(res.body) @@ -276,7 +276,7 @@ hello location /lua { rewrite_by_lua ' - local res = ngx.location.capture("/other", + res = ngx.location.capture("/other", { method = ngx.HTTP_PUT, body = "hello" }); ngx.print(res.body) @@ -313,7 +313,7 @@ GET location /lua { rewrite_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { method = ngx.HTTP_POST, body = "hello" }); ngx.print(res.body) @@ -345,7 +345,7 @@ hello rewrite_by_lua ' ngx.location.capture("/flush"); - local res = ngx.location.capture("/memc"); + res = ngx.location.capture("/memc"); ngx.say("GET: " .. res.status); res = ngx.location.capture("/memc", @@ -386,7 +386,7 @@ cached: hello ngx.location.capture("/flush", { share_all_vars = true }); - local res = ngx.location.capture("/memc", + res = ngx.location.capture("/memc", { share_all_vars = true }); ngx.say("GET: " .. res.status); @@ -417,7 +417,7 @@ cached: hello location /lua { rewrite_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { args = {} }) ngx.print(res.body) '; @@ -437,7 +437,7 @@ GET /lua location /lua { rewrite_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { args = { ["fo="] = "=>" } }) ngx.print(res.body) '; @@ -458,7 +458,7 @@ fo%3D=%3D%3E location /lua { rewrite_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { args = { ["fo="] = "=>", ["="] = ":" } }) ngx.print(res.body) @@ -480,7 +480,7 @@ GET /lua location /lua { rewrite_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { args = { foo = 3, bar = "hello" } }) ngx.print(res.body) @@ -502,7 +502,7 @@ GET /lua location /lua { rewrite_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { args = { [57] = "hi" } }) ngx.print(res.body) '; @@ -523,7 +523,7 @@ GET /lua location /lua { rewrite_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { args = { "hi" } }) ngx.print(res.body) '; @@ -544,7 +544,7 @@ GET /lua location /lua { rewrite_by_lua ' - local res = ngx.location.capture("/foo?a=3", + res = ngx.location.capture("/foo?a=3", { args = { b = 4 } }) ngx.print(res.body) '; @@ -565,7 +565,7 @@ a=3&b=4 location /lua { rewrite_by_lua ' - local res = ngx.location.capture("/foo?a=3", + res = ngx.location.capture("/foo?a=3", { args = "b=4" }) ngx.print(res.body) '; diff --git a/debian/modules/http-lua/t/023-rewrite/tcp-socket-timeout.t b/debian/modules/http-lua/t/023-rewrite/tcp-socket-timeout.t index e713bb5..329c045 100644 --- a/debian/modules/http-lua/t/023-rewrite/tcp-socket-timeout.t +++ b/debian/modules/http-lua/t/023-rewrite/tcp-socket-timeout.t @@ -46,7 +46,7 @@ __DATA__ location /t1 { rewrite_by_lua ' local sock = ngx.socket.tcp() - local ok, err = sock:connect("127.0.0.2", 12345) + local ok, err = sock:connect("agentzh.org", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -63,7 +63,7 @@ GET /t1 failed to connect: timeout --- error_log lua tcp socket connect timeout: 100 -lua tcp socket connect timed out, when connecting to 127.0.0.2:12345 +lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 --- timeout: 10 @@ -79,7 +79,7 @@ lua tcp socket connect timed out, when connecting to 127.0.0.2:12345 rewrite_by_lua ' local sock = ngx.socket.tcp() sock:settimeout(150) - local ok, err = sock:connect("127.0.0.2", 12345) + local ok, err = sock:connect("agentzh.org", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -114,7 +114,7 @@ lua tcp socket connect timeout: 150 rewrite_by_lua ' local sock = ngx.socket.tcp() sock:settimeout(nil) - local ok, err = sock:connect("127.0.0.2", 12345) + local ok, err = sock:connect("agentzh.org", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -149,7 +149,7 @@ lua tcp socket connect timeout: 102 rewrite_by_lua ' local sock = ngx.socket.tcp() sock:settimeout(0) - local ok, err = sock:connect("127.0.0.2", 12345) + local ok, err = sock:connect("agentzh.org", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -185,7 +185,7 @@ lua tcp socket connect timeout: 102 rewrite_by_lua ' local sock = ngx.socket.tcp() sock:settimeout(-1) - local ok, err = sock:connect("127.0.0.2", 12345) + local ok, err = sock:connect("agentzh.org", 12345) if not ok then ngx.say("failed to connect: ", err) return diff --git a/debian/modules/http-lua/t/023-rewrite/tcp-socket.t b/debian/modules/http-lua/t/023-rewrite/tcp-socket.t index 5258487..41aeab7 100644 --- a/debian/modules/http-lua/t/023-rewrite/tcp-socket.t +++ b/debian/modules/http-lua/t/023-rewrite/tcp-socket.t @@ -250,11 +250,11 @@ attempt to send data on a closed socket: } --- request GET /t ---- response_body_like +--- response_body connected: 1 request sent: 56 -first line received: HTTP\/1\.1 200 OK -second line received: (?:Date|Server): .*? +first line received: HTTP/1.1 200 OK +second line received: Server: openresty --- no_error_log [error] @@ -304,7 +304,7 @@ qr/connect\(\) failed \(\d+: Connection refused\)/ location /test { rewrite_by_lua ' local sock = ngx.socket.tcp() - local ok, err = sock:connect("127.0.0.2", 12345) + local ok, err = sock:connect("agentzh.org", 12345) ngx.say("connect: ", ok, " ", err) local bytes @@ -329,7 +329,7 @@ send: nil closed receive: nil closed close: nil closed --- error_log -lua tcp socket connect timed out, when connecting to 127.0.0.2:12345 +lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 --- timeout: 10 @@ -940,7 +940,7 @@ close: 1 nil end end - local ok, err = sock:close() + ok, err = sock:close() ngx.say("close: ", ok, " ", err) '; @@ -1082,7 +1082,7 @@ close: 1 nil === TEST 19: cannot survive across request boundary (send) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config server_tokens off; location /t { @@ -1143,7 +1143,7 @@ received: OK|failed to send request: closed)\$" === TEST 20: cannot survive across request boundary (receive) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config server_tokens off; location /t { @@ -1214,7 +1214,7 @@ received: OK|failed to receive a line: closed \[nil\])$/ === TEST 21: cannot survive across request boundary (close) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config server_tokens off; location /t { @@ -1285,7 +1285,7 @@ received: OK|failed to close: closed)$/ === TEST 22: cannot survive across request boundary (connect) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config server_tokens off; location /t { @@ -2041,7 +2041,7 @@ close: 1 nil === TEST 33: bad request tries to connect --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config server_tokens off; location = /main { @@ -2097,7 +2097,7 @@ qr/runtime error: rewrite_by_lua\(nginx\.conf:\d+\):7: bad request/ === TEST 34: bad request tries to receive --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config server_tokens off; location = /main { @@ -2156,7 +2156,7 @@ qr/runtime error: rewrite_by_lua\(nginx\.conf:\d+\):14: bad request/ === TEST 35: bad request tries to send --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config server_tokens off; location = /main { @@ -2215,7 +2215,7 @@ qr/runtime error: rewrite_by_lua\(nginx\.conf:\d+\):14: bad request/ === TEST 36: bad request tries to close --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config server_tokens off; location = /main { @@ -2274,7 +2274,7 @@ qr/runtime error: rewrite_by_lua\(nginx\.conf:\d+\):14: bad request/ === TEST 37: bad request tries to set keepalive --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config server_tokens off; location = /main { @@ -2333,7 +2333,7 @@ qr/runtime error: rewrite_by_lua\(nginx\.conf:\d+\):14: bad request/ === TEST 38: bad request tries to receiveuntil --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config server_tokens off; location = /main { diff --git a/debian/modules/http-lua/t/023-rewrite/uthread-exec.t b/debian/modules/http-lua/t/023-rewrite/uthread-exec.t index 9428bd6..2bea7e7 100644 --- a/debian/modules/http-lua/t/023-rewrite/uthread-exec.t +++ b/debian/modules/http-lua/t/023-rewrite/uthread-exec.t @@ -23,7 +23,7 @@ __DATA__ --- config location /lua { rewrite_by_lua ' - local function f() + function f() ngx.exec("/foo") end @@ -59,7 +59,7 @@ i am foo --- config location /lua { rewrite_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.exec("/foo") end @@ -95,7 +95,7 @@ i am foo --- config location /lua { rewrite_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.exec("/foo") end @@ -178,12 +178,12 @@ hello foo --- config location /lua { rewrite_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.exec("/foo") end - local function g() + function g() ngx.sleep(1) end @@ -270,7 +270,7 @@ hello foo location /lua { client_body_timeout 12000ms; rewrite_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.exec("/foo") end diff --git a/debian/modules/http-lua/t/023-rewrite/uthread-exit.t b/debian/modules/http-lua/t/023-rewrite/uthread-exit.t index e25f7f8..6ebbb67 100644 --- a/debian/modules/http-lua/t/023-rewrite/uthread-exit.t +++ b/debian/modules/http-lua/t/023-rewrite/uthread-exit.t @@ -24,7 +24,7 @@ __DATA__ --- config location /lua { rewrite_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.exit(0) end @@ -87,7 +87,7 @@ hello in thread --- config location /lua { rewrite_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -172,13 +172,13 @@ after --- config location /lua { rewrite_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.say("f") ngx.exit(0) end - local function g() + function g() ngx.sleep(1) ngx.say("g") end @@ -262,7 +262,7 @@ f --- config location /lua { rewrite_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.say("exiting the user thread") ngx.exit(0) @@ -298,10 +298,10 @@ exiting the user thread === TEST 5: exit in user thread (entry thread is still pending on the DNS resolver for ngx.socket.tcp) --- config location /lua { - resolver 127.0.0.2:12345; + resolver agentzh.org; resolver_timeout 12s; rewrite_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.001) ngx.exit(0) @@ -311,7 +311,7 @@ exiting the user thread ngx.thread.spawn(f) ngx.say("after") local sock = ngx.socket.tcp() - local ok, err = sock:connect("127.0.0.2", 12345) + local ok, err = sock:connect("agentzh.org", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -403,11 +403,11 @@ after === TEST 6: exit in user thread (entry thread is still pending on the DNS resolver for ngx.socket.udp) --- config location /lua { - resolver 127.0.0.2:12345; + resolver agentzh.org; #resolver 127.0.0.1; resolver_timeout 12s; rewrite_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.001) ngx.exit(0) @@ -510,7 +510,7 @@ after --- config location /lua { rewrite_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -521,7 +521,7 @@ after ngx.say("after") local sock = ngx.socket.tcp() sock:settimeout(12000) - local ok, err = sock:connect("127.0.0.2", 12345) + local ok, err = sock:connect("172.105.207.225", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -600,7 +600,7 @@ after --- config location /lua { rewrite_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -700,7 +700,7 @@ after --- config location /lua { rewrite_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -806,7 +806,7 @@ after --- config location /lua { rewrite_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -901,7 +901,7 @@ after --- config location /lua { rewrite_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -995,7 +995,7 @@ after location /lua { client_body_timeout 12000ms; rewrite_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -1080,7 +1080,7 @@ after location /lua { client_body_timeout 12000ms; rewrite_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -1164,7 +1164,7 @@ attempt to abort with pending subrequests location /lua { client_body_timeout 12000ms; rewrite_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.exit(0) end @@ -1247,7 +1247,7 @@ attempt to abort with pending subrequests location /lua { client_body_timeout 12000ms; rewrite_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.exit(0) end diff --git a/debian/modules/http-lua/t/023-rewrite/uthread-redirect.t b/debian/modules/http-lua/t/023-rewrite/uthread-redirect.t index 0e636f7..83de1a3 100644 --- a/debian/modules/http-lua/t/023-rewrite/uthread-redirect.t +++ b/debian/modules/http-lua/t/023-rewrite/uthread-redirect.t @@ -25,7 +25,7 @@ __DATA__ location /lua { client_body_timeout 12000ms; rewrite_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.redirect(301) end @@ -113,7 +113,7 @@ attempt to abort with pending subrequests --- config location /lua { rewrite_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.redirect(301) end diff --git a/debian/modules/http-lua/t/023-rewrite/uthread-spawn.t b/debian/modules/http-lua/t/023-rewrite/uthread-spawn.t index dccef87..5552107 100644 --- a/debian/modules/http-lua/t/023-rewrite/uthread-spawn.t +++ b/debian/modules/http-lua/t/023-rewrite/uthread-spawn.t @@ -23,7 +23,7 @@ __DATA__ --- config location /lua { rewrite_by_lua ' - local function f() + function f() ngx.say("hello in thread") end @@ -68,11 +68,11 @@ after --- config location /lua { rewrite_by_lua ' - local function f() + function f() ngx.say("in thread 1") end - local function g() + function g() ngx.say("in thread 2") end @@ -117,7 +117,7 @@ after 2 --- config location /lua { rewrite_by_lua ' - local function f() + function f() ngx.say("before sleep") ngx.sleep(0.1) ngx.say("after sleep") @@ -154,13 +154,13 @@ after sleep --- config location /lua { rewrite_by_lua ' - local function f() + function f() ngx.say("1: before sleep") ngx.sleep(0.2) ngx.say("1: after sleep") end - local function g() + function g() ngx.say("2: before sleep") ngx.sleep(0.1) ngx.say("2: after sleep") @@ -210,7 +210,7 @@ delete thread 2 --- config location /lua { rewrite_by_lua ' - local function f() + function f() ngx.blah() end @@ -241,9 +241,9 @@ qr/lua user thread aborted: runtime error: rewrite_by_lua\(nginx\.conf:\d+\):3: --- config location /lua { rewrite_by_lua ' - local function f() + function f() ngx.say("before capture") - local res = ngx.location.capture("/proxy") + res = ngx.location.capture("/proxy") ngx.say("after capture: ", res.body) end @@ -287,7 +287,7 @@ after capture: hello world --- config location /lua { rewrite_by_lua ' - local function f() + function f() ngx.say("before capture") local res = ngx.location.capture("/proxy?foo") ngx.say("after capture: ", res.body) @@ -340,7 +340,7 @@ after capture: hello foo --- config location /lua { rewrite_by_lua ' - local function f() + function f() ngx.say("before capture") local res = ngx.location.capture("/proxy?foo") ngx.say("after capture: ", res.body) @@ -394,13 +394,13 @@ capture: hello bar --- config location /lua { rewrite_by_lua ' - local function f() + function f() ngx.say("f: before capture") local res = ngx.location.capture("/proxy?foo") ngx.say("f: after capture: ", res.body) end - local function g() + function g() ngx.say("g: before capture") local res = ngx.location.capture("/proxy?bah") ngx.say("g: after capture: ", res.body) @@ -472,8 +472,7 @@ g: after capture: hello bah --- config location /lua { rewrite_by_lua ' - local g - local function f() + function f() ngx.say("before g") ngx.thread.spawn(g) ngx.say("after g") @@ -519,8 +518,7 @@ after g --- config location /lua { rewrite_by_lua ' - local g - local function f() + function f() ngx.say("before g") ngx.thread.spawn(g) ngx.say("after g") @@ -568,7 +566,7 @@ hello in g() location /lua { rewrite_by_lua ' local co - local function f() + function f() co = coroutine.running() ngx.sleep(0.1) end @@ -601,7 +599,7 @@ status: running location /lua { rewrite_by_lua ' local co - local function f() + function f() co = coroutine.running() end @@ -633,8 +631,7 @@ status: zombie location /lua { rewrite_by_lua ' local co - local g - local function f() + function f() co = coroutine.running() local co2 = coroutine.create(g) coroutine.resume(co2) @@ -673,8 +670,7 @@ status: normal --- config location /lua { rewrite_by_lua ' - local g - local function f() + function f() ngx.say("before g") ngx.thread.spawn(g) ngx.say("after g") @@ -721,7 +717,7 @@ after f rewrite_by_lua ' local yield = coroutine.yield - local function f() + function f() local self = coroutine.running() ngx.say("f 1") yield(self) @@ -774,7 +770,7 @@ f 3 rewrite_by_lua ' local yield = coroutine.yield - local function f() + function f() local self = coroutine.running() ngx.say("f 1") yield(self) @@ -783,7 +779,7 @@ f 3 ngx.say("f 3") end - local function g() + function g() local self = coroutine.running() ngx.say("g 1") yield(self) @@ -830,7 +826,7 @@ g 3 --- config location /lua { rewrite_by_lua ' - local function f() + function f() ngx.say("hello in thread") coroutine.yield(coroutine.running) ngx.flush(true) @@ -867,12 +863,12 @@ after --- config location /lua { rewrite_by_lua ' - local function f() + function f() ngx.say("hello from f") ngx.flush(true) end - local function g() + function g() ngx.say("hello from g") ngx.flush(true) end @@ -918,7 +914,7 @@ hello from g --- config location /lua { rewrite_by_lua ' - local function f() + function f() local sock = ngx.socket.tcp() local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_MEMCACHED_PORT) if not ok then @@ -970,7 +966,7 @@ received: OK --- config location /lua { rewrite_by_lua ' - local function f() + function f() local sock = ngx.socket.udp() local ok, err = sock:setpeername("127.0.0.1", 12345) local bytes, err = sock:send("blah") @@ -1031,7 +1027,7 @@ after)$ --- config location /lua { rewrite_by_lua ' - local function f() + function f() ngx.req.read_body() local body = ngx.req.get_body_data() ngx.say("body: ", body) @@ -1077,7 +1073,7 @@ body: hello world)$ --- config location /lua { rewrite_by_lua ' - local function f() + function f() local sock = ngx.req.socket() local body, err = sock:receive(11) if not body then diff --git a/debian/modules/http-lua/t/024-access/client-abort.t b/debian/modules/http-lua/t/024-access/client-abort.t index 83bf0a4..c16f4ea 100644 --- a/debian/modules/http-lua/t/024-access/client-abort.t +++ b/debian/modules/http-lua/t/024-access/client-abort.t @@ -200,7 +200,7 @@ bad things happen location = /sub { proxy_ignore_client_abort on; - proxy_pass http://127.0.0.2:12345/; + proxy_pass http://agentzh.org:12345/; } location = /sleep { @@ -241,7 +241,7 @@ client prematurely closed connection location = /sub { proxy_ignore_client_abort off; - proxy_pass http://127.0.0.2:12345/; + proxy_pass http://agentzh.org:12345/; } --- request GET /t @@ -546,7 +546,7 @@ client prematurely closed connection return end - local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_REDIS_PORT) + ok, err = sock:connect("127.0.0.1", $TEST_NGINX_REDIS_PORT) if not ok then ngx.log(ngx.ERR, "failed to connect: ", err) return diff --git a/debian/modules/http-lua/t/024-access/exec.t b/debian/modules/http-lua/t/024-access/exec.t index d168a47..43c1a77 100644 --- a/debian/modules/http-lua/t/024-access/exec.t +++ b/debian/modules/http-lua/t/024-access/exec.t @@ -326,7 +326,7 @@ hello --- config location /main { access_by_lua ' - local res = ngx.location.capture("/test_loc"); + res = ngx.location.capture("/test_loc"); ngx.print("hello, ", res.body) '; content_by_lua return; diff --git a/debian/modules/http-lua/t/024-access/mixed.t b/debian/modules/http-lua/t/024-access/mixed.t index 22f0037..a9f8039 100644 --- a/debian/modules/http-lua/t/024-access/mixed.t +++ b/debian/modules/http-lua/t/024-access/mixed.t @@ -35,7 +35,7 @@ __DATA__ access_by_lua ' ngx.location.capture("/flush"); - local res = ngx.location.capture("/memc"); + res = ngx.location.capture("/memc"); print("access GET: ", res.status); res = ngx.location.capture("/memc", @@ -49,7 +49,7 @@ __DATA__ content_by_lua ' ngx.location.capture("/flush"); - local res = ngx.location.capture("/memc"); + res = ngx.location.capture("/memc"); ngx.say("content GET: " .. res.status); res = ngx.location.capture("/memc", @@ -187,7 +187,7 @@ world\x03\x04\xff rewrite_by_lua ' ngx.location.capture("/flush"); - local res = ngx.location.capture("/memc"); + res = ngx.location.capture("/memc"); print("rewrite GET: " .. res.status); res = ngx.location.capture("/memc", @@ -201,7 +201,7 @@ world\x03\x04\xff access_by_lua ' ngx.location.capture("/flush"); - local res = ngx.location.capture("/memc"); + res = ngx.location.capture("/memc"); print("access GET: " .. res.status); res = ngx.location.capture("/memc", @@ -215,7 +215,7 @@ world\x03\x04\xff content_by_lua ' ngx.location.capture("/flush"); - local res = ngx.location.capture("/memc"); + res = ngx.location.capture("/memc"); ngx.say("content GET: " .. res.status); res = ngx.location.capture("/memc", diff --git a/debian/modules/http-lua/t/024-access/multi-capture.t b/debian/modules/http-lua/t/024-access/multi-capture.t index b1757dd..930b74d 100644 --- a/debian/modules/http-lua/t/024-access/multi-capture.t +++ b/debian/modules/http-lua/t/024-access/multi-capture.t @@ -154,7 +154,7 @@ res2.body = b location /main { access_by_lua ' - local res = ngx.location.capture("/foo?n=1") + res = ngx.location.capture("/foo?n=1") ngx.say("top res.status = " .. res.status) ngx.say("top res.body = [" .. res.body .. "]") '; diff --git a/debian/modules/http-lua/t/024-access/sanity.t b/debian/modules/http-lua/t/024-access/sanity.t index e5612a8..7ff177f 100644 --- a/debian/modules/http-lua/t/024-access/sanity.t +++ b/debian/modules/http-lua/t/024-access/sanity.t @@ -69,7 +69,7 @@ GET /lua location /lua { # NOTE: the newline escape sequence must be double-escaped, as nginx config # parser will unescape first! - access_by_lua 'local v = ngx.var["request_uri"] ngx.print("request_uri: ", v, "\\n")'; + access_by_lua 'v = ngx.var["request_uri"] ngx.print("request_uri: ", v, "\\n")'; content_by_lua 'ngx.exit(ngx.OK)'; } --- request @@ -87,7 +87,7 @@ request_uri: /lua?a=1&b=2 } --- user_files >>> test.lua -local v = ngx.var["request_uri"] +v = ngx.var["request_uri"] ngx.print("request_uri: ", v, "\n") --- request GET /lua?a=1&b=2 @@ -140,7 +140,7 @@ result: -0.4090441561579 === TEST 7: read $arg_xxx --- config location = /lua { - access_by_lua 'local who = ngx.var.arg_who + access_by_lua 'who = ngx.var.arg_who ngx.print("Hello, ", who, "!")'; content_by_lua 'ngx.exit(ngx.OK)'; } @@ -159,7 +159,7 @@ Hello, agentzh! location /lua { access_by_lua ' -local res = ngx.location.capture("/other") +res = ngx.location.capture("/other") ngx.print("status=", res.status, " ") ngx.print("body=", res.body) '; @@ -175,7 +175,7 @@ status=200 body=hello, world === TEST 9: capture non-existed location --- config location /lua { - access_by_lua 'local res = ngx.location.capture("/other"); ngx.print("status=", res.status)'; + access_by_lua 'res = ngx.location.capture("/other"); ngx.print("status=", res.status)'; content_by_lua 'ngx.exit(ngx.OK)'; } --- request @@ -187,7 +187,7 @@ GET /lua === TEST 10: invalid capture location (not as expected...) --- config location /lua { - access_by_lua 'local res = ngx.location.capture("*(#*"); ngx.say("res=", res.status)'; + access_by_lua 'res = ngx.location.capture("*(#*"); ngx.say("res=", res.status)'; content_by_lua 'ngx.exit(ngx.OK)'; } --- request @@ -244,7 +244,7 @@ GET /lua ngx.print("num is: ", num, "\\n"); if (num > 0) then - local res = ngx.location.capture("/recur?num="..tostring(num - 1)); + res = ngx.location.capture("/recur?num="..tostring(num - 1)); ngx.print("status=", res.status, " "); ngx.print("body=", res.body, "\\n"); else @@ -271,7 +271,7 @@ access phase not running in subrequests ngx.print("num is: ", num, "\\n"); if (num > 0) then - local res = ngx.location.capture("/recur?num="..tostring(num - 1)); + res = ngx.location.capture("/recur?num="..tostring(num - 1)); ngx.print("status=", res.status, " "); ngx.print("body=", res.body); else @@ -357,7 +357,7 @@ location /sub { } location /parent { set $a 12; - access_by_lua 'local res = ngx.location.capture("/sub"); ngx.print(res.body)'; + access_by_lua 'res = ngx.location.capture("/sub"); ngx.print(res.body)'; content_by_lua 'ngx.exit(ngx.OK)'; } --- request @@ -375,7 +375,7 @@ location /parent { set $a ''; access_by_lua ' ngx.var.a = 12; - local res = ngx.location.capture( + res = ngx.location.capture( "/sub", { share_all_vars = true } ); @@ -397,7 +397,7 @@ location /sub { } location /parent { access_by_lua ' - local res = ngx.location.capture("/sub", { share_all_vars = true }); + res = ngx.location.capture("/sub", { share_all_vars = true }); ngx.say(ngx.var.a) '; @@ -419,7 +419,7 @@ location /sub { location /parent { access_by_lua ' - local res = ngx.location.capture("/sub", { share_all_vars = false }); + res = ngx.location.capture("/sub", { share_all_vars = false }); ngx.say(ngx.var.a) '; content_by_lua return; @@ -439,7 +439,7 @@ GET /parent location /lua { access_by_lua ' - local res = ngx.location.capture("/other"); + res = ngx.location.capture("/other"); ngx.say("type: ", res.header["Content-Type"]); '; @@ -464,7 +464,7 @@ type: foo/bar location /lua { access_by_lua ' - local res = ngx.location.capture("/other"); + res = ngx.location.capture("/other"); ngx.say("type: ", res.header["Content-Type"]); ngx.say("Bar: ", res.header["Bar"]); '; @@ -492,7 +492,7 @@ Bar: Bah location /lua { access_by_lua ' - local res = ngx.location.capture("/other"); + res = ngx.location.capture("/other"); ngx.say("type: ", res.header["Content-Type"]); ngx.say("Bar: ", res.header["Bar"] or "nil"); '; diff --git a/debian/modules/http-lua/t/024-access/subrequest.t b/debian/modules/http-lua/t/024-access/subrequest.t index 665780a..b6ccf11 100644 --- a/debian/modules/http-lua/t/024-access/subrequest.t +++ b/debian/modules/http-lua/t/024-access/subrequest.t @@ -27,7 +27,7 @@ __DATA__ location /lua { access_by_lua ' - local res = ngx.location.capture("/other", + res = ngx.location.capture("/other", { method = ngx.HTTP_DELETE }); ngx.print(res.body) @@ -54,7 +54,7 @@ DELETE location /lua { access_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { method = ngx.HTTP_DELETE }); ngx.print(res.body) @@ -82,7 +82,7 @@ DELETE location /lua { access_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { method = ngx.HTTP_POST }); ngx.print(res.body) @@ -105,7 +105,7 @@ POST location /lua { access_by_lua ' - local res = ngx.location.capture("/other", + res = ngx.location.capture("/other", { method = ngx.HTTP_HEAD }); ngx.print(res.body) @@ -131,7 +131,7 @@ GET /lua location /lua { access_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { method = ngx.HTTP_GET }); ngx.print(res.body) @@ -158,7 +158,7 @@ GET location /lua { access_by_lua ' - local res = ngx.location.capture("/foo") + res = ngx.location.capture("/foo") ngx.print(res.body) '; @@ -184,7 +184,7 @@ GET location /lua { access_by_lua ' - local res = ngx.location.capture("/foo", {}) + res = ngx.location.capture("/foo", {}) ngx.print(res.body) '; @@ -213,7 +213,7 @@ GET location /lua { access_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { method = ngx.HTTP_PUT, body = "hello" }); ngx.print(res.body) @@ -241,7 +241,7 @@ hello location /lua { access_by_lua ' - local res = ngx.location.capture("/other", + res = ngx.location.capture("/other", { method = ngx.HTTP_PUT, body = "hello" }); ngx.print(res.body) @@ -276,7 +276,7 @@ hello location /lua { access_by_lua ' - local res = ngx.location.capture("/other", + res = ngx.location.capture("/other", { method = ngx.HTTP_PUT, body = "hello" }); ngx.print(res.body) @@ -313,7 +313,7 @@ GET location /lua { access_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { method = ngx.HTTP_POST, body = "hello" }); ngx.print(res.body) @@ -345,7 +345,7 @@ hello access_by_lua ' ngx.location.capture("/flush"); - local res = ngx.location.capture("/memc"); + res = ngx.location.capture("/memc"); ngx.say("GET: " .. res.status); res = ngx.location.capture("/memc", @@ -386,7 +386,7 @@ cached: hello ngx.location.capture("/flush", { share_all_vars = true }); - local res = ngx.location.capture("/memc", + res = ngx.location.capture("/memc", { share_all_vars = true }); ngx.say("GET: " .. res.status); @@ -417,7 +417,7 @@ cached: hello location /lua { access_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { args = {} }) ngx.print(res.body) '; @@ -437,7 +437,7 @@ GET /lua location /lua { access_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { args = { ["fo="] = "=>" } }) ngx.print(res.body) '; @@ -458,7 +458,7 @@ fo%3D=%3D%3E location /lua { access_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { args = { ["fo="] = "=>", ["="] = ":" } }) ngx.print(res.body) @@ -480,7 +480,7 @@ GET /lua location /lua { access_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { args = { foo = 3, bar = "hello" } }) ngx.print(res.body) @@ -502,7 +502,7 @@ GET /lua location /lua { access_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { args = { [57] = "hi" } }) ngx.print(res.body) '; @@ -523,7 +523,7 @@ GET /lua location /lua { access_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { args = { "hi" } }) ngx.print(res.body) '; @@ -544,7 +544,7 @@ GET /lua location /lua { access_by_lua ' - local res = ngx.location.capture("/foo?a=3", + res = ngx.location.capture("/foo?a=3", { args = { b = 4 } }) ngx.print(res.body) '; @@ -565,7 +565,7 @@ a=3&b=4 location /lua { access_by_lua ' - local res = ngx.location.capture("/foo?a=3", + res = ngx.location.capture("/foo?a=3", { args = "b=4" }) ngx.print(res.body) '; diff --git a/debian/modules/http-lua/t/024-access/uthread-exec.t b/debian/modules/http-lua/t/024-access/uthread-exec.t index 9c88eb3..7add3d4 100644 --- a/debian/modules/http-lua/t/024-access/uthread-exec.t +++ b/debian/modules/http-lua/t/024-access/uthread-exec.t @@ -23,7 +23,7 @@ __DATA__ --- config location /lua { access_by_lua ' - local function f() + function f() ngx.exec("/foo") end @@ -59,7 +59,7 @@ i am foo --- config location /lua { access_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.exec("/foo") end @@ -95,7 +95,7 @@ i am foo --- config location /lua { access_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.exec("/foo") end @@ -179,12 +179,12 @@ hello foo --- config location /lua { access_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.exec("/foo") end - local function g() + function g() ngx.sleep(1) end @@ -271,7 +271,7 @@ hello foo location /lua { client_body_timeout 12000ms; access_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.exec("/foo") end diff --git a/debian/modules/http-lua/t/024-access/uthread-exit.t b/debian/modules/http-lua/t/024-access/uthread-exit.t index 2757237..02c2a1f 100644 --- a/debian/modules/http-lua/t/024-access/uthread-exit.t +++ b/debian/modules/http-lua/t/024-access/uthread-exit.t @@ -24,7 +24,7 @@ __DATA__ --- config location /lua { access_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.exit(0) end @@ -87,7 +87,7 @@ hello in thread --- config location /lua { access_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -172,13 +172,13 @@ after --- config location /lua { access_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.say("f") ngx.exit(0) end - local function g() + function g() ngx.sleep(1) ngx.say("g") end @@ -262,7 +262,7 @@ f --- config location /lua { access_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.say("exiting the user thread") ngx.exit(0) @@ -298,10 +298,10 @@ exiting the user thread === TEST 5: exit in user thread (entry thread is still pending on the DNS resolver for ngx.socket.tcp) --- config location /lua { - resolver 127.0.0.2:12345; + resolver agentzh.org; resolver_timeout 12s; access_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.001) ngx.exit(0) @@ -394,10 +394,10 @@ after === TEST 6: exit in user thread (entry thread is still pending on the DNS resolver for ngx.socket.udp) --- config location /lua { - resolver 127.0.0.2:12345; + resolver agentzh.org; resolver_timeout 12s; access_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.001) ngx.exit(0) @@ -491,7 +491,7 @@ after --- config location /lua { access_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -502,7 +502,7 @@ after ngx.say("after") local sock = ngx.socket.tcp() sock:settimeout(12000) - local ok, err = sock:connect("127.0.0.2", 12345) + local ok, err = sock:connect("172.105.207.225", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -582,7 +582,7 @@ after --- config location /lua { access_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -682,7 +682,7 @@ after --- config location /lua { access_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -788,7 +788,7 @@ after --- config location /lua { access_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -883,7 +883,7 @@ after --- config location /lua { access_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -977,7 +977,7 @@ after location /lua { client_body_timeout 12000ms; access_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -1062,7 +1062,7 @@ after location /lua { client_body_timeout 12000ms; access_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -1146,7 +1146,7 @@ attempt to abort with pending subrequests location /lua { client_body_timeout 12000ms; access_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.exit(0) end @@ -1229,7 +1229,7 @@ attempt to abort with pending subrequests location /lua { client_body_timeout 12000ms; access_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.exit(0) end diff --git a/debian/modules/http-lua/t/024-access/uthread-redirect.t b/debian/modules/http-lua/t/024-access/uthread-redirect.t index cb99a35..4eb4759 100644 --- a/debian/modules/http-lua/t/024-access/uthread-redirect.t +++ b/debian/modules/http-lua/t/024-access/uthread-redirect.t @@ -25,7 +25,7 @@ __DATA__ location /lua { client_body_timeout 12000ms; access_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.redirect(301) end @@ -113,7 +113,7 @@ attempt to abort with pending subrequests --- config location /lua { access_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.redirect(301) end diff --git a/debian/modules/http-lua/t/024-access/uthread-spawn.t b/debian/modules/http-lua/t/024-access/uthread-spawn.t index bc92ccd..7c7ba3b 100644 --- a/debian/modules/http-lua/t/024-access/uthread-spawn.t +++ b/debian/modules/http-lua/t/024-access/uthread-spawn.t @@ -23,7 +23,7 @@ __DATA__ --- config location /lua { access_by_lua ' - local function f() + function f() ngx.say("hello in thread") end @@ -68,11 +68,11 @@ after --- config location /lua { access_by_lua ' - local function f() + function f() ngx.say("in thread 1") end - local function g() + function g() ngx.say("in thread 2") end @@ -117,7 +117,7 @@ after 2 --- config location /lua { access_by_lua ' - local function f() + function f() ngx.say("before sleep") ngx.sleep(0.1) ngx.say("after sleep") @@ -154,13 +154,13 @@ after sleep --- config location /lua { access_by_lua ' - local function f() + function f() ngx.say("1: before sleep") ngx.sleep(0.2) ngx.say("1: after sleep") end - local function g() + function g() ngx.say("2: before sleep") ngx.sleep(0.1) ngx.say("2: after sleep") @@ -210,7 +210,7 @@ delete thread 2 --- config location /lua { access_by_lua ' - local function f() + function f() ngx.blah() end @@ -241,9 +241,9 @@ qr/lua user thread aborted: runtime error: access_by_lua\(nginx\.conf:\d+\):3: a --- config location /lua { access_by_lua ' - local function f() + function f() ngx.say("before capture") - local res = ngx.location.capture("/proxy") + res = ngx.location.capture("/proxy") ngx.say("after capture: ", res.body) end @@ -287,7 +287,7 @@ after capture: hello world --- config location /lua { access_by_lua ' - local function f() + function f() ngx.say("before capture") local res = ngx.location.capture("/proxy?foo") ngx.say("after capture: ", res.body) @@ -340,7 +340,7 @@ after capture: hello foo --- config location /lua { access_by_lua ' - local function f() + function f() ngx.say("before capture") local res = ngx.location.capture("/proxy?foo") ngx.say("after capture: ", res.body) @@ -395,13 +395,13 @@ capture: hello bar --- config location /lua { access_by_lua ' - local function f() + function f() ngx.say("f: before capture") local res = ngx.location.capture("/proxy?foo") ngx.say("f: after capture: ", res.body) end - local function g() + function g() ngx.say("g: before capture") local res = ngx.location.capture("/proxy?bah") ngx.say("g: after capture: ", res.body) @@ -473,8 +473,7 @@ g: after capture: hello bah --- config location /lua { access_by_lua ' - local g - local function f() + function f() ngx.say("before g") ngx.thread.spawn(g) ngx.say("after g") @@ -520,8 +519,7 @@ after g --- config location /lua { access_by_lua ' - local g - local function f() + function f() ngx.say("before g") ngx.thread.spawn(g) ngx.say("after g") @@ -569,7 +567,7 @@ hello in g() location /lua { access_by_lua ' local co - local function f() + function f() co = coroutine.running() ngx.sleep(0.1) end @@ -602,7 +600,7 @@ status: running location /lua { access_by_lua ' local co - local function f() + function f() co = coroutine.running() end @@ -634,8 +632,7 @@ status: zombie location /lua { access_by_lua ' local co - local g - local function f() + function f() co = coroutine.running() local co2 = coroutine.create(g) coroutine.resume(co2) @@ -674,8 +671,7 @@ status: normal --- config location /lua { access_by_lua ' - local g - local function f() + function f() ngx.say("before g") ngx.thread.spawn(g) ngx.say("after g") @@ -722,7 +718,7 @@ after f access_by_lua ' local yield = coroutine.yield - local function f() + function f() local self = coroutine.running() ngx.say("f 1") yield(self) @@ -775,7 +771,7 @@ f 3 access_by_lua ' local yield = coroutine.yield - local function f() + function f() local self = coroutine.running() ngx.say("f 1") yield(self) @@ -784,7 +780,7 @@ f 3 ngx.say("f 3") end - local function g() + function g() local self = coroutine.running() ngx.say("g 1") yield(self) @@ -831,7 +827,7 @@ g 3 --- config location /lua { access_by_lua ' - local function f() + function f() ngx.say("hello in thread") coroutine.yield(coroutine.running) ngx.flush(true) @@ -868,12 +864,12 @@ after --- config location /lua { access_by_lua ' - local function f() + function f() ngx.say("hello from f") ngx.flush(true) end - local function g() + function g() ngx.say("hello from g") ngx.flush(true) end @@ -919,7 +915,7 @@ hello from g --- config location /lua { access_by_lua ' - local function f() + function f() local sock = ngx.socket.tcp() local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_MEMCACHED_PORT) if not ok then @@ -971,7 +967,7 @@ received: OK --- config location /lua { access_by_lua ' - local function f() + function f() local sock = ngx.socket.udp() local ok, err = sock:setpeername("127.0.0.1", 12345) local bytes, err = sock:send("blah") @@ -1032,7 +1028,7 @@ after)$ --- config location /lua { access_by_lua ' - local function f() + function f() ngx.req.read_body() local body = ngx.req.get_body_data() ngx.say("body: ", body) @@ -1077,7 +1073,7 @@ body: hello world)$ --- config location /lua { access_by_lua ' - local function f() + function f() local sock = ngx.req.socket() local body, err = sock:receive(11) if not body then diff --git a/debian/modules/http-lua/t/025-codecache.t b/debian/modules/http-lua/t/025-codecache.t index 22b78b2..20791d7 100644 --- a/debian/modules/http-lua/t/025-codecache.t +++ b/debian/modules/http-lua/t/025-codecache.t @@ -4,7 +4,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * 163; +plan tests => repeat_each() * 155; #$ENV{LUA_PATH} = $ENV{HOME} . '/work/JSON4Lua-0.9.30/json/?.lua'; @@ -27,7 +27,7 @@ __DATA__ location /update { content_by_lua ' -- os.execute("(echo HERE; pwd) > /dev/stderr") - local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/test.lua", "w")) + local f = assert(io.open("t/servroot/html/test.lua", "w")) f:write("ngx.say(101)") f:close() ngx.say("updated") @@ -61,7 +61,7 @@ updated location /update { content_by_lua ' -- os.execute("(echo HERE; pwd) > /dev/stderr") - local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/test.lua", "w")) + local f = assert(io.open("t/servroot/html/test.lua", "w")) f:write("ngx.say(101)") f:close() ngx.say("updated") @@ -95,7 +95,7 @@ updated location /update { content_by_lua ' -- os.execute("(echo HERE; pwd) > /dev/stderr") - local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/test.lua", "w")) + local f = assert(io.open("t/servroot/html/test.lua", "w")) f:write("ngx.say(101)") f:close() ngx.say("updated") @@ -130,7 +130,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ location /update { content_by_lua ' -- os.execute("(echo HERE; pwd) > /dev/stderr") - local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/test.lua", "w")) + local f = assert(io.open("t/servroot/html/test.lua", "w")) f:write("ngx.say(101)") f:close() ngx.say("updated") @@ -166,7 +166,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ location /update { content_by_lua ' -- os.execute("(echo HERE; pwd) > /dev/stderr") - local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/test.lua", "w")) + local f = assert(io.open("t/servroot/html/test.lua", "w")) f:write("ngx.say(101)") f:close() ngx.say("updated") @@ -193,7 +193,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ === TEST 6: code cache explicitly off (affects require) + content_by_lua --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location /lua { lua_code_cache off; @@ -204,7 +204,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ location /update { content_by_lua ' -- os.execute("(echo HERE; pwd) > /dev/stderr") - local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/foo.lua", "w")) + local f = assert(io.open("t/servroot/html/foo.lua", "w")) f:write("module(..., package.seeall); ngx.say(102);") f:close() ngx.say("updated") @@ -231,7 +231,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ === TEST 7: code cache explicitly off (affects require) + content_by_lua_file --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location /lua { lua_code_cache off; @@ -240,7 +240,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ location /update { content_by_lua ' -- os.execute("(echo HERE; pwd) > /dev/stderr") - local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/foo.lua", "w")) + local f = assert(io.open("t/servroot/html/foo.lua", "w")) f:write("module(..., package.seeall); ngx.say(102);") f:close() ngx.say("updated") @@ -269,7 +269,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ === TEST 8: code cache explicitly off (affects require) + set_by_lua_file --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location /lua { lua_code_cache off; @@ -279,7 +279,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ location /update { content_by_lua ' -- os.execute("(echo HERE; pwd) > /dev/stderr") - local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/foo.lua", "w")) + local f = assert(io.open("t/servroot/html/foo.lua", "w")) f:write("module(..., package.seeall); return 102;") f:close() ngx.say("updated") @@ -308,7 +308,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ === TEST 9: code cache explicitly on (affects require) + set_by_lua_file --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location /lua { lua_code_cache on; @@ -318,7 +318,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ location /update { content_by_lua ' -- os.execute("(echo HERE; pwd) > /dev/stderr") - local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/foo.lua", "w")) + local f = assert(io.open("t/servroot/html/foo.lua", "w")) f:write("module(..., package.seeall); return 102;") f:close() ngx.say("updated") @@ -355,7 +355,7 @@ updated location /update { content_by_lua ' -- os.execute("(echo HERE; pwd) > /dev/stderr") - local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/test.lua", "w")) + local f = assert(io.open("t/servroot/html/test.lua", "w")) f:write("return 101") f:close() ngx.say("updated") @@ -390,7 +390,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ location /update { content_by_lua ' -- os.execute("(echo HERE; pwd) > /dev/stderr") - local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/test.lua", "w")) + local f = assert(io.open("t/servroot/html/test.lua", "w")) f:write("return 101") f:close() ngx.say("updated") @@ -468,7 +468,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ === TEST 14: no clear builtin lib "string" --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config lua_code_cache off; location /lua { @@ -504,7 +504,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ === TEST 15: do not skip luarocks --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;'; + "lua_package_path '$::HtmlDir/?.lua;./?.lua'; lua_code_cache off;" --- config location /main { @@ -554,7 +554,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ === TEST 16: do not skip luarocks* --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;'; + "lua_package_path '$::HtmlDir/?.lua;./?.lua'; lua_code_cache off;" --- config location /main { @@ -604,7 +604,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ === TEST 17: clear _G table --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config lua_code_cache off; location /t { @@ -1050,7 +1050,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/, === TEST 29: cosocket connection pool timeout (after Lua VM destroys) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config lua_code_cache off; location = /t { @@ -1118,7 +1118,7 @@ qr/\blua tcp socket keepalive: free connection pool [0-9A-F]+ for "127.0.0.1:/, === TEST 30: cosocket connection pool timeout (before Lua VM destroys) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config lua_code_cache off; location = /t { @@ -1244,133 +1244,3 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/, "decrementing the reference count for Lua VM: 1", "lua close the global Lua VM", ] - - - -=== TEST 32: make sure inline code keys are correct -GitHub issue #1428 ---- config -include ../html/a/proxy.conf; -include ../html/b/proxy.conf; -include ../html/c/proxy.conf; - -location /t { - echo_location /a/; - echo_location /b/; - echo_location /a/; - echo_location /c/; -} - ---- user_files ->>> a/proxy.conf -location /a/ { - content_by_lua_block { ngx.say("/a/ is called") } -} - ->>> b/proxy.conf -location /b/ { - content_by_lua_block { ngx.say("/b/ is called") } -} - ->>> c/proxy.conf -location /c/ { - content_by_lua_block { ngx.say("/b/ is called") } -} - ---- request -GET /t ---- response_body -/a/ is called -/b/ is called -/a/ is called -/b/ is called ---- grep_error_log eval: qr/looking up Lua code cache with key '.*?'/ ---- grep_error_log_out eval -[ -"looking up Lua code cache with key '=content_by_lua(proxy.conf:2)nhli_3c7137b8371d10bc148c8f8bb3042ee6' -looking up Lua code cache with key '=content_by_lua(proxy.conf:2)nhli_1dfe09105792ef65c8d576cc486d5e04' -looking up Lua code cache with key '=content_by_lua(proxy.conf:2)nhli_3c7137b8371d10bc148c8f8bb3042ee6' -looking up Lua code cache with key '=content_by_lua(proxy.conf:2)nhli_1dfe09105792ef65c8d576cc486d5e04' -", -"looking up Lua code cache with key '=content_by_lua(proxy.conf:2)nhli_3c7137b8371d10bc148c8f8bb3042ee6' -looking up Lua code cache with key '=content_by_lua(proxy.conf:2)nhli_1dfe09105792ef65c8d576cc486d5e04' -looking up Lua code cache with key '=content_by_lua(proxy.conf:2)nhli_3c7137b8371d10bc148c8f8bb3042ee6' -looking up Lua code cache with key '=content_by_lua(proxy.conf:2)nhli_1dfe09105792ef65c8d576cc486d5e04' -looking up Lua code cache with key '=content_by_lua(proxy.conf:2)nhli_3c7137b8371d10bc148c8f8bb3042ee6' -looking up Lua code cache with key '=content_by_lua(proxy.conf:2)nhli_1dfe09105792ef65c8d576cc486d5e04' -looking up Lua code cache with key '=content_by_lua(proxy.conf:2)nhli_3c7137b8371d10bc148c8f8bb3042ee6' -looking up Lua code cache with key '=content_by_lua(proxy.conf:2)nhli_1dfe09105792ef65c8d576cc486d5e04' -"] ---- log_level: debug ---- no_error_log -[error] - - - -=== TEST 33: make sure Lua code file keys are correct -GitHub issue #1428 ---- config -include ../html/a/proxy.conf; -include ../html/b/proxy.conf; -include ../html/c/proxy.conf; - -location /t { - echo_location /a/; - echo_location /b/; - echo_location /a/; - echo_location /c/; -} - ---- user_files ->>> a.lua -ngx.say("/a/ is called") - ->>> b.lua -ngx.say("/b/ is called") - ->>> c.lua -ngx.say("/b/ is called") - ->>> a/proxy.conf -location /a/ { - content_by_lua_file html/a.lua; -} - ->>> b/proxy.conf -location /b/ { - content_by_lua_file html/b.lua; -} - ->>> c/proxy.conf -location /c/ { - content_by_lua_file html/c.lua; -} - ---- request -GET /t ---- response_body -/a/ is called -/b/ is called -/a/ is called -/b/ is called ---- grep_error_log eval: qr/looking up Lua code cache with key '.*?'/ ---- grep_error_log_out eval -[ -"looking up Lua code cache with key 'nhlf_48a9a7def61143c003a7de1644e026e4' -looking up Lua code cache with key 'nhlf_68f5f4e946c3efd1cc206452b807e8b6' -looking up Lua code cache with key 'nhlf_48a9a7def61143c003a7de1644e026e4' -looking up Lua code cache with key 'nhlf_042c9b3a136fbacbbd0e4b9ad10896b7' -", -"looking up Lua code cache with key 'nhlf_48a9a7def61143c003a7de1644e026e4' -looking up Lua code cache with key 'nhlf_68f5f4e946c3efd1cc206452b807e8b6' -looking up Lua code cache with key 'nhlf_48a9a7def61143c003a7de1644e026e4' -looking up Lua code cache with key 'nhlf_042c9b3a136fbacbbd0e4b9ad10896b7' -looking up Lua code cache with key 'nhlf_48a9a7def61143c003a7de1644e026e4' -looking up Lua code cache with key 'nhlf_68f5f4e946c3efd1cc206452b807e8b6' -looking up Lua code cache with key 'nhlf_48a9a7def61143c003a7de1644e026e4' -looking up Lua code cache with key 'nhlf_042c9b3a136fbacbbd0e4b9ad10896b7' -" -] ---- log_level: debug ---- no_error_log -[error] diff --git a/debian/modules/http-lua/t/027-multi-capture.t b/debian/modules/http-lua/t/027-multi-capture.t index 9299561..9227fe5 100644 --- a/debian/modules/http-lua/t/027-multi-capture.t +++ b/debian/modules/http-lua/t/027-multi-capture.t @@ -151,7 +151,7 @@ res2.body = b location /main { content_by_lua ' - local res = ngx.location.capture("/foo?n=1") + res = ngx.location.capture("/foo?n=1") ngx.say("top res.status = " .. res.status) ngx.say("top res.body = [" .. res.body .. "]") '; @@ -743,7 +743,7 @@ proxy_cache_path conf/cache levels=1:2 keys_zone=STATIC:10m inactive=10m max_siz location = /proxy { proxy_cache STATIC; - proxy_pass http://127.0.0.2:12345; + proxy_pass http://agentzh.org:12345; proxy_cache_key $proxy_host$uri$args; proxy_cache_valid any 1s; #proxy_http_version 1.1; diff --git a/debian/modules/http-lua/t/028-req-header.t b/debian/modules/http-lua/t/028-req-header.t index 8ddbb29..ca92daa 100644 --- a/debian/modules/http-lua/t/028-req-header.t +++ b/debian/modules/http-lua/t/028-req-header.t @@ -8,7 +8,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * (2 * blocks() + 44); +plan tests => repeat_each() * (2 * blocks() + 43); #no_diff(); no_long_string(); @@ -2008,25 +2008,3 @@ found 3 headers. --- no_error_log lua exceeding request header limit [error] - - - -=== TEST 61: setting Host header clears cached $host variable ---- config - location /req-header { - # this makes $host indexed and cacheable - set $foo $host; - - content_by_lua_block { - ngx.say(ngx.var.host) - ngx.req.set_header("Host", "new"); - ngx.say(ngx.var.host) - } - } ---- request -GET /req-header ---- response_body -localhost -new ---- no_error_log -[error] diff --git a/debian/modules/http-lua/t/030-uri-args.t b/debian/modules/http-lua/t/030-uri-args.t index 7af63c4..a9d46ff 100644 --- a/debian/modules/http-lua/t/030-uri-args.t +++ b/debian/modules/http-lua/t/030-uri-args.t @@ -421,7 +421,7 @@ done ngx.req.set_uri_args("hello") ngx.req.set_uri("/bar", true); '; - proxy_pass http://127.0.0.2:12345; + proxy_pass http://agentzh.org:12345; } --- request GET /foo?world @@ -568,7 +568,7 @@ HTTP/1.0 ca%20t=%25 ngx.req.set_uri("/bar", true); ngx.exit(503) '; - proxy_pass http://127.0.0.2:12345; + proxy_pass http://agentzh.org:12345; } --- request GET /foo?world @@ -586,7 +586,7 @@ hello #set $args 'hello'; set $err ''; access_by_lua ' - local res, err = pcall(ngx.req.set_uri, "/bar", true); + res, err = pcall(ngx.req.set_uri, "/bar", true); ngx.var.err = err '; echo "err: $err"; @@ -626,7 +626,7 @@ uri: /bar location /foo { #set $args 'hello'; content_by_lua ' - local res, err = pcall(ngx.req.set_uri, "/bar", true); + res, err = pcall(ngx.req.set_uri, "/bar", true); ngx.say("err: ", err) '; } @@ -665,7 +665,7 @@ uri: /bar location /foo { #set $args 'hello'; set_by_lua $err ' - local res, err = pcall(ngx.req.set_uri, "/bar", true); + res, err = pcall(ngx.req.set_uri, "/bar", true); return err '; echo "err: $err"; @@ -788,7 +788,7 @@ GET /lua location /lua { content_by_lua ' local t = {bar = ngx.shared.dogs, foo = 3} - local rc, err = pcall(ngx.encode_args, t) + rc, err = pcall(ngx.encode_args, t) ngx.say("rc: ", rc, ", err: ", err) '; } @@ -1112,7 +1112,6 @@ HTTP/1.0 a=3&b=5&b=6 --- config location /lua { content_by_lua ' - local err local args = "a=bar&b=foo" args, err = ngx.decode_args(args) @@ -1136,7 +1135,6 @@ b = foo --- config location /lua { content_by_lua ' - local err local args = "a=bar&b=foo&a=baz" args, err = ngx.decode_args(args) @@ -1160,7 +1158,6 @@ b = foo --- config location /lua { content_by_lua ' - local err local args = "" args, err = ngx.decode_args(args) if err then @@ -1181,7 +1178,6 @@ n = 0 --- config location /lua { content_by_lua ' - local err local args = "a&b" args, err = ngx.decode_args(args) if err then @@ -1204,7 +1200,6 @@ b = true --- config location /lua { content_by_lua ' - local err local args = "a=&b=" args, err = ngx.decode_args(args) @@ -1228,7 +1223,6 @@ b = --- config location /lua { content_by_lua ' - local err local args = "a=bar&b=foo" args, err = ngx.decode_args(args, 1) if err then @@ -1252,7 +1246,6 @@ b = nil --- config location /lua { content_by_lua ' - local err local args = "a=bar&b=foo" args, err = ngx.decode_args(args, -1) @@ -1277,7 +1270,7 @@ b = foo location /lua { content_by_lua ' local s = "f+f=bar&B=foo" - local args, err = ngx.decode_args(s) + args, err = ngx.decode_args(s) if err then ngx.say("err: ", err) end @@ -1309,7 +1302,7 @@ s = f+f=bar&B=foo lua_need_request_body on; location /t { content_by_lua ' - local function split(s, delimiter) + function split(s, delimiter) local result = {} local from = 1 local delim_from, delim_to = string.find(s, delimiter, from) diff --git a/debian/modules/http-lua/t/034-match.t b/debian/modules/http-lua/t/034-match.t index 473a11f..ebe5762 100644 --- a/debian/modules/http-lua/t/034-match.t +++ b/debian/modules/http-lua/t/034-match.t @@ -21,7 +21,7 @@ __DATA__ --- config location /re { content_by_lua ' - local m = ngx.re.match("hello, 1234", "([0-9]+)") + m = ngx.re.match("hello, 1234", "([0-9]+)") if m then ngx.say(m[0]) else @@ -40,7 +40,7 @@ __DATA__ --- config location /re { content_by_lua ' - local m = ngx.re.match("hello, 1234", "(\\\\d+)") + m = ngx.re.match("hello, 1234", "(\\\\d+)") if m then ngx.say(m[0]) else @@ -59,7 +59,7 @@ __DATA__ --- config location /re { content_by_lua ' - local m = ngx.re.match("hello, 1234", "(\\d+)") + m = ngx.re.match("hello, 1234", "(\\d+)") if m then ngx.say(m[0]) else @@ -80,7 +80,7 @@ __DATA__ --- config location /re { content_by_lua ' - local m = ngx.re.match("hello, 1234", "[[\\d+]]") + m = ngx.re.match("hello, 1234", "[[\\d+]]") if m then ngx.say(m[0]) else @@ -101,7 +101,7 @@ __DATA__ --- config location /re { content_by_lua ' - local m = ngx.re.match("hello, 1234", "([0-9]{2})[0-9]+") + m = ngx.re.match("hello, 1234", "([0-9]{2})[0-9]+") if m then ngx.say(m[0]) ngx.say(m[1]) @@ -122,7 +122,7 @@ __DATA__ --- config location /re { content_by_lua ' - local m = ngx.re.match("hello, 1234", "([a-z]+).*?([0-9]{2})[0-9]+", "") + m = ngx.re.match("hello, 1234", "([a-z]+).*?([0-9]{2})[0-9]+", "") if m then ngx.say(m[0]) ngx.say(m[1]) @@ -145,7 +145,7 @@ hello --- config location /re { content_by_lua ' - local m = ngx.re.match("hello, 1234", "([a-z]+).*?([0-9]{2})[0-9]+", "o") + m = ngx.re.match("hello, 1234", "([a-z]+).*?([0-9]{2})[0-9]+", "o") if m then ngx.say(m[0]) ngx.say(m[1]) @@ -168,7 +168,7 @@ hello --- config location /re { content_by_lua ' - local m = ngx.re.match("hello, 1234", "foo") + m = ngx.re.match("hello, 1234", "foo") if m then ngx.say(m[0]) else @@ -187,7 +187,7 @@ not matched: nil --- config location /re { content_by_lua ' - local m = ngx.re.match("hello, 1234", "HELLO") + m = ngx.re.match("hello, 1234", "HELLO") if m then ngx.say(m[0]) else @@ -206,7 +206,7 @@ not matched: nil --- config location /re { content_by_lua ' - local m = ngx.re.match("hello, 1234", "HELLO", "i") + m = ngx.re.match("hello, 1234", "HELLO", "i") if m then ngx.say(m[0]) else @@ -225,7 +225,7 @@ hello --- config location /re { content_by_lua ' - local rc, err = pcall(ngx.re.match, "hello章亦春", "HELLO.{2}", "iu") + rc, err = pcall(ngx.re.match, "hello章亦春", "HELLO.{2}", "iu") if not rc then ngx.say("FAIL: ", err) return @@ -249,7 +249,7 @@ hello --- config location /re { content_by_lua ' - local m = ngx.re.match("hello\\nworld", "^world", "m") + m = ngx.re.match("hello\\nworld", "^world", "m") if m then ngx.say(m[0]) else @@ -268,7 +268,7 @@ world --- config location /re { content_by_lua ' - local m = ngx.re.match("hello\\nworld", ".*", "m") + m = ngx.re.match("hello\\nworld", ".*", "m") if m then ngx.say(m[0]) else @@ -287,7 +287,7 @@ hello --- config location /re { content_by_lua ' - local m = ngx.re.match("hello\\nworld", "^world", "s") + m = ngx.re.match("hello\\nworld", "^world", "s") if m then ngx.say(m[0]) else @@ -306,7 +306,7 @@ not matched: nil --- config location /re { content_by_lua ' - local m = ngx.re.match("hello\\nworld", ".*", "s") + m = ngx.re.match("hello\\nworld", ".*", "s") if m then ngx.say(m[0]) else @@ -326,7 +326,7 @@ world --- config location /re { content_by_lua ' - local m = ngx.re.match("hello\\nworld", "\\\\w \\\\w", "x") + m = ngx.re.match("hello\\nworld", "\\\\w \\\\w", "x") if m then ngx.say(m[0]) else @@ -372,7 +372,7 @@ error: pcre_compile() failed: missing ) in "(abc" --- config location /re { content_by_lua ' - local rc, m = pcall(ngx.re.match, "hello\\nworld", ".*", "Hm") + rc, m = pcall(ngx.re.match, "hello\\nworld", ".*", "Hm") if rc then if m then ngx.say(m[0]) @@ -395,7 +395,7 @@ error: .*?unknown flag "H" \(flags "Hm"\) --- config location /re { content_by_lua ' - local m = ngx.re.match("hello, world", "(world)|(hello)", "x") + m = ngx.re.match("hello, world", "(world)|(hello)", "x") if m then ngx.say(m[0]) ngx.say(m[1]) @@ -418,7 +418,7 @@ hello --- config location /re { content_by_lua ' - local m = ngx.re.match("hello, 1234", "([0-9]+)(h?)") + m = ngx.re.match("hello, 1234", "([0-9]+)(h?)") if m then ngx.say(m[0]) ngx.say(m[1]) @@ -442,7 +442,7 @@ hello --- config location /re { content_by_lua ' - local m = ngx.re.match("hello, 1234", "([0-9]+)", "a") + m = ngx.re.match("hello, 1234", "([0-9]+)", "a") if m then ngx.say(m[0]) else @@ -461,7 +461,7 @@ not matched! --- config location /re { content_by_lua ' - local m = ngx.re.match("1234, hello", "([0-9]+)", "a") + m = ngx.re.match("1234, hello", "([0-9]+)", "a") if m then ngx.say(m[0]) else @@ -481,7 +481,7 @@ not matched! location /re { content_by_lua ' local ctx = {} - local m = ngx.re.match("1234, hello", "([0-9]+)", "", ctx) + m = ngx.re.match("1234, hello", "([0-9]+)", "", ctx) if m then ngx.say(m[0]) ngx.say(ctx.pos) @@ -504,7 +504,7 @@ not matched! location /re { content_by_lua ' local ctx = { pos = 3 } - local m = ngx.re.match("1234, hello", "([0-9]+)", "", ctx) + m = ngx.re.match("1234, hello", "([0-9]+)", "", ctx) if m then ngx.say(m[0]) ngx.say(ctx.pos) @@ -526,7 +526,7 @@ not matched! --- config location /re { set_by_lua $res ' - local m = ngx.re.match("hello, 1234", "([0-9]+)") + m = ngx.re.match("hello, 1234", "([0-9]+)") if m then return m[0] else @@ -569,7 +569,7 @@ baz } --- user_files >>> a.lua -local m = ngx.re.match("hello, 1234", "(\\\s+)") +m = ngx.re.match("hello, 1234", "(\\\s+)") if m then ngx.say("[", m[0], "]") else @@ -595,7 +595,7 @@ end local uri = "2" local regex = '(?:>[\\w\\s]*)'; ngx.say("regex: ", regex) -local m = ngx.re.match(uri, regex, "oi") +m = ngx.re.match(uri, regex, "oi") if m then ngx.say("[", m[0], "]") else @@ -613,7 +613,7 @@ regex: (?:>[\w\s]*) --- config location /re { content_by_lua ' - local m = ngx.re.match("hello, 1234", [[\\d+]]) + m = ngx.re.match("hello, 1234", [[\\d+]]) if m then ngx.say(m[0]) else @@ -660,7 +660,7 @@ error: pcre_compile() failed: missing ) in "([0-9]+" --- config location /re { content_by_lua ' - local m = ngx.re.match("hello, 1234", [[([0-9]+)]]) + m = ngx.re.match("hello, 1234", [[([0-9]+)]]) if m then ngx.say(m[0]) else @@ -1027,7 +1027,7 @@ exec opts: 0 >>> a.lua local re = [==[(?i:([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:=|<=>|r?like|sounds\s+like|regexp)([\s'\"`´’‘\(\)]*)?\2|([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp)([\s'\"`´’‘\(\)]*)?(?!\6)([\d\w]+))]==] -local s = string.rep([[ABCDEFG]], 10) +s = string.rep([[ABCDEFG]], 10) local start = ngx.now() @@ -1067,7 +1067,7 @@ error: pcre_exec() failed: -8 >>> a.lua local re = [==[(?i:([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:=|<=>|r?like|sounds\s+like|regexp)([\s'\"`´’‘\(\)]*)?\2|([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp)([\s'\"`´’‘\(\)]*)?(?!\6)([\d\w]+))]==] -local s = string.rep([[ABCDEFG]], 10) +s = string.rep([[ABCDEFG]], 10) local start = ngx.now() @@ -1101,7 +1101,7 @@ failed to match content_by_lua ' local res = {} local s = "hello, 1234" - local m = ngx.re.match(s, [[(\\d)(\\d)]], "o", nil, res) + m = ngx.re.match(s, [[(\\d)(\\d)]], "o", nil, res) if m then ngx.say("1: m size: ", #m) ngx.say("1: res size: ", #res) @@ -1132,12 +1132,11 @@ failed to match === TEST 48: init_by_lua --- http_config init_by_lua ' - package.loaded.m = ngx.re.match("hello, 1234", "(\\\\d+)") + m = ngx.re.match("hello, 1234", "(\\\\d+)") '; --- config location /re { content_by_lua ' - local m = package.loaded.m if m then ngx.say(m[0]) else diff --git a/debian/modules/http-lua/t/035-gmatch.t b/debian/modules/http-lua/t/035-gmatch.t index 0dfeaea..0426997 100644 --- a/debian/modules/http-lua/t/035-gmatch.t +++ b/debian/modules/http-lua/t/035-gmatch.t @@ -123,7 +123,7 @@ nil --- config location /re { content_by_lua ' - local it = ngx.re.gmatch("hello, 1234", "([0-9]+)", "a") + it = ngx.re.gmatch("hello, 1234", "([0-9]+)", "a") ngx.say(it()) '; } @@ -418,7 +418,7 @@ hello content_by_lua ' local a = {} for i = 1, 3 do - local it = ngx.re.gmatch("hello, world", "[a-z]+") + it = ngx.re.gmatch("hello, world", "[a-z]+") it() collectgarbage() table.insert(a, {"hello", "world"}) @@ -482,9 +482,9 @@ end GET /main --- response_body matched -matched ---- no_error_log -[error] +sr failed: 500 +--- error_log +attempt to use ngx.re.gmatch iterator in a request that did not create it @@ -518,7 +518,7 @@ matched: [] location /re { content_by_lua ' local it = ngx.re.gmatch("1234, 1234", "(?[0-9]+)") - local m = it() + m = it() if m then ngx.say(m[0]) ngx.say(m[1]) @@ -555,7 +555,7 @@ matched: [] content_by_lua ' local it = ngx.re.gmatch("1234, abcd, 1234", "(?[0-9]+)|(?[a-z]+)") - local m = it() + m = it() if m then ngx.say(m[0]) ngx.say(m[1]) @@ -599,7 +599,7 @@ abcd location /re { content_by_lua ' local it = ngx.re.gmatch("hello, 1234", "(?[a-z]+), (?[0-9]+)", "D") - local m = it() + m = it() if m then ngx.say(m[0]) ngx.say(m[1]) @@ -825,7 +825,7 @@ exec opts: 0 >>> a.lua local re = [==[(?i:([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:=|<=>|r?like|sounds\s+like|regexp)([\s'\"`´’‘\(\)]*)?\2|([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp)([\s'\"`´’‘\(\)]*)?(?!\6)([\d\w]+))]==] -local s = string.rep([[ABCDEFG]], 10) +s = string.rep([[ABCDEFG]], 10) local start = ngx.now() @@ -871,7 +871,7 @@ error: pcre_exec() failed: -8 >>> a.lua local re = [==[(?i:([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:=|<=>|r?like|sounds\s+like|regexp)([\s'\"`´’‘\(\)]*)?\2|([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp)([\s'\"`´’‘\(\)]*)?(?!\6)([\d\w]+))]==] -local s = string.rep([[ABCDEFG]], 10) +s = string.rep([[ABCDEFG]], 10) local start = ngx.now() @@ -881,7 +881,7 @@ if not it then return end -local res, err = it() +res, err = it() --[[ ngx.update_time() diff --git a/debian/modules/http-lua/t/036-sub.t b/debian/modules/http-lua/t/036-sub.t index 3e88eba..2b4b075 100644 --- a/debian/modules/http-lua/t/036-sub.t +++ b/debian/modules/http-lua/t/036-sub.t @@ -590,7 +590,7 @@ s: a好 >>> a.lua local re = [==[(?i:([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:=|<=>|r?like|sounds\s+like|regexp)([\s'\"`´’‘\(\)]*)?\2|([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp)([\s'\"`´’‘\(\)]*)?(?!\6)([\d\w]+))]==] -local s = string.rep([[ABCDEFG]], 10) +s = string.rep([[ABCDEFG]], 10) local start = ngx.now() @@ -693,7 +693,7 @@ ab.cd location = /t { content_by_lua ' - local function test() + function test() local data = [[ OUTER {FIRST} ]] diff --git a/debian/modules/http-lua/t/037-gsub.t b/debian/modules/http-lua/t/037-gsub.t index 41f86ac..4c5810d 100644 --- a/debian/modules/http-lua/t/037-gsub.t +++ b/debian/modules/http-lua/t/037-gsub.t @@ -511,7 +511,7 @@ s: aa >>> a.lua local re = [==[(?i:([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:=|<=>|r?like|sounds\s+like|regexp)([\s'\"`´’‘\(\)]*)?\2|([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp)([\s'\"`´’‘\(\)]*)?(?!\6)([\d\w]+))]==] -local s = string.rep([[ABCDEFG]], 10) +s = string.rep([[ABCDEFG]], 10) local start = ngx.now() diff --git a/debian/modules/http-lua/t/038-match-o.t b/debian/modules/http-lua/t/038-match-o.t index f6ae010..d61ff1f 100644 --- a/debian/modules/http-lua/t/038-match-o.t +++ b/debian/modules/http-lua/t/038-match-o.t @@ -20,7 +20,7 @@ __DATA__ --- config location /re { content_by_lua ' - local m = ngx.re.match("hello, 1234", "([0-9]+)", "o") + m = ngx.re.match("hello, 1234", "([0-9]+)", "o") if m then ngx.say(m[0]) else @@ -39,7 +39,7 @@ __DATA__ --- config location /re { content_by_lua ' - local m = ngx.re.match("hello, 1234", "(\\\\d+)", "o") + m = ngx.re.match("hello, 1234", "(\\\\d+)", "o") if m then ngx.say(m[0]) else @@ -58,7 +58,7 @@ __DATA__ --- config location /re { content_by_lua ' - local m = ngx.re.match("hello, 1234", "(\\d+)", "o") + m = ngx.re.match("hello, 1234", "(\\d+)", "o") if m then ngx.say(m[0]) else @@ -79,7 +79,7 @@ __DATA__ --- config location /re { content_by_lua ' - local m = ngx.re.match("hello, 1234", "[[\\d+]]", "o") + m = ngx.re.match("hello, 1234", "[[\\d+]]", "o") if m then ngx.say(m[0]) else @@ -100,7 +100,7 @@ __DATA__ --- config location /re { content_by_lua ' - local m = ngx.re.match("hello, 1234", "([0-9]{2})[0-9]+", "o") + m = ngx.re.match("hello, 1234", "([0-9]{2})[0-9]+", "o") if m then ngx.say(m[0]) ngx.say(m[1]) @@ -121,7 +121,7 @@ __DATA__ --- config location /re { content_by_lua ' - local m = ngx.re.match("hello, 1234", "([a-z]+).*?([0-9]{2})[0-9]+", "o") + m = ngx.re.match("hello, 1234", "([a-z]+).*?([0-9]{2})[0-9]+", "o") if m then ngx.say(m[0]) ngx.say(m[1]) @@ -144,7 +144,7 @@ hello --- config location /re { content_by_lua ' - local m = ngx.re.match("hello, 1234", "foo", "o") + m = ngx.re.match("hello, 1234", "foo", "o") if m then ngx.say(m[0]) else @@ -163,7 +163,7 @@ not matched: nil --- config location /re { content_by_lua ' - local m = ngx.re.match("hello, 1234", "HELLO", "o") + m = ngx.re.match("hello, 1234", "HELLO", "o") if m then ngx.say(m[0]) else @@ -182,7 +182,7 @@ not matched: nil --- config location /re { content_by_lua ' - local m = ngx.re.match("hello, 1234", "HELLO", "oi") + m = ngx.re.match("hello, 1234", "HELLO", "oi") if m then ngx.say(m[0]) else @@ -224,7 +224,7 @@ this version of PCRE is not compiled with PCRE_UTF8 support|^hello章亦$ --- config location /re { content_by_lua ' - local m = ngx.re.match("hello\\nworld", "^world", "mo") + m = ngx.re.match("hello\\nworld", "^world", "mo") if m then ngx.say(m[0]) else @@ -243,7 +243,7 @@ world --- config location /re { content_by_lua ' - local m = ngx.re.match("hello\\nworld", ".*", "om") + m = ngx.re.match("hello\\nworld", ".*", "om") if m then ngx.say(m[0]) else @@ -262,7 +262,7 @@ hello --- config location /re { content_by_lua ' - local m = ngx.re.match("hello\\nworld", "^world", "so") + m = ngx.re.match("hello\\nworld", "^world", "so") if m then ngx.say(m[0]) else @@ -281,7 +281,7 @@ not matched: nil --- config location /re { content_by_lua ' - local m = ngx.re.match("hello\\nworld", ".*", "os") + m = ngx.re.match("hello\\nworld", ".*", "os") if m then ngx.say(m[0]) else @@ -301,7 +301,7 @@ world --- config location /re { content_by_lua ' - local m = ngx.re.match("hello\\nworld", "\\\\w \\\\w", "xo") + m = ngx.re.match("hello\\nworld", "\\\\w \\\\w", "xo") if m then ngx.say(m[0]) else @@ -347,7 +347,7 @@ error: pcre_compile() failed: missing ) in "(abc" --- config location /re { content_by_lua ' - local rc, m = pcall(ngx.re.match, "hello\\nworld", ".*", "Ho") + rc, m = pcall(ngx.re.match, "hello\\nworld", ".*", "Ho") if rc then if m then ngx.say(m[0]) @@ -370,7 +370,7 @@ error: pcre_compile() failed: missing ) in "(abc" --- config location /re { content_by_lua ' - local m = ngx.re.match("hello, world", "(world)|(hello)", "xo") + m = ngx.re.match("hello, world", "(world)|(hello)", "xo") if m then ngx.say(m[0]) ngx.say(m[1]) @@ -393,7 +393,7 @@ hello --- config location /re { content_by_lua ' - local m = ngx.re.match("hello, 1234", "([0-9]+)(h?)", "o") + m = ngx.re.match("hello, 1234", "([0-9]+)(h?)", "o") if m then ngx.say(m[0]) ngx.say(m[1]) @@ -417,7 +417,7 @@ hello --- config location /re { content_by_lua ' - local m = ngx.re.match("hello, 1234", "([0-9]+)", "oa") + m = ngx.re.match("hello, 1234", "([0-9]+)", "oa") if m then ngx.say(m[0]) else @@ -436,7 +436,7 @@ not matched! --- config location /re { content_by_lua ' - local m = ngx.re.match("1234, hello", "([0-9]+)", "ao") + m = ngx.re.match("1234, hello", "([0-9]+)", "ao") if m then ngx.say(m[0]) else @@ -456,7 +456,7 @@ not matched! location /re { content_by_lua ' local ctx = {} - local m = ngx.re.match("1234, hello", "([0-9]+)", "o", ctx) + m = ngx.re.match("1234, hello", "([0-9]+)", "o", ctx) if m then ngx.say(m[0]) ngx.say(ctx.pos) @@ -479,7 +479,7 @@ not matched! location /re { content_by_lua ' local ctx = { pos = 3 } - local m = ngx.re.match("1234, hello", "([0-9]+)", "o", ctx) + m = ngx.re.match("1234, hello", "([0-9]+)", "o", ctx) if m then ngx.say(m[0]) ngx.say(ctx.pos) @@ -501,7 +501,7 @@ not matched! --- config location /re { set_by_lua $res ' - local m = ngx.re.match("hello, 1234", "([0-9]+)", "o") + m = ngx.re.match("hello, 1234", "([0-9]+)", "o") if m then return m[0] else diff --git a/debian/modules/http-lua/t/041-header-filter.t b/debian/modules/http-lua/t/041-header-filter.t index 0adc699..7d8ee74 100644 --- a/debian/modules/http-lua/t/041-header-filter.t +++ b/debian/modules/http-lua/t/041-header-filter.t @@ -10,7 +10,7 @@ log_level('debug'); repeat_each(2); -plan tests => repeat_each() * (blocks() * 2 + 13); +plan tests => repeat_each() * 94; #no_diff(); #no_long_string(); @@ -416,7 +416,7 @@ lua release ngx.ctx -=== TEST 20: globals are shared by all requests +=== TEST 20: global got cleared for each single request --- config location /lua { set $foo ''; @@ -428,7 +428,6 @@ lua release ngx.ctx if not foo then foo = 1 else - ngx.log(ngx.INFO, "old foo: ", foo) foo = foo + 1 end ngx.var.foo = foo @@ -436,13 +435,10 @@ lua release ngx.ctx } --- request GET /lua ---- response_body_like -^[12]$ +--- response_body +1 --- no_error_log [error] ---- grep_error_log eval: qr/old foo: \d+/ ---- grep_error_log_out eval -["", "old foo: 1\n"] @@ -734,8 +730,7 @@ hello world --- config location /t { header_filter_by_lua ' - local bar - local function foo() + function foo() bar() end diff --git a/debian/modules/http-lua/t/043-shdict.t b/debian/modules/http-lua/t/043-shdict.t index b0528e5..9183bf5 100644 --- a/debian/modules/http-lua/t/043-shdict.t +++ b/debian/modules/http-lua/t/043-shdict.t @@ -420,7 +420,7 @@ ngx_slab_alloc() failed: no memory in lua_shared_dict zone ngx.say(dogs:get(key)) key = string.rep("a", 65536) - local ok, err = dogs:set(key, "world") + ok, err = dogs:set(key, "world") if not ok then ngx.say("not ok: ", err) return @@ -2048,7 +2048,7 @@ get_stale ok: false, stale: false ngx.say("get not ok: ", err) return end - local flags = err + flags = err ngx.say("get_stale ok: ", data, ", flags: ", flags, ", stale: ", stale) diff --git a/debian/modules/http-lua/t/047-match-jit.t b/debian/modules/http-lua/t/047-match-jit.t index f53a408..2417a63 100644 --- a/debian/modules/http-lua/t/047-match-jit.t +++ b/debian/modules/http-lua/t/047-match-jit.t @@ -20,7 +20,7 @@ __DATA__ --- config location /re { content_by_lua ' - local m = ngx.re.match("hello, 1234", "([0-9]+)", "j") + m = ngx.re.match("hello, 1234", "([0-9]+)", "j") if m then ngx.say(m[0]) else @@ -41,7 +41,7 @@ pcre JIT compiling result: 1 --- config location /re { content_by_lua ' - local m = ngx.re.match("hello, world", "([0-9]+)", "j") + m = ngx.re.match("hello, world", "([0-9]+)", "j") if m then ngx.say(m[0]) else @@ -62,7 +62,7 @@ pcre JIT compiling result: 1 --- config location /re { content_by_lua ' - local m = ngx.re.match("hello, 1234", "([0-9]+)", "jo") + m = ngx.re.match("hello, 1234", "([0-9]+)", "jo") if m then ngx.say(m[0]) else @@ -87,7 +87,7 @@ qr/pcre JIT compiling result: \d+/ --- config location /re { content_by_lua ' - local m = ngx.re.match("hello, world", "([0-9]+)", "jo") + m = ngx.re.match("hello, world", "([0-9]+)", "jo") if m then ngx.say(m[0]) else @@ -147,7 +147,7 @@ error: pcre_compile() failed: missing ) in "(abc" >>> a.lua local re = [==[(?i:([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:=|<=>|r?like|sounds\s+like|regexp)([\s'\"`´’‘\(\)]*)?\2|([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp)([\s'\"`´’‘\(\)]*)?(?!\6)([\d\w]+))]==] -local s = string.rep([[ABCDEFG]], 21) +s = string.rep([[ABCDEFG]], 21) local start = ngx.now() @@ -187,7 +187,7 @@ error: pcre_exec() failed: -8 >>> a.lua local re = [==[(?i:([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:=|<=>|r?like|sounds\s+like|regexp)([\s'\"`´’‘\(\)]*)?\2|([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp)([\s'\"`´’‘\(\)]*)?(?!\6)([\d\w]+))]==] -local s = string.rep([[ABCDEFG]], 21) +s = string.rep([[ABCDEFG]], 21) local start = ngx.now() diff --git a/debian/modules/http-lua/t/048-match-dfa.t b/debian/modules/http-lua/t/048-match-dfa.t index edf3662..28b5a60 100644 --- a/debian/modules/http-lua/t/048-match-dfa.t +++ b/debian/modules/http-lua/t/048-match-dfa.t @@ -20,7 +20,7 @@ __DATA__ --- config location /re { content_by_lua ' - local m = ngx.re.match("hello", "(he|hell)", "d") + m = ngx.re.match("hello", "(he|hell)", "d") if m then ngx.say(m[0]) ngx.say(m[1]) @@ -43,7 +43,7 @@ nil --- config location /re { content_by_lua ' - local m = ngx.re.match("hello", "(he|hell)", "do") + m = ngx.re.match("hello", "(he|hell)", "do") if m then ngx.say(m[0]) ngx.say(m[1]) @@ -66,7 +66,7 @@ nil --- config location /re { content_by_lua ' - local m = ngx.re.match("hello", "(he|hell)", "jd") + m = ngx.re.match("hello", "(he|hell)", "jd") if m then ngx.say(m[0]) else @@ -85,7 +85,7 @@ hell --- config location /re { content_by_lua ' - local m = ngx.re.match("world", "(he|hell)", "d") + m = ngx.re.match("world", "(he|hell)", "d") if m then ngx.say(m[0]) else @@ -104,7 +104,7 @@ not matched! --- config location /re { content_by_lua ' - local m = ngx.re.match("hello", "he|hell", "do") + m = ngx.re.match("hello", "he|hell", "do") if m then ngx.say(m[0]) ngx.say(m[1]) @@ -127,7 +127,7 @@ nil --- config location /re { content_by_lua ' - local m = ngx.re.match("world", "([0-9]+)", "do") + m = ngx.re.match("world", "([0-9]+)", "do") if m then ngx.say(m[0]) else diff --git a/debian/modules/http-lua/t/055-subreq-vars.t b/debian/modules/http-lua/t/055-subreq-vars.t index 1369992..eb5e24d 100644 --- a/debian/modules/http-lua/t/055-subreq-vars.t +++ b/debian/modules/http-lua/t/055-subreq-vars.t @@ -28,7 +28,7 @@ __DATA__ location /lua { content_by_lua ' - local res = ngx.location.capture("/other", + res = ngx.location.capture("/other", { vars = { dog = "hello", cat = 32 }}); ngx.print(res.body) @@ -82,7 +82,7 @@ qr/variable "(dog|cat)" cannot be assigned a value \(maybe you forgot to define location /lua { set $dog ''; content_by_lua ' - local res = ngx.location.capture("/other", + res = ngx.location.capture("/other", { vars = { dog = "hello", cat = 32 }}); ngx.print(res.body) @@ -110,7 +110,7 @@ variable "cat" cannot be assigned a value (maybe you forgot to define it first?) set $dog ''; set $cat ''; content_by_lua ' - local res = ngx.location.capture("/other", + res = ngx.location.capture("/other", { vars = { dog = "hello", cat = 32 }}); ngx.print(res.body) @@ -137,7 +137,7 @@ cat = 32 set $dog ''; set $cat ''; content_by_lua ' - local res = ngx.location.capture("/other", + res = ngx.location.capture("/other", { vars = "hello" }); ngx.print(res.body) @@ -165,7 +165,7 @@ Bad vars option value set $dog ''; set $cat ''; content_by_lua ' - local res = ngx.location.capture("/other", + res = ngx.location.capture("/other", { vars = { cat = true } }); ngx.print(res.body) @@ -188,7 +188,7 @@ attempt to use bad variable value type boolean location /lua { content_by_lua ' - local res = ngx.location.capture("/other", + res = ngx.location.capture("/other", { vars = { args = "a=hello&b=32" }}); ngx.print(res.body) @@ -234,7 +234,7 @@ variable "query_string" not changeable location /lua { set $dog 'hello'; content_by_lua ' - local res = ngx.location.capture("/other", + res = ngx.location.capture("/other", { copy_all_vars = true }); ngx.print(res.body) @@ -259,7 +259,7 @@ GET /lua location /lua { set $dog 'hello'; content_by_lua ' - local res = ngx.location.capture("/other", + res = ngx.location.capture("/other", { share_all_vars = true }); ngx.print(res.body) @@ -284,7 +284,7 @@ GET /lua location /lua { set $dog 'hello'; content_by_lua ' - local res = ngx.location.capture("/other", + res = ngx.location.capture("/other", { vars = { dog = "hiya" }, copy_all_vars = true }); ngx.print(res.body) diff --git a/debian/modules/http-lua/t/056-flush.t b/debian/modules/http-lua/t/056-flush.t index bdd33d4..6b697a4 100644 --- a/debian/modules/http-lua/t/056-flush.t +++ b/debian/modules/http-lua/t/056-flush.t @@ -317,7 +317,7 @@ lua http 1.0 buffering makes ngx.flush() a no-op --- config location /test { content_by_lua ' - local function f() + function f() ngx.say("hello, world") ngx.flush(true) coroutine.yield() diff --git a/debian/modules/http-lua/t/057-flush-timeout.t b/debian/modules/http-lua/t/057-flush-timeout.t index 1f8cfaa..a046539 100644 --- a/debian/modules/http-lua/t/057-flush-timeout.t +++ b/debian/modules/http-lua/t/057-flush-timeout.t @@ -127,7 +127,7 @@ del timer 1234 send_timeout 200ms; location /lua { content_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) diff --git a/debian/modules/http-lua/t/058-tcp-socket.t b/debian/modules/http-lua/t/058-tcp-socket.t index 837006c..354a876 100644 --- a/debian/modules/http-lua/t/058-tcp-socket.t +++ b/debian/modules/http-lua/t/058-tcp-socket.t @@ -4,7 +4,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * 219; +plan tests => repeat_each() * 199; our $HtmlDir = html_dir; @@ -245,11 +245,11 @@ attempt to send data on a closed socket: --- request GET /t ---- response_body_like +--- response_body connected: 1 request sent: 56 -first line received: HTTP\/1\.1 200 OK -second line received: (?:Date|Server): .*? +first line received: HTTP/1.1 200 OK +second line received: Server: openresty --- no_error_log [error] --- timeout: 10 @@ -298,7 +298,7 @@ qr/connect\(\) failed \(\d+: Connection refused\)/ location /test { content_by_lua ' local sock = ngx.socket.tcp() - local ok, err = sock:connect("127.0.0.2", 12345) + local ok, err = sock:connect("agentzh.org", 12345) ngx.say("connect: ", ok, " ", err) local bytes @@ -321,7 +321,7 @@ send: nil closed receive: nil closed close: nil closed --- error_log -lua tcp socket connect timed out, when connecting to 127.0.0.2:12345 +lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 --- timeout: 10 @@ -914,7 +914,7 @@ close: 1 nil end end - local ok, err = sock:close() + ok, err = sock:close() ngx.say("close: ", ok, " ", err) '; } @@ -961,7 +961,7 @@ close: 1 nil line, err = sock:receive() ngx.say("receive: ", line, " ", err) - local ok, err = sock:close() + ok, err = sock:close() ngx.say("close: ", ok, " ", err) '; } @@ -1057,7 +1057,7 @@ close: 1 nil === TEST 19: cannot survive across request boundary (send) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config server_tokens off; location /t { @@ -1116,7 +1116,7 @@ received: OK|failed to send request: closed)\$" === TEST 20: cannot survive across request boundary (receive) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config server_tokens off; location /t { @@ -1191,7 +1191,7 @@ received: OK|failed to receive a line: closed \[nil\])$/ === TEST 21: cannot survive across request boundary (close) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config server_tokens off; location /t { @@ -1260,7 +1260,7 @@ received: OK|failed to close: closed)$/ === TEST 22: cannot survive across request boundary (connect) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config server_tokens off; location /t { @@ -2611,7 +2611,7 @@ close: 1 nil local ready = false local fatal = false - local function f() + function f() local line, err, part = sock:receive() if not line then ngx.say("failed to receive the 1st line: ", err, " [", part, "]") @@ -2672,7 +2672,7 @@ lua clean up the timer for pending ngx.sleep === TEST 44: bad request tries to connect --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config server_tokens off; location = /main { @@ -2726,7 +2726,7 @@ qr/runtime error: content_by_lua\(nginx\.conf:\d+\):7: bad request/ === TEST 45: bad request tries to receive --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config server_tokens off; location = /main { @@ -2783,7 +2783,7 @@ qr/runtime error: content_by_lua\(nginx\.conf:\d+\):14: bad request/ === TEST 46: bad request tries to send --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config server_tokens off; location = /main { @@ -2840,7 +2840,7 @@ qr/runtime error: content_by_lua\(nginx\.conf:\d+\):14: bad request/ === TEST 47: bad request tries to close --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config server_tokens off; location = /main { @@ -2897,7 +2897,7 @@ qr/runtime error: content_by_lua\(nginx\.conf:\d+\):14: bad request/ === TEST 48: bad request tries to set keepalive --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config server_tokens off; location = /main { @@ -2954,7 +2954,7 @@ qr/runtime error: content_by_lua\(nginx\.conf:\d+\):14: bad request/ === TEST 49: bad request tries to receiveuntil --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config server_tokens off; location = /main { @@ -3315,7 +3315,7 @@ close: 1 nil local thr = ngx.thread.spawn(function () sock = ngx.socket.tcp() - local ok, err = sock:connect("127.0.0.2", 12345) + local ok, err = sock:connect("agentzh.org", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -3464,7 +3464,7 @@ lua http cleanup reuse ngx.say("failed to create timer: ", err) end - local i = 1 + i = 1 while not done do local time = 0.005 * i if time > 0.1 then @@ -3545,7 +3545,7 @@ lua http cleanup reuse ngx.say("failed to create timer: ", err) end - local i = 1 + i = 1 while not done do local time = 0.005 * i if time > 0.1 then @@ -3720,10 +3720,10 @@ sudo iptables -I OUTPUT 1 -p udp --dport 10086 -j REJECT } --- request GET /t ---- response_body_like -failed to connect: www.google.com could not be resolved(?: \(\d+: Operation timed out\))? -failed to connect: www.google.com could not be resolved(?: \(\d+: Operation timed out\))? -failed to connect: www.google.com could not be resolved(?: \(\d+: Operation timed out\))? +--- response_body +failed to connect: www.google.com could not be resolved +failed to connect: www.google.com could not be resolved +failed to connect: www.google.com could not be resolved hello! --- error_log eval qr{\[alert\] .*? send\(\) failed \(\d+: Operation not permitted\) while resolving} @@ -3808,315 +3808,3 @@ received: received: truefalsenil --- no_error_log [error] - - - -=== TEST 64: receiveany method in cosocket ---- config - server_tokens off; - location = /t { - set $port $TEST_NGINX_SERVER_PORT; - content_by_lua_block { - local sock = ngx.socket.tcp() - sock:settimeout(500) - assert(sock:connect("127.0.0.1", ngx.var.port)) - local req = { - 'GET /foo HTTP/1.0\r\n', - 'Host: localhost\r\n', - 'Connection: close\r\n\r\n', - } - local ok, err = sock:send(req) - if not ok then - ngx.say("send request failed: ", err) - return - end - - -- skip http header - while true do - local data, err, _ = sock:receive('*l') - if err then - ngx.say('unexpected error occurs when receiving http head: ', err) - return - end - - if #data == 0 then -- read last line of head - break - end - end - - -- receive http body - while true do - local data, err = sock:receiveany(1024) - if err then - if err ~= 'closed' then - ngx.say('unexpected err: ', err) - end - break - end - ngx.say(data) - end - - sock:close() - } - } - - location = /foo { - content_by_lua_block { - local resp = { - '1', - '22', - 'hello world', - } - - local length = 0 - for _, v in ipairs(resp) do - length = length + #v - end - - -- flush http header - ngx.header['Content-Length'] = length - ngx.flush(true) - ngx.sleep(0.01) - - -- send http body - for _, v in ipairs(resp) do - ngx.print(v) - ngx.flush(true) - ngx.sleep(0.01) - end - } - } - ---- request -GET /t ---- response_body -1 -22 -hello world ---- no_error_log -[error] ---- error_log -lua tcp socket read any - - - -=== TEST 65: receiveany send data after read side closed ---- config - server_tokens off; - location = /t { - content_by_lua_block { - local sock = ngx.socket.tcp() - sock:settimeout(500) - assert(sock:connect("127.0.0.1", 7658)) - - while true do - local data, err = sock:receiveany(1024) - if err then - if err ~= 'closed' then - ngx.say('unexpected err: ', err) - break - end - - local data = "send data after read side closed" - local bytes, err = sock:send(data) - if not bytes then - ngx.say(err) - end - - break - end - ngx.say(data) - end - - sock:close() - } - } - ---- request -GET /t ---- tcp_listen: 7658 ---- tcp_shutdown: 1 ---- tcp_query eval: "send data after read side closed" ---- tcp_query_len: 32 ---- response_body ---- no_error_log -[error] - - - -=== TEST 66: receiveany with limited, max <= 0 ---- config - location = /t { - set $port $TEST_NGINX_SERVER_PORT; - content_by_lua_block { - local sock = ngx.socket.tcp() - sock:settimeout(500) - assert(sock:connect("127.0.0.1", ngx.var.port)) - - local function receiveany_say_err(...) - local ok, err = pcall(sock.receiveany, sock, ...) - if not ok then - ngx.say(err) - end - end - - - receiveany_say_err(0) - receiveany_say_err(-1) - receiveany_say_err() - receiveany_say_err(nil) - } - } - ---- response_body -bad argument #2 to '?' (bad max argument) -bad argument #2 to '?' (bad max argument) -expecting 2 arguments (including the object), but got 1 -bad argument #2 to '?' (bad max argument) ---- request -GET /t ---- no_error_log -[error] - - - -=== TEST 67: receiveany with limited, max is larger than data ---- config - server_tokens off; - location = /t { - set $port $TEST_NGINX_SERVER_PORT; - content_by_lua_block { - local sock = ngx.socket.tcp() - sock:settimeout(500) - assert(sock:connect("127.0.0.1", ngx.var.port)) - local req = { - 'GET /foo HTTP/1.0\r\n', - 'Host: localhost\r\n', - 'Connection: close\r\n\r\n', - } - local ok, err = sock:send(req) - if not ok then - ngx.say("send request failed: ", err) - return - end - - while true do - local data, err, _ = sock:receive('*l') - if err then - ngx.say('unexpected error occurs when receiving http head: ', err) - return - end - - if #data == 0 then -- read last line of head - break - end - end - - local data, err = sock:receiveany(128) - if err then - if err ~= 'closed' then - ngx.say('unexpected err: ', err) - end - else - ngx.say(data) - end - - sock:close() - } - } - - location = /foo { - content_by_lua_block { - local resp = 'hello world' - local length = #resp - - ngx.header['Content-Length'] = length - ngx.flush(true) - ngx.sleep(0.01) - - ngx.print(resp) - } - } - ---- request -GET /t ---- response_body -hello world ---- no_error_log -[error] ---- error_log -lua tcp socket calling receiveany() method to read at most 128 bytes - - - -=== TEST 68: receiveany with limited, max is smaller than data ---- config - server_tokens off; - location = /t { - set $port $TEST_NGINX_SERVER_PORT; - content_by_lua_block { - local sock = ngx.socket.tcp() - sock:settimeout(500) - assert(sock:connect("127.0.0.1", ngx.var.port)) - local req = { - 'GET /foo HTTP/1.0\r\n', - 'Host: localhost\r\n', - 'Connection: close\r\n\r\n', - } - local ok, err = sock:send(req) - if not ok then - ngx.say("send request failed: ", err) - return - end - - while true do - local data, err, _ = sock:receive('*l') - if err then - ngx.say('unexpected error occurs when receiving http head: ', err) - return - end - - if #data == 0 then -- read last line of head - break - end - end - - while true do - local data, err = sock:receiveany(7) - if err then - if err ~= 'closed' then - ngx.say('unexpected err: ', err) - end - break - - else - ngx.say(data) - end - end - - sock:close() - } - } - - location = /foo { - content_by_lua_block { - local resp = 'hello world' - local length = #resp - - ngx.header['Content-Length'] = length - ngx.flush(true) - ngx.sleep(0.01) - - ngx.print(resp) - } - } - ---- request -GET /t ---- response_body -hello w -orld ---- no_error_log -[error] ---- error_log -lua tcp socket calling receiveany() method to read at most 7 bytes diff --git a/debian/modules/http-lua/t/062-count.t b/debian/modules/http-lua/t/062-count.t index 9b0afe8..2ad2f9f 100644 --- a/debian/modules/http-lua/t/062-count.t +++ b/debian/modules/http-lua/t/062-count.t @@ -283,7 +283,7 @@ n = 5 --- request GET /test --- response_body -n = 22 +n = 18 --- no_error_log [error] @@ -444,28 +444,7 @@ worker: 4 -=== TEST 20: entries under the metatable of tcp sockets ---- config - location = /test { - content_by_lua_block { - local n = 0 - local sock = ngx.socket.tcp() - for k, v in pairs(getmetatable(sock)) do - n = n + 1 - end - ngx.say("n = ", n) - } - } ---- request -GET /test ---- response_body -n = 13 ---- no_error_log -[error] - - - -=== TEST 21: entries under the metatable of udp sockets +=== TEST 20: entries under the metatable of udp sockets --- config location = /test { content_by_lua ' @@ -486,7 +465,7 @@ n = 6 -=== TEST 22: entries under the metatable of req raw sockets +=== TEST 21: entries under the metatable of req raw sockets --- config location = /test { content_by_lua ' @@ -518,7 +497,7 @@ n = 6 -=== TEST 23: entries under the req raw sockets +=== TEST 22: entries under the req raw sockets --- config location = /test { content_by_lua_block { @@ -557,7 +536,7 @@ nrec = 3 -=== TEST 24: entries under the req sockets +=== TEST 23: entries under the req sockets --- config location = /test { content_by_lua_block { diff --git a/debian/modules/http-lua/t/063-abort.t b/debian/modules/http-lua/t/063-abort.t index 7c90eaa..411a07e 100644 --- a/debian/modules/http-lua/t/063-abort.t +++ b/debian/modules/http-lua/t/063-abort.t @@ -22,7 +22,7 @@ __DATA__ === TEST 1: ngx.exit(400) should abort print --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /memc_query { internal; @@ -68,7 +68,7 @@ GET /test?a === TEST 2: ngx.exit(400) should abort ngx.log --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /memc_query { internal; @@ -116,7 +116,7 @@ GET /test?a === TEST 3: ngx.exit(400) should abort ngx.location.capture --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /memc_query { internal; @@ -161,7 +161,7 @@ the "$memc_key" variable is not set === TEST 4: ngx.exit(400) should abort ngx.location.capture_multi --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /memc_query { internal; @@ -206,7 +206,7 @@ the "$memc_key" variable is not set === TEST 5: ngx.exit(400) should abort ngx.redirect --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /test { content_by_lua ' @@ -233,7 +233,7 @@ lua redirect to "/blah" with code 302 === TEST 6: ngx.exit(400) should abort ngx.exit --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /test { content_by_lua ' @@ -260,7 +260,7 @@ lua exit with code 503 === TEST 7: ngx.exit(400) should abort ngx.exec --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /test { content_by_lua ' @@ -287,7 +287,7 @@ lua exec "/blah?" === TEST 8: ngx.exit(400) should abort ngx.send_headers --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /test { content_by_lua ' @@ -314,7 +314,7 @@ lua send headers === TEST 9: ngx.exit(400) should abort ngx.print --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /test { content_by_lua ' @@ -341,7 +341,7 @@ lua print response === TEST 10: ngx.exit(400) should abort ngx.say --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /test { content_by_lua ' @@ -368,7 +368,7 @@ lua say response === TEST 11: ngx.exit(400) should abort ngx.flush --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /test { content_by_lua ' @@ -395,7 +395,7 @@ lua flush asynchronously === TEST 12: ngx.exit(400) should abort ngx.eof --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /test { content_by_lua ' @@ -422,7 +422,7 @@ lua send eof === TEST 13: ngx.exit(400) should abort ngx.re.match --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /test { content_by_lua ' @@ -449,7 +449,7 @@ lua compiling match regex "a" with options "jo" === TEST 14: ngx.exit(400) should abort ngx.re.gmatch --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /test { content_by_lua ' @@ -476,7 +476,7 @@ lua compiling gmatch regex "a" with options "jo" === TEST 15: ngx.exit(400) should abort ngx.re.sub --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /test { content_by_lua ' @@ -503,7 +503,7 @@ lua compiling sub regex "a" with options "jo" === TEST 16: ngx.exit(400) should abort ngx.re.gsub --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /test { content_by_lua ' @@ -530,7 +530,7 @@ lua compiling gsub regex "a" with options "jo" === TEST 17: ngx.exit(400) should abort ngx.shared.DICT (set) --- http_config eval - "lua_shared_dict dogs 1m; lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_shared_dict dogs 1m; lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /test { content_by_lua ' @@ -560,7 +560,7 @@ foo = 56 === TEST 18: ngx.exit(400) should abort ngx.shared.DICT (replace) --- http_config eval - "lua_shared_dict dogs 1m; lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_shared_dict dogs 1m; lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /test { content_by_lua ' @@ -590,7 +590,7 @@ foo = 56 === TEST 19: ngx.exit(400) should abort ngx.shared.DICT (incr) --- http_config eval - "lua_shared_dict dogs 1m; lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_shared_dict dogs 1m; lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /test { content_by_lua ' @@ -620,7 +620,7 @@ foo = 88 === TEST 20: ngx.exit(400) should abort ngx.shared.DICT (get) --- http_config eval - "lua_shared_dict dogs 1m; lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_shared_dict dogs 1m; lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /test { content_by_lua ' @@ -649,7 +649,7 @@ fetching key "foo" in shared dict "dogs" === TEST 21: ngx.exit(400) should skip os.execute --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /test { content_by_lua ' @@ -679,7 +679,7 @@ GET /test === TEST 22: ngx.exit(400) should break pcall and skip os.execute --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /test { content_by_lua ' @@ -709,7 +709,7 @@ fetching key "foo" in shared dict "dogs" === TEST 23: ngx.exit(400) should break pcall and skip os.execute (all in user module) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /test { content_by_lua ' @@ -739,7 +739,7 @@ GET /test === TEST 24: ngx.redirect() should break pcall and skip os.execute (all in user module) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /test { content_by_lua ' @@ -769,7 +769,7 @@ GET /test === TEST 25: ngx.redirect() should skip os.execute (all in user module) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /test { content_by_lua ' @@ -799,7 +799,7 @@ GET /test === TEST 26: ngx.exec() should break pcall and skip os.execute (all in user module) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /test { content_by_lua ' @@ -832,7 +832,7 @@ foo === TEST 27: ngx.exec() should skip os.execute (all in user module) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /test { content_by_lua ' @@ -865,7 +865,7 @@ foo === TEST 28: ngx.set_uri(uri, true) should break pcall and skip os.execute (all in user module) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /test { rewrite_by_lua ' @@ -921,7 +921,7 @@ hello world === TEST 30: ngx.exit(400) should break xpcall and skip os.execute (all in user module) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /test { content_by_lua ' @@ -955,7 +955,7 @@ GET /test === TEST 31: ngx.exec() should skip os.execute (all in user module) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /test { content_by_lua ' @@ -988,7 +988,7 @@ foo === TEST 32: ngx.exec() should break pcall and skip os.execute (all in user module) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /test { content_by_lua ' diff --git a/debian/modules/http-lua/t/064-pcall.t b/debian/modules/http-lua/t/064-pcall.t index 9af2de7..3011f3e 100644 --- a/debian/modules/http-lua/t/064-pcall.t +++ b/debian/modules/http-lua/t/064-pcall.t @@ -22,11 +22,11 @@ __DATA__ === TEST 1: pcall works --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /test { content_by_lua ' - local function f(a, b) + function f(a, b) if a == 0 and b == 0 then error("zero error") end @@ -58,11 +58,11 @@ $/s === TEST 2: xpcall works --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /test { content_by_lua ' - local function f(a, b) + function f(a, b) if a == 0 and b == 0 then error("zero error") end @@ -70,15 +70,15 @@ $/s return 23, "hello", true end - local function g() + function g() return f(0, 0) end - local function h() + function h() return f(0) end - local function err(...) + function err(...) ngx.say("error handler called: ", ...) return "this is the new err" end diff --git a/debian/modules/http-lua/t/065-tcp-socket-timeout.t b/debian/modules/http-lua/t/065-tcp-socket-timeout.t index 092094a..78b8cff 100644 --- a/debian/modules/http-lua/t/065-tcp-socket-timeout.t +++ b/debian/modules/http-lua/t/065-tcp-socket-timeout.t @@ -51,7 +51,7 @@ __DATA__ location /t { content_by_lua ' local sock = ngx.socket.tcp() - local ok, err = sock:connect("127.0.0.2", 12345) + local ok, err = sock:connect("agentzh.org", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -66,7 +66,7 @@ GET /t failed to connect: timeout --- error_log lua tcp socket connect timeout: 100 -lua tcp socket connect timed out, when connecting to 127.0.0.2:12345 +lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 --- timeout: 10 @@ -81,7 +81,7 @@ lua tcp socket connect timed out, when connecting to 127.0.0.2:12345 content_by_lua ' local sock = ngx.socket.tcp() sock:settimeout(150) - local ok, err = sock:connect("127.0.0.2", 12345) + local ok, err = sock:connect("agentzh.org", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -96,7 +96,7 @@ GET /t failed to connect: timeout --- error_log lua tcp socket connect timeout: 150 -lua tcp socket connect timed out, when connecting to 127.0.0.2:12345 +lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 --- timeout: 10 @@ -110,7 +110,7 @@ lua tcp socket connect timed out, when connecting to 127.0.0.2:12345 content_by_lua ' local sock = ngx.socket.tcp() sock:settimeout(nil) - local ok, err = sock:connect("127.0.0.2", 12345) + local ok, err = sock:connect("agentzh.org", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -125,7 +125,7 @@ GET /t failed to connect: timeout --- error_log lua tcp socket connect timeout: 102 -lua tcp socket connect timed out, when connecting to 127.0.0.2:12345 +lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 @@ -139,7 +139,7 @@ lua tcp socket connect timed out, when connecting to 127.0.0.2:12345 content_by_lua ' local sock = ngx.socket.tcp() sock:settimeout(0) - local ok, err = sock:connect("127.0.0.2", 12345) + local ok, err = sock:connect("agentzh.org", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -154,7 +154,7 @@ GET /t failed to connect: timeout --- error_log lua tcp socket connect timeout: 102 -lua tcp socket connect timed out, when connecting to 127.0.0.2:12345 +lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 --- timeout: 10 @@ -168,7 +168,7 @@ lua tcp socket connect timed out, when connecting to 127.0.0.2:12345 content_by_lua ' local sock = ngx.socket.tcp() sock:settimeout(-1) - local ok, err = sock:connect("127.0.0.2", 12345) + local ok, err = sock:connect("agentzh.org", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -584,7 +584,7 @@ bad timeout value --- config location /lua { content_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -683,7 +683,7 @@ after location /t { content_by_lua ' local sock = ngx.socket.tcp() - local ok, err = sock:connect("127.0.0.2", 12345) + local ok, err = sock:connect("agentzh.org", 12345) if not ok then ngx.say("1: failed to connect: ", err) @@ -707,7 +707,7 @@ GET /t 2: connected: 1 --- error_log lua tcp socket connect timeout: 100 -lua tcp socket connect timed out, when connecting to 127.0.0.2:12345 +lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 --- timeout: 10 diff --git a/debian/modules/http-lua/t/066-socket-receiveuntil.t b/debian/modules/http-lua/t/066-socket-receiveuntil.t index 89d2abf..ffe74aa 100644 --- a/debian/modules/http-lua/t/066-socket-receiveuntil.t +++ b/debian/modules/http-lua/t/066-socket-receiveuntil.t @@ -245,7 +245,7 @@ close: 1 nil local reader = sock:receiveuntil("abcabd") for i = 1, 2 do - local line, err, part = reader() + line, err, part = reader() if line then ngx.say("read: ", line) @@ -316,7 +316,7 @@ close: 1 nil local reader = sock:receiveuntil("aa") for i = 1, 2 do - local line, err, part = reader() + line, err, part = reader() if line then ngx.say("read: ", line) @@ -387,7 +387,7 @@ close: 1 nil local reader = sock:receiveuntil("aaa") for i = 1, 2 do - local line, err, part = reader() + line, err, part = reader() if line then ngx.say("read: ", line) @@ -458,7 +458,7 @@ close: 1 nil local reader = sock:receiveuntil("aaaaad") for i = 1, 2 do - local line, err, part = reader() + line, err, part = reader() if line then ngx.say("read: ", line) @@ -530,7 +530,7 @@ close: 1 nil local reader = sock:receiveuntil("aaaaad") for i = 1, 2 do - local line, err, part = reader() + line, err, part = reader() if line then ngx.say("read: ", line) @@ -602,7 +602,7 @@ close: 1 nil local reader = sock:receiveuntil("aaaaad") for i = 1, 2 do - local line, err, part = reader() + line, err, part = reader() if line then ngx.say("read: ", line) @@ -673,7 +673,7 @@ close: 1 nil local reader = sock:receiveuntil("abcabdabcabe") for i = 1, 2 do - local line, err, part = reader() + line, err, part = reader() if line then ngx.say("read: ", line) @@ -744,7 +744,7 @@ close: 1 nil local reader = sock:receiveuntil("abcabdabcabe") for i = 1, 2 do - local line, err, part = reader() + line, err, part = reader() if line then ngx.say("read: ", line) @@ -815,7 +815,7 @@ close: 1 nil local reader = sock:receiveuntil("abcabdabcabe") for i = 1, 2 do - local line, err, part = reader() + line, err, part = reader() if line then ngx.say("read: ", line) @@ -886,7 +886,7 @@ close: 1 nil local reader = sock:receiveuntil("abcabdabcabe") for i = 1, 2 do - local line, err, part = reader() + line, err, part = reader() if line then ngx.say("read: ", line) @@ -957,7 +957,7 @@ close: 1 nil local reader = sock:receiveuntil("--abc") for i = 1, 2 do - local line, err, part = reader() + line, err, part = reader() if line then ngx.say("read: ", line) @@ -1028,7 +1028,7 @@ close: 1 nil local reader = sock:receiveuntil("--abc") for i = 1, 7 do - local line, err, part = reader(4) + line, err, part = reader(4) if line then ngx.say("read: ", line) @@ -1105,7 +1105,7 @@ close: 1 nil local reader = sock:receiveuntil("--abc") for i = 1, 7 do - local line, err, part = reader(4) + line, err, part = reader(4) if line then ngx.say("read: ", line) @@ -1182,7 +1182,7 @@ close: 1 nil local reader = sock:receiveuntil("--abc") for i = 1, 7 do - local line, err, part = reader(4) + line, err, part = reader(4) if line then ngx.say("read: ", line) @@ -1270,7 +1270,7 @@ close: 1 nil local reader = sock:receiveuntil("abcabd") for i = 1, 2 do - local line, err, part = reader() + line, err, part = reader() if line then ngx.say("read: ", line) diff --git a/debian/modules/http-lua/t/067-req-socket.t b/debian/modules/http-lua/t/067-req-socket.t index 6593360..229d5cc 100644 --- a/debian/modules/http-lua/t/067-req-socket.t +++ b/debian/modules/http-lua/t/067-req-socket.t @@ -320,7 +320,7 @@ found the end of the stream === TEST 4: attempt to use the req socket across request boundary --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location /t { content_by_lua ' @@ -369,7 +369,7 @@ hello world === TEST 5: receive until on request_body - receiveuntil(1) on the last byte of the body See https://groups.google.com/group/openresty/browse_thread/thread/43cf01da3c681aba for details --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location /t { content_by_lua ' @@ -431,7 +431,7 @@ done === TEST 6: pipelined POST requests --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location /t { content_by_lua ' diff --git a/debian/modules/http-lua/t/068-socket-keepalive.t b/debian/modules/http-lua/t/068-socket-keepalive.t index e4c6988..f052e9a 100644 --- a/debian/modules/http-lua/t/068-socket-keepalive.t +++ b/debian/modules/http-lua/t/068-socket-keepalive.t @@ -4,14 +4,13 @@ use Test::Nginx::Socket::Lua; #repeat_each(2); -plan tests => repeat_each() * (blocks() * 4 + 31); +plan tests => repeat_each() * (blocks() * 5 + 9); our $HtmlDir = html_dir; $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; $ENV{TEST_NGINX_HTML_DIR} = $HtmlDir; $ENV{TEST_NGINX_REDIS_PORT} ||= 6379; -$ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; $ENV{LUA_PATH} ||= '/usr/local/openresty-debug/lualib/?.lua;/usr/local/openresty/lualib/?.lua;;'; @@ -30,7 +29,7 @@ __DATA__ === TEST 1: sanity --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -98,7 +97,7 @@ lua tcp socket keepalive create connection pool for key "127.0.0.1:$ENV{TEST_NGI === TEST 2: free up the whole connection pool if no active connections --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -169,7 +168,7 @@ received: OK === TEST 3: upstream sockets close prematurely --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config server_tokens off; keepalive_timeout 100ms; @@ -244,7 +243,7 @@ done === TEST 4: http keepalive --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config server_tokens off; location /t { @@ -702,35 +701,7 @@ qr/lua tcp socket connection pool size: 25\b/] -=== TEST 10: setkeepalive() 'pool_size' should be greater than zero ---- config - location /t { - set $port $TEST_NGINX_MEMCACHED_PORT; - content_by_lua_block { - local sock, err = ngx.socket.connect("127.0.0.1", ngx.var.port) - if not sock then - ngx.say(err) - return - end - - local ok, err = pcall(sock.setkeepalive, sock, 0, 0) - if not ok then - ngx.say(err) - return - end - ngx.say(ok) - } - } ---- request -GET /t ---- response_body -bad argument #3 to '?' (bad "pool_size" option value: 0) ---- no_error_log -[error] - - - -=== TEST 11: sock:keepalive_timeout(0) means unlimited +=== TEST 10: sock:keepalive_timeout(0) means unlimited --- config server_tokens off; location /t { @@ -805,10 +776,10 @@ qr/lua tcp socket connection pool size: 30\b/] -=== TEST 12: sanity (uds) +=== TEST 11: sanity (uds) --- http_config eval " - lua_package_path '$::HtmlDir/?.lua;./?.lua;;'; + lua_package_path '$::HtmlDir/?.lua;./?.lua'; server { listen unix:$::HtmlDir/nginx.sock; default_type 'text/plain'; @@ -887,7 +858,7 @@ received response of 119 bytes -=== TEST 13: github issue #108: ngx.locaiton.capture + redis.set_keepalive +=== TEST 12: github issue #108: ngx.locaiton.capture + redis.set_keepalive --- http_config eval qq{ lua_package_path "$::HtmlDir/?.lua;;"; @@ -934,9 +905,9 @@ lua tcp socket get keepalive peer: using connection -=== TEST 14: github issue #110: ngx.exit with HTTP_NOT_FOUND causes worker process to exit +=== TEST 13: github issue #110: ngx.exit with HTTP_NOT_FOUND causes worker process to exit --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config error_page 404 /404.html; location /t { @@ -993,9 +964,9 @@ Not found, dear... -=== TEST 15: custom pools (different pool for the same host:port) - tcp +=== TEST 14: custom pools (different pool for the same host:port) - tcp --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -1041,9 +1012,9 @@ lua tcp socket keepalive create connection pool for key "B" -=== TEST 16: custom pools (same pool for different host:port) - tcp +=== TEST 15: custom pools (same pool for different host:port) - tcp --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -1088,10 +1059,10 @@ lua tcp socket get keepalive peer: using connection -=== TEST 17: custom pools (different pool for the same host:port) - unix +=== TEST 16: custom pools (different pool for the same host:port) - unix --- http_config eval " - lua_package_path '$::HtmlDir/?.lua;./?.lua;;'; + lua_package_path '$::HtmlDir/?.lua;./?.lua'; server { listen unix:$::HtmlDir/nginx.sock; default_type 'text/plain'; @@ -1148,10 +1119,10 @@ lua tcp socket keepalive create connection pool for key "B" -=== TEST 18: custom pools (same pool for the same path) - unix +=== TEST 17: custom pools (same pool for the same path) - unix --- http_config eval " - lua_package_path '$::HtmlDir/?.lua;./?.lua;;'; + lua_package_path '$::HtmlDir/?.lua;./?.lua'; server { listen unix:$::HtmlDir/nginx.sock; default_type 'text/plain'; @@ -1203,9 +1174,9 @@ lua tcp socket get keepalive peer: using connection -=== TEST 19: numeric pool option value +=== TEST 18: numeric pool option value --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -1250,9 +1221,9 @@ lua tcp socket get keepalive peer: using connection -=== TEST 20: nil pool option value +=== TEST 19: nil pool option value --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -1293,9 +1264,9 @@ connected: 1, reused: 0 -=== TEST 21: (bad) table pool option value +=== TEST 20: (bad) table pool option value --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -1334,9 +1305,9 @@ bad argument #3 to 'connect' (bad "pool" option type: table) -=== TEST 22: (bad) boolean pool option value +=== TEST 21: (bad) boolean pool option value --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -1375,7 +1346,7 @@ bad argument #3 to 'connect' (bad "pool" option type: boolean) -=== TEST 23: clear the redis store +=== TEST 22: clear the redis store --- config location /t { redis2_query flushall; @@ -1392,9 +1363,9 @@ bad argument #3 to 'connect' (bad "pool" option type: boolean) -=== TEST 24: bug in send(): clear the chain writer ctx +=== TEST 23: bug in send(): clear the chain writer ctx --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location /t { set $port $TEST_NGINX_REDIS_PORT; @@ -1507,7 +1478,7 @@ done -=== TEST 25: setkeepalive() with explicit nil args +=== TEST 24: setkeepalive() with explicit nil args --- config server_tokens off; location /t { @@ -1580,1379 +1551,3 @@ done "lua tcp socket keepalive timeout: 100 ms", qr/lua tcp socket connection pool size: 30\b/] --- timeout: 4 - - - -=== TEST 26: conn queuing: connect() verifies the options for connection pool ---- config - location /t { - set $port $TEST_NGINX_SERVER_PORT; - - content_by_lua_block { - local sock = ngx.socket.tcp() - local function check_opts_for_connect(opts) - local ok, err = pcall(function() - sock:connect("127.0.0.1", ngx.var.port, opts) - end) - if not ok then - ngx.say(err) - else - ngx.say("ok") - end - end - - check_opts_for_connect({pool_size = 'a'}) - check_opts_for_connect({pool_size = 0}) - check_opts_for_connect({backlog = -1}) - check_opts_for_connect({backlog = 0}) - } - } ---- request -GET /t ---- response_body_like -.+ 'connect' \(bad "pool_size" option type: string\) -.+ 'connect' \(bad "pool_size" option value: 0\) -.+ 'connect' \(bad "backlog" option value: -1\) -ok ---- no_error_log -[error] - - - -=== TEST 27: conn queuing: connect() can specify 'pool_size' which overrides setkeepalive() ---- config - location /t { - set $port $TEST_NGINX_MEMCACHED_PORT; - - content_by_lua_block { - local port = ngx.var.port - local function go() - local sock = ngx.socket.tcp() - local ok, err = sock:connect("127.0.0.1", port, {pool_size = 1}) - if not ok then - ngx.say("failed to connect: ", err) - return - end - - ngx.say("connected: ", ok, ", reused: ", sock:getreusedtimes()) - - local req = "flush_all\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 line, err, part = sock:receive() - if line then - ngx.say("received: ", line) - else - ngx.say("failed to receive a line: ", err, " [", part, "]") - end - - local ok, err = sock:setkeepalive(0, 20) - if not ok then - ngx.say("failed to set reusable: ", err) - end - end - - -- reuse ok - go() - go() - - local sock1 = ngx.socket.connect("127.0.0.1", port) - local sock2 = ngx.socket.connect("127.0.0.1", port) - local ok, err = sock1:setkeepalive(0, 20) - if not ok then - ngx.say(err) - end - local ok, err = sock2:setkeepalive(0, 20) - if not ok then - ngx.say(err) - end - - -- the pool_size is 1 instead of 20 - sock1 = ngx.socket.connect("127.0.0.1", port) - sock2 = ngx.socket.connect("127.0.0.1", port) - ngx.say("reused: ", sock1:getreusedtimes()) - ngx.say("reused: ", sock2:getreusedtimes()) - sock1:setkeepalive(0, 20) - sock2:setkeepalive(0, 20) - } - } ---- request -GET /t ---- response_body -connected: 1, reused: 0 -request sent: 11 -received: OK -connected: 1, reused: 1 -request sent: 11 -received: OK -reused: 1 -reused: 0 ---- no_error_log eval -["[error]", -"lua tcp socket keepalive: free connection pool for ", -"lua tcp socket connection pool size: 20"] ---- error_log eval -[qq{lua tcp socket keepalive create connection pool for key "127.0.0.1:$ENV{TEST_NGINX_MEMCACHED_PORT}"}, -"lua tcp socket connection pool size: 1", -] - - - -=== TEST 28: conn queuing: connect() can specify 'pool_size' for unix domain socket ---- http_config eval -" - server { - listen unix:$::HtmlDir/nginx.sock; - } -" ---- config - location /t { - content_by_lua_block { - local path = "unix:" .. "$TEST_NGINX_HTML_DIR/nginx.sock"; - local function go() - local sock = ngx.socket.tcp() - local ok, err = sock:connect(path, {pool_size = 1}) - if not ok then - ngx.say("failed to connect: ", err) - return - end - - ngx.say("connected: ", ok, ", reused: ", sock:getreusedtimes()) - - local ok, err = sock:setkeepalive(0, 20) - if not ok then - ngx.say("failed to set reusable: ", err) - end - end - - go() - go() - - local sock1 = ngx.socket.connect(path) - local sock2 = ngx.socket.connect(path) - local ok, err = sock1:setkeepalive(0, 20) - if not ok then - ngx.say(err) - end - local ok, err = sock2:setkeepalive(0, 20) - if not ok then - ngx.say(err) - end - - -- the pool_size is 1 instead of 20 - sock1 = ngx.socket.connect(path) - sock2 = ngx.socket.connect(path) - ngx.say("reused: ", sock1:getreusedtimes()) - ngx.say("reused: ", sock2:getreusedtimes()) - sock1:setkeepalive(0, 20) - sock2:setkeepalive(0, 20) - } - } ---- request -GET /t ---- response_body -connected: 1, reused: 0 -connected: 1, reused: 1 -reused: 1 -reused: 0 ---- no_error_log eval -["[error]", -"lua tcp socket keepalive: free connection pool for ", -"lua tcp socket connection pool size: 20"] ---- error_log eval -["lua tcp socket get keepalive peer: using connection", -'lua tcp socket keepalive create connection pool for key "unix:', -"lua tcp socket connection pool size: 1", -] - - - -=== TEST 29: conn queuing: connect() can specify 'pool_size' for custom pool ---- config - location /t { - set $port $TEST_NGINX_MEMCACHED_PORT; - - content_by_lua_block { - local port = ngx.var.port - local function go(pool) - local sock = ngx.socket.tcp() - local ok, err = sock:connect("127.0.0.1", port, {pool = pool, pool_size = 1}) - if not ok then - ngx.say("failed to connect: ", err) - return - end - - ngx.say("connected: ", pool, ", reused: ", sock:getreusedtimes()) - - local ok, err = sock:setkeepalive(0, 20) - if not ok then - ngx.say("failed to set reusable: ", err) - end - end - - go('A') - go('B') - go('A') - go('B') - - local sock1 = ngx.socket.connect("127.0.0.1", port, {pool = 'A'}) - local sock2 = ngx.socket.connect("127.0.0.1", port, {pool = 'A'}) - local ok, err = sock1:setkeepalive(0, 20) - if not ok then - ngx.say(err) - end - local ok, err = sock2:setkeepalive(0, 20) - if not ok then - ngx.say(err) - end - - -- the pool_size is 1 instead of 20 - sock1 = ngx.socket.connect("127.0.0.1", port, {pool = 'A'}) - sock2 = ngx.socket.connect("127.0.0.1", port, {pool = 'A'}) - ngx.say("reused: ", sock1:getreusedtimes()) - ngx.say("reused: ", sock2:getreusedtimes()) - sock1:setkeepalive(0, 20) - sock2:setkeepalive(0, 20) - } - } ---- request -GET /t ---- response_body -connected: A, reused: 0 -connected: B, reused: 0 -connected: A, reused: 1 -connected: B, reused: 1 -reused: 1 -reused: 0 ---- no_error_log eval -["[error]", -"lua tcp socket keepalive: free connection pool for ", -"lua tcp socket connection pool size: 20"] ---- error_log eval -[qq{lua tcp socket keepalive create connection pool for key "A"}, -qq{lua tcp socket keepalive create connection pool for key "B"}, -"lua tcp socket connection pool size: 1", -] - - - -=== TEST 30: conn queuing: connect() uses lua_socket_pool_size as default if 'backlog' is given ---- config - location /t { - set $port $TEST_NGINX_MEMCACHED_PORT; - lua_socket_pool_size 1234; - - content_by_lua_block { - local port = ngx.var.port - local opts = {backlog = 0} - local sock, err = ngx.socket.connect("127.0.0.1", port, opts) - if not sock then - ngx.say(err) - else - ngx.say("ok") - end - } - } ---- request -GET /t ---- response_body -ok ---- error_log -lua tcp socket connection pool size: 1234 ---- no_error_log -[error] - - - -=== TEST 31: conn queuing: more connect operations than 'backlog' size ---- config - location /t { - set $port $TEST_NGINX_MEMCACHED_PORT; - - content_by_lua_block { - local port = ngx.var.port - local opts = {pool_size = 2, backlog = 0} - local sock = ngx.socket.connect("127.0.0.1", port, opts) - local not_reused_socket, err = ngx.socket.connect("127.0.0.1", port, opts) - if not not_reused_socket then - ngx.say(err) - return - end - -- burst - local ok, err = ngx.socket.connect("127.0.0.1", port, opts) - if not ok then - ngx.say(err) - end - - local ok, err = sock:setkeepalive() - if not ok then - ngx.say(err) - return - end - - ok, err = sock:connect("127.0.0.1", port, opts) - if not ok then - ngx.say(err) - end - ngx.say("reused: ", sock:getreusedtimes()) - -- both queue and pool is full - ok, err = ngx.socket.connect("127.0.0.1", port, opts) - if not ok then - ngx.say(err) - end - } - } ---- request -GET /t ---- response_body -too many waiting connect operations -reused: 1 -too many waiting connect operations ---- no_error_log -[error] - - - -=== TEST 32: conn queuing: once 'pool_size' is reached and pool has 'backlog' ---- config - location /t { - set $port $TEST_NGINX_MEMCACHED_PORT; - - content_by_lua_block { - local port = ngx.var.port - local opts = {pool_size = 2, backlog = 2} - local sock1 = ngx.socket.connect("127.0.0.1", port, opts) - - ngx.timer.at(0, function(premature) - local sock2, err = ngx.socket.connect("127.0.0.1", port, opts) - if not sock2 then - ngx.log(ngx.ERR, err) - return - end - - ngx.log(ngx.WARN, "start to handle timer") - ngx.sleep(0.1) - sock2:close() - -- resume connect operation - ngx.log(ngx.WARN, "continue to handle timer") - end) - - ngx.sleep(0.05) - ngx.log(ngx.WARN, "start to handle cosocket") - local sock3, err = ngx.socket.connect("127.0.0.1", port, opts) - if not sock3 then - ngx.say(err) - return - end - ngx.log(ngx.WARN, "continue to handle cosocket") - - local req = "flush_all\r\n" - local bytes, err = sock3:send(req) - if not bytes then - ngx.say("failed to send request: ", err) - return - end - ngx.say("request sent: ", bytes) - - local line, err, part = sock3:receive() - if line then - ngx.say("received: ", line) - else - ngx.say("failed to receive a line: ", err, " [", part, "]") - end - - local ok, err = sock3:setkeepalive() - if not ok then - ngx.say("failed to set reusable: ", err) - end - ngx.say("setkeepalive: OK") - } - } ---- request -GET /t ---- response_body -request sent: 11 -received: OK -setkeepalive: OK ---- no_error_log -[error] ---- error_log -lua tcp socket queue connect operation for connection pool "127.0.0.1 ---- grep_error_log eval: qr/(start|continue) to handle \w+/ ---- grep_error_log_out -start to handle timer -start to handle cosocket -continue to handle timer -continue to handle cosocket - - - -=== TEST 33: conn queuing: do not count failed connect operations ---- config - resolver $TEST_NGINX_RESOLVER ipv6=off; - resolver_timeout 3s; - location /t { - set $port $TEST_NGINX_MEMCACHED_PORT; - - content_by_lua_block { - local port = ngx.var.port - local opts = {pool = "test", pool_size = 1, backlog = 0} - - local sock = ngx.socket.tcp() - sock:settimeouts(100, 3000, 3000) - local ok, err = sock:connect("127.0.0.2", 12345, opts) - if not ok then - ngx.say(err) - end - - local sock, err = ngx.socket.connect("127.0.0.1", port, opts) - if not sock then - ngx.say(err) - end - ngx.say("ok") - } - } ---- request -GET /t ---- error_log -lua tcp socket connect timed out, when connecting to ---- response_body -timeout -ok - - - -=== TEST 34: conn queuing: connect until backlog is reached ---- config - location /t { - set $port $TEST_NGINX_MEMCACHED_PORT; - - content_by_lua_block { - local port = ngx.var.port - local opts = {pool_size = 1, backlog = 1} - local sock1 = ngx.socket.connect("127.0.0.1", port, opts) - - ngx.timer.at(0.01, function(premature) - ngx.log(ngx.WARN, "start to handle timer") - local sock2, err = ngx.socket.connect("127.0.0.1", port, opts) - if not sock2 then - ngx.log(ngx.ERR, err) - return - end - - ngx.sleep(0.02) - local ok, err = sock2:close() - if not ok then - ngx.log(ngx.ERR, err) - end - ngx.log(ngx.WARN, "continue to handle timer") - end) - - ngx.sleep(0.02) - local sock3, err = ngx.socket.connect("127.0.0.1", port, opts) - if not sock3 then - ngx.say(err) - end - local ok, err = sock1:setkeepalive() - if not ok then - ngx.say(err) - return - end - ngx.sleep(0.01) -- run sock2 - - ngx.log(ngx.WARN, "start to handle cosocket") - local sock3, err = ngx.socket.connect("127.0.0.1", port, opts) - if not sock3 then - ngx.say(err) - return - end - ngx.log(ngx.WARN, "continue to handle cosocket") - - local ok, err = sock3:setkeepalive() - if not ok then - ngx.say(err) - end - } - } ---- request -GET /t ---- response_body -too many waiting connect operations ---- no_error_log -[error] ---- error_log -lua tcp socket queue connect operation for connection pool "127.0.0.1 ---- grep_error_log eval: qr/queue connect operation for connection pool|(start|continue) to handle \w+/ ---- grep_error_log_out -start to handle timer -queue connect operation for connection pool -start to handle cosocket -queue connect operation for connection pool -continue to handle timer -continue to handle cosocket - - - -=== TEST 35: conn queuing: memory reuse for host in queueing connect operation ctx ---- config - location /t { - set $port $TEST_NGINX_MEMCACHED_PORT; - - content_by_lua_block { - local port = ngx.var.port - local opts = {pool = "test", pool_size = 1, backlog = 3} - local sock = ngx.socket.connect("127.0.0.1", port, opts) - - ngx.timer.at(0.01, function(premature) - local sock, err = ngx.socket.connect("0.0.0.0", port, opts) - if not sock then - ngx.log(ngx.ERR, err) - return - end - - local ok, err = sock:close() - if not ok then - ngx.log(ngx.ERR, err) - end - end) - - ngx.timer.at(0.015, function(premature) - local sock, err = ngx.socket.connect("127.0.0.1", port, opts) - if not sock then - ngx.log(ngx.ERR, err) - return - end - - local ok, err = sock:close() - if not ok then - ngx.log(ngx.ERR, err) - end - end) - - ngx.timer.at(0.02, function(premature) - local sock, err = ngx.socket.connect("0.0.0.0", port, opts) - if not sock then - ngx.log(ngx.ERR, err) - return - end - - local ok, err = sock:close() - if not ok then - ngx.log(ngx.ERR, err) - end - end) - - ngx.sleep(0.03) - local ok, err = sock:setkeepalive() - if not ok then - ngx.say(err) - return - end - ngx.say("ok") - } - } ---- request -GET /t ---- response_body -ok ---- no_error_log -[error] ---- grep_error_log eval: qr/queue connect operation for connection pool/ ---- grep_error_log_out -queue connect operation for connection pool -queue connect operation for connection pool -queue connect operation for connection pool - - - -=== TEST 36: conn queuing: connect() returns error after connect operation resumed ---- config - location /t { - set $port $TEST_NGINX_MEMCACHED_PORT; - - content_by_lua_block { - local port = ngx.var.port - local opts = {pool = "test", pool_size = 1, backlog = 1} - local sock = ngx.socket.connect("127.0.0.1", port, opts) - - ngx.timer.at(0, function(premature) - local sock, err = ngx.socket.connect("", port, opts) - if not sock then - ngx.log(ngx.WARN, err) - end - end) - - ngx.sleep(0.01) - -- use 'close' to force parsing host instead of reusing conn - local ok, err = sock:close() - if not ok then - ngx.say(err) - return - end - ngx.say("ok") - } - } ---- request -GET /t ---- response_body -ok ---- no_error_log -[error] ---- error_log -failed to parse host name ---- grep_error_log eval: qr/queue connect operation for connection pool/ ---- grep_error_log_out -queue connect operation for connection pool - - - -=== TEST 37: conn queuing: in uthread ---- config - location /t { - set $port $TEST_NGINX_MEMCACHED_PORT; - - content_by_lua_block { - local port = ngx.var.port - local opts = {pool_size = 1, backlog = 2} - - local conn_sock = function() - local sock, err = ngx.socket.connect("127.0.0.1", port, opts) - if not sock then - ngx.say(err) - return - end - ngx.say("start to handle uthread") - - ngx.sleep(0.01) - sock:close() - ngx.say("continue to handle other uthread") - end - - local sock, err = ngx.socket.connect("127.0.0.1", port, opts) - if not sock then - ngx.log(ngx.ERR, err) - return - end - - local co1 = ngx.thread.spawn(conn_sock) - local co2 = ngx.thread.spawn(conn_sock) - local co3 = ngx.thread.spawn(conn_sock) - - local ok, err = sock:setkeepalive() - if not ok then - ngx.log(ngx.ERR, err) - end - - ngx.thread.wait(co1) - ngx.thread.wait(co2) - ngx.thread.wait(co3) - ngx.say("all uthreads ok") - } - } ---- request -GET /t ---- response_body -too many waiting connect operations -start to handle uthread -continue to handle other uthread -start to handle uthread -continue to handle other uthread -all uthreads ok ---- no_error_log -[error] ---- grep_error_log eval: qr/queue connect operation for connection pool/ ---- grep_error_log_out -queue connect operation for connection pool -queue connect operation for connection pool - - - -=== TEST 38: conn queuing: in access_by_lua ---- config - location /t { - set $port $TEST_NGINX_MEMCACHED_PORT; - - access_by_lua_block { - local port = ngx.var.port - local opts = {pool_size = 1, backlog = 2} - - local conn_sock = function() - local sock, err = ngx.socket.connect("127.0.0.1", port, opts) - if not sock then - ngx.say(err) - return - end - ngx.say("start to handle uthread") - - ngx.sleep(0.01) - sock:close() - ngx.say("continue to handle other uthread") - end - - local sock, err = ngx.socket.connect("127.0.0.1", port, opts) - if not sock then - ngx.log(ngx.ERR, err) - return - end - - local co1 = ngx.thread.spawn(conn_sock) - local co2 = ngx.thread.spawn(conn_sock) - local co3 = ngx.thread.spawn(conn_sock) - - local ok, err = sock:setkeepalive() - if not ok then - ngx.log(ngx.ERR, err) - end - - ngx.thread.wait(co1) - ngx.thread.wait(co2) - ngx.thread.wait(co3) - ngx.say("all uthreads ok") - } - } ---- request -GET /t ---- response_body -too many waiting connect operations -start to handle uthread -continue to handle other uthread -start to handle uthread -continue to handle other uthread -all uthreads ok ---- no_error_log -[error] ---- grep_error_log eval: qr/queue connect operation for connection pool/ ---- grep_error_log_out -queue connect operation for connection pool -queue connect operation for connection pool - - - -=== TEST 39: conn queuing: in rewrite_by_lua ---- config - location /t { - set $port $TEST_NGINX_MEMCACHED_PORT; - - rewrite_by_lua_block { - local port = ngx.var.port - local opts = {pool_size = 1, backlog = 2} - - local conn_sock = function() - local sock, err = ngx.socket.connect("127.0.0.1", port, opts) - if not sock then - ngx.say(err) - return - end - ngx.say("start to handle uthread") - - ngx.sleep(0.01) - sock:close() - ngx.say("continue to handle other uthread") - end - - local sock, err = ngx.socket.connect("127.0.0.1", port, opts) - if not sock then - ngx.log(ngx.ERR, err) - return - end - - local co1 = ngx.thread.spawn(conn_sock) - local co2 = ngx.thread.spawn(conn_sock) - local co3 = ngx.thread.spawn(conn_sock) - - local ok, err = sock:setkeepalive() - if not ok then - ngx.log(ngx.ERR, err) - end - - ngx.thread.wait(co1) - ngx.thread.wait(co2) - ngx.thread.wait(co3) - ngx.say("all uthreads ok") - } - } ---- request -GET /t ---- response_body -too many waiting connect operations -start to handle uthread -continue to handle other uthread -start to handle uthread -continue to handle other uthread -all uthreads ok ---- no_error_log -[error] ---- grep_error_log eval: qr/queue connect operation for connection pool/ ---- grep_error_log_out -queue connect operation for connection pool -queue connect operation for connection pool - - - -=== TEST 40: conn queuing: in subrequest ---- config - set $port $TEST_NGINX_MEMCACHED_PORT; - - location /t { - content_by_lua_block { - local port = ngx.var.port - ngx.timer.at(0, function() - local opts = {pool_size = 1, backlog = 2} - local sock, err = ngx.socket.connect("127.0.0.1", port, opts) - if not sock then - ngx.log(ngx.ERR, err) - return - end - - ngx.sleep(0.1) - local ok, err = sock:setkeepalive() - if not ok then - ngx.log(ngx.ERR, err) - end - end) - - ngx.sleep(0.01) - local res1, res2, res3 = ngx.location.capture_multi{ - {"/conn"}, {"/conn"}, {"/conn"} - } - ngx.say(res1.body) - ngx.say(res2.body) - ngx.say(res3.body) - } - } - - location /conn { - content_by_lua_block { - local port = ngx.var.port - local sock, err = ngx.socket.connect("127.0.0.1", port) - if not sock then - ngx.print(err) - return - end - local ok, err = sock:setkeepalive() - if not ok then - ngx.print(err) - else - ngx.print("ok") - end - } - } ---- request -GET /t ---- response_body -ok -ok -too many waiting connect operations ---- no_error_log -[error] ---- grep_error_log eval: qr/queue connect operation for connection pool/ ---- grep_error_log_out -queue connect operation for connection pool -queue connect operation for connection pool - - - -=== TEST 41: conn queuing: timeouts when 'connect_timeout' is reached ---- config - location /t { - set $port $TEST_NGINX_MEMCACHED_PORT; - - content_by_lua_block { - local port = ngx.var.port - local opts = {pool_size = 1, backlog = 1} - local sock1 = ngx.socket.connect("127.0.0.1", port, opts) - - local sock2 = ngx.socket.tcp() - sock2:settimeouts(10, 3000, 3000) - local ok, err = sock2:connect("127.0.0.1", port, opts) - if not ok then - ngx.say(err) - end - } - } ---- request -GET /t ---- response_body -timeout ---- error_log eval -"lua tcp socket queued connect timed out, when trying to connect to 127.0.0.1:$ENV{TEST_NGINX_MEMCACHED_PORT}" - - - -=== TEST 42: conn queuing: set timeout via lua_socket_connect_timeout ---- config - lua_socket_connect_timeout 10ms; - location /t { - set $port $TEST_NGINX_MEMCACHED_PORT; - - content_by_lua_block { - local port = ngx.var.port - local opts = {pool_size = 1, backlog = 1} - local sock1 = ngx.socket.connect("127.0.0.1", port, opts) - - local sock2 = ngx.socket.tcp() - local ok, err = sock2:connect("127.0.0.1", port, opts) - if not ok then - ngx.say(err) - end - } - } ---- request -GET /t ---- response_body -timeout ---- error_log eval -"lua tcp socket queued connect timed out, when trying to connect to 127.0.0.1:$ENV{TEST_NGINX_MEMCACHED_PORT}" - - - -=== TEST 43: conn queuing: client aborting while connect operation is queued ---- config - location /t { - set $port $TEST_NGINX_MEMCACHED_PORT; - - content_by_lua_block { - local port = ngx.var.port - local opts = {pool_size = 1, backlog = 1} - local sock1 = ngx.socket.connect("127.0.0.1", port, opts) - - local sock2 = ngx.socket.tcp() - sock2:settimeouts(3000, 3000, 3000) - local ok, err = sock2:connect("127.0.0.1", port, opts) - if not ok then - ngx.say(err) - end - } - } ---- request -GET /t ---- ignore_response ---- timeout: 0.1 ---- abort ---- no_error_log -[error] - - - -=== TEST 44: conn queuing: resume next connect operation if resumed connect failed immediately ---- config - location /t { - set $port $TEST_NGINX_MEMCACHED_PORT; - - content_by_lua_block { - local port = ngx.var.port - local opts = {pool = "test", pool_size = 1, backlog = 2} - - local conn_sock = function(should_timeout) - local sock = ngx.socket.tcp() - local ok, err - if should_timeout then - ok, err = sock:connect("", port, opts) - else - ok, err = sock:connect("127.0.0.1", port, opts) - end - if not ok then - ngx.say(err) - return - end - ngx.say("connected in uthread") - sock:close() - end - - local sock, err = ngx.socket.connect("127.0.0.1", port, opts) - if not sock then - ngx.log(ngx.ERR, err) - return - end - - local co1 = ngx.thread.spawn(conn_sock, true) - local co2 = ngx.thread.spawn(conn_sock) - - local ok, err = sock:close() - if not ok then - ngx.log(ngx.ERR, err) - end - - ngx.thread.wait(co1) - ngx.thread.wait(co2) - ngx.say("ok") - } - } ---- request -GET /t ---- response_body -failed to parse host name "": no host -connected in uthread -ok ---- no_error_log -[error] - - - -=== TEST 45: conn queuing: resume connect operation if resumed connect failed (timeout) ---- config - resolver $TEST_NGINX_RESOLVER ipv6=off; - resolver_timeout 3s; - location /t { - set $port $TEST_NGINX_MEMCACHED_PORT; - - content_by_lua_block { - local port = ngx.var.port - local opts = {pool = "test", pool_size = 1, backlog = 1} - - local conn_sock = function(should_timeout) - local sock = ngx.socket.tcp() - local ok, err - if should_timeout then - sock:settimeouts(100, 3000, 3000) - ok, err = sock:connect("127.0.0.2", 12345, opts) - else - ok, err = sock:connect("127.0.0.1", port, opts) - end - if not ok then - ngx.say(err) - return - end - ngx.say("connected in uthread") - sock:close() - end - - local co1 = ngx.thread.spawn(conn_sock, true) - local co2 = ngx.thread.spawn(conn_sock) - - ngx.thread.wait(co1) - ngx.thread.wait(co2) - ngx.say("ok") - } - } ---- request -GET /t ---- response_body -timeout -connected in uthread -ok ---- error_log -queue connect operation for connection pool "test" -lua tcp socket connect timed out, when connecting to - - - -=== TEST 46: conn queuing: resume connect operation if resumed connect failed (could not be resolved) ---- config - resolver 127.0.0.2:12345 ipv6=off; - resolver_timeout 1s; - location /t { - set $port $TEST_NGINX_MEMCACHED_PORT; - - content_by_lua_block { - local port = ngx.var.port - local opts = {pool = "test", pool_size = 1, backlog = 1} - - local conn_sock = function(should_timeout) - local sock = ngx.socket.tcp() - local ok, err - if should_timeout then - sock:settimeouts(1, 3000, 3000) - ok, err = sock:connect("agentzh.org", 80, opts) - else - ok, err = sock:connect("127.0.0.1", port, opts) - end - if not ok then - ngx.say(err) - return - end - ngx.say("connected in uthread") - sock:close() - end - - local co1 = ngx.thread.spawn(conn_sock, true) - local co2 = ngx.thread.spawn(conn_sock) - - ngx.thread.wait(co1) - ngx.thread.wait(co2) - ngx.say("ok") - } - } ---- request -GET /t ---- response_body -agentzh.org could not be resolved (110: Operation timed out) -connected in uthread -ok ---- error_log -queue connect operation for connection pool "test" - - - -=== TEST 47: conn queuing: resume connect operation if resumed connect failed (connection refused) ---- config - location /t { - set $port $TEST_NGINX_MEMCACHED_PORT; - - content_by_lua_block { - local port = ngx.var.port - local opts = {pool = "test", pool_size = 1, backlog = 1} - - local conn_sock = function(should_timeout) - local sock = ngx.socket.tcp() - local ok, err - if should_timeout then - sock:settimeouts(100, 3000, 3000) - ok, err = sock:connect("127.0.0.1", 62345, opts) - else - ok, err = sock:connect("127.0.0.1", port, opts) - end - if not ok then - ngx.say(err) - return - end - ngx.say("connected in uthread") - sock:close() - end - - local co1 = ngx.thread.spawn(conn_sock, true) - local co2 = ngx.thread.spawn(conn_sock) - - ngx.thread.wait(co1) - ngx.thread.wait(co2) - ngx.say("ok") - } - } ---- request -GET /t ---- response_body -connection refused -connected in uthread -ok ---- error_log -queue connect operation for connection pool "test" - - - -=== TEST 48: conn queuing: resume connect operation if resumed connect failed (uthread aborted while resolving) ---- http_config - lua_package_path '../lua-resty-core/lib/?.lua;../lua-resty-lrucache/lib/?.lua;;'; ---- config - resolver 127.0.0.1 ipv6=off; - resolver_timeout 100s; - set $port $TEST_NGINX_MEMCACHED_PORT; - - location /sub { - content_by_lua_block { - local semaphore = require "ngx.semaphore" - local sem = semaphore.new() - - local function f() - sem:wait(0.1) - ngx.exit(0) - end - - local opts = {pool = "test", pool_size = 1, backlog = 1} - local port = ngx.var.port - ngx.timer.at(0, function() - sem:post() - local sock2, err = ngx.socket.connect("127.0.0.1", port, opts) - package.loaded.for_timer_to_resume:post() - if not sock2 then - ngx.log(ngx.ALERT, "resume connect failed: ", err) - return - end - - ngx.log(ngx.INFO, "resume success") - end) - - ngx.thread.spawn(f) - local sock1, err = ngx.socket.connect("openresty.org", 80, opts) - if not sock1 then - ngx.say(err) - return - end - } - } - - location /t { - content_by_lua_block { - local semaphore = require "ngx.semaphore" - local for_timer_to_resume = semaphore.new() - package.loaded.for_timer_to_resume = for_timer_to_resume - - ngx.location.capture("/sub") - for_timer_to_resume:wait(0.1) - } - } ---- request -GET /t ---- no_error_log -[alert] ---- error_log -resume success - - - -=== TEST 49: conn queuing: resume connect operation if resumed connect failed (uthread killed while resolving) ---- config - resolver 127.0.0.1 ipv6=off; - resolver_timeout 100s; - set $port $TEST_NGINX_MEMCACHED_PORT; - - location /t { - content_by_lua_block { - local opts = {pool = "test", pool_size = 1, backlog = 1} - local port = ngx.var.port - - local function resolve() - local sock1, err = ngx.socket.connect("openresty.org", 80, opts) - if not sock1 then - ngx.say(err) - return - end - end - - local th = ngx.thread.spawn(resolve) - local ok, err = ngx.thread.kill(th) - if not ok then - ngx.log(ngx.ALERT, "kill thread failed: ", err) - return - end - - local sock2, err = ngx.socket.connect("127.0.0.1", port, opts) - if not sock2 then - ngx.log(ngx.ALERT, "resume connect failed: ", err) - return - end - - ngx.log(ngx.INFO, "resume success") - } - } ---- request -GET /t ---- no_error_log -[alert] ---- error_log -resume success - - - -=== TEST 50: conn queuing: increase the counter for connections created before creating the pool with setkeepalive() ---- config - set $port $TEST_NGINX_MEMCACHED_PORT; - - location /t { - content_by_lua_block { - local function connect() - local sock, err = ngx.socket.connect("127.0.0.1", ngx.var.port) - if not sock then - error("connect failed: " .. err) - end - - return sock - end - - local sock1 = connect() - local sock2 = connect() - assert(sock1:setkeepalive()) - assert(sock2:setkeepalive()) - - local sock1 = connect() - local sock2 = connect() - assert(sock1:close()) - assert(sock2:close()) - - ngx.say("ok") - } - } ---- request -GET /t ---- no_error_log -[error] ---- response_body -ok - - - -=== TEST 51: conn queuing: only decrease the counter for connections which were counted by the pool ---- config - set $port $TEST_NGINX_MEMCACHED_PORT; - - location /t { - content_by_lua_block { - local function connect() - local sock, err = ngx.socket.connect("127.0.0.1", ngx.var.port) - if not sock then - error("connect failed: " .. err) - end - - return sock - end - - local sock1 = connect() - local sock2 = connect() - assert(sock1:setkeepalive(1000, 1)) - assert(sock2:setkeepalive(1000, 1)) - - local sock1 = connect() - local sock2 = connect() - assert(sock1:close()) - assert(sock2:close()) - - ngx.say("ok") - } - } ---- request -GET /t ---- no_error_log -[error] ---- response_body -ok - - - -=== TEST 52: conn queuing: clean up pending connect operations which are in queue ---- config - set $port $TEST_NGINX_MEMCACHED_PORT; - - location /sub { - content_by_lua_block { - local opts = {pool = "test", pool_size = 1, backlog = 1} - local sock, err = ngx.socket.connect("127.0.0.1", ngx.var.port, opts) - if not sock then - ngx.say("connect failed: " .. err) - return - end - - local function f() - assert(ngx.socket.connect("127.0.0.1", ngx.var.port, opts)) - end - - local th = ngx.thread.spawn(f) - local ok, err = ngx.thread.kill(th) - if not ok then - ngx.log(ngx.ERR, "kill thread failed: ", err) - return - end - - sock:close() - } - } - - location /t { - content_by_lua_block { - ngx.location.capture("/sub") - -- let pending connect operation resumes first - ngx.sleep(0) - ngx.say("ok") - } - } ---- request -GET /t ---- no_error_log -[error] ---- error_log -lua tcp socket abort queueing ---- response_body -ok diff --git a/debian/modules/http-lua/t/073-backtrace.t b/debian/modules/http-lua/t/073-backtrace.t index 663c3af..6c54692 100644 --- a/debian/modules/http-lua/t/073-backtrace.t +++ b/debian/modules/http-lua/t/073-backtrace.t @@ -21,10 +21,10 @@ __DATA__ --- config location /lua { content_by_lua - ' local function bar() + ' function bar() return lua_concat(3) end - local function foo() + function foo() bar() end foo() @@ -37,7 +37,7 @@ GET /lua attempt to call global 'lua_concat' : in function 'bar' :5: in function 'foo' -:7: in main chunk +:7: in function @@ -45,10 +45,10 @@ attempt to call global 'lua_concat' --- config location /lua { content_by_lua - ' local function bar() + ' function bar() error(nil) end - local function foo() + function foo() bar() end foo() @@ -64,7 +64,7 @@ GET /lua " in function 'error'", ": in function 'bar'", ":5: in function 'foo'", -qr/:7: in main chunk/, +qr/:7: in function /, ] @@ -125,7 +125,7 @@ probe process("$LIBLUA_PATH").function("lua_concat") { :63: in function 'func16' :67: in function 'func17' :71: in function 'func18' -:74: in main chunk +:74: in function diff --git a/debian/modules/http-lua/t/075-logby.t b/debian/modules/http-lua/t/075-logby.t index 8eece69..520c62e 100644 --- a/debian/modules/http-lua/t/075-logby.t +++ b/debian/modules/http-lua/t/075-logby.t @@ -220,7 +220,7 @@ failed to run log_by_lua*: unknown reason -=== TEST 11: globals sharing +=== TEST 11: globals get cleared for every single request --- config location /lua { echo ok; @@ -228,7 +228,6 @@ failed to run log_by_lua*: unknown reason if not foo then foo = 1 else - ngx.log(ngx.INFO, "old foo: ", foo) foo = foo + 1 end ngx.log(ngx.WARN, "foo = ", foo) @@ -238,9 +237,8 @@ failed to run log_by_lua*: unknown reason GET /lua --- response_body ok ---- grep_error_log eval: qr/old foo: \d+/ ---- grep_error_log_out eval -["", "old foo: 1\n"] +--- error_log +foo = 1 @@ -497,8 +495,7 @@ API disabled in the context of log_by_lua* location /t { echo ok; log_by_lua ' - local bar - local function foo() + function foo() bar() end diff --git a/debian/modules/http-lua/t/081-bytecode.t b/debian/modules/http-lua/t/081-bytecode.t index 92383bc..cb50e94 100644 --- a/debian/modules/http-lua/t/081-bytecode.t +++ b/debian/modules/http-lua/t/081-bytecode.t @@ -24,7 +24,7 @@ __DATA__ content_by_lua ' ngx.req.read_body(); local b = ngx.req.get_body_data(); - local f = io.open(ngx.var.realpath_root.."/test.lua", "w"); + f = io.open(ngx.var.realpath_root.."/test.lua", "w"); -- luajit bytecode: sub(149,-1), lua bytecode: sub(1,147) if jit then if not string.find(jit.version, "LuaJIT 2.0") then @@ -35,8 +35,7 @@ __DATA__ else f:write(string.sub(b, 1, 147)); end - f:close(); - local res = ngx.location.capture("/call"); + f:close(); res = ngx.location.capture("/call"); ngx.print(res.body) '; } @@ -61,15 +60,14 @@ __DATA__ content_by_lua ' ngx.req.read_body(); local b = ngx.req.get_body_data(); - local f = io.open(ngx.var.realpath_root.."/test.lua", "w"); + f = io.open(ngx.var.realpath_root.."/test.lua", "w"); -- luajit bytecode: sub(149,-1), lua bytecode: sub(1,147) if not package.loaded["jit"] then f:write(string.sub(b, 149)); else f:write(string.sub(b, 1, 147)); end - f:close(); - local res = ngx.location.capture("/call"); + f:close(); res = ngx.location.capture("/call"); if res.status == 200 then ngx.print(res.body) else @@ -87,7 +85,7 @@ __DATA__ --- response_body error --- error_log eval -qr/failed to load external Lua file ".*?test\.lua": .* cannot load incompatible bytecode/ +qr/failed to load external Lua file ".*?test\.lua": bad byte-code header/ @@ -98,15 +96,14 @@ qr/failed to load external Lua file ".*?test\.lua": .* cannot load incompatible content_by_lua ' ngx.req.read_body(); local b = ngx.req.get_body_data(); - local f = io.open(ngx.var.realpath_root.."/test.lua", "w"); + f = io.open(ngx.var.realpath_root.."/test.lua", "w"); -- luajit bytecode: sub(149,-1), lua bytecode: sub(1,147) if package.loaded["jit"] then f:write(string.sub(b, 149)); else f:write(string.sub(b, 1, 147)); end - f:close(); - local res = ngx.location.capture("/call"); + f:close(); res = ngx.location.capture("/call"); if res.status == 200 then ngx.print(res.body) else @@ -124,7 +121,7 @@ qr/failed to load external Lua file ".*?test\.lua": .* cannot load incompatible --- response_body error --- error_log -cannot load incompatible bytecode +bytecode format version unsupported @@ -135,7 +132,7 @@ cannot load incompatible bytecode content_by_lua ' ngx.req.read_body(); local b = ngx.req.get_body_data(); - local f = io.open(ngx.var.realpath_root.."/test.lua", "w"); + f = io.open(ngx.var.realpath_root.."/test.lua", "w"); -- luajit bytecode: sub(149,-1), lua bytecode: sub(1,147) local do_jit if jit then @@ -179,7 +176,7 @@ cannot load incompatible bytecode content_by_lua ' ngx.req.read_body(); local b = ngx.req.get_body_data(); - local f = io.open(ngx.var.realpath_root.."/test.lua", "w"); + f = io.open(ngx.var.realpath_root.."/test.lua", "w"); -- luajit bytecode: sub(149,-1), lua bytecode: sub(1,147) local jit; if package.loaded["jit"] then @@ -223,7 +220,7 @@ error content_by_lua ' ngx.req.read_body(); local b = ngx.req.get_body_data(); - local f = io.open(ngx.var.realpath_root.."/test.lua", "w"); + f = io.open(ngx.var.realpath_root.."/test.lua", "w"); -- luajit bytecode: sub(149,-1), lua bytecode: sub(1,147) if jit then if not string.find(jit.version, "LuaJIT 2.0") then @@ -259,9 +256,9 @@ error content_by_lua ' local bcsave = require "jit.bcsave" if jit then - local prefix = "$TEST_NGINX_SERVER_ROOT" - local infile = prefix .. "/html/a.lua" - local outfile = prefix .. "/html/a.luac" + local prefix = ngx.config.prefix() + local infile = prefix .. "html/a.lua" + local outfile = prefix .. "html/a.luac" bcsave.start("-s", infile, outfile) return ngx.exec("/call") end @@ -292,9 +289,9 @@ ngx.status = 201 ngx.say("hello from Lua!") content_by_lua ' local bcsave = require "jit.bcsave" if jit then - local prefix = "$TEST_NGINX_SERVER_ROOT" - local infile = prefix .. "/html/a.lua" - local outfile = prefix .. "/html/a.luac" + local prefix = ngx.config.prefix() + local infile = prefix .. "html/a.lua" + local outfile = prefix .. "html/a.luac" bcsave.start("-g", infile, outfile) return ngx.exec("/call") end @@ -323,9 +320,9 @@ ngx.status = 201 ngx.say("hello from Lua!") --- config location = /t { content_by_lua_block { - local f = assert(loadstring("local a = 1 ngx.say('a = ', a)", "=code")) + local f = assert(loadstring("a = a and a + 1 or 1 ngx.say('a = ', a)", "=code")) local bc = string.dump(f) - local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/a.luac", "w")) + local f = assert(io.open("t/servroot/html/a.luac", "w")) f:write(bc) f:close() } @@ -352,9 +349,9 @@ a = 1 --- config location = /t { content_by_lua_block { - local f = assert(loadstring("local a = 1 ngx.say('a = ', a)", "=code")) + local f = assert(loadstring("a = a and a + 1 or 1 ngx.say('a = ', a)", "=code")) local bc = string.dump(f, true) - local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/a.luac", "w")) + local f = assert(io.open("t/servroot/html/a.luac", "w")) f:write(bc) f:close() } diff --git a/debian/modules/http-lua/t/082-body-filter.t b/debian/modules/http-lua/t/082-body-filter.t index 5f765fa..98efa84 100644 --- a/debian/modules/http-lua/t/082-body-filter.t +++ b/debian/modules/http-lua/t/082-body-filter.t @@ -460,8 +460,7 @@ GET /t --- config location /t { body_filter_by_lua ' - local bar - local function foo() + function foo() bar() end diff --git a/debian/modules/http-lua/t/084-inclusive-receiveuntil.t b/debian/modules/http-lua/t/084-inclusive-receiveuntil.t index 66be893..f7d5d3d 100644 --- a/debian/modules/http-lua/t/084-inclusive-receiveuntil.t +++ b/debian/modules/http-lua/t/084-inclusive-receiveuntil.t @@ -56,7 +56,7 @@ __DATA__ local reader = sock:receiveuntil("abcabd", { inclusive = true }) for i = 1, 3 do - local line, err, part = reader() + line, err, part = reader() if line then ngx.say("read: ", line) @@ -128,7 +128,7 @@ close: 1 nil local reader = sock:receiveuntil("abcabdabcabe", { inclusive = true }) for i = 1, 2 do - local line, err, part = reader() + line, err, part = reader() if line then ngx.say("read: ", line) @@ -200,7 +200,7 @@ close: 1 nil local reader = sock:receiveuntil("abcabd", { inclusive = true }) for i = 1, 3 do - local line, err, part = reader() + line, err, part = reader() if line then ngx.say("read: ", line) @@ -272,7 +272,7 @@ close: 1 nil local reader = sock:receiveuntil("aa", { inclusive = nil }) for i = 1, 2 do - local line, err, part = reader() + line, err, part = reader() if line then ngx.say("read: ", line) @@ -343,7 +343,7 @@ close: 1 nil local reader = sock:receiveuntil("aa", { inclusive = false }) for i = 1, 2 do - local line, err, part = reader() + line, err, part = reader() if line then ngx.say("read: ", line) @@ -414,7 +414,7 @@ close: 1 nil local reader = sock:receiveuntil("aa", { inclusive = true }) for i = 1, 2 do - local line, err, part = reader() + line, err, part = reader() if line then ngx.say("read: ", line) @@ -485,7 +485,7 @@ close: 1 nil local reader = sock:receiveuntil("aa", { inclusive = "true" }) for i = 1, 2 do - local line, err, part = reader() + line, err, part = reader() if line then ngx.say("read: ", line) @@ -552,7 +552,7 @@ bad "inclusive" option value type: string local reader = sock:receiveuntil("aa", { inclusive = "true" }) for i = 1, 2 do - local line, err, part = reader() + line, err, part = reader() if line then ngx.say("read: ", line) @@ -620,7 +620,7 @@ bad "inclusive" option value type: string local reader = sock:receiveuntil("--abc", { inclusive = true }) for i = 1, 7 do - local line, err, part = reader(4) + line, err, part = reader(4) if line then ngx.say("read: ", line) @@ -697,7 +697,7 @@ close: 1 nil local reader = sock:receiveuntil("--abc", { inclusive = true }) for i = 1, 7 do - local line, err, part = reader(4) + line, err, part = reader(4) if line then ngx.say("read: ", line) diff --git a/debian/modules/http-lua/t/087-udp-socket.t b/debian/modules/http-lua/t/087-udp-socket.t index dc6cad5..8bedc32 100644 --- a/debian/modules/http-lua/t/087-udp-socket.t +++ b/debian/modules/http-lua/t/087-udp-socket.t @@ -555,7 +555,7 @@ lua udp socket read timed out local udp = socket.udp() - udp:settimeout(5000) -- 5 sec + udp:settimeout(2000) -- 2 sec local ok, err = udp:setpeername("$TEST_NGINX_RESOLVER", 53) if not ok then @@ -824,7 +824,7 @@ probe syscall.socket.return, syscall.connect.return { === TEST 15: bad request tries to setpeer --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config server_tokens off; location = /main { @@ -881,7 +881,7 @@ qr/runtime error: content_by_lua\(nginx\.conf:\d+\):14: bad request/ === TEST 16: bad request tries to send --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config server_tokens off; location = /main { @@ -938,7 +938,7 @@ qr/runtime error: content_by_lua\(nginx\.conf:\d+\):14: bad request/ === TEST 17: bad request tries to receive --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config server_tokens off; location = /main { @@ -995,7 +995,7 @@ qr/runtime error: content_by_lua\(nginx\.conf:\d+\):14: bad request/ === TEST 18: bad request tries to close --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config server_tokens off; location = /main { @@ -1052,7 +1052,7 @@ qr/runtime error: content_by_lua\(nginx\.conf:\d+\):14: bad request/ === TEST 19: bad request tries to receive --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config server_tokens off; location = /main { diff --git a/debian/modules/http-lua/t/090-log-socket-errors.t b/debian/modules/http-lua/t/090-log-socket-errors.t index f5a9f80..16576b6 100644 --- a/debian/modules/http-lua/t/090-log-socket-errors.t +++ b/debian/modules/http-lua/t/090-log-socket-errors.t @@ -28,7 +28,7 @@ __DATA__ lua_socket_log_errors off; content_by_lua ' local sock = ngx.socket.tcp() - local ok, err = sock:connect("127.0.0.2", 12345) + local ok, err = sock:connect("agentzh.org", 12345) ngx.say(err) '; } @@ -50,7 +50,7 @@ timeout lua_socket_log_errors on; content_by_lua ' local sock = ngx.socket.tcp() - local ok, err = sock:connect("127.0.0.2", 12345) + local ok, err = sock:connect("agentzh.org", 12345) ngx.say(err) '; } @@ -59,7 +59,7 @@ GET /t --- response_body timeout --- error_log -lua tcp socket connect timed out, when connecting to 127.0.0.2:12345 +lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 @@ -72,7 +72,7 @@ lua tcp socket connect timed out, when connecting to 127.0.0.2:12345 lua_socket_read_timeout 1ms; content_by_lua ' local sock = ngx.socket.udp() - local ok, err = sock:setpeername("127.0.0.2", 12345) + local ok, err = sock:setpeername("agentzh.org", 12345) ok, err = sock:receive() ngx.say(err) '; @@ -95,7 +95,7 @@ lua udp socket read timed out lua_socket_read_timeout 1ms; content_by_lua ' local sock = ngx.socket.udp() - local ok, err = sock:setpeername("127.0.0.2", 12345) + local ok, err = sock:setpeername("agentzh.org", 12345) ok, err = sock:receive() ngx.say(err) '; diff --git a/debian/modules/http-lua/t/091-coroutine.t b/debian/modules/http-lua/t/091-coroutine.t index 7cf60f9..bceb512 100644 --- a/debian/modules/http-lua/t/091-coroutine.t +++ b/debian/modules/http-lua/t/091-coroutine.t @@ -85,7 +85,7 @@ __DATA__ content_by_lua ' local cc, cr, cy = coroutine.create, coroutine.resume, coroutine.yield - local function f() + function f() local cnt = 0 for i = 1, 20 do ngx.say("Hello, ", cnt) @@ -120,7 +120,7 @@ Hello, 2 --- config location /lua { content_by_lua ' - local function f(fid) + function f(fid) local cnt = 0 while true do ngx.say("cc", fid, ": ", cnt) @@ -163,7 +163,7 @@ cc3: 2 resolver $TEST_NGINX_RESOLVER ipv6=off; location /lua { content_by_lua ' - local function worker(url) + function worker(url) local sock = ngx.socket.tcp() local ok, err = sock:connect(url, 80) coroutine.yield() @@ -178,7 +178,7 @@ cc3: 2 local urls = { "agentzh.org", - "openresty.com", + "iscribblet.org", "openresty.org" } @@ -204,7 +204,7 @@ cc3: 2 GET /lua --- response_body successfully connected to: agentzh.org -successfully connected to: openresty.com +successfully connected to: iscribblet.org successfully connected to: openresty.org *** All Done *** --- no_error_log @@ -218,14 +218,14 @@ successfully connected to: openresty.org location /lua { content_by_lua ' -- generate all the numbers from 2 to n - local function gen (n) + function gen (n) return coroutine.wrap(function () for i=2,n do coroutine.yield(i) end end) end -- filter the numbers generated by g, removing multiples of p - local function filter (p, g) + function filter (p, g) return coroutine.wrap(function () while 1 do local n = g() @@ -235,8 +235,8 @@ successfully connected to: openresty.org end) end - local N = 10 - local x = gen(N) -- generate primes up to N + N = 10 + x = gen(N) -- generate primes up to N while 1 do local n = x() -- pick a number until done if n == nil then break end @@ -264,14 +264,14 @@ GET /lua coroutine.create = nil coroutine.resume = nil -- generate all the numbers from 2 to n - local function gen (n) + function gen (n) return coroutine.wrap(function () for i=2,n do coroutine.yield(i) end end) end -- filter the numbers generated by g, removing multiples of p - local function filter (p, g) + function filter (p, g) return coroutine.wrap(function () while 1 do local n = g() @@ -281,8 +281,8 @@ GET /lua end) end - local N = 10 - local x = gen(N) -- generate primes up to N + N = 10 + x = gen(N) -- generate primes up to N while 1 do local n = x() -- pick a number until done if n == nil then break end @@ -307,7 +307,7 @@ GET /lua --- config location /lua { content_by_lua ' - local function generatefib (n) + function generatefib (n) return coroutine.wrap(function () local a,b = 1, 1 while a <= n do @@ -362,7 +362,7 @@ GET /lua resolver $TEST_NGINX_RESOLVER ipv6=off; location /lua { content_by_lua ' - local function worker(url) + function worker(url) local sock = ngx.socket.tcp() local ok, err = sock:connect(url, 80) coroutine.yield() @@ -377,7 +377,7 @@ GET /lua local urls = { "agentzh.org", - "openresty.com", + "iscribblet.org", "openresty.org" } @@ -398,7 +398,7 @@ GET /lua GET /lua --- response_body successfully connected to: agentzh.org -successfully connected to: openresty.com +successfully connected to: iscribblet.org successfully connected to: openresty.org *** All Done *** --- no_error_log @@ -414,7 +414,7 @@ successfully connected to: openresty.org local cc, cr, cy = coroutine.create, coroutine.resume, coroutine.yield local st, rn = coroutine.status, coroutine.running - local function f(self) + function f(self) local cnt = 0 if rn() ~= self then ngx.say("error"); return end ngx.say("running: ", st(self)) --running @@ -509,7 +509,7 @@ GET /lua --- config location /lua { content_by_lua ' - local function print(...) + function print(...) local args = {...} local is_first = true for i,v in ipairs(args) do @@ -523,12 +523,12 @@ GET /lua ngx.print("\\\n") end - local function foo (a) + function foo (a) print("foo", a) return coroutine.yield(2*a) end - local co = coroutine.create(function (a,b) + co = coroutine.create(function (a,b) print("co-body", a, b) local r = foo(a+1) print("co-body", r) @@ -566,8 +566,7 @@ main false cannot resume dead coroutine local create = coroutine.create local resume = coroutine.resume local yield = coroutine.yield - local g - local function f() + function f() ngx.say("f begin") yield() local c2 = create(g) @@ -628,9 +627,8 @@ main done local yield = coroutine.yield local code = 400 - local g - local function f() + function f() local c2 = create(g) yield() code = code + 1 @@ -685,9 +683,8 @@ exit local yield = coroutine.yield local code = 0 - local g - local function f() + function f() local c2 = create(g) yield() code = code + 1 @@ -743,7 +740,7 @@ num: 3 location /lua { echo hello; header_filter_by_lua ' - local function f() + function f() yield() end @@ -767,13 +764,13 @@ API disabled in the context of header_filter_by_lua* local c1, c2 - local function f() + function f() print("f 1") print(coroutine.resume(c2)) print("f 2") end - local function g() + function g() print("g 1") -- print(coroutine.resume(c1)) print("g 2") @@ -806,13 +803,13 @@ f 2 local c1, c2 - local function f() + function f() print("f 1") print(coroutine.resume(c2)) print("f 2") end - local function g() + function g() print("g 1") print(coroutine.resume(c1)) print("g 2") @@ -862,7 +859,7 @@ falsecannot resume running coroutine location /t { content_by_lua ' local co - local function f() + function f() ngx.say("f: ", coroutine.status(co)) ngx.say("f: ", coroutine.resume(co)) end @@ -888,7 +885,7 @@ chunk: true location /t { content_by_lua ' local co - local function f() + function f() error("bad") end co = coroutine.create(f) @@ -993,7 +990,7 @@ test10 resolver $TEST_NGINX_RESOLVER ipv6=off; location /lua { content_by_lua ' - local function worker(url) + function worker(url) local sock = ngx.socket.tcp() local ok, err = sock:connect(url, 80) coroutine.yield() @@ -1047,7 +1044,7 @@ successfully connected to: agentzh.org resolver $TEST_NGINX_RESOLVER ipv6=off; location /lua { content_by_lua ' - local function worker(url) + function worker(url) local sock = ngx.socket.tcp() local ok, err = sock:connect(url, 80) coroutine.yield() @@ -1107,7 +1104,7 @@ successfully connected to: agentzh.org --- config location /cotest { content_by_lua ' - local function generator() + function generator() return co_wrap(function() co_yield("data") end) @@ -1136,7 +1133,7 @@ data --- config location /cotest { content_by_lua ' - local function generator() + function generator() return co_wrap(function() co_yield("data") end) @@ -1169,7 +1166,7 @@ data content_by_lua ' local cc, cr, cy = coroutine.create, coroutine.resume, coroutine.yield - local function f() + function f() return 3 end @@ -1202,7 +1199,7 @@ ok local coroutine = require "coroutine" local cc, cr, cy = coroutine.create, coroutine.resume, coroutine.yield - local function f() + function f() local cnt = 0 for i = 1, 20 do ngx.say("Hello, ", cnt) @@ -1241,7 +1238,7 @@ Hello, 2 header_filter_by_lua ' local cc, cr, cy = coroutine.create, coroutine.resume, coroutine.yield - local function f() + function f() local cnt = 0 for i = 1, 20 do print("co yield: ", cnt) @@ -1281,7 +1278,7 @@ co yield: 2 body_filter_by_lua ' local cc, cr, cy = coroutine.create, coroutine.resume, coroutine.yield - local function f() + function f() local cnt = 0 for i = 1, 20 do print("co yield: ", cnt) diff --git a/debian/modules/http-lua/t/093-uthread-spawn.t b/debian/modules/http-lua/t/093-uthread-spawn.t index ab6db2f..b622d30 100644 --- a/debian/modules/http-lua/t/093-uthread-spawn.t +++ b/debian/modules/http-lua/t/093-uthread-spawn.t @@ -24,7 +24,7 @@ __DATA__ --- config location /lua { content_by_lua ' - local function f() + function f() ngx.say("hello in thread") end @@ -58,11 +58,11 @@ after --- config location /lua { content_by_lua ' - local function f() + function f() ngx.say("in thread 1") end - local function g() + function g() ngx.say("in thread 2") end @@ -107,7 +107,7 @@ after 2 --- config location /lua { content_by_lua ' - local function f() + function f() ngx.say("before sleep") ngx.sleep(0.1) ngx.say("after sleep") @@ -144,13 +144,13 @@ after sleep --- config location /lua { content_by_lua ' - local function f() + function f() ngx.say("1: before sleep") ngx.sleep(0.2) ngx.say("1: after sleep") end - local function g() + function g() ngx.say("2: before sleep") ngx.sleep(0.1) ngx.say("2: after sleep") @@ -200,7 +200,7 @@ delete thread 2 --- config location /lua { content_by_lua ' - local function f() + function f() ngx.blah() end @@ -231,9 +231,9 @@ qr/lua user thread aborted: runtime error: content_by_lua\(nginx\.conf:\d+\):3: --- config location /lua { content_by_lua ' - local function f() + function f() ngx.say("before capture") - local res = ngx.location.capture("/proxy") + res = ngx.location.capture("/proxy") ngx.say("after capture: ", res.body) end @@ -277,7 +277,7 @@ after capture: hello world --- config location /lua { content_by_lua ' - local function f() + function f() ngx.say("before capture") local res = ngx.location.capture("/proxy?foo") ngx.say("after capture: ", res.body) @@ -330,7 +330,7 @@ after capture: hello foo --- config location /lua { content_by_lua ' - local function f() + function f() ngx.say("before capture") local res = ngx.location.capture("/proxy?foo") ngx.say("after capture: ", res.body) @@ -384,13 +384,13 @@ capture: hello bar --- config location /lua { content_by_lua ' - local function f() + function f() ngx.say("f: before capture") local res = ngx.location.capture("/proxy?foo") ngx.say("f: after capture: ", res.body) end - local function g() + function g() ngx.say("g: before capture") local res = ngx.location.capture("/proxy?bah") ngx.say("g: after capture: ", res.body) @@ -462,8 +462,7 @@ g: after capture: hello bah --- config location /lua { content_by_lua ' - local g - local function f() + function f() ngx.say("before g") ngx.thread.spawn(g) ngx.say("after g") @@ -509,8 +508,7 @@ after g --- config location /lua { content_by_lua ' - local g - local function f() + function f() ngx.say("before g") ngx.thread.spawn(g) ngx.say("after g") @@ -558,7 +556,7 @@ hello in g() location /lua { content_by_lua ' local co - local function f() + function f() co = coroutine.running() ngx.sleep(0.1) end @@ -591,7 +589,7 @@ status: running location /lua { content_by_lua ' local co - local function f() + function f() co = coroutine.running() end @@ -623,8 +621,7 @@ status: zombie location /lua { content_by_lua ' local co - local g - local function f() + function f() co = coroutine.running() local co2 = coroutine.create(g) coroutine.resume(co2) @@ -663,8 +660,7 @@ status: normal --- config location /lua { content_by_lua ' - local g - local function f() + function f() ngx.say("before g") ngx.thread.spawn(g) ngx.say("after g") @@ -711,7 +707,7 @@ after f content_by_lua ' local yield = coroutine.yield - local function f() + function f() local self = coroutine.running() ngx.say("f 1") yield(self) @@ -764,7 +760,7 @@ f 3 content_by_lua ' local yield = coroutine.yield - local function f() + function f() local self = coroutine.running() ngx.say("f 1") yield(self) @@ -773,7 +769,7 @@ f 3 ngx.say("f 3") end - local function g() + function g() local self = coroutine.running() ngx.say("g 1") yield(self) @@ -820,7 +816,7 @@ g 3 --- config location /lua { content_by_lua ' - local function f() + function f() ngx.say("hello in thread") coroutine.yield(coroutine.running) ngx.flush(true) @@ -857,12 +853,12 @@ after --- config location /lua { content_by_lua ' - local function f() + function f() ngx.say("hello from f") ngx.flush(true) end - local function g() + function g() ngx.say("hello from g") ngx.flush(true) end @@ -908,7 +904,7 @@ hello from g --- config location /lua { content_by_lua ' - local function f() + function f() local sock = ngx.socket.tcp() local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_MEMCACHED_PORT) if not ok then @@ -960,7 +956,7 @@ received: OK --- config location /lua { content_by_lua ' - local function f() + function f() local sock = ngx.socket.udp() local ok, err = sock:setpeername("127.0.0.1", 12345) local bytes, err = sock:send("blah") @@ -1022,7 +1018,7 @@ after)$ --- config location /lua { content_by_lua ' - local function f() + function f() ngx.req.read_body() local body = ngx.req.get_body_data() ngx.say("body: ", body) @@ -1067,7 +1063,7 @@ body: hello world)$ --- config location /lua { content_by_lua ' - local function f() + function f() local sock = ngx.req.socket() local body, err = sock:receive(11) if not body then @@ -1117,7 +1113,7 @@ body: hello world)$ --- config location /lua { content_by_lua ' - local function f(a, b) + function f(a, b) ngx.say("hello ", a, " and ", b) end @@ -1651,7 +1647,7 @@ ok --- config location /lua { content_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.say("f") end diff --git a/debian/modules/http-lua/t/094-uthread-exit.t b/debian/modules/http-lua/t/094-uthread-exit.t index 58d8d0b..2f7d9ba 100644 --- a/debian/modules/http-lua/t/094-uthread-exit.t +++ b/debian/modules/http-lua/t/094-uthread-exit.t @@ -24,7 +24,7 @@ __DATA__ --- config location /lua { content_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.exit(0) end @@ -87,7 +87,7 @@ hello in thread --- config location /lua { content_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -171,13 +171,13 @@ after --- config location /lua { content_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.say("f") ngx.exit(0) end - local function g() + function g() ngx.sleep(1) ngx.say("g") end @@ -261,7 +261,7 @@ f --- config location /lua { content_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.say("exiting the user thread") ngx.exit(0) @@ -297,10 +297,10 @@ exiting the user thread === TEST 5: exit in user thread (entry thread is still pending on the DNS resolver for ngx.socket.tcp) --- config location /lua { - resolver 127.0.0.2:12345; + resolver agentzh.org; resolver_timeout 12s; content_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.001) ngx.exit(0) @@ -393,10 +393,10 @@ after === TEST 6: exit in user thread (entry thread is still pending on the DNS resolver for ngx.socket.udp) --- config location /lua { - resolver 127.0.0.2:12345; + resolver agentzh.org; resolver_timeout 12s; content_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.001) ngx.exit(0) @@ -490,7 +490,7 @@ after --- config location /lua { content_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -501,7 +501,7 @@ after ngx.say("after") local sock = ngx.socket.tcp() sock:settimeout(12000) - local ok, err = sock:connect("127.0.0.2", 12345) + local ok, err = sock:connect("172.105.207.225", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -580,7 +580,7 @@ after --- config location /lua { content_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -680,7 +680,7 @@ after --- config location /lua { content_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -786,7 +786,7 @@ after --- config location /lua { content_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -881,7 +881,7 @@ after --- config location /lua { content_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -974,7 +974,7 @@ after location /lua { client_body_timeout 12000ms; content_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -1059,7 +1059,7 @@ after location /lua { client_body_timeout 12000ms; content_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -1142,7 +1142,7 @@ attempt to abort with pending subrequests location /lua { client_body_timeout 12000ms; content_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.exit(0) end @@ -1225,7 +1225,7 @@ attempt to abort with pending subrequests location /lua { client_body_timeout 12000ms; content_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.exit(0) end @@ -1315,7 +1315,7 @@ attempt to abort with pending subrequests location /lua { client_body_timeout 12000ms; content_by_lua ' - local function f() + function f() ngx.location.capture_multi{ {"/echo"}, {"/sleep"} @@ -1407,7 +1407,7 @@ attempt to abort with pending subrequests location /lua { client_body_timeout 12000ms; content_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(444) @@ -1490,7 +1490,7 @@ free request location /lua { client_body_timeout 12000ms; content_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(408) @@ -1573,7 +1573,7 @@ free request location /lua { client_body_timeout 12000ms; content_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(499) diff --git a/debian/modules/http-lua/t/095-uthread-exec.t b/debian/modules/http-lua/t/095-uthread-exec.t index 7bf37c0..56156c4 100644 --- a/debian/modules/http-lua/t/095-uthread-exec.t +++ b/debian/modules/http-lua/t/095-uthread-exec.t @@ -23,7 +23,7 @@ __DATA__ --- config location /lua { content_by_lua ' - local function f() + function f() ngx.exec("/foo") end @@ -58,7 +58,7 @@ i am foo --- config location /lua { content_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.exec("/foo") end @@ -93,7 +93,7 @@ i am foo --- config location /lua { content_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.exec("/foo") end @@ -175,12 +175,12 @@ hello foo --- config location /lua { content_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.exec("/foo") end - local function g() + function g() ngx.sleep(1) end @@ -267,7 +267,7 @@ hello foo location /lua { client_body_timeout 12000ms; content_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.exec("/foo") end @@ -348,7 +348,7 @@ attempt to abort with pending subrequests location /lua { client_body_timeout 12000ms; content_by_lua ' - local function f() + function f() ngx.location.capture("/sleep") ngx.say("end") end diff --git a/debian/modules/http-lua/t/096-uthread-redirect.t b/debian/modules/http-lua/t/096-uthread-redirect.t index 95bff01..003c642 100644 --- a/debian/modules/http-lua/t/096-uthread-redirect.t +++ b/debian/modules/http-lua/t/096-uthread-redirect.t @@ -25,7 +25,7 @@ __DATA__ location /lua { client_body_timeout 12000ms; content_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.redirect(301) end @@ -114,7 +114,7 @@ attempt to abort with pending subrequests --- config location /lua { content_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.redirect(301) end @@ -194,7 +194,7 @@ free request location /lua { client_body_timeout 12000ms; content_by_lua ' - local function f() + function f() ngx.location.capture_multi{ {"/echo"}, {"/sleep"} diff --git a/debian/modules/http-lua/t/097-uthread-rewrite.t b/debian/modules/http-lua/t/097-uthread-rewrite.t index 998e256..2f0c06f 100644 --- a/debian/modules/http-lua/t/097-uthread-rewrite.t +++ b/debian/modules/http-lua/t/097-uthread-rewrite.t @@ -23,7 +23,7 @@ __DATA__ --- config location /lua { rewrite_by_lua ' - local function f() + function f() ngx.req.set_uri("/foo", true) end @@ -58,7 +58,7 @@ i am foo --- config location /lua { rewrite_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.req.set_uri("/foo", true) end @@ -93,7 +93,7 @@ i am foo --- config location /lua { rewrite_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.req.set_uri("/foo", true) end @@ -175,12 +175,12 @@ hello foo --- config location /lua { rewrite_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.req.set_uri("/foo", true) end - local function g() + function g() ngx.sleep(1) end @@ -267,7 +267,7 @@ hello foo location /lua { client_body_timeout 12000ms; rewrite_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.req.set_uri("/foo", true) end diff --git a/debian/modules/http-lua/t/098-uthread-wait.t b/debian/modules/http-lua/t/098-uthread-wait.t index c2819ae..4948596 100644 --- a/debian/modules/http-lua/t/098-uthread-wait.t +++ b/debian/modules/http-lua/t/098-uthread-wait.t @@ -23,7 +23,7 @@ __DATA__ --- config location /lua { content_by_lua ' - local function f() + function f() ngx.say("hello in thread") return "done" end @@ -72,7 +72,7 @@ done --- config location /lua { content_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.say("hello in thread") return "done" @@ -120,13 +120,13 @@ done --- config location /lua { content_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.say("f: hello") return "done" end - local function g() + function g() ngx.sleep(0.2) ngx.say("g: hello") return "done" @@ -200,13 +200,13 @@ f: done --- config location /lua { content_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.say("f: hello") return "done" end - local function g() + function g() ngx.sleep(0.2) ngx.say("g: hello") return "done" @@ -228,7 +228,7 @@ f: done ngx.say("g thread created: ", coroutine.status(tg)) - local ok, res = ngx.thread.wait(tf) + ok, res = ngx.thread.wait(tf) if not ok then ngx.say("failed to wait f: ", res) return @@ -281,7 +281,7 @@ g: done --- config location /lua { content_by_lua ' - local function f() + function f() ngx.say("hello in thread") return "done", 3.14 end @@ -330,7 +330,7 @@ res: done 3.14 --- config location /lua { content_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.say("hello in thread") return "done", 3.14 @@ -378,7 +378,7 @@ res: done 3.14 --- config location /lua { content_by_lua ' - local function f() + function f() ngx.say("hello in thread") error("bad bad!") end @@ -427,7 +427,7 @@ qr/lua user thread aborted: runtime error: content_by_lua\(nginx\.conf:\d+\):4: --- config location /lua { content_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.say("hello in thread") error("bad bad!") @@ -477,12 +477,12 @@ qr/lua user thread aborted: runtime error: content_by_lua\(nginx\.conf:\d+\):5: --- config location /lua { content_by_lua ' - local function g() + function g() ngx.say("hello in thread") return "done" end - local function f() + function f() local t, err = ngx.thread.spawn(g) if not t then ngx.say("failed to spawn thread: ", err) @@ -533,13 +533,13 @@ done --- config location /lua { content_by_lua ' - local function g() + function g() ngx.sleep(0.1) ngx.say("hello in thread") return "done" end - local function f() + function f() local t, err = ngx.thread.spawn(g) if not t then ngx.say("failed to spawn thread: ", err) @@ -593,12 +593,12 @@ done -- local out = function (...) ngx.log(ngx.ERR, ...) end local out = ngx.say - local function f() + function f() out("f: hello") return "f done" end - local function g() + function g() out("g: hello") return "g done" end @@ -668,13 +668,13 @@ g status: zombie -- local out = function (...) ngx.log(ngx.ERR, ...) end local out = ngx.say - local function f() + function f() ngx.sleep(0.1) out("f: hello") return "f done" end - local function g() + function g() ngx.sleep(0.2) out("g: hello") return "g done" @@ -745,13 +745,13 @@ g: hello -- local out = function (...) ngx.log(ngx.ERR, ...) end local out = ngx.say - local function f() + function f() ngx.sleep(0.2) out("f: hello") return "f done" end - local function g() + function g() ngx.sleep(0.1) out("g: hello") return "g done" @@ -822,12 +822,12 @@ f: hello -- local out = function (...) ngx.log(ngx.ERR, ...) end local out = ngx.say - local function f() + function f() out("f: hello") error("f done") end - local function g() + function g() out("g: hello") error("g done") end @@ -896,13 +896,13 @@ qr/lua user thread aborted: runtime error: content_by_lua\(nginx\.conf:\d+\):7: -- local out = function (...) ngx.log(ngx.ERR, ...) end local out = ngx.say - local function f() + function f() ngx.sleep(0.1) out("f: hello") error("f done") end - local function g() + function g() ngx.sleep(0.2) out("g: hello") error("g done") @@ -969,13 +969,13 @@ qr/lua user thread aborted: runtime error: content_by_lua\(nginx\.conf:\d+\):8: --- config location /lua { content_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.say("f: hello") return "done" end - local function g() + function g() ngx.sleep(0.2) ngx.say("g: hello") return "done" @@ -997,7 +997,7 @@ qr/lua user thread aborted: runtime error: content_by_lua\(nginx\.conf:\d+\):8: ngx.say("g thread created: ", coroutine.status(tg)) - local ok, res = ngx.thread.wait(tf, tg) + ok, res = ngx.thread.wait(tf, tg) if not ok then ngx.say("failed to wait: ", res) return @@ -1038,13 +1038,13 @@ res: done --- config location /lua { content_by_lua ' - local function f() + function f() ngx.sleep(0.2) ngx.say("f: hello") return "f done" end - local function g() + function g() ngx.sleep(0.1) ngx.say("g: hello") return "g done" @@ -1066,7 +1066,7 @@ res: done ngx.say("g thread created: ", coroutine.status(tg)) - local ok, res = ngx.thread.wait(tf, tg) + ok, res = ngx.thread.wait(tf, tg) if not ok then ngx.say("failed to wait: ", res) return @@ -1109,12 +1109,12 @@ res: g done content_by_lua ' local t - local function f() + function f() ngx.sleep(0.1) return "done" end - local function g() + function g() t = ngx.thread.spawn(f) end @@ -1154,7 +1154,7 @@ only the parent coroutine can wait on the thread --- config location /lua { content_by_lua ' - local function f() + function f() ngx.sleep(0.1) coroutine.yield() return "done" @@ -1192,7 +1192,7 @@ qr/lua entry thread aborted: runtime error: content_by_lua\(nginx\.conf:\d+\):11 --- config location /lua { content_by_lua ' - local function f() + function f() ngx.sleep(0.1) collectgarbage() error("f done") @@ -1228,7 +1228,7 @@ qr/lua user thread aborted: runtime error: content_by_lua\(nginx\.conf:\d+\):5: --- config location /lua { content_by_lua ' - local function f() + function f() ngx.say("hello in thread") return "done" end @@ -1283,7 +1283,7 @@ failed to run thread: already waited or killed --- config location /lua { content_by_lua ' - local function f() + function f() -- ngx.say("hello in thread") return "done" end diff --git a/debian/modules/http-lua/t/099-c-api.t b/debian/modules/http-lua/t/099-c-api.t index 5033462..a0b375c 100644 --- a/debian/modules/http-lua/t/099-c-api.t +++ b/debian/modules/http-lua/t/099-c-api.t @@ -86,7 +86,7 @@ dogs zone: defined local buf = ffi.new("char[?]", 4) ffi.copy(buf, "dogs", 4) - local zone = ffi.C.ngx_http_lua_find_zone(buf, 4) + zone = ffi.C.ngx_http_lua_find_zone(buf, 4) local val = ffi.new("ngx_http_lua_value_t[?]", 1) @@ -149,7 +149,7 @@ bar: rc=0, type=3, val=3.14159 local buf = ffi.new("char[?]", 4) ffi.copy(buf, "dogs", 4) - local zone = ffi.C.ngx_http_lua_find_zone(buf, 4) + zone = ffi.C.ngx_http_lua_find_zone(buf, 4) local val = ffi.new("ngx_http_lua_value_t[?]", 1) @@ -212,7 +212,7 @@ bar: rc=0, type=1, val=0 local buf = ffi.new("char[?]", 4) ffi.copy(buf, "dogs", 4) - local zone = ffi.C.ngx_http_lua_find_zone(buf, 4) + zone = ffi.C.ngx_http_lua_find_zone(buf, 4) local val = ffi.new("ngx_http_lua_value_t[?]", 1) @@ -272,7 +272,7 @@ bar: rc=-5 local buf = ffi.new("char[?]", 4) ffi.copy(buf, "dogs", 4) - local zone = ffi.C.ngx_http_lua_find_zone(buf, 4) + zone = ffi.C.ngx_http_lua_find_zone(buf, 4) local s = ffi.new("char[?]", 20) @@ -344,7 +344,7 @@ bar: rc=0, type=4, val=, len=0 local buf = ffi.new("char[?]", 4) ffi.copy(buf, "dogs", 4) - local zone = ffi.C.ngx_http_lua_find_zone(buf, 4) + zone = ffi.C.ngx_http_lua_find_zone(buf, 4) local val = ffi.new("ngx_http_lua_value_t[?]", 1) diff --git a/debian/modules/http-lua/t/100-client-abort.t b/debian/modules/http-lua/t/100-client-abort.t index f571387..89c1f6a 100644 --- a/debian/modules/http-lua/t/100-client-abort.t +++ b/debian/modules/http-lua/t/100-client-abort.t @@ -195,7 +195,7 @@ bad things happen location = /sub { proxy_ignore_client_abort on; - proxy_pass http://127.0.0.2:12345/; + proxy_pass http://agentzh.org:12345/; } location = /sleep { @@ -236,7 +236,7 @@ client prematurely closed connection location = /sub { proxy_ignore_client_abort off; - proxy_pass http://127.0.0.2:12345/; + proxy_pass http://agentzh.org:12345/; } --- request GET /t @@ -540,7 +540,7 @@ client prematurely closed connection return end - local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_REDIS_PORT) + ok, err = sock:connect("127.0.0.1", $TEST_NGINX_REDIS_PORT) if not ok then ngx.log(ngx.ERR, "failed to connect: ", err) return diff --git a/debian/modules/http-lua/t/106-timer.t b/debian/modules/http-lua/t/106-timer.t index 7b7c85e..3e4741e 100644 --- a/debian/modules/http-lua/t/106-timer.t +++ b/debian/modules/http-lua/t/106-timer.t @@ -76,7 +76,7 @@ qr/\[lua\] content_by_lua\(nginx\.conf:\d+\):\d+: elapsed: 0\.0(?:4[4-9]|5[0-6]) -=== TEST 2: globals are shared +=== TEST 2: separated global env --- config location /t { content_by_lua ' @@ -104,7 +104,7 @@ F(ngx_http_lua_timer_handler) { --- response_body registered timer -foo = 3 +foo = nil --- wait: 0.1 --- no_error_log @@ -320,7 +320,7 @@ qr/received: Server: \S+/, === TEST 6: tcp cosocket in timer handler (keep-alive connections) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /t { @@ -596,7 +596,7 @@ qr/\[lua\] log_by_lua\(nginx\.conf:\d+\):\d+: elapsed: 0\.0(?:6[4-9]|7[0-6])/, === TEST 10: tcp cosocket in timer handler (keep-alive connections) - log_by_lua --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /t { @@ -693,7 +693,7 @@ qr/go\(\): connected: 1, reused: \d+/, === TEST 11: tcp cosocket in timer handler (keep-alive connections) - header_filter_by_lua --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /t { @@ -799,7 +799,7 @@ qr/go\(\): connected: 1, reused: \d+/, === TEST 12: tcp cosocket in timer handler (keep-alive connections) - body_filter_by_lua --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /t { @@ -912,7 +912,7 @@ qr/go\(\): connected: 1, reused: \d+/, === TEST 13: tcp cosocket in timer handler (keep-alive connections) - set_by_lua --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /t { @@ -1023,7 +1023,7 @@ qr/go\(\): connected: 1, reused: \d+/, content_by_lua ' local cc, cr, cy = coroutine.create, coroutine.resume, coroutine.yield local function f() - local function f() + function f() local cnt = 0 for i = 1, 20 do print("cnt = ", cnt) @@ -1090,7 +1090,7 @@ registered timer ngx.log(ngx.ERR, ...) end local function handle() - local function f() + function f() print("hello in thread") return "done" end diff --git a/debian/modules/http-lua/t/108-timer-safe.t b/debian/modules/http-lua/t/108-timer-safe.t index 758d01a..2795998 100644 --- a/debian/modules/http-lua/t/108-timer-safe.t +++ b/debian/modules/http-lua/t/108-timer-safe.t @@ -229,7 +229,7 @@ qr/received: Server: \S+/, === TEST 4: tcp cosocket in timer handler (keep-alive connections) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /t { @@ -489,7 +489,7 @@ delete thread 2 --- response_body hello world ---- wait: 0.15 +--- wait: 0.1 --- no_error_log [error] [alert] @@ -499,7 +499,7 @@ hello world [ "registered timer", qr/\[lua\] .*? my lua timer handler/, -qr/\[lua\] log_by_lua\(nginx\.conf:\d+\):\d+: elapsed: 0\.0(?:6[4-9]|7[0-9]|8[0-6])/, +qr/\[lua\] log_by_lua\(nginx\.conf:\d+\):\d+: elapsed: 0\.0(?:6[4-9]|7[0-6])/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -508,7 +508,7 @@ qr/\[lua\] log_by_lua\(nginx\.conf:\d+\):\d+: elapsed: 0\.0(?:6[4-9]|7[0-9]|8[0- === TEST 8: tcp cosocket in timer handler (keep-alive connections) - log_by_lua --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /t { @@ -606,7 +606,7 @@ qr/go\(\): connected: 1, reused: \d+/, === TEST 9: tcp cosocket in timer handler (keep-alive connections) - header_filter_by_lua --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /t { @@ -713,7 +713,7 @@ qr/go\(\): connected: 1, reused: \d+/, === TEST 10: tcp cosocket in timer handler (keep-alive connections) - body_filter_by_lua --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /t { @@ -827,7 +827,7 @@ qr/go\(\): connected: 1, reused: \d+/, === TEST 11: tcp cosocket in timer handler (keep-alive connections) - set_by_lua --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /t { @@ -1007,7 +1007,7 @@ registered timer ngx.log(ngx.ERR, ...) end local function handle() - local function f() + function f() print("hello in thread") return "done" end diff --git a/debian/modules/http-lua/t/109-timer-hup.t b/debian/modules/http-lua/t/109-timer-hup.t index 2c197c2..0864046 100644 --- a/debian/modules/http-lua/t/109-timer-hup.t +++ b/debian/modules/http-lua/t/109-timer-hup.t @@ -46,7 +46,7 @@ __DATA__ --- config location /t { content_by_lua ' - local f, err = io.open("$TEST_NGINX_SERVER_ROOT/logs/nginx.pid", "r") + local f, err = io.open("t/servroot/logs/nginx.pid", "r") if not f then ngx.say("failed to open nginx.pid: ", err) return @@ -99,7 +99,7 @@ timer prematurely expired: true --- config location /t { content_by_lua ' - local f, err = io.open("$TEST_NGINX_SERVER_ROOT/logs/nginx.pid", "r") + local f, err = io.open("t/servroot/logs/nginx.pid", "r") if not f then ngx.say("failed to open nginx.pid: ", err) return @@ -163,7 +163,7 @@ timer prematurely expired: true --- config location /t { content_by_lua ' - local f, err = io.open("$TEST_NGINX_SERVER_ROOT/logs/nginx.pid", "r") + local f, err = io.open("t/servroot/logs/nginx.pid", "r") if not f then ngx.say("failed to open nginx.pid: ", err) return @@ -219,7 +219,7 @@ failed to register a new timer after reload: process exiting, context: ngx.timer --- config location /t { content_by_lua ' - local f, err = io.open("$TEST_NGINX_SERVER_ROOT/logs/nginx.pid", "r") + local f, err = io.open("t/servroot/logs/nginx.pid", "r") if not f then ngx.say("failed to open nginx.pid: ", err) return @@ -284,7 +284,7 @@ g: exiting=true --- config location /t { content_by_lua ' - local f, err = io.open("$TEST_NGINX_SERVER_ROOT/logs/nginx.pid", "r") + local f, err = io.open("t/servroot/logs/nginx.pid", "r") if not f then ngx.say("failed to open nginx.pid: ", err) return @@ -363,7 +363,7 @@ lua found 100 pending timers local line, err = sock:receive("*l") until not line or string.find(line, "^%s*$") - local function foo() + function foo() repeat -- Get and read chunk local line, err = sock:receive("*l") @@ -379,7 +379,7 @@ lua found 100 pending timers until len == 0 end - local co = coroutine.create(foo) + co = coroutine.create(foo) repeat local chunk = select(2,coroutine.resume(co)) until chunk == nil @@ -399,7 +399,7 @@ lua found 100 pending timers end local ok, err = ngx.timer.at(1, background_thread) - local f, err = io.open("$TEST_NGINX_SERVER_ROOT/logs/nginx.pid", "r") + local f, err = io.open("t/servroot/logs/nginx.pid", "r") if not f then ngx.say("failed to open nginx.pid: ", err) return @@ -453,7 +453,7 @@ lua found 1 pending timers end if kill then - local f, err = io.open("$TEST_NGINX_SERVER_ROOT/logs/nginx.pid", "r") + local f, err = io.open("t/servroot/logs/nginx.pid", "r") if not f then ngx.log(ngx.ERR, "failed to open nginx.pid: ", err) return diff --git a/debian/modules/http-lua/t/120-re-find.t b/debian/modules/http-lua/t/120-re-find.t index f80ca4f..73e6134 100644 --- a/debian/modules/http-lua/t/120-re-find.t +++ b/debian/modules/http-lua/t/120-re-find.t @@ -622,7 +622,7 @@ matched: 你 >>> a.lua local re = [==[(?i:([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:=|<=>|r?like|sounds\s+like|regexp)([\s'\"`´’‘\(\)]*)?\2|([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp)([\s'\"`´’‘\(\)]*)?(?!\6)([\d\w]+))]==] -local s = string.rep([[ABCDEFG]], 10) +s = string.rep([[ABCDEFG]], 10) local start = ngx.now() @@ -664,7 +664,7 @@ error: pcre_exec() failed: -8 >>> a.lua local re = [==[(?i:([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:=|<=>|r?like|sounds\s+like|regexp)([\s'\"`´’‘\(\)]*)?\2|([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp)([\s'\"`´’‘\(\)]*)?(?!\6)([\d\w]+))]==] -local s = string.rep([[ABCDEFG]], 10) +s = string.rep([[ABCDEFG]], 10) local start = ngx.now() diff --git a/debian/modules/http-lua/t/123-lua-path.t b/debian/modules/http-lua/t/123-lua-path.t index e30132f..23681a9 100644 --- a/debian/modules/http-lua/t/123-lua-path.t +++ b/debian/modules/http-lua/t/123-lua-path.t @@ -11,7 +11,7 @@ repeat_each(2); plan tests => repeat_each() * (blocks() * 3 + 1); -$ENV{LUA_PATH} = "../lua-resty-core/lib/?.lua;../lua-resty-lrucache/lib/?.lua;/foo/bar/baz"; +$ENV{LUA_PATH} = "/foo/bar/baz"; $ENV{LUA_CPATH} = "/baz/bar/foo"; #no_diff(); #no_long_string(); @@ -36,8 +36,8 @@ env LUA_CPATH; } --- request GET /lua ---- response_body_like -(?:\.\.\/lua-resty-core\/lib\/\?\.lua;\.\.\/lua-resty-lrucache\/lib\/\?\.lua;){1,2}\/foo\/bar\/baz +--- response_body +/foo/bar/baz /baz/bar/foo --- no_error_log @@ -60,8 +60,8 @@ env LUA_CPATH; } --- request GET /lua ---- response_body_like -(?:\.\.\/lua-resty-core\/lib\/\?\.lua;\.\.\/lua-resty-lrucache\/lib\/\?\.lua;){1,2}\/foo\/bar\/baz +--- response_body +/foo/bar/baz /baz/bar/foo --- no_error_log diff --git a/debian/modules/http-lua/t/124-init-worker.t b/debian/modules/http-lua/t/124-init-worker.t index b648d55..9b2a91f 100644 --- a/debian/modules/http-lua/t/124-init-worker.t +++ b/debian/modules/http-lua/t/124-init-worker.t @@ -521,11 +521,12 @@ warn(): Thu, 01 Jan 1970 01:34:38 GMT } --- request GET /t ---- response_body_like +--- response_body +timer created connected: 1 request sent: 56 -first line received: HTTP\/1\.1 200 OK -second line received: (?:Date|Server): .*? +first line received: HTTP/1.1 200 OK +second line received: Server: openresty --- no_error_log [error] --- timeout: 10 @@ -549,7 +550,6 @@ second line received: (?:Date|Server): .*? else say("connect: ", ok, " ", err) end - done = true end local ok, err = ngx.timer.at(0, handler) @@ -600,7 +600,6 @@ qr/connect\(\) failed \(\d+: Connection refused\), context: ngx\.timer$/ else say("connect: ", ok, " ", err) end - done = true end local ok, err = ngx.timer.at(0, handler) @@ -651,7 +650,6 @@ qr/connect\(\) failed \(\d+: Connection refused\)/ else say("connect: ", ok, " ", err) end - done = true end local ok, err = ngx.timer.at(0, handler) diff --git a/debian/modules/http-lua/t/126-shdict-frag.t b/debian/modules/http-lua/t/126-shdict-frag.t index 33646d1..5a2aff8 100644 --- a/debian/modules/http-lua/t/126-shdict-frag.t +++ b/debian/modules/http-lua/t/126-shdict-frag.t @@ -1240,8 +1240,8 @@ failed to safe set baz: no memory local key = "mylittlekey" .. rand(maxkeyidx) local ok, err = dogs:get(key) if not ok or rand() > 0.6 then - local sz = rand(maxsz) - local val = rep("a", sz) + sz = rand(maxsz) + val = rep("a", sz) local ok, err, forcible = dogs:set(key, val) if err then ngx.log(ngx.ERR, "failed to set key: ", err) diff --git a/debian/modules/http-lua/t/127-uthread-kill.t b/debian/modules/http-lua/t/127-uthread-kill.t index 5542153..cc43c62 100644 --- a/debian/modules/http-lua/t/127-uthread-kill.t +++ b/debian/modules/http-lua/t/127-uthread-kill.t @@ -23,7 +23,7 @@ __DATA__ --- config location /lua { content_by_lua ' - local function f() + function f() ngx.say("hello from f()") ngx.sleep(1) end @@ -81,7 +81,7 @@ lua clean up the timer for pending ngx.sleep --- config location /lua { content_by_lua ' - local function f() + function f() ngx.say("hello from f()") ngx.sleep(0.001) return 32 @@ -138,12 +138,12 @@ lua clean up the timer for pending ngx.sleep === TEST 3: kill pending resolver --- config - resolver 127.0.0.2:12345; + resolver agentzh.org:12345; location /lua { content_by_lua ' - local function f() + function f() local sock = ngx.socket.tcp() - sock:connect("some.127.0.0.2", 12345) + sock:connect("some.agentzh.org", 12345) end local t, err = ngx.thread.spawn(f) @@ -194,13 +194,13 @@ resolve name done: -2 location /lua { content_by_lua ' local ready = false - local function f() + function f() local sock = ngx.socket.tcp() sock:connect("agentzh.org", 80) sock:close() ready = true sock:settimeout(10000) - sock:connect("127.0.0.2", 12345) + sock:connect("agentzh.org", 12345) end local t, err = ngx.thread.spawn(f) @@ -262,7 +262,7 @@ lua finalize socket location = /t { content_by_lua ' - local function f() + function f() ngx.location.capture("/sub") end @@ -309,11 +309,11 @@ lua tcp socket abort resolver location = /t { content_by_lua ' - local function f() + function f() ngx.location.capture("/sub") end - local function g() + function g() ngx.sleep(0.3) end @@ -376,7 +376,7 @@ lua tcp socket abort resolver location = /t { content_by_lua ' local ready = false - local function f() + function f() ngx.location.capture("/sub") ready = true ngx.sleep(0.5) @@ -424,7 +424,7 @@ lua tcp socket abort resolver --- config location = /t { content_by_lua ' - local function f() + function f() return end @@ -473,7 +473,7 @@ lua tcp socket abort resolver ngx.say("killed main thread.") end - local function f() + function f() local ok, err = ngx.thread.kill(coroutine.running()) if not ok then ngx.say("failed to kill user thread: ", err) diff --git a/debian/modules/http-lua/t/128-duplex-tcp-socket.t b/debian/modules/http-lua/t/128-duplex-tcp-socket.t index 22b9f03..aed560c 100644 --- a/debian/modules/http-lua/t/128-duplex-tcp-socket.t +++ b/debian/modules/http-lua/t/128-duplex-tcp-socket.t @@ -396,7 +396,7 @@ F(ngx_http_lua_socket_tcp_finalize_write_part) { end sock:settimeout(300) - local ok, err = sock:connect("127.0.0.2", 12345) + local ok, err = sock:connect("172.105.207.225", 12345) ngx.say("connect: ", ok, " ", err) local ok, err = sock:close() @@ -425,7 +425,7 @@ close: nil closed --- config server_tokens off; lua_socket_log_errors off; - resolver 127.0.0.2:12345; + resolver agentzh.org:12345; resolver_timeout 300ms; location /t { content_by_lua ' @@ -459,7 +459,7 @@ close: nil closed end sock:settimeout(300) - local ok, err = sock:connect("some2.agentzh.org", 80) + local ok, err = sock:connect("some2.agentzh.org", 12345) ngx.say("connect: ", ok, " ", err) local ok, err = sock:close() diff --git a/debian/modules/http-lua/t/129-ssl-socket.t b/debian/modules/http-lua/t/129-ssl-socket.t index f2fa26b..3f05640 100644 --- a/debian/modules/http-lua/t/129-ssl-socket.t +++ b/debian/modules/http-lua/t/129-ssl-socket.t @@ -301,7 +301,7 @@ SSL reused session content_by_lua ' local sock = ngx.socket.tcp() - sock:settimeout(7000) + sock:settimeout(2000) do @@ -380,7 +380,7 @@ lua ssl free session --- no_error_log [error] [alert] ---- timeout: 10 +--- timeout: 5 @@ -573,7 +573,7 @@ SSL reused session ngx.say("ssl handshake: ", type(session)) - local req = "GET /en/linux-packages.html HTTP/1.1\\r\\nHost: openresty.com\\r\\nConnection: close\\r\\n\\r\\n" + local req = "GET / HTTP/1.1\\r\\nHost: agentzh.org\\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) @@ -602,7 +602,7 @@ GET /t --- response_body connected: 1 ssl handshake: userdata -sent http request: 80 bytes. +sent http request: 56 bytes. received: HTTP/1.1 404 Not Found close: 1 nil @@ -1333,13 +1333,13 @@ failed to send http request: closed --- grep_error_log_out --- error_log eval [ -qr/\[(crit|error)\] .*?SSL_do_handshake\(\) failed .*?(unsupported protocol|no protocols available)/, +qr/\[crit\] .*?SSL_do_handshake\(\) failed .*?(unsupported protocol|no protocols available)/, 'lua ssl server name: "openresty.org"', ] --- no_error_log SSL reused session +[error] [alert] -[emerg] --- timeout: 5 @@ -2508,7 +2508,7 @@ SSL reused session content_by_lua_block { local sock = ngx.socket.tcp() - sock:settimeout(7000) + sock:settimeout(2000) local ok, err = sock:connect("openresty.org", 443) if not ok then @@ -2529,4 +2529,4 @@ GET /t qr/\[error\] .* ngx.socket sslhandshake: expecting 1 ~ 5 arguments \(including the object\), but seen 0/ --- no_error_log [alert] ---- timeout: 10 +--- timeout: 5 diff --git a/debian/modules/http-lua/t/130-internal-api.t b/debian/modules/http-lua/t/130-internal-api.t index 2158e87..eba0980 100644 --- a/debian/modules/http-lua/t/130-internal-api.t +++ b/debian/modules/http-lua/t/130-internal-api.t @@ -8,7 +8,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * blocks() * 3; +plan tests => repeat_each() * 3; #no_diff(); no_long_string(); @@ -19,7 +19,12 @@ run_tests(); __DATA__ -=== TEST 1: req +=== TEST 1: __ngx_req and __ngx_cycle +--- http_config + init_by_lua ' + my_cycle = __ngx_cycle + '; + --- config location = /t { content_by_lua ' @@ -27,14 +32,18 @@ __DATA__ local function tonum(ud) return tonumber(ffi.cast("uintptr_t", ud)) end - ngx.say(string.format("content req=%#x", tonum(exdata()))) + ngx.say(string.format("init: cycle=%#x", tonum(my_cycle))) + ngx.say(string.format("content cycle=%#x", tonum(__ngx_cycle))) + ngx.say(string.format("content req=%#x", tonum(__ngx_req))) '; } --- request GET /t --- response_body_like chop -^content req=0x[a-f0-9]{4,} +^init: cycle=(0x[a-f0-9]{4,}) +content cycle=\1 +content req=0x[a-f0-9]{4,} $ --- no_error_log [error] diff --git a/debian/modules/http-lua/t/134-worker-count-5.t b/debian/modules/http-lua/t/134-worker-count-5.t index ec6d0e7..b257c12 100644 --- a/debian/modules/http-lua/t/134-worker-count-5.t +++ b/debian/modules/http-lua/t/134-worker-count-5.t @@ -3,7 +3,7 @@ use Test::Nginx::Socket::Lua; #worker_connections(1014); -master_on(); +#master_on(); workers(5); #log_level('warn'); @@ -55,7 +55,7 @@ workers: 5 === TEST 3: init_by_lua + module (github #681) --- http_config - lua_package_path "$TEST_NGINX_SERVER_ROOT/html/?.lua;;"; + lua_package_path "t/servroot/html/?.lua;;"; init_by_lua_block { local blah = require "file" diff --git a/debian/modules/http-lua/t/138-balancer.t b/debian/modules/http-lua/t/138-balancer.t index 151db7b..0aba66d 100644 --- a/debian/modules/http-lua/t/138-balancer.t +++ b/debian/modules/http-lua/t/138-balancer.t @@ -362,6 +362,8 @@ me: 101 === TEST 13: lua subrequests --- http_config + lua_package_path "t/servroot/html/?.lua;;"; + lua_code_cache off; upstream backend { diff --git a/debian/modules/http-lua/t/139-ssl-cert-by.t b/debian/modules/http-lua/t/139-ssl-cert-by.t index bebbdb2..a65d703 100644 --- a/debian/modules/http-lua/t/139-ssl-cert-by.t +++ b/debian/modules/http-lua/t/139-ssl-cert-by.t @@ -1278,7 +1278,7 @@ lua ssl server name: "test.com" listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_certificate_by_lua_block { - local function f() + function f() ngx.sleep(0.01) print("uthread: hello in thread") return "done" diff --git a/debian/modules/http-lua/t/140-ssl-c-api.t b/debian/modules/http-lua/t/140-ssl-c-api.t index a77f5d4..8734d14 100644 --- a/debian/modules/http-lua/t/140-ssl-c-api.t +++ b/debian/modules/http-lua/t/140-ssl-c-api.t @@ -10,7 +10,6 @@ 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"); - } else { plan tests => repeat_each() * (blocks() * 5 + 1); } @@ -69,7 +68,7 @@ _EOC_ my $http_config = $block->http_config || ''; $http_config .= <<'_EOC_'; -lua_package_path "$prefix/html/?.lua;../lua-resty-core/lib/?.lua;;"; +lua_package_path "$prefix/html/?.lua;;"; _EOC_ $block->set_value("http_config", $http_config); }); @@ -92,8 +91,8 @@ __DATA__ local errmsg = ffi.new("char *[1]") - local r = require "resty.core.base" .get_request() - if r == nil then + local r = getfenv(0).__ngx_req + if not r then ngx.log(ngx.ERR, "no request found") return end @@ -246,8 +245,8 @@ lua ssl server name: "test.com" local errmsg = ffi.new("char *[1]") - local r = require "resty.core.base" .get_request() - if r == nil then + local r = getfenv(0).__ngx_req + if not r then ngx.log(ngx.ERR, "no request found") return end @@ -400,8 +399,8 @@ lua ssl server name: "test.com" local errmsg = ffi.new("char *[1]") - local r = require "resty.core.base" .get_request() - if r == nil then + local r = getfenv(0).__ngx_req + if not r then ngx.log(ngx.ERR, "no request found") return end @@ -529,8 +528,8 @@ failed to parse PEM priv key: PEM_read_bio_PrivateKey() failed local errmsg = ffi.new("char *[1]") - local r = require "resty.core.base" .get_request() - if r == nil then + local r = getfenv(0).__ngx_req + if not r then ngx.log(ngx.ERR, "no request found") return end @@ -679,8 +678,8 @@ lua ssl server name: "test.com" local errmsg = ffi.new("char *[1]") - local r = require "resty.core.base" .get_request() - if r == nil then + local r = getfenv(0).__ngx_req + if not r then ngx.log(ngx.ERR, "no request found") return end diff --git a/debian/modules/http-lua/t/143-ssl-session-fetch.t b/debian/modules/http-lua/t/143-ssl-session-fetch.t index 78a66cf..4dc992d 100644 --- a/debian/modules/http-lua/t/143-ssl-session-fetch.t +++ b/debian/modules/http-lua/t/143-ssl-session-fetch.t @@ -1114,108 +1114,3 @@ qr/ssl_session_fetch_by_lua_block:1: ssl fetch sess by lua is running!/s [error] [alert] [emerg] - - - -=== TEST 14: keep global variable in ssl_session_(store|fetch)_by_lua when OpenResty LuaJIT is used ---- http_config - ssl_session_store_by_lua_block { - ngx.log(ngx.WARN, "new foo: ", foo) - if not foo then - foo = 1 - else - ngx.log(ngx.WARN, "old foo: ", foo) - foo = foo + 1 - end - } - ssl_session_fetch_by_lua_block { - ngx.log(ngx.WARN, "new bar: ", foo) - if not bar then - bar = 1 - else - ngx.log(ngx.WARN, "old bar: ", bar) - bar = bar + 1 - end - } - - 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_session_tickets off; - - server_tokens off; - location /foo { - content_by_lua_block { - ngx.say("foo: ", foo) - ngx.say("bar: ", bar) - } - } - } ---- 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 - - 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 - - package.loaded.session = 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 - - while true do - local line, err = sock:receive() - if not line then - -- ngx.say("failed to receive response status line: ", err) - break - end - - local m, err = ngx.re.match(line, "^foo: (.*)$", "jo") - if err then - ngx.say("failed to match line: ", err) - end - - if m and m[1] then - ngx.print(m[1]) - end - end - - local ok, err = sock:close() - ngx.say("done") - end -- do - } - } - ---- request -GET /t ---- response_body_like chomp -\A[123]done\n\z ---- grep_error_log eval: qr/old (foo|bar): \d+/ ---- grep_error_log_out eval -["", "old foo: 1\n", "old bar: 1\nold foo: 2\n"] ---- no_error_log -[error] -[alert] -[emerg] diff --git a/debian/modules/http-lua/t/147-tcp-socket-timeouts.t b/debian/modules/http-lua/t/147-tcp-socket-timeouts.t index 8566c0b..4ebc8f3 100644 --- a/debian/modules/http-lua/t/147-tcp-socket-timeouts.t +++ b/debian/modules/http-lua/t/147-tcp-socket-timeouts.t @@ -323,7 +323,7 @@ lua tcp socket write timed out sock:settimeouts(100, 100, 100) - local ok, err = sock:connect("127.0.0.2", 12345) + local ok, err = sock:connect("agentzh.org", 12345) ngx.say("connect: ", ok, " ", err) local bytes @@ -346,7 +346,7 @@ send: nil closed receive: nil closed close: nil closed --- error_log -lua tcp socket connect timed out, when connecting to 127.0.0.2:12345 +lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 --- timeout: 10 @@ -411,7 +411,7 @@ lua tcp socket connect timed out, when connecting to 127.0.0.2:12345 local chunk = 4 - local function read() + function read() sock:settimeout(200) -- read: 200 ms local data, err = sock:receive(content_length) @@ -506,7 +506,7 @@ failed to receive data: timeout local chunk = 4 - local function read() + function read() local data, err = sock:receive(content_length) if not data then ngx.log(ngx.ERR, "failed to receive data: ", err) diff --git a/debian/modules/http-lua/t/152-timer-every.t b/debian/modules/http-lua/t/152-timer-every.t index 7b42d2d..c8d62e7 100644 --- a/debian/modules/http-lua/t/152-timer-every.t +++ b/debian/modules/http-lua/t/152-timer-every.t @@ -63,7 +63,7 @@ qr/\[lua\] content_by_lua\(nginx\.conf:\d+\):\d+: elapsed: 0\.(?:09|10)\d*, cont -=== TEST 2: shared global env +=== TEST 2: separated global env --- config location /t { content_by_lua_block { @@ -84,7 +84,7 @@ qr/\[lua\] content_by_lua\(nginx\.conf:\d+\):\d+: elapsed: 0\.(?:09|10)\d*, cont --- request GET /t --- response_body -foo = 3 +foo = nil --- wait: 0.12 --- no_error_log [error] diff --git a/debian/modules/http-lua/t/153-semaphore-hup.t b/debian/modules/http-lua/t/153-semaphore-hup.t index 5c271a4..c85a21d 100644 --- a/debian/modules/http-lua/t/153-semaphore-hup.t +++ b/debian/modules/http-lua/t/153-semaphore-hup.t @@ -67,7 +67,7 @@ add_block_preprocessor(sub { return end - local shdict = ngx.shared.shdict + shdict = ngx.shared.shdict local success = shdict:add("reloaded", 1) if not success then return diff --git a/debian/modules/http-lua/t/156-slow-network.t b/debian/modules/http-lua/t/156-slow-network.t deleted file mode 100644 index 2d80506..0000000 --- a/debian/modules/http-lua/t/156-slow-network.t +++ /dev/null @@ -1,138 +0,0 @@ -BEGIN { - if (!defined $ENV{LD_PRELOAD}) { - $ENV{LD_PRELOAD} = ''; - } - - if ($ENV{LD_PRELOAD} !~ /\bmockeagain\.so\b/) { - $ENV{LD_PRELOAD} = "mockeagain.so $ENV{LD_PRELOAD}"; - } - - if ($ENV{MOCKEAGAIN} eq 'r') { - $ENV{MOCKEAGAIN} = 'rw'; - - } else { - $ENV{MOCKEAGAIN} = 'w'; - } - - $ENV{TEST_NGINX_EVENT_TYPE} = 'poll'; -} - -use Test::Nginx::Socket::Lua; - -repeat_each(2); - -plan tests => repeat_each() * (blocks() * 4); - -add_block_preprocessor(sub { - my $block = shift; - - if (!defined $block->error_log) { - $block->set_value("no_error_log", "[error]"); - } - - if (!defined $block->request) { - $block->set_value("request", "GET /t"); - } - -}); - - -log_level("debug"); -no_long_string(); -#no_diff(); -run_tests(); - -__DATA__ - -=== TEST 1: receiveany returns anything once socket receives ---- config - server_tokens off; - location = /t { - set $port $TEST_NGINX_SERVER_PORT; - content_by_lua_block { - local sock = ngx.socket.tcp() - sock:settimeout(500) - assert(sock:connect("127.0.0.1", ngx.var.port)) - local req = { - 'GET /foo HTTP/1.0\r\n', - 'Host: localhost\r\n', - 'Connection: close\r\n\r\n', - } - local ok, err = sock:send(req) - if not ok then - ngx.say("send request failed: ", err) - return - end - - - -- skip http header - while true do - local data, err, _ = sock:receive('*l') - if err then - ngx.say('unexpected error occurs when receiving http head: ' .. err) - return - end - if #data == 0 then -- read last line of head - break - end - end - - -- receive http body - while true do - local data, err = sock:receiveany(1024) - if err then - if err ~= 'closed' then - ngx.say('unexpected err: ', err) - end - break - end - ngx.say(data) - end - - sock:close() - } - } - - location = /foo { - content_by_lua_block { - local resp = { - '1', - 'hello', - } - - local length = 0 - for _, v in ipairs(resp) do - length = length + #v - end - - -- flush http header - ngx.header['Content-Length'] = length - ngx.flush(true) - ngx.sleep(0.01) - - -- send http body bytes by bytes - for _, v in ipairs(resp) do - ngx.print(v) - ngx.flush(true) - ngx.sleep(0.01) - end - } - } - ---- response_body -1 -h -e -l -l -o ---- grep_error_log eval -qr/lua tcp socket read any/ ---- grep_error_log_out -lua tcp socket read any -lua tcp socket read any -lua tcp socket read any -lua tcp socket read any -lua tcp socket read any -lua tcp socket read any -lua tcp socket read any diff --git a/debian/modules/http-lua/t/157-socket-keepalive-hup.t b/debian/modules/http-lua/t/157-socket-keepalive-hup.t deleted file mode 100644 index 357bb59..0000000 --- a/debian/modules/http-lua/t/157-socket-keepalive-hup.t +++ /dev/null @@ -1,91 +0,0 @@ -# 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 $SkipReason ? (skip_all => $SkipReason) : (); - -repeat_each(2); - -plan tests => repeat_each() * (blocks() * 8); - -#no_diff(); -no_long_string(); - -worker_connections(1024); -run_tests(); - -__DATA__ - -=== TEST 1: exiting ---- config - location /t { - set $port $TEST_NGINX_SERVER_PORT; - - content_by_lua_block { - local f, err = io.open("$TEST_NGINX_SERVER_ROOT/logs/nginx.pid", "r") - if not f then - ngx.say("failed to open nginx.pid: ", err) - return - end - - local pid = f:read() - -- ngx.say("master pid: [", pid, "]") - - f:close() - - local i = 0 - local port = ngx.var.port - - local function f(premature) - print("timer prematurely expired: ", premature) - - local sock = ngx.socket.tcp() - - local ok, err = sock:connect("127.0.0.1", port) - if not ok then - print("failed to connect: ", err) - return - end - - local ok, err = sock:setkeepalive() - if not ok then - print("failed to setkeepalive: ", err) - return - end - - print("setkeepalive successfully") - end - local ok, err = ngx.timer.at(3, f) - if not ok then - ngx.say("failed to set timer: ", err) - return - end - ngx.say("registered timer") - os.execute("kill -HUP " .. pid) - } - } ---- request -GET /t - ---- response_body -registered timer - ---- wait: 0.3 ---- no_error_log -[error] -[alert] -[crit] ---- error_log -timer prematurely expired: true -setkeepalive successfully -lua tcp socket set keepalive while process exiting, closing connection diff --git a/debian/modules/http-lua/t/158-global-var.t b/debian/modules/http-lua/t/158-global-var.t deleted file mode 100644 index 414a43a..0000000 --- a/debian/modules/http-lua/t/158-global-var.t +++ /dev/null @@ -1,508 +0,0 @@ -# vim:set ft= ts=4 sw=4 et fdm=marker: - -use Test::Nginx::Socket::Lua; - -log_level('debug'); - -repeat_each(2); - -plan tests => repeat_each() * (blocks() * 3 + 14); - -our $HtmlDir = html_dir; - -$ENV{TEST_NGINX_HTML_DIR} ||= html_dir(); - -no_long_string(); - -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 $TestCertificate = read_file("t/cert/test.crt"); -our $TestCertificateKey = read_file("t/cert/test.key"); - -add_block_preprocessor(sub { - my $block = shift; - - if (!defined $block->error_log) { - $block->set_value("no_error_log", "[error]"); - } - - if (!defined $block->request) { - $block->set_value("request", "GET /t"); - } - -}); - -run_tests(); - -__DATA__ - -=== TEST 1: set_by_lua ---- config - location /t { - set_by_lua_block $res { - if not foo then - foo = 1 - else - ngx.log(ngx.WARN, "old foo: ", foo) - foo = foo + 1 - end - return foo - } - echo $res; - } ---- 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, )/ ---- 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"] - - - -=== TEST 2: rewrite_by_lua ---- config - location /t { - rewrite_by_lua_block { - if not foo then - foo = 1 - else - ngx.log(ngx.WARN, "old foo: ", foo) - foo = foo + 1 - end - ngx.say(foo) - } - } ---- response_body_like chomp -\A[12]\n\z ---- grep_error_log eval -qr/(old foo: \d+|\[\w+\].*?writing a global lua variable \('[^'\s]+'\)|\w+_by_lua\(.*?\):\d+: in main chunk, )/ ---- grep_error_log_out eval -[qr/\A\[warn\] .*?writing a global lua variable \('foo'\) -rewrite_by_lua\(nginx\.conf:48\):3: in main chunk, \n\z/, "old foo: 1\n"] - - - -=== TEST 3: access_by_lua ---- config - location /t { - access_by_lua_block { - if not foo then - foo = 1 - else - ngx.log(ngx.WARN, "old foo: ", foo) - foo = foo + 1 - end - ngx.say(foo) - } - } ---- response_body_like chomp -\A[12]\n\z ---- grep_error_log eval -qr/(old foo: \d+|\[\w+\].*?writing a global lua variable \('[^'\s]+'\)|\w+_by_lua\(.*?\):\d+: in main chunk, )/ ---- grep_error_log_out eval -[qr/\A\[warn\] .*?writing a global lua variable \('foo'\) -access_by_lua\(nginx\.conf:48\):3: in main chunk, \n\z/, "old foo: 1\n"] - - - -=== TEST 4: content_by_lua ---- config - location /t { - content_by_lua_block { - if not foo then - foo = 1 - else - ngx.log(ngx.WARN, "old foo: ", foo) - foo = foo + 1 - end - ngx.say(foo) - } - } ---- response_body_like chomp -\A[12]\n\z ---- grep_error_log eval -qr/(old foo: \d+|\[\w+\].*?writing a global lua variable \('[^'\s]+'\)|\w+_by_lua\(.*?\):\d+: in main chunk, )/ ---- grep_error_log_out eval -[qr/\A\[warn\] .*?writing a global lua variable \('foo'\) -content_by_lua\(nginx\.conf:48\):3: in main chunk, \n\z/, "old foo: 1\n"] - - - -=== TEST 5: header_filter_by_lua ---- config - location /t { - content_by_lua_block { - ngx.say(foo) - } - header_filter_by_lua_block { - if not foo then - foo = 1 - else - ngx.log(ngx.WARN, "old foo: ", foo) - foo = foo + 1 - end - } - } ---- 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, )/ ---- 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"] - - - -=== TEST 6: body_filter_by_lua ---- config - location /t { - content_by_lua_block { - ngx.say(foo) - } - body_filter_by_lua_block { - if not foo then - foo = 1 - else - ngx.log(ngx.WARN, "old foo: ", foo) - foo = foo + 1 - end - } - } ---- 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, )/ ---- grep_error_log_out eval -[qr/\[warn\] .*?writing a global lua variable \('foo'\) -body_filter_by_lua:3: in main chunk, -old foo: 1\n\z/, "old foo: 2\nold foo: 3\n"] - - - -=== TEST 7: log_by_lua ---- config - location /t { - content_by_lua_block { - ngx.say(foo) - } - log_by_lua_block { - if not foo then - foo = 1 - else - ngx.log(ngx.WARN, "old foo: ", foo) - foo = foo + 1 - end - } - } ---- 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)/ ---- grep_error_log_out eval -[qr/\A\[warn\] .*?writing a global lua variable \('foo'\) -log_by_lua\(nginx\.conf:50\):3: in main chunk\n\z/, "old foo: 1\n"] - - - -=== TEST 8: ssl_certificate_by_lua ---- http_config - server { - listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; - server_name test.com; - ssl_certificate_by_lua_block { - if not foo then - foo = 1 - else - ngx.log(ngx.WARN, "old foo: ", foo) - foo = foo + 1 - end - } - ssl_certificate ../../cert/test.crt; - ssl_certificate_key ../../cert/test.key; - - server_tokens off; - location /foo { - content_by_lua_block { - ngx.say("foo: ", foo) - } - } - } ---- 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 - - local m, err = ngx.re.match(line, "^foo: (.*)$", "jo") - if err then - ngx.say("failed to match line: ", err) - end - - if m and m[1] then - ngx.print(m[1]) - end - end - - local ok, err = sock:close() - ngx.say("done") - end -- do - } - } - ---- 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)/ ---- 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"] - - - -=== TEST 9: timer ---- config - location /t { - content_by_lua_block { - local function f() - if not foo then - foo = 1 - else - ngx.log(ngx.WARN, "old foo: ", foo) - foo = foo + 1 - end - end - local ok, err = ngx.timer.at(0, f) - if not ok then - ngx.say("failed to set timer: ", err) - return - end - ngx.sleep(0.01) - ngx.say(foo) - } - } ---- response_body_like chomp -\A[12]\n\z ---- grep_error_log eval -qr/(old foo: \d+|\[\w+\].*?writing a global lua variable \('[^'\s]+'\)|\w+_by_lua\(.*?\):\d+: in\b)/ ---- grep_error_log_out eval -[qr/\A\[warn\] .*?writing a global lua variable \('foo'\) -content_by_lua\(nginx\.conf:56\):4: in\n\z/, "old foo: 1\n"] - - - -=== TEST 10: init_by_lua ---- http_config - init_by_lua_block { - foo = 1 - } ---- config - location /t { - content_by_lua_block { - if not foo then - foo = 1 - else - ngx.log(ngx.WARN, "old foo: ", foo) - foo = foo + 1 - end - ngx.say(foo) - } - } ---- response_body_like chomp -\A[23]\n\z ---- grep_error_log eval: qr/old foo: \d+/ ---- grep_error_log_out eval -["old foo: 1\n", "old foo: 2\n"] - - - -=== TEST 11: init_worker_by_lua ---- http_config - init_worker_by_lua_block { - if not foo then - foo = 1 - else - ngx.log(ngx.WARN, "old foo: ", foo) - foo = foo + 1 - end - } ---- config - location /t { - content_by_lua_block { - if not foo then - foo = 1 - else - ngx.log(ngx.WARN, "old foo: ", foo) - foo = foo + 1 - end - ngx.say(foo) - } - } ---- response_body_like chomp -\A[23]\n\z ---- grep_error_log eval: qr/old foo: \d+/ ---- grep_error_log_out eval -["old foo: 1\n", "old foo: 2\n"] - - - -=== TEST 12: init_by_lua + init_worker_by_lua ---- http_config - init_by_lua_block { - if not foo then - foo = 1 - else - ngx.log(ngx.WARN, "old foo: ", foo) - foo = foo + 1 - end - } - init_worker_by_lua_block { - if not foo then - foo = 1 - else - ngx.log(ngx.WARN, "old foo: ", foo) - foo = foo + 1 - end - } ---- config - location /t { - content_by_lua_block { - if not foo then - foo = 1 - else - ngx.log(ngx.WARN, "old foo: ", foo) - foo = foo + 1 - end - ngx.say(foo) - } - } ---- response_body_like chomp -\A[34]\n\z ---- grep_error_log eval: qr/old foo: \d+/ ---- grep_error_log_out eval -["old foo: 1\nold foo: 2\n", "old foo: 3\n"] - - - -=== TEST 13: don't show warn messages in init/init_worker ---- http_config - init_by_lua_block { - foo = 1 - } - - init_worker_by_lua_block { - bar = 2 - } ---- config - location /t { - content_by_lua_block { - ngx.say(foo) - ngx.say(bar) - } - } ---- response_body -1 -2 ---- no_error_log -setting global variable - - - -=== TEST 14: uthread ---- config - location /t { - content_by_lua_block { - local function f() - if not foo then - foo = 1 - else - ngx.log(ngx.WARN, "old foo: ", foo) - foo = foo + 1 - end - end - local ok, err = ngx.thread.spawn(f) - if not ok then - ngx.say("failed to set timer: ", err) - return - end - ngx.sleep(0.01) - ngx.say(foo) - } - } ---- response_body_like chomp -\A[12]\n\z ---- grep_error_log eval -qr/(old foo: \d+|writing a global lua variable \('\w+'\))/ ---- grep_error_log_out eval -["writing a global lua variable \('foo'\)\n", "old foo: 1\n"] - - - -=== TEST 15: balancer_by_lua ---- http_config - upstream backend { - server 0.0.0.1; - balancer_by_lua_block { - if not foo then - foo = 1 - else - ngx.log(ngx.WARN, "old foo: ", foo) - foo = foo + 1 - end - } - } ---- config - location = /t { - proxy_pass http://backend; - } ---- response_body_like: 502 Bad Gateway ---- error_code: 502 ---- error_log eval -qr/\[crit\].*?\Qconnect() to 0.0.0.1:80 failed\E/ ---- grep_error_log eval: qr/(old foo: \d+|writing a global lua variable \('\w+'\))/ ---- grep_error_log_out eval -["writing a global lua variable \('foo'\)\n", "old foo: 1\n"] diff --git a/debian/modules/http-lua/t/159-sa-restart.t b/debian/modules/http-lua/t/159-sa-restart.t deleted file mode 100644 index a0f0c0e..0000000 --- a/debian/modules/http-lua/t/159-sa-restart.t +++ /dev/null @@ -1,180 +0,0 @@ -# vim:set ft= ts=4 sw=4 et fdm=marker: - -use Test::Nginx::Socket::Lua; - -add_block_preprocessor(sub { - my $block = shift; - - my $http_config = $block->http_config || ''; - - $http_config .= <<_EOC_; - init_by_lua_block { - function test_sa_restart() - local signals = { - --"HUP", - --"INFO", - --"XCPU", - --"USR1", - --"USR2", - "ALRM", - --"INT", - "IO", - "CHLD", - --"WINCH", - } - - for _, signame in ipairs(signals) do - local cmd = string.format("kill -s %s %d && sleep 0.01", - signame, ngx.worker.pid()) - local err = select(2, io.popen(cmd):read("*a")) - if err then - error("SIG" .. signame .. " caused: " .. err) - end - end - end - } -_EOC_ - - $block->set_value("http_config", $http_config); - - if (!defined $block->config) { - my $config = <<_EOC_; - location /t { - echo ok; - } -_EOC_ - - $block->set_value("config", $config); - } - - if (!defined $block->request) { - $block->set_value("request", "GET /t"); - } - - if (!defined $block->response_body) { - $block->set_value("ignore_response_body"); - } - - if (!defined $block->no_error_log) { - $block->set_value("no_error_log", "[error]"); - } -}); - -plan tests => repeat_each() * (blocks() * 2 + 1); - -no_long_string(); -run_tests(); - -__DATA__ - -=== TEST 1: lua_sa_restart default - sets SA_RESTART in init_worker_by_lua* ---- http_config - init_worker_by_lua_block { - test_sa_restart() - } - - - -=== TEST 2: lua_sa_restart off - does not set SA_RESTART ---- http_config - lua_sa_restart off; - - init_worker_by_lua_block { - test_sa_restart() - } ---- no_error_log -[crit] ---- error_log -Interrupted system call - - - -=== TEST 3: lua_sa_restart on (default) - sets SA_RESTART if no init_worker_by_lua* phase is defined ---- config - location /t { - content_by_lua_block { - test_sa_restart() - } - } - - - -=== TEST 4: lua_sa_restart on (default) - SA_RESTART is effective in rewrite_by_lua* ---- config - location /t { - rewrite_by_lua_block { - test_sa_restart() - } - - echo ok; - } - - - -=== TEST 5: lua_sa_restart on (default) - SA_RESTART is effective in access_by_lua* ---- config - location /t { - access_by_lua_block { - test_sa_restart() - } - - echo ok; - } - - - -=== TEST 6: lua_sa_restart on (default) - SA_RESTART is effective in content_by_lua* ---- config - location /t { - content_by_lua_block { - test_sa_restart() - } - } - - - -=== TEST 7: lua_sa_restart on (default) - SA_RESTART is effective in header_filter_by_lua* ---- config - location /t { - echo ok; - - header_filter_by_lua_block { - test_sa_restart() - } - } - - - -=== TEST 8: lua_sa_restart on (default) - SA_RESTART is effective in body_filter_by_lua* ---- config - location /t { - echo ok; - - body_filter_by_lua_block { - test_sa_restart() - } - } - - - -=== TEST 9: lua_sa_restart on (default) - SA_RESTART is effective in log_by_lua* ---- config - location /t { - echo ok; - - log_by_lua_block { - test_sa_restart() - } - } - - - -=== TEST 10: lua_sa_restart on (default) - SA_RESTART is effective in timer phase ---- config - location /t { - echo ok; - - log_by_lua_block { - ngx.timer.at(0, test_sa_restart) - } - } diff --git a/debian/modules/http-lua/t/160-disable-init-by-lua.t b/debian/modules/http-lua/t/160-disable-init-by-lua.t deleted file mode 100644 index 541771e..0000000 --- a/debian/modules/http-lua/t/160-disable-init-by-lua.t +++ /dev/null @@ -1,194 +0,0 @@ -use Test::Nginx::Socket::Lua; - -repeat_each(2); - -plan tests => repeat_each() * (blocks() * 3); - -$ENV{TEST_NGINX_HTML_DIR} ||= html_dir(); - -my $html_dir = $ENV{TEST_NGINX_HTML_DIR}; -my $http_config = <<_EOC_; - init_by_lua_block { - function set_up_ngx_tmp_conf(conf) - if conf == nil then - conf = [[ - events { - worker_connections 64; - } - http { - init_by_lua_block { - ngx.log(ngx.ERR, "run init_by_lua") - } - } - ]] - end - - assert(os.execute("mkdir -p $html_dir/logs")) - - local conf_file = "$html_dir/nginx.conf" - local f, err = io.open(conf_file, "w") - if not f then - ngx.log(ngx.ERR, err) - return - end - - assert(f:write(conf)) - - return conf_file - end - - function get_ngx_bin_path() - local ffi = require "ffi" - ffi.cdef[[char **ngx_argv;]] - return ffi.string(ffi.C.ngx_argv[0]) - end - } -_EOC_ - -add_block_preprocessor(sub { - my $block = shift; - - if (!defined $block->http_config) { - $block->set_value("http_config", $http_config); - } - - if (!defined $block->request) { - $block->set_value("request", "GET /t"); - } -}); - -env_to_nginx("PATH"); -log_level("warn"); -no_long_string(); -run_tests(); - -__DATA__ - -=== TEST 1: ensure init_by_lua* is not run in signaller process ---- config - location = /t { - content_by_lua_block { - local conf_file = set_up_ngx_tmp_conf() - local nginx = get_ngx_bin_path() - - local cmd = nginx .. " -p $TEST_NGINX_HTML_DIR -c " .. conf_file .. " -s reopen" - local p, err = io.popen(cmd) - if not p then - ngx.log(ngx.ERR, err) - return - end - - local out, err = p:read("*a") - if not out then - ngx.log(ngx.ERR, err) - - else - ngx.log(ngx.WARN, out) - end - } - } ---- error_log -failed (2: No such file or directory) ---- no_error_log eval -qr/\[error\] .*? init_by_lua:\d+: run init_by_lua/ - - - -=== TEST 2: init_by_lua* does not run when testing Nginx configuration ---- config - location = /t { - content_by_lua_block { - local conf_file = set_up_ngx_tmp_conf() - local nginx = get_ngx_bin_path() - - local cmd = nginx .. " -p $TEST_NGINX_HTML_DIR -c " .. conf_file .. " -t" - local p, err = io.popen(cmd) - if not p then - ngx.log(ngx.ERR, err) - return - end - - local out, err = p:read("*a") - if not out then - ngx.log(ngx.ERR, err) - - else - ngx.log(ngx.WARN, out) - end - - local cmd = nginx .. " -p $TEST_NGINX_HTML_DIR -c " .. conf_file .. " -T" - local p, err = io.popen(cmd) - if not p then - ngx.log(ngx.ERR, err) - return - end - - local out, err = p:read("*a") - if not out then - ngx.log(ngx.ERR, err) - - else - ngx.log(ngx.WARN, out) - end - } - } ---- error_log -test is successful ---- no_error_log eval -qr/\[error\] .*? init_by_lua:\d+: run init_by_lua/ - - - -=== TEST 3: init_by_lua* does not run when testing Nginx configuration which contains 'lua_shared_dict' (GitHub #1462) ---- config - location = /t { - content_by_lua_block { - local conf = [[ - events { - worker_connections 64; - } - http { - lua_shared_dict test 64k; - init_by_lua_block { - ngx.log(ngx.ERR, "run init_by_lua with lua_shared_dict") - } - } - ]] - local conf_file = set_up_ngx_tmp_conf(conf) - local nginx = get_ngx_bin_path() - - local cmd = nginx .. " -p $TEST_NGINX_HTML_DIR -c " .. conf_file .. " -t" - local p, err = io.popen(cmd) - if not p then - ngx.log(ngx.ERR, err) - return - end - - local out, err = p:read("*a") - if not out then - ngx.log(ngx.ERR, err) - - else - ngx.log(ngx.WARN, out) - end - - local cmd = nginx .. " -p $TEST_NGINX_HTML_DIR -c " .. conf_file .. " -T" - local p, err = io.popen(cmd) - if not p then - ngx.log(ngx.ERR, err) - return - end - - local out, err = p:read("*a") - if not out then - ngx.log(ngx.ERR, err) - - else - ngx.log(ngx.WARN, out) - end - } - } ---- error_log -test is successful ---- no_error_log eval -qr/\[error\] .*? init_by_lua:\d+: run init_by_lua with lua_shared_dict/ diff --git a/debian/modules/http-lua/t/161-load-resty-core.t b/debian/modules/http-lua/t/161-load-resty-core.t deleted file mode 100644 index 41b18f0..0000000 --- a/debian/modules/http-lua/t/161-load-resty-core.t +++ /dev/null @@ -1,68 +0,0 @@ -use Test::Nginx::Socket::Lua; - -repeat_each(2); - -plan tests => repeat_each() * (blocks() * 3); - -add_block_preprocessor(sub { - my $block = shift; - - if (!defined $block->request) { - $block->set_value("request", "GET /t"); - } - - if (!defined $block->no_error_log) { - $block->set_value("no_error_log", "[error]"); - } -}); - -no_long_string(); -run_tests(); - -__DATA__ - -=== TEST 1: lua_load_resty_core is enabled by default ---- config - location = /t { - content_by_lua_block { - local loaded_resty_core = package.loaded["resty.core"] - local resty_core = require "resty.core" - - ngx.say("resty.core loaded: ", loaded_resty_core == resty_core) - } - } ---- response_body -resty.core loaded: true - - - -=== TEST 2: lua_load_resty_core can be disabled ---- http_config - lua_load_resty_core off; ---- config - location = /t { - content_by_lua_block { - local loaded_resty_core = package.loaded["resty.core"] - - ngx.say("resty.core loaded: ", loaded_resty_core ~= nil) - } - } ---- response_body -resty.core loaded: false - - - -=== TEST 3: lua_load_resty_core is effective when using lua_shared_dict ---- http_config - lua_shared_dict dogs 128k; ---- config - location = /t { - content_by_lua_block { - local loaded_resty_core = package.loaded["resty.core"] - local resty_core = require "resty.core" - - ngx.say("resty.core loaded: ", loaded_resty_core == resty_core) - } - } ---- response_body -resty.core loaded: true diff --git a/debian/modules/http-lua/t/data/fake-shm-module/ngx_http_lua_fake_shm_module.c b/debian/modules/http-lua/t/data/fake-shm-module/ngx_http_lua_fake_shm_module.c index ffc32f5..0286853 100644 --- a/debian/modules/http-lua/t/data/fake-shm-module/ngx_http_lua_fake_shm_module.c +++ b/debian/modules/http-lua/t/data/fake-shm-module/ngx_http_lua_fake_shm_module.c @@ -213,9 +213,10 @@ ngx_http_lua_fake_shm_preload(lua_State *L) ngx_uint_t i; ngx_shm_zone_t **zone; - ngx_shm_zone_t **zone_udata; - cycle = (ngx_cycle_t *) ngx_cycle; + lua_getglobal(L, "__ngx_cycle"); + cycle = lua_touserdata(L, -1); + lua_pop(L, 1); hmcf_ctx = (ngx_http_conf_ctx_t *) cycle->conf_ctx[ngx_http_module.index]; lfsmcf = hmcf_ctx->main_conf[ngx_http_lua_fake_shm_module.ctx_index]; @@ -241,9 +242,7 @@ ngx_http_lua_fake_shm_preload(lua_State *L) lua_createtable(L, 1 /* narr */, 0 /* nrec */); /* table of zone[i] */ - zone_udata = lua_newuserdata(L, sizeof(ngx_shm_zone_t *)); - /* shared mt key ud */ - *zone_udata = zone[i]; + lua_pushlightuserdata(L, zone[i]); /* shared mt key ud */ lua_rawseti(L, -2, 1); /* {zone[i]} */ lua_pushvalue(L, -3); /* shared mt key ud mt */ lua_setmetatable(L, -2); /* shared mt key ud */ @@ -263,10 +262,9 @@ ngx_http_lua_fake_shm_preload(lua_State *L) static int ngx_http_lua_fake_shm_get_info(lua_State *L) { - ngx_int_t n; - ngx_shm_zone_t *zone; - ngx_shm_zone_t **zone_udata; - ngx_http_lua_fake_shm_ctx_t *ctx; + ngx_int_t n; + ngx_shm_zone_t *zone; + ngx_http_lua_fake_shm_ctx_t *ctx; n = lua_gettop(L); @@ -278,15 +276,13 @@ ngx_http_lua_fake_shm_get_info(lua_State *L) luaL_checktype(L, 1, LUA_TTABLE); lua_rawgeti(L, 1, 1); - zone_udata = lua_touserdata(L, -1); + zone = lua_touserdata(L, -1); lua_pop(L, 1); - if (zone_udata == NULL) { + if (zone == NULL) { return luaL_error(L, "bad \"zone\" argument"); } - zone = *zone_udata; - ctx = (ngx_http_lua_fake_shm_ctx_t *) zone->data; lua_pushlstring(L, (char *) zone->shm.name.data, zone->shm.name.len); diff --git a/debian/modules/http-lua/util/build.sh b/debian/modules/http-lua/util/build.sh index 14e9fd4..164bf9f 100755 --- a/debian/modules/http-lua/util/build.sh +++ b/debian/modules/http-lua/util/build.sh @@ -22,8 +22,6 @@ force=$2 #--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-pcre-jit \ --with-ipv6 \ @@ -57,7 +55,7 @@ time ngx-build $force $version \ --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-shm-module \ --add-module=$root/t/data/fake-delayed-load-module \ --with-http_gunzip_module \ --with-http_dav_module \ From c9fc21913a0c616e50d065a0808c8bfcbeee1835 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Sat, 12 Oct 2019 18:00:53 +0300 Subject: [PATCH 015/329] Release 1.16.1-2 --- debian/changelog | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/debian/changelog b/debian/changelog index 0b0b75b..a692f86 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,10 @@ +nginx (1.16.1-2) unstable; urgency=medium + + * http-lua: Downgrade to 0.10.13 (Closes: #941917) + Temporary fix FTBFS on architectures where Luajit is not available. + + -- Christos Trochalakis Sat, 12 Oct 2019 17:59:23 +0300 + nginx (1.16.1-1) unstable; urgency=medium * New upstream version (Closes: #929200) From 06b6f5670e9ca2b6d71f05b6b531ac661b10c4b6 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Sat, 11 Jan 2020 09:21:48 +0200 Subject: [PATCH 016/329] Handle CVE-2019-20372, error page request smuggling Nginx before 1.17.7, with certain error_page configurations, allows HTTP request smuggling, as demonstrated by the ability of an attacker to read unauthorized web pages in environments where NGINX is being fronted by a load balancer. --- debian/patches/CVE-2019-20372.patch | 31 +++++++++++++++++++++++++++++ debian/patches/series | 1 + 2 files changed, 32 insertions(+) create mode 100644 debian/patches/CVE-2019-20372.patch diff --git a/debian/patches/CVE-2019-20372.patch b/debian/patches/CVE-2019-20372.patch new file mode 100644 index 0000000..7793fa4 --- /dev/null +++ b/debian/patches/CVE-2019-20372.patch @@ -0,0 +1,31 @@ +From 8bffc01d084b4881e3eed2052c115b8f04268cb9 Mon Sep 17 00:00:00 2001 +From: Ruslan Ermilov +Date: Mon, 23 Dec 2019 15:45:46 +0300 +Subject: [PATCH] Discard request body when redirecting to a URL via + error_page. + +Reported by Bert JW Regeer and Francisco Oca Gonzalez. +--- + src/http/ngx_http_special_response.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/src/http/ngx_http_special_response.c b/src/http/ngx_http_special_response.c +index 2c1ff174..e2a5e9dc 100644 +--- a/src/http/ngx_http_special_response.c ++++ b/src/http/ngx_http_special_response.c +@@ -623,6 +623,12 @@ ngx_http_send_error_page(ngx_http_request_t *r, ngx_http_err_page_t *err_page) + return ngx_http_named_location(r, &uri); + } + ++ r->expect_tested = 1; ++ ++ if (ngx_http_discard_request_body(r) != NGX_OK) { ++ r->keepalive = 0; ++ } ++ + location = ngx_list_push(&r->headers_out.headers); + + if (location == NULL) { +-- +2.23.0 + diff --git a/debian/patches/series b/debian/patches/series index 5b6b799..b221db7 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -1,2 +1,3 @@ 0002-Make-sure-signature-stays-the-same-in-all-nginx-buil.patch 0003-define_gnu_source-on-other-glibc-based-platforms.patch +CVE-2019-20372.patch From f6841c97e24e562a828e90ab7f00598c2fd987f0 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Sat, 11 Jan 2020 09:37:17 +0200 Subject: [PATCH 017/329] Release 1.16.1-3 --- debian/changelog | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/debian/changelog b/debian/changelog index a692f86..4f12422 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,10 @@ +nginx (1.16.1-3) unstable; urgency=high + + * Handle CVE-2019-20372, error page request smuggling + (Closes: #948579) + + -- Christos Trochalakis Sat, 11 Jan 2020 09:36:00 +0200 + nginx (1.16.1-2) unstable; urgency=medium * http-lua: Downgrade to 0.10.13 (Closes: #941917) From 55ef39e8e194200d8c2da5da12c96594971b41bb Mon Sep 17 00:00:00 2001 From: Mohamed Akram Date: Mon, 11 May 2020 22:44:59 +0400 Subject: [PATCH 018/329] Enable --with-compat configure option Closes: #897926 --- debian/rules | 1 + 1 file changed, 1 insertion(+) diff --git a/debian/rules b/debian/rules index 981a57e..4f28b78 100755 --- a/debian/rules +++ b/debian/rules @@ -60,6 +60,7 @@ common_configure_flags := \ --http-proxy-temp-path=/var/lib/nginx/proxy \ --http-scgi-temp-path=/var/lib/nginx/scgi \ --http-uwsgi-temp-path=/var/lib/nginx/uwsgi \ + --with-compat \ --with-debug \ --with-pcre-jit \ --with-http_ssl_module \ From e5f8119f92409de49e5ab9dfd8f0eba44b61fa5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Nov=C3=BD?= Date: Thu, 28 May 2020 19:56:08 +0200 Subject: [PATCH 019/329] Add REMOTE_USER fastcgi param --- debian/conf/fastcgi.conf | 1 + debian/conf/fastcgi_params | 1 + 2 files changed, 2 insertions(+) diff --git a/debian/conf/fastcgi.conf b/debian/conf/fastcgi.conf index 091738c..d53a628 100644 --- a/debian/conf/fastcgi.conf +++ b/debian/conf/fastcgi.conf @@ -18,6 +18,7 @@ fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; fastcgi_param REMOTE_ADDR $remote_addr; fastcgi_param REMOTE_PORT $remote_port; +fastcgi_param REMOTE_USER $remote_user; fastcgi_param SERVER_ADDR $server_addr; fastcgi_param SERVER_PORT $server_port; fastcgi_param SERVER_NAME $server_name; diff --git a/debian/conf/fastcgi_params b/debian/conf/fastcgi_params index 28decb9..69c4387 100644 --- a/debian/conf/fastcgi_params +++ b/debian/conf/fastcgi_params @@ -17,6 +17,7 @@ fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; fastcgi_param REMOTE_ADDR $remote_addr; fastcgi_param REMOTE_PORT $remote_port; +fastcgi_param REMOTE_USER $remote_user; fastcgi_param SERVER_ADDR $server_addr; fastcgi_param SERVER_PORT $server_port; fastcgi_param SERVER_NAME $server_name; From 3ef09c0f692984ea8b3ea2f40f0fa15e8502433e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Nov=C3=BD?= Date: Thu, 28 May 2020 20:30:37 +0200 Subject: [PATCH 020/329] Use debhelper-compat instead of debian/compat --- debian/compat | 1 - debian/control | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) delete mode 100644 debian/compat diff --git a/debian/compat b/debian/compat deleted file mode 100644 index f599e28..0000000 --- a/debian/compat +++ /dev/null @@ -1 +0,0 @@ -10 diff --git a/debian/control b/debian/control index 409dc22..6860800 100644 --- a/debian/control +++ b/debian/control @@ -3,7 +3,7 @@ Section: httpd Priority: optional Maintainer: Debian Nginx Maintainers Uploaders: Christos Trochalakis -Build-Depends: debhelper (>= 10), +Build-Depends: debhelper-compat (= 10), dpkg-dev (>= 1.15.5), libexpat-dev, libgd-dev, From 2b4e972bd350a3431f4313d154c4cc2854ee6024 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Nov=C3=BD?= Date: Thu, 28 May 2020 20:36:23 +0200 Subject: [PATCH 021/329] Replace dh_systemd_enable with dh_installsystemd --- debian/rules | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/debian/rules b/debian/rules index 4f28b78..8b3f962 100755 --- a/debian/rules +++ b/debian/rules @@ -154,8 +154,8 @@ override_dh_install: override_dh_installinit: dh_installinit --no-restart-on-upgrade --no-start --name=nginx -override_dh_systemd_enable: - dh_systemd_enable --name=nginx +override_dh_installsystemd: + dh_installsystemd --name=nginx override_dh_installlogrotate: dh_installlogrotate --package nginx-common --name=nginx From 12e9c91f45b611aeb9c66e3f7ea531b637e9ba6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Nov=C3=BD?= Date: Thu, 28 May 2020 20:41:04 +0200 Subject: [PATCH 022/329] Set Rules-Requires-Root: no --- debian/control | 1 + 1 file changed, 1 insertion(+) diff --git a/debian/control b/debian/control index 6860800..34b14d7 100644 --- a/debian/control +++ b/debian/control @@ -24,6 +24,7 @@ Standards-Version: 4.3.0 Homepage: https://nginx.net Vcs-Git: https://salsa.debian.org/nginx-team/nginx.git Vcs-Browser: https://salsa.debian.org/nginx-team/nginx +Rules-Requires-Root: no Package: nginx Architecture: all From 7f0bb450a9742c809e22e8b31f32d359945ab1d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Nov=C3=BD?= Date: Thu, 28 May 2020 20:49:21 +0200 Subject: [PATCH 023/329] d/rules/dh_installinit: Replace --no-restart-on-upgrade with --no-stop-on-upgrade --- debian/rules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/rules b/debian/rules index 8b3f962..bf4b9f3 100755 --- a/debian/rules +++ b/debian/rules @@ -152,7 +152,7 @@ override_dh_install: DH_AUTOSCRIPTDIR=$(CURDIR)/debian/autoscripts debian/dh_nginx override_dh_installinit: - dh_installinit --no-restart-on-upgrade --no-start --name=nginx + dh_installinit --no-stop-on-upgrade --no-start --name=nginx override_dh_installsystemd: dh_installsystemd --name=nginx From 52a04bd90d7a5098654e8eceb286adca5b4b6e30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Nov=C3=BD?= Date: Thu, 28 May 2020 20:54:39 +0200 Subject: [PATCH 024/329] Bump debhelper compat level to 13 --- debian/control | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/control b/debian/control index 34b14d7..e2f3990 100644 --- a/debian/control +++ b/debian/control @@ -3,7 +3,7 @@ Section: httpd Priority: optional Maintainer: Debian Nginx Maintainers Uploaders: Christos Trochalakis -Build-Depends: debhelper-compat (= 10), +Build-Depends: debhelper-compat (= 13), dpkg-dev (>= 1.15.5), libexpat-dev, libgd-dev, From d089e100447b31ef880030665879ce26b832af3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Nov=C3=BD?= Date: Thu, 28 May 2020 21:04:44 +0200 Subject: [PATCH 025/329] Use package.maintscript instead of dpkg-maintscript-helper --- debian/nginx-common.maintscript | 8 ++++++++ debian/nginx-common.postinst | 14 -------------- debian/nginx-common.postrm | 14 -------------- debian/nginx-common.preinst | 14 -------------- 4 files changed, 8 insertions(+), 42 deletions(-) create mode 100644 debian/nginx-common.maintscript diff --git a/debian/nginx-common.maintscript b/debian/nginx-common.maintscript new file mode 100644 index 0000000..e1e7f53 --- /dev/null +++ b/debian/nginx-common.maintscript @@ -0,0 +1,8 @@ +# Handle naxsi removal +rm_conffile /etc/nginx/naxsi.rules 1.6.2-2~ +rm_conffile /etc/nginx/naxsi_core.rules 1.6.2-2~ +rm_conffile /etc/nginx/naxsi-ui.conf.1.4.1 1.6.2-2~ +rm_conffile /etc/nginx/naxsi-ui.conf 1.6.2-2~ + +# Handle upstart removal +rm_conffile /etc/init/nginx.conf 1.13.5-1~ diff --git a/debian/nginx-common.postinst b/debian/nginx-common.postinst index f83032d..9e0610e 100644 --- a/debian/nginx-common.postinst +++ b/debian/nginx-common.postinst @@ -3,20 +3,6 @@ set -e . /usr/share/debconf/confmodule -# Handle naxsi removal -dpkg-maintscript-helper rm_conffile \ - /etc/nginx/naxsi.rules 1.6.2-2~ -- "$@" -dpkg-maintscript-helper rm_conffile \ - /etc/nginx/naxsi_core.rules 1.6.2-2~ -- "$@" -dpkg-maintscript-helper rm_conffile \ - /etc/nginx/naxsi-ui.conf.1.4.1 1.6.2-2~ -- "$@" -dpkg-maintscript-helper rm_conffile \ - /etc/nginx/naxsi-ui.conf 1.6.2-2~ -- "$@" - -# Handle upstart removal -dpkg-maintscript-helper rm_conffile \ - /etc/init/nginx.conf 1.13.5-1~ -- "$@" - case "$1" in configure) logdir="/var/log/nginx" diff --git a/debian/nginx-common.postrm b/debian/nginx-common.postrm index d6f313a..f5124c8 100644 --- a/debian/nginx-common.postrm +++ b/debian/nginx-common.postrm @@ -1,20 +1,6 @@ #!/bin/sh set -e -# Handle naxsi removal -dpkg-maintscript-helper rm_conffile \ - /etc/nginx/naxsi.rules 1.6.2-2~ -- "$@" -dpkg-maintscript-helper rm_conffile \ - /etc/nginx/naxsi_core.rules 1.6.2-2~ -- "$@" -dpkg-maintscript-helper rm_conffile \ - /etc/nginx/naxsi-ui.conf.1.4.1 1.6.2-2~ -- "$@" -dpkg-maintscript-helper rm_conffile \ - /etc/nginx/naxsi-ui.conf 1.6.2-2~ -- "$@" - -# Handle upstart removal -dpkg-maintscript-helper rm_conffile \ - /etc/init/nginx.conf 1.13.5-1~ -- "$@" - case "$1" in purge) rm -rf /var/lib/nginx /var/log/nginx /etc/nginx diff --git a/debian/nginx-common.preinst b/debian/nginx-common.preinst index 27f21da..ead53f7 100644 --- a/debian/nginx-common.preinst +++ b/debian/nginx-common.preinst @@ -1,20 +1,6 @@ #!/bin/sh set -e -# Handle naxsi removal -dpkg-maintscript-helper rm_conffile \ - /etc/nginx/naxsi.rules 1.6.2-2~ -- "$@" -dpkg-maintscript-helper rm_conffile \ - /etc/nginx/naxsi_core.rules 1.6.2-2~ -- "$@" -dpkg-maintscript-helper rm_conffile \ - /etc/nginx/naxsi-ui.conf.1.4.1 1.6.2-2~ -- "$@" -dpkg-maintscript-helper rm_conffile \ - /etc/nginx/naxsi-ui.conf 1.6.2-2~ -- "$@" - -# Handle upstart removal -dpkg-maintscript-helper rm_conffile \ - /etc/init/nginx.conf 1.13.5-1~ -- "$@" - case "$1" in install) # If we are doing a fresh install, then these files are no longer needed. From 403f780a4693f70066f9659cae8fc0e6adea161c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Nov=C3=BD?= Date: Thu, 28 May 2020 21:15:12 +0200 Subject: [PATCH 026/329] Bump standards version to 4.5.0 --- debian/control | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/control b/debian/control index e2f3990..835af43 100644 --- a/debian/control +++ b/debian/control @@ -20,7 +20,7 @@ Build-Depends: debhelper-compat (= 13), po-debconf, quilt, zlib1g-dev -Standards-Version: 4.3.0 +Standards-Version: 4.5.0 Homepage: https://nginx.net Vcs-Git: https://salsa.debian.org/nginx-team/nginx.git Vcs-Browser: https://salsa.debian.org/nginx-team/nginx From b575cfe355931e42fb61febe58d06076a8b10725 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Nov=C3=BD?= Date: Thu, 28 May 2020 21:22:34 +0200 Subject: [PATCH 027/329] nchan: Upgrade to 1.2.7 --- debian/modules/nchan/README.md | 1033 +++++++- debian/modules/nchan/changelog.txt | 205 ++ debian/modules/nchan/cloc-exclude.txt | 21 +- debian/modules/nchan/config | 87 +- debian/modules/nchan/src/nchan_commands.rb | 383 ++- .../modules/nchan/src/nchan_config_commands.c | 284 ++- debian/modules/nchan/src/nchan_defs.c | 9 +- debian/modules/nchan/src/nchan_defs.h | 11 +- debian/modules/nchan/src/nchan_module.c | 428 ++-- debian/modules/nchan/src/nchan_module.h | 34 +- debian/modules/nchan/src/nchan_setup.c | 703 +++++- debian/modules/nchan/src/nchan_types.h | 197 +- debian/modules/nchan/src/nchan_variables.c | 6 + debian/modules/nchan/src/nchan_version.h | 1 + .../modules/nchan/src/store/memory/groups.c | 570 +++++ .../modules/nchan/src/store/memory/groups.h | 55 + .../nchan/src/store/memory/ipc-handlers.c | 701 ++++-- .../nchan/src/store/memory/ipc-handlers.h | 16 +- debian/modules/nchan/src/store/memory/ipc.c | 30 +- debian/modules/nchan/src/store/memory/ipc.h | 11 +- .../modules/nchan/src/store/memory/memstore.c | 1457 +++++++---- .../nchan/src/store/memory/store-private.h | 41 +- debian/modules/nchan/src/store/memory/store.h | 6 +- .../modules/nchan/src/store/redis/cluster.c | 1257 ---------- .../modules/nchan/src/store/redis/cluster.h | 30 - debian/modules/nchan/src/store/redis/cmp.c | 1319 +++++++--- debian/modules/nchan/src/store/redis/cmp.h | 66 +- .../nchan/src/store/redis/hiredis/.gitignore | 7 + .../nchan/src/store/redis/hiredis/.travis.yml | 24 + .../src/store/redis/hiredis/CHANGELOG.md | 110 + .../nchan/src/store/redis/hiredis/COPYING | 29 + .../nchan/src/store/redis/hiredis/Makefile | 217 ++ .../nchan/src/store/redis/hiredis/README.md | 392 +++ .../src/store/redis/hiredis/adapters/ae.h | 127 + .../src/store/redis/hiredis/adapters/libev.h | 147 ++ .../store/redis/hiredis/adapters/libevent.h | 108 + .../src/store/redis/hiredis/adapters/libuv.h | 121 + .../nchan/src/store/redis/hiredis/async.c | 687 ++++++ .../nchan/src/store/redis/hiredis/async.h | 129 + .../nchan/src/store/redis/hiredis/dict.c | 338 +++ .../nchan/src/store/redis/hiredis/dict.h | 126 + .../store/redis/hiredis/examples/example-ae.c | 62 + .../redis/hiredis/examples/example-libev.c | 52 + .../redis/hiredis/examples/example-libevent.c | 53 + .../redis/hiredis/examples/example-libuv.c | 53 + .../store/redis/hiredis/examples/example.c | 78 + .../nchan/src/store/redis/hiredis/fmacros.h | 21 + .../nchan/src/store/redis/hiredis/hiredis.c | 1021 ++++++++ .../nchan/src/store/redis/hiredis/hiredis.h | 226 ++ .../nchan/src/store/redis/hiredis/net.c | 461 ++++ .../nchan/src/store/redis/hiredis/net.h | 53 + .../nchan/src/store/redis/hiredis/read.c | 525 ++++ .../nchan/src/store/redis/hiredis/read.h | 116 + .../nchan/src/store/redis/hiredis/sds.c | 1095 +++++++++ .../nchan/src/store/redis/hiredis/sds.h | 105 + .../nchan/src/store/redis/hiredis/test.c | 807 ++++++ .../nchan/src/store/redis/hiredis/win32.h | 42 + .../modules/nchan/src/store/redis/rdsstore.c | 2139 +++++++--------- .../{scripts => redis-lua-scripts}/.gitignore | 0 .../{scripts => redis-lua-scripts}/Gemfile | 0 .../add_fakesub.lua | 13 +- .../channel_keepalive.lua | 9 +- .../{scripts => redis-lua-scripts}/delete.lua | 58 +- .../redis/redis-lua-scripts/find_channel.lua | 70 + .../get_message.lua | 33 +- .../get_message_from_key.lua | 8 + .../publish.lua | 119 +- .../publish_status.lua | 8 +- .../{scripts => redis-lua-scripts}/rsck.lua | 37 +- .../subscriber_register.lua | 24 +- .../subscriber_unregister.lua | 6 +- .../testscripts.rb | 7 +- .../src/store/redis/redis_lua_commands.c | 1036 ++++++++ .../src/store/redis/redis_lua_commands.h | 1001 +------- .../src/store/redis/redis_nginx_adapter.c | 64 +- .../src/store/redis/redis_nginx_adapter.h | 7 +- .../nchan/src/store/redis/redis_nodeset.c | 2179 +++++++++++++++++ .../nchan/src/store/redis/redis_nodeset.h | 276 +++ .../src/store/redis/redis_nodeset_parser.c | 241 ++ .../src/store/redis/redis_nodeset_parser.h | 40 + .../src/store/redis/scripts/find_channel.lua | 56 - .../redis/scripts/get_message_from_key.lua | 9 - .../nchan/src/store/redis/store-private.h | 196 +- debian/modules/nchan/src/store/redis/store.h | 11 +- debian/modules/nchan/src/store/spool.c | 290 ++- debian/modules/nchan/src/store/spool.h | 14 +- .../modules/nchan/src/subscribers/benchmark.c | 72 + .../modules/nchan/src/subscribers/benchmark.h | 3 + debian/modules/nchan/src/subscribers/common.c | 565 ++--- debian/modules/nchan/src/subscribers/common.h | 17 +- .../nchan/src/subscribers/eventsource.c | 94 +- .../nchan/src/subscribers/getmsg_proxy.c | 106 + .../nchan/src/subscribers/getmsg_proxy.h | 1 + .../nchan/src/subscribers/http-chunked.c | 10 +- .../src/subscribers/http-multipart-mixed.c | 27 +- .../nchan/src/subscribers/http-raw-stream.c | 16 +- .../modules/nchan/src/subscribers/internal.c | 19 +- .../nchan/src/subscribers/longpoll-private.h | 4 +- .../modules/nchan/src/subscribers/longpoll.c | 240 +- .../nchan/src/subscribers/memstore_ipc.c | 63 +- .../nchan/src/subscribers/memstore_ipc.h | 3 + .../nchan/src/subscribers/memstore_multi.c | 53 +- .../nchan/src/subscribers/memstore_redis.c | 130 +- .../nchan/src/subscribers/memstore_redis.h | 1 - .../modules/nchan/src/subscribers/websocket.c | 1420 +++++++---- .../modules/nchan/src/subscribers/websocket.h | 3 +- debian/modules/nchan/src/uthash.h | 1234 ++++++---- debian/modules/nchan/src/util/hdr_histogram.c | 1015 ++++++++ debian/modules/nchan/src/util/hdr_histogram.h | 427 ++++ .../modules/nchan/src/util/nchan_benchmark.c | 804 ++++++ .../modules/nchan/src/util/nchan_benchmark.h | 91 + .../nchan/src/util/nchan_bufchainpool.c | 96 + .../nchan/src/util/nchan_bufchainpool.h | 17 + .../modules/nchan/src/util/nchan_channel_id.c | 82 +- .../modules/nchan/src/util/nchan_channel_id.h | 5 +- .../nchan/src/util/nchan_channel_info.c | 128 - .../nchan/src/util/nchan_channel_info.h | 7 - debian/modules/nchan/src/util/nchan_debug.c | 81 + debian/modules/nchan/src/util/nchan_debug.h | 13 + .../nchan/src/util/nchan_fake_request.c | 291 ++- .../nchan/src/util/nchan_fake_request.h | 58 +- debian/modules/nchan/src/util/nchan_list.c | 26 + debian/modules/nchan/src/util/nchan_list.h | 5 + .../src/util/{nchan_msgid.c => nchan_msg.c} | 324 ++- .../src/util/{nchan_msgid.h => nchan_msg.h} | 19 + debian/modules/nchan/src/util/nchan_output.c | 95 +- debian/modules/nchan/src/util/nchan_output.h | 6 +- .../nchan/src/util/nchan_output_info.c | 271 ++ .../nchan/src/util/nchan_output_info.h | 6 + debian/modules/nchan/src/util/nchan_rbtree.h | 6 +- debian/modules/nchan/src/util/nchan_slist.c | 164 ++ debian/modules/nchan/src/util/nchan_slist.h | 41 + .../modules/nchan/src/util/nchan_subrequest.c | 75 +- .../modules/nchan/src/util/nchan_subrequest.h | 5 +- debian/modules/nchan/src/util/nchan_util.c | 911 ++++++- debian/modules/nchan/src/util/nchan_util.h | 50 +- .../nchan/src/util/ngx_nchan_hacked_slab.c | 4 + debian/modules/nchan/src/util/shmem.c | 49 +- debian/modules/nchan/src/util/shmem.h | 5 + 139 files changed, 26023 insertions(+), 7479 deletions(-) mode change 100755 => 100644 debian/modules/nchan/src/nchan_module.c create mode 100644 debian/modules/nchan/src/nchan_version.h create mode 100644 debian/modules/nchan/src/store/memory/groups.c create mode 100644 debian/modules/nchan/src/store/memory/groups.h delete mode 100644 debian/modules/nchan/src/store/redis/cluster.c delete mode 100644 debian/modules/nchan/src/store/redis/cluster.h create mode 100644 debian/modules/nchan/src/store/redis/hiredis/.gitignore create mode 100644 debian/modules/nchan/src/store/redis/hiredis/.travis.yml create mode 100644 debian/modules/nchan/src/store/redis/hiredis/CHANGELOG.md create mode 100644 debian/modules/nchan/src/store/redis/hiredis/COPYING create mode 100644 debian/modules/nchan/src/store/redis/hiredis/Makefile create mode 100644 debian/modules/nchan/src/store/redis/hiredis/README.md create mode 100644 debian/modules/nchan/src/store/redis/hiredis/adapters/ae.h create mode 100644 debian/modules/nchan/src/store/redis/hiredis/adapters/libev.h create mode 100644 debian/modules/nchan/src/store/redis/hiredis/adapters/libevent.h create mode 100644 debian/modules/nchan/src/store/redis/hiredis/adapters/libuv.h create mode 100644 debian/modules/nchan/src/store/redis/hiredis/async.c create mode 100644 debian/modules/nchan/src/store/redis/hiredis/async.h create mode 100644 debian/modules/nchan/src/store/redis/hiredis/dict.c create mode 100644 debian/modules/nchan/src/store/redis/hiredis/dict.h create mode 100644 debian/modules/nchan/src/store/redis/hiredis/examples/example-ae.c create mode 100644 debian/modules/nchan/src/store/redis/hiredis/examples/example-libev.c create mode 100644 debian/modules/nchan/src/store/redis/hiredis/examples/example-libevent.c create mode 100644 debian/modules/nchan/src/store/redis/hiredis/examples/example-libuv.c create mode 100644 debian/modules/nchan/src/store/redis/hiredis/examples/example.c create mode 100644 debian/modules/nchan/src/store/redis/hiredis/fmacros.h create mode 100644 debian/modules/nchan/src/store/redis/hiredis/hiredis.c create mode 100644 debian/modules/nchan/src/store/redis/hiredis/hiredis.h create mode 100644 debian/modules/nchan/src/store/redis/hiredis/net.c create mode 100644 debian/modules/nchan/src/store/redis/hiredis/net.h create mode 100644 debian/modules/nchan/src/store/redis/hiredis/read.c create mode 100644 debian/modules/nchan/src/store/redis/hiredis/read.h create mode 100644 debian/modules/nchan/src/store/redis/hiredis/sds.c create mode 100644 debian/modules/nchan/src/store/redis/hiredis/sds.h create mode 100644 debian/modules/nchan/src/store/redis/hiredis/test.c create mode 100644 debian/modules/nchan/src/store/redis/hiredis/win32.h rename debian/modules/nchan/src/store/redis/{scripts => redis-lua-scripts}/.gitignore (100%) rename debian/modules/nchan/src/store/redis/{scripts => redis-lua-scripts}/Gemfile (100%) rename debian/modules/nchan/src/store/redis/{scripts => redis-lua-scripts}/add_fakesub.lua (65%) rename debian/modules/nchan/src/store/redis/{scripts => redis-lua-scripts}/channel_keepalive.lua (85%) rename debian/modules/nchan/src/store/redis/{scripts => redis-lua-scripts}/delete.lua (54%) create mode 100644 debian/modules/nchan/src/store/redis/redis-lua-scripts/find_channel.lua rename debian/modules/nchan/src/store/redis/{scripts => redis-lua-scripts}/get_message.lua (80%) create mode 100644 debian/modules/nchan/src/store/redis/redis-lua-scripts/get_message_from_key.lua rename debian/modules/nchan/src/store/redis/{scripts => redis-lua-scripts}/publish.lua (71%) rename debian/modules/nchan/src/store/redis/{scripts => redis-lua-scripts}/publish_status.lua (81%) rename debian/modules/nchan/src/store/redis/{scripts => redis-lua-scripts}/rsck.lua (86%) rename debian/modules/nchan/src/store/redis/{scripts => redis-lua-scripts}/subscriber_register.lua (62%) rename debian/modules/nchan/src/store/redis/{scripts => redis-lua-scripts}/subscriber_unregister.lua (85%) rename debian/modules/nchan/src/store/redis/{scripts => redis-lua-scripts}/testscripts.rb (94%) create mode 100644 debian/modules/nchan/src/store/redis/redis_lua_commands.c create mode 100644 debian/modules/nchan/src/store/redis/redis_nodeset.c create mode 100644 debian/modules/nchan/src/store/redis/redis_nodeset.h create mode 100644 debian/modules/nchan/src/store/redis/redis_nodeset_parser.c create mode 100644 debian/modules/nchan/src/store/redis/redis_nodeset_parser.h delete mode 100644 debian/modules/nchan/src/store/redis/scripts/find_channel.lua delete mode 100644 debian/modules/nchan/src/store/redis/scripts/get_message_from_key.lua create mode 100644 debian/modules/nchan/src/subscribers/benchmark.c create mode 100644 debian/modules/nchan/src/subscribers/benchmark.h create mode 100644 debian/modules/nchan/src/subscribers/getmsg_proxy.c create mode 100644 debian/modules/nchan/src/subscribers/getmsg_proxy.h create mode 100644 debian/modules/nchan/src/util/hdr_histogram.c create mode 100644 debian/modules/nchan/src/util/hdr_histogram.h create mode 100644 debian/modules/nchan/src/util/nchan_benchmark.c create mode 100644 debian/modules/nchan/src/util/nchan_benchmark.h delete mode 100644 debian/modules/nchan/src/util/nchan_channel_info.c delete mode 100644 debian/modules/nchan/src/util/nchan_channel_info.h create mode 100644 debian/modules/nchan/src/util/nchan_debug.c create mode 100644 debian/modules/nchan/src/util/nchan_debug.h rename debian/modules/nchan/src/util/{nchan_msgid.c => nchan_msg.c} (65%) rename debian/modules/nchan/src/util/{nchan_msgid.h => nchan_msg.h} (63%) create mode 100644 debian/modules/nchan/src/util/nchan_output_info.c create mode 100644 debian/modules/nchan/src/util/nchan_output_info.h create mode 100644 debian/modules/nchan/src/util/nchan_slist.c create mode 100644 debian/modules/nchan/src/util/nchan_slist.h diff --git a/debian/modules/nchan/README.md b/debian/modules/nchan/README.md index ee43ac9..152396d 100644 --- a/debian/modules/nchan/README.md +++ b/debian/modules/nchan/README.md @@ -1,57 +1,56 @@ - + -https://nchan.slact.net +https://nchan.io Nchan is a scalable, flexible pub/sub server for the modern web, built as a module for the [Nginx](http://nginx.org) web server. It can be configured as a standalone server, or as a shim between your application and hundreds, thousands, or millions of live subscribers. It can buffer messages in memory, on-disk, or via [Redis](http://redis.io). All connections are handled asynchronously and distributed among any number of worker processes. It can also scale to many Nginx servers with [Redis](http://redis.io). Messages are [published](#publisher-endpoints) to channels with HTTP `POST` requests or Websocket, and [subscribed](#subscriber-endpoint) also through [Websocket](#websocket), [long-polling](#long-polling), [EventSource](#eventsource) (SSE), old-fashioned [interval polling](#interval-polling), [and](#http-chunked-transfer) [more](#http-multipart-mixed). -In a web browser, you can use Websocket or EventSource directly, or the [NchanSubscriber.js](https://github.com/slact/nchan/blob/master/NchanSubscriber.js) wrapper library. It supports Long-Polling, EventSource, and resumable Websockets, and has a few other added convenience options. +In a web browser, you can use Websocket or EventSource natively, or the [NchanSubscriber.js](https://github.com/slact/nchan.js) wrapper library. It supports Long-Polling, EventSource, and resumable Websockets, and has a few other added convenience options. It's also available on [NPM](https://www.npmjs.com/package/nchan). ## Features - - RESTful, HTTP-native API. - - Supports [Websocket](https://nchan.slact.net/#websocket), [EventSource (Server-Sent Events)](https://nchan.slact.net/#eventsource), [Long-Polling](https://nchan.slact.net/#long-polling) and other HTTP-based subscribers. - - No-repeat, no-loss message delivery guarantees with per-channel configurable message buffers. + - RESTful, HTTP-native [API](#publishing-messages). + - Supports [Websocket](#websocket), [EventSource (Server-Sent Events)](#eventsource), [Long-Polling](#long-polling) and other HTTP-based subscribers. + - Per-channel configurable message buffers with no-repeat, no-loss message delivery guarantees. - Subscribe to [hundreds of channels](#channel-multiplexing) over a single subscriber connection. - - HTTP request [callbacks and hooks](https://nchan.slact.net/details#application-callbacks) for easy integration. - - Introspection with [channel events](https://nchan.slact.net/details#channel-events) and [url for monitoring performance statistics](https://nchan.slact.net/details#nchan_stub_status). - - Fast ephemeral local message storage and optional, slower, persistent storage with [Redis](https://nchan.slact.net/details#connecting-to-a-redis-server). - - Horizontally scalable (using [Redis](https://nchan.slact.net/details#connecting-to-a-redis-server)). - - Highly Available with no single point of failure (using [Redis Cluster](https://nchan.slact.net/details#redis-cluster)). - - + - HTTP request [callbacks and hooks](#hooks-and-callbacks) for easy integration. + - Introspection with [channel events](#channel-events) and [url for monitoring performance statistics](#nchan_stub_status-stats). + - Channel [group](#channel-groups) usage [accounting and limits](#limits-and-accounting). + - Fast, nonblocking [shared-memory local message storage](#memory-storage) and optional, slower, persistent storage with [Redis](#redis). + - Horizontally scalable (using [Redis](#redis)). + - Auto-failover and [high availability](#high-availability) with no single point of failure using [Redis Cluster](#redis-cluster). ## Status and History -The latest Nchan release is v1.0.8 (November 28, 2016) ([changelog](https://nchan.slact.net/changelog)). +The latest Nchan release is 1.2.7 (March 17, 2020) ([changelog](https://nchan.io/changelog)). -The first iteration of Nchan was written in 2009-2010 as the [Nginx HTTP Push Module](https://pushmodule.slact.net), and was vastly refactored into its present state in 2014-2016. The present release is in the **testing** phase. The core features and old functionality are thoroughly tested and stable. Some of the new functionality, especially Redis Cluster may be a bit buggy. +The first iteration of Nchan was written in 2009-2010 as the [Nginx HTTP Push Module](https://pushmodule.slact.net), and was vastly refactored into its present state in 2014-2016. #### Upgrade from Nginx HTTP Push Module -Although Nchan is backwards-compatible with all Push Module configuration directives, some of the more unusual and rarely used settings have been disabled and will be ignored (with a warning). See the [upgrade page](https://nchan.slact.net/upgrade) for a detailed list of changes and improvements, as well as a full list of incompatibilities. +Although Nchan is backwards-compatible with all Push Module configuration directives, some of the more unusual and rarely used settings have been disabled and will be ignored (with a warning). See the [upgrade page](https://nchan.io/upgrade) for a detailed list of changes and improvements, as well as a full list of incompatibilities. ## Does it scale? -benchmarking internal subscriber response times +benchmarking internal subscriber response times Yes it does. Like Nginx, Nchan can easily handle as much traffic as you can throw at it. I've tried to benchmark it, but my benchmarking tools are much slower than Nchan. The data I've gathered is on how long Nchan itself takes to respond to every subscriber after publishing a message -- this excludes TCP handshake times and internal HTTP request parsing. Basically, it measures how Nchan scales assuming all other components are already tuned for scalability. The graphed data are averages of 5 runs with 50-byte messages. -With a well-tuned OS and network stack on commodity server hardware, expect to handle upwards of 300K concurrent subscribers per second at minimal CPU load. Nchan can also be scaled out to multiple Nginx instances using the [Redis storage engine](#nchan_use_redis), and that too can be scaled up beyond a single-point-of-failure by using [Redis Cluster](https://nchan.slact.net/details#using-redis). +With a well-tuned OS and network stack on commodity server hardware, expect to handle upwards of 300K concurrent subscribers per second at minimal CPU load. Nchan can also be scaled out to multiple Nginx instances using the [Redis storage engine](#nchan_use_redis), and that too can be scaled up beyond a single-point-of-failure by using [Redis Cluster](#redis-cluster). -Currently, Nchan's main bottleneck is not CPU load but memory bandwidth. This can be improved significantly in future versions with fewer allocations and better use of contiguous memory pools. Please consider supporting Nchan to speed up the work of memory cache optimization. ## Install #### Download Packages - - [Arch Linux](https://archlinux.org): [nginx-nchan](https://aur.archlinux.org/packages/nginx-nchan/) and [nginx-nchan-git](https://aur.archlinux.org/packages/nginx-nchan-git/) are available in the Arch User Repository. - - Mac OS X: a [homebrew](http://brew.sh) package is available. `brew tap homebrew/nginx; brew install nginx-full --with-nchan-module` - - [Debian](https://www.debian.org/): A dynamic module build for is available in the Debian package repository: [libnginx-mod-nchan](https://packages.debian.org/sid/libnginx-mod-nchan). - Additionally, you can use the pre-built static module packages [nginx-common.deb](https://nchan.slact.net/download/nginx-common.deb) and [nginx-extras.deb](https://nchan.slact.net/download/nginx-extras.deb). Download both and install them with `dpkg -i`, followed by `sudo apt-get -f install`. - - [Ubuntu](http://www.ubuntu.com/): [nginx-common.ubuntu.deb](https://nchan.slact.net/download/nginx-common.ubuntu.deb) and [nginx-extras.ubuntu.deb](https://nchan.slact.net/download/nginx-extras.ubuntu.deb). Download both and install them with `dpkg -i`, followed by `sudo apt-get -f install`. Who knows when Ubuntu will add them to their repository?... - - [Fedora](https://fedoraproject.org): Dynamic module builds for Nginx > 1.10.0 are available: [nginx-mod-nchan.x86_64.rpm](https://nchan.slact.net/download/nginx-mod-nchan.x86-64.rpm), [nginx-mod-nchan.src.rpm](https://nchan.slact.net/download/nginx-mod-nchan.src.rpm). - - A statically compiled binary and associated linux nginx installation files are also [available as a tarball](https://nchan.slact.net/download/nginx-nchan-latest.tar.gz). + - [Arch Linux](https://archlinux.org): [nginx-mod-nchan](https://aur.archlinux.org/packages/nginx-mod-nchan/) and [nginx-mainline-mod-nchan](https://aur.archlinux.org/packages/nginx-mainline-mod-nchan/) are available in the Arch User Repository. + - Mac OS X: a [homebrew](http://brew.sh) package is available. `brew tap denji/nginx; brew install nginx-full --with-nchan-module` + - [Debian](https://www.debian.org/): A dynamic module build is available in the Debian package repository: [libnginx-mod-nchan](https://packages.debian.org/sid/libnginx-mod-nchan). + Additionally, you can use the pre-built static module packages [nginx-common.deb](https://nchan.io/download/nginx-common.deb) and [nginx-extras.deb](https://nchan.io/download/nginx-extras.deb). Download both and install them with `dpkg -i`, followed by `sudo apt-get -f install`. + - [Ubuntu](http://www.ubuntu.com/): [nginx-common.ubuntu.deb](https://nchan.io/download/nginx-common.ubuntu.deb) and [nginx-extras.ubuntu.deb](https://nchan.io/download/nginx-extras.ubuntu.deb). Download both and install them with `dpkg -i`, followed by `sudo apt-get -f install`. Who knows when Ubuntu will add Nchan to their repository?... + - [Fedora](https://fedoraproject.org): Dynamic module builds for Nginx > 1.10.0 are available: [nginx-mod-nchan.x86_64.rpm](https://nchan.io/download/nginx-mod-nchan.x86-64.rpm), [nginx-mod-nchan.src.rpm](https://nchan.io/download/nginx-mod-nchan.src.rpm). + - [Heroku](https://heroku.com): A buildpack for compiling Nchan into Nginx is available: [nchan-buildpack](https://github.com/andjosh/nchan-buildpack). A one-click, readily-deployable app is also available: [nchan-heroku](https://github.com/andjosh/nchan-heroku). + - A statically compiled binary and associated linux nginx installation files are also [available as a tarball](https://nchan.io/download/nginx-nchan-latest.tar.gz). #### Build From Source @@ -62,7 +61,7 @@ Grab the latest copy of Nginx from [nginx.org](http://nginx.org). Grab the lates If you're using Nginx > 1.9.11, you can build Nchan as a [dynamic module](https://www.nginx.com/blog/dynamic-modules-nginx-1-9-11/) with `--add-dynamic-module=path/to/nchan` -Run `make`, `make install`, and enjoy. (Caution, contents may be hot.) +Run `make`, then `make install`. ## Getting Started @@ -87,11 +86,11 @@ http { } ``` -You can now publish messages to channels by `POST`ing data to `/sub?id=channel_id` , and subscribe by pointing Websocket, EventSource, or [NchanSubscriber.js](https://github.com/slact/nchan/blob/master/NchanSubscriber.js) to `sub/?id=channel_id`. It's that simple. +You can now publish messages to channels by `POST`ing data to `/pub?id=channel_id` , and subscribe by pointing Websocket, EventSource, or [NchanSubscriber.js](https://github.com/slact/nchan.js) to `sub/?id=channel_id`. It's that simple. But Nchan is very flexible and highly configurable. So, of course, it can get a lot more complicated... -## Conceptual Overview +### Conceptual Overview The basic unit of most pub/sub solutions is the messaging *channel*. Nchan is no different. Publishers send messages to channels with a certain *channel id*, and subscribers subscribed to those channels receive them. Some number of messages may be buffered for a time in a channel's message buffer before they are deleted. Pretty simple, right? @@ -121,15 +120,26 @@ http { The above maps requests to the URI `/sub` onto the channel `foobar`'s *subscriber endpoint* , and similarly `/pub` onto channel `foobar`'s *publisher endpoint*. -#### Publisher Endpoints +## Publisher Endpoints Publisher endpoints are Nginx config *locations* with the [*`nchan_publisher`*](#nchan_publisher) directive. Messages can be published to a channel by sending HTTP **POST** requests with the message contents to the *publisher endpoint* locations. You can also publish messages through a **Websocket** connection to the same location. +```nginx + location /pub { + #example publisher location + nchan_publisher; + nchan_channel_id foo; + nchan_channel_group test; + nchan_message_buffer_length 50; + nchan_message_timeout 5m; + } +``` + -##### Publishing Messages +### Publishing Messages Requests and websocket messages are responded to with information about the channel at time of message publication. Here's an example from publishing with `curl`: @@ -147,7 +157,7 @@ The response can be in plaintext (as above), JSON, or XML, based on the request' ```console > curl --request POST --data "test message" -H "Accept: text/json" http://127.0.0.2:80/pub - {"messages": 6, "requested": 55, "subscribers": 0, "last_message_id": "1450755317:0" } + {"messages": 5, "requested": 18, "subscribers": 0, "last_message_id": "1450755280:0" } ``` Websocket publishers also receive the same responses when publishing, with the encoding determined by the *`Accept`* header present during the handshake. @@ -156,7 +166,7 @@ The response code for an HTTP request is *`202` Accepted* if no subscribers are Metadata can be added to a message when using an HTTP POST request for publishing. A `Content-Type` header will be associated as the message's content type (and output to Long-Poll, Interval-Poll, and multipart/mixed subscribers). A `X-EventSource-Event` header can also be used to associate an EventSource `event:` line value with a message. -##### Other Publisher Endpoint Actions +### Other Publisher Endpoint Actions **HTTP `GET`** requests return channel information without publishing a message. The response code is `200` if the channel exists, and `404` otherwise: ```console @@ -171,15 +181,32 @@ Metadata can be added to a message when using an HTTP POST request for publishin **HTTP `DELETE`** requests delete a channel and end all subscriber connections. Like the `GET` requests, this returns a `200` status response with channel info if the channel existed, and a `404` otherwise. -For an in-depth explanation of how settings are applied to channels from publisher locations, see the [details page](https://nchan.slact.net/details#publisher-endpoint-configs). +### How Channel Settings Work -#### Subscriber Endpoints +*A channel's configuration is set to the that of its last-used publishing location.* +So, if you want a channel to behave consistently, and want to publish to it from multiple locations, *make sure those locations have the same configuration*. + +You can also can use differently-configured publisher locations to dynamically update a channel's message buffer settings. This can be used to erase messages or to scale an existing channel's message buffer as desired. + +## Subscriber Endpoints Subscriber endpoints are Nginx config *locations* with the [*`nchan_subscriber`*](#nchan_subscriber) directive. Nchan supports several different kinds of subscribers for receiving messages: [*Websocket*](#websocket), [*EventSource*](#eventsource) (Server Sent Events), [*Long-Poll*](#long-polling), [*Interval-Poll*](#interval-polling). [*HTTP chunked transfer*](#http-chunked-transfer), and [*HTTP multipart/mixed*](#http-multipart-mixed). -- ##### Long-Polling +```nginx + location /sub { + #example subscriber location + nchan_subscriber; + nchan_channel_id foo; + nchan_channel_group test; + nchan_subscriber_first_message oldest; + } +``` + + + +- ### Long-Polling The tried-and-true server-push method supported by every browser out there. Initiated by sending an HTTP `GET` request to a channel subscriber endpoint. The long-polling subscriber walks through a channel's message queue via the built-in cache mechanism of HTTP clients, namely with the "`Last-Modified`" and "`Etag`" headers. Explicitly, to receive the next message for given a long-poll subscriber response, send a request with the "`If-Modified-Since`" header set to the previous response's "`Last-Modified`" header, and "`If-None-Match`" likewise set to the previous response's "`Etag`" header. @@ -187,15 +214,16 @@ Nchan supports several different kinds of subscribers for receiving messages: [* A message's associated content type, if present, will be sent to this subscriber with the `Content-Type` header. -- ##### Interval-Polling +- ### Interval-Polling Works just like long-polling, except if the requested message is not yet available, immediately responds with a `304 Not Modified`. - There is no way to differentiate between long-poll and interval-poll subscriber requests, so long-polling must be disabled for a subscriber location if you wish to use interval-polling. + Nchan cannot automatically distinguish between long-poll and interval-poll subscriber requests, so long-polling must be disabled for a subscriber location if you wish to use interval-polling. -- ##### Websocket +- ### Websocket Bidirectional communication for web browsers. Part of the [HTML5 spec](http://www.w3.org/TR/2014/REC-html5-20141028/single-page.html). Nchan supports the latest protocol version 13 ([RFC 6455](https://tools.ietf.org/html/rfc6455)). Initiated by sending a websocket handshake to the desired subscriber endpoint location. - If the websocket connection is closed by the server, the `close` frame will contain the HTTP response code and status line describing the reason for closing the connection. Server-initiated keep-alive pings can be configured with the [`nchan_websocket_ping_interval`](#nchan_websocket_ping_interval) config directive. Websocket extensions are not yet supported. - Messages published through a websocket connection can be forwarded to an upstream application with the [`nchan_publisher_upstream_request`](#nchan_publisher_upstream_request) config directive. + If the websocket connection is closed by the server, the `close` frame will contain the HTTP response code and status line describing the reason for closing the connection. Server-initiated keep-alive pings can be configured with the [`nchan_websocket_ping_interval`](#nchan_websocket_ping_interval) config directive. + Messages are delivered to subscribers in `text` websocket frames, except if a message's `content-type` is "`application/octet-stream`" -- then it is delivered in a `binary` frame. +
Websocket subscribers can use the custom `ws+meta.nchan` subprotocol to receive message metadata with messages, making websocket connections resumable. Messages received with this subprotocol are of the form
   id: message_id
@@ -204,9 +232,24 @@ Nchan supports several different kinds of subscribers for receiving messages: [*
   message_data
   
The `content-type:` line may be omitted. +
+ #### Websocket Publisher + Messages published through a websocket connection can be forwarded to an upstream application with the [`nchan_publisher_upstream_request`](#nchan_publisher_upstream_request) config directive. + Messages published in a binary frame are automatically given the `content-type` "`application/octet-stream`". + #### Permessage-deflate + Nchan version 1.1.8 and above supports the [permessage-deflate protocol extension](https://tools.ietf.org/html/rfc7692). Messages are deflated once when they are published, and then can be broadcast to any number of compatible websocket subscribers. Message deflation is enabled by setting the [`nchan_deflate_message_for_websocket on;`](#nchan_deflate_message_for_websocket) directive in a publisher location. +
+ The deflated data is stored alongside the original message in memory, or, if large enough, on disk. This means more [shared memory](#nchan_shared_memory_size) is necessary when using `nchan_deflate_message_for_websocket`. +
+ Deflation parameters (speed, memory use, strategy, etc.), can be tweaked using the [`nchan_permessage_deflate_compression_window`](#nchan_permessage_deflate_compression_window), [`nchan_permessage_deflate_compression_level`](#nchan_permessage_deflate_compression_level), + [`nchan_permessage_deflate_compression_strategy`](#nchan_permessage_deflate_compression_strategy), and + [`nchan_permessage_deflate_compression_window`](#nchan_permessage_deflate_compression_window) settings. +
+ Nchan also supports the (deprecated) [perframe-deflate extension](https://tools.ietf.org/html/draft-tyoshino-hybi-websocket-perframe-deflate-06) still in use by Safari as `x-webkit-perframe-deflate`. +
-- ##### EventSource +- ### EventSource Also known as [Server-Sent Events](https://en.wikipedia.org/wiki/Server-sent_events) or SSE, it predates Websockets in the [HTML5 spec](http://www.w3.org/TR/2014/REC-html5-20141028/single-page.html), and is a [very simple protocol](http://www.w3.org/TR/eventsource/#event-stream-interpretation). Initiated by sending an HTTP `GET` request to a channel subscriber endpoint with the "`Accept: text/event-stream`" header. Each message `data: ` segment will be prefaced by the message `id: `. @@ -217,7 +260,7 @@ Nchan supports several different kinds of subscribers for receiving messages: [* A message's associated `event` type, if present, will be sent to this subscriber with the `event:` line. -- ##### HTTP [multipart/mixed](http://www.w3.org/Protocols/rfc1341/7_2_Multipart.html#z0) +- ### HTTP [multipart/mixed](http://www.w3.org/Protocols/rfc1341/7_2_Multipart.html#z0) The `multipart/mixed` MIMEtype was conceived for emails, but hey, why not use it for HTTP? It's easy to parse and includes metadata with each message. Initiated by including an `Accept: multipart/mixed` header. The response headers and the unused "preamble" portion of the response body are sent right away, with the boundary string generated randomly for each subscriber. Each subsequent message will be sent as one part of the multipart message, and will include the message time and tag (`Last-Modified` and `Etag`) as well as the optional `Content-Type` headers. @@ -225,11 +268,11 @@ Nchan supports several different kinds of subscribers for receiving messages: [* A message's associated content type, if present, will be sent to this subscriber with the `Content-Type` header. -- ##### HTTP Raw Stream +- ### HTTP Raw Stream A simple subscription method similar to the [streaming subscriber](https://github.com/wandenberg/nginx-push-stream-module/blob/master/docs/directives/subscribers.textile#push_stream_subscriber) of the [Nginx HTTP Push Stream Module](https://github.com/wandenberg/nginx-push-stream-module). Messages are appended to the response body, separated by a newline or configurable by `nchan_subscriber_http_raw_stream_separator`. -- ##### HTTP [Chunked Transfer](http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.6.1) +- ### HTTP [Chunked Transfer](http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.6.1) This subscription method uses the `chunked` `Transfer-Encoding` to receive messages. Initiated by explicitly including `chunked` in the [`TE` header](http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.39): `TE: chunked` (or `TE: chunked;q=??` where the qval > 0) @@ -237,9 +280,7 @@ Nchan supports several different kinds of subscribers for receiving messages: [* Unlike the other subscriber types, the `chunked` subscriber cannot be used with http/2 because it dissallows chunked encoding. - - -#### PubSub Endpoint +## PubSub Endpoint PubSub endpoints are Nginx config *locations* with the [*`nchan_pubsub`*](#nchan_pubsub) directive. @@ -249,17 +290,19 @@ requests as subscribers, and all HTTP `POST` as publishers. One simple use case ```nginx location = /pubsub { nchan_pubsub; - nchan_channel_id foobar; + nchan_channel_id foo; + nchan_channel_group test; } ``` -A more applicable setup may set different publisher and subscriber channel ids: +A more interesting setup may set different publisher and subscriber channel ids: ```nginx location = /pubsub { nchan_pubsub; nchan_publisher_channel_id foo; nchan_subscriber_channel_id bar; + nchan_channel_group test; } ``` @@ -267,9 +310,9 @@ Here, subscribers will listen for messages on channel `foo`, and publishers will -### The Channel ID +## The Channel ID -So far the examples have used static channel ids, which is not very useful in practice. It can be set to any nginx *variable*, such as a querystring argument, a header value, or a part of the location url: +So far the examples have used static channel ids, which is not very useful. In practice, the channel id can be set to any nginx *variable*, such as a querystring argument, a header value, or a part of the location url: ```nginx location = /sub_by_ip { @@ -294,9 +337,11 @@ So far the examples have used static channel ids, which is not very useful in pr } ``` +I recommend using the last option, a channel id derived from the request URL via a regular expression. It makes things nice and RESTful. + -#### Channel Multiplexing +### Channel Multiplexing With channel multiplexing, subscribers can subscribe to up to 255 channels per connection. Messages published to all the specified channels will be delivered in-order to the subscriber. There are two ways to enable multiplexing: @@ -325,68 +370,626 @@ For more than 7 channels, `nchan_channel_id_split_delimiter` can be used to spli } ``` -Publishing to multiple channels with a single request is also possible, with similar configuration: +It is also possible to publish to multiple channels with a single request as well as delete multiple channels with a single request, with similar configuration: ```nginx location ~ /multipub/(\w+)/(\w+)$ { nchan_publisher; nchan_channel_id "$1" "$2" "another_channel"; + #POST /multipub/foo/bar will publish to: + # channels 'foo', 'bar', 'another_channel' + #DELETE /multipub/foo/bar will delete: + # channels 'foo', 'bar', 'another_channel' } ``` -`DELETE` requests to a multiplexed channel broadcast the deletion to each of the channels it multiplexes, deletes all their messages and kicks out all clients subscribed to any of the channel ids. +When a channel is deleted, all of its messages are deleted, and all of its subscribers' connection are closed -- including ones subscribing through a multiplexed location. For example, suppose a subscriber is subscribed to channels "foo" and "bar" via a single multiplexed connection. If "foo" is deleted, the connection is closed, and the subscriber therefore loses the "bar" subscription as well. -See the [details page](https://nchan.slact.net/details#securing-channels) for more information about using good IDs and keeping channels secure. +See the [Channel Security](#securing-channels) section about using good IDs and keeping private channels secure. +### Channel Groups + +Channels can be associated with groups to avoid channel ID conflicts: + +```nginx + location /test_pubsub { + nchan_pubsub; + nchan_channel_group "test"; + nchan_channel_id "foo"; + } + + location /pubsub { + nchan_pubsub; + nchan_channel_group "production"; + nchan_channel_id "foo"; + #same channel id, different channel group. Thus, different channel. + } + + location /flexgroup_pubsub { + nchan_pubsub; + nchan_channel_group $arg_group; + nchan_channel_id "foo"; + #group can be set with request variables too + } +``` + +#### Limits and Accounting + +Groups can be used to track aggregate channel usage, as well as set limits on the number of channels, subscribers, stored messages, memory use, etc: + +```nginx + #enable group accounting + nchan_channel_group_accounting on; + + location ~ /pubsub/(\w+)$ { + nchan_pubsub; + nchan_channel_group "limited"; + nchan_channel_id $1; + } + + location ~ /prelimited_pubsub/(\w+)$ { + nchan_pubsub; + nchan_channel_group "limited"; + nchan_channel_id $1; + nchan_group_max_subscribers 100; + nchan_group_max_messages_memory 50M; + } + + location /group { + nchan_channel_group limited; + nchan_group_location; + nchan_group_max_channels $arg_max_channels; + nchan_group_max_messages $arg_max_messages; + nchan_group_max_messages_memory $arg_max_messages_mem; + nchan_group_max_messages_disk $arg_max_messages_disk; + nchan_group_max_subscribers $arg_max_subs; + } +``` + +Here, `/group` is an `nchan_group_location`, which is used for accessing and modifying group data. To get group data, send a `GET` request to a `nchan_group_location`: + +```sh +> curl http://localhost/group + +channels: 10 +subscribers: 0 +messages: 219 +shared memory used by messages: 42362 bytes +disk space used by messages: 0 bytes +limits: + max channels: 0 + max subscribers: 0 + max messages: 0 + max messages shared memory: 0 + max messages disk space: 0 +``` + +By default, the data is returned in human-readable plaintext, but can also be formatted as JSON, XML, or YAML: + +```sh +> curl -H "Accept: text/json" http://localhost/group + +{ + "channels": 21, + "subscribers": 40, + "messages": 53, + "messages_memory": 19941, + "messages_disk": 0, + "limits": { + "channels": 0, + "subscribers": 0, + "messages": 0, + "messages_memory": 0, + "messages_disk": 0 + } +} +``` + +The data in the response are for the single Nchan instance only, regardless of whether Redis is used. A limit of 0 means 'unlimited'. + +Limits can be set per-location, as with the above `/prelimited_pubsub/...` location, or with a POST request to the `nchan_group_location`: +```sh +> curl -X POST "http://localhost/group?max_channels=15&max_subs=1000&max_messages_disk=0.5G" + +channels: 0 +subscribers: 0 +messages: 0 +shared memory used by messages: 0 bytes +disk space used by messages: 0 bytes +limits: + max channels: 15 + max subscribers: 1000 + max messages: 0 + max messages shared memory: 0 + max messages disk space: 536870912 + +``` + +Limits are only applied locally, regardless of whether Redis is enabled. +If a publisher or subscriber request exceeds a group limit, Nchan will respond to it with a `403 Forbidden` response. + + + +## Hooks and Callbacks + + + +### Request Authorization + +This feature, configured with [`nchan_authorize_request`](#nchan_authorize_request), behaves just like the Nginx [http_auth_request module](http://nginx.org/en/docs/http/ngx_http_auth_request_module.html#auth_request_set). + +Consider the configuration: +```nginx + upstream my_app { + server 127.0.0.1:8080; + } + location = /auth { + proxy_pass http://my_app/pubsub_authorize; + proxy_pass_request_body off; + proxy_set_header Content-Length ""; + proxy_set_header X-Subscriber-Type $nchan_subscriber_type; + proxy_set_header X-Publisher-Type $nchan_publisher_type; + proxy_set_header X-Prev-Message-Id $nchan_prev_message_id; + proxy_set_header X-Channel-Id $nchan_channel_id; + proxy_set_header X-Original-URI $request_uri; + proxy_set_header X-Forwarded-For $remote_addr; + } + + location ~ /pubsub/auth/(\w+)$ { + nchan_channel_id $1; + nchan_authorize_request /auth; + nchan_pubsub; + nchan_channel_group test; + } +``` + +Here, any request to the location `/pubsub/auth/<...>` will need to be authorized by your application (`my_app`). Nginx will generate a `GET /pubsub_authorize` request to the application, with additional headers set by the `proxy_set_header` directives. Note that Nchan-specific variables are available for this authorization request. Once your application receives this request, it should decide whether or not to authorize the subscriber. This can be done based on a forwarded session cookie, IP address, or any set of parameters of your choosing. If authorized, it should respond with an empty `200 OK` response. +All non-`2xx` response codes (such as `403 Forbidden`) are intepreted as authorization failures. In this case, the failing response is proxied to the client. + +Note that Websocket and EventSource clients will only try to authorize during the initial handshake request, whereas Long-Poll and Interval-Poll subscribers will need to be authorized each time they request the next message, which may flood your application with too many authorization requests. + + + +### Subscriber Presence + +Subscribers can notify an application when they have subscribed and unsubscribed to a channel using the [`nchan_subscribe_request`](#nchan_subscribe_request) +and [`nchan_unsubscribe_request`](#nchan_unsubscribe_request) settings. +These should point to Nginx locations configured to forward requests to an upstream proxy (your application): + +```nginx + location ~ /sub/(\w+)$ { + nchan_channel_id $1; + nchan_subscribe_request /upstream/sub; + nchan_unsubscribe_request /upstream/unsub; + nchan_subscriber; + nchan_channel_group test; + } + + location = /upstream/unsub { + proxy_pass http://127.0.0.1:9292/unsub; + proxy_ignore_client_abort on; #!!!important!!!! + proxy_set_header X-Subscriber-Type $nchan_subscriber_type; + proxy_set_header X-Channel-Id $nchan_channel_id; + proxy_set_header X-Original-URI $request_uri; + } + location = /upstream/sub { + proxy_pass http://127.0.0.1:9292/sub; + proxy_set_header X-Subscriber-Type $nchan_subscriber_type; + proxy_set_header X-Message-Id $nchan_message_id; + proxy_set_header X-Channel-Id $nchan_channel_id; + proxy_set_header X-Original-URI $request_uri; + } +``` + +In order for `nchan_unsubscribe_request` to work correctly, the location it points to must have `proxy_ignore_client_abort on;`. Otherwise, suddenly aborted subscribers may not trigger an unsubscribe request. + +Note that the subscribe/unsubscribe hooks are **disabled for long-poll and interval-poll clients**, because they would trigger these hooks each time they receive a message. + + + +### Message Forwarding + +Messages can be forwarded to an upstream application before being published using the `nchan_publisher_upstream_request` setting: + +```nginx + location ~ /pub/(\w+)$ { + #publisher endpoint + nchan_channel_id $1; + nchan_pubsub; + nchan_publisher_upstream_request /upstream_pub; + } + + location = /upstream_pub { + proxy_pass http://127.0.0.1:9292/pub; + proxy_set_header X-Publisher-Type $nchan_publisher_type; + proxy_set_header X-Prev-Message-Id $nchan_prev_message_id; + proxy_set_header X-Channel-Id $nchan_channel_id; + proxy_set_header X-Original-URI $request_uri; + } +``` +With this configuration, incoming messages are first `POST`ed to `http://127.0.0.1:9292/pub`. +The upstream response code determines how publishing will proceed: + - `304 Not Modified` publishes the message as received, without modifification. + - `204 No Content` discards the message + - `200 OK` is used for modifying the message. Instead of the original incoming message, the message contained in this HTTP response is published. + +There are two main use cases for `nchan_publisher_upstream_request`: forwarding incoming data from Websocket publishers to an application, and mutating incoming messages. + + + ## Storage Nchan can stores messages in memory, on disk, or via Redis. Memory storage is much faster, whereas Redis has additional overhead as is considerably slower for publishing messages, but offers near unlimited scalability for broadcast use cases with far more subscribers than publishers. - - ### Memory Storage -This storage method uses a segment of shared memory to store messages and channel data. Large messages as determined by Nginx's caching layer are stored on-disk. The size of the memory segment is configured with `nchan_max_reserved_memory`. Data stored here is not persistent, and is lost if Nginx is restarted or reloaded. +This default storage method uses a segment of shared memory to store messages and channel data. Large messages as determined by Nginx's caching layer are stored on-disk. The size of the memory segment is configured with `nchan_shared_memory_size`. Data stored here is not persistent, and is lost if Nginx is restarted or reloaded. ### Redis -Nchan can also store messages and channels on a Redis server, or in a Redis cluster. To use a Redis server, set `nchan_use_redis on;` and set the server url with `nchan_redis_url`. These two settings are inheritable by nested locations, so it is enough to set them within an `http { }` block to enable Redis for all Nchan locations in that block. Different locations can also use different Redis servers. +[Redis](http://redis.io) can be used to add **data persistence** and **horizontal scalability**, **failover** and **high availability** to your Nchan setup. -To use a Redis Cluster, the Redis servers acting as cluster nodes need to be configured in an `upstream { }` block: + + +#### Connecting to a Redis Server +To connect to a single Redis master server, use an `upstream` with `nchan_redis_server` and `nchan_redis_pass` settings: ```nginx +http { + upstream my_redis_server { + nchan_redis_server 127.0.0.1; + } + server { + listen 80; + + location ~ /redis_sub/(\w+)$ { + nchan_subscriber; + nchan_channel_id $1; + nchan_redis_pass my_redis_server; + } + location ~ /redis_pub/(\w+)$ { + nchan_redis_pass my_redis_server; + nchan_publisher; + nchan_channel_id $1; + } + } +} +``` + +All servers with the above configuration connecting to the same redis server share channel and message data. + +Channels that don't use Redis can be configured side-by-side with Redis-backed channels, provided the endpoints never overlap. (This can be ensured, as above, by setting separate `nchan_channel_group`s.). Different locations can also connect to different Redis servers. + +Nchan can work with a single Redis master. It can also auto-discover and use Redis slaves to balance PUBSUB traffic. + + + +#### Redis Cluster +Nchan also supports using Redis Cluster, which adds scalability via sharding channels among cluster nodes. Redis cluster also provides **automatic failover**, **high availability**, and eliminates the single point of failure of one shared Redis server. It is configred and used like so: + +```nginx +http { upstream redis_cluster { nchan_redis_server redis://127.0.0.1:7000; nchan_redis_server redis://127.0.0.1:7001; nchan_redis_server redis://127.0.0.1:7002; + # you don't need to specify all the nodes, they will be autodiscovered + # however, it's recommended that you do specify at least a few master nodes. } + server { + listen 80; + + location ~ /sub/(\w+)$ { + nchan_subscriber; + nchan_channel_id $1; + nchan_redis_pass redis_cluster; + } + location ~ /pub/(\w+)$ { + nchan_publisher; + nchan_channel_id $1; + nchan_redis_pass redis_cluster; + } + } +} ``` -It is best to specify all master cluster nodes, but this is not required -- as long as Nchan can connect to at least 1 node, it will discover and connect to the whole cluster. + -To use Redis Cluster in an Nchan location, use the `nchan_redis_pass` setting: +##### High Availability +Redis Cluster connections are designed to be resilient and try to recover from errors. Interrupted connections will have their commands queued until reconnection, and Nchan will publish any messages it successfully received while disconnected. Nchan is also adaptive to cluster modifications. It will add new nodes and remove them as needed. + +All Nchan servers sharing a Redis server or cluster should have their times synchronized (via ntpd or your favorite ntp daemon). Failure to do so may result in missed or duplicate messages. + +#### Tweaks and Optimizations + +As of version 1.2.0, Nchan uses Redis slaves to load-balance PUBSUB traffic. By default, there is an equal chance that a channel's PUBSUB subscription will go to any master or slave. The [`nchan_redis_subscribe_weights`](#nchan_redis_subscribe_weights) setting is available to fine-tune this load-balancing. + +Also from 1.2.0 onward, [`nchan_redis_optimize_target`](#nchan_redis_optimize_target) can be used to prefer optimizing Redis slaves for CPU or bandwidth. For heavy publishing loads, the tradeoff is very roughly 35% replication bandwidth per slave to 30% CPU load on slaves. + +## Introspection + +There are several ways to see what's happening inside Nchan. These are useful for debugging application integration and for measuring performance. + +### Channel Events + +Channel events are messages automatically published by Nchan when certain events occur in a channel. These are very useful for debugging the use of channels. However, they carry a significant performance overhead and should be used during development, and not in production. + +Channel events are published to special 'meta' channels associated with normal channels. Here's how to configure them: ```nginx - location ~ /pubsub/(\w+)$ { - nchan_channel_id $1; - nchan_pubsub; - nchan_redis_pass redis_cluster; +location ~ /pubsub/(.+)$ { + nchan_pubsub; + nchan_channel_id $1; + nchan_channel_events_channel_id $1; #enables channel events for this location +} + +location ~ /channel_events/(.+) { + #channel events subscriber location + nchan_subscriber; + nchan_channel_group meta; #"meta" is a SPECIAL channel group + nchan_channel_id $1; +} +``` + +Note the `/channel_events/...` location has a *special* `nchan_channel_group`, `meta`. This group is reserved for accessing "channel events channels", or"metachannels". + +Now, say I subscribe to `/channel_events/foo` I will refer to this as the channel events subscriber. + +Let's see what this channel events subscriber receives when I publish messages to + +Subscribing to `/pubsub/foo` produces the channel event +``` +subscriber_enqueue foo +``` + +Publishing a message to `/pubsub/foo`: +``` +channel_publish foo +``` + +Unsubscribing from `/pubsub/foo`: +``` +subscriber_dequeue foo +``` + +Deleting `/pubsub/foo` (with HTTP `DELETE /pubsub/foo`): +``` +channel_delete foo +``` + +The event string itself is configirable with [nchan_channel_event_string](#nchan_channel_event_string). By default, it is set to `$nchan_channel_event $nchan_channel_id`. +This string can use any Nginx and [Nchan variables](/#variables). + + +### nchan_stub_status Stats + +Like Nginx's [stub_status](https://nginx.org/en/docs/http/ngx_http_stub_status_module.html), +`nchan_stub_status` is used to get performance metrics. + +```nginx + location /nchan_stub_status { + nchan_stub_status; } +``` + +Sending a GET request to this location produces the response: + +```text +total published messages: 1906 +stored messages: 1249 +shared memory used: 1824K +channels: 80 +subscribers: 90 +redis pending commands: 0 +redis connected servers: 0 +total interprocess alerts received: 1059634 +interprocess alerts in transit: 0 +interprocess queued alerts: 0 +total interprocess send delay: 0 +total interprocess receive delay: 0 +nchan version: 1.1.5 +``` + +Here's what each line means, and how to interpret it: + - `total published messages`: Number of messages published to all channels through this Nchan server. + - `stored messages`: Number of messages currently buffered in memory + - `shared memory used`: Total shared memory used for buffering messages, storing channel information, and other purposes. This value should be comfortably below `nchan_shared_memory_size`. + - `channels`: Number of channels present on this Nchan server. + - `subscribers`: Number of subscribers to all channels on this Nchan server. + - `redis pending commands`: Number of commands sent to Redis that are awaiting a reply. May spike during high load, especially if the Redis server is overloaded. Should tend towards 0. + - `redis connected servers`: Number of redis servers to which Nchan is currently connected. + - `total interprocess alerts received`: Number of interprocess communication packets transmitted between Nginx workers processes for Nchan. Can grow at 100-10000 per second at high load. + - `interprocess alerts in transit`: Number of interprocess communication packets in transit between Nginx workers. May be nonzero during high load, but should always tend toward 0 over time. + - `interprocess queued alerts`: Number of interprocess communication packets waiting to be sent. May be nonzero during high load, but should always tend toward 0 over time. + - `total interprocess send delay`: Total amount of time interprocess communication packets spend being queued if delayed. May increase during high load. + - `total interprocess receive delay`: Total amount of time interprocess communication packets spend in transit if delayed. May increase during high load. + - `nchan_version`: current version of Nchan. Available for version 1.1.5 and above. + +Additionally, when there is at least one `nchan_stub_status` location, the following Nginx variables are available: + - `$nchan_stub_status_total_published_messages` + - `$nchan_stub_status_stored_messages` + - `$nchan_stub_status_shared_memory_used` + - `$nchan_stub_status_channels` + - `$nchan_stub_status_subscribers` + - `$nchan_stub_status_redis_pending_commands` + - `$nchan_stub_status_redis_connected_servers` + - `$nchan_stub_status_total_ipc_alerts_received` + - `$nchan_stub_status_ipc_queued_alerts` + - `$nchan_stub_status_total_ipc_send_delay` + - `$nchan_stub_status_total_ipc_receive_delay` + + +## Securing Channels + +### Securing Publisher Endpoints +Consider the use case of an application where authenticated users each use a private, dedicated channel for live updates. The configuration might look like this: + +```nginx +http { + server { + #available only on localhost + listen 127.0.0.1:8080; + location ~ /pub/(\w+)$ { + nchan_publisher; + nchan_channel_group my_app_group; + nchan_channel_id $1; + } + } + + server { + #available to the world + listen 80; + + location ~ /sub/(\w+)$ { + nchan_subscriber; + nchan_channel_group my_app_group; + nchan_channel_id $1; + } + } +} ``` -Note that `nchan_redis_pass` implies `nchan_use_redis on;`, and that this setting is *not* inherited by nested locations. +Here, the subscriber endpoint is available on a public-facing port 80, and the publisher endpoint is only available on localhost, so can be accessed only by applications residing on that machine. Another way to limit access to the publisher endpoint is by using the allow/deny settings: -When connecting several Nchan servers to the same Redis server (or cluster), the servers **must have their times synced up**. Failure to do so may result in missing and duplicated messages. +```nginx -See the [details page](https://nchan.slact.net/details#using-redis) for more information on using Redis. + server { + #available to the world + listen 80; + location ~ /pub/(\w+)$ { + allow 127.0.0.1; + deny all; + nchan_publisher; + nchan_channel_group my_app_group; + nchan_channel_id $1; + } +``` - +Here, only the local IP 127.0.0.1 is allowed to use the publisher location, even though it is defined in a non-localhost server block. +### Keeping a Channel Private + +A Channel ID that is meant to be private should be treated with the same care as a session ID token. Considering the above use case of one-channel-per-user, how can we ensure that only the authenticated user, and no one else, is able to access his channel? + +First, if you intend on securing the channel contents, you must use TLS/SSL: + +```nginx +http { + server { + #available only on localhost + listen 127.0.0.1:8080; + #...publisher endpoint config + } + server { + #available to the world + listen 443 ssl; + #SSL config goes here + location ~ /sub/(\w+)$ { + nchan_subscriber; + nchan_channel_group my_app_group; + nchan_channel_id $1; + } + } +} +``` + +Now that you have a secure connection between the subscriber client and the server, you don't need to worry about the channel ID or messages being passively intercepted. This is a minimum requirement for secure message delivery, but it is not sufficient. + +You must also take care to do at least one of the following: + - [Generate good, high-entropy Channel IDs](#good-ids). + - [Authorize all subscribers with the `nchan_authorize_request` config directive](#request-authorization). + - [Authorize subscribers and hide channel IDs with the "`X-Accel-Redirect`" mechanism](#x-accel-redirect). + +#### Good IDs + +An ID that can be guessed is an ID that can be hijacked. If you are not authenticating subscribers (as described below), a channel ID should be impossible to guess. Use at least 128 bits of entropy to generate a random token, associate it with the authenticated user, and share it only with the user's client. Do not reuse tokens, just as you would not reuse session IDs. + +#### X-Accel-Redirect + +This feature uses the [X-Accel feature](https://www.nginx.com/resources/wiki/start/topics/examples/x-accel) of Nginx upstream proxies to perform an internal request to a subscriber endpoint. +It allows a subscriber client to be authenticated by your application, and then redirected by nginx internally to a location chosen by your appplication (such as a publisher or subscriber endpoint). This makes it possible to have securely authenticated clients that are unaware of the channel id they are subscribed to. + +Consider the following configuration: +```nginx +upstream upstream_app { + server 127.0.0.1:8080; +} + +server { + listen 80; + + location = /sub_upstream { + proxy_pass http://upstream_app/subscriber_x_accel_redirect; + proxy_set_header X-Forwarded-For $remote_addr; + } + + location ~ /sub/internal/(\w+)$ { + internal; #this location only accessible for internal nginx redirects + nchan_subscriber; + nchan_channel_id $1; + nchan_channel_group test; + } +} +``` + +As commented, `/sub/internal/` is inaccessible from the outside: +```console +> curl -v http://127.0.0.1/sub/internal/foo + + < HTTP/1.1 404 Not Found + < Server: nginx/1.9.5 + < + + 404 Not Found + +

404 Not Found

+
nginx/1.9.5
+ + +``` + +But if a request is made to `/sub_upstream`, it gets forwarded to your application (`my_app`) on port 8080 with the url `/subscriber_x_accel_redirect`. +Note that you can set any forwarded headers here like any [`proxy_pass`](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass) Nginx location, +but unlike the case with `nchan_authorize_request`, Nchan-specific variables are not available. + +Now, your application must be set up to handle the request to `/subscriber_x_accel_redirect`. You should make sure the client is properly authenticated (maybe using a session cookie), and generate an associated channel id. If authentication fails, respond with a normal `403 Forbidden` response. You can also pass extra information about the failure in the response body and headers. + +If your application successfully authenticates the subscriber request, you now need to instruct Nginx to issue an internal redirect to `/sub/internal/my_channel_id`. +This is accomplished by responding with an empty `200 OK` response that includes two headers: +- `X-Accel-Redirect: /sub/internal/my_channel_id` +- `X-Accel-Buffering: no` + +In the presence of these headers, Nginx will not forward your app's response to the client, and instead will *internally* redirect to `/sub/internal/my_channel_id`. +This will behave as if the client had requested the subscriber endpoint location directly. + +Thus using X-Accel-Redirect it is possible to both authenticate all subscribers *and* keep channel IDs completely hidden from subscribers. + +This method is especially useful for EventSource and Websocket subscribers. Long-Polling subscribers will need to be re-authenticated for every new message, which may flood your application with too many authentication requests. + +### Revoking Channel Authorization + +In some cases, you may want to revoke a particular subscriber's authorization for a given channel (e.g., if the user's permissions are changed). If the channel is unique to the subscriber, this is simply accomplished by deleting the channel. The same can be achieved for shared channels by subscribing each subscriber to both the shared channel and a subscriber-specific channel via a multiplexed connection. Deleting the subscriber-specific channel will terminate the subscriber''s connection, thereby also terminating their subscription to the shared channel. Consider the following configuration: + +```nginx +location ~ /sub/(\w+) { + nchan_subscriber; + nchan_channel_id shared_$1 user_$arg_userid; + nchan_authorize_request /authorize; +} + +location /pub/user { + nchan_publisher; + nchan_channel_id user_$arg_userid; +} +``` + +A request to `/sub/foo?userid=1234` will subscribe to channels "shared_foo" and "user_1234" via a multiplexed connection. If you later send a `DELETE` request to `/pub/user?userid=1234`, this subscriber will be disconnected and therefore unsubscribed from both "user_1234" and "shared_foo". + ## Variables Nchan makes several variables usabled in the config file: @@ -401,13 +1004,16 @@ Nchan makes several variables usabled in the config file: For subscriber locations, this variable is set to the subscriber type (websocket, longpoll, etc.). - `$nchan_publisher_type` - For subscriber locations, this variable is set to the subscriber type (http or websocket). + For publisher locations, this variable is set to the subscriber type (http or websocket). - `$nchan_prev_message_id`, `$nchan_message_id` The current and previous (if applicable) message id for publisher request or subscriber response. - `$nchan_channel_event` For channel events, this is the event name. Useful when configuring `nchan_channel_event_string`. + +- `$nchan_version` + Current Nchan version. Available since 1.1.5. Additionally, `nchan_stub_status` data is also exposed as variables. These are available only when `nchan_stub_status` is enabled on at least one location: @@ -440,18 +1046,72 @@ Additionally, `nchan_stub_status` data is also exposed as variables. These are a > Split the channel id into several ids for multiplexing using the delimiter string provided. [more details](#channel-multiplexing) +- **nchan_deflate_message_for_websocket** `[ on | off ]` + arguments: 1 + default: `off` + context: server, location + > Store a compressed (deflated) copy of the message along with the original to be sent to websocket clients supporting the permessage-deflate protocol extension + - **nchan_eventsource_event** arguments: 1 default: `(none)` context: server, location, if > Set the EventSource `event:` line to this value. When used in a publisher location, overrides the published message's `X-EventSource-Event` header and associates the message with the given value. When used in a subscriber location, overrides all messages' associated `event:` string with the given value. +- **nchan_eventsource_ping_comment** + arguments: 1 + default: `(empty)` + context: server, location, if + > Set the EventSource comment `: ...` line for periodic pings from server to client. Newlines are not allowed. If empty, no comment is sent with the ping. + +- **nchan_eventsource_ping_data** + arguments: 1 + default: `(empty)` + context: server, location, if + > Set the EventSource `data:` line for periodic pings from server to client. Newlines are not allowed. If empty, no data is sent with the ping. + +- **nchan_eventsource_ping_event** + arguments: 1 + default: `ping` + context: server, location, if + > Set the EventSource `event:` line for periodic pings from server to client. Newlines are not allowed. If empty, no event type is sent with the ping. + +- **nchan_eventsource_ping_interval** ` (seconds)` + arguments: 1 + default: `0 (none)` + context: server, location, if + > Interval for sending ping messages to EventSource subscribers. Disabled by default. + - **nchan_longpoll_multipart_response** `[ off | on | raw ]` arguments: 1 default: `off` context: server, location, if > when set to 'on', enable sending multiple messages in a single longpoll response, separated using the multipart/mixed content-type scheme. If there is only one available message in response to a long-poll request, it is sent unmodified. This is useful for high-latency long-polling connections as a way to minimize round-trips to the server. When set to 'raw', sends multiple messages using the http-raw-stream message separator. +- **nchan_permessage_deflate_compression_level** `[ 0-9 ]` + arguments: 1 + default: `6` + context: http + > Compression level for the `deflate` algorithm used in websocket's permessage-deflate extension. 0: no compression, 1: fastest, worst, 9: slowest, best + +- **nchan_permessage_deflate_compression_memlevel** `[ 1-9 ]` + arguments: 1 + default: `8` + context: http + > Memory level for the `deflate` algorithm used in websocket's permessage-deflate extension. How much memory should be allocated for the internal compression state. 1 - minimum memory, slow and reduces compression ratio; 9 - maximum memory for optimal speed + +- **nchan_permessage_deflate_compression_strategy** `[ default | filtered | huffman-only | rle | fixed ]` + arguments: 1 + default: `default` + context: http + > Compression strategy for the `deflate` algorithm used in websocket's permessage-deflate extension. Use 'default' for normal data, For details see [zlib's section on copression strategies](http://zlib.net/manual.html#Advanced) + +- **nchan_permessage_deflate_compression_window** `[ 9-15 ]` + arguments: 1 + default: `10` + context: http + > Compression window for the `deflate` algorithm used in websocket's permessage-deflate extension. The base two logarithm of the window size (the size of the history buffer). The bigger the window, the better the compression, but the more memory used by the compressor. + - **nchan_publisher** `[ http | websocket ]` arguments: 0 - 2 default: `http websocket` @@ -471,7 +1131,7 @@ Additionally, `nchan_stub_status` data is also exposed as variables. These are a context: server, location, if > Send POST request to internal location (which may proxy to an upstream server) with published message in the request body. Useful for bridging websocket publishers with HTTP applications, or for transforming message via upstream application before publishing to a channel. > The upstream response code determines how publishing will proceed. A `200 OK` will publish the message from the upstream response's body. A `304 Not Modified` will publish the message as it was received from the publisher. A `204 No Content` will result in the message not being published. - [more details](https://nchan.slact.net/details#message-publishing-callbacks) + [more details](#message-forwarding) - **nchan_pubsub** `[ http | websocket | eventsource | longpoll | intervalpoll | chunked | multipart-mixed | http-raw-stream ]` arguments: 0 - 6 @@ -480,6 +1140,12 @@ Additionally, `nchan_stub_status` data is also exposed as variables. These are a > Defines a server or location as a pubsub endpoint. For long-polling, GETs subscribe. and POSTs publish. For Websockets, publishing data on a connection does not yield a channel metadata response. Without additional configuration, this turns a location into an echo server. [more details](#pubsub-endpoint) +- **nchan_subscribe_request** `` + arguments: 1 + context: server, location, if + > Send GET request to internal location (which may proxy to an upstream server) after subscribing. Disabled for longpoll and interval-polling subscribers. + [more details](#subscriber-presence) + - **nchan_subscriber** `[ websocket | eventsource | longpoll | intervalpoll | chunked | multipart-mixed | http-raw-stream ]` arguments: 0 - 5 default: `websocket eventsource longpoll chunked multipart-mixed` @@ -535,37 +1201,111 @@ Additionally, `nchan_stub_status` data is also exposed as variables. These are a legacy name: push_subscriber_timeout > Maximum time a subscriber may wait for a message before being disconnected. If you don't want a subscriber's connection to timeout, set this to 0. When possible, the subscriber will get a response with a `408 Request Timeout` status; otherwise the subscriber will simply be disconnected. +- **nchan_unsubscribe_request** `` + arguments: 1 + context: server, location, if + > Send GET request to internal location (which may proxy to an upstream server) after unsubscribing. Disabled for longpoll and interval-polling subscribers. + [more details](#subscriber-presence) + +- **nchan_websocket_client_heartbeat** ` ` + arguments: 2 + default: `none (disabled)` + context: server, location, if + > Most browser Websocket clients do not allow manually sending PINGs to the server. To overcome this limitation, this setting can be used to set up a PING/PONG message/response connection heartbeat. When the client sends the server message *heartbeat_in* (PING), the server automatically responds with *heartbeat_out* (PONG). + - **nchan_websocket_ping_interval** ` (seconds)` arguments: 1 default: `0 (none)` context: server, location, if > Interval for sending websocket ping frames. Disabled by default. +- **nchan_access_control_allow_credentials** + arguments: 1 + default: `on` + context: http, server, location, if + > When enabled, sets the [Cross-Origin Resource Sharing (CORS)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS) `Access-Control-Allow-Credentials` header to `true`. + +- **nchan_access_control_allow_origin** `` + arguments: 1 + default: `$http_origin` + context: http, server, location, if + > Set the [Cross-Origin Resource Sharing (CORS)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS) `Access-Control-Allow-Origin` header to this value. If the incoming request's `Origin` header does not match this value, respond with a `403 Forbidden`. Multiple origins can be provided in a single argument separated with a space. + - **nchan_authorize_request** `` arguments: 1 context: server, location, if > Send GET request to internal location (which may proxy to an upstream server) for authorization of a publisher or subscriber request. A 200 response authorizes the request, a 403 response forbids it. - [more details](https://nchan.slact.net/details#request-authorization) + [more details](#request-authorization) -- **nchan_subscribe_request** `` +- **nchan_channel_group** `` arguments: 1 + default: `(none)` context: server, location, if - > Send GET request to internal location (which may proxy to an upstream server) after subscribing. Disabled for longpoll and interval-polling subscribers. - [more details](https://nchan.slact.net/details#subsribe-and-unsubscribe-callbacks) + legacy name: push_channel_group + > The accounting and security group a channel belongs to. Works like a prefix string to the channel id. Can be set with nginx variables. -- **nchan_unsubscribe_request** `` +- **nchan_channel_group_accounting** arguments: 1 - context: server, location, if - > Send GET request to internal location (which may proxy to an upstream server) after unsubscribing. Disabled for longpoll and interval-polling subscribers. - [more details](https://nchan.slact.net/details#subsribe-and-unsubscribe-callbacks) + default: `off` + context: server, location + > Enable tracking channel, subscriber, and message information on a per-channel-group basis. Can be used to place upper limits on channel groups. -- **nchan_max_reserved_memory** `` +- **nchan_group_location** `[ get | set | delete | off ]` + arguments: 0 - 3 + default: `get set delete` + context: location + > Group information and configuration location. GET request for group info, POST to set limits, DELETE to delete all channels in group. + +- **nchan_group_max_channels** `` arguments: 1 - default: `32M` - context: http - legacy name: push_max_reserved_memory - > The size of the shared memory chunk this module will use for message queuing and buffering. - [more details](#memory-storage) + default: `0 (unlimited)` + context: location + > Maximum number of channels allowed in the group. + +- **nchan_group_max_messages** `` + arguments: 1 + default: `0 (unlimited)` + context: location + > Maximum number of messages allowed for all the channels in the group. + +- **nchan_group_max_messages_disk** `` + arguments: 1 + default: `0 (unlimited)` + context: location + > Maximum amount of disk space allowed for the messages of all the channels in the group. + +- **nchan_group_max_messages_memory** `` + arguments: 1 + default: `0 (unlimited)` + context: location + > Maximum amount of shared memory allowed for the messages of all the channels in the group. + +- **nchan_group_max_subscribers** `` + arguments: 1 + default: `0 (unlimited)` + context: location + > Maximum number of subscribers allowed for the messages of all the channels in the group. + +- **nchan_max_channel_id_length** `` + arguments: 1 + default: `1024` + context: http, server, location + legacy name: push_max_channel_id_length + > Maximum permissible channel id length (number of characters). This settings applies to ids before they may be split by the `nchan_channel_id_split_delimiter` Requests with a channel id that is too long will receive a `403 Forbidden` response. + +- **nchan_max_channel_subscribers** `` + arguments: 1 + default: `0 (unlimited)` + context: http, server, location + legacy name: push_max_channel_subscribers + > Maximum concurrent subscribers to the channel on this Nchan server. Does not include subscribers on other Nchan instances when using a shared Redis server. + +- **nchan_subscribe_existing_channels_only** `[ on | off ]` + arguments: 1 + default: `off` + context: http, server, location + legacy name: push_authorized_channels_only + > Whether or not a subscriber may create a channel by sending a request to a subscriber location. If set to on, a publisher must send a POST or PUT request before a subscriber can request messages on the channel. Otherwise, all subscriber requests to nonexistent channels will get a 403 Forbidden response. - **nchan_message_buffer_length** `[ | ]` arguments: 1 @@ -574,6 +1314,12 @@ Additionally, `nchan_stub_status` data is also exposed as variables. These are a legacy names: push_max_message_buffer_length, push_message_buffer_length > Publisher configuration setting the maximum number of messages to store per channel. A channel's message buffer will retain a maximum of this many most recent messages. An Nginx variable can also be used to set the buffer length dynamically. +- **nchan_message_temp_path** `` + arguments: 1 + default: `` + context: http + > Large messages are stored in temporary files in the `client_body_temp_path` or the `nchan_message_temp_path` if the former is unavailable. Default is the built-in default `client_body_temp_path` + - **nchan_message_timeout** `[

' after the header */ + ngx_flag_t hide_parent; /**< Hide parent directory. */ ngx_str_t header; /**< File name for header, or empty if none. */ ngx_str_t footer; /**< File name for footer, or empty if none. */ @@ -258,7 +259,7 @@ static char *ngx_http_fancyindex_ignore(ngx_conf_t *cf, void *conf); static uintptr_t - ngx_fancyindex_escape_uri(u_char *dst, u_char*src, size_t size); + ngx_fancyindex_escape_filename(u_char *dst, u_char*src, size_t size); /* * These are used only once per handler invocation. We can tell GCC to @@ -361,6 +362,13 @@ static ngx_command_t ngx_http_fancyindex_commands[] = { offsetof(ngx_http_fancyindex_loc_conf_t, show_path), NULL }, + { ngx_string("fancyindex_hide_parent_dir"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_fancyindex_loc_conf_t, hide_parent), + NULL }, + { ngx_string("fancyindex_time_format"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, ngx_conf_set_str_slot, @@ -410,8 +418,15 @@ static const ngx_str_t css_href_post = ngx_string("\" type=\"text/css\"/>\n"); +#ifdef NGX_ESCAPE_URI_COMPONENT +static inline uintptr_t +ngx_fancyindex_escape_filename(u_char *dst, u_char *src, size_t size) +{ + return ngx_escape_uri(dst, src, size, NGX_ESCAPE_URI_COMPONENT); +} +#else /* !NGX_ESCAPE_URI_COMPONENT */ static uintptr_t -ngx_fancyindex_escape_uri(u_char *dst, u_char *src, size_t size) +ngx_fancyindex_escape_filename(u_char *dst, u_char *src, size_t size) { /* * The ngx_escape_uri() function will not escape colons or the @@ -483,6 +498,7 @@ ngx_fancyindex_escape_uri(u_char *dst, u_char *src, size_t size) return escapes + uescapes; } } +#endif /* NGX_ESCAPE_URI_COMPONENT */ static ngx_inline ngx_buf_t* @@ -716,9 +732,9 @@ make_content_buf( return ngx_http_fancyindex_error(r, &dir, &path); ngx_cpystrn(entry->name.data, ngx_de_name(&dir), len + 1); - entry->escape = 2 * ngx_fancyindex_escape_uri(NULL, - ngx_de_name(&dir), - len); + entry->escape = 2 * ngx_fancyindex_escape_filename(NULL, + ngx_de_name(&dir), + len); entry->dir = ngx_de_is_dir(&dir); entry->mtime = ngx_de_mtime(&dir); @@ -901,7 +917,7 @@ make_content_buf( tp = ngx_timeofday(); /* "Parent dir" entry, always first if displayed */ - if (r->uri.len > 1) { + if (r->uri.len > 1 && alcf->hide_parent == 0) { b->last = ngx_cpymem_ssz(b->last, "" "Parent directory/" "-" "-" - ""); + "" + CRLF); } /* Entries for directories and files */ @@ -922,9 +939,9 @@ make_content_buf( b->last = ngx_cpymem_ssz(b->last, "last, - entry[i].name.data, - entry[i].name.len); + ngx_fancyindex_escape_filename(b->last, + entry[i].name.data, + entry[i].name.len); b->last += entry[i].name.len + entry[i].escape; @@ -1315,6 +1332,7 @@ ngx_http_fancyindex_create_loc_conf(ngx_conf_t *cf) conf->ignore = NGX_CONF_UNSET_PTR; conf->hide_symlinks = NGX_CONF_UNSET; conf->show_path = NGX_CONF_UNSET; + conf->hide_parent = NGX_CONF_UNSET; return conf; } @@ -1343,6 +1361,7 @@ ngx_http_fancyindex_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_ptr_value(conf->ignore, prev->ignore, NULL); ngx_conf_merge_value(conf->hide_symlinks, prev->hide_symlinks, 0); + ngx_conf_merge_value(conf->hide_parent, prev->hide_parent, 0); /* Just make sure we haven't disabled the show_path directive without providing a custom header */ if (conf->show_path == 0 && conf->header.len == 0) diff --git a/debian/modules/http-fancyindex/t/06-hide_parent.test b/debian/modules/http-fancyindex/t/06-hide_parent.test new file mode 100644 index 0000000..494c958 --- /dev/null +++ b/debian/modules/http-fancyindex/t/06-hide_parent.test @@ -0,0 +1,23 @@ +#! /bin/bash +cat <<--- +This test check the output using "fancyindex_hide_parent_dir on" +-- +use pup +nginx_start 'fancyindex_hide_parent_dir on;' + +content=$( fetch /child-directory/ ) + +# Check page title +[[ $(pup -p title text{} <<< "${content}") = "Index of /child-directory/" ]] + +# Check table headers +[[ $(pup -n body table tbody tr:first-child td <<< "${content}") -eq 3 ]] +{ + read -r name_label + read -r size_label + read -r date_label +} < <( pup -p body table tbody tr:first-child td text{} <<< "${content}" ) +[[ ${name_label} != Parent\ Directory/ ]] +[[ ${name_label} = empty-file.txt ]] +[[ ${size_label} != - ]] +[[ ${date_label} != - ]] diff --git a/debian/modules/http-fancyindex/t/bug95-square-brackets.test b/debian/modules/http-fancyindex/t/bug95-square-brackets.test new file mode 100644 index 0000000..16e1ddc --- /dev/null +++ b/debian/modules/http-fancyindex/t/bug95-square-brackets.test @@ -0,0 +1,19 @@ +#! /bin/bash +cat <<--- +Bug #95: FancyIndex does not encode square brackets +https://github.com/aperezdc/ngx-fancyindex/issues/95 +-- +use pup + +# Prepare a directory with a file that contains square brackets in the name. +mkdir -p "${TESTDIR}/bug95" +touch "${TESTDIR}"/bug95/'bug[95].txt' + +nginx_start +content=$(fetch /bug95/) +test -n "${content}" || fail 'Empty response' + +expected_href='bug%5B95%5D.txt' +obtained_href=$(pup -p body tbody 'tr:nth-child(2)' a 'attr{href}' <<< "${content}") +test "${expected_href}" = "${obtained_href}" || \ + fail 'Expected: %s - Obtained: %s' "${expected_href}" "${obtained_href}" diff --git a/debian/modules/http-fancyindex/t/child-directory/empty-file.txt b/debian/modules/http-fancyindex/t/child-directory/empty-file.txt new file mode 100644 index 0000000..e69de29 diff --git a/debian/modules/http-fancyindex/template.h b/debian/modules/http-fancyindex/template.h index 27b9500..2d6604b 100644 --- a/debian/modules/http-fancyindex/template.h +++ b/debian/modules/http-fancyindex/template.h @@ -57,9 +57,9 @@ static const u_char t06_list1[] = "" "" "" "" -"" -"" -"" +"" +"" +"" "" "" "\n" diff --git a/debian/modules/http-fancyindex/template.html b/debian/modules/http-fancyindex/template.html index 8e478f8..b2a3174 100644 --- a/debian/modules/http-fancyindex/template.html +++ b/debian/modules/http-fancyindex/template.html @@ -55,9 +55,9 @@
File Name  ↓ File Size  ↓ Date  ↓ File Name  ↓ File Size  ↓ Date  ↓ 
- - - + + + From dd794d9830967ad1ff407c78699201fb53ff3237 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Nov=C3=BD?= Date: Fri, 29 May 2020 07:59:08 +0200 Subject: [PATCH 035/329] Enable CI --- debian/gitlab-ci.yml | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 debian/gitlab-ci.yml diff --git a/debian/gitlab-ci.yml b/debian/gitlab-ci.yml new file mode 100644 index 0000000..557434c --- /dev/null +++ b/debian/gitlab-ci.yml @@ -0,0 +1,8 @@ +--- +include: + - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/salsa-ci.yml + - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/pipeline-jobs.yml + +# Disable reprotest which is failing now +variables: + SALSA_CI_DISABLE_REPROTEST: 1 From ead863a42cf70ce2ba6f98dd2cfe560f9c8b0c0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Nov=C3=BD?= Date: Fri, 29 May 2020 19:00:17 +0200 Subject: [PATCH 036/329] d/copyright: Add myself for Debian part --- debian/copyright | 1 + 1 file changed, 1 insertion(+) diff --git a/debian/copyright b/debian/copyright index 66a44d8..29d7d04 100644 --- a/debian/copyright +++ b/debian/copyright @@ -35,6 +35,7 @@ Copyright: 2007-2009, Fabio Tranchitella 2011 Dmitry E. Oboukhov 2011-2013, Cyril Lavier 2013-2016, Christos Trochalakis + 2020, Ondřej Nový License: BSD-2-clause Files: debian/modules/http-headers-more-filter/* From 8838bdc5f148f2e14218243362d557f876fc87f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Nov=C3=BD?= Date: Fri, 29 May 2020 19:00:50 +0200 Subject: [PATCH 037/329] Add myself as uploader --- debian/control | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/debian/control b/debian/control index 835af43..ffea058 100644 --- a/debian/control +++ b/debian/control @@ -2,7 +2,8 @@ Source: nginx Section: httpd Priority: optional Maintainer: Debian Nginx Maintainers -Uploaders: Christos Trochalakis +Uploaders: Christos Trochalakis , + Ondřej Nový , Build-Depends: debhelper-compat (= 13), dpkg-dev (>= 1.15.5), libexpat-dev, From 693c482e5c75d757d609d5c61691842fdc016e2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Nov=C3=BD?= Date: Fri, 29 May 2020 19:03:44 +0200 Subject: [PATCH 038/329] releasing package nginx version 1.18.0-1 --- debian/changelog | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/debian/changelog b/debian/changelog index cc8aeb0..3eeacf1 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,8 +1,28 @@ -nginx (1.18.0-1) UNRELEASED; urgency=medium +nginx (1.18.0-1) unstable; urgency=medium - * New upstream version. + [ Ondřej Nový ] + * New upstream version 1.18.0 + * Add REMOTE_USER fastcgi param + * Use debhelper-compat instead of debian/compat + * Replace dh_systemd_enable with dh_installsystemd + * Set Rules-Requires-Root: no + * d/rules/dh_installinit: Replace --no-restart-on-upgrade with + --no-stop-on-upgrade + * Bump debhelper compat level to 13 + * Use package.maintscript instead of dpkg-maintscript-helper + * Bump standards version to 4.5.0 + * d/watch: Change to 1.18.x + * d/patches/CVE-2019-20372.patch: Rebase + * Convert d/ngxmod to Python 3 (Closes: #953025) + * nchan: Upgrade to 1.2.7 + * http-fancyindex: Upgrade to 0.4.4 + * d/copyright: Add myself for Debian part + * Add myself as uploader - -- Ondřej Nový Thu, 28 May 2020 22:05:22 +0200 + [ Mohamed Akram ] + * Enable --with-compat configure option (Closes: #897926) + + -- Ondřej Nový Fri, 29 May 2020 19:03:30 +0200 nginx (1.16.1-3) unstable; urgency=high From 134d203c26598258fa5e4991dd21e4f0a1b6841f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Nov=C3=BD?= Date: Thu, 4 Jun 2020 09:38:07 +0200 Subject: [PATCH 039/329] d/conf/sites-available/default: Update PHP path for PHP 7.4 --- debian/conf/sites-available/default | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/conf/sites-available/default b/debian/conf/sites-available/default index f5c5e1b..c5af914 100644 --- a/debian/conf/sites-available/default +++ b/debian/conf/sites-available/default @@ -57,7 +57,7 @@ server { # include snippets/fastcgi-php.conf; # # # With php-fpm (or other unix sockets): - # fastcgi_pass unix:/run/php/php7.3-fpm.sock; + # fastcgi_pass unix:/run/php/php7.4-fpm.sock; # # With php-cgi (or other tcp sockets): # fastcgi_pass 127.0.0.1:9000; #} From c6872b4f53c1198a59deb80f65c7d43a988c0e51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Nov=C3=BD?= Date: Thu, 4 Jun 2020 09:41:10 +0200 Subject: [PATCH 040/329] d/conf/nginx.conf: Enable TLSv1.3 --- debian/conf/nginx.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/conf/nginx.conf b/debian/conf/nginx.conf index 132f680..9ee6e06 100644 --- a/debian/conf/nginx.conf +++ b/debian/conf/nginx.conf @@ -31,7 +31,7 @@ http { # SSL Settings ## - ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE + ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE ssl_prefer_server_ciphers on; ## From 4851b6ec88ae2597acd344d74d8f9997e6229f4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= Date: Fri, 4 Jan 2019 09:14:41 +0000 Subject: [PATCH 041/329] http-geoip2: Add ngx_http_geoip2_module 3.3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Ondřej Nový --- debian/control | 13 + debian/copyright | 4 + debian/libnginx-mod-http-geoip2.nginx | 13 + debian/libnginx-mod.conf/mod-http-geoip2.conf | 1 + debian/modules/control | 4 + debian/modules/http-geoip2/LICENSE | 23 + debian/modules/http-geoip2/README.md | 133 +++ debian/modules/http-geoip2/config | 43 + .../http-geoip2/ngx_http_geoip2_module.c | 793 ++++++++++++++++++ .../http-geoip2/ngx_stream_geoip2_module.c | 694 +++++++++++++++ debian/modules/watch/http-geoip2 | 4 + debian/rules | 2 + debian/tests/control | 3 + 13 files changed, 1730 insertions(+) create mode 100755 debian/libnginx-mod-http-geoip2.nginx create mode 100644 debian/libnginx-mod.conf/mod-http-geoip2.conf create mode 100644 debian/modules/http-geoip2/LICENSE create mode 100644 debian/modules/http-geoip2/README.md create mode 100644 debian/modules/http-geoip2/config create mode 100644 debian/modules/http-geoip2/ngx_http_geoip2_module.c create mode 100644 debian/modules/http-geoip2/ngx_stream_geoip2_module.c create mode 100644 debian/modules/watch/http-geoip2 diff --git a/debian/control b/debian/control index ffea058..b3ec941 100644 --- a/debian/control +++ b/debian/control @@ -12,6 +12,7 @@ Build-Depends: debhelper-compat (= 13), libhiredis-dev, liblua5.1-0-dev [!i386 !amd64 !kfreebsd-i386 !armel !armhf !powerpc !powerpcspe !mips !mipsel], libluajit-5.1-dev [i386 amd64 kfreebsd-i386 armel armhf powerpc powerpcspe mips mipsel], + libmaxminddb-dev, libmhash-dev, libpam0g-dev, libpcre3-dev, @@ -71,6 +72,7 @@ Depends: libnginx-mod-http-auth-pam (= ${binary:Version}), libnginx-mod-http-dav-ext (= ${binary:Version}), libnginx-mod-http-echo (= ${binary:Version}), libnginx-mod-http-geoip (= ${binary:Version}), + libnginx-mod-http-geoip2 (= ${binary:Version}), libnginx-mod-http-image-filter (= ${binary:Version}), libnginx-mod-http-subs-filter (= ${binary:Version}), libnginx-mod-http-upstream-fair (= ${binary:Version}), @@ -142,6 +144,7 @@ Depends: libnginx-mod-http-auth-pam (= ${binary:Version}), libnginx-mod-http-echo (= ${binary:Version}), libnginx-mod-http-fancyindex (= ${binary:Version}), libnginx-mod-http-geoip (= ${binary:Version}), + libnginx-mod-http-geoip2 (= ${binary:Version}), libnginx-mod-http-headers-more-filter (= ${binary:Version}), libnginx-mod-http-image-filter (= ${binary:Version}), libnginx-mod-http-lua (= ${binary:Version}), @@ -195,6 +198,16 @@ Description: GeoIP HTTP module for Nginx Those variables include country, region, city, latitude, longitude, postal code, etc. +Package: libnginx-mod-http-geoip2 +Architecture: any +Depends: ${misc:Depends}, ${shlibs:Depends} +Description: GeoIP2 HTTP module for Nginx + The ngx_http_geoip2 module creates variables with values depending on the + client IP address, using the precompiled MaxMind GeoIP2 databases. + . + Those variables include country, region, city, latitude, longitude, postal + code, etc. + Package: libnginx-mod-http-image-filter Architecture: any Depends: ${misc:Depends}, ${shlibs:Depends} diff --git a/debian/copyright b/debian/copyright index 29d7d04..3fb1c3f 100644 --- a/debian/copyright +++ b/debian/copyright @@ -44,6 +44,10 @@ Copyright: Copyright (c) 2009-2014, Yichun "agentzh" Zhang (章亦春) +License: BSD-2-clause + Files: debian/modules/http-ndk/* Copyright: Marcus Clyne License: BSD-3-clause diff --git a/debian/libnginx-mod-http-geoip2.nginx b/debian/libnginx-mod-http-geoip2.nginx new file mode 100755 index 0000000..78c206f --- /dev/null +++ b/debian/libnginx-mod-http-geoip2.nginx @@ -0,0 +1,13 @@ +#!/usr/bin/perl -w + +use File::Basename; + +# Guess module name +$module = basename($0, '.nginx'); +$module =~ s/^libnginx-mod-//; + +$modulepath = $module; +$modulepath =~ s/-/_/g; + +print "mod debian/build-extras/objs/ngx_${modulepath}_module.so\n"; +print "mod debian/libnginx-mod.conf/mod-${module}.conf\n"; diff --git a/debian/libnginx-mod.conf/mod-http-geoip2.conf b/debian/libnginx-mod.conf/mod-http-geoip2.conf new file mode 100644 index 0000000..9441b29 --- /dev/null +++ b/debian/libnginx-mod.conf/mod-http-geoip2.conf @@ -0,0 +1 @@ +load_module modules/ngx_http_geoip2_module.so; diff --git a/debian/modules/control b/debian/modules/control index d36b386..8f9964d 100644 --- a/debian/modules/control +++ b/debian/modules/control @@ -16,6 +16,10 @@ Homepage: https://github.com/agentzh/echo-nginx-module Version: v0.61 Files-Excluded: .gitignore .gitattributes .travis.yml +Module: http-geoip2 +Homepage: https://github.com/leev/ngx_http_geoip2_module +Version: 3.3 + Module: http-lua Homepage: https://github.com/openresty/lua-nginx-module Version: 0.10.13 diff --git a/debian/modules/http-geoip2/LICENSE b/debian/modules/http-geoip2/LICENSE new file mode 100644 index 0000000..fdc13a7 --- /dev/null +++ b/debian/modules/http-geoip2/LICENSE @@ -0,0 +1,23 @@ +Copyright (c) 2014, Lee Valentine +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/debian/modules/http-geoip2/README.md b/debian/modules/http-geoip2/README.md new file mode 100644 index 0000000..a5aec97 --- /dev/null +++ b/debian/modules/http-geoip2/README.md @@ -0,0 +1,133 @@ +Description +=========== + +**ngx_http_geoip2_module** - creates variables with values from the maxmind geoip2 databases based on the client IP (default) or from a specific variable (supports both IPv4 and IPv6) + +The module now supports nginx streams and can be used in the same way the http module can be used. + +## Installing +First install [libmaxminddb](https://github.com/maxmind/libmaxminddb) as described in its [README.md +file](https://github.com/maxmind/libmaxminddb/blob/master/README.md#installing-from-a-tarball). + +#### Download nginx source +``` +wget http://nginx.org/download/nginx-VERSION.tar.gz +tar zxvf nginx-VERSION.tar.gz +cd nginx-VERSION +``` + +##### To build as a dynamic module (nginx 1.9.11+): +``` +./configure --add-dynamic-module=/path/to/ngx_http_geoip2_module +make +make install +``` + +This will produce ```objs/ngx_http_geoip2_module.so```. It can be copied to your nginx module path manually if you wish. + +Add the following line to your nginx.conf: +``` +load_module modules/ngx_http_geoip2_module.so; +``` + +##### To build as a static module: +``` +./configure --add-module=/path/to/ngx_http_geoip2_module +make +make install +``` + +## Download Maxmind GeoLite2 Database (optional) +The free GeoLite2 databases are available from [Maxminds website](http://dev.maxmind.com/geoip/geoip2/geolite2/) + +[GeoLite2 City](http://geolite.maxmind.com/download/geoip/database/GeoLite2-City.mmdb.gz) +[GeoLite2 Country](http://geolite.maxmind.com/download/geoip/database/GeoLite2-Country.mmdb.gz) + +## Example Usage: +``` +http { + ... + geoip2 /etc/maxmind-country.mmdb { + auto_reload 5m; + $geoip2_metadata_country_build metadata build_epoch; + $geoip2_data_country_code default=US source=$variable_with_ip country iso_code; + $geoip2_data_country_name country names en; + } + + geoip2 /etc/maxmind-city.mmdb { + $geoip2_data_city_name default=London city names en; + } + .... + + fastcgi_param COUNTRY_CODE $geoip2_data_country_code; + fastcgi_param COUNTRY_NAME $geoip2_data_country_name; + fastcgi_param CITY_NAME $geoip2_data_city_name; + .... +} + +stream { + ... + geoip2 /etc/maxmind-country.mmdb { + $geoip2_data_country_code default=US source=$remote_addr country iso_code; + } + ... +} +``` + +##### Metadata: +Retrieve metadata regarding the geoip database. +``` +$variable_name metadata +``` +Available fields: + - build_epoch: the build timestamp of the maxmind database. + - last_check: the last time the database was checked for changes (when using auto_reload) + - last_change: the last time the database was reloaded (when using auto_reload) + +##### Autoreload (default: disabled): +Enabling auto reload will have nginx check the modification time of the database at the specified +interval and reload it if it has changed. +``` +auto_reload +``` + +##### GeoIP: +``` +$variable_name [default= + "iso_code": + "US" + "names": + { + "de": + "USA" + "en": + "United States" + } + } + } + +$ mmdblookup --file /usr/share/GeoIP/GeoIP2-Country.mmdb --ip 8.8.8.8 country names en + + "United States" +``` + +This translates to: + +``` +$country_name "default=United States" source=$remote_addr country names en +``` diff --git a/debian/modules/http-geoip2/config b/debian/modules/http-geoip2/config new file mode 100644 index 0000000..48bf15d --- /dev/null +++ b/debian/modules/http-geoip2/config @@ -0,0 +1,43 @@ +ngx_feature="MaxmindDB library" +ngx_feature_name= +ngx_feature_run=no +ngx_feature_incs="#include " +ngx_feature_libs=-lmaxminddb +ngx_feature_test="MMDB_s mmdb" +. auto/feature + +ngx_addon_name="ngx_geoip2_module" + +if [ $ngx_found = yes ]; then + if test -n "$ngx_module_link"; then + if [ $HTTP != NO ]; then + ngx_module_type=HTTP + ngx_module_name="ngx_http_geoip2_module" + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs="$ngx_addon_dir/ngx_http_geoip2_module.c" + ngx_module_libs="$ngx_feature_libs" + . auto/module + fi + + nginx_version=`awk '/^#define nginx_version / {print $3}' src/core/nginx.h` + if [ $STREAM != NO -a $nginx_version -gt 1011001 ]; then + ngx_module_type=STREAM + ngx_module_name="ngx_stream_geoip2_module" + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs="$ngx_addon_dir/ngx_stream_geoip2_module.c" + ngx_module_libs="$ngx_feature_libs" + . auto/module + fi + else + HTTP_MODULES="$HTTP_MODULES ngx_http_geoip2_module" + NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_geoip2_module.c" + CORE_LIBS="$CORE_LIBS $ngx_feature_libs" + fi +else + cat << END +$0: error: the geoip2 module requires the maxminddb library. +END + exit 1 +fi diff --git a/debian/modules/http-geoip2/ngx_http_geoip2_module.c b/debian/modules/http-geoip2/ngx_http_geoip2_module.c new file mode 100644 index 0000000..d27c94d --- /dev/null +++ b/debian/modules/http-geoip2/ngx_http_geoip2_module.c @@ -0,0 +1,793 @@ +/* + * Copyright (C) Lee Valentine + * + * Based on nginx's 'ngx_http_geoip_module.c' by Igor Sysoev + */ + + +#include +#include +#include + +#include + + +typedef struct { + MMDB_s mmdb; + MMDB_lookup_result_s result; + time_t last_check; + time_t last_change; + time_t check_interval; +#if (NGX_HAVE_INET6) + uint8_t address[16]; +#else + unsigned long address; +#endif + ngx_queue_t queue; +} ngx_http_geoip2_db_t; + +typedef struct { + ngx_queue_t databases; + ngx_array_t *proxies; + ngx_flag_t proxy_recursive; +} ngx_http_geoip2_conf_t; + +typedef struct { + ngx_http_geoip2_db_t *database; + const char **lookup; + ngx_str_t default_value; + ngx_http_complex_value_t source; +} ngx_http_geoip2_ctx_t; + +typedef struct { + ngx_http_geoip2_db_t *database; + ngx_str_t metavalue; +} ngx_http_geoip2_metadata_t; + + +static ngx_int_t ngx_http_geoip2_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_http_geoip2_metadata(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); +static void *ngx_http_geoip2_create_conf(ngx_conf_t *cf); +static char *ngx_http_geoip2_init_conf(ngx_conf_t *cf, void *conf); +static char *ngx_http_geoip2(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static char *ngx_http_geoip2_parse_config(ngx_conf_t *cf, ngx_command_t *dummy, + void *conf); +static char *ngx_http_geoip2_add_variable(ngx_conf_t *cf, ngx_command_t *dummy, + void *conf); +static char *ngx_http_geoip2_add_variable_geodata(ngx_conf_t *cf, + ngx_http_geoip2_db_t *database); +static char *ngx_http_geoip2_add_variable_metadata(ngx_conf_t *cf, + ngx_http_geoip2_db_t *database); +static char *ngx_http_geoip2_proxy(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static ngx_int_t ngx_http_geoip2_cidr_value(ngx_conf_t *cf, ngx_str_t *net, + ngx_cidr_t *cidr); +static void ngx_http_geoip2_cleanup(void *data); +static ngx_int_t ngx_http_geoip2_init(ngx_conf_t *cf); + + +#define FORMAT(fmt, ...) do { \ + p = ngx_palloc(r->pool, NGX_OFF_T_LEN); \ + if (p == NULL) { \ + return NGX_ERROR; \ + } \ + v->len = ngx_sprintf(p, fmt, __VA_ARGS__) - p; \ + v->data = p; \ +} while (0) + +static ngx_command_t ngx_http_geoip2_commands[] = { + + { ngx_string("geoip2"), + NGX_HTTP_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_TAKE1, + ngx_http_geoip2, + NGX_HTTP_MAIN_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("geoip2_proxy"), + NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1, + ngx_http_geoip2_proxy, + NGX_HTTP_MAIN_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("geoip2_proxy_recursive"), + NGX_HTTP_MAIN_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_MAIN_CONF_OFFSET, + offsetof(ngx_http_geoip2_conf_t, proxy_recursive), + NULL }, + + ngx_null_command +}; + + +static ngx_http_module_t ngx_http_geoip2_module_ctx = { + NULL, /* preconfiguration */ + ngx_http_geoip2_init, /* postconfiguration */ + + ngx_http_geoip2_create_conf, /* create main configuration */ + ngx_http_geoip2_init_conf, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + NULL, /* create location configuration */ + NULL /* merge location configuration */ +}; + + +ngx_module_t ngx_http_geoip2_module = { + NGX_MODULE_V1, + &ngx_http_geoip2_module_ctx, /* module context */ + ngx_http_geoip2_commands, /* module directives */ + NGX_HTTP_MODULE, /* module type */ + NULL, /* init master */ + NULL, /* init module */ + NULL, /* init process */ + NULL, /* init thread */ + NULL, /* exit thread */ + NULL, /* exit process */ + NULL, /* exit master */ + NGX_MODULE_V1_PADDING +}; + + +static ngx_int_t +ngx_http_geoip2_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, + uintptr_t data) +{ + ngx_http_geoip2_ctx_t *geoip2 = (ngx_http_geoip2_ctx_t *) data; + ngx_http_geoip2_db_t *database = geoip2->database; + int mmdb_error; + MMDB_entry_data_s entry_data; + ngx_http_geoip2_conf_t *gcf; + ngx_addr_t addr; + ngx_array_t *xfwd; + u_char *p; + ngx_str_t val; + +#if (NGX_HAVE_INET6) + uint8_t address[16], *addressp = address; +#else + unsigned long address; +#endif + + if (geoip2->source.value.len > 0) { + if (ngx_http_complex_value(r, &geoip2->source, &val) != NGX_OK) { + goto not_found; + } + + if (ngx_parse_addr(r->pool, &addr, val.data, val.len) != NGX_OK) { + goto not_found; + } + } else { + gcf = ngx_http_get_module_main_conf(r, ngx_http_geoip2_module); + addr.sockaddr = r->connection->sockaddr; + addr.socklen = r->connection->socklen; + + xfwd = &r->headers_in.x_forwarded_for; + + if (xfwd->nelts > 0 && gcf->proxies != NULL) { + (void) ngx_http_get_forwarded_addr(r, &addr, xfwd, NULL, + gcf->proxies, gcf->proxy_recursive); + } + } + + switch (addr.sockaddr->sa_family) { + case AF_INET: +#if (NGX_HAVE_INET6) + ngx_memset(addressp, 0, 12); + ngx_memcpy(addressp + 12, &((struct sockaddr_in *) + addr.sockaddr)->sin_addr.s_addr, 4); + break; + + case AF_INET6: + ngx_memcpy(addressp, &((struct sockaddr_in6 *) + addr.sockaddr)->sin6_addr.s6_addr, 16); +#else + address = ((struct sockaddr_in *)addr.sockaddr)->sin_addr.s_addr; +#endif + break; + + default: + goto not_found; + } + +#if (NGX_HAVE_INET6) + if (ngx_memcmp(&address, &database->address, sizeof(address)) + != 0) { +#else + if (address != database->address) { +#endif + memcpy(&database->address, &address, sizeof(address)); + database->result = MMDB_lookup_sockaddr(&database->mmdb, + addr.sockaddr, &mmdb_error); + + if (mmdb_error != MMDB_SUCCESS) { + goto not_found; + } + } + + if (!database->result.found_entry + || MMDB_aget_value(&database->result.entry, &entry_data, + geoip2->lookup) != MMDB_SUCCESS) { + goto not_found; + } + + if (!entry_data.has_data) { + goto not_found; + } + + switch (entry_data.type) { + case MMDB_DATA_TYPE_BOOLEAN: + FORMAT("%d", entry_data.boolean); + break; + case MMDB_DATA_TYPE_UTF8_STRING: + v->len = entry_data.data_size; + v->data = ngx_pnalloc(r->pool, v->len); + if (v->data == NULL) { + return NGX_ERROR; + } + ngx_memcpy(v->data, (u_char *) entry_data.utf8_string, v->len); + break; + case MMDB_DATA_TYPE_BYTES: + v->len = entry_data.data_size; + v->data = ngx_pnalloc(r->pool, v->len); + if (v->data == NULL) { + return NGX_ERROR; + } + ngx_memcpy(v->data, (u_char *) entry_data.bytes, v->len); + break; + case MMDB_DATA_TYPE_FLOAT: + FORMAT("%.5f", entry_data.float_value); + break; + case MMDB_DATA_TYPE_DOUBLE: + FORMAT("%.5f", entry_data.double_value); + break; + case MMDB_DATA_TYPE_UINT16: + FORMAT("%uD", entry_data.uint16); + break; + case MMDB_DATA_TYPE_UINT32: + FORMAT("%uD", entry_data.uint32); + break; + case MMDB_DATA_TYPE_INT32: + FORMAT("%D", entry_data.int32); + break; + case MMDB_DATA_TYPE_UINT64: + FORMAT("%uL", entry_data.uint64); + break; + case MMDB_DATA_TYPE_UINT128: ; +#if MMDB_UINT128_IS_BYTE_ARRAY + uint8_t *val = (uint8_t *)entry_data.uint128; + FORMAT( "0x%02x%02x%02x%02x%02x%02x%02x%02x" + "%02x%02x%02x%02x%02x%02x%02x%02x", + val[0], val[1], val[2], val[3], + val[4], val[5], val[6], val[7], + val[8], val[9], val[10], val[11], + val[12], val[13], val[14], val[15]); +#else + mmdb_uint128_t val = entry_data.uint128; + FORMAT("0x%016uxL%016uxL", + (uint64_t) (val >> 64), (uint64_t) val); +#endif + break; + default: + goto not_found; + } + + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + + return NGX_OK; + +not_found: + if (geoip2->default_value.len > 0) { + v->data = geoip2->default_value.data; + v->len = geoip2->default_value.len; + + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + } else { + v->not_found = 1; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_geoip2_metadata(ngx_http_request_t *r, ngx_http_variable_value_t *v, + uintptr_t data) +{ + ngx_http_geoip2_metadata_t *metadata = (ngx_http_geoip2_metadata_t *) data; + ngx_http_geoip2_db_t *database = metadata->database; + u_char *p; + + if (ngx_strncmp(metadata->metavalue.data, "build_epoch", 11) == 0) { + FORMAT("%uL", database->mmdb.metadata.build_epoch); + } else if (ngx_strncmp(metadata->metavalue.data, "last_check", 10) == 0) { + FORMAT("%T", database->last_check); + } else if (ngx_strncmp(metadata->metavalue.data, "last_change", 11) == 0) { + FORMAT("%T", database->last_change); + } else { + v->not_found = 1; + return NGX_OK; + } + + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + + return NGX_OK; +} + + +static void * +ngx_http_geoip2_create_conf(ngx_conf_t *cf) +{ + ngx_pool_cleanup_t *cln; + ngx_http_geoip2_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_geoip2_conf_t)); + if (conf == NULL) { + return NULL; + } + + conf->proxy_recursive = NGX_CONF_UNSET; + + cln = ngx_pool_cleanup_add(cf->pool, 0); + if (cln == NULL) { + return NULL; + } + + ngx_queue_init(&conf->databases); + + cln->handler = ngx_http_geoip2_cleanup; + cln->data = conf; + + return conf; +} + + +static char * +ngx_http_geoip2(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_geoip2_conf_t *gcf = conf; + ngx_str_t *value; + int status; + ngx_http_geoip2_db_t *database; + char *rv; + ngx_conf_t save; + ngx_queue_t *q; + + value = cf->args->elts; + + if (value[1].data && value[1].data[0] != '/') { + if (ngx_conf_full_name(cf->cycle, &value[1], 0) != NGX_OK) { + return NGX_CONF_ERROR; + } + } + + if (!ngx_queue_empty(&gcf->databases)) { + for (q = ngx_queue_head(&gcf->databases); + q != ngx_queue_sentinel(&gcf->databases); + q = ngx_queue_next(q)) + { + database = ngx_queue_data(q, ngx_http_geoip2_db_t, queue); + if (ngx_strcmp(value[1].data, database->mmdb.filename) == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "Duplicate GeoIP2 mmdb - %V", &value[1]); + return NGX_CONF_ERROR; + } + } + } + + database = ngx_pcalloc(cf->pool, sizeof(ngx_http_geoip2_db_t)); + if (database == NULL) { + return NGX_CONF_ERROR; + } + + ngx_queue_insert_tail(&gcf->databases, &database->queue); + database->last_check = database->last_change = ngx_time(); + + status = MMDB_open((char *) value[1].data, MMDB_MODE_MMAP, &database->mmdb); + + if (status != MMDB_SUCCESS) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "MMDB_open(\"%V\") failed - %s", &value[1], + MMDB_strerror(status)); + return NGX_CONF_ERROR; + } + + save = *cf; + cf->handler = ngx_http_geoip2_parse_config; + cf->handler_conf = (void *) database; + + rv = ngx_conf_parse(cf, NULL); + *cf = save; + return rv; +} + + +static char * +ngx_http_geoip2_parse_config(ngx_conf_t *cf, ngx_command_t *dummy, void *conf) +{ + ngx_http_geoip2_db_t *database; + ngx_str_t *value; + time_t interval; + + value = cf->args->elts; + + if (value[0].data[0] == '$') { + return ngx_http_geoip2_add_variable(cf, dummy, conf); + } + + if (value[0].len == 11 + && ngx_strncmp(value[0].data, "auto_reload", 11) == 0) { + if ((int) cf->args->nelts != 2) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid number of arguments for auto_reload"); + return NGX_CONF_ERROR; + } + + interval = ngx_parse_time(&value[1], true); + + if (interval == (time_t) NGX_ERROR) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid interval for auto_reload \"%V\"", + value[1]); + return NGX_CONF_ERROR; + } + + + database = (ngx_http_geoip2_db_t *) conf; + database->check_interval = interval; + return NGX_CONF_OK; + } + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid setting \"%V\"", &value[0]); + return NGX_CONF_ERROR; +} + + +static char * +ngx_http_geoip2_add_variable(ngx_conf_t *cf, ngx_command_t *dummy, void *conf) +{ + ngx_http_geoip2_db_t *database; + ngx_str_t *value; + int nelts; + + value = cf->args->elts; + + if (value[0].data[0] != '$') { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid variable name \"%V\"", &value[0]); + return NGX_CONF_ERROR; + } + + value[0].len--; + value[0].data++; + + nelts = (int) cf->args->nelts; + database = (ngx_http_geoip2_db_t *) conf; + + if (nelts > 0 && value[1].len == 8 && ngx_strncmp(value[1].data, "metadata", 8) == 0) { + return ngx_http_geoip2_add_variable_metadata(cf, database); + } + + return ngx_http_geoip2_add_variable_geodata(cf, database); +} + + +static char * +ngx_http_geoip2_add_variable_metadata(ngx_conf_t *cf, ngx_http_geoip2_db_t *database) +{ + ngx_http_geoip2_metadata_t *metadata; + ngx_str_t *value, name; + ngx_http_variable_t *var; + + metadata = ngx_pcalloc(cf->pool, sizeof(ngx_http_geoip2_metadata_t)); + if (metadata == NULL) { + return NGX_CONF_ERROR; + } + + value = cf->args->elts; + name = value[0]; + + metadata->database = database; + metadata->metavalue = value[2]; + + var = ngx_http_add_variable(cf, &name, NGX_HTTP_VAR_CHANGEABLE); + if (var == NULL) { + return NGX_CONF_ERROR; + } + + var->get_handler = ngx_http_geoip2_metadata; + var->data = (uintptr_t) metadata; + + return NGX_CONF_OK; +} + + +static char * +ngx_http_geoip2_add_variable_geodata(ngx_conf_t *cf, ngx_http_geoip2_db_t *database) +{ + ngx_http_geoip2_ctx_t *geoip2; + ngx_http_compile_complex_value_t ccv; + ngx_str_t *value, name, source; + ngx_http_variable_t *var; + int i, nelts, idx; + + geoip2 = ngx_pcalloc(cf->pool, sizeof(ngx_http_geoip2_ctx_t)); + if (geoip2 == NULL) { + return NGX_CONF_ERROR; + } + + geoip2->database = database; + ngx_str_null(&source); + + value = cf->args->elts; + name = value[0]; + + nelts = (int) cf->args->nelts; + idx = 1; + + if (nelts > idx) { + for (i = idx; i < nelts; i++) { + if (ngx_strnstr(value[idx].data, "=", value[idx].len) == NULL) { + break; + } + + if (value[idx].len > 8 && ngx_strncmp(value[idx].data, "default=", 8) == 0) { + if (geoip2->default_value.len > 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "default has already been declared for \"$%V\"", &name); + return NGX_CONF_ERROR; + } + + geoip2->default_value.len = value[idx].len - 8; + geoip2->default_value.data = value[idx].data + 8; + } else if (value[idx].len > 7 && ngx_strncmp(value[idx].data, "source=", 7) == 0) { + if (source.len > 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "source has already been declared for \"$%V\"", &name); + return NGX_CONF_ERROR; + } + + source.len = value[idx].len - 7; + source.data = value[idx].data + 7; + + if (source.data[0] != '$') { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid source variable name \"%V\"", &source); + return NGX_CONF_ERROR; + } + + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + ccv.cf = cf; + ccv.value = &source; + ccv.complex_value = &geoip2->source; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "unable to compile \"%V\" for \"$%V\"", &source, &name); + return NGX_CONF_ERROR; + } + } else { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid setting \"%V\" for \"$%V\"", &value[idx], &name); + return NGX_CONF_ERROR; + } + + idx++; + } + } + + var = ngx_http_add_variable(cf, &name, NGX_HTTP_VAR_CHANGEABLE); + if (var == NULL) { + return NGX_CONF_ERROR; + } + + geoip2->lookup = ngx_pcalloc(cf->pool, sizeof(const char *) * + (cf->args->nelts - (idx - 1))); + + if (geoip2->lookup == NULL) { + return NGX_CONF_ERROR; + } + + for (i = idx; i < nelts; i++) { + geoip2->lookup[i - idx] = (char *) value[i].data; + } + geoip2->lookup[i - idx] = NULL; + + var->get_handler = ngx_http_geoip2_variable; + var->data = (uintptr_t) geoip2; + + return NGX_CONF_OK; +} + + +static char * +ngx_http_geoip2_init_conf(ngx_conf_t *cf, void *conf) +{ + ngx_http_geoip2_conf_t *gcf = conf; + ngx_conf_init_value(gcf->proxy_recursive, 0); + return NGX_CONF_OK; +} + + +static char * +ngx_http_geoip2_proxy(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_geoip2_conf_t *gcf = conf; + ngx_str_t *value; + ngx_cidr_t cidr, *c; + + value = cf->args->elts; + + if (ngx_http_geoip2_cidr_value(cf, &value[1], &cidr) != NGX_OK) { + return NGX_CONF_ERROR; + } + + if (gcf->proxies == NULL) { + gcf->proxies = ngx_array_create(cf->pool, 4, sizeof(ngx_cidr_t)); + if (gcf->proxies == NULL) { + return NGX_CONF_ERROR; + } + } + + c = ngx_array_push(gcf->proxies); + if (c == NULL) { + return NGX_CONF_ERROR; + } + + *c = cidr; + + return NGX_CONF_OK; +} + + +static ngx_int_t +ngx_http_geoip2_cidr_value(ngx_conf_t *cf, ngx_str_t *net, ngx_cidr_t *cidr) +{ + ngx_int_t rc; + + if (ngx_strcmp(net->data, "255.255.255.255") == 0) { + cidr->family = AF_INET; + cidr->u.in.addr = 0xffffffff; + cidr->u.in.mask = 0xffffffff; + + return NGX_OK; + } + + rc = ngx_ptocidr(net, cidr); + + if (rc == NGX_ERROR) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid network \"%V\"", net); + return NGX_ERROR; + } + + if (rc == NGX_DONE) { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "low address bits of %V are meaningless", net); + } + + return NGX_OK; +} + + +static void +ngx_http_geoip2_cleanup(void *data) +{ + ngx_http_geoip2_conf_t *gcf = data; + ngx_queue_t *q; + ngx_http_geoip2_db_t *database; + + while (!ngx_queue_empty(&gcf->databases)) { + q = ngx_queue_head(&gcf->databases); + ngx_queue_remove(q); + database = ngx_queue_data(q, ngx_http_geoip2_db_t, queue); + MMDB_close(&database->mmdb); + } +} + + +static ngx_int_t +ngx_http_geoip2_log_handler(ngx_http_request_t *r) +{ + int status; + MMDB_s tmpdb; + ngx_queue_t *q; + ngx_file_info_t fi; + ngx_http_geoip2_db_t *database; + ngx_http_geoip2_conf_t *gcf; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "geoip2 http log handler"); + + gcf = ngx_http_get_module_main_conf(r, ngx_http_geoip2_module); + + if (ngx_queue_empty(&gcf->databases)) { + return NGX_OK; + } + + for (q = ngx_queue_head(&gcf->databases); + q != ngx_queue_sentinel(&gcf->databases); + q = ngx_queue_next(q)) + { + database = ngx_queue_data(q, ngx_http_geoip2_db_t, queue); + if (database->check_interval == 0) { + continue; + } + + if ((database->last_check + database->check_interval) + > ngx_time()) + { + continue; + } + + database->last_check = ngx_time(); + + if (ngx_file_info(database->mmdb.filename, &fi) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_EMERG, r->connection->log, ngx_errno, + ngx_file_info_n " \"%s\" failed", + database->mmdb.filename); + + continue; + } + + if (ngx_file_mtime(&fi) <= database->last_change) { + continue; + } + + /* do the reload */ + + ngx_memzero(&tmpdb, sizeof(MMDB_s)); + status = MMDB_open(database->mmdb.filename, MMDB_MODE_MMAP, &tmpdb); + + if (status != MMDB_SUCCESS) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "MMDB_open(\"%s\") failed to reload - %s", + database->mmdb.filename, MMDB_strerror(status)); + + continue; + } + + database->last_change = ngx_file_mtime(&fi); + MMDB_close(&database->mmdb); + database->mmdb = tmpdb; + + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "Reload MMDB \"%s\"", + database->mmdb.filename); + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_geoip2_init(ngx_conf_t *cf) +{ + ngx_http_handler_pt *h; + ngx_http_core_main_conf_t *cmcf; + + cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); + + h = ngx_array_push(&cmcf->phases[NGX_HTTP_LOG_PHASE].handlers); + if (h == NULL) { + return NGX_ERROR; + } + + *h = ngx_http_geoip2_log_handler; + + return NGX_OK; +} diff --git a/debian/modules/http-geoip2/ngx_stream_geoip2_module.c b/debian/modules/http-geoip2/ngx_stream_geoip2_module.c new file mode 100644 index 0000000..eb59082 --- /dev/null +++ b/debian/modules/http-geoip2/ngx_stream_geoip2_module.c @@ -0,0 +1,694 @@ +/* + * Copyright (C) Lee Valentine + * Copyright (C) Andrei Belov + * + * Based on nginx's 'ngx_stream_geoip_module.c' by Igor Sysoev + */ + + +#include +#include +#include + +#include + + +typedef struct { + MMDB_s mmdb; + MMDB_lookup_result_s result; + time_t last_check; + time_t last_change; + time_t check_interval; +#if (NGX_HAVE_INET6) + uint8_t address[16]; +#else + unsigned long address; +#endif + ngx_queue_t queue; +} ngx_stream_geoip2_db_t; + +typedef struct { + ngx_queue_t databases; +} ngx_stream_geoip2_conf_t; + +typedef struct { + ngx_stream_geoip2_db_t *database; + const char **lookup; + ngx_str_t default_value; + ngx_stream_complex_value_t source; +} ngx_stream_geoip2_ctx_t; + +typedef struct { + ngx_stream_geoip2_db_t *database; + ngx_str_t metavalue; +} ngx_stream_geoip2_metadata_t; + + +static ngx_int_t ngx_stream_geoip2_variable(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_stream_geoip2_metadata(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data); +static void *ngx_stream_geoip2_create_conf(ngx_conf_t *cf); +static char *ngx_stream_geoip2(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static char *ngx_stream_geoip2_parse_config(ngx_conf_t *cf, ngx_command_t *dummy, + void *conf); +static char *ngx_stream_geoip2(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static char *ngx_stream_geoip2_add_variable(ngx_conf_t *cf, ngx_command_t *dummy, + void *conf); +static char *ngx_stream_geoip2_add_variable_geodata(ngx_conf_t *cf, + ngx_stream_geoip2_db_t *database); +static char *ngx_stream_geoip2_add_variable_metadata(ngx_conf_t *cf, + ngx_stream_geoip2_db_t *database); +static void ngx_stream_geoip2_cleanup(void *data); +static ngx_int_t ngx_stream_geoip2_init(ngx_conf_t *cf); + + +#define FORMAT(fmt, ...) do { \ + p = ngx_palloc(s->connection->pool, NGX_OFF_T_LEN); \ + if (p == NULL) { \ + return NGX_ERROR; \ + } \ + v->len = ngx_sprintf(p, fmt, __VA_ARGS__) - p; \ + v->data = p; \ +} while (0) + +static ngx_command_t ngx_stream_geoip2_commands[] = { + + { ngx_string("geoip2"), + NGX_STREAM_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_TAKE1, + ngx_stream_geoip2, + NGX_STREAM_MAIN_CONF_OFFSET, + 0, + NULL }, + + ngx_null_command +}; + + +static ngx_stream_module_t ngx_stream_geoip2_module_ctx = { + NULL, /* preconfiguration */ + ngx_stream_geoip2_init, /* postconfiguration */ + + ngx_stream_geoip2_create_conf, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL /* merge server configuration */ +}; + + +ngx_module_t ngx_stream_geoip2_module = { + NGX_MODULE_V1, + &ngx_stream_geoip2_module_ctx, /* module context */ + ngx_stream_geoip2_commands, /* module directives */ + NGX_STREAM_MODULE, /* module type */ + NULL, /* init master */ + NULL, /* init module */ + NULL, /* init process */ + NULL, /* init thread */ + NULL, /* exit thread */ + NULL, /* exit process */ + NULL, /* exit master */ + NGX_MODULE_V1_PADDING +}; + + +static ngx_int_t +ngx_stream_geoip2_variable(ngx_stream_session_t *s, ngx_stream_variable_value_t *v, + uintptr_t data) +{ + int mmdb_error; + u_char *p; + ngx_str_t val; + ngx_addr_t addr; + MMDB_entry_data_s entry_data; + ngx_stream_geoip2_ctx_t *geoip2 = (ngx_stream_geoip2_ctx_t *) data; + ngx_stream_geoip2_db_t *database = geoip2->database; + +#if (NGX_HAVE_INET6) + uint8_t address[16], *addressp = address; +#else + unsigned long address; +#endif + + if (geoip2->source.value.len > 0) { + if (ngx_stream_complex_value(s, &geoip2->source, &val) != NGX_OK) { + goto not_found; + } + + if (ngx_parse_addr(s->connection->pool, &addr, val.data, val.len) != NGX_OK) { + goto not_found; + } + } else { + addr.sockaddr = s->connection->sockaddr; + addr.socklen = s->connection->socklen; + } + + switch (addr.sockaddr->sa_family) { + case AF_INET: +#if (NGX_HAVE_INET6) + ngx_memset(addressp, 0, 12); + ngx_memcpy(addressp + 12, &((struct sockaddr_in *) + addr.sockaddr)->sin_addr.s_addr, 4); + break; + + case AF_INET6: + ngx_memcpy(addressp, &((struct sockaddr_in6 *) + addr.sockaddr)->sin6_addr.s6_addr, 16); +#else + address = ((struct sockaddr_in *)addr.sockaddr)->sin_addr.s_addr; +#endif + break; + + default: + goto not_found; + } + +#if (NGX_HAVE_INET6) + if (ngx_memcmp(&address, &database->address, sizeof(address)) != 0) { +#else + if (address != database->address) { +#endif + memcpy(&database->address, &address, sizeof(address)); + database->result = MMDB_lookup_sockaddr(&database->mmdb, + addr.sockaddr, &mmdb_error); + + if (mmdb_error != MMDB_SUCCESS) { + goto not_found; + } + } + + if (!database->result.found_entry + || MMDB_aget_value(&database->result.entry, &entry_data, geoip2->lookup) + != MMDB_SUCCESS) + { + goto not_found; + } + + if (!entry_data.has_data) { + goto not_found; + } + + switch (entry_data.type) { + case MMDB_DATA_TYPE_BOOLEAN: + FORMAT("%d", entry_data.boolean); + break; + case MMDB_DATA_TYPE_UTF8_STRING: + v->len = entry_data.data_size; + v->data = ngx_pnalloc(s->connection->pool, v->len); + if (v->data == NULL) { + return NGX_ERROR; + } + ngx_memcpy(v->data, (u_char *) entry_data.utf8_string, v->len); + break; + case MMDB_DATA_TYPE_BYTES: + v->len = entry_data.data_size; + v->data = ngx_pnalloc(s->connection->pool, v->len); + if (v->data == NULL) { + return NGX_ERROR; + } + ngx_memcpy(v->data, (u_char *) entry_data.bytes, v->len); + break; + case MMDB_DATA_TYPE_FLOAT: + FORMAT("%.5f", entry_data.float_value); + break; + case MMDB_DATA_TYPE_DOUBLE: + FORMAT("%.5f", entry_data.double_value); + break; + case MMDB_DATA_TYPE_UINT16: + FORMAT("%uD", entry_data.uint16); + break; + case MMDB_DATA_TYPE_UINT32: + FORMAT("%uD", entry_data.uint32); + break; + case MMDB_DATA_TYPE_INT32: + FORMAT("%D", entry_data.int32); + break; + case MMDB_DATA_TYPE_UINT64: + FORMAT("%uL", entry_data.uint64); + break; + case MMDB_DATA_TYPE_UINT128: ; +#if MMDB_UINT128_IS_BYTE_ARRAY + uint8_t *val = (uint8_t *) entry_data.uint128; + FORMAT("0x%02x%02x%02x%02x%02x%02x%02x%02x" + "%02x%02x%02x%02x%02x%02x%02x%02x", + val[0], val[1], val[2], val[3], + val[4], val[5], val[6], val[7], + val[8], val[9], val[10], val[11], + val[12], val[13], val[14], val[15]); +#else + mmdb_uint128_t val = entry_data.uint128; + FORMAT("0x%016uxL%016uxL", + (uint64_t) (val >> 64), (uint64_t) val); +#endif + break; + default: + goto not_found; + } + + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + + return NGX_OK; + +not_found: + if (geoip2->default_value.len > 0) { + v->data = geoip2->default_value.data; + v->len = geoip2->default_value.len; + + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + + return NGX_OK; + } + + v->not_found = 1; + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_geoip2_metadata(ngx_stream_session_t *s, ngx_stream_variable_value_t *v, + uintptr_t data) +{ + ngx_stream_geoip2_metadata_t *metadata = (ngx_stream_geoip2_metadata_t *) data; + ngx_stream_geoip2_db_t *database = metadata->database; + u_char *p; + + if (ngx_strncmp(metadata->metavalue.data, "build_epoch", 11) == 0) { + FORMAT("%uL", database->mmdb.metadata.build_epoch); + } else if (ngx_strncmp(metadata->metavalue.data, "last_check", 10) == 0) { + FORMAT("%T", database->last_check); + } else if (ngx_strncmp(metadata->metavalue.data, "last_change", 11) == 0) { + FORMAT("%T", database->last_change); + } else { + v->not_found = 1; + return NGX_OK; + } + + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + + return NGX_OK; +} + + +static void * +ngx_stream_geoip2_create_conf(ngx_conf_t *cf) +{ + ngx_pool_cleanup_t *cln; + ngx_stream_geoip2_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_stream_geoip2_conf_t)); + if (conf == NULL) { + return NULL; + } + + cln = ngx_pool_cleanup_add(cf->pool, 0); + if (cln == NULL) { + return NULL; + } + + ngx_queue_init(&conf->databases); + + cln->handler = ngx_stream_geoip2_cleanup; + cln->data = conf; + + return conf; +} + + +static char * +ngx_stream_geoip2(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + int status; + char *rv; + ngx_str_t *value; + ngx_conf_t save; + ngx_stream_geoip2_db_t *database; + ngx_stream_geoip2_conf_t *gcf = conf; + ngx_queue_t *q; + + value = cf->args->elts; + + if (value[1].data && value[1].data[0] != '/') { + if (ngx_conf_full_name(cf->cycle, &value[1], 0) != NGX_OK) { + return NGX_CONF_ERROR; + } + } + + if (!ngx_queue_empty(&gcf->databases)) { + for (q = ngx_queue_head(&gcf->databases); + q != ngx_queue_sentinel(&gcf->databases); + q = ngx_queue_next(q)) + { + database = ngx_queue_data(q, ngx_stream_geoip2_db_t, queue); + if (ngx_strcmp(value[1].data, database->mmdb.filename) == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "Duplicate GeoIP2 mmdb - %V", &value[1]); + return NGX_CONF_ERROR; + } + } + } + + database = ngx_pcalloc(cf->pool, sizeof(ngx_stream_geoip2_db_t)); + if (database == NULL) { + return NGX_CONF_ERROR; + } + + ngx_queue_insert_tail(&gcf->databases, &database->queue); + database->last_check = database->last_change = ngx_time(); + + status = MMDB_open((char *) value[1].data, MMDB_MODE_MMAP, &database->mmdb); + + if (status != MMDB_SUCCESS) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "MMDB_open(\"%V\") failed - %s", &value[1], + MMDB_strerror(status)); + return NGX_CONF_ERROR; + } + + save = *cf; + cf->handler = ngx_stream_geoip2_parse_config; + cf->handler_conf = (void *) database; + + rv = ngx_conf_parse(cf, NULL); + *cf = save; + return rv; +} + + +static char * +ngx_stream_geoip2_parse_config(ngx_conf_t *cf, ngx_command_t *dummy, void *conf) +{ + ngx_stream_geoip2_db_t *database; + ngx_str_t *value; + time_t interval; + + value = cf->args->elts; + + if (value[0].data[0] == '$') { + return ngx_stream_geoip2_add_variable(cf, dummy, conf); + } + + if (value[0].len == 11 + && ngx_strncmp(value[0].data, "auto_reload", 11) == 0) { + if ((int) cf->args->nelts != 2) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid number of arguments for auto_reload"); + return NGX_CONF_ERROR; + } + + interval = ngx_parse_time(&value[1], true); + + if (interval == (time_t) NGX_ERROR) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid interval for auto_reload \"%V\"", + value[1]); + return NGX_CONF_ERROR; + } + + + database = (ngx_stream_geoip2_db_t *) conf; + database->check_interval = interval; + return NGX_CONF_OK; + } + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid setting \"%V\"", &value[0]); + return NGX_CONF_ERROR; +} + + +static char * +ngx_stream_geoip2_add_variable(ngx_conf_t *cf, ngx_command_t *dummy, void *conf) +{ + ngx_stream_geoip2_db_t *database; + ngx_str_t *value; + int nelts; + + value = cf->args->elts; + + if (value[0].data[0] != '$') { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid variable name \"%V\"", &value[0]); + return NGX_CONF_ERROR; + } + + value[0].len--; + value[0].data++; + + nelts = (int) cf->args->nelts; + database = (ngx_stream_geoip2_db_t *) conf; + + if (nelts > 0 && value[1].len == 8 && ngx_strncmp(value[1].data, "metadata", 8) == 0) { + return ngx_stream_geoip2_add_variable_metadata(cf, database); + } + + return ngx_stream_geoip2_add_variable_geodata(cf, database); +} + + +static char * +ngx_stream_geoip2_add_variable_metadata(ngx_conf_t *cf, ngx_stream_geoip2_db_t *database) +{ + ngx_stream_geoip2_metadata_t *metadata; + ngx_str_t *value, name; + ngx_stream_variable_t *var; + + metadata = ngx_pcalloc(cf->pool, sizeof(ngx_stream_geoip2_metadata_t)); + if (metadata == NULL) { + return NGX_CONF_ERROR; + } + + value = cf->args->elts; + name = value[0]; + + metadata->database = database; + metadata->metavalue = value[2]; + + var = ngx_stream_add_variable(cf, &name, NGX_STREAM_VAR_CHANGEABLE); + if (var == NULL) { + return NGX_CONF_ERROR; + } + + var->get_handler = ngx_stream_geoip2_metadata; + var->data = (uintptr_t) metadata; + + return NGX_CONF_OK; +} + + +static char * +ngx_stream_geoip2_add_variable_geodata(ngx_conf_t *cf, ngx_stream_geoip2_db_t *database) +{ + ngx_stream_geoip2_ctx_t *geoip2; + ngx_stream_compile_complex_value_t ccv; + ngx_str_t *value, name, source; + ngx_stream_variable_t *var; + int i, nelts, idx; + + geoip2 = ngx_pcalloc(cf->pool, sizeof(ngx_stream_geoip2_ctx_t)); + if (geoip2 == NULL) { + return NGX_CONF_ERROR; + } + + geoip2->database = database; + ngx_str_null(&source); + + value = cf->args->elts; + name = value[0]; + + nelts = (int) cf->args->nelts; + idx = 1; + + if (nelts > idx) { + for (i = idx; i < nelts; i++) { + if (ngx_strnstr(value[idx].data, "=", value[idx].len) == NULL) { + break; + } + + if (value[idx].len > 8 && ngx_strncmp(value[idx].data, "default=", 8) == 0) { + if (geoip2->default_value.len > 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "default has already been declared for \"$%V\"", &name); + return NGX_CONF_ERROR; + } + + geoip2->default_value.len = value[idx].len - 8; + geoip2->default_value.data = value[idx].data + 8; + + } else if (value[idx].len > 7 && ngx_strncmp(value[idx].data, "source=", 7) == 0) { + if (source.len > 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "source has already been declared for \"$%V\"", &name); + return NGX_CONF_ERROR; + } + + source.len = value[idx].len - 7; + source.data = value[idx].data + 7; + + if (source.data[0] != '$') { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid source variable name \"%V\"", &source); + return NGX_CONF_ERROR; + } + + ngx_memzero(&ccv, sizeof(ngx_stream_compile_complex_value_t)); + ccv.cf = cf; + ccv.value = &source; + ccv.complex_value = &geoip2->source; + + if (ngx_stream_compile_complex_value(&ccv) != NGX_OK) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "unable to compile \"%V\" for \"$%V\"", &source, &name); + return NGX_CONF_ERROR; + } + + } else { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid setting \"%V\" for \"$%V\"", &value[idx], &name); + return NGX_CONF_ERROR; + } + + idx++; + } + } + + var = ngx_stream_add_variable(cf, &name, NGX_STREAM_VAR_CHANGEABLE); + if (var == NULL) { + return NGX_CONF_ERROR; + } + + geoip2->lookup = ngx_pcalloc(cf->pool, + sizeof(const char *) * (cf->args->nelts - (idx - 1))); + + if (geoip2->lookup == NULL) { + return NGX_CONF_ERROR; + } + + for (i = idx; i < nelts; i++) { + geoip2->lookup[i - idx] = (char *) value[i].data; + } + geoip2->lookup[i - idx] = NULL; + + var->get_handler = ngx_stream_geoip2_variable; + var->data = (uintptr_t) geoip2; + + return NGX_CONF_OK; +} + + +static void +ngx_stream_geoip2_cleanup(void *data) +{ + ngx_queue_t *q; + ngx_stream_geoip2_db_t *database; + ngx_stream_geoip2_conf_t *gcf = data; + + while (!ngx_queue_empty(&gcf->databases)) { + q = ngx_queue_head(&gcf->databases); + ngx_queue_remove(q); + database = ngx_queue_data(q, ngx_stream_geoip2_db_t, queue); + MMDB_close(&database->mmdb); + } +} + + +static ngx_int_t +ngx_stream_geoip2_log_handler(ngx_stream_session_t *s) +{ + int status; + MMDB_s tmpdb; + ngx_queue_t *q; + ngx_file_info_t fi; + ngx_stream_geoip2_db_t *database; + ngx_stream_geoip2_conf_t *gcf; + + ngx_log_debug0(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, + "geoip2 stream log handler"); + + gcf = ngx_stream_get_module_main_conf(s, ngx_stream_geoip2_module); + + if (ngx_queue_empty(&gcf->databases)) { + return NGX_OK; + } + + for (q = ngx_queue_head(&gcf->databases); + q != ngx_queue_sentinel(&gcf->databases); + q = ngx_queue_next(q)) + { + database = ngx_queue_data(q, ngx_stream_geoip2_db_t, queue); + if (database->check_interval == 0) { + continue; + } + + if ((database->last_check + database->check_interval) + > ngx_time()) + { + continue; + } + + database->last_check = ngx_time(); + + if (ngx_file_info(database->mmdb.filename, &fi) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_EMERG, s->connection->log, ngx_errno, + ngx_file_info_n " \"%s\" failed", + database->mmdb.filename); + + continue; + } + + if (ngx_file_mtime(&fi) <= database->last_change) { + continue; + } + + /* do the reload */ + + ngx_memzero(&tmpdb, sizeof(MMDB_s)); + status = MMDB_open(database->mmdb.filename, MMDB_MODE_MMAP, &tmpdb); + + if (status != MMDB_SUCCESS) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "MMDB_open(\"%s\") failed to reload - %s", + database->mmdb.filename, MMDB_strerror(status)); + + continue; + } + + database->last_change = ngx_file_mtime(&fi); + MMDB_close(&database->mmdb); + database->mmdb = tmpdb; + + ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, + "Reload MMDB \"%s\"", + database->mmdb.filename); + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_geoip2_init(ngx_conf_t *cf) +{ + ngx_stream_handler_pt *h; + ngx_stream_core_main_conf_t *cmcf; + + cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module); + + h = ngx_array_push(&cmcf->phases[NGX_STREAM_LOG_PHASE].handlers); + if (h == NULL) { + return NGX_ERROR; + } + + *h = ngx_stream_geoip2_log_handler; + + return NGX_OK; +} diff --git a/debian/modules/watch/http-geoip2 b/debian/modules/watch/http-geoip2 new file mode 100644 index 0000000..da23145 --- /dev/null +++ b/debian/modules/watch/http-geoip2 @@ -0,0 +1,4 @@ +version=4 +opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%libnginx-mod-http-geoip2-$1.tar.gz%" \ + https://github.com/leev/ngx_http_geoip2_module/tags \ + (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/ngxmod uupdate http-geoip2 diff --git a/debian/rules b/debian/rules index bf4b9f3..bc9a234 100755 --- a/debian/rules +++ b/debian/rules @@ -13,6 +13,7 @@ DYN_MODS := \ http-echo \ http-fancyindex \ http-geoip \ + http-geoip2 \ http-headers-more-filter \ http-image-filter \ http-lua \ @@ -131,6 +132,7 @@ extras_configure_flags := \ --add-dynamic-module=$(MODULESDIR)/http-ndk \ --add-dynamic-module=$(MODULESDIR)/http-echo \ --add-dynamic-module=$(MODULESDIR)/http-fancyindex \ + --add-dynamic-module=$(MODULESDIR)/http-geoip2 \ --add-dynamic-module=$(MODULESDIR)/nchan \ --add-dynamic-module=$(MODULESDIR)/http-lua \ --add-dynamic-module=$(MODULESDIR)/rtmp \ diff --git a/debian/tests/control b/debian/tests/control index b491482..45f26e5 100644 --- a/debian/tests/control +++ b/debian/tests/control @@ -28,6 +28,7 @@ Depends: nginx-full, libnginx-mod-http-echo, libnginx-mod-http-fancyindex, libnginx-mod-http-geoip, + libnginx-mod-http-geoip2, libnginx-mod-http-headers-more-filter, libnginx-mod-http-image-filter, libnginx-mod-http-lua, @@ -51,6 +52,7 @@ Depends: nginx-light, libnginx-mod-http-echo, libnginx-mod-http-fancyindex, libnginx-mod-http-geoip, + libnginx-mod-http-geoip2, libnginx-mod-http-headers-more-filter, libnginx-mod-http-image-filter, libnginx-mod-http-lua, @@ -74,6 +76,7 @@ Depends: nginx-extras, libnginx-mod-http-echo, libnginx-mod-http-fancyindex, libnginx-mod-http-geoip, + libnginx-mod-http-geoip2, libnginx-mod-http-headers-more-filter, libnginx-mod-http-image-filter, libnginx-mod-http-lua, From e3540f5188a2983e7c0f41c40cd3c567bbe6185f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Nov=C3=BD?= Date: Thu, 4 Jun 2020 10:58:53 +0200 Subject: [PATCH 042/329] d/copyright: Update for release --- debian/copyright | 98 +++++++++++++++++++++++++++++++----------------- 1 file changed, 64 insertions(+), 34 deletions(-) diff --git a/debian/copyright b/debian/copyright index 3fb1c3f..82b44ee 100644 --- a/debian/copyright +++ b/debian/copyright @@ -3,12 +3,12 @@ Upstream-Name: nginx Source: https://nginx.org/en/download.html Files: * -Copyright: 2002-2014 Igor Sysoev - 2011-2014 Nginx, Inc. - Maxim Dounin - Valentin V. Bartenev - Roman Arutyunyan - Ruslan Ermilov +Copyright: 2002-2019, Igor Sysoev + 2011-2019, Nginx, Inc. + Maxim Dounin + Valentin V. Bartenev + Roman Arutyunyan + Ruslan Ermilov License: BSD-2-clause Files: src/core/ngx_murmurhash.c @@ -17,10 +17,16 @@ License: BSD-2-clause Files: src/http/modules/ngx_http_scgi_module.c src/http/modules/ngx_http_uwsgi_module.c -Copyright: Copyright (C) Igor Sysoev - Copyright (C) Nginx, Inc. - 2009-2010 Unbit S.a.s. - 2008 Manlio Perillo (manlio.perillo@gmail.com) +Copyright: 2009-2010, Unbit S.a.s. + 2008, Manlio Perillo (manlio.perillo@gmail.com) + Igor Sysoev + Nginx, Inc. +License: BSD-2-clause + +Files: nginx/src/http/v2/ngx_http_v2_huff_encode.c +Copyright: 2015, Vlad Krasnov + Nginx, Inc. + Valentin V. Bartenev License: BSD-2-clause Files: contrib/geo2nginx.pl @@ -39,74 +45,98 @@ Copyright: 2007-2009, Fabio Tranchitella License: BSD-2-clause Files: debian/modules/http-headers-more-filter/* -Copyright: Copyright (c) 2009-2014, Yichun "agentzh" Zhang (章亦春) , CloudFlare Inc. - Copyright (c) 2010-2013, Bernd Dorn - Copyright (c) Igor Sysoev +Copyright: 2009-2017, Yichun "agentzh" Zhang (章亦春) , CloudFlare Inc. + 2010-2013, Bernd Dorn + Igor Sysoev License: BSD-2-clause Files: debian/modules/http-geoip2/* -Copyright: Copyright (c) 2014, Lee Valentine +Copyright: 2014, Lee Valentine License: BSD-2-clause Files: debian/modules/http-ndk/* -Copyright: Marcus Clyne +Copyright: 2010-2018, Marcus Clyne License: BSD-3-clause Files: debian/modules/http-ndk/src/hash/md5.h debian/modules/http-ndk/src/hash/sha.h -Copyright: Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) +Copyright: 1995-1998, Eric Young License: BSD-4-clause +Files: debian/modules/http-ndk/src/hash/murmurhash2.c +Copyright: Austin Appleby +License: BSD-3-clause + Files: debian/modules/http-auth-pam/* -Copyright: 2008-2013, Sergio Talens Oliag +Copyright: 2008-2016, Sergio Talens Oliag License: BSD-2-clause Files: debian/modules/http-echo/* -Copyright: Copyright (c) 2009-2014, Yichun "agentzh" Zhang +Copyright: 2009-2014, Yichun "agentzh" Zhang License: BSD-2-clause Files: debian/modules/http-lua/* -Copyright: Copyright (C) 2009-2014, by Xiaozhe Wang (chaoslawful) . - Copyright (C) 2009-2014, by Yichun "agentzh" Zhang (章亦春) , CloudFlare Inc. +Copyright: 2009-2017, by Xiaozhe Wang (chaoslawful) . + 2009-2018, by Yichun "agentzh" Zhang (章亦春) , OpenResty Inc. License: BSD-2-clause +Files: debian/modules/http-lua/t/lib/CRC32.lua +Copyright: 2007-2008, Neil Richardson (nrich@iinet.net.au) +License: Expat + Files: debian/modules/http-upstream-fair/* -Copyright: Copyright (c) 2007 Grzegorz Nosek - Igor Sysoev +Copyright: 2007, Grzegorz Nosek + Igor Sysoev License: BSD-2-clause Files: debian/modules/nchan/* -Copyright: 2009-2016 Leo Ponomarev -License: MIT +Copyright: 2009-2016, Leo Ponomarev (slact) + 2014, Wandenberg Peixoto + Alexander Lyalin + Rogério Carvalho Schneider +License: Expat + +Files: debian/modules/nchan/src/store/redis/hiredis/* +Copyright: 2006-2014, Salvatore Sanfilippo + 2010-2011, Pieter Noordhuis + 2015, Matt Stancliff + Jan-Erik Rediger +License: BSD-3-clause Files: debian/modules/nchan/src/store/redis/cmp.* -Copyright: 2015 Charles Gunyon -License: MIT +Copyright: 2017, Charles Gunyon +License: Expat Files: debian/modules/http-uploadprogress/* -Copyright: Brice Figureau +Copyright: 2007, Brice Figureau 2002-2007, Igor Sysoev License: BSD-2-clause Files: debian/modules/http-cache-purge/* -Copyright: 2009-2012, FRiCKLE , - 2009-2012, Piotr Sikora +Copyright: 2009-2014, FRiCKLE , + 2009-2014, Piotr Sikora License: BSD-2-clause Files: debian/modules/http-dav-ext/* -Copyright: Arutyunyan Roman +Copyright: 2012-2018, Roman Arutyunyan License: BSD-2-clause Files: debian/modules/http-fancyindex/* -Copyright: Copyright (c) Adrian Perez +Copyright: 2007-2016, Adrian Perez License: BSD-2-clause Files: debian/modules/http-subs-filter/* -Copyright: Copyright (C) 2014 by Weibin Yao +Copyright: 2014, Weibin Yao License: BSD-2-clause +Files: debian/modules/http-subs-filter/test/* +Copyright: 2009-2011, Taobao Inc., Alibaba Group + Antoine BONAVITA "" + agentzh (章亦春) "" +License: BSD-3-clause + Files: debian/modules/rtmp/* -Copyright: Copyright (C) 2012-2014, Roman Arutyunyan +Copyright: 2012-2014, Roman Arutyunyan License: BSD-2-clause License: BSD-2-clause @@ -186,7 +216,7 @@ License: BSD-4-clause OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -License: MIT +License: Expat Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the From 1459087c8f82f6b0855d61844bec493224a6e2e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Nov=C3=BD?= Date: Thu, 4 Jun 2020 11:36:23 +0200 Subject: [PATCH 043/329] d/conf/nginx.conf: Remove tcp_nodelay on, which is same as default --- debian/conf/nginx.conf | 1 - 1 file changed, 1 deletion(-) diff --git a/debian/conf/nginx.conf b/debian/conf/nginx.conf index 9ee6e06..d8f88b0 100644 --- a/debian/conf/nginx.conf +++ b/debian/conf/nginx.conf @@ -16,7 +16,6 @@ http { sendfile on; tcp_nopush on; - tcp_nodelay on; keepalive_timeout 65; types_hash_max_size 2048; # server_tokens off; From 9fbad86c59ba7ae68d211f929527ac2a7a435c86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Nov=C3=BD?= Date: Thu, 4 Jun 2020 11:37:11 +0200 Subject: [PATCH 044/329] d/conf/nginx.conf: Remove keepalive_timeout 65 and use default value 75s. --- debian/conf/nginx.conf | 1 - 1 file changed, 1 deletion(-) diff --git a/debian/conf/nginx.conf b/debian/conf/nginx.conf index d8f88b0..162bc7f 100644 --- a/debian/conf/nginx.conf +++ b/debian/conf/nginx.conf @@ -16,7 +16,6 @@ http { sendfile on; tcp_nopush on; - keepalive_timeout 65; types_hash_max_size 2048; # server_tokens off; From 478b7377229e954941026db88334925d7c1a25f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Nov=C3=BD?= Date: Thu, 4 Jun 2020 11:37:49 +0200 Subject: [PATCH 045/329] d/conf/nginx.conf: Remove trailing whitespaces --- debian/conf/nginx.conf | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/debian/conf/nginx.conf b/debian/conf/nginx.conf index 162bc7f..136753e 100644 --- a/debian/conf/nginx.conf +++ b/debian/conf/nginx.conf @@ -64,17 +64,17 @@ http { #mail { # # See sample authentication script at: # # http://wiki.nginx.org/ImapAuthenticateWithApachePhpScript -# +# # # auth_http localhost/auth.php; # # pop3_capabilities "TOP" "USER"; # # imap_capabilities "IMAP4rev1" "UIDPLUS"; -# +# # server { # listen localhost:110; # protocol pop3; # proxy on; # } -# +# # server { # listen localhost:143; # protocol imap; From 3edca8428c0fd3b4a470da1b60ea48be63a66dbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Nov=C3=BD?= Date: Thu, 4 Jun 2020 20:23:32 +0200 Subject: [PATCH 046/329] Build dynamic modules only in extras flavour --- debian/rules | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/debian/rules b/debian/rules index bc9a234..45a337a 100755 --- a/debian/rules +++ b/debian/rules @@ -83,28 +83,14 @@ light_configure_flags := \ --without-http_memcached_module \ --without-http_referer_module \ --without-http_split_clients_module \ - --without-http_userid_module \ - --add-dynamic-module=$(MODULESDIR)/http-echo + --without-http_userid_module full_configure_flags := \ $(common_configure_flags) \ --with-http_addition_module \ - --with-http_geoip_module=dynamic \ --with-http_gunzip_module \ --with-http_gzip_static_module \ - --with-http_image_filter_module=dynamic \ --with-http_sub_module \ - --with-http_xslt_module=dynamic \ - --with-stream=dynamic \ - --with-stream_ssl_module \ - --with-stream_ssl_preread_module \ - --with-mail=dynamic \ - --with-mail_ssl_module \ - --add-dynamic-module=$(MODULESDIR)/http-auth-pam \ - --add-dynamic-module=$(MODULESDIR)/http-dav-ext \ - --add-dynamic-module=$(MODULESDIR)/http-echo \ - --add-dynamic-module=$(MODULESDIR)/http-upstream-fair \ - --add-dynamic-module=$(MODULESDIR)/http-subs-filter extras_configure_flags := \ $(common_configure_flags) \ From a2ddfe2d0e30516f984cf2dfc51f817397d55bd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Nov=C3=BD?= Date: Thu, 4 Jun 2020 20:35:46 +0200 Subject: [PATCH 047/329] d/ngx-conf: Convert to Python 3 --- debian/ngx-conf/ngx-conf | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/debian/ngx-conf/ngx-conf b/debian/ngx-conf/ngx-conf index de24fcc..658766a 100755 --- a/debian/ngx-conf/ngx-conf +++ b/debian/ngx-conf/ngx-conf @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 ## # copyright (c) 2015 Michael Lustfield @@ -37,7 +37,7 @@ import subprocess # Read configuration values -config_opts = ConfigParser.SafeConfigParser({ +config_opts = ConfigParser.ConfigParser({ 'base_dir': '/etc/nginx/', 'conf_dir': 'conf.d/', 'sites_en': 'sites-enabled/', @@ -211,7 +211,7 @@ def remove_configs(configs, verbose, force): for f in files: if os.path.isfile(f): if not force: - answer = str(raw_input('Are you sure you want to delete {}? (y/N) '.format(f))) + answer = str(input('Are you sure you want to delete {}? (y/N) '.format(f))) if answer.lower() != 'y' and answer.lower() != 'yes': break try: From a681a84cf0ecc555ae27ffe57e41828e7c066812 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Nov=C3=BD?= Date: Thu, 4 Jun 2020 20:43:40 +0200 Subject: [PATCH 048/329] d/control: Add GeoIP2 into description --- debian/control | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/debian/control b/debian/control index b3ec941..f28ce4b 100644 --- a/debian/control +++ b/debian/control @@ -106,8 +106,8 @@ Description: nginx web/proxy server (standard version) . MAIL MODULES: Mail Core, Auth HTTP, Proxy, SSL, IMAP, POP3, SMTP. . - THIRD PARTY MODULES: Auth PAM, DAV Ext, Echo, HTTP Substitutions, Upstream - Fair Queue. + THIRD PARTY MODULES: Auth PAM, DAV Ext, Echo, GeoIP2, HTTP Substitutions + Upstream Fair Queue. Package: nginx-light Architecture: any @@ -185,7 +185,7 @@ Description: nginx web/proxy server (extended version) MAIL MODULES: Mail Core, Auth HTTP, Proxy, SSL, IMAP, POP3, SMTP. . THIRD PARTY MODULES: Auth PAM, Cache Purge, DAV Ext, Echo, Fancy Index, - Headers More, Embedded Lua, HTTP Substitutions, Nchan, Upload Progress, + GeoIP2, Headers More, Embedded Lua, HTTP Substitutions, Nchan, Upload Progress, Upstream Fair Queue. Package: libnginx-mod-http-geoip From b39ced7d98a32c4eda52d7fad5a4b2e481d14c94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Nov=C3=BD?= Date: Thu, 4 Jun 2020 22:23:09 +0200 Subject: [PATCH 049/329] d/copyright: Fix wrong filename --- debian/copyright | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/copyright b/debian/copyright index 82b44ee..6177c46 100644 --- a/debian/copyright +++ b/debian/copyright @@ -23,7 +23,7 @@ Copyright: 2009-2010, Unbit S.a.s. Nginx, Inc. License: BSD-2-clause -Files: nginx/src/http/v2/ngx_http_v2_huff_encode.c +Files: src/http/v2/ngx_http_v2_huff_encode.c Copyright: 2015, Vlad Krasnov Nginx, Inc. Valentin V. Bartenev From 6982ab38dda9a1904b4fa01cd68552a5c3301f9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Nov=C3=BD?= Date: Thu, 4 Jun 2020 22:32:04 +0200 Subject: [PATCH 050/329] Introduce nginx-core and make it new default for "nginx" Version of nginx identical to that of nginx-full, but without any third-party modules, and only modules in the original nginx code base. --- debian/control | 65 ++++++++++++++----- debian/{nginx-full.dirs => nginx-core.dirs} | 0 debian/nginx-core.install | 1 + debian/nginx-core.manpages | 1 + ...ginx-full.postinst => nginx-core.postinst} | 0 debian/{nginx-full.prerm => nginx-core.prerm} | 0 ...ginx-full.triggers => nginx-core.triggers} | 0 debian/nginx-full.install | 1 - debian/nginx-full.manpages | 1 - debian/rules | 4 +- debian/tests/control | 28 ++++++++ debian/tests/core-module-deps | 3 + debian/tests/core-simple | 3 + 13 files changed, 86 insertions(+), 21 deletions(-) rename debian/{nginx-full.dirs => nginx-core.dirs} (100%) create mode 100644 debian/nginx-core.install create mode 100644 debian/nginx-core.manpages rename debian/{nginx-full.postinst => nginx-core.postinst} (100%) rename debian/{nginx-full.prerm => nginx-core.prerm} (100%) rename debian/{nginx-full.triggers => nginx-core.triggers} (100%) delete mode 100644 debian/nginx-full.install delete mode 100644 debian/nginx-full.manpages create mode 100644 debian/tests/core-module-deps create mode 100644 debian/tests/core-simple diff --git a/debian/control b/debian/control index f28ce4b..5d4fdde 100644 --- a/debian/control +++ b/debian/control @@ -30,16 +30,16 @@ Rules-Requires-Root: no Package: nginx Architecture: all -Depends: nginx-full (<< ${source:Version}.1~) | nginx-light (<< ${source:Version}.1~) | nginx-extras (<< ${source:Version}.1~), - nginx-full (>= ${source:Version}) | nginx-light (>= ${source:Version}) | nginx-extras (>= ${source:Version}), +Depends: nginx-core (<< ${source:Version}.1~) | nginx-full (<< ${source:Version}.1~) | nginx-light (<< ${source:Version}.1~) | nginx-extras (<< ${source:Version}.1~), + nginx-core (>= ${source:Version}) | nginx-full (>= ${source:Version}) | nginx-light (>= ${source:Version}) | nginx-extras (>= ${source:Version}), ${misc:Depends} Description: small, powerful, scalable web/proxy server Nginx ("engine X") is a high-performance web and reverse proxy server created by Igor Sysoev. It can be used both as a standalone web server and as a proxy to reduce the load on back-end HTTP or mail servers. . - This is a dependency package to install either nginx-full (by default), - nginx-light or nginx-extras. + This is a dependency package to install either nginx-core (by default), + nginx-full, nginx-light or nginx-extras. Package: nginx-doc Architecture: all @@ -66,23 +66,19 @@ Description: small, powerful, scalable web/proxy server - common files This package contains base configuration files used by all versions of nginx. -Package: nginx-full +Package: nginx-core Architecture: any -Depends: libnginx-mod-http-auth-pam (= ${binary:Version}), - libnginx-mod-http-dav-ext (= ${binary:Version}), - libnginx-mod-http-echo (= ${binary:Version}), - libnginx-mod-http-geoip (= ${binary:Version}), - libnginx-mod-http-geoip2 (= ${binary:Version}), +Depends: libnginx-mod-http-geoip (= ${binary:Version}), libnginx-mod-http-image-filter (= ${binary:Version}), - libnginx-mod-http-subs-filter (= ${binary:Version}), - libnginx-mod-http-upstream-fair (= ${binary:Version}), libnginx-mod-http-xslt-filter (= ${binary:Version}), libnginx-mod-mail (= ${binary:Version}), libnginx-mod-stream (= ${binary:Version}), nginx-common (= ${source:Version}), ${misc:Depends}, ${shlibs:Depends} -Breaks: nginx (<< 1.4.5-1) +Breaks: nginx (<< 1.4.5-1), + nginx-full (<< 1.18.0-1), +Replaces: nginx-full (<< 1.18.0-1), Provides: httpd, httpd-cgi, nginx Conflicts: nginx-extras, nginx-light Suggests: nginx-doc (= ${source:Version}) @@ -91,9 +87,44 @@ Description: nginx web/proxy server (standard version) created by Igor Sysoev. It can be used both as a standalone web server and as a proxy to reduce the load on back-end HTTP or mail servers. . - This package provides a version of nginx with the complete set of + This package provides a version of nginx identical to that of nginx-full, + but without any third-party modules, and only modules in the original + nginx code base. + . + STANDARD HTTP MODULES: Core, Access, Auth Basic, Auto Index, Browser, Empty + GIF, FastCGI, Geo, Limit Connections, Limit Requests, Map, Memcached, Proxy, + Referer, Rewrite, SCGI, Split Clients, UWSGI. + . + OPTIONAL HTTP MODULES: Addition, Auth Request, Charset, WebDAV, GeoIP, Gunzip, + Gzip, Gzip Precompression, Headers, HTTP/2, Image Filter, Index, Log, Real IP, + Slice, SSI, SSL, Stream, SSL Preread, Stub Status, Substitution, Thread Pool, + Upstream, User ID, XSLT. + . + MAIL MODULES: Mail Core, Auth HTTP, Proxy, SSL, IMAP, POP3, SMTP. + +Package: nginx-full +Architecture: all +Depends: libnginx-mod-http-auth-pam, + libnginx-mod-http-dav-ext, + libnginx-mod-http-echo, + libnginx-mod-http-geoip2, + libnginx-mod-http-subs-filter, + libnginx-mod-http-upstream-fair, + nginx-core (>= ${source:Version}), + nginx-core (<< ${source:Version}.1~), + ${misc:Depends}, + ${shlibs:Depends} +Breaks: nginx (<< 1.4.5-1) +Provides: httpd, httpd-cgi, nginx +Suggests: nginx-doc (= ${source:Version}) +Description: nginx web/proxy server (standard version with 3rd parties) + Nginx ("engine X") is a high-performance web and reverse proxy server + created by Igor Sysoev. It can be used both as a standalone web server + and as a proxy to reduce the load on back-end HTTP or mail servers. + . + This metapackage provides a version of nginx with the complete set of standard modules included (but omitting some of those included in - nginx-extra). + nginx-extras). . STANDARD HTTP MODULES: Core, Access, Auth Basic, Auto Index, Browser, Empty GIF, FastCGI, Geo, Limit Connections, Limit Requests, Map, Memcached, Proxy, @@ -117,7 +148,7 @@ Depends: libnginx-mod-http-echo (= ${binary:Version}), ${shlibs:Depends} Breaks: nginx (<< 1.4.5-1) Provides: httpd, httpd-cgi, nginx -Conflicts: nginx-extras, nginx-full +Conflicts: nginx-extras, nginx-core Suggests: nginx-doc (= ${source:Version}) Description: nginx web/proxy server (basic version) Nginx ("engine X") is a high-performance web and reverse proxy server @@ -161,7 +192,7 @@ Depends: libnginx-mod-http-auth-pam (= ${binary:Version}), ${shlibs:Depends} Breaks: nginx (<< 1.4.5-1) Provides: httpd, httpd-cgi, nginx -Conflicts: nginx-full, nginx-light +Conflicts: nginx-core, nginx-light Suggests: nginx-doc (= ${source:Version}) Description: nginx web/proxy server (extended version) Nginx ("engine X") is a high-performance web and reverse proxy server diff --git a/debian/nginx-full.dirs b/debian/nginx-core.dirs similarity index 100% rename from debian/nginx-full.dirs rename to debian/nginx-core.dirs diff --git a/debian/nginx-core.install b/debian/nginx-core.install new file mode 100644 index 0000000..a82f702 --- /dev/null +++ b/debian/nginx-core.install @@ -0,0 +1 @@ +debian/build-core/objs/nginx usr/sbin diff --git a/debian/nginx-core.manpages b/debian/nginx-core.manpages new file mode 100644 index 0000000..3b6d0bd --- /dev/null +++ b/debian/nginx-core.manpages @@ -0,0 +1 @@ +debian/build-core/objs/nginx.8 diff --git a/debian/nginx-full.postinst b/debian/nginx-core.postinst similarity index 100% rename from debian/nginx-full.postinst rename to debian/nginx-core.postinst diff --git a/debian/nginx-full.prerm b/debian/nginx-core.prerm similarity index 100% rename from debian/nginx-full.prerm rename to debian/nginx-core.prerm diff --git a/debian/nginx-full.triggers b/debian/nginx-core.triggers similarity index 100% rename from debian/nginx-full.triggers rename to debian/nginx-core.triggers diff --git a/debian/nginx-full.install b/debian/nginx-full.install deleted file mode 100644 index ccd2676..0000000 --- a/debian/nginx-full.install +++ /dev/null @@ -1 +0,0 @@ -debian/build-full/objs/nginx usr/sbin diff --git a/debian/nginx-full.manpages b/debian/nginx-full.manpages deleted file mode 100644 index 28267c2..0000000 --- a/debian/nginx-full.manpages +++ /dev/null @@ -1 +0,0 @@ -debian/build-full/objs/nginx.8 diff --git a/debian/rules b/debian/rules index 45a337a..9fead04 100755 --- a/debian/rules +++ b/debian/rules @@ -5,7 +5,7 @@ export DEB_BUILD_MAINT_OPTIONS=hardening=+all debian_cflags:=$(shell dpkg-buildflags --get CFLAGS) -fPIC $(shell dpkg-buildflags --get CPPFLAGS) debian_ldflags:=$(shell dpkg-buildflags --get LDFLAGS) -fPIC -FLAVOURS := full light extras +FLAVOURS := core light extras DYN_MODS := \ http-auth-pam \ http-cache-purge \ @@ -85,7 +85,7 @@ light_configure_flags := \ --without-http_split_clients_module \ --without-http_userid_module -full_configure_flags := \ +core_configure_flags := \ $(common_configure_flags) \ --with-http_addition_module \ --with-http_gunzip_module \ diff --git a/debian/tests/control b/debian/tests/control index 45f26e5..2ea2832 100644 --- a/debian/tests/control +++ b/debian/tests/control @@ -10,6 +10,10 @@ Tests: lua Restrictions: allow-stderr isolation-container needs-root Depends: nginx-extras, curl +Tests: core-simple +Restrictions: allow-stderr isolation-container +Depends: nginx-core, curl + Tests: full-simple Restrictions: allow-stderr isolation-container Depends: nginx-full, curl @@ -18,6 +22,30 @@ Tests: extras-simple Restrictions: allow-stderr isolation-container Depends: nginx-extras, curl +Tests: core-module-deps +Restrictions: allow-stderr isolation-container +Depends: nginx-core, + curl, + libnginx-mod-http-auth-pam, + libnginx-mod-http-cache-purge, + libnginx-mod-http-dav-ext, + libnginx-mod-http-echo, + libnginx-mod-http-fancyindex, + libnginx-mod-http-geoip, + libnginx-mod-http-geoip2, + libnginx-mod-http-headers-more-filter, + libnginx-mod-http-image-filter, + libnginx-mod-http-lua, + libnginx-mod-http-perl, + libnginx-mod-http-subs-filter, + libnginx-mod-http-uploadprogress, + libnginx-mod-http-upstream-fair, + libnginx-mod-http-xslt-filter, + libnginx-mod-mail, + libnginx-mod-nchan, + libnginx-mod-rtmp, + libnginx-mod-stream + Tests: full-module-deps Restrictions: allow-stderr isolation-container Depends: nginx-full, diff --git a/debian/tests/core-module-deps b/debian/tests/core-module-deps new file mode 100644 index 0000000..cefed50 --- /dev/null +++ b/debian/tests/core-module-deps @@ -0,0 +1,3 @@ +#!/bin/bash + +curl --silent --fail -o /dev/null -w "response_code: %{http_code}\n" http://127.0.0.1/ diff --git a/debian/tests/core-simple b/debian/tests/core-simple new file mode 100644 index 0000000..cefed50 --- /dev/null +++ b/debian/tests/core-simple @@ -0,0 +1,3 @@ +#!/bin/bash + +curl --silent --fail -o /dev/null -w "response_code: %{http_code}\n" http://127.0.0.1/ From 8dfca737efad4030f0b1b54cf71843fe49efc9dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Nov=C3=BD?= Date: Thu, 4 Jun 2020 22:33:47 +0200 Subject: [PATCH 051/329] libnginx-mod-* now depends on nginx- --- debian/control | 60 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 40 insertions(+), 20 deletions(-) diff --git a/debian/control b/debian/control index 5d4fdde..d18e602 100644 --- a/debian/control +++ b/debian/control @@ -221,7 +221,8 @@ Description: nginx web/proxy server (extended version) Package: libnginx-mod-http-geoip Architecture: any -Depends: ${misc:Depends}, ${shlibs:Depends} +Depends: ${misc:Depends}, ${shlibs:Depends}, + nginx-core (= ${binary:Version}) | nginx-full (= ${binary:Version}) | nginx-light (= ${binary:Version}) | nginx-extras (= ${binary:Version}), Description: GeoIP HTTP module for Nginx The ngx_http_geoip module creates variables with values depending on the client IP address, using the precompiled MaxMind databases. @@ -231,7 +232,8 @@ Description: GeoIP HTTP module for Nginx Package: libnginx-mod-http-geoip2 Architecture: any -Depends: ${misc:Depends}, ${shlibs:Depends} +Depends: ${misc:Depends}, ${shlibs:Depends}, + nginx-core (= ${binary:Version}) | nginx-full (= ${binary:Version}) | nginx-light (= ${binary:Version}) | nginx-extras (= ${binary:Version}), Description: GeoIP2 HTTP module for Nginx The ngx_http_geoip2 module creates variables with values depending on the client IP address, using the precompiled MaxMind GeoIP2 databases. @@ -241,7 +243,8 @@ Description: GeoIP2 HTTP module for Nginx Package: libnginx-mod-http-image-filter Architecture: any -Depends: ${misc:Depends}, ${shlibs:Depends} +Depends: ${misc:Depends}, ${shlibs:Depends}, + nginx-core (= ${binary:Version}) | nginx-full (= ${binary:Version}) | nginx-light (= ${binary:Version}) | nginx-extras (= ${binary:Version}), Description: HTTP image filter module for Nginx The ngx_http_image_filter module is a filter that transforms images in JPEG, GIF, and PNG formats. @@ -251,7 +254,8 @@ Description: HTTP image filter module for Nginx Package: libnginx-mod-http-xslt-filter Architecture: any -Depends: ${misc:Depends}, ${shlibs:Depends} +Depends: ${misc:Depends}, ${shlibs:Depends}, + nginx-core (= ${binary:Version}) | nginx-full (= ${binary:Version}) | nginx-light (= ${binary:Version}) | nginx-extras (= ${binary:Version}), Description: XSLT Transformation module for Nginx The ngx_http_xslt_filter module is a filter that transforms XML responses using one or more XSLT stylesheets. @@ -261,7 +265,8 @@ Description: XSLT Transformation module for Nginx Package: libnginx-mod-mail Architecture: any -Depends: ${misc:Depends}, ${shlibs:Depends} +Depends: ${misc:Depends}, ${shlibs:Depends}, + nginx-core (= ${binary:Version}) | nginx-full (= ${binary:Version}) | nginx-light (= ${binary:Version}) | nginx-extras (= ${binary:Version}), Description: Mail module for Nginx The nginx_mail module adds mail proxy support to nginx. . @@ -270,7 +275,8 @@ Description: Mail module for Nginx Package: libnginx-mod-stream Architecture: any -Depends: ${misc:Depends}, ${shlibs:Depends} +Depends: ${misc:Depends}, ${shlibs:Depends}, + nginx-core (= ${binary:Version}) | nginx-full (= ${binary:Version}) | nginx-light (= ${binary:Version}) | nginx-extras (= ${binary:Version}), Description: Stream module for Nginx The nginx_stream module adds stream proxy support to nginx. . @@ -280,7 +286,8 @@ Description: Stream module for Nginx Package: libnginx-mod-http-perl Architecture: any -Depends: ${misc:Depends}, ${perl:Depends}, ${shlibs:Depends} +Depends: ${misc:Depends}, ${perl:Depends}, ${shlibs:Depends}, + nginx-core (= ${binary:Version}) | nginx-full (= ${binary:Version}) | nginx-light (= ${binary:Version}) | nginx-extras (= ${binary:Version}), Replaces: nginx-extras (<< 1.9.14-1) Description: Perl module for Nginx Embed Perl runtime into nginx. @@ -292,7 +299,8 @@ Description: Perl module for Nginx Package: libnginx-mod-http-auth-pam Architecture: any -Depends: ${misc:Depends}, ${shlibs:Depends} +Depends: ${misc:Depends}, ${shlibs:Depends}, + nginx-core (= ${binary:Version}) | nginx-full (= ${binary:Version}) | nginx-light (= ${binary:Version}) | nginx-extras (= ${binary:Version}), Description: PAM authentication module for Nginx The nginx_http_auth_pam module enables authentication using PAM. . @@ -303,7 +311,8 @@ Package: libnginx-mod-http-lua Architecture: any Depends: libnginx-mod-http-ndk (= ${binary:Version}), ${misc:Depends}, - ${shlibs:Depends} + ${shlibs:Depends}, + nginx-core (= ${binary:Version}) | nginx-full (= ${binary:Version}) | nginx-light (= ${binary:Version}) | nginx-extras (= ${binary:Version}), Description: Lua module for Nginx Embed Lua runtime into nginx. . @@ -314,7 +323,8 @@ Description: Lua module for Nginx Package: libnginx-mod-http-ndk Architecture: any -Depends: ${misc:Depends}, ${shlibs:Depends} +Depends: ${misc:Depends}, ${shlibs:Depends}, + nginx-core (= ${binary:Version}) | nginx-full (= ${binary:Version}) | nginx-light (= ${binary:Version}) | nginx-extras (= ${binary:Version}), Description: Nginx Development Kit module The NDK is an Nginx module that is designed to extend the core functionality of the excellent Nginx webserver in a way that can be used as a basis of other @@ -327,7 +337,8 @@ Description: Nginx Development Kit module Package: libnginx-mod-nchan Architecture: any -Depends: ${misc:Depends}, ${shlibs:Depends} +Depends: ${misc:Depends}, ${shlibs:Depends}, + nginx-core (= ${binary:Version}) | nginx-full (= ${binary:Version}) | nginx-light (= ${binary:Version}) | nginx-extras (= ${binary:Version}), Description: Fast, flexible pub/sub server for Nginx Nchan is a scalable, flexible pub/sub server for the modern web, It can be configured as a standalone server, or as a shim between your application and @@ -340,7 +351,8 @@ Description: Fast, flexible pub/sub server for Nginx Package: libnginx-mod-http-echo Architecture: any -Depends: ${misc:Depends}, ${shlibs:Depends} +Depends: ${misc:Depends}, ${shlibs:Depends}, + nginx-core (= ${binary:Version}) | nginx-full (= ${binary:Version}) | nginx-light (= ${binary:Version}) | nginx-extras (= ${binary:Version}), Description: Bring echo and more shell style goodies to Nginx Echo module wraps lots of Nginx internal APIs for streaming input and output, parallel/sequential subrequests, timers and sleeping, as well as various meta @@ -361,7 +373,8 @@ Description: Bring echo and more shell style goodies to Nginx Package: libnginx-mod-http-upstream-fair Architecture: any -Depends: ${misc:Depends}, ${shlibs:Depends} +Depends: ${misc:Depends}, ${shlibs:Depends}, + nginx-core (= ${binary:Version}) | nginx-full (= ${binary:Version}) | nginx-light (= ${binary:Version}) | nginx-extras (= ${binary:Version}), Description: Nginx Upstream Fair Proxy Load Balancer The Nginx fair proxy balancer enhances the standard round-robin load balancer provided with Nginx so that it tracks busy backend servers and adjusts @@ -369,7 +382,8 @@ Description: Nginx Upstream Fair Proxy Load Balancer Package: libnginx-mod-http-headers-more-filter Architecture: any -Depends: ${misc:Depends}, ${shlibs:Depends} +Depends: ${misc:Depends}, ${shlibs:Depends}, + nginx-core (= ${binary:Version}) | nginx-full (= ${binary:Version}) | nginx-light (= ${binary:Version}) | nginx-extras (= ${binary:Version}), Description: Set and clear input and output headers for Nginx The Headers More module allows you to add, set, or clear any output or input header that you specify. @@ -380,7 +394,8 @@ Description: Set and clear input and output headers for Nginx Package: libnginx-mod-http-cache-purge Architecture: any -Depends: ${misc:Depends}, ${shlibs:Depends} +Depends: ${misc:Depends}, ${shlibs:Depends}, + nginx-core (= ${binary:Version}) | nginx-full (= ${binary:Version}) | nginx-light (= ${binary:Version}) | nginx-extras (= ${binary:Version}), Description: Purge content from Nginx caches Cache Purge module adds purging capabilities to Nginx. It allows purging content from caches used by all of Nginx proxy modules, like FastCGI, Proxy, @@ -388,7 +403,8 @@ Description: Purge content from Nginx caches Package: libnginx-mod-http-fancyindex Architecture: any -Depends: ${misc:Depends}, ${shlibs:Depends} +Depends: ${misc:Depends}, ${shlibs:Depends}, + nginx-core (= ${binary:Version}) | nginx-full (= ${binary:Version}) | nginx-light (= ${binary:Version}) | nginx-extras (= ${binary:Version}), Description: Fancy indexes module for the Nginx The Fancy Index module makes possible the generation of file listings, like the built-in autoindex module does, but adding a touch of style by introducing @@ -396,7 +412,8 @@ Description: Fancy indexes module for the Nginx Package: libnginx-mod-http-uploadprogress Architecture: any -Depends: ${misc:Depends}, ${shlibs:Depends} +Depends: ${misc:Depends}, ${shlibs:Depends}, + nginx-core (= ${binary:Version}) | nginx-full (= ${binary:Version}) | nginx-light (= ${binary:Version}) | nginx-extras (= ${binary:Version}), Description: Upload progress system for Nginx Upload progress module is an implementation of an upload progress system, that monitors RFC1867 POST uploads as they are transmitted to upstream servers. @@ -407,7 +424,8 @@ Description: Upload progress system for Nginx Package: libnginx-mod-http-subs-filter Architecture: any -Depends: ${misc:Depends}, ${shlibs:Depends} +Depends: ${misc:Depends}, ${shlibs:Depends}, + nginx-core (= ${binary:Version}) | nginx-full (= ${binary:Version}) | nginx-light (= ${binary:Version}) | nginx-extras (= ${binary:Version}), Description: Substitution filter module for Nginx Subsitution Nginx module can do both regular expression and fixed string substitutions on response bodies. The module is quite different from Nginx's @@ -416,7 +434,8 @@ Description: Substitution filter module for Nginx Package: libnginx-mod-http-dav-ext Architecture: any -Depends: ${misc:Depends}, ${shlibs:Depends} +Depends: ${misc:Depends}, ${shlibs:Depends}, + nginx-core (= ${binary:Version}) | nginx-full (= ${binary:Version}) | nginx-light (= ${binary:Version}) | nginx-extras (= ${binary:Version}), Description: WebDAV missing commands support for Nginx WebDAV Ext module complements the Nginx WebDAV module to provide a full WebDAV support. @@ -425,7 +444,8 @@ Description: WebDAV missing commands support for Nginx Package: libnginx-mod-rtmp Architecture: any -Depends: ${misc:Depends}, ${shlibs:Depends} +Depends: ${misc:Depends}, ${shlibs:Depends}, + nginx-core (= ${binary:Version}) | nginx-full (= ${binary:Version}) | nginx-light (= ${binary:Version}) | nginx-extras (= ${binary:Version}), Description: RTMP support for Nginx The nginx RTMP module is a fully-featured streaming solution implemented in nginx. From 6930b5ac144786de45f79b0231656a6a1968ed51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Nov=C3=BD?= Date: Thu, 4 Jun 2020 23:05:12 +0200 Subject: [PATCH 052/329] Add stream-geoip and stream-geoip2 modules --- debian/control | 45 ++++++++++++++++--- debian/libnginx-mod-stream-geoip.nginx | 13 ++++++ debian/libnginx-mod-stream-geoip2.nginx | 13 ++++++ .../libnginx-mod.conf/mod-stream-geoip.conf | 1 + .../libnginx-mod.conf/mod-stream-geoip2.conf | 1 + debian/rules | 5 ++- debian/tests/control | 16 +++++-- 7 files changed, 83 insertions(+), 11 deletions(-) create mode 100755 debian/libnginx-mod-stream-geoip.nginx create mode 100755 debian/libnginx-mod-stream-geoip2.nginx create mode 100644 debian/libnginx-mod.conf/mod-stream-geoip.conf create mode 100644 debian/libnginx-mod.conf/mod-stream-geoip2.conf diff --git a/debian/control b/debian/control index d18e602..d1fc34b 100644 --- a/debian/control +++ b/debian/control @@ -73,6 +73,7 @@ Depends: libnginx-mod-http-geoip (= ${binary:Version}), libnginx-mod-http-xslt-filter (= ${binary:Version}), libnginx-mod-mail (= ${binary:Version}), libnginx-mod-stream (= ${binary:Version}), + libnginx-mod-stream-geoip (= ${binary:Version}), nginx-common (= ${source:Version}), ${misc:Depends}, ${shlibs:Depends} @@ -97,10 +98,12 @@ Description: nginx web/proxy server (standard version) . OPTIONAL HTTP MODULES: Addition, Auth Request, Charset, WebDAV, GeoIP, Gunzip, Gzip, Gzip Precompression, Headers, HTTP/2, Image Filter, Index, Log, Real IP, - Slice, SSI, SSL, Stream, SSL Preread, Stub Status, Substitution, Thread Pool, + Slice, SSI, SSL, SSL Preread, Stub Status, Substitution, Thread Pool, Upstream, User ID, XSLT. . - MAIL MODULES: Mail Core, Auth HTTP, Proxy, SSL, IMAP, POP3, SMTP. + OPTIONAL MAIL MODULES: Mail Core, Auth HTTP, Proxy, SSL, IMAP, POP3, SMTP. + . + OPTIONAL STREAM MODULES: Stream Core, GeoIP Package: nginx-full Architecture: all @@ -110,6 +113,7 @@ Depends: libnginx-mod-http-auth-pam, libnginx-mod-http-geoip2, libnginx-mod-http-subs-filter, libnginx-mod-http-upstream-fair, + libnginx-mod-stream-geoip2, nginx-core (>= ${source:Version}), nginx-core (<< ${source:Version}.1~), ${misc:Depends}, @@ -135,7 +139,9 @@ Description: nginx web/proxy server (standard version with 3rd parties) Slice, SSI, SSL, Stream, SSL Preread, Stub Status, Substitution, Thread Pool, Upstream, User ID, XSLT. . - MAIL MODULES: Mail Core, Auth HTTP, Proxy, SSL, IMAP, POP3, SMTP. + OPTIONAL MAIL MODULES: Mail Core, Auth HTTP, Proxy, SSL, IMAP, POP3, SMTP. + . + OPTIONAL STREAM MODULES: Stream Core, GeoIP, GeoIP2 . THIRD PARTY MODULES: Auth PAM, DAV Ext, Echo, GeoIP2, HTTP Substitutions Upstream Fair Queue. @@ -187,6 +193,8 @@ Depends: libnginx-mod-http-auth-pam (= ${binary:Version}), libnginx-mod-mail (= ${binary:Version}), libnginx-mod-nchan (= ${binary:Version}), libnginx-mod-stream (= ${binary:Version}), + libnginx-mod-stream-geoip (= ${binary:Version}), + libnginx-mod-stream-geoip2 (= ${binary:Version}), nginx-common (= ${source:Version}), ${misc:Depends}, ${shlibs:Depends} @@ -210,10 +218,11 @@ Description: nginx web/proxy server (extended version) OPTIONAL HTTP MODULES: Addition, Auth Request, Charset, WebDAV, FLV, GeoIP, Gunzip, Gzip, Gzip Precompression, Headers, HTTP/2, Image Filter, Index, Log, MP4, Embedded Perl, Random Index, Real IP, Slice, Secure Link, SSI, SSL, - Stream, SSL Preread, Stub Status, Substitution, Thread Pool, Upstream, - User ID, XSLT. + SSL Preread, Stub Status, Substitution, Thread Pool, Upstream, User ID, XSLT. . - MAIL MODULES: Mail Core, Auth HTTP, Proxy, SSL, IMAP, POP3, SMTP. + OPTIONAL MAIL MODULES: Mail Core, Auth HTTP, Proxy, SSL, IMAP, POP3, SMTP. + . + OPTIONAL STREAM MODULES: Stream, GeoIP, GeoIP2 . THIRD PARTY MODULES: Auth PAM, Cache Purge, DAV Ext, Echo, Fancy Index, GeoIP2, Headers More, Embedded Lua, HTTP Substitutions, Nchan, Upload Progress, @@ -284,6 +293,30 @@ Description: Stream module for Nginx also supports ACLs/connection limiting and configuring multiple operational parameters. +Package: libnginx-mod-stream-geoip +Architecture: any +Depends: ${misc:Depends}, ${shlibs:Depends}, + libnginx-mod-stream (= ${binary:Version}), + nginx-core (= ${binary:Version}) | nginx-full (= ${binary:Version}) | nginx-light (= ${binary:Version}) | nginx-extras (= ${binary:Version}), +Description: GeoIP Stream module for Nginx + The ngx_stream_geoip module creates variables with values depending on the + client IP address, using the precompiled MaxMind databases. + . + Those variables include country, region, city, latitude, longitude, postal + code, etc. + +Package: libnginx-mod-stream-geoip2 +Architecture: any +Depends: ${misc:Depends}, ${shlibs:Depends}, + libnginx-mod-stream (= ${binary:Version}), + nginx-core (= ${binary:Version}) | nginx-full (= ${binary:Version}) | nginx-light (= ${binary:Version}) | nginx-extras (= ${binary:Version}), +Description: GeoIP2 Stream module for Nginx + The ngx_stream_geoip2 module creates variables with values depending on the + client IP address, using the precompiled MaxMind GeoIP2 databases. + . + Those variables include country, region, city, latitude, longitude, postal + code, etc. + Package: libnginx-mod-http-perl Architecture: any Depends: ${misc:Depends}, ${perl:Depends}, ${shlibs:Depends}, diff --git a/debian/libnginx-mod-stream-geoip.nginx b/debian/libnginx-mod-stream-geoip.nginx new file mode 100755 index 0000000..9acb103 --- /dev/null +++ b/debian/libnginx-mod-stream-geoip.nginx @@ -0,0 +1,13 @@ +#!/usr/bin/perl -w + +use File::Basename; + +# Guess module name +$module = basename($0, '.nginx'); +$module =~ s/^libnginx-mod-//; + +$modulepath = $module; +$modulepath =~ s/-/_/g; + +print "mod debian/build-extras/objs/ngx_${modulepath}_module.so\n"; +print "mod debian/libnginx-mod.conf/mod-${module}.conf 70\n"; diff --git a/debian/libnginx-mod-stream-geoip2.nginx b/debian/libnginx-mod-stream-geoip2.nginx new file mode 100755 index 0000000..9acb103 --- /dev/null +++ b/debian/libnginx-mod-stream-geoip2.nginx @@ -0,0 +1,13 @@ +#!/usr/bin/perl -w + +use File::Basename; + +# Guess module name +$module = basename($0, '.nginx'); +$module =~ s/^libnginx-mod-//; + +$modulepath = $module; +$modulepath =~ s/-/_/g; + +print "mod debian/build-extras/objs/ngx_${modulepath}_module.so\n"; +print "mod debian/libnginx-mod.conf/mod-${module}.conf 70\n"; diff --git a/debian/libnginx-mod.conf/mod-stream-geoip.conf b/debian/libnginx-mod.conf/mod-stream-geoip.conf new file mode 100644 index 0000000..7195856 --- /dev/null +++ b/debian/libnginx-mod.conf/mod-stream-geoip.conf @@ -0,0 +1 @@ +load_module modules/ngx_stream_geoip_module.so; diff --git a/debian/libnginx-mod.conf/mod-stream-geoip2.conf b/debian/libnginx-mod.conf/mod-stream-geoip2.conf new file mode 100644 index 0000000..4072597 --- /dev/null +++ b/debian/libnginx-mod.conf/mod-stream-geoip2.conf @@ -0,0 +1 @@ +load_module modules/ngx_stream_geoip2_module.so; diff --git a/debian/rules b/debian/rules index 9fead04..f777843 100755 --- a/debian/rules +++ b/debian/rules @@ -26,7 +26,9 @@ DYN_MODS := \ mail \ nchan \ rtmp \ - stream + stream \ + stream-geoip \ + stream-geoip2 MODULESDIR = $(CURDIR)/debian/modules BASEDIR = $(CURDIR) @@ -109,6 +111,7 @@ extras_configure_flags := \ --with-mail=dynamic \ --with-mail_ssl_module \ --with-stream=dynamic \ + --with-stream_geoip_module=dynamic \ --with-stream_ssl_module \ --with-stream_ssl_preread_module \ --add-dynamic-module=$(MODULESDIR)/http-headers-more-filter \ diff --git a/debian/tests/control b/debian/tests/control index 2ea2832..52690ae 100644 --- a/debian/tests/control +++ b/debian/tests/control @@ -44,7 +44,9 @@ Depends: nginx-core, libnginx-mod-mail, libnginx-mod-nchan, libnginx-mod-rtmp, - libnginx-mod-stream + libnginx-mod-stream-geoip, + libnginx-mod-stream-geoip2, + libnginx-mod-stream, Tests: full-module-deps Restrictions: allow-stderr isolation-container @@ -68,7 +70,9 @@ Depends: nginx-full, libnginx-mod-mail, libnginx-mod-nchan, libnginx-mod-rtmp, - libnginx-mod-stream + libnginx-mod-stream-geoip, + libnginx-mod-stream-geoip2, + libnginx-mod-stream, Tests: light-module-deps Restrictions: allow-stderr isolation-container @@ -92,7 +96,9 @@ Depends: nginx-light, libnginx-mod-mail, libnginx-mod-nchan, libnginx-mod-rtmp, - libnginx-mod-stream + libnginx-mod-stream-geoip, + libnginx-mod-stream-geoip2, + libnginx-mod-stream, Tests: extras-module-deps Restrictions: allow-stderr isolation-container @@ -116,4 +122,6 @@ Depends: nginx-extras, libnginx-mod-mail, libnginx-mod-nchan, libnginx-mod-rtmp, - libnginx-mod-stream + libnginx-mod-stream-geoip, + libnginx-mod-stream-geoip2, + libnginx-mod-stream, From d9b51eb2edf6d0723192cfe3115201a76ed54933 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Nov=C3=BD?= Date: Fri, 5 Jun 2020 09:39:38 +0200 Subject: [PATCH 053/329] d/copyright: Add Thomas Ward from Ubuntu --- debian/copyright | 1 + 1 file changed, 1 insertion(+) diff --git a/debian/copyright b/debian/copyright index 6177c46..3a43c25 100644 --- a/debian/copyright +++ b/debian/copyright @@ -41,6 +41,7 @@ Copyright: 2007-2009, Fabio Tranchitella 2011 Dmitry E. Oboukhov 2011-2013, Cyril Lavier 2013-2016, Christos Trochalakis + 2019-2020, Thomas Ward 2020, Ondřej Nový License: BSD-2-clause From cc65b80eb0bebe0e2d61c4e4b413b3bac729cf39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Nov=C3=BD?= Date: Fri, 5 Jun 2020 09:47:08 +0200 Subject: [PATCH 054/329] Check if port 80 is free before starting during install --- debian/control | 3 +++ debian/nginx-core.postinst | 7 ++++++- debian/nginx-extras.postinst | 7 ++++++- debian/nginx-light.postinst | 7 ++++++- 4 files changed, 21 insertions(+), 3 deletions(-) diff --git a/debian/control b/debian/control index d1fc34b..4f00178 100644 --- a/debian/control +++ b/debian/control @@ -75,6 +75,7 @@ Depends: libnginx-mod-http-geoip (= ${binary:Version}), libnginx-mod-stream (= ${binary:Version}), libnginx-mod-stream-geoip (= ${binary:Version}), nginx-common (= ${source:Version}), + iproute2, ${misc:Depends}, ${shlibs:Depends} Breaks: nginx (<< 1.4.5-1), @@ -150,6 +151,7 @@ Package: nginx-light Architecture: any Depends: libnginx-mod-http-echo (= ${binary:Version}), nginx-common (= ${source:Version}), + iproute2, ${misc:Depends}, ${shlibs:Depends} Breaks: nginx (<< 1.4.5-1) @@ -196,6 +198,7 @@ Depends: libnginx-mod-http-auth-pam (= ${binary:Version}), libnginx-mod-stream-geoip (= ${binary:Version}), libnginx-mod-stream-geoip2 (= ${binary:Version}), nginx-common (= ${source:Version}), + iproute2, ${misc:Depends}, ${shlibs:Depends} Breaks: nginx (<< 1.4.5-1) diff --git a/debian/nginx-core.postinst b/debian/nginx-core.postinst index 2a1730f..b43571a 100644 --- a/debian/nginx-core.postinst +++ b/debian/nginx-core.postinst @@ -24,7 +24,12 @@ if [ -x /etc/init.d/nginx ]; then invoke-rc.d nginx upgrade || invoke-rc.d nginx restart exit $? else - invoke-rc.d nginx start || exit $? + if [ -z "$(ss -nlt 'sport = 80' | grep -v ^State)" ]; then + invoke-rc.d nginx start || exit $? + else + echo "Not attempting to start NGINX, port 80 is already in use." + exit 0 + fi fi fi diff --git a/debian/nginx-extras.postinst b/debian/nginx-extras.postinst index 2a1730f..b43571a 100644 --- a/debian/nginx-extras.postinst +++ b/debian/nginx-extras.postinst @@ -24,7 +24,12 @@ if [ -x /etc/init.d/nginx ]; then invoke-rc.d nginx upgrade || invoke-rc.d nginx restart exit $? else - invoke-rc.d nginx start || exit $? + if [ -z "$(ss -nlt 'sport = 80' | grep -v ^State)" ]; then + invoke-rc.d nginx start || exit $? + else + echo "Not attempting to start NGINX, port 80 is already in use." + exit 0 + fi fi fi diff --git a/debian/nginx-light.postinst b/debian/nginx-light.postinst index 2a1730f..b43571a 100644 --- a/debian/nginx-light.postinst +++ b/debian/nginx-light.postinst @@ -24,7 +24,12 @@ if [ -x /etc/init.d/nginx ]; then invoke-rc.d nginx upgrade || invoke-rc.d nginx restart exit $? else - invoke-rc.d nginx start || exit $? + if [ -z "$(ss -nlt 'sport = 80' | grep -v ^State)" ]; then + invoke-rc.d nginx start || exit $? + else + echo "Not attempting to start NGINX, port 80 is already in use." + exit 0 + fi fi fi From 886b03658ead117ab38d2fcfc0cd46fe526b8562 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Nov=C3=BD?= Date: Fri, 5 Jun 2020 18:28:44 +0200 Subject: [PATCH 055/329] releasing package nginx version 1.18.0-2 --- debian/changelog | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/debian/changelog b/debian/changelog index 3eeacf1..84d1e27 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,28 @@ +nginx (1.18.0-2) unstable; urgency=medium + + [ Ondřej Nový ] + * d/copyright: + - Update for upstream release + - Add Thomas Ward from Ubuntu for debian/* + * d/conf/sites-available/default: Update PHP path for PHP 7.4 + * d/conf/nginx.conf: + - Enable TLSv1.3 + - Remove tcp_nodelay on, which is same as default + - Remove keepalive_timeout 65 and use default value 75s. + - Remove trailing whitespaces + * Introduce nginx-core and make it new default for "nginx" + * Add stream-geoip and stream-geoip2 modules + * d/ngx-conf: Convert to Python 3 + * d/control: Add GeoIP2 into description + * Build dynamic modules only in extras flavour + * libnginx-mod-* now depends on nginx- + * Check if port 80 is free before starting during install + + [ Ondřej Surý ] + * http-geoip2: Add ngx_http_geoip2_module 3.3 + + -- Ondřej Nový Fri, 05 Jun 2020 18:28:40 +0200 + nginx (1.18.0-1) unstable; urgency=medium [ Ondřej Nový ] From fd2d73b10f34e0a6ebaefa106d9e5fe0b2d5b6f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Nov=C3=BD?= Date: Thu, 11 Jun 2020 15:14:41 +0200 Subject: [PATCH 056/329] Source-only upload to allow migration. --- debian/changelog | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/debian/changelog b/debian/changelog index 84d1e27..09a6e1e 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +nginx (1.18.0-3) UNRELEASED; urgency=medium + + * Source-only upload to allow migration. + + -- Ondřej Nový Thu, 11 Jun 2020 15:14:29 +0200 + nginx (1.18.0-2) unstable; urgency=medium [ Ondřej Nový ] From f039c694b28eab9187a6f1caba4b5138724834ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Nov=C3=BD?= Date: Thu, 11 Jun 2020 15:15:05 +0200 Subject: [PATCH 057/329] releasing package nginx version 1.18.0-3 --- debian/changelog | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index 09a6e1e..c2bed08 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,8 +1,8 @@ -nginx (1.18.0-3) UNRELEASED; urgency=medium +nginx (1.18.0-3) unstable; urgency=medium * Source-only upload to allow migration. - -- Ondřej Nový Thu, 11 Jun 2020 15:14:29 +0200 + -- Ondřej Nový Thu, 11 Jun 2020 15:14:59 +0200 nginx (1.18.0-2) unstable; urgency=medium From b760bb04de1e98b65e86c9b3135897055a1c2b81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Nov=C3=BD?= Date: Wed, 24 Jun 2020 15:19:02 +0200 Subject: [PATCH 058/329] Update ngx_http_auth_pam_module upstream URL --- debian/modules/control | 2 +- debian/modules/watch/http-auth-pam | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/debian/modules/control b/debian/modules/control index 8f9964d..94b5538 100644 --- a/debian/modules/control +++ b/debian/modules/control @@ -8,7 +8,7 @@ Homepage: https://github.com/simpl/ngx_devel_kit/ Version: 0.3.1 Module: http-auth-pam -Homepage: https://github.com/stogh/ngx_http_auth_pam_module +Homepage: https://github.com/sto/ngx_http_auth_pam_module Version: 1.5.1 Module: http-echo diff --git a/debian/modules/watch/http-auth-pam b/debian/modules/watch/http-auth-pam index 3fb5a27..8c0a5c0 100644 --- a/debian/modules/watch/http-auth-pam +++ b/debian/modules/watch/http-auth-pam @@ -1,4 +1,4 @@ version=4 opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%libnginx-mod-http-auth-pam-$1.tar.gz%" \ - https://github.com/stogh/ngx_http_auth_pam_module/tags \ + https://github.com/sto/ngx_http_auth_pam_module/tags \ (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/ngxmod uupdate http-auth-pam From 704b0f0e37c33338c95c51108715fa4451c95262 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Nov=C3=BD?= Date: Wed, 24 Jun 2020 15:19:53 +0200 Subject: [PATCH 059/329] http-auth-pam: Upgrade to 1.5.2 (Closes: #963567) --- debian/modules/control | 2 +- debian/modules/http-auth-pam/ChangeLog | 10 ++++++++- debian/modules/http-auth-pam/LICENSE | 2 +- debian/modules/http-auth-pam/README.md | 10 ++++----- debian/modules/http-auth-pam/VERSION | 2 +- .../http-auth-pam/ngx_http_auth_pam_module.c | 21 +++++++++++++------ 6 files changed, 32 insertions(+), 15 deletions(-) diff --git a/debian/modules/control b/debian/modules/control index 94b5538..e980b2f 100644 --- a/debian/modules/control +++ b/debian/modules/control @@ -9,7 +9,7 @@ Version: 0.3.1 Module: http-auth-pam Homepage: https://github.com/sto/ngx_http_auth_pam_module -Version: 1.5.1 +Version: 1.5.2 Module: http-echo Homepage: https://github.com/agentzh/echo-nginx-module diff --git a/debian/modules/http-auth-pam/ChangeLog b/debian/modules/http-auth-pam/ChangeLog index d45eae4..084c99a 100644 --- a/debian/modules/http-auth-pam/ChangeLog +++ b/debian/modules/http-auth-pam/ChangeLog @@ -1,6 +1,14 @@ +2020-06-23 sto@mixinet.net + + * Version 1.5.2. + * Log authentication errors as errors instead of debug (patch provided by + Juha Koho, see https://github.com/sto/ngx_http_auth_pam_module/pull/11) + * Send client IP address to PAM (patch provided by Marcin Łojewski, see + https://github.com/sto/ngx_http_auth_pam_module/pull/14) + 2016-04-06 sto@iti.es - * Version 1.5.1. + * Version 1.5.1. * Fix building alongside other modules in nginx 1.9.11+ (patch provided by Graham Edgecombe ) diff --git a/debian/modules/http-auth-pam/LICENSE b/debian/modules/http-auth-pam/LICENSE index b2d9324..a9d6313 100644 --- a/debian/modules/http-auth-pam/LICENSE +++ b/debian/modules/http-auth-pam/LICENSE @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2016 Sergio Talens Oliag + * Copyright (C) 2008-2020 Sergio Talens Oliag * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/debian/modules/http-auth-pam/README.md b/debian/modules/http-auth-pam/README.md index a4eea45..975bafe 100644 --- a/debian/modules/http-auth-pam/README.md +++ b/debian/modules/http-auth-pam/README.md @@ -75,11 +75,11 @@ If you want use the ``pam_exec.so`` plugin for request based authentication the module can add to the PAM environment the ``HOST`` and ``REQUEST`` variables if you set the ``auth_pam_set_pam_env`` flag:: - location /pam_exec_protected { - auth_pam "Exec Zone"; - auth_pam_service_name "nginx_exec"; - auth_pam_set_pam_env on; - } + location /pam_exec_protected { + auth_pam "Exec Zone"; + auth_pam_service_name "nginx_exec"; + auth_pam_set_pam_env on; + } With this configuration if you access an URL like: diff --git a/debian/modules/http-auth-pam/VERSION b/debian/modules/http-auth-pam/VERSION index c239c60..4cda8f1 100644 --- a/debian/modules/http-auth-pam/VERSION +++ b/debian/modules/http-auth-pam/VERSION @@ -1 +1 @@ -1.5 +1.5.2 diff --git a/debian/modules/http-auth-pam/ngx_http_auth_pam_module.c b/debian/modules/http-auth-pam/ngx_http_auth_pam_module.c index 167a37f..55eeb92 100644 --- a/debian/modules/http-auth-pam/ngx_http_auth_pam_module.c +++ b/debian/modules/http-auth-pam/ngx_http_auth_pam_module.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2016 Sergio Talens-Oliag + * Copyright (C) 2008-2020 Sergio Talens-Oliag * * Based on nginx's 'ngx_http_auth_basic_module.c' by Igor Sysoev and apache's * 'mod_auth_pam.c' by Ingo Luetkebolhe. @@ -182,7 +182,7 @@ ngx_auth_pam_talker(int num_msg, const struct pam_message ** msg, case PAM_PROMPT_ECHO_OFF: response[i].resp = strdup((const char *)ainfo->password.data); break; - case PAM_ERROR_MSG: + case PAM_ERROR_MSG: ngx_log_error(NGX_LOG_ERR, ainfo->log, 0, "PAM: \'%s\'.", msg[i]->msg); break; @@ -335,12 +335,21 @@ ngx_http_auth_pam_authenticate(ngx_http_request_t *r, (const char *) ainfo.username.data, &conv_info, &pamh)) != PAM_SUCCESS) { - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0, "PAM: Could not start pam service: %s", pam_strerror(pamh, rc)); return NGX_HTTP_INTERNAL_SERVER_ERROR; } + /* send client IP address to PAM */ + char *client_ip_addr = ngx_strncpy_s(r->connection->addr_text, r->pool); + if ((rc = pam_set_item(pamh, PAM_RHOST, client_ip_addr)) != PAM_SUCCESS) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "PAM: Could not set item PAM_RHOST: %s", + pam_strerror(pamh, rc)); + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + if (alcf->set_pam_env) { add_request_info_to_pam_env(pamh, r); } @@ -348,7 +357,7 @@ ngx_http_auth_pam_authenticate(ngx_http_request_t *r, /* try to authenticate user, log error on failure */ if ((rc = pam_authenticate(pamh, PAM_DISALLOW_NULL_AUTHTOK)) != PAM_SUCCESS) { - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "PAM: user '%s' - not authenticated: %s", ainfo.username.data, pam_strerror(pamh, rc)); pam_end(pamh, PAM_SUCCESS); @@ -357,8 +366,8 @@ ngx_http_auth_pam_authenticate(ngx_http_request_t *r, /* check that the account is healthy */ if ((rc = pam_acct_mgmt(pamh, PAM_DISALLOW_NULL_AUTHTOK)) != PAM_SUCCESS) { - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "PAM: user '%s' - invalid account: %s", + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "PAM: user '%s' - invalid account: %s", ainfo.username.data, pam_strerror(pamh, rc)); pam_end(pamh, PAM_SUCCESS); return ngx_http_auth_pam_set_realm(r, &alcf->realm); From d08f16833f7bb9d8e3cc40225eb09c9fbacd2994 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Nov=C3=BD?= Date: Wed, 24 Jun 2020 15:21:16 +0200 Subject: [PATCH 060/329] d/copyright: Bump year of http-auth-pam --- debian/copyright | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/copyright b/debian/copyright index 3a43c25..c2a5f97 100644 --- a/debian/copyright +++ b/debian/copyright @@ -69,7 +69,7 @@ Copyright: Austin Appleby License: BSD-3-clause Files: debian/modules/http-auth-pam/* -Copyright: 2008-2016, Sergio Talens Oliag +Copyright: 2008-2020, Sergio Talens Oliag License: BSD-2-clause Files: debian/modules/http-echo/* From 7df3da6863e378b949868c9289755e8d8690351f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Nov=C3=BD?= Date: Tue, 30 Jun 2020 18:27:15 +0200 Subject: [PATCH 061/329] Revert: libnginx-mod-* now depends on nginx- (Closes: 963860). * Revert: libnginx-mod-* now depends on nginx- (Closes: 963860). * libnginx-mod-* recommends nginx now. --- debian/changelog | 7 +++++++ debian/control | 44 ++++++++++++++++++++++---------------------- 2 files changed, 29 insertions(+), 22 deletions(-) diff --git a/debian/changelog b/debian/changelog index c2bed08..fe36eea 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,10 @@ +nginx (1.18.0-4) UNRELEASED; urgency=medium + + * Revert: libnginx-mod-* now depends on nginx- (Closes: #963860) + * libnginx-mod-* recommends nginx now. + + -- Ondřej Nový Tue, 30 Jun 2020 18:26:36 +0200 + nginx (1.18.0-3) unstable; urgency=medium * Source-only upload to allow migration. diff --git a/debian/control b/debian/control index 4f00178..fe24d3e 100644 --- a/debian/control +++ b/debian/control @@ -234,7 +234,7 @@ Description: nginx web/proxy server (extended version) Package: libnginx-mod-http-geoip Architecture: any Depends: ${misc:Depends}, ${shlibs:Depends}, - nginx-core (= ${binary:Version}) | nginx-full (= ${binary:Version}) | nginx-light (= ${binary:Version}) | nginx-extras (= ${binary:Version}), +Recommends: nginx, Description: GeoIP HTTP module for Nginx The ngx_http_geoip module creates variables with values depending on the client IP address, using the precompiled MaxMind databases. @@ -245,7 +245,7 @@ Description: GeoIP HTTP module for Nginx Package: libnginx-mod-http-geoip2 Architecture: any Depends: ${misc:Depends}, ${shlibs:Depends}, - nginx-core (= ${binary:Version}) | nginx-full (= ${binary:Version}) | nginx-light (= ${binary:Version}) | nginx-extras (= ${binary:Version}), +Recommends: nginx, Description: GeoIP2 HTTP module for Nginx The ngx_http_geoip2 module creates variables with values depending on the client IP address, using the precompiled MaxMind GeoIP2 databases. @@ -256,7 +256,7 @@ Description: GeoIP2 HTTP module for Nginx Package: libnginx-mod-http-image-filter Architecture: any Depends: ${misc:Depends}, ${shlibs:Depends}, - nginx-core (= ${binary:Version}) | nginx-full (= ${binary:Version}) | nginx-light (= ${binary:Version}) | nginx-extras (= ${binary:Version}), +Recommends: nginx, Description: HTTP image filter module for Nginx The ngx_http_image_filter module is a filter that transforms images in JPEG, GIF, and PNG formats. @@ -267,7 +267,7 @@ Description: HTTP image filter module for Nginx Package: libnginx-mod-http-xslt-filter Architecture: any Depends: ${misc:Depends}, ${shlibs:Depends}, - nginx-core (= ${binary:Version}) | nginx-full (= ${binary:Version}) | nginx-light (= ${binary:Version}) | nginx-extras (= ${binary:Version}), +Recommends: nginx, Description: XSLT Transformation module for Nginx The ngx_http_xslt_filter module is a filter that transforms XML responses using one or more XSLT stylesheets. @@ -278,7 +278,7 @@ Description: XSLT Transformation module for Nginx Package: libnginx-mod-mail Architecture: any Depends: ${misc:Depends}, ${shlibs:Depends}, - nginx-core (= ${binary:Version}) | nginx-full (= ${binary:Version}) | nginx-light (= ${binary:Version}) | nginx-extras (= ${binary:Version}), +Recommends: nginx, Description: Mail module for Nginx The nginx_mail module adds mail proxy support to nginx. . @@ -288,7 +288,7 @@ Description: Mail module for Nginx Package: libnginx-mod-stream Architecture: any Depends: ${misc:Depends}, ${shlibs:Depends}, - nginx-core (= ${binary:Version}) | nginx-full (= ${binary:Version}) | nginx-light (= ${binary:Version}) | nginx-extras (= ${binary:Version}), +Recommends: nginx, Description: Stream module for Nginx The nginx_stream module adds stream proxy support to nginx. . @@ -300,7 +300,7 @@ Package: libnginx-mod-stream-geoip Architecture: any Depends: ${misc:Depends}, ${shlibs:Depends}, libnginx-mod-stream (= ${binary:Version}), - nginx-core (= ${binary:Version}) | nginx-full (= ${binary:Version}) | nginx-light (= ${binary:Version}) | nginx-extras (= ${binary:Version}), +Recommends: nginx, Description: GeoIP Stream module for Nginx The ngx_stream_geoip module creates variables with values depending on the client IP address, using the precompiled MaxMind databases. @@ -312,7 +312,7 @@ Package: libnginx-mod-stream-geoip2 Architecture: any Depends: ${misc:Depends}, ${shlibs:Depends}, libnginx-mod-stream (= ${binary:Version}), - nginx-core (= ${binary:Version}) | nginx-full (= ${binary:Version}) | nginx-light (= ${binary:Version}) | nginx-extras (= ${binary:Version}), +Recommends: nginx, Description: GeoIP2 Stream module for Nginx The ngx_stream_geoip2 module creates variables with values depending on the client IP address, using the precompiled MaxMind GeoIP2 databases. @@ -323,7 +323,7 @@ Description: GeoIP2 Stream module for Nginx Package: libnginx-mod-http-perl Architecture: any Depends: ${misc:Depends}, ${perl:Depends}, ${shlibs:Depends}, - nginx-core (= ${binary:Version}) | nginx-full (= ${binary:Version}) | nginx-light (= ${binary:Version}) | nginx-extras (= ${binary:Version}), +Recommends: nginx, Replaces: nginx-extras (<< 1.9.14-1) Description: Perl module for Nginx Embed Perl runtime into nginx. @@ -336,7 +336,7 @@ Description: Perl module for Nginx Package: libnginx-mod-http-auth-pam Architecture: any Depends: ${misc:Depends}, ${shlibs:Depends}, - nginx-core (= ${binary:Version}) | nginx-full (= ${binary:Version}) | nginx-light (= ${binary:Version}) | nginx-extras (= ${binary:Version}), +Recommends: nginx, Description: PAM authentication module for Nginx The nginx_http_auth_pam module enables authentication using PAM. . @@ -348,7 +348,7 @@ Architecture: any Depends: libnginx-mod-http-ndk (= ${binary:Version}), ${misc:Depends}, ${shlibs:Depends}, - nginx-core (= ${binary:Version}) | nginx-full (= ${binary:Version}) | nginx-light (= ${binary:Version}) | nginx-extras (= ${binary:Version}), +Recommends: nginx, Description: Lua module for Nginx Embed Lua runtime into nginx. . @@ -360,7 +360,7 @@ Description: Lua module for Nginx Package: libnginx-mod-http-ndk Architecture: any Depends: ${misc:Depends}, ${shlibs:Depends}, - nginx-core (= ${binary:Version}) | nginx-full (= ${binary:Version}) | nginx-light (= ${binary:Version}) | nginx-extras (= ${binary:Version}), +Recommends: nginx, Description: Nginx Development Kit module The NDK is an Nginx module that is designed to extend the core functionality of the excellent Nginx webserver in a way that can be used as a basis of other @@ -374,7 +374,7 @@ Description: Nginx Development Kit module Package: libnginx-mod-nchan Architecture: any Depends: ${misc:Depends}, ${shlibs:Depends}, - nginx-core (= ${binary:Version}) | nginx-full (= ${binary:Version}) | nginx-light (= ${binary:Version}) | nginx-extras (= ${binary:Version}), +Recommends: nginx, Description: Fast, flexible pub/sub server for Nginx Nchan is a scalable, flexible pub/sub server for the modern web, It can be configured as a standalone server, or as a shim between your application and @@ -388,7 +388,7 @@ Description: Fast, flexible pub/sub server for Nginx Package: libnginx-mod-http-echo Architecture: any Depends: ${misc:Depends}, ${shlibs:Depends}, - nginx-core (= ${binary:Version}) | nginx-full (= ${binary:Version}) | nginx-light (= ${binary:Version}) | nginx-extras (= ${binary:Version}), +Recommends: nginx, Description: Bring echo and more shell style goodies to Nginx Echo module wraps lots of Nginx internal APIs for streaming input and output, parallel/sequential subrequests, timers and sleeping, as well as various meta @@ -410,7 +410,7 @@ Description: Bring echo and more shell style goodies to Nginx Package: libnginx-mod-http-upstream-fair Architecture: any Depends: ${misc:Depends}, ${shlibs:Depends}, - nginx-core (= ${binary:Version}) | nginx-full (= ${binary:Version}) | nginx-light (= ${binary:Version}) | nginx-extras (= ${binary:Version}), +Recommends: nginx, Description: Nginx Upstream Fair Proxy Load Balancer The Nginx fair proxy balancer enhances the standard round-robin load balancer provided with Nginx so that it tracks busy backend servers and adjusts @@ -419,7 +419,7 @@ Description: Nginx Upstream Fair Proxy Load Balancer Package: libnginx-mod-http-headers-more-filter Architecture: any Depends: ${misc:Depends}, ${shlibs:Depends}, - nginx-core (= ${binary:Version}) | nginx-full (= ${binary:Version}) | nginx-light (= ${binary:Version}) | nginx-extras (= ${binary:Version}), +Recommends: nginx, Description: Set and clear input and output headers for Nginx The Headers More module allows you to add, set, or clear any output or input header that you specify. @@ -431,7 +431,7 @@ Description: Set and clear input and output headers for Nginx Package: libnginx-mod-http-cache-purge Architecture: any Depends: ${misc:Depends}, ${shlibs:Depends}, - nginx-core (= ${binary:Version}) | nginx-full (= ${binary:Version}) | nginx-light (= ${binary:Version}) | nginx-extras (= ${binary:Version}), +Recommends: nginx, Description: Purge content from Nginx caches Cache Purge module adds purging capabilities to Nginx. It allows purging content from caches used by all of Nginx proxy modules, like FastCGI, Proxy, @@ -440,7 +440,7 @@ Description: Purge content from Nginx caches Package: libnginx-mod-http-fancyindex Architecture: any Depends: ${misc:Depends}, ${shlibs:Depends}, - nginx-core (= ${binary:Version}) | nginx-full (= ${binary:Version}) | nginx-light (= ${binary:Version}) | nginx-extras (= ${binary:Version}), +Suggests: nginx, Description: Fancy indexes module for the Nginx The Fancy Index module makes possible the generation of file listings, like the built-in autoindex module does, but adding a touch of style by introducing @@ -449,7 +449,7 @@ Description: Fancy indexes module for the Nginx Package: libnginx-mod-http-uploadprogress Architecture: any Depends: ${misc:Depends}, ${shlibs:Depends}, - nginx-core (= ${binary:Version}) | nginx-full (= ${binary:Version}) | nginx-light (= ${binary:Version}) | nginx-extras (= ${binary:Version}), +Recommends: nginx, Description: Upload progress system for Nginx Upload progress module is an implementation of an upload progress system, that monitors RFC1867 POST uploads as they are transmitted to upstream servers. @@ -461,7 +461,7 @@ Description: Upload progress system for Nginx Package: libnginx-mod-http-subs-filter Architecture: any Depends: ${misc:Depends}, ${shlibs:Depends}, - nginx-core (= ${binary:Version}) | nginx-full (= ${binary:Version}) | nginx-light (= ${binary:Version}) | nginx-extras (= ${binary:Version}), +Recommends: nginx, Description: Substitution filter module for Nginx Subsitution Nginx module can do both regular expression and fixed string substitutions on response bodies. The module is quite different from Nginx's @@ -471,7 +471,7 @@ Description: Substitution filter module for Nginx Package: libnginx-mod-http-dav-ext Architecture: any Depends: ${misc:Depends}, ${shlibs:Depends}, - nginx-core (= ${binary:Version}) | nginx-full (= ${binary:Version}) | nginx-light (= ${binary:Version}) | nginx-extras (= ${binary:Version}), +Recommends: nginx, Description: WebDAV missing commands support for Nginx WebDAV Ext module complements the Nginx WebDAV module to provide a full WebDAV support. @@ -481,7 +481,7 @@ Description: WebDAV missing commands support for Nginx Package: libnginx-mod-rtmp Architecture: any Depends: ${misc:Depends}, ${shlibs:Depends}, - nginx-core (= ${binary:Version}) | nginx-full (= ${binary:Version}) | nginx-light (= ${binary:Version}) | nginx-extras (= ${binary:Version}), +Recommends: nginx, Description: RTMP support for Nginx The nginx RTMP module is a fully-featured streaming solution implemented in nginx. From bfdc885afc36da25bf5f5df8db8cebc75eddd63a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Nov=C3=BD?= Date: Fri, 3 Jul 2020 09:34:57 +0200 Subject: [PATCH 062/329] releasing package nginx version 1.18.0-4 --- debian/changelog | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/debian/changelog b/debian/changelog index fe36eea..f28e340 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,9 +1,12 @@ -nginx (1.18.0-4) UNRELEASED; urgency=medium +nginx (1.18.0-4) unstable; urgency=medium - * Revert: libnginx-mod-* now depends on nginx- (Closes: #963860) + * Revert: libnginx-mod-* now depends on nginx- (Closes: #963860). + * Update ngx_http_auth_pam_module upstream URL. * libnginx-mod-* recommends nginx now. + * http-auth-pam: Upgrade to 1.5.2 (Closes: #963567). + * d/copyright: Bump year of http-auth-pam. - -- Ondřej Nový Tue, 30 Jun 2020 18:26:36 +0200 + -- Ondřej Nový Fri, 03 Jul 2020 09:34:49 +0200 nginx (1.18.0-3) unstable; urgency=medium From aa1f93ee247cd7d21473f35bcba4a95cdfb388ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Nov=C3=BD?= Date: Tue, 14 Jul 2020 09:53:45 +0200 Subject: [PATCH 063/329] Prevented request smuggling in LUA CVE-2020-11724 Closes: #964950 --- debian/changelog | 8 + .../patches/http-lua/CVE-2020-11724.patch | 856 ++++++++++++++++++ debian/modules/patches/http-lua/series | 1 + 3 files changed, 865 insertions(+) create mode 100644 debian/modules/patches/http-lua/CVE-2020-11724.patch diff --git a/debian/changelog b/debian/changelog index f28e340..ddd6387 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,11 @@ +nginx (1.18.0-5) UNRELEASED; urgency=medium + + * Prevented request smuggling in LUA + CVE-2020-11724 + Closes: #964950 + + -- Ondřej Nový Tue, 14 Jul 2020 09:51:13 +0200 + nginx (1.18.0-4) unstable; urgency=medium * Revert: libnginx-mod-* now depends on nginx- (Closes: #963860). diff --git a/debian/modules/patches/http-lua/CVE-2020-11724.patch b/debian/modules/patches/http-lua/CVE-2020-11724.patch new file mode 100644 index 0000000..5e0eff7 --- /dev/null +++ b/debian/modules/patches/http-lua/CVE-2020-11724.patch @@ -0,0 +1,856 @@ +From 9ab38e8ee35fc08a57636b1b6190dca70b0076fa Mon Sep 17 00:00:00 2001 +From: Thibault Charbonnier +Date: Mon, 23 Mar 2020 19:40:47 -0700 +Origin: https://github.com/openresty/lua-nginx-module/commit/9ab38e8ee35fc08a57636b1b6190dca70b0076fa +Subject: [PATCH] bugfix: prevented request smuggling in the + ngx.location.capture API. + +Signed-off-by: Yichun Zhang (agentzh) +--- + src/ngx_http_lua_subrequest.c | 196 +++++-------- + t/020-subrequest.t | 520 +++++++++++++++++++++++++++++++++- + 2 files changed, 585 insertions(+), 131 deletions(-) + +Index: http-lua/src/ngx_http_lua_subrequest.c +=================================================================== +--- http-lua.orig/src/ngx_http_lua_subrequest.c 2020-07-14 09:50:35.830928117 +0200 ++++ http-lua/src/ngx_http_lua_subrequest.c 2020-07-14 09:50:35.826928232 +0200 +@@ -56,8 +56,6 @@ + ngx_string("Content-Length"); + + +-static ngx_int_t ngx_http_lua_set_content_length_header(ngx_http_request_t *r, +- off_t len); + static ngx_int_t ngx_http_lua_adjust_subrequest(ngx_http_request_t *sr, + ngx_uint_t method, int forward_body, + ngx_http_request_body_t *body, unsigned vars_action, +@@ -78,7 +76,7 @@ + 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 *r); ++ ngx_http_request_t *pr, int pr_not_chunked); + + + /* ngx.location.capture is just a thin wrapper around +@@ -628,8 +626,8 @@ + unsigned vars_action, ngx_array_t *extra_vars) + { + ngx_http_request_t *r; +- ngx_int_t rc; + ngx_http_core_main_conf_t *cmcf; ++ int pr_not_chunked = 0; + size_t size; + + r = sr->parent; +@@ -639,46 +637,32 @@ + if (body) { + sr->request_body = body; + +- rc = ngx_http_lua_set_content_length_header(sr, +- body->buf +- ? ngx_buf_size(body->buf) +- : 0); +- +- if (rc != NGX_OK) { +- return NGX_ERROR; +- } +- + } else if (!always_forward_body + && method != NGX_HTTP_PUT + && method != NGX_HTTP_POST + && r->headers_in.content_length_n > 0) + { +- rc = ngx_http_lua_set_content_length_header(sr, 0); +- if (rc != NGX_OK) { +- return NGX_ERROR; +- } +- +-#if 1 + sr->request_body = NULL; +-#endif + + } else { +- if (ngx_http_lua_copy_request_headers(sr, r) != NGX_OK) { +- return NGX_ERROR; ++ if (!r->headers_in.chunked) { ++ pr_not_chunked = 1; + } + +- if (sr->request_body) { ++ if (sr->request_body && sr->request_body->temp_file) { + + /* deep-copy the request body */ + +- if (sr->request_body->temp_file) { +- if (ngx_http_lua_copy_in_file_request_body(sr) != NGX_OK) { +- return NGX_ERROR; +- } ++ if (ngx_http_lua_copy_in_file_request_body(sr) != NGX_OK) { ++ return NGX_ERROR; + } + } + } + ++ if (ngx_http_lua_copy_request_headers(sr, r, pr_not_chunked) != NGX_OK) { ++ return NGX_ERROR; ++ } ++ + sr->method = method; + + switch (method) { +@@ -1124,100 +1108,6 @@ + } + + +-static ngx_int_t +-ngx_http_lua_set_content_length_header(ngx_http_request_t *r, off_t len) +-{ +- ngx_table_elt_t *h, *header; +- u_char *p; +- ngx_list_part_t *part; +- ngx_http_request_t *pr; +- ngx_uint_t i; +- +- r->headers_in.content_length_n = len; +- +- if (ngx_list_init(&r->headers_in.headers, r->pool, 20, +- sizeof(ngx_table_elt_t)) != NGX_OK) +- { +- return NGX_ERROR; +- } +- +- h = ngx_list_push(&r->headers_in.headers); +- if (h == NULL) { +- return NGX_ERROR; +- } +- +- h->key = ngx_http_lua_content_length_header_key; +- h->lowcase_key = ngx_pnalloc(r->pool, h->key.len); +- if (h->lowcase_key == NULL) { +- return NGX_ERROR; +- } +- +- ngx_strlow(h->lowcase_key, h->key.data, h->key.len); +- +- r->headers_in.content_length = h; +- +- p = ngx_palloc(r->pool, NGX_OFF_T_LEN); +- if (p == NULL) { +- return NGX_ERROR; +- } +- +- h->value.data = p; +- +- h->value.len = ngx_sprintf(h->value.data, "%O", len) - h->value.data; +- +- h->hash = ngx_http_lua_content_length_hash; +- +-#if 0 +- dd("content length hash: %lu == %lu", (unsigned long) h->hash, +- ngx_hash_key_lc((u_char *) "Content-Length", +- sizeof("Content-Length") - 1)); +-#endif +- +- dd("r content length: %.*s", +- (int) r->headers_in.content_length->value.len, +- r->headers_in.content_length->value.data); +- +- pr = r->parent; +- +- if (pr == NULL) { +- return NGX_OK; +- } +- +- /* forward the parent request's all other request headers */ +- +- part = &pr->headers_in.headers.part; +- header = part->elts; +- +- 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 == sizeof("Content-Length") - 1 +- && ngx_strncasecmp(header[i].key.data, (u_char *) "Content-Length", +- sizeof("Content-Length") - 1) == 0) +- { +- continue; +- } +- +- if (ngx_http_lua_set_input_header(r, header[i].key, +- header[i].value, 0) == NGX_ERROR) +- { +- return NGX_ERROR; +- } +- } +- +- return NGX_OK; +-} +- +- + static void + ngx_http_lua_handle_subreq_responses(ngx_http_request_t *r, + ngx_http_lua_ctx_t *ctx) +@@ -1732,11 +1622,17 @@ + + + static ngx_int_t +-ngx_http_lua_copy_request_headers(ngx_http_request_t *sr, ngx_http_request_t *r) ++ngx_http_lua_copy_request_headers(ngx_http_request_t *sr, ++ ngx_http_request_t *pr, int pr_not_chunked) + { +- ngx_table_elt_t *header; ++ ngx_table_elt_t *clh, *header; + ngx_list_part_t *part; + ngx_uint_t i; ++ u_char *p; ++ off_t len; ++ ++ dd("before: parent req headers count: %d", ++ (int) pr->headers_in.headers.part.nelts); + + if (ngx_list_init(&sr->headers_in.headers, sr->pool, 20, + sizeof(ngx_table_elt_t)) != NGX_OK) +@@ -1744,10 +1640,46 @@ + return NGX_ERROR; + } + +- dd("before: parent req headers count: %d", +- (int) r->headers_in.headers.part.nelts); ++ if (sr->request_body && !pr_not_chunked) { ++ ++ /* craft our own Content-Length */ ++ ++ len = sr->request_body->buf ? ngx_buf_size(sr->request_body->buf) : 0; ++ ++ clh = ngx_list_push(&sr->headers_in.headers); ++ if (clh == NULL) { ++ return NGX_ERROR; ++ } + +- part = &r->headers_in.headers.part; ++ clh->hash = ngx_http_lua_content_length_hash; ++ clh->key = ngx_http_lua_content_length_header_key; ++ clh->lowcase_key = ngx_pnalloc(sr->pool, clh->key.len); ++ if (clh->lowcase_key == NULL) { ++ return NGX_ERROR; ++ } ++ ++ ngx_strlow(clh->lowcase_key, clh->key.data, clh->key.len); ++ ++ p = ngx_palloc(sr->pool, NGX_OFF_T_LEN); ++ if (p == NULL) { ++ return NGX_ERROR; ++ } ++ ++ clh->value.data = p; ++ clh->value.len = ngx_sprintf(clh->value.data, "%O", len) ++ - clh->value.data; ++ ++ sr->headers_in.content_length = clh; ++ sr->headers_in.content_length_n = len; ++ ++ dd("sr crafted content-length: %.*s", ++ (int) sr->headers_in.content_length->value.len, ++ sr->headers_in.content_length->value.data); ++ } ++ ++ /* copy the parent request's headers */ ++ ++ part = &pr->headers_in.headers.part; + header = part->elts; + + for (i = 0; /* void */; i++) { +@@ -1762,7 +1694,14 @@ + i = 0; + } + +- dd("setting request header %.*s: %.*s", (int) header[i].key.len, ++ if (!pr_not_chunked && header[i].key.len == sizeof("Content-Length") - 1 ++ && ngx_strncasecmp(header[i].key.data, (u_char *) "Content-Length", ++ sizeof("Content-Length") - 1) == 0) ++ { ++ continue; ++ } ++ ++ dd("sr copied req header %.*s: %.*s", (int) header[i].key.len, + header[i].key.data, (int) header[i].value.len, + header[i].value.data); + +@@ -1774,9 +1713,10 @@ + } + + dd("after: parent req headers count: %d", +- (int) r->headers_in.headers.part.nelts); ++ (int) pr->headers_in.headers.part.nelts); + + return NGX_OK; + } + ++ + /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ +Index: http-lua/t/020-subrequest.t +=================================================================== +--- http-lua.orig/t/020-subrequest.t 2020-07-14 09:50:35.830928117 +0200 ++++ http-lua/t/020-subrequest.t 2020-07-14 09:50:35.826928232 +0200 +@@ -14,6 +14,7 @@ + plan tests => repeat_each() * (blocks() * 3 + 23); + + $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; ++$ENV{TEST_NGINX_HTML_DIR} ||= html_dir(); + + #no_diff(); + no_long_string(); +@@ -210,7 +211,7 @@ + + + +-=== TEST 8: PUT (nobody, proxy method) ++=== TEST 8: PUT (with body, proxy method) + --- config + location /other { + default_type 'foo/bar'; +@@ -242,7 +243,7 @@ + + + +-=== TEST 9: PUT (nobody, no proxy method) ++=== TEST 9: PUT (with body, no proxy method) + --- config + location /other { + default_type 'foo/bar'; +@@ -271,7 +272,7 @@ + + + +-=== TEST 10: PUT (nobody, no proxy method) ++=== TEST 10: PUT (no body, no proxy method) + --- config + location /other { + default_type 'foo/bar'; +@@ -2877,3 +2878,516 @@ + --- no_error_log + [error] + --- error_code: 200 ++ ++ ++ ++=== TEST 77: avoid request smuggling 1/4 (default capture + smuggle in header) ++--- http_config ++ upstream backend { ++ server unix:$TEST_NGINX_HTML_DIR/nginx.sock; ++ keepalive 32; ++ } ++ ++ server { ++ listen unix:$TEST_NGINX_HTML_DIR/nginx.sock; ++ ++ location / { ++ content_by_lua_block { ++ ngx.say("method: ", ngx.var.request_method, ++ ", uri: ", ngx.var.uri, ++ ", X: ", ngx.var.http_x) ++ } ++ } ++ } ++--- config ++ location /proxy { ++ proxy_http_version 1.1; ++ proxy_set_header Connection ""; ++ proxy_pass http://backend/foo; ++ } ++ ++ location /capture { ++ server_tokens off; ++ more_clear_headers Date; ++ ++ content_by_lua_block { ++ local res = ngx.location.capture("/proxy") ++ ngx.print(res.body) ++ } ++ } ++ ++ location /t { ++ content_by_lua_block { ++ local req = [[ ++GET /capture HTTP/1.1 ++Host: test.com ++Content-Length: 37 ++Transfer-Encoding: chunked ++ ++0 ++ ++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: 146 ++HTTP/1.1 200 OK ++Server: nginx ++Content-Type: text/plain ++Transfer-Encoding: chunked ++Connection: keep-alive ++ ++1f ++method: GET, uri: /foo, X: nil ++ ++0 ++ ++HTTP/1.1 200 OK ++Server: nginx ++Content-Type: text/plain ++Transfer-Encoding: chunked ++Connection: keep-alive ++ ++2d ++method: GET, uri: /foo, X: GET /bar HTTP/1.0 ++ ++0 ++--- no_error_log ++[error] ++ ++ ++ ++=== TEST 78: avoid request smuggling 2/4 (POST capture + smuggle in body) ++--- http_config ++ upstream backend { ++ server unix:$TEST_NGINX_HTML_DIR/nginx.sock; ++ keepalive 32; ++ } ++ ++ server { ++ listen unix:$TEST_NGINX_HTML_DIR/nginx.sock; ++ ++ location / { ++ content_by_lua_block { ++ ngx.say("method: ", ngx.var.request_method, ++ ", uri: ", ngx.var.uri) ++ } ++ } ++ } ++--- config ++ location /proxy { ++ proxy_http_version 1.1; ++ proxy_set_header Connection ""; ++ proxy_pass http://backend/foo; ++ } ++ ++ location /capture { ++ server_tokens off; ++ more_clear_headers Date; ++ ++ content_by_lua_block { ++ ngx.req.read_body() ++ local res = ngx.location.capture("/proxy", { method = ngx.HTTP_POST }) ++ ngx.print(res.body) ++ } ++ } ++ ++ location /t { ++ content_by_lua_block { ++ local req = [[ ++GET /capture HTTP/1.1 ++Host: test.com ++Content-Length: 57 ++Transfer-Encoding: chunked ++ ++0 ++ ++POST /capture HTTP/1.1 ++Host: test.com ++Content-Length: 60 ++ ++POST /bar HTTP/1.1 ++Host: test.com ++Content-Length: 5 ++ ++hello ++ ++]] ++ ++ 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: 205 ++HTTP/1.1 200 OK ++Server: nginx ++Content-Type: text/plain ++Transfer-Encoding: chunked ++Connection: keep-alive ++ ++18 ++method: POST, uri: /foo ++ ++0 ++ ++HTTP/1.1 200 OK ++Server: nginx ++Content-Type: text/plain ++Transfer-Encoding: chunked ++Connection: keep-alive ++ ++18 ++method: POST, uri: /foo ++ ++0 ++--- no_error_log ++[error] ++ ++ ++ ++=== TEST 79: avoid request smuggling 3/4 (POST capture w/ always_forward_body + smuggle in body) ++--- http_config ++ upstream backend { ++ server unix:$TEST_NGINX_HTML_DIR/nginx.sock; ++ keepalive 32; ++ } ++ ++ server { ++ listen unix:$TEST_NGINX_HTML_DIR/nginx.sock; ++ ++ location / { ++ content_by_lua_block { ++ ngx.say("method: ", ngx.var.request_method, ++ ", uri: ", ngx.var.uri) ++ } ++ } ++ } ++--- config ++ location /proxy { ++ proxy_http_version 1.1; ++ proxy_set_header Connection ""; ++ proxy_pass http://backend/foo; ++ } ++ ++ location /capture { ++ server_tokens off; ++ more_clear_headers Date; ++ ++ content_by_lua_block { ++ ngx.req.read_body() ++ local res = ngx.location.capture("/proxy", { ++ method = ngx.HTTP_POST, ++ always_forward_body = true ++ }) ++ ngx.print(res.body) ++ } ++ } ++ ++ location /t { ++ content_by_lua_block { ++ local req = [[ ++GET /capture HTTP/1.1 ++Host: test.com ++Content-Length: 57 ++Transfer-Encoding: chunked ++ ++0 ++ ++POST /capture HTTP/1.1 ++Host: test.com ++Content-Length: 60 ++ ++POST /bar HTTP/1.1 ++Host: test.com ++Content-Length: 5 ++ ++hello ++ ++]] ++ ++ 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: 205 ++HTTP/1.1 200 OK ++Server: nginx ++Content-Type: text/plain ++Transfer-Encoding: chunked ++Connection: keep-alive ++ ++18 ++method: POST, uri: /foo ++ ++0 ++ ++HTTP/1.1 200 OK ++Server: nginx ++Content-Type: text/plain ++Transfer-Encoding: chunked ++Connection: keep-alive ++ ++18 ++method: POST, uri: /foo ++ ++0 ++--- no_error_log ++[error] ++ ++ ++ ++=== TEST 80: avoid request smuggling 4/4 (POST capture w/ body + smuggle in body) ++--- http_config ++ upstream backend { ++ server unix:$TEST_NGINX_HTML_DIR/nginx.sock; ++ keepalive 32; ++ } ++ ++ server { ++ listen unix:$TEST_NGINX_HTML_DIR/nginx.sock; ++ ++ location / { ++ content_by_lua_block { ++ ngx.say("method: ", ngx.var.request_method, ++ ", uri: ", ngx.var.uri) ++ } ++ } ++ } ++--- config ++ location /proxy { ++ proxy_http_version 1.1; ++ proxy_set_header Connection ""; ++ proxy_pass http://backend/foo; ++ } ++ ++ location /capture { ++ server_tokens off; ++ more_clear_headers Date; ++ ++ content_by_lua_block { ++ ngx.req.read_body() ++ local res = ngx.location.capture("/proxy", { ++ method = ngx.HTTP_POST, ++ always_forward_body = true, ++ body = ngx.req.get_body_data() ++ }) ++ ngx.print(res.body) ++ } ++ } ++ ++ location /t { ++ content_by_lua_block { ++ local req = [[ ++GET /capture HTTP/1.1 ++Host: test.com ++Content-Length: 57 ++Transfer-Encoding: chunked ++ ++0 ++ ++POST /capture HTTP/1.1 ++Host: test.com ++Content-Length: 60 ++ ++POST /bar HTTP/1.1 ++Host: test.com ++Content-Length: 5 ++ ++hello ++ ++]] ++ ++ 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: 205 ++HTTP/1.1 200 OK ++Server: nginx ++Content-Type: text/plain ++Transfer-Encoding: chunked ++Connection: keep-alive ++ ++18 ++method: POST, uri: /foo ++ ++0 ++ ++HTTP/1.1 200 OK ++Server: nginx ++Content-Type: text/plain ++Transfer-Encoding: chunked ++Connection: keep-alive ++ ++18 ++method: POST, uri: /foo ++ ++0 ++--- no_error_log ++[error] diff --git a/debian/modules/patches/http-lua/series b/debian/modules/patches/http-lua/series index 6a8b245..1c68a88 100644 --- a/debian/modules/patches/http-lua/series +++ b/debian/modules/patches/http-lua/series @@ -1 +1,2 @@ discover-luajit-2.1.patch +CVE-2020-11724.patch From 0c7efeffcd8c4c21208891e19c252da2274b405d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Nov=C3=BD?= Date: Tue, 14 Jul 2020 10:08:21 +0200 Subject: [PATCH 064/329] releasing package nginx version 1.18.0-5 --- debian/changelog | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index ddd6387..9516633 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,10 +1,10 @@ -nginx (1.18.0-5) UNRELEASED; urgency=medium +nginx (1.18.0-5) unstable; urgency=medium * Prevented request smuggling in LUA CVE-2020-11724 Closes: #964950 - -- Ondřej Nový Tue, 14 Jul 2020 09:51:13 +0200 + -- Ondřej Nový Tue, 14 Jul 2020 10:08:15 +0200 nginx (1.18.0-4) unstable; urgency=medium From 371e61084fa4ddb1daf676d6d02741c2a87119c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Nov=C3=BD?= Date: Wed, 19 Aug 2020 15:19:52 +0200 Subject: [PATCH 065/329] Fix GCC-10 compatibility (Closes: #957605). --- debian/changelog | 6 ++ .../patches/nchan/gcc-10-compatibility.patch | 58 +++++++++++++++++++ debian/modules/patches/nchan/series | 1 + 3 files changed, 65 insertions(+) create mode 100644 debian/modules/patches/nchan/gcc-10-compatibility.patch create mode 100644 debian/modules/patches/nchan/series diff --git a/debian/changelog b/debian/changelog index 9516633..be0e809 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +nginx (1.18.0-6) UNRELEASED; urgency=medium + + * Fix GCC-10 compatibility (Closes: #957605). + + -- Ondřej Nový Wed, 19 Aug 2020 15:19:33 +0200 + nginx (1.18.0-5) unstable; urgency=medium * Prevented request smuggling in LUA diff --git a/debian/modules/patches/nchan/gcc-10-compatibility.patch b/debian/modules/patches/nchan/gcc-10-compatibility.patch new file mode 100644 index 0000000..00e3b45 --- /dev/null +++ b/debian/modules/patches/nchan/gcc-10-compatibility.patch @@ -0,0 +1,58 @@ +From f484c603a81c3bddd3f0160cfdbe231b8a453cde Mon Sep 17 00:00:00 2001 +From: Leo P +Date: Wed, 24 Jun 2020 15:28:07 -0400 +Subject: [PATCH] GCC 10 compatibility +Origin: https://github.com/slact/nchan/commit/f484c603a81c3bddd3f0160cfdbe231b8a453cde + +--- + src/store/memory/memstore.c | 2 ++ + src/store/memory/store-private.h | 2 +- + src/store/redis/redis_lua_commands.h | 7 +++++-- + 5 files changed, 10 insertions(+), 4 deletions(-) + +diff --git a/src/store/memory/memstore.c b/src/store/memory/memstore.c +index 2844220c..f0f78acc 100755 +--- a/src/store/memory/memstore.c ++++ b/src/store/memory/memstore.c +@@ -40,6 +40,8 @@ static ngx_int_t redis_fakesub_timer_interval; + + #endif + ++uint16_t memstore_worker_generation; ++ + + typedef struct { + //memstore_channel_head_t unbuffered_dummy_chanhead; +diff --git a/src/store/memory/store-private.h b/src/store/memory/store-private.h +index e4a426a3..49de940b 100644 +--- a/src/store/memory/store-private.h ++++ b/src/store/memory/store-private.h +@@ -172,6 +172,6 @@ ngx_int_t chanhead_gc_withdraw(memstore_channel_head_t *chanhead, const char *); + void memstore_chanhead_release(memstore_channel_head_t *ch, char *label); + void memstore_chanhead_reserve(memstore_channel_head_t *ch, const char *label); + +-uint16_t memstore_worker_generation; //times nginx has been restarted + 1 ++extern uint16_t memstore_worker_generation; //times nginx has been restarted + 1 + + #endif /*MEMSTORE_PRIVATE_HEADER*/ +diff --git a/src/store/redis/redis_lua_commands.h b/src/store/redis/redis_lua_commands.h +index 76fb7b95..2efb25bd 100644 +--- a/src/store/redis/redis_lua_commands.h ++++ b/src/store/redis/redis_lua_commands.h +@@ -1,3 +1,5 @@ ++#ifndef NCHAN_REDIS_LUA_SCRIPTS_H ++#define NCHAN_REDIS_LUA_SCRIPTS_H + // don't edit this please, it was auto-generated by hsss + // https://github.com/slact/hsss + +@@ -63,7 +65,8 @@ typedef struct { + redis_lua_script_t subscriber_unregister; + + } redis_lua_scripts_t; +-redis_lua_scripts_t redis_lua_scripts; +-const int redis_lua_scripts_count; ++extern redis_lua_scripts_t redis_lua_scripts; ++extern const int redis_lua_scripts_count; + #define REDIS_LUA_SCRIPTS_EACH(script) \ + for((script)=(redis_lua_script_t *)&redis_lua_scripts; (script) < (redis_lua_script_t *)(&redis_lua_scripts + 1); (script)++) ++#endif //NCHAN_REDIS_LUA_SCRIPTS_H diff --git a/debian/modules/patches/nchan/series b/debian/modules/patches/nchan/series new file mode 100644 index 0000000..80f5dee --- /dev/null +++ b/debian/modules/patches/nchan/series @@ -0,0 +1 @@ +gcc-10-compatibility.patch From d5edfb4e7a674fc06881872e54a4dfd964ea7a5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Nov=C3=BD?= Date: Wed, 19 Aug 2020 15:27:14 +0200 Subject: [PATCH 066/329] releasing package nginx version 1.18.0-6 --- debian/changelog | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index be0e809..266e3ea 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,8 +1,8 @@ -nginx (1.18.0-6) UNRELEASED; urgency=medium +nginx (1.18.0-6) unstable; urgency=medium * Fix GCC-10 compatibility (Closes: #957605). - -- Ondřej Nový Wed, 19 Aug 2020 15:19:33 +0200 + -- Ondřej Nový Wed, 19 Aug 2020 15:27:02 +0200 nginx (1.18.0-5) unstable; urgency=medium From 28cea613e4d327458cc715425cfa9ee399c68b11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Nov=C3=BD?= Date: Fri, 21 Aug 2020 14:14:23 +0200 Subject: [PATCH 067/329] d/p/CVE-2019-20372.patch: Drop, applied upstream. --- debian/changelog | 6 ++++++ debian/patches/CVE-2019-20372.patch | 26 -------------------------- debian/patches/series | 1 - 3 files changed, 6 insertions(+), 27 deletions(-) delete mode 100644 debian/patches/CVE-2019-20372.patch diff --git a/debian/changelog b/debian/changelog index 266e3ea..05a740b 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +nginx (1.18.0-7) UNRELEASED; urgency=medium + + * d/p/CVE-2019-20372.patch: Drop, applied upstream. + + -- Ondřej Nový Fri, 21 Aug 2020 14:14:13 +0200 + nginx (1.18.0-6) unstable; urgency=medium * Fix GCC-10 compatibility (Closes: #957605). diff --git a/debian/patches/CVE-2019-20372.patch b/debian/patches/CVE-2019-20372.patch deleted file mode 100644 index 741b0a9..0000000 --- a/debian/patches/CVE-2019-20372.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 8bffc01d084b4881e3eed2052c115b8f04268cb9 Mon Sep 17 00:00:00 2001 -From: Ruslan Ermilov -Date: Mon, 23 Dec 2019 15:45:46 +0300 -Subject: [PATCH] Discard request body when redirecting to a URL via - error_page. - -Reported by Bert JW Regeer and Francisco Oca Gonzalez. ---- - src/http/ngx_http_special_response.c | 6 ++++++ - 1 file changed, 6 insertions(+) - ---- a/src/http/ngx_http_special_response.c -+++ b/src/http/ngx_http_special_response.c -@@ -629,6 +629,12 @@ - r->keepalive = 0; - } - -+ r->expect_tested = 1; -+ -+ if (ngx_http_discard_request_body(r) != NGX_OK) { -+ r->keepalive = 0; -+ } -+ - location = ngx_list_push(&r->headers_out.headers); - - if (location == NULL) { diff --git a/debian/patches/series b/debian/patches/series index b221db7..5b6b799 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -1,3 +1,2 @@ 0002-Make-sure-signature-stays-the-same-in-all-nginx-buil.patch 0003-define_gnu_source-on-other-glibc-based-platforms.patch -CVE-2019-20372.patch From da49114fdc5bf958678fc432802408e05f4cb07b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= Date: Tue, 8 Oct 2019 22:48:47 +0200 Subject: [PATCH 068/329] Add arm64 and ppc64el to list of luajit platforms --- debian/control | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/debian/control b/debian/control index fe24d3e..d55777f 100644 --- a/debian/control +++ b/debian/control @@ -10,8 +10,8 @@ Build-Depends: debhelper-compat (= 13), libgd-dev, libgeoip-dev, libhiredis-dev, - liblua5.1-0-dev [!i386 !amd64 !kfreebsd-i386 !armel !armhf !powerpc !powerpcspe !mips !mipsel], - libluajit-5.1-dev [i386 amd64 kfreebsd-i386 armel armhf powerpc powerpcspe mips mipsel], + liblua5.1-0-dev [!i386 !amd64 !kfreebsd-i386 !armel !armhf !powerpc !powerpcspe !mips !mipsel !arm64 !ppc64el], + libluajit-5.1-dev [i386 amd64 kfreebsd-i386 armel armhf powerpc powerpcspe mips mipsel arm64 ppc64el], libmaxminddb-dev, libmhash-dev, libpam0g-dev, From ecdfceccf1f12f440c0890056d145b27dbb3c1ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Nov=C3=BD?= Date: Tue, 15 Mar 2022 11:01:10 +0100 Subject: [PATCH 069/329] http-auth-pam: Upgrade to 1.5.3 --- debian/modules/control | 2 +- debian/modules/http-auth-pam/ChangeLog | 6 ++++++ debian/modules/http-auth-pam/VERSION | 2 +- debian/modules/http-auth-pam/config | 3 ++- 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/debian/modules/control b/debian/modules/control index e980b2f..86b6094 100644 --- a/debian/modules/control +++ b/debian/modules/control @@ -9,7 +9,7 @@ Version: 0.3.1 Module: http-auth-pam Homepage: https://github.com/sto/ngx_http_auth_pam_module -Version: 1.5.2 +Version: 1.5.3 Module: http-echo Homepage: https://github.com/agentzh/echo-nginx-module diff --git a/debian/modules/http-auth-pam/ChangeLog b/debian/modules/http-auth-pam/ChangeLog index 084c99a..5974d79 100644 --- a/debian/modules/http-auth-pam/ChangeLog +++ b/debian/modules/http-auth-pam/ChangeLog @@ -1,3 +1,9 @@ +2021-08-23 sto@mixinet.net + + * Version 1.5.3. + * Always load after ngx_http_access_module (patch provided by khimaros, see + https://github.com/sto/ngx_http_auth_pam_module/pull/26) + 2020-06-23 sto@mixinet.net * Version 1.5.2. diff --git a/debian/modules/http-auth-pam/VERSION b/debian/modules/http-auth-pam/VERSION index 4cda8f1..8af85be 100644 --- a/debian/modules/http-auth-pam/VERSION +++ b/debian/modules/http-auth-pam/VERSION @@ -1 +1 @@ -1.5.2 +1.5.3 diff --git a/debian/modules/http-auth-pam/config b/debian/modules/http-auth-pam/config index 2275262..6965eea 100644 --- a/debian/modules/http-auth-pam/config +++ b/debian/modules/http-auth-pam/config @@ -7,10 +7,11 @@ if test -n "$ngx_module_link"; then ngx_module_deps= ngx_module_srcs="$ngx_addon_dir/ngx_http_auth_pam_module.c" ngx_module_libs="-lpam" + ngx_module_order="$ngx_module_name ngx_http_access_module" . auto/module else HTTP_MODULES="$HTTP_MODULES ngx_http_auth_pam_module" NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_auth_pam_module.c" CORE_LIBS="$CORE_LIBS -lpam" -fi \ No newline at end of file +fi From 0b739c803e9b15111d84aae1d2fbf8b538960aa8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Nov=C3=BD?= Date: Tue, 15 Mar 2022 11:01:16 +0100 Subject: [PATCH 070/329] http-echo: Upgrade to 0.62 --- debian/modules/control | 2 +- debian/modules/http-echo/README.markdown | 7 +++- debian/modules/http-echo/config | 29 ++++++++-------- .../http-echo/src/ngx_http_echo_util.h | 2 +- debian/modules/http-echo/valgrind.suppress | 33 +++++++++++-------- 5 files changed, 43 insertions(+), 30 deletions(-) diff --git a/debian/modules/control b/debian/modules/control index 86b6094..83deeab 100644 --- a/debian/modules/control +++ b/debian/modules/control @@ -13,7 +13,7 @@ Version: 1.5.3 Module: http-echo Homepage: https://github.com/agentzh/echo-nginx-module -Version: v0.61 +Version: 0.62 Files-Excluded: .gitignore .gitattributes .travis.yml Module: http-geoip2 diff --git a/debian/modules/http-echo/README.markdown b/debian/modules/http-echo/README.markdown index 71ac080..02d4608 100644 --- a/debian/modules/http-echo/README.markdown +++ b/debian/modules/http-echo/README.markdown @@ -1606,6 +1606,11 @@ Compatibility The following versions of Nginx should work with this module: +* **1.16.x** +* **1.15.x** (last tested: 1.15.8) +* **1.14.x** +* **1.13.x** (last tested: 1.13.6) +* **1.12.x** * **1.11.x** (last tested: 1.11.2) * **1.10.x** * **1.9.x** (last tested: 1.9.15) @@ -1809,7 +1814,7 @@ This wiki page is also maintained by the author himself, and everybody is encour Copyright & License =================== -Copyright (c) 2009-2017, Yichun "agentzh" Zhang (章亦春) , OpenResty Inc. +Copyright (c) 2009-2018, Yichun "agentzh" Zhang (章亦春) , OpenResty Inc. This module is licensed under the terms of the BSD license. diff --git a/debian/modules/http-echo/config b/debian/modules/http-echo/config index 32b54bf..4bf0f00 100644 --- a/debian/modules/http-echo/config +++ b/debian/modules/http-echo/config @@ -30,21 +30,24 @@ ECHO_DEPS=" \ $ngx_addon_dir/src/ngx_http_echo_foreach.h \ " -# nginx won't have HTTP_POSTPONE_FILTER_MODULE & HTTP_POSTPONE_FILTER_SRCS -# defined since 1.9.11 -if test -z "$HTTP_POSTPONE_FILTER_MODULE"; then - HTTP_POSTPONE_FILTER_MODULE=ngx_http_postpone_filter_module - HTTP_POSTPONE_FILTER_SRCS=src/http/ngx_http_postpone_filter_module.c +# nginx 1.17.0+ unconditionally enables the postpone filter +if [ ! -z "$HTTP_POSTPONE" ]; then + # nginx won't have HTTP_POSTPONE_FILTER_MODULE & HTTP_POSTPONE_FILTER_SRCS + # defined since 1.9.11 + if [ -z "$HTTP_POSTPONE_FILTER_MODULE" ]; then + HTTP_POSTPONE_FILTER_MODULE=ngx_http_postpone_filter_module + HTTP_POSTPONE_FILTER_SRCS=src/http/ngx_http_postpone_filter_module.c + fi + + # This module depends upon the postpone filter being activated + if [ "$HTTP_POSTPONE" != YES ]; then + HTTP_FILTER_MODULES="$HTTP_FILTER_MODULES $HTTP_POSTPONE_FILTER_MODULE" + HTTP_SRCS="$HTTP_SRCS $HTTP_POSTPONE_FILTER_SRCS" + HTTP_POSTPONE=YES + fi fi -# This module depends upon the postpone filter being activated -if [ $HTTP_POSTPONE != YES ]; then - HTTP_FILTER_MODULES="$HTTP_FILTER_MODULES $HTTP_POSTPONE_FILTER_MODULE" - HTTP_SRCS="$HTTP_SRCS $HTTP_POSTPONE_FILTER_SRCS" - HTTP_POSTPONE=YES -fi - -if test -n "$ngx_module_link"; then +if [ -n "$ngx_module_link" ]; then ngx_module_type=HTTP_AUX_FILTER ngx_module_name=$ngx_addon_name ngx_module_incs= diff --git a/debian/modules/http-echo/src/ngx_http_echo_util.h b/debian/modules/http-echo/src/ngx_http_echo_util.h index 24b3e15..d620d09 100644 --- a/debian/modules/http-echo/src/ngx_http_echo_util.h +++ b/debian/modules/http-echo/src/ngx_http_echo_util.h @@ -11,7 +11,7 @@ #include "ngx_http_echo_module.h" -#define ngx_http_echo_strcmp_const(a, b) \ +#define ngx_http_echo_strcmp_const(a, b) \ ngx_strncmp(a, b, sizeof(b) - 1) diff --git a/debian/modules/http-echo/valgrind.suppress b/debian/modules/http-echo/valgrind.suppress index d4bfe63..975415e 100644 --- a/debian/modules/http-echo/valgrind.suppress +++ b/debian/modules/http-echo/valgrind.suppress @@ -1,17 +1,3 @@ -{ - - Memcheck:Addr4 - fun:lj_str_new - fun:lua_setfield - fun:ngx_http_lua_cache_store_code -} -{ - - Memcheck:Addr4 - fun:lj_str_new - fun:lua_getfield - fun:ngx_http_lua_cache_load_code -} { Memcheck:Param @@ -46,3 +32,22 @@ fun:ngx_single_process_cycle fun:main } +{ + + Memcheck:Leak + match-leak-kinds: definite + fun:malloc + fun:ngx_alloc + fun:ngx_set_environment + fun:ngx_single_process_cycle +} +{ + + Memcheck:Leak + match-leak-kinds: definite + fun:malloc + fun:ngx_alloc + fun:ngx_set_environment + fun:ngx_worker_process_init + fun:ngx_worker_process_cycle +} From e5cbfb9f4badbb07dcef050c5afdd54a567b9bab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Nov=C3=BD?= Date: Tue, 15 Mar 2022 11:01:27 +0100 Subject: [PATCH 071/329] nchan: Upgrade to 1.2.15 --- debian/modules/control | 2 +- debian/modules/nchan/README.md | 107 ++- debian/modules/nchan/changelog.txt | 36 + debian/modules/nchan/config | 16 +- debian/modules/nchan/src/nchan_commands.rb | 149 +++- .../modules/nchan/src/nchan_config_commands.c | 616 +++++++++++++- debian/modules/nchan/src/nchan_defs.h | 5 +- debian/modules/nchan/src/nchan_module.c | 158 ++++ debian/modules/nchan/src/nchan_module.h | 1 + debian/modules/nchan/src/nchan_setup.c | 185 ++++- debian/modules/nchan/src/nchan_types.h | 66 ++ debian/modules/nchan/src/nchan_variables.c | 44 + debian/modules/nchan/src/nchan_version.h | 2 +- .../nchan/src/store/memory/ipc-handlers.c | 1 - .../modules/nchan/src/store/memory/memstore.c | 105 ++- .../nchan/src/store/memory/store-private.h | 4 +- .../nchan/src/store/redis/hiredis/.gitignore | 2 + .../nchan/src/store/redis/hiredis/.travis.yml | 119 ++- .../src/store/redis/hiredis/CHANGELOG.md | 258 +++++- .../nchan/src/store/redis/hiredis/Makefile | 179 +++- .../nchan/src/store/redis/hiredis/README.md | 300 ++++++- .../src/store/redis/hiredis/adapters/ae.h | 127 --- .../src/store/redis/hiredis/adapters/libev.h | 147 ---- .../store/redis/hiredis/adapters/libevent.h | 108 --- .../src/store/redis/hiredis/adapters/libuv.h | 121 --- .../nchan/src/store/redis/hiredis/alloc.c | 86 ++ .../nchan/src/store/redis/hiredis/alloc.h | 91 ++ .../nchan/src/store/redis/hiredis/async.c | 406 ++++++--- .../nchan/src/store/redis/hiredis/async.h | 18 + .../src/store/redis/hiredis/async_private.h | 75 ++ .../nchan/src/store/redis/hiredis/dict.c | 41 +- .../store/redis/hiredis/examples/example-ae.c | 62 -- .../redis/hiredis/examples/example-libev.c | 52 -- .../redis/hiredis/examples/example-libevent.c | 53 -- .../redis/hiredis/examples/example-libuv.c | 53 -- .../store/redis/hiredis/examples/example.c | 78 -- .../nchan/src/store/redis/hiredis/fmacros.h | 17 +- .../nchan/src/store/redis/hiredis/hiredis.c | 513 ++++++++---- .../nchan/src/store/redis/hiredis/hiredis.h | 179 +++- .../src/store/redis/hiredis/hiredis_ssl.h | 127 +++ .../nchan/src/store/redis/hiredis/net.c | 324 ++++++-- .../nchan/src/store/redis/hiredis/net.h | 9 +- .../nchan/src/store/redis/hiredis/read.c | 392 +++++++-- .../nchan/src/store/redis/hiredis/read.h | 37 +- .../nchan/src/store/redis/hiredis/sds.c | 555 +++++++++---- .../nchan/src/store/redis/hiredis/sds.h | 207 ++++- .../nchan/src/store/redis/hiredis/sdsalloc.h | 44 + .../src/store/redis/hiredis/sockcompat.c | 248 ++++++ .../src/store/redis/hiredis/sockcompat.h | 92 +++ .../nchan/src/store/redis/hiredis/ssl.c | 526 ++++++++++++ .../nchan/src/store/redis/hiredis/test.c | 782 +++++++++++++++--- .../nchan/src/store/redis/hiredis/win32.h | 18 +- .../modules/nchan/src/store/redis/rdsstore.c | 201 ++++- .../get_subscriber_info_id.lua | 18 + .../request_subscriber_info.lua | 15 + .../src/store/redis/redis_lua_commands.c | 39 +- .../src/store/redis/redis_lua_commands.h | 15 +- .../src/store/redis/redis_nginx_adapter.c | 100 +-- .../src/store/redis/redis_nginx_adapter.h | 8 +- .../nchan/src/store/redis/redis_nodeset.c | 601 ++++++++++++-- .../nchan/src/store/redis/redis_nodeset.h | 71 +- .../redis/scripts/get_unique_request_id.lua | 1 + .../nchan/src/store/redis/store-private.h | 2 + debian/modules/nchan/src/store/redis/store.h | 1 + debian/modules/nchan/src/subscribers/common.c | 52 +- debian/modules/nchan/src/subscribers/common.h | 3 +- .../nchan/src/subscribers/http-raw-stream.c | 30 +- .../modules/nchan/src/subscribers/internal.c | 38 +- .../modules/nchan/src/subscribers/internal.h | 6 +- .../nchan/src/subscribers/longpoll-private.h | 6 +- .../modules/nchan/src/subscribers/longpoll.c | 42 +- .../nchan/src/subscribers/memstore_ipc.c | 3 +- .../nchan/src/subscribers/memstore_multi.c | 3 + .../nchan/src/subscribers/memstore_redis.c | 4 + .../modules/nchan/src/subscribers/websocket.c | 38 +- .../modules/nchan/src/util/nchan_channel_id.c | 36 + .../modules/nchan/src/util/nchan_channel_id.h | 2 + .../nchan/src/util/nchan_fake_request.c | 6 +- .../nchan/src/util/nchan_output_info.c | 21 +- debian/modules/nchan/src/util/nchan_util.c | 57 ++ debian/modules/nchan/src/util/nchan_util.h | 5 +- 81 files changed, 7374 insertions(+), 1993 deletions(-) delete mode 100644 debian/modules/nchan/src/store/redis/hiredis/adapters/ae.h delete mode 100644 debian/modules/nchan/src/store/redis/hiredis/adapters/libev.h delete mode 100644 debian/modules/nchan/src/store/redis/hiredis/adapters/libevent.h delete mode 100644 debian/modules/nchan/src/store/redis/hiredis/adapters/libuv.h create mode 100644 debian/modules/nchan/src/store/redis/hiredis/alloc.c create mode 100644 debian/modules/nchan/src/store/redis/hiredis/alloc.h create mode 100644 debian/modules/nchan/src/store/redis/hiredis/async_private.h delete mode 100644 debian/modules/nchan/src/store/redis/hiredis/examples/example-ae.c delete mode 100644 debian/modules/nchan/src/store/redis/hiredis/examples/example-libev.c delete mode 100644 debian/modules/nchan/src/store/redis/hiredis/examples/example-libevent.c delete mode 100644 debian/modules/nchan/src/store/redis/hiredis/examples/example-libuv.c delete mode 100644 debian/modules/nchan/src/store/redis/hiredis/examples/example.c create mode 100644 debian/modules/nchan/src/store/redis/hiredis/hiredis_ssl.h create mode 100644 debian/modules/nchan/src/store/redis/hiredis/sdsalloc.h create mode 100644 debian/modules/nchan/src/store/redis/hiredis/sockcompat.c create mode 100644 debian/modules/nchan/src/store/redis/hiredis/sockcompat.h create mode 100644 debian/modules/nchan/src/store/redis/hiredis/ssl.c create mode 100644 debian/modules/nchan/src/store/redis/redis-lua-scripts/get_subscriber_info_id.lua create mode 100644 debian/modules/nchan/src/store/redis/redis-lua-scripts/request_subscriber_info.lua create mode 100644 debian/modules/nchan/src/store/redis/scripts/get_unique_request_id.lua diff --git a/debian/modules/control b/debian/modules/control index 83deeab..2fe5622 100644 --- a/debian/modules/control +++ b/debian/modules/control @@ -38,7 +38,7 @@ Patch: Module: nchan Homepage: https://github.com/slact/nchan -Version: 1.2.7 +Version: 1.2.15 Files-Excluded: dev nchan_logo.png NchanSubscriber.js src/hiredis nchan Module: http-uploadprogress diff --git a/debian/modules/nchan/README.md b/debian/modules/nchan/README.md index 152396d..f1c2a4d 100644 --- a/debian/modules/nchan/README.md +++ b/debian/modules/nchan/README.md @@ -22,7 +22,7 @@ In a web browser, you can use Websocket or EventSource natively, or the [NchanSu ## Status and History -The latest Nchan release is 1.2.7 (March 17, 2020) ([changelog](https://nchan.io/changelog)). +The latest Nchan release is 1.2.15 (December 27, 2021) ([changelog](https://nchan.io/changelog)). The first iteration of Nchan was written in 2009-2010 as the [Nginx HTTP Push Module](https://pushmodule.slact.net), and was vastly refactored into its present state in 2014-2016. @@ -704,6 +704,14 @@ Redis Cluster connections are designed to be resilient and try to recover from e All Nchan servers sharing a Redis server or cluster should have their times synchronized (via ntpd or your favorite ntp daemon). Failure to do so may result in missed or duplicate messages. +#### Using Redis securely + +Redis servers can be connected to via TLS by using the [nchan_redis_ssl](#nchan_redis_ssl) config setting in an `upstream` block, or by using the `rediss://` schema for the server URLs. + +A password and optional username for the `AUTH` command can be set by the [nchan_redis_username](#nchan_redis_username) and [nchan_redis_password](#nchan_redis_password) config settings in an `upstream` block, or by using the `redis://:@hostname` server URL schema. + +Note that autodiscovered Redis nodes inherit their parent's SSL, username, and password settings. + #### Tweaks and Optimizations As of version 1.2.0, Nchan uses Redis slaves to load-balance PUBSUB traffic. By default, there is an equal chance that a channel's PUBSUB subscription will go to any master or slave. The [`nchan_redis_subscribe_weights`](#nchan_redis_subscribe_weights) setting is available to fine-tune this load-balancing. @@ -1003,16 +1011,25 @@ Nchan makes several variables usabled in the config file: - `$nchan_subscriber_type` For subscriber locations, this variable is set to the subscriber type (websocket, longpoll, etc.). +- `$nchan_channel_subscriber_last_seen` + For publisher locations, this variable is set to the timestamp for the last connected subscriber. + +- `$nchan_channel_subscriber_count` + For publisher locations, this variable is set to the number of subscribers in the published channel. + +- `$nchan_channel_message_count` + For publisher locations, this variable is set to the number of messages buffered in the published channel. + - `$nchan_publisher_type` For publisher locations, this variable is set to the subscriber type (http or websocket). -- `$nchan_prev_message_id`, `$nchan_message_id` +- `$nchan_prev_message_id`, `$nchan_message_id` The current and previous (if applicable) message id for publisher request or subscriber response. -- `$nchan_channel_event` +- `$nchan_channel_event` For channel events, this is the event name. Useful when configuring `nchan_channel_event_string`. -- `$nchan_version` +- `$nchan_version` Current Nchan version. Available since 1.1.5. Additionally, `nchan_stub_status` data is also exposed as variables. These are available only when `nchan_stub_status` is enabled on at least one location: @@ -1180,7 +1197,18 @@ Additionally, `nchan_stub_status` data is also exposed as variables. These are a arguments: 1 default: `\n` context: server, location, if - > Message separator string for the http-raw-stream subscriber. Automatically terminated with a newline character. + > Message separator string for the http-raw-stream subscriber. Automatically terminated with a newline character if not explicitly set to an empty string. + +- **nchan_subscriber_info** + arguments: 0 + context: location + > A subscriber location for debugging the state of subscribers on a given channel. The subscribers of the channel specified by `nchan_channel_id` evaluate `nchan_subscriber_info_string` and send it back to the requested on this location. This is useful to see where subscribers are in an Nchan cluster, as well as debugging subscriber connection issues. + +- **nchan_subscriber_info_string** + arguments: 1 + default: `$nchan_subscriber_type $remote_addr:$remote_port $http_user_agent $server_name $request_uri $pid` + context: server, location + > this string is evaluated by each subscriber on a given channel and sent to the requester of a `nchan_subscriber_info` location - **nchan_subscriber_last_message_id** arguments: 1 - 5 @@ -1327,12 +1355,23 @@ Additionally, `nchan_stub_status` data is also exposed as variables. These are a legacy name: push_message_timeout > Publisher configuration setting the length of time a message may be queued before it is considered expired. If you do not want messages to expire, set this to 0. Note that messages always expire from oldest to newest, so an older message may prevent a newer one with a shorter timeout from expiring. An Nginx variable can also be used to set the timeout dynamically. +- **nchan_redis_cluster_check_interval** + arguments: 1 + default: `5s` + context: http, server, upstream, location + > Send a CLUSTER INFO command to each connected Redis node to see if the cluster config epoch has changed. Sent only when in Cluster mode and if any other command that may result in a MOVE error has not been sent in the configured time. + - **nchan_redis_connect_timeout** arguments: 1 default: `600ms` context: upstream > Redis server connection timeout. +- **nchan_redis_discovered_ip_range_blacklist** `` + arguments: 1 - 7 + context: upstream + > do not attempt to connect to **autodiscovered** nodes with IPs in the specified ranges. Useful for blacklisting private network ranges for clusters and Redis slaves. NOTE that this blacklist applies only to autodiscovered nodes, and not ones specified in the upstream block + - **nchan_redis_idle_channel_cache_timeout** ` - - - - - - - - - - - - - - - - - - - - - - - - - - - #cccccc - #dddddd - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - d - - - - h - - - - m - - - s - - - - - - - - - - - - - T - - - G - - - M - - K - - - - b - B - - /s - - - - - - active - idle - - - - - - - publishing - playing - - - - - - - - - #cccccc - #eeeeee - - - - - - - - - - - - - - - - - publishing - - - - active - - - - x - - - diff --git a/debian/modules/watch/http-ndk b/debian/modules/watch/http-ndk deleted file mode 100644 index f359136..0000000 --- a/debian/modules/watch/http-ndk +++ /dev/null @@ -1,4 +0,0 @@ -version=4 -opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%libnginx-mod-http-ndk-$1.tar.gz%" \ - https://github.com/simpl/ngx_devel_kit/tags \ - (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/ngxmod uupdate http-ndk diff --git a/debian/modules/watch/nchan b/debian/modules/watch/nchan deleted file mode 100644 index 199ab19..0000000 --- a/debian/modules/watch/nchan +++ /dev/null @@ -1,4 +0,0 @@ -version=4 -opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%libnginx-mod-nchan-$1.tar.gz%" \ - https://github.com/slact/nchan/tags \ - (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/ngxmod uupdate nchan diff --git a/debian/modules/watch/rtmp b/debian/modules/watch/rtmp deleted file mode 100644 index 2a95f4c..0000000 --- a/debian/modules/watch/rtmp +++ /dev/null @@ -1,4 +0,0 @@ -version=4 -opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%libnginx-mod-rtmp-$1.tar.gz%" \ - https://github.com/arut/nginx-rtmp-module/tags \ - (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/ngxmod uupdate rtmp From 34bfbac550a6891b2f24b4a5cd673af7ef594326 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Thu, 8 Dec 2022 14:23:55 +0100 Subject: [PATCH 186/329] release nginx 1.22.1-4, upload to unstable --- debian/changelog | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index d2cc473..78577de 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -nginx (1.22.1-4) UNRELEASED; urgency=medium +nginx (1.22.1-4) unstable; urgency=medium * d/t/*-module-deps: updated, added curl timeout 300 seconds and added nginx restart before calling curl @@ -13,7 +13,7 @@ nginx (1.22.1-4) UNRELEASED; urgency=medium - libnginx-mod-rtmp module - libnginx-mod-http-ndk module - -- Jan Mojžíš Thu, 08 Dec 2022 09:47:06 +0100 + -- Jan Mojžíš Thu, 08 Dec 2022 14:15:15 +0100 nginx (1.22.1-3) unstable; urgency=medium From 10a2613f37460f80f787898875bf064d4e8ba53e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Fri, 9 Dec 2022 16:20:40 +0100 Subject: [PATCH 187/329] remove 3th party modules --- debian/changelog | 17 + debian/control | 150 +- debian/copyright | 78 - debian/libnginx-mod-http-auth-pam.nginx | 13 - debian/libnginx-mod-http-cache-purge.nginx | 13 - debian/libnginx-mod-http-dav-ext.nginx | 13 - debian/libnginx-mod-http-echo.nginx | 13 - debian/libnginx-mod-http-fancyindex.nginx | 13 - debian/libnginx-mod-http-geoip2.nginx | 13 - ...ibnginx-mod-http-headers-more-filter.nginx | 13 - debian/libnginx-mod-http-subs-filter.nginx | 13 - debian/libnginx-mod-http-uploadprogress.nginx | 13 - debian/libnginx-mod-http-upstream-fair.nginx | 13 - debian/libnginx-mod-stream-geoip2.nginx | 13 - .../libnginx-mod.conf/mod-http-auth-pam.conf | 1 - .../mod-http-cache-purge.conf | 1 - .../libnginx-mod.conf/mod-http-dav-ext.conf | 1 - debian/libnginx-mod.conf/mod-http-echo.conf | 1 - .../mod-http-fancyindex.conf | 1 - debian/libnginx-mod.conf/mod-http-geoip2.conf | 1 - .../mod-http-headers-more-filter.conf | 1 - .../mod-http-subs-filter.conf | 1 - .../mod-http-uploadprogress.conf | 1 - .../mod-http-upstream-fair.conf | 1 - .../libnginx-mod.conf/mod-stream-geoip2.conf | 1 - debian/modules/control | 52 - debian/modules/http-auth-pam/ChangeLog | 63 - debian/modules/http-auth-pam/LICENSE | 25 - debian/modules/http-auth-pam/README.md | 95 - debian/modules/http-auth-pam/VERSION | 1 - debian/modules/http-auth-pam/config | 17 - .../http-auth-pam/ngx_http_auth_pam_module.c | 482 ---- debian/modules/http-cache-purge/CHANGES | 66 - debian/modules/http-cache-purge/LICENSE | 26 - debian/modules/http-cache-purge/README.md | 171 -- debian/modules/http-cache-purge/TODO.md | 7 - debian/modules/http-cache-purge/config | 21 - .../http-cache-purge/ngx_cache_purge_module.c | 1803 -------------- debian/modules/http-cache-purge/t/proxy1.t | 136 - .../modules/http-cache-purge/t/proxy1_vars.t | 138 -- debian/modules/http-cache-purge/t/proxy2.t | 349 --- .../modules/http-cache-purge/t/proxy2_vars.t | 353 --- debian/modules/http-dav-ext/LICENSE | 22 - debian/modules/http-dav-ext/README.rst | 188 -- debian/modules/http-dav-ext/config | 17 - .../http-dav-ext/ngx_http_dav_ext_module.c | 2181 ----------------- debian/modules/http-dav-ext/t/dav_ext.t | 141 -- debian/modules/http-echo/LICENSE | 25 - debian/modules/http-echo/README.markdown | 1851 -------------- debian/modules/http-echo/config | 63 - debian/modules/http-echo/src/ddebug.h | 114 - .../http-echo/src/ngx_http_echo_echo.c | 342 --- .../http-echo/src/ngx_http_echo_echo.h | 25 - .../http-echo/src/ngx_http_echo_filter.c | 282 --- .../http-echo/src/ngx_http_echo_filter.h | 15 - .../http-echo/src/ngx_http_echo_foreach.c | 183 -- .../http-echo/src/ngx_http_echo_foreach.h | 16 - .../http-echo/src/ngx_http_echo_handler.c | 429 ---- .../http-echo/src/ngx_http_echo_handler.h | 18 - .../http-echo/src/ngx_http_echo_location.c | 178 -- .../http-echo/src/ngx_http_echo_location.h | 13 - .../http-echo/src/ngx_http_echo_module.c | 682 ------ .../http-echo/src/ngx_http_echo_module.h | 151 -- .../src/ngx_http_echo_request_info.c | 522 ---- .../src/ngx_http_echo_request_info.h | 36 - .../http-echo/src/ngx_http_echo_sleep.c | 208 -- .../http-echo/src/ngx_http_echo_sleep.h | 16 - .../http-echo/src/ngx_http_echo_subrequest.c | 791 ------ .../http-echo/src/ngx_http_echo_subrequest.h | 19 - .../http-echo/src/ngx_http_echo_timer.c | 95 - .../http-echo/src/ngx_http_echo_timer.h | 13 - .../http-echo/src/ngx_http_echo_util.c | 302 --- .../http-echo/src/ngx_http_echo_util.h | 58 - .../modules/http-echo/src/ngx_http_echo_var.c | 110 - .../modules/http-echo/src/ngx_http_echo_var.h | 9 - debian/modules/http-echo/t/abort-parent.t | 63 - debian/modules/http-echo/t/blocking-sleep.t | 156 -- debian/modules/http-echo/t/echo-after-body.t | 261 -- debian/modules/http-echo/t/echo-before-body.t | 278 --- debian/modules/http-echo/t/echo-duplicate.t | 89 - debian/modules/http-echo/t/echo-timer.t | 107 - debian/modules/http-echo/t/echo.t | 416 ---- debian/modules/http-echo/t/exec.t | 228 -- debian/modules/http-echo/t/filter-used.t | 59 - debian/modules/http-echo/t/foreach-split.t | 283 --- debian/modules/http-echo/t/gzip.t | 31 - debian/modules/http-echo/t/if.t | 150 -- debian/modules/http-echo/t/incr.t | 32 - debian/modules/http-echo/t/location-async.t | 439 ---- debian/modules/http-echo/t/location.t | 567 ----- debian/modules/http-echo/t/mixed.t | 82 - debian/modules/http-echo/t/request-body.t | 58 - debian/modules/http-echo/t/request-info.t | 841 ------- debian/modules/http-echo/t/sleep.t | 200 -- debian/modules/http-echo/t/status.t | 142 -- debian/modules/http-echo/t/subrequest-async.t | 604 ----- debian/modules/http-echo/t/subrequest.t | 725 ------ debian/modules/http-echo/t/unused.t | 119 - debian/modules/http-echo/util/build.sh | 44 - debian/modules/http-echo/util/releng | 8 - debian/modules/http-echo/util/wiki2pod.pl | 131 - debian/modules/http-echo/valgrind.suppress | 53 - .../http-fancyindex/.github/workflows/ci.yml | 40 - debian/modules/http-fancyindex/CHANGELOG.md | 199 -- debian/modules/http-fancyindex/HACKING.md | 29 - debian/modules/http-fancyindex/LICENSE | 20 - debian/modules/http-fancyindex/README.rst | 319 --- debian/modules/http-fancyindex/config | 20 - .../ngx_http_fancyindex_module.c | 1615 ------------ .../http-fancyindex/t/00-build-artifacts.test | 22 - .../http-fancyindex/t/01-smoke-hasindex.test | 7 - .../t/02-smoke-indexisfancy.test | 11 - .../http-fancyindex/t/03-exact_size_off.test | 8 - .../http-fancyindex/t/04-hasindex-html.test | 24 - .../http-fancyindex/t/05-sort-by-size.test | 36 - .../http-fancyindex/t/06-hide_parent.test | 23 - .../http-fancyindex/t/07-directory-first.test | 50 - .../http-fancyindex/t/07-show_dotfiles.test | 21 - .../http-fancyindex/t/08-local-footer.test | 17 - .../http-fancyindex/t/09-local-header.test | 17 - .../t/10-local-headerfooter.test | 26 - .../t/11-local-footer-nested.test | 31 - .../t/12-local-footer-nested.test | 11 - .../t/bug61-empty-file-segfault.test | 16 - .../t/bug95-square-brackets.test | 19 - .../modules/http-fancyindex/t/build-and-run | 25 - .../t/child-directory/empty-file.txt | 0 debian/modules/http-fancyindex/t/get-pup | 81 - .../modules/http-fancyindex/t/has-index.test | 7 - .../http-fancyindex/t/has-index/index.html | 10 - debian/modules/http-fancyindex/t/nginx.conf | 25 - debian/modules/http-fancyindex/t/preamble | 111 - debian/modules/http-fancyindex/t/run | 86 - .../http-fancyindex/t/show_dotfiles/.okay | 0 debian/modules/http-fancyindex/template.awk | 52 - debian/modules/http-fancyindex/template.h | 94 - debian/modules/http-fancyindex/template.html | 93 - debian/modules/http-geoip2/LICENSE | 23 - debian/modules/http-geoip2/README.md | 133 - debian/modules/http-geoip2/config | 43 - .../http-geoip2/ngx_http_geoip2_module.c | 793 ------ .../http-geoip2/ngx_stream_geoip2_module.c | 694 ------ .../http-headers-more-filter/README.markdown | 549 ----- .../modules/http-headers-more-filter/config | 32 - .../http-headers-more-filter/src/ddebug.h | 124 - .../src/ngx_http_headers_more_filter_module.c | 348 --- .../src/ngx_http_headers_more_filter_module.h | 80 - .../src/ngx_http_headers_more_headers_in.c | 899 ------- .../src/ngx_http_headers_more_headers_in.h | 26 - .../src/ngx_http_headers_more_headers_out.c | 716 ------ .../src/ngx_http_headers_more_headers_out.h | 26 - .../src/ngx_http_headers_more_util.c | 380 --- .../src/ngx_http_headers_more_util.h | 52 - .../modules/http-headers-more-filter/t/bug.t | 393 --- .../http-headers-more-filter/t/builtin.t | 338 --- .../modules/http-headers-more-filter/t/eval.t | 36 - .../http-headers-more-filter/t/input-conn.t | 137 -- .../http-headers-more-filter/t/input-cookie.t | 183 -- .../http-headers-more-filter/t/input-ua.t | 628 ----- .../http-headers-more-filter/t/input.t | 1331 ---------- .../http-headers-more-filter/t/phase.t | 25 - .../http-headers-more-filter/t/sanity.t | 567 ----- .../http-headers-more-filter/t/subrequest.t | 68 - .../http-headers-more-filter/t/unused.t | 174 -- .../modules/http-headers-more-filter/t/vars.t | 58 - .../http-headers-more-filter/util/build.sh | 33 - .../valgrind.suppress | 135 - debian/modules/http-subs-filter/CHANGES | 37 - debian/modules/http-subs-filter/README | 141 -- debian/modules/http-subs-filter/config | 3 - .../doc/README.google_code_home_page.wiki | 120 - .../modules/http-subs-filter/doc/README.html | 199 -- .../modules/http-subs-filter/doc/README.wiki | 123 - .../ngx_http_subs_filter_module.c | 1298 ---------- debian/modules/http-subs-filter/test/README | 275 --- .../test/inc/Module/AutoInstall.pm | 820 ------- .../test/inc/Module/Install.pm | 470 ---- .../test/inc/Module/Install/AutoInstall.pm | 82 - .../test/inc/Module/Install/Base.pm | 83 - .../test/inc/Module/Install/Can.pm | 81 - .../test/inc/Module/Install/Fetch.pm | 93 - .../test/inc/Module/Install/Include.pm | 34 - .../test/inc/Module/Install/Makefile.pm | 415 ---- .../test/inc/Module/Install/Metadata.pm | 716 ------ .../test/inc/Module/Install/TestBase.pm | 29 - .../test/inc/Module/Install/Win32.pm | 64 - .../test/inc/Module/Install/WriteAll.pm | 63 - .../http-subs-filter/test/inc/Spiffy.pm | 539 ---- .../http-subs-filter/test/inc/Test/Base.pm | 682 ------ .../test/inc/Test/Base/Filter.pm | 341 --- .../http-subs-filter/test/inc/Test/Builder.pm | 1413 ----------- .../test/inc/Test/Builder/Module.pm | 81 - .../http-subs-filter/test/inc/Test/More.pm | 735 ------ .../http-subs-filter/test/lib/Test/Nginx.pm | 315 --- .../test/lib/Test/Nginx/LWP.pm | 524 ---- .../test/lib/Test/Nginx/Socket.pm | 1749 ------------- .../test/lib/Test/Nginx/Util.pm | 874 ------- debian/modules/http-subs-filter/test/t/subs.t | 136 - .../http-subs-filter/test/t/subs_capture.t | 32 - .../http-subs-filter/test/t/subs_fix_string.t | 32 - .../http-subs-filter/test/t/subs_regex.t | 108 - .../http-subs-filter/test/t/subs_types.t | 59 - debian/modules/http-subs-filter/test/test.sh | 5 - .../http-subs-filter/util/update-readme.sh | 7 - .../util/wiki2google_code_homepage.pl | 29 - .../modules/http-subs-filter/util/wiki2pod.pl | 129 - debian/modules/http-uploadprogress/CHANGES | 111 - debian/modules/http-uploadprogress/LICENSE | 25 - debian/modules/http-uploadprogress/Makefile | 8 - debian/modules/http-uploadprogress/README | 329 --- debian/modules/http-uploadprogress/config | 11 - .../ngx_http_uploadprogress_module.c | 1774 -------------- .../http-uploadprogress/test/client.sh | 8 - .../http-uploadprogress/test/stress.sh | 41 - debian/modules/http-upstream-fair/.gdbinit | 39 - debian/modules/http-upstream-fair/README | 53 - debian/modules/http-upstream-fair/config | 3 - .../ngx_http_upstream_fair_module.c | 1356 ---------- .../http-cache-purge/dynamic-module.patch | 34 - .../http-cache-purge/segfault-1.11.6.patch | 25 - .../modules/patches/http-cache-purge/series | 2 - .../http-subs-filter/dynamic-module.patch | 32 - .../patches/http-subs-filter/pcre2.patch | 24 - .../modules/patches/http-subs-filter/series | 2 - .../drop-default-port.patch | 37 - .../http-upstream-fair/dynamic-module.patch | 29 - .../http-upstream-fair/openssl-1.1.0.patch | 50 - .../modules/patches/http-upstream-fair/series | 3 - debian/modules/watch/http-auth-pam | 4 - debian/modules/watch/http-cache-purge | 4 - debian/modules/watch/http-dav-ext | 4 - debian/modules/watch/http-echo | 4 - debian/modules/watch/http-fancyindex | 4 - debian/modules/watch/http-geoip2 | 4 - debian/modules/watch/http-headers-more-filter | 4 - debian/modules/watch/http-lua | 4 - debian/modules/watch/http-subs-filter | 4 - debian/modules/watch/http-uploadprogress | 4 - debian/ngxmod | 222 -- debian/rules | 46 +- 240 files changed, 33 insertions(+), 48881 deletions(-) delete mode 100755 debian/libnginx-mod-http-auth-pam.nginx delete mode 100755 debian/libnginx-mod-http-cache-purge.nginx delete mode 100755 debian/libnginx-mod-http-dav-ext.nginx delete mode 100755 debian/libnginx-mod-http-echo.nginx delete mode 100755 debian/libnginx-mod-http-fancyindex.nginx delete mode 100755 debian/libnginx-mod-http-geoip2.nginx delete mode 100755 debian/libnginx-mod-http-headers-more-filter.nginx delete mode 100755 debian/libnginx-mod-http-subs-filter.nginx delete mode 100755 debian/libnginx-mod-http-uploadprogress.nginx delete mode 100755 debian/libnginx-mod-http-upstream-fair.nginx delete mode 100755 debian/libnginx-mod-stream-geoip2.nginx delete mode 100644 debian/libnginx-mod.conf/mod-http-auth-pam.conf delete mode 100644 debian/libnginx-mod.conf/mod-http-cache-purge.conf delete mode 100644 debian/libnginx-mod.conf/mod-http-dav-ext.conf delete mode 100644 debian/libnginx-mod.conf/mod-http-echo.conf delete mode 100644 debian/libnginx-mod.conf/mod-http-fancyindex.conf delete mode 100644 debian/libnginx-mod.conf/mod-http-geoip2.conf delete mode 100644 debian/libnginx-mod.conf/mod-http-headers-more-filter.conf delete mode 100644 debian/libnginx-mod.conf/mod-http-subs-filter.conf delete mode 100644 debian/libnginx-mod.conf/mod-http-uploadprogress.conf delete mode 100644 debian/libnginx-mod.conf/mod-http-upstream-fair.conf delete mode 100644 debian/libnginx-mod.conf/mod-stream-geoip2.conf delete mode 100644 debian/modules/control delete mode 100644 debian/modules/http-auth-pam/ChangeLog delete mode 100644 debian/modules/http-auth-pam/LICENSE delete mode 100644 debian/modules/http-auth-pam/README.md delete mode 100644 debian/modules/http-auth-pam/VERSION delete mode 100644 debian/modules/http-auth-pam/config delete mode 100644 debian/modules/http-auth-pam/ngx_http_auth_pam_module.c delete mode 100644 debian/modules/http-cache-purge/CHANGES delete mode 100644 debian/modules/http-cache-purge/LICENSE delete mode 100644 debian/modules/http-cache-purge/README.md delete mode 100644 debian/modules/http-cache-purge/TODO.md delete mode 100644 debian/modules/http-cache-purge/config delete mode 100644 debian/modules/http-cache-purge/ngx_cache_purge_module.c delete mode 100644 debian/modules/http-cache-purge/t/proxy1.t delete mode 100644 debian/modules/http-cache-purge/t/proxy1_vars.t delete mode 100644 debian/modules/http-cache-purge/t/proxy2.t delete mode 100644 debian/modules/http-cache-purge/t/proxy2_vars.t delete mode 100644 debian/modules/http-dav-ext/LICENSE delete mode 100644 debian/modules/http-dav-ext/README.rst delete mode 100644 debian/modules/http-dav-ext/config delete mode 100644 debian/modules/http-dav-ext/ngx_http_dav_ext_module.c delete mode 100644 debian/modules/http-dav-ext/t/dav_ext.t delete mode 100644 debian/modules/http-echo/LICENSE delete mode 100644 debian/modules/http-echo/README.markdown delete mode 100644 debian/modules/http-echo/config delete mode 100644 debian/modules/http-echo/src/ddebug.h delete mode 100644 debian/modules/http-echo/src/ngx_http_echo_echo.c delete mode 100644 debian/modules/http-echo/src/ngx_http_echo_echo.h delete mode 100644 debian/modules/http-echo/src/ngx_http_echo_filter.c delete mode 100644 debian/modules/http-echo/src/ngx_http_echo_filter.h delete mode 100644 debian/modules/http-echo/src/ngx_http_echo_foreach.c delete mode 100644 debian/modules/http-echo/src/ngx_http_echo_foreach.h delete mode 100644 debian/modules/http-echo/src/ngx_http_echo_handler.c delete mode 100644 debian/modules/http-echo/src/ngx_http_echo_handler.h delete mode 100644 debian/modules/http-echo/src/ngx_http_echo_location.c delete mode 100644 debian/modules/http-echo/src/ngx_http_echo_location.h delete mode 100644 debian/modules/http-echo/src/ngx_http_echo_module.c delete mode 100644 debian/modules/http-echo/src/ngx_http_echo_module.h delete mode 100644 debian/modules/http-echo/src/ngx_http_echo_request_info.c delete mode 100644 debian/modules/http-echo/src/ngx_http_echo_request_info.h delete mode 100644 debian/modules/http-echo/src/ngx_http_echo_sleep.c delete mode 100644 debian/modules/http-echo/src/ngx_http_echo_sleep.h delete mode 100644 debian/modules/http-echo/src/ngx_http_echo_subrequest.c delete mode 100644 debian/modules/http-echo/src/ngx_http_echo_subrequest.h delete mode 100644 debian/modules/http-echo/src/ngx_http_echo_timer.c delete mode 100644 debian/modules/http-echo/src/ngx_http_echo_timer.h delete mode 100644 debian/modules/http-echo/src/ngx_http_echo_util.c delete mode 100644 debian/modules/http-echo/src/ngx_http_echo_util.h delete mode 100644 debian/modules/http-echo/src/ngx_http_echo_var.c delete mode 100644 debian/modules/http-echo/src/ngx_http_echo_var.h delete mode 100644 debian/modules/http-echo/t/abort-parent.t delete mode 100644 debian/modules/http-echo/t/blocking-sleep.t delete mode 100644 debian/modules/http-echo/t/echo-after-body.t delete mode 100644 debian/modules/http-echo/t/echo-before-body.t delete mode 100644 debian/modules/http-echo/t/echo-duplicate.t delete mode 100644 debian/modules/http-echo/t/echo-timer.t delete mode 100644 debian/modules/http-echo/t/echo.t delete mode 100644 debian/modules/http-echo/t/exec.t delete mode 100644 debian/modules/http-echo/t/filter-used.t delete mode 100644 debian/modules/http-echo/t/foreach-split.t delete mode 100644 debian/modules/http-echo/t/gzip.t delete mode 100644 debian/modules/http-echo/t/if.t delete mode 100644 debian/modules/http-echo/t/incr.t delete mode 100644 debian/modules/http-echo/t/location-async.t delete mode 100644 debian/modules/http-echo/t/location.t delete mode 100644 debian/modules/http-echo/t/mixed.t delete mode 100644 debian/modules/http-echo/t/request-body.t delete mode 100644 debian/modules/http-echo/t/request-info.t delete mode 100644 debian/modules/http-echo/t/sleep.t delete mode 100644 debian/modules/http-echo/t/status.t delete mode 100644 debian/modules/http-echo/t/subrequest-async.t delete mode 100644 debian/modules/http-echo/t/subrequest.t delete mode 100644 debian/modules/http-echo/t/unused.t delete mode 100755 debian/modules/http-echo/util/build.sh delete mode 100755 debian/modules/http-echo/util/releng delete mode 100644 debian/modules/http-echo/util/wiki2pod.pl delete mode 100644 debian/modules/http-echo/valgrind.suppress delete mode 100644 debian/modules/http-fancyindex/.github/workflows/ci.yml delete mode 100644 debian/modules/http-fancyindex/CHANGELOG.md delete mode 100644 debian/modules/http-fancyindex/HACKING.md delete mode 100644 debian/modules/http-fancyindex/LICENSE delete mode 100644 debian/modules/http-fancyindex/README.rst delete mode 100644 debian/modules/http-fancyindex/config delete mode 100644 debian/modules/http-fancyindex/ngx_http_fancyindex_module.c delete mode 100644 debian/modules/http-fancyindex/t/00-build-artifacts.test delete mode 100644 debian/modules/http-fancyindex/t/01-smoke-hasindex.test delete mode 100644 debian/modules/http-fancyindex/t/02-smoke-indexisfancy.test delete mode 100644 debian/modules/http-fancyindex/t/03-exact_size_off.test delete mode 100644 debian/modules/http-fancyindex/t/04-hasindex-html.test delete mode 100644 debian/modules/http-fancyindex/t/05-sort-by-size.test delete mode 100644 debian/modules/http-fancyindex/t/06-hide_parent.test delete mode 100644 debian/modules/http-fancyindex/t/07-directory-first.test delete mode 100644 debian/modules/http-fancyindex/t/07-show_dotfiles.test delete mode 100644 debian/modules/http-fancyindex/t/08-local-footer.test delete mode 100644 debian/modules/http-fancyindex/t/09-local-header.test delete mode 100644 debian/modules/http-fancyindex/t/10-local-headerfooter.test delete mode 100644 debian/modules/http-fancyindex/t/11-local-footer-nested.test delete mode 100644 debian/modules/http-fancyindex/t/12-local-footer-nested.test delete mode 100644 debian/modules/http-fancyindex/t/bug61-empty-file-segfault.test delete mode 100644 debian/modules/http-fancyindex/t/bug95-square-brackets.test delete mode 100755 debian/modules/http-fancyindex/t/build-and-run delete mode 100644 debian/modules/http-fancyindex/t/child-directory/empty-file.txt delete mode 100755 debian/modules/http-fancyindex/t/get-pup delete mode 100644 debian/modules/http-fancyindex/t/has-index.test delete mode 100644 debian/modules/http-fancyindex/t/has-index/index.html delete mode 100644 debian/modules/http-fancyindex/t/nginx.conf delete mode 100644 debian/modules/http-fancyindex/t/preamble delete mode 100755 debian/modules/http-fancyindex/t/run delete mode 100644 debian/modules/http-fancyindex/t/show_dotfiles/.okay delete mode 100755 debian/modules/http-fancyindex/template.awk delete mode 100644 debian/modules/http-fancyindex/template.h delete mode 100644 debian/modules/http-fancyindex/template.html delete mode 100644 debian/modules/http-geoip2/LICENSE delete mode 100644 debian/modules/http-geoip2/README.md delete mode 100644 debian/modules/http-geoip2/config delete mode 100644 debian/modules/http-geoip2/ngx_http_geoip2_module.c delete mode 100644 debian/modules/http-geoip2/ngx_stream_geoip2_module.c delete mode 100644 debian/modules/http-headers-more-filter/README.markdown delete mode 100644 debian/modules/http-headers-more-filter/config delete mode 100644 debian/modules/http-headers-more-filter/src/ddebug.h delete mode 100644 debian/modules/http-headers-more-filter/src/ngx_http_headers_more_filter_module.c delete mode 100644 debian/modules/http-headers-more-filter/src/ngx_http_headers_more_filter_module.h delete mode 100644 debian/modules/http-headers-more-filter/src/ngx_http_headers_more_headers_in.c delete mode 100644 debian/modules/http-headers-more-filter/src/ngx_http_headers_more_headers_in.h delete mode 100644 debian/modules/http-headers-more-filter/src/ngx_http_headers_more_headers_out.c delete mode 100644 debian/modules/http-headers-more-filter/src/ngx_http_headers_more_headers_out.h delete mode 100644 debian/modules/http-headers-more-filter/src/ngx_http_headers_more_util.c delete mode 100644 debian/modules/http-headers-more-filter/src/ngx_http_headers_more_util.h delete mode 100644 debian/modules/http-headers-more-filter/t/bug.t delete mode 100644 debian/modules/http-headers-more-filter/t/builtin.t delete mode 100644 debian/modules/http-headers-more-filter/t/eval.t delete mode 100644 debian/modules/http-headers-more-filter/t/input-conn.t delete mode 100644 debian/modules/http-headers-more-filter/t/input-cookie.t delete mode 100644 debian/modules/http-headers-more-filter/t/input-ua.t delete mode 100644 debian/modules/http-headers-more-filter/t/input.t delete mode 100644 debian/modules/http-headers-more-filter/t/phase.t delete mode 100644 debian/modules/http-headers-more-filter/t/sanity.t delete mode 100644 debian/modules/http-headers-more-filter/t/subrequest.t delete mode 100644 debian/modules/http-headers-more-filter/t/unused.t delete mode 100644 debian/modules/http-headers-more-filter/t/vars.t delete mode 100755 debian/modules/http-headers-more-filter/util/build.sh delete mode 100644 debian/modules/http-headers-more-filter/valgrind.suppress delete mode 100644 debian/modules/http-subs-filter/CHANGES delete mode 100644 debian/modules/http-subs-filter/README delete mode 100644 debian/modules/http-subs-filter/config delete mode 100644 debian/modules/http-subs-filter/doc/README.google_code_home_page.wiki delete mode 100644 debian/modules/http-subs-filter/doc/README.html delete mode 100644 debian/modules/http-subs-filter/doc/README.wiki delete mode 100644 debian/modules/http-subs-filter/ngx_http_subs_filter_module.c delete mode 100644 debian/modules/http-subs-filter/test/README delete mode 100644 debian/modules/http-subs-filter/test/inc/Module/AutoInstall.pm delete mode 100644 debian/modules/http-subs-filter/test/inc/Module/Install.pm delete mode 100644 debian/modules/http-subs-filter/test/inc/Module/Install/AutoInstall.pm delete mode 100644 debian/modules/http-subs-filter/test/inc/Module/Install/Base.pm delete mode 100644 debian/modules/http-subs-filter/test/inc/Module/Install/Can.pm delete mode 100644 debian/modules/http-subs-filter/test/inc/Module/Install/Fetch.pm delete mode 100644 debian/modules/http-subs-filter/test/inc/Module/Install/Include.pm delete mode 100644 debian/modules/http-subs-filter/test/inc/Module/Install/Makefile.pm delete mode 100644 debian/modules/http-subs-filter/test/inc/Module/Install/Metadata.pm delete mode 100644 debian/modules/http-subs-filter/test/inc/Module/Install/TestBase.pm delete mode 100644 debian/modules/http-subs-filter/test/inc/Module/Install/Win32.pm delete mode 100644 debian/modules/http-subs-filter/test/inc/Module/Install/WriteAll.pm delete mode 100644 debian/modules/http-subs-filter/test/inc/Spiffy.pm delete mode 100644 debian/modules/http-subs-filter/test/inc/Test/Base.pm delete mode 100644 debian/modules/http-subs-filter/test/inc/Test/Base/Filter.pm delete mode 100644 debian/modules/http-subs-filter/test/inc/Test/Builder.pm delete mode 100644 debian/modules/http-subs-filter/test/inc/Test/Builder/Module.pm delete mode 100644 debian/modules/http-subs-filter/test/inc/Test/More.pm delete mode 100644 debian/modules/http-subs-filter/test/lib/Test/Nginx.pm delete mode 100644 debian/modules/http-subs-filter/test/lib/Test/Nginx/LWP.pm delete mode 100644 debian/modules/http-subs-filter/test/lib/Test/Nginx/Socket.pm delete mode 100644 debian/modules/http-subs-filter/test/lib/Test/Nginx/Util.pm delete mode 100644 debian/modules/http-subs-filter/test/t/subs.t delete mode 100644 debian/modules/http-subs-filter/test/t/subs_capture.t delete mode 100644 debian/modules/http-subs-filter/test/t/subs_fix_string.t delete mode 100644 debian/modules/http-subs-filter/test/t/subs_regex.t delete mode 100644 debian/modules/http-subs-filter/test/t/subs_types.t delete mode 100755 debian/modules/http-subs-filter/test/test.sh delete mode 100755 debian/modules/http-subs-filter/util/update-readme.sh delete mode 100644 debian/modules/http-subs-filter/util/wiki2google_code_homepage.pl delete mode 100644 debian/modules/http-subs-filter/util/wiki2pod.pl delete mode 100644 debian/modules/http-uploadprogress/CHANGES delete mode 100644 debian/modules/http-uploadprogress/LICENSE delete mode 100644 debian/modules/http-uploadprogress/Makefile delete mode 100644 debian/modules/http-uploadprogress/README delete mode 100644 debian/modules/http-uploadprogress/config delete mode 100644 debian/modules/http-uploadprogress/ngx_http_uploadprogress_module.c delete mode 100644 debian/modules/http-uploadprogress/test/client.sh delete mode 100644 debian/modules/http-uploadprogress/test/stress.sh delete mode 100644 debian/modules/http-upstream-fair/.gdbinit delete mode 100644 debian/modules/http-upstream-fair/README delete mode 100644 debian/modules/http-upstream-fair/config delete mode 100644 debian/modules/http-upstream-fair/ngx_http_upstream_fair_module.c delete mode 100644 debian/modules/patches/http-cache-purge/dynamic-module.patch delete mode 100644 debian/modules/patches/http-cache-purge/segfault-1.11.6.patch delete mode 100644 debian/modules/patches/http-cache-purge/series delete mode 100644 debian/modules/patches/http-subs-filter/dynamic-module.patch delete mode 100644 debian/modules/patches/http-subs-filter/pcre2.patch delete mode 100644 debian/modules/patches/http-subs-filter/series delete mode 100644 debian/modules/patches/http-upstream-fair/drop-default-port.patch delete mode 100644 debian/modules/patches/http-upstream-fair/dynamic-module.patch delete mode 100644 debian/modules/patches/http-upstream-fair/openssl-1.1.0.patch delete mode 100644 debian/modules/patches/http-upstream-fair/series delete mode 100644 debian/modules/watch/http-auth-pam delete mode 100644 debian/modules/watch/http-cache-purge delete mode 100644 debian/modules/watch/http-dav-ext delete mode 100644 debian/modules/watch/http-echo delete mode 100644 debian/modules/watch/http-fancyindex delete mode 100644 debian/modules/watch/http-geoip2 delete mode 100644 debian/modules/watch/http-headers-more-filter delete mode 100644 debian/modules/watch/http-lua delete mode 100644 debian/modules/watch/http-subs-filter delete mode 100644 debian/modules/watch/http-uploadprogress delete mode 100755 debian/ngxmod diff --git a/debian/changelog b/debian/changelog index 78577de..af4ebb8 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,20 @@ +nginx (1.22.1-5) UNRELEASED; urgency=medium + + * removed 3th party modules and moved to separate packages: + - libnginx-mod-http-geoip2 + - libnginx-mod-stream-geoip2 + - libnginx-mod-http-auth-pam + - libnginx-mod-http-echo + - libnginx-mod-http-upstream-fair + - libnginx-mod-http-headers-more-filter + - libnginx-mod-http-cache-purge + - libnginx-mod-http-fancyindex + - libnginx-mod-http-uploadprogress + - libnginx-mod-http-subs-filter + - libnginx-mod-http-dav-ext + + -- Jan Mojžíš Fri, 09 Dec 2022 16:33:16 +0100 + nginx (1.22.1-4) unstable; urgency=medium * d/t/*-module-deps: updated, added curl timeout 300 seconds and diff --git a/debian/control b/debian/control index 7415b24..dced73c 100644 --- a/debian/control +++ b/debian/control @@ -170,7 +170,7 @@ Description: nginx web/proxy server (standard version with 3rd parties) Package: nginx-light Architecture: any -Depends: libnginx-mod-http-echo (>= ${binary:Version}), +Depends: libnginx-mod-http-echo (>= 1:0.63-3~), nginx-common (= ${source:Version}), iproute2, ${misc:Depends}, @@ -197,26 +197,26 @@ Description: nginx web/proxy server (basic version) Package: nginx-extras Architecture: any -Depends: libnginx-mod-http-auth-pam (>= ${binary:Version}), - libnginx-mod-http-cache-purge (>= ${binary:Version}), - libnginx-mod-http-dav-ext (>= ${binary:Version}), - libnginx-mod-http-echo (>= ${binary:Version}), - libnginx-mod-http-fancyindex (>= ${binary:Version}), +Depends: libnginx-mod-http-auth-pam (>= 1:1.5.3-2~), + libnginx-mod-http-cache-purge (>= 1:2.3-3~), + libnginx-mod-http-dav-ext (>= 1:3.0.0-2~), + libnginx-mod-http-echo (>= 1:0.63-3~), + libnginx-mod-http-fancyindex (>= 1:0.5.2-2~), libnginx-mod-http-geoip (= ${binary:Version}), - libnginx-mod-http-geoip2 (>= ${binary:Version}), - libnginx-mod-http-headers-more-filter (>= ${binary:Version}), + libnginx-mod-http-geoip2 (>= 1:3.4-2~), + libnginx-mod-http-headers-more-filter (>= 1:0.34-2~), libnginx-mod-http-image-filter (= ${binary:Version}), libnginx-mod-http-lua (>=1:0.10.22-3~) [amd64 arm64 armel armhf i386 mips64el mipsel s390x powerpc], libnginx-mod-http-perl (= ${binary:Version}), - libnginx-mod-http-subs-filter (>= ${binary:Version}), - libnginx-mod-http-uploadprogress (>= ${binary:Version}), - libnginx-mod-http-upstream-fair (>= ${binary:Version}), + libnginx-mod-http-subs-filter (>= 1:0.6.4-2~), + libnginx-mod-http-uploadprogress (>= 1:0.9.2-2~), + libnginx-mod-http-upstream-fair (>= 1:0.0~git20120408.a18b409-2~), libnginx-mod-http-xslt-filter (= ${binary:Version}), libnginx-mod-mail (= ${binary:Version}), libnginx-mod-nchan (>= 1:1.3.5+dfsg-2~), libnginx-mod-stream (= ${binary:Version}), libnginx-mod-stream-geoip (= ${binary:Version}), - libnginx-mod-stream-geoip2 (>= ${binary:Version}), + libnginx-mod-stream-geoip2 (>= 1:3.4-2~), nginx-common (= ${source:Version}), iproute2, ${misc:Depends}, @@ -261,17 +261,6 @@ Description: GeoIP HTTP module for Nginx Those variables include country, region, city, latitude, longitude, postal code, etc. -Package: libnginx-mod-http-geoip2 -Architecture: any -Depends: ${misc:Depends}, ${shlibs:Depends}, -Recommends: nginx, -Description: GeoIP2 HTTP module for Nginx - The ngx_http_geoip2 module creates variables with values depending on the - client IP address, using the precompiled MaxMind GeoIP2 databases. - . - Those variables include country, region, city, latitude, longitude, postal - code, etc. - Package: libnginx-mod-http-image-filter Architecture: any Depends: ${misc:Depends}, ${shlibs:Depends}, @@ -327,18 +316,6 @@ Description: GeoIP Stream module for Nginx Those variables include country, region, city, latitude, longitude, postal code, etc. -Package: libnginx-mod-stream-geoip2 -Architecture: any -Depends: ${misc:Depends}, ${shlibs:Depends}, - libnginx-mod-stream (= ${binary:Version}), -Recommends: nginx, -Description: GeoIP2 Stream module for Nginx - The ngx_stream_geoip2 module creates variables with values depending on the - client IP address, using the precompiled MaxMind GeoIP2 databases. - . - Those variables include country, region, city, latitude, longitude, postal - code, etc. - Package: libnginx-mod-http-perl Architecture: any Depends: ${misc:Depends}, ${perl:Depends}, ${shlibs:Depends}, @@ -350,106 +327,3 @@ Description: Perl module for Nginx in Perl and insert Perl calls into SSI. . Note that this module is marked experimental. - -Package: libnginx-mod-http-auth-pam -Architecture: any -Depends: ${misc:Depends}, ${shlibs:Depends}, -Recommends: nginx, -Description: PAM authentication module for Nginx - The nginx_http_auth_pam module enables authentication using PAM. - . - The module uses PAM as a backend for simple http authentication. It - also allows setting the pam service name to allow more fine grained control. - -Package: libnginx-mod-http-echo -Architecture: any -Depends: ${misc:Depends}, ${shlibs:Depends}, -Recommends: nginx, -Description: Bring echo and more shell style goodies to Nginx - Echo module wraps lots of Nginx internal APIs for streaming input and output, - parallel/sequential subrequests, timers and sleeping, as well as various meta - data accessing. - . - Basically it provides various utilities that help testing and debugging of - other modules by trivially emulating different kinds of faked subrequest - locations. - . - People will also find it useful in real-world applications that need to: - . - 1. Serve static contents directly from memory. - 2. Wrap the upstream response with custom header and footer (kinda like the - addition module but with contents read directly from the config file and - Nginx variables). - 3. Merge contents of various "Nginx locations" (i.e., subrequests) together in - a single main request (using echo_location and its friends). - -Package: libnginx-mod-http-upstream-fair -Architecture: any -Depends: ${misc:Depends}, ${shlibs:Depends}, -Recommends: nginx, -Description: Nginx Upstream Fair Proxy Load Balancer - The Nginx fair proxy balancer enhances the standard round-robin load balancer - provided with Nginx so that it tracks busy backend servers and adjusts - balancing accordingly. - -Package: libnginx-mod-http-headers-more-filter -Architecture: any -Depends: ${misc:Depends}, ${shlibs:Depends}, -Recommends: nginx, -Description: Set and clear input and output headers for Nginx - The Headers More module allows you to add, set, or clear any output or input - header that you specify. - . - This is an enhanced version of the standard headers module because it provides - more utilities like resetting or clearing "builtin headers" like Content-Type, - Content-Length, and Server. - -Package: libnginx-mod-http-cache-purge -Architecture: any -Depends: ${misc:Depends}, ${shlibs:Depends}, -Recommends: nginx, -Description: Purge content from Nginx caches - Cache Purge module adds purging capabilities to Nginx. It allows purging - content from caches used by all of Nginx proxy modules, like FastCGI, Proxy, - SCGI and uWSGI. - -Package: libnginx-mod-http-fancyindex -Architecture: any -Depends: ${misc:Depends}, ${shlibs:Depends}, -Suggests: nginx, -Description: Fancy indexes module for the Nginx - The Fancy Index module makes possible the generation of file listings, like - the built-in autoindex module does, but adding a touch of style by introducing - ways to customize the result. - -Package: libnginx-mod-http-uploadprogress -Architecture: any -Depends: ${misc:Depends}, ${shlibs:Depends}, -Recommends: nginx, -Description: Upload progress system for Nginx - Upload progress module is an implementation of an upload progress system, that - monitors RFC1867 POST uploads as they are transmitted to upstream servers. - . - It works by tracking the uploads proxied by Nginx to upstream servers without - analysing the uploaded content and offers a web API to report upload progress - in Javscript, Json or any other format. - -Package: libnginx-mod-http-subs-filter -Architecture: any -Depends: ${misc:Depends}, ${shlibs:Depends}, -Recommends: nginx, -Description: Substitution filter module for Nginx - Substitution Nginx module can do both regular expression and fixed string - substitutions on response bodies. The module is quite different from Nginx's - native Substitution module. It scans the output chains buffer and - matches string line by line, just like Apache's mod_substitute. - -Package: libnginx-mod-http-dav-ext -Architecture: any -Depends: ${misc:Depends}, ${shlibs:Depends}, -Recommends: nginx, -Description: WebDAV missing commands support for Nginx - WebDAV Ext module complements the Nginx WebDAV module to provide a full - WebDAV support. - . - WebDAV Ext provides the missing PROPFIND & OPTIONS methods. diff --git a/debian/copyright b/debian/copyright index 713892f..3ae2899 100644 --- a/debian/copyright +++ b/debian/copyright @@ -51,57 +51,6 @@ Files: debian/debhelper/* Copyright: 2022 Miao Wang License: Expat -Files: debian/modules/http-headers-more-filter/* -Copyright: 2009-2017, Yichun "agentzh" Zhang (章亦春) , CloudFlare Inc. - 2010-2013, Bernd Dorn - Igor Sysoev -License: BSD-2-clause - -Files: debian/modules/http-geoip2/* -Copyright: 2014, Lee Valentine -License: BSD-2-clause - -Files: debian/modules/http-auth-pam/* -Copyright: 2008-2020, Sergio Talens Oliag -License: BSD-2-clause - -Files: debian/modules/http-echo/* -Copyright: 2009-2014, Yichun "agentzh" Zhang -License: BSD-2-clause - -Files: debian/modules/http-upstream-fair/* -Copyright: 2007, Grzegorz Nosek - Igor Sysoev -License: BSD-2-clause - -Files: debian/modules/http-uploadprogress/* -Copyright: 2007, Brice Figureau - 2002-2007, Igor Sysoev -License: BSD-2-clause - -Files: debian/modules/http-cache-purge/* -Copyright: 2009-2014, FRiCKLE , - 2009-2014, Piotr Sikora -License: BSD-2-clause - -Files: debian/modules/http-dav-ext/* -Copyright: 2012-2018, Roman Arutyunyan -License: BSD-2-clause - -Files: debian/modules/http-fancyindex/* -Copyright: 2007-2016, Adrian Perez -License: BSD-2-clause - -Files: debian/modules/http-subs-filter/* -Copyright: 2014, Weibin Yao -License: BSD-2-clause - -Files: debian/modules/http-subs-filter/test/* -Copyright: 2009-2011, Taobao Inc., Alibaba Group - Antoine BONAVITA "" - agentzh (章亦春) "" -License: BSD-3-clause - License: BSD-2-clause All rights reserved. . @@ -127,33 +76,6 @@ License: BSD-2-clause (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -License: BSD-3-clause - All rights reserved. - . - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - 3. Neither the name of the University nor the names of its contributors - may be used to endorse or promote products derived from this - software without specific prior written permission. - . - THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS - BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - License: Expat Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to diff --git a/debian/libnginx-mod-http-auth-pam.nginx b/debian/libnginx-mod-http-auth-pam.nginx deleted file mode 100755 index 78c206f..0000000 --- a/debian/libnginx-mod-http-auth-pam.nginx +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/perl -w - -use File::Basename; - -# Guess module name -$module = basename($0, '.nginx'); -$module =~ s/^libnginx-mod-//; - -$modulepath = $module; -$modulepath =~ s/-/_/g; - -print "mod debian/build-extras/objs/ngx_${modulepath}_module.so\n"; -print "mod debian/libnginx-mod.conf/mod-${module}.conf\n"; diff --git a/debian/libnginx-mod-http-cache-purge.nginx b/debian/libnginx-mod-http-cache-purge.nginx deleted file mode 100755 index 78c206f..0000000 --- a/debian/libnginx-mod-http-cache-purge.nginx +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/perl -w - -use File::Basename; - -# Guess module name -$module = basename($0, '.nginx'); -$module =~ s/^libnginx-mod-//; - -$modulepath = $module; -$modulepath =~ s/-/_/g; - -print "mod debian/build-extras/objs/ngx_${modulepath}_module.so\n"; -print "mod debian/libnginx-mod.conf/mod-${module}.conf\n"; diff --git a/debian/libnginx-mod-http-dav-ext.nginx b/debian/libnginx-mod-http-dav-ext.nginx deleted file mode 100755 index 78c206f..0000000 --- a/debian/libnginx-mod-http-dav-ext.nginx +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/perl -w - -use File::Basename; - -# Guess module name -$module = basename($0, '.nginx'); -$module =~ s/^libnginx-mod-//; - -$modulepath = $module; -$modulepath =~ s/-/_/g; - -print "mod debian/build-extras/objs/ngx_${modulepath}_module.so\n"; -print "mod debian/libnginx-mod.conf/mod-${module}.conf\n"; diff --git a/debian/libnginx-mod-http-echo.nginx b/debian/libnginx-mod-http-echo.nginx deleted file mode 100755 index 78c206f..0000000 --- a/debian/libnginx-mod-http-echo.nginx +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/perl -w - -use File::Basename; - -# Guess module name -$module = basename($0, '.nginx'); -$module =~ s/^libnginx-mod-//; - -$modulepath = $module; -$modulepath =~ s/-/_/g; - -print "mod debian/build-extras/objs/ngx_${modulepath}_module.so\n"; -print "mod debian/libnginx-mod.conf/mod-${module}.conf\n"; diff --git a/debian/libnginx-mod-http-fancyindex.nginx b/debian/libnginx-mod-http-fancyindex.nginx deleted file mode 100755 index 78c206f..0000000 --- a/debian/libnginx-mod-http-fancyindex.nginx +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/perl -w - -use File::Basename; - -# Guess module name -$module = basename($0, '.nginx'); -$module =~ s/^libnginx-mod-//; - -$modulepath = $module; -$modulepath =~ s/-/_/g; - -print "mod debian/build-extras/objs/ngx_${modulepath}_module.so\n"; -print "mod debian/libnginx-mod.conf/mod-${module}.conf\n"; diff --git a/debian/libnginx-mod-http-geoip2.nginx b/debian/libnginx-mod-http-geoip2.nginx deleted file mode 100755 index 78c206f..0000000 --- a/debian/libnginx-mod-http-geoip2.nginx +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/perl -w - -use File::Basename; - -# Guess module name -$module = basename($0, '.nginx'); -$module =~ s/^libnginx-mod-//; - -$modulepath = $module; -$modulepath =~ s/-/_/g; - -print "mod debian/build-extras/objs/ngx_${modulepath}_module.so\n"; -print "mod debian/libnginx-mod.conf/mod-${module}.conf\n"; diff --git a/debian/libnginx-mod-http-headers-more-filter.nginx b/debian/libnginx-mod-http-headers-more-filter.nginx deleted file mode 100755 index 78c206f..0000000 --- a/debian/libnginx-mod-http-headers-more-filter.nginx +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/perl -w - -use File::Basename; - -# Guess module name -$module = basename($0, '.nginx'); -$module =~ s/^libnginx-mod-//; - -$modulepath = $module; -$modulepath =~ s/-/_/g; - -print "mod debian/build-extras/objs/ngx_${modulepath}_module.so\n"; -print "mod debian/libnginx-mod.conf/mod-${module}.conf\n"; diff --git a/debian/libnginx-mod-http-subs-filter.nginx b/debian/libnginx-mod-http-subs-filter.nginx deleted file mode 100755 index 78c206f..0000000 --- a/debian/libnginx-mod-http-subs-filter.nginx +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/perl -w - -use File::Basename; - -# Guess module name -$module = basename($0, '.nginx'); -$module =~ s/^libnginx-mod-//; - -$modulepath = $module; -$modulepath =~ s/-/_/g; - -print "mod debian/build-extras/objs/ngx_${modulepath}_module.so\n"; -print "mod debian/libnginx-mod.conf/mod-${module}.conf\n"; diff --git a/debian/libnginx-mod-http-uploadprogress.nginx b/debian/libnginx-mod-http-uploadprogress.nginx deleted file mode 100755 index 78c206f..0000000 --- a/debian/libnginx-mod-http-uploadprogress.nginx +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/perl -w - -use File::Basename; - -# Guess module name -$module = basename($0, '.nginx'); -$module =~ s/^libnginx-mod-//; - -$modulepath = $module; -$modulepath =~ s/-/_/g; - -print "mod debian/build-extras/objs/ngx_${modulepath}_module.so\n"; -print "mod debian/libnginx-mod.conf/mod-${module}.conf\n"; diff --git a/debian/libnginx-mod-http-upstream-fair.nginx b/debian/libnginx-mod-http-upstream-fair.nginx deleted file mode 100755 index 78c206f..0000000 --- a/debian/libnginx-mod-http-upstream-fair.nginx +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/perl -w - -use File::Basename; - -# Guess module name -$module = basename($0, '.nginx'); -$module =~ s/^libnginx-mod-//; - -$modulepath = $module; -$modulepath =~ s/-/_/g; - -print "mod debian/build-extras/objs/ngx_${modulepath}_module.so\n"; -print "mod debian/libnginx-mod.conf/mod-${module}.conf\n"; diff --git a/debian/libnginx-mod-stream-geoip2.nginx b/debian/libnginx-mod-stream-geoip2.nginx deleted file mode 100755 index 9acb103..0000000 --- a/debian/libnginx-mod-stream-geoip2.nginx +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/perl -w - -use File::Basename; - -# Guess module name -$module = basename($0, '.nginx'); -$module =~ s/^libnginx-mod-//; - -$modulepath = $module; -$modulepath =~ s/-/_/g; - -print "mod debian/build-extras/objs/ngx_${modulepath}_module.so\n"; -print "mod debian/libnginx-mod.conf/mod-${module}.conf 70\n"; diff --git a/debian/libnginx-mod.conf/mod-http-auth-pam.conf b/debian/libnginx-mod.conf/mod-http-auth-pam.conf deleted file mode 100644 index 2eb6752..0000000 --- a/debian/libnginx-mod.conf/mod-http-auth-pam.conf +++ /dev/null @@ -1 +0,0 @@ -load_module modules/ngx_http_auth_pam_module.so; diff --git a/debian/libnginx-mod.conf/mod-http-cache-purge.conf b/debian/libnginx-mod.conf/mod-http-cache-purge.conf deleted file mode 100644 index 5974b1f..0000000 --- a/debian/libnginx-mod.conf/mod-http-cache-purge.conf +++ /dev/null @@ -1 +0,0 @@ -load_module modules/ngx_http_cache_purge_module.so; diff --git a/debian/libnginx-mod.conf/mod-http-dav-ext.conf b/debian/libnginx-mod.conf/mod-http-dav-ext.conf deleted file mode 100644 index e852329..0000000 --- a/debian/libnginx-mod.conf/mod-http-dav-ext.conf +++ /dev/null @@ -1 +0,0 @@ -load_module modules/ngx_http_dav_ext_module.so; diff --git a/debian/libnginx-mod.conf/mod-http-echo.conf b/debian/libnginx-mod.conf/mod-http-echo.conf deleted file mode 100644 index a82ee29..0000000 --- a/debian/libnginx-mod.conf/mod-http-echo.conf +++ /dev/null @@ -1 +0,0 @@ -load_module modules/ngx_http_echo_module.so; diff --git a/debian/libnginx-mod.conf/mod-http-fancyindex.conf b/debian/libnginx-mod.conf/mod-http-fancyindex.conf deleted file mode 100644 index 4aa4f2f..0000000 --- a/debian/libnginx-mod.conf/mod-http-fancyindex.conf +++ /dev/null @@ -1 +0,0 @@ -load_module modules/ngx_http_fancyindex_module.so; diff --git a/debian/libnginx-mod.conf/mod-http-geoip2.conf b/debian/libnginx-mod.conf/mod-http-geoip2.conf deleted file mode 100644 index 9441b29..0000000 --- a/debian/libnginx-mod.conf/mod-http-geoip2.conf +++ /dev/null @@ -1 +0,0 @@ -load_module modules/ngx_http_geoip2_module.so; diff --git a/debian/libnginx-mod.conf/mod-http-headers-more-filter.conf b/debian/libnginx-mod.conf/mod-http-headers-more-filter.conf deleted file mode 100644 index 266d84e..0000000 --- a/debian/libnginx-mod.conf/mod-http-headers-more-filter.conf +++ /dev/null @@ -1 +0,0 @@ -load_module modules/ngx_http_headers_more_filter_module.so; diff --git a/debian/libnginx-mod.conf/mod-http-subs-filter.conf b/debian/libnginx-mod.conf/mod-http-subs-filter.conf deleted file mode 100644 index fe34b6c..0000000 --- a/debian/libnginx-mod.conf/mod-http-subs-filter.conf +++ /dev/null @@ -1 +0,0 @@ -load_module modules/ngx_http_subs_filter_module.so; diff --git a/debian/libnginx-mod.conf/mod-http-uploadprogress.conf b/debian/libnginx-mod.conf/mod-http-uploadprogress.conf deleted file mode 100644 index edc0c0b..0000000 --- a/debian/libnginx-mod.conf/mod-http-uploadprogress.conf +++ /dev/null @@ -1 +0,0 @@ -load_module modules/ngx_http_uploadprogress_module.so; diff --git a/debian/libnginx-mod.conf/mod-http-upstream-fair.conf b/debian/libnginx-mod.conf/mod-http-upstream-fair.conf deleted file mode 100644 index 62750b5..0000000 --- a/debian/libnginx-mod.conf/mod-http-upstream-fair.conf +++ /dev/null @@ -1 +0,0 @@ -load_module modules/ngx_http_upstream_fair_module.so; diff --git a/debian/libnginx-mod.conf/mod-stream-geoip2.conf b/debian/libnginx-mod.conf/mod-stream-geoip2.conf deleted file mode 100644 index 4072597..0000000 --- a/debian/libnginx-mod.conf/mod-stream-geoip2.conf +++ /dev/null @@ -1 +0,0 @@ -load_module modules/ngx_stream_geoip2_module.so; diff --git a/debian/modules/control b/debian/modules/control deleted file mode 100644 index 7ff9851..0000000 --- a/debian/modules/control +++ /dev/null @@ -1,52 +0,0 @@ -Module: http-headers-more-filter -Homepage: https://github.com/agentzh/headers-more-nginx-module -Version: 0.33 -Files-Excluded: .gitignore .gitattributes .travis.yml - -Module: http-auth-pam -Homepage: https://github.com/sto/ngx_http_auth_pam_module -Version: 1.5.3 - -Module: http-echo -Homepage: https://github.com/agentzh/echo-nginx-module -Version: 0.62 -Files-Excluded: .gitignore .gitattributes .travis.yml - -Module: http-geoip2 -Homepage: https://github.com/leev/ngx_http_geoip2_module -Version: 3.3 - -Module: http-upstream-fair -Homepage: https://github.com/gnosek/nginx-upstream-fair -Version: a18b409 -Patch: - dynamic-module.patch - openssl-1.1.0.patch - drop-default-port.patch - -Module: http-uploadprogress -Homepage: https://github.com/masterzen/nginx-upload-progress-module -Files-Excluded: test -Version: 0.9.2 - -Module: http-cache-purge -Homepage: https://github.com/FRiCKLE/ngx_cache_purge/ -Version: 2.3 -Patch: - dynamic-module.patch - segfault-1.11.6.patch - -Module: http-dav-ext -Homepage: https://github.com/arut/nginx-dav-ext-module -Version: 3.0.0 - -Module: http-fancyindex -Homepage: https://github.com/aperezdc/ngx-fancyindex -Version: 0.5.2 -Files-Excluded: .gitignore .travis.yml - -Module: http-subs-filter -Homepage: https://github.com/yaoweibin/ngx_http_substitutions_filter_module -Version: 0.6.4 -Patch: dynamic-module.patch - diff --git a/debian/modules/http-auth-pam/ChangeLog b/debian/modules/http-auth-pam/ChangeLog deleted file mode 100644 index 5974d79..0000000 --- a/debian/modules/http-auth-pam/ChangeLog +++ /dev/null @@ -1,63 +0,0 @@ -2021-08-23 sto@mixinet.net - - * Version 1.5.3. - * Always load after ngx_http_access_module (patch provided by khimaros, see - https://github.com/sto/ngx_http_auth_pam_module/pull/26) - -2020-06-23 sto@mixinet.net - - * Version 1.5.2. - * Log authentication errors as errors instead of debug (patch provided by - Juha Koho, see https://github.com/sto/ngx_http_auth_pam_module/pull/11) - * Send client IP address to PAM (patch provided by Marcin Łojewski, see - https://github.com/sto/ngx_http_auth_pam_module/pull/14) - -2016-04-06 sto@iti.es - - * Version 1.5.1. - * Fix building alongside other modules in nginx 1.9.11+ (patch provided by - Graham Edgecombe ) - -2016-03-23 sto@iti.es - - * Version 1.5. - * Added support to build module dynamically (patch provided by Sjir - Bagmeijer ). - * Log PAM error and info messages to nginx log files (patch provided by - André Caron ). - -2015-02-04 sto@iti.es - - * Version 1.4. - * Cleanup PAM responses on error, the module was not doing it, causing - memory leaks (thanks to Michael Koziarski for the report). - -2013-09-17 sto@iti.es - - * Version 1.3. - * Added support to export HOST and REQUEST variables to the PAM ENVIRONMENT. - Thanks to Ruben Jenster for the initial patch, his version is available - from https://github.com/r10r/ngx_http_auth_pam_module; my version uses his - implementation but only if the user sets the ``pam_auth_set_pam_env`` - flag. - * Fixed bug from http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=+721702 - (ngx_module_t commands array should end with a ngx_null_command); the bug - was already fixed on the PAM_ENV patch, but I forgot about it until I went - back to my svn repository to add the debian patch... better latter than - never... ;) - -2010-11-15 sto@iti.upv.es - - * Version 1.2. - * Fixed possible memory leak when authentication fails, pam_end has to - be called to free memory (thanks to Neil Chintomby). - -2009-01-26 sto@iti.upv.es - - * Version 1.1. - * Fixed ngx_log_debugX calls, no we use the correct X value on each - call. - -2008-09-17 sto@iti.upv.es - - * Initial version (1.0). diff --git a/debian/modules/http-auth-pam/LICENSE b/debian/modules/http-auth-pam/LICENSE deleted file mode 100644 index a9d6313..0000000 --- a/debian/modules/http-auth-pam/LICENSE +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (C) 2008-2020 Sergio Talens Oliag - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ diff --git a/debian/modules/http-auth-pam/README.md b/debian/modules/http-auth-pam/README.md deleted file mode 100644 index 975bafe..0000000 --- a/debian/modules/http-auth-pam/README.md +++ /dev/null @@ -1,95 +0,0 @@ -# ngx_http_auth_pam_module - -## Nginx module to use PAM for simple http authentication - -### Compilation - -When compiling from source build as usual adding the ``--add-module`` option: - - ./configure --add-module=$PATH_TO_MODULE - -or if you want to build the module as dynamic use the ``--add-dynamic-module`` -option. - -If you are using a Debian GNU/Linux distribution install the ``nginx-full`` -package; the module has been included in the debian package since version -``1.1.6-1``, so it is available on all stable distributions since the *wheezy* -release. - -### Configuration - -The module only has two directives: - -- ``auth_pam``: This is the http authentication realm. If given the value - ``off`` the module is disabled (needed when we want to override the value - set on a lower-level directive). - -- ``auth_pam_service_name``: this is the PAM service name and by default it is - set to ``nginx``. - -### Examples - -To protect everything under ``/secure`` you will add the following to the -``nginx.conf`` file: - - location /secure { - auth_pam "Secure Zone"; - auth_pam_service_name "nginx"; - } - -Note that the module runs as the web server user, so the PAM modules used must -be able to authenticate the users without being root; that means that if you -want to use the ``pam_unix.so`` module to autenticate users you need to let the -web server user to read the ``/etc/shadow`` file if that does not scare you (on -Debian like systems you can add the ``www-data`` user to the ``shadow`` group). - -As an example, to authenticate users against an LDAP server (using the -``pam_ldap.so`` module) you will use an ``/etc/pam.d/nginx`` like the -following: - - auth required /lib/security/pam_ldap.so - account required /lib/security/pam_ldap.so - -If you also want to limit the users from LDAP that can authenticate you can -use the ``pam_listfile.so`` module; to limit who can access resources under -``/restricted`` add the following to the ``nginx.conf`` file: - - location /restricted { - auth_pam "Restricted Zone"; - auth_pam_service_name "nginx_restricted"; - } - -Use the following ``/etc/pam.d/nginx_restricted`` file: - - auth required /lib/security/pam_listfile.so onerr=fail item=user \ - sense=allow file=/etc/nginx/restricted_users - auth required /lib/security/pam_ldap.so - account required /lib/security/pam_ldap.so - -And add the users allowed to authenticate to the ``/etc/nginx/restricted_users`` -(remember that the web server user has to be able to read this file). - -### PAM Environment - -If you want use the ``pam_exec.so`` plugin for request based authentication the -module can add to the PAM environment the ``HOST`` and ``REQUEST`` variables if -you set the ``auth_pam_set_pam_env`` flag:: - - location /pam_exec_protected { - auth_pam "Exec Zone"; - auth_pam_service_name "nginx_exec"; - auth_pam_set_pam_env on; - } - -With this configuration if you access an URL like: - - http://localhost:8000/pam_exec_protected/page?foo=yes&bar=too - -the PAM environment will include the following variables: - - HOST=localhost:8000 - REQUEST=GET /pam_exec_protected/page?foo=yes&bar=too HTTP/1.1 - -You may use this information for request based authentication. -You need a recent pam release (>= version 1.0.90) to expose environment -variables to pam_exec. diff --git a/debian/modules/http-auth-pam/VERSION b/debian/modules/http-auth-pam/VERSION deleted file mode 100644 index 8af85be..0000000 --- a/debian/modules/http-auth-pam/VERSION +++ /dev/null @@ -1 +0,0 @@ -1.5.3 diff --git a/debian/modules/http-auth-pam/config b/debian/modules/http-auth-pam/config deleted file mode 100644 index 6965eea..0000000 --- a/debian/modules/http-auth-pam/config +++ /dev/null @@ -1,17 +0,0 @@ -ngx_addon_name=ngx_http_auth_pam_module - -if test -n "$ngx_module_link"; then - ngx_module_type=HTTP - ngx_module_name=ngx_http_auth_pam_module - ngx_module_incs= - ngx_module_deps= - ngx_module_srcs="$ngx_addon_dir/ngx_http_auth_pam_module.c" - ngx_module_libs="-lpam" - ngx_module_order="$ngx_module_name ngx_http_access_module" - - . auto/module -else - HTTP_MODULES="$HTTP_MODULES ngx_http_auth_pam_module" - NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_auth_pam_module.c" - CORE_LIBS="$CORE_LIBS -lpam" -fi diff --git a/debian/modules/http-auth-pam/ngx_http_auth_pam_module.c b/debian/modules/http-auth-pam/ngx_http_auth_pam_module.c deleted file mode 100644 index 55eeb92..0000000 --- a/debian/modules/http-auth-pam/ngx_http_auth_pam_module.c +++ /dev/null @@ -1,482 +0,0 @@ -/* - * Copyright (C) 2008-2020 Sergio Talens-Oliag - * - * Based on nginx's 'ngx_http_auth_basic_module.c' by Igor Sysoev and apache's - * 'mod_auth_pam.c' by Ingo Luetkebolhe. - * - * File: ngx_http_auth_pam_module.c - */ - -#include -#include -#include -#include - -#define NGX_PAM_SERVICE_NAME "nginx" - -/* Module context data */ -typedef struct { - ngx_str_t passwd; -} ngx_http_auth_pam_ctx_t; - -/* PAM authinfo */ -typedef struct { - ngx_str_t username; - ngx_str_t password; - ngx_log_t *log; -} ngx_pam_authinfo; - -/* Module configuration struct */ -typedef struct { - ngx_str_t realm; /* http basic auth realm */ - ngx_str_t service_name; /* pam service name */ - ngx_flag_t set_pam_env; /* flag that indicates if we should export - variables to PAM or NOT */ -} ngx_http_auth_pam_loc_conf_t; - -/* Module handler */ -static ngx_int_t ngx_http_auth_pam_handler(ngx_http_request_t *r); - -/* Function that authenticates the user -- is the only function that uses PAM */ -static ngx_int_t ngx_http_auth_pam_authenticate(ngx_http_request_t *r, - ngx_http_auth_pam_ctx_t *ctx, - ngx_str_t *passwd, void *conf); - -static ngx_int_t ngx_http_auth_pam_set_realm(ngx_http_request_t *r, - ngx_str_t *realm); - -static void *ngx_http_auth_pam_create_loc_conf(ngx_conf_t *cf); - -static char *ngx_http_auth_pam_merge_loc_conf(ngx_conf_t *cf, - void *parent, void *child); - -static ngx_int_t ngx_http_auth_pam_init(ngx_conf_t *cf); - -static char *ngx_http_auth_pam(ngx_conf_t *cf, void *post, void *data); - -static ngx_conf_post_handler_pt ngx_http_auth_pam_p = ngx_http_auth_pam; - -static int ngx_auth_pam_talker(int num_msg, const struct pam_message ** msg, - struct pam_response ** resp, void *appdata_ptr); - -static ngx_command_t ngx_http_auth_pam_commands[] = { - - { ngx_string("auth_pam"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LMT_CONF - |NGX_CONF_TAKE1, - ngx_conf_set_str_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_auth_pam_loc_conf_t, realm), - &ngx_http_auth_pam_p }, - - { ngx_string("auth_pam_service_name"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LMT_CONF - |NGX_CONF_TAKE1, - ngx_conf_set_str_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_auth_pam_loc_conf_t, service_name), - NULL }, - - { ngx_string("auth_pam_set_pam_env"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LMT_CONF - |NGX_CONF_FLAG, - ngx_conf_set_flag_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_auth_pam_loc_conf_t, set_pam_env), - NULL }, - - ngx_null_command -}; - - -static ngx_http_module_t ngx_http_auth_pam_module_ctx = { - NULL, /* preconfiguration */ - ngx_http_auth_pam_init, /* postconfiguration */ - - NULL, /* create main configuration */ - NULL, /* init main configuration */ - - NULL, /* create server configuration */ - NULL, /* merge server configuration */ - - ngx_http_auth_pam_create_loc_conf, /* create location configuration */ - ngx_http_auth_pam_merge_loc_conf /* merge location configuration */ -}; - - -ngx_module_t ngx_http_auth_pam_module = { - NGX_MODULE_V1, - &ngx_http_auth_pam_module_ctx, /* module context */ - ngx_http_auth_pam_commands, /* module directives */ - NGX_HTTP_MODULE, /* module type */ - NULL, /* init master */ - NULL, /* init module */ - NULL, /* init process */ - NULL, /* init thread */ - NULL, /* exit thread */ - NULL, /* exit process */ - NULL, /* exit master */ - NGX_MODULE_V1_PADDING -}; - - -/* - * Function to free PAM_CONV responses if an error is returned. - */ -static void -free_resp(int num_msg, struct pam_response *response) -{ - int i; - if (response == NULL) - return; - for (i = 0; i < num_msg; i++) { - if (response[i].resp) { - /* clear before freeing -- may be a password */ - bzero(response[i].resp, strlen(response[i].resp)); - free(response[i].resp); - response[i].resp = NULL; - } - } - free(response); -} - -/* - * ngx_auth_pam_talker: supply authentication information to PAM when asked - * - * Assumptions: - * A password is asked for by requesting input without echoing - * A username is asked for by requesting input _with_ echoing - */ -static int -ngx_auth_pam_talker(int num_msg, const struct pam_message ** msg, - struct pam_response ** resp, void *appdata_ptr) -{ - int i; - ngx_pam_authinfo *ainfo; - struct pam_response *response; - - ainfo = (ngx_pam_authinfo *) appdata_ptr; - response = NULL; - - /* parameter sanity checking */ - if (!resp || !msg || !ainfo) - return PAM_CONV_ERR; - - /* allocate memory to store response */ - response = malloc(num_msg * sizeof(struct pam_response)); - if (!response) - return PAM_CONV_ERR; - - /* copy values */ - for (i = 0; i < num_msg; i++) { - /* initialize to safe values */ - response[i].resp_retcode = 0; - response[i].resp = 0; - - /* select response based on requested output style */ - switch (msg[i]->msg_style) { - case PAM_PROMPT_ECHO_ON: - /* on memory allocation failure, auth fails */ - response[i].resp = strdup((const char *)ainfo->username.data); - break; - case PAM_PROMPT_ECHO_OFF: - response[i].resp = strdup((const char *)ainfo->password.data); - break; - case PAM_ERROR_MSG: - ngx_log_error(NGX_LOG_ERR, ainfo->log, 0, - "PAM: \'%s\'.", msg[i]->msg); - break; - case PAM_TEXT_INFO: - ngx_log_error(NGX_LOG_INFO, ainfo->log, 0, - "PAM: \'%s\'.", msg[i]->msg); - break; - default: - free_resp(i, response); - return PAM_CONV_ERR; - } - } - /* everything okay, set PAM response values */ - *resp = response; - return PAM_SUCCESS; -} - -static ngx_int_t -ngx_http_auth_pam_handler(ngx_http_request_t *r) -{ - ngx_int_t rc; - ngx_http_auth_pam_ctx_t *ctx; - ngx_http_auth_pam_loc_conf_t *alcf; - - alcf = ngx_http_get_module_loc_conf(r, ngx_http_auth_pam_module); - - if (alcf->realm.len == 0) { - return NGX_DECLINED; - } - - ctx = ngx_http_get_module_ctx(r, ngx_http_auth_pam_module); - - if (ctx) { - return ngx_http_auth_pam_authenticate(r, ctx, &ctx->passwd, alcf); - } - - /* Decode http auth user and passwd, leaving values on the request */ - rc = ngx_http_auth_basic_user(r); - - if (rc == NGX_DECLINED) { - return ngx_http_auth_pam_set_realm(r, &alcf->realm); - } - - if (rc == NGX_ERROR) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - /* Check user & password using PAM */ - return ngx_http_auth_pam_authenticate(r, ctx, &ctx->passwd, alcf); -} - -/** - * create a key value pair from the given key and value string - */ -static void set_to_pam_env(pam_handle_t *pamh, ngx_http_request_t *r, - char *key, char *value) -{ - if (key != NULL && value != NULL) { - size_t size = strlen(key) + strlen(value) + 1 * sizeof(char); - char *key_value_pair = ngx_palloc(r->pool, size); - sprintf(key_value_pair, "%s=%s", key, value); - - pam_putenv(pamh, key_value_pair); - } -} - -/** - * creates a '\0' terminated string from the given ngx_str_t - * - * @param source nginx string structure with data and length - * @param pool pool of the request used for memory allocation - */ -static char* ngx_strncpy_s(ngx_str_t source, ngx_pool_t *pool) -{ - // allocate memory in pool - char* destination = ngx_palloc(pool, source.len + 1); - strncpy(destination, (char *) source.data, source.len); - // add null terminator - destination[source.len] = '\0'; - return destination; -} - -/** - * enrich pam environment with request parameters - */ -static void add_request_info_to_pam_env(pam_handle_t *pamh, - ngx_http_request_t *r) -{ - char *request_info = ngx_strncpy_s(r->request_line, r->pool); - char *host_info = ngx_strncpy_s(r->headers_in.host->value, r->pool); - - set_to_pam_env(pamh, r, "REQUEST", request_info); - set_to_pam_env(pamh, r, "HOST", host_info); -} - -static ngx_int_t -ngx_http_auth_pam_authenticate(ngx_http_request_t *r, - ngx_http_auth_pam_ctx_t *ctx, ngx_str_t *passwd, - void *conf) -{ - ngx_int_t rc; - ngx_http_auth_pam_loc_conf_t *alcf; - - ngx_pam_authinfo ainfo; - struct pam_conv conv_info; /* PAM struct */ - pam_handle_t *pamh; - u_char *service_name; - - alcf = conf; - - size_t len; - u_char *uname_buf, *p; - - /** - * Get username and password, note that r->headers_in.user contains the - * string 'user:pass', so we need to copy the username - **/ - for (len = 0; len < r->headers_in.user.len; len++) { - if (r->headers_in.user.data[len] == ':') { - break; - } - } - uname_buf = ngx_palloc(r->pool, len+1); - if (uname_buf == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - p = ngx_cpymem(uname_buf, r->headers_in.user.data , len); - *p ='\0'; - - ainfo.username.data = uname_buf; - ainfo.username.len = len; - - ainfo.password.data = r->headers_in.passwd.data; - ainfo.password.len = r->headers_in.passwd.len; - - ainfo.log = r->connection->log; - - conv_info.conv = &ngx_auth_pam_talker; - conv_info.appdata_ptr = (void *) &ainfo; - - pamh = NULL; - - /* Initialize PAM */ - if (alcf->service_name.data == NULL) { - service_name = (u_char *) NGX_PAM_SERVICE_NAME; - } else { - service_name = alcf->service_name.data; - } - if ((rc = pam_start((const char *) service_name, - (const char *) ainfo.username.data, - &conv_info, - &pamh)) != PAM_SUCCESS) { - ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0, - "PAM: Could not start pam service: %s", - pam_strerror(pamh, rc)); - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - /* send client IP address to PAM */ - char *client_ip_addr = ngx_strncpy_s(r->connection->addr_text, r->pool); - if ((rc = pam_set_item(pamh, PAM_RHOST, client_ip_addr)) != PAM_SUCCESS) { - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "PAM: Could not set item PAM_RHOST: %s", - pam_strerror(pamh, rc)); - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - if (alcf->set_pam_env) { - add_request_info_to_pam_env(pamh, r); - } - - /* try to authenticate user, log error on failure */ - if ((rc = pam_authenticate(pamh, - PAM_DISALLOW_NULL_AUTHTOK)) != PAM_SUCCESS) { - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "PAM: user '%s' - not authenticated: %s", - ainfo.username.data, pam_strerror(pamh, rc)); - pam_end(pamh, PAM_SUCCESS); - return ngx_http_auth_pam_set_realm(r, &alcf->realm); - } /* endif authenticate */ - - /* check that the account is healthy */ - if ((rc = pam_acct_mgmt(pamh, PAM_DISALLOW_NULL_AUTHTOK)) != PAM_SUCCESS) { - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "PAM: user '%s' - invalid account: %s", - ainfo.username.data, pam_strerror(pamh, rc)); - pam_end(pamh, PAM_SUCCESS); - return ngx_http_auth_pam_set_realm(r, &alcf->realm); - } - - pam_end(pamh, PAM_SUCCESS); - return NGX_OK; -} - -static ngx_int_t -ngx_http_auth_pam_set_realm(ngx_http_request_t *r, ngx_str_t *realm) -{ - r->headers_out.www_authenticate = ngx_list_push(&r->headers_out.headers); - if (r->headers_out.www_authenticate == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - r->headers_out.www_authenticate->hash = 1; - r->headers_out.www_authenticate->key.len = sizeof("WWW-Authenticate") - 1; - r->headers_out.www_authenticate->key.data = (u_char *) "WWW-Authenticate"; - r->headers_out.www_authenticate->value = *realm; - - return NGX_HTTP_UNAUTHORIZED; -} - -static void * -ngx_http_auth_pam_create_loc_conf(ngx_conf_t *cf) -{ - ngx_http_auth_pam_loc_conf_t *conf; - - conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_auth_pam_loc_conf_t)); - if (conf == NULL) { - return NGX_CONF_ERROR; - } - - /* Strings are already NULL, but the flags have to be marked as unset */ - conf->set_pam_env = NGX_CONF_UNSET; - - return conf; -} - -static char * -ngx_http_auth_pam_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) -{ - ngx_http_auth_pam_loc_conf_t *prev = parent; - ngx_http_auth_pam_loc_conf_t *conf = child; - - if (conf->realm.data == NULL) { - conf->realm = prev->realm; - } - - if (conf->service_name.data == NULL) { - conf->service_name = prev->service_name; - } - - /* By default set_pam_env is off */ - ngx_conf_merge_value(conf->set_pam_env, prev->set_pam_env, 0); - - return NGX_CONF_OK; -} - -static ngx_int_t -ngx_http_auth_pam_init(ngx_conf_t *cf) -{ - ngx_http_handler_pt *h; - ngx_http_core_main_conf_t *cmcf; - - cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); - - h = ngx_array_push(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers); - if (h == NULL) { - return NGX_ERROR; - } - - *h = ngx_http_auth_pam_handler; - - return NGX_OK; -} - -static char * -ngx_http_auth_pam(ngx_conf_t *cf, void *post, void *data) -{ - ngx_str_t *realm = data; - - size_t len; - u_char *basic, *p; - - if (ngx_strcmp(realm->data, "off") == 0) { - realm->len = 0; - realm->data = (u_char *) ""; - - return NGX_CONF_OK; - } - - len = sizeof("Basic realm=\"") - 1 + realm->len + 1; - - basic = ngx_palloc(cf->pool, len); - if (basic == NULL) { - return NGX_CONF_ERROR; - } - - p = ngx_cpymem(basic, "Basic realm=\"", sizeof("Basic realm=\"") - 1); - p = ngx_cpymem(p, realm->data, realm->len); - *p = '"'; - - realm->len = len; - realm->data = basic; - - return NGX_CONF_OK; -} - -/* File: ngx_http_auth_pam_module.c */ diff --git a/debian/modules/http-cache-purge/CHANGES b/debian/modules/http-cache-purge/CHANGES deleted file mode 100644 index ead3cdf..0000000 --- a/debian/modules/http-cache-purge/CHANGES +++ /dev/null @@ -1,66 +0,0 @@ -2014-12-23 VERSION 2.3 - * Fix compatibility with nginx-1.7.9+. - -2014-12-02 VERSION 2.2 - * Fix compatibility with nginx-1.7.8+. - -2014-05-19 - * Fix build on Solaris with SunCC (Solaris Studio). - Reported by Jussi Sallinen. - -2013-03-19 VERSION 2.1 - * When enabled, cache purge will now catch all requests with - PURGE (or specified) method, even if cache isn't configured. - Previously, it would pass such requests to the upstream. - -2012-12-07 VERSION 2.0 - * Add alternative "same location" syntax. - From CloudFlare. - -2012-07-02 VERSION 1.6 - * Fix compatibility with nginx-1.3.2+. - Reported by MagicBear, patch from Ruslan Ermilov. - -2011-12-20 VERSION 1.5 - * Fix on-disk cache size calculation. - Since the initial release, recorded on-disk cache size was - decreased twice for purged content (once during cache purge - and once during subsequent cache update). - This resulted in recorded on-disk cache size being much - smaller than in reality, which could lead to on-disk cache - outgrowing defined "max_size" parameter. - Patch from Pyry Hakulinen. - -2011-10-05 VERSION 1.4 - * Add AIO support. - Requested by Emin Hasanov. - -2011-05-03 VERSION 1.3 - * Fix compatibility with nginx-1.0.1. - Reported by Sergey A. Osokin and Markus Linnala. - -2010-08-29 - * Fix compatibility with nginx-0.8.0 and versions older than - nginx-0.7.60. - -2010-08-11 VERSION 1.2 - * Fix various build scenarios with disabled upstream modules. - Reported by Johan Bergstroem. - - * Add ability to purge content from SCGI's cache. - Requested by Johan Bergstroem. - -2010-06-08 VERSION 1.1 - * Fix compatibility with nginx-0.8.40+. - - * Add ability to purge content from uWSGI's cache. - -2010-01-10 VERSION 1.0 - * Initial module release. - -2009-11-17 - * Fix patch compatibility with nginx-0.8.11+. - Reported by Bing Ran. - -2009-08-11 - * Initial patch release. diff --git a/debian/modules/http-cache-purge/LICENSE b/debian/modules/http-cache-purge/LICENSE deleted file mode 100644 index 0047538..0000000 --- a/debian/modules/http-cache-purge/LICENSE +++ /dev/null @@ -1,26 +0,0 @@ -Copyright (c) 2009-2014, FRiCKLE -Copyright (c) 2009-2014, Piotr Sikora -All rights reserved. - -This project was fully funded by yo.se. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/debian/modules/http-cache-purge/README.md b/debian/modules/http-cache-purge/README.md deleted file mode 100644 index 3b42e32..0000000 --- a/debian/modules/http-cache-purge/README.md +++ /dev/null @@ -1,171 +0,0 @@ -About -===== -`ngx_cache_purge` is `nginx` module which adds ability to purge content from -`FastCGI`, `proxy`, `SCGI` and `uWSGI` caches. - - -Sponsors -======== -Work on the original patch was fully funded by [yo.se](http://yo.se). - - -Status -====== -This module is production-ready. - - -Configuration directives (same location syntax) -=============================================== -fastcgi_cache_purge -------------------- -* **syntax**: `fastcgi_cache_purge on|off| [from all| [.. ]]` -* **default**: `none` -* **context**: `http`, `server`, `location` - -Allow purging of selected pages from `FastCGI`'s cache. - - -proxy_cache_purge ------------------ -* **syntax**: `proxy_cache_purge on|off| [from all| [.. ]]` -* **default**: `none` -* **context**: `http`, `server`, `location` - -Allow purging of selected pages from `proxy`'s cache. - - -scgi_cache_purge ----------------- -* **syntax**: `scgi_cache_purge on|off| [from all| [.. ]]` -* **default**: `none` -* **context**: `http`, `server`, `location` - -Allow purging of selected pages from `SCGI`'s cache. - - -uwsgi_cache_purge ------------------ -* **syntax**: `uwsgi_cache_purge on|off| [from all| [.. ]]` -* **default**: `none` -* **context**: `http`, `server`, `location` - -Allow purging of selected pages from `uWSGI`'s cache. - - -Configuration directives (separate location syntax) -=================================================== -fastcgi_cache_purge -------------------- -* **syntax**: `fastcgi_cache_purge zone_name key` -* **default**: `none` -* **context**: `location` - -Sets area and key used for purging selected pages from `FastCGI`'s cache. - - -proxy_cache_purge ------------------ -* **syntax**: `proxy_cache_purge zone_name key` -* **default**: `none` -* **context**: `location` - -Sets area and key used for purging selected pages from `proxy`'s cache. - - -scgi_cache_purge ----------------- -* **syntax**: `scgi_cache_purge zone_name key` -* **default**: `none` -* **context**: `location` - -Sets area and key used for purging selected pages from `SCGI`'s cache. - - -uwsgi_cache_purge ------------------ -* **syntax**: `uwsgi_cache_purge zone_name key` -* **default**: `none` -* **context**: `location` - -Sets area and key used for purging selected pages from `uWSGI`'s cache. - - -Sample configuration (same location syntax) -=========================================== - http { - proxy_cache_path /tmp/cache keys_zone=tmpcache:10m; - - server { - location / { - proxy_pass http://127.0.0.1:8000; - proxy_cache tmpcache; - proxy_cache_key $uri$is_args$args; - proxy_cache_purge PURGE from 127.0.0.1; - } - } - } - - -Sample configuration (separate location syntax) -=============================================== - http { - proxy_cache_path /tmp/cache keys_zone=tmpcache:10m; - - server { - location / { - proxy_pass http://127.0.0.1:8000; - proxy_cache tmpcache; - proxy_cache_key $uri$is_args$args; - } - - location ~ /purge(/.*) { - allow 127.0.0.1; - deny all; - proxy_cache_purge tmpcache $1$is_args$args; - } - } - } - - -Testing -======= -`ngx_cache_purge` comes with complete test suite based on [Test::Nginx](http://github.com/agentzh/test-nginx). - -You can test it by running: - -`$ prove` - - -License -======= - Copyright (c) 2009-2014, FRiCKLE - Copyright (c) 2009-2014, Piotr Sikora - All rights reserved. - - This project was fully funded by yo.se. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -See also -======== -- [ngx_slowfs_cache](http://github.com/FRiCKLE/ngx_slowfs_cache). diff --git a/debian/modules/http-cache-purge/TODO.md b/debian/modules/http-cache-purge/TODO.md deleted file mode 100644 index e279043..0000000 --- a/debian/modules/http-cache-purge/TODO.md +++ /dev/null @@ -1,7 +0,0 @@ -Features that __will not__ be added to `ngx_cache_purge`: - -* Support for prefixed purges (`/purge/images/*`). - Reason: Impossible with current cache implementation. - -* Support for wildcard/regex purges (`/purge/*.jpg`). - Reason: Impossible with current cache implementation. diff --git a/debian/modules/http-cache-purge/config b/debian/modules/http-cache-purge/config deleted file mode 100644 index 34f42ec..0000000 --- a/debian/modules/http-cache-purge/config +++ /dev/null @@ -1,21 +0,0 @@ -if [ "$HTTP_PROXY" = "YES" ]; then - have=NGX_HTTP_PROXY . auto/have -fi - -if [ "$HTTP_FASTCGI" = "YES" ]; then - have=NGX_HTTP_FASTCGI . auto/have -fi - -if [ "$HTTP_SCGI" = "YES" ]; then - have=NGX_HTTP_SCGI . auto/have -fi - -if [ "$HTTP_UWSGI" = "YES" ]; then - have=NGX_HTTP_UWSGI . auto/have -fi - -ngx_addon_name=ngx_http_cache_purge_module -HTTP_MODULES="$HTTP_MODULES ngx_http_cache_purge_module" -NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_cache_purge_module.c" - -have=NGX_CACHE_PURGE_MODULE . auto/have diff --git a/debian/modules/http-cache-purge/ngx_cache_purge_module.c b/debian/modules/http-cache-purge/ngx_cache_purge_module.c deleted file mode 100644 index 62d3818..0000000 --- a/debian/modules/http-cache-purge/ngx_cache_purge_module.c +++ /dev/null @@ -1,1803 +0,0 @@ -/* - * Copyright (c) 2009-2014, FRiCKLE - * Copyright (c) 2009-2014, Piotr Sikora - * All rights reserved. - * - * This project was fully funded by yo.se. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include -#include - - -#ifndef nginx_version -#error This module cannot be build against an unknown nginx version. -#endif - - -#if (NGX_HTTP_CACHE) - -typedef struct { - ngx_flag_t enable; - ngx_str_t method; - ngx_array_t *access; /* array of ngx_in_cidr_t */ - ngx_array_t *access6; /* array of ngx_in6_cidr_t */ -} ngx_http_cache_purge_conf_t; - -typedef struct { -# if (NGX_HTTP_FASTCGI) - ngx_http_cache_purge_conf_t fastcgi; -# endif /* NGX_HTTP_FASTCGI */ -# if (NGX_HTTP_PROXY) - ngx_http_cache_purge_conf_t proxy; -# endif /* NGX_HTTP_PROXY */ -# if (NGX_HTTP_SCGI) - ngx_http_cache_purge_conf_t scgi; -# endif /* NGX_HTTP_SCGI */ -# if (NGX_HTTP_UWSGI) - ngx_http_cache_purge_conf_t uwsgi; -# endif /* NGX_HTTP_UWSGI */ - - ngx_http_cache_purge_conf_t *conf; - ngx_http_handler_pt handler; - ngx_http_handler_pt original_handler; -} ngx_http_cache_purge_loc_conf_t; - -# if (NGX_HTTP_FASTCGI) -char *ngx_http_fastcgi_cache_purge_conf(ngx_conf_t *cf, - ngx_command_t *cmd, void *conf); -ngx_int_t ngx_http_fastcgi_cache_purge_handler(ngx_http_request_t *r); -# endif /* NGX_HTTP_FASTCGI */ - -# if (NGX_HTTP_PROXY) -char *ngx_http_proxy_cache_purge_conf(ngx_conf_t *cf, - ngx_command_t *cmd, void *conf); -ngx_int_t ngx_http_proxy_cache_purge_handler(ngx_http_request_t *r); -# endif /* NGX_HTTP_PROXY */ - -# if (NGX_HTTP_SCGI) -char *ngx_http_scgi_cache_purge_conf(ngx_conf_t *cf, - ngx_command_t *cmd, void *conf); -ngx_int_t ngx_http_scgi_cache_purge_handler(ngx_http_request_t *r); -# endif /* NGX_HTTP_SCGI */ - -# if (NGX_HTTP_UWSGI) -char *ngx_http_uwsgi_cache_purge_conf(ngx_conf_t *cf, - ngx_command_t *cmd, void *conf); -ngx_int_t ngx_http_uwsgi_cache_purge_handler(ngx_http_request_t *r); -# endif /* NGX_HTTP_UWSGI */ - -ngx_int_t ngx_http_cache_purge_access_handler(ngx_http_request_t *r); -ngx_int_t ngx_http_cache_purge_access(ngx_array_t *a, ngx_array_t *a6, - struct sockaddr *s); - -ngx_int_t ngx_http_cache_purge_send_response(ngx_http_request_t *r); -# if (nginx_version >= 1007009) -ngx_int_t ngx_http_cache_purge_cache_get(ngx_http_request_t *r, - ngx_http_upstream_t *u, ngx_http_file_cache_t **cache); -# endif /* nginx_version >= 1007009 */ -ngx_int_t ngx_http_cache_purge_init(ngx_http_request_t *r, - ngx_http_file_cache_t *cache, ngx_http_complex_value_t *cache_key); -void ngx_http_cache_purge_handler(ngx_http_request_t *r); - -ngx_int_t ngx_http_file_cache_purge(ngx_http_request_t *r); - -char *ngx_http_cache_purge_conf(ngx_conf_t *cf, - ngx_http_cache_purge_conf_t *cpcf); - -void *ngx_http_cache_purge_create_loc_conf(ngx_conf_t *cf); -char *ngx_http_cache_purge_merge_loc_conf(ngx_conf_t *cf, - void *parent, void *child); - -static ngx_command_t ngx_http_cache_purge_module_commands[] = { - -# if (NGX_HTTP_FASTCGI) - { ngx_string("fastcgi_cache_purge"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, - ngx_http_fastcgi_cache_purge_conf, - NGX_HTTP_LOC_CONF_OFFSET, - 0, - NULL }, -# endif /* NGX_HTTP_FASTCGI */ - -# if (NGX_HTTP_PROXY) - { ngx_string("proxy_cache_purge"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, - ngx_http_proxy_cache_purge_conf, - NGX_HTTP_LOC_CONF_OFFSET, - 0, - NULL }, -# endif /* NGX_HTTP_PROXY */ - -# if (NGX_HTTP_SCGI) - { ngx_string("scgi_cache_purge"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, - ngx_http_scgi_cache_purge_conf, - NGX_HTTP_LOC_CONF_OFFSET, - 0, - NULL }, -# endif /* NGX_HTTP_SCGI */ - -# if (NGX_HTTP_UWSGI) - { ngx_string("uwsgi_cache_purge"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, - ngx_http_uwsgi_cache_purge_conf, - NGX_HTTP_LOC_CONF_OFFSET, - 0, - NULL }, -# endif /* NGX_HTTP_UWSGI */ - - ngx_null_command -}; - -static ngx_http_module_t ngx_http_cache_purge_module_ctx = { - NULL, /* preconfiguration */ - NULL, /* postconfiguration */ - - NULL, /* create main configuration */ - NULL, /* init main configuration */ - - NULL, /* create server configuration */ - NULL, /* merge server configuration */ - - ngx_http_cache_purge_create_loc_conf, /* create location configuration */ - ngx_http_cache_purge_merge_loc_conf /* merge location configuration */ -}; - -ngx_module_t ngx_http_cache_purge_module = { - NGX_MODULE_V1, - &ngx_http_cache_purge_module_ctx, /* module context */ - ngx_http_cache_purge_module_commands, /* module directives */ - NGX_HTTP_MODULE, /* module type */ - NULL, /* init master */ - NULL, /* init module */ - NULL, /* init process */ - NULL, /* init thread */ - NULL, /* exit thread */ - NULL, /* exit process */ - NULL, /* exit master */ - NGX_MODULE_V1_PADDING -}; - -static char ngx_http_cache_purge_success_page_top[] = -"" CRLF -"Successful purge" CRLF -"" CRLF -"

Successful purge

" CRLF -; - -static char ngx_http_cache_purge_success_page_tail[] = -CRLF "
" CRLF -"
" NGINX_VER "
" CRLF -"" CRLF -"" CRLF -; - -# if (NGX_HTTP_FASTCGI) -extern ngx_module_t ngx_http_fastcgi_module; - -# if (nginx_version >= 1007009) - -typedef struct { - ngx_array_t caches; /* ngx_http_file_cache_t * */ -} ngx_http_fastcgi_main_conf_t; - -# endif /* nginx_version >= 1007009 */ - -# if (nginx_version >= 1007008) - -typedef struct { - ngx_array_t *flushes; - ngx_array_t *lengths; - ngx_array_t *values; - ngx_uint_t number; - ngx_hash_t hash; -} ngx_http_fastcgi_params_t; - -# endif /* nginx_version >= 1007008 */ - -typedef struct { - ngx_http_upstream_conf_t upstream; - - ngx_str_t index; - -# if (nginx_version >= 1007008) - ngx_http_fastcgi_params_t params; - ngx_http_fastcgi_params_t params_cache; -# else - ngx_array_t *flushes; - ngx_array_t *params_len; - ngx_array_t *params; -# endif /* nginx_version >= 1007008 */ - - ngx_array_t *params_source; - ngx_array_t *catch_stderr; - - ngx_array_t *fastcgi_lengths; - ngx_array_t *fastcgi_values; - -# if (nginx_version >= 8040) && (nginx_version < 1007008) - ngx_hash_t headers_hash; - ngx_uint_t header_params; -# endif /* nginx_version >= 8040 && nginx_version < 1007008 */ - -# if (nginx_version >= 1001004) - ngx_flag_t keep_conn; -# endif /* nginx_version >= 1001004 */ - - ngx_http_complex_value_t cache_key; - -# if (NGX_PCRE) - ngx_regex_t *split_regex; - ngx_str_t split_name; -# endif /* NGX_PCRE */ -} ngx_http_fastcgi_loc_conf_t; - -char * -ngx_http_fastcgi_cache_purge_conf(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf) -{ - ngx_http_compile_complex_value_t ccv; - ngx_http_cache_purge_loc_conf_t *cplcf; - ngx_http_core_loc_conf_t *clcf; - ngx_http_fastcgi_loc_conf_t *flcf; - ngx_str_t *value; -# if (nginx_version >= 1007009) - ngx_http_complex_value_t cv; -# endif /* nginx_version >= 1007009 */ - - cplcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_cache_purge_module); - - /* check for duplicates / collisions */ - if (cplcf->fastcgi.enable != NGX_CONF_UNSET) { - return "is duplicate"; - } - - if (cf->args->nelts != 3) { - return ngx_http_cache_purge_conf(cf, &cplcf->fastcgi); - } - - if (cf->cmd_type & (NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF)) { - return "(separate location syntax) is not allowed here"; - } - - flcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_fastcgi_module); - -# if (nginx_version >= 1007009) - if (flcf->upstream.cache > 0) -# else - if (flcf->upstream.cache != NGX_CONF_UNSET_PTR - && flcf->upstream.cache != NULL) -# endif /* nginx_version >= 1007009 */ - { - return "is incompatible with \"fastcgi_cache\""; - } - - if (flcf->upstream.upstream || flcf->fastcgi_lengths) { - return "is incompatible with \"fastcgi_pass\""; - } - - if (flcf->upstream.store > 0 -# if (nginx_version < 1007009) - || flcf->upstream.store_lengths -# endif /* nginx_version >= 1007009 */ - ) - { - return "is incompatible with \"fastcgi_store\""; - } - - value = cf->args->elts; - - /* set fastcgi_cache part */ -# if (nginx_version >= 1007009) - - flcf->upstream.cache = 1; - - ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); - - ccv.cf = cf; - ccv.value = &value[1]; - ccv.complex_value = &cv; - - if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { - return NGX_CONF_ERROR; - } - - if (cv.lengths != NULL) { - - flcf->upstream.cache_value = ngx_palloc(cf->pool, - sizeof(ngx_http_complex_value_t)); - if (flcf->upstream.cache_value == NULL) { - return NGX_CONF_ERROR; - } - - *flcf->upstream.cache_value = cv; - - } else { - - flcf->upstream.cache_zone = ngx_shared_memory_add(cf, &value[1], 0, - &ngx_http_fastcgi_module); - if (flcf->upstream.cache_zone == NULL) { - return NGX_CONF_ERROR; - } - } - -# else - - flcf->upstream.cache = ngx_shared_memory_add(cf, &value[1], 0, - &ngx_http_fastcgi_module); - if (flcf->upstream.cache == NULL) { - return NGX_CONF_ERROR; - } - -# endif /* nginx_version >= 1007009 */ - - /* set fastcgi_cache_key part */ - ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); - - ccv.cf = cf; - ccv.value = &value[2]; - ccv.complex_value = &flcf->cache_key; - - if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { - return NGX_CONF_ERROR; - } - - /* set handler */ - clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); - - cplcf->fastcgi.enable = 0; - clcf->handler = ngx_http_fastcgi_cache_purge_handler; - - return NGX_CONF_OK; -} - -ngx_int_t -ngx_http_fastcgi_cache_purge_handler(ngx_http_request_t *r) -{ - ngx_http_file_cache_t *cache; - ngx_http_fastcgi_loc_conf_t *flcf; -# if (nginx_version >= 1007009) - ngx_http_fastcgi_main_conf_t *fmcf; - ngx_int_t rc; -# endif /* nginx_version >= 1007009 */ - - if (ngx_http_upstream_create(r) != NGX_OK) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module); - - r->upstream->conf = &flcf->upstream; - -# if (nginx_version >= 1007009) - - fmcf = ngx_http_get_module_main_conf(r, ngx_http_fastcgi_module); - - r->upstream->caches = &fmcf->caches; - - rc = ngx_http_cache_purge_cache_get(r, r->upstream, &cache); - if (rc != NGX_OK) { - return rc; - } - -# else - - cache = flcf->upstream.cache->data; - -# endif /* nginx_version >= 1007009 */ - - if (ngx_http_cache_purge_init(r, cache, &flcf->cache_key) != NGX_OK) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - -# if (nginx_version >= 8011) - r->main->count++; -# endif - - ngx_http_cache_purge_handler(r); - - return NGX_DONE; -} -# endif /* NGX_HTTP_FASTCGI */ - -# if (NGX_HTTP_PROXY) -extern ngx_module_t ngx_http_proxy_module; - -typedef struct { - ngx_str_t key_start; - ngx_str_t schema; - ngx_str_t host_header; - ngx_str_t port; - ngx_str_t uri; -} ngx_http_proxy_vars_t; - -# if (nginx_version >= 1007009) - -typedef struct { - ngx_array_t caches; /* ngx_http_file_cache_t * */ -} ngx_http_proxy_main_conf_t; - -# endif /* nginx_version >= 1007009 */ - -# if (nginx_version >= 1007008) - -typedef struct { - ngx_array_t *flushes; - ngx_array_t *lengths; - ngx_array_t *values; - ngx_hash_t hash; -} ngx_http_proxy_headers_t; - -# endif /* nginx_version >= 1007008 */ - -typedef struct { - ngx_http_upstream_conf_t upstream; - -# if (nginx_version >= 1007008) - ngx_array_t *body_flushes; - ngx_array_t *body_lengths; - ngx_array_t *body_values; - ngx_str_t body_source; - - ngx_http_proxy_headers_t headers; - ngx_http_proxy_headers_t headers_cache; -# else - ngx_array_t *flushes; - ngx_array_t *body_set_len; - ngx_array_t *body_set; - ngx_array_t *headers_set_len; - ngx_array_t *headers_set; - ngx_hash_t headers_set_hash; -# endif /* nginx_version >= 1007008 */ - - ngx_array_t *headers_source; -# if (nginx_version < 8040) - ngx_array_t *headers_names; -# endif /* nginx_version < 8040 */ - - ngx_array_t *proxy_lengths; - ngx_array_t *proxy_values; - - ngx_array_t *redirects; -# if (nginx_version >= 1001015) - ngx_array_t *cookie_domains; - ngx_array_t *cookie_paths; -# endif /* nginx_version >= 1001015 */ - -# if (nginx_version < 1007008) - ngx_str_t body_source; -# endif /* nginx_version < 1007008 */ - - ngx_str_t method; - ngx_str_t location; - ngx_str_t url; - - ngx_http_complex_value_t cache_key; - - ngx_http_proxy_vars_t vars; - - ngx_flag_t redirect; - -# if (nginx_version >= 1001004) - ngx_uint_t http_version; -# endif /* nginx_version >= 1001004 */ - - ngx_uint_t headers_hash_max_size; - ngx_uint_t headers_hash_bucket_size; - -# if (NGX_HTTP_SSL) -# if (nginx_version >= 1005006) - ngx_uint_t ssl; - ngx_uint_t ssl_protocols; - ngx_str_t ssl_ciphers; -# endif /* nginx_version >= 1005006 */ -# if (nginx_version >= 1007000) - ngx_uint_t ssl_verify_depth; - ngx_str_t ssl_trusted_certificate; - ngx_str_t ssl_crl; -# endif /* nginx_version >= 1007000 */ -# if (nginx_version >= 1007008) - ngx_str_t ssl_certificate; - ngx_str_t ssl_certificate_key; - ngx_array_t *ssl_passwords; -# endif /* nginx_version >= 1007008 */ -# endif -} ngx_http_proxy_loc_conf_t; - -char * -ngx_http_proxy_cache_purge_conf(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) -{ - ngx_http_compile_complex_value_t ccv; - ngx_http_cache_purge_loc_conf_t *cplcf; - ngx_http_core_loc_conf_t *clcf; - ngx_http_proxy_loc_conf_t *plcf; - ngx_str_t *value; -# if (nginx_version >= 1007009) - ngx_http_complex_value_t cv; -# endif /* nginx_version >= 1007009 */ - - cplcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_cache_purge_module); - - /* check for duplicates / collisions */ - if (cplcf->proxy.enable != NGX_CONF_UNSET) { - return "is duplicate"; - } - - if (cf->args->nelts != 3) { - return ngx_http_cache_purge_conf(cf, &cplcf->proxy); - } - - if (cf->cmd_type & (NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF)) { - return "(separate location syntax) is not allowed here"; - } - - plcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_proxy_module); - -# if (nginx_version >= 1007009) - if (plcf->upstream.cache > 0) -# else - if (plcf->upstream.cache != NGX_CONF_UNSET_PTR - && plcf->upstream.cache != NULL) -# endif /* nginx_version >= 1007009 */ - { - return "is incompatible with \"proxy_cache\""; - } - - if (plcf->upstream.upstream || plcf->proxy_lengths) { - return "is incompatible with \"proxy_pass\""; - } - - if (plcf->upstream.store > 0 -# if (nginx_version < 1007009) - || plcf->upstream.store_lengths -# endif /* nginx_version >= 1007009 */ - ) - { - return "is incompatible with \"proxy_store\""; - } - - value = cf->args->elts; - - /* set proxy_cache part */ -# if (nginx_version >= 1007009) - - plcf->upstream.cache = 1; - - ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); - - ccv.cf = cf; - ccv.value = &value[1]; - ccv.complex_value = &cv; - - if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { - return NGX_CONF_ERROR; - } - - if (cv.lengths != NULL) { - - plcf->upstream.cache_value = ngx_palloc(cf->pool, - sizeof(ngx_http_complex_value_t)); - if (plcf->upstream.cache_value == NULL) { - return NGX_CONF_ERROR; - } - - *plcf->upstream.cache_value = cv; - - } else { - - plcf->upstream.cache_zone = ngx_shared_memory_add(cf, &value[1], 0, - &ngx_http_proxy_module); - if (plcf->upstream.cache_zone == NULL) { - return NGX_CONF_ERROR; - } - } - -# else - - plcf->upstream.cache = ngx_shared_memory_add(cf, &value[1], 0, - &ngx_http_proxy_module); - if (plcf->upstream.cache == NULL) { - return NGX_CONF_ERROR; - } - -# endif /* nginx_version >= 1007009 */ - - /* set proxy_cache_key part */ - ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); - - ccv.cf = cf; - ccv.value = &value[2]; - ccv.complex_value = &plcf->cache_key; - - if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { - return NGX_CONF_ERROR; - } - - /* set handler */ - clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); - - cplcf->proxy.enable = 0; - clcf->handler = ngx_http_proxy_cache_purge_handler; - - return NGX_CONF_OK; -} - -ngx_int_t -ngx_http_proxy_cache_purge_handler(ngx_http_request_t *r) -{ - ngx_http_file_cache_t *cache; - ngx_http_proxy_loc_conf_t *plcf; -# if (nginx_version >= 1007009) - ngx_http_proxy_main_conf_t *pmcf; - ngx_int_t rc; -# endif /* nginx_version >= 1007009 */ - - if (ngx_http_upstream_create(r) != NGX_OK) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module); - - r->upstream->conf = &plcf->upstream; - -# if (nginx_version >= 1007009) - - pmcf = ngx_http_get_module_main_conf(r, ngx_http_proxy_module); - - r->upstream->caches = &pmcf->caches; - - rc = ngx_http_cache_purge_cache_get(r, r->upstream, &cache); - if (rc != NGX_OK) { - return rc; - } - -# else - - cache = plcf->upstream.cache->data; - -# endif /* nginx_version >= 1007009 */ - - if (ngx_http_cache_purge_init(r, cache, &plcf->cache_key) != NGX_OK) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - -# if (nginx_version >= 8011) - r->main->count++; -# endif - - ngx_http_cache_purge_handler(r); - - return NGX_DONE; -} -# endif /* NGX_HTTP_PROXY */ - -# if (NGX_HTTP_SCGI) -extern ngx_module_t ngx_http_scgi_module; - -# if (nginx_version >= 1007009) - -typedef struct { - ngx_array_t caches; /* ngx_http_file_cache_t * */ -} ngx_http_scgi_main_conf_t; - -# endif /* nginx_version >= 1007009 */ - -# if (nginx_version >= 1007008) - -typedef struct { - ngx_array_t *flushes; - ngx_array_t *lengths; - ngx_array_t *values; - ngx_uint_t number; - ngx_hash_t hash; -} ngx_http_scgi_params_t; - -# endif /* nginx_version >= 1007008 */ - -typedef struct { - ngx_http_upstream_conf_t upstream; - -# if (nginx_version >= 1007008) - ngx_http_scgi_params_t params; - ngx_http_scgi_params_t params_cache; - ngx_array_t *params_source; -# else - ngx_array_t *flushes; - ngx_array_t *params_len; - ngx_array_t *params; - ngx_array_t *params_source; - - ngx_hash_t headers_hash; - ngx_uint_t header_params; -# endif /* nginx_version >= 1007008 */ - - ngx_array_t *scgi_lengths; - ngx_array_t *scgi_values; - - ngx_http_complex_value_t cache_key; -} ngx_http_scgi_loc_conf_t; - -char * -ngx_http_scgi_cache_purge_conf(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) -{ - ngx_http_compile_complex_value_t ccv; - ngx_http_cache_purge_loc_conf_t *cplcf; - ngx_http_core_loc_conf_t *clcf; - ngx_http_scgi_loc_conf_t *slcf; - ngx_str_t *value; -# if (nginx_version >= 1007009) - ngx_http_complex_value_t cv; -# endif /* nginx_version >= 1007009 */ - - cplcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_cache_purge_module); - - /* check for duplicates / collisions */ - if (cplcf->scgi.enable != NGX_CONF_UNSET) { - return "is duplicate"; - } - - if (cf->args->nelts != 3) { - return ngx_http_cache_purge_conf(cf, &cplcf->scgi); - } - - if (cf->cmd_type & (NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF)) { - return "(separate location syntax) is not allowed here"; - } - - slcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_scgi_module); - -# if (nginx_version >= 1007009) - if (slcf->upstream.cache > 0) -# else - if (slcf->upstream.cache != NGX_CONF_UNSET_PTR - && slcf->upstream.cache != NULL) -# endif /* nginx_version >= 1007009 */ - { - return "is incompatible with \"scgi_cache\""; - } - - if (slcf->upstream.upstream || slcf->scgi_lengths) { - return "is incompatible with \"scgi_pass\""; - } - - if (slcf->upstream.store > 0 -# if (nginx_version < 1007009) - || slcf->upstream.store_lengths -# endif /* nginx_version >= 1007009 */ - ) - { - return "is incompatible with \"scgi_store\""; - } - - value = cf->args->elts; - - /* set scgi_cache part */ -# if (nginx_version >= 1007009) - - slcf->upstream.cache = 1; - - ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); - - ccv.cf = cf; - ccv.value = &value[1]; - ccv.complex_value = &cv; - - if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { - return NGX_CONF_ERROR; - } - - if (cv.lengths != NULL) { - - slcf->upstream.cache_value = ngx_palloc(cf->pool, - sizeof(ngx_http_complex_value_t)); - if (slcf->upstream.cache_value == NULL) { - return NGX_CONF_ERROR; - } - - *slcf->upstream.cache_value = cv; - - } else { - - slcf->upstream.cache_zone = ngx_shared_memory_add(cf, &value[1], 0, - &ngx_http_scgi_module); - if (slcf->upstream.cache_zone == NULL) { - return NGX_CONF_ERROR; - } - } - -# else - - slcf->upstream.cache = ngx_shared_memory_add(cf, &value[1], 0, - &ngx_http_scgi_module); - if (slcf->upstream.cache == NULL) { - return NGX_CONF_ERROR; - } - -# endif /* nginx_version >= 1007009 */ - - /* set scgi_cache_key part */ - ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); - - ccv.cf = cf; - ccv.value = &value[2]; - ccv.complex_value = &slcf->cache_key; - - if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { - return NGX_CONF_ERROR; - } - - /* set handler */ - clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); - - cplcf->scgi.enable = 0; - clcf->handler = ngx_http_scgi_cache_purge_handler; - - return NGX_CONF_OK; -} - -ngx_int_t -ngx_http_scgi_cache_purge_handler(ngx_http_request_t *r) -{ - ngx_http_file_cache_t *cache; - ngx_http_scgi_loc_conf_t *slcf; -# if (nginx_version >= 1007009) - ngx_http_scgi_main_conf_t *smcf; - ngx_int_t rc; -# endif /* nginx_version >= 1007009 */ - - if (ngx_http_upstream_create(r) != NGX_OK) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - slcf = ngx_http_get_module_loc_conf(r, ngx_http_scgi_module); - - r->upstream->conf = &slcf->upstream; - -# if (nginx_version >= 1007009) - - smcf = ngx_http_get_module_main_conf(r, ngx_http_scgi_module); - - r->upstream->caches = &smcf->caches; - - rc = ngx_http_cache_purge_cache_get(r, r->upstream, &cache); - if (rc != NGX_OK) { - return rc; - } - -# else - - cache = slcf->upstream.cache->data; - -# endif /* nginx_version >= 1007009 */ - - if (ngx_http_cache_purge_init(r, cache, &slcf->cache_key) != NGX_OK) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - -# if (nginx_version >= 8011) - r->main->count++; -# endif - - ngx_http_cache_purge_handler(r); - - return NGX_DONE; -} -# endif /* NGX_HTTP_SCGI */ - -# if (NGX_HTTP_UWSGI) -extern ngx_module_t ngx_http_uwsgi_module; - -# if (nginx_version >= 1007009) - -typedef struct { - ngx_array_t caches; /* ngx_http_file_cache_t * */ -} ngx_http_uwsgi_main_conf_t; - -# endif /* nginx_version >= 1007009 */ - -# if (nginx_version >= 1007008) - -typedef struct { - ngx_array_t *flushes; - ngx_array_t *lengths; - ngx_array_t *values; - ngx_uint_t number; - ngx_hash_t hash; -} ngx_http_uwsgi_params_t; - -# endif /* nginx_version >= 1007008 */ - -typedef struct { - ngx_http_upstream_conf_t upstream; - -# if (nginx_version >= 1007008) - ngx_http_uwsgi_params_t params; - ngx_http_uwsgi_params_t params_cache; - ngx_array_t *params_source; -# else - ngx_array_t *flushes; - ngx_array_t *params_len; - ngx_array_t *params; - ngx_array_t *params_source; - - ngx_hash_t headers_hash; - ngx_uint_t header_params; -# endif /* nginx_version >= 1007008 */ - - ngx_array_t *uwsgi_lengths; - ngx_array_t *uwsgi_values; - - ngx_http_complex_value_t cache_key; - - ngx_str_t uwsgi_string; - - ngx_uint_t modifier1; - ngx_uint_t modifier2; - -# if (NGX_HTTP_SSL) -# if (nginx_version >= 1005008) - ngx_uint_t ssl; - ngx_uint_t ssl_protocols; - ngx_str_t ssl_ciphers; -# endif /* nginx_version >= 1005008 */ -# if (nginx_version >= 1007000) - ngx_uint_t ssl_verify_depth; - ngx_str_t ssl_trusted_certificate; - ngx_str_t ssl_crl; -# endif /* nginx_version >= 1007000 */ -# if (nginx_version >= 1007008) - ngx_str_t ssl_certificate; - ngx_str_t ssl_certificate_key; - ngx_array_t *ssl_passwords; -# endif /* nginx_version >= 1007008 */ -# endif -} ngx_http_uwsgi_loc_conf_t; - -char * -ngx_http_uwsgi_cache_purge_conf(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) -{ - ngx_http_compile_complex_value_t ccv; - ngx_http_cache_purge_loc_conf_t *cplcf; - ngx_http_core_loc_conf_t *clcf; - ngx_http_uwsgi_loc_conf_t *ulcf; - ngx_str_t *value; -# if (nginx_version >= 1007009) - ngx_http_complex_value_t cv; -# endif /* nginx_version >= 1007009 */ - - cplcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_cache_purge_module); - - /* check for duplicates / collisions */ - if (cplcf->uwsgi.enable != NGX_CONF_UNSET) { - return "is duplicate"; - } - - if (cf->args->nelts != 3) { - return ngx_http_cache_purge_conf(cf, &cplcf->uwsgi); - } - - if (cf->cmd_type & (NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF)) { - return "(separate location syntax) is not allowed here"; - } - - ulcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_uwsgi_module); - -# if (nginx_version >= 1007009) - if (ulcf->upstream.cache > 0) -# else - if (ulcf->upstream.cache != NGX_CONF_UNSET_PTR - && ulcf->upstream.cache != NULL) -# endif /* nginx_version >= 1007009 */ - { - return "is incompatible with \"uwsgi_cache\""; - } - - if (ulcf->upstream.upstream || ulcf->uwsgi_lengths) { - return "is incompatible with \"uwsgi_pass\""; - } - - if (ulcf->upstream.store > 0 -# if (nginx_version < 1007009) - || ulcf->upstream.store_lengths -# endif /* nginx_version >= 1007009 */ - ) - { - return "is incompatible with \"uwsgi_store\""; - } - - value = cf->args->elts; - - /* set uwsgi_cache part */ -# if (nginx_version >= 1007009) - - ulcf->upstream.cache = 1; - - ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); - - ccv.cf = cf; - ccv.value = &value[1]; - ccv.complex_value = &cv; - - if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { - return NGX_CONF_ERROR; - } - - if (cv.lengths != NULL) { - - ulcf->upstream.cache_value = ngx_palloc(cf->pool, - sizeof(ngx_http_complex_value_t)); - if (ulcf->upstream.cache_value == NULL) { - return NGX_CONF_ERROR; - } - - *ulcf->upstream.cache_value = cv; - - } else { - - ulcf->upstream.cache_zone = ngx_shared_memory_add(cf, &value[1], 0, - &ngx_http_uwsgi_module); - if (ulcf->upstream.cache_zone == NULL) { - return NGX_CONF_ERROR; - } - } - -# else - - ulcf->upstream.cache = ngx_shared_memory_add(cf, &value[1], 0, - &ngx_http_uwsgi_module); - if (ulcf->upstream.cache == NULL) { - return NGX_CONF_ERROR; - } - -# endif /* nginx_version >= 1007009 */ - - /* set uwsgi_cache_key part */ - ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); - - ccv.cf = cf; - ccv.value = &value[2]; - ccv.complex_value = &ulcf->cache_key; - - if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { - return NGX_CONF_ERROR; - } - - /* set handler */ - clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); - - cplcf->uwsgi.enable = 0; - clcf->handler = ngx_http_uwsgi_cache_purge_handler; - - return NGX_CONF_OK; -} - -ngx_int_t -ngx_http_uwsgi_cache_purge_handler(ngx_http_request_t *r) -{ - ngx_http_file_cache_t *cache; - ngx_http_uwsgi_loc_conf_t *ulcf; -# if (nginx_version >= 1007009) - ngx_http_uwsgi_main_conf_t *umcf; - ngx_int_t rc; -# endif /* nginx_version >= 1007009 */ - - if (ngx_http_upstream_create(r) != NGX_OK) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - ulcf = ngx_http_get_module_loc_conf(r, ngx_http_uwsgi_module); - - r->upstream->conf = &ulcf->upstream; - -# if (nginx_version >= 1007009) - - umcf = ngx_http_get_module_main_conf(r, ngx_http_uwsgi_module); - - r->upstream->caches = &umcf->caches; - - rc = ngx_http_cache_purge_cache_get(r, r->upstream, &cache); - if (rc != NGX_OK) { - return rc; - } - -# else - - cache = ulcf->upstream.cache->data; - -# endif /* nginx_version >= 1007009 */ - - if (ngx_http_cache_purge_init(r, cache, &ulcf->cache_key) != NGX_OK) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - -# if (nginx_version >= 8011) - r->main->count++; -# endif - - ngx_http_cache_purge_handler(r); - - return NGX_DONE; -} -# endif /* NGX_HTTP_UWSGI */ - -ngx_int_t -ngx_http_cache_purge_access_handler(ngx_http_request_t *r) -{ - ngx_http_cache_purge_loc_conf_t *cplcf; - - cplcf = ngx_http_get_module_loc_conf(r, ngx_http_cache_purge_module); - - if (r->method_name.len != cplcf->conf->method.len - || (ngx_strncmp(r->method_name.data, cplcf->conf->method.data, - r->method_name.len))) - { - return cplcf->original_handler(r); - } - - if ((cplcf->conf->access || cplcf->conf->access6) - && ngx_http_cache_purge_access(cplcf->conf->access, - cplcf->conf->access6, - r->connection->sockaddr) != NGX_OK) - { - return NGX_HTTP_FORBIDDEN; - } - - if (cplcf->handler == NULL) { - return NGX_HTTP_NOT_FOUND; - } - - return cplcf->handler(r); -} - -ngx_int_t -ngx_http_cache_purge_access(ngx_array_t *access, ngx_array_t *access6, - struct sockaddr *s) -{ - in_addr_t inaddr; - ngx_in_cidr_t *a; - ngx_uint_t i; -# if (NGX_HAVE_INET6) - struct in6_addr *inaddr6; - ngx_in6_cidr_t *a6; - u_char *p; - ngx_uint_t n; -# endif /* NGX_HAVE_INET6 */ - - switch (s->sa_family) { - case AF_INET: - if (access == NULL) { - return NGX_DECLINED; - } - - inaddr = ((struct sockaddr_in *) s)->sin_addr.s_addr; - -# if (NGX_HAVE_INET6) - ipv4: -# endif /* NGX_HAVE_INET6 */ - - a = access->elts; - for (i = 0; i < access->nelts; i++) { - if ((inaddr & a[i].mask) == a[i].addr) { - return NGX_OK; - } - } - - return NGX_DECLINED; - -# if (NGX_HAVE_INET6) - case AF_INET6: - inaddr6 = &((struct sockaddr_in6 *) s)->sin6_addr; - p = inaddr6->s6_addr; - - if (access && IN6_IS_ADDR_V4MAPPED(inaddr6)) { - inaddr = p[12] << 24; - inaddr += p[13] << 16; - inaddr += p[14] << 8; - inaddr += p[15]; - inaddr = htonl(inaddr); - - goto ipv4; - } - - if (access6 == NULL) { - return NGX_DECLINED; - } - - a6 = access6->elts; - for (i = 0; i < access6->nelts; i++) { - for (n = 0; n < 16; n++) { - if ((p[n] & a6[i].mask.s6_addr[n]) != a6[i].addr.s6_addr[n]) { - goto next; - } - } - - return NGX_OK; - - next: - continue; - } - - return NGX_DECLINED; -# endif /* NGX_HAVE_INET6 */ - } - - return NGX_DECLINED; -} - -ngx_int_t -ngx_http_cache_purge_send_response(ngx_http_request_t *r) -{ - ngx_chain_t out; - ngx_buf_t *b; - ngx_str_t *key; - ngx_int_t rc; - size_t len; - - key = r->cache->keys.elts; - - len = sizeof(ngx_http_cache_purge_success_page_top) - 1 - + sizeof(ngx_http_cache_purge_success_page_tail) - 1 - + sizeof("
Key : ") - 1 + sizeof(CRLF "
Path: ") - 1 - + key[0].len + r->cache->file.name.len; - - r->headers_out.content_type.len = sizeof("text/html") - 1; - r->headers_out.content_type.data = (u_char *) "text/html"; - r->headers_out.status = NGX_HTTP_OK; - r->headers_out.content_length_n = len; - - if (r->method == NGX_HTTP_HEAD) { - rc = ngx_http_send_header(r); - if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { - return rc; - } - } - - b = ngx_create_temp_buf(r->pool, len); - if (b == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - out.buf = b; - out.next = NULL; - - b->last = ngx_cpymem(b->last, ngx_http_cache_purge_success_page_top, - sizeof(ngx_http_cache_purge_success_page_top) - 1); - b->last = ngx_cpymem(b->last, "
Key : ", sizeof("
Key : ") - 1); - b->last = ngx_cpymem(b->last, key[0].data, key[0].len); - b->last = ngx_cpymem(b->last, CRLF "
Path: ", - sizeof(CRLF "
Path: ") - 1); - b->last = ngx_cpymem(b->last, r->cache->file.name.data, - r->cache->file.name.len); - b->last = ngx_cpymem(b->last, ngx_http_cache_purge_success_page_tail, - sizeof(ngx_http_cache_purge_success_page_tail) - 1); - b->last_buf = 1; - - rc = ngx_http_send_header(r); - if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { - return rc; - } - - return ngx_http_output_filter(r, &out); -} - -# if (nginx_version >= 1007009) - -/* - * Based on: ngx_http_upstream.c/ngx_http_upstream_cache_get - * Copyright (C) Igor Sysoev - * Copyright (C) Nginx, Inc. - */ -ngx_int_t -ngx_http_cache_purge_cache_get(ngx_http_request_t *r, ngx_http_upstream_t *u, - ngx_http_file_cache_t **cache) -{ - ngx_str_t *name, val; - ngx_uint_t i; - ngx_http_file_cache_t **caches; - - if (u->conf->cache_zone) { - *cache = u->conf->cache_zone->data; - return NGX_OK; - } - - if (ngx_http_complex_value(r, u->conf->cache_value, &val) != NGX_OK) { - return NGX_ERROR; - } - - if (val.len == 0 - || (val.len == 3 && ngx_strncmp(val.data, "off", 3) == 0)) - { - return NGX_DECLINED; - } - - caches = u->caches->elts; - - for (i = 0; i < u->caches->nelts; i++) { - name = &caches[i]->shm_zone->shm.name; - - if (name->len == val.len - && ngx_strncmp(name->data, val.data, val.len) == 0) - { - *cache = caches[i]; - return NGX_OK; - } - } - - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "cache \"%V\" not found", &val); - - return NGX_ERROR; -} - -# endif /* nginx_version >= 1007009 */ - -ngx_int_t -ngx_http_cache_purge_init(ngx_http_request_t *r, ngx_http_file_cache_t *cache, - ngx_http_complex_value_t *cache_key) -{ - ngx_http_cache_t *c; - ngx_str_t *key; - ngx_int_t rc; - - rc = ngx_http_discard_request_body(r); - if (rc != NGX_OK) { - return NGX_ERROR; - } - - c = ngx_pcalloc(r->pool, sizeof(ngx_http_cache_t)); - if (c == NULL) { - return NGX_ERROR; - } - - rc = ngx_array_init(&c->keys, r->pool, 1, sizeof(ngx_str_t)); - if (rc != NGX_OK) { - return NGX_ERROR; - } - - key = ngx_array_push(&c->keys); - if (key == NULL) { - return NGX_ERROR; - } - - rc = ngx_http_complex_value(r, cache_key, key); - if (rc != NGX_OK) { - return NGX_ERROR; - } - - r->cache = c; - c->body_start = ngx_pagesize; - c->file_cache = cache; - c->file.log = r->connection->log; - - ngx_http_file_cache_create_key(r); - - return NGX_OK; -} - -void -ngx_http_cache_purge_handler(ngx_http_request_t *r) -{ - ngx_int_t rc; - -# if (NGX_HAVE_FILE_AIO) - if (r->aio) { - return; - } -# endif - - rc = ngx_http_file_cache_purge(r); - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http file cache purge: %i, \"%s\"", - rc, r->cache->file.name.data); - - switch (rc) { - case NGX_OK: - r->write_event_handler = ngx_http_request_empty_handler; - ngx_http_finalize_request(r, ngx_http_cache_purge_send_response(r)); - return; - case NGX_DECLINED: - ngx_http_finalize_request(r, NGX_HTTP_NOT_FOUND); - return; -# if (NGX_HAVE_FILE_AIO) - case NGX_AGAIN: - r->write_event_handler = ngx_http_cache_purge_handler; - return; -# endif - default: - ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); - } -} - -ngx_int_t -ngx_http_file_cache_purge(ngx_http_request_t *r) -{ - ngx_http_file_cache_t *cache; - ngx_http_cache_t *c; - - switch (ngx_http_file_cache_open(r)) { - case NGX_OK: - case NGX_HTTP_CACHE_STALE: -# if (nginx_version >= 8001) \ - || ((nginx_version < 8000) && (nginx_version >= 7060)) - case NGX_HTTP_CACHE_UPDATING: -# endif - break; - case NGX_DECLINED: - return NGX_DECLINED; -# if (NGX_HAVE_FILE_AIO) - case NGX_AGAIN: - return NGX_AGAIN; -# endif - default: - return NGX_ERROR; - } - - c = r->cache; - cache = c->file_cache; - - /* - * delete file from disk but *keep* in-memory node, - * because other requests might still point to it. - */ - - ngx_shmtx_lock(&cache->shpool->mutex); - - if (!c->node->exists) { - /* race between concurrent purges, backoff */ - ngx_shmtx_unlock(&cache->shpool->mutex); - return NGX_DECLINED; - } - -# if (nginx_version >= 1000001) - cache->sh->size -= c->node->fs_size; - c->node->fs_size = 0; -# else - cache->sh->size -= (c->node->length + cache->bsize - 1) / cache->bsize; - c->node->length = 0; -# endif - - c->node->exists = 0; -# if (nginx_version >= 8001) \ - || ((nginx_version < 8000) && (nginx_version >= 7060)) - c->node->updating = 0; -# endif - - ngx_shmtx_unlock(&cache->shpool->mutex); - - if (ngx_delete_file(c->file.name.data) == NGX_FILE_ERROR) { - /* entry in error log is enough, don't notice client */ - ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno, - ngx_delete_file_n " \"%s\" failed", c->file.name.data); - } - - /* file deleted from cache */ - return NGX_OK; -} - -char * -ngx_http_cache_purge_conf(ngx_conf_t *cf, ngx_http_cache_purge_conf_t *cpcf) -{ - ngx_cidr_t cidr; - ngx_in_cidr_t *access; -# if (NGX_HAVE_INET6) - ngx_in6_cidr_t *access6; -# endif /* NGX_HAVE_INET6 */ - ngx_str_t *value; - ngx_int_t rc; - ngx_uint_t i; - - value = cf->args->elts; - - if (ngx_strcmp(value[1].data, "off") == 0) { - cpcf->enable = 0; - return NGX_CONF_OK; - - } else if (ngx_strcmp(value[1].data, "on") == 0) { - ngx_str_set(&cpcf->method, "PURGE"); - - } else { - cpcf->method = value[1]; - } - - if (cf->args->nelts < 4) { - cpcf->enable = 1; - return NGX_CONF_OK; - } - - /* sanity check */ - if (ngx_strcmp(value[2].data, "from") != 0) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid parameter \"%V\", expected" - " \"from\" keyword", &value[2]); - return NGX_CONF_ERROR; - } - - if (ngx_strcmp(value[3].data, "all") == 0) { - cpcf->enable = 1; - return NGX_CONF_OK; - } - - for (i = 3; i < cf->args->nelts; i++) { - rc = ngx_ptocidr(&value[i], &cidr); - - if (rc == NGX_ERROR) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid parameter \"%V\"", &value[i]); - return NGX_CONF_ERROR; - } - - if (rc == NGX_DONE) { - ngx_conf_log_error(NGX_LOG_WARN, cf, 0, - "low address bits of %V are meaningless", - &value[i]); - } - - switch (cidr.family) { - case AF_INET: - if (cpcf->access == NULL) { - cpcf->access = ngx_array_create(cf->pool, cf->args->nelts - 3, - sizeof(ngx_in_cidr_t)); - if (cpcf->access == NULL) { - return NGX_CONF_ERROR; - } - } - - access = ngx_array_push(cpcf->access); - if (access == NULL) { - return NGX_CONF_ERROR; - } - - access->mask = cidr.u.in.mask; - access->addr = cidr.u.in.addr; - - break; - -# if (NGX_HAVE_INET6) - case AF_INET6: - if (cpcf->access6 == NULL) { - cpcf->access6 = ngx_array_create(cf->pool, cf->args->nelts - 3, - sizeof(ngx_in6_cidr_t)); - if (cpcf->access6 == NULL) { - return NGX_CONF_ERROR; - } - } - - access6 = ngx_array_push(cpcf->access6); - if (access6 == NULL) { - return NGX_CONF_ERROR; - } - - access6->mask = cidr.u.in6.mask; - access6->addr = cidr.u.in6.addr; - - break; -# endif /* NGX_HAVE_INET6 */ - } - } - - cpcf->enable = 1; - - return NGX_CONF_OK; -} - -void -ngx_http_cache_purge_merge_conf(ngx_http_cache_purge_conf_t *conf, - ngx_http_cache_purge_conf_t *prev) -{ - if (conf->enable == NGX_CONF_UNSET) { - if (prev->enable == 1) { - conf->enable = prev->enable; - conf->method = prev->method; - conf->access = prev->access; - conf->access6 = prev->access6; - - } else { - conf->enable = 0; - } - } -} - -void * -ngx_http_cache_purge_create_loc_conf(ngx_conf_t *cf) -{ - ngx_http_cache_purge_loc_conf_t *conf; - - conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_cache_purge_loc_conf_t)); - if (conf == NULL) { - return NULL; - } - - /* - * set by ngx_pcalloc(): - * - * conf->*.method = { 0, NULL } - * conf->*.access = NULL - * conf->*.access6 = NULL - * conf->handler = NULL - * conf->original_handler = NULL - */ - -# if (NGX_HTTP_FASTCGI) - conf->fastcgi.enable = NGX_CONF_UNSET; -# endif /* NGX_HTTP_FASTCGI */ -# if (NGX_HTTP_PROXY) - conf->proxy.enable = NGX_CONF_UNSET; -# endif /* NGX_HTTP_PROXY */ -# if (NGX_HTTP_SCGI) - conf->scgi.enable = NGX_CONF_UNSET; -# endif /* NGX_HTTP_SCGI */ -# if (NGX_HTTP_UWSGI) - conf->uwsgi.enable = NGX_CONF_UNSET; -# endif /* NGX_HTTP_UWSGI */ - - conf->conf = NGX_CONF_UNSET_PTR; - - return conf; -} - -char * -ngx_http_cache_purge_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) -{ - ngx_http_cache_purge_loc_conf_t *prev = parent; - ngx_http_cache_purge_loc_conf_t *conf = child; - ngx_http_core_loc_conf_t *clcf; -# if (NGX_HTTP_FASTCGI) - ngx_http_fastcgi_loc_conf_t *flcf; -# endif /* NGX_HTTP_FASTCGI */ -# if (NGX_HTTP_PROXY) - ngx_http_proxy_loc_conf_t *plcf; -# endif /* NGX_HTTP_PROXY */ -# if (NGX_HTTP_SCGI) - ngx_http_scgi_loc_conf_t *slcf; -# endif /* NGX_HTTP_SCGI */ -# if (NGX_HTTP_UWSGI) - ngx_http_uwsgi_loc_conf_t *ulcf; -# endif /* NGX_HTTP_UWSGI */ - - clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); - -# if (NGX_HTTP_FASTCGI) - ngx_http_cache_purge_merge_conf(&conf->fastcgi, &prev->fastcgi); - - if (conf->fastcgi.enable && clcf->handler != NULL) { - flcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_fastcgi_module); - - if (flcf->upstream.upstream || flcf->fastcgi_lengths) { - conf->conf = &conf->fastcgi; - conf->handler = flcf->upstream.cache - ? ngx_http_fastcgi_cache_purge_handler : NULL; - conf->original_handler = clcf->handler; - - clcf->handler = ngx_http_cache_purge_access_handler; - - return NGX_CONF_OK; - } - } -# endif /* NGX_HTTP_FASTCGI */ - -# if (NGX_HTTP_PROXY) - ngx_http_cache_purge_merge_conf(&conf->proxy, &prev->proxy); - - if (conf->proxy.enable && clcf->handler != NULL) { - plcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_proxy_module); - - if (plcf->upstream.upstream || plcf->proxy_lengths) { - conf->conf = &conf->proxy; - conf->handler = plcf->upstream.cache - ? ngx_http_proxy_cache_purge_handler : NULL; - conf->original_handler = clcf->handler; - - clcf->handler = ngx_http_cache_purge_access_handler; - - return NGX_CONF_OK; - } - } -# endif /* NGX_HTTP_PROXY */ - -# if (NGX_HTTP_SCGI) - ngx_http_cache_purge_merge_conf(&conf->scgi, &prev->scgi); - - if (conf->scgi.enable && clcf->handler != NULL) { - slcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_scgi_module); - - if (slcf->upstream.upstream || slcf->scgi_lengths) { - conf->conf = &conf->scgi; - conf->handler = slcf->upstream.cache - ? ngx_http_scgi_cache_purge_handler : NULL; - conf->original_handler = clcf->handler; - clcf->handler = ngx_http_cache_purge_access_handler; - - return NGX_CONF_OK; - } - } -# endif /* NGX_HTTP_SCGI */ - -# if (NGX_HTTP_UWSGI) - ngx_http_cache_purge_merge_conf(&conf->uwsgi, &prev->uwsgi); - - if (conf->uwsgi.enable && clcf->handler != NULL) { - ulcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_uwsgi_module); - - if (ulcf->upstream.upstream || ulcf->uwsgi_lengths) { - conf->conf = &conf->uwsgi; - conf->handler = ulcf->upstream.cache - ? ngx_http_uwsgi_cache_purge_handler : NULL; - conf->original_handler = clcf->handler; - - clcf->handler = ngx_http_cache_purge_access_handler; - - return NGX_CONF_OK; - } - } -# endif /* NGX_HTTP_UWSGI */ - - ngx_conf_merge_ptr_value(conf->conf, prev->conf, NULL); - - if (conf->handler == NULL) { - conf->handler = prev->handler; - } - - if (conf->original_handler == NULL) { - conf->original_handler = prev->original_handler; - } - - return NGX_CONF_OK; -} - -#else /* !NGX_HTTP_CACHE */ - -static ngx_http_module_t ngx_http_cache_purge_module_ctx = { - NULL, /* preconfiguration */ - NULL, /* postconfiguration */ - - NULL, /* create main configuration */ - NULL, /* init main configuration */ - - NULL, /* create server configuration */ - NULL, /* merge server configuration */ - - NULL, /* create location configuration */ - NULL, /* merge location configuration */ -}; - -ngx_module_t ngx_http_cache_purge_module = { - NGX_MODULE_V1, - &ngx_http_cache_purge_module_ctx, /* module context */ - NULL, /* module directives */ - NGX_HTTP_MODULE, /* module type */ - NULL, /* init master */ - NULL, /* init module */ - NULL, /* init process */ - NULL, /* init thread */ - NULL, /* exit thread */ - NULL, /* exit process */ - NULL, /* exit master */ - NGX_MODULE_V1_PADDING -}; - -#endif /* NGX_HTTP_CACHE */ diff --git a/debian/modules/http-cache-purge/t/proxy1.t b/debian/modules/http-cache-purge/t/proxy1.t deleted file mode 100644 index e5c0054..0000000 --- a/debian/modules/http-cache-purge/t/proxy1.t +++ /dev/null @@ -1,136 +0,0 @@ -# vi:filetype=perl - -use lib 'lib'; -use Test::Nginx::Socket; - -repeat_each(1); - -plan tests => repeat_each() * (blocks() * 4 + 3 * 1); - -our $http_config = <<'_EOC_'; - proxy_cache_path /tmp/ngx_cache_purge_cache keys_zone=test_cache:10m; - proxy_temp_path /tmp/ngx_cache_purge_temp 1 2; -_EOC_ - -our $config = <<'_EOC_'; - location /proxy { - proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd; - proxy_cache test_cache; - proxy_cache_key $uri$is_args$args; - proxy_cache_valid 3m; - add_header X-Cache-Status $upstream_cache_status; - } - - location ~ /purge(/.*) { - proxy_cache_purge test_cache $1$is_args$args; - } - - location = /etc/passwd { - root /; - } -_EOC_ - -worker_connections(128); -no_shuffle(); -run_tests(); - -no_diff(); - -__DATA__ - -=== TEST 1: prepare ---- http_config eval: $::http_config ---- config eval: $::config ---- request -GET /proxy/passwd ---- error_code: 200 ---- response_headers -Content-Type: text/plain ---- response_body_like: root ---- timeout: 10 ---- no_error_log eval -qr/\[(warn|error|crit|alert|emerg)\]/ ---- skip_nginx2: 4: < 0.8.3 or < 0.7.62 - - - -=== TEST 2: get from cache ---- http_config eval: $::http_config ---- config eval: $::config ---- request -GET /proxy/passwd ---- error_code: 200 ---- response_headers -Content-Type: text/plain -X-Cache-Status: HIT ---- response_body_like: root ---- timeout: 10 ---- no_error_log eval -qr/\[(warn|error|crit|alert|emerg)\]/ ---- skip_nginx2: 5: < 0.8.3 or < 0.7.62 - - - -=== TEST 3: purge from cache ---- http_config eval: $::http_config ---- config eval: $::config ---- request -PURGE /purge/proxy/passwd ---- error_code: 200 ---- response_headers -Content-Type: text/html ---- response_body_like: Successful purge ---- timeout: 10 ---- no_error_log eval -qr/\[(warn|error|crit|alert|emerg)\]/ ---- skip_nginx2: 4: < 0.8.3 or < 0.7.62 - - - -=== TEST 4: purge from empty cache ---- http_config eval: $::http_config ---- config eval: $::config ---- request -PURGE /purge/proxy/passwd ---- error_code: 404 ---- response_headers -Content-Type: text/html ---- response_body_like: 404 Not Found ---- timeout: 10 ---- no_error_log eval -qr/\[(warn|error|crit|alert|emerg)\]/ ---- skip_nginx2: 4: < 0.8.3 or < 0.7.62 - - - -=== TEST 5: get from source ---- http_config eval: $::http_config ---- config eval: $::config ---- request -GET /proxy/passwd ---- error_code: 200 ---- response_headers -Content-Type: text/plain -X-Cache-Status: MISS ---- response_body_like: root ---- timeout: 10 ---- no_error_log eval -qr/\[(warn|error|crit|alert|emerg)\]/ ---- skip_nginx2: 5: < 0.8.3 or < 0.7.62 - - - -=== TEST 6: get from cache ---- http_config eval: $::http_config ---- config eval: $::config ---- request -GET /proxy/passwd ---- error_code: 200 ---- response_headers -Content-Type: text/plain -X-Cache-Status: HIT ---- response_body_like: root ---- timeout: 10 ---- no_error_log eval -qr/\[(warn|error|crit|alert|emerg)\]/ ---- skip_nginx2: 5: < 0.8.3 or < 0.7.62 diff --git a/debian/modules/http-cache-purge/t/proxy1_vars.t b/debian/modules/http-cache-purge/t/proxy1_vars.t deleted file mode 100644 index af3553d..0000000 --- a/debian/modules/http-cache-purge/t/proxy1_vars.t +++ /dev/null @@ -1,138 +0,0 @@ -# vi:filetype=perl - -use lib 'lib'; -use Test::Nginx::Socket; - -repeat_each(1); - -plan tests => repeat_each() * (blocks() * 4 + 3 * 1); - -our $http_config = <<'_EOC_'; - proxy_cache_path /tmp/ngx_cache_purge_cache keys_zone=test_cache:10m; - proxy_temp_path /tmp/ngx_cache_purge_temp 1 2; -_EOC_ - -our $config = <<'_EOC_'; - set $cache test_cache; - - location /proxy { - proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd; - proxy_cache $cache; - proxy_cache_key $uri$is_args$args; - proxy_cache_valid 3m; - add_header X-Cache-Status $upstream_cache_status; - } - - location ~ /purge(/.*) { - proxy_cache_purge $cache $1$is_args$args; - } - - location = /etc/passwd { - root /; - } -_EOC_ - -worker_connections(128); -no_shuffle(); -run_tests(); - -no_diff(); - -__DATA__ - -=== TEST 1: prepare ---- http_config eval: $::http_config ---- config eval: $::config ---- request -GET /proxy/passwd ---- error_code: 200 ---- response_headers -Content-Type: text/plain ---- response_body_like: root ---- timeout: 10 ---- no_error_log eval -qr/\[(warn|error|crit|alert|emerg)\]/ ---- skip_nginx: 4: < 1.7.9 - - - -=== TEST 2: get from cache ---- http_config eval: $::http_config ---- config eval: $::config ---- request -GET /proxy/passwd ---- error_code: 200 ---- response_headers -Content-Type: text/plain -X-Cache-Status: HIT ---- response_body_like: root ---- timeout: 10 ---- no_error_log eval -qr/\[(warn|error|crit|alert|emerg)\]/ ---- skip_nginx: 5: < 1.7.9 - - - -=== TEST 3: purge from cache ---- http_config eval: $::http_config ---- config eval: $::config ---- request -PURGE /purge/proxy/passwd ---- error_code: 200 ---- response_headers -Content-Type: text/html ---- response_body_like: Successful purge ---- timeout: 10 ---- no_error_log eval -qr/\[(warn|error|crit|alert|emerg)\]/ ---- skip_nginx: 4: < 1.7.9 - - - -=== TEST 4: purge from empty cache ---- http_config eval: $::http_config ---- config eval: $::config ---- request -PURGE /purge/proxy/passwd ---- error_code: 404 ---- response_headers -Content-Type: text/html ---- response_body_like: 404 Not Found ---- timeout: 10 ---- no_error_log eval -qr/\[(warn|error|crit|alert|emerg)\]/ ---- skip_nginx: 4: < 1.7.9 - - - -=== TEST 5: get from source ---- http_config eval: $::http_config ---- config eval: $::config ---- request -GET /proxy/passwd ---- error_code: 200 ---- response_headers -Content-Type: text/plain -X-Cache-Status: MISS ---- response_body_like: root ---- timeout: 10 ---- no_error_log eval -qr/\[(warn|error|crit|alert|emerg)\]/ ---- skip_nginx: 5: < 1.7.9 - - - -=== TEST 6: get from cache ---- http_config eval: $::http_config ---- config eval: $::config ---- request -GET /proxy/passwd ---- error_code: 200 ---- response_headers -Content-Type: text/plain -X-Cache-Status: HIT ---- response_body_like: root ---- timeout: 10 ---- no_error_log eval -qr/\[(warn|error|crit|alert|emerg)\]/ ---- skip_nginx: 5: < 1.7.9 diff --git a/debian/modules/http-cache-purge/t/proxy2.t b/debian/modules/http-cache-purge/t/proxy2.t deleted file mode 100644 index c07b042..0000000 --- a/debian/modules/http-cache-purge/t/proxy2.t +++ /dev/null @@ -1,349 +0,0 @@ -# vi:filetype=perl - -use lib 'lib'; -use Test::Nginx::Socket; - -repeat_each(1); - -plan tests => repeat_each() * (blocks() * 4 + 6 * 1); - -our $http_config = <<'_EOC_'; - proxy_cache_path /tmp/ngx_cache_purge_cache keys_zone=test_cache:10m; - proxy_temp_path /tmp/ngx_cache_purge_temp 1 2; -_EOC_ - -our $config = <<'_EOC_'; - proxy_cache_purge on; - - location /proxy { - proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd; - proxy_cache test_cache; - proxy_cache_key $uri$is_args$args; - proxy_cache_valid 3m; - add_header X-Cache-Status $upstream_cache_status; - - if ($uri) { } - } - - location = /etc/passwd { - root /; - } -_EOC_ - -our $config_allowed = <<'_EOC_'; - proxy_cache_purge PURGE from 1.0.0.0/8 127.0.0.0/8 3.0.0.0/8; - - location /proxy { - proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd; - proxy_cache test_cache; - proxy_cache_key $uri$is_args$args; - proxy_cache_valid 3m; - add_header X-Cache-Status $upstream_cache_status; - } - - location = /etc/passwd { - root /; - } -_EOC_ - -our $config_forbidden = <<'_EOC_'; - proxy_cache_purge PURGE from 1.0.0.0/8; - - location /proxy { - proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd; - proxy_cache test_cache; - proxy_cache_key $uri$is_args$args; - proxy_cache_valid 3m; - add_header X-Cache-Status $upstream_cache_status; - } - - location = /etc/passwd { - root /; - } -_EOC_ - -worker_connections(128); -no_shuffle(); -run_tests(); - -no_diff(); - -__DATA__ - -=== TEST 1: prepare ---- http_config eval: $::http_config ---- config eval: $::config ---- request -GET /proxy/passwd ---- error_code: 200 ---- response_headers -Content-Type: text/plain ---- response_body_like: root ---- timeout: 10 ---- no_error_log eval -qr/\[(warn|error|crit|alert|emerg)\]/ ---- skip_nginx2: 4: < 0.8.3 or < 0.7.62 - - - -=== TEST 2: get from cache ---- http_config eval: $::http_config ---- config eval: $::config ---- request -GET /proxy/passwd ---- error_code: 200 ---- response_headers -Content-Type: text/plain -X-Cache-Status: HIT ---- response_body_like: root ---- timeout: 10 ---- no_error_log eval -qr/\[(warn|error|crit|alert|emerg)\]/ ---- skip_nginx2: 5: < 0.8.3 or < 0.7.62 - - - -=== TEST 3: purge from cache ---- http_config eval: $::http_config ---- config eval: $::config ---- request -PURGE /proxy/passwd ---- error_code: 200 ---- response_headers -Content-Type: text/html ---- response_body_like: Successful purge ---- timeout: 10 ---- no_error_log eval -qr/\[(warn|error|crit|alert|emerg)\]/ ---- skip_nginx2: 4: < 0.8.3 or < 0.7.62 - - - -=== TEST 4: purge from empty cache ---- http_config eval: $::http_config ---- config eval: $::config ---- request -PURGE /proxy/passwd ---- error_code: 404 ---- response_headers -Content-Type: text/html ---- response_body_like: 404 Not Found ---- timeout: 10 ---- no_error_log eval -qr/\[(warn|error|crit|alert|emerg)\]/ ---- skip_nginx2: 4: < 0.8.3 or < 0.7.62 - - - -=== TEST 5: get from source ---- http_config eval: $::http_config ---- config eval: $::config ---- request -GET /proxy/passwd ---- error_code: 200 ---- response_headers -Content-Type: text/plain -X-Cache-Status: MISS ---- response_body_like: root ---- timeout: 10 ---- no_error_log eval -qr/\[(warn|error|crit|alert|emerg)\]/ ---- skip_nginx2: 5: < 0.8.3 or < 0.7.62 - - - -=== TEST 6: get from cache ---- http_config eval: $::http_config ---- config eval: $::config ---- request -GET /proxy/passwd ---- error_code: 200 ---- response_headers -Content-Type: text/plain -X-Cache-Status: HIT ---- response_body_like: root ---- timeout: 10 ---- no_error_log eval -qr/\[(warn|error|crit|alert|emerg)\]/ ---- skip_nginx2: 5: < 0.8.3 or < 0.7.62 - - - -=== TEST 7: purge from cache (PURGE allowed) ---- http_config eval: $::http_config ---- config eval: $::config_allowed ---- request -PURGE /proxy/passwd ---- error_code: 200 ---- response_headers -Content-Type: text/html ---- response_body_like: Successful purge ---- timeout: 10 ---- no_error_log eval -qr/\[(warn|error|crit|alert|emerg)\]/ ---- skip_nginx2: 4: < 0.8.3 or < 0.7.62 - - - -=== TEST 8: purge from empty cache (PURGE allowed) ---- http_config eval: $::http_config ---- config eval: $::config_allowed ---- request -PURGE /proxy/passwd ---- error_code: 404 ---- response_headers -Content-Type: text/html ---- response_body_like: 404 Not Found ---- timeout: 10 ---- no_error_log eval -qr/\[(warn|error|crit|alert|emerg)\]/ ---- skip_nginx2: 4: < 0.8.3 or < 0.7.62 - - - -=== TEST 9: get from source (PURGE allowed) ---- http_config eval: $::http_config ---- config eval: $::config_allowed ---- request -GET /proxy/passwd ---- error_code: 200 ---- response_headers -Content-Type: text/plain -X-Cache-Status: MISS ---- response_body_like: root ---- timeout: 10 ---- no_error_log eval -qr/\[(warn|error|crit|alert|emerg)\]/ ---- skip_nginx2: 5: < 0.8.3 or < 0.7.62 - - - -=== TEST 10: get from cache (PURGE allowed) ---- http_config eval: $::http_config ---- config eval: $::config_allowed ---- request -GET /proxy/passwd ---- error_code: 200 ---- response_headers -Content-Type: text/plain -X-Cache-Status: HIT ---- response_body_like: root ---- timeout: 10 ---- no_error_log eval -qr/\[(warn|error|crit|alert|emerg)\]/ ---- skip_nginx2: 5: < 0.8.3 or < 0.7.62 - - - -=== TEST 11: purge from cache (PURGE not allowed) ---- http_config eval: $::http_config ---- config eval: $::config_forbidden ---- request -PURGE /proxy/passwd ---- error_code: 403 ---- response_headers -Content-Type: text/html ---- response_body_like: 403 Forbidden ---- timeout: 10 ---- no_error_log eval -qr/\[(warn|error|crit|alert|emerg)\]/ ---- skip_nginx2: 4: < 0.8.3 or < 0.7.62 - - - -=== TEST 12: get from cache (PURGE not allowed) ---- http_config eval: $::http_config ---- config eval: $::config_forbidden ---- request -GET /proxy/passwd ---- error_code: 200 ---- response_headers -Content-Type: text/plain -X-Cache-Status: HIT ---- response_body_like: root ---- timeout: 10 ---- no_error_log eval -qr/\[(warn|error|crit|alert|emerg)\]/ ---- skip_nginx2: 5: < 0.8.3 or < 0.7.62 - - - -=== TEST 13: no cache (PURGE allowed) ---- http_config eval: $::http_config ---- config - proxy_cache_purge PURGE from 1.0.0.0/8 127.0.0.0/8 3.0.0.0/8; - - location /proxy { - proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd; - } - - location = /etc/passwd { - root /; - } ---- request -PURGE /proxy/passwd ---- error_code: 404 ---- response_headers -Content-Type: text/html ---- response_body_like: 404 Not Found ---- timeout: 10 ---- no_error_log eval -qr/\[(warn|error|crit|alert|emerg)\]/ ---- skip_nginx2: 4: < 0.8.3 or < 0.7.62 - - - -=== TEST 14: no cache (PURGE not allowed) ---- http_config eval: $::http_config ---- config - proxy_cache_purge PURGE from 1.0.0.0/8; - - location /proxy { - proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd; - } - - location = /etc/passwd { - root /; - } ---- request -PURGE /proxy/passwd ---- error_code: 403 ---- response_headers -Content-Type: text/html ---- response_body_like: 403 Forbidden ---- timeout: 10 ---- no_error_log eval -qr/\[(warn|error|crit|alert|emerg)\]/ ---- skip_nginx2: 4: < 0.8.3 or < 0.7.62 - - - -=== TEST 15: multiple cache purge directives ---- http_config eval: $::http_config ---- config - fastcgi_cache_purge on; - proxy_cache_purge on; - - location /proxy { - proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd; - proxy_cache test_cache; - proxy_cache_key $uri$is_args$args; - proxy_cache_valid 3m; - add_header X-Cache-Status $upstream_cache_status; - - if ($uri) { } - } - - location = /etc/passwd { - root /; - } ---- request -PURGE /proxy/passwd ---- error_code: 200 ---- response_headers -Content-Type: text/html ---- response_body_like: Successful purge ---- timeout: 10 ---- no_error_log eval -qr/\[(warn|error|crit|alert|emerg)\]/ ---- skip_nginx2: 4: < 0.8.3 or < 0.7.62 diff --git a/debian/modules/http-cache-purge/t/proxy2_vars.t b/debian/modules/http-cache-purge/t/proxy2_vars.t deleted file mode 100644 index d09c08e..0000000 --- a/debian/modules/http-cache-purge/t/proxy2_vars.t +++ /dev/null @@ -1,353 +0,0 @@ -# vi:filetype=perl - -use lib 'lib'; -use Test::Nginx::Socket; - -repeat_each(1); - -plan tests => repeat_each() * (blocks() * 4 + 6 * 1); - -our $http_config = <<'_EOC_'; - proxy_cache_path /tmp/ngx_cache_purge_cache keys_zone=test_cache:10m; - proxy_temp_path /tmp/ngx_cache_purge_temp 1 2; -_EOC_ - -our $config = <<'_EOC_'; - proxy_cache_purge on; - set $cache test_cache; - - location /proxy { - proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd; - proxy_cache $cache; - proxy_cache_key $uri$is_args$args; - proxy_cache_valid 3m; - add_header X-Cache-Status $upstream_cache_status; - - if ($uri) { } - } - - location = /etc/passwd { - root /; - } -_EOC_ - -our $config_allowed = <<'_EOC_'; - proxy_cache_purge PURGE from 1.0.0.0/8 127.0.0.0/8 3.0.0.0/8; - set $cache test_cache; - - location /proxy { - proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd; - proxy_cache $cache; - proxy_cache_key $uri$is_args$args; - proxy_cache_valid 3m; - add_header X-Cache-Status $upstream_cache_status; - } - - location = /etc/passwd { - root /; - } -_EOC_ - -our $config_forbidden = <<'_EOC_'; - proxy_cache_purge PURGE from 1.0.0.0/8; - set $cache test_cache; - - location /proxy { - proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd; - proxy_cache $cache; - proxy_cache_key $uri$is_args$args; - proxy_cache_valid 3m; - add_header X-Cache-Status $upstream_cache_status; - } - - location = /etc/passwd { - root /; - } -_EOC_ - -worker_connections(128); -no_shuffle(); -run_tests(); - -no_diff(); - -__DATA__ - -=== TEST 1: prepare ---- http_config eval: $::http_config ---- config eval: $::config ---- request -GET /proxy/passwd ---- error_code: 200 ---- response_headers -Content-Type: text/plain ---- response_body_like: root ---- timeout: 10 ---- no_error_log eval -qr/\[(warn|error|crit|alert|emerg)\]/ ---- skip_nginx: 4: < 1.7.9 - - - -=== TEST 2: get from cache ---- http_config eval: $::http_config ---- config eval: $::config ---- request -GET /proxy/passwd ---- error_code: 200 ---- response_headers -Content-Type: text/plain -X-Cache-Status: HIT ---- response_body_like: root ---- timeout: 10 ---- no_error_log eval -qr/\[(warn|error|crit|alert|emerg)\]/ ---- skip_nginx: 5: < 1.7.9 - - - -=== TEST 3: purge from cache ---- http_config eval: $::http_config ---- config eval: $::config ---- request -PURGE /proxy/passwd ---- error_code: 200 ---- response_headers -Content-Type: text/html ---- response_body_like: Successful purge ---- timeout: 10 ---- no_error_log eval -qr/\[(warn|error|crit|alert|emerg)\]/ ---- skip_nginx: 4: < 1.7.9 - - - -=== TEST 4: purge from empty cache ---- http_config eval: $::http_config ---- config eval: $::config ---- request -PURGE /proxy/passwd ---- error_code: 404 ---- response_headers -Content-Type: text/html ---- response_body_like: 404 Not Found ---- timeout: 10 ---- no_error_log eval -qr/\[(warn|error|crit|alert|emerg)\]/ ---- skip_nginx: 4: < 1.7.9 - - - -=== TEST 5: get from source ---- http_config eval: $::http_config ---- config eval: $::config ---- request -GET /proxy/passwd ---- error_code: 200 ---- response_headers -Content-Type: text/plain -X-Cache-Status: MISS ---- response_body_like: root ---- timeout: 10 ---- no_error_log eval -qr/\[(warn|error|crit|alert|emerg)\]/ ---- skip_nginx: 5: < 1.7.9 - - - -=== TEST 6: get from cache ---- http_config eval: $::http_config ---- config eval: $::config ---- request -GET /proxy/passwd ---- error_code: 200 ---- response_headers -Content-Type: text/plain -X-Cache-Status: HIT ---- response_body_like: root ---- timeout: 10 ---- no_error_log eval -qr/\[(warn|error|crit|alert|emerg)\]/ ---- skip_nginx: 5: < 1.7.9 - - - -=== TEST 7: purge from cache (PURGE allowed) ---- http_config eval: $::http_config ---- config eval: $::config_allowed ---- request -PURGE /proxy/passwd ---- error_code: 200 ---- response_headers -Content-Type: text/html ---- response_body_like: Successful purge ---- timeout: 10 ---- no_error_log eval -qr/\[(warn|error|crit|alert|emerg)\]/ ---- skip_nginx: 4: < 1.7.9 - - - -=== TEST 8: purge from empty cache (PURGE allowed) ---- http_config eval: $::http_config ---- config eval: $::config_allowed ---- request -PURGE /proxy/passwd ---- error_code: 404 ---- response_headers -Content-Type: text/html ---- response_body_like: 404 Not Found ---- timeout: 10 ---- no_error_log eval -qr/\[(warn|error|crit|alert|emerg)\]/ ---- skip_nginx: 4: < 1.7.9 - - - -=== TEST 9: get from source (PURGE allowed) ---- http_config eval: $::http_config ---- config eval: $::config_allowed ---- request -GET /proxy/passwd ---- error_code: 200 ---- response_headers -Content-Type: text/plain -X-Cache-Status: MISS ---- response_body_like: root ---- timeout: 10 ---- no_error_log eval -qr/\[(warn|error|crit|alert|emerg)\]/ ---- skip_nginx: 5: < 1.7.9 - - - -=== TEST 10: get from cache (PURGE allowed) ---- http_config eval: $::http_config ---- config eval: $::config_allowed ---- request -GET /proxy/passwd ---- error_code: 200 ---- response_headers -Content-Type: text/plain -X-Cache-Status: HIT ---- response_body_like: root ---- timeout: 10 ---- no_error_log eval -qr/\[(warn|error|crit|alert|emerg)\]/ ---- skip_nginx: 5: < 1.7.9 - - - -=== TEST 11: purge from cache (PURGE not allowed) ---- http_config eval: $::http_config ---- config eval: $::config_forbidden ---- request -PURGE /proxy/passwd ---- error_code: 403 ---- response_headers -Content-Type: text/html ---- response_body_like: 403 Forbidden ---- timeout: 10 ---- no_error_log eval -qr/\[(warn|error|crit|alert|emerg)\]/ ---- skip_nginx: 4: < 1.7.9 - - - -=== TEST 12: get from cache (PURGE not allowed) ---- http_config eval: $::http_config ---- config eval: $::config_forbidden ---- request -GET /proxy/passwd ---- error_code: 200 ---- response_headers -Content-Type: text/plain -X-Cache-Status: HIT ---- response_body_like: root ---- timeout: 10 ---- no_error_log eval -qr/\[(warn|error|crit|alert|emerg)\]/ ---- skip_nginx: 5: < 1.7.9 - - - -=== TEST 13: no cache (PURGE allowed) ---- http_config eval: $::http_config ---- config - proxy_cache_purge PURGE from 1.0.0.0/8 127.0.0.0/8 3.0.0.0/8; - - location /proxy { - proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd; - } - - location = /etc/passwd { - root /; - } ---- request -PURGE /proxy/passwd ---- error_code: 404 ---- response_headers -Content-Type: text/html ---- response_body_like: 404 Not Found ---- timeout: 10 ---- no_error_log eval -qr/\[(warn|error|crit|alert|emerg)\]/ ---- skip_nginx: 4: < 1.7.9 - - - -=== TEST 14: no cache (PURGE not allowed) ---- http_config eval: $::http_config ---- config - proxy_cache_purge PURGE from 1.0.0.0/8; - - location /proxy { - proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd; - } - - location = /etc/passwd { - root /; - } ---- request -PURGE /proxy/passwd ---- error_code: 403 ---- response_headers -Content-Type: text/html ---- response_body_like: 403 Forbidden ---- timeout: 10 ---- no_error_log eval -qr/\[(warn|error|crit|alert|emerg)\]/ ---- skip_nginx: 4: < 1.7.9 - - - -=== TEST 15: multiple cache purge directives ---- http_config eval: $::http_config ---- config - fastcgi_cache_purge on; - proxy_cache_purge on; - set $cache test_cache; - - location /proxy { - proxy_pass $scheme://127.0.0.1:$server_port/etc/passwd; - proxy_cache $cache; - proxy_cache_key $uri$is_args$args; - proxy_cache_valid 3m; - add_header X-Cache-Status $upstream_cache_status; - - if ($uri) { } - } - - location = /etc/passwd { - root /; - } ---- request -PURGE /proxy/passwd ---- error_code: 200 ---- response_headers -Content-Type: text/html ---- response_body_like: Successful purge ---- timeout: 10 ---- no_error_log eval -qr/\[(warn|error|crit|alert|emerg)\]/ ---- skip_nginx: 4: < 1.7.9 diff --git a/debian/modules/http-dav-ext/LICENSE b/debian/modules/http-dav-ext/LICENSE deleted file mode 100644 index c68a7d4..0000000 --- a/debian/modules/http-dav-ext/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -Copyright (C) 2012-2018 Roman Arutyunyan -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/debian/modules/http-dav-ext/README.rst b/debian/modules/http-dav-ext/README.rst deleted file mode 100644 index 092056e..0000000 --- a/debian/modules/http-dav-ext/README.rst +++ /dev/null @@ -1,188 +0,0 @@ -******************** -nginx-dav-ext-module -******************** - -nginx_ WebDAV_ PROPFIND,OPTIONS,LOCK,UNLOCK support. - -.. contents:: - - -About -===== - -The standard ngx_http_dav_module_ provides partial WebDAV_ implementation and -only supports GET,HEAD,PUT,DELETE,MKCOL,COPY,MOVE methods. - -For full WebDAV_ support in nginx_ you need to enable the standard -ngx_http_dav_module_ as well as this module for the missing methods. - - -Build -===== - -Building nginx_ with the module: - -.. code-block:: bash - - # static module - $ ./configure --with-http_dav_module --add-module=/path/to/nginx-dav-ext-module - - # dynamic module - $ ./configure --with-http_dav_module --add-dynamic-module=/path/to/nginx-dav-ext-module - -Trying to compile nginx_ with this module but without ngx_http_dav_module_ will -result in compilation error. - - -Requirements -============ - -- nginx_ version >= 1.13.4 -- ``libxml2`` + ``libxslt`` - -The ``libxslt`` library is technically redundant and is only required since this -combination is supported by nginx_ for the xslt module. -Using builtin nginx mechanisms for linking against third-party libraries -brings certain compatibility benefits. -However this redundancy can be easily eliminated in the ``config`` file. - - -Testing -======= - -The module tests require standard nginx-tests_ and Perl ``HTTP::DAV`` library. - -.. code-block:: bash - - $ export PERL5LIB=/path/to/nginx-tests/lib - $ export TEST_NGINX_BINARY=/path/to/nginx - $ prove t - - -Locking -======= - -- Only the exclusive write locks are supported, which is the only type of locks - described in the WebDAV_ specification. - -- All currently held locks are kept in a list. - Checking if an object is constrained by a lock requires O(n) operations. - A huge number of simultaneously held locks may degrade performance. - Thus it is not recommended to have a large lock timeout which would increase - the number of locks. - - -Directives -========== - -dav_ext_methods ---------------- - -========== ==== -*Syntax:* ``dav_ext_methods [PROPFIND] [OPTIONS] [LOCK] [UNLOCK]`` -*Context:* http, server, location -========== ==== - -Enables support for the specified WebDAV methods in the current scope. - -dav_ext_lock_zone ------------------ - -========== ==== -*Syntax:* ``dav_ext_lock_zone zone=NAME:SIZE [timeout=TIMEOUT]`` -*Context:* http -========== ==== - -Defines a shared zone for WebDAV locks with specified NAME and SIZE. -Also, defines a lock expiration TIMEOUT. -Default lock timeout value is 1 minute. - - -dav_ext_lock ------------- - -========== ==== -*Syntax:* ``dav_ext_lock zone=NAME`` -*Context:* http, server, location -========== ==== - -Enables WebDAV locking in the specified scope. -Locks are stored in the shared zone specified by NAME. -This zone must be defined with the ``dav_ext_lock_zone`` directive. - -Note that even though this directive enables locking capabilities in the -current scope, HTTP methods LOCK and UNLOCK should also be explicitly specified -in the ``dav_ext_methods``. - - -Example 1 -========= - -Simple lockless example:: - - location / { - root /data/www; - - dav_methods PUT DELETE MKCOL COPY MOVE; - dav_ext_methods PROPFIND OPTIONS; - } - - -Example 2 -========= - -WebDAV with locking:: - - http { - dav_ext_lock_zone zone=foo:10m; - - ... - - server { - ... - - location / { - root /data/www; - - dav_methods PUT DELETE MKCOL COPY MOVE; - dav_ext_methods PROPFIND OPTIONS LOCK UNLOCK; - dav_ext_lock zone=foo; - } - } - } - - -Example 3 -========= - -WebDAV with locking which works with MacOS client:: - - http { - dav_ext_lock_zone zone=foo:10m; - - ... - - server { - ... - - location / { - root /data/www; - - # enable creating directories without trailing slash - set $x $uri$request_method; - if ($x ~ [^/]MKCOL$) { - rewrite ^(.*)$ $1/; - } - - dav_methods PUT DELETE MKCOL COPY MOVE; - dav_ext_methods PROPFIND OPTIONS LOCK UNLOCK; - dav_ext_lock zone=foo; - } - } - } - -.. _ngx_http_dav_module: http://nginx.org/en/docs/http/ngx_http_dav_module.html -.. _nginx-tests: http://hg.nginx.org/nginx-tests -.. _nginx: http://nginx.org -.. _WebDAV: https://tools.ietf.org/html/rfc4918 -.. _`RFC4918 If Header`: https://tools.ietf.org/html/rfc4918#section-10.4 diff --git a/debian/modules/http-dav-ext/config b/debian/modules/http-dav-ext/config deleted file mode 100644 index 91ae1b3..0000000 --- a/debian/modules/http-dav-ext/config +++ /dev/null @@ -1,17 +0,0 @@ -ngx_addon_name=ngx_http_dav_ext_module - -ngx_module_type=HTTP -ngx_module_name=ngx_http_dav_ext_module - -# nginx has robust builtin support for linking against -# libxml2+libxslt. This is definitelty the right way to go if -# building nginx with the xslt module, in which case libxslt will -# be linked anyway. In other cases libxslt is just redundant. -# If that's a big deal, libxml2 can be linked directly: -# ngx_module_libs=-lxml2 - -ngx_module_libs=LIBXSLT - -ngx_module_srcs="$ngx_addon_dir/ngx_http_dav_ext_module.c" - -. auto/module diff --git a/debian/modules/http-dav-ext/ngx_http_dav_ext_module.c b/debian/modules/http-dav-ext/ngx_http_dav_ext_module.c deleted file mode 100644 index 0d6d067..0000000 --- a/debian/modules/http-dav-ext/ngx_http_dav_ext_module.c +++ /dev/null @@ -1,2181 +0,0 @@ - -/* - * Copyright (C) Roman Arutyunyan - */ - - -#include -#include -#include -#include - - -#define NGX_HTTP_DAV_EXT_OFF 2 - -#define NGX_HTTP_DAV_EXT_PREALLOCATE 50 - -#define NGX_HTTP_DAV_EXT_NODE_PROPFIND 0x01 -#define NGX_HTTP_DAV_EXT_NODE_PROP 0x02 -#define NGX_HTTP_DAV_EXT_NODE_PROPNAME 0x04 -#define NGX_HTTP_DAV_EXT_NODE_ALLPROP 0x08 - -#define NGX_HTTP_DAV_EXT_PROP_DISPLAYNAME 0x01 -#define NGX_HTTP_DAV_EXT_PROP_GETCONTENTLENGTH 0x02 -#define NGX_HTTP_DAV_EXT_PROP_GETLASTMODIFIED 0x04 -#define NGX_HTTP_DAV_EXT_PROP_RESOURCETYPE 0x08 -#define NGX_HTTP_DAV_EXT_PROP_LOCKDISCOVERY 0x10 -#define NGX_HTTP_DAV_EXT_PROP_SUPPORTEDLOCK 0x20 - -#define NGX_HTTP_DAV_EXT_PROP_ALL 0x7f -#define NGX_HTTP_DAV_EXT_PROP_NAMES 0x80 - - -typedef struct { - ngx_str_t uri; - ngx_str_t name; - time_t mtime; - off_t size; - - time_t lock_expire; - ngx_str_t lock_root; - uint32_t lock_token; - - unsigned dir:1; - unsigned lock_supported:1; - unsigned lock_infinite:1; -} ngx_http_dav_ext_entry_t; - - -typedef struct { - ngx_uint_t nodes; - ngx_uint_t props; -} ngx_http_dav_ext_xml_ctx_t; - - -typedef struct { - ngx_uint_t methods; - ngx_shm_zone_t *shm_zone; -} ngx_http_dav_ext_loc_conf_t; - - -typedef struct { - ngx_queue_t queue; - uint32_t token; - time_t expire; - ngx_uint_t infinite; /* unsigned infinite:1; */ - size_t len; - u_char data[1]; -} ngx_http_dav_ext_node_t; - - -typedef struct { - ngx_queue_t queue; -} ngx_http_dav_ext_lock_sh_t; - - -typedef struct { - time_t timeout; - ngx_slab_pool_t *shpool; - ngx_http_dav_ext_lock_sh_t *sh; -} ngx_http_dav_ext_lock_t; - - -static ngx_int_t ngx_http_dav_ext_precontent_handler(ngx_http_request_t *r); -static ngx_int_t ngx_http_dav_ext_strip_uri(ngx_http_request_t *r, - ngx_str_t *uri); -static ngx_int_t ngx_http_dav_ext_verify_lock(ngx_http_request_t *r, - ngx_str_t *uri, ngx_uint_t delete_lock); -static ngx_http_dav_ext_node_t *ngx_http_dav_ext_lock_lookup( - ngx_http_request_t *r, ngx_http_dav_ext_lock_t *lock, ngx_str_t *uri, - ngx_int_t depth); - -static ngx_int_t ngx_http_dav_ext_content_handler(ngx_http_request_t *r); -static void ngx_http_dav_ext_propfind_handler(ngx_http_request_t *r); -static void ngx_http_dav_ext_propfind_xml_start(void *data, - const xmlChar *localname, const xmlChar *prefix, const xmlChar *uri, - int nb_namespaces, const xmlChar **namespaces, int nb_attributes, - int nb_defaulted, const xmlChar **attributes); -static void ngx_http_dav_ext_propfind_xml_end(void *data, - const xmlChar *localname, const xmlChar *prefix, const xmlChar *uri); -static ngx_int_t ngx_http_dav_ext_propfind(ngx_http_request_t *r, - ngx_uint_t props); -static ngx_int_t ngx_http_dav_ext_set_locks(ngx_http_request_t *r, - ngx_http_dav_ext_entry_t *entry); -static ngx_int_t ngx_http_dav_ext_propfind_response(ngx_http_request_t *r, - ngx_array_t *entries, ngx_uint_t props); -static ngx_int_t ngx_http_dav_ext_lock_handler(ngx_http_request_t *r); -static ngx_int_t ngx_http_dav_ext_lock_response(ngx_http_request_t *r, - ngx_uint_t status, time_t timeout, ngx_uint_t depth, uint32_t token); -static ngx_int_t ngx_http_dav_ext_unlock_handler(ngx_http_request_t *r); - -static ngx_int_t ngx_http_dav_ext_depth(ngx_http_request_t *r, - ngx_int_t default_depth); -static uint32_t ngx_http_dav_ext_lock_token(ngx_http_request_t *r); -static uint32_t ngx_http_dav_ext_if(ngx_http_request_t *r, ngx_str_t *uri); -static uintptr_t ngx_http_dav_ext_format_propfind(ngx_http_request_t *r, - u_char *dst, ngx_http_dav_ext_entry_t *entry, ngx_uint_t props); -static uintptr_t ngx_http_dav_ext_format_lockdiscovery(ngx_http_request_t *r, - u_char *dst, ngx_http_dav_ext_entry_t *entry); -static uintptr_t ngx_http_dav_ext_format_token(u_char *dst, uint32_t token, - ngx_uint_t brackets); - -static ngx_int_t ngx_http_dav_ext_init_zone(ngx_shm_zone_t *shm_zone, - void *data); -static void *ngx_http_dav_ext_create_loc_conf(ngx_conf_t *cf); -static char *ngx_http_dav_ext_merge_loc_conf(ngx_conf_t *cf, void *parent, - void *child); -static char *ngx_http_dav_ext_lock_zone(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf); -static char *ngx_http_dav_ext_lock(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf); -static ngx_int_t ngx_http_dav_ext_init(ngx_conf_t *cf); - - -static ngx_conf_bitmask_t ngx_http_dav_ext_methods_mask[] = { - { ngx_string("off"), NGX_HTTP_DAV_EXT_OFF }, - { ngx_string("propfind"), NGX_HTTP_PROPFIND }, - { ngx_string("options"), NGX_HTTP_OPTIONS }, - { ngx_string("lock"), NGX_HTTP_LOCK }, - { ngx_string("unlock"), NGX_HTTP_UNLOCK }, - { ngx_null_string, 0 } -}; - - -static ngx_command_t ngx_http_dav_ext_commands[] = { - - { ngx_string("dav_ext_methods"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, - ngx_conf_set_bitmask_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_dav_ext_loc_conf_t, methods), - &ngx_http_dav_ext_methods_mask }, - - { ngx_string("dav_ext_lock_zone"), - NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE12, - ngx_http_dav_ext_lock_zone, - 0, - 0, - NULL }, - - { ngx_string("dav_ext_lock"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_http_dav_ext_lock, - NGX_HTTP_LOC_CONF_OFFSET, - 0, - NULL }, - - ngx_null_command -}; - - -static ngx_http_module_t ngx_http_dav_ext_module_ctx = { - NULL, /* preconfiguration */ - ngx_http_dav_ext_init, /* postconfiguration */ - - NULL, /* create main configuration */ - NULL, /* init main configuration */ - - NULL, /* create server configuration */ - NULL, /* merge server configuration */ - - ngx_http_dav_ext_create_loc_conf, /* create location configuration */ - ngx_http_dav_ext_merge_loc_conf, /* merge location configuration */ -}; - - -ngx_module_t ngx_http_dav_ext_module = { - NGX_MODULE_V1, - &ngx_http_dav_ext_module_ctx, /* module context */ - ngx_http_dav_ext_commands, /* module directives */ - NGX_HTTP_MODULE, /* module type */ - NULL, /* init master */ - NULL, /* init module */ - NULL, /* init process */ - NULL, /* init thread */ - NULL, /* exit thread */ - NULL, /* exit process */ - NULL, /* exit master */ - NGX_MODULE_V1_PADDING -}; - - -static ngx_int_t -ngx_http_dav_ext_precontent_handler(ngx_http_request_t *r) -{ - ngx_str_t uri; - ngx_int_t rc; - ngx_uint_t delete_lock; - ngx_table_elt_t *dest; - ngx_http_dav_ext_loc_conf_t *dlcf; - - dlcf = ngx_http_get_module_loc_conf(r, ngx_http_dav_ext_module); - - if (dlcf->shm_zone == NULL) { - return NGX_DECLINED; - } - - if (r->method & (NGX_HTTP_PUT|NGX_HTTP_DELETE|NGX_HTTP_MKCOL|NGX_HTTP_MOVE)) - { - delete_lock = (r->method & (NGX_HTTP_DELETE|NGX_HTTP_MOVE)) ? 1 : 0; - - rc = ngx_http_dav_ext_verify_lock(r, &r->uri, delete_lock); - if (rc != NGX_OK) { - return rc; - } - } - - if (r->method & (NGX_HTTP_MOVE|NGX_HTTP_COPY)) { - dest = r->headers_in.destination; - if (dest == NULL) { - return NGX_DECLINED; - } - - uri.data = dest->value.data; - uri.len = dest->value.len; - - if (ngx_http_dav_ext_strip_uri(r, &uri) != NGX_OK) { - return NGX_DECLINED; - } - - rc = ngx_http_dav_ext_verify_lock(r, &uri, 0); - if (rc != NGX_OK) { - return rc; - } - } - - return NGX_DECLINED; -} - - -static ngx_int_t -ngx_http_dav_ext_strip_uri(ngx_http_request_t *r, ngx_str_t *uri) -{ - u_char *p, *last, *host; - size_t len; - - if (uri->data[0] == '/') { - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http dav_ext strip uri:\"%V\" unchanged", uri); - return NGX_OK; - } - - len = r->headers_in.server.len; - - if (len == 0) { - goto failed; - } - -#if (NGX_HTTP_SSL) - - if (r->connection->ssl) { - if (ngx_strncmp(uri->data, "https://", sizeof("https://") - 1) != 0) { - goto failed; - } - - host = uri->data + sizeof("https://") - 1; - - } else -#endif - { - if (ngx_strncmp(uri->data, "http://", sizeof("http://") - 1) != 0) { - goto failed; - } - - host = uri->data + sizeof("http://") - 1; - } - - if (ngx_strncmp(host, r->headers_in.server.data, len) != 0) { - goto failed; - } - - last = uri->data + uri->len; - - for (p = host + len; p != last; p++) { - if (*p == '/') { - ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http dav_ext strip uri \"%V\" \"%*s\"", - uri, last - p, p); - - uri->data = p; - uri->len = last - p; - - return NGX_OK; - } - } - -failed: - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http dav_ext strip uri \"%V\" failed", uri); - - return NGX_DECLINED; -} - - -static ngx_int_t -ngx_http_dav_ext_verify_lock(ngx_http_request_t *r, ngx_str_t *uri, - ngx_uint_t delete_lock) -{ - uint32_t token; - ngx_http_dav_ext_node_t *node; - ngx_http_dav_ext_lock_t *lock; - ngx_http_dav_ext_loc_conf_t *dlcf; - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http dav_ext verify lock \"%V\"", uri); - - token = ngx_http_dav_ext_if(r, uri); - - dlcf = ngx_http_get_module_loc_conf(r, ngx_http_dav_ext_module); - lock = dlcf->shm_zone->data; - - ngx_shmtx_lock(&lock->shpool->mutex); - - node = ngx_http_dav_ext_lock_lookup(r, lock, uri, -1); - if (node == NULL) { - ngx_shmtx_unlock(&lock->shpool->mutex); - return NGX_OK; - } - - if (token == 0) { - ngx_shmtx_unlock(&lock->shpool->mutex); - return 423; /* Locked */ - } - - if (token != node->token) { - ngx_shmtx_unlock(&lock->shpool->mutex); - return NGX_HTTP_PRECONDITION_FAILED; - } - - /* - * RFC4918: - * If a request causes the lock-root of any lock to become an - * unmapped URL, then the lock MUST also be deleted by that request. - */ - - if (delete_lock && node->len == uri->len) { - ngx_queue_remove(&node->queue); - ngx_slab_free_locked(lock->shpool, node); - } - - ngx_shmtx_unlock(&lock->shpool->mutex); - - return NGX_OK; -} - - -static ngx_http_dav_ext_node_t * -ngx_http_dav_ext_lock_lookup(ngx_http_request_t *r, - ngx_http_dav_ext_lock_t *lock, ngx_str_t *uri, ngx_int_t depth) -{ - time_t now; - ngx_queue_t *q; - ngx_http_dav_ext_node_t *node; - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http dav_ext lock lookup \"%V\"", uri); - - if (uri->len == 0) { - return NULL; - } - - now = ngx_time(); - - while (!ngx_queue_empty(&lock->sh->queue)) { - q = ngx_queue_head(&lock->sh->queue); - node = (ngx_http_dav_ext_node_t *) q; - - if (node->expire >= now) { - break; - } - - ngx_queue_remove(q); - ngx_slab_free_locked(lock->shpool, node); - } - - for (q = ngx_queue_head(&lock->sh->queue); - q != ngx_queue_sentinel(&lock->sh->queue); - q = ngx_queue_next(q)) - { - node = (ngx_http_dav_ext_node_t *) q; - - if (uri->len >= node->len) { - if (ngx_memcmp(uri->data, node->data, node->len)) { - continue; - } - - if (uri->len > node->len) { - if (node->data[node->len - 1] != '/') { - continue; - } - - if (!node->infinite - && ngx_strlchr(uri->data + node->len, - uri->data + uri->len - 1, '/')) - { - continue; - } - } - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http dav_ext lock found \"%*s\"", - node->len, node->data); - - return node; - } - - /* uri->len < node->len */ - - if (depth >= 0) { - if (ngx_memcmp(node->data, uri->data, uri->len)) { - continue; - } - - if (uri->data[uri->len - 1] != '/') { - continue; - } - - if (depth == 0 - && ngx_strlchr(node->data + uri->len, - node->data + node->len - 1, '/')) - { - continue; - } - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http dav_ext lock found \"%*s\"", - node->len, node->data); - - return node; - } - } - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http dav_ext lock not found"); - - return NULL; -} - - -static ngx_int_t -ngx_http_dav_ext_content_handler(ngx_http_request_t *r) -{ - ngx_int_t rc; - ngx_table_elt_t *h; - ngx_http_dav_ext_loc_conf_t *dlcf; - - dlcf = ngx_http_get_module_loc_conf(r, ngx_http_dav_ext_module); - - if (!(r->method & dlcf->methods)) { - return NGX_DECLINED; - } - - switch (r->method) { - - case NGX_HTTP_PROPFIND: - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http dav_ext propfind"); - - rc = ngx_http_read_client_request_body(r, - ngx_http_dav_ext_propfind_handler); - if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { - return rc; - } - - return NGX_DONE; - - case NGX_HTTP_OPTIONS: - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http dav_ext options"); - - rc = ngx_http_discard_request_body(r); - - if (rc != NGX_OK) { - return rc; - } - - h = ngx_list_push(&r->headers_out.headers); - if (h == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - ngx_str_set(&h->key, "DAV"); - h->value.len = 1; - h->value.data = (u_char *) (dlcf->shm_zone ? "2" : "1"); - h->hash = 1; - - h = ngx_list_push(&r->headers_out.headers); - if (h == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - /* XXX */ - ngx_str_set(&h->key, "Allow"); - ngx_str_set(&h->value, - "GET,HEAD,PUT,DELETE,MKCOL,COPY,MOVE,PROPFIND,OPTIONS,LOCK,UNLOCK"); - h->hash = 1; - - r->headers_out.status = NGX_HTTP_OK; - r->headers_out.content_length_n = 0; - - rc = ngx_http_send_header(r); - - if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { - return rc; - } - - return ngx_http_send_special(r, NGX_HTTP_LAST); - - case NGX_HTTP_LOCK: - - if (dlcf->shm_zone == NULL) { - return NGX_HTTP_NOT_ALLOWED; - } - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http dav_ext lock"); - - /* - * Body is expected to carry the requested lock type, but - * since we only support write/exclusive locks, we ignore it. - * Ideally we could throw an error if a lock of another type - * is requested, but the amount of work required for that is - * not worth it. - */ - - rc = ngx_http_discard_request_body(r); - - if (rc != NGX_OK) { - return rc; - } - - return ngx_http_dav_ext_lock_handler(r); - - case NGX_HTTP_UNLOCK: - - if (dlcf->shm_zone == NULL) { - return NGX_HTTP_NOT_ALLOWED; - } - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http dav_ext unlock"); - - rc = ngx_http_discard_request_body(r); - - if (rc != NGX_OK) { - return rc; - } - - return ngx_http_dav_ext_unlock_handler(r); - } - - return NGX_DECLINED; -} - - -static void -ngx_http_dav_ext_propfind_handler(ngx_http_request_t *r) -{ - off_t len; - ngx_buf_t *b; - ngx_chain_t *cl; - xmlSAXHandler sax; - xmlParserCtxtPtr pctx; - ngx_http_dav_ext_xml_ctx_t xctx; - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http dav_ext propfind handler"); - - ngx_memzero(&xctx, sizeof(ngx_http_dav_ext_xml_ctx_t)); - ngx_memzero(&sax, sizeof(xmlSAXHandler)); - - sax.initialized = XML_SAX2_MAGIC; - sax.startElementNs = ngx_http_dav_ext_propfind_xml_start; - sax.endElementNs = ngx_http_dav_ext_propfind_xml_end; - - pctx = xmlCreatePushParserCtxt(&sax, &xctx, NULL, 0, NULL); - if (pctx == NULL) { - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "xmlCreatePushParserCtxt() failed"); - ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); - return; - } - - len = 0; - - for (cl = r->request_body->bufs; cl; cl = cl->next) { - b = cl->buf; - - if (b->in_file) { - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "PROPFIND client body is in file, " - "you may want to increase client_body_buffer_size"); - xmlFreeParserCtxt(pctx); - ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); - return; - } - - if (ngx_buf_special(b)) { - continue; - } - - len += b->last - b->pos; - - if (xmlParseChunk(pctx, (const char *) b->pos, b->last - b->pos, - b->last_buf)) - { - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "xmlParseChunk() failed"); - xmlFreeParserCtxt(pctx); - ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); - return; - } - } - - xmlFreeParserCtxt(pctx); - - if (len == 0) { - - /* - * For easier debugging treat bodiless requests - * as if they expect all properties. - */ - - xctx.props = NGX_HTTP_DAV_EXT_PROP_ALL; - } - - ngx_http_finalize_request(r, ngx_http_dav_ext_propfind(r, xctx.props)); -} - - -static void -ngx_http_dav_ext_propfind_xml_start(void *data, const xmlChar *localname, - const xmlChar *prefix, const xmlChar *uri, int nb_namespaces, - const xmlChar **namespaces, int nb_attributes, int nb_defaulted, - const xmlChar **attributes) -{ - ngx_http_dav_ext_xml_ctx_t *xctx = data; - - if (ngx_strcmp(localname, "propfind") == 0) { - xctx->nodes ^= NGX_HTTP_DAV_EXT_NODE_PROPFIND; - } - - if (ngx_strcmp(localname, "prop") == 0) { - xctx->nodes ^= NGX_HTTP_DAV_EXT_NODE_PROP; - } - - if (ngx_strcmp(localname, "propname") == 0) { - xctx->nodes ^= NGX_HTTP_DAV_EXT_NODE_PROPNAME; - } - - if (ngx_strcmp(localname, "allprop") == 0) { - xctx->nodes ^= NGX_HTTP_DAV_EXT_NODE_ALLPROP; - } -} - - -static void -ngx_http_dav_ext_propfind_xml_end(void *data, const xmlChar *localname, - const xmlChar *prefix, const xmlChar *uri) -{ - ngx_http_dav_ext_xml_ctx_t *xctx = data; - - if (xctx->nodes & NGX_HTTP_DAV_EXT_NODE_PROPFIND) { - - if (xctx->nodes & NGX_HTTP_DAV_EXT_NODE_PROP) { - if (ngx_strcmp(localname, "displayname") == 0) { - xctx->props |= NGX_HTTP_DAV_EXT_PROP_DISPLAYNAME; - } - - if (ngx_strcmp(localname, "getcontentlength") == 0) { - xctx->props |= NGX_HTTP_DAV_EXT_PROP_GETCONTENTLENGTH; - } - - if (ngx_strcmp(localname, "getlastmodified") == 0) { - xctx->props |= NGX_HTTP_DAV_EXT_PROP_GETLASTMODIFIED; - } - - if (ngx_strcmp(localname, "resourcetype") == 0) { - xctx->props |= NGX_HTTP_DAV_EXT_PROP_RESOURCETYPE; - } - - if (ngx_strcmp(localname, "lockdiscovery") == 0) { - xctx->props |= NGX_HTTP_DAV_EXT_PROP_LOCKDISCOVERY; - } - - if (ngx_strcmp(localname, "supportedlock") == 0) { - xctx->props |= NGX_HTTP_DAV_EXT_PROP_SUPPORTEDLOCK; - } - } - - if (xctx->nodes & NGX_HTTP_DAV_EXT_NODE_PROPNAME) { - xctx->props |= NGX_HTTP_DAV_EXT_PROP_NAMES; - } - - if (xctx->nodes & NGX_HTTP_DAV_EXT_NODE_ALLPROP) { - xctx->props = NGX_HTTP_DAV_EXT_PROP_ALL; - } - } - - ngx_http_dav_ext_propfind_xml_start(data, localname, prefix, uri, - 0, NULL, 0, 0, NULL); -} - - -static ngx_int_t -ngx_http_dav_ext_propfind(ngx_http_request_t *r, ngx_uint_t props) -{ - size_t root, allocated; - u_char *p, *last, *filename; - ngx_int_t rc; - ngx_err_t err; - ngx_str_t path, name; - ngx_dir_t dir; - ngx_uint_t depth; - ngx_array_t entries; - ngx_file_info_t fi; - ngx_http_dav_ext_entry_t *entry; - - if (ngx_array_init(&entries, r->pool, 40, sizeof(ngx_http_dav_ext_entry_t)) - != NGX_OK) - { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - rc = ngx_http_dav_ext_depth(r, 0); - - if (rc == NGX_ERROR) { - return NGX_HTTP_BAD_REQUEST; - } - - if (rc == NGX_MAX_INT_T_VALUE) { - - /* - * RFC4918: - * 403 Forbidden - A server MAY reject PROPFIND requests on - * collections with depth header of "Infinity", in which case - * it SHOULD use this error with the precondition code - * 'propfind-finite-depth' inside the error body. - */ - - return NGX_HTTP_FORBIDDEN; - } - - depth = rc; - - last = ngx_http_map_uri_to_path(r, &path, &root, - NGX_HTTP_DAV_EXT_PREALLOCATE); - if (last == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - allocated = path.len; - path.len = last - path.data; - - if (path.len > 1 && path.data[path.len - 1] == '/') { - path.len--; - - } else { - last++; - } - - path.data[path.len] = '\0'; - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http dav_ext propfind path: \"%s\"", path.data); - - if (ngx_file_info(path.data, &fi) == NGX_FILE_ERROR) { - return NGX_HTTP_NOT_FOUND; - } - - if (r->uri.len < 2) { - name = r->uri; - - } else { - name.data = &r->uri.data[r->uri.len - 1]; - name.len = (name.data[0] == '/') ? 0 : 1; - - while (name.data != r->uri.data) { - p = name.data - 1; - if (*p == '/') { - break; - } - - name.data--; - name.len++; - } - } - - entry = ngx_array_push(&entries); - if (entry == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - ngx_memzero(entry, sizeof(ngx_http_dav_ext_entry_t)); - - entry->uri = r->uri; - entry->name = name; - entry->dir = ngx_is_dir(&fi); - entry->mtime = ngx_file_mtime(&fi); - entry->size = ngx_file_size(&fi); - - if (ngx_http_dav_ext_set_locks(r, entry) != NGX_OK) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http dav_ext propfind name:\"%V\", uri:\"%V\"", - &entry->name, &entry->uri); - - if (depth == 0 || !entry->dir) { - return ngx_http_dav_ext_propfind_response(r, &entries, props); - } - - if (ngx_open_dir(&path, &dir) == NGX_ERROR) { - ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno, - ngx_open_dir_n " \"%s\" failed", path.data); - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - rc = NGX_OK; - - filename = path.data; - filename[path.len] = '/'; - - for ( ;; ) { - ngx_set_errno(0); - - if (ngx_read_dir(&dir) == NGX_ERROR) { - err = ngx_errno; - - if (err != NGX_ENOMOREFILES) { - ngx_log_error(NGX_LOG_CRIT, r->connection->log, err, - ngx_read_dir_n " \"%V\" failed", &path); - rc = NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - break; - } - - name.len = ngx_de_namelen(&dir); - name.data = ngx_de_name(&dir); - - if (name.data[0] == '.') { - continue; - } - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http dav_ext propfind child path: \"%s\"", name.data); - - entry = ngx_array_push(&entries); - if (entry == NULL) { - rc = NGX_HTTP_INTERNAL_SERVER_ERROR; - break; - } - - ngx_memzero(entry, sizeof(ngx_http_dav_ext_entry_t)); - - if (!dir.valid_info) { - - if (path.len + 1 + name.len + 1 > allocated) { - allocated = path.len + 1 + name.len + 1 - + NGX_HTTP_DAV_EXT_PREALLOCATE; - - filename = ngx_pnalloc(r->pool, allocated); - if (filename == NULL) { - rc = NGX_HTTP_INTERNAL_SERVER_ERROR; - break; - } - - last = ngx_cpystrn(filename, path.data, path.len + 1); - *last++ = '/'; - } - - ngx_cpystrn(last, name.data, name.len + 1); - - if (ngx_de_info(filename, &dir) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno, - ngx_de_info_n " \"%s\" failed", filename); - rc = NGX_HTTP_INTERNAL_SERVER_ERROR; - break; - } - } - - p = ngx_pnalloc(r->pool, name.len); - if (p == NULL) { - rc = NGX_HTTP_INTERNAL_SERVER_ERROR; - break; - } - - ngx_memcpy(p, name.data, name.len); - entry->name.data = p; - entry->name.len = name.len; - - p = ngx_pnalloc(r->pool, r->uri.len + 1 + name.len + 1); - if (p == NULL) { - rc = NGX_HTTP_INTERNAL_SERVER_ERROR; - break; - } - - entry->uri.data = p; - - p = ngx_cpymem(p, r->uri.data, r->uri.len); - if (r->uri.len && r->uri.data[r->uri.len - 1] != '/') { - *p++ = '/'; - } - - p = ngx_cpymem(p, name.data, name.len); - if (ngx_de_is_dir(&dir)) { - *p++ = '/'; - } - - entry->uri.len = p - entry->uri.data; - entry->dir = ngx_de_is_dir(&dir); - entry->mtime = ngx_de_mtime(&dir); - entry->size = ngx_de_size(&dir); - - if (ngx_http_dav_ext_set_locks(r, entry) != NGX_OK) { - rc = NGX_HTTP_INTERNAL_SERVER_ERROR; - break; - } - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http dav_ext propfind child name:\"%V\", uri:\"%V\"", - &entry->name, &entry->uri); - } - - if (ngx_close_dir(&dir) == NGX_ERROR) { - ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno, - ngx_close_dir_n " \"%V\" failed", &path); - } - - if (rc != NGX_OK) { - return rc; - } - - return ngx_http_dav_ext_propfind_response(r, &entries, props); -} - - -static ngx_int_t -ngx_http_dav_ext_set_locks(ngx_http_request_t *r, - ngx_http_dav_ext_entry_t *entry) -{ - ngx_http_dav_ext_node_t *node; - ngx_http_dav_ext_lock_t *lock; - ngx_http_dav_ext_loc_conf_t *dlcf; - - dlcf = ngx_http_get_module_loc_conf(r, ngx_http_dav_ext_module); - - if (dlcf->shm_zone == NULL) { - entry->lock_supported = 0; - return NGX_OK; - } - - entry->lock_supported = 1; - - lock = dlcf->shm_zone->data; - - ngx_shmtx_lock(&lock->shpool->mutex); - - node = ngx_http_dav_ext_lock_lookup(r, lock, &entry->uri, -1); - if (node == NULL) { - ngx_shmtx_unlock(&lock->shpool->mutex); - return NGX_OK; - } - - entry->lock_infinite = node->infinite ? 1 : 0; - entry->lock_expire = node->expire; - entry->lock_token = node->token; - - entry->lock_root.data = ngx_pnalloc(r->pool, node->len); - if (entry->lock_root.data == NULL) { - ngx_shmtx_unlock(&lock->shpool->mutex); - return NGX_ERROR; - } - - ngx_memcpy(entry->lock_root.data, node->data, node->len); - entry->lock_root.len = node->len; - - ngx_shmtx_unlock(&lock->shpool->mutex); - - return NGX_OK; -} - - -static ngx_int_t -ngx_http_dav_ext_propfind_response(ngx_http_request_t *r, ngx_array_t *entries, - ngx_uint_t props) -{ - size_t len; - u_char *p; - uintptr_t escape; - ngx_buf_t *b; - ngx_int_t rc; - ngx_uint_t n; - ngx_chain_t cl; - ngx_http_dav_ext_entry_t *entry; - - static u_char head[] = - "\n" - "\n"; - - static u_char tail[] = - "\n"; - - entry = entries->elts; - - for (n = 0; n < entries->nelts; n++) { - escape = 2 * ngx_escape_uri(NULL, entry[n].uri.data, entry[n].uri.len, - NGX_ESCAPE_URI); - if (escape == 0) { - continue; - } - - p = ngx_pnalloc(r->pool, entry[n].uri.len + escape); - if (p == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - entry[n].uri.len = (u_char *) ngx_escape_uri(p, entry[n].uri.data, - entry[n].uri.len, - NGX_ESCAPE_URI) - - p; - entry[n].uri.data = p; - } - - len = sizeof(head) - 1 + sizeof(tail) - 1; - - for (n = 0; n < entries->nelts; n++) { - len += ngx_http_dav_ext_format_propfind(r, NULL, &entry[n], props); - } - - b = ngx_create_temp_buf(r->pool, len); - if (b == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - b->last = ngx_cpymem(b->last, head, sizeof(head) - 1); - - for (n = 0; n < entries->nelts; n++) { - b->last = (u_char *) ngx_http_dav_ext_format_propfind(r, b->last, - &entry[n], props); - } - - b->last = ngx_cpymem(b->last, tail, sizeof(tail) - 1); - - b->last_buf = (r == r->main) ? 1 : 0; - b->last_in_chain = 1; - - cl.buf = b; - cl.next = NULL; - - r->headers_out.status = 207; - ngx_str_set(&r->headers_out.status_line, "207 Multi-Status"); - - r->headers_out.content_length_n = b->last - b->pos; - - r->headers_out.content_type_len = sizeof("text/xml") - 1; - ngx_str_set(&r->headers_out.content_type, "text/xml"); - r->headers_out.content_type_lowcase = NULL; - - ngx_str_set(&r->headers_out.charset, "utf-8"); - - rc = ngx_http_send_header(r); - - if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { - return rc; - } - - return ngx_http_output_filter(r, &cl); -} - - -static ngx_int_t -ngx_http_dav_ext_lock_handler(ngx_http_request_t *r) -{ - u_char *last; - size_t n, root; - time_t now; - uint32_t token, new_token; - ngx_fd_t fd; - ngx_int_t rc, depth; - ngx_str_t path; - ngx_uint_t status; - ngx_file_info_t fi; - ngx_http_dav_ext_lock_t *lock; - ngx_http_dav_ext_node_t *node; - ngx_http_dav_ext_loc_conf_t *dlcf; - - if (r->uri.len == 0) { - return NGX_HTTP_BAD_REQUEST; - } - - dlcf = ngx_http_get_module_loc_conf(r, ngx_http_dav_ext_module); - lock = dlcf->shm_zone->data; - - /* - * RFC4918: - * If no Depth header is submitted on a LOCK request, then the request - * MUST act as if a "Depth:infinity" had been submitted. - */ - - rc = ngx_http_dav_ext_depth(r, NGX_MAX_INT_T_VALUE); - - if (rc == NGX_ERROR || rc == 1) { - - /* - * RFC4918: - * Values other than 0 or infinity MUST NOT be used with the Depth - * header on a LOCK method. - */ - - return NGX_HTTP_BAD_REQUEST; - } - - depth = rc; - - token = ngx_http_dav_ext_if(r, &r->uri); - - do { - new_token = ngx_random(); - } while (new_token == 0); - - now = ngx_time(); - - ngx_shmtx_lock(&lock->shpool->mutex); - - node = ngx_http_dav_ext_lock_lookup(r, lock, &r->uri, depth); - - if (node) { - if (token == 0) { - ngx_shmtx_unlock(&lock->shpool->mutex); - return 423; /* Locked */ - } - - if (node->token != token) { - ngx_shmtx_unlock(&lock->shpool->mutex); - return NGX_HTTP_PRECONDITION_FAILED; - } - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http dav_ext refresh lock"); - - node->expire = now + lock->timeout; - - ngx_queue_remove(&node->queue); - ngx_queue_insert_tail(&lock->sh->queue, &node->queue); - - ngx_shmtx_unlock(&lock->shpool->mutex); - - return ngx_http_dav_ext_lock_response(r, NGX_HTTP_OK, lock->timeout, - depth, token); - } - - n = sizeof(ngx_http_dav_ext_node_t) + r->uri.len - 1; - - node = ngx_slab_alloc_locked(lock->shpool, n); - if (node == NULL) { - ngx_shmtx_unlock(&lock->shpool->mutex); - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - ngx_memzero(node, sizeof(ngx_http_dav_ext_node_t)); - - ngx_memcpy(&node->data, r->uri.data, r->uri.len); - - node->len = r->uri.len; - node->token = new_token; - node->expire = now + lock->timeout; - node->infinite = (depth ? 1 : 0); - - ngx_queue_insert_tail(&lock->sh->queue, &node->queue); - - ngx_shmtx_unlock(&lock->shpool->mutex); - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http dav_ext add lock"); - - last = ngx_http_map_uri_to_path(r, &path, &root, 0); - if (last == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - *last = '\0'; - - status = NGX_HTTP_OK; - - if (ngx_file_info(path.data, &fi) == NGX_FILE_ERROR) { - - /* - * RFC4918: - * A successful lock request to an unmapped URL MUST result in the - * creation of a locked (non-collection) resource with empty content. - */ - - fd = ngx_open_file(path.data, NGX_FILE_RDONLY, NGX_FILE_CREATE_OR_OPEN, - NGX_FILE_DEFAULT_ACCESS); - - if (fd == NGX_INVALID_FILE) { - - /* - * RFC4918: - * 409 (Conflict) - A resource cannot be created at the destination - * until one or more intermediate collections have been created. - * The server MUST NOT create those intermediate collections - * automatically. - */ - - ngx_log_error(NGX_LOG_ERR, r->connection->log, ngx_errno, - ngx_open_file_n " \"%s\" failed", path.data); - return NGX_HTTP_CONFLICT; - } - - if (ngx_close_file(fd) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno, - ngx_close_file_n " \"%s\" failed", path.data); - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - status = NGX_HTTP_CREATED; - } - - return ngx_http_dav_ext_lock_response(r, status, lock->timeout, depth, - new_token); -} - - -static ngx_int_t -ngx_http_dav_ext_lock_response(ngx_http_request_t *r, ngx_uint_t status, - time_t timeout, ngx_uint_t depth, uint32_t token) -{ - size_t len; - time_t now; - u_char *p; - ngx_int_t rc; - ngx_buf_t *b; - ngx_chain_t cl; - ngx_table_elt_t *h; - ngx_http_dav_ext_entry_t entry; - - static u_char head[] = - "\n" - "\n"; - - static u_char tail[] = - "\n"; - - now = ngx_time(); - - ngx_memzero(&entry, sizeof(ngx_http_dav_ext_entry_t)); - - entry.lock_expire = now + timeout; - entry.lock_root = r->uri; - entry.lock_infinite = depth ? 1 : 0; - entry.lock_token = token; - - len = sizeof(head) - 1 - + ngx_http_dav_ext_format_lockdiscovery(r, NULL, &entry) - + sizeof(tail) - 1; - - b = ngx_create_temp_buf(r->pool, len); - if (b == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - b->last = ngx_cpymem(b->last, head, sizeof(head) - 1); - b->last = (u_char *) ngx_http_dav_ext_format_lockdiscovery(r, b->last, - &entry); - b->last = ngx_cpymem(b->last, tail, sizeof(tail) - 1); - - b->last_buf = (r == r->main) ? 1 : 0; - b->last_in_chain = 1; - - cl.buf = b; - cl.next = NULL; - - r->headers_out.status = status; - r->headers_out.content_length_n = b->last - b->pos; - - r->headers_out.content_type_len = sizeof("text/xml") - 1; - ngx_str_set(&r->headers_out.content_type, "text/xml"); - r->headers_out.content_type_lowcase = NULL; - - ngx_str_set(&r->headers_out.charset, "utf-8"); - - h = ngx_list_push(&r->headers_out.headers); - if (h == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - ngx_str_set(&h->key, "Lock-Token"); - - p = ngx_pnalloc(r->pool, ngx_http_dav_ext_format_token(NULL, token, 1)); - if (p == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - h->value.data = p; - h->value.len = (u_char *) ngx_http_dav_ext_format_token(p, token, 1) - p; - h->hash = 1; - - rc = ngx_http_send_header(r); - - if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { - return rc; - } - - return ngx_http_output_filter(r, &cl); -} - - -static ngx_int_t -ngx_http_dav_ext_unlock_handler(ngx_http_request_t *r) -{ - uint32_t token; - ngx_http_dav_ext_lock_t *lock; - ngx_http_dav_ext_node_t *node; - ngx_http_dav_ext_loc_conf_t *dlcf; - - token = ngx_http_dav_ext_lock_token(r); - - dlcf = ngx_http_get_module_loc_conf(r, ngx_http_dav_ext_module); - lock = dlcf->shm_zone->data; - - ngx_shmtx_lock(&lock->shpool->mutex); - - node = ngx_http_dav_ext_lock_lookup(r, lock, &r->uri, -1); - - if (node == NULL || node->token != token) { - ngx_shmtx_unlock(&lock->shpool->mutex); - return NGX_HTTP_NO_CONTENT; - } - - ngx_queue_remove(&node->queue); - ngx_slab_free_locked(lock->shpool, node); - - ngx_shmtx_unlock(&lock->shpool->mutex); - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http dav_ext delete lock"); - - return NGX_HTTP_NO_CONTENT; -} - - -static ngx_int_t -ngx_http_dav_ext_depth(ngx_http_request_t *r, ngx_int_t default_depth) -{ - ngx_table_elt_t *depth; - - depth = r->headers_in.depth; - - if (depth == NULL) { - return default_depth; - } - - if (depth->value.len == 1) { - - if (depth->value.data[0] == '0') { - return 0; - } - - if (depth->value.data[0] == '1') { - return 1; - } - - } else { - - if (depth->value.len == sizeof("infinity") - 1 - && ngx_strcmp(depth->value.data, "infinity") == 0) - { - return NGX_MAX_INT_T_VALUE; - } - } - - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "client sent invalid \"Depth\" header: \"%V\"", - &depth->value); - - return NGX_ERROR; -} - - -static uint32_t -ngx_http_dav_ext_lock_token(ngx_http_request_t *r) -{ - u_char *p, ch; - uint32_t token; - ngx_uint_t i, n; - ngx_list_part_t *part; - ngx_table_elt_t *header; - - static u_char name[] = "lock-token"; - - part = &r->headers_in.headers.part; - header = part->elts; - - for (i = 0; /* void */ ; i++) { - - if (i >= part->nelts) { - if (part->next == NULL) { - break; - } - - part = part->next; - header = part->elts; - i = 0; - } - - for (n = 0; n < sizeof(name) - 1 && n < header[i].key.len; n++) { - ch = header[i].key.data[n]; - - if (ch >= 'A' && ch <= 'Z') { - ch |= 0x20; - } - - if (name[n] != ch) { - break; - } - } - - if (n == sizeof(name) - 1 && n == header[i].key.len) { - p = header[i].value.data; - - if (ngx_strncmp(p, "= '0' && ch <= '9') { - token = token * 16 + (ch - '0'); - continue; - } - - ch = (u_char) (ch | 0x20); - - if (ch >= 'a' && ch <= 'f') { - token = token * 16 + (ch - 'a' + 10); - continue; - } - - return 0; - } - - if (*p != '>') { - return 0; - } - - return token; - } - } - - return 0; -} - - -static uint32_t -ngx_http_dav_ext_if(ngx_http_request_t *r, ngx_str_t *uri) -{ - u_char *p, ch; - uint32_t token; - ngx_str_t tag; - ngx_uint_t i, n; - ngx_list_part_t *part; - ngx_table_elt_t *header; - - static u_char name[] = "if"; - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http dav_ext if \"%V\"", uri); - - part = &r->headers_in.headers.part; - header = part->elts; - - for (i = 0; /* void */ ; i++) { - - if (i >= part->nelts) { - if (part->next == NULL) { - break; - } - - part = part->next; - header = part->elts; - i = 0; - } - - for (n = 0; n < sizeof(name) - 1 && n < header[i].key.len; n++) { - ch = header[i].key.data[n]; - - if (ch >= 'A' && ch <= 'Z') { - ch |= 0x20; - } - - if (name[n] != ch) { - break; - } - } - - if (n == sizeof(name) - 1 && n == header[i].key.len) { - p = header[i].value.data; - tag = r->uri; - - while (*p != '\0') { - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http dav_ext if list \"%s\"", p); - - while (*p == ' ') { p++; } - - if (*p == '<') { - tag.data = ++p; - - while (*p != '\0' && *p != '>') { p++; } - - if (*p == '\0') { - break; - } - - tag.len = p++ - tag.data; - - (void) ngx_http_dav_ext_strip_uri(r, &tag); - - while (*p == ' ') { p++; } - } - - if (*p != '(') { - break; - } - - p++; - - if (tag.len == 0 - || tag.len > uri->len - || (tag.len < uri->len && tag.data[tag.len - 1] != '/') - || ngx_memcmp(tag.data, uri->data, tag.len)) - { - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http dav_ext if tag mismatch \"%V\"", &tag); - - while (*p != '\0' && *p != ')') { p++; } - - if (*p == ')') { - p++; - } - - continue; - } - - while (*p != '\0') { - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http dav_ext if condition \"%s\"", p); - - while (*p == ' ') { p++; } - - if (ngx_strncmp(p, "Not", 3) == 0) { - p += 3; - while (*p == ' ') { p++; } - goto next; - } - - if (*p == '[') { - p++; - while (*p != '\0' && *p != ']') { p++; } - goto next; - } - - if (ngx_strncmp(p, "= '0' && ch <= '9') { - token = token * 16 + (ch - '0'); - continue; - } - - ch = (u_char) (ch | 0x20); - - if (ch >= 'a' && ch <= 'f') { - token = token * 16 + (ch - 'a' + 10); - continue; - } - - goto next; - } - - if (*p != '>') { - goto next; - } - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http dav_ext if token: %uxD", token); - - return token; - - next: - - while (*p != '\0' && *p != ' ' && *p != ')') { p++; } - - if (*p == ')') { - p++; - break; - } - } - } - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http dav_ext if header mismatch"); - } - } - - return 0; -} - - -static uintptr_t -ngx_http_dav_ext_format_propfind(ngx_http_request_t *r, u_char *dst, - ngx_http_dav_ext_entry_t *entry, ngx_uint_t props) -{ - size_t len; - - static u_char head[] = - "\n" - ""; - - /* uri */ - - static u_char prop[] = - "\n" - "\n" - "\n"; - - /* properties */ - - static u_char tail[] = - "\n" - "HTTP/1.1 200 OK\n" - "\n" - "\n"; - - static u_char names[] = - "\n" - "\n" - "\n" - "\n" - "\n" - "\n"; - - static u_char supportedlock[] = - "\n" - "\n" - "\n" - "\n"; - - if (dst == NULL) { - len = sizeof(head) - 1 - + sizeof(prop) - 1 - + sizeof(tail) - 1; - - len += entry->uri.len + ngx_escape_html(NULL, entry->uri.data, - entry->uri.len); - - if (props & NGX_HTTP_DAV_EXT_PROP_NAMES) { - len += sizeof(names) - 1; - - } else { - len += sizeof("" - "\n" - - "" - "\n" - - "" - "Mon, 28 Sep 1970 06:00:00 GMT" - "\n" - - "" - "" - "\n" - - "\n" - "\n") - 1; - - /* displayname */ - len += entry->name.len - + ngx_escape_html(NULL, entry->name.data, entry->name.len); - - /* getcontentlength */ - len += NGX_OFF_T_LEN; - - /* lockdiscovery */ - len += ngx_http_dav_ext_format_lockdiscovery(r, NULL, entry); - - /* supportedlock */ - if (entry->lock_supported) { - len += sizeof(supportedlock) - 1; - } - } - - return len; - } - - dst = ngx_cpymem(dst, head, sizeof(head) - 1); - dst = (u_char *) ngx_escape_html(dst, entry->uri.data, entry->uri.len); - dst = ngx_cpymem(dst, prop, sizeof(prop) - 1); - - if (props & NGX_HTTP_DAV_EXT_PROP_NAMES) { - dst = ngx_cpymem(dst, names, sizeof(names) - 1); - - } else { - if (props & NGX_HTTP_DAV_EXT_PROP_DISPLAYNAME) { - dst = ngx_cpymem(dst, "", - sizeof("") - 1); - dst = (u_char *) ngx_escape_html(dst, entry->name.data, - entry->name.len); - dst = ngx_cpymem(dst, "\n", - sizeof("\n") - 1); - } - - if (props & NGX_HTTP_DAV_EXT_PROP_GETCONTENTLENGTH) { - if (!entry->dir) { - dst = ngx_sprintf(dst, "%O" - "\n", entry->size); - } - } - - if (props & NGX_HTTP_DAV_EXT_PROP_GETLASTMODIFIED) { - dst = ngx_cpymem(dst, "", - sizeof("") - 1); - dst = ngx_http_time(dst, entry->mtime); - dst = ngx_cpymem(dst, "\n", - sizeof("\n") - 1); - } - - if (props & NGX_HTTP_DAV_EXT_PROP_RESOURCETYPE) { - dst = ngx_cpymem(dst, "", - sizeof("") - 1); - - if (entry->dir) { - dst = ngx_cpymem(dst, "", - sizeof("") - 1); - } - - dst = ngx_cpymem(dst, "\n", - sizeof("\n") - 1); - } - - if (props & NGX_HTTP_DAV_EXT_PROP_LOCKDISCOVERY) { - dst = (u_char *) ngx_http_dav_ext_format_lockdiscovery(r, dst, - entry); - } - - if (props & NGX_HTTP_DAV_EXT_PROP_SUPPORTEDLOCK) { - dst = ngx_cpymem(dst, "\n", - sizeof("\n") - 1); - - if (entry->lock_supported) { - dst = ngx_cpymem(dst, supportedlock, sizeof(supportedlock) - 1); - } - - dst = ngx_cpymem(dst, "\n", - sizeof("\n") - 1); - } - } - - dst = ngx_cpymem(dst, tail, sizeof(tail) - 1); - - return (uintptr_t) dst; -} - - -static uintptr_t -ngx_http_dav_ext_format_lockdiscovery(ngx_http_request_t *r, u_char *dst, - ngx_http_dav_ext_entry_t *entry) -{ - size_t len; - time_t now; - - if (dst == NULL) { - if (entry->lock_token == 0) { - return sizeof("\n") - 1; - } - - len = sizeof("\n" - "\n" - "\n" - "\n" - "infinity\n" - "Second-\n" - "\n" - "\n" - "\n" - "\n") - 1; - - /* timeout */ - len += NGX_TIME_T_LEN; - - /* token */ - len += ngx_http_dav_ext_format_token(NULL, entry->lock_token, 0); - - /* lockroot */ - len += entry->lock_root.len + ngx_escape_html(NULL, - entry->lock_root.data, - entry->lock_root.len); - return len; - } - - if (entry->lock_token == 0) { - dst = ngx_cpymem(dst, "\n", - sizeof("\n") - 1); - return (uintptr_t) dst; - } - - now = ngx_time(); - - dst = ngx_cpymem(dst, "\n", - sizeof("\n") - 1); - - dst = ngx_cpymem(dst, "\n", - sizeof("\n") - 1); - - dst = ngx_cpymem(dst, "\n", - sizeof("\n") - 1); - - dst = ngx_cpymem(dst, "\n", - sizeof("\n") - 1); - - dst = ngx_sprintf(dst, "%s\n", - entry->lock_infinite ? "infinity" : "0"); - - dst = ngx_sprintf(dst, "Second-%T\n", - entry->lock_expire - now); - - dst = ngx_cpymem(dst, "", - sizeof("") - 1); - dst = (u_char *) ngx_http_dav_ext_format_token(dst, entry->lock_token, 0); - dst = ngx_cpymem(dst, "\n", - sizeof("\n") - 1); - - dst = ngx_cpymem(dst, "", - sizeof("") - 1); - dst = (u_char *) ngx_escape_html(dst, entry->lock_root.data, - entry->lock_root.len); - dst = ngx_cpymem(dst, "\n", - sizeof("\n") - 1); - - dst = ngx_cpymem(dst, "\n", - sizeof("\n") - 1); - - dst = ngx_cpymem(dst, "\n", - sizeof("\n") - 1); - - return (uintptr_t) dst; -} - - -static uintptr_t -ngx_http_dav_ext_format_token(u_char *dst, uint32_t token, ngx_uint_t brackets) -{ - ngx_uint_t n; - - static u_char hex[] = "0123456789abcdef"; - - if (dst == NULL) { - return sizeof("") - 1 + (brackets ? 2 : 0); - } - - if (brackets) { - *dst++ = '<'; - } - - dst = ngx_cpymem(dst, "urn:", 4); - - for (n = 0; n < 4; n++) { - *dst++ = hex[token >> 28]; - *dst++ = hex[(token >> 24) & 0xf]; - token <<= 8; - } - - if (brackets) { - *dst++ = '>'; - } - - return (uintptr_t) dst; -} - - -static ngx_int_t -ngx_http_dav_ext_init_zone(ngx_shm_zone_t *shm_zone, void *data) -{ - ngx_http_dav_ext_lock_t *olock = data; - - size_t len; - ngx_http_dav_ext_lock_t *lock; - - lock = shm_zone->data; - - if (olock) { - lock->sh = olock->sh; - lock->shpool = olock->shpool; - return NGX_OK; - } - - lock->shpool = (ngx_slab_pool_t *) shm_zone->shm.addr; - - if (shm_zone->shm.exists) { - lock->sh = lock->shpool->data; - return NGX_OK; - } - - lock->sh = ngx_slab_alloc(lock->shpool, sizeof(ngx_http_dav_ext_lock_sh_t)); - if (lock->sh == NULL) { - return NGX_ERROR; - } - - lock->shpool->data = lock->sh; - - ngx_queue_init(&lock->sh->queue); - - len = sizeof(" in dav_ext zone \"\"") + shm_zone->shm.name.len; - - lock->shpool->log_ctx = ngx_slab_alloc(lock->shpool, len); - if (lock->shpool->log_ctx == NULL) { - return NGX_ERROR; - } - - ngx_sprintf(lock->shpool->log_ctx, " in dav_ext zone \"%V\"%Z", - &shm_zone->shm.name); - - return NGX_OK; -} - - -static void * -ngx_http_dav_ext_create_loc_conf(ngx_conf_t *cf) -{ - ngx_http_dav_ext_loc_conf_t *conf; - - conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_dav_ext_loc_conf_t)); - if (conf == NULL) { - return NULL; - } - - /* - * set by ngx_pcalloc(): - * - * conf->shm_zone = NULL; - */ - - return conf; -} - - -static char * -ngx_http_dav_ext_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) -{ - ngx_http_dav_ext_loc_conf_t *prev = parent; - ngx_http_dav_ext_loc_conf_t *conf = child; - - ngx_conf_merge_bitmask_value(conf->methods, prev->methods, - (NGX_CONF_BITMASK_SET|NGX_HTTP_DAV_EXT_OFF)); - - if (conf->shm_zone == NULL) { - conf->shm_zone = prev->shm_zone; - } - - return NGX_CONF_OK; -} - - -static char * -ngx_http_dav_ext_lock_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) -{ - u_char *p; - time_t timeout; - ssize_t size; - ngx_str_t *value, name, s; - ngx_uint_t i; - ngx_shm_zone_t *shm_zone; - ngx_http_dav_ext_lock_t *lock; - - value = cf->args->elts; - - name.len = 0; - size = 0; - timeout = 60; - - for (i = 1; i < cf->args->nelts; i++) { - - if (ngx_strncmp(value[i].data, "zone=", 5) == 0) { - - name.data = value[i].data + 5; - - p = (u_char *) ngx_strchr(name.data, ':'); - - if (p == NULL) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid zone size \"%V\"", &value[i]); - return NGX_CONF_ERROR; - } - - name.len = p - name.data; - - s.data = p + 1; - s.len = value[i].data + value[i].len - s.data; - - size = ngx_parse_size(&s); - - if (size == NGX_ERROR) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid zone size \"%V\"", &value[i]); - return NGX_CONF_ERROR; - } - - if (size < (ssize_t) (8 * ngx_pagesize)) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "zone \"%V\" is too small", &value[i]); - return NGX_CONF_ERROR; - } - - continue; - } - - if (ngx_strncmp(value[i].data, "timeout=", 8) == 0) { - - s.len = value[i].len - 8; - s.data = value[i].data + 8; - - timeout = ngx_parse_time(&s, 1); - if (timeout == (time_t) NGX_ERROR || timeout == 0) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid timeout value \"%V\"", &value[i]); - return NGX_CONF_ERROR; - } - - continue; - } - - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid parameter \"%V\"", &value[i]); - return NGX_CONF_ERROR; - } - - if (name.len == 0) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "\"%V\" must have \"zone\" parameter", - &cmd->name); - return NGX_CONF_ERROR; - } - - lock = ngx_pcalloc(cf->pool, sizeof(ngx_http_dav_ext_lock_t)); - if (lock == NULL) { - return NGX_CONF_ERROR; - } - - lock->timeout = timeout; - - shm_zone = ngx_shared_memory_add(cf, &name, size, - &ngx_http_dav_ext_module); - if (shm_zone == NULL) { - return NGX_CONF_ERROR; - } - - if (shm_zone->data) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "duplicate zone \"%V\"", &name); - return NGX_CONF_ERROR; - } - - shm_zone->init = ngx_http_dav_ext_init_zone; - shm_zone->data = lock; - - return NGX_CONF_OK; -} - - -static char * -ngx_http_dav_ext_lock(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) -{ - ngx_http_dav_ext_loc_conf_t *dlcf = conf; - - ngx_str_t *value, s; - ngx_uint_t i; - ngx_shm_zone_t *shm_zone; - - if (dlcf->shm_zone) { - return "is duplicate"; - } - - value = cf->args->elts; - - shm_zone = NULL; - - for (i = 1; i < cf->args->nelts; i++) { - - if (ngx_strncmp(value[i].data, "zone=", 5) == 0) { - - s.len = value[i].len - 5; - s.data = value[i].data + 5; - - shm_zone = ngx_shared_memory_add(cf, &s, 0, - &ngx_http_dav_ext_module); - if (shm_zone == NULL) { - return NGX_CONF_ERROR; - } - - continue; - } - - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid parameter \"%V\"", &value[i]); - return NGX_CONF_ERROR; - } - - if (shm_zone == NULL) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "\"%V\" must have \"zone\" parameter", &cmd->name); - return NGX_CONF_ERROR; - } - - dlcf->shm_zone = shm_zone; - - return NGX_CONF_OK; -} - - -static ngx_int_t -ngx_http_dav_ext_init(ngx_conf_t *cf) -{ - ngx_http_handler_pt *h; - ngx_http_core_main_conf_t *cmcf; - - cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); - - h = ngx_array_push(&cmcf->phases[NGX_HTTP_PRECONTENT_PHASE].handlers); - if (h == NULL) { - return NGX_ERROR; - } - - *h = ngx_http_dav_ext_precontent_handler; - - h = ngx_array_push(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers); - if (h == NULL) { - return NGX_ERROR; - } - - *h = ngx_http_dav_ext_content_handler; - - return NGX_OK; -} diff --git a/debian/modules/http-dav-ext/t/dav_ext.t b/debian/modules/http-dav-ext/t/dav_ext.t deleted file mode 100644 index 00327e2..0000000 --- a/debian/modules/http-dav-ext/t/dav_ext.t +++ /dev/null @@ -1,141 +0,0 @@ -#!/usr/bin/perl - -# (C) Roman Arutyunyan - -# Tests for nginx-dav-ext-module. - -############################################################################### - -use warnings; -use strict; - -use Test::More; - -BEGIN { use FindBin; chdir($FindBin::Bin); } - -use lib 'lib'; -use Test::Nginx; -use HTTP::DAV - -############################################################################### - -select STDERR; $| = 1; -select STDOUT; $| = 1; - -my $t = Test::Nginx->new()->has(qw/http dav/)->plan(20); - -$t->write_file_expand('nginx.conf', <<'EOF'); - -%%TEST_GLOBALS%% - -daemon off; - -events { -} - -http { - %%TEST_GLOBALS_HTTP%% - - dav_ext_lock_zone zone=foo:10m timeout=10s; - - server { - listen 127.0.0.1:8080; - server_name localhost; - - location / { - dav_methods PUT DELETE MKCOL COPY MOVE; - dav_ext_methods PROPFIND OPTIONS LOCK UNLOCK; - dav_ext_lock zone=foo; - } - } -} - -EOF - -$t->write_file('foo', 'foo'); - -$t->run(); - -############################################################################### - -my $url = "http://127.0.0.1:8080"; - -my $content; - -my $d = HTTP::DAV->new(); -$d->open($url); - -my $d2 = HTTP::DAV->new(); -$d2->open($url); - -#debug: -#$d->DebugLevel(3); -#see /tmp/perldav_debug.txt. - -my $p = $d->propfind('/', 1); -is($p->is_collection, 1, 'propfind dir collection'); -is($p->get_property('displayname'), '/', 'propfind dir displayname'); -is($p->get_uri(), 'http://127.0.0.1:8080/', 'propfind dir uri'); - -$p = $d->propfind('/foo'); -is($p->is_collection, 0, 'propfind file collection'); -is($p->get_property('displayname'), 'foo', 'propfind file displayname'); -is($p->get_uri(), 'http://127.0.0.1:8080/foo', 'propfind file uri'); -is($p->get_property('getcontentlength'), '3', 'propfind file size'); - -$d->lock('/foo'); -is($d->lock('/foo'), 0, 'prevent double lock'); - -$d->unlock('/foo'); -is($d->lock('/foo'), 1, 'relock'); - -$d->lock('/bar'); -$p = $d->propfind('/bar'); -is($p->get_property('displayname'), 'bar', 'lock creates a file'); - -$d->get('/bar', \$content) or $content = 'none'; -is($content, '', 'lock creates an empty file'); - -$content = "bar"; -$d->put(\$content, '/bar'); -$d->get('/bar', \$content) or $content = ''; -is($content, 'bar', 'put lock'); - -$content = "qux"; -$d2->put(\$content, '/bar'); -$d2->get('/bar', \$content) or $content = ''; -isnt($content, 'qux', 'prevent put lock'); - -$d->mkcol('/d/'); -$d->lock('/d/'); -$d->copy('/bar', '/d/bar'); -$d->get('/d/bar', \$content) or $content = ''; -is($content, 'bar', 'copy lock'); - -$d2->copy('/bar', '/d/qux'); -$d2->get('/d/qux', \$content) or $content = ''; -isnt($content, 'bar', 'prevent copy lock'); - -$d2->delete('/d/bar'); -$d2->get('/d/bar', \$content) or $content = ''; -is($content, 'bar', 'prevent delete lock'); - -$d->delete('/d/bar'); -$d->get('/d/bar', \$content) or $content = ''; -is($content, '', 'delete lock'); - -$d->mkcol('/d/c/'); -$p = $d->propfind('/d/c/'); -is($p->is_collection, 1, 'mkcol lock'); - -$d2->mkcol('/d/e/'); -is($d2->propfind('/d/e/'), 0, 'prevent mkcol lock'); - -$d->unlock('/d/'); -$d->lock('/d/', -depth=>"0"); -$content = 'qux'; -$d2->put(\$content, '/d/c/qux'); -$d2->get('/d/c/qux', \$content) or $content = ''; -is($content, 'qux', 'put to a depth-0-locked subdirectory'); - -############################################################################### diff --git a/debian/modules/http-echo/LICENSE b/debian/modules/http-echo/LICENSE deleted file mode 100644 index 6feffbf..0000000 --- a/debian/modules/http-echo/LICENSE +++ /dev/null @@ -1,25 +0,0 @@ -Copyright (C) 2009-2014, Yichun "agentzh" Zhang . -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/debian/modules/http-echo/README.markdown b/debian/modules/http-echo/README.markdown deleted file mode 100644 index 02d4608..0000000 --- a/debian/modules/http-echo/README.markdown +++ /dev/null @@ -1,1851 +0,0 @@ -Name -==== - -**ngx_echo** - Brings "echo", "sleep", "time", "exec" and more shell-style goodies to Nginx config file. - -*This module is not distributed with the Nginx source.* See [the installation instructions](#installation). - -Table of Contents -================= - -* [Name](#name) -* [Status](#status) -* [Version](#version) -* [Synopsis](#synopsis) -* [Description](#description) -* [Content Handler Directives](#content-handler-directives) - * [echo](#echo) - * [echo_duplicate](#echo_duplicate) - * [echo_flush](#echo_flush) - * [echo_sleep](#echo_sleep) - * [echo_blocking_sleep](#echo_blocking_sleep) - * [echo_reset_timer](#echo_reset_timer) - * [echo_read_request_body](#echo_read_request_body) - * [echo_location_async](#echo_location_async) - * [echo_location](#echo_location) - * [echo_subrequest_async](#echo_subrequest_async) - * [echo_subrequest](#echo_subrequest) - * [echo_foreach_split](#echo_foreach_split) - * [echo_end](#echo_end) - * [echo_request_body](#echo_request_body) - * [echo_exec](#echo_exec) - * [echo_status](#echo_status) -* [Filter Directives](#filter-directives) - * [echo_before_body](#echo_before_body) - * [echo_after_body](#echo_after_body) -* [Variables](#variables) - * [$echo_it](#echo_it) - * [$echo_timer_elapsed](#echo_timer_elapsed) - * [$echo_request_body](#echo_request_body) - * [$echo_request_method](#echo_request_method) - * [$echo_client_request_method](#echo_client_request_method) - * [$echo_client_request_headers](#echo_client_request_headers) - * [$echo_cacheable_request_uri](#echo_cacheable_request_uri) - * [$echo_request_uri](#echo_request_uri) - * [$echo_incr](#echo_incr) - * [$echo_response_status](#echo_response_status) -* [Installation](#installation) -* [Compatibility](#compatibility) -* [Modules that use this module for testing](#modules-that-use-this-module-for-testing) -* [Community](#community) - * [English Mailing List](#english-mailing-list) - * [Chinese Mailing List](#chinese-mailing-list) -* [Report Bugs](#report-bugs) -* [Source Repository](#source-repository) -* [Changes](#changes) -* [Test Suite](#test-suite) -* [TODO](#todo) -* [Getting involved](#getting-involved) -* [Author](#author) -* [Copyright & License](#copyright--license) -* [See Also](#see-also) - -Status -====== - -This module is production ready. - -Version -======= - -This document describes ngx_echo [v0.61](https://github.com/openresty/echo-nginx-module/tags) released on 8 August 2017. - -Synopsis -======== - -```nginx - - location /hello { - echo "hello, world!"; - } -``` - -```nginx - - location /hello { - echo -n "hello, "; - echo "world!"; - } -``` - -```nginx - - location /timed_hello { - echo_reset_timer; - echo hello world; - echo "'hello world' takes about $echo_timer_elapsed sec."; - echo hiya igor; - echo "'hiya igor' takes about $echo_timer_elapsed sec."; - } -``` - -```nginx - - location /echo_with_sleep { - echo hello; - echo_flush; # ensure the client can see previous output immediately - echo_sleep 2.5; # in sec - echo world; - } -``` - -```nginx - - # in the following example, accessing /echo yields - # hello - # world - # blah - # hiya - # igor - location /echo { - echo_before_body hello; - echo_before_body world; - proxy_pass $scheme://127.0.0.1:$server_port$request_uri/more; - echo_after_body hiya; - echo_after_body igor; - } - location /echo/more { - echo blah; - } -``` - -```nginx - - # the output of /main might be - # hello - # world - # took 0.000 sec for total. - # and the whole request would take about 2 sec to complete. - location /main { - echo_reset_timer; - - # subrequests in parallel - echo_location_async /sub1; - echo_location_async /sub2; - - echo "took $echo_timer_elapsed sec for total."; - } - location /sub1 { - echo_sleep 2; - echo hello; - } - location /sub2 { - echo_sleep 1; - echo world; - } -``` - -```nginx - - # the output of /main might be - # hello - # world - # took 3.003 sec for total. - # and the whole request would take about 3 sec to complete. - location /main { - echo_reset_timer; - - # subrequests in series (chained by CPS) - echo_location /sub1; - echo_location /sub2; - - echo "took $echo_timer_elapsed sec for total."; - } - location /sub1 { - echo_sleep 2; - echo hello; - } - location /sub2 { - echo_sleep 1; - echo world; - } -``` - -```nginx - - # Accessing /dup gives - # ------ END ------ - location /dup { - echo_duplicate 3 "--"; - echo_duplicate 1 " END "; - echo_duplicate 3 "--"; - echo; - } -``` - -```nginx - - # /bighello will generate 1000,000,000 hello's. - location /bighello { - echo_duplicate 1000_000_000 'hello'; - } -``` - -```nginx - - # echo back the client request - location /echoback { - echo_duplicate 1 $echo_client_request_headers; - echo "\r"; - - echo_read_request_body; - - echo_request_body; - } -``` - -```nginx - - # GET /multi will yields - # querystring: foo=Foo - # method: POST - # body: hi - # content length: 2 - # /// - # querystring: bar=Bar - # method: PUT - # body: hello - # content length: 5 - # /// - location /multi { - echo_subrequest_async POST '/sub' -q 'foo=Foo' -b 'hi'; - echo_subrequest_async PUT '/sub' -q 'bar=Bar' -b 'hello'; - } - location /sub { - echo "querystring: $query_string"; - echo "method: $echo_request_method"; - echo "body: $echo_request_body"; - echo "content length: $http_content_length"; - echo '///'; - } -``` - -```nginx - - # GET /merge?/foo.js&/bar/blah.js&/yui/baz.js will merge the .js resources together - location /merge { - default_type 'text/javascript'; - echo_foreach_split '&' $query_string; - echo "/* JS File $echo_it */"; - echo_location_async $echo_it; - echo; - echo_end; - } -``` - -```nginx - - # accessing /if?val=abc yields the "hit" output - # while /if?val=bcd yields "miss": - location ^~ /if { - set $res miss; - if ($arg_val ~* '^a') { - set $res hit; - echo $res; - } - echo $res; - } -``` - -[Back to TOC](#table-of-contents) - -Description -=========== - -This module wraps lots of Nginx internal APIs for streaming input and output, parallel/sequential subrequests, timers and sleeping, as well as various meta data accessing. - -Basically it provides various utilities that help testing and debugging of other modules by trivially emulating different kinds of faked subrequest locations. - -People will also find it useful in real-world applications that need to - -1. serve static contents directly from memory (loading from the Nginx config file). -1. wrap the upstream response with custom header and footer (kinda like the [addition module](http://nginx.org/en/docs/http/ngx_http_addition_module.html) but with contents read directly from the config file and Nginx variables). -1. merge contents of various "Nginx locations" (i.e., subrequests) together in a single main request (using [echo_location](#echo_location) and its friends). - -This is a special dual-role module that can *lazily* serve as a content handler or register itself as an output filter only upon demand. By default, this module does not do anything at all. - -Technically, this module has also demonstrated the following techniques that might be helpful for module writers: - -1. Issue parallel subrequests directly from content handler. -1. Issue chained subrequests directly from content handler, by passing continuation along the subrequest chain. -1. Issue subrequests with all HTTP 1.1 methods and even an optional faked HTTP request body. -1. Interact with the Nginx event model directly from content handler using custom events and timers, and resume the content handler back if necessary. -1. Dual-role module that can (lazily) serve as a content handler or an output filter or both. -1. Nginx config file variable creation and interpolation. -1. Streaming output control using output_chain, flush and its friends. -1. Read client request body from the content handler, and returns back (asynchronously) to the content handler after completion. -1. Use Perl-based declarative [test suite](#test-suite) to drive the development of Nginx C modules. - -[Back to TOC](#table-of-contents) - -Content Handler Directives -========================== - -Use of the following directives register this module to the current Nginx location as a content handler. If you want to use another module, like the [standard proxy module](http://nginx.org/en/docs/http/ngx_http_proxy_module.html), as the content handler, use the [filter directives](#filter-directives) provided by this module. - -All the content handler directives can be mixed together in a single Nginx location and they're supposed to run sequentially just as in the Bash scripting language. - -Every content handler directive supports variable interpolation in its arguments (if any). - -The MIME type set by the [standard default_type directive](http://nginx.org/en/docs/http/ngx_http_core_module.html#default_type) is respected by this module, as in: - -```nginx - - location /hello { - default_type text/plain; - echo hello; - } -``` - -Then on the client side: - -```bash - - $ curl -I 'http://localhost/echo' - HTTP/1.1 200 OK - Server: nginx/0.8.20 - Date: Sat, 17 Oct 2009 03:40:19 GMT - Content-Type: text/plain - Connection: keep-alive -``` - -Since the [v0.22](#v022) release, all of the directives are allowed in the [rewrite module](http://nginx.org/en/docs/http/ngx_http_rewrite_module.html)'s [if](http://nginx.org/en/docs/http/ngx_http_rewrite_module.html#if) directive block, for instance: - -```nginx - - location ^~ /if { - set $res miss; - if ($arg_val ~* '^a') { - set $res hit; - echo $res; - } - echo $res; - } -``` - -[Back to TOC](#table-of-contents) - -echo ----- -**syntax:** *echo \[options\] <string>...* - -**default:** *no* - -**context:** *location, location if* - -**phase:** *content* - -Sends arguments joined by spaces, along with a trailing newline, out to the client. - -Note that the data might be buffered by Nginx's underlying buffer. To force the output data flushed immediately, use the [echo_flush](#echo_flush) command just after `echo`, as in - -```nginx - - echo hello world; - echo_flush; -``` - -When no argument is specified, *echo* emits the trailing newline alone, just like the *echo* command in shell. - -Variables may appear in the arguments. An example is - -```nginx - - echo The current request uri is $request_uri; -``` - -where [$request_uri](http://nginx.org/en/docs/http/ngx_http_core_module.html#var_request_uri) is a variable exposed by the [ngx_http_core_module](http://nginx.org/en/docs/http/ngx_http_core_module.html). - -This command can be used multiple times in a single location configuration, as in - -```nginx - - location /echo { - echo hello; - echo world; - } -``` - -The output on the client side looks like this - -```bash - - $ curl 'http://localhost/echo' - hello - world -``` - -Special characters like newlines (`\n`) and tabs (`\t`) can be escaped using C-style escaping sequences. But a notable exception is the dollar sign (`$`). As of Nginx 0.8.20, there's still no clean way to escape this character. (A work-around might be to use a `$echo_dollor` variable that is always evaluated to the constant `$` character. This feature will possibly be introduced in a future version of this module.) - -As of the echo [v0.28](#v028) release, one can suppress the trailing newline character in the output by using the `-n` option, as in - -```nginx - - location /echo { - echo -n "hello, "; - echo "world"; - } -``` - -Accessing `/echo` gives - -```bash - - $ curl 'http://localhost/echo' - hello, world -``` - -Leading `-n` in variable values won't take effect and will be emitted literally, as in - -```nginx - - location /echo { - set $opt -n; - echo $opt "hello,"; - echo "world"; - } -``` - -This gives the following output - -```bash - - $ curl 'http://localhost/echo' - -n hello, - world -``` - -One can output leading `-n` literals and other options using the special `--` option like this - -```nginx - - location /echo { - echo -- -n is an option; - } -``` - -which yields - -```bash - - $ curl 'http://localhost/echo' - -n is an option -``` - -Use this form when you want to output anything leading with a dash (`-`). - -[Back to TOC](#table-of-contents) - -echo_duplicate --------------- -**syntax:** *echo_duplicate <count> <string>* - -**default:** *no* - -**context:** *location, location if* - -**phase:** *content* - -Outputs duplication of a string indicated by the second argument, using the count specified in the first argument. - -For instance, - -```nginx - - location /dup { - echo_duplicate 3 "abc"; - } -``` - -will lead to the output of `"abcabcabc"`. - -Underscores are allowed in the count number, just like in Perl. For example, to emit 1000,000,000 instances of `"hello, world"`: - -```nginx - - location /many_hellos { - echo_duplicate 1000_000_000 "hello, world"; - } -``` - -The `count` argument could be zero, but not negative. The second `string` argument could be an empty string ("") likewise. - -Unlike the [echo](#echo) directive, no trailing newline is appended to the result. So it's possible to "abuse" this directive as a no-trailing-newline version of [echo](#echo) by using "count" 1, as in - -```nginx - - location /echo_art { - echo_duplicate 2 '---'; - echo_duplicate 1 ' END '; # we don't want a trailing newline here - echo_duplicate 2 '---'; - echo; # we want a trailing newline here... - } -``` - -You get - -```bash - ------ END ------ -``` - -But use of the `-n` option in [echo](#echo) is more appropriate for this purpose. - -This directive was first introduced in [version 0.11](#v011). - -[Back to TOC](#table-of-contents) - -echo_flush ----------- -**syntax:** *echo_flush* - -**default:** *no* - -**context:** *location, location if* - -**phase:** *content* - -Forces the data potentially buffered by underlying Nginx output filters to send immediately to the client side via socket. - -Note that techically the command just emits a ngx_buf_t object with `flush` slot set to 1, so certain weird third-party output filter module could still block it before it reaches Nginx's (last) write filter. - -This directive does not take any argument. - -Consider the following example: - -```nginx - - location /flush { - echo hello; - - echo_flush; - - echo_sleep 1; - echo world; - } -``` - -Then on the client side, using curl to access `/flush`, you'll see the "hello" line immediately, but only after 1 second, the last "world" line. Without calling `echo_flush` in the example above, you'll most likely see no output until 1 second is elapsed due to the internal buffering of Nginx. - -This directive will fail to flush the output buffer in case of subrequests get involved. Consider the following example: - -```nginx - - location /main { - echo_location_async /sub; - echo hello; - echo_flush; - } - location /sub { - echo_sleep 1; - } -``` - -Then the client won't see "hello" appear even if `echo_flush` has been executed before the subrequest to `/sub` has actually started executing. The outputs of `/main` that are sent *after* [echo_location_async](#echo_location_async) will be postponed and buffered firmly. - -This does *not* apply to outputs sent before the subrequest initiated. For a modified version of the example given above: - -```nginx - - location /main { - echo hello; - echo_flush; - echo_location_async /sub; - } - location /sub { - echo_sleep 1; - } -``` - -The client will immediately see "hello" before `/sub` enters sleeping. - -See also [echo](#echo), [echo_sleep](#echo_sleep), and [echo_location_async](#echo_location_async). - -[Back to TOC](#table-of-contents) - -echo_sleep ----------- -**syntax:** *echo_sleep <seconds>* - -**default:** *no* - -**context:** *location, location if* - -**phase:** *content* - -Sleeps for the time period specified by the argument, which is in seconds. - -This operation is non-blocking on server side, so unlike the [echo_blocking_sleep](#echo_blocking_sleep) directive, it won't block the whole Nginx worker process. - -The period might takes three digits after the decimal point and must be greater than 0.001. - -An example is - -```nginx - - location /echo_after_sleep { - echo_sleep 1.234; - echo resumed!; - } -``` - -Behind the scene, it sets up a per-request "sleep" ngx_event_t object, and adds a timer using that custom event to the Nginx event model and just waits for a timeout on that event. Because the "sleep" event is per-request, this directive can work in parallel subrequests. - -[Back to TOC](#table-of-contents) - -echo_blocking_sleep -------------------- -**syntax:** *echo_blocking_sleep <seconds>* - -**default:** *no* - -**context:** *location, location if* - -**phase:** *content* - -This is a blocking version of the [echo_sleep](#echo_sleep) directive. - -See the documentation of [echo_sleep](#echo_sleep) for more detail. - -Behind the curtain, it calls the ngx_msleep macro provided by the Nginx core which maps to usleep on POSIX-compliant systems. - -Note that this directive will block the current Nginx worker process completely while being executed, so never use it in production environment. - -[Back to TOC](#table-of-contents) - -echo_reset_timer ----------------- -**syntax:** *echo_reset_timer* - -**default:** *no* - -**context:** *location, location if* - -**phase:** *content* - -Reset the timer begin time to *now*, i.e., the time when this command is executed during request. - -The timer begin time is default to the starting time of the current request and can be overridden by this directive, potentially multiple times in a single location. For example: - -```nginx - - location /timed_sleep { - echo_sleep 0.03; - echo "$echo_timer_elapsed sec elapsed."; - - echo_reset_timer; - - echo_sleep 0.02; - echo "$echo_timer_elapsed sec elapsed."; - } -``` - -The output on the client side might be - -```bash - - $ curl 'http://localhost/timed_sleep' - 0.032 sec elapsed. - 0.020 sec elapsed. -``` - -The actual figures you get on your side may vary a bit due to your system's current activities. - -Invocation of this directive will force the underlying Nginx timer to get updated to the current system time (regardless the timer resolution specified elsewhere in the config file). Furthermore, references of the [$echo_timer_elapsed](#echo_timer_elapsed) variable will also trigger timer update forcibly. - -See also [echo_sleep](#echo_sleep) and [$echo_timer_elapsed](#echo_timer_elapsed). - -[Back to TOC](#table-of-contents) - -echo_read_request_body ----------------------- -**syntax:** *echo_read_request_body* - -**default:** *no* - -**context:** *location, location if* - -**phase:** *content* - -Explicitly reads request body so that the [$request_body](http://nginx.org/en/docs/http/ngx_http_core_module.html#var_request_body) variable will always have non-empty values (unless the body is so big that it has been saved by Nginx to a local temporary file). - -Note that this might not be the original client request body because the current request might be a subrequest with a "artificial" body specified by its parent. - -This directive does not generate any output itself, just like [echo_sleep](#echo_sleep). - -Here's an example for echo'ing back the original HTTP client request (both headers and body are included): - -```nginx - - location /echoback { - echo_duplicate 1 $echo_client_request_headers; - echo "\r"; - echo_read_request_body; - echo $request_body; - } -``` - -The content of `/echoback` looks like this on my side (I was using Perl's LWP utility to access this location on the server): - -```bash - - $ (echo hello; echo world) | lwp-request -m POST 'http://localhost/echoback' - POST /echoback HTTP/1.1 - TE: deflate,gzip;q=0.3 - Connection: TE, close - Host: localhost - User-Agent: lwp-request/5.818 libwww-perl/5.820 - Content-Length: 12 - Content-Type: application/x-www-form-urlencoded - - hello - world -``` - -Because `/echoback` is the main request, [$request_body](http://nginx.org/en/docs/http/ngx_http_core_module.html#var_request_body) holds the original client request body. - -Before Nginx 0.7.56, it makes no sense to use this directive because [$request_body](http://nginx.org/en/docs/http/ngx_http_core_module.html#var_request_body) was first introduced in Nginx 0.7.58. - -This directive itself was first introduced in the echo module's [v0.14 release](#v014). - -[Back to TOC](#table-of-contents) - -echo_location_async -------------------- -**syntax:** *echo_location_async <location> [<url_args>]* - -**default:** *no* - -**context:** *location, location if* - -**phase:** *content* - -Issue GET subrequest to the location specified (first argument) with optional url arguments specified in the second argument. - -As of Nginx 0.8.20, the `location` argument does *not* support named location, due to a limitation in the `ngx_http_subrequest` function. The same is true for its brother, the [echo_location](#echo_location) directive. - -A very simple example is - -```nginx - - location /main { - echo_location_async /sub; - echo world; - } - location /sub { - echo hello; - } -``` - -Accessing `/main` gets - -```bash - - hello - world -``` - -Calling multiple locations in parallel is also possible: - -```nginx - - location /main { - echo_reset_timer; - echo_location_async /sub1; - echo_location_async /sub2; - echo "took $echo_timer_elapsed sec for total."; - } - location /sub1 { - echo_sleep 2; # sleeps 2 sec - echo hello; - } - location /sub2 { - echo_sleep 1; # sleeps 1 sec - echo world; - } -``` - -Accessing `/main` yields - -```bash - - $ time curl 'http://localhost/main' - hello - world - took 0.000 sec for total. - - real 0m2.006s - user 0m0.000s - sys 0m0.004s -``` - -You can see that the main handler `/main` does *not* wait the subrequests `/sub1` and `/sub2` to complete and quickly goes on, hence the "0.000 sec" timing result. The whole request, however takes approximately 2 sec in total to complete because `/sub1` and `/sub2` run in parallel (or "concurrently" to be more accurate). - -If you use [echo_blocking_sleep](#echo_blocking_sleep) in the previous example instead, then you'll get the same output, but with 3 sec total response time, because "blocking sleep" blocks the whole Nginx worker process. - -Locations can also take an optional querystring argument, for instance - -```nginx - - location /main { - echo_location_async /sub 'foo=Foo&bar=Bar'; - } - location /sub { - echo $arg_foo $arg_bar; - } -``` - -Accessing `/main` yields - -```bash - - $ curl 'http://localhost/main' - Foo Bar -``` - -Querystrings is *not* allowed to be concatenated onto the `location` argument with "?" directly, for example, `/sub?foo=Foo&bar=Bar` is an invalid location, and shouldn't be fed as the first argument to this directive. - -Technically speaking, this directive is an example that Nginx content handler issues one or more subrequests directly. AFAIK, the [fancyindex module](https://connectical.com/projects/ngx-fancyindex/wiki) also does such kind of things ;) - -Nginx named locations like `@foo` is *not* supported here. - -This directive is logically equivalent to the GET version of [echo_subrequest_async](#echo_subrequest_async). For example, - -```nginx - - echo_location_async /foo 'bar=Bar'; -``` - -is logically equivalent to - -```nginx - - echo_subrequest_async GET /foo -q 'bar=Bar'; -``` - -But calling this directive is slightly faster than calling [echo_subrequest_async](#echo_subrequest_async) using `GET` because we don't have to parse the HTTP method names like `GET` and options like `-q`. - -This directive is first introduced in [version 0.09](#v009) of this module and requires at least Nginx 0.7.46. - -[Back to TOC](#table-of-contents) - -echo_location -------------- -**syntax:** *echo_location <location> [<url_args>]* - -**default:** *no* - -**context:** *location, location if* - -**phase:** *content* - -Just like the [echo_location_async](#echo_location_async) directive, but `echo_location` issues subrequests *in series* rather than in parallel. That is, the content handler directives following this directive won't be executed until the subrequest issued by this directive completes. - -The final response body is almost always equivalent to the case when [echo_location_async](#echo_location_async) is used instead, only if timing variables is used in the outputs. - -Consider the following example: - -```nginx - - location /main { - echo_reset_timer; - echo_location /sub1; - echo_location /sub2; - echo "took $echo_timer_elapsed sec for total."; - } - location /sub1 { - echo_sleep 2; - echo hello; - } - location /sub2 { - echo_sleep 1; - echo world; - } -``` - -The location `/main` above will take for total 3 sec to complete (compared to 2 sec if [echo_location_async](#echo_location_async) is used instead here). Here's the result in action on my machine: - -```bash - - $ curl 'http://localhost/main' - hello - world - took 3.003 sec for total. - - real 0m3.027s - user 0m0.020s - sys 0m0.004s -``` - -This directive is logically equivalent to the GET version of [echo_subrequest](#echo_subrequest). For example, - -```nginx - - echo_location /foo 'bar=Bar'; -``` - -is logically equivalent to - -```nginx - - echo_subrequest GET /foo -q 'bar=Bar'; -``` - -But calling this directive is slightly faster than calling [echo_subrequest](#echo_subrequest) using `GET` because we don't have to parse the HTTP method names like `GET` and options like `-q`. - -Behind the scene, it creates an `ngx_http_post_subrequest_t` object as a *continuation* and passes it into the `ngx_http_subrequest` function call. Nginx will later reopen this "continuation" in the subrequest's `ngx_http_finalize_request` function call. We resumes the execution of the parent-request's content handler and starts to run the next directive (command) if any. - -Nginx named locations like `@foo` is *not* supported here. - -This directive was first introduced in the [release v0.12](#v012). - -See also [echo_location_async](#echo_location_async) for more details about the meaning of the arguments. - -[Back to TOC](#table-of-contents) - -echo_subrequest_async ---------------------- -**syntax:** *echo_subrequest_async <HTTP_method> <location> [-q <url_args>] [-b <request_body>] [-f <request_body_path>]* - -**default:** *no* - -**context:** *location, location if* - -**phase:** *content* - -Initiate an asynchronous subrequest using HTTP method, an optional url arguments (or querystring) and an optional request body which can be defined as a string or as a path to a file which contains the body. - -This directive is very much like a generalized version of the [echo_location_async](#echo_location_async) directive. - -Here's a small example demonstrating its usage: - -```nginx - - location /multi { - # body defined as string - echo_subrequest_async POST '/sub' -q 'foo=Foo' -b 'hi'; - # body defined as path to a file, relative to nginx prefix path if not absolute - echo_subrequest_async PUT '/sub' -q 'bar=Bar' -f '/tmp/hello.txt'; - } - location /sub { - echo "querystring: $query_string"; - echo "method: $echo_request_method"; - echo "body: $echo_request_body"; - echo "content length: $http_content_length"; - echo '///'; - } -``` - -Then on the client side: - -```bash - - $ echo -n hello > /tmp/hello.txt - $ curl 'http://localhost/multi' - querystring: foo=Foo - method: POST - body: hi - content length: 2 - /// - querystring: bar=Bar - method: PUT - body: hello - content length: 5 - /// -``` - -Here's more funny example using the standard [proxy module](#httpproxymodule) to handle the subrequest: - -```nginx - - location /main { - echo_subrequest_async POST /sub -b 'hello, world'; - } - location /sub { - proxy_pass $scheme://127.0.0.1:$server_port/proxied; - } - location /proxied { - echo "method: $echo_request_method."; - - # we need to read body explicitly here...or $echo_request_body - # will evaluate to empty ("") - echo_read_request_body; - - echo "body: $echo_request_body."; - } -``` - -Then on the client side, we can see that - -```bash - - $ curl 'http://localhost/main' - method: POST. - body: hello, world. -``` - -Nginx named locations like `@foo` is *not* supported here. - -This directive takes several options: - - - -q Specify the URL arguments (or URL querystring) for the subrequest. - - -f Specify the path for the file whose content will be serve as the - subrequest's request body. - - -b Specify the request body data - - -This directive was first introduced in the [release v0.15](#v015). - -The `-f` option to define a file path for the body was introduced in the [release v0.35](#v035). - -See also the [echo_subrequest](#echo_subrequest) and [echo_location_async](#echo_location_async) directives. - -[Back to TOC](#table-of-contents) - -echo_subrequest ---------------- -**syntax:** *echo_subrequest <HTTP_method> <location> [-q <url_args>] [-b <request_body>] [-f <request_body_path>]* - -**default:** *no* - -**context:** *location, location if* - -**phase:** *content* - -This is the synchronous version of the [echo_subrequest_async](#echo_subrequest_async) directive. And just like [echo_location](#echo_location), it does not block the Nginx worker process (while [echo_blocking_sleep](#echo_blocking_sleep) does), rather, it uses continuation to pass control along the subrequest chain. - -See [echo_subrequest_async](#echo_subrequest_async) for more details. - -Nginx named locations like `@foo` is *not* supported here. - -This directive was first introduced in the [release v0.15](#v015). - -[Back to TOC](#table-of-contents) - -echo_foreach_split ------------------- -**syntax:** *echo_foreach_split <delimiter> <string>* - -**default:** *no* - -**context:** *location, location if* - -**phase:** *content* - -Split the second argument `string` using the delimiter specified in the first argument, and then iterate through the resulting items. For instance: - -```nginx - - location /loop { - echo_foreach_split ',' $arg_list; - echo "item: $echo_it"; - echo_end; - } -``` - -Accessing /main yields - -```bash - - $ curl 'http://localhost/loop?list=cat,dog,mouse' - item: cat - item: dog - item: mouse -``` - -As seen in the previous example, this directive should always be accompanied by an [echo_end](#echo_end) directive. - -Parallel `echo_foreach_split` loops are allowed, but nested ones are currently forbidden. - -The `delimiter` argument could contain *multiple* arbitrary characters, like - -```nginx - - # this outputs "cat\ndog\nmouse\n" - echo_foreach_split -- '-a-' 'cat-a-dog-a-mouse'; - echo $echo_it; - echo_end; -``` - -Logically speaking, this looping structure is just the `foreach` loop combined with a `split` function call in Perl (using the previous example): - -```perl - - foreach (split ',', $arg_list) { - print "item $_\n"; - } -``` - -People will also find it useful in merging multiple `.js` or `.css` resources into a whole. Here's an example: - -```nginx - - location /merge { - default_type 'text/javascript'; - - echo_foreach_split '&' $query_string; - echo "/* JS File $echo_it */"; - echo_location_async $echo_it; - echo; - echo_end; - } -``` - -Then accessing /merge to merge the `.js` resources specified in the query string: - -```bash - - $ curl 'http://localhost/merge?/foo/bar.js&/yui/blah.js&/baz.js' -``` - -One can also use third-party Nginx cache module to cache the merged response generated by the `/merge` location in the previous example. - -This directive was first introduced in the [release v0.17](#v017). - -[Back to TOC](#table-of-contents) - -echo_end --------- -**syntax:** *echo_end* - -**default:** *no* - -**context:** *location, location if* - -**phase:** *content* - -This directive is used to terminate the body of looping and conditional control structures like [echo_foreach_split](#echo_foreach_split). - -This directive was first introduced in the [release v0.17](#v017). - -[Back to TOC](#table-of-contents) - -echo_request_body ------------------ -**syntax:** *echo_request_body* - -**default:** *no* - -**context:** *location, location if* - -**phase:** *content* - -Outputs the contents of the request body previous read. - -Behind the scene, it's implemented roughly like this: - -```C - - if (r->request_body && r->request_body->bufs) { - return ngx_http_output_filter(r, r->request_body->bufs); - } -``` - -Unlike the [$echo_request_body](#echo_request_body) and $request_body variables, this directive will show the whole request body even if some parts or all parts of it are saved in temporary files on the disk. - -It is a "no-op" if no request body has been read yet. - -This directive was first introduced in the [release v0.18](#v018). - -See also [echo_read_request_body](#echo_read_request_body) and the [chunkin module](http://github.com/agentzh/chunkin-nginx-module). - -[Back to TOC](#table-of-contents) - -echo_exec ---------- -**syntax:** *echo_exec <location> [<query_string>]* - -**syntax:** *echo_exec <named_location>* - -**default:** *no* - -**context:** *location, location if* - -**phase:** *content* - -Does an internal redirect to the location specified. An optional query string can be specified for normal locations, as in - -```nginx - - location /foo { - echo_exec /bar weight=5; - } - location /bar { - echo $arg_weight; - } -``` - -Or equivalently - -```nginx - - location /foo { - echo_exec /bar?weight=5; - } - location /bar { - echo $arg_weight; - } -``` - -Named locations are also supported. Here's an example: - -```nginx - - location /foo { - echo_exec @bar; - } - location @bar { - # you'll get /foo rather than @bar - # due to a potential bug in nginx. - echo $echo_request_uri; - } -``` - -But query string (if any) will always be ignored for named location redirects due to a limitation in the `ngx_http_named_location` function. - -Never try to echo things before the `echo_exec` directive or you won't see the proper response of the location you want to redirect to. Because any echoing will cause the original location handler to send HTTP headers before the redirection happens. - -Technically speaking, this directive exposes the Nginx internal API functions `ngx_http_internal_redirect` and `ngx_http_named_location`. - -This directive was first introduced in the [v0.21 release](#v021). - -[Back to TOC](#table-of-contents) - -echo_status ------------ -**syntax:** *echo_status <status-num>* - -**default:** *echo_status 200* - -**context:** *location, location if* - -**phase:** *content* - -Specify the default response status code. Default to `200`. This directive is declarative and the relative order with other echo-like directives is not important. - -Here is an example, - -```nginx - - location = /bad { - echo_status 404; - echo "Something is missing..."; - } -``` - -then we get a response like this: - - - HTTP/1.1 404 Not Found - Server: nginx/1.2.1 - Date: Sun, 24 Jun 2012 03:58:18 GMT - Content-Type: text/plain - Transfer-Encoding: chunked - Connection: keep-alive - - Something is missing... - - -This directive was first introduced in the `v0.40` release. - -[Back to TOC](#table-of-contents) - -Filter Directives -================= - -Use of the following directives trigger the filter registration of this module. By default, no filter will be registered by this module. - -Every filter directive supports variable interpolation in its arguments (if any). - -[Back to TOC](#table-of-contents) - -echo_before_body ----------------- -**syntax:** *echo_before_body \[options\] \[argument\]...* - -**default:** *no* - -**context:** *location, location if* - -**phase:** *output filter* - -It's the filter version of the [echo](#echo) directive, and prepends its output to the beginning of the original outputs generated by the underlying content handler. - -An example is - -```nginx - - location /echo { - echo_before_body hello; - proxy_pass $scheme://127.0.0.1:$server_port$request_uri/more; - } - location /echo/more { - echo world - } -``` - -Accessing `/echo` from the client side yields - -```bash - - hello - world -``` - -In the previous sample, we borrow the [standard proxy module](http://nginx.org/en/docs/http/ngx_http_proxy_module.html) to serve as the underlying content handler that generates the "main contents". - -Multiple instances of this filter directive are also allowed, as in: - -```nginx - - location /echo { - echo_before_body hello; - echo_before_body world; - echo !; - } -``` - -On the client side, the output is like - -```bash - - $ curl 'http://localhost/echo' - hello - world - ! -``` - -In this example, we also use the [content handler directives](#content-handler-directives) provided by this module as the underlying content handler. - -This directive also supports the `-n` and `--` options like the [echo](#echo) directive. - -This directive can be mixed with its brother directive [echo_after_body](#echo_after_body). - -[Back to TOC](#table-of-contents) - -echo_after_body ---------------- -**syntax:** *echo_after_body \[argument\]...* - -**default:** *no* - -**context:** *location, location if* - -**phase:** *output filter* - -It's very much like the [echo_before_body](#echo_before_body) directive, but *appends* its output to the end of the original outputs generated by the underlying content handler. - -Here's a simple example: - -```nginx - - location /echo { - echo_after_body hello; - proxy_pass http://127.0.0.1:$server_port$request_uri/more; - } - location /echo/more { - echo world - } -``` - -Accessing `/echo` from the client side yields - - - world - hello - - -Multiple instances are allowed, as in: - -```nginx - - location /echo { - echo_after_body hello; - echo_after_body world; - echo i; - echo say; - } -``` - -The output on the client side while accessing the `/echo` location looks like - - - i - say - hello - world - - -This directive also supports the `-n` and `--` options like the [echo](#echo) directive. - -This directive can be mixed with its brother directive [echo_before_body](#echo_before_body). - -[Back to TOC](#table-of-contents) - -Variables -========= - -[Back to TOC](#table-of-contents) - -$echo_it --------- - -This is a "topic variable" used by [echo_foreach_split](#echo_foreach_split), just like the `$_` variable in Perl. - -[Back to TOC](#table-of-contents) - -$echo_timer_elapsed -------------------- - -This variable holds the seconds elapsed since the start of the current request (might be a subrequest though) or the last invocation of the [echo_reset_timer](#echo_reset_timer) command. - -The timing result takes three digits after the decimal point. - -References of this variable will force the underlying Nginx timer to update to the current system time, regardless the timer resolution settings elsewhere in the config file, just like the [echo_reset_timer](#echo_reset_timer) directive. - -[Back to TOC](#table-of-contents) - -$echo_request_body ------------------- - -Evaluates to the current (sub)request's request body previously read if no part of the body has been saved to a temporary file. To always show the request body even if it's very large, use the [echo_request_body](#echo_request_body) directive. - -[Back to TOC](#table-of-contents) - -$echo_request_method --------------------- - -Evaluates to the HTTP request method of the current request (it can be a subrequest). - -Behind the scene, it just takes the string data stored in `r->method_name`. - -Compare it to the [$echo_client_request_method](#echo_client_request_method) variable. - -At least for Nginx 0.8.20 and older, the [$request_method](http://nginx.org/en/docs/http/ngx_http_core_module.html#var_request_method) variable provided by the [http core module](http://nginx.org/en/docs/http/ngx_http_core_module.html) is actually doing what our [$echo_client_request_method](#echo_client_request_method) is doing. - -This variable was first introduced in our [v0.15 release](#v015). - -[Back to TOC](#table-of-contents) - -$echo_client_request_method ---------------------------- - -Always evaluates to the main request's HTTP method even if the current request is a subrequest. - -Behind the scene, it just takes the string data stored in `r->main->method_name`. - -Compare it to the [$echo_request_method](#echo_request_method) variable. - -This variable was first introduced in our [v0.15 release](#v015). - -[Back to TOC](#table-of-contents) - -$echo_client_request_headers ----------------------------- - -Evaluates to the original client request's headers. - -Just as the name suggests, it will always take the main request (or the client request) even if it's currently executed in a subrequest. - -A simple example is below: - -```nginx - - location /echoback { - echo "headers are:" - echo $echo_client_request_headers; - } -``` - -Accessing `/echoback` yields - -```bash - - $ curl 'http://localhost/echoback' - headers are - GET /echoback HTTP/1.1 - User-Agent: curl/7.18.2 (i486-pc-linux-gnu) libcurl/7.18.2 OpenSSL/0.9.8g - Host: localhost:1984 - Accept: */* -``` - -Behind the scene, it recovers `r->main->header_in` (or the large header buffers, if any) on the C level and does not construct the headers itself by traversing parsed results in the request object. - -This varible is always evaluated to an empty value in HTTP/2 requests for now due to the current implementation. - -This variable was first introduced in [version 0.15](#v015). - -[Back to TOC](#table-of-contents) - -$echo_cacheable_request_uri ---------------------------- - -Evaluates to the parsed form of the URI (usually led by `/`) of the current (sub-)request. Unlike the [$echo_request_uri](#echo_request_uri) variable, it is cacheable. - -See [$echo_request_uri](#echo_request_uri) for more details. - -This variable was first introduced in [version 0.17](#v017). - -[Back to TOC](#table-of-contents) - -$echo_request_uri ------------------ - -Evaluates to the parsed form of the URI (usually led by `/`) of the current (sub-)request. Unlike the [$echo_cacheable_request_uri](#echo_cacheable_request_uri) variable, it is *not* cacheable. - -This is quite different from the [$request_uri](http://nginx.org/en/docs/http/ngx_http_core_module.html#var_request_uri) variable exported by the [ngx_http_core_module](http://nginx.org/en/docs/http/ngx_http_core_module.html), because `$request_uri` is the *unparsed* form of the current request's URI. - -This variable was first introduced in [version 0.17](#v017). - -[Back to TOC](#table-of-contents) - -$echo_incr ----------- - -It is a counter that always generate the current counting number, starting from 1. The counter is always associated with the main request even if it is accessed within a subrequest. - -Consider the following example - -```Nginx - - location /main { - echo "main pre: $echo_incr"; - echo_location_async /sub; - echo_location_async /sub; - echo "main post: $echo_incr"; - } - location /sub { - echo "sub: $echo_incr"; - } -``` - -Accessing `/main` yields - - main pre: 1 - sub: 3 - sub: 4 - main post: 2 - -This directive was first introduced in the [v0.18 release](#v018). - -[Back to TOC](#table-of-contents) - -$echo_response_status ---------------------- - -Evaluates to the status code of the current (sub)request, null if not any. - -Behind the scene, it's just the textual representation of `r->headers_out->status`. - -This directive was first introduced in the [v0.23 release](#v023). - -[Back to TOC](#table-of-contents) - -Installation -============ - -You're recommended to install this module (as well as the Nginx core and many other goodies) via the [OpenResty bundle](http://openresty.org). See [the detailed instructions](http://openresty.org/#Installation) for downloading and installing OpenResty into your system. This is the easiest and most safe way to set things up. - -Alternatively, you can install this module manually with the Nginx source: - -Grab the nginx source code from [nginx.org](http://nginx.org/), for example, -the version 1.11.2 (see [nginx compatibility](#compatibility)), and then build the source with this module: - -```bash - - $ wget 'http://nginx.org/download/nginx-1.11.2.tar.gz' - $ tar -xzvf nginx-1.11.2.tar.gz - $ cd nginx-1.11.2/ - - # Here we assume you would install you nginx under /opt/nginx/. - $ ./configure --prefix=/opt/nginx \ - --add-module=/path/to/echo-nginx-module - - $ make -j2 - $ make install -``` - -Download the latest version of the release tarball of this module from [echo-nginx-module file list](https://github.com/openresty/echo-nginx-module/tags). - -Starting from NGINX 1.9.11, you can also compile this module as a dynamic module, by using the `--add-dynamic-module=PATH` option instead of `--add-module=PATH` on the -`./configure` command line above. And then you can explicitly load the module in your `nginx.conf` via the [load_module](http://nginx.org/en/docs/ngx_core_module.html#load_module) -directive, for example, - -```nginx -load_module /path/to/modules/ngx_http_echo_module.so; -``` - -Also, this module is included and enabled by default in the [OpenResty bundle](http://openresty.org). - -[Back to TOC](#table-of-contents) - -Compatibility -============= - -The following versions of Nginx should work with this module: - -* **1.16.x** -* **1.15.x** (last tested: 1.15.8) -* **1.14.x** -* **1.13.x** (last tested: 1.13.6) -* **1.12.x** -* **1.11.x** (last tested: 1.11.2) -* **1.10.x** -* **1.9.x** (last tested: 1.9.15) -* **1.8.x** -* **1.7.x** (last tested: 1.7.10) -* **1.6.x** -* **1.5.x** (last tested: 1.5.12) -* **1.4.x** (last tested: 1.4.4) -* **1.3.x** (last tested: 1.3.7) -* **1.2.x** (last tested: 1.2.9) -* **1.1.x** (last tested: 1.1.5) -* **1.0.x** (last tested: 1.0.11) -* **0.9.x** (last tested: 0.9.4) -* **0.8.x** (last tested: 0.8.54) -* **0.7.x >= 0.7.21** (last tested: 0.7.68) - -In particular, - -* the directive [echo_location_async](#echo_location_async) and its brother [echo_subrequest_async](#echo_subrequest_async) do *not* work with **0.7.x < 0.7.46**. -* the [echo_after_body](#echo_after_body) directive does *not* work at all with nginx **< 0.8.7**. -* the [echo_sleep](#echo_sleep) directive cannot be used after [echo_location](#echo_location) or [echo_subrequest](#echo_subrequest) for nginx **< 0.8.11**. - -Earlier versions of Nginx like 0.6.x and 0.5.x will *not* work at all. - -If you find that any particular version of Nginx above 0.7.21 does not work with this module, please consider [reporting a bug](#report-bugs). - -[Back to TOC](#table-of-contents) - -Modules that use this module for testing -======================================== - -The following modules take advantage of this `echo` module in their test suite: - -* The [memc](http://github.com/openresty/memc-nginx-module) module that supports almost the whole memcached TCP protocol. -* The [chunkin](http://github.com/agentzh/chunkin-nginx-module) module that adds HTTP 1.1 chunked input support to Nginx. -* The [headers_more](http://github.com/openresty/headers-more-nginx-module) module that allows you to add, set, and clear input and output headers under the conditions that you specify. -* The `echo` module itself. - -Please mail me other modules that use `echo` in any form and I'll add them to the list above :) - -[Back to TOC](#table-of-contents) - -Community -========= - -[Back to TOC](#table-of-contents) - -English Mailing List --------------------- - -The [openresty-en](https://groups.google.com/group/openresty-en) mailing list is for English speakers. - -[Back to TOC](#table-of-contents) - -Chinese Mailing List --------------------- - -The [openresty](https://groups.google.com/group/openresty) mailing list is for Chinese speakers. - -[Back to TOC](#table-of-contents) - -Report Bugs -=========== - -Although a lot of effort has been put into testing and code tuning, there must be some serious bugs lurking somewhere in this module. So whenever you are bitten by any quirks, please don't hesitate to - -1. create a ticket on the [issue tracking interface](https://github.com/openresty/echo-nginx-module/issues) provided by GitHub, -1. or send a bug report, questions, or even patches to the [OpenResty Community](#community). - -[Back to TOC](#table-of-contents) - -Source Repository -================= - -Available on github at [openresty/echo-nginx-module](https://github.com/openresty/echo-nginx-module). - -[Back to TOC](#table-of-contents) - -Changes -======= - -The changes of every release of this module can be obtained from the OpenResty bundle's change logs: - - - -[Back to TOC](#table-of-contents) - -Test Suite -========== - -This module comes with a Perl-driven test suite. The [test cases](https://github.com/openresty/echo-nginx-module/tree/master/t/) are -[declarative](https://github.com/openresty/echo-nginx-module/blob/master/t/echo.t) too. Thanks to the [Test::Nginx](http://search.cpan.org/perldoc?Test::Nginx) module in the Perl world. - -To run it on your side: - -```bash - - $ PATH=/path/to/your/nginx-with-echo-module:$PATH prove -r t -``` - -You need to terminate any Nginx processes before running the test suite if you have changed the Nginx server binary. - -Because a single nginx server (by default, `localhost:1984`) is used across all the test scripts (`.t` files), it's meaningless to run the test suite in parallel by specifying `-jN` when invoking the `prove` utility. - -Some parts of the test suite requires standard modules [proxy](http://nginx.org/en/docs/http/ngx_http_proxy_module.html), [rewrite](http://nginx.org/en/docs/http/ngx_http_rewrite_module.html) and [SSI](http://nginx.org/en/docs/http/ngx_http_ssi_module.html) to be enabled as well when building Nginx. - -[Back to TOC](#table-of-contents) - -TODO -==== - -* Fix the [echo_after_body](#echo_after_body) directive in subrequests. -* Add directives *echo_read_client_request_body* and *echo_request_headers*. -* Add new directive *echo_log* to use Nginx's logging facility directly from the config file and specific loglevel can be specified, as in - -```nginx - - echo_log debug "I am being called."; -``` - -* Add support for options `-h` and `-t` to [echo_subrequest_async](#echo_subrequest_async) and [echo_subrequest](#echo_subrequest). For example - -```nginx - - echo_subrequest POST /sub -q 'foo=Foo&bar=Bar' -b 'hello' -t 'text/plan' -h 'X-My-Header: blah blah' -``` - -* Add options to control whether a subrequest should inherit cached variables from its parent request (i.e. the current request that is calling the subrequest in question). Currently none of the subrequests issued by this module inherit the cached variables from the parent request. -* Add new variable *$echo_active_subrequests* to show `r->main->count - 1`. -* Add the *echo_file* and *echo_cached_file* directives. -* Add new varaible *$echo_request_headers* to accompany the existing [$echo_client_request_headers](#echo_client_request_headers) variable. -* Add new directive *echo_foreach*, as in - -```nginx - - echo_foreach 'cat' 'dog' 'mouse'; - echo_location_async "/animals/$echo_it"; - echo_end; -``` - -* Add new directive *echo_foreach_range*, as in - -```nginx - - echo_foreach_range '[1..100]' '[a-zA-z0-9]'; - echo_location_async "/item/$echo_it"; - echo_end; -``` - -* Add new directive *echo_repeat*, as in - -```nginx - - echo_repeat 10 $i { - echo "Page $i"; - echo_location "/path/to/page/$i"; - } -``` - -This is just another way of saying - -```nginx - - echo_foreach_range $i [1..10]; - echo "Page $i"; - echo_location "/path/to/page/$i"; - echo_end; -``` - -Thanks Marcus Clyne for providing this idea. - -* Add new variable $echo_random which always returns a random non-negative integer with the lower/upper limit specified by the new directives `echo_random_min` and `echo_random_max`. For example, - -```nginx - - echo_random_min 10 - echo_random_max 200 - echo "random number: $echo_random"; -``` - -Thanks Marcus Clyne for providing this idea. - -[Back to TOC](#table-of-contents) - -Getting involved -================ - -You'll be very welcomed to submit patches to the [author](#author) or just ask for a commit bit to the [source repository](#source-repository) on GitHub. - -[Back to TOC](#table-of-contents) - -Author -====== - -Yichun "agentzh" Zhang (章亦春) *<agentzh@gmail.com>*, OpenResty Inc. - -This wiki page is also maintained by the author himself, and everybody is encouraged to improve this page as well. - -[Back to TOC](#table-of-contents) - -Copyright & License -=================== - -Copyright (c) 2009-2018, Yichun "agentzh" Zhang (章亦春) , OpenResty Inc. - -This module is licensed under the terms of the BSD license. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - -* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -[Back to TOC](#table-of-contents) - -See Also -======== - -* The original [blog post](http://agentzh.blogspot.com/2009/10/hacking-on-nginx-echo-module.html) about this module's initial development. -* The standard [addition filter module](http://nginx.org/en/docs/http/ngx_http_addition_module.html). -* The standard [proxy module](http://nginx.org/en/docs/http/ngx_http_proxy_module.html). -* The [OpenResty](http://openresty.org) bundle. - -[Back to TOC](#table-of-contents) - diff --git a/debian/modules/http-echo/config b/debian/modules/http-echo/config deleted file mode 100644 index 4bf0f00..0000000 --- a/debian/modules/http-echo/config +++ /dev/null @@ -1,63 +0,0 @@ -ngx_addon_name=ngx_http_echo_module - -ECHO_SRCS=" \ - $ngx_addon_dir/src/ngx_http_echo_module.c \ - $ngx_addon_dir/src/ngx_http_echo_util.c \ - $ngx_addon_dir/src/ngx_http_echo_timer.c \ - $ngx_addon_dir/src/ngx_http_echo_var.c \ - $ngx_addon_dir/src/ngx_http_echo_handler.c \ - $ngx_addon_dir/src/ngx_http_echo_filter.c \ - $ngx_addon_dir/src/ngx_http_echo_sleep.c \ - $ngx_addon_dir/src/ngx_http_echo_location.c \ - $ngx_addon_dir/src/ngx_http_echo_echo.c \ - $ngx_addon_dir/src/ngx_http_echo_request_info.c \ - $ngx_addon_dir/src/ngx_http_echo_subrequest.c \ - $ngx_addon_dir/src/ngx_http_echo_foreach.c \ - " - -ECHO_DEPS=" \ - $ngx_addon_dir/src/ddebug.h \ - $ngx_addon_dir/src/ngx_http_echo_module.h \ - $ngx_addon_dir/src/ngx_http_echo_handler.h \ - $ngx_addon_dir/src/ngx_http_echo_util.h \ - $ngx_addon_dir/src/ngx_http_echo_sleep.h \ - $ngx_addon_dir/src/ngx_http_echo_filter.h \ - $ngx_addon_dir/src/ngx_http_echo_var.h \ - $ngx_addon_dir/src/ngx_http_echo_location.h \ - $ngx_addon_dir/src/ngx_http_echo_echo.h \ - $ngx_addon_dir/src/ngx_http_echo_request_info.h \ - $ngx_addon_dir/src/ngx_http_echo_subrequest.h \ - $ngx_addon_dir/src/ngx_http_echo_foreach.h \ - " - -# nginx 1.17.0+ unconditionally enables the postpone filter -if [ ! -z "$HTTP_POSTPONE" ]; then - # nginx won't have HTTP_POSTPONE_FILTER_MODULE & HTTP_POSTPONE_FILTER_SRCS - # defined since 1.9.11 - if [ -z "$HTTP_POSTPONE_FILTER_MODULE" ]; then - HTTP_POSTPONE_FILTER_MODULE=ngx_http_postpone_filter_module - HTTP_POSTPONE_FILTER_SRCS=src/http/ngx_http_postpone_filter_module.c - fi - - # This module depends upon the postpone filter being activated - if [ "$HTTP_POSTPONE" != YES ]; then - HTTP_FILTER_MODULES="$HTTP_FILTER_MODULES $HTTP_POSTPONE_FILTER_MODULE" - HTTP_SRCS="$HTTP_SRCS $HTTP_POSTPONE_FILTER_SRCS" - HTTP_POSTPONE=YES - fi -fi - -if [ -n "$ngx_module_link" ]; then - ngx_module_type=HTTP_AUX_FILTER - ngx_module_name=$ngx_addon_name - ngx_module_incs= - ngx_module_deps="$ECHO_DEPS" - ngx_module_srcs="$ECHO_SRCS" - ngx_module_libs= - - . auto/module -else - HTTP_AUX_FILTER_MODULES="$HTTP_AUX_FILTER_MODULES $ngx_addon_name" - NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ECHO_SRCS" - NGX_ADDON_DEPS="$NGX_ADDON_DEPS $ECHO_DEPS" -fi diff --git a/debian/modules/http-echo/src/ddebug.h b/debian/modules/http-echo/src/ddebug.h deleted file mode 100644 index a92d7a7..0000000 --- a/debian/modules/http-echo/src/ddebug.h +++ /dev/null @@ -1,114 +0,0 @@ -#ifndef DDEBUG_H -#define DDEBUG_H - -#include -#include -#include - -#if defined(DDEBUG) && (DDEBUG) - -# if (NGX_HAVE_VARIADIC_MACROS) - -# define dd(...) fprintf(stderr, "echo *** %s: ", __func__); \ - fprintf(stderr, __VA_ARGS__); \ - fprintf(stderr, " at %s line %d.\n", __FILE__, __LINE__) - -# else - -#include -#include - -#include - -static ngx_inline void -dd(const char * fmt, ...) { -} - -# endif - -# if DDEBUG > 1 - -# define dd_enter() dd_enter_helper(r, __func__) - -static ngx_inline void -dd_enter_helper(ngx_http_request_t *r, const char *func) { - ngx_http_posted_request_t *pr; - - fprintf(stderr, ">enter %s %.*s %.*s?%.*s c:%d m:%p r:%p ar:%p pr:%p", - func, - (int) r->method_name.len, r->method_name.data, - (int) r->uri.len, r->uri.data, - (int) r->args.len, r->args.data, - 0/*(int) r->main->count*/, r->main, - r, r->connection->data, r->parent); - - if (r->posted_requests) { - fprintf(stderr, " posted:"); - - for (pr = r->posted_requests; pr; pr = pr->next) { - fprintf(stderr, "%p,", pr); - } - } - - fprintf(stderr, "\n"); -} - -# else - -# define dd_enter() - -# endif - -#else - -# if (NGX_HAVE_VARIADIC_MACROS) - -# define dd(...) - -# define dd_enter() - -# else - -#include - -static ngx_inline void -dd(const char * fmt, ...) { -} - -static ngx_inline void -dd_enter() { -} - -# endif - -#endif - -#if defined(DDEBUG) && (DDEBUG) - -#define dd_check_read_event_handler(r) \ - dd("r->read_event_handler = %s", \ - r->read_event_handler == ngx_http_block_reading ? \ - "ngx_http_block_reading" : \ - r->read_event_handler == ngx_http_test_reading ? \ - "ngx_http_test_reading" : \ - r->read_event_handler == ngx_http_request_empty_handler ? \ - "ngx_http_request_empty_handler" : "UNKNOWN") - -#define dd_check_write_event_handler(r) \ - dd("r->write_event_handler = %s", \ - r->write_event_handler == ngx_http_handler ? \ - "ngx_http_handler" : \ - r->write_event_handler == ngx_http_core_run_phases ? \ - "ngx_http_core_run_phases" : \ - r->write_event_handler == ngx_http_request_empty_handler ? \ - "ngx_http_request_empty_handler" : "UNKNOWN") - -#else - -#define dd_check_read_event_handler(r) -#define dd_check_write_event_handler(r) - -#endif - -#endif /* DDEBUG_H */ - diff --git a/debian/modules/http-echo/src/ngx_http_echo_echo.c b/debian/modules/http-echo/src/ngx_http_echo_echo.c deleted file mode 100644 index f5789f5..0000000 --- a/debian/modules/http-echo/src/ngx_http_echo_echo.c +++ /dev/null @@ -1,342 +0,0 @@ -#ifndef DDEBUG -#define DDEBUG 0 -#endif -#include "ddebug.h" - -#include "ngx_http_echo_echo.h" -#include "ngx_http_echo_util.h" -#include "ngx_http_echo_filter.h" - -#include - -static ngx_buf_t ngx_http_echo_space_buf; - -static ngx_buf_t ngx_http_echo_newline_buf; - - -ngx_int_t -ngx_http_echo_echo_init(ngx_conf_t *cf) -{ - static u_char space_str[] = " "; - static u_char newline_str[] = "\n"; - - dd("global init..."); - - ngx_memzero(&ngx_http_echo_space_buf, sizeof(ngx_buf_t)); - - ngx_http_echo_space_buf.memory = 1; - - ngx_http_echo_space_buf.start = - ngx_http_echo_space_buf.pos = - space_str; - - ngx_http_echo_space_buf.end = - ngx_http_echo_space_buf.last = - space_str + sizeof(space_str) - 1; - - ngx_memzero(&ngx_http_echo_newline_buf, sizeof(ngx_buf_t)); - - ngx_http_echo_newline_buf.memory = 1; - - ngx_http_echo_newline_buf.start = - ngx_http_echo_newline_buf.pos = - newline_str; - - ngx_http_echo_newline_buf.end = - ngx_http_echo_newline_buf.last = - newline_str + sizeof(newline_str) - 1; - - return NGX_OK; -} - - -ngx_int_t -ngx_http_echo_exec_echo_sync(ngx_http_request_t *r, - ngx_http_echo_ctx_t *ctx) -{ - ngx_buf_t *buf; - ngx_chain_t *cl = NULL; /* the head of the chain link */ - - buf = ngx_calloc_buf(r->pool); - if (buf == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - buf->sync = 1; - - cl = ngx_alloc_chain_link(r->pool); - if (cl == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - cl->buf = buf; - cl->next = NULL; - - return ngx_http_echo_send_chain_link(r, ctx, cl); -} - - -ngx_int_t -ngx_http_echo_exec_echo(ngx_http_request_t *r, - ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args, - ngx_flag_t in_filter, ngx_array_t *opts) -{ - ngx_uint_t i; - - ngx_buf_t *space_buf; - ngx_buf_t *newline_buf; - ngx_buf_t *buf; - - ngx_str_t *computed_arg; - ngx_str_t *computed_arg_elts; - ngx_str_t *opt; - - ngx_chain_t *cl = NULL; /* the head of the chain link */ - ngx_chain_t **ll = &cl; /* always point to the address of the last link */ - - dd_enter(); - - if (computed_args == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - computed_arg_elts = computed_args->elts; - for (i = 0; i < computed_args->nelts; i++) { - computed_arg = &computed_arg_elts[i]; - - if (computed_arg->len == 0) { - buf = NULL; - - } else { - buf = ngx_calloc_buf(r->pool); - if (buf == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - buf->start = buf->pos = computed_arg->data; - buf->last = buf->end = computed_arg->data + - computed_arg->len; - - buf->memory = 1; - } - - if (cl == NULL) { - cl = ngx_alloc_chain_link(r->pool); - if (cl == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - cl->buf = buf; - cl->next = NULL; - ll = &cl->next; - - } else { - /* append a space first */ - *ll = ngx_alloc_chain_link(r->pool); - - if (*ll == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - space_buf = ngx_calloc_buf(r->pool); - - if (space_buf == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - /* nginx clears buf flags at the end of each request handling, - * so we have to make a clone here. */ - *space_buf = ngx_http_echo_space_buf; - - (*ll)->buf = space_buf; - (*ll)->next = NULL; - - ll = &(*ll)->next; - - /* then append the buf only if it's non-empty */ - if (buf) { - *ll = ngx_alloc_chain_link(r->pool); - if (*ll == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - (*ll)->buf = buf; - (*ll)->next = NULL; - - ll = &(*ll)->next; - } - } - } /* end for */ - - if (cl && cl->buf == NULL) { - cl = cl->next; - } - - if (opts && opts->nelts > 0) { - opt = opts->elts; - /* FIXME handle other unrecognized options here */ - if (opt[0].len == 1 && opt[0].data[0] == 'n') { - goto done; - } - } - - /* append the newline character */ - - newline_buf = ngx_calloc_buf(r->pool); - - if (newline_buf == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - *newline_buf = ngx_http_echo_newline_buf; - - if (cl == NULL) { - cl = ngx_alloc_chain_link(r->pool); - - if (cl == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - cl->buf = newline_buf; - cl->next = NULL; - /* ll = &cl->next; */ - - } else { - *ll = ngx_alloc_chain_link(r->pool); - - if (*ll == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - (*ll)->buf = newline_buf; - (*ll)->next = NULL; - /* ll = &(*ll)->next; */ - } - -done: - - if (cl == NULL || cl->buf == NULL) { - return NGX_OK; - } - - if (in_filter) { - return ngx_http_echo_next_body_filter(r, cl); - } - - return ngx_http_echo_send_chain_link(r, ctx, cl); -} - - -ngx_int_t -ngx_http_echo_exec_echo_flush(ngx_http_request_t *r, ngx_http_echo_ctx_t *ctx) -{ - return ngx_http_send_special(r, NGX_HTTP_FLUSH); -} - - -ngx_int_t -ngx_http_echo_exec_echo_request_body(ngx_http_request_t *r, - ngx_http_echo_ctx_t *ctx) -{ - ngx_buf_t *b; - ngx_chain_t *out, *cl, **ll; - - if (r->request_body == NULL || r->request_body->bufs == NULL) { - return NGX_OK; - } - - out = NULL; - ll = &out; - - for (cl = r->request_body->bufs; cl; cl = cl->next) { - if (ngx_buf_special(cl->buf)) { - /* we do not want to create zero-size bufs */ - continue; - } - - *ll = ngx_alloc_chain_link(r->pool); - if (*ll == NULL) { - return NGX_ERROR; - } - - b = ngx_alloc_buf(r->pool); - if (b == NULL) { - return NGX_ERROR; - } - - (*ll)->buf = b; - (*ll)->next = NULL; - - ngx_memcpy(b, cl->buf, sizeof(ngx_buf_t)); - b->tag = (ngx_buf_tag_t) &ngx_http_echo_exec_echo_request_body; - b->last_buf = 0; - b->last_in_chain = 0; - - ll = &(*ll)->next; - } - - if (out == NULL) { - return NGX_OK; - } - - return ngx_http_echo_send_chain_link(r, ctx, out); -} - - -ngx_int_t -ngx_http_echo_exec_echo_duplicate(ngx_http_request_t *r, - ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args) -{ - ngx_str_t *computed_arg; - ngx_str_t *computed_arg_elts; - ssize_t i, count; - ngx_str_t *str; - u_char *p; - ngx_int_t rc; - ngx_buf_t *buf; - ngx_chain_t *cl; - - dd_enter(); - - computed_arg_elts = computed_args->elts; - - computed_arg = &computed_arg_elts[0]; - - count = ngx_http_echo_atosz(computed_arg->data, computed_arg->len); - - if (count == NGX_ERROR) { - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "invalid size specified: \"%V\"", computed_arg); - - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - str = &computed_arg_elts[1]; - - if (count == 0 || str->len == 0) { - rc = ngx_http_echo_send_header_if_needed(r, ctx); - if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { - return rc; - } - - return NGX_OK; - } - - buf = ngx_create_temp_buf(r->pool, count * str->len); - if (buf == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - p = buf->pos; - for (i = 0; i < count; i++) { - p = ngx_copy(p, str->data, str->len); - } - buf->last = p; - - cl = ngx_alloc_chain_link(r->pool); - if (cl == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - cl->next = NULL; - cl->buf = buf; - - return ngx_http_echo_send_chain_link(r, ctx, cl); -} diff --git a/debian/modules/http-echo/src/ngx_http_echo_echo.h b/debian/modules/http-echo/src/ngx_http_echo_echo.h deleted file mode 100644 index 896f1ed..0000000 --- a/debian/modules/http-echo/src/ngx_http_echo_echo.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef ECHO_ECHO_H -#define ECHO_ECHO_H - -#include "ngx_http_echo_module.h" - -ngx_int_t ngx_http_echo_echo_init(ngx_conf_t *cf); - -ngx_int_t ngx_http_echo_exec_echo_sync(ngx_http_request_t *r, - ngx_http_echo_ctx_t *ctx); - -ngx_int_t ngx_http_echo_exec_echo(ngx_http_request_t *r, - ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args, - ngx_flag_t in_filter, ngx_array_t *opts); - -ngx_int_t ngx_http_echo_exec_echo_request_body(ngx_http_request_t *r, - ngx_http_echo_ctx_t *ctx); - -ngx_int_t ngx_http_echo_exec_echo_flush(ngx_http_request_t *r, - ngx_http_echo_ctx_t *ctx); - -ngx_int_t ngx_http_echo_exec_echo_duplicate(ngx_http_request_t *r, - ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args); - -#endif /* ECHO_ECHO_H */ - diff --git a/debian/modules/http-echo/src/ngx_http_echo_filter.c b/debian/modules/http-echo/src/ngx_http_echo_filter.c deleted file mode 100644 index 689b52e..0000000 --- a/debian/modules/http-echo/src/ngx_http_echo_filter.c +++ /dev/null @@ -1,282 +0,0 @@ -#ifndef DDEBUG -#define DDEBUG 0 -#endif -#include "ddebug.h" - -#include "ngx_http_echo_filter.h" -#include "ngx_http_echo_util.h" -#include "ngx_http_echo_echo.h" - -#include - - - -ngx_http_output_header_filter_pt ngx_http_echo_next_header_filter; - -ngx_http_output_body_filter_pt ngx_http_echo_next_body_filter; - -static ngx_int_t ngx_http_echo_header_filter(ngx_http_request_t *r); - -static ngx_int_t ngx_http_echo_body_filter(ngx_http_request_t *r, - ngx_chain_t *in); - -/* filter handlers */ -static ngx_int_t ngx_http_echo_exec_filter_cmds(ngx_http_request_t *r, - ngx_http_echo_ctx_t *ctx, ngx_array_t *cmds, ngx_uint_t *iterator); - - -static volatile ngx_cycle_t *ngx_http_echo_prev_cycle = NULL; - - -ngx_int_t -ngx_http_echo_filter_init(ngx_conf_t *cf) -{ - int multi_http_blocks; - ngx_http_echo_main_conf_t *emcf; - - emcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_echo_module); - - if (ngx_http_echo_prev_cycle != ngx_cycle) { - ngx_http_echo_prev_cycle = ngx_cycle; - multi_http_blocks = 0; - - } else { - multi_http_blocks = 1; - } - - if (multi_http_blocks || emcf->requires_filter) { - dd("top header filter: %ld", - (unsigned long) ngx_http_top_header_filter); - - ngx_http_echo_next_header_filter = ngx_http_top_header_filter; - ngx_http_top_header_filter = ngx_http_echo_header_filter; - - dd("top body filter: %ld", (unsigned long) ngx_http_top_body_filter); - - ngx_http_echo_next_body_filter = ngx_http_top_body_filter; - ngx_http_top_body_filter = ngx_http_echo_body_filter; - } - - return NGX_OK; -} - - -static ngx_int_t -ngx_http_echo_header_filter(ngx_http_request_t *r) -{ - ngx_http_echo_loc_conf_t *conf; - ngx_http_echo_ctx_t *ctx; - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "echo header filter, uri \"%V?%V\"", &r->uri, &r->args); - - ctx = ngx_http_get_module_ctx(r, ngx_http_echo_module); - - /* XXX we should add option to insert contents for responses - * of non-200 status code here... */ - /* - if (r->headers_out.status != NGX_HTTP_OK) { - if (ctx != NULL) { - ctx->skip_filter = 1; - } - return ngx_http_echo_next_header_filter(r); - } - */ - - conf = ngx_http_get_module_loc_conf(r, ngx_http_echo_module); - if (conf->before_body_cmds == NULL && conf->after_body_cmds == NULL) { - if (ctx != NULL) { - ctx->skip_filter = 1; - } - return ngx_http_echo_next_header_filter(r); - } - - if (ctx == NULL) { - ctx = ngx_http_echo_create_ctx(r); - if (ctx == NULL) { - return NGX_ERROR; - } - - ngx_http_set_ctx(r, ctx, ngx_http_echo_module); - } - - /* enable streaming here (use chunked encoding) */ - ngx_http_clear_content_length(r); - ngx_http_clear_accept_ranges(r); - - return ngx_http_echo_next_header_filter(r); -} - - -static ngx_int_t -ngx_http_echo_body_filter(ngx_http_request_t *r, ngx_chain_t *in) -{ - ngx_http_echo_ctx_t *ctx; - ngx_int_t rc; - ngx_http_echo_loc_conf_t *conf; - unsigned last; - ngx_chain_t *cl; - ngx_buf_t *b; - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "echo body filter, uri \"%V?%V\"", &r->uri, &r->args); - - if (in == NULL || r->header_only) { - return ngx_http_echo_next_body_filter(r, in); - } - - ctx = ngx_http_get_module_ctx(r, ngx_http_echo_module); - - if (ctx == NULL || ctx->skip_filter) { - return ngx_http_echo_next_body_filter(r, in); - } - - conf = ngx_http_get_module_loc_conf(r, ngx_http_echo_module); - - if (!ctx->before_body_sent) { - ctx->before_body_sent = 1; - - if (conf->before_body_cmds != NULL) { - rc = ngx_http_echo_exec_filter_cmds(r, ctx, conf->before_body_cmds, - &ctx->next_before_body_cmd); - if (rc != NGX_OK) { - return NGX_ERROR; - } - } - } - - if (conf->after_body_cmds == NULL) { - ctx->skip_filter = 1; - return ngx_http_echo_next_body_filter(r, in); - } - - last = 0; - - for (cl = in; cl; cl = cl->next) { - dd("cl %p, special %d", cl, ngx_buf_special(cl->buf)); - - if (cl->buf->last_buf || cl->buf->last_in_chain) { - cl->buf->last_buf = 0; - cl->buf->last_in_chain = 0; - cl->buf->sync = 1; - last = 1; - } - } - - dd("in %p, last %d", in, (int) last); - - if (in) { - rc = ngx_http_echo_next_body_filter(r, in); - -#if 0 - if (rc == NGX_AGAIN) { - return NGX_ERROR; - } -#endif - - dd("next filter returns %d, last %d", (int) rc, (int) last); - - if (rc == NGX_ERROR || rc > NGX_OK || !last) { - return rc; - } - } - - dd("exec filter cmds for after body cmds"); - - rc = ngx_http_echo_exec_filter_cmds(r, ctx, conf->after_body_cmds, - &ctx->next_after_body_cmd); - if (rc == NGX_ERROR || rc > NGX_OK) { - dd("FAILED: exec filter cmds for after body cmds"); - return NGX_ERROR; - } - - ctx->skip_filter = 1; - - dd("after body cmds executed...terminating..."); - - /* XXX we can NOT use - * ngx_http_send_special(r, NGX_HTTP_LAST) here - * because we should bypass the upstream filters. */ - - b = ngx_calloc_buf(r->pool); - if (b == NULL) { - return NGX_ERROR; - } - - if (r == r->main && !r->post_action) { - b->last_buf = 1; - - } else { - b->sync = 1; - b->last_in_chain = 1; - } - - cl = ngx_alloc_chain_link(r->pool); - if (cl == NULL) { - return NGX_ERROR; - } - - cl->next = NULL; - cl->buf = b; - - return ngx_http_echo_next_body_filter(r, cl); -} - - -static ngx_int_t -ngx_http_echo_exec_filter_cmds(ngx_http_request_t *r, - ngx_http_echo_ctx_t *ctx, ngx_array_t *cmds, ngx_uint_t *iterator) -{ - ngx_int_t rc; - ngx_array_t *opts = NULL; - ngx_array_t *computed_args = NULL; - ngx_http_echo_cmd_t *cmd; - ngx_http_echo_cmd_t *cmd_elts; - - for (cmd_elts = cmds->elts; *iterator < cmds->nelts; (*iterator)++) { - cmd = &cmd_elts[*iterator]; - - /* evaluate arguments for the current cmd (if any) */ - if (cmd->args) { - computed_args = ngx_array_create(r->pool, cmd->args->nelts, - sizeof(ngx_str_t)); - if (computed_args == NULL) { - return NGX_ERROR; - } - - opts = ngx_array_create(r->pool, 1, sizeof(ngx_str_t)); - if (opts == NULL) { - return NGX_ERROR; - } - - rc = ngx_http_echo_eval_cmd_args(r, cmd, computed_args, opts); - - if (rc != NGX_OK) { - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "Failed to evaluate arguments for " - "the directive."); - return rc; - } - } - - /* do command dispatch based on the opcode */ - switch (cmd->opcode) { - case echo_opcode_echo_before_body: - case echo_opcode_echo_after_body: - dd("exec echo_before_body or echo_after_body..."); - - rc = ngx_http_echo_exec_echo(r, ctx, computed_args, - 1 /* in filter */, opts); - - if (rc == NGX_ERROR || rc > NGX_OK) { - return rc; - } - - break; - default: - break; - } - } - - return NGX_OK; -} diff --git a/debian/modules/http-echo/src/ngx_http_echo_filter.h b/debian/modules/http-echo/src/ngx_http_echo_filter.h deleted file mode 100644 index ea5115d..0000000 --- a/debian/modules/http-echo/src/ngx_http_echo_filter.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef ECHO_FILTER_H -#define ECHO_FILTER_H - -#include "ngx_http_echo_module.h" - - -extern ngx_http_output_header_filter_pt ngx_http_echo_next_header_filter; - -extern ngx_http_output_body_filter_pt ngx_http_echo_next_body_filter; - - -ngx_int_t ngx_http_echo_filter_init (ngx_conf_t *cf); - -#endif /* ECHO_FILTER_H */ - diff --git a/debian/modules/http-echo/src/ngx_http_echo_foreach.c b/debian/modules/http-echo/src/ngx_http_echo_foreach.c deleted file mode 100644 index a4a2b54..0000000 --- a/debian/modules/http-echo/src/ngx_http_echo_foreach.c +++ /dev/null @@ -1,183 +0,0 @@ -#ifndef DDEBUG -#define DDEBUG 0 -#endif -#include "ddebug.h" - -#include "ngx_http_echo_foreach.h" -#include "ngx_http_echo_util.h" - -#include - - -ngx_int_t -ngx_http_echo_it_variable(ngx_http_request_t *r, - ngx_http_variable_value_t *v, uintptr_t data) -{ - ngx_http_echo_ctx_t *ctx; - ngx_uint_t i; - ngx_array_t *choices; - ngx_str_t *choice_elts, *choice; - - ctx = ngx_http_get_module_ctx(r, ngx_http_echo_module); - - if (ctx && ctx->foreach != NULL) { - - choices = ctx->foreach->choices; - i = ctx->foreach->next_choice; - - if (i < choices->nelts) { - choice_elts = choices->elts; - choice = &choice_elts[i]; - - v->len = choice->len; - v->data = choice->data; - v->valid = 1; - v->no_cacheable = 1; - v->not_found = 0; - - return NGX_OK; - } - } - - v->not_found = 1; - - return NGX_OK; -} - - -ngx_int_t -ngx_http_echo_exec_echo_foreach_split(ngx_http_request_t *r, - ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args) -{ - ngx_http_echo_loc_conf_t *elcf; - ngx_str_t *delimiter, *compound; - u_char *pos, *last, *end; - ngx_str_t *choice; - ngx_str_t *computed_arg_elts; - ngx_array_t *cmds; - ngx_http_echo_cmd_t *cmd; - ngx_http_echo_cmd_t *cmd_elts; - - if (ctx->foreach != NULL) { - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "Nested echo_foreach not supported yet."); - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - if (computed_args->nelts < 2) { - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "echo_foreach should take at least two arguments. " - "(if your delimiter starts with \"-\", preceding it " - "with a \"--\".)"); - - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - computed_arg_elts = computed_args->elts; - - compound = &computed_arg_elts[1]; - - dd("HEY coumpound len: %u", (int) compound->len); - - ctx->foreach = ngx_palloc(r->pool, sizeof(ngx_http_echo_foreach_ctx_t)); - - if (ctx->foreach == NULL) { - return NGX_ERROR; - } - - ctx->foreach->cmd_index = ctx->next_handler_cmd; - - ctx->foreach->next_choice = 0; - - ctx->foreach->choices = ngx_array_create(r->pool, 10, sizeof(ngx_str_t)); - if (ctx->foreach->choices == NULL) { - return NGX_ERROR; - } - - delimiter = &computed_arg_elts[0]; - - pos = compound->data; - end = compound->data + compound->len; - - while ((last = ngx_http_echo_strlstrn(pos, end, delimiter->data, - delimiter->len - 1)) != NULL) - { - dd("entered the loop"); - - if (last == pos) { - dd("!!! len == 0"); - pos = last + delimiter->len; - continue; - } - - choice = ngx_array_push(ctx->foreach->choices); - if (choice == NULL) { - return NGX_ERROR; - } - - choice->data = pos; - choice->len = last - pos; - pos = last + delimiter->len; - } - - if (pos < end) { - choice = ngx_array_push(ctx->foreach->choices); - if (choice == NULL) { - return NGX_ERROR; - } - - choice->data = pos; - choice->len = end - pos; - } - - if (ctx->foreach->choices->nelts == 0) { - /* skip the foreach body entirely */ - elcf = ngx_http_get_module_loc_conf(r, ngx_http_echo_module); - cmds = elcf->handler_cmds; - cmd_elts = cmds->elts; - for (/* void */; ctx->next_handler_cmd < cmds->nelts; - ctx->next_handler_cmd++) - { - cmd = &cmd_elts[ctx->next_handler_cmd + 1]; - if (cmd->opcode == echo_opcode_echo_end) { - return NGX_OK; - } - } - - } - - return NGX_OK; -} - - -ngx_int_t -ngx_http_echo_exec_echo_end(ngx_http_request_t *r, - ngx_http_echo_ctx_t *ctx) -{ - if (ctx->foreach == NULL) { - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "Found a echo_end that has no corresponding echo_foreach " - "before it."); - return NGX_ERROR; - } - - ctx->foreach->next_choice++; - - if (ctx->foreach->next_choice >= ctx->foreach->choices->nelts) { - /* TODO We need to explicitly free the foreach ctx from - * the pool */ - ctx->foreach = NULL; - - return NGX_OK; - } - - dd("echo_end: ++ next_choice (total: %u): %u", - (unsigned) ctx->foreach->choices->nelts, - (unsigned) ctx->foreach->next_choice); - - /* the main handler dispatcher loop will increment - * ctx->next_handler_cmd for us anyway. */ - ctx->next_handler_cmd = ctx->foreach->cmd_index; - - return NGX_OK; -} diff --git a/debian/modules/http-echo/src/ngx_http_echo_foreach.h b/debian/modules/http-echo/src/ngx_http_echo_foreach.h deleted file mode 100644 index 49592f4..0000000 --- a/debian/modules/http-echo/src/ngx_http_echo_foreach.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef ECHO_FOREACH_H -#define ECHO_FOREACH_H - -#include "ngx_http_echo_module.h" - -ngx_int_t ngx_http_echo_exec_echo_foreach_split(ngx_http_request_t *r, - ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args); - -ngx_int_t ngx_http_echo_exec_echo_end(ngx_http_request_t *r, - ngx_http_echo_ctx_t *ctx); - -ngx_int_t ngx_http_echo_it_variable(ngx_http_request_t *r, - ngx_http_variable_value_t *v, uintptr_t data); - -#endif /* ECHO_FOREACH_H */ - diff --git a/debian/modules/http-echo/src/ngx_http_echo_handler.c b/debian/modules/http-echo/src/ngx_http_echo_handler.c deleted file mode 100644 index 00933a4..0000000 --- a/debian/modules/http-echo/src/ngx_http_echo_handler.c +++ /dev/null @@ -1,429 +0,0 @@ - -/* - * Copyright (C) Yichun Zhang (agentzh) - */ - - -#ifndef DDEBUG -#define DDEBUG 0 -#endif -#include "ddebug.h" - - -#include "ngx_http_echo_filter.h" -#include "ngx_http_echo_handler.h" -#include "ngx_http_echo_echo.h" -#include "ngx_http_echo_util.h" -#include "ngx_http_echo_sleep.h" -#include "ngx_http_echo_var.h" -#include "ngx_http_echo_timer.h" -#include "ngx_http_echo_location.h" -#include "ngx_http_echo_subrequest.h" -#include "ngx_http_echo_request_info.h" -#include "ngx_http_echo_foreach.h" - -#include -#include - - -void -ngx_http_echo_wev_handler(ngx_http_request_t *r) -{ - ngx_int_t rc; - ngx_http_echo_ctx_t *ctx; - - dd("wev handler"); - - ctx = ngx_http_get_module_ctx(r, ngx_http_echo_module); - - if (ctx == NULL) { - ngx_http_finalize_request(r, NGX_ERROR); - return; - } - - dd("waiting: %d, done: %d", (int) ctx->waiting, (int) ctx->done); - - if (ctx->waiting && ! ctx->done) { - - if (r == r->connection->data && r->postponed) { - - if (r->postponed->request) { - r->connection->data = r->postponed->request; - -#if defined(nginx_version) && nginx_version >= 8012 - ngx_http_post_request(r->postponed->request, NULL); -#else - ngx_http_post_request(r->postponed->request); -#endif - - } else { - ngx_http_echo_flush_postponed_outputs(r); - } - } - - return; - } - - ctx->done = 0; - - ctx->next_handler_cmd++; - - rc = ngx_http_echo_run_cmds(r); - - dd("rc: %d", (int) rc); - - if (rc == NGX_ERROR || rc == NGX_DONE) { - ngx_http_finalize_request(r, rc); - return; - } - - if (rc == NGX_AGAIN) { - dd("mark busy %d for %.*s", (int) ctx->next_handler_cmd, - (int) r->uri.len, - r->uri.data); - - ctx->waiting = 1; - ctx->done = 0; - - } else { - dd("mark ready %d", (int) ctx->next_handler_cmd); - ctx->waiting = 0; - ctx->done = 1; - - dd("finalizing with rc %d", (int) rc); - - dd("finalize request %.*s with %d", (int) r->uri.len, r->uri.data, - (int) rc); - - ngx_http_finalize_request(r, rc); - } -} - - -ngx_int_t -ngx_http_echo_handler(ngx_http_request_t *r) -{ - ngx_int_t rc; - ngx_http_echo_ctx_t *ctx; - - dd("subrequest in memory: %d", (int) r->subrequest_in_memory); - - rc = ngx_http_echo_run_cmds(r); - - dd("run cmds returned %d", (int) rc); - - if (rc == NGX_ERROR - || rc == NGX_OK - || rc == NGX_DONE - || rc == NGX_DECLINED) - { - return rc; - } - - ctx = ngx_http_get_module_ctx(r, ngx_http_echo_module); - - if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { - if (ctx && r->header_sent) { - return NGX_ERROR; - } - - return rc; - } - - /* rc == NGX_AGAIN */ - -#if defined(nginx_version) && nginx_version >= 8011 - r->main->count++; -#endif - - dd("%d", r->connection->destroyed); - dd("%d", r->done); - - if (ctx) { - dd("mark busy %d for %.*s", (int) ctx->next_handler_cmd, - (int) r->uri.len, - r->uri.data); - - ctx->waiting = 1; - ctx->done = 0; - } - - return NGX_DONE; -} - - -ngx_int_t -ngx_http_echo_run_cmds(ngx_http_request_t *r) -{ - ngx_http_echo_loc_conf_t *elcf; - ngx_http_echo_ctx_t *ctx; - ngx_int_t rc; - ngx_array_t *cmds; - ngx_array_t *computed_args = NULL; - ngx_http_echo_cmd_t *cmd; - ngx_http_echo_cmd_t *cmd_elts; - ngx_array_t *opts = NULL; - - elcf = ngx_http_get_module_loc_conf(r, ngx_http_echo_module); - cmds = elcf->handler_cmds; - if (cmds == NULL) { - return NGX_DECLINED; - } - - ctx = ngx_http_get_module_ctx(r, ngx_http_echo_module); - if (ctx == NULL) { - ctx = ngx_http_echo_create_ctx(r); - if (ctx == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - ngx_http_set_ctx(r, ctx, ngx_http_echo_module); - } - - dd("exec handler: %.*s: %i", (int) r->uri.len, r->uri.data, - (int) ctx->next_handler_cmd); - - cmd_elts = cmds->elts; - - for (; ctx->next_handler_cmd < cmds->nelts; ctx->next_handler_cmd++) { - - cmd = &cmd_elts[ctx->next_handler_cmd]; - - /* evaluate arguments for the current cmd (if any) */ - if (cmd->args) { - computed_args = ngx_array_create(r->pool, cmd->args->nelts, - sizeof(ngx_str_t)); - - if (computed_args == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - opts = ngx_array_create(r->pool, 1, sizeof(ngx_str_t)); - - if (opts == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - rc = ngx_http_echo_eval_cmd_args(r, cmd, computed_args, opts); - if (rc != NGX_OK) { - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "Failed to evaluate arguments for " - "the directive."); - return rc; - } - } - - /* do command dispatch based on the opcode */ - - switch (cmd->opcode) { - - case echo_opcode_echo_sync: - rc = ngx_http_echo_exec_echo_sync(r, ctx); - break; - - case echo_opcode_echo: - /* XXX moved the following code to a separate - * function */ - dd("found echo opcode"); - rc = ngx_http_echo_exec_echo(r, ctx, computed_args, - 0 /* in filter */, opts); - break; - - case echo_opcode_echo_request_body: - rc = ngx_http_echo_exec_echo_request_body(r, ctx); - break; - - case echo_opcode_echo_location_async: - if (!r->request_body) { - /* we require reading the request body before doing - * subrequests */ - - ctx->next_handler_cmd--; /* re-run the current cmd */ - goto read_request_body; - } - - dd("found opcode echo location async..."); - rc = ngx_http_echo_exec_echo_location_async(r, ctx, - computed_args); - break; - - case echo_opcode_echo_location: - if (!r->request_body) { - /* we require reading the request body before doing - * subrequests */ - - ctx->next_handler_cmd--; /* re-run the current cmd */ - goto read_request_body; - } - - return ngx_http_echo_exec_echo_location(r, ctx, computed_args); - - case echo_opcode_echo_subrequest_async: - if (!r->request_body) { - /* we require reading the request body before doing - * subrequests */ - - ctx->next_handler_cmd--; /* re-run the current cmd */ - goto read_request_body; - } - - dd("found opcode echo subrequest async..."); - rc = ngx_http_echo_exec_echo_subrequest_async(r, ctx, - computed_args); - break; - - case echo_opcode_echo_subrequest: - if (!r->request_body) { - /* we require reading the request body before doing - * subrequests */ - - ctx->next_handler_cmd--; /* re-run the current cmd */ - goto read_request_body; - } - - return ngx_http_echo_exec_echo_subrequest(r, ctx, computed_args); - - case echo_opcode_echo_sleep: - return ngx_http_echo_exec_echo_sleep(r, ctx, computed_args); - - case echo_opcode_echo_flush: - rc = ngx_http_echo_exec_echo_flush(r, ctx); - break; - - case echo_opcode_echo_blocking_sleep: - rc = ngx_http_echo_exec_echo_blocking_sleep(r, ctx, - computed_args); - break; - - case echo_opcode_echo_reset_timer: - rc = ngx_http_echo_exec_echo_reset_timer(r, ctx); - break; - - case echo_opcode_echo_duplicate: - rc = ngx_http_echo_exec_echo_duplicate(r, ctx, computed_args); - break; - - case echo_opcode_echo_read_request_body: - -read_request_body: - - ctx->wait_read_request_body = 0; - - rc = ngx_http_echo_exec_echo_read_request_body(r, ctx); - - if (rc == NGX_ERROR) { - return NGX_ERROR; - } - - if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { -#if (nginx_version >= 8011 && nginx_version < 1002006) \ - || (nginx_version >= 1003000 && nginx_version < 1003009) - r->main->count--; -#endif - return rc; - } - -#if nginx_version >= 8011 - r->main->count--; -#endif - dd("read request body: %d", (int) rc); - - if (rc == NGX_OK) { - continue; - } - - /* rc == NGX_AGAIN */ - ctx->wait_read_request_body = 1; - return NGX_AGAIN; - - case echo_opcode_echo_foreach_split: - rc = ngx_http_echo_exec_echo_foreach_split(r, ctx, computed_args); - break; - - case echo_opcode_echo_end: - rc = ngx_http_echo_exec_echo_end(r, ctx); - break; - - case echo_opcode_echo_exec: - dd("echo_exec"); - return ngx_http_echo_exec_exec(r, ctx, computed_args); - - default: - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "unknown opcode: %d", cmd->opcode); - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { - return rc; - } - } - - rc = ngx_http_echo_send_chain_link(r, ctx, NULL /* indicate LAST */); - - if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { - return rc; - } - - if (!r->request_body) { - if (ngx_http_discard_request_body(r) != NGX_OK) { - return NGX_ERROR; - } - } - - return NGX_OK; -} - - -ngx_int_t -ngx_http_echo_post_subrequest(ngx_http_request_t *r, - void *data, ngx_int_t rc) -{ - ngx_http_echo_ctx_t *ctx = data; - ngx_http_request_t *pr; - ngx_http_echo_ctx_t *pr_ctx; - - dd("echo post_subrequest: %.*s", (int) r->uri.len, r->uri.data); - - if (ctx->run_post_subrequest) { - dd("already run post_subrequest: %p: %.*s", ctx, - (int) r->uri.len, r->uri.data); - - return rc; - } - - dd("setting run_post_subrequest to 1 for %p for %.*s", ctx, - (int) r->uri.len, r->uri.data); - - ctx->run_post_subrequest = 1; - - pr = r->parent; - - pr_ctx = ngx_http_get_module_ctx(pr, ngx_http_echo_module); - if (pr_ctx == NULL) { - return NGX_ERROR; - } - - dd("mark ready %d", (int) pr_ctx->next_handler_cmd); - - pr_ctx->waiting = 0; - pr_ctx->done = 1; - - pr->write_event_handler = ngx_http_echo_wev_handler; - - /* work-around issues in nginx's event module */ - - if (r != r->connection->data - && r->postponed - && (r->main->posted_requests == NULL - || r->main->posted_requests->request != pr)) - { -#if defined(nginx_version) && nginx_version >= 8012 - ngx_http_post_request(pr, NULL); -#else - ngx_http_post_request(pr); -#endif - } - - return rc; -} diff --git a/debian/modules/http-echo/src/ngx_http_echo_handler.h b/debian/modules/http-echo/src/ngx_http_echo_handler.h deleted file mode 100644 index afc0666..0000000 --- a/debian/modules/http-echo/src/ngx_http_echo_handler.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef ECHO_HANDLER_H -#define ECHO_HANDLER_H - -#include "ngx_http_echo_module.h" - - -void ngx_http_echo_wev_handler(ngx_http_request_t *r); - -ngx_int_t ngx_http_echo_handler(ngx_http_request_t *r); - -ngx_int_t ngx_http_echo_run_cmds(ngx_http_request_t *r); - -ngx_int_t ngx_http_echo_post_subrequest(ngx_http_request_t *r, - void *data, ngx_int_t rc); - - -#endif /* ECHO_HANDLER_H */ - diff --git a/debian/modules/http-echo/src/ngx_http_echo_location.c b/debian/modules/http-echo/src/ngx_http_echo_location.c deleted file mode 100644 index bfabb5e..0000000 --- a/debian/modules/http-echo/src/ngx_http_echo_location.c +++ /dev/null @@ -1,178 +0,0 @@ -#ifndef DDEBUG -#define DDEBUG 0 -#endif -#include "ddebug.h" - -#include "ngx_http_echo_util.h" -#include "ngx_http_echo_location.h" -#include "ngx_http_echo_handler.h" - -#include - - -static ngx_int_t ngx_http_echo_adjust_subrequest(ngx_http_request_t *sr); - - -ngx_int_t -ngx_http_echo_exec_echo_location_async(ngx_http_request_t *r, - ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args) -{ - ngx_int_t rc; - ngx_http_request_t *sr; /* subrequest object */ - ngx_str_t *computed_arg_elts; - ngx_str_t location; - ngx_str_t *url_args; - ngx_str_t args; - ngx_uint_t flags = 0; - - dd_enter(); - - computed_arg_elts = computed_args->elts; - - location = computed_arg_elts[0]; - - if (location.len == 0) { - return NGX_ERROR; - } - - if (computed_args->nelts > 1) { - url_args = &computed_arg_elts[1]; - } else { - url_args = NULL; - } - - args.data = NULL; - args.len = 0; - - if (ngx_http_parse_unsafe_uri(r, &location, &args, &flags) != NGX_OK) { - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "echo_location_async sees unsafe uri: \"%V\"", - &location); - return NGX_ERROR; - } - - if (args.len > 0 && url_args == NULL) { - url_args = &args; - } - - rc = ngx_http_echo_send_header_if_needed(r, ctx); - if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { - return rc; - } - - rc = ngx_http_subrequest(r, &location, url_args, &sr, NULL, 0); - - if (rc != NGX_OK) { - return NGX_ERROR; - } - - rc = ngx_http_echo_adjust_subrequest(sr); - if (rc != NGX_OK) { - return NGX_ERROR; - } - - return NGX_OK; -} - - -ngx_int_t -ngx_http_echo_exec_echo_location(ngx_http_request_t *r, - ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args) -{ - ngx_int_t rc; - ngx_http_request_t *sr; /* subrequest object */ - ngx_str_t *computed_arg_elts; - ngx_str_t location; - ngx_str_t *url_args; - ngx_http_post_subrequest_t *psr; - ngx_str_t args; - ngx_uint_t flags = 0; - ngx_http_echo_ctx_t *sr_ctx; - - computed_arg_elts = computed_args->elts; - - location = computed_arg_elts[0]; - - if (location.len == 0) { - return NGX_ERROR; - } - - if (computed_args->nelts > 1) { - url_args = &computed_arg_elts[1]; - - } else { - url_args = NULL; - } - - args.data = NULL; - args.len = 0; - - if (ngx_http_parse_unsafe_uri(r, &location, &args, &flags) != NGX_OK) { - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "echo_location sees unsafe uri: \"%V\"", - &location); - return NGX_ERROR; - } - - if (args.len > 0 && url_args == NULL) { - url_args = &args; - } - - rc = ngx_http_echo_send_header_if_needed(r, ctx); - if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { - return rc; - } - - sr_ctx = ngx_http_echo_create_ctx(r); - - psr = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t)); - if (psr == NULL) { - return NGX_ERROR; - } - - psr->handler = ngx_http_echo_post_subrequest; - psr->data = sr_ctx; - - rc = ngx_http_subrequest(r, &location, url_args, &sr, psr, 0); - - if (rc != NGX_OK) { - return NGX_ERROR; - } - - rc = ngx_http_echo_adjust_subrequest(sr); - - if (rc != NGX_OK) { - return NGX_ERROR; - } - - return NGX_AGAIN; -} - - -static ngx_int_t -ngx_http_echo_adjust_subrequest(ngx_http_request_t *sr) -{ - ngx_http_core_main_conf_t *cmcf; - ngx_http_request_t *r; - - /* we do not inherit the parent request's variables */ - cmcf = ngx_http_get_module_main_conf(sr, ngx_http_core_module); - - r = sr->parent; - - sr->header_in = r->header_in; - - /* XXX work-around a bug in ngx_http_subrequest */ - if (r->headers_in.headers.last == &r->headers_in.headers.part) { - sr->headers_in.headers.last = &sr->headers_in.headers.part; - } - - sr->variables = ngx_pcalloc(sr->pool, cmcf->variables.nelts - * sizeof(ngx_http_variable_value_t)); - - if (sr->variables == NULL) { - return NGX_ERROR; - } - - return NGX_OK; -} diff --git a/debian/modules/http-echo/src/ngx_http_echo_location.h b/debian/modules/http-echo/src/ngx_http_echo_location.h deleted file mode 100644 index 6bc0e03..0000000 --- a/debian/modules/http-echo/src/ngx_http_echo_location.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef ECHO_LOCATION_H -#define ECHO_LOCATION_H - -#include "ngx_http_echo_module.h" - -ngx_int_t ngx_http_echo_exec_echo_location_async(ngx_http_request_t *r, - ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args); - -ngx_int_t ngx_http_echo_exec_echo_location(ngx_http_request_t *r, - ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args); - -#endif /* ECHO_LOCATION_H */ - diff --git a/debian/modules/http-echo/src/ngx_http_echo_module.c b/debian/modules/http-echo/src/ngx_http_echo_module.c deleted file mode 100644 index 8d736d7..0000000 --- a/debian/modules/http-echo/src/ngx_http_echo_module.c +++ /dev/null @@ -1,682 +0,0 @@ - -/* - * Copyright (C) Yichun Zhang (agentzh) - */ - - -#ifndef DDEBUG -#define DDEBUG 0 -#endif -#include "ddebug.h" - - -#include "ngx_http_echo_handler.h" -#include "ngx_http_echo_filter.h" -#include "ngx_http_echo_echo.h" -#include "ngx_http_echo_request_info.h" -#include "ngx_http_echo_var.h" -#include "ngx_http_echo_util.h" - - -#include -#include -#include - - -/* config init handler */ -static void *ngx_http_echo_create_loc_conf(ngx_conf_t *cf); -static char *ngx_http_echo_merge_loc_conf(ngx_conf_t *cf, void *parent, - void *child); -static void *ngx_http_echo_create_main_conf(ngx_conf_t *cf); -static ngx_int_t ngx_http_echo_post_config(ngx_conf_t *cf); - -/* config directive handlers */ -static char *ngx_http_echo_echo(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf); -static char *ngx_http_echo_echo_request_body(ngx_conf_t *cf, - ngx_command_t *cmd, void *conf); -static char *ngx_http_echo_echo_sleep(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf); -static char *ngx_http_echo_echo_flush(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf); -static char *ngx_http_echo_echo_blocking_sleep(ngx_conf_t *cf, - ngx_command_t *cmd, void *conf); -static char *ngx_http_echo_echo_reset_timer(ngx_conf_t *cf, - ngx_command_t *cmd, void *conf); -static char *ngx_http_echo_echo_before_body(ngx_conf_t *cf, - ngx_command_t *cmd, void *conf); -static char *ngx_http_echo_echo_after_body(ngx_conf_t *cf, - ngx_command_t *cmd, void *conf); -static char *ngx_http_echo_echo_location_async(ngx_conf_t *cf, - ngx_command_t *cmd, void *conf); -static char *ngx_http_echo_echo_location(ngx_conf_t *cf, - ngx_command_t *cmd, void *conf); -static char *ngx_http_echo_echo_subrequest_async(ngx_conf_t *cf, - ngx_command_t *cmd, void *conf); -static char *ngx_http_echo_echo_subrequest(ngx_conf_t *cf, - ngx_command_t *cmd, void *conf); -static char *ngx_http_echo_echo_duplicate(ngx_conf_t *cf, - ngx_command_t *cmd, void *conf); -static char *ngx_http_echo_echo_read_request_body(ngx_conf_t *cf, - ngx_command_t *cmd, void *conf); -static char *ngx_http_echo_echo_foreach_split(ngx_conf_t *cf, - ngx_command_t *cmd, void *conf); -static char *ngx_http_echo_echo_end(ngx_conf_t *cf, - ngx_command_t *cmd, void *conf); -static char *ngx_http_echo_echo_abort_parent(ngx_conf_t *cf, - ngx_command_t *cmd, void *conf); -static char *ngx_http_echo_echo_exec(ngx_conf_t *cf, - ngx_command_t *cmd, void *conf); -static char *ngx_http_echo_helper(ngx_http_echo_opcode_t opcode, - ngx_http_echo_cmd_category_t cat, - ngx_conf_t *cf, ngx_command_t *cmd, void *conf); - - -static ngx_http_module_t ngx_http_echo_module_ctx = { - NULL, /* preconfiguration */ - ngx_http_echo_post_config, /* postconfiguration */ - - ngx_http_echo_create_main_conf, /* create main configuration */ - NULL, /* init main configuration */ - - NULL, /* create server configuration */ - NULL, /* merge server configuration */ - - ngx_http_echo_create_loc_conf, /* create location configuration */ - ngx_http_echo_merge_loc_conf /* merge location configuration */ -}; - - -static ngx_command_t ngx_http_echo_commands[] = { - - { ngx_string("echo"), - NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_ANY, - ngx_http_echo_echo, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_echo_loc_conf_t, handler_cmds), - NULL }, - - { ngx_string("echo_request_body"), - NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_NOARGS, - ngx_http_echo_echo_request_body, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_echo_loc_conf_t, handler_cmds), - NULL }, - - { ngx_string("echo_sleep"), - NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1, - ngx_http_echo_echo_sleep, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_echo_loc_conf_t, handler_cmds), - NULL }, - - { ngx_string("echo_flush"), - NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_NOARGS, - ngx_http_echo_echo_flush, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_echo_loc_conf_t, handler_cmds), - NULL }, - - { ngx_string("echo_blocking_sleep"), - NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1, - ngx_http_echo_echo_blocking_sleep, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_echo_loc_conf_t, handler_cmds), - NULL }, - - { ngx_string("echo_reset_timer"), - NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_NOARGS, - ngx_http_echo_echo_reset_timer, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_echo_loc_conf_t, handler_cmds), - NULL }, - - { ngx_string("echo_before_body"), - NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_ANY, - ngx_http_echo_echo_before_body, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_echo_loc_conf_t, before_body_cmds), - NULL }, - - { ngx_string("echo_after_body"), - NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_ANY, - ngx_http_echo_echo_after_body, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_echo_loc_conf_t, after_body_cmds), - NULL }, - - { ngx_string("echo_location_async"), - NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE12, - ngx_http_echo_echo_location_async, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_echo_loc_conf_t, handler_cmds), - NULL }, - - { ngx_string("echo_location"), - NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE12, - ngx_http_echo_echo_location, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_echo_loc_conf_t, handler_cmds), - NULL }, - - { ngx_string("echo_subrequest_async"), - NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_2MORE, - ngx_http_echo_echo_subrequest_async, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_echo_loc_conf_t, handler_cmds), - NULL }, - - { ngx_string("echo_subrequest"), - NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_2MORE, - ngx_http_echo_echo_subrequest, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_echo_loc_conf_t, handler_cmds), - NULL }, - - { ngx_string("echo_duplicate"), - NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_2MORE, - ngx_http_echo_echo_duplicate, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_echo_loc_conf_t, handler_cmds), - NULL }, - - { ngx_string("echo_read_request_body"), - NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_NOARGS, - ngx_http_echo_echo_read_request_body, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_echo_loc_conf_t, handler_cmds), - NULL }, - - { ngx_string("echo_foreach_split"), - NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_2MORE, - ngx_http_echo_echo_foreach_split, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_echo_loc_conf_t, handler_cmds), - NULL }, - - { ngx_string("echo_end"), - NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_NOARGS, - ngx_http_echo_echo_end, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_echo_loc_conf_t, handler_cmds), - NULL }, - - { ngx_string("echo_abort_parent"), - NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_NOARGS, - ngx_http_echo_echo_abort_parent, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_echo_loc_conf_t, handler_cmds), - NULL }, - - { ngx_string("echo_exec"), - NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE12, - ngx_http_echo_echo_exec, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_echo_loc_conf_t, handler_cmds), - NULL }, - - { ngx_string("echo_status"), - NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1, - ngx_conf_set_num_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_echo_loc_conf_t, status), - NULL }, - - ngx_null_command -}; - - -ngx_module_t ngx_http_echo_module = { - NGX_MODULE_V1, - &ngx_http_echo_module_ctx, /* module context */ - ngx_http_echo_commands, /* module directives */ - NGX_HTTP_MODULE, /* module type */ - NULL, /* init master */ - NULL, /* init module */ - NULL, /* init process */ - NULL, /* init thread */ - NULL, /* exit thread */ - NULL, /* exit process */ - NULL, /* exit master */ - NGX_MODULE_V1_PADDING -}; - - -static void * -ngx_http_echo_create_loc_conf(ngx_conf_t *cf) -{ - ngx_http_echo_loc_conf_t *conf; - - conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_echo_loc_conf_t)); - if (conf == NULL) { - return NULL; - } - - /* set by ngx_pcalloc - * conf->handler_cmds = NULL - * conf->before_body_cmds = NULL - * conf->after_body_cmds = NULL - * conf->seen_leading_output = 0 - * conf->seen_trailing_output = 0 - */ - - conf->status = NGX_CONF_UNSET; - - return conf; -} - - -static char * -ngx_http_echo_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) -{ - ngx_http_echo_loc_conf_t *prev = parent; - ngx_http_echo_loc_conf_t *conf = child; - - if (conf->handler_cmds == NULL) { - conf->handler_cmds = prev->handler_cmds; - conf->seen_leading_output = prev->seen_leading_output; - } - - if (conf->before_body_cmds == NULL) { - conf->before_body_cmds = prev->before_body_cmds; - } - - if (conf->after_body_cmds == NULL) { - conf->after_body_cmds = prev->after_body_cmds; - } - - ngx_conf_merge_value(conf->status, prev->status, 200); - - return NGX_CONF_OK; -} - - -static char * -ngx_http_echo_helper(ngx_http_echo_opcode_t opcode, - ngx_http_echo_cmd_category_t cat, - ngx_conf_t *cf, ngx_command_t *cmd, void *conf) -{ - ngx_str_t *raw_args; - ngx_uint_t i, n; - ngx_array_t **args_ptr; - ngx_array_t **cmds_ptr; - ngx_http_echo_cmd_t *echo_cmd; - ngx_http_core_loc_conf_t *clcf; - ngx_http_script_compile_t sc; - ngx_http_echo_main_conf_t *emcf; - ngx_http_echo_arg_template_t *arg; - - emcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_echo_module); - - /* cmds_ptr points to ngx_http_echo_loc_conf_t's - * handler_cmds, before_body_cmds, or after_body_cmds - * array, depending on the actual offset */ - cmds_ptr = (ngx_array_t **) (((u_char *) conf) + cmd->offset); - - if (*cmds_ptr == NULL) { - *cmds_ptr = ngx_array_create(cf->pool, 1, - sizeof(ngx_http_echo_cmd_t)); - - if (*cmds_ptr == NULL) { - return NGX_CONF_ERROR; - } - - if (cat == echo_handler_cmd) { - dd("registering the content handler"); - /* register the content handler */ - clcf = ngx_http_conf_get_module_loc_conf(cf, - ngx_http_core_module); - - dd("registering the content handler (2)"); - clcf->handler = ngx_http_echo_handler; - - } else { - dd("filter used = 1"); - emcf->requires_filter = 1; - } - } - - echo_cmd = ngx_array_push(*cmds_ptr); - - if (echo_cmd == NULL) { - return NGX_CONF_ERROR; - } - - echo_cmd->opcode = opcode; - - args_ptr = &echo_cmd->args; - *args_ptr = ngx_array_create(cf->pool, 1, - sizeof(ngx_http_echo_arg_template_t)); - - if (*args_ptr == NULL) { - return NGX_CONF_ERROR; - } - - raw_args = cf->args->elts; - - /* we skip the first arg and start from the second */ - - for (i = 1 ; i < cf->args->nelts; i++) { - arg = ngx_array_push(*args_ptr); - - if (arg == NULL) { - return NGX_CONF_ERROR; - } - - arg->raw_value = raw_args[i]; - - dd("found raw arg %s", raw_args[i].data); - - arg->lengths = NULL; - arg->values = NULL; - - n = ngx_http_script_variables_count(&arg->raw_value); - - if (n > 0) { - ngx_memzero(&sc, sizeof(ngx_http_script_compile_t)); - - sc.cf = cf; - sc.source = &arg->raw_value; - sc.lengths = &arg->lengths; - sc.values = &arg->values; - sc.variables = n; - sc.complete_lengths = 1; - sc.complete_values = 1; - - if (ngx_http_script_compile(&sc) != NGX_OK) { - return NGX_CONF_ERROR; - } - } - } /* end for */ - - return NGX_CONF_OK; -} - - -static char * -ngx_http_echo_echo(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) -{ - ngx_http_echo_loc_conf_t *elcf = conf; - - if (!elcf->seen_leading_output) { - elcf->seen_leading_output = 1; - } - - dd("in echo_echo..."); - return ngx_http_echo_helper(echo_opcode_echo, echo_handler_cmd, - cf, cmd, conf); -} - - -static char * -ngx_http_echo_echo_request_body(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf) -{ - ngx_http_echo_loc_conf_t *elcf = conf; - - if (!elcf->seen_leading_output) { - elcf->seen_leading_output = 1; - } - - dd("in echo_echo_request_body..."); - return ngx_http_echo_helper(echo_opcode_echo_request_body, echo_handler_cmd, - cf, cmd, conf); -} - - -static char * -ngx_http_echo_echo_sleep(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) -{ - dd("in echo_sleep..."); - return ngx_http_echo_helper(echo_opcode_echo_sleep, echo_handler_cmd, - cf, cmd, conf); -} - - -static char * -ngx_http_echo_echo_flush(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) -{ - ngx_http_echo_loc_conf_t *elcf = conf; - - if (!elcf->seen_leading_output) { - elcf->seen_leading_output = 1; - } - - dd("in echo_flush..."); - return ngx_http_echo_helper(echo_opcode_echo_flush, echo_handler_cmd, - cf, cmd, conf); -} - - -static char * -ngx_http_echo_echo_blocking_sleep(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf) -{ - dd("in echo_blocking_sleep..."); - return ngx_http_echo_helper(echo_opcode_echo_blocking_sleep, - echo_handler_cmd, cf, cmd, conf); -} - - -static char * -ngx_http_echo_echo_reset_timer(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) -{ - return ngx_http_echo_helper(echo_opcode_echo_reset_timer, echo_handler_cmd, - cf, cmd, conf); -} - - -static char * -ngx_http_echo_echo_before_body(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) -{ - dd("processing echo_before_body directive..."); - return ngx_http_echo_helper(echo_opcode_echo_before_body, echo_filter_cmd, - cf, cmd, conf); -} - - -static char * -ngx_http_echo_echo_after_body(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) -{ - return ngx_http_echo_helper(echo_opcode_echo_after_body, echo_filter_cmd, - cf, cmd, conf); -} - - -static char * -ngx_http_echo_echo_location_async(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf) -{ - ngx_http_echo_loc_conf_t *elcf = conf; - char *ret; - - if (!elcf->seen_leading_output) { - elcf->seen_leading_output = 1; - - ret = ngx_http_echo_helper(echo_opcode_echo_sync, echo_handler_cmd, - cf, cmd, conf); - - if (ret != NGX_CONF_OK) { - return ret; - } - } - - return ngx_http_echo_helper(echo_opcode_echo_location_async, - echo_handler_cmd, cf, cmd, conf); -} - - -static char * -ngx_http_echo_echo_location(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) -{ - ngx_http_echo_loc_conf_t *elcf = conf; - char *ret; - - if (!elcf->seen_leading_output) { - elcf->seen_leading_output = 1; - - ret = ngx_http_echo_helper(echo_opcode_echo_sync, echo_handler_cmd, - cf, cmd, conf); - - if (ret != NGX_CONF_OK) { - return ret; - } - } - - return ngx_http_echo_helper(echo_opcode_echo_location, echo_handler_cmd, - cf, cmd, conf); -} - - -static char * -ngx_http_echo_echo_subrequest_async(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf) -{ - char *ret; - ngx_http_echo_loc_conf_t *elcf = conf; - - if (!elcf->seen_leading_output) { - elcf->seen_leading_output = 1; - - ret = ngx_http_echo_helper(echo_opcode_echo_sync, echo_handler_cmd, - cf, cmd, conf); - - if (ret != NGX_CONF_OK) { - return ret; - } - } - - return ngx_http_echo_helper(echo_opcode_echo_subrequest_async, - echo_handler_cmd, cf, cmd, conf); -} - - -static char * -ngx_http_echo_echo_subrequest(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf) -{ - ngx_http_echo_loc_conf_t *elcf = conf; - char *ret; - - if (!elcf->seen_leading_output) { - elcf->seen_leading_output = 1; - - ret = ngx_http_echo_helper(echo_opcode_echo_sync, echo_handler_cmd, - cf, cmd, conf); - - if (ret != NGX_CONF_OK) { - return ret; - } - } - - return ngx_http_echo_helper(echo_opcode_echo_subrequest, echo_handler_cmd, - cf, cmd, conf); -} - - -static char * -ngx_http_echo_echo_duplicate(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) -{ - ngx_http_echo_loc_conf_t *elcf = conf; - - if (!elcf->seen_leading_output) { - elcf->seen_leading_output = 1; - } - - return ngx_http_echo_helper(echo_opcode_echo_duplicate, echo_handler_cmd, - cf, cmd, conf); -} - - -static char * -ngx_http_echo_echo_read_request_body(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf) -{ - return ngx_http_echo_helper(echo_opcode_echo_read_request_body, - echo_handler_cmd, cf, cmd, conf); -} - - -static char * -ngx_http_echo_echo_foreach_split(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) -{ - return ngx_http_echo_helper(echo_opcode_echo_foreach_split, - echo_handler_cmd, cf, cmd, conf); -} - - -static char * -ngx_http_echo_echo_end(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) -{ - return ngx_http_echo_helper(echo_opcode_echo_end, echo_handler_cmd, cf, - cmd, conf); -} - - -static char * -ngx_http_echo_echo_abort_parent(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) -{ - return ngx_http_echo_helper(echo_opcode_echo_abort_parent, echo_handler_cmd, - cf, cmd, conf); -} - - -static char * -ngx_http_echo_echo_exec(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) -{ - return ngx_http_echo_helper(echo_opcode_echo_exec, echo_handler_cmd, - cf, cmd, conf); -} - - -static void * -ngx_http_echo_create_main_conf(ngx_conf_t *cf) -{ -#if nginx_version >= 1011011 - ngx_pool_cleanup_t *cln; -#endif - ngx_http_echo_main_conf_t *emcf; - - emcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_echo_main_conf_t)); - if (emcf == NULL) { - return NULL; - } - - /* set by ngx_pcalloc: - * hmcf->requires_filter = 0; - */ - -#if nginx_version >= 1011011 - cln = ngx_pool_cleanup_add(cf->pool, 0); - if (cln == NULL) { - return NULL; - } - - cln->data = emcf; - cln->handler = ngx_http_echo_request_headers_cleanup; -#endif - - return emcf; -} - - -static ngx_int_t -ngx_http_echo_post_config(ngx_conf_t *cf) -{ - ngx_int_t rc; - - rc = ngx_http_echo_filter_init(cf); - if (rc != NGX_OK) { - return rc; - } - - rc = ngx_http_echo_echo_init(cf); - if (rc != NGX_OK) { - return rc; - } - - ngx_http_echo_content_length_hash = - ngx_http_echo_hash_literal("content-length"); - - return ngx_http_echo_add_variables(cf); -} diff --git a/debian/modules/http-echo/src/ngx_http_echo_module.h b/debian/modules/http-echo/src/ngx_http_echo_module.h deleted file mode 100644 index ce0a305..0000000 --- a/debian/modules/http-echo/src/ngx_http_echo_module.h +++ /dev/null @@ -1,151 +0,0 @@ - -/* - * Copyright (C) Yichun Zhang (agentzh) - */ - - -#ifndef NGX_HTTP_ECHO_MODULE_H -#define NGX_HTTP_ECHO_MODULE_H - - -#include -#include -#include - - -extern ngx_module_t ngx_http_echo_module; - - -/* config directive's opcode */ -typedef enum { - echo_opcode_echo_sync, - echo_opcode_echo, - echo_opcode_echo_request_body, - echo_opcode_echo_sleep, - echo_opcode_echo_flush, - echo_opcode_echo_blocking_sleep, - echo_opcode_echo_reset_timer, - echo_opcode_echo_before_body, - echo_opcode_echo_after_body, - echo_opcode_echo_location_async, - echo_opcode_echo_location, - echo_opcode_echo_subrequest_async, - echo_opcode_echo_subrequest, - echo_opcode_echo_duplicate, - echo_opcode_echo_read_request_body, - echo_opcode_echo_foreach_split, - echo_opcode_echo_end, - echo_opcode_echo_abort_parent, - echo_opcode_echo_exec -} ngx_http_echo_opcode_t; - - -/* all the various config directives (or commands) are - * divided into two categories: "handler commands", - * and "filter commands". For instance, the "echo" - * directive is a handler command while - * "echo_before_body" is a filter one. */ -typedef enum { - echo_handler_cmd, - echo_filter_cmd - -} ngx_http_echo_cmd_category_t; - - -/* compiled form of a config directive argument's value */ -typedef struct { - /* holds the raw string of the argument value */ - ngx_str_t raw_value; - - /* fields "lengths" and "values" are set by - * the function ngx_http_script_compile, - * iff the argument value indeed contains - * nginx variables like "$foo" */ - ngx_array_t *lengths; - ngx_array_t *values; - -} ngx_http_echo_arg_template_t; - - -/* represent a config directive (or command) like "echo". */ -typedef struct { - ngx_http_echo_opcode_t opcode; - - /* each argument is of type echo_arg_template_t: */ - ngx_array_t *args; -} ngx_http_echo_cmd_t; - - -/* location config struct */ -typedef struct { - /* elements of the following arrays are of type - * ngx_http_echo_cmd_t */ - ngx_array_t *handler_cmds; - ngx_array_t *before_body_cmds; - ngx_array_t *after_body_cmds; - - unsigned seen_leading_output; - - ngx_int_t status; -} ngx_http_echo_loc_conf_t; - - -typedef struct { - ngx_int_t requires_filter; -#if nginx_version >= 1011011 - ngx_buf_t **busy_buf_ptrs; - ngx_int_t busy_buf_ptr_count; -#endif -} ngx_http_echo_main_conf_t; - - -typedef struct { - ngx_array_t *choices; /* items after splitting */ - ngx_uint_t next_choice; /* current item index */ - ngx_uint_t cmd_index; /* cmd index for the echo_foreach direcitve */ -} ngx_http_echo_foreach_ctx_t; - - -/* context struct in the request handling cycle, holding - * the current states of the command evaluator */ -typedef struct { - /* index of the next handler command in - * ngx_http_echo_loc_conf_t's "handler_cmds" array. */ - ngx_uint_t next_handler_cmd; - - /* index of the next before-body filter command in - * ngx_http_echo_loc_conf_t's "before_body_cmds" array. */ - ngx_uint_t next_before_body_cmd; - - /* index of the next after-body filter command in - * ngx_http_echo_loc_conf_t's "after_body_cmds" array. */ - ngx_uint_t next_after_body_cmd; - - ngx_http_echo_foreach_ctx_t *foreach; - - ngx_time_t timer_begin; - - ngx_event_t sleep; - - ngx_uint_t counter; - - unsigned before_body_sent:1; - unsigned skip_filter:1; - - unsigned wait_read_request_body:1; - - unsigned waiting:1; - unsigned done:1; - - unsigned run_post_subrequest:1; - unsigned header_sent:1; /* r->header_sent is not sufficient - * because special header filters like - * ngx_http_image_filter_module's may - * intercept the whole header filter chain - * leaving r->header_sent unset. So we - * should always test both flags. */ - -} ngx_http_echo_ctx_t; - - -#endif /* NGX_HTTP_ECHO_MODULE_H */ diff --git a/debian/modules/http-echo/src/ngx_http_echo_request_info.c b/debian/modules/http-echo/src/ngx_http_echo_request_info.c deleted file mode 100644 index 7dd3683..0000000 --- a/debian/modules/http-echo/src/ngx_http_echo_request_info.c +++ /dev/null @@ -1,522 +0,0 @@ - -/* - * Copyright (C) Yichun Zhang (agentzh) - */ - - -#ifndef DDEBUG -#define DDEBUG 0 -#endif -#include "ddebug.h" - -#include "ngx_http_echo_request_info.h" -#include "ngx_http_echo_util.h" -#include "ngx_http_echo_handler.h" - -#include - - -static void ngx_http_echo_post_read_request_body(ngx_http_request_t *r); -#if nginx_version >= 1011011 -void ngx_http_echo_request_headers_cleanup(void *data); -#endif - - -ngx_int_t -ngx_http_echo_exec_echo_read_request_body(ngx_http_request_t *r, - ngx_http_echo_ctx_t *ctx) -{ - return ngx_http_read_client_request_body(r, - ngx_http_echo_post_read_request_body); -} - - -static void -ngx_http_echo_post_read_request_body(ngx_http_request_t *r) -{ - ngx_http_echo_ctx_t *ctx; - - ctx = ngx_http_get_module_ctx(r, ngx_http_echo_module); - - dd("wait read request body %d", (int) ctx->wait_read_request_body); - - if (ctx->wait_read_request_body) { - ctx->waiting = 0; - ctx->done = 1; - - r->write_event_handler = ngx_http_echo_wev_handler; - - ngx_http_echo_wev_handler(r); - } -} - - -/* this function's implementation is borrowed from nginx 0.8.20 - * and modified a bit to work with subrequests. - * Copyrighted (C) by Igor Sysoev */ -ngx_int_t -ngx_http_echo_request_method_variable(ngx_http_request_t *r, - ngx_http_variable_value_t *v, uintptr_t data) -{ - if (r->method_name.data) { - v->len = r->method_name.len; - v->valid = 1; - v->no_cacheable = 0; - v->not_found = 0; - v->data = r->method_name.data; - - } else { - v->not_found = 1; - } - - return NGX_OK; -} - - -/* this function's implementation is borrowed from nginx 0.8.20 - * and modified a bit to work with subrequests. - * Copyrighted (C) by Igor Sysoev */ -ngx_int_t -ngx_http_echo_client_request_method_variable(ngx_http_request_t *r, - ngx_http_variable_value_t *v, uintptr_t data) -{ - if (r->main->method_name.data) { - v->len = r->main->method_name.len; - v->valid = 1; - v->no_cacheable = 0; - v->not_found = 0; - v->data = r->main->method_name.data; - - } else { - v->not_found = 1; - } - - return NGX_OK; -} - - -/* this function's implementation is borrowed from nginx 0.8.20 - * and modified a bit to work with subrequests. - * Copyrighted (C) by Igor Sysoev */ -ngx_int_t -ngx_http_echo_request_body_variable(ngx_http_request_t *r, - ngx_http_variable_value_t *v, uintptr_t data) -{ - u_char *p; - size_t len; - ngx_buf_t *b; - ngx_chain_t *cl; - ngx_chain_t *in; - - if (r->request_body == NULL - || r->request_body->bufs == NULL - || r->request_body->temp_file) - { - v->not_found = 1; - - return NGX_OK; - } - - in = r->request_body->bufs; - - len = 0; - for (cl = in; cl; cl = cl->next) { - b = cl->buf; - - if (!ngx_buf_in_memory(b)) { - if (b->in_file) { - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "variable echo_request_body sees in-file only " - "buffers and discard the whole body data"); - - v->not_found = 1; - - return NGX_OK; - } - - } else { - len += b->last - b->pos; - } - } - - p = ngx_pnalloc(r->pool, len); - if (p == NULL) { - return NGX_ERROR; - } - - v->data = p; - - for (cl = in; cl; cl = cl->next) { - b = cl->buf; - - if (ngx_buf_in_memory(b)) { - p = ngx_copy(p, b->pos, b->last - b->pos); - } - } - - if (p - v->data != (ssize_t) len) { - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "variable echo_request_body: buffer error"); - - v->not_found = 1; - - return NGX_OK; - } - - v->len = len; - v->valid = 1; - v->no_cacheable = 0; - v->not_found = 0; - - return NGX_OK; -} - - -ngx_int_t -ngx_http_echo_client_request_headers_variable(ngx_http_request_t *r, - ngx_http_variable_value_t *v, uintptr_t data) -{ - int line_break_len; - size_t size; - u_char *p, *last, *pos; - ngx_int_t i, j; - ngx_buf_t *b, *first = NULL; - unsigned found; -#if nginx_version >= 1011011 - ngx_buf_t **bb; - ngx_chain_t *cl; - ngx_http_echo_main_conf_t *emcf; -#endif - ngx_connection_t *c; - ngx_http_request_t *mr; - ngx_http_connection_t *hc; - - mr = r->main; - hc = r->main->http_connection; - c = mr->connection; - -#if (NGX_HTTP_V2) - /* TODO */ - if (mr->stream) { - v->not_found = 1; - return NGX_OK; - } -#endif - -#if nginx_version >= 1011011 - emcf = ngx_http_get_module_main_conf(r, ngx_http_echo_module); -#endif - - size = 0; - b = c->buffer; - - if (mr->request_line.data[mr->request_line.len] == CR) { - line_break_len = 2; - - } else { - line_break_len = 1; - } - - if (mr->request_line.data >= b->start - && mr->request_line.data + mr->request_line.len + line_break_len - <= b->pos) - { - first = b; - size += b->pos - mr->request_line.data; - } - - if (hc->nbusy) { - b = NULL; - -#if nginx_version >= 1011011 - if (hc->nbusy > emcf->busy_buf_ptr_count) { - if (emcf->busy_buf_ptrs) { - ngx_free(emcf->busy_buf_ptrs); - } - - emcf->busy_buf_ptrs = ngx_alloc(hc->nbusy * sizeof(ngx_buf_t *), - r->connection->log); - - if (emcf->busy_buf_ptrs == NULL) { - return NGX_ERROR; - } - - emcf->busy_buf_ptr_count = hc->nbusy; - } - - bb = emcf->busy_buf_ptrs; - for (cl = hc->busy; cl; cl = cl->next) { - *bb++ = cl->buf; - } - - bb = emcf->busy_buf_ptrs; - for (i = hc->nbusy; i > 0; i--) { - b = bb[i - 1]; -#else - for (i = 0; i < hc->nbusy; i++) { - b = hc->busy[i]; -#endif - - if (first == NULL) { - if (mr->request_line.data >= b->pos - || mr->request_line.data + mr->request_line.len - + line_break_len <= b->start) - { - continue; - } - - dd("found first at %d", (int) i); - first = b; - } - - size += b->pos - b->start; - } - } - - - size++; /* plus the null terminator, as required by the later - ngx_strstr() call */ - - v->data = ngx_palloc(r->pool, size); - if (v->data == NULL) { - return NGX_ERROR; - } - - last = v->data; - - b = c->buffer; - found = 0; - - if (first == b) { - found = 1; - pos = b->pos; - - last = ngx_copy(v->data, mr->request_line.data, - pos - mr->request_line.data); - - if (b != mr->header_in) { - /* skip truncated header entries (if any) */ - while (last > v->data && last[-1] != LF) { - last--; - } - } - - i = 0; - for (p = v->data; p != last; p++) { - if (*p == '\0') { - i++; - if (p + 1 != last && *(p + 1) == LF) { - *p = CR; - - } else if (i % 2 == 1) { - *p = ':'; - - } else { - *p = LF; - } - } - } - } - - if (hc->nbusy) { - -#if nginx_version >= 1011011 - bb = emcf->busy_buf_ptrs; - for (i = hc->nbusy; i > 0; i--) { - b = bb[i - 1]; -#else - for (i = 0; i < hc->nbusy; i++) { - b = hc->busy[i]; -#endif - - if (!found) { - if (b != first) { - continue; - } - - dd("found first"); - found = 1; - } - - p = last; - - pos = b->pos; - - if (b == first) { - dd("request line: %.*s", (int) mr->request_line.len, - mr->request_line.data); - - last = ngx_copy(last, - mr->request_line.data, - pos - mr->request_line.data); - - } else { - last = ngx_copy(last, b->start, pos - b->start); - } - -#if 1 - /* skip truncated header entries (if any) */ - while (last > p && last[-1] != LF) { - last--; - } -#endif - - j = 0; - for (; p != last; p++) { - if (*p == '\0') { - j++; - if (p + 1 == last) { - /* XXX this should not happen */ - dd("found string end!!"); - - } else if (*(p + 1) == LF) { - *p = CR; - - } else if (j % 2 == 1) { - *p = ':'; - - } else { - *p = LF; - } - } - } - - if (b == mr->header_in) { - break; - } - } - } - - *last++ = '\0'; - - if (last - v->data > (ssize_t) size) { - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "buffer error when evaluating " - "$echo_client__request_headers: \"%V\"", - (ngx_int_t) (last - v->data - size)); - - return NGX_ERROR; - } - - /* strip the leading part (if any) of the request body in our header. - * the first part of the request body could slip in because nginx core's - * ngx_http_request_body_length_filter and etc can move r->header_in->pos - * in case that some of the body data has been preread into r->header_in. - */ - - if ((p = (u_char *) ngx_strstr(v->data, CRLF CRLF)) != NULL) { - last = p + sizeof(CRLF CRLF) - 1; - - } else if ((p = (u_char *) ngx_strstr(v->data, CRLF "\n")) != NULL) { - last = p + sizeof(CRLF "\n") - 1; - - } else if ((p = (u_char *) ngx_strstr(v->data, "\n" CRLF)) != NULL) { - last = p + sizeof("\n" CRLF) - 1; - - } else { - for (p = last - 1; p - v->data >= 2; p--) { - if (p[0] == LF && p[-1] == CR) { - p[-1] = LF; - last = p + 1; - break; - } - - if (p[0] == LF && p[-1] == LF) { - last = p + 1; - break; - } - } - } - - v->len = last - v->data; - v->valid = 1; - v->no_cacheable = 0; - v->not_found = 0; - - return NGX_OK; -} - - -ngx_int_t -ngx_http_echo_cacheable_request_uri_variable(ngx_http_request_t *r, - ngx_http_variable_value_t *v, uintptr_t data) -{ - if (r->uri.len) { - v->len = r->uri.len; - v->valid = 1; - v->no_cacheable = 0; - v->not_found = 0; - v->data = r->uri.data; - - } else { - v->not_found = 1; - } - - return NGX_OK; -} - - -ngx_int_t -ngx_http_echo_request_uri_variable(ngx_http_request_t *r, - ngx_http_variable_value_t *v, uintptr_t data) -{ - if (r->uri.len) { - v->len = r->uri.len; - v->valid = 1; - v->no_cacheable = 1; - v->not_found = 0; - v->data = r->uri.data; - - } else { - v->not_found = 1; - } - - return NGX_OK; -} - - -ngx_int_t -ngx_http_echo_response_status_variable(ngx_http_request_t *r, - ngx_http_variable_value_t *v, uintptr_t data) -{ - u_char *p; - - if (r->headers_out.status) { - dd("headers out status: %d", (int) r->headers_out.status); - - p = ngx_palloc(r->pool, NGX_INT_T_LEN); - if (p == NULL) { - return NGX_ERROR; - } - - v->len = ngx_sprintf(p, "%ui", r->headers_out.status) - p; - v->data = p; - - v->valid = 1; - v->no_cacheable = 1; - v->not_found = 0; - - } else { - v->not_found = 1; - } - - return NGX_OK; -} - - -#if nginx_version >= 1011011 -void -ngx_http_echo_request_headers_cleanup(void *data) -{ - ngx_http_echo_main_conf_t *emcf; - - emcf = (ngx_http_echo_main_conf_t *) data; - - if (emcf->busy_buf_ptrs) { - ngx_free(emcf->busy_buf_ptrs); - emcf->busy_buf_ptrs = NULL; - } -} -#endif - -/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/debian/modules/http-echo/src/ngx_http_echo_request_info.h b/debian/modules/http-echo/src/ngx_http_echo_request_info.h deleted file mode 100644 index aa5730b..0000000 --- a/debian/modules/http-echo/src/ngx_http_echo_request_info.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef ECHO_REQUEST_INFO_H -#define ECHO_REQUEST_INFO_H - - -#include "ngx_http_echo_module.h" - - -ngx_int_t ngx_http_echo_exec_echo_read_request_body( - ngx_http_request_t *r, ngx_http_echo_ctx_t *ctx); - -ngx_int_t ngx_http_echo_request_method_variable(ngx_http_request_t *r, - ngx_http_variable_value_t *v, uintptr_t data); - -ngx_int_t ngx_http_echo_client_request_method_variable(ngx_http_request_t *r, - ngx_http_variable_value_t *v, uintptr_t data); - -ngx_int_t ngx_http_echo_request_body_variable(ngx_http_request_t *r, - ngx_http_variable_value_t *v, uintptr_t data); - -ngx_int_t ngx_http_echo_client_request_headers_variable(ngx_http_request_t *r, - ngx_http_variable_value_t *v, uintptr_t data); - -ngx_int_t ngx_http_echo_cacheable_request_uri_variable(ngx_http_request_t *r, - ngx_http_variable_value_t *v, uintptr_t data); - -ngx_int_t ngx_http_echo_request_uri_variable(ngx_http_request_t *r, - ngx_http_variable_value_t *v, uintptr_t data); - -ngx_int_t ngx_http_echo_response_status_variable(ngx_http_request_t *r, - ngx_http_variable_value_t *v, uintptr_t data); - -#if nginx_version >= 1011011 -void ngx_http_echo_request_headers_cleanup(void *data); -#endif - -#endif /* ECHO_REQUEST_INFO_H */ diff --git a/debian/modules/http-echo/src/ngx_http_echo_sleep.c b/debian/modules/http-echo/src/ngx_http_echo_sleep.c deleted file mode 100644 index c96fa5a..0000000 --- a/debian/modules/http-echo/src/ngx_http_echo_sleep.c +++ /dev/null @@ -1,208 +0,0 @@ - -/* - * Copyright (C) Yichun Zhang (agentzh) - */ - - -#ifndef DDEBUG -#define DDEBUG 0 -#endif -#include "ddebug.h" - - -#include "ngx_http_echo_sleep.h" -#include "ngx_http_echo_handler.h" - -#include -#include - - -/* event handler for echo_sleep */ - -static void ngx_http_echo_post_sleep(ngx_http_request_t *r); -static void ngx_http_echo_sleep_cleanup(void *data); - - -ngx_int_t -ngx_http_echo_exec_echo_sleep(ngx_http_request_t *r, - ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args) -{ - ngx_str_t *computed_arg; - ngx_str_t *computed_arg_elts; - ngx_int_t delay; /* in msec */ - ngx_http_cleanup_t *cln; - - computed_arg_elts = computed_args->elts; - computed_arg = &computed_arg_elts[0]; - - delay = ngx_atofp(computed_arg->data, computed_arg->len, 3); - - if (delay == NGX_ERROR) { - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "invalid sleep duration \"%V\"", &computed_arg_elts[0]); - - return NGX_HTTP_BAD_REQUEST; - } - - dd("adding timer with delay %lu ms, r:%.*s", (unsigned long) delay, - (int) r->uri.len, r->uri.data); - - ngx_add_timer(&ctx->sleep, (ngx_msec_t) delay); - - /* we don't check broken downstream connections - * ourselves so even if the client shuts down - * the connection prematurely, nginx will still - * go on waiting for our timers to get properly - * expired. However, we'd still register a - * cleanup handler for completeness. */ - - cln = ngx_http_cleanup_add(r, 0); - if (cln == NULL) { - return NGX_ERROR; - } - - cln->handler = ngx_http_echo_sleep_cleanup; - cln->data = r; - - return NGX_AGAIN; -} - - -static void -ngx_http_echo_post_sleep(ngx_http_request_t *r) -{ - ngx_http_echo_ctx_t *ctx; - /* ngx_int_t rc; */ - - dd("post sleep, r:%.*s", (int) r->uri.len, r->uri.data); - - ctx = ngx_http_get_module_ctx(r, ngx_http_echo_module); - - if (ctx == NULL) { - return; - } - - ctx->waiting = 0; - ctx->done = 1; - - dd("sleep: after get module ctx"); - - dd("timed out? %d", ctx->sleep.timedout); - dd("timer set? %d", ctx->sleep.timer_set); - - if (!ctx->sleep.timedout) { - dd("HERE reached!"); - return; - } - - ctx->sleep.timedout = 0; - - if (ctx->sleep.timer_set) { - dd("deleting timer for echo_sleep"); - - ngx_del_timer(&ctx->sleep); - } - - /* r->write_event_handler = ngx_http_request_empty_handler; */ - - ngx_http_echo_wev_handler(r); -} - - -void -ngx_http_echo_sleep_event_handler(ngx_event_t *ev) -{ - ngx_connection_t *c; - ngx_http_request_t *r; - ngx_http_log_ctx_t *ctx; - - r = ev->data; - c = r->connection; - - if (c->destroyed) { - return; - } - - if (c->error) { - ngx_http_finalize_request(r, NGX_ERROR); - return; - } - - ctx = c->log->data; - ctx->current_request = r; - - /* XXX when r->done == 1 we should do cleaning immediately - * and delete our timer and then quit. */ - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, - "echo sleep event handler: \"%V?%V\"", &r->uri, &r->args); - - /* - if (r->done) { - return; - } - */ - - ngx_http_echo_post_sleep(r); - -#if defined(nginx_version) - - dd("before run posted requests"); - - ngx_http_run_posted_requests(c); - - dd("after run posted requests"); - -#endif -} - - -ngx_int_t -ngx_http_echo_exec_echo_blocking_sleep(ngx_http_request_t *r, - ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args) -{ - ngx_str_t *computed_arg; - ngx_str_t *computed_arg_elts; - ngx_int_t delay; /* in msec */ - - computed_arg_elts = computed_args->elts; - computed_arg = &computed_arg_elts[0]; - - delay = ngx_atofp(computed_arg->data, computed_arg->len, 3); - - if (delay == NGX_ERROR) { - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "invalid sleep duration \"%V\"", &computed_arg_elts[0]); - return NGX_HTTP_BAD_REQUEST; - } - - dd("blocking delay: %lu ms", (unsigned long) delay); - - ngx_msleep((ngx_msec_t) delay); - - return NGX_OK; -} - - -static void -ngx_http_echo_sleep_cleanup(void *data) -{ - ngx_http_request_t *r = data; - ngx_http_echo_ctx_t *ctx; - - dd("echo sleep cleanup"); - - ctx = ngx_http_get_module_ctx(r, ngx_http_echo_module); - if (ctx == NULL) { - return; - } - - if (ctx->sleep.timer_set) { - dd("cleanup: deleting timer for echo_sleep"); - - ngx_del_timer(&ctx->sleep); - return; - } - - dd("cleanup: timer not set"); -} diff --git a/debian/modules/http-echo/src/ngx_http_echo_sleep.h b/debian/modules/http-echo/src/ngx_http_echo_sleep.h deleted file mode 100644 index 8bb70c3..0000000 --- a/debian/modules/http-echo/src/ngx_http_echo_sleep.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef ECHO_SLEEP_H -#define ECHO_SLEEP_H - -#include "ngx_http_echo_module.h" - -ngx_int_t ngx_http_echo_exec_echo_sleep( - ngx_http_request_t *r, ngx_http_echo_ctx_t *ctx, - ngx_array_t *computed_args); - -ngx_int_t ngx_http_echo_exec_echo_blocking_sleep(ngx_http_request_t *r, - ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args); - -void ngx_http_echo_sleep_event_handler(ngx_event_t *ev); - -#endif /* ECHO_SLEEP_H */ - diff --git a/debian/modules/http-echo/src/ngx_http_echo_subrequest.c b/debian/modules/http-echo/src/ngx_http_echo_subrequest.c deleted file mode 100644 index 8644d7f..0000000 --- a/debian/modules/http-echo/src/ngx_http_echo_subrequest.c +++ /dev/null @@ -1,791 +0,0 @@ - -/* - * Copyright (C) Yichun Zhang (agentzh) - */ - - -#ifndef DDEBUG -#define DDEBUG 0 -#endif -#include "ddebug.h" - - -#include "ngx_http_echo_util.h" -#include "ngx_http_echo_subrequest.h" -#include "ngx_http_echo_handler.h" -#include - - -#define ngx_http_echo_method_name(m) { sizeof(m) - 1, (u_char *) m " " } - - -ngx_str_t ngx_http_echo_content_length_header_key = - ngx_string("Content-Length"); - -ngx_str_t ngx_http_echo_get_method = ngx_http_echo_method_name("GET"); -ngx_str_t ngx_http_echo_put_method = ngx_http_echo_method_name("PUT"); -ngx_str_t ngx_http_echo_post_method = ngx_http_echo_method_name("POST"); -ngx_str_t ngx_http_echo_head_method = ngx_http_echo_method_name("HEAD"); -ngx_str_t ngx_http_echo_copy_method = ngx_http_echo_method_name("COPY"); -ngx_str_t ngx_http_echo_move_method = ngx_http_echo_method_name("MOVE"); -ngx_str_t ngx_http_echo_lock_method = ngx_http_echo_method_name("LOCK"); -ngx_str_t ngx_http_echo_mkcol_method = ngx_http_echo_method_name("MKCOL"); -ngx_str_t ngx_http_echo_trace_method = ngx_http_echo_method_name("TRACE"); -ngx_str_t ngx_http_echo_delete_method = ngx_http_echo_method_name("DELETE"); -ngx_str_t ngx_http_echo_unlock_method = ngx_http_echo_method_name("UNLOCK"); -ngx_str_t ngx_http_echo_options_method = ngx_http_echo_method_name("OPTIONS"); -ngx_str_t ngx_http_echo_propfind_method = - ngx_http_echo_method_name("PROPFIND"); -ngx_str_t ngx_http_echo_proppatch_method = - ngx_http_echo_method_name("PROPPATCH"); - - -typedef struct ngx_http_echo_subrequest_s { - ngx_uint_t method; - ngx_str_t *method_name; - ngx_str_t *location; - ngx_str_t *query_string; - ssize_t content_length_n; - ngx_http_request_body_t *request_body; -} ngx_http_echo_subrequest_t; - - -static ngx_int_t ngx_http_echo_parse_method_name(ngx_str_t **method_name_ptr); -static ngx_int_t ngx_http_echo_adjust_subrequest(ngx_http_request_t *sr, - ngx_http_echo_subrequest_t *parsed_sr); -static ngx_int_t ngx_http_echo_parse_subrequest_spec(ngx_http_request_t *r, - ngx_array_t *computed_args, ngx_http_echo_subrequest_t **parsed_sr_ptr); -static ngx_int_t ngx_http_echo_set_content_length_header(ngx_http_request_t *r, - off_t len); - - -ngx_int_t -ngx_http_echo_exec_echo_subrequest_async(ngx_http_request_t *r, - ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args) -{ - ngx_int_t rc; - ngx_http_echo_subrequest_t *parsed_sr; - ngx_http_request_t *sr; /* subrequest object */ - ngx_str_t args; - ngx_uint_t flags = 0; - - dd_enter(); - - rc = ngx_http_echo_parse_subrequest_spec(r, computed_args, &parsed_sr); - if (rc != NGX_OK) { - return rc; - } - - dd("location: %.*s", - (int) parsed_sr->location->len, - parsed_sr->location->data); - - args.data = NULL; - args.len = 0; - - if (ngx_http_parse_unsafe_uri(r, parsed_sr->location, &args, &flags) - != NGX_OK) - { - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "echo_subrequest_async sees unsafe uri: \"%V\"", - parsed_sr->location); - return NGX_ERROR; - } - - if (args.len > 0 && parsed_sr->query_string == NULL) { - parsed_sr->query_string = &args; - } - - rc = ngx_http_echo_send_header_if_needed(r, ctx); - if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { - return rc; - } - - rc = ngx_http_subrequest(r, parsed_sr->location, parsed_sr->query_string, - &sr, NULL, 0); - - if (rc != NGX_OK) { - return NGX_ERROR; - } - - rc = ngx_http_echo_adjust_subrequest(sr, parsed_sr); - - if (rc != NGX_OK) { - return rc; - } - - return NGX_OK; -} - - -ngx_int_t -ngx_http_echo_exec_echo_subrequest(ngx_http_request_t *r, - ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args) -{ - ngx_int_t rc; - ngx_http_request_t *sr; /* subrequest object */ - ngx_http_post_subrequest_t *psr; - ngx_http_echo_subrequest_t *parsed_sr; - ngx_str_t args; - ngx_uint_t flags = 0; - ngx_http_echo_ctx_t *sr_ctx; - - dd_enter(); - - rc = ngx_http_echo_parse_subrequest_spec(r, computed_args, &parsed_sr); - if (rc != NGX_OK) { - return rc; - } - - args.data = NULL; - args.len = 0; - - if (ngx_http_parse_unsafe_uri(r, parsed_sr->location, &args, &flags) - != NGX_OK) - { - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "echo_subrequest sees unsafe uri: \"%V\"", - parsed_sr->location); - return NGX_ERROR; - } - - if (args.len > 0 && parsed_sr->query_string == NULL) { - parsed_sr->query_string = &args; - } - - rc = ngx_http_echo_send_header_if_needed(r, ctx); - if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { - return rc; - } - - sr_ctx = ngx_http_echo_create_ctx(r); - - /* set by ngx_http_echo_create_ctx - * sr_ctx->run_post_subrequest = 0 - */ - - dd("creating sr ctx for %.*s: %p", (int) parsed_sr->location->len, - parsed_sr->location->data, sr_ctx); - - psr = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t)); - - if (psr == NULL) { - return NGX_ERROR; - } - - psr->handler = ngx_http_echo_post_subrequest; - psr->data = sr_ctx; - - rc = ngx_http_subrequest(r, parsed_sr->location, parsed_sr->query_string, - &sr, psr, 0); - - if (rc != NGX_OK) { - return NGX_ERROR; - } - - sr_ctx->sleep.data = sr; - - ngx_http_set_ctx(sr, sr_ctx, ngx_http_echo_module); - - rc = ngx_http_echo_adjust_subrequest(sr, parsed_sr); - - if (rc != NGX_OK) { - return NGX_ERROR; - } - - return NGX_AGAIN; -} - - -static ngx_int_t -ngx_http_echo_parse_subrequest_spec(ngx_http_request_t *r, - ngx_array_t *computed_args, ngx_http_echo_subrequest_t **parsed_sr_ptr) -{ - ngx_str_t *computed_arg_elts, *arg; - ngx_str_t **to_write = NULL; - ngx_str_t *method_name; - ngx_str_t *body_str = NULL; - ngx_str_t *body_file = NULL; - ngx_uint_t i; - ngx_flag_t expecting_opt; - ngx_http_request_body_t *rb = NULL; - ngx_buf_t *b; - ngx_http_echo_subrequest_t *parsed_sr; - ngx_open_file_info_t of; - ngx_http_core_loc_conf_t *clcf; - size_t len; - - *parsed_sr_ptr = ngx_pcalloc(r->pool, sizeof(ngx_http_echo_subrequest_t)); - if (*parsed_sr_ptr == NULL) { - return NGX_ERROR; - } - - parsed_sr = *parsed_sr_ptr; - computed_arg_elts = computed_args->elts; - method_name = &computed_arg_elts[0]; - parsed_sr->location = &computed_arg_elts[1]; - - if (parsed_sr->location->len == 0) { - return NGX_ERROR; - } - - expecting_opt = 1; - - for (i = 2; i < computed_args->nelts; i++) { - arg = &computed_arg_elts[i]; - - if (!expecting_opt) { - if (to_write == NULL) { - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "echo_subrequest_async: to_write should NOT be NULL"); - return NGX_ERROR; - } - - *to_write = arg; - to_write = NULL; - - expecting_opt = 1; - - continue; - } - - if (arg->len == 2) { - if (ngx_strncmp("-q", arg->data, arg->len) == 0) { - to_write = &parsed_sr->query_string; - expecting_opt = 0; - continue; - } - - if (ngx_strncmp("-b", arg->data, arg->len) == 0) { - to_write = &body_str; - expecting_opt = 0; - continue; - } - - if (ngx_strncmp("-f", arg->data, arg->len) == 0) { - dd("found option -f"); - to_write = &body_file; - expecting_opt = 0; - continue; - } - } - - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "unknown option for echo_subrequest*: %V", arg); - - return NGX_ERROR; - } - - if (body_str != NULL && body_str->len) { - rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t)); - - if (rb == NULL) { - return NGX_ERROR; - } - - parsed_sr->content_length_n = body_str->len; - - b = ngx_calloc_buf(r->pool); - if (b == NULL) { - return NGX_ERROR; - } - - b->temporary = 1; - /* b->memory = 1; */ - b->start = b->pos = body_str->data; - b->end = b->last = body_str->data + body_str->len; - - rb->bufs = ngx_alloc_chain_link(r->pool); - if (rb->bufs == NULL) { - return NGX_ERROR; - } - - rb->bufs->buf = b; - rb->bufs->next = NULL; - - rb->buf = b; - - } else if (body_file != NULL && body_file->len) { - - dd("body_file defined %.*s", (int) body_file->len, body_file->data); - - body_file->data = ngx_http_echo_rebase_path(r->pool, body_file->data, - body_file->len, &len); - - if (body_file->data == NULL) { - return NGX_ERROR; - } - - body_file->len = len; - - dd("after rebase, the path becomes %.*s", (int) body_file->len, - body_file->data); - - rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t)); - if (rb == NULL) { - return NGX_ERROR; - } - - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - ngx_memzero(&of, sizeof(ngx_open_file_info_t)); - -#if defined(nginx_version) && nginx_version >= 8018 - of.read_ahead = clcf->read_ahead; -#endif - - of.directio = clcf->directio; - of.valid = clcf->open_file_cache_valid; - of.min_uses = clcf->open_file_cache_min_uses; - of.errors = clcf->open_file_cache_errors; - of.events = clcf->open_file_cache_events; - - if (ngx_open_cached_file(clcf->open_file_cache, body_file, &of, r->pool) - != NGX_OK) - { - ngx_log_error(NGX_LOG_ERR, r->connection->log, of.err, - "%s \"%V\" failed", - of.failed, body_file); - - return NGX_ERROR; - } - - dd("file content size: %d", (int) of.size); - - parsed_sr->content_length_n = (ssize_t) of.size; - - b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); - if (b == NULL) { - return NGX_ERROR; - } - - b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t)); - if (b->file == NULL) { - return NGX_ERROR; - } - - b->file_pos = 0; - b->file_last = of.size; - - b->in_file = b->file_last ? 1: 0; - -#if 0 - b->last_buf = (r == r->main) ? 1: 0; - b->last_in_chain = 1; -#endif - - b->file->fd = of.fd; - b->file->name = *body_file; - b->file->log = r->connection->log; - b->file->directio = of.is_directio; - - rb->bufs = ngx_alloc_chain_link(r->pool); - if (rb->bufs == NULL) { - return NGX_ERROR; - } - - rb->bufs->buf = b; - rb->bufs->next = NULL; - rb->buf = b; - } - - parsed_sr->request_body = rb; - - parsed_sr->method = ngx_http_echo_parse_method_name(&method_name); - parsed_sr->method_name = method_name; - - return NGX_OK; -} - - -static ngx_int_t -ngx_http_echo_adjust_subrequest(ngx_http_request_t *sr, - ngx_http_echo_subrequest_t *parsed_sr) -{ - ngx_http_core_main_conf_t *cmcf; - ngx_http_request_t *r; - ngx_http_request_body_t *body; - ngx_int_t rc; - - sr->method = parsed_sr->method; - sr->method_name = *(parsed_sr->method_name); - - if (sr->method == NGX_HTTP_HEAD) { - sr->header_only = 1; - } - - r = sr->parent; - - sr->header_in = r->header_in; - - /* XXX work-around a bug in ngx_http_subrequest */ - if (r->headers_in.headers.last == &r->headers_in.headers.part) { - sr->headers_in.headers.last = &sr->headers_in.headers.part; - } - - /* we do not inherit the parent request's variables */ - cmcf = ngx_http_get_module_main_conf(sr, ngx_http_core_module); - sr->variables = ngx_pcalloc(sr->pool, cmcf->variables.nelts - * sizeof(ngx_http_variable_value_t)); - - if (sr->variables == NULL) { - return NGX_ERROR; - } - - body = parsed_sr->request_body; - if (body) { - sr->request_body = body; - - rc = ngx_http_echo_set_content_length_header(sr, body->buf ? - ngx_buf_size(body->buf) - : 0); - - if (rc != NGX_OK) { - return NGX_ERROR; - } - } - - dd("subrequest body: %p", sr->request_body); - - return NGX_OK; -} - - -static ngx_int_t -ngx_http_echo_parse_method_name(ngx_str_t **method_name_ptr) -{ - const ngx_str_t *method_name = *method_name_ptr; - - switch (method_name->len) { - case 3: - if (ngx_http_echo_strcmp_const(method_name->data, "GET") == 0) { - *method_name_ptr = &ngx_http_echo_get_method; - return NGX_HTTP_GET; - } - - if (ngx_http_echo_strcmp_const(method_name->data, "PUT") == 0) { - *method_name_ptr = &ngx_http_echo_put_method; - return NGX_HTTP_PUT; - } - - return NGX_HTTP_UNKNOWN; - - case 4: - if (ngx_http_echo_strcmp_const(method_name->data, "POST") == 0) { - *method_name_ptr = &ngx_http_echo_post_method; - return NGX_HTTP_POST; - } - - if (ngx_http_echo_strcmp_const(method_name->data, "HEAD") == 0) { - *method_name_ptr = &ngx_http_echo_head_method; - return NGX_HTTP_HEAD; - } - - if (ngx_http_echo_strcmp_const(method_name->data, "COPY") == 0) { - *method_name_ptr = &ngx_http_echo_copy_method; - return NGX_HTTP_COPY; - } - - if (ngx_http_echo_strcmp_const(method_name->data, "MOVE") == 0) { - *method_name_ptr = &ngx_http_echo_move_method; - return NGX_HTTP_MOVE; - } - - if (ngx_http_echo_strcmp_const(method_name->data, "LOCK") == 0) { - *method_name_ptr = &ngx_http_echo_lock_method; - return NGX_HTTP_LOCK; - } - - return NGX_HTTP_UNKNOWN; - - case 5: - if (ngx_http_echo_strcmp_const(method_name->data, "MKCOL") == 0) { - *method_name_ptr = &ngx_http_echo_mkcol_method; - return NGX_HTTP_MKCOL; - } - - if (ngx_http_echo_strcmp_const(method_name->data, "TRACE") == 0) { - *method_name_ptr = &ngx_http_echo_trace_method; - return NGX_HTTP_TRACE; - } - - return NGX_HTTP_UNKNOWN; - - case 6: - if (ngx_http_echo_strcmp_const(method_name->data, "DELETE") == 0) { - *method_name_ptr = &ngx_http_echo_delete_method; - return NGX_HTTP_DELETE; - } - - if (ngx_http_echo_strcmp_const(method_name->data, "UNLOCK") == 0) { - *method_name_ptr = &ngx_http_echo_unlock_method; - return NGX_HTTP_UNLOCK; - } - - return NGX_HTTP_UNKNOWN; - - case 7: - if (ngx_http_echo_strcmp_const(method_name->data, "OPTIONS") == 0) { - *method_name_ptr = &ngx_http_echo_options_method; - return NGX_HTTP_OPTIONS; - } - - return NGX_HTTP_UNKNOWN; - - case 8: - if (ngx_http_echo_strcmp_const(method_name->data, "PROPFIND") == 0) { - *method_name_ptr = &ngx_http_echo_propfind_method; - return NGX_HTTP_PROPFIND; - } - - return NGX_HTTP_UNKNOWN; - - case 9: - if (ngx_http_echo_strcmp_const(method_name->data, "PROPPATCH") == 0) { - *method_name_ptr = &ngx_http_echo_proppatch_method; - return NGX_HTTP_PROPPATCH; - } - - return NGX_HTTP_UNKNOWN; - - default: - return NGX_HTTP_UNKNOWN; - } -} - - -/* XXX extermely evil and not working yet */ -ngx_int_t -ngx_http_echo_exec_abort_parent(ngx_http_request_t *r, - ngx_http_echo_ctx_t *ctx) -{ -#if 0 - ngx_http_postponed_request_t *pr, *ppr; - ngx_http_request_t *saved_data = NULL; - ngx_chain_t *out = NULL; - /* ngx_int_t rc; */ - - dd("aborting parent..."); - - if (r == r->main || r->parent == NULL) { - return NGX_OK; - } - - if (r->parent->postponed) { - dd("Found parent->postponed..."); - - saved_data = r->connection->data; - ppr = NULL; - for (pr = r->parent->postponed; pr->next; pr = pr->next) { - if (pr->request == NULL) { - continue; - } - - if (pr->request == r) { - /* r->parent->postponed->next = pr; */ - dd("found the current subrequest"); - out = pr->out; - continue; - } - - /* r->connection->data = pr->request; */ - dd("finalizing the subrequest..."); - ngx_http_upstream_create(pr->request); - pr->request->upstream = NULL; - - if (ppr == NULL) { - r->parent->postponed = pr->next; - ppr = pr->next; - } else { - ppr->next = pr->next; - ppr = pr->next; - } - } - } - - r->parent->postponed->next = NULL; - - /* - r->connection->data = r->parent; - r->connection->buffered = 0; - - if (out != NULL) { - dd("trying to send more stuffs for the parent"); - ngx_http_output_filter(r->parent, out); - } - */ - - /* ngx_http_send_special(r->parent, NGX_HTTP_LAST); */ - - if (saved_data) { - r->connection->data = saved_data; - } - - dd("terminating the parent request"); - - return ngx_http_echo_send_chain_link(r, ctx, NULL /* indicate LAST */); - - /* ngx_http_upstream_create(r); */ - - /* ngx_http_finalize_request(r->parent, NGX_ERROR); */ -#endif - - return NGX_OK; -} - - -ngx_int_t -ngx_http_echo_exec_exec(ngx_http_request_t *r, - ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args) -{ - ngx_str_t *uri; - ngx_str_t *user_args; - ngx_str_t args; - ngx_uint_t flags; - ngx_str_t *computed_arg; - - computed_arg = computed_args->elts; - - uri = &computed_arg[0]; - - if (uri->len == 0) { - return NGX_HTTP_BAD_REQUEST; - } - - if (computed_args->nelts > 1) { - user_args = &computed_arg[1]; - - } else { - user_args = NULL; - } - - args.data = NULL; - args.len = 0; - - if (ngx_http_parse_unsafe_uri(r, uri, &args, &flags) != NGX_OK) { - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "echo_exec sees unsafe uri: \"%V\"", - uri); - return NGX_ERROR; - } - - if (args.len > 0 && user_args == NULL) { - user_args = &args; - } - - r->write_event_handler = ngx_http_request_empty_handler; - - if (uri->data[0] == '@') { - - if (user_args && user_args->len > 0) { - ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, - "querystring %V ignored when exec'ing named " - "location %V", user_args, uri); - } - -#if 1 - /* clear the modules contexts */ - ngx_memzero(r->ctx, sizeof(void *) * ngx_http_max_module); -#endif - - dd("named location: %.*s, c:%d", (int) uri->len, uri->data, - (int) r->main->count); - - return ngx_http_named_location(r, uri); - } - - return ngx_http_internal_redirect(r, uri, user_args); -} - - -static ngx_int_t -ngx_http_echo_set_content_length_header(ngx_http_request_t *r, off_t len) -{ - ngx_table_elt_t *h, *header; - u_char *p; - ngx_list_part_t *part; - ngx_http_request_t *pr; - ngx_uint_t i; - - r->headers_in.content_length_n = len; - - if (ngx_list_init(&r->headers_in.headers, r->pool, 20, - sizeof(ngx_table_elt_t)) - != NGX_OK) - { - return NGX_ERROR; - } - - h = ngx_list_push(&r->headers_in.headers); - if (h == NULL) { - return NGX_ERROR; - } - - h->key = ngx_http_echo_content_length_header_key; - h->lowcase_key = ngx_pnalloc(r->pool, h->key.len); - if (h->lowcase_key == NULL) { - return NGX_ERROR; - } - - ngx_strlow(h->lowcase_key, h->key.data, h->key.len); - - r->headers_in.content_length = h; - - p = ngx_palloc(r->pool, NGX_OFF_T_LEN); - if (p == NULL) { - return NGX_ERROR; - } - - h->value.data = p; - - h->value.len = ngx_sprintf(h->value.data, "%O", len) - h->value.data; - - h->hash = ngx_http_echo_content_length_hash; - - dd("r content length: %.*s", - (int) r->headers_in.content_length->value.len, - r->headers_in.content_length->value.data); - - pr = r->parent; - - if (pr == NULL) { - return NGX_OK; - } - - /* forward the parent request's all other request headers */ - - part = &pr->headers_in.headers.part; - header = part->elts; - - 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 == sizeof("Content-Length") - 1 - && ngx_strncasecmp(header[i].key.data, (u_char *) "Content-Length", - sizeof("Content-Length") - 1) - == 0) - { - continue; - } - - h = ngx_list_push(&r->headers_in.headers); - if (h == NULL) { - return NGX_ERROR; - } - - *h = header[i]; - } - - /* XXX maybe we should set those built-in header slot in - * ngx_http_headers_in_t too? */ - - return NGX_OK; -} diff --git a/debian/modules/http-echo/src/ngx_http_echo_subrequest.h b/debian/modules/http-echo/src/ngx_http_echo_subrequest.h deleted file mode 100644 index 61c0a04..0000000 --- a/debian/modules/http-echo/src/ngx_http_echo_subrequest.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef ECHO_SUBREQUEST_H -#define ECHO_SUBREQUEST_H - -#include "ngx_http_echo_module.h" - -ngx_int_t ngx_http_echo_exec_echo_subrequest(ngx_http_request_t *r, - ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args); - -ngx_int_t ngx_http_echo_exec_echo_subrequest_async(ngx_http_request_t *r, - ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args); - -ngx_int_t ngx_http_echo_exec_abort_parent(ngx_http_request_t *r, - ngx_http_echo_ctx_t *ctx); - -ngx_int_t ngx_http_echo_exec_exec(ngx_http_request_t *r, - ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args); - -#endif /* ECHO_SUBREQUEST_H */ - diff --git a/debian/modules/http-echo/src/ngx_http_echo_timer.c b/debian/modules/http-echo/src/ngx_http_echo_timer.c deleted file mode 100644 index e2777ee..0000000 --- a/debian/modules/http-echo/src/ngx_http_echo_timer.c +++ /dev/null @@ -1,95 +0,0 @@ -#ifndef DDEBUG -#define DDEBUG 0 -#endif - -#include "ddebug.h" - -#include "ngx_http_echo_timer.h" -#include "ngx_http_echo_util.h" - -#include -#include -#include - - -ngx_int_t -ngx_http_echo_timer_elapsed_variable(ngx_http_request_t *r, - ngx_http_variable_value_t *v, uintptr_t data) -{ - ngx_http_echo_ctx_t *ctx; - ngx_msec_int_t ms; - u_char *p; - ngx_time_t *tp; - size_t size; - - ctx = ngx_http_get_module_ctx(r, ngx_http_echo_module); - if (ctx == NULL) { - ctx = ngx_http_echo_create_ctx(r); - if (ctx == NULL) { - return NGX_ERROR; - } - - ngx_http_set_ctx(r, ctx, ngx_http_echo_module); - } - - if (ctx->timer_begin.sec == 0) { - ctx->timer_begin.sec = r->start_sec; - ctx->timer_begin.msec = (ngx_msec_t) r->start_msec; - } - - /* force the ngx timer to update */ - -#if (nginx_version >= 8035) || (nginx_version < 8000 && nginx_version >= 7066) - ngx_time_update(); -#else - ngx_time_update(0, 0); -#endif - - tp = ngx_timeofday(); - - dd("old sec msec: %ld %d\n", (long) ctx->timer_begin.sec, - (int) ctx->timer_begin.msec); - - dd("new sec msec: %ld %d\n", (long) tp->sec, (int) tp->msec); - - ms = (ngx_msec_int_t) - ((tp->sec - ctx->timer_begin.sec) * 1000 + - (tp->msec - ctx->timer_begin.msec)); - ms = (ms >= 0) ? ms : 0; - - size = sizeof("-9223372036854775808.000") - 1; - - p = ngx_palloc(r->pool, size); - if (p == NULL) { - return NGX_ERROR; - } - - v->len = ngx_snprintf(p, size, "%T.%03M", ms / 1000, ms % 1000) - p; - v->data = p; - - v->valid = 1; - v->no_cacheable = 1; - v->not_found = 0; - - return NGX_OK; -} - - -ngx_int_t -ngx_http_echo_exec_echo_reset_timer(ngx_http_request_t *r, - ngx_http_echo_ctx_t *ctx) -{ - dd("Exec timer..."); - - /* force the ngx timer to update */ - -#if (nginx_version >= 8035) || (nginx_version < 8000 && nginx_version >= 7066) - ngx_time_update(); -#else - ngx_time_update(0, 0); -#endif - - ctx->timer_begin = *ngx_timeofday(); - return NGX_OK; -} - diff --git a/debian/modules/http-echo/src/ngx_http_echo_timer.h b/debian/modules/http-echo/src/ngx_http_echo_timer.h deleted file mode 100644 index b6e7ff3..0000000 --- a/debian/modules/http-echo/src/ngx_http_echo_timer.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef ECHO_TIMER_H -#define ECHO_TIMER_H - -#include "ngx_http_echo_module.h" - -ngx_int_t ngx_http_echo_timer_elapsed_variable(ngx_http_request_t *r, - ngx_http_variable_value_t *v, uintptr_t data); - -ngx_int_t ngx_http_echo_exec_echo_reset_timer(ngx_http_request_t *r, - ngx_http_echo_ctx_t *ctx); - -#endif /* ECHO_TIMER_H */ - diff --git a/debian/modules/http-echo/src/ngx_http_echo_util.c b/debian/modules/http-echo/src/ngx_http_echo_util.c deleted file mode 100644 index fed0587..0000000 --- a/debian/modules/http-echo/src/ngx_http_echo_util.c +++ /dev/null @@ -1,302 +0,0 @@ - -/* - * Copyright (C) Yichun Zhang (agentzh) - */ - - -#ifndef DDEBUG -#define DDEBUG 0 -#endif -#include "ddebug.h" - - -#include "ngx_http_echo_util.h" -#include "ngx_http_echo_sleep.h" - - -ngx_uint_t ngx_http_echo_content_length_hash = 0; - - -ngx_http_echo_ctx_t * -ngx_http_echo_create_ctx(ngx_http_request_t *r) -{ - ngx_http_echo_ctx_t *ctx; - - ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_echo_ctx_t)); - if (ctx == NULL) { - return NULL; - } - - ctx->sleep.handler = ngx_http_echo_sleep_event_handler; - ctx->sleep.data = r; - ctx->sleep.log = r->connection->log; - - return ctx; -} - - -ngx_int_t -ngx_http_echo_eval_cmd_args(ngx_http_request_t *r, - ngx_http_echo_cmd_t *cmd, ngx_array_t *computed_args, - ngx_array_t *opts) -{ - unsigned expecting_opts = 1; - ngx_uint_t i; - ngx_array_t *args = cmd->args; - ngx_str_t *arg, *raw, *opt; - ngx_http_echo_arg_template_t *value; - - value = args->elts; - - for (i = 0; i < args->nelts; i++) { - raw = &value[i].raw_value; - - if (value[i].lengths == NULL && raw->len > 0) { - if (expecting_opts) { - if (raw->len == 1 || raw->data[0] != '-') { - expecting_opts = 0; - - } else if (raw->data[1] == '-') { - expecting_opts = 0; - continue; - - } else { - opt = ngx_array_push(opts); - if (opt == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - opt->len = raw->len - 1; - opt->data = raw->data + 1; - - dd("pushing opt: %.*s", (int) opt->len, opt->data); - - continue; - } - } - - } else { - expecting_opts = 0; - } - - arg = ngx_array_push(computed_args); - if (arg == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - if (value[i].lengths == NULL) { /* does not contain vars */ - dd("Using raw value \"%.*s\"", (int) raw->len, raw->data); - *arg = *raw; - - } else { - if (ngx_http_script_run(r, arg, value[i].lengths->elts, - 0, value[i].values->elts) - == NULL) - { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - } - - dd("pushed arg: %.*s", (int) arg->len, arg->data); - } - - return NGX_OK; -} - - -ngx_int_t -ngx_http_echo_send_chain_link(ngx_http_request_t *r, - ngx_http_echo_ctx_t *ctx, ngx_chain_t *in) -{ - ngx_int_t rc; - - rc = ngx_http_echo_send_header_if_needed(r, ctx); - - if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { - return rc; - } - - if (in == NULL) { - -#if defined(nginx_version) && nginx_version <= 8004 - - /* earlier versions of nginx does not allow subrequests - to send last_buf themselves */ - if (r != r->main) { - return NGX_OK; - } - -#endif - - rc = ngx_http_send_special(r, NGX_HTTP_LAST); - if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { - return rc; - } - - return NGX_OK; - } - - /* FIXME we should udpate chains to recycle chain links and bufs */ - return ngx_http_output_filter(r, in); -} - - -ngx_int_t -ngx_http_echo_send_header_if_needed(ngx_http_request_t *r, - ngx_http_echo_ctx_t *ctx) -{ - ngx_int_t rc; - ngx_http_echo_loc_conf_t *elcf; - - if (!r->header_sent && !ctx->header_sent) { - elcf = ngx_http_get_module_loc_conf(r, ngx_http_echo_module); - - r->headers_out.status = (ngx_uint_t) elcf->status; - - if (ngx_http_set_content_type(r) != NGX_OK) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - ngx_http_clear_content_length(r); - ngx_http_clear_accept_ranges(r); - - rc = ngx_http_send_header(r); - ctx->header_sent = 1; - return rc; - } - - return NGX_OK; -} - - -ssize_t -ngx_http_echo_atosz(u_char *line, size_t n) -{ - ssize_t value; - - if (n == 0) { - return NGX_ERROR; - } - - for (value = 0; n--; line++) { - if (*line == '_') { /* we ignore undercores */ - continue; - } - - if (*line < '0' || *line > '9') { - return NGX_ERROR; - } - - value = value * 10 + (*line - '0'); - } - - if (value < 0) { - return NGX_ERROR; - } - - return value; -} - - -/* Modified from the ngx_strlcasestrn function in ngx_string.h - * Copyright (C) by Igor Sysoev */ -u_char * -ngx_http_echo_strlstrn(u_char *s1, u_char *last, u_char *s2, size_t n) -{ - ngx_uint_t c1, c2; - - c2 = (ngx_uint_t) *s2++; - last -= n; - - do { - do { - if (s1 >= last) { - return NULL; - } - - c1 = (ngx_uint_t) *s1++; - - } while (c1 != c2); - - } while (ngx_strncmp(s1, s2, n) != 0); - - return --s1; -} - - -ngx_int_t -ngx_http_echo_post_request_at_head(ngx_http_request_t *r, - ngx_http_posted_request_t *pr) -{ - dd_enter(); - - if (pr == NULL) { - pr = ngx_palloc(r->pool, sizeof(ngx_http_posted_request_t)); - if (pr == NULL) { - return NGX_ERROR; - } - } - - pr->request = r; - pr->next = r->main->posted_requests; - r->main->posted_requests = pr; - - return NGX_OK; -} - - -u_char * -ngx_http_echo_rebase_path(ngx_pool_t *pool, u_char *src, size_t osize, - size_t *nsize) -{ - u_char *p, *dst; - - if (osize == 0) { - return NULL; - } - - if (src[0] == '/') { - /* being an absolute path already, just add a trailing '\0' */ - *nsize = osize; - - dst = ngx_palloc(pool, *nsize + 1); - if (dst == NULL) { - *nsize = 0; - return NULL; - } - - p = ngx_copy(dst, src, osize); - *p = '\0'; - - return dst; - } - - *nsize = ngx_cycle->prefix.len + osize; - - dst = ngx_palloc(pool, *nsize + 1); - if (dst == NULL) { - *nsize = 0; - return NULL; - } - - p = ngx_copy(dst, ngx_cycle->prefix.data, ngx_cycle->prefix.len); - p = ngx_copy(p, src, osize); - - *p = '\0'; - - return dst; -} - - -ngx_int_t -ngx_http_echo_flush_postponed_outputs(ngx_http_request_t *r) -{ - if (r == r->connection->data && r->postponed) { - /* notify the downstream postpone filter to flush the postponed - * outputs of the current request */ - return ngx_http_output_filter(r, NULL); - } - - /* do nothing */ - return NGX_OK; -} diff --git a/debian/modules/http-echo/src/ngx_http_echo_util.h b/debian/modules/http-echo/src/ngx_http_echo_util.h deleted file mode 100644 index d620d09..0000000 --- a/debian/modules/http-echo/src/ngx_http_echo_util.h +++ /dev/null @@ -1,58 +0,0 @@ - -/* - * Copyright (C) Yichun Zhang (agentzh) - */ - - -#ifndef NGX_HTTP_ECHO_UTIL_H -#define NGX_HTTP_ECHO_UTIL_H - - -#include "ngx_http_echo_module.h" - - -#define ngx_http_echo_strcmp_const(a, b) \ - ngx_strncmp(a, b, sizeof(b) - 1) - - -#define ngx_http_echo_hash_literal(s) \ - ngx_http_echo_hash_str((u_char *) s, sizeof(s) - 1) - - -static ngx_inline ngx_uint_t -ngx_http_echo_hash_str(u_char *src, size_t n) -{ - ngx_uint_t key; - - key = 0; - - while (n--) { - key = ngx_hash(key, *src); - src++; - } - - return key; -} - - -extern ngx_uint_t ngx_http_echo_content_length_hash; - - -ngx_http_echo_ctx_t *ngx_http_echo_create_ctx(ngx_http_request_t *r); -ngx_int_t ngx_http_echo_eval_cmd_args(ngx_http_request_t *r, - ngx_http_echo_cmd_t *cmd, ngx_array_t *computed_args, - ngx_array_t *opts); -ngx_int_t ngx_http_echo_send_header_if_needed(ngx_http_request_t *r, - ngx_http_echo_ctx_t *ctx); -ngx_int_t ngx_http_echo_send_chain_link(ngx_http_request_t *r, - ngx_http_echo_ctx_t *ctx, ngx_chain_t *cl); -ssize_t ngx_http_echo_atosz(u_char *line, size_t n); -u_char *ngx_http_echo_strlstrn(u_char *s1, u_char *last, u_char *s2, size_t n); -ngx_int_t ngx_http_echo_post_request_at_head(ngx_http_request_t *r, - ngx_http_posted_request_t *pr); -u_char *ngx_http_echo_rebase_path(ngx_pool_t *pool, u_char *src, size_t osize, - size_t *nsize); -ngx_int_t ngx_http_echo_flush_postponed_outputs(ngx_http_request_t *r); - - -#endif /* NGX_HTTP_ECHO_UTIL_H */ diff --git a/debian/modules/http-echo/src/ngx_http_echo_var.c b/debian/modules/http-echo/src/ngx_http_echo_var.c deleted file mode 100644 index 138a510..0000000 --- a/debian/modules/http-echo/src/ngx_http_echo_var.c +++ /dev/null @@ -1,110 +0,0 @@ -#ifndef DDEBUG -#define DDEBUG 0 -#endif -#include "ddebug.h" - -#include "ngx_http_echo_var.h" -#include "ngx_http_echo_timer.h" -#include "ngx_http_echo_request_info.h" -#include "ngx_http_echo_foreach.h" - - -static ngx_int_t ngx_http_echo_incr_variable(ngx_http_request_t *r, - ngx_http_variable_value_t *v, uintptr_t data); - - -static ngx_http_variable_t ngx_http_echo_variables[] = { - - { ngx_string("echo_timer_elapsed"), NULL, - ngx_http_echo_timer_elapsed_variable, 0, - NGX_HTTP_VAR_NOCACHEABLE, 0 }, - - { ngx_string("echo_request_method"), NULL, - ngx_http_echo_request_method_variable, 0, - NGX_HTTP_VAR_NOCACHEABLE, 0 }, - - { ngx_string("echo_cacheable_request_uri"), NULL, - ngx_http_echo_cacheable_request_uri_variable, 0, - 0, 0 }, - - { ngx_string("echo_request_uri"), NULL, - ngx_http_echo_request_uri_variable, 0, - 0, 0 }, - - { ngx_string("echo_client_request_method"), NULL, - ngx_http_echo_client_request_method_variable, 0, - NGX_HTTP_VAR_NOCACHEABLE, 0 }, - - { ngx_string("echo_request_body"), NULL, - ngx_http_echo_request_body_variable, 0, - NGX_HTTP_VAR_NOCACHEABLE, 0 }, - - { ngx_string("echo_client_request_headers"), NULL, - ngx_http_echo_client_request_headers_variable, 0, - NGX_HTTP_VAR_NOCACHEABLE, 0 }, - - { ngx_string("echo_it"), NULL, - ngx_http_echo_it_variable, 0, - NGX_HTTP_VAR_NOCACHEABLE, 0 }, - - { ngx_string("echo_incr"), NULL, - ngx_http_echo_incr_variable, 0, - NGX_HTTP_VAR_NOCACHEABLE, 0 }, - - { ngx_string("echo_response_status"), NULL, - ngx_http_echo_response_status_variable, 0, - NGX_HTTP_VAR_NOCACHEABLE, 0 }, - - { ngx_null_string, NULL, NULL, 0, 0, 0 } -}; - - -ngx_int_t -ngx_http_echo_add_variables(ngx_conf_t *cf) -{ - ngx_http_variable_t *var, *v; - - for (v = ngx_http_echo_variables; v->name.len; v++) { - var = ngx_http_add_variable(cf, &v->name, v->flags); - if (var == NULL) { - return NGX_ERROR; - } - - var->get_handler = v->get_handler; - var->data = v->data; - } - - return NGX_OK; -} - - -static ngx_int_t -ngx_http_echo_incr_variable(ngx_http_request_t *r, - ngx_http_variable_value_t *v, uintptr_t data) -{ - ngx_http_echo_ctx_t *ctx; - u_char *p; - - ctx = ngx_http_get_module_ctx(r->main, ngx_http_echo_module); - - if (ctx == NULL) { - return NGX_ERROR; - } - - ctx->counter++; - - p = ngx_palloc(r->pool, NGX_INT_T_LEN); - if (p == NULL) { - return NGX_ERROR; - } - - v->len = ngx_sprintf(p, "%ui", ctx->counter) - p; - v->data = p; - - v->valid = 1; - v->not_found = 0; - v->no_cacheable = 1; - - return NGX_OK; -} - diff --git a/debian/modules/http-echo/src/ngx_http_echo_var.h b/debian/modules/http-echo/src/ngx_http_echo_var.h deleted file mode 100644 index 8b24e02..0000000 --- a/debian/modules/http-echo/src/ngx_http_echo_var.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef ECHO_VAR_H -#define ECHO_VAR_H - -#include "ngx_http_echo_module.h" - -ngx_int_t ngx_http_echo_add_variables(ngx_conf_t *cf); - -#endif /* ECHO_VAR_H */ - diff --git a/debian/modules/http-echo/t/abort-parent.t b/debian/modules/http-echo/t/abort-parent.t deleted file mode 100644 index 6137607..0000000 --- a/debian/modules/http-echo/t/abort-parent.t +++ /dev/null @@ -1,63 +0,0 @@ -# vi:filetype= - -use lib 'lib'; -use Test::Nginx::LWP skip_all => - 'not working at all'; - -plan tests => 2 * blocks(); - -run_tests(); - -__DATA__ - -=== TEST 1: sanity ---- config - location /abort { - echo hello; - echo_flush; - echo_location_async '/foo'; - echo_location_async '/bar'; - echo_location_async '/baz'; - echo world; - echo_flush; - } - - location /proxy { - proxy_pass "http://127.0.0.1:$server_port/sleep?$query_string"; - } - - location /sleep { - echo_sleep $arg_sleep; - echo $arg_echo; - echo_flush; - } - - location /foo { - echo_location '/proxy?sleep=1&echo=foo'; - #echo_flush; - echo_abort_parent; - } - - location /bar { - proxy_pass 'http://127.0.0.1:$server_port/sleep_bar'; - } - - location /baz { - proxy_pass 'http://127.0.0.1:$server_port/sleep_baz'; - } - - location /sleep_bar { - echo_sleep 2; - echo bar; - } - - location /sleep_baz { - echo_sleep 3; - echo baz; - } ---- request - GET /abort ---- response_body -hello -bar - diff --git a/debian/modules/http-echo/t/blocking-sleep.t b/debian/modules/http-echo/t/blocking-sleep.t deleted file mode 100644 index 0bdc6cc..0000000 --- a/debian/modules/http-echo/t/blocking-sleep.t +++ /dev/null @@ -1,156 +0,0 @@ -# vi:filetype= - -use lib 'lib'; -use Test::Nginx::Socket; - -plan tests => 2 * blocks(); - -#$Test::Nginx::LWP::LogLevel = 'debug'; - -run_tests(); - -__DATA__ - -=== TEST 1: sanity ---- config - location /echo { - echo_blocking_sleep 1; - } ---- request - GET /echo ---- response_body - - - -=== TEST 2: fractional delay ---- config - location /echo { - echo_blocking_sleep 0.01; - } ---- request - GET /echo ---- response_body - - - -=== TEST 3: leading echo ---- config - location /echo { - echo before...; - echo_blocking_sleep 0.01; - } ---- request - GET /echo ---- response_body -before... - - - -=== TEST 4: trailing echo ---- config - location /echo { - echo_blocking_sleep 0.01; - echo after...; - } ---- request - GET /echo ---- response_body -after... - - - -=== TEST 5: two echos around sleep ---- config - location /echo { - echo before...; - echo_blocking_sleep 0.01; - echo after...; - } ---- request - GET /echo ---- response_body -before... -after... - - - -=== TEST 6: interleaving sleep and echo ---- config - location /echo { - echo 1; - echo_blocking_sleep 0.01; - echo 2; - echo_blocking_sleep 0.01; - } ---- request - GET /echo ---- response_body -1 -2 - - - -=== TEST 7: interleaving sleep and echo with echo at the end... ---- config - location /echo { - echo 1; - echo_blocking_sleep 0.01; - echo 2; - echo_blocking_sleep 0.01; - echo 3; - } ---- request - GET /echo ---- response_body -1 -2 -3 - - - -=== TEST 8: flush before sleep -we didn't really test the actual effect of "echo_flush" here... -merely checks if it croaks if appears. ---- config - location /flush { - echo hi; - echo_flush; - echo_blocking_sleep 0.01; - echo trees; - } ---- request - GET /flush ---- response_body -hi -trees - - - -=== TEST 9: flush does not increment opcode pointer itself ---- config - location /flush { - echo hi; - echo_flush; - echo trees; - } ---- request - GET /flush ---- response_body -hi -trees - - - -=== TEST 10: blocking sleep by variable ---- config - location ~ ^/sleep/(.+) { - echo before...; - echo_blocking_sleep $1; - echo after...; - } ---- request - GET /sleep/0.01 ---- response_body -before... -after... - diff --git a/debian/modules/http-echo/t/echo-after-body.t b/debian/modules/http-echo/t/echo-after-body.t deleted file mode 100644 index 44c4c72..0000000 --- a/debian/modules/http-echo/t/echo-after-body.t +++ /dev/null @@ -1,261 +0,0 @@ -# vi:filetype= - -use lib 'lib'; -use Test::Nginx::Socket; - -repeat_each(2); - -plan tests => repeat_each() * (2 * blocks() + 1); - -no_long_string(); -log_level('warn'); - -#master_on(); -#workers(1); - -run_tests(); - -__DATA__ - -=== TEST 1: sanity ---- http_config - postpone_output 1; ---- config - location /echo { - echo_after_body hello; - echo world; - } ---- request - GET /echo ---- response_body -world -hello - - - -=== TEST 2: echo after proxy ---- config - location /echo { - echo_after_body hello; - proxy_pass http://127.0.0.1:$server_port$request_uri/more; - } - location /echo/more { - echo world; - } ---- request - GET /echo ---- response_body -world -hello - - - -=== TEST 3: with variables ---- config - location /echo { - echo_after_body $request_method; - echo world; - } ---- request - GET /echo ---- response_body -world -GET - - - -=== TEST 4: w/o args ---- config - location /echo { - echo_after_body; - echo world; - } ---- request - GET /echo ---- response_body eval -"world\n\n" - - - -=== TEST 5: order is not important ---- config - location /reversed { - echo world; - echo_after_body hello; - } ---- request - GET /reversed ---- response_body -world -hello - - - -=== TEST 6: multiple echo_after_body instances ---- config - location /echo { - echo_after_body hello; - echo_after_body world; - echo !; - } ---- request - GET /echo ---- response_body -! -hello -world - - - -=== TEST 7: multiple echo_after_body instances with multiple echo cmds ---- config - location /echo { - echo_after_body hello; - echo_after_body world; - echo i; - echo say; - } ---- request - GET /echo ---- response_body -i -say -hello -world - - - -=== TEST 8: echo-after-body & echo-before-body ---- config - location /mixed { - echo_before_body hello; - echo_after_body world; - echo_before_body hiya; - echo_after_body igor; - echo ////////; - } ---- request - GET /mixed ---- response_body -hello -hiya -//////// -world -igor - - - -=== TEST 9: echo around proxy ---- config - location /echo { - echo_before_body hello; - echo_before_body world; - #echo $scheme://$host:$server_port$request_uri/more; - proxy_pass $scheme://127.0.0.1:$server_port$request_uri/more; - echo_after_body hiya; - echo_after_body igor; - } - location /echo/more { - echo blah; - } ---- request - GET /echo ---- response_body -hello -world -blah -hiya -igor - - - -=== TEST 10: with $echo_response_status ---- config - location /status { - echo_after_body "status: $echo_response_status"; - return 404; - } ---- request - GET /status ---- response_body_like -.*404 Not Found.* -status: 404$ ---- error_code: 404 - - - -=== TEST 11: in subrequests ---- config - location /main { - echo_location_async /hello; - } - location /hello { - echo_after_body 'world!'; - echo 'hello'; - } ---- request - GET /main ---- response_body -hello -world! - - - -=== TEST 12: echo_after_body + gzip ---- config - gzip on; - gzip_min_length 1; - location /main { - echo_after_body 'world!'; - echo_duplicate 1024 'hello'; - } ---- request - GET /main ---- response_body_like -hello ---- SKIP - - - -=== TEST 13: echo_after_body + proxy output ---- config - #gzip on; - #gzip_min_length 1; - location /main { - echo_after_body 'world'; - proxy_pass http://127.0.0.1:$server_port/foo; - } - location /foo { - echo_duplicate 10 hello; - } ---- request - GET /main ---- response_body_like -^(?:hello){10}world$ - - - -=== TEST 14: in subrequests (we get last_in_chain set properly) ---- config - location /main { - echo_location_async /hello; - } - location /hello { - echo 'hello'; - echo_after_body 'world!'; - body_filter_by_lua ' - local eof = ngx.arg[2] - if eof then - print("lua: eof found in body") - end - '; - } ---- request - GET /main ---- response_body -hello -world! ---- log_level: notice ---- error_log -lua: eof found in body - diff --git a/debian/modules/http-echo/t/echo-before-body.t b/debian/modules/http-echo/t/echo-before-body.t deleted file mode 100644 index 1513184..0000000 --- a/debian/modules/http-echo/t/echo-before-body.t +++ /dev/null @@ -1,278 +0,0 @@ -# vi:filetype= - -use lib 'lib'; -use Test::Nginx::Socket; - -plan tests => 2 * blocks(); - -#$Test::Nginx::LWP::LogLevel = 'debug'; - -run_tests(); - -__DATA__ - -=== TEST 1: sanity ---- config - location /echo { - echo_before_body hello; - echo world; - } ---- request - GET /echo ---- response_body -hello -world - - - -=== TEST 2: echo before proxy ---- config - location /echo { - echo_before_body hello; - proxy_pass $scheme://127.0.0.1:$server_port$request_uri/more; - } - location /echo/more { - echo world; - } ---- request - GET /echo ---- response_body -hello -world - - - -=== TEST 3: with variables ---- config - location /echo { - echo_before_body $request_method; - echo world; - } ---- request - GET /echo ---- response_body -GET -world - - - -=== TEST 4: w/o args ---- config - location /echo { - echo_before_body; - echo world; - } ---- request - GET /echo ---- response_body eval -"\nworld\n" - - - -=== TEST 5: order is not important ---- config - location /reversed { - echo world; - echo_before_body hello; - } ---- request - GET /reversed ---- response_body -hello -world - - - -=== TEST 6: multiple echo_before_body instances ---- config - location /echo { - echo_before_body hello; - echo_before_body world; - echo !; - } ---- request - GET /echo ---- response_body -hello -world -! - - - -=== TEST 7: multiple echo_before_body instances with multiple echo cmds ---- config - location /echo { - echo_before_body hello; - echo_before_body world; - echo i; - echo say; - } ---- request - GET /echo ---- response_body -hello -world -i -say - - - -=== TEST 8: with $echo_response_status ---- config - location /status { - echo_before_body "status: $echo_response_status"; - return 404; - } ---- request - GET /status ---- response_body_like -status: 404 -.*404 Not Found.*$ ---- error_code: 404 - - - -=== TEST 9: $echo_response_status in echo_before_body in subrequests ---- config - location /main { - echo_location '/status?val=403'; - echo_location '/status?val=500'; - } - location /status { - if ($arg_val = 500) { - echo_before_body "status: $echo_response_status"; - return 500; - break; - } - if ($arg_val = 403) { - echo_before_body "status: $echo_response_status"; - return 403; - break; - } - return 200; - } ---- request - GET /main ---- response_body_like -^status: 403.*?status: 500.*$ - - - -=== TEST 10: echo -n ---- config - location /echo { - echo_before_body -n hello; - echo_before_body -n world; - echo ==; - } ---- request - GET /echo ---- response_body -helloworld== - - - -=== TEST 11: echo a -n ---- config - location /echo { - echo_before_body a -n hello; - echo_before_body b -n world; - echo ==; - } ---- request - GET /echo ---- response_body -a -n hello -b -n world -== - - - -=== TEST 12: -n in a var ---- config - location /echo { - set $opt -n; - echo_before_body $opt hello; - echo_before_body $opt world; - echo ==; - } ---- request - GET /echo ---- response_body --n hello --n world -== - - - -=== TEST 13: -n only ---- config - location /echo { - echo_before_body -n; - echo_before_body -n; - echo ==; - } ---- request - GET /echo ---- response_body -== - - - -=== TEST 14: -n with an empty string ---- config - location /echo { - echo_before_body -n ""; - set $empty ""; - echo_before_body -n $empty; - echo ==; - } ---- request - GET /echo ---- response_body -== - - - -=== TEST 15: -- -n ---- config - location /echo { - echo_before_body -- -n hello; - echo_before_body -- -n world; - echo ==; - } ---- request - GET /echo ---- response_body --n hello --n world -== - - - -=== TEST 16: -n -n ---- config - location /echo { - echo_before_body -n -n hello; - echo_before_body -n -n world; - echo ==; - } ---- request - GET /echo ---- response_body -helloworld== - - - -=== TEST 17: -n -- -n ---- config - location /echo { - echo_before_body -n -- -n hello; - echo_before_body -n -- -n world; - echo ==; - } ---- request - GET /echo ---- response_body --n hello-n world== - diff --git a/debian/modules/http-echo/t/echo-duplicate.t b/debian/modules/http-echo/t/echo-duplicate.t deleted file mode 100644 index 82b6725..0000000 --- a/debian/modules/http-echo/t/echo-duplicate.t +++ /dev/null @@ -1,89 +0,0 @@ -# vi:filetype= - -use lib 'lib'; -use Test::Nginx::Socket; - -plan tests => 2 * blocks(); - -#$Test::Nginx::LWP::LogLevel = 'debug'; - -run_tests(); - -__DATA__ - -=== TEST 1: sanity ---- config - location /dup { - echo_duplicate 3 a; - } ---- request - GET /dup ---- response_body: aaa - - - -=== TEST 2: abc abc ---- config - location /dup { - echo_duplicate 2 abc; - } ---- request - GET /dup ---- response_body: abcabc - - - -=== TEST 3: big size with underscores ---- config - location /dup { - echo_duplicate 10_000 A; - } ---- request - GET /dup ---- response_body eval -'A' x 10_000 - - - -=== TEST 4: 0 duplicate 0 empty strings ---- config - location /dup { - echo_duplicate 0 ""; - } ---- request - GET /dup ---- response_body - - - -=== TEST 5: 0 duplicate non-empty strings ---- config - location /dup { - echo_duplicate 0 "abc"; - } ---- request - GET /dup ---- response_body - - - -=== TEST 6: duplication of empty strings ---- config - location /dup { - echo_duplicate 2 ""; - } ---- request - GET /dup ---- response_body - - - -=== TEST 7: sanity (HEAD) ---- config - location /dup { - echo_duplicate 3 a; - } ---- request - HEAD /dup ---- response_body - diff --git a/debian/modules/http-echo/t/echo-timer.t b/debian/modules/http-echo/t/echo-timer.t deleted file mode 100644 index 712524d..0000000 --- a/debian/modules/http-echo/t/echo-timer.t +++ /dev/null @@ -1,107 +0,0 @@ -# vi:filetype= - -use lib 'lib'; -use Test::Nginx::Socket; - -plan tests => 2 * blocks(); - -run_tests(); - -__DATA__ - -=== TEST 1: timer without explicit reset ---- config - location /timer { - echo_sleep 0.03; - echo "elapsed $echo_timer_elapsed sec."; - } ---- request - GET /timer ---- response_body_like -^elapsed 0\.0(2[6-9]|3[0-6]) sec\.$ - - - -=== TEST 2: timer without explicit reset and sleep ---- config - location /timer { - echo "elapsed $echo_timer_elapsed sec."; - } ---- request - GET /timer ---- response_body_like -^elapsed 0\.00[0-5] sec\.$ - - - -=== TEST 3: timing accumulated sleeps ---- config - location /timer { - echo_sleep 0.03; - echo_sleep 0.02; - echo "elapsed $echo_timer_elapsed sec."; - } ---- request - GET /timer ---- response_body_like -^elapsed 0\.0(4[6-9]|5[0-6]) sec\.$ - - - -=== TEST 4: timer with explicit reset but without sleep ---- config - location /timer { - echo_reset_timer; - echo "elapsed $echo_timer_elapsed sec."; - } ---- request - GET /timer ---- response_body_like -^elapsed 0\.00[0-5] sec\.$ - - - -=== TEST 5: reset timer between sleeps ---- config - location /timer { - echo_sleep 0.02; - echo "elapsed $echo_timer_elapsed sec."; - echo_reset_timer; - echo_sleep 0.03; - echo "elapsed $echo_timer_elapsed sec."; - } ---- request - GET /timer ---- response_body_like -^elapsed 0\.0(1[6-9]|2[0-6]) sec\. -elapsed 0\.0(2[6-9]|3[0-6]) sec\.$ - - - -=== TEST 6: reset timer between blocking sleeps ---- config - location /timer { - echo_blocking_sleep 0.02; - echo "elapsed $echo_timer_elapsed sec."; - echo_reset_timer; - echo_blocking_sleep 0.03; - echo "elapsed $echo_timer_elapsed sec."; - } ---- request - GET /timer ---- response_body_like -^elapsed 0\.0(1[6-9]|2[0-9]) sec\. -elapsed 0\.0(2[6-9]|3[0-6]) sec\.$ - - - -=== TEST 7: timer without explicit reset ---- config - location = /timer { - return 200 "$echo_timer_elapsed"; - } ---- request - GET /timer ---- response_body_like chop -^0(\.0\d*)$ - diff --git a/debian/modules/http-echo/t/echo.t b/debian/modules/http-echo/t/echo.t deleted file mode 100644 index b181259..0000000 --- a/debian/modules/http-echo/t/echo.t +++ /dev/null @@ -1,416 +0,0 @@ -# vi:filetype= - -use lib 'lib'; -use Test::Nginx::Socket; - -repeat_each(2); - -plan tests => repeat_each() * (2 * blocks() + 6); - -#$Test::Nginx::LWP::LogLevel = 'debug'; - -run_tests(); - -__DATA__ - -=== TEST 1: sanity ---- config - location /echo { - echo hello; - } ---- request - GET /echo ---- response_body -hello - - - -=== TEST 2: multiple args ---- config - location /echo { - echo say hello world; - } ---- request - GET /echo ---- response_body -say hello world - - - -=== TEST 3: multiple directive instances ---- config - location /echo { - echo say that; - echo hello; - echo world !; - } ---- request - GET /echo ---- response_body -say that -hello -world ! - - - -=== TEST 4: echo without arguments ---- config - location /echo { - echo; - echo; - } ---- request - GET /echo ---- response_body eval -"\n\n" - - - -=== TEST 5: escaped newline ---- config - location /echo { - echo "hello\nworld"; - } ---- request - GET /echo ---- response_body -hello -world - - - -=== TEST 6: escaped tabs and \r and " wihtin "..." ---- config - location /echo { - echo "i say \"hello\tworld\"\r"; - } ---- request - GET /echo ---- response_body eval: "i say \"hello\tworld\"\r\n" - - - -=== TEST 7: escaped tabs and \r and " in single quotes ---- config - location /echo { - echo 'i say \"hello\tworld\"\r'; - } ---- request - GET /echo ---- response_body eval: "i say \"hello\tworld\"\r\n" - - - -=== TEST 8: escaped tabs and \r and " w/o any quotes ---- config - location /echo { - echo i say \"hello\tworld\"\r; - } ---- request - GET /echo ---- response_body eval: "i say \"hello\tworld\"\r\n" - - - -=== TEST 9: escaping $ -As of Nginx 0.8.20, there's still no way to escape the '$' character. ---- config - location /echo { - echo \$; - } ---- request - GET /echo ---- response_body -$ ---- SKIP - - - -=== TEST 10: XSS ---- config - location /blah { - echo_duplicate 1 "$arg_callback("; - echo_location_async "/data?$uri"; - echo_duplicate 1 ")"; - } - location /data { - echo_duplicate 1 '{"dog":"$query_string"}'; - } ---- request - GET /blah/9999999.json?callback=ding1111111 ---- response_body chomp -ding1111111({"dog":"/blah/9999999.json"}) - - - -=== TEST 11: XSS - filter version ---- config - location /blah { - echo_before_body "$arg_callback("; - - echo_duplicate 1 '{"dog":"$uri"}'; - - echo_after_body ")"; - } ---- request - GET /blah/9999999.json?callback=ding1111111 ---- response_body -ding1111111( -{"dog":"/blah/9999999.json"}) - - - -=== TEST 12: if ---- config -location /first { - echo "before"; - echo_location_async /second $request_uri; - echo "after"; -} - -location = /second { - if ($query_string ~ '([^?]+)') { - set $memcached_key $1; # needing this to be keyed on the request_path, not the entire uri - echo $memcached_key; - } -} ---- request - GET /first/9999999.json?callback=ding1111111 ---- response_body -before -/first/9999999.json -after - - - -=== TEST 13: echo -n ---- config - location /echo { - echo -n hello; - echo -n world; - } ---- request - GET /echo ---- response_body chop -helloworld - - - -=== TEST 14: echo a -n ---- config - location /echo { - echo a -n hello; - echo b -n world; - } ---- request - GET /echo ---- response_body -a -n hello -b -n world - - - -=== TEST 15: -n in a var ---- config - location /echo { - set $opt -n; - echo $opt hello; - echo $opt world; - } ---- request - GET /echo ---- response_body --n hello --n world - - - -=== TEST 16: -n only ---- config - location /echo { - echo -n; - echo -n; - } ---- request - GET /echo ---- response_body chop - - - -=== TEST 17: -n with an empty string ---- config - location /echo { - echo -n ""; - set $empty ""; - echo -n $empty; - } ---- request - GET /echo ---- response_body chop - - - -=== TEST 18: -- -n ---- config - location /echo { - echo -- -n hello; - echo -- -n world; - } ---- request - GET /echo ---- response_body --n hello --n world - - - -=== TEST 19: -n -n ---- config - location /echo { - echo -n -n hello; - echo -n -n world; - } ---- request - GET /echo ---- response_body chop -helloworld - - - -=== TEST 20: -n -- -n ---- config - location /echo { - echo -n -- -n hello; - echo -n -- -n world; - } ---- request - GET /echo ---- response_body chop --n hello-n world - - - -=== TEST 21: proxy ---- config - location /main { - proxy_pass http://127.0.0.1:$server_port/echo; - } - location /echo { - echo hello; - echo world; - } ---- request - GET /main ---- response_headers -!Content-Length ---- response_body -hello -world - - - -=== TEST 22: if is evil ---- config - location /test { - set $a 3; - set_by_lua $a ' - if ngx.var.a == "3" then - return 4 - end - '; - echo $a; - } ---- request - GET /test ---- response_body -4 ---- SKIP - - - -=== TEST 23: HEAD ---- config - location /echo { - echo hello; - echo world; - } ---- request - HEAD /echo ---- response_body - - - -=== TEST 24: POST ---- config - location /echo { - echo hello; - echo world; - } ---- pipelined_requests eval -["POST /echo -blah blah", "POST /echo -foo bar baz"] ---- response_body eval -["hello\nworld\n","hello\nworld\n"] - - - -=== TEST 25: POST ---- config - location /echo { - echo_sleep 0.001; - echo hello; - echo world; - } ---- pipelined_requests eval -["POST /echo -blah blah", "POST /echo -foo bar baz"] ---- response_body eval -["hello\nworld\n","hello\nworld\n"] - - - -=== TEST 26: empty arg after -n (github issue #33) ---- config - location = /t { - set $empty ""; - echo -n $empty hello world; - } ---- request - GET /t ---- response_body chop - hello world - - - -=== TEST 27: image filter ---- config - location = /gif { - empty_gif; - } - - location = /t { - default_type image/gif; - image_filter resize 10 10; - set $gif1 ''; - set $gif2 ''; - rewrite_by_lua ' - local res = ngx.location.capture("/gif") - local data = res.body - ngx.var.gif1 = string.sub(data, 1, #data - 1) - ngx.var.gif2 = string.sub(data, #data) - '; - echo -n $gif1; - echo -n $gif2; - } ---- request - GET /t ---- stap -F(ngx_http_image_header_filter) { - println("image header filter") -} ---- stap_out -image header filter ---- response_body_like: . - diff --git a/debian/modules/http-echo/t/exec.t b/debian/modules/http-echo/t/exec.t deleted file mode 100644 index b7c1308..0000000 --- a/debian/modules/http-echo/t/exec.t +++ /dev/null @@ -1,228 +0,0 @@ -# vi:filetype= - -use lib 'lib'; -use Test::Nginx::Socket; - -repeat_each(2); - -plan tests => repeat_each() * (2 * blocks() + 1); - -#$Test::Nginx::LWP::LogLevel = 'debug'; - -run_tests(); - -__DATA__ - -=== TEST 1: exec normal location ---- config - location /main { - echo_exec /bar; - echo end; - } - location = /bar { - echo "$echo_request_uri:"; - echo bar; - } ---- request - GET /main ---- response_body -/bar: -bar - - - -=== TEST 2: location with args (inlined in uri) ---- config - location /main { - echo_exec /bar?a=32; - echo end; - } - location /bar { - echo "a: [$arg_a]"; - } ---- request - GET /main ---- response_body -a: [32] - - - -=== TEST 3: location with args (in separate arg) ---- config - location /main { - echo_exec /bar a=56; - echo end; - } - location /bar { - echo "a: [$arg_a]"; - } ---- request - GET /main ---- response_body -a: [56] - - - -=== TEST 4: exec named location ---- config - location /main { - echo_exec @bar; - echo end; - } - location @bar { - echo bar; - } ---- request - GET /main ---- response_body -bar - - - -=== TEST 5: query string ignored for named locations ---- config - location /main { - echo_exec @bar?a=32; - echo end; - } - location @bar { - echo "a: [$arg_a]"; - } ---- request - GET /main ---- response_body -a: [] ---- error_log -querystring a=32 ignored when exec'ing named location @bar - - - -=== TEST 6: query string ignored for named locations ---- config - location /foo { - echo_exec @bar; - } - location @bar { - echo "uri: [$echo_request_uri]"; - } ---- request - GET /foo ---- response_body -uri: [/foo] - - - -=== TEST 7: exec(named location) in subrequests ---- config - location /entry { - echo_location /foo; - echo_sleep 0.001; - echo_location /foo2; - } - location /foo { - echo_exec @bar; - } - location /foo2 { - echo_exec @bar; - } - - location @bar { - proxy_pass http://127.0.0.1:$server_port/bar; - } - location /bar { - echo_sleep 0.01; - echo hello; - } ---- request - GET /entry ---- response_body -hello -hello - - - -=== TEST 8: exec(normal loctions) in subrequests ---- config - location /entry { - echo_location /foo; - echo_sleep 0.001; - echo_location /foo2; - } - location /foo { - echo_exec /baz; - } - location /foo2 { - echo_exec /baz; - } - - location /baz { - proxy_pass http://127.0.0.1:$server_port/bar; - } - location /bar { - echo_sleep 0.01; - echo hello; - } ---- request - GET /entry ---- response_body -hello -hello - - - -=== TEST 9: exec should clear ctx ---- config - location @bar { - echo hello; - echo world; - echo heh; - } - location /foo { - #echo_sleep 0.001; - echo_reset_timer; - echo_exec @bar; - } ---- request - GET /foo ---- response_body -hello -world -heh - - - -=== TEST 10: reset ctx ---- config - location @proxy { - rewrite_by_lua return; - echo hello; - } - location /main { - rewrite_by_lua return; - echo_exec @proxy; - } ---- request - GET /main ---- response_body -hello - - - -=== TEST 11: yield before exec ---- config - location @bar { - echo hello; - echo world; - echo heh; - } - location /foo { - echo_sleep 0.001; - echo_exec @bar; - } ---- request - GET /foo ---- response_body -hello -world -heh - diff --git a/debian/modules/http-echo/t/filter-used.t b/debian/modules/http-echo/t/filter-used.t deleted file mode 100644 index 2835270..0000000 --- a/debian/modules/http-echo/t/filter-used.t +++ /dev/null @@ -1,59 +0,0 @@ -# vi:filetype= - -use lib 'lib'; -use Test::Nginx::Socket; - -repeat_each(2); - -plan tests => repeat_each() * (3 * blocks()); - -no_long_string(); -log_level('warn'); - -#master_on(); -#workers(1); - -run_tests(); - -__DATA__ - -=== TEST 1: filter indeed used ---- http_config - postpone_output 1; ---- config - location /echo { - echo_after_body hello; - echo world; - } ---- request - GET /echo ---- stap -F(ngx_http_echo_header_filter) { - println("echo header filter called") -} ---- stap_out -echo header filter called ---- response_body -world -hello - - - -=== TEST 2: filter not used ---- http_config - postpone_output 1; ---- config - location /echo { - #echo_after_body hello; - echo world; - } ---- request - GET /echo ---- stap -F(ngx_http_echo_header_filter) { - println("echo header filter called") -} ---- stap_out ---- response_body -world - diff --git a/debian/modules/http-echo/t/foreach-split.t b/debian/modules/http-echo/t/foreach-split.t deleted file mode 100644 index 266a701..0000000 --- a/debian/modules/http-echo/t/foreach-split.t +++ /dev/null @@ -1,283 +0,0 @@ -# vi:filetype= - -use lib 'lib'; -use Test::Nginx::Socket; - -repeat_each(2); - -plan tests => repeat_each() * 2 * blocks(); - -#$Test::Nginx::LWP::LogLevel = 'debug'; - -run_tests(); - -__DATA__ - -=== TEST 1: sanity ---- config - location /main { - echo_foreach_split '&' $query_string; - echo_location_async $echo_it; - echo '/* end */'; - echo_end; - } - location /sub/1.css { - echo "body { font-size: 12pt; }"; - } - location /sub/2.css { - echo "table { color: 'red'; }"; - } ---- request - GET /main?/sub/1.css&/sub/2.css ---- response_body -body { font-size: 12pt; } -/* end */ -table { color: 'red'; } -/* end */ - - - -=== TEST 2: split in a url argument (echo_location_async) ---- config - location /main_async { - echo_foreach_split ',' $arg_cssfiles; - echo_location_async $echo_it; - echo_end; - } - location /foo.css { - echo foo; - } - location /bar.css { - echo bar; - } - location /baz.css { - echo baz; - } ---- request - GET /main_async?cssfiles=/foo.css,/bar.css,/baz.css ---- response_body -foo -bar -baz - - - -=== TEST 3: split in a url argument (echo_location) ---- config - location /main_sync { - echo_foreach_split ',' $arg_cssfiles; - echo_location $echo_it; - echo_end; - } - location /foo.css { - echo foo; - } - location /bar.css { - echo bar; - } - location /baz.css { - echo baz; - } ---- request - GET /main_sync?cssfiles=/foo.css,/bar.css,/baz.css ---- response_body -foo -bar -baz ---- SKIP - - - -=== TEST 4: empty loop ---- config - location /main { - echo "start"; - echo_foreach_split ',' $arg_cssfiles; - echo_end; - echo "end"; - } ---- request - GET /main?cssfiles=/foo.css,/bar.css,/baz.css ---- response_body -start -end - - - -=== TEST 5: trailing delimiter ---- config - location /main_t { - echo_foreach_split ',' $arg_cssfiles; - echo_location_async $echo_it; - echo_end; - } - location /foo.css { - echo foo; - } ---- request - GET /main_t?cssfiles=/foo.css, ---- response_body -foo - - - -=== TEST 6: multi-char delimiter ---- config - location /main_sleep { - echo_foreach_split '-a-' $arg_list; - echo $echo_it; - echo_end; - } ---- request - GET /main_sleep?list=foo-a-bar-a-baz ---- error_code: 500 ---- response_body_like: 500 Internal Server Error - - - -=== TEST 7: multi-char delimiter (the right way) ---- config - location /main_sleep { - echo_foreach_split -- '-a-' $arg_list; - echo $echo_it; - echo_end; - } ---- request - GET /main_sleep?list=foo-a-bar-a-baz ---- response_body -foo -bar -baz - - - -=== TEST 8: loop with sleep ---- config - location /main_sleep { - echo_foreach_split '-' $arg_list; - echo_sleep 0.001; - echo $echo_it; - echo_end; - } ---- request - GET /main_sleep?list=foo-a-bar-A-baz ---- response_body -foo -a -bar -A -baz - - - -=== TEST 9: empty ---- config - location /merge { - default_type 'text/javascript'; - echo_foreach_split '&' $query_string; - echo "/* JS File $echo_it */"; - echo_location_async $echo_it; - echo; - echo_end; - } ---- request - GET /merge ---- response_body - - - -=== TEST 10: single & ---- config - location /merge { - default_type 'text/javascript'; - echo_foreach_split '&' $query_string; - echo "/* JS File $echo_it */"; - echo_location_async $echo_it; - echo; - echo_end; - } ---- request - GET /merge?& ---- response_body - - - -=== TEST 11: pure &'s ---- config - location /merge { - default_type 'text/javascript'; - echo_foreach_split '&' $query_string; - echo "/* JS File $echo_it */"; - echo_location_async $echo_it; - echo; - echo_end; - } ---- request - GET /merge?&&& ---- response_body - - - -=== TEST 12: pure & and spaces -TODO: needs to uri_decode $echo_it... ---- config - location /merge { - default_type 'text/javascript'; - echo_foreach_split '&' $query_string; - echo "/* JS File $echo_it */"; - echo_location_async $echo_it; - echo; - echo_end; - } ---- request - GET /merge?&%20&%20& ---- response_body ---- SKIP - - - -=== TEST 13: multiple foreach_split ---- config - location /multi { - echo_foreach_split '&' $query_string; - echo [$echo_it]; - echo_end; - - echo '...'; - - echo_foreach_split '-' $query_string; - echo [$echo_it]; - echo_end; - } ---- request - GET /multi?a-b&c-d ---- response_body -[a-b] -[c-d] -... -[a] -[b&c] -[d] - - - -=== TEST 14: github issue #2: setting a variable from $echo_it results to crashing ---- config -location = /getFile { - set $filelist "a,b,c"; - echo_foreach_split ',' $filelist; - set $file $echo_it; - echo_subrequest GET '/getFile2' -q 'sha256=$file'; - echo_end; -} - -location = /getFile2 { - echo "sha256: $arg_sha256"; -} ---- request - GET /getFile ---- response_body -sha256: -sha256: -sha256: - diff --git a/debian/modules/http-echo/t/gzip.t b/debian/modules/http-echo/t/gzip.t deleted file mode 100644 index 61eb4f6..0000000 --- a/debian/modules/http-echo/t/gzip.t +++ /dev/null @@ -1,31 +0,0 @@ -# vi:filetype= - -use lib 'lib'; -use Test::Nginx::Socket; - -repeat_each(1); - -plan tests => repeat_each() * 2 * blocks(); - -#$Test::Nginx::LWP::LogLevel = 'debug'; - -run_tests(); - -__DATA__ - -=== TEST 1: sanity ---- config - location /gzip { - gzip on; - gzip_min_length 10; - gzip_types text/plain; - - echo_duplicate 1000 hello; - } ---- request - GET /gzip ---- more_headers -Accept-Encoding: gzip ---- response_headers -Content-Encoding: gzip ---- timeout: 20 diff --git a/debian/modules/http-echo/t/if.t b/debian/modules/http-echo/t/if.t deleted file mode 100644 index 054ec43..0000000 --- a/debian/modules/http-echo/t/if.t +++ /dev/null @@ -1,150 +0,0 @@ -# vi:filetype= - -use lib 'lib'; -use Test::Nginx::Socket; - -plan tests => 2 * blocks(); - -#$Test::Nginx::LWP::LogLevel = 'debug'; - -run_tests(); - -__DATA__ - -=== TEST 1: sanity (hit) ---- config - location ^~ /if { - set $res miss; - if ($arg_val ~* '^a') { - set $res hit; - echo $res; - } - echo $res; - } ---- request - GET /if?val=abc ---- response_body -hit - - - -=== TEST 2: sanity (miss) ---- config - location ^~ /if { - set $res miss; - if ($arg_val ~* '^a') { - set $res hit; - echo $res; - } - echo $res; - } ---- request - GET /if?val=bcd ---- response_body -miss - - - -=== TEST 3: proxy in if (hit) ---- config - location ^~ /if { - set $res miss; - if ($arg_val ~* '^a') { - set $res hit; - proxy_pass $scheme://127.0.0.1:$server_port/foo?res=$res; - } - proxy_pass $scheme://127.0.0.1:$server_port/foo?res=$res; - } - location /foo { - echo "res = $arg_res"; - } ---- request - GET /if?val=abc ---- response_body -res = hit - - - -=== TEST 4: proxy in if (miss) ---- config - location ^~ /if { - set $res miss; - if ($arg_val ~* '^a') { - set $res hit; - proxy_pass $scheme://127.0.0.1:$server_port/foo?res=$res; - } - proxy_pass $scheme://127.0.0.1:$server_port/foo?res=$res; - } - location /foo { - echo "res = $arg_res"; - } ---- request - GET /if?val=bcd ---- response_body -res = miss - - - -=== TEST 5: if too long url (hit) ---- config - location /foo { - if ($request_uri ~ '.{20,}') { - echo too long; - } - echo ok; - } ---- request - GET /foo?a=12345678901234567890 ---- response_body -too long - - - -=== TEST 6: if too long url (miss) ---- config - location /foo { - if ($request_uri ~ '.{20,}') { - echo too long; - } - echo ok; - } ---- request - GET /foo?a=1234567890 ---- response_body -ok - - - -=== TEST 7: echo should be inherited by if blocks ---- config - location /foo { - if ($uri ~ 'foo') { - } - echo ok; - } ---- request - GET /foo ---- response_body -ok - - - -=== TEST 8: echo_after_body and echo_before_body should be inherited by if blocks ---- config - location /foo { - if ($uri ~ 'foo') { - } - echo_before_body -n 'hello'; - echo_location /comma; - echo_after_body 'world'; - } - - location = /comma { - internal; - echo -n ', '; - } ---- request - GET /foo ---- response_body -hello, world - diff --git a/debian/modules/http-echo/t/incr.t b/debian/modules/http-echo/t/incr.t deleted file mode 100644 index 8ad6d98..0000000 --- a/debian/modules/http-echo/t/incr.t +++ /dev/null @@ -1,32 +0,0 @@ -# vi:filetype= - -use lib 'lib'; -use Test::Nginx::Socket; - -plan tests => 2 * blocks(); - -#$Test::Nginx::LWP::LogLevel = 'debug'; - -run_tests(); - -__DATA__ - -=== TEST 1: sanity ---- config - location /main { - echo "main pre: $echo_incr"; - echo_location_async /sub; - echo_location_async /sub; - echo "main post: $echo_incr"; - } - location /sub { - echo "sub: $echo_incr"; - } ---- request - GET /main ---- response_body -main pre: 1 -sub: 3 -sub: 4 -main post: 2 - diff --git a/debian/modules/http-echo/t/location-async.t b/debian/modules/http-echo/t/location-async.t deleted file mode 100644 index 3494516..0000000 --- a/debian/modules/http-echo/t/location-async.t +++ /dev/null @@ -1,439 +0,0 @@ -# vi:filetype= - -use lib 'lib'; -use Test::Nginx::Socket; - -repeat_each(2); - -plan tests => repeat_each() * (2 * blocks() + 1); - -run_tests(); - -__DATA__ - -=== TEST 1: sanity ---- config - location /main { - echo_location_async /sub; - } - location /sub { - echo hello; - } ---- request - GET /main ---- response_body -hello - - - -=== TEST 2: trailing echo ---- config - location /main { - echo_location_async /sub; - echo after subrequest; - } - location /sub { - echo hello; - } ---- request - GET /main ---- response_body -hello -after subrequest - - - -=== TEST 3: leading echo ---- config - location /main { - echo before subrequest; - echo_location_async /sub; - } - location /sub { - echo hello; - } ---- request - GET /main ---- response_body -before subrequest -hello - - - -=== TEST 4: leading & trailing echo ---- config - location /main { - echo before subrequest; - echo_location_async /sub; - echo after subrequest; - } - location /sub { - echo hello; - } ---- request - GET /main ---- response_body -before subrequest -hello -after subrequest - - - -=== TEST 5: multiple subrequests ---- config - location /main { - echo before sr 1; - echo_location_async /sub; - echo after sr 1; - echo before sr 2; - echo_location_async /sub; - echo after sr 2; - } - location /sub { - echo hello; - } ---- request - GET /main ---- response_body -before sr 1 -hello -after sr 1 -before sr 2 -hello -after sr 2 - - - -=== TEST 6: timed multiple subrequests (blocking sleep) ---- config - location /main { - echo_reset_timer; - echo_location_async /sub1; - echo_location_async /sub2; - echo "took $echo_timer_elapsed sec for total."; - } - location /sub1 { - echo_blocking_sleep 0.02; - echo hello; - } - location /sub2 { - echo_blocking_sleep 0.01; - echo world; - } - ---- request - GET /main ---- response_body_like -^hello -world -took 0\.00[0-5] sec for total\.$ - - - -=== TEST 7: timed multiple subrequests (non-blocking sleep) ---- config - location /main { - echo_reset_timer; - echo_location_async /sub1; - echo_location_async /sub2; - echo "took $echo_timer_elapsed sec for total."; - } - location /sub1 { - echo_sleep 0.02; - echo hello; - } - location /sub2 { - echo_sleep 0.01; - echo world; - } - ---- request - GET /main ---- response_body_like -^hello -world -took 0\.00[0-5] sec for total\.$ - - - -=== TEST 8: location with args ---- config - location /main { - echo_location_async /sub 'foo=Foo&bar=Bar'; - } - location /sub { - echo $arg_foo $arg_bar; - } ---- request - GET /main ---- response_body -Foo Bar - - - -=== TEST 9: encoded chars in query strings ---- config - location /main { - echo_location_async /sub 'foo=a%20b&bar=Bar'; - } - location /sub { - echo $arg_foo $arg_bar; - } ---- request - GET /main ---- response_body -a%20b Bar - - - -=== TEST 10: UTF-8 chars in query strings ---- config - location /main { - echo_location_async /sub 'foo=你好'; - } - location /sub { - echo $arg_foo; - } ---- request - GET /main ---- response_body -你好 - - - -=== TEST 11: encoded chars in location url ---- config - location /main { - echo_location_async /sub%31 'foo=Foo&bar=Bar'; - } - location /sub%31 { - echo 'sub%31'; - } - location /sub1 { - echo 'sub1'; - } ---- request - GET /main ---- response_body -sub1 - - - -=== TEST 12: querystring in url ---- config - location /main { - echo_location_async /sub?foo=Foo&bar=Bar; - } - location /sub { - echo $arg_foo $arg_bar; - } ---- request - GET /main ---- response_body -Foo Bar - - - -=== TEST 13: querystring in url *AND* an explicit querystring ---- config - location /main { - echo_location_async /sub?foo=Foo&bar=Bar blah=Blah; - } - location /sub { - echo $arg_foo $arg_bar $arg_blah; - } ---- request - GET /main ---- response_body - Blah - - - -=== TEST 14: explicit flush in main request -flush won't really flush the buffer... ---- config - location /main_flush { - echo 'pre main'; - echo_location_async /sub; - echo 'post main'; - echo_flush; - } - - location /sub { - echo_sleep 0.02; - echo 'sub'; - } ---- request - GET /main_flush ---- response_body -pre main -sub -post main - - - -=== TEST 15: no varaiable inheritance ---- config - location /main { - echo $echo_cacheable_request_uri; - echo_location_async /sub; - echo_location_async /sub2; - } - location /sub { - echo $echo_cacheable_request_uri; - } - location /sub2 { - echo $echo_cacheable_request_uri; - } - ---- request - GET /main ---- response_body -/main -/sub -/sub2 - - - -=== TEST 16: unsafe uri ---- config - location /unsafe { - echo_location_async '/../foo'; - } ---- request - GET /unsafe ---- stap2 -F(ngx_http_send_header) { - printf("send header on req %p (header sent: %d)\n", $r, $r->header_sent) - print_ubacktrace() -} ---- ignore_response ---- error_log -echo_location_async sees unsafe uri: "/../foo" ---- no_error_log -[error] -[alert] - - - -=== TEST 17: access/deny (access phase handlers skipped in subrequests) ---- config - location /main { - echo_location_async /denied; - } - location /denied { - deny all; - echo No no no; - } ---- request - GET /main ---- error_code: 200 ---- response_body -No no no - - - -=== TEST 18: rewrite is honored. ---- config - location /main { - echo_location_async /rewrite; - } - location /rewrite { - rewrite ^ /foo break; - echo $uri; - } ---- request - GET /main ---- response_body -/foo - - - -=== TEST 19: let subrequest to read the main request's request body ---- SKIP ---- config - location /main { - echo_location_async /sub; - } - location /sub { - echo_read_request_body; - echo_request_body; - } ---- request -POST /main -hello, body! ---- response_body chomp -hello, body! - - - -=== TEST 20: leading subrequest & echo_before_body ---- config - location /main { - echo_before_body hello; - echo_location_async /foo; - } - location /foo { - echo world; - } ---- request - GET /main ---- response_body -hello -world - - - -=== TEST 21: leading subrequest & xss ---- config - location /main { - default_type 'application/json'; - xss_get on; - xss_callback_arg c; - echo_location_async /foo; - } - location /foo { - echo -n world; - } ---- request - GET /main?c=hi ---- response_body chop -hi(world); - - - -=== TEST 22: multiple leading subrequest & xss ---- config - location /main { - default_type 'application/json'; - xss_get on; - xss_callback_arg c; - echo_location_async /foo; - echo_location_async /bar; - } - location /foo { - echo -n world; - } - location /bar { - echo -n ' people'; - } ---- request - GET /main?c=hi ---- response_body chop -hi(world people); - - - -=== TEST 23: sanity (HEAD) ---- config - location /main { - echo_location_async /sub; - echo_location_async /sub; - } - location /sub { - echo hello; - } ---- request - HEAD /main ---- response_body - diff --git a/debian/modules/http-echo/t/location.t b/debian/modules/http-echo/t/location.t deleted file mode 100644 index 48c851e..0000000 --- a/debian/modules/http-echo/t/location.t +++ /dev/null @@ -1,567 +0,0 @@ -# vi:filetype= - -use lib 'lib'; - -use Test::Nginx::Socket; - -repeat_each(2); - -plan tests => repeat_each() * (2 * blocks() + 2); - -#$Test::Nginx::LWP::LogLevel = 'debug'; - -#no_diff(); - -run_tests(); - -__DATA__ - -=== TEST 1: sanity ---- config - location /main { - echo_location /sub; - } - location /sub { - echo hello; - } ---- request - GET /main ---- response_body -hello - - - -=== TEST 2: sanity with proxy in the middle ---- config - location /main { - echo_location /proxy; - } - location /proxy { - proxy_pass $scheme://127.0.0.1:$server_port/sub; - } - location /sub { - echo hello; - } ---- request - GET /main ---- response_body -hello - - - -=== TEST 3: trailing echo ---- config - location /main { - echo_location /sub; - echo after subrequest; - } - location /sub { - echo hello; - } ---- request - GET /main ---- response_body -hello -after subrequest - - - -=== TEST 4: leading echo ---- config - location /main { - echo before subrequest; - echo_location /sub; - } - location /sub { - echo hello; - } ---- request - GET /main ---- response_body -before subrequest -hello - - - -=== TEST 5: leading & trailing echo ---- config - location /main { - echo before subrequest; - echo_location /sub; - echo after subrequest; - } - location /sub { - echo hello; - } ---- request - GET /main ---- response_body -before subrequest -hello -after subrequest - - - -=== TEST 6: multiple subrequests ---- config - location /main { - echo before sr 1; - echo_location /sub; - echo after sr 1; - echo before sr 2; - echo_location /sub; - echo after sr 2; - } - location /sub { - echo hello; - } ---- request - GET /main ---- response_body -before sr 1 -hello -after sr 1 -before sr 2 -hello -after sr 2 - - - -=== TEST 7: timed multiple subrequests (blocking sleep) ---- config - location /main { - echo_reset_timer; - echo_location /sub1; - echo_location /sub2; - echo "took $echo_timer_elapsed sec for total."; - } - location /sub1 { - echo_blocking_sleep 0.02; - echo hello; - } - location /sub2 { - echo_blocking_sleep 0.01; - echo world; - } - ---- request - GET /main ---- response_body_like -^hello -world -took 0\.0(?:2[5-9]|3[0-6]) sec for total\.$ - - - -=== TEST 8: timed multiple subrequests (non-blocking sleep) ---- config - location /main { - echo_reset_timer; - echo_location /sub1; - echo_location /sub2; - echo "took $echo_timer_elapsed sec for total."; - } - location /sub1 { - echo_sleep 0.02; - echo hello; - } - location /sub2 { - echo_sleep 0.01; - echo world; - } - ---- request - GET /main ---- response_body_like -^hello -world -took 0\.0(?:2[5-9]|3[0-6]) sec for total\.$ - - - -=== TEST 9: location with args ---- config - location /main { - echo_location /sub 'foo=Foo&bar=Bar'; - } - location /sub { - echo $arg_foo $arg_bar; - } ---- request - GET /main ---- response_body -Foo Bar - - - -=== TEST 10: chained subrequests ---- config - location /main { - echo 'pre main'; - echo_location /sub; - echo 'post main'; - } - - location /sub { - echo 'pre sub'; - echo_location /subsub; - echo 'post sub'; - } - - location /subsub { - echo 'subsub'; - } ---- request - GET /main ---- response_body -pre main -pre sub -subsub -post sub -post main - - - -=== TEST 11: chained subrequests using named locations -as of 0.8.20, ngx_http_subrequest still does not support -named location. sigh. this case is a TODO. ---- config - location /main { - echo 'pre main'; - echo_location @sub; - echo 'post main'; - } - - location @sub { - echo 'pre sub'; - echo_location @subsub; - echo 'post sub'; - } - - location @subsub { - echo 'subsub'; - } ---- request - GET /main ---- response_body -pre main -pre sub -subsub -post sub -post main ---- SKIP - - - -=== TEST 12: explicit flush in main request ---- config - location /main { - echo 'pre main'; - echo_location /sub; - echo 'post main'; - echo_flush; - } - - location /sub { - echo_sleep 0.02; - echo 'sub'; - } ---- request - GET /main ---- response_body -pre main -sub -post main - - - -=== TEST 13: no varaiable inheritance ---- config - location /main { - echo $echo_cacheable_request_uri; - echo_location /sub; - echo_location /sub2; - } - location /sub { - echo $echo_cacheable_request_uri; - } - location /sub2 { - echo $echo_cacheable_request_uri; - } - ---- request - GET /main ---- response_body -/main -/sub -/sub2 - - - -=== TEST 14: unsafe uri ---- config - location /unsafe { - echo_location '/../foo'; - } ---- request - GET /unsafe ---- ignore_response ---- error_log -echo_location sees unsafe uri: "/../foo" ---- no_error_log -[error] -[alert] - - - -=== TEST 15: querystring in url ---- config - location /main { - echo_location /sub?foo=Foo&bar=Bar; - } - location /sub { - echo $arg_foo $arg_bar; - } ---- request - GET /main ---- response_body -Foo Bar - - - -=== TEST 16: querystring in url *AND* an explicit querystring ---- config - location /main { - echo_location /sub?foo=Foo&bar=Bar blah=Blah; - } - location /sub { - echo $arg_foo $arg_bar $arg_blah; - } ---- request - GET /main ---- response_body - Blah - - - -=== TEST 17: let subrequest to read the main request's request body ---- SKIP ---- config - location /main { - echo_location /sub; - } - location /sub { - echo_read_request_body; - echo_request_body; - } ---- request -POST /main -hello, body! ---- response_body chomp -hello, body! - - - -=== TEST 18: sleep after location ---- config - location /main { - echo_location /sub; - echo_sleep 0.001; - echo_location /sub; - } - location /sub { - echo_sleep 0.001; - echo sub; - } ---- request - GET /main ---- response_body -sub -sub ---- skip_nginx: 2: < 0.8.11 - - - -=== TEST 19: deep nested echo_location/echo_location_async ---- config - location /main { - echo_location /bar; - echo_location_async /bar; - echo_location_async /bar; - echo_location /group; - echo_location_async /group; - } - - location /group { - echo_location /bar; - echo_location_async /bar; - } - - location /bar { - #echo_sleep 0.001; - echo $echo_incr; - } ---- request -GET /main ---- response_body -1 -2 -3 -4 -5 -6 -7 ---- timeout: 2 - - - -=== TEST 20: deep nested echo_location/echo_location_async (with sleep) ---- config - location /main { - echo_location /bar; - echo_location_async /bar; - echo_location_async /bar; - echo_location /group; - echo_location_async /group; - } - - location /group { - echo_location /baz; - echo_location_async /bah; - } - - location ~ '^/ba[rzh]' { - echo_sleep 0.001; - echo $echo_incr; - } ---- request -GET /main ---- response_body -1 -2 -3 -4 -5 -6 -7 ---- timeout: 2 - - - -=== TEST 21: deep nested echo_location (with sleep) ---- config - location /main { - echo_location /bar; - echo_location /bar; - echo_location /bar; - echo_location /group; - echo_location /group; - } - - location /group { - echo_location /bar; - echo_location /bar; - } - - location /incr { - echo_sleep 0.001; - echo $echo_incr; - } - - location /bar { - proxy_pass $scheme://127.0.0.1:$server_port/incr; - } ---- request -GET /main ---- response_body -1 -1 -1 -1 -1 -1 -1 ---- timeout: 5 ---- no_error_log -[error] - - - -=== TEST 22: leading subrequest & echo_before_body ---- config - location /main { - echo_before_body hello; - echo_location /foo; - } - location /foo { - echo world; - } ---- request - GET /main ---- response_body -hello -world - - - -=== TEST 23: leading subrequest & xss ---- config - location /main { - default_type 'application/json'; - xss_get on; - xss_callback_arg c; - echo_location /foo; - } - location /foo { - echo -n world; - } ---- request - GET /main?c=hi ---- response_body chop -hi(world); - - - -=== TEST 24: multiple leading subrequest & xss ---- config - location /main { - default_type 'application/json'; - xss_get on; - xss_callback_arg c; - echo_location /foo; - echo_location /bar; - } - location /main2 { - content_by_lua ' - local res = ngx.location.capture("/foo") - local res2 = ngx.location.capture("/bar") - ngx.say(res.body) - ngx.say(res2.body) - '; - } - location /foo { - echo -n world; - } - location /bar { - echo -n ' people'; - } ---- request - GET /main?c=hi ---- response_body chop -hi(world people); - - - -=== TEST 25: sanity (HEAD) ---- config - location /main { - echo_location /sub; - echo_location /sub; - } - location /sub { - echo hello; - } ---- request - HEAD /main ---- response_body - diff --git a/debian/modules/http-echo/t/mixed.t b/debian/modules/http-echo/t/mixed.t deleted file mode 100644 index abf2599..0000000 --- a/debian/modules/http-echo/t/mixed.t +++ /dev/null @@ -1,82 +0,0 @@ -# vi:filetype= - -use lib 'lib'; -use Test::Nginx::Socket; - -plan tests => 2 * blocks(); - -run_tests(); - -__DATA__ - -=== TEST 1: echo before echo_client_request_headers ---- config - location /echo { - echo "headers:"; - echo -n $echo_client_request_headers; - } ---- request - GET /echo ---- response_body eval -"headers: -GET /echo HTTP/1.1\r -Host: localhost\r -Connection: close\r -\r -" - - - -=== TEST 2: echo_client_request_headers before echo ---- config - location /echo { - echo -n $echo_client_request_headers; - echo "...these are the headers"; - } ---- request - GET /echo ---- response_body eval -"GET /echo HTTP/1.1\r -Host: localhost\r -Connection: close\r -\r -...these are the headers -" - - - -=== TEST 3: echo & headers & echo ---- config - location /echo { - echo "headers are"; - echo -n $echo_client_request_headers; - echo "...these are the headers"; - } ---- request - GET /echo ---- response_body eval -"headers are -GET /echo HTTP/1.1\r -Host: localhost\r -Connection: close\r -\r -...these are the headers -" - - - -=== TEST 4: mixed with echo_duplicate ---- config - location /mixed { - echo hello; - echo_duplicate 2 ---; - echo_duplicate 1 ' END '; - echo_duplicate 2 ---; - echo; - } ---- request - GET /mixed ---- response_body -hello ------- END ------ - diff --git a/debian/modules/http-echo/t/request-body.t b/debian/modules/http-echo/t/request-body.t deleted file mode 100644 index d467b2e..0000000 --- a/debian/modules/http-echo/t/request-body.t +++ /dev/null @@ -1,58 +0,0 @@ -# vi:filetype= - -use lib 'lib'; -use Test::Nginx::Socket; - -repeat_each(2); - -plan tests => repeat_each() * 2 * blocks(); - -run_tests(); - -__DATA__ - -=== TEST 1: big client body buffered into temp files ---- config - location /echo { - client_body_buffer_size 1k; - echo_read_request_body; - echo_request_body; - } ---- request eval -"POST /echo -" . 'a' x 4096 . 'end'; ---- response_body eval -'a' x 4096 . 'end' - - - -=== TEST 2: in memory request body (trailing echo) ---- config - location /echo { - client_body_buffer_size 1k; - echo_read_request_body; - echo_request_body; - echo done; - } ---- request -POST /echo -hello world ---- response_body -hello worlddone - - - -=== TEST 3: big client body buffered into temp files (trailing echo) ---- config - location /echo { - client_body_buffer_size 1k; - echo_read_request_body; - echo_request_body; - echo done; - } ---- request eval -"POST /echo -" . 'a' x 4096 . "end\n"; ---- response_body eval -'a' x 4096 . "enddone\n" - diff --git a/debian/modules/http-echo/t/request-info.t b/debian/modules/http-echo/t/request-info.t deleted file mode 100644 index 8fd015e..0000000 --- a/debian/modules/http-echo/t/request-info.t +++ /dev/null @@ -1,841 +0,0 @@ -# vi:filetype= - -use lib 'lib'; -use Test::Nginx::Socket; - -repeat_each(2); - -plan tests => repeat_each() * (3 * blocks() + 15); - -run_tests(); - -__DATA__ - -=== TEST 1: standalone directive ---- config - location /echo { - echo -n $echo_client_request_headers; - } ---- request - GET /echo ---- response_body eval -"GET /echo HTTP/1.1\r -Host: localhost\r -Connection: close\r -\r -" ---- no_error_log -[error] - - - -=== TEST 2: multiple instances ---- config - location /echo { - echo -n $echo_client_request_headers; - echo -n $echo_client_request_headers; - } ---- request - GET /echo ---- response_body eval -"GET /echo HTTP/1.1\r -Host: localhost\r -Connection: close\r -\r -GET /echo HTTP/1.1\r -Host: localhost\r -Connection: close\r -\r -" ---- no_error_log -[error] - - - -=== TEST 3: does not explicitly request_body ---- config - location /echo { - echo [$echo_request_body]; - } ---- request -POST /echo -body here -heh ---- response_body -[] ---- no_error_log -[error] - - - -=== TEST 4: let proxy read request_body ---- config - location /echo { - echo_before_body [$echo_request_body]; - proxy_pass $scheme://127.0.0.1:$server_port/blah; - } - location /blah { echo_duplicate 0 ''; } ---- request -POST /echo -body here -heh ---- response_body -[body here -heh] ---- no_error_log -[error] - - - -=== TEST 5: use echo_read_request_body to read it! ---- config - location /echo { - echo_read_request_body; - echo [$echo_request_body]; - } ---- request -POST /echo -body here -heh ---- response_body -[body here -heh] ---- no_error_log -[error] - - - -=== TEST 6: how about sleep after that? ---- config - location /echo { - echo_read_request_body; - echo_sleep 0.002; - echo [$echo_request_body]; - } ---- request -POST /echo -body here -heh ---- response_body -[body here -heh] ---- no_error_log -[error] - - - -=== TEST 7: echo back the whole client request ---- config - # echo back the client request - location /echoback { - echo -n $echo_client_request_headers; - echo_read_request_body; - echo $echo_request_body; - } ---- request -POST /echoback -body here -haha ---- response_body eval -"POST /echoback HTTP/1.1\r -Host: localhost\r -Connection: close\r -Content-Length: 14\r -\r -body here -haha -" ---- no_error_log -[error] - - - -=== TEST 8: echo_request_body ---- config - location /body { - client_body_buffer_size 5; - echo_read_request_body; - echo "[$echo_request_body]"; - echo_request_body; - } ---- request eval -"POST /body -" . ('a' x 2048) . "b" ---- response_body eval -"[]\n" . -('a' x 2048) . "b" ---- no_error_log -[error] - - - -=== TEST 9: $echo_response_status in content handler ---- config - location /status { - echo "status: $echo_response_status"; - } ---- request - GET /status ---- response_body -status: ---- no_error_log -[error] - - - -=== TEST 10: echo_request_body (empty body) ---- config - location /body { - echo_read_request_body; - echo_request_body; - } - location /main { - proxy_pass http://127.0.0.1:$server_port/body; - } ---- request eval -"POST /main" ---- response_body eval -"" ---- no_error_log -[error] - - - -=== TEST 11: small header ---- config - location /t { - echo -n $echo_client_request_headers; - } ---- request -GET /t ---- response_body eval -qq{GET /t HTTP/1.1\r -Host: localhost\r -Connection: close\r -\r -} ---- no_error_log -[error] ---- no_error_log -[error] - - - -=== TEST 12: large header ---- config - client_header_buffer_size 10; - large_client_header_buffers 30 561; - location /t { - echo -n $echo_client_request_headers; - } ---- request -GET /t ---- more_headers eval -CORE::join "\n", map { "Header$_: value-$_" } 1..512 - ---- response_body eval -qq{GET /t HTTP/1.1\r -Host: localhost\r -Connection: close\r -} -.(CORE::join "\r\n", map { "Header$_: value-$_" } 1..512) . "\r\n\r\n" - ---- no_error_log -[error] - - - -=== TEST 13: small header, with leading CRLF ---- config - location /t { - echo -n $echo_client_request_headers; - } ---- raw_request eval -"\r\nGET /t HTTP/1.1\r -Host: localhost\r -Connection: close\r -\r -" ---- response_body eval -qq{GET /t HTTP/1.1\r -Host: localhost\r -Connection: close\r -\r -} ---- no_error_log -[error] - - - -=== TEST 14: large header, with leading CRLF ---- config - client_header_buffer_size 10; - large_client_header_buffers 30 561; - location /t { - echo -n $echo_client_request_headers; - } - ---- raw_request eval -"\r\nGET /t HTTP/1.1\r -Host: localhost\r -Connection: close\r -". -(CORE::join "\r\n", map { "Header$_: value-$_" } 1..512) . "\r\n\r\n" - ---- response_body eval -qq{GET /t HTTP/1.1\r -Host: localhost\r -Connection: close\r -} -.(CORE::join "\r\n", map { "Header$_: value-$_" } 1..512) . "\r\n\r\n" - ---- no_error_log -[error] - - - -=== TEST 15: small header, pipelined ---- config - location /t { - echo -n $echo_client_request_headers; - } ---- pipelined_requests eval -["GET /t", "GET /th"] - ---- more_headers -Foo: bar - ---- response_body eval -[qq{GET /t HTTP/1.1\r -Host: localhost\r -Connection: keep-alive\r -Foo: bar\r -\r -}, qq{GET /th HTTP/1.1\r -Host: localhost\r -Connection: close\r -Foo: bar\r -\r -}] ---- no_error_log -[error] - - - -=== TEST 16: large header, pipelined ---- config - client_header_buffer_size 10; - large_client_header_buffers 30 561; - location /t { - echo -n $echo_client_request_headers; - } ---- pipelined_requests eval -["GET /t", "GET /t"] - ---- more_headers eval -CORE::join "\n", map { "Header$_: value-$_" } 1..512 - ---- response_body eval -my $headers = (CORE::join "\r\n", map { "Header$_: value-$_" } 1..512) . "\r\n\r\n"; - -[qq{GET /t HTTP/1.1\r -Host: localhost\r -Connection: keep-alive\r -$headers}, -qq{GET /t HTTP/1.1\r -Host: localhost\r -Connection: close\r -$headers}] - ---- no_error_log -[error] - - - -=== TEST 17: small header, multi-line header ---- config - location /t { - echo -n $echo_client_request_headers; - } ---- raw_request eval -"GET /t HTTP/1.1\r -Host: localhost\r -Connection: close\r -Foo: bar baz\r - blah\r -\r -" ---- response_body eval -qq{GET /t HTTP/1.1\r -Host: localhost\r -Connection: close\r -Foo: bar baz\r - blah\r -\r -} ---- no_error_log -[error] - - - -=== TEST 18: large header, multi-line header ---- config - client_header_buffer_size 10; - large_client_header_buffers 50 567; - location /t { - echo -n $echo_client_request_headers; - } - ---- raw_request eval -my $headers = (CORE::join "\r\n", map { "Header$_: value-$_\r\n hello $_ world blah blah" } 1..512) . "\r\n\r\n"; - -qq{GET /t HTTP/1.1\r -Host: localhost\r -Connection: close\r -$headers} - ---- response_body eval -qq{GET /t HTTP/1.1\r -Host: localhost\r -Connection: close\r -} -.(CORE::join "\r\n", map { "Header$_: value-$_\r\n hello $_ world blah blah" } 1..512) . "\r\n\r\n" - ---- no_error_log -[error] - - - -=== TEST 19: small header (POST body) ---- config - location /t { - echo_read_request_body; - echo -n $echo_client_request_headers; - } ---- request -POST /t -hello ---- response_body eval -qq{POST /t HTTP/1.1\r -Host: localhost\r -Connection: close\r -Content-Length: 5\r -\r -} ---- no_error_log -[error] - - - -=== TEST 20: small header (POST body) - in subrequests (location) ---- config - location /t { - echo -n $echo_client_request_headers; - } - location /main { - echo_location /t; - } - ---- request -POST /main -hello ---- response_body eval -qq{POST /main HTTP/1.1\r -Host: localhost\r -Connection: close\r -Content-Length: 5\r -\r -} ---- no_error_log -[error] - - - -=== TEST 21: large header (POST body) ---- config - client_header_buffer_size 10; - large_client_header_buffers 30 561; - location /t { - echo_read_request_body; - echo -n $echo_client_request_headers; - } ---- request -POST /t -hello - ---- more_headers eval -CORE::join"\n", map { "Header$_: value-$_" } 1..512 - ---- response_body eval -qq{POST /t HTTP/1.1\r -Host: localhost\r -Connection: close\r -} -.(CORE::join "\r\n", map { "Header$_: value-$_" } 1..512) . "\r\nContent-Length: 5\r\n\r\n" - ---- no_error_log -[error] ---- timeout: 5 - - - -=== TEST 22: large header (POST body) - in subrequests ---- config - client_header_buffer_size 10; - large_client_header_buffers 30 561; - location /t { - echo_read_request_body; - echo -n $echo_client_request_headers; - } - - location /main { - echo_location /t; - } ---- request -POST /main -hello ---- more_headers eval -CORE::join"\n", map { "Header$_: value-$_" } 1..512 - ---- response_body eval -qq{POST /main HTTP/1.1\r -Host: localhost\r -Connection: close\r -} -.(CORE::join "\r\n", map { "Header$_: value-$_" } 1..512) . "\r\nContent-Length: 5\r\n\r\n" - ---- no_error_log -[error] ---- timeout: 5 - - - -=== TEST 23: raw headers - the default header buffer can hold the request line, but not the header entries ---- config - location /t { - echo_read_request_body; - echo -n $echo_client_request_headers; - } ---- request -GET /t ---- more_headers eval -my $s = "User-Agent: curl\nBah: bah\n"; -$s .= "Accept: */*\n"; -$s .= "Cookie: " . "C" x 1200 . "\n"; -$s ---- response_body eval -"GET /t HTTP/1.1\r -Host: localhost\r -Connection: close\r -User-Agent: curl\r -Bah: bah\r -Accept: */*\r -Cookie: " . ("C" x 1200) . "\r\n\r\n" ---- no_error_log -[error] - - - -=== TEST 24: small header (POST body) - in subrequests (location_async) ---- config - location /t { - echo -n $echo_client_request_headers; - } - location /main { - echo_location_async /t; - } - ---- request -POST /main -hello ---- response_body eval -qq{POST /main HTTP/1.1\r -Host: localhost\r -Connection: close\r -Content-Length: 5\r -\r -} ---- no_error_log -[error] - - - -=== TEST 25: small header (POST body) - in subrequests (subrequest) ---- config - location /t { - echo -n $echo_client_request_headers; - } - location /main { - echo_subrequest GET /t; - } - ---- request -POST /main -hello ---- response_body eval -qq{POST /main HTTP/1.1\r -Host: localhost\r -Connection: close\r -Content-Length: 5\r -\r -} ---- no_error_log -[error] - - - -=== TEST 26: small header (POST body) - in subrequests (subrequest_async) ---- config - location /t { - echo -n $echo_client_request_headers; - } - location /main { - echo_subrequest_async GET /t; - } - ---- request -POST /main -hello ---- response_body eval -qq{POST /main HTTP/1.1\r -Host: localhost\r -Connection: close\r -Content-Length: 5\r -\r -} ---- no_error_log -[error] - - - -=== TEST 27: ngx_proxy/ngx_fastcgi/etc change r->header_end to point to their own buffers ---- config - location = /t { - proxy_buffering off; - proxy_pass http://127.0.0.1:$server_port/bad; - proxy_intercept_errors on; - error_page 500 = /500; - } - - location = /bad { - return 500; - } - - location = /500 { - echo -n $echo_client_request_headers; - } ---- request -GET /t ---- response_body eval -"GET /t HTTP/1.1\r -Host: localhost\r -Connection: close\r -\r -" ---- no_error_log -[error] - - - -=== TEST 28: ngx_proxy/ngx_fastcgi/etc change r->header_end to point to their own buffers (exclusive LF in the request data) ---- config - location = /t { - proxy_buffering off; - proxy_pass http://127.0.0.1:$server_port/bad; - proxy_intercept_errors on; - error_page 500 = /500; - } - - location = /bad { - return 500; - } - - location = /500 { - internal; - echo -n $echo_client_request_headers; - } ---- raw_request eval -"GET /t HTTP/1.1 -Host: localhost -Connection: close -Content-Length: 5 - -hello" ---- response_body eval -"GET /t HTTP/1.1 -Host: localhost -Connection: close -Content-Length: 5 - -" ---- no_error_log -[error] - - - -=== TEST 29: ngx_proxy/ngx_fastcgi/etc change r->header_end to point to their own buffers (mixed LF and CRLF in the request data) ---- config - location = /t { - proxy_buffering off; - proxy_pass http://127.0.0.1:$server_port/bad; - proxy_intercept_errors on; - error_page 500 = /500; - } - - location = /bad { - return 500; - } - - location = /500 { - internal; - echo -n $echo_client_request_headers; - } ---- raw_request eval -"GET /t HTTP/1.1\r -Host: localhost -Connection: close\r -Content-Length: 5\r - -hello" ---- response_body eval -"GET /t HTTP/1.1\r -Host: localhost -Connection: close\r -Content-Length: 5\r - -" ---- no_error_log -[error] - - - -=== TEST 30: ngx_proxy/ngx_fastcgi/etc change r->header_end to point to their own buffers (another way of mixing LF and CRLF in the request data) ---- config - location = /t { - proxy_buffering off; - proxy_pass http://127.0.0.1:$server_port/bad; - proxy_intercept_errors on; - error_page 500 = /500; - } - - location = /bad { - return 500; - } - - location = /500 { - internal; - echo -n $echo_client_request_headers; - } ---- raw_request eval -"GET /t HTTP/1.1\r -Host: localhost -Connection: close\r -Content-Length: 5 -\r -hello" ---- response_body eval -"GET /t HTTP/1.1\r -Host: localhost -Connection: close\r -Content-Length: 5 -\r -" ---- no_error_log -[error] - - - -=== TEST 31: two pipelined requests with large headers ---- config - client_header_buffer_size 10; - large_client_header_buffers 3 5610; - location /t { - echo -n $echo_client_request_headers; - } ---- pipelined_requests eval -["GET /t", "GET /t"] ---- more_headers eval -CORE::join "\n", map { "Header$_: value-$_" } 1..585 - ---- response_body eval -[qq{GET /t HTTP/1.1\r -Host: localhost\r -Connection: keep-alive\r -} -.(CORE::join "\r\n", map { "Header$_: value-$_" } 1..585) . "\r\n\r\n", -qq{GET /t HTTP/1.1\r -Host: localhost\r -Connection: close\r -} -.(CORE::join "\r\n", map { "Header$_: value-$_" } 1..585) . "\r\n\r\n", -, -] - ---- no_error_log -[error] ---- timeout: 5 - - - -=== TEST 32: a request with large header and a smaller pipelined request following ---- config - client_header_buffer_size 10; - large_client_header_buffers 2 1921; - location /t { - echo -n $echo_client_request_headers; - } ---- pipelined_requests eval -["GET /t", "GET /t"] ---- more_headers eval -[CORE::join("\n", map { "Header$_: value-$_" } 1..170), "Foo: bar\n"] - ---- response_body eval -[qq{GET /t HTTP/1.1\r -Host: localhost\r -Connection: keep-alive\r -} -.(CORE::join "\r\n", map { "Header$_: value-$_" } 1..170) . "\r\n\r\n", -qq{GET /t HTTP/1.1\r -Host: localhost\r -Connection: close\r -Foo: bar\r -\r -}, -] - ---- no_error_log -[error] ---- timeout: 5 - - - -=== TEST 33: a request with large header and a smaller pipelined request following ---- config - client_header_buffer_size 10; - large_client_header_buffers 2 1921; - location /t { - echo -n $echo_client_request_headers; - } ---- pipelined_requests eval -["GET /t", "GET /t" . ("a" x 512)] ---- more_headers eval -[CORE::join("\n", map { "Header$_: value-$_" } 1..170), "Foo: bar\n"] - ---- response_body eval -[qq{GET /t HTTP/1.1\r -Host: localhost\r -Connection: keep-alive\r -} -.(CORE::join "\r\n", map { "Header$_: value-$_" } 1..170) . "\r\n\r\n", -qq{GET /t} . ("a" x 512) . qq{ HTTP/1.1\r -Host: localhost\r -Connection: close\r -Foo: bar\r -\r -}, -] - ---- no_error_log -[error] ---- timeout: 5 - diff --git a/debian/modules/http-echo/t/sleep.t b/debian/modules/http-echo/t/sleep.t deleted file mode 100644 index f8e741e..0000000 --- a/debian/modules/http-echo/t/sleep.t +++ /dev/null @@ -1,200 +0,0 @@ -# vi:filetype= - -use lib 'lib'; -use Test::Nginx::Socket; - -plan tests => 2 * blocks(); - -run_tests(); - -__DATA__ - -=== TEST 1: sanity ---- config - location /echo { - echo_sleep 1; - } ---- request - GET /echo ---- response_body - - - -=== TEST 2: fractional delay ---- config - location /echo { - echo_sleep 0.01; - } ---- request - GET /echo ---- response_body - - - -=== TEST 3: leading echo ---- config - location /echo { - echo before...; - echo_sleep 0.01; - } ---- request - GET /echo ---- response_body -before... - - - -=== TEST 4: trailing echo ---- config - location /echo { - echo_sleep 0.01; - echo after...; - } ---- request - GET /echo ---- response_body -after... - - - -=== TEST 5: two echos around sleep ---- config - location /echo { - echo before...; - echo_sleep 0.01; - echo after...; - } ---- request - GET /echo ---- response_body -before... -after... - - - -=== TEST 6: interleaving sleep and echo ---- config - location /echo { - echo 1; - echo_sleep 0.01; - echo 2; - echo_sleep 0.01; - } ---- request - GET /echo ---- response_body -1 -2 - - - -=== TEST 7: interleaving sleep and echo with echo at the end... ---- config - location /echo { - echo 1; - echo_sleep 0.01; - echo 2; - echo_sleep 0.01; - echo 3; - } ---- request - GET /echo ---- response_body -1 -2 -3 - - - -=== TEST 8: flush before sleep -we didn't really test the actual effect of "echo_flush" here... -merely checks if it croaks if appears. ---- config - location /flush { - echo hi; - echo_flush; - echo_sleep 0.01; - echo trees; - } ---- request - GET /flush ---- response_body -hi -trees - - - -=== TEST 9: flush does not increment opcode pointer itself ---- config - location /flush { - echo hi; - echo_flush; - echo trees; - } ---- request - GET /flush ---- response_body -hi -trees - - - -=== TEST 10: sleep through a proxy -this reveals a bug in v0.19 and the bug is fixed in v0.20. ---- config - location /proxy { - proxy_pass $scheme://127.0.0.1:$server_port/entry'; - } - location /entry { - echo_sleep 0.001; - echo done; - } ---- request - GET /proxy ---- response_body_like -done - - - -=== TEST 11: abnormally quit ---- config - location /quit { - echo before; - echo_flush; - echo_sleep 1; - echo after; - } ---- request - GET /quit ---- response_body -before -after - - - -=== TEST 12: two echos around sleep (HEAD) ---- config - location /echo { - echo before...; - echo_sleep 0.01; - echo after...; - } ---- request - HEAD /echo ---- response_body - - - -=== TEST 13: sleep by variable ---- config - location ~ ^/sleep/(.+) { - echo before...; - echo_sleep $1; - echo after...; - } ---- request - GET /sleep/0.01 ---- response_body -before... -after... - diff --git a/debian/modules/http-echo/t/status.t b/debian/modules/http-echo/t/status.t deleted file mode 100644 index d97b084..0000000 --- a/debian/modules/http-echo/t/status.t +++ /dev/null @@ -1,142 +0,0 @@ -# vi:filetype= - -use lib 'lib'; -use Test::Nginx::Socket; - -repeat_each(1); - -plan tests => repeat_each() * (2 * blocks()); - -#$Test::Nginx::LWP::LogLevel = 'debug'; - -run_tests(); - -__DATA__ - -=== TEST 1: 200 ---- config - location /echo { - echo_status 200; - echo hello; - } ---- request - GET /echo ---- response_body -hello ---- error_code: 200 - - - -=== TEST 2: if location (200) ---- config - location /echo { - set $true 1; - if ($true) { - } - echo_status 200; - echo hello; - } ---- request - GET /echo ---- response_body -hello ---- error_code: 200 - - - -=== TEST 3: 404 ---- config - location /echo { - echo_status 404; - echo hello; - } ---- request - GET /echo ---- response_body -hello ---- error_code: 404 - - - -=== TEST 4: if location (404) ---- config - location /echo { - set $true 1; - if ($true) { - } - echo_status 404; - echo hello; - } ---- request - GET /echo ---- response_body -hello ---- error_code: 404 - - - -=== TEST 5: 500 ---- config - location /echo { - echo_status 500; - echo hello; - } ---- request - GET /echo ---- response_body -hello ---- error_code: 500 - - - -=== TEST 6: if location (500) ---- config - location /echo { - set $true 1; - if ($true) { - } - echo_status 500; - echo hello; - } ---- request - GET /echo ---- response_body -hello ---- error_code: 500 - - - -=== TEST 7: if location (500) no inherit ---- config - location /echo { - set $true 1; - if ($true) { - echo_status 503; - } - echo_status 500; - echo hello; - } ---- request - GET /echo ---- response_body -hello ---- error_code: 503 - - - -=== TEST 8: subrequest ---- config - location /echo { - echo_location /sub; - echo_status 503; - } - - location /sub { - echo blah blah; - } ---- request - GET /echo ---- response_body -blah blah ---- error_code: 503 - diff --git a/debian/modules/http-echo/t/subrequest-async.t b/debian/modules/http-echo/t/subrequest-async.t deleted file mode 100644 index 882b368..0000000 --- a/debian/modules/http-echo/t/subrequest-async.t +++ /dev/null @@ -1,604 +0,0 @@ -# vi:filetype= - -use lib 'lib'; -use Test::Nginx::Socket; - -repeat_each(2); - -plan tests => repeat_each() * (blocks() * 2 + 1); - -#$Test::Nginx::LWP::LogLevel = 'debug'; - -$ENV{TEST_NGINX_HTML_DIR} = html_dir; - -run_tests(); - -__DATA__ - -=== TEST 1: sanity - GET ---- config - location /main { - echo_subrequest_async GET /sub; - } - location /sub { - echo "sub method: $echo_request_method"; - echo "main method: $echo_client_request_method"; - } ---- request - GET /main ---- response_body -sub method: GET -main method: GET - - - -=== TEST 2: sanity - DELETE ---- config - location /main { - echo_subrequest_async DELETE /sub; - } - location /sub { - echo "sub method: $echo_request_method"; - echo "main method: $echo_client_request_method"; - } ---- request - GET /main ---- response_body -sub method: DELETE -main method: GET - - - -=== TEST 3: trailing echo ---- config - location /main { - echo_subrequest_async GET /sub; - echo after subrequest; - } - location /sub { - echo hello; - } ---- request - GET /main ---- response_body -hello -after subrequest - - - -=== TEST 4: leading echo ---- config - location /main { - echo before subrequest; - echo_subrequest_async GET /sub; - } - location /sub { - echo hello; - } ---- request - GET /main ---- response_body -before subrequest -hello - - - -=== TEST 5: leading & trailing echo ---- config - location /main { - echo before subrequest; - echo_subrequest_async GET /sub; - echo after subrequest; - } - location /sub { - echo hello; - } ---- request - GET /main ---- response_body -before subrequest -hello -after subrequest - - - -=== TEST 6: multiple subrequests ---- config - location /main { - echo before sr 1; - echo_subrequest_async GET /sub; - echo after sr 1; - echo before sr 2; - echo_subrequest_async GET /sub; - echo after sr 2; - } - location /sub { - echo hello; - } ---- request - GET /main ---- response_body -before sr 1 -hello -after sr 1 -before sr 2 -hello -after sr 2 - - - -=== TEST 7: timed multiple subrequests (blocking sleep) ---- config - location /main { - echo_reset_timer; - echo_subrequest_async GET /sub1; - echo_subrequest_async GET /sub2; - echo "took $echo_timer_elapsed sec for total."; - } - location /sub1 { - echo_blocking_sleep 0.02; - echo hello; - } - location /sub2 { - echo_blocking_sleep 0.01; - echo world; - } - ---- request - GET /main ---- response_body_like -^hello -world -took 0\.00[0-5] sec for total\.$ - - - -=== TEST 8: timed multiple subrequests (non-blocking sleep) ---- config - location /main { - echo_reset_timer; - echo_subrequest_async GET /sub1; - echo_subrequest_async GET /sub2; - echo "took $echo_timer_elapsed sec for total."; - } - location /sub1 { - echo_sleep 0.02; - echo hello; - } - location /sub2 { - echo_sleep 0.01; - echo world; - } - ---- request - GET /main ---- response_body_like -^hello -world -took 0\.00[0-5] sec for total\.$ - - - -=== TEST 9: location with args ---- config - location /main { - echo_subrequest_async GET /sub -q 'foo=Foo&bar=Bar'; - } - location /sub { - echo $arg_foo $arg_bar; - } ---- request - GET /main ---- response_body -Foo Bar - - - -=== TEST 10: encoded chars in query strings ---- config - location /main { - echo_subrequest_async GET /sub -q 'foo=a%20b&bar=Bar'; - } - location /sub { - echo $arg_foo $arg_bar; - } ---- request - GET /main ---- response_body -a%20b Bar - - - -=== TEST 11: UTF-8 chars in query strings ---- config - location /main { - echo_subrequest_async GET /sub -q 'foo=你好'; - } - location /sub { - echo $arg_foo; - } ---- request - GET /main ---- response_body -你好 - - - -=== TEST 12: encoded chars in location url ---- config - location /main { - echo_subrequest_async GET /sub%31 -q 'foo=Foo&bar=Bar'; - } - location /sub%31 { - echo 'sub%31'; - } - location /sub1 { - echo 'sub1'; - } ---- request - GET /main ---- response_body -sub1 - - - -=== TEST 13: querystring in url ---- config - location /main { - echo_subrequest_async GET /sub?foo=Foo&bar=Bar; - } - location /sub { - echo $arg_foo $arg_bar; - } ---- request - GET /main ---- response_body -Foo Bar - - - -=== TEST 14: querystring in url *AND* an explicit querystring ---- config - location /main { - echo_subrequest_async GET /sub?foo=Foo&bar=Bar -q blah=Blah; - } - location /sub { - echo $arg_foo $arg_bar $arg_blah; - } ---- request - GET /main ---- response_body - Blah - - - -=== TEST 15: explicit flush in main request -flush won't really flush the buffer... ---- config - location /main_flush { - echo 'pre main'; - echo_subrequest_async GET /sub; - echo 'post main'; - echo_flush; - } - - location /sub { - echo_sleep 0.02; - echo 'sub'; - } ---- request - GET /main_flush ---- response_body -pre main -sub -post main - - - -=== TEST 16: POST subrequest with body (with proxy in the middle) and without read body explicitly ---- config - location /main { - echo_subrequest_async POST /proxy -b 'hello, world'; - } - location /proxy { - proxy_pass $scheme://127.0.0.1:$server_port/sub; - } - location /sub { - echo "sub method: $echo_request_method."; - # we need to read body explicitly here...or $echo_request_body - # will evaluate to empty ("") - echo "sub body: $echo_request_body."; - } ---- request - GET /main ---- response_body -sub method: POST. -sub body: . - - - -=== TEST 17: POST subrequest with body (with proxy in the middle) and read body explicitly ---- config - location /main { - echo_subrequest_async POST /proxy -b 'hello, world'; - } - location /proxy { - proxy_pass $scheme://127.0.0.1:$server_port/sub; - } - location /sub { - echo "sub method: $echo_request_method."; - # we need to read body explicitly here...or $echo_request_body - # will evaluate to empty ("") - echo_read_request_body; - echo "sub body: $echo_request_body."; - } ---- request - GET /main ---- response_body -sub method: POST. -sub body: hello, world. - - - -=== TEST 18: multiple subrequests ---- config - location /multi { - echo_subrequest_async POST '/sub' -q 'foo=Foo' -b 'hi'; - echo_subrequest_async PUT '/sub' -q 'bar=Bar' -b 'hello'; - } - location /sub { - echo "querystring: $query_string"; - echo "method: $echo_request_method"; - echo "body: $echo_request_body"; - echo "content length: $http_content_length"; - echo '///'; - } ---- request - GET /multi ---- response_body -querystring: foo=Foo -method: POST -body: hi -content length: 2 -/// -querystring: bar=Bar -method: PUT -body: hello -content length: 5 -/// - - - -=== TEST 19: no varaiable inheritance ---- config - location /main { - echo $echo_cacheable_request_uri; - echo_subrequest_async GET /sub; - echo_subrequest_async GET /sub2; - } - location /sub { - echo $echo_cacheable_request_uri; - } - location /sub2 { - echo $echo_cacheable_request_uri; - } - ---- request - GET /main ---- response_body -/main -/sub -/sub2 - - - -=== TEST 20: unsafe uri ---- config - location /unsafe { - echo_subrequest_async GET '/../foo'; - } ---- request - GET /unsafe ---- ignore_response ---- error_log -echo_subrequest_async sees unsafe uri: "/../foo" ---- no_error_log -[error] -[alert] - - - -=== TEST 21: let subrequest to read the main request's request body ---- SKIP ---- config - location /main { - echo_subrequest_async POST /sub; - } - location /sub { - echo_read_request_body; - echo_request_body; - } ---- request -POST /main -hello, body! ---- response_body chomp -hello, body! - - - -=== TEST 22: POST subrequest with file body (relative paths) ---- config - location /main { - echo_subrequest_async POST /sub -f html/blah.txt; - } - location /sub { - echo "sub method: $echo_request_method"; - # we don't need to call echo_read_client_body explicitly here - echo_request_body; - } ---- user_files ->>> blah.txt -Hello, world ---- request - GET /main ---- response_body -sub method: POST -Hello, world - - - -=== TEST 23: POST subrequest with file body (absolute paths) ---- config - location /main { - echo_subrequest_async POST /sub -f $TEST_NGINX_HTML_DIR/blah.txt; - } - location /sub { - echo "sub method: $echo_request_method"; - # we don't need to call echo_read_client_body explicitly here - echo_request_body; - } ---- user_files ->>> blah.txt -Hello, world! -Haha ---- request - GET /main ---- response_body -sub method: POST -Hello, world! -Haha - - - -=== TEST 24: POST subrequest with file body (file not found) ---- config - location /main { - echo_subrequest_async POST /sub -f html/blah/blah.txt; - } - location /sub { - echo "sub method: $echo_request_method"; - # we don't need to call echo_read_client_body explicitly here - echo_request_body; - } ---- user_files ->>> blah.txt -Hello, world ---- request - GET /main ---- ignore_response ---- error_log eval -qr/open\(\) ".*?" failed/ ---- no_error_log -[alert] - - - -=== TEST 25: POST subrequest with file body (absolute paths in vars) ---- config - location /main { - set $path $TEST_NGINX_HTML_DIR/blah.txt; - echo_subrequest_async POST /sub -f $path; - } - location /sub { - echo "sub method: $echo_request_method"; - # we don't need to call echo_read_client_body explicitly here - echo_request_body; - } ---- user_files ->>> blah.txt -Hello, world! -Haha ---- request - GET /main ---- response_body -sub method: POST -Hello, world! -Haha - - - -=== TEST 26: leading subrequest & echo_before_body ---- config - location /main { - echo_before_body hello; - echo_subrequest_async GET /foo; - } - location /foo { - echo world; - } ---- request - GET /main ---- response_body -hello -world - - - -=== TEST 27: leading subrequest & xss ---- config - location /main { - default_type 'application/json'; - xss_get on; - xss_callback_arg c; - echo_subrequest_async GET /foo; - } - location /foo { - echo -n world; - } ---- request - GET /main?c=hi ---- response_body chop -hi(world); - - - -=== TEST 28: multiple leading subrequest & xss ---- config - location /main { - default_type 'application/json'; - xss_get on; - xss_callback_arg c; - echo_subrequest_async GET /foo; - echo_subrequest_async GET /bar; - } - location /foo { - echo -n world; - } - location /bar { - echo -n ' people'; - } ---- request - GET /main?c=hi ---- response_body chop -hi(world people); - - - -=== TEST 29: sanity (HEAD) ---- config - location /main { - echo_subrequest_async GET /sub; - echo_subrequest_async GET /sub; - } - location /sub { - echo hello; - } ---- request - HEAD /main ---- response_body - - - -=== TEST 30: HEAD subrequest ---- config - location /main { - echo_subrequest_async HEAD /sub; - echo_subrequest_async HEAD /sub; - } - location /sub { - echo hello; - } ---- request - GET /main ---- response_body - diff --git a/debian/modules/http-echo/t/subrequest.t b/debian/modules/http-echo/t/subrequest.t deleted file mode 100644 index 6d965d0..0000000 --- a/debian/modules/http-echo/t/subrequest.t +++ /dev/null @@ -1,725 +0,0 @@ -# vi:filetype= - -use lib 'lib'; - -use Test::Nginx::Socket; - -repeat_each(2); - -plan tests => repeat_each() * (2 * blocks() + 1); - -$ENV{TEST_NGINX_HTML_DIR} = html_dir; -$ENV{TEST_NGINX_CLIENT_PORT} ||= server_port(); - -run_tests(); - -__DATA__ - -=== TEST 1: sanity ---- config - location /main { - echo_subrequest GET /sub; - } - location /sub { - echo hello; - } ---- request - GET /main ---- response_body -hello - - - -=== TEST 2: trailing echo ---- config - location /main { - echo_subrequest GET /sub; - echo after subrequest; - } - location /sub { - echo hello; - } ---- request - GET /main ---- response_body -hello -after subrequest - - - -=== TEST 3: leading echo ---- config - location /main { - echo before subrequest; - echo_subrequest GET /sub; - } - location /sub { - echo hello; - } ---- request - GET /main ---- response_body -before subrequest -hello - - - -=== TEST 4: leading & trailing echo ---- config - location /main { - echo before subrequest; - echo_subrequest GET /sub; - echo after subrequest; - } - location /sub { - echo hello; - } ---- request - GET /main ---- response_body -before subrequest -hello -after subrequest - - - -=== TEST 5: multiple subrequests ---- config - location /main { - echo before sr 1; - echo_subrequest GET /sub; - echo after sr 1; - echo before sr 2; - echo_subrequest GET /sub; - echo after sr 2; - } - location /sub { - echo hello; - } ---- request - GET /main ---- response_body -before sr 1 -hello -after sr 1 -before sr 2 -hello -after sr 2 - - - -=== TEST 6: timed multiple subrequests (blocking sleep) ---- config - location /main { - echo_reset_timer; - echo_subrequest GET /sub1; - echo_subrequest GET /sub2; - echo "took $echo_timer_elapsed sec for total."; - } - location /sub1 { - echo_blocking_sleep 0.02; - echo hello; - } - location /sub2 { - echo_blocking_sleep 0.01; - echo world; - } - ---- request - GET /main ---- response_body_like -^hello -world -took 0\.0(?:2[5-9]|3[0-6]) sec for total\.$ - - - -=== TEST 7: timed multiple subrequests (non-blocking sleep) ---- config - location /main { - echo_reset_timer; - echo_subrequest GET /sub1; - echo_subrequest GET /sub2; - echo "took $echo_timer_elapsed sec for total."; - } - location /sub1 { - echo_sleep 0.02; - echo hello; - } - location /sub2 { - echo_sleep 0.01; - echo world; - } - ---- request - GET /main ---- response_body_like -^hello -world -took 0\.0(?:2[5-9]|3[0-6]) sec for total\.$ - - - -=== TEST 8: location with args ---- config - location /main { - echo_subrequest GET /sub -q 'foo=Foo&bar=Bar'; - } - location /sub { - echo $arg_foo $arg_bar; - } ---- request - GET /main ---- response_body -Foo Bar - - - -=== TEST 9: chained subrequests ---- config - location /main { - echo 'pre main'; - echo_subrequest GET /sub; - echo 'post main'; - } - - location /sub { - echo 'pre sub'; - echo_subrequest GET /subsub; - echo 'post sub'; - } - - location /subsub { - echo 'subsub'; - } ---- request - GET /main ---- response_body -pre main -pre sub -subsub -post sub -post main - - - -=== TEST 10: chained subrequests using named locations -as of 0.8.20, ngx_http_subrequest still does not support -named location. sigh. this case is a TODO. ---- config - location /main { - echo 'pre main'; - echo_subrequest GET @sub; - echo 'post main'; - } - - location @sub { - echo 'pre sub'; - echo_subrequest GET @subsub; - echo 'post sub'; - } - - location @subsub { - echo 'subsub'; - } ---- request - GET /main ---- response_body -pre main -pre sub -subsub -post sub -post main ---- SKIP - - - -=== TEST 11: explicit flush in main request ---- config - location /main { - echo 'pre main'; - echo_subrequest GET /sub; - echo 'post main'; - echo_flush; - } - - location /sub { - echo_sleep 0.02; - echo 'sub'; - } ---- request - GET /main ---- response_body -pre main -sub -post main - - - -=== TEST 12: DELETE subrequest ---- config - location /main { - echo_subrequest DELETE /sub; - } - location /sub { - echo "sub method: $echo_request_method"; - echo "main method: $echo_client_request_method"; - } ---- request - GET /main ---- response_body -sub method: DELETE -main method: GET - - - -=== TEST 13: DELETE subrequest ---- config - location /main { - echo "main method: $echo_client_request_method"; - echo_subrequest GET /proxy; - echo_subrequest DELETE /proxy; - } - location /proxy { - proxy_pass $scheme://127.0.0.1:$server_port/sub; - } - location /sub { - echo "sub method: $echo_request_method"; - } ---- request - GET /main ---- response_body -main method: GET -sub method: GET -sub method: DELETE - - - -=== TEST 14: POST subrequest with body ---- config - location /main { - echo_subrequest POST /sub -b 'hello, world'; - } - location /sub { - echo "sub method: $echo_request_method"; - # we don't need to call echo_read_client_body explicitly here - echo "sub body: $echo_request_body"; - } ---- request - GET /main ---- response_body -sub method: POST -sub body: hello, world - - - -=== TEST 15: POST subrequest with body (explicitly read the body) ---- config - location /main { - echo_subrequest POST /sub -b 'hello, world'; - } - location /sub { - echo "sub method: $echo_request_method"; - # we call echo_read_client_body explicitly here even - # though it's not necessary. - echo_read_request_body; - echo "sub body: $echo_request_body"; - } ---- request - GET /main ---- response_body -sub method: POST -sub body: hello, world - - - -=== TEST 16: POST subrequest with body (with proxy in the middle) and without read body explicitly ---- config - location /main { - echo_subrequest POST /proxy -b 'hello, world'; - } - location /proxy { - proxy_pass $scheme://127.0.0.1:$server_port/sub; - } - location /sub { - echo "sub method: $echo_request_method."; - # we need to read body explicitly here...or $echo_request_body - # will evaluate to empty ("") - echo "sub body: $echo_request_body."; - } ---- request - GET /main ---- response_body -sub method: POST. -sub body: . - - - -=== TEST 17: POST subrequest with body (with proxy in the middle) and read body explicitly ---- config - location /main { - echo_subrequest POST /proxy -b 'hello, world'; - } - location /proxy { - proxy_pass $scheme://127.0.0.1:$server_port/sub; - } - location /sub { - echo "sub method: $echo_request_method."; - # we need to read body explicitly here...or $echo_request_body - # will evaluate to empty ("") - echo_read_request_body; - echo "sub body: $echo_request_body."; - } ---- request - GET /main ---- response_body -sub method: POST. -sub body: hello, world. - - - -=== TEST 18: multiple subrequests ---- config - location /multi { - echo_subrequest POST '/sub' -q 'foo=Foo' -b 'hi'; - echo_subrequest PUT '/sub' -q 'bar=Bar' -b 'hello'; - } - location /sub { - echo "querystring: $query_string"; - echo "method: $echo_request_method"; - echo "body: $echo_request_body"; - echo "content length: $http_content_length"; - echo '///'; - } ---- request - GET /multi ---- response_body -querystring: foo=Foo -method: POST -body: hi -content length: 2 -/// -querystring: bar=Bar -method: PUT -body: hello -content length: 5 -/// - - - -=== TEST 19: unsafe uri ---- config - location /unsafe { - echo_subrequest GET '/../foo'; - } ---- request - GET /unsafe ---- ignore_response ---- error_log -echo_subrequest sees unsafe uri: "/../foo" ---- no_error_log -[error] - - - -=== TEST 20: querystring in url ---- config - location /main { - echo_subrequest GET /sub?foo=Foo&bar=Bar; - } - location /sub { - echo $arg_foo $arg_bar; - } ---- request - GET /main ---- response_body -Foo Bar - - - -=== TEST 21: querystring in url *AND* an explicit querystring ---- config - location /main { - echo_subrequest GET /sub?foo=Foo&bar=Bar -q blah=Blah; - } - location /sub { - echo $arg_foo $arg_bar $arg_blah; - } ---- request - GET /main ---- response_body - Blah - - - -=== TEST 22: let subrequest to read the main request's request body ---- SKIP ---- config - location /main { - echo_subrequest POST /sub; - } - location /sub { - echo_read_request_body; - echo_request_body; - } ---- request -POST /main -hello, body! ---- response_body chomp -hello, body! - - - -=== TEST 23: deep nested echo_subrequest/echo_subrequest_async ---- config - location /main { - echo_subrequest GET /bar; - echo_subrequest_async GET /bar; - echo_subrequest_async GET /bar; - echo_subrequest GET /group; - echo_subrequest_async GET /group; - } - - location /group { - echo_subrequest GET /bar; - echo_subrequest_async GET /bar; - } - - location /bar { - echo $echo_incr; - } ---- request -GET /main ---- response_body -1 -2 -3 -4 -5 -6 -7 - - - -=== TEST 24: deep nested echo_subrequest/echo_subrequest_async ---- config - location /main { - echo_subrequest GET /bar?a; - echo_subrequest_async GET /bar?b; - echo_subrequest_async GET /bar?c; - echo_subrequest GET /group?a=d&b=e; - echo_subrequest_async GET /group?a=f&b=g; - } - - location /group { - echo_subrequest GET /bar?$arg_a; - echo_subrequest_async GET /bar?$arg_b; - } - - location /bar { - echo -n $query_string; - } ---- request -GET /main ---- response_body: abcdefg ---- timeout: 2 - - - -=== TEST 25: POST subrequest with file body (relative paths) ---- config - location /main { - echo_subrequest POST /sub -f html/blah.txt; - } - location /sub { - echo "sub method: $echo_request_method"; - # we don't need to call echo_read_client_body explicitly here - echo_request_body; - } ---- user_files ->>> blah.txt -Hello, world ---- request - GET /main ---- response_body -sub method: POST -Hello, world - - - -=== TEST 26: POST subrequest with file body (absolute paths) ---- config - location /main { - echo_subrequest POST /sub -f $TEST_NGINX_HTML_DIR/blah.txt; - } - location /sub { - echo "sub method: $echo_request_method"; - # we don't need to call echo_read_client_body explicitly here - echo_request_body; - } ---- user_files ->>> blah.txt -Hello, world! -Haha ---- request - GET /main ---- response_body -sub method: POST -Hello, world! -Haha - - - -=== TEST 27: POST subrequest with file body (file not found) ---- config - location /main { - echo_subrequest POST /sub -f html/blah/blah.txt; - } - location /sub { - echo "sub method: $echo_request_method"; - # we don't need to call echo_read_client_body explicitly here - echo_request_body; - } ---- user_files ->>> blah.txt -Hello, world ---- request - GET /main ---- ignore_response ---- error_log eval -qr/open\(\) ".*?" failed/ ---- no_error_log -[alert] - - - -=== TEST 28: leading subrequest & echo_before_body ---- config - location /main { - echo_before_body hello; - echo_subrequest GET /foo; - } - location /foo { - echo world; - } ---- request - GET /main ---- response_body -hello -world - - - -=== TEST 29: leading subrequest & xss ---- config - location /main { - default_type 'application/json'; - xss_get on; - xss_callback_arg c; - echo_subrequest GET /foo; - } - location /foo { - echo -n world; - } ---- request - GET /main?c=hi ---- response_body chop -hi(world); - - - -=== TEST 30: multiple leading subrequest & xss ---- config - location /main { - default_type 'application/json'; - xss_get on; - xss_callback_arg c; - echo_subrequest GET /foo; - echo_subrequest GET /bar; - } - location /foo { - echo -n world; - } - location /bar { - echo -n ' people'; - } ---- request - GET /main?c=hi ---- response_body chop -hi(world people); - - - -=== TEST 31: sanity (HEAD) ---- config - location /main { - echo_subrequest GET /sub; - echo_subrequest GET /sub; - } - location /sub { - echo hello; - } ---- request - HEAD /main ---- response_body - - - -=== TEST 32: POST subrequest to ngx_proxy ---- config - location /hello { - default_type text/plain; - echo_subrequest POST '/proxy' -q 'foo=Foo&bar=baz' -b 'request_body=test&test=3'; - } - - location /proxy { - proxy_pass http://127.0.0.1:$TEST_NGINX_CLIENT_PORT/sub; - #proxy_pass http://127.0.0.1:1113/sub; - } - - location /sub { - echo_read_request_body; - echo "sub method: $echo_request_method"; - # we don't need to call echo_read_client_body explicitly here - echo "sub body: $echo_request_body"; - } ---- request - GET /hello ---- response_body -sub method: POST -sub body: request_body=test&test=3 - - - -=== TEST 33: HEAD subrequest ---- config - location /main { - echo_subrequest HEAD /sub; - echo_subrequest HEAD /sub; - } - location /sub { - echo hello; - } ---- request - GET /main ---- response_body - - - -=== TEST 34: method name as an nginx variable (github issue #34) ---- config - location ~ ^/delay/(?[0-9.]+)/(?.*)$ { - # echo_blocking_sleep $delay; - echo_subrequest '$echo_request_method' '/$originalURL' -q '$args'; - } - - location /api { - echo "args: $args"; - } ---- request - GET /delay/0.343/api/?a=b ---- response_body -args: a=b ---- no_error_log -[error] - diff --git a/debian/modules/http-echo/t/unused.t b/debian/modules/http-echo/t/unused.t deleted file mode 100644 index f3c6e9e..0000000 --- a/debian/modules/http-echo/t/unused.t +++ /dev/null @@ -1,119 +0,0 @@ -# vi:filetype= - -use lib 'lib'; -use Test::Nginx::Socket; - -repeat_each(2); - -plan tests => repeat_each() * (5 * blocks()); - -no_long_string(); -log_level('warn'); - -#master_on(); -#workers(1); - -run_tests(); - -__DATA__ - -=== TEST 1: filters used ---- http_config - postpone_output 1; ---- config - location /echo { - echo world; - echo_after_body hello; - } ---- request - GET /echo?blah ---- response_body -world -hello ---- error_log -echo header filter, uri "/echo?blah" -echo body filter, uri "/echo?blah" ---- no_error_log -[error] ---- log_level: debug - - - -=== TEST 2: filters not used ---- http_config - postpone_output 1; ---- config - location /echo { - echo world; - #echo_after_body hello; - } ---- request - GET /echo?blah ---- response_body -world ---- no_error_log -echo header filter, uri "/echo?blah" -echo body filter, uri "/echo?blah" -[error] ---- log_level: debug - - - -=== TEST 3: (after) filters used (multiple http {} blocks) -This test case won't run with nginx 1.9.3+ since duplicate http {} blocks -have been prohibited since then. ---- SKIP ---- http_config - postpone_output 1; ---- config - location /echo { - echo world; - echo_after_body hello; - } - ---- post_main_config - http { - } - ---- request - GET /echo?blah ---- response_body -world -hello ---- error_log -echo header filter, uri "/echo?blah" -echo body filter, uri "/echo?blah" ---- no_error_log -[error] ---- log_level: debug - - - -=== TEST 4: (before) filters used (multiple http {} blocks) -This test case won't run with nginx 1.9.3+ since duplicate http {} blocks -have been prohibited since then. ---- SKIP ---- http_config - postpone_output 1; ---- config - location /echo { - echo world; - echo_before_body hello; - } - ---- post_main_config - http { - } - ---- request - GET /echo?blah ---- response_body -hello -world ---- error_log -echo header filter, uri "/echo?blah" -echo body filter, uri "/echo?blah" ---- no_error_log -[error] ---- log_level: debug - diff --git a/debian/modules/http-echo/util/build.sh b/debian/modules/http-echo/util/build.sh deleted file mode 100755 index 45949bb..0000000 --- a/debian/modules/http-echo/util/build.sh +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/env bash - -# this file is mostly meant to be used by the author himself. - -root=`pwd` -version=$1 -force=$2 -home=~ - - #--with-cc=gcc46 \ - -ngx-build $force $version \ - --with-ld-opt="-L$PCRE_LIB -Wl,-rpath,$PCRE_LIB:$LIBDRIZZLE_LIB:/usr/local/lib" \ - --with-cc-opt="-DDEBUG_MALLOC" \ - --with-http_stub_status_module \ - --with-http_image_filter_module \ - --without-mail_pop3_module \ - --without-mail_imap_module \ - --without-mail_smtp_module \ - --without-http_upstream_ip_hash_module \ - --without-http_memcached_module \ - --without-http_referer_module \ - --without-http_autoindex_module \ - --without-http_auth_basic_module \ - --without-http_userid_module \ - --add-module=$root/../ndk-nginx-module \ - --add-module=$root/../set-misc-nginx-module \ - --add-module=$root/../eval-nginx-module \ - --add-module=$root/../xss-nginx-module \ - --add-module=$root/../rds-json-nginx-module \ - --add-module=$root/../headers-more-nginx-module \ - --add-module=$root/../lua-nginx-module \ - --add-module=$root $opts \ - --with-http_v2_module \ - --with-select_module \ - --with-poll_module \ - --without-http_ssi_module \ - --with-debug || exit 1 - #--add-module=$root/../lz-session-nginx-module \ - #--add-module=$home/work/ndk \ - #--add-module=$home/work/ndk/examples/http/set_var \ - #--add-module=$root/../eval-nginx-module \ - #--add-module=/home/agentz/work/nginx_eval_module-1.0.1 \ - diff --git a/debian/modules/http-echo/util/releng b/debian/modules/http-echo/util/releng deleted file mode 100755 index b3ad9f2..0000000 --- a/debian/modules/http-echo/util/releng +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -./update-readme -ack '.{81}' src/ngx_http_*.[ch] -ack '(?<=\#define)\s*DDEBUG\s*[12]' src -echo ======================================= -ack '(?<=This document describes echo-nginx-module v)\d+\.\d+' README - diff --git a/debian/modules/http-echo/util/wiki2pod.pl b/debian/modules/http-echo/util/wiki2pod.pl deleted file mode 100644 index cdd33a2..0000000 --- a/debian/modules/http-echo/util/wiki2pod.pl +++ /dev/null @@ -1,131 +0,0 @@ -#!/usr/bin/env perl - -use strict; -use warnings; -use bytes; - -my @nl_counts; -my $last_nl_count_level; - -my @bl_counts; -my $last_bl_count_level; - -sub fmt_pos ($) { - (my $s = $_[0]) =~ s{\#(.*)}{/"$1"}; - $s; -} - -sub fmt_mark ($$) { - my ($tag, $s) = @_; - my $max_level = 0; - while ($s =~ /([<>])\1*/g) { - my $level = length $&; - if ($level > $max_level) { - $max_level = $level; - } - } - - my $times = $max_level + 1; - if ($times > 1) { - $s = " $s "; - } - return $tag . ('<' x $times) . $s . ('>' x $times); -} - -print "=encoding utf-8\n\n"; - -while (<>) { - if ($. == 1) { - # strip the leading U+FEFF byte in MS-DOS text files - my $first = ord(substr($_, 0, 1)); - #printf STDERR "0x%x", $first; - #my $second = ord(substr($_, 2, 1)); - #printf STDERR "0x%x", $second; - if ($first == 0xEF) { - substr($_, 0, 1, ''); - #warn "Hit!"; - } - } - s{\[(http[^ \]]+) ([^\]]*)\]}{$2 (L<$1>)}gi; - s{ \[\[ ( [^\]\|]+ ) \| ([^\]]*) \]\] }{"L<$2|" . fmt_pos($1) . ">"}gixe; - s{(.*?)}{fmt_mark('C', $1)}gie; - s{'''(.*?)'''}{fmt_mark('B', $1)}ge; - s{''(.*?)''}{fmt_mark('I', $1)}ge; - if (s{^\s*<[^>]+>\s*$}{}) { - next; - } - - if (/^\s*$/) { - print "\n"; - next; - } - -=begin cmt - - if ($. == 1) { - warn $_; - for my $i (0..length($_) - 1) { - my $chr = substr($_, $i, 1); - warn "chr ord($i): ".ord($chr)." \"$chr\"\n"; - } - } - -=end cmt -=cut - - if (/(=+) (.*) \1$/) { - #warn "HERE! $_" if $. == 1; - my ($level, $title) = (length $1, $2); - collapse_lists(); - - print "\n=head$level $title\n\n"; - } elsif (/^(\#+) (.*)/) { - my ($level, $txt) = (length($1) - 1, $2); - if (defined $last_nl_count_level && $level != $last_nl_count_level) { - print "\n=back\n\n"; - } - $last_nl_count_level = $level; - $nl_counts[$level] ||= 0; - if ($nl_counts[$level] == 0) { - print "\n=over\n\n"; - } - $nl_counts[$level]++; - print "\n=item $nl_counts[$level].\n\n"; - print "$txt\n"; - } elsif (/^(\*+) (.*)/) { - my ($level, $txt) = (length($1) - 1, $2); - if (defined $last_bl_count_level && $level != $last_bl_count_level) { - print "\n=back\n\n"; - } - $last_bl_count_level = $level; - $bl_counts[$level] ||= 0; - if ($bl_counts[$level] == 0) { - print "\n=over\n\n"; - } - $bl_counts[$level]++; - print "\n=item *\n\n"; - print "$txt\n"; - } else { - collapse_lists(); - print; - } -} - -collapse_lists(); - -sub collapse_lists { - while (defined $last_nl_count_level && $last_nl_count_level >= 0) { - print "\n=back\n\n"; - $last_nl_count_level--; - } - undef $last_nl_count_level; - undef @nl_counts; - - while (defined $last_bl_count_level && $last_bl_count_level >= 0) { - print "\n=back\n\n"; - $last_bl_count_level--; - } - undef $last_bl_count_level; - undef @bl_counts; -} - diff --git a/debian/modules/http-echo/valgrind.suppress b/debian/modules/http-echo/valgrind.suppress deleted file mode 100644 index 975415e..0000000 --- a/debian/modules/http-echo/valgrind.suppress +++ /dev/null @@ -1,53 +0,0 @@ -{ - - Memcheck:Param - epoll_ctl(event) - fun:epoll_ctl -} -{ - - Memcheck:Leak - fun:malloc - fun:ngx_alloc - fun:ngx_event_process_init -} -{ - - Memcheck:Cond - fun:index - fun:expand_dynamic_string_token - fun:_dl_map_object - fun:map_doit - fun:_dl_catch_error - fun:do_preload - fun:dl_main -} -{ - - Memcheck:Leak - match-leak-kinds: definite - fun:malloc - fun:ngx_alloc - fun:ngx_set_environment - fun:ngx_single_process_cycle - fun:main -} -{ - - Memcheck:Leak - match-leak-kinds: definite - fun:malloc - fun:ngx_alloc - fun:ngx_set_environment - fun:ngx_single_process_cycle -} -{ - - Memcheck:Leak - match-leak-kinds: definite - fun:malloc - fun:ngx_alloc - fun:ngx_set_environment - fun:ngx_worker_process_init - fun:ngx_worker_process_cycle -} diff --git a/debian/modules/http-fancyindex/.github/workflows/ci.yml b/debian/modules/http-fancyindex/.github/workflows/ci.yml deleted file mode 100644 index a7bb1f8..0000000 --- a/debian/modules/http-fancyindex/.github/workflows/ci.yml +++ /dev/null @@ -1,40 +0,0 @@ ---- -name: Build -on: [pull_request] - -jobs: - build: - strategy: - fail-fast: false - matrix: - compiler: [gcc, clang] - dynamic: [0, 1] - nginx: - # Mainline - - 1.21.3 - # Stable. - - 1.20.1 - # First version with loadable module support. - - 1.9.15 - # Oldest supported version. - - 0.8.55 - exclude: - - nginx: 0.8.55 - dynamic: 1 - runs-on: ubuntu-18.04 - env: - CFLAGS: "-Wno-error" - steps: - - name: Checkout - uses: actions/checkout@v2 - - name: Install Packages - run: | - sudo apt update - sudo apt install -y libpcre3-dev libssl-dev - t/get-pup || echo 'Tests needing pup will be skipped' - - name: Test - env: - CC: ${{ matrix.compiler }} - run: | - CC=${{ matrix.compiler }} - t/build-and-run ${{ matrix.nginx }} ${{ matrix.dynamic }} diff --git a/debian/modules/http-fancyindex/CHANGELOG.md b/debian/modules/http-fancyindex/CHANGELOG.md deleted file mode 100644 index ebeb379..0000000 --- a/debian/modules/http-fancyindex/CHANGELOG.md +++ /dev/null @@ -1,199 +0,0 @@ -# Change Log -All notable changes to this project will be documented in this file. - -## [Unreleased] - -## [0.5.2] - 2021-10-28 -### Fixed -- Properly escape file names to ensure that file names are never renreded - as HTML. (Patch by Anthony Ryan <>, - [#128](https://github.com/aperezdc/ngx-fancyindex/pull/128).) - -## [0.5.1] - 2020-10-26 -### Fixed -- Properly handle optional second argument to `fancyindex_header` and - `fancyindex_footer` - ([#117](https://github.com/aperezdc/ngx-fancyindex/issues/117)). - -## [0.5.0] - 2020-10-24 -### Added -- New option `fancyindex_show_dotfiles`. (Path by Joshua Shaffer - <>.) -- The `fancyindex_header` and `fancyindex_footer` options now support local - files properly, by means of a `local` flag. (Patches by JoungKyun Kim - <> and Adrián Pérez <>.) - -### Changed -- Improved performance of directory entry sorting, which should be quite - noticeable for directories with thousands of files. (Patch by - [Yuxiang Zhang](https://github.com/z4yx).) -- The minimum Nginx version supported by the module is now 0.8.x. - -### Fixed -- Properly escape square brackets in directory entry names when the module - is built with older versions of Nginx. (Patch by Adrián Pérez - <>.) -- Fix directory entry listing not being shown when using the - [nginx-auth-ldap](https://github.com/kvspb/nginx-auth-ldap) module. (Patch - by JoungKyun Kim <>.) - -## [0.4.4] - 2020-02-19 -### Added -- New option `fancyindex_hide_parent_dir`, which disables generating - links to parent directories in listings. (Patch by Kawai Ryota - <>.) - -### Changed -- Each table row is now separated by a new line (as a matter of fact, - a `CRLF` sequence), which makes it easier to parse output using simple - text tools. (Patch by Anders Trier <>.) -- Some corrections and additions to the README file. (Patches by Nicolas - Carpi <> and David Beitey <>.) - -### Fixed -- Use correct character references for `&` characters in table sorter URLs - within the template (Patch by David Beitey <>.) -- Properly encode filenames when used as URI components. - -## [0.4.3] - 2018-07-03 -### Added -- Table cells now have class names, which allows for better CSS styling. - (Patch by qjqqyy <>.) -- The test suite now can parse and check elements from the HTML returned - by the module, thanks to the [pup](https://github.com/EricChiang/pup) - tool. - -### Fixed -- Sorting by file size now works correctly. - (Patch by qjqqyy <>.) - -## [0.4.2] - 2017-08-19 -### Changed -- Generated HTML from the default template is now proper HTML5, and it should - pass validation (#52). -- File sizes now have decimal positions when using `fancyindex_exact_size off`. - (Patch by Anders Trier <>.) -- Multiple updates to `README.rst` (Patches by Danila Vershinin - <>, Iulian Onofrei, Lilian Besson, and Nick Geoghegan - <>.) - -### Fixed -- Sorting by file size now also works correctly for directories which contain - files of sizes bigger than `INT_MAX`. (#74, fix suggestion by Chris Young.) -- Custom headers which fail to declare an UTF-8 encoding no longer cause table - header arrows to be rendered incorrectly by browsers (#50). -- Fix segmentation fault when opening directories with empty files (#61, patch - by Catgirl <>.) - -## [0.4.1] - 2016-08-18 -### Added -- New `fancyindex_directories_first` configuration directive (enabled by - default), which allows setting whether directories are sorted before other - files. (Patch by Luke Zapart <>.) - -### Fixed -- Fix index files not working when the fancyindex module is in use (#46). - - -## [0.4.0] - 2016-06-08 -### Added -- The module can now be built as a [dynamic - module](https://www.nginx.com/resources/wiki/extending/converting/). - (Patch by Róbert Nagy <>.) -- New configuration directive `fancyindex_show_path`, which allows hiding the - `

` header which contains the current path. - (Patch by Thomas P. <>.) - -### Changed -- Directory and file links in listings now have a title="..." attribute. - (Patch by `@janglapuk` <>.) - -### Fixed -- Fix for hung requests when the module is used along with `ngx_pagespeed`. - (Patch by Otto van der Schaaf <>.) - - -## [0.3.6] - 2016-01-26 -### Added -- New feature: Allow filtering out symbolic links using the - `fancyindex_hide_symlinks` configuration directive. (Idea and prototype - patch by Thomas Wemm.) -- New feature: Allow specifying the format of timestamps using the - `fancyindex_time_format` configuration directive. (Idea suggested by Xiao - Meng <>). - -### Changed -- Listings in top-level directories will not generate a "Parent Directory" - link as first element of the listing. (Patch by Thomas P.) - -### Fixed -- Fix propagation and overriding of the `fancyindex_css_href` setting inside - nested locations. -- Minor changes in the code to allow building cleanly under Windows with - Visual Studio 2013. (Patch by Y. Yuan <>). - - -## [0.3.5] - 2015-02-19 -### Added -- New feature: Allow setting the default sort criterion using the - `fancyindex_default_sort` configuration directive. (Patch by - Алексей Урбанский). -- New feature: Allow changing the maximum length of file names, using - the `fancyindex_name_length` configuration directive. (Patch by - Martin Herkt). - -### Changed -- Renames `NEWS.rst` to `CHANGELOG.md`, which follows the recommendations - from [Keep a Change Log](http://keepachangelog.com/). -- Configuring Nginx without the `http_addition_module` will generate a - warning during configuration, as it is needed for the `fancyindex_footer` - and `fancyindex_header` directives. - - -## [0.3.4] - 2014-09-03 - -### Added -- Viewport is now defined in the generated HTML, which works better - for mobile devices. - -### Changed -- Even-odd row styling moved to the CSS using :nth-child(). This - makes the HTML served to clients smaller. - - -## [0.3.3] - 2013-10-25 - -### Added -- New feature: table headers in the default template are now clickable - to set the sorting criteria and direction of the index entries. - (https://github.com/aperezdc/ngx-fancyindex/issues/7) - - -## [0.3.2] - 2013-06-05 - -### Fixed -- Solved a bug that would leave certain clients stalled forever. -- Improved handling of subrequests for non-builtin headers/footers. - - -## [0.3.1] - 2011-04-04 - -### Added -- `NEWS.rst` file, to act as change log. - - -[Unreleased]: https://github.com/aperezdc/ngx-fancyindex/compare/v0.5.2...HEAD -[0.5.2]: https://github.com/aperezdc/ngx-fancyindex/compare/v0.5.1...v0.5.2 -[0.5.1]: https://github.com/aperezdc/ngx-fancyindex/compare/v0.5.0...v0.5.1 -[0.5.0]: https://github.com/aperezdc/ngx-fancyindex/compare/v0.4.4...v0.5.0 -[0.4.4]: https://github.com/aperezdc/ngx-fancyindex/compare/v0.4.3...v0.4.4 -[0.4.3]: https://github.com/aperezdc/ngx-fancyindex/compare/v0.4.2...v0.4.3 -[0.4.2]: https://github.com/aperezdc/ngx-fancyindex/compare/v0.4.1...v0.4.2 -[0.4.1]: https://github.com/aperezdc/ngx-fancyindex/compare/v0.4.0...v0.4.1 -[0.4.0]: https://github.com/aperezdc/ngx-fancyindex/compare/v0.3.6...v0.4.0 -[0.3.6]: https://github.com/aperezdc/ngx-fancyindex/compare/v0.3.5...v0.3.6 -[0.3.5]: https://github.com/aperezdc/ngx-fancyindex/compare/v0.3.4...v0.3.5 -[0.3.4]: https://github.com/aperezdc/ngx-fancyindex/compare/v0.3.3...v0.3.4 -[0.3.3]: https://github.com/aperezdc/ngx-fancyindex/compare/v0.3.2...v0.3.3 -[0.3.2]: https://github.com/aperezdc/ngx-fancyindex/compare/v0.3.1...v0.3.2 -[0.3.1]: https://github.com/aperezdc/ngx-fancyindex/compare/v0.3...v0.3.1 diff --git a/debian/modules/http-fancyindex/HACKING.md b/debian/modules/http-fancyindex/HACKING.md deleted file mode 100644 index 4c8608a..0000000 --- a/debian/modules/http-fancyindex/HACKING.md +++ /dev/null @@ -1,29 +0,0 @@ -# Fancy Index module Hacking HOW-TO - -## How to modify the template - -The template is in the `template.html` file. Note that comment markers are -used to control how the `template.awk` Awk script generates the C header -which gets ultimately included in the compiled object code. Comment markers -have the `` format. Here `identifier` must be -a valid C identifier. All the text following the marker until the next -marker will be flattened into a C string. - -If the identifier is `NONE` (capitalized) the text from that marker up to -the next marker will be discarded. - - -## Regenerating the C header - -You will need Awk. I hope any decent implementation will do, but the GNU one -is known to work flawlessly. Just do: - - $ awk -f template.awk template.html > template.h - -If your copy of `awk` is not the GNU implementation, you will need to -install it and use `gawk` instead in the command line above. - -This includes macOS where the current built-in `awk` (currently version -20070501 at time of testing on 10.13.6) doesn't apply correctly and causes -characters to be omitted from the output. `gawk` can be installed with a -package manager such as [Homebrew](https://brew.sh). diff --git a/debian/modules/http-fancyindex/LICENSE b/debian/modules/http-fancyindex/LICENSE deleted file mode 100644 index 9fd66ee..0000000 --- a/debian/modules/http-fancyindex/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -SUCH DAMAGE. diff --git a/debian/modules/http-fancyindex/README.rst b/debian/modules/http-fancyindex/README.rst deleted file mode 100644 index c61a6a4..0000000 --- a/debian/modules/http-fancyindex/README.rst +++ /dev/null @@ -1,319 +0,0 @@ -======================== -Nginx Fancy Index module -======================== - -.. image:: https://travis-ci.com/aperezdc/ngx-fancyindex.svg?branch=master - :target: https://travis-ci.com/aperezdc/ngx-fancyindex - :alt: Build Status - -.. contents:: - -The Fancy Index module makes possible the generation of file listings, like -the built-in `autoindex `__ -module does, but adding a touch of style. This is possible because the module -allows a certain degree of customization of the generated content: - -* Custom headers. Either local or stored remotely. -* Custom footers. Either local or stored remotely. -* Add you own CSS style rules. -* Allow choosing to sort elements by name (default), modification time, or - size; both ascending (default), or descending. - -This module is designed to work with Nginx_, a high performance open source web -server written by `Igor Sysoev `__. - - -Requirements -============ - -CentOS 7 -~~~~~~~~ - -For users of the `official stable `__ Nginx repository, `extra packages repository with dynamic modules `__ is available and fancyindex is included. - -Install directly:: - - yum install https://extras.getpagespeed.com/redhat/7/x86_64/RPMS/nginx-module-fancyindex-1.12.0.0.4.1-1.el7.gps.x86_64.rpm - -Alternatively, add extras repository first (for future updates) and install the module:: - - yum install nginx-module-fancyindex - -Then load the module in `/etc/nginx/nginx.conf` using:: - - load_module "modules/ngx_http_fancyindex_module.so"; - -Other platforms -~~~~~~~~~~~~~~~ - -In most other cases you will need the sources for Nginx_. Any version starting -from the 0.8 series should work. - -In order to use the ``fancyindex_header_`` and ``fancyindex_footer_`` directives -you will also need the `ngx_http_addition_module `_ -built into Nginx. - - -Building -======== - -1. Unpack the Nginx_ sources:: - - $ gunzip -c nginx-?.?.?.tar.gz | tar -xvf - - -2. Unpack the sources for the fancy indexing module:: - - $ gunzip -c nginx-fancyindex-?.?.?.tar.gz | tar -xvf - - -3. Change to the directory which contains the Nginx_ sources, run the - configuration script with the desired options and be sure to put an - ``--add-module`` flag pointing to the directory which contains the source - of the fancy indexing module:: - - $ cd nginx-?.?.? - $ ./configure --add-module=../nginx-fancyindex-?.?.? \ - [--with-http_addition_module] [extra desired options] - - Since version 0.4.0, the module can also be built as a - `dynamic module `_, - using ``--add-dynamic-module=…`` instead and - ``load_module "modules/ngx_http_fancyindex_module.so";`` - in the configuration file - -4. Build and install the software:: - - $ make - - And then, as ``root``:: - - # make install - -5. Configure Nginx_ by using the modules' configuration directives_. - - -Example -======= - -You can test the default built-in style by adding the following lines into -a ``server`` section in your Nginx_ configuration file:: - - location / { - fancyindex on; # Enable fancy indexes. - fancyindex_exact_size off; # Output human-readable file sizes. - } - - -Themes -~~~~~~ - -The following themes demonstrate the level of customization which can be -achieved using the module: - -* `Theme `__ by - `@TheInsomniac `__. Uses custom header and - footer. -* `Theme `__ by - `@Naereen `__. Uses custom header and footer, the - header includes search field to filter by filename using JavaScript. -* `Theme `__ by - `@fraoustin `__. Responsive theme using - Material Design elements. -* `Theme `__ by - `@alehaa `__. Simple, flat theme based on - Bootstrap 4 and FontAwesome. - - -Directives -========== - -fancyindex -~~~~~~~~~~ -:Syntax: *fancyindex* [*on* | *off*] -:Default: fancyindex off -:Context: http, server, location -:Description: - Enables or disables fancy directory indexes. - -fancyindex_default_sort -~~~~~~~~~~~~~~~~~~~~~~~ -:Syntax: *fancyindex_default_sort* [*name* | *size* | *date* | *name_desc* | *size_desc* | *date_desc*] -:Default: fancyindex_default_sort name -:Context: http, server, location -:Description: - Defines sorting criterion by default. - -fancyindex_directories_first -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -:Syntax: *fancyindex_directories_first* [*on* | *off*] -:Default: fancyindex_directories_first on -:Context: http, server, location -:Description: - If enabled (default setting), groups directories together and sorts them - before all regular files. If disabled, directories are sorted together with files. - -fancyindex_css_href -~~~~~~~~~~~~~~~~~~~ -:Syntax: *fancyindex_css_href uri* -:Default: fancyindex_css_href "" -:Context: http, server, location -:Description: - Allows inserting a link to a CSS style sheet in generated listings. The - provided *uri* parameter will be inserted as-is in a ```` HTML tag. - The link is inserted after the built-in CSS rules, so you can override the - default styles. - -fancyindex_exact_size -~~~~~~~~~~~~~~~~~~~~~ -:Syntax: *fancyindex_exact_size* [*on* | *off*] -:Default: fancyindex_exact_size on -:Context: http, server, location -:Description: - Defines how to represent file sizes in the directory listing; either - accurately, or rounding off to the kilobyte, the megabyte and the - gigabyte. - -fancyindex_name_length -~~~~~~~~~~~~~~~~~~~~~~ -:Syntax: *fancyindex_name_length length* -:Default: fancyindex_name_length 50 -:Context: http, server, location -:Description: - Defines the maximum file name length limit in bytes. - -fancyindex_footer -~~~~~~~~~~~~~~~~~ -:Syntax: *fancyindex_footer path* [*subrequest* | *local*] -:Default: fancyindex_footer "" -:Context: http, server, location -:Description: - Specifies which file should be inserted at the foot of directory listings. - If set to an empty string, the default footer supplied by the module will - be sent. The optional parameter indicates whether the *path* is to be - treated as an URI to load using a *subrequest* (the default), or whether - it refers to a *local* file. - -.. note:: Using this directive needs the ngx_http_addition_module_ built - into Nginx. - -.. warning:: When inserting custom header/footer a subrequest will be - issued so potentially any URL can be used as source for them. Although it - will work with external URLs, only using internal ones is supported. - External URLs are totally untested and using them will make Nginx_ block - while waiting for the subrequest to complete. If you feel like external - header/footer is a must-have for you, please - `let me know `__. - -fancyindex_header -~~~~~~~~~~~~~~~~~ -:Syntax: *fancyindex_header path* [*subrequest* | *local*] -:Default: fancyindex_header "" -:Context: http, server, location -:Description: - Specifies which file should be inserted at the head of directory listings. - If set to an empty string, the default header supplied by the module will - be sent. The optional parameter indicates whether the *path* is to be - treated as an URI to load using a *subrequest* (the default), or whether - it refers to a *local* file. - -.. note:: Using this directive needs the ngx_http_addition_module_ built - into Nginx. - -fancyindex_show_path -~~~~~~~~~~~~~~~~~~~~ -:Syntax: *fancyindex_show_path* [*on* | *off*] -:Default: fancyindex_show_path on -:Context: http, server, location -:Description: - Whether to output or not the path and the closing

tag after the header. - This is useful when you want to handle the path displaying with a PHP script - for example. - -.. warning:: This directive can be turned off only if a custom header is provided - using fancyindex_header. - -fancyindex_show_dotfiles -~~~~~~~~~~~~~~~~~~~~ -:Syntax: *fancyindex_show_dotfiles* [*on* | *off*] -:Default: fancyindex_show_dotfiles off -:Context: http, server, location -:Description: - Whether to list files that are proceeded with a dot. Normal convention is to - hide these. - -fancyindex_ignore -~~~~~~~~~~~~~~~~~ -:Syntax: *fancyindex_ignore string1 [string2 [... stringN]]* -:Default: No default. -:Context: http, server, location -:Description: - Specifies a list of file names which will be not be shown in generated - listings. If Nginx was built with PCRE support strings are interpreted as - regular expressions. - -fancyindex_hide_symlinks -~~~~~~~~~~~~~~~~~~~~~~~~ -:Syntax: *fancyindex_hide_symlinks* [*on* | *off*] -:Default: fancyindex_hide_symlinks off -:Context: http, server, location -:Description: - When enabled, generated listings will not contain symbolic links. - -fancyindex_hide_parent_dir -~~~~~~~~~~~~~~~~~~~~~~~~ -:Syntax: *fancyindex_hide_parent_dir* [*on* | *off*] -:Default: fancyindex_hide_parent_dir off -:Context: http, server, location -:Description: - When enabled, it will not show parent directory. - -fancyindex_localtime -~~~~~~~~~~~~~~~~~~~~ -:Syntax: *fancyindex_localtime* [*on* | *off*] -:Default: fancyindex_localtime off -:Context: http, server, location -:Description: - Enables showing file times as local time. Default is “off” (GMT time). - -fancyindex_time_format -~~~~~~~~~~~~~~~~~~~~~~ -:Syntax: *fancyindex_time_format* string -:Default: fancyindex_time_format "%Y-%b-%d %H:%M" -:Context: http, server, location -:Description: - Format string used for timestamps. The format specifiers are a subset of - those supported by the `strftime `_ - function, and the behavior is locale-independent (for example, day and month - names are always in English). The supported formats are: - - * ``%a``: Abbreviated name of the day of the week. - * ``%A``: Full name of the day of the week. - * ``%b``: Abbreviated month name. - * ``%B``: Full month name. - * ``%d``: Day of the month as a decimal number (range 01 to 31). - * ``%e``: Like ``%d``, the day of the month as a decimal number, but a - leading zero is replaced by a space. - * ``%F``: Equivalent to ``%Y-%m-%d`` (the ISO 8601 date format). - * ``%H``: Hour as a decimal number using a 24-hour clock (range 00 - to 23). - * ``%I``: Hour as a decimal number using a 12-hour clock (range 01 to 12). - * ``%k``: Hour (24-hour clock) as a decimal number (range 0 to 23); - single digits are preceded by a blank. - * ``%l``: Hour (12-hour clock) as a decimal number (range 1 to 12); single - digits are preceded by a blank. - * ``%m``: Month as a decimal number (range 01 to 12). - * ``%M``: Minute as a decimal number (range 00 to 59). - * ``%p``: Either "AM" or "PM" according to the given time value. - * ``%P``: Like ``%p`` but in lowercase: "am" or "pm". - * ``%r``: Time in a.m. or p.m. notation. Equivalent to ``%I:%M:%S %p``. - * ``%R``: Time in 24-hour notation (``%H:%M``). - * ``%S``: Second as a decimal number (range 00 to 60). - * ``%T``: Time in 24-hour notation (``%H:%M:%S``). - * ``%u``: Day of the week as a decimal, range 1 to 7, Monday being 1. - * ``%w``: Day of the week as a decimal, range 0 to 6, Monday being 0. - * ``%y``: Year as a decimal number without a century (range 00 to 99). - * ``%Y``: Year as a decimal number including the century. - - -.. _nginx: https://nginx.org - -.. vim:ft=rst:spell:spelllang=en: diff --git a/debian/modules/http-fancyindex/config b/debian/modules/http-fancyindex/config deleted file mode 100644 index 4ef3809..0000000 --- a/debian/modules/http-fancyindex/config +++ /dev/null @@ -1,20 +0,0 @@ -# vim:ft=sh: -ngx_addon_name=ngx_http_fancyindex_module - -if [ "$ngx_module_link" = DYNAMIC ] ; then - ngx_module_type=HTTP - ngx_module_name=ngx_http_fancyindex_module - ngx_module_srcs="$ngx_addon_dir/ngx_http_fancyindex_module.c" - ngx_module_deps="$ngx_addon_dir/template.h" - ngx_module_order="$ngx_module_name ngx_http_autoindex_module" - . auto/module -else - # XXX: Insert fancyindex module *after* index module! - # - HTTP_MODULES=`echo "${HTTP_MODULES}" | sed -e \ - 's/ngx_http_index_module/ngx_http_fancyindex_module ngx_http_index_module/'` - NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_fancyindex_module.c" - if [ $HTTP_ADDITION != YES ] ; then - echo " - The 'addition' filter is needed for fancyindex_{header,footer}, but it was disabled" - fi -fi diff --git a/debian/modules/http-fancyindex/ngx_http_fancyindex_module.c b/debian/modules/http-fancyindex/ngx_http_fancyindex_module.c deleted file mode 100644 index d5f1722..0000000 --- a/debian/modules/http-fancyindex/ngx_http_fancyindex_module.c +++ /dev/null @@ -1,1615 +0,0 @@ -/* - * ngx_http_fancyindex_module.c - * Copyright © 2007-2016 Adrian Perez - * - * Module used for fancy indexing of directories. Features and differences - * with the stock nginx autoindex module: - * - * - Output is a table instead of a
 element with embedded  links.
- *  - Header and footer may be added to every generated directory listing.
- *  - Default header and/or footer are generated if custom ones are not
- *    configured. Files used for header and footer can only be local path
- *    names (i.e. you cannot insert the result of a subrequest.)
- *  - Proper HTML is generated: it should validate both as XHTML 1.0 Strict
- *    and HTML 4.01.
- *
- * Base functionality heavy based upon the stock nginx autoindex module,
- * which in turn was made by Igor Sysoev, like the majority of nginx.
- *
- * Distributed under terms of the BSD license.
- */
-
-#include 
-#include 
-#include 
-#include 
-
-#include "template.h"
-
-#if defined(__GNUC__) && (__GNUC__ >= 3)
-# define ngx_force_inline __attribute__((__always_inline__))
-#else /* !__GNUC__ */
-# define ngx_force_inline
-#endif /* __GNUC__ */
-
-
-static const char *short_weekday[] = {
-    "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun",
-};
-static const char *long_weekday[] = {
-    "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Sunday",
-};
-static const char *short_month[] = {
-    "Jan", "Feb", "Mar", "Apr", "May", "Jun",
-    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
-};
-static const char *long_month[] = {
-    "January", "February", "March", "April", "May", "June", "July",
-    "August", "September", "October", "November", "December",
-};
-
-
-#define DATETIME_FORMATS(F_, t) \
-    F_ ('a',  3, "%3s",  short_weekday[((t)->ngx_tm_wday + 6) % 7]) \
-    F_ ('A',  9, "%s",   long_weekday [((t)->ngx_tm_wday + 6) % 7]) \
-    F_ ('b',  3, "%3s",  short_month[(t)->ngx_tm_mon - 1]         ) \
-    F_ ('B',  9, "%s",   long_month [(t)->ngx_tm_mon - 1]         ) \
-    F_ ('d',  2, "%02d", (t)->ngx_tm_mday                         ) \
-    F_ ('e',  2, "%2d",  (t)->ngx_tm_mday                         ) \
-    F_ ('F', 10, "%d-%02d-%02d",                                    \
-                  (t)->ngx_tm_year,                                 \
-                  (t)->ngx_tm_mon,                                  \
-                  (t)->ngx_tm_mday                                ) \
-    F_ ('H',  2, "%02d", (t)->ngx_tm_hour                         ) \
-    F_ ('I',  2, "%02d", ((t)->ngx_tm_hour % 12) + 1              ) \
-    F_ ('k',  2, "%2d",  (t)->ngx_tm_hour                         ) \
-    F_ ('l',  2, "%2d",  ((t)->ngx_tm_hour % 12) + 1              ) \
-    F_ ('m',  2, "%02d", (t)->ngx_tm_mon                          ) \
-    F_ ('M',  2, "%02d", (t)->ngx_tm_min                          ) \
-    F_ ('p',  2, "%2s",  (((t)->ngx_tm_hour < 12) ? "AM" : "PM")  ) \
-    F_ ('P',  2, "%2s",  (((t)->ngx_tm_hour < 12) ? "am" : "pm")  ) \
-    F_ ('r', 11, "%02d:%02d:%02d %2s",                              \
-                 ((t)->ngx_tm_hour % 12) + 1,                       \
-                 (t)->ngx_tm_min,                                   \
-                 (t)->ngx_tm_sec,                                   \
-                 (((t)->ngx_tm_hour < 12) ? "AM" : "PM")          ) \
-    F_ ('R',  5, "%02d:%02d", (t)->ngx_tm_hour, (t)->ngx_tm_min   ) \
-    F_ ('S',  2, "%02d", (t)->ngx_tm_sec                          ) \
-    F_ ('T',  8, "%02d:%02d:%02d",                                  \
-                 (t)->ngx_tm_hour,                                  \
-                 (t)->ngx_tm_min,                                   \
-                 (t)->ngx_tm_sec                                  ) \
-    F_ ('u',  1, "%1d", (((t)->ngx_tm_wday + 6) % 7) + 1          ) \
-    F_ ('w',  1, "%1d", ((t)->ngx_tm_wday + 6) % 7                ) \
-    F_ ('y',  2, "%02d", (t)->ngx_tm_year % 100                   ) \
-    F_ ('Y',  4, "%04d", (t)->ngx_tm_year                         )
-
-
-static size_t
-ngx_fancyindex_timefmt_calc_size (const ngx_str_t *fmt)
-{
-#define DATETIME_CASE(letter, fmtlen, fmt, ...) \
-        case letter: result += (fmtlen); break;
-
-    size_t i, result = 0;
-    for (i = 0; i < fmt->len; i++) {
-        if (fmt->data[i] == '%') {
-            if (++i >= fmt->len) {
-                result++;
-                break;
-            }
-            switch (fmt->data[i]) {
-                DATETIME_FORMATS(DATETIME_CASE,)
-                default:
-                    result++;
-            }
-        } else {
-            result++;
-        }
-    }
-    return result;
-
-#undef DATETIME_CASE
-}
-
-
-static u_char*
-ngx_fancyindex_timefmt (u_char *buffer, const ngx_str_t *fmt, const ngx_tm_t *tm)
-{
-#define DATETIME_CASE(letter, fmtlen, fmt, ...) \
-        case letter: buffer = ngx_snprintf(buffer, fmtlen, fmt, ##__VA_ARGS__); break;
-
-    size_t i;
-    for (i = 0; i < fmt->len; i++) {
-        if (fmt->data[i] == '%') {
-            if (++i >= fmt->len) {
-                *buffer++ = '%';
-                break;
-            }
-            switch (fmt->data[i]) {
-                DATETIME_FORMATS(DATETIME_CASE, tm)
-                default:
-                    *buffer++ = fmt->data[i];
-            }
-        } else {
-            *buffer++ = fmt->data[i];
-        }
-    }
-    return buffer;
-
-#undef DATETIME_CASE
-}
-
-typedef struct {
-    ngx_str_t path;
-    ngx_str_t local;
-} ngx_fancyindex_headerfooter_conf_t;
-
-/**
- * Configuration structure for the fancyindex module. The configuration
- * commands defined in the module do fill in the members of this structure.
- */
-typedef struct {
-    ngx_flag_t enable;         /**< Module is enabled. */
-    ngx_uint_t default_sort;   /**< Default sort criterion. */
-    ngx_flag_t dirs_first;     /**< Group directories together first when sorting */
-    ngx_flag_t localtime;      /**< File mtime dates are sent in local time. */
-    ngx_flag_t exact_size;     /**< Sizes are sent always in bytes. */
-    ngx_uint_t name_length;    /**< Maximum length of file names in bytes. */
-    ngx_flag_t hide_symlinks;  /**< Hide symbolic links in listings. */
-    ngx_flag_t show_path;      /**< Whether to display or not the path + '' after the header */
-    ngx_flag_t hide_parent;    /**< Hide parent directory. */
-    ngx_flag_t show_dot_files; /**< Show files that start with a dot.*/
-
-    ngx_str_t  css_href;       /**< Link to a CSS stylesheet, or empty if none. */
-    ngx_str_t  time_format;    /**< Format used for file timestamps. */
-
-    ngx_array_t *ignore;       /**< List of files to ignore in listings. */
-
-    ngx_fancyindex_headerfooter_conf_t header;
-    ngx_fancyindex_headerfooter_conf_t footer;
-} ngx_http_fancyindex_loc_conf_t;
-
-#define NGX_HTTP_FANCYINDEX_SORT_CRITERION_NAME       0
-#define NGX_HTTP_FANCYINDEX_SORT_CRITERION_SIZE       1
-#define NGX_HTTP_FANCYINDEX_SORT_CRITERION_DATE       2
-#define NGX_HTTP_FANCYINDEX_SORT_CRITERION_NAME_DESC  3
-#define NGX_HTTP_FANCYINDEX_SORT_CRITERION_SIZE_DESC  4
-#define NGX_HTTP_FANCYINDEX_SORT_CRITERION_DATE_DESC  5
-
-static ngx_conf_enum_t ngx_http_fancyindex_sort_criteria[] = {
-    { ngx_string("name"), NGX_HTTP_FANCYINDEX_SORT_CRITERION_NAME },
-    { ngx_string("size"), NGX_HTTP_FANCYINDEX_SORT_CRITERION_SIZE },
-    { ngx_string("date"), NGX_HTTP_FANCYINDEX_SORT_CRITERION_DATE },
-    { ngx_string("name_desc"), NGX_HTTP_FANCYINDEX_SORT_CRITERION_NAME_DESC },
-    { ngx_string("size_desc"), NGX_HTTP_FANCYINDEX_SORT_CRITERION_SIZE_DESC },
-    { ngx_string("date_desc"), NGX_HTTP_FANCYINDEX_SORT_CRITERION_DATE_DESC },
-    { ngx_null_string, 0 }
-};
-
-enum {
-    NGX_HTTP_FANCYINDEX_HEADERFOOTER_SUBREQUEST,
-    NGX_HTTP_FANCYINDEX_HEADERFOOTER_LOCAL,
-};
-
-static ngx_uint_t
-headerfooter_kind(const ngx_str_t *value)
-{
-    static const struct {
-        ngx_str_t name;
-        ngx_uint_t value;
-    } values[] = {
-        { ngx_string("subrequest"), NGX_HTTP_FANCYINDEX_HEADERFOOTER_SUBREQUEST },
-        { ngx_string("local"), NGX_HTTP_FANCYINDEX_HEADERFOOTER_LOCAL },
-    };
-
-    unsigned i;
-
-    for (i = 0; i < sizeof(values) / sizeof(values[0]); i++) {
-        if (value->len == values[i].name.len &&
-            ngx_strcasecmp(value->data, values[i].name.data) == 0)
-        {
-            return values[i].value;
-        }
-    }
-
-    return NGX_CONF_UNSET_UINT;
-}
-
-static char*
-ngx_fancyindex_conf_set_headerfooter(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
-{
-    ngx_fancyindex_headerfooter_conf_t *item =
-        (void*) (((char*) conf) + cmd->offset);
-    ngx_str_t *values = cf->args->elts;
-
-    if (item->path.data)
-        return "is duplicate";
-
-    item->path = values[1];
-
-    /* Kind of path. Default is "subrequest". */
-    ngx_uint_t kind = NGX_HTTP_FANCYINDEX_HEADERFOOTER_SUBREQUEST;
-    if (cf->args->nelts == 3) {
-        kind = headerfooter_kind(&values[2]);
-        if (kind == NGX_CONF_UNSET_UINT) {
-            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                               "unknown header/footer kind \"%V\"", &values[2]);
-            return NGX_CONF_ERROR;
-        }
-    }
-
-    if (kind == NGX_HTTP_FANCYINDEX_HEADERFOOTER_LOCAL) {
-        ngx_file_t file;
-        ngx_file_info_t fi;
-        ssize_t n;
-
-        ngx_memzero(&file, sizeof(ngx_file_t));
-        file.log = cf->log;
-        file.fd = ngx_open_file(item->path.data, NGX_FILE_RDONLY, 0, 0);
-        if (file.fd == NGX_INVALID_FILE) {
-            ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno,
-                               "cannot open file \"%V\"", &values[1]);
-            return NGX_CONF_ERROR;
-        }
-
-        if (ngx_fd_info(file.fd, &fi) == NGX_FILE_ERROR) {
-            ngx_close_file(file.fd);
-            ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno,
-                               "cannot get info for file \"%V\"", &values[1]);
-            return NGX_CONF_ERROR;
-        }
-
-        item->local.len = ngx_file_size(&fi);
-        item->local.data = ngx_pcalloc(cf->pool, item->local.len + 1);
-        if (item->local.data == NULL) {
-            ngx_close_file(file.fd);
-            return NGX_CONF_ERROR;
-        }
-
-        n = item->local.len;
-        while (n > 0) {
-            ssize_t r = ngx_read_file(&file,
-                                      item->local.data + file.offset,
-                                      n,
-                                      file.offset);
-            if (r == NGX_ERROR) {
-                ngx_close_file(file.fd);
-                ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno,
-                                   "cannot read file \"%V\"", &values[1]);
-                return NGX_CONF_ERROR;
-            }
-
-            n -= r;
-        }
-        item->local.data[item->local.len] = '\0';
-    }
-
-    return NGX_CONF_OK;
-}
-
-#define NGX_HTTP_FANCYINDEX_PREALLOCATE  50
-
-
-/**
- * Calculates the length of a NULL-terminated string. It is ugly having to
- * remember to substract 1 from the sizeof result.
- */
-#define ngx_sizeof_ssz(_s)  (sizeof(_s) - 1)
-
-/**
- * Compute the length of a statically allocated array
- */
-#define DIM(x) (sizeof(x)/sizeof(*(x)))
-
-/**
- * Copy a static zero-terminated string. Useful to output template
- * string pieces into a temporary buffer.
- */
-#define ngx_cpymem_ssz(_p, _t) \
-	(ngx_cpymem((_p), (_t), sizeof(_t) - 1))
-
-/**
- * Copy a ngx_str_t.
- */
-#define ngx_cpymem_str(_p, _s) \
-	(ngx_cpymem((_p), (_s).data, (_s).len))
-
-/**
- * Check whether a particular bit is set in a particular value.
- */
-#define ngx_has_flag(_where, _what) \
-	(((_where) & (_what)) == (_what))
-
-
-
-
-typedef struct {
-    ngx_str_t      name;
-    size_t         utf_len;
-    ngx_uint_t     escape;
-    ngx_uint_t     escape_html;
-    ngx_uint_t     dir;
-    time_t         mtime;
-    off_t          size;
-} ngx_http_fancyindex_entry_t;
-
-
-
-static int ngx_libc_cdecl
-    ngx_http_fancyindex_cmp_entries_name_desc(const void *one, const void *two);
-static int ngx_libc_cdecl
-    ngx_http_fancyindex_cmp_entries_size_desc(const void *one, const void *two);
-static int ngx_libc_cdecl
-    ngx_http_fancyindex_cmp_entries_mtime_desc(const void *one, const void *two);
-static int ngx_libc_cdecl
-    ngx_http_fancyindex_cmp_entries_name_asc(const void *one, const void *two);
-static int ngx_libc_cdecl
-    ngx_http_fancyindex_cmp_entries_size_asc(const void *one, const void *two);
-static int ngx_libc_cdecl
-    ngx_http_fancyindex_cmp_entries_mtime_asc(const void *one, const void *two);
-
-static ngx_int_t ngx_http_fancyindex_error(ngx_http_request_t *r,
-    ngx_dir_t *dir, ngx_str_t *name);
-
-static ngx_int_t ngx_http_fancyindex_init(ngx_conf_t *cf);
-
-static void *ngx_http_fancyindex_create_loc_conf(ngx_conf_t *cf);
-
-static char *ngx_http_fancyindex_merge_loc_conf(ngx_conf_t *cf,
-    void *parent, void *child);
-
-static char *ngx_http_fancyindex_ignore(ngx_conf_t    *cf,
-                                        ngx_command_t *cmd,
-                                        void          *conf);
-
-static uintptr_t
-    ngx_fancyindex_escape_filename(u_char *dst, u_char*src, size_t size);
-
-/*
- * These are used only once per handler invocation. We can tell GCC to
- * inline them always, if possible (see how ngx_force_inline is defined
- * above).
- */
-static ngx_inline ngx_buf_t*
-    make_header_buf(ngx_http_request_t *r, const ngx_str_t css_href)
-    ngx_force_inline;
-
-
-static ngx_command_t  ngx_http_fancyindex_commands[] = {
-
-    { ngx_string("fancyindex"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
-      ngx_conf_set_flag_slot,
-      NGX_HTTP_LOC_CONF_OFFSET,
-      offsetof(ngx_http_fancyindex_loc_conf_t, enable),
-      NULL },
-
-    { ngx_string("fancyindex_default_sort"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
-      ngx_conf_set_enum_slot,
-      NGX_HTTP_LOC_CONF_OFFSET,
-      offsetof(ngx_http_fancyindex_loc_conf_t, default_sort),
-      &ngx_http_fancyindex_sort_criteria },
-
-    { ngx_string("fancyindex_directories_first"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
-      ngx_conf_set_flag_slot,
-      NGX_HTTP_LOC_CONF_OFFSET,
-      offsetof(ngx_http_fancyindex_loc_conf_t, dirs_first),
-      NULL },
-
-    { ngx_string("fancyindex_localtime"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
-      ngx_conf_set_flag_slot,
-      NGX_HTTP_LOC_CONF_OFFSET,
-      offsetof(ngx_http_fancyindex_loc_conf_t, localtime),
-      NULL },
-
-    { ngx_string("fancyindex_exact_size"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
-      ngx_conf_set_flag_slot,
-      NGX_HTTP_LOC_CONF_OFFSET,
-      offsetof(ngx_http_fancyindex_loc_conf_t, exact_size),
-      NULL },
-
-    { ngx_string("fancyindex_name_length"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
-      ngx_conf_set_num_slot,
-      NGX_HTTP_LOC_CONF_OFFSET,
-      offsetof(ngx_http_fancyindex_loc_conf_t, name_length),
-      NULL },
-
-    { ngx_string("fancyindex_header"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12,
-      ngx_fancyindex_conf_set_headerfooter,
-      NGX_HTTP_LOC_CONF_OFFSET,
-      offsetof(ngx_http_fancyindex_loc_conf_t, header),
-      NULL },
-
-    { ngx_string("fancyindex_footer"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12,
-      ngx_fancyindex_conf_set_headerfooter,
-      NGX_HTTP_LOC_CONF_OFFSET,
-      offsetof(ngx_http_fancyindex_loc_conf_t, footer),
-      NULL },
-
-    { ngx_string("fancyindex_css_href"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
-      ngx_conf_set_str_slot,
-      NGX_HTTP_LOC_CONF_OFFSET,
-      offsetof(ngx_http_fancyindex_loc_conf_t, css_href),
-      NULL },
-
-    { ngx_string("fancyindex_ignore"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
-      ngx_http_fancyindex_ignore,
-      NGX_HTTP_LOC_CONF_OFFSET,
-      0,
-      NULL },
-
-    { ngx_string("fancyindex_hide_symlinks"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
-      ngx_conf_set_flag_slot,
-      NGX_HTTP_LOC_CONF_OFFSET,
-      offsetof(ngx_http_fancyindex_loc_conf_t, hide_symlinks),
-      NULL },
-
-    { ngx_string("fancyindex_show_path"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
-      ngx_conf_set_flag_slot,
-      NGX_HTTP_LOC_CONF_OFFSET,
-      offsetof(ngx_http_fancyindex_loc_conf_t, show_path),
-      NULL },
-
-    { ngx_string("fancyindex_show_dotfiles"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
-      ngx_conf_set_flag_slot,
-      NGX_HTTP_LOC_CONF_OFFSET,
-      offsetof(ngx_http_fancyindex_loc_conf_t, show_dot_files),
-      NULL },
-
-    { ngx_string("fancyindex_hide_parent_dir"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
-      ngx_conf_set_flag_slot,
-      NGX_HTTP_LOC_CONF_OFFSET,
-      offsetof(ngx_http_fancyindex_loc_conf_t, hide_parent),
-      NULL },
-
-    { ngx_string("fancyindex_time_format"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
-      ngx_conf_set_str_slot,
-      NGX_HTTP_LOC_CONF_OFFSET,
-      offsetof(ngx_http_fancyindex_loc_conf_t, time_format),
-      NULL },
-
-    ngx_null_command
-};
-
-
-static ngx_http_module_t  ngx_http_fancyindex_module_ctx = {
-    NULL,                                  /* preconfiguration */
-    ngx_http_fancyindex_init,              /* postconfiguration */
-
-    NULL,                                  /* create main configuration */
-    NULL,                                  /* init main configuration */
-
-    NULL,                                  /* create server configuration */
-    NULL,                                  /* merge server configuration */
-
-    ngx_http_fancyindex_create_loc_conf,   /* create location configuration */
-    ngx_http_fancyindex_merge_loc_conf     /* merge location configuration */
-};
-
-
-ngx_module_t  ngx_http_fancyindex_module = {
-    NGX_MODULE_V1,
-    &ngx_http_fancyindex_module_ctx,       /* module context */
-    ngx_http_fancyindex_commands,          /* module directives */
-    NGX_HTTP_MODULE,                       /* module type */
-    NULL,                                  /* init master */
-    NULL,                                  /* init module */
-    NULL,                                  /* init process */
-    NULL,                                  /* init thread */
-    NULL,                                  /* exit thread */
-    NULL,                                  /* exit process */
-    NULL,                                  /* exit master */
-    NGX_MODULE_V1_PADDING
-};
-
-
-
-static const ngx_str_t css_href_pre =
-    ngx_string("\n");
-
-
-#ifdef NGX_ESCAPE_URI_COMPONENT
-static inline uintptr_t
-ngx_fancyindex_escape_filename(u_char *dst, u_char *src, size_t size)
-{
-    return ngx_escape_uri(dst, src, size, NGX_ESCAPE_URI_COMPONENT);
-}
-#else /* !NGX_ESCAPE_URI_COMPONENT */
-static uintptr_t
-ngx_fancyindex_escape_filename(u_char *dst, u_char *src, size_t size)
-{
-    /*
-     * The ngx_escape_uri() function will not escape colons or the
-     * ? character, which signals the beginning of the query string.
-     * So we handle those characters ourselves.
-     *
-     * TODO: Get rid of this once ngx_escape_uri() works as expected!
-     */
-
-    u_int escapes = 0;
-    u_char *psrc = src;
-    size_t psize = size;
-
-    while (psize--) {
-        switch (*psrc++) {
-            case ':':
-            case '?':
-            case '[':
-            case ']':
-                escapes++;
-                break;
-        }
-    }
-
-    if (dst == NULL) {
-        return escapes + ngx_escape_uri(NULL, src, size, NGX_ESCAPE_HTML);
-    }
-    else if (escapes == 0) {
-        /* No need to do extra escaping, avoid the temporary buffer */
-        return ngx_escape_uri(dst, src, size, NGX_ESCAPE_HTML);
-    }
-    else {
-        uintptr_t uescapes = ngx_escape_uri(NULL, src, size, NGX_ESCAPE_HTML);
-        size_t bufsz = size + 2 * uescapes;
-
-        /*
-         * GCC and CLANG both support stack-allocated variable length
-         * arrays. Take advantage of that to avoid a malloc-free cycle.
-         */
-#if defined(__GNUC__) || defined(__clang__)
-        u_char cbuf[bufsz];
-        u_char *buf = cbuf;
-#else  /* __GNUC__ || __clang__ */
-        u_char *buf = (u_char*) malloc(sizeof(u_char) * bufsz);
-#endif /* __GNUC__ || __clang__ */
-
-        ngx_escape_uri(buf, src, size, NGX_ESCAPE_HTML);
-
-        while (bufsz--) {
-            switch (*buf) {
-                case ':':
-                    *dst++ = '%';
-                    *dst++ = '3';
-                    *dst++ = 'A';
-                    break;
-                case '?':
-                    *dst++ = '%';
-                    *dst++ = '3';
-                    *dst++ = 'F';
-                    break;
-                case '[':
-                    *dst++ = '%';
-                    *dst++ = '5';
-                    *dst++ = 'B';
-                    break;
-                case ']':
-                    *dst++ = '%';
-                    *dst++ = '5';
-                    *dst++ = 'D';
-                    break;
-                default:
-                    *dst++ = *buf;
-            }
-            buf++;
-        }
-
-#if !defined(__GNUC__) && !defined(__clang__)
-        free(buf);
-#endif /* !__GNUC__ && !__clang__ */
-
-        return escapes + uescapes;
-    }
-}
-#endif /* NGX_ESCAPE_URI_COMPONENT */
-
-
-static ngx_inline ngx_buf_t*
-make_header_buf(ngx_http_request_t *r, const ngx_str_t css_href)
-{
-    ngx_buf_t *b;
-    size_t blen = r->uri.len
-        + ngx_sizeof_ssz(t01_head1)
-        + ngx_sizeof_ssz(t02_head2)
-        + ngx_sizeof_ssz(t03_head3)
-        + ngx_sizeof_ssz(t04_body1)
-        ;
-
-    if (css_href.len) {
-        blen += css_href_pre.len \
-              + css_href.len \
-              + css_href_post.len
-              ;
-    }
-
-    if ((b = ngx_create_temp_buf(r->pool, blen)) == NULL)
-        return NULL;
-
-    b->last = ngx_cpymem_ssz(b->last, t01_head1);
-
-    if (css_href.len) {
-        b->last = ngx_cpymem_str(b->last, css_href_pre);
-        b->last = ngx_cpymem_str(b->last, css_href);
-        b->last = ngx_cpymem_str(b->last, css_href_post);
-    }
-
-    b->last = ngx_cpymem_ssz(b->last, t02_head2);
-    b->last = ngx_cpymem_str(b->last, r->uri);
-    b->last = ngx_cpymem_ssz(b->last, t03_head3);
-    b->last = ngx_cpymem_ssz(b->last, t04_body1);
-
-    return b;
-}
-
-
-static ngx_inline ngx_int_t
-make_content_buf(
-        ngx_http_request_t *r, ngx_buf_t **pb,
-        ngx_http_fancyindex_loc_conf_t *alcf)
-{
-    ngx_http_fancyindex_entry_t *entry;
-
-    int (*sort_cmp_func)(const void *, const void *);
-    const char  *sort_url_args = "";
-
-    off_t        length;
-    size_t       len, root, copy, allocated, escape_html;
-    int64_t      multiplier;
-    u_char      *filename, *last;
-    ngx_tm_t     tm;
-    ngx_array_t  entries;
-    ngx_time_t  *tp;
-    ngx_uint_t   i, j;
-    ngx_str_t    path;
-    ngx_dir_t    dir;
-    ngx_buf_t   *b;
-
-    static const char    *sizes[]  = { "EiB", "PiB", "TiB", "GiB", "MiB", "KiB", "B" };
-    static const int64_t  exbibyte = 1024LL * 1024LL * 1024LL *
-                                     1024LL * 1024LL * 1024LL;
-
-    /*
-     * NGX_DIR_MASK_LEN is lesser than NGX_HTTP_FANCYINDEX_PREALLOCATE
-     */
-    if ((last = ngx_http_map_uri_to_path(r, &path, &root,
-                    NGX_HTTP_FANCYINDEX_PREALLOCATE)) == NULL)
-        return NGX_HTTP_INTERNAL_SERVER_ERROR;
-
-    allocated = path.len;
-    path.len  = last - path.data - 1;
-    path.data[path.len] = '\0';
-
-    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                   "http fancyindex: \"%s\"", path.data);
-
-    if (ngx_open_dir(&path, &dir) == NGX_ERROR) {
-        ngx_int_t rc, err = ngx_errno;
-        ngx_uint_t level;
-
-        if (err == NGX_ENOENT || err == NGX_ENOTDIR || err == NGX_ENAMETOOLONG) {
-            level = NGX_LOG_ERR;
-            rc = NGX_HTTP_NOT_FOUND;
-        } else if (err == NGX_EACCES) {
-            level = NGX_LOG_ERR;
-            rc = NGX_HTTP_FORBIDDEN;
-        } else {
-            level = NGX_LOG_CRIT;
-            rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
-        }
-
-        ngx_log_error(level, r->connection->log, err,
-                ngx_open_dir_n " \"%s\" failed", path.data);
-
-        return rc;
-    }
-
-#if (NGX_SUPPRESS_WARN)
-    /* MSVC thinks 'entries' may be used without having been initialized */
-    ngx_memzero(&entries, sizeof(ngx_array_t));
-#endif /* NGX_SUPPRESS_WARN */
-
-
-    if (ngx_array_init(&entries, r->pool, 40,
-                sizeof(ngx_http_fancyindex_entry_t)) != NGX_OK)
-        return ngx_http_fancyindex_error(r, &dir, &path);
-
-    filename = path.data;
-    filename[path.len] = '/';
-
-    /* Read directory entries and their associated information. */
-    for (;;) {
-        ngx_set_errno(0);
-
-        if (ngx_read_dir(&dir) == NGX_ERROR) {
-            ngx_int_t err = ngx_errno;
-
-            if (err != NGX_ENOMOREFILES) {
-                ngx_log_error(NGX_LOG_CRIT, r->connection->log, err,
-                        ngx_read_dir_n " \"%V\" failed", &path);
-                return ngx_http_fancyindex_error(r, &dir, &path);
-            }
-            break;
-        }
-
-        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                       "http fancyindex file: \"%s\"", ngx_de_name(&dir));
-
-        len = ngx_de_namelen(&dir);
-
-        if (!alcf->show_dot_files && ngx_de_name(&dir)[0] == '.')
-            continue;
-
-        if (alcf->hide_symlinks && ngx_de_is_link (&dir))
-            continue;
-
-#if NGX_PCRE
-        {
-            ngx_str_t str;
-            str.len = len;
-            str.data = ngx_de_name(&dir);
-
-            if (alcf->ignore && ngx_regex_exec_array(alcf->ignore, &str,
-                                                     r->connection->log)
-                != NGX_DECLINED)
-            {
-                continue;
-            }
-        }
-#else /* !NGX_PCRE */
-        if (alcf->ignore) {
-            u_int match_found = 0;
-            ngx_str_t *s = alcf->ignore->elts;
-
-            for (i = 0; i < alcf->ignore->nelts; i++, s++) {
-                if (ngx_strcmp(ngx_de_name(&dir), s->data) == 0) {
-                    match_found = 1;
-                    break;
-                }
-            }
-
-            if (match_found) {
-                continue;
-            }
-        }
-#endif /* NGX_PCRE */
-
-        if (!dir.valid_info) {
-            /* 1 byte for '/' and 1 byte for terminating '\0' */
-            if (path.len + 1 + len + 1 > allocated) {
-                allocated = path.len + 1 + len + 1
-                          + NGX_HTTP_FANCYINDEX_PREALLOCATE;
-
-                if ((filename = ngx_palloc(r->pool, allocated)) == NULL)
-                    return ngx_http_fancyindex_error(r, &dir, &path);
-
-                last = ngx_cpystrn(filename, path.data, path.len + 1);
-                *last++ = '/';
-            }
-
-            ngx_cpystrn(last, ngx_de_name(&dir), len + 1);
-
-            if (ngx_de_info(filename, &dir) == NGX_FILE_ERROR) {
-                ngx_int_t err = ngx_errno;
-
-                if (err != NGX_ENOENT) {
-                    ngx_log_error(NGX_LOG_ERR, r->connection->log, err,
-                            ngx_de_info_n " \"%s\" failed", filename);
-                    continue;
-                }
-
-                if (ngx_de_link_info(filename, &dir) == NGX_FILE_ERROR) {
-                    ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
-                            ngx_de_link_info_n " \"%s\" failed", filename);
-                    return ngx_http_fancyindex_error(r, &dir, &path);
-                }
-            }
-        }
-
-        if ((entry = ngx_array_push(&entries)) == NULL)
-            return ngx_http_fancyindex_error(r, &dir, &path);
-
-        entry->name.len  = len;
-        entry->name.data = ngx_palloc(r->pool, len + 1);
-        if (entry->name.data == NULL)
-            return ngx_http_fancyindex_error(r, &dir, &path);
-
-        ngx_cpystrn(entry->name.data, ngx_de_name(&dir), len + 1);
-        entry->escape = 2 * ngx_fancyindex_escape_filename(NULL,
-                                                           ngx_de_name(&dir),
-                                                           len);
-        entry->escape_html = ngx_escape_html(NULL,
-                                             entry->name.data,
-                                             entry->name.len);
-
-        entry->dir     = ngx_de_is_dir(&dir);
-        entry->mtime   = ngx_de_mtime(&dir);
-        entry->size    = ngx_de_size(&dir);
-        entry->utf_len = (r->headers_out.charset.len == 5 &&
-                ngx_strncasecmp(r->headers_out.charset.data, (u_char*) "utf-8", 5) == 0)
-            ?  ngx_utf8_length(entry->name.data, entry->name.len)
-            : len;
-    }
-
-    if (ngx_close_dir(&dir) == NGX_ERROR) {
-        ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
-                ngx_close_dir_n " \"%s\" failed", &path);
-    }
-
-    /*
-     * Calculate needed buffer length.
-     */
-
-    escape_html = ngx_escape_html(NULL, r->uri.data, r->uri.len);
-
-    if (alcf->show_path)
-        len = r->uri.len + escape_html
-          + ngx_sizeof_ssz(t05_body2)
-          + ngx_sizeof_ssz(t06_list1)
-          + ngx_sizeof_ssz(t_parentdir_entry)
-          + ngx_sizeof_ssz(t07_list2)
-          + ngx_fancyindex_timefmt_calc_size (&alcf->time_format) * entries.nelts
-          ;
-   else
-        len = r->uri.len + escape_html
-          + ngx_sizeof_ssz(t06_list1)
-          + ngx_sizeof_ssz(t_parentdir_entry)
-          + ngx_sizeof_ssz(t07_list2)
-          + ngx_fancyindex_timefmt_calc_size (&alcf->time_format) * entries.nelts
-          ;
-
-    /*
-     * If we are a the root of the webserver (URI =  "/" --> length of 1),
-     * do not display the "Parent Directory" link.
-     */
-    if (r->uri.len == 1) {
-        len -= ngx_sizeof_ssz(t_parentdir_entry);
-    }
-
-    entry = entries.elts;
-    for (i = 0; i < entries.nelts; i++) {
-        /*
-         * Genearated table rows are as follows, unneeded whitespace
-         * is stripped out:
-         *
-         *   
- * - * - * - */ - len += ngx_sizeof_ssz("\n") /* Date suffix */ - + 2 /* CR LF */ - ; - } - - if ((b = ngx_create_temp_buf(r->pool, len)) == NULL) - return NGX_HTTP_INTERNAL_SERVER_ERROR; - - /* - * Determine the sorting criteria. URL arguments look like: - * - * C=x[&O=y] - * - * Where x={M,S,N} and y={A,D} - */ - if ((r->args.len == 3 || (r->args.len == 7 && r->args.data[3] == '&')) && - r->args.data[0] == 'C' && r->args.data[1] == '=') - { - /* Determine whether the direction of the sorting */ - ngx_int_t sort_descending = r->args.len == 7 - && r->args.data[4] == 'O' - && r->args.data[5] == '=' - && r->args.data[6] == 'D'; - - /* Pick the sorting criteria */ - switch (r->args.data[2]) { - case 'M': /* Sort by mtime */ - if (sort_descending) { - sort_cmp_func = ngx_http_fancyindex_cmp_entries_mtime_desc; - if (alcf->default_sort != NGX_HTTP_FANCYINDEX_SORT_CRITERION_DATE_DESC) - sort_url_args = "?C=M&O=D"; - } - else { - sort_cmp_func = ngx_http_fancyindex_cmp_entries_mtime_asc; - if (alcf->default_sort != NGX_HTTP_FANCYINDEX_SORT_CRITERION_DATE) - sort_url_args = "?C=M&O=A"; - } - break; - case 'S': /* Sort by size */ - if (sort_descending) { - sort_cmp_func = ngx_http_fancyindex_cmp_entries_size_desc; - if (alcf->default_sort != NGX_HTTP_FANCYINDEX_SORT_CRITERION_SIZE_DESC) - sort_url_args = "?C=S&O=D"; - } - else { - sort_cmp_func = ngx_http_fancyindex_cmp_entries_size_asc; - if (alcf->default_sort != NGX_HTTP_FANCYINDEX_SORT_CRITERION_SIZE) - sort_url_args = "?C=S&O=A"; - } - break; - case 'N': /* Sort by name */ - default: - if (sort_descending) { - sort_cmp_func = ngx_http_fancyindex_cmp_entries_name_desc; - if (alcf->default_sort != NGX_HTTP_FANCYINDEX_SORT_CRITERION_NAME_DESC) - sort_url_args = "?C=N&O=D"; - } - else { - sort_cmp_func = ngx_http_fancyindex_cmp_entries_name_asc; - if (alcf->default_sort != NGX_HTTP_FANCYINDEX_SORT_CRITERION_NAME) - sort_url_args = "?C=N&O=A"; - } - break; - } - } - else { - switch (alcf->default_sort) { - case NGX_HTTP_FANCYINDEX_SORT_CRITERION_DATE_DESC: - sort_cmp_func = ngx_http_fancyindex_cmp_entries_mtime_desc; - break; - case NGX_HTTP_FANCYINDEX_SORT_CRITERION_DATE: - sort_cmp_func = ngx_http_fancyindex_cmp_entries_mtime_asc; - break; - case NGX_HTTP_FANCYINDEX_SORT_CRITERION_SIZE_DESC: - sort_cmp_func = ngx_http_fancyindex_cmp_entries_size_desc; - break; - case NGX_HTTP_FANCYINDEX_SORT_CRITERION_SIZE: - sort_cmp_func = ngx_http_fancyindex_cmp_entries_size_asc; - break; - case NGX_HTTP_FANCYINDEX_SORT_CRITERION_NAME_DESC: - sort_cmp_func = ngx_http_fancyindex_cmp_entries_name_desc; - break; - case NGX_HTTP_FANCYINDEX_SORT_CRITERION_NAME: - default: - sort_cmp_func = ngx_http_fancyindex_cmp_entries_name_asc; - break; - } - } - - /* Sort entries, if needed */ - if (entries.nelts > 1) { - if (alcf->dirs_first) - { - ngx_http_fancyindex_entry_t *l, *r; - - l = entry; - r = entry + entries.nelts - 1; - while (l < r) - { - while (l < r && l->dir) - l++; - while (l < r && !r->dir) - r--; - if (l < r) { - /* Now l points a file while r points a directory */ - ngx_http_fancyindex_entry_t tmp; - tmp = *l; - *l = *r; - *r = tmp; - } - } - if (r->dir) - r++; - - if (r > entry) - /* Sort directories */ - ngx_qsort(entry, (size_t)(r - entry), - sizeof(ngx_http_fancyindex_entry_t), sort_cmp_func); - if (r < entry + entries.nelts) - /* Sort files */ - ngx_qsort(r, (size_t)(entry + entries.nelts - r), - sizeof(ngx_http_fancyindex_entry_t), sort_cmp_func); - } else { - ngx_qsort(entry, (size_t)entries.nelts, - sizeof(ngx_http_fancyindex_entry_t), sort_cmp_func); - } - } - - /* Display the path, if needed */ - if (alcf->show_path){ - b->last = last = (u_char *) ngx_escape_html(b->last, r->uri.data, r->uri.len); - b->last = ngx_cpymem_ssz(b->last, t05_body2); - } - - /* Open the
File Name  ↓ File Size  ↓ Date  ↓ File Name  ↓ File Size  ↓ Date  ↓ 
") + 20 /* File size */ @@ -890,24 +994,46 @@ make_content_buf( /* Sort entries, if needed */ if (entries.nelts > 1) { - /* Use ngx_sort for stability */ - ngx_sort(entry, (size_t) entries.nelts, - sizeof(ngx_http_fancyindex_entry_t), - sort_cmp_func); - if (alcf->dirs_first) { - /* Sort directories first */ - ngx_sort(entry, (size_t) entries.nelts, - sizeof(ngx_http_fancyindex_entry_t), - ngx_http_fancyindex_cmp_entries_dirs_first); - } + ngx_http_fancyindex_entry_t *l, *r; + l = entry; + r = entry + entries.nelts - 1; + while (l < r) + { + while (l < r && l->dir) + l++; + while (l < r && !r->dir) + r--; + if (l < r) { + /* Now l points a file while r points a directory */ + ngx_http_fancyindex_entry_t tmp; + tmp = *l; + *l = *r; + *r = tmp; + } + } + if (r->dir) + r++; + + if (r > entry) + /* Sort directories */ + ngx_qsort(entry, (size_t)(r - entry), + sizeof(ngx_http_fancyindex_entry_t), sort_cmp_func); + if (r < entry + entries.nelts) + /* Sort files */ + ngx_qsort(r, (size_t)(entry + entries.nelts - r), + sizeof(ngx_http_fancyindex_entry_t), sort_cmp_func); + } else { + ngx_qsort(entry, (size_t)entries.nelts, + sizeof(ngx_http_fancyindex_entry_t), sort_cmp_func); + } } /* Display the path, if needed */ if (alcf->show_path){ - b->last = ngx_cpymem_str(b->last, r->uri); + b->last = last = (u_char *) ngx_escape_html(b->last, r->uri.data, r->uri.len); b->last = ngx_cpymem_ssz(b->last, t05_body2); } @@ -960,26 +1086,32 @@ make_content_buf( *b->last++ = '"'; b->last = ngx_cpymem_ssz(b->last, " title=\""); - b->last = ngx_cpymem_str(b->last, entry[i].name); + b->last = (u_char *) ngx_escape_html(b->last, entry[i].name.data, entry[i].name.len); *b->last++ = '"'; *b->last++ = '>'; len = entry[i].utf_len; - if (entry[i].name.len - len) { + if (entry[i].name.len != len) { if (len > alcf->name_length) { copy = alcf->name_length - 3 + 1; } else { copy = alcf->name_length + 1; } + last = b->last; b->last = ngx_utf8_cpystrn(b->last, entry[i].name.data, - copy, entry[i].name.len); + copy, entry[i].name.len); + + b->last = (u_char *) ngx_escape_html(last, entry[i].name.data, b->last - last); last = b->last; } else { - b->last = ngx_cpystrn(b->last, entry[i].name.data, - alcf->name_length + 1); + if (len > alcf->name_length) { + b->last = (u_char *) ngx_escape_html(b->last, entry[i].name.data, alcf->name_length + 1); + } else { + b->last = (u_char *) ngx_escape_html(b->last, entry[i].name.data, entry[i].name.len); + } last = b->last - 3; } @@ -1016,7 +1148,7 @@ make_content_buf( if (j == DIM(sizes) - 1) b->last = ngx_sprintf(b->last, "%O %s", length, sizes[j]); else - b->last = ngx_sprintf(b->last, "%.1f %s", + b->last = ngx_sprintf(b->last, "%.1f %s", (float) length / multiplier, sizes[j]); } } @@ -1088,19 +1220,19 @@ ngx_http_fancyindex_handler(ngx_http_request_t *r) if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) return rc; - if (alcf->header.len > 0) { + if (alcf->header.path.len > 0 && alcf->header.local.len == 0) { /* URI is configured, make Nginx take care of with a subrequest. */ - sr_uri = &alcf->header; + sr_uri = &alcf->header.path; if (*sr_uri->data != '/') { /* Relative path */ - rel_uri.len = r->uri.len + alcf->header.len; + rel_uri.len = r->uri.len + alcf->header.path.len; rel_uri.data = ngx_palloc(r->pool, rel_uri.len); if (rel_uri.data == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } ngx_memcpy(ngx_cpymem(rel_uri.data, r->uri.data, r->uri.len), - alcf->header.data, alcf->header.len); + alcf->header.path.data, alcf->header.path.len); sr_uri = &rel_uri; } @@ -1128,25 +1260,42 @@ ngx_http_fancyindex_handler(ngx_http_request_t *r) } else { add_builtin_header: - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http fancyindex: adding built-in header"); /* Make space before */ out[1].next = out[0].next; out[1].buf = out[0].buf; /* Chain header buffer */ out[0].next = &out[1]; - out[0].buf = make_header_buf(r, alcf->css_href); + if (alcf->header.local.len > 0) { + /* Header buffer is local, make a buffer pointing to the data. */ + out[0].buf = ngx_calloc_buf(r->pool); + if (out[0].buf == NULL) + return NGX_ERROR; + out[0].buf->memory = 1; + out[0].buf->pos = alcf->header.local.data; + out[0].buf->last = alcf->header.local.data + alcf->header.local.len; + } else { + /* Prepare a buffer with the contents of the builtin header. */ + out[0].buf = make_header_buf(r, alcf->css_href); + } } /* If footer is disabled, chain up footer buffer. */ - if (alcf->footer.len == 0) { - ngx_uint_t last = (alcf->header.len == 0) ? 2 : 1; - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http fancyindex: adding built-in footer at %i", last); + if (alcf->footer.path.len == 0 || alcf->footer.local.len > 0) { + ngx_uint_t last = (alcf->header.path.len == 0) ? 2 : 1; out[last-1].next = &out[last]; - out[last].buf = make_footer_buf(r); + out[last].buf = ngx_calloc_buf(r->pool); + if (out[last].buf == NULL) + return NGX_ERROR; + + out[last].buf->memory = 1; + if (alcf->footer.local.len > 0) { + out[last].buf->pos = alcf->footer.local.data; + out[last].buf->last = alcf->footer.local.data + alcf->footer.local.len; + } else { + out[last].buf->pos = (u_char*) t08_foot1; + out[last].buf->last = (u_char*) t08_foot1 + sizeof(t08_foot1) - 1; + } out[last-1].buf->last_in_chain = 0; out[last].buf->last_in_chain = 1; @@ -1167,17 +1316,17 @@ add_builtin_header: return NGX_HTTP_INTERNAL_SERVER_ERROR; /* URI is configured, make Nginx take care of with a subrequest. */ - sr_uri = &alcf->footer; + sr_uri = &alcf->footer.path; if (*sr_uri->data != '/') { /* Relative path */ - rel_uri.len = r->uri.len + alcf->footer.len; + rel_uri.len = r->uri.len + alcf->footer.path.len; rel_uri.data = ngx_palloc(r->pool, rel_uri.len); if (rel_uri.data == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } ngx_memcpy(ngx_cpymem(rel_uri.data, r->uri.data, r->uri.len), - alcf->footer.data, alcf->footer.len); + alcf->footer.path.data, alcf->footer.path.len); sr_uri = &rel_uri; } @@ -1202,7 +1351,12 @@ add_builtin_header: * we get something different from a 404? */ out[0].next = NULL; - out[0].buf = make_footer_buf(r); + out[0].buf = ngx_calloc_buf(r->pool); + if (out[0].buf == NULL) + return NGX_ERROR; + out[0].buf->memory = 1; + out[0].buf->pos = (u_char*) t08_foot1; + out[0].buf->last = (u_char*) t08_foot1 + sizeof(t08_foot1) - 1; out[0].buf->last_in_chain = 1; out[0].buf->last_buf = 1; /* Directly send out the builtin footer */ @@ -1212,25 +1366,8 @@ add_builtin_header: return (r != r->main) ? rc : ngx_http_send_special(r, NGX_HTTP_LAST); } -static ngx_int_t ngx_libc_cdecl -ngx_http_fancyindex_cmp_entries_dirs_first(const void *one, const void *two) -{ - ngx_http_fancyindex_entry_t *first = (ngx_http_fancyindex_entry_t *) one; - ngx_http_fancyindex_entry_t *second = (ngx_http_fancyindex_entry_t *) two; - /* move the directories to the start */ - if (first->dir && !second->dir) { - return -1; - } - if (!first->dir && second->dir) { - return 1; - } - - return 0; -} - - -static ngx_int_t ngx_libc_cdecl +static int ngx_libc_cdecl ngx_http_fancyindex_cmp_entries_name_desc(const void *one, const void *two) { ngx_http_fancyindex_entry_t *first = (ngx_http_fancyindex_entry_t *) one; @@ -1240,7 +1377,7 @@ ngx_http_fancyindex_cmp_entries_name_desc(const void *one, const void *two) } -static ngx_int_t ngx_libc_cdecl +static int ngx_libc_cdecl ngx_http_fancyindex_cmp_entries_size_desc(const void *one, const void *two) { ngx_http_fancyindex_entry_t *first = (ngx_http_fancyindex_entry_t *) one; @@ -1250,7 +1387,7 @@ ngx_http_fancyindex_cmp_entries_size_desc(const void *one, const void *two) } -static ngx_int_t ngx_libc_cdecl +static int ngx_libc_cdecl ngx_http_fancyindex_cmp_entries_mtime_desc(const void *one, const void *two) { ngx_http_fancyindex_entry_t *first = (ngx_http_fancyindex_entry_t *) one; @@ -1260,7 +1397,7 @@ ngx_http_fancyindex_cmp_entries_mtime_desc(const void *one, const void *two) } -static ngx_int_t ngx_libc_cdecl +static int ngx_libc_cdecl ngx_http_fancyindex_cmp_entries_name_asc(const void *one, const void *two) { ngx_http_fancyindex_entry_t *first = (ngx_http_fancyindex_entry_t *) one; @@ -1270,7 +1407,7 @@ ngx_http_fancyindex_cmp_entries_name_asc(const void *one, const void *two) } -static ngx_int_t ngx_libc_cdecl +static int ngx_libc_cdecl ngx_http_fancyindex_cmp_entries_size_asc(const void *one, const void *two) { ngx_http_fancyindex_entry_t *first = (ngx_http_fancyindex_entry_t *) one; @@ -1280,7 +1417,7 @@ ngx_http_fancyindex_cmp_entries_size_asc(const void *one, const void *two) } -static ngx_int_t ngx_libc_cdecl +static int ngx_libc_cdecl ngx_http_fancyindex_cmp_entries_mtime_asc(const void *one, const void *two) { ngx_http_fancyindex_entry_t *first = (ngx_http_fancyindex_entry_t *) one; @@ -1314,25 +1451,26 @@ ngx_http_fancyindex_create_loc_conf(ngx_conf_t *cf) /* * Set by ngx_pcalloc: - * conf->header.len = 0 - * conf->header.data = NULL - * conf->footer.len = 0 - * conf->footer.data = NULL + * conf->header.*.len = 0 + * conf->header.*.data = NULL + * conf->footer.*.len = 0 + * conf->footer.*.data = NULL * conf->css_href.len = 0 * conf->css_href.data = NULL * conf->time_format.len = 0 * conf->time_format.data = NULL */ - conf->enable = NGX_CONF_UNSET; - conf->default_sort = NGX_CONF_UNSET_UINT; - conf->dirs_first = NGX_CONF_UNSET; - conf->localtime = NGX_CONF_UNSET; - conf->name_length = NGX_CONF_UNSET_UINT; - conf->exact_size = NGX_CONF_UNSET; - conf->ignore = NGX_CONF_UNSET_PTR; - conf->hide_symlinks = NGX_CONF_UNSET; - conf->show_path = NGX_CONF_UNSET; - conf->hide_parent = NGX_CONF_UNSET; + conf->enable = NGX_CONF_UNSET; + conf->default_sort = NGX_CONF_UNSET_UINT; + conf->dirs_first = NGX_CONF_UNSET; + conf->localtime = NGX_CONF_UNSET; + conf->name_length = NGX_CONF_UNSET_UINT; + conf->exact_size = NGX_CONF_UNSET; + conf->ignore = NGX_CONF_UNSET_PTR; + conf->hide_symlinks = NGX_CONF_UNSET; + conf->show_path = NGX_CONF_UNSET; + conf->hide_parent = NGX_CONF_UNSET; + conf->show_dot_files = NGX_CONF_UNSET; return conf; } @@ -1352,10 +1490,14 @@ ngx_http_fancyindex_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_value(conf->localtime, prev->localtime, 0); ngx_conf_merge_value(conf->exact_size, prev->exact_size, 1); ngx_conf_merge_value(conf->show_path, prev->show_path, 1); + ngx_conf_merge_value(conf->show_dot_files, prev->show_dot_files, 0); ngx_conf_merge_uint_value(conf->name_length, prev->name_length, 50); - ngx_conf_merge_str_value(conf->header, prev->header, ""); - ngx_conf_merge_str_value(conf->footer, prev->footer, ""); + ngx_conf_merge_str_value(conf->header.path, prev->header.path, ""); + ngx_conf_merge_str_value(conf->header.path, prev->header.local, ""); + ngx_conf_merge_str_value(conf->footer.path, prev->footer.path, ""); + ngx_conf_merge_str_value(conf->footer.path, prev->footer.local, ""); + ngx_conf_merge_str_value(conf->css_href, prev->css_href, ""); ngx_conf_merge_str_value(conf->time_format, prev->time_format, "%Y-%b-%d %H:%M"); @@ -1364,7 +1506,7 @@ ngx_http_fancyindex_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_value(conf->hide_parent, prev->hide_parent, 0); /* Just make sure we haven't disabled the show_path directive without providing a custom header */ - if (conf->show_path == 0 && conf->header.len == 0) + if (conf->show_path == 0 && conf->header.path.len == 0) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "FancyIndex : cannot set show_path to off without providing a custom header !"); return NGX_CONF_ERROR; diff --git a/debian/modules/http-fancyindex/t/07-directory-first.test b/debian/modules/http-fancyindex/t/07-directory-first.test new file mode 100644 index 0000000..82c37cc --- /dev/null +++ b/debian/modules/http-fancyindex/t/07-directory-first.test @@ -0,0 +1,50 @@ +#! /bin/bash +cat <<--- +This test check the output using "fancyindex_directories_first on" +-- +use pup + +for d in "008d" "000d" "004d" ; do + mkdir -p "${TESTDIR}/dir_first/${d}" +done +for f in "005f" "001f" "003f"; do + touch "${TESTDIR}/dir_first/${f}" +done +for d in "006d" "002d" ; do + mkdir -p "${TESTDIR}/dir_first/${d}" +done + +nginx_start 'fancyindex_directories_first on;' +previous='' +cur_type='' +while read -r name ; do + case "$name" in + *Parent*) + ;; + *d*) + echo "dir $name" + [[ "$cur_type" = f ]] && fail 'Directories should come before Files' + cur_type=d + if [[ -z ${previous} ]] ; then + previous=${name} + else + [[ ${previous} < ${name} ]] || fail \ + 'Name %s should come before %s\n' "${previous}" "${name}" + fi + ;; + *f*) + echo "file $name" + [[ -z "$cur_type" ]] && fail 'Directories should come before Files' + if [[ "$cur_type" = d ]] ; then + cur_type=f + previous=${name} + else + [[ ${previous} < ${name} ]] || fail \ + 'Name %s should come before %s\n' "${previous}" "${name}" + fi + ;; + esac +done < <( fetch '/dir_first/' \ + | pup -p body table tbody 'td:nth-child(1)' text{} ) + +nginx_is_running || fail "Nginx died" diff --git a/debian/modules/http-fancyindex/t/07-show_dotfiles.test b/debian/modules/http-fancyindex/t/07-show_dotfiles.test new file mode 100644 index 0000000..6b56410 --- /dev/null +++ b/debian/modules/http-fancyindex/t/07-show_dotfiles.test @@ -0,0 +1,21 @@ +#! /bin/bash +cat <<--- +Test the option to show dotfiles. +-- +# Turn it on. +nginx_start 'fancyindex_show_dotfiles on;' +on_content=$(fetch /show_dotfiles/) +nginx_stop +if [ $(grep '.okay' <<< "${on_content}") -ne 0 ] ; then + exit 1 +fi + +# Turn it off. +nginx_start +off_content=$(fetch /show_dotfiles/) +nginx_stop +if [ $(grep '.okay' <<< "${on_content}") -eq 0] ; then + exit 1 +fi + +exit 0 diff --git a/debian/modules/http-fancyindex/t/08-local-footer.test b/debian/modules/http-fancyindex/t/08-local-footer.test new file mode 100644 index 0000000..6d6318b --- /dev/null +++ b/debian/modules/http-fancyindex/t/08-local-footer.test @@ -0,0 +1,17 @@ +#! /bin/bash +cat <<--- +This test checks that a local footer can be included with +"fancyindex_header ... local" +-- +use pup + +cat > "${TESTDIR}/footer" <yes +EOF + +nginx_start "fancyindex_footer \"${TESTDIR}/footer\" local;" + +T=$(fetch / | pup -p body 'div#customfooter' text{}) +[[ $T == yes ]] || fail 'Custom header missing' + +nginx_is_running || fail 'Nginx died' diff --git a/debian/modules/http-fancyindex/t/09-local-header.test b/debian/modules/http-fancyindex/t/09-local-header.test new file mode 100644 index 0000000..455b966 --- /dev/null +++ b/debian/modules/http-fancyindex/t/09-local-header.test @@ -0,0 +1,17 @@ +#! /bin/bash +cat <<--- +This test checks that a local header can be included with +"fancyindex_header ... local" +-- +use pup + +cat > "${TESTDIR}/header" <yes +EOF + +nginx_start "fancyindex_header \"${TESTDIR}/header\" local;" + +T=$(fetch / | pup -p body 'div#customheader' text{}) +[[ $T == yes ]] || fail 'Custom header missing' + +nginx_is_running || fail 'Nginx died' diff --git a/debian/modules/http-fancyindex/t/10-local-headerfooter.test b/debian/modules/http-fancyindex/t/10-local-headerfooter.test new file mode 100644 index 0000000..6adfb45 --- /dev/null +++ b/debian/modules/http-fancyindex/t/10-local-headerfooter.test @@ -0,0 +1,26 @@ +#! /bin/bash +cat <<--- +This test checks that both a local header and footer can be included with +"fancyindex_{header,footer} ... local" +-- +use pup + +cat > "${TESTDIR}/header" <yes +EOF +cat > "${TESTDIR}/footer" <yes +EOF + +nginx_start "fancyindex_header \"${TESTDIR}/header\" local; + fancyindex_footer \"${TESTDIR}/footer\" local;" + +P=$(fetch /) + +H=$(pup -p body 'div#customheader' text{} <<< "$P") +[[ $H == yes ]] || fail 'Custom header missing' + +F=$(pup -p body 'div#customfooter' text{} <<< "$P") +[[ $F == yes ]] || fail 'Custom footer missing' + +nginx_is_running || fail 'Nginx died' diff --git a/debian/modules/http-fancyindex/t/11-local-footer-nested.test b/debian/modules/http-fancyindex/t/11-local-footer-nested.test new file mode 100644 index 0000000..0530853 --- /dev/null +++ b/debian/modules/http-fancyindex/t/11-local-footer-nested.test @@ -0,0 +1,31 @@ +#! /bin/bash +cat <<--- +This test checks that local footers are correctly included in presence of +directives in nested locations: + + fancyindex_footer local; + location /sub { + fancyindex_footer local; + } + +-- +use pup + +echo '
yes
' > "${TESTDIR}/top-footer" +echo '
yes
' > "${TESTDIR}/sub-footer" + +nginx_start "fancyindex_footer \"${TESTDIR}/top-footer\" local; + location /child-directory { + fancyindex_footer \"${TESTDIR}/sub-footer\" local; + }" + +T=$(fetch /) +echo "$T" > "$TESTDIR/top.html" +[[ $(pup -p body 'div#topfooter' text{} <<< "$T") = yes ]] || fail 'Custom header missing at /' +[[ -z $(pup -p body 'div#subfooter' text{} <<< "$T") ]] || fail 'Wrong header at /' + +T=$(fetch /child-directory/) +[[ $(pup -p body 'div#subfooter' text{} <<< "$T") = yes ]] || fail 'Custom header missing at /sub/' +[[ -z $(pup -p body 'div#topfooter' text{} <<< "$T") ]] || fail 'Wrong header at /sub/' + +nginx_is_running || fail 'Nginx died' diff --git a/debian/modules/http-fancyindex/t/12-local-footer-nested.test b/debian/modules/http-fancyindex/t/12-local-footer-nested.test new file mode 100644 index 0000000..7c0aef7 --- /dev/null +++ b/debian/modules/http-fancyindex/t/12-local-footer-nested.test @@ -0,0 +1,11 @@ +#! /bin/bash +cat <<--- +This test checks that the configuration file is properly parsed if there +is only one parameter passed to the fancyndex_header and fancyindex_footer +configuration directives. +-- + +nginx_start 'fancyindex_header "/header"; + fancyindex_footer "/footer";' + +nginx_is_running || fail 'Nginx died' diff --git a/debian/modules/http-fancyindex/t/preamble b/debian/modules/http-fancyindex/t/preamble index d3e4e30..26f2819 100644 --- a/debian/modules/http-fancyindex/t/preamble +++ b/debian/modules/http-fancyindex/t/preamble @@ -20,7 +20,7 @@ function nginx_conf_generate () { keepalive_timeout 65; server { server_name localhost; - listen 127.0.0.1:8888; + listen 127.0.0.1:${NGINX_PORT}; root ${TESTDIR}; error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } @@ -36,6 +36,11 @@ function nginx_conf_generate () { readonly NGINX_CONF="${PREFIX}/conf/nginx.conf" readonly NGINX_PID="${PREFIX}/logs/nginx.pid" + +NGINX_PORT=$(ss -4Htnl | awk '{ sub("[^:]+:", "", $4) ; seen[$4]=1 } +END { p=1025 ; while (seen[p]) p++; print p}') +readonly NGINX_PORT + rm -f "${NGINX_CONF}" "${NGINX_PID}" mkdir -p "${PREFIX}/logs" @@ -85,7 +90,7 @@ function fetch () { opts+=( -S ) shift fi - wget "${opts[@]}" -O- "http://localhost:8888${1:-/}" 2>&1 + wget "${opts[@]}" -O- "http://localhost:${NGINX_PORT}${1:-/}" 2>&1 } function skip () { diff --git a/debian/modules/http-fancyindex/t/run b/debian/modules/http-fancyindex/t/run index 06cc3db..9988fa2 100755 --- a/debian/modules/http-fancyindex/t/run +++ b/debian/modules/http-fancyindex/t/run @@ -1,4 +1,4 @@ -#! /bin/bash +#!/bin/bash set -e if [[ $# -lt 1 || $# -gt 2 ]] ; then diff --git a/debian/modules/http-fancyindex/t/show_dotfiles/.okay b/debian/modules/http-fancyindex/t/show_dotfiles/.okay new file mode 100644 index 0000000..e69de29 From a63400c839e50677ba4b0b1b8bc79348651ffeef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Nov=C3=BD?= Date: Tue, 15 Mar 2022 11:01:40 +0100 Subject: [PATCH 073/329] rtmp: Upgrade to 1.2.2 --- debian/modules/control | 2 +- debian/modules/rtmp/ngx_rtmp_amf.c | 2 +- debian/modules/rtmp/ngx_rtmp_eval.c | 2 ++ debian/modules/rtmp/ngx_rtmp_handler.c | 4 +++- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/debian/modules/control b/debian/modules/control index a9bf5e6..8ba5644 100644 --- a/debian/modules/control +++ b/debian/modules/control @@ -70,5 +70,5 @@ Patch: dynamic-module.patch Module: rtmp Homepage: https://github.com/arut/nginx-rtmp-module Files-Excluded: test -Version: 1.2.1 +Version: 1.2.2 diff --git a/debian/modules/rtmp/ngx_rtmp_amf.c b/debian/modules/rtmp/ngx_rtmp_amf.c index b20989c..3fe3ccf 100644 --- a/debian/modules/rtmp/ngx_rtmp_amf.c +++ b/debian/modules/rtmp/ngx_rtmp_amf.c @@ -328,7 +328,7 @@ ngx_rtmp_amf_read(ngx_rtmp_amf_ctx_t *ctx, ngx_rtmp_amf_elt_t *elts, } else { switch (ngx_rtmp_amf_get(ctx, &type8, 1)) { case NGX_DONE: - if (elts->type & NGX_RTMP_AMF_OPTIONAL) { + if (elts && elts->type & NGX_RTMP_AMF_OPTIONAL) { return NGX_OK; } /* fall through */ diff --git a/debian/modules/rtmp/ngx_rtmp_eval.c b/debian/modules/rtmp/ngx_rtmp_eval.c index 1e5195a..a92a863 100644 --- a/debian/modules/rtmp/ngx_rtmp_eval.c +++ b/debian/modules/rtmp/ngx_rtmp_eval.c @@ -167,6 +167,8 @@ ngx_rtmp_eval(void *ctx, ngx_str_t *in, ngx_rtmp_eval_t **e, ngx_str_t *out, continue; } + /* fall through */ + case ESCAPE: ngx_rtmp_eval_append(&b, &c, 1, log); state = NORMAL; diff --git a/debian/modules/rtmp/ngx_rtmp_handler.c b/debian/modules/rtmp/ngx_rtmp_handler.c index 17eadee..f42a3bb 100644 --- a/debian/modules/rtmp/ngx_rtmp_handler.c +++ b/debian/modules/rtmp/ngx_rtmp_handler.c @@ -241,7 +241,9 @@ ngx_rtmp_recv(ngx_event_t *rev) "reusing formerly read data: %d", old_size); b->pos = b->start; - b->last = ngx_movemem(b->pos, old_pos, old_size); + + size = ngx_min((size_t) (b->end - b->start), old_size); + b->last = ngx_movemem(b->pos, old_pos, size); if (s->in_chunk_size_changing) { ngx_rtmp_finalize_set_chunk_size(s); From 70f87643c9a5e34fc1dc902f4c4d8d1215b4db84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Nov=C3=BD?= Date: Tue, 15 Mar 2022 11:03:47 +0100 Subject: [PATCH 074/329] http-lua: Upgrade to 0.10.15 --- debian/modules/control | 2 +- debian/modules/http-lua/README.markdown | 235 +- debian/modules/http-lua/config | 45 + .../modules/http-lua/doc/HttpLuaModule.wiki | 213 +- .../http-lua/src/api/ngx_http_lua_api.h | 2 +- .../http-lua/src/ngx_http_lua_accessby.c | 4 +- .../modules/http-lua/src/ngx_http_lua_api.c | 2 +- .../http-lua/src/ngx_http_lua_balancer.c | 3 + .../http-lua/src/ngx_http_lua_bodyfilterby.c | 50 +- .../http-lua/src/ngx_http_lua_bodyfilterby.h | 2 +- .../modules/http-lua/src/ngx_http_lua_cache.c | 23 +- .../http-lua/src/ngx_http_lua_clfactory.c | 45 +- .../http-lua/src/ngx_http_lua_common.h | 49 +- .../http-lua/src/ngx_http_lua_contentby.c | 2 + .../http-lua/src/ngx_http_lua_control.c | 3 +- .../http-lua/src/ngx_http_lua_coroutine.c | 18 +- .../http-lua/src/ngx_http_lua_directive.c | 11 +- .../src/ngx_http_lua_headerfilterby.c | 3 +- .../http-lua/src/ngx_http_lua_headers.c | 83 +- .../http-lua/src/ngx_http_lua_headers_in.c | 10 +- .../http-lua/src/ngx_http_lua_headers_out.c | 20 +- .../http-lua/src/ngx_http_lua_headers_out.h | 6 +- .../http-lua/src/ngx_http_lua_initworkerby.c | 19 + .../http-lua/src/ngx_http_lua_input_filters.c | 137 + .../http-lua/src/ngx_http_lua_input_filters.h | 29 + .../modules/http-lua/src/ngx_http_lua_logby.c | 3 +- .../modules/http-lua/src/ngx_http_lua_misc.c | 27 + .../http-lua/src/ngx_http_lua_module.c | 56 + .../modules/http-lua/src/ngx_http_lua_ndk.c | 41 + .../modules/http-lua/src/ngx_http_lua_pipe.c | 2475 +++++++++++++++++ .../modules/http-lua/src/ngx_http_lua_pipe.h | 95 + .../modules/http-lua/src/ngx_http_lua_regex.c | 10 +- .../http-lua/src/ngx_http_lua_rewriteby.c | 4 +- .../http-lua/src/ngx_http_lua_script.c | 4 +- .../modules/http-lua/src/ngx_http_lua_setby.c | 34 +- .../modules/http-lua/src/ngx_http_lua_setby.h | 2 +- .../http-lua/src/ngx_http_lua_shdict.c | 44 +- .../http-lua/src/ngx_http_lua_socket_tcp.c | 1608 +++++++---- .../http-lua/src/ngx_http_lua_socket_tcp.h | 29 +- .../http-lua/src/ngx_http_lua_socket_udp.c | 12 +- .../http-lua/src/ngx_http_lua_ssl_certby.c | 2 + .../src/ngx_http_lua_ssl_session_fetchby.c | 2 + .../src/ngx_http_lua_ssl_session_storeby.c | 3 + .../http-lua/src/ngx_http_lua_string.c | 14 + .../http-lua/src/ngx_http_lua_subrequest.c | 8 + .../modules/http-lua/src/ngx_http_lua_timer.c | 44 +- .../http-lua/src/ngx_http_lua_uthread.c | 3 +- .../modules/http-lua/src/ngx_http_lua_util.c | 168 +- .../modules/http-lua/src/ngx_http_lua_util.h | 28 +- .../http-lua/src/ngx_http_lua_worker.c | 11 + debian/modules/http-lua/t/000--init.t | 5 - debian/modules/http-lua/t/001-set.t | 23 +- debian/modules/http-lua/t/002-content.t | 38 +- debian/modules/http-lua/t/004-require.t | 12 +- debian/modules/http-lua/t/005-exit.t | 2 +- debian/modules/http-lua/t/009-log.t | 12 +- debian/modules/http-lua/t/011-md5_bin.t | 2 +- debian/modules/http-lua/t/013-base64.t | 2 +- debian/modules/http-lua/t/014-bugs.t | 49 +- debian/modules/http-lua/t/016-resp-header.t | 504 +++- debian/modules/http-lua/t/017-exec.t | 4 +- debian/modules/http-lua/t/020-subrequest.t | 134 +- .../http-lua/t/023-rewrite/client-abort.t | 6 +- debian/modules/http-lua/t/023-rewrite/exec.t | 4 +- debian/modules/http-lua/t/023-rewrite/mixed.t | 4 +- .../http-lua/t/023-rewrite/multi-capture.t | 2 +- .../http-lua/t/023-rewrite/req-socket.t | 6 +- .../modules/http-lua/t/023-rewrite/sanity.t | 28 +- .../http-lua/t/023-rewrite/socket-keepalive.t | 12 +- .../http-lua/t/023-rewrite/subrequest.t | 42 +- .../t/023-rewrite/tcp-socket-timeout.t | 12 +- .../http-lua/t/023-rewrite/tcp-socket.t | 32 +- .../http-lua/t/023-rewrite/uthread-exec.t | 12 +- .../http-lua/t/023-rewrite/uthread-exit.t | 40 +- .../http-lua/t/023-rewrite/uthread-redirect.t | 4 +- .../http-lua/t/023-rewrite/uthread-spawn.t | 62 +- .../http-lua/t/024-access/client-abort.t | 6 +- debian/modules/http-lua/t/024-access/exec.t | 2 +- debian/modules/http-lua/t/024-access/mixed.t | 10 +- .../http-lua/t/024-access/multi-capture.t | 2 +- debian/modules/http-lua/t/024-access/sanity.t | 30 +- .../http-lua/t/024-access/subrequest.t | 42 +- .../http-lua/t/024-access/uthread-exec.t | 12 +- .../http-lua/t/024-access/uthread-exit.t | 38 +- .../http-lua/t/024-access/uthread-redirect.t | 4 +- .../http-lua/t/024-access/uthread-spawn.t | 62 +- debian/modules/http-lua/t/025-codecache.t | 174 +- debian/modules/http-lua/t/027-multi-capture.t | 4 +- debian/modules/http-lua/t/028-req-header.t | 24 +- debian/modules/http-lua/t/030-uri-args.t | 23 +- debian/modules/http-lua/t/034-match.t | 65 +- debian/modules/http-lua/t/035-gmatch.t | 22 +- debian/modules/http-lua/t/036-sub.t | 4 +- debian/modules/http-lua/t/037-gsub.t | 2 +- debian/modules/http-lua/t/038-match-o.t | 44 +- debian/modules/http-lua/t/041-header-filter.t | 15 +- debian/modules/http-lua/t/043-shdict.t | 4 +- debian/modules/http-lua/t/047-match-jit.t | 12 +- debian/modules/http-lua/t/048-match-dfa.t | 12 +- debian/modules/http-lua/t/055-subreq-vars.t | 18 +- debian/modules/http-lua/t/056-flush.t | 2 +- debian/modules/http-lua/t/057-flush-timeout.t | 2 +- debian/modules/http-lua/t/058-tcp-socket.t | 364 ++- debian/modules/http-lua/t/062-count.t | 31 +- debian/modules/http-lua/t/063-abort.t | 62 +- debian/modules/http-lua/t/064-pcall.t | 14 +- .../http-lua/t/065-tcp-socket-timeout.t | 24 +- .../http-lua/t/066-socket-receiveuntil.t | 30 +- debian/modules/http-lua/t/067-req-socket.t | 6 +- .../modules/http-lua/t/068-socket-keepalive.t | 1467 +++++++++- debian/modules/http-lua/t/073-backtrace.t | 14 +- debian/modules/http-lua/t/075-logby.t | 11 +- debian/modules/http-lua/t/081-bytecode.t | 45 +- debian/modules/http-lua/t/082-body-filter.t | 3 +- .../http-lua/t/084-inclusive-receiveuntil.t | 20 +- debian/modules/http-lua/t/087-udp-socket.t | 12 +- .../http-lua/t/090-log-socket-errors.t | 10 +- debian/modules/http-lua/t/091-coroutine.t | 81 +- debian/modules/http-lua/t/093-uthread-spawn.t | 66 +- debian/modules/http-lua/t/094-uthread-exit.t | 46 +- debian/modules/http-lua/t/095-uthread-exec.t | 14 +- .../modules/http-lua/t/096-uthread-redirect.t | 6 +- .../modules/http-lua/t/097-uthread-rewrite.t | 12 +- debian/modules/http-lua/t/098-uthread-wait.t | 74 +- debian/modules/http-lua/t/099-c-api.t | 10 +- debian/modules/http-lua/t/100-client-abort.t | 6 +- debian/modules/http-lua/t/106-timer.t | 18 +- debian/modules/http-lua/t/108-timer-safe.t | 16 +- debian/modules/http-lua/t/109-timer-hup.t | 18 +- debian/modules/http-lua/t/120-re-find.t | 4 +- debian/modules/http-lua/t/123-lua-path.t | 10 +- debian/modules/http-lua/t/124-init-worker.t | 10 +- debian/modules/http-lua/t/126-shdict-frag.t | 4 +- debian/modules/http-lua/t/127-uthread-kill.t | 26 +- .../http-lua/t/128-duplex-tcp-socket.t | 6 +- debian/modules/http-lua/t/129-ssl-socket.t | 16 +- debian/modules/http-lua/t/130-internal-api.t | 17 +- .../modules/http-lua/t/134-worker-count-5.t | 4 +- debian/modules/http-lua/t/138-balancer.t | 2 - debian/modules/http-lua/t/139-ssl-cert-by.t | 2 +- debian/modules/http-lua/t/140-ssl-c-api.t | 23 +- .../http-lua/t/143-ssl-session-fetch.t | 105 + .../http-lua/t/147-tcp-socket-timeouts.t | 8 +- debian/modules/http-lua/t/152-timer-every.t | 4 +- debian/modules/http-lua/t/153-semaphore-hup.t | 2 +- debian/modules/http-lua/t/156-slow-network.t | 138 + .../http-lua/t/157-socket-keepalive-hup.t | 91 + debian/modules/http-lua/t/158-global-var.t | 508 ++++ debian/modules/http-lua/t/159-sa-restart.t | 180 ++ .../http-lua/t/160-disable-init-by-lua.t | 194 ++ .../modules/http-lua/t/161-load-resty-core.t | 68 + .../ngx_http_lua_fake_shm_module.c | 22 +- debian/modules/http-lua/util/build.sh | 4 +- 153 files changed, 9493 insertions(+), 1866 deletions(-) create mode 100644 debian/modules/http-lua/src/ngx_http_lua_input_filters.c create mode 100644 debian/modules/http-lua/src/ngx_http_lua_input_filters.h create mode 100644 debian/modules/http-lua/src/ngx_http_lua_pipe.c create mode 100644 debian/modules/http-lua/src/ngx_http_lua_pipe.h create mode 100644 debian/modules/http-lua/t/156-slow-network.t create mode 100644 debian/modules/http-lua/t/157-socket-keepalive-hup.t create mode 100644 debian/modules/http-lua/t/158-global-var.t create mode 100644 debian/modules/http-lua/t/159-sa-restart.t create mode 100644 debian/modules/http-lua/t/160-disable-init-by-lua.t create mode 100644 debian/modules/http-lua/t/161-load-resty-core.t diff --git a/debian/modules/control b/debian/modules/control index 8ba5644..4034f4d 100644 --- a/debian/modules/control +++ b/debian/modules/control @@ -22,7 +22,7 @@ Version: 3.3 Module: http-lua Homepage: https://github.com/openresty/lua-nginx-module -Version: 0.10.13 +Version: 0.10.15 Patch: openssl-1.1.0.patch discover-luajit-2.1.patch diff --git a/debian/modules/http-lua/README.markdown b/debian/modules/http-lua/README.markdown index 15ad00e..ed0c72d 100644 --- a/debian/modules/http-lua/README.markdown +++ b/debian/modules/http-lua/README.markdown @@ -8,6 +8,8 @@ Name ngx_http_lua_module - Embed the power of Lua into Nginx HTTP Servers. +This module is a core component of OpenResty. If you are using this module, then you are essentially using OpenResty :) + *This module is not distributed with the Nginx source.* See [the installation instructions](#installation). Table of Contents @@ -23,7 +25,6 @@ Table of Contents * [Installation](#installation) * [Building as a dynamic module](#building-as-a-dynamic-module) * [C Macro Configurations](#c-macro-configurations) - * [Installation on Ubuntu 11.10](#installation-on-ubuntu-1110) * [Community](#community) * [English Mailing List](#english-mailing-list) * [Chinese Mailing List](#chinese-mailing-list) @@ -62,7 +63,7 @@ Production ready. Version ======= -This document describes ngx_lua [v0.10.13](https://github.com/openresty/lua-nginx-module/tags) released on 22 April 2018. +This document describes ngx_lua [v0.10.15](https://github.com/openresty/lua-nginx-module/tags) released on March 14th, 2019. Synopsis ======== @@ -187,7 +188,9 @@ Synopsis Description =========== -This module embeds Lua, via the standard Lua 5.1 interpreter or [LuaJIT 2.0/2.1](http://luajit.org/luajit.html), into Nginx and by leveraging Nginx's subrequests, allows the integration of the powerful Lua threads (Lua coroutines) into the Nginx event model. +This module is a core component of OpenResty. If you are using this module, then you are essentially using OpenResty :) + +This module embeds Lua, via [LuaJIT 2.0/2.1](http://luajit.org/luajit.html), into Nginx and by leveraging Nginx's subrequests, allows the integration of the powerful Lua threads (Lua coroutines) into the Nginx event model. Unlike [Apache's mod_lua](https://httpd.apache.org/docs/trunk/mod/mod_lua.html) and [Lighttpd's mod_magnet](http://redmine.lighttpd.net/wiki/1/Docs:ModMagnet), Lua code executed using this module can be *100% non-blocking* on network traffic as long as the [Nginx API for Lua](#nginx-api-for-lua) provided by this module is used to handle requests to upstream services such as MySQL, PostgreSQL, Memcached, Redis, or upstream HTTP web services. @@ -265,11 +268,11 @@ Nginx cores older than 1.6.0 (exclusive) are *not* supported. Installation ============ -It is *highly* recommended to use [OpenResty releases](http://openresty.org) which integrate Nginx, ngx_lua, LuaJIT 2.1, as well as other powerful companion Nginx modules and Lua libraries. It is discouraged to build this module with nginx yourself since it is tricky to set up exactly right. Also, the stock nginx cores have various limitations and long standing bugs that can make some of this modules' features become disabled, not work properly, or run slower. The same applies to LuaJIT as well. OpenResty includes its own version of LuaJIT which gets specifically optimized and enhanced for the OpenResty environment. +It is *highly* recommended to use [OpenResty releases](http://openresty.org) which integrate Nginx, ngx_lua, OpenResty's LuaJIT 2.1 branch version, as well as other powerful companion Nginx modules and Lua libraries. It is discouraged to build this module with nginx yourself since it is tricky to set up exactly right. Also, the stock nginx cores have various limitations and long standing bugs that can make some of this modules' features become disabled, not work properly, or run slower. The same applies to LuaJIT as well. OpenResty includes its own version of LuaJIT which gets specifically optimized and enhanced for the OpenResty environment. Alternatively, ngx_lua can be manually compiled into Nginx: -1. Install LuaJIT 2.0 or 2.1 (recommended) or Lua 5.1 (Lua 5.2 is *not* supported yet). LuaJIT can be downloaded from the [LuaJIT project website](http://luajit.org/download.html) and Lua 5.1, from the [Lua project website](http://www.lua.org/). Some distribution package managers also distribute LuaJIT and/or Lua. +1. LuaJIT can be downloaded from the [latest release of OpenResty's LuaJIT branch version](https://github.com/openresty/luajit2/releases). The official LuaJIT 2.0 and 2.1 releases are also supported, although the performance will be significantly lower in many cases. 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 version of Nginx [HERE](http://nginx.org/) (See [Nginx Compatibility](#nginx-compatibility)) @@ -345,29 +348,6 @@ To enable one or more of these macros, just pass extra C compiler options to the ./configure --with-cc-opt="-DNGX_LUA_USE_ASSERT -DNGX_LUA_ABORT_AT_PANIC" -[Back to TOC](#table-of-contents) - -Installation on Ubuntu 11.10 ----------------------------- - -Note that it is recommended to use LuaJIT 2.0 or LuaJIT 2.1 instead of the standard Lua 5.1 interpreter wherever possible. - -If the standard Lua 5.1 interpreter is required however, run the following command to install it from the Ubuntu repository: - -```bash - - apt-get install -y lua5.1 liblua5.1-0 liblua5.1-0-dev -``` - -Everything should be installed correctly, except for one small tweak. - -Library name `liblua.so` has been changed in liblua5.1 package, it only comes with `liblua5.1.so`, which needs to be symlinked to `/usr/lib` so it could be found during the configuration process. - -```bash - - ln -s /usr/lib/x86_64-linux-gnu/liblua5.1.so /usr/lib/liblua.so -``` - [Back to TOC](#table-of-contents) Community @@ -411,7 +391,7 @@ Lua/LuaJIT bytecode support As from the `v0.5.0rc32` release, all `*_by_lua_file` configure directives (such as [content_by_lua_file](#content_by_lua_file)) support loading Lua 5.1 and LuaJIT 2.0/2.1 raw bytecode files directly. -Please note that the bytecode format used by LuaJIT 2.0/2.1 is not compatible with that used by the standard Lua 5.1 interpreter. So if using LuaJIT 2.0/2.1 with ngx_lua, LuaJIT compatible bytecode files must be generated as shown: +Please note that the bytecode format used by LuaJIT 2.0/2.1 is not compatible with that used by the standard Lua 5.1 interpreter. So if you are using LuaJIT 2.0/2.1 with ngx_lua, LuaJIT compatible bytecode files must be generated as shown: ```bash @@ -431,20 +411,6 @@ Please refer to the official LuaJIT documentation on the `-b` option for more de Also, the bytecode files generated by LuaJIT 2.1 is *not* compatible with LuaJIT 2.0, and vice versa. The support for LuaJIT 2.1 bytecode was first added in ngx_lua v0.9.3. -Similarly, if using the standard Lua 5.1 interpreter with ngx_lua, Lua compatible bytecode files must be generated using the `luac` commandline utility as shown: - -```bash - - luac -o /path/to/output_file.luac /path/to/input_file.lua -``` - -Unlike as with LuaJIT, debug information is included in standard Lua 5.1 bytecode files by default. This can be striped out by specifying the `-s` option as shown: - -```bash - - luac -s -o /path/to/output_file.luac /path/to/input_file.lua -``` - Attempts to load standard Lua 5.1 bytecode files into ngx_lua instances linked to LuaJIT 2.0/2.1 or vice versa, will result in an error message, such as that below, being logged into the Nginx `error.log` file: @@ -642,8 +608,7 @@ This issue is due to limitations in the Nginx event model and only appears to af Lua Coroutine Yielding/Resuming ------------------------------- -* Because Lua's `dofile` and `require` builtins are currently implemented as C functions in both Lua 5.1 and LuaJIT 2.0/2.1, if the Lua file being loaded by `dofile` or `require` invokes [ngx.location.capture*](#ngxlocationcapture), [ngx.exec](#ngxexec), [ngx.exit](#ngxexit), or other API functions requiring yielding in the *top-level* scope of the Lua file, then the Lua error "attempt to yield across C-call boundary" will be raised. To avoid this, put these calls requiring yielding into your own Lua functions in the Lua file instead of the top-level scope of the file. -* As the standard Lua 5.1 interpreter's VM is not fully resumable, the methods [ngx.location.capture](#ngxlocationcapture), [ngx.location.capture_multi](#ngxlocationcapture_multi), [ngx.redirect](#ngxredirect), [ngx.exec](#ngxexec), and [ngx.exit](#ngxexit) cannot be used within the context of a Lua [pcall()](http://www.lua.org/manual/5.1/manual.html#pdf-pcall) or [xpcall()](http://www.lua.org/manual/5.1/manual.html#pdf-xpcall) or even the first line of the `for ... in ...` statement when the standard Lua 5.1 interpreter is used and the `attempt to yield across metamethod/C-call boundary` error will be produced. Please use LuaJIT 2.x, which supports a fully resumable VM, to avoid this. +* Because Lua's `dofile` and `require` builtins are currently implemented as C functions in LuaJIT 2.0/2.1, if the Lua file being loaded by `dofile` or `require` invokes [ngx.location.capture*](#ngxlocationcapture), [ngx.exec](#ngxexec), [ngx.exit](#ngxexit), or other API functions requiring yielding in the *top-level* scope of the Lua file, then the Lua error "attempt to yield across C-call boundary" will be raised. To avoid this, put these calls requiring yielding into your own Lua functions in the Lua file instead of the top-level scope of the file. [Back to TOC](#table-of-contents) @@ -995,7 +960,7 @@ This module is licensed under the BSD license. Copyright (C) 2009-2017, by Xiaozhe Wang (chaoslawful) . -Copyright (C) 2009-2018, by Yichun "agentzh" Zhang (章亦春) , OpenResty Inc. +Copyright (C) 2009-2019, by Yichun "agentzh" Zhang (章亦春) , OpenResty Inc. All rights reserved. @@ -1039,6 +1004,7 @@ See Also Directives ========== +* [lua_load_resty_core](#lua_load_resty_core) * [lua_capture_error_log](#lua_capture_error_log) * [lua_use_default_type](#lua_use_default_type) * [lua_malloc_trim](#lua_malloc_trim) @@ -1104,6 +1070,7 @@ Directives * [lua_check_client_abort](#lua_check_client_abort) * [lua_max_pending_timers](#lua_max_pending_timers) * [lua_max_running_timers](#lua_max_running_timers) +* [lua_sa_restart](#lua_sa_restart) The basic building blocks of scripting Nginx with Lua are directives. Directives are used to specify when the user Lua code is run and @@ -1113,6 +1080,38 @@ how the result will be used. Below is a diagram showing the order in which direc [Back to TOC](#table-of-contents) +lua_load_resty_core +------------------- + +**syntax:** *lua_load_resty_core on|off* + +**default:** *lua_load_resty_core on* + +**context:** *http* + +Controls whether the `resty.core` module (from +[lua-resty-core](https://github.com/openresty/lua-resty-core)) should be loaded +or not. When enabled, this directive is equivalent to executing the following +when the Lua VM is created: + +```lua + + require "resty.core" +``` + +Note that usage of the `resty.core` module is recommended, as its +FFI implementation is both faster, safer, and more complete than the Lua C API +of the ngx_lua module. + +It must also be noted that the Lua C API of the ngx_lua module will eventually +be removed, and usage of the FFI-based API (i.e. the `resty.core` +module) will become mandatory. This directive only aims at providing a +temporary backwards-compatibility mode in case of edge-cases. + +This directive was first introduced in the `v0.10.15` release. + +[Back to TOC](#directives) + lua_capture_error_log --------------------- **syntax:** *lua_capture_error_log size* @@ -2602,14 +2601,14 @@ SSL session resumption can then get immediately initiated and bypass the full SS Please note that TLS session tickets are very different and it is the clients' responsibility to cache the SSL session state when session tickets are used. SSL session resumptions based on TLS session tickets would happen automatically without going through this hook (nor the -[ssl_session_store_by_lua_block](#ssl_session_store_by_lua) hook). This hook is mainly +[ssl_session_store_by_lua*](#ssl_session_store_by_lua_block) hook). This hook is mainly for older or less capable SSL clients that can only do SSL sessions by session IDs. When [ssl_certificate_by_lua*](#ssl_certificate_by_lua_block) is specified at the same time, this hook usually runs before [ssl_certificate_by_lua*](#ssl_certificate_by_lua_block). When the SSL session is found and successfully loaded for the current SSL connection, SSL session resumption will happen and thus bypass the [ssl_certificate_by_lua*](#ssl_certificate_by_lua_block) -hook completely. In this case, NGINX also bypasses the [ssl_session_store_by_lua_block](#ssl_session_store_by_lua) +hook completely. In this case, NGINX also bypasses the [ssl_session_store_by_lua*](#ssl_session_store_by_lua_block) hook, for obvious reasons. To easily test this hook locally with a modern web browser, you can temporarily put the following line @@ -3108,6 +3107,23 @@ This directive was first introduced in the `v0.8.0` release. [Back to TOC](#directives) +lua_sa_restart +-------------- + +**syntax:** *lua_sa_restart on|off* + +**default:** *lua_sa_restart on* + +**context:** *http* + +When enabled, this module will set the `SA_RESTART` flag on nginx workers signal dispositions. + +This allows Lua I/O primitives to not be interrupted by nginx's handling of various signals. + +This directive was first introduced in the `v0.10.14` release. + +[Back to TOC](#directives) + Nginx API for Lua ================= @@ -3221,6 +3237,7 @@ Nginx API for Lua * [tcpsock:sslhandshake](#tcpsocksslhandshake) * [tcpsock:send](#tcpsocksend) * [tcpsock:receive](#tcpsockreceive) +* [tcpsock:receiveany](#tcpsockreceiveany) * [tcpsock:receiveuntil](#tcpsockreceiveuntil) * [tcpsock:close](#tcpsockclose) * [tcpsock:settimeout](#tcpsocksettimeout) @@ -4302,7 +4319,7 @@ ngx.req.get_method ------------------ **syntax:** *method_name = ngx.req.get_method()* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, balancer_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, balancer_by_lua*, log_by_lua** Retrieves the current request's request method name. Strings like `"GET"` and `"POST"` are returned instead of numerical [method constants](#http-method-constants). @@ -4887,7 +4904,7 @@ This function returns `nil` if 1. the request body has been read into disk temporary files, 1. or the request body has zero size. -If the request body has not been read yet, call [ngx.req.read_body](#ngxreqread_body) first (or turned on [lua_need_request_body](#lua_need_request_body) to force this module to read the request body. This is not recommended however). +If the request body has not been read yet, call [ngx.req.read_body](#ngxreqread_body) first (or turn on [lua_need_request_body](#lua_need_request_body) to force this module to read the request body. This is not recommended however). If the request body has been read into disk files, try calling the [ngx.req.get_body_file](#ngxreqget_body_file) function instead. @@ -4911,7 +4928,7 @@ Retrieves the file name for the in-file request body data. Returns `nil` if the The returned file is read only and is usually cleaned up by Nginx's memory pool. It should not be manually modified, renamed, or removed in Lua code. -If the request body has not been read yet, call [ngx.req.read_body](#ngxreqread_body) first (or turned on [lua_need_request_body](#lua_need_request_body) to force this module to read the request body. This is not recommended however). +If the request body has not been read yet, call [ngx.req.read_body](#ngxreqread_body) first (or turn on [lua_need_request_body](#lua_need_request_body) to force this module to read the request body. This is not recommended however). If the request body has been read into memory, try calling the [ngx.req.get_body_data](#ngxreqget_body_data) function instead. @@ -4931,7 +4948,9 @@ ngx.req.set_body_data Set the current request's request body using the in-memory data specified by the `data` argument. -If the current request's request body has not been read, then it will be properly discarded. When the current request's request body has been read into memory or buffered into a disk file, then the old request body's memory will be freed or the disk file will be cleaned up immediately, respectively. +If the request body has not been read yet, call [ngx.req.read_body](#ngxreqread_body) first (or turn on [lua_need_request_body](#lua_need_request_body) to force this module to read the request body. This is not recommended however). Additionally, the request body must not have been previously discarded by [ngx.req.discard_body](#ngxreqdiscard_body). + +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. This function was first introduced in the `v0.3.1rc18` release. @@ -4947,11 +4966,13 @@ ngx.req.set_body_file Set the current request's request body using the in-file data specified by the `file_name` argument. +If the request body has not been read yet, call [ngx.req.read_body](#ngxreqread_body) first (or turn on [lua_need_request_body](#lua_need_request_body) to force this module to read the request body. This is not recommended however). Additionally, the request body must not have been previously discarded by [ngx.req.discard_body](#ngxreqdiscard_body). + If the optional `auto_clean` argument is given a `true` value, then this file will be removed at request completion or the next time this function or [ngx.req.set_body_data](#ngxreqset_body_data) are called in the same request. The `auto_clean` is default to `false`. Please ensure that the file specified by the `file_name` argument exists and is readable by an Nginx worker process by setting its permission properly to avoid Lua exception errors. -If the current request's request body has not been read, then it will be properly discarded. When the current request's request body has been read into memory or buffered into a disk file, then the old request body's memory will be freed or the disk file will be cleaned up immediately, respectively. +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. This function was first introduced in the `v0.3.1rc18` release. @@ -6717,7 +6738,7 @@ ngx.shared.DICT.flush_expired Flushes out the expired items in the dictionary, up to the maximal number specified by the optional `max_count` argument. When the `max_count` argument is given `0` or not given at all, then it means unlimited. Returns the number of items that have actually been flushed. -Unlike the [flush_all](#ngxshareddictflush_all) method, this method actually free up the memory used by the expired items. +Unlike the [flush_all](#ngxshareddictflush_all) method, this method actually frees up the memory used by the expired items. This feature was first introduced in the `v0.6.3` release. @@ -7002,6 +7023,7 @@ Creates and returns a TCP or stream-oriented unix domain socket object (also kno * [settimeout](#tcpsocksettimeout) * [settimeouts](#tcpsocksettimeouts) * [setoption](#tcpsocksetoption) +* [receiveany](#tcpsockreceiveany) * [receiveuntil](#tcpsockreceiveuntil) * [setkeepalive](#tcpsocksetkeepalive) * [getreusedtimes](#tcpsockgetreusedtimes) @@ -7106,6 +7128,43 @@ An optional Lua table can be specified as the last argument to this method to sp * `pool` specify a custom name for the connection pool being used. If omitted, then the connection pool name will be generated from the string template `":"` or `""`. +* `pool_size` + specify the size of the connection pool. If omitted and no + `backlog` option was provided, no pool will be created. If omitted + but `backlog` was provided, the pool will be created with a default + size equal to the value of the [lua_socket_pool_size](#lua_socket_pool_size) + directive. + The connection pool holds up to `pool_size` alive connections + ready to be reused by subsequent calls to [connect](#tcpsockconnect), but + note that there is no upper limit to the total number of opened connections + outside of the pool. If you need to restrict the total number of opened + connections, specify the `backlog` option. + When the connection pool would exceed its size limit, the least recently used + (kept-alive) connection already in the pool will be closed to make room for + the current connection. + Note that the cosocket connection pool is per Nginx worker process rather + than per Nginx server instance, so the size limit specified here also applies + to every single Nginx worker process. Also note that the size of the connection + pool cannot be changed once it has been created. + This option was first introduced in the `v0.10.14` release. + +* `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). + 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 operation will abort once they have been queued for more + than `connect_timeout`, controlled by + [settimeouts](#tcpsocksettimeouts), and will return `nil` plus + the error string `"timeout"`. + This option was first introduced in the `v0.10.14` release. + The support for the options table argument was first introduced in the `v0.5.7` release. This method was first introduced in the `v0.5.0rc1` release. @@ -7231,6 +7290,40 @@ This feature was first introduced in the `v0.5.0rc1` release. [Back to TOC](#nginx-api-for-lua) +tcpsock:receiveany +------------------ +**syntax:** *data, err = tcpsock:receiveany(max)* + +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua** + +Returns any data received by the connected socket, at most `max` bytes. + +This method is a synchronous operation just like the [send](#tcpsocksend) method and is 100% nonblocking. + +In case of success, it returns the data received; in case of error, it returns `nil` with a string describing the error. + +If the received data is more than this size, this method will return with exactly this size of data. +The remaining data in the underlying receive buffer could be returned in the next reading operation. + +Timeout for the reading operation is controlled by the [lua_socket_read_timeout](#lua_socket_read_timeout) config directive and the [settimeouts](#tcpsocksettimeouts) method. And the latter takes priority. For example: + +```lua + + sock:settimeouts(1000, 1000, 1000) -- one second timeout for connect/read/write + local data, err = sock:receiveany(10 * 1024 * 1024) -- read any data, at most 10K + if not data then + ngx.say("failed to read any data: ", err) + return + end + ngx.say("successfully read: ", data) +``` + +This method doesn't automatically close the current connection when the read timeout error occurs. For other connection errors, this method always automatically closes the connection. + +This feature was first introduced in the `v0.10.14` release. + +[Back to TOC](#nginx-api-for-lua) + tcpsock:receiveuntil -------------------- **syntax:** *iterator = tcpsock:receiveuntil(pattern, options?)* @@ -7403,13 +7496,31 @@ Puts the current socket's connection immediately into the cosocket built-in conn The first optional argument, `timeout`, can be used to specify the maximal idle timeout (in milliseconds) for the current connection. If omitted, the default setting in the [lua_socket_keepalive_timeout](#lua_socket_keepalive_timeout) config directive will be used. If the `0` value is given, then the timeout interval is unlimited. -The second optional argument, `size`, can be used to specify the maximal number of connections allowed in the connection pool for the current server (i.e., the current host-port pair or the unix domain socket file path). Note that the size of the connection pool cannot be changed once the pool is created. When this argument is omitted, the default setting in the [lua_socket_pool_size](#lua_socket_pool_size) config directive will be used. - -When the connection pool exceeds the available size limit, the least recently used (idle) connection already in the pool will be closed to make room for the current connection. - -Note that the cosocket connection pool is per Nginx worker process rather than per Nginx server instance, so the size limit specified here also applies to every single Nginx worker process. - -Idle connections in the pool will be monitored for any exceptional events like connection abortion or unexpected incoming data on the line, in which cases the connection in question will be closed and removed from the pool. +The second optional argument `size` is considered deprecated since +the `v0.10.14` release of this module, in favor of the +`pool_size` option of the [connect](#tcpsockconnect) method. +Since the `v0.10.14` release, this option will only take effect if +the call to [connect](#tcpsockconnect) did not already create a connection +pool. +When this option takes effect (no connection pool was previously created by +[connect](#tcpsockconnect)), it will specify the size of the connection pool, +and create it. +If omitted (and no pool was previously created), the default size is the value +of the [lua_socket_pool_size](#lua_socket_pool_size) directive. +The connection pool holds up to `size` alive connections ready to be +reused by subsequent calls to [connect](#tcpsockconnect), but note that there +is no upper limit to the total number of opened connections outside of the +pool. +When the connection pool would exceed its size limit, the least recently used +(kept-alive) connection already in the pool will be closed to make room for +the current connection. +Note that the cosocket connection pool is per Nginx worker process rather +than per Nginx server instance, so the size limit specified here also applies +to every single Nginx worker process. Also note that the size of the connection +pool cannot be changed once it has been created. +If you need to restrict the total number of opened connections, specify both +the `pool_size` and `backlog` option in the call to +[connect](#tcpsockconnect). In case of success, this method returns `1`; otherwise, it returns `nil` and a string describing the error. @@ -8181,7 +8292,7 @@ This Lua module does not ship with this ngx_lua module itself rather it is shipp the [lua-resty-core](https://github.com/openresty/lua-resty-core) library. -Please refer to the [documentation](https://github.com/openresty/lua-resty-core/blob/ocsp-cert-by-lua-2/lib/ngx/ocsp.md) +Please refer to the [documentation](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ocsp.md) for this `ngx.ocsp` Lua module for more details. This feature requires at least ngx_lua `v0.10.0`. diff --git a/debian/modules/http-lua/config b/debian/modules/http-lua/config index 044deb9..e1d5e35 100644 --- a/debian/modules/http-lua/config +++ b/debian/modules/http-lua/config @@ -361,6 +361,8 @@ HTTP_LUA_SRCS=" \ $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_log_ringbuf.c \ + $ngx_addon_dir/src/ngx_http_lua_input_filters.c \ + $ngx_addon_dir/src/ngx_http_lua_pipe.c \ " HTTP_LUA_DEPS=" \ @@ -422,6 +424,8 @@ HTTP_LUA_DEPS=" \ $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_log_ringbuf.h \ + $ngx_addon_dir/src/ngx_http_lua_input_filters.h \ + $ngx_addon_dir/src/ngx_http_lua_pipe.h \ " CFLAGS="$CFLAGS -DNDK_SET_VAR" @@ -474,6 +478,17 @@ ngx_feature_test='setsockopt(1, SOL_SOCKET, SO_PASSCRED, NULL, 0);' . auto/feature +ngx_feature="SA_RESTART" +ngx_feature_libs= +ngx_feature_name="NGX_HTTP_LUA_HAVE_SA_RESTART" +ngx_feature_run=no +ngx_feature_incs="#include " +ngx_feature_path= +ngx_feature_test='struct sigaction act; + act.sa_flags |= SA_RESTART;' + +. auto/feature + ngx_feature="__attribute__(constructor)" ngx_feature_libs= ngx_feature_name="NGX_HTTP_LUA_HAVE_CONSTRUCTOR" @@ -512,6 +527,36 @@ CC_TEST_FLAGS="$SAVED_CC_TEST_FLAGS" # ---------------------------------------- +ngx_feature="pipe2" +ngx_feature_libs= +ngx_feature_name="NGX_HTTP_LUA_HAVE_PIPE2" +ngx_feature_run=no +ngx_feature_incs="#include " +ngx_feature_test="int fd[2]; pipe2(fd, O_CLOEXEC|O_NONBLOCK);" +SAVED_CC_TEST_FLAGS="$CC_TEST_FLAGS" +CC_TEST_FLAGS="-Werror -Wall $CC_TEST_FLAGS" + +. auto/feature + +CC_TEST_FLAGS="$SAVED_CC_TEST_FLAGS" + +# ---------------------------------------- + +ngx_feature="signalfd" +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);" +SAVED_CC_TEST_FLAGS="$CC_TEST_FLAGS" +CC_TEST_FLAGS="-Werror -Wall $CC_TEST_FLAGS" + +. auto/feature + +CC_TEST_FLAGS="$SAVED_CC_TEST_FLAGS" + +# ---------------------------------------- + if test -n "$ngx_module_link"; then ngx_module_type=HTTP_AUX_FILTER ngx_module_name=$ngx_addon_name diff --git a/debian/modules/http-lua/doc/HttpLuaModule.wiki b/debian/modules/http-lua/doc/HttpLuaModule.wiki index e3c61e2..ff9b269 100644 --- a/debian/modules/http-lua/doc/HttpLuaModule.wiki +++ b/debian/modules/http-lua/doc/HttpLuaModule.wiki @@ -2,6 +2,8 @@ ngx_http_lua_module - Embed the power of Lua into Nginx HTTP Servers. +This module is a core component of OpenResty. If you are using this module, then you are essentially using OpenResty :) + ''This module is not distributed with the Nginx source.'' See [[#Installation|the installation instructions]]. = Status = @@ -10,7 +12,7 @@ Production ready. = Version = -This document describes ngx_lua [https://github.com/openresty/lua-nginx-module/tags v0.10.13] released on 22 April 2018. +This document describes ngx_lua [https://github.com/openresty/lua-nginx-module/tags v0.10.15] released on March 14th, 2019. = Synopsis = @@ -130,7 +132,9 @@ This document describes ngx_lua [https://github.com/openresty/lua-nginx-module/t = Description = -This module embeds Lua, via the standard Lua 5.1 interpreter or [http://luajit.org/luajit.html LuaJIT 2.0/2.1], into Nginx and by leveraging Nginx's subrequests, allows the integration of the powerful Lua threads (Lua coroutines) into the Nginx event model. +This module is a core component of OpenResty. If you are using this module, then you are essentially using OpenResty :) + +This module embeds Lua, via [http://luajit.org/luajit.html LuaJIT 2.0/2.1], into Nginx and by leveraging Nginx's subrequests, allows the integration of the powerful Lua threads (Lua coroutines) into the Nginx event model. Unlike [https://httpd.apache.org/docs/trunk/mod/mod_lua.html Apache's mod_lua] and [http://redmine.lighttpd.net/wiki/1/Docs:ModMagnet Lighttpd's mod_magnet], Lua code executed using this module can be ''100% non-blocking'' on network traffic as long as the [[#Nginx API for Lua|Nginx API for Lua]] provided by this module is used to handle requests to upstream services such as MySQL, PostgreSQL, Memcached, Redis, or upstream HTTP web services. @@ -199,11 +203,11 @@ Nginx cores older than 1.6.0 (exclusive) are *not* supported. = Installation = -It is *highly* recommended to use [http://openresty.org OpenResty releases] which integrate Nginx, ngx_lua, LuaJIT 2.1, as well as other powerful companion Nginx modules and Lua libraries. It is discouraged to build this module with nginx yourself since it is tricky to set up exactly right. Also, the stock nginx cores have various limitations and long standing bugs that can make some of this modules' features become disabled, not work properly, or run slower. The same applies to LuaJIT as well. OpenResty includes its own version of LuaJIT which gets specifically optimized and enhanced for the OpenResty environment. +It is *highly* recommended to use [http://openresty.org OpenResty releases] which integrate Nginx, ngx_lua, OpenResty's LuaJIT 2.1 branch version, as well as other powerful companion Nginx modules and Lua libraries. It is discouraged to build this module with nginx yourself since it is tricky to set up exactly right. Also, the stock nginx cores have various limitations and long standing bugs that can make some of this modules' features become disabled, not work properly, or run slower. The same applies to LuaJIT as well. OpenResty includes its own version of LuaJIT which gets specifically optimized and enhanced for the OpenResty environment. Alternatively, ngx_lua can be manually compiled into Nginx: -# Install LuaJIT 2.0 or 2.1 (recommended) or Lua 5.1 (Lua 5.2 is ''not'' supported yet). LuaJIT can be downloaded from the [http://luajit.org/download.html LuaJIT project website] and Lua 5.1, from the [http://www.lua.org/ Lua project website]. Some distribution package managers also distribute LuaJIT and/or Lua. +# LuaJIT can be downloaded from the [https://github.com/openresty/luajit2/releases latest release of OpenResty's LuaJIT branch version]. The official LuaJIT 2.0 and 2.1 releases are also supported, although the performance will be significantly lower in many cases. # 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 version of Nginx [http://nginx.org/ HERE] (See [[#Nginx Compatibility|Nginx Compatibility]]) @@ -271,24 +275,6 @@ To enable one or more of these macros, just pass extra C compiler options to the ./configure --with-cc-opt="-DNGX_LUA_USE_ASSERT -DNGX_LUA_ABORT_AT_PANIC" -== Installation on Ubuntu 11.10 == - -Note that it is recommended to use LuaJIT 2.0 or LuaJIT 2.1 instead of the standard Lua 5.1 interpreter wherever possible. - -If the standard Lua 5.1 interpreter is required however, run the following command to install it from the Ubuntu repository: - - -apt-get install -y lua5.1 liblua5.1-0 liblua5.1-0-dev - - -Everything should be installed correctly, except for one small tweak. - -Library name liblua.so has been changed in liblua5.1 package, it only comes with liblua5.1.so, which needs to be symlinked to /usr/lib so it could be found during the configuration process. - - -ln -s /usr/lib/x86_64-linux-gnu/liblua5.1.so /usr/lib/liblua.so - - = Community = == English Mailing List == @@ -314,7 +300,7 @@ Please submit bug reports, wishlists, or patches by As from the v0.5.0rc32 release, all *_by_lua_file configure directives (such as [[#content_by_lua_file|content_by_lua_file]]) support loading Lua 5.1 and LuaJIT 2.0/2.1 raw bytecode files directly. -Please note that the bytecode format used by LuaJIT 2.0/2.1 is not compatible with that used by the standard Lua 5.1 interpreter. So if using LuaJIT 2.0/2.1 with ngx_lua, LuaJIT compatible bytecode files must be generated as shown: +Please note that the bytecode format used by LuaJIT 2.0/2.1 is not compatible with that used by the standard Lua 5.1 interpreter. So if you are using LuaJIT 2.0/2.1 with ngx_lua, LuaJIT compatible bytecode files must be generated as shown: /path/to/luajit/bin/luajit -b /path/to/input_file.lua /path/to/output_file.ljbc @@ -332,18 +318,6 @@ http://luajit.org/running.html#opt_b Also, the bytecode files generated by LuaJIT 2.1 is ''not'' compatible with LuaJIT 2.0, and vice versa. The support for LuaJIT 2.1 bytecode was first added in ngx_lua v0.9.3. -Similarly, if using the standard Lua 5.1 interpreter with ngx_lua, Lua compatible bytecode files must be generated using the luac commandline utility as shown: - - - luac -o /path/to/output_file.luac /path/to/input_file.lua - - -Unlike as with LuaJIT, debug information is included in standard Lua 5.1 bytecode files by default. This can be striped out by specifying the -s option as shown: - - - luac -s -o /path/to/output_file.luac /path/to/input_file.lua - - Attempts to load standard Lua 5.1 bytecode files into ngx_lua instances linked to LuaJIT 2.0/2.1 or vice versa, will result in an error message, such as that below, being logged into the Nginx error.log file: @@ -510,8 +484,7 @@ However, later attempts to manipulate the cosocket object will fail and return t This issue is due to limitations in the Nginx event model and only appears to affect Mac OS X. == Lua Coroutine Yielding/Resuming == -* Because Lua's dofile and require builtins are currently implemented as C functions in both Lua 5.1 and LuaJIT 2.0/2.1, if the Lua file being loaded by dofile or require invokes [[#ngx.location.capture|ngx.location.capture*]], [[#ngx.exec|ngx.exec]], [[#ngx.exit|ngx.exit]], or other API functions requiring yielding in the *top-level* scope of the Lua file, then the Lua error "attempt to yield across C-call boundary" will be raised. To avoid this, put these calls requiring yielding into your own Lua functions in the Lua file instead of the top-level scope of the file. -* As the standard Lua 5.1 interpreter's VM is not fully resumable, the methods [[#ngx.location.capture|ngx.location.capture]], [[#ngx.location.capture_multi|ngx.location.capture_multi]], [[#ngx.redirect|ngx.redirect]], [[#ngx.exec|ngx.exec]], and [[#ngx.exit|ngx.exit]] cannot be used within the context of a Lua [http://www.lua.org/manual/5.1/manual.html#pdf-pcall pcall()] or [http://www.lua.org/manual/5.1/manual.html#pdf-xpcall xpcall()] or even the first line of the for ... in ... statement when the standard Lua 5.1 interpreter is used and the attempt to yield across metamethod/C-call boundary error will be produced. Please use LuaJIT 2.x, which supports a fully resumable VM, to avoid this. +* Because Lua's dofile and require builtins are currently implemented as C functions in LuaJIT 2.0/2.1, if the Lua file being loaded by dofile or require invokes [[#ngx.location.capture|ngx.location.capture*]], [[#ngx.exec|ngx.exec]], [[#ngx.exit|ngx.exit]], or other API functions requiring yielding in the *top-level* scope of the Lua file, then the Lua error "attempt to yield across C-call boundary" will be raised. To avoid this, put these calls requiring yielding into your own Lua functions in the Lua file instead of the top-level scope of the file. == Lua Variable Scope == Care must be taken when importing modules and this form should be used: @@ -817,7 +790,7 @@ This module is licensed under the BSD license. Copyright (C) 2009-2017, by Xiaozhe Wang (chaoslawful) . -Copyright (C) 2009-2018, by Yichun "agentzh" Zhang (章亦春) , OpenResty Inc. +Copyright (C) 2009-2019, by Yichun "agentzh" Zhang (章亦春) , OpenResty Inc. All rights reserved. @@ -862,6 +835,34 @@ how the result will be used. Below is a diagram showing the order in which direc ![Lua Nginx Modules Directives](https://cloud.githubusercontent.com/assets/2137369/15272097/77d1c09e-1a37-11e6-97ef-d9767035fc3e.png) +== lua_load_resty_core == + +'''syntax:''' ''lua_load_resty_core on|off'' + +'''default:''' ''lua_load_resty_core on'' + +'''context:''' ''http'' + +Controls whether the resty.core module (from +[https://github.com/openresty/lua-resty-core lua-resty-core]) should be loaded +or not. When enabled, this directive is equivalent to executing the following +when the Lua VM is created: + + + require "resty.core" + + +Note that usage of the resty.core module is recommended, as its +FFI implementation is both faster, safer, and more complete than the Lua C API +of the ngx_lua module. + +It must also be noted that the Lua C API of the ngx_lua module will eventually +be removed, and usage of the FFI-based API (i.e. the resty.core +module) will become mandatory. This directive only aims at providing a +temporary backwards-compatibility mode in case of edge-cases. + +This directive was first introduced in the v0.10.15 release. + == lua_capture_error_log == '''syntax:''' ''lua_capture_error_log size'' @@ -2196,14 +2197,14 @@ SSL session resumption can then get immediately initiated and bypass the full SS Please note that TLS session tickets are very different and it is the clients' responsibility to cache the SSL session state when session tickets are used. SSL session resumptions based on TLS session tickets would happen automatically without going through this hook (nor the -[[#ssl_session_store_by_lua*|ssl_session_store_by_lua_block]] hook). This hook is mainly +[[#ssl_session_store_by_lua_block|ssl_session_store_by_lua*]] hook). This hook is mainly for older or less capable SSL clients that can only do SSL sessions by session IDs. When [[#ssl_certificate_by_lua_block|ssl_certificate_by_lua*]] is specified at the same time, this hook usually runs before [[#ssl_certificate_by_lua_block|ssl_certificate_by_lua*]]. When the SSL session is found and successfully loaded for the current SSL connection, SSL session resumption will happen and thus bypass the [[#ssl_certificate_by_lua_block|ssl_certificate_by_lua*]] -hook completely. In this case, NGINX also bypasses the [[#ssl_session_store_by_lua*|ssl_session_store_by_lua_block]] +hook completely. In this case, NGINX also bypasses the [[#ssl_session_store_by_lua_block|ssl_session_store_by_lua*]] hook, for obvious reasons. To easily test this hook locally with a modern web browser, you can temporarily put the following line @@ -2626,6 +2627,20 @@ When exceeding this limit, Nginx will stop running the callbacks of newly expire This directive was first introduced in the v0.8.0 release. +== lua_sa_restart == + +'''syntax:''' ''lua_sa_restart on|off'' + +'''default:''' ''lua_sa_restart on'' + +'''context:''' ''http'' + +When enabled, this module will set the `SA_RESTART` flag on nginx workers signal dispositions. + +This allows Lua I/O primitives to not be interrupted by nginx's handling of various signals. + +This directive was first introduced in the v0.10.14 release. + = Nginx API for Lua = @@ -3563,7 +3578,7 @@ This method does not work in HTTP/2 requests yet. == ngx.req.get_method == '''syntax:''' ''method_name = ngx.req.get_method()'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, balancer_by_lua*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, balancer_by_lua*, log_by_lua*'' Retrieves the current request's request method name. Strings like "GET" and "POST" are returned instead of numerical [[#HTTP method constants|method constants]]. @@ -4071,7 +4086,7 @@ This function returns nil if # the request body has been read into disk temporary files, # or the request body has zero size. -If the request body has not been read yet, call [[#ngx.req.read_body|ngx.req.read_body]] first (or turned on [[#lua_need_request_body|lua_need_request_body]] to force this module to read the request body. This is not recommended however). +If the request body has not been read yet, call [[#ngx.req.read_body|ngx.req.read_body]] first (or turn on [[#lua_need_request_body|lua_need_request_body]] to force this module to read the request body. This is not recommended however). If the request body has been read into disk files, try calling the [[#ngx.req.get_body_file|ngx.req.get_body_file]] function instead. @@ -4092,7 +4107,7 @@ Retrieves the file name for the in-file request body data. Returns nildata argument. -If the current request's request body has not been read, then it will be properly discarded. When the current request's request body has been read into memory or buffered into a disk file, then the old request body's memory will be freed or the disk file will be cleaned up immediately, respectively. +If the request body has not been read yet, call [[#ngx.req.read_body|ngx.req.read_body]] first (or turn on [[#lua_need_request_body|lua_need_request_body]] to force this module to read the request body. This is not recommended however). Additionally, the request body must not have been previously discarded by [[#ngx.req.discard_body|ngx.req.discard_body]]. + +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. This function was first introduced in the v0.3.1rc18 release. @@ -4122,11 +4139,13 @@ See also [[#ngx.req.set_body_file|ngx.req.set_body_file]]. Set the current request's request body using the in-file data specified by the file_name argument. +If the request body has not been read yet, call [[#ngx.req.read_body|ngx.req.read_body]] first (or turn on [[#lua_need_request_body|lua_need_request_body]] to force this module to read the request body. This is not recommended however). Additionally, the request body must not have been previously discarded by [[#ngx.req.discard_body|ngx.req.discard_body]]. + If the optional auto_clean argument is given a true value, then this file will be removed at request completion or the next time this function or [[#ngx.req.set_body_data|ngx.req.set_body_data]] are called in the same request. The auto_clean is default to false. Please ensure that the file specified by the file_name argument exists and is readable by an Nginx worker process by setting its permission properly to avoid Lua exception errors. -If the current request's request body has not been read, then it will be properly discarded. When the current request's request body has been read into memory or buffered into a disk file, then the old request body's memory will be freed or the disk file will be cleaned up immediately, respectively. +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. This function was first introduced in the v0.3.1rc18 release. @@ -5648,7 +5667,7 @@ See also [[#ngx.shared.DICT.flush_expired|ngx.shared.DICT.flush_expired]] and [[ Flushes out the expired items in the dictionary, up to the maximal number specified by the optional max_count argument. When the max_count argument is given 0 or not given at all, then it means unlimited. Returns the number of items that have actually been flushed. -Unlike the [[#ngx.shared.DICT.flush_all|flush_all]] method, this method actually free up the memory used by the expired items. +Unlike the [[#ngx.shared.DICT.flush_all|flush_all]] method, this method actually frees up the memory used by the expired items. This feature was first introduced in the v0.6.3 release. @@ -5894,6 +5913,7 @@ Creates and returns a TCP or stream-oriented unix domain socket object (also kno * [[#tcpsock:settimeout|settimeout]] * [[#tcpsock:settimeouts|settimeouts]] * [[#tcpsock:setoption|setoption]] +* [[#tcpsock:receiveany|receiveany]] * [[#tcpsock:receiveuntil|receiveuntil]] * [[#tcpsock:setkeepalive|setkeepalive]] * [[#tcpsock:getreusedtimes|getreusedtimes]] @@ -5991,6 +6011,43 @@ An optional Lua table can be specified as the last argument to this method to sp * pool : specify a custom name for the connection pool being used. If omitted, then the connection pool name will be generated from the string template ":" or "". +* pool_size +: specify the size of the connection pool. If omitted and no +: backlog option was provided, no pool will be created. If omitted +: but backlog was provided, the pool will be created with a default +: size equal to the value of the [[#lua_socket_pool_size|lua_socket_pool_size]] +: directive. +: The connection pool holds up to pool_size alive connections +: ready to be reused by subsequent calls to [[#tcpsock:connect|connect]], but +: note that there is no upper limit to the total number of opened connections +: outside of the pool. If you need to restrict the total number of opened +: connections, specify the backlog option. +: When the connection pool would exceed its size limit, the least recently used +: (kept-alive) connection already in the pool will be closed to make room for +: the current connection. +: Note that the cosocket connection pool is per Nginx worker process rather +: than per Nginx server instance, so the size limit specified here also applies +: to every single Nginx worker process. Also note that the size of the connection +: pool cannot be changed once it has been created. +: This option was first introduced in the v0.10.14 release. + +* 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). +: 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 operation will abort once they have been queued for more +: than connect_timeout, controlled by +: [[#tcpsock:settimeouts|settimeouts]], and will return nil plus +: the error string "timeout". +: This option was first introduced in the v0.10.14 release. + The support for the options table argument was first introduced in the v0.5.7 release. This method was first introduced in the v0.5.0rc1 release. @@ -6103,6 +6160,36 @@ Since the v0.8.8 release, this method no longer automatically close This feature was first introduced in the v0.5.0rc1 release. +== tcpsock:receiveany == +'''syntax:''' ''data, err = tcpsock:receiveany(max)'' + +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*'' + +Returns any data received by the connected socket, at most max bytes. + +This method is a synchronous operation just like the [[#tcpsock:send|send]] method and is 100% nonblocking. + +In case of success, it returns the data received; in case of error, it returns nil with a string describing the error. + +If the received data is more than this size, this method will return with exactly this size of data. +The remaining data in the underlying receive buffer could be returned in the next reading operation. + +Timeout for the reading operation is controlled by the [[#lua_socket_read_timeout|lua_socket_read_timeout]] config directive and the [[#tcpsock:settimeouts|settimeouts]] method. And the latter takes priority. For example: + + + sock:settimeouts(1000, 1000, 1000) -- one second timeout for connect/read/write + local data, err = sock:receiveany(10 * 1024 * 1024) -- read any data, at most 10K + if not data then + ngx.say("failed to read any data: ", err) + return + end + ngx.say("successfully read: ", data) + + +This method doesn't automatically close the current connection when the read timeout error occurs. For other connection errors, this method always automatically closes the connection. + +This feature was first introduced in the v0.10.14 release. + == tcpsock:receiveuntil == '''syntax:''' ''iterator = tcpsock:receiveuntil(pattern, options?)'' @@ -6255,13 +6342,31 @@ Puts the current socket's connection immediately into the cosocket built-in conn The first optional argument, timeout, can be used to specify the maximal idle timeout (in milliseconds) for the current connection. If omitted, the default setting in the [[#lua_socket_keepalive_timeout|lua_socket_keepalive_timeout]] config directive will be used. If the 0 value is given, then the timeout interval is unlimited. -The second optional argument, size, can be used to specify the maximal number of connections allowed in the connection pool for the current server (i.e., the current host-port pair or the unix domain socket file path). Note that the size of the connection pool cannot be changed once the pool is created. When this argument is omitted, the default setting in the [[#lua_socket_pool_size|lua_socket_pool_size]] config directive will be used. - -When the connection pool exceeds the available size limit, the least recently used (idle) connection already in the pool will be closed to make room for the current connection. - -Note that the cosocket connection pool is per Nginx worker process rather than per Nginx server instance, so the size limit specified here also applies to every single Nginx worker process. - -Idle connections in the pool will be monitored for any exceptional events like connection abortion or unexpected incoming data on the line, in which cases the connection in question will be closed and removed from the pool. +The second optional argument size is considered deprecated since +the v0.10.14 release of this module, in favor of the +pool_size option of the [[#tcpsock:connect|connect]] method. +Since the v0.10.14 release, this option will only take effect if +the call to [[#tcpsock:connect|connect]] did not already create a connection +pool. +When this option takes effect (no connection pool was previously created by +[[#tcpsock:connect|connect]]), it will specify the size of the connection pool, +and create it. +If omitted (and no pool was previously created), the default size is the value +of the [[#lua_socket_pool_size|lua_socket_pool_size]] directive. +The connection pool holds up to size alive connections ready to be +reused by subsequent calls to [[#tcpsock:connect|connect]], but note that there +is no upper limit to the total number of opened connections outside of the +pool. +When the connection pool would exceed its size limit, the least recently used +(kept-alive) connection already in the pool will be closed to make room for +the current connection. +Note that the cosocket connection pool is per Nginx worker process rather +than per Nginx server instance, so the size limit specified here also applies +to every single Nginx worker process. Also note that the size of the connection +pool cannot be changed once it has been created. +If you need to restrict the total number of opened connections, specify both +the pool_size and backlog option in the call to +[[#tcpsock:connect|connect]]. In case of success, this method returns 1; otherwise, it returns nil and a string describing the error. @@ -6950,7 +7055,7 @@ This Lua module does not ship with this ngx_lua module itself rather it is shipp the [https://github.com/openresty/lua-resty-core lua-resty-core] library. -Please refer to the [https://github.com/openresty/lua-resty-core/blob/ocsp-cert-by-lua-2/lib/ngx/ocsp.md documentation] +Please refer to the [https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ocsp.md documentation] for this ngx.ocsp Lua module for more details. This feature requires at least ngx_lua v0.10.0. diff --git a/debian/modules/http-lua/src/api/ngx_http_lua_api.h b/debian/modules/http-lua/src/api/ngx_http_lua_api.h index c7c0e6b..129eb99 100644 --- a/debian/modules/http-lua/src/api/ngx_http_lua_api.h +++ b/debian/modules/http-lua/src/api/ngx_http_lua_api.h @@ -19,7 +19,7 @@ /* Public API for other Nginx modules */ -#define ngx_http_lua_version 10013 +#define ngx_http_lua_version 10015 typedef struct { diff --git a/debian/modules/http-lua/src/ngx_http_lua_accessby.c b/debian/modules/http-lua/src/ngx_http_lua_accessby.c index 56bf0fa..d3fe294 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_accessby.c +++ b/debian/modules/http-lua/src/ngx_http_lua_accessby.c @@ -60,7 +60,7 @@ ngx_http_lua_access_handler(ngx_http_request_t *r) #endif if (cur_ph < last_ph) { - dd("swaping the contents of cur_ph and last_ph..."); + dd("swapping the contents of cur_ph and last_ph..."); tmp = *cur_ph; @@ -261,9 +261,11 @@ ngx_http_lua_access_by_chunk(lua_State *L, ngx_http_request_t *r) /* 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); diff --git a/debian/modules/http-lua/src/ngx_http_lua_api.c b/debian/modules/http-lua/src/ngx_http_lua_api.c index 7b590e7..ac014f2 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_api.c +++ b/debian/modules/http-lua/src/ngx_http_lua_api.c @@ -195,7 +195,7 @@ ngx_http_lua_shared_memory_init(ngx_shm_zone_t *shm_zone, void *data) lmcf->shm_zones_inited++; if (lmcf->shm_zones_inited == lmcf->shm_zones->nelts - && lmcf->init_handler) + && lmcf->init_handler && !ngx_test_config) { saved_cycle = ngx_cycle; ngx_cycle = ctx->cycle; diff --git a/debian/modules/http-lua/src/ngx_http_lua_balancer.c b/debian/modules/http-lua/src/ngx_http_lua_balancer.c index fdf2af3..3ecd592 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_balancer.c +++ b/debian/modules/http-lua/src/ngx_http_lua_balancer.c @@ -362,6 +362,8 @@ ngx_http_lua_balancer_by_chunk(lua_State *L, ngx_http_request_t *r) /* init nginx context in Lua VM */ ngx_http_lua_set_req(L, r); + +#ifndef OPENRESTY_LUAJIT ngx_http_lua_create_new_globals_table(L, 0 /* narr */, 1 /* nrec */); /* {{{ make new env inheriting main thread's globals table */ @@ -372,6 +374,7 @@ ngx_http_lua_balancer_by_chunk(lua_State *L, ngx_http_request_t *r) /* }}} */ lua_setfenv(L, -2); /* set new running env for the code closure */ +#endif /* OPENRESTY_LUAJIT */ lua_pushcfunction(L, ngx_http_lua_traceback); lua_insert(L, 1); /* put it under chunk and args */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_bodyfilterby.c b/debian/modules/http-lua/src/ngx_http_lua_bodyfilterby.c index 2b3c38f..f3af14c 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_bodyfilterby.c +++ b/debian/modules/http-lua/src/ngx_http_lua_bodyfilterby.c @@ -32,10 +32,6 @@ static void ngx_http_lua_body_filter_by_lua_env(lua_State *L, static ngx_http_output_body_filter_pt ngx_http_next_body_filter; -/* key for the ngx_chain_t *in pointer in the Lua thread */ -#define ngx_http_lua_chain_key "__ngx_cl" - - /** * Set environment table for the given code closure. * @@ -51,12 +47,14 @@ static void ngx_http_lua_body_filter_by_lua_env(lua_State *L, ngx_http_request_t *r, ngx_chain_t *in) { - /* set nginx request pointer to current lua thread's globals table */ + ngx_http_lua_main_conf_t *lmcf; + ngx_http_lua_set_req(L, r); - lua_pushlightuserdata(L, in); - lua_setglobal(L, ngx_http_lua_chain_key); + lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); + lmcf->body_filter_chain = in; +#ifndef OPENRESTY_LUAJIT /** * we want to create empty environment for current script * @@ -79,6 +77,7 @@ ngx_http_lua_body_filter_by_lua_env(lua_State *L, ngx_http_request_t *r, /* }}} */ lua_setfenv(L, -2); /* set new running env for the code closure */ +#endif /* OPENRESTY_LUAJIT */ } @@ -236,8 +235,8 @@ ngx_http_lua_body_filter(ngx_http_request_t *r, ngx_chain_t *in) ngx_int_t rc; uint16_t old_context; ngx_http_cleanup_t *cln; - lua_State *L; ngx_chain_t *out; + ngx_http_lua_main_conf_t *lmcf; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua body filter for user lua code, uri \"%V\"", &r->uri); @@ -299,11 +298,8 @@ ngx_http_lua_body_filter(ngx_http_request_t *r, ngx_chain_t *in) return NGX_ERROR; } - L = ngx_http_lua_get_lua_vm(r, ctx); - - lua_getglobal(L, ngx_http_lua_chain_key); - out = lua_touserdata(L, -1); - lua_pop(L, 1); + lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); + out = lmcf->body_filter_chain; if (in == out) { return ngx_http_next_body_filter(r, in); @@ -345,7 +341,7 @@ ngx_http_lua_body_filter_init(void) int -ngx_http_lua_body_filter_param_get(lua_State *L) +ngx_http_lua_body_filter_param_get(lua_State *L, ngx_http_request_t *r) { u_char *data, *p; size_t size; @@ -354,6 +350,8 @@ ngx_http_lua_body_filter_param_get(lua_State *L) int idx; ngx_chain_t *in; + ngx_http_lua_main_conf_t *lmcf; + idx = luaL_checkint(L, 2); dd("index: %d", idx); @@ -363,8 +361,8 @@ ngx_http_lua_body_filter_param_get(lua_State *L) return 1; } - lua_getglobal(L, ngx_http_lua_chain_key); - in = lua_touserdata(L, -1); + lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); + in = lmcf->body_filter_chain; if (idx == 2) { /* asking for the eof argument */ @@ -442,6 +440,8 @@ ngx_http_lua_body_filter_param_set(lua_State *L, ngx_http_request_t *r, ngx_chain_t *cl; ngx_chain_t *in; + ngx_http_lua_main_conf_t *lmcf; + idx = luaL_checkint(L, 2); dd("index: %d", idx); @@ -450,13 +450,13 @@ ngx_http_lua_body_filter_param_set(lua_State *L, ngx_http_request_t *r, return luaL_error(L, "bad index: %d", idx); } + lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); + if (idx == 2) { /* overwriting the eof flag */ last = lua_toboolean(L, 3); - lua_getglobal(L, ngx_http_lua_chain_key); - in = lua_touserdata(L, -1); - lua_pop(L, 1); + in = lmcf->body_filter_chain; if (last) { ctx->seen_last_in_filter = 1; @@ -521,9 +521,7 @@ ngx_http_lua_body_filter_param_set(lua_State *L, ngx_http_request_t *r, case LUA_TNIL: /* discard the buffers */ - lua_getglobal(L, ngx_http_lua_chain_key); /* key val */ - in = lua_touserdata(L, -1); - lua_pop(L, 1); + in = lmcf->body_filter_chain; last = 0; @@ -557,9 +555,7 @@ ngx_http_lua_body_filter_param_set(lua_State *L, ngx_http_request_t *r, lua_typename(L, type)); } - lua_getglobal(L, ngx_http_lua_chain_key); - in = lua_touserdata(L, -1); - lua_pop(L, 1); + in = lmcf->body_filter_chain; last = 0; @@ -625,8 +621,8 @@ done: } } - lua_pushlightuserdata(L, cl); - lua_setglobal(L, ngx_http_lua_chain_key); + lmcf->body_filter_chain = cl; + return 0; } diff --git a/debian/modules/http-lua/src/ngx_http_lua_bodyfilterby.h b/debian/modules/http-lua/src/ngx_http_lua_bodyfilterby.h index 6a4b306..b108202 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_bodyfilterby.h +++ b/debian/modules/http-lua/src/ngx_http_lua_bodyfilterby.h @@ -21,7 +21,7 @@ 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); +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/debian/modules/http-lua/src/ngx_http_lua_cache.c b/debian/modules/http-lua/src/ngx_http_lua_cache.c index 5ea3069..5b29527 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_cache.c +++ b/debian/modules/http-lua/src/ngx_http_lua_cache.c @@ -35,11 +35,14 @@ static ngx_int_t ngx_http_lua_cache_load_code(ngx_log_t *log, lua_State *L, const char *key) { +#ifndef OPENRESTY_LUAJIT int rc; u_char *err; +#endif /* get code cache table */ - lua_pushlightuserdata(L, &ngx_http_lua_code_cache_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + code_cache_key)); lua_rawget(L, LUA_REGISTRYINDEX); /* sp++ */ dd("Code cache table to load: %p", lua_topointer(L, -1)); @@ -52,6 +55,10 @@ ngx_http_lua_cache_load_code(ngx_log_t *log, lua_State *L, lua_getfield(L, -1, key); /* sp++ */ if (lua_isfunction(L, -1)) { +#ifdef OPENRESTY_LUAJIT + lua_remove(L, -2); /* sp-- */ + return NGX_OK; +#else /* call closure factory to gen new closure */ rc = lua_pcall(L, 0, 1, 0); if (rc == 0) { @@ -73,6 +80,7 @@ ngx_http_lua_cache_load_code(ngx_log_t *log, lua_State *L, key, err); lua_pop(L, 2); return NGX_ERROR; +#endif /* OPENRESTY_LUAJIT */ } dd("Value associated with given key in code cache table is not code " @@ -102,10 +110,13 @@ ngx_http_lua_cache_load_code(ngx_log_t *log, lua_State *L, static ngx_int_t ngx_http_lua_cache_store_code(lua_State *L, const char *key) { +#ifndef OPENRESTY_LUAJIT int rc; +#endif /* get code cache table */ - lua_pushlightuserdata(L, &ngx_http_lua_code_cache_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + code_cache_key)); lua_rawget(L, LUA_REGISTRYINDEX); dd("Code cache table to store: %p", lua_topointer(L, -1)); @@ -121,12 +132,14 @@ ngx_http_lua_cache_store_code(lua_State *L, const char *key) /* remove cache table, leave closure factory at top of stack */ lua_pop(L, 1); /* closure */ +#ifndef OPENRESTY_LUAJIT /* call closure factory to generate new closure */ rc = lua_pcall(L, 0, 1, 0); if (rc != 0) { dd("Error: failed to call closure factory!!"); return NGX_ERROR; } +#endif return NGX_OK; } @@ -143,7 +156,8 @@ ngx_http_lua_cache_loadbuffer(ngx_log_t *log, lua_State *L, n = lua_gettop(L); - dd("XXX cache key: [%s]", cache_key); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, + "looking up Lua code cache with key '%s'", cache_key); rc = ngx_http_lua_cache_load_code(log, L, (char *) cache_key); if (rc == NGX_OK) { @@ -227,7 +241,8 @@ ngx_http_lua_cache_loadfile(ngx_log_t *log, lua_State *L, dd("CACHE file key already pre-calculated"); } - dd("XXX cache key for file: [%s]", cache_key); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, + "looking up Lua code cache with key '%s'", cache_key); rc = ngx_http_lua_cache_load_code(log, L, (char *) cache_key); if (rc == NGX_OK) { diff --git a/debian/modules/http-lua/src/ngx_http_lua_clfactory.c b/debian/modules/http-lua/src/ngx_http_lua_clfactory.c index 041f046..754ed8d 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_clfactory.c +++ b/debian/modules/http-lua/src/ngx_http_lua_clfactory.c @@ -15,11 +15,13 @@ #include "ngx_http_lua_clfactory.h" +#ifndef OPENRESTY_LUAJIT #define CLFACTORY_BEGIN_CODE "return function() " #define CLFACTORY_BEGIN_SIZE (sizeof(CLFACTORY_BEGIN_CODE) - 1) #define CLFACTORY_END_CODE "\nend" #define CLFACTORY_END_SIZE (sizeof(CLFACTORY_END_CODE) - 1) +#endif /* @@ -59,6 +61,7 @@ * length(Instruction) = 4 or 8 * little endian or big endian */ +#ifndef OPENRESTY_LUAJIT #define LUA_LITTLE_ENDIAN_4BYTES_CODE \ "\x24\x00\x00\x00\x1e\x00\x00\x01\x1e\x00\x80\x00" #define LUA_LITTLE_ENDIAN_8BYTES_CODE \ @@ -75,6 +78,7 @@ #define LUA_BIG_ENDIAN_8BYTES_CODE_LEN (8 + 8 + 8) #define LUAC_HEADERSIZE 12 #define LUAC_VERSION 0x51 +#endif /* OPENRESTY_LUAJIT */ /* @@ -147,6 +151,7 @@ * --------------------- */ +#ifndef OPENRESTY_LUAJIT #define POS_SOURCE_STR_LEN LUAC_HEADERSIZE #define POS_START_LINE (POS_SOURCE_STR_LEN + sizeof(size_t)) #define POS_LAST_LINE (POS_START_LINE + sizeof(int)) @@ -160,6 +165,7 @@ (POS_BYTECODE + LUA_LITTLE_ENDIAN_8BYTES_CODE_LEN \ + sizeof(int) + sizeof(int)) #define MAX_END_CODE_SIZE (sizeof(int) + sizeof(int) + sizeof(int)) +#endif /* OPENRESTY_LUAJIT */ /* * taken from chaoslawful: @@ -225,6 +231,7 @@ /* bytecode for luajit 2.0 */ +#ifndef OPENRESTY_LUAJIT #define LJ20_LITTLE_ENDIAN_CODE_STRIPPED \ "\x14\x03\x00\x01\x00\x01\x00\x03" \ "\x31\x00\x00\x00\x30\x00\x00\x80\x48\x00\x02\x00" \ @@ -275,6 +282,7 @@ #define LJ21_BCDUMP_VERSION 2 #define LJ20_BCDUMP_VERSION 1 #define LJ_SIGNATURE "\x1b\x4c\x4a" +#endif /* OPENRESTY_LUAJIT */ typedef enum { @@ -292,10 +300,11 @@ enum { typedef struct { ngx_http_lua_clfactory_file_type_e file_type; - int sent_begin; - int sent_end; int extraline; FILE *f; +#ifndef OPENRESTY_LUAJIT + int sent_begin; + int sent_end; size_t begin_code_len; size_t end_code_len; size_t rest_len; @@ -307,13 +316,16 @@ typedef struct { char *ptr; char str[MAX_END_CODE_SIZE]; } end_code; +#endif /* OPENRESTY_LUAJIT */ char buff[NGX_LUA_READER_BUFSIZE]; } ngx_http_lua_clfactory_file_ctx_t; typedef struct { +#ifndef OPENRESTY_LUAJIT int sent_begin; int sent_end; +#endif const char *s; size_t size; } ngx_http_lua_clfactory_buffer_ctx_t; @@ -325,9 +337,12 @@ static int ngx_http_lua_clfactory_errfile(lua_State *L, const char *what, int fname_index); static const char *ngx_http_lua_clfactory_getS(lua_State *L, void *ud, size_t *size); +#ifndef OPENRESTY_LUAJIT static long ngx_http_lua_clfactory_file_size(FILE *f); +#endif +#ifndef OPENRESTY_LUAJIT int ngx_http_lua_clfactory_bytecode_prepare(lua_State *L, ngx_http_lua_clfactory_file_ctx_t *lf, int fname_index) @@ -593,6 +608,7 @@ error: return LUA_ERRFILE; } +#endif /* OPENRESTY_LUAJIT */ ngx_int_t @@ -612,10 +628,12 @@ ngx_http_lua_clfactory_loadfile(lua_State *L, const char *filename) lf.extraline = 0; lf.file_type = NGX_LUA_TEXT_FILE; +#ifndef OPENRESTY_LUAJIT lf.begin_code.ptr = CLFACTORY_BEGIN_CODE; lf.begin_code_len = CLFACTORY_BEGIN_SIZE; lf.end_code.ptr = CLFACTORY_END_CODE; lf.end_code_len = CLFACTORY_END_SIZE; +#endif lua_pushfstring(L, "@%s", filename); @@ -683,20 +701,27 @@ ngx_http_lua_clfactory_loadfile(lua_State *L, const char *filename) /* skip eventual `#!...' */ } +#ifndef OPENRESTY_LUAJIT status = ngx_http_lua_clfactory_bytecode_prepare(L, &lf, fname_index); if (status != 0) { return status; } +#endif lf.extraline = 0; } +#ifndef OPENRESTY_LUAJIT if (lf.file_type == NGX_LUA_TEXT_FILE) { ungetc(c, lf.f); } lf.sent_begin = lf.sent_end = 0; + +#else + ungetc(c, lf.f); +#endif status = lua_load(L, ngx_http_lua_clfactory_getF, &lf, lua_tostring(L, -1)); @@ -725,8 +750,10 @@ ngx_http_lua_clfactory_loadbuffer(lua_State *L, const char *buff, ls.s = buff; ls.size = size; +#ifndef OPENRESTY_LUAJIT ls.sent_begin = 0; ls.sent_end = 0; +#endif return lua_load(L, ngx_http_lua_clfactory_getS, &ls, name); } @@ -735,7 +762,9 @@ ngx_http_lua_clfactory_loadbuffer(lua_State *L, const char *buff, static const char * ngx_http_lua_clfactory_getF(lua_State *L, void *ud, size_t *size) { +#ifndef OPENRESTY_LUAJIT char *buf; +#endif size_t num; ngx_http_lua_clfactory_file_ctx_t *lf; @@ -748,6 +777,7 @@ ngx_http_lua_clfactory_getF(lua_State *L, void *ud, size_t *size) return "\n"; } +#ifndef OPENRESTY_LUAJIT if (lf->sent_begin == 0) { lf->sent_begin = 1; *size = lf->begin_code_len; @@ -761,12 +791,14 @@ ngx_http_lua_clfactory_getF(lua_State *L, void *ud, size_t *size) return buf; } +#endif /* OPENRESTY_LUAJIT */ num = fread(lf->buff, 1, sizeof(lf->buff), lf->f); dd("fread returned %d", (int) num); if (num == 0) { +#ifndef OPENRESTY_LUAJIT if (lf->sent_end == 0) { lf->sent_end = 1; *size = lf->end_code_len; @@ -780,11 +812,13 @@ ngx_http_lua_clfactory_getF(lua_State *L, void *ud, size_t *size) return buf; } +#endif /* OPENRESTY_LUAJIT */ *size = 0; return NULL; } +#ifndef OPENRESTY_LUAJIT if (lf->file_type == NGX_LUA_BT_LJ) { /* skip the footer(\x00) in luajit */ @@ -800,6 +834,7 @@ ngx_http_lua_clfactory_getF(lua_State *L, void *ud, size_t *size) } } } +#endif /* OPENRESTY_LUAJIT */ *size = num; return lf->buff; @@ -833,19 +868,23 @@ ngx_http_lua_clfactory_getS(lua_State *L, void *ud, size_t *size) { ngx_http_lua_clfactory_buffer_ctx_t *ls = ud; +#ifndef OPENRESTY_LUAJIT if (ls->sent_begin == 0) { ls->sent_begin = 1; *size = CLFACTORY_BEGIN_SIZE; return CLFACTORY_BEGIN_CODE; } +#endif if (ls->size == 0) { +#ifndef OPENRESTY_LUAJIT if (ls->sent_end == 0) { ls->sent_end = 1; *size = CLFACTORY_END_SIZE; return CLFACTORY_END_CODE; } +#endif return NULL; } @@ -857,6 +896,7 @@ ngx_http_lua_clfactory_getS(lua_State *L, void *ud, size_t *size) } +#ifndef OPENRESTY_LUAJIT static long ngx_http_lua_clfactory_file_size(FILE *f) { @@ -882,6 +922,7 @@ ngx_http_lua_clfactory_file_size(FILE *f) return len; } +#endif /* OPENRESTY_LUAJIT */ /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_common.h b/debian/modules/http-lua/src/ngx_http_lua_common.h index 01ef2be..dae5245 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_common.h +++ b/debian/modules/http-lua/src/ngx_http_lua_common.h @@ -17,7 +17,7 @@ #include #include -#include +#include #include #include @@ -140,6 +140,15 @@ typedef struct { #endif +#if (NGX_PTR_SIZE >= 8 && !defined(_WIN64)) +#define ngx_http_lua_lightudata_mask(ludata) \ + ((void *) ((uintptr_t) (&ngx_http_lua_##ludata) & ((1UL << 47) - 1))) + +#else +#define ngx_http_lua_lightudata_mask(ludata) (&ngx_http_lua_##ludata) +#endif + + typedef struct ngx_http_lua_main_conf_s ngx_http_lua_main_conf_t; typedef union ngx_http_lua_srv_conf_u ngx_http_lua_srv_conf_t; @@ -173,6 +182,8 @@ struct ngx_http_lua_main_conf_s { ngx_cycle_t *cycle; ngx_pool_t *pool; + ngx_flag_t load_resty_core; + ngx_int_t max_pending_timers; ngx_int_t pending_timers; @@ -208,9 +219,31 @@ struct ngx_http_lua_main_conf_s { ngx_str_t init_worker_src; ngx_http_lua_balancer_peer_data_t *balancer_peer_data; - /* 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. + /* 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 + * concurrent requests when storing the chain + * data pointer in the main conf. + */ + + ngx_http_variable_value_t *setby_args; + /* neither yielding nor recursion is possible in + * set_by_lua*, so there cannot be any races among + * concurrent requests when storing the args pointer + * in the main conf. + */ + + size_t setby_nargs; + /* neither yielding nor recursion is possible in + * set_by_lua*, so there cannot be any races among + * concurrent requests when storing the nargs in the + * main conf. */ ngx_uint_t shm_zones_inited; @@ -227,6 +260,10 @@ struct ngx_http_lua_main_conf_s { ngx_int_t busy_buf_ptr_count; #endif + ngx_int_t host_var_index; + + ngx_flag_t set_sa_restart; + unsigned requires_header_filter:1; unsigned requires_body_filter:1; unsigned requires_capture_filter:1; @@ -444,7 +481,7 @@ typedef struct { typedef struct ngx_http_lua_ctx_s { - /* for lua_coce_cache off: */ + /* for lua_code_cache off: */ ngx_http_lua_vm_state_t *vm_state; ngx_http_request_t *request; @@ -531,6 +568,8 @@ typedef struct ngx_http_lua_ctx_s { unsigned headers_set:1; /* whether the user has set custom response headers */ + unsigned mime_set:1; /* whether the user has set Content-Type + response header */ unsigned entered_rewrite_phase:1; unsigned entered_access_phase:1; diff --git a/debian/modules/http-lua/src/ngx_http_lua_contentby.c b/debian/modules/http-lua/src/ngx_http_lua_contentby.c index ecd6c0e..274c9ad 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_contentby.c +++ b/debian/modules/http-lua/src/ngx_http_lua_contentby.c @@ -63,9 +63,11 @@ ngx_http_lua_content_by_chunk(lua_State *L, ngx_http_request_t *r) /* 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); diff --git a/debian/modules/http-lua/src/ngx_http_lua_control.c b/debian/modules/http-lua/src/ngx_http_lua_control.c index 6ac2cbf..5cd1d64 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_control.c +++ b/debian/modules/http-lua/src/ngx_http_lua_control.c @@ -432,7 +432,8 @@ ngx_http_lua_on_abort(lua_State *L) ngx_http_lua_coroutine_create_helper(L, r, ctx, &coctx); - lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + coroutines_key)); lua_rawget(L, LUA_REGISTRYINDEX); lua_pushvalue(L, -2); diff --git a/debian/modules/http-lua/src/ngx_http_lua_coroutine.c b/debian/modules/http-lua/src/ngx_http_lua_coroutine.c index b790814..99a2423 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_coroutine.c +++ b/debian/modules/http-lua/src/ngx_http_lua_coroutine.c @@ -104,11 +104,15 @@ ngx_http_lua_coroutine_create_helper(lua_State *L, ngx_http_request_t *r, coctx->co = co; coctx->co_status = NGX_HTTP_LUA_CO_SUSPENDED; +#ifdef OPENRESTY_LUAJIT + ngx_http_lua_set_req(co, r); +#else /* make new coroutine share globals of the parent coroutine. * NOTE: globals don't have to be separated! */ ngx_http_lua_get_globals_table(L); lua_xmove(L, co, 1); ngx_http_lua_set_globals_table(co); +#endif lua_xmove(vm, L, 1); /* move coroutine from main thread to L */ @@ -288,15 +292,27 @@ ngx_http_lua_inject_coroutine_api(ngx_log_t *log, lua_State *L) { const char buf[] = "local keys = {'create', 'yield', 'resume', 'status'}\n" +#ifdef OPENRESTY_LUAJIT + "local get_req = require 'thread.exdata'\n" +#else "local getfenv = getfenv\n" +#endif "for _, key in ipairs(keys) do\n" "local std = coroutine['_' .. key]\n" "local ours = coroutine['__' .. key]\n" "local raw_ctx = ngx._phase_ctx\n" "coroutine[key] = function (...)\n" +#ifdef OPENRESTY_LUAJIT + "local r = get_req()\n" +#else "local r = getfenv(0).__ngx_req\n" - "if r then\n" +#endif + "if r ~= nil then\n" +#ifdef OPENRESTY_LUAJIT + "local ctx = raw_ctx()\n" +#else "local ctx = raw_ctx(r)\n" +#endif /* ignore header and body filters */ "if ctx ~= 0x020 and ctx ~= 0x040 then\n" "return ours(...)\n" diff --git a/debian/modules/http-lua/src/ngx_http_lua_directive.c b/debian/modules/http-lua/src/ngx_http_lua_directive.c index fb8c6dc..a989c26 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_directive.c +++ b/debian/modules/http-lua/src/ngx_http_lua_directive.c @@ -1304,11 +1304,12 @@ ngx_http_lua_gen_chunk_name(ngx_conf_t *cf, const char *tag, size_t tag_len, found: - ngx_snprintf(out, len, "=%*s(%*s:%d)%Z", - tag_len, tag, cf->conf_file->file.name.data - + cf->conf_file->file.name.len - p, - p, cf->conf_file->line); - *chunkname_len = len; + p = ngx_snprintf(out, len, "=%*s(%*s:%d)%Z", + tag_len, tag, cf->conf_file->file.name.data + + cf->conf_file->file.name.len - p, + p, cf->conf_file->line); + + *chunkname_len = p - out - 1; /* exclude the trailing '\0' byte */ return out; } diff --git a/debian/modules/http-lua/src/ngx_http_lua_headerfilterby.c b/debian/modules/http-lua/src/ngx_http_lua_headerfilterby.c index b504530..a0acd4a 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_headerfilterby.c +++ b/debian/modules/http-lua/src/ngx_http_lua_headerfilterby.c @@ -42,9 +42,9 @@ static ngx_http_output_header_filter_pt ngx_http_next_header_filter; static void ngx_http_lua_header_filter_by_lua_env(lua_State *L, ngx_http_request_t *r) { - /* set nginx request pointer to current lua thread's globals table */ ngx_http_lua_set_req(L, r); +#ifndef OPENRESTY_LUAJIT /** * we want to create empty environment for current script * @@ -68,6 +68,7 @@ ngx_http_lua_header_filter_by_lua_env(lua_State *L, ngx_http_request_t *r) /* }}} */ lua_setfenv(L, -2); /* set new running env for the code closure */ +#endif /* OPENRESTY_LUAJIT */ } diff --git a/debian/modules/http-lua/src/ngx_http_lua_headers.c b/debian/modules/http-lua/src/ngx_http_lua_headers.c index b833577..e3f48bc 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_headers.c +++ b/debian/modules/http-lua/src/ngx_http_lua_headers.c @@ -442,7 +442,8 @@ ngx_http_lua_ngx_req_get_headers(lua_State *L) lua_createtable(L, 0, count); if (!raw) { - lua_pushlightuserdata(L, &ngx_http_lua_headers_metatable_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + headers_metatable_key)); lua_rawget(L, LUA_REGISTRYINDEX); lua_setmetatable(L, -2); } @@ -504,7 +505,6 @@ ngx_http_lua_ngx_resp_get_headers(lua_State *L) ngx_table_elt_t *header; ngx_http_request_t *r; ngx_http_lua_ctx_t *ctx; - ngx_int_t rc; u_char *lowcase_key = NULL; size_t lowcase_key_sz = 0; ngx_uint_t i; @@ -543,17 +543,6 @@ ngx_http_lua_ngx_resp_get_headers(lua_State *L) return luaL_error(L, "no ctx found"); } - if (!ctx->headers_set) { - rc = ngx_http_lua_set_content_type(r); - if (rc != NGX_OK) { - return luaL_error(L, - "failed to set default content type: %d", - (int) rc); - } - - ctx->headers_set = 1; - } - ngx_http_lua_check_fake_request(L, r); part = &r->headers_out.headers.part; @@ -566,7 +555,8 @@ ngx_http_lua_ngx_resp_get_headers(lua_State *L) lua_createtable(L, 0, count + 2); if (!raw) { - lua_pushlightuserdata(L, &ngx_http_lua_headers_metatable_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + headers_metatable_key)); lua_rawget(L, LUA_REGISTRYINDEX); lua_setmetatable(L, -2); } @@ -694,7 +684,6 @@ ngx_http_lua_ngx_header_get(lua_State *L) size_t len; ngx_http_lua_loc_conf_t *llcf; ngx_http_lua_ctx_t *ctx; - ngx_int_t rc; r = ngx_http_lua_get_req(L); if (r == NULL) { @@ -737,18 +726,7 @@ ngx_http_lua_ngx_header_get(lua_State *L) key.len = len; - if (!ctx->headers_set) { - rc = ngx_http_lua_set_content_type(r); - if (rc != NGX_OK) { - return luaL_error(L, - "failed to set default content type: %d", - (int) rc); - } - - ctx->headers_set = 1; - } - - return ngx_http_lua_get_output_header(L, r, &key); + return ngx_http_lua_get_output_header(L, r, ctx, &key); } @@ -811,16 +789,7 @@ ngx_http_lua_ngx_header_set(lua_State *L) } } - if (!ctx->headers_set) { - rc = ngx_http_lua_set_content_type(r); - if (rc != NGX_OK) { - return luaL_error(L, - "failed to set default content type: %d", - (int) rc); - } - - ctx->headers_set = 1; - } + ctx->headers_set = 1; if (lua_type(L, 3) == LUA_TNIL) { ngx_str_null(&value); @@ -845,7 +814,7 @@ ngx_http_lua_ngx_header_set(lua_State *L) ngx_memcpy(value.data, p, len); value.len = len; - rc = ngx_http_lua_set_output_header(r, key, value, + rc = ngx_http_lua_set_output_header(r, ctx, key, value, i == 1 /* override */); if (rc == NGX_ERROR) { @@ -872,7 +841,7 @@ ngx_http_lua_ngx_header_set(lua_State *L) dd("key: %.*s, value: %.*s", (int) key.len, key.data, (int) value.len, value.data); - rc = ngx_http_lua_set_output_header(r, key, value, 1 /* override */); + rc = ngx_http_lua_set_output_header(r, ctx, key, value, 1 /* override */); if (rc == NGX_ERROR) { return luaL_error(L, "failed to set header %s (error: %d)", @@ -1081,7 +1050,8 @@ ngx_http_lua_create_headers_metatable(ngx_log_t *log, lua_State *L) "local new_key = string.gsub(string.lower(key), '_', '-')\n" "if new_key ~= key then return tb[new_key] else return nil end"; - lua_pushlightuserdata(L, &ngx_http_lua_headers_metatable_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + headers_metatable_key)); /* metatable for ngx.req.get_headers(_, true) and * ngx.resp.get_headers(_, true) */ @@ -1241,15 +1211,7 @@ ngx_http_lua_ffi_set_resp_header(ngx_http_request_t *r, const u_char *key_data, } } - if (!ctx->headers_set) { - rc = ngx_http_lua_set_content_type(r); - if (rc != NGX_OK) { - *errmsg = "failed to set default content type"; - return NGX_ERROR; - } - - ctx->headers_set = 1; - } + ctx->headers_set = 1; if (is_nil) { value.data = NULL; @@ -1276,7 +1238,7 @@ ngx_http_lua_ffi_set_resp_header(ngx_http_request_t *r, const u_char *key_data, ngx_memcpy(value.data, p, len); value.len = len; - rc = ngx_http_lua_set_output_header(r, key, value, + rc = ngx_http_lua_set_output_header(r, ctx, key, value, override && i == 0); if (rc == NGX_ERROR) { @@ -1302,7 +1264,7 @@ ngx_http_lua_ffi_set_resp_header(ngx_http_request_t *r, const u_char *key_data, dd("key: %.*s, value: %.*s", (int) key.len, key.data, (int) value.len, value.data); - rc = ngx_http_lua_set_output_header(r, key, value, override); + rc = ngx_http_lua_set_output_header(r, ctx, key, value, override); if (rc == NGX_ERROR) { *errmsg = "failed to set header"; @@ -1370,7 +1332,8 @@ ngx_http_lua_ffi_req_header_set_single_value(ngx_http_request_t *r, int ngx_http_lua_ffi_get_resp_header(ngx_http_request_t *r, const u_char *key, size_t key_len, - u_char *key_buf, ngx_http_lua_ffi_str_t *values, int max_nvalues) + u_char *key_buf, ngx_http_lua_ffi_str_t *values, int max_nvalues, + char **errmsg) { int found; u_char c, *p; @@ -1387,19 +1350,10 @@ ngx_http_lua_ffi_get_resp_header(ngx_http_request_t *r, ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { - /* *errmsg = "no ctx found"; */ + *errmsg = "no ctx found"; return NGX_ERROR; } - if (!ctx->headers_set) { - if (ngx_http_lua_set_content_type(r) != NGX_OK) { - /* *errmsg = "failed to set default content type"; */ - return NGX_ERROR; - } - - ctx->headers_set = 1; - } - llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); if (llcf->transform_underscores_in_resp_headers && memchr(key, '_', key_len) != NULL) @@ -1425,6 +1379,7 @@ ngx_http_lua_ffi_get_resp_header(ngx_http_request_t *r, { p = ngx_palloc(r->pool, NGX_OFF_T_LEN); if (p == NULL) { + *errmsg = "no memory"; return NGX_ERROR; } @@ -1438,8 +1393,8 @@ ngx_http_lua_ffi_get_resp_header(ngx_http_request_t *r, break; case 12: - if (r->headers_out.content_type.len - && ngx_strncasecmp(key_buf, (u_char *) "Content-Type", 12) == 0) + if (ngx_strncasecmp(key_buf, (u_char *) "Content-Type", 12) == 0 + && r->headers_out.content_type.len) { values[0].data = r->headers_out.content_type.data; values[0].len = r->headers_out.content_type.len; diff --git a/debian/modules/http-lua/src/ngx_http_lua_headers_in.c b/debian/modules/http-lua/src/ngx_http_lua_headers_in.c index 4852b2f..c52cd13 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_headers_in.c +++ b/debian/modules/http-lua/src/ngx_http_lua_headers_in.c @@ -432,10 +432,14 @@ static ngx_int_t ngx_http_set_host_header(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, ngx_str_t *value) { - ngx_str_t host; + ngx_str_t host; + ngx_http_lua_main_conf_t *lmcf; + ngx_http_variable_value_t *var; dd("server new value len: %d", (int) value->len); + lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); + if (value->len) { host= *value; @@ -449,6 +453,10 @@ ngx_http_set_host_header(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, r->headers_in.server = *value; } + var = &r->variables[lmcf->host_var_index]; + var->valid = 0; + var->not_found = 0; + return ngx_http_set_builtin_header(r, hv, value); } diff --git a/debian/modules/http-lua/src/ngx_http_lua_headers_out.c b/debian/modules/http-lua/src/ngx_http_lua_headers_out.c index b908eae..cf94bd0 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_headers_out.c +++ b/debian/modules/http-lua/src/ngx_http_lua_headers_out.c @@ -106,6 +106,12 @@ static ngx_http_lua_set_header_t ngx_http_lua_set_handlers[] = { offsetof(ngx_http_headers_out_t, cache_control), ngx_http_set_builtin_multi_header }, +#if defined(nginx_version) && nginx_version >= 1013009 + { ngx_string("Link"), + offsetof(ngx_http_headers_out_t, link), + ngx_http_set_builtin_multi_header }, +#endif + { ngx_null_string, 0, ngx_http_set_header } }; @@ -476,8 +482,8 @@ ngx_http_clear_builtin_header(ngx_http_request_t *r, ngx_int_t -ngx_http_lua_set_output_header(ngx_http_request_t *r, ngx_str_t key, - ngx_str_t value, unsigned override) +ngx_http_lua_set_output_header(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx, + ngx_str_t key, ngx_str_t value, unsigned override) { ngx_http_lua_header_val_t hv; ngx_http_lua_set_header_t *handlers = ngx_http_lua_set_handlers; @@ -508,6 +514,10 @@ ngx_http_lua_set_output_header(ngx_http_request_t *r, ngx_str_t key, hv.offset = handlers[i].offset; hv.handler = handlers[i].handler; + if (hv.handler == ngx_http_set_content_type_header) { + ctx->mime_set = 1; + } + break; } @@ -528,7 +538,7 @@ ngx_http_lua_set_output_header(ngx_http_request_t *r, ngx_str_t key, int ngx_http_lua_get_output_header(lua_State *L, ngx_http_request_t *r, - ngx_str_t *key) + ngx_http_lua_ctx_t *ctx, ngx_str_t *key) { ngx_table_elt_t *h; ngx_list_part_t *part; @@ -550,8 +560,8 @@ ngx_http_lua_get_output_header(lua_State *L, ngx_http_request_t *r, break; case 12: - if (r->headers_out.content_type.len - && ngx_strncasecmp(key->data, (u_char *) "Content-Type", 12) == 0) + if (ngx_strncasecmp(key->data, (u_char *) "Content-Type", 12) == 0 + && r->headers_out.content_type.len) { lua_pushlstring(L, (char *) r->headers_out.content_type.data, r->headers_out.content_type.len); diff --git a/debian/modules/http-lua/src/ngx_http_lua_headers_out.h b/debian/modules/http-lua/src/ngx_http_lua_headers_out.h index ef5e6d4..6ec1fe3 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_headers_out.h +++ b/debian/modules/http-lua/src/ngx_http_lua_headers_out.h @@ -12,10 +12,10 @@ #include "ngx_http_lua_common.h" -ngx_int_t ngx_http_lua_set_output_header(ngx_http_request_t *r, ngx_str_t key, - ngx_str_t value, unsigned override); +ngx_int_t ngx_http_lua_set_output_header(ngx_http_request_t *r, + ngx_http_lua_ctx_t *ctx, ngx_str_t key, ngx_str_t value, unsigned override); int ngx_http_lua_get_output_header(lua_State *L, ngx_http_request_t *r, - ngx_str_t *key); + ngx_http_lua_ctx_t *ctx, ngx_str_t *key); #endif /* _NGX_HTTP_LUA_HEADERS_OUT_H_INCLUDED_ */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_initworkerby.c b/debian/modules/http-lua/src/ngx_http_lua_initworkerby.c index 4a722a0..76acdc3 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_initworkerby.c +++ b/debian/modules/http-lua/src/ngx_http_lua_initworkerby.c @@ -12,6 +12,7 @@ #include "ngx_http_lua_initworkerby.h" #include "ngx_http_lua_util.h" +#include "ngx_http_lua_pipe.h" static u_char *ngx_http_lua_log_init_worker_error(ngx_log_t *log, @@ -25,6 +26,7 @@ ngx_http_lua_init_worker(ngx_cycle_t *cycle) void *cur, *prev; ngx_uint_t i; ngx_conf_t conf; + ngx_conf_file_t cf_file; ngx_cycle_t *fake_cycle; ngx_module_t **modules; ngx_open_file_t *file, *ofile; @@ -64,8 +66,21 @@ ngx_http_lua_init_worker(ngx_cycle_t *cycle) return NGX_OK; } + +#ifdef HAVE_NGX_LUA_PIPE + if (ngx_http_lua_pipe_add_signal_handler(cycle) != NGX_OK) { + return NGX_ERROR; + } +#endif + #endif /* NGX_WIN32 */ +#if (NGX_HTTP_LUA_HAVE_SA_RESTART) + if (lmcf->set_sa_restart) { + ngx_http_lua_set_sa_restart(ngx_cycle->log); + } +#endif + if (lmcf->init_worker_handler == NULL) { return NGX_OK; } @@ -166,6 +181,10 @@ ngx_http_lua_init_worker(ngx_cycle_t *cycle) conf.pool = fake_cycle->pool; conf.log = cycle->log; + ngx_memzero(&cf_file, sizeof(cf_file)); + cf_file.file.name = cycle->conf_file; + conf.conf_file = &cf_file; + http_ctx.loc_conf = ngx_pcalloc(conf.pool, sizeof(void *) * ngx_http_max_module); if (http_ctx.loc_conf == NULL) { diff --git a/debian/modules/http-lua/src/ngx_http_lua_input_filters.c b/debian/modules/http-lua/src/ngx_http_lua_input_filters.c new file mode 100644 index 0000000..87a9d8c --- /dev/null +++ b/debian/modules/http-lua/src/ngx_http_lua_input_filters.c @@ -0,0 +1,137 @@ + +/* + * Copyright (C) by OpenResty Inc. + */ + + +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + + +#include "ngx_http_lua_common.h" + + +ngx_int_t +ngx_http_lua_read_bytes(ngx_buf_t *src, ngx_chain_t *buf_in, size_t *rest, + ssize_t bytes, ngx_log_t *log) +{ + if (bytes == 0) { + return NGX_ERROR; + } + + if ((size_t) bytes >= *rest) { + + buf_in->buf->last += *rest; + src->pos += *rest; + *rest = 0; + + return NGX_OK; + } + + /* bytes < *rest */ + + buf_in->buf->last += bytes; + src->pos += bytes; + *rest -= bytes; + + return NGX_AGAIN; +} + + +ngx_int_t +ngx_http_lua_read_all(ngx_buf_t *src, ngx_chain_t *buf_in, ssize_t bytes, + ngx_log_t *log) +{ + if (bytes == 0) { + return NGX_OK; + } + + buf_in->buf->last += bytes; + src->pos += bytes; + + return NGX_AGAIN; +} + + +ngx_int_t +ngx_http_lua_read_any(ngx_buf_t *src, ngx_chain_t *buf_in, size_t *max, + ssize_t bytes, ngx_log_t *log) +{ + if (bytes == 0) { + return NGX_ERROR; + } + + if (bytes >= (ssize_t) *max) { + bytes = (ssize_t) *max; + } + + buf_in->buf->last += bytes; + src->pos += bytes; + + return NGX_OK; +} + + +ngx_int_t +ngx_http_lua_read_line(ngx_buf_t *src, ngx_chain_t *buf_in, ssize_t bytes, + ngx_log_t *log) +{ + u_char *dst; + u_char c; +#if (NGX_DEBUG) + u_char *begin; +#endif + +#if (NGX_DEBUG) + begin = src->pos; +#endif + + if (bytes == 0) { + return NGX_ERROR; + } + + dd("already read: %p: %.*s", buf_in, + (int) (buf_in->buf->last - buf_in->buf->pos), buf_in->buf->pos); + + dd("data read: %.*s", (int) bytes, src->pos); + + dst = buf_in->buf->last; + + while (bytes--) { + + c = *src->pos++; + + switch (c) { + case '\n': + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, log, 0, + "lua read the final line part: \"%*s\"", + src->pos - 1 - begin, begin); + + buf_in->buf->last = dst; + + dd("read a line: %p: %.*s", buf_in, + (int) (buf_in->buf->last - buf_in->buf->pos), buf_in->buf->pos); + + return NGX_OK; + + case '\r': + /* ignore it */ + break; + + default: + *dst++ = c; + break; + } + } + +#if (NGX_DEBUG) + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, log, 0, + "lua read partial line data: %*s", dst - begin, begin); +#endif + + buf_in->buf->last = dst; + + return NGX_AGAIN; +} diff --git a/debian/modules/http-lua/src/ngx_http_lua_input_filters.h b/debian/modules/http-lua/src/ngx_http_lua_input_filters.h new file mode 100644 index 0000000..046d40f --- /dev/null +++ b/debian/modules/http-lua/src/ngx_http_lua_input_filters.h @@ -0,0 +1,29 @@ + +/* + * Copyright (C) by OpenResty Inc. + */ + + +#ifndef _NGX_HTTP_LUA_INPUT_FILTERS_H_INCLUDED_ +#define _NGX_HTTP_LUA_INPUT_FILTERS_H_INCLUDED_ + + +#include "ngx_http_lua_common.h" + + +ngx_int_t ngx_http_lua_read_bytes(ngx_buf_t *src, ngx_chain_t *buf_in, + size_t *rest, ssize_t bytes, ngx_log_t *log); + +ngx_int_t ngx_http_lua_read_all(ngx_buf_t *src, ngx_chain_t *buf_in, + ssize_t bytes, ngx_log_t *log); + +ngx_int_t ngx_http_lua_read_any(ngx_buf_t *src, ngx_chain_t *buf_in, + size_t *max, ssize_t bytes, ngx_log_t *log); + +ngx_int_t ngx_http_lua_read_line(ngx_buf_t *src, ngx_chain_t *buf_in, + ssize_t bytes, ngx_log_t *log); + + +#endif /* _NGX_HTTP_LUA_INPUT_FILTERS_H_INCLUDED_ */ + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_logby.c b/debian/modules/http-lua/src/ngx_http_lua_logby.c index 0f1d2f3..32d1cba 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_logby.c +++ b/debian/modules/http-lua/src/ngx_http_lua_logby.c @@ -38,9 +38,9 @@ static ngx_int_t ngx_http_lua_log_by_chunk(lua_State *L, ngx_http_request_t *r); static void ngx_http_lua_log_by_lua_env(lua_State *L, ngx_http_request_t *r) { - /* set nginx request pointer to current lua thread's globals table */ ngx_http_lua_set_req(L, r); +#ifndef OPENRESTY_LUAJIT /** * we want to create empty environment for current script * @@ -64,6 +64,7 @@ ngx_http_lua_log_by_lua_env(lua_State *L, ngx_http_request_t *r) /* }}} */ lua_setfenv(L, -2); /* set new running env for the code closure */ +#endif /* OPENRESTY_LUAJIT */ } diff --git a/debian/modules/http-lua/src/ngx_http_lua_misc.c b/debian/modules/http-lua/src/ngx_http_lua_misc.c index f96e2f2..145ca9b 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_misc.c +++ b/debian/modules/http-lua/src/ngx_http_lua_misc.c @@ -286,6 +286,33 @@ ngx_http_lua_ffi_headers_sent(ngx_http_request_t *r) return r->header_sent ? 1 : 0; } + + +int +ngx_http_lua_ffi_get_conf_env(u_char *name, u_char **env_buf, size_t *name_len) +{ + ngx_uint_t i; + ngx_str_t *var; + ngx_core_conf_t *ccf; + + ccf = (ngx_core_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx, + ngx_core_module); + + var = ccf->env.elts; + + for (i = 0; i < ccf->env.nelts; i++) { + if (var[i].data[var[i].len] == '=' + && ngx_strncmp(name, var[i].data, var[i].len) == 0) + { + *env_buf = var[i].data; + *name_len = var[i].len; + + return NGX_OK; + } + } + + return NGX_DECLINED; +} #endif /* NGX_LUA_NO_FFI_API */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_module.c b/debian/modules/http-lua/src/ngx_http_lua_module.c index ae8bc0e..2a3f5d5 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_module.c +++ b/debian/modules/http-lua/src/ngx_http_lua_module.c @@ -29,6 +29,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_pipe.h" static void *ngx_http_lua_create_main_conf(ngx_conf_t *cf); @@ -76,6 +77,13 @@ static ngx_conf_bitmask_t ngx_http_lua_ssl_protocols[] = { static ngx_command_t ngx_http_lua_cmds[] = { + { ngx_string("lua_load_resty_core"), + NGX_HTTP_MAIN_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_MAIN_CONF_OFFSET, + offsetof(ngx_http_lua_main_conf_t, load_resty_core), + NULL }, + { ngx_string("lua_max_running_timers"), NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1, ngx_conf_set_num_slot, @@ -104,6 +112,13 @@ static ngx_command_t ngx_http_lua_cmds[] = { 0, NULL }, + { ngx_string("lua_sa_restart"), + NGX_HTTP_MAIN_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_MAIN_CONF_OFFSET, + offsetof(ngx_http_lua_main_conf_t, set_sa_restart), + NULL }, + #if (NGX_PCRE) { ngx_string("lua_regex_cache_max_entries"), NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1, @@ -638,9 +653,19 @@ ngx_http_lua_init(ngx_conf_t *cf) #if !defined(NGX_LUA_NO_FFI_API) || nginx_version >= 1011011 ngx_pool_cleanup_t *cln; #endif + ngx_str_t name = ngx_string("host"); + + if (ngx_process == NGX_PROCESS_SIGNALLER || ngx_test_config) { + return NGX_OK; + } lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_lua_module); + lmcf->host_var_index = ngx_http_get_variable_index(cf, &name); + if (lmcf->host_var_index == NGX_ERROR) { + return NGX_ERROR; + } + if (ngx_http_lua_prev_cycle != ngx_cycle) { ngx_http_lua_prev_cycle = ngx_cycle; multi_http_blocks = 0; @@ -725,6 +750,11 @@ ngx_http_lua_init(ngx_conf_t *cf) cln->data = lmcf; cln->handler = ngx_http_lua_sema_mm_cleanup; + +#ifdef HAVE_NGX_LUA_PIPE + ngx_http_lua_pipe_init(); +#endif + #endif #if nginx_version >= 1011011 @@ -740,6 +770,19 @@ ngx_http_lua_init(ngx_conf_t *cf) if (lmcf->lua == NULL) { dd("initializing lua vm"); +#ifndef OPENRESTY_LUAJIT + if (ngx_process != NGX_PROCESS_SIGNALLER && !ngx_test_config) { + ngx_log_error(NGX_LOG_ALERT, cf->log, 0, + "detected a LuaJIT version which is not OpenResty's" + "; many optimizations will be disabled and " + "performance will be compromised (see " + "https://github.com/openresty/luajit2 for " + "OpenResty's LuaJIT or, even better, consider using " + "the OpenResty releases from https://openresty.org/" + "en/download.html)"); + } +#endif + ngx_http_lua_content_length_hash = ngx_http_lua_hash_literal("content-length"); ngx_http_lua_location_hash = ngx_http_lua_hash_literal("location"); @@ -841,6 +884,7 @@ ngx_http_lua_create_main_conf(ngx_conf_t *cf) */ lmcf->pool = cf->pool; + lmcf->load_resty_core = NGX_CONF_UNSET; lmcf->max_pending_timers = NGX_CONF_UNSET; lmcf->max_running_timers = NGX_CONF_UNSET; #if (NGX_PCRE) @@ -850,6 +894,8 @@ ngx_http_lua_create_main_conf(ngx_conf_t *cf) lmcf->postponed_to_rewrite_phase_end = NGX_CONF_UNSET; lmcf->postponed_to_access_phase_end = NGX_CONF_UNSET; + lmcf->set_sa_restart = NGX_CONF_UNSET; + #if (NGX_HTTP_LUA_HAVE_MALLOC_TRIM) lmcf->malloc_trim_cycle = NGX_CONF_UNSET_UINT; #endif @@ -872,6 +918,10 @@ ngx_http_lua_init_main_conf(ngx_conf_t *cf, void *conf) { ngx_http_lua_main_conf_t *lmcf = conf; + if (lmcf->load_resty_core == NGX_CONF_UNSET) { + lmcf->load_resty_core = 1; + } + #if (NGX_PCRE) if (lmcf->regex_cache_max_entries == NGX_CONF_UNSET) { lmcf->regex_cache_max_entries = 1024; @@ -890,6 +940,12 @@ ngx_http_lua_init_main_conf(ngx_conf_t *cf, void *conf) lmcf->max_running_timers = 256; } +#if (NGX_HTTP_LUA_HAVE_SA_RESTART) + if (lmcf->set_sa_restart == NGX_CONF_UNSET) { + lmcf->set_sa_restart = 1; + } +#endif + #if (NGX_HTTP_LUA_HAVE_MALLOC_TRIM) if (lmcf->malloc_trim_cycle == NGX_CONF_UNSET_UINT) { lmcf->malloc_trim_cycle = 1000; /* number of reqs */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_ndk.c b/debian/modules/http-lua/src/ngx_http_lua_ndk.c index 24b80b4..6344183 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_ndk.c +++ b/debian/modules/http-lua/src/ngx_http_lua_ndk.c @@ -186,6 +186,47 @@ ngx_http_lua_inject_ndk_api(lua_State *L) } +int +ngx_http_lua_ffi_ndk_lookup_directive(const u_char *var_data, + size_t var_len, ndk_set_var_value_pt *func) +{ + *func = ngx_http_lookup_ndk_set_var_directive((u_char *) var_data, var_len); + + if (*func == NULL) { + return NGX_ERROR; + } + + return NGX_OK; +} + + +int +ngx_http_lua_ffi_ndk_set_var_get(ngx_http_request_t *r, + ndk_set_var_value_pt func, const u_char *arg_data, size_t arg_len, + ngx_http_lua_ffi_str_t *value) +{ + ngx_int_t rc; + ngx_str_t res; + ngx_http_variable_value_t arg; + + ngx_memzero(&arg, sizeof(ngx_http_variable_value_t)); + arg.valid = 1; + + arg.data = (u_char *) arg_data; + arg.len = arg_len; + + rc = func(r, &res, &arg); + + if (rc != NGX_OK) { + return rc; + } + + value->data = res.data; + value->len = res.len; + return NGX_OK; +} + + #endif /* defined(NDK) && NDK */ /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_pipe.c b/debian/modules/http-lua/src/ngx_http_lua_pipe.c new file mode 100644 index 0000000..8c8221f --- /dev/null +++ b/debian/modules/http-lua/src/ngx_http_lua_pipe.c @@ -0,0 +1,2475 @@ + +/* + * Copyright (C) by OpenResty Inc. + */ + + +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + + +#include "ngx_http_lua_common.h" +#include "ngx_http_lua_input_filters.h" +#include "ngx_http_lua_util.h" +#include "ngx_http_lua_pipe.h" +#if (NGX_HTTP_LUA_HAVE_SIGNALFD) +#include +#endif + + +#ifdef HAVE_NGX_LUA_PIPE +static ngx_rbtree_node_t *ngx_http_lua_pipe_lookup_pid(ngx_rbtree_key_t key); +#if !(NGX_HTTP_LUA_HAVE_SIGNALFD) +static void ngx_http_lua_pipe_sigchld_handler(int signo, siginfo_t *siginfo, + void *ucontext); +#endif +static void ngx_http_lua_pipe_sigchld_event_handler(ngx_event_t *ev); +static ssize_t ngx_http_lua_pipe_fd_read(ngx_connection_t *c, u_char *buf, + size_t size); +static ssize_t ngx_http_lua_pipe_fd_write(ngx_connection_t *c, u_char *buf, + size_t size); +static ngx_int_t ngx_http_lua_pipe_close_helper( + ngx_http_lua_pipe_ctx_t *pipe_ctx, ngx_event_t *ev, int forced); +static ngx_int_t ngx_http_lua_pipe_close_stdin(ngx_http_lua_pipe_t *pipe, + int forced); +static ngx_int_t ngx_http_lua_pipe_close_stdout(ngx_http_lua_pipe_t *pipe, + int forced); +static ngx_int_t ngx_http_lua_pipe_close_stderr(ngx_http_lua_pipe_t *pipe, + int forced); +static void ngx_http_lua_pipe_proc_finalize(ngx_http_lua_ffi_pipe_proc_t *proc, + int forced); +static ngx_int_t ngx_http_lua_pipe_get_lua_ctx(ngx_http_request_t *r, + ngx_http_lua_ctx_t **ctx, u_char *errbuf, size_t *errbuf_size); +static void ngx_http_lua_pipe_put_error(ngx_http_lua_pipe_ctx_t *pipe_ctx, + u_char *errbuf, size_t *errbuf_size); +static void ngx_http_lua_pipe_put_data(ngx_http_lua_pipe_t *pipe, + ngx_http_lua_pipe_ctx_t *pipe_ctx, u_char **buf, size_t *buf_size); +static ngx_int_t ngx_http_lua_pipe_add_input_buffer(ngx_http_lua_pipe_t *pipe, + ngx_http_lua_pipe_ctx_t *pipe_ctx); +static ngx_int_t ngx_http_lua_pipe_read_all(void *data, ssize_t bytes); +static ngx_int_t ngx_http_lua_pipe_read_bytes(void *data, ssize_t bytes); +static ngx_int_t ngx_http_lua_pipe_read_line(void *data, ssize_t bytes); +static ngx_int_t ngx_http_lua_pipe_read_any(void *data, ssize_t bytes); +static ngx_int_t ngx_http_lua_pipe_read(ngx_http_lua_pipe_t *pipe, + ngx_http_lua_pipe_ctx_t *pipe_ctx); +static ngx_int_t ngx_http_lua_pipe_init_ctx( + ngx_http_lua_pipe_ctx_t **pipe_ctx_pt, int fd, ngx_pool_t *pool, + u_char *errbuf, size_t *errbuf_size); +static ngx_int_t ngx_http_lua_pipe_write(ngx_http_lua_pipe_t *pipe, + ngx_http_lua_pipe_ctx_t *pipe_ctx); +static int ngx_http_lua_pipe_read_stdout_retval( + ngx_http_lua_ffi_pipe_proc_t *proc, lua_State *L); +static int ngx_http_lua_pipe_read_stderr_retval( + ngx_http_lua_ffi_pipe_proc_t *proc, lua_State *L); +static int ngx_http_lua_pipe_read_retval_helper( + ngx_http_lua_ffi_pipe_proc_t *proc, lua_State *L, int from_stderr); +static int ngx_http_lua_pipe_write_retval(ngx_http_lua_ffi_pipe_proc_t *proc, + lua_State *L); +static int ngx_http_lua_pipe_wait_retval(ngx_http_lua_ffi_pipe_proc_t *proc, + lua_State *L); +static void ngx_http_lua_pipe_resume_helper(ngx_event_t *ev, + ngx_http_lua_co_ctx_t *wait_co_ctx); +static void ngx_http_lua_pipe_resume_read_stdout_handler(ngx_event_t *ev); +static void ngx_http_lua_pipe_resume_read_stderr_handler(ngx_event_t *ev); +static void ngx_http_lua_pipe_resume_write_handler(ngx_event_t *ev); +static void ngx_http_lua_pipe_resume_wait_handler(ngx_event_t *ev); +static ngx_int_t ngx_http_lua_pipe_resume(ngx_http_request_t *r); +static void ngx_http_lua_pipe_dummy_event_handler(ngx_event_t *ev); +static void ngx_http_lua_pipe_clear_event(ngx_event_t *ev); +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 ngx_rbtree_t ngx_http_lua_pipe_rbtree; +static ngx_rbtree_node_t ngx_http_lua_pipe_proc_sentinel; + + +#if (NGX_HTTP_LUA_HAVE_SIGNALFD) +static int ngx_http_lua_signalfd; +static struct signalfd_siginfo ngx_http_lua_pipe_notification; + +#define ngx_http_lua_read_sigfd ngx_http_lua_signalfd + +#else +static int ngx_http_lua_sigchldfd[2]; +static u_char ngx_http_lua_pipe_notification[1]; + +#define ngx_http_lua_read_sigfd ngx_http_lua_sigchldfd[0] +#define ngx_http_lua_write_sigfd ngx_http_lua_sigchldfd[1] +#endif + + +static ngx_connection_t *ngx_http_lua_sigfd_conn = NULL; + + +/* The below signals are ignored by Nginx. + * We need to reset them for the spawned child processes. */ +ngx_http_lua_pipe_signal_t ngx_signals[] = { + { SIGSYS, "SIGSYS" }, + { SIGPIPE, "SIGPIPE" }, + { 0, NULL } +}; + + +enum { + PIPE_ERR_CLOSED = 1, + PIPE_ERR_SYSCALL, + PIPE_ERR_NOMEM, + PIPE_ERR_TIMEOUT, + PIPE_ERR_ADD_READ_EV, + PIPE_ERR_ADD_WRITE_EV +}; + + +enum { + PIPE_READ_ALL = 0, + PIPE_READ_BYTES, + PIPE_READ_LINE, + PIPE_READ_ANY +}; + + +#define REASON_EXIT "exit" +#define REASON_SIGNAL "signal" +#define REASON_UNKNOWN "unknown" + +#define REASON_RUNNING_CODE 0 +#define REASON_EXIT_CODE 1 +#define REASON_SIGNAL_CODE 2 +#define REASON_UNKNOWN_CODE 3 + + +void +ngx_http_lua_pipe_init(void) +{ + ngx_rbtree_init(&ngx_http_lua_pipe_rbtree, + &ngx_http_lua_pipe_proc_sentinel, ngx_rbtree_insert_value); +} + + +ngx_int_t +ngx_http_lua_pipe_add_signal_handler(ngx_cycle_t *cycle) +{ + ngx_event_t *rev; +#if (NGX_HTTP_LUA_HAVE_SIGNALFD) + sigset_t set; + +#else + int rc; + struct sigaction sa; +#endif + +#if (NGX_HTTP_LUA_HAVE_SIGNALFD) + if (sigemptyset(&set) != 0) { + ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno, + "lua pipe init signal set failed"); + return NGX_ERROR; + } + + if (sigaddset(&set, SIGCHLD) != 0) { + ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno, + "lua pipe add SIGCHLD to signal set failed"); + return NGX_ERROR; + } + + if (sigprocmask(SIG_BLOCK, &set, NULL) != 0) { + ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno, + "lua pipe block SIGCHLD failed"); + return NGX_ERROR; + } + + ngx_http_lua_signalfd = signalfd(-1, &set, SFD_NONBLOCK|SFD_CLOEXEC); + if (ngx_http_lua_signalfd < 0) { + ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno, + "lua pipe create signalfd instance failed"); + return NGX_ERROR; + } + +#else /* !(NGX_HTTP_LUA_HAVE_SIGNALFD) */ +# if (NGX_HTTP_LUA_HAVE_PIPE2) + rc = pipe2(ngx_http_lua_sigchldfd, O_NONBLOCK|O_CLOEXEC); +# else + rc = pipe(ngx_http_lua_sigchldfd); +# endif + + if (rc == -1) { + ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno, + "lua pipe init SIGCHLD fd failed"); + return NGX_ERROR; + } + +# if !(NGX_HTTP_LUA_HAVE_PIPE2) + if (ngx_nonblocking(ngx_http_lua_read_sigfd) == -1) { + ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno, "lua pipe " + ngx_nonblocking_n " SIGCHLD read fd failed"); + goto failed; + } + + if (ngx_nonblocking(ngx_http_lua_write_sigfd) == -1) { + ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno, "lua pipe " + ngx_nonblocking_n " SIGCHLD write fd failed"); + goto failed; + } + + /* it's ok not to set the pipe fd with O_CLOEXEC. This requires + * extra syscall */ +# endif /* !(NGX_HTTP_LUA_HAVE_PIPE2) */ +#endif /* NGX_HTTP_LUA_HAVE_SIGNALFD */ + + ngx_http_lua_sigfd_conn = ngx_get_connection(ngx_http_lua_read_sigfd, + cycle->log); + if (ngx_http_lua_sigfd_conn == NULL) { + goto failed; + } + + ngx_http_lua_sigfd_conn->log = cycle->log; + ngx_http_lua_sigfd_conn->recv = ngx_http_lua_pipe_fd_read; + rev = ngx_http_lua_sigfd_conn->read; + rev->log = ngx_http_lua_sigfd_conn->log; + rev->handler = ngx_http_lua_pipe_sigchld_event_handler; + +#ifdef HAVE_SOCKET_CLOEXEC_PATCH + rev->skip_socket_leak_check = 1; +#endif + + if (ngx_handle_read_event(rev, 0) == NGX_ERROR) { + goto failed; + } + +#if !(NGX_HTTP_LUA_HAVE_SIGNALFD) + ngx_memzero(&sa, sizeof(struct sigaction)); + sa.sa_sigaction = ngx_http_lua_pipe_sigchld_handler; + sa.sa_flags = SA_SIGINFO; + + if (sigemptyset(&sa.sa_mask) != 0) { + ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno, + "lua pipe init signal mask failed"); + goto failed; + } + + if (sigaction(SIGCHLD, &sa, NULL) == -1) { + ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno, + "lua pipe sigaction(SIGCHLD) failed"); + goto failed; + } +#endif + + return NGX_OK; + +failed: + + if (ngx_http_lua_sigfd_conn != NULL) { + ngx_close_connection(ngx_http_lua_sigfd_conn); + ngx_http_lua_sigfd_conn = NULL; + } + + if (close(ngx_http_lua_read_sigfd) == -1) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, + "lua pipe close the read sigfd failed"); + } + +#if !(NGX_HTTP_LUA_HAVE_SIGNALFD) + if (close(ngx_http_lua_write_sigfd) == -1) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, + "lua pipe close the write sigfd failed"); + } +#endif + + return NGX_ERROR; +} + + +static ngx_rbtree_node_t * +ngx_http_lua_pipe_lookup_pid(ngx_rbtree_key_t key) +{ + ngx_rbtree_node_t *node, *sentinel; + + node = ngx_http_lua_pipe_rbtree.root; + sentinel = ngx_http_lua_pipe_rbtree.sentinel; + + while (node != sentinel) { + if (key < node->key) { + node = node->left; + continue; + } + + if (key > node->key) { + node = node->right; + continue; + } + + return node; + } + + return NULL; +} + + +#if !(NGX_HTTP_LUA_HAVE_SIGNALFD) +static void +ngx_http_lua_pipe_sigchld_handler(int signo, siginfo_t *siginfo, + void *ucontext) +{ + ngx_err_t err, saved_err; + ngx_int_t n; + + saved_err = ngx_errno; + + for ( ;; ) { + n = write(ngx_http_lua_write_sigfd, ngx_http_lua_pipe_notification, + sizeof(ngx_http_lua_pipe_notification)); + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0, + "lua pipe SIGCHLD fd write siginfo:%p", siginfo); + + if (n >= 0) { + break; + } + + err = ngx_errno; + + if (err != NGX_EINTR) { + if (err != NGX_EAGAIN) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, err, + "lua pipe SIGCHLD fd write failed"); + } + + break; + } + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, err, + "lua pipe SIGCHLD fd write was interrupted"); + } + + ngx_set_errno(saved_err); +} +#endif + + +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"); + + for ( ;; ) { +#if (NGX_HTTP_LUA_HAVE_SIGNALFD) + n = c->recv(c, (u_char *) &ngx_http_lua_pipe_notification, +#else + n = c->recv(c, ngx_http_lua_pipe_notification, +#endif + sizeof(ngx_http_lua_pipe_notification)); + + if (n <= 0) { + if (n == NGX_ERROR) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, + "lua pipe SIGCHLD fd read failed"); + } + + break; + } + + for ( ;; ) { + pid = waitpid(-1, &status, WNOHANG); + + if (pid == 0) { + break; + } + + if (pid < 0) { + if (ngx_errno != NGX_ECHILD) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, + "lua pipe waitpid failed"); + } + + break; + } + + /* This log is ported from Nginx's signal handler since we override + * or block it in this implementation. */ + ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0, + "signal %d (SIGCHLD) received from %P", + SIGCHLD, pid); + + 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); + } + + 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 ssize_t +ngx_http_lua_pipe_fd_read(ngx_connection_t *c, u_char *buf, size_t size) +{ + ssize_t n; + ngx_err_t err; + ngx_event_t *rev; + + rev = c->read; + + do { + n = read(c->fd, buf, size); + + err = ngx_errno; + + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, + "read: fd:%d %z of %uz", c->fd, n, size); + + if (n == 0) { + rev->ready = 0; + rev->eof = 1; + return 0; + } + + if (n > 0) { + if ((size_t) n < size + && !(ngx_event_flags & NGX_USE_GREEDY_EVENT)) + { + rev->ready = 0; + } + + return n; + } + + if (err == NGX_EAGAIN || err == NGX_EINTR) { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, + "read() not ready"); + n = NGX_AGAIN; + + } else { + n = ngx_connection_error(c, err, "read() failed"); + break; + } + + } while (err == NGX_EINTR); + + rev->ready = 0; + + if (n == NGX_ERROR) { + rev->error = 1; + } + + return n; +} + + +static ssize_t +ngx_http_lua_pipe_fd_write(ngx_connection_t *c, u_char *buf, size_t size) +{ + ssize_t n; + ngx_err_t err; + ngx_event_t *wev; + + wev = c->write; + + do { + n = write(c->fd, buf, size); + + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, + "write: fd:%d %z of %uz", c->fd, n, size); + + if (n >= 0) { + if ((size_t) n != size) { + wev->ready = 0; + } + + return n; + } + + err = ngx_errno; + + if (err == NGX_EAGAIN || err == NGX_EINTR) { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, + "write() not ready"); + n = NGX_AGAIN; + + } else if (err != NGX_EPIPE) { + n = ngx_connection_error(c, err, "write() failed"); + break; + } + + } while (err == NGX_EINTR); + + wev->ready = 0; + + if (n == NGX_ERROR) { + wev->error = 1; + } + + return n; +} + + +int +ngx_http_lua_ffi_pipe_spawn(ngx_http_lua_ffi_pipe_proc_t *proc, + const char *file, const char **argv, int merge_stderr, size_t buffer_size, + u_char *errbuf, size_t *errbuf_size) +{ + int rc; + int in[2]; + int out[2]; + int err[2]; + int stdin_fd, stdout_fd, stderr_fd; + int errlog_fd, temp_errlog_fd; + ngx_pid_t pid; + ssize_t pool_size; + ngx_pool_t *pool; + ngx_uint_t i; + ngx_listening_t *ls; + ngx_http_lua_pipe_t *pp; + ngx_rbtree_node_t *node; + ngx_http_lua_pipe_node_t *pipe_node; + struct sigaction sa; + ngx_http_lua_pipe_signal_t *sig; + sigset_t set; + + pool_size = ngx_align(NGX_MIN_POOL_SIZE + buffer_size * 2, + NGX_POOL_ALIGNMENT); + + pool = ngx_create_pool(pool_size, ngx_cycle->log); + if (pool == NULL) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "no memory") + - errbuf; + return NGX_ERROR; + } + + pp = ngx_pcalloc(pool, sizeof(ngx_http_lua_pipe_t) + + offsetof(ngx_rbtree_node_t, color) + + sizeof(ngx_http_lua_pipe_node_t)); + if (pp == NULL) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "no memory") + - errbuf; + goto free_pool; + } + + rc = pipe(in); + if (rc == -1) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "pipe failed: %s", + strerror(errno)) + - errbuf; + goto free_pool; + } + + rc = pipe(out); + if (rc == -1) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "pipe failed: %s", + strerror(errno)) + - errbuf; + goto close_in_fd; + } + + if (!merge_stderr) { + rc = pipe(err); + if (rc == -1) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, + "pipe failed: %s", strerror(errno)) + - errbuf; + goto close_in_out_fd; + } + } + + pid = fork(); + if (pid == -1) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "fork failed: %s", + strerror(errno)) + - errbuf; + goto close_in_out_err_fd; + } + + if (pid == 0) { + +#if (NGX_HAVE_CPU_AFFINITY) + /* reset the CPU affinity mask */ + ngx_uint_t log_level; + ngx_cpuset_t child_cpu_affinity; + + if (ngx_process == NGX_PROCESS_WORKER + && ngx_get_cpu_affinity(ngx_worker) != NULL) + { + CPU_ZERO(&child_cpu_affinity); + + for (i = 0; i < (ngx_uint_t) ngx_min(ngx_ncpu, CPU_SETSIZE); i++) { + CPU_SET(i, &child_cpu_affinity); + } + + log_level = ngx_cycle->log->log_level; + ngx_cycle->log->log_level = NGX_LOG_WARN; + ngx_setaffinity(&child_cpu_affinity, ngx_cycle->log); + ngx_cycle->log->log_level = log_level; + } +#endif + + /* reset the handler of ignored signals to the default */ + for (sig = ngx_signals; sig->signo != 0; sig++) { + ngx_memzero(&sa, sizeof(struct sigaction)); + sa.sa_handler = SIG_DFL; + + if (sigemptyset(&sa.sa_mask) != 0) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, + "lua pipe child init signal mask failed"); + exit(EXIT_FAILURE); + } + + if (sigaction(sig->signo, &sa, NULL) == -1) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, + "lua pipe child reset signal handler for %s " + "failed", sig->signame); + exit(EXIT_FAILURE); + } + } + + /* reset signal mask */ + if (sigemptyset(&set) != 0) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, + "lua pipe child init signal set failed"); + exit(EXIT_FAILURE); + } + + if (sigprocmask(SIG_SETMASK, &set, NULL) != 0) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, + "lua pipe child reset signal mask failed"); + exit(EXIT_FAILURE); + } + + /* close listening socket fd */ + ls = ngx_cycle->listening.elts; + for (i = 0; i < ngx_cycle->listening.nelts; i++) { + if (ngx_close_socket(ls[i].fd) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_socket_errno, + "lua pipe child " ngx_close_socket_n + " %V failed", &ls[i].addr_text); + } + } + + /* close and dup pipefd */ + if (close(in[1]) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, + "lua pipe child failed to close the in[1] " + "pipe fd"); + } + + if (close(out[0]) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, + "lua pipe child failed to close the out[0] " + "pipe fd"); + } + + if (ngx_cycle->log->file && ngx_cycle->log->file->fd == STDERR_FILENO) { + errlog_fd = ngx_cycle->log->file->fd; + temp_errlog_fd = dup(errlog_fd); + + if (temp_errlog_fd == -1) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, + "lua pipe child dup errlog fd failed"); + exit(EXIT_FAILURE); + } + + if (ngx_cloexec(temp_errlog_fd) == -1) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, + "lua pipe child new errlog fd " ngx_cloexec_n + " failed"); + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe child dup old errlog fd %d to new fd %d", + ngx_cycle->log->file->fd, temp_errlog_fd); + + ngx_cycle->log->file->fd = temp_errlog_fd; + } + + if (dup2(in[0], STDIN_FILENO) == -1) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, + "lua pipe child dup2 stdin failed"); + exit(EXIT_FAILURE); + } + + if (dup2(out[1], STDOUT_FILENO) == -1) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, + "lua pipe child dup2 stdout failed"); + exit(EXIT_FAILURE); + } + + if (merge_stderr) { + if (dup2(STDOUT_FILENO, STDERR_FILENO) == -1) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, + "lua pipe child dup2 stderr failed"); + exit(EXIT_FAILURE); + } + + } else { + if (close(err[0]) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, + "lua pipe child failed to close the err[0] " + "pipe fd"); + } + + if (dup2(err[1], STDERR_FILENO) == -1) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, + "lua pipe child dup2 stderr failed"); + exit(EXIT_FAILURE); + } + } + + if (execvp(file, (char * const *) argv) == -1) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, + "lua pipe child execvp() failed while executing %s", + file); + } + + exit(EXIT_FAILURE); + } + + /* parent process */ + if (close(in[0]) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, + "lua pipe: failed to close the in[0] pipe fd"); + } + + stdin_fd = in[1]; + + if (ngx_nonblocking(stdin_fd) == -1) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, + ngx_nonblocking_n " failed: %s", + strerror(errno)) + - errbuf; + goto close_in_out_err_fd; + } + + pp->stdin_fd = stdin_fd; + + if (close(out[1]) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, + "lua pipe: failed to close the out[1] pipe fd"); + } + + stdout_fd = out[0]; + + if (ngx_nonblocking(stdout_fd) == -1) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, + ngx_nonblocking_n " failed: %s", + strerror(errno)) + - errbuf; + goto close_in_out_err_fd; + } + + pp->stdout_fd = stdout_fd; + + if (!merge_stderr) { + if (close(err[1]) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, + "lua pipe: failed to close the err[1] pipe fd"); + } + + stderr_fd = err[0]; + + if (ngx_nonblocking(stderr_fd) == -1) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, + ngx_nonblocking_n " failed: %s", + strerror(errno)) + - errbuf; + goto close_in_out_err_fd; + } + + pp->stderr_fd = stderr_fd; + } + + node = (ngx_rbtree_node_t *) (pp + 1); + node->key = pid; + pipe_node = (ngx_http_lua_pipe_node_t *) &node->color; + pipe_node->proc = proc; + ngx_rbtree_insert(&ngx_http_lua_pipe_rbtree, node); + + pp->node = node; + pp->pool = pool; + pp->merge_stderr = merge_stderr; + pp->buffer_size = buffer_size; + + proc->_pid = pid; + proc->write_timeout = 10000; + proc->stdout_read_timeout = 10000; + proc->stderr_read_timeout = 10000; + proc->wait_timeout = 10000; + proc->pipe = pp; + + ngx_log_debug4(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe spawn process:%p pid:%P merge_stderr:%d " + "buffer_size:%uz", proc, pid, merge_stderr, buffer_size); + return NGX_OK; + +close_in_out_err_fd: + + if (!merge_stderr) { + if (close(err[0]) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, + "failed to close the err[0] pipe fd"); + } + + if (close(err[1]) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, + "failed to close the err[1] pipe fd"); + } + } + +close_in_out_fd: + + if (close(out[0]) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, + "failed to close the out[0] pipe fd"); + } + + if (close(out[1]) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, + "failed to close the out[1] pipe fd"); + } + +close_in_fd: + + if (close(in[0]) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, + "failed to close the in[0] pipe fd"); + } + + if (close(in[1]) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, + "failed to close the in[1] pipe fd"); + } + +free_pool: + + ngx_destroy_pool(pool); + return NGX_ERROR; +} + + +static ngx_int_t +ngx_http_lua_pipe_close_helper(ngx_http_lua_pipe_ctx_t *pipe_ctx, + ngx_event_t *ev, int forced) +{ + if (ev->handler != ngx_http_lua_pipe_dummy_event_handler && !forced) { + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe cannot close fd:%d without " + "forced pipe:%p ev:%p", pipe_ctx->c->fd, pipe_ctx, ev); + return NGX_ERROR; + } + + ngx_close_connection(pipe_ctx->c); + pipe_ctx->c = NULL; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_lua_pipe_close_stdin(ngx_http_lua_pipe_t *pipe, int forced) +{ + ngx_event_t *wev; + + if (pipe->stdin_ctx == NULL) { + if (pipe->stdin_fd != -1) { + if (close(pipe->stdin_fd) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, + "failed to close the stdin pipe fd"); + } + + pipe->stdin_fd = -1; + } + + } else if (pipe->stdin_ctx->c != NULL) { + wev = pipe->stdin_ctx->c->write; + return ngx_http_lua_pipe_close_helper(pipe->stdin_ctx, wev, forced); + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_lua_pipe_close_stdout(ngx_http_lua_pipe_t *pipe, int forced) +{ + ngx_event_t *rev; + + if (pipe->stdout_ctx == NULL) { + if (pipe->stdout_fd != -1) { + if (close(pipe->stdout_fd) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, + "failed to close the stdout pipe fd"); + } + + pipe->stdout_fd = -1; + } + + } else if (pipe->stdout_ctx->c != NULL) { + rev = pipe->stdout_ctx->c->read; + return ngx_http_lua_pipe_close_helper(pipe->stdout_ctx, rev, forced); + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_lua_pipe_close_stderr(ngx_http_lua_pipe_t *pipe, int forced) +{ + ngx_event_t *rev; + + if (pipe->stderr_ctx == NULL) { + if (pipe->stderr_fd != -1) { + if (close(pipe->stderr_fd) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, + "failed to close the stderr pipe fd"); + } + + pipe->stderr_fd = -1; + } + + } else if (pipe->stderr_ctx->c != NULL) { + rev = pipe->stderr_ctx->c->read; + return ngx_http_lua_pipe_close_helper(pipe->stderr_ctx, rev, forced); + } + + return NGX_OK; +} + + +int +ngx_http_lua_ffi_pipe_proc_shutdown_stdin(ngx_http_lua_ffi_pipe_proc_t *proc, + u_char *errbuf, size_t *errbuf_size) +{ + ngx_int_t rc; + ngx_http_lua_pipe_t *pipe; + + pipe = proc->pipe; + if (pipe == NULL || pipe->closed) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "closed") - errbuf; + return NGX_ERROR; + } + + rc = ngx_http_lua_pipe_close_stdin(pipe, 0); + if (rc != NGX_OK) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "pipe busy writing") + - errbuf; + return NGX_ERROR; + } + + return NGX_OK; +} + + +int +ngx_http_lua_ffi_pipe_proc_shutdown_stdout(ngx_http_lua_ffi_pipe_proc_t *proc, + u_char *errbuf, size_t *errbuf_size) +{ + ngx_int_t rc; + ngx_http_lua_pipe_t *pipe; + + pipe = proc->pipe; + if (pipe == NULL || pipe->closed) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "closed") - errbuf; + return NGX_ERROR; + } + + rc = ngx_http_lua_pipe_close_stdout(pipe, 0); + if (rc != NGX_OK) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "pipe busy reading") + - errbuf; + return NGX_ERROR; + } + + return NGX_OK; +} + + +int +ngx_http_lua_ffi_pipe_proc_shutdown_stderr(ngx_http_lua_ffi_pipe_proc_t *proc, + u_char *errbuf, size_t *errbuf_size) +{ + ngx_http_lua_pipe_t *pipe; + + pipe = proc->pipe; + if (pipe == NULL || pipe->closed) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "closed") - errbuf; + return NGX_ERROR; + } + + if (pipe->merge_stderr) { + /* stdout is used internally as stderr when merge_stderr is true */ + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "merged to stdout") + - errbuf; + return NGX_ERROR; + } + + if (ngx_http_lua_pipe_close_stderr(pipe, 0) != NGX_OK) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "pipe busy reading") + - errbuf; + return NGX_ERROR; + } + + return NGX_OK; +} + + +static void +ngx_http_lua_pipe_proc_finalize(ngx_http_lua_ffi_pipe_proc_t *proc, int forced) +{ + ngx_http_lua_pipe_t *pipe; + + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe finalize process:%p pid:%P forced:%d", proc, + proc->_pid, forced); + pipe = proc->pipe; + + if (pipe->node) { + ngx_rbtree_delete(&ngx_http_lua_pipe_rbtree, pipe->node); + pipe->node = NULL; + } + + pipe->dead = 1; + + ngx_http_lua_pipe_close_stdin(pipe, forced); + ngx_http_lua_pipe_close_stdout(pipe, forced); + + if (!pipe->merge_stderr) { + ngx_http_lua_pipe_close_stderr(pipe, forced); + } + + pipe->closed = 1; +} + + +void +ngx_http_lua_ffi_pipe_proc_destroy(ngx_http_lua_ffi_pipe_proc_t *proc) +{ + ngx_http_lua_pipe_t *pipe; + + pipe = proc->pipe; + if (pipe == NULL) { + return; + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe destroy process:%p pid:%P", proc, proc->_pid); + + if (!pipe->dead) { + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe kill process:%p pid:%P", proc, proc->_pid); + + if (kill(proc->_pid, SIGKILL) == -1) { + if (ngx_errno != ESRCH) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, + "lua pipe failed to kill process:%p pid:%P"); + } + } + } + + ngx_http_lua_pipe_proc_finalize(proc, 1); + ngx_destroy_pool(pipe->pool); + proc->pipe = NULL; +} + + +static ngx_int_t +ngx_http_lua_pipe_get_lua_ctx(ngx_http_request_t *r, + ngx_http_lua_ctx_t **ctx, u_char *errbuf, size_t *errbuf_size) +{ + int rc; + + *ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx == NULL) { + return NGX_HTTP_LUA_FFI_NO_REQ_CTX; + } + + rc = ngx_http_lua_ffi_check_context(*ctx, NGX_HTTP_LUA_CONTEXT_REWRITE + | NGX_HTTP_LUA_CONTEXT_ACCESS + | NGX_HTTP_LUA_CONTEXT_CONTENT + | NGX_HTTP_LUA_CONTEXT_TIMER + | NGX_HTTP_LUA_CONTEXT_SSL_CERT + | NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH, + errbuf, errbuf_size); + if (rc != NGX_OK) { + return NGX_HTTP_LUA_FFI_BAD_CONTEXT; + } + + return NGX_OK; +} + + +static void +ngx_http_lua_pipe_put_error(ngx_http_lua_pipe_ctx_t *pipe_ctx, u_char *errbuf, + size_t *errbuf_size) +{ + switch (pipe_ctx->err_type) { + + case PIPE_ERR_CLOSED: + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "closed") - errbuf; + break; + + case PIPE_ERR_SYSCALL: + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "%s", + strerror(pipe_ctx->pipe_errno)) + - errbuf; + break; + + case PIPE_ERR_NOMEM: + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "no memory") + - errbuf; + break; + + case PIPE_ERR_TIMEOUT: + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "timeout") + - errbuf; + break; + + case PIPE_ERR_ADD_READ_EV: + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, + "failed to add read event") + - errbuf; + break; + + case PIPE_ERR_ADD_WRITE_EV: + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, + "failed to add write event") + - errbuf; + break; + + default: + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, + "unexpected err type: %d", pipe_ctx->err_type); + ngx_http_lua_assert(NULL); + } +} + + +static void +ngx_http_lua_pipe_put_data(ngx_http_lua_pipe_t *pipe, + ngx_http_lua_pipe_ctx_t *pipe_ctx, u_char **buf, size_t *buf_size) +{ + size_t size = 0; + size_t chunk_size; + size_t nbufs; + u_char *p; + ngx_buf_t *b; + ngx_chain_t *cl; + ngx_chain_t **ll; + + nbufs = 0; + ll = NULL; + + for (cl = pipe_ctx->bufs_in; cl; cl = cl->next) { + b = cl->buf; + chunk_size = b->last - b->pos; + + if (cl->next) { + ll = &cl->next; + } + + size += chunk_size; + + nbufs++; + } + + if (*buf_size < size) { + *buf = NULL; + *buf_size = size; + + return; + } + + *buf_size = size; + + p = *buf; + for (cl = pipe_ctx->bufs_in; cl; cl = cl->next) { + b = cl->buf; + chunk_size = b->last - b->pos; + p = ngx_cpymem(p, b->pos, chunk_size); + } + + if (nbufs > 1 && ll) { + *ll = pipe->free_bufs; + pipe->free_bufs = pipe_ctx->bufs_in; + pipe_ctx->bufs_in = pipe_ctx->buf_in; + } + + if (pipe_ctx->buffer.pos == pipe_ctx->buffer.last) { + pipe_ctx->buffer.pos = pipe_ctx->buffer.start; + pipe_ctx->buffer.last = pipe_ctx->buffer.start; + } + + if (pipe_ctx->bufs_in) { + pipe_ctx->buf_in->buf->last = pipe_ctx->buffer.pos; + pipe_ctx->buf_in->buf->pos = pipe_ctx->buffer.pos; + } +} + + +static ngx_int_t +ngx_http_lua_pipe_add_input_buffer(ngx_http_lua_pipe_t *pipe, + ngx_http_lua_pipe_ctx_t *pipe_ctx) +{ + ngx_chain_t *cl; + + cl = ngx_http_lua_chain_get_free_buf(ngx_cycle->log, pipe->pool, + &pipe->free_bufs, + pipe->buffer_size); + + if (cl == NULL) { + pipe_ctx->err_type = PIPE_ERR_NOMEM; + return NGX_ERROR; + } + + pipe_ctx->buf_in->next = cl; + pipe_ctx->buf_in = cl; + pipe_ctx->buffer = *cl->buf; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_lua_pipe_read_all(void *data, ssize_t bytes) +{ + ngx_http_lua_pipe_ctx_t *pipe_ctx = data; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, "lua pipe read all"); + return ngx_http_lua_read_all(&pipe_ctx->buffer, pipe_ctx->buf_in, bytes, + ngx_cycle->log); +} + + +static ngx_int_t +ngx_http_lua_pipe_read_bytes(void *data, ssize_t bytes) +{ + ngx_int_t rc; + ngx_http_lua_pipe_ctx_t *pipe_ctx = data; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe read bytes %z", bytes); + + rc = ngx_http_lua_read_bytes(&pipe_ctx->buffer, pipe_ctx->buf_in, + &pipe_ctx->rest, bytes, ngx_cycle->log); + if (rc == NGX_ERROR) { + pipe_ctx->err_type = PIPE_ERR_CLOSED; + return NGX_ERROR; + } + + return rc; +} + + +static ngx_int_t +ngx_http_lua_pipe_read_line(void *data, ssize_t bytes) +{ + ngx_int_t rc; + ngx_http_lua_pipe_ctx_t *pipe_ctx = data; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe read line"); + rc = ngx_http_lua_read_line(&pipe_ctx->buffer, pipe_ctx->buf_in, bytes, + ngx_cycle->log); + if (rc == NGX_ERROR) { + pipe_ctx->err_type = PIPE_ERR_CLOSED; + return NGX_ERROR; + } + + return rc; +} + + +static ngx_int_t +ngx_http_lua_pipe_read_any(void *data, ssize_t bytes) +{ + ngx_int_t rc; + ngx_http_lua_pipe_ctx_t *pipe_ctx = data; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, "lua pipe read any"); + rc = ngx_http_lua_read_any(&pipe_ctx->buffer, pipe_ctx->buf_in, + &pipe_ctx->rest, bytes, ngx_cycle->log); + if (rc == NGX_ERROR) { + pipe_ctx->err_type = PIPE_ERR_CLOSED; + return NGX_ERROR; + } + + return rc; +} + + +static ngx_int_t +ngx_http_lua_pipe_read(ngx_http_lua_pipe_t *pipe, + ngx_http_lua_pipe_ctx_t *pipe_ctx) +{ + int rc; + int read; + size_t size; + ssize_t n; + ngx_buf_t *b; + ngx_event_t *rev; + ngx_connection_t *c; + + c = pipe_ctx->c; + rev = c->read; + b = &pipe_ctx->buffer; + read = 0; + + for ( ;; ) { + size = b->last - b->pos; + + if (size || pipe_ctx->eof) { + rc = pipe_ctx->input_filter(pipe_ctx->input_filter_ctx, size); + if (rc == NGX_ERROR) { + return NGX_ERROR; + } + + if (rc == NGX_OK) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe read done pipe:%p", pipe_ctx); + return NGX_OK; + } + + /* rc == NGX_AGAIN */ + continue; + } + + if (read && !rev->ready) { + break; + } + + size = b->end - b->last; + + if (size == 0) { + rc = ngx_http_lua_pipe_add_input_buffer(pipe, pipe_ctx); + if (rc == NGX_ERROR) { + return NGX_ERROR; + } + + b = &pipe_ctx->buffer; + size = (size_t) (b->end - b->last); + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe try to read data %uz pipe:%p", + size, pipe_ctx); + + n = c->recv(c, b->last, size); + read = 1; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe read data returned %z pipe:%p", n, pipe_ctx); + + if (n == NGX_AGAIN) { + break; + } + + if (n == 0) { + pipe_ctx->eof = 1; + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe closed pipe:%p", pipe_ctx); + continue; + } + + if (n == NGX_ERROR) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, ngx_errno, + "lua pipe read data error pipe:%p", pipe_ctx); + + pipe_ctx->err_type = PIPE_ERR_SYSCALL; + pipe_ctx->pipe_errno = ngx_errno; + return NGX_ERROR; + } + + b->last += n; + } + + return NGX_AGAIN; +} + + +static ngx_int_t +ngx_http_lua_pipe_init_ctx(ngx_http_lua_pipe_ctx_t **pipe_ctx_pt, int fd, + ngx_pool_t *pool, u_char *errbuf, size_t *errbuf_size) +{ + ngx_connection_t *c; + + if (fd == -1) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "closed") - errbuf; + return NGX_ERROR; + } + + *pipe_ctx_pt = ngx_pcalloc(pool, sizeof(ngx_http_lua_pipe_ctx_t)); + if (*pipe_ctx_pt == NULL) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "no memory") + - errbuf; + return NGX_ERROR; + } + + c = ngx_get_connection(fd, ngx_cycle->log); + if (c == NULL) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "no connection") + - errbuf; + return NGX_ERROR; + } + + c->log = ngx_cycle->log; + c->recv = ngx_http_lua_pipe_fd_read; + c->read->handler = ngx_http_lua_pipe_dummy_event_handler; + c->read->log = c->log; + +#ifdef HAVE_SOCKET_CLOEXEC_PATCH + c->read->skip_socket_leak_check = 1; +#endif + + c->send = ngx_http_lua_pipe_fd_write; + c->write->handler = ngx_http_lua_pipe_dummy_event_handler; + c->write->log = c->log; + (*pipe_ctx_pt)->c = c; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe init pipe ctx:%p fd:*%d", *pipe_ctx_pt, fd); + + return NGX_OK; +} + + +int +ngx_http_lua_ffi_pipe_proc_read(ngx_http_request_t *r, + ngx_http_lua_ffi_pipe_proc_t *proc, int from_stderr, int reader_type, + size_t length, u_char **buf, size_t *buf_size, u_char *errbuf, + size_t *errbuf_size) +{ + int rc; + ngx_msec_t timeout; + ngx_event_t *rev; + ngx_connection_t *c; + ngx_http_lua_ctx_t *ctx; + ngx_http_lua_pipe_t *pipe; + ngx_http_lua_co_ctx_t *wait_co_ctx; + ngx_http_lua_pipe_ctx_t *pipe_ctx; + + rc = ngx_http_lua_pipe_get_lua_ctx(r, &ctx, errbuf, errbuf_size); + if (rc != NGX_OK) { + return rc; + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua pipe read process:%p pid:%P", proc, proc->_pid); + + pipe = proc->pipe; + if (pipe == NULL || pipe->closed) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "closed") - errbuf; + return NGX_ERROR; + } + + if (pipe->merge_stderr && from_stderr) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "merged to stdout") + - errbuf; + return NGX_ERROR; + } + + if (from_stderr) { + if (pipe->stderr_ctx == NULL) { + if (ngx_http_lua_pipe_init_ctx(&pipe->stderr_ctx, pipe->stderr_fd, + pipe->pool, errbuf, + errbuf_size) + != NGX_OK) + { + return NGX_ERROR; + } + + } else { + pipe->stderr_ctx->err_type = 0; + } + + pipe_ctx = pipe->stderr_ctx; + + } else { + if (pipe->stdout_ctx == NULL) { + if (ngx_http_lua_pipe_init_ctx(&pipe->stdout_ctx, pipe->stdout_fd, + pipe->pool, errbuf, + errbuf_size) + != NGX_OK) + { + return NGX_ERROR; + } + + } else { + pipe->stdout_ctx->err_type = 0; + } + + pipe_ctx = pipe->stdout_ctx; + } + + c = pipe_ctx->c; + if (c == NULL) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "closed") - errbuf; + return NGX_ERROR; + } + + rev = c->read; + if (rev->handler != ngx_http_lua_pipe_dummy_event_handler) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "pipe busy reading") + - errbuf; + return NGX_ERROR; + } + + pipe_ctx->input_filter_ctx = pipe_ctx; + + switch (reader_type) { + + case PIPE_READ_ALL: + pipe_ctx->input_filter = ngx_http_lua_pipe_read_all; + break; + + case PIPE_READ_BYTES: + pipe_ctx->input_filter = ngx_http_lua_pipe_read_bytes; + break; + + case PIPE_READ_LINE: + pipe_ctx->input_filter = ngx_http_lua_pipe_read_line; + break; + + case PIPE_READ_ANY: + pipe_ctx->input_filter = ngx_http_lua_pipe_read_any; + break; + + default: + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, + "unexpected reader_type: %d", reader_type); + ngx_http_lua_assert(NULL); + } + + pipe_ctx->rest = length; + + if (pipe_ctx->bufs_in == NULL) { + pipe_ctx->bufs_in = + ngx_http_lua_chain_get_free_buf(ngx_cycle->log, pipe->pool, + &pipe->free_bufs, + pipe->buffer_size); + + if (pipe_ctx->bufs_in == NULL) { + pipe_ctx->err_type = PIPE_ERR_NOMEM; + goto error; + } + + pipe_ctx->buf_in = pipe_ctx->bufs_in; + pipe_ctx->buffer = *pipe_ctx->buf_in->buf; + } + + rc = ngx_http_lua_pipe_read(pipe, pipe_ctx); + if (rc == NGX_ERROR) { + goto error; + } + + if (rc == NGX_OK) { + ngx_http_lua_pipe_put_data(pipe, pipe_ctx, buf, buf_size); + return NGX_OK; + } + + /* rc == NGX_AGAIN */ + wait_co_ctx = ctx->cur_co_ctx; + + c->data = wait_co_ctx; + if (ngx_handle_read_event(rev, 0) != NGX_OK) { + pipe_ctx->err_type = PIPE_ERR_ADD_READ_EV; + goto error; + } + + wait_co_ctx->data = proc; + + if (from_stderr) { + rev->handler = ngx_http_lua_pipe_resume_read_stderr_handler; + wait_co_ctx->cleanup = ngx_http_lua_pipe_proc_read_stderr_cleanup; + timeout = proc->stderr_read_timeout; + + } else { + rev->handler = ngx_http_lua_pipe_resume_read_stdout_handler; + wait_co_ctx->cleanup = ngx_http_lua_pipe_proc_read_stdout_cleanup; + timeout = proc->stdout_read_timeout; + } + + if (timeout > 0) { + ngx_add_timer(rev, timeout); + ngx_log_debug5(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua pipe add timer for reading: %d(ms) process:%p " + "pid:%P pipe:%p ev:%p", timeout, proc, proc->_pid, pipe, + rev); + } + + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua pipe read yielding process:%p pid:%P pipe:%p", proc, + proc->_pid, pipe); + + return NGX_AGAIN; + +error: + + if (pipe_ctx->bufs_in) { + ngx_http_lua_pipe_put_data(pipe, pipe_ctx, buf, buf_size); + ngx_http_lua_pipe_put_error(pipe_ctx, errbuf, errbuf_size); + return NGX_DECLINED; + } + + ngx_http_lua_pipe_put_error(pipe_ctx, errbuf, errbuf_size); + + return NGX_ERROR; +} + + +/* + * ngx_http_lua_ffi_pipe_get_read_result should only be called just after + * ngx_http_lua_ffi_pipe_proc_read, so we omit most of the sanity check already + * done in ngx_http_lua_ffi_pipe_proc_read. + */ +int +ngx_http_lua_ffi_pipe_get_read_result(ngx_http_request_t *r, + ngx_http_lua_ffi_pipe_proc_t *proc, int from_stderr, u_char **buf, + size_t *buf_size, u_char *errbuf, size_t *errbuf_size) +{ + ngx_http_lua_pipe_t *pipe; + ngx_http_lua_pipe_ctx_t *pipe_ctx; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua pipe get read result process:%p pid:%P", proc, + proc->_pid); + + pipe = proc->pipe; + pipe_ctx = from_stderr ? pipe->stderr_ctx : pipe->stdout_ctx; + + if (!pipe_ctx->err_type) { + ngx_http_lua_pipe_put_data(pipe, pipe_ctx, buf, buf_size); + return NGX_OK; + } + + if (pipe_ctx->bufs_in) { + ngx_http_lua_pipe_put_data(pipe, pipe_ctx, buf, buf_size); + ngx_http_lua_pipe_put_error(pipe_ctx, errbuf, errbuf_size); + return NGX_DECLINED; + } + + ngx_http_lua_pipe_put_error(pipe_ctx, errbuf, errbuf_size); + + return NGX_ERROR; +} + + +static ngx_int_t +ngx_http_lua_pipe_write(ngx_http_lua_pipe_t *pipe, + ngx_http_lua_pipe_ctx_t *pipe_ctx) +{ + size_t size; + ngx_int_t n; + ngx_buf_t *b; + ngx_connection_t *c; + + c = pipe_ctx->c; + b = pipe_ctx->buf_in->buf; + + for ( ;; ) { + size = b->last - b->pos; + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe try to write data %uz pipe:%p", size, + pipe_ctx); + + n = c->send(c, b->pos, size); + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe write returned %i pipe:%p", n, pipe_ctx); + + if (n >= 0) { + b->pos += n; + + if (b->pos == b->last) { + b->pos = b->start; + b->last = b->start; + + if (!pipe->free_bufs) { + pipe->free_bufs = pipe_ctx->buf_in; + + } else { + pipe->free_bufs->next = pipe_ctx->buf_in; + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe write done pipe:%p", pipe_ctx); + return NGX_OK; + } + + continue; + } + + /* NGX_ERROR || NGX_AGAIN */ + break; + } + + if (n == NGX_ERROR) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, ngx_errno, + "lua pipe write data error pipe:%p", pipe_ctx); + + if (ngx_errno == NGX_EPIPE) { + pipe_ctx->err_type = PIPE_ERR_CLOSED; + + } else { + pipe_ctx->err_type = PIPE_ERR_SYSCALL; + pipe_ctx->pipe_errno = ngx_errno; + } + + return NGX_ERROR; + } + + return NGX_AGAIN; +} + + +ssize_t +ngx_http_lua_ffi_pipe_proc_write(ngx_http_request_t *r, + ngx_http_lua_ffi_pipe_proc_t *proc, const u_char *data, size_t len, + u_char *errbuf, size_t *errbuf_size) +{ + int rc; + ngx_buf_t *b; + ngx_msec_t timeout; + ngx_chain_t *cl; + ngx_event_t *wev; + ngx_http_lua_ctx_t *ctx; + ngx_http_lua_pipe_t *pipe; + ngx_http_lua_co_ctx_t *wait_co_ctx; + ngx_http_lua_pipe_ctx_t *pipe_ctx; + + rc = ngx_http_lua_pipe_get_lua_ctx(r, &ctx, errbuf, errbuf_size); + if (rc != NGX_OK) { + return rc; + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua pipe write process:%p pid:%P", proc, proc->_pid); + + pipe = proc->pipe; + if (pipe == NULL || pipe->closed) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "closed") - errbuf; + return NGX_ERROR; + } + + if (pipe->stdin_ctx == NULL) { + if (ngx_http_lua_pipe_init_ctx(&pipe->stdin_ctx, pipe->stdin_fd, + pipe->pool, errbuf, + errbuf_size) + != NGX_OK) + { + return NGX_ERROR; + } + + } else { + pipe->stdin_ctx->err_type = 0; + } + + pipe_ctx = pipe->stdin_ctx; + if (pipe_ctx->c == NULL) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "closed") - errbuf; + return NGX_ERROR; + } + + wev = pipe_ctx->c->write; + if (wev->handler != ngx_http_lua_pipe_dummy_event_handler) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "pipe busy writing") + - errbuf; + return NGX_ERROR; + } + + pipe_ctx->rest = len; + + cl = ngx_http_lua_chain_get_free_buf(ngx_cycle->log, pipe->pool, + &pipe->free_bufs, len); + if (cl == NULL) { + pipe_ctx->err_type = PIPE_ERR_NOMEM; + goto error; + } + + pipe_ctx->buf_in = cl; + b = pipe_ctx->buf_in->buf; + b->last = ngx_copy(b->last, data, len); + + rc = ngx_http_lua_pipe_write(pipe, pipe_ctx); + if (rc == NGX_ERROR) { + goto error; + } + + if (rc == NGX_OK) { + return len; + } + + /* rc == NGX_AGAIN */ + wait_co_ctx = ctx->cur_co_ctx; + pipe_ctx->c->data = wait_co_ctx; + + wev->handler = ngx_http_lua_pipe_resume_write_handler; + if (ngx_handle_write_event(wev, 0) != NGX_OK) { + pipe_ctx->err_type = PIPE_ERR_ADD_WRITE_EV; + goto error; + } + + wait_co_ctx->data = proc; + wait_co_ctx->cleanup = ngx_http_lua_pipe_proc_write_cleanup; + timeout = proc->write_timeout; + + if (timeout > 0) { + ngx_add_timer(wev, timeout); + ngx_log_debug5(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua pipe add timer for writing: %d(ms) process:%p " + "pid:%P pipe:%p ev:%p", timeout, proc, proc->_pid, pipe, + wev); + } + + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua pipe write yielding process:%p pid:%P pipe:%p", proc, + proc->_pid, pipe); + + return NGX_AGAIN; + +error: + + ngx_http_lua_pipe_put_error(pipe_ctx, errbuf, errbuf_size); + return NGX_ERROR; +} + + +/* + * ngx_http_lua_ffi_pipe_get_write_result should only be called just after + * ngx_http_lua_ffi_pipe_proc_write, so we omit most of the sanity check + * already done in ngx_http_lua_ffi_pipe_proc_write. + */ +ssize_t +ngx_http_lua_ffi_pipe_get_write_result(ngx_http_request_t *r, + ngx_http_lua_ffi_pipe_proc_t *proc, u_char *errbuf, size_t *errbuf_size) +{ + ngx_http_lua_pipe_t *pipe; + ngx_http_lua_pipe_ctx_t *pipe_ctx; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua pipe get write result process:%p pid:%P", proc, + proc->_pid); + + pipe = proc->pipe; + pipe_ctx = pipe->stdin_ctx; + + if (pipe_ctx->err_type) { + ngx_http_lua_pipe_put_error(pipe_ctx, errbuf, errbuf_size); + return NGX_ERROR; + } + + return pipe_ctx->rest; +} + + +int +ngx_http_lua_ffi_pipe_proc_wait(ngx_http_request_t *r, + ngx_http_lua_ffi_pipe_proc_t *proc, char **reason, int *status, + u_char *errbuf, size_t *errbuf_size) +{ + int rc; + ngx_rbtree_node_t *node; + ngx_http_lua_ctx_t *ctx; + ngx_http_lua_pipe_t *pipe; + ngx_http_lua_co_ctx_t *wait_co_ctx; + ngx_http_lua_pipe_node_t *pipe_node; + + rc = ngx_http_lua_pipe_get_lua_ctx(r, &ctx, errbuf, errbuf_size); + if (rc != NGX_OK) { + return rc; + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua pipe wait process:%p pid:%P", proc, proc->_pid); + + pipe = proc->pipe; + if (pipe == NULL || pipe->closed) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "exited") - errbuf; + return NGX_ERROR; + } + + node = pipe->node; + pipe_node = (ngx_http_lua_pipe_node_t *) &node->color; + if (pipe_node->wait_co_ctx) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "pipe busy waiting") + - errbuf; + return NGX_ERROR; + } + + if (pipe_node->reason_code == REASON_RUNNING_CODE) { + wait_co_ctx = ctx->cur_co_ctx; + wait_co_ctx->data = proc; + ngx_memzero(&wait_co_ctx->sleep, sizeof(ngx_event_t)); + wait_co_ctx->sleep.handler = ngx_http_lua_pipe_resume_wait_handler; + wait_co_ctx->sleep.data = wait_co_ctx; + wait_co_ctx->sleep.log = r->connection->log; + wait_co_ctx->cleanup = ngx_http_lua_pipe_proc_wait_cleanup; + + pipe_node->wait_co_ctx = wait_co_ctx; + + if (proc->wait_timeout > 0) { + ngx_add_timer(&wait_co_ctx->sleep, proc->wait_timeout); + ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua pipe add timer for waiting: %d(ms) process:%p " + "pid:%P ev:%p", proc->wait_timeout, proc, + proc->_pid, &wait_co_ctx->sleep); + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua pipe wait yielding process:%p pid:%P", proc, + proc->_pid); + + return NGX_AGAIN; + } + + *status = pipe_node->status; + + switch (pipe_node->reason_code) { + + case REASON_EXIT_CODE: + *reason = REASON_EXIT; + break; + + case REASON_SIGNAL_CODE: + *reason = REASON_SIGNAL; + break; + + default: + *reason = REASON_UNKNOWN; + } + + ngx_http_lua_pipe_proc_finalize(proc, 0); + + if (*status == 0) { + return NGX_OK; + } + + return NGX_DECLINED; +} + + +int +ngx_http_lua_ffi_pipe_proc_kill(ngx_http_lua_ffi_pipe_proc_t *proc, int signal, + u_char *errbuf, size_t *errbuf_size) +{ + ngx_pid_t pid; + ngx_http_lua_pipe_t *pipe; + + pipe = proc->pipe; + + if (pipe == NULL || pipe->dead) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "exited") - errbuf; + return NGX_ERROR; + } + + pid = proc->_pid; + + if (kill(pid, signal) == -1) { + switch (ngx_errno) { + case EINVAL: + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "invalid signal") + - errbuf; + break; + + case ESRCH: + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "exited") + - errbuf; + break; + + default: + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "%s", + strerror(ngx_errno)) + - errbuf; + } + + return NGX_ERROR; + } + + return NGX_OK; +} + + +static int +ngx_http_lua_pipe_read_stdout_retval(ngx_http_lua_ffi_pipe_proc_t *proc, + lua_State *L) +{ + return ngx_http_lua_pipe_read_retval_helper(proc, L, 0); +} + + +static int +ngx_http_lua_pipe_read_stderr_retval(ngx_http_lua_ffi_pipe_proc_t *proc, + lua_State *L) +{ + return ngx_http_lua_pipe_read_retval_helper(proc, L, 1); +} + + +static int +ngx_http_lua_pipe_read_retval_helper(ngx_http_lua_ffi_pipe_proc_t *proc, + lua_State *L, int from_stderr) +{ + int rc; + ngx_msec_t timeout; + ngx_event_t *rev; + ngx_http_lua_pipe_t *pipe; + ngx_http_lua_pipe_ctx_t *pipe_ctx; + + pipe = proc->pipe; + if (from_stderr) { + pipe_ctx = pipe->stderr_ctx; + + } else { + pipe_ctx = pipe->stdout_ctx; + } + + if (pipe->timeout) { + pipe->timeout = 0; + pipe_ctx->err_type = PIPE_ERR_TIMEOUT; + return 0; + } + + rc = ngx_http_lua_pipe_read(pipe, pipe_ctx); + if (rc != NGX_AGAIN) { + return 0; + } + + rev = pipe_ctx->c->read; + + if (from_stderr) { + rev->handler = ngx_http_lua_pipe_resume_read_stderr_handler; + timeout = proc->stderr_read_timeout; + + } else { + rev->handler = ngx_http_lua_pipe_resume_read_stdout_handler; + timeout = proc->stdout_read_timeout; + } + + if (timeout > 0) { + ngx_add_timer(rev, timeout); + ngx_log_debug5(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe add timer for reading: %d(ms) proc:%p " + "pid:%P pipe:%p ev:%p", timeout, proc, proc->_pid, pipe, + rev); + } + + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe read yielding process:%p pid:%P pipe:%p", proc, + proc->_pid, pipe); + + return NGX_AGAIN; +} + + +static int +ngx_http_lua_pipe_write_retval(ngx_http_lua_ffi_pipe_proc_t *proc, + lua_State *L) +{ + int rc; + ngx_msec_t timeout; + ngx_event_t *wev; + ngx_http_lua_pipe_t *pipe; + ngx_http_lua_pipe_ctx_t *pipe_ctx; + + pipe = proc->pipe; + pipe_ctx = pipe->stdin_ctx; + + if (pipe->timeout) { + pipe->timeout = 0; + pipe_ctx->err_type = PIPE_ERR_TIMEOUT; + return 0; + } + + rc = ngx_http_lua_pipe_write(pipe, pipe_ctx); + if (rc != NGX_AGAIN) { + return 0; + } + + wev = pipe_ctx->c->write; + wev->handler = ngx_http_lua_pipe_resume_write_handler; + timeout = proc->write_timeout; + + if (timeout > 0) { + ngx_add_timer(wev, timeout); + ngx_log_debug5(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe add timer for writing: %d(ms) proc:%p " + "pid:%P pipe:%p ev:%p", timeout, proc, proc->_pid, pipe, + wev); + } + + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe write yielding process:%p pid:%P pipe:%p", proc, + proc->_pid, pipe); + + return NGX_AGAIN; +} + + +static int +ngx_http_lua_pipe_wait_retval(ngx_http_lua_ffi_pipe_proc_t *proc, lua_State *L) +{ + int nret; + ngx_rbtree_node_t *node; + ngx_http_lua_pipe_t *pipe; + ngx_http_lua_pipe_node_t *pipe_node; + + pipe = proc->pipe; + node = pipe->node; + pipe_node = (ngx_http_lua_pipe_node_t *) &node->color; + pipe_node->wait_co_ctx = NULL; + + if (pipe->timeout) { + pipe->timeout = 0; + lua_pushnil(L); + lua_pushliteral(L, "timeout"); + return 2; + } + + ngx_http_lua_pipe_proc_finalize(pipe_node->proc, 0); + + if (pipe_node->status == 0) { + lua_pushboolean(L, 1); + lua_pushliteral(L, REASON_EXIT); + lua_pushinteger(L, pipe_node->status); + nret = 3; + + } else { + lua_pushboolean(L, 0); + + switch (pipe_node->reason_code) { + + case REASON_EXIT_CODE: + lua_pushliteral(L, REASON_EXIT); + break; + + case REASON_SIGNAL_CODE: + lua_pushliteral(L, REASON_SIGNAL); + break; + + default: + lua_pushliteral(L, REASON_UNKNOWN); + } + + lua_pushinteger(L, pipe_node->status); + nret = 3; + } + + return nret; +} + + +static void +ngx_http_lua_pipe_resume_helper(ngx_event_t *ev, + ngx_http_lua_co_ctx_t *wait_co_ctx) +{ + ngx_connection_t *c; + ngx_http_request_t *r; + ngx_http_lua_ctx_t *ctx; + ngx_http_lua_pipe_t *pipe; + ngx_http_lua_ffi_pipe_proc_t *proc; + + if (ev->timedout) { + proc = wait_co_ctx->data; + pipe = proc->pipe; + pipe->timeout = 1; + ev->timedout = 0; + } + + ngx_http_lua_pipe_clear_event(ev); + + r = ngx_http_lua_get_req(wait_co_ctx->co); + c = r->connection; + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + ngx_http_lua_assert(ctx != NULL); + + ctx->cur_co_ctx = wait_co_ctx; + + if (ctx->entered_content_phase) { + (void) ngx_http_lua_pipe_resume(r); + + } else { + ctx->resume_handler = ngx_http_lua_pipe_resume; + ngx_http_core_run_phases(r); + } + + ngx_http_run_posted_requests(c); +} + + +static void +ngx_http_lua_pipe_resume_read_stdout_handler(ngx_event_t *ev) +{ + ngx_connection_t *c = ev->data; + ngx_http_lua_co_ctx_t *wait_co_ctx; + ngx_http_lua_pipe_t *pipe; + ngx_http_lua_ffi_pipe_proc_t *proc; + + wait_co_ctx = c->data; + proc = wait_co_ctx->data; + pipe = proc->pipe; + pipe->retval_handler = ngx_http_lua_pipe_read_stdout_retval; + ngx_http_lua_pipe_resume_helper(ev, wait_co_ctx); +} + + +static void +ngx_http_lua_pipe_resume_read_stderr_handler(ngx_event_t *ev) +{ + ngx_connection_t *c = ev->data; + ngx_http_lua_co_ctx_t *wait_co_ctx; + ngx_http_lua_pipe_t *pipe; + ngx_http_lua_ffi_pipe_proc_t *proc; + + wait_co_ctx = c->data; + proc = wait_co_ctx->data; + pipe = proc->pipe; + pipe->retval_handler = ngx_http_lua_pipe_read_stderr_retval; + ngx_http_lua_pipe_resume_helper(ev, wait_co_ctx); +} + + +static void +ngx_http_lua_pipe_resume_write_handler(ngx_event_t *ev) +{ + ngx_connection_t *c = ev->data; + ngx_http_lua_co_ctx_t *wait_co_ctx; + ngx_http_lua_pipe_t *pipe; + ngx_http_lua_ffi_pipe_proc_t *proc; + + wait_co_ctx = c->data; + proc = wait_co_ctx->data; + pipe = proc->pipe; + pipe->retval_handler = ngx_http_lua_pipe_write_retval; + ngx_http_lua_pipe_resume_helper(ev, wait_co_ctx); +} + + +static void +ngx_http_lua_pipe_resume_wait_handler(ngx_event_t *ev) +{ + ngx_http_lua_co_ctx_t *wait_co_ctx = ev->data; + ngx_http_lua_pipe_t *pipe; + ngx_http_lua_ffi_pipe_proc_t *proc; + + proc = wait_co_ctx->data; + pipe = proc->pipe; + pipe->retval_handler = ngx_http_lua_pipe_wait_retval; + ngx_http_lua_pipe_resume_helper(ev, wait_co_ctx); +} + + +static ngx_int_t +ngx_http_lua_pipe_resume(ngx_http_request_t *r) +{ + int nret; + lua_State *vm; + ngx_int_t rc; + ngx_uint_t nreqs; + ngx_connection_t *c; + ngx_http_lua_ctx_t *ctx; + ngx_http_lua_pipe_t *pipe; + ngx_http_lua_ffi_pipe_proc_t *proc; + + 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; + ctx->cur_co_ctx->cleanup = NULL; + + proc = ctx->cur_co_ctx->data; + pipe = proc->pipe; + nret = pipe->retval_handler(proc, ctx->cur_co_ctx->co); + if (nret == NGX_AGAIN) { + return NGX_DONE; + } + + c = r->connection; + vm = ngx_http_lua_get_lua_vm(r, ctx); + nreqs = c->requests; + + rc = ngx_http_lua_run_thread(vm, r, ctx, nret); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua run thread returned %d", rc); + + if (rc == NGX_AGAIN) { + return ngx_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); + } + + /* rc == NGX_ERROR || rc >= NGX_OK */ + + if (ctx->entered_content_phase) { + ngx_http_lua_finalize_request(r, rc); + return NGX_DONE; + } + + return rc; +} + + +static void +ngx_http_lua_pipe_dummy_event_handler(ngx_event_t *ev) +{ + /* do nothing */ +} + + +static void +ngx_http_lua_pipe_clear_event(ngx_event_t *ev) +{ + ev->handler = ngx_http_lua_pipe_dummy_event_handler; + + if (ev->timer_set) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ev->log, 0, + "lua pipe del timer for ev:%p", ev); + ngx_del_timer(ev); + } + + if (ev->posted) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ev->log, 0, + "lua pipe del posted event for ev:%p", ev); + ngx_delete_posted_event(ev); + } +} + + +static void +ngx_http_lua_pipe_proc_read_stdout_cleanup(void *data) +{ + ngx_event_t *rev; + ngx_connection_t *c; + ngx_http_lua_co_ctx_t *wait_co_ctx = data; + ngx_http_lua_ffi_pipe_proc_t *proc; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe proc read stdout cleanup"); + + proc = wait_co_ctx->data; + c = proc->pipe->stdout_ctx->c; + if (c) { + rev = c->read; + ngx_http_lua_pipe_clear_event(rev); + } + + wait_co_ctx->cleanup = NULL; +} + + +static void +ngx_http_lua_pipe_proc_read_stderr_cleanup(void *data) +{ + ngx_event_t *rev; + ngx_connection_t *c; + ngx_http_lua_co_ctx_t *wait_co_ctx = data; + ngx_http_lua_ffi_pipe_proc_t *proc; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe proc read stderr cleanup"); + + proc = wait_co_ctx->data; + c = proc->pipe->stderr_ctx->c; + if (c) { + rev = c->read; + ngx_http_lua_pipe_clear_event(rev); + } + + wait_co_ctx->cleanup = NULL; +} + + +static void +ngx_http_lua_pipe_proc_write_cleanup(void *data) +{ + ngx_event_t *wev; + ngx_connection_t *c; + ngx_http_lua_co_ctx_t *wait_co_ctx = data; + ngx_http_lua_ffi_pipe_proc_t *proc; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe proc write cleanup"); + + proc = wait_co_ctx->data; + c = proc->pipe->stdin_ctx->c; + if (c) { + wev = c->write; + ngx_http_lua_pipe_clear_event(wev); + } + + wait_co_ctx->cleanup = NULL; +} + + +static void +ngx_http_lua_pipe_proc_wait_cleanup(void *data) +{ + ngx_rbtree_node_t *node; + ngx_http_lua_co_ctx_t *wait_co_ctx = data; + ngx_http_lua_pipe_node_t *pipe_node; + ngx_http_lua_ffi_pipe_proc_t *proc; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua pipe proc wait cleanup"); + + proc = wait_co_ctx->data; + node = proc->pipe->node; + pipe_node = (ngx_http_lua_pipe_node_t *) &node->color; + pipe_node->wait_co_ctx = NULL; + + ngx_http_lua_pipe_clear_event(&wait_co_ctx->sleep); + + wait_co_ctx->cleanup = NULL; +} + + +#endif /* HAVE_NGX_LUA_PIPE */ + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_pipe.h b/debian/modules/http-lua/src/ngx_http_lua_pipe.h new file mode 100644 index 0000000..b5cea89 --- /dev/null +++ b/debian/modules/http-lua/src/ngx_http_lua_pipe.h @@ -0,0 +1,95 @@ + +/* + * Copyright (C) by OpenResty Inc. + */ + + +#ifndef _NGX_HTTP_LUA_PIPE_H_INCLUDED_ +#define _NGX_HTTP_LUA_PIPE_H_INCLUDED_ + + +#include "ngx_http_lua_common.h" + + +typedef ngx_int_t (*ngx_http_lua_pipe_input_filter)(void *data, ssize_t bytes); + + +typedef struct { + ngx_connection_t *c; + ngx_http_lua_pipe_input_filter input_filter; + void *input_filter_ctx; + size_t rest; + ngx_chain_t *buf_in; + ngx_chain_t *bufs_in; + ngx_buf_t buffer; + ngx_err_t pipe_errno; + unsigned err_type:16; + unsigned eof:1; +} ngx_http_lua_pipe_ctx_t; + + +typedef struct ngx_http_lua_pipe_s ngx_http_lua_pipe_t; + + +typedef struct { + ngx_pid_t _pid; + ngx_msec_t write_timeout; + ngx_msec_t stdout_read_timeout; + ngx_msec_t stderr_read_timeout; + ngx_msec_t wait_timeout; + /* pipe hides the implementation from the Lua binding */ + ngx_http_lua_pipe_t *pipe; +} ngx_http_lua_ffi_pipe_proc_t; + + +typedef int (*ngx_http_lua_pipe_retval_handler)( + ngx_http_lua_ffi_pipe_proc_t *proc, lua_State *L); + + +struct ngx_http_lua_pipe_s { + ngx_pool_t *pool; + ngx_chain_t *free_bufs; + ngx_rbtree_node_t *node; + int stdin_fd; + int stdout_fd; + int stderr_fd; + ngx_http_lua_pipe_ctx_t *stdin_ctx; + ngx_http_lua_pipe_ctx_t *stdout_ctx; + ngx_http_lua_pipe_ctx_t *stderr_ctx; + ngx_http_lua_pipe_retval_handler retval_handler; + size_t buffer_size; + unsigned closed:1; + unsigned dead:1; + unsigned timeout:1; + unsigned merge_stderr:1; +}; + + +typedef struct { + u_char color; + u_char reason_code; + int status; + ngx_http_lua_co_ctx_t *wait_co_ctx; + ngx_http_lua_ffi_pipe_proc_t *proc; +} ngx_http_lua_pipe_node_t; + + +typedef struct { + int signo; + char *signame; +} ngx_http_lua_pipe_signal_t; + + +#if !(NGX_WIN32) && !defined(NGX_LUA_NO_FFI_API) \ + && defined(HAVE_SOCKET_CLOEXEC_PATCH) +#define HAVE_NGX_LUA_PIPE 1 + + +void ngx_http_lua_pipe_init(void); +ngx_int_t ngx_http_lua_pipe_add_signal_handler(ngx_cycle_t *cycle); +#endif + + +#endif /* _NGX_HTTP_LUA_PIPE_H_INCLUDED_ */ + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_regex.c b/debian/modules/http-lua/src/ngx_http_lua_regex.c index 843d1e4..8f3373b 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_regex.c +++ b/debian/modules/http-lua/src/ngx_http_lua_regex.c @@ -15,7 +15,6 @@ #include "ngx_http_lua_regex.h" #include "ngx_http_lua_pcrefix.h" #include "ngx_http_lua_script.h" -#include "ngx_http_lua_pcrefix.h" #include "ngx_http_lua_util.h" @@ -249,7 +248,8 @@ ngx_http_lua_ngx_re_match_helper(lua_State *L, int wantcaps) dd("server pool %p", lmcf->pool); - lua_pushlightuserdata(L, &ngx_http_lua_regex_cache_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + regex_cache_key)); lua_rawget(L, LUA_REGISTRYINDEX); /* table */ lua_pushliteral(L, "m"); @@ -720,7 +720,8 @@ ngx_http_lua_ngx_re_gmatch(lua_State *L) dd("server pool %p", lmcf->pool); - lua_pushlightuserdata(L, &ngx_http_lua_regex_cache_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + regex_cache_key)); lua_rawget(L, LUA_REGISTRYINDEX); /* table */ lua_pushliteral(L, "m"); @@ -1388,7 +1389,8 @@ ngx_http_lua_ngx_re_sub_helper(lua_State *L, unsigned global) dd("server pool %p", lmcf->pool); - lua_pushlightuserdata(L, &ngx_http_lua_regex_cache_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + regex_cache_key)); lua_rawget(L, LUA_REGISTRYINDEX); /* table */ lua_pushliteral(L, "s"); diff --git a/debian/modules/http-lua/src/ngx_http_lua_rewriteby.c b/debian/modules/http-lua/src/ngx_http_lua_rewriteby.c index 1bbe87c..1de9968 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_rewriteby.c +++ b/debian/modules/http-lua/src/ngx_http_lua_rewriteby.c @@ -62,7 +62,7 @@ ngx_http_lua_rewrite_handler(ngx_http_request_t *r) #endif if (cur_ph < last_ph) { - dd("swaping the contents of cur_ph and last_ph..."); + dd("swapping the contents of cur_ph and last_ph..."); tmp = *cur_ph; @@ -261,9 +261,11 @@ ngx_http_lua_rewrite_by_chunk(lua_State *L, ngx_http_request_t *r) /* 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); diff --git a/debian/modules/http-lua/src/ngx_http_lua_script.c b/debian/modules/http-lua/src/ngx_http_lua_script.c index 95ebadf..c675a16 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_script.c +++ b/debian/modules/http-lua/src/ngx_http_lua_script.c @@ -329,7 +329,7 @@ ngx_http_lua_script_add_copy_code(ngx_http_lua_script_compile_t *sc, return NGX_ERROR; } - code->code = (ngx_http_lua_script_code_pt) + code->code = (ngx_http_lua_script_code_pt) (void *) ngx_http_lua_script_copy_len_code; code->len = len; @@ -399,7 +399,7 @@ ngx_http_lua_script_add_capture_code(ngx_http_lua_script_compile_t *sc, return NGX_ERROR; } - code->code = (ngx_http_lua_script_code_pt) + code->code = (ngx_http_lua_script_code_pt) (void *) ngx_http_lua_script_copy_capture_len_code; code->n = 2 * n; diff --git a/debian/modules/http-lua/src/ngx_http_lua_setby.c b/debian/modules/http-lua/src/ngx_http_lua_setby.c index 2e8762a..d4288b5 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_setby.c +++ b/debian/modules/http-lua/src/ngx_http_lua_setby.c @@ -30,13 +30,6 @@ static void ngx_http_lua_set_by_lua_env(lua_State *L, ngx_http_request_t *r, size_t nargs, ngx_http_variable_value_t *args); -/* keys in Lua thread for fetching args and nargs in set_by_lua* */ - -#define ngx_http_lua_nargs_key "__ngx_nargs" - -#define ngx_http_lua_args_key "__ngx_args" - - ngx_int_t 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) @@ -134,23 +127,24 @@ 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_lua_setby_param_get(lua_State *L, ngx_http_request_t *r) { int idx; int n; ngx_http_variable_value_t *v; + ngx_http_lua_main_conf_t *lmcf; idx = luaL_checkint(L, 2); idx--; - /* get number of args from globals */ - lua_getglobal(L, ngx_http_lua_nargs_key); - n = (int) lua_tointeger(L, -1); + lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); - /* get args from globals */ - lua_getglobal(L, ngx_http_lua_args_key); - v = lua_touserdata(L, -1); + /* get number of args from lmcf */ + n = lmcf->setby_nargs; + + /* get args from lmcf */ + v = lmcf->setby_args; if (idx < 0 || idx > n - 1) { lua_pushnil(L); @@ -178,15 +172,16 @@ static void ngx_http_lua_set_by_lua_env(lua_State *L, ngx_http_request_t *r, size_t nargs, ngx_http_variable_value_t *args) { - /* set nginx request pointer to current lua thread's globals table */ + ngx_http_lua_main_conf_t *lmcf; + ngx_http_lua_set_req(L, r); - lua_pushinteger(L, nargs); - lua_setglobal(L, ngx_http_lua_nargs_key); + lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); - lua_pushlightuserdata(L, args); - lua_setglobal(L, ngx_http_lua_args_key); + lmcf->setby_nargs = nargs; + lmcf->setby_args = args; +#ifndef OPENRESTY_LUAJIT /** * we want to create empty environment for current script * @@ -211,6 +206,7 @@ ngx_http_lua_set_by_lua_env(lua_State *L, ngx_http_request_t *r, size_t nargs, /* }}} */ lua_setfenv(L, -2); /* set new running env for the code closure */ +#endif } /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_setby.h b/debian/modules/http-lua/src/ngx_http_lua_setby.h index da71753..f43eef7 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_setby.h +++ b/debian/modules/http-lua/src/ngx_http_lua_setby.h @@ -7,7 +7,7 @@ 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); +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/debian/modules/http-lua/src/ngx_http_lua_shdict.c b/debian/modules/http-lua/src/ngx_http_lua_shdict.c index 5fb7930..b017bea 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_shdict.c +++ b/debian/modules/http-lua/src/ngx_http_lua_shdict.c @@ -325,6 +325,7 @@ ngx_http_lua_inject_shdict_api(ngx_http_lua_main_conf_t *lmcf, lua_State *L) ngx_http_lua_shdict_ctx_t *ctx; ngx_uint_t i; ngx_shm_zone_t **zone; + ngx_shm_zone_t **zone_udata; if (lmcf->shdict_zones != NULL) { lua_createtable(L, 0, lmcf->shdict_zones->nelts /* nrec */); @@ -396,7 +397,9 @@ ngx_http_lua_inject_shdict_api(ngx_http_lua_main_conf_t *lmcf, lua_State *L) lua_createtable(L, 1 /* narr */, 0 /* nrec */); /* table of zone[i] */ - lua_pushlightuserdata(L, zone[i]); /* shared mt key ud */ + zone_udata = lua_newuserdata(L, sizeof(ngx_shm_zone_t *)); + /* shared mt key ud */ + *zone_udata = zone[i]; lua_rawseti(L, -2, SHDICT_USERDATA_INDEX); /* {zone[i]} */ lua_pushvalue(L, -3); /* shared mt key ud mt */ lua_setmetatable(L, -2); /* shared mt key ud */ @@ -431,11 +434,17 @@ static ngx_inline ngx_shm_zone_t * ngx_http_lua_shdict_get_zone(lua_State *L, int index) { ngx_shm_zone_t *zone; + ngx_shm_zone_t **zone_udata; lua_rawgeti(L, index, SHDICT_USERDATA_INDEX); - zone = lua_touserdata(L, -1); + zone_udata = lua_touserdata(L, -1); lua_pop(L, 1); + if (zone_udata == NULL) { + return NULL; + } + + zone = *zone_udata; return zone; } @@ -2209,6 +2218,17 @@ ngx_http_lua_find_zone(u_char *name_data, size_t name_len) #ifndef NGX_LUA_NO_FFI_API +ngx_shm_zone_t * +ngx_http_lua_ffi_shdict_udata_to_zone(void *zone_udata) +{ + if (zone_udata == NULL) { + return NULL; + } + + return *(ngx_shm_zone_t **) zone_udata; +} + + int ngx_http_lua_ffi_shdict_store(ngx_shm_zone_t *zone, int op, u_char *key, size_t key_len, int value_type, u_char *str_value_buf, @@ -2225,10 +2245,6 @@ ngx_http_lua_ffi_shdict_store(ngx_shm_zone_t *zone, int op, u_char *key, ngx_http_lua_shdict_ctx_t *ctx; ngx_http_lua_shdict_node_t *sd; - if (zone == NULL) { - return NGX_ERROR; - } - dd("exptime: %ld", exptime); ctx = zone->data; @@ -2490,10 +2506,6 @@ ngx_http_lua_ffi_shdict_get(ngx_shm_zone_t *zone, u_char *key, ngx_http_lua_shdict_node_t *sd; ngx_str_t value; - if (zone == NULL) { - return NGX_ERROR; - } - *err = NULL; ctx = zone->data; @@ -2636,10 +2648,6 @@ ngx_http_lua_ffi_shdict_incr(ngx_shm_zone_t *zone, u_char *key, u_char *p; ngx_queue_t *queue, *q; - if (zone == NULL) { - return NGX_ERROR; - } - if (init_ttl > 0) { tp = ngx_timeofday(); } @@ -2915,10 +2923,6 @@ ngx_http_lua_ffi_shdict_get_ttl(ngx_shm_zone_t *zone, u_char *key, ngx_http_lua_shdict_ctx_t *ctx; ngx_http_lua_shdict_node_t *sd; - if (zone == NULL) { - return NGX_ERROR; - } - ctx = zone->data; hash = ngx_crc32_short(key, key_len); @@ -2959,10 +2963,6 @@ ngx_http_lua_ffi_shdict_set_expire(ngx_shm_zone_t *zone, u_char *key, ngx_http_lua_shdict_ctx_t *ctx; ngx_http_lua_shdict_node_t *sd; - if (zone == NULL) { - return NGX_ERROR; - } - if (exptime > 0) { tp = ngx_timeofday(); } diff --git a/debian/modules/http-lua/src/ngx_http_lua_socket_tcp.c b/debian/modules/http-lua/src/ngx_http_lua_socket_tcp.c index efdf427..87461e6 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_socket_tcp.c +++ b/debian/modules/http-lua/src/ngx_http_lua_socket_tcp.c @@ -11,6 +11,7 @@ #include "ngx_http_lua_socket_tcp.h" +#include "ngx_http_lua_input_filters.h" #include "ngx_http_lua_util.h" #include "ngx_http_lua_uthread.h" #include "ngx_http_lua_output.h" @@ -24,6 +25,7 @@ static int ngx_http_lua_socket_tcp_connect(lua_State *L); static int ngx_http_lua_socket_tcp_sslhandshake(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); static int ngx_http_lua_socket_tcp_send(lua_State *L); static int ngx_http_lua_socket_tcp_close(lua_State *L); static int ngx_http_lua_socket_tcp_setoption(lua_State *L); @@ -69,6 +71,8 @@ static int ngx_http_lua_socket_tcp_conn_retval_handler(ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u, lua_State *L); 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 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, @@ -86,6 +90,7 @@ static int ngx_http_lua_socket_write_error_retval_handler(ngx_http_request_t *r, static ngx_int_t ngx_http_lua_socket_read_all(void *data, ssize_t bytes); static ngx_int_t ngx_http_lua_socket_read_until(void *data, ssize_t bytes); static ngx_int_t ngx_http_lua_socket_read_chunk(void *data, ssize_t bytes); +static ngx_int_t ngx_http_lua_socket_read_any(void *data, ssize_t bytes); static int ngx_http_lua_socket_tcp_receiveuntil(lua_State *L); static int ngx_http_lua_socket_receiveuntil_iterator(lua_State *L); static ngx_int_t ngx_http_lua_socket_compile_pattern(u_char *data, size_t len, @@ -95,12 +100,28 @@ static int ngx_http_lua_req_socket(lua_State *L); static void ngx_http_lua_req_socket_rev_handler(ngx_http_request_t *r); static int ngx_http_lua_socket_tcp_getreusedtimes(lua_State *L); static int ngx_http_lua_socket_tcp_setkeepalive(lua_State *L); +static void ngx_http_lua_socket_tcp_create_socket_pool(lua_State *L, + ngx_http_request_t *r, ngx_str_t key, ngx_int_t pool_size, + ngx_int_t backlog, ngx_http_lua_socket_pool_t **spool); static ngx_int_t ngx_http_lua_get_keepalive_peer(ngx_http_request_t *r, - lua_State *L, int key_index, ngx_http_lua_socket_tcp_upstream_t *u); static void ngx_http_lua_socket_keepalive_dummy_handler(ngx_event_t *ev); +static int ngx_http_lua_socket_tcp_connect_helper(lua_State *L, + ngx_http_lua_socket_tcp_upstream_t *u, ngx_http_request_t *r, + ngx_http_lua_ctx_t *ctx, u_char *host_ref, size_t host_len, in_port_t port, + unsigned resuming); +static void ngx_http_lua_socket_tcp_conn_op_timeout_handler( + ngx_event_t *ev); +static int ngx_http_lua_socket_tcp_conn_op_timeout_retval_handler( + ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u, lua_State *L); +static void ngx_http_lua_socket_tcp_resume_conn_op( + ngx_http_lua_socket_pool_t *spool); +static void ngx_http_lua_socket_tcp_conn_op_ctx_cleanup(void *data); +static void ngx_http_lua_socket_tcp_conn_op_resume_handler(ngx_event_t *ev); static ngx_int_t ngx_http_lua_socket_keepalive_close_handler(ngx_event_t *ev); static void ngx_http_lua_socket_keepalive_rev_handler(ngx_event_t *ev); +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, @@ -113,11 +134,13 @@ static ngx_int_t ngx_http_lua_socket_add_input_buffer(ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u); static ngx_int_t ngx_http_lua_socket_insert_buffer(ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u, u_char *pat, size_t prefix); +static ngx_int_t ngx_http_lua_socket_tcp_conn_op_resume(ngx_http_request_t *r); static ngx_int_t ngx_http_lua_socket_tcp_conn_resume(ngx_http_request_t *r); static ngx_int_t ngx_http_lua_socket_tcp_read_resume(ngx_http_request_t *r); static ngx_int_t ngx_http_lua_socket_tcp_write_resume(ngx_http_request_t *r); static ngx_int_t ngx_http_lua_socket_tcp_resume_helper(ngx_http_request_t *r, int socket_op); +static void ngx_http_lua_tcp_queue_conn_op_cleanup(void *data); static void ngx_http_lua_tcp_resolve_cleanup(void *data); static void ngx_http_lua_coctx_cleanup(void *data); static void ngx_http_lua_socket_free_pool(ngx_log_t *log, @@ -150,7 +173,8 @@ enum { enum { SOCKET_OP_CONNECT, SOCKET_OP_READ, - SOCKET_OP_WRITE + SOCKET_OP_WRITE, + SOCKET_OP_RESUME_CONN }; @@ -229,7 +253,8 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) lua_setfield(L, -2, "socket"); /* {{{req socket object metatable */ - lua_pushlightuserdata(L, &ngx_http_lua_req_socket_metatable_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + req_socket_metatable_key)); lua_createtable(L, 0 /* narr */, 5 /* nrec */); lua_pushcfunction(L, ngx_http_lua_socket_tcp_receive); @@ -251,7 +276,8 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) /* }}} */ /* {{{raw req socket object metatable */ - lua_pushlightuserdata(L, &ngx_http_lua_raw_req_socket_metatable_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + raw_req_socket_metatable_key)); lua_createtable(L, 0 /* narr */, 6 /* nrec */); lua_pushcfunction(L, ngx_http_lua_socket_tcp_receive); @@ -276,7 +302,8 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) /* }}} */ /* {{{tcp object metatable */ - lua_pushlightuserdata(L, &ngx_http_lua_tcp_socket_metatable_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + tcp_socket_metatable_key)); lua_createtable(L, 0 /* narr */, 12 /* nrec */); lua_pushcfunction(L, ngx_http_lua_socket_tcp_connect); @@ -292,6 +319,9 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) lua_pushcfunction(L, ngx_http_lua_socket_tcp_receive); lua_setfield(L, -2, "receive"); + lua_pushcfunction(L, ngx_http_lua_socket_tcp_receiveany); + lua_setfield(L, -2, "receiveany"); + lua_pushcfunction(L, ngx_http_lua_socket_tcp_receiveuntil); lua_setfield(L, -2, "receiveuntil"); @@ -322,7 +352,8 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) /* }}} */ /* {{{upstream userdata metatable */ - lua_pushlightuserdata(L, &ngx_http_lua_upstream_udata_metatable_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + upstream_udata_metatable_key)); lua_createtable(L, 0 /* narr */, 1 /* nrec */); /* metatable */ lua_pushcfunction(L, ngx_http_lua_socket_tcp_upstream_destroy); lua_setfield(L, -2, "__gc"); @@ -330,7 +361,8 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) /* }}} */ /* {{{downstream userdata metatable */ - lua_pushlightuserdata(L, &ngx_http_lua_downstream_udata_metatable_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + downstream_udata_metatable_key)); lua_createtable(L, 0 /* narr */, 1 /* nrec */); /* metatable */ lua_pushcfunction(L, ngx_http_lua_socket_downstream_destroy); lua_setfield(L, -2, "__gc"); @@ -338,7 +370,8 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) /* }}} */ /* {{{socket pool userdata metatable */ - lua_pushlightuserdata(L, &ngx_http_lua_pool_udata_metatable_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + pool_udata_metatable_key)); lua_createtable(L, 0, 1); /* metatable */ lua_pushcfunction(L, ngx_http_lua_socket_shutdown_pool); lua_setfield(L, -2, "__gc"); @@ -346,7 +379,8 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) /* }}} */ /* {{{socket compiled pattern userdata metatable */ - lua_pushlightuserdata(L, &ngx_http_lua_pattern_udata_metatable_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + pattern_udata_metatable_key)); lua_createtable(L, 0 /* narr */, 1 /* nrec */); /* metatable */ lua_pushcfunction(L, ngx_http_lua_socket_cleanup_compiled_pattern); lua_setfield(L, -2, "__gc"); @@ -356,7 +390,8 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) #if (NGX_HTTP_SSL) /* {{{ssl session userdata metatable */ - lua_pushlightuserdata(L, &ngx_http_lua_ssl_session_metatable_key); + 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"); @@ -404,7 +439,8 @@ ngx_http_lua_socket_tcp(lua_State *L) | NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH); lua_createtable(L, 5 /* narr */, 1 /* nrec */); - lua_pushlightuserdata(L, &ngx_http_lua_tcp_socket_metatable_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + tcp_socket_metatable_key)); lua_rawget(L, LUA_REGISTRYINDEX); lua_setmetatable(L, -2); @@ -414,31 +450,421 @@ ngx_http_lua_socket_tcp(lua_State *L) } +static void +ngx_http_lua_socket_tcp_create_socket_pool(lua_State *L, ngx_http_request_t *r, + ngx_str_t key, ngx_int_t pool_size, ngx_int_t backlog, + ngx_http_lua_socket_pool_t **spool) +{ + u_char *p; + size_t size, key_len; + ngx_int_t i; + ngx_http_lua_socket_pool_t *sp; + ngx_http_lua_socket_pool_item_t *items; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua tcp socket connection pool size: %i, backlog: %i", + pool_size, backlog); + + key_len = ngx_align(key.len + 1, sizeof(void *)); + + size = sizeof(ngx_http_lua_socket_pool_t) - 1 + key_len + + sizeof(ngx_http_lua_socket_pool_item_t) * pool_size; + + /* before calling this function, the Lua stack is: + * -1 key + * -2 pools + */ + sp = lua_newuserdata(L, size); + if (sp == NULL) { + luaL_error(L, "no memory"); + return; + } + + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + pool_udata_metatable_key)); + lua_rawget(L, LUA_REGISTRYINDEX); + lua_setmetatable(L, -2); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua tcp socket keepalive create connection pool for key" + " \"%V\"", &key); + + /* a new socket pool with metatable is push to the stack, so now we have: + * -1 sp + * -2 key + * -3 pools + * + * it is time to set pools[key] to sp. + */ + lua_rawset(L, -3); + + /* clean up the stack for consistency's sake */ + lua_pop(L, 1); + + sp->backlog = backlog; + sp->size = pool_size; + sp->connections = 0; + sp->lua_vm = ngx_http_lua_get_lua_vm(r, NULL); + + ngx_queue_init(&sp->cache_connect_op); + ngx_queue_init(&sp->wait_connect_op); + ngx_queue_init(&sp->cache); + ngx_queue_init(&sp->free); + + p = ngx_copy(sp->key, key.data, key.len); + *p++ = '\0'; + + items = (ngx_http_lua_socket_pool_item_t *) (sp->key + key_len); + + dd("items: %p", items); + + ngx_http_lua_assert((void *) items == ngx_align_ptr(items, sizeof(void *))); + + for (i = 0; i < pool_size; i++) { + ngx_queue_insert_head(&sp->free, &items[i].queue); + items[i].socket_pool = sp; + } + + *spool = sp; +} + + +static int +ngx_http_lua_socket_tcp_connect_helper(lua_State *L, + ngx_http_lua_socket_tcp_upstream_t *u, ngx_http_request_t *r, + ngx_http_lua_ctx_t *ctx, u_char *host_ref, size_t host_len, in_port_t port, + unsigned resuming) +{ + int n; + int host_size; + int saved_top; + ngx_int_t rc; + ngx_str_t host; + ngx_str_t *conn_op_host; + ngx_url_t url; + ngx_queue_t *q; + ngx_resolver_ctx_t *rctx, temp; + ngx_http_lua_co_ctx_t *coctx; + ngx_http_core_loc_conf_t *clcf; + ngx_http_lua_socket_pool_t *spool; + ngx_http_lua_socket_tcp_conn_op_ctx_t *conn_op_ctx; + + spool = u->socket_pool; + if (spool != NULL) { + rc = ngx_http_lua_get_keepalive_peer(r, u); + + if (rc == NGX_OK) { + lua_pushinteger(L, 1); + return 1; + } + + /* rc == NGX_DECLINED */ + + spool->connections++; + + /* check if backlog is enabled and + * don't queue resuming connection operation */ + if (spool->backlog >= 0 && !resuming) { + + dd("lua tcp socket %s connections %ld", + spool->key, spool->connections); + + if (spool->connections > spool->size + spool->backlog) { + spool->connections--; + lua_pushnil(L); + lua_pushliteral(L, "too many waiting connect operations"); + return 2; + } + + if (spool->connections > spool->size) { + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, u->peer.log, 0, + "lua tcp socket queue connect operation for " + "connection pool \"%s\", connections: %i", + spool->key, spool->connections); + + host_size = sizeof(u_char) * + (ngx_max(host_len, NGX_INET_ADDRSTRLEN) + 1); + + if (!ngx_queue_empty(&spool->cache_connect_op)) { + q = ngx_queue_last(&spool->cache_connect_op); + ngx_queue_remove(q); + conn_op_ctx = ngx_queue_data( + q, ngx_http_lua_socket_tcp_conn_op_ctx_t, queue); + + conn_op_host = &conn_op_ctx->host; + if (host_len > conn_op_host->len + && host_len > NGX_INET_ADDRSTRLEN) + { + ngx_free(conn_op_host->data); + conn_op_host->data = ngx_alloc(host_size, + ngx_cycle->log); + if (conn_op_host->data == NULL) { + ngx_free(conn_op_ctx); + goto no_memory_and_not_resuming; + } + } + + } else { + conn_op_ctx = ngx_alloc( + sizeof(ngx_http_lua_socket_tcp_conn_op_ctx_t), + ngx_cycle->log); + if (conn_op_ctx == NULL) { + goto no_memory_and_not_resuming; + } + + conn_op_host = &conn_op_ctx->host; + conn_op_host->data = ngx_alloc(host_size, ngx_cycle->log); + if (conn_op_host->data == NULL) { + ngx_free(conn_op_ctx); + goto no_memory_and_not_resuming; + } + } + + conn_op_ctx->cleanup = NULL; + + ngx_memcpy(conn_op_host->data, host_ref, host_len); + conn_op_host->data[host_len] = '\0'; + conn_op_host->len = host_len; + + conn_op_ctx->port = port; + + u->write_co_ctx = ctx->cur_co_ctx; + + conn_op_ctx->u = u; + ctx->cur_co_ctx->cleanup = + ngx_http_lua_tcp_queue_conn_op_cleanup; + ctx->cur_co_ctx->data = conn_op_ctx; + + ngx_memzero(&conn_op_ctx->event, sizeof(ngx_event_t)); + conn_op_ctx->event.handler = + ngx_http_lua_socket_tcp_conn_op_timeout_handler; + conn_op_ctx->event.data = conn_op_ctx; + conn_op_ctx->event.log = ngx_cycle->log; + + ngx_add_timer(&conn_op_ctx->event, u->connect_timeout); + + ngx_queue_insert_tail(&spool->wait_connect_op, + &conn_op_ctx->queue); + + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua tcp socket queued connect operation for " + "%d(ms), u: %p, ctx: %p", + u->connect_timeout, conn_op_ctx->u, conn_op_ctx); + + return lua_yield(L, 0); + } + } + + } /* end spool != NULL */ + + host.data = ngx_palloc(r->pool, host_len + 1); + if (host.data == NULL) { + return luaL_error(L, "no memory"); + } + + host.len = host_len; + + ngx_memcpy(host.data, host_ref, host_len); + host.data[host_len] = '\0'; + + ngx_memzero(&url, sizeof(ngx_url_t)); + url.url = host; + url.default_port = port; + url.no_resolve = 1; + + coctx = ctx->cur_co_ctx; + + if (ngx_parse_url(r->pool, &url) != NGX_OK) { + lua_pushnil(L); + + if (url.err) { + lua_pushfstring(L, "failed to parse host name \"%s\": %s", + url.url.data, url.err); + + } else { + lua_pushfstring(L, "failed to parse host name \"%s\"", + url.url.data); + } + + goto failed; + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua tcp socket connect timeout: %M", u->connect_timeout); + + u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t)); + if (u->resolved == NULL) { + if (resuming) { + lua_pushnil(L); + lua_pushliteral(L, "no memory"); + goto failed; + } + + goto no_memory_and_not_resuming; + } + + if (url.addrs && url.addrs[0].sockaddr) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua tcp socket network address given directly"); + + u->resolved->sockaddr = url.addrs[0].sockaddr; + u->resolved->socklen = url.addrs[0].socklen; + u->resolved->naddrs = 1; + u->resolved->host = url.addrs[0].name; + + } else { + u->resolved->host = host; + u->resolved->port = url.default_port; + } + + if (u->resolved->sockaddr) { + rc = ngx_http_lua_socket_resolve_retval_handler(r, u, L); + if (rc == NGX_AGAIN && !resuming) { + return lua_yield(L, 0); + } + + if (rc > 1) { + goto failed; + } + + return rc; + } + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + temp.name = host; + rctx = ngx_resolve_start(clcf->resolver, &temp); + if (rctx == NULL) { + u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_RESOLVER; + lua_pushnil(L); + lua_pushliteral(L, "failed to start the resolver"); + goto failed; + } + + if (rctx == NGX_NO_RESOLVER) { + u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_RESOLVER; + lua_pushnil(L); + lua_pushfstring(L, "no resolver defined to resolve \"%s\"", host.data); + goto failed; + } + + rctx->name = host; +#if !defined(nginx_version) || nginx_version < 1005008 + rctx->type = NGX_RESOLVE_A; +#endif + rctx->handler = ngx_http_lua_socket_resolve_handler; + rctx->data = u; + rctx->timeout = clcf->resolver_timeout; + + u->resolved->ctx = rctx; + u->write_co_ctx = ctx->cur_co_ctx; + + ngx_http_lua_cleanup_pending_operation(coctx); + coctx->cleanup = ngx_http_lua_tcp_resolve_cleanup; + coctx->data = u; + + saved_top = lua_gettop(L); + + if (ngx_resolve_name(rctx) != NGX_OK) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua tcp socket fail to run resolver immediately"); + + u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_RESOLVER; + + coctx->cleanup = NULL; + coctx->data = NULL; + + u->resolved->ctx = NULL; + lua_pushnil(L); + lua_pushfstring(L, "%s could not be resolved", host.data); + goto failed; + } + + if (u->conn_waiting) { + dd("resolved and already connecting"); + + if (resuming) { + return NGX_AGAIN; + } + + return lua_yield(L, 0); + } + + n = lua_gettop(L) - saved_top; + if (n) { + dd("errors occurred during resolving or connecting" + "or already connected"); + + if (n > 1) { + goto failed; + } + + return n; + } + + /* still resolving */ + + u->conn_waiting = 1; + u->write_prepare_retvals = ngx_http_lua_socket_resolve_retval_handler; + + dd("setting data to %p", u); + + if (ctx->entered_content_phase) { + r->write_event_handler = ngx_http_lua_content_wev_handler; + + } else { + r->write_event_handler = ngx_http_core_run_phases; + } + + if (resuming) { + return NGX_AGAIN; + } + + return lua_yield(L, 0); + +failed: + + if (spool != NULL) { + spool->connections--; + ngx_http_lua_socket_tcp_resume_conn_op(spool); + } + + return 2; + +no_memory_and_not_resuming: + + if (spool != NULL) { + spool->connections--; + ngx_http_lua_socket_tcp_resume_conn_op(spool); + } + + return luaL_error(L, "no memory"); +} + + static int ngx_http_lua_socket_tcp_connect(lua_State *L) { ngx_http_request_t *r; ngx_http_lua_ctx_t *ctx; - ngx_str_t host; int port; - ngx_resolver_ctx_t *rctx, temp; - ngx_http_core_loc_conf_t *clcf; - int saved_top; int n; u_char *p; size_t len; - ngx_url_t url; - ngx_int_t rc; ngx_http_lua_loc_conf_t *llcf; ngx_peer_connection_t *pc; int connect_timeout, send_timeout, read_timeout; unsigned custom_pool; int key_index; + ngx_int_t backlog; + ngx_int_t pool_size; + ngx_str_t key; const char *msg; - ngx_http_lua_co_ctx_t *coctx; ngx_http_lua_socket_tcp_upstream_t *u; + ngx_http_lua_socket_pool_t *spool; + n = lua_gettop(L); if (n != 2 && n != 3 && n != 4) { return luaL_error(L, "ngx.socket connect: expecting 2, 3, or 4 " @@ -466,13 +892,54 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) p = (u_char *) luaL_checklstring(L, 2, &len); + backlog = -1; key_index = 2; + pool_size = 0; custom_pool = 0; + llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); if (lua_type(L, n) == LUA_TTABLE) { /* found the last optional option table */ + lua_getfield(L, n, "pool_size"); + + if (lua_isnumber(L, -1)) { + pool_size = (ngx_int_t) lua_tointeger(L, -1); + + if (pool_size <= 0) { + msg = lua_pushfstring(L, "bad \"pool_size\" option value: %i", + pool_size); + return luaL_argerror(L, n, msg); + } + + } else if (!lua_isnil(L, -1)) { + msg = lua_pushfstring(L, "bad \"pool_size\" option type: %s", + lua_typename(L, lua_type(L, -1))); + return luaL_argerror(L, n, msg); + } + + lua_pop(L, 1); + + lua_getfield(L, n, "backlog"); + + if (lua_isnumber(L, -1)) { + backlog = (ngx_int_t) lua_tointeger(L, -1); + + if (backlog < 0) { + msg = lua_pushfstring(L, "bad \"backlog\" option value: %i", + backlog); + return luaL_argerror(L, n, msg); + } + + /* use default value for pool size if only backlog specified */ + if (pool_size == 0) { + pool_size = llcf->pool_size; + } + } + + lua_pop(L, 1); + lua_getfield(L, n, "pool"); switch (lua_type(L, -1)) { @@ -572,7 +1039,8 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) } #if 1 - lua_pushlightuserdata(L, &ngx_http_lua_upstream_udata_metatable_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + upstream_udata_metatable_key)); lua_rawget(L, LUA_REGISTRYINDEX); lua_setmetatable(L, -2); #endif @@ -582,12 +1050,8 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) ngx_memzero(u, sizeof(ngx_http_lua_socket_tcp_upstream_t)); - coctx = ctx->cur_co_ctx; - u->request = r; /* set the controlling request */ - llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); - u->conf = llcf; pc = &u->peer; @@ -628,163 +1092,28 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) u->read_timeout = u->conf->read_timeout; } - rc = ngx_http_lua_get_keepalive_peer(r, L, key_index, u); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask(socket_pool_key)); + lua_rawget(L, LUA_REGISTRYINDEX); /* table */ + lua_pushvalue(L, key_index); /* key */ - if (rc == NGX_OK) { - lua_pushinteger(L, 1); - return 1; + lua_rawget(L, -2); + spool = lua_touserdata(L, -1); + lua_pop(L, 1); + + if (spool != NULL) { + u->socket_pool = spool; + + } else if (pool_size > 0) { + lua_pushvalue(L, key_index); + key.data = (u_char *) lua_tolstring(L, -1, &key.len); + + ngx_http_lua_socket_tcp_create_socket_pool(L, r, key, pool_size, + backlog, &spool); + u->socket_pool = spool; } - if (rc == NGX_ERROR) { - lua_pushnil(L); - lua_pushliteral(L, "error in get keepalive peer"); - return 2; - } - - /* rc == NGX_DECLINED */ - - /* TODO: we should avoid this in-pool allocation */ - - host.data = ngx_palloc(r->pool, len + 1); - if (host.data == NULL) { - return luaL_error(L, "no memory"); - } - - host.len = len; - - ngx_memcpy(host.data, p, len); - host.data[len] = '\0'; - - ngx_memzero(&url, sizeof(ngx_url_t)); - - url.url.len = host.len; - url.url.data = host.data; - url.default_port = (in_port_t) port; - url.no_resolve = 1; - - if (ngx_parse_url(r->pool, &url) != NGX_OK) { - lua_pushnil(L); - - if (url.err) { - lua_pushfstring(L, "failed to parse host name \"%s\": %s", - host.data, url.err); - - } else { - lua_pushfstring(L, "failed to parse host name \"%s\"", host.data); - } - - return 2; - } - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua tcp socket connect timeout: %M", u->connect_timeout); - - u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t)); - if (u->resolved == NULL) { - return luaL_error(L, "no memory"); - } - - if (url.addrs && url.addrs[0].sockaddr) { - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua tcp socket network address given directly"); - - u->resolved->sockaddr = url.addrs[0].sockaddr; - u->resolved->socklen = url.addrs[0].socklen; - u->resolved->naddrs = 1; - u->resolved->host = url.addrs[0].name; - - } else { - u->resolved->host = host; - u->resolved->port = (in_port_t) port; - } - - if (u->resolved->sockaddr) { - rc = ngx_http_lua_socket_resolve_retval_handler(r, u, L); - if (rc == NGX_AGAIN) { - return lua_yield(L, 0); - } - - return rc; - } - - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - - temp.name = host; - rctx = ngx_resolve_start(clcf->resolver, &temp); - if (rctx == NULL) { - u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_RESOLVER; - lua_pushnil(L); - lua_pushliteral(L, "failed to start the resolver"); - return 2; - } - - if (rctx == NGX_NO_RESOLVER) { - u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_RESOLVER; - lua_pushnil(L); - lua_pushfstring(L, "no resolver defined to resolve \"%s\"", host.data); - return 2; - } - - rctx->name = host; -#if !defined(nginx_version) || nginx_version < 1005008 - rctx->type = NGX_RESOLVE_A; -#endif - rctx->handler = ngx_http_lua_socket_resolve_handler; - rctx->data = u; - rctx->timeout = clcf->resolver_timeout; - - u->resolved->ctx = rctx; - u->write_co_ctx = ctx->cur_co_ctx; - - ngx_http_lua_cleanup_pending_operation(coctx); - coctx->cleanup = ngx_http_lua_tcp_resolve_cleanup; - coctx->data = u; - - saved_top = lua_gettop(L); - - if (ngx_resolve_name(rctx) != NGX_OK) { - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua tcp socket fail to run resolver immediately"); - - u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_RESOLVER; - - coctx->cleanup = NULL; - coctx->data = NULL; - - u->resolved->ctx = NULL; - lua_pushnil(L); - lua_pushfstring(L, "%s could not be resolved", host.data); - - return 2; - } - - if (u->conn_waiting) { - dd("resolved and already connecting"); - return lua_yield(L, 0); - } - - n = lua_gettop(L) - saved_top; - if (n) { - dd("errors occurred during resolving or connecting" - "or already connected"); - return n; - } - - /* still resolving */ - - u->conn_waiting = 1; - u->write_prepare_retvals = ngx_http_lua_socket_resolve_retval_handler; - - dd("setting data to %p", u); - - if (ctx->entered_content_phase) { - r->write_event_handler = ngx_http_lua_content_wev_handler; - - } else { - r->write_event_handler = ngx_http_core_run_phases; - } - - return lua_yield(L, 0); + return ngx_http_lua_socket_tcp_connect_helper(L, u, r, ctx, p, + len, port, 0); } @@ -1638,7 +1967,8 @@ ngx_http_lua_ssl_handshake_retval_handler(ngx_http_request_t *r, "lua ssl save session: %p", ssl_session); /* set up the __gc metamethod */ - lua_pushlightuserdata(L, &ngx_http_lua_ssl_session_metatable_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + ssl_session_metatable_key)); lua_rawget(L, LUA_REGISTRYINDEX); lua_setmetatable(L, -2); } @@ -1755,20 +2085,173 @@ ngx_http_lua_socket_tcp_conn_retval_handler(ngx_http_request_t *r, } +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) +{ + ngx_int_t rc; + 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) { + u->bufs_in = + ngx_http_lua_chain_get_free_buf(r->connection->log, r->pool, + &ctx->free_recv_bufs, + u->conf->buffer_size); + + if (u->bufs_in == NULL) { + return luaL_error(L, "no memory"); + } + + u->buf_in = u->bufs_in; + u->buffer = *u->buf_in->buf; + } + + dd("tcp receive: buf_in: %p, bufs_in: %p", u->buf_in, u->bufs_in); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua tcp socket read timeout: %M", u->read_timeout); + + if (u->raw_downstream || u->body_downstream) { + r->read_event_handler = ngx_http_lua_req_socket_rev_handler; + } + + u->read_waiting = 0; + u->read_co_ctx = NULL; + + rc = ngx_http_lua_socket_tcp_read(r, u); + + if (rc == NGX_ERROR) { + dd("read failed: %d", (int) u->ft_type); + rc = ngx_http_lua_socket_tcp_receive_retval_handler(r, u, L); + dd("tcp receive retval returned: %d", (int) rc); + return rc; + } + + if (rc == NGX_OK) { + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua tcp socket receive done in a single run"); + + return ngx_http_lua_socket_tcp_receive_retval_handler(r, u, L); + } + + /* rc == NGX_AGAIN */ + + u->read_event_handler = ngx_http_lua_socket_read_handler; + + coctx = ctx->cur_co_ctx; + + ngx_http_lua_cleanup_pending_operation(coctx); + coctx->cleanup = ngx_http_lua_coctx_cleanup; + coctx->data = u; + + if (ctx->entered_content_phase) { + r->write_event_handler = ngx_http_lua_content_wev_handler; + + } else { + r->write_event_handler = ngx_http_core_run_phases; + } + + u->read_co_ctx = coctx; + u->read_waiting = 1; + u->read_prepare_retvals = ngx_http_lua_socket_tcp_receive_retval_handler; + + dd("setting data to %p, coctx:%p", u, coctx); + + if (u->raw_downstream || u->body_downstream) { + ctx->downstream = u; + } + + return lua_yield(L, 0); +} + + +static int +ngx_http_lua_socket_tcp_receiveany(lua_State *L) +{ + int n; + lua_Integer bytes; + ngx_http_request_t *r; + ngx_http_lua_loc_conf_t *llcf; + ngx_http_lua_socket_tcp_upstream_t *u; + + n = lua_gettop(L); + if (n != 2) { + return luaL_error(L, "expecting 2 arguments " + "(including the object), but got %d", n); + } + + r = ngx_http_lua_get_req(L); + if (r == NULL) { + return luaL_error(L, "no request found"); + } + + luaL_checktype(L, 1, LUA_TTABLE); + + lua_rawgeti(L, 1, SOCKET_CTX_INDEX); + u = lua_touserdata(L, -1); + + if (u == NULL || u->peer.connection == NULL || u->read_closed) { + + llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); + + if (llcf->log_socket_errors) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "attempt to receive data on a closed socket: u:%p, " + "c:%p, ft:%d eof:%d", + u, u ? u->peer.connection : NULL, + u ? (int) u->ft_type : 0, u ? (int) u->eof : 0); + } + + lua_pushnil(L); + lua_pushliteral(L, "closed"); + return 2; + } + + if (u->request != r) { + return luaL_error(L, "bad request"); + } + + ngx_http_lua_socket_check_busy_connecting(r, u, L); + ngx_http_lua_socket_check_busy_reading(r, u, L); + + if (!lua_isnumber(L, 2)) { + return luaL_argerror(L, 2, "bad max argument"); + } + + bytes = lua_tointeger(L, 2); + if (bytes <= 0) { + return luaL_argerror(L, 2, "bad max argument"); + } + + u->input_filter = ngx_http_lua_socket_read_any; + u->rest = (size_t) bytes; + u->length = u->rest; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua tcp socket calling receiveany() method to read at " + "most %uz bytes", u->rest); + + return ngx_http_lua_socket_tcp_receive_helper(r, u, L); +} + + static int ngx_http_lua_socket_tcp_receive(lua_State *L) { ngx_http_request_t *r; ngx_http_lua_socket_tcp_upstream_t *u; - ngx_int_t rc; - ngx_http_lua_ctx_t *ctx; int n; ngx_str_t pat; lua_Integer bytes; char *p; int typ; ngx_http_lua_loc_conf_t *llcf; - ngx_http_lua_co_ctx_t *coctx; n = lua_gettop(L); if (n != 1 && n != 2) { @@ -1883,119 +2366,27 @@ ngx_http_lua_socket_tcp_receive(lua_State *L) u->rest = 0; } - u->input_filter_ctx = u; - - ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); - - if (u->bufs_in == NULL) { - u->bufs_in = - ngx_http_lua_chain_get_free_buf(r->connection->log, r->pool, - &ctx->free_recv_bufs, - u->conf->buffer_size); - - if (u->bufs_in == NULL) { - return luaL_error(L, "no memory"); - } - - u->buf_in = u->bufs_in; - u->buffer = *u->buf_in->buf; - } - - dd("tcp receive: buf_in: %p, bufs_in: %p", u->buf_in, u->bufs_in); - - if (u->raw_downstream || u->body_downstream) { - r->read_event_handler = ngx_http_lua_req_socket_rev_handler; - } - - u->read_waiting = 0; - u->read_co_ctx = NULL; - - rc = ngx_http_lua_socket_tcp_read(r, u); - - if (rc == NGX_ERROR) { - dd("read failed: %d", (int) u->ft_type); - rc = ngx_http_lua_socket_tcp_receive_retval_handler(r, u, L); - dd("tcp receive retval returned: %d", (int) rc); - return rc; - } - - if (rc == NGX_OK) { - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua tcp socket receive done in a single run"); - - return ngx_http_lua_socket_tcp_receive_retval_handler(r, u, L); - } - - /* rc == NGX_AGAIN */ - - u->read_event_handler = ngx_http_lua_socket_read_handler; - - coctx = ctx->cur_co_ctx; - - ngx_http_lua_cleanup_pending_operation(coctx); - coctx->cleanup = ngx_http_lua_coctx_cleanup; - coctx->data = u; - - if (ctx->entered_content_phase) { - r->write_event_handler = ngx_http_lua_content_wev_handler; - - } else { - r->write_event_handler = ngx_http_core_run_phases; - } - - u->read_co_ctx = coctx; - u->read_waiting = 1; - u->read_prepare_retvals = ngx_http_lua_socket_tcp_receive_retval_handler; - - dd("setting data to %p, coctx:%p", u, coctx); - - if (u->raw_downstream || u->body_downstream) { - ctx->downstream = u; - } - - return lua_yield(L, 0); + return ngx_http_lua_socket_tcp_receive_helper(r, u, L); } static ngx_int_t ngx_http_lua_socket_read_chunk(void *data, ssize_t bytes) { + ngx_int_t rc; ngx_http_lua_socket_tcp_upstream_t *u = data; - ngx_buf_t *b; -#if (NGX_DEBUG) - ngx_http_request_t *r; - - r = u->request; -#endif - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, u->request->connection->log, 0, "lua tcp socket read chunk %z", bytes); - if (bytes == 0) { + rc = ngx_http_lua_read_bytes(&u->buffer, u->buf_in, &u->rest, + bytes, u->request->connection->log); + if (rc == NGX_ERROR) { u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_CLOSED; return NGX_ERROR; } - b = &u->buffer; - - if (bytes >= (ssize_t) u->rest) { - - u->buf_in->buf->last += u->rest; - b->pos += u->rest; - u->rest = 0; - - return NGX_OK; - } - - /* bytes < u->rest */ - - u->buf_in->buf->last += bytes; - b->pos += bytes; - u->rest -= bytes; - - return NGX_AGAIN; + return rc; } @@ -2004,26 +2395,10 @@ ngx_http_lua_socket_read_all(void *data, ssize_t bytes) { ngx_http_lua_socket_tcp_upstream_t *u = data; - ngx_buf_t *b; -#if (NGX_DEBUG) - ngx_http_request_t *r; - - r = u->request; -#endif - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, u->request->connection->log, 0, "lua tcp socket read all"); - - if (bytes == 0) { - return NGX_OK; - } - - b = &u->buffer; - - u->buf_in->buf->last += bytes; - b->pos += bytes; - - return NGX_AGAIN; + return ngx_http_lua_read_all(&u->buffer, u->buf_in, bytes, + u->request->connection->log); } @@ -2032,72 +2407,40 @@ ngx_http_lua_socket_read_line(void *data, ssize_t bytes) { ngx_http_lua_socket_tcp_upstream_t *u = data; - ngx_buf_t *b; - u_char *dst; - u_char c; -#if (NGX_DEBUG) - u_char *begin; -#endif + ngx_int_t rc; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, u->request->connection->log, 0, "lua tcp socket read line"); - if (bytes == 0) { + rc = ngx_http_lua_read_line(&u->buffer, u->buf_in, bytes, + u->request->connection->log); + if (rc == NGX_ERROR) { u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_CLOSED; return NGX_ERROR; } - b = &u->buffer; + return rc; +} -#if (NGX_DEBUG) - begin = b->pos; -#endif - dd("already read: %p: %.*s", u->buf_in, - (int) (u->buf_in->buf->last - u->buf_in->buf->pos), - u->buf_in->buf->pos); +static ngx_int_t +ngx_http_lua_socket_read_any(void *data, ssize_t bytes) +{ + ngx_http_lua_socket_tcp_upstream_t *u = data; - dd("data read: %.*s", (int) bytes, b->pos); + ngx_int_t rc; - dst = u->buf_in->buf->last; + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, u->request->connection->log, 0, + "lua tcp socket read any"); - while (bytes--) { - - c = *b->pos++; - - switch (c) { - case '\n': - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, u->request->connection->log, 0, - "lua tcp socket read the final line part: \"%*s\"", - b->pos - 1 - begin, begin); - - u->buf_in->buf->last = dst; - - dd("read a line: %p: %.*s", u->buf_in, - (int) (u->buf_in->buf->last - u->buf_in->buf->pos), - u->buf_in->buf->pos); - - return NGX_OK; - - case '\r': - /* ignore it */ - break; - - default: - *dst++ = c; - break; - } + rc = ngx_http_lua_read_any(&u->buffer, u->buf_in, &u->rest, bytes, + u->request->connection->log); + if (rc == NGX_ERROR) { + u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_CLOSED; + return NGX_ERROR; } -#if (NGX_DEBUG) - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, u->request->connection->log, 0, - "lua tcp socket read partial line data: %*s", - dst - begin, begin); -#endif - - u->buf_in->buf->last = dst; - - return NGX_AGAIN; + return rc; } @@ -3539,6 +3882,267 @@ ngx_http_lua_socket_tcp_finalize_write_part(ngx_http_request_t *r, } +static void +ngx_http_lua_socket_tcp_conn_op_timeout_handler(ngx_event_t *ev) +{ + ngx_http_lua_socket_tcp_upstream_t *u; + ngx_http_lua_ctx_t *ctx; + ngx_connection_t *c; + ngx_http_request_t *r; + ngx_http_lua_co_ctx_t *coctx; + ngx_http_lua_loc_conf_t *llcf; + ngx_http_lua_socket_tcp_conn_op_ctx_t *conn_op_ctx; + + conn_op_ctx = ev->data; + ngx_queue_remove(&conn_op_ctx->queue); + + u = conn_op_ctx->u; + r = u->request; + + coctx = u->write_co_ctx; + coctx->cleanup = NULL; + /* note that we store conn_op_ctx in coctx->data instead of u */ + coctx->data = conn_op_ctx; + u->write_co_ctx = NULL; + + llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); + + if (llcf->log_socket_errors) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "lua tcp socket queued connect timed out," + " when trying to connect to %V:%ud", + &conn_op_ctx->host, conn_op_ctx->port); + } + + ngx_queue_insert_head(&u->socket_pool->cache_connect_op, + &conn_op_ctx->queue); + u->socket_pool->connections--; + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx == NULL) { + return; + } + + ctx->cur_co_ctx = coctx; + + ngx_http_lua_assert(coctx && (!ngx_http_lua_is_thread(ctx) + || coctx->co_ref >= 0)); + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua tcp socket waking up the current request"); + + u->write_prepare_retvals = + ngx_http_lua_socket_tcp_conn_op_timeout_retval_handler; + + c = r->connection; + + if (ctx->entered_content_phase) { + (void) ngx_http_lua_socket_tcp_conn_op_resume(r); + + } else { + ctx->resume_handler = ngx_http_lua_socket_tcp_conn_op_resume; + ngx_http_core_run_phases(r); + } + + ngx_http_run_posted_requests(c); +} + + +static int +ngx_http_lua_socket_tcp_conn_op_timeout_retval_handler(ngx_http_request_t *r, + ngx_http_lua_socket_tcp_upstream_t *u, lua_State *L) +{ + lua_pushnil(L); + lua_pushliteral(L, "timeout"); + return 2; +} + + +static void +ngx_http_lua_socket_tcp_resume_conn_op(ngx_http_lua_socket_pool_t *spool) +{ + ngx_queue_t *q; + ngx_http_lua_socket_tcp_conn_op_ctx_t *conn_op_ctx; + +#if (NGX_DEBUG) + ngx_http_lua_assert(spool->connections >= 0); + +#else + if (spool->connections < 0) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, + "lua tcp socket connections count mismatched for " + "connection pool \"%s\", connections: %i, size: %i", + spool->key, spool->connections, spool->size); + spool->connections = 0; + } +#endif + + /* we manually destroy wait_connect_op before triggering connect + * operation resumption, so that there is no resumption happens when Nginx + * is exiting. + */ + if (ngx_queue_empty(&spool->wait_connect_op)) { + return; + } + + q = ngx_queue_head(&spool->wait_connect_op); + conn_op_ctx = ngx_queue_data(q, ngx_http_lua_socket_tcp_conn_op_ctx_t, + queue); + ngx_log_debug4(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua tcp socket post connect operation resumption " + "u: %p, ctx: %p for connection pool \"%s\", " + "connections: %i", + conn_op_ctx->u, conn_op_ctx, spool->key, spool->connections); + + if (conn_op_ctx->event.timer_set) { + ngx_del_timer(&conn_op_ctx->event); + } + + conn_op_ctx->event.handler = + ngx_http_lua_socket_tcp_conn_op_resume_handler; + + ngx_post_event((&conn_op_ctx->event), &ngx_posted_events); +} + + +static void +ngx_http_lua_socket_tcp_conn_op_ctx_cleanup(void *data) +{ + ngx_http_lua_socket_tcp_upstream_t *u; + ngx_http_lua_socket_tcp_conn_op_ctx_t *conn_op_ctx = data; + + u = conn_op_ctx->u; + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, u->request->connection->log, 0, + "cleanup lua tcp socket conn_op_ctx: \"%V\"", + &u->request->uri); + + ngx_queue_insert_head(&u->socket_pool->cache_connect_op, + &conn_op_ctx->queue); +} + + +static void +ngx_http_lua_socket_tcp_conn_op_resume_handler(ngx_event_t *ev) +{ + ngx_queue_t *q; + ngx_connection_t *c; + ngx_http_lua_ctx_t *ctx; + ngx_http_request_t *r; + ngx_http_cleanup_t *cln; + ngx_http_lua_co_ctx_t *coctx; + ngx_http_lua_socket_pool_t *spool; + ngx_http_lua_socket_tcp_upstream_t *u; + ngx_http_lua_socket_tcp_conn_op_ctx_t *conn_op_ctx; + + conn_op_ctx = ev->data; + u = conn_op_ctx->u; + r = u->request; + spool = u->socket_pool; + + if (ngx_queue_empty(&spool->wait_connect_op)) { +#if (NGX_DEBUG) + ngx_http_lua_assert(!(spool->backlog >= 0 + && spool->connections > spool->size)); + +#else + if (spool->backlog >= 0 && spool->connections > spool->size) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, + "lua tcp socket connections count mismatched for " + "connection pool \"%s\", connections: %i, size: %i", + spool->key, spool->connections, spool->size); + spool->connections = spool->size; + } +#endif + + return; + } + + q = ngx_queue_head(&spool->wait_connect_op); + ngx_queue_remove(q); + + coctx = u->write_co_ctx; + coctx->cleanup = NULL; + /* note that we store conn_op_ctx in coctx->data instead of u */ + coctx->data = conn_op_ctx; + /* clear ngx_http_lua_tcp_queue_conn_op_cleanup */ + u->write_co_ctx = NULL; + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx == NULL) { + ngx_queue_insert_head(&spool->cache_connect_op, + &conn_op_ctx->queue); + return; + } + + ctx->cur_co_ctx = coctx; + + ngx_http_lua_assert(coctx && (!ngx_http_lua_is_thread(ctx) + || coctx->co_ref >= 0)); + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua tcp socket waking up the current request"); + + u->write_prepare_retvals = + ngx_http_lua_socket_tcp_conn_op_resume_retval_handler; + + c = r->connection; + + if (ctx->entered_content_phase) { + (void) ngx_http_lua_socket_tcp_conn_op_resume(r); + + } else { + cln = ngx_http_lua_cleanup_add(r, 0); + if (cln != NULL) { + cln->handler = ngx_http_lua_socket_tcp_conn_op_ctx_cleanup; + cln->data = conn_op_ctx; + conn_op_ctx->cleanup = &cln->handler; + } + + ctx->resume_handler = ngx_http_lua_socket_tcp_conn_op_resume; + ngx_http_core_run_phases(r); + } + + ngx_http_run_posted_requests(c); +} + + +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) +{ + int nret; + ngx_http_lua_ctx_t *ctx; + ngx_http_lua_co_ctx_t *coctx; + ngx_http_lua_socket_tcp_conn_op_ctx_t *conn_op_ctx; + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx == NULL) { + return NGX_ERROR; + } + + coctx = ctx->cur_co_ctx; + dd("coctx: %p", coctx); + conn_op_ctx = coctx->data; + if (conn_op_ctx->cleanup != NULL) { + *conn_op_ctx->cleanup = NULL; + ngx_http_lua_cleanup_free(r, conn_op_ctx->cleanup); + conn_op_ctx->cleanup = NULL; + } + + /* decrease pending connect operation counter */ + u->socket_pool->connections--; + + nret = ngx_http_lua_socket_tcp_connect_helper(L, u, r, ctx, + conn_op_ctx->host.data, + conn_op_ctx->host.len, + conn_op_ctx->port, 1); + ngx_queue_insert_head(&u->socket_pool->cache_connect_op, + &conn_op_ctx->queue); + + return nret; +} + + static void ngx_http_lua_socket_tcp_finalize(ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u) @@ -3589,21 +4193,21 @@ ngx_http_lua_socket_tcp_finalize(ngx_http_request_t *r, ngx_http_lua_socket_tcp_close_connection(c); u->peer.connection = NULL; - - if (!u->reused) { - return; - } + u->conn_closed = 1; spool = u->socket_pool; if (spool == NULL) { return; } - spool->active_connections--; + spool->connections--; - if (spool->active_connections == 0) { + if (spool->connections == 0) { ngx_http_lua_socket_free_pool(r->connection->log, spool); + return; } + + ngx_http_lua_socket_tcp_resume_conn_op(spool); } } @@ -3775,7 +4379,8 @@ ngx_http_lua_socket_tcp_receiveuntil(lua_State *L) return luaL_error(L, "no memory"); } - lua_pushlightuserdata(L, &ngx_http_lua_pattern_udata_metatable_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + pattern_udata_metatable_key)); lua_rawget(L, LUA_REGISTRYINDEX); lua_setmetatable(L, -2); @@ -4430,10 +5035,12 @@ ngx_http_lua_req_socket(lua_State *L) lua_createtable(L, 2 /* narr */, 3 /* nrec */); /* the object */ if (raw) { - lua_pushlightuserdata(L, &ngx_http_lua_raw_req_socket_metatable_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + raw_req_socket_metatable_key)); } else { - lua_pushlightuserdata(L, &ngx_http_lua_req_socket_metatable_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + req_socket_metatable_key)); } lua_rawget(L, LUA_REGISTRYINDEX); @@ -4445,7 +5052,8 @@ ngx_http_lua_req_socket(lua_State *L) } #if 1 - lua_pushlightuserdata(L, &ngx_http_lua_downstream_udata_metatable_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + downstream_udata_metatable_key)); lua_rawget(L, LUA_REGISTRYINDEX); lua_setmetatable(L, -2); #endif @@ -4572,20 +5180,18 @@ ngx_http_lua_socket_tcp_setkeepalive(lua_State *L) ngx_http_lua_socket_tcp_upstream_t *u; ngx_connection_t *c; ngx_http_lua_socket_pool_t *spool; - size_t size, key_len; ngx_str_t key; - ngx_uint_t i; ngx_queue_t *q; ngx_peer_connection_t *pc; - u_char *p; ngx_http_request_t *r; ngx_msec_t timeout; - ngx_uint_t pool_size; + ngx_int_t pool_size; int n; ngx_int_t rc; ngx_buf_t *b; + const char *msg; - ngx_http_lua_socket_pool_item_t *items, *item; + ngx_http_lua_socket_pool_item_t *item; n = lua_gettop(L); @@ -4596,17 +5202,6 @@ ngx_http_lua_socket_tcp_setkeepalive(lua_State *L) luaL_checktype(L, 1, LUA_TTABLE); - lua_pushlightuserdata(L, &ngx_http_lua_socket_pool_key); - lua_rawget(L, LUA_REGISTRYINDEX); - - lua_rawgeti(L, 1, SOCKET_KEY_INDEX); - key.data = (u_char *) lua_tolstring(L, -1, &key.len); - if (key.data == NULL) { - lua_pushnil(L); - lua_pushliteral(L, "key not found"); - return 2; - } - lua_rawgeti(L, 1, SOCKET_CTX_INDEX); u = lua_touserdata(L, -1); lua_pop(L, 1); @@ -4617,7 +5212,7 @@ ngx_http_lua_socket_tcp_setkeepalive(lua_State *L) return 2; } - /* stack: obj cache key */ + /* stack: obj timeout? size? */ pc = &u->peer; c = pc->connection; @@ -4669,9 +5264,32 @@ ngx_http_lua_socket_tcp_setkeepalive(lua_State *L) return 2; } + if (ngx_terminate || ngx_exiting) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, + "lua tcp socket set keepalive while process exiting, " + "closing connection %p", c); + + ngx_http_lua_socket_tcp_finalize(r, u); + lua_pushinteger(L, 1); + return 1; + } + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, "lua tcp socket set keepalive: saving connection %p", c); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask(socket_pool_key)); + lua_rawget(L, LUA_REGISTRYINDEX); + + /* stack: obj timeout? size? pools */ + + lua_rawgeti(L, 1, SOCKET_KEY_INDEX); + key.data = (u_char *) lua_tolstring(L, -1, &key.len); + if (key.data == NULL) { + lua_pushnil(L); + lua_pushliteral(L, "key not found"); + return 2; + } + dd("saving connection to key %s", lua_tostring(L, -1)); lua_pushvalue(L, -1); @@ -4679,7 +5297,7 @@ ngx_http_lua_socket_tcp_setkeepalive(lua_State *L) spool = lua_touserdata(L, -1); lua_pop(L, 1); - /* stack: obj timeout? size? cache key */ + /* stack: obj timeout? size? pools cache_key */ llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); @@ -4693,82 +5311,49 @@ ngx_http_lua_socket_tcp_setkeepalive(lua_State *L) pool_size = llcf->pool_size; } - if (pool_size == 0) { - lua_pushnil(L); - lua_pushliteral(L, "zero pool size"); - return 2; + if (pool_size <= 0) { + msg = lua_pushfstring(L, "bad \"pool_size\" option value: %i", + pool_size); + return luaL_argerror(L, n, msg); } - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua tcp socket connection pool size: %ui", pool_size); - - key_len = ngx_align(key.len + 1, sizeof(void *)); - - size = sizeof(ngx_http_lua_socket_pool_t) + key_len - 1 - + sizeof(ngx_http_lua_socket_pool_item_t) - * pool_size; - - spool = lua_newuserdata(L, size); - if (spool == NULL) { - return luaL_error(L, "no memory"); - } - - lua_pushlightuserdata(L, &ngx_http_lua_pool_udata_metatable_key); - lua_rawget(L, LUA_REGISTRYINDEX); - lua_setmetatable(L, -2); - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, - "lua tcp socket keepalive create connection pool for key" - " \"%s\"", lua_tostring(L, -2)); - - lua_rawset(L, -3); - - spool->active_connections = 0; - spool->lua_vm = ngx_http_lua_get_lua_vm(r, NULL); - - ngx_queue_init(&spool->cache); - ngx_queue_init(&spool->free); - - p = ngx_copy(spool->key, key.data, key.len); - *p++ = '\0'; - - items = (ngx_http_lua_socket_pool_item_t *) (spool->key + key_len); - - dd("items: %p", items); - - ngx_http_lua_assert((void *) items == ngx_align_ptr(items, - sizeof(void *))); - - for (i = 0; i < pool_size; i++) { - ngx_queue_insert_head(&spool->free, &items[i].queue); - items[i].socket_pool = spool; - } + ngx_http_lua_socket_tcp_create_socket_pool(L, r, key, pool_size, -1, + &spool); } if (ngx_queue_empty(&spool->free)) { q = ngx_queue_last(&spool->cache); ngx_queue_remove(q); - spool->active_connections--; item = ngx_queue_data(q, ngx_http_lua_socket_pool_item_t, queue); ngx_http_lua_socket_tcp_close_connection(item->connection); + /* only decrease the counter for connections which were counted */ + if (u->socket_pool != NULL) { + u->socket_pool->connections--; + } + } else { q = ngx_queue_head(&spool->free); ngx_queue_remove(q); item = ngx_queue_data(q, ngx_http_lua_socket_pool_item_t, queue); + + /* we should always increase connections after getting connected, + * and decrease connections after getting closed. + * however, we don't create connection pool in previous connect method. + * so we increase connections here for backward compatibility. + */ + if (u->socket_pool == NULL) { + spool->connections++; + } } item->connection = c; ngx_queue_insert_head(&spool->cache, q); - if (!u->reused) { - spool->active_connections++; - } - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0, "lua tcp socket clear current socket connection"); @@ -4837,48 +5422,33 @@ ngx_http_lua_socket_tcp_setkeepalive(lua_State *L) ngx_http_lua_socket_tcp_finalize(r, u); #endif + /* since we set u->peer->connection to NULL previously, the connect + * operation won't be resumed in the ngx_http_lua_socket_tcp_finalize. + * Therefore we need to resume it here. + */ + ngx_http_lua_socket_tcp_resume_conn_op(spool); + lua_pushinteger(L, 1); return 1; } static ngx_int_t -ngx_http_lua_get_keepalive_peer(ngx_http_request_t *r, lua_State *L, - int key_index, ngx_http_lua_socket_tcp_upstream_t *u) +ngx_http_lua_get_keepalive_peer(ngx_http_request_t *r, + ngx_http_lua_socket_tcp_upstream_t *u) { ngx_http_lua_socket_pool_item_t *item; ngx_http_lua_socket_pool_t *spool; ngx_http_cleanup_t *cln; ngx_queue_t *q; - int top; ngx_peer_connection_t *pc; ngx_connection_t *c; - top = lua_gettop(L); - - if (key_index < 0) { - key_index = top + key_index + 1; - } - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua tcp socket pool get keepalive peer"); pc = &u->peer; - - lua_pushlightuserdata(L, &ngx_http_lua_socket_pool_key); - lua_rawget(L, LUA_REGISTRYINDEX); /* table */ - lua_pushvalue(L, key_index); /* key */ - lua_rawget(L, -2); - - spool = lua_touserdata(L, -1); - if (spool == NULL) { - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0, - "lua tcp socket keepalive connection pool not found"); - lua_settop(L, top); - return NGX_DECLINED; - } - - u->socket_pool = spool; + spool = u->socket_pool; if (!ngx_queue_empty(&spool->cache)) { q = ngx_queue_head(&spool->cache); @@ -4923,7 +5493,6 @@ ngx_http_lua_get_keepalive_peer(ngx_http_request_t *r, lua_State *L, cln = ngx_http_lua_cleanup_add(r, 0); if (cln == NULL) { u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_ERROR; - lua_settop(L, top); return NGX_ERROR; } @@ -4932,16 +5501,12 @@ ngx_http_lua_get_keepalive_peer(ngx_http_request_t *r, lua_State *L, u->cleanup = &cln->handler; } - lua_settop(L, top); - return NGX_OK; } ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0, "lua tcp socket keepalive: connection pool empty"); - lua_settop(L, top); - return NGX_DECLINED; } @@ -5013,13 +5578,15 @@ close: ngx_queue_remove(&item->queue); ngx_queue_insert_head(&spool->free, &item->queue); - spool->active_connections--; + spool->connections--; - dd("keepalive: active connections: %u", - (unsigned) spool->active_connections); + dd("keepalive: connections: %u", (unsigned) spool->connections); - if (spool->active_connections == 0) { + if (spool->connections == 0) { ngx_http_lua_socket_free_pool(ev->log, spool); + + } else { + ngx_http_lua_socket_tcp_resume_conn_op(spool); } return NGX_DECLINED; @@ -5037,7 +5604,7 @@ ngx_http_lua_socket_free_pool(ngx_log_t *log, ngx_http_lua_socket_pool_t *spool) L = spool->lua_vm; - lua_pushlightuserdata(L, &ngx_http_lua_socket_pool_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask(socket_pool_key)); lua_rawget(L, LUA_REGISTRYINDEX); lua_pushstring(L, (char *) spool->key); lua_pushnil(L); @@ -5049,9 +5616,10 @@ ngx_http_lua_socket_free_pool(ngx_log_t *log, ngx_http_lua_socket_pool_t *spool) static void ngx_http_lua_socket_shutdown_pool_helper(ngx_http_lua_socket_pool_t *spool) { - ngx_queue_t *q; - ngx_connection_t *c; - ngx_http_lua_socket_pool_item_t *item; + ngx_queue_t *q; + ngx_connection_t *c; + ngx_http_lua_socket_pool_item_t *item; + ngx_http_lua_socket_tcp_conn_op_ctx_t *conn_op_ctx; while (!ngx_queue_empty(&spool->cache)) { q = ngx_queue_head(&spool->cache); @@ -5065,7 +5633,29 @@ ngx_http_lua_socket_shutdown_pool_helper(ngx_http_lua_socket_pool_t *spool) ngx_queue_insert_head(&spool->free, q); } - spool->active_connections = 0; + while (!ngx_queue_empty(&spool->cache_connect_op)) { + q = ngx_queue_head(&spool->cache_connect_op); + ngx_queue_remove(q); + conn_op_ctx = ngx_queue_data(q, ngx_http_lua_socket_tcp_conn_op_ctx_t, + queue); + ngx_http_lua_socket_tcp_free_conn_op_ctx(conn_op_ctx); + } + + while (!ngx_queue_empty(&spool->wait_connect_op)) { + q = ngx_queue_head(&spool->wait_connect_op); + ngx_queue_remove(q); + conn_op_ctx = ngx_queue_data(q, ngx_http_lua_socket_tcp_conn_op_ctx_t, + queue); + + if (conn_op_ctx->event.timer_set) { + ngx_del_timer(&conn_op_ctx->event); + } + + ngx_http_lua_socket_tcp_free_conn_op_ctx(conn_op_ctx); + } + + /* spool->connections will be decreased down to zero in + * ngx_http_lua_socket_tcp_finalize */ } @@ -5319,6 +5909,13 @@ static ngx_int_t ngx_http_lua_socket_insert_buffer(ngx_http_request_t *r, } +static ngx_int_t +ngx_http_lua_socket_tcp_conn_op_resume(ngx_http_request_t *r) +{ + return ngx_http_lua_socket_tcp_resume_helper(r, SOCKET_OP_RESUME_CONN); +} + + static ngx_int_t ngx_http_lua_socket_tcp_conn_resume(ngx_http_request_t *r) { @@ -5343,13 +5940,14 @@ ngx_http_lua_socket_tcp_write_resume(ngx_http_request_t *r) static ngx_int_t ngx_http_lua_socket_tcp_resume_helper(ngx_http_request_t *r, int socket_op) { - int nret; - lua_State *vm; - ngx_int_t rc; - ngx_uint_t nreqs; - ngx_connection_t *c; - ngx_http_lua_ctx_t *ctx; - ngx_http_lua_co_ctx_t *coctx; + int nret; + lua_State *vm; + ngx_int_t rc; + ngx_uint_t nreqs; + ngx_connection_t *c; + ngx_http_lua_ctx_t *ctx; + ngx_http_lua_co_ctx_t *coctx; + ngx_http_lua_socket_tcp_conn_op_ctx_t *conn_op_ctx; ngx_http_lua_socket_tcp_retval_handler prepare_retvals; @@ -5369,15 +5967,22 @@ ngx_http_lua_socket_tcp_resume_helper(ngx_http_request_t *r, int socket_op) dd("coctx: %p", coctx); - u = coctx->data; - switch (socket_op) { + + case SOCKET_OP_RESUME_CONN: + conn_op_ctx = coctx->data; + u = conn_op_ctx->u; + prepare_retvals = u->write_prepare_retvals; + break; + case SOCKET_OP_CONNECT: case SOCKET_OP_WRITE: + u = coctx->data; prepare_retvals = u->write_prepare_retvals; break; case SOCKET_OP_READ: + u = coctx->data; prepare_retvals = u->read_prepare_retvals; break; @@ -5391,6 +5996,15 @@ ngx_http_lua_socket_tcp_resume_helper(ngx_http_request_t *r, int socket_op) "u:%p", prepare_retvals, u); nret = prepare_retvals(r, u, ctx->cur_co_ctx->co); + if (socket_op == SOCKET_OP_CONNECT + && nret > 1 + && !u->conn_closed + && u->socket_pool != NULL) + { + u->socket_pool->connections--; + ngx_http_lua_socket_tcp_resume_conn_op(u->socket_pool); + } + if (nret == NGX_AGAIN) { return NGX_DONE; } @@ -5422,6 +6036,36 @@ ngx_http_lua_socket_tcp_resume_helper(ngx_http_request_t *r, int socket_op) } +static void +ngx_http_lua_tcp_queue_conn_op_cleanup(void *data) +{ + ngx_http_lua_co_ctx_t *coctx = data; + ngx_http_lua_socket_tcp_upstream_t *u; + ngx_http_lua_socket_tcp_conn_op_ctx_t *conn_op_ctx; + + conn_op_ctx = coctx->data; + u = conn_op_ctx->u; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua tcp socket abort queueing, conn_op_ctx: %p, u: %p", + conn_op_ctx, u); + + if (conn_op_ctx->event.posted) { + ngx_delete_posted_event(&conn_op_ctx->event); + + } else if (conn_op_ctx->event.timer_set) { + ngx_del_timer(&conn_op_ctx->event); + } + + ngx_queue_remove(&conn_op_ctx->queue); + ngx_queue_insert_head(&u->socket_pool->cache_connect_op, + &conn_op_ctx->queue); + + u->socket_pool->connections--; + ngx_http_lua_socket_tcp_resume_conn_op(u->socket_pool); +} + + static void ngx_http_lua_tcp_resolve_cleanup(void *data) { @@ -5437,6 +6081,11 @@ ngx_http_lua_tcp_resolve_cleanup(void *data) return; } + if (u->socket_pool != NULL) { + u->socket_pool->connections--; + ngx_http_lua_socket_tcp_resume_conn_op(u->socket_pool); + } + rctx = u->resolved->ctx; if (rctx == NULL) { return; @@ -5496,7 +6145,8 @@ ngx_http_lua_cleanup_conn_pools(lua_State *L) { ngx_http_lua_socket_pool_t *spool; - lua_pushlightuserdata(L, &ngx_http_lua_socket_pool_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + socket_pool_key)); lua_rawget(L, LUA_REGISTRYINDEX); /* table */ lua_pushnil(L); /* first key */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_socket_tcp.h b/debian/modules/http-lua/src/ngx_http_lua_socket_tcp.h index dbdee41..091e437 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_socket_tcp.h +++ b/debian/modules/http-lua/src/ngx_http_lua_socket_tcp.h @@ -35,17 +35,39 @@ typedef void (*ngx_http_lua_socket_tcp_upstream_handler_pt) (ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u); +typedef struct { + ngx_event_t event; + ngx_queue_t queue; + ngx_str_t host; + ngx_http_cleanup_pt *cleanup; + ngx_http_lua_socket_tcp_upstream_t *u; + in_port_t port; +} ngx_http_lua_socket_tcp_conn_op_ctx_t; + + +#define ngx_http_lua_socket_tcp_free_conn_op_ctx(conn_op_ctx) \ + ngx_free(conn_op_ctx->host.data); \ + ngx_free(conn_op_ctx) + + typedef struct { lua_State *lua_vm; - /* active connections == out-of-pool reused connections - * + in-pool connections */ - ngx_uint_t active_connections; + ngx_int_t size; + ngx_queue_t cache_connect_op; + ngx_queue_t wait_connect_op; + + /* connections == active connections + pending connect operations, + * while active connections == out-of-pool reused connections + * + in-pool connections */ + ngx_int_t connections; /* queues of ngx_http_lua_socket_pool_item_t: */ ngx_queue_t cache; ngx_queue_t free; + ngx_int_t backlog; + u_char key[1]; } ngx_http_lua_socket_pool_t; @@ -104,6 +126,7 @@ struct ngx_http_lua_socket_tcp_upstream_s { unsigned raw_downstream:1; unsigned read_closed:1; unsigned write_closed:1; + unsigned conn_closed:1; #if (NGX_HTTP_SSL) unsigned ssl_verify:1; unsigned ssl_session_reuse:1; diff --git a/debian/modules/http-lua/src/ngx_http_lua_socket_udp.c b/debian/modules/http-lua/src/ngx_http_lua_socket_udp.c index 8927f41..cbc32d6 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_socket_udp.c +++ b/debian/modules/http-lua/src/ngx_http_lua_socket_udp.c @@ -81,7 +81,8 @@ ngx_http_lua_inject_socket_udp_api(ngx_log_t *log, lua_State *L) lua_setfield(L, -2, "udp"); /* ngx socket */ /* udp socket object metatable */ - lua_pushlightuserdata(L, &ngx_http_lua_socket_udp_metatable_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + socket_udp_metatable_key)); lua_createtable(L, 0 /* narr */, 6 /* nrec */); lua_pushcfunction(L, ngx_http_lua_socket_udp_setpeername); @@ -105,7 +106,8 @@ ngx_http_lua_inject_socket_udp_api(ngx_log_t *log, lua_State *L) /* }}} */ /* udp socket object metatable */ - lua_pushlightuserdata(L, &ngx_http_lua_udp_udata_metatable_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + udp_udata_metatable_key)); lua_createtable(L, 0 /* narr */, 1 /* nrec */); /* metatable */ lua_pushcfunction(L, ngx_http_lua_socket_udp_upstream_destroy); lua_setfield(L, -2, "__gc"); @@ -144,7 +146,8 @@ ngx_http_lua_socket_udp(lua_State *L) | NGX_HTTP_LUA_CONTEXT_SSL_CERT); lua_createtable(L, 3 /* narr */, 1 /* nrec */); - lua_pushlightuserdata(L, &ngx_http_lua_socket_udp_metatable_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + socket_udp_metatable_key)); lua_rawget(L, LUA_REGISTRYINDEX); lua_setmetatable(L, -2); @@ -263,7 +266,8 @@ ngx_http_lua_socket_udp_setpeername(lua_State *L) } #if 1 - lua_pushlightuserdata(L, &ngx_http_lua_udp_udata_metatable_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + udp_udata_metatable_key)); lua_rawget(L, LUA_REGISTRYINDEX); lua_setmetatable(L, -2); #endif diff --git a/debian/modules/http-lua/src/ngx_http_lua_ssl_certby.c b/debian/modules/http-lua/src/ngx_http_lua_ssl_certby.c index 453a5c7..622d0a5 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_ssl_certby.c +++ b/debian/modules/http-lua/src/ngx_http_lua_ssl_certby.c @@ -498,9 +498,11 @@ ngx_http_lua_ssl_cert_by_chunk(lua_State *L, ngx_http_request_t *r) /* 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); diff --git a/debian/modules/http-lua/src/ngx_http_lua_ssl_session_fetchby.c b/debian/modules/http-lua/src/ngx_http_lua_ssl_session_fetchby.c index 0b88a87..303efb4 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_ssl_session_fetchby.c +++ b/debian/modules/http-lua/src/ngx_http_lua_ssl_session_fetchby.c @@ -505,9 +505,11 @@ ngx_http_lua_ssl_sess_fetch_by_chunk(lua_State *L, ngx_http_request_t *r) /* 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); diff --git a/debian/modules/http-lua/src/ngx_http_lua_ssl_session_storeby.c b/debian/modules/http-lua/src/ngx_http_lua_ssl_session_storeby.c index 7609c39..a02f729 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_ssl_session_storeby.c +++ b/debian/modules/http-lua/src/ngx_http_lua_ssl_session_storeby.c @@ -380,6 +380,8 @@ ngx_http_lua_ssl_sess_store_by_chunk(lua_State *L, ngx_http_request_t *r) /* init nginx context in Lua VM */ ngx_http_lua_set_req(L, r); + +#ifndef OPENRESTY_LUAJIT ngx_http_lua_create_new_globals_table(L, 0 /* narr */, 1 /* nrec */); /* {{{ make new env inheriting main thread's globals table */ @@ -390,6 +392,7 @@ ngx_http_lua_ssl_sess_store_by_chunk(lua_State *L, ngx_http_request_t *r) /* }}} */ lua_setfenv(L, -2); /* set new running env for the code closure */ +#endif lua_pushcfunction(L, ngx_http_lua_traceback); lua_insert(L, 1); /* put it under chunk and args */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_string.c b/debian/modules/http-lua/src/ngx_http_lua_string.c index 239b232..bdadeb4 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_string.c +++ b/debian/modules/http-lua/src/ngx_http_lua_string.c @@ -762,6 +762,20 @@ ngx_http_lua_ffi_escape_uri(const u_char *src, size_t len, u_char *dst) ngx_http_lua_escape_uri(dst, (u_char *) src, len, NGX_ESCAPE_URI_COMPONENT); } + +void +ngx_http_lua_ffi_str_replace_char(u_char *buf, size_t len, const u_char find, + const u_char replace) +{ + while (len) { + if (*buf == find) { + *buf = replace; + } + + buf++; + len--; + } +} #endif /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_subrequest.c b/debian/modules/http-lua/src/ngx_http_lua_subrequest.c index 826a43c..f312b65 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_subrequest.c +++ b/debian/modules/http-lua/src/ngx_http_lua_subrequest.c @@ -1031,6 +1031,14 @@ ngx_http_lua_post_subrequest(ngx_http_request_t *r, void *data, ngx_int_t rc) dd("pr_coctx status: %d", (int) pr_coctx->sr_statuses[ctx->index]); /* copy subrequest response headers */ + if (ctx->headers_set) { + rc = ngx_http_lua_set_content_type(r, ctx); + if (rc != NGX_OK) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "failed to set default content type: %i", rc); + return NGX_ERROR; + } + } pr_coctx->sr_headers[ctx->index] = &r->headers_out; diff --git a/debian/modules/http-lua/src/ngx_http_lua_timer.c b/debian/modules/http-lua/src/ngx_http_lua_timer.c index 596b2f7..e92c211 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_timer.c +++ b/debian/modules/http-lua/src/ngx_http_lua_timer.c @@ -220,6 +220,7 @@ ngx_http_lua_ngx_timer_helper(lua_State *L, int every) ngx_http_lua_probe_user_coroutine_create(r, L, co); +#ifndef OPENRESTY_LUAJIT lua_createtable(co, 0, 0); /* the new globals table */ /* co stack: global_tb */ @@ -232,6 +233,7 @@ ngx_http_lua_ngx_timer_helper(lua_State *L, int every) /* co stack: global_tb */ ngx_http_lua_set_globals_table(co); +#endif /* co stack: */ @@ -251,12 +253,15 @@ ngx_http_lua_ngx_timer_helper(lua_State *L, int every) /* L stack: time func [args] thread */ /* co stack: func */ +#ifndef OPENRESTY_LUAJIT ngx_http_lua_get_globals_table(co); lua_setfenv(co, -2); +#endif /* co stack: func */ - lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + coroutines_key)); lua_rawget(L, LUA_REGISTRYINDEX); /* L stack: time func [args] thread coroutines */ @@ -345,6 +350,9 @@ ngx_http_lua_ngx_timer_helper(lua_State *L, int every) ngx_add_timer(ev, delay); + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "created timer (co: %p delay: %M ms)", tctx->co, delay); + lua_pushinteger(L, 1); return 1; @@ -358,7 +366,8 @@ nomem: ngx_free(ev); } - lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + coroutines_key)); lua_rawget(L, LUA_REGISTRYINDEX); luaL_unref(L, -1, co_ref); @@ -387,6 +396,7 @@ ngx_http_lua_timer_copy(ngx_http_lua_timer_ctx_t *old_tctx) co = lua_newthread(vm); +#ifndef OPENRESTY_LUAJIT lua_createtable(co, 0, 0); /* the new globals table */ /* co stack: global_tb */ @@ -399,6 +409,7 @@ ngx_http_lua_timer_copy(ngx_http_lua_timer_ctx_t *old_tctx) /* co stack: global_tb */ ngx_http_lua_set_globals_table(co); +#endif /* co stack: */ @@ -418,12 +429,15 @@ ngx_http_lua_timer_copy(ngx_http_lua_timer_ctx_t *old_tctx) /* L stack: func [args] thread */ /* co stack: func */ +#ifndef OPENRESTY_LUAJIT ngx_http_lua_get_globals_table(co); lua_setfenv(co, -2); +#endif /* co stack: func */ - lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + coroutines_key)); lua_rawget(L, LUA_REGISTRYINDEX); /* L stack: func [args] thread coroutines */ @@ -498,6 +512,10 @@ ngx_http_lua_timer_copy(ngx_http_lua_timer_ctx_t *old_tctx) ngx_add_timer(ev, tctx->delay); + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "created next timer (co: %p delay: %M ms)", tctx->co, + tctx->delay); + return NGX_OK; nomem: @@ -512,7 +530,8 @@ nomem: /* L stack: func [args] */ - lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + coroutines_key)); lua_rawget(L, LUA_REGISTRYINDEX); luaL_unref(L, -1, co_ref); @@ -568,6 +587,9 @@ ngx_http_lua_timer_handler(ngx_event_t *ev) c = ngx_http_lua_create_fake_connection(tctx.pool); if (c == NULL) { + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, + "failed to create fake connection to run timer (co: %p)", + tctx.co); goto failed; } @@ -579,6 +601,9 @@ ngx_http_lua_timer_handler(ngx_event_t *ev) r = ngx_http_lua_create_fake_request(c); if (r == NULL) { + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, + "failed to create fake request to run timer (co: %p)", + tctx.co); goto failed; } @@ -614,6 +639,8 @@ ngx_http_lua_timer_handler(ngx_event_t *ev) ctx = ngx_http_lua_create_ctx(r); if (ctx == NULL) { + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, + "failed to create ctx to run timer (co: %p)", tctx.co); goto failed; } @@ -622,6 +649,9 @@ ngx_http_lua_timer_handler(ngx_event_t *ev) pcln = ngx_pool_cleanup_add(r->pool, 0); if (pcln == NULL) { + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, + "failed to add vm cleanup to run timer (co: %p)", + tctx.co); goto failed; } @@ -635,6 +665,9 @@ ngx_http_lua_timer_handler(ngx_event_t *ev) cln = ngx_http_cleanup_add(r, 0); if (cln == NULL) { + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, + "failed to add request cleanup to run timer (co: %p)", + tctx.co); goto failed; } @@ -692,7 +725,8 @@ ngx_http_lua_timer_handler(ngx_event_t *ev) failed: if (tctx.co_ref && tctx.co) { - lua_pushlightuserdata(tctx.co, &ngx_http_lua_coroutines_key); + lua_pushlightuserdata(tctx.co, ngx_http_lua_lightudata_mask( + coroutines_key)); lua_rawget(tctx.co, LUA_REGISTRYINDEX); luaL_unref(tctx.co, -1, tctx.co_ref); lua_settop(tctx.co, 0); diff --git a/debian/modules/http-lua/src/ngx_http_lua_uthread.c b/debian/modules/http-lua/src/ngx_http_lua_uthread.c index 8195ec0..43517a0 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_uthread.c +++ b/debian/modules/http-lua/src/ngx_http_lua_uthread.c @@ -70,7 +70,8 @@ ngx_http_lua_uthread_spawn(lua_State *L) /* anchor the newly created coroutine into the Lua registry */ - lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + coroutines_key)); lua_rawget(L, LUA_REGISTRYINDEX); lua_pushvalue(L, -2); coctx->co_ref = luaL_ref(L, -2); diff --git a/debian/modules/http-lua/src/ngx_http_lua_util.c b/debian/modules/http-lua/src/ngx_http_lua_util.c index f7a537e..c12262e 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_util.c +++ b/debian/modules/http-lua/src/ngx_http_lua_util.c @@ -70,6 +70,25 @@ #endif +#if (NGX_HTTP_LUA_HAVE_SA_RESTART) +#define NGX_HTTP_LUA_SA_RESTART_SIGS { \ + ngx_signal_value(NGX_RECONFIGURE_SIGNAL), \ + ngx_signal_value(NGX_REOPEN_SIGNAL), \ + ngx_signal_value(NGX_NOACCEPT_SIGNAL), \ + ngx_signal_value(NGX_TERMINATE_SIGNAL), \ + ngx_signal_value(NGX_SHUTDOWN_SIGNAL), \ + ngx_signal_value(NGX_CHANGEBIN_SIGNAL), \ + SIGALRM, \ + SIGINT, \ + SIGIO, \ + SIGCHLD, \ + SIGSYS, \ + SIGPIPE, \ + 0 \ +}; +#endif + + char ngx_http_lua_code_cache_key; char ngx_http_lua_regex_cache_key; char ngx_http_lua_socket_pool_key; @@ -128,6 +147,13 @@ static int ngx_http_lua_get_raw_phase_context(lua_State *L); #define LUA_PATH_SEP ";" #endif + +#if !defined(LUA_DEFAULT_PATH) && (NGX_DEBUG) +#define LUA_DEFAULT_PATH "../lua-resty-core/lib/?.lua;" \ + "../lua-resty-lrucache/lib/?.lua" +#endif + + #define AUX_MARK "\1" @@ -171,6 +197,7 @@ ngx_http_lua_set_path(ngx_cycle_t *cycle, lua_State *L, int tab_idx, } +#ifndef OPENRESTY_LUAJIT /** * Create new table and set _G field to itself. * @@ -185,6 +212,7 @@ ngx_http_lua_create_new_globals_table(lua_State *L, int narr, int nrec) lua_pushvalue(L, -1); lua_setfield(L, -2, "_G"); } +#endif /* OPENRESTY_LUAJIT */ static lua_State * @@ -313,11 +341,13 @@ ngx_http_lua_new_thread(ngx_http_request_t *r, lua_State *L, int *ref) base = lua_gettop(L); - lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + coroutines_key)); lua_rawget(L, LUA_REGISTRYINDEX); co = lua_newthread(L); +#ifndef OPENRESTY_LUAJIT /* {{{ inherit coroutine's globals to main thread's globals table * for print() function will try to find tostring() in current * globals table. @@ -332,6 +362,7 @@ ngx_http_lua_new_thread(ngx_http_request_t *r, lua_State *L, int *ref) ngx_http_lua_set_globals_table(co); /* }}} */ +#endif /* OPENRESTY_LUAJIT */ *ref = luaL_ref(L, -2); @@ -356,7 +387,8 @@ ngx_http_lua_del_thread(ngx_http_request_t *r, lua_State *L, ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua deleting light thread"); - lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + coroutines_key)); lua_rawget(L, LUA_REGISTRYINDEX); ngx_http_lua_probe_thread_delete(r, coctx->co, ctx); @@ -408,7 +440,9 @@ ngx_http_lua_send_header_if_needed(ngx_http_request_t *r, r->headers_out.status = NGX_HTTP_OK; } - if (!ctx->headers_set && ngx_http_lua_set_content_type(r) != NGX_OK) { + if (!ctx->mime_set + && ngx_http_lua_set_content_type(r, ctx) != NGX_OK) + { return NGX_ERROR; } @@ -657,7 +691,8 @@ ngx_http_lua_init_registry(lua_State *L, ngx_log_t *log) /* {{{ register a table to anchor lua coroutines reliably: * {([int]ref) = [cort]} */ - lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + coroutines_key)); lua_createtable(L, 0, 32 /* nrec */); lua_rawset(L, LUA_REGISTRYINDEX); /* }}} */ @@ -668,20 +703,23 @@ ngx_http_lua_init_registry(lua_State *L, ngx_log_t *log) lua_rawset(L, LUA_REGISTRYINDEX); /* create the registry entry for the Lua socket connection pool table */ - lua_pushlightuserdata(L, &ngx_http_lua_socket_pool_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + socket_pool_key)); lua_createtable(L, 0, 8 /* nrec */); lua_rawset(L, LUA_REGISTRYINDEX); #if (NGX_PCRE) /* create the registry entry for the Lua precompiled regex object cache */ - lua_pushlightuserdata(L, &ngx_http_lua_regex_cache_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + regex_cache_key)); lua_createtable(L, 0, 16 /* nrec */); lua_rawset(L, LUA_REGISTRYINDEX); #endif /* {{{ register table to cache user code: * { [(string)cache_key] = } */ - lua_pushlightuserdata(L, &ngx_http_lua_code_cache_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + code_cache_key)); lua_createtable(L, 0, 8 /* nrec */); lua_rawset(L, LUA_REGISTRYINDEX); /* }}} */ @@ -695,9 +733,6 @@ ngx_http_lua_init_globals(lua_State *L, ngx_cycle_t *cycle, ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "lua initializing lua globals"); - lua_pushlightuserdata(L, cycle); - lua_setglobal(L, "__ngx_cycle"); - #if defined(NDK) && NDK ngx_http_lua_inject_ndk_api(L); #endif /* defined(NDK) && NDK */ @@ -756,6 +791,52 @@ ngx_http_lua_inject_ngx_api(lua_State *L, ngx_http_lua_main_conf_t *lmcf, lua_setglobal(L, "ngx"); ngx_http_lua_inject_coroutine_api(log, L); + +#ifdef OPENRESTY_LUAJIT + { + int rc; + + const char buf[] = + "local ngx_log = ngx.log\n" + "local ngx_WARN = ngx.WARN\n" + "local tostring = tostring\n" + "local ngx_get_phase = ngx.get_phase\n" + "local traceback = require 'debug'.traceback\n" + "local function newindex(table, key, value)\n" + "rawset(table, key, value)\n" + "local phase = ngx_get_phase()\n" + "if phase == 'init_worker' or phase == 'init' then\n" + "return\n" + "end\n" + "ngx_log(ngx_WARN, 'writing a global lua variable " + "(\\'', tostring(key), '\\') which may lead to " + "race conditions between concurrent requests, so " + "prefer the use of \\'local\\' variables', " + "traceback('', 2))\n" + "end\n" + "setmetatable(_G, { __newindex = newindex })\n" + ; + + rc = luaL_loadbuffer(L, buf, sizeof(buf) - 1, "=_G write guard"); + + if (rc != 0) { + ngx_log_error(NGX_LOG_ERR, log, 0, + "failed to load Lua code (%i): %s", + rc, lua_tostring(L, -1)); + + lua_pop(L, 1); + return; + } + + rc = lua_pcall(L, 0, 0, 0); + if (rc != 0) { + ngx_log_error(NGX_LOG_ERR, log, 0, + "failed to run Lua code (%i): %s", + rc, lua_tostring(L, -1)); + lua_pop(L, 1); + } + } +#endif } @@ -2954,12 +3035,12 @@ ngx_http_lua_param_get(lua_State *L) | NGX_HTTP_LUA_CONTEXT_BODY_FILTER); if (ctx->context & (NGX_HTTP_LUA_CONTEXT_SET)) { - return ngx_http_lua_setby_param_get(L); + 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); + return ngx_http_lua_body_filter_param_get(L, r); } @@ -3156,7 +3237,8 @@ ngx_http_lua_finalize_threads(ngx_http_request_t *r, ngx_http_lua_probe_thread_delete(r, coctx->co, ctx); - lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + coroutines_key)); lua_rawget(L, LUA_REGISTRYINDEX); inited = 1; @@ -3194,7 +3276,8 @@ ngx_http_lua_finalize_threads(ngx_http_request_t *r, ngx_http_lua_probe_thread_delete(r, coctx->co, ctx); if (!inited) { - lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + coroutines_key)); lua_rawget(L, LUA_REGISTRYINDEX); inited = 1; } @@ -3223,7 +3306,8 @@ ngx_http_lua_finalize_threads(ngx_http_request_t *r, ngx_http_lua_probe_thread_delete(r, coctx->co, ctx); if (!inited) { - lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); + lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( + coroutines_key)); lua_rawget(L, LUA_REGISTRYINDEX); inited = 1; } @@ -3736,6 +3820,7 @@ ngx_http_lua_init_vm(lua_State *parent_vm, ngx_cycle_t *cycle, ngx_pool_t *pool, ngx_http_lua_main_conf_t *lmcf, ngx_log_t *log, ngx_pool_cleanup_t **pcln) { + int rc; lua_State *L; ngx_uint_t i; ngx_pool_cleanup_t *cln; @@ -3778,6 +3863,11 @@ ngx_http_lua_init_vm(lua_State *parent_vm, ngx_cycle_t *cycle, *pcln = cln; } +#ifdef OPENRESTY_LUAJIT + /* load FFI library first since cdata needs it */ + luaopen_ffi(L); +#endif + if (lmcf->preload_hooks) { /* register the 3rd-party module's preload hooks */ @@ -3798,6 +3888,21 @@ ngx_http_lua_init_vm(lua_State *parent_vm, ngx_cycle_t *cycle, lua_pop(L, 2); } + if (lmcf->load_resty_core) { + lua_getglobal(L, "require"); + lua_pushstring(L, "resty.core"); + + rc = lua_pcall(L, 1, 1, 0); + if (rc != 0) { + ngx_log_error(NGX_LOG_ERR, log, 0, + "lua_load_resty_core failed to load the resty.core " + "module from https://github.com/openresty/lua-resty" + "-core; ensure you are using an OpenResty release " + "from https://openresty.org/en/download.html " + "(rc: %i, reason: %s)", rc, lua_tostring(L, -1)); + } + } + return L; } @@ -4041,7 +4146,12 @@ ngx_http_lua_get_raw_phase_context(lua_State *L) ngx_http_request_t *r; ngx_http_lua_ctx_t *ctx; +#ifdef OPENRESTY_LUAJIT + r = lua_getexdata(L); +#else r = lua_touserdata(L, 1); +#endif + if (r == NULL) { return 0; } @@ -4129,4 +4239,32 @@ ngx_http_lua_cleanup_free(ngx_http_request_t *r, ngx_http_cleanup_pt *cleanup) } +#if (NGX_HTTP_LUA_HAVE_SA_RESTART) +void +ngx_http_lua_set_sa_restart(ngx_log_t *log) +{ + int *signo; + int sigs[] = NGX_HTTP_LUA_SA_RESTART_SIGS; + struct sigaction act; + + for (signo = sigs; *signo != 0; signo++) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, + "setting SA_RESTART for signal %d", *signo); + + if (sigaction(*signo, NULL, &act) != 0) { + ngx_log_error(NGX_LOG_WARN, log, ngx_errno, "failed to get " + "sigaction for signal %d", *signo); + } + + act.sa_flags |= SA_RESTART; + + if (sigaction(*signo, &act, NULL) != 0) { + ngx_log_error(NGX_LOG_WARN, log, ngx_errno, "failed to set " + "sigaction for signal %d", *signo); + } + } +} +#endif + + /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_util.h b/debian/modules/http-lua/src/ngx_http_lua_util.h index 7dcc6f7..f08f481 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_util.h +++ b/debian/modules/http-lua/src/ngx_http_lua_util.h @@ -9,6 +9,11 @@ #define _NGX_HTTP_LUA_UTIL_H_INCLUDED_ +#ifdef DDEBUG +#include "ddebug.h" +#endif + + #include "ngx_http_lua_common.h" #include "ngx_http_lua_api.h" @@ -188,7 +193,9 @@ ngx_int_t ngx_http_lua_open_and_stat_file(u_char *name, ngx_chain_t *ngx_http_lua_chain_get_free_buf(ngx_log_t *log, ngx_pool_t *p, ngx_chain_t **free, size_t len); +#ifndef OPENRESTY_LUAJIT void ngx_http_lua_create_new_globals_table(lua_State *L, int narr, int nrec); +#endif int ngx_http_lua_traceback(lua_State *L); @@ -243,6 +250,9 @@ ngx_http_cleanup_t *ngx_http_lua_cleanup_add(ngx_http_request_t *r, void ngx_http_lua_cleanup_free(ngx_http_request_t *r, ngx_http_cleanup_pt *cleanup); +#if (NGX_HTTP_LUA_HAVE_SA_RESTART) +void ngx_http_lua_set_sa_restart(ngx_log_t *log); +#endif #define ngx_http_lua_check_if_abortable(L, ctx) \ if ((ctx)->no_abort) { \ @@ -282,7 +292,9 @@ ngx_http_lua_create_ctx(ngx_http_request_t *r) if (!llcf->enable_code_cache && r->connection->fd != (ngx_socket_t) -1) { lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); +#ifdef DDEBUG dd("lmcf: %p", lmcf); +#endif L = ngx_http_lua_init_vm(lmcf->lua, lmcf->cycle, r->pool, lmcf, r->connection->log, &cln); @@ -323,7 +335,11 @@ ngx_http_lua_get_lua_vm(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx) } lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); + +#ifdef DDEBUG dd("lmcf->lua: %p", lmcf->lua); +#endif + return lmcf->lua; } @@ -334,6 +350,9 @@ ngx_http_lua_get_lua_vm(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx) static ngx_inline ngx_http_request_t * ngx_http_lua_get_req(lua_State *L) { +#ifdef OPENRESTY_LUAJIT + return lua_getexdata(L); +#else ngx_http_request_t *r; lua_getglobal(L, ngx_http_lua_req_key); @@ -341,14 +360,19 @@ ngx_http_lua_get_req(lua_State *L) lua_pop(L, 1); return r; +#endif } static ngx_inline void ngx_http_lua_set_req(lua_State *L, ngx_http_request_t *r) { +#ifdef OPENRESTY_LUAJIT + lua_setexdata(L, (void *) r); +#else lua_pushlightuserdata(L, r); lua_setglobal(L, ngx_http_lua_req_key); +#endif } @@ -387,10 +411,12 @@ ngx_http_lua_hash_str(u_char *src, size_t n) static ngx_inline ngx_int_t -ngx_http_lua_set_content_type(ngx_http_request_t *r) +ngx_http_lua_set_content_type(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx) { ngx_http_lua_loc_conf_t *llcf; + ctx->mime_set = 1; + llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); if (llcf->use_default_type && r->headers_out.status != NGX_HTTP_NOT_MODIFIED) diff --git a/debian/modules/http-lua/src/ngx_http_lua_worker.c b/debian/modules/http-lua/src/ngx_http_lua_worker.c index 461509b..33cfa11 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_worker.c +++ b/debian/modules/http-lua/src/ngx_http_lua_worker.c @@ -153,6 +153,8 @@ ngx_http_lua_ffi_master_pid(void) int ngx_http_lua_ffi_get_process_type(void) { + ngx_core_conf_t *ccf; + #if defined(HAVE_PRIVILEGED_PROCESS_PATCH) && !NGX_WIN32 if (ngx_process == NGX_PROCESS_HELPER) { if (ngx_is_privileged_agent) { @@ -161,6 +163,15 @@ ngx_http_lua_ffi_get_process_type(void) } #endif + if (ngx_process == NGX_PROCESS_SINGLE) { + ccf = (ngx_core_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx, + ngx_core_module); + + if (ccf->master) { + return NGX_PROCESS_MASTER; + } + } + return ngx_process; } diff --git a/debian/modules/http-lua/t/000--init.t b/debian/modules/http-lua/t/000--init.t index dbe2c33..5865755 100644 --- a/debian/modules/http-lua/t/000--init.t +++ b/debian/modules/http-lua/t/000--init.t @@ -10,11 +10,6 @@ $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; $ENV{TEST_NGINX_MYSQL_PORT} ||= 3306; our $http_config = <<'_EOC_'; - upstream database { - drizzle_server 127.0.0.1:$TEST_NGINX_MYSQL_PORT protocol=mysql - dbname=ngx_test user=ngx_test password=ngx_test; - } - lua_package_path "../lua-resty-mysql/lib/?.lua;;"; _EOC_ diff --git a/debian/modules/http-lua/t/001-set.t b/debian/modules/http-lua/t/001-set.t index ba8f22c..9e8ee7b 100644 --- a/debian/modules/http-lua/t/001-set.t +++ b/debian/modules/http-lua/t/001-set.t @@ -4,7 +4,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * (blocks() * 3 + 4); +plan tests => repeat_each() * (blocks() * 3 + 5); #log_level("warn"); no_long_string(); @@ -46,7 +46,7 @@ helloworld === TEST 3: internal only --- config location /lua { - set_by_lua $res "function fib(n) if n > 2 then return fib(n-1)+fib(n-2) else return 1 end end return fib(10)"; + set_by_lua $res "local function fib(n) if n > 2 then return fib(n-1)+fib(n-2) else return 1 end end return fib(10)"; echo $res; } --- request @@ -76,7 +76,7 @@ GET /lua?a=1&b=2 === TEST 5: fib by arg --- config location /fib { - set_by_lua $res "function fib(n) if n > 2 then return fib(n-1)+fib(n-2) else return 1 end end return fib(tonumber(ngx.arg[1]))" $arg_n; + set_by_lua $res "local function fib(n) if n > 2 then return fib(n-1)+fib(n-2) else return 1 end end return fib(tonumber(ngx.arg[1]))" $arg_n; echo $res; } --- request @@ -592,25 +592,30 @@ failed to run set_by_lua*: unknown reason -=== TEST 37: globals get cleared for every single request +=== TEST 37: globals are shared in all requests. --- config location /lua { - set_by_lua $res ' + set_by_lua_block $res { if not foo then foo = 1 else + ngx.log(ngx.INFO, "old foo: ", foo) foo = foo + 1 end return foo - '; + } echo $res; } --- request GET /lua ---- response_body -1 +--- response_body_like chomp +\A[12] +\z --- no_error_log [error] +--- grep_error_log eval: qr/(old foo: \d+|writing a global lua variable \('\w+'\))/ +--- grep_error_log_out eval +["writing a global lua variable \('foo'\)\n", "old foo: 1\n"] @@ -755,6 +760,8 @@ GET /lua?name=jim --- config location /t { set_by_lua $a ' + local bar + local foo function foo() bar() end diff --git a/debian/modules/http-lua/t/002-content.t b/debian/modules/http-lua/t/002-content.t index cc92d6f..bb569f5 100644 --- a/debian/modules/http-lua/t/002-content.t +++ b/debian/modules/http-lua/t/002-content.t @@ -86,7 +86,7 @@ qr/content_by_lua\(nginx\.conf:\d+\):1: attempt to call field 'echo' \(a nil val location /lua { # NOTE: the newline escape sequence must be double-escaped, as nginx config # parser will unescape first! - content_by_lua 'v = ngx.var["request_uri"] ngx.print("request_uri: ", v, "\\n")'; + content_by_lua 'local v = ngx.var["request_uri"] ngx.print("request_uri: ", v, "\\n")'; } --- request GET /lua?a=1&b=2 @@ -102,7 +102,7 @@ request_uri: /lua?a=1&b=2 } --- user_files >>> test.lua -v = ngx.var["request_uri"] +local v = ngx.var["request_uri"] ngx.print("request_uri: ", v, "\n") --- request GET /lua?a=1&b=2 @@ -154,7 +154,7 @@ result: -0.4090441561579 === TEST 7: read $arg_xxx --- config location = /lua { - content_by_lua 'who = ngx.var.arg_who + content_by_lua 'local who = ngx.var.arg_who ngx.print("Hello, ", who, "!")'; } --- request @@ -171,7 +171,7 @@ Hello, agentzh! } location /lua { - content_by_lua 'res = ngx.location.capture("/other"); ngx.print("status=", res.status, " "); ngx.print("body=", res.body)'; + content_by_lua 'local res = ngx.location.capture("/other"); ngx.print("status=", res.status, " "); ngx.print("body=", res.body)'; } --- request GET /lua @@ -183,7 +183,7 @@ status=200 body=hello, world ei= TEST 9: capture non-existed location --- config location /lua { - content_by_lua 'res = ngx.location.capture("/other"); ngx.print("status=", res.status)'; + content_by_lua 'local res = ngx.location.capture("/other"); ngx.print("status=", res.status)'; } --- request GET /lua @@ -194,7 +194,7 @@ GET /lua === TEST 9: invalid capture location (not as expected...) --- config location /lua { - content_by_lua 'res = ngx.location.capture("*(#*"); ngx.say("res=", res.status)'; + content_by_lua 'local res = ngx.location.capture("*(#*"); ngx.say("res=", res.status)'; } --- request GET /lua @@ -247,7 +247,7 @@ GET /lua ngx.print("num is: ", num, "\\n"); if (num > 0) then - res = ngx.location.capture("/recur?num="..tostring(num - 1)); + local res = ngx.location.capture("/recur?num="..tostring(num - 1)); ngx.print("status=", res.status, " "); ngx.print("body=", res.body, "\\n"); else @@ -271,7 +271,7 @@ end ngx.print("num is: ", num, "\\n"); if (num > 0) then - res = ngx.location.capture("/recur?num="..tostring(num - 1)); + local res = ngx.location.capture("/recur?num="..tostring(num - 1)); ngx.print("status=", res.status, " "); ngx.print("body=", res.body); else @@ -353,7 +353,7 @@ location /sub { } location /parent { set $a 12; - content_by_lua 'res = ngx.location.capture("/sub"); ngx.print(res.body)'; + content_by_lua 'local res = ngx.location.capture("/sub"); ngx.print(res.body)'; } --- request GET /parent @@ -369,7 +369,7 @@ location /sub { location /parent { set $a 12; content_by_lua ' - res = ngx.location.capture( + local res = ngx.location.capture( "/sub", { share_all_vars = true } ); @@ -390,7 +390,7 @@ location /sub { } location /parent { content_by_lua ' - res = ngx.location.capture("/sub", { share_all_vars = true }); + local res = ngx.location.capture("/sub", { share_all_vars = true }); ngx.say(ngx.var.a) '; } @@ -408,7 +408,7 @@ location /sub { } location /parent { content_by_lua ' - res = ngx.location.capture("/sub", { share_all_vars = false }); + local res = ngx.location.capture("/sub", { share_all_vars = false }); ngx.say(ngx.var.a) '; } @@ -427,7 +427,7 @@ GET /parent location /lua { content_by_lua ' - res = ngx.location.capture("/other"); + local res = ngx.location.capture("/other"); ngx.say("type: ", res.header["Content-Type"]); '; } @@ -454,7 +454,7 @@ type: foo/bar location /lua { content_by_lua ' - res = ngx.location.capture("/other"); + local res = ngx.location.capture("/other"); ngx.say("type: ", type(res.header["Set-Cookie"])); ngx.say("len: ", #res.header["Set-Cookie"]); ngx.say("value: ", table.concat(res.header["Set-Cookie"], "|")) @@ -482,7 +482,7 @@ value: a|hello, world|foo location /lua { content_by_lua ' - res = ngx.location.capture("/other"); + local res = ngx.location.capture("/other"); ngx.say("type: ", res.header["Content-Type"]); ngx.say("Bar: ", res.header["Bar"]); '; @@ -507,7 +507,7 @@ Bar: Bah location /lua { content_by_lua ' - res = ngx.location.capture("/other"); + local res = ngx.location.capture("/other"); ngx.say("type: ", res.header["Content-Type"]); ngx.say("Bar: ", res.header["Bar"] or "nil"); '; @@ -524,7 +524,7 @@ Bar: nil --- config location /lua { content_by_lua ' - data = "hello, world" + local data = "hello, world" -- ngx.header["Content-Length"] = #data -- ngx.header.content_length = #data ngx.print(data) @@ -742,7 +742,7 @@ true --- config location /lua { content_by_lua ' - data = "hello,\\nworld\\n" + local data = "hello,\\nworld\\n" ngx.header["Content-Length"] = #data ngx.say("hello,") ngx.flush() @@ -801,7 +801,7 @@ world } --- user_files >>> test.lua -v = ngx.var["request_uri"] +local v = ngx.var["request_uri"] ngx.print("request_uri: ", v, "\n") --- request GET /lua?a=1&b=2 diff --git a/debian/modules/http-lua/t/004-require.t b/debian/modules/http-lua/t/004-require.t index 35e04db..17e1d57 100644 --- a/debian/modules/http-lua/t/004-require.t +++ b/debian/modules/http-lua/t/004-require.t @@ -24,7 +24,7 @@ __DATA__ === TEST 1: sanity --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /main { echo_location /load; @@ -85,7 +85,7 @@ hello, foo --- request GET /main --- user_files ---- response_body_like: ^[^;]+/servroot/html/\?.so$ +--- response_body_like: ^[^;]+/servroot(_\d+)?/html/\?\.so$ @@ -100,7 +100,7 @@ GET /main } --- request GET /main ---- response_body_like: ^[^;]+/servroot/html/\?.lua;.+\.lua;$ +--- response_body_like: ^[^;]+/servroot(_\d+)?/html/\?\.lua;(.+\.lua)?;*$ @@ -115,7 +115,7 @@ GET /main } --- request GET /main ---- response_body_like: ^[^;]+/servroot/html/\?.so;.+\.so;$ +--- response_body_like: ^[^;]+/servroot(_\d+)?/html/\?\.so;(.+\.so)?;*$ @@ -130,7 +130,7 @@ GET /main } --- request GET /main ---- response_body_like: ^.+\.lua;[^;]+/servroot/html/\?.lua$ +--- response_body_like: ^(.+\.lua)?;*?[^;]+/servroot(_\d+)?/html/\?\.lua$ @@ -145,7 +145,7 @@ GET /main } --- request GET /main ---- response_body_like: ^.+\.so;[^;]+/servroot/html/\?.so$ +--- response_body_like: ^(.+\.so)?;*?[^;]+/servroot(_\d+)?/html/\?\.so$ diff --git a/debian/modules/http-lua/t/005-exit.t b/debian/modules/http-lua/t/005-exit.t index a5a28b3..a416a75 100644 --- a/debian/modules/http-lua/t/005-exit.t +++ b/debian/modules/http-lua/t/005-exit.t @@ -452,7 +452,7 @@ Hi --- config location /lua { content_by_lua ' - function f () + local function f () ngx.say("hello") ngx.exit(200) end diff --git a/debian/modules/http-lua/t/009-log.t b/debian/modules/http-lua/t/009-log.t index 68c057f..cb3895b 100644 --- a/debian/modules/http-lua/t/009-log.t +++ b/debian/modules/http-lua/t/009-log.t @@ -414,6 +414,8 @@ GET /log --- config location /log { content_by_lua ' + local foo + local bar function foo() bar() end @@ -431,7 +433,7 @@ GET /log --- response_body done --- error_log eval -qr/\[error\] \S+: \S+ \[lua\] content_by_lua\(nginx\.conf:\d+\):7: bar\(\): hello, log12343.14159/ +qr/\[error\] \S+: \S+ \[lua\] content_by_lua\(nginx\.conf:\d+\):9: bar\(\): hello, log12343.14159/ @@ -439,6 +441,8 @@ qr/\[error\] \S+: \S+ \[lua\] content_by_lua\(nginx\.conf:\d+\):7: bar\(\): hell --- config location /log { content_by_lua ' + local foo + local bar function foo() return bar(5) end @@ -461,7 +465,7 @@ GET /log --- response_body done --- error_log eval -qr/\[error\] \S+: \S+ \[lua\] content_by_lua\(nginx\.conf:\d+\):8:(?: foo\(\):)? hello, log12343.14159/ +qr/\[error\] \S+: \S+ \[lua\] content_by_lua\(nginx\.conf:\d+\):10:(?: foo\(\):)? hello, log12343.14159/ @@ -472,6 +476,8 @@ qr/\[error\] \S+: \S+ \[lua\] content_by_lua\(nginx\.conf:\d+\):8:(?: foo\(\):)? } --- user_files >>> test.lua +local foo +local bar function foo() bar() end @@ -488,7 +494,7 @@ GET /log --- response_body done --- error_log eval -qr/\[error\] \S+: \S+ \[lua\] test.lua:6: bar\(\): hello, log12343.14159/ +qr/\[error\] \S+: \S+ \[lua\] test.lua:8: bar\(\): hello, log12343.14159/ diff --git a/debian/modules/http-lua/t/011-md5_bin.t b/debian/modules/http-lua/t/011-md5_bin.t index ae7c974..dc0fd9c 100644 --- a/debian/modules/http-lua/t/011-md5_bin.t +++ b/debian/modules/http-lua/t/011-md5_bin.t @@ -156,7 +156,7 @@ d41d8cd98f00b204e9800998ecf8427e --- config location = /t { content_by_lua ' - s = ngx.md5_bin(45) + local s = ngx.md5_bin(45) s = string.gsub(s, ".", function (c) return string.format("%02x", string.byte(c)) end) diff --git a/debian/modules/http-lua/t/013-base64.t b/debian/modules/http-lua/t/013-base64.t index 1cc27de..d1a8d8b 100644 --- a/debian/modules/http-lua/t/013-base64.t +++ b/debian/modules/http-lua/t/013-base64.t @@ -242,4 +242,4 @@ GET /t --- response_body_like: 500 Internal Server Error --- error_code: 500 --- error_log eval -qr/bad argument \#2 to 'encode_base64' \(boolean expected, got number\)|\[error\] .*? boolean argument only/ +qr/bad argument \#2 to 'encode_base64' \(boolean expected, got number\)|\[error\] .*? bad no_padding: boolean expected, got number/ diff --git a/debian/modules/http-lua/t/014-bugs.t b/debian/modules/http-lua/t/014-bugs.t index 9aadff0..dad084e 100644 --- a/debian/modules/http-lua/t/014-bugs.t +++ b/debian/modules/http-lua/t/014-bugs.t @@ -43,7 +43,7 @@ __DATA__ === TEST 1: sanity --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /load { content_by_lua ' @@ -69,7 +69,7 @@ end === TEST 2: sanity --- http_config -lua_package_path '/home/agentz/rpm/BUILD/lua-yajl-1.1/build/?.so;/home/lz/luax/?.so;./?.so'; +lua_package_cpath '/home/agentz/rpm/BUILD/lua-yajl-1.1/build/?.so;/home/lz/luax/?.so;./?.so'; --- config location = '/report/listBidwordPrices4lzExtra.htm' { content_by_lua ' @@ -112,7 +112,7 @@ GET /report/listBidwordPrices4lzExtra.htm?words=123,156,2532 } location = /main { content_by_lua ' - res = ngx.location.capture("/memc?c=get&k=foo&v=") + local res = ngx.location.capture("/memc?c=get&k=foo&v=") ngx.say("1: ", res.body) res = ngx.location.capture("/memc?c=set&k=foo&v=bar"); @@ -204,7 +204,7 @@ https://github.com/chaoslawful/lua-nginx-module/issues/37 content_by_lua ' -- local yajl = require "yajl" ngx.header["Set-Cookie"] = {} - res = ngx.location.capture("/sub") + local res = ngx.location.capture("/sub") for i,j in pairs(res.header) do ngx.header[i] = j @@ -231,7 +231,7 @@ Set-Cookie: TestCookie2=bar.*" } --- user_files >>> foo.lua -res = {} +local res = {} res = {'good 1', 'good 2', 'good 3'} return ngx.redirect("/somedir/" .. ngx.escape_uri(res[math.random(1,#res)])) --- request @@ -579,7 +579,7 @@ $s -=== TEST 26: unexpected globals sharing by using _G +=== TEST 26: globals sharing by using _G --- config location /test { content_by_lua ' @@ -593,12 +593,12 @@ $s } --- pipelined_requests eval ["GET /test", "GET /test", "GET /test"] ---- response_body eval -["0", "0", "0"] +--- response_body_like eval +[qr/\A[036]\z/, qr/\A[147]\z/, qr/\A[258]\z/] -=== TEST 27: unexpected globals sharing by using _G (set_by_lua*) +=== TEST 27: globals sharing by using _G (set_by_lua*) --- config location /test { set_by_lua $a ' @@ -613,12 +613,12 @@ $s } --- pipelined_requests eval ["GET /test", "GET /test", "GET /test"] ---- response_body eval -["0", "0", "0"] +--- response_body_like eval +[qr/\A[036]\z/, qr/\A[147]\z/, qr/\A[258]\z/] -=== TEST 28: unexpected globals sharing by using _G (log_by_lua*) +=== TEST 28: globals sharing by using _G (log_by_lua*) --- http_config lua_shared_dict log_dict 100k; --- config @@ -633,19 +633,19 @@ $s if _G.t then _G.t = _G.t + 1 else - _G.t = 0 + _G.t = 1 end log_dict:set("cnt", t) '; } --- pipelined_requests eval ["GET /test", "GET /test", "GET /test"] ---- response_body eval -["0", "0", "0"] +--- response_body_like eval +[qr/\A[036]\z/, qr/\A[147]\z/, qr/\A[258]\z/] -=== TEST 29: unexpected globals sharing by using _G (header_filter_by_lua*) +=== TEST 29: globals sharing by using _G (header_filter_by_lua*) --- config location /test { header_filter_by_lua ' @@ -663,12 +663,12 @@ $s } --- pipelined_requests eval ["GET /test", "GET /test", "GET /test"] ---- response_body eval -["0", "0", "0"] +--- response_body_like eval +[qr/\A[036]\z/, qr/\A[147]\z/, qr/\A[258]\z/] -=== TEST 30: unexpected globals sharing by using _G (body_filter_by_lua*) +=== TEST 30: globals sharing by using _G (body_filter_by_lua*) --- config location /test { body_filter_by_lua ' @@ -686,8 +686,9 @@ $s } --- request GET /test ---- response_body -a0 +--- response_body_like eval +qr/\Aa[036] +\z/ --- no_error_log [error] @@ -846,7 +847,7 @@ ok === TEST 37: resolving names with a trailing dot --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /t { resolver $TEST_NGINX_RESOLVER ipv6=off; @@ -864,7 +865,7 @@ GET /t === TEST 38: resolving names with a trailing dot --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua'; + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;'; server { listen 12354; @@ -891,7 +892,7 @@ args: foo=1&bar=2 === TEST 39: lua_code_cache off + setkeepalive --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config lua_code_cache off; location = /t { diff --git a/debian/modules/http-lua/t/016-resp-header.t b/debian/modules/http-lua/t/016-resp-header.t index 72c1e05..e38202b 100644 --- a/debian/modules/http-lua/t/016-resp-header.t +++ b/debian/modules/http-lua/t/016-resp-header.t @@ -8,7 +8,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * (blocks() * 3 + 46); +plan tests => repeat_each() * (blocks() * 3 + 59); #no_diff(); no_long_string(); @@ -630,7 +630,46 @@ Cache-Control: private, no-store -=== TEST 32: set multi values to cache-control and override it with a single value +=== TEST 32: set single value to Link header +--- config + location = /t { + content_by_lua_block { + ngx.header.link = "; rel=preload" + ngx.say("Link: ", ngx.var.sent_http_link) + } + } +--- request +GET /t +--- response_headers +Link: ; rel=preload +--- response_body +Link: ; rel=preload + + + +=== TEST 33: set multi values to Link header +--- config + location = /t { + content_by_lua_block { + ngx.header.link = { + "; rel=preload", + "; rel=preload; as=style" + } + + ngx.say("Link: ", ngx.var.sent_http_link) + } + } +--- request +GET /t +--- response_headers +Link: ; rel=preload, ; rel=preload; as=style +--- response_body_like chop +^Link: ; rel=preload[;,] ; rel=preload; as=style$ +--- skip_nginx: 3: < 1.13.9 + + + +=== TEST 34: set multi values to cache-control and override it with a single value --- config location /lua { content_by_lua ' @@ -650,7 +689,30 @@ Cache-Control: no-cache -=== TEST 33: set multi values to cache-control and override it with multiple values +=== TEST 35: set multi values to Link header and override it with a single value +--- config + location /lua { + content_by_lua_block { + ngx.header.link = { + "; rel=preload", + "; rel=preload; as=style" + } + ngx.header.link = "; rel=preload" + ngx.say("Link: ", ngx.var.sent_http_link) + ngx.say("Link: ", ngx.header.link) + } + } +--- request + GET /lua +--- response_headers +Link: ; rel=preload +--- response_body +Link: ; rel=preload +Link: ; rel=preload + + + +=== TEST 36: set multi values to cache-control and override it with multiple values --- config location /lua { content_by_lua ' @@ -672,7 +734,37 @@ Cache-Control: no-cache[;,] blah[;,] foo$ -=== TEST 34: set the www-authenticate response header +=== TEST 37: set multi values to Link header and override it with multiple values +--- config + location /lua { + content_by_lua_block { + ngx.header.link = { + "; rel=preload", + "; rel=preload; as=style" + } + ngx.header.link = { + "; rel=preload", + "; rel=preload", + "; rel=preload; as=style" + } + ngx.say("Link: ", ngx.var.sent_http_link) + ngx.say("Link: ", table.concat(ngx.header.link, ", ")) + } + } +--- request + GET /lua +--- response_headers +Link: ; rel=preload, ; rel=preload, ; rel=preload; as=style +--- response_body_like chop +^Link: ; rel=preload[;,] ; rel=preload[;,] ; rel=preload; as=style +Link: ; rel=preload[;,] ; rel=preload[;,] ; rel=preload; as=style$ +--- no_error_log +[error] +--- skip_nginx: 4: < 1.13.9 + + + +=== TEST 38: set the www-authenticate response header --- config location /lua { content_by_lua ' @@ -689,7 +781,7 @@ WWW-Authenticate: blah -=== TEST 35: set and clear the www-authenticate response header +=== TEST 39: set and clear the www-authenticate response header --- config location /lua { content_by_lua ' @@ -707,7 +799,7 @@ Foo: nil -=== TEST 36: set multi values to cache-control and override it with multiple values (to reproduce a bug) +=== TEST 40: set multi values to cache-control and override it with multiple values (to reproduce a bug) --- config location /lua { content_by_lua ' @@ -727,7 +819,7 @@ Cache-Control: blah -=== TEST 37: set last-modified and return 304 +=== TEST 41: set last-modified and return 304 --- config location /lua { content_by_lua ' @@ -745,7 +837,7 @@ Last-Modified: Thu, 18 Nov 2010 11:27:35 GMT -=== TEST 38: set last-modified and return 200 +=== TEST 42: set last-modified and return 200 --- config location /lua { content_by_lua ' @@ -764,7 +856,7 @@ Thu, 18 Nov 2010 11:27:35 GMT -=== TEST 39: set response content-encoding header should bypass ngx_http_gzip_filter_module +=== TEST 43: set response content-encoding header should bypass ngx_http_gzip_filter_module --- config default_type text/plain; gzip on; @@ -781,13 +873,16 @@ GET /read --- more_headers Accept-Encoding: gzip --- response_headers -Content-Type: text/plain +Content-Encoding: gzip +--- no_error_log +[error] +http gzip filter --- response_body Hello, world, my dear friend! -=== TEST 40: no transform underscores (write) +=== TEST 44: no transform underscores (write) --- config lua_transform_underscores_in_response_headers off; location = /t { @@ -807,7 +902,7 @@ nil -=== TEST 41: with transform underscores (write) +=== TEST 45: with transform underscores (write) --- config lua_transform_underscores_in_response_headers on; location = /t { @@ -827,7 +922,7 @@ Hello -=== TEST 42: github issue #199: underscores in lua variables +=== TEST 46: github issue #199: underscores in lua variables --- config location /read { content_by_lua ' @@ -860,7 +955,7 @@ something: hello -=== TEST 43: set multiple response header +=== TEST 47: set multiple response header --- config location /read { content_by_lua ' @@ -880,7 +975,7 @@ text/my-plain-50 -=== TEST 44: set multiple response header and then reset and then clear +=== TEST 48: set multiple response header and then reset and then clear --- config location /read { content_by_lua ' @@ -909,7 +1004,7 @@ ok -=== TEST 45: set response content-type header for multiple times +=== TEST 49: set response content-type header for multiple times --- config location /read { content_by_lua ' @@ -927,7 +1022,7 @@ Hi -=== TEST 46: set Last-Modified response header for multiple times +=== TEST 50: set Last-Modified response header for multiple times --- config location /read { content_by_lua ' @@ -945,7 +1040,7 @@ ok -=== TEST 47: set Last-Modified response header and then clear +=== TEST 51: set Last-Modified response header and then clear --- config location /read { content_by_lua ' @@ -963,7 +1058,7 @@ ok -=== TEST 48: github #20: segfault caused by the nasty optimization in the nginx core (write) +=== TEST 52: github #20: segfault caused by the nasty optimization in the nginx core (write) --- config location = /t/ { header_filter_by_lua ' @@ -985,7 +1080,7 @@ Location: http://localhost:$ServerPort/t/ -=== TEST 49: github #20: segfault caused by the nasty optimization in the nginx core (read) +=== TEST 53: github #20: segfault caused by the nasty optimization in the nginx core (read) --- config location = /t/ { header_filter_by_lua ' @@ -1007,7 +1102,7 @@ Location: http://localhost:$ServerPort/t/ -=== TEST 50: github #20: segfault caused by the nasty optimization in the nginx core (read Location) +=== TEST 54: github #20: segfault caused by the nasty optimization in the nginx core (read Location) --- config location = /t/ { header_filter_by_lua ' @@ -1030,7 +1125,7 @@ Foo: /t/ -=== TEST 51: github #20: segfault caused by the nasty optimization in the nginx core (set Foo and read Location) +=== TEST 55: github #20: segfault caused by the nasty optimization in the nginx core (set Foo and read Location) --- config location = /t/ { header_filter_by_lua ' @@ -1054,7 +1149,7 @@ Foo: /t/ -=== TEST 52: case sensitive cache-control header +=== TEST 56: case sensitive cache-control header --- config location /lua { content_by_lua ' @@ -1071,7 +1166,24 @@ Cache-Control: private -=== TEST 53: clear Cache-Control when there was no Cache-Control +=== TEST 57: case sensitive Link header +--- config + location /lua { + content_by_lua_block { + ngx.header["link"] = "; rel=preload" + ngx.say("Link: ", ngx.var.sent_http_link) + } + } +--- request + GET /lua +--- raw_response_headers_like chop +link: ; rel=preload +--- response_body +Link: ; rel=preload + + + +=== TEST 58: clear Cache-Control when there was no Cache-Control --- config location /lua { content_by_lua ' @@ -1088,7 +1200,24 @@ Cache-Control: nil -=== TEST 54: set response content-type header +=== TEST 59: clear Link header when there was no Link +--- config + location /lua { + content_by_lua_block { + ngx.header["Link"] = nil + ngx.say("Link: ", ngx.var.sent_http_link) + } + } +--- request + GET /lua +--- raw_response_headers_unlike eval +qr/Link/i +--- response_body +Link: nil + + + +=== TEST 60: set response content-type header --- config location /read { content_by_lua ' @@ -1107,7 +1236,7 @@ s = content_type -=== TEST 55: set a number header name +=== TEST 61: set a number header name --- config location /lua { content_by_lua ' @@ -1126,7 +1255,7 @@ s = content_type -=== TEST 56: set a number header name (in a table value) +=== TEST 62: set a number header name (in a table value) --- config location /lua { content_by_lua ' @@ -1145,7 +1274,7 @@ foo: 32 -=== TEST 57: random access resp headers +=== TEST 63: random access resp headers --- config location /resp-header { content_by_lua ' @@ -1185,7 +1314,7 @@ bar: baz -=== TEST 58: iterating through raw resp headers +=== TEST 64: iterating through raw resp headers --- config location /resp-header { content_by_lua ' @@ -1221,7 +1350,7 @@ bar: nil -=== TEST 59: removed response headers +=== TEST 65: removed response headers --- config location /resp-header { content_by_lua ' @@ -1254,7 +1383,7 @@ bar: baz -=== TEST 60: built-in Content-Type header +=== TEST 66: built-in Content-Type header --- config location = /t { content_by_lua ' @@ -1287,7 +1416,7 @@ my content_type: text/plain -=== TEST 61: built-in Content-Length header +=== TEST 67: built-in Content-Length header --- config location = /t { content_by_lua ' @@ -1320,7 +1449,7 @@ my content_length: 3 -=== TEST 62: built-in Connection header +=== TEST 68: built-in Connection header --- config location = /t { content_by_lua ' @@ -1351,7 +1480,7 @@ my connection: close -=== TEST 63: built-in Transfer-Encoding header (chunked) +=== TEST 69: built-in Transfer-Encoding header (chunked) --- config location = /t { content_by_lua ' @@ -1383,7 +1512,7 @@ my transfer-encoding: chunked -=== TEST 64: built-in Transfer-Encoding header (none) +=== TEST 70: built-in Transfer-Encoding header (none) --- config location = /t { content_by_lua ' @@ -1416,7 +1545,7 @@ my transfer_encoding: nil -=== TEST 65: set Location (no host) +=== TEST 71: set Location (no host) --- config location = /t { content_by_lua ' @@ -1435,7 +1564,7 @@ Location: /foo/bar -=== TEST 66: set Location (with host) +=== TEST 72: set Location (with host) --- config location = /t { content_by_lua ' @@ -1454,7 +1583,7 @@ Location: http://test.com/foo/bar -=== TEST 67: ngx.header["Content-Type"] with ngx_gzip +=== TEST 73: ngx.header["Content-Type"] with ngx_gzip --- config gzip on; gzip_min_length 1; @@ -1478,7 +1607,7 @@ Content-Type: text/html; charset=utf-8 -=== TEST 68: ngx.header["Content-Type"] with "; blah" +=== TEST 74: ngx.header["Content-Type"] with "; blah" --- config location = /test2 { content_by_lua ' @@ -1498,84 +1627,11 @@ test -=== TEST 69: return the matched content-type instead of default_type ---- http_config -types { - image/png png; -} ---- config -location /set/ { - default_type text/html; - content_by_lua_block { - ngx.say(ngx.header["content-type"]) - } -} ---- request -GET /set/hello.png ---- response_headers -Content-Type: image/png ---- response_body -image/png ---- no_error_log -[error] - - - -=== TEST 70: always return the matched content-type ---- config - location /set/ { - default_type "image/png"; - content_by_lua_block { - ngx.say(ngx.header["content-type"]) - ngx.say(ngx.header["content-type"]) - } - } ---- request -GET /set/hello.png ---- response_headers -Content-Type: image/png ---- response_body -image/png -image/png ---- no_error_log -[error] - - - -=== TEST 71: return the matched content-type after ngx.resp.get_headers() ---- http_config -types { - image/png png; -} ---- config - location /set/ { - default_type text/html; - content_by_lua_block { - local h, err = ngx.resp.get_headers() - if err then - ngx.log(ngx.ERR, "err: ", err) - return ngx.exit(500) - end - - ngx.say(h["content-type"]) - } - } ---- request -GET /set/hello.png ---- response_headers -Content-Type: image/png ---- response_body -image/png ---- no_error_log -[error] - - - -=== TEST 72: exceeding max header limit (default 100) +=== TEST 75: exceeding max header limit (default 100) --- config location /resp-header { content_by_lua_block { - for i = 1, 99 do + for i = 1, 100 do ngx.header["Foo" .. i] = "Foo" end @@ -1605,11 +1661,11 @@ lua exceeding response header limit 101 > 100 -=== TEST 73: NOT exceeding max header limit (default 100) +=== TEST 76: NOT exceeding max header limit (default 100) --- config location /resp-header { content_by_lua_block { - for i = 1, 98 do + for i = 1, 99 do ngx.header["Foo" .. i] = "Foo" end @@ -1637,11 +1693,11 @@ lua exceeding response header limit -=== TEST 74: exceeding max header limit (custom limit, 3) +=== TEST 77: exceeding max header limit (custom limit, 3) --- config location /resp-header { content_by_lua_block { - for i = 1, 2 do + for i = 1, 3 do ngx.header["Foo" .. i] = "Foo" end @@ -1671,11 +1727,11 @@ lua exceeding response header limit 4 > 3 -=== TEST 75: NOT exceeding max header limit (custom limit, 3) +=== TEST 78: NOT exceeding max header limit (custom limit, 3) --- config location /resp-header { content_by_lua_block { - for i = 1, 1 do + for i = 1, 2 do ngx.header["Foo" .. i] = "Foo" end @@ -1699,3 +1755,211 @@ found 3 resp headers --- no_error_log [error] lua exceeding response header limit + + + +=== TEST 79: return nil if Content-Type is not set yet +--- config + location /t { + default_type text/html; + content_by_lua_block { + ngx.log(ngx.WARN, "Content-Type: ", ngx.header["content-type"]) + ngx.say("Content-Type: ", ngx.header["content-type"]) + } + } +--- request +GET /t +--- response_headers +Content-Type: text/html +--- response_body +Content-Type: nil +--- no_error_log +[error] +--- error_log +Content-Type: nil + + + +=== TEST 80: don't generate Content-Type when setting other response header +--- config + location = /backend { + content_by_lua_block { + ngx.say("foo") + } + header_filter_by_lua_block { + ngx.header.content_type = nil + } + } + + location = /t { + default_type text/html; + rewrite_by_lua_block { + ngx.header.blah = "foo" + } + proxy_pass http://127.0.0.1:$TEST_NGINX_SERVER_PORT/backend; + } +--- request +GET /t +--- response_body +foo +--- response_headers +blah: foo +!Content-Type +--- no_error_log +[error] + + + +=== TEST 81: don't generate Content-Type when getting other response header +--- config + location = /backend { + content_by_lua_block { + ngx.say("foo") + } + header_filter_by_lua_block { + ngx.header.content_type = nil + } + } + + location = /t { + default_type text/html; + rewrite_by_lua_block { + local h = ngx.header.content_length + } + proxy_pass http://127.0.0.1:$TEST_NGINX_SERVER_PORT/backend; + } +--- request +GET /t +--- response_body +foo +--- response_headers +!Content-Type +--- no_error_log +[error] + + + +=== TEST 82: don't generate Content-Type when getting it +--- config + location = /backend { + content_by_lua_block { + ngx.say("foo") + } + header_filter_by_lua_block { + ngx.header.content_type = nil + } + } + + location /t { + proxy_pass http://127.0.0.1:$TEST_NGINX_SERVER_PORT/backend; + header_filter_by_lua_block { + ngx.log(ngx.WARN, "Content-Type: ", ngx.header["content-type"]) + } + } +--- request +GET /t +--- response_body +foo +--- response_headers +!Content-Type +--- no_error_log +[error] +--- error_log +Content-Type: nil + + + +=== TEST 83: generate default Content-Type when setting other response header +--- config + location = /t { + default_type text/html; + content_by_lua_block { + ngx.header.blah = "foo" + ngx.say("foo") + } + } +--- request +GET /t +--- response_body +foo +--- response_headers +blah: foo +Content-Type: text/html +--- no_error_log +[error] + + + +=== TEST 84: don't generate Content-Type when calling ngx.resp.get_headers() +--- config + location = /backend { + content_by_lua_block { + ngx.say("foo") + } + header_filter_by_lua_block { + ngx.header.content_type = nil + } + } + + location /t { + proxy_pass http://127.0.0.1:$TEST_NGINX_SERVER_PORT/backend; + header_filter_by_lua_block { + local h, err = ngx.resp.get_headers() + if err then + ngx.log(ngx.ERR, "err: ", err) + return + end + + ngx.log(ngx.WARN, "Content-Type: ", h["content-type"]) + } + } +--- request +GET /t +--- response_body +foo +--- response_headers +!Content-Type +--- no_error_log +[error] +--- error_log +Content-Type: nil + + + +=== TEST 85: don't generate default Content-Type when Content-Type is cleared +--- config + location = /t { + default_type text/html; + content_by_lua_block { + ngx.header["Content-Type"] = nil + ngx.say("foo") + } + } +--- request +GET /t +--- response_body +foo +--- response_headers +!Content-Type +--- no_error_log +[error] + + + +=== TEST 86: don't generate default Content-Type when Content-Type is set +--- config + location = /t { + default_type text/html; + content_by_lua_block { + ngx.header["Content-Type"] = "application/json" + ngx.say("foo") + } + } +--- request +GET /t +--- response_body +foo +--- response_headers +Content-Type: application/json +--- no_error_log +[error] diff --git a/debian/modules/http-lua/t/017-exec.t b/debian/modules/http-lua/t/017-exec.t index 544b8bb..a73e93e 100644 --- a/debian/modules/http-lua/t/017-exec.t +++ b/debian/modules/http-lua/t/017-exec.t @@ -382,7 +382,7 @@ hello --- config location /lua { content_by_lua ' - function f () + local function f () ngx.exec("/hi") end @@ -524,7 +524,7 @@ hello --- config location /main { rewrite_by_lua ' - res = ngx.location.capture("/test_loc"); + local res = ngx.location.capture("/test_loc"); ngx.print("hello, ", res.body) '; content_by_lua return; diff --git a/debian/modules/http-lua/t/020-subrequest.t b/debian/modules/http-lua/t/020-subrequest.t index 658a1d2..5a386db 100644 --- a/debian/modules/http-lua/t/020-subrequest.t +++ b/debian/modules/http-lua/t/020-subrequest.t @@ -32,7 +32,7 @@ __DATA__ location /lua { content_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { method = ngx.HTTP_DELETE }); ngx.print(res.body) @@ -62,7 +62,7 @@ lua http subrequest "/other?" location /lua { content_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { method = ngx.HTTP_DELETE }); ngx.print(res.body) @@ -90,7 +90,7 @@ DELETE location /t { content_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { method = ngx.HTTP_POST }); ngx.print(res.body) @@ -114,7 +114,7 @@ POST location /lua { content_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { method = ngx.HTTP_HEAD }); ngx.print(res.body) @@ -141,7 +141,7 @@ GET /lua location /lua { content_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { method = ngx.HTTP_GET }); ngx.print(res.body) @@ -169,7 +169,7 @@ GET location /lua { content_by_lua ' - res = ngx.location.capture("/foo") + local res = ngx.location.capture("/foo") ngx.print(res.body) '; @@ -196,7 +196,7 @@ GET location /lua { content_by_lua ' - res = ngx.location.capture("/foo", {}) + local res = ngx.location.capture("/foo", {}) ngx.print(res.body) '; @@ -226,7 +226,7 @@ GET location /lua { content_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { method = ngx.HTTP_PUT, body = "hello" }); ngx.print(res.body) @@ -255,7 +255,7 @@ hello location /lua { content_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { method = ngx.HTTP_PUT, body = "hello" }); ngx.print(res.body) @@ -291,7 +291,7 @@ hello location /lua { content_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { method = ngx.HTTP_PUT, body = "hello" }); ngx.print(res.body) @@ -329,7 +329,7 @@ GET location /lua { content_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { method = ngx.HTTP_POST, body = "hello" }); ngx.print(res.body) @@ -362,7 +362,7 @@ hello content_by_lua ' ngx.location.capture("/flush"); - res = ngx.location.capture("/memc"); + local res = ngx.location.capture("/memc"); ngx.say("GET: " .. res.status); res = ngx.location.capture("/memc", @@ -404,7 +404,7 @@ cached: hello ngx.location.capture("/flush", { share_all_vars = true }); - res = ngx.location.capture("/memc", + local res = ngx.location.capture("/memc", { share_all_vars = true }); ngx.say("GET: " .. res.status); @@ -435,7 +435,7 @@ cached: hello location /lua { content_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { args = {} }) ngx.print(res.body) '; @@ -456,7 +456,7 @@ GET /lua location /lua { content_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { args = { ["fo="] = "=>" } }) ngx.print(res.body) '; @@ -478,7 +478,7 @@ fo%3D=%3D%3E location /lua { content_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { args = { ["fo="] = "=>", ["="] = ":" } }) ngx.print(res.body) @@ -503,7 +503,7 @@ GET /lua location /lua { content_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { args = { foo = 3, bar = "hello" } }) ngx.print(res.body) @@ -526,7 +526,7 @@ GET /lua location /lua { content_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { args = { [57] = "hi" } }) ngx.print(res.body) '; @@ -548,7 +548,7 @@ attempt to use a non-string key in the "args" option table location /lua { content_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { args = { "hi" } }) ngx.print(res.body) '; @@ -570,7 +570,7 @@ attempt to use a non-string key in the "args" option table location /lua { content_by_lua ' - res = ngx.location.capture("/foo?a=3", + local res = ngx.location.capture("/foo?a=3", { args = { b = 4 } }) ngx.print(res.body) '; @@ -592,7 +592,7 @@ a=3&b=4 location /lua { content_by_lua ' - res = ngx.location.capture("/foo?a=3", + local res = ngx.location.capture("/foo?a=3", { args = "b=4" }) ngx.print(res.body) '; @@ -685,7 +685,7 @@ https://github.com/chaoslawful/lua-nginx-module/issues/38 location /lua { content_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { method = ngx.HTTP_GET }); ngx.say("header foo: [", res.body, "]") '; @@ -711,7 +711,7 @@ https://github.com/chaoslawful/lua-nginx-module/issues/38 location /lua { content_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { body = "abc" }); ngx.say("header foo: [", res.body, "]") '; @@ -746,8 +746,8 @@ header foo: [bar] } location /main { content_by_lua ' - res1, res2 = ngx.location.capture_multi({{"/a"}, {"/b"}}) - res3 = ngx.location.capture("/c") + local res1, res2 = ngx.location.capture_multi({{"/a"}, {"/b"}}) + local res3 = ngx.location.capture("/c") ngx.print(res1.body, res2.body, res3.body) '; } @@ -780,7 +780,7 @@ lua reuse free buf memory location /lua { content_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { method = ngx.HTTP_POST, body = "hello" }); ngx.print(res.body) @@ -801,7 +801,7 @@ hello --- config location /lua { content_by_lua ' - res = ngx.location.capture("/foo.html") + local res = ngx.location.capture("/foo.html") ngx.say(res.status) ngx.say(res.header["Last-Modified"]) @@ -832,7 +832,7 @@ hello, static file$ location /lua { content_by_lua ' local ctx = {} - res = ngx.location.capture("/sub", { ctx = ctx }) + local res = ngx.location.capture("/sub", { ctx = ctx }) ngx.say(ctx.foo); ngx.say(ngx.ctx.foo); @@ -857,7 +857,7 @@ nil } location /lua { content_by_lua ' - res = ngx.location.capture("/sub", { ctx = ngx.ctx }) + local res = ngx.location.capture("/sub", { ctx = ngx.ctx }) ngx.say(ngx.ctx.foo); '; } @@ -885,7 +885,7 @@ bar location /t { content_by_lua ' - res = ngx.location.capture("/memc", + local res = ngx.location.capture("/memc", { method = ngx.HTTP_PUT, body = "hello 1234" }); -- ngx.say("PUT: " .. res.status); @@ -922,7 +922,7 @@ lua reuse free buf chain, but reallocate memory because location /lua { content_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { method = ngx.HTTP_GET }); ngx.print(res.body) @@ -959,7 +959,7 @@ nil content_by_lua ' ngx.req.read_body() - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { method = ngx.HTTP_GET }); ngx.print(res.body) @@ -996,7 +996,7 @@ nil content_by_lua ' ngx.req.read_body() - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { method = ngx.HTTP_POST }); ngx.print(res.body) @@ -1033,7 +1033,7 @@ hello, world content_by_lua ' ngx.req.read_body() - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { method = ngx.HTTP_PUT }); ngx.print(res.body) @@ -1074,7 +1074,7 @@ lua subrequests cycle while processing "/t" location /lua { content_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { method = ngx.HTTP_OPTIONS }); ngx.print(res.body) @@ -1099,7 +1099,7 @@ OPTIONS location /lua { content_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { method = ngx.HTTP_OPTIONS, body = "hello world" }); ngx.print(res.body) @@ -1151,7 +1151,7 @@ r%5B%5D=http%3A%2F%2Fajax.googleapis.com%3A80%2Fajax%2Flibs%2Fjquery%2F1.7.2%2Fj location /main { content_by_lua ' - res = ngx.location.capture("/sub") + local res = ngx.location.capture("/sub") ngx.say("status: ", res.status) ngx.say("body: ", res.body) '; @@ -1172,7 +1172,7 @@ body: location /main { content_by_lua ' - res = ngx.location.capture("/sub") + local res = ngx.location.capture("/sub") ngx.say("status: ", res.status) ngx.say("body: ", res.body) '; @@ -1196,7 +1196,7 @@ body: location /main { content_by_lua ' - res = ngx.location.capture("/sub") + local res = ngx.location.capture("/sub") ngx.say("status: ", res.status) ngx.say("body: ", res.body) '; @@ -1242,7 +1242,7 @@ F(ngx_http_finalize_request) { location /main { content_by_lua ' - res = ngx.location.capture("/memc") + local res = ngx.location.capture("/memc") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -1312,7 +1312,7 @@ upstream prematurely closed connection location /main { content_by_lua ' - res = ngx.location.capture("/memc") + local res = ngx.location.capture("/memc") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -1385,7 +1385,7 @@ upstream timed out location /main { content_by_lua ' - res = ngx.location.capture("/proxy") + local res = ngx.location.capture("/proxy") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -1445,7 +1445,7 @@ upstream prematurely closed connection location /main { content_by_lua ' - res = ngx.location.capture("/proxy") + local res = ngx.location.capture("/proxy") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -1507,7 +1507,7 @@ upstream timed out location /main { content_by_lua ' - res = ngx.location.capture("/proxy") + local res = ngx.location.capture("/proxy") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -1567,7 +1567,7 @@ truncated: false location /main { content_by_lua ' - res = ngx.location.capture("/proxy") + local res = ngx.location.capture("/proxy") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -1630,7 +1630,7 @@ upstream timed out location /main { content_by_lua ' - res = ngx.location.capture("/proxy") + local res = ngx.location.capture("/proxy") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -1690,7 +1690,7 @@ truncated: false location /main { content_by_lua ' - res = ngx.location.capture("/proxy") + local res = ngx.location.capture("/proxy") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -1756,7 +1756,7 @@ upstream timed out ngx.req.read_body() for i = 1, 2 do - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { method = ngx.HTTP_POST }); ngx.say(res.body) @@ -1796,7 +1796,7 @@ hello world ngx.req.read_body() for i = 1, 2 do - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { method = ngx.HTTP_POST }); ngx.say(res.body) @@ -1836,7 +1836,7 @@ hello world ngx.req.read_body() for i = 1, 2 do - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { method = ngx.HTTP_POST }); ngx.say(res.body) @@ -1916,7 +1916,7 @@ a client request body is buffered to a temporary file location /main { content_by_lua ' - res = ngx.location.capture("/proxy") + local res = ngx.location.capture("/proxy") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -1979,7 +1979,7 @@ upstream prematurely closed connection location /main { content_by_lua ' - res = ngx.location.capture("/proxy") + local res = ngx.location.capture("/proxy") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -2040,7 +2040,7 @@ upstream prematurely closed connection location /main { content_by_lua ' - res = ngx.location.capture("/proxy") + local res = ngx.location.capture("/proxy") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -2102,7 +2102,7 @@ upstream timed out location /main { content_by_lua ' - res = ngx.location.capture("/proxy") + local res = ngx.location.capture("/proxy") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -2160,7 +2160,7 @@ truncated: false location /main { content_by_lua ' - res = ngx.location.capture("/proxy") + local res = ngx.location.capture("/proxy") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -2219,7 +2219,7 @@ truncated: false location /main { content_by_lua ' - res = ngx.location.capture("/proxy") + local res = ngx.location.capture("/proxy") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -2288,7 +2288,7 @@ upstream prematurely closed connection } for i, method in ipairs(methods) do - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { method = method }) ngx.print(res.body) end @@ -2324,7 +2324,7 @@ method: TRACE location /lua { content_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { method = ngx.HTTP_DELETE }); ngx.print(res.body) @@ -2353,7 +2353,7 @@ nil location /lua { content_by_lua ' ngx.req.read_body() - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { method = ngx.HTTP_DELETE, always_forward_body = true }); ngx.print(res.body) @@ -2382,7 +2382,7 @@ hello world location /lua { content_by_lua ' ngx.req.read_body() - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { method = ngx.HTTP_DELETE, always_forward_body = true }); ngx.print(res.body) @@ -2410,7 +2410,7 @@ hello world --- config location = /t { content_by_lua ' - res = ngx.location.capture("/sub") + local res = ngx.location.capture("/sub") ngx.print(res.body) '; } @@ -2603,7 +2603,7 @@ qr/Assertion .*? failed/ location = /t { content_by_lua ' - res = ngx.location.capture("/sub") + local res = ngx.location.capture("/sub") ngx.print(res.body) ngx.say("pr: User-Agent: ", ngx.var.http_user_agent) ngx.say("pr: Host: ", ngx.var.http_host) @@ -2636,7 +2636,7 @@ pr: Host: localhost location = /t { content_by_lua ' - res = ngx.location.capture("/sub") + local res = ngx.location.capture("/sub") ngx.print(res.body) ngx.say("pr: User-Agent: ", ngx.var.http_user_agent) ngx.say("pr: Host: ", ngx.var.http_host) @@ -2669,7 +2669,7 @@ pr: Host: localhost location = /t { content_by_lua ' - res = ngx.location.capture("/sub") + local res = ngx.location.capture("/sub") ngx.print(res.body) ngx.say("pr: User-Agent: ", ngx.var.http_user_agent) ngx.say("pr: Host: ", ngx.var.http_host) @@ -2699,7 +2699,7 @@ pr: Host: localhost location = /t { content_by_lua ' - res = ngx.location.capture("/sub") + local res = ngx.location.capture("/sub") ngx.print(res.body) ngx.say("pr: Cookie: ", ngx.var.http_cookie) '; @@ -2727,7 +2727,7 @@ pr: Cookie: foo; bar location = /t { content_by_lua ' - res = ngx.location.capture("/sub") + local res = ngx.location.capture("/sub") ngx.print(res.body) ngx.say("pr: Cookie: ", ngx.var.http_cookie) '; @@ -2750,7 +2750,7 @@ pr: Cookie: foo; bar --- config location /lua { content_by_lua ' - res = ngx.location.capture("/index.html", + local res = ngx.location.capture("/index.html", { method = ngx.HTTP_HEAD }); ngx.say("content-length: ", res.header["Content-Length"]) ngx.say("body: [", res.body, "]") diff --git a/debian/modules/http-lua/t/023-rewrite/client-abort.t b/debian/modules/http-lua/t/023-rewrite/client-abort.t index 117d17e..0d6f2b3 100644 --- a/debian/modules/http-lua/t/023-rewrite/client-abort.t +++ b/debian/modules/http-lua/t/023-rewrite/client-abort.t @@ -199,7 +199,7 @@ bad things happen location = /sub { proxy_ignore_client_abort on; - proxy_pass http://agentzh.org:12345/; + proxy_pass http://127.0.0.2:12345/; } location = /sleep { @@ -240,7 +240,7 @@ client prematurely closed connection location = /sub { proxy_ignore_client_abort off; - proxy_pass http://agentzh.org:12345/; + proxy_pass http://127.0.0.2:12345/; } --- request GET /t @@ -545,7 +545,7 @@ client prematurely closed connection return end - ok, err = sock:connect("127.0.0.1", $TEST_NGINX_REDIS_PORT) + local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_REDIS_PORT) if not ok then ngx.log(ngx.ERR, "failed to connect: ", err) return diff --git a/debian/modules/http-lua/t/023-rewrite/exec.t b/debian/modules/http-lua/t/023-rewrite/exec.t index edd4607..59691cb 100644 --- a/debian/modules/http-lua/t/023-rewrite/exec.t +++ b/debian/modules/http-lua/t/023-rewrite/exec.t @@ -326,7 +326,7 @@ hello --- config location /main { rewrite_by_lua ' - res = ngx.location.capture("/test_loc"); + local res = ngx.location.capture("/test_loc"); ngx.print("hello, ", res.body) '; content_by_lua return; @@ -354,7 +354,7 @@ hello, bah --- config location /main { rewrite_by_lua ' - res = ngx.location.capture("/test_loc"); + local res = ngx.location.capture("/test_loc"); ngx.print("hello, ", res.body) '; content_by_lua return; diff --git a/debian/modules/http-lua/t/023-rewrite/mixed.t b/debian/modules/http-lua/t/023-rewrite/mixed.t index 0f742b2..5b38d3f 100644 --- a/debian/modules/http-lua/t/023-rewrite/mixed.t +++ b/debian/modules/http-lua/t/023-rewrite/mixed.t @@ -35,7 +35,7 @@ __DATA__ rewrite_by_lua ' ngx.location.capture("/flush"); - res = ngx.location.capture("/memc"); + local res = ngx.location.capture("/memc"); print("rewrite GET: " .. res.status); res = ngx.location.capture("/memc", @@ -49,7 +49,7 @@ __DATA__ content_by_lua ' ngx.location.capture("/flush"); - res = ngx.location.capture("/memc"); + local res = ngx.location.capture("/memc"); ngx.say("content GET: " .. res.status); res = ngx.location.capture("/memc", diff --git a/debian/modules/http-lua/t/023-rewrite/multi-capture.t b/debian/modules/http-lua/t/023-rewrite/multi-capture.t index 083ec78..a0a02b7 100644 --- a/debian/modules/http-lua/t/023-rewrite/multi-capture.t +++ b/debian/modules/http-lua/t/023-rewrite/multi-capture.t @@ -154,7 +154,7 @@ res2.body = b location /main { rewrite_by_lua ' - res = ngx.location.capture("/foo?n=1") + local res = ngx.location.capture("/foo?n=1") ngx.say("top res.status = " .. res.status) ngx.say("top res.body = [" .. res.body .. "]") '; diff --git a/debian/modules/http-lua/t/023-rewrite/req-socket.t b/debian/modules/http-lua/t/023-rewrite/req-socket.t index 87cbbbe..9292385 100644 --- a/debian/modules/http-lua/t/023-rewrite/req-socket.t +++ b/debian/modules/http-lua/t/023-rewrite/req-socket.t @@ -325,7 +325,7 @@ found the end of the stream === TEST 4: attempt to use the req socket across request boundary --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /t { rewrite_by_lua ' @@ -376,7 +376,7 @@ hello world === TEST 5: receive until on request_body - receiveuntil(1) on the last byte of the body See https://groups.google.com/group/openresty/browse_thread/thread/43cf01da3c681aba for details --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /t { rewrite_by_lua ' @@ -440,7 +440,7 @@ done === TEST 6: pipelined POST requests --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /t { rewrite_by_lua ' diff --git a/debian/modules/http-lua/t/023-rewrite/sanity.t b/debian/modules/http-lua/t/023-rewrite/sanity.t index b90aa0e..73a85dc 100644 --- a/debian/modules/http-lua/t/023-rewrite/sanity.t +++ b/debian/modules/http-lua/t/023-rewrite/sanity.t @@ -69,7 +69,7 @@ GET /lua location /lua { # NOTE: the newline escape sequence must be double-escaped, as nginx config # parser will unescape first! - rewrite_by_lua 'v = ngx.var["request_uri"] ngx.print("request_uri: ", v, "\\n")'; + rewrite_by_lua 'local v = ngx.var["request_uri"] ngx.print("request_uri: ", v, "\\n")'; content_by_lua 'ngx.exit(ngx.OK)'; } --- request @@ -87,7 +87,7 @@ request_uri: /lua?a=1&b=2 } --- user_files >>> test.lua -v = ngx.var["request_uri"] +local v = ngx.var["request_uri"] ngx.print("request_uri: ", v, "\n") --- request GET /lua?a=1&b=2 @@ -140,7 +140,7 @@ result: -0.4090441561579 === TEST 7: read $arg_xxx --- config location = /lua { - rewrite_by_lua 'who = ngx.var.arg_who + rewrite_by_lua 'local who = ngx.var.arg_who ngx.print("Hello, ", who, "!")'; content_by_lua 'ngx.exit(ngx.OK)'; } @@ -159,7 +159,7 @@ Hello, agentzh! location /lua { rewrite_by_lua ' -res = ngx.location.capture("/other") +local res = ngx.location.capture("/other") ngx.print("status=", res.status, " ") ngx.print("body=", res.body) '; @@ -175,7 +175,7 @@ status=200 body=hello, world === TEST 9: capture non-existed location --- config location /lua { - rewrite_by_lua 'res = ngx.location.capture("/other"); ngx.print("status=", res.status)'; + rewrite_by_lua 'local res = ngx.location.capture("/other"); ngx.print("status=", res.status)'; content_by_lua 'ngx.exit(ngx.OK)'; } --- request @@ -187,7 +187,7 @@ GET /lua === TEST 10: invalid capture location (not as expected...) --- config location /lua { - rewrite_by_lua 'res = ngx.location.capture("*(#*"); ngx.say("res=", res.status)'; + rewrite_by_lua 'local res = ngx.location.capture("*(#*"); ngx.say("res=", res.status)'; content_by_lua 'ngx.exit(ngx.OK)'; } --- request @@ -270,7 +270,7 @@ end ngx.print("num is: ", num, "\\n"); if (num > 0) then - res = ngx.location.capture("/recur?num="..tostring(num - 1)); + local res = ngx.location.capture("/recur?num="..tostring(num - 1)); ngx.print("status=", res.status, " "); ngx.print("body=", res.body); else @@ -359,7 +359,7 @@ location /sub { } location /parent { set $a 12; - rewrite_by_lua 'res = ngx.location.capture("/sub"); ngx.print(res.body)'; + rewrite_by_lua 'local res = ngx.location.capture("/sub"); ngx.print(res.body)'; content_by_lua 'ngx.exit(ngx.OK)'; } --- request @@ -377,7 +377,7 @@ location /parent { set $a ''; rewrite_by_lua ' ngx.var.a = 12; - res = ngx.location.capture( + local res = ngx.location.capture( "/sub", { share_all_vars = true } ); @@ -399,7 +399,7 @@ location /sub { } location /parent { rewrite_by_lua ' - res = ngx.location.capture("/sub", { share_all_vars = true }); + local res = ngx.location.capture("/sub", { share_all_vars = true }); ngx.say(ngx.var.a) '; @@ -421,7 +421,7 @@ location /sub { location /parent { rewrite_by_lua ' - res = ngx.location.capture("/sub", { share_all_vars = false }); + local res = ngx.location.capture("/sub", { share_all_vars = false }); ngx.say(ngx.var.a) '; content_by_lua return; @@ -441,7 +441,7 @@ GET /parent location /lua { rewrite_by_lua ' - res = ngx.location.capture("/other"); + local res = ngx.location.capture("/other"); ngx.say("type: ", res.header["Content-Type"]); '; @@ -466,7 +466,7 @@ type: foo/bar location /lua { rewrite_by_lua ' - res = ngx.location.capture("/other"); + local res = ngx.location.capture("/other"); ngx.say("type: ", res.header["Content-Type"]); ngx.say("Bar: ", res.header["Bar"]); '; @@ -494,7 +494,7 @@ Bar: Bah location /lua { rewrite_by_lua ' - res = ngx.location.capture("/other"); + local res = ngx.location.capture("/other"); ngx.say("type: ", res.header["Content-Type"]); ngx.say("Bar: ", res.header["Bar"] or "nil"); '; diff --git a/debian/modules/http-lua/t/023-rewrite/socket-keepalive.t b/debian/modules/http-lua/t/023-rewrite/socket-keepalive.t index 489a70f..8b532ea 100644 --- a/debian/modules/http-lua/t/023-rewrite/socket-keepalive.t +++ b/debian/modules/http-lua/t/023-rewrite/socket-keepalive.t @@ -27,7 +27,7 @@ __DATA__ === TEST 1: sanity --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -104,7 +104,7 @@ lua tcp socket get keepalive peer: using connection === TEST 2: free up the whole connection pool if no active connections --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -177,7 +177,7 @@ received: OK === TEST 3: upstream sockets close prematurely --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; keepalive_timeout 100ms; @@ -254,7 +254,7 @@ done === TEST 4: http keepalive --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location /t { @@ -815,7 +815,7 @@ lua tcp socket keepalive timeout: unlimited === TEST 11: sanity (uds) --- http_config eval " - lua_package_path '$::HtmlDir/?.lua;./?.lua'; + lua_package_path '$::HtmlDir/?.lua;./?.lua;;'; server { listen unix:$::HtmlDir/nginx.sock; default_type 'text/plain'; @@ -953,7 +953,7 @@ lua tcp socket get keepalive peer: using connection === TEST 13: github issue #110: ngx.exit with HTTP_NOT_FOUND causes worker process to exit --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config error_page 404 /404.html; location /t { diff --git a/debian/modules/http-lua/t/023-rewrite/subrequest.t b/debian/modules/http-lua/t/023-rewrite/subrequest.t index 5d1e8f0..cb8523c 100644 --- a/debian/modules/http-lua/t/023-rewrite/subrequest.t +++ b/debian/modules/http-lua/t/023-rewrite/subrequest.t @@ -27,7 +27,7 @@ __DATA__ location /lua { rewrite_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { method = ngx.HTTP_DELETE }); ngx.print(res.body) @@ -54,7 +54,7 @@ DELETE location /lua { rewrite_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { method = ngx.HTTP_DELETE }); ngx.print(res.body) @@ -82,7 +82,7 @@ DELETE location /lua { rewrite_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { method = ngx.HTTP_POST }); ngx.print(res.body) @@ -105,7 +105,7 @@ POST location /lua { rewrite_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { method = ngx.HTTP_HEAD }); ngx.print(res.body) @@ -131,7 +131,7 @@ GET /lua location /lua { rewrite_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { method = ngx.HTTP_GET }); ngx.print(res.body) @@ -158,7 +158,7 @@ GET location /lua { rewrite_by_lua ' - res = ngx.location.capture("/foo") + local res = ngx.location.capture("/foo") ngx.print(res.body) '; @@ -184,7 +184,7 @@ GET location /lua { rewrite_by_lua ' - res = ngx.location.capture("/foo", {}) + local res = ngx.location.capture("/foo", {}) ngx.print(res.body) '; @@ -213,7 +213,7 @@ GET location /lua { rewrite_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { method = ngx.HTTP_PUT, body = "hello" }); ngx.print(res.body) @@ -241,7 +241,7 @@ hello location /lua { rewrite_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { method = ngx.HTTP_PUT, body = "hello" }); ngx.print(res.body) @@ -276,7 +276,7 @@ hello location /lua { rewrite_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { method = ngx.HTTP_PUT, body = "hello" }); ngx.print(res.body) @@ -313,7 +313,7 @@ GET location /lua { rewrite_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { method = ngx.HTTP_POST, body = "hello" }); ngx.print(res.body) @@ -345,7 +345,7 @@ hello rewrite_by_lua ' ngx.location.capture("/flush"); - res = ngx.location.capture("/memc"); + local res = ngx.location.capture("/memc"); ngx.say("GET: " .. res.status); res = ngx.location.capture("/memc", @@ -386,7 +386,7 @@ cached: hello ngx.location.capture("/flush", { share_all_vars = true }); - res = ngx.location.capture("/memc", + local res = ngx.location.capture("/memc", { share_all_vars = true }); ngx.say("GET: " .. res.status); @@ -417,7 +417,7 @@ cached: hello location /lua { rewrite_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { args = {} }) ngx.print(res.body) '; @@ -437,7 +437,7 @@ GET /lua location /lua { rewrite_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { args = { ["fo="] = "=>" } }) ngx.print(res.body) '; @@ -458,7 +458,7 @@ fo%3D=%3D%3E location /lua { rewrite_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { args = { ["fo="] = "=>", ["="] = ":" } }) ngx.print(res.body) @@ -480,7 +480,7 @@ GET /lua location /lua { rewrite_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { args = { foo = 3, bar = "hello" } }) ngx.print(res.body) @@ -502,7 +502,7 @@ GET /lua location /lua { rewrite_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { args = { [57] = "hi" } }) ngx.print(res.body) '; @@ -523,7 +523,7 @@ GET /lua location /lua { rewrite_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { args = { "hi" } }) ngx.print(res.body) '; @@ -544,7 +544,7 @@ GET /lua location /lua { rewrite_by_lua ' - res = ngx.location.capture("/foo?a=3", + local res = ngx.location.capture("/foo?a=3", { args = { b = 4 } }) ngx.print(res.body) '; @@ -565,7 +565,7 @@ a=3&b=4 location /lua { rewrite_by_lua ' - res = ngx.location.capture("/foo?a=3", + local res = ngx.location.capture("/foo?a=3", { args = "b=4" }) ngx.print(res.body) '; diff --git a/debian/modules/http-lua/t/023-rewrite/tcp-socket-timeout.t b/debian/modules/http-lua/t/023-rewrite/tcp-socket-timeout.t index 329c045..e713bb5 100644 --- a/debian/modules/http-lua/t/023-rewrite/tcp-socket-timeout.t +++ b/debian/modules/http-lua/t/023-rewrite/tcp-socket-timeout.t @@ -46,7 +46,7 @@ __DATA__ location /t1 { rewrite_by_lua ' local sock = ngx.socket.tcp() - local ok, err = sock:connect("agentzh.org", 12345) + local ok, err = sock:connect("127.0.0.2", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -63,7 +63,7 @@ GET /t1 failed to connect: timeout --- error_log lua tcp socket connect timeout: 100 -lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 +lua tcp socket connect timed out, when connecting to 127.0.0.2:12345 --- timeout: 10 @@ -79,7 +79,7 @@ lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 rewrite_by_lua ' local sock = ngx.socket.tcp() sock:settimeout(150) - local ok, err = sock:connect("agentzh.org", 12345) + local ok, err = sock:connect("127.0.0.2", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -114,7 +114,7 @@ lua tcp socket connect timeout: 150 rewrite_by_lua ' local sock = ngx.socket.tcp() sock:settimeout(nil) - local ok, err = sock:connect("agentzh.org", 12345) + local ok, err = sock:connect("127.0.0.2", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -149,7 +149,7 @@ lua tcp socket connect timeout: 102 rewrite_by_lua ' local sock = ngx.socket.tcp() sock:settimeout(0) - local ok, err = sock:connect("agentzh.org", 12345) + local ok, err = sock:connect("127.0.0.2", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -185,7 +185,7 @@ lua tcp socket connect timeout: 102 rewrite_by_lua ' local sock = ngx.socket.tcp() sock:settimeout(-1) - local ok, err = sock:connect("agentzh.org", 12345) + local ok, err = sock:connect("127.0.0.2", 12345) if not ok then ngx.say("failed to connect: ", err) return diff --git a/debian/modules/http-lua/t/023-rewrite/tcp-socket.t b/debian/modules/http-lua/t/023-rewrite/tcp-socket.t index 41aeab7..5258487 100644 --- a/debian/modules/http-lua/t/023-rewrite/tcp-socket.t +++ b/debian/modules/http-lua/t/023-rewrite/tcp-socket.t @@ -250,11 +250,11 @@ attempt to send data on a closed socket: } --- request GET /t ---- response_body +--- response_body_like connected: 1 request sent: 56 -first line received: HTTP/1.1 200 OK -second line received: Server: openresty +first line received: HTTP\/1\.1 200 OK +second line received: (?:Date|Server): .*? --- no_error_log [error] @@ -304,7 +304,7 @@ qr/connect\(\) failed \(\d+: Connection refused\)/ location /test { rewrite_by_lua ' local sock = ngx.socket.tcp() - local ok, err = sock:connect("agentzh.org", 12345) + local ok, err = sock:connect("127.0.0.2", 12345) ngx.say("connect: ", ok, " ", err) local bytes @@ -329,7 +329,7 @@ send: nil closed receive: nil closed close: nil closed --- error_log -lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 +lua tcp socket connect timed out, when connecting to 127.0.0.2:12345 --- timeout: 10 @@ -940,7 +940,7 @@ close: 1 nil end end - ok, err = sock:close() + local ok, err = sock:close() ngx.say("close: ", ok, " ", err) '; @@ -1082,7 +1082,7 @@ close: 1 nil === TEST 19: cannot survive across request boundary (send) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location /t { @@ -1143,7 +1143,7 @@ received: OK|failed to send request: closed)\$" === TEST 20: cannot survive across request boundary (receive) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location /t { @@ -1214,7 +1214,7 @@ received: OK|failed to receive a line: closed \[nil\])$/ === TEST 21: cannot survive across request boundary (close) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location /t { @@ -1285,7 +1285,7 @@ received: OK|failed to close: closed)$/ === TEST 22: cannot survive across request boundary (connect) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location /t { @@ -2041,7 +2041,7 @@ close: 1 nil === TEST 33: bad request tries to connect --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location = /main { @@ -2097,7 +2097,7 @@ qr/runtime error: rewrite_by_lua\(nginx\.conf:\d+\):7: bad request/ === TEST 34: bad request tries to receive --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location = /main { @@ -2156,7 +2156,7 @@ qr/runtime error: rewrite_by_lua\(nginx\.conf:\d+\):14: bad request/ === TEST 35: bad request tries to send --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location = /main { @@ -2215,7 +2215,7 @@ qr/runtime error: rewrite_by_lua\(nginx\.conf:\d+\):14: bad request/ === TEST 36: bad request tries to close --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location = /main { @@ -2274,7 +2274,7 @@ qr/runtime error: rewrite_by_lua\(nginx\.conf:\d+\):14: bad request/ === TEST 37: bad request tries to set keepalive --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location = /main { @@ -2333,7 +2333,7 @@ qr/runtime error: rewrite_by_lua\(nginx\.conf:\d+\):14: bad request/ === TEST 38: bad request tries to receiveuntil --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location = /main { diff --git a/debian/modules/http-lua/t/023-rewrite/uthread-exec.t b/debian/modules/http-lua/t/023-rewrite/uthread-exec.t index 2bea7e7..9428bd6 100644 --- a/debian/modules/http-lua/t/023-rewrite/uthread-exec.t +++ b/debian/modules/http-lua/t/023-rewrite/uthread-exec.t @@ -23,7 +23,7 @@ __DATA__ --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.exec("/foo") end @@ -59,7 +59,7 @@ i am foo --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.exec("/foo") end @@ -95,7 +95,7 @@ i am foo --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.exec("/foo") end @@ -178,12 +178,12 @@ hello foo --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.exec("/foo") end - function g() + local function g() ngx.sleep(1) end @@ -270,7 +270,7 @@ hello foo location /lua { client_body_timeout 12000ms; rewrite_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.exec("/foo") end diff --git a/debian/modules/http-lua/t/023-rewrite/uthread-exit.t b/debian/modules/http-lua/t/023-rewrite/uthread-exit.t index 6ebbb67..e25f7f8 100644 --- a/debian/modules/http-lua/t/023-rewrite/uthread-exit.t +++ b/debian/modules/http-lua/t/023-rewrite/uthread-exit.t @@ -24,7 +24,7 @@ __DATA__ --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.exit(0) end @@ -87,7 +87,7 @@ hello in thread --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -172,13 +172,13 @@ after --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.say("f") ngx.exit(0) end - function g() + local function g() ngx.sleep(1) ngx.say("g") end @@ -262,7 +262,7 @@ f --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.say("exiting the user thread") ngx.exit(0) @@ -298,10 +298,10 @@ exiting the user thread === TEST 5: exit in user thread (entry thread is still pending on the DNS resolver for ngx.socket.tcp) --- config location /lua { - resolver agentzh.org; + resolver 127.0.0.2:12345; resolver_timeout 12s; rewrite_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.001) ngx.exit(0) @@ -311,7 +311,7 @@ exiting the user thread ngx.thread.spawn(f) ngx.say("after") local sock = ngx.socket.tcp() - local ok, err = sock:connect("agentzh.org", 12345) + local ok, err = sock:connect("127.0.0.2", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -403,11 +403,11 @@ after === TEST 6: exit in user thread (entry thread is still pending on the DNS resolver for ngx.socket.udp) --- config location /lua { - resolver agentzh.org; + resolver 127.0.0.2:12345; #resolver 127.0.0.1; resolver_timeout 12s; rewrite_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.001) ngx.exit(0) @@ -510,7 +510,7 @@ after --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -521,7 +521,7 @@ after ngx.say("after") local sock = ngx.socket.tcp() sock:settimeout(12000) - local ok, err = sock:connect("172.105.207.225", 12345) + local ok, err = sock:connect("127.0.0.2", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -600,7 +600,7 @@ after --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -700,7 +700,7 @@ after --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -806,7 +806,7 @@ after --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -901,7 +901,7 @@ after --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -995,7 +995,7 @@ after location /lua { client_body_timeout 12000ms; rewrite_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -1080,7 +1080,7 @@ after location /lua { client_body_timeout 12000ms; rewrite_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -1164,7 +1164,7 @@ attempt to abort with pending subrequests location /lua { client_body_timeout 12000ms; rewrite_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.exit(0) end @@ -1247,7 +1247,7 @@ attempt to abort with pending subrequests location /lua { client_body_timeout 12000ms; rewrite_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.exit(0) end diff --git a/debian/modules/http-lua/t/023-rewrite/uthread-redirect.t b/debian/modules/http-lua/t/023-rewrite/uthread-redirect.t index 83de1a3..0e636f7 100644 --- a/debian/modules/http-lua/t/023-rewrite/uthread-redirect.t +++ b/debian/modules/http-lua/t/023-rewrite/uthread-redirect.t @@ -25,7 +25,7 @@ __DATA__ location /lua { client_body_timeout 12000ms; rewrite_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.redirect(301) end @@ -113,7 +113,7 @@ attempt to abort with pending subrequests --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.redirect(301) end diff --git a/debian/modules/http-lua/t/023-rewrite/uthread-spawn.t b/debian/modules/http-lua/t/023-rewrite/uthread-spawn.t index 5552107..dccef87 100644 --- a/debian/modules/http-lua/t/023-rewrite/uthread-spawn.t +++ b/debian/modules/http-lua/t/023-rewrite/uthread-spawn.t @@ -23,7 +23,7 @@ __DATA__ --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.say("hello in thread") end @@ -68,11 +68,11 @@ after --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.say("in thread 1") end - function g() + local function g() ngx.say("in thread 2") end @@ -117,7 +117,7 @@ after 2 --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.say("before sleep") ngx.sleep(0.1) ngx.say("after sleep") @@ -154,13 +154,13 @@ after sleep --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.say("1: before sleep") ngx.sleep(0.2) ngx.say("1: after sleep") end - function g() + local function g() ngx.say("2: before sleep") ngx.sleep(0.1) ngx.say("2: after sleep") @@ -210,7 +210,7 @@ delete thread 2 --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.blah() end @@ -241,9 +241,9 @@ qr/lua user thread aborted: runtime error: rewrite_by_lua\(nginx\.conf:\d+\):3: --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.say("before capture") - res = ngx.location.capture("/proxy") + local res = ngx.location.capture("/proxy") ngx.say("after capture: ", res.body) end @@ -287,7 +287,7 @@ after capture: hello world --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.say("before capture") local res = ngx.location.capture("/proxy?foo") ngx.say("after capture: ", res.body) @@ -340,7 +340,7 @@ after capture: hello foo --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.say("before capture") local res = ngx.location.capture("/proxy?foo") ngx.say("after capture: ", res.body) @@ -394,13 +394,13 @@ capture: hello bar --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.say("f: before capture") local res = ngx.location.capture("/proxy?foo") ngx.say("f: after capture: ", res.body) end - function g() + local function g() ngx.say("g: before capture") local res = ngx.location.capture("/proxy?bah") ngx.say("g: after capture: ", res.body) @@ -472,7 +472,8 @@ g: after capture: hello bah --- config location /lua { rewrite_by_lua ' - function f() + local g + local function f() ngx.say("before g") ngx.thread.spawn(g) ngx.say("after g") @@ -518,7 +519,8 @@ after g --- config location /lua { rewrite_by_lua ' - function f() + local g + local function f() ngx.say("before g") ngx.thread.spawn(g) ngx.say("after g") @@ -566,7 +568,7 @@ hello in g() location /lua { rewrite_by_lua ' local co - function f() + local function f() co = coroutine.running() ngx.sleep(0.1) end @@ -599,7 +601,7 @@ status: running location /lua { rewrite_by_lua ' local co - function f() + local function f() co = coroutine.running() end @@ -631,7 +633,8 @@ status: zombie location /lua { rewrite_by_lua ' local co - function f() + local g + local function f() co = coroutine.running() local co2 = coroutine.create(g) coroutine.resume(co2) @@ -670,7 +673,8 @@ status: normal --- config location /lua { rewrite_by_lua ' - function f() + local g + local function f() ngx.say("before g") ngx.thread.spawn(g) ngx.say("after g") @@ -717,7 +721,7 @@ after f rewrite_by_lua ' local yield = coroutine.yield - function f() + local function f() local self = coroutine.running() ngx.say("f 1") yield(self) @@ -770,7 +774,7 @@ f 3 rewrite_by_lua ' local yield = coroutine.yield - function f() + local function f() local self = coroutine.running() ngx.say("f 1") yield(self) @@ -779,7 +783,7 @@ f 3 ngx.say("f 3") end - function g() + local function g() local self = coroutine.running() ngx.say("g 1") yield(self) @@ -826,7 +830,7 @@ g 3 --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.say("hello in thread") coroutine.yield(coroutine.running) ngx.flush(true) @@ -863,12 +867,12 @@ after --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.say("hello from f") ngx.flush(true) end - function g() + local function g() ngx.say("hello from g") ngx.flush(true) end @@ -914,7 +918,7 @@ hello from g --- config location /lua { rewrite_by_lua ' - function f() + local function f() local sock = ngx.socket.tcp() local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_MEMCACHED_PORT) if not ok then @@ -966,7 +970,7 @@ received: OK --- config location /lua { rewrite_by_lua ' - function f() + local function f() local sock = ngx.socket.udp() local ok, err = sock:setpeername("127.0.0.1", 12345) local bytes, err = sock:send("blah") @@ -1027,7 +1031,7 @@ after)$ --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.req.read_body() local body = ngx.req.get_body_data() ngx.say("body: ", body) @@ -1073,7 +1077,7 @@ body: hello world)$ --- config location /lua { rewrite_by_lua ' - function f() + local function f() local sock = ngx.req.socket() local body, err = sock:receive(11) if not body then diff --git a/debian/modules/http-lua/t/024-access/client-abort.t b/debian/modules/http-lua/t/024-access/client-abort.t index c16f4ea..83bf0a4 100644 --- a/debian/modules/http-lua/t/024-access/client-abort.t +++ b/debian/modules/http-lua/t/024-access/client-abort.t @@ -200,7 +200,7 @@ bad things happen location = /sub { proxy_ignore_client_abort on; - proxy_pass http://agentzh.org:12345/; + proxy_pass http://127.0.0.2:12345/; } location = /sleep { @@ -241,7 +241,7 @@ client prematurely closed connection location = /sub { proxy_ignore_client_abort off; - proxy_pass http://agentzh.org:12345/; + proxy_pass http://127.0.0.2:12345/; } --- request GET /t @@ -546,7 +546,7 @@ client prematurely closed connection return end - ok, err = sock:connect("127.0.0.1", $TEST_NGINX_REDIS_PORT) + local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_REDIS_PORT) if not ok then ngx.log(ngx.ERR, "failed to connect: ", err) return diff --git a/debian/modules/http-lua/t/024-access/exec.t b/debian/modules/http-lua/t/024-access/exec.t index 43c1a77..d168a47 100644 --- a/debian/modules/http-lua/t/024-access/exec.t +++ b/debian/modules/http-lua/t/024-access/exec.t @@ -326,7 +326,7 @@ hello --- config location /main { access_by_lua ' - res = ngx.location.capture("/test_loc"); + local res = ngx.location.capture("/test_loc"); ngx.print("hello, ", res.body) '; content_by_lua return; diff --git a/debian/modules/http-lua/t/024-access/mixed.t b/debian/modules/http-lua/t/024-access/mixed.t index a9f8039..22f0037 100644 --- a/debian/modules/http-lua/t/024-access/mixed.t +++ b/debian/modules/http-lua/t/024-access/mixed.t @@ -35,7 +35,7 @@ __DATA__ access_by_lua ' ngx.location.capture("/flush"); - res = ngx.location.capture("/memc"); + local res = ngx.location.capture("/memc"); print("access GET: ", res.status); res = ngx.location.capture("/memc", @@ -49,7 +49,7 @@ __DATA__ content_by_lua ' ngx.location.capture("/flush"); - res = ngx.location.capture("/memc"); + local res = ngx.location.capture("/memc"); ngx.say("content GET: " .. res.status); res = ngx.location.capture("/memc", @@ -187,7 +187,7 @@ world\x03\x04\xff rewrite_by_lua ' ngx.location.capture("/flush"); - res = ngx.location.capture("/memc"); + local res = ngx.location.capture("/memc"); print("rewrite GET: " .. res.status); res = ngx.location.capture("/memc", @@ -201,7 +201,7 @@ world\x03\x04\xff access_by_lua ' ngx.location.capture("/flush"); - res = ngx.location.capture("/memc"); + local res = ngx.location.capture("/memc"); print("access GET: " .. res.status); res = ngx.location.capture("/memc", @@ -215,7 +215,7 @@ world\x03\x04\xff content_by_lua ' ngx.location.capture("/flush"); - res = ngx.location.capture("/memc"); + local res = ngx.location.capture("/memc"); ngx.say("content GET: " .. res.status); res = ngx.location.capture("/memc", diff --git a/debian/modules/http-lua/t/024-access/multi-capture.t b/debian/modules/http-lua/t/024-access/multi-capture.t index 930b74d..b1757dd 100644 --- a/debian/modules/http-lua/t/024-access/multi-capture.t +++ b/debian/modules/http-lua/t/024-access/multi-capture.t @@ -154,7 +154,7 @@ res2.body = b location /main { access_by_lua ' - res = ngx.location.capture("/foo?n=1") + local res = ngx.location.capture("/foo?n=1") ngx.say("top res.status = " .. res.status) ngx.say("top res.body = [" .. res.body .. "]") '; diff --git a/debian/modules/http-lua/t/024-access/sanity.t b/debian/modules/http-lua/t/024-access/sanity.t index 7ff177f..e5612a8 100644 --- a/debian/modules/http-lua/t/024-access/sanity.t +++ b/debian/modules/http-lua/t/024-access/sanity.t @@ -69,7 +69,7 @@ GET /lua location /lua { # NOTE: the newline escape sequence must be double-escaped, as nginx config # parser will unescape first! - access_by_lua 'v = ngx.var["request_uri"] ngx.print("request_uri: ", v, "\\n")'; + access_by_lua 'local v = ngx.var["request_uri"] ngx.print("request_uri: ", v, "\\n")'; content_by_lua 'ngx.exit(ngx.OK)'; } --- request @@ -87,7 +87,7 @@ request_uri: /lua?a=1&b=2 } --- user_files >>> test.lua -v = ngx.var["request_uri"] +local v = ngx.var["request_uri"] ngx.print("request_uri: ", v, "\n") --- request GET /lua?a=1&b=2 @@ -140,7 +140,7 @@ result: -0.4090441561579 === TEST 7: read $arg_xxx --- config location = /lua { - access_by_lua 'who = ngx.var.arg_who + access_by_lua 'local who = ngx.var.arg_who ngx.print("Hello, ", who, "!")'; content_by_lua 'ngx.exit(ngx.OK)'; } @@ -159,7 +159,7 @@ Hello, agentzh! location /lua { access_by_lua ' -res = ngx.location.capture("/other") +local res = ngx.location.capture("/other") ngx.print("status=", res.status, " ") ngx.print("body=", res.body) '; @@ -175,7 +175,7 @@ status=200 body=hello, world === TEST 9: capture non-existed location --- config location /lua { - access_by_lua 'res = ngx.location.capture("/other"); ngx.print("status=", res.status)'; + access_by_lua 'local res = ngx.location.capture("/other"); ngx.print("status=", res.status)'; content_by_lua 'ngx.exit(ngx.OK)'; } --- request @@ -187,7 +187,7 @@ GET /lua === TEST 10: invalid capture location (not as expected...) --- config location /lua { - access_by_lua 'res = ngx.location.capture("*(#*"); ngx.say("res=", res.status)'; + access_by_lua 'local res = ngx.location.capture("*(#*"); ngx.say("res=", res.status)'; content_by_lua 'ngx.exit(ngx.OK)'; } --- request @@ -244,7 +244,7 @@ GET /lua ngx.print("num is: ", num, "\\n"); if (num > 0) then - res = ngx.location.capture("/recur?num="..tostring(num - 1)); + local res = ngx.location.capture("/recur?num="..tostring(num - 1)); ngx.print("status=", res.status, " "); ngx.print("body=", res.body, "\\n"); else @@ -271,7 +271,7 @@ access phase not running in subrequests ngx.print("num is: ", num, "\\n"); if (num > 0) then - res = ngx.location.capture("/recur?num="..tostring(num - 1)); + local res = ngx.location.capture("/recur?num="..tostring(num - 1)); ngx.print("status=", res.status, " "); ngx.print("body=", res.body); else @@ -357,7 +357,7 @@ location /sub { } location /parent { set $a 12; - access_by_lua 'res = ngx.location.capture("/sub"); ngx.print(res.body)'; + access_by_lua 'local res = ngx.location.capture("/sub"); ngx.print(res.body)'; content_by_lua 'ngx.exit(ngx.OK)'; } --- request @@ -375,7 +375,7 @@ location /parent { set $a ''; access_by_lua ' ngx.var.a = 12; - res = ngx.location.capture( + local res = ngx.location.capture( "/sub", { share_all_vars = true } ); @@ -397,7 +397,7 @@ location /sub { } location /parent { access_by_lua ' - res = ngx.location.capture("/sub", { share_all_vars = true }); + local res = ngx.location.capture("/sub", { share_all_vars = true }); ngx.say(ngx.var.a) '; @@ -419,7 +419,7 @@ location /sub { location /parent { access_by_lua ' - res = ngx.location.capture("/sub", { share_all_vars = false }); + local res = ngx.location.capture("/sub", { share_all_vars = false }); ngx.say(ngx.var.a) '; content_by_lua return; @@ -439,7 +439,7 @@ GET /parent location /lua { access_by_lua ' - res = ngx.location.capture("/other"); + local res = ngx.location.capture("/other"); ngx.say("type: ", res.header["Content-Type"]); '; @@ -464,7 +464,7 @@ type: foo/bar location /lua { access_by_lua ' - res = ngx.location.capture("/other"); + local res = ngx.location.capture("/other"); ngx.say("type: ", res.header["Content-Type"]); ngx.say("Bar: ", res.header["Bar"]); '; @@ -492,7 +492,7 @@ Bar: Bah location /lua { access_by_lua ' - res = ngx.location.capture("/other"); + local res = ngx.location.capture("/other"); ngx.say("type: ", res.header["Content-Type"]); ngx.say("Bar: ", res.header["Bar"] or "nil"); '; diff --git a/debian/modules/http-lua/t/024-access/subrequest.t b/debian/modules/http-lua/t/024-access/subrequest.t index b6ccf11..665780a 100644 --- a/debian/modules/http-lua/t/024-access/subrequest.t +++ b/debian/modules/http-lua/t/024-access/subrequest.t @@ -27,7 +27,7 @@ __DATA__ location /lua { access_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { method = ngx.HTTP_DELETE }); ngx.print(res.body) @@ -54,7 +54,7 @@ DELETE location /lua { access_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { method = ngx.HTTP_DELETE }); ngx.print(res.body) @@ -82,7 +82,7 @@ DELETE location /lua { access_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { method = ngx.HTTP_POST }); ngx.print(res.body) @@ -105,7 +105,7 @@ POST location /lua { access_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { method = ngx.HTTP_HEAD }); ngx.print(res.body) @@ -131,7 +131,7 @@ GET /lua location /lua { access_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { method = ngx.HTTP_GET }); ngx.print(res.body) @@ -158,7 +158,7 @@ GET location /lua { access_by_lua ' - res = ngx.location.capture("/foo") + local res = ngx.location.capture("/foo") ngx.print(res.body) '; @@ -184,7 +184,7 @@ GET location /lua { access_by_lua ' - res = ngx.location.capture("/foo", {}) + local res = ngx.location.capture("/foo", {}) ngx.print(res.body) '; @@ -213,7 +213,7 @@ GET location /lua { access_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { method = ngx.HTTP_PUT, body = "hello" }); ngx.print(res.body) @@ -241,7 +241,7 @@ hello location /lua { access_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { method = ngx.HTTP_PUT, body = "hello" }); ngx.print(res.body) @@ -276,7 +276,7 @@ hello location /lua { access_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { method = ngx.HTTP_PUT, body = "hello" }); ngx.print(res.body) @@ -313,7 +313,7 @@ GET location /lua { access_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { method = ngx.HTTP_POST, body = "hello" }); ngx.print(res.body) @@ -345,7 +345,7 @@ hello access_by_lua ' ngx.location.capture("/flush"); - res = ngx.location.capture("/memc"); + local res = ngx.location.capture("/memc"); ngx.say("GET: " .. res.status); res = ngx.location.capture("/memc", @@ -386,7 +386,7 @@ cached: hello ngx.location.capture("/flush", { share_all_vars = true }); - res = ngx.location.capture("/memc", + local res = ngx.location.capture("/memc", { share_all_vars = true }); ngx.say("GET: " .. res.status); @@ -417,7 +417,7 @@ cached: hello location /lua { access_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { args = {} }) ngx.print(res.body) '; @@ -437,7 +437,7 @@ GET /lua location /lua { access_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { args = { ["fo="] = "=>" } }) ngx.print(res.body) '; @@ -458,7 +458,7 @@ fo%3D=%3D%3E location /lua { access_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { args = { ["fo="] = "=>", ["="] = ":" } }) ngx.print(res.body) @@ -480,7 +480,7 @@ GET /lua location /lua { access_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { args = { foo = 3, bar = "hello" } }) ngx.print(res.body) @@ -502,7 +502,7 @@ GET /lua location /lua { access_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { args = { [57] = "hi" } }) ngx.print(res.body) '; @@ -523,7 +523,7 @@ GET /lua location /lua { access_by_lua ' - res = ngx.location.capture("/foo", + local res = ngx.location.capture("/foo", { args = { "hi" } }) ngx.print(res.body) '; @@ -544,7 +544,7 @@ GET /lua location /lua { access_by_lua ' - res = ngx.location.capture("/foo?a=3", + local res = ngx.location.capture("/foo?a=3", { args = { b = 4 } }) ngx.print(res.body) '; @@ -565,7 +565,7 @@ a=3&b=4 location /lua { access_by_lua ' - res = ngx.location.capture("/foo?a=3", + local res = ngx.location.capture("/foo?a=3", { args = "b=4" }) ngx.print(res.body) '; diff --git a/debian/modules/http-lua/t/024-access/uthread-exec.t b/debian/modules/http-lua/t/024-access/uthread-exec.t index 7add3d4..9c88eb3 100644 --- a/debian/modules/http-lua/t/024-access/uthread-exec.t +++ b/debian/modules/http-lua/t/024-access/uthread-exec.t @@ -23,7 +23,7 @@ __DATA__ --- config location /lua { access_by_lua ' - function f() + local function f() ngx.exec("/foo") end @@ -59,7 +59,7 @@ i am foo --- config location /lua { access_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.exec("/foo") end @@ -95,7 +95,7 @@ i am foo --- config location /lua { access_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.exec("/foo") end @@ -179,12 +179,12 @@ hello foo --- config location /lua { access_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.exec("/foo") end - function g() + local function g() ngx.sleep(1) end @@ -271,7 +271,7 @@ hello foo location /lua { client_body_timeout 12000ms; access_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.exec("/foo") end diff --git a/debian/modules/http-lua/t/024-access/uthread-exit.t b/debian/modules/http-lua/t/024-access/uthread-exit.t index 02c2a1f..2757237 100644 --- a/debian/modules/http-lua/t/024-access/uthread-exit.t +++ b/debian/modules/http-lua/t/024-access/uthread-exit.t @@ -24,7 +24,7 @@ __DATA__ --- config location /lua { access_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.exit(0) end @@ -87,7 +87,7 @@ hello in thread --- config location /lua { access_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -172,13 +172,13 @@ after --- config location /lua { access_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.say("f") ngx.exit(0) end - function g() + local function g() ngx.sleep(1) ngx.say("g") end @@ -262,7 +262,7 @@ f --- config location /lua { access_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.say("exiting the user thread") ngx.exit(0) @@ -298,10 +298,10 @@ exiting the user thread === TEST 5: exit in user thread (entry thread is still pending on the DNS resolver for ngx.socket.tcp) --- config location /lua { - resolver agentzh.org; + resolver 127.0.0.2:12345; resolver_timeout 12s; access_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.001) ngx.exit(0) @@ -394,10 +394,10 @@ after === TEST 6: exit in user thread (entry thread is still pending on the DNS resolver for ngx.socket.udp) --- config location /lua { - resolver agentzh.org; + resolver 127.0.0.2:12345; resolver_timeout 12s; access_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.001) ngx.exit(0) @@ -491,7 +491,7 @@ after --- config location /lua { access_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -502,7 +502,7 @@ after ngx.say("after") local sock = ngx.socket.tcp() sock:settimeout(12000) - local ok, err = sock:connect("172.105.207.225", 12345) + local ok, err = sock:connect("127.0.0.2", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -582,7 +582,7 @@ after --- config location /lua { access_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -682,7 +682,7 @@ after --- config location /lua { access_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -788,7 +788,7 @@ after --- config location /lua { access_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -883,7 +883,7 @@ after --- config location /lua { access_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -977,7 +977,7 @@ after location /lua { client_body_timeout 12000ms; access_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -1062,7 +1062,7 @@ after location /lua { client_body_timeout 12000ms; access_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -1146,7 +1146,7 @@ attempt to abort with pending subrequests location /lua { client_body_timeout 12000ms; access_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.exit(0) end @@ -1229,7 +1229,7 @@ attempt to abort with pending subrequests location /lua { client_body_timeout 12000ms; access_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.exit(0) end diff --git a/debian/modules/http-lua/t/024-access/uthread-redirect.t b/debian/modules/http-lua/t/024-access/uthread-redirect.t index 4eb4759..cb99a35 100644 --- a/debian/modules/http-lua/t/024-access/uthread-redirect.t +++ b/debian/modules/http-lua/t/024-access/uthread-redirect.t @@ -25,7 +25,7 @@ __DATA__ location /lua { client_body_timeout 12000ms; access_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.redirect(301) end @@ -113,7 +113,7 @@ attempt to abort with pending subrequests --- config location /lua { access_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.redirect(301) end diff --git a/debian/modules/http-lua/t/024-access/uthread-spawn.t b/debian/modules/http-lua/t/024-access/uthread-spawn.t index 7c7ba3b..bc92ccd 100644 --- a/debian/modules/http-lua/t/024-access/uthread-spawn.t +++ b/debian/modules/http-lua/t/024-access/uthread-spawn.t @@ -23,7 +23,7 @@ __DATA__ --- config location /lua { access_by_lua ' - function f() + local function f() ngx.say("hello in thread") end @@ -68,11 +68,11 @@ after --- config location /lua { access_by_lua ' - function f() + local function f() ngx.say("in thread 1") end - function g() + local function g() ngx.say("in thread 2") end @@ -117,7 +117,7 @@ after 2 --- config location /lua { access_by_lua ' - function f() + local function f() ngx.say("before sleep") ngx.sleep(0.1) ngx.say("after sleep") @@ -154,13 +154,13 @@ after sleep --- config location /lua { access_by_lua ' - function f() + local function f() ngx.say("1: before sleep") ngx.sleep(0.2) ngx.say("1: after sleep") end - function g() + local function g() ngx.say("2: before sleep") ngx.sleep(0.1) ngx.say("2: after sleep") @@ -210,7 +210,7 @@ delete thread 2 --- config location /lua { access_by_lua ' - function f() + local function f() ngx.blah() end @@ -241,9 +241,9 @@ qr/lua user thread aborted: runtime error: access_by_lua\(nginx\.conf:\d+\):3: a --- config location /lua { access_by_lua ' - function f() + local function f() ngx.say("before capture") - res = ngx.location.capture("/proxy") + local res = ngx.location.capture("/proxy") ngx.say("after capture: ", res.body) end @@ -287,7 +287,7 @@ after capture: hello world --- config location /lua { access_by_lua ' - function f() + local function f() ngx.say("before capture") local res = ngx.location.capture("/proxy?foo") ngx.say("after capture: ", res.body) @@ -340,7 +340,7 @@ after capture: hello foo --- config location /lua { access_by_lua ' - function f() + local function f() ngx.say("before capture") local res = ngx.location.capture("/proxy?foo") ngx.say("after capture: ", res.body) @@ -395,13 +395,13 @@ capture: hello bar --- config location /lua { access_by_lua ' - function f() + local function f() ngx.say("f: before capture") local res = ngx.location.capture("/proxy?foo") ngx.say("f: after capture: ", res.body) end - function g() + local function g() ngx.say("g: before capture") local res = ngx.location.capture("/proxy?bah") ngx.say("g: after capture: ", res.body) @@ -473,7 +473,8 @@ g: after capture: hello bah --- config location /lua { access_by_lua ' - function f() + local g + local function f() ngx.say("before g") ngx.thread.spawn(g) ngx.say("after g") @@ -519,7 +520,8 @@ after g --- config location /lua { access_by_lua ' - function f() + local g + local function f() ngx.say("before g") ngx.thread.spawn(g) ngx.say("after g") @@ -567,7 +569,7 @@ hello in g() location /lua { access_by_lua ' local co - function f() + local function f() co = coroutine.running() ngx.sleep(0.1) end @@ -600,7 +602,7 @@ status: running location /lua { access_by_lua ' local co - function f() + local function f() co = coroutine.running() end @@ -632,7 +634,8 @@ status: zombie location /lua { access_by_lua ' local co - function f() + local g + local function f() co = coroutine.running() local co2 = coroutine.create(g) coroutine.resume(co2) @@ -671,7 +674,8 @@ status: normal --- config location /lua { access_by_lua ' - function f() + local g + local function f() ngx.say("before g") ngx.thread.spawn(g) ngx.say("after g") @@ -718,7 +722,7 @@ after f access_by_lua ' local yield = coroutine.yield - function f() + local function f() local self = coroutine.running() ngx.say("f 1") yield(self) @@ -771,7 +775,7 @@ f 3 access_by_lua ' local yield = coroutine.yield - function f() + local function f() local self = coroutine.running() ngx.say("f 1") yield(self) @@ -780,7 +784,7 @@ f 3 ngx.say("f 3") end - function g() + local function g() local self = coroutine.running() ngx.say("g 1") yield(self) @@ -827,7 +831,7 @@ g 3 --- config location /lua { access_by_lua ' - function f() + local function f() ngx.say("hello in thread") coroutine.yield(coroutine.running) ngx.flush(true) @@ -864,12 +868,12 @@ after --- config location /lua { access_by_lua ' - function f() + local function f() ngx.say("hello from f") ngx.flush(true) end - function g() + local function g() ngx.say("hello from g") ngx.flush(true) end @@ -915,7 +919,7 @@ hello from g --- config location /lua { access_by_lua ' - function f() + local function f() local sock = ngx.socket.tcp() local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_MEMCACHED_PORT) if not ok then @@ -967,7 +971,7 @@ received: OK --- config location /lua { access_by_lua ' - function f() + local function f() local sock = ngx.socket.udp() local ok, err = sock:setpeername("127.0.0.1", 12345) local bytes, err = sock:send("blah") @@ -1028,7 +1032,7 @@ after)$ --- config location /lua { access_by_lua ' - function f() + local function f() ngx.req.read_body() local body = ngx.req.get_body_data() ngx.say("body: ", body) @@ -1073,7 +1077,7 @@ body: hello world)$ --- config location /lua { access_by_lua ' - function f() + local function f() local sock = ngx.req.socket() local body, err = sock:receive(11) if not body then diff --git a/debian/modules/http-lua/t/025-codecache.t b/debian/modules/http-lua/t/025-codecache.t index 20791d7..22b78b2 100644 --- a/debian/modules/http-lua/t/025-codecache.t +++ b/debian/modules/http-lua/t/025-codecache.t @@ -4,7 +4,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * 155; +plan tests => repeat_each() * 163; #$ENV{LUA_PATH} = $ENV{HOME} . '/work/JSON4Lua-0.9.30/json/?.lua'; @@ -27,7 +27,7 @@ __DATA__ location /update { content_by_lua ' -- os.execute("(echo HERE; pwd) > /dev/stderr") - local f = assert(io.open("t/servroot/html/test.lua", "w")) + local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/test.lua", "w")) f:write("ngx.say(101)") f:close() ngx.say("updated") @@ -61,7 +61,7 @@ updated location /update { content_by_lua ' -- os.execute("(echo HERE; pwd) > /dev/stderr") - local f = assert(io.open("t/servroot/html/test.lua", "w")) + local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/test.lua", "w")) f:write("ngx.say(101)") f:close() ngx.say("updated") @@ -95,7 +95,7 @@ updated location /update { content_by_lua ' -- os.execute("(echo HERE; pwd) > /dev/stderr") - local f = assert(io.open("t/servroot/html/test.lua", "w")) + local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/test.lua", "w")) f:write("ngx.say(101)") f:close() ngx.say("updated") @@ -130,7 +130,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ location /update { content_by_lua ' -- os.execute("(echo HERE; pwd) > /dev/stderr") - local f = assert(io.open("t/servroot/html/test.lua", "w")) + local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/test.lua", "w")) f:write("ngx.say(101)") f:close() ngx.say("updated") @@ -166,7 +166,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ location /update { content_by_lua ' -- os.execute("(echo HERE; pwd) > /dev/stderr") - local f = assert(io.open("t/servroot/html/test.lua", "w")) + local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/test.lua", "w")) f:write("ngx.say(101)") f:close() ngx.say("updated") @@ -193,7 +193,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ === TEST 6: code cache explicitly off (affects require) + content_by_lua --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /lua { lua_code_cache off; @@ -204,7 +204,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ location /update { content_by_lua ' -- os.execute("(echo HERE; pwd) > /dev/stderr") - local f = assert(io.open("t/servroot/html/foo.lua", "w")) + local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/foo.lua", "w")) f:write("module(..., package.seeall); ngx.say(102);") f:close() ngx.say("updated") @@ -231,7 +231,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ === TEST 7: code cache explicitly off (affects require) + content_by_lua_file --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /lua { lua_code_cache off; @@ -240,7 +240,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ location /update { content_by_lua ' -- os.execute("(echo HERE; pwd) > /dev/stderr") - local f = assert(io.open("t/servroot/html/foo.lua", "w")) + local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/foo.lua", "w")) f:write("module(..., package.seeall); ngx.say(102);") f:close() ngx.say("updated") @@ -269,7 +269,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ === TEST 8: code cache explicitly off (affects require) + set_by_lua_file --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /lua { lua_code_cache off; @@ -279,7 +279,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ location /update { content_by_lua ' -- os.execute("(echo HERE; pwd) > /dev/stderr") - local f = assert(io.open("t/servroot/html/foo.lua", "w")) + local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/foo.lua", "w")) f:write("module(..., package.seeall); return 102;") f:close() ngx.say("updated") @@ -308,7 +308,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ === TEST 9: code cache explicitly on (affects require) + set_by_lua_file --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /lua { lua_code_cache on; @@ -318,7 +318,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ location /update { content_by_lua ' -- os.execute("(echo HERE; pwd) > /dev/stderr") - local f = assert(io.open("t/servroot/html/foo.lua", "w")) + local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/foo.lua", "w")) f:write("module(..., package.seeall); return 102;") f:close() ngx.say("updated") @@ -355,7 +355,7 @@ updated location /update { content_by_lua ' -- os.execute("(echo HERE; pwd) > /dev/stderr") - local f = assert(io.open("t/servroot/html/test.lua", "w")) + local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/test.lua", "w")) f:write("return 101") f:close() ngx.say("updated") @@ -390,7 +390,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ location /update { content_by_lua ' -- os.execute("(echo HERE; pwd) > /dev/stderr") - local f = assert(io.open("t/servroot/html/test.lua", "w")) + local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/test.lua", "w")) f:write("return 101") f:close() ngx.say("updated") @@ -468,7 +468,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ === TEST 14: no clear builtin lib "string" --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config lua_code_cache off; location /lua { @@ -504,7 +504,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ === TEST 15: do not skip luarocks --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua'; + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;'; lua_code_cache off;" --- config location /main { @@ -554,7 +554,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ === TEST 16: do not skip luarocks* --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua'; + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;'; lua_code_cache off;" --- config location /main { @@ -604,7 +604,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ === TEST 17: clear _G table --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config lua_code_cache off; location /t { @@ -1050,7 +1050,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/, === TEST 29: cosocket connection pool timeout (after Lua VM destroys) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config lua_code_cache off; location = /t { @@ -1118,7 +1118,7 @@ qr/\blua tcp socket keepalive: free connection pool [0-9A-F]+ for "127.0.0.1:/, === TEST 30: cosocket connection pool timeout (before Lua VM destroys) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config lua_code_cache off; location = /t { @@ -1244,3 +1244,133 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/, "decrementing the reference count for Lua VM: 1", "lua close the global Lua VM", ] + + + +=== TEST 32: make sure inline code keys are correct +GitHub issue #1428 +--- config +include ../html/a/proxy.conf; +include ../html/b/proxy.conf; +include ../html/c/proxy.conf; + +location /t { + echo_location /a/; + echo_location /b/; + echo_location /a/; + echo_location /c/; +} + +--- user_files +>>> a/proxy.conf +location /a/ { + content_by_lua_block { ngx.say("/a/ is called") } +} + +>>> b/proxy.conf +location /b/ { + content_by_lua_block { ngx.say("/b/ is called") } +} + +>>> c/proxy.conf +location /c/ { + content_by_lua_block { ngx.say("/b/ is called") } +} + +--- request +GET /t +--- response_body +/a/ is called +/b/ is called +/a/ is called +/b/ is called +--- grep_error_log eval: qr/looking up Lua code cache with key '.*?'/ +--- grep_error_log_out eval +[ +"looking up Lua code cache with key '=content_by_lua(proxy.conf:2)nhli_3c7137b8371d10bc148c8f8bb3042ee6' +looking up Lua code cache with key '=content_by_lua(proxy.conf:2)nhli_1dfe09105792ef65c8d576cc486d5e04' +looking up Lua code cache with key '=content_by_lua(proxy.conf:2)nhli_3c7137b8371d10bc148c8f8bb3042ee6' +looking up Lua code cache with key '=content_by_lua(proxy.conf:2)nhli_1dfe09105792ef65c8d576cc486d5e04' +", +"looking up Lua code cache with key '=content_by_lua(proxy.conf:2)nhli_3c7137b8371d10bc148c8f8bb3042ee6' +looking up Lua code cache with key '=content_by_lua(proxy.conf:2)nhli_1dfe09105792ef65c8d576cc486d5e04' +looking up Lua code cache with key '=content_by_lua(proxy.conf:2)nhli_3c7137b8371d10bc148c8f8bb3042ee6' +looking up Lua code cache with key '=content_by_lua(proxy.conf:2)nhli_1dfe09105792ef65c8d576cc486d5e04' +looking up Lua code cache with key '=content_by_lua(proxy.conf:2)nhli_3c7137b8371d10bc148c8f8bb3042ee6' +looking up Lua code cache with key '=content_by_lua(proxy.conf:2)nhli_1dfe09105792ef65c8d576cc486d5e04' +looking up Lua code cache with key '=content_by_lua(proxy.conf:2)nhli_3c7137b8371d10bc148c8f8bb3042ee6' +looking up Lua code cache with key '=content_by_lua(proxy.conf:2)nhli_1dfe09105792ef65c8d576cc486d5e04' +"] +--- log_level: debug +--- no_error_log +[error] + + + +=== TEST 33: make sure Lua code file keys are correct +GitHub issue #1428 +--- config +include ../html/a/proxy.conf; +include ../html/b/proxy.conf; +include ../html/c/proxy.conf; + +location /t { + echo_location /a/; + echo_location /b/; + echo_location /a/; + echo_location /c/; +} + +--- user_files +>>> a.lua +ngx.say("/a/ is called") + +>>> b.lua +ngx.say("/b/ is called") + +>>> c.lua +ngx.say("/b/ is called") + +>>> a/proxy.conf +location /a/ { + content_by_lua_file html/a.lua; +} + +>>> b/proxy.conf +location /b/ { + content_by_lua_file html/b.lua; +} + +>>> c/proxy.conf +location /c/ { + content_by_lua_file html/c.lua; +} + +--- request +GET /t +--- response_body +/a/ is called +/b/ is called +/a/ is called +/b/ is called +--- grep_error_log eval: qr/looking up Lua code cache with key '.*?'/ +--- grep_error_log_out eval +[ +"looking up Lua code cache with key 'nhlf_48a9a7def61143c003a7de1644e026e4' +looking up Lua code cache with key 'nhlf_68f5f4e946c3efd1cc206452b807e8b6' +looking up Lua code cache with key 'nhlf_48a9a7def61143c003a7de1644e026e4' +looking up Lua code cache with key 'nhlf_042c9b3a136fbacbbd0e4b9ad10896b7' +", +"looking up Lua code cache with key 'nhlf_48a9a7def61143c003a7de1644e026e4' +looking up Lua code cache with key 'nhlf_68f5f4e946c3efd1cc206452b807e8b6' +looking up Lua code cache with key 'nhlf_48a9a7def61143c003a7de1644e026e4' +looking up Lua code cache with key 'nhlf_042c9b3a136fbacbbd0e4b9ad10896b7' +looking up Lua code cache with key 'nhlf_48a9a7def61143c003a7de1644e026e4' +looking up Lua code cache with key 'nhlf_68f5f4e946c3efd1cc206452b807e8b6' +looking up Lua code cache with key 'nhlf_48a9a7def61143c003a7de1644e026e4' +looking up Lua code cache with key 'nhlf_042c9b3a136fbacbbd0e4b9ad10896b7' +" +] +--- log_level: debug +--- no_error_log +[error] diff --git a/debian/modules/http-lua/t/027-multi-capture.t b/debian/modules/http-lua/t/027-multi-capture.t index 9227fe5..9299561 100644 --- a/debian/modules/http-lua/t/027-multi-capture.t +++ b/debian/modules/http-lua/t/027-multi-capture.t @@ -151,7 +151,7 @@ res2.body = b location /main { content_by_lua ' - res = ngx.location.capture("/foo?n=1") + local res = ngx.location.capture("/foo?n=1") ngx.say("top res.status = " .. res.status) ngx.say("top res.body = [" .. res.body .. "]") '; @@ -743,7 +743,7 @@ proxy_cache_path conf/cache levels=1:2 keys_zone=STATIC:10m inactive=10m max_siz location = /proxy { proxy_cache STATIC; - proxy_pass http://agentzh.org:12345; + proxy_pass http://127.0.0.2:12345; proxy_cache_key $proxy_host$uri$args; proxy_cache_valid any 1s; #proxy_http_version 1.1; diff --git a/debian/modules/http-lua/t/028-req-header.t b/debian/modules/http-lua/t/028-req-header.t index ca92daa..8ddbb29 100644 --- a/debian/modules/http-lua/t/028-req-header.t +++ b/debian/modules/http-lua/t/028-req-header.t @@ -8,7 +8,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * (2 * blocks() + 43); +plan tests => repeat_each() * (2 * blocks() + 44); #no_diff(); no_long_string(); @@ -2008,3 +2008,25 @@ found 3 headers. --- no_error_log lua exceeding request header limit [error] + + + +=== TEST 61: setting Host header clears cached $host variable +--- config + location /req-header { + # this makes $host indexed and cacheable + set $foo $host; + + content_by_lua_block { + ngx.say(ngx.var.host) + ngx.req.set_header("Host", "new"); + ngx.say(ngx.var.host) + } + } +--- request +GET /req-header +--- response_body +localhost +new +--- no_error_log +[error] diff --git a/debian/modules/http-lua/t/030-uri-args.t b/debian/modules/http-lua/t/030-uri-args.t index a9d46ff..7af63c4 100644 --- a/debian/modules/http-lua/t/030-uri-args.t +++ b/debian/modules/http-lua/t/030-uri-args.t @@ -421,7 +421,7 @@ done ngx.req.set_uri_args("hello") ngx.req.set_uri("/bar", true); '; - proxy_pass http://agentzh.org:12345; + proxy_pass http://127.0.0.2:12345; } --- request GET /foo?world @@ -568,7 +568,7 @@ HTTP/1.0 ca%20t=%25 ngx.req.set_uri("/bar", true); ngx.exit(503) '; - proxy_pass http://agentzh.org:12345; + proxy_pass http://127.0.0.2:12345; } --- request GET /foo?world @@ -586,7 +586,7 @@ hello #set $args 'hello'; set $err ''; access_by_lua ' - res, err = pcall(ngx.req.set_uri, "/bar", true); + local res, err = pcall(ngx.req.set_uri, "/bar", true); ngx.var.err = err '; echo "err: $err"; @@ -626,7 +626,7 @@ uri: /bar location /foo { #set $args 'hello'; content_by_lua ' - res, err = pcall(ngx.req.set_uri, "/bar", true); + local res, err = pcall(ngx.req.set_uri, "/bar", true); ngx.say("err: ", err) '; } @@ -665,7 +665,7 @@ uri: /bar location /foo { #set $args 'hello'; set_by_lua $err ' - res, err = pcall(ngx.req.set_uri, "/bar", true); + local res, err = pcall(ngx.req.set_uri, "/bar", true); return err '; echo "err: $err"; @@ -788,7 +788,7 @@ GET /lua location /lua { content_by_lua ' local t = {bar = ngx.shared.dogs, foo = 3} - rc, err = pcall(ngx.encode_args, t) + local rc, err = pcall(ngx.encode_args, t) ngx.say("rc: ", rc, ", err: ", err) '; } @@ -1112,6 +1112,7 @@ HTTP/1.0 a=3&b=5&b=6 --- config location /lua { content_by_lua ' + local err local args = "a=bar&b=foo" args, err = ngx.decode_args(args) @@ -1135,6 +1136,7 @@ b = foo --- config location /lua { content_by_lua ' + local err local args = "a=bar&b=foo&a=baz" args, err = ngx.decode_args(args) @@ -1158,6 +1160,7 @@ b = foo --- config location /lua { content_by_lua ' + local err local args = "" args, err = ngx.decode_args(args) if err then @@ -1178,6 +1181,7 @@ n = 0 --- config location /lua { content_by_lua ' + local err local args = "a&b" args, err = ngx.decode_args(args) if err then @@ -1200,6 +1204,7 @@ b = true --- config location /lua { content_by_lua ' + local err local args = "a=&b=" args, err = ngx.decode_args(args) @@ -1223,6 +1228,7 @@ b = --- config location /lua { content_by_lua ' + local err local args = "a=bar&b=foo" args, err = ngx.decode_args(args, 1) if err then @@ -1246,6 +1252,7 @@ b = nil --- config location /lua { content_by_lua ' + local err local args = "a=bar&b=foo" args, err = ngx.decode_args(args, -1) @@ -1270,7 +1277,7 @@ b = foo location /lua { content_by_lua ' local s = "f+f=bar&B=foo" - args, err = ngx.decode_args(s) + local args, err = ngx.decode_args(s) if err then ngx.say("err: ", err) end @@ -1302,7 +1309,7 @@ s = f+f=bar&B=foo lua_need_request_body on; location /t { content_by_lua ' - function split(s, delimiter) + local function split(s, delimiter) local result = {} local from = 1 local delim_from, delim_to = string.find(s, delimiter, from) diff --git a/debian/modules/http-lua/t/034-match.t b/debian/modules/http-lua/t/034-match.t index ebe5762..473a11f 100644 --- a/debian/modules/http-lua/t/034-match.t +++ b/debian/modules/http-lua/t/034-match.t @@ -21,7 +21,7 @@ __DATA__ --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "([0-9]+)") + local m = ngx.re.match("hello, 1234", "([0-9]+)") if m then ngx.say(m[0]) else @@ -40,7 +40,7 @@ __DATA__ --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "(\\\\d+)") + local m = ngx.re.match("hello, 1234", "(\\\\d+)") if m then ngx.say(m[0]) else @@ -59,7 +59,7 @@ __DATA__ --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "(\\d+)") + local m = ngx.re.match("hello, 1234", "(\\d+)") if m then ngx.say(m[0]) else @@ -80,7 +80,7 @@ __DATA__ --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "[[\\d+]]") + local m = ngx.re.match("hello, 1234", "[[\\d+]]") if m then ngx.say(m[0]) else @@ -101,7 +101,7 @@ __DATA__ --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "([0-9]{2})[0-9]+") + local m = ngx.re.match("hello, 1234", "([0-9]{2})[0-9]+") if m then ngx.say(m[0]) ngx.say(m[1]) @@ -122,7 +122,7 @@ __DATA__ --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "([a-z]+).*?([0-9]{2})[0-9]+", "") + local m = ngx.re.match("hello, 1234", "([a-z]+).*?([0-9]{2})[0-9]+", "") if m then ngx.say(m[0]) ngx.say(m[1]) @@ -145,7 +145,7 @@ hello --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "([a-z]+).*?([0-9]{2})[0-9]+", "o") + local m = ngx.re.match("hello, 1234", "([a-z]+).*?([0-9]{2})[0-9]+", "o") if m then ngx.say(m[0]) ngx.say(m[1]) @@ -168,7 +168,7 @@ hello --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "foo") + local m = ngx.re.match("hello, 1234", "foo") if m then ngx.say(m[0]) else @@ -187,7 +187,7 @@ not matched: nil --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "HELLO") + local m = ngx.re.match("hello, 1234", "HELLO") if m then ngx.say(m[0]) else @@ -206,7 +206,7 @@ not matched: nil --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "HELLO", "i") + local m = ngx.re.match("hello, 1234", "HELLO", "i") if m then ngx.say(m[0]) else @@ -225,7 +225,7 @@ hello --- config location /re { content_by_lua ' - rc, err = pcall(ngx.re.match, "hello章亦春", "HELLO.{2}", "iu") + local rc, err = pcall(ngx.re.match, "hello章亦春", "HELLO.{2}", "iu") if not rc then ngx.say("FAIL: ", err) return @@ -249,7 +249,7 @@ hello --- config location /re { content_by_lua ' - m = ngx.re.match("hello\\nworld", "^world", "m") + local m = ngx.re.match("hello\\nworld", "^world", "m") if m then ngx.say(m[0]) else @@ -268,7 +268,7 @@ world --- config location /re { content_by_lua ' - m = ngx.re.match("hello\\nworld", ".*", "m") + local m = ngx.re.match("hello\\nworld", ".*", "m") if m then ngx.say(m[0]) else @@ -287,7 +287,7 @@ hello --- config location /re { content_by_lua ' - m = ngx.re.match("hello\\nworld", "^world", "s") + local m = ngx.re.match("hello\\nworld", "^world", "s") if m then ngx.say(m[0]) else @@ -306,7 +306,7 @@ not matched: nil --- config location /re { content_by_lua ' - m = ngx.re.match("hello\\nworld", ".*", "s") + local m = ngx.re.match("hello\\nworld", ".*", "s") if m then ngx.say(m[0]) else @@ -326,7 +326,7 @@ world --- config location /re { content_by_lua ' - m = ngx.re.match("hello\\nworld", "\\\\w \\\\w", "x") + local m = ngx.re.match("hello\\nworld", "\\\\w \\\\w", "x") if m then ngx.say(m[0]) else @@ -372,7 +372,7 @@ error: pcre_compile() failed: missing ) in "(abc" --- config location /re { content_by_lua ' - rc, m = pcall(ngx.re.match, "hello\\nworld", ".*", "Hm") + local rc, m = pcall(ngx.re.match, "hello\\nworld", ".*", "Hm") if rc then if m then ngx.say(m[0]) @@ -395,7 +395,7 @@ error: .*?unknown flag "H" \(flags "Hm"\) --- config location /re { content_by_lua ' - m = ngx.re.match("hello, world", "(world)|(hello)", "x") + local m = ngx.re.match("hello, world", "(world)|(hello)", "x") if m then ngx.say(m[0]) ngx.say(m[1]) @@ -418,7 +418,7 @@ hello --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "([0-9]+)(h?)") + local m = ngx.re.match("hello, 1234", "([0-9]+)(h?)") if m then ngx.say(m[0]) ngx.say(m[1]) @@ -442,7 +442,7 @@ hello --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "([0-9]+)", "a") + local m = ngx.re.match("hello, 1234", "([0-9]+)", "a") if m then ngx.say(m[0]) else @@ -461,7 +461,7 @@ not matched! --- config location /re { content_by_lua ' - m = ngx.re.match("1234, hello", "([0-9]+)", "a") + local m = ngx.re.match("1234, hello", "([0-9]+)", "a") if m then ngx.say(m[0]) else @@ -481,7 +481,7 @@ not matched! location /re { content_by_lua ' local ctx = {} - m = ngx.re.match("1234, hello", "([0-9]+)", "", ctx) + local m = ngx.re.match("1234, hello", "([0-9]+)", "", ctx) if m then ngx.say(m[0]) ngx.say(ctx.pos) @@ -504,7 +504,7 @@ not matched! location /re { content_by_lua ' local ctx = { pos = 3 } - m = ngx.re.match("1234, hello", "([0-9]+)", "", ctx) + local m = ngx.re.match("1234, hello", "([0-9]+)", "", ctx) if m then ngx.say(m[0]) ngx.say(ctx.pos) @@ -526,7 +526,7 @@ not matched! --- config location /re { set_by_lua $res ' - m = ngx.re.match("hello, 1234", "([0-9]+)") + local m = ngx.re.match("hello, 1234", "([0-9]+)") if m then return m[0] else @@ -569,7 +569,7 @@ baz } --- user_files >>> a.lua -m = ngx.re.match("hello, 1234", "(\\\s+)") +local m = ngx.re.match("hello, 1234", "(\\\s+)") if m then ngx.say("[", m[0], "]") else @@ -595,7 +595,7 @@ end local uri = "2" local regex = '(?:>[\\w\\s]*)'; ngx.say("regex: ", regex) -m = ngx.re.match(uri, regex, "oi") +local m = ngx.re.match(uri, regex, "oi") if m then ngx.say("[", m[0], "]") else @@ -613,7 +613,7 @@ regex: (?:>[\w\s]*) --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", [[\\d+]]) + local m = ngx.re.match("hello, 1234", [[\\d+]]) if m then ngx.say(m[0]) else @@ -660,7 +660,7 @@ error: pcre_compile() failed: missing ) in "([0-9]+" --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", [[([0-9]+)]]) + local m = ngx.re.match("hello, 1234", [[([0-9]+)]]) if m then ngx.say(m[0]) else @@ -1027,7 +1027,7 @@ exec opts: 0 >>> a.lua local re = [==[(?i:([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:=|<=>|r?like|sounds\s+like|regexp)([\s'\"`´’‘\(\)]*)?\2|([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp)([\s'\"`´’‘\(\)]*)?(?!\6)([\d\w]+))]==] -s = string.rep([[ABCDEFG]], 10) +local s = string.rep([[ABCDEFG]], 10) local start = ngx.now() @@ -1067,7 +1067,7 @@ error: pcre_exec() failed: -8 >>> a.lua local re = [==[(?i:([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:=|<=>|r?like|sounds\s+like|regexp)([\s'\"`´’‘\(\)]*)?\2|([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp)([\s'\"`´’‘\(\)]*)?(?!\6)([\d\w]+))]==] -s = string.rep([[ABCDEFG]], 10) +local s = string.rep([[ABCDEFG]], 10) local start = ngx.now() @@ -1101,7 +1101,7 @@ failed to match content_by_lua ' local res = {} local s = "hello, 1234" - m = ngx.re.match(s, [[(\\d)(\\d)]], "o", nil, res) + local m = ngx.re.match(s, [[(\\d)(\\d)]], "o", nil, res) if m then ngx.say("1: m size: ", #m) ngx.say("1: res size: ", #res) @@ -1132,11 +1132,12 @@ failed to match === TEST 48: init_by_lua --- http_config init_by_lua ' - m = ngx.re.match("hello, 1234", "(\\\\d+)") + package.loaded.m = ngx.re.match("hello, 1234", "(\\\\d+)") '; --- config location /re { content_by_lua ' + local m = package.loaded.m if m then ngx.say(m[0]) else diff --git a/debian/modules/http-lua/t/035-gmatch.t b/debian/modules/http-lua/t/035-gmatch.t index 0426997..0dfeaea 100644 --- a/debian/modules/http-lua/t/035-gmatch.t +++ b/debian/modules/http-lua/t/035-gmatch.t @@ -123,7 +123,7 @@ nil --- config location /re { content_by_lua ' - it = ngx.re.gmatch("hello, 1234", "([0-9]+)", "a") + local it = ngx.re.gmatch("hello, 1234", "([0-9]+)", "a") ngx.say(it()) '; } @@ -418,7 +418,7 @@ hello content_by_lua ' local a = {} for i = 1, 3 do - it = ngx.re.gmatch("hello, world", "[a-z]+") + local it = ngx.re.gmatch("hello, world", "[a-z]+") it() collectgarbage() table.insert(a, {"hello", "world"}) @@ -482,9 +482,9 @@ end GET /main --- response_body matched -sr failed: 500 ---- error_log -attempt to use ngx.re.gmatch iterator in a request that did not create it +matched +--- no_error_log +[error] @@ -518,7 +518,7 @@ matched: [] location /re { content_by_lua ' local it = ngx.re.gmatch("1234, 1234", "(?[0-9]+)") - m = it() + local m = it() if m then ngx.say(m[0]) ngx.say(m[1]) @@ -555,7 +555,7 @@ matched: [] content_by_lua ' local it = ngx.re.gmatch("1234, abcd, 1234", "(?[0-9]+)|(?[a-z]+)") - m = it() + local m = it() if m then ngx.say(m[0]) ngx.say(m[1]) @@ -599,7 +599,7 @@ abcd location /re { content_by_lua ' local it = ngx.re.gmatch("hello, 1234", "(?[a-z]+), (?[0-9]+)", "D") - m = it() + local m = it() if m then ngx.say(m[0]) ngx.say(m[1]) @@ -825,7 +825,7 @@ exec opts: 0 >>> a.lua local re = [==[(?i:([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:=|<=>|r?like|sounds\s+like|regexp)([\s'\"`´’‘\(\)]*)?\2|([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp)([\s'\"`´’‘\(\)]*)?(?!\6)([\d\w]+))]==] -s = string.rep([[ABCDEFG]], 10) +local s = string.rep([[ABCDEFG]], 10) local start = ngx.now() @@ -871,7 +871,7 @@ error: pcre_exec() failed: -8 >>> a.lua local re = [==[(?i:([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:=|<=>|r?like|sounds\s+like|regexp)([\s'\"`´’‘\(\)]*)?\2|([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp)([\s'\"`´’‘\(\)]*)?(?!\6)([\d\w]+))]==] -s = string.rep([[ABCDEFG]], 10) +local s = string.rep([[ABCDEFG]], 10) local start = ngx.now() @@ -881,7 +881,7 @@ if not it then return end -res, err = it() +local res, err = it() --[[ ngx.update_time() diff --git a/debian/modules/http-lua/t/036-sub.t b/debian/modules/http-lua/t/036-sub.t index 2b4b075..3e88eba 100644 --- a/debian/modules/http-lua/t/036-sub.t +++ b/debian/modules/http-lua/t/036-sub.t @@ -590,7 +590,7 @@ s: a好 >>> a.lua local re = [==[(?i:([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:=|<=>|r?like|sounds\s+like|regexp)([\s'\"`´’‘\(\)]*)?\2|([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp)([\s'\"`´’‘\(\)]*)?(?!\6)([\d\w]+))]==] -s = string.rep([[ABCDEFG]], 10) +local s = string.rep([[ABCDEFG]], 10) local start = ngx.now() @@ -693,7 +693,7 @@ ab.cd location = /t { content_by_lua ' - function test() + local function test() local data = [[ OUTER {FIRST} ]] diff --git a/debian/modules/http-lua/t/037-gsub.t b/debian/modules/http-lua/t/037-gsub.t index 4c5810d..41f86ac 100644 --- a/debian/modules/http-lua/t/037-gsub.t +++ b/debian/modules/http-lua/t/037-gsub.t @@ -511,7 +511,7 @@ s: aa >>> a.lua local re = [==[(?i:([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:=|<=>|r?like|sounds\s+like|regexp)([\s'\"`´’‘\(\)]*)?\2|([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp)([\s'\"`´’‘\(\)]*)?(?!\6)([\d\w]+))]==] -s = string.rep([[ABCDEFG]], 10) +local s = string.rep([[ABCDEFG]], 10) local start = ngx.now() diff --git a/debian/modules/http-lua/t/038-match-o.t b/debian/modules/http-lua/t/038-match-o.t index d61ff1f..f6ae010 100644 --- a/debian/modules/http-lua/t/038-match-o.t +++ b/debian/modules/http-lua/t/038-match-o.t @@ -20,7 +20,7 @@ __DATA__ --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "([0-9]+)", "o") + local m = ngx.re.match("hello, 1234", "([0-9]+)", "o") if m then ngx.say(m[0]) else @@ -39,7 +39,7 @@ __DATA__ --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "(\\\\d+)", "o") + local m = ngx.re.match("hello, 1234", "(\\\\d+)", "o") if m then ngx.say(m[0]) else @@ -58,7 +58,7 @@ __DATA__ --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "(\\d+)", "o") + local m = ngx.re.match("hello, 1234", "(\\d+)", "o") if m then ngx.say(m[0]) else @@ -79,7 +79,7 @@ __DATA__ --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "[[\\d+]]", "o") + local m = ngx.re.match("hello, 1234", "[[\\d+]]", "o") if m then ngx.say(m[0]) else @@ -100,7 +100,7 @@ __DATA__ --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "([0-9]{2})[0-9]+", "o") + local m = ngx.re.match("hello, 1234", "([0-9]{2})[0-9]+", "o") if m then ngx.say(m[0]) ngx.say(m[1]) @@ -121,7 +121,7 @@ __DATA__ --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "([a-z]+).*?([0-9]{2})[0-9]+", "o") + local m = ngx.re.match("hello, 1234", "([a-z]+).*?([0-9]{2})[0-9]+", "o") if m then ngx.say(m[0]) ngx.say(m[1]) @@ -144,7 +144,7 @@ hello --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "foo", "o") + local m = ngx.re.match("hello, 1234", "foo", "o") if m then ngx.say(m[0]) else @@ -163,7 +163,7 @@ not matched: nil --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "HELLO", "o") + local m = ngx.re.match("hello, 1234", "HELLO", "o") if m then ngx.say(m[0]) else @@ -182,7 +182,7 @@ not matched: nil --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "HELLO", "oi") + local m = ngx.re.match("hello, 1234", "HELLO", "oi") if m then ngx.say(m[0]) else @@ -224,7 +224,7 @@ this version of PCRE is not compiled with PCRE_UTF8 support|^hello章亦$ --- config location /re { content_by_lua ' - m = ngx.re.match("hello\\nworld", "^world", "mo") + local m = ngx.re.match("hello\\nworld", "^world", "mo") if m then ngx.say(m[0]) else @@ -243,7 +243,7 @@ world --- config location /re { content_by_lua ' - m = ngx.re.match("hello\\nworld", ".*", "om") + local m = ngx.re.match("hello\\nworld", ".*", "om") if m then ngx.say(m[0]) else @@ -262,7 +262,7 @@ hello --- config location /re { content_by_lua ' - m = ngx.re.match("hello\\nworld", "^world", "so") + local m = ngx.re.match("hello\\nworld", "^world", "so") if m then ngx.say(m[0]) else @@ -281,7 +281,7 @@ not matched: nil --- config location /re { content_by_lua ' - m = ngx.re.match("hello\\nworld", ".*", "os") + local m = ngx.re.match("hello\\nworld", ".*", "os") if m then ngx.say(m[0]) else @@ -301,7 +301,7 @@ world --- config location /re { content_by_lua ' - m = ngx.re.match("hello\\nworld", "\\\\w \\\\w", "xo") + local m = ngx.re.match("hello\\nworld", "\\\\w \\\\w", "xo") if m then ngx.say(m[0]) else @@ -347,7 +347,7 @@ error: pcre_compile() failed: missing ) in "(abc" --- config location /re { content_by_lua ' - rc, m = pcall(ngx.re.match, "hello\\nworld", ".*", "Ho") + local rc, m = pcall(ngx.re.match, "hello\\nworld", ".*", "Ho") if rc then if m then ngx.say(m[0]) @@ -370,7 +370,7 @@ error: pcre_compile() failed: missing ) in "(abc" --- config location /re { content_by_lua ' - m = ngx.re.match("hello, world", "(world)|(hello)", "xo") + local m = ngx.re.match("hello, world", "(world)|(hello)", "xo") if m then ngx.say(m[0]) ngx.say(m[1]) @@ -393,7 +393,7 @@ hello --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "([0-9]+)(h?)", "o") + local m = ngx.re.match("hello, 1234", "([0-9]+)(h?)", "o") if m then ngx.say(m[0]) ngx.say(m[1]) @@ -417,7 +417,7 @@ hello --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "([0-9]+)", "oa") + local m = ngx.re.match("hello, 1234", "([0-9]+)", "oa") if m then ngx.say(m[0]) else @@ -436,7 +436,7 @@ not matched! --- config location /re { content_by_lua ' - m = ngx.re.match("1234, hello", "([0-9]+)", "ao") + local m = ngx.re.match("1234, hello", "([0-9]+)", "ao") if m then ngx.say(m[0]) else @@ -456,7 +456,7 @@ not matched! location /re { content_by_lua ' local ctx = {} - m = ngx.re.match("1234, hello", "([0-9]+)", "o", ctx) + local m = ngx.re.match("1234, hello", "([0-9]+)", "o", ctx) if m then ngx.say(m[0]) ngx.say(ctx.pos) @@ -479,7 +479,7 @@ not matched! location /re { content_by_lua ' local ctx = { pos = 3 } - m = ngx.re.match("1234, hello", "([0-9]+)", "o", ctx) + local m = ngx.re.match("1234, hello", "([0-9]+)", "o", ctx) if m then ngx.say(m[0]) ngx.say(ctx.pos) @@ -501,7 +501,7 @@ not matched! --- config location /re { set_by_lua $res ' - m = ngx.re.match("hello, 1234", "([0-9]+)", "o") + local m = ngx.re.match("hello, 1234", "([0-9]+)", "o") if m then return m[0] else diff --git a/debian/modules/http-lua/t/041-header-filter.t b/debian/modules/http-lua/t/041-header-filter.t index 7d8ee74..0adc699 100644 --- a/debian/modules/http-lua/t/041-header-filter.t +++ b/debian/modules/http-lua/t/041-header-filter.t @@ -10,7 +10,7 @@ log_level('debug'); repeat_each(2); -plan tests => repeat_each() * 94; +plan tests => repeat_each() * (blocks() * 2 + 13); #no_diff(); #no_long_string(); @@ -416,7 +416,7 @@ lua release ngx.ctx -=== TEST 20: global got cleared for each single request +=== TEST 20: globals are shared by all requests --- config location /lua { set $foo ''; @@ -428,6 +428,7 @@ lua release ngx.ctx if not foo then foo = 1 else + ngx.log(ngx.INFO, "old foo: ", foo) foo = foo + 1 end ngx.var.foo = foo @@ -435,10 +436,13 @@ lua release ngx.ctx } --- request GET /lua ---- response_body -1 +--- response_body_like +^[12]$ --- no_error_log [error] +--- grep_error_log eval: qr/old foo: \d+/ +--- grep_error_log_out eval +["", "old foo: 1\n"] @@ -730,7 +734,8 @@ hello world --- config location /t { header_filter_by_lua ' - function foo() + local bar + local function foo() bar() end diff --git a/debian/modules/http-lua/t/043-shdict.t b/debian/modules/http-lua/t/043-shdict.t index 9183bf5..b0528e5 100644 --- a/debian/modules/http-lua/t/043-shdict.t +++ b/debian/modules/http-lua/t/043-shdict.t @@ -420,7 +420,7 @@ ngx_slab_alloc() failed: no memory in lua_shared_dict zone ngx.say(dogs:get(key)) key = string.rep("a", 65536) - ok, err = dogs:set(key, "world") + local ok, err = dogs:set(key, "world") if not ok then ngx.say("not ok: ", err) return @@ -2048,7 +2048,7 @@ get_stale ok: false, stale: false ngx.say("get not ok: ", err) return end - flags = err + local flags = err ngx.say("get_stale ok: ", data, ", flags: ", flags, ", stale: ", stale) diff --git a/debian/modules/http-lua/t/047-match-jit.t b/debian/modules/http-lua/t/047-match-jit.t index 2417a63..f53a408 100644 --- a/debian/modules/http-lua/t/047-match-jit.t +++ b/debian/modules/http-lua/t/047-match-jit.t @@ -20,7 +20,7 @@ __DATA__ --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "([0-9]+)", "j") + local m = ngx.re.match("hello, 1234", "([0-9]+)", "j") if m then ngx.say(m[0]) else @@ -41,7 +41,7 @@ pcre JIT compiling result: 1 --- config location /re { content_by_lua ' - m = ngx.re.match("hello, world", "([0-9]+)", "j") + local m = ngx.re.match("hello, world", "([0-9]+)", "j") if m then ngx.say(m[0]) else @@ -62,7 +62,7 @@ pcre JIT compiling result: 1 --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "([0-9]+)", "jo") + local m = ngx.re.match("hello, 1234", "([0-9]+)", "jo") if m then ngx.say(m[0]) else @@ -87,7 +87,7 @@ qr/pcre JIT compiling result: \d+/ --- config location /re { content_by_lua ' - m = ngx.re.match("hello, world", "([0-9]+)", "jo") + local m = ngx.re.match("hello, world", "([0-9]+)", "jo") if m then ngx.say(m[0]) else @@ -147,7 +147,7 @@ error: pcre_compile() failed: missing ) in "(abc" >>> a.lua local re = [==[(?i:([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:=|<=>|r?like|sounds\s+like|regexp)([\s'\"`´’‘\(\)]*)?\2|([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp)([\s'\"`´’‘\(\)]*)?(?!\6)([\d\w]+))]==] -s = string.rep([[ABCDEFG]], 21) +local s = string.rep([[ABCDEFG]], 21) local start = ngx.now() @@ -187,7 +187,7 @@ error: pcre_exec() failed: -8 >>> a.lua local re = [==[(?i:([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:=|<=>|r?like|sounds\s+like|regexp)([\s'\"`´’‘\(\)]*)?\2|([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp)([\s'\"`´’‘\(\)]*)?(?!\6)([\d\w]+))]==] -s = string.rep([[ABCDEFG]], 21) +local s = string.rep([[ABCDEFG]], 21) local start = ngx.now() diff --git a/debian/modules/http-lua/t/048-match-dfa.t b/debian/modules/http-lua/t/048-match-dfa.t index 28b5a60..edf3662 100644 --- a/debian/modules/http-lua/t/048-match-dfa.t +++ b/debian/modules/http-lua/t/048-match-dfa.t @@ -20,7 +20,7 @@ __DATA__ --- config location /re { content_by_lua ' - m = ngx.re.match("hello", "(he|hell)", "d") + local m = ngx.re.match("hello", "(he|hell)", "d") if m then ngx.say(m[0]) ngx.say(m[1]) @@ -43,7 +43,7 @@ nil --- config location /re { content_by_lua ' - m = ngx.re.match("hello", "(he|hell)", "do") + local m = ngx.re.match("hello", "(he|hell)", "do") if m then ngx.say(m[0]) ngx.say(m[1]) @@ -66,7 +66,7 @@ nil --- config location /re { content_by_lua ' - m = ngx.re.match("hello", "(he|hell)", "jd") + local m = ngx.re.match("hello", "(he|hell)", "jd") if m then ngx.say(m[0]) else @@ -85,7 +85,7 @@ hell --- config location /re { content_by_lua ' - m = ngx.re.match("world", "(he|hell)", "d") + local m = ngx.re.match("world", "(he|hell)", "d") if m then ngx.say(m[0]) else @@ -104,7 +104,7 @@ not matched! --- config location /re { content_by_lua ' - m = ngx.re.match("hello", "he|hell", "do") + local m = ngx.re.match("hello", "he|hell", "do") if m then ngx.say(m[0]) ngx.say(m[1]) @@ -127,7 +127,7 @@ nil --- config location /re { content_by_lua ' - m = ngx.re.match("world", "([0-9]+)", "do") + local m = ngx.re.match("world", "([0-9]+)", "do") if m then ngx.say(m[0]) else diff --git a/debian/modules/http-lua/t/055-subreq-vars.t b/debian/modules/http-lua/t/055-subreq-vars.t index eb5e24d..1369992 100644 --- a/debian/modules/http-lua/t/055-subreq-vars.t +++ b/debian/modules/http-lua/t/055-subreq-vars.t @@ -28,7 +28,7 @@ __DATA__ location /lua { content_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { vars = { dog = "hello", cat = 32 }}); ngx.print(res.body) @@ -82,7 +82,7 @@ qr/variable "(dog|cat)" cannot be assigned a value \(maybe you forgot to define location /lua { set $dog ''; content_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { vars = { dog = "hello", cat = 32 }}); ngx.print(res.body) @@ -110,7 +110,7 @@ variable "cat" cannot be assigned a value (maybe you forgot to define it first?) set $dog ''; set $cat ''; content_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { vars = { dog = "hello", cat = 32 }}); ngx.print(res.body) @@ -137,7 +137,7 @@ cat = 32 set $dog ''; set $cat ''; content_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { vars = "hello" }); ngx.print(res.body) @@ -165,7 +165,7 @@ Bad vars option value set $dog ''; set $cat ''; content_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { vars = { cat = true } }); ngx.print(res.body) @@ -188,7 +188,7 @@ attempt to use bad variable value type boolean location /lua { content_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { vars = { args = "a=hello&b=32" }}); ngx.print(res.body) @@ -234,7 +234,7 @@ variable "query_string" not changeable location /lua { set $dog 'hello'; content_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { copy_all_vars = true }); ngx.print(res.body) @@ -259,7 +259,7 @@ GET /lua location /lua { set $dog 'hello'; content_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { share_all_vars = true }); ngx.print(res.body) @@ -284,7 +284,7 @@ GET /lua location /lua { set $dog 'hello'; content_by_lua ' - res = ngx.location.capture("/other", + local res = ngx.location.capture("/other", { vars = { dog = "hiya" }, copy_all_vars = true }); ngx.print(res.body) diff --git a/debian/modules/http-lua/t/056-flush.t b/debian/modules/http-lua/t/056-flush.t index 6b697a4..bdd33d4 100644 --- a/debian/modules/http-lua/t/056-flush.t +++ b/debian/modules/http-lua/t/056-flush.t @@ -317,7 +317,7 @@ lua http 1.0 buffering makes ngx.flush() a no-op --- config location /test { content_by_lua ' - function f() + local function f() ngx.say("hello, world") ngx.flush(true) coroutine.yield() diff --git a/debian/modules/http-lua/t/057-flush-timeout.t b/debian/modules/http-lua/t/057-flush-timeout.t index a046539..1f8cfaa 100644 --- a/debian/modules/http-lua/t/057-flush-timeout.t +++ b/debian/modules/http-lua/t/057-flush-timeout.t @@ -127,7 +127,7 @@ del timer 1234 send_timeout 200ms; location /lua { content_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) diff --git a/debian/modules/http-lua/t/058-tcp-socket.t b/debian/modules/http-lua/t/058-tcp-socket.t index 354a876..837006c 100644 --- a/debian/modules/http-lua/t/058-tcp-socket.t +++ b/debian/modules/http-lua/t/058-tcp-socket.t @@ -4,7 +4,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * 199; +plan tests => repeat_each() * 219; our $HtmlDir = html_dir; @@ -245,11 +245,11 @@ attempt to send data on a closed socket: --- request GET /t ---- response_body +--- response_body_like connected: 1 request sent: 56 -first line received: HTTP/1.1 200 OK -second line received: Server: openresty +first line received: HTTP\/1\.1 200 OK +second line received: (?:Date|Server): .*? --- no_error_log [error] --- timeout: 10 @@ -298,7 +298,7 @@ qr/connect\(\) failed \(\d+: Connection refused\)/ location /test { content_by_lua ' local sock = ngx.socket.tcp() - local ok, err = sock:connect("agentzh.org", 12345) + local ok, err = sock:connect("127.0.0.2", 12345) ngx.say("connect: ", ok, " ", err) local bytes @@ -321,7 +321,7 @@ send: nil closed receive: nil closed close: nil closed --- error_log -lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 +lua tcp socket connect timed out, when connecting to 127.0.0.2:12345 --- timeout: 10 @@ -914,7 +914,7 @@ close: 1 nil end end - ok, err = sock:close() + local ok, err = sock:close() ngx.say("close: ", ok, " ", err) '; } @@ -961,7 +961,7 @@ close: 1 nil line, err = sock:receive() ngx.say("receive: ", line, " ", err) - ok, err = sock:close() + local ok, err = sock:close() ngx.say("close: ", ok, " ", err) '; } @@ -1057,7 +1057,7 @@ close: 1 nil === TEST 19: cannot survive across request boundary (send) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location /t { @@ -1116,7 +1116,7 @@ received: OK|failed to send request: closed)\$" === TEST 20: cannot survive across request boundary (receive) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location /t { @@ -1191,7 +1191,7 @@ received: OK|failed to receive a line: closed \[nil\])$/ === TEST 21: cannot survive across request boundary (close) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location /t { @@ -1260,7 +1260,7 @@ received: OK|failed to close: closed)$/ === TEST 22: cannot survive across request boundary (connect) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location /t { @@ -2611,7 +2611,7 @@ close: 1 nil local ready = false local fatal = false - function f() + local function f() local line, err, part = sock:receive() if not line then ngx.say("failed to receive the 1st line: ", err, " [", part, "]") @@ -2672,7 +2672,7 @@ lua clean up the timer for pending ngx.sleep === TEST 44: bad request tries to connect --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location = /main { @@ -2726,7 +2726,7 @@ qr/runtime error: content_by_lua\(nginx\.conf:\d+\):7: bad request/ === TEST 45: bad request tries to receive --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location = /main { @@ -2783,7 +2783,7 @@ qr/runtime error: content_by_lua\(nginx\.conf:\d+\):14: bad request/ === TEST 46: bad request tries to send --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location = /main { @@ -2840,7 +2840,7 @@ qr/runtime error: content_by_lua\(nginx\.conf:\d+\):14: bad request/ === TEST 47: bad request tries to close --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location = /main { @@ -2897,7 +2897,7 @@ qr/runtime error: content_by_lua\(nginx\.conf:\d+\):14: bad request/ === TEST 48: bad request tries to set keepalive --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location = /main { @@ -2954,7 +2954,7 @@ qr/runtime error: content_by_lua\(nginx\.conf:\d+\):14: bad request/ === TEST 49: bad request tries to receiveuntil --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location = /main { @@ -3315,7 +3315,7 @@ close: 1 nil local thr = ngx.thread.spawn(function () sock = ngx.socket.tcp() - local ok, err = sock:connect("agentzh.org", 12345) + local ok, err = sock:connect("127.0.0.2", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -3464,7 +3464,7 @@ lua http cleanup reuse ngx.say("failed to create timer: ", err) end - i = 1 + local i = 1 while not done do local time = 0.005 * i if time > 0.1 then @@ -3545,7 +3545,7 @@ lua http cleanup reuse ngx.say("failed to create timer: ", err) end - i = 1 + local i = 1 while not done do local time = 0.005 * i if time > 0.1 then @@ -3720,10 +3720,10 @@ sudo iptables -I OUTPUT 1 -p udp --dport 10086 -j REJECT } --- request GET /t ---- response_body -failed to connect: www.google.com could not be resolved -failed to connect: www.google.com could not be resolved -failed to connect: www.google.com could not be resolved +--- response_body_like +failed to connect: www.google.com could not be resolved(?: \(\d+: Operation timed out\))? +failed to connect: www.google.com could not be resolved(?: \(\d+: Operation timed out\))? +failed to connect: www.google.com could not be resolved(?: \(\d+: Operation timed out\))? hello! --- error_log eval qr{\[alert\] .*? send\(\) failed \(\d+: Operation not permitted\) while resolving} @@ -3808,3 +3808,315 @@ received: received: truefalsenil --- no_error_log [error] + + + +=== TEST 64: receiveany method in cosocket +--- config + server_tokens off; + location = /t { + set $port $TEST_NGINX_SERVER_PORT; + content_by_lua_block { + local sock = ngx.socket.tcp() + sock:settimeout(500) + assert(sock:connect("127.0.0.1", ngx.var.port)) + local req = { + 'GET /foo HTTP/1.0\r\n', + 'Host: localhost\r\n', + 'Connection: close\r\n\r\n', + } + local ok, err = sock:send(req) + if not ok then + ngx.say("send request failed: ", err) + return + end + + -- skip http header + while true do + local data, err, _ = sock:receive('*l') + if err then + ngx.say('unexpected error occurs when receiving http head: ', err) + return + end + + if #data == 0 then -- read last line of head + break + end + end + + -- receive http body + while true do + local data, err = sock:receiveany(1024) + if err then + if err ~= 'closed' then + ngx.say('unexpected err: ', err) + end + break + end + ngx.say(data) + end + + sock:close() + } + } + + location = /foo { + content_by_lua_block { + local resp = { + '1', + '22', + 'hello world', + } + + local length = 0 + for _, v in ipairs(resp) do + length = length + #v + end + + -- flush http header + ngx.header['Content-Length'] = length + ngx.flush(true) + ngx.sleep(0.01) + + -- send http body + for _, v in ipairs(resp) do + ngx.print(v) + ngx.flush(true) + ngx.sleep(0.01) + end + } + } + +--- request +GET /t +--- response_body +1 +22 +hello world +--- no_error_log +[error] +--- error_log +lua tcp socket read any + + + +=== TEST 65: receiveany send data after read side closed +--- config + server_tokens off; + location = /t { + content_by_lua_block { + local sock = ngx.socket.tcp() + sock:settimeout(500) + assert(sock:connect("127.0.0.1", 7658)) + + while true do + local data, err = sock:receiveany(1024) + if err then + if err ~= 'closed' then + ngx.say('unexpected err: ', err) + break + end + + local data = "send data after read side closed" + local bytes, err = sock:send(data) + if not bytes then + ngx.say(err) + end + + break + end + ngx.say(data) + end + + sock:close() + } + } + +--- request +GET /t +--- tcp_listen: 7658 +--- tcp_shutdown: 1 +--- tcp_query eval: "send data after read side closed" +--- tcp_query_len: 32 +--- response_body +--- no_error_log +[error] + + + +=== TEST 66: receiveany with limited, max <= 0 +--- config + location = /t { + set $port $TEST_NGINX_SERVER_PORT; + content_by_lua_block { + local sock = ngx.socket.tcp() + sock:settimeout(500) + assert(sock:connect("127.0.0.1", ngx.var.port)) + + local function receiveany_say_err(...) + local ok, err = pcall(sock.receiveany, sock, ...) + if not ok then + ngx.say(err) + end + end + + + receiveany_say_err(0) + receiveany_say_err(-1) + receiveany_say_err() + receiveany_say_err(nil) + } + } + +--- response_body +bad argument #2 to '?' (bad max argument) +bad argument #2 to '?' (bad max argument) +expecting 2 arguments (including the object), but got 1 +bad argument #2 to '?' (bad max argument) +--- request +GET /t +--- no_error_log +[error] + + + +=== TEST 67: receiveany with limited, max is larger than data +--- config + server_tokens off; + location = /t { + set $port $TEST_NGINX_SERVER_PORT; + content_by_lua_block { + local sock = ngx.socket.tcp() + sock:settimeout(500) + assert(sock:connect("127.0.0.1", ngx.var.port)) + local req = { + 'GET /foo HTTP/1.0\r\n', + 'Host: localhost\r\n', + 'Connection: close\r\n\r\n', + } + local ok, err = sock:send(req) + if not ok then + ngx.say("send request failed: ", err) + return + end + + while true do + local data, err, _ = sock:receive('*l') + if err then + ngx.say('unexpected error occurs when receiving http head: ', err) + return + end + + if #data == 0 then -- read last line of head + break + end + end + + local data, err = sock:receiveany(128) + if err then + if err ~= 'closed' then + ngx.say('unexpected err: ', err) + end + else + ngx.say(data) + end + + sock:close() + } + } + + location = /foo { + content_by_lua_block { + local resp = 'hello world' + local length = #resp + + ngx.header['Content-Length'] = length + ngx.flush(true) + ngx.sleep(0.01) + + ngx.print(resp) + } + } + +--- request +GET /t +--- response_body +hello world +--- no_error_log +[error] +--- error_log +lua tcp socket calling receiveany() method to read at most 128 bytes + + + +=== TEST 68: receiveany with limited, max is smaller than data +--- config + server_tokens off; + location = /t { + set $port $TEST_NGINX_SERVER_PORT; + content_by_lua_block { + local sock = ngx.socket.tcp() + sock:settimeout(500) + assert(sock:connect("127.0.0.1", ngx.var.port)) + local req = { + 'GET /foo HTTP/1.0\r\n', + 'Host: localhost\r\n', + 'Connection: close\r\n\r\n', + } + local ok, err = sock:send(req) + if not ok then + ngx.say("send request failed: ", err) + return + end + + while true do + local data, err, _ = sock:receive('*l') + if err then + ngx.say('unexpected error occurs when receiving http head: ', err) + return + end + + if #data == 0 then -- read last line of head + break + end + end + + while true do + local data, err = sock:receiveany(7) + if err then + if err ~= 'closed' then + ngx.say('unexpected err: ', err) + end + break + + else + ngx.say(data) + end + end + + sock:close() + } + } + + location = /foo { + content_by_lua_block { + local resp = 'hello world' + local length = #resp + + ngx.header['Content-Length'] = length + ngx.flush(true) + ngx.sleep(0.01) + + ngx.print(resp) + } + } + +--- request +GET /t +--- response_body +hello w +orld +--- no_error_log +[error] +--- error_log +lua tcp socket calling receiveany() method to read at most 7 bytes diff --git a/debian/modules/http-lua/t/062-count.t b/debian/modules/http-lua/t/062-count.t index 2ad2f9f..9b0afe8 100644 --- a/debian/modules/http-lua/t/062-count.t +++ b/debian/modules/http-lua/t/062-count.t @@ -283,7 +283,7 @@ n = 5 --- request GET /test --- response_body -n = 18 +n = 22 --- no_error_log [error] @@ -444,7 +444,28 @@ worker: 4 -=== TEST 20: entries under the metatable of udp sockets +=== TEST 20: entries under the metatable of tcp sockets +--- config + location = /test { + content_by_lua_block { + local n = 0 + local sock = ngx.socket.tcp() + for k, v in pairs(getmetatable(sock)) do + n = n + 1 + end + ngx.say("n = ", n) + } + } +--- request +GET /test +--- response_body +n = 13 +--- no_error_log +[error] + + + +=== TEST 21: entries under the metatable of udp sockets --- config location = /test { content_by_lua ' @@ -465,7 +486,7 @@ n = 6 -=== TEST 21: entries under the metatable of req raw sockets +=== TEST 22: entries under the metatable of req raw sockets --- config location = /test { content_by_lua ' @@ -497,7 +518,7 @@ n = 6 -=== TEST 22: entries under the req raw sockets +=== TEST 23: entries under the req raw sockets --- config location = /test { content_by_lua_block { @@ -536,7 +557,7 @@ nrec = 3 -=== TEST 23: entries under the req sockets +=== TEST 24: entries under the req sockets --- config location = /test { content_by_lua_block { diff --git a/debian/modules/http-lua/t/063-abort.t b/debian/modules/http-lua/t/063-abort.t index 411a07e..7c90eaa 100644 --- a/debian/modules/http-lua/t/063-abort.t +++ b/debian/modules/http-lua/t/063-abort.t @@ -22,7 +22,7 @@ __DATA__ === TEST 1: ngx.exit(400) should abort print --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /memc_query { internal; @@ -68,7 +68,7 @@ GET /test?a === TEST 2: ngx.exit(400) should abort ngx.log --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /memc_query { internal; @@ -116,7 +116,7 @@ GET /test?a === TEST 3: ngx.exit(400) should abort ngx.location.capture --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /memc_query { internal; @@ -161,7 +161,7 @@ the "$memc_key" variable is not set === TEST 4: ngx.exit(400) should abort ngx.location.capture_multi --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /memc_query { internal; @@ -206,7 +206,7 @@ the "$memc_key" variable is not set === TEST 5: ngx.exit(400) should abort ngx.redirect --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -233,7 +233,7 @@ lua redirect to "/blah" with code 302 === TEST 6: ngx.exit(400) should abort ngx.exit --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -260,7 +260,7 @@ lua exit with code 503 === TEST 7: ngx.exit(400) should abort ngx.exec --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -287,7 +287,7 @@ lua exec "/blah?" === TEST 8: ngx.exit(400) should abort ngx.send_headers --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -314,7 +314,7 @@ lua send headers === TEST 9: ngx.exit(400) should abort ngx.print --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -341,7 +341,7 @@ lua print response === TEST 10: ngx.exit(400) should abort ngx.say --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -368,7 +368,7 @@ lua say response === TEST 11: ngx.exit(400) should abort ngx.flush --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -395,7 +395,7 @@ lua flush asynchronously === TEST 12: ngx.exit(400) should abort ngx.eof --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -422,7 +422,7 @@ lua send eof === TEST 13: ngx.exit(400) should abort ngx.re.match --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -449,7 +449,7 @@ lua compiling match regex "a" with options "jo" === TEST 14: ngx.exit(400) should abort ngx.re.gmatch --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -476,7 +476,7 @@ lua compiling gmatch regex "a" with options "jo" === TEST 15: ngx.exit(400) should abort ngx.re.sub --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -503,7 +503,7 @@ lua compiling sub regex "a" with options "jo" === TEST 16: ngx.exit(400) should abort ngx.re.gsub --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -530,7 +530,7 @@ lua compiling gsub regex "a" with options "jo" === TEST 17: ngx.exit(400) should abort ngx.shared.DICT (set) --- http_config eval - "lua_shared_dict dogs 1m; lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_shared_dict dogs 1m; lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -560,7 +560,7 @@ foo = 56 === TEST 18: ngx.exit(400) should abort ngx.shared.DICT (replace) --- http_config eval - "lua_shared_dict dogs 1m; lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_shared_dict dogs 1m; lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -590,7 +590,7 @@ foo = 56 === TEST 19: ngx.exit(400) should abort ngx.shared.DICT (incr) --- http_config eval - "lua_shared_dict dogs 1m; lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_shared_dict dogs 1m; lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -620,7 +620,7 @@ foo = 88 === TEST 20: ngx.exit(400) should abort ngx.shared.DICT (get) --- http_config eval - "lua_shared_dict dogs 1m; lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_shared_dict dogs 1m; lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -649,7 +649,7 @@ fetching key "foo" in shared dict "dogs" === TEST 21: ngx.exit(400) should skip os.execute --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -679,7 +679,7 @@ GET /test === TEST 22: ngx.exit(400) should break pcall and skip os.execute --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -709,7 +709,7 @@ fetching key "foo" in shared dict "dogs" === TEST 23: ngx.exit(400) should break pcall and skip os.execute (all in user module) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -739,7 +739,7 @@ GET /test === TEST 24: ngx.redirect() should break pcall and skip os.execute (all in user module) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -769,7 +769,7 @@ GET /test === TEST 25: ngx.redirect() should skip os.execute (all in user module) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -799,7 +799,7 @@ GET /test === TEST 26: ngx.exec() should break pcall and skip os.execute (all in user module) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -832,7 +832,7 @@ foo === TEST 27: ngx.exec() should skip os.execute (all in user module) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -865,7 +865,7 @@ foo === TEST 28: ngx.set_uri(uri, true) should break pcall and skip os.execute (all in user module) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { rewrite_by_lua ' @@ -921,7 +921,7 @@ hello world === TEST 30: ngx.exit(400) should break xpcall and skip os.execute (all in user module) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -955,7 +955,7 @@ GET /test === TEST 31: ngx.exec() should skip os.execute (all in user module) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' @@ -988,7 +988,7 @@ foo === TEST 32: ngx.exec() should break pcall and skip os.execute (all in user module) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' diff --git a/debian/modules/http-lua/t/064-pcall.t b/debian/modules/http-lua/t/064-pcall.t index 3011f3e..9af2de7 100644 --- a/debian/modules/http-lua/t/064-pcall.t +++ b/debian/modules/http-lua/t/064-pcall.t @@ -22,11 +22,11 @@ __DATA__ === TEST 1: pcall works --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' - function f(a, b) + local function f(a, b) if a == 0 and b == 0 then error("zero error") end @@ -58,11 +58,11 @@ $/s === TEST 2: xpcall works --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /test { content_by_lua ' - function f(a, b) + local function f(a, b) if a == 0 and b == 0 then error("zero error") end @@ -70,15 +70,15 @@ $/s return 23, "hello", true end - function g() + local function g() return f(0, 0) end - function h() + local function h() return f(0) end - function err(...) + local function err(...) ngx.say("error handler called: ", ...) return "this is the new err" end diff --git a/debian/modules/http-lua/t/065-tcp-socket-timeout.t b/debian/modules/http-lua/t/065-tcp-socket-timeout.t index 78b8cff..092094a 100644 --- a/debian/modules/http-lua/t/065-tcp-socket-timeout.t +++ b/debian/modules/http-lua/t/065-tcp-socket-timeout.t @@ -51,7 +51,7 @@ __DATA__ location /t { content_by_lua ' local sock = ngx.socket.tcp() - local ok, err = sock:connect("agentzh.org", 12345) + local ok, err = sock:connect("127.0.0.2", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -66,7 +66,7 @@ GET /t failed to connect: timeout --- error_log lua tcp socket connect timeout: 100 -lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 +lua tcp socket connect timed out, when connecting to 127.0.0.2:12345 --- timeout: 10 @@ -81,7 +81,7 @@ lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 content_by_lua ' local sock = ngx.socket.tcp() sock:settimeout(150) - local ok, err = sock:connect("agentzh.org", 12345) + local ok, err = sock:connect("127.0.0.2", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -96,7 +96,7 @@ GET /t failed to connect: timeout --- error_log lua tcp socket connect timeout: 150 -lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 +lua tcp socket connect timed out, when connecting to 127.0.0.2:12345 --- timeout: 10 @@ -110,7 +110,7 @@ lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 content_by_lua ' local sock = ngx.socket.tcp() sock:settimeout(nil) - local ok, err = sock:connect("agentzh.org", 12345) + local ok, err = sock:connect("127.0.0.2", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -125,7 +125,7 @@ GET /t failed to connect: timeout --- error_log lua tcp socket connect timeout: 102 -lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 +lua tcp socket connect timed out, when connecting to 127.0.0.2:12345 @@ -139,7 +139,7 @@ lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 content_by_lua ' local sock = ngx.socket.tcp() sock:settimeout(0) - local ok, err = sock:connect("agentzh.org", 12345) + local ok, err = sock:connect("127.0.0.2", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -154,7 +154,7 @@ GET /t failed to connect: timeout --- error_log lua tcp socket connect timeout: 102 -lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 +lua tcp socket connect timed out, when connecting to 127.0.0.2:12345 --- timeout: 10 @@ -168,7 +168,7 @@ lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 content_by_lua ' local sock = ngx.socket.tcp() sock:settimeout(-1) - local ok, err = sock:connect("agentzh.org", 12345) + local ok, err = sock:connect("127.0.0.2", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -584,7 +584,7 @@ bad timeout value --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -683,7 +683,7 @@ after location /t { content_by_lua ' local sock = ngx.socket.tcp() - local ok, err = sock:connect("agentzh.org", 12345) + local ok, err = sock:connect("127.0.0.2", 12345) if not ok then ngx.say("1: failed to connect: ", err) @@ -707,7 +707,7 @@ GET /t 2: connected: 1 --- error_log lua tcp socket connect timeout: 100 -lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 +lua tcp socket connect timed out, when connecting to 127.0.0.2:12345 --- timeout: 10 diff --git a/debian/modules/http-lua/t/066-socket-receiveuntil.t b/debian/modules/http-lua/t/066-socket-receiveuntil.t index ffe74aa..89d2abf 100644 --- a/debian/modules/http-lua/t/066-socket-receiveuntil.t +++ b/debian/modules/http-lua/t/066-socket-receiveuntil.t @@ -245,7 +245,7 @@ close: 1 nil local reader = sock:receiveuntil("abcabd") for i = 1, 2 do - line, err, part = reader() + local line, err, part = reader() if line then ngx.say("read: ", line) @@ -316,7 +316,7 @@ close: 1 nil local reader = sock:receiveuntil("aa") for i = 1, 2 do - line, err, part = reader() + local line, err, part = reader() if line then ngx.say("read: ", line) @@ -387,7 +387,7 @@ close: 1 nil local reader = sock:receiveuntil("aaa") for i = 1, 2 do - line, err, part = reader() + local line, err, part = reader() if line then ngx.say("read: ", line) @@ -458,7 +458,7 @@ close: 1 nil local reader = sock:receiveuntil("aaaaad") for i = 1, 2 do - line, err, part = reader() + local line, err, part = reader() if line then ngx.say("read: ", line) @@ -530,7 +530,7 @@ close: 1 nil local reader = sock:receiveuntil("aaaaad") for i = 1, 2 do - line, err, part = reader() + local line, err, part = reader() if line then ngx.say("read: ", line) @@ -602,7 +602,7 @@ close: 1 nil local reader = sock:receiveuntil("aaaaad") for i = 1, 2 do - line, err, part = reader() + local line, err, part = reader() if line then ngx.say("read: ", line) @@ -673,7 +673,7 @@ close: 1 nil local reader = sock:receiveuntil("abcabdabcabe") for i = 1, 2 do - line, err, part = reader() + local line, err, part = reader() if line then ngx.say("read: ", line) @@ -744,7 +744,7 @@ close: 1 nil local reader = sock:receiveuntil("abcabdabcabe") for i = 1, 2 do - line, err, part = reader() + local line, err, part = reader() if line then ngx.say("read: ", line) @@ -815,7 +815,7 @@ close: 1 nil local reader = sock:receiveuntil("abcabdabcabe") for i = 1, 2 do - line, err, part = reader() + local line, err, part = reader() if line then ngx.say("read: ", line) @@ -886,7 +886,7 @@ close: 1 nil local reader = sock:receiveuntil("abcabdabcabe") for i = 1, 2 do - line, err, part = reader() + local line, err, part = reader() if line then ngx.say("read: ", line) @@ -957,7 +957,7 @@ close: 1 nil local reader = sock:receiveuntil("--abc") for i = 1, 2 do - line, err, part = reader() + local line, err, part = reader() if line then ngx.say("read: ", line) @@ -1028,7 +1028,7 @@ close: 1 nil local reader = sock:receiveuntil("--abc") for i = 1, 7 do - line, err, part = reader(4) + local line, err, part = reader(4) if line then ngx.say("read: ", line) @@ -1105,7 +1105,7 @@ close: 1 nil local reader = sock:receiveuntil("--abc") for i = 1, 7 do - line, err, part = reader(4) + local line, err, part = reader(4) if line then ngx.say("read: ", line) @@ -1182,7 +1182,7 @@ close: 1 nil local reader = sock:receiveuntil("--abc") for i = 1, 7 do - line, err, part = reader(4) + local line, err, part = reader(4) if line then ngx.say("read: ", line) @@ -1270,7 +1270,7 @@ close: 1 nil local reader = sock:receiveuntil("abcabd") for i = 1, 2 do - line, err, part = reader() + local line, err, part = reader() if line then ngx.say("read: ", line) diff --git a/debian/modules/http-lua/t/067-req-socket.t b/debian/modules/http-lua/t/067-req-socket.t index 229d5cc..6593360 100644 --- a/debian/modules/http-lua/t/067-req-socket.t +++ b/debian/modules/http-lua/t/067-req-socket.t @@ -320,7 +320,7 @@ found the end of the stream === TEST 4: attempt to use the req socket across request boundary --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /t { content_by_lua ' @@ -369,7 +369,7 @@ hello world === TEST 5: receive until on request_body - receiveuntil(1) on the last byte of the body See https://groups.google.com/group/openresty/browse_thread/thread/43cf01da3c681aba for details --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /t { content_by_lua ' @@ -431,7 +431,7 @@ done === TEST 6: pipelined POST requests --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /t { content_by_lua ' diff --git a/debian/modules/http-lua/t/068-socket-keepalive.t b/debian/modules/http-lua/t/068-socket-keepalive.t index f052e9a..e4c6988 100644 --- a/debian/modules/http-lua/t/068-socket-keepalive.t +++ b/debian/modules/http-lua/t/068-socket-keepalive.t @@ -4,13 +4,14 @@ use Test::Nginx::Socket::Lua; #repeat_each(2); -plan tests => repeat_each() * (blocks() * 5 + 9); +plan tests => repeat_each() * (blocks() * 4 + 31); our $HtmlDir = html_dir; $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; $ENV{TEST_NGINX_HTML_DIR} = $HtmlDir; $ENV{TEST_NGINX_REDIS_PORT} ||= 6379; +$ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; $ENV{LUA_PATH} ||= '/usr/local/openresty-debug/lualib/?.lua;/usr/local/openresty/lualib/?.lua;;'; @@ -29,7 +30,7 @@ __DATA__ === TEST 1: sanity --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -97,7 +98,7 @@ lua tcp socket keepalive create connection pool for key "127.0.0.1:$ENV{TEST_NGI === TEST 2: free up the whole connection pool if no active connections --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -168,7 +169,7 @@ received: OK === TEST 3: upstream sockets close prematurely --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; keepalive_timeout 100ms; @@ -243,7 +244,7 @@ done === TEST 4: http keepalive --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location /t { @@ -701,7 +702,35 @@ qr/lua tcp socket connection pool size: 25\b/] -=== TEST 10: sock:keepalive_timeout(0) means unlimited +=== TEST 10: setkeepalive() 'pool_size' should be greater than zero +--- config + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + content_by_lua_block { + local sock, err = ngx.socket.connect("127.0.0.1", ngx.var.port) + if not sock then + ngx.say(err) + return + end + + local ok, err = pcall(sock.setkeepalive, sock, 0, 0) + if not ok then + ngx.say(err) + return + end + ngx.say(ok) + } + } +--- request +GET /t +--- response_body +bad argument #3 to '?' (bad "pool_size" option value: 0) +--- no_error_log +[error] + + + +=== TEST 11: sock:keepalive_timeout(0) means unlimited --- config server_tokens off; location /t { @@ -776,10 +805,10 @@ qr/lua tcp socket connection pool size: 30\b/] -=== TEST 11: sanity (uds) +=== TEST 12: sanity (uds) --- http_config eval " - lua_package_path '$::HtmlDir/?.lua;./?.lua'; + lua_package_path '$::HtmlDir/?.lua;./?.lua;;'; server { listen unix:$::HtmlDir/nginx.sock; default_type 'text/plain'; @@ -858,7 +887,7 @@ received response of 119 bytes -=== TEST 12: github issue #108: ngx.locaiton.capture + redis.set_keepalive +=== TEST 13: github issue #108: ngx.locaiton.capture + redis.set_keepalive --- http_config eval qq{ lua_package_path "$::HtmlDir/?.lua;;"; @@ -905,9 +934,9 @@ lua tcp socket get keepalive peer: using connection -=== TEST 13: github issue #110: ngx.exit with HTTP_NOT_FOUND causes worker process to exit +=== TEST 14: github issue #110: ngx.exit with HTTP_NOT_FOUND causes worker process to exit --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config error_page 404 /404.html; location /t { @@ -964,9 +993,9 @@ Not found, dear... -=== TEST 14: custom pools (different pool for the same host:port) - tcp +=== TEST 15: custom pools (different pool for the same host:port) - tcp --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -1012,9 +1041,9 @@ lua tcp socket keepalive create connection pool for key "B" -=== TEST 15: custom pools (same pool for different host:port) - tcp +=== TEST 16: custom pools (same pool for different host:port) - tcp --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -1059,10 +1088,10 @@ lua tcp socket get keepalive peer: using connection -=== TEST 16: custom pools (different pool for the same host:port) - unix +=== TEST 17: custom pools (different pool for the same host:port) - unix --- http_config eval " - lua_package_path '$::HtmlDir/?.lua;./?.lua'; + lua_package_path '$::HtmlDir/?.lua;./?.lua;;'; server { listen unix:$::HtmlDir/nginx.sock; default_type 'text/plain'; @@ -1119,10 +1148,10 @@ lua tcp socket keepalive create connection pool for key "B" -=== TEST 17: custom pools (same pool for the same path) - unix +=== TEST 18: custom pools (same pool for the same path) - unix --- http_config eval " - lua_package_path '$::HtmlDir/?.lua;./?.lua'; + lua_package_path '$::HtmlDir/?.lua;./?.lua;;'; server { listen unix:$::HtmlDir/nginx.sock; default_type 'text/plain'; @@ -1174,9 +1203,9 @@ lua tcp socket get keepalive peer: using connection -=== TEST 18: numeric pool option value +=== TEST 19: numeric pool option value --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -1221,9 +1250,9 @@ lua tcp socket get keepalive peer: using connection -=== TEST 19: nil pool option value +=== TEST 20: nil pool option value --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -1264,9 +1293,9 @@ connected: 1, reused: 0 -=== TEST 20: (bad) table pool option value +=== TEST 21: (bad) table pool option value --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -1305,9 +1334,9 @@ bad argument #3 to 'connect' (bad "pool" option type: table) -=== TEST 21: (bad) boolean pool option value +=== TEST 22: (bad) boolean pool option value --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -1346,7 +1375,7 @@ bad argument #3 to 'connect' (bad "pool" option type: boolean) -=== TEST 22: clear the redis store +=== TEST 23: clear the redis store --- config location /t { redis2_query flushall; @@ -1363,9 +1392,9 @@ bad argument #3 to 'connect' (bad "pool" option type: boolean) -=== TEST 23: bug in send(): clear the chain writer ctx +=== TEST 24: bug in send(): clear the chain writer ctx --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location /t { set $port $TEST_NGINX_REDIS_PORT; @@ -1478,7 +1507,7 @@ done -=== TEST 24: setkeepalive() with explicit nil args +=== TEST 25: setkeepalive() with explicit nil args --- config server_tokens off; location /t { @@ -1551,3 +1580,1379 @@ done "lua tcp socket keepalive timeout: 100 ms", qr/lua tcp socket connection pool size: 30\b/] --- timeout: 4 + + + +=== TEST 26: conn queuing: connect() verifies the options for connection pool +--- config + location /t { + set $port $TEST_NGINX_SERVER_PORT; + + content_by_lua_block { + local sock = ngx.socket.tcp() + local function check_opts_for_connect(opts) + local ok, err = pcall(function() + sock:connect("127.0.0.1", ngx.var.port, opts) + end) + if not ok then + ngx.say(err) + else + ngx.say("ok") + end + end + + check_opts_for_connect({pool_size = 'a'}) + check_opts_for_connect({pool_size = 0}) + check_opts_for_connect({backlog = -1}) + check_opts_for_connect({backlog = 0}) + } + } +--- request +GET /t +--- response_body_like +.+ 'connect' \(bad "pool_size" option type: string\) +.+ 'connect' \(bad "pool_size" option value: 0\) +.+ 'connect' \(bad "backlog" option value: -1\) +ok +--- no_error_log +[error] + + + +=== TEST 27: conn queuing: connect() can specify 'pool_size' which overrides setkeepalive() +--- config + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + local port = ngx.var.port + local function go() + local sock = ngx.socket.tcp() + local ok, err = sock:connect("127.0.0.1", port, {pool_size = 1}) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok, ", reused: ", sock:getreusedtimes()) + + local req = "flush_all\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 line, err, part = sock:receive() + if line then + ngx.say("received: ", line) + else + ngx.say("failed to receive a line: ", err, " [", part, "]") + end + + local ok, err = sock:setkeepalive(0, 20) + if not ok then + ngx.say("failed to set reusable: ", err) + end + end + + -- reuse ok + go() + go() + + local sock1 = ngx.socket.connect("127.0.0.1", port) + local sock2 = ngx.socket.connect("127.0.0.1", port) + local ok, err = sock1:setkeepalive(0, 20) + if not ok then + ngx.say(err) + end + local ok, err = sock2:setkeepalive(0, 20) + if not ok then + ngx.say(err) + end + + -- the pool_size is 1 instead of 20 + sock1 = ngx.socket.connect("127.0.0.1", port) + sock2 = ngx.socket.connect("127.0.0.1", port) + ngx.say("reused: ", sock1:getreusedtimes()) + ngx.say("reused: ", sock2:getreusedtimes()) + sock1:setkeepalive(0, 20) + sock2:setkeepalive(0, 20) + } + } +--- request +GET /t +--- response_body +connected: 1, reused: 0 +request sent: 11 +received: OK +connected: 1, reused: 1 +request sent: 11 +received: OK +reused: 1 +reused: 0 +--- no_error_log eval +["[error]", +"lua tcp socket keepalive: free connection pool for ", +"lua tcp socket connection pool size: 20"] +--- error_log eval +[qq{lua tcp socket keepalive create connection pool for key "127.0.0.1:$ENV{TEST_NGINX_MEMCACHED_PORT}"}, +"lua tcp socket connection pool size: 1", +] + + + +=== TEST 28: conn queuing: connect() can specify 'pool_size' for unix domain socket +--- http_config eval +" + server { + listen unix:$::HtmlDir/nginx.sock; + } +" +--- config + location /t { + content_by_lua_block { + local path = "unix:" .. "$TEST_NGINX_HTML_DIR/nginx.sock"; + local function go() + local sock = ngx.socket.tcp() + local ok, err = sock:connect(path, {pool_size = 1}) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok, ", reused: ", sock:getreusedtimes()) + + local ok, err = sock:setkeepalive(0, 20) + if not ok then + ngx.say("failed to set reusable: ", err) + end + end + + go() + go() + + local sock1 = ngx.socket.connect(path) + local sock2 = ngx.socket.connect(path) + local ok, err = sock1:setkeepalive(0, 20) + if not ok then + ngx.say(err) + end + local ok, err = sock2:setkeepalive(0, 20) + if not ok then + ngx.say(err) + end + + -- the pool_size is 1 instead of 20 + sock1 = ngx.socket.connect(path) + sock2 = ngx.socket.connect(path) + ngx.say("reused: ", sock1:getreusedtimes()) + ngx.say("reused: ", sock2:getreusedtimes()) + sock1:setkeepalive(0, 20) + sock2:setkeepalive(0, 20) + } + } +--- request +GET /t +--- response_body +connected: 1, reused: 0 +connected: 1, reused: 1 +reused: 1 +reused: 0 +--- no_error_log eval +["[error]", +"lua tcp socket keepalive: free connection pool for ", +"lua tcp socket connection pool size: 20"] +--- error_log eval +["lua tcp socket get keepalive peer: using connection", +'lua tcp socket keepalive create connection pool for key "unix:', +"lua tcp socket connection pool size: 1", +] + + + +=== TEST 29: conn queuing: connect() can specify 'pool_size' for custom pool +--- config + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + local port = ngx.var.port + local function go(pool) + local sock = ngx.socket.tcp() + local ok, err = sock:connect("127.0.0.1", port, {pool = pool, pool_size = 1}) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", pool, ", reused: ", sock:getreusedtimes()) + + local ok, err = sock:setkeepalive(0, 20) + if not ok then + ngx.say("failed to set reusable: ", err) + end + end + + go('A') + go('B') + go('A') + go('B') + + local sock1 = ngx.socket.connect("127.0.0.1", port, {pool = 'A'}) + local sock2 = ngx.socket.connect("127.0.0.1", port, {pool = 'A'}) + local ok, err = sock1:setkeepalive(0, 20) + if not ok then + ngx.say(err) + end + local ok, err = sock2:setkeepalive(0, 20) + if not ok then + ngx.say(err) + end + + -- the pool_size is 1 instead of 20 + sock1 = ngx.socket.connect("127.0.0.1", port, {pool = 'A'}) + sock2 = ngx.socket.connect("127.0.0.1", port, {pool = 'A'}) + ngx.say("reused: ", sock1:getreusedtimes()) + ngx.say("reused: ", sock2:getreusedtimes()) + sock1:setkeepalive(0, 20) + sock2:setkeepalive(0, 20) + } + } +--- request +GET /t +--- response_body +connected: A, reused: 0 +connected: B, reused: 0 +connected: A, reused: 1 +connected: B, reused: 1 +reused: 1 +reused: 0 +--- no_error_log eval +["[error]", +"lua tcp socket keepalive: free connection pool for ", +"lua tcp socket connection pool size: 20"] +--- error_log eval +[qq{lua tcp socket keepalive create connection pool for key "A"}, +qq{lua tcp socket keepalive create connection pool for key "B"}, +"lua tcp socket connection pool size: 1", +] + + + +=== TEST 30: conn queuing: connect() uses lua_socket_pool_size as default if 'backlog' is given +--- config + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + lua_socket_pool_size 1234; + + content_by_lua_block { + local port = ngx.var.port + local opts = {backlog = 0} + local sock, err = ngx.socket.connect("127.0.0.1", port, opts) + if not sock then + ngx.say(err) + else + ngx.say("ok") + end + } + } +--- request +GET /t +--- response_body +ok +--- error_log +lua tcp socket connection pool size: 1234 +--- no_error_log +[error] + + + +=== TEST 31: conn queuing: more connect operations than 'backlog' size +--- config + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + local port = ngx.var.port + local opts = {pool_size = 2, backlog = 0} + local sock = ngx.socket.connect("127.0.0.1", port, opts) + local not_reused_socket, err = ngx.socket.connect("127.0.0.1", port, opts) + if not not_reused_socket then + ngx.say(err) + return + end + -- burst + local ok, err = ngx.socket.connect("127.0.0.1", port, opts) + if not ok then + ngx.say(err) + end + + local ok, err = sock:setkeepalive() + if not ok then + ngx.say(err) + return + end + + ok, err = sock:connect("127.0.0.1", port, opts) + if not ok then + ngx.say(err) + end + ngx.say("reused: ", sock:getreusedtimes()) + -- both queue and pool is full + ok, err = ngx.socket.connect("127.0.0.1", port, opts) + if not ok then + ngx.say(err) + end + } + } +--- request +GET /t +--- response_body +too many waiting connect operations +reused: 1 +too many waiting connect operations +--- no_error_log +[error] + + + +=== TEST 32: conn queuing: once 'pool_size' is reached and pool has 'backlog' +--- config + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + local port = ngx.var.port + local opts = {pool_size = 2, backlog = 2} + local sock1 = ngx.socket.connect("127.0.0.1", port, opts) + + ngx.timer.at(0, function(premature) + local sock2, err = ngx.socket.connect("127.0.0.1", port, opts) + if not sock2 then + ngx.log(ngx.ERR, err) + return + end + + ngx.log(ngx.WARN, "start to handle timer") + ngx.sleep(0.1) + sock2:close() + -- resume connect operation + ngx.log(ngx.WARN, "continue to handle timer") + end) + + ngx.sleep(0.05) + ngx.log(ngx.WARN, "start to handle cosocket") + local sock3, err = ngx.socket.connect("127.0.0.1", port, opts) + if not sock3 then + ngx.say(err) + return + end + ngx.log(ngx.WARN, "continue to handle cosocket") + + local req = "flush_all\r\n" + local bytes, err = sock3:send(req) + if not bytes then + ngx.say("failed to send request: ", err) + return + end + ngx.say("request sent: ", bytes) + + local line, err, part = sock3:receive() + if line then + ngx.say("received: ", line) + else + ngx.say("failed to receive a line: ", err, " [", part, "]") + end + + local ok, err = sock3:setkeepalive() + if not ok then + ngx.say("failed to set reusable: ", err) + end + ngx.say("setkeepalive: OK") + } + } +--- request +GET /t +--- response_body +request sent: 11 +received: OK +setkeepalive: OK +--- no_error_log +[error] +--- error_log +lua tcp socket queue connect operation for connection pool "127.0.0.1 +--- grep_error_log eval: qr/(start|continue) to handle \w+/ +--- grep_error_log_out +start to handle timer +start to handle cosocket +continue to handle timer +continue to handle cosocket + + + +=== TEST 33: conn queuing: do not count failed connect operations +--- config + resolver $TEST_NGINX_RESOLVER ipv6=off; + resolver_timeout 3s; + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + local port = ngx.var.port + local opts = {pool = "test", pool_size = 1, backlog = 0} + + local sock = ngx.socket.tcp() + sock:settimeouts(100, 3000, 3000) + local ok, err = sock:connect("127.0.0.2", 12345, opts) + if not ok then + ngx.say(err) + end + + local sock, err = ngx.socket.connect("127.0.0.1", port, opts) + if not sock then + ngx.say(err) + end + ngx.say("ok") + } + } +--- request +GET /t +--- error_log +lua tcp socket connect timed out, when connecting to +--- response_body +timeout +ok + + + +=== TEST 34: conn queuing: connect until backlog is reached +--- config + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + local port = ngx.var.port + local opts = {pool_size = 1, backlog = 1} + local sock1 = ngx.socket.connect("127.0.0.1", port, opts) + + ngx.timer.at(0.01, function(premature) + ngx.log(ngx.WARN, "start to handle timer") + local sock2, err = ngx.socket.connect("127.0.0.1", port, opts) + if not sock2 then + ngx.log(ngx.ERR, err) + return + end + + ngx.sleep(0.02) + local ok, err = sock2:close() + if not ok then + ngx.log(ngx.ERR, err) + end + ngx.log(ngx.WARN, "continue to handle timer") + end) + + ngx.sleep(0.02) + local sock3, err = ngx.socket.connect("127.0.0.1", port, opts) + if not sock3 then + ngx.say(err) + end + local ok, err = sock1:setkeepalive() + if not ok then + ngx.say(err) + return + end + ngx.sleep(0.01) -- run sock2 + + ngx.log(ngx.WARN, "start to handle cosocket") + local sock3, err = ngx.socket.connect("127.0.0.1", port, opts) + if not sock3 then + ngx.say(err) + return + end + ngx.log(ngx.WARN, "continue to handle cosocket") + + local ok, err = sock3:setkeepalive() + if not ok then + ngx.say(err) + end + } + } +--- request +GET /t +--- response_body +too many waiting connect operations +--- no_error_log +[error] +--- error_log +lua tcp socket queue connect operation for connection pool "127.0.0.1 +--- grep_error_log eval: qr/queue connect operation for connection pool|(start|continue) to handle \w+/ +--- grep_error_log_out +start to handle timer +queue connect operation for connection pool +start to handle cosocket +queue connect operation for connection pool +continue to handle timer +continue to handle cosocket + + + +=== TEST 35: conn queuing: memory reuse for host in queueing connect operation ctx +--- config + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + local port = ngx.var.port + local opts = {pool = "test", pool_size = 1, backlog = 3} + local sock = ngx.socket.connect("127.0.0.1", port, opts) + + ngx.timer.at(0.01, function(premature) + local sock, err = ngx.socket.connect("0.0.0.0", port, opts) + if not sock then + ngx.log(ngx.ERR, err) + return + end + + local ok, err = sock:close() + if not ok then + ngx.log(ngx.ERR, err) + end + end) + + ngx.timer.at(0.015, function(premature) + local sock, err = ngx.socket.connect("127.0.0.1", port, opts) + if not sock then + ngx.log(ngx.ERR, err) + return + end + + local ok, err = sock:close() + if not ok then + ngx.log(ngx.ERR, err) + end + end) + + ngx.timer.at(0.02, function(premature) + local sock, err = ngx.socket.connect("0.0.0.0", port, opts) + if not sock then + ngx.log(ngx.ERR, err) + return + end + + local ok, err = sock:close() + if not ok then + ngx.log(ngx.ERR, err) + end + end) + + ngx.sleep(0.03) + local ok, err = sock:setkeepalive() + if not ok then + ngx.say(err) + return + end + ngx.say("ok") + } + } +--- request +GET /t +--- response_body +ok +--- no_error_log +[error] +--- grep_error_log eval: qr/queue connect operation for connection pool/ +--- grep_error_log_out +queue connect operation for connection pool +queue connect operation for connection pool +queue connect operation for connection pool + + + +=== TEST 36: conn queuing: connect() returns error after connect operation resumed +--- config + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + local port = ngx.var.port + local opts = {pool = "test", pool_size = 1, backlog = 1} + local sock = ngx.socket.connect("127.0.0.1", port, opts) + + ngx.timer.at(0, function(premature) + local sock, err = ngx.socket.connect("", port, opts) + if not sock then + ngx.log(ngx.WARN, err) + end + end) + + ngx.sleep(0.01) + -- use 'close' to force parsing host instead of reusing conn + local ok, err = sock:close() + if not ok then + ngx.say(err) + return + end + ngx.say("ok") + } + } +--- request +GET /t +--- response_body +ok +--- no_error_log +[error] +--- error_log +failed to parse host name +--- grep_error_log eval: qr/queue connect operation for connection pool/ +--- grep_error_log_out +queue connect operation for connection pool + + + +=== TEST 37: conn queuing: in uthread +--- config + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + local port = ngx.var.port + local opts = {pool_size = 1, backlog = 2} + + local conn_sock = function() + local sock, err = ngx.socket.connect("127.0.0.1", port, opts) + if not sock then + ngx.say(err) + return + end + ngx.say("start to handle uthread") + + ngx.sleep(0.01) + sock:close() + ngx.say("continue to handle other uthread") + end + + local sock, err = ngx.socket.connect("127.0.0.1", port, opts) + if not sock then + ngx.log(ngx.ERR, err) + return + end + + local co1 = ngx.thread.spawn(conn_sock) + local co2 = ngx.thread.spawn(conn_sock) + local co3 = ngx.thread.spawn(conn_sock) + + local ok, err = sock:setkeepalive() + if not ok then + ngx.log(ngx.ERR, err) + end + + ngx.thread.wait(co1) + ngx.thread.wait(co2) + ngx.thread.wait(co3) + ngx.say("all uthreads ok") + } + } +--- request +GET /t +--- response_body +too many waiting connect operations +start to handle uthread +continue to handle other uthread +start to handle uthread +continue to handle other uthread +all uthreads ok +--- no_error_log +[error] +--- grep_error_log eval: qr/queue connect operation for connection pool/ +--- grep_error_log_out +queue connect operation for connection pool +queue connect operation for connection pool + + + +=== TEST 38: conn queuing: in access_by_lua +--- config + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + access_by_lua_block { + local port = ngx.var.port + local opts = {pool_size = 1, backlog = 2} + + local conn_sock = function() + local sock, err = ngx.socket.connect("127.0.0.1", port, opts) + if not sock then + ngx.say(err) + return + end + ngx.say("start to handle uthread") + + ngx.sleep(0.01) + sock:close() + ngx.say("continue to handle other uthread") + end + + local sock, err = ngx.socket.connect("127.0.0.1", port, opts) + if not sock then + ngx.log(ngx.ERR, err) + return + end + + local co1 = ngx.thread.spawn(conn_sock) + local co2 = ngx.thread.spawn(conn_sock) + local co3 = ngx.thread.spawn(conn_sock) + + local ok, err = sock:setkeepalive() + if not ok then + ngx.log(ngx.ERR, err) + end + + ngx.thread.wait(co1) + ngx.thread.wait(co2) + ngx.thread.wait(co3) + ngx.say("all uthreads ok") + } + } +--- request +GET /t +--- response_body +too many waiting connect operations +start to handle uthread +continue to handle other uthread +start to handle uthread +continue to handle other uthread +all uthreads ok +--- no_error_log +[error] +--- grep_error_log eval: qr/queue connect operation for connection pool/ +--- grep_error_log_out +queue connect operation for connection pool +queue connect operation for connection pool + + + +=== TEST 39: conn queuing: in rewrite_by_lua +--- config + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + rewrite_by_lua_block { + local port = ngx.var.port + local opts = {pool_size = 1, backlog = 2} + + local conn_sock = function() + local sock, err = ngx.socket.connect("127.0.0.1", port, opts) + if not sock then + ngx.say(err) + return + end + ngx.say("start to handle uthread") + + ngx.sleep(0.01) + sock:close() + ngx.say("continue to handle other uthread") + end + + local sock, err = ngx.socket.connect("127.0.0.1", port, opts) + if not sock then + ngx.log(ngx.ERR, err) + return + end + + local co1 = ngx.thread.spawn(conn_sock) + local co2 = ngx.thread.spawn(conn_sock) + local co3 = ngx.thread.spawn(conn_sock) + + local ok, err = sock:setkeepalive() + if not ok then + ngx.log(ngx.ERR, err) + end + + ngx.thread.wait(co1) + ngx.thread.wait(co2) + ngx.thread.wait(co3) + ngx.say("all uthreads ok") + } + } +--- request +GET /t +--- response_body +too many waiting connect operations +start to handle uthread +continue to handle other uthread +start to handle uthread +continue to handle other uthread +all uthreads ok +--- no_error_log +[error] +--- grep_error_log eval: qr/queue connect operation for connection pool/ +--- grep_error_log_out +queue connect operation for connection pool +queue connect operation for connection pool + + + +=== TEST 40: conn queuing: in subrequest +--- config + set $port $TEST_NGINX_MEMCACHED_PORT; + + location /t { + content_by_lua_block { + local port = ngx.var.port + ngx.timer.at(0, function() + local opts = {pool_size = 1, backlog = 2} + local sock, err = ngx.socket.connect("127.0.0.1", port, opts) + if not sock then + ngx.log(ngx.ERR, err) + return + end + + ngx.sleep(0.1) + local ok, err = sock:setkeepalive() + if not ok then + ngx.log(ngx.ERR, err) + end + end) + + ngx.sleep(0.01) + local res1, res2, res3 = ngx.location.capture_multi{ + {"/conn"}, {"/conn"}, {"/conn"} + } + ngx.say(res1.body) + ngx.say(res2.body) + ngx.say(res3.body) + } + } + + location /conn { + content_by_lua_block { + local port = ngx.var.port + local sock, err = ngx.socket.connect("127.0.0.1", port) + if not sock then + ngx.print(err) + return + end + local ok, err = sock:setkeepalive() + if not ok then + ngx.print(err) + else + ngx.print("ok") + end + } + } +--- request +GET /t +--- response_body +ok +ok +too many waiting connect operations +--- no_error_log +[error] +--- grep_error_log eval: qr/queue connect operation for connection pool/ +--- grep_error_log_out +queue connect operation for connection pool +queue connect operation for connection pool + + + +=== TEST 41: conn queuing: timeouts when 'connect_timeout' is reached +--- config + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + local port = ngx.var.port + local opts = {pool_size = 1, backlog = 1} + local sock1 = ngx.socket.connect("127.0.0.1", port, opts) + + local sock2 = ngx.socket.tcp() + sock2:settimeouts(10, 3000, 3000) + local ok, err = sock2:connect("127.0.0.1", port, opts) + if not ok then + ngx.say(err) + end + } + } +--- request +GET /t +--- response_body +timeout +--- error_log eval +"lua tcp socket queued connect timed out, when trying to connect to 127.0.0.1:$ENV{TEST_NGINX_MEMCACHED_PORT}" + + + +=== TEST 42: conn queuing: set timeout via lua_socket_connect_timeout +--- config + lua_socket_connect_timeout 10ms; + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + local port = ngx.var.port + local opts = {pool_size = 1, backlog = 1} + local sock1 = ngx.socket.connect("127.0.0.1", port, opts) + + local sock2 = ngx.socket.tcp() + local ok, err = sock2:connect("127.0.0.1", port, opts) + if not ok then + ngx.say(err) + end + } + } +--- request +GET /t +--- response_body +timeout +--- error_log eval +"lua tcp socket queued connect timed out, when trying to connect to 127.0.0.1:$ENV{TEST_NGINX_MEMCACHED_PORT}" + + + +=== TEST 43: conn queuing: client aborting while connect operation is queued +--- config + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + local port = ngx.var.port + local opts = {pool_size = 1, backlog = 1} + local sock1 = ngx.socket.connect("127.0.0.1", port, opts) + + local sock2 = ngx.socket.tcp() + sock2:settimeouts(3000, 3000, 3000) + local ok, err = sock2:connect("127.0.0.1", port, opts) + if not ok then + ngx.say(err) + end + } + } +--- request +GET /t +--- ignore_response +--- timeout: 0.1 +--- abort +--- no_error_log +[error] + + + +=== TEST 44: conn queuing: resume next connect operation if resumed connect failed immediately +--- config + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + local port = ngx.var.port + local opts = {pool = "test", pool_size = 1, backlog = 2} + + local conn_sock = function(should_timeout) + local sock = ngx.socket.tcp() + local ok, err + if should_timeout then + ok, err = sock:connect("", port, opts) + else + ok, err = sock:connect("127.0.0.1", port, opts) + end + if not ok then + ngx.say(err) + return + end + ngx.say("connected in uthread") + sock:close() + end + + local sock, err = ngx.socket.connect("127.0.0.1", port, opts) + if not sock then + ngx.log(ngx.ERR, err) + return + end + + local co1 = ngx.thread.spawn(conn_sock, true) + local co2 = ngx.thread.spawn(conn_sock) + + local ok, err = sock:close() + if not ok then + ngx.log(ngx.ERR, err) + end + + ngx.thread.wait(co1) + ngx.thread.wait(co2) + ngx.say("ok") + } + } +--- request +GET /t +--- response_body +failed to parse host name "": no host +connected in uthread +ok +--- no_error_log +[error] + + + +=== TEST 45: conn queuing: resume connect operation if resumed connect failed (timeout) +--- config + resolver $TEST_NGINX_RESOLVER ipv6=off; + resolver_timeout 3s; + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + local port = ngx.var.port + local opts = {pool = "test", pool_size = 1, backlog = 1} + + local conn_sock = function(should_timeout) + local sock = ngx.socket.tcp() + local ok, err + if should_timeout then + sock:settimeouts(100, 3000, 3000) + ok, err = sock:connect("127.0.0.2", 12345, opts) + else + ok, err = sock:connect("127.0.0.1", port, opts) + end + if not ok then + ngx.say(err) + return + end + ngx.say("connected in uthread") + sock:close() + end + + local co1 = ngx.thread.spawn(conn_sock, true) + local co2 = ngx.thread.spawn(conn_sock) + + ngx.thread.wait(co1) + ngx.thread.wait(co2) + ngx.say("ok") + } + } +--- request +GET /t +--- response_body +timeout +connected in uthread +ok +--- error_log +queue connect operation for connection pool "test" +lua tcp socket connect timed out, when connecting to + + + +=== TEST 46: conn queuing: resume connect operation if resumed connect failed (could not be resolved) +--- config + resolver 127.0.0.2:12345 ipv6=off; + resolver_timeout 1s; + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + local port = ngx.var.port + local opts = {pool = "test", pool_size = 1, backlog = 1} + + local conn_sock = function(should_timeout) + local sock = ngx.socket.tcp() + local ok, err + if should_timeout then + sock:settimeouts(1, 3000, 3000) + ok, err = sock:connect("agentzh.org", 80, opts) + else + ok, err = sock:connect("127.0.0.1", port, opts) + end + if not ok then + ngx.say(err) + return + end + ngx.say("connected in uthread") + sock:close() + end + + local co1 = ngx.thread.spawn(conn_sock, true) + local co2 = ngx.thread.spawn(conn_sock) + + ngx.thread.wait(co1) + ngx.thread.wait(co2) + ngx.say("ok") + } + } +--- request +GET /t +--- response_body +agentzh.org could not be resolved (110: Operation timed out) +connected in uthread +ok +--- error_log +queue connect operation for connection pool "test" + + + +=== TEST 47: conn queuing: resume connect operation if resumed connect failed (connection refused) +--- config + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + local port = ngx.var.port + local opts = {pool = "test", pool_size = 1, backlog = 1} + + local conn_sock = function(should_timeout) + local sock = ngx.socket.tcp() + local ok, err + if should_timeout then + sock:settimeouts(100, 3000, 3000) + ok, err = sock:connect("127.0.0.1", 62345, opts) + else + ok, err = sock:connect("127.0.0.1", port, opts) + end + if not ok then + ngx.say(err) + return + end + ngx.say("connected in uthread") + sock:close() + end + + local co1 = ngx.thread.spawn(conn_sock, true) + local co2 = ngx.thread.spawn(conn_sock) + + ngx.thread.wait(co1) + ngx.thread.wait(co2) + ngx.say("ok") + } + } +--- request +GET /t +--- response_body +connection refused +connected in uthread +ok +--- error_log +queue connect operation for connection pool "test" + + + +=== TEST 48: conn queuing: resume connect operation if resumed connect failed (uthread aborted while resolving) +--- http_config + lua_package_path '../lua-resty-core/lib/?.lua;../lua-resty-lrucache/lib/?.lua;;'; +--- config + resolver 127.0.0.1 ipv6=off; + resolver_timeout 100s; + set $port $TEST_NGINX_MEMCACHED_PORT; + + location /sub { + content_by_lua_block { + local semaphore = require "ngx.semaphore" + local sem = semaphore.new() + + local function f() + sem:wait(0.1) + ngx.exit(0) + end + + local opts = {pool = "test", pool_size = 1, backlog = 1} + local port = ngx.var.port + ngx.timer.at(0, function() + sem:post() + local sock2, err = ngx.socket.connect("127.0.0.1", port, opts) + package.loaded.for_timer_to_resume:post() + if not sock2 then + ngx.log(ngx.ALERT, "resume connect failed: ", err) + return + end + + ngx.log(ngx.INFO, "resume success") + end) + + ngx.thread.spawn(f) + local sock1, err = ngx.socket.connect("openresty.org", 80, opts) + if not sock1 then + ngx.say(err) + return + end + } + } + + location /t { + content_by_lua_block { + local semaphore = require "ngx.semaphore" + local for_timer_to_resume = semaphore.new() + package.loaded.for_timer_to_resume = for_timer_to_resume + + ngx.location.capture("/sub") + for_timer_to_resume:wait(0.1) + } + } +--- request +GET /t +--- no_error_log +[alert] +--- error_log +resume success + + + +=== TEST 49: conn queuing: resume connect operation if resumed connect failed (uthread killed while resolving) +--- config + resolver 127.0.0.1 ipv6=off; + resolver_timeout 100s; + set $port $TEST_NGINX_MEMCACHED_PORT; + + location /t { + content_by_lua_block { + local opts = {pool = "test", pool_size = 1, backlog = 1} + local port = ngx.var.port + + local function resolve() + local sock1, err = ngx.socket.connect("openresty.org", 80, opts) + if not sock1 then + ngx.say(err) + return + end + end + + local th = ngx.thread.spawn(resolve) + local ok, err = ngx.thread.kill(th) + if not ok then + ngx.log(ngx.ALERT, "kill thread failed: ", err) + return + end + + local sock2, err = ngx.socket.connect("127.0.0.1", port, opts) + if not sock2 then + ngx.log(ngx.ALERT, "resume connect failed: ", err) + return + end + + ngx.log(ngx.INFO, "resume success") + } + } +--- request +GET /t +--- no_error_log +[alert] +--- error_log +resume success + + + +=== TEST 50: conn queuing: increase the counter for connections created before creating the pool with setkeepalive() +--- config + set $port $TEST_NGINX_MEMCACHED_PORT; + + location /t { + content_by_lua_block { + local function connect() + local sock, err = ngx.socket.connect("127.0.0.1", ngx.var.port) + if not sock then + error("connect failed: " .. err) + end + + return sock + end + + local sock1 = connect() + local sock2 = connect() + assert(sock1:setkeepalive()) + assert(sock2:setkeepalive()) + + local sock1 = connect() + local sock2 = connect() + assert(sock1:close()) + assert(sock2:close()) + + ngx.say("ok") + } + } +--- request +GET /t +--- no_error_log +[error] +--- response_body +ok + + + +=== TEST 51: conn queuing: only decrease the counter for connections which were counted by the pool +--- config + set $port $TEST_NGINX_MEMCACHED_PORT; + + location /t { + content_by_lua_block { + local function connect() + local sock, err = ngx.socket.connect("127.0.0.1", ngx.var.port) + if not sock then + error("connect failed: " .. err) + end + + return sock + end + + local sock1 = connect() + local sock2 = connect() + assert(sock1:setkeepalive(1000, 1)) + assert(sock2:setkeepalive(1000, 1)) + + local sock1 = connect() + local sock2 = connect() + assert(sock1:close()) + assert(sock2:close()) + + ngx.say("ok") + } + } +--- request +GET /t +--- no_error_log +[error] +--- response_body +ok + + + +=== TEST 52: conn queuing: clean up pending connect operations which are in queue +--- config + set $port $TEST_NGINX_MEMCACHED_PORT; + + location /sub { + content_by_lua_block { + local opts = {pool = "test", pool_size = 1, backlog = 1} + local sock, err = ngx.socket.connect("127.0.0.1", ngx.var.port, opts) + if not sock then + ngx.say("connect failed: " .. err) + return + end + + local function f() + assert(ngx.socket.connect("127.0.0.1", ngx.var.port, opts)) + end + + local th = ngx.thread.spawn(f) + local ok, err = ngx.thread.kill(th) + if not ok then + ngx.log(ngx.ERR, "kill thread failed: ", err) + return + end + + sock:close() + } + } + + location /t { + content_by_lua_block { + ngx.location.capture("/sub") + -- let pending connect operation resumes first + ngx.sleep(0) + ngx.say("ok") + } + } +--- request +GET /t +--- no_error_log +[error] +--- error_log +lua tcp socket abort queueing +--- response_body +ok diff --git a/debian/modules/http-lua/t/073-backtrace.t b/debian/modules/http-lua/t/073-backtrace.t index 6c54692..663c3af 100644 --- a/debian/modules/http-lua/t/073-backtrace.t +++ b/debian/modules/http-lua/t/073-backtrace.t @@ -21,10 +21,10 @@ __DATA__ --- config location /lua { content_by_lua - ' function bar() + ' local function bar() return lua_concat(3) end - function foo() + local function foo() bar() end foo() @@ -37,7 +37,7 @@ GET /lua attempt to call global 'lua_concat' : in function 'bar' :5: in function 'foo' -:7: in function +:7: in main chunk @@ -45,10 +45,10 @@ attempt to call global 'lua_concat' --- config location /lua { content_by_lua - ' function bar() + ' local function bar() error(nil) end - function foo() + local function foo() bar() end foo() @@ -64,7 +64,7 @@ GET /lua " in function 'error'", ": in function 'bar'", ":5: in function 'foo'", -qr/:7: in function /, +qr/:7: in main chunk/, ] @@ -125,7 +125,7 @@ probe process("$LIBLUA_PATH").function("lua_concat") { :63: in function 'func16' :67: in function 'func17' :71: in function 'func18' -:74: in function +:74: in main chunk diff --git a/debian/modules/http-lua/t/075-logby.t b/debian/modules/http-lua/t/075-logby.t index 520c62e..8eece69 100644 --- a/debian/modules/http-lua/t/075-logby.t +++ b/debian/modules/http-lua/t/075-logby.t @@ -220,7 +220,7 @@ failed to run log_by_lua*: unknown reason -=== TEST 11: globals get cleared for every single request +=== TEST 11: globals sharing --- config location /lua { echo ok; @@ -228,6 +228,7 @@ failed to run log_by_lua*: unknown reason if not foo then foo = 1 else + ngx.log(ngx.INFO, "old foo: ", foo) foo = foo + 1 end ngx.log(ngx.WARN, "foo = ", foo) @@ -237,8 +238,9 @@ failed to run log_by_lua*: unknown reason GET /lua --- response_body ok ---- error_log -foo = 1 +--- grep_error_log eval: qr/old foo: \d+/ +--- grep_error_log_out eval +["", "old foo: 1\n"] @@ -495,7 +497,8 @@ API disabled in the context of log_by_lua* location /t { echo ok; log_by_lua ' - function foo() + local bar + local function foo() bar() end diff --git a/debian/modules/http-lua/t/081-bytecode.t b/debian/modules/http-lua/t/081-bytecode.t index cb50e94..92383bc 100644 --- a/debian/modules/http-lua/t/081-bytecode.t +++ b/debian/modules/http-lua/t/081-bytecode.t @@ -24,7 +24,7 @@ __DATA__ content_by_lua ' ngx.req.read_body(); local b = ngx.req.get_body_data(); - f = io.open(ngx.var.realpath_root.."/test.lua", "w"); + local f = io.open(ngx.var.realpath_root.."/test.lua", "w"); -- luajit bytecode: sub(149,-1), lua bytecode: sub(1,147) if jit then if not string.find(jit.version, "LuaJIT 2.0") then @@ -35,7 +35,8 @@ __DATA__ else f:write(string.sub(b, 1, 147)); end - f:close(); res = ngx.location.capture("/call"); + f:close(); + local res = ngx.location.capture("/call"); ngx.print(res.body) '; } @@ -60,14 +61,15 @@ __DATA__ content_by_lua ' ngx.req.read_body(); local b = ngx.req.get_body_data(); - f = io.open(ngx.var.realpath_root.."/test.lua", "w"); + local f = io.open(ngx.var.realpath_root.."/test.lua", "w"); -- luajit bytecode: sub(149,-1), lua bytecode: sub(1,147) if not package.loaded["jit"] then f:write(string.sub(b, 149)); else f:write(string.sub(b, 1, 147)); end - f:close(); res = ngx.location.capture("/call"); + f:close(); + local res = ngx.location.capture("/call"); if res.status == 200 then ngx.print(res.body) else @@ -85,7 +87,7 @@ __DATA__ --- response_body error --- error_log eval -qr/failed to load external Lua file ".*?test\.lua": bad byte-code header/ +qr/failed to load external Lua file ".*?test\.lua": .* cannot load incompatible bytecode/ @@ -96,14 +98,15 @@ qr/failed to load external Lua file ".*?test\.lua": bad byte-code header/ content_by_lua ' ngx.req.read_body(); local b = ngx.req.get_body_data(); - f = io.open(ngx.var.realpath_root.."/test.lua", "w"); + local f = io.open(ngx.var.realpath_root.."/test.lua", "w"); -- luajit bytecode: sub(149,-1), lua bytecode: sub(1,147) if package.loaded["jit"] then f:write(string.sub(b, 149)); else f:write(string.sub(b, 1, 147)); end - f:close(); res = ngx.location.capture("/call"); + f:close(); + local res = ngx.location.capture("/call"); if res.status == 200 then ngx.print(res.body) else @@ -121,7 +124,7 @@ qr/failed to load external Lua file ".*?test\.lua": bad byte-code header/ --- response_body error --- error_log -bytecode format version unsupported +cannot load incompatible bytecode @@ -132,7 +135,7 @@ bytecode format version unsupported content_by_lua ' ngx.req.read_body(); local b = ngx.req.get_body_data(); - f = io.open(ngx.var.realpath_root.."/test.lua", "w"); + local f = io.open(ngx.var.realpath_root.."/test.lua", "w"); -- luajit bytecode: sub(149,-1), lua bytecode: sub(1,147) local do_jit if jit then @@ -176,7 +179,7 @@ bytecode format version unsupported content_by_lua ' ngx.req.read_body(); local b = ngx.req.get_body_data(); - f = io.open(ngx.var.realpath_root.."/test.lua", "w"); + local f = io.open(ngx.var.realpath_root.."/test.lua", "w"); -- luajit bytecode: sub(149,-1), lua bytecode: sub(1,147) local jit; if package.loaded["jit"] then @@ -220,7 +223,7 @@ error content_by_lua ' ngx.req.read_body(); local b = ngx.req.get_body_data(); - f = io.open(ngx.var.realpath_root.."/test.lua", "w"); + local f = io.open(ngx.var.realpath_root.."/test.lua", "w"); -- luajit bytecode: sub(149,-1), lua bytecode: sub(1,147) if jit then if not string.find(jit.version, "LuaJIT 2.0") then @@ -256,9 +259,9 @@ error content_by_lua ' local bcsave = require "jit.bcsave" if jit then - local prefix = ngx.config.prefix() - local infile = prefix .. "html/a.lua" - local outfile = prefix .. "html/a.luac" + local prefix = "$TEST_NGINX_SERVER_ROOT" + local infile = prefix .. "/html/a.lua" + local outfile = prefix .. "/html/a.luac" bcsave.start("-s", infile, outfile) return ngx.exec("/call") end @@ -289,9 +292,9 @@ ngx.status = 201 ngx.say("hello from Lua!") content_by_lua ' local bcsave = require "jit.bcsave" if jit then - local prefix = ngx.config.prefix() - local infile = prefix .. "html/a.lua" - local outfile = prefix .. "html/a.luac" + local prefix = "$TEST_NGINX_SERVER_ROOT" + local infile = prefix .. "/html/a.lua" + local outfile = prefix .. "/html/a.luac" bcsave.start("-g", infile, outfile) return ngx.exec("/call") end @@ -320,9 +323,9 @@ ngx.status = 201 ngx.say("hello from Lua!") --- config location = /t { content_by_lua_block { - local f = assert(loadstring("a = a and a + 1 or 1 ngx.say('a = ', a)", "=code")) + local f = assert(loadstring("local a = 1 ngx.say('a = ', a)", "=code")) local bc = string.dump(f) - local f = assert(io.open("t/servroot/html/a.luac", "w")) + local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/a.luac", "w")) f:write(bc) f:close() } @@ -349,9 +352,9 @@ a = 1 --- config location = /t { content_by_lua_block { - local f = assert(loadstring("a = a and a + 1 or 1 ngx.say('a = ', a)", "=code")) + local f = assert(loadstring("local a = 1 ngx.say('a = ', a)", "=code")) local bc = string.dump(f, true) - local f = assert(io.open("t/servroot/html/a.luac", "w")) + local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/a.luac", "w")) f:write(bc) f:close() } diff --git a/debian/modules/http-lua/t/082-body-filter.t b/debian/modules/http-lua/t/082-body-filter.t index 98efa84..5f765fa 100644 --- a/debian/modules/http-lua/t/082-body-filter.t +++ b/debian/modules/http-lua/t/082-body-filter.t @@ -460,7 +460,8 @@ GET /t --- config location /t { body_filter_by_lua ' - function foo() + local bar + local function foo() bar() end diff --git a/debian/modules/http-lua/t/084-inclusive-receiveuntil.t b/debian/modules/http-lua/t/084-inclusive-receiveuntil.t index f7d5d3d..66be893 100644 --- a/debian/modules/http-lua/t/084-inclusive-receiveuntil.t +++ b/debian/modules/http-lua/t/084-inclusive-receiveuntil.t @@ -56,7 +56,7 @@ __DATA__ local reader = sock:receiveuntil("abcabd", { inclusive = true }) for i = 1, 3 do - line, err, part = reader() + local line, err, part = reader() if line then ngx.say("read: ", line) @@ -128,7 +128,7 @@ close: 1 nil local reader = sock:receiveuntil("abcabdabcabe", { inclusive = true }) for i = 1, 2 do - line, err, part = reader() + local line, err, part = reader() if line then ngx.say("read: ", line) @@ -200,7 +200,7 @@ close: 1 nil local reader = sock:receiveuntil("abcabd", { inclusive = true }) for i = 1, 3 do - line, err, part = reader() + local line, err, part = reader() if line then ngx.say("read: ", line) @@ -272,7 +272,7 @@ close: 1 nil local reader = sock:receiveuntil("aa", { inclusive = nil }) for i = 1, 2 do - line, err, part = reader() + local line, err, part = reader() if line then ngx.say("read: ", line) @@ -343,7 +343,7 @@ close: 1 nil local reader = sock:receiveuntil("aa", { inclusive = false }) for i = 1, 2 do - line, err, part = reader() + local line, err, part = reader() if line then ngx.say("read: ", line) @@ -414,7 +414,7 @@ close: 1 nil local reader = sock:receiveuntil("aa", { inclusive = true }) for i = 1, 2 do - line, err, part = reader() + local line, err, part = reader() if line then ngx.say("read: ", line) @@ -485,7 +485,7 @@ close: 1 nil local reader = sock:receiveuntil("aa", { inclusive = "true" }) for i = 1, 2 do - line, err, part = reader() + local line, err, part = reader() if line then ngx.say("read: ", line) @@ -552,7 +552,7 @@ bad "inclusive" option value type: string local reader = sock:receiveuntil("aa", { inclusive = "true" }) for i = 1, 2 do - line, err, part = reader() + local line, err, part = reader() if line then ngx.say("read: ", line) @@ -620,7 +620,7 @@ bad "inclusive" option value type: string local reader = sock:receiveuntil("--abc", { inclusive = true }) for i = 1, 7 do - line, err, part = reader(4) + local line, err, part = reader(4) if line then ngx.say("read: ", line) @@ -697,7 +697,7 @@ close: 1 nil local reader = sock:receiveuntil("--abc", { inclusive = true }) for i = 1, 7 do - line, err, part = reader(4) + local line, err, part = reader(4) if line then ngx.say("read: ", line) diff --git a/debian/modules/http-lua/t/087-udp-socket.t b/debian/modules/http-lua/t/087-udp-socket.t index 8bedc32..dc6cad5 100644 --- a/debian/modules/http-lua/t/087-udp-socket.t +++ b/debian/modules/http-lua/t/087-udp-socket.t @@ -555,7 +555,7 @@ lua udp socket read timed out local udp = socket.udp() - udp:settimeout(2000) -- 2 sec + udp:settimeout(5000) -- 5 sec local ok, err = udp:setpeername("$TEST_NGINX_RESOLVER", 53) if not ok then @@ -824,7 +824,7 @@ probe syscall.socket.return, syscall.connect.return { === TEST 15: bad request tries to setpeer --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location = /main { @@ -881,7 +881,7 @@ qr/runtime error: content_by_lua\(nginx\.conf:\d+\):14: bad request/ === TEST 16: bad request tries to send --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location = /main { @@ -938,7 +938,7 @@ qr/runtime error: content_by_lua\(nginx\.conf:\d+\):14: bad request/ === TEST 17: bad request tries to receive --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location = /main { @@ -995,7 +995,7 @@ qr/runtime error: content_by_lua\(nginx\.conf:\d+\):14: bad request/ === TEST 18: bad request tries to close --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location = /main { @@ -1052,7 +1052,7 @@ qr/runtime error: content_by_lua\(nginx\.conf:\d+\):14: bad request/ === TEST 19: bad request tries to receive --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config server_tokens off; location = /main { diff --git a/debian/modules/http-lua/t/090-log-socket-errors.t b/debian/modules/http-lua/t/090-log-socket-errors.t index 16576b6..f5a9f80 100644 --- a/debian/modules/http-lua/t/090-log-socket-errors.t +++ b/debian/modules/http-lua/t/090-log-socket-errors.t @@ -28,7 +28,7 @@ __DATA__ lua_socket_log_errors off; content_by_lua ' local sock = ngx.socket.tcp() - local ok, err = sock:connect("agentzh.org", 12345) + local ok, err = sock:connect("127.0.0.2", 12345) ngx.say(err) '; } @@ -50,7 +50,7 @@ timeout lua_socket_log_errors on; content_by_lua ' local sock = ngx.socket.tcp() - local ok, err = sock:connect("agentzh.org", 12345) + local ok, err = sock:connect("127.0.0.2", 12345) ngx.say(err) '; } @@ -59,7 +59,7 @@ GET /t --- response_body timeout --- error_log -lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 +lua tcp socket connect timed out, when connecting to 127.0.0.2:12345 @@ -72,7 +72,7 @@ lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 lua_socket_read_timeout 1ms; content_by_lua ' local sock = ngx.socket.udp() - local ok, err = sock:setpeername("agentzh.org", 12345) + local ok, err = sock:setpeername("127.0.0.2", 12345) ok, err = sock:receive() ngx.say(err) '; @@ -95,7 +95,7 @@ lua udp socket read timed out lua_socket_read_timeout 1ms; content_by_lua ' local sock = ngx.socket.udp() - local ok, err = sock:setpeername("agentzh.org", 12345) + local ok, err = sock:setpeername("127.0.0.2", 12345) ok, err = sock:receive() ngx.say(err) '; diff --git a/debian/modules/http-lua/t/091-coroutine.t b/debian/modules/http-lua/t/091-coroutine.t index bceb512..7cf60f9 100644 --- a/debian/modules/http-lua/t/091-coroutine.t +++ b/debian/modules/http-lua/t/091-coroutine.t @@ -85,7 +85,7 @@ __DATA__ content_by_lua ' local cc, cr, cy = coroutine.create, coroutine.resume, coroutine.yield - function f() + local function f() local cnt = 0 for i = 1, 20 do ngx.say("Hello, ", cnt) @@ -120,7 +120,7 @@ Hello, 2 --- config location /lua { content_by_lua ' - function f(fid) + local function f(fid) local cnt = 0 while true do ngx.say("cc", fid, ": ", cnt) @@ -163,7 +163,7 @@ cc3: 2 resolver $TEST_NGINX_RESOLVER ipv6=off; location /lua { content_by_lua ' - function worker(url) + local function worker(url) local sock = ngx.socket.tcp() local ok, err = sock:connect(url, 80) coroutine.yield() @@ -178,7 +178,7 @@ cc3: 2 local urls = { "agentzh.org", - "iscribblet.org", + "openresty.com", "openresty.org" } @@ -204,7 +204,7 @@ cc3: 2 GET /lua --- response_body successfully connected to: agentzh.org -successfully connected to: iscribblet.org +successfully connected to: openresty.com successfully connected to: openresty.org *** All Done *** --- no_error_log @@ -218,14 +218,14 @@ successfully connected to: openresty.org location /lua { content_by_lua ' -- generate all the numbers from 2 to n - function gen (n) + local function gen (n) return coroutine.wrap(function () for i=2,n do coroutine.yield(i) end end) end -- filter the numbers generated by g, removing multiples of p - function filter (p, g) + local function filter (p, g) return coroutine.wrap(function () while 1 do local n = g() @@ -235,8 +235,8 @@ successfully connected to: openresty.org end) end - N = 10 - x = gen(N) -- generate primes up to N + local N = 10 + local x = gen(N) -- generate primes up to N while 1 do local n = x() -- pick a number until done if n == nil then break end @@ -264,14 +264,14 @@ GET /lua coroutine.create = nil coroutine.resume = nil -- generate all the numbers from 2 to n - function gen (n) + local function gen (n) return coroutine.wrap(function () for i=2,n do coroutine.yield(i) end end) end -- filter the numbers generated by g, removing multiples of p - function filter (p, g) + local function filter (p, g) return coroutine.wrap(function () while 1 do local n = g() @@ -281,8 +281,8 @@ GET /lua end) end - N = 10 - x = gen(N) -- generate primes up to N + local N = 10 + local x = gen(N) -- generate primes up to N while 1 do local n = x() -- pick a number until done if n == nil then break end @@ -307,7 +307,7 @@ GET /lua --- config location /lua { content_by_lua ' - function generatefib (n) + local function generatefib (n) return coroutine.wrap(function () local a,b = 1, 1 while a <= n do @@ -362,7 +362,7 @@ GET /lua resolver $TEST_NGINX_RESOLVER ipv6=off; location /lua { content_by_lua ' - function worker(url) + local function worker(url) local sock = ngx.socket.tcp() local ok, err = sock:connect(url, 80) coroutine.yield() @@ -377,7 +377,7 @@ GET /lua local urls = { "agentzh.org", - "iscribblet.org", + "openresty.com", "openresty.org" } @@ -398,7 +398,7 @@ GET /lua GET /lua --- response_body successfully connected to: agentzh.org -successfully connected to: iscribblet.org +successfully connected to: openresty.com successfully connected to: openresty.org *** All Done *** --- no_error_log @@ -414,7 +414,7 @@ successfully connected to: openresty.org local cc, cr, cy = coroutine.create, coroutine.resume, coroutine.yield local st, rn = coroutine.status, coroutine.running - function f(self) + local function f(self) local cnt = 0 if rn() ~= self then ngx.say("error"); return end ngx.say("running: ", st(self)) --running @@ -509,7 +509,7 @@ GET /lua --- config location /lua { content_by_lua ' - function print(...) + local function print(...) local args = {...} local is_first = true for i,v in ipairs(args) do @@ -523,12 +523,12 @@ GET /lua ngx.print("\\\n") end - function foo (a) + local function foo (a) print("foo", a) return coroutine.yield(2*a) end - co = coroutine.create(function (a,b) + local co = coroutine.create(function (a,b) print("co-body", a, b) local r = foo(a+1) print("co-body", r) @@ -566,7 +566,8 @@ main false cannot resume dead coroutine local create = coroutine.create local resume = coroutine.resume local yield = coroutine.yield - function f() + local g + local function f() ngx.say("f begin") yield() local c2 = create(g) @@ -627,8 +628,9 @@ main done local yield = coroutine.yield local code = 400 + local g - function f() + local function f() local c2 = create(g) yield() code = code + 1 @@ -683,8 +685,9 @@ exit local yield = coroutine.yield local code = 0 + local g - function f() + local function f() local c2 = create(g) yield() code = code + 1 @@ -740,7 +743,7 @@ num: 3 location /lua { echo hello; header_filter_by_lua ' - function f() + local function f() yield() end @@ -764,13 +767,13 @@ API disabled in the context of header_filter_by_lua* local c1, c2 - function f() + local function f() print("f 1") print(coroutine.resume(c2)) print("f 2") end - function g() + local function g() print("g 1") -- print(coroutine.resume(c1)) print("g 2") @@ -803,13 +806,13 @@ f 2 local c1, c2 - function f() + local function f() print("f 1") print(coroutine.resume(c2)) print("f 2") end - function g() + local function g() print("g 1") print(coroutine.resume(c1)) print("g 2") @@ -859,7 +862,7 @@ falsecannot resume running coroutine location /t { content_by_lua ' local co - function f() + local function f() ngx.say("f: ", coroutine.status(co)) ngx.say("f: ", coroutine.resume(co)) end @@ -885,7 +888,7 @@ chunk: true location /t { content_by_lua ' local co - function f() + local function f() error("bad") end co = coroutine.create(f) @@ -990,7 +993,7 @@ test10 resolver $TEST_NGINX_RESOLVER ipv6=off; location /lua { content_by_lua ' - function worker(url) + local function worker(url) local sock = ngx.socket.tcp() local ok, err = sock:connect(url, 80) coroutine.yield() @@ -1044,7 +1047,7 @@ successfully connected to: agentzh.org resolver $TEST_NGINX_RESOLVER ipv6=off; location /lua { content_by_lua ' - function worker(url) + local function worker(url) local sock = ngx.socket.tcp() local ok, err = sock:connect(url, 80) coroutine.yield() @@ -1104,7 +1107,7 @@ successfully connected to: agentzh.org --- config location /cotest { content_by_lua ' - function generator() + local function generator() return co_wrap(function() co_yield("data") end) @@ -1133,7 +1136,7 @@ data --- config location /cotest { content_by_lua ' - function generator() + local function generator() return co_wrap(function() co_yield("data") end) @@ -1166,7 +1169,7 @@ data content_by_lua ' local cc, cr, cy = coroutine.create, coroutine.resume, coroutine.yield - function f() + local function f() return 3 end @@ -1199,7 +1202,7 @@ ok local coroutine = require "coroutine" local cc, cr, cy = coroutine.create, coroutine.resume, coroutine.yield - function f() + local function f() local cnt = 0 for i = 1, 20 do ngx.say("Hello, ", cnt) @@ -1238,7 +1241,7 @@ Hello, 2 header_filter_by_lua ' local cc, cr, cy = coroutine.create, coroutine.resume, coroutine.yield - function f() + local function f() local cnt = 0 for i = 1, 20 do print("co yield: ", cnt) @@ -1278,7 +1281,7 @@ co yield: 2 body_filter_by_lua ' local cc, cr, cy = coroutine.create, coroutine.resume, coroutine.yield - function f() + local function f() local cnt = 0 for i = 1, 20 do print("co yield: ", cnt) diff --git a/debian/modules/http-lua/t/093-uthread-spawn.t b/debian/modules/http-lua/t/093-uthread-spawn.t index b622d30..ab6db2f 100644 --- a/debian/modules/http-lua/t/093-uthread-spawn.t +++ b/debian/modules/http-lua/t/093-uthread-spawn.t @@ -24,7 +24,7 @@ __DATA__ --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("hello in thread") end @@ -58,11 +58,11 @@ after --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("in thread 1") end - function g() + local function g() ngx.say("in thread 2") end @@ -107,7 +107,7 @@ after 2 --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("before sleep") ngx.sleep(0.1) ngx.say("after sleep") @@ -144,13 +144,13 @@ after sleep --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("1: before sleep") ngx.sleep(0.2) ngx.say("1: after sleep") end - function g() + local function g() ngx.say("2: before sleep") ngx.sleep(0.1) ngx.say("2: after sleep") @@ -200,7 +200,7 @@ delete thread 2 --- config location /lua { content_by_lua ' - function f() + local function f() ngx.blah() end @@ -231,9 +231,9 @@ qr/lua user thread aborted: runtime error: content_by_lua\(nginx\.conf:\d+\):3: --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("before capture") - res = ngx.location.capture("/proxy") + local res = ngx.location.capture("/proxy") ngx.say("after capture: ", res.body) end @@ -277,7 +277,7 @@ after capture: hello world --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("before capture") local res = ngx.location.capture("/proxy?foo") ngx.say("after capture: ", res.body) @@ -330,7 +330,7 @@ after capture: hello foo --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("before capture") local res = ngx.location.capture("/proxy?foo") ngx.say("after capture: ", res.body) @@ -384,13 +384,13 @@ capture: hello bar --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("f: before capture") local res = ngx.location.capture("/proxy?foo") ngx.say("f: after capture: ", res.body) end - function g() + local function g() ngx.say("g: before capture") local res = ngx.location.capture("/proxy?bah") ngx.say("g: after capture: ", res.body) @@ -462,7 +462,8 @@ g: after capture: hello bah --- config location /lua { content_by_lua ' - function f() + local g + local function f() ngx.say("before g") ngx.thread.spawn(g) ngx.say("after g") @@ -508,7 +509,8 @@ after g --- config location /lua { content_by_lua ' - function f() + local g + local function f() ngx.say("before g") ngx.thread.spawn(g) ngx.say("after g") @@ -556,7 +558,7 @@ hello in g() location /lua { content_by_lua ' local co - function f() + local function f() co = coroutine.running() ngx.sleep(0.1) end @@ -589,7 +591,7 @@ status: running location /lua { content_by_lua ' local co - function f() + local function f() co = coroutine.running() end @@ -621,7 +623,8 @@ status: zombie location /lua { content_by_lua ' local co - function f() + local g + local function f() co = coroutine.running() local co2 = coroutine.create(g) coroutine.resume(co2) @@ -660,7 +663,8 @@ status: normal --- config location /lua { content_by_lua ' - function f() + local g + local function f() ngx.say("before g") ngx.thread.spawn(g) ngx.say("after g") @@ -707,7 +711,7 @@ after f content_by_lua ' local yield = coroutine.yield - function f() + local function f() local self = coroutine.running() ngx.say("f 1") yield(self) @@ -760,7 +764,7 @@ f 3 content_by_lua ' local yield = coroutine.yield - function f() + local function f() local self = coroutine.running() ngx.say("f 1") yield(self) @@ -769,7 +773,7 @@ f 3 ngx.say("f 3") end - function g() + local function g() local self = coroutine.running() ngx.say("g 1") yield(self) @@ -816,7 +820,7 @@ g 3 --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("hello in thread") coroutine.yield(coroutine.running) ngx.flush(true) @@ -853,12 +857,12 @@ after --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("hello from f") ngx.flush(true) end - function g() + local function g() ngx.say("hello from g") ngx.flush(true) end @@ -904,7 +908,7 @@ hello from g --- config location /lua { content_by_lua ' - function f() + local function f() local sock = ngx.socket.tcp() local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_MEMCACHED_PORT) if not ok then @@ -956,7 +960,7 @@ received: OK --- config location /lua { content_by_lua ' - function f() + local function f() local sock = ngx.socket.udp() local ok, err = sock:setpeername("127.0.0.1", 12345) local bytes, err = sock:send("blah") @@ -1018,7 +1022,7 @@ after)$ --- config location /lua { content_by_lua ' - function f() + local function f() ngx.req.read_body() local body = ngx.req.get_body_data() ngx.say("body: ", body) @@ -1063,7 +1067,7 @@ body: hello world)$ --- config location /lua { content_by_lua ' - function f() + local function f() local sock = ngx.req.socket() local body, err = sock:receive(11) if not body then @@ -1113,7 +1117,7 @@ body: hello world)$ --- config location /lua { content_by_lua ' - function f(a, b) + local function f(a, b) ngx.say("hello ", a, " and ", b) end @@ -1647,7 +1651,7 @@ ok --- config location /lua { content_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.say("f") end diff --git a/debian/modules/http-lua/t/094-uthread-exit.t b/debian/modules/http-lua/t/094-uthread-exit.t index 2f7d9ba..58d8d0b 100644 --- a/debian/modules/http-lua/t/094-uthread-exit.t +++ b/debian/modules/http-lua/t/094-uthread-exit.t @@ -24,7 +24,7 @@ __DATA__ --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.exit(0) end @@ -87,7 +87,7 @@ hello in thread --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -171,13 +171,13 @@ after --- config location /lua { content_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.say("f") ngx.exit(0) end - function g() + local function g() ngx.sleep(1) ngx.say("g") end @@ -261,7 +261,7 @@ f --- config location /lua { content_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.say("exiting the user thread") ngx.exit(0) @@ -297,10 +297,10 @@ exiting the user thread === TEST 5: exit in user thread (entry thread is still pending on the DNS resolver for ngx.socket.tcp) --- config location /lua { - resolver agentzh.org; + resolver 127.0.0.2:12345; resolver_timeout 12s; content_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.001) ngx.exit(0) @@ -393,10 +393,10 @@ after === TEST 6: exit in user thread (entry thread is still pending on the DNS resolver for ngx.socket.udp) --- config location /lua { - resolver agentzh.org; + resolver 127.0.0.2:12345; resolver_timeout 12s; content_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.001) ngx.exit(0) @@ -490,7 +490,7 @@ after --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -501,7 +501,7 @@ after ngx.say("after") local sock = ngx.socket.tcp() sock:settimeout(12000) - local ok, err = sock:connect("172.105.207.225", 12345) + local ok, err = sock:connect("127.0.0.2", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -580,7 +580,7 @@ after --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -680,7 +680,7 @@ after --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -786,7 +786,7 @@ after --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -881,7 +881,7 @@ after --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -974,7 +974,7 @@ after location /lua { client_body_timeout 12000ms; content_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -1059,7 +1059,7 @@ after location /lua { client_body_timeout 12000ms; content_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -1142,7 +1142,7 @@ attempt to abort with pending subrequests location /lua { client_body_timeout 12000ms; content_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.exit(0) end @@ -1225,7 +1225,7 @@ attempt to abort with pending subrequests location /lua { client_body_timeout 12000ms; content_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.exit(0) end @@ -1315,7 +1315,7 @@ attempt to abort with pending subrequests location /lua { client_body_timeout 12000ms; content_by_lua ' - function f() + local function f() ngx.location.capture_multi{ {"/echo"}, {"/sleep"} @@ -1407,7 +1407,7 @@ attempt to abort with pending subrequests location /lua { client_body_timeout 12000ms; content_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(444) @@ -1490,7 +1490,7 @@ free request location /lua { client_body_timeout 12000ms; content_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(408) @@ -1573,7 +1573,7 @@ free request location /lua { client_body_timeout 12000ms; content_by_lua ' - function f() + local function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(499) diff --git a/debian/modules/http-lua/t/095-uthread-exec.t b/debian/modules/http-lua/t/095-uthread-exec.t index 56156c4..7bf37c0 100644 --- a/debian/modules/http-lua/t/095-uthread-exec.t +++ b/debian/modules/http-lua/t/095-uthread-exec.t @@ -23,7 +23,7 @@ __DATA__ --- config location /lua { content_by_lua ' - function f() + local function f() ngx.exec("/foo") end @@ -58,7 +58,7 @@ i am foo --- config location /lua { content_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.exec("/foo") end @@ -93,7 +93,7 @@ i am foo --- config location /lua { content_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.exec("/foo") end @@ -175,12 +175,12 @@ hello foo --- config location /lua { content_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.exec("/foo") end - function g() + local function g() ngx.sleep(1) end @@ -267,7 +267,7 @@ hello foo location /lua { client_body_timeout 12000ms; content_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.exec("/foo") end @@ -348,7 +348,7 @@ attempt to abort with pending subrequests location /lua { client_body_timeout 12000ms; content_by_lua ' - function f() + local function f() ngx.location.capture("/sleep") ngx.say("end") end diff --git a/debian/modules/http-lua/t/096-uthread-redirect.t b/debian/modules/http-lua/t/096-uthread-redirect.t index 003c642..95bff01 100644 --- a/debian/modules/http-lua/t/096-uthread-redirect.t +++ b/debian/modules/http-lua/t/096-uthread-redirect.t @@ -25,7 +25,7 @@ __DATA__ location /lua { client_body_timeout 12000ms; content_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.redirect(301) end @@ -114,7 +114,7 @@ attempt to abort with pending subrequests --- config location /lua { content_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.redirect(301) end @@ -194,7 +194,7 @@ free request location /lua { client_body_timeout 12000ms; content_by_lua ' - function f() + local function f() ngx.location.capture_multi{ {"/echo"}, {"/sleep"} diff --git a/debian/modules/http-lua/t/097-uthread-rewrite.t b/debian/modules/http-lua/t/097-uthread-rewrite.t index 2f0c06f..998e256 100644 --- a/debian/modules/http-lua/t/097-uthread-rewrite.t +++ b/debian/modules/http-lua/t/097-uthread-rewrite.t @@ -23,7 +23,7 @@ __DATA__ --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.req.set_uri("/foo", true) end @@ -58,7 +58,7 @@ i am foo --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.req.set_uri("/foo", true) end @@ -93,7 +93,7 @@ i am foo --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.req.set_uri("/foo", true) end @@ -175,12 +175,12 @@ hello foo --- config location /lua { rewrite_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.req.set_uri("/foo", true) end - function g() + local function g() ngx.sleep(1) end @@ -267,7 +267,7 @@ hello foo location /lua { client_body_timeout 12000ms; rewrite_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.req.set_uri("/foo", true) end diff --git a/debian/modules/http-lua/t/098-uthread-wait.t b/debian/modules/http-lua/t/098-uthread-wait.t index 4948596..c2819ae 100644 --- a/debian/modules/http-lua/t/098-uthread-wait.t +++ b/debian/modules/http-lua/t/098-uthread-wait.t @@ -23,7 +23,7 @@ __DATA__ --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("hello in thread") return "done" end @@ -72,7 +72,7 @@ done --- config location /lua { content_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.say("hello in thread") return "done" @@ -120,13 +120,13 @@ done --- config location /lua { content_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.say("f: hello") return "done" end - function g() + local function g() ngx.sleep(0.2) ngx.say("g: hello") return "done" @@ -200,13 +200,13 @@ f: done --- config location /lua { content_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.say("f: hello") return "done" end - function g() + local function g() ngx.sleep(0.2) ngx.say("g: hello") return "done" @@ -228,7 +228,7 @@ f: done ngx.say("g thread created: ", coroutine.status(tg)) - ok, res = ngx.thread.wait(tf) + local ok, res = ngx.thread.wait(tf) if not ok then ngx.say("failed to wait f: ", res) return @@ -281,7 +281,7 @@ g: done --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("hello in thread") return "done", 3.14 end @@ -330,7 +330,7 @@ res: done 3.14 --- config location /lua { content_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.say("hello in thread") return "done", 3.14 @@ -378,7 +378,7 @@ res: done 3.14 --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("hello in thread") error("bad bad!") end @@ -427,7 +427,7 @@ qr/lua user thread aborted: runtime error: content_by_lua\(nginx\.conf:\d+\):4: --- config location /lua { content_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.say("hello in thread") error("bad bad!") @@ -477,12 +477,12 @@ qr/lua user thread aborted: runtime error: content_by_lua\(nginx\.conf:\d+\):5: --- config location /lua { content_by_lua ' - function g() + local function g() ngx.say("hello in thread") return "done" end - function f() + local function f() local t, err = ngx.thread.spawn(g) if not t then ngx.say("failed to spawn thread: ", err) @@ -533,13 +533,13 @@ done --- config location /lua { content_by_lua ' - function g() + local function g() ngx.sleep(0.1) ngx.say("hello in thread") return "done" end - function f() + local function f() local t, err = ngx.thread.spawn(g) if not t then ngx.say("failed to spawn thread: ", err) @@ -593,12 +593,12 @@ done -- local out = function (...) ngx.log(ngx.ERR, ...) end local out = ngx.say - function f() + local function f() out("f: hello") return "f done" end - function g() + local function g() out("g: hello") return "g done" end @@ -668,13 +668,13 @@ g status: zombie -- local out = function (...) ngx.log(ngx.ERR, ...) end local out = ngx.say - function f() + local function f() ngx.sleep(0.1) out("f: hello") return "f done" end - function g() + local function g() ngx.sleep(0.2) out("g: hello") return "g done" @@ -745,13 +745,13 @@ g: hello -- local out = function (...) ngx.log(ngx.ERR, ...) end local out = ngx.say - function f() + local function f() ngx.sleep(0.2) out("f: hello") return "f done" end - function g() + local function g() ngx.sleep(0.1) out("g: hello") return "g done" @@ -822,12 +822,12 @@ f: hello -- local out = function (...) ngx.log(ngx.ERR, ...) end local out = ngx.say - function f() + local function f() out("f: hello") error("f done") end - function g() + local function g() out("g: hello") error("g done") end @@ -896,13 +896,13 @@ qr/lua user thread aborted: runtime error: content_by_lua\(nginx\.conf:\d+\):7: -- local out = function (...) ngx.log(ngx.ERR, ...) end local out = ngx.say - function f() + local function f() ngx.sleep(0.1) out("f: hello") error("f done") end - function g() + local function g() ngx.sleep(0.2) out("g: hello") error("g done") @@ -969,13 +969,13 @@ qr/lua user thread aborted: runtime error: content_by_lua\(nginx\.conf:\d+\):8: --- config location /lua { content_by_lua ' - function f() + local function f() ngx.sleep(0.1) ngx.say("f: hello") return "done" end - function g() + local function g() ngx.sleep(0.2) ngx.say("g: hello") return "done" @@ -997,7 +997,7 @@ qr/lua user thread aborted: runtime error: content_by_lua\(nginx\.conf:\d+\):8: ngx.say("g thread created: ", coroutine.status(tg)) - ok, res = ngx.thread.wait(tf, tg) + local ok, res = ngx.thread.wait(tf, tg) if not ok then ngx.say("failed to wait: ", res) return @@ -1038,13 +1038,13 @@ res: done --- config location /lua { content_by_lua ' - function f() + local function f() ngx.sleep(0.2) ngx.say("f: hello") return "f done" end - function g() + local function g() ngx.sleep(0.1) ngx.say("g: hello") return "g done" @@ -1066,7 +1066,7 @@ res: done ngx.say("g thread created: ", coroutine.status(tg)) - ok, res = ngx.thread.wait(tf, tg) + local ok, res = ngx.thread.wait(tf, tg) if not ok then ngx.say("failed to wait: ", res) return @@ -1109,12 +1109,12 @@ res: g done content_by_lua ' local t - function f() + local function f() ngx.sleep(0.1) return "done" end - function g() + local function g() t = ngx.thread.spawn(f) end @@ -1154,7 +1154,7 @@ only the parent coroutine can wait on the thread --- config location /lua { content_by_lua ' - function f() + local function f() ngx.sleep(0.1) coroutine.yield() return "done" @@ -1192,7 +1192,7 @@ qr/lua entry thread aborted: runtime error: content_by_lua\(nginx\.conf:\d+\):11 --- config location /lua { content_by_lua ' - function f() + local function f() ngx.sleep(0.1) collectgarbage() error("f done") @@ -1228,7 +1228,7 @@ qr/lua user thread aborted: runtime error: content_by_lua\(nginx\.conf:\d+\):5: --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("hello in thread") return "done" end @@ -1283,7 +1283,7 @@ failed to run thread: already waited or killed --- config location /lua { content_by_lua ' - function f() + local function f() -- ngx.say("hello in thread") return "done" end diff --git a/debian/modules/http-lua/t/099-c-api.t b/debian/modules/http-lua/t/099-c-api.t index a0b375c..5033462 100644 --- a/debian/modules/http-lua/t/099-c-api.t +++ b/debian/modules/http-lua/t/099-c-api.t @@ -86,7 +86,7 @@ dogs zone: defined local buf = ffi.new("char[?]", 4) ffi.copy(buf, "dogs", 4) - zone = ffi.C.ngx_http_lua_find_zone(buf, 4) + local zone = ffi.C.ngx_http_lua_find_zone(buf, 4) local val = ffi.new("ngx_http_lua_value_t[?]", 1) @@ -149,7 +149,7 @@ bar: rc=0, type=3, val=3.14159 local buf = ffi.new("char[?]", 4) ffi.copy(buf, "dogs", 4) - zone = ffi.C.ngx_http_lua_find_zone(buf, 4) + local zone = ffi.C.ngx_http_lua_find_zone(buf, 4) local val = ffi.new("ngx_http_lua_value_t[?]", 1) @@ -212,7 +212,7 @@ bar: rc=0, type=1, val=0 local buf = ffi.new("char[?]", 4) ffi.copy(buf, "dogs", 4) - zone = ffi.C.ngx_http_lua_find_zone(buf, 4) + local zone = ffi.C.ngx_http_lua_find_zone(buf, 4) local val = ffi.new("ngx_http_lua_value_t[?]", 1) @@ -272,7 +272,7 @@ bar: rc=-5 local buf = ffi.new("char[?]", 4) ffi.copy(buf, "dogs", 4) - zone = ffi.C.ngx_http_lua_find_zone(buf, 4) + local zone = ffi.C.ngx_http_lua_find_zone(buf, 4) local s = ffi.new("char[?]", 20) @@ -344,7 +344,7 @@ bar: rc=0, type=4, val=, len=0 local buf = ffi.new("char[?]", 4) ffi.copy(buf, "dogs", 4) - zone = ffi.C.ngx_http_lua_find_zone(buf, 4) + local zone = ffi.C.ngx_http_lua_find_zone(buf, 4) local val = ffi.new("ngx_http_lua_value_t[?]", 1) diff --git a/debian/modules/http-lua/t/100-client-abort.t b/debian/modules/http-lua/t/100-client-abort.t index 89c1f6a..f571387 100644 --- a/debian/modules/http-lua/t/100-client-abort.t +++ b/debian/modules/http-lua/t/100-client-abort.t @@ -195,7 +195,7 @@ bad things happen location = /sub { proxy_ignore_client_abort on; - proxy_pass http://agentzh.org:12345/; + proxy_pass http://127.0.0.2:12345/; } location = /sleep { @@ -236,7 +236,7 @@ client prematurely closed connection location = /sub { proxy_ignore_client_abort off; - proxy_pass http://agentzh.org:12345/; + proxy_pass http://127.0.0.2:12345/; } --- request GET /t @@ -540,7 +540,7 @@ client prematurely closed connection return end - ok, err = sock:connect("127.0.0.1", $TEST_NGINX_REDIS_PORT) + local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_REDIS_PORT) if not ok then ngx.log(ngx.ERR, "failed to connect: ", err) return diff --git a/debian/modules/http-lua/t/106-timer.t b/debian/modules/http-lua/t/106-timer.t index 3e4741e..7b7c85e 100644 --- a/debian/modules/http-lua/t/106-timer.t +++ b/debian/modules/http-lua/t/106-timer.t @@ -76,7 +76,7 @@ qr/\[lua\] content_by_lua\(nginx\.conf:\d+\):\d+: elapsed: 0\.0(?:4[4-9]|5[0-6]) -=== TEST 2: separated global env +=== TEST 2: globals are shared --- config location /t { content_by_lua ' @@ -104,7 +104,7 @@ F(ngx_http_lua_timer_handler) { --- response_body registered timer -foo = nil +foo = 3 --- wait: 0.1 --- no_error_log @@ -320,7 +320,7 @@ qr/received: Server: \S+/, === TEST 6: tcp cosocket in timer handler (keep-alive connections) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /t { @@ -596,7 +596,7 @@ qr/\[lua\] log_by_lua\(nginx\.conf:\d+\):\d+: elapsed: 0\.0(?:6[4-9]|7[0-6])/, === TEST 10: tcp cosocket in timer handler (keep-alive connections) - log_by_lua --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /t { @@ -693,7 +693,7 @@ qr/go\(\): connected: 1, reused: \d+/, === TEST 11: tcp cosocket in timer handler (keep-alive connections) - header_filter_by_lua --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /t { @@ -799,7 +799,7 @@ qr/go\(\): connected: 1, reused: \d+/, === TEST 12: tcp cosocket in timer handler (keep-alive connections) - body_filter_by_lua --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /t { @@ -912,7 +912,7 @@ qr/go\(\): connected: 1, reused: \d+/, === TEST 13: tcp cosocket in timer handler (keep-alive connections) - set_by_lua --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /t { @@ -1023,7 +1023,7 @@ qr/go\(\): connected: 1, reused: \d+/, content_by_lua ' local cc, cr, cy = coroutine.create, coroutine.resume, coroutine.yield local function f() - function f() + local function f() local cnt = 0 for i = 1, 20 do print("cnt = ", cnt) @@ -1090,7 +1090,7 @@ registered timer ngx.log(ngx.ERR, ...) end local function handle() - function f() + local function f() print("hello in thread") return "done" end diff --git a/debian/modules/http-lua/t/108-timer-safe.t b/debian/modules/http-lua/t/108-timer-safe.t index 2795998..758d01a 100644 --- a/debian/modules/http-lua/t/108-timer-safe.t +++ b/debian/modules/http-lua/t/108-timer-safe.t @@ -229,7 +229,7 @@ qr/received: Server: \S+/, === TEST 4: tcp cosocket in timer handler (keep-alive connections) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /t { @@ -489,7 +489,7 @@ delete thread 2 --- response_body hello world ---- wait: 0.1 +--- wait: 0.15 --- no_error_log [error] [alert] @@ -499,7 +499,7 @@ hello world [ "registered timer", qr/\[lua\] .*? my lua timer handler/, -qr/\[lua\] log_by_lua\(nginx\.conf:\d+\):\d+: elapsed: 0\.0(?:6[4-9]|7[0-6])/, +qr/\[lua\] log_by_lua\(nginx\.conf:\d+\):\d+: elapsed: 0\.0(?:6[4-9]|7[0-9]|8[0-6])/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -508,7 +508,7 @@ qr/\[lua\] log_by_lua\(nginx\.conf:\d+\):\d+: elapsed: 0\.0(?:6[4-9]|7[0-6])/, === TEST 8: tcp cosocket in timer handler (keep-alive connections) - log_by_lua --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /t { @@ -606,7 +606,7 @@ qr/go\(\): connected: 1, reused: \d+/, === TEST 9: tcp cosocket in timer handler (keep-alive connections) - header_filter_by_lua --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /t { @@ -713,7 +713,7 @@ qr/go\(\): connected: 1, reused: \d+/, === TEST 10: tcp cosocket in timer handler (keep-alive connections) - body_filter_by_lua --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /t { @@ -827,7 +827,7 @@ qr/go\(\): connected: 1, reused: \d+/, === TEST 11: tcp cosocket in timer handler (keep-alive connections) - set_by_lua --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" --- config location = /t { @@ -1007,7 +1007,7 @@ registered timer ngx.log(ngx.ERR, ...) end local function handle() - function f() + local function f() print("hello in thread") return "done" end diff --git a/debian/modules/http-lua/t/109-timer-hup.t b/debian/modules/http-lua/t/109-timer-hup.t index 0864046..2c197c2 100644 --- a/debian/modules/http-lua/t/109-timer-hup.t +++ b/debian/modules/http-lua/t/109-timer-hup.t @@ -46,7 +46,7 @@ __DATA__ --- config location /t { content_by_lua ' - local f, err = io.open("t/servroot/logs/nginx.pid", "r") + local f, err = io.open("$TEST_NGINX_SERVER_ROOT/logs/nginx.pid", "r") if not f then ngx.say("failed to open nginx.pid: ", err) return @@ -99,7 +99,7 @@ timer prematurely expired: true --- config location /t { content_by_lua ' - local f, err = io.open("t/servroot/logs/nginx.pid", "r") + local f, err = io.open("$TEST_NGINX_SERVER_ROOT/logs/nginx.pid", "r") if not f then ngx.say("failed to open nginx.pid: ", err) return @@ -163,7 +163,7 @@ timer prematurely expired: true --- config location /t { content_by_lua ' - local f, err = io.open("t/servroot/logs/nginx.pid", "r") + local f, err = io.open("$TEST_NGINX_SERVER_ROOT/logs/nginx.pid", "r") if not f then ngx.say("failed to open nginx.pid: ", err) return @@ -219,7 +219,7 @@ failed to register a new timer after reload: process exiting, context: ngx.timer --- config location /t { content_by_lua ' - local f, err = io.open("t/servroot/logs/nginx.pid", "r") + local f, err = io.open("$TEST_NGINX_SERVER_ROOT/logs/nginx.pid", "r") if not f then ngx.say("failed to open nginx.pid: ", err) return @@ -284,7 +284,7 @@ g: exiting=true --- config location /t { content_by_lua ' - local f, err = io.open("t/servroot/logs/nginx.pid", "r") + local f, err = io.open("$TEST_NGINX_SERVER_ROOT/logs/nginx.pid", "r") if not f then ngx.say("failed to open nginx.pid: ", err) return @@ -363,7 +363,7 @@ lua found 100 pending timers local line, err = sock:receive("*l") until not line or string.find(line, "^%s*$") - function foo() + local function foo() repeat -- Get and read chunk local line, err = sock:receive("*l") @@ -379,7 +379,7 @@ lua found 100 pending timers until len == 0 end - co = coroutine.create(foo) + local co = coroutine.create(foo) repeat local chunk = select(2,coroutine.resume(co)) until chunk == nil @@ -399,7 +399,7 @@ lua found 100 pending timers end local ok, err = ngx.timer.at(1, background_thread) - local f, err = io.open("t/servroot/logs/nginx.pid", "r") + local f, err = io.open("$TEST_NGINX_SERVER_ROOT/logs/nginx.pid", "r") if not f then ngx.say("failed to open nginx.pid: ", err) return @@ -453,7 +453,7 @@ lua found 1 pending timers end if kill then - local f, err = io.open("t/servroot/logs/nginx.pid", "r") + local f, err = io.open("$TEST_NGINX_SERVER_ROOT/logs/nginx.pid", "r") if not f then ngx.log(ngx.ERR, "failed to open nginx.pid: ", err) return diff --git a/debian/modules/http-lua/t/120-re-find.t b/debian/modules/http-lua/t/120-re-find.t index 73e6134..f80ca4f 100644 --- a/debian/modules/http-lua/t/120-re-find.t +++ b/debian/modules/http-lua/t/120-re-find.t @@ -622,7 +622,7 @@ matched: 你 >>> a.lua local re = [==[(?i:([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:=|<=>|r?like|sounds\s+like|regexp)([\s'\"`´’‘\(\)]*)?\2|([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp)([\s'\"`´’‘\(\)]*)?(?!\6)([\d\w]+))]==] -s = string.rep([[ABCDEFG]], 10) +local s = string.rep([[ABCDEFG]], 10) local start = ngx.now() @@ -664,7 +664,7 @@ error: pcre_exec() failed: -8 >>> a.lua local re = [==[(?i:([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:=|<=>|r?like|sounds\s+like|regexp)([\s'\"`´’‘\(\)]*)?\2|([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp)([\s'\"`´’‘\(\)]*)?(?!\6)([\d\w]+))]==] -s = string.rep([[ABCDEFG]], 10) +local s = string.rep([[ABCDEFG]], 10) local start = ngx.now() diff --git a/debian/modules/http-lua/t/123-lua-path.t b/debian/modules/http-lua/t/123-lua-path.t index 23681a9..e30132f 100644 --- a/debian/modules/http-lua/t/123-lua-path.t +++ b/debian/modules/http-lua/t/123-lua-path.t @@ -11,7 +11,7 @@ repeat_each(2); plan tests => repeat_each() * (blocks() * 3 + 1); -$ENV{LUA_PATH} = "/foo/bar/baz"; +$ENV{LUA_PATH} = "../lua-resty-core/lib/?.lua;../lua-resty-lrucache/lib/?.lua;/foo/bar/baz"; $ENV{LUA_CPATH} = "/baz/bar/foo"; #no_diff(); #no_long_string(); @@ -36,8 +36,8 @@ env LUA_CPATH; } --- request GET /lua ---- response_body -/foo/bar/baz +--- response_body_like +(?:\.\.\/lua-resty-core\/lib\/\?\.lua;\.\.\/lua-resty-lrucache\/lib\/\?\.lua;){1,2}\/foo\/bar\/baz /baz/bar/foo --- no_error_log @@ -60,8 +60,8 @@ env LUA_CPATH; } --- request GET /lua ---- response_body -/foo/bar/baz +--- response_body_like +(?:\.\.\/lua-resty-core\/lib\/\?\.lua;\.\.\/lua-resty-lrucache\/lib\/\?\.lua;){1,2}\/foo\/bar\/baz /baz/bar/foo --- no_error_log diff --git a/debian/modules/http-lua/t/124-init-worker.t b/debian/modules/http-lua/t/124-init-worker.t index 9b2a91f..b648d55 100644 --- a/debian/modules/http-lua/t/124-init-worker.t +++ b/debian/modules/http-lua/t/124-init-worker.t @@ -521,12 +521,11 @@ warn(): Thu, 01 Jan 1970 01:34:38 GMT } --- request GET /t ---- response_body -timer created +--- response_body_like connected: 1 request sent: 56 -first line received: HTTP/1.1 200 OK -second line received: Server: openresty +first line received: HTTP\/1\.1 200 OK +second line received: (?:Date|Server): .*? --- no_error_log [error] --- timeout: 10 @@ -550,6 +549,7 @@ second line received: Server: openresty else say("connect: ", ok, " ", err) end + done = true end local ok, err = ngx.timer.at(0, handler) @@ -600,6 +600,7 @@ qr/connect\(\) failed \(\d+: Connection refused\), context: ngx\.timer$/ else say("connect: ", ok, " ", err) end + done = true end local ok, err = ngx.timer.at(0, handler) @@ -650,6 +651,7 @@ qr/connect\(\) failed \(\d+: Connection refused\)/ else say("connect: ", ok, " ", err) end + done = true end local ok, err = ngx.timer.at(0, handler) diff --git a/debian/modules/http-lua/t/126-shdict-frag.t b/debian/modules/http-lua/t/126-shdict-frag.t index 5a2aff8..33646d1 100644 --- a/debian/modules/http-lua/t/126-shdict-frag.t +++ b/debian/modules/http-lua/t/126-shdict-frag.t @@ -1240,8 +1240,8 @@ failed to safe set baz: no memory local key = "mylittlekey" .. rand(maxkeyidx) local ok, err = dogs:get(key) if not ok or rand() > 0.6 then - sz = rand(maxsz) - val = rep("a", sz) + local sz = rand(maxsz) + local val = rep("a", sz) local ok, err, forcible = dogs:set(key, val) if err then ngx.log(ngx.ERR, "failed to set key: ", err) diff --git a/debian/modules/http-lua/t/127-uthread-kill.t b/debian/modules/http-lua/t/127-uthread-kill.t index cc43c62..5542153 100644 --- a/debian/modules/http-lua/t/127-uthread-kill.t +++ b/debian/modules/http-lua/t/127-uthread-kill.t @@ -23,7 +23,7 @@ __DATA__ --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("hello from f()") ngx.sleep(1) end @@ -81,7 +81,7 @@ lua clean up the timer for pending ngx.sleep --- config location /lua { content_by_lua ' - function f() + local function f() ngx.say("hello from f()") ngx.sleep(0.001) return 32 @@ -138,12 +138,12 @@ lua clean up the timer for pending ngx.sleep === TEST 3: kill pending resolver --- config - resolver agentzh.org:12345; + resolver 127.0.0.2:12345; location /lua { content_by_lua ' - function f() + local function f() local sock = ngx.socket.tcp() - sock:connect("some.agentzh.org", 12345) + sock:connect("some.127.0.0.2", 12345) end local t, err = ngx.thread.spawn(f) @@ -194,13 +194,13 @@ resolve name done: -2 location /lua { content_by_lua ' local ready = false - function f() + local function f() local sock = ngx.socket.tcp() sock:connect("agentzh.org", 80) sock:close() ready = true sock:settimeout(10000) - sock:connect("agentzh.org", 12345) + sock:connect("127.0.0.2", 12345) end local t, err = ngx.thread.spawn(f) @@ -262,7 +262,7 @@ lua finalize socket location = /t { content_by_lua ' - function f() + local function f() ngx.location.capture("/sub") end @@ -309,11 +309,11 @@ lua tcp socket abort resolver location = /t { content_by_lua ' - function f() + local function f() ngx.location.capture("/sub") end - function g() + local function g() ngx.sleep(0.3) end @@ -376,7 +376,7 @@ lua tcp socket abort resolver location = /t { content_by_lua ' local ready = false - function f() + local function f() ngx.location.capture("/sub") ready = true ngx.sleep(0.5) @@ -424,7 +424,7 @@ lua tcp socket abort resolver --- config location = /t { content_by_lua ' - function f() + local function f() return end @@ -473,7 +473,7 @@ lua tcp socket abort resolver ngx.say("killed main thread.") end - function f() + local function f() local ok, err = ngx.thread.kill(coroutine.running()) if not ok then ngx.say("failed to kill user thread: ", err) diff --git a/debian/modules/http-lua/t/128-duplex-tcp-socket.t b/debian/modules/http-lua/t/128-duplex-tcp-socket.t index aed560c..22b9f03 100644 --- a/debian/modules/http-lua/t/128-duplex-tcp-socket.t +++ b/debian/modules/http-lua/t/128-duplex-tcp-socket.t @@ -396,7 +396,7 @@ F(ngx_http_lua_socket_tcp_finalize_write_part) { end sock:settimeout(300) - local ok, err = sock:connect("172.105.207.225", 12345) + local ok, err = sock:connect("127.0.0.2", 12345) ngx.say("connect: ", ok, " ", err) local ok, err = sock:close() @@ -425,7 +425,7 @@ close: nil closed --- config server_tokens off; lua_socket_log_errors off; - resolver agentzh.org:12345; + resolver 127.0.0.2:12345; resolver_timeout 300ms; location /t { content_by_lua ' @@ -459,7 +459,7 @@ close: nil closed end sock:settimeout(300) - local ok, err = sock:connect("some2.agentzh.org", 12345) + local ok, err = sock:connect("some2.agentzh.org", 80) ngx.say("connect: ", ok, " ", err) local ok, err = sock:close() diff --git a/debian/modules/http-lua/t/129-ssl-socket.t b/debian/modules/http-lua/t/129-ssl-socket.t index 3f05640..f2fa26b 100644 --- a/debian/modules/http-lua/t/129-ssl-socket.t +++ b/debian/modules/http-lua/t/129-ssl-socket.t @@ -301,7 +301,7 @@ SSL reused session content_by_lua ' local sock = ngx.socket.tcp() - sock:settimeout(2000) + sock:settimeout(7000) do @@ -380,7 +380,7 @@ lua ssl free session --- no_error_log [error] [alert] ---- timeout: 5 +--- timeout: 10 @@ -573,7 +573,7 @@ SSL reused session ngx.say("ssl handshake: ", type(session)) - local req = "GET / HTTP/1.1\\r\\nHost: agentzh.org\\r\\nConnection: close\\r\\n\\r\\n" + local req = "GET /en/linux-packages.html HTTP/1.1\\r\\nHost: openresty.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) @@ -602,7 +602,7 @@ GET /t --- response_body connected: 1 ssl handshake: userdata -sent http request: 56 bytes. +sent http request: 80 bytes. received: HTTP/1.1 404 Not Found close: 1 nil @@ -1333,13 +1333,13 @@ failed to send http request: closed --- grep_error_log_out --- error_log eval [ -qr/\[crit\] .*?SSL_do_handshake\(\) failed .*?(unsupported protocol|no protocols available)/, +qr/\[(crit|error)\] .*?SSL_do_handshake\(\) failed .*?(unsupported protocol|no protocols available)/, 'lua ssl server name: "openresty.org"', ] --- no_error_log SSL reused session -[error] [alert] +[emerg] --- timeout: 5 @@ -2508,7 +2508,7 @@ SSL reused session content_by_lua_block { local sock = ngx.socket.tcp() - sock:settimeout(2000) + sock:settimeout(7000) local ok, err = sock:connect("openresty.org", 443) if not ok then @@ -2529,4 +2529,4 @@ GET /t qr/\[error\] .* ngx.socket sslhandshake: expecting 1 ~ 5 arguments \(including the object\), but seen 0/ --- no_error_log [alert] ---- timeout: 5 +--- timeout: 10 diff --git a/debian/modules/http-lua/t/130-internal-api.t b/debian/modules/http-lua/t/130-internal-api.t index eba0980..2158e87 100644 --- a/debian/modules/http-lua/t/130-internal-api.t +++ b/debian/modules/http-lua/t/130-internal-api.t @@ -8,7 +8,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * 3; +plan tests => repeat_each() * blocks() * 3; #no_diff(); no_long_string(); @@ -19,12 +19,7 @@ run_tests(); __DATA__ -=== TEST 1: __ngx_req and __ngx_cycle ---- http_config - init_by_lua ' - my_cycle = __ngx_cycle - '; - +=== TEST 1: req --- config location = /t { content_by_lua ' @@ -32,18 +27,14 @@ __DATA__ local function tonum(ud) return tonumber(ffi.cast("uintptr_t", ud)) end - ngx.say(string.format("init: cycle=%#x", tonum(my_cycle))) - ngx.say(string.format("content cycle=%#x", tonum(__ngx_cycle))) - ngx.say(string.format("content req=%#x", tonum(__ngx_req))) + ngx.say(string.format("content req=%#x", tonum(exdata()))) '; } --- request GET /t --- response_body_like chop -^init: cycle=(0x[a-f0-9]{4,}) -content cycle=\1 -content req=0x[a-f0-9]{4,} +^content req=0x[a-f0-9]{4,} $ --- no_error_log [error] diff --git a/debian/modules/http-lua/t/134-worker-count-5.t b/debian/modules/http-lua/t/134-worker-count-5.t index b257c12..ec6d0e7 100644 --- a/debian/modules/http-lua/t/134-worker-count-5.t +++ b/debian/modules/http-lua/t/134-worker-count-5.t @@ -3,7 +3,7 @@ use Test::Nginx::Socket::Lua; #worker_connections(1014); -#master_on(); +master_on(); workers(5); #log_level('warn'); @@ -55,7 +55,7 @@ workers: 5 === TEST 3: init_by_lua + module (github #681) --- http_config - lua_package_path "t/servroot/html/?.lua;;"; + lua_package_path "$TEST_NGINX_SERVER_ROOT/html/?.lua;;"; init_by_lua_block { local blah = require "file" diff --git a/debian/modules/http-lua/t/138-balancer.t b/debian/modules/http-lua/t/138-balancer.t index 0aba66d..151db7b 100644 --- a/debian/modules/http-lua/t/138-balancer.t +++ b/debian/modules/http-lua/t/138-balancer.t @@ -362,8 +362,6 @@ me: 101 === TEST 13: lua subrequests --- http_config - lua_package_path "t/servroot/html/?.lua;;"; - lua_code_cache off; upstream backend { diff --git a/debian/modules/http-lua/t/139-ssl-cert-by.t b/debian/modules/http-lua/t/139-ssl-cert-by.t index a65d703..bebbdb2 100644 --- a/debian/modules/http-lua/t/139-ssl-cert-by.t +++ b/debian/modules/http-lua/t/139-ssl-cert-by.t @@ -1278,7 +1278,7 @@ lua ssl server name: "test.com" listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_certificate_by_lua_block { - function f() + local function f() ngx.sleep(0.01) print("uthread: hello in thread") return "done" diff --git a/debian/modules/http-lua/t/140-ssl-c-api.t b/debian/modules/http-lua/t/140-ssl-c-api.t index 8734d14..a77f5d4 100644 --- a/debian/modules/http-lua/t/140-ssl-c-api.t +++ b/debian/modules/http-lua/t/140-ssl-c-api.t @@ -10,6 +10,7 @@ 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"); + } else { plan tests => repeat_each() * (blocks() * 5 + 1); } @@ -68,7 +69,7 @@ _EOC_ my $http_config = $block->http_config || ''; $http_config .= <<'_EOC_'; -lua_package_path "$prefix/html/?.lua;;"; +lua_package_path "$prefix/html/?.lua;../lua-resty-core/lib/?.lua;;"; _EOC_ $block->set_value("http_config", $http_config); }); @@ -91,8 +92,8 @@ __DATA__ local errmsg = ffi.new("char *[1]") - local r = getfenv(0).__ngx_req - if not r then + local r = require "resty.core.base" .get_request() + if r == nil then ngx.log(ngx.ERR, "no request found") return end @@ -245,8 +246,8 @@ lua ssl server name: "test.com" local errmsg = ffi.new("char *[1]") - local r = getfenv(0).__ngx_req - if not r then + local r = require "resty.core.base" .get_request() + if r == nil then ngx.log(ngx.ERR, "no request found") return end @@ -399,8 +400,8 @@ lua ssl server name: "test.com" local errmsg = ffi.new("char *[1]") - local r = getfenv(0).__ngx_req - if not r then + local r = require "resty.core.base" .get_request() + if r == nil then ngx.log(ngx.ERR, "no request found") return end @@ -528,8 +529,8 @@ failed to parse PEM priv key: PEM_read_bio_PrivateKey() failed local errmsg = ffi.new("char *[1]") - local r = getfenv(0).__ngx_req - if not r then + local r = require "resty.core.base" .get_request() + if r == nil then ngx.log(ngx.ERR, "no request found") return end @@ -678,8 +679,8 @@ lua ssl server name: "test.com" local errmsg = ffi.new("char *[1]") - local r = getfenv(0).__ngx_req - if not r then + local r = require "resty.core.base" .get_request() + if r == nil then ngx.log(ngx.ERR, "no request found") return end diff --git a/debian/modules/http-lua/t/143-ssl-session-fetch.t b/debian/modules/http-lua/t/143-ssl-session-fetch.t index 4dc992d..78a66cf 100644 --- a/debian/modules/http-lua/t/143-ssl-session-fetch.t +++ b/debian/modules/http-lua/t/143-ssl-session-fetch.t @@ -1114,3 +1114,108 @@ qr/ssl_session_fetch_by_lua_block:1: ssl fetch sess by lua is running!/s [error] [alert] [emerg] + + + +=== TEST 14: keep global variable in ssl_session_(store|fetch)_by_lua when OpenResty LuaJIT is used +--- http_config + ssl_session_store_by_lua_block { + ngx.log(ngx.WARN, "new foo: ", foo) + if not foo then + foo = 1 + else + ngx.log(ngx.WARN, "old foo: ", foo) + foo = foo + 1 + end + } + ssl_session_fetch_by_lua_block { + ngx.log(ngx.WARN, "new bar: ", foo) + if not bar then + bar = 1 + else + ngx.log(ngx.WARN, "old bar: ", bar) + bar = bar + 1 + end + } + + 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_session_tickets off; + + server_tokens off; + location /foo { + content_by_lua_block { + ngx.say("foo: ", foo) + ngx.say("bar: ", bar) + } + } + } +--- 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 + + 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 + + package.loaded.session = 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 + + while true do + local line, err = sock:receive() + if not line then + -- ngx.say("failed to receive response status line: ", err) + break + end + + local m, err = ngx.re.match(line, "^foo: (.*)$", "jo") + if err then + ngx.say("failed to match line: ", err) + end + + if m and m[1] then + ngx.print(m[1]) + end + end + + local ok, err = sock:close() + ngx.say("done") + end -- do + } + } + +--- request +GET /t +--- response_body_like chomp +\A[123]done\n\z +--- grep_error_log eval: qr/old (foo|bar): \d+/ +--- grep_error_log_out eval +["", "old foo: 1\n", "old bar: 1\nold foo: 2\n"] +--- no_error_log +[error] +[alert] +[emerg] diff --git a/debian/modules/http-lua/t/147-tcp-socket-timeouts.t b/debian/modules/http-lua/t/147-tcp-socket-timeouts.t index 4ebc8f3..8566c0b 100644 --- a/debian/modules/http-lua/t/147-tcp-socket-timeouts.t +++ b/debian/modules/http-lua/t/147-tcp-socket-timeouts.t @@ -323,7 +323,7 @@ lua tcp socket write timed out sock:settimeouts(100, 100, 100) - local ok, err = sock:connect("agentzh.org", 12345) + local ok, err = sock:connect("127.0.0.2", 12345) ngx.say("connect: ", ok, " ", err) local bytes @@ -346,7 +346,7 @@ send: nil closed receive: nil closed close: nil closed --- error_log -lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 +lua tcp socket connect timed out, when connecting to 127.0.0.2:12345 --- timeout: 10 @@ -411,7 +411,7 @@ lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 local chunk = 4 - function read() + local function read() sock:settimeout(200) -- read: 200 ms local data, err = sock:receive(content_length) @@ -506,7 +506,7 @@ failed to receive data: timeout local chunk = 4 - function read() + local function read() local data, err = sock:receive(content_length) if not data then ngx.log(ngx.ERR, "failed to receive data: ", err) diff --git a/debian/modules/http-lua/t/152-timer-every.t b/debian/modules/http-lua/t/152-timer-every.t index c8d62e7..7b42d2d 100644 --- a/debian/modules/http-lua/t/152-timer-every.t +++ b/debian/modules/http-lua/t/152-timer-every.t @@ -63,7 +63,7 @@ qr/\[lua\] content_by_lua\(nginx\.conf:\d+\):\d+: elapsed: 0\.(?:09|10)\d*, cont -=== TEST 2: separated global env +=== TEST 2: shared global env --- config location /t { content_by_lua_block { @@ -84,7 +84,7 @@ qr/\[lua\] content_by_lua\(nginx\.conf:\d+\):\d+: elapsed: 0\.(?:09|10)\d*, cont --- request GET /t --- response_body -foo = nil +foo = 3 --- wait: 0.12 --- no_error_log [error] diff --git a/debian/modules/http-lua/t/153-semaphore-hup.t b/debian/modules/http-lua/t/153-semaphore-hup.t index c85a21d..5c271a4 100644 --- a/debian/modules/http-lua/t/153-semaphore-hup.t +++ b/debian/modules/http-lua/t/153-semaphore-hup.t @@ -67,7 +67,7 @@ add_block_preprocessor(sub { return end - shdict = ngx.shared.shdict + local shdict = ngx.shared.shdict local success = shdict:add("reloaded", 1) if not success then return diff --git a/debian/modules/http-lua/t/156-slow-network.t b/debian/modules/http-lua/t/156-slow-network.t new file mode 100644 index 0000000..2d80506 --- /dev/null +++ b/debian/modules/http-lua/t/156-slow-network.t @@ -0,0 +1,138 @@ +BEGIN { + if (!defined $ENV{LD_PRELOAD}) { + $ENV{LD_PRELOAD} = ''; + } + + if ($ENV{LD_PRELOAD} !~ /\bmockeagain\.so\b/) { + $ENV{LD_PRELOAD} = "mockeagain.so $ENV{LD_PRELOAD}"; + } + + if ($ENV{MOCKEAGAIN} eq 'r') { + $ENV{MOCKEAGAIN} = 'rw'; + + } else { + $ENV{MOCKEAGAIN} = 'w'; + } + + $ENV{TEST_NGINX_EVENT_TYPE} = 'poll'; +} + +use Test::Nginx::Socket::Lua; + +repeat_each(2); + +plan tests => repeat_each() * (blocks() * 4); + +add_block_preprocessor(sub { + my $block = shift; + + if (!defined $block->error_log) { + $block->set_value("no_error_log", "[error]"); + } + + if (!defined $block->request) { + $block->set_value("request", "GET /t"); + } + +}); + + +log_level("debug"); +no_long_string(); +#no_diff(); +run_tests(); + +__DATA__ + +=== TEST 1: receiveany returns anything once socket receives +--- config + server_tokens off; + location = /t { + set $port $TEST_NGINX_SERVER_PORT; + content_by_lua_block { + local sock = ngx.socket.tcp() + sock:settimeout(500) + assert(sock:connect("127.0.0.1", ngx.var.port)) + local req = { + 'GET /foo HTTP/1.0\r\n', + 'Host: localhost\r\n', + 'Connection: close\r\n\r\n', + } + local ok, err = sock:send(req) + if not ok then + ngx.say("send request failed: ", err) + return + end + + + -- skip http header + while true do + local data, err, _ = sock:receive('*l') + if err then + ngx.say('unexpected error occurs when receiving http head: ' .. err) + return + end + if #data == 0 then -- read last line of head + break + end + end + + -- receive http body + while true do + local data, err = sock:receiveany(1024) + if err then + if err ~= 'closed' then + ngx.say('unexpected err: ', err) + end + break + end + ngx.say(data) + end + + sock:close() + } + } + + location = /foo { + content_by_lua_block { + local resp = { + '1', + 'hello', + } + + local length = 0 + for _, v in ipairs(resp) do + length = length + #v + end + + -- flush http header + ngx.header['Content-Length'] = length + ngx.flush(true) + ngx.sleep(0.01) + + -- send http body bytes by bytes + for _, v in ipairs(resp) do + ngx.print(v) + ngx.flush(true) + ngx.sleep(0.01) + end + } + } + +--- response_body +1 +h +e +l +l +o +--- grep_error_log eval +qr/lua tcp socket read any/ +--- grep_error_log_out +lua tcp socket read any +lua tcp socket read any +lua tcp socket read any +lua tcp socket read any +lua tcp socket read any +lua tcp socket read any +lua tcp socket read any diff --git a/debian/modules/http-lua/t/157-socket-keepalive-hup.t b/debian/modules/http-lua/t/157-socket-keepalive-hup.t new file mode 100644 index 0000000..357bb59 --- /dev/null +++ b/debian/modules/http-lua/t/157-socket-keepalive-hup.t @@ -0,0 +1,91 @@ +# 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 $SkipReason ? (skip_all => $SkipReason) : (); + +repeat_each(2); + +plan tests => repeat_each() * (blocks() * 8); + +#no_diff(); +no_long_string(); + +worker_connections(1024); +run_tests(); + +__DATA__ + +=== TEST 1: exiting +--- config + location /t { + set $port $TEST_NGINX_SERVER_PORT; + + content_by_lua_block { + local f, err = io.open("$TEST_NGINX_SERVER_ROOT/logs/nginx.pid", "r") + if not f then + ngx.say("failed to open nginx.pid: ", err) + return + end + + local pid = f:read() + -- ngx.say("master pid: [", pid, "]") + + f:close() + + local i = 0 + local port = ngx.var.port + + local function f(premature) + print("timer prematurely expired: ", premature) + + local sock = ngx.socket.tcp() + + local ok, err = sock:connect("127.0.0.1", port) + if not ok then + print("failed to connect: ", err) + return + end + + local ok, err = sock:setkeepalive() + if not ok then + print("failed to setkeepalive: ", err) + return + end + + print("setkeepalive successfully") + end + local ok, err = ngx.timer.at(3, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + os.execute("kill -HUP " .. pid) + } + } +--- request +GET /t + +--- response_body +registered timer + +--- wait: 0.3 +--- no_error_log +[error] +[alert] +[crit] +--- error_log +timer prematurely expired: true +setkeepalive successfully +lua tcp socket set keepalive while process exiting, closing connection diff --git a/debian/modules/http-lua/t/158-global-var.t b/debian/modules/http-lua/t/158-global-var.t new file mode 100644 index 0000000..414a43a --- /dev/null +++ b/debian/modules/http-lua/t/158-global-var.t @@ -0,0 +1,508 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use Test::Nginx::Socket::Lua; + +log_level('debug'); + +repeat_each(2); + +plan tests => repeat_each() * (blocks() * 3 + 14); + +our $HtmlDir = html_dir; + +$ENV{TEST_NGINX_HTML_DIR} ||= html_dir(); + +no_long_string(); + +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 $TestCertificate = read_file("t/cert/test.crt"); +our $TestCertificateKey = read_file("t/cert/test.key"); + +add_block_preprocessor(sub { + my $block = shift; + + if (!defined $block->error_log) { + $block->set_value("no_error_log", "[error]"); + } + + if (!defined $block->request) { + $block->set_value("request", "GET /t"); + } + +}); + +run_tests(); + +__DATA__ + +=== TEST 1: set_by_lua +--- config + location /t { + set_by_lua_block $res { + if not foo then + foo = 1 + else + ngx.log(ngx.WARN, "old foo: ", foo) + foo = foo + 1 + end + return foo + } + echo $res; + } +--- 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, )/ +--- 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"] + + + +=== TEST 2: rewrite_by_lua +--- config + location /t { + rewrite_by_lua_block { + if not foo then + foo = 1 + else + ngx.log(ngx.WARN, "old foo: ", foo) + foo = foo + 1 + end + ngx.say(foo) + } + } +--- response_body_like chomp +\A[12]\n\z +--- grep_error_log eval +qr/(old foo: \d+|\[\w+\].*?writing a global lua variable \('[^'\s]+'\)|\w+_by_lua\(.*?\):\d+: in main chunk, )/ +--- grep_error_log_out eval +[qr/\A\[warn\] .*?writing a global lua variable \('foo'\) +rewrite_by_lua\(nginx\.conf:48\):3: in main chunk, \n\z/, "old foo: 1\n"] + + + +=== TEST 3: access_by_lua +--- config + location /t { + access_by_lua_block { + if not foo then + foo = 1 + else + ngx.log(ngx.WARN, "old foo: ", foo) + foo = foo + 1 + end + ngx.say(foo) + } + } +--- response_body_like chomp +\A[12]\n\z +--- grep_error_log eval +qr/(old foo: \d+|\[\w+\].*?writing a global lua variable \('[^'\s]+'\)|\w+_by_lua\(.*?\):\d+: in main chunk, )/ +--- grep_error_log_out eval +[qr/\A\[warn\] .*?writing a global lua variable \('foo'\) +access_by_lua\(nginx\.conf:48\):3: in main chunk, \n\z/, "old foo: 1\n"] + + + +=== TEST 4: content_by_lua +--- config + location /t { + content_by_lua_block { + if not foo then + foo = 1 + else + ngx.log(ngx.WARN, "old foo: ", foo) + foo = foo + 1 + end + ngx.say(foo) + } + } +--- response_body_like chomp +\A[12]\n\z +--- grep_error_log eval +qr/(old foo: \d+|\[\w+\].*?writing a global lua variable \('[^'\s]+'\)|\w+_by_lua\(.*?\):\d+: in main chunk, )/ +--- grep_error_log_out eval +[qr/\A\[warn\] .*?writing a global lua variable \('foo'\) +content_by_lua\(nginx\.conf:48\):3: in main chunk, \n\z/, "old foo: 1\n"] + + + +=== TEST 5: header_filter_by_lua +--- config + location /t { + content_by_lua_block { + ngx.say(foo) + } + header_filter_by_lua_block { + if not foo then + foo = 1 + else + ngx.log(ngx.WARN, "old foo: ", foo) + foo = foo + 1 + end + } + } +--- 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, )/ +--- 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"] + + + +=== TEST 6: body_filter_by_lua +--- config + location /t { + content_by_lua_block { + ngx.say(foo) + } + body_filter_by_lua_block { + if not foo then + foo = 1 + else + ngx.log(ngx.WARN, "old foo: ", foo) + foo = foo + 1 + end + } + } +--- 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, )/ +--- grep_error_log_out eval +[qr/\[warn\] .*?writing a global lua variable \('foo'\) +body_filter_by_lua:3: in main chunk, +old foo: 1\n\z/, "old foo: 2\nold foo: 3\n"] + + + +=== TEST 7: log_by_lua +--- config + location /t { + content_by_lua_block { + ngx.say(foo) + } + log_by_lua_block { + if not foo then + foo = 1 + else + ngx.log(ngx.WARN, "old foo: ", foo) + foo = foo + 1 + end + } + } +--- 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)/ +--- grep_error_log_out eval +[qr/\A\[warn\] .*?writing a global lua variable \('foo'\) +log_by_lua\(nginx\.conf:50\):3: in main chunk\n\z/, "old foo: 1\n"] + + + +=== TEST 8: ssl_certificate_by_lua +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + ssl_certificate_by_lua_block { + if not foo then + foo = 1 + else + ngx.log(ngx.WARN, "old foo: ", foo) + foo = foo + 1 + end + } + ssl_certificate ../../cert/test.crt; + ssl_certificate_key ../../cert/test.key; + + server_tokens off; + location /foo { + content_by_lua_block { + ngx.say("foo: ", foo) + } + } + } +--- 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 + + local m, err = ngx.re.match(line, "^foo: (.*)$", "jo") + if err then + ngx.say("failed to match line: ", err) + end + + if m and m[1] then + ngx.print(m[1]) + end + end + + local ok, err = sock:close() + ngx.say("done") + end -- do + } + } + +--- 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)/ +--- 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"] + + + +=== TEST 9: timer +--- config + location /t { + content_by_lua_block { + local function f() + if not foo then + foo = 1 + else + ngx.log(ngx.WARN, "old foo: ", foo) + foo = foo + 1 + end + end + local ok, err = ngx.timer.at(0, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.sleep(0.01) + ngx.say(foo) + } + } +--- response_body_like chomp +\A[12]\n\z +--- grep_error_log eval +qr/(old foo: \d+|\[\w+\].*?writing a global lua variable \('[^'\s]+'\)|\w+_by_lua\(.*?\):\d+: in\b)/ +--- grep_error_log_out eval +[qr/\A\[warn\] .*?writing a global lua variable \('foo'\) +content_by_lua\(nginx\.conf:56\):4: in\n\z/, "old foo: 1\n"] + + + +=== TEST 10: init_by_lua +--- http_config + init_by_lua_block { + foo = 1 + } +--- config + location /t { + content_by_lua_block { + if not foo then + foo = 1 + else + ngx.log(ngx.WARN, "old foo: ", foo) + foo = foo + 1 + end + ngx.say(foo) + } + } +--- response_body_like chomp +\A[23]\n\z +--- grep_error_log eval: qr/old foo: \d+/ +--- grep_error_log_out eval +["old foo: 1\n", "old foo: 2\n"] + + + +=== TEST 11: init_worker_by_lua +--- http_config + init_worker_by_lua_block { + if not foo then + foo = 1 + else + ngx.log(ngx.WARN, "old foo: ", foo) + foo = foo + 1 + end + } +--- config + location /t { + content_by_lua_block { + if not foo then + foo = 1 + else + ngx.log(ngx.WARN, "old foo: ", foo) + foo = foo + 1 + end + ngx.say(foo) + } + } +--- response_body_like chomp +\A[23]\n\z +--- grep_error_log eval: qr/old foo: \d+/ +--- grep_error_log_out eval +["old foo: 1\n", "old foo: 2\n"] + + + +=== TEST 12: init_by_lua + init_worker_by_lua +--- http_config + init_by_lua_block { + if not foo then + foo = 1 + else + ngx.log(ngx.WARN, "old foo: ", foo) + foo = foo + 1 + end + } + init_worker_by_lua_block { + if not foo then + foo = 1 + else + ngx.log(ngx.WARN, "old foo: ", foo) + foo = foo + 1 + end + } +--- config + location /t { + content_by_lua_block { + if not foo then + foo = 1 + else + ngx.log(ngx.WARN, "old foo: ", foo) + foo = foo + 1 + end + ngx.say(foo) + } + } +--- response_body_like chomp +\A[34]\n\z +--- grep_error_log eval: qr/old foo: \d+/ +--- grep_error_log_out eval +["old foo: 1\nold foo: 2\n", "old foo: 3\n"] + + + +=== TEST 13: don't show warn messages in init/init_worker +--- http_config + init_by_lua_block { + foo = 1 + } + + init_worker_by_lua_block { + bar = 2 + } +--- config + location /t { + content_by_lua_block { + ngx.say(foo) + ngx.say(bar) + } + } +--- response_body +1 +2 +--- no_error_log +setting global variable + + + +=== TEST 14: uthread +--- config + location /t { + content_by_lua_block { + local function f() + if not foo then + foo = 1 + else + ngx.log(ngx.WARN, "old foo: ", foo) + foo = foo + 1 + end + end + local ok, err = ngx.thread.spawn(f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.sleep(0.01) + ngx.say(foo) + } + } +--- response_body_like chomp +\A[12]\n\z +--- grep_error_log eval +qr/(old foo: \d+|writing a global lua variable \('\w+'\))/ +--- grep_error_log_out eval +["writing a global lua variable \('foo'\)\n", "old foo: 1\n"] + + + +=== TEST 15: balancer_by_lua +--- http_config + upstream backend { + server 0.0.0.1; + balancer_by_lua_block { + if not foo then + foo = 1 + else + ngx.log(ngx.WARN, "old foo: ", foo) + foo = foo + 1 + end + } + } +--- config + location = /t { + proxy_pass http://backend; + } +--- response_body_like: 502 Bad Gateway +--- error_code: 502 +--- error_log eval +qr/\[crit\].*?\Qconnect() to 0.0.0.1:80 failed\E/ +--- grep_error_log eval: qr/(old foo: \d+|writing a global lua variable \('\w+'\))/ +--- grep_error_log_out eval +["writing a global lua variable \('foo'\)\n", "old foo: 1\n"] diff --git a/debian/modules/http-lua/t/159-sa-restart.t b/debian/modules/http-lua/t/159-sa-restart.t new file mode 100644 index 0000000..a0f0c0e --- /dev/null +++ b/debian/modules/http-lua/t/159-sa-restart.t @@ -0,0 +1,180 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use Test::Nginx::Socket::Lua; + +add_block_preprocessor(sub { + my $block = shift; + + my $http_config = $block->http_config || ''; + + $http_config .= <<_EOC_; + init_by_lua_block { + function test_sa_restart() + local signals = { + --"HUP", + --"INFO", + --"XCPU", + --"USR1", + --"USR2", + "ALRM", + --"INT", + "IO", + "CHLD", + --"WINCH", + } + + for _, signame in ipairs(signals) do + local cmd = string.format("kill -s %s %d && sleep 0.01", + signame, ngx.worker.pid()) + local err = select(2, io.popen(cmd):read("*a")) + if err then + error("SIG" .. signame .. " caused: " .. err) + end + end + end + } +_EOC_ + + $block->set_value("http_config", $http_config); + + if (!defined $block->config) { + my $config = <<_EOC_; + location /t { + echo ok; + } +_EOC_ + + $block->set_value("config", $config); + } + + if (!defined $block->request) { + $block->set_value("request", "GET /t"); + } + + if (!defined $block->response_body) { + $block->set_value("ignore_response_body"); + } + + if (!defined $block->no_error_log) { + $block->set_value("no_error_log", "[error]"); + } +}); + +plan tests => repeat_each() * (blocks() * 2 + 1); + +no_long_string(); +run_tests(); + +__DATA__ + +=== TEST 1: lua_sa_restart default - sets SA_RESTART in init_worker_by_lua* +--- http_config + init_worker_by_lua_block { + test_sa_restart() + } + + + +=== TEST 2: lua_sa_restart off - does not set SA_RESTART +--- http_config + lua_sa_restart off; + + init_worker_by_lua_block { + test_sa_restart() + } +--- no_error_log +[crit] +--- error_log +Interrupted system call + + + +=== TEST 3: lua_sa_restart on (default) - sets SA_RESTART if no init_worker_by_lua* phase is defined +--- config + location /t { + content_by_lua_block { + test_sa_restart() + } + } + + + +=== TEST 4: lua_sa_restart on (default) - SA_RESTART is effective in rewrite_by_lua* +--- config + location /t { + rewrite_by_lua_block { + test_sa_restart() + } + + echo ok; + } + + + +=== TEST 5: lua_sa_restart on (default) - SA_RESTART is effective in access_by_lua* +--- config + location /t { + access_by_lua_block { + test_sa_restart() + } + + echo ok; + } + + + +=== TEST 6: lua_sa_restart on (default) - SA_RESTART is effective in content_by_lua* +--- config + location /t { + content_by_lua_block { + test_sa_restart() + } + } + + + +=== TEST 7: lua_sa_restart on (default) - SA_RESTART is effective in header_filter_by_lua* +--- config + location /t { + echo ok; + + header_filter_by_lua_block { + test_sa_restart() + } + } + + + +=== TEST 8: lua_sa_restart on (default) - SA_RESTART is effective in body_filter_by_lua* +--- config + location /t { + echo ok; + + body_filter_by_lua_block { + test_sa_restart() + } + } + + + +=== TEST 9: lua_sa_restart on (default) - SA_RESTART is effective in log_by_lua* +--- config + location /t { + echo ok; + + log_by_lua_block { + test_sa_restart() + } + } + + + +=== TEST 10: lua_sa_restart on (default) - SA_RESTART is effective in timer phase +--- config + location /t { + echo ok; + + log_by_lua_block { + ngx.timer.at(0, test_sa_restart) + } + } diff --git a/debian/modules/http-lua/t/160-disable-init-by-lua.t b/debian/modules/http-lua/t/160-disable-init-by-lua.t new file mode 100644 index 0000000..541771e --- /dev/null +++ b/debian/modules/http-lua/t/160-disable-init-by-lua.t @@ -0,0 +1,194 @@ +use Test::Nginx::Socket::Lua; + +repeat_each(2); + +plan tests => repeat_each() * (blocks() * 3); + +$ENV{TEST_NGINX_HTML_DIR} ||= html_dir(); + +my $html_dir = $ENV{TEST_NGINX_HTML_DIR}; +my $http_config = <<_EOC_; + init_by_lua_block { + function set_up_ngx_tmp_conf(conf) + if conf == nil then + conf = [[ + events { + worker_connections 64; + } + http { + init_by_lua_block { + ngx.log(ngx.ERR, "run init_by_lua") + } + } + ]] + end + + assert(os.execute("mkdir -p $html_dir/logs")) + + local conf_file = "$html_dir/nginx.conf" + local f, err = io.open(conf_file, "w") + if not f then + ngx.log(ngx.ERR, err) + return + end + + assert(f:write(conf)) + + return conf_file + end + + function get_ngx_bin_path() + local ffi = require "ffi" + ffi.cdef[[char **ngx_argv;]] + return ffi.string(ffi.C.ngx_argv[0]) + end + } +_EOC_ + +add_block_preprocessor(sub { + my $block = shift; + + if (!defined $block->http_config) { + $block->set_value("http_config", $http_config); + } + + if (!defined $block->request) { + $block->set_value("request", "GET /t"); + } +}); + +env_to_nginx("PATH"); +log_level("warn"); +no_long_string(); +run_tests(); + +__DATA__ + +=== TEST 1: ensure init_by_lua* is not run in signaller process +--- config + location = /t { + content_by_lua_block { + local conf_file = set_up_ngx_tmp_conf() + local nginx = get_ngx_bin_path() + + local cmd = nginx .. " -p $TEST_NGINX_HTML_DIR -c " .. conf_file .. " -s reopen" + local p, err = io.popen(cmd) + if not p then + ngx.log(ngx.ERR, err) + return + end + + local out, err = p:read("*a") + if not out then + ngx.log(ngx.ERR, err) + + else + ngx.log(ngx.WARN, out) + end + } + } +--- error_log +failed (2: No such file or directory) +--- no_error_log eval +qr/\[error\] .*? init_by_lua:\d+: run init_by_lua/ + + + +=== TEST 2: init_by_lua* does not run when testing Nginx configuration +--- config + location = /t { + content_by_lua_block { + local conf_file = set_up_ngx_tmp_conf() + local nginx = get_ngx_bin_path() + + local cmd = nginx .. " -p $TEST_NGINX_HTML_DIR -c " .. conf_file .. " -t" + local p, err = io.popen(cmd) + if not p then + ngx.log(ngx.ERR, err) + return + end + + local out, err = p:read("*a") + if not out then + ngx.log(ngx.ERR, err) + + else + ngx.log(ngx.WARN, out) + end + + local cmd = nginx .. " -p $TEST_NGINX_HTML_DIR -c " .. conf_file .. " -T" + local p, err = io.popen(cmd) + if not p then + ngx.log(ngx.ERR, err) + return + end + + local out, err = p:read("*a") + if not out then + ngx.log(ngx.ERR, err) + + else + ngx.log(ngx.WARN, out) + end + } + } +--- error_log +test is successful +--- no_error_log eval +qr/\[error\] .*? init_by_lua:\d+: run init_by_lua/ + + + +=== TEST 3: init_by_lua* does not run when testing Nginx configuration which contains 'lua_shared_dict' (GitHub #1462) +--- config + location = /t { + content_by_lua_block { + local conf = [[ + events { + worker_connections 64; + } + http { + lua_shared_dict test 64k; + init_by_lua_block { + ngx.log(ngx.ERR, "run init_by_lua with lua_shared_dict") + } + } + ]] + local conf_file = set_up_ngx_tmp_conf(conf) + local nginx = get_ngx_bin_path() + + local cmd = nginx .. " -p $TEST_NGINX_HTML_DIR -c " .. conf_file .. " -t" + local p, err = io.popen(cmd) + if not p then + ngx.log(ngx.ERR, err) + return + end + + local out, err = p:read("*a") + if not out then + ngx.log(ngx.ERR, err) + + else + ngx.log(ngx.WARN, out) + end + + local cmd = nginx .. " -p $TEST_NGINX_HTML_DIR -c " .. conf_file .. " -T" + local p, err = io.popen(cmd) + if not p then + ngx.log(ngx.ERR, err) + return + end + + local out, err = p:read("*a") + if not out then + ngx.log(ngx.ERR, err) + + else + ngx.log(ngx.WARN, out) + end + } + } +--- error_log +test is successful +--- no_error_log eval +qr/\[error\] .*? init_by_lua:\d+: run init_by_lua with lua_shared_dict/ diff --git a/debian/modules/http-lua/t/161-load-resty-core.t b/debian/modules/http-lua/t/161-load-resty-core.t new file mode 100644 index 0000000..41b18f0 --- /dev/null +++ b/debian/modules/http-lua/t/161-load-resty-core.t @@ -0,0 +1,68 @@ +use Test::Nginx::Socket::Lua; + +repeat_each(2); + +plan tests => repeat_each() * (blocks() * 3); + +add_block_preprocessor(sub { + my $block = shift; + + if (!defined $block->request) { + $block->set_value("request", "GET /t"); + } + + if (!defined $block->no_error_log) { + $block->set_value("no_error_log", "[error]"); + } +}); + +no_long_string(); +run_tests(); + +__DATA__ + +=== TEST 1: lua_load_resty_core is enabled by default +--- config + location = /t { + content_by_lua_block { + local loaded_resty_core = package.loaded["resty.core"] + local resty_core = require "resty.core" + + ngx.say("resty.core loaded: ", loaded_resty_core == resty_core) + } + } +--- response_body +resty.core loaded: true + + + +=== TEST 2: lua_load_resty_core can be disabled +--- http_config + lua_load_resty_core off; +--- config + location = /t { + content_by_lua_block { + local loaded_resty_core = package.loaded["resty.core"] + + ngx.say("resty.core loaded: ", loaded_resty_core ~= nil) + } + } +--- response_body +resty.core loaded: false + + + +=== TEST 3: lua_load_resty_core is effective when using lua_shared_dict +--- http_config + lua_shared_dict dogs 128k; +--- config + location = /t { + content_by_lua_block { + local loaded_resty_core = package.loaded["resty.core"] + local resty_core = require "resty.core" + + ngx.say("resty.core loaded: ", loaded_resty_core == resty_core) + } + } +--- response_body +resty.core loaded: true diff --git a/debian/modules/http-lua/t/data/fake-shm-module/ngx_http_lua_fake_shm_module.c b/debian/modules/http-lua/t/data/fake-shm-module/ngx_http_lua_fake_shm_module.c index 0286853..ffc32f5 100644 --- a/debian/modules/http-lua/t/data/fake-shm-module/ngx_http_lua_fake_shm_module.c +++ b/debian/modules/http-lua/t/data/fake-shm-module/ngx_http_lua_fake_shm_module.c @@ -213,10 +213,9 @@ ngx_http_lua_fake_shm_preload(lua_State *L) ngx_uint_t i; ngx_shm_zone_t **zone; + ngx_shm_zone_t **zone_udata; - lua_getglobal(L, "__ngx_cycle"); - cycle = lua_touserdata(L, -1); - lua_pop(L, 1); + cycle = (ngx_cycle_t *) ngx_cycle; hmcf_ctx = (ngx_http_conf_ctx_t *) cycle->conf_ctx[ngx_http_module.index]; lfsmcf = hmcf_ctx->main_conf[ngx_http_lua_fake_shm_module.ctx_index]; @@ -242,7 +241,9 @@ ngx_http_lua_fake_shm_preload(lua_State *L) lua_createtable(L, 1 /* narr */, 0 /* nrec */); /* table of zone[i] */ - lua_pushlightuserdata(L, zone[i]); /* shared mt key ud */ + zone_udata = lua_newuserdata(L, sizeof(ngx_shm_zone_t *)); + /* shared mt key ud */ + *zone_udata = zone[i]; lua_rawseti(L, -2, 1); /* {zone[i]} */ lua_pushvalue(L, -3); /* shared mt key ud mt */ lua_setmetatable(L, -2); /* shared mt key ud */ @@ -262,9 +263,10 @@ ngx_http_lua_fake_shm_preload(lua_State *L) static int ngx_http_lua_fake_shm_get_info(lua_State *L) { - ngx_int_t n; - ngx_shm_zone_t *zone; - ngx_http_lua_fake_shm_ctx_t *ctx; + ngx_int_t n; + ngx_shm_zone_t *zone; + ngx_shm_zone_t **zone_udata; + ngx_http_lua_fake_shm_ctx_t *ctx; n = lua_gettop(L); @@ -276,13 +278,15 @@ ngx_http_lua_fake_shm_get_info(lua_State *L) luaL_checktype(L, 1, LUA_TTABLE); lua_rawgeti(L, 1, 1); - zone = lua_touserdata(L, -1); + zone_udata = lua_touserdata(L, -1); lua_pop(L, 1); - if (zone == NULL) { + if (zone_udata == NULL) { return luaL_error(L, "bad \"zone\" argument"); } + zone = *zone_udata; + ctx = (ngx_http_lua_fake_shm_ctx_t *) zone->data; lua_pushlstring(L, (char *) zone->shm.name.data, zone->shm.name.len); diff --git a/debian/modules/http-lua/util/build.sh b/debian/modules/http-lua/util/build.sh index 164bf9f..14e9fd4 100755 --- a/debian/modules/http-lua/util/build.sh +++ b/debian/modules/http-lua/util/build.sh @@ -22,6 +22,8 @@ force=$2 #--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-pcre-jit \ --with-ipv6 \ @@ -55,7 +57,7 @@ time ngx-build $force $version \ --add-module=$root/../redis2-nginx-module \ --add-module=$root/../stream-lua-nginx-module \ --add-module=$root/t/data/fake-module \ - --add-module=$root/t/data/fake-shm-module \ + $add_fake_shm_module \ --add-module=$root/t/data/fake-delayed-load-module \ --with-http_gunzip_module \ --with-http_dav_module \ From 7bc0cfe077ec67ac0e4cde241114d571ae40c1c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Nov=C3=BD?= Date: Tue, 15 Mar 2022 11:13:17 +0100 Subject: [PATCH 075/329] http-lua: Rebase patch --- .../patches/http-lua/CVE-2020-11724.patch | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/debian/modules/patches/http-lua/CVE-2020-11724.patch b/debian/modules/patches/http-lua/CVE-2020-11724.patch index 5e0eff7..5b47abe 100644 --- a/debian/modules/patches/http-lua/CVE-2020-11724.patch +++ b/debian/modules/patches/http-lua/CVE-2020-11724.patch @@ -13,8 +13,8 @@ Signed-off-by: Yichun Zhang (agentzh) Index: http-lua/src/ngx_http_lua_subrequest.c =================================================================== ---- http-lua.orig/src/ngx_http_lua_subrequest.c 2020-07-14 09:50:35.830928117 +0200 -+++ http-lua/src/ngx_http_lua_subrequest.c 2020-07-14 09:50:35.826928232 +0200 +--- http-lua.orig/src/ngx_http_lua_subrequest.c 2022-03-15 11:11:11.303357830 +0100 ++++ http-lua/src/ngx_http_lua_subrequest.c 2022-03-15 11:11:11.299357831 +0100 @@ -56,8 +56,6 @@ ngx_string("Content-Length"); @@ -99,7 +99,7 @@ Index: http-lua/src/ngx_http_lua_subrequest.c sr->method = method; switch (method) { -@@ -1124,100 +1108,6 @@ +@@ -1132,100 +1116,6 @@ } @@ -200,7 +200,7 @@ Index: http-lua/src/ngx_http_lua_subrequest.c static void ngx_http_lua_handle_subreq_responses(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx) -@@ -1732,11 +1622,17 @@ +@@ -1740,11 +1630,17 @@ static ngx_int_t @@ -220,7 +220,7 @@ Index: http-lua/src/ngx_http_lua_subrequest.c if (ngx_list_init(&sr->headers_in.headers, sr->pool, 20, sizeof(ngx_table_elt_t)) != NGX_OK) -@@ -1744,10 +1640,46 @@ +@@ -1752,10 +1648,46 @@ return NGX_ERROR; } @@ -270,7 +270,7 @@ Index: http-lua/src/ngx_http_lua_subrequest.c header = part->elts; for (i = 0; /* void */; i++) { -@@ -1762,7 +1694,14 @@ +@@ -1770,7 +1702,14 @@ i = 0; } @@ -286,7 +286,7 @@ Index: http-lua/src/ngx_http_lua_subrequest.c header[i].key.data, (int) header[i].value.len, header[i].value.data); -@@ -1774,9 +1713,10 @@ +@@ -1782,9 +1721,10 @@ } dd("after: parent req headers count: %d", @@ -300,8 +300,8 @@ Index: http-lua/src/ngx_http_lua_subrequest.c /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ Index: http-lua/t/020-subrequest.t =================================================================== ---- http-lua.orig/t/020-subrequest.t 2020-07-14 09:50:35.830928117 +0200 -+++ http-lua/t/020-subrequest.t 2020-07-14 09:50:35.826928232 +0200 +--- http-lua.orig/t/020-subrequest.t 2022-03-15 11:11:11.303357830 +0100 ++++ http-lua/t/020-subrequest.t 2022-03-15 11:11:11.299357831 +0100 @@ -14,6 +14,7 @@ plan tests => repeat_each() * (blocks() * 3 + 23); From 976d4826bba96c5b3c8e3fd454606da59a50b7f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Nov=C3=BD?= Date: Tue, 15 Mar 2022 11:13:34 +0100 Subject: [PATCH 076/329] nchan: Drop GCC 10 patch, applied upstream --- .../patches/nchan/gcc-10-compatibility.patch | 58 ------------------- debian/modules/patches/nchan/series | 1 - 2 files changed, 59 deletions(-) delete mode 100644 debian/modules/patches/nchan/gcc-10-compatibility.patch delete mode 100644 debian/modules/patches/nchan/series diff --git a/debian/modules/patches/nchan/gcc-10-compatibility.patch b/debian/modules/patches/nchan/gcc-10-compatibility.patch deleted file mode 100644 index 00e3b45..0000000 --- a/debian/modules/patches/nchan/gcc-10-compatibility.patch +++ /dev/null @@ -1,58 +0,0 @@ -From f484c603a81c3bddd3f0160cfdbe231b8a453cde Mon Sep 17 00:00:00 2001 -From: Leo P -Date: Wed, 24 Jun 2020 15:28:07 -0400 -Subject: [PATCH] GCC 10 compatibility -Origin: https://github.com/slact/nchan/commit/f484c603a81c3bddd3f0160cfdbe231b8a453cde - ---- - src/store/memory/memstore.c | 2 ++ - src/store/memory/store-private.h | 2 +- - src/store/redis/redis_lua_commands.h | 7 +++++-- - 5 files changed, 10 insertions(+), 4 deletions(-) - -diff --git a/src/store/memory/memstore.c b/src/store/memory/memstore.c -index 2844220c..f0f78acc 100755 ---- a/src/store/memory/memstore.c -+++ b/src/store/memory/memstore.c -@@ -40,6 +40,8 @@ static ngx_int_t redis_fakesub_timer_interval; - - #endif - -+uint16_t memstore_worker_generation; -+ - - typedef struct { - //memstore_channel_head_t unbuffered_dummy_chanhead; -diff --git a/src/store/memory/store-private.h b/src/store/memory/store-private.h -index e4a426a3..49de940b 100644 ---- a/src/store/memory/store-private.h -+++ b/src/store/memory/store-private.h -@@ -172,6 +172,6 @@ ngx_int_t chanhead_gc_withdraw(memstore_channel_head_t *chanhead, const char *); - void memstore_chanhead_release(memstore_channel_head_t *ch, char *label); - void memstore_chanhead_reserve(memstore_channel_head_t *ch, const char *label); - --uint16_t memstore_worker_generation; //times nginx has been restarted + 1 -+extern uint16_t memstore_worker_generation; //times nginx has been restarted + 1 - - #endif /*MEMSTORE_PRIVATE_HEADER*/ -diff --git a/src/store/redis/redis_lua_commands.h b/src/store/redis/redis_lua_commands.h -index 76fb7b95..2efb25bd 100644 ---- a/src/store/redis/redis_lua_commands.h -+++ b/src/store/redis/redis_lua_commands.h -@@ -1,3 +1,5 @@ -+#ifndef NCHAN_REDIS_LUA_SCRIPTS_H -+#define NCHAN_REDIS_LUA_SCRIPTS_H - // don't edit this please, it was auto-generated by hsss - // https://github.com/slact/hsss - -@@ -63,7 +65,8 @@ typedef struct { - redis_lua_script_t subscriber_unregister; - - } redis_lua_scripts_t; --redis_lua_scripts_t redis_lua_scripts; --const int redis_lua_scripts_count; -+extern redis_lua_scripts_t redis_lua_scripts; -+extern const int redis_lua_scripts_count; - #define REDIS_LUA_SCRIPTS_EACH(script) \ - for((script)=(redis_lua_script_t *)&redis_lua_scripts; (script) < (redis_lua_script_t *)(&redis_lua_scripts + 1); (script)++) -+#endif //NCHAN_REDIS_LUA_SCRIPTS_H diff --git a/debian/modules/patches/nchan/series b/debian/modules/patches/nchan/series deleted file mode 100644 index 80f5dee..0000000 --- a/debian/modules/patches/nchan/series +++ /dev/null @@ -1 +0,0 @@ -gcc-10-compatibility.patch From 4499fb4947e2e86632d1aef513e79872afae54f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Nov=C3=BD?= Date: Tue, 15 Mar 2022 11:29:20 +0100 Subject: [PATCH 077/329] d/watch: Bump version to 4 --- debian/watch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/watch b/debian/watch index 5ea7cc0..26440a9 100644 --- a/debian/watch +++ b/debian/watch @@ -1,3 +1,3 @@ -version=3 +version=4 opts=pgpsigurlmangle=s/$/.asc/ \ https://nginx.org/download/nginx-(1\.18\.\d+)\.tar\.gz From a13d46c86515c9be61741dac706085b4c9f02879 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Nov=C3=BD?= Date: Tue, 15 Mar 2022 11:37:01 +0100 Subject: [PATCH 078/329] d/nginx-common.nginx.service: Fix service shutdown desctiption to mention SIGQUIT instead of SIGSTOP (LP: #1919965) (Thanks Athos Ribeiro) --- debian/nginx-common.nginx.service | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/nginx-common.nginx.service b/debian/nginx-common.nginx.service index 2f4286f..78bf0ce 100644 --- a/debian/nginx-common.nginx.service +++ b/debian/nginx-common.nginx.service @@ -1,7 +1,7 @@ # Stop dance for nginx # ======================= # -# ExecStop sends SIGSTOP (graceful stop) to the nginx process. +# ExecStop sends SIGQUIT (graceful stop) to the nginx process. # If, after 5s (--retry QUIT/5) nginx is still running, systemd takes control # and sends SIGTERM (fast shutdown) to the main process. # After another 5s (TimeoutStopSec=5), and if nginx is alive, systemd sends From bd32060ee7b03cb55d7d3fc72ce9a2b16ce0277d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Nov=C3=BD?= Date: Tue, 15 Mar 2022 11:39:40 +0100 Subject: [PATCH 079/329] Bump standards version to 4.6.1 (no changes) --- debian/control | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/control b/debian/control index d55777f..719dcc7 100644 --- a/debian/control +++ b/debian/control @@ -22,7 +22,7 @@ Build-Depends: debhelper-compat (= 13), po-debconf, quilt, zlib1g-dev -Standards-Version: 4.5.0 +Standards-Version: 4.6.0 Homepage: https://nginx.net Vcs-Git: https://salsa.debian.org/nginx-team/nginx.git Vcs-Browser: https://salsa.debian.org/nginx-team/nginx From 4ea741ae27bb497632a7d960520aba039dc771ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Nov=C3=BD?= Date: Tue, 15 Mar 2022 11:44:33 +0100 Subject: [PATCH 080/329] d/copyright: Bump my copyright year --- debian/copyright | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/copyright b/debian/copyright index c2a5f97..03ef16d 100644 --- a/debian/copyright +++ b/debian/copyright @@ -42,7 +42,7 @@ Copyright: 2007-2009, Fabio Tranchitella 2011-2013, Cyril Lavier 2013-2016, Christos Trochalakis 2019-2020, Thomas Ward - 2020, Ondřej Nový + 2020-2022, Ondřej Nový License: BSD-2-clause Files: debian/modules/http-headers-more-filter/* From 4f1a2c590c57119733fdc975bf9030bb3afe3a8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Nov=C3=BD?= Date: Tue, 15 Mar 2022 11:50:23 +0100 Subject: [PATCH 081/329] releasing package nginx version 1.18.0-7 --- debian/changelog | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index 05a740b..9cbe50c 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,8 +1,27 @@ -nginx (1.18.0-7) UNRELEASED; urgency=medium +nginx (1.18.0-7) unstable; urgency=medium + [ Ondřej Nový ] * d/p/CVE-2019-20372.patch: Drop, applied upstream. + * http-auth-pam: Upgrade to 1.5.3. + * http-echo: Upgrade to 0.62. + * nchan: Upgrade to 1.2.15. + * http-fancyindex: Upgrade to 0.5.2. + * rtmp: Upgrade to 1.2.2. + * http-lua: Upgrade to 0.10.15 (Closes: #994178). + * http-lua: Rebase patch. + * nchan: Drop GCC 10 patch, applied upstream. + * d/watch: Bump version to 4. + * Bump standards version to 4.6.1 (no changes). + * d/copyright: Bump my copyright year. - -- Ondřej Nový Fri, 21 Aug 2020 14:14:13 +0200 + [ Ondřej Surý ] + * Add arm64 and ppc64el to list of luajit platforms. + + [ Athos Ribeiro ] + * d/nginx-common.nginx.service: Fix service shutdown desctiption to mention + SIGQUIT instead of SIGSTOP (LP: #1919965). + + -- Ondřej Nový Tue, 15 Mar 2022 11:50:18 +0100 nginx (1.18.0-6) unstable; urgency=medium From bc5f19ef77b6d4fc6094283b5180862386a72cc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Nov=C3=BD?= Date: Tue, 15 Mar 2022 13:23:10 +0100 Subject: [PATCH 082/329] releasing package nginx version 1.18.0-8 --- debian/changelog | 15 ++++++++ ...ff-by-one-write-in-ngx_resolver_copy.patch | 34 +++++++++++++++++++ debian/patches/series | 1 + 3 files changed, 50 insertions(+) create mode 100644 debian/patches/Resolver-fixed-off-by-one-write-in-ngx_resolver_copy.patch diff --git a/debian/changelog b/debian/changelog index 9cbe50c..8b0d9f0 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,10 @@ +nginx (1.18.0-8) unstable; urgency=medium + + * Restore patch: + d/p/Resolver-fixed-off-by-one-write-in-ngx_resolver_copy.patch + + -- Ondřej Nový Tue, 15 Mar 2022 13:23:06 +0100 + nginx (1.18.0-7) unstable; urgency=medium [ Ondřej Nový ] @@ -23,6 +30,14 @@ nginx (1.18.0-7) unstable; urgency=medium -- Ondřej Nový Tue, 15 Mar 2022 11:50:18 +0100 +nginx (1.18.0-6.1) unstable; urgency=high + + * Non-maintainer upload. + * Resolver: fixed off-by-one write in ngx_resolver_copy() (CVE-2021-23017) + (Closes: #989095) + + -- Salvatore Bonaccorso Sat, 29 May 2021 16:21:37 +0200 + nginx (1.18.0-6) unstable; urgency=medium * Fix GCC-10 compatibility (Closes: #957605). diff --git a/debian/patches/Resolver-fixed-off-by-one-write-in-ngx_resolver_copy.patch b/debian/patches/Resolver-fixed-off-by-one-write-in-ngx_resolver_copy.patch new file mode 100644 index 0000000..449c096 --- /dev/null +++ b/debian/patches/Resolver-fixed-off-by-one-write-in-ngx_resolver_copy.patch @@ -0,0 +1,34 @@ +From: Maxim Dounin +Date: Tue, 25 May 2021 15:17:36 +0300 +Subject: Resolver: fixed off-by-one write in ngx_resolver_copy(). +Origin: https://github.com/nginx/nginx/commit/7199ebc203f74fd9e44595474de6bdc41740c5cf +Bug-Debian: https://bugs.debian.org/989095 +Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2021-23017 + +Reported by Luis Merino, Markus Vervier, Eric Sesterhenn, X41 D-Sec GmbH. +--- + src/core/ngx_resolver.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/src/core/ngx_resolver.c ++++ b/src/core/ngx_resolver.c +@@ -3993,15 +3993,15 @@ + n = *src++; + + } else { ++ if (dst != name->data) { ++ *dst++ = '.'; ++ } ++ + ngx_strlow(dst, src, n); + dst += n; + src += n; + + n = *src++; +- +- if (n != 0) { +- *dst++ = '.'; +- } + } + + if (n == 0) { diff --git a/debian/patches/series b/debian/patches/series index 5b6b799..9416267 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -1,2 +1,3 @@ 0002-Make-sure-signature-stays-the-same-in-all-nginx-buil.patch 0003-define_gnu_source-on-other-glibc-based-platforms.patch +Resolver-fixed-off-by-one-write-in-ngx_resolver_copy.patch From 31e3a6a61bc63dbc1254b5e68094e20d9f98a7b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Nov=C3=BD?= Date: Tue, 15 Mar 2022 14:30:13 +0100 Subject: [PATCH 083/329] d/changelog: Fix typo --- debian/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 8b0d9f0..8af7ecf 100644 --- a/debian/changelog +++ b/debian/changelog @@ -25,7 +25,7 @@ nginx (1.18.0-7) unstable; urgency=medium * Add arm64 and ppc64el to list of luajit platforms. [ Athos Ribeiro ] - * d/nginx-common.nginx.service: Fix service shutdown desctiption to mention + * d/nginx-common.nginx.service: Fix service shutdown description to mention SIGQUIT instead of SIGSTOP (LP: #1919965). -- Ondřej Nový Tue, 15 Mar 2022 11:50:18 +0100 From 6a0621d22796eb499cc430096aa7e8e5d0d957aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Tue, 5 Apr 2022 19:05:32 +0200 Subject: [PATCH 084/329] http-lua: Downgrade to v0.10.13 --- debian/modules/control | 2 +- debian/modules/http-lua/README.markdown | 235 +- debian/modules/http-lua/config | 45 - .../modules/http-lua/doc/HttpLuaModule.wiki | 213 +- .../http-lua/src/api/ngx_http_lua_api.h | 2 +- .../http-lua/src/ngx_http_lua_accessby.c | 4 +- .../modules/http-lua/src/ngx_http_lua_api.c | 2 +- .../http-lua/src/ngx_http_lua_balancer.c | 3 - .../http-lua/src/ngx_http_lua_bodyfilterby.c | 50 +- .../http-lua/src/ngx_http_lua_bodyfilterby.h | 2 +- .../modules/http-lua/src/ngx_http_lua_cache.c | 23 +- .../http-lua/src/ngx_http_lua_clfactory.c | 45 +- .../http-lua/src/ngx_http_lua_common.h | 49 +- .../http-lua/src/ngx_http_lua_contentby.c | 2 - .../http-lua/src/ngx_http_lua_control.c | 3 +- .../http-lua/src/ngx_http_lua_coroutine.c | 18 +- .../http-lua/src/ngx_http_lua_directive.c | 11 +- .../src/ngx_http_lua_headerfilterby.c | 3 +- .../http-lua/src/ngx_http_lua_headers.c | 83 +- .../http-lua/src/ngx_http_lua_headers_in.c | 10 +- .../http-lua/src/ngx_http_lua_headers_out.c | 20 +- .../http-lua/src/ngx_http_lua_headers_out.h | 6 +- .../http-lua/src/ngx_http_lua_initworkerby.c | 19 - .../http-lua/src/ngx_http_lua_input_filters.c | 137 - .../http-lua/src/ngx_http_lua_input_filters.h | 29 - .../modules/http-lua/src/ngx_http_lua_logby.c | 3 +- .../modules/http-lua/src/ngx_http_lua_misc.c | 27 - .../http-lua/src/ngx_http_lua_module.c | 56 - .../modules/http-lua/src/ngx_http_lua_ndk.c | 41 - .../modules/http-lua/src/ngx_http_lua_pipe.c | 2475 ----------------- .../modules/http-lua/src/ngx_http_lua_pipe.h | 95 - .../modules/http-lua/src/ngx_http_lua_regex.c | 10 +- .../http-lua/src/ngx_http_lua_rewriteby.c | 4 +- .../http-lua/src/ngx_http_lua_script.c | 4 +- .../modules/http-lua/src/ngx_http_lua_setby.c | 34 +- .../modules/http-lua/src/ngx_http_lua_setby.h | 2 +- .../http-lua/src/ngx_http_lua_shdict.c | 44 +- .../http-lua/src/ngx_http_lua_socket_tcp.c | 1608 ++++------- .../http-lua/src/ngx_http_lua_socket_tcp.h | 29 +- .../http-lua/src/ngx_http_lua_socket_udp.c | 12 +- .../http-lua/src/ngx_http_lua_ssl_certby.c | 2 - .../src/ngx_http_lua_ssl_session_fetchby.c | 2 - .../src/ngx_http_lua_ssl_session_storeby.c | 3 - .../http-lua/src/ngx_http_lua_string.c | 14 - .../http-lua/src/ngx_http_lua_subrequest.c | 8 - .../modules/http-lua/src/ngx_http_lua_timer.c | 44 +- .../http-lua/src/ngx_http_lua_uthread.c | 3 +- .../modules/http-lua/src/ngx_http_lua_util.c | 168 +- .../modules/http-lua/src/ngx_http_lua_util.h | 28 +- .../http-lua/src/ngx_http_lua_worker.c | 11 - debian/modules/http-lua/t/.gitignore | 2 - debian/modules/http-lua/t/000--init.t | 5 + debian/modules/http-lua/t/001-set.t | 23 +- debian/modules/http-lua/t/002-content.t | 38 +- debian/modules/http-lua/t/004-require.t | 12 +- debian/modules/http-lua/t/005-exit.t | 2 +- debian/modules/http-lua/t/009-log.t | 12 +- debian/modules/http-lua/t/011-md5_bin.t | 2 +- debian/modules/http-lua/t/013-base64.t | 2 +- debian/modules/http-lua/t/014-bugs.t | 49 +- debian/modules/http-lua/t/016-resp-header.t | 504 +--- debian/modules/http-lua/t/017-exec.t | 4 +- debian/modules/http-lua/t/020-subrequest.t | 134 +- .../http-lua/t/023-rewrite/client-abort.t | 6 +- debian/modules/http-lua/t/023-rewrite/exec.t | 4 +- debian/modules/http-lua/t/023-rewrite/mixed.t | 4 +- .../http-lua/t/023-rewrite/multi-capture.t | 2 +- .../http-lua/t/023-rewrite/req-socket.t | 6 +- .../modules/http-lua/t/023-rewrite/sanity.t | 28 +- .../http-lua/t/023-rewrite/socket-keepalive.t | 12 +- .../http-lua/t/023-rewrite/subrequest.t | 42 +- .../t/023-rewrite/tcp-socket-timeout.t | 12 +- .../http-lua/t/023-rewrite/tcp-socket.t | 32 +- .../http-lua/t/023-rewrite/uthread-exec.t | 12 +- .../http-lua/t/023-rewrite/uthread-exit.t | 40 +- .../http-lua/t/023-rewrite/uthread-redirect.t | 4 +- .../http-lua/t/023-rewrite/uthread-spawn.t | 62 +- .../http-lua/t/024-access/client-abort.t | 6 +- debian/modules/http-lua/t/024-access/exec.t | 2 +- debian/modules/http-lua/t/024-access/mixed.t | 10 +- .../http-lua/t/024-access/multi-capture.t | 2 +- debian/modules/http-lua/t/024-access/sanity.t | 30 +- .../http-lua/t/024-access/subrequest.t | 42 +- .../http-lua/t/024-access/uthread-exec.t | 12 +- .../http-lua/t/024-access/uthread-exit.t | 38 +- .../http-lua/t/024-access/uthread-redirect.t | 4 +- .../http-lua/t/024-access/uthread-spawn.t | 62 +- debian/modules/http-lua/t/025-codecache.t | 174 +- debian/modules/http-lua/t/027-multi-capture.t | 4 +- debian/modules/http-lua/t/028-req-header.t | 24 +- debian/modules/http-lua/t/030-uri-args.t | 23 +- debian/modules/http-lua/t/034-match.t | 65 +- debian/modules/http-lua/t/035-gmatch.t | 22 +- debian/modules/http-lua/t/036-sub.t | 4 +- debian/modules/http-lua/t/037-gsub.t | 2 +- debian/modules/http-lua/t/038-match-o.t | 44 +- debian/modules/http-lua/t/041-header-filter.t | 15 +- debian/modules/http-lua/t/043-shdict.t | 4 +- debian/modules/http-lua/t/047-match-jit.t | 12 +- debian/modules/http-lua/t/048-match-dfa.t | 12 +- debian/modules/http-lua/t/055-subreq-vars.t | 18 +- debian/modules/http-lua/t/056-flush.t | 2 +- debian/modules/http-lua/t/057-flush-timeout.t | 2 +- debian/modules/http-lua/t/058-tcp-socket.t | 364 +-- debian/modules/http-lua/t/062-count.t | 31 +- debian/modules/http-lua/t/063-abort.t | 62 +- debian/modules/http-lua/t/064-pcall.t | 14 +- .../http-lua/t/065-tcp-socket-timeout.t | 24 +- .../http-lua/t/066-socket-receiveuntil.t | 30 +- debian/modules/http-lua/t/067-req-socket.t | 6 +- .../modules/http-lua/t/068-socket-keepalive.t | 1467 +--------- debian/modules/http-lua/t/073-backtrace.t | 14 +- debian/modules/http-lua/t/075-logby.t | 11 +- debian/modules/http-lua/t/081-bytecode.t | 45 +- debian/modules/http-lua/t/082-body-filter.t | 3 +- .../http-lua/t/084-inclusive-receiveuntil.t | 20 +- debian/modules/http-lua/t/087-udp-socket.t | 12 +- .../http-lua/t/090-log-socket-errors.t | 10 +- debian/modules/http-lua/t/091-coroutine.t | 81 +- debian/modules/http-lua/t/093-uthread-spawn.t | 66 +- debian/modules/http-lua/t/094-uthread-exit.t | 46 +- debian/modules/http-lua/t/095-uthread-exec.t | 14 +- .../modules/http-lua/t/096-uthread-redirect.t | 6 +- .../modules/http-lua/t/097-uthread-rewrite.t | 12 +- debian/modules/http-lua/t/098-uthread-wait.t | 74 +- debian/modules/http-lua/t/099-c-api.t | 10 +- debian/modules/http-lua/t/100-client-abort.t | 6 +- debian/modules/http-lua/t/106-timer.t | 18 +- debian/modules/http-lua/t/108-timer-safe.t | 16 +- debian/modules/http-lua/t/109-timer-hup.t | 18 +- debian/modules/http-lua/t/120-re-find.t | 4 +- debian/modules/http-lua/t/123-lua-path.t | 10 +- debian/modules/http-lua/t/124-init-worker.t | 10 +- debian/modules/http-lua/t/126-shdict-frag.t | 4 +- debian/modules/http-lua/t/127-uthread-kill.t | 26 +- .../http-lua/t/128-duplex-tcp-socket.t | 6 +- debian/modules/http-lua/t/129-ssl-socket.t | 16 +- debian/modules/http-lua/t/130-internal-api.t | 17 +- .../modules/http-lua/t/134-worker-count-5.t | 4 +- debian/modules/http-lua/t/138-balancer.t | 2 + debian/modules/http-lua/t/139-ssl-cert-by.t | 2 +- debian/modules/http-lua/t/140-ssl-c-api.t | 23 +- .../http-lua/t/143-ssl-session-fetch.t | 105 - .../http-lua/t/147-tcp-socket-timeouts.t | 8 +- debian/modules/http-lua/t/152-timer-every.t | 4 +- debian/modules/http-lua/t/153-semaphore-hup.t | 2 +- debian/modules/http-lua/t/156-slow-network.t | 138 - .../http-lua/t/157-socket-keepalive-hup.t | 91 - debian/modules/http-lua/t/158-global-var.t | 508 ---- debian/modules/http-lua/t/159-sa-restart.t | 180 -- .../http-lua/t/160-disable-init-by-lua.t | 194 -- .../modules/http-lua/t/161-load-resty-core.t | 68 - .../ngx_http_lua_fake_shm_module.c | 22 +- debian/modules/http-lua/util/build.sh | 4 +- .../patches/http-lua/CVE-2020-11724.patch | 18 +- 155 files changed, 1875 insertions(+), 9504 deletions(-) delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_input_filters.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_input_filters.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_pipe.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_pipe.h delete mode 100644 debian/modules/http-lua/t/.gitignore delete mode 100644 debian/modules/http-lua/t/156-slow-network.t delete mode 100644 debian/modules/http-lua/t/157-socket-keepalive-hup.t delete mode 100644 debian/modules/http-lua/t/158-global-var.t delete mode 100644 debian/modules/http-lua/t/159-sa-restart.t delete mode 100644 debian/modules/http-lua/t/160-disable-init-by-lua.t delete mode 100644 debian/modules/http-lua/t/161-load-resty-core.t diff --git a/debian/modules/control b/debian/modules/control index 4034f4d..b3e517e 100644 --- a/debian/modules/control +++ b/debian/modules/control @@ -22,7 +22,7 @@ Version: 3.3 Module: http-lua Homepage: https://github.com/openresty/lua-nginx-module -Version: 0.10.15 +Version: v0.10.13 Patch: openssl-1.1.0.patch discover-luajit-2.1.patch diff --git a/debian/modules/http-lua/README.markdown b/debian/modules/http-lua/README.markdown index ed0c72d..15ad00e 100644 --- a/debian/modules/http-lua/README.markdown +++ b/debian/modules/http-lua/README.markdown @@ -8,8 +8,6 @@ Name ngx_http_lua_module - Embed the power of Lua into Nginx HTTP Servers. -This module is a core component of OpenResty. If you are using this module, then you are essentially using OpenResty :) - *This module is not distributed with the Nginx source.* See [the installation instructions](#installation). Table of Contents @@ -25,6 +23,7 @@ Table of Contents * [Installation](#installation) * [Building as a dynamic module](#building-as-a-dynamic-module) * [C Macro Configurations](#c-macro-configurations) + * [Installation on Ubuntu 11.10](#installation-on-ubuntu-1110) * [Community](#community) * [English Mailing List](#english-mailing-list) * [Chinese Mailing List](#chinese-mailing-list) @@ -63,7 +62,7 @@ Production ready. Version ======= -This document describes ngx_lua [v0.10.15](https://github.com/openresty/lua-nginx-module/tags) released on March 14th, 2019. +This document describes ngx_lua [v0.10.13](https://github.com/openresty/lua-nginx-module/tags) released on 22 April 2018. Synopsis ======== @@ -188,9 +187,7 @@ Synopsis Description =========== -This module is a core component of OpenResty. If you are using this module, then you are essentially using OpenResty :) - -This module embeds Lua, via [LuaJIT 2.0/2.1](http://luajit.org/luajit.html), into Nginx and by leveraging Nginx's subrequests, allows the integration of the powerful Lua threads (Lua coroutines) into the Nginx event model. +This module embeds Lua, via the standard Lua 5.1 interpreter or [LuaJIT 2.0/2.1](http://luajit.org/luajit.html), into Nginx and by leveraging Nginx's subrequests, allows the integration of the powerful Lua threads (Lua coroutines) into the Nginx event model. Unlike [Apache's mod_lua](https://httpd.apache.org/docs/trunk/mod/mod_lua.html) and [Lighttpd's mod_magnet](http://redmine.lighttpd.net/wiki/1/Docs:ModMagnet), Lua code executed using this module can be *100% non-blocking* on network traffic as long as the [Nginx API for Lua](#nginx-api-for-lua) provided by this module is used to handle requests to upstream services such as MySQL, PostgreSQL, Memcached, Redis, or upstream HTTP web services. @@ -268,11 +265,11 @@ Nginx cores older than 1.6.0 (exclusive) are *not* supported. Installation ============ -It is *highly* recommended to use [OpenResty releases](http://openresty.org) which integrate Nginx, ngx_lua, OpenResty's LuaJIT 2.1 branch version, as well as other powerful companion Nginx modules and Lua libraries. It is discouraged to build this module with nginx yourself since it is tricky to set up exactly right. Also, the stock nginx cores have various limitations and long standing bugs that can make some of this modules' features become disabled, not work properly, or run slower. The same applies to LuaJIT as well. OpenResty includes its own version of LuaJIT which gets specifically optimized and enhanced for the OpenResty environment. +It is *highly* recommended to use [OpenResty releases](http://openresty.org) which integrate Nginx, ngx_lua, LuaJIT 2.1, as well as other powerful companion Nginx modules and Lua libraries. It is discouraged to build this module with nginx yourself since it is tricky to set up exactly right. Also, the stock nginx cores have various limitations and long standing bugs that can make some of this modules' features become disabled, not work properly, or run slower. The same applies to LuaJIT as well. OpenResty includes its own version of LuaJIT which gets specifically optimized and enhanced for the OpenResty environment. Alternatively, ngx_lua can be manually compiled into Nginx: -1. LuaJIT can be downloaded from the [latest release of OpenResty's LuaJIT branch version](https://github.com/openresty/luajit2/releases). The official LuaJIT 2.0 and 2.1 releases are also supported, although the performance will be significantly lower in many cases. +1. Install LuaJIT 2.0 or 2.1 (recommended) or Lua 5.1 (Lua 5.2 is *not* supported yet). LuaJIT can be downloaded from the [LuaJIT project website](http://luajit.org/download.html) and Lua 5.1, from the [Lua project website](http://www.lua.org/). Some distribution package managers also distribute LuaJIT and/or Lua. 1. Download the latest version of the ngx_devel_kit (NDK) module [HERE](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 version of Nginx [HERE](http://nginx.org/) (See [Nginx Compatibility](#nginx-compatibility)) @@ -348,6 +345,29 @@ To enable one or more of these macros, just pass extra C compiler options to the ./configure --with-cc-opt="-DNGX_LUA_USE_ASSERT -DNGX_LUA_ABORT_AT_PANIC" +[Back to TOC](#table-of-contents) + +Installation on Ubuntu 11.10 +---------------------------- + +Note that it is recommended to use LuaJIT 2.0 or LuaJIT 2.1 instead of the standard Lua 5.1 interpreter wherever possible. + +If the standard Lua 5.1 interpreter is required however, run the following command to install it from the Ubuntu repository: + +```bash + + apt-get install -y lua5.1 liblua5.1-0 liblua5.1-0-dev +``` + +Everything should be installed correctly, except for one small tweak. + +Library name `liblua.so` has been changed in liblua5.1 package, it only comes with `liblua5.1.so`, which needs to be symlinked to `/usr/lib` so it could be found during the configuration process. + +```bash + + ln -s /usr/lib/x86_64-linux-gnu/liblua5.1.so /usr/lib/liblua.so +``` + [Back to TOC](#table-of-contents) Community @@ -391,7 +411,7 @@ Lua/LuaJIT bytecode support As from the `v0.5.0rc32` release, all `*_by_lua_file` configure directives (such as [content_by_lua_file](#content_by_lua_file)) support loading Lua 5.1 and LuaJIT 2.0/2.1 raw bytecode files directly. -Please note that the bytecode format used by LuaJIT 2.0/2.1 is not compatible with that used by the standard Lua 5.1 interpreter. So if you are using LuaJIT 2.0/2.1 with ngx_lua, LuaJIT compatible bytecode files must be generated as shown: +Please note that the bytecode format used by LuaJIT 2.0/2.1 is not compatible with that used by the standard Lua 5.1 interpreter. So if using LuaJIT 2.0/2.1 with ngx_lua, LuaJIT compatible bytecode files must be generated as shown: ```bash @@ -411,6 +431,20 @@ Please refer to the official LuaJIT documentation on the `-b` option for more de Also, the bytecode files generated by LuaJIT 2.1 is *not* compatible with LuaJIT 2.0, and vice versa. The support for LuaJIT 2.1 bytecode was first added in ngx_lua v0.9.3. +Similarly, if using the standard Lua 5.1 interpreter with ngx_lua, Lua compatible bytecode files must be generated using the `luac` commandline utility as shown: + +```bash + + luac -o /path/to/output_file.luac /path/to/input_file.lua +``` + +Unlike as with LuaJIT, debug information is included in standard Lua 5.1 bytecode files by default. This can be striped out by specifying the `-s` option as shown: + +```bash + + luac -s -o /path/to/output_file.luac /path/to/input_file.lua +``` + Attempts to load standard Lua 5.1 bytecode files into ngx_lua instances linked to LuaJIT 2.0/2.1 or vice versa, will result in an error message, such as that below, being logged into the Nginx `error.log` file: @@ -608,7 +642,8 @@ This issue is due to limitations in the Nginx event model and only appears to af Lua Coroutine Yielding/Resuming ------------------------------- -* Because Lua's `dofile` and `require` builtins are currently implemented as C functions in LuaJIT 2.0/2.1, if the Lua file being loaded by `dofile` or `require` invokes [ngx.location.capture*](#ngxlocationcapture), [ngx.exec](#ngxexec), [ngx.exit](#ngxexit), or other API functions requiring yielding in the *top-level* scope of the Lua file, then the Lua error "attempt to yield across C-call boundary" will be raised. To avoid this, put these calls requiring yielding into your own Lua functions in the Lua file instead of the top-level scope of the file. +* Because Lua's `dofile` and `require` builtins are currently implemented as C functions in both Lua 5.1 and LuaJIT 2.0/2.1, if the Lua file being loaded by `dofile` or `require` invokes [ngx.location.capture*](#ngxlocationcapture), [ngx.exec](#ngxexec), [ngx.exit](#ngxexit), or other API functions requiring yielding in the *top-level* scope of the Lua file, then the Lua error "attempt to yield across C-call boundary" will be raised. To avoid this, put these calls requiring yielding into your own Lua functions in the Lua file instead of the top-level scope of the file. +* As the standard Lua 5.1 interpreter's VM is not fully resumable, the methods [ngx.location.capture](#ngxlocationcapture), [ngx.location.capture_multi](#ngxlocationcapture_multi), [ngx.redirect](#ngxredirect), [ngx.exec](#ngxexec), and [ngx.exit](#ngxexit) cannot be used within the context of a Lua [pcall()](http://www.lua.org/manual/5.1/manual.html#pdf-pcall) or [xpcall()](http://www.lua.org/manual/5.1/manual.html#pdf-xpcall) or even the first line of the `for ... in ...` statement when the standard Lua 5.1 interpreter is used and the `attempt to yield across metamethod/C-call boundary` error will be produced. Please use LuaJIT 2.x, which supports a fully resumable VM, to avoid this. [Back to TOC](#table-of-contents) @@ -960,7 +995,7 @@ This module is licensed under the BSD license. Copyright (C) 2009-2017, by Xiaozhe Wang (chaoslawful) . -Copyright (C) 2009-2019, by Yichun "agentzh" Zhang (章亦春) , OpenResty Inc. +Copyright (C) 2009-2018, by Yichun "agentzh" Zhang (章亦春) , OpenResty Inc. All rights reserved. @@ -1004,7 +1039,6 @@ See Also Directives ========== -* [lua_load_resty_core](#lua_load_resty_core) * [lua_capture_error_log](#lua_capture_error_log) * [lua_use_default_type](#lua_use_default_type) * [lua_malloc_trim](#lua_malloc_trim) @@ -1070,7 +1104,6 @@ Directives * [lua_check_client_abort](#lua_check_client_abort) * [lua_max_pending_timers](#lua_max_pending_timers) * [lua_max_running_timers](#lua_max_running_timers) -* [lua_sa_restart](#lua_sa_restart) The basic building blocks of scripting Nginx with Lua are directives. Directives are used to specify when the user Lua code is run and @@ -1080,38 +1113,6 @@ how the result will be used. Below is a diagram showing the order in which direc [Back to TOC](#table-of-contents) -lua_load_resty_core -------------------- - -**syntax:** *lua_load_resty_core on|off* - -**default:** *lua_load_resty_core on* - -**context:** *http* - -Controls whether the `resty.core` module (from -[lua-resty-core](https://github.com/openresty/lua-resty-core)) should be loaded -or not. When enabled, this directive is equivalent to executing the following -when the Lua VM is created: - -```lua - - require "resty.core" -``` - -Note that usage of the `resty.core` module is recommended, as its -FFI implementation is both faster, safer, and more complete than the Lua C API -of the ngx_lua module. - -It must also be noted that the Lua C API of the ngx_lua module will eventually -be removed, and usage of the FFI-based API (i.e. the `resty.core` -module) will become mandatory. This directive only aims at providing a -temporary backwards-compatibility mode in case of edge-cases. - -This directive was first introduced in the `v0.10.15` release. - -[Back to TOC](#directives) - lua_capture_error_log --------------------- **syntax:** *lua_capture_error_log size* @@ -2601,14 +2602,14 @@ SSL session resumption can then get immediately initiated and bypass the full SS Please note that TLS session tickets are very different and it is the clients' responsibility to cache the SSL session state when session tickets are used. SSL session resumptions based on TLS session tickets would happen automatically without going through this hook (nor the -[ssl_session_store_by_lua*](#ssl_session_store_by_lua_block) hook). This hook is mainly +[ssl_session_store_by_lua_block](#ssl_session_store_by_lua) hook). This hook is mainly for older or less capable SSL clients that can only do SSL sessions by session IDs. When [ssl_certificate_by_lua*](#ssl_certificate_by_lua_block) is specified at the same time, this hook usually runs before [ssl_certificate_by_lua*](#ssl_certificate_by_lua_block). When the SSL session is found and successfully loaded for the current SSL connection, SSL session resumption will happen and thus bypass the [ssl_certificate_by_lua*](#ssl_certificate_by_lua_block) -hook completely. In this case, NGINX also bypasses the [ssl_session_store_by_lua*](#ssl_session_store_by_lua_block) +hook completely. In this case, NGINX also bypasses the [ssl_session_store_by_lua_block](#ssl_session_store_by_lua) hook, for obvious reasons. To easily test this hook locally with a modern web browser, you can temporarily put the following line @@ -3107,23 +3108,6 @@ This directive was first introduced in the `v0.8.0` release. [Back to TOC](#directives) -lua_sa_restart --------------- - -**syntax:** *lua_sa_restart on|off* - -**default:** *lua_sa_restart on* - -**context:** *http* - -When enabled, this module will set the `SA_RESTART` flag on nginx workers signal dispositions. - -This allows Lua I/O primitives to not be interrupted by nginx's handling of various signals. - -This directive was first introduced in the `v0.10.14` release. - -[Back to TOC](#directives) - Nginx API for Lua ================= @@ -3237,7 +3221,6 @@ Nginx API for Lua * [tcpsock:sslhandshake](#tcpsocksslhandshake) * [tcpsock:send](#tcpsocksend) * [tcpsock:receive](#tcpsockreceive) -* [tcpsock:receiveany](#tcpsockreceiveany) * [tcpsock:receiveuntil](#tcpsockreceiveuntil) * [tcpsock:close](#tcpsockclose) * [tcpsock:settimeout](#tcpsocksettimeout) @@ -4319,7 +4302,7 @@ ngx.req.get_method ------------------ **syntax:** *method_name = ngx.req.get_method()* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, balancer_by_lua*, log_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, balancer_by_lua** Retrieves the current request's request method name. Strings like `"GET"` and `"POST"` are returned instead of numerical [method constants](#http-method-constants). @@ -4904,7 +4887,7 @@ This function returns `nil` if 1. the request body has been read into disk temporary files, 1. or the request body has zero size. -If the request body has not been read yet, call [ngx.req.read_body](#ngxreqread_body) first (or turn on [lua_need_request_body](#lua_need_request_body) to force this module to read the request body. This is not recommended however). +If the request body has not been read yet, call [ngx.req.read_body](#ngxreqread_body) first (or turned on [lua_need_request_body](#lua_need_request_body) to force this module to read the request body. This is not recommended however). If the request body has been read into disk files, try calling the [ngx.req.get_body_file](#ngxreqget_body_file) function instead. @@ -4928,7 +4911,7 @@ Retrieves the file name for the in-file request body data. Returns `nil` if the The returned file is read only and is usually cleaned up by Nginx's memory pool. It should not be manually modified, renamed, or removed in Lua code. -If the request body has not been read yet, call [ngx.req.read_body](#ngxreqread_body) first (or turn on [lua_need_request_body](#lua_need_request_body) to force this module to read the request body. This is not recommended however). +If the request body has not been read yet, call [ngx.req.read_body](#ngxreqread_body) first (or turned on [lua_need_request_body](#lua_need_request_body) to force this module to read the request body. This is not recommended however). If the request body has been read into memory, try calling the [ngx.req.get_body_data](#ngxreqget_body_data) function instead. @@ -4948,9 +4931,7 @@ ngx.req.set_body_data Set the current request's request body using the in-memory data specified by the `data` argument. -If the request body has not been read yet, call [ngx.req.read_body](#ngxreqread_body) first (or turn on [lua_need_request_body](#lua_need_request_body) to force this module to read the request body. This is not recommended however). Additionally, the request body must not have been previously discarded by [ngx.req.discard_body](#ngxreqdiscard_body). - -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. +If the current request's request body has not been read, then it will be properly discarded. When the current request's request body has been read into memory or buffered into a disk file, then the old request body's memory will be freed or the disk file will be cleaned up immediately, respectively. This function was first introduced in the `v0.3.1rc18` release. @@ -4966,13 +4947,11 @@ ngx.req.set_body_file Set the current request's request body using the in-file data specified by the `file_name` argument. -If the request body has not been read yet, call [ngx.req.read_body](#ngxreqread_body) first (or turn on [lua_need_request_body](#lua_need_request_body) to force this module to read the request body. This is not recommended however). Additionally, the request body must not have been previously discarded by [ngx.req.discard_body](#ngxreqdiscard_body). - If the optional `auto_clean` argument is given a `true` value, then this file will be removed at request completion or the next time this function or [ngx.req.set_body_data](#ngxreqset_body_data) are called in the same request. The `auto_clean` is default to `false`. Please ensure that the file specified by the `file_name` argument exists and is readable by an Nginx worker process by setting its permission properly to avoid Lua exception errors. -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. +If the current request's request body has not been read, then it will be properly discarded. When the current request's request body has been read into memory or buffered into a disk file, then the old request body's memory will be freed or the disk file will be cleaned up immediately, respectively. This function was first introduced in the `v0.3.1rc18` release. @@ -6738,7 +6717,7 @@ ngx.shared.DICT.flush_expired Flushes out the expired items in the dictionary, up to the maximal number specified by the optional `max_count` argument. When the `max_count` argument is given `0` or not given at all, then it means unlimited. Returns the number of items that have actually been flushed. -Unlike the [flush_all](#ngxshareddictflush_all) method, this method actually frees up the memory used by the expired items. +Unlike the [flush_all](#ngxshareddictflush_all) method, this method actually free up the memory used by the expired items. This feature was first introduced in the `v0.6.3` release. @@ -7023,7 +7002,6 @@ Creates and returns a TCP or stream-oriented unix domain socket object (also kno * [settimeout](#tcpsocksettimeout) * [settimeouts](#tcpsocksettimeouts) * [setoption](#tcpsocksetoption) -* [receiveany](#tcpsockreceiveany) * [receiveuntil](#tcpsockreceiveuntil) * [setkeepalive](#tcpsocksetkeepalive) * [getreusedtimes](#tcpsockgetreusedtimes) @@ -7128,43 +7106,6 @@ An optional Lua table can be specified as the last argument to this method to sp * `pool` specify a custom name for the connection pool being used. If omitted, then the connection pool name will be generated from the string template `":"` or `""`. -* `pool_size` - specify the size of the connection pool. If omitted and no - `backlog` option was provided, no pool will be created. If omitted - but `backlog` was provided, the pool will be created with a default - size equal to the value of the [lua_socket_pool_size](#lua_socket_pool_size) - directive. - The connection pool holds up to `pool_size` alive connections - ready to be reused by subsequent calls to [connect](#tcpsockconnect), but - note that there is no upper limit to the total number of opened connections - outside of the pool. If you need to restrict the total number of opened - connections, specify the `backlog` option. - When the connection pool would exceed its size limit, the least recently used - (kept-alive) connection already in the pool will be closed to make room for - the current connection. - Note that the cosocket connection pool is per Nginx worker process rather - than per Nginx server instance, so the size limit specified here also applies - to every single Nginx worker process. Also note that the size of the connection - pool cannot be changed once it has been created. - This option was first introduced in the `v0.10.14` release. - -* `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). - 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 operation will abort once they have been queued for more - than `connect_timeout`, controlled by - [settimeouts](#tcpsocksettimeouts), and will return `nil` plus - the error string `"timeout"`. - This option was first introduced in the `v0.10.14` release. - The support for the options table argument was first introduced in the `v0.5.7` release. This method was first introduced in the `v0.5.0rc1` release. @@ -7290,40 +7231,6 @@ This feature was first introduced in the `v0.5.0rc1` release. [Back to TOC](#nginx-api-for-lua) -tcpsock:receiveany ------------------- -**syntax:** *data, err = tcpsock:receiveany(max)* - -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua** - -Returns any data received by the connected socket, at most `max` bytes. - -This method is a synchronous operation just like the [send](#tcpsocksend) method and is 100% nonblocking. - -In case of success, it returns the data received; in case of error, it returns `nil` with a string describing the error. - -If the received data is more than this size, this method will return with exactly this size of data. -The remaining data in the underlying receive buffer could be returned in the next reading operation. - -Timeout for the reading operation is controlled by the [lua_socket_read_timeout](#lua_socket_read_timeout) config directive and the [settimeouts](#tcpsocksettimeouts) method. And the latter takes priority. For example: - -```lua - - sock:settimeouts(1000, 1000, 1000) -- one second timeout for connect/read/write - local data, err = sock:receiveany(10 * 1024 * 1024) -- read any data, at most 10K - if not data then - ngx.say("failed to read any data: ", err) - return - end - ngx.say("successfully read: ", data) -``` - -This method doesn't automatically close the current connection when the read timeout error occurs. For other connection errors, this method always automatically closes the connection. - -This feature was first introduced in the `v0.10.14` release. - -[Back to TOC](#nginx-api-for-lua) - tcpsock:receiveuntil -------------------- **syntax:** *iterator = tcpsock:receiveuntil(pattern, options?)* @@ -7496,31 +7403,13 @@ Puts the current socket's connection immediately into the cosocket built-in conn The first optional argument, `timeout`, can be used to specify the maximal idle timeout (in milliseconds) for the current connection. If omitted, the default setting in the [lua_socket_keepalive_timeout](#lua_socket_keepalive_timeout) config directive will be used. If the `0` value is given, then the timeout interval is unlimited. -The second optional argument `size` is considered deprecated since -the `v0.10.14` release of this module, in favor of the -`pool_size` option of the [connect](#tcpsockconnect) method. -Since the `v0.10.14` release, this option will only take effect if -the call to [connect](#tcpsockconnect) did not already create a connection -pool. -When this option takes effect (no connection pool was previously created by -[connect](#tcpsockconnect)), it will specify the size of the connection pool, -and create it. -If omitted (and no pool was previously created), the default size is the value -of the [lua_socket_pool_size](#lua_socket_pool_size) directive. -The connection pool holds up to `size` alive connections ready to be -reused by subsequent calls to [connect](#tcpsockconnect), but note that there -is no upper limit to the total number of opened connections outside of the -pool. -When the connection pool would exceed its size limit, the least recently used -(kept-alive) connection already in the pool will be closed to make room for -the current connection. -Note that the cosocket connection pool is per Nginx worker process rather -than per Nginx server instance, so the size limit specified here also applies -to every single Nginx worker process. Also note that the size of the connection -pool cannot be changed once it has been created. -If you need to restrict the total number of opened connections, specify both -the `pool_size` and `backlog` option in the call to -[connect](#tcpsockconnect). +The second optional argument, `size`, can be used to specify the maximal number of connections allowed in the connection pool for the current server (i.e., the current host-port pair or the unix domain socket file path). Note that the size of the connection pool cannot be changed once the pool is created. When this argument is omitted, the default setting in the [lua_socket_pool_size](#lua_socket_pool_size) config directive will be used. + +When the connection pool exceeds the available size limit, the least recently used (idle) connection already in the pool will be closed to make room for the current connection. + +Note that the cosocket connection pool is per Nginx worker process rather than per Nginx server instance, so the size limit specified here also applies to every single Nginx worker process. + +Idle connections in the pool will be monitored for any exceptional events like connection abortion or unexpected incoming data on the line, in which cases the connection in question will be closed and removed from the pool. In case of success, this method returns `1`; otherwise, it returns `nil` and a string describing the error. @@ -8292,7 +8181,7 @@ This Lua module does not ship with this ngx_lua module itself rather it is shipp the [lua-resty-core](https://github.com/openresty/lua-resty-core) library. -Please refer to the [documentation](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ocsp.md) +Please refer to the [documentation](https://github.com/openresty/lua-resty-core/blob/ocsp-cert-by-lua-2/lib/ngx/ocsp.md) for this `ngx.ocsp` Lua module for more details. This feature requires at least ngx_lua `v0.10.0`. diff --git a/debian/modules/http-lua/config b/debian/modules/http-lua/config index e1d5e35..044deb9 100644 --- a/debian/modules/http-lua/config +++ b/debian/modules/http-lua/config @@ -361,8 +361,6 @@ HTTP_LUA_SRCS=" \ $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_log_ringbuf.c \ - $ngx_addon_dir/src/ngx_http_lua_input_filters.c \ - $ngx_addon_dir/src/ngx_http_lua_pipe.c \ " HTTP_LUA_DEPS=" \ @@ -424,8 +422,6 @@ HTTP_LUA_DEPS=" \ $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_log_ringbuf.h \ - $ngx_addon_dir/src/ngx_http_lua_input_filters.h \ - $ngx_addon_dir/src/ngx_http_lua_pipe.h \ " CFLAGS="$CFLAGS -DNDK_SET_VAR" @@ -478,17 +474,6 @@ ngx_feature_test='setsockopt(1, SOL_SOCKET, SO_PASSCRED, NULL, 0);' . auto/feature -ngx_feature="SA_RESTART" -ngx_feature_libs= -ngx_feature_name="NGX_HTTP_LUA_HAVE_SA_RESTART" -ngx_feature_run=no -ngx_feature_incs="#include " -ngx_feature_path= -ngx_feature_test='struct sigaction act; - act.sa_flags |= SA_RESTART;' - -. auto/feature - ngx_feature="__attribute__(constructor)" ngx_feature_libs= ngx_feature_name="NGX_HTTP_LUA_HAVE_CONSTRUCTOR" @@ -527,36 +512,6 @@ CC_TEST_FLAGS="$SAVED_CC_TEST_FLAGS" # ---------------------------------------- -ngx_feature="pipe2" -ngx_feature_libs= -ngx_feature_name="NGX_HTTP_LUA_HAVE_PIPE2" -ngx_feature_run=no -ngx_feature_incs="#include " -ngx_feature_test="int fd[2]; pipe2(fd, O_CLOEXEC|O_NONBLOCK);" -SAVED_CC_TEST_FLAGS="$CC_TEST_FLAGS" -CC_TEST_FLAGS="-Werror -Wall $CC_TEST_FLAGS" - -. auto/feature - -CC_TEST_FLAGS="$SAVED_CC_TEST_FLAGS" - -# ---------------------------------------- - -ngx_feature="signalfd" -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);" -SAVED_CC_TEST_FLAGS="$CC_TEST_FLAGS" -CC_TEST_FLAGS="-Werror -Wall $CC_TEST_FLAGS" - -. auto/feature - -CC_TEST_FLAGS="$SAVED_CC_TEST_FLAGS" - -# ---------------------------------------- - if test -n "$ngx_module_link"; then ngx_module_type=HTTP_AUX_FILTER ngx_module_name=$ngx_addon_name diff --git a/debian/modules/http-lua/doc/HttpLuaModule.wiki b/debian/modules/http-lua/doc/HttpLuaModule.wiki index ff9b269..e3c61e2 100644 --- a/debian/modules/http-lua/doc/HttpLuaModule.wiki +++ b/debian/modules/http-lua/doc/HttpLuaModule.wiki @@ -2,8 +2,6 @@ ngx_http_lua_module - Embed the power of Lua into Nginx HTTP Servers. -This module is a core component of OpenResty. If you are using this module, then you are essentially using OpenResty :) - ''This module is not distributed with the Nginx source.'' See [[#Installation|the installation instructions]]. = Status = @@ -12,7 +10,7 @@ Production ready. = Version = -This document describes ngx_lua [https://github.com/openresty/lua-nginx-module/tags v0.10.15] released on March 14th, 2019. +This document describes ngx_lua [https://github.com/openresty/lua-nginx-module/tags v0.10.13] released on 22 April 2018. = Synopsis = @@ -132,9 +130,7 @@ This document describes ngx_lua [https://github.com/openresty/lua-nginx-module/t = Description = -This module is a core component of OpenResty. If you are using this module, then you are essentially using OpenResty :) - -This module embeds Lua, via [http://luajit.org/luajit.html LuaJIT 2.0/2.1], into Nginx and by leveraging Nginx's subrequests, allows the integration of the powerful Lua threads (Lua coroutines) into the Nginx event model. +This module embeds Lua, via the standard Lua 5.1 interpreter or [http://luajit.org/luajit.html LuaJIT 2.0/2.1], into Nginx and by leveraging Nginx's subrequests, allows the integration of the powerful Lua threads (Lua coroutines) into the Nginx event model. Unlike [https://httpd.apache.org/docs/trunk/mod/mod_lua.html Apache's mod_lua] and [http://redmine.lighttpd.net/wiki/1/Docs:ModMagnet Lighttpd's mod_magnet], Lua code executed using this module can be ''100% non-blocking'' on network traffic as long as the [[#Nginx API for Lua|Nginx API for Lua]] provided by this module is used to handle requests to upstream services such as MySQL, PostgreSQL, Memcached, Redis, or upstream HTTP web services. @@ -203,11 +199,11 @@ Nginx cores older than 1.6.0 (exclusive) are *not* supported. = Installation = -It is *highly* recommended to use [http://openresty.org OpenResty releases] which integrate Nginx, ngx_lua, OpenResty's LuaJIT 2.1 branch version, as well as other powerful companion Nginx modules and Lua libraries. It is discouraged to build this module with nginx yourself since it is tricky to set up exactly right. Also, the stock nginx cores have various limitations and long standing bugs that can make some of this modules' features become disabled, not work properly, or run slower. The same applies to LuaJIT as well. OpenResty includes its own version of LuaJIT which gets specifically optimized and enhanced for the OpenResty environment. +It is *highly* recommended to use [http://openresty.org OpenResty releases] which integrate Nginx, ngx_lua, LuaJIT 2.1, as well as other powerful companion Nginx modules and Lua libraries. It is discouraged to build this module with nginx yourself since it is tricky to set up exactly right. Also, the stock nginx cores have various limitations and long standing bugs that can make some of this modules' features become disabled, not work properly, or run slower. The same applies to LuaJIT as well. OpenResty includes its own version of LuaJIT which gets specifically optimized and enhanced for the OpenResty environment. Alternatively, ngx_lua can be manually compiled into Nginx: -# LuaJIT can be downloaded from the [https://github.com/openresty/luajit2/releases latest release of OpenResty's LuaJIT branch version]. The official LuaJIT 2.0 and 2.1 releases are also supported, although the performance will be significantly lower in many cases. +# Install LuaJIT 2.0 or 2.1 (recommended) or Lua 5.1 (Lua 5.2 is ''not'' supported yet). LuaJIT can be downloaded from the [http://luajit.org/download.html LuaJIT project website] and Lua 5.1, from the [http://www.lua.org/ Lua project website]. Some distribution package managers also distribute LuaJIT and/or Lua. # Download the latest version of the ngx_devel_kit (NDK) module [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 version of Nginx [http://nginx.org/ HERE] (See [[#Nginx Compatibility|Nginx Compatibility]]) @@ -275,6 +271,24 @@ To enable one or more of these macros, just pass extra C compiler options to the ./configure --with-cc-opt="-DNGX_LUA_USE_ASSERT -DNGX_LUA_ABORT_AT_PANIC" +== Installation on Ubuntu 11.10 == + +Note that it is recommended to use LuaJIT 2.0 or LuaJIT 2.1 instead of the standard Lua 5.1 interpreter wherever possible. + +If the standard Lua 5.1 interpreter is required however, run the following command to install it from the Ubuntu repository: + + +apt-get install -y lua5.1 liblua5.1-0 liblua5.1-0-dev + + +Everything should be installed correctly, except for one small tweak. + +Library name liblua.so has been changed in liblua5.1 package, it only comes with liblua5.1.so, which needs to be symlinked to /usr/lib so it could be found during the configuration process. + + +ln -s /usr/lib/x86_64-linux-gnu/liblua5.1.so /usr/lib/liblua.so + + = Community = == English Mailing List == @@ -300,7 +314,7 @@ Please submit bug reports, wishlists, or patches by As from the v0.5.0rc32 release, all *_by_lua_file configure directives (such as [[#content_by_lua_file|content_by_lua_file]]) support loading Lua 5.1 and LuaJIT 2.0/2.1 raw bytecode files directly. -Please note that the bytecode format used by LuaJIT 2.0/2.1 is not compatible with that used by the standard Lua 5.1 interpreter. So if you are using LuaJIT 2.0/2.1 with ngx_lua, LuaJIT compatible bytecode files must be generated as shown: +Please note that the bytecode format used by LuaJIT 2.0/2.1 is not compatible with that used by the standard Lua 5.1 interpreter. So if using LuaJIT 2.0/2.1 with ngx_lua, LuaJIT compatible bytecode files must be generated as shown: /path/to/luajit/bin/luajit -b /path/to/input_file.lua /path/to/output_file.ljbc @@ -318,6 +332,18 @@ http://luajit.org/running.html#opt_b Also, the bytecode files generated by LuaJIT 2.1 is ''not'' compatible with LuaJIT 2.0, and vice versa. The support for LuaJIT 2.1 bytecode was first added in ngx_lua v0.9.3. +Similarly, if using the standard Lua 5.1 interpreter with ngx_lua, Lua compatible bytecode files must be generated using the luac commandline utility as shown: + + + luac -o /path/to/output_file.luac /path/to/input_file.lua + + +Unlike as with LuaJIT, debug information is included in standard Lua 5.1 bytecode files by default. This can be striped out by specifying the -s option as shown: + + + luac -s -o /path/to/output_file.luac /path/to/input_file.lua + + Attempts to load standard Lua 5.1 bytecode files into ngx_lua instances linked to LuaJIT 2.0/2.1 or vice versa, will result in an error message, such as that below, being logged into the Nginx error.log file: @@ -484,7 +510,8 @@ However, later attempts to manipulate the cosocket object will fail and return t This issue is due to limitations in the Nginx event model and only appears to affect Mac OS X. == Lua Coroutine Yielding/Resuming == -* Because Lua's dofile and require builtins are currently implemented as C functions in LuaJIT 2.0/2.1, if the Lua file being loaded by dofile or require invokes [[#ngx.location.capture|ngx.location.capture*]], [[#ngx.exec|ngx.exec]], [[#ngx.exit|ngx.exit]], or other API functions requiring yielding in the *top-level* scope of the Lua file, then the Lua error "attempt to yield across C-call boundary" will be raised. To avoid this, put these calls requiring yielding into your own Lua functions in the Lua file instead of the top-level scope of the file. +* Because Lua's dofile and require builtins are currently implemented as C functions in both Lua 5.1 and LuaJIT 2.0/2.1, if the Lua file being loaded by dofile or require invokes [[#ngx.location.capture|ngx.location.capture*]], [[#ngx.exec|ngx.exec]], [[#ngx.exit|ngx.exit]], or other API functions requiring yielding in the *top-level* scope of the Lua file, then the Lua error "attempt to yield across C-call boundary" will be raised. To avoid this, put these calls requiring yielding into your own Lua functions in the Lua file instead of the top-level scope of the file. +* As the standard Lua 5.1 interpreter's VM is not fully resumable, the methods [[#ngx.location.capture|ngx.location.capture]], [[#ngx.location.capture_multi|ngx.location.capture_multi]], [[#ngx.redirect|ngx.redirect]], [[#ngx.exec|ngx.exec]], and [[#ngx.exit|ngx.exit]] cannot be used within the context of a Lua [http://www.lua.org/manual/5.1/manual.html#pdf-pcall pcall()] or [http://www.lua.org/manual/5.1/manual.html#pdf-xpcall xpcall()] or even the first line of the for ... in ... statement when the standard Lua 5.1 interpreter is used and the attempt to yield across metamethod/C-call boundary error will be produced. Please use LuaJIT 2.x, which supports a fully resumable VM, to avoid this. == Lua Variable Scope == Care must be taken when importing modules and this form should be used: @@ -790,7 +817,7 @@ This module is licensed under the BSD license. Copyright (C) 2009-2017, by Xiaozhe Wang (chaoslawful) . -Copyright (C) 2009-2019, by Yichun "agentzh" Zhang (章亦春) , OpenResty Inc. +Copyright (C) 2009-2018, by Yichun "agentzh" Zhang (章亦春) , OpenResty Inc. All rights reserved. @@ -835,34 +862,6 @@ how the result will be used. Below is a diagram showing the order in which direc ![Lua Nginx Modules Directives](https://cloud.githubusercontent.com/assets/2137369/15272097/77d1c09e-1a37-11e6-97ef-d9767035fc3e.png) -== lua_load_resty_core == - -'''syntax:''' ''lua_load_resty_core on|off'' - -'''default:''' ''lua_load_resty_core on'' - -'''context:''' ''http'' - -Controls whether the resty.core module (from -[https://github.com/openresty/lua-resty-core lua-resty-core]) should be loaded -or not. When enabled, this directive is equivalent to executing the following -when the Lua VM is created: - - - require "resty.core" - - -Note that usage of the resty.core module is recommended, as its -FFI implementation is both faster, safer, and more complete than the Lua C API -of the ngx_lua module. - -It must also be noted that the Lua C API of the ngx_lua module will eventually -be removed, and usage of the FFI-based API (i.e. the resty.core -module) will become mandatory. This directive only aims at providing a -temporary backwards-compatibility mode in case of edge-cases. - -This directive was first introduced in the v0.10.15 release. - == lua_capture_error_log == '''syntax:''' ''lua_capture_error_log size'' @@ -2197,14 +2196,14 @@ SSL session resumption can then get immediately initiated and bypass the full SS Please note that TLS session tickets are very different and it is the clients' responsibility to cache the SSL session state when session tickets are used. SSL session resumptions based on TLS session tickets would happen automatically without going through this hook (nor the -[[#ssl_session_store_by_lua_block|ssl_session_store_by_lua*]] hook). This hook is mainly +[[#ssl_session_store_by_lua*|ssl_session_store_by_lua_block]] hook). This hook is mainly for older or less capable SSL clients that can only do SSL sessions by session IDs. When [[#ssl_certificate_by_lua_block|ssl_certificate_by_lua*]] is specified at the same time, this hook usually runs before [[#ssl_certificate_by_lua_block|ssl_certificate_by_lua*]]. When the SSL session is found and successfully loaded for the current SSL connection, SSL session resumption will happen and thus bypass the [[#ssl_certificate_by_lua_block|ssl_certificate_by_lua*]] -hook completely. In this case, NGINX also bypasses the [[#ssl_session_store_by_lua_block|ssl_session_store_by_lua*]] +hook completely. In this case, NGINX also bypasses the [[#ssl_session_store_by_lua*|ssl_session_store_by_lua_block]] hook, for obvious reasons. To easily test this hook locally with a modern web browser, you can temporarily put the following line @@ -2627,20 +2626,6 @@ When exceeding this limit, Nginx will stop running the callbacks of newly expire This directive was first introduced in the v0.8.0 release. -== lua_sa_restart == - -'''syntax:''' ''lua_sa_restart on|off'' - -'''default:''' ''lua_sa_restart on'' - -'''context:''' ''http'' - -When enabled, this module will set the `SA_RESTART` flag on nginx workers signal dispositions. - -This allows Lua I/O primitives to not be interrupted by nginx's handling of various signals. - -This directive was first introduced in the v0.10.14 release. - = Nginx API for Lua = @@ -3578,7 +3563,7 @@ This method does not work in HTTP/2 requests yet. == ngx.req.get_method == '''syntax:''' ''method_name = ngx.req.get_method()'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, balancer_by_lua*, log_by_lua*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, balancer_by_lua*'' Retrieves the current request's request method name. Strings like "GET" and "POST" are returned instead of numerical [[#HTTP method constants|method constants]]. @@ -4086,7 +4071,7 @@ This function returns nil if # the request body has been read into disk temporary files, # or the request body has zero size. -If the request body has not been read yet, call [[#ngx.req.read_body|ngx.req.read_body]] first (or turn on [[#lua_need_request_body|lua_need_request_body]] to force this module to read the request body. This is not recommended however). +If the request body has not been read yet, call [[#ngx.req.read_body|ngx.req.read_body]] first (or turned on [[#lua_need_request_body|lua_need_request_body]] to force this module to read the request body. This is not recommended however). If the request body has been read into disk files, try calling the [[#ngx.req.get_body_file|ngx.req.get_body_file]] function instead. @@ -4107,7 +4092,7 @@ Retrieves the file name for the in-file request body data. Returns nildata argument. -If the request body has not been read yet, call [[#ngx.req.read_body|ngx.req.read_body]] first (or turn on [[#lua_need_request_body|lua_need_request_body]] to force this module to read the request body. This is not recommended however). Additionally, the request body must not have been previously discarded by [[#ngx.req.discard_body|ngx.req.discard_body]]. - -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. +If the current request's request body has not been read, then it will be properly discarded. When the current request's request body has been read into memory or buffered into a disk file, then the old request body's memory will be freed or the disk file will be cleaned up immediately, respectively. This function was first introduced in the v0.3.1rc18 release. @@ -4139,13 +4122,11 @@ See also [[#ngx.req.set_body_file|ngx.req.set_body_file]]. Set the current request's request body using the in-file data specified by the file_name argument. -If the request body has not been read yet, call [[#ngx.req.read_body|ngx.req.read_body]] first (or turn on [[#lua_need_request_body|lua_need_request_body]] to force this module to read the request body. This is not recommended however). Additionally, the request body must not have been previously discarded by [[#ngx.req.discard_body|ngx.req.discard_body]]. - If the optional auto_clean argument is given a true value, then this file will be removed at request completion or the next time this function or [[#ngx.req.set_body_data|ngx.req.set_body_data]] are called in the same request. The auto_clean is default to false. Please ensure that the file specified by the file_name argument exists and is readable by an Nginx worker process by setting its permission properly to avoid Lua exception errors. -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. +If the current request's request body has not been read, then it will be properly discarded. When the current request's request body has been read into memory or buffered into a disk file, then the old request body's memory will be freed or the disk file will be cleaned up immediately, respectively. This function was first introduced in the v0.3.1rc18 release. @@ -5667,7 +5648,7 @@ See also [[#ngx.shared.DICT.flush_expired|ngx.shared.DICT.flush_expired]] and [[ Flushes out the expired items in the dictionary, up to the maximal number specified by the optional max_count argument. When the max_count argument is given 0 or not given at all, then it means unlimited. Returns the number of items that have actually been flushed. -Unlike the [[#ngx.shared.DICT.flush_all|flush_all]] method, this method actually frees up the memory used by the expired items. +Unlike the [[#ngx.shared.DICT.flush_all|flush_all]] method, this method actually free up the memory used by the expired items. This feature was first introduced in the v0.6.3 release. @@ -5913,7 +5894,6 @@ Creates and returns a TCP or stream-oriented unix domain socket object (also kno * [[#tcpsock:settimeout|settimeout]] * [[#tcpsock:settimeouts|settimeouts]] * [[#tcpsock:setoption|setoption]] -* [[#tcpsock:receiveany|receiveany]] * [[#tcpsock:receiveuntil|receiveuntil]] * [[#tcpsock:setkeepalive|setkeepalive]] * [[#tcpsock:getreusedtimes|getreusedtimes]] @@ -6011,43 +5991,6 @@ An optional Lua table can be specified as the last argument to this method to sp * pool : specify a custom name for the connection pool being used. If omitted, then the connection pool name will be generated from the string template ":" or "". -* pool_size -: specify the size of the connection pool. If omitted and no -: backlog option was provided, no pool will be created. If omitted -: but backlog was provided, the pool will be created with a default -: size equal to the value of the [[#lua_socket_pool_size|lua_socket_pool_size]] -: directive. -: The connection pool holds up to pool_size alive connections -: ready to be reused by subsequent calls to [[#tcpsock:connect|connect]], but -: note that there is no upper limit to the total number of opened connections -: outside of the pool. If you need to restrict the total number of opened -: connections, specify the backlog option. -: When the connection pool would exceed its size limit, the least recently used -: (kept-alive) connection already in the pool will be closed to make room for -: the current connection. -: Note that the cosocket connection pool is per Nginx worker process rather -: than per Nginx server instance, so the size limit specified here also applies -: to every single Nginx worker process. Also note that the size of the connection -: pool cannot be changed once it has been created. -: This option was first introduced in the v0.10.14 release. - -* 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). -: 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 operation will abort once they have been queued for more -: than connect_timeout, controlled by -: [[#tcpsock:settimeouts|settimeouts]], and will return nil plus -: the error string "timeout". -: This option was first introduced in the v0.10.14 release. - The support for the options table argument was first introduced in the v0.5.7 release. This method was first introduced in the v0.5.0rc1 release. @@ -6160,36 +6103,6 @@ Since the v0.8.8 release, this method no longer automatically close This feature was first introduced in the v0.5.0rc1 release. -== tcpsock:receiveany == -'''syntax:''' ''data, err = tcpsock:receiveany(max)'' - -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*'' - -Returns any data received by the connected socket, at most max bytes. - -This method is a synchronous operation just like the [[#tcpsock:send|send]] method and is 100% nonblocking. - -In case of success, it returns the data received; in case of error, it returns nil with a string describing the error. - -If the received data is more than this size, this method will return with exactly this size of data. -The remaining data in the underlying receive buffer could be returned in the next reading operation. - -Timeout for the reading operation is controlled by the [[#lua_socket_read_timeout|lua_socket_read_timeout]] config directive and the [[#tcpsock:settimeouts|settimeouts]] method. And the latter takes priority. For example: - - - sock:settimeouts(1000, 1000, 1000) -- one second timeout for connect/read/write - local data, err = sock:receiveany(10 * 1024 * 1024) -- read any data, at most 10K - if not data then - ngx.say("failed to read any data: ", err) - return - end - ngx.say("successfully read: ", data) - - -This method doesn't automatically close the current connection when the read timeout error occurs. For other connection errors, this method always automatically closes the connection. - -This feature was first introduced in the v0.10.14 release. - == tcpsock:receiveuntil == '''syntax:''' ''iterator = tcpsock:receiveuntil(pattern, options?)'' @@ -6342,31 +6255,13 @@ Puts the current socket's connection immediately into the cosocket built-in conn The first optional argument, timeout, can be used to specify the maximal idle timeout (in milliseconds) for the current connection. If omitted, the default setting in the [[#lua_socket_keepalive_timeout|lua_socket_keepalive_timeout]] config directive will be used. If the 0 value is given, then the timeout interval is unlimited. -The second optional argument size is considered deprecated since -the v0.10.14 release of this module, in favor of the -pool_size option of the [[#tcpsock:connect|connect]] method. -Since the v0.10.14 release, this option will only take effect if -the call to [[#tcpsock:connect|connect]] did not already create a connection -pool. -When this option takes effect (no connection pool was previously created by -[[#tcpsock:connect|connect]]), it will specify the size of the connection pool, -and create it. -If omitted (and no pool was previously created), the default size is the value -of the [[#lua_socket_pool_size|lua_socket_pool_size]] directive. -The connection pool holds up to size alive connections ready to be -reused by subsequent calls to [[#tcpsock:connect|connect]], but note that there -is no upper limit to the total number of opened connections outside of the -pool. -When the connection pool would exceed its size limit, the least recently used -(kept-alive) connection already in the pool will be closed to make room for -the current connection. -Note that the cosocket connection pool is per Nginx worker process rather -than per Nginx server instance, so the size limit specified here also applies -to every single Nginx worker process. Also note that the size of the connection -pool cannot be changed once it has been created. -If you need to restrict the total number of opened connections, specify both -the pool_size and backlog option in the call to -[[#tcpsock:connect|connect]]. +The second optional argument, size, can be used to specify the maximal number of connections allowed in the connection pool for the current server (i.e., the current host-port pair or the unix domain socket file path). Note that the size of the connection pool cannot be changed once the pool is created. When this argument is omitted, the default setting in the [[#lua_socket_pool_size|lua_socket_pool_size]] config directive will be used. + +When the connection pool exceeds the available size limit, the least recently used (idle) connection already in the pool will be closed to make room for the current connection. + +Note that the cosocket connection pool is per Nginx worker process rather than per Nginx server instance, so the size limit specified here also applies to every single Nginx worker process. + +Idle connections in the pool will be monitored for any exceptional events like connection abortion or unexpected incoming data on the line, in which cases the connection in question will be closed and removed from the pool. In case of success, this method returns 1; otherwise, it returns nil and a string describing the error. @@ -7055,7 +6950,7 @@ This Lua module does not ship with this ngx_lua module itself rather it is shipp the [https://github.com/openresty/lua-resty-core lua-resty-core] library. -Please refer to the [https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ocsp.md documentation] +Please refer to the [https://github.com/openresty/lua-resty-core/blob/ocsp-cert-by-lua-2/lib/ngx/ocsp.md documentation] for this ngx.ocsp Lua module for more details. This feature requires at least ngx_lua v0.10.0. diff --git a/debian/modules/http-lua/src/api/ngx_http_lua_api.h b/debian/modules/http-lua/src/api/ngx_http_lua_api.h index 129eb99..c7c0e6b 100644 --- a/debian/modules/http-lua/src/api/ngx_http_lua_api.h +++ b/debian/modules/http-lua/src/api/ngx_http_lua_api.h @@ -19,7 +19,7 @@ /* Public API for other Nginx modules */ -#define ngx_http_lua_version 10015 +#define ngx_http_lua_version 10013 typedef struct { diff --git a/debian/modules/http-lua/src/ngx_http_lua_accessby.c b/debian/modules/http-lua/src/ngx_http_lua_accessby.c index d3fe294..56bf0fa 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_accessby.c +++ b/debian/modules/http-lua/src/ngx_http_lua_accessby.c @@ -60,7 +60,7 @@ ngx_http_lua_access_handler(ngx_http_request_t *r) #endif if (cur_ph < last_ph) { - dd("swapping the contents of cur_ph and last_ph..."); + dd("swaping the contents of cur_ph and last_ph..."); tmp = *cur_ph; @@ -261,11 +261,9 @@ ngx_http_lua_access_by_chunk(lua_State *L, ngx_http_request_t *r) /* 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); diff --git a/debian/modules/http-lua/src/ngx_http_lua_api.c b/debian/modules/http-lua/src/ngx_http_lua_api.c index ac014f2..7b590e7 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_api.c +++ b/debian/modules/http-lua/src/ngx_http_lua_api.c @@ -195,7 +195,7 @@ ngx_http_lua_shared_memory_init(ngx_shm_zone_t *shm_zone, void *data) lmcf->shm_zones_inited++; if (lmcf->shm_zones_inited == lmcf->shm_zones->nelts - && lmcf->init_handler && !ngx_test_config) + && lmcf->init_handler) { saved_cycle = ngx_cycle; ngx_cycle = ctx->cycle; diff --git a/debian/modules/http-lua/src/ngx_http_lua_balancer.c b/debian/modules/http-lua/src/ngx_http_lua_balancer.c index 3ecd592..fdf2af3 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_balancer.c +++ b/debian/modules/http-lua/src/ngx_http_lua_balancer.c @@ -362,8 +362,6 @@ ngx_http_lua_balancer_by_chunk(lua_State *L, ngx_http_request_t *r) /* init nginx context in Lua VM */ ngx_http_lua_set_req(L, r); - -#ifndef OPENRESTY_LUAJIT ngx_http_lua_create_new_globals_table(L, 0 /* narr */, 1 /* nrec */); /* {{{ make new env inheriting main thread's globals table */ @@ -374,7 +372,6 @@ ngx_http_lua_balancer_by_chunk(lua_State *L, ngx_http_request_t *r) /* }}} */ lua_setfenv(L, -2); /* set new running env for the code closure */ -#endif /* OPENRESTY_LUAJIT */ lua_pushcfunction(L, ngx_http_lua_traceback); lua_insert(L, 1); /* put it under chunk and args */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_bodyfilterby.c b/debian/modules/http-lua/src/ngx_http_lua_bodyfilterby.c index f3af14c..2b3c38f 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_bodyfilterby.c +++ b/debian/modules/http-lua/src/ngx_http_lua_bodyfilterby.c @@ -32,6 +32,10 @@ static void ngx_http_lua_body_filter_by_lua_env(lua_State *L, static ngx_http_output_body_filter_pt ngx_http_next_body_filter; +/* key for the ngx_chain_t *in pointer in the Lua thread */ +#define ngx_http_lua_chain_key "__ngx_cl" + + /** * Set environment table for the given code closure. * @@ -47,14 +51,12 @@ static void ngx_http_lua_body_filter_by_lua_env(lua_State *L, ngx_http_request_t *r, ngx_chain_t *in) { - ngx_http_lua_main_conf_t *lmcf; - + /* set nginx request pointer to current lua thread's globals table */ ngx_http_lua_set_req(L, r); - lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); - lmcf->body_filter_chain = in; + lua_pushlightuserdata(L, in); + lua_setglobal(L, ngx_http_lua_chain_key); -#ifndef OPENRESTY_LUAJIT /** * we want to create empty environment for current script * @@ -77,7 +79,6 @@ ngx_http_lua_body_filter_by_lua_env(lua_State *L, ngx_http_request_t *r, /* }}} */ lua_setfenv(L, -2); /* set new running env for the code closure */ -#endif /* OPENRESTY_LUAJIT */ } @@ -235,8 +236,8 @@ ngx_http_lua_body_filter(ngx_http_request_t *r, ngx_chain_t *in) ngx_int_t rc; uint16_t old_context; ngx_http_cleanup_t *cln; + lua_State *L; ngx_chain_t *out; - ngx_http_lua_main_conf_t *lmcf; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua body filter for user lua code, uri \"%V\"", &r->uri); @@ -298,8 +299,11 @@ ngx_http_lua_body_filter(ngx_http_request_t *r, ngx_chain_t *in) return NGX_ERROR; } - lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); - out = lmcf->body_filter_chain; + L = ngx_http_lua_get_lua_vm(r, ctx); + + lua_getglobal(L, ngx_http_lua_chain_key); + out = lua_touserdata(L, -1); + lua_pop(L, 1); if (in == out) { return ngx_http_next_body_filter(r, in); @@ -341,7 +345,7 @@ 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_body_filter_param_get(lua_State *L) { u_char *data, *p; size_t size; @@ -350,8 +354,6 @@ ngx_http_lua_body_filter_param_get(lua_State *L, ngx_http_request_t *r) int idx; ngx_chain_t *in; - ngx_http_lua_main_conf_t *lmcf; - idx = luaL_checkint(L, 2); dd("index: %d", idx); @@ -361,8 +363,8 @@ ngx_http_lua_body_filter_param_get(lua_State *L, ngx_http_request_t *r) return 1; } - lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); - in = lmcf->body_filter_chain; + lua_getglobal(L, ngx_http_lua_chain_key); + in = lua_touserdata(L, -1); if (idx == 2) { /* asking for the eof argument */ @@ -440,8 +442,6 @@ ngx_http_lua_body_filter_param_set(lua_State *L, ngx_http_request_t *r, ngx_chain_t *cl; ngx_chain_t *in; - ngx_http_lua_main_conf_t *lmcf; - idx = luaL_checkint(L, 2); dd("index: %d", idx); @@ -450,13 +450,13 @@ ngx_http_lua_body_filter_param_set(lua_State *L, ngx_http_request_t *r, return luaL_error(L, "bad index: %d", idx); } - lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); - if (idx == 2) { /* overwriting the eof flag */ last = lua_toboolean(L, 3); - in = lmcf->body_filter_chain; + lua_getglobal(L, ngx_http_lua_chain_key); + in = lua_touserdata(L, -1); + lua_pop(L, 1); if (last) { ctx->seen_last_in_filter = 1; @@ -521,7 +521,9 @@ ngx_http_lua_body_filter_param_set(lua_State *L, ngx_http_request_t *r, case LUA_TNIL: /* discard the buffers */ - in = lmcf->body_filter_chain; + lua_getglobal(L, ngx_http_lua_chain_key); /* key val */ + in = lua_touserdata(L, -1); + lua_pop(L, 1); last = 0; @@ -555,7 +557,9 @@ ngx_http_lua_body_filter_param_set(lua_State *L, ngx_http_request_t *r, lua_typename(L, type)); } - in = lmcf->body_filter_chain; + lua_getglobal(L, ngx_http_lua_chain_key); + in = lua_touserdata(L, -1); + lua_pop(L, 1); last = 0; @@ -621,8 +625,8 @@ done: } } - lmcf->body_filter_chain = cl; - + lua_pushlightuserdata(L, cl); + lua_setglobal(L, ngx_http_lua_chain_key); return 0; } diff --git a/debian/modules/http-lua/src/ngx_http_lua_bodyfilterby.h b/debian/modules/http-lua/src/ngx_http_lua_bodyfilterby.h index b108202..6a4b306 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_bodyfilterby.h +++ b/debian/modules/http-lua/src/ngx_http_lua_bodyfilterby.h @@ -21,7 +21,7 @@ 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_get(lua_State *L); int ngx_http_lua_body_filter_param_set(lua_State *L, ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx); diff --git a/debian/modules/http-lua/src/ngx_http_lua_cache.c b/debian/modules/http-lua/src/ngx_http_lua_cache.c index 5b29527..5ea3069 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_cache.c +++ b/debian/modules/http-lua/src/ngx_http_lua_cache.c @@ -35,14 +35,11 @@ static ngx_int_t ngx_http_lua_cache_load_code(ngx_log_t *log, lua_State *L, const char *key) { -#ifndef OPENRESTY_LUAJIT int rc; u_char *err; -#endif /* get code cache table */ - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - code_cache_key)); + lua_pushlightuserdata(L, &ngx_http_lua_code_cache_key); lua_rawget(L, LUA_REGISTRYINDEX); /* sp++ */ dd("Code cache table to load: %p", lua_topointer(L, -1)); @@ -55,10 +52,6 @@ ngx_http_lua_cache_load_code(ngx_log_t *log, lua_State *L, lua_getfield(L, -1, key); /* sp++ */ if (lua_isfunction(L, -1)) { -#ifdef OPENRESTY_LUAJIT - lua_remove(L, -2); /* sp-- */ - return NGX_OK; -#else /* call closure factory to gen new closure */ rc = lua_pcall(L, 0, 1, 0); if (rc == 0) { @@ -80,7 +73,6 @@ ngx_http_lua_cache_load_code(ngx_log_t *log, lua_State *L, key, err); lua_pop(L, 2); return NGX_ERROR; -#endif /* OPENRESTY_LUAJIT */ } dd("Value associated with given key in code cache table is not code " @@ -110,13 +102,10 @@ ngx_http_lua_cache_load_code(ngx_log_t *log, lua_State *L, static ngx_int_t ngx_http_lua_cache_store_code(lua_State *L, const char *key) { -#ifndef OPENRESTY_LUAJIT int rc; -#endif /* get code cache table */ - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - code_cache_key)); + lua_pushlightuserdata(L, &ngx_http_lua_code_cache_key); lua_rawget(L, LUA_REGISTRYINDEX); dd("Code cache table to store: %p", lua_topointer(L, -1)); @@ -132,14 +121,12 @@ ngx_http_lua_cache_store_code(lua_State *L, const char *key) /* remove cache table, leave closure factory at top of stack */ lua_pop(L, 1); /* closure */ -#ifndef OPENRESTY_LUAJIT /* call closure factory to generate new closure */ rc = lua_pcall(L, 0, 1, 0); if (rc != 0) { dd("Error: failed to call closure factory!!"); return NGX_ERROR; } -#endif return NGX_OK; } @@ -156,8 +143,7 @@ ngx_http_lua_cache_loadbuffer(ngx_log_t *log, lua_State *L, n = lua_gettop(L); - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, - "looking up Lua code cache with key '%s'", cache_key); + dd("XXX cache key: [%s]", cache_key); rc = ngx_http_lua_cache_load_code(log, L, (char *) cache_key); if (rc == NGX_OK) { @@ -241,8 +227,7 @@ ngx_http_lua_cache_loadfile(ngx_log_t *log, lua_State *L, dd("CACHE file key already pre-calculated"); } - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, - "looking up Lua code cache with key '%s'", cache_key); + dd("XXX cache key for file: [%s]", cache_key); rc = ngx_http_lua_cache_load_code(log, L, (char *) cache_key); if (rc == NGX_OK) { diff --git a/debian/modules/http-lua/src/ngx_http_lua_clfactory.c b/debian/modules/http-lua/src/ngx_http_lua_clfactory.c index 754ed8d..041f046 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_clfactory.c +++ b/debian/modules/http-lua/src/ngx_http_lua_clfactory.c @@ -15,13 +15,11 @@ #include "ngx_http_lua_clfactory.h" -#ifndef OPENRESTY_LUAJIT #define CLFACTORY_BEGIN_CODE "return function() " #define CLFACTORY_BEGIN_SIZE (sizeof(CLFACTORY_BEGIN_CODE) - 1) #define CLFACTORY_END_CODE "\nend" #define CLFACTORY_END_SIZE (sizeof(CLFACTORY_END_CODE) - 1) -#endif /* @@ -61,7 +59,6 @@ * length(Instruction) = 4 or 8 * little endian or big endian */ -#ifndef OPENRESTY_LUAJIT #define LUA_LITTLE_ENDIAN_4BYTES_CODE \ "\x24\x00\x00\x00\x1e\x00\x00\x01\x1e\x00\x80\x00" #define LUA_LITTLE_ENDIAN_8BYTES_CODE \ @@ -78,7 +75,6 @@ #define LUA_BIG_ENDIAN_8BYTES_CODE_LEN (8 + 8 + 8) #define LUAC_HEADERSIZE 12 #define LUAC_VERSION 0x51 -#endif /* OPENRESTY_LUAJIT */ /* @@ -151,7 +147,6 @@ * --------------------- */ -#ifndef OPENRESTY_LUAJIT #define POS_SOURCE_STR_LEN LUAC_HEADERSIZE #define POS_START_LINE (POS_SOURCE_STR_LEN + sizeof(size_t)) #define POS_LAST_LINE (POS_START_LINE + sizeof(int)) @@ -165,7 +160,6 @@ (POS_BYTECODE + LUA_LITTLE_ENDIAN_8BYTES_CODE_LEN \ + sizeof(int) + sizeof(int)) #define MAX_END_CODE_SIZE (sizeof(int) + sizeof(int) + sizeof(int)) -#endif /* OPENRESTY_LUAJIT */ /* * taken from chaoslawful: @@ -231,7 +225,6 @@ /* bytecode for luajit 2.0 */ -#ifndef OPENRESTY_LUAJIT #define LJ20_LITTLE_ENDIAN_CODE_STRIPPED \ "\x14\x03\x00\x01\x00\x01\x00\x03" \ "\x31\x00\x00\x00\x30\x00\x00\x80\x48\x00\x02\x00" \ @@ -282,7 +275,6 @@ #define LJ21_BCDUMP_VERSION 2 #define LJ20_BCDUMP_VERSION 1 #define LJ_SIGNATURE "\x1b\x4c\x4a" -#endif /* OPENRESTY_LUAJIT */ typedef enum { @@ -300,11 +292,10 @@ enum { typedef struct { ngx_http_lua_clfactory_file_type_e file_type; - int extraline; - FILE *f; -#ifndef OPENRESTY_LUAJIT int sent_begin; int sent_end; + int extraline; + FILE *f; size_t begin_code_len; size_t end_code_len; size_t rest_len; @@ -316,16 +307,13 @@ typedef struct { char *ptr; char str[MAX_END_CODE_SIZE]; } end_code; -#endif /* OPENRESTY_LUAJIT */ char buff[NGX_LUA_READER_BUFSIZE]; } ngx_http_lua_clfactory_file_ctx_t; typedef struct { -#ifndef OPENRESTY_LUAJIT int sent_begin; int sent_end; -#endif const char *s; size_t size; } ngx_http_lua_clfactory_buffer_ctx_t; @@ -337,12 +325,9 @@ static int ngx_http_lua_clfactory_errfile(lua_State *L, const char *what, int fname_index); static const char *ngx_http_lua_clfactory_getS(lua_State *L, void *ud, size_t *size); -#ifndef OPENRESTY_LUAJIT static long ngx_http_lua_clfactory_file_size(FILE *f); -#endif -#ifndef OPENRESTY_LUAJIT int ngx_http_lua_clfactory_bytecode_prepare(lua_State *L, ngx_http_lua_clfactory_file_ctx_t *lf, int fname_index) @@ -608,7 +593,6 @@ error: return LUA_ERRFILE; } -#endif /* OPENRESTY_LUAJIT */ ngx_int_t @@ -628,12 +612,10 @@ ngx_http_lua_clfactory_loadfile(lua_State *L, const char *filename) lf.extraline = 0; lf.file_type = NGX_LUA_TEXT_FILE; -#ifndef OPENRESTY_LUAJIT lf.begin_code.ptr = CLFACTORY_BEGIN_CODE; lf.begin_code_len = CLFACTORY_BEGIN_SIZE; lf.end_code.ptr = CLFACTORY_END_CODE; lf.end_code_len = CLFACTORY_END_SIZE; -#endif lua_pushfstring(L, "@%s", filename); @@ -701,27 +683,20 @@ ngx_http_lua_clfactory_loadfile(lua_State *L, const char *filename) /* skip eventual `#!...' */ } -#ifndef OPENRESTY_LUAJIT status = ngx_http_lua_clfactory_bytecode_prepare(L, &lf, fname_index); if (status != 0) { return status; } -#endif lf.extraline = 0; } -#ifndef OPENRESTY_LUAJIT if (lf.file_type == NGX_LUA_TEXT_FILE) { ungetc(c, lf.f); } lf.sent_begin = lf.sent_end = 0; - -#else - ungetc(c, lf.f); -#endif status = lua_load(L, ngx_http_lua_clfactory_getF, &lf, lua_tostring(L, -1)); @@ -750,10 +725,8 @@ ngx_http_lua_clfactory_loadbuffer(lua_State *L, const char *buff, ls.s = buff; ls.size = size; -#ifndef OPENRESTY_LUAJIT ls.sent_begin = 0; ls.sent_end = 0; -#endif return lua_load(L, ngx_http_lua_clfactory_getS, &ls, name); } @@ -762,9 +735,7 @@ ngx_http_lua_clfactory_loadbuffer(lua_State *L, const char *buff, static const char * ngx_http_lua_clfactory_getF(lua_State *L, void *ud, size_t *size) { -#ifndef OPENRESTY_LUAJIT char *buf; -#endif size_t num; ngx_http_lua_clfactory_file_ctx_t *lf; @@ -777,7 +748,6 @@ ngx_http_lua_clfactory_getF(lua_State *L, void *ud, size_t *size) return "\n"; } -#ifndef OPENRESTY_LUAJIT if (lf->sent_begin == 0) { lf->sent_begin = 1; *size = lf->begin_code_len; @@ -791,14 +761,12 @@ ngx_http_lua_clfactory_getF(lua_State *L, void *ud, size_t *size) return buf; } -#endif /* OPENRESTY_LUAJIT */ num = fread(lf->buff, 1, sizeof(lf->buff), lf->f); dd("fread returned %d", (int) num); if (num == 0) { -#ifndef OPENRESTY_LUAJIT if (lf->sent_end == 0) { lf->sent_end = 1; *size = lf->end_code_len; @@ -812,13 +780,11 @@ ngx_http_lua_clfactory_getF(lua_State *L, void *ud, size_t *size) return buf; } -#endif /* OPENRESTY_LUAJIT */ *size = 0; return NULL; } -#ifndef OPENRESTY_LUAJIT if (lf->file_type == NGX_LUA_BT_LJ) { /* skip the footer(\x00) in luajit */ @@ -834,7 +800,6 @@ ngx_http_lua_clfactory_getF(lua_State *L, void *ud, size_t *size) } } } -#endif /* OPENRESTY_LUAJIT */ *size = num; return lf->buff; @@ -868,23 +833,19 @@ ngx_http_lua_clfactory_getS(lua_State *L, void *ud, size_t *size) { ngx_http_lua_clfactory_buffer_ctx_t *ls = ud; -#ifndef OPENRESTY_LUAJIT if (ls->sent_begin == 0) { ls->sent_begin = 1; *size = CLFACTORY_BEGIN_SIZE; return CLFACTORY_BEGIN_CODE; } -#endif if (ls->size == 0) { -#ifndef OPENRESTY_LUAJIT if (ls->sent_end == 0) { ls->sent_end = 1; *size = CLFACTORY_END_SIZE; return CLFACTORY_END_CODE; } -#endif return NULL; } @@ -896,7 +857,6 @@ ngx_http_lua_clfactory_getS(lua_State *L, void *ud, size_t *size) } -#ifndef OPENRESTY_LUAJIT static long ngx_http_lua_clfactory_file_size(FILE *f) { @@ -922,7 +882,6 @@ ngx_http_lua_clfactory_file_size(FILE *f) return len; } -#endif /* OPENRESTY_LUAJIT */ /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_common.h b/debian/modules/http-lua/src/ngx_http_lua_common.h index dae5245..01ef2be 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_common.h +++ b/debian/modules/http-lua/src/ngx_http_lua_common.h @@ -17,7 +17,7 @@ #include #include -#include +#include #include #include @@ -140,15 +140,6 @@ typedef struct { #endif -#if (NGX_PTR_SIZE >= 8 && !defined(_WIN64)) -#define ngx_http_lua_lightudata_mask(ludata) \ - ((void *) ((uintptr_t) (&ngx_http_lua_##ludata) & ((1UL << 47) - 1))) - -#else -#define ngx_http_lua_lightudata_mask(ludata) (&ngx_http_lua_##ludata) -#endif - - typedef struct ngx_http_lua_main_conf_s ngx_http_lua_main_conf_t; typedef union ngx_http_lua_srv_conf_u ngx_http_lua_srv_conf_t; @@ -182,8 +173,6 @@ struct ngx_http_lua_main_conf_s { ngx_cycle_t *cycle; ngx_pool_t *pool; - ngx_flag_t load_resty_core; - ngx_int_t max_pending_timers; ngx_int_t pending_timers; @@ -219,31 +208,9 @@ struct ngx_http_lua_main_conf_s { ngx_str_t init_worker_src; 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 - * concurrent requests when storing the chain - * data pointer in the main conf. - */ - - ngx_http_variable_value_t *setby_args; - /* neither yielding nor recursion is possible in - * set_by_lua*, so there cannot be any races among - * concurrent requests when storing the args pointer - * in the main conf. - */ - - size_t setby_nargs; - /* neither yielding nor recursion is possible in - * set_by_lua*, so there cannot be any races among - * concurrent requests when storing the nargs in the - * main conf. + /* 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. */ ngx_uint_t shm_zones_inited; @@ -260,10 +227,6 @@ struct ngx_http_lua_main_conf_s { ngx_int_t busy_buf_ptr_count; #endif - ngx_int_t host_var_index; - - ngx_flag_t set_sa_restart; - unsigned requires_header_filter:1; unsigned requires_body_filter:1; unsigned requires_capture_filter:1; @@ -481,7 +444,7 @@ typedef struct { typedef struct ngx_http_lua_ctx_s { - /* for lua_code_cache off: */ + /* for lua_coce_cache off: */ ngx_http_lua_vm_state_t *vm_state; ngx_http_request_t *request; @@ -568,8 +531,6 @@ typedef struct ngx_http_lua_ctx_s { unsigned headers_set:1; /* whether the user has set custom response headers */ - unsigned mime_set:1; /* whether the user has set Content-Type - response header */ unsigned entered_rewrite_phase:1; unsigned entered_access_phase:1; diff --git a/debian/modules/http-lua/src/ngx_http_lua_contentby.c b/debian/modules/http-lua/src/ngx_http_lua_contentby.c index 274c9ad..ecd6c0e 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_contentby.c +++ b/debian/modules/http-lua/src/ngx_http_lua_contentby.c @@ -63,11 +63,9 @@ ngx_http_lua_content_by_chunk(lua_State *L, ngx_http_request_t *r) /* 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); diff --git a/debian/modules/http-lua/src/ngx_http_lua_control.c b/debian/modules/http-lua/src/ngx_http_lua_control.c index 5cd1d64..6ac2cbf 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_control.c +++ b/debian/modules/http-lua/src/ngx_http_lua_control.c @@ -432,8 +432,7 @@ ngx_http_lua_on_abort(lua_State *L) ngx_http_lua_coroutine_create_helper(L, r, ctx, &coctx); - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - coroutines_key)); + lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); lua_rawget(L, LUA_REGISTRYINDEX); lua_pushvalue(L, -2); diff --git a/debian/modules/http-lua/src/ngx_http_lua_coroutine.c b/debian/modules/http-lua/src/ngx_http_lua_coroutine.c index 99a2423..b790814 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_coroutine.c +++ b/debian/modules/http-lua/src/ngx_http_lua_coroutine.c @@ -104,15 +104,11 @@ ngx_http_lua_coroutine_create_helper(lua_State *L, ngx_http_request_t *r, coctx->co = co; coctx->co_status = NGX_HTTP_LUA_CO_SUSPENDED; -#ifdef OPENRESTY_LUAJIT - ngx_http_lua_set_req(co, r); -#else /* make new coroutine share globals of the parent coroutine. * NOTE: globals don't have to be separated! */ ngx_http_lua_get_globals_table(L); lua_xmove(L, co, 1); ngx_http_lua_set_globals_table(co); -#endif lua_xmove(vm, L, 1); /* move coroutine from main thread to L */ @@ -292,27 +288,15 @@ ngx_http_lua_inject_coroutine_api(ngx_log_t *log, lua_State *L) { const char buf[] = "local keys = {'create', 'yield', 'resume', 'status'}\n" -#ifdef OPENRESTY_LUAJIT - "local get_req = require 'thread.exdata'\n" -#else "local getfenv = getfenv\n" -#endif "for _, key in ipairs(keys) do\n" "local std = coroutine['_' .. key]\n" "local ours = coroutine['__' .. key]\n" "local raw_ctx = ngx._phase_ctx\n" "coroutine[key] = function (...)\n" -#ifdef OPENRESTY_LUAJIT - "local r = get_req()\n" -#else "local r = getfenv(0).__ngx_req\n" -#endif - "if r ~= nil then\n" -#ifdef OPENRESTY_LUAJIT - "local ctx = raw_ctx()\n" -#else + "if r then\n" "local ctx = raw_ctx(r)\n" -#endif /* ignore header and body filters */ "if ctx ~= 0x020 and ctx ~= 0x040 then\n" "return ours(...)\n" diff --git a/debian/modules/http-lua/src/ngx_http_lua_directive.c b/debian/modules/http-lua/src/ngx_http_lua_directive.c index a989c26..fb8c6dc 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_directive.c +++ b/debian/modules/http-lua/src/ngx_http_lua_directive.c @@ -1304,12 +1304,11 @@ ngx_http_lua_gen_chunk_name(ngx_conf_t *cf, const char *tag, size_t tag_len, found: - p = ngx_snprintf(out, len, "=%*s(%*s:%d)%Z", - tag_len, tag, cf->conf_file->file.name.data - + cf->conf_file->file.name.len - p, - p, cf->conf_file->line); - - *chunkname_len = p - out - 1; /* exclude the trailing '\0' byte */ + ngx_snprintf(out, len, "=%*s(%*s:%d)%Z", + tag_len, tag, cf->conf_file->file.name.data + + cf->conf_file->file.name.len - p, + p, cf->conf_file->line); + *chunkname_len = len; return out; } diff --git a/debian/modules/http-lua/src/ngx_http_lua_headerfilterby.c b/debian/modules/http-lua/src/ngx_http_lua_headerfilterby.c index a0acd4a..b504530 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_headerfilterby.c +++ b/debian/modules/http-lua/src/ngx_http_lua_headerfilterby.c @@ -42,9 +42,9 @@ static ngx_http_output_header_filter_pt ngx_http_next_header_filter; static void ngx_http_lua_header_filter_by_lua_env(lua_State *L, ngx_http_request_t *r) { + /* set nginx request pointer to current lua thread's globals table */ ngx_http_lua_set_req(L, r); -#ifndef OPENRESTY_LUAJIT /** * we want to create empty environment for current script * @@ -68,7 +68,6 @@ ngx_http_lua_header_filter_by_lua_env(lua_State *L, ngx_http_request_t *r) /* }}} */ lua_setfenv(L, -2); /* set new running env for the code closure */ -#endif /* OPENRESTY_LUAJIT */ } diff --git a/debian/modules/http-lua/src/ngx_http_lua_headers.c b/debian/modules/http-lua/src/ngx_http_lua_headers.c index e3f48bc..b833577 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_headers.c +++ b/debian/modules/http-lua/src/ngx_http_lua_headers.c @@ -442,8 +442,7 @@ ngx_http_lua_ngx_req_get_headers(lua_State *L) lua_createtable(L, 0, count); if (!raw) { - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - headers_metatable_key)); + lua_pushlightuserdata(L, &ngx_http_lua_headers_metatable_key); lua_rawget(L, LUA_REGISTRYINDEX); lua_setmetatable(L, -2); } @@ -505,6 +504,7 @@ ngx_http_lua_ngx_resp_get_headers(lua_State *L) ngx_table_elt_t *header; ngx_http_request_t *r; ngx_http_lua_ctx_t *ctx; + ngx_int_t rc; u_char *lowcase_key = NULL; size_t lowcase_key_sz = 0; ngx_uint_t i; @@ -543,6 +543,17 @@ ngx_http_lua_ngx_resp_get_headers(lua_State *L) return luaL_error(L, "no ctx found"); } + if (!ctx->headers_set) { + rc = ngx_http_lua_set_content_type(r); + if (rc != NGX_OK) { + return luaL_error(L, + "failed to set default content type: %d", + (int) rc); + } + + ctx->headers_set = 1; + } + ngx_http_lua_check_fake_request(L, r); part = &r->headers_out.headers.part; @@ -555,8 +566,7 @@ ngx_http_lua_ngx_resp_get_headers(lua_State *L) lua_createtable(L, 0, count + 2); if (!raw) { - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - headers_metatable_key)); + lua_pushlightuserdata(L, &ngx_http_lua_headers_metatable_key); lua_rawget(L, LUA_REGISTRYINDEX); lua_setmetatable(L, -2); } @@ -684,6 +694,7 @@ ngx_http_lua_ngx_header_get(lua_State *L) size_t len; ngx_http_lua_loc_conf_t *llcf; ngx_http_lua_ctx_t *ctx; + ngx_int_t rc; r = ngx_http_lua_get_req(L); if (r == NULL) { @@ -726,7 +737,18 @@ ngx_http_lua_ngx_header_get(lua_State *L) key.len = len; - return ngx_http_lua_get_output_header(L, r, ctx, &key); + if (!ctx->headers_set) { + rc = ngx_http_lua_set_content_type(r); + if (rc != NGX_OK) { + return luaL_error(L, + "failed to set default content type: %d", + (int) rc); + } + + ctx->headers_set = 1; + } + + return ngx_http_lua_get_output_header(L, r, &key); } @@ -789,7 +811,16 @@ ngx_http_lua_ngx_header_set(lua_State *L) } } - ctx->headers_set = 1; + if (!ctx->headers_set) { + rc = ngx_http_lua_set_content_type(r); + if (rc != NGX_OK) { + return luaL_error(L, + "failed to set default content type: %d", + (int) rc); + } + + ctx->headers_set = 1; + } if (lua_type(L, 3) == LUA_TNIL) { ngx_str_null(&value); @@ -814,7 +845,7 @@ ngx_http_lua_ngx_header_set(lua_State *L) ngx_memcpy(value.data, p, len); value.len = len; - rc = ngx_http_lua_set_output_header(r, ctx, key, value, + rc = ngx_http_lua_set_output_header(r, key, value, i == 1 /* override */); if (rc == NGX_ERROR) { @@ -841,7 +872,7 @@ ngx_http_lua_ngx_header_set(lua_State *L) dd("key: %.*s, value: %.*s", (int) key.len, key.data, (int) value.len, value.data); - rc = ngx_http_lua_set_output_header(r, ctx, key, value, 1 /* override */); + rc = ngx_http_lua_set_output_header(r, key, value, 1 /* override */); if (rc == NGX_ERROR) { return luaL_error(L, "failed to set header %s (error: %d)", @@ -1050,8 +1081,7 @@ ngx_http_lua_create_headers_metatable(ngx_log_t *log, lua_State *L) "local new_key = string.gsub(string.lower(key), '_', '-')\n" "if new_key ~= key then return tb[new_key] else return nil end"; - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - headers_metatable_key)); + lua_pushlightuserdata(L, &ngx_http_lua_headers_metatable_key); /* metatable for ngx.req.get_headers(_, true) and * ngx.resp.get_headers(_, true) */ @@ -1211,7 +1241,15 @@ ngx_http_lua_ffi_set_resp_header(ngx_http_request_t *r, const u_char *key_data, } } - ctx->headers_set = 1; + if (!ctx->headers_set) { + rc = ngx_http_lua_set_content_type(r); + if (rc != NGX_OK) { + *errmsg = "failed to set default content type"; + return NGX_ERROR; + } + + ctx->headers_set = 1; + } if (is_nil) { value.data = NULL; @@ -1238,7 +1276,7 @@ ngx_http_lua_ffi_set_resp_header(ngx_http_request_t *r, const u_char *key_data, ngx_memcpy(value.data, p, len); value.len = len; - rc = ngx_http_lua_set_output_header(r, ctx, key, value, + rc = ngx_http_lua_set_output_header(r, key, value, override && i == 0); if (rc == NGX_ERROR) { @@ -1264,7 +1302,7 @@ ngx_http_lua_ffi_set_resp_header(ngx_http_request_t *r, const u_char *key_data, dd("key: %.*s, value: %.*s", (int) key.len, key.data, (int) value.len, value.data); - rc = ngx_http_lua_set_output_header(r, ctx, key, value, override); + rc = ngx_http_lua_set_output_header(r, key, value, override); if (rc == NGX_ERROR) { *errmsg = "failed to set header"; @@ -1332,8 +1370,7 @@ ngx_http_lua_ffi_req_header_set_single_value(ngx_http_request_t *r, int ngx_http_lua_ffi_get_resp_header(ngx_http_request_t *r, const u_char *key, size_t key_len, - u_char *key_buf, ngx_http_lua_ffi_str_t *values, int max_nvalues, - char **errmsg) + u_char *key_buf, ngx_http_lua_ffi_str_t *values, int max_nvalues) { int found; u_char c, *p; @@ -1350,10 +1387,19 @@ ngx_http_lua_ffi_get_resp_header(ngx_http_request_t *r, ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { - *errmsg = "no ctx found"; + /* *errmsg = "no ctx found"; */ return NGX_ERROR; } + if (!ctx->headers_set) { + if (ngx_http_lua_set_content_type(r) != NGX_OK) { + /* *errmsg = "failed to set default content type"; */ + return NGX_ERROR; + } + + ctx->headers_set = 1; + } + llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); if (llcf->transform_underscores_in_resp_headers && memchr(key, '_', key_len) != NULL) @@ -1379,7 +1425,6 @@ ngx_http_lua_ffi_get_resp_header(ngx_http_request_t *r, { p = ngx_palloc(r->pool, NGX_OFF_T_LEN); if (p == NULL) { - *errmsg = "no memory"; return NGX_ERROR; } @@ -1393,8 +1438,8 @@ ngx_http_lua_ffi_get_resp_header(ngx_http_request_t *r, break; case 12: - if (ngx_strncasecmp(key_buf, (u_char *) "Content-Type", 12) == 0 - && r->headers_out.content_type.len) + if (r->headers_out.content_type.len + && ngx_strncasecmp(key_buf, (u_char *) "Content-Type", 12) == 0) { values[0].data = r->headers_out.content_type.data; values[0].len = r->headers_out.content_type.len; diff --git a/debian/modules/http-lua/src/ngx_http_lua_headers_in.c b/debian/modules/http-lua/src/ngx_http_lua_headers_in.c index c52cd13..4852b2f 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_headers_in.c +++ b/debian/modules/http-lua/src/ngx_http_lua_headers_in.c @@ -432,14 +432,10 @@ static ngx_int_t ngx_http_set_host_header(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, ngx_str_t *value) { - ngx_str_t host; - ngx_http_lua_main_conf_t *lmcf; - ngx_http_variable_value_t *var; + ngx_str_t host; dd("server new value len: %d", (int) value->len); - lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); - if (value->len) { host= *value; @@ -453,10 +449,6 @@ ngx_http_set_host_header(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, r->headers_in.server = *value; } - var = &r->variables[lmcf->host_var_index]; - var->valid = 0; - var->not_found = 0; - return ngx_http_set_builtin_header(r, hv, value); } diff --git a/debian/modules/http-lua/src/ngx_http_lua_headers_out.c b/debian/modules/http-lua/src/ngx_http_lua_headers_out.c index cf94bd0..b908eae 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_headers_out.c +++ b/debian/modules/http-lua/src/ngx_http_lua_headers_out.c @@ -106,12 +106,6 @@ static ngx_http_lua_set_header_t ngx_http_lua_set_handlers[] = { offsetof(ngx_http_headers_out_t, cache_control), ngx_http_set_builtin_multi_header }, -#if defined(nginx_version) && nginx_version >= 1013009 - { ngx_string("Link"), - offsetof(ngx_http_headers_out_t, link), - ngx_http_set_builtin_multi_header }, -#endif - { ngx_null_string, 0, ngx_http_set_header } }; @@ -482,8 +476,8 @@ ngx_http_clear_builtin_header(ngx_http_request_t *r, ngx_int_t -ngx_http_lua_set_output_header(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx, - ngx_str_t key, ngx_str_t value, unsigned override) +ngx_http_lua_set_output_header(ngx_http_request_t *r, 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; @@ -514,10 +508,6 @@ ngx_http_lua_set_output_header(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx, hv.offset = handlers[i].offset; hv.handler = handlers[i].handler; - if (hv.handler == ngx_http_set_content_type_header) { - ctx->mime_set = 1; - } - break; } @@ -538,7 +528,7 @@ ngx_http_lua_set_output_header(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx, 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_str_t *key) { ngx_table_elt_t *h; ngx_list_part_t *part; @@ -560,8 +550,8 @@ ngx_http_lua_get_output_header(lua_State *L, ngx_http_request_t *r, break; case 12: - if (ngx_strncasecmp(key->data, (u_char *) "Content-Type", 12) == 0 - && r->headers_out.content_type.len) + if (r->headers_out.content_type.len + && ngx_strncasecmp(key->data, (u_char *) "Content-Type", 12) == 0) { lua_pushlstring(L, (char *) r->headers_out.content_type.data, r->headers_out.content_type.len); diff --git a/debian/modules/http-lua/src/ngx_http_lua_headers_out.h b/debian/modules/http-lua/src/ngx_http_lua_headers_out.h index 6ec1fe3..ef5e6d4 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_headers_out.h +++ b/debian/modules/http-lua/src/ngx_http_lua_headers_out.h @@ -12,10 +12,10 @@ #include "ngx_http_lua_common.h" -ngx_int_t ngx_http_lua_set_output_header(ngx_http_request_t *r, - ngx_http_lua_ctx_t *ctx, ngx_str_t key, ngx_str_t value, unsigned override); +ngx_int_t ngx_http_lua_set_output_header(ngx_http_request_t *r, ngx_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_str_t *key); #endif /* _NGX_HTTP_LUA_HEADERS_OUT_H_INCLUDED_ */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_initworkerby.c b/debian/modules/http-lua/src/ngx_http_lua_initworkerby.c index 76acdc3..4a722a0 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_initworkerby.c +++ b/debian/modules/http-lua/src/ngx_http_lua_initworkerby.c @@ -12,7 +12,6 @@ #include "ngx_http_lua_initworkerby.h" #include "ngx_http_lua_util.h" -#include "ngx_http_lua_pipe.h" static u_char *ngx_http_lua_log_init_worker_error(ngx_log_t *log, @@ -26,7 +25,6 @@ ngx_http_lua_init_worker(ngx_cycle_t *cycle) void *cur, *prev; ngx_uint_t i; ngx_conf_t conf; - ngx_conf_file_t cf_file; ngx_cycle_t *fake_cycle; ngx_module_t **modules; ngx_open_file_t *file, *ofile; @@ -66,21 +64,8 @@ ngx_http_lua_init_worker(ngx_cycle_t *cycle) return NGX_OK; } - -#ifdef HAVE_NGX_LUA_PIPE - if (ngx_http_lua_pipe_add_signal_handler(cycle) != NGX_OK) { - return NGX_ERROR; - } -#endif - #endif /* NGX_WIN32 */ -#if (NGX_HTTP_LUA_HAVE_SA_RESTART) - if (lmcf->set_sa_restart) { - ngx_http_lua_set_sa_restart(ngx_cycle->log); - } -#endif - if (lmcf->init_worker_handler == NULL) { return NGX_OK; } @@ -181,10 +166,6 @@ ngx_http_lua_init_worker(ngx_cycle_t *cycle) conf.pool = fake_cycle->pool; conf.log = cycle->log; - ngx_memzero(&cf_file, sizeof(cf_file)); - cf_file.file.name = cycle->conf_file; - conf.conf_file = &cf_file; - http_ctx.loc_conf = ngx_pcalloc(conf.pool, sizeof(void *) * ngx_http_max_module); if (http_ctx.loc_conf == NULL) { diff --git a/debian/modules/http-lua/src/ngx_http_lua_input_filters.c b/debian/modules/http-lua/src/ngx_http_lua_input_filters.c deleted file mode 100644 index 87a9d8c..0000000 --- a/debian/modules/http-lua/src/ngx_http_lua_input_filters.c +++ /dev/null @@ -1,137 +0,0 @@ - -/* - * Copyright (C) by OpenResty Inc. - */ - - -#ifndef DDEBUG -#define DDEBUG 0 -#endif -#include "ddebug.h" - - -#include "ngx_http_lua_common.h" - - -ngx_int_t -ngx_http_lua_read_bytes(ngx_buf_t *src, ngx_chain_t *buf_in, size_t *rest, - ssize_t bytes, ngx_log_t *log) -{ - if (bytes == 0) { - return NGX_ERROR; - } - - if ((size_t) bytes >= *rest) { - - buf_in->buf->last += *rest; - src->pos += *rest; - *rest = 0; - - return NGX_OK; - } - - /* bytes < *rest */ - - buf_in->buf->last += bytes; - src->pos += bytes; - *rest -= bytes; - - return NGX_AGAIN; -} - - -ngx_int_t -ngx_http_lua_read_all(ngx_buf_t *src, ngx_chain_t *buf_in, ssize_t bytes, - ngx_log_t *log) -{ - if (bytes == 0) { - return NGX_OK; - } - - buf_in->buf->last += bytes; - src->pos += bytes; - - return NGX_AGAIN; -} - - -ngx_int_t -ngx_http_lua_read_any(ngx_buf_t *src, ngx_chain_t *buf_in, size_t *max, - ssize_t bytes, ngx_log_t *log) -{ - if (bytes == 0) { - return NGX_ERROR; - } - - if (bytes >= (ssize_t) *max) { - bytes = (ssize_t) *max; - } - - buf_in->buf->last += bytes; - src->pos += bytes; - - return NGX_OK; -} - - -ngx_int_t -ngx_http_lua_read_line(ngx_buf_t *src, ngx_chain_t *buf_in, ssize_t bytes, - ngx_log_t *log) -{ - u_char *dst; - u_char c; -#if (NGX_DEBUG) - u_char *begin; -#endif - -#if (NGX_DEBUG) - begin = src->pos; -#endif - - if (bytes == 0) { - return NGX_ERROR; - } - - dd("already read: %p: %.*s", buf_in, - (int) (buf_in->buf->last - buf_in->buf->pos), buf_in->buf->pos); - - dd("data read: %.*s", (int) bytes, src->pos); - - dst = buf_in->buf->last; - - while (bytes--) { - - c = *src->pos++; - - switch (c) { - case '\n': - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, log, 0, - "lua read the final line part: \"%*s\"", - src->pos - 1 - begin, begin); - - buf_in->buf->last = dst; - - dd("read a line: %p: %.*s", buf_in, - (int) (buf_in->buf->last - buf_in->buf->pos), buf_in->buf->pos); - - return NGX_OK; - - case '\r': - /* ignore it */ - break; - - default: - *dst++ = c; - break; - } - } - -#if (NGX_DEBUG) - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, log, 0, - "lua read partial line data: %*s", dst - begin, begin); -#endif - - buf_in->buf->last = dst; - - return NGX_AGAIN; -} diff --git a/debian/modules/http-lua/src/ngx_http_lua_input_filters.h b/debian/modules/http-lua/src/ngx_http_lua_input_filters.h deleted file mode 100644 index 046d40f..0000000 --- a/debian/modules/http-lua/src/ngx_http_lua_input_filters.h +++ /dev/null @@ -1,29 +0,0 @@ - -/* - * Copyright (C) by OpenResty Inc. - */ - - -#ifndef _NGX_HTTP_LUA_INPUT_FILTERS_H_INCLUDED_ -#define _NGX_HTTP_LUA_INPUT_FILTERS_H_INCLUDED_ - - -#include "ngx_http_lua_common.h" - - -ngx_int_t ngx_http_lua_read_bytes(ngx_buf_t *src, ngx_chain_t *buf_in, - size_t *rest, ssize_t bytes, ngx_log_t *log); - -ngx_int_t ngx_http_lua_read_all(ngx_buf_t *src, ngx_chain_t *buf_in, - ssize_t bytes, ngx_log_t *log); - -ngx_int_t ngx_http_lua_read_any(ngx_buf_t *src, ngx_chain_t *buf_in, - size_t *max, ssize_t bytes, ngx_log_t *log); - -ngx_int_t ngx_http_lua_read_line(ngx_buf_t *src, ngx_chain_t *buf_in, - ssize_t bytes, ngx_log_t *log); - - -#endif /* _NGX_HTTP_LUA_INPUT_FILTERS_H_INCLUDED_ */ - -/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_logby.c b/debian/modules/http-lua/src/ngx_http_lua_logby.c index 32d1cba..0f1d2f3 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_logby.c +++ b/debian/modules/http-lua/src/ngx_http_lua_logby.c @@ -38,9 +38,9 @@ static ngx_int_t ngx_http_lua_log_by_chunk(lua_State *L, ngx_http_request_t *r); static void ngx_http_lua_log_by_lua_env(lua_State *L, ngx_http_request_t *r) { + /* set nginx request pointer to current lua thread's globals table */ ngx_http_lua_set_req(L, r); -#ifndef OPENRESTY_LUAJIT /** * we want to create empty environment for current script * @@ -64,7 +64,6 @@ ngx_http_lua_log_by_lua_env(lua_State *L, ngx_http_request_t *r) /* }}} */ lua_setfenv(L, -2); /* set new running env for the code closure */ -#endif /* OPENRESTY_LUAJIT */ } diff --git a/debian/modules/http-lua/src/ngx_http_lua_misc.c b/debian/modules/http-lua/src/ngx_http_lua_misc.c index 145ca9b..f96e2f2 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_misc.c +++ b/debian/modules/http-lua/src/ngx_http_lua_misc.c @@ -286,33 +286,6 @@ ngx_http_lua_ffi_headers_sent(ngx_http_request_t *r) return r->header_sent ? 1 : 0; } - - -int -ngx_http_lua_ffi_get_conf_env(u_char *name, u_char **env_buf, size_t *name_len) -{ - ngx_uint_t i; - ngx_str_t *var; - ngx_core_conf_t *ccf; - - ccf = (ngx_core_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx, - ngx_core_module); - - var = ccf->env.elts; - - for (i = 0; i < ccf->env.nelts; i++) { - if (var[i].data[var[i].len] == '=' - && ngx_strncmp(name, var[i].data, var[i].len) == 0) - { - *env_buf = var[i].data; - *name_len = var[i].len; - - return NGX_OK; - } - } - - return NGX_DECLINED; -} #endif /* NGX_LUA_NO_FFI_API */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_module.c b/debian/modules/http-lua/src/ngx_http_lua_module.c index 2a3f5d5..ae8bc0e 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_module.c +++ b/debian/modules/http-lua/src/ngx_http_lua_module.c @@ -29,7 +29,6 @@ #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_pipe.h" static void *ngx_http_lua_create_main_conf(ngx_conf_t *cf); @@ -77,13 +76,6 @@ static ngx_conf_bitmask_t ngx_http_lua_ssl_protocols[] = { static ngx_command_t ngx_http_lua_cmds[] = { - { ngx_string("lua_load_resty_core"), - NGX_HTTP_MAIN_CONF|NGX_CONF_FLAG, - ngx_conf_set_flag_slot, - NGX_HTTP_MAIN_CONF_OFFSET, - offsetof(ngx_http_lua_main_conf_t, load_resty_core), - NULL }, - { ngx_string("lua_max_running_timers"), NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1, ngx_conf_set_num_slot, @@ -112,13 +104,6 @@ static ngx_command_t ngx_http_lua_cmds[] = { 0, NULL }, - { ngx_string("lua_sa_restart"), - NGX_HTTP_MAIN_CONF|NGX_CONF_FLAG, - ngx_conf_set_flag_slot, - NGX_HTTP_MAIN_CONF_OFFSET, - offsetof(ngx_http_lua_main_conf_t, set_sa_restart), - NULL }, - #if (NGX_PCRE) { ngx_string("lua_regex_cache_max_entries"), NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1, @@ -653,19 +638,9 @@ ngx_http_lua_init(ngx_conf_t *cf) #if !defined(NGX_LUA_NO_FFI_API) || nginx_version >= 1011011 ngx_pool_cleanup_t *cln; #endif - ngx_str_t name = ngx_string("host"); - - if (ngx_process == NGX_PROCESS_SIGNALLER || ngx_test_config) { - return NGX_OK; - } lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_lua_module); - lmcf->host_var_index = ngx_http_get_variable_index(cf, &name); - if (lmcf->host_var_index == NGX_ERROR) { - return NGX_ERROR; - } - if (ngx_http_lua_prev_cycle != ngx_cycle) { ngx_http_lua_prev_cycle = ngx_cycle; multi_http_blocks = 0; @@ -750,11 +725,6 @@ ngx_http_lua_init(ngx_conf_t *cf) cln->data = lmcf; cln->handler = ngx_http_lua_sema_mm_cleanup; - -#ifdef HAVE_NGX_LUA_PIPE - ngx_http_lua_pipe_init(); -#endif - #endif #if nginx_version >= 1011011 @@ -770,19 +740,6 @@ ngx_http_lua_init(ngx_conf_t *cf) if (lmcf->lua == NULL) { dd("initializing lua vm"); -#ifndef OPENRESTY_LUAJIT - if (ngx_process != NGX_PROCESS_SIGNALLER && !ngx_test_config) { - ngx_log_error(NGX_LOG_ALERT, cf->log, 0, - "detected a LuaJIT version which is not OpenResty's" - "; many optimizations will be disabled and " - "performance will be compromised (see " - "https://github.com/openresty/luajit2 for " - "OpenResty's LuaJIT or, even better, consider using " - "the OpenResty releases from https://openresty.org/" - "en/download.html)"); - } -#endif - ngx_http_lua_content_length_hash = ngx_http_lua_hash_literal("content-length"); ngx_http_lua_location_hash = ngx_http_lua_hash_literal("location"); @@ -884,7 +841,6 @@ ngx_http_lua_create_main_conf(ngx_conf_t *cf) */ lmcf->pool = cf->pool; - lmcf->load_resty_core = NGX_CONF_UNSET; lmcf->max_pending_timers = NGX_CONF_UNSET; lmcf->max_running_timers = NGX_CONF_UNSET; #if (NGX_PCRE) @@ -894,8 +850,6 @@ ngx_http_lua_create_main_conf(ngx_conf_t *cf) lmcf->postponed_to_rewrite_phase_end = NGX_CONF_UNSET; lmcf->postponed_to_access_phase_end = NGX_CONF_UNSET; - lmcf->set_sa_restart = NGX_CONF_UNSET; - #if (NGX_HTTP_LUA_HAVE_MALLOC_TRIM) lmcf->malloc_trim_cycle = NGX_CONF_UNSET_UINT; #endif @@ -918,10 +872,6 @@ ngx_http_lua_init_main_conf(ngx_conf_t *cf, void *conf) { ngx_http_lua_main_conf_t *lmcf = conf; - if (lmcf->load_resty_core == NGX_CONF_UNSET) { - lmcf->load_resty_core = 1; - } - #if (NGX_PCRE) if (lmcf->regex_cache_max_entries == NGX_CONF_UNSET) { lmcf->regex_cache_max_entries = 1024; @@ -940,12 +890,6 @@ ngx_http_lua_init_main_conf(ngx_conf_t *cf, void *conf) lmcf->max_running_timers = 256; } -#if (NGX_HTTP_LUA_HAVE_SA_RESTART) - if (lmcf->set_sa_restart == NGX_CONF_UNSET) { - lmcf->set_sa_restart = 1; - } -#endif - #if (NGX_HTTP_LUA_HAVE_MALLOC_TRIM) if (lmcf->malloc_trim_cycle == NGX_CONF_UNSET_UINT) { lmcf->malloc_trim_cycle = 1000; /* number of reqs */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_ndk.c b/debian/modules/http-lua/src/ngx_http_lua_ndk.c index 6344183..24b80b4 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_ndk.c +++ b/debian/modules/http-lua/src/ngx_http_lua_ndk.c @@ -186,47 +186,6 @@ ngx_http_lua_inject_ndk_api(lua_State *L) } -int -ngx_http_lua_ffi_ndk_lookup_directive(const u_char *var_data, - size_t var_len, ndk_set_var_value_pt *func) -{ - *func = ngx_http_lookup_ndk_set_var_directive((u_char *) var_data, var_len); - - if (*func == NULL) { - return NGX_ERROR; - } - - return NGX_OK; -} - - -int -ngx_http_lua_ffi_ndk_set_var_get(ngx_http_request_t *r, - ndk_set_var_value_pt func, const u_char *arg_data, size_t arg_len, - ngx_http_lua_ffi_str_t *value) -{ - ngx_int_t rc; - ngx_str_t res; - ngx_http_variable_value_t arg; - - ngx_memzero(&arg, sizeof(ngx_http_variable_value_t)); - arg.valid = 1; - - arg.data = (u_char *) arg_data; - arg.len = arg_len; - - rc = func(r, &res, &arg); - - if (rc != NGX_OK) { - return rc; - } - - value->data = res.data; - value->len = res.len; - return NGX_OK; -} - - #endif /* defined(NDK) && NDK */ /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_pipe.c b/debian/modules/http-lua/src/ngx_http_lua_pipe.c deleted file mode 100644 index 8c8221f..0000000 --- a/debian/modules/http-lua/src/ngx_http_lua_pipe.c +++ /dev/null @@ -1,2475 +0,0 @@ - -/* - * Copyright (C) by OpenResty Inc. - */ - - -#ifndef DDEBUG -#define DDEBUG 0 -#endif -#include "ddebug.h" - - -#include "ngx_http_lua_common.h" -#include "ngx_http_lua_input_filters.h" -#include "ngx_http_lua_util.h" -#include "ngx_http_lua_pipe.h" -#if (NGX_HTTP_LUA_HAVE_SIGNALFD) -#include -#endif - - -#ifdef HAVE_NGX_LUA_PIPE -static ngx_rbtree_node_t *ngx_http_lua_pipe_lookup_pid(ngx_rbtree_key_t key); -#if !(NGX_HTTP_LUA_HAVE_SIGNALFD) -static void ngx_http_lua_pipe_sigchld_handler(int signo, siginfo_t *siginfo, - void *ucontext); -#endif -static void ngx_http_lua_pipe_sigchld_event_handler(ngx_event_t *ev); -static ssize_t ngx_http_lua_pipe_fd_read(ngx_connection_t *c, u_char *buf, - size_t size); -static ssize_t ngx_http_lua_pipe_fd_write(ngx_connection_t *c, u_char *buf, - size_t size); -static ngx_int_t ngx_http_lua_pipe_close_helper( - ngx_http_lua_pipe_ctx_t *pipe_ctx, ngx_event_t *ev, int forced); -static ngx_int_t ngx_http_lua_pipe_close_stdin(ngx_http_lua_pipe_t *pipe, - int forced); -static ngx_int_t ngx_http_lua_pipe_close_stdout(ngx_http_lua_pipe_t *pipe, - int forced); -static ngx_int_t ngx_http_lua_pipe_close_stderr(ngx_http_lua_pipe_t *pipe, - int forced); -static void ngx_http_lua_pipe_proc_finalize(ngx_http_lua_ffi_pipe_proc_t *proc, - int forced); -static ngx_int_t ngx_http_lua_pipe_get_lua_ctx(ngx_http_request_t *r, - ngx_http_lua_ctx_t **ctx, u_char *errbuf, size_t *errbuf_size); -static void ngx_http_lua_pipe_put_error(ngx_http_lua_pipe_ctx_t *pipe_ctx, - u_char *errbuf, size_t *errbuf_size); -static void ngx_http_lua_pipe_put_data(ngx_http_lua_pipe_t *pipe, - ngx_http_lua_pipe_ctx_t *pipe_ctx, u_char **buf, size_t *buf_size); -static ngx_int_t ngx_http_lua_pipe_add_input_buffer(ngx_http_lua_pipe_t *pipe, - ngx_http_lua_pipe_ctx_t *pipe_ctx); -static ngx_int_t ngx_http_lua_pipe_read_all(void *data, ssize_t bytes); -static ngx_int_t ngx_http_lua_pipe_read_bytes(void *data, ssize_t bytes); -static ngx_int_t ngx_http_lua_pipe_read_line(void *data, ssize_t bytes); -static ngx_int_t ngx_http_lua_pipe_read_any(void *data, ssize_t bytes); -static ngx_int_t ngx_http_lua_pipe_read(ngx_http_lua_pipe_t *pipe, - ngx_http_lua_pipe_ctx_t *pipe_ctx); -static ngx_int_t ngx_http_lua_pipe_init_ctx( - ngx_http_lua_pipe_ctx_t **pipe_ctx_pt, int fd, ngx_pool_t *pool, - u_char *errbuf, size_t *errbuf_size); -static ngx_int_t ngx_http_lua_pipe_write(ngx_http_lua_pipe_t *pipe, - ngx_http_lua_pipe_ctx_t *pipe_ctx); -static int ngx_http_lua_pipe_read_stdout_retval( - ngx_http_lua_ffi_pipe_proc_t *proc, lua_State *L); -static int ngx_http_lua_pipe_read_stderr_retval( - ngx_http_lua_ffi_pipe_proc_t *proc, lua_State *L); -static int ngx_http_lua_pipe_read_retval_helper( - ngx_http_lua_ffi_pipe_proc_t *proc, lua_State *L, int from_stderr); -static int ngx_http_lua_pipe_write_retval(ngx_http_lua_ffi_pipe_proc_t *proc, - lua_State *L); -static int ngx_http_lua_pipe_wait_retval(ngx_http_lua_ffi_pipe_proc_t *proc, - lua_State *L); -static void ngx_http_lua_pipe_resume_helper(ngx_event_t *ev, - ngx_http_lua_co_ctx_t *wait_co_ctx); -static void ngx_http_lua_pipe_resume_read_stdout_handler(ngx_event_t *ev); -static void ngx_http_lua_pipe_resume_read_stderr_handler(ngx_event_t *ev); -static void ngx_http_lua_pipe_resume_write_handler(ngx_event_t *ev); -static void ngx_http_lua_pipe_resume_wait_handler(ngx_event_t *ev); -static ngx_int_t ngx_http_lua_pipe_resume(ngx_http_request_t *r); -static void ngx_http_lua_pipe_dummy_event_handler(ngx_event_t *ev); -static void ngx_http_lua_pipe_clear_event(ngx_event_t *ev); -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 ngx_rbtree_t ngx_http_lua_pipe_rbtree; -static ngx_rbtree_node_t ngx_http_lua_pipe_proc_sentinel; - - -#if (NGX_HTTP_LUA_HAVE_SIGNALFD) -static int ngx_http_lua_signalfd; -static struct signalfd_siginfo ngx_http_lua_pipe_notification; - -#define ngx_http_lua_read_sigfd ngx_http_lua_signalfd - -#else -static int ngx_http_lua_sigchldfd[2]; -static u_char ngx_http_lua_pipe_notification[1]; - -#define ngx_http_lua_read_sigfd ngx_http_lua_sigchldfd[0] -#define ngx_http_lua_write_sigfd ngx_http_lua_sigchldfd[1] -#endif - - -static ngx_connection_t *ngx_http_lua_sigfd_conn = NULL; - - -/* The below signals are ignored by Nginx. - * We need to reset them for the spawned child processes. */ -ngx_http_lua_pipe_signal_t ngx_signals[] = { - { SIGSYS, "SIGSYS" }, - { SIGPIPE, "SIGPIPE" }, - { 0, NULL } -}; - - -enum { - PIPE_ERR_CLOSED = 1, - PIPE_ERR_SYSCALL, - PIPE_ERR_NOMEM, - PIPE_ERR_TIMEOUT, - PIPE_ERR_ADD_READ_EV, - PIPE_ERR_ADD_WRITE_EV -}; - - -enum { - PIPE_READ_ALL = 0, - PIPE_READ_BYTES, - PIPE_READ_LINE, - PIPE_READ_ANY -}; - - -#define REASON_EXIT "exit" -#define REASON_SIGNAL "signal" -#define REASON_UNKNOWN "unknown" - -#define REASON_RUNNING_CODE 0 -#define REASON_EXIT_CODE 1 -#define REASON_SIGNAL_CODE 2 -#define REASON_UNKNOWN_CODE 3 - - -void -ngx_http_lua_pipe_init(void) -{ - ngx_rbtree_init(&ngx_http_lua_pipe_rbtree, - &ngx_http_lua_pipe_proc_sentinel, ngx_rbtree_insert_value); -} - - -ngx_int_t -ngx_http_lua_pipe_add_signal_handler(ngx_cycle_t *cycle) -{ - ngx_event_t *rev; -#if (NGX_HTTP_LUA_HAVE_SIGNALFD) - sigset_t set; - -#else - int rc; - struct sigaction sa; -#endif - -#if (NGX_HTTP_LUA_HAVE_SIGNALFD) - if (sigemptyset(&set) != 0) { - ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno, - "lua pipe init signal set failed"); - return NGX_ERROR; - } - - if (sigaddset(&set, SIGCHLD) != 0) { - ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno, - "lua pipe add SIGCHLD to signal set failed"); - return NGX_ERROR; - } - - if (sigprocmask(SIG_BLOCK, &set, NULL) != 0) { - ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno, - "lua pipe block SIGCHLD failed"); - return NGX_ERROR; - } - - ngx_http_lua_signalfd = signalfd(-1, &set, SFD_NONBLOCK|SFD_CLOEXEC); - if (ngx_http_lua_signalfd < 0) { - ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno, - "lua pipe create signalfd instance failed"); - return NGX_ERROR; - } - -#else /* !(NGX_HTTP_LUA_HAVE_SIGNALFD) */ -# if (NGX_HTTP_LUA_HAVE_PIPE2) - rc = pipe2(ngx_http_lua_sigchldfd, O_NONBLOCK|O_CLOEXEC); -# else - rc = pipe(ngx_http_lua_sigchldfd); -# endif - - if (rc == -1) { - ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno, - "lua pipe init SIGCHLD fd failed"); - return NGX_ERROR; - } - -# if !(NGX_HTTP_LUA_HAVE_PIPE2) - if (ngx_nonblocking(ngx_http_lua_read_sigfd) == -1) { - ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno, "lua pipe " - ngx_nonblocking_n " SIGCHLD read fd failed"); - goto failed; - } - - if (ngx_nonblocking(ngx_http_lua_write_sigfd) == -1) { - ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno, "lua pipe " - ngx_nonblocking_n " SIGCHLD write fd failed"); - goto failed; - } - - /* it's ok not to set the pipe fd with O_CLOEXEC. This requires - * extra syscall */ -# endif /* !(NGX_HTTP_LUA_HAVE_PIPE2) */ -#endif /* NGX_HTTP_LUA_HAVE_SIGNALFD */ - - ngx_http_lua_sigfd_conn = ngx_get_connection(ngx_http_lua_read_sigfd, - cycle->log); - if (ngx_http_lua_sigfd_conn == NULL) { - goto failed; - } - - ngx_http_lua_sigfd_conn->log = cycle->log; - ngx_http_lua_sigfd_conn->recv = ngx_http_lua_pipe_fd_read; - rev = ngx_http_lua_sigfd_conn->read; - rev->log = ngx_http_lua_sigfd_conn->log; - rev->handler = ngx_http_lua_pipe_sigchld_event_handler; - -#ifdef HAVE_SOCKET_CLOEXEC_PATCH - rev->skip_socket_leak_check = 1; -#endif - - if (ngx_handle_read_event(rev, 0) == NGX_ERROR) { - goto failed; - } - -#if !(NGX_HTTP_LUA_HAVE_SIGNALFD) - ngx_memzero(&sa, sizeof(struct sigaction)); - sa.sa_sigaction = ngx_http_lua_pipe_sigchld_handler; - sa.sa_flags = SA_SIGINFO; - - if (sigemptyset(&sa.sa_mask) != 0) { - ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno, - "lua pipe init signal mask failed"); - goto failed; - } - - if (sigaction(SIGCHLD, &sa, NULL) == -1) { - ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno, - "lua pipe sigaction(SIGCHLD) failed"); - goto failed; - } -#endif - - return NGX_OK; - -failed: - - if (ngx_http_lua_sigfd_conn != NULL) { - ngx_close_connection(ngx_http_lua_sigfd_conn); - ngx_http_lua_sigfd_conn = NULL; - } - - if (close(ngx_http_lua_read_sigfd) == -1) { - ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, - "lua pipe close the read sigfd failed"); - } - -#if !(NGX_HTTP_LUA_HAVE_SIGNALFD) - if (close(ngx_http_lua_write_sigfd) == -1) { - ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, - "lua pipe close the write sigfd failed"); - } -#endif - - return NGX_ERROR; -} - - -static ngx_rbtree_node_t * -ngx_http_lua_pipe_lookup_pid(ngx_rbtree_key_t key) -{ - ngx_rbtree_node_t *node, *sentinel; - - node = ngx_http_lua_pipe_rbtree.root; - sentinel = ngx_http_lua_pipe_rbtree.sentinel; - - while (node != sentinel) { - if (key < node->key) { - node = node->left; - continue; - } - - if (key > node->key) { - node = node->right; - continue; - } - - return node; - } - - return NULL; -} - - -#if !(NGX_HTTP_LUA_HAVE_SIGNALFD) -static void -ngx_http_lua_pipe_sigchld_handler(int signo, siginfo_t *siginfo, - void *ucontext) -{ - ngx_err_t err, saved_err; - ngx_int_t n; - - saved_err = ngx_errno; - - for ( ;; ) { - n = write(ngx_http_lua_write_sigfd, ngx_http_lua_pipe_notification, - sizeof(ngx_http_lua_pipe_notification)); - - ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0, - "lua pipe SIGCHLD fd write siginfo:%p", siginfo); - - if (n >= 0) { - break; - } - - err = ngx_errno; - - if (err != NGX_EINTR) { - if (err != NGX_EAGAIN) { - ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, err, - "lua pipe SIGCHLD fd write failed"); - } - - break; - } - - ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, err, - "lua pipe SIGCHLD fd write was interrupted"); - } - - ngx_set_errno(saved_err); -} -#endif - - -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"); - - for ( ;; ) { -#if (NGX_HTTP_LUA_HAVE_SIGNALFD) - n = c->recv(c, (u_char *) &ngx_http_lua_pipe_notification, -#else - n = c->recv(c, ngx_http_lua_pipe_notification, -#endif - sizeof(ngx_http_lua_pipe_notification)); - - if (n <= 0) { - if (n == NGX_ERROR) { - ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, - "lua pipe SIGCHLD fd read failed"); - } - - break; - } - - for ( ;; ) { - pid = waitpid(-1, &status, WNOHANG); - - if (pid == 0) { - break; - } - - if (pid < 0) { - if (ngx_errno != NGX_ECHILD) { - ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, - "lua pipe waitpid failed"); - } - - break; - } - - /* This log is ported from Nginx's signal handler since we override - * or block it in this implementation. */ - ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0, - "signal %d (SIGCHLD) received from %P", - SIGCHLD, pid); - - 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); - } - - 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 ssize_t -ngx_http_lua_pipe_fd_read(ngx_connection_t *c, u_char *buf, size_t size) -{ - ssize_t n; - ngx_err_t err; - ngx_event_t *rev; - - rev = c->read; - - do { - n = read(c->fd, buf, size); - - err = ngx_errno; - - ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, - "read: fd:%d %z of %uz", c->fd, n, size); - - if (n == 0) { - rev->ready = 0; - rev->eof = 1; - return 0; - } - - if (n > 0) { - if ((size_t) n < size - && !(ngx_event_flags & NGX_USE_GREEDY_EVENT)) - { - rev->ready = 0; - } - - return n; - } - - if (err == NGX_EAGAIN || err == NGX_EINTR) { - ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, - "read() not ready"); - n = NGX_AGAIN; - - } else { - n = ngx_connection_error(c, err, "read() failed"); - break; - } - - } while (err == NGX_EINTR); - - rev->ready = 0; - - if (n == NGX_ERROR) { - rev->error = 1; - } - - return n; -} - - -static ssize_t -ngx_http_lua_pipe_fd_write(ngx_connection_t *c, u_char *buf, size_t size) -{ - ssize_t n; - ngx_err_t err; - ngx_event_t *wev; - - wev = c->write; - - do { - n = write(c->fd, buf, size); - - ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, - "write: fd:%d %z of %uz", c->fd, n, size); - - if (n >= 0) { - if ((size_t) n != size) { - wev->ready = 0; - } - - return n; - } - - err = ngx_errno; - - if (err == NGX_EAGAIN || err == NGX_EINTR) { - ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, - "write() not ready"); - n = NGX_AGAIN; - - } else if (err != NGX_EPIPE) { - n = ngx_connection_error(c, err, "write() failed"); - break; - } - - } while (err == NGX_EINTR); - - wev->ready = 0; - - if (n == NGX_ERROR) { - wev->error = 1; - } - - return n; -} - - -int -ngx_http_lua_ffi_pipe_spawn(ngx_http_lua_ffi_pipe_proc_t *proc, - const char *file, const char **argv, int merge_stderr, size_t buffer_size, - u_char *errbuf, size_t *errbuf_size) -{ - int rc; - int in[2]; - int out[2]; - int err[2]; - int stdin_fd, stdout_fd, stderr_fd; - int errlog_fd, temp_errlog_fd; - ngx_pid_t pid; - ssize_t pool_size; - ngx_pool_t *pool; - ngx_uint_t i; - ngx_listening_t *ls; - ngx_http_lua_pipe_t *pp; - ngx_rbtree_node_t *node; - ngx_http_lua_pipe_node_t *pipe_node; - struct sigaction sa; - ngx_http_lua_pipe_signal_t *sig; - sigset_t set; - - pool_size = ngx_align(NGX_MIN_POOL_SIZE + buffer_size * 2, - NGX_POOL_ALIGNMENT); - - pool = ngx_create_pool(pool_size, ngx_cycle->log); - if (pool == NULL) { - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "no memory") - - errbuf; - return NGX_ERROR; - } - - pp = ngx_pcalloc(pool, sizeof(ngx_http_lua_pipe_t) - + offsetof(ngx_rbtree_node_t, color) - + sizeof(ngx_http_lua_pipe_node_t)); - if (pp == NULL) { - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "no memory") - - errbuf; - goto free_pool; - } - - rc = pipe(in); - if (rc == -1) { - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "pipe failed: %s", - strerror(errno)) - - errbuf; - goto free_pool; - } - - rc = pipe(out); - if (rc == -1) { - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "pipe failed: %s", - strerror(errno)) - - errbuf; - goto close_in_fd; - } - - if (!merge_stderr) { - rc = pipe(err); - if (rc == -1) { - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, - "pipe failed: %s", strerror(errno)) - - errbuf; - goto close_in_out_fd; - } - } - - pid = fork(); - if (pid == -1) { - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "fork failed: %s", - strerror(errno)) - - errbuf; - goto close_in_out_err_fd; - } - - if (pid == 0) { - -#if (NGX_HAVE_CPU_AFFINITY) - /* reset the CPU affinity mask */ - ngx_uint_t log_level; - ngx_cpuset_t child_cpu_affinity; - - if (ngx_process == NGX_PROCESS_WORKER - && ngx_get_cpu_affinity(ngx_worker) != NULL) - { - CPU_ZERO(&child_cpu_affinity); - - for (i = 0; i < (ngx_uint_t) ngx_min(ngx_ncpu, CPU_SETSIZE); i++) { - CPU_SET(i, &child_cpu_affinity); - } - - log_level = ngx_cycle->log->log_level; - ngx_cycle->log->log_level = NGX_LOG_WARN; - ngx_setaffinity(&child_cpu_affinity, ngx_cycle->log); - ngx_cycle->log->log_level = log_level; - } -#endif - - /* reset the handler of ignored signals to the default */ - for (sig = ngx_signals; sig->signo != 0; sig++) { - ngx_memzero(&sa, sizeof(struct sigaction)); - sa.sa_handler = SIG_DFL; - - if (sigemptyset(&sa.sa_mask) != 0) { - ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, - "lua pipe child init signal mask failed"); - exit(EXIT_FAILURE); - } - - if (sigaction(sig->signo, &sa, NULL) == -1) { - ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, - "lua pipe child reset signal handler for %s " - "failed", sig->signame); - exit(EXIT_FAILURE); - } - } - - /* reset signal mask */ - if (sigemptyset(&set) != 0) { - ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, - "lua pipe child init signal set failed"); - exit(EXIT_FAILURE); - } - - if (sigprocmask(SIG_SETMASK, &set, NULL) != 0) { - ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, - "lua pipe child reset signal mask failed"); - exit(EXIT_FAILURE); - } - - /* close listening socket fd */ - ls = ngx_cycle->listening.elts; - for (i = 0; i < ngx_cycle->listening.nelts; i++) { - if (ngx_close_socket(ls[i].fd) == -1) { - ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_socket_errno, - "lua pipe child " ngx_close_socket_n - " %V failed", &ls[i].addr_text); - } - } - - /* close and dup pipefd */ - if (close(in[1]) == -1) { - ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, - "lua pipe child failed to close the in[1] " - "pipe fd"); - } - - if (close(out[0]) == -1) { - ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, - "lua pipe child failed to close the out[0] " - "pipe fd"); - } - - if (ngx_cycle->log->file && ngx_cycle->log->file->fd == STDERR_FILENO) { - errlog_fd = ngx_cycle->log->file->fd; - temp_errlog_fd = dup(errlog_fd); - - if (temp_errlog_fd == -1) { - ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, - "lua pipe child dup errlog fd failed"); - exit(EXIT_FAILURE); - } - - if (ngx_cloexec(temp_errlog_fd) == -1) { - ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, - "lua pipe child new errlog fd " ngx_cloexec_n - " failed"); - } - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "lua pipe child dup old errlog fd %d to new fd %d", - ngx_cycle->log->file->fd, temp_errlog_fd); - - ngx_cycle->log->file->fd = temp_errlog_fd; - } - - if (dup2(in[0], STDIN_FILENO) == -1) { - ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, - "lua pipe child dup2 stdin failed"); - exit(EXIT_FAILURE); - } - - if (dup2(out[1], STDOUT_FILENO) == -1) { - ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, - "lua pipe child dup2 stdout failed"); - exit(EXIT_FAILURE); - } - - if (merge_stderr) { - if (dup2(STDOUT_FILENO, STDERR_FILENO) == -1) { - ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, - "lua pipe child dup2 stderr failed"); - exit(EXIT_FAILURE); - } - - } else { - if (close(err[0]) == -1) { - ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, - "lua pipe child failed to close the err[0] " - "pipe fd"); - } - - if (dup2(err[1], STDERR_FILENO) == -1) { - ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, - "lua pipe child dup2 stderr failed"); - exit(EXIT_FAILURE); - } - } - - if (execvp(file, (char * const *) argv) == -1) { - ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, - "lua pipe child execvp() failed while executing %s", - file); - } - - exit(EXIT_FAILURE); - } - - /* parent process */ - if (close(in[0]) == -1) { - ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, - "lua pipe: failed to close the in[0] pipe fd"); - } - - stdin_fd = in[1]; - - if (ngx_nonblocking(stdin_fd) == -1) { - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, - ngx_nonblocking_n " failed: %s", - strerror(errno)) - - errbuf; - goto close_in_out_err_fd; - } - - pp->stdin_fd = stdin_fd; - - if (close(out[1]) == -1) { - ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, - "lua pipe: failed to close the out[1] pipe fd"); - } - - stdout_fd = out[0]; - - if (ngx_nonblocking(stdout_fd) == -1) { - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, - ngx_nonblocking_n " failed: %s", - strerror(errno)) - - errbuf; - goto close_in_out_err_fd; - } - - pp->stdout_fd = stdout_fd; - - if (!merge_stderr) { - if (close(err[1]) == -1) { - ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, - "lua pipe: failed to close the err[1] pipe fd"); - } - - stderr_fd = err[0]; - - if (ngx_nonblocking(stderr_fd) == -1) { - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, - ngx_nonblocking_n " failed: %s", - strerror(errno)) - - errbuf; - goto close_in_out_err_fd; - } - - pp->stderr_fd = stderr_fd; - } - - node = (ngx_rbtree_node_t *) (pp + 1); - node->key = pid; - pipe_node = (ngx_http_lua_pipe_node_t *) &node->color; - pipe_node->proc = proc; - ngx_rbtree_insert(&ngx_http_lua_pipe_rbtree, node); - - pp->node = node; - pp->pool = pool; - pp->merge_stderr = merge_stderr; - pp->buffer_size = buffer_size; - - proc->_pid = pid; - proc->write_timeout = 10000; - proc->stdout_read_timeout = 10000; - proc->stderr_read_timeout = 10000; - proc->wait_timeout = 10000; - proc->pipe = pp; - - ngx_log_debug4(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "lua pipe spawn process:%p pid:%P merge_stderr:%d " - "buffer_size:%uz", proc, pid, merge_stderr, buffer_size); - return NGX_OK; - -close_in_out_err_fd: - - if (!merge_stderr) { - if (close(err[0]) == -1) { - ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, - "failed to close the err[0] pipe fd"); - } - - if (close(err[1]) == -1) { - ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, - "failed to close the err[1] pipe fd"); - } - } - -close_in_out_fd: - - if (close(out[0]) == -1) { - ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, - "failed to close the out[0] pipe fd"); - } - - if (close(out[1]) == -1) { - ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, - "failed to close the out[1] pipe fd"); - } - -close_in_fd: - - if (close(in[0]) == -1) { - ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, - "failed to close the in[0] pipe fd"); - } - - if (close(in[1]) == -1) { - ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, - "failed to close the in[1] pipe fd"); - } - -free_pool: - - ngx_destroy_pool(pool); - return NGX_ERROR; -} - - -static ngx_int_t -ngx_http_lua_pipe_close_helper(ngx_http_lua_pipe_ctx_t *pipe_ctx, - ngx_event_t *ev, int forced) -{ - if (ev->handler != ngx_http_lua_pipe_dummy_event_handler && !forced) { - ngx_log_debug3(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "lua pipe cannot close fd:%d without " - "forced pipe:%p ev:%p", pipe_ctx->c->fd, pipe_ctx, ev); - return NGX_ERROR; - } - - ngx_close_connection(pipe_ctx->c); - pipe_ctx->c = NULL; - - return NGX_OK; -} - - -static ngx_int_t -ngx_http_lua_pipe_close_stdin(ngx_http_lua_pipe_t *pipe, int forced) -{ - ngx_event_t *wev; - - if (pipe->stdin_ctx == NULL) { - if (pipe->stdin_fd != -1) { - if (close(pipe->stdin_fd) == -1) { - ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, - "failed to close the stdin pipe fd"); - } - - pipe->stdin_fd = -1; - } - - } else if (pipe->stdin_ctx->c != NULL) { - wev = pipe->stdin_ctx->c->write; - return ngx_http_lua_pipe_close_helper(pipe->stdin_ctx, wev, forced); - } - - return NGX_OK; -} - - -static ngx_int_t -ngx_http_lua_pipe_close_stdout(ngx_http_lua_pipe_t *pipe, int forced) -{ - ngx_event_t *rev; - - if (pipe->stdout_ctx == NULL) { - if (pipe->stdout_fd != -1) { - if (close(pipe->stdout_fd) == -1) { - ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, - "failed to close the stdout pipe fd"); - } - - pipe->stdout_fd = -1; - } - - } else if (pipe->stdout_ctx->c != NULL) { - rev = pipe->stdout_ctx->c->read; - return ngx_http_lua_pipe_close_helper(pipe->stdout_ctx, rev, forced); - } - - return NGX_OK; -} - - -static ngx_int_t -ngx_http_lua_pipe_close_stderr(ngx_http_lua_pipe_t *pipe, int forced) -{ - ngx_event_t *rev; - - if (pipe->stderr_ctx == NULL) { - if (pipe->stderr_fd != -1) { - if (close(pipe->stderr_fd) == -1) { - ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, - "failed to close the stderr pipe fd"); - } - - pipe->stderr_fd = -1; - } - - } else if (pipe->stderr_ctx->c != NULL) { - rev = pipe->stderr_ctx->c->read; - return ngx_http_lua_pipe_close_helper(pipe->stderr_ctx, rev, forced); - } - - return NGX_OK; -} - - -int -ngx_http_lua_ffi_pipe_proc_shutdown_stdin(ngx_http_lua_ffi_pipe_proc_t *proc, - u_char *errbuf, size_t *errbuf_size) -{ - ngx_int_t rc; - ngx_http_lua_pipe_t *pipe; - - pipe = proc->pipe; - if (pipe == NULL || pipe->closed) { - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "closed") - errbuf; - return NGX_ERROR; - } - - rc = ngx_http_lua_pipe_close_stdin(pipe, 0); - if (rc != NGX_OK) { - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "pipe busy writing") - - errbuf; - return NGX_ERROR; - } - - return NGX_OK; -} - - -int -ngx_http_lua_ffi_pipe_proc_shutdown_stdout(ngx_http_lua_ffi_pipe_proc_t *proc, - u_char *errbuf, size_t *errbuf_size) -{ - ngx_int_t rc; - ngx_http_lua_pipe_t *pipe; - - pipe = proc->pipe; - if (pipe == NULL || pipe->closed) { - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "closed") - errbuf; - return NGX_ERROR; - } - - rc = ngx_http_lua_pipe_close_stdout(pipe, 0); - if (rc != NGX_OK) { - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "pipe busy reading") - - errbuf; - return NGX_ERROR; - } - - return NGX_OK; -} - - -int -ngx_http_lua_ffi_pipe_proc_shutdown_stderr(ngx_http_lua_ffi_pipe_proc_t *proc, - u_char *errbuf, size_t *errbuf_size) -{ - ngx_http_lua_pipe_t *pipe; - - pipe = proc->pipe; - if (pipe == NULL || pipe->closed) { - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "closed") - errbuf; - return NGX_ERROR; - } - - if (pipe->merge_stderr) { - /* stdout is used internally as stderr when merge_stderr is true */ - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "merged to stdout") - - errbuf; - return NGX_ERROR; - } - - if (ngx_http_lua_pipe_close_stderr(pipe, 0) != NGX_OK) { - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "pipe busy reading") - - errbuf; - return NGX_ERROR; - } - - return NGX_OK; -} - - -static void -ngx_http_lua_pipe_proc_finalize(ngx_http_lua_ffi_pipe_proc_t *proc, int forced) -{ - ngx_http_lua_pipe_t *pipe; - - ngx_log_debug3(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "lua pipe finalize process:%p pid:%P forced:%d", proc, - proc->_pid, forced); - pipe = proc->pipe; - - if (pipe->node) { - ngx_rbtree_delete(&ngx_http_lua_pipe_rbtree, pipe->node); - pipe->node = NULL; - } - - pipe->dead = 1; - - ngx_http_lua_pipe_close_stdin(pipe, forced); - ngx_http_lua_pipe_close_stdout(pipe, forced); - - if (!pipe->merge_stderr) { - ngx_http_lua_pipe_close_stderr(pipe, forced); - } - - pipe->closed = 1; -} - - -void -ngx_http_lua_ffi_pipe_proc_destroy(ngx_http_lua_ffi_pipe_proc_t *proc) -{ - ngx_http_lua_pipe_t *pipe; - - pipe = proc->pipe; - if (pipe == NULL) { - return; - } - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "lua pipe destroy process:%p pid:%P", proc, proc->_pid); - - if (!pipe->dead) { - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "lua pipe kill process:%p pid:%P", proc, proc->_pid); - - if (kill(proc->_pid, SIGKILL) == -1) { - if (ngx_errno != ESRCH) { - ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, - "lua pipe failed to kill process:%p pid:%P"); - } - } - } - - ngx_http_lua_pipe_proc_finalize(proc, 1); - ngx_destroy_pool(pipe->pool); - proc->pipe = NULL; -} - - -static ngx_int_t -ngx_http_lua_pipe_get_lua_ctx(ngx_http_request_t *r, - ngx_http_lua_ctx_t **ctx, u_char *errbuf, size_t *errbuf_size) -{ - int rc; - - *ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); - if (ctx == NULL) { - return NGX_HTTP_LUA_FFI_NO_REQ_CTX; - } - - rc = ngx_http_lua_ffi_check_context(*ctx, NGX_HTTP_LUA_CONTEXT_REWRITE - | NGX_HTTP_LUA_CONTEXT_ACCESS - | NGX_HTTP_LUA_CONTEXT_CONTENT - | NGX_HTTP_LUA_CONTEXT_TIMER - | NGX_HTTP_LUA_CONTEXT_SSL_CERT - | NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH, - errbuf, errbuf_size); - if (rc != NGX_OK) { - return NGX_HTTP_LUA_FFI_BAD_CONTEXT; - } - - return NGX_OK; -} - - -static void -ngx_http_lua_pipe_put_error(ngx_http_lua_pipe_ctx_t *pipe_ctx, u_char *errbuf, - size_t *errbuf_size) -{ - switch (pipe_ctx->err_type) { - - case PIPE_ERR_CLOSED: - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "closed") - errbuf; - break; - - case PIPE_ERR_SYSCALL: - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "%s", - strerror(pipe_ctx->pipe_errno)) - - errbuf; - break; - - case PIPE_ERR_NOMEM: - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "no memory") - - errbuf; - break; - - case PIPE_ERR_TIMEOUT: - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "timeout") - - errbuf; - break; - - case PIPE_ERR_ADD_READ_EV: - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, - "failed to add read event") - - errbuf; - break; - - case PIPE_ERR_ADD_WRITE_EV: - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, - "failed to add write event") - - errbuf; - break; - - default: - ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, - "unexpected err type: %d", pipe_ctx->err_type); - ngx_http_lua_assert(NULL); - } -} - - -static void -ngx_http_lua_pipe_put_data(ngx_http_lua_pipe_t *pipe, - ngx_http_lua_pipe_ctx_t *pipe_ctx, u_char **buf, size_t *buf_size) -{ - size_t size = 0; - size_t chunk_size; - size_t nbufs; - u_char *p; - ngx_buf_t *b; - ngx_chain_t *cl; - ngx_chain_t **ll; - - nbufs = 0; - ll = NULL; - - for (cl = pipe_ctx->bufs_in; cl; cl = cl->next) { - b = cl->buf; - chunk_size = b->last - b->pos; - - if (cl->next) { - ll = &cl->next; - } - - size += chunk_size; - - nbufs++; - } - - if (*buf_size < size) { - *buf = NULL; - *buf_size = size; - - return; - } - - *buf_size = size; - - p = *buf; - for (cl = pipe_ctx->bufs_in; cl; cl = cl->next) { - b = cl->buf; - chunk_size = b->last - b->pos; - p = ngx_cpymem(p, b->pos, chunk_size); - } - - if (nbufs > 1 && ll) { - *ll = pipe->free_bufs; - pipe->free_bufs = pipe_ctx->bufs_in; - pipe_ctx->bufs_in = pipe_ctx->buf_in; - } - - if (pipe_ctx->buffer.pos == pipe_ctx->buffer.last) { - pipe_ctx->buffer.pos = pipe_ctx->buffer.start; - pipe_ctx->buffer.last = pipe_ctx->buffer.start; - } - - if (pipe_ctx->bufs_in) { - pipe_ctx->buf_in->buf->last = pipe_ctx->buffer.pos; - pipe_ctx->buf_in->buf->pos = pipe_ctx->buffer.pos; - } -} - - -static ngx_int_t -ngx_http_lua_pipe_add_input_buffer(ngx_http_lua_pipe_t *pipe, - ngx_http_lua_pipe_ctx_t *pipe_ctx) -{ - ngx_chain_t *cl; - - cl = ngx_http_lua_chain_get_free_buf(ngx_cycle->log, pipe->pool, - &pipe->free_bufs, - pipe->buffer_size); - - if (cl == NULL) { - pipe_ctx->err_type = PIPE_ERR_NOMEM; - return NGX_ERROR; - } - - pipe_ctx->buf_in->next = cl; - pipe_ctx->buf_in = cl; - pipe_ctx->buffer = *cl->buf; - - return NGX_OK; -} - - -static ngx_int_t -ngx_http_lua_pipe_read_all(void *data, ssize_t bytes) -{ - ngx_http_lua_pipe_ctx_t *pipe_ctx = data; - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, "lua pipe read all"); - return ngx_http_lua_read_all(&pipe_ctx->buffer, pipe_ctx->buf_in, bytes, - ngx_cycle->log); -} - - -static ngx_int_t -ngx_http_lua_pipe_read_bytes(void *data, ssize_t bytes) -{ - ngx_int_t rc; - ngx_http_lua_pipe_ctx_t *pipe_ctx = data; - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "lua pipe read bytes %z", bytes); - - rc = ngx_http_lua_read_bytes(&pipe_ctx->buffer, pipe_ctx->buf_in, - &pipe_ctx->rest, bytes, ngx_cycle->log); - if (rc == NGX_ERROR) { - pipe_ctx->err_type = PIPE_ERR_CLOSED; - return NGX_ERROR; - } - - return rc; -} - - -static ngx_int_t -ngx_http_lua_pipe_read_line(void *data, ssize_t bytes) -{ - ngx_int_t rc; - ngx_http_lua_pipe_ctx_t *pipe_ctx = data; - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "lua pipe read line"); - rc = ngx_http_lua_read_line(&pipe_ctx->buffer, pipe_ctx->buf_in, bytes, - ngx_cycle->log); - if (rc == NGX_ERROR) { - pipe_ctx->err_type = PIPE_ERR_CLOSED; - return NGX_ERROR; - } - - return rc; -} - - -static ngx_int_t -ngx_http_lua_pipe_read_any(void *data, ssize_t bytes) -{ - ngx_int_t rc; - ngx_http_lua_pipe_ctx_t *pipe_ctx = data; - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, "lua pipe read any"); - rc = ngx_http_lua_read_any(&pipe_ctx->buffer, pipe_ctx->buf_in, - &pipe_ctx->rest, bytes, ngx_cycle->log); - if (rc == NGX_ERROR) { - pipe_ctx->err_type = PIPE_ERR_CLOSED; - return NGX_ERROR; - } - - return rc; -} - - -static ngx_int_t -ngx_http_lua_pipe_read(ngx_http_lua_pipe_t *pipe, - ngx_http_lua_pipe_ctx_t *pipe_ctx) -{ - int rc; - int read; - size_t size; - ssize_t n; - ngx_buf_t *b; - ngx_event_t *rev; - ngx_connection_t *c; - - c = pipe_ctx->c; - rev = c->read; - b = &pipe_ctx->buffer; - read = 0; - - for ( ;; ) { - size = b->last - b->pos; - - if (size || pipe_ctx->eof) { - rc = pipe_ctx->input_filter(pipe_ctx->input_filter_ctx, size); - if (rc == NGX_ERROR) { - return NGX_ERROR; - } - - if (rc == NGX_OK) { - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "lua pipe read done pipe:%p", pipe_ctx); - return NGX_OK; - } - - /* rc == NGX_AGAIN */ - continue; - } - - if (read && !rev->ready) { - break; - } - - size = b->end - b->last; - - if (size == 0) { - rc = ngx_http_lua_pipe_add_input_buffer(pipe, pipe_ctx); - if (rc == NGX_ERROR) { - return NGX_ERROR; - } - - b = &pipe_ctx->buffer; - size = (size_t) (b->end - b->last); - } - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "lua pipe try to read data %uz pipe:%p", - size, pipe_ctx); - - n = c->recv(c, b->last, size); - read = 1; - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "lua pipe read data returned %z pipe:%p", n, pipe_ctx); - - if (n == NGX_AGAIN) { - break; - } - - if (n == 0) { - pipe_ctx->eof = 1; - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "lua pipe closed pipe:%p", pipe_ctx); - continue; - } - - if (n == NGX_ERROR) { - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, ngx_errno, - "lua pipe read data error pipe:%p", pipe_ctx); - - pipe_ctx->err_type = PIPE_ERR_SYSCALL; - pipe_ctx->pipe_errno = ngx_errno; - return NGX_ERROR; - } - - b->last += n; - } - - return NGX_AGAIN; -} - - -static ngx_int_t -ngx_http_lua_pipe_init_ctx(ngx_http_lua_pipe_ctx_t **pipe_ctx_pt, int fd, - ngx_pool_t *pool, u_char *errbuf, size_t *errbuf_size) -{ - ngx_connection_t *c; - - if (fd == -1) { - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "closed") - errbuf; - return NGX_ERROR; - } - - *pipe_ctx_pt = ngx_pcalloc(pool, sizeof(ngx_http_lua_pipe_ctx_t)); - if (*pipe_ctx_pt == NULL) { - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "no memory") - - errbuf; - return NGX_ERROR; - } - - c = ngx_get_connection(fd, ngx_cycle->log); - if (c == NULL) { - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "no connection") - - errbuf; - return NGX_ERROR; - } - - c->log = ngx_cycle->log; - c->recv = ngx_http_lua_pipe_fd_read; - c->read->handler = ngx_http_lua_pipe_dummy_event_handler; - c->read->log = c->log; - -#ifdef HAVE_SOCKET_CLOEXEC_PATCH - c->read->skip_socket_leak_check = 1; -#endif - - c->send = ngx_http_lua_pipe_fd_write; - c->write->handler = ngx_http_lua_pipe_dummy_event_handler; - c->write->log = c->log; - (*pipe_ctx_pt)->c = c; - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "lua pipe init pipe ctx:%p fd:*%d", *pipe_ctx_pt, fd); - - return NGX_OK; -} - - -int -ngx_http_lua_ffi_pipe_proc_read(ngx_http_request_t *r, - ngx_http_lua_ffi_pipe_proc_t *proc, int from_stderr, int reader_type, - size_t length, u_char **buf, size_t *buf_size, u_char *errbuf, - size_t *errbuf_size) -{ - int rc; - ngx_msec_t timeout; - ngx_event_t *rev; - ngx_connection_t *c; - ngx_http_lua_ctx_t *ctx; - ngx_http_lua_pipe_t *pipe; - ngx_http_lua_co_ctx_t *wait_co_ctx; - ngx_http_lua_pipe_ctx_t *pipe_ctx; - - rc = ngx_http_lua_pipe_get_lua_ctx(r, &ctx, errbuf, errbuf_size); - if (rc != NGX_OK) { - return rc; - } - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua pipe read process:%p pid:%P", proc, proc->_pid); - - pipe = proc->pipe; - if (pipe == NULL || pipe->closed) { - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "closed") - errbuf; - return NGX_ERROR; - } - - if (pipe->merge_stderr && from_stderr) { - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "merged to stdout") - - errbuf; - return NGX_ERROR; - } - - if (from_stderr) { - if (pipe->stderr_ctx == NULL) { - if (ngx_http_lua_pipe_init_ctx(&pipe->stderr_ctx, pipe->stderr_fd, - pipe->pool, errbuf, - errbuf_size) - != NGX_OK) - { - return NGX_ERROR; - } - - } else { - pipe->stderr_ctx->err_type = 0; - } - - pipe_ctx = pipe->stderr_ctx; - - } else { - if (pipe->stdout_ctx == NULL) { - if (ngx_http_lua_pipe_init_ctx(&pipe->stdout_ctx, pipe->stdout_fd, - pipe->pool, errbuf, - errbuf_size) - != NGX_OK) - { - return NGX_ERROR; - } - - } else { - pipe->stdout_ctx->err_type = 0; - } - - pipe_ctx = pipe->stdout_ctx; - } - - c = pipe_ctx->c; - if (c == NULL) { - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "closed") - errbuf; - return NGX_ERROR; - } - - rev = c->read; - if (rev->handler != ngx_http_lua_pipe_dummy_event_handler) { - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "pipe busy reading") - - errbuf; - return NGX_ERROR; - } - - pipe_ctx->input_filter_ctx = pipe_ctx; - - switch (reader_type) { - - case PIPE_READ_ALL: - pipe_ctx->input_filter = ngx_http_lua_pipe_read_all; - break; - - case PIPE_READ_BYTES: - pipe_ctx->input_filter = ngx_http_lua_pipe_read_bytes; - break; - - case PIPE_READ_LINE: - pipe_ctx->input_filter = ngx_http_lua_pipe_read_line; - break; - - case PIPE_READ_ANY: - pipe_ctx->input_filter = ngx_http_lua_pipe_read_any; - break; - - default: - ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, - "unexpected reader_type: %d", reader_type); - ngx_http_lua_assert(NULL); - } - - pipe_ctx->rest = length; - - if (pipe_ctx->bufs_in == NULL) { - pipe_ctx->bufs_in = - ngx_http_lua_chain_get_free_buf(ngx_cycle->log, pipe->pool, - &pipe->free_bufs, - pipe->buffer_size); - - if (pipe_ctx->bufs_in == NULL) { - pipe_ctx->err_type = PIPE_ERR_NOMEM; - goto error; - } - - pipe_ctx->buf_in = pipe_ctx->bufs_in; - pipe_ctx->buffer = *pipe_ctx->buf_in->buf; - } - - rc = ngx_http_lua_pipe_read(pipe, pipe_ctx); - if (rc == NGX_ERROR) { - goto error; - } - - if (rc == NGX_OK) { - ngx_http_lua_pipe_put_data(pipe, pipe_ctx, buf, buf_size); - return NGX_OK; - } - - /* rc == NGX_AGAIN */ - wait_co_ctx = ctx->cur_co_ctx; - - c->data = wait_co_ctx; - if (ngx_handle_read_event(rev, 0) != NGX_OK) { - pipe_ctx->err_type = PIPE_ERR_ADD_READ_EV; - goto error; - } - - wait_co_ctx->data = proc; - - if (from_stderr) { - rev->handler = ngx_http_lua_pipe_resume_read_stderr_handler; - wait_co_ctx->cleanup = ngx_http_lua_pipe_proc_read_stderr_cleanup; - timeout = proc->stderr_read_timeout; - - } else { - rev->handler = ngx_http_lua_pipe_resume_read_stdout_handler; - wait_co_ctx->cleanup = ngx_http_lua_pipe_proc_read_stdout_cleanup; - timeout = proc->stdout_read_timeout; - } - - if (timeout > 0) { - ngx_add_timer(rev, timeout); - ngx_log_debug5(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua pipe add timer for reading: %d(ms) process:%p " - "pid:%P pipe:%p ev:%p", timeout, proc, proc->_pid, pipe, - rev); - } - - ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua pipe read yielding process:%p pid:%P pipe:%p", proc, - proc->_pid, pipe); - - return NGX_AGAIN; - -error: - - if (pipe_ctx->bufs_in) { - ngx_http_lua_pipe_put_data(pipe, pipe_ctx, buf, buf_size); - ngx_http_lua_pipe_put_error(pipe_ctx, errbuf, errbuf_size); - return NGX_DECLINED; - } - - ngx_http_lua_pipe_put_error(pipe_ctx, errbuf, errbuf_size); - - return NGX_ERROR; -} - - -/* - * ngx_http_lua_ffi_pipe_get_read_result should only be called just after - * ngx_http_lua_ffi_pipe_proc_read, so we omit most of the sanity check already - * done in ngx_http_lua_ffi_pipe_proc_read. - */ -int -ngx_http_lua_ffi_pipe_get_read_result(ngx_http_request_t *r, - ngx_http_lua_ffi_pipe_proc_t *proc, int from_stderr, u_char **buf, - size_t *buf_size, u_char *errbuf, size_t *errbuf_size) -{ - ngx_http_lua_pipe_t *pipe; - ngx_http_lua_pipe_ctx_t *pipe_ctx; - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua pipe get read result process:%p pid:%P", proc, - proc->_pid); - - pipe = proc->pipe; - pipe_ctx = from_stderr ? pipe->stderr_ctx : pipe->stdout_ctx; - - if (!pipe_ctx->err_type) { - ngx_http_lua_pipe_put_data(pipe, pipe_ctx, buf, buf_size); - return NGX_OK; - } - - if (pipe_ctx->bufs_in) { - ngx_http_lua_pipe_put_data(pipe, pipe_ctx, buf, buf_size); - ngx_http_lua_pipe_put_error(pipe_ctx, errbuf, errbuf_size); - return NGX_DECLINED; - } - - ngx_http_lua_pipe_put_error(pipe_ctx, errbuf, errbuf_size); - - return NGX_ERROR; -} - - -static ngx_int_t -ngx_http_lua_pipe_write(ngx_http_lua_pipe_t *pipe, - ngx_http_lua_pipe_ctx_t *pipe_ctx) -{ - size_t size; - ngx_int_t n; - ngx_buf_t *b; - ngx_connection_t *c; - - c = pipe_ctx->c; - b = pipe_ctx->buf_in->buf; - - for ( ;; ) { - size = b->last - b->pos; - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "lua pipe try to write data %uz pipe:%p", size, - pipe_ctx); - - n = c->send(c, b->pos, size); - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "lua pipe write returned %i pipe:%p", n, pipe_ctx); - - if (n >= 0) { - b->pos += n; - - if (b->pos == b->last) { - b->pos = b->start; - b->last = b->start; - - if (!pipe->free_bufs) { - pipe->free_bufs = pipe_ctx->buf_in; - - } else { - pipe->free_bufs->next = pipe_ctx->buf_in; - } - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "lua pipe write done pipe:%p", pipe_ctx); - return NGX_OK; - } - - continue; - } - - /* NGX_ERROR || NGX_AGAIN */ - break; - } - - if (n == NGX_ERROR) { - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, ngx_errno, - "lua pipe write data error pipe:%p", pipe_ctx); - - if (ngx_errno == NGX_EPIPE) { - pipe_ctx->err_type = PIPE_ERR_CLOSED; - - } else { - pipe_ctx->err_type = PIPE_ERR_SYSCALL; - pipe_ctx->pipe_errno = ngx_errno; - } - - return NGX_ERROR; - } - - return NGX_AGAIN; -} - - -ssize_t -ngx_http_lua_ffi_pipe_proc_write(ngx_http_request_t *r, - ngx_http_lua_ffi_pipe_proc_t *proc, const u_char *data, size_t len, - u_char *errbuf, size_t *errbuf_size) -{ - int rc; - ngx_buf_t *b; - ngx_msec_t timeout; - ngx_chain_t *cl; - ngx_event_t *wev; - ngx_http_lua_ctx_t *ctx; - ngx_http_lua_pipe_t *pipe; - ngx_http_lua_co_ctx_t *wait_co_ctx; - ngx_http_lua_pipe_ctx_t *pipe_ctx; - - rc = ngx_http_lua_pipe_get_lua_ctx(r, &ctx, errbuf, errbuf_size); - if (rc != NGX_OK) { - return rc; - } - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua pipe write process:%p pid:%P", proc, proc->_pid); - - pipe = proc->pipe; - if (pipe == NULL || pipe->closed) { - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "closed") - errbuf; - return NGX_ERROR; - } - - if (pipe->stdin_ctx == NULL) { - if (ngx_http_lua_pipe_init_ctx(&pipe->stdin_ctx, pipe->stdin_fd, - pipe->pool, errbuf, - errbuf_size) - != NGX_OK) - { - return NGX_ERROR; - } - - } else { - pipe->stdin_ctx->err_type = 0; - } - - pipe_ctx = pipe->stdin_ctx; - if (pipe_ctx->c == NULL) { - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "closed") - errbuf; - return NGX_ERROR; - } - - wev = pipe_ctx->c->write; - if (wev->handler != ngx_http_lua_pipe_dummy_event_handler) { - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "pipe busy writing") - - errbuf; - return NGX_ERROR; - } - - pipe_ctx->rest = len; - - cl = ngx_http_lua_chain_get_free_buf(ngx_cycle->log, pipe->pool, - &pipe->free_bufs, len); - if (cl == NULL) { - pipe_ctx->err_type = PIPE_ERR_NOMEM; - goto error; - } - - pipe_ctx->buf_in = cl; - b = pipe_ctx->buf_in->buf; - b->last = ngx_copy(b->last, data, len); - - rc = ngx_http_lua_pipe_write(pipe, pipe_ctx); - if (rc == NGX_ERROR) { - goto error; - } - - if (rc == NGX_OK) { - return len; - } - - /* rc == NGX_AGAIN */ - wait_co_ctx = ctx->cur_co_ctx; - pipe_ctx->c->data = wait_co_ctx; - - wev->handler = ngx_http_lua_pipe_resume_write_handler; - if (ngx_handle_write_event(wev, 0) != NGX_OK) { - pipe_ctx->err_type = PIPE_ERR_ADD_WRITE_EV; - goto error; - } - - wait_co_ctx->data = proc; - wait_co_ctx->cleanup = ngx_http_lua_pipe_proc_write_cleanup; - timeout = proc->write_timeout; - - if (timeout > 0) { - ngx_add_timer(wev, timeout); - ngx_log_debug5(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua pipe add timer for writing: %d(ms) process:%p " - "pid:%P pipe:%p ev:%p", timeout, proc, proc->_pid, pipe, - wev); - } - - ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua pipe write yielding process:%p pid:%P pipe:%p", proc, - proc->_pid, pipe); - - return NGX_AGAIN; - -error: - - ngx_http_lua_pipe_put_error(pipe_ctx, errbuf, errbuf_size); - return NGX_ERROR; -} - - -/* - * ngx_http_lua_ffi_pipe_get_write_result should only be called just after - * ngx_http_lua_ffi_pipe_proc_write, so we omit most of the sanity check - * already done in ngx_http_lua_ffi_pipe_proc_write. - */ -ssize_t -ngx_http_lua_ffi_pipe_get_write_result(ngx_http_request_t *r, - ngx_http_lua_ffi_pipe_proc_t *proc, u_char *errbuf, size_t *errbuf_size) -{ - ngx_http_lua_pipe_t *pipe; - ngx_http_lua_pipe_ctx_t *pipe_ctx; - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua pipe get write result process:%p pid:%P", proc, - proc->_pid); - - pipe = proc->pipe; - pipe_ctx = pipe->stdin_ctx; - - if (pipe_ctx->err_type) { - ngx_http_lua_pipe_put_error(pipe_ctx, errbuf, errbuf_size); - return NGX_ERROR; - } - - return pipe_ctx->rest; -} - - -int -ngx_http_lua_ffi_pipe_proc_wait(ngx_http_request_t *r, - ngx_http_lua_ffi_pipe_proc_t *proc, char **reason, int *status, - u_char *errbuf, size_t *errbuf_size) -{ - int rc; - ngx_rbtree_node_t *node; - ngx_http_lua_ctx_t *ctx; - ngx_http_lua_pipe_t *pipe; - ngx_http_lua_co_ctx_t *wait_co_ctx; - ngx_http_lua_pipe_node_t *pipe_node; - - rc = ngx_http_lua_pipe_get_lua_ctx(r, &ctx, errbuf, errbuf_size); - if (rc != NGX_OK) { - return rc; - } - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua pipe wait process:%p pid:%P", proc, proc->_pid); - - pipe = proc->pipe; - if (pipe == NULL || pipe->closed) { - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "exited") - errbuf; - return NGX_ERROR; - } - - node = pipe->node; - pipe_node = (ngx_http_lua_pipe_node_t *) &node->color; - if (pipe_node->wait_co_ctx) { - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "pipe busy waiting") - - errbuf; - return NGX_ERROR; - } - - if (pipe_node->reason_code == REASON_RUNNING_CODE) { - wait_co_ctx = ctx->cur_co_ctx; - wait_co_ctx->data = proc; - ngx_memzero(&wait_co_ctx->sleep, sizeof(ngx_event_t)); - wait_co_ctx->sleep.handler = ngx_http_lua_pipe_resume_wait_handler; - wait_co_ctx->sleep.data = wait_co_ctx; - wait_co_ctx->sleep.log = r->connection->log; - wait_co_ctx->cleanup = ngx_http_lua_pipe_proc_wait_cleanup; - - pipe_node->wait_co_ctx = wait_co_ctx; - - if (proc->wait_timeout > 0) { - ngx_add_timer(&wait_co_ctx->sleep, proc->wait_timeout); - ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua pipe add timer for waiting: %d(ms) process:%p " - "pid:%P ev:%p", proc->wait_timeout, proc, - proc->_pid, &wait_co_ctx->sleep); - } - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua pipe wait yielding process:%p pid:%P", proc, - proc->_pid); - - return NGX_AGAIN; - } - - *status = pipe_node->status; - - switch (pipe_node->reason_code) { - - case REASON_EXIT_CODE: - *reason = REASON_EXIT; - break; - - case REASON_SIGNAL_CODE: - *reason = REASON_SIGNAL; - break; - - default: - *reason = REASON_UNKNOWN; - } - - ngx_http_lua_pipe_proc_finalize(proc, 0); - - if (*status == 0) { - return NGX_OK; - } - - return NGX_DECLINED; -} - - -int -ngx_http_lua_ffi_pipe_proc_kill(ngx_http_lua_ffi_pipe_proc_t *proc, int signal, - u_char *errbuf, size_t *errbuf_size) -{ - ngx_pid_t pid; - ngx_http_lua_pipe_t *pipe; - - pipe = proc->pipe; - - if (pipe == NULL || pipe->dead) { - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "exited") - errbuf; - return NGX_ERROR; - } - - pid = proc->_pid; - - if (kill(pid, signal) == -1) { - switch (ngx_errno) { - case EINVAL: - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "invalid signal") - - errbuf; - break; - - case ESRCH: - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "exited") - - errbuf; - break; - - default: - *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "%s", - strerror(ngx_errno)) - - errbuf; - } - - return NGX_ERROR; - } - - return NGX_OK; -} - - -static int -ngx_http_lua_pipe_read_stdout_retval(ngx_http_lua_ffi_pipe_proc_t *proc, - lua_State *L) -{ - return ngx_http_lua_pipe_read_retval_helper(proc, L, 0); -} - - -static int -ngx_http_lua_pipe_read_stderr_retval(ngx_http_lua_ffi_pipe_proc_t *proc, - lua_State *L) -{ - return ngx_http_lua_pipe_read_retval_helper(proc, L, 1); -} - - -static int -ngx_http_lua_pipe_read_retval_helper(ngx_http_lua_ffi_pipe_proc_t *proc, - lua_State *L, int from_stderr) -{ - int rc; - ngx_msec_t timeout; - ngx_event_t *rev; - ngx_http_lua_pipe_t *pipe; - ngx_http_lua_pipe_ctx_t *pipe_ctx; - - pipe = proc->pipe; - if (from_stderr) { - pipe_ctx = pipe->stderr_ctx; - - } else { - pipe_ctx = pipe->stdout_ctx; - } - - if (pipe->timeout) { - pipe->timeout = 0; - pipe_ctx->err_type = PIPE_ERR_TIMEOUT; - return 0; - } - - rc = ngx_http_lua_pipe_read(pipe, pipe_ctx); - if (rc != NGX_AGAIN) { - return 0; - } - - rev = pipe_ctx->c->read; - - if (from_stderr) { - rev->handler = ngx_http_lua_pipe_resume_read_stderr_handler; - timeout = proc->stderr_read_timeout; - - } else { - rev->handler = ngx_http_lua_pipe_resume_read_stdout_handler; - timeout = proc->stdout_read_timeout; - } - - if (timeout > 0) { - ngx_add_timer(rev, timeout); - ngx_log_debug5(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "lua pipe add timer for reading: %d(ms) proc:%p " - "pid:%P pipe:%p ev:%p", timeout, proc, proc->_pid, pipe, - rev); - } - - ngx_log_debug3(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "lua pipe read yielding process:%p pid:%P pipe:%p", proc, - proc->_pid, pipe); - - return NGX_AGAIN; -} - - -static int -ngx_http_lua_pipe_write_retval(ngx_http_lua_ffi_pipe_proc_t *proc, - lua_State *L) -{ - int rc; - ngx_msec_t timeout; - ngx_event_t *wev; - ngx_http_lua_pipe_t *pipe; - ngx_http_lua_pipe_ctx_t *pipe_ctx; - - pipe = proc->pipe; - pipe_ctx = pipe->stdin_ctx; - - if (pipe->timeout) { - pipe->timeout = 0; - pipe_ctx->err_type = PIPE_ERR_TIMEOUT; - return 0; - } - - rc = ngx_http_lua_pipe_write(pipe, pipe_ctx); - if (rc != NGX_AGAIN) { - return 0; - } - - wev = pipe_ctx->c->write; - wev->handler = ngx_http_lua_pipe_resume_write_handler; - timeout = proc->write_timeout; - - if (timeout > 0) { - ngx_add_timer(wev, timeout); - ngx_log_debug5(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "lua pipe add timer for writing: %d(ms) proc:%p " - "pid:%P pipe:%p ev:%p", timeout, proc, proc->_pid, pipe, - wev); - } - - ngx_log_debug3(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "lua pipe write yielding process:%p pid:%P pipe:%p", proc, - proc->_pid, pipe); - - return NGX_AGAIN; -} - - -static int -ngx_http_lua_pipe_wait_retval(ngx_http_lua_ffi_pipe_proc_t *proc, lua_State *L) -{ - int nret; - ngx_rbtree_node_t *node; - ngx_http_lua_pipe_t *pipe; - ngx_http_lua_pipe_node_t *pipe_node; - - pipe = proc->pipe; - node = pipe->node; - pipe_node = (ngx_http_lua_pipe_node_t *) &node->color; - pipe_node->wait_co_ctx = NULL; - - if (pipe->timeout) { - pipe->timeout = 0; - lua_pushnil(L); - lua_pushliteral(L, "timeout"); - return 2; - } - - ngx_http_lua_pipe_proc_finalize(pipe_node->proc, 0); - - if (pipe_node->status == 0) { - lua_pushboolean(L, 1); - lua_pushliteral(L, REASON_EXIT); - lua_pushinteger(L, pipe_node->status); - nret = 3; - - } else { - lua_pushboolean(L, 0); - - switch (pipe_node->reason_code) { - - case REASON_EXIT_CODE: - lua_pushliteral(L, REASON_EXIT); - break; - - case REASON_SIGNAL_CODE: - lua_pushliteral(L, REASON_SIGNAL); - break; - - default: - lua_pushliteral(L, REASON_UNKNOWN); - } - - lua_pushinteger(L, pipe_node->status); - nret = 3; - } - - return nret; -} - - -static void -ngx_http_lua_pipe_resume_helper(ngx_event_t *ev, - ngx_http_lua_co_ctx_t *wait_co_ctx) -{ - ngx_connection_t *c; - ngx_http_request_t *r; - ngx_http_lua_ctx_t *ctx; - ngx_http_lua_pipe_t *pipe; - ngx_http_lua_ffi_pipe_proc_t *proc; - - if (ev->timedout) { - proc = wait_co_ctx->data; - pipe = proc->pipe; - pipe->timeout = 1; - ev->timedout = 0; - } - - ngx_http_lua_pipe_clear_event(ev); - - r = ngx_http_lua_get_req(wait_co_ctx->co); - c = r->connection; - - ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); - ngx_http_lua_assert(ctx != NULL); - - ctx->cur_co_ctx = wait_co_ctx; - - if (ctx->entered_content_phase) { - (void) ngx_http_lua_pipe_resume(r); - - } else { - ctx->resume_handler = ngx_http_lua_pipe_resume; - ngx_http_core_run_phases(r); - } - - ngx_http_run_posted_requests(c); -} - - -static void -ngx_http_lua_pipe_resume_read_stdout_handler(ngx_event_t *ev) -{ - ngx_connection_t *c = ev->data; - ngx_http_lua_co_ctx_t *wait_co_ctx; - ngx_http_lua_pipe_t *pipe; - ngx_http_lua_ffi_pipe_proc_t *proc; - - wait_co_ctx = c->data; - proc = wait_co_ctx->data; - pipe = proc->pipe; - pipe->retval_handler = ngx_http_lua_pipe_read_stdout_retval; - ngx_http_lua_pipe_resume_helper(ev, wait_co_ctx); -} - - -static void -ngx_http_lua_pipe_resume_read_stderr_handler(ngx_event_t *ev) -{ - ngx_connection_t *c = ev->data; - ngx_http_lua_co_ctx_t *wait_co_ctx; - ngx_http_lua_pipe_t *pipe; - ngx_http_lua_ffi_pipe_proc_t *proc; - - wait_co_ctx = c->data; - proc = wait_co_ctx->data; - pipe = proc->pipe; - pipe->retval_handler = ngx_http_lua_pipe_read_stderr_retval; - ngx_http_lua_pipe_resume_helper(ev, wait_co_ctx); -} - - -static void -ngx_http_lua_pipe_resume_write_handler(ngx_event_t *ev) -{ - ngx_connection_t *c = ev->data; - ngx_http_lua_co_ctx_t *wait_co_ctx; - ngx_http_lua_pipe_t *pipe; - ngx_http_lua_ffi_pipe_proc_t *proc; - - wait_co_ctx = c->data; - proc = wait_co_ctx->data; - pipe = proc->pipe; - pipe->retval_handler = ngx_http_lua_pipe_write_retval; - ngx_http_lua_pipe_resume_helper(ev, wait_co_ctx); -} - - -static void -ngx_http_lua_pipe_resume_wait_handler(ngx_event_t *ev) -{ - ngx_http_lua_co_ctx_t *wait_co_ctx = ev->data; - ngx_http_lua_pipe_t *pipe; - ngx_http_lua_ffi_pipe_proc_t *proc; - - proc = wait_co_ctx->data; - pipe = proc->pipe; - pipe->retval_handler = ngx_http_lua_pipe_wait_retval; - ngx_http_lua_pipe_resume_helper(ev, wait_co_ctx); -} - - -static ngx_int_t -ngx_http_lua_pipe_resume(ngx_http_request_t *r) -{ - int nret; - lua_State *vm; - ngx_int_t rc; - ngx_uint_t nreqs; - ngx_connection_t *c; - ngx_http_lua_ctx_t *ctx; - ngx_http_lua_pipe_t *pipe; - ngx_http_lua_ffi_pipe_proc_t *proc; - - 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; - ctx->cur_co_ctx->cleanup = NULL; - - proc = ctx->cur_co_ctx->data; - pipe = proc->pipe; - nret = pipe->retval_handler(proc, ctx->cur_co_ctx->co); - if (nret == NGX_AGAIN) { - return NGX_DONE; - } - - c = r->connection; - vm = ngx_http_lua_get_lua_vm(r, ctx); - nreqs = c->requests; - - rc = ngx_http_lua_run_thread(vm, r, ctx, nret); - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua run thread returned %d", rc); - - if (rc == NGX_AGAIN) { - return ngx_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); - } - - /* rc == NGX_ERROR || rc >= NGX_OK */ - - if (ctx->entered_content_phase) { - ngx_http_lua_finalize_request(r, rc); - return NGX_DONE; - } - - return rc; -} - - -static void -ngx_http_lua_pipe_dummy_event_handler(ngx_event_t *ev) -{ - /* do nothing */ -} - - -static void -ngx_http_lua_pipe_clear_event(ngx_event_t *ev) -{ - ev->handler = ngx_http_lua_pipe_dummy_event_handler; - - if (ev->timer_set) { - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ev->log, 0, - "lua pipe del timer for ev:%p", ev); - ngx_del_timer(ev); - } - - if (ev->posted) { - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ev->log, 0, - "lua pipe del posted event for ev:%p", ev); - ngx_delete_posted_event(ev); - } -} - - -static void -ngx_http_lua_pipe_proc_read_stdout_cleanup(void *data) -{ - ngx_event_t *rev; - ngx_connection_t *c; - ngx_http_lua_co_ctx_t *wait_co_ctx = data; - ngx_http_lua_ffi_pipe_proc_t *proc; - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "lua pipe proc read stdout cleanup"); - - proc = wait_co_ctx->data; - c = proc->pipe->stdout_ctx->c; - if (c) { - rev = c->read; - ngx_http_lua_pipe_clear_event(rev); - } - - wait_co_ctx->cleanup = NULL; -} - - -static void -ngx_http_lua_pipe_proc_read_stderr_cleanup(void *data) -{ - ngx_event_t *rev; - ngx_connection_t *c; - ngx_http_lua_co_ctx_t *wait_co_ctx = data; - ngx_http_lua_ffi_pipe_proc_t *proc; - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "lua pipe proc read stderr cleanup"); - - proc = wait_co_ctx->data; - c = proc->pipe->stderr_ctx->c; - if (c) { - rev = c->read; - ngx_http_lua_pipe_clear_event(rev); - } - - wait_co_ctx->cleanup = NULL; -} - - -static void -ngx_http_lua_pipe_proc_write_cleanup(void *data) -{ - ngx_event_t *wev; - ngx_connection_t *c; - ngx_http_lua_co_ctx_t *wait_co_ctx = data; - ngx_http_lua_ffi_pipe_proc_t *proc; - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "lua pipe proc write cleanup"); - - proc = wait_co_ctx->data; - c = proc->pipe->stdin_ctx->c; - if (c) { - wev = c->write; - ngx_http_lua_pipe_clear_event(wev); - } - - wait_co_ctx->cleanup = NULL; -} - - -static void -ngx_http_lua_pipe_proc_wait_cleanup(void *data) -{ - ngx_rbtree_node_t *node; - ngx_http_lua_co_ctx_t *wait_co_ctx = data; - ngx_http_lua_pipe_node_t *pipe_node; - ngx_http_lua_ffi_pipe_proc_t *proc; - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "lua pipe proc wait cleanup"); - - proc = wait_co_ctx->data; - node = proc->pipe->node; - pipe_node = (ngx_http_lua_pipe_node_t *) &node->color; - pipe_node->wait_co_ctx = NULL; - - ngx_http_lua_pipe_clear_event(&wait_co_ctx->sleep); - - wait_co_ctx->cleanup = NULL; -} - - -#endif /* HAVE_NGX_LUA_PIPE */ - -/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_pipe.h b/debian/modules/http-lua/src/ngx_http_lua_pipe.h deleted file mode 100644 index b5cea89..0000000 --- a/debian/modules/http-lua/src/ngx_http_lua_pipe.h +++ /dev/null @@ -1,95 +0,0 @@ - -/* - * Copyright (C) by OpenResty Inc. - */ - - -#ifndef _NGX_HTTP_LUA_PIPE_H_INCLUDED_ -#define _NGX_HTTP_LUA_PIPE_H_INCLUDED_ - - -#include "ngx_http_lua_common.h" - - -typedef ngx_int_t (*ngx_http_lua_pipe_input_filter)(void *data, ssize_t bytes); - - -typedef struct { - ngx_connection_t *c; - ngx_http_lua_pipe_input_filter input_filter; - void *input_filter_ctx; - size_t rest; - ngx_chain_t *buf_in; - ngx_chain_t *bufs_in; - ngx_buf_t buffer; - ngx_err_t pipe_errno; - unsigned err_type:16; - unsigned eof:1; -} ngx_http_lua_pipe_ctx_t; - - -typedef struct ngx_http_lua_pipe_s ngx_http_lua_pipe_t; - - -typedef struct { - ngx_pid_t _pid; - ngx_msec_t write_timeout; - ngx_msec_t stdout_read_timeout; - ngx_msec_t stderr_read_timeout; - ngx_msec_t wait_timeout; - /* pipe hides the implementation from the Lua binding */ - ngx_http_lua_pipe_t *pipe; -} ngx_http_lua_ffi_pipe_proc_t; - - -typedef int (*ngx_http_lua_pipe_retval_handler)( - ngx_http_lua_ffi_pipe_proc_t *proc, lua_State *L); - - -struct ngx_http_lua_pipe_s { - ngx_pool_t *pool; - ngx_chain_t *free_bufs; - ngx_rbtree_node_t *node; - int stdin_fd; - int stdout_fd; - int stderr_fd; - ngx_http_lua_pipe_ctx_t *stdin_ctx; - ngx_http_lua_pipe_ctx_t *stdout_ctx; - ngx_http_lua_pipe_ctx_t *stderr_ctx; - ngx_http_lua_pipe_retval_handler retval_handler; - size_t buffer_size; - unsigned closed:1; - unsigned dead:1; - unsigned timeout:1; - unsigned merge_stderr:1; -}; - - -typedef struct { - u_char color; - u_char reason_code; - int status; - ngx_http_lua_co_ctx_t *wait_co_ctx; - ngx_http_lua_ffi_pipe_proc_t *proc; -} ngx_http_lua_pipe_node_t; - - -typedef struct { - int signo; - char *signame; -} ngx_http_lua_pipe_signal_t; - - -#if !(NGX_WIN32) && !defined(NGX_LUA_NO_FFI_API) \ - && defined(HAVE_SOCKET_CLOEXEC_PATCH) -#define HAVE_NGX_LUA_PIPE 1 - - -void ngx_http_lua_pipe_init(void); -ngx_int_t ngx_http_lua_pipe_add_signal_handler(ngx_cycle_t *cycle); -#endif - - -#endif /* _NGX_HTTP_LUA_PIPE_H_INCLUDED_ */ - -/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_regex.c b/debian/modules/http-lua/src/ngx_http_lua_regex.c index 8f3373b..843d1e4 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_regex.c +++ b/debian/modules/http-lua/src/ngx_http_lua_regex.c @@ -15,6 +15,7 @@ #include "ngx_http_lua_regex.h" #include "ngx_http_lua_pcrefix.h" #include "ngx_http_lua_script.h" +#include "ngx_http_lua_pcrefix.h" #include "ngx_http_lua_util.h" @@ -248,8 +249,7 @@ ngx_http_lua_ngx_re_match_helper(lua_State *L, int wantcaps) dd("server pool %p", lmcf->pool); - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - regex_cache_key)); + lua_pushlightuserdata(L, &ngx_http_lua_regex_cache_key); lua_rawget(L, LUA_REGISTRYINDEX); /* table */ lua_pushliteral(L, "m"); @@ -720,8 +720,7 @@ ngx_http_lua_ngx_re_gmatch(lua_State *L) dd("server pool %p", lmcf->pool); - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - regex_cache_key)); + lua_pushlightuserdata(L, &ngx_http_lua_regex_cache_key); lua_rawget(L, LUA_REGISTRYINDEX); /* table */ lua_pushliteral(L, "m"); @@ -1389,8 +1388,7 @@ ngx_http_lua_ngx_re_sub_helper(lua_State *L, unsigned global) dd("server pool %p", lmcf->pool); - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - regex_cache_key)); + lua_pushlightuserdata(L, &ngx_http_lua_regex_cache_key); lua_rawget(L, LUA_REGISTRYINDEX); /* table */ lua_pushliteral(L, "s"); diff --git a/debian/modules/http-lua/src/ngx_http_lua_rewriteby.c b/debian/modules/http-lua/src/ngx_http_lua_rewriteby.c index 1de9968..1bbe87c 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_rewriteby.c +++ b/debian/modules/http-lua/src/ngx_http_lua_rewriteby.c @@ -62,7 +62,7 @@ ngx_http_lua_rewrite_handler(ngx_http_request_t *r) #endif if (cur_ph < last_ph) { - dd("swapping the contents of cur_ph and last_ph..."); + dd("swaping the contents of cur_ph and last_ph..."); tmp = *cur_ph; @@ -261,11 +261,9 @@ ngx_http_lua_rewrite_by_chunk(lua_State *L, ngx_http_request_t *r) /* 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); diff --git a/debian/modules/http-lua/src/ngx_http_lua_script.c b/debian/modules/http-lua/src/ngx_http_lua_script.c index c675a16..95ebadf 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_script.c +++ b/debian/modules/http-lua/src/ngx_http_lua_script.c @@ -329,7 +329,7 @@ ngx_http_lua_script_add_copy_code(ngx_http_lua_script_compile_t *sc, return NGX_ERROR; } - code->code = (ngx_http_lua_script_code_pt) (void *) + code->code = (ngx_http_lua_script_code_pt) ngx_http_lua_script_copy_len_code; code->len = len; @@ -399,7 +399,7 @@ ngx_http_lua_script_add_capture_code(ngx_http_lua_script_compile_t *sc, return NGX_ERROR; } - code->code = (ngx_http_lua_script_code_pt) (void *) + code->code = (ngx_http_lua_script_code_pt) ngx_http_lua_script_copy_capture_len_code; code->n = 2 * n; diff --git a/debian/modules/http-lua/src/ngx_http_lua_setby.c b/debian/modules/http-lua/src/ngx_http_lua_setby.c index d4288b5..2e8762a 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_setby.c +++ b/debian/modules/http-lua/src/ngx_http_lua_setby.c @@ -30,6 +30,13 @@ static void ngx_http_lua_set_by_lua_env(lua_State *L, ngx_http_request_t *r, size_t nargs, ngx_http_variable_value_t *args); +/* keys in Lua thread for fetching args and nargs in set_by_lua* */ + +#define ngx_http_lua_nargs_key "__ngx_nargs" + +#define ngx_http_lua_args_key "__ngx_args" + + ngx_int_t 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) @@ -127,24 +134,23 @@ 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) +ngx_http_lua_setby_param_get(lua_State *L) { 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); + /* get number of args from globals */ + lua_getglobal(L, ngx_http_lua_nargs_key); + n = (int) lua_tointeger(L, -1); - /* get number of args from lmcf */ - n = lmcf->setby_nargs; - - /* get args from lmcf */ - v = lmcf->setby_args; + /* get args from globals */ + lua_getglobal(L, ngx_http_lua_args_key); + v = lua_touserdata(L, -1); if (idx < 0 || idx > n - 1) { lua_pushnil(L); @@ -172,16 +178,15 @@ static void ngx_http_lua_set_by_lua_env(lua_State *L, ngx_http_request_t *r, size_t nargs, ngx_http_variable_value_t *args) { - ngx_http_lua_main_conf_t *lmcf; - + /* set nginx request pointer to current lua thread's globals table */ ngx_http_lua_set_req(L, r); - lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); + lua_pushinteger(L, nargs); + lua_setglobal(L, ngx_http_lua_nargs_key); - lmcf->setby_nargs = nargs; - lmcf->setby_args = args; + lua_pushlightuserdata(L, args); + lua_setglobal(L, ngx_http_lua_args_key); -#ifndef OPENRESTY_LUAJIT /** * we want to create empty environment for current script * @@ -206,7 +211,6 @@ ngx_http_lua_set_by_lua_env(lua_State *L, ngx_http_request_t *r, size_t nargs, /* }}} */ lua_setfenv(L, -2); /* set new running env for the code closure */ -#endif } /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_setby.h b/debian/modules/http-lua/src/ngx_http_lua_setby.h index f43eef7..da71753 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_setby.h +++ b/debian/modules/http-lua/src/ngx_http_lua_setby.h @@ -7,7 +7,7 @@ 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); +int ngx_http_lua_setby_param_get(lua_State *L); #endif /* _NGX_HTTP_LUA_SET_BY_H_INCLUDED_ */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_shdict.c b/debian/modules/http-lua/src/ngx_http_lua_shdict.c index b017bea..5fb7930 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_shdict.c +++ b/debian/modules/http-lua/src/ngx_http_lua_shdict.c @@ -325,7 +325,6 @@ ngx_http_lua_inject_shdict_api(ngx_http_lua_main_conf_t *lmcf, lua_State *L) ngx_http_lua_shdict_ctx_t *ctx; ngx_uint_t i; ngx_shm_zone_t **zone; - ngx_shm_zone_t **zone_udata; if (lmcf->shdict_zones != NULL) { lua_createtable(L, 0, lmcf->shdict_zones->nelts /* nrec */); @@ -397,9 +396,7 @@ ngx_http_lua_inject_shdict_api(ngx_http_lua_main_conf_t *lmcf, lua_State *L) lua_createtable(L, 1 /* narr */, 0 /* nrec */); /* table of zone[i] */ - zone_udata = lua_newuserdata(L, sizeof(ngx_shm_zone_t *)); - /* shared mt key ud */ - *zone_udata = zone[i]; + lua_pushlightuserdata(L, zone[i]); /* shared mt key ud */ lua_rawseti(L, -2, SHDICT_USERDATA_INDEX); /* {zone[i]} */ lua_pushvalue(L, -3); /* shared mt key ud mt */ lua_setmetatable(L, -2); /* shared mt key ud */ @@ -434,17 +431,11 @@ static ngx_inline ngx_shm_zone_t * ngx_http_lua_shdict_get_zone(lua_State *L, int index) { ngx_shm_zone_t *zone; - ngx_shm_zone_t **zone_udata; lua_rawgeti(L, index, SHDICT_USERDATA_INDEX); - zone_udata = lua_touserdata(L, -1); + zone = lua_touserdata(L, -1); lua_pop(L, 1); - if (zone_udata == NULL) { - return NULL; - } - - zone = *zone_udata; return zone; } @@ -2218,17 +2209,6 @@ ngx_http_lua_find_zone(u_char *name_data, size_t name_len) #ifndef NGX_LUA_NO_FFI_API -ngx_shm_zone_t * -ngx_http_lua_ffi_shdict_udata_to_zone(void *zone_udata) -{ - if (zone_udata == NULL) { - return NULL; - } - - return *(ngx_shm_zone_t **) zone_udata; -} - - int ngx_http_lua_ffi_shdict_store(ngx_shm_zone_t *zone, int op, u_char *key, size_t key_len, int value_type, u_char *str_value_buf, @@ -2245,6 +2225,10 @@ ngx_http_lua_ffi_shdict_store(ngx_shm_zone_t *zone, int op, u_char *key, ngx_http_lua_shdict_ctx_t *ctx; ngx_http_lua_shdict_node_t *sd; + if (zone == NULL) { + return NGX_ERROR; + } + dd("exptime: %ld", exptime); ctx = zone->data; @@ -2506,6 +2490,10 @@ ngx_http_lua_ffi_shdict_get(ngx_shm_zone_t *zone, u_char *key, ngx_http_lua_shdict_node_t *sd; ngx_str_t value; + if (zone == NULL) { + return NGX_ERROR; + } + *err = NULL; ctx = zone->data; @@ -2648,6 +2636,10 @@ ngx_http_lua_ffi_shdict_incr(ngx_shm_zone_t *zone, u_char *key, u_char *p; ngx_queue_t *queue, *q; + if (zone == NULL) { + return NGX_ERROR; + } + if (init_ttl > 0) { tp = ngx_timeofday(); } @@ -2923,6 +2915,10 @@ ngx_http_lua_ffi_shdict_get_ttl(ngx_shm_zone_t *zone, u_char *key, ngx_http_lua_shdict_ctx_t *ctx; ngx_http_lua_shdict_node_t *sd; + if (zone == NULL) { + return NGX_ERROR; + } + ctx = zone->data; hash = ngx_crc32_short(key, key_len); @@ -2963,6 +2959,10 @@ ngx_http_lua_ffi_shdict_set_expire(ngx_shm_zone_t *zone, u_char *key, ngx_http_lua_shdict_ctx_t *ctx; ngx_http_lua_shdict_node_t *sd; + if (zone == NULL) { + return NGX_ERROR; + } + if (exptime > 0) { tp = ngx_timeofday(); } diff --git a/debian/modules/http-lua/src/ngx_http_lua_socket_tcp.c b/debian/modules/http-lua/src/ngx_http_lua_socket_tcp.c index 87461e6..efdf427 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_socket_tcp.c +++ b/debian/modules/http-lua/src/ngx_http_lua_socket_tcp.c @@ -11,7 +11,6 @@ #include "ngx_http_lua_socket_tcp.h" -#include "ngx_http_lua_input_filters.h" #include "ngx_http_lua_util.h" #include "ngx_http_lua_uthread.h" #include "ngx_http_lua_output.h" @@ -25,7 +24,6 @@ static int ngx_http_lua_socket_tcp_connect(lua_State *L); static int ngx_http_lua_socket_tcp_sslhandshake(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); static int ngx_http_lua_socket_tcp_send(lua_State *L); static int ngx_http_lua_socket_tcp_close(lua_State *L); static int ngx_http_lua_socket_tcp_setoption(lua_State *L); @@ -71,8 +69,6 @@ static int ngx_http_lua_socket_tcp_conn_retval_handler(ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u, lua_State *L); 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 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, @@ -90,7 +86,6 @@ static int ngx_http_lua_socket_write_error_retval_handler(ngx_http_request_t *r, static ngx_int_t ngx_http_lua_socket_read_all(void *data, ssize_t bytes); static ngx_int_t ngx_http_lua_socket_read_until(void *data, ssize_t bytes); static ngx_int_t ngx_http_lua_socket_read_chunk(void *data, ssize_t bytes); -static ngx_int_t ngx_http_lua_socket_read_any(void *data, ssize_t bytes); static int ngx_http_lua_socket_tcp_receiveuntil(lua_State *L); static int ngx_http_lua_socket_receiveuntil_iterator(lua_State *L); static ngx_int_t ngx_http_lua_socket_compile_pattern(u_char *data, size_t len, @@ -100,28 +95,12 @@ static int ngx_http_lua_req_socket(lua_State *L); static void ngx_http_lua_req_socket_rev_handler(ngx_http_request_t *r); static int ngx_http_lua_socket_tcp_getreusedtimes(lua_State *L); static int ngx_http_lua_socket_tcp_setkeepalive(lua_State *L); -static void ngx_http_lua_socket_tcp_create_socket_pool(lua_State *L, - ngx_http_request_t *r, ngx_str_t key, ngx_int_t pool_size, - ngx_int_t backlog, ngx_http_lua_socket_pool_t **spool); static ngx_int_t ngx_http_lua_get_keepalive_peer(ngx_http_request_t *r, + lua_State *L, int key_index, ngx_http_lua_socket_tcp_upstream_t *u); static void ngx_http_lua_socket_keepalive_dummy_handler(ngx_event_t *ev); -static int ngx_http_lua_socket_tcp_connect_helper(lua_State *L, - ngx_http_lua_socket_tcp_upstream_t *u, ngx_http_request_t *r, - ngx_http_lua_ctx_t *ctx, u_char *host_ref, size_t host_len, in_port_t port, - unsigned resuming); -static void ngx_http_lua_socket_tcp_conn_op_timeout_handler( - ngx_event_t *ev); -static int ngx_http_lua_socket_tcp_conn_op_timeout_retval_handler( - ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u, lua_State *L); -static void ngx_http_lua_socket_tcp_resume_conn_op( - ngx_http_lua_socket_pool_t *spool); -static void ngx_http_lua_socket_tcp_conn_op_ctx_cleanup(void *data); -static void ngx_http_lua_socket_tcp_conn_op_resume_handler(ngx_event_t *ev); static ngx_int_t ngx_http_lua_socket_keepalive_close_handler(ngx_event_t *ev); static void ngx_http_lua_socket_keepalive_rev_handler(ngx_event_t *ev); -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, @@ -134,13 +113,11 @@ static ngx_int_t ngx_http_lua_socket_add_input_buffer(ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u); static ngx_int_t ngx_http_lua_socket_insert_buffer(ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u, u_char *pat, size_t prefix); -static ngx_int_t ngx_http_lua_socket_tcp_conn_op_resume(ngx_http_request_t *r); static ngx_int_t ngx_http_lua_socket_tcp_conn_resume(ngx_http_request_t *r); static ngx_int_t ngx_http_lua_socket_tcp_read_resume(ngx_http_request_t *r); static ngx_int_t ngx_http_lua_socket_tcp_write_resume(ngx_http_request_t *r); static ngx_int_t ngx_http_lua_socket_tcp_resume_helper(ngx_http_request_t *r, int socket_op); -static void ngx_http_lua_tcp_queue_conn_op_cleanup(void *data); static void ngx_http_lua_tcp_resolve_cleanup(void *data); static void ngx_http_lua_coctx_cleanup(void *data); static void ngx_http_lua_socket_free_pool(ngx_log_t *log, @@ -173,8 +150,7 @@ enum { enum { SOCKET_OP_CONNECT, SOCKET_OP_READ, - SOCKET_OP_WRITE, - SOCKET_OP_RESUME_CONN + SOCKET_OP_WRITE }; @@ -253,8 +229,7 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) lua_setfield(L, -2, "socket"); /* {{{req socket object metatable */ - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - req_socket_metatable_key)); + lua_pushlightuserdata(L, &ngx_http_lua_req_socket_metatable_key); lua_createtable(L, 0 /* narr */, 5 /* nrec */); lua_pushcfunction(L, ngx_http_lua_socket_tcp_receive); @@ -276,8 +251,7 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) /* }}} */ /* {{{raw req socket object metatable */ - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - raw_req_socket_metatable_key)); + lua_pushlightuserdata(L, &ngx_http_lua_raw_req_socket_metatable_key); lua_createtable(L, 0 /* narr */, 6 /* nrec */); lua_pushcfunction(L, ngx_http_lua_socket_tcp_receive); @@ -302,8 +276,7 @@ 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_pushlightuserdata(L, &ngx_http_lua_tcp_socket_metatable_key); lua_createtable(L, 0 /* narr */, 12 /* nrec */); lua_pushcfunction(L, ngx_http_lua_socket_tcp_connect); @@ -319,9 +292,6 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) lua_pushcfunction(L, ngx_http_lua_socket_tcp_receive); lua_setfield(L, -2, "receive"); - lua_pushcfunction(L, ngx_http_lua_socket_tcp_receiveany); - lua_setfield(L, -2, "receiveany"); - lua_pushcfunction(L, ngx_http_lua_socket_tcp_receiveuntil); lua_setfield(L, -2, "receiveuntil"); @@ -352,8 +322,7 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) /* }}} */ /* {{{upstream userdata metatable */ - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - upstream_udata_metatable_key)); + lua_pushlightuserdata(L, &ngx_http_lua_upstream_udata_metatable_key); lua_createtable(L, 0 /* narr */, 1 /* nrec */); /* metatable */ lua_pushcfunction(L, ngx_http_lua_socket_tcp_upstream_destroy); lua_setfield(L, -2, "__gc"); @@ -361,8 +330,7 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) /* }}} */ /* {{{downstream userdata metatable */ - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - downstream_udata_metatable_key)); + lua_pushlightuserdata(L, &ngx_http_lua_downstream_udata_metatable_key); lua_createtable(L, 0 /* narr */, 1 /* nrec */); /* metatable */ lua_pushcfunction(L, ngx_http_lua_socket_downstream_destroy); lua_setfield(L, -2, "__gc"); @@ -370,8 +338,7 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) /* }}} */ /* {{{socket pool userdata metatable */ - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - pool_udata_metatable_key)); + lua_pushlightuserdata(L, &ngx_http_lua_pool_udata_metatable_key); lua_createtable(L, 0, 1); /* metatable */ lua_pushcfunction(L, ngx_http_lua_socket_shutdown_pool); lua_setfield(L, -2, "__gc"); @@ -379,8 +346,7 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) /* }}} */ /* {{{socket compiled pattern userdata metatable */ - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - pattern_udata_metatable_key)); + lua_pushlightuserdata(L, &ngx_http_lua_pattern_udata_metatable_key); lua_createtable(L, 0 /* narr */, 1 /* nrec */); /* metatable */ lua_pushcfunction(L, ngx_http_lua_socket_cleanup_compiled_pattern); lua_setfield(L, -2, "__gc"); @@ -390,8 +356,7 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) #if (NGX_HTTP_SSL) /* {{{ssl session userdata metatable */ - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - ssl_session_metatable_key)); + lua_pushlightuserdata(L, &ngx_http_lua_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"); @@ -439,8 +404,7 @@ ngx_http_lua_socket_tcp(lua_State *L) | NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH); lua_createtable(L, 5 /* narr */, 1 /* nrec */); - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - tcp_socket_metatable_key)); + lua_pushlightuserdata(L, &ngx_http_lua_tcp_socket_metatable_key); lua_rawget(L, LUA_REGISTRYINDEX); lua_setmetatable(L, -2); @@ -450,421 +414,31 @@ ngx_http_lua_socket_tcp(lua_State *L) } -static void -ngx_http_lua_socket_tcp_create_socket_pool(lua_State *L, ngx_http_request_t *r, - ngx_str_t key, ngx_int_t pool_size, ngx_int_t backlog, - ngx_http_lua_socket_pool_t **spool) -{ - u_char *p; - size_t size, key_len; - ngx_int_t i; - ngx_http_lua_socket_pool_t *sp; - ngx_http_lua_socket_pool_item_t *items; - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua tcp socket connection pool size: %i, backlog: %i", - pool_size, backlog); - - key_len = ngx_align(key.len + 1, sizeof(void *)); - - size = sizeof(ngx_http_lua_socket_pool_t) - 1 + key_len - + sizeof(ngx_http_lua_socket_pool_item_t) * pool_size; - - /* before calling this function, the Lua stack is: - * -1 key - * -2 pools - */ - sp = lua_newuserdata(L, size); - if (sp == NULL) { - luaL_error(L, "no memory"); - return; - } - - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - pool_udata_metatable_key)); - lua_rawget(L, LUA_REGISTRYINDEX); - lua_setmetatable(L, -2); - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua tcp socket keepalive create connection pool for key" - " \"%V\"", &key); - - /* a new socket pool with metatable is push to the stack, so now we have: - * -1 sp - * -2 key - * -3 pools - * - * it is time to set pools[key] to sp. - */ - lua_rawset(L, -3); - - /* clean up the stack for consistency's sake */ - lua_pop(L, 1); - - sp->backlog = backlog; - sp->size = pool_size; - sp->connections = 0; - sp->lua_vm = ngx_http_lua_get_lua_vm(r, NULL); - - ngx_queue_init(&sp->cache_connect_op); - ngx_queue_init(&sp->wait_connect_op); - ngx_queue_init(&sp->cache); - ngx_queue_init(&sp->free); - - p = ngx_copy(sp->key, key.data, key.len); - *p++ = '\0'; - - items = (ngx_http_lua_socket_pool_item_t *) (sp->key + key_len); - - dd("items: %p", items); - - ngx_http_lua_assert((void *) items == ngx_align_ptr(items, sizeof(void *))); - - for (i = 0; i < pool_size; i++) { - ngx_queue_insert_head(&sp->free, &items[i].queue); - items[i].socket_pool = sp; - } - - *spool = sp; -} - - -static int -ngx_http_lua_socket_tcp_connect_helper(lua_State *L, - ngx_http_lua_socket_tcp_upstream_t *u, ngx_http_request_t *r, - ngx_http_lua_ctx_t *ctx, u_char *host_ref, size_t host_len, in_port_t port, - unsigned resuming) -{ - int n; - int host_size; - int saved_top; - ngx_int_t rc; - ngx_str_t host; - ngx_str_t *conn_op_host; - ngx_url_t url; - ngx_queue_t *q; - ngx_resolver_ctx_t *rctx, temp; - ngx_http_lua_co_ctx_t *coctx; - ngx_http_core_loc_conf_t *clcf; - ngx_http_lua_socket_pool_t *spool; - ngx_http_lua_socket_tcp_conn_op_ctx_t *conn_op_ctx; - - spool = u->socket_pool; - if (spool != NULL) { - rc = ngx_http_lua_get_keepalive_peer(r, u); - - if (rc == NGX_OK) { - lua_pushinteger(L, 1); - return 1; - } - - /* rc == NGX_DECLINED */ - - spool->connections++; - - /* check if backlog is enabled and - * don't queue resuming connection operation */ - if (spool->backlog >= 0 && !resuming) { - - dd("lua tcp socket %s connections %ld", - spool->key, spool->connections); - - if (spool->connections > spool->size + spool->backlog) { - spool->connections--; - lua_pushnil(L); - lua_pushliteral(L, "too many waiting connect operations"); - return 2; - } - - if (spool->connections > spool->size) { - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, u->peer.log, 0, - "lua tcp socket queue connect operation for " - "connection pool \"%s\", connections: %i", - spool->key, spool->connections); - - host_size = sizeof(u_char) * - (ngx_max(host_len, NGX_INET_ADDRSTRLEN) + 1); - - if (!ngx_queue_empty(&spool->cache_connect_op)) { - q = ngx_queue_last(&spool->cache_connect_op); - ngx_queue_remove(q); - conn_op_ctx = ngx_queue_data( - q, ngx_http_lua_socket_tcp_conn_op_ctx_t, queue); - - conn_op_host = &conn_op_ctx->host; - if (host_len > conn_op_host->len - && host_len > NGX_INET_ADDRSTRLEN) - { - ngx_free(conn_op_host->data); - conn_op_host->data = ngx_alloc(host_size, - ngx_cycle->log); - if (conn_op_host->data == NULL) { - ngx_free(conn_op_ctx); - goto no_memory_and_not_resuming; - } - } - - } else { - conn_op_ctx = ngx_alloc( - sizeof(ngx_http_lua_socket_tcp_conn_op_ctx_t), - ngx_cycle->log); - if (conn_op_ctx == NULL) { - goto no_memory_and_not_resuming; - } - - conn_op_host = &conn_op_ctx->host; - conn_op_host->data = ngx_alloc(host_size, ngx_cycle->log); - if (conn_op_host->data == NULL) { - ngx_free(conn_op_ctx); - goto no_memory_and_not_resuming; - } - } - - conn_op_ctx->cleanup = NULL; - - ngx_memcpy(conn_op_host->data, host_ref, host_len); - conn_op_host->data[host_len] = '\0'; - conn_op_host->len = host_len; - - conn_op_ctx->port = port; - - u->write_co_ctx = ctx->cur_co_ctx; - - conn_op_ctx->u = u; - ctx->cur_co_ctx->cleanup = - ngx_http_lua_tcp_queue_conn_op_cleanup; - ctx->cur_co_ctx->data = conn_op_ctx; - - ngx_memzero(&conn_op_ctx->event, sizeof(ngx_event_t)); - conn_op_ctx->event.handler = - ngx_http_lua_socket_tcp_conn_op_timeout_handler; - conn_op_ctx->event.data = conn_op_ctx; - conn_op_ctx->event.log = ngx_cycle->log; - - ngx_add_timer(&conn_op_ctx->event, u->connect_timeout); - - ngx_queue_insert_tail(&spool->wait_connect_op, - &conn_op_ctx->queue); - - ngx_log_debug3(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "lua tcp socket queued connect operation for " - "%d(ms), u: %p, ctx: %p", - u->connect_timeout, conn_op_ctx->u, conn_op_ctx); - - return lua_yield(L, 0); - } - } - - } /* end spool != NULL */ - - host.data = ngx_palloc(r->pool, host_len + 1); - if (host.data == NULL) { - return luaL_error(L, "no memory"); - } - - host.len = host_len; - - ngx_memcpy(host.data, host_ref, host_len); - host.data[host_len] = '\0'; - - ngx_memzero(&url, sizeof(ngx_url_t)); - url.url = host; - url.default_port = port; - url.no_resolve = 1; - - coctx = ctx->cur_co_ctx; - - if (ngx_parse_url(r->pool, &url) != NGX_OK) { - lua_pushnil(L); - - if (url.err) { - lua_pushfstring(L, "failed to parse host name \"%s\": %s", - url.url.data, url.err); - - } else { - lua_pushfstring(L, "failed to parse host name \"%s\"", - url.url.data); - } - - goto failed; - } - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua tcp socket connect timeout: %M", u->connect_timeout); - - u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t)); - if (u->resolved == NULL) { - if (resuming) { - lua_pushnil(L); - lua_pushliteral(L, "no memory"); - goto failed; - } - - goto no_memory_and_not_resuming; - } - - if (url.addrs && url.addrs[0].sockaddr) { - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua tcp socket network address given directly"); - - u->resolved->sockaddr = url.addrs[0].sockaddr; - u->resolved->socklen = url.addrs[0].socklen; - u->resolved->naddrs = 1; - u->resolved->host = url.addrs[0].name; - - } else { - u->resolved->host = host; - u->resolved->port = url.default_port; - } - - if (u->resolved->sockaddr) { - rc = ngx_http_lua_socket_resolve_retval_handler(r, u, L); - if (rc == NGX_AGAIN && !resuming) { - return lua_yield(L, 0); - } - - if (rc > 1) { - goto failed; - } - - return rc; - } - - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - - temp.name = host; - rctx = ngx_resolve_start(clcf->resolver, &temp); - if (rctx == NULL) { - u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_RESOLVER; - lua_pushnil(L); - lua_pushliteral(L, "failed to start the resolver"); - goto failed; - } - - if (rctx == NGX_NO_RESOLVER) { - u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_RESOLVER; - lua_pushnil(L); - lua_pushfstring(L, "no resolver defined to resolve \"%s\"", host.data); - goto failed; - } - - rctx->name = host; -#if !defined(nginx_version) || nginx_version < 1005008 - rctx->type = NGX_RESOLVE_A; -#endif - rctx->handler = ngx_http_lua_socket_resolve_handler; - rctx->data = u; - rctx->timeout = clcf->resolver_timeout; - - u->resolved->ctx = rctx; - u->write_co_ctx = ctx->cur_co_ctx; - - ngx_http_lua_cleanup_pending_operation(coctx); - coctx->cleanup = ngx_http_lua_tcp_resolve_cleanup; - coctx->data = u; - - saved_top = lua_gettop(L); - - if (ngx_resolve_name(rctx) != NGX_OK) { - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua tcp socket fail to run resolver immediately"); - - u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_RESOLVER; - - coctx->cleanup = NULL; - coctx->data = NULL; - - u->resolved->ctx = NULL; - lua_pushnil(L); - lua_pushfstring(L, "%s could not be resolved", host.data); - goto failed; - } - - if (u->conn_waiting) { - dd("resolved and already connecting"); - - if (resuming) { - return NGX_AGAIN; - } - - return lua_yield(L, 0); - } - - n = lua_gettop(L) - saved_top; - if (n) { - dd("errors occurred during resolving or connecting" - "or already connected"); - - if (n > 1) { - goto failed; - } - - return n; - } - - /* still resolving */ - - u->conn_waiting = 1; - u->write_prepare_retvals = ngx_http_lua_socket_resolve_retval_handler; - - dd("setting data to %p", u); - - if (ctx->entered_content_phase) { - r->write_event_handler = ngx_http_lua_content_wev_handler; - - } else { - r->write_event_handler = ngx_http_core_run_phases; - } - - if (resuming) { - return NGX_AGAIN; - } - - return lua_yield(L, 0); - -failed: - - if (spool != NULL) { - spool->connections--; - ngx_http_lua_socket_tcp_resume_conn_op(spool); - } - - return 2; - -no_memory_and_not_resuming: - - if (spool != NULL) { - spool->connections--; - ngx_http_lua_socket_tcp_resume_conn_op(spool); - } - - return luaL_error(L, "no memory"); -} - - static int ngx_http_lua_socket_tcp_connect(lua_State *L) { ngx_http_request_t *r; ngx_http_lua_ctx_t *ctx; + ngx_str_t host; int port; + ngx_resolver_ctx_t *rctx, temp; + ngx_http_core_loc_conf_t *clcf; + int saved_top; int n; u_char *p; size_t len; + ngx_url_t url; + ngx_int_t rc; ngx_http_lua_loc_conf_t *llcf; ngx_peer_connection_t *pc; int connect_timeout, send_timeout, read_timeout; unsigned custom_pool; int key_index; - ngx_int_t backlog; - ngx_int_t pool_size; - ngx_str_t key; const char *msg; + ngx_http_lua_co_ctx_t *coctx; ngx_http_lua_socket_tcp_upstream_t *u; - ngx_http_lua_socket_pool_t *spool; - n = lua_gettop(L); if (n != 2 && n != 3 && n != 4) { return luaL_error(L, "ngx.socket connect: expecting 2, 3, or 4 " @@ -892,54 +466,13 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) p = (u_char *) luaL_checklstring(L, 2, &len); - backlog = -1; key_index = 2; - pool_size = 0; custom_pool = 0; - llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); if (lua_type(L, n) == LUA_TTABLE) { /* found the last optional option table */ - lua_getfield(L, n, "pool_size"); - - if (lua_isnumber(L, -1)) { - pool_size = (ngx_int_t) lua_tointeger(L, -1); - - if (pool_size <= 0) { - msg = lua_pushfstring(L, "bad \"pool_size\" option value: %i", - pool_size); - return luaL_argerror(L, n, msg); - } - - } else if (!lua_isnil(L, -1)) { - msg = lua_pushfstring(L, "bad \"pool_size\" option type: %s", - lua_typename(L, lua_type(L, -1))); - return luaL_argerror(L, n, msg); - } - - lua_pop(L, 1); - - lua_getfield(L, n, "backlog"); - - if (lua_isnumber(L, -1)) { - backlog = (ngx_int_t) lua_tointeger(L, -1); - - if (backlog < 0) { - msg = lua_pushfstring(L, "bad \"backlog\" option value: %i", - backlog); - return luaL_argerror(L, n, msg); - } - - /* use default value for pool size if only backlog specified */ - if (pool_size == 0) { - pool_size = llcf->pool_size; - } - } - - lua_pop(L, 1); - lua_getfield(L, n, "pool"); switch (lua_type(L, -1)) { @@ -1039,8 +572,7 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) } #if 1 - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - upstream_udata_metatable_key)); + lua_pushlightuserdata(L, &ngx_http_lua_upstream_udata_metatable_key); lua_rawget(L, LUA_REGISTRYINDEX); lua_setmetatable(L, -2); #endif @@ -1050,8 +582,12 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) ngx_memzero(u, sizeof(ngx_http_lua_socket_tcp_upstream_t)); + coctx = ctx->cur_co_ctx; + u->request = r; /* set the controlling request */ + llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); + u->conf = llcf; pc = &u->peer; @@ -1092,28 +628,163 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) u->read_timeout = u->conf->read_timeout; } - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask(socket_pool_key)); - lua_rawget(L, LUA_REGISTRYINDEX); /* table */ - lua_pushvalue(L, key_index); /* key */ + rc = ngx_http_lua_get_keepalive_peer(r, L, key_index, u); - lua_rawget(L, -2); - spool = lua_touserdata(L, -1); - lua_pop(L, 1); - - if (spool != NULL) { - u->socket_pool = spool; - - } else if (pool_size > 0) { - lua_pushvalue(L, key_index); - key.data = (u_char *) lua_tolstring(L, -1, &key.len); - - ngx_http_lua_socket_tcp_create_socket_pool(L, r, key, pool_size, - backlog, &spool); - u->socket_pool = spool; + if (rc == NGX_OK) { + lua_pushinteger(L, 1); + return 1; } - return ngx_http_lua_socket_tcp_connect_helper(L, u, r, ctx, p, - len, port, 0); + if (rc == NGX_ERROR) { + lua_pushnil(L); + lua_pushliteral(L, "error in get keepalive peer"); + return 2; + } + + /* rc == NGX_DECLINED */ + + /* TODO: we should avoid this in-pool allocation */ + + host.data = ngx_palloc(r->pool, len + 1); + if (host.data == NULL) { + return luaL_error(L, "no memory"); + } + + host.len = len; + + ngx_memcpy(host.data, p, len); + host.data[len] = '\0'; + + ngx_memzero(&url, sizeof(ngx_url_t)); + + url.url.len = host.len; + url.url.data = host.data; + url.default_port = (in_port_t) port; + url.no_resolve = 1; + + if (ngx_parse_url(r->pool, &url) != NGX_OK) { + lua_pushnil(L); + + if (url.err) { + lua_pushfstring(L, "failed to parse host name \"%s\": %s", + host.data, url.err); + + } else { + lua_pushfstring(L, "failed to parse host name \"%s\"", host.data); + } + + return 2; + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua tcp socket connect timeout: %M", u->connect_timeout); + + u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t)); + if (u->resolved == NULL) { + return luaL_error(L, "no memory"); + } + + if (url.addrs && url.addrs[0].sockaddr) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua tcp socket network address given directly"); + + u->resolved->sockaddr = url.addrs[0].sockaddr; + u->resolved->socklen = url.addrs[0].socklen; + u->resolved->naddrs = 1; + u->resolved->host = url.addrs[0].name; + + } else { + u->resolved->host = host; + u->resolved->port = (in_port_t) port; + } + + if (u->resolved->sockaddr) { + rc = ngx_http_lua_socket_resolve_retval_handler(r, u, L); + if (rc == NGX_AGAIN) { + return lua_yield(L, 0); + } + + return rc; + } + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + temp.name = host; + rctx = ngx_resolve_start(clcf->resolver, &temp); + if (rctx == NULL) { + u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_RESOLVER; + lua_pushnil(L); + lua_pushliteral(L, "failed to start the resolver"); + return 2; + } + + if (rctx == NGX_NO_RESOLVER) { + u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_RESOLVER; + lua_pushnil(L); + lua_pushfstring(L, "no resolver defined to resolve \"%s\"", host.data); + return 2; + } + + rctx->name = host; +#if !defined(nginx_version) || nginx_version < 1005008 + rctx->type = NGX_RESOLVE_A; +#endif + rctx->handler = ngx_http_lua_socket_resolve_handler; + rctx->data = u; + rctx->timeout = clcf->resolver_timeout; + + u->resolved->ctx = rctx; + u->write_co_ctx = ctx->cur_co_ctx; + + ngx_http_lua_cleanup_pending_operation(coctx); + coctx->cleanup = ngx_http_lua_tcp_resolve_cleanup; + coctx->data = u; + + saved_top = lua_gettop(L); + + if (ngx_resolve_name(rctx) != NGX_OK) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua tcp socket fail to run resolver immediately"); + + u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_RESOLVER; + + coctx->cleanup = NULL; + coctx->data = NULL; + + u->resolved->ctx = NULL; + lua_pushnil(L); + lua_pushfstring(L, "%s could not be resolved", host.data); + + return 2; + } + + if (u->conn_waiting) { + dd("resolved and already connecting"); + return lua_yield(L, 0); + } + + n = lua_gettop(L) - saved_top; + if (n) { + dd("errors occurred during resolving or connecting" + "or already connected"); + return n; + } + + /* still resolving */ + + u->conn_waiting = 1; + u->write_prepare_retvals = ngx_http_lua_socket_resolve_retval_handler; + + dd("setting data to %p", u); + + if (ctx->entered_content_phase) { + r->write_event_handler = ngx_http_lua_content_wev_handler; + + } else { + r->write_event_handler = ngx_http_core_run_phases; + } + + return lua_yield(L, 0); } @@ -1967,8 +1638,7 @@ ngx_http_lua_ssl_handshake_retval_handler(ngx_http_request_t *r, "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_pushlightuserdata(L, &ngx_http_lua_ssl_session_metatable_key); lua_rawget(L, LUA_REGISTRYINDEX); lua_setmetatable(L, -2); } @@ -2085,173 +1755,20 @@ ngx_http_lua_socket_tcp_conn_retval_handler(ngx_http_request_t *r, } -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) -{ - ngx_int_t rc; - 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) { - u->bufs_in = - ngx_http_lua_chain_get_free_buf(r->connection->log, r->pool, - &ctx->free_recv_bufs, - u->conf->buffer_size); - - if (u->bufs_in == NULL) { - return luaL_error(L, "no memory"); - } - - u->buf_in = u->bufs_in; - u->buffer = *u->buf_in->buf; - } - - dd("tcp receive: buf_in: %p, bufs_in: %p", u->buf_in, u->bufs_in); - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua tcp socket read timeout: %M", u->read_timeout); - - if (u->raw_downstream || u->body_downstream) { - r->read_event_handler = ngx_http_lua_req_socket_rev_handler; - } - - u->read_waiting = 0; - u->read_co_ctx = NULL; - - rc = ngx_http_lua_socket_tcp_read(r, u); - - if (rc == NGX_ERROR) { - dd("read failed: %d", (int) u->ft_type); - rc = ngx_http_lua_socket_tcp_receive_retval_handler(r, u, L); - dd("tcp receive retval returned: %d", (int) rc); - return rc; - } - - if (rc == NGX_OK) { - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua tcp socket receive done in a single run"); - - return ngx_http_lua_socket_tcp_receive_retval_handler(r, u, L); - } - - /* rc == NGX_AGAIN */ - - u->read_event_handler = ngx_http_lua_socket_read_handler; - - coctx = ctx->cur_co_ctx; - - ngx_http_lua_cleanup_pending_operation(coctx); - coctx->cleanup = ngx_http_lua_coctx_cleanup; - coctx->data = u; - - if (ctx->entered_content_phase) { - r->write_event_handler = ngx_http_lua_content_wev_handler; - - } else { - r->write_event_handler = ngx_http_core_run_phases; - } - - u->read_co_ctx = coctx; - u->read_waiting = 1; - u->read_prepare_retvals = ngx_http_lua_socket_tcp_receive_retval_handler; - - dd("setting data to %p, coctx:%p", u, coctx); - - if (u->raw_downstream || u->body_downstream) { - ctx->downstream = u; - } - - return lua_yield(L, 0); -} - - -static int -ngx_http_lua_socket_tcp_receiveany(lua_State *L) -{ - int n; - lua_Integer bytes; - ngx_http_request_t *r; - ngx_http_lua_loc_conf_t *llcf; - ngx_http_lua_socket_tcp_upstream_t *u; - - n = lua_gettop(L); - if (n != 2) { - return luaL_error(L, "expecting 2 arguments " - "(including the object), but got %d", n); - } - - r = ngx_http_lua_get_req(L); - if (r == NULL) { - return luaL_error(L, "no request found"); - } - - luaL_checktype(L, 1, LUA_TTABLE); - - lua_rawgeti(L, 1, SOCKET_CTX_INDEX); - u = lua_touserdata(L, -1); - - if (u == NULL || u->peer.connection == NULL || u->read_closed) { - - llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); - - if (llcf->log_socket_errors) { - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "attempt to receive data on a closed socket: u:%p, " - "c:%p, ft:%d eof:%d", - u, u ? u->peer.connection : NULL, - u ? (int) u->ft_type : 0, u ? (int) u->eof : 0); - } - - lua_pushnil(L); - lua_pushliteral(L, "closed"); - return 2; - } - - if (u->request != r) { - return luaL_error(L, "bad request"); - } - - ngx_http_lua_socket_check_busy_connecting(r, u, L); - ngx_http_lua_socket_check_busy_reading(r, u, L); - - if (!lua_isnumber(L, 2)) { - return luaL_argerror(L, 2, "bad max argument"); - } - - bytes = lua_tointeger(L, 2); - if (bytes <= 0) { - return luaL_argerror(L, 2, "bad max argument"); - } - - u->input_filter = ngx_http_lua_socket_read_any; - u->rest = (size_t) bytes; - u->length = u->rest; - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua tcp socket calling receiveany() method to read at " - "most %uz bytes", u->rest); - - return ngx_http_lua_socket_tcp_receive_helper(r, u, L); -} - - static int ngx_http_lua_socket_tcp_receive(lua_State *L) { ngx_http_request_t *r; ngx_http_lua_socket_tcp_upstream_t *u; + ngx_int_t rc; + ngx_http_lua_ctx_t *ctx; int n; ngx_str_t pat; lua_Integer bytes; char *p; int typ; ngx_http_lua_loc_conf_t *llcf; + ngx_http_lua_co_ctx_t *coctx; n = lua_gettop(L); if (n != 1 && n != 2) { @@ -2366,27 +1883,119 @@ ngx_http_lua_socket_tcp_receive(lua_State *L) u->rest = 0; } - return ngx_http_lua_socket_tcp_receive_helper(r, u, L); + u->input_filter_ctx = u; + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + + if (u->bufs_in == NULL) { + u->bufs_in = + ngx_http_lua_chain_get_free_buf(r->connection->log, r->pool, + &ctx->free_recv_bufs, + u->conf->buffer_size); + + if (u->bufs_in == NULL) { + return luaL_error(L, "no memory"); + } + + u->buf_in = u->bufs_in; + u->buffer = *u->buf_in->buf; + } + + dd("tcp receive: buf_in: %p, bufs_in: %p", u->buf_in, u->bufs_in); + + if (u->raw_downstream || u->body_downstream) { + r->read_event_handler = ngx_http_lua_req_socket_rev_handler; + } + + u->read_waiting = 0; + u->read_co_ctx = NULL; + + rc = ngx_http_lua_socket_tcp_read(r, u); + + if (rc == NGX_ERROR) { + dd("read failed: %d", (int) u->ft_type); + rc = ngx_http_lua_socket_tcp_receive_retval_handler(r, u, L); + dd("tcp receive retval returned: %d", (int) rc); + return rc; + } + + if (rc == NGX_OK) { + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua tcp socket receive done in a single run"); + + return ngx_http_lua_socket_tcp_receive_retval_handler(r, u, L); + } + + /* rc == NGX_AGAIN */ + + u->read_event_handler = ngx_http_lua_socket_read_handler; + + coctx = ctx->cur_co_ctx; + + ngx_http_lua_cleanup_pending_operation(coctx); + coctx->cleanup = ngx_http_lua_coctx_cleanup; + coctx->data = u; + + if (ctx->entered_content_phase) { + r->write_event_handler = ngx_http_lua_content_wev_handler; + + } else { + r->write_event_handler = ngx_http_core_run_phases; + } + + u->read_co_ctx = coctx; + u->read_waiting = 1; + u->read_prepare_retvals = ngx_http_lua_socket_tcp_receive_retval_handler; + + dd("setting data to %p, coctx:%p", u, coctx); + + if (u->raw_downstream || u->body_downstream) { + ctx->downstream = u; + } + + return lua_yield(L, 0); } static ngx_int_t ngx_http_lua_socket_read_chunk(void *data, ssize_t bytes) { - ngx_int_t rc; ngx_http_lua_socket_tcp_upstream_t *u = data; - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, u->request->connection->log, 0, + ngx_buf_t *b; +#if (NGX_DEBUG) + ngx_http_request_t *r; + + r = u->request; +#endif + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua tcp socket read chunk %z", bytes); - rc = ngx_http_lua_read_bytes(&u->buffer, u->buf_in, &u->rest, - bytes, u->request->connection->log); - if (rc == NGX_ERROR) { + if (bytes == 0) { u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_CLOSED; return NGX_ERROR; } - return rc; + b = &u->buffer; + + if (bytes >= (ssize_t) u->rest) { + + u->buf_in->buf->last += u->rest; + b->pos += u->rest; + u->rest = 0; + + return NGX_OK; + } + + /* bytes < u->rest */ + + u->buf_in->buf->last += bytes; + b->pos += bytes; + u->rest -= bytes; + + return NGX_AGAIN; } @@ -2395,10 +2004,26 @@ ngx_http_lua_socket_read_all(void *data, ssize_t bytes) { ngx_http_lua_socket_tcp_upstream_t *u = data; - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, u->request->connection->log, 0, + ngx_buf_t *b; +#if (NGX_DEBUG) + ngx_http_request_t *r; + + r = u->request; +#endif + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua tcp socket read all"); - return ngx_http_lua_read_all(&u->buffer, u->buf_in, bytes, - u->request->connection->log); + + if (bytes == 0) { + return NGX_OK; + } + + b = &u->buffer; + + u->buf_in->buf->last += bytes; + b->pos += bytes; + + return NGX_AGAIN; } @@ -2407,40 +2032,72 @@ ngx_http_lua_socket_read_line(void *data, ssize_t bytes) { ngx_http_lua_socket_tcp_upstream_t *u = data; - ngx_int_t rc; + ngx_buf_t *b; + u_char *dst; + u_char c; +#if (NGX_DEBUG) + u_char *begin; +#endif ngx_log_debug0(NGX_LOG_DEBUG_HTTP, u->request->connection->log, 0, "lua tcp socket read line"); - rc = ngx_http_lua_read_line(&u->buffer, u->buf_in, bytes, - u->request->connection->log); - if (rc == NGX_ERROR) { + if (bytes == 0) { u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_CLOSED; return NGX_ERROR; } - return rc; -} + b = &u->buffer; +#if (NGX_DEBUG) + begin = b->pos; +#endif -static ngx_int_t -ngx_http_lua_socket_read_any(void *data, ssize_t bytes) -{ - ngx_http_lua_socket_tcp_upstream_t *u = data; + dd("already read: %p: %.*s", u->buf_in, + (int) (u->buf_in->buf->last - u->buf_in->buf->pos), + u->buf_in->buf->pos); - ngx_int_t rc; + dd("data read: %.*s", (int) bytes, b->pos); - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, u->request->connection->log, 0, - "lua tcp socket read any"); + dst = u->buf_in->buf->last; - rc = ngx_http_lua_read_any(&u->buffer, u->buf_in, &u->rest, bytes, - u->request->connection->log); - if (rc == NGX_ERROR) { - u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_CLOSED; - return NGX_ERROR; + while (bytes--) { + + c = *b->pos++; + + switch (c) { + case '\n': + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, u->request->connection->log, 0, + "lua tcp socket read the final line part: \"%*s\"", + b->pos - 1 - begin, begin); + + u->buf_in->buf->last = dst; + + dd("read a line: %p: %.*s", u->buf_in, + (int) (u->buf_in->buf->last - u->buf_in->buf->pos), + u->buf_in->buf->pos); + + return NGX_OK; + + case '\r': + /* ignore it */ + break; + + default: + *dst++ = c; + break; + } } - return rc; +#if (NGX_DEBUG) + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, u->request->connection->log, 0, + "lua tcp socket read partial line data: %*s", + dst - begin, begin); +#endif + + u->buf_in->buf->last = dst; + + return NGX_AGAIN; } @@ -3882,267 +3539,6 @@ ngx_http_lua_socket_tcp_finalize_write_part(ngx_http_request_t *r, } -static void -ngx_http_lua_socket_tcp_conn_op_timeout_handler(ngx_event_t *ev) -{ - ngx_http_lua_socket_tcp_upstream_t *u; - ngx_http_lua_ctx_t *ctx; - ngx_connection_t *c; - ngx_http_request_t *r; - ngx_http_lua_co_ctx_t *coctx; - ngx_http_lua_loc_conf_t *llcf; - ngx_http_lua_socket_tcp_conn_op_ctx_t *conn_op_ctx; - - conn_op_ctx = ev->data; - ngx_queue_remove(&conn_op_ctx->queue); - - u = conn_op_ctx->u; - r = u->request; - - coctx = u->write_co_ctx; - coctx->cleanup = NULL; - /* note that we store conn_op_ctx in coctx->data instead of u */ - coctx->data = conn_op_ctx; - u->write_co_ctx = NULL; - - llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); - - if (llcf->log_socket_errors) { - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "lua tcp socket queued connect timed out," - " when trying to connect to %V:%ud", - &conn_op_ctx->host, conn_op_ctx->port); - } - - ngx_queue_insert_head(&u->socket_pool->cache_connect_op, - &conn_op_ctx->queue); - u->socket_pool->connections--; - - ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); - if (ctx == NULL) { - return; - } - - ctx->cur_co_ctx = coctx; - - ngx_http_lua_assert(coctx && (!ngx_http_lua_is_thread(ctx) - || coctx->co_ref >= 0)); - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua tcp socket waking up the current request"); - - u->write_prepare_retvals = - ngx_http_lua_socket_tcp_conn_op_timeout_retval_handler; - - c = r->connection; - - if (ctx->entered_content_phase) { - (void) ngx_http_lua_socket_tcp_conn_op_resume(r); - - } else { - ctx->resume_handler = ngx_http_lua_socket_tcp_conn_op_resume; - ngx_http_core_run_phases(r); - } - - ngx_http_run_posted_requests(c); -} - - -static int -ngx_http_lua_socket_tcp_conn_op_timeout_retval_handler(ngx_http_request_t *r, - ngx_http_lua_socket_tcp_upstream_t *u, lua_State *L) -{ - lua_pushnil(L); - lua_pushliteral(L, "timeout"); - return 2; -} - - -static void -ngx_http_lua_socket_tcp_resume_conn_op(ngx_http_lua_socket_pool_t *spool) -{ - ngx_queue_t *q; - ngx_http_lua_socket_tcp_conn_op_ctx_t *conn_op_ctx; - -#if (NGX_DEBUG) - ngx_http_lua_assert(spool->connections >= 0); - -#else - if (spool->connections < 0) { - ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, - "lua tcp socket connections count mismatched for " - "connection pool \"%s\", connections: %i, size: %i", - spool->key, spool->connections, spool->size); - spool->connections = 0; - } -#endif - - /* we manually destroy wait_connect_op before triggering connect - * operation resumption, so that there is no resumption happens when Nginx - * is exiting. - */ - if (ngx_queue_empty(&spool->wait_connect_op)) { - return; - } - - q = ngx_queue_head(&spool->wait_connect_op); - conn_op_ctx = ngx_queue_data(q, ngx_http_lua_socket_tcp_conn_op_ctx_t, - queue); - ngx_log_debug4(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "lua tcp socket post connect operation resumption " - "u: %p, ctx: %p for connection pool \"%s\", " - "connections: %i", - conn_op_ctx->u, conn_op_ctx, spool->key, spool->connections); - - if (conn_op_ctx->event.timer_set) { - ngx_del_timer(&conn_op_ctx->event); - } - - conn_op_ctx->event.handler = - ngx_http_lua_socket_tcp_conn_op_resume_handler; - - ngx_post_event((&conn_op_ctx->event), &ngx_posted_events); -} - - -static void -ngx_http_lua_socket_tcp_conn_op_ctx_cleanup(void *data) -{ - ngx_http_lua_socket_tcp_upstream_t *u; - ngx_http_lua_socket_tcp_conn_op_ctx_t *conn_op_ctx = data; - - u = conn_op_ctx->u; - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, u->request->connection->log, 0, - "cleanup lua tcp socket conn_op_ctx: \"%V\"", - &u->request->uri); - - ngx_queue_insert_head(&u->socket_pool->cache_connect_op, - &conn_op_ctx->queue); -} - - -static void -ngx_http_lua_socket_tcp_conn_op_resume_handler(ngx_event_t *ev) -{ - ngx_queue_t *q; - ngx_connection_t *c; - ngx_http_lua_ctx_t *ctx; - ngx_http_request_t *r; - ngx_http_cleanup_t *cln; - ngx_http_lua_co_ctx_t *coctx; - ngx_http_lua_socket_pool_t *spool; - ngx_http_lua_socket_tcp_upstream_t *u; - ngx_http_lua_socket_tcp_conn_op_ctx_t *conn_op_ctx; - - conn_op_ctx = ev->data; - u = conn_op_ctx->u; - r = u->request; - spool = u->socket_pool; - - if (ngx_queue_empty(&spool->wait_connect_op)) { -#if (NGX_DEBUG) - ngx_http_lua_assert(!(spool->backlog >= 0 - && spool->connections > spool->size)); - -#else - if (spool->backlog >= 0 && spool->connections > spool->size) { - ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, - "lua tcp socket connections count mismatched for " - "connection pool \"%s\", connections: %i, size: %i", - spool->key, spool->connections, spool->size); - spool->connections = spool->size; - } -#endif - - return; - } - - q = ngx_queue_head(&spool->wait_connect_op); - ngx_queue_remove(q); - - coctx = u->write_co_ctx; - coctx->cleanup = NULL; - /* note that we store conn_op_ctx in coctx->data instead of u */ - coctx->data = conn_op_ctx; - /* clear ngx_http_lua_tcp_queue_conn_op_cleanup */ - u->write_co_ctx = NULL; - - ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); - if (ctx == NULL) { - ngx_queue_insert_head(&spool->cache_connect_op, - &conn_op_ctx->queue); - return; - } - - ctx->cur_co_ctx = coctx; - - ngx_http_lua_assert(coctx && (!ngx_http_lua_is_thread(ctx) - || coctx->co_ref >= 0)); - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua tcp socket waking up the current request"); - - u->write_prepare_retvals = - ngx_http_lua_socket_tcp_conn_op_resume_retval_handler; - - c = r->connection; - - if (ctx->entered_content_phase) { - (void) ngx_http_lua_socket_tcp_conn_op_resume(r); - - } else { - cln = ngx_http_lua_cleanup_add(r, 0); - if (cln != NULL) { - cln->handler = ngx_http_lua_socket_tcp_conn_op_ctx_cleanup; - cln->data = conn_op_ctx; - conn_op_ctx->cleanup = &cln->handler; - } - - ctx->resume_handler = ngx_http_lua_socket_tcp_conn_op_resume; - ngx_http_core_run_phases(r); - } - - ngx_http_run_posted_requests(c); -} - - -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) -{ - int nret; - ngx_http_lua_ctx_t *ctx; - ngx_http_lua_co_ctx_t *coctx; - ngx_http_lua_socket_tcp_conn_op_ctx_t *conn_op_ctx; - - ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); - if (ctx == NULL) { - return NGX_ERROR; - } - - coctx = ctx->cur_co_ctx; - dd("coctx: %p", coctx); - conn_op_ctx = coctx->data; - if (conn_op_ctx->cleanup != NULL) { - *conn_op_ctx->cleanup = NULL; - ngx_http_lua_cleanup_free(r, conn_op_ctx->cleanup); - conn_op_ctx->cleanup = NULL; - } - - /* decrease pending connect operation counter */ - u->socket_pool->connections--; - - nret = ngx_http_lua_socket_tcp_connect_helper(L, u, r, ctx, - conn_op_ctx->host.data, - conn_op_ctx->host.len, - conn_op_ctx->port, 1); - ngx_queue_insert_head(&u->socket_pool->cache_connect_op, - &conn_op_ctx->queue); - - return nret; -} - - static void ngx_http_lua_socket_tcp_finalize(ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u) @@ -4193,21 +3589,21 @@ ngx_http_lua_socket_tcp_finalize(ngx_http_request_t *r, ngx_http_lua_socket_tcp_close_connection(c); u->peer.connection = NULL; - u->conn_closed = 1; + + if (!u->reused) { + return; + } spool = u->socket_pool; if (spool == NULL) { return; } - spool->connections--; + spool->active_connections--; - if (spool->connections == 0) { + if (spool->active_connections == 0) { ngx_http_lua_socket_free_pool(r->connection->log, spool); - return; } - - ngx_http_lua_socket_tcp_resume_conn_op(spool); } } @@ -4379,8 +3775,7 @@ ngx_http_lua_socket_tcp_receiveuntil(lua_State *L) return luaL_error(L, "no memory"); } - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - pattern_udata_metatable_key)); + lua_pushlightuserdata(L, &ngx_http_lua_pattern_udata_metatable_key); lua_rawget(L, LUA_REGISTRYINDEX); lua_setmetatable(L, -2); @@ -5035,12 +4430,10 @@ ngx_http_lua_req_socket(lua_State *L) lua_createtable(L, 2 /* narr */, 3 /* nrec */); /* the object */ if (raw) { - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - raw_req_socket_metatable_key)); + lua_pushlightuserdata(L, &ngx_http_lua_raw_req_socket_metatable_key); } else { - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - req_socket_metatable_key)); + lua_pushlightuserdata(L, &ngx_http_lua_req_socket_metatable_key); } lua_rawget(L, LUA_REGISTRYINDEX); @@ -5052,8 +4445,7 @@ ngx_http_lua_req_socket(lua_State *L) } #if 1 - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - downstream_udata_metatable_key)); + lua_pushlightuserdata(L, &ngx_http_lua_downstream_udata_metatable_key); lua_rawget(L, LUA_REGISTRYINDEX); lua_setmetatable(L, -2); #endif @@ -5180,18 +4572,20 @@ ngx_http_lua_socket_tcp_setkeepalive(lua_State *L) ngx_http_lua_socket_tcp_upstream_t *u; ngx_connection_t *c; ngx_http_lua_socket_pool_t *spool; + size_t size, key_len; ngx_str_t key; + ngx_uint_t i; ngx_queue_t *q; ngx_peer_connection_t *pc; + u_char *p; ngx_http_request_t *r; ngx_msec_t timeout; - ngx_int_t pool_size; + ngx_uint_t pool_size; int n; ngx_int_t rc; ngx_buf_t *b; - const char *msg; - ngx_http_lua_socket_pool_item_t *item; + ngx_http_lua_socket_pool_item_t *items, *item; n = lua_gettop(L); @@ -5202,6 +4596,17 @@ ngx_http_lua_socket_tcp_setkeepalive(lua_State *L) luaL_checktype(L, 1, LUA_TTABLE); + lua_pushlightuserdata(L, &ngx_http_lua_socket_pool_key); + lua_rawget(L, LUA_REGISTRYINDEX); + + lua_rawgeti(L, 1, SOCKET_KEY_INDEX); + key.data = (u_char *) lua_tolstring(L, -1, &key.len); + if (key.data == NULL) { + lua_pushnil(L); + lua_pushliteral(L, "key not found"); + return 2; + } + lua_rawgeti(L, 1, SOCKET_CTX_INDEX); u = lua_touserdata(L, -1); lua_pop(L, 1); @@ -5212,7 +4617,7 @@ ngx_http_lua_socket_tcp_setkeepalive(lua_State *L) return 2; } - /* stack: obj timeout? size? */ + /* stack: obj cache key */ pc = &u->peer; c = pc->connection; @@ -5264,32 +4669,9 @@ ngx_http_lua_socket_tcp_setkeepalive(lua_State *L) return 2; } - if (ngx_terminate || ngx_exiting) { - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, - "lua tcp socket set keepalive while process exiting, " - "closing connection %p", c); - - ngx_http_lua_socket_tcp_finalize(r, u); - lua_pushinteger(L, 1); - return 1; - } - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, "lua tcp socket set keepalive: saving connection %p", c); - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask(socket_pool_key)); - lua_rawget(L, LUA_REGISTRYINDEX); - - /* stack: obj timeout? size? pools */ - - lua_rawgeti(L, 1, SOCKET_KEY_INDEX); - key.data = (u_char *) lua_tolstring(L, -1, &key.len); - if (key.data == NULL) { - lua_pushnil(L); - lua_pushliteral(L, "key not found"); - return 2; - } - dd("saving connection to key %s", lua_tostring(L, -1)); lua_pushvalue(L, -1); @@ -5297,7 +4679,7 @@ ngx_http_lua_socket_tcp_setkeepalive(lua_State *L) spool = lua_touserdata(L, -1); lua_pop(L, 1); - /* stack: obj timeout? size? pools cache_key */ + /* stack: obj timeout? size? cache key */ llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); @@ -5311,49 +4693,82 @@ ngx_http_lua_socket_tcp_setkeepalive(lua_State *L) pool_size = llcf->pool_size; } - if (pool_size <= 0) { - msg = lua_pushfstring(L, "bad \"pool_size\" option value: %i", - pool_size); - return luaL_argerror(L, n, msg); + if (pool_size == 0) { + lua_pushnil(L); + lua_pushliteral(L, "zero pool size"); + return 2; } - ngx_http_lua_socket_tcp_create_socket_pool(L, r, key, pool_size, -1, - &spool); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua tcp socket connection pool size: %ui", pool_size); + + key_len = ngx_align(key.len + 1, sizeof(void *)); + + size = sizeof(ngx_http_lua_socket_pool_t) + key_len - 1 + + sizeof(ngx_http_lua_socket_pool_item_t) + * pool_size; + + spool = lua_newuserdata(L, size); + if (spool == NULL) { + return luaL_error(L, "no memory"); + } + + lua_pushlightuserdata(L, &ngx_http_lua_pool_udata_metatable_key); + lua_rawget(L, LUA_REGISTRYINDEX); + lua_setmetatable(L, -2); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, + "lua tcp socket keepalive create connection pool for key" + " \"%s\"", lua_tostring(L, -2)); + + lua_rawset(L, -3); + + spool->active_connections = 0; + spool->lua_vm = ngx_http_lua_get_lua_vm(r, NULL); + + ngx_queue_init(&spool->cache); + ngx_queue_init(&spool->free); + + p = ngx_copy(spool->key, key.data, key.len); + *p++ = '\0'; + + items = (ngx_http_lua_socket_pool_item_t *) (spool->key + key_len); + + dd("items: %p", items); + + ngx_http_lua_assert((void *) items == ngx_align_ptr(items, + sizeof(void *))); + + for (i = 0; i < pool_size; i++) { + ngx_queue_insert_head(&spool->free, &items[i].queue); + items[i].socket_pool = spool; + } } if (ngx_queue_empty(&spool->free)) { q = ngx_queue_last(&spool->cache); ngx_queue_remove(q); + spool->active_connections--; item = ngx_queue_data(q, ngx_http_lua_socket_pool_item_t, queue); ngx_http_lua_socket_tcp_close_connection(item->connection); - /* only decrease the counter for connections which were counted */ - if (u->socket_pool != NULL) { - u->socket_pool->connections--; - } - } else { q = ngx_queue_head(&spool->free); ngx_queue_remove(q); item = ngx_queue_data(q, ngx_http_lua_socket_pool_item_t, queue); - - /* we should always increase connections after getting connected, - * and decrease connections after getting closed. - * however, we don't create connection pool in previous connect method. - * so we increase connections here for backward compatibility. - */ - if (u->socket_pool == NULL) { - spool->connections++; - } } item->connection = c; ngx_queue_insert_head(&spool->cache, q); + if (!u->reused) { + spool->active_connections++; + } + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0, "lua tcp socket clear current socket connection"); @@ -5422,33 +4837,48 @@ ngx_http_lua_socket_tcp_setkeepalive(lua_State *L) ngx_http_lua_socket_tcp_finalize(r, u); #endif - /* since we set u->peer->connection to NULL previously, the connect - * operation won't be resumed in the ngx_http_lua_socket_tcp_finalize. - * Therefore we need to resume it here. - */ - ngx_http_lua_socket_tcp_resume_conn_op(spool); - lua_pushinteger(L, 1); return 1; } static ngx_int_t -ngx_http_lua_get_keepalive_peer(ngx_http_request_t *r, - ngx_http_lua_socket_tcp_upstream_t *u) +ngx_http_lua_get_keepalive_peer(ngx_http_request_t *r, lua_State *L, + int key_index, ngx_http_lua_socket_tcp_upstream_t *u) { ngx_http_lua_socket_pool_item_t *item; ngx_http_lua_socket_pool_t *spool; ngx_http_cleanup_t *cln; ngx_queue_t *q; + int top; ngx_peer_connection_t *pc; ngx_connection_t *c; + top = lua_gettop(L); + + if (key_index < 0) { + key_index = top + key_index + 1; + } + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua tcp socket pool get keepalive peer"); pc = &u->peer; - spool = u->socket_pool; + + lua_pushlightuserdata(L, &ngx_http_lua_socket_pool_key); + lua_rawget(L, LUA_REGISTRYINDEX); /* table */ + lua_pushvalue(L, key_index); /* key */ + lua_rawget(L, -2); + + spool = lua_touserdata(L, -1); + if (spool == NULL) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0, + "lua tcp socket keepalive connection pool not found"); + lua_settop(L, top); + return NGX_DECLINED; + } + + u->socket_pool = spool; if (!ngx_queue_empty(&spool->cache)) { q = ngx_queue_head(&spool->cache); @@ -5493,6 +4923,7 @@ ngx_http_lua_get_keepalive_peer(ngx_http_request_t *r, cln = ngx_http_lua_cleanup_add(r, 0); if (cln == NULL) { u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_ERROR; + lua_settop(L, top); return NGX_ERROR; } @@ -5501,12 +4932,16 @@ ngx_http_lua_get_keepalive_peer(ngx_http_request_t *r, u->cleanup = &cln->handler; } + lua_settop(L, top); + return NGX_OK; } ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0, "lua tcp socket keepalive: connection pool empty"); + lua_settop(L, top); + return NGX_DECLINED; } @@ -5578,15 +5013,13 @@ close: ngx_queue_remove(&item->queue); ngx_queue_insert_head(&spool->free, &item->queue); - spool->connections--; + spool->active_connections--; - dd("keepalive: connections: %u", (unsigned) spool->connections); + dd("keepalive: active connections: %u", + (unsigned) spool->active_connections); - if (spool->connections == 0) { + if (spool->active_connections == 0) { ngx_http_lua_socket_free_pool(ev->log, spool); - - } else { - ngx_http_lua_socket_tcp_resume_conn_op(spool); } return NGX_DECLINED; @@ -5604,7 +5037,7 @@ ngx_http_lua_socket_free_pool(ngx_log_t *log, ngx_http_lua_socket_pool_t *spool) L = spool->lua_vm; - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask(socket_pool_key)); + lua_pushlightuserdata(L, &ngx_http_lua_socket_pool_key); lua_rawget(L, LUA_REGISTRYINDEX); lua_pushstring(L, (char *) spool->key); lua_pushnil(L); @@ -5616,10 +5049,9 @@ ngx_http_lua_socket_free_pool(ngx_log_t *log, ngx_http_lua_socket_pool_t *spool) static void ngx_http_lua_socket_shutdown_pool_helper(ngx_http_lua_socket_pool_t *spool) { - ngx_queue_t *q; - ngx_connection_t *c; - ngx_http_lua_socket_pool_item_t *item; - ngx_http_lua_socket_tcp_conn_op_ctx_t *conn_op_ctx; + ngx_queue_t *q; + ngx_connection_t *c; + ngx_http_lua_socket_pool_item_t *item; while (!ngx_queue_empty(&spool->cache)) { q = ngx_queue_head(&spool->cache); @@ -5633,29 +5065,7 @@ ngx_http_lua_socket_shutdown_pool_helper(ngx_http_lua_socket_pool_t *spool) ngx_queue_insert_head(&spool->free, q); } - while (!ngx_queue_empty(&spool->cache_connect_op)) { - q = ngx_queue_head(&spool->cache_connect_op); - ngx_queue_remove(q); - conn_op_ctx = ngx_queue_data(q, ngx_http_lua_socket_tcp_conn_op_ctx_t, - queue); - ngx_http_lua_socket_tcp_free_conn_op_ctx(conn_op_ctx); - } - - while (!ngx_queue_empty(&spool->wait_connect_op)) { - q = ngx_queue_head(&spool->wait_connect_op); - ngx_queue_remove(q); - conn_op_ctx = ngx_queue_data(q, ngx_http_lua_socket_tcp_conn_op_ctx_t, - queue); - - if (conn_op_ctx->event.timer_set) { - ngx_del_timer(&conn_op_ctx->event); - } - - ngx_http_lua_socket_tcp_free_conn_op_ctx(conn_op_ctx); - } - - /* spool->connections will be decreased down to zero in - * ngx_http_lua_socket_tcp_finalize */ + spool->active_connections = 0; } @@ -5909,13 +5319,6 @@ static ngx_int_t ngx_http_lua_socket_insert_buffer(ngx_http_request_t *r, } -static ngx_int_t -ngx_http_lua_socket_tcp_conn_op_resume(ngx_http_request_t *r) -{ - return ngx_http_lua_socket_tcp_resume_helper(r, SOCKET_OP_RESUME_CONN); -} - - static ngx_int_t ngx_http_lua_socket_tcp_conn_resume(ngx_http_request_t *r) { @@ -5940,14 +5343,13 @@ ngx_http_lua_socket_tcp_write_resume(ngx_http_request_t *r) static ngx_int_t ngx_http_lua_socket_tcp_resume_helper(ngx_http_request_t *r, int socket_op) { - int nret; - lua_State *vm; - ngx_int_t rc; - ngx_uint_t nreqs; - ngx_connection_t *c; - ngx_http_lua_ctx_t *ctx; - ngx_http_lua_co_ctx_t *coctx; - ngx_http_lua_socket_tcp_conn_op_ctx_t *conn_op_ctx; + int nret; + lua_State *vm; + ngx_int_t rc; + ngx_uint_t nreqs; + ngx_connection_t *c; + ngx_http_lua_ctx_t *ctx; + ngx_http_lua_co_ctx_t *coctx; ngx_http_lua_socket_tcp_retval_handler prepare_retvals; @@ -5967,22 +5369,15 @@ ngx_http_lua_socket_tcp_resume_helper(ngx_http_request_t *r, int socket_op) dd("coctx: %p", coctx); + u = coctx->data; + switch (socket_op) { - - case SOCKET_OP_RESUME_CONN: - conn_op_ctx = coctx->data; - u = conn_op_ctx->u; - prepare_retvals = u->write_prepare_retvals; - break; - case SOCKET_OP_CONNECT: case SOCKET_OP_WRITE: - u = coctx->data; prepare_retvals = u->write_prepare_retvals; break; case SOCKET_OP_READ: - u = coctx->data; prepare_retvals = u->read_prepare_retvals; break; @@ -5996,15 +5391,6 @@ ngx_http_lua_socket_tcp_resume_helper(ngx_http_request_t *r, int socket_op) "u:%p", prepare_retvals, u); nret = prepare_retvals(r, u, ctx->cur_co_ctx->co); - if (socket_op == SOCKET_OP_CONNECT - && nret > 1 - && !u->conn_closed - && u->socket_pool != NULL) - { - u->socket_pool->connections--; - ngx_http_lua_socket_tcp_resume_conn_op(u->socket_pool); - } - if (nret == NGX_AGAIN) { return NGX_DONE; } @@ -6036,36 +5422,6 @@ ngx_http_lua_socket_tcp_resume_helper(ngx_http_request_t *r, int socket_op) } -static void -ngx_http_lua_tcp_queue_conn_op_cleanup(void *data) -{ - ngx_http_lua_co_ctx_t *coctx = data; - ngx_http_lua_socket_tcp_upstream_t *u; - ngx_http_lua_socket_tcp_conn_op_ctx_t *conn_op_ctx; - - conn_op_ctx = coctx->data; - u = conn_op_ctx->u; - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "lua tcp socket abort queueing, conn_op_ctx: %p, u: %p", - conn_op_ctx, u); - - if (conn_op_ctx->event.posted) { - ngx_delete_posted_event(&conn_op_ctx->event); - - } else if (conn_op_ctx->event.timer_set) { - ngx_del_timer(&conn_op_ctx->event); - } - - ngx_queue_remove(&conn_op_ctx->queue); - ngx_queue_insert_head(&u->socket_pool->cache_connect_op, - &conn_op_ctx->queue); - - u->socket_pool->connections--; - ngx_http_lua_socket_tcp_resume_conn_op(u->socket_pool); -} - - static void ngx_http_lua_tcp_resolve_cleanup(void *data) { @@ -6081,11 +5437,6 @@ ngx_http_lua_tcp_resolve_cleanup(void *data) return; } - if (u->socket_pool != NULL) { - u->socket_pool->connections--; - ngx_http_lua_socket_tcp_resume_conn_op(u->socket_pool); - } - rctx = u->resolved->ctx; if (rctx == NULL) { return; @@ -6145,8 +5496,7 @@ ngx_http_lua_cleanup_conn_pools(lua_State *L) { ngx_http_lua_socket_pool_t *spool; - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - socket_pool_key)); + lua_pushlightuserdata(L, &ngx_http_lua_socket_pool_key); lua_rawget(L, LUA_REGISTRYINDEX); /* table */ lua_pushnil(L); /* first key */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_socket_tcp.h b/debian/modules/http-lua/src/ngx_http_lua_socket_tcp.h index 091e437..dbdee41 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_socket_tcp.h +++ b/debian/modules/http-lua/src/ngx_http_lua_socket_tcp.h @@ -35,39 +35,17 @@ typedef void (*ngx_http_lua_socket_tcp_upstream_handler_pt) (ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u); -typedef struct { - ngx_event_t event; - ngx_queue_t queue; - ngx_str_t host; - ngx_http_cleanup_pt *cleanup; - ngx_http_lua_socket_tcp_upstream_t *u; - in_port_t port; -} ngx_http_lua_socket_tcp_conn_op_ctx_t; - - -#define ngx_http_lua_socket_tcp_free_conn_op_ctx(conn_op_ctx) \ - ngx_free(conn_op_ctx->host.data); \ - ngx_free(conn_op_ctx) - - typedef struct { lua_State *lua_vm; - ngx_int_t size; - ngx_queue_t cache_connect_op; - ngx_queue_t wait_connect_op; - - /* connections == active connections + pending connect operations, - * while active connections == out-of-pool reused connections - * + in-pool connections */ - ngx_int_t connections; + /* active connections == out-of-pool reused connections + * + in-pool connections */ + ngx_uint_t active_connections; /* queues of ngx_http_lua_socket_pool_item_t: */ ngx_queue_t cache; ngx_queue_t free; - ngx_int_t backlog; - u_char key[1]; } ngx_http_lua_socket_pool_t; @@ -126,7 +104,6 @@ struct ngx_http_lua_socket_tcp_upstream_s { unsigned raw_downstream:1; unsigned read_closed:1; unsigned write_closed:1; - unsigned conn_closed:1; #if (NGX_HTTP_SSL) unsigned ssl_verify:1; unsigned ssl_session_reuse:1; diff --git a/debian/modules/http-lua/src/ngx_http_lua_socket_udp.c b/debian/modules/http-lua/src/ngx_http_lua_socket_udp.c index cbc32d6..8927f41 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_socket_udp.c +++ b/debian/modules/http-lua/src/ngx_http_lua_socket_udp.c @@ -81,8 +81,7 @@ ngx_http_lua_inject_socket_udp_api(ngx_log_t *log, lua_State *L) lua_setfield(L, -2, "udp"); /* ngx socket */ /* udp socket object metatable */ - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - socket_udp_metatable_key)); + lua_pushlightuserdata(L, &ngx_http_lua_socket_udp_metatable_key); lua_createtable(L, 0 /* narr */, 6 /* nrec */); lua_pushcfunction(L, ngx_http_lua_socket_udp_setpeername); @@ -106,8 +105,7 @@ ngx_http_lua_inject_socket_udp_api(ngx_log_t *log, lua_State *L) /* }}} */ /* udp socket object metatable */ - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - udp_udata_metatable_key)); + lua_pushlightuserdata(L, &ngx_http_lua_udp_udata_metatable_key); lua_createtable(L, 0 /* narr */, 1 /* nrec */); /* metatable */ lua_pushcfunction(L, ngx_http_lua_socket_udp_upstream_destroy); lua_setfield(L, -2, "__gc"); @@ -146,8 +144,7 @@ ngx_http_lua_socket_udp(lua_State *L) | NGX_HTTP_LUA_CONTEXT_SSL_CERT); lua_createtable(L, 3 /* narr */, 1 /* nrec */); - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - socket_udp_metatable_key)); + lua_pushlightuserdata(L, &ngx_http_lua_socket_udp_metatable_key); lua_rawget(L, LUA_REGISTRYINDEX); lua_setmetatable(L, -2); @@ -266,8 +263,7 @@ ngx_http_lua_socket_udp_setpeername(lua_State *L) } #if 1 - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - udp_udata_metatable_key)); + lua_pushlightuserdata(L, &ngx_http_lua_udp_udata_metatable_key); lua_rawget(L, LUA_REGISTRYINDEX); lua_setmetatable(L, -2); #endif diff --git a/debian/modules/http-lua/src/ngx_http_lua_ssl_certby.c b/debian/modules/http-lua/src/ngx_http_lua_ssl_certby.c index 622d0a5..453a5c7 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_ssl_certby.c +++ b/debian/modules/http-lua/src/ngx_http_lua_ssl_certby.c @@ -498,11 +498,9 @@ ngx_http_lua_ssl_cert_by_chunk(lua_State *L, ngx_http_request_t *r) /* 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); diff --git a/debian/modules/http-lua/src/ngx_http_lua_ssl_session_fetchby.c b/debian/modules/http-lua/src/ngx_http_lua_ssl_session_fetchby.c index 303efb4..0b88a87 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_ssl_session_fetchby.c +++ b/debian/modules/http-lua/src/ngx_http_lua_ssl_session_fetchby.c @@ -505,11 +505,9 @@ ngx_http_lua_ssl_sess_fetch_by_chunk(lua_State *L, ngx_http_request_t *r) /* 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); diff --git a/debian/modules/http-lua/src/ngx_http_lua_ssl_session_storeby.c b/debian/modules/http-lua/src/ngx_http_lua_ssl_session_storeby.c index a02f729..7609c39 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_ssl_session_storeby.c +++ b/debian/modules/http-lua/src/ngx_http_lua_ssl_session_storeby.c @@ -380,8 +380,6 @@ ngx_http_lua_ssl_sess_store_by_chunk(lua_State *L, ngx_http_request_t *r) /* init nginx context in Lua VM */ ngx_http_lua_set_req(L, r); - -#ifndef OPENRESTY_LUAJIT ngx_http_lua_create_new_globals_table(L, 0 /* narr */, 1 /* nrec */); /* {{{ make new env inheriting main thread's globals table */ @@ -392,7 +390,6 @@ ngx_http_lua_ssl_sess_store_by_chunk(lua_State *L, ngx_http_request_t *r) /* }}} */ lua_setfenv(L, -2); /* set new running env for the code closure */ -#endif lua_pushcfunction(L, ngx_http_lua_traceback); lua_insert(L, 1); /* put it under chunk and args */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_string.c b/debian/modules/http-lua/src/ngx_http_lua_string.c index bdadeb4..239b232 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_string.c +++ b/debian/modules/http-lua/src/ngx_http_lua_string.c @@ -762,20 +762,6 @@ ngx_http_lua_ffi_escape_uri(const u_char *src, size_t len, u_char *dst) ngx_http_lua_escape_uri(dst, (u_char *) src, len, NGX_ESCAPE_URI_COMPONENT); } - -void -ngx_http_lua_ffi_str_replace_char(u_char *buf, size_t len, const u_char find, - const u_char replace) -{ - while (len) { - if (*buf == find) { - *buf = replace; - } - - buf++; - len--; - } -} #endif /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_subrequest.c b/debian/modules/http-lua/src/ngx_http_lua_subrequest.c index f312b65..826a43c 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_subrequest.c +++ b/debian/modules/http-lua/src/ngx_http_lua_subrequest.c @@ -1031,14 +1031,6 @@ ngx_http_lua_post_subrequest(ngx_http_request_t *r, void *data, ngx_int_t rc) dd("pr_coctx status: %d", (int) pr_coctx->sr_statuses[ctx->index]); /* copy subrequest response headers */ - if (ctx->headers_set) { - rc = ngx_http_lua_set_content_type(r, ctx); - if (rc != NGX_OK) { - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "failed to set default content type: %i", rc); - return NGX_ERROR; - } - } pr_coctx->sr_headers[ctx->index] = &r->headers_out; diff --git a/debian/modules/http-lua/src/ngx_http_lua_timer.c b/debian/modules/http-lua/src/ngx_http_lua_timer.c index e92c211..596b2f7 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_timer.c +++ b/debian/modules/http-lua/src/ngx_http_lua_timer.c @@ -220,7 +220,6 @@ ngx_http_lua_ngx_timer_helper(lua_State *L, int every) ngx_http_lua_probe_user_coroutine_create(r, L, co); -#ifndef OPENRESTY_LUAJIT lua_createtable(co, 0, 0); /* the new globals table */ /* co stack: global_tb */ @@ -233,7 +232,6 @@ ngx_http_lua_ngx_timer_helper(lua_State *L, int every) /* co stack: global_tb */ ngx_http_lua_set_globals_table(co); -#endif /* co stack: */ @@ -253,15 +251,12 @@ ngx_http_lua_ngx_timer_helper(lua_State *L, int every) /* L stack: time func [args] thread */ /* co stack: func */ -#ifndef OPENRESTY_LUAJIT ngx_http_lua_get_globals_table(co); lua_setfenv(co, -2); -#endif /* co stack: func */ - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - coroutines_key)); + lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); lua_rawget(L, LUA_REGISTRYINDEX); /* L stack: time func [args] thread coroutines */ @@ -350,9 +345,6 @@ ngx_http_lua_ngx_timer_helper(lua_State *L, int every) ngx_add_timer(ev, delay); - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "created timer (co: %p delay: %M ms)", tctx->co, delay); - lua_pushinteger(L, 1); return 1; @@ -366,8 +358,7 @@ nomem: ngx_free(ev); } - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - coroutines_key)); + lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); lua_rawget(L, LUA_REGISTRYINDEX); luaL_unref(L, -1, co_ref); @@ -396,7 +387,6 @@ ngx_http_lua_timer_copy(ngx_http_lua_timer_ctx_t *old_tctx) co = lua_newthread(vm); -#ifndef OPENRESTY_LUAJIT lua_createtable(co, 0, 0); /* the new globals table */ /* co stack: global_tb */ @@ -409,7 +399,6 @@ ngx_http_lua_timer_copy(ngx_http_lua_timer_ctx_t *old_tctx) /* co stack: global_tb */ ngx_http_lua_set_globals_table(co); -#endif /* co stack: */ @@ -429,15 +418,12 @@ ngx_http_lua_timer_copy(ngx_http_lua_timer_ctx_t *old_tctx) /* L stack: func [args] thread */ /* co stack: func */ -#ifndef OPENRESTY_LUAJIT ngx_http_lua_get_globals_table(co); lua_setfenv(co, -2); -#endif /* co stack: func */ - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - coroutines_key)); + lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); lua_rawget(L, LUA_REGISTRYINDEX); /* L stack: func [args] thread coroutines */ @@ -512,10 +498,6 @@ ngx_http_lua_timer_copy(ngx_http_lua_timer_ctx_t *old_tctx) ngx_add_timer(ev, tctx->delay); - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "created next timer (co: %p delay: %M ms)", tctx->co, - tctx->delay); - return NGX_OK; nomem: @@ -530,8 +512,7 @@ nomem: /* L stack: func [args] */ - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - coroutines_key)); + lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); lua_rawget(L, LUA_REGISTRYINDEX); luaL_unref(L, -1, co_ref); @@ -587,9 +568,6 @@ ngx_http_lua_timer_handler(ngx_event_t *ev) c = ngx_http_lua_create_fake_connection(tctx.pool); if (c == NULL) { - ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, - "failed to create fake connection to run timer (co: %p)", - tctx.co); goto failed; } @@ -601,9 +579,6 @@ ngx_http_lua_timer_handler(ngx_event_t *ev) r = ngx_http_lua_create_fake_request(c); if (r == NULL) { - ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, - "failed to create fake request to run timer (co: %p)", - tctx.co); goto failed; } @@ -639,8 +614,6 @@ ngx_http_lua_timer_handler(ngx_event_t *ev) ctx = ngx_http_lua_create_ctx(r); if (ctx == NULL) { - ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, - "failed to create ctx to run timer (co: %p)", tctx.co); goto failed; } @@ -649,9 +622,6 @@ ngx_http_lua_timer_handler(ngx_event_t *ev) pcln = ngx_pool_cleanup_add(r->pool, 0); if (pcln == NULL) { - ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, - "failed to add vm cleanup to run timer (co: %p)", - tctx.co); goto failed; } @@ -665,9 +635,6 @@ ngx_http_lua_timer_handler(ngx_event_t *ev) cln = ngx_http_cleanup_add(r, 0); if (cln == NULL) { - ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, - "failed to add request cleanup to run timer (co: %p)", - tctx.co); goto failed; } @@ -725,8 +692,7 @@ ngx_http_lua_timer_handler(ngx_event_t *ev) failed: if (tctx.co_ref && tctx.co) { - lua_pushlightuserdata(tctx.co, ngx_http_lua_lightudata_mask( - coroutines_key)); + lua_pushlightuserdata(tctx.co, &ngx_http_lua_coroutines_key); lua_rawget(tctx.co, LUA_REGISTRYINDEX); luaL_unref(tctx.co, -1, tctx.co_ref); lua_settop(tctx.co, 0); diff --git a/debian/modules/http-lua/src/ngx_http_lua_uthread.c b/debian/modules/http-lua/src/ngx_http_lua_uthread.c index 43517a0..8195ec0 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_uthread.c +++ b/debian/modules/http-lua/src/ngx_http_lua_uthread.c @@ -70,8 +70,7 @@ ngx_http_lua_uthread_spawn(lua_State *L) /* anchor the newly created coroutine into the Lua registry */ - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - coroutines_key)); + lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); lua_rawget(L, LUA_REGISTRYINDEX); lua_pushvalue(L, -2); coctx->co_ref = luaL_ref(L, -2); diff --git a/debian/modules/http-lua/src/ngx_http_lua_util.c b/debian/modules/http-lua/src/ngx_http_lua_util.c index c12262e..f7a537e 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_util.c +++ b/debian/modules/http-lua/src/ngx_http_lua_util.c @@ -70,25 +70,6 @@ #endif -#if (NGX_HTTP_LUA_HAVE_SA_RESTART) -#define NGX_HTTP_LUA_SA_RESTART_SIGS { \ - ngx_signal_value(NGX_RECONFIGURE_SIGNAL), \ - ngx_signal_value(NGX_REOPEN_SIGNAL), \ - ngx_signal_value(NGX_NOACCEPT_SIGNAL), \ - ngx_signal_value(NGX_TERMINATE_SIGNAL), \ - ngx_signal_value(NGX_SHUTDOWN_SIGNAL), \ - ngx_signal_value(NGX_CHANGEBIN_SIGNAL), \ - SIGALRM, \ - SIGINT, \ - SIGIO, \ - SIGCHLD, \ - SIGSYS, \ - SIGPIPE, \ - 0 \ -}; -#endif - - char ngx_http_lua_code_cache_key; char ngx_http_lua_regex_cache_key; char ngx_http_lua_socket_pool_key; @@ -147,13 +128,6 @@ static int ngx_http_lua_get_raw_phase_context(lua_State *L); #define LUA_PATH_SEP ";" #endif - -#if !defined(LUA_DEFAULT_PATH) && (NGX_DEBUG) -#define LUA_DEFAULT_PATH "../lua-resty-core/lib/?.lua;" \ - "../lua-resty-lrucache/lib/?.lua" -#endif - - #define AUX_MARK "\1" @@ -197,7 +171,6 @@ ngx_http_lua_set_path(ngx_cycle_t *cycle, lua_State *L, int tab_idx, } -#ifndef OPENRESTY_LUAJIT /** * Create new table and set _G field to itself. * @@ -212,7 +185,6 @@ ngx_http_lua_create_new_globals_table(lua_State *L, int narr, int nrec) lua_pushvalue(L, -1); lua_setfield(L, -2, "_G"); } -#endif /* OPENRESTY_LUAJIT */ static lua_State * @@ -341,13 +313,11 @@ ngx_http_lua_new_thread(ngx_http_request_t *r, lua_State *L, int *ref) base = lua_gettop(L); - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - coroutines_key)); + lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); lua_rawget(L, LUA_REGISTRYINDEX); co = lua_newthread(L); -#ifndef OPENRESTY_LUAJIT /* {{{ inherit coroutine's globals to main thread's globals table * for print() function will try to find tostring() in current * globals table. @@ -362,7 +332,6 @@ ngx_http_lua_new_thread(ngx_http_request_t *r, lua_State *L, int *ref) ngx_http_lua_set_globals_table(co); /* }}} */ -#endif /* OPENRESTY_LUAJIT */ *ref = luaL_ref(L, -2); @@ -387,8 +356,7 @@ ngx_http_lua_del_thread(ngx_http_request_t *r, lua_State *L, ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua deleting light thread"); - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - coroutines_key)); + lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); lua_rawget(L, LUA_REGISTRYINDEX); ngx_http_lua_probe_thread_delete(r, coctx->co, ctx); @@ -440,9 +408,7 @@ 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) - { + if (!ctx->headers_set && ngx_http_lua_set_content_type(r) != NGX_OK) { return NGX_ERROR; } @@ -691,8 +657,7 @@ ngx_http_lua_init_registry(lua_State *L, ngx_log_t *log) /* {{{ register a table to anchor lua coroutines reliably: * {([int]ref) = [cort]} */ - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - coroutines_key)); + lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); lua_createtable(L, 0, 32 /* nrec */); lua_rawset(L, LUA_REGISTRYINDEX); /* }}} */ @@ -703,23 +668,20 @@ ngx_http_lua_init_registry(lua_State *L, ngx_log_t *log) lua_rawset(L, LUA_REGISTRYINDEX); /* create the registry entry for the Lua socket connection pool table */ - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - socket_pool_key)); + lua_pushlightuserdata(L, &ngx_http_lua_socket_pool_key); lua_createtable(L, 0, 8 /* nrec */); lua_rawset(L, LUA_REGISTRYINDEX); #if (NGX_PCRE) /* create the registry entry for the Lua precompiled regex object cache */ - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - regex_cache_key)); + lua_pushlightuserdata(L, &ngx_http_lua_regex_cache_key); lua_createtable(L, 0, 16 /* nrec */); lua_rawset(L, LUA_REGISTRYINDEX); #endif /* {{{ register table to cache user code: * { [(string)cache_key] = } */ - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - code_cache_key)); + lua_pushlightuserdata(L, &ngx_http_lua_code_cache_key); lua_createtable(L, 0, 8 /* nrec */); lua_rawset(L, LUA_REGISTRYINDEX); /* }}} */ @@ -733,6 +695,9 @@ ngx_http_lua_init_globals(lua_State *L, ngx_cycle_t *cycle, ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "lua initializing lua globals"); + lua_pushlightuserdata(L, cycle); + lua_setglobal(L, "__ngx_cycle"); + #if defined(NDK) && NDK ngx_http_lua_inject_ndk_api(L); #endif /* defined(NDK) && NDK */ @@ -791,52 +756,6 @@ ngx_http_lua_inject_ngx_api(lua_State *L, ngx_http_lua_main_conf_t *lmcf, lua_setglobal(L, "ngx"); ngx_http_lua_inject_coroutine_api(log, L); - -#ifdef OPENRESTY_LUAJIT - { - int rc; - - const char buf[] = - "local ngx_log = ngx.log\n" - "local ngx_WARN = ngx.WARN\n" - "local tostring = tostring\n" - "local ngx_get_phase = ngx.get_phase\n" - "local traceback = require 'debug'.traceback\n" - "local function newindex(table, key, value)\n" - "rawset(table, key, value)\n" - "local phase = ngx_get_phase()\n" - "if phase == 'init_worker' or phase == 'init' then\n" - "return\n" - "end\n" - "ngx_log(ngx_WARN, 'writing a global lua variable " - "(\\'', tostring(key), '\\') which may lead to " - "race conditions between concurrent requests, so " - "prefer the use of \\'local\\' variables', " - "traceback('', 2))\n" - "end\n" - "setmetatable(_G, { __newindex = newindex })\n" - ; - - rc = luaL_loadbuffer(L, buf, sizeof(buf) - 1, "=_G write guard"); - - if (rc != 0) { - ngx_log_error(NGX_LOG_ERR, log, 0, - "failed to load Lua code (%i): %s", - rc, lua_tostring(L, -1)); - - lua_pop(L, 1); - return; - } - - rc = lua_pcall(L, 0, 0, 0); - if (rc != 0) { - ngx_log_error(NGX_LOG_ERR, log, 0, - "failed to run Lua code (%i): %s", - rc, lua_tostring(L, -1)); - lua_pop(L, 1); - } - } -#endif } @@ -3035,12 +2954,12 @@ ngx_http_lua_param_get(lua_State *L) | NGX_HTTP_LUA_CONTEXT_BODY_FILTER); if (ctx->context & (NGX_HTTP_LUA_CONTEXT_SET)) { - return ngx_http_lua_setby_param_get(L, r); + return ngx_http_lua_setby_param_get(L); } /* ctx->context & (NGX_HTTP_LUA_CONTEXT_BODY_FILTER) */ - return ngx_http_lua_body_filter_param_get(L, r); + return ngx_http_lua_body_filter_param_get(L); } @@ -3237,8 +3156,7 @@ ngx_http_lua_finalize_threads(ngx_http_request_t *r, ngx_http_lua_probe_thread_delete(r, coctx->co, ctx); - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - coroutines_key)); + lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); lua_rawget(L, LUA_REGISTRYINDEX); inited = 1; @@ -3276,8 +3194,7 @@ ngx_http_lua_finalize_threads(ngx_http_request_t *r, ngx_http_lua_probe_thread_delete(r, coctx->co, ctx); if (!inited) { - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - coroutines_key)); + lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); lua_rawget(L, LUA_REGISTRYINDEX); inited = 1; } @@ -3306,8 +3223,7 @@ ngx_http_lua_finalize_threads(ngx_http_request_t *r, ngx_http_lua_probe_thread_delete(r, coctx->co, ctx); if (!inited) { - lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( - coroutines_key)); + lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); lua_rawget(L, LUA_REGISTRYINDEX); inited = 1; } @@ -3820,7 +3736,6 @@ ngx_http_lua_init_vm(lua_State *parent_vm, ngx_cycle_t *cycle, ngx_pool_t *pool, ngx_http_lua_main_conf_t *lmcf, ngx_log_t *log, ngx_pool_cleanup_t **pcln) { - int rc; lua_State *L; ngx_uint_t i; ngx_pool_cleanup_t *cln; @@ -3863,11 +3778,6 @@ ngx_http_lua_init_vm(lua_State *parent_vm, ngx_cycle_t *cycle, *pcln = cln; } -#ifdef OPENRESTY_LUAJIT - /* load FFI library first since cdata needs it */ - luaopen_ffi(L); -#endif - if (lmcf->preload_hooks) { /* register the 3rd-party module's preload hooks */ @@ -3888,21 +3798,6 @@ ngx_http_lua_init_vm(lua_State *parent_vm, ngx_cycle_t *cycle, lua_pop(L, 2); } - if (lmcf->load_resty_core) { - lua_getglobal(L, "require"); - lua_pushstring(L, "resty.core"); - - rc = lua_pcall(L, 1, 1, 0); - if (rc != 0) { - ngx_log_error(NGX_LOG_ERR, log, 0, - "lua_load_resty_core failed to load the resty.core " - "module from https://github.com/openresty/lua-resty" - "-core; ensure you are using an OpenResty release " - "from https://openresty.org/en/download.html " - "(rc: %i, reason: %s)", rc, lua_tostring(L, -1)); - } - } - return L; } @@ -4146,12 +4041,7 @@ ngx_http_lua_get_raw_phase_context(lua_State *L) ngx_http_request_t *r; ngx_http_lua_ctx_t *ctx; -#ifdef OPENRESTY_LUAJIT - r = lua_getexdata(L); -#else r = lua_touserdata(L, 1); -#endif - if (r == NULL) { return 0; } @@ -4239,32 +4129,4 @@ ngx_http_lua_cleanup_free(ngx_http_request_t *r, ngx_http_cleanup_pt *cleanup) } -#if (NGX_HTTP_LUA_HAVE_SA_RESTART) -void -ngx_http_lua_set_sa_restart(ngx_log_t *log) -{ - int *signo; - int sigs[] = NGX_HTTP_LUA_SA_RESTART_SIGS; - struct sigaction act; - - for (signo = sigs; *signo != 0; signo++) { - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, - "setting SA_RESTART for signal %d", *signo); - - if (sigaction(*signo, NULL, &act) != 0) { - ngx_log_error(NGX_LOG_WARN, log, ngx_errno, "failed to get " - "sigaction for signal %d", *signo); - } - - act.sa_flags |= SA_RESTART; - - if (sigaction(*signo, &act, NULL) != 0) { - ngx_log_error(NGX_LOG_WARN, log, ngx_errno, "failed to set " - "sigaction for signal %d", *signo); - } - } -} -#endif - - /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_util.h b/debian/modules/http-lua/src/ngx_http_lua_util.h index f08f481..7dcc6f7 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_util.h +++ b/debian/modules/http-lua/src/ngx_http_lua_util.h @@ -9,11 +9,6 @@ #define _NGX_HTTP_LUA_UTIL_H_INCLUDED_ -#ifdef DDEBUG -#include "ddebug.h" -#endif - - #include "ngx_http_lua_common.h" #include "ngx_http_lua_api.h" @@ -193,9 +188,7 @@ ngx_int_t ngx_http_lua_open_and_stat_file(u_char *name, ngx_chain_t *ngx_http_lua_chain_get_free_buf(ngx_log_t *log, ngx_pool_t *p, ngx_chain_t **free, size_t len); -#ifndef OPENRESTY_LUAJIT void ngx_http_lua_create_new_globals_table(lua_State *L, int narr, int nrec); -#endif int ngx_http_lua_traceback(lua_State *L); @@ -250,9 +243,6 @@ ngx_http_cleanup_t *ngx_http_lua_cleanup_add(ngx_http_request_t *r, void ngx_http_lua_cleanup_free(ngx_http_request_t *r, ngx_http_cleanup_pt *cleanup); -#if (NGX_HTTP_LUA_HAVE_SA_RESTART) -void ngx_http_lua_set_sa_restart(ngx_log_t *log); -#endif #define ngx_http_lua_check_if_abortable(L, ctx) \ if ((ctx)->no_abort) { \ @@ -292,9 +282,7 @@ ngx_http_lua_create_ctx(ngx_http_request_t *r) if (!llcf->enable_code_cache && r->connection->fd != (ngx_socket_t) -1) { lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); -#ifdef DDEBUG dd("lmcf: %p", lmcf); -#endif L = ngx_http_lua_init_vm(lmcf->lua, lmcf->cycle, r->pool, lmcf, r->connection->log, &cln); @@ -335,11 +323,7 @@ ngx_http_lua_get_lua_vm(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx) } lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); - -#ifdef DDEBUG dd("lmcf->lua: %p", lmcf->lua); -#endif - return lmcf->lua; } @@ -350,9 +334,6 @@ ngx_http_lua_get_lua_vm(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx) static ngx_inline ngx_http_request_t * ngx_http_lua_get_req(lua_State *L) { -#ifdef OPENRESTY_LUAJIT - return lua_getexdata(L); -#else ngx_http_request_t *r; lua_getglobal(L, ngx_http_lua_req_key); @@ -360,19 +341,14 @@ ngx_http_lua_get_req(lua_State *L) lua_pop(L, 1); return r; -#endif } static ngx_inline void ngx_http_lua_set_req(lua_State *L, ngx_http_request_t *r) { -#ifdef OPENRESTY_LUAJIT - lua_setexdata(L, (void *) r); -#else lua_pushlightuserdata(L, r); lua_setglobal(L, ngx_http_lua_req_key); -#endif } @@ -411,12 +387,10 @@ ngx_http_lua_hash_str(u_char *src, size_t n) static ngx_inline ngx_int_t -ngx_http_lua_set_content_type(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx) +ngx_http_lua_set_content_type(ngx_http_request_t *r) { ngx_http_lua_loc_conf_t *llcf; - ctx->mime_set = 1; - llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); if (llcf->use_default_type && r->headers_out.status != NGX_HTTP_NOT_MODIFIED) diff --git a/debian/modules/http-lua/src/ngx_http_lua_worker.c b/debian/modules/http-lua/src/ngx_http_lua_worker.c index 33cfa11..461509b 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_worker.c +++ b/debian/modules/http-lua/src/ngx_http_lua_worker.c @@ -153,8 +153,6 @@ ngx_http_lua_ffi_master_pid(void) int ngx_http_lua_ffi_get_process_type(void) { - ngx_core_conf_t *ccf; - #if defined(HAVE_PRIVILEGED_PROCESS_PATCH) && !NGX_WIN32 if (ngx_process == NGX_PROCESS_HELPER) { if (ngx_is_privileged_agent) { @@ -163,15 +161,6 @@ ngx_http_lua_ffi_get_process_type(void) } #endif - if (ngx_process == NGX_PROCESS_SINGLE) { - ccf = (ngx_core_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx, - ngx_core_module); - - if (ccf->master) { - return NGX_PROCESS_MASTER; - } - } - return ngx_process; } diff --git a/debian/modules/http-lua/t/.gitignore b/debian/modules/http-lua/t/.gitignore deleted file mode 100644 index 3170741..0000000 --- a/debian/modules/http-lua/t/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -servroot - diff --git a/debian/modules/http-lua/t/000--init.t b/debian/modules/http-lua/t/000--init.t index 5865755..dbe2c33 100644 --- a/debian/modules/http-lua/t/000--init.t +++ b/debian/modules/http-lua/t/000--init.t @@ -10,6 +10,11 @@ $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; $ENV{TEST_NGINX_MYSQL_PORT} ||= 3306; our $http_config = <<'_EOC_'; + upstream database { + drizzle_server 127.0.0.1:$TEST_NGINX_MYSQL_PORT protocol=mysql + dbname=ngx_test user=ngx_test password=ngx_test; + } + lua_package_path "../lua-resty-mysql/lib/?.lua;;"; _EOC_ diff --git a/debian/modules/http-lua/t/001-set.t b/debian/modules/http-lua/t/001-set.t index 9e8ee7b..ba8f22c 100644 --- a/debian/modules/http-lua/t/001-set.t +++ b/debian/modules/http-lua/t/001-set.t @@ -4,7 +4,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * (blocks() * 3 + 5); +plan tests => repeat_each() * (blocks() * 3 + 4); #log_level("warn"); no_long_string(); @@ -46,7 +46,7 @@ helloworld === TEST 3: internal only --- config location /lua { - set_by_lua $res "local function fib(n) if n > 2 then return fib(n-1)+fib(n-2) else return 1 end end return fib(10)"; + set_by_lua $res "function fib(n) if n > 2 then return fib(n-1)+fib(n-2) else return 1 end end return fib(10)"; echo $res; } --- request @@ -76,7 +76,7 @@ GET /lua?a=1&b=2 === TEST 5: fib by arg --- config location /fib { - set_by_lua $res "local function fib(n) if n > 2 then return fib(n-1)+fib(n-2) else return 1 end end return fib(tonumber(ngx.arg[1]))" $arg_n; + set_by_lua $res "function fib(n) if n > 2 then return fib(n-1)+fib(n-2) else return 1 end end return fib(tonumber(ngx.arg[1]))" $arg_n; echo $res; } --- request @@ -592,30 +592,25 @@ failed to run set_by_lua*: unknown reason -=== TEST 37: globals are shared in all requests. +=== TEST 37: globals get cleared for every single request --- config location /lua { - set_by_lua_block $res { + set_by_lua $res ' if not foo then foo = 1 else - ngx.log(ngx.INFO, "old foo: ", foo) foo = foo + 1 end return foo - } + '; echo $res; } --- request GET /lua ---- response_body_like chomp -\A[12] -\z +--- response_body +1 --- no_error_log [error] ---- grep_error_log eval: qr/(old foo: \d+|writing a global lua variable \('\w+'\))/ ---- grep_error_log_out eval -["writing a global lua variable \('foo'\)\n", "old foo: 1\n"] @@ -760,8 +755,6 @@ GET /lua?name=jim --- config location /t { set_by_lua $a ' - local bar - local foo function foo() bar() end diff --git a/debian/modules/http-lua/t/002-content.t b/debian/modules/http-lua/t/002-content.t index bb569f5..cc92d6f 100644 --- a/debian/modules/http-lua/t/002-content.t +++ b/debian/modules/http-lua/t/002-content.t @@ -86,7 +86,7 @@ qr/content_by_lua\(nginx\.conf:\d+\):1: attempt to call field 'echo' \(a nil val location /lua { # NOTE: the newline escape sequence must be double-escaped, as nginx config # parser will unescape first! - content_by_lua 'local v = ngx.var["request_uri"] ngx.print("request_uri: ", v, "\\n")'; + content_by_lua 'v = ngx.var["request_uri"] ngx.print("request_uri: ", v, "\\n")'; } --- request GET /lua?a=1&b=2 @@ -102,7 +102,7 @@ request_uri: /lua?a=1&b=2 } --- user_files >>> test.lua -local v = ngx.var["request_uri"] +v = ngx.var["request_uri"] ngx.print("request_uri: ", v, "\n") --- request GET /lua?a=1&b=2 @@ -154,7 +154,7 @@ result: -0.4090441561579 === TEST 7: read $arg_xxx --- config location = /lua { - content_by_lua 'local who = ngx.var.arg_who + content_by_lua 'who = ngx.var.arg_who ngx.print("Hello, ", who, "!")'; } --- request @@ -171,7 +171,7 @@ Hello, agentzh! } location /lua { - content_by_lua 'local res = ngx.location.capture("/other"); ngx.print("status=", res.status, " "); ngx.print("body=", res.body)'; + content_by_lua 'res = ngx.location.capture("/other"); ngx.print("status=", res.status, " "); ngx.print("body=", res.body)'; } --- request GET /lua @@ -183,7 +183,7 @@ status=200 body=hello, world ei= TEST 9: capture non-existed location --- config location /lua { - content_by_lua 'local res = ngx.location.capture("/other"); ngx.print("status=", res.status)'; + content_by_lua 'res = ngx.location.capture("/other"); ngx.print("status=", res.status)'; } --- request GET /lua @@ -194,7 +194,7 @@ GET /lua === TEST 9: invalid capture location (not as expected...) --- config location /lua { - content_by_lua 'local res = ngx.location.capture("*(#*"); ngx.say("res=", res.status)'; + content_by_lua 'res = ngx.location.capture("*(#*"); ngx.say("res=", res.status)'; } --- request GET /lua @@ -247,7 +247,7 @@ GET /lua ngx.print("num is: ", num, "\\n"); if (num > 0) then - local res = ngx.location.capture("/recur?num="..tostring(num - 1)); + res = ngx.location.capture("/recur?num="..tostring(num - 1)); ngx.print("status=", res.status, " "); ngx.print("body=", res.body, "\\n"); else @@ -271,7 +271,7 @@ end ngx.print("num is: ", num, "\\n"); if (num > 0) then - local res = ngx.location.capture("/recur?num="..tostring(num - 1)); + res = ngx.location.capture("/recur?num="..tostring(num - 1)); ngx.print("status=", res.status, " "); ngx.print("body=", res.body); else @@ -353,7 +353,7 @@ location /sub { } location /parent { set $a 12; - content_by_lua 'local res = ngx.location.capture("/sub"); ngx.print(res.body)'; + content_by_lua 'res = ngx.location.capture("/sub"); ngx.print(res.body)'; } --- request GET /parent @@ -369,7 +369,7 @@ location /sub { location /parent { set $a 12; content_by_lua ' - local res = ngx.location.capture( + res = ngx.location.capture( "/sub", { share_all_vars = true } ); @@ -390,7 +390,7 @@ location /sub { } location /parent { content_by_lua ' - local res = ngx.location.capture("/sub", { share_all_vars = true }); + res = ngx.location.capture("/sub", { share_all_vars = true }); ngx.say(ngx.var.a) '; } @@ -408,7 +408,7 @@ location /sub { } location /parent { content_by_lua ' - local res = ngx.location.capture("/sub", { share_all_vars = false }); + res = ngx.location.capture("/sub", { share_all_vars = false }); ngx.say(ngx.var.a) '; } @@ -427,7 +427,7 @@ GET /parent location /lua { content_by_lua ' - local res = ngx.location.capture("/other"); + res = ngx.location.capture("/other"); ngx.say("type: ", res.header["Content-Type"]); '; } @@ -454,7 +454,7 @@ type: foo/bar location /lua { content_by_lua ' - local res = ngx.location.capture("/other"); + res = ngx.location.capture("/other"); ngx.say("type: ", type(res.header["Set-Cookie"])); ngx.say("len: ", #res.header["Set-Cookie"]); ngx.say("value: ", table.concat(res.header["Set-Cookie"], "|")) @@ -482,7 +482,7 @@ value: a|hello, world|foo location /lua { content_by_lua ' - local res = ngx.location.capture("/other"); + res = ngx.location.capture("/other"); ngx.say("type: ", res.header["Content-Type"]); ngx.say("Bar: ", res.header["Bar"]); '; @@ -507,7 +507,7 @@ Bar: Bah location /lua { content_by_lua ' - local res = ngx.location.capture("/other"); + res = ngx.location.capture("/other"); ngx.say("type: ", res.header["Content-Type"]); ngx.say("Bar: ", res.header["Bar"] or "nil"); '; @@ -524,7 +524,7 @@ Bar: nil --- config location /lua { content_by_lua ' - local data = "hello, world" + data = "hello, world" -- ngx.header["Content-Length"] = #data -- ngx.header.content_length = #data ngx.print(data) @@ -742,7 +742,7 @@ true --- config location /lua { content_by_lua ' - local data = "hello,\\nworld\\n" + data = "hello,\\nworld\\n" ngx.header["Content-Length"] = #data ngx.say("hello,") ngx.flush() @@ -801,7 +801,7 @@ world } --- user_files >>> test.lua -local v = ngx.var["request_uri"] +v = ngx.var["request_uri"] ngx.print("request_uri: ", v, "\n") --- request GET /lua?a=1&b=2 diff --git a/debian/modules/http-lua/t/004-require.t b/debian/modules/http-lua/t/004-require.t index 17e1d57..35e04db 100644 --- a/debian/modules/http-lua/t/004-require.t +++ b/debian/modules/http-lua/t/004-require.t @@ -24,7 +24,7 @@ __DATA__ === TEST 1: sanity --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location /main { echo_location /load; @@ -85,7 +85,7 @@ hello, foo --- request GET /main --- user_files ---- response_body_like: ^[^;]+/servroot(_\d+)?/html/\?\.so$ +--- response_body_like: ^[^;]+/servroot/html/\?.so$ @@ -100,7 +100,7 @@ GET /main } --- request GET /main ---- response_body_like: ^[^;]+/servroot(_\d+)?/html/\?\.lua;(.+\.lua)?;*$ +--- response_body_like: ^[^;]+/servroot/html/\?.lua;.+\.lua;$ @@ -115,7 +115,7 @@ GET /main } --- request GET /main ---- response_body_like: ^[^;]+/servroot(_\d+)?/html/\?\.so;(.+\.so)?;*$ +--- response_body_like: ^[^;]+/servroot/html/\?.so;.+\.so;$ @@ -130,7 +130,7 @@ GET /main } --- request GET /main ---- response_body_like: ^(.+\.lua)?;*?[^;]+/servroot(_\d+)?/html/\?\.lua$ +--- response_body_like: ^.+\.lua;[^;]+/servroot/html/\?.lua$ @@ -145,7 +145,7 @@ GET /main } --- request GET /main ---- response_body_like: ^(.+\.so)?;*?[^;]+/servroot(_\d+)?/html/\?\.so$ +--- response_body_like: ^.+\.so;[^;]+/servroot/html/\?.so$ diff --git a/debian/modules/http-lua/t/005-exit.t b/debian/modules/http-lua/t/005-exit.t index a416a75..a5a28b3 100644 --- a/debian/modules/http-lua/t/005-exit.t +++ b/debian/modules/http-lua/t/005-exit.t @@ -452,7 +452,7 @@ Hi --- config location /lua { content_by_lua ' - local function f () + function f () ngx.say("hello") ngx.exit(200) end diff --git a/debian/modules/http-lua/t/009-log.t b/debian/modules/http-lua/t/009-log.t index cb3895b..68c057f 100644 --- a/debian/modules/http-lua/t/009-log.t +++ b/debian/modules/http-lua/t/009-log.t @@ -414,8 +414,6 @@ GET /log --- config location /log { content_by_lua ' - local foo - local bar function foo() bar() end @@ -433,7 +431,7 @@ GET /log --- response_body done --- error_log eval -qr/\[error\] \S+: \S+ \[lua\] content_by_lua\(nginx\.conf:\d+\):9: bar\(\): hello, log12343.14159/ +qr/\[error\] \S+: \S+ \[lua\] content_by_lua\(nginx\.conf:\d+\):7: bar\(\): hello, log12343.14159/ @@ -441,8 +439,6 @@ qr/\[error\] \S+: \S+ \[lua\] content_by_lua\(nginx\.conf:\d+\):9: bar\(\): hell --- config location /log { content_by_lua ' - local foo - local bar function foo() return bar(5) end @@ -465,7 +461,7 @@ GET /log --- response_body done --- error_log eval -qr/\[error\] \S+: \S+ \[lua\] content_by_lua\(nginx\.conf:\d+\):10:(?: foo\(\):)? hello, log12343.14159/ +qr/\[error\] \S+: \S+ \[lua\] content_by_lua\(nginx\.conf:\d+\):8:(?: foo\(\):)? hello, log12343.14159/ @@ -476,8 +472,6 @@ qr/\[error\] \S+: \S+ \[lua\] content_by_lua\(nginx\.conf:\d+\):10:(?: foo\(\):) } --- user_files >>> test.lua -local foo -local bar function foo() bar() end @@ -494,7 +488,7 @@ GET /log --- response_body done --- error_log eval -qr/\[error\] \S+: \S+ \[lua\] test.lua:8: bar\(\): hello, log12343.14159/ +qr/\[error\] \S+: \S+ \[lua\] test.lua:6: bar\(\): hello, log12343.14159/ diff --git a/debian/modules/http-lua/t/011-md5_bin.t b/debian/modules/http-lua/t/011-md5_bin.t index dc0fd9c..ae7c974 100644 --- a/debian/modules/http-lua/t/011-md5_bin.t +++ b/debian/modules/http-lua/t/011-md5_bin.t @@ -156,7 +156,7 @@ d41d8cd98f00b204e9800998ecf8427e --- config location = /t { content_by_lua ' - local s = ngx.md5_bin(45) + s = ngx.md5_bin(45) s = string.gsub(s, ".", function (c) return string.format("%02x", string.byte(c)) end) diff --git a/debian/modules/http-lua/t/013-base64.t b/debian/modules/http-lua/t/013-base64.t index d1a8d8b..1cc27de 100644 --- a/debian/modules/http-lua/t/013-base64.t +++ b/debian/modules/http-lua/t/013-base64.t @@ -242,4 +242,4 @@ GET /t --- response_body_like: 500 Internal Server Error --- error_code: 500 --- error_log eval -qr/bad argument \#2 to 'encode_base64' \(boolean expected, got number\)|\[error\] .*? bad no_padding: boolean expected, got number/ +qr/bad argument \#2 to 'encode_base64' \(boolean expected, got number\)|\[error\] .*? boolean argument only/ diff --git a/debian/modules/http-lua/t/014-bugs.t b/debian/modules/http-lua/t/014-bugs.t index dad084e..9aadff0 100644 --- a/debian/modules/http-lua/t/014-bugs.t +++ b/debian/modules/http-lua/t/014-bugs.t @@ -43,7 +43,7 @@ __DATA__ === TEST 1: sanity --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location /load { content_by_lua ' @@ -69,7 +69,7 @@ end === TEST 2: sanity --- http_config -lua_package_cpath '/home/agentz/rpm/BUILD/lua-yajl-1.1/build/?.so;/home/lz/luax/?.so;./?.so'; +lua_package_path '/home/agentz/rpm/BUILD/lua-yajl-1.1/build/?.so;/home/lz/luax/?.so;./?.so'; --- config location = '/report/listBidwordPrices4lzExtra.htm' { content_by_lua ' @@ -112,7 +112,7 @@ GET /report/listBidwordPrices4lzExtra.htm?words=123,156,2532 } location = /main { content_by_lua ' - local res = ngx.location.capture("/memc?c=get&k=foo&v=") + res = ngx.location.capture("/memc?c=get&k=foo&v=") ngx.say("1: ", res.body) res = ngx.location.capture("/memc?c=set&k=foo&v=bar"); @@ -204,7 +204,7 @@ https://github.com/chaoslawful/lua-nginx-module/issues/37 content_by_lua ' -- local yajl = require "yajl" ngx.header["Set-Cookie"] = {} - local res = ngx.location.capture("/sub") + res = ngx.location.capture("/sub") for i,j in pairs(res.header) do ngx.header[i] = j @@ -231,7 +231,7 @@ Set-Cookie: TestCookie2=bar.*" } --- user_files >>> foo.lua -local res = {} +res = {} res = {'good 1', 'good 2', 'good 3'} return ngx.redirect("/somedir/" .. ngx.escape_uri(res[math.random(1,#res)])) --- request @@ -579,7 +579,7 @@ $s -=== TEST 26: globals sharing by using _G +=== TEST 26: unexpected globals sharing by using _G --- config location /test { content_by_lua ' @@ -593,12 +593,12 @@ $s } --- pipelined_requests eval ["GET /test", "GET /test", "GET /test"] ---- response_body_like eval -[qr/\A[036]\z/, qr/\A[147]\z/, qr/\A[258]\z/] +--- response_body eval +["0", "0", "0"] -=== TEST 27: globals sharing by using _G (set_by_lua*) +=== TEST 27: unexpected globals sharing by using _G (set_by_lua*) --- config location /test { set_by_lua $a ' @@ -613,12 +613,12 @@ $s } --- pipelined_requests eval ["GET /test", "GET /test", "GET /test"] ---- response_body_like eval -[qr/\A[036]\z/, qr/\A[147]\z/, qr/\A[258]\z/] +--- response_body eval +["0", "0", "0"] -=== TEST 28: globals sharing by using _G (log_by_lua*) +=== TEST 28: unexpected globals sharing by using _G (log_by_lua*) --- http_config lua_shared_dict log_dict 100k; --- config @@ -633,19 +633,19 @@ $s if _G.t then _G.t = _G.t + 1 else - _G.t = 1 + _G.t = 0 end log_dict:set("cnt", t) '; } --- pipelined_requests eval ["GET /test", "GET /test", "GET /test"] ---- response_body_like eval -[qr/\A[036]\z/, qr/\A[147]\z/, qr/\A[258]\z/] +--- response_body eval +["0", "0", "0"] -=== TEST 29: globals sharing by using _G (header_filter_by_lua*) +=== TEST 29: unexpected globals sharing by using _G (header_filter_by_lua*) --- config location /test { header_filter_by_lua ' @@ -663,12 +663,12 @@ $s } --- pipelined_requests eval ["GET /test", "GET /test", "GET /test"] ---- response_body_like eval -[qr/\A[036]\z/, qr/\A[147]\z/, qr/\A[258]\z/] +--- response_body eval +["0", "0", "0"] -=== TEST 30: globals sharing by using _G (body_filter_by_lua*) +=== TEST 30: unexpected globals sharing by using _G (body_filter_by_lua*) --- config location /test { body_filter_by_lua ' @@ -686,9 +686,8 @@ $s } --- request GET /test ---- response_body_like eval -qr/\Aa[036] -\z/ +--- response_body +a0 --- no_error_log [error] @@ -847,7 +846,7 @@ ok === TEST 37: resolving names with a trailing dot --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location /t { resolver $TEST_NGINX_RESOLVER ipv6=off; @@ -865,7 +864,7 @@ GET /t === TEST 38: resolving names with a trailing dot --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;'; + "lua_package_path '$::HtmlDir/?.lua;./?.lua'; server { listen 12354; @@ -892,7 +891,7 @@ args: foo=1&bar=2 === TEST 39: lua_code_cache off + setkeepalive --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config lua_code_cache off; location = /t { diff --git a/debian/modules/http-lua/t/016-resp-header.t b/debian/modules/http-lua/t/016-resp-header.t index e38202b..72c1e05 100644 --- a/debian/modules/http-lua/t/016-resp-header.t +++ b/debian/modules/http-lua/t/016-resp-header.t @@ -8,7 +8,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * (blocks() * 3 + 59); +plan tests => repeat_each() * (blocks() * 3 + 46); #no_diff(); no_long_string(); @@ -630,46 +630,7 @@ Cache-Control: private, no-store -=== TEST 32: set single value to Link header ---- config - location = /t { - content_by_lua_block { - ngx.header.link = "; rel=preload" - ngx.say("Link: ", ngx.var.sent_http_link) - } - } ---- request -GET /t ---- response_headers -Link: ; rel=preload ---- response_body -Link: ; rel=preload - - - -=== TEST 33: set multi values to Link header ---- config - location = /t { - content_by_lua_block { - ngx.header.link = { - "; rel=preload", - "; rel=preload; as=style" - } - - ngx.say("Link: ", ngx.var.sent_http_link) - } - } ---- request -GET /t ---- response_headers -Link: ; rel=preload, ; rel=preload; as=style ---- response_body_like chop -^Link: ; rel=preload[;,] ; rel=preload; as=style$ ---- skip_nginx: 3: < 1.13.9 - - - -=== TEST 34: set multi values to cache-control and override it with a single value +=== TEST 32: set multi values to cache-control and override it with a single value --- config location /lua { content_by_lua ' @@ -689,30 +650,7 @@ Cache-Control: no-cache -=== TEST 35: set multi values to Link header and override it with a single value ---- config - location /lua { - content_by_lua_block { - ngx.header.link = { - "; rel=preload", - "; rel=preload; as=style" - } - ngx.header.link = "; rel=preload" - ngx.say("Link: ", ngx.var.sent_http_link) - ngx.say("Link: ", ngx.header.link) - } - } ---- request - GET /lua ---- response_headers -Link: ; rel=preload ---- response_body -Link: ; rel=preload -Link: ; rel=preload - - - -=== TEST 36: set multi values to cache-control and override it with multiple values +=== TEST 33: set multi values to cache-control and override it with multiple values --- config location /lua { content_by_lua ' @@ -734,37 +672,7 @@ Cache-Control: no-cache[;,] blah[;,] foo$ -=== TEST 37: set multi values to Link header and override it with multiple values ---- config - location /lua { - content_by_lua_block { - ngx.header.link = { - "; rel=preload", - "; rel=preload; as=style" - } - ngx.header.link = { - "; rel=preload", - "; rel=preload", - "; rel=preload; as=style" - } - ngx.say("Link: ", ngx.var.sent_http_link) - ngx.say("Link: ", table.concat(ngx.header.link, ", ")) - } - } ---- request - GET /lua ---- response_headers -Link: ; rel=preload, ; rel=preload, ; rel=preload; as=style ---- response_body_like chop -^Link: ; rel=preload[;,] ; rel=preload[;,] ; rel=preload; as=style -Link: ; rel=preload[;,] ; rel=preload[;,] ; rel=preload; as=style$ ---- no_error_log -[error] ---- skip_nginx: 4: < 1.13.9 - - - -=== TEST 38: set the www-authenticate response header +=== TEST 34: set the www-authenticate response header --- config location /lua { content_by_lua ' @@ -781,7 +689,7 @@ WWW-Authenticate: blah -=== TEST 39: set and clear the www-authenticate response header +=== TEST 35: set and clear the www-authenticate response header --- config location /lua { content_by_lua ' @@ -799,7 +707,7 @@ Foo: nil -=== TEST 40: set multi values to cache-control and override it with multiple values (to reproduce a bug) +=== TEST 36: set multi values to cache-control and override it with multiple values (to reproduce a bug) --- config location /lua { content_by_lua ' @@ -819,7 +727,7 @@ Cache-Control: blah -=== TEST 41: set last-modified and return 304 +=== TEST 37: set last-modified and return 304 --- config location /lua { content_by_lua ' @@ -837,7 +745,7 @@ Last-Modified: Thu, 18 Nov 2010 11:27:35 GMT -=== TEST 42: set last-modified and return 200 +=== TEST 38: set last-modified and return 200 --- config location /lua { content_by_lua ' @@ -856,7 +764,7 @@ Thu, 18 Nov 2010 11:27:35 GMT -=== TEST 43: set response content-encoding header should bypass ngx_http_gzip_filter_module +=== TEST 39: set response content-encoding header should bypass ngx_http_gzip_filter_module --- config default_type text/plain; gzip on; @@ -873,16 +781,13 @@ GET /read --- more_headers Accept-Encoding: gzip --- response_headers -Content-Encoding: gzip ---- no_error_log -[error] -http gzip filter +Content-Type: text/plain --- response_body Hello, world, my dear friend! -=== TEST 44: no transform underscores (write) +=== TEST 40: no transform underscores (write) --- config lua_transform_underscores_in_response_headers off; location = /t { @@ -902,7 +807,7 @@ nil -=== TEST 45: with transform underscores (write) +=== TEST 41: with transform underscores (write) --- config lua_transform_underscores_in_response_headers on; location = /t { @@ -922,7 +827,7 @@ Hello -=== TEST 46: github issue #199: underscores in lua variables +=== TEST 42: github issue #199: underscores in lua variables --- config location /read { content_by_lua ' @@ -955,7 +860,7 @@ something: hello -=== TEST 47: set multiple response header +=== TEST 43: set multiple response header --- config location /read { content_by_lua ' @@ -975,7 +880,7 @@ text/my-plain-50 -=== TEST 48: set multiple response header and then reset and then clear +=== TEST 44: set multiple response header and then reset and then clear --- config location /read { content_by_lua ' @@ -1004,7 +909,7 @@ ok -=== TEST 49: set response content-type header for multiple times +=== TEST 45: set response content-type header for multiple times --- config location /read { content_by_lua ' @@ -1022,7 +927,7 @@ Hi -=== TEST 50: set Last-Modified response header for multiple times +=== TEST 46: set Last-Modified response header for multiple times --- config location /read { content_by_lua ' @@ -1040,7 +945,7 @@ ok -=== TEST 51: set Last-Modified response header and then clear +=== TEST 47: set Last-Modified response header and then clear --- config location /read { content_by_lua ' @@ -1058,7 +963,7 @@ ok -=== TEST 52: github #20: segfault caused by the nasty optimization in the nginx core (write) +=== TEST 48: github #20: segfault caused by the nasty optimization in the nginx core (write) --- config location = /t/ { header_filter_by_lua ' @@ -1080,7 +985,7 @@ Location: http://localhost:$ServerPort/t/ -=== TEST 53: github #20: segfault caused by the nasty optimization in the nginx core (read) +=== TEST 49: github #20: segfault caused by the nasty optimization in the nginx core (read) --- config location = /t/ { header_filter_by_lua ' @@ -1102,7 +1007,7 @@ Location: http://localhost:$ServerPort/t/ -=== TEST 54: github #20: segfault caused by the nasty optimization in the nginx core (read Location) +=== TEST 50: github #20: segfault caused by the nasty optimization in the nginx core (read Location) --- config location = /t/ { header_filter_by_lua ' @@ -1125,7 +1030,7 @@ Foo: /t/ -=== TEST 55: github #20: segfault caused by the nasty optimization in the nginx core (set Foo and read Location) +=== TEST 51: github #20: segfault caused by the nasty optimization in the nginx core (set Foo and read Location) --- config location = /t/ { header_filter_by_lua ' @@ -1149,7 +1054,7 @@ Foo: /t/ -=== TEST 56: case sensitive cache-control header +=== TEST 52: case sensitive cache-control header --- config location /lua { content_by_lua ' @@ -1166,24 +1071,7 @@ Cache-Control: private -=== TEST 57: case sensitive Link header ---- config - location /lua { - content_by_lua_block { - ngx.header["link"] = "; rel=preload" - ngx.say("Link: ", ngx.var.sent_http_link) - } - } ---- request - GET /lua ---- raw_response_headers_like chop -link: ; rel=preload ---- response_body -Link: ; rel=preload - - - -=== TEST 58: clear Cache-Control when there was no Cache-Control +=== TEST 53: clear Cache-Control when there was no Cache-Control --- config location /lua { content_by_lua ' @@ -1200,24 +1088,7 @@ Cache-Control: nil -=== TEST 59: clear Link header when there was no Link ---- config - location /lua { - content_by_lua_block { - ngx.header["Link"] = nil - ngx.say("Link: ", ngx.var.sent_http_link) - } - } ---- request - GET /lua ---- raw_response_headers_unlike eval -qr/Link/i ---- response_body -Link: nil - - - -=== TEST 60: set response content-type header +=== TEST 54: set response content-type header --- config location /read { content_by_lua ' @@ -1236,7 +1107,7 @@ s = content_type -=== TEST 61: set a number header name +=== TEST 55: set a number header name --- config location /lua { content_by_lua ' @@ -1255,7 +1126,7 @@ s = content_type -=== TEST 62: set a number header name (in a table value) +=== TEST 56: set a number header name (in a table value) --- config location /lua { content_by_lua ' @@ -1274,7 +1145,7 @@ foo: 32 -=== TEST 63: random access resp headers +=== TEST 57: random access resp headers --- config location /resp-header { content_by_lua ' @@ -1314,7 +1185,7 @@ bar: baz -=== TEST 64: iterating through raw resp headers +=== TEST 58: iterating through raw resp headers --- config location /resp-header { content_by_lua ' @@ -1350,7 +1221,7 @@ bar: nil -=== TEST 65: removed response headers +=== TEST 59: removed response headers --- config location /resp-header { content_by_lua ' @@ -1383,7 +1254,7 @@ bar: baz -=== TEST 66: built-in Content-Type header +=== TEST 60: built-in Content-Type header --- config location = /t { content_by_lua ' @@ -1416,7 +1287,7 @@ my content_type: text/plain -=== TEST 67: built-in Content-Length header +=== TEST 61: built-in Content-Length header --- config location = /t { content_by_lua ' @@ -1449,7 +1320,7 @@ my content_length: 3 -=== TEST 68: built-in Connection header +=== TEST 62: built-in Connection header --- config location = /t { content_by_lua ' @@ -1480,7 +1351,7 @@ my connection: close -=== TEST 69: built-in Transfer-Encoding header (chunked) +=== TEST 63: built-in Transfer-Encoding header (chunked) --- config location = /t { content_by_lua ' @@ -1512,7 +1383,7 @@ my transfer-encoding: chunked -=== TEST 70: built-in Transfer-Encoding header (none) +=== TEST 64: built-in Transfer-Encoding header (none) --- config location = /t { content_by_lua ' @@ -1545,7 +1416,7 @@ my transfer_encoding: nil -=== TEST 71: set Location (no host) +=== TEST 65: set Location (no host) --- config location = /t { content_by_lua ' @@ -1564,7 +1435,7 @@ Location: /foo/bar -=== TEST 72: set Location (with host) +=== TEST 66: set Location (with host) --- config location = /t { content_by_lua ' @@ -1583,7 +1454,7 @@ Location: http://test.com/foo/bar -=== TEST 73: ngx.header["Content-Type"] with ngx_gzip +=== TEST 67: ngx.header["Content-Type"] with ngx_gzip --- config gzip on; gzip_min_length 1; @@ -1607,7 +1478,7 @@ Content-Type: text/html; charset=utf-8 -=== TEST 74: ngx.header["Content-Type"] with "; blah" +=== TEST 68: ngx.header["Content-Type"] with "; blah" --- config location = /test2 { content_by_lua ' @@ -1627,11 +1498,84 @@ test -=== TEST 75: exceeding max header limit (default 100) +=== TEST 69: return the matched content-type instead of default_type +--- http_config +types { + image/png png; +} +--- config +location /set/ { + default_type text/html; + content_by_lua_block { + ngx.say(ngx.header["content-type"]) + } +} +--- request +GET /set/hello.png +--- response_headers +Content-Type: image/png +--- response_body +image/png +--- no_error_log +[error] + + + +=== TEST 70: always return the matched content-type +--- config + location /set/ { + default_type "image/png"; + content_by_lua_block { + ngx.say(ngx.header["content-type"]) + ngx.say(ngx.header["content-type"]) + } + } +--- request +GET /set/hello.png +--- response_headers +Content-Type: image/png +--- response_body +image/png +image/png +--- no_error_log +[error] + + + +=== TEST 71: return the matched content-type after ngx.resp.get_headers() +--- http_config +types { + image/png png; +} +--- config + location /set/ { + default_type text/html; + content_by_lua_block { + local h, err = ngx.resp.get_headers() + if err then + ngx.log(ngx.ERR, "err: ", err) + return ngx.exit(500) + end + + ngx.say(h["content-type"]) + } + } +--- request +GET /set/hello.png +--- response_headers +Content-Type: image/png +--- response_body +image/png +--- no_error_log +[error] + + + +=== TEST 72: exceeding max header limit (default 100) --- config location /resp-header { content_by_lua_block { - for i = 1, 100 do + for i = 1, 99 do ngx.header["Foo" .. i] = "Foo" end @@ -1661,11 +1605,11 @@ lua exceeding response header limit 101 > 100 -=== TEST 76: NOT exceeding max header limit (default 100) +=== TEST 73: NOT exceeding max header limit (default 100) --- config location /resp-header { content_by_lua_block { - for i = 1, 99 do + for i = 1, 98 do ngx.header["Foo" .. i] = "Foo" end @@ -1693,11 +1637,11 @@ lua exceeding response header limit -=== TEST 77: exceeding max header limit (custom limit, 3) +=== TEST 74: exceeding max header limit (custom limit, 3) --- config location /resp-header { content_by_lua_block { - for i = 1, 3 do + for i = 1, 2 do ngx.header["Foo" .. i] = "Foo" end @@ -1727,11 +1671,11 @@ lua exceeding response header limit 4 > 3 -=== TEST 78: NOT exceeding max header limit (custom limit, 3) +=== TEST 75: NOT exceeding max header limit (custom limit, 3) --- config location /resp-header { content_by_lua_block { - for i = 1, 2 do + for i = 1, 1 do ngx.header["Foo" .. i] = "Foo" end @@ -1755,211 +1699,3 @@ found 3 resp headers --- no_error_log [error] lua exceeding response header limit - - - -=== TEST 79: return nil if Content-Type is not set yet ---- config - location /t { - default_type text/html; - content_by_lua_block { - ngx.log(ngx.WARN, "Content-Type: ", ngx.header["content-type"]) - ngx.say("Content-Type: ", ngx.header["content-type"]) - } - } ---- request -GET /t ---- response_headers -Content-Type: text/html ---- response_body -Content-Type: nil ---- no_error_log -[error] ---- error_log -Content-Type: nil - - - -=== TEST 80: don't generate Content-Type when setting other response header ---- config - location = /backend { - content_by_lua_block { - ngx.say("foo") - } - header_filter_by_lua_block { - ngx.header.content_type = nil - } - } - - location = /t { - default_type text/html; - rewrite_by_lua_block { - ngx.header.blah = "foo" - } - proxy_pass http://127.0.0.1:$TEST_NGINX_SERVER_PORT/backend; - } ---- request -GET /t ---- response_body -foo ---- response_headers -blah: foo -!Content-Type ---- no_error_log -[error] - - - -=== TEST 81: don't generate Content-Type when getting other response header ---- config - location = /backend { - content_by_lua_block { - ngx.say("foo") - } - header_filter_by_lua_block { - ngx.header.content_type = nil - } - } - - location = /t { - default_type text/html; - rewrite_by_lua_block { - local h = ngx.header.content_length - } - proxy_pass http://127.0.0.1:$TEST_NGINX_SERVER_PORT/backend; - } ---- request -GET /t ---- response_body -foo ---- response_headers -!Content-Type ---- no_error_log -[error] - - - -=== TEST 82: don't generate Content-Type when getting it ---- config - location = /backend { - content_by_lua_block { - ngx.say("foo") - } - header_filter_by_lua_block { - ngx.header.content_type = nil - } - } - - location /t { - proxy_pass http://127.0.0.1:$TEST_NGINX_SERVER_PORT/backend; - header_filter_by_lua_block { - ngx.log(ngx.WARN, "Content-Type: ", ngx.header["content-type"]) - } - } ---- request -GET /t ---- response_body -foo ---- response_headers -!Content-Type ---- no_error_log -[error] ---- error_log -Content-Type: nil - - - -=== TEST 83: generate default Content-Type when setting other response header ---- config - location = /t { - default_type text/html; - content_by_lua_block { - ngx.header.blah = "foo" - ngx.say("foo") - } - } ---- request -GET /t ---- response_body -foo ---- response_headers -blah: foo -Content-Type: text/html ---- no_error_log -[error] - - - -=== TEST 84: don't generate Content-Type when calling ngx.resp.get_headers() ---- config - location = /backend { - content_by_lua_block { - ngx.say("foo") - } - header_filter_by_lua_block { - ngx.header.content_type = nil - } - } - - location /t { - proxy_pass http://127.0.0.1:$TEST_NGINX_SERVER_PORT/backend; - header_filter_by_lua_block { - local h, err = ngx.resp.get_headers() - if err then - ngx.log(ngx.ERR, "err: ", err) - return - end - - ngx.log(ngx.WARN, "Content-Type: ", h["content-type"]) - } - } ---- request -GET /t ---- response_body -foo ---- response_headers -!Content-Type ---- no_error_log -[error] ---- error_log -Content-Type: nil - - - -=== TEST 85: don't generate default Content-Type when Content-Type is cleared ---- config - location = /t { - default_type text/html; - content_by_lua_block { - ngx.header["Content-Type"] = nil - ngx.say("foo") - } - } ---- request -GET /t ---- response_body -foo ---- response_headers -!Content-Type ---- no_error_log -[error] - - - -=== TEST 86: don't generate default Content-Type when Content-Type is set ---- config - location = /t { - default_type text/html; - content_by_lua_block { - ngx.header["Content-Type"] = "application/json" - ngx.say("foo") - } - } ---- request -GET /t ---- response_body -foo ---- response_headers -Content-Type: application/json ---- no_error_log -[error] diff --git a/debian/modules/http-lua/t/017-exec.t b/debian/modules/http-lua/t/017-exec.t index a73e93e..544b8bb 100644 --- a/debian/modules/http-lua/t/017-exec.t +++ b/debian/modules/http-lua/t/017-exec.t @@ -382,7 +382,7 @@ hello --- config location /lua { content_by_lua ' - local function f () + function f () ngx.exec("/hi") end @@ -524,7 +524,7 @@ hello --- config location /main { rewrite_by_lua ' - local res = ngx.location.capture("/test_loc"); + res = ngx.location.capture("/test_loc"); ngx.print("hello, ", res.body) '; content_by_lua return; diff --git a/debian/modules/http-lua/t/020-subrequest.t b/debian/modules/http-lua/t/020-subrequest.t index 5a386db..658a1d2 100644 --- a/debian/modules/http-lua/t/020-subrequest.t +++ b/debian/modules/http-lua/t/020-subrequest.t @@ -32,7 +32,7 @@ __DATA__ location /lua { content_by_lua ' - local res = ngx.location.capture("/other", + res = ngx.location.capture("/other", { method = ngx.HTTP_DELETE }); ngx.print(res.body) @@ -62,7 +62,7 @@ lua http subrequest "/other?" location /lua { content_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { method = ngx.HTTP_DELETE }); ngx.print(res.body) @@ -90,7 +90,7 @@ DELETE location /t { content_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { method = ngx.HTTP_POST }); ngx.print(res.body) @@ -114,7 +114,7 @@ POST location /lua { content_by_lua ' - local res = ngx.location.capture("/other", + res = ngx.location.capture("/other", { method = ngx.HTTP_HEAD }); ngx.print(res.body) @@ -141,7 +141,7 @@ GET /lua location /lua { content_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { method = ngx.HTTP_GET }); ngx.print(res.body) @@ -169,7 +169,7 @@ GET location /lua { content_by_lua ' - local res = ngx.location.capture("/foo") + res = ngx.location.capture("/foo") ngx.print(res.body) '; @@ -196,7 +196,7 @@ GET location /lua { content_by_lua ' - local res = ngx.location.capture("/foo", {}) + res = ngx.location.capture("/foo", {}) ngx.print(res.body) '; @@ -226,7 +226,7 @@ GET location /lua { content_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { method = ngx.HTTP_PUT, body = "hello" }); ngx.print(res.body) @@ -255,7 +255,7 @@ hello location /lua { content_by_lua ' - local res = ngx.location.capture("/other", + res = ngx.location.capture("/other", { method = ngx.HTTP_PUT, body = "hello" }); ngx.print(res.body) @@ -291,7 +291,7 @@ hello location /lua { content_by_lua ' - local res = ngx.location.capture("/other", + res = ngx.location.capture("/other", { method = ngx.HTTP_PUT, body = "hello" }); ngx.print(res.body) @@ -329,7 +329,7 @@ GET location /lua { content_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { method = ngx.HTTP_POST, body = "hello" }); ngx.print(res.body) @@ -362,7 +362,7 @@ hello content_by_lua ' ngx.location.capture("/flush"); - local res = ngx.location.capture("/memc"); + res = ngx.location.capture("/memc"); ngx.say("GET: " .. res.status); res = ngx.location.capture("/memc", @@ -404,7 +404,7 @@ cached: hello ngx.location.capture("/flush", { share_all_vars = true }); - local res = ngx.location.capture("/memc", + res = ngx.location.capture("/memc", { share_all_vars = true }); ngx.say("GET: " .. res.status); @@ -435,7 +435,7 @@ cached: hello location /lua { content_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { args = {} }) ngx.print(res.body) '; @@ -456,7 +456,7 @@ GET /lua location /lua { content_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { args = { ["fo="] = "=>" } }) ngx.print(res.body) '; @@ -478,7 +478,7 @@ fo%3D=%3D%3E location /lua { content_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { args = { ["fo="] = "=>", ["="] = ":" } }) ngx.print(res.body) @@ -503,7 +503,7 @@ GET /lua location /lua { content_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { args = { foo = 3, bar = "hello" } }) ngx.print(res.body) @@ -526,7 +526,7 @@ GET /lua location /lua { content_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { args = { [57] = "hi" } }) ngx.print(res.body) '; @@ -548,7 +548,7 @@ attempt to use a non-string key in the "args" option table location /lua { content_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { args = { "hi" } }) ngx.print(res.body) '; @@ -570,7 +570,7 @@ attempt to use a non-string key in the "args" option table location /lua { content_by_lua ' - local res = ngx.location.capture("/foo?a=3", + res = ngx.location.capture("/foo?a=3", { args = { b = 4 } }) ngx.print(res.body) '; @@ -592,7 +592,7 @@ a=3&b=4 location /lua { content_by_lua ' - local res = ngx.location.capture("/foo?a=3", + res = ngx.location.capture("/foo?a=3", { args = "b=4" }) ngx.print(res.body) '; @@ -685,7 +685,7 @@ https://github.com/chaoslawful/lua-nginx-module/issues/38 location /lua { content_by_lua ' - local res = ngx.location.capture("/other", + res = ngx.location.capture("/other", { method = ngx.HTTP_GET }); ngx.say("header foo: [", res.body, "]") '; @@ -711,7 +711,7 @@ https://github.com/chaoslawful/lua-nginx-module/issues/38 location /lua { content_by_lua ' - local res = ngx.location.capture("/other", + res = ngx.location.capture("/other", { body = "abc" }); ngx.say("header foo: [", res.body, "]") '; @@ -746,8 +746,8 @@ header foo: [bar] } location /main { content_by_lua ' - local res1, res2 = ngx.location.capture_multi({{"/a"}, {"/b"}}) - local res3 = ngx.location.capture("/c") + res1, res2 = ngx.location.capture_multi({{"/a"}, {"/b"}}) + res3 = ngx.location.capture("/c") ngx.print(res1.body, res2.body, res3.body) '; } @@ -780,7 +780,7 @@ lua reuse free buf memory location /lua { content_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { method = ngx.HTTP_POST, body = "hello" }); ngx.print(res.body) @@ -801,7 +801,7 @@ hello --- config location /lua { content_by_lua ' - local res = ngx.location.capture("/foo.html") + res = ngx.location.capture("/foo.html") ngx.say(res.status) ngx.say(res.header["Last-Modified"]) @@ -832,7 +832,7 @@ hello, static file$ location /lua { content_by_lua ' local ctx = {} - local res = ngx.location.capture("/sub", { ctx = ctx }) + res = ngx.location.capture("/sub", { ctx = ctx }) ngx.say(ctx.foo); ngx.say(ngx.ctx.foo); @@ -857,7 +857,7 @@ nil } location /lua { content_by_lua ' - local res = ngx.location.capture("/sub", { ctx = ngx.ctx }) + res = ngx.location.capture("/sub", { ctx = ngx.ctx }) ngx.say(ngx.ctx.foo); '; } @@ -885,7 +885,7 @@ bar location /t { content_by_lua ' - local res = ngx.location.capture("/memc", + res = ngx.location.capture("/memc", { method = ngx.HTTP_PUT, body = "hello 1234" }); -- ngx.say("PUT: " .. res.status); @@ -922,7 +922,7 @@ lua reuse free buf chain, but reallocate memory because location /lua { content_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { method = ngx.HTTP_GET }); ngx.print(res.body) @@ -959,7 +959,7 @@ nil content_by_lua ' ngx.req.read_body() - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { method = ngx.HTTP_GET }); ngx.print(res.body) @@ -996,7 +996,7 @@ nil content_by_lua ' ngx.req.read_body() - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { method = ngx.HTTP_POST }); ngx.print(res.body) @@ -1033,7 +1033,7 @@ hello, world content_by_lua ' ngx.req.read_body() - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { method = ngx.HTTP_PUT }); ngx.print(res.body) @@ -1074,7 +1074,7 @@ lua subrequests cycle while processing "/t" location /lua { content_by_lua ' - local res = ngx.location.capture("/other", + res = ngx.location.capture("/other", { method = ngx.HTTP_OPTIONS }); ngx.print(res.body) @@ -1099,7 +1099,7 @@ OPTIONS location /lua { content_by_lua ' - local res = ngx.location.capture("/other", + res = ngx.location.capture("/other", { method = ngx.HTTP_OPTIONS, body = "hello world" }); ngx.print(res.body) @@ -1151,7 +1151,7 @@ r%5B%5D=http%3A%2F%2Fajax.googleapis.com%3A80%2Fajax%2Flibs%2Fjquery%2F1.7.2%2Fj location /main { content_by_lua ' - local res = ngx.location.capture("/sub") + res = ngx.location.capture("/sub") ngx.say("status: ", res.status) ngx.say("body: ", res.body) '; @@ -1172,7 +1172,7 @@ body: location /main { content_by_lua ' - local res = ngx.location.capture("/sub") + res = ngx.location.capture("/sub") ngx.say("status: ", res.status) ngx.say("body: ", res.body) '; @@ -1196,7 +1196,7 @@ body: location /main { content_by_lua ' - local res = ngx.location.capture("/sub") + res = ngx.location.capture("/sub") ngx.say("status: ", res.status) ngx.say("body: ", res.body) '; @@ -1242,7 +1242,7 @@ F(ngx_http_finalize_request) { location /main { content_by_lua ' - local res = ngx.location.capture("/memc") + res = ngx.location.capture("/memc") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -1312,7 +1312,7 @@ upstream prematurely closed connection location /main { content_by_lua ' - local res = ngx.location.capture("/memc") + res = ngx.location.capture("/memc") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -1385,7 +1385,7 @@ upstream timed out location /main { content_by_lua ' - local res = ngx.location.capture("/proxy") + res = ngx.location.capture("/proxy") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -1445,7 +1445,7 @@ upstream prematurely closed connection location /main { content_by_lua ' - local res = ngx.location.capture("/proxy") + res = ngx.location.capture("/proxy") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -1507,7 +1507,7 @@ upstream timed out location /main { content_by_lua ' - local res = ngx.location.capture("/proxy") + res = ngx.location.capture("/proxy") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -1567,7 +1567,7 @@ truncated: false location /main { content_by_lua ' - local res = ngx.location.capture("/proxy") + res = ngx.location.capture("/proxy") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -1630,7 +1630,7 @@ upstream timed out location /main { content_by_lua ' - local res = ngx.location.capture("/proxy") + res = ngx.location.capture("/proxy") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -1690,7 +1690,7 @@ truncated: false location /main { content_by_lua ' - local res = ngx.location.capture("/proxy") + res = ngx.location.capture("/proxy") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -1756,7 +1756,7 @@ upstream timed out ngx.req.read_body() for i = 1, 2 do - local res = ngx.location.capture("/other", + res = ngx.location.capture("/other", { method = ngx.HTTP_POST }); ngx.say(res.body) @@ -1796,7 +1796,7 @@ hello world ngx.req.read_body() for i = 1, 2 do - local res = ngx.location.capture("/other", + res = ngx.location.capture("/other", { method = ngx.HTTP_POST }); ngx.say(res.body) @@ -1836,7 +1836,7 @@ hello world ngx.req.read_body() for i = 1, 2 do - local res = ngx.location.capture("/other", + res = ngx.location.capture("/other", { method = ngx.HTTP_POST }); ngx.say(res.body) @@ -1916,7 +1916,7 @@ a client request body is buffered to a temporary file location /main { content_by_lua ' - local res = ngx.location.capture("/proxy") + res = ngx.location.capture("/proxy") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -1979,7 +1979,7 @@ upstream prematurely closed connection location /main { content_by_lua ' - local res = ngx.location.capture("/proxy") + res = ngx.location.capture("/proxy") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -2040,7 +2040,7 @@ upstream prematurely closed connection location /main { content_by_lua ' - local res = ngx.location.capture("/proxy") + res = ngx.location.capture("/proxy") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -2102,7 +2102,7 @@ upstream timed out location /main { content_by_lua ' - local res = ngx.location.capture("/proxy") + res = ngx.location.capture("/proxy") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -2160,7 +2160,7 @@ truncated: false location /main { content_by_lua ' - local res = ngx.location.capture("/proxy") + res = ngx.location.capture("/proxy") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -2219,7 +2219,7 @@ truncated: false location /main { content_by_lua ' - local res = ngx.location.capture("/proxy") + res = ngx.location.capture("/proxy") ngx.say("status: ", res.status) ngx.say("body: ", res.body) ngx.say("truncated: ", res.truncated) @@ -2288,7 +2288,7 @@ upstream prematurely closed connection } for i, method in ipairs(methods) do - local res = ngx.location.capture("/other", + res = ngx.location.capture("/other", { method = method }) ngx.print(res.body) end @@ -2324,7 +2324,7 @@ method: TRACE location /lua { content_by_lua ' - local res = ngx.location.capture("/other", + res = ngx.location.capture("/other", { method = ngx.HTTP_DELETE }); ngx.print(res.body) @@ -2353,7 +2353,7 @@ nil location /lua { content_by_lua ' ngx.req.read_body() - local res = ngx.location.capture("/other", + res = ngx.location.capture("/other", { method = ngx.HTTP_DELETE, always_forward_body = true }); ngx.print(res.body) @@ -2382,7 +2382,7 @@ hello world location /lua { content_by_lua ' ngx.req.read_body() - local res = ngx.location.capture("/other", + res = ngx.location.capture("/other", { method = ngx.HTTP_DELETE, always_forward_body = true }); ngx.print(res.body) @@ -2410,7 +2410,7 @@ hello world --- config location = /t { content_by_lua ' - local res = ngx.location.capture("/sub") + res = ngx.location.capture("/sub") ngx.print(res.body) '; } @@ -2603,7 +2603,7 @@ qr/Assertion .*? failed/ location = /t { content_by_lua ' - local res = ngx.location.capture("/sub") + res = ngx.location.capture("/sub") ngx.print(res.body) ngx.say("pr: User-Agent: ", ngx.var.http_user_agent) ngx.say("pr: Host: ", ngx.var.http_host) @@ -2636,7 +2636,7 @@ pr: Host: localhost location = /t { content_by_lua ' - local res = ngx.location.capture("/sub") + res = ngx.location.capture("/sub") ngx.print(res.body) ngx.say("pr: User-Agent: ", ngx.var.http_user_agent) ngx.say("pr: Host: ", ngx.var.http_host) @@ -2669,7 +2669,7 @@ pr: Host: localhost location = /t { content_by_lua ' - local res = ngx.location.capture("/sub") + res = ngx.location.capture("/sub") ngx.print(res.body) ngx.say("pr: User-Agent: ", ngx.var.http_user_agent) ngx.say("pr: Host: ", ngx.var.http_host) @@ -2699,7 +2699,7 @@ pr: Host: localhost location = /t { content_by_lua ' - local res = ngx.location.capture("/sub") + res = ngx.location.capture("/sub") ngx.print(res.body) ngx.say("pr: Cookie: ", ngx.var.http_cookie) '; @@ -2727,7 +2727,7 @@ pr: Cookie: foo; bar location = /t { content_by_lua ' - local res = ngx.location.capture("/sub") + res = ngx.location.capture("/sub") ngx.print(res.body) ngx.say("pr: Cookie: ", ngx.var.http_cookie) '; @@ -2750,7 +2750,7 @@ pr: Cookie: foo; bar --- config location /lua { content_by_lua ' - local res = ngx.location.capture("/index.html", + res = ngx.location.capture("/index.html", { method = ngx.HTTP_HEAD }); ngx.say("content-length: ", res.header["Content-Length"]) ngx.say("body: [", res.body, "]") diff --git a/debian/modules/http-lua/t/023-rewrite/client-abort.t b/debian/modules/http-lua/t/023-rewrite/client-abort.t index 0d6f2b3..117d17e 100644 --- a/debian/modules/http-lua/t/023-rewrite/client-abort.t +++ b/debian/modules/http-lua/t/023-rewrite/client-abort.t @@ -199,7 +199,7 @@ bad things happen location = /sub { proxy_ignore_client_abort on; - proxy_pass http://127.0.0.2:12345/; + proxy_pass http://agentzh.org:12345/; } location = /sleep { @@ -240,7 +240,7 @@ client prematurely closed connection location = /sub { proxy_ignore_client_abort off; - proxy_pass http://127.0.0.2:12345/; + proxy_pass http://agentzh.org:12345/; } --- request GET /t @@ -545,7 +545,7 @@ client prematurely closed connection return end - local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_REDIS_PORT) + ok, err = sock:connect("127.0.0.1", $TEST_NGINX_REDIS_PORT) if not ok then ngx.log(ngx.ERR, "failed to connect: ", err) return diff --git a/debian/modules/http-lua/t/023-rewrite/exec.t b/debian/modules/http-lua/t/023-rewrite/exec.t index 59691cb..edd4607 100644 --- a/debian/modules/http-lua/t/023-rewrite/exec.t +++ b/debian/modules/http-lua/t/023-rewrite/exec.t @@ -326,7 +326,7 @@ hello --- config location /main { rewrite_by_lua ' - local res = ngx.location.capture("/test_loc"); + res = ngx.location.capture("/test_loc"); ngx.print("hello, ", res.body) '; content_by_lua return; @@ -354,7 +354,7 @@ hello, bah --- config location /main { rewrite_by_lua ' - local res = ngx.location.capture("/test_loc"); + res = ngx.location.capture("/test_loc"); ngx.print("hello, ", res.body) '; content_by_lua return; diff --git a/debian/modules/http-lua/t/023-rewrite/mixed.t b/debian/modules/http-lua/t/023-rewrite/mixed.t index 5b38d3f..0f742b2 100644 --- a/debian/modules/http-lua/t/023-rewrite/mixed.t +++ b/debian/modules/http-lua/t/023-rewrite/mixed.t @@ -35,7 +35,7 @@ __DATA__ rewrite_by_lua ' ngx.location.capture("/flush"); - local res = ngx.location.capture("/memc"); + res = ngx.location.capture("/memc"); print("rewrite GET: " .. res.status); res = ngx.location.capture("/memc", @@ -49,7 +49,7 @@ __DATA__ content_by_lua ' ngx.location.capture("/flush"); - local res = ngx.location.capture("/memc"); + res = ngx.location.capture("/memc"); ngx.say("content GET: " .. res.status); res = ngx.location.capture("/memc", diff --git a/debian/modules/http-lua/t/023-rewrite/multi-capture.t b/debian/modules/http-lua/t/023-rewrite/multi-capture.t index a0a02b7..083ec78 100644 --- a/debian/modules/http-lua/t/023-rewrite/multi-capture.t +++ b/debian/modules/http-lua/t/023-rewrite/multi-capture.t @@ -154,7 +154,7 @@ res2.body = b location /main { rewrite_by_lua ' - local res = ngx.location.capture("/foo?n=1") + res = ngx.location.capture("/foo?n=1") ngx.say("top res.status = " .. res.status) ngx.say("top res.body = [" .. res.body .. "]") '; diff --git a/debian/modules/http-lua/t/023-rewrite/req-socket.t b/debian/modules/http-lua/t/023-rewrite/req-socket.t index 9292385..87cbbbe 100644 --- a/debian/modules/http-lua/t/023-rewrite/req-socket.t +++ b/debian/modules/http-lua/t/023-rewrite/req-socket.t @@ -325,7 +325,7 @@ found the end of the stream === TEST 4: attempt to use the req socket across request boundary --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location /t { rewrite_by_lua ' @@ -376,7 +376,7 @@ hello world === TEST 5: receive until on request_body - receiveuntil(1) on the last byte of the body See https://groups.google.com/group/openresty/browse_thread/thread/43cf01da3c681aba for details --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location /t { rewrite_by_lua ' @@ -440,7 +440,7 @@ done === TEST 6: pipelined POST requests --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location /t { rewrite_by_lua ' diff --git a/debian/modules/http-lua/t/023-rewrite/sanity.t b/debian/modules/http-lua/t/023-rewrite/sanity.t index 73a85dc..b90aa0e 100644 --- a/debian/modules/http-lua/t/023-rewrite/sanity.t +++ b/debian/modules/http-lua/t/023-rewrite/sanity.t @@ -69,7 +69,7 @@ GET /lua location /lua { # NOTE: the newline escape sequence must be double-escaped, as nginx config # parser will unescape first! - rewrite_by_lua 'local v = ngx.var["request_uri"] ngx.print("request_uri: ", v, "\\n")'; + rewrite_by_lua 'v = ngx.var["request_uri"] ngx.print("request_uri: ", v, "\\n")'; content_by_lua 'ngx.exit(ngx.OK)'; } --- request @@ -87,7 +87,7 @@ request_uri: /lua?a=1&b=2 } --- user_files >>> test.lua -local v = ngx.var["request_uri"] +v = ngx.var["request_uri"] ngx.print("request_uri: ", v, "\n") --- request GET /lua?a=1&b=2 @@ -140,7 +140,7 @@ result: -0.4090441561579 === TEST 7: read $arg_xxx --- config location = /lua { - rewrite_by_lua 'local who = ngx.var.arg_who + rewrite_by_lua 'who = ngx.var.arg_who ngx.print("Hello, ", who, "!")'; content_by_lua 'ngx.exit(ngx.OK)'; } @@ -159,7 +159,7 @@ Hello, agentzh! location /lua { rewrite_by_lua ' -local res = ngx.location.capture("/other") +res = ngx.location.capture("/other") ngx.print("status=", res.status, " ") ngx.print("body=", res.body) '; @@ -175,7 +175,7 @@ status=200 body=hello, world === TEST 9: capture non-existed location --- config location /lua { - rewrite_by_lua 'local res = ngx.location.capture("/other"); ngx.print("status=", res.status)'; + rewrite_by_lua 'res = ngx.location.capture("/other"); ngx.print("status=", res.status)'; content_by_lua 'ngx.exit(ngx.OK)'; } --- request @@ -187,7 +187,7 @@ GET /lua === TEST 10: invalid capture location (not as expected...) --- config location /lua { - rewrite_by_lua 'local res = ngx.location.capture("*(#*"); ngx.say("res=", res.status)'; + rewrite_by_lua 'res = ngx.location.capture("*(#*"); ngx.say("res=", res.status)'; content_by_lua 'ngx.exit(ngx.OK)'; } --- request @@ -270,7 +270,7 @@ end ngx.print("num is: ", num, "\\n"); if (num > 0) then - local res = ngx.location.capture("/recur?num="..tostring(num - 1)); + res = ngx.location.capture("/recur?num="..tostring(num - 1)); ngx.print("status=", res.status, " "); ngx.print("body=", res.body); else @@ -359,7 +359,7 @@ location /sub { } location /parent { set $a 12; - rewrite_by_lua 'local res = ngx.location.capture("/sub"); ngx.print(res.body)'; + rewrite_by_lua 'res = ngx.location.capture("/sub"); ngx.print(res.body)'; content_by_lua 'ngx.exit(ngx.OK)'; } --- request @@ -377,7 +377,7 @@ location /parent { set $a ''; rewrite_by_lua ' ngx.var.a = 12; - local res = ngx.location.capture( + res = ngx.location.capture( "/sub", { share_all_vars = true } ); @@ -399,7 +399,7 @@ location /sub { } location /parent { rewrite_by_lua ' - local res = ngx.location.capture("/sub", { share_all_vars = true }); + res = ngx.location.capture("/sub", { share_all_vars = true }); ngx.say(ngx.var.a) '; @@ -421,7 +421,7 @@ location /sub { location /parent { rewrite_by_lua ' - local res = ngx.location.capture("/sub", { share_all_vars = false }); + res = ngx.location.capture("/sub", { share_all_vars = false }); ngx.say(ngx.var.a) '; content_by_lua return; @@ -441,7 +441,7 @@ GET /parent location /lua { rewrite_by_lua ' - local res = ngx.location.capture("/other"); + res = ngx.location.capture("/other"); ngx.say("type: ", res.header["Content-Type"]); '; @@ -466,7 +466,7 @@ type: foo/bar location /lua { rewrite_by_lua ' - local res = ngx.location.capture("/other"); + res = ngx.location.capture("/other"); ngx.say("type: ", res.header["Content-Type"]); ngx.say("Bar: ", res.header["Bar"]); '; @@ -494,7 +494,7 @@ Bar: Bah location /lua { rewrite_by_lua ' - local res = ngx.location.capture("/other"); + res = ngx.location.capture("/other"); ngx.say("type: ", res.header["Content-Type"]); ngx.say("Bar: ", res.header["Bar"] or "nil"); '; diff --git a/debian/modules/http-lua/t/023-rewrite/socket-keepalive.t b/debian/modules/http-lua/t/023-rewrite/socket-keepalive.t index 8b532ea..489a70f 100644 --- a/debian/modules/http-lua/t/023-rewrite/socket-keepalive.t +++ b/debian/modules/http-lua/t/023-rewrite/socket-keepalive.t @@ -27,7 +27,7 @@ __DATA__ === TEST 1: sanity --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -104,7 +104,7 @@ lua tcp socket get keepalive peer: using connection === TEST 2: free up the whole connection pool if no active connections --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -177,7 +177,7 @@ received: OK === TEST 3: upstream sockets close prematurely --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config server_tokens off; keepalive_timeout 100ms; @@ -254,7 +254,7 @@ done === TEST 4: http keepalive --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config server_tokens off; location /t { @@ -815,7 +815,7 @@ lua tcp socket keepalive timeout: unlimited === TEST 11: sanity (uds) --- http_config eval " - lua_package_path '$::HtmlDir/?.lua;./?.lua;;'; + lua_package_path '$::HtmlDir/?.lua;./?.lua'; server { listen unix:$::HtmlDir/nginx.sock; default_type 'text/plain'; @@ -953,7 +953,7 @@ lua tcp socket get keepalive peer: using connection === TEST 13: github issue #110: ngx.exit with HTTP_NOT_FOUND causes worker process to exit --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config error_page 404 /404.html; location /t { diff --git a/debian/modules/http-lua/t/023-rewrite/subrequest.t b/debian/modules/http-lua/t/023-rewrite/subrequest.t index cb8523c..5d1e8f0 100644 --- a/debian/modules/http-lua/t/023-rewrite/subrequest.t +++ b/debian/modules/http-lua/t/023-rewrite/subrequest.t @@ -27,7 +27,7 @@ __DATA__ location /lua { rewrite_by_lua ' - local res = ngx.location.capture("/other", + res = ngx.location.capture("/other", { method = ngx.HTTP_DELETE }); ngx.print(res.body) @@ -54,7 +54,7 @@ DELETE location /lua { rewrite_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { method = ngx.HTTP_DELETE }); ngx.print(res.body) @@ -82,7 +82,7 @@ DELETE location /lua { rewrite_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { method = ngx.HTTP_POST }); ngx.print(res.body) @@ -105,7 +105,7 @@ POST location /lua { rewrite_by_lua ' - local res = ngx.location.capture("/other", + res = ngx.location.capture("/other", { method = ngx.HTTP_HEAD }); ngx.print(res.body) @@ -131,7 +131,7 @@ GET /lua location /lua { rewrite_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { method = ngx.HTTP_GET }); ngx.print(res.body) @@ -158,7 +158,7 @@ GET location /lua { rewrite_by_lua ' - local res = ngx.location.capture("/foo") + res = ngx.location.capture("/foo") ngx.print(res.body) '; @@ -184,7 +184,7 @@ GET location /lua { rewrite_by_lua ' - local res = ngx.location.capture("/foo", {}) + res = ngx.location.capture("/foo", {}) ngx.print(res.body) '; @@ -213,7 +213,7 @@ GET location /lua { rewrite_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { method = ngx.HTTP_PUT, body = "hello" }); ngx.print(res.body) @@ -241,7 +241,7 @@ hello location /lua { rewrite_by_lua ' - local res = ngx.location.capture("/other", + res = ngx.location.capture("/other", { method = ngx.HTTP_PUT, body = "hello" }); ngx.print(res.body) @@ -276,7 +276,7 @@ hello location /lua { rewrite_by_lua ' - local res = ngx.location.capture("/other", + res = ngx.location.capture("/other", { method = ngx.HTTP_PUT, body = "hello" }); ngx.print(res.body) @@ -313,7 +313,7 @@ GET location /lua { rewrite_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { method = ngx.HTTP_POST, body = "hello" }); ngx.print(res.body) @@ -345,7 +345,7 @@ hello rewrite_by_lua ' ngx.location.capture("/flush"); - local res = ngx.location.capture("/memc"); + res = ngx.location.capture("/memc"); ngx.say("GET: " .. res.status); res = ngx.location.capture("/memc", @@ -386,7 +386,7 @@ cached: hello ngx.location.capture("/flush", { share_all_vars = true }); - local res = ngx.location.capture("/memc", + res = ngx.location.capture("/memc", { share_all_vars = true }); ngx.say("GET: " .. res.status); @@ -417,7 +417,7 @@ cached: hello location /lua { rewrite_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { args = {} }) ngx.print(res.body) '; @@ -437,7 +437,7 @@ GET /lua location /lua { rewrite_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { args = { ["fo="] = "=>" } }) ngx.print(res.body) '; @@ -458,7 +458,7 @@ fo%3D=%3D%3E location /lua { rewrite_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { args = { ["fo="] = "=>", ["="] = ":" } }) ngx.print(res.body) @@ -480,7 +480,7 @@ GET /lua location /lua { rewrite_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { args = { foo = 3, bar = "hello" } }) ngx.print(res.body) @@ -502,7 +502,7 @@ GET /lua location /lua { rewrite_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { args = { [57] = "hi" } }) ngx.print(res.body) '; @@ -523,7 +523,7 @@ GET /lua location /lua { rewrite_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { args = { "hi" } }) ngx.print(res.body) '; @@ -544,7 +544,7 @@ GET /lua location /lua { rewrite_by_lua ' - local res = ngx.location.capture("/foo?a=3", + res = ngx.location.capture("/foo?a=3", { args = { b = 4 } }) ngx.print(res.body) '; @@ -565,7 +565,7 @@ a=3&b=4 location /lua { rewrite_by_lua ' - local res = ngx.location.capture("/foo?a=3", + res = ngx.location.capture("/foo?a=3", { args = "b=4" }) ngx.print(res.body) '; diff --git a/debian/modules/http-lua/t/023-rewrite/tcp-socket-timeout.t b/debian/modules/http-lua/t/023-rewrite/tcp-socket-timeout.t index e713bb5..329c045 100644 --- a/debian/modules/http-lua/t/023-rewrite/tcp-socket-timeout.t +++ b/debian/modules/http-lua/t/023-rewrite/tcp-socket-timeout.t @@ -46,7 +46,7 @@ __DATA__ location /t1 { rewrite_by_lua ' local sock = ngx.socket.tcp() - local ok, err = sock:connect("127.0.0.2", 12345) + local ok, err = sock:connect("agentzh.org", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -63,7 +63,7 @@ GET /t1 failed to connect: timeout --- error_log lua tcp socket connect timeout: 100 -lua tcp socket connect timed out, when connecting to 127.0.0.2:12345 +lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 --- timeout: 10 @@ -79,7 +79,7 @@ lua tcp socket connect timed out, when connecting to 127.0.0.2:12345 rewrite_by_lua ' local sock = ngx.socket.tcp() sock:settimeout(150) - local ok, err = sock:connect("127.0.0.2", 12345) + local ok, err = sock:connect("agentzh.org", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -114,7 +114,7 @@ lua tcp socket connect timeout: 150 rewrite_by_lua ' local sock = ngx.socket.tcp() sock:settimeout(nil) - local ok, err = sock:connect("127.0.0.2", 12345) + local ok, err = sock:connect("agentzh.org", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -149,7 +149,7 @@ lua tcp socket connect timeout: 102 rewrite_by_lua ' local sock = ngx.socket.tcp() sock:settimeout(0) - local ok, err = sock:connect("127.0.0.2", 12345) + local ok, err = sock:connect("agentzh.org", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -185,7 +185,7 @@ lua tcp socket connect timeout: 102 rewrite_by_lua ' local sock = ngx.socket.tcp() sock:settimeout(-1) - local ok, err = sock:connect("127.0.0.2", 12345) + local ok, err = sock:connect("agentzh.org", 12345) if not ok then ngx.say("failed to connect: ", err) return diff --git a/debian/modules/http-lua/t/023-rewrite/tcp-socket.t b/debian/modules/http-lua/t/023-rewrite/tcp-socket.t index 5258487..41aeab7 100644 --- a/debian/modules/http-lua/t/023-rewrite/tcp-socket.t +++ b/debian/modules/http-lua/t/023-rewrite/tcp-socket.t @@ -250,11 +250,11 @@ attempt to send data on a closed socket: } --- request GET /t ---- response_body_like +--- response_body connected: 1 request sent: 56 -first line received: HTTP\/1\.1 200 OK -second line received: (?:Date|Server): .*? +first line received: HTTP/1.1 200 OK +second line received: Server: openresty --- no_error_log [error] @@ -304,7 +304,7 @@ qr/connect\(\) failed \(\d+: Connection refused\)/ location /test { rewrite_by_lua ' local sock = ngx.socket.tcp() - local ok, err = sock:connect("127.0.0.2", 12345) + local ok, err = sock:connect("agentzh.org", 12345) ngx.say("connect: ", ok, " ", err) local bytes @@ -329,7 +329,7 @@ send: nil closed receive: nil closed close: nil closed --- error_log -lua tcp socket connect timed out, when connecting to 127.0.0.2:12345 +lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 --- timeout: 10 @@ -940,7 +940,7 @@ close: 1 nil end end - local ok, err = sock:close() + ok, err = sock:close() ngx.say("close: ", ok, " ", err) '; @@ -1082,7 +1082,7 @@ close: 1 nil === TEST 19: cannot survive across request boundary (send) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config server_tokens off; location /t { @@ -1143,7 +1143,7 @@ received: OK|failed to send request: closed)\$" === TEST 20: cannot survive across request boundary (receive) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config server_tokens off; location /t { @@ -1214,7 +1214,7 @@ received: OK|failed to receive a line: closed \[nil\])$/ === TEST 21: cannot survive across request boundary (close) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config server_tokens off; location /t { @@ -1285,7 +1285,7 @@ received: OK|failed to close: closed)$/ === TEST 22: cannot survive across request boundary (connect) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config server_tokens off; location /t { @@ -2041,7 +2041,7 @@ close: 1 nil === TEST 33: bad request tries to connect --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config server_tokens off; location = /main { @@ -2097,7 +2097,7 @@ qr/runtime error: rewrite_by_lua\(nginx\.conf:\d+\):7: bad request/ === TEST 34: bad request tries to receive --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config server_tokens off; location = /main { @@ -2156,7 +2156,7 @@ qr/runtime error: rewrite_by_lua\(nginx\.conf:\d+\):14: bad request/ === TEST 35: bad request tries to send --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config server_tokens off; location = /main { @@ -2215,7 +2215,7 @@ qr/runtime error: rewrite_by_lua\(nginx\.conf:\d+\):14: bad request/ === TEST 36: bad request tries to close --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config server_tokens off; location = /main { @@ -2274,7 +2274,7 @@ qr/runtime error: rewrite_by_lua\(nginx\.conf:\d+\):14: bad request/ === TEST 37: bad request tries to set keepalive --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config server_tokens off; location = /main { @@ -2333,7 +2333,7 @@ qr/runtime error: rewrite_by_lua\(nginx\.conf:\d+\):14: bad request/ === TEST 38: bad request tries to receiveuntil --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config server_tokens off; location = /main { diff --git a/debian/modules/http-lua/t/023-rewrite/uthread-exec.t b/debian/modules/http-lua/t/023-rewrite/uthread-exec.t index 9428bd6..2bea7e7 100644 --- a/debian/modules/http-lua/t/023-rewrite/uthread-exec.t +++ b/debian/modules/http-lua/t/023-rewrite/uthread-exec.t @@ -23,7 +23,7 @@ __DATA__ --- config location /lua { rewrite_by_lua ' - local function f() + function f() ngx.exec("/foo") end @@ -59,7 +59,7 @@ i am foo --- config location /lua { rewrite_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.exec("/foo") end @@ -95,7 +95,7 @@ i am foo --- config location /lua { rewrite_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.exec("/foo") end @@ -178,12 +178,12 @@ hello foo --- config location /lua { rewrite_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.exec("/foo") end - local function g() + function g() ngx.sleep(1) end @@ -270,7 +270,7 @@ hello foo location /lua { client_body_timeout 12000ms; rewrite_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.exec("/foo") end diff --git a/debian/modules/http-lua/t/023-rewrite/uthread-exit.t b/debian/modules/http-lua/t/023-rewrite/uthread-exit.t index e25f7f8..6ebbb67 100644 --- a/debian/modules/http-lua/t/023-rewrite/uthread-exit.t +++ b/debian/modules/http-lua/t/023-rewrite/uthread-exit.t @@ -24,7 +24,7 @@ __DATA__ --- config location /lua { rewrite_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.exit(0) end @@ -87,7 +87,7 @@ hello in thread --- config location /lua { rewrite_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -172,13 +172,13 @@ after --- config location /lua { rewrite_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.say("f") ngx.exit(0) end - local function g() + function g() ngx.sleep(1) ngx.say("g") end @@ -262,7 +262,7 @@ f --- config location /lua { rewrite_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.say("exiting the user thread") ngx.exit(0) @@ -298,10 +298,10 @@ exiting the user thread === TEST 5: exit in user thread (entry thread is still pending on the DNS resolver for ngx.socket.tcp) --- config location /lua { - resolver 127.0.0.2:12345; + resolver agentzh.org; resolver_timeout 12s; rewrite_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.001) ngx.exit(0) @@ -311,7 +311,7 @@ exiting the user thread ngx.thread.spawn(f) ngx.say("after") local sock = ngx.socket.tcp() - local ok, err = sock:connect("127.0.0.2", 12345) + local ok, err = sock:connect("agentzh.org", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -403,11 +403,11 @@ after === TEST 6: exit in user thread (entry thread is still pending on the DNS resolver for ngx.socket.udp) --- config location /lua { - resolver 127.0.0.2:12345; + resolver agentzh.org; #resolver 127.0.0.1; resolver_timeout 12s; rewrite_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.001) ngx.exit(0) @@ -510,7 +510,7 @@ after --- config location /lua { rewrite_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -521,7 +521,7 @@ after ngx.say("after") local sock = ngx.socket.tcp() sock:settimeout(12000) - local ok, err = sock:connect("127.0.0.2", 12345) + local ok, err = sock:connect("172.105.207.225", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -600,7 +600,7 @@ after --- config location /lua { rewrite_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -700,7 +700,7 @@ after --- config location /lua { rewrite_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -806,7 +806,7 @@ after --- config location /lua { rewrite_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -901,7 +901,7 @@ after --- config location /lua { rewrite_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -995,7 +995,7 @@ after location /lua { client_body_timeout 12000ms; rewrite_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -1080,7 +1080,7 @@ after location /lua { client_body_timeout 12000ms; rewrite_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -1164,7 +1164,7 @@ attempt to abort with pending subrequests location /lua { client_body_timeout 12000ms; rewrite_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.exit(0) end @@ -1247,7 +1247,7 @@ attempt to abort with pending subrequests location /lua { client_body_timeout 12000ms; rewrite_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.exit(0) end diff --git a/debian/modules/http-lua/t/023-rewrite/uthread-redirect.t b/debian/modules/http-lua/t/023-rewrite/uthread-redirect.t index 0e636f7..83de1a3 100644 --- a/debian/modules/http-lua/t/023-rewrite/uthread-redirect.t +++ b/debian/modules/http-lua/t/023-rewrite/uthread-redirect.t @@ -25,7 +25,7 @@ __DATA__ location /lua { client_body_timeout 12000ms; rewrite_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.redirect(301) end @@ -113,7 +113,7 @@ attempt to abort with pending subrequests --- config location /lua { rewrite_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.redirect(301) end diff --git a/debian/modules/http-lua/t/023-rewrite/uthread-spawn.t b/debian/modules/http-lua/t/023-rewrite/uthread-spawn.t index dccef87..5552107 100644 --- a/debian/modules/http-lua/t/023-rewrite/uthread-spawn.t +++ b/debian/modules/http-lua/t/023-rewrite/uthread-spawn.t @@ -23,7 +23,7 @@ __DATA__ --- config location /lua { rewrite_by_lua ' - local function f() + function f() ngx.say("hello in thread") end @@ -68,11 +68,11 @@ after --- config location /lua { rewrite_by_lua ' - local function f() + function f() ngx.say("in thread 1") end - local function g() + function g() ngx.say("in thread 2") end @@ -117,7 +117,7 @@ after 2 --- config location /lua { rewrite_by_lua ' - local function f() + function f() ngx.say("before sleep") ngx.sleep(0.1) ngx.say("after sleep") @@ -154,13 +154,13 @@ after sleep --- config location /lua { rewrite_by_lua ' - local function f() + function f() ngx.say("1: before sleep") ngx.sleep(0.2) ngx.say("1: after sleep") end - local function g() + function g() ngx.say("2: before sleep") ngx.sleep(0.1) ngx.say("2: after sleep") @@ -210,7 +210,7 @@ delete thread 2 --- config location /lua { rewrite_by_lua ' - local function f() + function f() ngx.blah() end @@ -241,9 +241,9 @@ qr/lua user thread aborted: runtime error: rewrite_by_lua\(nginx\.conf:\d+\):3: --- config location /lua { rewrite_by_lua ' - local function f() + function f() ngx.say("before capture") - local res = ngx.location.capture("/proxy") + res = ngx.location.capture("/proxy") ngx.say("after capture: ", res.body) end @@ -287,7 +287,7 @@ after capture: hello world --- config location /lua { rewrite_by_lua ' - local function f() + function f() ngx.say("before capture") local res = ngx.location.capture("/proxy?foo") ngx.say("after capture: ", res.body) @@ -340,7 +340,7 @@ after capture: hello foo --- config location /lua { rewrite_by_lua ' - local function f() + function f() ngx.say("before capture") local res = ngx.location.capture("/proxy?foo") ngx.say("after capture: ", res.body) @@ -394,13 +394,13 @@ capture: hello bar --- config location /lua { rewrite_by_lua ' - local function f() + function f() ngx.say("f: before capture") local res = ngx.location.capture("/proxy?foo") ngx.say("f: after capture: ", res.body) end - local function g() + function g() ngx.say("g: before capture") local res = ngx.location.capture("/proxy?bah") ngx.say("g: after capture: ", res.body) @@ -472,8 +472,7 @@ g: after capture: hello bah --- config location /lua { rewrite_by_lua ' - local g - local function f() + function f() ngx.say("before g") ngx.thread.spawn(g) ngx.say("after g") @@ -519,8 +518,7 @@ after g --- config location /lua { rewrite_by_lua ' - local g - local function f() + function f() ngx.say("before g") ngx.thread.spawn(g) ngx.say("after g") @@ -568,7 +566,7 @@ hello in g() location /lua { rewrite_by_lua ' local co - local function f() + function f() co = coroutine.running() ngx.sleep(0.1) end @@ -601,7 +599,7 @@ status: running location /lua { rewrite_by_lua ' local co - local function f() + function f() co = coroutine.running() end @@ -633,8 +631,7 @@ status: zombie location /lua { rewrite_by_lua ' local co - local g - local function f() + function f() co = coroutine.running() local co2 = coroutine.create(g) coroutine.resume(co2) @@ -673,8 +670,7 @@ status: normal --- config location /lua { rewrite_by_lua ' - local g - local function f() + function f() ngx.say("before g") ngx.thread.spawn(g) ngx.say("after g") @@ -721,7 +717,7 @@ after f rewrite_by_lua ' local yield = coroutine.yield - local function f() + function f() local self = coroutine.running() ngx.say("f 1") yield(self) @@ -774,7 +770,7 @@ f 3 rewrite_by_lua ' local yield = coroutine.yield - local function f() + function f() local self = coroutine.running() ngx.say("f 1") yield(self) @@ -783,7 +779,7 @@ f 3 ngx.say("f 3") end - local function g() + function g() local self = coroutine.running() ngx.say("g 1") yield(self) @@ -830,7 +826,7 @@ g 3 --- config location /lua { rewrite_by_lua ' - local function f() + function f() ngx.say("hello in thread") coroutine.yield(coroutine.running) ngx.flush(true) @@ -867,12 +863,12 @@ after --- config location /lua { rewrite_by_lua ' - local function f() + function f() ngx.say("hello from f") ngx.flush(true) end - local function g() + function g() ngx.say("hello from g") ngx.flush(true) end @@ -918,7 +914,7 @@ hello from g --- config location /lua { rewrite_by_lua ' - local function f() + function f() local sock = ngx.socket.tcp() local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_MEMCACHED_PORT) if not ok then @@ -970,7 +966,7 @@ received: OK --- config location /lua { rewrite_by_lua ' - local function f() + function f() local sock = ngx.socket.udp() local ok, err = sock:setpeername("127.0.0.1", 12345) local bytes, err = sock:send("blah") @@ -1031,7 +1027,7 @@ after)$ --- config location /lua { rewrite_by_lua ' - local function f() + function f() ngx.req.read_body() local body = ngx.req.get_body_data() ngx.say("body: ", body) @@ -1077,7 +1073,7 @@ body: hello world)$ --- config location /lua { rewrite_by_lua ' - local function f() + function f() local sock = ngx.req.socket() local body, err = sock:receive(11) if not body then diff --git a/debian/modules/http-lua/t/024-access/client-abort.t b/debian/modules/http-lua/t/024-access/client-abort.t index 83bf0a4..c16f4ea 100644 --- a/debian/modules/http-lua/t/024-access/client-abort.t +++ b/debian/modules/http-lua/t/024-access/client-abort.t @@ -200,7 +200,7 @@ bad things happen location = /sub { proxy_ignore_client_abort on; - proxy_pass http://127.0.0.2:12345/; + proxy_pass http://agentzh.org:12345/; } location = /sleep { @@ -241,7 +241,7 @@ client prematurely closed connection location = /sub { proxy_ignore_client_abort off; - proxy_pass http://127.0.0.2:12345/; + proxy_pass http://agentzh.org:12345/; } --- request GET /t @@ -546,7 +546,7 @@ client prematurely closed connection return end - local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_REDIS_PORT) + ok, err = sock:connect("127.0.0.1", $TEST_NGINX_REDIS_PORT) if not ok then ngx.log(ngx.ERR, "failed to connect: ", err) return diff --git a/debian/modules/http-lua/t/024-access/exec.t b/debian/modules/http-lua/t/024-access/exec.t index d168a47..43c1a77 100644 --- a/debian/modules/http-lua/t/024-access/exec.t +++ b/debian/modules/http-lua/t/024-access/exec.t @@ -326,7 +326,7 @@ hello --- config location /main { access_by_lua ' - local res = ngx.location.capture("/test_loc"); + res = ngx.location.capture("/test_loc"); ngx.print("hello, ", res.body) '; content_by_lua return; diff --git a/debian/modules/http-lua/t/024-access/mixed.t b/debian/modules/http-lua/t/024-access/mixed.t index 22f0037..a9f8039 100644 --- a/debian/modules/http-lua/t/024-access/mixed.t +++ b/debian/modules/http-lua/t/024-access/mixed.t @@ -35,7 +35,7 @@ __DATA__ access_by_lua ' ngx.location.capture("/flush"); - local res = ngx.location.capture("/memc"); + res = ngx.location.capture("/memc"); print("access GET: ", res.status); res = ngx.location.capture("/memc", @@ -49,7 +49,7 @@ __DATA__ content_by_lua ' ngx.location.capture("/flush"); - local res = ngx.location.capture("/memc"); + res = ngx.location.capture("/memc"); ngx.say("content GET: " .. res.status); res = ngx.location.capture("/memc", @@ -187,7 +187,7 @@ world\x03\x04\xff rewrite_by_lua ' ngx.location.capture("/flush"); - local res = ngx.location.capture("/memc"); + res = ngx.location.capture("/memc"); print("rewrite GET: " .. res.status); res = ngx.location.capture("/memc", @@ -201,7 +201,7 @@ world\x03\x04\xff access_by_lua ' ngx.location.capture("/flush"); - local res = ngx.location.capture("/memc"); + res = ngx.location.capture("/memc"); print("access GET: " .. res.status); res = ngx.location.capture("/memc", @@ -215,7 +215,7 @@ world\x03\x04\xff content_by_lua ' ngx.location.capture("/flush"); - local res = ngx.location.capture("/memc"); + res = ngx.location.capture("/memc"); ngx.say("content GET: " .. res.status); res = ngx.location.capture("/memc", diff --git a/debian/modules/http-lua/t/024-access/multi-capture.t b/debian/modules/http-lua/t/024-access/multi-capture.t index b1757dd..930b74d 100644 --- a/debian/modules/http-lua/t/024-access/multi-capture.t +++ b/debian/modules/http-lua/t/024-access/multi-capture.t @@ -154,7 +154,7 @@ res2.body = b location /main { access_by_lua ' - local res = ngx.location.capture("/foo?n=1") + res = ngx.location.capture("/foo?n=1") ngx.say("top res.status = " .. res.status) ngx.say("top res.body = [" .. res.body .. "]") '; diff --git a/debian/modules/http-lua/t/024-access/sanity.t b/debian/modules/http-lua/t/024-access/sanity.t index e5612a8..7ff177f 100644 --- a/debian/modules/http-lua/t/024-access/sanity.t +++ b/debian/modules/http-lua/t/024-access/sanity.t @@ -69,7 +69,7 @@ GET /lua location /lua { # NOTE: the newline escape sequence must be double-escaped, as nginx config # parser will unescape first! - access_by_lua 'local v = ngx.var["request_uri"] ngx.print("request_uri: ", v, "\\n")'; + access_by_lua 'v = ngx.var["request_uri"] ngx.print("request_uri: ", v, "\\n")'; content_by_lua 'ngx.exit(ngx.OK)'; } --- request @@ -87,7 +87,7 @@ request_uri: /lua?a=1&b=2 } --- user_files >>> test.lua -local v = ngx.var["request_uri"] +v = ngx.var["request_uri"] ngx.print("request_uri: ", v, "\n") --- request GET /lua?a=1&b=2 @@ -140,7 +140,7 @@ result: -0.4090441561579 === TEST 7: read $arg_xxx --- config location = /lua { - access_by_lua 'local who = ngx.var.arg_who + access_by_lua 'who = ngx.var.arg_who ngx.print("Hello, ", who, "!")'; content_by_lua 'ngx.exit(ngx.OK)'; } @@ -159,7 +159,7 @@ Hello, agentzh! location /lua { access_by_lua ' -local res = ngx.location.capture("/other") +res = ngx.location.capture("/other") ngx.print("status=", res.status, " ") ngx.print("body=", res.body) '; @@ -175,7 +175,7 @@ status=200 body=hello, world === TEST 9: capture non-existed location --- config location /lua { - access_by_lua 'local res = ngx.location.capture("/other"); ngx.print("status=", res.status)'; + access_by_lua 'res = ngx.location.capture("/other"); ngx.print("status=", res.status)'; content_by_lua 'ngx.exit(ngx.OK)'; } --- request @@ -187,7 +187,7 @@ GET /lua === TEST 10: invalid capture location (not as expected...) --- config location /lua { - access_by_lua 'local res = ngx.location.capture("*(#*"); ngx.say("res=", res.status)'; + access_by_lua 'res = ngx.location.capture("*(#*"); ngx.say("res=", res.status)'; content_by_lua 'ngx.exit(ngx.OK)'; } --- request @@ -244,7 +244,7 @@ GET /lua ngx.print("num is: ", num, "\\n"); if (num > 0) then - local res = ngx.location.capture("/recur?num="..tostring(num - 1)); + res = ngx.location.capture("/recur?num="..tostring(num - 1)); ngx.print("status=", res.status, " "); ngx.print("body=", res.body, "\\n"); else @@ -271,7 +271,7 @@ access phase not running in subrequests ngx.print("num is: ", num, "\\n"); if (num > 0) then - local res = ngx.location.capture("/recur?num="..tostring(num - 1)); + res = ngx.location.capture("/recur?num="..tostring(num - 1)); ngx.print("status=", res.status, " "); ngx.print("body=", res.body); else @@ -357,7 +357,7 @@ location /sub { } location /parent { set $a 12; - access_by_lua 'local res = ngx.location.capture("/sub"); ngx.print(res.body)'; + access_by_lua 'res = ngx.location.capture("/sub"); ngx.print(res.body)'; content_by_lua 'ngx.exit(ngx.OK)'; } --- request @@ -375,7 +375,7 @@ location /parent { set $a ''; access_by_lua ' ngx.var.a = 12; - local res = ngx.location.capture( + res = ngx.location.capture( "/sub", { share_all_vars = true } ); @@ -397,7 +397,7 @@ location /sub { } location /parent { access_by_lua ' - local res = ngx.location.capture("/sub", { share_all_vars = true }); + res = ngx.location.capture("/sub", { share_all_vars = true }); ngx.say(ngx.var.a) '; @@ -419,7 +419,7 @@ location /sub { location /parent { access_by_lua ' - local res = ngx.location.capture("/sub", { share_all_vars = false }); + res = ngx.location.capture("/sub", { share_all_vars = false }); ngx.say(ngx.var.a) '; content_by_lua return; @@ -439,7 +439,7 @@ GET /parent location /lua { access_by_lua ' - local res = ngx.location.capture("/other"); + res = ngx.location.capture("/other"); ngx.say("type: ", res.header["Content-Type"]); '; @@ -464,7 +464,7 @@ type: foo/bar location /lua { access_by_lua ' - local res = ngx.location.capture("/other"); + res = ngx.location.capture("/other"); ngx.say("type: ", res.header["Content-Type"]); ngx.say("Bar: ", res.header["Bar"]); '; @@ -492,7 +492,7 @@ Bar: Bah location /lua { access_by_lua ' - local res = ngx.location.capture("/other"); + res = ngx.location.capture("/other"); ngx.say("type: ", res.header["Content-Type"]); ngx.say("Bar: ", res.header["Bar"] or "nil"); '; diff --git a/debian/modules/http-lua/t/024-access/subrequest.t b/debian/modules/http-lua/t/024-access/subrequest.t index 665780a..b6ccf11 100644 --- a/debian/modules/http-lua/t/024-access/subrequest.t +++ b/debian/modules/http-lua/t/024-access/subrequest.t @@ -27,7 +27,7 @@ __DATA__ location /lua { access_by_lua ' - local res = ngx.location.capture("/other", + res = ngx.location.capture("/other", { method = ngx.HTTP_DELETE }); ngx.print(res.body) @@ -54,7 +54,7 @@ DELETE location /lua { access_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { method = ngx.HTTP_DELETE }); ngx.print(res.body) @@ -82,7 +82,7 @@ DELETE location /lua { access_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { method = ngx.HTTP_POST }); ngx.print(res.body) @@ -105,7 +105,7 @@ POST location /lua { access_by_lua ' - local res = ngx.location.capture("/other", + res = ngx.location.capture("/other", { method = ngx.HTTP_HEAD }); ngx.print(res.body) @@ -131,7 +131,7 @@ GET /lua location /lua { access_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { method = ngx.HTTP_GET }); ngx.print(res.body) @@ -158,7 +158,7 @@ GET location /lua { access_by_lua ' - local res = ngx.location.capture("/foo") + res = ngx.location.capture("/foo") ngx.print(res.body) '; @@ -184,7 +184,7 @@ GET location /lua { access_by_lua ' - local res = ngx.location.capture("/foo", {}) + res = ngx.location.capture("/foo", {}) ngx.print(res.body) '; @@ -213,7 +213,7 @@ GET location /lua { access_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { method = ngx.HTTP_PUT, body = "hello" }); ngx.print(res.body) @@ -241,7 +241,7 @@ hello location /lua { access_by_lua ' - local res = ngx.location.capture("/other", + res = ngx.location.capture("/other", { method = ngx.HTTP_PUT, body = "hello" }); ngx.print(res.body) @@ -276,7 +276,7 @@ hello location /lua { access_by_lua ' - local res = ngx.location.capture("/other", + res = ngx.location.capture("/other", { method = ngx.HTTP_PUT, body = "hello" }); ngx.print(res.body) @@ -313,7 +313,7 @@ GET location /lua { access_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { method = ngx.HTTP_POST, body = "hello" }); ngx.print(res.body) @@ -345,7 +345,7 @@ hello access_by_lua ' ngx.location.capture("/flush"); - local res = ngx.location.capture("/memc"); + res = ngx.location.capture("/memc"); ngx.say("GET: " .. res.status); res = ngx.location.capture("/memc", @@ -386,7 +386,7 @@ cached: hello ngx.location.capture("/flush", { share_all_vars = true }); - local res = ngx.location.capture("/memc", + res = ngx.location.capture("/memc", { share_all_vars = true }); ngx.say("GET: " .. res.status); @@ -417,7 +417,7 @@ cached: hello location /lua { access_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { args = {} }) ngx.print(res.body) '; @@ -437,7 +437,7 @@ GET /lua location /lua { access_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { args = { ["fo="] = "=>" } }) ngx.print(res.body) '; @@ -458,7 +458,7 @@ fo%3D=%3D%3E location /lua { access_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { args = { ["fo="] = "=>", ["="] = ":" } }) ngx.print(res.body) @@ -480,7 +480,7 @@ GET /lua location /lua { access_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { args = { foo = 3, bar = "hello" } }) ngx.print(res.body) @@ -502,7 +502,7 @@ GET /lua location /lua { access_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { args = { [57] = "hi" } }) ngx.print(res.body) '; @@ -523,7 +523,7 @@ GET /lua location /lua { access_by_lua ' - local res = ngx.location.capture("/foo", + res = ngx.location.capture("/foo", { args = { "hi" } }) ngx.print(res.body) '; @@ -544,7 +544,7 @@ GET /lua location /lua { access_by_lua ' - local res = ngx.location.capture("/foo?a=3", + res = ngx.location.capture("/foo?a=3", { args = { b = 4 } }) ngx.print(res.body) '; @@ -565,7 +565,7 @@ a=3&b=4 location /lua { access_by_lua ' - local res = ngx.location.capture("/foo?a=3", + res = ngx.location.capture("/foo?a=3", { args = "b=4" }) ngx.print(res.body) '; diff --git a/debian/modules/http-lua/t/024-access/uthread-exec.t b/debian/modules/http-lua/t/024-access/uthread-exec.t index 9c88eb3..7add3d4 100644 --- a/debian/modules/http-lua/t/024-access/uthread-exec.t +++ b/debian/modules/http-lua/t/024-access/uthread-exec.t @@ -23,7 +23,7 @@ __DATA__ --- config location /lua { access_by_lua ' - local function f() + function f() ngx.exec("/foo") end @@ -59,7 +59,7 @@ i am foo --- config location /lua { access_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.exec("/foo") end @@ -95,7 +95,7 @@ i am foo --- config location /lua { access_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.exec("/foo") end @@ -179,12 +179,12 @@ hello foo --- config location /lua { access_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.exec("/foo") end - local function g() + function g() ngx.sleep(1) end @@ -271,7 +271,7 @@ hello foo location /lua { client_body_timeout 12000ms; access_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.exec("/foo") end diff --git a/debian/modules/http-lua/t/024-access/uthread-exit.t b/debian/modules/http-lua/t/024-access/uthread-exit.t index 2757237..02c2a1f 100644 --- a/debian/modules/http-lua/t/024-access/uthread-exit.t +++ b/debian/modules/http-lua/t/024-access/uthread-exit.t @@ -24,7 +24,7 @@ __DATA__ --- config location /lua { access_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.exit(0) end @@ -87,7 +87,7 @@ hello in thread --- config location /lua { access_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -172,13 +172,13 @@ after --- config location /lua { access_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.say("f") ngx.exit(0) end - local function g() + function g() ngx.sleep(1) ngx.say("g") end @@ -262,7 +262,7 @@ f --- config location /lua { access_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.say("exiting the user thread") ngx.exit(0) @@ -298,10 +298,10 @@ exiting the user thread === TEST 5: exit in user thread (entry thread is still pending on the DNS resolver for ngx.socket.tcp) --- config location /lua { - resolver 127.0.0.2:12345; + resolver agentzh.org; resolver_timeout 12s; access_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.001) ngx.exit(0) @@ -394,10 +394,10 @@ after === TEST 6: exit in user thread (entry thread is still pending on the DNS resolver for ngx.socket.udp) --- config location /lua { - resolver 127.0.0.2:12345; + resolver agentzh.org; resolver_timeout 12s; access_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.001) ngx.exit(0) @@ -491,7 +491,7 @@ after --- config location /lua { access_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -502,7 +502,7 @@ after ngx.say("after") local sock = ngx.socket.tcp() sock:settimeout(12000) - local ok, err = sock:connect("127.0.0.2", 12345) + local ok, err = sock:connect("172.105.207.225", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -582,7 +582,7 @@ after --- config location /lua { access_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -682,7 +682,7 @@ after --- config location /lua { access_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -788,7 +788,7 @@ after --- config location /lua { access_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -883,7 +883,7 @@ after --- config location /lua { access_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -977,7 +977,7 @@ after location /lua { client_body_timeout 12000ms; access_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -1062,7 +1062,7 @@ after location /lua { client_body_timeout 12000ms; access_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -1146,7 +1146,7 @@ attempt to abort with pending subrequests location /lua { client_body_timeout 12000ms; access_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.exit(0) end @@ -1229,7 +1229,7 @@ attempt to abort with pending subrequests location /lua { client_body_timeout 12000ms; access_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.exit(0) end diff --git a/debian/modules/http-lua/t/024-access/uthread-redirect.t b/debian/modules/http-lua/t/024-access/uthread-redirect.t index cb99a35..4eb4759 100644 --- a/debian/modules/http-lua/t/024-access/uthread-redirect.t +++ b/debian/modules/http-lua/t/024-access/uthread-redirect.t @@ -25,7 +25,7 @@ __DATA__ location /lua { client_body_timeout 12000ms; access_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.redirect(301) end @@ -113,7 +113,7 @@ attempt to abort with pending subrequests --- config location /lua { access_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.redirect(301) end diff --git a/debian/modules/http-lua/t/024-access/uthread-spawn.t b/debian/modules/http-lua/t/024-access/uthread-spawn.t index bc92ccd..7c7ba3b 100644 --- a/debian/modules/http-lua/t/024-access/uthread-spawn.t +++ b/debian/modules/http-lua/t/024-access/uthread-spawn.t @@ -23,7 +23,7 @@ __DATA__ --- config location /lua { access_by_lua ' - local function f() + function f() ngx.say("hello in thread") end @@ -68,11 +68,11 @@ after --- config location /lua { access_by_lua ' - local function f() + function f() ngx.say("in thread 1") end - local function g() + function g() ngx.say("in thread 2") end @@ -117,7 +117,7 @@ after 2 --- config location /lua { access_by_lua ' - local function f() + function f() ngx.say("before sleep") ngx.sleep(0.1) ngx.say("after sleep") @@ -154,13 +154,13 @@ after sleep --- config location /lua { access_by_lua ' - local function f() + function f() ngx.say("1: before sleep") ngx.sleep(0.2) ngx.say("1: after sleep") end - local function g() + function g() ngx.say("2: before sleep") ngx.sleep(0.1) ngx.say("2: after sleep") @@ -210,7 +210,7 @@ delete thread 2 --- config location /lua { access_by_lua ' - local function f() + function f() ngx.blah() end @@ -241,9 +241,9 @@ qr/lua user thread aborted: runtime error: access_by_lua\(nginx\.conf:\d+\):3: a --- config location /lua { access_by_lua ' - local function f() + function f() ngx.say("before capture") - local res = ngx.location.capture("/proxy") + res = ngx.location.capture("/proxy") ngx.say("after capture: ", res.body) end @@ -287,7 +287,7 @@ after capture: hello world --- config location /lua { access_by_lua ' - local function f() + function f() ngx.say("before capture") local res = ngx.location.capture("/proxy?foo") ngx.say("after capture: ", res.body) @@ -340,7 +340,7 @@ after capture: hello foo --- config location /lua { access_by_lua ' - local function f() + function f() ngx.say("before capture") local res = ngx.location.capture("/proxy?foo") ngx.say("after capture: ", res.body) @@ -395,13 +395,13 @@ capture: hello bar --- config location /lua { access_by_lua ' - local function f() + function f() ngx.say("f: before capture") local res = ngx.location.capture("/proxy?foo") ngx.say("f: after capture: ", res.body) end - local function g() + function g() ngx.say("g: before capture") local res = ngx.location.capture("/proxy?bah") ngx.say("g: after capture: ", res.body) @@ -473,8 +473,7 @@ g: after capture: hello bah --- config location /lua { access_by_lua ' - local g - local function f() + function f() ngx.say("before g") ngx.thread.spawn(g) ngx.say("after g") @@ -520,8 +519,7 @@ after g --- config location /lua { access_by_lua ' - local g - local function f() + function f() ngx.say("before g") ngx.thread.spawn(g) ngx.say("after g") @@ -569,7 +567,7 @@ hello in g() location /lua { access_by_lua ' local co - local function f() + function f() co = coroutine.running() ngx.sleep(0.1) end @@ -602,7 +600,7 @@ status: running location /lua { access_by_lua ' local co - local function f() + function f() co = coroutine.running() end @@ -634,8 +632,7 @@ status: zombie location /lua { access_by_lua ' local co - local g - local function f() + function f() co = coroutine.running() local co2 = coroutine.create(g) coroutine.resume(co2) @@ -674,8 +671,7 @@ status: normal --- config location /lua { access_by_lua ' - local g - local function f() + function f() ngx.say("before g") ngx.thread.spawn(g) ngx.say("after g") @@ -722,7 +718,7 @@ after f access_by_lua ' local yield = coroutine.yield - local function f() + function f() local self = coroutine.running() ngx.say("f 1") yield(self) @@ -775,7 +771,7 @@ f 3 access_by_lua ' local yield = coroutine.yield - local function f() + function f() local self = coroutine.running() ngx.say("f 1") yield(self) @@ -784,7 +780,7 @@ f 3 ngx.say("f 3") end - local function g() + function g() local self = coroutine.running() ngx.say("g 1") yield(self) @@ -831,7 +827,7 @@ g 3 --- config location /lua { access_by_lua ' - local function f() + function f() ngx.say("hello in thread") coroutine.yield(coroutine.running) ngx.flush(true) @@ -868,12 +864,12 @@ after --- config location /lua { access_by_lua ' - local function f() + function f() ngx.say("hello from f") ngx.flush(true) end - local function g() + function g() ngx.say("hello from g") ngx.flush(true) end @@ -919,7 +915,7 @@ hello from g --- config location /lua { access_by_lua ' - local function f() + function f() local sock = ngx.socket.tcp() local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_MEMCACHED_PORT) if not ok then @@ -971,7 +967,7 @@ received: OK --- config location /lua { access_by_lua ' - local function f() + function f() local sock = ngx.socket.udp() local ok, err = sock:setpeername("127.0.0.1", 12345) local bytes, err = sock:send("blah") @@ -1032,7 +1028,7 @@ after)$ --- config location /lua { access_by_lua ' - local function f() + function f() ngx.req.read_body() local body = ngx.req.get_body_data() ngx.say("body: ", body) @@ -1077,7 +1073,7 @@ body: hello world)$ --- config location /lua { access_by_lua ' - local function f() + function f() local sock = ngx.req.socket() local body, err = sock:receive(11) if not body then diff --git a/debian/modules/http-lua/t/025-codecache.t b/debian/modules/http-lua/t/025-codecache.t index 22b78b2..20791d7 100644 --- a/debian/modules/http-lua/t/025-codecache.t +++ b/debian/modules/http-lua/t/025-codecache.t @@ -4,7 +4,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * 163; +plan tests => repeat_each() * 155; #$ENV{LUA_PATH} = $ENV{HOME} . '/work/JSON4Lua-0.9.30/json/?.lua'; @@ -27,7 +27,7 @@ __DATA__ location /update { content_by_lua ' -- os.execute("(echo HERE; pwd) > /dev/stderr") - local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/test.lua", "w")) + local f = assert(io.open("t/servroot/html/test.lua", "w")) f:write("ngx.say(101)") f:close() ngx.say("updated") @@ -61,7 +61,7 @@ updated location /update { content_by_lua ' -- os.execute("(echo HERE; pwd) > /dev/stderr") - local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/test.lua", "w")) + local f = assert(io.open("t/servroot/html/test.lua", "w")) f:write("ngx.say(101)") f:close() ngx.say("updated") @@ -95,7 +95,7 @@ updated location /update { content_by_lua ' -- os.execute("(echo HERE; pwd) > /dev/stderr") - local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/test.lua", "w")) + local f = assert(io.open("t/servroot/html/test.lua", "w")) f:write("ngx.say(101)") f:close() ngx.say("updated") @@ -130,7 +130,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ location /update { content_by_lua ' -- os.execute("(echo HERE; pwd) > /dev/stderr") - local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/test.lua", "w")) + local f = assert(io.open("t/servroot/html/test.lua", "w")) f:write("ngx.say(101)") f:close() ngx.say("updated") @@ -166,7 +166,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ location /update { content_by_lua ' -- os.execute("(echo HERE; pwd) > /dev/stderr") - local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/test.lua", "w")) + local f = assert(io.open("t/servroot/html/test.lua", "w")) f:write("ngx.say(101)") f:close() ngx.say("updated") @@ -193,7 +193,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ === TEST 6: code cache explicitly off (affects require) + content_by_lua --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location /lua { lua_code_cache off; @@ -204,7 +204,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ location /update { content_by_lua ' -- os.execute("(echo HERE; pwd) > /dev/stderr") - local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/foo.lua", "w")) + local f = assert(io.open("t/servroot/html/foo.lua", "w")) f:write("module(..., package.seeall); ngx.say(102);") f:close() ngx.say("updated") @@ -231,7 +231,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ === TEST 7: code cache explicitly off (affects require) + content_by_lua_file --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location /lua { lua_code_cache off; @@ -240,7 +240,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ location /update { content_by_lua ' -- os.execute("(echo HERE; pwd) > /dev/stderr") - local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/foo.lua", "w")) + local f = assert(io.open("t/servroot/html/foo.lua", "w")) f:write("module(..., package.seeall); ngx.say(102);") f:close() ngx.say("updated") @@ -269,7 +269,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ === TEST 8: code cache explicitly off (affects require) + set_by_lua_file --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location /lua { lua_code_cache off; @@ -279,7 +279,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ location /update { content_by_lua ' -- os.execute("(echo HERE; pwd) > /dev/stderr") - local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/foo.lua", "w")) + local f = assert(io.open("t/servroot/html/foo.lua", "w")) f:write("module(..., package.seeall); return 102;") f:close() ngx.say("updated") @@ -308,7 +308,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ === TEST 9: code cache explicitly on (affects require) + set_by_lua_file --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location /lua { lua_code_cache on; @@ -318,7 +318,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ location /update { content_by_lua ' -- os.execute("(echo HERE; pwd) > /dev/stderr") - local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/foo.lua", "w")) + local f = assert(io.open("t/servroot/html/foo.lua", "w")) f:write("module(..., package.seeall); return 102;") f:close() ngx.say("updated") @@ -355,7 +355,7 @@ updated location /update { content_by_lua ' -- os.execute("(echo HERE; pwd) > /dev/stderr") - local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/test.lua", "w")) + local f = assert(io.open("t/servroot/html/test.lua", "w")) f:write("return 101") f:close() ngx.say("updated") @@ -390,7 +390,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ location /update { content_by_lua ' -- os.execute("(echo HERE; pwd) > /dev/stderr") - local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/test.lua", "w")) + local f = assert(io.open("t/servroot/html/test.lua", "w")) f:write("return 101") f:close() ngx.say("updated") @@ -468,7 +468,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ === TEST 14: no clear builtin lib "string" --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config lua_code_cache off; location /lua { @@ -504,7 +504,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ === TEST 15: do not skip luarocks --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;'; + "lua_package_path '$::HtmlDir/?.lua;./?.lua'; lua_code_cache off;" --- config location /main { @@ -554,7 +554,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ === TEST 16: do not skip luarocks* --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;'; + "lua_package_path '$::HtmlDir/?.lua;./?.lua'; lua_code_cache off;" --- config location /main { @@ -604,7 +604,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ === TEST 17: clear _G table --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config lua_code_cache off; location /t { @@ -1050,7 +1050,7 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/, === TEST 29: cosocket connection pool timeout (after Lua VM destroys) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config lua_code_cache off; location = /t { @@ -1118,7 +1118,7 @@ qr/\blua tcp socket keepalive: free connection pool [0-9A-F]+ for "127.0.0.1:/, === TEST 30: cosocket connection pool timeout (before Lua VM destroys) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config lua_code_cache off; location = /t { @@ -1244,133 +1244,3 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/, "decrementing the reference count for Lua VM: 1", "lua close the global Lua VM", ] - - - -=== TEST 32: make sure inline code keys are correct -GitHub issue #1428 ---- config -include ../html/a/proxy.conf; -include ../html/b/proxy.conf; -include ../html/c/proxy.conf; - -location /t { - echo_location /a/; - echo_location /b/; - echo_location /a/; - echo_location /c/; -} - ---- user_files ->>> a/proxy.conf -location /a/ { - content_by_lua_block { ngx.say("/a/ is called") } -} - ->>> b/proxy.conf -location /b/ { - content_by_lua_block { ngx.say("/b/ is called") } -} - ->>> c/proxy.conf -location /c/ { - content_by_lua_block { ngx.say("/b/ is called") } -} - ---- request -GET /t ---- response_body -/a/ is called -/b/ is called -/a/ is called -/b/ is called ---- grep_error_log eval: qr/looking up Lua code cache with key '.*?'/ ---- grep_error_log_out eval -[ -"looking up Lua code cache with key '=content_by_lua(proxy.conf:2)nhli_3c7137b8371d10bc148c8f8bb3042ee6' -looking up Lua code cache with key '=content_by_lua(proxy.conf:2)nhli_1dfe09105792ef65c8d576cc486d5e04' -looking up Lua code cache with key '=content_by_lua(proxy.conf:2)nhli_3c7137b8371d10bc148c8f8bb3042ee6' -looking up Lua code cache with key '=content_by_lua(proxy.conf:2)nhli_1dfe09105792ef65c8d576cc486d5e04' -", -"looking up Lua code cache with key '=content_by_lua(proxy.conf:2)nhli_3c7137b8371d10bc148c8f8bb3042ee6' -looking up Lua code cache with key '=content_by_lua(proxy.conf:2)nhli_1dfe09105792ef65c8d576cc486d5e04' -looking up Lua code cache with key '=content_by_lua(proxy.conf:2)nhli_3c7137b8371d10bc148c8f8bb3042ee6' -looking up Lua code cache with key '=content_by_lua(proxy.conf:2)nhli_1dfe09105792ef65c8d576cc486d5e04' -looking up Lua code cache with key '=content_by_lua(proxy.conf:2)nhli_3c7137b8371d10bc148c8f8bb3042ee6' -looking up Lua code cache with key '=content_by_lua(proxy.conf:2)nhli_1dfe09105792ef65c8d576cc486d5e04' -looking up Lua code cache with key '=content_by_lua(proxy.conf:2)nhli_3c7137b8371d10bc148c8f8bb3042ee6' -looking up Lua code cache with key '=content_by_lua(proxy.conf:2)nhli_1dfe09105792ef65c8d576cc486d5e04' -"] ---- log_level: debug ---- no_error_log -[error] - - - -=== TEST 33: make sure Lua code file keys are correct -GitHub issue #1428 ---- config -include ../html/a/proxy.conf; -include ../html/b/proxy.conf; -include ../html/c/proxy.conf; - -location /t { - echo_location /a/; - echo_location /b/; - echo_location /a/; - echo_location /c/; -} - ---- user_files ->>> a.lua -ngx.say("/a/ is called") - ->>> b.lua -ngx.say("/b/ is called") - ->>> c.lua -ngx.say("/b/ is called") - ->>> a/proxy.conf -location /a/ { - content_by_lua_file html/a.lua; -} - ->>> b/proxy.conf -location /b/ { - content_by_lua_file html/b.lua; -} - ->>> c/proxy.conf -location /c/ { - content_by_lua_file html/c.lua; -} - ---- request -GET /t ---- response_body -/a/ is called -/b/ is called -/a/ is called -/b/ is called ---- grep_error_log eval: qr/looking up Lua code cache with key '.*?'/ ---- grep_error_log_out eval -[ -"looking up Lua code cache with key 'nhlf_48a9a7def61143c003a7de1644e026e4' -looking up Lua code cache with key 'nhlf_68f5f4e946c3efd1cc206452b807e8b6' -looking up Lua code cache with key 'nhlf_48a9a7def61143c003a7de1644e026e4' -looking up Lua code cache with key 'nhlf_042c9b3a136fbacbbd0e4b9ad10896b7' -", -"looking up Lua code cache with key 'nhlf_48a9a7def61143c003a7de1644e026e4' -looking up Lua code cache with key 'nhlf_68f5f4e946c3efd1cc206452b807e8b6' -looking up Lua code cache with key 'nhlf_48a9a7def61143c003a7de1644e026e4' -looking up Lua code cache with key 'nhlf_042c9b3a136fbacbbd0e4b9ad10896b7' -looking up Lua code cache with key 'nhlf_48a9a7def61143c003a7de1644e026e4' -looking up Lua code cache with key 'nhlf_68f5f4e946c3efd1cc206452b807e8b6' -looking up Lua code cache with key 'nhlf_48a9a7def61143c003a7de1644e026e4' -looking up Lua code cache with key 'nhlf_042c9b3a136fbacbbd0e4b9ad10896b7' -" -] ---- log_level: debug ---- no_error_log -[error] diff --git a/debian/modules/http-lua/t/027-multi-capture.t b/debian/modules/http-lua/t/027-multi-capture.t index 9299561..9227fe5 100644 --- a/debian/modules/http-lua/t/027-multi-capture.t +++ b/debian/modules/http-lua/t/027-multi-capture.t @@ -151,7 +151,7 @@ res2.body = b location /main { content_by_lua ' - local res = ngx.location.capture("/foo?n=1") + res = ngx.location.capture("/foo?n=1") ngx.say("top res.status = " .. res.status) ngx.say("top res.body = [" .. res.body .. "]") '; @@ -743,7 +743,7 @@ proxy_cache_path conf/cache levels=1:2 keys_zone=STATIC:10m inactive=10m max_siz location = /proxy { proxy_cache STATIC; - proxy_pass http://127.0.0.2:12345; + proxy_pass http://agentzh.org:12345; proxy_cache_key $proxy_host$uri$args; proxy_cache_valid any 1s; #proxy_http_version 1.1; diff --git a/debian/modules/http-lua/t/028-req-header.t b/debian/modules/http-lua/t/028-req-header.t index 8ddbb29..ca92daa 100644 --- a/debian/modules/http-lua/t/028-req-header.t +++ b/debian/modules/http-lua/t/028-req-header.t @@ -8,7 +8,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * (2 * blocks() + 44); +plan tests => repeat_each() * (2 * blocks() + 43); #no_diff(); no_long_string(); @@ -2008,25 +2008,3 @@ found 3 headers. --- no_error_log lua exceeding request header limit [error] - - - -=== TEST 61: setting Host header clears cached $host variable ---- config - location /req-header { - # this makes $host indexed and cacheable - set $foo $host; - - content_by_lua_block { - ngx.say(ngx.var.host) - ngx.req.set_header("Host", "new"); - ngx.say(ngx.var.host) - } - } ---- request -GET /req-header ---- response_body -localhost -new ---- no_error_log -[error] diff --git a/debian/modules/http-lua/t/030-uri-args.t b/debian/modules/http-lua/t/030-uri-args.t index 7af63c4..a9d46ff 100644 --- a/debian/modules/http-lua/t/030-uri-args.t +++ b/debian/modules/http-lua/t/030-uri-args.t @@ -421,7 +421,7 @@ done ngx.req.set_uri_args("hello") ngx.req.set_uri("/bar", true); '; - proxy_pass http://127.0.0.2:12345; + proxy_pass http://agentzh.org:12345; } --- request GET /foo?world @@ -568,7 +568,7 @@ HTTP/1.0 ca%20t=%25 ngx.req.set_uri("/bar", true); ngx.exit(503) '; - proxy_pass http://127.0.0.2:12345; + proxy_pass http://agentzh.org:12345; } --- request GET /foo?world @@ -586,7 +586,7 @@ hello #set $args 'hello'; set $err ''; access_by_lua ' - local res, err = pcall(ngx.req.set_uri, "/bar", true); + res, err = pcall(ngx.req.set_uri, "/bar", true); ngx.var.err = err '; echo "err: $err"; @@ -626,7 +626,7 @@ uri: /bar location /foo { #set $args 'hello'; content_by_lua ' - local res, err = pcall(ngx.req.set_uri, "/bar", true); + res, err = pcall(ngx.req.set_uri, "/bar", true); ngx.say("err: ", err) '; } @@ -665,7 +665,7 @@ uri: /bar location /foo { #set $args 'hello'; set_by_lua $err ' - local res, err = pcall(ngx.req.set_uri, "/bar", true); + res, err = pcall(ngx.req.set_uri, "/bar", true); return err '; echo "err: $err"; @@ -788,7 +788,7 @@ GET /lua location /lua { content_by_lua ' local t = {bar = ngx.shared.dogs, foo = 3} - local rc, err = pcall(ngx.encode_args, t) + rc, err = pcall(ngx.encode_args, t) ngx.say("rc: ", rc, ", err: ", err) '; } @@ -1112,7 +1112,6 @@ HTTP/1.0 a=3&b=5&b=6 --- config location /lua { content_by_lua ' - local err local args = "a=bar&b=foo" args, err = ngx.decode_args(args) @@ -1136,7 +1135,6 @@ b = foo --- config location /lua { content_by_lua ' - local err local args = "a=bar&b=foo&a=baz" args, err = ngx.decode_args(args) @@ -1160,7 +1158,6 @@ b = foo --- config location /lua { content_by_lua ' - local err local args = "" args, err = ngx.decode_args(args) if err then @@ -1181,7 +1178,6 @@ n = 0 --- config location /lua { content_by_lua ' - local err local args = "a&b" args, err = ngx.decode_args(args) if err then @@ -1204,7 +1200,6 @@ b = true --- config location /lua { content_by_lua ' - local err local args = "a=&b=" args, err = ngx.decode_args(args) @@ -1228,7 +1223,6 @@ b = --- config location /lua { content_by_lua ' - local err local args = "a=bar&b=foo" args, err = ngx.decode_args(args, 1) if err then @@ -1252,7 +1246,6 @@ b = nil --- config location /lua { content_by_lua ' - local err local args = "a=bar&b=foo" args, err = ngx.decode_args(args, -1) @@ -1277,7 +1270,7 @@ b = foo location /lua { content_by_lua ' local s = "f+f=bar&B=foo" - local args, err = ngx.decode_args(s) + args, err = ngx.decode_args(s) if err then ngx.say("err: ", err) end @@ -1309,7 +1302,7 @@ s = f+f=bar&B=foo lua_need_request_body on; location /t { content_by_lua ' - local function split(s, delimiter) + function split(s, delimiter) local result = {} local from = 1 local delim_from, delim_to = string.find(s, delimiter, from) diff --git a/debian/modules/http-lua/t/034-match.t b/debian/modules/http-lua/t/034-match.t index 473a11f..ebe5762 100644 --- a/debian/modules/http-lua/t/034-match.t +++ b/debian/modules/http-lua/t/034-match.t @@ -21,7 +21,7 @@ __DATA__ --- config location /re { content_by_lua ' - local m = ngx.re.match("hello, 1234", "([0-9]+)") + m = ngx.re.match("hello, 1234", "([0-9]+)") if m then ngx.say(m[0]) else @@ -40,7 +40,7 @@ __DATA__ --- config location /re { content_by_lua ' - local m = ngx.re.match("hello, 1234", "(\\\\d+)") + m = ngx.re.match("hello, 1234", "(\\\\d+)") if m then ngx.say(m[0]) else @@ -59,7 +59,7 @@ __DATA__ --- config location /re { content_by_lua ' - local m = ngx.re.match("hello, 1234", "(\\d+)") + m = ngx.re.match("hello, 1234", "(\\d+)") if m then ngx.say(m[0]) else @@ -80,7 +80,7 @@ __DATA__ --- config location /re { content_by_lua ' - local m = ngx.re.match("hello, 1234", "[[\\d+]]") + m = ngx.re.match("hello, 1234", "[[\\d+]]") if m then ngx.say(m[0]) else @@ -101,7 +101,7 @@ __DATA__ --- config location /re { content_by_lua ' - local m = ngx.re.match("hello, 1234", "([0-9]{2})[0-9]+") + m = ngx.re.match("hello, 1234", "([0-9]{2})[0-9]+") if m then ngx.say(m[0]) ngx.say(m[1]) @@ -122,7 +122,7 @@ __DATA__ --- config location /re { content_by_lua ' - local m = ngx.re.match("hello, 1234", "([a-z]+).*?([0-9]{2})[0-9]+", "") + m = ngx.re.match("hello, 1234", "([a-z]+).*?([0-9]{2})[0-9]+", "") if m then ngx.say(m[0]) ngx.say(m[1]) @@ -145,7 +145,7 @@ hello --- config location /re { content_by_lua ' - local m = ngx.re.match("hello, 1234", "([a-z]+).*?([0-9]{2})[0-9]+", "o") + m = ngx.re.match("hello, 1234", "([a-z]+).*?([0-9]{2})[0-9]+", "o") if m then ngx.say(m[0]) ngx.say(m[1]) @@ -168,7 +168,7 @@ hello --- config location /re { content_by_lua ' - local m = ngx.re.match("hello, 1234", "foo") + m = ngx.re.match("hello, 1234", "foo") if m then ngx.say(m[0]) else @@ -187,7 +187,7 @@ not matched: nil --- config location /re { content_by_lua ' - local m = ngx.re.match("hello, 1234", "HELLO") + m = ngx.re.match("hello, 1234", "HELLO") if m then ngx.say(m[0]) else @@ -206,7 +206,7 @@ not matched: nil --- config location /re { content_by_lua ' - local m = ngx.re.match("hello, 1234", "HELLO", "i") + m = ngx.re.match("hello, 1234", "HELLO", "i") if m then ngx.say(m[0]) else @@ -225,7 +225,7 @@ hello --- config location /re { content_by_lua ' - local rc, err = pcall(ngx.re.match, "hello章亦春", "HELLO.{2}", "iu") + rc, err = pcall(ngx.re.match, "hello章亦春", "HELLO.{2}", "iu") if not rc then ngx.say("FAIL: ", err) return @@ -249,7 +249,7 @@ hello --- config location /re { content_by_lua ' - local m = ngx.re.match("hello\\nworld", "^world", "m") + m = ngx.re.match("hello\\nworld", "^world", "m") if m then ngx.say(m[0]) else @@ -268,7 +268,7 @@ world --- config location /re { content_by_lua ' - local m = ngx.re.match("hello\\nworld", ".*", "m") + m = ngx.re.match("hello\\nworld", ".*", "m") if m then ngx.say(m[0]) else @@ -287,7 +287,7 @@ hello --- config location /re { content_by_lua ' - local m = ngx.re.match("hello\\nworld", "^world", "s") + m = ngx.re.match("hello\\nworld", "^world", "s") if m then ngx.say(m[0]) else @@ -306,7 +306,7 @@ not matched: nil --- config location /re { content_by_lua ' - local m = ngx.re.match("hello\\nworld", ".*", "s") + m = ngx.re.match("hello\\nworld", ".*", "s") if m then ngx.say(m[0]) else @@ -326,7 +326,7 @@ world --- config location /re { content_by_lua ' - local m = ngx.re.match("hello\\nworld", "\\\\w \\\\w", "x") + m = ngx.re.match("hello\\nworld", "\\\\w \\\\w", "x") if m then ngx.say(m[0]) else @@ -372,7 +372,7 @@ error: pcre_compile() failed: missing ) in "(abc" --- config location /re { content_by_lua ' - local rc, m = pcall(ngx.re.match, "hello\\nworld", ".*", "Hm") + rc, m = pcall(ngx.re.match, "hello\\nworld", ".*", "Hm") if rc then if m then ngx.say(m[0]) @@ -395,7 +395,7 @@ error: .*?unknown flag "H" \(flags "Hm"\) --- config location /re { content_by_lua ' - local m = ngx.re.match("hello, world", "(world)|(hello)", "x") + m = ngx.re.match("hello, world", "(world)|(hello)", "x") if m then ngx.say(m[0]) ngx.say(m[1]) @@ -418,7 +418,7 @@ hello --- config location /re { content_by_lua ' - local m = ngx.re.match("hello, 1234", "([0-9]+)(h?)") + m = ngx.re.match("hello, 1234", "([0-9]+)(h?)") if m then ngx.say(m[0]) ngx.say(m[1]) @@ -442,7 +442,7 @@ hello --- config location /re { content_by_lua ' - local m = ngx.re.match("hello, 1234", "([0-9]+)", "a") + m = ngx.re.match("hello, 1234", "([0-9]+)", "a") if m then ngx.say(m[0]) else @@ -461,7 +461,7 @@ not matched! --- config location /re { content_by_lua ' - local m = ngx.re.match("1234, hello", "([0-9]+)", "a") + m = ngx.re.match("1234, hello", "([0-9]+)", "a") if m then ngx.say(m[0]) else @@ -481,7 +481,7 @@ not matched! location /re { content_by_lua ' local ctx = {} - local m = ngx.re.match("1234, hello", "([0-9]+)", "", ctx) + m = ngx.re.match("1234, hello", "([0-9]+)", "", ctx) if m then ngx.say(m[0]) ngx.say(ctx.pos) @@ -504,7 +504,7 @@ not matched! location /re { content_by_lua ' local ctx = { pos = 3 } - local m = ngx.re.match("1234, hello", "([0-9]+)", "", ctx) + m = ngx.re.match("1234, hello", "([0-9]+)", "", ctx) if m then ngx.say(m[0]) ngx.say(ctx.pos) @@ -526,7 +526,7 @@ not matched! --- config location /re { set_by_lua $res ' - local m = ngx.re.match("hello, 1234", "([0-9]+)") + m = ngx.re.match("hello, 1234", "([0-9]+)") if m then return m[0] else @@ -569,7 +569,7 @@ baz } --- user_files >>> a.lua -local m = ngx.re.match("hello, 1234", "(\\\s+)") +m = ngx.re.match("hello, 1234", "(\\\s+)") if m then ngx.say("[", m[0], "]") else @@ -595,7 +595,7 @@ end local uri = "2" local regex = '(?:>[\\w\\s]*)'; ngx.say("regex: ", regex) -local m = ngx.re.match(uri, regex, "oi") +m = ngx.re.match(uri, regex, "oi") if m then ngx.say("[", m[0], "]") else @@ -613,7 +613,7 @@ regex: (?:>[\w\s]*) --- config location /re { content_by_lua ' - local m = ngx.re.match("hello, 1234", [[\\d+]]) + m = ngx.re.match("hello, 1234", [[\\d+]]) if m then ngx.say(m[0]) else @@ -660,7 +660,7 @@ error: pcre_compile() failed: missing ) in "([0-9]+" --- config location /re { content_by_lua ' - local m = ngx.re.match("hello, 1234", [[([0-9]+)]]) + m = ngx.re.match("hello, 1234", [[([0-9]+)]]) if m then ngx.say(m[0]) else @@ -1027,7 +1027,7 @@ exec opts: 0 >>> a.lua local re = [==[(?i:([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:=|<=>|r?like|sounds\s+like|regexp)([\s'\"`´’‘\(\)]*)?\2|([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp)([\s'\"`´’‘\(\)]*)?(?!\6)([\d\w]+))]==] -local s = string.rep([[ABCDEFG]], 10) +s = string.rep([[ABCDEFG]], 10) local start = ngx.now() @@ -1067,7 +1067,7 @@ error: pcre_exec() failed: -8 >>> a.lua local re = [==[(?i:([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:=|<=>|r?like|sounds\s+like|regexp)([\s'\"`´’‘\(\)]*)?\2|([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp)([\s'\"`´’‘\(\)]*)?(?!\6)([\d\w]+))]==] -local s = string.rep([[ABCDEFG]], 10) +s = string.rep([[ABCDEFG]], 10) local start = ngx.now() @@ -1101,7 +1101,7 @@ failed to match content_by_lua ' local res = {} local s = "hello, 1234" - local m = ngx.re.match(s, [[(\\d)(\\d)]], "o", nil, res) + m = ngx.re.match(s, [[(\\d)(\\d)]], "o", nil, res) if m then ngx.say("1: m size: ", #m) ngx.say("1: res size: ", #res) @@ -1132,12 +1132,11 @@ failed to match === TEST 48: init_by_lua --- http_config init_by_lua ' - package.loaded.m = ngx.re.match("hello, 1234", "(\\\\d+)") + m = ngx.re.match("hello, 1234", "(\\\\d+)") '; --- config location /re { content_by_lua ' - local m = package.loaded.m if m then ngx.say(m[0]) else diff --git a/debian/modules/http-lua/t/035-gmatch.t b/debian/modules/http-lua/t/035-gmatch.t index 0dfeaea..0426997 100644 --- a/debian/modules/http-lua/t/035-gmatch.t +++ b/debian/modules/http-lua/t/035-gmatch.t @@ -123,7 +123,7 @@ nil --- config location /re { content_by_lua ' - local it = ngx.re.gmatch("hello, 1234", "([0-9]+)", "a") + it = ngx.re.gmatch("hello, 1234", "([0-9]+)", "a") ngx.say(it()) '; } @@ -418,7 +418,7 @@ hello content_by_lua ' local a = {} for i = 1, 3 do - local it = ngx.re.gmatch("hello, world", "[a-z]+") + it = ngx.re.gmatch("hello, world", "[a-z]+") it() collectgarbage() table.insert(a, {"hello", "world"}) @@ -482,9 +482,9 @@ end GET /main --- response_body matched -matched ---- no_error_log -[error] +sr failed: 500 +--- error_log +attempt to use ngx.re.gmatch iterator in a request that did not create it @@ -518,7 +518,7 @@ matched: [] location /re { content_by_lua ' local it = ngx.re.gmatch("1234, 1234", "(?[0-9]+)") - local m = it() + m = it() if m then ngx.say(m[0]) ngx.say(m[1]) @@ -555,7 +555,7 @@ matched: [] content_by_lua ' local it = ngx.re.gmatch("1234, abcd, 1234", "(?[0-9]+)|(?[a-z]+)") - local m = it() + m = it() if m then ngx.say(m[0]) ngx.say(m[1]) @@ -599,7 +599,7 @@ abcd location /re { content_by_lua ' local it = ngx.re.gmatch("hello, 1234", "(?[a-z]+), (?[0-9]+)", "D") - local m = it() + m = it() if m then ngx.say(m[0]) ngx.say(m[1]) @@ -825,7 +825,7 @@ exec opts: 0 >>> a.lua local re = [==[(?i:([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:=|<=>|r?like|sounds\s+like|regexp)([\s'\"`´’‘\(\)]*)?\2|([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp)([\s'\"`´’‘\(\)]*)?(?!\6)([\d\w]+))]==] -local s = string.rep([[ABCDEFG]], 10) +s = string.rep([[ABCDEFG]], 10) local start = ngx.now() @@ -871,7 +871,7 @@ error: pcre_exec() failed: -8 >>> a.lua local re = [==[(?i:([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:=|<=>|r?like|sounds\s+like|regexp)([\s'\"`´’‘\(\)]*)?\2|([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp)([\s'\"`´’‘\(\)]*)?(?!\6)([\d\w]+))]==] -local s = string.rep([[ABCDEFG]], 10) +s = string.rep([[ABCDEFG]], 10) local start = ngx.now() @@ -881,7 +881,7 @@ if not it then return end -local res, err = it() +res, err = it() --[[ ngx.update_time() diff --git a/debian/modules/http-lua/t/036-sub.t b/debian/modules/http-lua/t/036-sub.t index 3e88eba..2b4b075 100644 --- a/debian/modules/http-lua/t/036-sub.t +++ b/debian/modules/http-lua/t/036-sub.t @@ -590,7 +590,7 @@ s: a好 >>> a.lua local re = [==[(?i:([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:=|<=>|r?like|sounds\s+like|regexp)([\s'\"`´’‘\(\)]*)?\2|([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp)([\s'\"`´’‘\(\)]*)?(?!\6)([\d\w]+))]==] -local s = string.rep([[ABCDEFG]], 10) +s = string.rep([[ABCDEFG]], 10) local start = ngx.now() @@ -693,7 +693,7 @@ ab.cd location = /t { content_by_lua ' - local function test() + function test() local data = [[ OUTER {FIRST} ]] diff --git a/debian/modules/http-lua/t/037-gsub.t b/debian/modules/http-lua/t/037-gsub.t index 41f86ac..4c5810d 100644 --- a/debian/modules/http-lua/t/037-gsub.t +++ b/debian/modules/http-lua/t/037-gsub.t @@ -511,7 +511,7 @@ s: aa >>> a.lua local re = [==[(?i:([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:=|<=>|r?like|sounds\s+like|regexp)([\s'\"`´’‘\(\)]*)?\2|([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp)([\s'\"`´’‘\(\)]*)?(?!\6)([\d\w]+))]==] -local s = string.rep([[ABCDEFG]], 10) +s = string.rep([[ABCDEFG]], 10) local start = ngx.now() diff --git a/debian/modules/http-lua/t/038-match-o.t b/debian/modules/http-lua/t/038-match-o.t index f6ae010..d61ff1f 100644 --- a/debian/modules/http-lua/t/038-match-o.t +++ b/debian/modules/http-lua/t/038-match-o.t @@ -20,7 +20,7 @@ __DATA__ --- config location /re { content_by_lua ' - local m = ngx.re.match("hello, 1234", "([0-9]+)", "o") + m = ngx.re.match("hello, 1234", "([0-9]+)", "o") if m then ngx.say(m[0]) else @@ -39,7 +39,7 @@ __DATA__ --- config location /re { content_by_lua ' - local m = ngx.re.match("hello, 1234", "(\\\\d+)", "o") + m = ngx.re.match("hello, 1234", "(\\\\d+)", "o") if m then ngx.say(m[0]) else @@ -58,7 +58,7 @@ __DATA__ --- config location /re { content_by_lua ' - local m = ngx.re.match("hello, 1234", "(\\d+)", "o") + m = ngx.re.match("hello, 1234", "(\\d+)", "o") if m then ngx.say(m[0]) else @@ -79,7 +79,7 @@ __DATA__ --- config location /re { content_by_lua ' - local m = ngx.re.match("hello, 1234", "[[\\d+]]", "o") + m = ngx.re.match("hello, 1234", "[[\\d+]]", "o") if m then ngx.say(m[0]) else @@ -100,7 +100,7 @@ __DATA__ --- config location /re { content_by_lua ' - local m = ngx.re.match("hello, 1234", "([0-9]{2})[0-9]+", "o") + m = ngx.re.match("hello, 1234", "([0-9]{2})[0-9]+", "o") if m then ngx.say(m[0]) ngx.say(m[1]) @@ -121,7 +121,7 @@ __DATA__ --- config location /re { content_by_lua ' - local m = ngx.re.match("hello, 1234", "([a-z]+).*?([0-9]{2})[0-9]+", "o") + m = ngx.re.match("hello, 1234", "([a-z]+).*?([0-9]{2})[0-9]+", "o") if m then ngx.say(m[0]) ngx.say(m[1]) @@ -144,7 +144,7 @@ hello --- config location /re { content_by_lua ' - local m = ngx.re.match("hello, 1234", "foo", "o") + m = ngx.re.match("hello, 1234", "foo", "o") if m then ngx.say(m[0]) else @@ -163,7 +163,7 @@ not matched: nil --- config location /re { content_by_lua ' - local m = ngx.re.match("hello, 1234", "HELLO", "o") + m = ngx.re.match("hello, 1234", "HELLO", "o") if m then ngx.say(m[0]) else @@ -182,7 +182,7 @@ not matched: nil --- config location /re { content_by_lua ' - local m = ngx.re.match("hello, 1234", "HELLO", "oi") + m = ngx.re.match("hello, 1234", "HELLO", "oi") if m then ngx.say(m[0]) else @@ -224,7 +224,7 @@ this version of PCRE is not compiled with PCRE_UTF8 support|^hello章亦$ --- config location /re { content_by_lua ' - local m = ngx.re.match("hello\\nworld", "^world", "mo") + m = ngx.re.match("hello\\nworld", "^world", "mo") if m then ngx.say(m[0]) else @@ -243,7 +243,7 @@ world --- config location /re { content_by_lua ' - local m = ngx.re.match("hello\\nworld", ".*", "om") + m = ngx.re.match("hello\\nworld", ".*", "om") if m then ngx.say(m[0]) else @@ -262,7 +262,7 @@ hello --- config location /re { content_by_lua ' - local m = ngx.re.match("hello\\nworld", "^world", "so") + m = ngx.re.match("hello\\nworld", "^world", "so") if m then ngx.say(m[0]) else @@ -281,7 +281,7 @@ not matched: nil --- config location /re { content_by_lua ' - local m = ngx.re.match("hello\\nworld", ".*", "os") + m = ngx.re.match("hello\\nworld", ".*", "os") if m then ngx.say(m[0]) else @@ -301,7 +301,7 @@ world --- config location /re { content_by_lua ' - local m = ngx.re.match("hello\\nworld", "\\\\w \\\\w", "xo") + m = ngx.re.match("hello\\nworld", "\\\\w \\\\w", "xo") if m then ngx.say(m[0]) else @@ -347,7 +347,7 @@ error: pcre_compile() failed: missing ) in "(abc" --- config location /re { content_by_lua ' - local rc, m = pcall(ngx.re.match, "hello\\nworld", ".*", "Ho") + rc, m = pcall(ngx.re.match, "hello\\nworld", ".*", "Ho") if rc then if m then ngx.say(m[0]) @@ -370,7 +370,7 @@ error: pcre_compile() failed: missing ) in "(abc" --- config location /re { content_by_lua ' - local m = ngx.re.match("hello, world", "(world)|(hello)", "xo") + m = ngx.re.match("hello, world", "(world)|(hello)", "xo") if m then ngx.say(m[0]) ngx.say(m[1]) @@ -393,7 +393,7 @@ hello --- config location /re { content_by_lua ' - local m = ngx.re.match("hello, 1234", "([0-9]+)(h?)", "o") + m = ngx.re.match("hello, 1234", "([0-9]+)(h?)", "o") if m then ngx.say(m[0]) ngx.say(m[1]) @@ -417,7 +417,7 @@ hello --- config location /re { content_by_lua ' - local m = ngx.re.match("hello, 1234", "([0-9]+)", "oa") + m = ngx.re.match("hello, 1234", "([0-9]+)", "oa") if m then ngx.say(m[0]) else @@ -436,7 +436,7 @@ not matched! --- config location /re { content_by_lua ' - local m = ngx.re.match("1234, hello", "([0-9]+)", "ao") + m = ngx.re.match("1234, hello", "([0-9]+)", "ao") if m then ngx.say(m[0]) else @@ -456,7 +456,7 @@ not matched! location /re { content_by_lua ' local ctx = {} - local m = ngx.re.match("1234, hello", "([0-9]+)", "o", ctx) + m = ngx.re.match("1234, hello", "([0-9]+)", "o", ctx) if m then ngx.say(m[0]) ngx.say(ctx.pos) @@ -479,7 +479,7 @@ not matched! location /re { content_by_lua ' local ctx = { pos = 3 } - local m = ngx.re.match("1234, hello", "([0-9]+)", "o", ctx) + m = ngx.re.match("1234, hello", "([0-9]+)", "o", ctx) if m then ngx.say(m[0]) ngx.say(ctx.pos) @@ -501,7 +501,7 @@ not matched! --- config location /re { set_by_lua $res ' - local m = ngx.re.match("hello, 1234", "([0-9]+)", "o") + m = ngx.re.match("hello, 1234", "([0-9]+)", "o") if m then return m[0] else diff --git a/debian/modules/http-lua/t/041-header-filter.t b/debian/modules/http-lua/t/041-header-filter.t index 0adc699..7d8ee74 100644 --- a/debian/modules/http-lua/t/041-header-filter.t +++ b/debian/modules/http-lua/t/041-header-filter.t @@ -10,7 +10,7 @@ log_level('debug'); repeat_each(2); -plan tests => repeat_each() * (blocks() * 2 + 13); +plan tests => repeat_each() * 94; #no_diff(); #no_long_string(); @@ -416,7 +416,7 @@ lua release ngx.ctx -=== TEST 20: globals are shared by all requests +=== TEST 20: global got cleared for each single request --- config location /lua { set $foo ''; @@ -428,7 +428,6 @@ lua release ngx.ctx if not foo then foo = 1 else - ngx.log(ngx.INFO, "old foo: ", foo) foo = foo + 1 end ngx.var.foo = foo @@ -436,13 +435,10 @@ lua release ngx.ctx } --- request GET /lua ---- response_body_like -^[12]$ +--- response_body +1 --- no_error_log [error] ---- grep_error_log eval: qr/old foo: \d+/ ---- grep_error_log_out eval -["", "old foo: 1\n"] @@ -734,8 +730,7 @@ hello world --- config location /t { header_filter_by_lua ' - local bar - local function foo() + function foo() bar() end diff --git a/debian/modules/http-lua/t/043-shdict.t b/debian/modules/http-lua/t/043-shdict.t index b0528e5..9183bf5 100644 --- a/debian/modules/http-lua/t/043-shdict.t +++ b/debian/modules/http-lua/t/043-shdict.t @@ -420,7 +420,7 @@ ngx_slab_alloc() failed: no memory in lua_shared_dict zone ngx.say(dogs:get(key)) key = string.rep("a", 65536) - local ok, err = dogs:set(key, "world") + ok, err = dogs:set(key, "world") if not ok then ngx.say("not ok: ", err) return @@ -2048,7 +2048,7 @@ get_stale ok: false, stale: false ngx.say("get not ok: ", err) return end - local flags = err + flags = err ngx.say("get_stale ok: ", data, ", flags: ", flags, ", stale: ", stale) diff --git a/debian/modules/http-lua/t/047-match-jit.t b/debian/modules/http-lua/t/047-match-jit.t index f53a408..2417a63 100644 --- a/debian/modules/http-lua/t/047-match-jit.t +++ b/debian/modules/http-lua/t/047-match-jit.t @@ -20,7 +20,7 @@ __DATA__ --- config location /re { content_by_lua ' - local m = ngx.re.match("hello, 1234", "([0-9]+)", "j") + m = ngx.re.match("hello, 1234", "([0-9]+)", "j") if m then ngx.say(m[0]) else @@ -41,7 +41,7 @@ pcre JIT compiling result: 1 --- config location /re { content_by_lua ' - local m = ngx.re.match("hello, world", "([0-9]+)", "j") + m = ngx.re.match("hello, world", "([0-9]+)", "j") if m then ngx.say(m[0]) else @@ -62,7 +62,7 @@ pcre JIT compiling result: 1 --- config location /re { content_by_lua ' - local m = ngx.re.match("hello, 1234", "([0-9]+)", "jo") + m = ngx.re.match("hello, 1234", "([0-9]+)", "jo") if m then ngx.say(m[0]) else @@ -87,7 +87,7 @@ qr/pcre JIT compiling result: \d+/ --- config location /re { content_by_lua ' - local m = ngx.re.match("hello, world", "([0-9]+)", "jo") + m = ngx.re.match("hello, world", "([0-9]+)", "jo") if m then ngx.say(m[0]) else @@ -147,7 +147,7 @@ error: pcre_compile() failed: missing ) in "(abc" >>> a.lua local re = [==[(?i:([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:=|<=>|r?like|sounds\s+like|regexp)([\s'\"`´’‘\(\)]*)?\2|([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp)([\s'\"`´’‘\(\)]*)?(?!\6)([\d\w]+))]==] -local s = string.rep([[ABCDEFG]], 21) +s = string.rep([[ABCDEFG]], 21) local start = ngx.now() @@ -187,7 +187,7 @@ error: pcre_exec() failed: -8 >>> a.lua local re = [==[(?i:([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:=|<=>|r?like|sounds\s+like|regexp)([\s'\"`´’‘\(\)]*)?\2|([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp)([\s'\"`´’‘\(\)]*)?(?!\6)([\d\w]+))]==] -local s = string.rep([[ABCDEFG]], 21) +s = string.rep([[ABCDEFG]], 21) local start = ngx.now() diff --git a/debian/modules/http-lua/t/048-match-dfa.t b/debian/modules/http-lua/t/048-match-dfa.t index edf3662..28b5a60 100644 --- a/debian/modules/http-lua/t/048-match-dfa.t +++ b/debian/modules/http-lua/t/048-match-dfa.t @@ -20,7 +20,7 @@ __DATA__ --- config location /re { content_by_lua ' - local m = ngx.re.match("hello", "(he|hell)", "d") + m = ngx.re.match("hello", "(he|hell)", "d") if m then ngx.say(m[0]) ngx.say(m[1]) @@ -43,7 +43,7 @@ nil --- config location /re { content_by_lua ' - local m = ngx.re.match("hello", "(he|hell)", "do") + m = ngx.re.match("hello", "(he|hell)", "do") if m then ngx.say(m[0]) ngx.say(m[1]) @@ -66,7 +66,7 @@ nil --- config location /re { content_by_lua ' - local m = ngx.re.match("hello", "(he|hell)", "jd") + m = ngx.re.match("hello", "(he|hell)", "jd") if m then ngx.say(m[0]) else @@ -85,7 +85,7 @@ hell --- config location /re { content_by_lua ' - local m = ngx.re.match("world", "(he|hell)", "d") + m = ngx.re.match("world", "(he|hell)", "d") if m then ngx.say(m[0]) else @@ -104,7 +104,7 @@ not matched! --- config location /re { content_by_lua ' - local m = ngx.re.match("hello", "he|hell", "do") + m = ngx.re.match("hello", "he|hell", "do") if m then ngx.say(m[0]) ngx.say(m[1]) @@ -127,7 +127,7 @@ nil --- config location /re { content_by_lua ' - local m = ngx.re.match("world", "([0-9]+)", "do") + m = ngx.re.match("world", "([0-9]+)", "do") if m then ngx.say(m[0]) else diff --git a/debian/modules/http-lua/t/055-subreq-vars.t b/debian/modules/http-lua/t/055-subreq-vars.t index 1369992..eb5e24d 100644 --- a/debian/modules/http-lua/t/055-subreq-vars.t +++ b/debian/modules/http-lua/t/055-subreq-vars.t @@ -28,7 +28,7 @@ __DATA__ location /lua { content_by_lua ' - local res = ngx.location.capture("/other", + res = ngx.location.capture("/other", { vars = { dog = "hello", cat = 32 }}); ngx.print(res.body) @@ -82,7 +82,7 @@ qr/variable "(dog|cat)" cannot be assigned a value \(maybe you forgot to define location /lua { set $dog ''; content_by_lua ' - local res = ngx.location.capture("/other", + res = ngx.location.capture("/other", { vars = { dog = "hello", cat = 32 }}); ngx.print(res.body) @@ -110,7 +110,7 @@ variable "cat" cannot be assigned a value (maybe you forgot to define it first?) set $dog ''; set $cat ''; content_by_lua ' - local res = ngx.location.capture("/other", + res = ngx.location.capture("/other", { vars = { dog = "hello", cat = 32 }}); ngx.print(res.body) @@ -137,7 +137,7 @@ cat = 32 set $dog ''; set $cat ''; content_by_lua ' - local res = ngx.location.capture("/other", + res = ngx.location.capture("/other", { vars = "hello" }); ngx.print(res.body) @@ -165,7 +165,7 @@ Bad vars option value set $dog ''; set $cat ''; content_by_lua ' - local res = ngx.location.capture("/other", + res = ngx.location.capture("/other", { vars = { cat = true } }); ngx.print(res.body) @@ -188,7 +188,7 @@ attempt to use bad variable value type boolean location /lua { content_by_lua ' - local res = ngx.location.capture("/other", + res = ngx.location.capture("/other", { vars = { args = "a=hello&b=32" }}); ngx.print(res.body) @@ -234,7 +234,7 @@ variable "query_string" not changeable location /lua { set $dog 'hello'; content_by_lua ' - local res = ngx.location.capture("/other", + res = ngx.location.capture("/other", { copy_all_vars = true }); ngx.print(res.body) @@ -259,7 +259,7 @@ GET /lua location /lua { set $dog 'hello'; content_by_lua ' - local res = ngx.location.capture("/other", + res = ngx.location.capture("/other", { share_all_vars = true }); ngx.print(res.body) @@ -284,7 +284,7 @@ GET /lua location /lua { set $dog 'hello'; content_by_lua ' - local res = ngx.location.capture("/other", + res = ngx.location.capture("/other", { vars = { dog = "hiya" }, copy_all_vars = true }); ngx.print(res.body) diff --git a/debian/modules/http-lua/t/056-flush.t b/debian/modules/http-lua/t/056-flush.t index bdd33d4..6b697a4 100644 --- a/debian/modules/http-lua/t/056-flush.t +++ b/debian/modules/http-lua/t/056-flush.t @@ -317,7 +317,7 @@ lua http 1.0 buffering makes ngx.flush() a no-op --- config location /test { content_by_lua ' - local function f() + function f() ngx.say("hello, world") ngx.flush(true) coroutine.yield() diff --git a/debian/modules/http-lua/t/057-flush-timeout.t b/debian/modules/http-lua/t/057-flush-timeout.t index 1f8cfaa..a046539 100644 --- a/debian/modules/http-lua/t/057-flush-timeout.t +++ b/debian/modules/http-lua/t/057-flush-timeout.t @@ -127,7 +127,7 @@ del timer 1234 send_timeout 200ms; location /lua { content_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) diff --git a/debian/modules/http-lua/t/058-tcp-socket.t b/debian/modules/http-lua/t/058-tcp-socket.t index 837006c..354a876 100644 --- a/debian/modules/http-lua/t/058-tcp-socket.t +++ b/debian/modules/http-lua/t/058-tcp-socket.t @@ -4,7 +4,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * 219; +plan tests => repeat_each() * 199; our $HtmlDir = html_dir; @@ -245,11 +245,11 @@ attempt to send data on a closed socket: --- request GET /t ---- response_body_like +--- response_body connected: 1 request sent: 56 -first line received: HTTP\/1\.1 200 OK -second line received: (?:Date|Server): .*? +first line received: HTTP/1.1 200 OK +second line received: Server: openresty --- no_error_log [error] --- timeout: 10 @@ -298,7 +298,7 @@ qr/connect\(\) failed \(\d+: Connection refused\)/ location /test { content_by_lua ' local sock = ngx.socket.tcp() - local ok, err = sock:connect("127.0.0.2", 12345) + local ok, err = sock:connect("agentzh.org", 12345) ngx.say("connect: ", ok, " ", err) local bytes @@ -321,7 +321,7 @@ send: nil closed receive: nil closed close: nil closed --- error_log -lua tcp socket connect timed out, when connecting to 127.0.0.2:12345 +lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 --- timeout: 10 @@ -914,7 +914,7 @@ close: 1 nil end end - local ok, err = sock:close() + ok, err = sock:close() ngx.say("close: ", ok, " ", err) '; } @@ -961,7 +961,7 @@ close: 1 nil line, err = sock:receive() ngx.say("receive: ", line, " ", err) - local ok, err = sock:close() + ok, err = sock:close() ngx.say("close: ", ok, " ", err) '; } @@ -1057,7 +1057,7 @@ close: 1 nil === TEST 19: cannot survive across request boundary (send) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config server_tokens off; location /t { @@ -1116,7 +1116,7 @@ received: OK|failed to send request: closed)\$" === TEST 20: cannot survive across request boundary (receive) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config server_tokens off; location /t { @@ -1191,7 +1191,7 @@ received: OK|failed to receive a line: closed \[nil\])$/ === TEST 21: cannot survive across request boundary (close) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config server_tokens off; location /t { @@ -1260,7 +1260,7 @@ received: OK|failed to close: closed)$/ === TEST 22: cannot survive across request boundary (connect) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config server_tokens off; location /t { @@ -2611,7 +2611,7 @@ close: 1 nil local ready = false local fatal = false - local function f() + function f() local line, err, part = sock:receive() if not line then ngx.say("failed to receive the 1st line: ", err, " [", part, "]") @@ -2672,7 +2672,7 @@ lua clean up the timer for pending ngx.sleep === TEST 44: bad request tries to connect --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config server_tokens off; location = /main { @@ -2726,7 +2726,7 @@ qr/runtime error: content_by_lua\(nginx\.conf:\d+\):7: bad request/ === TEST 45: bad request tries to receive --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config server_tokens off; location = /main { @@ -2783,7 +2783,7 @@ qr/runtime error: content_by_lua\(nginx\.conf:\d+\):14: bad request/ === TEST 46: bad request tries to send --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config server_tokens off; location = /main { @@ -2840,7 +2840,7 @@ qr/runtime error: content_by_lua\(nginx\.conf:\d+\):14: bad request/ === TEST 47: bad request tries to close --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config server_tokens off; location = /main { @@ -2897,7 +2897,7 @@ qr/runtime error: content_by_lua\(nginx\.conf:\d+\):14: bad request/ === TEST 48: bad request tries to set keepalive --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config server_tokens off; location = /main { @@ -2954,7 +2954,7 @@ qr/runtime error: content_by_lua\(nginx\.conf:\d+\):14: bad request/ === TEST 49: bad request tries to receiveuntil --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config server_tokens off; location = /main { @@ -3315,7 +3315,7 @@ close: 1 nil local thr = ngx.thread.spawn(function () sock = ngx.socket.tcp() - local ok, err = sock:connect("127.0.0.2", 12345) + local ok, err = sock:connect("agentzh.org", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -3464,7 +3464,7 @@ lua http cleanup reuse ngx.say("failed to create timer: ", err) end - local i = 1 + i = 1 while not done do local time = 0.005 * i if time > 0.1 then @@ -3545,7 +3545,7 @@ lua http cleanup reuse ngx.say("failed to create timer: ", err) end - local i = 1 + i = 1 while not done do local time = 0.005 * i if time > 0.1 then @@ -3720,10 +3720,10 @@ sudo iptables -I OUTPUT 1 -p udp --dport 10086 -j REJECT } --- request GET /t ---- response_body_like -failed to connect: www.google.com could not be resolved(?: \(\d+: Operation timed out\))? -failed to connect: www.google.com could not be resolved(?: \(\d+: Operation timed out\))? -failed to connect: www.google.com could not be resolved(?: \(\d+: Operation timed out\))? +--- response_body +failed to connect: www.google.com could not be resolved +failed to connect: www.google.com could not be resolved +failed to connect: www.google.com could not be resolved hello! --- error_log eval qr{\[alert\] .*? send\(\) failed \(\d+: Operation not permitted\) while resolving} @@ -3808,315 +3808,3 @@ received: received: truefalsenil --- no_error_log [error] - - - -=== TEST 64: receiveany method in cosocket ---- config - server_tokens off; - location = /t { - set $port $TEST_NGINX_SERVER_PORT; - content_by_lua_block { - local sock = ngx.socket.tcp() - sock:settimeout(500) - assert(sock:connect("127.0.0.1", ngx.var.port)) - local req = { - 'GET /foo HTTP/1.0\r\n', - 'Host: localhost\r\n', - 'Connection: close\r\n\r\n', - } - local ok, err = sock:send(req) - if not ok then - ngx.say("send request failed: ", err) - return - end - - -- skip http header - while true do - local data, err, _ = sock:receive('*l') - if err then - ngx.say('unexpected error occurs when receiving http head: ', err) - return - end - - if #data == 0 then -- read last line of head - break - end - end - - -- receive http body - while true do - local data, err = sock:receiveany(1024) - if err then - if err ~= 'closed' then - ngx.say('unexpected err: ', err) - end - break - end - ngx.say(data) - end - - sock:close() - } - } - - location = /foo { - content_by_lua_block { - local resp = { - '1', - '22', - 'hello world', - } - - local length = 0 - for _, v in ipairs(resp) do - length = length + #v - end - - -- flush http header - ngx.header['Content-Length'] = length - ngx.flush(true) - ngx.sleep(0.01) - - -- send http body - for _, v in ipairs(resp) do - ngx.print(v) - ngx.flush(true) - ngx.sleep(0.01) - end - } - } - ---- request -GET /t ---- response_body -1 -22 -hello world ---- no_error_log -[error] ---- error_log -lua tcp socket read any - - - -=== TEST 65: receiveany send data after read side closed ---- config - server_tokens off; - location = /t { - content_by_lua_block { - local sock = ngx.socket.tcp() - sock:settimeout(500) - assert(sock:connect("127.0.0.1", 7658)) - - while true do - local data, err = sock:receiveany(1024) - if err then - if err ~= 'closed' then - ngx.say('unexpected err: ', err) - break - end - - local data = "send data after read side closed" - local bytes, err = sock:send(data) - if not bytes then - ngx.say(err) - end - - break - end - ngx.say(data) - end - - sock:close() - } - } - ---- request -GET /t ---- tcp_listen: 7658 ---- tcp_shutdown: 1 ---- tcp_query eval: "send data after read side closed" ---- tcp_query_len: 32 ---- response_body ---- no_error_log -[error] - - - -=== TEST 66: receiveany with limited, max <= 0 ---- config - location = /t { - set $port $TEST_NGINX_SERVER_PORT; - content_by_lua_block { - local sock = ngx.socket.tcp() - sock:settimeout(500) - assert(sock:connect("127.0.0.1", ngx.var.port)) - - local function receiveany_say_err(...) - local ok, err = pcall(sock.receiveany, sock, ...) - if not ok then - ngx.say(err) - end - end - - - receiveany_say_err(0) - receiveany_say_err(-1) - receiveany_say_err() - receiveany_say_err(nil) - } - } - ---- response_body -bad argument #2 to '?' (bad max argument) -bad argument #2 to '?' (bad max argument) -expecting 2 arguments (including the object), but got 1 -bad argument #2 to '?' (bad max argument) ---- request -GET /t ---- no_error_log -[error] - - - -=== TEST 67: receiveany with limited, max is larger than data ---- config - server_tokens off; - location = /t { - set $port $TEST_NGINX_SERVER_PORT; - content_by_lua_block { - local sock = ngx.socket.tcp() - sock:settimeout(500) - assert(sock:connect("127.0.0.1", ngx.var.port)) - local req = { - 'GET /foo HTTP/1.0\r\n', - 'Host: localhost\r\n', - 'Connection: close\r\n\r\n', - } - local ok, err = sock:send(req) - if not ok then - ngx.say("send request failed: ", err) - return - end - - while true do - local data, err, _ = sock:receive('*l') - if err then - ngx.say('unexpected error occurs when receiving http head: ', err) - return - end - - if #data == 0 then -- read last line of head - break - end - end - - local data, err = sock:receiveany(128) - if err then - if err ~= 'closed' then - ngx.say('unexpected err: ', err) - end - else - ngx.say(data) - end - - sock:close() - } - } - - location = /foo { - content_by_lua_block { - local resp = 'hello world' - local length = #resp - - ngx.header['Content-Length'] = length - ngx.flush(true) - ngx.sleep(0.01) - - ngx.print(resp) - } - } - ---- request -GET /t ---- response_body -hello world ---- no_error_log -[error] ---- error_log -lua tcp socket calling receiveany() method to read at most 128 bytes - - - -=== TEST 68: receiveany with limited, max is smaller than data ---- config - server_tokens off; - location = /t { - set $port $TEST_NGINX_SERVER_PORT; - content_by_lua_block { - local sock = ngx.socket.tcp() - sock:settimeout(500) - assert(sock:connect("127.0.0.1", ngx.var.port)) - local req = { - 'GET /foo HTTP/1.0\r\n', - 'Host: localhost\r\n', - 'Connection: close\r\n\r\n', - } - local ok, err = sock:send(req) - if not ok then - ngx.say("send request failed: ", err) - return - end - - while true do - local data, err, _ = sock:receive('*l') - if err then - ngx.say('unexpected error occurs when receiving http head: ', err) - return - end - - if #data == 0 then -- read last line of head - break - end - end - - while true do - local data, err = sock:receiveany(7) - if err then - if err ~= 'closed' then - ngx.say('unexpected err: ', err) - end - break - - else - ngx.say(data) - end - end - - sock:close() - } - } - - location = /foo { - content_by_lua_block { - local resp = 'hello world' - local length = #resp - - ngx.header['Content-Length'] = length - ngx.flush(true) - ngx.sleep(0.01) - - ngx.print(resp) - } - } - ---- request -GET /t ---- response_body -hello w -orld ---- no_error_log -[error] ---- error_log -lua tcp socket calling receiveany() method to read at most 7 bytes diff --git a/debian/modules/http-lua/t/062-count.t b/debian/modules/http-lua/t/062-count.t index 9b0afe8..2ad2f9f 100644 --- a/debian/modules/http-lua/t/062-count.t +++ b/debian/modules/http-lua/t/062-count.t @@ -283,7 +283,7 @@ n = 5 --- request GET /test --- response_body -n = 22 +n = 18 --- no_error_log [error] @@ -444,28 +444,7 @@ worker: 4 -=== TEST 20: entries under the metatable of tcp sockets ---- config - location = /test { - content_by_lua_block { - local n = 0 - local sock = ngx.socket.tcp() - for k, v in pairs(getmetatable(sock)) do - n = n + 1 - end - ngx.say("n = ", n) - } - } ---- request -GET /test ---- response_body -n = 13 ---- no_error_log -[error] - - - -=== TEST 21: entries under the metatable of udp sockets +=== TEST 20: entries under the metatable of udp sockets --- config location = /test { content_by_lua ' @@ -486,7 +465,7 @@ n = 6 -=== TEST 22: entries under the metatable of req raw sockets +=== TEST 21: entries under the metatable of req raw sockets --- config location = /test { content_by_lua ' @@ -518,7 +497,7 @@ n = 6 -=== TEST 23: entries under the req raw sockets +=== TEST 22: entries under the req raw sockets --- config location = /test { content_by_lua_block { @@ -557,7 +536,7 @@ nrec = 3 -=== TEST 24: entries under the req sockets +=== TEST 23: entries under the req sockets --- config location = /test { content_by_lua_block { diff --git a/debian/modules/http-lua/t/063-abort.t b/debian/modules/http-lua/t/063-abort.t index 7c90eaa..411a07e 100644 --- a/debian/modules/http-lua/t/063-abort.t +++ b/debian/modules/http-lua/t/063-abort.t @@ -22,7 +22,7 @@ __DATA__ === TEST 1: ngx.exit(400) should abort print --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /memc_query { internal; @@ -68,7 +68,7 @@ GET /test?a === TEST 2: ngx.exit(400) should abort ngx.log --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /memc_query { internal; @@ -116,7 +116,7 @@ GET /test?a === TEST 3: ngx.exit(400) should abort ngx.location.capture --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /memc_query { internal; @@ -161,7 +161,7 @@ the "$memc_key" variable is not set === TEST 4: ngx.exit(400) should abort ngx.location.capture_multi --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /memc_query { internal; @@ -206,7 +206,7 @@ the "$memc_key" variable is not set === TEST 5: ngx.exit(400) should abort ngx.redirect --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /test { content_by_lua ' @@ -233,7 +233,7 @@ lua redirect to "/blah" with code 302 === TEST 6: ngx.exit(400) should abort ngx.exit --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /test { content_by_lua ' @@ -260,7 +260,7 @@ lua exit with code 503 === TEST 7: ngx.exit(400) should abort ngx.exec --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /test { content_by_lua ' @@ -287,7 +287,7 @@ lua exec "/blah?" === TEST 8: ngx.exit(400) should abort ngx.send_headers --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /test { content_by_lua ' @@ -314,7 +314,7 @@ lua send headers === TEST 9: ngx.exit(400) should abort ngx.print --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /test { content_by_lua ' @@ -341,7 +341,7 @@ lua print response === TEST 10: ngx.exit(400) should abort ngx.say --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /test { content_by_lua ' @@ -368,7 +368,7 @@ lua say response === TEST 11: ngx.exit(400) should abort ngx.flush --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /test { content_by_lua ' @@ -395,7 +395,7 @@ lua flush asynchronously === TEST 12: ngx.exit(400) should abort ngx.eof --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /test { content_by_lua ' @@ -422,7 +422,7 @@ lua send eof === TEST 13: ngx.exit(400) should abort ngx.re.match --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /test { content_by_lua ' @@ -449,7 +449,7 @@ lua compiling match regex "a" with options "jo" === TEST 14: ngx.exit(400) should abort ngx.re.gmatch --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /test { content_by_lua ' @@ -476,7 +476,7 @@ lua compiling gmatch regex "a" with options "jo" === TEST 15: ngx.exit(400) should abort ngx.re.sub --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /test { content_by_lua ' @@ -503,7 +503,7 @@ lua compiling sub regex "a" with options "jo" === TEST 16: ngx.exit(400) should abort ngx.re.gsub --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /test { content_by_lua ' @@ -530,7 +530,7 @@ lua compiling gsub regex "a" with options "jo" === TEST 17: ngx.exit(400) should abort ngx.shared.DICT (set) --- http_config eval - "lua_shared_dict dogs 1m; lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_shared_dict dogs 1m; lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /test { content_by_lua ' @@ -560,7 +560,7 @@ foo = 56 === TEST 18: ngx.exit(400) should abort ngx.shared.DICT (replace) --- http_config eval - "lua_shared_dict dogs 1m; lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_shared_dict dogs 1m; lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /test { content_by_lua ' @@ -590,7 +590,7 @@ foo = 56 === TEST 19: ngx.exit(400) should abort ngx.shared.DICT (incr) --- http_config eval - "lua_shared_dict dogs 1m; lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_shared_dict dogs 1m; lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /test { content_by_lua ' @@ -620,7 +620,7 @@ foo = 88 === TEST 20: ngx.exit(400) should abort ngx.shared.DICT (get) --- http_config eval - "lua_shared_dict dogs 1m; lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_shared_dict dogs 1m; lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /test { content_by_lua ' @@ -649,7 +649,7 @@ fetching key "foo" in shared dict "dogs" === TEST 21: ngx.exit(400) should skip os.execute --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /test { content_by_lua ' @@ -679,7 +679,7 @@ GET /test === TEST 22: ngx.exit(400) should break pcall and skip os.execute --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /test { content_by_lua ' @@ -709,7 +709,7 @@ fetching key "foo" in shared dict "dogs" === TEST 23: ngx.exit(400) should break pcall and skip os.execute (all in user module) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /test { content_by_lua ' @@ -739,7 +739,7 @@ GET /test === TEST 24: ngx.redirect() should break pcall and skip os.execute (all in user module) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /test { content_by_lua ' @@ -769,7 +769,7 @@ GET /test === TEST 25: ngx.redirect() should skip os.execute (all in user module) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /test { content_by_lua ' @@ -799,7 +799,7 @@ GET /test === TEST 26: ngx.exec() should break pcall and skip os.execute (all in user module) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /test { content_by_lua ' @@ -832,7 +832,7 @@ foo === TEST 27: ngx.exec() should skip os.execute (all in user module) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /test { content_by_lua ' @@ -865,7 +865,7 @@ foo === TEST 28: ngx.set_uri(uri, true) should break pcall and skip os.execute (all in user module) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /test { rewrite_by_lua ' @@ -921,7 +921,7 @@ hello world === TEST 30: ngx.exit(400) should break xpcall and skip os.execute (all in user module) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /test { content_by_lua ' @@ -955,7 +955,7 @@ GET /test === TEST 31: ngx.exec() should skip os.execute (all in user module) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /test { content_by_lua ' @@ -988,7 +988,7 @@ foo === TEST 32: ngx.exec() should break pcall and skip os.execute (all in user module) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /test { content_by_lua ' diff --git a/debian/modules/http-lua/t/064-pcall.t b/debian/modules/http-lua/t/064-pcall.t index 9af2de7..3011f3e 100644 --- a/debian/modules/http-lua/t/064-pcall.t +++ b/debian/modules/http-lua/t/064-pcall.t @@ -22,11 +22,11 @@ __DATA__ === TEST 1: pcall works --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /test { content_by_lua ' - local function f(a, b) + function f(a, b) if a == 0 and b == 0 then error("zero error") end @@ -58,11 +58,11 @@ $/s === TEST 2: xpcall works --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /test { content_by_lua ' - local function f(a, b) + function f(a, b) if a == 0 and b == 0 then error("zero error") end @@ -70,15 +70,15 @@ $/s return 23, "hello", true end - local function g() + function g() return f(0, 0) end - local function h() + function h() return f(0) end - local function err(...) + function err(...) ngx.say("error handler called: ", ...) return "this is the new err" end diff --git a/debian/modules/http-lua/t/065-tcp-socket-timeout.t b/debian/modules/http-lua/t/065-tcp-socket-timeout.t index 092094a..78b8cff 100644 --- a/debian/modules/http-lua/t/065-tcp-socket-timeout.t +++ b/debian/modules/http-lua/t/065-tcp-socket-timeout.t @@ -51,7 +51,7 @@ __DATA__ location /t { content_by_lua ' local sock = ngx.socket.tcp() - local ok, err = sock:connect("127.0.0.2", 12345) + local ok, err = sock:connect("agentzh.org", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -66,7 +66,7 @@ GET /t failed to connect: timeout --- error_log lua tcp socket connect timeout: 100 -lua tcp socket connect timed out, when connecting to 127.0.0.2:12345 +lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 --- timeout: 10 @@ -81,7 +81,7 @@ lua tcp socket connect timed out, when connecting to 127.0.0.2:12345 content_by_lua ' local sock = ngx.socket.tcp() sock:settimeout(150) - local ok, err = sock:connect("127.0.0.2", 12345) + local ok, err = sock:connect("agentzh.org", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -96,7 +96,7 @@ GET /t failed to connect: timeout --- error_log lua tcp socket connect timeout: 150 -lua tcp socket connect timed out, when connecting to 127.0.0.2:12345 +lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 --- timeout: 10 @@ -110,7 +110,7 @@ lua tcp socket connect timed out, when connecting to 127.0.0.2:12345 content_by_lua ' local sock = ngx.socket.tcp() sock:settimeout(nil) - local ok, err = sock:connect("127.0.0.2", 12345) + local ok, err = sock:connect("agentzh.org", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -125,7 +125,7 @@ GET /t failed to connect: timeout --- error_log lua tcp socket connect timeout: 102 -lua tcp socket connect timed out, when connecting to 127.0.0.2:12345 +lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 @@ -139,7 +139,7 @@ lua tcp socket connect timed out, when connecting to 127.0.0.2:12345 content_by_lua ' local sock = ngx.socket.tcp() sock:settimeout(0) - local ok, err = sock:connect("127.0.0.2", 12345) + local ok, err = sock:connect("agentzh.org", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -154,7 +154,7 @@ GET /t failed to connect: timeout --- error_log lua tcp socket connect timeout: 102 -lua tcp socket connect timed out, when connecting to 127.0.0.2:12345 +lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 --- timeout: 10 @@ -168,7 +168,7 @@ lua tcp socket connect timed out, when connecting to 127.0.0.2:12345 content_by_lua ' local sock = ngx.socket.tcp() sock:settimeout(-1) - local ok, err = sock:connect("127.0.0.2", 12345) + local ok, err = sock:connect("agentzh.org", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -584,7 +584,7 @@ bad timeout value --- config location /lua { content_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -683,7 +683,7 @@ after location /t { content_by_lua ' local sock = ngx.socket.tcp() - local ok, err = sock:connect("127.0.0.2", 12345) + local ok, err = sock:connect("agentzh.org", 12345) if not ok then ngx.say("1: failed to connect: ", err) @@ -707,7 +707,7 @@ GET /t 2: connected: 1 --- error_log lua tcp socket connect timeout: 100 -lua tcp socket connect timed out, when connecting to 127.0.0.2:12345 +lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 --- timeout: 10 diff --git a/debian/modules/http-lua/t/066-socket-receiveuntil.t b/debian/modules/http-lua/t/066-socket-receiveuntil.t index 89d2abf..ffe74aa 100644 --- a/debian/modules/http-lua/t/066-socket-receiveuntil.t +++ b/debian/modules/http-lua/t/066-socket-receiveuntil.t @@ -245,7 +245,7 @@ close: 1 nil local reader = sock:receiveuntil("abcabd") for i = 1, 2 do - local line, err, part = reader() + line, err, part = reader() if line then ngx.say("read: ", line) @@ -316,7 +316,7 @@ close: 1 nil local reader = sock:receiveuntil("aa") for i = 1, 2 do - local line, err, part = reader() + line, err, part = reader() if line then ngx.say("read: ", line) @@ -387,7 +387,7 @@ close: 1 nil local reader = sock:receiveuntil("aaa") for i = 1, 2 do - local line, err, part = reader() + line, err, part = reader() if line then ngx.say("read: ", line) @@ -458,7 +458,7 @@ close: 1 nil local reader = sock:receiveuntil("aaaaad") for i = 1, 2 do - local line, err, part = reader() + line, err, part = reader() if line then ngx.say("read: ", line) @@ -530,7 +530,7 @@ close: 1 nil local reader = sock:receiveuntil("aaaaad") for i = 1, 2 do - local line, err, part = reader() + line, err, part = reader() if line then ngx.say("read: ", line) @@ -602,7 +602,7 @@ close: 1 nil local reader = sock:receiveuntil("aaaaad") for i = 1, 2 do - local line, err, part = reader() + line, err, part = reader() if line then ngx.say("read: ", line) @@ -673,7 +673,7 @@ close: 1 nil local reader = sock:receiveuntil("abcabdabcabe") for i = 1, 2 do - local line, err, part = reader() + line, err, part = reader() if line then ngx.say("read: ", line) @@ -744,7 +744,7 @@ close: 1 nil local reader = sock:receiveuntil("abcabdabcabe") for i = 1, 2 do - local line, err, part = reader() + line, err, part = reader() if line then ngx.say("read: ", line) @@ -815,7 +815,7 @@ close: 1 nil local reader = sock:receiveuntil("abcabdabcabe") for i = 1, 2 do - local line, err, part = reader() + line, err, part = reader() if line then ngx.say("read: ", line) @@ -886,7 +886,7 @@ close: 1 nil local reader = sock:receiveuntil("abcabdabcabe") for i = 1, 2 do - local line, err, part = reader() + line, err, part = reader() if line then ngx.say("read: ", line) @@ -957,7 +957,7 @@ close: 1 nil local reader = sock:receiveuntil("--abc") for i = 1, 2 do - local line, err, part = reader() + line, err, part = reader() if line then ngx.say("read: ", line) @@ -1028,7 +1028,7 @@ close: 1 nil local reader = sock:receiveuntil("--abc") for i = 1, 7 do - local line, err, part = reader(4) + line, err, part = reader(4) if line then ngx.say("read: ", line) @@ -1105,7 +1105,7 @@ close: 1 nil local reader = sock:receiveuntil("--abc") for i = 1, 7 do - local line, err, part = reader(4) + line, err, part = reader(4) if line then ngx.say("read: ", line) @@ -1182,7 +1182,7 @@ close: 1 nil local reader = sock:receiveuntil("--abc") for i = 1, 7 do - local line, err, part = reader(4) + line, err, part = reader(4) if line then ngx.say("read: ", line) @@ -1270,7 +1270,7 @@ close: 1 nil local reader = sock:receiveuntil("abcabd") for i = 1, 2 do - local line, err, part = reader() + line, err, part = reader() if line then ngx.say("read: ", line) diff --git a/debian/modules/http-lua/t/067-req-socket.t b/debian/modules/http-lua/t/067-req-socket.t index 6593360..229d5cc 100644 --- a/debian/modules/http-lua/t/067-req-socket.t +++ b/debian/modules/http-lua/t/067-req-socket.t @@ -320,7 +320,7 @@ found the end of the stream === TEST 4: attempt to use the req socket across request boundary --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location /t { content_by_lua ' @@ -369,7 +369,7 @@ hello world === TEST 5: receive until on request_body - receiveuntil(1) on the last byte of the body See https://groups.google.com/group/openresty/browse_thread/thread/43cf01da3c681aba for details --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location /t { content_by_lua ' @@ -431,7 +431,7 @@ done === TEST 6: pipelined POST requests --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location /t { content_by_lua ' diff --git a/debian/modules/http-lua/t/068-socket-keepalive.t b/debian/modules/http-lua/t/068-socket-keepalive.t index e4c6988..f052e9a 100644 --- a/debian/modules/http-lua/t/068-socket-keepalive.t +++ b/debian/modules/http-lua/t/068-socket-keepalive.t @@ -4,14 +4,13 @@ use Test::Nginx::Socket::Lua; #repeat_each(2); -plan tests => repeat_each() * (blocks() * 4 + 31); +plan tests => repeat_each() * (blocks() * 5 + 9); our $HtmlDir = html_dir; $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; $ENV{TEST_NGINX_HTML_DIR} = $HtmlDir; $ENV{TEST_NGINX_REDIS_PORT} ||= 6379; -$ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; $ENV{LUA_PATH} ||= '/usr/local/openresty-debug/lualib/?.lua;/usr/local/openresty/lualib/?.lua;;'; @@ -30,7 +29,7 @@ __DATA__ === TEST 1: sanity --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -98,7 +97,7 @@ lua tcp socket keepalive create connection pool for key "127.0.0.1:$ENV{TEST_NGI === TEST 2: free up the whole connection pool if no active connections --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -169,7 +168,7 @@ received: OK === TEST 3: upstream sockets close prematurely --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config server_tokens off; keepalive_timeout 100ms; @@ -244,7 +243,7 @@ done === TEST 4: http keepalive --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config server_tokens off; location /t { @@ -702,35 +701,7 @@ qr/lua tcp socket connection pool size: 25\b/] -=== TEST 10: setkeepalive() 'pool_size' should be greater than zero ---- config - location /t { - set $port $TEST_NGINX_MEMCACHED_PORT; - content_by_lua_block { - local sock, err = ngx.socket.connect("127.0.0.1", ngx.var.port) - if not sock then - ngx.say(err) - return - end - - local ok, err = pcall(sock.setkeepalive, sock, 0, 0) - if not ok then - ngx.say(err) - return - end - ngx.say(ok) - } - } ---- request -GET /t ---- response_body -bad argument #3 to '?' (bad "pool_size" option value: 0) ---- no_error_log -[error] - - - -=== TEST 11: sock:keepalive_timeout(0) means unlimited +=== TEST 10: sock:keepalive_timeout(0) means unlimited --- config server_tokens off; location /t { @@ -805,10 +776,10 @@ qr/lua tcp socket connection pool size: 30\b/] -=== TEST 12: sanity (uds) +=== TEST 11: sanity (uds) --- http_config eval " - lua_package_path '$::HtmlDir/?.lua;./?.lua;;'; + lua_package_path '$::HtmlDir/?.lua;./?.lua'; server { listen unix:$::HtmlDir/nginx.sock; default_type 'text/plain'; @@ -887,7 +858,7 @@ received response of 119 bytes -=== TEST 13: github issue #108: ngx.locaiton.capture + redis.set_keepalive +=== TEST 12: github issue #108: ngx.locaiton.capture + redis.set_keepalive --- http_config eval qq{ lua_package_path "$::HtmlDir/?.lua;;"; @@ -934,9 +905,9 @@ lua tcp socket get keepalive peer: using connection -=== TEST 14: github issue #110: ngx.exit with HTTP_NOT_FOUND causes worker process to exit +=== TEST 13: github issue #110: ngx.exit with HTTP_NOT_FOUND causes worker process to exit --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config error_page 404 /404.html; location /t { @@ -993,9 +964,9 @@ Not found, dear... -=== TEST 15: custom pools (different pool for the same host:port) - tcp +=== TEST 14: custom pools (different pool for the same host:port) - tcp --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -1041,9 +1012,9 @@ lua tcp socket keepalive create connection pool for key "B" -=== TEST 16: custom pools (same pool for different host:port) - tcp +=== TEST 15: custom pools (same pool for different host:port) - tcp --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -1088,10 +1059,10 @@ lua tcp socket get keepalive peer: using connection -=== TEST 17: custom pools (different pool for the same host:port) - unix +=== TEST 16: custom pools (different pool for the same host:port) - unix --- http_config eval " - lua_package_path '$::HtmlDir/?.lua;./?.lua;;'; + lua_package_path '$::HtmlDir/?.lua;./?.lua'; server { listen unix:$::HtmlDir/nginx.sock; default_type 'text/plain'; @@ -1148,10 +1119,10 @@ lua tcp socket keepalive create connection pool for key "B" -=== TEST 18: custom pools (same pool for the same path) - unix +=== TEST 17: custom pools (same pool for the same path) - unix --- http_config eval " - lua_package_path '$::HtmlDir/?.lua;./?.lua;;'; + lua_package_path '$::HtmlDir/?.lua;./?.lua'; server { listen unix:$::HtmlDir/nginx.sock; default_type 'text/plain'; @@ -1203,9 +1174,9 @@ lua tcp socket get keepalive peer: using connection -=== TEST 19: numeric pool option value +=== TEST 18: numeric pool option value --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -1250,9 +1221,9 @@ lua tcp socket get keepalive peer: using connection -=== TEST 20: nil pool option value +=== TEST 19: nil pool option value --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -1293,9 +1264,9 @@ connected: 1, reused: 0 -=== TEST 21: (bad) table pool option value +=== TEST 20: (bad) table pool option value --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -1334,9 +1305,9 @@ bad argument #3 to 'connect' (bad "pool" option type: table) -=== TEST 22: (bad) boolean pool option value +=== TEST 21: (bad) boolean pool option value --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location /t { set $port $TEST_NGINX_MEMCACHED_PORT; @@ -1375,7 +1346,7 @@ bad argument #3 to 'connect' (bad "pool" option type: boolean) -=== TEST 23: clear the redis store +=== TEST 22: clear the redis store --- config location /t { redis2_query flushall; @@ -1392,9 +1363,9 @@ bad argument #3 to 'connect' (bad "pool" option type: boolean) -=== TEST 24: bug in send(): clear the chain writer ctx +=== TEST 23: bug in send(): clear the chain writer ctx --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location /t { set $port $TEST_NGINX_REDIS_PORT; @@ -1507,7 +1478,7 @@ done -=== TEST 25: setkeepalive() with explicit nil args +=== TEST 24: setkeepalive() with explicit nil args --- config server_tokens off; location /t { @@ -1580,1379 +1551,3 @@ done "lua tcp socket keepalive timeout: 100 ms", qr/lua tcp socket connection pool size: 30\b/] --- timeout: 4 - - - -=== TEST 26: conn queuing: connect() verifies the options for connection pool ---- config - location /t { - set $port $TEST_NGINX_SERVER_PORT; - - content_by_lua_block { - local sock = ngx.socket.tcp() - local function check_opts_for_connect(opts) - local ok, err = pcall(function() - sock:connect("127.0.0.1", ngx.var.port, opts) - end) - if not ok then - ngx.say(err) - else - ngx.say("ok") - end - end - - check_opts_for_connect({pool_size = 'a'}) - check_opts_for_connect({pool_size = 0}) - check_opts_for_connect({backlog = -1}) - check_opts_for_connect({backlog = 0}) - } - } ---- request -GET /t ---- response_body_like -.+ 'connect' \(bad "pool_size" option type: string\) -.+ 'connect' \(bad "pool_size" option value: 0\) -.+ 'connect' \(bad "backlog" option value: -1\) -ok ---- no_error_log -[error] - - - -=== TEST 27: conn queuing: connect() can specify 'pool_size' which overrides setkeepalive() ---- config - location /t { - set $port $TEST_NGINX_MEMCACHED_PORT; - - content_by_lua_block { - local port = ngx.var.port - local function go() - local sock = ngx.socket.tcp() - local ok, err = sock:connect("127.0.0.1", port, {pool_size = 1}) - if not ok then - ngx.say("failed to connect: ", err) - return - end - - ngx.say("connected: ", ok, ", reused: ", sock:getreusedtimes()) - - local req = "flush_all\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 line, err, part = sock:receive() - if line then - ngx.say("received: ", line) - else - ngx.say("failed to receive a line: ", err, " [", part, "]") - end - - local ok, err = sock:setkeepalive(0, 20) - if not ok then - ngx.say("failed to set reusable: ", err) - end - end - - -- reuse ok - go() - go() - - local sock1 = ngx.socket.connect("127.0.0.1", port) - local sock2 = ngx.socket.connect("127.0.0.1", port) - local ok, err = sock1:setkeepalive(0, 20) - if not ok then - ngx.say(err) - end - local ok, err = sock2:setkeepalive(0, 20) - if not ok then - ngx.say(err) - end - - -- the pool_size is 1 instead of 20 - sock1 = ngx.socket.connect("127.0.0.1", port) - sock2 = ngx.socket.connect("127.0.0.1", port) - ngx.say("reused: ", sock1:getreusedtimes()) - ngx.say("reused: ", sock2:getreusedtimes()) - sock1:setkeepalive(0, 20) - sock2:setkeepalive(0, 20) - } - } ---- request -GET /t ---- response_body -connected: 1, reused: 0 -request sent: 11 -received: OK -connected: 1, reused: 1 -request sent: 11 -received: OK -reused: 1 -reused: 0 ---- no_error_log eval -["[error]", -"lua tcp socket keepalive: free connection pool for ", -"lua tcp socket connection pool size: 20"] ---- error_log eval -[qq{lua tcp socket keepalive create connection pool for key "127.0.0.1:$ENV{TEST_NGINX_MEMCACHED_PORT}"}, -"lua tcp socket connection pool size: 1", -] - - - -=== TEST 28: conn queuing: connect() can specify 'pool_size' for unix domain socket ---- http_config eval -" - server { - listen unix:$::HtmlDir/nginx.sock; - } -" ---- config - location /t { - content_by_lua_block { - local path = "unix:" .. "$TEST_NGINX_HTML_DIR/nginx.sock"; - local function go() - local sock = ngx.socket.tcp() - local ok, err = sock:connect(path, {pool_size = 1}) - if not ok then - ngx.say("failed to connect: ", err) - return - end - - ngx.say("connected: ", ok, ", reused: ", sock:getreusedtimes()) - - local ok, err = sock:setkeepalive(0, 20) - if not ok then - ngx.say("failed to set reusable: ", err) - end - end - - go() - go() - - local sock1 = ngx.socket.connect(path) - local sock2 = ngx.socket.connect(path) - local ok, err = sock1:setkeepalive(0, 20) - if not ok then - ngx.say(err) - end - local ok, err = sock2:setkeepalive(0, 20) - if not ok then - ngx.say(err) - end - - -- the pool_size is 1 instead of 20 - sock1 = ngx.socket.connect(path) - sock2 = ngx.socket.connect(path) - ngx.say("reused: ", sock1:getreusedtimes()) - ngx.say("reused: ", sock2:getreusedtimes()) - sock1:setkeepalive(0, 20) - sock2:setkeepalive(0, 20) - } - } ---- request -GET /t ---- response_body -connected: 1, reused: 0 -connected: 1, reused: 1 -reused: 1 -reused: 0 ---- no_error_log eval -["[error]", -"lua tcp socket keepalive: free connection pool for ", -"lua tcp socket connection pool size: 20"] ---- error_log eval -["lua tcp socket get keepalive peer: using connection", -'lua tcp socket keepalive create connection pool for key "unix:', -"lua tcp socket connection pool size: 1", -] - - - -=== TEST 29: conn queuing: connect() can specify 'pool_size' for custom pool ---- config - location /t { - set $port $TEST_NGINX_MEMCACHED_PORT; - - content_by_lua_block { - local port = ngx.var.port - local function go(pool) - local sock = ngx.socket.tcp() - local ok, err = sock:connect("127.0.0.1", port, {pool = pool, pool_size = 1}) - if not ok then - ngx.say("failed to connect: ", err) - return - end - - ngx.say("connected: ", pool, ", reused: ", sock:getreusedtimes()) - - local ok, err = sock:setkeepalive(0, 20) - if not ok then - ngx.say("failed to set reusable: ", err) - end - end - - go('A') - go('B') - go('A') - go('B') - - local sock1 = ngx.socket.connect("127.0.0.1", port, {pool = 'A'}) - local sock2 = ngx.socket.connect("127.0.0.1", port, {pool = 'A'}) - local ok, err = sock1:setkeepalive(0, 20) - if not ok then - ngx.say(err) - end - local ok, err = sock2:setkeepalive(0, 20) - if not ok then - ngx.say(err) - end - - -- the pool_size is 1 instead of 20 - sock1 = ngx.socket.connect("127.0.0.1", port, {pool = 'A'}) - sock2 = ngx.socket.connect("127.0.0.1", port, {pool = 'A'}) - ngx.say("reused: ", sock1:getreusedtimes()) - ngx.say("reused: ", sock2:getreusedtimes()) - sock1:setkeepalive(0, 20) - sock2:setkeepalive(0, 20) - } - } ---- request -GET /t ---- response_body -connected: A, reused: 0 -connected: B, reused: 0 -connected: A, reused: 1 -connected: B, reused: 1 -reused: 1 -reused: 0 ---- no_error_log eval -["[error]", -"lua tcp socket keepalive: free connection pool for ", -"lua tcp socket connection pool size: 20"] ---- error_log eval -[qq{lua tcp socket keepalive create connection pool for key "A"}, -qq{lua tcp socket keepalive create connection pool for key "B"}, -"lua tcp socket connection pool size: 1", -] - - - -=== TEST 30: conn queuing: connect() uses lua_socket_pool_size as default if 'backlog' is given ---- config - location /t { - set $port $TEST_NGINX_MEMCACHED_PORT; - lua_socket_pool_size 1234; - - content_by_lua_block { - local port = ngx.var.port - local opts = {backlog = 0} - local sock, err = ngx.socket.connect("127.0.0.1", port, opts) - if not sock then - ngx.say(err) - else - ngx.say("ok") - end - } - } ---- request -GET /t ---- response_body -ok ---- error_log -lua tcp socket connection pool size: 1234 ---- no_error_log -[error] - - - -=== TEST 31: conn queuing: more connect operations than 'backlog' size ---- config - location /t { - set $port $TEST_NGINX_MEMCACHED_PORT; - - content_by_lua_block { - local port = ngx.var.port - local opts = {pool_size = 2, backlog = 0} - local sock = ngx.socket.connect("127.0.0.1", port, opts) - local not_reused_socket, err = ngx.socket.connect("127.0.0.1", port, opts) - if not not_reused_socket then - ngx.say(err) - return - end - -- burst - local ok, err = ngx.socket.connect("127.0.0.1", port, opts) - if not ok then - ngx.say(err) - end - - local ok, err = sock:setkeepalive() - if not ok then - ngx.say(err) - return - end - - ok, err = sock:connect("127.0.0.1", port, opts) - if not ok then - ngx.say(err) - end - ngx.say("reused: ", sock:getreusedtimes()) - -- both queue and pool is full - ok, err = ngx.socket.connect("127.0.0.1", port, opts) - if not ok then - ngx.say(err) - end - } - } ---- request -GET /t ---- response_body -too many waiting connect operations -reused: 1 -too many waiting connect operations ---- no_error_log -[error] - - - -=== TEST 32: conn queuing: once 'pool_size' is reached and pool has 'backlog' ---- config - location /t { - set $port $TEST_NGINX_MEMCACHED_PORT; - - content_by_lua_block { - local port = ngx.var.port - local opts = {pool_size = 2, backlog = 2} - local sock1 = ngx.socket.connect("127.0.0.1", port, opts) - - ngx.timer.at(0, function(premature) - local sock2, err = ngx.socket.connect("127.0.0.1", port, opts) - if not sock2 then - ngx.log(ngx.ERR, err) - return - end - - ngx.log(ngx.WARN, "start to handle timer") - ngx.sleep(0.1) - sock2:close() - -- resume connect operation - ngx.log(ngx.WARN, "continue to handle timer") - end) - - ngx.sleep(0.05) - ngx.log(ngx.WARN, "start to handle cosocket") - local sock3, err = ngx.socket.connect("127.0.0.1", port, opts) - if not sock3 then - ngx.say(err) - return - end - ngx.log(ngx.WARN, "continue to handle cosocket") - - local req = "flush_all\r\n" - local bytes, err = sock3:send(req) - if not bytes then - ngx.say("failed to send request: ", err) - return - end - ngx.say("request sent: ", bytes) - - local line, err, part = sock3:receive() - if line then - ngx.say("received: ", line) - else - ngx.say("failed to receive a line: ", err, " [", part, "]") - end - - local ok, err = sock3:setkeepalive() - if not ok then - ngx.say("failed to set reusable: ", err) - end - ngx.say("setkeepalive: OK") - } - } ---- request -GET /t ---- response_body -request sent: 11 -received: OK -setkeepalive: OK ---- no_error_log -[error] ---- error_log -lua tcp socket queue connect operation for connection pool "127.0.0.1 ---- grep_error_log eval: qr/(start|continue) to handle \w+/ ---- grep_error_log_out -start to handle timer -start to handle cosocket -continue to handle timer -continue to handle cosocket - - - -=== TEST 33: conn queuing: do not count failed connect operations ---- config - resolver $TEST_NGINX_RESOLVER ipv6=off; - resolver_timeout 3s; - location /t { - set $port $TEST_NGINX_MEMCACHED_PORT; - - content_by_lua_block { - local port = ngx.var.port - local opts = {pool = "test", pool_size = 1, backlog = 0} - - local sock = ngx.socket.tcp() - sock:settimeouts(100, 3000, 3000) - local ok, err = sock:connect("127.0.0.2", 12345, opts) - if not ok then - ngx.say(err) - end - - local sock, err = ngx.socket.connect("127.0.0.1", port, opts) - if not sock then - ngx.say(err) - end - ngx.say("ok") - } - } ---- request -GET /t ---- error_log -lua tcp socket connect timed out, when connecting to ---- response_body -timeout -ok - - - -=== TEST 34: conn queuing: connect until backlog is reached ---- config - location /t { - set $port $TEST_NGINX_MEMCACHED_PORT; - - content_by_lua_block { - local port = ngx.var.port - local opts = {pool_size = 1, backlog = 1} - local sock1 = ngx.socket.connect("127.0.0.1", port, opts) - - ngx.timer.at(0.01, function(premature) - ngx.log(ngx.WARN, "start to handle timer") - local sock2, err = ngx.socket.connect("127.0.0.1", port, opts) - if not sock2 then - ngx.log(ngx.ERR, err) - return - end - - ngx.sleep(0.02) - local ok, err = sock2:close() - if not ok then - ngx.log(ngx.ERR, err) - end - ngx.log(ngx.WARN, "continue to handle timer") - end) - - ngx.sleep(0.02) - local sock3, err = ngx.socket.connect("127.0.0.1", port, opts) - if not sock3 then - ngx.say(err) - end - local ok, err = sock1:setkeepalive() - if not ok then - ngx.say(err) - return - end - ngx.sleep(0.01) -- run sock2 - - ngx.log(ngx.WARN, "start to handle cosocket") - local sock3, err = ngx.socket.connect("127.0.0.1", port, opts) - if not sock3 then - ngx.say(err) - return - end - ngx.log(ngx.WARN, "continue to handle cosocket") - - local ok, err = sock3:setkeepalive() - if not ok then - ngx.say(err) - end - } - } ---- request -GET /t ---- response_body -too many waiting connect operations ---- no_error_log -[error] ---- error_log -lua tcp socket queue connect operation for connection pool "127.0.0.1 ---- grep_error_log eval: qr/queue connect operation for connection pool|(start|continue) to handle \w+/ ---- grep_error_log_out -start to handle timer -queue connect operation for connection pool -start to handle cosocket -queue connect operation for connection pool -continue to handle timer -continue to handle cosocket - - - -=== TEST 35: conn queuing: memory reuse for host in queueing connect operation ctx ---- config - location /t { - set $port $TEST_NGINX_MEMCACHED_PORT; - - content_by_lua_block { - local port = ngx.var.port - local opts = {pool = "test", pool_size = 1, backlog = 3} - local sock = ngx.socket.connect("127.0.0.1", port, opts) - - ngx.timer.at(0.01, function(premature) - local sock, err = ngx.socket.connect("0.0.0.0", port, opts) - if not sock then - ngx.log(ngx.ERR, err) - return - end - - local ok, err = sock:close() - if not ok then - ngx.log(ngx.ERR, err) - end - end) - - ngx.timer.at(0.015, function(premature) - local sock, err = ngx.socket.connect("127.0.0.1", port, opts) - if not sock then - ngx.log(ngx.ERR, err) - return - end - - local ok, err = sock:close() - if not ok then - ngx.log(ngx.ERR, err) - end - end) - - ngx.timer.at(0.02, function(premature) - local sock, err = ngx.socket.connect("0.0.0.0", port, opts) - if not sock then - ngx.log(ngx.ERR, err) - return - end - - local ok, err = sock:close() - if not ok then - ngx.log(ngx.ERR, err) - end - end) - - ngx.sleep(0.03) - local ok, err = sock:setkeepalive() - if not ok then - ngx.say(err) - return - end - ngx.say("ok") - } - } ---- request -GET /t ---- response_body -ok ---- no_error_log -[error] ---- grep_error_log eval: qr/queue connect operation for connection pool/ ---- grep_error_log_out -queue connect operation for connection pool -queue connect operation for connection pool -queue connect operation for connection pool - - - -=== TEST 36: conn queuing: connect() returns error after connect operation resumed ---- config - location /t { - set $port $TEST_NGINX_MEMCACHED_PORT; - - content_by_lua_block { - local port = ngx.var.port - local opts = {pool = "test", pool_size = 1, backlog = 1} - local sock = ngx.socket.connect("127.0.0.1", port, opts) - - ngx.timer.at(0, function(premature) - local sock, err = ngx.socket.connect("", port, opts) - if not sock then - ngx.log(ngx.WARN, err) - end - end) - - ngx.sleep(0.01) - -- use 'close' to force parsing host instead of reusing conn - local ok, err = sock:close() - if not ok then - ngx.say(err) - return - end - ngx.say("ok") - } - } ---- request -GET /t ---- response_body -ok ---- no_error_log -[error] ---- error_log -failed to parse host name ---- grep_error_log eval: qr/queue connect operation for connection pool/ ---- grep_error_log_out -queue connect operation for connection pool - - - -=== TEST 37: conn queuing: in uthread ---- config - location /t { - set $port $TEST_NGINX_MEMCACHED_PORT; - - content_by_lua_block { - local port = ngx.var.port - local opts = {pool_size = 1, backlog = 2} - - local conn_sock = function() - local sock, err = ngx.socket.connect("127.0.0.1", port, opts) - if not sock then - ngx.say(err) - return - end - ngx.say("start to handle uthread") - - ngx.sleep(0.01) - sock:close() - ngx.say("continue to handle other uthread") - end - - local sock, err = ngx.socket.connect("127.0.0.1", port, opts) - if not sock then - ngx.log(ngx.ERR, err) - return - end - - local co1 = ngx.thread.spawn(conn_sock) - local co2 = ngx.thread.spawn(conn_sock) - local co3 = ngx.thread.spawn(conn_sock) - - local ok, err = sock:setkeepalive() - if not ok then - ngx.log(ngx.ERR, err) - end - - ngx.thread.wait(co1) - ngx.thread.wait(co2) - ngx.thread.wait(co3) - ngx.say("all uthreads ok") - } - } ---- request -GET /t ---- response_body -too many waiting connect operations -start to handle uthread -continue to handle other uthread -start to handle uthread -continue to handle other uthread -all uthreads ok ---- no_error_log -[error] ---- grep_error_log eval: qr/queue connect operation for connection pool/ ---- grep_error_log_out -queue connect operation for connection pool -queue connect operation for connection pool - - - -=== TEST 38: conn queuing: in access_by_lua ---- config - location /t { - set $port $TEST_NGINX_MEMCACHED_PORT; - - access_by_lua_block { - local port = ngx.var.port - local opts = {pool_size = 1, backlog = 2} - - local conn_sock = function() - local sock, err = ngx.socket.connect("127.0.0.1", port, opts) - if not sock then - ngx.say(err) - return - end - ngx.say("start to handle uthread") - - ngx.sleep(0.01) - sock:close() - ngx.say("continue to handle other uthread") - end - - local sock, err = ngx.socket.connect("127.0.0.1", port, opts) - if not sock then - ngx.log(ngx.ERR, err) - return - end - - local co1 = ngx.thread.spawn(conn_sock) - local co2 = ngx.thread.spawn(conn_sock) - local co3 = ngx.thread.spawn(conn_sock) - - local ok, err = sock:setkeepalive() - if not ok then - ngx.log(ngx.ERR, err) - end - - ngx.thread.wait(co1) - ngx.thread.wait(co2) - ngx.thread.wait(co3) - ngx.say("all uthreads ok") - } - } ---- request -GET /t ---- response_body -too many waiting connect operations -start to handle uthread -continue to handle other uthread -start to handle uthread -continue to handle other uthread -all uthreads ok ---- no_error_log -[error] ---- grep_error_log eval: qr/queue connect operation for connection pool/ ---- grep_error_log_out -queue connect operation for connection pool -queue connect operation for connection pool - - - -=== TEST 39: conn queuing: in rewrite_by_lua ---- config - location /t { - set $port $TEST_NGINX_MEMCACHED_PORT; - - rewrite_by_lua_block { - local port = ngx.var.port - local opts = {pool_size = 1, backlog = 2} - - local conn_sock = function() - local sock, err = ngx.socket.connect("127.0.0.1", port, opts) - if not sock then - ngx.say(err) - return - end - ngx.say("start to handle uthread") - - ngx.sleep(0.01) - sock:close() - ngx.say("continue to handle other uthread") - end - - local sock, err = ngx.socket.connect("127.0.0.1", port, opts) - if not sock then - ngx.log(ngx.ERR, err) - return - end - - local co1 = ngx.thread.spawn(conn_sock) - local co2 = ngx.thread.spawn(conn_sock) - local co3 = ngx.thread.spawn(conn_sock) - - local ok, err = sock:setkeepalive() - if not ok then - ngx.log(ngx.ERR, err) - end - - ngx.thread.wait(co1) - ngx.thread.wait(co2) - ngx.thread.wait(co3) - ngx.say("all uthreads ok") - } - } ---- request -GET /t ---- response_body -too many waiting connect operations -start to handle uthread -continue to handle other uthread -start to handle uthread -continue to handle other uthread -all uthreads ok ---- no_error_log -[error] ---- grep_error_log eval: qr/queue connect operation for connection pool/ ---- grep_error_log_out -queue connect operation for connection pool -queue connect operation for connection pool - - - -=== TEST 40: conn queuing: in subrequest ---- config - set $port $TEST_NGINX_MEMCACHED_PORT; - - location /t { - content_by_lua_block { - local port = ngx.var.port - ngx.timer.at(0, function() - local opts = {pool_size = 1, backlog = 2} - local sock, err = ngx.socket.connect("127.0.0.1", port, opts) - if not sock then - ngx.log(ngx.ERR, err) - return - end - - ngx.sleep(0.1) - local ok, err = sock:setkeepalive() - if not ok then - ngx.log(ngx.ERR, err) - end - end) - - ngx.sleep(0.01) - local res1, res2, res3 = ngx.location.capture_multi{ - {"/conn"}, {"/conn"}, {"/conn"} - } - ngx.say(res1.body) - ngx.say(res2.body) - ngx.say(res3.body) - } - } - - location /conn { - content_by_lua_block { - local port = ngx.var.port - local sock, err = ngx.socket.connect("127.0.0.1", port) - if not sock then - ngx.print(err) - return - end - local ok, err = sock:setkeepalive() - if not ok then - ngx.print(err) - else - ngx.print("ok") - end - } - } ---- request -GET /t ---- response_body -ok -ok -too many waiting connect operations ---- no_error_log -[error] ---- grep_error_log eval: qr/queue connect operation for connection pool/ ---- grep_error_log_out -queue connect operation for connection pool -queue connect operation for connection pool - - - -=== TEST 41: conn queuing: timeouts when 'connect_timeout' is reached ---- config - location /t { - set $port $TEST_NGINX_MEMCACHED_PORT; - - content_by_lua_block { - local port = ngx.var.port - local opts = {pool_size = 1, backlog = 1} - local sock1 = ngx.socket.connect("127.0.0.1", port, opts) - - local sock2 = ngx.socket.tcp() - sock2:settimeouts(10, 3000, 3000) - local ok, err = sock2:connect("127.0.0.1", port, opts) - if not ok then - ngx.say(err) - end - } - } ---- request -GET /t ---- response_body -timeout ---- error_log eval -"lua tcp socket queued connect timed out, when trying to connect to 127.0.0.1:$ENV{TEST_NGINX_MEMCACHED_PORT}" - - - -=== TEST 42: conn queuing: set timeout via lua_socket_connect_timeout ---- config - lua_socket_connect_timeout 10ms; - location /t { - set $port $TEST_NGINX_MEMCACHED_PORT; - - content_by_lua_block { - local port = ngx.var.port - local opts = {pool_size = 1, backlog = 1} - local sock1 = ngx.socket.connect("127.0.0.1", port, opts) - - local sock2 = ngx.socket.tcp() - local ok, err = sock2:connect("127.0.0.1", port, opts) - if not ok then - ngx.say(err) - end - } - } ---- request -GET /t ---- response_body -timeout ---- error_log eval -"lua tcp socket queued connect timed out, when trying to connect to 127.0.0.1:$ENV{TEST_NGINX_MEMCACHED_PORT}" - - - -=== TEST 43: conn queuing: client aborting while connect operation is queued ---- config - location /t { - set $port $TEST_NGINX_MEMCACHED_PORT; - - content_by_lua_block { - local port = ngx.var.port - local opts = {pool_size = 1, backlog = 1} - local sock1 = ngx.socket.connect("127.0.0.1", port, opts) - - local sock2 = ngx.socket.tcp() - sock2:settimeouts(3000, 3000, 3000) - local ok, err = sock2:connect("127.0.0.1", port, opts) - if not ok then - ngx.say(err) - end - } - } ---- request -GET /t ---- ignore_response ---- timeout: 0.1 ---- abort ---- no_error_log -[error] - - - -=== TEST 44: conn queuing: resume next connect operation if resumed connect failed immediately ---- config - location /t { - set $port $TEST_NGINX_MEMCACHED_PORT; - - content_by_lua_block { - local port = ngx.var.port - local opts = {pool = "test", pool_size = 1, backlog = 2} - - local conn_sock = function(should_timeout) - local sock = ngx.socket.tcp() - local ok, err - if should_timeout then - ok, err = sock:connect("", port, opts) - else - ok, err = sock:connect("127.0.0.1", port, opts) - end - if not ok then - ngx.say(err) - return - end - ngx.say("connected in uthread") - sock:close() - end - - local sock, err = ngx.socket.connect("127.0.0.1", port, opts) - if not sock then - ngx.log(ngx.ERR, err) - return - end - - local co1 = ngx.thread.spawn(conn_sock, true) - local co2 = ngx.thread.spawn(conn_sock) - - local ok, err = sock:close() - if not ok then - ngx.log(ngx.ERR, err) - end - - ngx.thread.wait(co1) - ngx.thread.wait(co2) - ngx.say("ok") - } - } ---- request -GET /t ---- response_body -failed to parse host name "": no host -connected in uthread -ok ---- no_error_log -[error] - - - -=== TEST 45: conn queuing: resume connect operation if resumed connect failed (timeout) ---- config - resolver $TEST_NGINX_RESOLVER ipv6=off; - resolver_timeout 3s; - location /t { - set $port $TEST_NGINX_MEMCACHED_PORT; - - content_by_lua_block { - local port = ngx.var.port - local opts = {pool = "test", pool_size = 1, backlog = 1} - - local conn_sock = function(should_timeout) - local sock = ngx.socket.tcp() - local ok, err - if should_timeout then - sock:settimeouts(100, 3000, 3000) - ok, err = sock:connect("127.0.0.2", 12345, opts) - else - ok, err = sock:connect("127.0.0.1", port, opts) - end - if not ok then - ngx.say(err) - return - end - ngx.say("connected in uthread") - sock:close() - end - - local co1 = ngx.thread.spawn(conn_sock, true) - local co2 = ngx.thread.spawn(conn_sock) - - ngx.thread.wait(co1) - ngx.thread.wait(co2) - ngx.say("ok") - } - } ---- request -GET /t ---- response_body -timeout -connected in uthread -ok ---- error_log -queue connect operation for connection pool "test" -lua tcp socket connect timed out, when connecting to - - - -=== TEST 46: conn queuing: resume connect operation if resumed connect failed (could not be resolved) ---- config - resolver 127.0.0.2:12345 ipv6=off; - resolver_timeout 1s; - location /t { - set $port $TEST_NGINX_MEMCACHED_PORT; - - content_by_lua_block { - local port = ngx.var.port - local opts = {pool = "test", pool_size = 1, backlog = 1} - - local conn_sock = function(should_timeout) - local sock = ngx.socket.tcp() - local ok, err - if should_timeout then - sock:settimeouts(1, 3000, 3000) - ok, err = sock:connect("agentzh.org", 80, opts) - else - ok, err = sock:connect("127.0.0.1", port, opts) - end - if not ok then - ngx.say(err) - return - end - ngx.say("connected in uthread") - sock:close() - end - - local co1 = ngx.thread.spawn(conn_sock, true) - local co2 = ngx.thread.spawn(conn_sock) - - ngx.thread.wait(co1) - ngx.thread.wait(co2) - ngx.say("ok") - } - } ---- request -GET /t ---- response_body -agentzh.org could not be resolved (110: Operation timed out) -connected in uthread -ok ---- error_log -queue connect operation for connection pool "test" - - - -=== TEST 47: conn queuing: resume connect operation if resumed connect failed (connection refused) ---- config - location /t { - set $port $TEST_NGINX_MEMCACHED_PORT; - - content_by_lua_block { - local port = ngx.var.port - local opts = {pool = "test", pool_size = 1, backlog = 1} - - local conn_sock = function(should_timeout) - local sock = ngx.socket.tcp() - local ok, err - if should_timeout then - sock:settimeouts(100, 3000, 3000) - ok, err = sock:connect("127.0.0.1", 62345, opts) - else - ok, err = sock:connect("127.0.0.1", port, opts) - end - if not ok then - ngx.say(err) - return - end - ngx.say("connected in uthread") - sock:close() - end - - local co1 = ngx.thread.spawn(conn_sock, true) - local co2 = ngx.thread.spawn(conn_sock) - - ngx.thread.wait(co1) - ngx.thread.wait(co2) - ngx.say("ok") - } - } ---- request -GET /t ---- response_body -connection refused -connected in uthread -ok ---- error_log -queue connect operation for connection pool "test" - - - -=== TEST 48: conn queuing: resume connect operation if resumed connect failed (uthread aborted while resolving) ---- http_config - lua_package_path '../lua-resty-core/lib/?.lua;../lua-resty-lrucache/lib/?.lua;;'; ---- config - resolver 127.0.0.1 ipv6=off; - resolver_timeout 100s; - set $port $TEST_NGINX_MEMCACHED_PORT; - - location /sub { - content_by_lua_block { - local semaphore = require "ngx.semaphore" - local sem = semaphore.new() - - local function f() - sem:wait(0.1) - ngx.exit(0) - end - - local opts = {pool = "test", pool_size = 1, backlog = 1} - local port = ngx.var.port - ngx.timer.at(0, function() - sem:post() - local sock2, err = ngx.socket.connect("127.0.0.1", port, opts) - package.loaded.for_timer_to_resume:post() - if not sock2 then - ngx.log(ngx.ALERT, "resume connect failed: ", err) - return - end - - ngx.log(ngx.INFO, "resume success") - end) - - ngx.thread.spawn(f) - local sock1, err = ngx.socket.connect("openresty.org", 80, opts) - if not sock1 then - ngx.say(err) - return - end - } - } - - location /t { - content_by_lua_block { - local semaphore = require "ngx.semaphore" - local for_timer_to_resume = semaphore.new() - package.loaded.for_timer_to_resume = for_timer_to_resume - - ngx.location.capture("/sub") - for_timer_to_resume:wait(0.1) - } - } ---- request -GET /t ---- no_error_log -[alert] ---- error_log -resume success - - - -=== TEST 49: conn queuing: resume connect operation if resumed connect failed (uthread killed while resolving) ---- config - resolver 127.0.0.1 ipv6=off; - resolver_timeout 100s; - set $port $TEST_NGINX_MEMCACHED_PORT; - - location /t { - content_by_lua_block { - local opts = {pool = "test", pool_size = 1, backlog = 1} - local port = ngx.var.port - - local function resolve() - local sock1, err = ngx.socket.connect("openresty.org", 80, opts) - if not sock1 then - ngx.say(err) - return - end - end - - local th = ngx.thread.spawn(resolve) - local ok, err = ngx.thread.kill(th) - if not ok then - ngx.log(ngx.ALERT, "kill thread failed: ", err) - return - end - - local sock2, err = ngx.socket.connect("127.0.0.1", port, opts) - if not sock2 then - ngx.log(ngx.ALERT, "resume connect failed: ", err) - return - end - - ngx.log(ngx.INFO, "resume success") - } - } ---- request -GET /t ---- no_error_log -[alert] ---- error_log -resume success - - - -=== TEST 50: conn queuing: increase the counter for connections created before creating the pool with setkeepalive() ---- config - set $port $TEST_NGINX_MEMCACHED_PORT; - - location /t { - content_by_lua_block { - local function connect() - local sock, err = ngx.socket.connect("127.0.0.1", ngx.var.port) - if not sock then - error("connect failed: " .. err) - end - - return sock - end - - local sock1 = connect() - local sock2 = connect() - assert(sock1:setkeepalive()) - assert(sock2:setkeepalive()) - - local sock1 = connect() - local sock2 = connect() - assert(sock1:close()) - assert(sock2:close()) - - ngx.say("ok") - } - } ---- request -GET /t ---- no_error_log -[error] ---- response_body -ok - - - -=== TEST 51: conn queuing: only decrease the counter for connections which were counted by the pool ---- config - set $port $TEST_NGINX_MEMCACHED_PORT; - - location /t { - content_by_lua_block { - local function connect() - local sock, err = ngx.socket.connect("127.0.0.1", ngx.var.port) - if not sock then - error("connect failed: " .. err) - end - - return sock - end - - local sock1 = connect() - local sock2 = connect() - assert(sock1:setkeepalive(1000, 1)) - assert(sock2:setkeepalive(1000, 1)) - - local sock1 = connect() - local sock2 = connect() - assert(sock1:close()) - assert(sock2:close()) - - ngx.say("ok") - } - } ---- request -GET /t ---- no_error_log -[error] ---- response_body -ok - - - -=== TEST 52: conn queuing: clean up pending connect operations which are in queue ---- config - set $port $TEST_NGINX_MEMCACHED_PORT; - - location /sub { - content_by_lua_block { - local opts = {pool = "test", pool_size = 1, backlog = 1} - local sock, err = ngx.socket.connect("127.0.0.1", ngx.var.port, opts) - if not sock then - ngx.say("connect failed: " .. err) - return - end - - local function f() - assert(ngx.socket.connect("127.0.0.1", ngx.var.port, opts)) - end - - local th = ngx.thread.spawn(f) - local ok, err = ngx.thread.kill(th) - if not ok then - ngx.log(ngx.ERR, "kill thread failed: ", err) - return - end - - sock:close() - } - } - - location /t { - content_by_lua_block { - ngx.location.capture("/sub") - -- let pending connect operation resumes first - ngx.sleep(0) - ngx.say("ok") - } - } ---- request -GET /t ---- no_error_log -[error] ---- error_log -lua tcp socket abort queueing ---- response_body -ok diff --git a/debian/modules/http-lua/t/073-backtrace.t b/debian/modules/http-lua/t/073-backtrace.t index 663c3af..6c54692 100644 --- a/debian/modules/http-lua/t/073-backtrace.t +++ b/debian/modules/http-lua/t/073-backtrace.t @@ -21,10 +21,10 @@ __DATA__ --- config location /lua { content_by_lua - ' local function bar() + ' function bar() return lua_concat(3) end - local function foo() + function foo() bar() end foo() @@ -37,7 +37,7 @@ GET /lua attempt to call global 'lua_concat' : in function 'bar' :5: in function 'foo' -:7: in main chunk +:7: in function @@ -45,10 +45,10 @@ attempt to call global 'lua_concat' --- config location /lua { content_by_lua - ' local function bar() + ' function bar() error(nil) end - local function foo() + function foo() bar() end foo() @@ -64,7 +64,7 @@ GET /lua " in function 'error'", ": in function 'bar'", ":5: in function 'foo'", -qr/:7: in main chunk/, +qr/:7: in function /, ] @@ -125,7 +125,7 @@ probe process("$LIBLUA_PATH").function("lua_concat") { :63: in function 'func16' :67: in function 'func17' :71: in function 'func18' -:74: in main chunk +:74: in function diff --git a/debian/modules/http-lua/t/075-logby.t b/debian/modules/http-lua/t/075-logby.t index 8eece69..520c62e 100644 --- a/debian/modules/http-lua/t/075-logby.t +++ b/debian/modules/http-lua/t/075-logby.t @@ -220,7 +220,7 @@ failed to run log_by_lua*: unknown reason -=== TEST 11: globals sharing +=== TEST 11: globals get cleared for every single request --- config location /lua { echo ok; @@ -228,7 +228,6 @@ failed to run log_by_lua*: unknown reason if not foo then foo = 1 else - ngx.log(ngx.INFO, "old foo: ", foo) foo = foo + 1 end ngx.log(ngx.WARN, "foo = ", foo) @@ -238,9 +237,8 @@ failed to run log_by_lua*: unknown reason GET /lua --- response_body ok ---- grep_error_log eval: qr/old foo: \d+/ ---- grep_error_log_out eval -["", "old foo: 1\n"] +--- error_log +foo = 1 @@ -497,8 +495,7 @@ API disabled in the context of log_by_lua* location /t { echo ok; log_by_lua ' - local bar - local function foo() + function foo() bar() end diff --git a/debian/modules/http-lua/t/081-bytecode.t b/debian/modules/http-lua/t/081-bytecode.t index 92383bc..cb50e94 100644 --- a/debian/modules/http-lua/t/081-bytecode.t +++ b/debian/modules/http-lua/t/081-bytecode.t @@ -24,7 +24,7 @@ __DATA__ content_by_lua ' ngx.req.read_body(); local b = ngx.req.get_body_data(); - local f = io.open(ngx.var.realpath_root.."/test.lua", "w"); + f = io.open(ngx.var.realpath_root.."/test.lua", "w"); -- luajit bytecode: sub(149,-1), lua bytecode: sub(1,147) if jit then if not string.find(jit.version, "LuaJIT 2.0") then @@ -35,8 +35,7 @@ __DATA__ else f:write(string.sub(b, 1, 147)); end - f:close(); - local res = ngx.location.capture("/call"); + f:close(); res = ngx.location.capture("/call"); ngx.print(res.body) '; } @@ -61,15 +60,14 @@ __DATA__ content_by_lua ' ngx.req.read_body(); local b = ngx.req.get_body_data(); - local f = io.open(ngx.var.realpath_root.."/test.lua", "w"); + f = io.open(ngx.var.realpath_root.."/test.lua", "w"); -- luajit bytecode: sub(149,-1), lua bytecode: sub(1,147) if not package.loaded["jit"] then f:write(string.sub(b, 149)); else f:write(string.sub(b, 1, 147)); end - f:close(); - local res = ngx.location.capture("/call"); + f:close(); res = ngx.location.capture("/call"); if res.status == 200 then ngx.print(res.body) else @@ -87,7 +85,7 @@ __DATA__ --- response_body error --- error_log eval -qr/failed to load external Lua file ".*?test\.lua": .* cannot load incompatible bytecode/ +qr/failed to load external Lua file ".*?test\.lua": bad byte-code header/ @@ -98,15 +96,14 @@ qr/failed to load external Lua file ".*?test\.lua": .* cannot load incompatible content_by_lua ' ngx.req.read_body(); local b = ngx.req.get_body_data(); - local f = io.open(ngx.var.realpath_root.."/test.lua", "w"); + f = io.open(ngx.var.realpath_root.."/test.lua", "w"); -- luajit bytecode: sub(149,-1), lua bytecode: sub(1,147) if package.loaded["jit"] then f:write(string.sub(b, 149)); else f:write(string.sub(b, 1, 147)); end - f:close(); - local res = ngx.location.capture("/call"); + f:close(); res = ngx.location.capture("/call"); if res.status == 200 then ngx.print(res.body) else @@ -124,7 +121,7 @@ qr/failed to load external Lua file ".*?test\.lua": .* cannot load incompatible --- response_body error --- error_log -cannot load incompatible bytecode +bytecode format version unsupported @@ -135,7 +132,7 @@ cannot load incompatible bytecode content_by_lua ' ngx.req.read_body(); local b = ngx.req.get_body_data(); - local f = io.open(ngx.var.realpath_root.."/test.lua", "w"); + f = io.open(ngx.var.realpath_root.."/test.lua", "w"); -- luajit bytecode: sub(149,-1), lua bytecode: sub(1,147) local do_jit if jit then @@ -179,7 +176,7 @@ cannot load incompatible bytecode content_by_lua ' ngx.req.read_body(); local b = ngx.req.get_body_data(); - local f = io.open(ngx.var.realpath_root.."/test.lua", "w"); + f = io.open(ngx.var.realpath_root.."/test.lua", "w"); -- luajit bytecode: sub(149,-1), lua bytecode: sub(1,147) local jit; if package.loaded["jit"] then @@ -223,7 +220,7 @@ error content_by_lua ' ngx.req.read_body(); local b = ngx.req.get_body_data(); - local f = io.open(ngx.var.realpath_root.."/test.lua", "w"); + f = io.open(ngx.var.realpath_root.."/test.lua", "w"); -- luajit bytecode: sub(149,-1), lua bytecode: sub(1,147) if jit then if not string.find(jit.version, "LuaJIT 2.0") then @@ -259,9 +256,9 @@ error content_by_lua ' local bcsave = require "jit.bcsave" if jit then - local prefix = "$TEST_NGINX_SERVER_ROOT" - local infile = prefix .. "/html/a.lua" - local outfile = prefix .. "/html/a.luac" + local prefix = ngx.config.prefix() + local infile = prefix .. "html/a.lua" + local outfile = prefix .. "html/a.luac" bcsave.start("-s", infile, outfile) return ngx.exec("/call") end @@ -292,9 +289,9 @@ ngx.status = 201 ngx.say("hello from Lua!") content_by_lua ' local bcsave = require "jit.bcsave" if jit then - local prefix = "$TEST_NGINX_SERVER_ROOT" - local infile = prefix .. "/html/a.lua" - local outfile = prefix .. "/html/a.luac" + local prefix = ngx.config.prefix() + local infile = prefix .. "html/a.lua" + local outfile = prefix .. "html/a.luac" bcsave.start("-g", infile, outfile) return ngx.exec("/call") end @@ -323,9 +320,9 @@ ngx.status = 201 ngx.say("hello from Lua!") --- config location = /t { content_by_lua_block { - local f = assert(loadstring("local a = 1 ngx.say('a = ', a)", "=code")) + local f = assert(loadstring("a = a and a + 1 or 1 ngx.say('a = ', a)", "=code")) local bc = string.dump(f) - local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/a.luac", "w")) + local f = assert(io.open("t/servroot/html/a.luac", "w")) f:write(bc) f:close() } @@ -352,9 +349,9 @@ a = 1 --- config location = /t { content_by_lua_block { - local f = assert(loadstring("local a = 1 ngx.say('a = ', a)", "=code")) + local f = assert(loadstring("a = a and a + 1 or 1 ngx.say('a = ', a)", "=code")) local bc = string.dump(f, true) - local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/a.luac", "w")) + local f = assert(io.open("t/servroot/html/a.luac", "w")) f:write(bc) f:close() } diff --git a/debian/modules/http-lua/t/082-body-filter.t b/debian/modules/http-lua/t/082-body-filter.t index 5f765fa..98efa84 100644 --- a/debian/modules/http-lua/t/082-body-filter.t +++ b/debian/modules/http-lua/t/082-body-filter.t @@ -460,8 +460,7 @@ GET /t --- config location /t { body_filter_by_lua ' - local bar - local function foo() + function foo() bar() end diff --git a/debian/modules/http-lua/t/084-inclusive-receiveuntil.t b/debian/modules/http-lua/t/084-inclusive-receiveuntil.t index 66be893..f7d5d3d 100644 --- a/debian/modules/http-lua/t/084-inclusive-receiveuntil.t +++ b/debian/modules/http-lua/t/084-inclusive-receiveuntil.t @@ -56,7 +56,7 @@ __DATA__ local reader = sock:receiveuntil("abcabd", { inclusive = true }) for i = 1, 3 do - local line, err, part = reader() + line, err, part = reader() if line then ngx.say("read: ", line) @@ -128,7 +128,7 @@ close: 1 nil local reader = sock:receiveuntil("abcabdabcabe", { inclusive = true }) for i = 1, 2 do - local line, err, part = reader() + line, err, part = reader() if line then ngx.say("read: ", line) @@ -200,7 +200,7 @@ close: 1 nil local reader = sock:receiveuntil("abcabd", { inclusive = true }) for i = 1, 3 do - local line, err, part = reader() + line, err, part = reader() if line then ngx.say("read: ", line) @@ -272,7 +272,7 @@ close: 1 nil local reader = sock:receiveuntil("aa", { inclusive = nil }) for i = 1, 2 do - local line, err, part = reader() + line, err, part = reader() if line then ngx.say("read: ", line) @@ -343,7 +343,7 @@ close: 1 nil local reader = sock:receiveuntil("aa", { inclusive = false }) for i = 1, 2 do - local line, err, part = reader() + line, err, part = reader() if line then ngx.say("read: ", line) @@ -414,7 +414,7 @@ close: 1 nil local reader = sock:receiveuntil("aa", { inclusive = true }) for i = 1, 2 do - local line, err, part = reader() + line, err, part = reader() if line then ngx.say("read: ", line) @@ -485,7 +485,7 @@ close: 1 nil local reader = sock:receiveuntil("aa", { inclusive = "true" }) for i = 1, 2 do - local line, err, part = reader() + line, err, part = reader() if line then ngx.say("read: ", line) @@ -552,7 +552,7 @@ bad "inclusive" option value type: string local reader = sock:receiveuntil("aa", { inclusive = "true" }) for i = 1, 2 do - local line, err, part = reader() + line, err, part = reader() if line then ngx.say("read: ", line) @@ -620,7 +620,7 @@ bad "inclusive" option value type: string local reader = sock:receiveuntil("--abc", { inclusive = true }) for i = 1, 7 do - local line, err, part = reader(4) + line, err, part = reader(4) if line then ngx.say("read: ", line) @@ -697,7 +697,7 @@ close: 1 nil local reader = sock:receiveuntil("--abc", { inclusive = true }) for i = 1, 7 do - local line, err, part = reader(4) + line, err, part = reader(4) if line then ngx.say("read: ", line) diff --git a/debian/modules/http-lua/t/087-udp-socket.t b/debian/modules/http-lua/t/087-udp-socket.t index dc6cad5..8bedc32 100644 --- a/debian/modules/http-lua/t/087-udp-socket.t +++ b/debian/modules/http-lua/t/087-udp-socket.t @@ -555,7 +555,7 @@ lua udp socket read timed out local udp = socket.udp() - udp:settimeout(5000) -- 5 sec + udp:settimeout(2000) -- 2 sec local ok, err = udp:setpeername("$TEST_NGINX_RESOLVER", 53) if not ok then @@ -824,7 +824,7 @@ probe syscall.socket.return, syscall.connect.return { === TEST 15: bad request tries to setpeer --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config server_tokens off; location = /main { @@ -881,7 +881,7 @@ qr/runtime error: content_by_lua\(nginx\.conf:\d+\):14: bad request/ === TEST 16: bad request tries to send --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config server_tokens off; location = /main { @@ -938,7 +938,7 @@ qr/runtime error: content_by_lua\(nginx\.conf:\d+\):14: bad request/ === TEST 17: bad request tries to receive --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config server_tokens off; location = /main { @@ -995,7 +995,7 @@ qr/runtime error: content_by_lua\(nginx\.conf:\d+\):14: bad request/ === TEST 18: bad request tries to close --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config server_tokens off; location = /main { @@ -1052,7 +1052,7 @@ qr/runtime error: content_by_lua\(nginx\.conf:\d+\):14: bad request/ === TEST 19: bad request tries to receive --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config server_tokens off; location = /main { diff --git a/debian/modules/http-lua/t/090-log-socket-errors.t b/debian/modules/http-lua/t/090-log-socket-errors.t index f5a9f80..16576b6 100644 --- a/debian/modules/http-lua/t/090-log-socket-errors.t +++ b/debian/modules/http-lua/t/090-log-socket-errors.t @@ -28,7 +28,7 @@ __DATA__ lua_socket_log_errors off; content_by_lua ' local sock = ngx.socket.tcp() - local ok, err = sock:connect("127.0.0.2", 12345) + local ok, err = sock:connect("agentzh.org", 12345) ngx.say(err) '; } @@ -50,7 +50,7 @@ timeout lua_socket_log_errors on; content_by_lua ' local sock = ngx.socket.tcp() - local ok, err = sock:connect("127.0.0.2", 12345) + local ok, err = sock:connect("agentzh.org", 12345) ngx.say(err) '; } @@ -59,7 +59,7 @@ GET /t --- response_body timeout --- error_log -lua tcp socket connect timed out, when connecting to 127.0.0.2:12345 +lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 @@ -72,7 +72,7 @@ lua tcp socket connect timed out, when connecting to 127.0.0.2:12345 lua_socket_read_timeout 1ms; content_by_lua ' local sock = ngx.socket.udp() - local ok, err = sock:setpeername("127.0.0.2", 12345) + local ok, err = sock:setpeername("agentzh.org", 12345) ok, err = sock:receive() ngx.say(err) '; @@ -95,7 +95,7 @@ lua udp socket read timed out lua_socket_read_timeout 1ms; content_by_lua ' local sock = ngx.socket.udp() - local ok, err = sock:setpeername("127.0.0.2", 12345) + local ok, err = sock:setpeername("agentzh.org", 12345) ok, err = sock:receive() ngx.say(err) '; diff --git a/debian/modules/http-lua/t/091-coroutine.t b/debian/modules/http-lua/t/091-coroutine.t index 7cf60f9..bceb512 100644 --- a/debian/modules/http-lua/t/091-coroutine.t +++ b/debian/modules/http-lua/t/091-coroutine.t @@ -85,7 +85,7 @@ __DATA__ content_by_lua ' local cc, cr, cy = coroutine.create, coroutine.resume, coroutine.yield - local function f() + function f() local cnt = 0 for i = 1, 20 do ngx.say("Hello, ", cnt) @@ -120,7 +120,7 @@ Hello, 2 --- config location /lua { content_by_lua ' - local function f(fid) + function f(fid) local cnt = 0 while true do ngx.say("cc", fid, ": ", cnt) @@ -163,7 +163,7 @@ cc3: 2 resolver $TEST_NGINX_RESOLVER ipv6=off; location /lua { content_by_lua ' - local function worker(url) + function worker(url) local sock = ngx.socket.tcp() local ok, err = sock:connect(url, 80) coroutine.yield() @@ -178,7 +178,7 @@ cc3: 2 local urls = { "agentzh.org", - "openresty.com", + "iscribblet.org", "openresty.org" } @@ -204,7 +204,7 @@ cc3: 2 GET /lua --- response_body successfully connected to: agentzh.org -successfully connected to: openresty.com +successfully connected to: iscribblet.org successfully connected to: openresty.org *** All Done *** --- no_error_log @@ -218,14 +218,14 @@ successfully connected to: openresty.org location /lua { content_by_lua ' -- generate all the numbers from 2 to n - local function gen (n) + function gen (n) return coroutine.wrap(function () for i=2,n do coroutine.yield(i) end end) end -- filter the numbers generated by g, removing multiples of p - local function filter (p, g) + function filter (p, g) return coroutine.wrap(function () while 1 do local n = g() @@ -235,8 +235,8 @@ successfully connected to: openresty.org end) end - local N = 10 - local x = gen(N) -- generate primes up to N + N = 10 + x = gen(N) -- generate primes up to N while 1 do local n = x() -- pick a number until done if n == nil then break end @@ -264,14 +264,14 @@ GET /lua coroutine.create = nil coroutine.resume = nil -- generate all the numbers from 2 to n - local function gen (n) + function gen (n) return coroutine.wrap(function () for i=2,n do coroutine.yield(i) end end) end -- filter the numbers generated by g, removing multiples of p - local function filter (p, g) + function filter (p, g) return coroutine.wrap(function () while 1 do local n = g() @@ -281,8 +281,8 @@ GET /lua end) end - local N = 10 - local x = gen(N) -- generate primes up to N + N = 10 + x = gen(N) -- generate primes up to N while 1 do local n = x() -- pick a number until done if n == nil then break end @@ -307,7 +307,7 @@ GET /lua --- config location /lua { content_by_lua ' - local function generatefib (n) + function generatefib (n) return coroutine.wrap(function () local a,b = 1, 1 while a <= n do @@ -362,7 +362,7 @@ GET /lua resolver $TEST_NGINX_RESOLVER ipv6=off; location /lua { content_by_lua ' - local function worker(url) + function worker(url) local sock = ngx.socket.tcp() local ok, err = sock:connect(url, 80) coroutine.yield() @@ -377,7 +377,7 @@ GET /lua local urls = { "agentzh.org", - "openresty.com", + "iscribblet.org", "openresty.org" } @@ -398,7 +398,7 @@ GET /lua GET /lua --- response_body successfully connected to: agentzh.org -successfully connected to: openresty.com +successfully connected to: iscribblet.org successfully connected to: openresty.org *** All Done *** --- no_error_log @@ -414,7 +414,7 @@ successfully connected to: openresty.org local cc, cr, cy = coroutine.create, coroutine.resume, coroutine.yield local st, rn = coroutine.status, coroutine.running - local function f(self) + function f(self) local cnt = 0 if rn() ~= self then ngx.say("error"); return end ngx.say("running: ", st(self)) --running @@ -509,7 +509,7 @@ GET /lua --- config location /lua { content_by_lua ' - local function print(...) + function print(...) local args = {...} local is_first = true for i,v in ipairs(args) do @@ -523,12 +523,12 @@ GET /lua ngx.print("\\\n") end - local function foo (a) + function foo (a) print("foo", a) return coroutine.yield(2*a) end - local co = coroutine.create(function (a,b) + co = coroutine.create(function (a,b) print("co-body", a, b) local r = foo(a+1) print("co-body", r) @@ -566,8 +566,7 @@ main false cannot resume dead coroutine local create = coroutine.create local resume = coroutine.resume local yield = coroutine.yield - local g - local function f() + function f() ngx.say("f begin") yield() local c2 = create(g) @@ -628,9 +627,8 @@ main done local yield = coroutine.yield local code = 400 - local g - local function f() + function f() local c2 = create(g) yield() code = code + 1 @@ -685,9 +683,8 @@ exit local yield = coroutine.yield local code = 0 - local g - local function f() + function f() local c2 = create(g) yield() code = code + 1 @@ -743,7 +740,7 @@ num: 3 location /lua { echo hello; header_filter_by_lua ' - local function f() + function f() yield() end @@ -767,13 +764,13 @@ API disabled in the context of header_filter_by_lua* local c1, c2 - local function f() + function f() print("f 1") print(coroutine.resume(c2)) print("f 2") end - local function g() + function g() print("g 1") -- print(coroutine.resume(c1)) print("g 2") @@ -806,13 +803,13 @@ f 2 local c1, c2 - local function f() + function f() print("f 1") print(coroutine.resume(c2)) print("f 2") end - local function g() + function g() print("g 1") print(coroutine.resume(c1)) print("g 2") @@ -862,7 +859,7 @@ falsecannot resume running coroutine location /t { content_by_lua ' local co - local function f() + function f() ngx.say("f: ", coroutine.status(co)) ngx.say("f: ", coroutine.resume(co)) end @@ -888,7 +885,7 @@ chunk: true location /t { content_by_lua ' local co - local function f() + function f() error("bad") end co = coroutine.create(f) @@ -993,7 +990,7 @@ test10 resolver $TEST_NGINX_RESOLVER ipv6=off; location /lua { content_by_lua ' - local function worker(url) + function worker(url) local sock = ngx.socket.tcp() local ok, err = sock:connect(url, 80) coroutine.yield() @@ -1047,7 +1044,7 @@ successfully connected to: agentzh.org resolver $TEST_NGINX_RESOLVER ipv6=off; location /lua { content_by_lua ' - local function worker(url) + function worker(url) local sock = ngx.socket.tcp() local ok, err = sock:connect(url, 80) coroutine.yield() @@ -1107,7 +1104,7 @@ successfully connected to: agentzh.org --- config location /cotest { content_by_lua ' - local function generator() + function generator() return co_wrap(function() co_yield("data") end) @@ -1136,7 +1133,7 @@ data --- config location /cotest { content_by_lua ' - local function generator() + function generator() return co_wrap(function() co_yield("data") end) @@ -1169,7 +1166,7 @@ data content_by_lua ' local cc, cr, cy = coroutine.create, coroutine.resume, coroutine.yield - local function f() + function f() return 3 end @@ -1202,7 +1199,7 @@ ok local coroutine = require "coroutine" local cc, cr, cy = coroutine.create, coroutine.resume, coroutine.yield - local function f() + function f() local cnt = 0 for i = 1, 20 do ngx.say("Hello, ", cnt) @@ -1241,7 +1238,7 @@ Hello, 2 header_filter_by_lua ' local cc, cr, cy = coroutine.create, coroutine.resume, coroutine.yield - local function f() + function f() local cnt = 0 for i = 1, 20 do print("co yield: ", cnt) @@ -1281,7 +1278,7 @@ co yield: 2 body_filter_by_lua ' local cc, cr, cy = coroutine.create, coroutine.resume, coroutine.yield - local function f() + function f() local cnt = 0 for i = 1, 20 do print("co yield: ", cnt) diff --git a/debian/modules/http-lua/t/093-uthread-spawn.t b/debian/modules/http-lua/t/093-uthread-spawn.t index ab6db2f..b622d30 100644 --- a/debian/modules/http-lua/t/093-uthread-spawn.t +++ b/debian/modules/http-lua/t/093-uthread-spawn.t @@ -24,7 +24,7 @@ __DATA__ --- config location /lua { content_by_lua ' - local function f() + function f() ngx.say("hello in thread") end @@ -58,11 +58,11 @@ after --- config location /lua { content_by_lua ' - local function f() + function f() ngx.say("in thread 1") end - local function g() + function g() ngx.say("in thread 2") end @@ -107,7 +107,7 @@ after 2 --- config location /lua { content_by_lua ' - local function f() + function f() ngx.say("before sleep") ngx.sleep(0.1) ngx.say("after sleep") @@ -144,13 +144,13 @@ after sleep --- config location /lua { content_by_lua ' - local function f() + function f() ngx.say("1: before sleep") ngx.sleep(0.2) ngx.say("1: after sleep") end - local function g() + function g() ngx.say("2: before sleep") ngx.sleep(0.1) ngx.say("2: after sleep") @@ -200,7 +200,7 @@ delete thread 2 --- config location /lua { content_by_lua ' - local function f() + function f() ngx.blah() end @@ -231,9 +231,9 @@ qr/lua user thread aborted: runtime error: content_by_lua\(nginx\.conf:\d+\):3: --- config location /lua { content_by_lua ' - local function f() + function f() ngx.say("before capture") - local res = ngx.location.capture("/proxy") + res = ngx.location.capture("/proxy") ngx.say("after capture: ", res.body) end @@ -277,7 +277,7 @@ after capture: hello world --- config location /lua { content_by_lua ' - local function f() + function f() ngx.say("before capture") local res = ngx.location.capture("/proxy?foo") ngx.say("after capture: ", res.body) @@ -330,7 +330,7 @@ after capture: hello foo --- config location /lua { content_by_lua ' - local function f() + function f() ngx.say("before capture") local res = ngx.location.capture("/proxy?foo") ngx.say("after capture: ", res.body) @@ -384,13 +384,13 @@ capture: hello bar --- config location /lua { content_by_lua ' - local function f() + function f() ngx.say("f: before capture") local res = ngx.location.capture("/proxy?foo") ngx.say("f: after capture: ", res.body) end - local function g() + function g() ngx.say("g: before capture") local res = ngx.location.capture("/proxy?bah") ngx.say("g: after capture: ", res.body) @@ -462,8 +462,7 @@ g: after capture: hello bah --- config location /lua { content_by_lua ' - local g - local function f() + function f() ngx.say("before g") ngx.thread.spawn(g) ngx.say("after g") @@ -509,8 +508,7 @@ after g --- config location /lua { content_by_lua ' - local g - local function f() + function f() ngx.say("before g") ngx.thread.spawn(g) ngx.say("after g") @@ -558,7 +556,7 @@ hello in g() location /lua { content_by_lua ' local co - local function f() + function f() co = coroutine.running() ngx.sleep(0.1) end @@ -591,7 +589,7 @@ status: running location /lua { content_by_lua ' local co - local function f() + function f() co = coroutine.running() end @@ -623,8 +621,7 @@ status: zombie location /lua { content_by_lua ' local co - local g - local function f() + function f() co = coroutine.running() local co2 = coroutine.create(g) coroutine.resume(co2) @@ -663,8 +660,7 @@ status: normal --- config location /lua { content_by_lua ' - local g - local function f() + function f() ngx.say("before g") ngx.thread.spawn(g) ngx.say("after g") @@ -711,7 +707,7 @@ after f content_by_lua ' local yield = coroutine.yield - local function f() + function f() local self = coroutine.running() ngx.say("f 1") yield(self) @@ -764,7 +760,7 @@ f 3 content_by_lua ' local yield = coroutine.yield - local function f() + function f() local self = coroutine.running() ngx.say("f 1") yield(self) @@ -773,7 +769,7 @@ f 3 ngx.say("f 3") end - local function g() + function g() local self = coroutine.running() ngx.say("g 1") yield(self) @@ -820,7 +816,7 @@ g 3 --- config location /lua { content_by_lua ' - local function f() + function f() ngx.say("hello in thread") coroutine.yield(coroutine.running) ngx.flush(true) @@ -857,12 +853,12 @@ after --- config location /lua { content_by_lua ' - local function f() + function f() ngx.say("hello from f") ngx.flush(true) end - local function g() + function g() ngx.say("hello from g") ngx.flush(true) end @@ -908,7 +904,7 @@ hello from g --- config location /lua { content_by_lua ' - local function f() + function f() local sock = ngx.socket.tcp() local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_MEMCACHED_PORT) if not ok then @@ -960,7 +956,7 @@ received: OK --- config location /lua { content_by_lua ' - local function f() + function f() local sock = ngx.socket.udp() local ok, err = sock:setpeername("127.0.0.1", 12345) local bytes, err = sock:send("blah") @@ -1022,7 +1018,7 @@ after)$ --- config location /lua { content_by_lua ' - local function f() + function f() ngx.req.read_body() local body = ngx.req.get_body_data() ngx.say("body: ", body) @@ -1067,7 +1063,7 @@ body: hello world)$ --- config location /lua { content_by_lua ' - local function f() + function f() local sock = ngx.req.socket() local body, err = sock:receive(11) if not body then @@ -1117,7 +1113,7 @@ body: hello world)$ --- config location /lua { content_by_lua ' - local function f(a, b) + function f(a, b) ngx.say("hello ", a, " and ", b) end @@ -1651,7 +1647,7 @@ ok --- config location /lua { content_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.say("f") end diff --git a/debian/modules/http-lua/t/094-uthread-exit.t b/debian/modules/http-lua/t/094-uthread-exit.t index 58d8d0b..2f7d9ba 100644 --- a/debian/modules/http-lua/t/094-uthread-exit.t +++ b/debian/modules/http-lua/t/094-uthread-exit.t @@ -24,7 +24,7 @@ __DATA__ --- config location /lua { content_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.exit(0) end @@ -87,7 +87,7 @@ hello in thread --- config location /lua { content_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -171,13 +171,13 @@ after --- config location /lua { content_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.say("f") ngx.exit(0) end - local function g() + function g() ngx.sleep(1) ngx.say("g") end @@ -261,7 +261,7 @@ f --- config location /lua { content_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.say("exiting the user thread") ngx.exit(0) @@ -297,10 +297,10 @@ exiting the user thread === TEST 5: exit in user thread (entry thread is still pending on the DNS resolver for ngx.socket.tcp) --- config location /lua { - resolver 127.0.0.2:12345; + resolver agentzh.org; resolver_timeout 12s; content_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.001) ngx.exit(0) @@ -393,10 +393,10 @@ after === TEST 6: exit in user thread (entry thread is still pending on the DNS resolver for ngx.socket.udp) --- config location /lua { - resolver 127.0.0.2:12345; + resolver agentzh.org; resolver_timeout 12s; content_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.001) ngx.exit(0) @@ -490,7 +490,7 @@ after --- config location /lua { content_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -501,7 +501,7 @@ after ngx.say("after") local sock = ngx.socket.tcp() sock:settimeout(12000) - local ok, err = sock:connect("127.0.0.2", 12345) + local ok, err = sock:connect("172.105.207.225", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -580,7 +580,7 @@ after --- config location /lua { content_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -680,7 +680,7 @@ after --- config location /lua { content_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -786,7 +786,7 @@ after --- config location /lua { content_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -881,7 +881,7 @@ after --- config location /lua { content_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -974,7 +974,7 @@ after location /lua { client_body_timeout 12000ms; content_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -1059,7 +1059,7 @@ after location /lua { client_body_timeout 12000ms; content_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(0) @@ -1142,7 +1142,7 @@ attempt to abort with pending subrequests location /lua { client_body_timeout 12000ms; content_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.exit(0) end @@ -1225,7 +1225,7 @@ attempt to abort with pending subrequests location /lua { client_body_timeout 12000ms; content_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.exit(0) end @@ -1315,7 +1315,7 @@ attempt to abort with pending subrequests location /lua { client_body_timeout 12000ms; content_by_lua ' - local function f() + function f() ngx.location.capture_multi{ {"/echo"}, {"/sleep"} @@ -1407,7 +1407,7 @@ attempt to abort with pending subrequests location /lua { client_body_timeout 12000ms; content_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(444) @@ -1490,7 +1490,7 @@ free request location /lua { client_body_timeout 12000ms; content_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(408) @@ -1573,7 +1573,7 @@ free request location /lua { client_body_timeout 12000ms; content_by_lua ' - local function f() + function f() ngx.say("hello in thread") ngx.sleep(0.1) ngx.exit(499) diff --git a/debian/modules/http-lua/t/095-uthread-exec.t b/debian/modules/http-lua/t/095-uthread-exec.t index 7bf37c0..56156c4 100644 --- a/debian/modules/http-lua/t/095-uthread-exec.t +++ b/debian/modules/http-lua/t/095-uthread-exec.t @@ -23,7 +23,7 @@ __DATA__ --- config location /lua { content_by_lua ' - local function f() + function f() ngx.exec("/foo") end @@ -58,7 +58,7 @@ i am foo --- config location /lua { content_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.exec("/foo") end @@ -93,7 +93,7 @@ i am foo --- config location /lua { content_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.exec("/foo") end @@ -175,12 +175,12 @@ hello foo --- config location /lua { content_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.exec("/foo") end - local function g() + function g() ngx.sleep(1) end @@ -267,7 +267,7 @@ hello foo location /lua { client_body_timeout 12000ms; content_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.exec("/foo") end @@ -348,7 +348,7 @@ attempt to abort with pending subrequests location /lua { client_body_timeout 12000ms; content_by_lua ' - local function f() + function f() ngx.location.capture("/sleep") ngx.say("end") end diff --git a/debian/modules/http-lua/t/096-uthread-redirect.t b/debian/modules/http-lua/t/096-uthread-redirect.t index 95bff01..003c642 100644 --- a/debian/modules/http-lua/t/096-uthread-redirect.t +++ b/debian/modules/http-lua/t/096-uthread-redirect.t @@ -25,7 +25,7 @@ __DATA__ location /lua { client_body_timeout 12000ms; content_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.redirect(301) end @@ -114,7 +114,7 @@ attempt to abort with pending subrequests --- config location /lua { content_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.redirect(301) end @@ -194,7 +194,7 @@ free request location /lua { client_body_timeout 12000ms; content_by_lua ' - local function f() + function f() ngx.location.capture_multi{ {"/echo"}, {"/sleep"} diff --git a/debian/modules/http-lua/t/097-uthread-rewrite.t b/debian/modules/http-lua/t/097-uthread-rewrite.t index 998e256..2f0c06f 100644 --- a/debian/modules/http-lua/t/097-uthread-rewrite.t +++ b/debian/modules/http-lua/t/097-uthread-rewrite.t @@ -23,7 +23,7 @@ __DATA__ --- config location /lua { rewrite_by_lua ' - local function f() + function f() ngx.req.set_uri("/foo", true) end @@ -58,7 +58,7 @@ i am foo --- config location /lua { rewrite_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.req.set_uri("/foo", true) end @@ -93,7 +93,7 @@ i am foo --- config location /lua { rewrite_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.req.set_uri("/foo", true) end @@ -175,12 +175,12 @@ hello foo --- config location /lua { rewrite_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.req.set_uri("/foo", true) end - local function g() + function g() ngx.sleep(1) end @@ -267,7 +267,7 @@ hello foo location /lua { client_body_timeout 12000ms; rewrite_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.req.set_uri("/foo", true) end diff --git a/debian/modules/http-lua/t/098-uthread-wait.t b/debian/modules/http-lua/t/098-uthread-wait.t index c2819ae..4948596 100644 --- a/debian/modules/http-lua/t/098-uthread-wait.t +++ b/debian/modules/http-lua/t/098-uthread-wait.t @@ -23,7 +23,7 @@ __DATA__ --- config location /lua { content_by_lua ' - local function f() + function f() ngx.say("hello in thread") return "done" end @@ -72,7 +72,7 @@ done --- config location /lua { content_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.say("hello in thread") return "done" @@ -120,13 +120,13 @@ done --- config location /lua { content_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.say("f: hello") return "done" end - local function g() + function g() ngx.sleep(0.2) ngx.say("g: hello") return "done" @@ -200,13 +200,13 @@ f: done --- config location /lua { content_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.say("f: hello") return "done" end - local function g() + function g() ngx.sleep(0.2) ngx.say("g: hello") return "done" @@ -228,7 +228,7 @@ f: done ngx.say("g thread created: ", coroutine.status(tg)) - local ok, res = ngx.thread.wait(tf) + ok, res = ngx.thread.wait(tf) if not ok then ngx.say("failed to wait f: ", res) return @@ -281,7 +281,7 @@ g: done --- config location /lua { content_by_lua ' - local function f() + function f() ngx.say("hello in thread") return "done", 3.14 end @@ -330,7 +330,7 @@ res: done 3.14 --- config location /lua { content_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.say("hello in thread") return "done", 3.14 @@ -378,7 +378,7 @@ res: done 3.14 --- config location /lua { content_by_lua ' - local function f() + function f() ngx.say("hello in thread") error("bad bad!") end @@ -427,7 +427,7 @@ qr/lua user thread aborted: runtime error: content_by_lua\(nginx\.conf:\d+\):4: --- config location /lua { content_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.say("hello in thread") error("bad bad!") @@ -477,12 +477,12 @@ qr/lua user thread aborted: runtime error: content_by_lua\(nginx\.conf:\d+\):5: --- config location /lua { content_by_lua ' - local function g() + function g() ngx.say("hello in thread") return "done" end - local function f() + function f() local t, err = ngx.thread.spawn(g) if not t then ngx.say("failed to spawn thread: ", err) @@ -533,13 +533,13 @@ done --- config location /lua { content_by_lua ' - local function g() + function g() ngx.sleep(0.1) ngx.say("hello in thread") return "done" end - local function f() + function f() local t, err = ngx.thread.spawn(g) if not t then ngx.say("failed to spawn thread: ", err) @@ -593,12 +593,12 @@ done -- local out = function (...) ngx.log(ngx.ERR, ...) end local out = ngx.say - local function f() + function f() out("f: hello") return "f done" end - local function g() + function g() out("g: hello") return "g done" end @@ -668,13 +668,13 @@ g status: zombie -- local out = function (...) ngx.log(ngx.ERR, ...) end local out = ngx.say - local function f() + function f() ngx.sleep(0.1) out("f: hello") return "f done" end - local function g() + function g() ngx.sleep(0.2) out("g: hello") return "g done" @@ -745,13 +745,13 @@ g: hello -- local out = function (...) ngx.log(ngx.ERR, ...) end local out = ngx.say - local function f() + function f() ngx.sleep(0.2) out("f: hello") return "f done" end - local function g() + function g() ngx.sleep(0.1) out("g: hello") return "g done" @@ -822,12 +822,12 @@ f: hello -- local out = function (...) ngx.log(ngx.ERR, ...) end local out = ngx.say - local function f() + function f() out("f: hello") error("f done") end - local function g() + function g() out("g: hello") error("g done") end @@ -896,13 +896,13 @@ qr/lua user thread aborted: runtime error: content_by_lua\(nginx\.conf:\d+\):7: -- local out = function (...) ngx.log(ngx.ERR, ...) end local out = ngx.say - local function f() + function f() ngx.sleep(0.1) out("f: hello") error("f done") end - local function g() + function g() ngx.sleep(0.2) out("g: hello") error("g done") @@ -969,13 +969,13 @@ qr/lua user thread aborted: runtime error: content_by_lua\(nginx\.conf:\d+\):8: --- config location /lua { content_by_lua ' - local function f() + function f() ngx.sleep(0.1) ngx.say("f: hello") return "done" end - local function g() + function g() ngx.sleep(0.2) ngx.say("g: hello") return "done" @@ -997,7 +997,7 @@ qr/lua user thread aborted: runtime error: content_by_lua\(nginx\.conf:\d+\):8: ngx.say("g thread created: ", coroutine.status(tg)) - local ok, res = ngx.thread.wait(tf, tg) + ok, res = ngx.thread.wait(tf, tg) if not ok then ngx.say("failed to wait: ", res) return @@ -1038,13 +1038,13 @@ res: done --- config location /lua { content_by_lua ' - local function f() + function f() ngx.sleep(0.2) ngx.say("f: hello") return "f done" end - local function g() + function g() ngx.sleep(0.1) ngx.say("g: hello") return "g done" @@ -1066,7 +1066,7 @@ res: done ngx.say("g thread created: ", coroutine.status(tg)) - local ok, res = ngx.thread.wait(tf, tg) + ok, res = ngx.thread.wait(tf, tg) if not ok then ngx.say("failed to wait: ", res) return @@ -1109,12 +1109,12 @@ res: g done content_by_lua ' local t - local function f() + function f() ngx.sleep(0.1) return "done" end - local function g() + function g() t = ngx.thread.spawn(f) end @@ -1154,7 +1154,7 @@ only the parent coroutine can wait on the thread --- config location /lua { content_by_lua ' - local function f() + function f() ngx.sleep(0.1) coroutine.yield() return "done" @@ -1192,7 +1192,7 @@ qr/lua entry thread aborted: runtime error: content_by_lua\(nginx\.conf:\d+\):11 --- config location /lua { content_by_lua ' - local function f() + function f() ngx.sleep(0.1) collectgarbage() error("f done") @@ -1228,7 +1228,7 @@ qr/lua user thread aborted: runtime error: content_by_lua\(nginx\.conf:\d+\):5: --- config location /lua { content_by_lua ' - local function f() + function f() ngx.say("hello in thread") return "done" end @@ -1283,7 +1283,7 @@ failed to run thread: already waited or killed --- config location /lua { content_by_lua ' - local function f() + function f() -- ngx.say("hello in thread") return "done" end diff --git a/debian/modules/http-lua/t/099-c-api.t b/debian/modules/http-lua/t/099-c-api.t index 5033462..a0b375c 100644 --- a/debian/modules/http-lua/t/099-c-api.t +++ b/debian/modules/http-lua/t/099-c-api.t @@ -86,7 +86,7 @@ dogs zone: defined local buf = ffi.new("char[?]", 4) ffi.copy(buf, "dogs", 4) - local zone = ffi.C.ngx_http_lua_find_zone(buf, 4) + zone = ffi.C.ngx_http_lua_find_zone(buf, 4) local val = ffi.new("ngx_http_lua_value_t[?]", 1) @@ -149,7 +149,7 @@ bar: rc=0, type=3, val=3.14159 local buf = ffi.new("char[?]", 4) ffi.copy(buf, "dogs", 4) - local zone = ffi.C.ngx_http_lua_find_zone(buf, 4) + zone = ffi.C.ngx_http_lua_find_zone(buf, 4) local val = ffi.new("ngx_http_lua_value_t[?]", 1) @@ -212,7 +212,7 @@ bar: rc=0, type=1, val=0 local buf = ffi.new("char[?]", 4) ffi.copy(buf, "dogs", 4) - local zone = ffi.C.ngx_http_lua_find_zone(buf, 4) + zone = ffi.C.ngx_http_lua_find_zone(buf, 4) local val = ffi.new("ngx_http_lua_value_t[?]", 1) @@ -272,7 +272,7 @@ bar: rc=-5 local buf = ffi.new("char[?]", 4) ffi.copy(buf, "dogs", 4) - local zone = ffi.C.ngx_http_lua_find_zone(buf, 4) + zone = ffi.C.ngx_http_lua_find_zone(buf, 4) local s = ffi.new("char[?]", 20) @@ -344,7 +344,7 @@ bar: rc=0, type=4, val=, len=0 local buf = ffi.new("char[?]", 4) ffi.copy(buf, "dogs", 4) - local zone = ffi.C.ngx_http_lua_find_zone(buf, 4) + zone = ffi.C.ngx_http_lua_find_zone(buf, 4) local val = ffi.new("ngx_http_lua_value_t[?]", 1) diff --git a/debian/modules/http-lua/t/100-client-abort.t b/debian/modules/http-lua/t/100-client-abort.t index f571387..89c1f6a 100644 --- a/debian/modules/http-lua/t/100-client-abort.t +++ b/debian/modules/http-lua/t/100-client-abort.t @@ -195,7 +195,7 @@ bad things happen location = /sub { proxy_ignore_client_abort on; - proxy_pass http://127.0.0.2:12345/; + proxy_pass http://agentzh.org:12345/; } location = /sleep { @@ -236,7 +236,7 @@ client prematurely closed connection location = /sub { proxy_ignore_client_abort off; - proxy_pass http://127.0.0.2:12345/; + proxy_pass http://agentzh.org:12345/; } --- request GET /t @@ -540,7 +540,7 @@ client prematurely closed connection return end - local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_REDIS_PORT) + ok, err = sock:connect("127.0.0.1", $TEST_NGINX_REDIS_PORT) if not ok then ngx.log(ngx.ERR, "failed to connect: ", err) return diff --git a/debian/modules/http-lua/t/106-timer.t b/debian/modules/http-lua/t/106-timer.t index 7b7c85e..3e4741e 100644 --- a/debian/modules/http-lua/t/106-timer.t +++ b/debian/modules/http-lua/t/106-timer.t @@ -76,7 +76,7 @@ qr/\[lua\] content_by_lua\(nginx\.conf:\d+\):\d+: elapsed: 0\.0(?:4[4-9]|5[0-6]) -=== TEST 2: globals are shared +=== TEST 2: separated global env --- config location /t { content_by_lua ' @@ -104,7 +104,7 @@ F(ngx_http_lua_timer_handler) { --- response_body registered timer -foo = 3 +foo = nil --- wait: 0.1 --- no_error_log @@ -320,7 +320,7 @@ qr/received: Server: \S+/, === TEST 6: tcp cosocket in timer handler (keep-alive connections) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /t { @@ -596,7 +596,7 @@ qr/\[lua\] log_by_lua\(nginx\.conf:\d+\):\d+: elapsed: 0\.0(?:6[4-9]|7[0-6])/, === TEST 10: tcp cosocket in timer handler (keep-alive connections) - log_by_lua --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /t { @@ -693,7 +693,7 @@ qr/go\(\): connected: 1, reused: \d+/, === TEST 11: tcp cosocket in timer handler (keep-alive connections) - header_filter_by_lua --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /t { @@ -799,7 +799,7 @@ qr/go\(\): connected: 1, reused: \d+/, === TEST 12: tcp cosocket in timer handler (keep-alive connections) - body_filter_by_lua --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /t { @@ -912,7 +912,7 @@ qr/go\(\): connected: 1, reused: \d+/, === TEST 13: tcp cosocket in timer handler (keep-alive connections) - set_by_lua --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /t { @@ -1023,7 +1023,7 @@ qr/go\(\): connected: 1, reused: \d+/, content_by_lua ' local cc, cr, cy = coroutine.create, coroutine.resume, coroutine.yield local function f() - local function f() + function f() local cnt = 0 for i = 1, 20 do print("cnt = ", cnt) @@ -1090,7 +1090,7 @@ registered timer ngx.log(ngx.ERR, ...) end local function handle() - local function f() + function f() print("hello in thread") return "done" end diff --git a/debian/modules/http-lua/t/108-timer-safe.t b/debian/modules/http-lua/t/108-timer-safe.t index 758d01a..2795998 100644 --- a/debian/modules/http-lua/t/108-timer-safe.t +++ b/debian/modules/http-lua/t/108-timer-safe.t @@ -229,7 +229,7 @@ qr/received: Server: \S+/, === TEST 4: tcp cosocket in timer handler (keep-alive connections) --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /t { @@ -489,7 +489,7 @@ delete thread 2 --- response_body hello world ---- wait: 0.15 +--- wait: 0.1 --- no_error_log [error] [alert] @@ -499,7 +499,7 @@ hello world [ "registered timer", qr/\[lua\] .*? my lua timer handler/, -qr/\[lua\] log_by_lua\(nginx\.conf:\d+\):\d+: elapsed: 0\.0(?:6[4-9]|7[0-9]|8[0-6])/, +qr/\[lua\] log_by_lua\(nginx\.conf:\d+\):\d+: elapsed: 0\.0(?:6[4-9]|7[0-6])/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -508,7 +508,7 @@ qr/\[lua\] log_by_lua\(nginx\.conf:\d+\):\d+: elapsed: 0\.0(?:6[4-9]|7[0-9]|8[0- === TEST 8: tcp cosocket in timer handler (keep-alive connections) - log_by_lua --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /t { @@ -606,7 +606,7 @@ qr/go\(\): connected: 1, reused: \d+/, === TEST 9: tcp cosocket in timer handler (keep-alive connections) - header_filter_by_lua --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /t { @@ -713,7 +713,7 @@ qr/go\(\): connected: 1, reused: \d+/, === TEST 10: tcp cosocket in timer handler (keep-alive connections) - body_filter_by_lua --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /t { @@ -827,7 +827,7 @@ qr/go\(\): connected: 1, reused: \d+/, === TEST 11: tcp cosocket in timer handler (keep-alive connections) - set_by_lua --- http_config eval - "lua_package_path '$::HtmlDir/?.lua;./?.lua;;';" + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location = /t { @@ -1007,7 +1007,7 @@ registered timer ngx.log(ngx.ERR, ...) end local function handle() - local function f() + function f() print("hello in thread") return "done" end diff --git a/debian/modules/http-lua/t/109-timer-hup.t b/debian/modules/http-lua/t/109-timer-hup.t index 2c197c2..0864046 100644 --- a/debian/modules/http-lua/t/109-timer-hup.t +++ b/debian/modules/http-lua/t/109-timer-hup.t @@ -46,7 +46,7 @@ __DATA__ --- config location /t { content_by_lua ' - local f, err = io.open("$TEST_NGINX_SERVER_ROOT/logs/nginx.pid", "r") + local f, err = io.open("t/servroot/logs/nginx.pid", "r") if not f then ngx.say("failed to open nginx.pid: ", err) return @@ -99,7 +99,7 @@ timer prematurely expired: true --- config location /t { content_by_lua ' - local f, err = io.open("$TEST_NGINX_SERVER_ROOT/logs/nginx.pid", "r") + local f, err = io.open("t/servroot/logs/nginx.pid", "r") if not f then ngx.say("failed to open nginx.pid: ", err) return @@ -163,7 +163,7 @@ timer prematurely expired: true --- config location /t { content_by_lua ' - local f, err = io.open("$TEST_NGINX_SERVER_ROOT/logs/nginx.pid", "r") + local f, err = io.open("t/servroot/logs/nginx.pid", "r") if not f then ngx.say("failed to open nginx.pid: ", err) return @@ -219,7 +219,7 @@ failed to register a new timer after reload: process exiting, context: ngx.timer --- config location /t { content_by_lua ' - local f, err = io.open("$TEST_NGINX_SERVER_ROOT/logs/nginx.pid", "r") + local f, err = io.open("t/servroot/logs/nginx.pid", "r") if not f then ngx.say("failed to open nginx.pid: ", err) return @@ -284,7 +284,7 @@ g: exiting=true --- config location /t { content_by_lua ' - local f, err = io.open("$TEST_NGINX_SERVER_ROOT/logs/nginx.pid", "r") + local f, err = io.open("t/servroot/logs/nginx.pid", "r") if not f then ngx.say("failed to open nginx.pid: ", err) return @@ -363,7 +363,7 @@ lua found 100 pending timers local line, err = sock:receive("*l") until not line or string.find(line, "^%s*$") - local function foo() + function foo() repeat -- Get and read chunk local line, err = sock:receive("*l") @@ -379,7 +379,7 @@ lua found 100 pending timers until len == 0 end - local co = coroutine.create(foo) + co = coroutine.create(foo) repeat local chunk = select(2,coroutine.resume(co)) until chunk == nil @@ -399,7 +399,7 @@ lua found 100 pending timers end local ok, err = ngx.timer.at(1, background_thread) - local f, err = io.open("$TEST_NGINX_SERVER_ROOT/logs/nginx.pid", "r") + local f, err = io.open("t/servroot/logs/nginx.pid", "r") if not f then ngx.say("failed to open nginx.pid: ", err) return @@ -453,7 +453,7 @@ lua found 1 pending timers end if kill then - local f, err = io.open("$TEST_NGINX_SERVER_ROOT/logs/nginx.pid", "r") + local f, err = io.open("t/servroot/logs/nginx.pid", "r") if not f then ngx.log(ngx.ERR, "failed to open nginx.pid: ", err) return diff --git a/debian/modules/http-lua/t/120-re-find.t b/debian/modules/http-lua/t/120-re-find.t index f80ca4f..73e6134 100644 --- a/debian/modules/http-lua/t/120-re-find.t +++ b/debian/modules/http-lua/t/120-re-find.t @@ -622,7 +622,7 @@ matched: 你 >>> a.lua local re = [==[(?i:([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:=|<=>|r?like|sounds\s+like|regexp)([\s'\"`´’‘\(\)]*)?\2|([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp)([\s'\"`´’‘\(\)]*)?(?!\6)([\d\w]+))]==] -local s = string.rep([[ABCDEFG]], 10) +s = string.rep([[ABCDEFG]], 10) local start = ngx.now() @@ -664,7 +664,7 @@ error: pcre_exec() failed: -8 >>> a.lua local re = [==[(?i:([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:=|<=>|r?like|sounds\s+like|regexp)([\s'\"`´’‘\(\)]*)?\2|([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp)([\s'\"`´’‘\(\)]*)?(?!\6)([\d\w]+))]==] -local s = string.rep([[ABCDEFG]], 10) +s = string.rep([[ABCDEFG]], 10) local start = ngx.now() diff --git a/debian/modules/http-lua/t/123-lua-path.t b/debian/modules/http-lua/t/123-lua-path.t index e30132f..23681a9 100644 --- a/debian/modules/http-lua/t/123-lua-path.t +++ b/debian/modules/http-lua/t/123-lua-path.t @@ -11,7 +11,7 @@ repeat_each(2); plan tests => repeat_each() * (blocks() * 3 + 1); -$ENV{LUA_PATH} = "../lua-resty-core/lib/?.lua;../lua-resty-lrucache/lib/?.lua;/foo/bar/baz"; +$ENV{LUA_PATH} = "/foo/bar/baz"; $ENV{LUA_CPATH} = "/baz/bar/foo"; #no_diff(); #no_long_string(); @@ -36,8 +36,8 @@ env LUA_CPATH; } --- request GET /lua ---- response_body_like -(?:\.\.\/lua-resty-core\/lib\/\?\.lua;\.\.\/lua-resty-lrucache\/lib\/\?\.lua;){1,2}\/foo\/bar\/baz +--- response_body +/foo/bar/baz /baz/bar/foo --- no_error_log @@ -60,8 +60,8 @@ env LUA_CPATH; } --- request GET /lua ---- response_body_like -(?:\.\.\/lua-resty-core\/lib\/\?\.lua;\.\.\/lua-resty-lrucache\/lib\/\?\.lua;){1,2}\/foo\/bar\/baz +--- response_body +/foo/bar/baz /baz/bar/foo --- no_error_log diff --git a/debian/modules/http-lua/t/124-init-worker.t b/debian/modules/http-lua/t/124-init-worker.t index b648d55..9b2a91f 100644 --- a/debian/modules/http-lua/t/124-init-worker.t +++ b/debian/modules/http-lua/t/124-init-worker.t @@ -521,11 +521,12 @@ warn(): Thu, 01 Jan 1970 01:34:38 GMT } --- request GET /t ---- response_body_like +--- response_body +timer created connected: 1 request sent: 56 -first line received: HTTP\/1\.1 200 OK -second line received: (?:Date|Server): .*? +first line received: HTTP/1.1 200 OK +second line received: Server: openresty --- no_error_log [error] --- timeout: 10 @@ -549,7 +550,6 @@ second line received: (?:Date|Server): .*? else say("connect: ", ok, " ", err) end - done = true end local ok, err = ngx.timer.at(0, handler) @@ -600,7 +600,6 @@ qr/connect\(\) failed \(\d+: Connection refused\), context: ngx\.timer$/ else say("connect: ", ok, " ", err) end - done = true end local ok, err = ngx.timer.at(0, handler) @@ -651,7 +650,6 @@ qr/connect\(\) failed \(\d+: Connection refused\)/ else say("connect: ", ok, " ", err) end - done = true end local ok, err = ngx.timer.at(0, handler) diff --git a/debian/modules/http-lua/t/126-shdict-frag.t b/debian/modules/http-lua/t/126-shdict-frag.t index 33646d1..5a2aff8 100644 --- a/debian/modules/http-lua/t/126-shdict-frag.t +++ b/debian/modules/http-lua/t/126-shdict-frag.t @@ -1240,8 +1240,8 @@ failed to safe set baz: no memory local key = "mylittlekey" .. rand(maxkeyidx) local ok, err = dogs:get(key) if not ok or rand() > 0.6 then - local sz = rand(maxsz) - local val = rep("a", sz) + sz = rand(maxsz) + val = rep("a", sz) local ok, err, forcible = dogs:set(key, val) if err then ngx.log(ngx.ERR, "failed to set key: ", err) diff --git a/debian/modules/http-lua/t/127-uthread-kill.t b/debian/modules/http-lua/t/127-uthread-kill.t index 5542153..cc43c62 100644 --- a/debian/modules/http-lua/t/127-uthread-kill.t +++ b/debian/modules/http-lua/t/127-uthread-kill.t @@ -23,7 +23,7 @@ __DATA__ --- config location /lua { content_by_lua ' - local function f() + function f() ngx.say("hello from f()") ngx.sleep(1) end @@ -81,7 +81,7 @@ lua clean up the timer for pending ngx.sleep --- config location /lua { content_by_lua ' - local function f() + function f() ngx.say("hello from f()") ngx.sleep(0.001) return 32 @@ -138,12 +138,12 @@ lua clean up the timer for pending ngx.sleep === TEST 3: kill pending resolver --- config - resolver 127.0.0.2:12345; + resolver agentzh.org:12345; location /lua { content_by_lua ' - local function f() + function f() local sock = ngx.socket.tcp() - sock:connect("some.127.0.0.2", 12345) + sock:connect("some.agentzh.org", 12345) end local t, err = ngx.thread.spawn(f) @@ -194,13 +194,13 @@ resolve name done: -2 location /lua { content_by_lua ' local ready = false - local function f() + function f() local sock = ngx.socket.tcp() sock:connect("agentzh.org", 80) sock:close() ready = true sock:settimeout(10000) - sock:connect("127.0.0.2", 12345) + sock:connect("agentzh.org", 12345) end local t, err = ngx.thread.spawn(f) @@ -262,7 +262,7 @@ lua finalize socket location = /t { content_by_lua ' - local function f() + function f() ngx.location.capture("/sub") end @@ -309,11 +309,11 @@ lua tcp socket abort resolver location = /t { content_by_lua ' - local function f() + function f() ngx.location.capture("/sub") end - local function g() + function g() ngx.sleep(0.3) end @@ -376,7 +376,7 @@ lua tcp socket abort resolver location = /t { content_by_lua ' local ready = false - local function f() + function f() ngx.location.capture("/sub") ready = true ngx.sleep(0.5) @@ -424,7 +424,7 @@ lua tcp socket abort resolver --- config location = /t { content_by_lua ' - local function f() + function f() return end @@ -473,7 +473,7 @@ lua tcp socket abort resolver ngx.say("killed main thread.") end - local function f() + function f() local ok, err = ngx.thread.kill(coroutine.running()) if not ok then ngx.say("failed to kill user thread: ", err) diff --git a/debian/modules/http-lua/t/128-duplex-tcp-socket.t b/debian/modules/http-lua/t/128-duplex-tcp-socket.t index 22b9f03..aed560c 100644 --- a/debian/modules/http-lua/t/128-duplex-tcp-socket.t +++ b/debian/modules/http-lua/t/128-duplex-tcp-socket.t @@ -396,7 +396,7 @@ F(ngx_http_lua_socket_tcp_finalize_write_part) { end sock:settimeout(300) - local ok, err = sock:connect("127.0.0.2", 12345) + local ok, err = sock:connect("172.105.207.225", 12345) ngx.say("connect: ", ok, " ", err) local ok, err = sock:close() @@ -425,7 +425,7 @@ close: nil closed --- config server_tokens off; lua_socket_log_errors off; - resolver 127.0.0.2:12345; + resolver agentzh.org:12345; resolver_timeout 300ms; location /t { content_by_lua ' @@ -459,7 +459,7 @@ close: nil closed end sock:settimeout(300) - local ok, err = sock:connect("some2.agentzh.org", 80) + local ok, err = sock:connect("some2.agentzh.org", 12345) ngx.say("connect: ", ok, " ", err) local ok, err = sock:close() diff --git a/debian/modules/http-lua/t/129-ssl-socket.t b/debian/modules/http-lua/t/129-ssl-socket.t index f2fa26b..3f05640 100644 --- a/debian/modules/http-lua/t/129-ssl-socket.t +++ b/debian/modules/http-lua/t/129-ssl-socket.t @@ -301,7 +301,7 @@ SSL reused session content_by_lua ' local sock = ngx.socket.tcp() - sock:settimeout(7000) + sock:settimeout(2000) do @@ -380,7 +380,7 @@ lua ssl free session --- no_error_log [error] [alert] ---- timeout: 10 +--- timeout: 5 @@ -573,7 +573,7 @@ SSL reused session ngx.say("ssl handshake: ", type(session)) - local req = "GET /en/linux-packages.html HTTP/1.1\\r\\nHost: openresty.com\\r\\nConnection: close\\r\\n\\r\\n" + local req = "GET / HTTP/1.1\\r\\nHost: agentzh.org\\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) @@ -602,7 +602,7 @@ GET /t --- response_body connected: 1 ssl handshake: userdata -sent http request: 80 bytes. +sent http request: 56 bytes. received: HTTP/1.1 404 Not Found close: 1 nil @@ -1333,13 +1333,13 @@ failed to send http request: closed --- grep_error_log_out --- error_log eval [ -qr/\[(crit|error)\] .*?SSL_do_handshake\(\) failed .*?(unsupported protocol|no protocols available)/, +qr/\[crit\] .*?SSL_do_handshake\(\) failed .*?(unsupported protocol|no protocols available)/, 'lua ssl server name: "openresty.org"', ] --- no_error_log SSL reused session +[error] [alert] -[emerg] --- timeout: 5 @@ -2508,7 +2508,7 @@ SSL reused session content_by_lua_block { local sock = ngx.socket.tcp() - sock:settimeout(7000) + sock:settimeout(2000) local ok, err = sock:connect("openresty.org", 443) if not ok then @@ -2529,4 +2529,4 @@ GET /t qr/\[error\] .* ngx.socket sslhandshake: expecting 1 ~ 5 arguments \(including the object\), but seen 0/ --- no_error_log [alert] ---- timeout: 10 +--- timeout: 5 diff --git a/debian/modules/http-lua/t/130-internal-api.t b/debian/modules/http-lua/t/130-internal-api.t index 2158e87..eba0980 100644 --- a/debian/modules/http-lua/t/130-internal-api.t +++ b/debian/modules/http-lua/t/130-internal-api.t @@ -8,7 +8,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * blocks() * 3; +plan tests => repeat_each() * 3; #no_diff(); no_long_string(); @@ -19,7 +19,12 @@ run_tests(); __DATA__ -=== TEST 1: req +=== TEST 1: __ngx_req and __ngx_cycle +--- http_config + init_by_lua ' + my_cycle = __ngx_cycle + '; + --- config location = /t { content_by_lua ' @@ -27,14 +32,18 @@ __DATA__ local function tonum(ud) return tonumber(ffi.cast("uintptr_t", ud)) end - ngx.say(string.format("content req=%#x", tonum(exdata()))) + ngx.say(string.format("init: cycle=%#x", tonum(my_cycle))) + ngx.say(string.format("content cycle=%#x", tonum(__ngx_cycle))) + ngx.say(string.format("content req=%#x", tonum(__ngx_req))) '; } --- request GET /t --- response_body_like chop -^content req=0x[a-f0-9]{4,} +^init: cycle=(0x[a-f0-9]{4,}) +content cycle=\1 +content req=0x[a-f0-9]{4,} $ --- no_error_log [error] diff --git a/debian/modules/http-lua/t/134-worker-count-5.t b/debian/modules/http-lua/t/134-worker-count-5.t index ec6d0e7..b257c12 100644 --- a/debian/modules/http-lua/t/134-worker-count-5.t +++ b/debian/modules/http-lua/t/134-worker-count-5.t @@ -3,7 +3,7 @@ use Test::Nginx::Socket::Lua; #worker_connections(1014); -master_on(); +#master_on(); workers(5); #log_level('warn'); @@ -55,7 +55,7 @@ workers: 5 === TEST 3: init_by_lua + module (github #681) --- http_config - lua_package_path "$TEST_NGINX_SERVER_ROOT/html/?.lua;;"; + lua_package_path "t/servroot/html/?.lua;;"; init_by_lua_block { local blah = require "file" diff --git a/debian/modules/http-lua/t/138-balancer.t b/debian/modules/http-lua/t/138-balancer.t index 151db7b..0aba66d 100644 --- a/debian/modules/http-lua/t/138-balancer.t +++ b/debian/modules/http-lua/t/138-balancer.t @@ -362,6 +362,8 @@ me: 101 === TEST 13: lua subrequests --- http_config + lua_package_path "t/servroot/html/?.lua;;"; + lua_code_cache off; upstream backend { diff --git a/debian/modules/http-lua/t/139-ssl-cert-by.t b/debian/modules/http-lua/t/139-ssl-cert-by.t index bebbdb2..a65d703 100644 --- a/debian/modules/http-lua/t/139-ssl-cert-by.t +++ b/debian/modules/http-lua/t/139-ssl-cert-by.t @@ -1278,7 +1278,7 @@ lua ssl server name: "test.com" listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_certificate_by_lua_block { - local function f() + function f() ngx.sleep(0.01) print("uthread: hello in thread") return "done" diff --git a/debian/modules/http-lua/t/140-ssl-c-api.t b/debian/modules/http-lua/t/140-ssl-c-api.t index a77f5d4..8734d14 100644 --- a/debian/modules/http-lua/t/140-ssl-c-api.t +++ b/debian/modules/http-lua/t/140-ssl-c-api.t @@ -10,7 +10,6 @@ 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"); - } else { plan tests => repeat_each() * (blocks() * 5 + 1); } @@ -69,7 +68,7 @@ _EOC_ my $http_config = $block->http_config || ''; $http_config .= <<'_EOC_'; -lua_package_path "$prefix/html/?.lua;../lua-resty-core/lib/?.lua;;"; +lua_package_path "$prefix/html/?.lua;;"; _EOC_ $block->set_value("http_config", $http_config); }); @@ -92,8 +91,8 @@ __DATA__ local errmsg = ffi.new("char *[1]") - local r = require "resty.core.base" .get_request() - if r == nil then + local r = getfenv(0).__ngx_req + if not r then ngx.log(ngx.ERR, "no request found") return end @@ -246,8 +245,8 @@ lua ssl server name: "test.com" local errmsg = ffi.new("char *[1]") - local r = require "resty.core.base" .get_request() - if r == nil then + local r = getfenv(0).__ngx_req + if not r then ngx.log(ngx.ERR, "no request found") return end @@ -400,8 +399,8 @@ lua ssl server name: "test.com" local errmsg = ffi.new("char *[1]") - local r = require "resty.core.base" .get_request() - if r == nil then + local r = getfenv(0).__ngx_req + if not r then ngx.log(ngx.ERR, "no request found") return end @@ -529,8 +528,8 @@ failed to parse PEM priv key: PEM_read_bio_PrivateKey() failed local errmsg = ffi.new("char *[1]") - local r = require "resty.core.base" .get_request() - if r == nil then + local r = getfenv(0).__ngx_req + if not r then ngx.log(ngx.ERR, "no request found") return end @@ -679,8 +678,8 @@ lua ssl server name: "test.com" local errmsg = ffi.new("char *[1]") - local r = require "resty.core.base" .get_request() - if r == nil then + local r = getfenv(0).__ngx_req + if not r then ngx.log(ngx.ERR, "no request found") return end diff --git a/debian/modules/http-lua/t/143-ssl-session-fetch.t b/debian/modules/http-lua/t/143-ssl-session-fetch.t index 78a66cf..4dc992d 100644 --- a/debian/modules/http-lua/t/143-ssl-session-fetch.t +++ b/debian/modules/http-lua/t/143-ssl-session-fetch.t @@ -1114,108 +1114,3 @@ qr/ssl_session_fetch_by_lua_block:1: ssl fetch sess by lua is running!/s [error] [alert] [emerg] - - - -=== TEST 14: keep global variable in ssl_session_(store|fetch)_by_lua when OpenResty LuaJIT is used ---- http_config - ssl_session_store_by_lua_block { - ngx.log(ngx.WARN, "new foo: ", foo) - if not foo then - foo = 1 - else - ngx.log(ngx.WARN, "old foo: ", foo) - foo = foo + 1 - end - } - ssl_session_fetch_by_lua_block { - ngx.log(ngx.WARN, "new bar: ", foo) - if not bar then - bar = 1 - else - ngx.log(ngx.WARN, "old bar: ", bar) - bar = bar + 1 - end - } - - 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_session_tickets off; - - server_tokens off; - location /foo { - content_by_lua_block { - ngx.say("foo: ", foo) - ngx.say("bar: ", bar) - } - } - } ---- 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 - - 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 - - package.loaded.session = 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 - - while true do - local line, err = sock:receive() - if not line then - -- ngx.say("failed to receive response status line: ", err) - break - end - - local m, err = ngx.re.match(line, "^foo: (.*)$", "jo") - if err then - ngx.say("failed to match line: ", err) - end - - if m and m[1] then - ngx.print(m[1]) - end - end - - local ok, err = sock:close() - ngx.say("done") - end -- do - } - } - ---- request -GET /t ---- response_body_like chomp -\A[123]done\n\z ---- grep_error_log eval: qr/old (foo|bar): \d+/ ---- grep_error_log_out eval -["", "old foo: 1\n", "old bar: 1\nold foo: 2\n"] ---- no_error_log -[error] -[alert] -[emerg] diff --git a/debian/modules/http-lua/t/147-tcp-socket-timeouts.t b/debian/modules/http-lua/t/147-tcp-socket-timeouts.t index 8566c0b..4ebc8f3 100644 --- a/debian/modules/http-lua/t/147-tcp-socket-timeouts.t +++ b/debian/modules/http-lua/t/147-tcp-socket-timeouts.t @@ -323,7 +323,7 @@ lua tcp socket write timed out sock:settimeouts(100, 100, 100) - local ok, err = sock:connect("127.0.0.2", 12345) + local ok, err = sock:connect("agentzh.org", 12345) ngx.say("connect: ", ok, " ", err) local bytes @@ -346,7 +346,7 @@ send: nil closed receive: nil closed close: nil closed --- error_log -lua tcp socket connect timed out, when connecting to 127.0.0.2:12345 +lua tcp socket connect timed out, when connecting to 172.105.207.225:12345 --- timeout: 10 @@ -411,7 +411,7 @@ lua tcp socket connect timed out, when connecting to 127.0.0.2:12345 local chunk = 4 - local function read() + function read() sock:settimeout(200) -- read: 200 ms local data, err = sock:receive(content_length) @@ -506,7 +506,7 @@ failed to receive data: timeout local chunk = 4 - local function read() + function read() local data, err = sock:receive(content_length) if not data then ngx.log(ngx.ERR, "failed to receive data: ", err) diff --git a/debian/modules/http-lua/t/152-timer-every.t b/debian/modules/http-lua/t/152-timer-every.t index 7b42d2d..c8d62e7 100644 --- a/debian/modules/http-lua/t/152-timer-every.t +++ b/debian/modules/http-lua/t/152-timer-every.t @@ -63,7 +63,7 @@ qr/\[lua\] content_by_lua\(nginx\.conf:\d+\):\d+: elapsed: 0\.(?:09|10)\d*, cont -=== TEST 2: shared global env +=== TEST 2: separated global env --- config location /t { content_by_lua_block { @@ -84,7 +84,7 @@ qr/\[lua\] content_by_lua\(nginx\.conf:\d+\):\d+: elapsed: 0\.(?:09|10)\d*, cont --- request GET /t --- response_body -foo = 3 +foo = nil --- wait: 0.12 --- no_error_log [error] diff --git a/debian/modules/http-lua/t/153-semaphore-hup.t b/debian/modules/http-lua/t/153-semaphore-hup.t index 5c271a4..c85a21d 100644 --- a/debian/modules/http-lua/t/153-semaphore-hup.t +++ b/debian/modules/http-lua/t/153-semaphore-hup.t @@ -67,7 +67,7 @@ add_block_preprocessor(sub { return end - local shdict = ngx.shared.shdict + shdict = ngx.shared.shdict local success = shdict:add("reloaded", 1) if not success then return diff --git a/debian/modules/http-lua/t/156-slow-network.t b/debian/modules/http-lua/t/156-slow-network.t deleted file mode 100644 index 2d80506..0000000 --- a/debian/modules/http-lua/t/156-slow-network.t +++ /dev/null @@ -1,138 +0,0 @@ -BEGIN { - if (!defined $ENV{LD_PRELOAD}) { - $ENV{LD_PRELOAD} = ''; - } - - if ($ENV{LD_PRELOAD} !~ /\bmockeagain\.so\b/) { - $ENV{LD_PRELOAD} = "mockeagain.so $ENV{LD_PRELOAD}"; - } - - if ($ENV{MOCKEAGAIN} eq 'r') { - $ENV{MOCKEAGAIN} = 'rw'; - - } else { - $ENV{MOCKEAGAIN} = 'w'; - } - - $ENV{TEST_NGINX_EVENT_TYPE} = 'poll'; -} - -use Test::Nginx::Socket::Lua; - -repeat_each(2); - -plan tests => repeat_each() * (blocks() * 4); - -add_block_preprocessor(sub { - my $block = shift; - - if (!defined $block->error_log) { - $block->set_value("no_error_log", "[error]"); - } - - if (!defined $block->request) { - $block->set_value("request", "GET /t"); - } - -}); - - -log_level("debug"); -no_long_string(); -#no_diff(); -run_tests(); - -__DATA__ - -=== TEST 1: receiveany returns anything once socket receives ---- config - server_tokens off; - location = /t { - set $port $TEST_NGINX_SERVER_PORT; - content_by_lua_block { - local sock = ngx.socket.tcp() - sock:settimeout(500) - assert(sock:connect("127.0.0.1", ngx.var.port)) - local req = { - 'GET /foo HTTP/1.0\r\n', - 'Host: localhost\r\n', - 'Connection: close\r\n\r\n', - } - local ok, err = sock:send(req) - if not ok then - ngx.say("send request failed: ", err) - return - end - - - -- skip http header - while true do - local data, err, _ = sock:receive('*l') - if err then - ngx.say('unexpected error occurs when receiving http head: ' .. err) - return - end - if #data == 0 then -- read last line of head - break - end - end - - -- receive http body - while true do - local data, err = sock:receiveany(1024) - if err then - if err ~= 'closed' then - ngx.say('unexpected err: ', err) - end - break - end - ngx.say(data) - end - - sock:close() - } - } - - location = /foo { - content_by_lua_block { - local resp = { - '1', - 'hello', - } - - local length = 0 - for _, v in ipairs(resp) do - length = length + #v - end - - -- flush http header - ngx.header['Content-Length'] = length - ngx.flush(true) - ngx.sleep(0.01) - - -- send http body bytes by bytes - for _, v in ipairs(resp) do - ngx.print(v) - ngx.flush(true) - ngx.sleep(0.01) - end - } - } - ---- response_body -1 -h -e -l -l -o ---- grep_error_log eval -qr/lua tcp socket read any/ ---- grep_error_log_out -lua tcp socket read any -lua tcp socket read any -lua tcp socket read any -lua tcp socket read any -lua tcp socket read any -lua tcp socket read any -lua tcp socket read any diff --git a/debian/modules/http-lua/t/157-socket-keepalive-hup.t b/debian/modules/http-lua/t/157-socket-keepalive-hup.t deleted file mode 100644 index 357bb59..0000000 --- a/debian/modules/http-lua/t/157-socket-keepalive-hup.t +++ /dev/null @@ -1,91 +0,0 @@ -# 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 $SkipReason ? (skip_all => $SkipReason) : (); - -repeat_each(2); - -plan tests => repeat_each() * (blocks() * 8); - -#no_diff(); -no_long_string(); - -worker_connections(1024); -run_tests(); - -__DATA__ - -=== TEST 1: exiting ---- config - location /t { - set $port $TEST_NGINX_SERVER_PORT; - - content_by_lua_block { - local f, err = io.open("$TEST_NGINX_SERVER_ROOT/logs/nginx.pid", "r") - if not f then - ngx.say("failed to open nginx.pid: ", err) - return - end - - local pid = f:read() - -- ngx.say("master pid: [", pid, "]") - - f:close() - - local i = 0 - local port = ngx.var.port - - local function f(premature) - print("timer prematurely expired: ", premature) - - local sock = ngx.socket.tcp() - - local ok, err = sock:connect("127.0.0.1", port) - if not ok then - print("failed to connect: ", err) - return - end - - local ok, err = sock:setkeepalive() - if not ok then - print("failed to setkeepalive: ", err) - return - end - - print("setkeepalive successfully") - end - local ok, err = ngx.timer.at(3, f) - if not ok then - ngx.say("failed to set timer: ", err) - return - end - ngx.say("registered timer") - os.execute("kill -HUP " .. pid) - } - } ---- request -GET /t - ---- response_body -registered timer - ---- wait: 0.3 ---- no_error_log -[error] -[alert] -[crit] ---- error_log -timer prematurely expired: true -setkeepalive successfully -lua tcp socket set keepalive while process exiting, closing connection diff --git a/debian/modules/http-lua/t/158-global-var.t b/debian/modules/http-lua/t/158-global-var.t deleted file mode 100644 index 414a43a..0000000 --- a/debian/modules/http-lua/t/158-global-var.t +++ /dev/null @@ -1,508 +0,0 @@ -# vim:set ft= ts=4 sw=4 et fdm=marker: - -use Test::Nginx::Socket::Lua; - -log_level('debug'); - -repeat_each(2); - -plan tests => repeat_each() * (blocks() * 3 + 14); - -our $HtmlDir = html_dir; - -$ENV{TEST_NGINX_HTML_DIR} ||= html_dir(); - -no_long_string(); - -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 $TestCertificate = read_file("t/cert/test.crt"); -our $TestCertificateKey = read_file("t/cert/test.key"); - -add_block_preprocessor(sub { - my $block = shift; - - if (!defined $block->error_log) { - $block->set_value("no_error_log", "[error]"); - } - - if (!defined $block->request) { - $block->set_value("request", "GET /t"); - } - -}); - -run_tests(); - -__DATA__ - -=== TEST 1: set_by_lua ---- config - location /t { - set_by_lua_block $res { - if not foo then - foo = 1 - else - ngx.log(ngx.WARN, "old foo: ", foo) - foo = foo + 1 - end - return foo - } - echo $res; - } ---- 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, )/ ---- 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"] - - - -=== TEST 2: rewrite_by_lua ---- config - location /t { - rewrite_by_lua_block { - if not foo then - foo = 1 - else - ngx.log(ngx.WARN, "old foo: ", foo) - foo = foo + 1 - end - ngx.say(foo) - } - } ---- response_body_like chomp -\A[12]\n\z ---- grep_error_log eval -qr/(old foo: \d+|\[\w+\].*?writing a global lua variable \('[^'\s]+'\)|\w+_by_lua\(.*?\):\d+: in main chunk, )/ ---- grep_error_log_out eval -[qr/\A\[warn\] .*?writing a global lua variable \('foo'\) -rewrite_by_lua\(nginx\.conf:48\):3: in main chunk, \n\z/, "old foo: 1\n"] - - - -=== TEST 3: access_by_lua ---- config - location /t { - access_by_lua_block { - if not foo then - foo = 1 - else - ngx.log(ngx.WARN, "old foo: ", foo) - foo = foo + 1 - end - ngx.say(foo) - } - } ---- response_body_like chomp -\A[12]\n\z ---- grep_error_log eval -qr/(old foo: \d+|\[\w+\].*?writing a global lua variable \('[^'\s]+'\)|\w+_by_lua\(.*?\):\d+: in main chunk, )/ ---- grep_error_log_out eval -[qr/\A\[warn\] .*?writing a global lua variable \('foo'\) -access_by_lua\(nginx\.conf:48\):3: in main chunk, \n\z/, "old foo: 1\n"] - - - -=== TEST 4: content_by_lua ---- config - location /t { - content_by_lua_block { - if not foo then - foo = 1 - else - ngx.log(ngx.WARN, "old foo: ", foo) - foo = foo + 1 - end - ngx.say(foo) - } - } ---- response_body_like chomp -\A[12]\n\z ---- grep_error_log eval -qr/(old foo: \d+|\[\w+\].*?writing a global lua variable \('[^'\s]+'\)|\w+_by_lua\(.*?\):\d+: in main chunk, )/ ---- grep_error_log_out eval -[qr/\A\[warn\] .*?writing a global lua variable \('foo'\) -content_by_lua\(nginx\.conf:48\):3: in main chunk, \n\z/, "old foo: 1\n"] - - - -=== TEST 5: header_filter_by_lua ---- config - location /t { - content_by_lua_block { - ngx.say(foo) - } - header_filter_by_lua_block { - if not foo then - foo = 1 - else - ngx.log(ngx.WARN, "old foo: ", foo) - foo = foo + 1 - end - } - } ---- 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, )/ ---- 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"] - - - -=== TEST 6: body_filter_by_lua ---- config - location /t { - content_by_lua_block { - ngx.say(foo) - } - body_filter_by_lua_block { - if not foo then - foo = 1 - else - ngx.log(ngx.WARN, "old foo: ", foo) - foo = foo + 1 - end - } - } ---- 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, )/ ---- grep_error_log_out eval -[qr/\[warn\] .*?writing a global lua variable \('foo'\) -body_filter_by_lua:3: in main chunk, -old foo: 1\n\z/, "old foo: 2\nold foo: 3\n"] - - - -=== TEST 7: log_by_lua ---- config - location /t { - content_by_lua_block { - ngx.say(foo) - } - log_by_lua_block { - if not foo then - foo = 1 - else - ngx.log(ngx.WARN, "old foo: ", foo) - foo = foo + 1 - end - } - } ---- 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)/ ---- grep_error_log_out eval -[qr/\A\[warn\] .*?writing a global lua variable \('foo'\) -log_by_lua\(nginx\.conf:50\):3: in main chunk\n\z/, "old foo: 1\n"] - - - -=== TEST 8: ssl_certificate_by_lua ---- http_config - server { - listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; - server_name test.com; - ssl_certificate_by_lua_block { - if not foo then - foo = 1 - else - ngx.log(ngx.WARN, "old foo: ", foo) - foo = foo + 1 - end - } - ssl_certificate ../../cert/test.crt; - ssl_certificate_key ../../cert/test.key; - - server_tokens off; - location /foo { - content_by_lua_block { - ngx.say("foo: ", foo) - } - } - } ---- 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 - - local m, err = ngx.re.match(line, "^foo: (.*)$", "jo") - if err then - ngx.say("failed to match line: ", err) - end - - if m and m[1] then - ngx.print(m[1]) - end - end - - local ok, err = sock:close() - ngx.say("done") - end -- do - } - } - ---- 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)/ ---- 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"] - - - -=== TEST 9: timer ---- config - location /t { - content_by_lua_block { - local function f() - if not foo then - foo = 1 - else - ngx.log(ngx.WARN, "old foo: ", foo) - foo = foo + 1 - end - end - local ok, err = ngx.timer.at(0, f) - if not ok then - ngx.say("failed to set timer: ", err) - return - end - ngx.sleep(0.01) - ngx.say(foo) - } - } ---- response_body_like chomp -\A[12]\n\z ---- grep_error_log eval -qr/(old foo: \d+|\[\w+\].*?writing a global lua variable \('[^'\s]+'\)|\w+_by_lua\(.*?\):\d+: in\b)/ ---- grep_error_log_out eval -[qr/\A\[warn\] .*?writing a global lua variable \('foo'\) -content_by_lua\(nginx\.conf:56\):4: in\n\z/, "old foo: 1\n"] - - - -=== TEST 10: init_by_lua ---- http_config - init_by_lua_block { - foo = 1 - } ---- config - location /t { - content_by_lua_block { - if not foo then - foo = 1 - else - ngx.log(ngx.WARN, "old foo: ", foo) - foo = foo + 1 - end - ngx.say(foo) - } - } ---- response_body_like chomp -\A[23]\n\z ---- grep_error_log eval: qr/old foo: \d+/ ---- grep_error_log_out eval -["old foo: 1\n", "old foo: 2\n"] - - - -=== TEST 11: init_worker_by_lua ---- http_config - init_worker_by_lua_block { - if not foo then - foo = 1 - else - ngx.log(ngx.WARN, "old foo: ", foo) - foo = foo + 1 - end - } ---- config - location /t { - content_by_lua_block { - if not foo then - foo = 1 - else - ngx.log(ngx.WARN, "old foo: ", foo) - foo = foo + 1 - end - ngx.say(foo) - } - } ---- response_body_like chomp -\A[23]\n\z ---- grep_error_log eval: qr/old foo: \d+/ ---- grep_error_log_out eval -["old foo: 1\n", "old foo: 2\n"] - - - -=== TEST 12: init_by_lua + init_worker_by_lua ---- http_config - init_by_lua_block { - if not foo then - foo = 1 - else - ngx.log(ngx.WARN, "old foo: ", foo) - foo = foo + 1 - end - } - init_worker_by_lua_block { - if not foo then - foo = 1 - else - ngx.log(ngx.WARN, "old foo: ", foo) - foo = foo + 1 - end - } ---- config - location /t { - content_by_lua_block { - if not foo then - foo = 1 - else - ngx.log(ngx.WARN, "old foo: ", foo) - foo = foo + 1 - end - ngx.say(foo) - } - } ---- response_body_like chomp -\A[34]\n\z ---- grep_error_log eval: qr/old foo: \d+/ ---- grep_error_log_out eval -["old foo: 1\nold foo: 2\n", "old foo: 3\n"] - - - -=== TEST 13: don't show warn messages in init/init_worker ---- http_config - init_by_lua_block { - foo = 1 - } - - init_worker_by_lua_block { - bar = 2 - } ---- config - location /t { - content_by_lua_block { - ngx.say(foo) - ngx.say(bar) - } - } ---- response_body -1 -2 ---- no_error_log -setting global variable - - - -=== TEST 14: uthread ---- config - location /t { - content_by_lua_block { - local function f() - if not foo then - foo = 1 - else - ngx.log(ngx.WARN, "old foo: ", foo) - foo = foo + 1 - end - end - local ok, err = ngx.thread.spawn(f) - if not ok then - ngx.say("failed to set timer: ", err) - return - end - ngx.sleep(0.01) - ngx.say(foo) - } - } ---- response_body_like chomp -\A[12]\n\z ---- grep_error_log eval -qr/(old foo: \d+|writing a global lua variable \('\w+'\))/ ---- grep_error_log_out eval -["writing a global lua variable \('foo'\)\n", "old foo: 1\n"] - - - -=== TEST 15: balancer_by_lua ---- http_config - upstream backend { - server 0.0.0.1; - balancer_by_lua_block { - if not foo then - foo = 1 - else - ngx.log(ngx.WARN, "old foo: ", foo) - foo = foo + 1 - end - } - } ---- config - location = /t { - proxy_pass http://backend; - } ---- response_body_like: 502 Bad Gateway ---- error_code: 502 ---- error_log eval -qr/\[crit\].*?\Qconnect() to 0.0.0.1:80 failed\E/ ---- grep_error_log eval: qr/(old foo: \d+|writing a global lua variable \('\w+'\))/ ---- grep_error_log_out eval -["writing a global lua variable \('foo'\)\n", "old foo: 1\n"] diff --git a/debian/modules/http-lua/t/159-sa-restart.t b/debian/modules/http-lua/t/159-sa-restart.t deleted file mode 100644 index a0f0c0e..0000000 --- a/debian/modules/http-lua/t/159-sa-restart.t +++ /dev/null @@ -1,180 +0,0 @@ -# vim:set ft= ts=4 sw=4 et fdm=marker: - -use Test::Nginx::Socket::Lua; - -add_block_preprocessor(sub { - my $block = shift; - - my $http_config = $block->http_config || ''; - - $http_config .= <<_EOC_; - init_by_lua_block { - function test_sa_restart() - local signals = { - --"HUP", - --"INFO", - --"XCPU", - --"USR1", - --"USR2", - "ALRM", - --"INT", - "IO", - "CHLD", - --"WINCH", - } - - for _, signame in ipairs(signals) do - local cmd = string.format("kill -s %s %d && sleep 0.01", - signame, ngx.worker.pid()) - local err = select(2, io.popen(cmd):read("*a")) - if err then - error("SIG" .. signame .. " caused: " .. err) - end - end - end - } -_EOC_ - - $block->set_value("http_config", $http_config); - - if (!defined $block->config) { - my $config = <<_EOC_; - location /t { - echo ok; - } -_EOC_ - - $block->set_value("config", $config); - } - - if (!defined $block->request) { - $block->set_value("request", "GET /t"); - } - - if (!defined $block->response_body) { - $block->set_value("ignore_response_body"); - } - - if (!defined $block->no_error_log) { - $block->set_value("no_error_log", "[error]"); - } -}); - -plan tests => repeat_each() * (blocks() * 2 + 1); - -no_long_string(); -run_tests(); - -__DATA__ - -=== TEST 1: lua_sa_restart default - sets SA_RESTART in init_worker_by_lua* ---- http_config - init_worker_by_lua_block { - test_sa_restart() - } - - - -=== TEST 2: lua_sa_restart off - does not set SA_RESTART ---- http_config - lua_sa_restart off; - - init_worker_by_lua_block { - test_sa_restart() - } ---- no_error_log -[crit] ---- error_log -Interrupted system call - - - -=== TEST 3: lua_sa_restart on (default) - sets SA_RESTART if no init_worker_by_lua* phase is defined ---- config - location /t { - content_by_lua_block { - test_sa_restart() - } - } - - - -=== TEST 4: lua_sa_restart on (default) - SA_RESTART is effective in rewrite_by_lua* ---- config - location /t { - rewrite_by_lua_block { - test_sa_restart() - } - - echo ok; - } - - - -=== TEST 5: lua_sa_restart on (default) - SA_RESTART is effective in access_by_lua* ---- config - location /t { - access_by_lua_block { - test_sa_restart() - } - - echo ok; - } - - - -=== TEST 6: lua_sa_restart on (default) - SA_RESTART is effective in content_by_lua* ---- config - location /t { - content_by_lua_block { - test_sa_restart() - } - } - - - -=== TEST 7: lua_sa_restart on (default) - SA_RESTART is effective in header_filter_by_lua* ---- config - location /t { - echo ok; - - header_filter_by_lua_block { - test_sa_restart() - } - } - - - -=== TEST 8: lua_sa_restart on (default) - SA_RESTART is effective in body_filter_by_lua* ---- config - location /t { - echo ok; - - body_filter_by_lua_block { - test_sa_restart() - } - } - - - -=== TEST 9: lua_sa_restart on (default) - SA_RESTART is effective in log_by_lua* ---- config - location /t { - echo ok; - - log_by_lua_block { - test_sa_restart() - } - } - - - -=== TEST 10: lua_sa_restart on (default) - SA_RESTART is effective in timer phase ---- config - location /t { - echo ok; - - log_by_lua_block { - ngx.timer.at(0, test_sa_restart) - } - } diff --git a/debian/modules/http-lua/t/160-disable-init-by-lua.t b/debian/modules/http-lua/t/160-disable-init-by-lua.t deleted file mode 100644 index 541771e..0000000 --- a/debian/modules/http-lua/t/160-disable-init-by-lua.t +++ /dev/null @@ -1,194 +0,0 @@ -use Test::Nginx::Socket::Lua; - -repeat_each(2); - -plan tests => repeat_each() * (blocks() * 3); - -$ENV{TEST_NGINX_HTML_DIR} ||= html_dir(); - -my $html_dir = $ENV{TEST_NGINX_HTML_DIR}; -my $http_config = <<_EOC_; - init_by_lua_block { - function set_up_ngx_tmp_conf(conf) - if conf == nil then - conf = [[ - events { - worker_connections 64; - } - http { - init_by_lua_block { - ngx.log(ngx.ERR, "run init_by_lua") - } - } - ]] - end - - assert(os.execute("mkdir -p $html_dir/logs")) - - local conf_file = "$html_dir/nginx.conf" - local f, err = io.open(conf_file, "w") - if not f then - ngx.log(ngx.ERR, err) - return - end - - assert(f:write(conf)) - - return conf_file - end - - function get_ngx_bin_path() - local ffi = require "ffi" - ffi.cdef[[char **ngx_argv;]] - return ffi.string(ffi.C.ngx_argv[0]) - end - } -_EOC_ - -add_block_preprocessor(sub { - my $block = shift; - - if (!defined $block->http_config) { - $block->set_value("http_config", $http_config); - } - - if (!defined $block->request) { - $block->set_value("request", "GET /t"); - } -}); - -env_to_nginx("PATH"); -log_level("warn"); -no_long_string(); -run_tests(); - -__DATA__ - -=== TEST 1: ensure init_by_lua* is not run in signaller process ---- config - location = /t { - content_by_lua_block { - local conf_file = set_up_ngx_tmp_conf() - local nginx = get_ngx_bin_path() - - local cmd = nginx .. " -p $TEST_NGINX_HTML_DIR -c " .. conf_file .. " -s reopen" - local p, err = io.popen(cmd) - if not p then - ngx.log(ngx.ERR, err) - return - end - - local out, err = p:read("*a") - if not out then - ngx.log(ngx.ERR, err) - - else - ngx.log(ngx.WARN, out) - end - } - } ---- error_log -failed (2: No such file or directory) ---- no_error_log eval -qr/\[error\] .*? init_by_lua:\d+: run init_by_lua/ - - - -=== TEST 2: init_by_lua* does not run when testing Nginx configuration ---- config - location = /t { - content_by_lua_block { - local conf_file = set_up_ngx_tmp_conf() - local nginx = get_ngx_bin_path() - - local cmd = nginx .. " -p $TEST_NGINX_HTML_DIR -c " .. conf_file .. " -t" - local p, err = io.popen(cmd) - if not p then - ngx.log(ngx.ERR, err) - return - end - - local out, err = p:read("*a") - if not out then - ngx.log(ngx.ERR, err) - - else - ngx.log(ngx.WARN, out) - end - - local cmd = nginx .. " -p $TEST_NGINX_HTML_DIR -c " .. conf_file .. " -T" - local p, err = io.popen(cmd) - if not p then - ngx.log(ngx.ERR, err) - return - end - - local out, err = p:read("*a") - if not out then - ngx.log(ngx.ERR, err) - - else - ngx.log(ngx.WARN, out) - end - } - } ---- error_log -test is successful ---- no_error_log eval -qr/\[error\] .*? init_by_lua:\d+: run init_by_lua/ - - - -=== TEST 3: init_by_lua* does not run when testing Nginx configuration which contains 'lua_shared_dict' (GitHub #1462) ---- config - location = /t { - content_by_lua_block { - local conf = [[ - events { - worker_connections 64; - } - http { - lua_shared_dict test 64k; - init_by_lua_block { - ngx.log(ngx.ERR, "run init_by_lua with lua_shared_dict") - } - } - ]] - local conf_file = set_up_ngx_tmp_conf(conf) - local nginx = get_ngx_bin_path() - - local cmd = nginx .. " -p $TEST_NGINX_HTML_DIR -c " .. conf_file .. " -t" - local p, err = io.popen(cmd) - if not p then - ngx.log(ngx.ERR, err) - return - end - - local out, err = p:read("*a") - if not out then - ngx.log(ngx.ERR, err) - - else - ngx.log(ngx.WARN, out) - end - - local cmd = nginx .. " -p $TEST_NGINX_HTML_DIR -c " .. conf_file .. " -T" - local p, err = io.popen(cmd) - if not p then - ngx.log(ngx.ERR, err) - return - end - - local out, err = p:read("*a") - if not out then - ngx.log(ngx.ERR, err) - - else - ngx.log(ngx.WARN, out) - end - } - } ---- error_log -test is successful ---- no_error_log eval -qr/\[error\] .*? init_by_lua:\d+: run init_by_lua with lua_shared_dict/ diff --git a/debian/modules/http-lua/t/161-load-resty-core.t b/debian/modules/http-lua/t/161-load-resty-core.t deleted file mode 100644 index 41b18f0..0000000 --- a/debian/modules/http-lua/t/161-load-resty-core.t +++ /dev/null @@ -1,68 +0,0 @@ -use Test::Nginx::Socket::Lua; - -repeat_each(2); - -plan tests => repeat_each() * (blocks() * 3); - -add_block_preprocessor(sub { - my $block = shift; - - if (!defined $block->request) { - $block->set_value("request", "GET /t"); - } - - if (!defined $block->no_error_log) { - $block->set_value("no_error_log", "[error]"); - } -}); - -no_long_string(); -run_tests(); - -__DATA__ - -=== TEST 1: lua_load_resty_core is enabled by default ---- config - location = /t { - content_by_lua_block { - local loaded_resty_core = package.loaded["resty.core"] - local resty_core = require "resty.core" - - ngx.say("resty.core loaded: ", loaded_resty_core == resty_core) - } - } ---- response_body -resty.core loaded: true - - - -=== TEST 2: lua_load_resty_core can be disabled ---- http_config - lua_load_resty_core off; ---- config - location = /t { - content_by_lua_block { - local loaded_resty_core = package.loaded["resty.core"] - - ngx.say("resty.core loaded: ", loaded_resty_core ~= nil) - } - } ---- response_body -resty.core loaded: false - - - -=== TEST 3: lua_load_resty_core is effective when using lua_shared_dict ---- http_config - lua_shared_dict dogs 128k; ---- config - location = /t { - content_by_lua_block { - local loaded_resty_core = package.loaded["resty.core"] - local resty_core = require "resty.core" - - ngx.say("resty.core loaded: ", loaded_resty_core == resty_core) - } - } ---- response_body -resty.core loaded: true diff --git a/debian/modules/http-lua/t/data/fake-shm-module/ngx_http_lua_fake_shm_module.c b/debian/modules/http-lua/t/data/fake-shm-module/ngx_http_lua_fake_shm_module.c index ffc32f5..0286853 100644 --- a/debian/modules/http-lua/t/data/fake-shm-module/ngx_http_lua_fake_shm_module.c +++ b/debian/modules/http-lua/t/data/fake-shm-module/ngx_http_lua_fake_shm_module.c @@ -213,9 +213,10 @@ ngx_http_lua_fake_shm_preload(lua_State *L) ngx_uint_t i; ngx_shm_zone_t **zone; - ngx_shm_zone_t **zone_udata; - cycle = (ngx_cycle_t *) ngx_cycle; + lua_getglobal(L, "__ngx_cycle"); + cycle = lua_touserdata(L, -1); + lua_pop(L, 1); hmcf_ctx = (ngx_http_conf_ctx_t *) cycle->conf_ctx[ngx_http_module.index]; lfsmcf = hmcf_ctx->main_conf[ngx_http_lua_fake_shm_module.ctx_index]; @@ -241,9 +242,7 @@ ngx_http_lua_fake_shm_preload(lua_State *L) lua_createtable(L, 1 /* narr */, 0 /* nrec */); /* table of zone[i] */ - zone_udata = lua_newuserdata(L, sizeof(ngx_shm_zone_t *)); - /* shared mt key ud */ - *zone_udata = zone[i]; + lua_pushlightuserdata(L, zone[i]); /* shared mt key ud */ lua_rawseti(L, -2, 1); /* {zone[i]} */ lua_pushvalue(L, -3); /* shared mt key ud mt */ lua_setmetatable(L, -2); /* shared mt key ud */ @@ -263,10 +262,9 @@ ngx_http_lua_fake_shm_preload(lua_State *L) static int ngx_http_lua_fake_shm_get_info(lua_State *L) { - ngx_int_t n; - ngx_shm_zone_t *zone; - ngx_shm_zone_t **zone_udata; - ngx_http_lua_fake_shm_ctx_t *ctx; + ngx_int_t n; + ngx_shm_zone_t *zone; + ngx_http_lua_fake_shm_ctx_t *ctx; n = lua_gettop(L); @@ -278,15 +276,13 @@ ngx_http_lua_fake_shm_get_info(lua_State *L) luaL_checktype(L, 1, LUA_TTABLE); lua_rawgeti(L, 1, 1); - zone_udata = lua_touserdata(L, -1); + zone = lua_touserdata(L, -1); lua_pop(L, 1); - if (zone_udata == NULL) { + if (zone == NULL) { return luaL_error(L, "bad \"zone\" argument"); } - zone = *zone_udata; - ctx = (ngx_http_lua_fake_shm_ctx_t *) zone->data; lua_pushlstring(L, (char *) zone->shm.name.data, zone->shm.name.len); diff --git a/debian/modules/http-lua/util/build.sh b/debian/modules/http-lua/util/build.sh index 14e9fd4..164bf9f 100755 --- a/debian/modules/http-lua/util/build.sh +++ b/debian/modules/http-lua/util/build.sh @@ -22,8 +22,6 @@ force=$2 #--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-pcre-jit \ --with-ipv6 \ @@ -57,7 +55,7 @@ time ngx-build $force $version \ --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-shm-module \ --add-module=$root/t/data/fake-delayed-load-module \ --with-http_gunzip_module \ --with-http_dav_module \ diff --git a/debian/modules/patches/http-lua/CVE-2020-11724.patch b/debian/modules/patches/http-lua/CVE-2020-11724.patch index 5b47abe..5e0eff7 100644 --- a/debian/modules/patches/http-lua/CVE-2020-11724.patch +++ b/debian/modules/patches/http-lua/CVE-2020-11724.patch @@ -13,8 +13,8 @@ Signed-off-by: Yichun Zhang (agentzh) Index: http-lua/src/ngx_http_lua_subrequest.c =================================================================== ---- http-lua.orig/src/ngx_http_lua_subrequest.c 2022-03-15 11:11:11.303357830 +0100 -+++ http-lua/src/ngx_http_lua_subrequest.c 2022-03-15 11:11:11.299357831 +0100 +--- http-lua.orig/src/ngx_http_lua_subrequest.c 2020-07-14 09:50:35.830928117 +0200 ++++ http-lua/src/ngx_http_lua_subrequest.c 2020-07-14 09:50:35.826928232 +0200 @@ -56,8 +56,6 @@ ngx_string("Content-Length"); @@ -99,7 +99,7 @@ Index: http-lua/src/ngx_http_lua_subrequest.c sr->method = method; switch (method) { -@@ -1132,100 +1116,6 @@ +@@ -1124,100 +1108,6 @@ } @@ -200,7 +200,7 @@ Index: http-lua/src/ngx_http_lua_subrequest.c static void ngx_http_lua_handle_subreq_responses(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx) -@@ -1740,11 +1630,17 @@ +@@ -1732,11 +1622,17 @@ static ngx_int_t @@ -220,7 +220,7 @@ Index: http-lua/src/ngx_http_lua_subrequest.c if (ngx_list_init(&sr->headers_in.headers, sr->pool, 20, sizeof(ngx_table_elt_t)) != NGX_OK) -@@ -1752,10 +1648,46 @@ +@@ -1744,10 +1640,46 @@ return NGX_ERROR; } @@ -270,7 +270,7 @@ Index: http-lua/src/ngx_http_lua_subrequest.c header = part->elts; for (i = 0; /* void */; i++) { -@@ -1770,7 +1702,14 @@ +@@ -1762,7 +1694,14 @@ i = 0; } @@ -286,7 +286,7 @@ Index: http-lua/src/ngx_http_lua_subrequest.c header[i].key.data, (int) header[i].value.len, header[i].value.data); -@@ -1782,9 +1721,10 @@ +@@ -1774,9 +1713,10 @@ } dd("after: parent req headers count: %d", @@ -300,8 +300,8 @@ Index: http-lua/src/ngx_http_lua_subrequest.c /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ Index: http-lua/t/020-subrequest.t =================================================================== ---- http-lua.orig/t/020-subrequest.t 2022-03-15 11:11:11.303357830 +0100 -+++ http-lua/t/020-subrequest.t 2022-03-15 11:11:11.299357831 +0100 +--- http-lua.orig/t/020-subrequest.t 2020-07-14 09:50:35.830928117 +0200 ++++ http-lua/t/020-subrequest.t 2020-07-14 09:50:35.826928232 +0200 @@ -14,6 +14,7 @@ plan tests => repeat_each() * (blocks() * 3 + 23); From 054b32430f5190016e23c5f4ec8c2b0d564731a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Tue, 5 Apr 2022 19:20:29 +0200 Subject: [PATCH 085/329] http-lus: Backport segfault bugfix --- debian/changelog | 8 +++++ .../http-lua/bug-994178-segfault.patch | 31 +++++++++++++++++++ debian/modules/patches/http-lua/series | 1 + 3 files changed, 40 insertions(+) create mode 100644 debian/modules/patches/http-lua/bug-994178-segfault.patch diff --git a/debian/changelog b/debian/changelog index 8af7ecf..58f262e 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,11 @@ +nginx (1.18.0-9) UNRELEASED; urgency=medium + + * http-lua: Downgrade to 0.10.13 (Closes: #1008787). + * http-lus: Backport upstream bugfix for segfault in nginx core >= 1.15.0 when + libnginx-mod-http-lua is loaded and init_worker_by_lua* is used. + + -- Jan Mojžíš Tue, 05 Apr 2022 19:11:47 +0200 + nginx (1.18.0-8) unstable; urgency=medium * Restore patch: diff --git a/debian/modules/patches/http-lua/bug-994178-segfault.patch b/debian/modules/patches/http-lua/bug-994178-segfault.patch new file mode 100644 index 0000000..89dee6a --- /dev/null +++ b/debian/modules/patches/http-lua/bug-994178-segfault.patch @@ -0,0 +1,31 @@ +From: Datong Sun +Date: Wed Jul 18 16:21:09 2018 -0700 +Origin: https://github.com/openresty/lua-nginx-module/commit/e94f2e5d64daa45ff396e262d8dab8e56f5f10e0 +Subject: fixed segfault in NGINX core >= 1.15.0 when init_worker_by_lua* is + used. + +Signed-off-by: Yichun Zhang (agentzh) + +diff --git a/src/ngx_http_lua_initworkerby.c b/src/ngx_http_lua_initworkerby.c +index 4a722a06..2a82fcb9 100644 +--- a/src/ngx_http_lua_initworkerby.c ++++ b/src/ngx_http_lua_initworkerby.c +@@ -25,6 +25,7 @@ ngx_http_lua_init_worker(ngx_cycle_t *cycle) + void *cur, *prev; + ngx_uint_t i; + ngx_conf_t conf; ++ ngx_conf_file_t cf_file; + ngx_cycle_t *fake_cycle; + ngx_module_t **modules; + ngx_open_file_t *file, *ofile; +@@ -166,6 +167,10 @@ ngx_http_lua_init_worker(ngx_cycle_t *cycle) + conf.pool = fake_cycle->pool; + conf.log = cycle->log; + ++ ngx_memzero(&cf_file, sizeof(cf_file)); ++ cf_file.file.name = cycle->conf_file; ++ conf.conf_file = &cf_file; ++ + http_ctx.loc_conf = ngx_pcalloc(conf.pool, + sizeof(void *) * ngx_http_max_module); + if (http_ctx.loc_conf == NULL) { diff --git a/debian/modules/patches/http-lua/series b/debian/modules/patches/http-lua/series index 1c68a88..61d5c01 100644 --- a/debian/modules/patches/http-lua/series +++ b/debian/modules/patches/http-lua/series @@ -1,2 +1,3 @@ discover-luajit-2.1.patch CVE-2020-11724.patch +bug-994178-segfault.patch From b58e677848e4dd9a33c6d43dd157de35489b56ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Tue, 5 Apr 2022 19:25:57 +0200 Subject: [PATCH 086/329] d/control: fix Homepage nginx.net -> nginx.org --- debian/changelog | 5 +++-- debian/control | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/debian/changelog b/debian/changelog index 58f262e..12a7a37 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,8 +1,9 @@ nginx (1.18.0-9) UNRELEASED; urgency=medium * http-lua: Downgrade to 0.10.13 (Closes: #1008787). - * http-lus: Backport upstream bugfix for segfault in nginx core >= 1.15.0 when - libnginx-mod-http-lua is loaded and init_worker_by_lua* is used. + * http-lua: Backport upstream bugfix for segfault in nginx core >= 1.15.0 + when libnginx-mod-http-lua is loaded and init_worker_by_lua* is used. + * d/control: fix Homepage nginx.net -> nginx.org (Closes: #976158) -- Jan Mojžíš Tue, 05 Apr 2022 19:11:47 +0200 diff --git a/debian/control b/debian/control index 719dcc7..158de5b 100644 --- a/debian/control +++ b/debian/control @@ -23,7 +23,7 @@ Build-Depends: debhelper-compat (= 13), quilt, zlib1g-dev Standards-Version: 4.6.0 -Homepage: https://nginx.net +Homepage: https://nginx.org Vcs-Git: https://salsa.debian.org/nginx-team/nginx.git Vcs-Browser: https://salsa.debian.org/nginx-team/nginx Rules-Requires-Root: no From ced892ac0d0422b6032915918d904d74266bc061 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Tue, 5 Apr 2022 19:38:33 +0200 Subject: [PATCH 087/329] d/control: Add mips64el,ppc64,kfreebsd-amd64 to list of luajit platforms. --- debian/changelog | 1 + debian/control | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index 12a7a37..6938cd8 100644 --- a/debian/changelog +++ b/debian/changelog @@ -3,6 +3,7 @@ nginx (1.18.0-9) UNRELEASED; urgency=medium * http-lua: Downgrade to 0.10.13 (Closes: #1008787). * http-lua: Backport upstream bugfix for segfault in nginx core >= 1.15.0 when libnginx-mod-http-lua is loaded and init_worker_by_lua* is used. + * d/control: Add mips64el,ppc64,kfreebsd-amd64 to list of luajit platforms. * d/control: fix Homepage nginx.net -> nginx.org (Closes: #976158) -- Jan Mojžíš Tue, 05 Apr 2022 19:11:47 +0200 diff --git a/debian/control b/debian/control index 158de5b..44b741e 100644 --- a/debian/control +++ b/debian/control @@ -10,8 +10,8 @@ Build-Depends: debhelper-compat (= 13), libgd-dev, libgeoip-dev, libhiredis-dev, - liblua5.1-0-dev [!i386 !amd64 !kfreebsd-i386 !armel !armhf !powerpc !powerpcspe !mips !mipsel !arm64 !ppc64el], - libluajit-5.1-dev [i386 amd64 kfreebsd-i386 armel armhf powerpc powerpcspe mips mipsel arm64 ppc64el], + liblua5.1-0-dev [!i386 !amd64 !kfreebsd-i386 !kfreebsd-amd64 !armel !armhf !powerpc !powerpcspe !mips !mipsel !mips64el !arm64 !ppc64 !ppc64el], + libluajit-5.1-dev [i386 amd64 kfreebsd-i386 kfreebsd-amd64 armel armhf powerpc powerpcspe mips mipsel mips64el arm64 ppc64 ppc64el], libmaxminddb-dev, libmhash-dev, libpam0g-dev, From c3be1137f3ca56d5a8e4c3f0c5351b14221f8c72 Mon Sep 17 00:00:00 2001 From: Thomas Ward Date: Thu, 7 Apr 2022 15:35:33 -0400 Subject: [PATCH 088/329] Update watch file syntax for proper version matching/reporting --- debian/changelog | 6 ++++++ debian/watch | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 6938cd8..921ba09 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,11 +1,17 @@ nginx (1.18.0-9) UNRELEASED; urgency=medium + [ Jan Mojžíš ] * http-lua: Downgrade to 0.10.13 (Closes: #1008787). * http-lua: Backport upstream bugfix for segfault in nginx core >= 1.15.0 when libnginx-mod-http-lua is loaded and init_worker_by_lua* is used. * d/control: Add mips64el,ppc64,kfreebsd-amd64 to list of luajit platforms. * d/control: fix Homepage nginx.net -> nginx.org (Closes: #976158) + [ Thomas Ward ] + * d/watch: Update watch syntax to match all even versions of NGINX releases + rather than use a watch syntax that is static to one specific version. + This will fix the untracked "New upstream stable versions" problem. + -- Jan Mojžíš Tue, 05 Apr 2022 19:11:47 +0200 nginx (1.18.0-8) unstable; urgency=medium diff --git a/debian/watch b/debian/watch index 26440a9..86d8da1 100644 --- a/debian/watch +++ b/debian/watch @@ -1,3 +1,3 @@ version=4 opts=pgpsigurlmangle=s/$/.asc/ \ -https://nginx.org/download/nginx-(1\.18\.\d+)\.tar\.gz +https://nginx.org/download/nginx-(\d+\.\d+[02468]\.\d+)\.tar\.gz From 7e21f77a9033fdd9b86f16c79b3b26f02be5a146 Mon Sep 17 00:00:00 2001 From: Thomas Ward Date: Tue, 12 Apr 2022 12:54:09 -0400 Subject: [PATCH 089/329] Update uploaders as Thomas Ward is now a maintainer in Salsa --- debian/changelog | 2 ++ debian/control | 1 + 2 files changed, 3 insertions(+) diff --git a/debian/changelog b/debian/changelog index 921ba09..8dd544e 100644 --- a/debian/changelog +++ b/debian/changelog @@ -11,6 +11,8 @@ nginx (1.18.0-9) UNRELEASED; urgency=medium * d/watch: Update watch syntax to match all even versions of NGINX releases rather than use a watch syntax that is static to one specific version. This will fix the untracked "New upstream stable versions" problem. + * d/control: Update 'uploaders' as Thomas Ward is now a maintainer in + the Salsa repository. -- Jan Mojžíš Tue, 05 Apr 2022 19:11:47 +0200 diff --git a/debian/control b/debian/control index 44b741e..52b24de 100644 --- a/debian/control +++ b/debian/control @@ -4,6 +4,7 @@ Priority: optional Maintainer: Debian Nginx Maintainers Uploaders: Christos Trochalakis , Ondřej Nový , + Thomas Ward , Build-Depends: debhelper-compat (= 13), dpkg-dev (>= 1.15.5), libexpat-dev, From 2a278d9a5566eae406f7151b98dc2a9be8a5b899 Mon Sep 17 00:00:00 2001 From: Thomas Ward Date: Thu, 14 Apr 2022 16:28:34 -0400 Subject: [PATCH 090/329] Release of 1.18.0-9 --- debian/changelog | 2 +- debian/copyright | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index 8dd544e..e65ef2c 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -nginx (1.18.0-9) UNRELEASED; urgency=medium +nginx (1.18.0-9) unstable; urgency=medium [ Jan Mojžíš ] * http-lua: Downgrade to 0.10.13 (Closes: #1008787). diff --git a/debian/copyright b/debian/copyright index 03ef16d..f82fc2d 100644 --- a/debian/copyright +++ b/debian/copyright @@ -41,7 +41,7 @@ Copyright: 2007-2009, Fabio Tranchitella 2011 Dmitry E. Oboukhov 2011-2013, Cyril Lavier 2013-2016, Christos Trochalakis - 2019-2020, Thomas Ward + 2019-2022, Thomas Ward 2020-2022, Ondřej Nový License: BSD-2-clause From 5c35f1696fdb5521e72e0c0f79b3203140d34327 Mon Sep 17 00:00:00 2001 From: Thomas Ward Date: Tue, 19 Apr 2022 09:50:28 -0400 Subject: [PATCH 091/329] New upstream version 1.20.2 --- CHANGES | 261 +++- CHANGES.ru | 263 +++- LICENSE | 4 +- auto/init | 2 + auto/install | 2 + auto/make | 13 +- auto/module | 44 +- auto/modules | 16 + auto/options | 5 + auto/os/linux | 25 + auto/unix | 79 +- configure | 4 + contrib/vim/syntax/nginx.vim | 155 ++- man/nginx.8 | 13 +- src/core/nginx.c | 42 +- src/core/nginx.h | 4 +- src/core/ngx_buf.c | 8 +- src/core/ngx_buf.h | 20 +- src/core/ngx_conf_file.c | 2 +- src/core/ngx_connection.c | 41 +- src/core/ngx_connection.h | 3 +- src/core/ngx_cycle.c | 17 +- src/core/ngx_cycle.h | 2 + src/core/ngx_log.c | 19 +- src/core/ngx_log.h | 2 +- src/core/ngx_resolver.c | 100 +- src/core/ngx_string.c | 87 +- src/event/modules/ngx_eventport_module.c | 2 +- src/event/ngx_event.c | 6 +- src/event/ngx_event_accept.c | 2 + src/event/ngx_event_connect.c | 2 + src/event/ngx_event_openssl.c | 395 +++++- src/event/ngx_event_openssl.h | 35 + src/event/ngx_event_openssl_stapling.c | 1230 ++++++++++++++--- src/event/ngx_event_pipe.c | 28 + src/event/ngx_event_udp.c | 2 + src/http/modules/ngx_http_fastcgi_module.c | 136 +- src/http/modules/ngx_http_flv_module.c | 6 - src/http/modules/ngx_http_grpc_module.c | 167 ++- .../modules/ngx_http_gzip_filter_module.c | 30 +- src/http/modules/ngx_http_limit_req_module.c | 51 +- src/http/modules/ngx_http_memcached_module.c | 9 +- src/http/modules/ngx_http_mp4_module.c | 6 - src/http/modules/ngx_http_proxy_module.c | 851 ++++++++++-- src/http/modules/ngx_http_scgi_module.c | 36 + .../modules/ngx_http_slice_filter_module.c | 5 + src/http/modules/ngx_http_ssl_module.c | 281 +++- src/http/modules/ngx_http_ssl_module.h | 6 + .../modules/ngx_http_stub_status_module.c | 10 - .../ngx_http_upstream_keepalive_module.c | 16 +- .../modules/ngx_http_userid_filter_module.c | 74 + src/http/modules/ngx_http_uwsgi_module.c | 71 + .../modules/ngx_http_xslt_filter_module.c | 1 + src/http/ngx_http.c | 5 +- src/http/ngx_http_cache.h | 3 + src/http/ngx_http_core_module.c | 36 +- src/http/ngx_http_core_module.h | 1 + src/http/ngx_http_file_cache.c | 50 +- src/http/ngx_http_parse.c | 17 + src/http/ngx_http_request.c | 171 ++- src/http/ngx_http_request.h | 3 + src/http/ngx_http_request_body.c | 208 ++- src/http/ngx_http_special_response.c | 4 + src/http/ngx_http_upstream.c | 52 +- src/http/ngx_http_upstream.h | 3 + src/http/ngx_http_upstream_round_robin.c | 20 +- src/http/ngx_http_upstream_round_robin.h | 1 + src/http/ngx_http_variables.c | 36 +- src/http/v2/ngx_http_v2.c | 319 ++++- src/http/v2/ngx_http_v2.h | 2 + src/http/v2/ngx_http_v2_module.c | 146 +- src/http/v2/ngx_http_v2_module.h | 5 - src/mail/ngx_mail.c | 2 + src/mail/ngx_mail.h | 9 +- src/mail/ngx_mail_auth_http_module.c | 78 +- src/mail/ngx_mail_core_module.c | 5 + src/mail/ngx_mail_handler.c | 136 +- src/mail/ngx_mail_imap_handler.c | 22 +- src/mail/ngx_mail_pop3_handler.c | 22 +- src/mail/ngx_mail_proxy_module.c | 260 +++- src/mail/ngx_mail_realip_module.c | 269 ++++ src/mail/ngx_mail_smtp_handler.c | 22 +- src/mail/ngx_mail_ssl_module.c | 32 + src/mail/ngx_mail_ssl_module.h | 1 + src/misc/ngx_cpp_test_module.cpp | 2 + src/os/unix/ngx_errno.c | 137 +- src/os/unix/ngx_files.c | 45 + src/os/unix/ngx_files.h | 6 +- src/os/unix/ngx_process_cycle.c | 71 +- src/os/unix/ngx_udp_sendmsg_chain.c | 7 + src/stream/ngx_stream_proxy_module.c | 37 +- src/stream/ngx_stream_set_module.c | 226 +++ src/stream/ngx_stream_ssl_module.c | 33 + src/stream/ngx_stream_ssl_module.h | 1 + src/stream/ngx_stream_upstream_round_robin.c | 20 +- src/stream/ngx_stream_upstream_round_robin.h | 1 + src/stream/ngx_stream_write_filter_module.c | 3 +- 97 files changed, 6154 insertions(+), 1066 deletions(-) create mode 100644 src/mail/ngx_mail_realip_module.c create mode 100644 src/stream/ngx_stream_set_module.c diff --git a/CHANGES b/CHANGES index 6da9172..7881653 100644 --- a/CHANGES +++ b/CHANGES @@ -1,7 +1,264 @@ -Changes with nginx 1.18.0 21 Apr 2020 +Changes with nginx 1.20.2 16 Nov 2021 - *) 1.18.x stable branch. + *) Feature: OpenSSL 3.0 compatibility. + + *) Bugfix: SSL variables might be empty when used in logs; the bug had + appeared in 1.19.5. + + *) Bugfix: keepalive connections with gRPC backends might not be closed + after receiving a GOAWAY frame. + + *) Bugfix: backend SSL connections in the stream module might hang after + an SSL handshake. + + *) Bugfix: SSL connections with gRPC backends might hang if select, + poll, or /dev/poll methods were used. + + *) Bugfix: in the $content_length variable when using chunked transfer + encoding. + + *) Bugfix: requests might hang when using HTTP/2 and the "aio_write" + directive. + + +Changes with nginx 1.20.1 25 May 2021 + + *) Security: 1-byte memory overwrite might occur during DNS server + response processing if the "resolver" directive was used, allowing an + attacker who is able to forge UDP packets from the DNS server to + cause worker process crash or, potentially, arbitrary code execution + (CVE-2021-23017). + + +Changes with nginx 1.20.0 20 Apr 2021 + + *) 1.20.x stable branch. + + +Changes with nginx 1.19.10 13 Apr 2021 + + *) Change: the default value of the "keepalive_requests" directive was + changed to 1000. + + *) Feature: the "keepalive_time" directive. + + *) Feature: the $connection_time variable. + + *) Workaround: "gzip filter failed to use preallocated memory" alerts + appeared in logs when using zlib-ng. + + +Changes with nginx 1.19.9 30 Mar 2021 + + *) Bugfix: nginx could not be built with the mail proxy module, but + without the ngx_mail_ssl_module; the bug had appeared in 1.19.8. + + *) Bugfix: "upstream sent response body larger than indicated content + length" errors might occur when working with gRPC backends; the bug + had appeared in 1.19.1. + + *) Bugfix: nginx might not close a connection till keepalive timeout + expiration if the connection was closed by the client while + discarding the request body. + + *) Bugfix: nginx might not detect that a connection was already closed + by the client when waiting for auth_delay or limit_req delay, or when + working with backends. + + *) Bugfix: in the eventport method. + + +Changes with nginx 1.19.8 09 Mar 2021 + + *) Feature: flags in the "proxy_cookie_flags" directive can now contain + variables. + + *) Feature: the "proxy_protocol" parameter of the "listen" directive, + the "proxy_protocol" and "set_real_ip_from" directives in mail proxy. + + *) Bugfix: HTTP/2 connections were immediately closed when using + "keepalive_timeout 0"; the bug had appeared in 1.19.7. + + *) Bugfix: some errors were logged as unknown if nginx was built with + glibc 2.32. + + *) Bugfix: in the eventport method. + + +Changes with nginx 1.19.7 16 Feb 2021 + + *) Change: connections handling in HTTP/2 has been changed to better + match HTTP/1.x; the "http2_recv_timeout", "http2_idle_timeout", and + "http2_max_requests" directives have been removed, the + "keepalive_timeout" and "keepalive_requests" directives should be + used instead. + + *) Change: the "http2_max_field_size" and "http2_max_header_size" + directives have been removed, the "large_client_header_buffers" + directive should be used instead. + + *) Feature: now, if free worker connections are exhausted, nginx starts + closing not only keepalive connections, but also connections in + lingering close. + + *) Bugfix: "zero size buf in output" alerts might appear in logs if an + upstream server returned an incorrect response during unbuffered + proxying; the bug had appeared in 1.19.1. + + *) Bugfix: HEAD requests were handled incorrectly if the "return" + directive was used with the "image_filter" or "xslt_stylesheet" + directives. + + *) Bugfix: in the "add_trailer" directive. + + +Changes with nginx 1.19.6 15 Dec 2020 + + *) Bugfix: "no live upstreams" errors if a "server" inside "upstream" + block was marked as "down". + + *) Bugfix: a segmentation fault might occur in a worker process if HTTPS + was used; the bug had appeared in 1.19.5. + + *) Bugfix: nginx returned the 400 response on requests like + "GET http://example.com?args HTTP/1.0". + + *) Bugfix: in the ngx_http_flv_module and ngx_http_mp4_module. + Thanks to Chris Newton. + + +Changes with nginx 1.19.5 24 Nov 2020 + + *) Feature: the -e switch. + + *) Feature: the same source files can now be specified in different + modules while building addon modules. + + *) Bugfix: SSL shutdown did not work when lingering close was used. + + *) Bugfix: "upstream sent frame for closed stream" errors might occur + when working with gRPC backends. + + *) Bugfix: in request body filters internal API. + + +Changes with nginx 1.19.4 27 Oct 2020 + + *) Feature: the "ssl_conf_command", "proxy_ssl_conf_command", + "grpc_ssl_conf_command", and "uwsgi_ssl_conf_command" directives. + + *) Feature: the "ssl_reject_handshake" directive. + + *) Feature: the "proxy_smtp_auth" directive in mail proxy. + + +Changes with nginx 1.19.3 29 Sep 2020 + + *) Feature: the ngx_stream_set_module. + + *) Feature: the "proxy_cookie_flags" directive. + + *) Feature: the "userid_flags" directive. + + *) Bugfix: the "stale-if-error" cache control extension was erroneously + applied if backend returned a response with status code 500, 502, + 503, 504, 403, 404, or 429. + + *) Bugfix: "[crit] cache file ... has too long header" messages might + appear in logs if caching was used and the backend returned responses + with the "Vary" header line. + + *) Workaround: "[crit] SSL_write() failed" messages might appear in logs + when using OpenSSL 1.1.1. + + *) Bugfix: "SSL_shutdown() failed (SSL: ... bad write retry)" messages + might appear in logs; the bug had appeared in 1.19.2. + + *) Bugfix: a segmentation fault might occur in a worker process when + using HTTP/2 if errors with code 400 were redirected to a proxied + location using the "error_page" directive. + + *) Bugfix: socket leak when using HTTP/2 and subrequests in the njs + module. + + +Changes with nginx 1.19.2 11 Aug 2020 + + *) Change: now nginx starts closing keepalive connections before all + free worker connections are exhausted, and logs a warning about this + to the error log. + + *) Change: optimization of client request body reading when using + chunked transfer encoding. + + *) Bugfix: memory leak if the "ssl_ocsp" directive was used. + + *) Bugfix: "zero size buf in output" alerts might appear in logs if a + FastCGI server returned an incorrect response; the bug had appeared + in 1.19.1. + + *) Bugfix: a segmentation fault might occur in a worker process if + different large_client_header_buffers sizes were used in different + virtual servers. + + *) Bugfix: SSL shutdown might not work. + + *) Bugfix: "SSL_shutdown() failed (SSL: ... bad write retry)" messages + might appear in logs. + + *) Bugfix: in the ngx_http_slice_module. + + *) Bugfix: in the ngx_http_xslt_filter_module. + + +Changes with nginx 1.19.1 07 Jul 2020 + + *) Change: the "lingering_close", "lingering_time", and + "lingering_timeout" directives now work when using HTTP/2. + + *) Change: now extra data sent by a backend are always discarded. + + *) Change: now after receiving a too short response from a FastCGI + server nginx tries to send the available part of the response to the + client, and then closes the client connection. + + *) Change: now after receiving a response with incorrect length from a + gRPC backend nginx stops response processing with an error. + + *) Feature: the "min_free" parameter of the "proxy_cache_path", + "fastcgi_cache_path", "scgi_cache_path", and "uwsgi_cache_path" + directives. + Thanks to Adam Bambuch. + + *) Bugfix: nginx did not delete unix domain listen sockets during + graceful shutdown on the SIGQUIT signal. + + *) Bugfix: zero length UDP datagrams were not proxied. + + *) Bugfix: proxying to uwsgi backends using SSL might not work. + Thanks to Guanzhong Chen. + + *) Bugfix: in error handling when using the "ssl_ocsp" directive. + + *) Bugfix: on XFS and NFS file systems disk cache size might be + calculated incorrectly. + + *) Bugfix: "negative size buf in writer" alerts might appear in logs if + a memcached server returned a malformed response. + + +Changes with nginx 1.19.0 26 May 2020 + + *) Feature: client certificate validation with OCSP. + + *) Bugfix: "upstream sent frame for closed stream" errors might occur + when working with gRPC backends. + + *) Bugfix: OCSP stapling might not work if the "resolver" directive was + not specified. + + *) Bugfix: connections with incorrect HTTP/2 preface were not logged. Changes with nginx 1.17.10 14 Apr 2020 diff --git a/CHANGES.ru b/CHANGES.ru index e430021..a766cc5 100644 --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,7 +1,266 @@ -Изменения в nginx 1.18.0 21.04.2020 +Изменения в nginx 1.20.2 16.11.2021 - *) Стабильная ветка 1.18.x. + *) Добавление: совместимость с OpenSSL 3.0. + + *) Исправление: SSL-переменные могли быть пустыми при записи в лог; + ошибка появилась в 1.19.5. + + *) Исправление: keepalive-соединения с gRPC-бэкендами могли не + закрываться после получения GOAWAY-фрейма. + + *) Исправление: SSL-соединения к бэкендам в модуле stream могли зависать + после SSL handshake. + + *) Исправление: SSL-соединения с gRPC-бэкендами могли зависать, если + использовались методы select, poll или /dev/poll. + + *) Исправление: в переменной $content_length при использовании chunked + transfer encoding. + + *) Исправление: при использовании HTTP/2 и директивы aio_write запросы + могли зависать. + + +Изменения в nginx 1.20.1 25.05.2021 + + *) Безопасность: при использовании директивы resolver во время обработки + ответа DNS-сервера могла происходить перезапись одного байта памяти, + что позволяло атакующему, имеющему возможность подделывать UDP-пакеты + от DNS-сервера, вызвать падение рабочего процесса или, потенциально, + выполнение произвольного кода (CVE-2021-23017). + + +Изменения в nginx 1.20.0 20.04.2021 + + *) Стабильная ветка 1.20.x. + + +Изменения в nginx 1.19.10 13.04.2021 + + *) Изменение: в директиве keepalive_requests значение по умолчанию + изменено на 1000. + + *) Добавление: директива keepalive_time. + + *) Добавление: переменная $connection_time. + + *) Изменение: при использовании zlib-ng в логах появлялись сообщения + "gzip filter failed to use preallocated memory". + + +Изменения в nginx 1.19.9 30.03.2021 + + *) Исправление: nginx не собирался с почтовым прокси-сервером, но без + модуля ngx_mail_ssl_module; ошибка появилась в 1.19.8. + + *) Исправление: при работе с gRPC-бэкендами могли возникать ошибки + "upstream sent response body larger than indicated content length"; + ошибка появилась в 1.19.1. + + *) Исправление: если клиент закрывал соединение в момент отбрасывания + тела запроса, nginx мог не закрыть соединение до истечения + keepalive-таймаута. + + *) Исправление: при ожидании задержки limit_req или auth_delay, а также + при работе с бэкендами nginx мог не обнаружить, что соединение уже + закрыто клиентом. + + *) Исправление: в методе обработки соединений eventport. + + +Изменения в nginx 1.19.8 09.03.2021 + + *) Добавление: в директиве proxy_cookie_flags теперь флаги можно + задавать с помощью переменных. + + *) Добавление: параметр proxy_protocol в директиве listen, директивы + proxy_protocol и set_real_ip_from в почтовом прокси-сервере. + + *) Исправление: HTTP/2-соединения сразу закрывались при использовании + "keepalive_timeout 0"; ошибка появилась в 1.19.7. + + *) Исправление: некоторые ошибки логгировались как неизвестные, если + nginx был собран с glibc 2.32. + + *) Исправление: в методе обработки соединений eventport. + + +Изменения в nginx 1.19.7 16.02.2021 + + *) Изменение: обработка соединений в HTTP/2 была изменена и теперь более + соответствует HTTP/1.x; директивы http2_recv_timeout, + http2_idle_timeout и http2_max_requests упразднены, вместо них + следует использовать директивы keepalive_timeout и + keepalive_requests. + + *) Изменение: директивы http2_max_field_size и http2_max_header_size + упразднены, вместо них следует использовать директиву + large_client_header_buffers. + + *) Добавление: теперь при исчерпании свободных соединений nginx + закрывает не только keepalive-соединения, но и соединения в lingering + close. + + *) Исправление: в логах могли появляться сообщения "zero size buf in + output", если бэкенд возвращал некорректный ответ при + небуферизированном проксировании; ошибка появилась в 1.19.1. + + *) Исправление: при использовании директивы return вместе с image_filter + или xslt_stylesheet HEAD-запросы обрабатывались некорректно. + + *) Исправление: в директиве add_trailer. + + +Изменения в nginx 1.19.6 15.12.2020 + + *) Исправление: ошибки "no live upstreams", если server в блоке upstream + был помечен как down. + + *) Исправление: при использовании HTTPS в рабочем процессе мог произойти + segmentation fault; ошибка появилась в 1.19.5. + + *) Исправление: nginx возвращал ошибку 400 на запросы вида + "GET http://example.com?args HTTP/1.0". + + *) Исправление: в модулях ngx_http_flv_module и ngx_http_mp4_module. + Спасибо Chris Newton. + + +Изменения в nginx 1.19.5 24.11.2020 + + *) Добавление: ключ -e. + + *) Добавление: при сборке дополнительных модулей теперь можно указывать + одни и те же исходные файлы в разных модулях. + + *) Исправление: SSL shutdown не работал при закрытии соединений с + ожиданием дополнительных данных (lingering close). + + *) Исправление: при работе с gRPC-бэкендами могли возникать ошибки + "upstream sent frame for closed stream". + + *) Исправление: во внутреннем API для обработки тела запроса. + + +Изменения в nginx 1.19.4 27.10.2020 + + *) Добавление: директивы ssl_conf_command, proxy_ssl_conf_command, + grpc_ssl_conf_command и uwsgi_ssl_conf_command. + + *) Добавление: директива ssl_reject_handshake. + + *) Добавление: директива proxy_smtp_auth в почтовом прокси-сервере. + + +Изменения в nginx 1.19.3 29.09.2020 + + *) Добавление: модуль ngx_stream_set_module. + + *) Добавление: директива proxy_cookie_flags. + + *) Добавление: директива userid_flags. + + *) Исправление: расширение управления кэшированием stale-if-error + ошибочно применялось, если бэкенд возвращал ответ с кодом 500, 502, + 503, 504, 403, 404 или 429. + + *) Исправление: если использовалось кэширование и бэкенд возвращал + ответы с строкой заголовка Vary, в логах могли появляться сообщения + "[crit] cache file ... has too long header". + + *) Изменение: при использовании OpenSSL 1.1.1 в логах могли появляться + сообщения "[crit] SSL_write() failed". + + *) Исправление: в логах могли появляться сообщения "SSL_shutdown() + failed (SSL: ... bad write retry)"; ошибка появилась в 1.19.2. + + *) Исправление: при использовании HTTP/2 в рабочем процессе мог + произойти segmentation fault, если ошибки с кодом 400 с помощью + директивы error_page перенаправлялись в проксируемый location. + + *) Исправление: утечки сокетов при использовании HTTP/2 и подзапросов в + модуле njs. + + +Изменения в nginx 1.19.2 11.08.2020 + + *) Изменение: теперь nginx начинает закрывать keepalive-соединения, не + дожидаясь исчерпания всех свободных соединений, а также пишет об этом + предупреждение в лог ошибок. + + *) Изменение: оптимизация чтения тела запроса при использовании chunked + transfer encoding. + + *) Исправление: утечки памяти при использовании директивы ssl_ocsp. + + *) Исправление: в логах могли появляться сообщения "zero size buf in + output", если FastCGI-сервер возвращал некорректный ответ; ошибка + появилась в 1.19.1. + + *) Исправление: в рабочем процессе мог произойти segmentation fault, + если размеры large_client_header_buffers отличались в разных + виртуальных серверах. + + *) Исправление: SSL shutdown мог не работать. + + *) Исправление: в логах могли появляться сообщения "SSL_shutdown() + failed (SSL: ... bad write retry)". + + *) Исправление: в модуле ngx_http_slice_module. + + *) Исправление: в модуле ngx_http_xslt_filter_module. + + +Изменения в nginx 1.19.1 07.07.2020 + + *) Изменение: директивы lingering_close, lingering_time и + lingering_timeout теперь работают при использовании HTTP/2. + + *) Изменение: теперь лишние данные, присланные бэкендом, всегда + отбрасываются. + + *) Изменение: теперь при получении слишком короткого ответа от + FastCGI-сервера nginx пытается отправить клиенту доступную часть + ответа, после чего закрывает соединение с клиентом. + + *) Изменение: теперь при получении ответа некорректной длины от + gRPC-бэкенда nginx прекращает обработку ответа с ошибкой. + + *) Добавление: параметр min_free в директивах proxy_cache_path, + fastcgi_cache_path, scgi_cache_path и uwsgi_cache_path. + Спасибо Adam Bambuch. + + *) Исправление: nginx не удалял unix domain listen-сокеты при плавном + завершении по сигналу SIGQUIT. + + *) Исправление: UDP-пакеты нулевого размера не проксировались. + + *) Исправление: проксирование на uwsgi-бэкенды с использованием SSL + могло не работать. + Спасибо Guanzhong Chen. + + *) Исправление: в обработке ошибок при использовании директивы ssl_ocsp. + + *) Исправление: при использовании файловых систем XFS и NFS размер кэша + на диске мог считаться некорректно. + + *) Исправление: если сервер memcached возвращал некорректный ответ, в + логах могли появляться сообщения "negative size buf in writer". + + +Изменения в nginx 1.19.0 26.05.2020 + + *) Добавление: проверка клиентских сертификатов с помощью OCSP. + + *) Исправление: при работе с gRPC-бэкендами могли возникать ошибки + "upstream sent frame for closed stream". + + *) Исправление: OCSP stapling мог не работать, если не была указана + директива resolver. + + *) Исправление: соединения с некорректным HTTP/2 preface не + логгировались. Изменения в nginx 1.17.10 14.04.2020 diff --git a/LICENSE b/LICENSE index c63e0ba..fd0c72d 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ /* - * Copyright (C) 2002-2019 Igor Sysoev - * Copyright (C) 2011-2019 Nginx, Inc. + * Copyright (C) 2002-2021 Igor Sysoev + * Copyright (C) 2011-2021 Nginx, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/auto/init b/auto/init index 910f529..f816dfc 100644 --- a/auto/init +++ b/auto/init @@ -48,4 +48,6 @@ default: build clean: rm -rf Makefile $NGX_OBJS + +.PHONY: default clean END diff --git a/auto/install b/auto/install index d884487..c764fdd 100644 --- a/auto/install +++ b/auto/install @@ -215,4 +215,6 @@ upgrade: test -f $NGX_PID_PATH.oldbin kill -QUIT \`cat $NGX_PID_PATH.oldbin\` + +.PHONY: build install modules upgrade END diff --git a/auto/make b/auto/make index 34c40cd..ef7c9f6 100644 --- a/auto/make +++ b/auto/make @@ -313,7 +313,7 @@ $ngx_obj: \$(CORE_DEPS) \$(HTTP_DEPS)$ngx_cont$ngx_src END fi - done + done fi @@ -343,7 +343,7 @@ $ngx_obj: \$(CORE_DEPS) \$(MAIL_DEPS)$ngx_cont$ngx_src $ngx_cc$ngx_tab$ngx_objout$ngx_obj$ngx_tab$ngx_src$NGX_AUX END - done + done fi @@ -373,7 +373,7 @@ $ngx_obj: \$(CORE_DEPS) \$(STREAM_DEPS)$ngx_cont$ngx_src $ngx_cc$ngx_tab$ngx_objout$ngx_obj$ngx_tab$ngx_src$NGX_AUX END - done + done fi @@ -399,7 +399,7 @@ $ngx_obj: \$(CORE_DEPS) $ngx_cont$ngx_src $ngx_cc$ngx_tab$ngx_objout$ngx_obj$ngx_tab$ngx_src$NGX_AUX END - done + done fi @@ -431,7 +431,7 @@ $ngx_obj: \$(ADDON_DEPS)$ngx_cont$ngx_src $ngx_cc$ngx_tab$ngx_objout$ngx_obj$ngx_tab$ngx_src$NGX_AUX END - done + done fi @@ -502,6 +502,7 @@ fi for ngx_module in $DYNAMIC_MODULES do eval ngx_module_srcs="\$${ngx_module}_SRCS" + eval ngx_module_shrd="\$${ngx_module}_SHRD" eval eval ngx_module_libs="\\\"\$${ngx_module}_LIBS\\\"" eval ngx_module_modules="\$${ngx_module}_MODULES" @@ -567,7 +568,7 @@ END | sed -e "s/\(.*\.\)c/\1$ngx_objext/"` ngx_module_objs= - for ngx_src in $ngx_module_srcs + for ngx_src in $ngx_module_srcs $ngx_module_shrd do case "$ngx_src" in src/*) diff --git a/auto/module b/auto/module index a2b578d..3857d04 100644 --- a/auto/module +++ b/auto/module @@ -17,7 +17,6 @@ if [ "$ngx_module_link" = DYNAMIC ]; then done DYNAMIC_MODULES="$DYNAMIC_MODULES $ngx_module" - eval ${ngx_module}_SRCS=\"$ngx_module_srcs\" eval ${ngx_module}_MODULES=\"$ngx_module_name\" @@ -31,6 +30,30 @@ if [ "$ngx_module_link" = DYNAMIC ]; then eval ${ngx_module}_ORDER=\"$ngx_module_order\" fi + srcs= + shrd= + for src in $ngx_module_srcs + do + found=no + for old in $DYNAMIC_MODULES_SRCS + do + if [ $src = $old ]; then + found=yes + break + fi + done + + if [ $found = no ]; then + srcs="$srcs $src" + else + shrd="$shrd $src" + fi + done + eval ${ngx_module}_SRCS=\"$srcs\" + eval ${ngx_module}_SHRD=\"$shrd\" + + DYNAMIC_MODULES_SRCS="$DYNAMIC_MODULES_SRCS $srcs" + if test -n "$ngx_module_incs"; then CORE_INCS="$CORE_INCS $ngx_module_incs" fi @@ -107,7 +130,24 @@ elif [ "$ngx_module_link" = ADDON ]; then eval ${ngx_module_type}_MODULES=\"\$${ngx_module_type}_MODULES \ $ngx_module_name\" - NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_module_srcs" + srcs= + for src in $ngx_module_srcs + do + found=no + for old in $NGX_ADDON_SRCS + do + if [ $src = $old ]; then + found=yes + break + fi + done + + if [ $found = no ]; then + srcs="$srcs $src" + fi + done + + NGX_ADDON_SRCS="$NGX_ADDON_SRCS $srcs" if test -n "$ngx_module_incs"; then eval ${ngx_var}_INCS=\"\$${ngx_var}_INCS $ngx_module_incs\" diff --git a/auto/modules b/auto/modules index d78e282..f5a4597 100644 --- a/auto/modules +++ b/auto/modules @@ -985,6 +985,12 @@ if [ $MAIL != NO ]; then ngx_module_srcs=src/mail/ngx_mail_proxy_module.c . auto/module + + ngx_module_name=ngx_mail_realip_module + ngx_module_deps= + ngx_module_srcs=src/mail/ngx_mail_realip_module.c + + . auto/module fi @@ -1119,6 +1125,16 @@ if [ $STREAM != NO ]; then . auto/module fi + if [ $STREAM_SET = YES ]; then + ngx_module_name=ngx_stream_set_module + ngx_module_deps= + ngx_module_srcs=src/stream/ngx_stream_set_module.c + ngx_module_libs= + ngx_module_link=$STREAM_SET + + . auto/module + fi + if [ $STREAM_UPSTREAM_HASH = YES ]; then ngx_module_name=ngx_stream_upstream_hash_module ngx_module_deps= diff --git a/auto/options b/auto/options index 521c976..80be906 100644 --- a/auto/options +++ b/auto/options @@ -124,6 +124,7 @@ STREAM_GEOIP=NO STREAM_MAP=YES STREAM_SPLIT_CLIENTS=YES STREAM_RETURN=YES +STREAM_SET=YES STREAM_UPSTREAM_HASH=YES STREAM_UPSTREAM_LEAST_CONN=YES STREAM_UPSTREAM_RANDOM=YES @@ -131,8 +132,10 @@ STREAM_UPSTREAM_ZONE=YES STREAM_SSL_PREREAD=NO DYNAMIC_MODULES= +DYNAMIC_MODULES_SRCS= NGX_ADDONS= +NGX_ADDON_SRCS= NGX_ADDON_DEPS= DYNAMIC_ADDONS= @@ -324,6 +327,7 @@ use the \"--with-mail_ssl_module\" option instead" --without-stream_split_clients_module) STREAM_SPLIT_CLIENTS=NO ;; --without-stream_return_module) STREAM_RETURN=NO ;; + --without-stream_set_module) STREAM_SET=NO ;; --without-stream_upstream_hash_module) STREAM_UPSTREAM_HASH=NO ;; --without-stream_upstream_least_conn_module) @@ -538,6 +542,7 @@ cat << END --without-stream_split_clients_module disable ngx_stream_split_clients_module --without-stream_return_module disable ngx_stream_return_module + --without-stream_set_module disable ngx_stream_set_module --without-stream_upstream_hash_module disable ngx_stream_upstream_hash_module --without-stream_upstream_least_conn_module diff --git a/auto/os/linux b/auto/os/linux index 5e280ec..74b5870 100644 --- a/auto/os/linux +++ b/auto/os/linux @@ -86,6 +86,31 @@ if [ $ngx_found = yes ]; then ee.data.ptr = NULL; epoll_ctl(efd, EPOLL_CTL_ADD, fd, &ee)" . auto/feature + + + # eventfd() + + ngx_feature="eventfd()" + ngx_feature_name="NGX_HAVE_EVENTFD" + ngx_feature_run=no + ngx_feature_incs="#include " + ngx_feature_path= + ngx_feature_libs= + ngx_feature_test="(void) eventfd(0, 0)" + . auto/feature + + if [ $ngx_found = yes ]; then + have=NGX_HAVE_SYS_EVENTFD_H . auto/have + fi + + + if [ $ngx_found = no ]; then + + ngx_feature="eventfd() (SYS_eventfd)" + ngx_feature_incs="#include " + ngx_feature_test="(void) SYS_eventfd" + . auto/feature + fi fi diff --git a/auto/unix b/auto/unix index ff9697a..8671019 100644 --- a/auto/unix +++ b/auto/unix @@ -582,29 +582,6 @@ Currently file AIO is supported on FreeBSD 4.3+ and Linux 2.6.22+ only END exit 1 fi - -else - - ngx_feature="eventfd()" - ngx_feature_name="NGX_HAVE_EVENTFD" - ngx_feature_run=no - ngx_feature_incs="#include " - ngx_feature_path= - ngx_feature_libs= - ngx_feature_test="(void) eventfd(0, 0)" - . auto/feature - - if [ $ngx_found = yes ]; then - have=NGX_HAVE_SYS_EVENTFD_H . auto/have - fi - - if [ $ngx_found = no ]; then - - ngx_feature="eventfd() (SYS_eventfd)" - ngx_feature_incs="#include " - ngx_feature_test="(void) SYS_eventfd" - . auto/feature - fi fi @@ -727,17 +704,33 @@ ngx_feature_test="char buf[1]; struct iovec vec[1]; ssize_t n; . auto/feature -ngx_feature="sys_nerr" -ngx_feature_name="NGX_SYS_NERR" -ngx_feature_run=value -ngx_feature_incs='#include - #include ' +# strerrordesc_np(), introduced in glibc 2.32 + +ngx_feature="strerrordesc_np()" +ngx_feature_name="NGX_HAVE_STRERRORDESC_NP" +ngx_feature_run=no +ngx_feature_incs='#include ' ngx_feature_path= ngx_feature_libs= -ngx_feature_test='printf("%d", sys_nerr);' +ngx_feature_test="char *p; p = strerrordesc_np(0); + if (p == NULL) return 1" . auto/feature +if [ $ngx_found = no ]; then + + ngx_feature="sys_nerr" + ngx_feature_name="NGX_SYS_NERR" + ngx_feature_run=value + ngx_feature_incs='#include + #include ' + ngx_feature_path= + ngx_feature_libs= + ngx_feature_test='printf("%d", sys_nerr);' + . auto/feature +fi + + if [ $ngx_found = no ]; then # Cygiwn defines _sys_nerr @@ -753,34 +746,6 @@ if [ $ngx_found = no ]; then fi -if [ $ngx_found = no ]; then - - # Solaris has no sys_nerr - ngx_feature='maximum errno' - ngx_feature_name=NGX_SYS_NERR - ngx_feature_run=value - ngx_feature_incs='#include - #include - #include ' - ngx_feature_path= - ngx_feature_libs= - ngx_feature_test='int n; - char *p; - for (n = 1; n < 1000; n++) { - errno = 0; - p = strerror(n); - if (errno == EINVAL - || p == NULL - || strncmp(p, "Unknown error", 13) == 0) - { - break; - } - } - printf("%d", n);' - . auto/feature -fi - - ngx_feature="localtime_r()" ngx_feature_name="NGX_HAVE_LOCALTIME_R" ngx_feature_run=no diff --git a/configure b/configure index 7e6e33a..474d69e 100755 --- a/configure +++ b/configure @@ -87,6 +87,10 @@ have=NGX_PID_PATH value="\"$NGX_PID_PATH\"" . auto/define have=NGX_LOCK_PATH value="\"$NGX_LOCK_PATH\"" . auto/define have=NGX_ERROR_LOG_PATH value="\"$NGX_ERROR_LOG_PATH\"" . auto/define +if [ ".$NGX_ERROR_LOG_PATH" = "." ]; then + have=NGX_ERROR_LOG_STDERR . auto/have +fi + have=NGX_HTTP_LOG_PATH value="\"$NGX_HTTP_LOG_PATH\"" . auto/define have=NGX_HTTP_CLIENT_TEMP_PATH value="\"$NGX_HTTP_CLIENT_TEMP_PATH\"" . auto/define diff --git a/contrib/vim/syntax/nginx.vim b/contrib/vim/syntax/nginx.vim index 1a3a7b7..88ec847 100644 --- a/contrib/vim/syntax/nginx.vim +++ b/contrib/vim/syntax/nginx.vim @@ -141,6 +141,7 @@ syn keyword ngxDirective contained ancient_browser_value syn keyword ngxDirective contained api syn keyword ngxDirective contained auth_basic syn keyword ngxDirective contained auth_basic_user_file +syn keyword ngxDirective contained auth_delay syn keyword ngxDirective contained auth_http syn keyword ngxDirective contained auth_http_header syn keyword ngxDirective contained auth_http_pass_client_cert @@ -267,6 +268,7 @@ syn keyword ngxDirective contained grpc_socket_keepalive syn keyword ngxDirective contained grpc_ssl_certificate syn keyword ngxDirective contained grpc_ssl_certificate_key syn keyword ngxDirective contained grpc_ssl_ciphers +syn keyword ngxDirective contained grpc_ssl_conf_command syn keyword ngxDirective contained grpc_ssl_crl syn keyword ngxDirective contained grpc_ssl_name syn keyword ngxDirective contained grpc_ssl_password_file @@ -332,6 +334,7 @@ syn keyword ngxDirective contained ip_hash syn keyword ngxDirective contained js_access syn keyword ngxDirective contained js_content syn keyword ngxDirective contained js_filter +syn keyword ngxDirective contained js_import syn keyword ngxDirective contained js_include syn keyword ngxDirective contained js_path syn keyword ngxDirective contained js_preread @@ -348,6 +351,7 @@ syn keyword ngxDirective contained large_client_header_buffers syn keyword ngxDirective contained least_conn syn keyword ngxDirective contained least_time syn keyword ngxDirective contained limit_conn +syn keyword ngxDirective contained limit_conn_dry_run syn keyword ngxDirective contained limit_conn_log_level syn keyword ngxDirective contained limit_conn_status syn keyword ngxDirective contained limit_conn_zone @@ -444,6 +448,7 @@ syn keyword ngxDirective contained proxy_cache_use_stale syn keyword ngxDirective contained proxy_cache_valid syn keyword ngxDirective contained proxy_connect_timeout syn keyword ngxDirective contained proxy_cookie_domain +syn keyword ngxDirective contained proxy_cookie_flags syn keyword ngxDirective contained proxy_cookie_path syn keyword ngxDirective contained proxy_download_rate syn keyword ngxDirective contained proxy_force_ranges @@ -477,11 +482,13 @@ syn keyword ngxDirective contained proxy_send_timeout syn keyword ngxDirective contained proxy_session_drop syn keyword ngxDirective contained proxy_set_body syn keyword ngxDirective contained proxy_set_header +syn keyword ngxDirective contained proxy_smtp_auth syn keyword ngxDirective contained proxy_socket_keepalive syn keyword ngxDirective contained proxy_ssl syn keyword ngxDirective contained proxy_ssl_certificate syn keyword ngxDirective contained proxy_ssl_certificate_key syn keyword ngxDirective contained proxy_ssl_ciphers +syn keyword ngxDirective contained proxy_ssl_conf_command syn keyword ngxDirective contained proxy_ssl_crl syn keyword ngxDirective contained proxy_ssl_name syn keyword ngxDirective contained proxy_ssl_password_file @@ -589,16 +596,21 @@ syn keyword ngxDirective contained ssl_certificate syn keyword ngxDirective contained ssl_certificate_key syn keyword ngxDirective contained ssl_ciphers syn keyword ngxDirective contained ssl_client_certificate +syn keyword ngxDirective contained ssl_conf_command syn keyword ngxDirective contained ssl_crl syn keyword ngxDirective contained ssl_dhparam syn keyword ngxDirective contained ssl_early_data syn keyword ngxDirective contained ssl_ecdh_curve syn keyword ngxDirective contained ssl_engine syn keyword ngxDirective contained ssl_handshake_timeout +syn keyword ngxDirective contained ssl_ocsp +syn keyword ngxDirective contained ssl_ocsp_cache +syn keyword ngxDirective contained ssl_ocsp_responder syn keyword ngxDirective contained ssl_password_file syn keyword ngxDirective contained ssl_prefer_server_ciphers syn keyword ngxDirective contained ssl_preread syn keyword ngxDirective contained ssl_protocols +syn keyword ngxDirective contained ssl_reject_handshake syn keyword ngxDirective contained ssl_session_cache syn keyword ngxDirective contained ssl_session_ticket_key syn keyword ngxDirective contained ssl_session_tickets @@ -637,6 +649,7 @@ syn keyword ngxDirective contained user syn keyword ngxDirective contained userid syn keyword ngxDirective contained userid_domain syn keyword ngxDirective contained userid_expires +syn keyword ngxDirective contained userid_flags syn keyword ngxDirective contained userid_mark syn keyword ngxDirective contained userid_name syn keyword ngxDirective contained userid_p3p @@ -687,6 +700,7 @@ syn keyword ngxDirective contained uwsgi_socket_keepalive syn keyword ngxDirective contained uwsgi_ssl_certificate syn keyword ngxDirective contained uwsgi_ssl_certificate_key syn keyword ngxDirective contained uwsgi_ssl_ciphers +syn keyword ngxDirective contained uwsgi_ssl_conf_command syn keyword ngxDirective contained uwsgi_ssl_crl syn keyword ngxDirective contained uwsgi_ssl_name syn keyword ngxDirective contained uwsgi_ssl_password_file @@ -732,6 +746,7 @@ syn keyword ngxDirective contained zone_sync_ssl syn keyword ngxDirective contained zone_sync_ssl_certificate syn keyword ngxDirective contained zone_sync_ssl_certificate_key syn keyword ngxDirective contained zone_sync_ssl_ciphers +syn keyword ngxDirective contained zone_sync_ssl_conf_command syn keyword ngxDirective contained zone_sync_ssl_crl syn keyword ngxDirective contained zone_sync_ssl_name syn keyword ngxDirective contained zone_sync_ssl_password_file @@ -770,6 +785,7 @@ syn keyword ngxDirectiveThirdParty contained auth_gss_authorized_principal syn keyword ngxDirectiveThirdParty contained auth_gss_force_realm syn keyword ngxDirectiveThirdParty contained auth_gss_format_full syn keyword ngxDirectiveThirdParty contained auth_gss_keytab +syn keyword ngxDirectiveThirdParty contained auth_gss_map_to_local syn keyword ngxDirectiveThirdParty contained auth_gss_realm syn keyword ngxDirectiveThirdParty contained auth_gss_service_name @@ -791,8 +807,8 @@ syn keyword ngxDirectiveThirdParty contained auth_pam_set_pam_env " AJP protocol proxy " https://github.com/yaoweibin/nginx_ajp_module -syn keyword ngxDirectiveThirdParty contained ajp_buffer_size syn keyword ngxDirectiveThirdParty contained ajp_buffers +syn keyword ngxDirectiveThirdParty contained ajp_buffer_size syn keyword ngxDirectiveThirdParty contained ajp_busy_buffers_size syn keyword ngxDirectiveThirdParty contained ajp_cache syn keyword ngxDirectiveThirdParty contained ajp_cache_key @@ -818,6 +834,7 @@ syn keyword ngxDirectiveThirdParty contained ajp_pass_header syn keyword ngxDirectiveThirdParty contained ajp_pass_request_body syn keyword ngxDirectiveThirdParty contained ajp_pass_request_headers syn keyword ngxDirectiveThirdParty contained ajp_read_timeout +syn keyword ngxDirectiveThirdParty contained ajp_secret syn keyword ngxDirectiveThirdParty contained ajp_send_lowat syn keyword ngxDirectiveThirdParty contained ajp_send_timeout syn keyword ngxDirectiveThirdParty contained ajp_store @@ -854,8 +871,8 @@ syn keyword ngxDirectiveThirdParty contained content_handler_property syn keyword ngxDirectiveThirdParty contained content_handler_type syn keyword ngxDirectiveThirdParty contained handler_code syn keyword ngxDirectiveThirdParty contained handler_name -syn keyword ngxDirectiveThirdParty contained handler_type syn keyword ngxDirectiveThirdParty contained handlers_lazy_init +syn keyword ngxDirectiveThirdParty contained handler_type syn keyword ngxDirectiveThirdParty contained header_filter_code syn keyword ngxDirectiveThirdParty contained header_filter_name syn keyword ngxDirectiveThirdParty contained header_filter_property @@ -871,6 +888,10 @@ syn keyword ngxDirectiveThirdParty contained jvm_options syn keyword ngxDirectiveThirdParty contained jvm_path syn keyword ngxDirectiveThirdParty contained jvm_var syn keyword ngxDirectiveThirdParty contained jvm_workers +syn keyword ngxDirectiveThirdParty contained log_handler_code +syn keyword ngxDirectiveThirdParty contained log_handler_name +syn keyword ngxDirectiveThirdParty contained log_handler_property +syn keyword ngxDirectiveThirdParty contained log_handler_type syn keyword ngxDirectiveThirdParty contained max_balanced_tcp_connections syn keyword ngxDirectiveThirdParty contained rewrite_handler_code syn keyword ngxDirectiveThirdParty contained rewrite_handler_name @@ -879,6 +900,7 @@ syn keyword ngxDirectiveThirdParty contained rewrite_handler_type syn keyword ngxDirectiveThirdParty contained shared_map syn keyword ngxDirectiveThirdParty contained write_page_size + " Certificate Transparency " https://github.com/grahamedgecombe/nginx-ct syn keyword ngxDirectiveThirdParty contained ssl_ct @@ -942,6 +964,7 @@ syn keyword ngxDirectiveThirdParty contained fancyindex_hide_symlinks syn keyword ngxDirectiveThirdParty contained fancyindex_ignore syn keyword ngxDirectiveThirdParty contained fancyindex_localtime syn keyword ngxDirectiveThirdParty contained fancyindex_name_length +syn keyword ngxDirectiveThirdParty contained fancyindex_show_dotfiles syn keyword ngxDirectiveThirdParty contained fancyindex_show_path syn keyword ngxDirectiveThirdParty contained fancyindex_time_format @@ -991,8 +1014,8 @@ syn keyword ngxDirectiveThirdParty contained nchan_benchmark_publisher_distribut syn keyword ngxDirectiveThirdParty contained nchan_benchmark_subscriber_distribution syn keyword ngxDirectiveThirdParty contained nchan_benchmark_subscribers_per_channel syn keyword ngxDirectiveThirdParty contained nchan_benchmark_time -syn keyword ngxDirectiveThirdParty contained nchan_channel_event_string syn keyword ngxDirectiveThirdParty contained nchan_channel_events_channel_id +syn keyword ngxDirectiveThirdParty contained nchan_channel_event_string syn keyword ngxDirectiveThirdParty contained nchan_channel_group syn keyword ngxDirectiveThirdParty contained nchan_channel_group_accounting syn keyword ngxDirectiveThirdParty contained nchan_channel_id @@ -1000,6 +1023,10 @@ syn keyword ngxDirectiveThirdParty contained nchan_channel_id_split_delimiter syn keyword ngxDirectiveThirdParty contained nchan_channel_timeout syn keyword ngxDirectiveThirdParty contained nchan_deflate_message_for_websocket syn keyword ngxDirectiveThirdParty contained nchan_eventsource_event +syn keyword ngxDirectiveThirdParty contained nchan_eventsource_ping_comment +syn keyword ngxDirectiveThirdParty contained nchan_eventsource_ping_data +syn keyword ngxDirectiveThirdParty contained nchan_eventsource_ping_event +syn keyword ngxDirectiveThirdParty contained nchan_eventsource_ping_interval syn keyword ngxDirectiveThirdParty contained nchan_group_location syn keyword ngxDirectiveThirdParty contained nchan_group_max_channels syn keyword ngxDirectiveThirdParty contained nchan_group_max_messages @@ -1047,10 +1074,10 @@ syn keyword ngxDirectiveThirdParty contained nchan_store_messages syn keyword ngxDirectiveThirdParty contained nchan_stub_status syn keyword ngxDirectiveThirdParty contained nchan_sub_channel_id syn keyword ngxDirectiveThirdParty contained nchan_subscribe_existing_channels_only -syn keyword ngxDirectiveThirdParty contained nchan_subscribe_request syn keyword ngxDirectiveThirdParty contained nchan_subscriber syn keyword ngxDirectiveThirdParty contained nchan_subscriber_channel_id syn keyword ngxDirectiveThirdParty contained nchan_subscriber_compound_etag_message_id +syn keyword ngxDirectiveThirdParty contained nchan_subscribe_request syn keyword ngxDirectiveThirdParty contained nchan_subscriber_first_message syn keyword ngxDirectiveThirdParty contained nchan_subscriber_http_raw_stream_separator syn keyword ngxDirectiveThirdParty contained nchan_subscriber_last_message_id @@ -1311,6 +1338,8 @@ syn keyword ngxDirectiveThirdParty contained body_filter_by_lua_file syn keyword ngxDirectiveThirdParty contained content_by_lua syn keyword ngxDirectiveThirdParty contained content_by_lua_block syn keyword ngxDirectiveThirdParty contained content_by_lua_file +syn keyword ngxDirectiveThirdParty contained exit_worker_by_lua_block +syn keyword ngxDirectiveThirdParty contained exit_worker_by_lua_file syn keyword ngxDirectiveThirdParty contained header_filter_by_lua syn keyword ngxDirectiveThirdParty contained header_filter_by_lua_block syn keyword ngxDirectiveThirdParty contained header_filter_by_lua_file @@ -1352,6 +1381,7 @@ syn keyword ngxDirectiveThirdParty contained lua_ssl_crl syn keyword ngxDirectiveThirdParty contained lua_ssl_protocols syn keyword ngxDirectiveThirdParty contained lua_ssl_trusted_certificate syn keyword ngxDirectiveThirdParty contained lua_ssl_verify_depth +syn keyword ngxDirectiveThirdParty contained lua_thread_cache_max_entries syn keyword ngxDirectiveThirdParty contained lua_transform_underscores_in_response_headers syn keyword ngxDirectiveThirdParty contained lua_use_default_type syn keyword ngxDirectiveThirdParty contained rewrite_by_lua @@ -1987,11 +2017,7 @@ syn keyword ngxDirectiveThirdParty contained concat_unique " update upstreams' config by restful interface " https://github.com/yzprofile/ngx_http_dyups_module syn keyword ngxDirectiveThirdParty contained dyups_interface -syn keyword ngxDirectiveThirdParty contained dyups_read_msg_log -syn keyword ngxDirectiveThirdParty contained dyups_read_msg_timeout syn keyword ngxDirectiveThirdParty contained dyups_shm_zone_size -syn keyword ngxDirectiveThirdParty contained dyups_trylock -syn keyword ngxDirectiveThirdParty contained dyups_upstream_conf " add given content to the end of the response according to the condition specified " https://github.com/flygoast/ngx_http_footer_if_filter @@ -2271,6 +2297,7 @@ syn keyword ngxDirectiveThirdParty contained testcookie_refresh_encrypt_cookie_i syn keyword ngxDirectiveThirdParty contained testcookie_refresh_encrypt_cookie_key syn keyword ngxDirectiveThirdParty contained testcookie_refresh_status syn keyword ngxDirectiveThirdParty contained testcookie_refresh_template +syn keyword ngxDirectiveThirdParty contained testcookie_samesite syn keyword ngxDirectiveThirdParty contained testcookie_secret syn keyword ngxDirectiveThirdParty contained testcookie_secure_flag syn keyword ngxDirectiveThirdParty contained testcookie_session @@ -2308,31 +2335,105 @@ syn keyword ngxDirectiveThirdParty contained user_agent " https://github.com/flygoast/ngx_http_upstream_ketama_chash syn keyword ngxDirectiveThirdParty contained ketama_chash +" nginx-sticky-module-ng +" https://github.com/ayty-adrianomartins/nginx-sticky-module-ng +syn keyword ngxDirectiveThirdParty contained sticky_no_fallback + +" dynamic linking and call the function of your application +" https://github.com/Taymindis/nginx-link-function +syn keyword ngxDirectiveThirdParty contained ngx_link_func_add_prop +syn keyword ngxDirectiveThirdParty contained ngx_link_func_add_req_header +syn keyword ngxDirectiveThirdParty contained ngx_link_func_ca_cert +syn keyword ngxDirectiveThirdParty contained ngx_link_func_call +syn keyword ngxDirectiveThirdParty contained ngx_link_func_download_link_lib +syn keyword ngxDirectiveThirdParty contained ngx_link_func_lib +syn keyword ngxDirectiveThirdParty contained ngx_link_func_shm_size +syn keyword ngxDirectiveThirdParty contained ngx_link_func_subrequest + +" purge content from FastCGI, proxy, SCGI and uWSGI caches +" https://github.com/torden/ngx_cache_purge +syn keyword ngxDirectiveThirdParty contained cache_purge_response_type + +" set the flags "HttpOnly", "secure" and "SameSite" for cookies +" https://github.com/AirisX/nginx_cookie_flag_module +syn keyword ngxDirectiveThirdParty contained set_cookie_flag + +" Embed websockify into Nginx (convert any tcp connection into websocket) +" https://github.com/tg123/websockify-nginx-module +syn keyword ngxDirectiveThirdParty contained websockify_buffer_size +syn keyword ngxDirectiveThirdParty contained websockify_connect_timeout +syn keyword ngxDirectiveThirdParty contained websockify_pass +syn keyword ngxDirectiveThirdParty contained websockify_read_timeout +syn keyword ngxDirectiveThirdParty contained websockify_send_timeout + +" IP2Location Nginx +" https://github.com/ip2location/ip2location-nginx +syn keyword ngxDirectiveThirdParty contained ip2location_proxy +syn keyword ngxDirectiveThirdParty contained ip2location_proxy_recursive +syn keyword ngxDirectiveThirdParty contained ip2location_areacode +syn keyword ngxDirectiveThirdParty contained ip2location_city +syn keyword ngxDirectiveThirdParty contained ip2location_country_long +syn keyword ngxDirectiveThirdParty contained ip2location_country_short +syn keyword ngxDirectiveThirdParty contained ip2location_domain +syn keyword ngxDirectiveThirdParty contained ip2location_elevation +syn keyword ngxDirectiveThirdParty contained ip2location_iddcode +syn keyword ngxDirectiveThirdParty contained ip2location_isp +syn keyword ngxDirectiveThirdParty contained ip2location_latitude +syn keyword ngxDirectiveThirdParty contained ip2location_longitude +syn keyword ngxDirectiveThirdParty contained ip2location_mcc +syn keyword ngxDirectiveThirdParty contained ip2location_mnc +syn keyword ngxDirectiveThirdParty contained ip2location_mobilebrand +syn keyword ngxDirectiveThirdParty contained ip2location_netspeed +syn keyword ngxDirectiveThirdParty contained ip2location_region +syn keyword ngxDirectiveThirdParty contained ip2location_timezone +syn keyword ngxDirectiveThirdParty contained ip2location_usagetype +syn keyword ngxDirectiveThirdParty contained ip2location_weatherstationcode +syn keyword ngxDirectiveThirdParty contained ip2location_weatherstationname +syn keyword ngxDirectiveThirdParty contained ip2location_zipcode + +" IP2Proxy module for Nginx +" https://github.com/ip2location/ip2proxy-nginx +syn keyword ngxDirectiveThirdParty contained ip2proxy_as +syn keyword ngxDirectiveThirdParty contained ip2proxy_asn +syn keyword ngxDirectiveThirdParty contained ip2proxy_city +syn keyword ngxDirectiveThirdParty contained ip2proxy_country_long +syn keyword ngxDirectiveThirdParty contained ip2proxy_country_short +syn keyword ngxDirectiveThirdParty contained ip2proxy_database +syn keyword ngxDirectiveThirdParty contained ip2proxy_domain +syn keyword ngxDirectiveThirdParty contained ip2proxy_isp +syn keyword ngxDirectiveThirdParty contained ip2proxy_is_proxy +syn keyword ngxDirectiveThirdParty contained ip2proxy_last_seen +syn keyword ngxDirectiveThirdParty contained ip2proxy_proxy +syn keyword ngxDirectiveThirdParty contained ip2proxy_proxy_recursive +syn keyword ngxDirectiveThirdParty contained ip2proxy_proxy_type +syn keyword ngxDirectiveThirdParty contained ip2proxy_region +syn keyword ngxDirectiveThirdParty contained ip2proxy_threat +syn keyword ngxDirectiveThirdParty contained ip2proxy_usage_type " highlight -hi link ngxComment Comment -hi link ngxParamComment Comment -hi link ngxListenComment Comment -hi link ngxVariable Identifier -hi link ngxVariableString PreProc -hi link ngxString String -hi link ngxListenString String +hi def link ngxComment Comment +hi def link ngxParamComment Comment +hi def link ngxListenComment Comment +hi def link ngxVariable Identifier +hi def link ngxVariableString PreProc +hi def link ngxString String +hi def link ngxListenString String -hi link ngxBoolean Boolean -hi link ngxDirectiveBlock Statement -hi link ngxDirectiveImportant Type -hi link ngxDirectiveListen Type -hi link ngxDirectiveControl Keyword -hi link ngxDirectiveError Constant -hi link ngxDirectiveDeprecated Error -hi link ngxDirective Identifier -hi link ngxDirectiveThirdParty Special -hi link ngxDirectiveThirdPartyDeprecated Error +hi def link ngxBoolean Boolean +hi def link ngxDirectiveBlock Statement +hi def link ngxDirectiveImportant Type +hi def link ngxDirectiveListen Type +hi def link ngxDirectiveControl Keyword +hi def link ngxDirectiveError Constant +hi def link ngxDirectiveDeprecated Error +hi def link ngxDirective Identifier +hi def link ngxDirectiveThirdParty Special +hi def link ngxDirectiveThirdPartyDeprecated Error -hi link ngxListenOptions Keyword -hi link ngxListenOptionsDeprecated Error +hi def link ngxListenOptions Keyword +hi def link ngxListenOptionsDeprecated Error let b:current_syntax = "nginx" diff --git a/man/nginx.8 b/man/nginx.8 index 573d935..10db3e6 100644 --- a/man/nginx.8 +++ b/man/nginx.8 @@ -25,7 +25,7 @@ .\" SUCH DAMAGE. .\" .\" -.Dd December 5, 2019 +.Dd November 5, 2020 .Dt NGINX 8 .Os .Sh NAME @@ -35,6 +35,7 @@ .Nm .Op Fl ?hqTtVv .Op Fl c Ar file +.Op Fl e Ar file .Op Fl g Ar directives .Op Fl p Ar prefix .Op Fl s Ar signal @@ -54,6 +55,12 @@ Print help. .It Fl c Ar file Use an alternative configuration .Ar file . +.It Fl e Ar file +Use an alternative error log +.Ar file . +Special value +.Cm stderr +indicates that the standard error output should be used. .It Fl g Ar directives Set global configuration directives. See @@ -198,10 +205,10 @@ Development of started in 2002, with the first public release on October 4, 2004. .Sh AUTHORS .An -nosplit -.An Igor Sysoev Aq igor@sysoev.ru . +.An Igor Sysoev Aq Mt igor@sysoev.ru . .Pp This manual page was originally written by -.An Sergey A. Osokin Aq osa@FreeBSD.org.ru +.An Sergey A. Osokin Aq Mt osa@FreeBSD.org.ru as a result of compiling many .Nm documents from all over the world. diff --git a/src/core/nginx.c b/src/core/nginx.c index 9fcb0eb..48a20e9 100644 --- a/src/core/nginx.c +++ b/src/core/nginx.c @@ -183,6 +183,7 @@ static ngx_uint_t ngx_show_help; static ngx_uint_t ngx_show_version; static ngx_uint_t ngx_show_configure; static u_char *ngx_prefix; +static u_char *ngx_error_log; static u_char *ngx_conf_file; static u_char *ngx_conf_params; static char *ngx_signal; @@ -230,7 +231,7 @@ main(int argc, char *const *argv) ngx_pid = ngx_getpid(); ngx_parent = ngx_getppid(); - log = ngx_log_init(ngx_prefix); + log = ngx_log_init(ngx_prefix, ngx_error_log); if (log == NULL) { return 1; } @@ -393,9 +394,9 @@ ngx_show_version_info(void) if (ngx_show_help) { ngx_write_stderr( - "Usage: nginx [-?hvVtTq] [-s signal] [-c filename] " - "[-p prefix] [-g directives]" NGX_LINEFEED - NGX_LINEFEED + "Usage: nginx [-?hvVtTq] [-s signal] [-p prefix]" NGX_LINEFEED + " [-e filename] [-c filename] [-g directives]" + NGX_LINEFEED NGX_LINEFEED "Options:" NGX_LINEFEED " -?,-h : this help" NGX_LINEFEED " -v : show version and exit" NGX_LINEFEED @@ -413,6 +414,12 @@ ngx_show_version_info(void) NGX_LINEFEED #else " -p prefix : set prefix path (default: NONE)" NGX_LINEFEED +#endif + " -e filename : set error log file (default: " +#ifdef NGX_ERROR_LOG_STDERR + "stderr)" NGX_LINEFEED +#else + NGX_ERROR_LOG_PATH ")" NGX_LINEFEED #endif " -c filename : set configuration file (default: " NGX_CONF_PATH ")" NGX_LINEFEED @@ -492,6 +499,7 @@ ngx_add_inherited_sockets(ngx_cycle_t *cycle) ngx_memzero(ls, sizeof(ngx_listening_t)); ls->fd = (ngx_socket_t) s; + ls->inherited = 1; } } @@ -799,6 +807,24 @@ ngx_get_options(int argc, char *const *argv) ngx_log_stderr(0, "option \"-p\" requires directory name"); return NGX_ERROR; + case 'e': + if (*p) { + ngx_error_log = p; + + } else if (argv[++i]) { + ngx_error_log = (u_char *) argv[i]; + + } else { + ngx_log_stderr(0, "option \"-e\" requires file name"); + return NGX_ERROR; + } + + if (ngx_strcmp(ngx_error_log, "stderr") == 0) { + ngx_error_log = (u_char *) ""; + } + + goto next; + case 'c': if (*p) { ngx_conf_file = p; @@ -991,6 +1017,14 @@ ngx_process_options(ngx_cycle_t *cycle) } } + if (ngx_error_log) { + cycle->error_log.len = ngx_strlen(ngx_error_log); + cycle->error_log.data = ngx_error_log; + + } else { + ngx_str_set(&cycle->error_log, NGX_ERROR_LOG_PATH); + } + if (ngx_conf_params) { cycle->conf_param.len = ngx_strlen(ngx_conf_params); cycle->conf_param.data = ngx_conf_params; diff --git a/src/core/nginx.h b/src/core/nginx.h index 9656f98..7b873a1 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1018000 -#define NGINX_VERSION "1.18.0" +#define nginx_version 1020002 +#define NGINX_VERSION "1.20.2" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD diff --git a/src/core/ngx_buf.c b/src/core/ngx_buf.c index c3783c4..811f24d 100644 --- a/src/core/ngx_buf.c +++ b/src/core/ngx_buf.c @@ -203,16 +203,16 @@ ngx_chain_update_chains(ngx_pool_t *p, ngx_chain_t **free, ngx_chain_t **busy, while (*busy) { cl = *busy; - if (ngx_buf_size(cl->buf) != 0) { - break; - } - if (cl->buf->tag != tag) { *busy = cl->next; ngx_free_chain(p, cl); continue; } + if (ngx_buf_size(cl->buf) != 0) { + break; + } + cl->buf->pos = cl->buf->start; cl->buf->last = cl->buf->start; diff --git a/src/core/ngx_buf.h b/src/core/ngx_buf.h index 12781a7..4b66562 100644 --- a/src/core/ngx_buf.h +++ b/src/core/ngx_buf.h @@ -125,20 +125,20 @@ typedef struct { #define NGX_CHAIN_ERROR (ngx_chain_t *) NGX_ERROR -#define ngx_buf_in_memory(b) (b->temporary || b->memory || b->mmap) -#define ngx_buf_in_memory_only(b) (ngx_buf_in_memory(b) && !b->in_file) +#define ngx_buf_in_memory(b) ((b)->temporary || (b)->memory || (b)->mmap) +#define ngx_buf_in_memory_only(b) (ngx_buf_in_memory(b) && !(b)->in_file) #define ngx_buf_special(b) \ - ((b->flush || b->last_buf || b->sync) \ - && !ngx_buf_in_memory(b) && !b->in_file) + (((b)->flush || (b)->last_buf || (b)->sync) \ + && !ngx_buf_in_memory(b) && !(b)->in_file) #define ngx_buf_sync_only(b) \ - (b->sync \ - && !ngx_buf_in_memory(b) && !b->in_file && !b->flush && !b->last_buf) + ((b)->sync && !ngx_buf_in_memory(b) \ + && !(b)->in_file && !(b)->flush && !(b)->last_buf) #define ngx_buf_size(b) \ - (ngx_buf_in_memory(b) ? (off_t) (b->last - b->pos): \ - (b->file_last - b->file_pos)) + (ngx_buf_in_memory(b) ? (off_t) ((b)->last - (b)->pos): \ + ((b)->file_last - (b)->file_pos)) ngx_buf_t *ngx_create_temp_buf(ngx_pool_t *pool, size_t size); ngx_chain_t *ngx_create_chain_of_bufs(ngx_pool_t *pool, ngx_bufs_t *bufs); @@ -149,8 +149,8 @@ ngx_chain_t *ngx_create_chain_of_bufs(ngx_pool_t *pool, ngx_bufs_t *bufs); ngx_chain_t *ngx_alloc_chain_link(ngx_pool_t *pool); #define ngx_free_chain(pool, cl) \ - cl->next = pool->chain; \ - pool->chain = cl + (cl)->next = (pool)->chain; \ + (pool)->chain = (cl) diff --git a/src/core/ngx_conf_file.c b/src/core/ngx_conf_file.c index 6d1629e..fec7bb8 100644 --- a/src/core/ngx_conf_file.c +++ b/src/core/ngx_conf_file.c @@ -1137,7 +1137,7 @@ ngx_conf_set_keyval_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) a = (ngx_array_t **) (p + cmd->offset); - if (*a == NULL) { + if (*a == NGX_CONF_UNSET_PTR || *a == NULL) { *a = ngx_array_create(cf->pool, 4, sizeof(ngx_keyval_t)); if (*a == NULL) { return NGX_CONF_ERROR; diff --git a/src/core/ngx_connection.c b/src/core/ngx_connection.c index 3368253..8339e2b 100644 --- a/src/core/ngx_connection.c +++ b/src/core/ngx_connection.c @@ -1070,7 +1070,8 @@ ngx_close_listening_sockets(ngx_cycle_t *cycle) if (ls[i].sockaddr->sa_family == AF_UNIX && ngx_process <= NGX_PROCESS_MASTER - && ngx_new_binary == 0) + && ngx_new_binary == 0 + && (!ls[i].inherited || ngx_getppid() != ngx_parent)) { u_char *name = ls[i].addr_text.data + sizeof("unix:") - 1; @@ -1106,12 +1107,9 @@ ngx_get_connection(ngx_socket_t s, ngx_log_t *log) return NULL; } - c = ngx_cycle->free_connections; + ngx_drain_connections((ngx_cycle_t *) ngx_cycle); - if (c == NULL) { - ngx_drain_connections((ngx_cycle_t *) ngx_cycle); - c = ngx_cycle->free_connections; - } + c = ngx_cycle->free_connections; if (c == NULL) { ngx_log_error(NGX_LOG_ALERT, log, 0, @@ -1297,6 +1295,22 @@ ngx_drain_connections(ngx_cycle_t *cycle) ngx_queue_t *q; ngx_connection_t *c; + if (cycle->free_connection_n > cycle->connection_n / 16 + || cycle->reusable_connections_n == 0) + { + return; + } + + if (cycle->connections_reuse_time != ngx_time()) { + cycle->connections_reuse_time = ngx_time(); + + ngx_log_error(NGX_LOG_WARN, cycle->log, 0, + "%ui worker_connections are not enough, " + "reusing connections", + cycle->connection_n); + } + + c = NULL; n = ngx_max(ngx_min(32, cycle->reusable_connections_n / 8), 1); for (i = 0; i < n; i++) { @@ -1313,6 +1327,21 @@ ngx_drain_connections(ngx_cycle_t *cycle) c->close = 1; c->read->handler(c->read); } + + if (cycle->free_connection_n == 0 && c && c->reusable) { + + /* + * if no connections were freed, try to reuse the last + * connection again: this should free it as long as + * previous reuse moved it to lingering close + */ + + ngx_log_debug0(NGX_LOG_DEBUG_CORE, c->log, 0, + "reusing connection again"); + + c->close = 1; + c->read->handler(c->read); + } } diff --git a/src/core/ngx_connection.h b/src/core/ngx_connection.h index ad6556d..4716da4 100644 --- a/src/core/ngx_connection.h +++ b/src/core/ngx_connection.h @@ -45,8 +45,6 @@ struct ngx_listening_s { size_t pool_size; /* should be here because of the AcceptEx() preread */ size_t post_accept_buffer_size; - /* should be here because of the deferred accept */ - ngx_msec_t post_accept_timeout; ngx_listening_t *previous; ngx_connection_t *connection; @@ -164,6 +162,7 @@ struct ngx_connection_s { ngx_atomic_uint_t number; + ngx_msec_t start_time; ngx_uint_t requests; unsigned buffered:8; diff --git a/src/core/ngx_cycle.c b/src/core/ngx_cycle.c index 95f4bdf..6978c3e 100644 --- a/src/core/ngx_cycle.c +++ b/src/core/ngx_cycle.c @@ -96,6 +96,15 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) return NULL; } + cycle->error_log.len = old_cycle->error_log.len; + cycle->error_log.data = ngx_pnalloc(pool, old_cycle->error_log.len + 1); + if (cycle->error_log.data == NULL) { + ngx_destroy_pool(pool); + return NULL; + } + ngx_cpystrn(cycle->error_log.data, old_cycle->error_log.data, + old_cycle->error_log.len + 1); + cycle->conf_file.len = old_cycle->conf_file.len; cycle->conf_file.data = ngx_pnalloc(pool, old_cycle->conf_file.len + 1); if (cycle->conf_file.data == NULL) { @@ -520,6 +529,7 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) == NGX_OK) { nls[n].fd = ls[i].fd; + nls[n].inherited = ls[i].inherited; nls[n].previous = &ls[i]; ls[i].remain = 1; @@ -1008,6 +1018,7 @@ ngx_int_t ngx_create_pidfile(ngx_str_t *name, ngx_log_t *log) { size_t len; + ngx_int_t rc; ngx_uint_t create; ngx_file_t file; u_char pid[NGX_INT64_LEN + 2]; @@ -1032,11 +1043,13 @@ ngx_create_pidfile(ngx_str_t *name, ngx_log_t *log) return NGX_ERROR; } + rc = NGX_OK; + if (!ngx_test_config) { len = ngx_snprintf(pid, NGX_INT64_LEN + 2, "%P%N", ngx_pid) - pid; if (ngx_write_file(&file, pid, len, 0) == NGX_ERROR) { - return NGX_ERROR; + rc = NGX_ERROR; } } @@ -1045,7 +1058,7 @@ ngx_create_pidfile(ngx_str_t *name, ngx_log_t *log) ngx_close_file_n " \"%s\" failed", file.name.data); } - return NGX_OK; + return rc; } diff --git a/src/core/ngx_cycle.h b/src/core/ngx_cycle.h index 54fa2e6..0c47f25 100644 --- a/src/core/ngx_cycle.h +++ b/src/core/ngx_cycle.h @@ -55,6 +55,7 @@ struct ngx_cycle_s { ngx_queue_t reusable_connections_queue; ngx_uint_t reusable_connections_n; + time_t connections_reuse_time; ngx_array_t listening; ngx_array_t paths; @@ -79,6 +80,7 @@ struct ngx_cycle_s { ngx_str_t conf_param; ngx_str_t conf_prefix; ngx_str_t prefix; + ngx_str_t error_log; ngx_str_t lock_file; ngx_str_t hostname; }; diff --git a/src/core/ngx_log.c b/src/core/ngx_log.c index 8e9408d..0c09426 100644 --- a/src/core/ngx_log.c +++ b/src/core/ngx_log.c @@ -315,7 +315,7 @@ ngx_log_errno(u_char *buf, u_char *last, ngx_err_t err) ngx_log_t * -ngx_log_init(u_char *prefix) +ngx_log_init(u_char *prefix, u_char *error_log) { u_char *p, *name; size_t nlen, plen; @@ -323,13 +323,11 @@ ngx_log_init(u_char *prefix) ngx_log.file = &ngx_log_file; ngx_log.log_level = NGX_LOG_NOTICE; - name = (u_char *) NGX_ERROR_LOG_PATH; - - /* - * we use ngx_strlen() here since BCC warns about - * condition is always false and unreachable code - */ + if (error_log == NULL) { + error_log = (u_char *) NGX_ERROR_LOG_PATH; + } + name = error_log; nlen = ngx_strlen(name); if (nlen == 0) { @@ -369,7 +367,7 @@ ngx_log_init(u_char *prefix) *p++ = '/'; } - ngx_cpystrn(p, (u_char *) NGX_ERROR_LOG_PATH, nlen + 1); + ngx_cpystrn(p, error_log, nlen + 1); p = name; } @@ -403,8 +401,7 @@ ngx_log_init(u_char *prefix) ngx_int_t ngx_log_open_default(ngx_cycle_t *cycle) { - ngx_log_t *log; - static ngx_str_t error_log = ngx_string(NGX_ERROR_LOG_PATH); + ngx_log_t *log; if (ngx_log_get_file_log(&cycle->new_log) != NULL) { return NGX_OK; @@ -425,7 +422,7 @@ ngx_log_open_default(ngx_cycle_t *cycle) log->log_level = NGX_LOG_ERR; - log->file = ngx_conf_open_file(cycle, &error_log); + log->file = ngx_conf_open_file(cycle, &cycle->error_log); if (log->file == NULL) { return NGX_ERROR; } diff --git a/src/core/ngx_log.h b/src/core/ngx_log.h index afb73bf..ab64a5a 100644 --- a/src/core/ngx_log.h +++ b/src/core/ngx_log.h @@ -228,7 +228,7 @@ void ngx_cdecl ngx_log_debug_core(ngx_log_t *log, ngx_err_t err, /*********************************/ -ngx_log_t *ngx_log_init(u_char *prefix); +ngx_log_t *ngx_log_init(u_char *prefix, u_char *error_log); void ngx_cdecl ngx_log_abort(ngx_err_t err, const char *fmt, ...); void ngx_cdecl ngx_log_stderr(ngx_err_t err, const char *fmt, ...); u_char *ngx_log_errno(u_char *buf, u_char *last, ngx_err_t err); diff --git a/src/core/ngx_resolver.c b/src/core/ngx_resolver.c index e51712c..58d5f3e 100644 --- a/src/core/ngx_resolver.c +++ b/src/core/ngx_resolver.c @@ -1563,13 +1563,28 @@ ngx_resolver_udp_read(ngx_event_t *rev) do { n = ngx_udp_recv(c, buf, NGX_RESOLVER_UDP_SIZE); - if (n < 0) { - return; + if (n == NGX_AGAIN) { + break; + } + + if (n == NGX_ERROR) { + goto failed; } ngx_resolver_process_response(rec->resolver, buf, n, 0); } while (rev->ready); + + if (ngx_handle_read_event(rev, 0) != NGX_OK) { + goto failed; + } + + return; + +failed: + + ngx_close_connection(rec->udp); + rec->udp = NULL; } @@ -1783,6 +1798,12 @@ ngx_resolver_process_response(ngx_resolver_t *r, u_char *buf, size_t n, i = sizeof(ngx_resolver_hdr_t); while (i < (ngx_uint_t) n) { + + if (buf[i] & 0xc0) { + err = "unexpected compression pointer in DNS response"; + goto done; + } + if (buf[i] == '\0') { goto found; } @@ -1918,7 +1939,7 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t n, if (rn == NULL) { ngx_log_error(r->log_level, r->log, 0, - "unexpected response for %V", &name); + "unexpected DNS response for %V", &name); ngx_resolver_free(r, name.data); goto failed; } @@ -1930,7 +1951,7 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t n, if (rn->query6 == NULL || rn->naddrs6 != (u_short) -1) { ngx_log_error(r->log_level, r->log, 0, - "unexpected response for %V", &name); + "unexpected DNS response for %V", &name); ngx_resolver_free(r, name.data); goto failed; } @@ -1949,7 +1970,7 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t n, if (rn->query == NULL || rn->naddrs != (u_short) -1) { ngx_log_error(r->log_level, r->log, 0, - "unexpected response for %V", &name); + "unexpected DNS response for %V", &name); ngx_resolver_free(r, name.data); goto failed; } @@ -1964,7 +1985,7 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t n, if (ident != qident) { ngx_log_error(r->log_level, r->log, 0, - "wrong ident %ui response for %V, expect %ui", + "wrong ident %ui in DNS response for %V, expect %ui", ident, &name, qident); ngx_resolver_free(r, name.data); goto failed; @@ -2149,7 +2170,7 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t n, if (class != 1) { ngx_log_error(r->log_level, r->log, 0, - "unexpected RR class %ui", class); + "unexpected RR class %ui in DNS response", class); goto failed; } @@ -2218,7 +2239,7 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t n, default: ngx_log_error(r->log_level, r->log, 0, - "unexpected RR type %ui", type); + "unexpected RR type %ui in DNS response", type); } i += len; @@ -2567,7 +2588,7 @@ ngx_resolver_process_srv(ngx_resolver_t *r, u_char *buf, size_t n, if (rn == NULL || rn->query == NULL) { ngx_log_error(r->log_level, r->log, 0, - "unexpected response for %V", &name); + "unexpected DNS response for %V", &name); ngx_resolver_free(r, name.data); goto failed; } @@ -2581,7 +2602,7 @@ ngx_resolver_process_srv(ngx_resolver_t *r, u_char *buf, size_t n, if (ident != qident) { ngx_log_error(r->log_level, r->log, 0, - "wrong ident %ui response for %V, expect %ui", + "wrong ident %ui in DNS response for %V, expect %ui", ident, &name, qident); ngx_resolver_free(r, name.data); goto failed; @@ -2691,7 +2712,7 @@ ngx_resolver_process_srv(ngx_resolver_t *r, u_char *buf, size_t n, if (class != 1) { ngx_log_error(r->log_level, r->log, 0, - "unexpected RR class %ui", class); + "unexpected RR class %ui in DNS response", class); goto failed; } @@ -2734,7 +2755,7 @@ ngx_resolver_process_srv(ngx_resolver_t *r, u_char *buf, size_t n, default: ngx_log_error(r->log_level, r->log, 0, - "unexpected RR type %ui", type); + "unexpected RR type %ui in DNS response", type); } i += len; @@ -3165,7 +3186,7 @@ valid: if (rn == NULL || rn->query == NULL) { ngx_log_error(r->log_level, r->log, 0, - "unexpected response for %V", &name); + "unexpected DNS response for %V", &name); ngx_resolver_free(r, name.data); goto failed; } @@ -3174,7 +3195,7 @@ valid: if (ident != qident) { ngx_log_error(r->log_level, r->log, 0, - "wrong ident %ui response for %V, expect %ui", + "wrong ident %ui in DNS response for %V, expect %ui", ident, &name, qident); ngx_resolver_free(r, name.data); goto failed; @@ -3256,7 +3277,7 @@ valid: if (class != 1) { ngx_log_error(r->log_level, r->log, 0, - "unexpected RR class %ui", class); + "unexpected RR class %ui in DNS response", class); goto failed; } @@ -3283,7 +3304,7 @@ valid: default: ngx_log_error(r->log_level, r->log, 0, - "unexpected RR type %ui", type); + "unexpected RR type %ui in DNS response", type); } i += len; @@ -3924,11 +3945,11 @@ ngx_resolver_copy(ngx_resolver_t *r, ngx_str_t *name, u_char *buf, u_char *src, { char *err; u_char *p, *dst; - ssize_t len; + size_t len; ngx_uint_t i, n; p = src; - len = -1; + len = 0; /* * compression pointers allow to create endless loop, so we set limit; @@ -3943,6 +3964,16 @@ ngx_resolver_copy(ngx_resolver_t *r, ngx_str_t *name, u_char *buf, u_char *src, } if (n & 0xc0) { + if ((n & 0xc0) != 0xc0) { + err = "invalid label type in DNS response"; + goto invalid; + } + + if (p >= last) { + err = "name is out of DNS response"; + goto invalid; + } + n = ((n & 0x3f) << 8) + *p; p = &buf[n]; @@ -3952,12 +3983,12 @@ ngx_resolver_copy(ngx_resolver_t *r, ngx_str_t *name, u_char *buf, u_char *src, } if (p >= last) { - err = "name is out of response"; + err = "name is out of DNS response"; goto invalid; } } - err = "compression pointers loop"; + err = "compression pointers loop in DNS response"; invalid: @@ -3971,7 +4002,7 @@ done: return NGX_OK; } - if (len == -1) { + if (len == 0) { ngx_str_null(name); return NGX_OK; } @@ -3983,30 +4014,23 @@ done: name->data = dst; - n = *src++; - for ( ;; ) { + n = *src++; + + if (n == 0) { + name->len = dst - name->data - 1; + return NGX_OK; + } + if (n & 0xc0) { n = ((n & 0x3f) << 8) + *src; src = &buf[n]; - n = *src++; - } else { ngx_strlow(dst, src, n); dst += n; src += n; - - n = *src++; - - if (n != 0) { - *dst++ = '.'; - } - } - - if (n == 0) { - name->len = dst - name->data; - return NGX_OK; + *dst++ = '.'; } } } @@ -4444,6 +4468,8 @@ ngx_udp_connect(ngx_resolver_connection_t *rec) c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1); + c->start_time = ngx_current_msec; + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, &rec->log, 0, "connect to %V, fd:%d #%uA", &rec->server, s, c->number); @@ -4530,6 +4556,8 @@ ngx_tcp_connect(ngx_resolver_connection_t *rec) c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1); + c->start_time = ngx_current_msec; + if (ngx_add_conn) { if (ngx_add_conn(c) == NGX_ERROR) { goto failed; diff --git a/src/core/ngx_string.c b/src/core/ngx_string.c index 468e960..93f32ea 100644 --- a/src/core/ngx_string.c +++ b/src/core/ngx_string.c @@ -11,6 +11,8 @@ static u_char *ngx_sprintf_num(u_char *buf, u_char *last, uint64_t ui64, u_char zero, ngx_uint_t hexadecimal, ngx_uint_t width); +static u_char *ngx_sprintf_str(u_char *buf, u_char *last, u_char *src, + size_t len, ngx_uint_t hexadecimal); static void ngx_encode_base64_internal(ngx_str_t *dst, ngx_str_t *src, const u_char *basis, ngx_uint_t padding); static ngx_int_t ngx_decode_base64_internal(ngx_str_t *dst, ngx_str_t *src, @@ -101,10 +103,10 @@ ngx_pstrdup(ngx_pool_t *pool, ngx_str_t *src) * %M ngx_msec_t * %r rlim_t * %p void * - * %V ngx_str_t * - * %v ngx_variable_value_t * - * %s null-terminated string - * %*s length and string + * %[x|X]V ngx_str_t * + * %[x|X]v ngx_variable_value_t * + * %[x|X]s null-terminated string + * %*[x|X]s length and string * %Z '\0' * %N '\n' * %c char @@ -165,7 +167,7 @@ ngx_vslprintf(u_char *buf, u_char *last, const char *fmt, va_list args) u_char *p, zero; int d; double f; - size_t len, slen; + size_t slen; int64_t i64; uint64_t ui64, frac; ngx_msec_t ms; @@ -250,8 +252,7 @@ ngx_vslprintf(u_char *buf, u_char *last, const char *fmt, va_list args) case 'V': v = va_arg(args, ngx_str_t *); - len = ngx_min(((size_t) (last - buf)), v->len); - buf = ngx_cpymem(buf, v->data, len); + buf = ngx_sprintf_str(buf, last, v->data, v->len, hex); fmt++; continue; @@ -259,8 +260,7 @@ ngx_vslprintf(u_char *buf, u_char *last, const char *fmt, va_list args) case 'v': vv = va_arg(args, ngx_variable_value_t *); - len = ngx_min(((size_t) (last - buf)), vv->len); - buf = ngx_cpymem(buf, vv->data, len); + buf = ngx_sprintf_str(buf, last, vv->data, vv->len, hex); fmt++; continue; @@ -268,16 +268,7 @@ ngx_vslprintf(u_char *buf, u_char *last, const char *fmt, va_list args) case 's': p = va_arg(args, u_char *); - if (slen == (size_t) -1) { - while (*p && buf < last) { - *buf++ = *p++; - } - - } else { - len = ngx_min(((size_t) (last - buf)), slen); - buf = ngx_cpymem(buf, p, len); - } - + buf = ngx_sprintf_str(buf, last, p, slen, hex); fmt++; continue; @@ -576,6 +567,64 @@ ngx_sprintf_num(u_char *buf, u_char *last, uint64_t ui64, u_char zero, } +static u_char * +ngx_sprintf_str(u_char *buf, u_char *last, u_char *src, size_t len, + ngx_uint_t hexadecimal) +{ + static u_char hex[] = "0123456789abcdef"; + static u_char HEX[] = "0123456789ABCDEF"; + + if (hexadecimal == 0) { + + if (len == (size_t) -1) { + while (*src && buf < last) { + *buf++ = *src++; + } + + } else { + len = ngx_min((size_t) (last - buf), len); + buf = ngx_cpymem(buf, src, len); + } + + } else if (hexadecimal == 1) { + + if (len == (size_t) -1) { + + while (*src && buf < last - 1) { + *buf++ = hex[*src >> 4]; + *buf++ = hex[*src++ & 0xf]; + } + + } else { + + while (len-- && buf < last - 1) { + *buf++ = hex[*src >> 4]; + *buf++ = hex[*src++ & 0xf]; + } + } + + } else { /* hexadecimal == 2 */ + + if (len == (size_t) -1) { + + while (*src && buf < last - 1) { + *buf++ = HEX[*src >> 4]; + *buf++ = HEX[*src++ & 0xf]; + } + + } else { + + while (len-- && buf < last - 1) { + *buf++ = HEX[*src >> 4]; + *buf++ = HEX[*src++ & 0xf]; + } + } + } + + return buf; +} + + /* * We use ngx_strcasecmp()/ngx_strncasecmp() for 7-bit ASCII strings only, * and implement our own ngx_strcasecmp()/ngx_strncasecmp() diff --git a/src/event/modules/ngx_eventport_module.c b/src/event/modules/ngx_eventport_module.c index f67c704..d304e1c 100644 --- a/src/event/modules/ngx_eventport_module.c +++ b/src/event/modules/ngx_eventport_module.c @@ -399,7 +399,7 @@ ngx_eventport_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags) return NGX_ERROR; } - } else { + } else if (ev->active) { ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ev->log, 0, "eventport del event: fd:%d", c->fd); diff --git a/src/event/ngx_event.c b/src/event/ngx_event.c index 402a7f5..7777d04 100644 --- a/src/event/ngx_event.c +++ b/src/event/ngx_event.c @@ -257,9 +257,7 @@ ngx_process_events_and_timers(ngx_cycle_t *cycle) ngx_shmtx_unlock(&ngx_accept_mutex); } - if (delta) { - ngx_event_expire_timers(); - } + ngx_event_expire_timers(); ngx_event_process_posted(cycle, &ngx_posted_events); } @@ -318,7 +316,7 @@ ngx_handle_read_event(ngx_event_t *rev, ngx_uint_t flags) return NGX_OK; } - if (rev->oneshot && !rev->ready) { + if (rev->oneshot && rev->ready) { if (ngx_del_event(rev, NGX_READ_EVENT, 0) == NGX_ERROR) { return NGX_ERROR; } diff --git a/src/event/ngx_event_accept.c b/src/event/ngx_event_accept.c index 4364240..b05666c 100644 --- a/src/event/ngx_event_accept.c +++ b/src/event/ngx_event_accept.c @@ -256,6 +256,8 @@ ngx_event_accept(ngx_event_t *ev) c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1); + c->start_time = ngx_current_msec; + #if (NGX_STAT_STUB) (void) ngx_atomic_fetch_add(ngx_stat_handled, 1); #endif diff --git a/src/event/ngx_event_connect.c b/src/event/ngx_event_connect.c index 1ffa798..adbbde6 100644 --- a/src/event/ngx_event_connect.c +++ b/src/event/ngx_event_connect.c @@ -193,6 +193,8 @@ ngx_event_connect_peer(ngx_peer_connection_t *pc) c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1); + c->start_time = ngx_current_msec; + if (ngx_add_conn) { if (ngx_add_conn(c) == NGX_ERROR) { goto failed; diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c index 91b415c..ce2a566 100644 --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -83,7 +83,7 @@ static time_t ngx_ssl_parse_time( #if OPENSSL_VERSION_NUMBER > 0x10100000L const #endif - ASN1_TIME *asn1time); + ASN1_TIME *asn1time, ngx_log_t *log); static void *ngx_openssl_create_conf(ngx_cycle_t *cycle); static char *ngx_openssl_engine(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); @@ -130,6 +130,7 @@ int ngx_ssl_connection_index; int ngx_ssl_server_conf_index; int ngx_ssl_session_cache_index; int ngx_ssl_session_ticket_keys_index; +int ngx_ssl_ocsp_index; int ngx_ssl_certificate_index; int ngx_ssl_next_certificate_index; int ngx_ssl_certificate_name_index; @@ -213,6 +214,13 @@ ngx_ssl_init(ngx_log_t *log) return NGX_ERROR; } + ngx_ssl_ocsp_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL, NULL); + if (ngx_ssl_ocsp_index == -1) { + ngx_ssl_error(NGX_LOG_ALERT, log, 0, + "SSL_CTX_get_ex_new_index() failed"); + return NGX_ERROR; + } + ngx_ssl_certificate_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL, NULL); if (ngx_ssl_certificate_index == -1) { @@ -370,6 +378,10 @@ ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_t protocols, void *data) SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_CLIENT_RENEGOTIATION); #endif +#ifdef SSL_OP_IGNORE_UNEXPECTED_EOF + SSL_CTX_set_options(ssl->ctx, SSL_OP_IGNORE_UNEXPECTED_EOF); +#endif + #ifdef SSL_MODE_RELEASE_BUFFERS SSL_CTX_set_mode(ssl->ctx, SSL_MODE_RELEASE_BUFFERS); #endif @@ -912,6 +924,9 @@ ngx_int_t ngx_ssl_trusted_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert, ngx_int_t depth) { + SSL_CTX_set_verify(ssl->ctx, SSL_CTX_get_verify_mode(ssl->ctx), + ngx_ssl_verify_callback); + SSL_CTX_set_verify_depth(ssl->ctx, depth); if (cert->len == 0) { @@ -1003,26 +1018,52 @@ ngx_ssl_verify_callback(int ok, X509_STORE_CTX *x509_store) c = ngx_ssl_get_connection(ssl_conn); + if (!(c->log->log_level & NGX_LOG_DEBUG_EVENT)) { + return 1; + } + cert = X509_STORE_CTX_get_current_cert(x509_store); err = X509_STORE_CTX_get_error(x509_store); depth = X509_STORE_CTX_get_error_depth(x509_store); sname = X509_get_subject_name(cert); - subject = sname ? X509_NAME_oneline(sname, NULL, 0) : "(none)"; + + if (sname) { + subject = X509_NAME_oneline(sname, NULL, 0); + if (subject == NULL) { + ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, + "X509_NAME_oneline() failed"); + } + + } else { + subject = NULL; + } iname = X509_get_issuer_name(cert); - issuer = iname ? X509_NAME_oneline(iname, NULL, 0) : "(none)"; + + if (iname) { + issuer = X509_NAME_oneline(iname, NULL, 0); + if (issuer == NULL) { + ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, + "X509_NAME_oneline() failed"); + } + + } else { + issuer = NULL; + } ngx_log_debug5(NGX_LOG_DEBUG_EVENT, c->log, 0, "verify:%d, error:%d, depth:%d, " "subject:\"%s\", issuer:\"%s\"", - ok, err, depth, subject, issuer); + ok, err, depth, + subject ? subject : "(none)", + issuer ? issuer : "(none)"); - if (sname) { + if (subject) { OPENSSL_free(subject); } - if (iname) { + if (issuer) { OPENSSL_free(issuer); } #endif @@ -1079,6 +1120,8 @@ ngx_ssl_info_callback(const ngx_ssl_conn_t *ssl_conn, int where, int ret) } +#if (OPENSSL_VERSION_NUMBER < 0x10100001L && !defined LIBRESSL_VERSION_NUMBER) + RSA * ngx_ssl_rsa512_key_callback(ngx_ssl_conn_t *ssl_conn, int is_export, int key_length) @@ -1089,7 +1132,7 @@ ngx_ssl_rsa512_key_callback(ngx_ssl_conn_t *ssl_conn, int is_export, return NULL; } -#if (OPENSSL_VERSION_NUMBER < 0x10100003L && !defined OPENSSL_NO_DEPRECATED) +#ifndef OPENSSL_NO_DEPRECATED if (key == NULL) { key = RSA_generate_key(512, RSA_F4, NULL, NULL); @@ -1100,6 +1143,8 @@ ngx_ssl_rsa512_key_callback(ngx_ssl_conn_t *ssl_conn, int is_export, return key; } +#endif + ngx_array_t * ngx_ssl_read_password_file(ngx_conf_t *cf, ngx_str_t *file) @@ -1313,7 +1358,6 @@ ngx_ssl_passwords_cleanup(void *data) ngx_int_t ngx_ssl_dhparam(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file) { - DH *dh; BIO *bio; if (file->len == 0) { @@ -1331,6 +1375,10 @@ ngx_ssl_dhparam(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file) return NGX_ERROR; } +#ifdef SSL_CTX_set_tmp_dh + { + DH *dh; + dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); if (dh == NULL) { ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, @@ -1339,9 +1387,42 @@ ngx_ssl_dhparam(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file) return NGX_ERROR; } - SSL_CTX_set_tmp_dh(ssl->ctx, dh); + if (SSL_CTX_set_tmp_dh(ssl->ctx, dh) != 1) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "SSL_CTX_set_tmp_dh(\"%s\") failed", file->data); + DH_free(dh); + BIO_free(bio); + return NGX_ERROR; + } DH_free(dh); + } +#else + { + EVP_PKEY *dh; + + /* + * PEM_read_bio_DHparams() and SSL_CTX_set_tmp_dh() + * are deprecated in OpenSSL 3.0 + */ + + dh = PEM_read_bio_Parameters(bio, NULL); + if (dh == NULL) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "PEM_read_bio_Parameters(\"%s\") failed", file->data); + BIO_free(bio); + return NGX_ERROR; + } + + if (SSL_CTX_set0_tmp_dh_pkey(ssl->ctx, dh) != 1) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "SSL_CTX_set0_tmp_dh_pkey(\%s\") failed", file->data); + BIO_free(bio); + return NGX_ERROR; + } + } +#endif + BIO_free(bio); return NGX_OK; @@ -1459,6 +1540,78 @@ ngx_ssl_early_data(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_uint_t enable) } +ngx_int_t +ngx_ssl_conf_commands(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_array_t *commands) +{ + if (commands == NULL) { + return NGX_OK; + } + +#ifdef SSL_CONF_FLAG_FILE + { + int type; + u_char *key, *value; + ngx_uint_t i; + ngx_keyval_t *cmd; + SSL_CONF_CTX *cctx; + + cctx = SSL_CONF_CTX_new(); + if (cctx == NULL) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "SSL_CONF_CTX_new() failed"); + return NGX_ERROR; + } + + SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_FILE); + SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_SERVER); + SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_CLIENT); + SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_CERTIFICATE); + SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_SHOW_ERRORS); + + SSL_CONF_CTX_set_ssl_ctx(cctx, ssl->ctx); + + cmd = commands->elts; + for (i = 0; i < commands->nelts; i++) { + + key = cmd[i].key.data; + type = SSL_CONF_cmd_value_type(cctx, (char *) key); + + if (type == SSL_CONF_TYPE_FILE || type == SSL_CONF_TYPE_DIR) { + if (ngx_conf_full_name(cf->cycle, &cmd[i].value, 1) != NGX_OK) { + SSL_CONF_CTX_free(cctx); + return NGX_ERROR; + } + } + + value = cmd[i].value.data; + + if (SSL_CONF_cmd(cctx, (char *) key, (char *) value) <= 0) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "SSL_CONF_cmd(\"%s\", \"%s\") failed", key, value); + SSL_CONF_CTX_free(cctx); + return NGX_ERROR; + } + } + + if (SSL_CONF_CTX_finish(cctx) != 1) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "SSL_CONF_finish() failed"); + SSL_CONF_CTX_free(cctx); + return NGX_ERROR; + } + + SSL_CONF_CTX_free(cctx); + + return NGX_OK; + } +#else + ngx_log_error(NGX_LOG_EMERG, ssl->log, 0, + "SSL_CONF_cmd() is not available on this platform"); + return NGX_ERROR; +#endif +} + + ngx_int_t ngx_ssl_client_session_cache(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_uint_t enable) { @@ -1594,6 +1747,7 @@ ngx_ssl_handshake(ngx_connection_t *c) { int n, sslerr; ngx_err_t err; + ngx_int_t rc; #ifdef SSL_READ_EARLY_DATA_SUCCESS if (c->ssl->try_early_data) { @@ -1601,6 +1755,10 @@ ngx_ssl_handshake(ngx_connection_t *c) } #endif + if (c->ssl->in_ocsp) { + return ngx_ssl_ocsp_validate(c); + } + ngx_ssl_clear_error(c->log); n = SSL_do_handshake(c->ssl->connection); @@ -1621,13 +1779,14 @@ ngx_ssl_handshake(ngx_connection_t *c) ngx_ssl_handshake_log(c); #endif - c->ssl->handshaked = 1; - c->recv = ngx_ssl_recv; c->send = ngx_ssl_write; c->recv_chain = ngx_ssl_recv_chain; c->send_chain = ngx_ssl_send_chain; + c->read->ready = 1; + c->write->ready = 1; + #ifndef SSL_OP_NO_RENEGOTIATION #if OPENSSL_VERSION_NUMBER < 0x10100000L #ifdef SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS @@ -1641,6 +1800,20 @@ ngx_ssl_handshake(ngx_connection_t *c) #endif #endif + rc = ngx_ssl_ocsp_validate(c); + + if (rc == NGX_ERROR) { + return NGX_ERROR; + } + + if (rc == NGX_AGAIN) { + c->read->handler = ngx_ssl_handshake_handler; + c->write->handler = ngx_ssl_handshake_handler; + return NGX_AGAIN; + } + + c->ssl->handshaked = 1; + return NGX_OK; } @@ -1693,6 +1866,13 @@ ngx_ssl_handshake(ngx_connection_t *c) return NGX_ERROR; } + if (c->ssl->handshake_rejected) { + ngx_connection_error(c, err, "handshake rejected"); + ERR_clear_error(); + + return NGX_ERROR; + } + c->read->error = 1; ngx_ssl_connection_error(c, sslerr, err, "SSL_do_handshake() failed"); @@ -1710,6 +1890,7 @@ ngx_ssl_try_early_data(ngx_connection_t *c) u_char buf; size_t readbytes; ngx_err_t err; + ngx_int_t rc; ngx_ssl_clear_error(c->log); @@ -1744,7 +1925,6 @@ ngx_ssl_try_early_data(ngx_connection_t *c) c->ssl->early_buf = buf; c->ssl->early_preread = 1; - c->ssl->handshaked = 1; c->ssl->in_early = 1; c->recv = ngx_ssl_recv; @@ -1752,6 +1932,23 @@ ngx_ssl_try_early_data(ngx_connection_t *c) c->recv_chain = ngx_ssl_recv_chain; c->send_chain = ngx_ssl_send_chain; + c->read->ready = 1; + c->write->ready = 1; + + rc = ngx_ssl_ocsp_validate(c); + + if (rc == NGX_ERROR) { + return NGX_ERROR; + } + + if (rc == NGX_AGAIN) { + c->read->handler = ngx_ssl_handshake_handler; + c->write->handler = ngx_ssl_handshake_handler; + return NGX_AGAIN; + } + + c->ssl->handshaked = 1; + return NGX_OK; } @@ -1827,6 +2024,10 @@ ngx_ssl_handshake_log(ngx_connection_t *c) #endif SSL_CIPHER *cipher; + if (!(c->log->log_level & NGX_LOG_DEBUG_EVENT)) { + return; + } + cipher = SSL_get_current_cipher(c->ssl->connection); if (cipher) { @@ -2531,6 +2732,18 @@ ngx_ssl_write(ngx_connection_t *c, u_char *data, size_t size) sslerr = SSL_get_error(c->ssl->connection, n); + if (sslerr == SSL_ERROR_ZERO_RETURN) { + + /* + * OpenSSL 1.1.1 fails to return SSL_ERROR_SYSCALL if an error + * happens during SSL_write() after close_notify alert from the + * peer, and returns SSL_ERROR_ZERO_RETURN instead, + * https://git.openssl.org/?p=openssl.git;a=commitdiff;h=8051ab2 + */ + + sslerr = SSL_ERROR_SYSCALL; + } + err = (sslerr == SSL_ERROR_SYSCALL) ? ngx_errno : 0; ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_get_error: %d", sslerr); @@ -2732,8 +2945,14 @@ ngx_ssl_free_buffer(ngx_connection_t *c) ngx_int_t ngx_ssl_shutdown(ngx_connection_t *c) { - int n, sslerr, mode; - ngx_err_t err; + int n, sslerr, mode; + ngx_int_t rc; + ngx_err_t err; + ngx_uint_t tries; + + rc = NGX_OK; + + ngx_ssl_ocsp_cleanup(c); if (SSL_in_init(c->ssl->connection)) { /* @@ -2742,13 +2961,10 @@ ngx_ssl_shutdown(ngx_connection_t *c) * Avoid calling SSL_shutdown() if handshake wasn't completed. */ - SSL_free(c->ssl->connection); - c->ssl = NULL; - - return NGX_OK; + goto done; } - if (c->timedout) { + if (c->timedout || c->error || c->buffered) { mode = SSL_RECEIVED_SHUTDOWN|SSL_SENT_SHUTDOWN; SSL_set_quiet_shutdown(c->ssl->connection, 1); @@ -2772,55 +2988,87 @@ ngx_ssl_shutdown(ngx_connection_t *c) ngx_ssl_clear_error(c->log); - n = SSL_shutdown(c->ssl->connection); + tries = 2; - ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_shutdown: %d", n); + for ( ;; ) { - sslerr = 0; + /* + * For bidirectional shutdown, SSL_shutdown() needs to be called + * twice: first call sends the "close notify" alert and returns 0, + * second call waits for the peer's "close notify" alert. + */ - /* before 0.9.8m SSL_shutdown() returned 0 instead of -1 on errors */ + n = SSL_shutdown(c->ssl->connection); + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_shutdown: %d", n); + + if (n == 1) { + goto done; + } + + if (n == 0 && tries-- > 1) { + continue; + } + + /* before 0.9.8m SSL_shutdown() returned 0 instead of -1 on errors */ - if (n != 1 && ERR_peek_error()) { sslerr = SSL_get_error(c->ssl->connection, n); ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_get_error: %d", sslerr); - } - if (n == 1 || sslerr == 0 || sslerr == SSL_ERROR_ZERO_RETURN) { - SSL_free(c->ssl->connection); - c->ssl = NULL; + if (sslerr == SSL_ERROR_WANT_READ || sslerr == SSL_ERROR_WANT_WRITE) { + c->read->handler = ngx_ssl_shutdown_handler; + c->write->handler = ngx_ssl_shutdown_handler; - return NGX_OK; - } + if (sslerr == SSL_ERROR_WANT_READ) { + c->read->ready = 0; - if (sslerr == SSL_ERROR_WANT_READ || sslerr == SSL_ERROR_WANT_WRITE) { - c->read->handler = ngx_ssl_shutdown_handler; - c->write->handler = ngx_ssl_shutdown_handler; + } else { + c->write->ready = 0; + } - if (ngx_handle_read_event(c->read, 0) != NGX_OK) { - return NGX_ERROR; + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + goto failed; + } + + if (ngx_handle_write_event(c->write, 0) != NGX_OK) { + goto failed; + } + + ngx_add_timer(c->read, 3000); + + return NGX_AGAIN; } - if (ngx_handle_write_event(c->write, 0) != NGX_OK) { - return NGX_ERROR; + if (sslerr == SSL_ERROR_ZERO_RETURN || ERR_peek_error() == 0) { + goto done; } - if (sslerr == SSL_ERROR_WANT_READ) { - ngx_add_timer(c->read, 30000); - } + err = (sslerr == SSL_ERROR_SYSCALL) ? ngx_errno : 0; - return NGX_AGAIN; + ngx_ssl_connection_error(c, sslerr, err, "SSL_shutdown() failed"); + + break; } - err = (sslerr == SSL_ERROR_SYSCALL) ? ngx_errno : 0; +failed: - ngx_ssl_connection_error(c, sslerr, err, "SSL_shutdown() failed"); + rc = NGX_ERROR; + +done: + + if (c->ssl->shutdown_without_free) { + c->ssl->shutdown_without_free = 0; + c->recv = ngx_recv; + return rc; + } SSL_free(c->ssl->connection); c->ssl = NULL; + c->recv = ngx_recv; - return NGX_ERROR; + return rc; } @@ -3036,7 +3284,7 @@ ngx_ssl_error(ngx_uint_t level, ngx_log_t *log, ngx_err_t err, char *fmt, ...) for ( ;; ) { - n = ERR_peek_error_line_data(NULL, NULL, &data, &flags); + n = ERR_peek_error_data(&data, &flags); if (n == 0) { break; @@ -3202,8 +3450,9 @@ ngx_ssl_session_id_context(ngx_ssl_t *ssl, ngx_str_t *sess_ctx, } } - if (SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_certificate_index) == NULL) { - + if (SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_certificate_index) == NULL + && certificates != NULL) + { /* * If certificates are loaded dynamically, we use certificate * names as specified in the configuration (with variables). @@ -3897,9 +4146,6 @@ ngx_ssl_session_ticket_key_callback(ngx_ssl_conn_t *ssl_conn, ngx_ssl_session_ticket_key_t *key; const EVP_MD *digest; const EVP_CIPHER *cipher; -#if (NGX_DEBUG) - u_char buf[32]; -#endif c = ngx_ssl_get_connection(ssl_conn); ssl_ctx = c->ssl->session_ctx; @@ -3921,8 +4167,8 @@ ngx_ssl_session_ticket_key_callback(ngx_ssl_conn_t *ssl_conn, /* encrypt session ticket */ ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, - "ssl session ticket encrypt, key: \"%*s\" (%s session)", - ngx_hex_dump(buf, key[0].name, 16) - buf, buf, + "ssl session ticket encrypt, key: \"%*xs\" (%s session)", + (size_t) 16, key[0].name, SSL_session_reused(ssl_conn) ? "reused" : "new"); if (key[0].size == 48) { @@ -3968,17 +4214,16 @@ ngx_ssl_session_ticket_key_callback(ngx_ssl_conn_t *ssl_conn, } ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, - "ssl session ticket decrypt, key: \"%*s\" not found", - ngx_hex_dump(buf, name, 16) - buf, buf); + "ssl session ticket decrypt, key: \"%*xs\" not found", + (size_t) 16, name); return 0; found: ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, - "ssl session ticket decrypt, key: \"%*s\"%s", - ngx_hex_dump(buf, key[i].name, 16) - buf, buf, - (i == 0) ? " (default)" : ""); + "ssl session ticket decrypt, key: \"%*xs\"%s", + (size_t) 16, key[i].name, (i == 0) ? " (default)" : ""); if (key[i].size == 48) { cipher = EVP_aes_128_cbc(); @@ -4635,11 +4880,13 @@ ngx_ssl_get_subject_dn(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) bio = BIO_new(BIO_s_mem()); if (bio == NULL) { + ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "BIO_new() failed"); X509_free(cert); return NGX_ERROR; } if (X509_NAME_print_ex(bio, name, 0, XN_FLAG_RFC2253) < 0) { + ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "X509_NAME_print_ex() failed"); goto failed; } @@ -4687,11 +4934,13 @@ ngx_ssl_get_issuer_dn(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) bio = BIO_new(BIO_s_mem()); if (bio == NULL) { + ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "BIO_new() failed"); X509_free(cert); return NGX_ERROR; } if (X509_NAME_print_ex(bio, name, 0, XN_FLAG_RFC2253) < 0) { + ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "X509_NAME_print_ex() failed"); goto failed; } @@ -4740,6 +4989,11 @@ ngx_ssl_get_subject_dn_legacy(ngx_connection_t *c, ngx_pool_t *pool, } p = X509_NAME_oneline(name, NULL, 0); + if (p == NULL) { + ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "X509_NAME_oneline() failed"); + X509_free(cert); + return NGX_ERROR; + } for (len = 0; p[len]; len++) { /* void */ } @@ -4783,6 +5037,11 @@ ngx_ssl_get_issuer_dn_legacy(ngx_connection_t *c, ngx_pool_t *pool, } p = X509_NAME_oneline(name, NULL, 0); + if (p == NULL) { + ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "X509_NAME_oneline() failed"); + X509_free(cert); + return NGX_ERROR; + } for (len = 0; p[len]; len++) { /* void */ } @@ -4819,6 +5078,7 @@ ngx_ssl_get_serial_number(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) bio = BIO_new(BIO_s_mem()); if (bio == NULL) { + ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "BIO_new() failed"); X509_free(cert); return NGX_ERROR; } @@ -4857,6 +5117,7 @@ ngx_ssl_get_fingerprint(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) } if (!X509_digest(cert, EVP_sha1(), buf, &len)) { + ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "X509_digest() failed"); X509_free(cert); return NGX_ERROR; } @@ -4894,11 +5155,14 @@ ngx_ssl_get_client_verify(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) rc = SSL_get_verify_result(c->ssl->connection); if (rc == X509_V_OK) { - ngx_str_set(s, "SUCCESS"); - return NGX_OK; - } + if (ngx_ssl_ocsp_get_status(c, &str) == NGX_OK) { + ngx_str_set(s, "SUCCESS"); + return NGX_OK; + } - str = X509_verify_cert_error_string(rc); + } else { + str = X509_verify_cert_error_string(rc); + } s->data = ngx_pnalloc(pool, sizeof("FAILED:") - 1 + ngx_strlen(str)); if (s->data == NULL) { @@ -4927,6 +5191,7 @@ ngx_ssl_get_client_v_start(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) bio = BIO_new(BIO_s_mem()); if (bio == NULL) { + ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "BIO_new() failed"); X509_free(cert); return NGX_ERROR; } @@ -4971,6 +5236,7 @@ ngx_ssl_get_client_v_end(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) bio = BIO_new(BIO_s_mem()); if (bio == NULL) { + ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "BIO_new() failed"); X509_free(cert); return NGX_ERROR; } @@ -5013,9 +5279,9 @@ ngx_ssl_get_client_v_remain(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) } #if OPENSSL_VERSION_NUMBER > 0x10100000L - end = ngx_ssl_parse_time(X509_get0_notAfter(cert)); + end = ngx_ssl_parse_time(X509_get0_notAfter(cert), c->log); #else - end = ngx_ssl_parse_time(X509_get_notAfter(cert)); + end = ngx_ssl_parse_time(X509_get_notAfter(cert), c->log); #endif if (end == (time_t) NGX_ERROR) { @@ -5050,7 +5316,7 @@ ngx_ssl_parse_time( #if OPENSSL_VERSION_NUMBER > 0x10100000L const #endif - ASN1_TIME *asn1time) + ASN1_TIME *asn1time, ngx_log_t *log) { BIO *bio; char *value; @@ -5066,6 +5332,7 @@ ngx_ssl_parse_time( bio = BIO_new(BIO_s_mem()); if (bio == NULL) { + ngx_ssl_error(NGX_LOG_ALERT, log, 0, "BIO_new() failed"); return NGX_ERROR; } diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h index 61da0c5..81b87d7 100644 --- a/src/event/ngx_event_openssl.h +++ b/src/event/ngx_event_openssl.h @@ -12,6 +12,8 @@ #include #include +#define OPENSSL_SUPPRESS_DEPRECATED + #include #include #include @@ -64,6 +66,19 @@ #endif +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L && !defined SSL_get_peer_certificate) +#define SSL_get_peer_certificate(s) SSL_get1_peer_certificate(s) +#endif + + +#if (OPENSSL_VERSION_NUMBER < 0x30000000L && !defined ERR_peek_error_data) +#define ERR_peek_error_data(d, f) ERR_peek_error_line_data(NULL, NULL, d, f) +#endif + + +typedef struct ngx_ssl_ocsp_s ngx_ssl_ocsp_t; + + struct ngx_ssl_s { SSL_CTX *ctx; ngx_log_t *log; @@ -87,16 +102,21 @@ struct ngx_ssl_connection_s { ngx_event_handler_pt saved_read_handler; ngx_event_handler_pt saved_write_handler; + ngx_ssl_ocsp_t *ocsp; + u_char early_buf; unsigned handshaked:1; + unsigned handshake_rejected:1; unsigned renegotiation:1; unsigned buffer:1; unsigned no_wait_shutdown:1; unsigned no_send_shutdown:1; + unsigned shutdown_without_free:1; unsigned handshake_buffer_set:1; unsigned try_early_data:1; unsigned in_early:1; + unsigned in_ocsp:1; unsigned early_preread:1; unsigned write_blocked:1; }; @@ -180,8 +200,18 @@ ngx_int_t ngx_ssl_stapling(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file, ngx_str_t *responder, ngx_uint_t verify); ngx_int_t ngx_ssl_stapling_resolver(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_resolver_t *resolver, ngx_msec_t resolver_timeout); +ngx_int_t ngx_ssl_ocsp(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *responder, + ngx_uint_t depth, ngx_shm_zone_t *shm_zone); +ngx_int_t ngx_ssl_ocsp_resolver(ngx_conf_t *cf, ngx_ssl_t *ssl, + ngx_resolver_t *resolver, ngx_msec_t resolver_timeout); +ngx_int_t ngx_ssl_ocsp_validate(ngx_connection_t *c); +ngx_int_t ngx_ssl_ocsp_get_status(ngx_connection_t *c, const char **s); +void ngx_ssl_ocsp_cleanup(ngx_connection_t *c); +ngx_int_t ngx_ssl_ocsp_cache_init(ngx_shm_zone_t *shm_zone, void *data); +#if (OPENSSL_VERSION_NUMBER < 0x10100001L && !defined LIBRESSL_VERSION_NUMBER) RSA *ngx_ssl_rsa512_key_callback(ngx_ssl_conn_t *ssl_conn, int is_export, int key_length); +#endif ngx_array_t *ngx_ssl_read_password_file(ngx_conf_t *cf, ngx_str_t *file); ngx_array_t *ngx_ssl_preserve_passwords(ngx_conf_t *cf, ngx_array_t *passwords); @@ -189,6 +219,9 @@ ngx_int_t ngx_ssl_dhparam(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file); ngx_int_t ngx_ssl_ecdh_curve(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *name); ngx_int_t ngx_ssl_early_data(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_uint_t enable); +ngx_int_t ngx_ssl_conf_commands(ngx_conf_t *cf, ngx_ssl_t *ssl, + ngx_array_t *commands); + ngx_int_t ngx_ssl_client_session_cache(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_uint_t enable); ngx_int_t ngx_ssl_session_cache(ngx_ssl_t *ssl, ngx_str_t *sess_ctx, @@ -197,6 +230,7 @@ ngx_int_t ngx_ssl_session_cache(ngx_ssl_t *ssl, ngx_str_t *sess_ctx, ngx_int_t ngx_ssl_session_ticket_keys(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_array_t *paths); ngx_int_t ngx_ssl_session_cache_init(ngx_shm_zone_t *shm_zone, void *data); + ngx_int_t ngx_ssl_create_connection(ngx_ssl_t *ssl, ngx_connection_t *c, ngx_uint_t flags); @@ -281,6 +315,7 @@ extern int ngx_ssl_connection_index; extern int ngx_ssl_server_conf_index; extern int ngx_ssl_session_cache_index; extern int ngx_ssl_session_ticket_keys_index; +extern int ngx_ssl_ocsp_index; extern int ngx_ssl_certificate_index; extern int ngx_ssl_next_certificate_index; extern int ngx_ssl_certificate_name_index; diff --git a/src/event/ngx_event_openssl_stapling.c b/src/event/ngx_event_openssl_stapling.c index 5a7e40e..e3fa8c4 100644 --- a/src/event/ngx_event_openssl_stapling.c +++ b/src/event/ngx_event_openssl_stapling.c @@ -22,6 +22,7 @@ typedef struct { ngx_msec_t resolver_timeout; ngx_addr_t *addrs; + ngx_uint_t naddrs; ngx_str_t host; ngx_str_t uri; in_port_t port; @@ -30,6 +31,7 @@ typedef struct { X509 *cert; X509 *issuer; + STACK_OF(X509) *chain; u_char *name; @@ -41,15 +43,66 @@ typedef struct { } ngx_ssl_stapling_t; +typedef struct { + ngx_addr_t *addrs; + ngx_uint_t naddrs; + + ngx_str_t host; + ngx_str_t uri; + in_port_t port; + ngx_uint_t depth; + + ngx_shm_zone_t *shm_zone; + + ngx_resolver_t *resolver; + ngx_msec_t resolver_timeout; +} ngx_ssl_ocsp_conf_t; + + +typedef struct { + ngx_rbtree_t rbtree; + ngx_rbtree_node_t sentinel; + ngx_queue_t expire_queue; +} ngx_ssl_ocsp_cache_t; + + +typedef struct { + ngx_str_node_t node; + ngx_queue_t queue; + int status; + time_t valid; +} ngx_ssl_ocsp_cache_node_t; + + typedef struct ngx_ssl_ocsp_ctx_s ngx_ssl_ocsp_ctx_t; + +struct ngx_ssl_ocsp_s { + STACK_OF(X509) *certs; + ngx_uint_t ncert; + + int cert_status; + ngx_int_t status; + + ngx_ssl_ocsp_conf_t *conf; + ngx_ssl_ocsp_ctx_t *ctx; +}; + + struct ngx_ssl_ocsp_ctx_s { + SSL_CTX *ssl_ctx; + X509 *cert; X509 *issuer; + STACK_OF(X509) *chain; + + int status; + time_t valid; u_char *name; ngx_uint_t naddrs; + ngx_uint_t naddr; ngx_addr_t *addrs; ngx_str_t host; @@ -64,17 +117,20 @@ struct ngx_ssl_ocsp_ctx_s { void (*handler)(ngx_ssl_ocsp_ctx_t *ctx); void *data; + ngx_str_t key; ngx_buf_t *request; ngx_buf_t *response; ngx_peer_connection_t peer; + ngx_shm_zone_t *shm_zone; + ngx_int_t (*process)(ngx_ssl_ocsp_ctx_t *ctx); ngx_uint_t state; ngx_uint_t code; ngx_uint_t count; - + ngx_uint_t flags; ngx_uint_t done; u_char *header_name_start; @@ -105,8 +161,14 @@ static time_t ngx_ssl_stapling_time(ASN1_GENERALIZEDTIME *asn1time); static void ngx_ssl_stapling_cleanup(void *data); -static ngx_ssl_ocsp_ctx_t *ngx_ssl_ocsp_start(void); +static void ngx_ssl_ocsp_validate_next(ngx_connection_t *c); +static void ngx_ssl_ocsp_handler(ngx_ssl_ocsp_ctx_t *ctx); +static ngx_int_t ngx_ssl_ocsp_responder(ngx_connection_t *c, + ngx_ssl_ocsp_ctx_t *ctx); + +static ngx_ssl_ocsp_ctx_t *ngx_ssl_ocsp_start(ngx_log_t *log); static void ngx_ssl_ocsp_done(ngx_ssl_ocsp_ctx_t *ctx); +static void ngx_ssl_ocsp_next(ngx_ssl_ocsp_ctx_t *ctx); static void ngx_ssl_ocsp_request(ngx_ssl_ocsp_ctx_t *ctx); static void ngx_ssl_ocsp_resolve_handler(ngx_resolver_ctx_t *resolve); static void ngx_ssl_ocsp_connect(ngx_ssl_ocsp_ctx_t *ctx); @@ -120,6 +182,11 @@ static ngx_int_t ngx_ssl_ocsp_parse_status_line(ngx_ssl_ocsp_ctx_t *ctx); static ngx_int_t ngx_ssl_ocsp_process_headers(ngx_ssl_ocsp_ctx_t *ctx); static ngx_int_t ngx_ssl_ocsp_parse_header_line(ngx_ssl_ocsp_ctx_t *ctx); static ngx_int_t ngx_ssl_ocsp_process_body(ngx_ssl_ocsp_ctx_t *ctx); +static ngx_int_t ngx_ssl_ocsp_verify(ngx_ssl_ocsp_ctx_t *ctx); + +static ngx_int_t ngx_ssl_ocsp_cache_lookup(ngx_ssl_ocsp_ctx_t *ctx); +static ngx_int_t ngx_ssl_ocsp_cache_store(ngx_ssl_ocsp_ctx_t *ctx); +static ngx_int_t ngx_ssl_ocsp_create_key(ngx_ssl_ocsp_ctx_t *ctx); static u_char *ngx_ssl_ocsp_log_error(ngx_log_t *log, u_char *buf, size_t len); @@ -173,6 +240,18 @@ ngx_ssl_stapling_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, X509 *cert, return NGX_ERROR; } +#ifdef SSL_CTRL_SELECT_CURRENT_CERT + /* OpenSSL 1.0.2+ */ + SSL_CTX_select_current_cert(ssl->ctx, cert); +#endif + +#ifdef SSL_CTRL_GET_EXTRA_CHAIN_CERTS + /* OpenSSL 1.0.1+ */ + SSL_CTX_get_extra_chain_certs(ssl->ctx, &staple->chain); +#else + staple->chain = ssl->ctx->extra_certs; +#endif + staple->ssl_ctx = ssl->ctx; staple->timeout = 60000; staple->verify = verify; @@ -289,29 +368,16 @@ ngx_ssl_stapling_issuer(ngx_conf_t *cf, ngx_ssl_t *ssl, X509 *cert, *issuer; X509_STORE *store; X509_STORE_CTX *store_ctx; - STACK_OF(X509) *chain; cert = staple->cert; -#ifdef SSL_CTRL_SELECT_CURRENT_CERT - /* OpenSSL 1.0.2+ */ - SSL_CTX_select_current_cert(ssl->ctx, cert); -#endif - -#ifdef SSL_CTRL_GET_EXTRA_CHAIN_CERTS - /* OpenSSL 1.0.1+ */ - SSL_CTX_get_extra_chain_certs(ssl->ctx, &chain); -#else - chain = ssl->ctx->extra_certs; -#endif - - n = sk_X509_num(chain); + n = sk_X509_num(staple->chain); ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ssl->log, 0, "SSL get issuer: %d extra certs", n); for (i = 0; i < n; i++) { - issuer = sk_X509_value(chain, i); + issuer = sk_X509_value(staple->chain, i); if (X509_check_issued(issuer, cert) == X509_V_OK) { #if OPENSSL_VERSION_NUMBER >= 0x10100001L X509_up_ref(issuer); @@ -462,6 +528,7 @@ ngx_ssl_stapling_responder(ngx_conf_t *cf, ngx_ssl_t *ssl, } staple->addrs = u.addrs; + staple->naddrs = u.naddrs; staple->host = u.host; staple->uri = u.uri; staple->port = u.port; @@ -559,16 +626,20 @@ ngx_ssl_stapling_update(ngx_ssl_stapling_t *staple) staple->loading = 1; - ctx = ngx_ssl_ocsp_start(); + ctx = ngx_ssl_ocsp_start(ngx_cycle->log); if (ctx == NULL) { return; } + ctx->ssl_ctx = staple->ssl_ctx; ctx->cert = staple->cert; ctx->issuer = staple->issuer; + ctx->chain = staple->chain; ctx->name = staple->name; + ctx->flags = (staple->verify ? OCSP_TRUSTOTHER : OCSP_NOVERIFY); ctx->addrs = staple->addrs; + ctx->naddrs = staple->naddrs; ctx->host = staple->host; ctx->uri = staple->uri; ctx->port = staple->port; @@ -589,137 +660,27 @@ ngx_ssl_stapling_update(ngx_ssl_stapling_t *staple) static void ngx_ssl_stapling_ocsp_handler(ngx_ssl_ocsp_ctx_t *ctx) { - int n; - size_t len; - time_t now, valid; - ngx_str_t response; - X509_STORE *store; - const u_char *p; - STACK_OF(X509) *chain; - OCSP_CERTID *id; - OCSP_RESPONSE *ocsp; - OCSP_BASICRESP *basic; - ngx_ssl_stapling_t *staple; - ASN1_GENERALIZEDTIME *thisupdate, *nextupdate; + time_t now; + ngx_str_t response; + ngx_ssl_stapling_t *staple; staple = ctx->data; now = ngx_time(); - ocsp = NULL; - basic = NULL; - id = NULL; - if (ctx->code != 200) { + if (ngx_ssl_ocsp_verify(ctx) != NGX_OK) { goto error; } - /* check the response */ - - len = ctx->response->last - ctx->response->pos; - p = ctx->response->pos; - - ocsp = d2i_OCSP_RESPONSE(NULL, &p, len); - if (ocsp == NULL) { - ngx_ssl_error(NGX_LOG_ERR, ctx->log, 0, - "d2i_OCSP_RESPONSE() failed"); - goto error; - } - - n = OCSP_response_status(ocsp); - - if (n != OCSP_RESPONSE_STATUS_SUCCESSFUL) { - ngx_log_error(NGX_LOG_ERR, ctx->log, 0, - "OCSP response not successful (%d: %s)", - n, OCSP_response_status_str(n)); - goto error; - } - - basic = OCSP_response_get1_basic(ocsp); - if (basic == NULL) { - ngx_ssl_error(NGX_LOG_ERR, ctx->log, 0, - "OCSP_response_get1_basic() failed"); - goto error; - } - - store = SSL_CTX_get_cert_store(staple->ssl_ctx); - if (store == NULL) { - ngx_ssl_error(NGX_LOG_CRIT, ctx->log, 0, - "SSL_CTX_get_cert_store() failed"); - goto error; - } - -#ifdef SSL_CTRL_SELECT_CURRENT_CERT - /* OpenSSL 1.0.2+ */ - SSL_CTX_select_current_cert(staple->ssl_ctx, ctx->cert); -#endif - -#ifdef SSL_CTRL_GET_EXTRA_CHAIN_CERTS - /* OpenSSL 1.0.1+ */ - SSL_CTX_get_extra_chain_certs(staple->ssl_ctx, &chain); -#else - chain = staple->ssl_ctx->extra_certs; -#endif - - if (OCSP_basic_verify(basic, chain, store, - staple->verify ? OCSP_TRUSTOTHER : OCSP_NOVERIFY) - != 1) - { - ngx_ssl_error(NGX_LOG_ERR, ctx->log, 0, - "OCSP_basic_verify() failed"); - goto error; - } - - id = OCSP_cert_to_id(NULL, ctx->cert, ctx->issuer); - if (id == NULL) { - ngx_ssl_error(NGX_LOG_CRIT, ctx->log, 0, - "OCSP_cert_to_id() failed"); - goto error; - } - - if (OCSP_resp_find_status(basic, id, &n, NULL, NULL, - &thisupdate, &nextupdate) - != 1) - { - ngx_log_error(NGX_LOG_ERR, ctx->log, 0, - "certificate status not found in the OCSP response"); - goto error; - } - - if (n != V_OCSP_CERTSTATUS_GOOD) { + if (ctx->status != V_OCSP_CERTSTATUS_GOOD) { ngx_log_error(NGX_LOG_ERR, ctx->log, 0, "certificate status \"%s\" in the OCSP response", - OCSP_cert_status_str(n)); + OCSP_cert_status_str(ctx->status)); goto error; } - if (OCSP_check_validity(thisupdate, nextupdate, 300, -1) != 1) { - ngx_ssl_error(NGX_LOG_ERR, ctx->log, 0, - "OCSP_check_validity() failed"); - goto error; - } - - if (nextupdate) { - valid = ngx_ssl_stapling_time(nextupdate); - if (valid == (time_t) NGX_ERROR) { - ngx_log_error(NGX_LOG_ERR, ctx->log, 0, - "invalid nextUpdate time in certificate status"); - goto error; - } - - } else { - valid = NGX_MAX_TIME_T_VALUE; - } - - OCSP_CERTID_free(id); - OCSP_BASICRESP_free(basic); - OCSP_RESPONSE_free(ocsp); - - id = NULL; - basic = NULL; - ocsp = NULL; - /* copy the response to memory not in ctx->pool */ - response.len = len; + response.len = ctx->response->last - ctx->response->pos; response.data = ngx_alloc(response.len, ctx->log); if (response.data == NULL) { @@ -728,16 +689,12 @@ ngx_ssl_stapling_ocsp_handler(ngx_ssl_ocsp_ctx_t *ctx) ngx_memcpy(response.data, ctx->response->pos, response.len); - ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ctx->log, 0, - "ssl ocsp response, %s, %uz", - OCSP_cert_status_str(n), response.len); - if (staple->staple.data) { ngx_free(staple->staple.data); } staple->staple = response; - staple->valid = valid; + staple->valid = ctx->valid; /* * refresh before the response expires, @@ -745,7 +702,7 @@ ngx_ssl_stapling_ocsp_handler(ngx_ssl_ocsp_ctx_t *ctx) */ staple->loading = 0; - staple->refresh = ngx_max(ngx_min(valid - 300, now + 3600), now + 300); + staple->refresh = ngx_max(ngx_min(ctx->valid - 300, now + 3600), now + 300); ngx_ssl_ocsp_done(ctx); return; @@ -755,18 +712,6 @@ error: staple->loading = 0; staple->refresh = now + 300; - if (id) { - OCSP_CERTID_free(id); - } - - if (basic) { - OCSP_BASICRESP_free(basic); - } - - if (ocsp) { - OCSP_RESPONSE_free(ocsp); - } - ngx_ssl_ocsp_done(ctx); } @@ -820,14 +765,507 @@ ngx_ssl_stapling_cleanup(void *data) } -static ngx_ssl_ocsp_ctx_t * -ngx_ssl_ocsp_start(void) +ngx_int_t +ngx_ssl_ocsp(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *responder, + ngx_uint_t depth, ngx_shm_zone_t *shm_zone) +{ + ngx_url_t u; + ngx_ssl_ocsp_conf_t *ocf; + + ocf = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_ocsp_conf_t)); + if (ocf == NULL) { + return NGX_ERROR; + } + + ocf->depth = depth; + ocf->shm_zone = shm_zone; + + if (responder->len) { + ngx_memzero(&u, sizeof(ngx_url_t)); + + u.url = *responder; + u.default_port = 80; + u.uri_part = 1; + + if (u.url.len > 7 + && ngx_strncasecmp(u.url.data, (u_char *) "http://", 7) == 0) + { + u.url.len -= 7; + u.url.data += 7; + + } else { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "invalid URL prefix in OCSP responder \"%V\" " + "in \"ssl_ocsp_responder\"", &u.url); + return NGX_ERROR; + } + + if (ngx_parse_url(cf->pool, &u) != NGX_OK) { + if (u.err) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "%s in OCSP responder \"%V\" " + "in \"ssl_ocsp_responder\"", u.err, &u.url); + } + + return NGX_ERROR; + } + + ocf->addrs = u.addrs; + ocf->naddrs = u.naddrs; + ocf->host = u.host; + ocf->uri = u.uri; + ocf->port = u.port; + } + + if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_ocsp_index, ocf) == 0) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "SSL_CTX_set_ex_data() failed"); + return NGX_ERROR; + } + + return NGX_OK; +} + + +ngx_int_t +ngx_ssl_ocsp_resolver(ngx_conf_t *cf, ngx_ssl_t *ssl, + ngx_resolver_t *resolver, ngx_msec_t resolver_timeout) +{ + ngx_ssl_ocsp_conf_t *ocf; + + ocf = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_ocsp_index); + ocf->resolver = resolver; + ocf->resolver_timeout = resolver_timeout; + + return NGX_OK; +} + + +ngx_int_t +ngx_ssl_ocsp_validate(ngx_connection_t *c) +{ + X509 *cert; + SSL_CTX *ssl_ctx; + ngx_int_t rc; + X509_STORE *store; + X509_STORE_CTX *store_ctx; + STACK_OF(X509) *chain; + ngx_ssl_ocsp_t *ocsp; + ngx_ssl_ocsp_conf_t *ocf; + + if (c->ssl->in_ocsp) { + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + return NGX_ERROR; + } + + if (ngx_handle_write_event(c->write, 0) != NGX_OK) { + return NGX_ERROR; + } + + return NGX_AGAIN; + } + + ssl_ctx = SSL_get_SSL_CTX(c->ssl->connection); + + ocf = SSL_CTX_get_ex_data(ssl_ctx, ngx_ssl_ocsp_index); + if (ocf == NULL) { + return NGX_OK; + } + + if (SSL_get_verify_result(c->ssl->connection) != X509_V_OK) { + return NGX_OK; + } + + cert = SSL_get_peer_certificate(c->ssl->connection); + if (cert == NULL) { + return NGX_OK; + } + + ocsp = ngx_pcalloc(c->pool, sizeof(ngx_ssl_ocsp_t)); + if (ocsp == NULL) { + X509_free(cert); + return NGX_ERROR; + } + + c->ssl->ocsp = ocsp; + + ocsp->status = NGX_AGAIN; + ocsp->cert_status = V_OCSP_CERTSTATUS_GOOD; + ocsp->conf = ocf; + +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined LIBRESSL_VERSION_NUMBER) + + ocsp->certs = SSL_get0_verified_chain(c->ssl->connection); + + if (ocsp->certs) { + ocsp->certs = X509_chain_up_ref(ocsp->certs); + if (ocsp->certs == NULL) { + X509_free(cert); + return NGX_ERROR; + } + } + +#endif + + if (ocsp->certs == NULL) { + store = SSL_CTX_get_cert_store(ssl_ctx); + if (store == NULL) { + ngx_ssl_error(NGX_LOG_ERR, c->log, 0, + "SSL_CTX_get_cert_store() failed"); + X509_free(cert); + return NGX_ERROR; + } + + store_ctx = X509_STORE_CTX_new(); + if (store_ctx == NULL) { + ngx_ssl_error(NGX_LOG_ERR, c->log, 0, + "X509_STORE_CTX_new() failed"); + X509_free(cert); + return NGX_ERROR; + } + + chain = SSL_get_peer_cert_chain(c->ssl->connection); + + if (X509_STORE_CTX_init(store_ctx, store, cert, chain) == 0) { + ngx_ssl_error(NGX_LOG_ERR, c->log, 0, + "X509_STORE_CTX_init() failed"); + X509_STORE_CTX_free(store_ctx); + X509_free(cert); + return NGX_ERROR; + } + + rc = X509_verify_cert(store_ctx); + if (rc <= 0) { + ngx_ssl_error(NGX_LOG_ERR, c->log, 0, "X509_verify_cert() failed"); + X509_STORE_CTX_free(store_ctx); + X509_free(cert); + return NGX_ERROR; + } + + ocsp->certs = X509_STORE_CTX_get1_chain(store_ctx); + if (ocsp->certs == NULL) { + ngx_ssl_error(NGX_LOG_ERR, c->log, 0, + "X509_STORE_CTX_get1_chain() failed"); + X509_STORE_CTX_free(store_ctx); + X509_free(cert); + return NGX_ERROR; + } + + X509_STORE_CTX_free(store_ctx); + } + + X509_free(cert); + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "ssl ocsp validate, certs:%d", sk_X509_num(ocsp->certs)); + + ngx_ssl_ocsp_validate_next(c); + + if (ocsp->status == NGX_AGAIN) { + c->ssl->in_ocsp = 1; + return NGX_AGAIN; + } + + return NGX_OK; +} + + +static void +ngx_ssl_ocsp_validate_next(ngx_connection_t *c) +{ + ngx_int_t rc; + ngx_uint_t n; + ngx_ssl_ocsp_t *ocsp; + ngx_ssl_ocsp_ctx_t *ctx; + ngx_ssl_ocsp_conf_t *ocf; + + ocsp = c->ssl->ocsp; + ocf = ocsp->conf; + + n = sk_X509_num(ocsp->certs); + + for ( ;; ) { + + if (ocsp->ncert == n - 1 || (ocf->depth == 2 && ocsp->ncert == 1)) { + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "ssl ocsp validated, certs:%ui", ocsp->ncert); + rc = NGX_OK; + goto done; + } + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "ssl ocsp validate cert:%ui", ocsp->ncert); + + ctx = ngx_ssl_ocsp_start(c->log); + if (ctx == NULL) { + rc = NGX_ERROR; + goto done; + } + + ocsp->ctx = ctx; + + ctx->ssl_ctx = SSL_get_SSL_CTX(c->ssl->connection); + ctx->cert = sk_X509_value(ocsp->certs, ocsp->ncert); + ctx->issuer = sk_X509_value(ocsp->certs, ocsp->ncert + 1); + ctx->chain = ocsp->certs; + + ctx->resolver = ocf->resolver; + ctx->resolver_timeout = ocf->resolver_timeout; + + ctx->handler = ngx_ssl_ocsp_handler; + ctx->data = c; + + ctx->shm_zone = ocf->shm_zone; + + ctx->addrs = ocf->addrs; + ctx->naddrs = ocf->naddrs; + ctx->host = ocf->host; + ctx->uri = ocf->uri; + ctx->port = ocf->port; + + rc = ngx_ssl_ocsp_responder(c, ctx); + if (rc != NGX_OK) { + goto done; + } + + if (ctx->uri.len == 0) { + ngx_str_set(&ctx->uri, "/"); + } + + ocsp->ncert++; + + rc = ngx_ssl_ocsp_cache_lookup(ctx); + + if (rc == NGX_ERROR) { + goto done; + } + + if (rc == NGX_DECLINED) { + break; + } + + /* rc == NGX_OK */ + + if (ctx->status != V_OCSP_CERTSTATUS_GOOD) { + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ctx->log, 0, + "ssl ocsp cached status \"%s\"", + OCSP_cert_status_str(ctx->status)); + ocsp->cert_status = ctx->status; + goto done; + } + + ocsp->ctx = NULL; + ngx_ssl_ocsp_done(ctx); + } + + ngx_ssl_ocsp_request(ctx); + return; + +done: + + ocsp->status = rc; + + if (c->ssl->in_ocsp) { + c->ssl->handshaked = 1; + c->ssl->handler(c); + } +} + + +static void +ngx_ssl_ocsp_handler(ngx_ssl_ocsp_ctx_t *ctx) +{ + ngx_int_t rc; + ngx_ssl_ocsp_t *ocsp; + ngx_connection_t *c; + + c = ctx->data; + ocsp = c->ssl->ocsp; + ocsp->ctx = NULL; + + rc = ngx_ssl_ocsp_verify(ctx); + if (rc != NGX_OK) { + goto done; + } + + rc = ngx_ssl_ocsp_cache_store(ctx); + if (rc != NGX_OK) { + goto done; + } + + if (ctx->status != V_OCSP_CERTSTATUS_GOOD) { + ocsp->cert_status = ctx->status; + goto done; + } + + ngx_ssl_ocsp_done(ctx); + + ngx_ssl_ocsp_validate_next(c); + + return; + +done: + + ocsp->status = rc; + ngx_ssl_ocsp_done(ctx); + + if (c->ssl->in_ocsp) { + c->ssl->handshaked = 1; + c->ssl->handler(c); + } +} + + +static ngx_int_t +ngx_ssl_ocsp_responder(ngx_connection_t *c, ngx_ssl_ocsp_ctx_t *ctx) +{ + char *s; + ngx_str_t responder; + ngx_url_t u; + STACK_OF(OPENSSL_STRING) *aia; + + if (ctx->host.len) { + return NGX_OK; + } + + /* extract OCSP responder URL from certificate */ + + aia = X509_get1_ocsp(ctx->cert); + if (aia == NULL) { + ngx_log_error(NGX_LOG_ERR, c->log, 0, + "no OCSP responder URL in certificate"); + return NGX_ERROR; + } + +#if OPENSSL_VERSION_NUMBER >= 0x10000000L + s = sk_OPENSSL_STRING_value(aia, 0); +#else + s = sk_value(aia, 0); +#endif + if (s == NULL) { + ngx_log_error(NGX_LOG_ERR, c->log, 0, + "no OCSP responder URL in certificate"); + X509_email_free(aia); + return NGX_ERROR; + } + + responder.len = ngx_strlen(s); + responder.data = ngx_palloc(ctx->pool, responder.len); + if (responder.data == NULL) { + X509_email_free(aia); + return NGX_ERROR; + } + + ngx_memcpy(responder.data, s, responder.len); + X509_email_free(aia); + + ngx_memzero(&u, sizeof(ngx_url_t)); + + u.url = responder; + u.default_port = 80; + u.uri_part = 1; + u.no_resolve = 1; + + if (u.url.len > 7 + && ngx_strncasecmp(u.url.data, (u_char *) "http://", 7) == 0) + { + u.url.len -= 7; + u.url.data += 7; + + } else { + ngx_log_error(NGX_LOG_ERR, c->log, 0, + "invalid URL prefix in OCSP responder \"%V\" " + "in certificate", &u.url); + return NGX_ERROR; + } + + if (ngx_parse_url(ctx->pool, &u) != NGX_OK) { + if (u.err) { + ngx_log_error(NGX_LOG_ERR, c->log, 0, + "%s in OCSP responder \"%V\" in certificate", + u.err, &u.url); + } + + return NGX_ERROR; + } + + if (u.host.len == 0) { + ngx_log_error(NGX_LOG_ERR, c->log, 0, + "empty host in OCSP responder in certificate"); + return NGX_ERROR; + } + + ctx->addrs = u.addrs; + ctx->naddrs = u.naddrs; + ctx->host = u.host; + ctx->uri = u.uri; + ctx->port = u.port; + + return NGX_OK; +} + + +ngx_int_t +ngx_ssl_ocsp_get_status(ngx_connection_t *c, const char **s) +{ + ngx_ssl_ocsp_t *ocsp; + + ocsp = c->ssl->ocsp; + if (ocsp == NULL) { + return NGX_OK; + } + + if (ocsp->status == NGX_ERROR) { + *s = "certificate status request failed"; + return NGX_DECLINED; + } + + switch (ocsp->cert_status) { + + case V_OCSP_CERTSTATUS_GOOD: + return NGX_OK; + + case V_OCSP_CERTSTATUS_REVOKED: + *s = "certificate revoked"; + break; + + default: /* V_OCSP_CERTSTATUS_UNKNOWN */ + *s = "certificate status unknown"; + } + + return NGX_DECLINED; +} + + +void +ngx_ssl_ocsp_cleanup(ngx_connection_t *c) +{ + ngx_ssl_ocsp_t *ocsp; + + ocsp = c->ssl->ocsp; + if (ocsp == NULL) { + return; + } + + if (ocsp->ctx) { + ngx_ssl_ocsp_done(ocsp->ctx); + ocsp->ctx = NULL; + } + + if (ocsp->certs) { + sk_X509_pop_free(ocsp->certs, X509_free); + ocsp->certs = NULL; + } +} + + +static ngx_ssl_ocsp_ctx_t * +ngx_ssl_ocsp_start(ngx_log_t *log) { - ngx_log_t *log; ngx_pool_t *pool; ngx_ssl_ocsp_ctx_t *ctx; - pool = ngx_create_pool(2048, ngx_cycle->log); + pool = ngx_create_pool(2048, log); if (pool == NULL) { return NULL; } @@ -884,6 +1322,36 @@ ngx_ssl_ocsp_error(ngx_ssl_ocsp_ctx_t *ctx) } +static void +ngx_ssl_ocsp_next(ngx_ssl_ocsp_ctx_t *ctx) +{ + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ctx->log, 0, + "ssl ocsp next"); + + if (++ctx->naddr >= ctx->naddrs) { + ngx_ssl_ocsp_error(ctx); + return; + } + + ctx->request->pos = ctx->request->start; + + if (ctx->response) { + ctx->response->last = ctx->response->pos; + } + + if (ctx->peer.connection) { + ngx_close_connection(ctx->peer.connection); + ctx->peer.connection = NULL; + } + + ctx->state = 0; + ctx->count = 0; + ctx->done = 0; + + ngx_ssl_ocsp_connect(ctx); +} + + static void ngx_ssl_ocsp_request(ngx_ssl_ocsp_ctx_t *ctx) { @@ -909,6 +1377,14 @@ ngx_ssl_ocsp_request(ngx_ssl_ocsp_ctx_t *ctx) } if (resolve == NGX_NO_RESOLVER) { + if (ctx->naddrs == 0) { + ngx_log_error(NGX_LOG_ERR, ctx->log, 0, + "no resolver defined to resolve %V", &ctx->host); + + ngx_ssl_ocsp_error(ctx); + return; + } + ngx_log_error(NGX_LOG_WARN, ctx->log, 0, "no resolver defined to resolve %V", &ctx->host); goto connect; @@ -1022,16 +1498,17 @@ failed: static void ngx_ssl_ocsp_connect(ngx_ssl_ocsp_ctx_t *ctx) { - ngx_int_t rc; + ngx_int_t rc; + ngx_addr_t *addr; - ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ctx->log, 0, - "ssl ocsp connect"); + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ctx->log, 0, + "ssl ocsp connect %ui/%ui", ctx->naddr, ctx->naddrs); - /* TODO: use all ip addresses */ + addr = &ctx->addrs[ctx->naddr]; - ctx->peer.sockaddr = ctx->addrs[0].sockaddr; - ctx->peer.socklen = ctx->addrs[0].socklen; - ctx->peer.name = &ctx->addrs[0].name; + ctx->peer.sockaddr = addr->sockaddr; + ctx->peer.socklen = addr->socklen; + ctx->peer.name = &addr->name; ctx->peer.get = ngx_event_get_peer; ctx->peer.log = ctx->log; ctx->peer.log_error = NGX_ERROR_ERR; @@ -1041,11 +1518,16 @@ ngx_ssl_ocsp_connect(ngx_ssl_ocsp_ctx_t *ctx) ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ctx->log, 0, "ssl ocsp connect peer done"); - if (rc == NGX_ERROR || rc == NGX_BUSY || rc == NGX_DECLINED) { + if (rc == NGX_ERROR) { ngx_ssl_ocsp_error(ctx); return; } + if (rc == NGX_BUSY || rc == NGX_DECLINED) { + ngx_ssl_ocsp_next(ctx); + return; + } + ctx->peer.connection->data = ctx; ctx->peer.connection->pool = ctx->pool; @@ -1054,8 +1536,10 @@ ngx_ssl_ocsp_connect(ngx_ssl_ocsp_ctx_t *ctx) ctx->process = ngx_ssl_ocsp_process_status_line; - ngx_add_timer(ctx->peer.connection->read, ctx->timeout); - ngx_add_timer(ctx->peer.connection->write, ctx->timeout); + if (ctx->timeout) { + ngx_add_timer(ctx->peer.connection->read, ctx->timeout); + ngx_add_timer(ctx->peer.connection->write, ctx->timeout); + } if (rc == NGX_OK) { ngx_ssl_ocsp_write_handler(ctx->peer.connection->write); @@ -1080,7 +1564,7 @@ ngx_ssl_ocsp_write_handler(ngx_event_t *wev) if (wev->timedout) { ngx_log_error(NGX_LOG_ERR, wev->log, NGX_ETIMEDOUT, "OCSP responder timed out"); - ngx_ssl_ocsp_error(ctx); + ngx_ssl_ocsp_next(ctx); return; } @@ -1089,7 +1573,7 @@ ngx_ssl_ocsp_write_handler(ngx_event_t *wev) n = ngx_send(c, ctx->request->pos, size); if (n == NGX_ERROR) { - ngx_ssl_ocsp_error(ctx); + ngx_ssl_ocsp_next(ctx); return; } @@ -1111,7 +1595,7 @@ ngx_ssl_ocsp_write_handler(ngx_event_t *wev) } } - if (!wev->timer_set) { + if (!wev->timer_set && ctx->timeout) { ngx_add_timer(wev, ctx->timeout); } } @@ -1134,7 +1618,7 @@ ngx_ssl_ocsp_read_handler(ngx_event_t *rev) if (rev->timedout) { ngx_log_error(NGX_LOG_ERR, rev->log, NGX_ETIMEDOUT, "OCSP responder timed out"); - ngx_ssl_ocsp_error(ctx); + ngx_ssl_ocsp_next(ctx); return; } @@ -1158,7 +1642,7 @@ ngx_ssl_ocsp_read_handler(ngx_event_t *rev) rc = ctx->process(ctx); if (rc == NGX_ERROR) { - ngx_ssl_ocsp_error(ctx); + ngx_ssl_ocsp_next(ctx); return; } @@ -1189,7 +1673,7 @@ ngx_ssl_ocsp_read_handler(ngx_event_t *rev) ngx_log_error(NGX_LOG_ERR, ctx->log, 0, "OCSP responder prematurely closed connection"); - ngx_ssl_ocsp_error(ctx); + ngx_ssl_ocsp_next(ctx); } @@ -1831,6 +2315,360 @@ ngx_ssl_ocsp_process_body(ngx_ssl_ocsp_ctx_t *ctx) } +static ngx_int_t +ngx_ssl_ocsp_verify(ngx_ssl_ocsp_ctx_t *ctx) +{ + int n; + size_t len; + X509_STORE *store; + const u_char *p; + OCSP_CERTID *id; + OCSP_RESPONSE *ocsp; + OCSP_BASICRESP *basic; + ASN1_GENERALIZEDTIME *thisupdate, *nextupdate; + + ocsp = NULL; + basic = NULL; + id = NULL; + + if (ctx->code != 200) { + goto error; + } + + /* check the response */ + + len = ctx->response->last - ctx->response->pos; + p = ctx->response->pos; + + ocsp = d2i_OCSP_RESPONSE(NULL, &p, len); + if (ocsp == NULL) { + ngx_ssl_error(NGX_LOG_ERR, ctx->log, 0, + "d2i_OCSP_RESPONSE() failed"); + goto error; + } + + n = OCSP_response_status(ocsp); + + if (n != OCSP_RESPONSE_STATUS_SUCCESSFUL) { + ngx_log_error(NGX_LOG_ERR, ctx->log, 0, + "OCSP response not successful (%d: %s)", + n, OCSP_response_status_str(n)); + goto error; + } + + basic = OCSP_response_get1_basic(ocsp); + if (basic == NULL) { + ngx_ssl_error(NGX_LOG_ERR, ctx->log, 0, + "OCSP_response_get1_basic() failed"); + goto error; + } + + store = SSL_CTX_get_cert_store(ctx->ssl_ctx); + if (store == NULL) { + ngx_ssl_error(NGX_LOG_CRIT, ctx->log, 0, + "SSL_CTX_get_cert_store() failed"); + goto error; + } + + if (OCSP_basic_verify(basic, ctx->chain, store, ctx->flags) != 1) { + ngx_ssl_error(NGX_LOG_ERR, ctx->log, 0, + "OCSP_basic_verify() failed"); + goto error; + } + + id = OCSP_cert_to_id(NULL, ctx->cert, ctx->issuer); + if (id == NULL) { + ngx_ssl_error(NGX_LOG_CRIT, ctx->log, 0, + "OCSP_cert_to_id() failed"); + goto error; + } + + if (OCSP_resp_find_status(basic, id, &ctx->status, NULL, NULL, + &thisupdate, &nextupdate) + != 1) + { + ngx_log_error(NGX_LOG_ERR, ctx->log, 0, + "certificate status not found in the OCSP response"); + goto error; + } + + if (OCSP_check_validity(thisupdate, nextupdate, 300, -1) != 1) { + ngx_ssl_error(NGX_LOG_ERR, ctx->log, 0, + "OCSP_check_validity() failed"); + goto error; + } + + if (nextupdate) { + ctx->valid = ngx_ssl_stapling_time(nextupdate); + if (ctx->valid == (time_t) NGX_ERROR) { + ngx_log_error(NGX_LOG_ERR, ctx->log, 0, + "invalid nextUpdate time in certificate status"); + goto error; + } + + } else { + ctx->valid = NGX_MAX_TIME_T_VALUE; + } + + OCSP_CERTID_free(id); + OCSP_BASICRESP_free(basic); + OCSP_RESPONSE_free(ocsp); + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ctx->log, 0, + "ssl ocsp response, %s, %uz", + OCSP_cert_status_str(ctx->status), len); + + return NGX_OK; + +error: + + if (id) { + OCSP_CERTID_free(id); + } + + if (basic) { + OCSP_BASICRESP_free(basic); + } + + if (ocsp) { + OCSP_RESPONSE_free(ocsp); + } + + return NGX_ERROR; +} + + +ngx_int_t +ngx_ssl_ocsp_cache_init(ngx_shm_zone_t *shm_zone, void *data) +{ + size_t len; + ngx_slab_pool_t *shpool; + ngx_ssl_ocsp_cache_t *cache; + + if (data) { + shm_zone->data = data; + return NGX_OK; + } + + shpool = (ngx_slab_pool_t *) shm_zone->shm.addr; + + if (shm_zone->shm.exists) { + shm_zone->data = shpool->data; + return NGX_OK; + } + + cache = ngx_slab_alloc(shpool, sizeof(ngx_ssl_ocsp_cache_t)); + if (cache == NULL) { + return NGX_ERROR; + } + + shpool->data = cache; + shm_zone->data = cache; + + ngx_rbtree_init(&cache->rbtree, &cache->sentinel, + ngx_str_rbtree_insert_value); + + ngx_queue_init(&cache->expire_queue); + + len = sizeof(" in OCSP cache \"\"") + shm_zone->shm.name.len; + + shpool->log_ctx = ngx_slab_alloc(shpool, len); + if (shpool->log_ctx == NULL) { + return NGX_ERROR; + } + + ngx_sprintf(shpool->log_ctx, " in OCSP cache \"%V\"%Z", + &shm_zone->shm.name); + + shpool->log_nomem = 0; + + return NGX_OK; +} + + +static ngx_int_t +ngx_ssl_ocsp_cache_lookup(ngx_ssl_ocsp_ctx_t *ctx) +{ + uint32_t hash; + ngx_shm_zone_t *shm_zone; + ngx_slab_pool_t *shpool; + ngx_ssl_ocsp_cache_t *cache; + ngx_ssl_ocsp_cache_node_t *node; + + shm_zone = ctx->shm_zone; + + if (shm_zone == NULL) { + return NGX_DECLINED; + } + + if (ngx_ssl_ocsp_create_key(ctx) != NGX_OK) { + return NGX_ERROR; + } + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ctx->log, 0, "ssl ocsp cache lookup"); + + cache = shm_zone->data; + shpool = (ngx_slab_pool_t *) shm_zone->shm.addr; + hash = ngx_hash_key(ctx->key.data, ctx->key.len); + + ngx_shmtx_lock(&shpool->mutex); + + node = (ngx_ssl_ocsp_cache_node_t *) + ngx_str_rbtree_lookup(&cache->rbtree, &ctx->key, hash); + + if (node) { + if (node->valid > ngx_time()) { + ctx->status = node->status; + ngx_shmtx_unlock(&shpool->mutex); + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ctx->log, 0, + "ssl ocsp cache hit, %s", + OCSP_cert_status_str(ctx->status)); + + return NGX_OK; + } + + ngx_queue_remove(&node->queue); + ngx_rbtree_delete(&cache->rbtree, &node->node.node); + ngx_slab_free_locked(shpool, node); + + ngx_shmtx_unlock(&shpool->mutex); + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ctx->log, 0, + "ssl ocsp cache expired"); + + return NGX_DECLINED; + } + + ngx_shmtx_unlock(&shpool->mutex); + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ctx->log, 0, "ssl ocsp cache miss"); + + return NGX_DECLINED; +} + + +static ngx_int_t +ngx_ssl_ocsp_cache_store(ngx_ssl_ocsp_ctx_t *ctx) +{ + time_t now, valid; + uint32_t hash; + ngx_queue_t *q; + ngx_shm_zone_t *shm_zone; + ngx_slab_pool_t *shpool; + ngx_ssl_ocsp_cache_t *cache; + ngx_ssl_ocsp_cache_node_t *node; + + shm_zone = ctx->shm_zone; + + if (shm_zone == NULL) { + return NGX_OK; + } + + valid = ctx->valid; + + now = ngx_time(); + + if (valid < now) { + return NGX_OK; + } + + if (valid == NGX_MAX_TIME_T_VALUE) { + valid = now + 3600; + } + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ctx->log, 0, + "ssl ocsp cache store, valid:%T", valid - now); + + cache = shm_zone->data; + shpool = (ngx_slab_pool_t *) shm_zone->shm.addr; + hash = ngx_hash_key(ctx->key.data, ctx->key.len); + + ngx_shmtx_lock(&shpool->mutex); + + node = ngx_slab_calloc_locked(shpool, + sizeof(ngx_ssl_ocsp_cache_node_t) + ctx->key.len); + if (node == NULL) { + + if (!ngx_queue_empty(&cache->expire_queue)) { + q = ngx_queue_last(&cache->expire_queue); + node = ngx_queue_data(q, ngx_ssl_ocsp_cache_node_t, queue); + + ngx_rbtree_delete(&cache->rbtree, &node->node.node); + ngx_queue_remove(q); + ngx_slab_free_locked(shpool, node); + + node = ngx_slab_alloc_locked(shpool, + sizeof(ngx_ssl_ocsp_cache_node_t) + ctx->key.len); + } + + if (node == NULL) { + ngx_shmtx_unlock(&shpool->mutex); + ngx_log_error(NGX_LOG_ALERT, ctx->log, 0, + "could not allocate new entry%s", shpool->log_ctx); + return NGX_ERROR; + } + } + + node->node.str.len = ctx->key.len; + node->node.str.data = (u_char *) node + sizeof(ngx_ssl_ocsp_cache_node_t); + ngx_memcpy(node->node.str.data, ctx->key.data, ctx->key.len); + node->node.node.key = hash; + node->status = ctx->status; + node->valid = valid; + + ngx_rbtree_insert(&cache->rbtree, &node->node.node); + ngx_queue_insert_head(&cache->expire_queue, &node->queue); + + ngx_shmtx_unlock(&shpool->mutex); + + return NGX_OK; +} + + +static ngx_int_t +ngx_ssl_ocsp_create_key(ngx_ssl_ocsp_ctx_t *ctx) +{ + u_char *p; + X509_NAME *name; + ASN1_INTEGER *serial; + + p = ngx_pnalloc(ctx->pool, 60); + if (p == NULL) { + return NGX_ERROR; + } + + ctx->key.data = p; + ctx->key.len = 60; + + name = X509_get_subject_name(ctx->issuer); + if (X509_NAME_digest(name, EVP_sha1(), p, NULL) == 0) { + return NGX_ERROR; + } + + p += 20; + + if (X509_pubkey_digest(ctx->issuer, EVP_sha1(), p, NULL) == 0) { + return NGX_ERROR; + } + + p += 20; + + serial = X509_get_serialNumber(ctx->cert); + if (serial->length > 20) { + return NGX_ERROR; + } + + p = ngx_cpymem(p, serial->data, serial->length); + ngx_memzero(p, 20 - serial->length); + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ctx->log, 0, + "ssl ocsp key %xV", &ctx->key); + + return NGX_OK; +} + + static u_char * ngx_ssl_ocsp_log_error(ngx_log_t *log, u_char *buf, size_t len) { @@ -1891,4 +2729,50 @@ ngx_ssl_stapling_resolver(ngx_conf_t *cf, ngx_ssl_t *ssl, } +ngx_int_t +ngx_ssl_ocsp(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *responder, + ngx_uint_t depth, ngx_shm_zone_t *shm_zone) +{ + ngx_log_error(NGX_LOG_EMERG, ssl->log, 0, + "\"ssl_ocsp\" is not supported on this platform"); + + return NGX_ERROR; +} + + +ngx_int_t +ngx_ssl_ocsp_resolver(ngx_conf_t *cf, ngx_ssl_t *ssl, + ngx_resolver_t *resolver, ngx_msec_t resolver_timeout) +{ + return NGX_OK; +} + + +ngx_int_t +ngx_ssl_ocsp_validate(ngx_connection_t *c) +{ + return NGX_OK; +} + + +ngx_int_t +ngx_ssl_ocsp_get_status(ngx_connection_t *c, const char **s) +{ + return NGX_OK; +} + + +void +ngx_ssl_ocsp_cleanup(ngx_connection_t *c) +{ +} + + +ngx_int_t +ngx_ssl_ocsp_cache_init(ngx_shm_zone_t *shm_zone, void *data) +{ + return NGX_OK; +} + + #endif diff --git a/src/event/ngx_event_pipe.c b/src/event/ngx_event_pipe.c index 531b13a..54412e1 100644 --- a/src/event/ngx_event_pipe.c +++ b/src/event/ngx_event_pipe.c @@ -960,6 +960,22 @@ ngx_event_pipe_copy_input_filter(ngx_event_pipe_t *p, ngx_buf_t *buf) return NGX_OK; } + if (p->upstream_done) { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, p->log, 0, + "input data after close"); + return NGX_OK; + } + + if (p->length == 0) { + p->upstream_done = 1; + + ngx_log_error(NGX_LOG_WARN, p->log, 0, + "upstream sent more data than specified in " + "\"Content-Length\" header"); + + return NGX_OK; + } + cl = ngx_chain_get_free_buf(p->pool, &p->free); if (cl == NULL) { return NGX_ERROR; @@ -987,6 +1003,18 @@ ngx_event_pipe_copy_input_filter(ngx_event_pipe_t *p, ngx_buf_t *buf) return NGX_OK; } + if (b->last - b->pos > p->length) { + + ngx_log_error(NGX_LOG_WARN, p->log, 0, + "upstream sent more data than specified in " + "\"Content-Length\" header"); + + b->last = b->pos + p->length; + p->upstream_done = 1; + + return NGX_OK; + } + p->length -= b->last - b->pos; return NGX_OK; diff --git a/src/event/ngx_event_udp.c b/src/event/ngx_event_udp.c index 5572830..a524ae0 100644 --- a/src/event/ngx_event_udp.c +++ b/src/event/ngx_event_udp.c @@ -363,6 +363,8 @@ ngx_event_recvmsg(ngx_event_t *ev) c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1); + c->start_time = ngx_current_msec; + #if (NGX_STAT_STUB) (void) ngx_atomic_fetch_add(ngx_stat_handled, 1); #endif diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c index 2be0672..5191880 100644 --- a/src/http/modules/ngx_http_fastcgi_module.c +++ b/src/http/modules/ngx_http_fastcgi_module.c @@ -81,12 +81,15 @@ typedef struct { size_t length; size_t padding; + off_t rest; + ngx_chain_t *free; ngx_chain_t *busy; unsigned fastcgi_stdout:1; unsigned large_stderr:1; unsigned header_sent:1; + unsigned closed:1; ngx_array_t *split_parts; @@ -2075,13 +2078,31 @@ ngx_http_fastcgi_process_header(ngx_http_request_t *r) static ngx_int_t ngx_http_fastcgi_input_filter_init(void *data) { - ngx_http_request_t *r = data; + ngx_http_request_t *r = data; + + ngx_http_upstream_t *u; + ngx_http_fastcgi_ctx_t *f; ngx_http_fastcgi_loc_conf_t *flcf; + u = r->upstream; + + f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module); flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module); - r->upstream->pipe->length = flcf->keep_conn ? - (off_t) sizeof(ngx_http_fastcgi_header_t) : -1; + u->pipe->length = flcf->keep_conn ? + (off_t) sizeof(ngx_http_fastcgi_header_t) : -1; + + if (u->headers_in.status_n == NGX_HTTP_NO_CONTENT + || u->headers_in.status_n == NGX_HTTP_NOT_MODIFIED) + { + f->rest = 0; + + } else if (r->method == NGX_HTTP_HEAD) { + f->rest = -2; + + } else { + f->rest = u->headers_in.content_length_n; + } return NGX_OK; } @@ -2106,6 +2127,15 @@ ngx_http_fastcgi_input_filter(ngx_event_pipe_t *p, ngx_buf_t *buf) f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module); flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module); + if (p->upstream_done || f->closed) { + r->upstream->keepalive = 0; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, p->log, 0, + "http fastcgi data after close"); + + return NGX_OK; + } + b = NULL; prev = &buf->shadow; @@ -2128,13 +2158,25 @@ ngx_http_fastcgi_input_filter(ngx_event_pipe_t *p, ngx_buf_t *buf) if (f->type == NGX_HTTP_FASTCGI_STDOUT && f->length == 0) { f->state = ngx_http_fastcgi_st_padding; + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, p->log, 0, + "http fastcgi closed stdout"); + + if (f->rest > 0) { + ngx_log_error(NGX_LOG_ERR, p->log, 0, + "upstream prematurely closed " + "FastCGI stdout"); + + p->upstream_error = 1; + p->upstream_eof = 0; + f->closed = 1; + + break; + } + if (!flcf->keep_conn) { p->upstream_done = 1; } - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, p->log, 0, - "http fastcgi closed stdout"); - continue; } @@ -2143,6 +2185,18 @@ ngx_http_fastcgi_input_filter(ngx_event_pipe_t *p, ngx_buf_t *buf) ngx_log_debug0(NGX_LOG_DEBUG_HTTP, p->log, 0, "http fastcgi sent end request"); + if (f->rest > 0) { + ngx_log_error(NGX_LOG_ERR, p->log, 0, + "upstream prematurely closed " + "FastCGI request"); + + p->upstream_error = 1; + p->upstream_eof = 0; + f->closed = 1; + + break; + } + if (!flcf->keep_conn) { p->upstream_done = 1; break; @@ -2252,6 +2306,18 @@ ngx_http_fastcgi_input_filter(ngx_event_pipe_t *p, ngx_buf_t *buf) break; } + if (f->rest == -2) { + f->rest = r->upstream->headers_in.content_length_n; + } + + if (f->rest == 0) { + ngx_log_error(NGX_LOG_WARN, p->log, 0, + "upstream sent more data than specified in " + "\"Content-Length\" header"); + p->upstream_done = 1; + break; + } + cl = ngx_chain_get_free_buf(p->pool, &p->free); if (cl == NULL) { return NGX_ERROR; @@ -2289,15 +2355,27 @@ ngx_http_fastcgi_input_filter(ngx_event_pipe_t *p, ngx_buf_t *buf) f->pos += f->length; b->last = f->pos; - continue; + } else { + f->length -= f->last - f->pos; + f->pos = f->last; + b->last = f->last; } - f->length -= f->last - f->pos; + if (f->rest > 0) { - b->last = f->last; + if (b->last - b->pos > f->rest) { + ngx_log_error(NGX_LOG_WARN, p->log, 0, + "upstream sent more data than specified in " + "\"Content-Length\" header"); - break; + b->last = b->pos + f->rest; + p->upstream_done = 1; + break; + } + + f->rest -= b->last - b->pos; + } } if (flcf->keep_conn) { @@ -2391,6 +2469,14 @@ ngx_http_fastcgi_non_buffered_filter(void *data, ssize_t bytes) if (f->type == NGX_HTTP_FASTCGI_END_REQUEST) { + if (f->rest > 0) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "upstream prematurely closed " + "FastCGI request"); + u->error = 1; + break; + } + if (f->pos + f->padding < f->last) { u->length = 0; break; @@ -2486,6 +2572,14 @@ ngx_http_fastcgi_non_buffered_filter(void *data, ssize_t bytes) break; } + if (f->rest == 0) { + ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, + "upstream sent more data than specified in " + "\"Content-Length\" header"); + u->length = 0; + break; + } + cl = ngx_chain_get_free_buf(r->pool, &u->free_bufs); if (cl == NULL) { return NGX_ERROR; @@ -2510,13 +2604,27 @@ ngx_http_fastcgi_non_buffered_filter(void *data, ssize_t bytes) f->pos += f->length; b->last = f->pos; - continue; + } else { + f->length -= f->last - f->pos; + f->pos = f->last; + b->last = f->last; } - f->length -= f->last - f->pos; - b->last = f->last; + if (f->rest > 0) { - break; + if (b->last - b->pos > f->rest) { + ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, + "upstream sent more data than specified in " + "\"Content-Length\" header"); + + b->last = b->pos + f->rest; + u->length = 0; + + break; + } + + f->rest -= b->last - b->pos; + } } return NGX_OK; diff --git a/src/http/modules/ngx_http_flv_module.c b/src/http/modules/ngx_http_flv_module.c index 7b72fae..cc06d53 100644 --- a/src/http/modules/ngx_http_flv_module.c +++ b/src/http/modules/ngx_http_flv_module.c @@ -156,12 +156,6 @@ ngx_http_flv_handler(ngx_http_request_t *r) } if (!of.is_file) { - - if (ngx_close_file(of.fd) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, - ngx_close_file_n " \"%s\" failed", path.data); - } - return NGX_DECLINED; } diff --git a/src/http/modules/ngx_http_grpc_module.c b/src/http/modules/ngx_http_grpc_module.c index d4af66d..27a36e8 100644 --- a/src/http/modules/ngx_http_grpc_module.c +++ b/src/http/modules/ngx_http_grpc_module.c @@ -40,6 +40,7 @@ typedef struct { ngx_str_t ssl_certificate; ngx_str_t ssl_certificate_key; ngx_array_t *ssl_passwords; + ngx_array_t *ssl_conf_commands; #endif } ngx_http_grpc_loc_conf_t; @@ -84,6 +85,8 @@ typedef struct { ngx_uint_t pings; ngx_uint_t settings; + off_t length; + ssize_t send_window; size_t recv_window; @@ -120,6 +123,8 @@ typedef struct { unsigned end_stream:1; unsigned done:1; unsigned status:1; + unsigned rst:1; + unsigned goaway:1; ngx_http_request_t *request; @@ -205,6 +210,8 @@ static char *ngx_http_grpc_pass(ngx_conf_t *cf, ngx_command_t *cmd, #if (NGX_HTTP_SSL) static char *ngx_http_grpc_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static char *ngx_http_grpc_ssl_conf_command_check(ngx_conf_t *cf, void *post, + void *data); static ngx_int_t ngx_http_grpc_set_ssl(ngx_conf_t *cf, ngx_http_grpc_loc_conf_t *glcf); #endif @@ -239,6 +246,9 @@ static ngx_conf_bitmask_t ngx_http_grpc_ssl_protocols[] = { { ngx_null_string, 0 } }; +static ngx_conf_post_t ngx_http_grpc_ssl_conf_command_post = + { ngx_http_grpc_ssl_conf_command_check }; + #endif @@ -435,6 +445,13 @@ static ngx_command_t ngx_http_grpc_commands[] = { 0, NULL }, + { ngx_string("grpc_ssl_conf_command"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2, + ngx_conf_set_keyval_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_grpc_loc_conf_t, ssl_conf_commands), + &ngx_http_grpc_ssl_conf_command_post }, + #endif ngx_null_command @@ -1125,20 +1142,11 @@ ngx_http_grpc_create_request(ngx_http_request_t *r) f->flags |= NGX_HTTP_V2_END_HEADERS_FLAG; -#if (NGX_DEBUG) - if (r->connection->log->log_level & NGX_LOG_DEBUG_HTTP) { - u_char buf[512]; - size_t n, m; - - n = ngx_min(b->last - b->pos, 256); - m = ngx_hex_dump(buf, b->pos, n) - buf; - - ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "grpc header: %*s%s, len: %uz", - m, buf, b->last - b->pos > 256 ? "..." : "", - b->last - b->pos); - } -#endif + ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "grpc header: %*xs%s, len: %uz", + (size_t) ngx_min(b->last - b->pos, 256), b->pos, + b->last - b->pos > 256 ? "..." : "", + b->last - b->pos); if (r->request_body_no_buffering) { @@ -1205,6 +1213,8 @@ ngx_http_grpc_reinit_request(ngx_http_request_t *r) ctx->end_stream = 0; ctx->done = 0; ctx->status = 0; + ctx->rst = 0; + ctx->goaway = 0; ctx->connection = NULL; return NGX_OK; @@ -1560,6 +1570,7 @@ ngx_http_grpc_body_output_filter(void *data, ngx_chain_t *in) && ctx->out == NULL && ctx->output_closed && !ctx->output_blocked + && !ctx->goaway && ctx->state == ngx_http_grpc_st_start) { u->keepalive = 1; @@ -1587,20 +1598,11 @@ ngx_http_grpc_process_header(ngx_http_request_t *r) u = r->upstream; b = &u->buffer; -#if (NGX_DEBUG) - if (r->connection->log->log_level & NGX_LOG_DEBUG_HTTP) { - u_char buf[512]; - size_t n, m; - - n = ngx_min(b->last - b->pos, 256); - m = ngx_hex_dump(buf, b->pos, n) - buf; - - ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "grpc response: %*s%s, len: %uz", - m, buf, b->last - b->pos > 256 ? "..." : "", - b->last - b->pos); - } -#endif + ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "grpc response: %*xs%s, len: %uz", + (size_t) ngx_min(b->last - b->pos, 256), + b->pos, b->last - b->pos > 256 ? "..." : "", + b->last - b->pos); ctx = ngx_http_grpc_get_ctx(r); @@ -1718,6 +1720,8 @@ ngx_http_grpc_process_header(ngx_http_request_t *r) return NGX_HTTP_UPSTREAM_INVALID_HEADER; } + ctx->goaway = 1; + continue; } @@ -1911,6 +1915,7 @@ ngx_http_grpc_process_header(ngx_http_request_t *r) && ctx->out == NULL && ctx->output_closed && !ctx->output_blocked + && !ctx->goaway && b->last == b->pos) { u->keepalive = 1; @@ -1951,10 +1956,29 @@ ngx_http_grpc_filter_init(void *data) r = ctx->request; u = r->upstream; - u->length = 1; + if (u->headers_in.status_n == NGX_HTTP_NO_CONTENT + || u->headers_in.status_n == NGX_HTTP_NOT_MODIFIED + || r->method == NGX_HTTP_HEAD) + { + ctx->length = 0; + + } else { + ctx->length = u->headers_in.content_length_n; + } if (ctx->end_stream) { + + if (ctx->length > 0) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "upstream prematurely closed stream"); + return NGX_ERROR; + } + u->length = 0; + ctx->done = 1; + + } else { + u->length = 1; } return NGX_OK; @@ -1997,6 +2021,12 @@ ngx_http_grpc_filter(void *data, ssize_t bytes) if (ctx->done) { + if (ctx->length > 0) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "upstream prematurely closed stream"); + return NGX_ERROR; + } + /* * We have finished parsing the response and the * remaining control frames. If there are unsent @@ -2014,6 +2044,7 @@ ngx_http_grpc_filter(void *data, ssize_t bytes) if (ctx->in == NULL && ctx->output_closed && !ctx->output_blocked + && !ctx->goaway && ctx->state == ngx_http_grpc_st_start) { u->keepalive = 1; @@ -2088,7 +2119,10 @@ ngx_http_grpc_filter(void *data, ssize_t bytes) return NGX_ERROR; } - if (ctx->stream_id && ctx->done) { + if (ctx->stream_id && ctx->done + && ctx->type != NGX_HTTP_V2_RST_STREAM_FRAME + && ctx->type != NGX_HTTP_V2_WINDOW_UPDATE_FRAME) + { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "upstream sent frame for closed stream %ui", ctx->stream_id); @@ -2131,11 +2165,21 @@ ngx_http_grpc_filter(void *data, ssize_t bytes) return NGX_ERROR; } - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "upstream rejected request with error %ui", - ctx->error); + if (ctx->error || !ctx->done) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "upstream rejected request with error %ui", + ctx->error); + return NGX_ERROR; + } - return NGX_ERROR; + if (ctx->rst) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "upstream sent frame for closed stream %ui", + ctx->stream_id); + return NGX_ERROR; + } + + ctx->rst = 1; } if (ctx->type == NGX_HTTP_V2_GOAWAY_FRAME) { @@ -2170,6 +2214,8 @@ ngx_http_grpc_filter(void *data, ssize_t bytes) return NGX_ERROR; } + ctx->goaway = 1; + continue; } @@ -2402,6 +2448,18 @@ ngx_http_grpc_filter(void *data, ssize_t bytes) b->pos = b->last; buf->last = b->pos; + if (ctx->length != -1) { + + if (buf->last - buf->pos > ctx->length) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "upstream sent response body larger " + "than indicated content length"); + return NGX_ERROR; + } + + ctx->length -= buf->last - buf->pos; + } + return NGX_AGAIN; } @@ -2409,6 +2467,18 @@ ngx_http_grpc_filter(void *data, ssize_t bytes) buf->last = b->pos; ctx->rest = ctx->padding; + if (ctx->length != -1) { + + if (buf->last - buf->pos > ctx->length) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "upstream sent response body larger " + "than indicated content length"); + return NGX_ERROR; + } + + ctx->length -= buf->last - buf->pos; + } + done: if (ctx->padding) { @@ -4272,7 +4342,6 @@ ngx_http_grpc_create_loc_conf(ngx_conf_t *cf) * conf->upstream.hide_headers_hash = { NULL, 0 }; * conf->upstream.ssl_name = NULL; * - * conf->headers_source = NULL; * conf->headers.lengths = NULL; * conf->headers.values = NULL; * conf->headers.hash = { NULL, 0 }; @@ -4308,6 +4377,7 @@ ngx_http_grpc_create_loc_conf(ngx_conf_t *cf) conf->upstream.ssl_verify = NGX_CONF_UNSET; conf->ssl_verify_depth = NGX_CONF_UNSET_UINT; conf->ssl_passwords = NGX_CONF_UNSET_PTR; + conf->ssl_conf_commands = NGX_CONF_UNSET_PTR; #endif /* the hardcoded values */ @@ -4325,6 +4395,8 @@ ngx_http_grpc_create_loc_conf(ngx_conf_t *cf) conf->upstream.pass_trailers = 1; conf->upstream.preserve_output = 1; + conf->headers_source = NGX_CONF_UNSET_PTR; + ngx_str_set(&conf->upstream.module, "grpc"); return conf; @@ -4416,6 +4488,9 @@ ngx_http_grpc_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) prev->ssl_certificate_key, ""); ngx_conf_merge_ptr_value(conf->ssl_passwords, prev->ssl_passwords, NULL); + ngx_conf_merge_ptr_value(conf->ssl_conf_commands, + prev->ssl_conf_commands, NULL); + if (conf->ssl && ngx_http_grpc_set_ssl(cf, conf) != NGX_OK) { return NGX_CONF_ERROR; } @@ -4455,9 +4530,10 @@ ngx_http_grpc_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) clcf->handler = ngx_http_grpc_handler; } - if (conf->headers_source == NULL) { + ngx_conf_merge_ptr_value(conf->headers_source, prev->headers_source, NULL); + + if (conf->headers_source == prev->headers_source) { conf->headers = prev->headers; - conf->headers_source = prev->headers_source; conf->host_set = prev->host_set; } @@ -4782,6 +4858,17 @@ ngx_http_grpc_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } +static char * +ngx_http_grpc_ssl_conf_command_check(ngx_conf_t *cf, void *post, void *data) +{ +#ifndef SSL_CONF_FLAG_FILE + return "is not supported on this platform"; +#else + return NGX_CONF_OK; +#endif +} + + static ngx_int_t ngx_http_grpc_set_ssl(ngx_conf_t *cf, ngx_http_grpc_loc_conf_t *glcf) { @@ -4872,6 +4959,12 @@ ngx_http_grpc_set_ssl(ngx_conf_t *cf, ngx_http_grpc_loc_conf_t *glcf) #endif + if (ngx_ssl_conf_commands(cf, glcf->upstream.ssl, glcf->ssl_conf_commands) + != NGX_OK) + { + return NGX_ERROR; + } + return NGX_OK; } diff --git a/src/http/modules/ngx_http_gzip_filter_module.c b/src/http/modules/ngx_http_gzip_filter_module.c index c75169c..b8c5ccc 100644 --- a/src/http/modules/ngx_http_gzip_filter_module.c +++ b/src/http/modules/ngx_http_gzip_filter_module.c @@ -56,7 +56,7 @@ typedef struct { unsigned done:1; unsigned nomem:1; unsigned buffering:1; - unsigned intel:1; + unsigned zlib_ng:1; size_t zin; size_t zout; @@ -213,7 +213,7 @@ static ngx_str_t ngx_http_gzip_ratio = ngx_string("gzip_ratio"); static ngx_http_output_header_filter_pt ngx_http_next_header_filter; static ngx_http_output_body_filter_pt ngx_http_next_body_filter; -static ngx_uint_t ngx_http_gzip_assume_intel; +static ngx_uint_t ngx_http_gzip_assume_zlib_ng; static ngx_int_t @@ -501,18 +501,21 @@ ngx_http_gzip_filter_memory(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx) * 8K is for zlib deflate_state, it takes * *) 5816 bytes on i386 and sparc64 (32-bit mode) * *) 5920 bytes on amd64 and sparc64 + * + * A zlib variant from Intel (https://github.com/jtkukunas/zlib) + * uses additional 16-byte padding in one of window-sized buffers. */ - if (!ngx_http_gzip_assume_intel) { - ctx->allocated = 8192 + (1 << (wbits + 2)) + (1 << (memlevel + 9)); + if (!ngx_http_gzip_assume_zlib_ng) { + ctx->allocated = 8192 + 16 + (1 << (wbits + 2)) + + (1 << (memlevel + 9)); } else { /* - * A zlib variant from Intel, https://github.com/jtkukunas/zlib. - * It can force window bits to 13 for fast compression level, - * on processors with SSE 4.2 it uses 64K hash instead of scaling - * it from the specified memory level, and also introduces - * 16-byte padding in one out of the two window-sized buffers. + * Another zlib variant, https://github.com/zlib-ng/zlib-ng. + * It forces window bits to 13 for fast compression level, + * uses 16-byte padding in one of window-sized buffers, and + * uses 128K hash. */ if (conf->level == 1) { @@ -520,9 +523,8 @@ ngx_http_gzip_filter_memory(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx) } ctx->allocated = 8192 + 16 + (1 << (wbits + 2)) - + (1 << (ngx_max(memlevel, 8) + 8)) - + (1 << (memlevel + 8)); - ctx->intel = 1; + + 131072 + (1 << (memlevel + 8)); + ctx->zlib_ng = 1; } } @@ -945,13 +947,13 @@ ngx_http_gzip_filter_alloc(void *opaque, u_int items, u_int size) return p; } - if (ctx->intel) { + if (ctx->zlib_ng) { ngx_log_error(NGX_LOG_ALERT, ctx->request->connection->log, 0, "gzip filter failed to use preallocated memory: " "%ud of %ui", items * size, ctx->allocated); } else { - ngx_http_gzip_assume_intel = 1; + ngx_http_gzip_assume_zlib_ng = 1; } p = ngx_palloc(ctx->request->pool, items * size); diff --git a/src/http/modules/ngx_http_limit_req_module.c b/src/http/modules/ngx_http_limit_req_module.c index 6bd3e6a..2b062a3 100644 --- a/src/http/modules/ngx_http_limit_req_module.c +++ b/src/http/modules/ngx_http_limit_req_module.c @@ -69,6 +69,8 @@ static ngx_int_t ngx_http_limit_req_lookup(ngx_http_limit_req_limit_t *limit, ngx_uint_t hash, ngx_str_t *key, ngx_uint_t *ep, ngx_uint_t account); static ngx_msec_t ngx_http_limit_req_account(ngx_http_limit_req_limit_t *limits, ngx_uint_t n, ngx_uint_t *ep, ngx_http_limit_req_limit_t **limit); +static void ngx_http_limit_req_unlock(ngx_http_limit_req_limit_t *limits, + ngx_uint_t n); static void ngx_http_limit_req_expire(ngx_http_limit_req_ctx_t *ctx, ngx_uint_t n); @@ -223,6 +225,7 @@ ngx_http_limit_req_handler(ngx_http_request_t *r) ctx = limit->shm_zone->data; if (ngx_http_complex_value(r, &ctx->key, &key) != NGX_OK) { + ngx_http_limit_req_unlock(limits, n); return NGX_HTTP_INTERNAL_SERVER_ERROR; } @@ -270,21 +273,7 @@ ngx_http_limit_req_handler(ngx_http_request_t *r) &limit->shm_zone->shm.name); } - while (n--) { - ctx = limits[n].shm_zone->data; - - if (ctx->node == NULL) { - continue; - } - - ngx_shmtx_lock(&ctx->shpool->mutex); - - ctx->node->count--; - - ngx_shmtx_unlock(&ctx->shpool->mutex); - - ctx->node = NULL; - } + ngx_http_limit_req_unlock(limits, n); if (lrcf->dry_run) { r->main->limit_req_status = NGX_HTTP_LIMIT_REQ_REJECTED_DRY_RUN; @@ -321,8 +310,13 @@ ngx_http_limit_req_handler(ngx_http_request_t *r) r->main->limit_req_status = NGX_HTTP_LIMIT_REQ_DELAYED; - if (ngx_handle_read_event(r->connection->read, 0) != NGX_OK) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; + if (r->connection->read->ready) { + ngx_post_event(r->connection->read, &ngx_posted_events); + + } else { + if (ngx_handle_read_event(r->connection->read, 0) != NGX_OK) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } } r->read_event_handler = ngx_http_test_reading; @@ -612,6 +606,29 @@ ngx_http_limit_req_account(ngx_http_limit_req_limit_t *limits, ngx_uint_t n, } +static void +ngx_http_limit_req_unlock(ngx_http_limit_req_limit_t *limits, ngx_uint_t n) +{ + ngx_http_limit_req_ctx_t *ctx; + + while (n--) { + ctx = limits[n].shm_zone->data; + + if (ctx->node == NULL) { + continue; + } + + ngx_shmtx_lock(&ctx->shpool->mutex); + + ctx->node->count--; + + ngx_shmtx_unlock(&ctx->shpool->mutex); + + ctx->node = NULL; + } +} + + static void ngx_http_limit_req_expire(ngx_http_limit_req_ctx_t *ctx, ngx_uint_t n) { diff --git a/src/http/modules/ngx_http_memcached_module.c b/src/http/modules/ngx_http_memcached_module.c index 775bd7e..c82df6e 100644 --- a/src/http/modules/ngx_http_memcached_module.c +++ b/src/http/modules/ngx_http_memcached_module.c @@ -485,10 +485,11 @@ ngx_http_memcached_filter(void *data, ssize_t bytes) if (u->length == (ssize_t) ctx->rest) { - if (ngx_strncmp(b->last, + if (bytes > u->length + || ngx_strncmp(b->last, ngx_http_memcached_end + NGX_HTTP_MEMCACHED_END - ctx->rest, bytes) - != 0) + != 0) { ngx_log_error(NGX_LOG_ERR, ctx->request->connection->log, 0, "memcached sent invalid trailer"); @@ -540,7 +541,9 @@ ngx_http_memcached_filter(void *data, ssize_t bytes) last += (size_t) (u->length - NGX_HTTP_MEMCACHED_END); - if (ngx_strncmp(last, ngx_http_memcached_end, b->last - last) != 0) { + if (bytes > u->length + || ngx_strncmp(last, ngx_http_memcached_end, b->last - last) != 0) + { ngx_log_error(NGX_LOG_ERR, ctx->request->connection->log, 0, "memcached sent invalid trailer"); diff --git a/src/http/modules/ngx_http_mp4_module.c b/src/http/modules/ngx_http_mp4_module.c index c1006ab..0e93fbd 100644 --- a/src/http/modules/ngx_http_mp4_module.c +++ b/src/http/modules/ngx_http_mp4_module.c @@ -521,12 +521,6 @@ ngx_http_mp4_handler(ngx_http_request_t *r) } if (!of.is_file) { - - if (ngx_close_file(of.fd) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, - ngx_close_file_n " \"%s\" failed", path.data); - } - return NGX_DECLINED; } diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c index 3aafb99..a63c3ed 100644 --- a/src/http/modules/ngx_http_proxy_module.c +++ b/src/http/modules/ngx_http_proxy_module.c @@ -10,6 +10,19 @@ #include +#define NGX_HTTP_PROXY_COOKIE_SECURE 0x0001 +#define NGX_HTTP_PROXY_COOKIE_SECURE_ON 0x0002 +#define NGX_HTTP_PROXY_COOKIE_SECURE_OFF 0x0004 +#define NGX_HTTP_PROXY_COOKIE_HTTPONLY 0x0008 +#define NGX_HTTP_PROXY_COOKIE_HTTPONLY_ON 0x0010 +#define NGX_HTTP_PROXY_COOKIE_HTTPONLY_OFF 0x0020 +#define NGX_HTTP_PROXY_COOKIE_SAMESITE 0x0040 +#define NGX_HTTP_PROXY_COOKIE_SAMESITE_STRICT 0x0080 +#define NGX_HTTP_PROXY_COOKIE_SAMESITE_LAX 0x0100 +#define NGX_HTTP_PROXY_COOKIE_SAMESITE_NONE 0x0200 +#define NGX_HTTP_PROXY_COOKIE_SAMESITE_OFF 0x0400 + + typedef struct { ngx_array_t caches; /* ngx_http_file_cache_t * */ } ngx_http_proxy_main_conf_t; @@ -18,7 +31,7 @@ typedef struct { typedef struct ngx_http_proxy_rewrite_s ngx_http_proxy_rewrite_t; typedef ngx_int_t (*ngx_http_proxy_rewrite_pt)(ngx_http_request_t *r, - ngx_table_elt_t *h, size_t prefix, size_t len, + ngx_str_t *value, size_t prefix, size_t len, ngx_http_proxy_rewrite_t *pr); struct ngx_http_proxy_rewrite_s { @@ -35,6 +48,19 @@ struct ngx_http_proxy_rewrite_s { }; +typedef struct { + union { + ngx_http_complex_value_t complex; +#if (NGX_PCRE) + ngx_http_regex_t *regex; +#endif + } cookie; + + ngx_array_t flags_values; + ngx_uint_t regex; +} ngx_http_proxy_cookie_flags_t; + + typedef struct { ngx_str_t key_start; ngx_str_t schema; @@ -72,6 +98,7 @@ typedef struct { ngx_array_t *redirects; ngx_array_t *cookie_domains; ngx_array_t *cookie_paths; + ngx_array_t *cookie_flags; ngx_http_complex_value_t *method; ngx_str_t location; @@ -100,6 +127,7 @@ typedef struct { ngx_str_t ssl_certificate; ngx_str_t ssl_certificate_key; ngx_array_t *ssl_passwords; + ngx_array_t *ssl_conf_commands; #endif } ngx_http_proxy_loc_conf_t; @@ -158,10 +186,16 @@ static ngx_int_t ngx_http_proxy_rewrite_redirect(ngx_http_request_t *r, ngx_table_elt_t *h, size_t prefix); static ngx_int_t ngx_http_proxy_rewrite_cookie(ngx_http_request_t *r, ngx_table_elt_t *h); +static ngx_int_t ngx_http_proxy_parse_cookie(ngx_str_t *value, + ngx_array_t *attrs); static ngx_int_t ngx_http_proxy_rewrite_cookie_value(ngx_http_request_t *r, - ngx_table_elt_t *h, u_char *value, ngx_array_t *rewrites); + ngx_str_t *value, ngx_array_t *rewrites); +static ngx_int_t ngx_http_proxy_rewrite_cookie_flags(ngx_http_request_t *r, + ngx_array_t *attrs, ngx_array_t *flags); +static ngx_int_t ngx_http_proxy_edit_cookie_flags(ngx_http_request_t *r, + ngx_array_t *attrs, ngx_uint_t flags); static ngx_int_t ngx_http_proxy_rewrite(ngx_http_request_t *r, - ngx_table_elt_t *h, size_t prefix, size_t len, ngx_str_t *replacement); + ngx_str_t *value, size_t prefix, size_t len, ngx_str_t *replacement); static ngx_int_t ngx_http_proxy_add_variables(ngx_conf_t *cf); static void *ngx_http_proxy_create_main_conf(ngx_conf_t *cf); @@ -180,6 +214,8 @@ static char *ngx_http_proxy_cookie_domain(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static char *ngx_http_proxy_cookie_path(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static char *ngx_http_proxy_cookie_flags(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); static char *ngx_http_proxy_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); #if (NGX_HTTP_CACHE) @@ -194,6 +230,10 @@ static char *ngx_http_proxy_ssl_password_file(ngx_conf_t *cf, #endif static char *ngx_http_proxy_lowat_check(ngx_conf_t *cf, void *post, void *data); +#if (NGX_HTTP_SSL) +static char *ngx_http_proxy_ssl_conf_command_check(ngx_conf_t *cf, void *post, + void *data); +#endif static ngx_int_t ngx_http_proxy_rewrite_regex(ngx_conf_t *cf, ngx_http_proxy_rewrite_t *pr, ngx_str_t *regex, ngx_uint_t caseless); @@ -239,6 +279,9 @@ static ngx_conf_bitmask_t ngx_http_proxy_ssl_protocols[] = { { ngx_null_string, 0 } }; +static ngx_conf_post_t ngx_http_proxy_ssl_conf_command_post = + { ngx_http_proxy_ssl_conf_command_check }; + #endif @@ -282,6 +325,13 @@ static ngx_command_t ngx_http_proxy_commands[] = { 0, NULL }, + { ngx_string("proxy_cookie_flags"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234, + ngx_http_proxy_cookie_flags, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + { ngx_string("proxy_store"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_http_proxy_store, @@ -722,6 +772,13 @@ static ngx_command_t ngx_http_proxy_commands[] = { 0, NULL }, + { ngx_string("proxy_ssl_conf_command"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2, + ngx_conf_set_keyval_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_proxy_loc_conf_t, ssl_conf_commands), + &ngx_http_proxy_ssl_conf_command_post }, + #endif ngx_null_command @@ -845,6 +902,36 @@ static ngx_path_init_t ngx_http_proxy_temp_path = { }; +static ngx_conf_bitmask_t ngx_http_proxy_cookie_flags_masks[] = { + + { ngx_string("secure"), + NGX_HTTP_PROXY_COOKIE_SECURE|NGX_HTTP_PROXY_COOKIE_SECURE_ON }, + + { ngx_string("nosecure"), + NGX_HTTP_PROXY_COOKIE_SECURE|NGX_HTTP_PROXY_COOKIE_SECURE_OFF }, + + { ngx_string("httponly"), + NGX_HTTP_PROXY_COOKIE_HTTPONLY|NGX_HTTP_PROXY_COOKIE_HTTPONLY_ON }, + + { ngx_string("nohttponly"), + NGX_HTTP_PROXY_COOKIE_HTTPONLY|NGX_HTTP_PROXY_COOKIE_HTTPONLY_OFF }, + + { ngx_string("samesite=strict"), + NGX_HTTP_PROXY_COOKIE_SAMESITE|NGX_HTTP_PROXY_COOKIE_SAMESITE_STRICT }, + + { ngx_string("samesite=lax"), + NGX_HTTP_PROXY_COOKIE_SAMESITE|NGX_HTTP_PROXY_COOKIE_SAMESITE_LAX }, + + { ngx_string("samesite=none"), + NGX_HTTP_PROXY_COOKIE_SAMESITE|NGX_HTTP_PROXY_COOKIE_SAMESITE_NONE }, + + { ngx_string("nosamesite"), + NGX_HTTP_PROXY_COOKIE_SAMESITE|NGX_HTTP_PROXY_COOKIE_SAMESITE_OFF }, + + { ngx_null_string, 0 } +}; + + static ngx_int_t ngx_http_proxy_handler(ngx_http_request_t *r) { @@ -906,7 +993,7 @@ ngx_http_proxy_handler(ngx_http_request_t *r) u->rewrite_redirect = ngx_http_proxy_rewrite_redirect; } - if (plcf->cookie_domains || plcf->cookie_paths) { + if (plcf->cookie_domains || plcf->cookie_paths || plcf->cookie_flags) { u->rewrite_cookie = ngx_http_proxy_rewrite_cookie; } @@ -2015,6 +2102,25 @@ ngx_http_proxy_copy_filter(ngx_event_pipe_t *p, ngx_buf_t *buf) return NGX_OK; } + if (p->upstream_done) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, p->log, 0, + "http proxy data after close"); + return NGX_OK; + } + + if (p->length == 0) { + + ngx_log_error(NGX_LOG_WARN, p->log, 0, + "upstream sent more data than specified in " + "\"Content-Length\" header"); + + r = p->input_ctx; + r->upstream->keepalive = 0; + p->upstream_done = 1; + + return NGX_OK; + } + cl = ngx_chain_get_free_buf(p->pool, &p->free); if (cl == NULL) { return NGX_ERROR; @@ -2042,20 +2148,23 @@ ngx_http_proxy_copy_filter(ngx_event_pipe_t *p, ngx_buf_t *buf) return NGX_OK; } + if (b->last - b->pos > p->length) { + + ngx_log_error(NGX_LOG_WARN, p->log, 0, + "upstream sent more data than specified in " + "\"Content-Length\" header"); + + b->last = b->pos + p->length; + p->upstream_done = 1; + + return NGX_OK; + } + p->length -= b->last - b->pos; if (p->length == 0) { r = p->input_ctx; - p->upstream_done = 1; r->upstream->keepalive = !r->upstream->headers_in.connection_close; - - } else if (p->length < 0) { - r = p->input_ctx; - p->upstream_done = 1; - - ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, - "upstream sent more data than specified in " - "\"Content-Length\" header"); } return NGX_OK; @@ -2082,6 +2191,23 @@ ngx_http_proxy_chunked_filter(ngx_event_pipe_t *p, ngx_buf_t *buf) return NGX_ERROR; } + if (p->upstream_done) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, p->log, 0, + "http proxy data after close"); + return NGX_OK; + } + + if (p->length == 0) { + + ngx_log_error(NGX_LOG_WARN, p->log, 0, + "upstream sent data after final chunk"); + + r->upstream->keepalive = 0; + p->upstream_done = 1; + + return NGX_OK; + } + b = NULL; prev = &buf->shadow; @@ -2144,9 +2270,15 @@ ngx_http_proxy_chunked_filter(ngx_event_pipe_t *p, ngx_buf_t *buf) /* a whole response has been parsed successfully */ - p->upstream_done = 1; + p->length = 0; r->upstream->keepalive = !r->upstream->headers_in.connection_close; + if (buf->pos != buf->last) { + ngx_log_error(NGX_LOG_WARN, p->log, 0, + "upstream sent data after final chunk"); + r->upstream->keepalive = 0; + } + break; } @@ -2161,13 +2293,13 @@ ngx_http_proxy_chunked_filter(ngx_event_pipe_t *p, ngx_buf_t *buf) /* invalid response */ - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + ngx_log_error(NGX_LOG_ERR, p->log, 0, "upstream sent invalid chunked response"); return NGX_ERROR; } - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, p->log, 0, "http proxy chunked state %ui, length %O", ctx->chunked.state, p->length); @@ -2202,6 +2334,13 @@ ngx_http_proxy_non_buffered_copy_filter(void *data, ssize_t bytes) u = r->upstream; + if (u->length == 0) { + ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, + "upstream sent more data than specified in " + "\"Content-Length\" header"); + return NGX_OK; + } + for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) { ll = &cl->next; } @@ -2227,6 +2366,18 @@ ngx_http_proxy_non_buffered_copy_filter(void *data, ssize_t bytes) return NGX_OK; } + if (bytes > u->length) { + + ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, + "upstream sent more data than specified in " + "\"Content-Length\" header"); + + cl->buf->last = cl->buf->pos + u->length; + u->length = 0; + + return NGX_OK; + } + u->length -= bytes; if (u->length == 0) { @@ -2313,6 +2464,12 @@ ngx_http_proxy_non_buffered_chunked_filter(void *data, ssize_t bytes) u->keepalive = !u->headers_in.connection_close; u->length = 0; + if (buf->pos != buf->last) { + ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, + "upstream sent data after final chunk"); + u->keepalive = 0; + } + break; } @@ -2521,7 +2678,7 @@ ngx_http_proxy_rewrite_redirect(ngx_http_request_t *r, ngx_table_elt_t *h, len = h->value.len - prefix; for (i = 0; i < plcf->redirects->nelts; i++) { - rc = pr[i].handler(r, h, prefix, len, &pr[i]); + rc = pr[i].handler(r, &h->value, prefix, len, &pr[i]); if (rc != NGX_DECLINED) { return rc; @@ -2535,27 +2692,43 @@ ngx_http_proxy_rewrite_redirect(ngx_http_request_t *r, ngx_table_elt_t *h, static ngx_int_t ngx_http_proxy_rewrite_cookie(ngx_http_request_t *r, ngx_table_elt_t *h) { - size_t prefix; u_char *p; + size_t len; ngx_int_t rc, rv; + ngx_str_t *key, *value; + ngx_uint_t i; + ngx_array_t attrs; + ngx_keyval_t *attr; ngx_http_proxy_loc_conf_t *plcf; - p = (u_char *) ngx_strchr(h->value.data, ';'); - if (p == NULL) { - return NGX_DECLINED; + if (ngx_array_init(&attrs, r->pool, 2, sizeof(ngx_keyval_t)) != NGX_OK) { + return NGX_ERROR; } - prefix = p + 1 - h->value.data; + if (ngx_http_proxy_parse_cookie(&h->value, &attrs) != NGX_OK) { + return NGX_ERROR; + } + + attr = attrs.elts; + + if (attr[0].value.data == NULL) { + return NGX_DECLINED; + } rv = NGX_DECLINED; plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module); - if (plcf->cookie_domains) { - p = ngx_strcasestrn(h->value.data + prefix, "domain=", 7 - 1); + for (i = 1; i < attrs.nelts; i++) { - if (p) { - rc = ngx_http_proxy_rewrite_cookie_value(r, h, p + 7, + key = &attr[i].key; + value = &attr[i].value; + + if (plcf->cookie_domains && key->len == 6 + && ngx_strncasecmp(key->data, (u_char *) "domain", 6) == 0 + && value->data) + { + rc = ngx_http_proxy_rewrite_cookie_value(r, value, plcf->cookie_domains); if (rc == NGX_ERROR) { return NGX_ERROR; @@ -2565,13 +2738,12 @@ ngx_http_proxy_rewrite_cookie(ngx_http_request_t *r, ngx_table_elt_t *h) rv = rc; } } - } - if (plcf->cookie_paths) { - p = ngx_strcasestrn(h->value.data + prefix, "path=", 5 - 1); - - if (p) { - rc = ngx_http_proxy_rewrite_cookie_value(r, h, p + 5, + if (plcf->cookie_paths && key->len == 4 + && ngx_strncasecmp(key->data, (u_char *) "path", 4) == 0 + && value->data) + { + rc = ngx_http_proxy_rewrite_cookie_value(r, value, plcf->cookie_paths); if (rc == NGX_ERROR) { return NGX_ERROR; @@ -2583,30 +2755,153 @@ ngx_http_proxy_rewrite_cookie(ngx_http_request_t *r, ngx_table_elt_t *h) } } - return rv; + if (plcf->cookie_flags) { + rc = ngx_http_proxy_rewrite_cookie_flags(r, &attrs, + plcf->cookie_flags); + if (rc == NGX_ERROR) { + return NGX_ERROR; + } + + if (rc != NGX_DECLINED) { + rv = rc; + } + + attr = attrs.elts; + } + + if (rv != NGX_OK) { + return rv; + } + + len = 0; + + for (i = 0; i < attrs.nelts; i++) { + + if (attr[i].key.data == NULL) { + continue; + } + + if (i > 0) { + len += 2; + } + + len += attr[i].key.len; + + if (attr[i].value.data) { + len += 1 + attr[i].value.len; + } + } + + p = ngx_pnalloc(r->pool, len + 1); + if (p == NULL) { + return NGX_ERROR; + } + + h->value.data = p; + h->value.len = len; + + for (i = 0; i < attrs.nelts; i++) { + + if (attr[i].key.data == NULL) { + continue; + } + + if (i > 0) { + *p++ = ';'; + *p++ = ' '; + } + + p = ngx_cpymem(p, attr[i].key.data, attr[i].key.len); + + if (attr[i].value.data) { + *p++ = '='; + p = ngx_cpymem(p, attr[i].value.data, attr[i].value.len); + } + } + + *p = '\0'; + + return NGX_OK; } static ngx_int_t -ngx_http_proxy_rewrite_cookie_value(ngx_http_request_t *r, ngx_table_elt_t *h, - u_char *value, ngx_array_t *rewrites) +ngx_http_proxy_parse_cookie(ngx_str_t *value, ngx_array_t *attrs) +{ + u_char *start, *end, *p, *last; + ngx_str_t name, val; + ngx_keyval_t *attr; + + start = value->data; + end = value->data + value->len; + + for ( ;; ) { + + last = (u_char *) ngx_strchr(start, ';'); + + if (last == NULL) { + last = end; + } + + while (start < last && *start == ' ') { start++; } + + for (p = start; p < last && *p != '='; p++) { /* void */ } + + name.data = start; + name.len = p - start; + + while (name.len && name.data[name.len - 1] == ' ') { + name.len--; + } + + if (p < last) { + + p++; + + while (p < last && *p == ' ') { p++; } + + val.data = p; + val.len = last - val.data; + + while (val.len && val.data[val.len - 1] == ' ') { + val.len--; + } + + } else { + ngx_str_null(&val); + } + + attr = ngx_array_push(attrs); + if (attr == NULL) { + return NGX_ERROR; + } + + attr->key = name; + attr->value = val; + + if (last == end) { + break; + } + + start = last + 1; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_proxy_rewrite_cookie_value(ngx_http_request_t *r, ngx_str_t *value, + ngx_array_t *rewrites) { - size_t len, prefix; - u_char *p; ngx_int_t rc; ngx_uint_t i; ngx_http_proxy_rewrite_t *pr; - prefix = value - h->value.data; - - p = (u_char *) ngx_strchr(value, ';'); - - len = p ? (size_t) (p - value) : (h->value.len - prefix); - pr = rewrites->elts; for (i = 0; i < rewrites->nelts; i++) { - rc = pr[i].handler(r, h, prefix, len, &pr[i]); + rc = pr[i].handler(r, value, 0, value->len, &pr[i]); if (rc != NGX_DECLINED) { return rc; @@ -2618,8 +2913,236 @@ ngx_http_proxy_rewrite_cookie_value(ngx_http_request_t *r, ngx_table_elt_t *h, static ngx_int_t -ngx_http_proxy_rewrite_complex_handler(ngx_http_request_t *r, - ngx_table_elt_t *h, size_t prefix, size_t len, ngx_http_proxy_rewrite_t *pr) +ngx_http_proxy_rewrite_cookie_flags(ngx_http_request_t *r, ngx_array_t *attrs, + ngx_array_t *flags) +{ + ngx_str_t pattern, value; +#if (NGX_PCRE) + ngx_int_t rc; +#endif + ngx_uint_t i, m, f, nelts; + ngx_keyval_t *attr; + ngx_conf_bitmask_t *mask; + ngx_http_complex_value_t *flags_values; + ngx_http_proxy_cookie_flags_t *pcf; + + attr = attrs->elts; + pcf = flags->elts; + + for (i = 0; i < flags->nelts; i++) { + +#if (NGX_PCRE) + if (pcf[i].regex) { + rc = ngx_http_regex_exec(r, pcf[i].cookie.regex, &attr[0].key); + + if (rc == NGX_ERROR) { + return NGX_ERROR; + } + + if (rc == NGX_OK) { + break; + } + + /* NGX_DECLINED */ + + continue; + } +#endif + + if (ngx_http_complex_value(r, &pcf[i].cookie.complex, &pattern) + != NGX_OK) + { + return NGX_ERROR; + } + + if (pattern.len == attr[0].key.len + && ngx_strncasecmp(attr[0].key.data, pattern.data, pattern.len) + == 0) + { + break; + } + } + + if (i == flags->nelts) { + return NGX_DECLINED; + } + + nelts = pcf[i].flags_values.nelts; + flags_values = pcf[i].flags_values.elts; + + mask = ngx_http_proxy_cookie_flags_masks; + f = 0; + + for (i = 0; i < nelts; i++) { + + if (ngx_http_complex_value(r, &flags_values[i], &value) != NGX_OK) { + return NGX_ERROR; + } + + if (value.len == 0) { + continue; + } + + for (m = 0; mask[m].name.len != 0; m++) { + + if (mask[m].name.len != value.len + || ngx_strncasecmp(mask[m].name.data, value.data, value.len) + != 0) + { + continue; + } + + f |= mask[m].mask; + + break; + } + + if (mask[m].name.len == 0) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "invalid proxy_cookie_flags flag \"%V\"", &value); + } + } + + if (f == 0) { + return NGX_DECLINED; + } + + return ngx_http_proxy_edit_cookie_flags(r, attrs, f); +} + + +static ngx_int_t +ngx_http_proxy_edit_cookie_flags(ngx_http_request_t *r, ngx_array_t *attrs, + ngx_uint_t flags) +{ + ngx_str_t *key, *value; + ngx_uint_t i; + ngx_keyval_t *attr; + + attr = attrs->elts; + + for (i = 1; i < attrs->nelts; i++) { + key = &attr[i].key; + + if (key->len == 6 + && ngx_strncasecmp(key->data, (u_char *) "secure", 6) == 0) + { + if (flags & NGX_HTTP_PROXY_COOKIE_SECURE_ON) { + flags &= ~NGX_HTTP_PROXY_COOKIE_SECURE_ON; + + } else if (flags & NGX_HTTP_PROXY_COOKIE_SECURE_OFF) { + key->data = NULL; + } + + continue; + } + + if (key->len == 8 + && ngx_strncasecmp(key->data, (u_char *) "httponly", 8) == 0) + { + if (flags & NGX_HTTP_PROXY_COOKIE_HTTPONLY_ON) { + flags &= ~NGX_HTTP_PROXY_COOKIE_HTTPONLY_ON; + + } else if (flags & NGX_HTTP_PROXY_COOKIE_HTTPONLY_OFF) { + key->data = NULL; + } + + continue; + } + + if (key->len == 8 + && ngx_strncasecmp(key->data, (u_char *) "samesite", 8) == 0) + { + value = &attr[i].value; + + if (flags & NGX_HTTP_PROXY_COOKIE_SAMESITE_STRICT) { + flags &= ~NGX_HTTP_PROXY_COOKIE_SAMESITE_STRICT; + + if (value->len != 6 + || ngx_strncasecmp(value->data, (u_char *) "strict", 6) + != 0) + { + ngx_str_set(key, "SameSite"); + ngx_str_set(value, "Strict"); + } + + } else if (flags & NGX_HTTP_PROXY_COOKIE_SAMESITE_LAX) { + flags &= ~NGX_HTTP_PROXY_COOKIE_SAMESITE_LAX; + + if (value->len != 3 + || ngx_strncasecmp(value->data, (u_char *) "lax", 3) != 0) + { + ngx_str_set(key, "SameSite"); + ngx_str_set(value, "Lax"); + } + + } else if (flags & NGX_HTTP_PROXY_COOKIE_SAMESITE_NONE) { + flags &= ~NGX_HTTP_PROXY_COOKIE_SAMESITE_NONE; + + if (value->len != 4 + || ngx_strncasecmp(value->data, (u_char *) "none", 4) != 0) + { + ngx_str_set(key, "SameSite"); + ngx_str_set(value, "None"); + } + + } else if (flags & NGX_HTTP_PROXY_COOKIE_SAMESITE_OFF) { + key->data = NULL; + } + + continue; + } + } + + if (flags & NGX_HTTP_PROXY_COOKIE_SECURE_ON) { + attr = ngx_array_push(attrs); + if (attr == NULL) { + return NGX_ERROR; + } + + ngx_str_set(&attr->key, "Secure"); + ngx_str_null(&attr->value); + } + + if (flags & NGX_HTTP_PROXY_COOKIE_HTTPONLY_ON) { + attr = ngx_array_push(attrs); + if (attr == NULL) { + return NGX_ERROR; + } + + ngx_str_set(&attr->key, "HttpOnly"); + ngx_str_null(&attr->value); + } + + if (flags & (NGX_HTTP_PROXY_COOKIE_SAMESITE_STRICT + |NGX_HTTP_PROXY_COOKIE_SAMESITE_LAX + |NGX_HTTP_PROXY_COOKIE_SAMESITE_NONE)) + { + attr = ngx_array_push(attrs); + if (attr == NULL) { + return NGX_ERROR; + } + + ngx_str_set(&attr->key, "SameSite"); + + if (flags & NGX_HTTP_PROXY_COOKIE_SAMESITE_STRICT) { + ngx_str_set(&attr->value, "Strict"); + + } else if (flags & NGX_HTTP_PROXY_COOKIE_SAMESITE_LAX) { + ngx_str_set(&attr->value, "Lax"); + + } else { + ngx_str_set(&attr->value, "None"); + } + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_proxy_rewrite_complex_handler(ngx_http_request_t *r, ngx_str_t *value, + size_t prefix, size_t len, ngx_http_proxy_rewrite_t *pr) { ngx_str_t pattern, replacement; @@ -2628,8 +3151,7 @@ ngx_http_proxy_rewrite_complex_handler(ngx_http_request_t *r, } if (pattern.len > len - || ngx_rstrncmp(h->value.data + prefix, pattern.data, - pattern.len) != 0) + || ngx_rstrncmp(value->data + prefix, pattern.data, pattern.len) != 0) { return NGX_DECLINED; } @@ -2638,20 +3160,20 @@ ngx_http_proxy_rewrite_complex_handler(ngx_http_request_t *r, return NGX_ERROR; } - return ngx_http_proxy_rewrite(r, h, prefix, pattern.len, &replacement); + return ngx_http_proxy_rewrite(r, value, prefix, pattern.len, &replacement); } #if (NGX_PCRE) static ngx_int_t -ngx_http_proxy_rewrite_regex_handler(ngx_http_request_t *r, ngx_table_elt_t *h, +ngx_http_proxy_rewrite_regex_handler(ngx_http_request_t *r, ngx_str_t *value, size_t prefix, size_t len, ngx_http_proxy_rewrite_t *pr) { ngx_str_t pattern, replacement; pattern.len = len; - pattern.data = h->value.data + prefix; + pattern.data = value->data + prefix; if (ngx_http_regex_exec(r, pr->pattern.regex, &pattern) != NGX_OK) { return NGX_DECLINED; @@ -2661,20 +3183,15 @@ ngx_http_proxy_rewrite_regex_handler(ngx_http_request_t *r, ngx_table_elt_t *h, return NGX_ERROR; } - if (prefix == 0 && h->value.len == len) { - h->value = replacement; - return NGX_OK; - } - - return ngx_http_proxy_rewrite(r, h, prefix, len, &replacement); + return ngx_http_proxy_rewrite(r, value, prefix, len, &replacement); } #endif static ngx_int_t -ngx_http_proxy_rewrite_domain_handler(ngx_http_request_t *r, - ngx_table_elt_t *h, size_t prefix, size_t len, ngx_http_proxy_rewrite_t *pr) +ngx_http_proxy_rewrite_domain_handler(ngx_http_request_t *r, ngx_str_t *value, + size_t prefix, size_t len, ngx_http_proxy_rewrite_t *pr) { u_char *p; ngx_str_t pattern, replacement; @@ -2683,9 +3200,9 @@ ngx_http_proxy_rewrite_domain_handler(ngx_http_request_t *r, return NGX_ERROR; } - p = h->value.data + prefix; + p = value->data + prefix; - if (p[0] == '.') { + if (len && p[0] == '.') { p++; prefix++; len--; @@ -2699,18 +3216,23 @@ ngx_http_proxy_rewrite_domain_handler(ngx_http_request_t *r, return NGX_ERROR; } - return ngx_http_proxy_rewrite(r, h, prefix, len, &replacement); + return ngx_http_proxy_rewrite(r, value, prefix, len, &replacement); } static ngx_int_t -ngx_http_proxy_rewrite(ngx_http_request_t *r, ngx_table_elt_t *h, size_t prefix, +ngx_http_proxy_rewrite(ngx_http_request_t *r, ngx_str_t *value, size_t prefix, size_t len, ngx_str_t *replacement) { u_char *p, *data; size_t new_len; - new_len = replacement->len + h->value.len - len; + if (len == value->len) { + *value = *replacement; + return NGX_OK; + } + + new_len = replacement->len + value->len - len; if (replacement->len > len) { @@ -2719,23 +3241,22 @@ ngx_http_proxy_rewrite(ngx_http_request_t *r, ngx_table_elt_t *h, size_t prefix, return NGX_ERROR; } - p = ngx_copy(data, h->value.data, prefix); + p = ngx_copy(data, value->data, prefix); p = ngx_copy(p, replacement->data, replacement->len); - ngx_memcpy(p, h->value.data + prefix + len, - h->value.len - len - prefix + 1); + ngx_memcpy(p, value->data + prefix + len, + value->len - len - prefix + 1); - h->value.data = data; + value->data = data; } else { - p = ngx_copy(h->value.data + prefix, replacement->data, - replacement->len); + p = ngx_copy(value->data + prefix, replacement->data, replacement->len); - ngx_memmove(p, h->value.data + prefix + len, - h->value.len - len - prefix + 1); + ngx_memmove(p, value->data + prefix + len, + value->len - len - prefix + 1); } - h->value.len = new_len; + value->len = new_len; return NGX_OK; } @@ -2811,7 +3332,6 @@ ngx_http_proxy_create_loc_conf(ngx_conf_t *cf) * conf->method = NULL; * conf->location = NULL; * conf->url = { 0, NULL }; - * conf->headers_source = NULL; * conf->headers.lengths = NULL; * conf->headers.values = NULL; * conf->headers.hash = { NULL, 0 }; @@ -2884,16 +3404,20 @@ ngx_http_proxy_create_loc_conf(ngx_conf_t *cf) conf->upstream.ssl_verify = NGX_CONF_UNSET; conf->ssl_verify_depth = NGX_CONF_UNSET_UINT; conf->ssl_passwords = NGX_CONF_UNSET_PTR; + conf->ssl_conf_commands = NGX_CONF_UNSET_PTR; #endif /* "proxy_cyclic_temp_file" is disabled */ conf->upstream.cyclic_temp_file = 0; + conf->headers_source = NGX_CONF_UNSET_PTR; + conf->redirect = NGX_CONF_UNSET; conf->upstream.change_buffering = 1; conf->cookie_domains = NGX_CONF_UNSET_PTR; conf->cookie_paths = NGX_CONF_UNSET_PTR; + conf->cookie_flags = NGX_CONF_UNSET_PTR; conf->http_version = NGX_CONF_UNSET_UINT; @@ -3228,6 +3752,9 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) prev->ssl_certificate_key, ""); ngx_conf_merge_ptr_value(conf->ssl_passwords, prev->ssl_passwords, NULL); + ngx_conf_merge_ptr_value(conf->ssl_conf_commands, + prev->ssl_conf_commands, NULL); + if (conf->ssl && ngx_http_proxy_set_ssl(cf, conf) != NGX_OK) { return NGX_CONF_ERROR; } @@ -3289,6 +3816,8 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_ptr_value(conf->cookie_paths, prev->cookie_paths, NULL); + ngx_conf_merge_ptr_value(conf->cookie_flags, prev->cookie_flags, NULL); + ngx_conf_merge_uint_value(conf->http_version, prev->http_version, NGX_HTTP_VERSION_10); @@ -3359,12 +3888,13 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) } } - if (conf->headers_source == NULL) { + ngx_conf_merge_ptr_value(conf->headers_source, prev->headers_source, NULL); + + if (conf->headers_source == prev->headers_source) { conf->headers = prev->headers; #if (NGX_HTTP_CACHE) conf->headers_cache = prev->headers_cache; #endif - conf->headers_source = prev->headers_source; } rc = ngx_http_proxy_init_headers(cf, conf, &conf->headers, @@ -3703,7 +4233,7 @@ ngx_http_proxy_redirect(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_http_compile_complex_value_t ccv; if (plcf->redirect == 0) { - return NGX_CONF_OK; + return "is duplicate"; } plcf->redirect = 1; @@ -3712,16 +4242,12 @@ ngx_http_proxy_redirect(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) if (cf->args->nelts == 2) { if (ngx_strcmp(value[1].data, "off") == 0) { - plcf->redirect = 0; - plcf->redirects = NULL; - return NGX_CONF_OK; - } - if (ngx_strcmp(value[1].data, "false") == 0) { - ngx_conf_log_error(NGX_LOG_ERR, cf, 0, - "invalid parameter \"false\", use \"off\" instead"); + if (plcf->redirects) { + return "is duplicate"; + } + plcf->redirect = 0; - plcf->redirects = NULL; return NGX_CONF_OK; } @@ -3745,7 +4271,9 @@ ngx_http_proxy_redirect(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return NGX_CONF_ERROR; } - if (ngx_strcmp(value[1].data, "default") == 0) { + if (cf->args->nelts == 2 + && ngx_strcmp(value[1].data, "default") == 0) + { if (plcf->proxy_lengths) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "\"proxy_redirect default\" cannot be used " @@ -3848,7 +4376,7 @@ ngx_http_proxy_cookie_domain(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_http_compile_complex_value_t ccv; if (plcf->cookie_domains == NULL) { - return NGX_CONF_OK; + return "is duplicate"; } value = cf->args->elts; @@ -3856,6 +4384,11 @@ ngx_http_proxy_cookie_domain(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) if (cf->args->nelts == 2) { if (ngx_strcmp(value[1].data, "off") == 0) { + + if (plcf->cookie_domains != NGX_CONF_UNSET_PTR) { + return "is duplicate"; + } + plcf->cookie_domains = NULL; return NGX_CONF_OK; } @@ -3935,7 +4468,7 @@ ngx_http_proxy_cookie_path(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_http_compile_complex_value_t ccv; if (plcf->cookie_paths == NULL) { - return NGX_CONF_OK; + return "is duplicate"; } value = cf->args->elts; @@ -3943,6 +4476,11 @@ ngx_http_proxy_cookie_path(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) if (cf->args->nelts == 2) { if (ngx_strcmp(value[1].data, "off") == 0) { + + if (plcf->cookie_paths != NGX_CONF_UNSET_PTR) { + return "is duplicate"; + } + plcf->cookie_paths = NULL; return NGX_CONF_OK; } @@ -4012,6 +4550,126 @@ ngx_http_proxy_cookie_path(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } +static char * +ngx_http_proxy_cookie_flags(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_proxy_loc_conf_t *plcf = conf; + + ngx_str_t *value; + ngx_uint_t i; + ngx_http_complex_value_t *cv; + ngx_http_proxy_cookie_flags_t *pcf; + ngx_http_compile_complex_value_t ccv; +#if (NGX_PCRE) + ngx_regex_compile_t rc; + u_char errstr[NGX_MAX_CONF_ERRSTR]; +#endif + + if (plcf->cookie_flags == NULL) { + return "is duplicate"; + } + + value = cf->args->elts; + + if (cf->args->nelts == 2) { + + if (ngx_strcmp(value[1].data, "off") == 0) { + + if (plcf->cookie_flags != NGX_CONF_UNSET_PTR) { + return "is duplicate"; + } + + plcf->cookie_flags = NULL; + return NGX_CONF_OK; + } + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid parameter \"%V\"", &value[1]); + return NGX_CONF_ERROR; + } + + if (plcf->cookie_flags == NGX_CONF_UNSET_PTR) { + plcf->cookie_flags = ngx_array_create(cf->pool, 1, + sizeof(ngx_http_proxy_cookie_flags_t)); + if (plcf->cookie_flags == NULL) { + return NGX_CONF_ERROR; + } + } + + pcf = ngx_array_push(plcf->cookie_flags); + if (pcf == NULL) { + return NGX_CONF_ERROR; + } + + pcf->regex = 0; + + if (value[1].data[0] == '~') { + value[1].len--; + value[1].data++; + +#if (NGX_PCRE) + ngx_memzero(&rc, sizeof(ngx_regex_compile_t)); + + rc.pattern = value[1]; + rc.err.len = NGX_MAX_CONF_ERRSTR; + rc.err.data = errstr; + rc.options = NGX_REGEX_CASELESS; + + pcf->cookie.regex = ngx_http_regex_compile(cf, &rc); + if (pcf->cookie.regex == NULL) { + return NGX_CONF_ERROR; + } + + pcf->regex = 1; +#else + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "using regex \"%V\" requires PCRE library", + &value[1]); + return NGX_CONF_ERROR; +#endif + + } else { + + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[1]; + ccv.complex_value = &pcf->cookie.complex; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + } + + if (ngx_array_init(&pcf->flags_values, cf->pool, cf->args->nelts - 2, + sizeof(ngx_http_complex_value_t)) + != NGX_OK) + { + return NGX_CONF_ERROR; + } + + for (i = 2; i < cf->args->nelts; i++) { + + cv = ngx_array_push(&pcf->flags_values); + if (cv == NULL) { + return NGX_CONF_ERROR; + } + + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[i]; + ccv.complex_value = cv; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + } + + return NGX_CONF_OK; +} + + static ngx_int_t ngx_http_proxy_rewrite_regex(ngx_conf_t *cf, ngx_http_proxy_rewrite_t *pr, ngx_str_t *regex, ngx_uint_t caseless) @@ -4250,6 +4908,17 @@ ngx_http_proxy_lowat_check(ngx_conf_t *cf, void *post, void *data) #if (NGX_HTTP_SSL) +static char * +ngx_http_proxy_ssl_conf_command_check(ngx_conf_t *cf, void *post, void *data) +{ +#ifndef SSL_CONF_FLAG_FILE + return "is not supported on this platform"; +#else + return NGX_CONF_OK; +#endif +} + + static ngx_int_t ngx_http_proxy_set_ssl(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *plcf) { @@ -4327,6 +4996,12 @@ ngx_http_proxy_set_ssl(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *plcf) return NGX_ERROR; } + if (ngx_ssl_conf_commands(cf, plcf->upstream.ssl, plcf->ssl_conf_commands) + != NGX_OK) + { + return NGX_ERROR; + } + return NGX_OK; } diff --git a/src/http/modules/ngx_http_scgi_module.c b/src/http/modules/ngx_http_scgi_module.c index 7216f78..600999c 100644 --- a/src/http/modules/ngx_http_scgi_module.c +++ b/src/http/modules/ngx_http_scgi_module.c @@ -49,6 +49,7 @@ static ngx_int_t ngx_http_scgi_create_request(ngx_http_request_t *r); static ngx_int_t ngx_http_scgi_reinit_request(ngx_http_request_t *r); static ngx_int_t ngx_http_scgi_process_status_line(ngx_http_request_t *r); static ngx_int_t ngx_http_scgi_process_header(ngx_http_request_t *r); +static ngx_int_t ngx_http_scgi_input_filter_init(void *data); static void ngx_http_scgi_abort_request(ngx_http_request_t *r); static void ngx_http_scgi_finalize_request(ngx_http_request_t *r, ngx_int_t rc); @@ -534,6 +535,10 @@ ngx_http_scgi_handler(ngx_http_request_t *r) u->pipe->input_filter = ngx_event_pipe_copy_input_filter; u->pipe->input_ctx = r; + u->input_filter_init = ngx_http_scgi_input_filter_init; + u->input_filter = ngx_http_upstream_non_buffered_filter; + u->input_filter_ctx = r; + if (!scf->upstream.request_buffering && scf->upstream.pass_request_body && !r->headers_in.chunked) @@ -1145,6 +1150,37 @@ ngx_http_scgi_process_header(ngx_http_request_t *r) } +static ngx_int_t +ngx_http_scgi_input_filter_init(void *data) +{ + ngx_http_request_t *r = data; + ngx_http_upstream_t *u; + + u = r->upstream; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http scgi filter init s:%ui l:%O", + u->headers_in.status_n, u->headers_in.content_length_n); + + if (u->headers_in.status_n == NGX_HTTP_NO_CONTENT + || u->headers_in.status_n == NGX_HTTP_NOT_MODIFIED) + { + u->pipe->length = 0; + u->length = 0; + + } else if (r->method == NGX_HTTP_HEAD) { + u->pipe->length = -1; + u->length = -1; + + } else { + u->pipe->length = u->headers_in.content_length_n; + u->length = u->headers_in.content_length_n; + } + + return NGX_OK; +} + + static void ngx_http_scgi_abort_request(ngx_http_request_t *r) { diff --git a/src/http/modules/ngx_http_slice_filter_module.c b/src/http/modules/ngx_http_slice_filter_module.c index c1edbca..186380a 100644 --- a/src/http/modules/ngx_http_slice_filter_module.c +++ b/src/http/modules/ngx_http_slice_filter_module.c @@ -180,6 +180,11 @@ ngx_http_slice_header_filter(ngx_http_request_t *r) r->headers_out.content_range->hash = 0; r->headers_out.content_range = NULL; + if (r->headers_out.accept_ranges) { + r->headers_out.accept_ranges->hash = 0; + r->headers_out.accept_ranges = NULL; + } + r->allow_ranges = 1; r->subrequest_ranges = 1; r->single_range = 1; diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c index 495e628..a47d696 100644 --- a/src/http/modules/ngx_http_ssl_module.c +++ b/src/http/modules/ngx_http_ssl_module.c @@ -50,6 +50,11 @@ static char *ngx_http_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static char *ngx_http_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static char *ngx_http_ssl_ocsp_cache(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); + +static char *ngx_http_ssl_conf_command_check(ngx_conf_t *cf, void *post, + void *data); static ngx_int_t ngx_http_ssl_init(ngx_conf_t *cf); @@ -74,11 +79,23 @@ static ngx_conf_enum_t ngx_http_ssl_verify[] = { }; +static ngx_conf_enum_t ngx_http_ssl_ocsp[] = { + { ngx_string("off"), 0 }, + { ngx_string("on"), 1 }, + { ngx_string("leaf"), 2 }, + { ngx_null_string, 0 } +}; + + static ngx_conf_deprecated_t ngx_http_ssl_deprecated = { ngx_conf_deprecated, "ssl", "listen ... ssl" }; +static ngx_conf_post_t ngx_http_ssl_conf_command_post = + { ngx_http_ssl_conf_command_check }; + + static ngx_command_t ngx_http_ssl_commands[] = { { ngx_string("ssl"), @@ -214,6 +231,27 @@ static ngx_command_t ngx_http_ssl_commands[] = { offsetof(ngx_http_ssl_srv_conf_t, crl), NULL }, + { ngx_string("ssl_ocsp"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG, + ngx_conf_set_enum_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_http_ssl_srv_conf_t, ocsp), + &ngx_http_ssl_ocsp }, + + { ngx_string("ssl_ocsp_responder"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_http_ssl_srv_conf_t, ocsp_responder), + NULL }, + + { ngx_string("ssl_ocsp_cache"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_http_ssl_ocsp_cache, + NGX_HTTP_SRV_CONF_OFFSET, + 0, + NULL }, + { ngx_string("ssl_stapling"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, @@ -249,6 +287,20 @@ static ngx_command_t ngx_http_ssl_commands[] = { offsetof(ngx_http_ssl_srv_conf_t, early_data), NULL }, + { ngx_string("ssl_conf_command"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE2, + ngx_conf_set_keyval_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_http_ssl_srv_conf_t, conf_commands), + &ngx_http_ssl_conf_command_post }, + + { ngx_string("ssl_reject_handshake"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_http_ssl_srv_conf_t, reject_handshake), + NULL }, + ngx_null_command }; @@ -561,6 +613,7 @@ ngx_http_ssl_create_srv_conf(ngx_conf_t *cf) * sscf->crl = { 0, NULL }; * sscf->ciphers = { 0, NULL }; * sscf->shm_zone = NULL; + * sscf->ocsp_responder = { 0, NULL }; * sscf->stapling_file = { 0, NULL }; * sscf->stapling_responder = { 0, NULL }; */ @@ -568,16 +621,20 @@ ngx_http_ssl_create_srv_conf(ngx_conf_t *cf) sscf->enable = NGX_CONF_UNSET; sscf->prefer_server_ciphers = NGX_CONF_UNSET; sscf->early_data = NGX_CONF_UNSET; + sscf->reject_handshake = NGX_CONF_UNSET; sscf->buffer_size = NGX_CONF_UNSET_SIZE; sscf->verify = NGX_CONF_UNSET_UINT; sscf->verify_depth = NGX_CONF_UNSET_UINT; sscf->certificates = NGX_CONF_UNSET_PTR; sscf->certificate_keys = NGX_CONF_UNSET_PTR; sscf->passwords = NGX_CONF_UNSET_PTR; + sscf->conf_commands = NGX_CONF_UNSET_PTR; sscf->builtin_session_cache = NGX_CONF_UNSET; sscf->session_timeout = NGX_CONF_UNSET; sscf->session_tickets = NGX_CONF_UNSET; sscf->session_ticket_keys = NGX_CONF_UNSET_PTR; + sscf->ocsp = NGX_CONF_UNSET_UINT; + sscf->ocsp_cache_zone = NGX_CONF_UNSET_PTR; sscf->stapling = NGX_CONF_UNSET; sscf->stapling_verify = NGX_CONF_UNSET; @@ -611,6 +668,7 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) prev->prefer_server_ciphers, 0); ngx_conf_merge_value(conf->early_data, prev->early_data, 0); + ngx_conf_merge_value(conf->reject_handshake, prev->reject_handshake, 0); ngx_conf_merge_bitmask_value(conf->protocols, prev->protocols, (NGX_CONF_BITMASK_SET|NGX_SSL_TLSv1 @@ -641,6 +699,13 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_str_value(conf->ciphers, prev->ciphers, NGX_DEFAULT_CIPHERS); + ngx_conf_merge_ptr_value(conf->conf_commands, prev->conf_commands, NULL); + + ngx_conf_merge_uint_value(conf->ocsp, prev->ocsp, 0); + ngx_conf_merge_str_value(conf->ocsp_responder, prev->ocsp_responder, ""); + ngx_conf_merge_ptr_value(conf->ocsp_cache_zone, + prev->ocsp_cache_zone, NULL); + ngx_conf_merge_value(conf->stapling, prev->stapling, 0); ngx_conf_merge_value(conf->stapling_verify, prev->stapling_verify, 0); ngx_conf_merge_str_value(conf->stapling_file, prev->stapling_file, ""); @@ -651,7 +716,27 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) if (conf->enable) { - if (conf->certificates == NULL) { + if (conf->certificates) { + if (conf->certificate_keys == NULL) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "no \"ssl_certificate_key\" is defined for " + "the \"ssl\" directive in %s:%ui", + conf->file, conf->line); + return NGX_CONF_ERROR; + } + + if (conf->certificate_keys->nelts < conf->certificates->nelts) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "no \"ssl_certificate_key\" is defined " + "for certificate \"%V\" and " + "the \"ssl\" directive in %s:%ui", + ((ngx_str_t *) conf->certificates->elts) + + conf->certificates->nelts - 1, + conf->file, conf->line); + return NGX_CONF_ERROR; + } + + } else if (!conf->reject_handshake) { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "no \"ssl_certificate\" is defined for " "the \"ssl\" directive in %s:%ui", @@ -659,30 +744,7 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) return NGX_CONF_ERROR; } - if (conf->certificate_keys == NULL) { - ngx_log_error(NGX_LOG_EMERG, cf->log, 0, - "no \"ssl_certificate_key\" is defined for " - "the \"ssl\" directive in %s:%ui", - conf->file, conf->line); - return NGX_CONF_ERROR; - } - - if (conf->certificate_keys->nelts < conf->certificates->nelts) { - ngx_log_error(NGX_LOG_EMERG, cf->log, 0, - "no \"ssl_certificate_key\" is defined " - "for certificate \"%V\" and " - "the \"ssl\" directive in %s:%ui", - ((ngx_str_t *) conf->certificates->elts) - + conf->certificates->nelts - 1, - conf->file, conf->line); - return NGX_CONF_ERROR; - } - - } else { - - if (conf->certificates == NULL) { - return NGX_CONF_OK; - } + } else if (conf->certificates) { if (conf->certificate_keys == NULL || conf->certificate_keys->nelts < conf->certificates->nelts) @@ -694,6 +756,9 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) + conf->certificates->nelts - 1); return NGX_CONF_ERROR; } + + } else if (!conf->reject_handshake) { + return NGX_CONF_OK; } if (ngx_ssl_create(&conf->ssl, conf->protocols, conf) != NGX_OK) { @@ -752,7 +817,7 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) return NGX_CONF_ERROR; #endif - } else { + } else if (conf->certificates) { /* configure certificates */ @@ -802,6 +867,23 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) return NGX_CONF_ERROR; } + if (conf->ocsp) { + + if (conf->verify == 3) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "\"ssl_ocsp\" is incompatible with " + "\"ssl_verify_client optional_no_ca\""); + return NGX_CONF_ERROR; + } + + if (ngx_ssl_ocsp(cf, &conf->ssl, &conf->ocsp_responder, conf->ocsp, + conf->ocsp_cache_zone) + != NGX_OK) + { + return NGX_CONF_ERROR; + } + } + if (ngx_ssl_dhparam(cf, &conf->ssl, &conf->dhparam) != NGX_OK) { return NGX_CONF_ERROR; } @@ -857,6 +939,10 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) return NGX_CONF_ERROR; } + if (ngx_ssl_conf_commands(cf, &conf->ssl, conf->conf_commands) != NGX_OK) { + return NGX_CONF_ERROR; + } + return NGX_CONF_OK; } @@ -870,6 +956,10 @@ ngx_http_ssl_compile_certificates(ngx_conf_t *cf, ngx_http_complex_value_t *cv; ngx_http_compile_complex_value_t ccv; + if (conf->certificates == NULL) { + return NGX_OK; + } + cert = conf->certificates->elts; key = conf->certificate_keys->elts; nelts = conf->certificates->nelts; @@ -1100,6 +1190,96 @@ invalid: } +static char * +ngx_http_ssl_ocsp_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_ssl_srv_conf_t *sscf = conf; + + size_t len; + ngx_int_t n; + ngx_str_t *value, name, size; + ngx_uint_t j; + + if (sscf->ocsp_cache_zone != NGX_CONF_UNSET_PTR) { + return "is duplicate"; + } + + value = cf->args->elts; + + if (ngx_strcmp(value[1].data, "off") == 0) { + sscf->ocsp_cache_zone = NULL; + return NGX_CONF_OK; + } + + if (value[1].len <= sizeof("shared:") - 1 + || ngx_strncmp(value[1].data, "shared:", sizeof("shared:") - 1) != 0) + { + goto invalid; + } + + len = 0; + + for (j = sizeof("shared:") - 1; j < value[1].len; j++) { + if (value[1].data[j] == ':') { + break; + } + + len++; + } + + if (len == 0) { + goto invalid; + } + + name.len = len; + name.data = value[1].data + sizeof("shared:") - 1; + + size.len = value[1].len - j - 1; + size.data = name.data + len + 1; + + n = ngx_parse_size(&size); + + if (n == NGX_ERROR) { + goto invalid; + } + + if (n < (ngx_int_t) (8 * ngx_pagesize)) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "OCSP cache \"%V\" is too small", &value[1]); + + return NGX_CONF_ERROR; + } + + sscf->ocsp_cache_zone = ngx_shared_memory_add(cf, &name, n, + &ngx_http_ssl_module_ctx); + if (sscf->ocsp_cache_zone == NULL) { + return NGX_CONF_ERROR; + } + + sscf->ocsp_cache_zone->init = ngx_ssl_ocsp_cache_init; + + return NGX_CONF_OK; + +invalid: + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid OCSP cache \"%V\"", &value[1]); + + return NGX_CONF_ERROR; +} + + +static char * +ngx_http_ssl_conf_command_check(ngx_conf_t *cf, void *post, void *data) +{ +#ifndef SSL_CONF_FLAG_FILE + return "is not supported on this platform"; +#else + return NGX_CONF_OK; +#endif +} + + static ngx_int_t ngx_http_ssl_init(ngx_conf_t *cf) { @@ -1118,17 +1298,28 @@ ngx_http_ssl_init(ngx_conf_t *cf) sscf = cscfp[s]->ctx->srv_conf[ngx_http_ssl_module.ctx_index]; - if (sscf->ssl.ctx == NULL || !sscf->stapling) { + if (sscf->ssl.ctx == NULL) { continue; } clcf = cscfp[s]->ctx->loc_conf[ngx_http_core_module.ctx_index]; - if (ngx_ssl_stapling_resolver(cf, &sscf->ssl, clcf->resolver, + if (sscf->stapling) { + if (ngx_ssl_stapling_resolver(cf, &sscf->ssl, clcf->resolver, + clcf->resolver_timeout) + != NGX_OK) + { + return NGX_ERROR; + } + } + + if (sscf->ocsp) { + if (ngx_ssl_ocsp_resolver(cf, &sscf->ssl, clcf->resolver, clcf->resolver_timeout) - != NGX_OK) - { - return NGX_ERROR; + != NGX_OK) + { + return NGX_ERROR; + } } } @@ -1149,7 +1340,33 @@ ngx_http_ssl_init(ngx_conf_t *cf) cscf = addr[a].default_server; sscf = cscf->ctx->srv_conf[ngx_http_ssl_module.ctx_index]; - if (sscf->certificates == NULL) { + if (sscf->certificates) { + continue; + } + + if (!sscf->reject_handshake) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "no \"ssl_certificate\" is defined for " + "the \"listen ... ssl\" directive in %s:%ui", + cscf->file_name, cscf->line); + return NGX_ERROR; + } + + /* + * if no certificates are defined in the default server, + * check all non-default server blocks + */ + + cscfp = addr[a].servers.elts; + for (s = 0; s < addr[a].servers.nelts; s++) { + + cscf = cscfp[s]; + sscf = cscf->ctx->srv_conf[ngx_http_ssl_module.ctx_index]; + + if (sscf->certificates || sscf->reject_handshake) { + continue; + } + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "no \"ssl_certificate\" is defined for " "the \"listen ... ssl\" directive in %s:%ui", diff --git a/src/http/modules/ngx_http_ssl_module.h b/src/http/modules/ngx_http_ssl_module.h index 26fdccf..7ab0f7e 100644 --- a/src/http/modules/ngx_http_ssl_module.h +++ b/src/http/modules/ngx_http_ssl_module.h @@ -21,6 +21,7 @@ typedef struct { ngx_flag_t prefer_server_ciphers; ngx_flag_t early_data; + ngx_flag_t reject_handshake; ngx_uint_t protocols; @@ -48,12 +49,17 @@ typedef struct { ngx_str_t ciphers; ngx_array_t *passwords; + ngx_array_t *conf_commands; ngx_shm_zone_t *shm_zone; ngx_flag_t session_tickets; ngx_array_t *session_ticket_keys; + ngx_uint_t ocsp; + ngx_str_t ocsp_responder; + ngx_shm_zone_t *ocsp_cache_zone; + ngx_flag_t stapling; ngx_flag_t stapling_verify; ngx_str_t stapling_file; diff --git a/src/http/modules/ngx_http_stub_status_module.c b/src/http/modules/ngx_http_stub_status_module.c index 9bdf881..db68b76 100644 --- a/src/http/modules/ngx_http_stub_status_module.c +++ b/src/http/modules/ngx_http_stub_status_module.c @@ -103,16 +103,6 @@ ngx_http_stub_status_handler(ngx_http_request_t *r) ngx_str_set(&r->headers_out.content_type, "text/plain"); r->headers_out.content_type_lowcase = NULL; - if (r->method == NGX_HTTP_HEAD) { - r->headers_out.status = NGX_HTTP_OK; - - rc = ngx_http_send_header(r); - - if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { - return rc; - } - } - size = sizeof("Active connections: \n") + NGX_ATOMIC_T_LEN + sizeof("server accepts handled requests\n") - 1 + 6 + 3 * NGX_ATOMIC_T_LEN diff --git a/src/http/modules/ngx_http_upstream_keepalive_module.c b/src/http/modules/ngx_http_upstream_keepalive_module.c index 1560807..1a4dfd7 100644 --- a/src/http/modules/ngx_http_upstream_keepalive_module.c +++ b/src/http/modules/ngx_http_upstream_keepalive_module.c @@ -13,6 +13,7 @@ typedef struct { ngx_uint_t max_cached; ngx_uint_t requests; + ngx_msec_t time; ngx_msec_t timeout; ngx_queue_t cache; @@ -86,6 +87,13 @@ static ngx_command_t ngx_http_upstream_keepalive_commands[] = { 0, NULL }, + { ngx_string("keepalive_time"), + NGX_HTTP_UPS_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_http_upstream_keepalive_srv_conf_t, time), + NULL }, + { ngx_string("keepalive_timeout"), NGX_HTTP_UPS_CONF|NGX_CONF_TAKE1, ngx_conf_set_msec_slot, @@ -149,8 +157,9 @@ ngx_http_upstream_init_keepalive(ngx_conf_t *cf, kcf = ngx_http_conf_upstream_srv_conf(us, ngx_http_upstream_keepalive_module); + ngx_conf_init_msec_value(kcf->time, 3600000); ngx_conf_init_msec_value(kcf->timeout, 60000); - ngx_conf_init_uint_value(kcf->requests, 100); + ngx_conf_init_uint_value(kcf->requests, 1000); if (kcf->original_init_upstream(cf, us) != NGX_OK) { return NGX_ERROR; @@ -326,6 +335,10 @@ ngx_http_upstream_free_keepalive_peer(ngx_peer_connection_t *pc, void *data, goto invalid; } + if (ngx_current_msec - c->start_time > kp->conf->time) { + goto invalid; + } + if (!u->keepalive) { goto invalid; } @@ -513,6 +526,7 @@ ngx_http_upstream_keepalive_create_conf(ngx_conf_t *cf) * conf->max_cached = 0; */ + conf->time = NGX_CONF_UNSET_MSEC; conf->timeout = NGX_CONF_UNSET_MSEC; conf->requests = NGX_CONF_UNSET_UINT; diff --git a/src/http/modules/ngx_http_userid_filter_module.c b/src/http/modules/ngx_http_userid_filter_module.c index 31cf402..1e33c5c 100644 --- a/src/http/modules/ngx_http_userid_filter_module.c +++ b/src/http/modules/ngx_http_userid_filter_module.c @@ -15,12 +15,21 @@ #define NGX_HTTP_USERID_V1 2 #define NGX_HTTP_USERID_ON 3 +#define NGX_HTTP_USERID_COOKIE_OFF 0x0002 +#define NGX_HTTP_USERID_COOKIE_SECURE 0x0004 +#define NGX_HTTP_USERID_COOKIE_HTTPONLY 0x0008 +#define NGX_HTTP_USERID_COOKIE_SAMESITE 0x0010 +#define NGX_HTTP_USERID_COOKIE_SAMESITE_STRICT 0x0020 +#define NGX_HTTP_USERID_COOKIE_SAMESITE_LAX 0x0040 +#define NGX_HTTP_USERID_COOKIE_SAMESITE_NONE 0x0080 + /* 31 Dec 2037 23:55:55 GMT */ #define NGX_HTTP_USERID_MAX_EXPIRES 2145916555 typedef struct { ngx_uint_t enable; + ngx_uint_t flags; ngx_int_t service; @@ -88,6 +97,20 @@ static ngx_conf_enum_t ngx_http_userid_state[] = { }; +static ngx_conf_bitmask_t ngx_http_userid_flags[] = { + { ngx_string("off"), NGX_HTTP_USERID_COOKIE_OFF }, + { ngx_string("secure"), NGX_HTTP_USERID_COOKIE_SECURE }, + { ngx_string("httponly"), NGX_HTTP_USERID_COOKIE_HTTPONLY }, + { ngx_string("samesite=strict"), + NGX_HTTP_USERID_COOKIE_SAMESITE|NGX_HTTP_USERID_COOKIE_SAMESITE_STRICT }, + { ngx_string("samesite=lax"), + NGX_HTTP_USERID_COOKIE_SAMESITE|NGX_HTTP_USERID_COOKIE_SAMESITE_LAX }, + { ngx_string("samesite=none"), + NGX_HTTP_USERID_COOKIE_SAMESITE|NGX_HTTP_USERID_COOKIE_SAMESITE_NONE }, + { ngx_null_string, 0 } +}; + + static ngx_conf_post_handler_pt ngx_http_userid_domain_p = ngx_http_userid_domain; static ngx_conf_post_handler_pt ngx_http_userid_path_p = ngx_http_userid_path; @@ -138,6 +161,13 @@ static ngx_command_t ngx_http_userid_commands[] = { 0, NULL }, + { ngx_string("userid_flags"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE123, + ngx_conf_set_bitmask_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_userid_conf_t, flags), + &ngx_http_userid_flags }, + { ngx_string("userid_p3p"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_str_slot, @@ -383,6 +413,26 @@ ngx_http_userid_set_uid(ngx_http_request_t *r, ngx_http_userid_ctx_t *ctx, len += conf->domain.len; } + if (conf->flags & NGX_HTTP_USERID_COOKIE_SECURE) { + len += sizeof("; secure") - 1; + } + + if (conf->flags & NGX_HTTP_USERID_COOKIE_HTTPONLY) { + len += sizeof("; httponly") - 1; + } + + if (conf->flags & NGX_HTTP_USERID_COOKIE_SAMESITE_STRICT) { + len += sizeof("; samesite=strict") - 1; + } + + if (conf->flags & NGX_HTTP_USERID_COOKIE_SAMESITE_LAX) { + len += sizeof("; samesite=lax") - 1; + } + + if (conf->flags & NGX_HTTP_USERID_COOKIE_SAMESITE_NONE) { + len += sizeof("; samesite=none") - 1; + } + cookie = ngx_pnalloc(r->pool, len); if (cookie == NULL) { return NGX_ERROR; @@ -422,6 +472,26 @@ ngx_http_userid_set_uid(ngx_http_request_t *r, ngx_http_userid_ctx_t *ctx, p = ngx_copy(p, conf->path.data, conf->path.len); + if (conf->flags & NGX_HTTP_USERID_COOKIE_SECURE) { + p = ngx_cpymem(p, "; secure", sizeof("; secure") - 1); + } + + if (conf->flags & NGX_HTTP_USERID_COOKIE_HTTPONLY) { + p = ngx_cpymem(p, "; httponly", sizeof("; httponly") - 1); + } + + if (conf->flags & NGX_HTTP_USERID_COOKIE_SAMESITE_STRICT) { + p = ngx_cpymem(p, "; samesite=strict", sizeof("; samesite=strict") - 1); + } + + if (conf->flags & NGX_HTTP_USERID_COOKIE_SAMESITE_LAX) { + p = ngx_cpymem(p, "; samesite=lax", sizeof("; samesite=lax") - 1); + } + + if (conf->flags & NGX_HTTP_USERID_COOKIE_SAMESITE_NONE) { + p = ngx_cpymem(p, "; samesite=none", sizeof("; samesite=none") - 1); + } + set_cookie = ngx_list_push(&r->headers_out.headers); if (set_cookie == NULL) { return NGX_ERROR; @@ -658,6 +728,7 @@ ngx_http_userid_create_conf(ngx_conf_t *cf) /* * set by ngx_pcalloc(): * + * conf->flags = 0; * conf->name = { 0, NULL }; * conf->domain = { 0, NULL }; * conf->path = { 0, NULL }; @@ -682,6 +753,9 @@ ngx_http_userid_merge_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_uint_value(conf->enable, prev->enable, NGX_HTTP_USERID_OFF); + ngx_conf_merge_bitmask_value(conf->flags, prev->flags, + (NGX_CONF_BITMASK_SET|NGX_HTTP_USERID_COOKIE_OFF)); + ngx_conf_merge_str_value(conf->name, prev->name, "uid"); ngx_conf_merge_str_value(conf->domain, prev->domain, ""); ngx_conf_merge_str_value(conf->path, prev->path, "; path=/"); diff --git a/src/http/modules/ngx_http_uwsgi_module.c b/src/http/modules/ngx_http_uwsgi_module.c index 56dc236..1334f44 100644 --- a/src/http/modules/ngx_http_uwsgi_module.c +++ b/src/http/modules/ngx_http_uwsgi_module.c @@ -57,6 +57,7 @@ typedef struct { ngx_str_t ssl_certificate; ngx_str_t ssl_certificate_key; ngx_array_t *ssl_passwords; + ngx_array_t *ssl_conf_commands; #endif } ngx_http_uwsgi_loc_conf_t; @@ -67,6 +68,7 @@ static ngx_int_t ngx_http_uwsgi_create_request(ngx_http_request_t *r); static ngx_int_t ngx_http_uwsgi_reinit_request(ngx_http_request_t *r); static ngx_int_t ngx_http_uwsgi_process_status_line(ngx_http_request_t *r); static ngx_int_t ngx_http_uwsgi_process_header(ngx_http_request_t *r); +static ngx_int_t ngx_http_uwsgi_input_filter_init(void *data); static void ngx_http_uwsgi_abort_request(ngx_http_request_t *r); static void ngx_http_uwsgi_finalize_request(ngx_http_request_t *r, ngx_int_t rc); @@ -95,6 +97,8 @@ static char *ngx_http_uwsgi_cache_key(ngx_conf_t *cf, ngx_command_t *cmd, #if (NGX_HTTP_SSL) static char *ngx_http_uwsgi_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static char *ngx_http_uwsgi_ssl_conf_command_check(ngx_conf_t *cf, void *post, + void *data); static ngx_int_t ngx_http_uwsgi_set_ssl(ngx_conf_t *cf, ngx_http_uwsgi_loc_conf_t *uwcf); #endif @@ -133,6 +137,9 @@ static ngx_conf_bitmask_t ngx_http_uwsgi_ssl_protocols[] = { { ngx_null_string, 0 } }; +static ngx_conf_post_t ngx_http_uwsgi_ssl_conf_command_post = + { ngx_http_uwsgi_ssl_conf_command_check }; + #endif @@ -560,6 +567,13 @@ static ngx_command_t ngx_http_uwsgi_commands[] = { 0, NULL }, + { ngx_string("uwsgi_ssl_conf_command"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2, + ngx_conf_set_keyval_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_uwsgi_loc_conf_t, ssl_conf_commands), + &ngx_http_uwsgi_ssl_conf_command_post }, + #endif ngx_null_command @@ -703,6 +717,10 @@ ngx_http_uwsgi_handler(ngx_http_request_t *r) u->pipe->input_filter = ngx_event_pipe_copy_input_filter; u->pipe->input_ctx = r; + u->input_filter_init = ngx_http_uwsgi_input_filter_init; + u->input_filter = ngx_http_upstream_non_buffered_filter; + u->input_filter_ctx = r; + if (!uwcf->upstream.request_buffering && uwcf->upstream.pass_request_body && !r->headers_in.chunked) @@ -1141,6 +1159,7 @@ ngx_http_uwsgi_create_request(ngx_http_request_t *r) r->upstream->request_bufs = cl; } + b->flush = 1; cl->next = NULL; return NGX_OK; @@ -1355,6 +1374,37 @@ ngx_http_uwsgi_process_header(ngx_http_request_t *r) } +static ngx_int_t +ngx_http_uwsgi_input_filter_init(void *data) +{ + ngx_http_request_t *r = data; + ngx_http_upstream_t *u; + + u = r->upstream; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http uwsgi filter init s:%ui l:%O", + u->headers_in.status_n, u->headers_in.content_length_n); + + if (u->headers_in.status_n == NGX_HTTP_NO_CONTENT + || u->headers_in.status_n == NGX_HTTP_NOT_MODIFIED) + { + u->pipe->length = 0; + u->length = 0; + + } else if (r->method == NGX_HTTP_HEAD) { + u->pipe->length = -1; + u->length = -1; + + } else { + u->pipe->length = u->headers_in.content_length_n; + u->length = u->headers_in.content_length_n; + } + + return NGX_OK; +} + + static void ngx_http_uwsgi_abort_request(ngx_http_request_t *r) { @@ -1463,6 +1513,7 @@ ngx_http_uwsgi_create_loc_conf(ngx_conf_t *cf) conf->upstream.ssl_verify = NGX_CONF_UNSET; conf->ssl_verify_depth = NGX_CONF_UNSET_UINT; conf->ssl_passwords = NGX_CONF_UNSET_PTR; + conf->ssl_conf_commands = NGX_CONF_UNSET_PTR; #endif /* "uwsgi_cyclic_temp_file" is disabled */ @@ -1793,6 +1844,9 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) prev->ssl_certificate_key, ""); ngx_conf_merge_ptr_value(conf->ssl_passwords, prev->ssl_passwords, NULL); + ngx_conf_merge_ptr_value(conf->ssl_conf_commands, + prev->ssl_conf_commands, NULL); + if (conf->ssl && ngx_http_uwsgi_set_ssl(cf, conf) != NGX_OK) { return NGX_CONF_ERROR; } @@ -2339,6 +2393,17 @@ ngx_http_uwsgi_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } +static char * +ngx_http_uwsgi_ssl_conf_command_check(ngx_conf_t *cf, void *post, void *data) +{ +#ifndef SSL_CONF_FLAG_FILE + return "is not supported on this platform"; +#else + return NGX_CONF_OK; +#endif +} + + static ngx_int_t ngx_http_uwsgi_set_ssl(ngx_conf_t *cf, ngx_http_uwsgi_loc_conf_t *uwcf) { @@ -2416,6 +2481,12 @@ ngx_http_uwsgi_set_ssl(ngx_conf_t *cf, ngx_http_uwsgi_loc_conf_t *uwcf) return NGX_ERROR; } + if (ngx_ssl_conf_commands(cf, uwcf->upstream.ssl, uwcf->ssl_conf_commands) + != NGX_OK) + { + return NGX_ERROR; + } + return NGX_OK; } diff --git a/src/http/modules/ngx_http_xslt_filter_module.c b/src/http/modules/ngx_http_xslt_filter_module.c index b2f107d..8afd656 100644 --- a/src/http/modules/ngx_http_xslt_filter_module.c +++ b/src/http/modules/ngx_http_xslt_filter_module.c @@ -233,6 +233,7 @@ ngx_http_xslt_header_filter(ngx_http_request_t *r) ngx_http_set_ctx(r, ctx, ngx_http_xslt_filter_module); r->main_filter_need_in_memory = 1; + r->allow_ranges = 0; return NGX_OK; } diff --git a/src/http/ngx_http.c b/src/http/ngx_http.c index 79ef9c6..e1d3d00 100644 --- a/src/http/ngx_http.c +++ b/src/http/ngx_http.c @@ -1469,14 +1469,14 @@ ngx_http_server_names(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf, NGX_HASH_WILDCARD_KEY); if (rc == NGX_ERROR) { - return NGX_ERROR; + goto failed; } if (rc == NGX_DECLINED) { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "invalid server name or wildcard \"%V\" on %V", &name[n].name, &addr->opt.addr_text); - return NGX_ERROR; + goto failed; } if (rc == NGX_BUSY) { @@ -1714,7 +1714,6 @@ ngx_http_add_listening(ngx_conf_t *cf, ngx_http_conf_addr_t *addr) cscf = addr->default_server; ls->pool_size = cscf->connection_pool_size; - ls->post_accept_timeout = cscf->client_header_timeout; clcf = cscf->ctx->loc_conf[ngx_http_core_module.ctx_index]; diff --git a/src/http/ngx_http_cache.h b/src/http/ngx_http_cache.h index f9e9664..bb936c5 100644 --- a/src/http/ngx_http_cache.h +++ b/src/http/ngx_http_cache.h @@ -80,6 +80,7 @@ struct ngx_http_cache_s { ngx_str_t vary; u_char variant[NGX_HTTP_CACHE_KEY_LEN]; + size_t buffer_size; size_t header_start; size_t body_start; off_t length; @@ -116,6 +117,7 @@ struct ngx_http_cache_s { unsigned purged:1; unsigned reading:1; unsigned secondary:1; + unsigned update_variant:1; unsigned background:1; unsigned stale_updating:1; @@ -160,6 +162,7 @@ struct ngx_http_file_cache_s { ngx_path_t *path; + off_t min_free; off_t max_size; size_t bsize; diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c index 3671558..6664fa6 100644 --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -495,6 +495,13 @@ static ngx_command_t ngx_http_core_commands[] = { offsetof(ngx_http_core_loc_conf_t, limit_rate_after), NULL }, + { ngx_string("keepalive_time"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_core_loc_conf_t, keepalive_time), + NULL }, + { ngx_string("keepalive_timeout"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12, ngx_http_core_keepalive, @@ -1190,8 +1197,13 @@ ngx_http_core_auth_delay(ngx_http_request_t *r) ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "delaying unauthorized request"); - if (ngx_handle_read_event(r->connection->read, 0) != NGX_OK) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; + if (r->connection->read->ready) { + ngx_post_event(r->connection->read, &ngx_posted_events); + + } else { + if (ngx_handle_read_event(r->connection->read, 0) != NGX_OK) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } } r->read_event_handler = ngx_http_test_reading; @@ -1330,6 +1342,11 @@ ngx_http_update_location_config(ngx_http_request_t *r) } else if (r->connection->requests >= clcf->keepalive_requests) { r->keepalive = 0; + } else if (ngx_current_msec - r->connection->start_time + > clcf->keepalive_time) + { + r->keepalive = 0; + } else if (r->headers_in.msie6 && r->method == NGX_HTTP_POST && (clcf->keepalive_disable @@ -1782,7 +1799,7 @@ ngx_http_send_response(ngx_http_request_t *r, ngx_uint_t status, } } - if (r->method == NGX_HTTP_HEAD || (r != r->main && val.len == 0)) { + if (r != r->main && val.len == 0) { return ngx_http_send_header(r); } @@ -3495,6 +3512,7 @@ ngx_http_core_create_loc_conf(ngx_conf_t *cf) clcf->send_timeout = NGX_CONF_UNSET_MSEC; clcf->send_lowat = NGX_CONF_UNSET_SIZE; clcf->postpone_output = NGX_CONF_UNSET_SIZE; + clcf->keepalive_time = NGX_CONF_UNSET_MSEC; clcf->keepalive_timeout = NGX_CONF_UNSET_MSEC; clcf->keepalive_header = NGX_CONF_UNSET; clcf->keepalive_requests = NGX_CONF_UNSET_UINT; @@ -3733,12 +3751,14 @@ ngx_http_core_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) conf->limit_rate_after = prev->limit_rate_after; } + ngx_conf_merge_msec_value(conf->keepalive_time, + prev->keepalive_time, 3600000); ngx_conf_merge_msec_value(conf->keepalive_timeout, prev->keepalive_timeout, 75000); ngx_conf_merge_sec_value(conf->keepalive_header, prev->keepalive_header, 0); ngx_conf_merge_uint_value(conf->keepalive_requests, - prev->keepalive_requests, 100); + prev->keepalive_requests, 1000); ngx_conf_merge_uint_value(conf->lingering_close, prev->lingering_close, NGX_HTTP_LINGERING_ON); ngx_conf_merge_msec_value(conf->lingering_time, @@ -4078,14 +4098,6 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) #endif } - if (ngx_strcmp(value[n].data, "spdy") == 0) { - ngx_conf_log_error(NGX_LOG_WARN, cf, 0, - "invalid parameter \"spdy\": " - "ngx_http_spdy_module was superseded " - "by ngx_http_v2_module"); - continue; - } - if (ngx_strncmp(value[n].data, "so_keepalive=", 13) == 0) { if (ngx_strcmp(&value[n].data[13], "on") == 0) { diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h index 2aadae7..2341fd4 100644 --- a/src/http/ngx_http_core_module.h +++ b/src/http/ngx_http_core_module.h @@ -359,6 +359,7 @@ struct ngx_http_core_loc_conf_s { ngx_msec_t client_body_timeout; /* client_body_timeout */ ngx_msec_t send_timeout; /* send_timeout */ + ngx_msec_t keepalive_time; /* keepalive_time */ ngx_msec_t keepalive_timeout; /* keepalive_timeout */ ngx_msec_t lingering_time; /* lingering_time */ ngx_msec_t lingering_timeout; /* lingering_timeout */ diff --git a/src/http/ngx_http_file_cache.c b/src/http/ngx_http_file_cache.c index ecdf11e..c40093b 100644 --- a/src/http/ngx_http_file_cache.c +++ b/src/http/ngx_http_file_cache.c @@ -294,6 +294,8 @@ ngx_http_file_cache_open(ngx_http_request_t *r) cln->data = c; } + c->buffer_size = c->body_start; + rc = ngx_http_file_cache_exists(cache, c); ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, @@ -852,7 +854,7 @@ ngx_http_file_cache_exists(ngx_http_file_cache_t *cache, ngx_http_cache_t *c) if (fcn->exists || fcn->uses >= c->min_uses) { c->exists = fcn->exists; - if (fcn->body_start) { + if (fcn->body_start && !c->update_variant) { c->body_start = fcn->body_start; } @@ -1230,7 +1232,7 @@ ngx_http_file_cache_reopen(ngx_http_request_t *r, ngx_http_cache_t *c) c->secondary = 1; c->file.name.len = 0; - c->body_start = c->buf->end - c->buf->start; + c->body_start = c->buffer_size; ngx_memcpy(c->key, c->variant, NGX_HTTP_CACHE_KEY_LEN); @@ -1337,6 +1339,7 @@ ngx_http_file_cache_update_variant(ngx_http_request_t *r, ngx_http_cache_t *c) ngx_shmtx_unlock(&cache->shpool->mutex); c->file.name.len = 0; + c->update_variant = 1; ngx_memcpy(c->key, c->main, NGX_HTTP_CACHE_KEY_LEN); @@ -1959,7 +1962,7 @@ ngx_http_file_cache_manager(void *data) { ngx_http_file_cache_t *cache = data; - off_t size; + off_t size, free; time_t wait; ngx_msec_t elapsed, next; ngx_uint_t count, watermark; @@ -1988,7 +1991,19 @@ ngx_http_file_cache_manager(void *data) size, count, (ngx_int_t) watermark); if (size < cache->max_size && count < watermark) { - break; + + if (!cache->min_free) { + break; + } + + free = ngx_fs_available(cache->path->name.data); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "http file cache free: %O", free); + + if (free > cache->min_free) { + break; + } } wait = ngx_http_file_cache_forced_expire(cache); @@ -2304,7 +2319,7 @@ ngx_http_file_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { char *confp = conf; - off_t max_size; + off_t max_size, min_free; u_char *last, *p; time_t inactive; ssize_t size; @@ -2341,6 +2356,7 @@ ngx_http_file_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) name.len = 0; size = 0; max_size = NGX_MAX_OFF_T_VALUE; + min_free = 0; value = cf->args->elts; @@ -2476,6 +2492,29 @@ ngx_http_file_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) continue; } + if (ngx_strncmp(value[i].data, "min_free=", 9) == 0) { + +#if (NGX_WIN32 || NGX_HAVE_STATFS || NGX_HAVE_STATVFS) + + s.len = value[i].len - 9; + s.data = value[i].data + 9; + + min_free = ngx_parse_offset(&s); + if (min_free < 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid min_free value \"%V\"", &value[i]); + return NGX_CONF_ERROR; + } + +#else + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "min_free is not supported " + "on this platform, ignored"); +#endif + + continue; + } + if (ngx_strncmp(value[i].data, "loader_files=", 13) == 0) { loader_files = ngx_atoi(value[i].data + 13, value[i].len - 13); @@ -2607,6 +2646,7 @@ ngx_http_file_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) cache->inactive = inactive; cache->max_size = max_size; + cache->min_free = min_free; caches = (ngx_array_t *) (confp + cmd->offset); diff --git a/src/http/ngx_http_parse.c b/src/http/ngx_http_parse.c index cfc42f9..20ad89a 100644 --- a/src/http/ngx_http_parse.c +++ b/src/http/ngx_http_parse.c @@ -380,6 +380,12 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) r->uri_start = p; state = sw_after_slash_in_uri; break; + case '?': + r->uri_start = p; + r->args_start = p + 1; + r->empty_path_in_uri = 1; + state = sw_uri; + break; case ' ': /* * use single "/" from request line to preserve pointers, @@ -446,6 +452,13 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) r->uri_start = p; state = sw_after_slash_in_uri; break; + case '?': + r->port_end = p; + r->uri_start = p; + r->args_start = p + 1; + r->empty_path_in_uri = 1; + state = sw_uri; + break; case ' ': r->port_end = p; /* @@ -1287,6 +1300,10 @@ ngx_http_parse_complex_uri(ngx_http_request_t *r, ngx_uint_t merge_slashes) r->uri_ext = NULL; r->args_start = NULL; + if (r->empty_path_in_uri) { + *u++ = '/'; + } + ch = *p++; while (p <= r->uri_end) { diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index eb53996..136c461 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -49,7 +49,7 @@ static void ngx_http_request_finalizer(ngx_http_request_t *r); static void ngx_http_set_keepalive(ngx_http_request_t *r); static void ngx_http_keepalive_handler(ngx_event_t *ev); -static void ngx_http_set_lingering_close(ngx_http_request_t *r); +static void ngx_http_set_lingering_close(ngx_connection_t *c); static void ngx_http_lingering_close_handler(ngx_event_t *ev); static ngx_int_t ngx_http_post_action(ngx_http_request_t *r); static void ngx_http_close_request(ngx_http_request_t *r, ngx_int_t error); @@ -206,16 +206,17 @@ ngx_http_header_t ngx_http_headers_in[] = { void ngx_http_init_connection(ngx_connection_t *c) { - ngx_uint_t i; - ngx_event_t *rev; - struct sockaddr_in *sin; - ngx_http_port_t *port; - ngx_http_in_addr_t *addr; - ngx_http_log_ctx_t *ctx; - ngx_http_connection_t *hc; + ngx_uint_t i; + ngx_event_t *rev; + struct sockaddr_in *sin; + ngx_http_port_t *port; + ngx_http_in_addr_t *addr; + ngx_http_log_ctx_t *ctx; + ngx_http_connection_t *hc; + ngx_http_core_srv_conf_t *cscf; #if (NGX_HAVE_INET6) - struct sockaddr_in6 *sin6; - ngx_http_in6_addr_t *addr6; + struct sockaddr_in6 *sin6; + ngx_http_in6_addr_t *addr6; #endif hc = ngx_pcalloc(c->pool, sizeof(ngx_http_connection_t)); @@ -361,7 +362,9 @@ ngx_http_init_connection(ngx_connection_t *c) return; } - ngx_add_timer(rev, c->listening->post_accept_timeout); + cscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_core_module); + + ngx_add_timer(rev, cscf->client_header_timeout); ngx_reusable_connection(c, 1); if (ngx_handle_read_event(rev, 0) != NGX_OK) { @@ -431,7 +434,7 @@ ngx_http_wait_request_handler(ngx_event_t *rev) if (n == NGX_AGAIN) { if (!rev->timer_set) { - ngx_add_timer(rev, c->listening->post_accept_timeout); + ngx_add_timer(rev, cscf->client_header_timeout); ngx_reusable_connection(c, 1); } @@ -649,6 +652,7 @@ ngx_http_ssl_handshake(ngx_event_t *rev) ngx_http_connection_t *hc; ngx_http_ssl_srv_conf_t *sscf; ngx_http_core_loc_conf_t *clcf; + ngx_http_core_srv_conf_t *cscf; c = rev->data; hc = c->data; @@ -680,7 +684,9 @@ ngx_http_ssl_handshake(ngx_event_t *rev) rev->ready = 0; if (!rev->timer_set) { - ngx_add_timer(rev, c->listening->post_accept_timeout); + cscf = ngx_http_get_module_srv_conf(hc->conf_ctx, + ngx_http_core_module); + ngx_add_timer(rev, cscf->client_header_timeout); ngx_reusable_connection(c, 1); } @@ -755,7 +761,9 @@ ngx_http_ssl_handshake(ngx_event_t *rev) if (rc == NGX_AGAIN) { if (!rev->timer_set) { - ngx_add_timer(rev, c->listening->post_accept_timeout); + cscf = ngx_http_get_module_srv_conf(hc->conf_ctx, + ngx_http_core_module); + ngx_add_timer(rev, cscf->client_header_timeout); } c->ssl->handler = ngx_http_ssl_handshake_handler; @@ -871,10 +879,14 @@ ngx_http_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg) return SSL_TLSEXT_ERR_ALERT_FATAL; } + hc = c->data; + servername = SSL_get_servername(ssl_conn, TLSEXT_NAMETYPE_host_name); if (servername == NULL) { - return SSL_TLSEXT_ERR_OK; + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, + "SSL server name: null"); + goto done; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, @@ -883,7 +895,7 @@ ngx_http_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg) host.len = ngx_strlen(servername); if (host.len == 0) { - return SSL_TLSEXT_ERR_OK; + goto done; } host.data = (u_char *) servername; @@ -891,32 +903,27 @@ ngx_http_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg) rc = ngx_http_validate_host(&host, c->pool, 1); if (rc == NGX_ERROR) { - *ad = SSL_AD_INTERNAL_ERROR; - return SSL_TLSEXT_ERR_ALERT_FATAL; + goto error; } if (rc == NGX_DECLINED) { - return SSL_TLSEXT_ERR_OK; + goto done; } - hc = c->data; - rc = ngx_http_find_virtual_server(c, hc->addr_conf->virtual_names, &host, NULL, &cscf); if (rc == NGX_ERROR) { - *ad = SSL_AD_INTERNAL_ERROR; - return SSL_TLSEXT_ERR_ALERT_FATAL; + goto error; } if (rc == NGX_DECLINED) { - return SSL_TLSEXT_ERR_OK; + goto done; } hc->ssl_servername = ngx_palloc(c->pool, sizeof(ngx_str_t)); if (hc->ssl_servername == NULL) { - *ad = SSL_AD_INTERNAL_ERROR; - return SSL_TLSEXT_ERR_ALERT_FATAL; + goto error; } *hc->ssl_servername = host; @@ -932,7 +939,9 @@ ngx_http_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg) c->ssl->buffer_size = sscf->buffer_size; if (sscf->ssl.ctx) { - SSL_set_SSL_CTX(ssl_conn, sscf->ssl.ctx); + if (SSL_set_SSL_CTX(ssl_conn, sscf->ssl.ctx) == NULL) { + goto error; + } /* * SSL_set_SSL_CTX() only changes certs as of 1.0.0d @@ -957,7 +966,22 @@ ngx_http_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg) #endif } +done: + + sscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_ssl_module); + + if (sscf->reject_handshake) { + c->ssl->handshake_rejected = 1; + *ad = SSL_AD_UNRECOGNIZED_NAME; + return SSL_TLSEXT_ERR_ALERT_FATAL; + } + return SSL_TLSEXT_ERR_OK; + +error: + + *ad = SSL_AD_INTERNAL_ERROR; + return SSL_TLSEXT_ERR_ALERT_FATAL; } #endif @@ -1208,9 +1232,13 @@ ngx_http_process_request_uri(ngx_http_request_t *r) r->uri.len = r->uri_end - r->uri_start; } - if (r->complex_uri || r->quoted_uri) { + if (r->complex_uri || r->quoted_uri || r->empty_path_in_uri) { - r->uri.data = ngx_pnalloc(r->pool, r->uri.len + 1); + if (r->empty_path_in_uri) { + r->uri.len++; + } + + r->uri.data = ngx_pnalloc(r->pool, r->uri.len); if (r->uri.data == NULL) { ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return NGX_ERROR; @@ -1234,7 +1262,7 @@ ngx_http_process_request_uri(ngx_http_request_t *r) r->unparsed_uri.len = r->uri_end - r->uri_start; r->unparsed_uri.data = r->uri_start; - r->valid_unparsed_uri = r->space_in_uri ? 0 : 1; + r->valid_unparsed_uri = (r->space_in_uri || r->empty_path_in_uri) ? 0 : 1; if (r->uri_ext) { if (r->args_start) { @@ -1647,6 +1675,12 @@ ngx_http_alloc_large_header_buffer(ngx_http_request_t *r, ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http large header copy: %uz", r->header_in->pos - old); + if (r->header_in->pos - old > b->end - b->start) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "too large header to copy"); + return NGX_ERROR; + } + new = b->start; ngx_memcpy(new, old, r->header_in->pos - old); @@ -1993,6 +2027,7 @@ ngx_http_process_request(ngx_http_request_t *r) if (r->http_connection->ssl) { long rc; X509 *cert; + const char *s; ngx_http_ssl_srv_conf_t *sscf; if (c->ssl == NULL) { @@ -2037,6 +2072,17 @@ ngx_http_process_request(ngx_http_request_t *r) X509_free(cert); } + + if (ngx_ssl_ocsp_get_status(c, &s) != NGX_OK) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "client SSL certificate verify error: %s", s); + + ngx_ssl_remove_cached_session(c->ssl->session_ctx, + (SSL_get0_session(c->ssl->connection))); + + ngx_http_finalize_request(r, NGX_HTTPS_CERT_ERROR); + return; + } } } @@ -2597,11 +2643,6 @@ ngx_http_finalize_request(ngx_http_request_t *r, ngx_int_t rc) ngx_del_timer(c->write); } - if (c->read->eof) { - ngx_http_close_request(r, 0); - return; - } - ngx_http_finalize_connection(r); } @@ -2700,6 +2741,11 @@ ngx_http_finalize_connection(ngx_http_request_t *r) r = r->main; + if (r->connection->read->eof) { + ngx_http_close_request(r, 0); + return; + } + if (r->reading_body) { r->keepalive = 0; r->lingering_close = 1; @@ -2720,7 +2766,7 @@ ngx_http_finalize_connection(ngx_http_request_t *r) || r->header_in->pos < r->header_in->last || r->connection->read->ready))) { - ngx_http_set_lingering_close(r); + ngx_http_set_lingering_close(r->connection); return; } @@ -2974,6 +3020,12 @@ closed: rev->error = 1; } +#if (NGX_HTTP_SSL) + if (c->ssl) { + c->ssl->no_send_shutdown = 1; + } +#endif + ngx_log_error(NGX_LOG_INFO, c->log, err, "client prematurely closed connection"); @@ -2999,13 +3051,6 @@ ngx_http_set_keepalive(ngx_http_request_t *r) ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "set http keepalive handler"); - if (r->discard_body) { - r->write_event_handler = ngx_http_request_empty_handler; - r->lingering_time = ngx_time() + (time_t) (clcf->lingering_time / 1000); - ngx_add_timer(rev, clcf->lingering_timeout); - return; - } - c->log->action = "closing request"; hc = r->http_connection; @@ -3335,22 +3380,43 @@ ngx_http_keepalive_handler(ngx_event_t *rev) static void -ngx_http_set_lingering_close(ngx_http_request_t *r) +ngx_http_set_lingering_close(ngx_connection_t *c) { ngx_event_t *rev, *wev; - ngx_connection_t *c; + ngx_http_request_t *r; ngx_http_core_loc_conf_t *clcf; - c = r->connection; + r = c->data; clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + if (r->lingering_time == 0) { + r->lingering_time = ngx_time() + (time_t) (clcf->lingering_time / 1000); + } + +#if (NGX_HTTP_SSL) + if (c->ssl) { + ngx_int_t rc; + + c->ssl->shutdown_without_free = 1; + + rc = ngx_ssl_shutdown(c); + + if (rc == NGX_ERROR) { + ngx_http_close_request(r, 0); + return; + } + + if (rc == NGX_AGAIN) { + c->ssl->handler = ngx_http_set_lingering_close; + return; + } + } +#endif + rev = c->read; rev->handler = ngx_http_lingering_close_handler; - r->lingering_time = ngx_time() + (time_t) (clcf->lingering_time / 1000); - ngx_add_timer(rev, clcf->lingering_timeout); - if (ngx_handle_read_event(rev, 0) != NGX_OK) { ngx_http_close_request(r, 0); return; @@ -3373,6 +3439,11 @@ ngx_http_set_lingering_close(ngx_http_request_t *r) return; } + c->close = 0; + ngx_reusable_connection(c, 1); + + ngx_add_timer(rev, clcf->lingering_timeout); + if (rev->ready) { ngx_http_lingering_close_handler(rev); } @@ -3395,7 +3466,7 @@ ngx_http_lingering_close_handler(ngx_event_t *rev) ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http lingering close handler"); - if (rev->timedout) { + if (rev->timedout || c->close) { ngx_http_close_request(r, 0); return; } diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h index 70c2d42..6dfb4a4 100644 --- a/src/http/ngx_http_request.h +++ b/src/http/ngx_http_request.h @@ -470,6 +470,9 @@ struct ngx_http_request_s { /* URI with " " */ unsigned space_in_uri:1; + /* URI with empty path */ + unsigned empty_path_in_uri:1; + unsigned invalid_header:1; unsigned add_uri_to_alias:1; diff --git a/src/http/ngx_http_request_body.c b/src/http/ngx_http_request_body.c index c4f092e..0cae88f 100644 --- a/src/http/ngx_http_request_body.c +++ b/src/http/ngx_http_request_body.c @@ -12,6 +12,8 @@ static void ngx_http_read_client_request_body_handler(ngx_http_request_t *r); static ngx_int_t ngx_http_do_read_client_request_body(ngx_http_request_t *r); +static ngx_int_t ngx_http_copy_pipelined_header(ngx_http_request_t *r, + ngx_buf_t *buf); static ngx_int_t ngx_http_write_request_body(ngx_http_request_t *r); static ngx_int_t ngx_http_read_discarded_request_body(ngx_http_request_t *r); static ngx_int_t ngx_http_discard_request_body_filter(ngx_http_request_t *r, @@ -135,8 +137,9 @@ ngx_http_read_client_request_body(ngx_http_request_t *r, } else { /* set rb->rest */ - if (ngx_http_request_body_filter(r, NULL) != NGX_OK) { - rc = NGX_HTTP_INTERNAL_SERVER_ERROR; + rc = ngx_http_request_body_filter(r, NULL); + + if (rc != NGX_OK) { goto done; } } @@ -282,28 +285,12 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r) for ( ;; ) { if (rb->buf->last == rb->buf->end) { - if (rb->buf->pos != rb->buf->last) { + /* update chains */ - /* pass buffer to request body filter chain */ + rc = ngx_http_request_body_filter(r, NULL); - out.buf = rb->buf; - out.next = NULL; - - rc = ngx_http_request_body_filter(r, &out); - - if (rc != NGX_OK) { - return rc; - } - - } else { - - /* update chains */ - - rc = ngx_http_request_body_filter(r, NULL); - - if (rc != NGX_OK) { - return rc; - } + if (rc != NGX_OK) { + return rc; } if (rb->busy != NULL) { @@ -319,6 +306,9 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r) return NGX_AGAIN; } + ngx_log_error(NGX_LOG_ALERT, c->log, 0, + "busy buffers after request body flush"); + return NGX_HTTP_INTERNAL_SERVER_ERROR; } @@ -355,17 +345,15 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r) rb->buf->last += n; r->request_length += n; - if (n == rest) { - /* pass buffer to request body filter chain */ + /* pass buffer to request body filter chain */ - out.buf = rb->buf; - out.next = NULL; + out.buf = rb->buf; + out.next = NULL; - rc = ngx_http_request_body_filter(r, &out); + rc = ngx_http_request_body_filter(r, &out); - if (rc != NGX_OK) { - return rc; - } + if (rc != NGX_OK) { + return rc; } if (rb->rest == 0) { @@ -386,21 +374,6 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r) if (!c->read->ready) { - if (r->request_body_no_buffering - && rb->buf->pos != rb->buf->last) - { - /* pass buffer to request body filter chain */ - - out.buf = rb->buf; - out.next = NULL; - - rc = ngx_http_request_body_filter(r, &out); - - if (rc != NGX_OK) { - return rc; - } - } - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); ngx_add_timer(c->read, clcf->client_body_timeout); @@ -412,6 +385,10 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r) } } + if (ngx_http_copy_pipelined_header(r, rb->buf) != NGX_OK) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + if (c->read->timer_set) { ngx_del_timer(c->read); } @@ -425,6 +402,88 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r) } +static ngx_int_t +ngx_http_copy_pipelined_header(ngx_http_request_t *r, ngx_buf_t *buf) +{ + size_t n; + ngx_buf_t *b; + ngx_chain_t *cl; + ngx_http_connection_t *hc; + ngx_http_core_srv_conf_t *cscf; + + b = r->header_in; + n = buf->last - buf->pos; + + if (buf == b || n == 0) { + return NGX_OK; + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http body pipelined header: %uz", n); + + /* + * if there is a pipelined request in the client body buffer, + * copy it to the r->header_in buffer if there is enough room, + * or allocate a large client header buffer + */ + + if (n > (size_t) (b->end - b->last)) { + + hc = r->http_connection; + + if (hc->free) { + cl = hc->free; + hc->free = cl->next; + + b = cl->buf; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http large header free: %p %uz", + b->pos, b->end - b->last); + + } else { + cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); + + b = ngx_create_temp_buf(r->connection->pool, + cscf->large_client_header_buffers.size); + if (b == NULL) { + return NGX_ERROR; + } + + cl = ngx_alloc_chain_link(r->connection->pool); + if (cl == NULL) { + return NGX_ERROR; + } + + cl->buf = b; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http large header alloc: %p %uz", + b->pos, b->end - b->last); + } + + cl->next = hc->busy; + hc->busy = cl; + hc->nbusy++; + + r->header_in = b; + + if (n > (size_t) (b->end - b->last)) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "too large pipelined header after reading body"); + return NGX_ERROR; + } + } + + ngx_memcpy(b->last, buf->pos, n); + + b->last += n; + r->request_length -= n; + + return NGX_OK; +} + + static ngx_int_t ngx_http_write_request_body(ngx_http_request_t *r) { @@ -619,6 +678,7 @@ ngx_http_discarded_request_body_handler(ngx_http_request_t *r) if (rc == NGX_OK) { r->discard_body = 0; r->lingering_close = 0; + r->lingering_time = 0; ngx_http_finalize_request(r, NGX_DONE); return; } @@ -670,8 +730,7 @@ ngx_http_read_discarded_request_body(ngx_http_request_t *r) for ( ;; ) { if (r->headers_in.content_length_n == 0) { - r->read_event_handler = ngx_http_block_reading; - return NGX_OK; + break; } if (!r->connection->read->ready) { @@ -705,15 +764,24 @@ ngx_http_read_discarded_request_body(ngx_http_request_t *r) return rc; } } + + if (ngx_http_copy_pipelined_header(r, &b) != NGX_OK) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + r->read_event_handler = ngx_http_block_reading; + + return NGX_OK; } static ngx_int_t ngx_http_discard_request_body_filter(ngx_http_request_t *r, ngx_buf_t *b) { - size_t size; - ngx_int_t rc; - ngx_http_request_body_t *rb; + size_t size; + ngx_int_t rc; + ngx_http_request_body_t *rb; + ngx_http_core_srv_conf_t *cscf; if (r->headers_in.chunked) { @@ -768,7 +836,10 @@ ngx_http_discard_request_body_filter(ngx_http_request_t *r, ngx_buf_t *b) /* set amount of data we want to see next time */ - r->headers_in.content_length_n = rb->chunked->length; + cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); + + r->headers_in.content_length_n = ngx_max(rb->chunked->length, + (off_t) cscf->large_client_header_buffers.size); break; } @@ -936,6 +1007,7 @@ ngx_http_request_body_chunked_filter(ngx_http_request_t *r, ngx_chain_t *in) ngx_chain_t *cl, *out, *tl, **ll; ngx_http_request_body_t *rb; ngx_http_core_loc_conf_t *clcf; + ngx_http_core_srv_conf_t *cscf; rb = r->request_body; @@ -949,8 +1021,10 @@ ngx_http_request_body_chunked_filter(ngx_http_request_t *r, ngx_chain_t *in) return NGX_HTTP_INTERNAL_SERVER_ERROR; } + cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); + r->headers_in.content_length_n = 0; - rb->rest = 3; + rb->rest = cscf->large_client_header_buffers.size; } out = NULL; @@ -958,6 +1032,8 @@ ngx_http_request_body_chunked_filter(ngx_http_request_t *r, ngx_chain_t *in) for (cl = in; cl; cl = cl->next) { + b = NULL; + for ( ;; ) { ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0, @@ -992,6 +1068,29 @@ ngx_http_request_body_chunked_filter(ngx_http_request_t *r, ngx_chain_t *in) return NGX_HTTP_REQUEST_ENTITY_TOO_LARGE; } + if (b + && rb->chunked->size <= 128 + && cl->buf->last - cl->buf->pos >= rb->chunked->size) + { + r->headers_in.content_length_n += rb->chunked->size; + + if (rb->chunked->size < 8) { + + while (rb->chunked->size) { + *b->last++ = *cl->buf->pos++; + rb->chunked->size--; + } + + } else { + ngx_memmove(b->last, cl->buf->pos, rb->chunked->size); + b->last += rb->chunked->size; + cl->buf->pos += rb->chunked->size; + rb->chunked->size = 0; + } + + continue; + } + tl = ngx_chain_get_free_buf(r->pool, &rb->free); if (tl == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; @@ -1057,7 +1156,10 @@ ngx_http_request_body_chunked_filter(ngx_http_request_t *r, ngx_chain_t *in) /* set rb->rest, amount of data we want to see next time */ - rb->rest = rb->chunked->length; + cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); + + rb->rest = ngx_max(rb->chunked->length, + (off_t) cscf->large_client_header_buffers.size); break; } diff --git a/src/http/ngx_http_special_response.c b/src/http/ngx_http_special_response.c index 76e6705..72f56fd 100644 --- a/src/http/ngx_http_special_response.c +++ b/src/http/ngx_http_special_response.c @@ -575,6 +575,10 @@ ngx_http_clean_header(ngx_http_request_t *r) r->headers_out.headers.part.next = NULL; r->headers_out.headers.last = &r->headers_out.headers.part; + r->headers_out.trailers.part.nelts = 0; + r->headers_out.trailers.part.next = NULL; + r->headers_out.trailers.last = &r->headers_out.trailers.part; + r->headers_out.content_length_n = -1; r->headers_out.last_modified_time = -1; } diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c index 89e1319..b682af5 100644 --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -77,9 +77,6 @@ static void static void ngx_http_upstream_process_non_buffered_request(ngx_http_request_t *r, ngx_uint_t do_write); -static ngx_int_t ngx_http_upstream_non_buffered_filter_init(void *data); -static ngx_int_t ngx_http_upstream_non_buffered_filter(void *data, - ssize_t bytes); #if (NGX_THREADS) static ngx_int_t ngx_http_upstream_thread_handler(ngx_thread_task_t *task, ngx_file_t *file); @@ -610,6 +607,17 @@ ngx_http_upstream_init_request(ngx_http_request_t *r) u->store = u->conf->store; if (!u->store && !r->post_action && !u->conf->ignore_client_abort) { + + if (r->connection->read->ready) { + ngx_post_event(r->connection->read, &ngx_posted_events); + + } else { + if (ngx_handle_read_event(r->connection->read, 0) != NGX_OK) { + ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + } + r->read_event_handler = ngx_http_upstream_rd_check_broken_connection; r->write_event_handler = ngx_http_upstream_wr_check_broken_connection; } @@ -1919,6 +1927,7 @@ ngx_http_upstream_reinit(ngx_http_request_t *r, ngx_http_upstream_t *u) u->keepalive = 0; u->upgrade = 0; + u->error = 0; ngx_memzero(&u->headers_in, sizeof(ngx_http_upstream_headers_in_t)); u->headers_in.content_length_n = -1; @@ -2053,6 +2062,10 @@ ngx_http_upstream_send_request(ngx_http_request_t *r, ngx_http_upstream_t *u, c->tcp_nopush = NGX_TCP_NOPUSH_UNSET; } + if (c->read->ready) { + ngx_post_event(c->read, &ngx_posted_events); + } + return; } @@ -2475,7 +2488,7 @@ ngx_http_upstream_test_next(ngx_http_request_t *r, ngx_http_upstream_t *u) #if (NGX_HTTP_CACHE) if (u->cache_status == NGX_HTTP_CACHE_EXPIRED - && ((u->conf->cache_use_stale & un->mask) || r->cache->stale_error)) + && (u->conf->cache_use_stale & un->mask)) { ngx_int_t rc; @@ -2502,6 +2515,8 @@ ngx_http_upstream_test_next(ngx_http_request_t *r, ngx_http_upstream_t *u) } #endif + + break; } #if (NGX_HTTP_CACHE) @@ -3011,9 +3026,7 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u) return; } - if (u->peer.connection->read->ready || u->length == 0) { - ngx_http_upstream_process_non_buffered_upstream(r, u); - } + ngx_http_upstream_process_non_buffered_upstream(r, u); } return; @@ -3625,7 +3638,7 @@ ngx_http_upstream_process_non_buffered_request(ngx_http_request_t *r, return; } - if (upstream->read->error) { + if (upstream->read->error || u->error) { ngx_http_upstream_finalize_request(r, u, NGX_HTTP_BAD_GATEWAY); return; @@ -3703,14 +3716,14 @@ ngx_http_upstream_process_non_buffered_request(ngx_http_request_t *r, } -static ngx_int_t +ngx_int_t ngx_http_upstream_non_buffered_filter_init(void *data) { return NGX_OK; } -static ngx_int_t +ngx_int_t ngx_http_upstream_non_buffered_filter(void *data, ssize_t bytes) { ngx_http_request_t *r = data; @@ -3721,6 +3734,13 @@ ngx_http_upstream_non_buffered_filter(void *data, ssize_t bytes) u = r->upstream; + if (u->length == 0) { + ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, + "upstream sent more data than specified in " + "\"Content-Length\" header"); + return NGX_OK; + } + for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) { ll = &cl->next; } @@ -3746,6 +3766,18 @@ ngx_http_upstream_non_buffered_filter(void *data, ssize_t bytes) return NGX_OK; } + if (bytes > u->length) { + + ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, + "upstream sent more data than specified in " + "\"Content-Length\" header"); + + cl->buf->last = cl->buf->pos + u->length; + u->length = 0; + + return NGX_OK; + } + u->length -= bytes; return NGX_OK; diff --git a/src/http/ngx_http_upstream.h b/src/http/ngx_http_upstream.h index 6079d72..fd642c2 100644 --- a/src/http/ngx_http_upstream.h +++ b/src/http/ngx_http_upstream.h @@ -391,6 +391,7 @@ struct ngx_http_upstream_s { unsigned buffering:1; unsigned keepalive:1; unsigned upgrade:1; + unsigned error:1; unsigned request_sent:1; unsigned request_body_sent:1; @@ -414,6 +415,8 @@ typedef struct { ngx_int_t ngx_http_upstream_create(ngx_http_request_t *r); void ngx_http_upstream_init(ngx_http_request_t *r); +ngx_int_t ngx_http_upstream_non_buffered_filter_init(void *data); +ngx_int_t ngx_http_upstream_non_buffered_filter(void *data, ssize_t bytes); ngx_http_upstream_srv_conf_t *ngx_http_upstream_add(ngx_conf_t *cf, ngx_url_t *u, ngx_uint_t flags); char *ngx_http_upstream_bind_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, diff --git a/src/http/ngx_http_upstream_round_robin.c b/src/http/ngx_http_upstream_round_robin.c index 8e7b4ea..1f15fae 100644 --- a/src/http/ngx_http_upstream_round_robin.c +++ b/src/http/ngx_http_upstream_round_robin.c @@ -10,8 +10,8 @@ #include -#define ngx_http_upstream_tries(p) ((p)->number \ - + ((p)->next ? (p)->next->number : 0)) +#define ngx_http_upstream_tries(p) ((p)->tries \ + + ((p)->next ? (p)->next->tries : 0)) static ngx_http_upstream_rr_peer_t *ngx_http_upstream_get_peer( @@ -32,7 +32,7 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf, ngx_http_upstream_srv_conf_t *us) { ngx_url_t u; - ngx_uint_t i, j, n, w; + ngx_uint_t i, j, n, w, t; ngx_http_upstream_server_t *server; ngx_http_upstream_rr_peer_t *peer, **peerp; ngx_http_upstream_rr_peers_t *peers, *backup; @@ -44,6 +44,7 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf, n = 0; w = 0; + t = 0; for (i = 0; i < us->servers->nelts; i++) { if (server[i].backup) { @@ -52,6 +53,10 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf, n += server[i].naddrs; w += server[i].naddrs * server[i].weight; + + if (!server[i].down) { + t += server[i].naddrs; + } } if (n == 0) { @@ -75,6 +80,7 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf, peers->number = n; peers->weighted = (w != n); peers->total_weight = w; + peers->tries = t; peers->name = &us->host; n = 0; @@ -110,6 +116,7 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf, n = 0; w = 0; + t = 0; for (i = 0; i < us->servers->nelts; i++) { if (!server[i].backup) { @@ -118,6 +125,10 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf, n += server[i].naddrs; w += server[i].naddrs * server[i].weight; + + if (!server[i].down) { + t += server[i].naddrs; + } } if (n == 0) { @@ -139,6 +150,7 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf, backup->number = n; backup->weighted = (w != n); backup->total_weight = w; + backup->tries = t; backup->name = &us->host; n = 0; @@ -214,6 +226,7 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf, peers->number = n; peers->weighted = 0; peers->total_weight = n; + peers->tries = n; peers->name = &us->host; peerp = &peers->peer; @@ -332,6 +345,7 @@ ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r, peers->single = (ur->naddrs == 1); peers->number = ur->naddrs; + peers->tries = ur->naddrs; peers->name = &ur->host; if (ur->sockaddr) { diff --git a/src/http/ngx_http_upstream_round_robin.h b/src/http/ngx_http_upstream_round_robin.h index 45f258d..922ceaa 100644 --- a/src/http/ngx_http_upstream_round_robin.h +++ b/src/http/ngx_http_upstream_round_robin.h @@ -68,6 +68,7 @@ struct ngx_http_upstream_rr_peers_s { #endif ngx_uint_t total_weight; + ngx_uint_t tries; unsigned single:1; unsigned weighted:1; diff --git a/src/http/ngx_http_variables.c b/src/http/ngx_http_variables.c index e067cf0..942dacd 100644 --- a/src/http/ngx_http_variables.c +++ b/src/http/ngx_http_variables.c @@ -129,6 +129,8 @@ static ngx_int_t ngx_http_variable_connection(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_variable_connection_requests(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_http_variable_connection_time(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_variable_nginx_version(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); @@ -342,6 +344,9 @@ static ngx_http_variable_t ngx_http_core_variables[] = { { ngx_string("connection_requests"), NULL, ngx_http_variable_connection_requests, 0, 0, 0 }, + { ngx_string("connection_time"), NULL, ngx_http_variable_connection_time, + 0, NGX_HTTP_VAR_NOCACHEABLE, 0 }, + { ngx_string("nginx_version"), NULL, ngx_http_variable_nginx_version, 0, 0, 0 }, @@ -1075,7 +1080,7 @@ ngx_http_variable_argument(ngx_http_request_t *r, ngx_http_variable_value_t *v, len = name->len - (sizeof("arg_") - 1); arg = name->data + sizeof("arg_") - 1; - if (ngx_http_arg(r, arg, len, &value) != NGX_OK) { + if (len == 0 || ngx_http_arg(r, arg, len, &value) != NGX_OK) { v->not_found = 1; return NGX_OK; } @@ -1174,6 +1179,10 @@ ngx_http_variable_content_length(ngx_http_request_t *r, v->no_cacheable = 0; v->not_found = 0; + } else if (r->headers_in.chunked) { + v->not_found = 1; + v->no_cacheable = 1; + } else { v->not_found = 1; } @@ -2252,6 +2261,31 @@ ngx_http_variable_connection_requests(ngx_http_request_t *r, } +static ngx_int_t +ngx_http_variable_connection_time(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + u_char *p; + ngx_msec_int_t ms; + + p = ngx_pnalloc(r->pool, NGX_TIME_T_LEN + 4); + if (p == NULL) { + return NGX_ERROR; + } + + ms = ngx_current_msec - r->connection->start_time; + ms = ngx_max(ms, 0); + + v->len = ngx_sprintf(p, "%T.%03M", (time_t) ms / 1000, ms % 1000) - p; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = p; + + return NGX_OK; +} + + static ngx_int_t ngx_http_variable_nginx_version(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c index 8b0fc53..3611a2e 100644 --- a/src/http/v2/ngx_http_v2.c +++ b/src/http/v2/ngx_http_v2.c @@ -60,6 +60,8 @@ typedef struct { static void ngx_http_v2_read_handler(ngx_event_t *rev); static void ngx_http_v2_write_handler(ngx_event_t *wev); static void ngx_http_v2_handle_connection(ngx_http_v2_connection_t *h2c); +static void ngx_http_v2_lingering_close(ngx_connection_t *c); +static void ngx_http_v2_lingering_close_handler(ngx_event_t *rev); static u_char *ngx_http_v2_state_proxy_protocol(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end); @@ -236,6 +238,7 @@ ngx_http_v2_init(ngx_event_t *rev) ngx_http_v2_srv_conf_t *h2scf; ngx_http_v2_main_conf_t *h2mcf; ngx_http_v2_connection_t *h2c; + ngx_http_core_srv_conf_t *cscf; c = rev->data; hc = c->data; @@ -274,7 +277,7 @@ ngx_http_v2_init(ngx_event_t *rev) h2scf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_v2_module); h2c->concurrent_pushes = h2scf->concurrent_pushes; - h2c->priority_limit = h2scf->concurrent_streams; + h2c->priority_limit = ngx_max(h2scf->concurrent_streams, 100); h2c->pool = ngx_create_pool(h2scf->pool_size, h2c->connection->log); if (h2c->pool == NULL) { @@ -323,7 +326,14 @@ ngx_http_v2_init(ngx_event_t *rev) rev->handler = ngx_http_v2_read_handler; c->write->handler = ngx_http_v2_write_handler; + if (!rev->timer_set) { + cscf = ngx_http_get_module_srv_conf(hc->conf_ctx, + ngx_http_core_module); + ngx_add_timer(rev, cscf->client_header_timeout); + } + c->idle = 1; + ngx_reusable_connection(c, 0); ngx_http_v2_read_handler(rev); } @@ -360,6 +370,11 @@ ngx_http_v2_read_handler(ngx_event_t *rev) return; } + if (!h2c->processing && !h2c->pushing) { + ngx_http_v2_finalize_connection(h2c, NGX_HTTP_V2_NO_ERROR); + return; + } + if (!h2c->goaway) { h2c->goaway = 1; @@ -447,14 +462,6 @@ ngx_http_v2_read_handler(ngx_event_t *rev) h2c->blocked = 0; - if (h2c->processing || h2c->pushing) { - if (rev->timer_set) { - ngx_del_timer(rev); - } - - return; - } - ngx_http_v2_handle_connection(h2c); } @@ -473,6 +480,7 @@ ngx_http_v2_write_handler(ngx_event_t *wev) ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http2 write event timed out"); c->error = 1; + c->timedout = 1; ngx_http_v2_finalize_connection(h2c, 0); return; } @@ -626,9 +634,9 @@ error: static void ngx_http_v2_handle_connection(ngx_http_v2_connection_t *h2c) { - ngx_int_t rc; - ngx_connection_t *c; - ngx_http_v2_srv_conf_t *h2scf; + ngx_int_t rc; + ngx_connection_t *c; + ngx_http_core_loc_conf_t *clcf; if (h2c->last_out || h2c->processing || h2c->pushing) { return; @@ -661,14 +669,20 @@ ngx_http_v2_handle_connection(ngx_http_v2_connection_t *h2c) } if (h2c->goaway) { - ngx_http_close_connection(c); + ngx_http_v2_lingering_close(c); return; } - h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, - ngx_http_v2_module); + clcf = ngx_http_get_module_loc_conf(h2c->http_connection->conf_ctx, + ngx_http_core_module); + + if (!c->read->timer_set) { + ngx_add_timer(c->read, clcf->keepalive_timeout); + } + + ngx_reusable_connection(c, 1); + if (h2c->state.incomplete) { - ngx_add_timer(c->read, h2scf->recv_timeout); return; } @@ -686,7 +700,6 @@ ngx_http_v2_handle_connection(ngx_http_v2_connection_t *h2c) #endif c->destroyed = 1; - ngx_reusable_connection(c, 1); c->write->handler = ngx_http_empty_handler; c->read->handler = ngx_http_v2_idle_handler; @@ -694,8 +707,142 @@ ngx_http_v2_handle_connection(ngx_http_v2_connection_t *h2c) if (c->write->timer_set) { ngx_del_timer(c->write); } +} - ngx_add_timer(c->read, h2scf->idle_timeout); + +static void +ngx_http_v2_lingering_close(ngx_connection_t *c) +{ + ngx_event_t *rev, *wev; + ngx_http_v2_connection_t *h2c; + ngx_http_core_loc_conf_t *clcf; + + h2c = c->data; + + clcf = ngx_http_get_module_loc_conf(h2c->http_connection->conf_ctx, + ngx_http_core_module); + + if (clcf->lingering_close == NGX_HTTP_LINGERING_OFF) { + ngx_http_close_connection(c); + return; + } + + if (h2c->lingering_time == 0) { + h2c->lingering_time = ngx_time() + + (time_t) (clcf->lingering_time / 1000); + } + +#if (NGX_HTTP_SSL) + if (c->ssl) { + ngx_int_t rc; + + rc = ngx_ssl_shutdown(c); + + if (rc == NGX_ERROR) { + ngx_http_close_connection(c); + return; + } + + if (rc == NGX_AGAIN) { + c->ssl->handler = ngx_http_v2_lingering_close; + return; + } + } +#endif + + rev = c->read; + rev->handler = ngx_http_v2_lingering_close_handler; + + if (ngx_handle_read_event(rev, 0) != NGX_OK) { + ngx_http_close_connection(c); + return; + } + + wev = c->write; + wev->handler = ngx_http_empty_handler; + + if (wev->active && (ngx_event_flags & NGX_USE_LEVEL_EVENT)) { + if (ngx_del_event(wev, NGX_WRITE_EVENT, 0) != NGX_OK) { + ngx_http_close_connection(c); + return; + } + } + + if (ngx_shutdown_socket(c->fd, NGX_WRITE_SHUTDOWN) == -1) { + ngx_connection_error(c, ngx_socket_errno, + ngx_shutdown_socket_n " failed"); + ngx_http_close_connection(c); + return; + } + + c->close = 0; + ngx_reusable_connection(c, 1); + + ngx_add_timer(rev, clcf->lingering_timeout); + + if (rev->ready) { + ngx_http_v2_lingering_close_handler(rev); + } +} + + +static void +ngx_http_v2_lingering_close_handler(ngx_event_t *rev) +{ + ssize_t n; + ngx_msec_t timer; + ngx_connection_t *c; + ngx_http_core_loc_conf_t *clcf; + ngx_http_v2_connection_t *h2c; + u_char buffer[NGX_HTTP_LINGERING_BUFFER_SIZE]; + + c = rev->data; + h2c = c->data; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http2 lingering close handler"); + + if (rev->timedout || c->close) { + ngx_http_close_connection(c); + return; + } + + timer = (ngx_msec_t) h2c->lingering_time - (ngx_msec_t) ngx_time(); + if ((ngx_msec_int_t) timer <= 0) { + ngx_http_close_connection(c); + return; + } + + do { + n = c->recv(c, buffer, NGX_HTTP_LINGERING_BUFFER_SIZE); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "lingering read: %z", n); + + if (n == NGX_AGAIN) { + break; + } + + if (n == NGX_ERROR || n == 0) { + ngx_http_close_connection(c); + return; + } + + } while (rev->ready); + + if (ngx_handle_read_event(rev, 0) != NGX_OK) { + ngx_http_close_connection(c); + return; + } + + clcf = ngx_http_get_module_loc_conf(h2c->http_connection->conf_ctx, + ngx_http_core_module); + timer *= 1000; + + if (timer > clcf->lingering_timeout) { + timer = clcf->lingering_timeout; + } + + ngx_add_timer(rev, timer); } @@ -731,9 +878,8 @@ ngx_http_v2_state_preface(ngx_http_v2_connection_t *h2c, u_char *pos, } if (ngx_memcmp(pos, preface, sizeof(preface) - 1) != 0) { - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, - "invalid http2 connection preface \"%*s\"", - sizeof(preface) - 1, pos); + ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, + "invalid connection preface"); return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR); } @@ -754,9 +900,8 @@ ngx_http_v2_state_preface_end(ngx_http_v2_connection_t *h2c, u_char *pos, } if (ngx_memcmp(pos, preface, sizeof(preface) - 1) != 0) { - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, - "invalid http2 connection preface \"%*s\"", - sizeof(preface) - 1, pos); + ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, + "invalid connection preface"); return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR); } @@ -845,6 +990,13 @@ ngx_http_v2_state_data(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end) ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, "http2 DATA frame"); + if (h2c->state.sid == 0) { + ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, + "client sent DATA frame with incorrect identifier"); + + return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR); + } + if (size > h2c->recv_window) { ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, "client violated connection flow control: " @@ -943,6 +1095,7 @@ ngx_http_v2_state_read_data(ngx_http_v2_connection_t *h2c, u_char *pos, size_t size; ngx_buf_t *buf; ngx_int_t rc; + ngx_connection_t *fc; ngx_http_request_t *r; ngx_http_v2_stream_t *stream; ngx_http_v2_srv_conf_t *h2scf; @@ -961,6 +1114,7 @@ ngx_http_v2_state_read_data(ngx_http_v2_connection_t *h2c, u_char *pos, } r = stream->request; + fc = r->connection; if (r->reading_body && !r->request_body_no_buffering) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, @@ -969,6 +1123,13 @@ ngx_http_v2_state_read_data(ngx_http_v2_connection_t *h2c, u_char *pos, return ngx_http_v2_state_skip_padded(h2c, pos, end); } + if (r->headers_in.content_length_n < 0 && !r->headers_in.chunked) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, + "skipping http2 DATA frame"); + + return ngx_http_v2_state_skip_padded(h2c, pos, end); + } + size = end - pos; if (size >= h2c->state.length) { @@ -986,6 +1147,8 @@ ngx_http_v2_state_read_data(ngx_http_v2_connection_t *h2c, u_char *pos, ngx_http_finalize_request(r, rc); } + ngx_http_run_posted_requests(fc); + } else if (size) { buf = stream->preread; @@ -1031,12 +1194,15 @@ static u_char * ngx_http_v2_state_headers(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end) { - size_t size; - ngx_uint_t padded, priority, depend, dependency, excl, weight; - ngx_uint_t status; - ngx_http_v2_node_t *node; - ngx_http_v2_stream_t *stream; - ngx_http_v2_srv_conf_t *h2scf; + size_t size; + ngx_uint_t padded, priority, depend, dependency, excl, + weight; + ngx_uint_t status; + ngx_http_v2_node_t *node; + ngx_http_v2_stream_t *stream; + ngx_http_v2_srv_conf_t *h2scf; + ngx_http_core_srv_conf_t *cscf; + ngx_http_core_loc_conf_t *clcf; padded = h2c->state.flags & NGX_HTTP_V2_PADDED_FLAG; priority = h2c->state.flags & NGX_HTTP_V2_PRIORITY_FLAG; @@ -1137,11 +1303,15 @@ ngx_http_v2_state_headers(ngx_http_v2_connection_t *h2c, u_char *pos, return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR); } + cscf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, + ngx_http_core_module); + + h2c->state.header_limit = cscf->large_client_header_buffers.size + * cscf->large_client_header_buffers.num; + h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, ngx_http_v2_module); - h2c->state.header_limit = h2scf->max_header_size; - if (h2c->processing >= h2scf->concurrent_streams) { ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, "concurrent streams exceeded %ui", h2c->processing); @@ -1195,7 +1365,14 @@ ngx_http_v2_state_headers(ngx_http_v2_connection_t *h2c, u_char *pos, ngx_http_v2_set_dependency(h2c, node, depend, excl); } - if (h2c->connection->requests >= h2scf->max_requests) { + clcf = ngx_http_get_module_loc_conf(h2c->http_connection->conf_ctx, + ngx_http_core_module); + + if (clcf->keepalive_timeout == 0 + || h2c->connection->requests >= clcf->keepalive_requests + || ngx_current_msec - h2c->connection->start_time + > clcf->keepalive_time) + { h2c->goaway = 1; if (ngx_http_v2_send_goaway(h2c, NGX_HTTP_V2_NO_ERROR) == NGX_ERROR) { @@ -1320,10 +1497,10 @@ static u_char * ngx_http_v2_state_field_len(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end) { - size_t alloc; - ngx_int_t len; - ngx_uint_t huff; - ngx_http_v2_srv_conf_t *h2scf; + size_t alloc; + ngx_int_t len; + ngx_uint_t huff; + ngx_http_core_srv_conf_t *cscf; if (!(h2c->state.flags & NGX_HTTP_V2_END_HEADERS_FLAG) && h2c->state.length < NGX_HTTP_V2_INT_OCTETS) @@ -1370,12 +1547,12 @@ ngx_http_v2_state_field_len(ngx_http_v2_connection_t *h2c, u_char *pos, "http2 %s string, len:%i", huff ? "encoded" : "raw", len); - h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, - ngx_http_v2_module); + cscf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, + ngx_http_core_module); - if ((size_t) len > h2scf->max_field_size) { + if ((size_t) len > cscf->large_client_header_buffers.size) { ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, - "client exceeded http2_max_field_size limit"); + "client sent too large header field"); return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_ENHANCE_YOUR_CALM); } @@ -1590,7 +1767,7 @@ ngx_http_v2_state_process_header(ngx_http_v2_connection_t *h2c, u_char *pos, if (len > h2c->state.header_limit) { ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, - "client exceeded http2_max_header_size limit"); + "client sent too large header"); return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_ENHANCE_YOUR_CALM); } @@ -1987,6 +2164,16 @@ static u_char * ngx_http_v2_state_settings(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, + "http2 SETTINGS frame"); + + if (h2c->state.sid) { + ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, + "client sent SETTINGS frame with incorrect identifier"); + + return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR); + } + if (h2c->state.flags == NGX_HTTP_V2_ACK_FLAG) { if (h2c->state.length != 0) { @@ -2010,9 +2197,6 @@ ngx_http_v2_state_settings(ngx_http_v2_connection_t *h2c, u_char *pos, return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR); } - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, - "http2 SETTINGS frame"); - return ngx_http_v2_state_settings_params(h2c, pos, end); } @@ -2161,6 +2345,13 @@ ngx_http_v2_state_ping(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end) ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, "http2 PING frame"); + if (h2c->state.sid) { + ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, + "client sent PING frame with incorrect identifier"); + + return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR); + } + if (h2c->state.flags & NGX_HTTP_V2_ACK_FLAG) { return ngx_http_v2_state_skip(h2c, pos, end); } @@ -2202,6 +2393,13 @@ ngx_http_v2_state_goaway(ngx_http_v2_connection_t *h2c, u_char *pos, return ngx_http_v2_state_save(h2c, pos, end, ngx_http_v2_state_goaway); } + if (h2c->state.sid) { + ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, + "client sent GOAWAY frame with incorrect identifier"); + + return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR); + } + #if (NGX_DEBUG) h2c->state.length -= NGX_HTTP_V2_GOAWAY_SIZE; @@ -3103,6 +3301,10 @@ ngx_http_v2_create_stream(ngx_http_v2_connection_t *h2c, ngx_uint_t push) h2c->priority_limit += h2scf->concurrent_streams; + if (h2c->connection->read->timer_set) { + ngx_del_timer(h2c->connection->read); + } + return stream; } @@ -4469,6 +4671,7 @@ ngx_http_v2_idle_handler(ngx_event_t *rev) ngx_connection_t *c; ngx_http_v2_srv_conf_t *h2scf; ngx_http_v2_connection_t *h2c; + ngx_http_core_loc_conf_t *clcf; c = rev->data; h2c = c->data; @@ -4500,10 +4703,10 @@ ngx_http_v2_idle_handler(ngx_event_t *rev) #endif - h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, - ngx_http_v2_module); + clcf = ngx_http_get_module_loc_conf(h2c->http_connection->conf_ctx, + ngx_http_core_module); - if (h2c->idle++ > 10 * h2scf->max_requests) { + if (h2c->idle++ > 10 * clcf->keepalive_requests) { ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, "http2 flood detected"); ngx_http_v2_finalize_connection(h2c, NGX_HTTP_V2_NO_ERROR); @@ -4513,6 +4716,9 @@ ngx_http_v2_idle_handler(ngx_event_t *rev) c->destroyed = 0; ngx_reusable_connection(c, 0); + h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, + ngx_http_v2_module); + h2c->pool = ngx_create_pool(h2scf->pool_size, h2c->connection->log); if (h2c->pool == NULL) { ngx_http_v2_finalize_connection(h2c, NGX_HTTP_V2_INTERNAL_ERROR); @@ -4543,16 +4749,15 @@ ngx_http_v2_finalize_connection(ngx_http_v2_connection_t *h2c, h2c->blocked = 1; if (!c->error && !h2c->goaway) { + h2c->goaway = 1; + if (ngx_http_v2_send_goaway(h2c, status) != NGX_ERROR) { (void) ngx_http_v2_send_output_queue(h2c); } } - c->error = 1; - if (!h2c->processing && !h2c->pushing) { - ngx_http_close_connection(c); - return; + goto done; } c->read->handler = ngx_http_empty_handler; @@ -4600,10 +4805,18 @@ ngx_http_v2_finalize_connection(ngx_http_v2_connection_t *h2c, h2c->blocked = 0; if (h2c->processing || h2c->pushing) { + c->error = 1; return; } - ngx_http_close_connection(c); +done: + + if (c->error) { + ngx_http_close_connection(c); + return; + } + + ngx_http_v2_lingering_close(c); } diff --git a/src/http/v2/ngx_http_v2.h b/src/http/v2/ngx_http_v2.h index 59ddf54..3492297 100644 --- a/src/http/v2/ngx_http_v2.h +++ b/src/http/v2/ngx_http_v2.h @@ -157,6 +157,8 @@ struct ngx_http_v2_connection_s { ngx_uint_t last_sid; ngx_uint_t last_push; + time_t lingering_time; + unsigned closed_nodes:8; unsigned settings_ack:1; unsigned table_update:1; diff --git a/src/http/v2/ngx_http_v2_module.c b/src/http/v2/ngx_http_v2_module.c index c54dc10..0050886 100644 --- a/src/http/v2/ngx_http_v2_module.c +++ b/src/http/v2/ngx_http_v2_module.c @@ -36,10 +36,31 @@ static char *ngx_http_v2_preread_size(ngx_conf_t *cf, void *post, void *data); static char *ngx_http_v2_streams_index_mask(ngx_conf_t *cf, void *post, void *data); static char *ngx_http_v2_chunk_size(ngx_conf_t *cf, void *post, void *data); -static char *ngx_http_v2_spdy_deprecated(ngx_conf_t *cf, ngx_command_t *cmd, +static char *ngx_http_v2_obsolete(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static ngx_conf_deprecated_t ngx_http_v2_recv_timeout_deprecated = { + ngx_conf_deprecated, "http2_recv_timeout", "client_header_timeout" +}; + +static ngx_conf_deprecated_t ngx_http_v2_idle_timeout_deprecated = { + ngx_conf_deprecated, "http2_idle_timeout", "keepalive_timeout" +}; + +static ngx_conf_deprecated_t ngx_http_v2_max_requests_deprecated = { + ngx_conf_deprecated, "http2_max_requests", "keepalive_requests" +}; + +static ngx_conf_deprecated_t ngx_http_v2_max_field_size_deprecated = { + ngx_conf_deprecated, "http2_max_field_size", "large_client_header_buffers" +}; + +static ngx_conf_deprecated_t ngx_http_v2_max_header_size_deprecated = { + ngx_conf_deprecated, "http2_max_header_size", "large_client_header_buffers" +}; + + static ngx_conf_post_t ngx_http_v2_recv_buffer_size_post = { ngx_http_v2_recv_buffer_size }; static ngx_conf_post_t ngx_http_v2_pool_size_post = @@ -84,24 +105,24 @@ static ngx_command_t ngx_http_v2_commands[] = { { ngx_string("http2_max_requests"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_num_slot, - NGX_HTTP_SRV_CONF_OFFSET, - offsetof(ngx_http_v2_srv_conf_t, max_requests), - NULL }, + ngx_http_v2_obsolete, + 0, + 0, + &ngx_http_v2_max_requests_deprecated }, { ngx_string("http2_max_field_size"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_size_slot, - NGX_HTTP_SRV_CONF_OFFSET, - offsetof(ngx_http_v2_srv_conf_t, max_field_size), - NULL }, + ngx_http_v2_obsolete, + 0, + 0, + &ngx_http_v2_max_field_size_deprecated }, { ngx_string("http2_max_header_size"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_size_slot, - NGX_HTTP_SRV_CONF_OFFSET, - offsetof(ngx_http_v2_srv_conf_t, max_header_size), - NULL }, + ngx_http_v2_obsolete, + 0, + 0, + &ngx_http_v2_max_header_size_deprecated }, { ngx_string("http2_body_preread_size"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, @@ -119,17 +140,17 @@ static ngx_command_t ngx_http_v2_commands[] = { { ngx_string("http2_recv_timeout"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_msec_slot, - NGX_HTTP_SRV_CONF_OFFSET, - offsetof(ngx_http_v2_srv_conf_t, recv_timeout), - NULL }, + ngx_http_v2_obsolete, + 0, + 0, + &ngx_http_v2_recv_timeout_deprecated }, { ngx_string("http2_idle_timeout"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_msec_slot, - NGX_HTTP_SRV_CONF_OFFSET, - offsetof(ngx_http_v2_srv_conf_t, idle_timeout), - NULL }, + ngx_http_v2_obsolete, + 0, + 0, + &ngx_http_v2_idle_timeout_deprecated }, { ngx_string("http2_chunk_size"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, @@ -152,62 +173,6 @@ static ngx_command_t ngx_http_v2_commands[] = { 0, NULL }, - { ngx_string("spdy_recv_buffer_size"), - NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1, - ngx_http_v2_spdy_deprecated, - NGX_HTTP_MAIN_CONF_OFFSET, - 0, - NULL }, - - { ngx_string("spdy_pool_size"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, - ngx_http_v2_spdy_deprecated, - NGX_HTTP_SRV_CONF_OFFSET, - 0, - NULL }, - - { ngx_string("spdy_max_concurrent_streams"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, - ngx_http_v2_spdy_deprecated, - NGX_HTTP_SRV_CONF_OFFSET, - 0, - NULL }, - - { ngx_string("spdy_streams_index_size"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, - ngx_http_v2_spdy_deprecated, - NGX_HTTP_SRV_CONF_OFFSET, - 0, - NULL }, - - { ngx_string("spdy_recv_timeout"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, - ngx_http_v2_spdy_deprecated, - NGX_HTTP_SRV_CONF_OFFSET, - 0, - NULL }, - - { ngx_string("spdy_keepalive_timeout"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, - ngx_http_v2_spdy_deprecated, - NGX_HTTP_SRV_CONF_OFFSET, - 0, - NULL }, - - { ngx_string("spdy_headers_comp"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, - ngx_http_v2_spdy_deprecated, - NGX_HTTP_SRV_CONF_OFFSET, - 0, - NULL }, - - { ngx_string("spdy_chunk_size"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_http_v2_spdy_deprecated, - NGX_HTTP_LOC_CONF_OFFSET, - 0, - NULL }, - ngx_null_command }; @@ -353,18 +318,11 @@ ngx_http_v2_create_srv_conf(ngx_conf_t *cf) h2scf->concurrent_streams = NGX_CONF_UNSET_UINT; h2scf->concurrent_pushes = NGX_CONF_UNSET_UINT; - h2scf->max_requests = NGX_CONF_UNSET_UINT; - - h2scf->max_field_size = NGX_CONF_UNSET_SIZE; - h2scf->max_header_size = NGX_CONF_UNSET_SIZE; h2scf->preread_size = NGX_CONF_UNSET_SIZE; h2scf->streams_index_mask = NGX_CONF_UNSET_UINT; - h2scf->recv_timeout = NGX_CONF_UNSET_MSEC; - h2scf->idle_timeout = NGX_CONF_UNSET_MSEC; - return h2scf; } @@ -381,23 +339,12 @@ ngx_http_v2_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) prev->concurrent_streams, 128); ngx_conf_merge_uint_value(conf->concurrent_pushes, prev->concurrent_pushes, 10); - ngx_conf_merge_uint_value(conf->max_requests, prev->max_requests, 1000); - - ngx_conf_merge_size_value(conf->max_field_size, prev->max_field_size, - 4096); - ngx_conf_merge_size_value(conf->max_header_size, prev->max_header_size, - 16384); ngx_conf_merge_size_value(conf->preread_size, prev->preread_size, 65536); ngx_conf_merge_uint_value(conf->streams_index_mask, prev->streams_index_mask, 32 - 1); - ngx_conf_merge_msec_value(conf->recv_timeout, - prev->recv_timeout, 30000); - ngx_conf_merge_msec_value(conf->idle_timeout, - prev->idle_timeout, 180000); - return NGX_CONF_OK; } @@ -600,11 +547,14 @@ ngx_http_v2_chunk_size(ngx_conf_t *cf, void *post, void *data) static char * -ngx_http_v2_spdy_deprecated(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +ngx_http_v2_obsolete(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { + ngx_conf_deprecated_t *d = cmd->post; + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, - "invalid directive \"%V\": ngx_http_spdy_module " - "was superseded by ngx_http_v2_module", &cmd->name); + "the \"%s\" directive is obsolete, " + "use the \"%s\" directive instead", + d->old_name, d->new_name); return NGX_CONF_OK; } diff --git a/src/http/v2/ngx_http_v2_module.h b/src/http/v2/ngx_http_v2_module.h index cdd2921..ca4a0bf 100644 --- a/src/http/v2/ngx_http_v2_module.h +++ b/src/http/v2/ngx_http_v2_module.h @@ -24,13 +24,8 @@ typedef struct { size_t pool_size; ngx_uint_t concurrent_streams; ngx_uint_t concurrent_pushes; - ngx_uint_t max_requests; - size_t max_field_size; - size_t max_header_size; size_t preread_size; ngx_uint_t streams_index_mask; - ngx_msec_t recv_timeout; - ngx_msec_t idle_timeout; } ngx_http_v2_srv_conf_t; diff --git a/src/mail/ngx_mail.c b/src/mail/ngx_mail.c index f17c2cc..890d815 100644 --- a/src/mail/ngx_mail.c +++ b/src/mail/ngx_mail.c @@ -405,6 +405,7 @@ ngx_mail_add_addrs(ngx_conf_t *cf, ngx_mail_port_t *mport, #if (NGX_MAIL_SSL) addrs[i].conf.ssl = addr[i].opt.ssl; #endif + addrs[i].conf.proxy_protocol = addr[i].opt.proxy_protocol; addrs[i].conf.addr_text = addr[i].opt.addr_text; } @@ -439,6 +440,7 @@ ngx_mail_add_addrs6(ngx_conf_t *cf, ngx_mail_port_t *mport, #if (NGX_MAIL_SSL) addrs6[i].conf.ssl = addr[i].opt.ssl; #endif + addrs6[i].conf.proxy_protocol = addr[i].opt.proxy_protocol; addrs6[i].conf.addr_text = addr[i].opt.addr_text; } diff --git a/src/mail/ngx_mail.h b/src/mail/ngx_mail.h index d904f25..b865a3b 100644 --- a/src/mail/ngx_mail.h +++ b/src/mail/ngx_mail.h @@ -41,6 +41,7 @@ typedef struct { unsigned ipv6only:1; #endif unsigned so_keepalive:2; + unsigned proxy_protocol:1; #if (NGX_HAVE_KEEPALIVE_TUNABLE) int tcp_keepidle; int tcp_keepintvl; @@ -55,7 +56,8 @@ typedef struct { typedef struct { ngx_mail_conf_ctx_t *ctx; ngx_str_t addr_text; - ngx_uint_t ssl; /* unsigned ssl:1; */ + unsigned ssl:1; + unsigned proxy_protocol:1; } ngx_mail_addr_conf_t; typedef struct { @@ -162,10 +164,12 @@ typedef enum { ngx_smtp_auth_external, ngx_smtp_helo, ngx_smtp_helo_xclient, + ngx_smtp_helo_auth, ngx_smtp_helo_from, ngx_smtp_xclient, ngx_smtp_xclient_from, ngx_smtp_xclient_helo, + ngx_smtp_xclient_auth, ngx_smtp_from, ngx_smtp_to } ngx_smtp_state_e; @@ -174,6 +178,7 @@ typedef enum { typedef struct { ngx_peer_connection_t upstream; ngx_buf_t *buffer; + ngx_uint_t proxy_protocol; /* unsigned proxy_protocol:1; */ } ngx_mail_proxy_ctx_t; @@ -195,6 +200,7 @@ typedef struct { ngx_uint_t mail_state; + unsigned ssl:1; unsigned protocol:3; unsigned blocked:1; unsigned quit:1; @@ -403,6 +409,7 @@ char *ngx_mail_capabilities(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); /* STUB */ void ngx_mail_proxy_init(ngx_mail_session_t *s, ngx_addr_t *peer); void ngx_mail_auth_http_init(ngx_mail_session_t *s); +ngx_int_t ngx_mail_realip_handler(ngx_mail_session_t *s); /**/ diff --git a/src/mail/ngx_mail_auth_http_module.c b/src/mail/ngx_mail_auth_http_module.c index 6b57358..2a198f4 100644 --- a/src/mail/ngx_mail_auth_http_module.c +++ b/src/mail/ngx_mail_auth_http_module.c @@ -1135,10 +1135,10 @@ ngx_mail_auth_http_create_request(ngx_mail_session_t *s, ngx_pool_t *pool, size_t len; ngx_buf_t *b; ngx_str_t login, passwd; + ngx_connection_t *c; #if (NGX_MAIL_SSL) ngx_str_t verify, subject, issuer, serial, fingerprint, raw_cert, cert; - ngx_connection_t *c; ngx_mail_ssl_conf_t *sslcf; #endif ngx_mail_core_srv_conf_t *cscf; @@ -1151,9 +1151,10 @@ ngx_mail_auth_http_create_request(ngx_mail_session_t *s, ngx_pool_t *pool, return NULL; } + c = s->connection; + #if (NGX_MAIL_SSL) - c = s->connection; sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module); if (c->ssl && sslcf->verify) { @@ -1224,22 +1225,49 @@ ngx_mail_auth_http_create_request(ngx_mail_session_t *s, ngx_pool_t *pool, + sizeof("Client-IP: ") - 1 + s->connection->addr_text.len + sizeof(CRLF) - 1 + sizeof("Client-Host: ") - 1 + s->host.len + sizeof(CRLF) - 1 - + sizeof("Auth-SMTP-Helo: ") - 1 + s->smtp_helo.len + sizeof(CRLF) - 1 - + sizeof("Auth-SMTP-From: ") - 1 + s->smtp_from.len + sizeof(CRLF) - 1 - + sizeof("Auth-SMTP-To: ") - 1 + s->smtp_to.len + sizeof(CRLF) - 1 -#if (NGX_MAIL_SSL) - + sizeof("Auth-SSL: on" CRLF) - 1 - + sizeof("Auth-SSL-Verify: ") - 1 + verify.len + sizeof(CRLF) - 1 - + sizeof("Auth-SSL-Subject: ") - 1 + subject.len + sizeof(CRLF) - 1 - + sizeof("Auth-SSL-Issuer: ") - 1 + issuer.len + sizeof(CRLF) - 1 - + sizeof("Auth-SSL-Serial: ") - 1 + serial.len + sizeof(CRLF) - 1 - + sizeof("Auth-SSL-Fingerprint: ") - 1 + fingerprint.len - + sizeof(CRLF) - 1 - + sizeof("Auth-SSL-Cert: ") - 1 + cert.len + sizeof(CRLF) - 1 -#endif + ahcf->header.len + sizeof(CRLF) - 1; + if (c->proxy_protocol) { + len += sizeof("Proxy-Protocol-Addr: ") - 1 + + c->proxy_protocol->src_addr.len + sizeof(CRLF) - 1 + + sizeof("Proxy-Protocol-Port: ") - 1 + + sizeof("65535") - 1 + sizeof(CRLF) - 1 + + sizeof("Proxy-Protocol-Server-Addr: ") - 1 + + c->proxy_protocol->dst_addr.len + sizeof(CRLF) - 1 + + sizeof("Proxy-Protocol-Server-Port: ") - 1 + + sizeof("65535") - 1 + sizeof(CRLF) - 1; + } + + if (s->auth_method == NGX_MAIL_AUTH_NONE) { + len += sizeof("Auth-SMTP-Helo: ") - 1 + s->smtp_helo.len + + sizeof(CRLF) - 1 + + sizeof("Auth-SMTP-From: ") - 1 + s->smtp_from.len + + sizeof(CRLF) - 1 + + sizeof("Auth-SMTP-To: ") - 1 + s->smtp_to.len + + sizeof(CRLF) - 1; + } + +#if (NGX_MAIL_SSL) + + if (c->ssl) { + len += sizeof("Auth-SSL: on" CRLF) - 1 + + sizeof("Auth-SSL-Verify: ") - 1 + verify.len + + sizeof(CRLF) - 1 + + sizeof("Auth-SSL-Subject: ") - 1 + subject.len + + sizeof(CRLF) - 1 + + sizeof("Auth-SSL-Issuer: ") - 1 + issuer.len + + sizeof(CRLF) - 1 + + sizeof("Auth-SSL-Serial: ") - 1 + serial.len + + sizeof(CRLF) - 1 + + sizeof("Auth-SSL-Fingerprint: ") - 1 + fingerprint.len + + sizeof(CRLF) - 1 + + sizeof("Auth-SSL-Cert: ") - 1 + cert.len + + sizeof(CRLF) - 1; + } + +#endif + b = ngx_create_temp_buf(pool, len); if (b == NULL) { return NULL; @@ -1298,6 +1326,26 @@ ngx_mail_auth_http_create_request(ngx_mail_session_t *s, ngx_pool_t *pool, *b->last++ = CR; *b->last++ = LF; } + if (c->proxy_protocol) { + b->last = ngx_cpymem(b->last, "Proxy-Protocol-Addr: ", + sizeof("Proxy-Protocol-Addr: ") - 1); + b->last = ngx_copy(b->last, c->proxy_protocol->src_addr.data, + c->proxy_protocol->src_addr.len); + *b->last++ = CR; *b->last++ = LF; + + b->last = ngx_sprintf(b->last, "Proxy-Protocol-Port: %d" CRLF, + c->proxy_protocol->src_port); + + b->last = ngx_cpymem(b->last, "Proxy-Protocol-Server-Addr: ", + sizeof("Proxy-Protocol-Server-Addr: ") - 1); + b->last = ngx_copy(b->last, c->proxy_protocol->dst_addr.data, + c->proxy_protocol->dst_addr.len); + *b->last++ = CR; *b->last++ = LF; + + b->last = ngx_sprintf(b->last, "Proxy-Protocol-Server-Port: %d" CRLF, + c->proxy_protocol->dst_port); + } + if (s->auth_method == NGX_MAIL_AUTH_NONE) { /* HELO, MAIL FROM, and RCPT TO can't contain CRLF, no need to escape */ diff --git a/src/mail/ngx_mail_core_module.c b/src/mail/ngx_mail_core_module.c index e16d702..4083124 100644 --- a/src/mail/ngx_mail_core_module.c +++ b/src/mail/ngx_mail_core_module.c @@ -548,6 +548,11 @@ ngx_mail_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) #endif } + if (ngx_strcmp(value[i].data, "proxy_protocol") == 0) { + ls->proxy_protocol = 1; + continue; + } + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "the invalid \"%V\" parameter", &value[i]); return NGX_CONF_ERROR; diff --git a/src/mail/ngx_mail_handler.c b/src/mail/ngx_mail_handler.c index 803a247..0aaa0e7 100644 --- a/src/mail/ngx_mail_handler.c +++ b/src/mail/ngx_mail_handler.c @@ -11,6 +11,8 @@ #include +static void ngx_mail_proxy_protocol_handler(ngx_event_t *rev); +static void ngx_mail_init_session_handler(ngx_event_t *rev); static void ngx_mail_init_session(ngx_connection_t *c); #if (NGX_MAIL_SSL) @@ -26,6 +28,7 @@ ngx_mail_init_connection(ngx_connection_t *c) { size_t len; ngx_uint_t i; + ngx_event_t *rev; ngx_mail_port_t *port; struct sockaddr *sa; struct sockaddr_in *sin; @@ -129,6 +132,10 @@ ngx_mail_init_connection(ngx_connection_t *c) s->main_conf = addr_conf->ctx->main_conf; s->srv_conf = addr_conf->ctx->srv_conf; +#if (NGX_MAIL_SSL) + s->ssl = addr_conf->ssl; +#endif + s->addr_text = &addr_conf->addr_text; c->data = s; @@ -159,13 +166,126 @@ ngx_mail_init_connection(ngx_connection_t *c) c->log_error = NGX_ERROR_INFO; + rev = c->read; + rev->handler = ngx_mail_init_session_handler; + + if (addr_conf->proxy_protocol) { + c->log->action = "reading PROXY protocol"; + + rev->handler = ngx_mail_proxy_protocol_handler; + + if (!rev->ready) { + ngx_add_timer(rev, cscf->timeout); + + if (ngx_handle_read_event(rev, 0) != NGX_OK) { + ngx_mail_close_connection(c); + } + + return; + } + } + + if (ngx_use_accept_mutex) { + ngx_post_event(rev, &ngx_posted_events); + return; + } + + rev->handler(rev); +} + + +static void +ngx_mail_proxy_protocol_handler(ngx_event_t *rev) +{ + u_char *p, buf[NGX_PROXY_PROTOCOL_MAX_HEADER]; + size_t size; + ssize_t n; + ngx_err_t err; + ngx_connection_t *c; + ngx_mail_session_t *s; + ngx_mail_core_srv_conf_t *cscf; + + c = rev->data; + s = c->data; + + ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, + "mail PROXY protocol handler"); + + if (rev->timedout) { + ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out"); + c->timedout = 1; + ngx_mail_close_connection(c); + return; + } + + n = recv(c->fd, (char *) buf, sizeof(buf), MSG_PEEK); + + err = ngx_socket_errno; + + ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0, "recv(): %z", n); + + if (n == -1) { + if (err == NGX_EAGAIN) { + rev->ready = 0; + + if (!rev->timer_set) { + cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); + ngx_add_timer(rev, cscf->timeout); + } + + if (ngx_handle_read_event(rev, 0) != NGX_OK) { + ngx_mail_close_connection(c); + } + + return; + } + + ngx_connection_error(c, err, "recv() failed"); + + ngx_mail_close_connection(c); + return; + } + + p = ngx_proxy_protocol_read(c, buf, buf + n); + + if (p == NULL) { + ngx_mail_close_connection(c); + return; + } + + size = p - buf; + + if (c->recv(c, buf, size) != (ssize_t) size) { + ngx_mail_close_connection(c); + return; + } + + if (ngx_mail_realip_handler(s) != NGX_OK) { + ngx_mail_close_connection(c); + return; + } + + ngx_mail_init_session_handler(rev); +} + + +static void +ngx_mail_init_session_handler(ngx_event_t *rev) +{ + ngx_connection_t *c; + + c = rev->data; + #if (NGX_MAIL_SSL) { + ngx_mail_session_t *s; ngx_mail_ssl_conf_t *sslcf; + s = c->data; + sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module); - if (sslcf->enable || addr_conf->ssl) { + if (sslcf->enable || s->ssl) { c->log->action = "SSL handshaking"; ngx_mail_ssl_init_connection(&sslcf->ssl, c); @@ -215,9 +335,10 @@ ngx_mail_ssl_init_connection(ngx_ssl_t *ssl, ngx_connection_t *c) s = c->data; - cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); - - ngx_add_timer(c->read, cscf->timeout); + if (!c->read->timer_set) { + cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); + ngx_add_timer(c->read, cscf->timeout); + } c->ssl->handler = ngx_mail_ssl_handshake_handler; @@ -338,6 +459,8 @@ ngx_mail_init_session(ngx_connection_t *c) s = c->data; + c->log->action = "sending client greeting line"; + cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); s->protocol = cscf->protocol->type; @@ -722,11 +845,6 @@ ngx_mail_read_command(ngx_mail_session_t *s, ngx_connection_t *c) } if (n == NGX_AGAIN) { - if (ngx_handle_read_event(c->read, 0) != NGX_OK) { - ngx_mail_session_internal_server_error(s); - return NGX_ERROR; - } - if (s->buffer->pos == s->buffer->last) { return NGX_AGAIN; } diff --git a/src/mail/ngx_mail_imap_handler.c b/src/mail/ngx_mail_imap_handler.c index 3bf09ec..5dfdd76 100644 --- a/src/mail/ngx_mail_imap_handler.c +++ b/src/mail/ngx_mail_imap_handler.c @@ -123,6 +123,12 @@ ngx_mail_imap_auth_state(ngx_event_t *rev) if (s->out.len) { ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "imap send handler busy"); s->blocked = 1; + + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + ngx_mail_close_connection(c); + return; + } + return; } @@ -130,7 +136,16 @@ ngx_mail_imap_auth_state(ngx_event_t *rev) rc = ngx_mail_read_command(s, c); - if (rc == NGX_AGAIN || rc == NGX_ERROR) { + if (rc == NGX_AGAIN) { + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + ngx_mail_session_internal_server_error(s); + return; + } + + return; + } + + if (rc == NGX_ERROR) { return; } @@ -293,6 +308,11 @@ ngx_mail_imap_auth_state(ngx_event_t *rev) } } + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + ngx_mail_session_internal_server_error(s); + return; + } + ngx_mail_send(c->write); } diff --git a/src/mail/ngx_mail_pop3_handler.c b/src/mail/ngx_mail_pop3_handler.c index 9310c27..edfd986 100644 --- a/src/mail/ngx_mail_pop3_handler.c +++ b/src/mail/ngx_mail_pop3_handler.c @@ -138,6 +138,12 @@ ngx_mail_pop3_auth_state(ngx_event_t *rev) if (s->out.len) { ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "pop3 send handler busy"); s->blocked = 1; + + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + ngx_mail_close_connection(c); + return; + } + return; } @@ -145,7 +151,16 @@ ngx_mail_pop3_auth_state(ngx_event_t *rev) rc = ngx_mail_read_command(s, c); - if (rc == NGX_AGAIN || rc == NGX_ERROR) { + if (rc == NGX_AGAIN) { + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + ngx_mail_session_internal_server_error(s); + return; + } + + return; + } + + if (rc == NGX_ERROR) { return; } @@ -275,6 +290,11 @@ ngx_mail_pop3_auth_state(ngx_event_t *rev) s->arg_start = s->buffer->start; } + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + ngx_mail_session_internal_server_error(s); + return; + } + ngx_mail_send(c->write); } } diff --git a/src/mail/ngx_mail_proxy_module.c b/src/mail/ngx_mail_proxy_module.c index 1c86e54..66aa0ba 100644 --- a/src/mail/ngx_mail_proxy_module.c +++ b/src/mail/ngx_mail_proxy_module.c @@ -16,6 +16,8 @@ typedef struct { ngx_flag_t enable; ngx_flag_t pass_error_message; ngx_flag_t xclient; + ngx_flag_t smtp_auth; + ngx_flag_t proxy_protocol; size_t buffer_size; ngx_msec_t timeout; } ngx_mail_proxy_conf_t; @@ -25,7 +27,8 @@ static void ngx_mail_proxy_block_read(ngx_event_t *rev); static void ngx_mail_proxy_pop3_handler(ngx_event_t *rev); static void ngx_mail_proxy_imap_handler(ngx_event_t *rev); static void ngx_mail_proxy_smtp_handler(ngx_event_t *rev); -static void ngx_mail_proxy_dummy_handler(ngx_event_t *ev); +static void ngx_mail_proxy_write_handler(ngx_event_t *wev); +static ngx_int_t ngx_mail_proxy_send_proxy_protocol(ngx_mail_session_t *s); static ngx_int_t ngx_mail_proxy_read_response(ngx_mail_session_t *s, ngx_uint_t state); static void ngx_mail_proxy_handler(ngx_event_t *ev); @@ -74,6 +77,20 @@ static ngx_command_t ngx_mail_proxy_commands[] = { offsetof(ngx_mail_proxy_conf_t, xclient), NULL }, + { ngx_string("proxy_smtp_auth"), + NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_MAIL_SRV_CONF_OFFSET, + offsetof(ngx_mail_proxy_conf_t, smtp_auth), + NULL }, + + { ngx_string("proxy_protocol"), + NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_MAIL_SRV_CONF_OFFSET, + offsetof(ngx_mail_proxy_conf_t, proxy_protocol), + NULL }, + ngx_null_command }; @@ -148,7 +165,7 @@ ngx_mail_proxy_init(ngx_mail_session_t *s, ngx_addr_t *peer) p->upstream.connection->pool = s->connection->pool; s->connection->read->handler = ngx_mail_proxy_block_read; - p->upstream.connection->write->handler = ngx_mail_proxy_dummy_handler; + p->upstream.connection->write->handler = ngx_mail_proxy_write_handler; pcf = ngx_mail_get_module_srv_conf(s, ngx_mail_proxy_module); @@ -159,6 +176,8 @@ ngx_mail_proxy_init(ngx_mail_session_t *s, ngx_addr_t *peer) return; } + s->proxy->proxy_protocol = pcf->proxy_protocol; + s->out.len = 0; switch (s->protocol) { @@ -178,6 +197,12 @@ ngx_mail_proxy_init(ngx_mail_session_t *s, ngx_addr_t *peer) s->mail_state = ngx_smtp_start; break; } + + if (rc == NGX_AGAIN) { + return; + } + + ngx_mail_proxy_write_handler(p->upstream.connection->write); } @@ -222,9 +247,25 @@ ngx_mail_proxy_pop3_handler(ngx_event_t *rev) return; } + if (s->proxy->proxy_protocol) { + ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "mail proxy pop3 busy"); + + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + ngx_mail_proxy_internal_server_error(s); + return; + } + + return; + } + rc = ngx_mail_proxy_read_response(s, 0); if (rc == NGX_AGAIN) { + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + ngx_mail_proxy_internal_server_error(s); + return; + } + return; } @@ -306,6 +347,11 @@ ngx_mail_proxy_pop3_handler(ngx_event_t *rev) return; } + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + ngx_mail_proxy_internal_server_error(s); + return; + } + s->proxy->buffer->pos = s->proxy->buffer->start; s->proxy->buffer->last = s->proxy->buffer->start; } @@ -335,9 +381,25 @@ ngx_mail_proxy_imap_handler(ngx_event_t *rev) return; } + if (s->proxy->proxy_protocol) { + ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "mail proxy imap busy"); + + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + ngx_mail_proxy_internal_server_error(s); + return; + } + + return; + } + rc = ngx_mail_proxy_read_response(s, s->mail_state); if (rc == NGX_AGAIN) { + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + ngx_mail_proxy_internal_server_error(s); + return; + } + return; } @@ -440,6 +502,11 @@ ngx_mail_proxy_imap_handler(ngx_event_t *rev) return; } + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + ngx_mail_proxy_internal_server_error(s); + return; + } + s->proxy->buffer->pos = s->proxy->buffer->start; s->proxy->buffer->last = s->proxy->buffer->start; } @@ -450,7 +517,7 @@ ngx_mail_proxy_smtp_handler(ngx_event_t *rev) { u_char *p; ngx_int_t rc; - ngx_str_t line; + ngx_str_t line, auth, encoded; ngx_buf_t *b; ngx_connection_t *c; ngx_mail_session_t *s; @@ -471,9 +538,25 @@ ngx_mail_proxy_smtp_handler(ngx_event_t *rev) return; } + if (s->proxy->proxy_protocol) { + ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "mail proxy smtp busy"); + + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + ngx_mail_proxy_internal_server_error(s); + return; + } + + return; + } + rc = ngx_mail_proxy_read_response(s, s->mail_state); if (rc == NGX_AGAIN) { + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + ngx_mail_proxy_internal_server_error(s); + return; + } + return; } @@ -513,6 +596,9 @@ ngx_mail_proxy_smtp_handler(ngx_event_t *rev) } else if (s->auth_method == NGX_MAIL_AUTH_NONE) { s->mail_state = ngx_smtp_helo_from; + } else if (pcf->smtp_auth) { + s->mail_state = ngx_smtp_helo_auth; + } else { s->mail_state = ngx_smtp_helo; } @@ -552,7 +638,9 @@ ngx_mail_proxy_smtp_handler(ngx_event_t *rev) p = ngx_copy(p, s->connection->addr_text.data, s->connection->addr_text.len); - if (s->login.len) { + pcf = ngx_mail_get_module_srv_conf(s, ngx_mail_proxy_module); + + if (s->login.len && !pcf->smtp_auth) { p = ngx_cpymem(p, " LOGIN=", sizeof(" LOGIN=") - 1); p = ngx_copy(p, s->login.data, s->login.len); } @@ -570,6 +658,9 @@ ngx_mail_proxy_smtp_handler(ngx_event_t *rev) } else if (s->auth_method == NGX_MAIL_AUTH_NONE) { s->mail_state = ngx_smtp_xclient_from; + } else if (pcf->smtp_auth) { + s->mail_state = ngx_smtp_xclient_auth; + } else { s->mail_state = ngx_smtp_xclient; } @@ -595,8 +686,62 @@ ngx_mail_proxy_smtp_handler(ngx_event_t *rev) &s->smtp_helo) - line.data; - s->mail_state = (s->auth_method == NGX_MAIL_AUTH_NONE) ? - ngx_smtp_helo_from : ngx_smtp_helo; + pcf = ngx_mail_get_module_srv_conf(s, ngx_mail_proxy_module); + + if (s->auth_method == NGX_MAIL_AUTH_NONE) { + s->mail_state = ngx_smtp_helo_from; + + } else if (pcf->smtp_auth) { + s->mail_state = ngx_smtp_helo_auth; + + } else { + s->mail_state = ngx_smtp_helo; + } + + break; + + case ngx_smtp_helo_auth: + case ngx_smtp_xclient_auth: + ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0, + "mail proxy send auth"); + + s->connection->log->action = "sending AUTH to upstream"; + + if (s->passwd.data == NULL) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "no password available"); + ngx_mail_proxy_internal_server_error(s); + return; + } + + auth.len = 1 + s->login.len + 1 + s->passwd.len; + auth.data = ngx_pnalloc(c->pool, auth.len); + if (auth.data == NULL) { + ngx_mail_proxy_internal_server_error(s); + return; + } + + auth.len = ngx_sprintf(auth.data, "%Z%V%Z%V", &s->login, &s->passwd) + - auth.data; + + line.len = sizeof("AUTH PLAIN " CRLF) - 1 + + ngx_base64_encoded_length(auth.len); + + line.data = ngx_pnalloc(c->pool, line.len); + if (line.data == NULL) { + ngx_mail_proxy_internal_server_error(s); + return; + } + + encoded.data = ngx_cpymem(line.data, "AUTH PLAIN ", + sizeof("AUTH PLAIN ") - 1); + + ngx_encode_base64(&encoded, &auth); + + p = encoded.data + encoded.len; + *p++ = CR; *p = LF; + + s->mail_state = ngx_smtp_auth_plain; break; @@ -643,6 +788,7 @@ ngx_mail_proxy_smtp_handler(ngx_event_t *rev) case ngx_smtp_helo: case ngx_smtp_xclient: + case ngx_smtp_auth_plain: case ngx_smtp_to: b = s->proxy->buffer; @@ -692,25 +838,103 @@ ngx_mail_proxy_smtp_handler(ngx_event_t *rev) return; } + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + ngx_mail_proxy_internal_server_error(s); + return; + } + s->proxy->buffer->pos = s->proxy->buffer->start; s->proxy->buffer->last = s->proxy->buffer->start; } static void -ngx_mail_proxy_dummy_handler(ngx_event_t *wev) +ngx_mail_proxy_write_handler(ngx_event_t *wev) { ngx_connection_t *c; ngx_mail_session_t *s; - ngx_log_debug0(NGX_LOG_DEBUG_MAIL, wev->log, 0, "mail proxy dummy handler"); + ngx_log_debug0(NGX_LOG_DEBUG_MAIL, wev->log, 0, "mail proxy write handler"); + + c = wev->data; + s = c->data; + + if (s->proxy->proxy_protocol) { + if (ngx_mail_proxy_send_proxy_protocol(s) != NGX_OK) { + return; + } + + s->proxy->proxy_protocol = 0; + } if (ngx_handle_write_event(wev, 0) != NGX_OK) { - c = wev->data; - s = c->data; - - ngx_mail_proxy_close_session(s); + ngx_mail_proxy_internal_server_error(s); } + + if (c->read->ready) { + ngx_post_event(c->read, &ngx_posted_events); + } +} + + +static ngx_int_t +ngx_mail_proxy_send_proxy_protocol(ngx_mail_session_t *s) +{ + u_char *p; + ssize_t n, size; + ngx_connection_t *c; + u_char buf[NGX_PROXY_PROTOCOL_MAX_HEADER]; + + s->connection->log->action = "sending PROXY protocol header to upstream"; + + ngx_log_debug0(NGX_LOG_DEBUG_MAIL, s->connection->log, 0, + "mail proxy send PROXY protocol header"); + + p = ngx_proxy_protocol_write(s->connection, buf, + buf + NGX_PROXY_PROTOCOL_MAX_HEADER); + if (p == NULL) { + ngx_mail_proxy_internal_server_error(s); + return NGX_ERROR; + } + + c = s->proxy->upstream.connection; + + size = p - buf; + + n = c->send(c, buf, size); + + if (n == NGX_AGAIN) { + if (ngx_handle_write_event(c->write, 0) != NGX_OK) { + ngx_mail_proxy_internal_server_error(s); + return NGX_ERROR; + } + + return NGX_AGAIN; + } + + if (n == NGX_ERROR) { + ngx_mail_proxy_internal_server_error(s); + return NGX_ERROR; + } + + if (n != size) { + + /* + * PROXY protocol specification: + * The sender must always ensure that the header + * is sent at once, so that the transport layer + * maintains atomicity along the path to the receiver. + */ + + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "could not send PROXY protocol header at once"); + + ngx_mail_proxy_internal_server_error(s); + + return NGX_ERROR; + } + + return NGX_OK; } @@ -824,6 +1048,7 @@ ngx_mail_proxy_read_response(ngx_mail_session_t *s, ngx_uint_t state) case ngx_smtp_helo: case ngx_smtp_helo_xclient: case ngx_smtp_helo_from: + case ngx_smtp_helo_auth: case ngx_smtp_from: if (p[0] == '2' && p[1] == '5' && p[2] == '0') { return NGX_OK; @@ -833,11 +1058,18 @@ ngx_mail_proxy_read_response(ngx_mail_session_t *s, ngx_uint_t state) case ngx_smtp_xclient: case ngx_smtp_xclient_from: case ngx_smtp_xclient_helo: + case ngx_smtp_xclient_auth: if (p[0] == '2' && (p[1] == '2' || p[1] == '5') && p[2] == '0') { return NGX_OK; } break; + case ngx_smtp_auth_plain: + if (p[0] == '2' && p[1] == '3' && p[2] == '5') { + return NGX_OK; + } + break; + case ngx_smtp_to: return NGX_OK; } @@ -1102,6 +1334,8 @@ ngx_mail_proxy_create_conf(ngx_conf_t *cf) pcf->enable = NGX_CONF_UNSET; pcf->pass_error_message = NGX_CONF_UNSET; pcf->xclient = NGX_CONF_UNSET; + pcf->smtp_auth = NGX_CONF_UNSET; + pcf->proxy_protocol = NGX_CONF_UNSET; pcf->buffer_size = NGX_CONF_UNSET_SIZE; pcf->timeout = NGX_CONF_UNSET_MSEC; @@ -1118,6 +1352,8 @@ ngx_mail_proxy_merge_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_value(conf->enable, prev->enable, 0); ngx_conf_merge_value(conf->pass_error_message, prev->pass_error_message, 0); ngx_conf_merge_value(conf->xclient, prev->xclient, 1); + ngx_conf_merge_value(conf->smtp_auth, prev->smtp_auth, 0); + ngx_conf_merge_value(conf->proxy_protocol, prev->proxy_protocol, 0); ngx_conf_merge_size_value(conf->buffer_size, prev->buffer_size, (size_t) ngx_pagesize); ngx_conf_merge_msec_value(conf->timeout, prev->timeout, 24 * 60 * 60000); diff --git a/src/mail/ngx_mail_realip_module.c b/src/mail/ngx_mail_realip_module.c new file mode 100644 index 0000000..c93d7d3 --- /dev/null +++ b/src/mail/ngx_mail_realip_module.c @@ -0,0 +1,269 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include + + +typedef struct { + ngx_array_t *from; /* array of ngx_cidr_t */ +} ngx_mail_realip_srv_conf_t; + + +static ngx_int_t ngx_mail_realip_set_addr(ngx_mail_session_t *s, + ngx_addr_t *addr); +static char *ngx_mail_realip_from(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static void *ngx_mail_realip_create_srv_conf(ngx_conf_t *cf); +static char *ngx_mail_realip_merge_srv_conf(ngx_conf_t *cf, void *parent, + void *child); + + +static ngx_command_t ngx_mail_realip_commands[] = { + + { ngx_string("set_real_ip_from"), + NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, + ngx_mail_realip_from, + NGX_MAIL_SRV_CONF_OFFSET, + 0, + NULL }, + + ngx_null_command +}; + + +static ngx_mail_module_t ngx_mail_realip_module_ctx = { + NULL, /* protocol */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + ngx_mail_realip_create_srv_conf, /* create server configuration */ + ngx_mail_realip_merge_srv_conf /* merge server configuration */ +}; + + +ngx_module_t ngx_mail_realip_module = { + NGX_MODULE_V1, + &ngx_mail_realip_module_ctx, /* module context */ + ngx_mail_realip_commands, /* module directives */ + NGX_MAIL_MODULE, /* module type */ + NULL, /* init master */ + NULL, /* init module */ + NULL, /* init process */ + NULL, /* init thread */ + NULL, /* exit thread */ + NULL, /* exit process */ + NULL, /* exit master */ + NGX_MODULE_V1_PADDING +}; + + +ngx_int_t +ngx_mail_realip_handler(ngx_mail_session_t *s) +{ + ngx_addr_t addr; + ngx_connection_t *c; + ngx_mail_realip_srv_conf_t *rscf; + + rscf = ngx_mail_get_module_srv_conf(s, ngx_mail_realip_module); + + if (rscf->from == NULL) { + return NGX_OK; + } + + c = s->connection; + + if (c->proxy_protocol == NULL) { + return NGX_OK; + } + + if (ngx_cidr_match(c->sockaddr, rscf->from) != NGX_OK) { + return NGX_OK; + } + + if (ngx_parse_addr(c->pool, &addr, c->proxy_protocol->src_addr.data, + c->proxy_protocol->src_addr.len) + != NGX_OK) + { + return NGX_OK; + } + + ngx_inet_set_port(addr.sockaddr, c->proxy_protocol->src_port); + + return ngx_mail_realip_set_addr(s, &addr); +} + + +static ngx_int_t +ngx_mail_realip_set_addr(ngx_mail_session_t *s, ngx_addr_t *addr) +{ + size_t len; + u_char *p; + u_char text[NGX_SOCKADDR_STRLEN]; + ngx_connection_t *c; + + c = s->connection; + + len = ngx_sock_ntop(addr->sockaddr, addr->socklen, text, + NGX_SOCKADDR_STRLEN, 0); + if (len == 0) { + return NGX_ERROR; + } + + p = ngx_pnalloc(c->pool, len); + if (p == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(p, text, len); + + c->sockaddr = addr->sockaddr; + c->socklen = addr->socklen; + c->addr_text.len = len; + c->addr_text.data = p; + + return NGX_OK; +} + + +static char * +ngx_mail_realip_from(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_mail_realip_srv_conf_t *rscf = conf; + + ngx_int_t rc; + ngx_str_t *value; + ngx_url_t u; + ngx_cidr_t c, *cidr; + ngx_uint_t i; + struct sockaddr_in *sin; +#if (NGX_HAVE_INET6) + struct sockaddr_in6 *sin6; +#endif + + value = cf->args->elts; + + if (rscf->from == NULL) { + rscf->from = ngx_array_create(cf->pool, 2, + sizeof(ngx_cidr_t)); + if (rscf->from == NULL) { + return NGX_CONF_ERROR; + } + } + +#if (NGX_HAVE_UNIX_DOMAIN) + + if (ngx_strcmp(value[1].data, "unix:") == 0) { + cidr = ngx_array_push(rscf->from); + if (cidr == NULL) { + return NGX_CONF_ERROR; + } + + cidr->family = AF_UNIX; + return NGX_CONF_OK; + } + +#endif + + rc = ngx_ptocidr(&value[1], &c); + + if (rc != NGX_ERROR) { + if (rc == NGX_DONE) { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "low address bits of %V are meaningless", + &value[1]); + } + + cidr = ngx_array_push(rscf->from); + if (cidr == NULL) { + return NGX_CONF_ERROR; + } + + *cidr = c; + + return NGX_CONF_OK; + } + + ngx_memzero(&u, sizeof(ngx_url_t)); + u.host = value[1]; + + if (ngx_inet_resolve_host(cf->pool, &u) != NGX_OK) { + if (u.err) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "%s in set_real_ip_from \"%V\"", + u.err, &u.host); + } + + return NGX_CONF_ERROR; + } + + cidr = ngx_array_push_n(rscf->from, u.naddrs); + if (cidr == NULL) { + return NGX_CONF_ERROR; + } + + ngx_memzero(cidr, u.naddrs * sizeof(ngx_cidr_t)); + + for (i = 0; i < u.naddrs; i++) { + cidr[i].family = u.addrs[i].sockaddr->sa_family; + + switch (cidr[i].family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + sin6 = (struct sockaddr_in6 *) u.addrs[i].sockaddr; + cidr[i].u.in6.addr = sin6->sin6_addr; + ngx_memset(cidr[i].u.in6.mask.s6_addr, 0xff, 16); + break; +#endif + + default: /* AF_INET */ + sin = (struct sockaddr_in *) u.addrs[i].sockaddr; + cidr[i].u.in.addr = sin->sin_addr.s_addr; + cidr[i].u.in.mask = 0xffffffff; + break; + } + } + + return NGX_CONF_OK; +} + + +static void * +ngx_mail_realip_create_srv_conf(ngx_conf_t *cf) +{ + ngx_mail_realip_srv_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_mail_realip_srv_conf_t)); + if (conf == NULL) { + return NULL; + } + + /* + * set by ngx_pcalloc(): + * + * conf->from = NULL; + */ + + return conf; +} + + +static char * +ngx_mail_realip_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_mail_realip_srv_conf_t *prev = parent; + ngx_mail_realip_srv_conf_t *conf = child; + + if (conf->from == NULL) { + conf->from = prev->from; + } + + return NGX_CONF_OK; +} diff --git a/src/mail/ngx_mail_smtp_handler.c b/src/mail/ngx_mail_smtp_handler.c index f1017e0..e68ceed 100644 --- a/src/mail/ngx_mail_smtp_handler.c +++ b/src/mail/ngx_mail_smtp_handler.c @@ -449,6 +449,12 @@ ngx_mail_smtp_auth_state(ngx_event_t *rev) if (s->out.len) { ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "smtp send handler busy"); s->blocked = 1; + + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + ngx_mail_close_connection(c); + return; + } + return; } @@ -456,7 +462,16 @@ ngx_mail_smtp_auth_state(ngx_event_t *rev) rc = ngx_mail_read_command(s, c); - if (rc == NGX_AGAIN || rc == NGX_ERROR) { + if (rc == NGX_AGAIN) { + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + ngx_mail_session_internal_server_error(s); + return; + } + + return; + } + + if (rc == NGX_ERROR) { return; } @@ -568,6 +583,11 @@ ngx_mail_smtp_auth_state(ngx_event_t *rev) s->arg_start = s->buffer->pos; } + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + ngx_mail_session_internal_server_error(s); + return; + } + ngx_mail_send(c->write); } } diff --git a/src/mail/ngx_mail_ssl_module.c b/src/mail/ngx_mail_ssl_module.c index e193b29..7eae83e 100644 --- a/src/mail/ngx_mail_ssl_module.c +++ b/src/mail/ngx_mail_ssl_module.c @@ -26,6 +26,9 @@ static char *ngx_mail_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, static char *ngx_mail_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static char *ngx_mail_ssl_conf_command_check(ngx_conf_t *cf, void *post, + void *data); + static ngx_conf_enum_t ngx_mail_starttls_state[] = { { ngx_string("off"), NGX_MAIL_STARTTLS_OFF }, @@ -61,6 +64,10 @@ static ngx_conf_deprecated_t ngx_mail_ssl_deprecated = { }; +static ngx_conf_post_t ngx_mail_ssl_conf_command_post = + { ngx_mail_ssl_conf_command_check }; + + static ngx_command_t ngx_mail_ssl_commands[] = { { ngx_string("ssl"), @@ -196,6 +203,13 @@ static ngx_command_t ngx_mail_ssl_commands[] = { offsetof(ngx_mail_ssl_conf_t, crl), NULL }, + { ngx_string("ssl_conf_command"), + NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE2, + ngx_conf_set_keyval_slot, + NGX_MAIL_SRV_CONF_OFFSET, + offsetof(ngx_mail_ssl_conf_t, conf_commands), + &ngx_mail_ssl_conf_command_post }, + ngx_null_command }; @@ -259,6 +273,7 @@ ngx_mail_ssl_create_conf(ngx_conf_t *cf) scf->certificates = NGX_CONF_UNSET_PTR; scf->certificate_keys = NGX_CONF_UNSET_PTR; scf->passwords = NGX_CONF_UNSET_PTR; + scf->conf_commands = NGX_CONF_UNSET_PTR; scf->prefer_server_ciphers = NGX_CONF_UNSET; scf->verify = NGX_CONF_UNSET_UINT; scf->verify_depth = NGX_CONF_UNSET_UINT; @@ -316,6 +331,8 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_str_value(conf->ciphers, prev->ciphers, NGX_DEFAULT_CIPHERS); + ngx_conf_merge_ptr_value(conf->conf_commands, prev->conf_commands, NULL); + conf->ssl.log = cf->log; @@ -461,6 +478,10 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) return NGX_CONF_ERROR; } + if (ngx_ssl_conf_commands(cf, &conf->ssl, conf->conf_commands) != NGX_OK) { + return NGX_CONF_ERROR; + } + return NGX_CONF_OK; } @@ -654,3 +675,14 @@ invalid: return NGX_CONF_ERROR; } + + +static char * +ngx_mail_ssl_conf_command_check(ngx_conf_t *cf, void *post, void *data) +{ +#ifndef SSL_CONF_FLAG_FILE + return "is not supported on this platform"; +#else + return NGX_CONF_OK; +#endif +} diff --git a/src/mail/ngx_mail_ssl_module.h b/src/mail/ngx_mail_ssl_module.h index d6b0b8e..a0a6113 100644 --- a/src/mail/ngx_mail_ssl_module.h +++ b/src/mail/ngx_mail_ssl_module.h @@ -48,6 +48,7 @@ typedef struct { ngx_str_t ciphers; ngx_array_t *passwords; + ngx_array_t *conf_commands; ngx_shm_zone_t *shm_zone; diff --git a/src/misc/ngx_cpp_test_module.cpp b/src/misc/ngx_cpp_test_module.cpp index 5d2f08d..0026409 100644 --- a/src/misc/ngx_cpp_test_module.cpp +++ b/src/misc/ngx_cpp_test_module.cpp @@ -14,6 +14,8 @@ extern "C" { #include #include #include + + #include } // nginx header files should go before other, because they define 64-bit off_t diff --git a/src/os/unix/ngx_errno.c b/src/os/unix/ngx_errno.c index e787b23..ca23b2d 100644 --- a/src/os/unix/ngx_errno.c +++ b/src/os/unix/ngx_errno.c @@ -9,6 +9,49 @@ #include +static ngx_str_t ngx_unknown_error = ngx_string("Unknown error"); + + +#if (NGX_HAVE_STRERRORDESC_NP) + +/* + * The strerrordesc_np() function, introduced in glibc 2.32, is + * async-signal-safe. This makes it possible to use it directly, + * without copying error messages. + */ + + +u_char * +ngx_strerror(ngx_err_t err, u_char *errstr, size_t size) +{ + size_t len; + const char *msg; + + msg = strerrordesc_np(err); + + if (msg == NULL) { + msg = (char *) ngx_unknown_error.data; + len = ngx_unknown_error.len; + + } else { + len = ngx_strlen(msg); + } + + size = ngx_min(size, len); + + return ngx_cpymem(errstr, msg, size); +} + + +ngx_int_t +ngx_strerror_init(void) +{ + return NGX_OK; +} + + +#else + /* * The strerror() messages are copied because: * @@ -26,7 +69,8 @@ static ngx_str_t *ngx_sys_errlist; -static ngx_str_t ngx_unknown_error = ngx_string("Unknown error"); +static ngx_err_t ngx_first_error; +static ngx_err_t ngx_last_error; u_char * @@ -34,8 +78,13 @@ ngx_strerror(ngx_err_t err, u_char *errstr, size_t size) { ngx_str_t *msg; - msg = ((ngx_uint_t) err < NGX_SYS_NERR) ? &ngx_sys_errlist[err]: - &ngx_unknown_error; + if (err >= ngx_first_error && err < ngx_last_error) { + msg = &ngx_sys_errlist[err - ngx_first_error]; + + } else { + msg = &ngx_unknown_error; + } + size = ngx_min(size, msg->len); return ngx_cpymem(errstr, msg->data, size); @@ -50,20 +99,92 @@ ngx_strerror_init(void) size_t len; ngx_err_t err; +#if (NGX_SYS_NERR) + ngx_first_error = 0; + ngx_last_error = NGX_SYS_NERR; + +#elif (EPERM > 1000 && EPERM < 0x7fffffff - 1000) + + /* + * If number of errors is not known, and EPERM error code has large + * but reasonable value, guess possible error codes based on the error + * messages returned by strerror(), starting from EPERM. Notably, + * this covers GNU/Hurd, where errors start at 0x40000001. + */ + + for (err = EPERM; err > EPERM - 1000; err--) { + ngx_set_errno(0); + msg = strerror(err); + + if (errno == EINVAL + || msg == NULL + || strncmp(msg, "Unknown error", 13) == 0) + { + continue; + } + + ngx_first_error = err; + } + + for (err = EPERM; err < EPERM + 1000; err++) { + ngx_set_errno(0); + msg = strerror(err); + + if (errno == EINVAL + || msg == NULL + || strncmp(msg, "Unknown error", 13) == 0) + { + continue; + } + + ngx_last_error = err + 1; + } + +#else + + /* + * If number of errors is not known, guess it based on the error + * messages returned by strerror(). + */ + + ngx_first_error = 0; + + for (err = 0; err < 1000; err++) { + ngx_set_errno(0); + msg = strerror(err); + + if (errno == EINVAL + || msg == NULL + || strncmp(msg, "Unknown error", 13) == 0) + { + continue; + } + + ngx_last_error = err + 1; + } + +#endif + /* * ngx_strerror() is not ready to work at this stage, therefore, * malloc() is used and possible errors are logged using strerror(). */ - len = NGX_SYS_NERR * sizeof(ngx_str_t); + len = (ngx_last_error - ngx_first_error) * sizeof(ngx_str_t); ngx_sys_errlist = malloc(len); if (ngx_sys_errlist == NULL) { goto failed; } - for (err = 0; err < NGX_SYS_NERR; err++) { + for (err = ngx_first_error; err < ngx_last_error; err++) { msg = strerror(err); + + if (msg == NULL) { + ngx_sys_errlist[err - ngx_first_error] = ngx_unknown_error; + continue; + } + len = ngx_strlen(msg); p = malloc(len); @@ -72,8 +193,8 @@ ngx_strerror_init(void) } ngx_memcpy(p, msg, len); - ngx_sys_errlist[err].len = len; - ngx_sys_errlist[err].data = p; + ngx_sys_errlist[err - ngx_first_error].len = len; + ngx_sys_errlist[err - ngx_first_error].data = p; } return NGX_OK; @@ -85,3 +206,5 @@ failed: return NGX_ERROR; } + +#endif diff --git a/src/os/unix/ngx_files.c b/src/os/unix/ngx_files.c index 482d327..1c82a8e 100644 --- a/src/os/unix/ngx_files.c +++ b/src/os/unix/ngx_files.c @@ -875,9 +875,28 @@ ngx_fs_bsize(u_char *name) return 512; } +#if (NGX_LINUX) + if ((size_t) fs.f_bsize > ngx_pagesize) { + return 512; + } +#endif + return (size_t) fs.f_bsize; } + +off_t +ngx_fs_available(u_char *name) +{ + struct statfs fs; + + if (statfs((char *) name, &fs) == -1) { + return NGX_MAX_OFF_T_VALUE; + } + + return (off_t) fs.f_bavail * fs.f_bsize; +} + #elif (NGX_HAVE_STATVFS) size_t @@ -893,9 +912,28 @@ ngx_fs_bsize(u_char *name) return 512; } +#if (NGX_LINUX) + if ((size_t) fs.f_frsize > ngx_pagesize) { + return 512; + } +#endif + return (size_t) fs.f_frsize; } + +off_t +ngx_fs_available(u_char *name) +{ + struct statvfs fs; + + if (statvfs((char *) name, &fs) == -1) { + return NGX_MAX_OFF_T_VALUE; + } + + return (off_t) fs.f_bavail * fs.f_frsize; +} + #else size_t @@ -904,4 +942,11 @@ ngx_fs_bsize(u_char *name) return 512; } + +off_t +ngx_fs_available(u_char *name) +{ + return NGX_MAX_OFF_T_VALUE; +} + #endif diff --git a/src/os/unix/ngx_files.h b/src/os/unix/ngx_files.h index 383e38e..d084713 100644 --- a/src/os/unix/ngx_files.h +++ b/src/os/unix/ngx_files.h @@ -185,7 +185,10 @@ ngx_int_t ngx_set_file_time(u_char *name, ngx_fd_t fd, time_t s); #define ngx_is_exec(sb) (((sb)->st_mode & S_IXUSR) == S_IXUSR) #define ngx_file_access(sb) ((sb)->st_mode & 0777) #define ngx_file_size(sb) (sb)->st_size -#define ngx_file_fs_size(sb) ngx_max((sb)->st_size, (sb)->st_blocks * 512) +#define ngx_file_fs_size(sb) \ + (((sb)->st_blocks * 512 > (sb)->st_size \ + && (sb)->st_blocks * 512 < (sb)->st_size + 8 * (sb)->st_blksize) \ + ? (sb)->st_blocks * 512 : (sb)->st_size) #define ngx_file_mtime(sb) (sb)->st_mtime #define ngx_file_uniq(sb) (sb)->st_ino @@ -346,6 +349,7 @@ ngx_int_t ngx_directio_off(ngx_fd_t fd); #endif size_t ngx_fs_bsize(u_char *name); +off_t ngx_fs_available(u_char *name); #if (NGX_HAVE_OPENAT) diff --git a/src/os/unix/ngx_process_cycle.c b/src/os/unix/ngx_process_cycle.c index 5817a2c..b31485f 100644 --- a/src/os/unix/ngx_process_cycle.c +++ b/src/os/unix/ngx_process_cycle.c @@ -15,7 +15,7 @@ static void ngx_start_worker_processes(ngx_cycle_t *cycle, ngx_int_t n, ngx_int_t type); static void ngx_start_cache_manager_processes(ngx_cycle_t *cycle, ngx_uint_t respawn); -static void ngx_pass_open_channel(ngx_cycle_t *cycle, ngx_channel_t *ch); +static void ngx_pass_open_channel(ngx_cycle_t *cycle); static void ngx_signal_worker_processes(ngx_cycle_t *cycle, int signo); static ngx_uint_t ngx_reap_children(ngx_cycle_t *cycle); static void ngx_master_process_exit(ngx_cycle_t *cycle); @@ -77,12 +77,11 @@ ngx_master_process_cycle(ngx_cycle_t *cycle) u_char *p; size_t size; ngx_int_t i; - ngx_uint_t n, sigio; + ngx_uint_t sigio; sigset_t set; struct itimerval itv; ngx_uint_t live; ngx_msec_t delay; - ngx_listening_t *ls; ngx_core_conf_t *ccf; sigemptyset(&set); @@ -204,16 +203,7 @@ ngx_master_process_cycle(ngx_cycle_t *cycle) if (ngx_quit) { ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); - - ls = cycle->listening.elts; - for (n = 0; n < cycle->listening.nelts; n++) { - if (ngx_close_socket(ls[n].fd) == -1) { - ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno, - ngx_close_socket_n " %V failed", - &ls[n].addr_text); - } - } - cycle->listening.nelts = 0; + ngx_close_listening_sockets(cycle); continue; } @@ -345,25 +335,16 @@ ngx_single_process_cycle(ngx_cycle_t *cycle) static void ngx_start_worker_processes(ngx_cycle_t *cycle, ngx_int_t n, ngx_int_t type) { - ngx_int_t i; - ngx_channel_t ch; + ngx_int_t i; ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "start worker processes"); - ngx_memzero(&ch, sizeof(ngx_channel_t)); - - ch.command = NGX_CMD_OPEN_CHANNEL; - for (i = 0; i < n; i++) { ngx_spawn_process(cycle, ngx_worker_process_cycle, (void *) (intptr_t) i, "worker process", type); - ch.pid = ngx_processes[ngx_process_slot].pid; - ch.slot = ngx_process_slot; - ch.fd = ngx_processes[ngx_process_slot].channel[0]; - - ngx_pass_open_channel(cycle, &ch); + ngx_pass_open_channel(cycle); } } @@ -371,9 +352,8 @@ ngx_start_worker_processes(ngx_cycle_t *cycle, ngx_int_t n, ngx_int_t type) static void ngx_start_cache_manager_processes(ngx_cycle_t *cycle, ngx_uint_t respawn) { - ngx_uint_t i, manager, loader; - ngx_path_t **path; - ngx_channel_t ch; + ngx_uint_t i, manager, loader; + ngx_path_t **path; manager = 0; loader = 0; @@ -398,14 +378,7 @@ ngx_start_cache_manager_processes(ngx_cycle_t *cycle, ngx_uint_t respawn) &ngx_cache_manager_ctx, "cache manager process", respawn ? NGX_PROCESS_JUST_RESPAWN : NGX_PROCESS_RESPAWN); - ngx_memzero(&ch, sizeof(ngx_channel_t)); - - ch.command = NGX_CMD_OPEN_CHANNEL; - ch.pid = ngx_processes[ngx_process_slot].pid; - ch.slot = ngx_process_slot; - ch.fd = ngx_processes[ngx_process_slot].channel[0]; - - ngx_pass_open_channel(cycle, &ch); + ngx_pass_open_channel(cycle); if (loader == 0) { return; @@ -415,19 +388,20 @@ ngx_start_cache_manager_processes(ngx_cycle_t *cycle, ngx_uint_t respawn) &ngx_cache_loader_ctx, "cache loader process", respawn ? NGX_PROCESS_JUST_SPAWN : NGX_PROCESS_NORESPAWN); - ch.command = NGX_CMD_OPEN_CHANNEL; - ch.pid = ngx_processes[ngx_process_slot].pid; - ch.slot = ngx_process_slot; - ch.fd = ngx_processes[ngx_process_slot].channel[0]; - - ngx_pass_open_channel(cycle, &ch); + ngx_pass_open_channel(cycle); } static void -ngx_pass_open_channel(ngx_cycle_t *cycle, ngx_channel_t *ch) +ngx_pass_open_channel(ngx_cycle_t *cycle) { - ngx_int_t i; + ngx_int_t i; + ngx_channel_t ch; + + ch.command = NGX_CMD_OPEN_CHANNEL; + ch.pid = ngx_processes[ngx_process_slot].pid; + ch.slot = ngx_process_slot; + ch.fd = ngx_processes[ngx_process_slot].channel[0]; for (i = 0; i < ngx_last_process; i++) { @@ -440,14 +414,14 @@ ngx_pass_open_channel(ngx_cycle_t *cycle, ngx_channel_t *ch) ngx_log_debug6(NGX_LOG_DEBUG_CORE, cycle->log, 0, "pass channel s:%i pid:%P fd:%d to s:%i pid:%P fd:%d", - ch->slot, ch->pid, ch->fd, + ch.slot, ch.pid, ch.fd, i, ngx_processes[i].pid, ngx_processes[i].channel[0]); /* TODO: NGX_AGAIN */ ngx_write_channel(ngx_processes[i].channel[0], - ch, sizeof(ngx_channel_t), cycle->log); + &ch, sizeof(ngx_channel_t), cycle->log); } } @@ -631,12 +605,7 @@ ngx_reap_children(ngx_cycle_t *cycle) } - ch.command = NGX_CMD_OPEN_CHANNEL; - ch.pid = ngx_processes[ngx_process_slot].pid; - ch.slot = ngx_process_slot; - ch.fd = ngx_processes[ngx_process_slot].channel[0]; - - ngx_pass_open_channel(cycle, &ch); + ngx_pass_open_channel(cycle); live = 1; diff --git a/src/os/unix/ngx_udp_sendmsg_chain.c b/src/os/unix/ngx_udp_sendmsg_chain.c index 5399c79..3d1d6dd 100644 --- a/src/os/unix/ngx_udp_sendmsg_chain.c +++ b/src/os/unix/ngx_udp_sendmsg_chain.c @@ -189,6 +189,13 @@ ngx_udp_output_chain_to_iovec(ngx_iovec_t *vec, ngx_chain_t *in, ngx_log_t *log) return cl; } + /* zero-sized datagram; pretend to have at least 1 iov */ + if (n == 0) { + iov = &vec->iovs[n++]; + iov->iov_base = NULL; + iov->iov_len = 0; + } + vec->count = n; vec->size = total; diff --git a/src/stream/ngx_stream_proxy_module.c b/src/stream/ngx_stream_proxy_module.c index 7484a72..01cda7a 100644 --- a/src/stream/ngx_stream_proxy_module.c +++ b/src/stream/ngx_stream_proxy_module.c @@ -49,6 +49,7 @@ typedef struct { ngx_str_t ssl_certificate; ngx_str_t ssl_certificate_key; ngx_array_t *ssl_passwords; + ngx_array_t *ssl_conf_commands; ngx_ssl_t *ssl; #endif @@ -94,6 +95,8 @@ static char *ngx_stream_proxy_bind(ngx_conf_t *cf, ngx_command_t *cmd, static ngx_int_t ngx_stream_proxy_send_proxy_protocol(ngx_stream_session_t *s); static char *ngx_stream_proxy_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static char *ngx_stream_proxy_ssl_conf_command_check(ngx_conf_t *cf, void *post, + void *data); static void ngx_stream_proxy_ssl_init_connection(ngx_stream_session_t *s); static void ngx_stream_proxy_ssl_handshake(ngx_connection_t *pc); static void ngx_stream_proxy_ssl_save_session(ngx_connection_t *c); @@ -112,6 +115,9 @@ static ngx_conf_bitmask_t ngx_stream_proxy_ssl_protocols[] = { { ngx_null_string, 0 } }; +static ngx_conf_post_t ngx_stream_proxy_ssl_conf_command_post = + { ngx_stream_proxy_ssl_conf_command_check }; + #endif @@ -331,6 +337,13 @@ static ngx_command_t ngx_stream_proxy_commands[] = { 0, NULL }, + { ngx_string("proxy_ssl_conf_command"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE2, + ngx_conf_set_keyval_slot, + NGX_STREAM_SRV_CONF_OFFSET, + offsetof(ngx_stream_proxy_srv_conf_t, ssl_conf_commands), + &ngx_stream_proxy_ssl_conf_command_post }, + #endif ngx_null_command @@ -839,7 +852,7 @@ ngx_stream_proxy_init_upstream(ngx_stream_session_t *s) u->upstream_buf.last = p; } - if (c->buffer && c->buffer->pos < c->buffer->last) { + if (c->buffer && c->buffer->pos <= c->buffer->last) { ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0, "stream proxy add preread buffer: %uz", c->buffer->last - c->buffer->pos); @@ -853,6 +866,7 @@ ngx_stream_proxy_init_upstream(ngx_stream_session_t *s) *cl->buf = *c->buffer; cl->buf->tag = (ngx_buf_tag_t) &ngx_stream_proxy_module; + cl->buf->temporary = (cl->buf->pos == cl->buf->last) ? 0 : 1; cl->buf->flush = 1; cl->next = u->upstream_out; @@ -1007,6 +1021,17 @@ ngx_stream_proxy_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, } +static char * +ngx_stream_proxy_ssl_conf_command_check(ngx_conf_t *cf, void *post, void *data) +{ +#ifndef SSL_CONF_FLAG_FILE + return "is not supported on this platform"; +#else + return NGX_CONF_OK; +#endif +} + + static void ngx_stream_proxy_ssl_init_connection(ngx_stream_session_t *s) { @@ -1984,6 +2009,7 @@ ngx_stream_proxy_create_srv_conf(ngx_conf_t *cf) conf->ssl_verify = NGX_CONF_UNSET; conf->ssl_verify_depth = NGX_CONF_UNSET_UINT; conf->ssl_passwords = NGX_CONF_UNSET_PTR; + conf->ssl_conf_commands = NGX_CONF_UNSET_PTR; #endif return conf; @@ -2071,6 +2097,9 @@ ngx_stream_proxy_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_ptr_value(conf->ssl_passwords, prev->ssl_passwords, NULL); + ngx_conf_merge_ptr_value(conf->ssl_conf_commands, + prev->ssl_conf_commands, NULL); + if (conf->ssl_enable && ngx_stream_proxy_set_ssl(cf, conf) != NGX_OK) { return NGX_CONF_ERROR; } @@ -2155,6 +2184,12 @@ ngx_stream_proxy_set_ssl(ngx_conf_t *cf, ngx_stream_proxy_srv_conf_t *pscf) return NGX_ERROR; } + if (ngx_ssl_conf_commands(cf, pscf->ssl, pscf->ssl_conf_commands) + != NGX_OK) + { + return NGX_ERROR; + } + return NGX_OK; } diff --git a/src/stream/ngx_stream_set_module.c b/src/stream/ngx_stream_set_module.c new file mode 100644 index 0000000..9b34a60 --- /dev/null +++ b/src/stream/ngx_stream_set_module.c @@ -0,0 +1,226 @@ + +/* + * Copyright (C) Pavel Pautov + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include + + +typedef struct { + ngx_int_t index; + ngx_stream_set_variable_pt set_handler; + uintptr_t data; + ngx_stream_complex_value_t value; +} ngx_stream_set_cmd_t; + + +typedef struct { + ngx_array_t commands; +} ngx_stream_set_srv_conf_t; + + +static ngx_int_t ngx_stream_set_handler(ngx_stream_session_t *s); +static ngx_int_t ngx_stream_set_var(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_stream_set_init(ngx_conf_t *cf); +static void *ngx_stream_set_create_srv_conf(ngx_conf_t *cf); +static char *ngx_stream_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); + + +static ngx_command_t ngx_stream_set_commands[] = { + + { ngx_string("set"), + NGX_STREAM_SRV_CONF|NGX_CONF_TAKE2, + ngx_stream_set, + NGX_STREAM_SRV_CONF_OFFSET, + 0, + NULL }, + + ngx_null_command +}; + + +static ngx_stream_module_t ngx_stream_set_module_ctx = { + NULL, /* preconfiguration */ + ngx_stream_set_init, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + ngx_stream_set_create_srv_conf, /* create server configuration */ + NULL /* merge server configuration */ +}; + + +ngx_module_t ngx_stream_set_module = { + NGX_MODULE_V1, + &ngx_stream_set_module_ctx, /* module context */ + ngx_stream_set_commands, /* module directives */ + NGX_STREAM_MODULE, /* module type */ + NULL, /* init master */ + NULL, /* init module */ + NULL, /* init process */ + NULL, /* init thread */ + NULL, /* exit thread */ + NULL, /* exit process */ + NULL, /* exit master */ + NGX_MODULE_V1_PADDING +}; + + +static ngx_int_t +ngx_stream_set_handler(ngx_stream_session_t *s) +{ + ngx_str_t str; + ngx_uint_t i; + ngx_stream_set_cmd_t *cmds; + ngx_stream_set_srv_conf_t *scf; + ngx_stream_variable_value_t vv; + + scf = ngx_stream_get_module_srv_conf(s, ngx_stream_set_module); + cmds = scf->commands.elts; + vv = ngx_stream_variable_null_value; + + for (i = 0; i < scf->commands.nelts; i++) { + if (ngx_stream_complex_value(s, &cmds[i].value, &str) != NGX_OK) { + return NGX_ERROR; + } + + if (cmds[i].set_handler != NULL) { + vv.len = str.len; + vv.data = str.data; + cmds[i].set_handler(s, &vv, cmds[i].data); + + } else { + s->variables[cmds[i].index].len = str.len; + s->variables[cmds[i].index].valid = 1; + s->variables[cmds[i].index].no_cacheable = 0; + s->variables[cmds[i].index].not_found = 0; + s->variables[cmds[i].index].data = str.data; + } + } + + return NGX_DECLINED; +} + + +static ngx_int_t +ngx_stream_set_var(ngx_stream_session_t *s, ngx_stream_variable_value_t *v, + uintptr_t data) +{ + *v = ngx_stream_variable_null_value; + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_set_init(ngx_conf_t *cf) +{ + ngx_stream_handler_pt *h; + ngx_stream_core_main_conf_t *cmcf; + + cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module); + + h = ngx_array_push(&cmcf->phases[NGX_STREAM_PREACCESS_PHASE].handlers); + if (h == NULL) { + return NGX_ERROR; + } + + *h = ngx_stream_set_handler; + + return NGX_OK; +} + + +static void * +ngx_stream_set_create_srv_conf(ngx_conf_t *cf) +{ + ngx_stream_set_srv_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_stream_set_srv_conf_t)); + if (conf == NULL) { + return NULL; + } + + /* + * set by ngx_pcalloc(): + * + * conf->commands = { NULL }; + */ + + return conf; +} + + +static char * +ngx_stream_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_stream_set_srv_conf_t *scf = conf; + + ngx_str_t *args; + ngx_int_t index; + ngx_stream_set_cmd_t *set_cmd; + ngx_stream_variable_t *v; + ngx_stream_compile_complex_value_t ccv; + + args = cf->args->elts; + + if (args[1].data[0] != '$') { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid variable name \"%V\"", &args[1]); + return NGX_CONF_ERROR; + } + + args[1].len--; + args[1].data++; + + v = ngx_stream_add_variable(cf, &args[1], + NGX_STREAM_VAR_CHANGEABLE|NGX_STREAM_VAR_WEAK); + if (v == NULL) { + return NGX_CONF_ERROR; + } + + index = ngx_stream_get_variable_index(cf, &args[1]); + if (index == NGX_ERROR) { + return NGX_CONF_ERROR; + } + + if (v->get_handler == NULL) { + v->get_handler = ngx_stream_set_var; + } + + if (scf->commands.elts == NULL) { + if (ngx_array_init(&scf->commands, cf->pool, 1, + sizeof(ngx_stream_set_cmd_t)) + != NGX_OK) + { + return NGX_CONF_ERROR; + } + } + + set_cmd = ngx_array_push(&scf->commands); + if (set_cmd == NULL) { + return NGX_CONF_ERROR; + } + + set_cmd->index = index; + set_cmd->set_handler = v->set_handler; + set_cmd->data = v->data; + + ngx_memzero(&ccv, sizeof(ngx_stream_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &args[2]; + ccv.complex_value = &set_cmd->value; + + if (ngx_stream_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} diff --git a/src/stream/ngx_stream_ssl_module.c b/src/stream/ngx_stream_ssl_module.c index 79f30a8..d8c0471 100644 --- a/src/stream/ngx_stream_ssl_module.c +++ b/src/stream/ngx_stream_ssl_module.c @@ -45,6 +45,10 @@ static char *ngx_stream_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static char *ngx_stream_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); + +static char *ngx_stream_ssl_conf_command_check(ngx_conf_t *cf, void *post, + void *data); + static ngx_int_t ngx_stream_ssl_init(ngx_conf_t *cf); @@ -68,6 +72,10 @@ static ngx_conf_enum_t ngx_stream_ssl_verify[] = { }; +static ngx_conf_post_t ngx_stream_ssl_conf_command_post = + { ngx_stream_ssl_conf_command_check }; + + static ngx_command_t ngx_stream_ssl_commands[] = { { ngx_string("ssl_handshake_timeout"), @@ -196,6 +204,13 @@ static ngx_command_t ngx_stream_ssl_commands[] = { offsetof(ngx_stream_ssl_conf_t, crl), NULL }, + { ngx_string("ssl_conf_command"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE2, + ngx_conf_set_keyval_slot, + NGX_STREAM_SRV_CONF_OFFSET, + offsetof(ngx_stream_ssl_conf_t, conf_commands), + &ngx_stream_ssl_conf_command_post }, + ngx_null_command }; @@ -595,6 +610,7 @@ ngx_stream_ssl_create_conf(ngx_conf_t *cf) scf->certificates = NGX_CONF_UNSET_PTR; scf->certificate_keys = NGX_CONF_UNSET_PTR; scf->passwords = NGX_CONF_UNSET_PTR; + scf->conf_commands = NGX_CONF_UNSET_PTR; scf->prefer_server_ciphers = NGX_CONF_UNSET; scf->verify = NGX_CONF_UNSET_UINT; scf->verify_depth = NGX_CONF_UNSET_UINT; @@ -650,6 +666,8 @@ ngx_stream_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_str_value(conf->ciphers, prev->ciphers, NGX_DEFAULT_CIPHERS); + ngx_conf_merge_ptr_value(conf->conf_commands, prev->conf_commands, NULL); + conf->ssl.log = cf->log; @@ -811,6 +829,10 @@ ngx_stream_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) return NGX_CONF_ERROR; } + if (ngx_ssl_conf_commands(cf, &conf->ssl, conf->conf_commands) != NGX_OK) { + return NGX_CONF_ERROR; + } + return NGX_CONF_OK; } @@ -1034,6 +1056,17 @@ invalid: } +static char * +ngx_stream_ssl_conf_command_check(ngx_conf_t *cf, void *post, void *data) +{ +#ifndef SSL_CONF_FLAG_FILE + return "is not supported on this platform"; +#else + return NGX_CONF_OK; +#endif +} + + static ngx_int_t ngx_stream_ssl_init(ngx_conf_t *cf) { diff --git a/src/stream/ngx_stream_ssl_module.h b/src/stream/ngx_stream_ssl_module.h index 6cb4140..c6e24be 100644 --- a/src/stream/ngx_stream_ssl_module.h +++ b/src/stream/ngx_stream_ssl_module.h @@ -46,6 +46,7 @@ typedef struct { ngx_str_t ciphers; ngx_array_t *passwords; + ngx_array_t *conf_commands; ngx_shm_zone_t *shm_zone; diff --git a/src/stream/ngx_stream_upstream_round_robin.c b/src/stream/ngx_stream_upstream_round_robin.c index c207667..ae3bf37 100644 --- a/src/stream/ngx_stream_upstream_round_robin.c +++ b/src/stream/ngx_stream_upstream_round_robin.c @@ -10,8 +10,8 @@ #include -#define ngx_stream_upstream_tries(p) ((p)->number \ - + ((p)->next ? (p)->next->number : 0)) +#define ngx_stream_upstream_tries(p) ((p)->tries \ + + ((p)->next ? (p)->next->tries : 0)) static ngx_stream_upstream_rr_peer_t *ngx_stream_upstream_get_peer( @@ -38,7 +38,7 @@ ngx_stream_upstream_init_round_robin(ngx_conf_t *cf, ngx_stream_upstream_srv_conf_t *us) { ngx_url_t u; - ngx_uint_t i, j, n, w; + ngx_uint_t i, j, n, w, t; ngx_stream_upstream_server_t *server; ngx_stream_upstream_rr_peer_t *peer, **peerp; ngx_stream_upstream_rr_peers_t *peers, *backup; @@ -50,6 +50,7 @@ ngx_stream_upstream_init_round_robin(ngx_conf_t *cf, n = 0; w = 0; + t = 0; for (i = 0; i < us->servers->nelts; i++) { if (server[i].backup) { @@ -58,6 +59,10 @@ ngx_stream_upstream_init_round_robin(ngx_conf_t *cf, n += server[i].naddrs; w += server[i].naddrs * server[i].weight; + + if (!server[i].down) { + t += server[i].naddrs; + } } if (n == 0) { @@ -81,6 +86,7 @@ ngx_stream_upstream_init_round_robin(ngx_conf_t *cf, peers->number = n; peers->weighted = (w != n); peers->total_weight = w; + peers->tries = t; peers->name = &us->host; n = 0; @@ -116,6 +122,7 @@ ngx_stream_upstream_init_round_robin(ngx_conf_t *cf, n = 0; w = 0; + t = 0; for (i = 0; i < us->servers->nelts; i++) { if (!server[i].backup) { @@ -124,6 +131,10 @@ ngx_stream_upstream_init_round_robin(ngx_conf_t *cf, n += server[i].naddrs; w += server[i].naddrs * server[i].weight; + + if (!server[i].down) { + t += server[i].naddrs; + } } if (n == 0) { @@ -145,6 +156,7 @@ ngx_stream_upstream_init_round_robin(ngx_conf_t *cf, backup->number = n; backup->weighted = (w != n); backup->total_weight = w; + backup->tries = t; backup->name = &us->host; n = 0; @@ -220,6 +232,7 @@ ngx_stream_upstream_init_round_robin(ngx_conf_t *cf, peers->number = n; peers->weighted = 0; peers->total_weight = n; + peers->tries = n; peers->name = &us->host; peerp = &peers->peer; @@ -342,6 +355,7 @@ ngx_stream_upstream_create_round_robin_peer(ngx_stream_session_t *s, peers->single = (ur->naddrs == 1); peers->number = ur->naddrs; + peers->tries = ur->naddrs; peers->name = &ur->host; if (ur->sockaddr) { diff --git a/src/stream/ngx_stream_upstream_round_robin.h b/src/stream/ngx_stream_upstream_round_robin.h index 35d9fce..bd96667 100644 --- a/src/stream/ngx_stream_upstream_round_robin.h +++ b/src/stream/ngx_stream_upstream_round_robin.h @@ -66,6 +66,7 @@ struct ngx_stream_upstream_rr_peers_s { #endif ngx_uint_t total_weight; + ngx_uint_t tries; unsigned single:1; unsigned weighted:1; diff --git a/src/stream/ngx_stream_write_filter_module.c b/src/stream/ngx_stream_write_filter_module.c index 24326c6..156a61c 100644 --- a/src/stream/ngx_stream_write_filter_module.c +++ b/src/stream/ngx_stream_write_filter_module.c @@ -234,7 +234,8 @@ ngx_stream_write_filter(ngx_stream_session_t *s, ngx_chain_t *in, if (size == 0 && !(c->buffered & NGX_LOWLEVEL_BUFFERED) - && !(last && c->need_last_buf)) + && !(last && c->need_last_buf) + && !(c->type == SOCK_DGRAM && flush)) { if (last || flush || sync) { for (cl = *out; cl; /* void */) { From c85dfc1d2b1e718623b7d5bdda80a32d830b97c7 Mon Sep 17 00:00:00 2001 From: Thomas Ward Date: Tue, 19 Apr 2022 09:58:16 -0400 Subject: [PATCH 092/329] New 1.20.2 version, drop unneeded patch --- configure | 4 +++ debian/changelog | 10 ++++++ ...ff-by-one-write-in-ngx_resolver_copy.patch | 34 ------------------- debian/patches/series | 1 - 4 files changed, 14 insertions(+), 35 deletions(-) delete mode 100644 debian/patches/Resolver-fixed-off-by-one-write-in-ngx_resolver_copy.patch diff --git a/configure b/configure index 474d69e..b7c507a 100755 --- a/configure +++ b/configure @@ -58,6 +58,10 @@ if [ "$NGX_PLATFORM" != win32 ]; then . auto/unix fi +# Debian +# Make sure signature stays the same on all nginx flavors +have=NGX_HTTP_HEADERS . auto/have + . auto/threads . auto/modules . auto/lib/conf diff --git a/debian/changelog b/debian/changelog index e65ef2c..92a1d6a 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,13 @@ +nginx (1.20.2-1) UNRELEASED; urgency=medium + + * This is an NGINX Maintainer Team upload. + * Update to latest upstream Stable version (1.20.2) (Closes: #1008855) + * d/patches/Resolver-fixed-off-by-one-write-in-ngx_resolver + _copy.patch: Drop CVE-2021-23017 patch, as this is fixed in 1.20.1 + and we are now using 1.20.2 which already contains the patch. + + -- Thomas Ward Tue, 19 Apr 2022 09:50:42 -0400 + nginx (1.18.0-9) unstable; urgency=medium [ Jan Mojžíš ] diff --git a/debian/patches/Resolver-fixed-off-by-one-write-in-ngx_resolver_copy.patch b/debian/patches/Resolver-fixed-off-by-one-write-in-ngx_resolver_copy.patch deleted file mode 100644 index 449c096..0000000 --- a/debian/patches/Resolver-fixed-off-by-one-write-in-ngx_resolver_copy.patch +++ /dev/null @@ -1,34 +0,0 @@ -From: Maxim Dounin -Date: Tue, 25 May 2021 15:17:36 +0300 -Subject: Resolver: fixed off-by-one write in ngx_resolver_copy(). -Origin: https://github.com/nginx/nginx/commit/7199ebc203f74fd9e44595474de6bdc41740c5cf -Bug-Debian: https://bugs.debian.org/989095 -Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2021-23017 - -Reported by Luis Merino, Markus Vervier, Eric Sesterhenn, X41 D-Sec GmbH. ---- - src/core/ngx_resolver.c | 8 ++++---- - 1 file changed, 4 insertions(+), 4 deletions(-) - ---- a/src/core/ngx_resolver.c -+++ b/src/core/ngx_resolver.c -@@ -3993,15 +3993,15 @@ - n = *src++; - - } else { -+ if (dst != name->data) { -+ *dst++ = '.'; -+ } -+ - ngx_strlow(dst, src, n); - dst += n; - src += n; - - n = *src++; -- -- if (n != 0) { -- *dst++ = '.'; -- } - } - - if (n == 0) { diff --git a/debian/patches/series b/debian/patches/series index 9416267..5b6b799 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -1,3 +1,2 @@ 0002-Make-sure-signature-stays-the-same-in-all-nginx-buil.patch 0003-define_gnu_source-on-other-glibc-based-platforms.patch -Resolver-fixed-off-by-one-write-in-ngx_resolver_copy.patch From 9cb8bb9efcc7a2830d6be4593d910c58873ede72 Mon Sep 17 00:00:00 2001 From: Thomas Ward Date: Tue, 19 Apr 2022 10:07:47 -0400 Subject: [PATCH 093/329] Fix some branch uncleanliness that happened in local branch which made it to Salsa --- configure | 4 ---- debian/changelog | 4 +++- ...Make-sure-signature-stays-the-same-in-all-nginx-buil.patch | 4 +--- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/configure b/configure index b7c507a..474d69e 100755 --- a/configure +++ b/configure @@ -58,10 +58,6 @@ if [ "$NGX_PLATFORM" != win32 ]; then . auto/unix fi -# Debian -# Make sure signature stays the same on all nginx flavors -have=NGX_HTTP_HEADERS . auto/have - . auto/threads . auto/modules . auto/lib/conf diff --git a/debian/changelog b/debian/changelog index 92a1d6a..b9daae0 100644 --- a/debian/changelog +++ b/debian/changelog @@ -5,7 +5,9 @@ nginx (1.20.2-1) UNRELEASED; urgency=medium * d/patches/Resolver-fixed-off-by-one-write-in-ngx_resolver _copy.patch: Drop CVE-2021-23017 patch, as this is fixed in 1.20.1 and we are now using 1.20.2 which already contains the patch. - + * Refreshed d/patches/0002-Make-sure-signature-stays-the-same- + in-all-nginx-buil.patch (fuzz thanks to 1.20.2) + -- Thomas Ward Tue, 19 Apr 2022 09:50:42 -0400 nginx (1.18.0-9) unstable; urgency=medium diff --git a/debian/patches/0002-Make-sure-signature-stays-the-same-in-all-nginx-buil.patch b/debian/patches/0002-Make-sure-signature-stays-the-same-in-all-nginx-buil.patch index 9cc3962..9e27e1a 100644 --- a/debian/patches/0002-Make-sure-signature-stays-the-same-in-all-nginx-buil.patch +++ b/debian/patches/0002-Make-sure-signature-stays-the-same-in-all-nginx-buil.patch @@ -13,11 +13,9 @@ binaries share the same signature. configure | 4 ++++ 1 file changed, 4 insertions(+) -diff --git a/configure b/configure -index ceff15e..3816fa1 100755 --- a/configure +++ b/configure -@@ -58,6 +58,10 @@ if [ "$NGX_PLATFORM" != win32 ]; then +@@ -58,6 +58,10 @@ . auto/unix fi From 528e57d73dcd7a728b0b65f857e3ab4c1ecc8ef3 Mon Sep 17 00:00:00 2001 From: Thomas Ward Date: Tue, 19 Apr 2022 10:26:55 -0400 Subject: [PATCH 094/329] Update d/conf/mime.types --- debian/changelog | 2 ++ debian/conf/mime.types | 23 ++++++++++++++--------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/debian/changelog b/debian/changelog index b9daae0..19d30df 100644 --- a/debian/changelog +++ b/debian/changelog @@ -7,6 +7,8 @@ nginx (1.20.2-1) UNRELEASED; urgency=medium and we are now using 1.20.2 which already contains the patch. * Refreshed d/patches/0002-Make-sure-signature-stays-the-same- in-all-nginx-buil.patch (fuzz thanks to 1.20.2) + * d/conf/mime.types: Update mime.types to more match upstream mime.types + and include upstream changes with mime.types from 1.20.2. -- Thomas Ward Tue, 19 Apr 2022 09:50:42 -0400 diff --git a/debian/conf/mime.types b/debian/conf/mime.types index 89be9a4..3bd94e5 100644 --- a/debian/conf/mime.types +++ b/debian/conf/mime.types @@ -16,15 +16,17 @@ types { text/x-component htc; image/png png; + image/svg+xml svg svgz; image/tiff tif tiff; image/vnd.wap.wbmp wbmp; + image/webp webp; image/x-icon ico; image/x-jng jng; image/x-ms-bmp bmp; - image/svg+xml svg svgz; - image/webp webp; - application/font-woff woff; + font/woff woff; + font/woff2 woff; + application/java-archive jar war ear; application/json json; application/mac-binhex40 hqx; @@ -33,12 +35,19 @@ types { application/postscript ps eps ai; application/rtf rtf; application/vnd.apple.mpegurl m3u8; + application/vnd.google-earth.kml+xml kml; + application/vnd.google-earth.kmz kmz; application/vnd.ms-excel xls; application/vnd.ms-fontobject eot; application/vnd.ms-powerpoint ppt; + application/vnd.oasis.opendocument.graphics odg; + application/vnd.oasis.opendocument.presentation odp; + application/vnd.oasis.opendocument.spreadsheet ods; + application/vnd.oasis.opendocument.text odt; + application/vnd.openxmlformats-officedocument.presentationml.presentation pptx; + application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx; + application/vnd.openxmlformats-officedocument.wordprocessingml.document docx; application/vnd.wap.wmlc wmlc; - application/vnd.google-earth.kml+xml kml; - application/vnd.google-earth.kmz kmz; application/x-7z-compressed 7z; application/x-cocoa cco; application/x-java-archive-diff jardiff; @@ -64,10 +73,6 @@ types { application/octet-stream iso img; application/octet-stream msi msp msm; - application/vnd.openxmlformats-officedocument.wordprocessingml.document docx; - application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx; - application/vnd.openxmlformats-officedocument.presentationml.presentation pptx; - audio/midi mid midi kar; audio/mpeg mp3; audio/ogg ogg; From 9bc813d5a2a6a5707ad356007170d0f422508f54 Mon Sep 17 00:00:00 2001 From: Thomas Ward Date: Tue, 19 Apr 2022 10:37:35 -0400 Subject: [PATCH 095/329] Remove self from uploaders per other DDs --- debian/changelog | 3 +++ debian/control | 1 - 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 19d30df..d851b0d 100644 --- a/debian/changelog +++ b/debian/changelog @@ -9,6 +9,9 @@ nginx (1.20.2-1) UNRELEASED; urgency=medium in-all-nginx-buil.patch (fuzz thanks to 1.20.2) * d/conf/mime.types: Update mime.types to more match upstream mime.types and include upstream changes with mime.types from 1.20.2. + * d/control: Remove self from Uploaders per other Debian devs, who want + that commit to be done by someone on the current uploaders/maintainers + group instead. -- Thomas Ward Tue, 19 Apr 2022 09:50:42 -0400 diff --git a/debian/control b/debian/control index 52b24de..44b741e 100644 --- a/debian/control +++ b/debian/control @@ -4,7 +4,6 @@ Priority: optional Maintainer: Debian Nginx Maintainers Uploaders: Christos Trochalakis , Ondřej Nový , - Thomas Ward , Build-Depends: debhelper-compat (= 13), dpkg-dev (>= 1.15.5), libexpat-dev, From 8735246ec068c25949a2fbd819060780f3f92fbd Mon Sep 17 00:00:00 2001 From: Thomas Ward Date: Tue, 19 Apr 2022 12:26:14 -0400 Subject: [PATCH 096/329] Update d/conf/mime.types again using 1.21.x upstream --- debian/changelog | 3 ++- debian/conf/mime.types | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index d851b0d..497d4b1 100644 --- a/debian/changelog +++ b/debian/changelog @@ -8,7 +8,8 @@ nginx (1.20.2-1) UNRELEASED; urgency=medium * Refreshed d/patches/0002-Make-sure-signature-stays-the-same- in-all-nginx-buil.patch (fuzz thanks to 1.20.2) * d/conf/mime.types: Update mime.types to more match upstream mime.types - and include upstream changes with mime.types from 1.20.2. + and include upstream changes with mime.types from 1.21.x via nginx.org + mercurial repository versions. * d/control: Remove self from Uploaders per other Debian devs, who want that commit to be done by someone on the current uploaders/maintainers group instead. diff --git a/debian/conf/mime.types b/debian/conf/mime.types index 3bd94e5..cfa1714 100644 --- a/debian/conf/mime.types +++ b/debian/conf/mime.types @@ -15,6 +15,7 @@ types { text/vnd.wap.wml wml; text/x-component htc; + image/avif avif; image/png png; image/svg+xml svg svgz; image/tiff tif tiff; From 48b9b6e3ea956358bb8b7497ce6db9569ea144e5 Mon Sep 17 00:00:00 2001 From: Thomas Ward Date: Tue, 19 Apr 2022 12:27:49 -0400 Subject: [PATCH 097/329] Missed part of mime.types updates --- debian/conf/mime.types | 1 + 1 file changed, 1 insertion(+) diff --git a/debian/conf/mime.types b/debian/conf/mime.types index cfa1714..d55df56 100644 --- a/debian/conf/mime.types +++ b/debian/conf/mime.types @@ -49,6 +49,7 @@ types { application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx; application/vnd.openxmlformats-officedocument.wordprocessingml.document docx; application/vnd.wap.wmlc wmlc; + application/wasm wasm; application/x-7z-compressed 7z; application/x-cocoa cco; application/x-java-archive-diff jardiff; From 1fcb59adce7213aeba8ff5b42df2134125fd03f9 Mon Sep 17 00:00:00 2001 From: Thomas Ward Date: Thu, 21 Apr 2022 11:20:04 -0400 Subject: [PATCH 098/329] 1.20.2-1 release --- debian/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 497d4b1..0fdcbe6 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -nginx (1.20.2-1) UNRELEASED; urgency=medium +nginx (1.20.2-1) unstable; urgency=medium * This is an NGINX Maintainer Team upload. * Update to latest upstream Stable version (1.20.2) (Closes: #1008855) From 9c7d79dce0f34774b1505b53450c786c0b6e4a57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Nov=C3=BD?= Date: Wed, 4 May 2022 15:45:04 +0200 Subject: [PATCH 099/329] Add Thomas Ward as uploader --- debian/control | 1 + 1 file changed, 1 insertion(+) diff --git a/debian/control b/debian/control index 44b741e..52b24de 100644 --- a/debian/control +++ b/debian/control @@ -4,6 +4,7 @@ Priority: optional Maintainer: Debian Nginx Maintainers Uploaders: Christos Trochalakis , Ondřej Nový , + Thomas Ward , Build-Depends: debhelper-compat (= 13), dpkg-dev (>= 1.15.5), libexpat-dev, From 45005f76d4dfaee9e0ca477eb92bc4453008f712 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Nov=C3=BD?= Date: Wed, 4 May 2022 15:45:57 +0200 Subject: [PATCH 100/329] =?UTF-8?q?Add=20Jan=20Moj=C5=BE=C3=AD=C5=A1=20=20as=20uploader?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- debian/control | 1 + 1 file changed, 1 insertion(+) diff --git a/debian/control b/debian/control index 52b24de..cc32589 100644 --- a/debian/control +++ b/debian/control @@ -5,6 +5,7 @@ Maintainer: Debian Nginx Maintainers , Ondřej Nový , Thomas Ward , + Jan Mojžíš , Build-Depends: debhelper-compat (= 13), dpkg-dev (>= 1.15.5), libexpat-dev, From 747ca190d0950815163158b7631e3286a5fce7f8 Mon Sep 17 00:00:00 2001 From: Thomas Ward Date: Wed, 4 May 2022 10:56:19 -0400 Subject: [PATCH 101/329] Update packaging - this was done by Ondrej, let's make it live --- debian/changelog | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 0fdcbe6..a8e366e 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,6 +1,9 @@ nginx (1.20.2-1) unstable; urgency=medium - * This is an NGINX Maintainer Team upload. + [ Ondřej Nový ] + * d/control: Update Uploaders for new maintainers. + + [ Thomas Ward ] * Update to latest upstream Stable version (1.20.2) (Closes: #1008855) * d/patches/Resolver-fixed-off-by-one-write-in-ngx_resolver _copy.patch: Drop CVE-2021-23017 patch, as this is fixed in 1.20.1 From 9c33aafeff59fe7be599fb3ace016d02cd39d47e Mon Sep 17 00:00:00 2001 From: Thomas Ward Date: Wed, 4 May 2022 15:35:09 -0400 Subject: [PATCH 102/329] Add CVE-2021-3618 patches and mitigations --- configure | 4 ++++ debian/patches/series | 1 + src/mail/ngx_mail.h | 3 +++ src/mail/ngx_mail_core_module.c | 10 ++++++++++ src/mail/ngx_mail_handler.c | 15 ++++++++++++++- src/os/unix/ngx_posix_config.h | 5 ++++- 6 files changed, 36 insertions(+), 2 deletions(-) diff --git a/configure b/configure index 474d69e..b7c507a 100755 --- a/configure +++ b/configure @@ -58,6 +58,10 @@ if [ "$NGX_PLATFORM" != win32 ]; then . auto/unix fi +# Debian +# Make sure signature stays the same on all nginx flavors +have=NGX_HTTP_HEADERS . auto/have + . auto/threads . auto/modules . auto/lib/conf diff --git a/debian/patches/series b/debian/patches/series index 5b6b799..4e43575 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -1,2 +1,3 @@ 0002-Make-sure-signature-stays-the-same-in-all-nginx-buil.patch 0003-define_gnu_source-on-other-glibc-based-platforms.patch +CVE-2021-3618.patch diff --git a/src/mail/ngx_mail.h b/src/mail/ngx_mail.h index b865a3b..76cae37 100644 --- a/src/mail/ngx_mail.h +++ b/src/mail/ngx_mail.h @@ -115,6 +115,8 @@ typedef struct { ngx_msec_t timeout; ngx_msec_t resolver_timeout; + ngx_uint_t max_errors; + ngx_str_t server_name; u_char *file_name; @@ -231,6 +233,7 @@ typedef struct { ngx_uint_t command; ngx_array_t args; + ngx_uint_t errors; ngx_uint_t login_attempt; /* used to parse POP3/IMAP/SMTP command */ diff --git a/src/mail/ngx_mail_core_module.c b/src/mail/ngx_mail_core_module.c index 4083124..115671c 100644 --- a/src/mail/ngx_mail_core_module.c +++ b/src/mail/ngx_mail_core_module.c @@ -85,6 +85,13 @@ static ngx_command_t ngx_mail_core_commands[] = { offsetof(ngx_mail_core_srv_conf_t, resolver_timeout), NULL }, + { ngx_string("max_errors"), + NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_MAIL_SRV_CONF_OFFSET, + offsetof(ngx_mail_core_srv_conf_t, max_errors), + NULL }, + ngx_null_command }; @@ -163,6 +170,8 @@ ngx_mail_core_create_srv_conf(ngx_conf_t *cf) cscf->timeout = NGX_CONF_UNSET_MSEC; cscf->resolver_timeout = NGX_CONF_UNSET_MSEC; + cscf->max_errors = NGX_CONF_UNSET_UINT; + cscf->resolver = NGX_CONF_UNSET_PTR; cscf->file_name = cf->conf_file->file.name.data; @@ -182,6 +191,7 @@ ngx_mail_core_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_msec_value(conf->resolver_timeout, prev->resolver_timeout, 30000); + ngx_conf_merge_uint_value(conf->max_errors, prev->max_errors, 5); ngx_conf_merge_str_value(conf->server_name, prev->server_name, ""); diff --git a/src/mail/ngx_mail_handler.c b/src/mail/ngx_mail_handler.c index 0aaa0e7..71b8151 100644 --- a/src/mail/ngx_mail_handler.c +++ b/src/mail/ngx_mail_handler.c @@ -871,7 +871,20 @@ ngx_mail_read_command(ngx_mail_session_t *s, ngx_connection_t *c) return NGX_MAIL_PARSE_INVALID_COMMAND; } - if (rc == NGX_IMAP_NEXT || rc == NGX_MAIL_PARSE_INVALID_COMMAND) { + if (rc == NGX_MAIL_PARSE_INVALID_COMMAND) { + + s->errors++; + + if (s->errors >= cscf->max_errors) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "client sent too many invalid commands"); + s->quit = 1; + } + + return rc; + } + + if (rc == NGX_IMAP_NEXT) { return rc; } diff --git a/src/os/unix/ngx_posix_config.h b/src/os/unix/ngx_posix_config.h index 2a8c413..03f7e0a 100644 --- a/src/os/unix/ngx_posix_config.h +++ b/src/os/unix/ngx_posix_config.h @@ -21,10 +21,13 @@ #endif -#if (NGX_GNU_HURD) +#if defined(__GLIBC__) #ifndef _GNU_SOURCE #define _GNU_SOURCE /* accept4() */ #endif +#endif + +#if (NGX_GNU_HURD) #define _FILE_OFFSET_BITS 64 #endif From ad330f7cb1ff7d791dc8255bf679dc87008e4255 Mon Sep 17 00:00:00 2001 From: Thomas Ward Date: Wed, 4 May 2022 15:35:34 -0400 Subject: [PATCH 103/329] Unpop all patches to keep tree clean --- configure | 4 ---- src/mail/ngx_mail.h | 3 --- src/mail/ngx_mail_core_module.c | 10 ---------- src/mail/ngx_mail_handler.c | 15 +-------------- src/os/unix/ngx_posix_config.h | 5 +---- 5 files changed, 2 insertions(+), 35 deletions(-) diff --git a/configure b/configure index b7c507a..474d69e 100755 --- a/configure +++ b/configure @@ -58,10 +58,6 @@ if [ "$NGX_PLATFORM" != win32 ]; then . auto/unix fi -# Debian -# Make sure signature stays the same on all nginx flavors -have=NGX_HTTP_HEADERS . auto/have - . auto/threads . auto/modules . auto/lib/conf diff --git a/src/mail/ngx_mail.h b/src/mail/ngx_mail.h index 76cae37..b865a3b 100644 --- a/src/mail/ngx_mail.h +++ b/src/mail/ngx_mail.h @@ -115,8 +115,6 @@ typedef struct { ngx_msec_t timeout; ngx_msec_t resolver_timeout; - ngx_uint_t max_errors; - ngx_str_t server_name; u_char *file_name; @@ -233,7 +231,6 @@ typedef struct { ngx_uint_t command; ngx_array_t args; - ngx_uint_t errors; ngx_uint_t login_attempt; /* used to parse POP3/IMAP/SMTP command */ diff --git a/src/mail/ngx_mail_core_module.c b/src/mail/ngx_mail_core_module.c index 115671c..4083124 100644 --- a/src/mail/ngx_mail_core_module.c +++ b/src/mail/ngx_mail_core_module.c @@ -85,13 +85,6 @@ static ngx_command_t ngx_mail_core_commands[] = { offsetof(ngx_mail_core_srv_conf_t, resolver_timeout), NULL }, - { ngx_string("max_errors"), - NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_num_slot, - NGX_MAIL_SRV_CONF_OFFSET, - offsetof(ngx_mail_core_srv_conf_t, max_errors), - NULL }, - ngx_null_command }; @@ -170,8 +163,6 @@ ngx_mail_core_create_srv_conf(ngx_conf_t *cf) cscf->timeout = NGX_CONF_UNSET_MSEC; cscf->resolver_timeout = NGX_CONF_UNSET_MSEC; - cscf->max_errors = NGX_CONF_UNSET_UINT; - cscf->resolver = NGX_CONF_UNSET_PTR; cscf->file_name = cf->conf_file->file.name.data; @@ -191,7 +182,6 @@ ngx_mail_core_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_msec_value(conf->resolver_timeout, prev->resolver_timeout, 30000); - ngx_conf_merge_uint_value(conf->max_errors, prev->max_errors, 5); ngx_conf_merge_str_value(conf->server_name, prev->server_name, ""); diff --git a/src/mail/ngx_mail_handler.c b/src/mail/ngx_mail_handler.c index 71b8151..0aaa0e7 100644 --- a/src/mail/ngx_mail_handler.c +++ b/src/mail/ngx_mail_handler.c @@ -871,20 +871,7 @@ ngx_mail_read_command(ngx_mail_session_t *s, ngx_connection_t *c) return NGX_MAIL_PARSE_INVALID_COMMAND; } - if (rc == NGX_MAIL_PARSE_INVALID_COMMAND) { - - s->errors++; - - if (s->errors >= cscf->max_errors) { - ngx_log_error(NGX_LOG_INFO, c->log, 0, - "client sent too many invalid commands"); - s->quit = 1; - } - - return rc; - } - - if (rc == NGX_IMAP_NEXT) { + if (rc == NGX_IMAP_NEXT || rc == NGX_MAIL_PARSE_INVALID_COMMAND) { return rc; } diff --git a/src/os/unix/ngx_posix_config.h b/src/os/unix/ngx_posix_config.h index 03f7e0a..2a8c413 100644 --- a/src/os/unix/ngx_posix_config.h +++ b/src/os/unix/ngx_posix_config.h @@ -21,13 +21,10 @@ #endif -#if defined(__GLIBC__) +#if (NGX_GNU_HURD) #ifndef _GNU_SOURCE #define _GNU_SOURCE /* accept4() */ #endif -#endif - -#if (NGX_GNU_HURD) #define _FILE_OFFSET_BITS 64 #endif From 4514c0f658d7ab5170d1ae6765a847d1934b96a2 Mon Sep 17 00:00:00 2001 From: Thomas Ward Date: Wed, 4 May 2022 16:06:32 -0400 Subject: [PATCH 104/329] Add changelong for CVE patch inclusion --- debian/changelog | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/debian/changelog b/debian/changelog index a8e366e..39bedc2 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,11 @@ +nginx (1.20.2-2) UNRELEASED; urgency=medium + + * d/patches/CVE-2021-3618.patch: Include upstream changeset from NGINX + that adds mitigations into the Mail module for CVE-2021-3618.patch. + (Closes: #991328) + + -- Thomas Ward Wed, 04 May 2022 16:04:59 -0400 + nginx (1.20.2-1) unstable; urgency=medium [ Ondřej Nový ] From 2c5ea38623cc2a64907e210794ea1aed0b84d30e Mon Sep 17 00:00:00 2001 From: Thomas Ward Date: Wed, 4 May 2022 20:18:41 -0400 Subject: [PATCH 105/329] Oops forgot to add the patch --- debian/patches/CVE-2021-3618.patch | 84 ++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 debian/patches/CVE-2021-3618.patch diff --git a/debian/patches/CVE-2021-3618.patch b/debian/patches/CVE-2021-3618.patch new file mode 100644 index 0000000..10f37a9 --- /dev/null +++ b/debian/patches/CVE-2021-3618.patch @@ -0,0 +1,84 @@ +Subject: Patch mitigation for CVE-2021-3618 + Mail: max_errors directive. + . + Similarly to smtpd_hard_error_limit in Postfix and smtp_max_unknown_commands + in Exim, specifies the number of errors after which the connection is closed. +Origin: upstream, http://hg.nginx.org/nginx/rev/ec1071830799 +Bug-Debian: https://bugs.debian.org/991328 + +--- a/src/mail/ngx_mail.h ++++ b/src/mail/ngx_mail.h +@@ -115,6 +115,8 @@ + ngx_msec_t timeout; + ngx_msec_t resolver_timeout; + ++ ngx_uint_t max_errors; ++ + ngx_str_t server_name; + + u_char *file_name; +@@ -231,6 +233,7 @@ + ngx_uint_t command; + ngx_array_t args; + ++ ngx_uint_t errors; + ngx_uint_t login_attempt; + + /* used to parse POP3/IMAP/SMTP command */ +--- a/src/mail/ngx_mail_core_module.c ++++ b/src/mail/ngx_mail_core_module.c +@@ -85,6 +85,13 @@ + offsetof(ngx_mail_core_srv_conf_t, resolver_timeout), + NULL }, + ++ { ngx_string("max_errors"), ++ NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, ++ ngx_conf_set_num_slot, ++ NGX_MAIL_SRV_CONF_OFFSET, ++ offsetof(ngx_mail_core_srv_conf_t, max_errors), ++ NULL }, ++ + ngx_null_command + }; + +@@ -163,6 +170,8 @@ + cscf->timeout = NGX_CONF_UNSET_MSEC; + cscf->resolver_timeout = NGX_CONF_UNSET_MSEC; + ++ cscf->max_errors = NGX_CONF_UNSET_UINT; ++ + cscf->resolver = NGX_CONF_UNSET_PTR; + + cscf->file_name = cf->conf_file->file.name.data; +@@ -182,6 +191,7 @@ + ngx_conf_merge_msec_value(conf->resolver_timeout, prev->resolver_timeout, + 30000); + ++ ngx_conf_merge_uint_value(conf->max_errors, prev->max_errors, 5); + + ngx_conf_merge_str_value(conf->server_name, prev->server_name, ""); + +--- a/src/mail/ngx_mail_handler.c ++++ b/src/mail/ngx_mail_handler.c +@@ -871,7 +871,20 @@ + return NGX_MAIL_PARSE_INVALID_COMMAND; + } + +- if (rc == NGX_IMAP_NEXT || rc == NGX_MAIL_PARSE_INVALID_COMMAND) { ++ if (rc == NGX_MAIL_PARSE_INVALID_COMMAND) { ++ ++ s->errors++; ++ ++ if (s->errors >= cscf->max_errors) { ++ ngx_log_error(NGX_LOG_INFO, c->log, 0, ++ "client sent too many invalid commands"); ++ s->quit = 1; ++ } ++ ++ return rc; ++ } ++ ++ if (rc == NGX_IMAP_NEXT) { + return rc; + } + From 78d84c5752e34dce414523e4b5edcf569a0d90ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Thu, 5 May 2022 06:49:36 +0200 Subject: [PATCH 106/329] d/p/0003-define_gnu_source-on-other-glibc-based-platforms.patch update fixes build on hurd-i386 --- debian/changelog | 5 +++++ ...ine_gnu_source-on-other-glibc-based-platforms.patch | 10 +++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/debian/changelog b/debian/changelog index 39bedc2..3b651cd 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,9 +1,14 @@ nginx (1.20.2-2) UNRELEASED; urgency=medium + [ Thomas Ward ] * d/patches/CVE-2021-3618.patch: Include upstream changeset from NGINX that adds mitigations into the Mail module for CVE-2021-3618.patch. (Closes: #991328) + [ Jan Mojžíš ] + * d/p/0003-define_gnu_source-on-other-glibc-based-platforms.patch update, + fixes build on hurd-i386 platform + -- Thomas Ward Wed, 04 May 2022 16:04:59 -0400 nginx (1.20.2-1) unstable; urgency=medium diff --git a/debian/patches/0003-define_gnu_source-on-other-glibc-based-platforms.patch b/debian/patches/0003-define_gnu_source-on-other-glibc-based-platforms.patch index bb9b089..d43fd23 100644 --- a/debian/patches/0003-define_gnu_source-on-other-glibc-based-platforms.patch +++ b/debian/patches/0003-define_gnu_source-on-other-glibc-based-platforms.patch @@ -4,14 +4,18 @@ Subject: Use _GNU_SOURCE on GNU/kFreeBSD Define _GNU_SOURCE not only on GNU/Hurd, but also other glibc-based platforms including GNU/kFreeBSD. ---- a/src/os/unix/ngx_posix_config.h -+++ b/src/os/unix/ngx_posix_config.h + +modified by jan.mojzis@gmail.com +Index: nginx/src/os/unix/ngx_posix_config.h +=================================================================== +--- nginx.orig/src/os/unix/ngx_posix_config.h ++++ nginx/src/os/unix/ngx_posix_config.h @@ -21,10 +21,13 @@ #endif -#if (NGX_GNU_HURD) -+#if defined(__GLIBC__) ++#if defined(NGX_GNU_HURD) || defined(__GLIBC__) #ifndef _GNU_SOURCE #define _GNU_SOURCE /* accept4() */ #endif From 9a6a526958f6e1157347f0af236316317a290a3c Mon Sep 17 00:00:00 2001 From: Thomas Ward Date: Mon, 9 May 2022 11:55:56 -0400 Subject: [PATCH 107/329] 1.20.2-2 release --- debian/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 3b651cd..4240fae 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -nginx (1.20.2-2) UNRELEASED; urgency=medium +nginx (1.20.2-2) unstable; urgency=medium [ Thomas Ward ] * d/patches/CVE-2021-3618.patch: Include upstream changeset from NGINX From 9b87224f4f5357e7146e6b56fb6da20f0d260d05 Mon Sep 17 00:00:00 2001 From: Thomas Ward Date: Tue, 10 May 2022 12:08:52 -0400 Subject: [PATCH 108/329] Bug 1010798 - fixes woff2 typo --- debian/changelog | 7 +++++++ debian/conf/mime.types | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 4240fae..3b9b5b7 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,10 @@ +nginx (1.20.2-3) UNRELEASED; urgency=medium + + * d/conf/mime.types: Fix a typo in font/woff2 extension in + mime.types. (Closes: #1010798) + + -- Thomas Ward Tue, 10 May 2022 12:08:02 -0400 + nginx (1.20.2-2) unstable; urgency=medium [ Thomas Ward ] diff --git a/debian/conf/mime.types b/debian/conf/mime.types index d55df56..692b16c 100644 --- a/debian/conf/mime.types +++ b/debian/conf/mime.types @@ -26,7 +26,7 @@ types { image/x-ms-bmp bmp; font/woff woff; - font/woff2 woff; + font/woff2 woff2; application/java-archive jar war ear; application/json json; From 493d6c7b862858fe5ae2acef6b952bb02f782f05 Mon Sep 17 00:00:00 2001 From: Thomas Ward Date: Tue, 24 May 2022 14:18:52 -0400 Subject: [PATCH 109/329] Update signing keys - new upstream signing key(s) observed. --- debian/upstream/signing-key.asc | 65 +++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/debian/upstream/signing-key.asc b/debian/upstream/signing-key.asc index 01a2a5f..5e36f56 100644 --- a/debian/upstream/signing-key.asc +++ b/debian/upstream/signing-key.asc @@ -1,3 +1,6 @@ +# Previously used as signing key up through May 24, 2022 +# and may be used in future. Keep this around intentionally as such. +# gpg: pub rsa2048/520A9993A1C052F8 2011-11-27 Maxim Dounin -----BEGIN PGP PUBLIC KEY BLOCK----- mQENBE7SKu8BCADQo6x4ZQfAcPlJMLmL8zBEBUS6GyKMMMDtrTh3Yaq481HB54oR @@ -27,3 +30,65 @@ QE2uIxTCawHr12PsllPkbqPk/PagIttfEJqn9b0CrqPC3HREePb2aMJ/Ctw/76CO wn0mtXeIXLCTvBmznXfaMKllsqbsy2nCJ2P2uJjOntw= =NeQn -----END PGP PUBLIC KEY BLOCK----- + + +# First observed on May 24, 2022 +# +# pub rsa3072 2018-05-07 [SC] [expires: 2027-05-17] +# 13C82A63B603576156E30A4EA0EA981B66B0D967 +#uid [ unknown] Konstantin Pavlov +#uid [ unknown] Konstantin Pavlov +#sub rsa3072 2018-05-07 [E] [expires: 2027-05-17] + +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mQGNBFrwMiUBDADo56OlDknN+ReCMP+8CN1biK5izmGd755TxktHLI9nAP8ociIq +Hjrps22pBtAIQ6eZpwCFBys2mR/441rOgZW+O6uqBYrttbxTMvE43EmKYGuFCmuR +u0JGMPuqnzF3Y+6uoKzqMzazSrZIBWsBKAkNYTw8+yPlxGgffhBp1ueME7Lskglh +EV9gmrEM0QlWod7wSQvyruExPm5INx3MG63Xfvc0bPiWUOGKyMb7kXA5VgnWuzmS +BCMm17+A32vMyxhYcvSEgUayQjGghI1uPDSqBQBMEFTgSK2wWzvAXf/M45nxKBgQ +IEDmvoC8RM9JTtUr7RE/E1mjsuefF2vYYYsWBstRFGAlUV1/lPNNibu3NqbCug6b +1IWJuV1DX9T9/f81GZJrsPgYYKC6Ai8C1B0NGWjos7/GzgEFENQgf5duOhFPadQz +QbRxBoId4Fe/Uwe2HxI8ESCQMwsq8bowcCn6XRA2EYkAt17Kab6LH6tTP54XG9TL +bV7bAhyrvZAk1lUAEQEAAbQjS29uc3RhbnRpbiBQYXZsb3YgPGsucGF2bG92QGY1 +LmNvbT6JAdcEEwEIAEECGwMFCwkIBwICIgIGFQoJCAsCBBYCAwECHgcCF4AWIQQT +yCpjtgNXYVbjCk6g6pgbZrDZZwUCYoTfvAUJEPqvFwAKCRCg6pgbZrDZZxFYDADK +R02XgC+AoyrqMwBNXC8Y6aiilEsyppsgj+KwZcGKDYN488gEmff+/KIEdtglw3I3 +tCMbo+FzFjHveeVCb0qrIMerWJg+o4YrxxqlQ9Q1InpduKLrIuGae0J1ybITS8+v +iYAmwzy1Wb2CDDuCnhCR/QDfOE1CvRILVqIKezC0tRrBTEvRO84m6YMBtJ1DP75Z +2cTNyjPos9+uxi4JcMKrMUBwZKya+z5i+Uxd66wuPj9KmggNG1x+bqMWmpTrSKUn +gbLabFUth+uWumpj3/7HBT8Ov7rPgzY/vn3Fn5mKdLQm+kRwSX9/FbtHAE3Qsm+f +6WW8CZ4XzL9ONfhQYwO2Jrq4HzgYloZkL+1Zs61X+zeEyr4o/mzt5DHbQRsD1UzQ +gnh7t3YdSAy6gBqevjPWkQlq9e8eoFRydN/htwjS7dleikOsYktSnTIKlRXAWGCm +jkRpQyZYuuPcWcGRt/0MVewRJmLemH6O+NviqhgGRePO9QR0R+yfdCwewPJEDk60 +JEtvbnN0YW50aW4gUGF2bG92IDx0aHJlc2hAbmdpbnguY29tPokB1AQTAQgAPgIb +AwULCQgHAwUVCgkICwUWAwIBAAIeAQIXgBYhBBPIKmO2A1dhVuMKTqDqmBtmsNln +BQJihN+8BQkQ+q8XAAoJEKDqmBtmsNlncQ0L/0Yk1QejO06gWwV1J2eK9LmjbMof +y2ujZBgW1IGt/goo5R4PzC8lBBcsBtsKyN0Rsh7QdLrtKKLQrE/gpwMTMdKhJTdP +/c5tUY3EwgIdBMYVaxArZQiWlPgSnoKuKydnn6Rb+Qtrhvb9pjn5XlGd/VSbAXZe +8YTj6B8qjUa2YY+IreyB6wkPN/ytV5vcocbS7mzXaibGPVT35e0Pl1Be+xbJkbTm +JTSJCSPwyHm9t2Vuq4e/c3fMwhOUbBjfssspR103vo91XO5sY+v2aQJOctNrv4Zp +HMrwBH7MeqDISCWg9PICUv0ewHzAEGB+K0v342rVAzVNEctwM3Jic7fEJYsItdw+ +Zk4r8NYqACoRCdSUEHqhP0DbYoWdthpUwD1J5ryWyKTCpTL4wNhKEMcNaiHH3qor +SssyMHMFRPoXKw9Pcay+Uo8NXc2KKxhEHTbQts0jYUNcq0yuWHoNQ4vhKkf9CHBr +b/vS22vfEJyd6FX6ZRYK56A3EFAV8hK0BvZAw7kBjQRa8DInAQwA2Rk7UdUgpCWl ++BMz9B9eKj0XtsNEciXHHKnSFYaSNCWNwib/FsiMfcPFh7xwUTof7e7HBFkvv0QE +MCEp7R1MVNBfMiGtG1ICFIt9nByznPsRk4VvbY/prK4DZy2AmlwhNcT2pQO3Aasc +gsCWdf6G+wcwnHg9tWCp0Xs9BNXuppmcRrpP4M1PPRIVeG1jeVXvuSHO2HjqPSXP +5DhGgSGN7uLOhiLTnPINd186vf6tqRdqYw3g0W1ImEjGXHeNQfnieIWdU3X4C8KT +EPsV3lvtmSAQCoge0CyKfz4cORi4j8Edp8JpDQlbAThe529+R3eKUw7I/3ESxJBd +qzLE/ItWvAcbGEserLDFrg9J1ojiKhsw3TVcDk+HIDzVakMz6HTd4ExSijMqTehz +gKSVHDL+l2jc0f4VSecI+xwC3/kNsNTBpiPoUYtXBbJllHgQAakREkSKQBas02eq +Ru8SlQ3yEn87zTtNW8L7xpe7ZVtxwUgp40PUrsb8uMDJG7ZP5rhLABEBAAGJAbwE +GAEIACYCGwwWIQQTyCpjtgNXYVbjCk6g6pgbZrDZZwUCYoTfwQUJEPqvGgAKCRCg +6pgbZrDZZ3oEDAC1J3BVwlkX+eoo8VsXAYxMXm8kIaTqOn/tHMOYepK+cWUdHaeC +H3N8LigwN4Ve2LtzLBqN3WRAxFNy0DIzdBfA7QdcAoDLnB2FNrWTmwvC9nXkCogF +fSCq7c+1oFHdn7M/VZNU4o0nhVOnqM8NLGcgzX3K3hr+WLYUgNQ9G6x0N9VU43tq +VwJhvNv4pyiRpRdLlmhOEf35a/sWE1dttSKdrBhyzTbptw4dXr4lUpvlswWs+dLp +SPPhWAuifORv/amWh3bxIxYEqE4o5NI/PQLJvJJLsJvMIIjpKlAGBJg5h3WCiIAk +l7H+BesOUIIg8ava5ZUyjlFdszBMaBosZvRgFAlfnYhSGqzhip6PvXfK1YokNv7k +qw43c0f1SmtSXZR43SRv/4vpXG7IqtTuqgSwn1qDJgr4yfs8QQykO/jG+cz7X+5O +KSAulWi9OoqLyDWlsm3WccPIcJfbm71P+I/ha7ESVQfOxC92fQ7HQAboj7NhecJ4 +RLqjzrWSHmPGClI= +=J2qy +-----END PGP PUBLIC KEY BLOCK----- From deedff451f7c54de893254fd39b46ec9efb84e65 Mon Sep 17 00:00:00 2001 From: Thomas Ward Date: Tue, 24 May 2022 14:19:05 -0400 Subject: [PATCH 110/329] New upstream version 1.22.0 --- CHANGES | 160 +++++- CHANGES.ru | 164 +++++- LICENSE | 2 +- auto/lib/pcre/conf | 164 +++--- auto/lib/pcre/make | 152 +++++- auto/modules | 7 +- auto/options | 3 + auto/os/freebsd | 8 +- auto/sources | 3 + auto/summary | 4 +- conf/mime.types | 2 + contrib/vim/syntax/nginx.vim | 61 ++- html/50x.html | 8 +- html/index.html | 8 +- src/core/nginx.h | 4 +- src/core/ngx_buf.h | 3 - src/core/ngx_connection.c | 25 +- src/core/ngx_connection.h | 2 +- src/core/ngx_hash.c | 4 + src/core/ngx_module.h | 2 +- src/core/ngx_output_chain.c | 53 +- src/core/ngx_rbtree.h | 3 + src/core/ngx_regex.c | 474 ++++++++++++++++-- src/core/ngx_regex.h | 38 +- src/core/ngx_resolver.c | 4 +- src/core/ngx_rwlock.c | 18 +- src/core/ngx_string.c | 45 +- src/core/ngx_times.c | 4 - src/event/ngx_event.c | 32 +- src/event/ngx_event.h | 5 +- src/event/ngx_event_accept.c | 58 +++ src/event/ngx_event_openssl.c | 368 ++++++++++++-- src/event/ngx_event_openssl.h | 10 +- src/event/ngx_event_timer.c | 4 +- src/http/modules/ngx_http_auth_basic_module.c | 27 +- src/http/modules/ngx_http_dav_module.c | 25 +- src/http/modules/ngx_http_fastcgi_module.c | 6 +- src/http/modules/ngx_http_grpc_module.c | 112 +++-- src/http/modules/ngx_http_mp4_module.c | 261 ++++++++-- src/http/modules/ngx_http_proxy_module.c | 113 +++-- src/http/modules/ngx_http_scgi_module.c | 6 +- .../modules/ngx_http_secure_link_module.c | 17 +- src/http/modules/ngx_http_ssl_module.c | 80 +-- src/http/modules/ngx_http_static_module.c | 17 +- src/http/modules/ngx_http_uwsgi_module.c | 93 ++-- src/http/ngx_http.c | 42 +- src/http/ngx_http.h | 8 + src/http/ngx_http_copy_filter_module.c | 90 ++-- src/http/ngx_http_core_module.c | 36 +- src/http/ngx_http_core_module.h | 5 +- src/http/ngx_http_header_filter_module.c | 4 + ...2_huff_decode.c => ngx_http_huff_decode.c} | 18 +- ...2_huff_encode.c => ngx_http_huff_encode.c} | 30 +- src/http/ngx_http_parse.c | 118 ++--- src/http/ngx_http_request.c | 71 +-- src/http/ngx_http_request.h | 39 +- src/http/ngx_http_request_body.c | 130 ++++- src/http/ngx_http_script.c | 40 +- src/http/ngx_http_script.h | 2 + src/http/ngx_http_upstream.c | 104 +++- src/http/ngx_http_upstream.h | 4 + src/http/ngx_http_write_filter_module.c | 9 +- src/http/v2/ngx_http_v2.c | 338 +++++++++---- src/http/v2/ngx_http_v2.h | 9 +- src/http/v2/ngx_http_v2_encode.c | 2 +- src/http/v2/ngx_http_v2_filter_module.c | 29 +- src/mail/ngx_mail.h | 6 +- src/mail/ngx_mail_auth_http_module.c | 41 +- src/mail/ngx_mail_core_module.c | 10 + src/mail/ngx_mail_handler.c | 40 +- src/mail/ngx_mail_imap_handler.c | 43 +- src/mail/ngx_mail_imap_module.c | 1 + src/mail/ngx_mail_parse.c | 175 ++++--- src/mail/ngx_mail_pop3_handler.c | 15 +- src/mail/ngx_mail_pop3_module.c | 1 + src/mail/ngx_mail_proxy_module.c | 17 +- src/mail/ngx_mail_smtp_module.c | 1 + src/mail/ngx_mail_ssl_module.c | 72 ++- src/os/unix/ngx_atomic.h | 66 +-- src/os/unix/ngx_freebsd_sendfile_chain.c | 93 ++-- src/os/unix/ngx_linux_sendfile_chain.c | 13 +- src/os/unix/ngx_process_cycle.c | 2 + src/os/unix/ngx_readv_chain.c | 2 +- src/stream/ngx_stream.c | 4 + src/stream/ngx_stream.h | 3 + src/stream/ngx_stream_core_module.c | 25 + src/stream/ngx_stream_proxy_module.c | 176 +++++-- src/stream/ngx_stream_script.c | 40 +- src/stream/ngx_stream_script.h | 2 + src/stream/ngx_stream_ssl_module.c | 144 +++++- src/stream/ngx_stream_ssl_module.h | 1 + src/stream/ngx_stream_upstream.h | 1 + 92 files changed, 3480 insertions(+), 1301 deletions(-) rename src/http/{v2/ngx_http_v2_huff_decode.c => ngx_http_huff_decode.c} (99%) rename src/http/{v2/ngx_http_v2_huff_encode.c => ngx_http_huff_encode.c} (93%) diff --git a/CHANGES b/CHANGES index 7881653..6b232cf 100644 --- a/CHANGES +++ b/CHANGES @@ -1,28 +1,144 @@ -Changes with nginx 1.20.2 16 Nov 2021 +Changes with nginx 1.22.0 24 May 2022 + + *) 1.22.x stable branch. + + +Changes with nginx 1.21.6 25 Jan 2022 + + *) Bugfix: when using EPOLLEXCLUSIVE on Linux client connections were + unevenly distributed among worker processes. + + *) Bugfix: nginx returned the "Connection: keep-alive" header line in + responses during graceful shutdown of old worker processes. + + *) Bugfix: in the "ssl_session_ticket_key" when using TLSv1.3. + + +Changes with nginx 1.21.5 28 Dec 2021 + + *) Change: now nginx is built with the PCRE2 library by default. + + *) Change: now nginx always uses sendfile(SF_NODISKIO) on FreeBSD. + + *) Feature: support for sendfile(SF_NOCACHE) on FreeBSD. + + *) Feature: the $ssl_curve variable. + + *) Bugfix: connections might hang when using HTTP/2 without SSL with the + "sendfile" and "aio" directives. + + +Changes with nginx 1.21.4 02 Nov 2021 + + *) Change: support for NPN instead of ALPN to establish HTTP/2 + connections has been removed. + + *) Change: now nginx rejects SSL connections if ALPN is used by the + client, but no supported protocols can be negotiated. + + *) Change: the default value of the "sendfile_max_chunk" directive was + changed to 2 megabytes. + + *) Feature: the "proxy_half_close" directive in the stream module. + + *) Feature: the "ssl_alpn" directive in the stream module. + + *) Feature: the $ssl_alpn_protocol variable. + + *) Feature: support for SSL_sendfile() when using OpenSSL 3.0. + + *) Feature: the "mp4_start_key_frame" directive in the + ngx_http_mp4_module. + Thanks to Tracey Jaquith. + + *) Bugfix: in the $content_length variable when using chunked transfer + encoding. + + *) Bugfix: after receiving a response with incorrect length from a + proxied backend nginx might nevertheless cache the connection. + Thanks to Awdhesh Mathpal. + + *) Bugfix: invalid headers from backends were logged at the "info" level + instead of "error"; the bug had appeared in 1.21.1. + + *) Bugfix: requests might hang when using HTTP/2 and the "aio_write" + directive. + + +Changes with nginx 1.21.3 07 Sep 2021 + + *) Change: optimization of client request body reading when using + HTTP/2. + + *) Bugfix: in request body filters internal API when using HTTP/2 and + buffering of the data being processed. + + +Changes with nginx 1.21.2 31 Aug 2021 + + *) Change: now nginx rejects HTTP/1.0 requests with the + "Transfer-Encoding" header line. + + *) Change: export ciphers are no longer supported. *) Feature: OpenSSL 3.0 compatibility. + *) Feature: the "Auth-SSL-Protocol" and "Auth-SSL-Cipher" header lines + are now passed to the mail proxy authentication server. + Thanks to Rob Mueller. + + *) Feature: request body filters API now permits buffering of the data + being processed. + + *) Bugfix: backend SSL connections in the stream module might hang after + an SSL handshake. + + *) Bugfix: the security level, which is available in OpenSSL 1.1.0 or + newer, did not affect loading of the server certificates when set + with "@SECLEVEL=N" in the "ssl_ciphers" directive. + + *) Bugfix: SSL connections with gRPC backends might hang if select, + poll, or /dev/poll methods were used. + + *) Bugfix: when using HTTP/2 client request body was always written to + disk if the "Content-Length" header line was not present in the + request. + + +Changes with nginx 1.21.1 06 Jul 2021 + + *) Change: now nginx always returns an error for the CONNECT method. + + *) Change: now nginx always returns an error if both "Content-Length" + and "Transfer-Encoding" header lines are present in the request. + + *) Change: now nginx always returns an error if spaces or control + characters are used in the request line. + + *) Change: now nginx always returns an error if spaces or control + characters are used in a header name. + + *) Change: now nginx always returns an error if spaces or control + characters are used in the "Host" request header line. + + *) Change: optimization of configuration testing when using many + listening sockets. + + *) Bugfix: nginx did not escape """, "<", ">", "\", "^", "`", "{", "|", + and "}" characters when proxying with changed URI. + *) Bugfix: SSL variables might be empty when used in logs; the bug had appeared in 1.19.5. *) Bugfix: keepalive connections with gRPC backends might not be closed after receiving a GOAWAY frame. - *) Bugfix: backend SSL connections in the stream module might hang after - an SSL handshake. - - *) Bugfix: SSL connections with gRPC backends might hang if select, - poll, or /dev/poll methods were used. - - *) Bugfix: in the $content_length variable when using chunked transfer - encoding. - - *) Bugfix: requests might hang when using HTTP/2 and the "aio_write" - directive. + *) Bugfix: reduced memory consumption for long-lived requests when + proxying with more than 64 buffers. -Changes with nginx 1.20.1 25 May 2021 +Changes with nginx 1.21.0 25 May 2021 *) Security: 1-byte memory overwrite might occur during DNS server response processing if the "resolver" directive was used, allowing an @@ -30,10 +146,24 @@ Changes with nginx 1.20.1 25 May 2021 cause worker process crash or, potentially, arbitrary code execution (CVE-2021-23017). + *) Feature: variables support in the "proxy_ssl_certificate", + "proxy_ssl_certificate_key" "grpc_ssl_certificate", + "grpc_ssl_certificate_key", "uwsgi_ssl_certificate", and + "uwsgi_ssl_certificate_key" directives. -Changes with nginx 1.20.0 20 Apr 2021 + *) Feature: the "max_errors" directive in the mail proxy module. - *) 1.20.x stable branch. + *) Feature: the mail proxy module supports POP3 and IMAP pipelining. + + *) Feature: the "fastopen" parameter of the "listen" directive in the + stream module. + Thanks to Anbang Wen. + + *) Bugfix: special characters were not escaped during automatic redirect + with appended trailing slash. + + *) Bugfix: connections with clients in the mail proxy module might be + closed unexpectedly when using SMTP pipelining. Changes with nginx 1.19.10 13 Apr 2021 diff --git a/CHANGES.ru b/CHANGES.ru index a766cc5..bd49853 100644 --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,28 +1,148 @@ -Изменения в nginx 1.20.2 16.11.2021 +Изменения в nginx 1.22.0 24.05.2022 + + *) Стабильная ветка 1.22.x. + + +Изменения в nginx 1.21.6 25.01.2022 + + *) Исправление: при использование EPOLLEXCLUSIVE на Linux распределение + клиентских соединений между рабочими процессами было неравномерным. + + *) Исправление: во время плавного завершения старых рабочих процессов + nginx возвращал в ответах строку заголовка "Connection: keep-alive". + + *) Исправление: в директиве ssl_session_ticket_key при использовании + TLSv1.3. + + +Изменения в nginx 1.21.5 28.12.2021 + + *) Изменение: теперь nginx по умолчанию собирается с библиотекой PCRE2. + + *) Изменение: теперь nginx всегда использует sendfile(SF_NODISKIO) на + FreeBSD. + + *) Добавление: поддержка sendfile(SF_NOCACHE) на FreeBSD. + + *) Добавление: переменная $ssl_curve. + + *) Исправление: при использовании HTTP/2 без SSL вместе с директивами + sendfile и aio соединения могли зависать. + + +Изменения в nginx 1.21.4 02.11.2021 + + *) Изменение: поддержка NPN вместо ALPN для установления + HTTP/2-соединений упразднена. + + *) Изменение: теперь nginx закрывает SSL соединение, если клиент + использует ALPN, но nginx не поддерживает ни один из присланных + клиентом протоколов. + + *) Изменение: в директиве sendfile_max_chunk значение по умолчанию + изменено на 2 мегабайта. + + *) Добавление: директива proxy_half_close в модуле stream. + + *) Добавление: директива ssl_alpn в модуле stream. + + *) Добавление: переменная $ssl_alpn_protocol. + + *) Добавление: поддержка SSL_sendfile() при использовании OpenSSL 3.0. + + *) Добавление: директива mp4_start_key_frame в модуле + ngx_http_mp4_module. + Спасибо Tracey Jaquith. + + *) Исправление: в переменной $content_length при использовании chunked + transfer encoding. + + *) Исправление: при получении ответа некорректной длины от проксируемого + бэкенда nginx мог тем не менее закэшировать соединение. + Спасибо Awdhesh Mathpal. + + *) Исправление: некорректные заголовки от бэкендов логгировались на + уровне info вместо error; ошибка появилась в 1.21.1. + + *) Исправление: при использовании HTTP/2 и директивы aio_write запросы + могли зависать. + + +Изменения в nginx 1.21.3 07.09.2021 + + *) Изменение: оптимизация чтения тела запроса при использовании HTTP/2. + + *) Исправление: во внутреннем API для обработки тела запроса при + использовании HTTP/2 и буферизации обрабатываемых данных. + + +Изменения в nginx 1.21.2 31.08.2021 + + *) Изменение: теперь nginx возвращает ошибку, если в запросе по + протоколу HTTP/1.0 присутствует строка заголовка "Transfer-Encoding". + + *) Изменение: экспортные шифры больше не поддерживаются. *) Добавление: совместимость с OpenSSL 3.0. + *) Добавление: теперь серверу аутентификации почтового прокси-сервера + передаются строки заголовка "Auth-SSL-Protocol" и "Auth-SSL-Cipher". + Спасибо Rob Mueller. + + *) Добавление: API для обработки тела запроса теперь позволяет + буферизировать обрабатываемые данные. + + *) Исправление: SSL-соединения к бэкендам в модуле stream могли зависать + после SSL handshake. + + *) Исправление: уровень безопасности, доступный в OpenSSL 1.1.0 и новее, + не учитывался при загрузке сертификатов сервера, если был задан через + "@SECLEVEL=N" в директиве ssl_ciphers. + + *) Исправление: SSL-соединения с gRPC-бэкендами могли зависать, если + использовались методы select, poll или /dev/poll. + + *) Исправление: при использовании HTTP/2 тело запроса всегда + записывалось на диск, если в запросе не было строки заголовка + "Content-Length". + + +Изменения в nginx 1.21.1 06.07.2021 + + *) Изменение: теперь nginx для метода CONNECT всегда возвращает ошибку. + + *) Изменение: теперь nginx всегда возвращает ошибку, если в запросе + одновременно присутствуют строки заголовка "Content-Length" и + "Transfer-Encoding". + + *) Изменение: теперь nginx всегда возвращает ошибку, если в строке + запроса используются пробелы или управляющие символы. + + *) Изменение: теперь nginx всегда возвращает ошибку, если в имени + заголовка используются пробелы или управляющие символы. + + *) Изменение: теперь nginx всегда возвращает ошибку, если в строке + "Host" заголовка запроса используются пробелы или управляющие + символы. + + *) Изменение: оптимизация тестирования конфигурации при использовании + большого количества listen-сокетов. + + *) Исправление: nginx не экранировал символы """, "<", ">", "\", "^", + "`", "{", "|", и "}" при проксировании с изменением URI запроса. + *) Исправление: SSL-переменные могли быть пустыми при записи в лог; ошибка появилась в 1.19.5. *) Исправление: keepalive-соединения с gRPC-бэкендами могли не закрываться после получения GOAWAY-фрейма. - *) Исправление: SSL-соединения к бэкендам в модуле stream могли зависать - после SSL handshake. - - *) Исправление: SSL-соединения с gRPC-бэкендами могли зависать, если - использовались методы select, poll или /dev/poll. - - *) Исправление: в переменной $content_length при использовании chunked - transfer encoding. - - *) Исправление: при использовании HTTP/2 и директивы aio_write запросы - могли зависать. + *) Исправление: уменьшено потребление памяти для долгоживущих запросов + при проксировании с использованием более 64 буферов. -Изменения в nginx 1.20.1 25.05.2021 +Изменения в nginx 1.21.0 25.05.2021 *) Безопасность: при использовании директивы resolver во время обработки ответа DNS-сервера могла происходить перезапись одного байта памяти, @@ -30,10 +150,24 @@ от DNS-сервера, вызвать падение рабочего процесса или, потенциально, выполнение произвольного кода (CVE-2021-23017). + *) Добавление: директивы proxy_ssl_certificate, + proxy_ssl_certificate_key, grpc_ssl_certificate, + grpc_ssl_certificate_key, uwsgi_ssl_certificate и + uwsgi_ssl_certificate_key поддерживают переменные. -Изменения в nginx 1.20.0 20.04.2021 + *) Добавление: директива max_errors в почтовом прокси-сервере. - *) Стабильная ветка 1.20.x. + *) Добавление: почтовый прокси-сервер поддерживает POP3 и IMAP + pipelining. + + *) Добавление: параметр fastopen директивы listen в модуле stream. + Спасибо Anbang Wen. + + *) Исправление: специальные символы не экранировались при автоматическом + перенаправлении с добавлением завершающего слэша. + + *) Исправление: при использовании SMTP pipelining соединения с клиентами + в почтовом прокси-сервере могли неожиданно закрываться. Изменения в nginx 1.19.10 13.04.2021 diff --git a/LICENSE b/LICENSE index fd0c72d..fdedcb7 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ /* * Copyright (C) 2002-2021 Igor Sysoev - * Copyright (C) 2011-2021 Nginx, Inc. + * Copyright (C) 2011-2022 Nginx, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/auto/lib/pcre/conf b/auto/lib/pcre/conf index 5e3960f..20c1caf 100644 --- a/auto/lib/pcre/conf +++ b/auto/lib/pcre/conf @@ -4,87 +4,62 @@ if [ $PCRE != NONE ]; then - CORE_INCS="$CORE_INCS $PCRE" - case "$NGX_CC_NAME" in + if [ -f $PCRE/src/pcre2.h.generic ]; then - msvc | owc | bcc) - have=NGX_PCRE . auto/have + PCRE_LIBRARY=PCRE2 + + have=NGX_PCRE . auto/have + have=NGX_PCRE2 . auto/have + + if [ "$NGX_PLATFORM" = win32 ]; then + have=PCRE2_STATIC . auto/have + fi + + CORE_INCS="$CORE_INCS $PCRE/src/" + CORE_DEPS="$CORE_DEPS $PCRE/src/pcre2.h" + + case "$NGX_CC_NAME" in + + msvc) + LINK_DEPS="$LINK_DEPS $PCRE/src/pcre2-8.lib" + CORE_LIBS="$CORE_LIBS $PCRE/src/pcre2-8.lib" + ;; + + *) + LINK_DEPS="$LINK_DEPS $PCRE/.libs/libpcre2-8.a" + CORE_LIBS="$CORE_LIBS $PCRE/.libs/libpcre2-8.a" + ;; + + esac + + else + + PCRE_LIBRARY=PCRE + + have=NGX_PCRE . auto/have + + if [ "$NGX_PLATFORM" = win32 ]; then have=PCRE_STATIC . auto/have - CORE_DEPS="$CORE_DEPS $PCRE/pcre.h" - LINK_DEPS="$LINK_DEPS $PCRE/pcre.lib" - CORE_LIBS="$CORE_LIBS $PCRE/pcre.lib" - ;; + fi - icc) - have=NGX_PCRE . auto/have - CORE_DEPS="$CORE_DEPS $PCRE/pcre.h" + CORE_INCS="$CORE_INCS $PCRE" + CORE_DEPS="$CORE_DEPS $PCRE/pcre.h" - LINK_DEPS="$LINK_DEPS $PCRE/.libs/libpcre.a" + case "$NGX_CC_NAME" in - echo $ngx_n "checking for PCRE library ...$ngx_c" + msvc | owc | bcc) + LINK_DEPS="$LINK_DEPS $PCRE/pcre.lib" + CORE_LIBS="$CORE_LIBS $PCRE/pcre.lib" + ;; - if [ -f $PCRE/pcre.h ]; then - ngx_pcre_ver=`grep PCRE_MAJOR $PCRE/pcre.h \ - | sed -e 's/^.*PCRE_MAJOR.* \(.*\)$/\1/'` - - else if [ -f $PCRE/configure.in ]; then - ngx_pcre_ver=`grep PCRE_MAJOR= $PCRE/configure.in \ - | sed -e 's/^.*=\(.*\)$/\1/'` - - else - ngx_pcre_ver=`grep pcre_major, $PCRE/configure.ac \ - | sed -e 's/^.*pcre_major,.*\[\(.*\)\].*$/\1/'` - fi - fi - - echo " $ngx_pcre_ver major version found" - - # to allow -ipo optimization we link with the *.o but not library - - case "$ngx_pcre_ver" in - 4|5) - CORE_LIBS="$CORE_LIBS $PCRE/pcre.o" - ;; - - 6) - CORE_LIBS="$CORE_LIBS $PCRE/pcre_chartables.o" - CORE_LIBS="$CORE_LIBS $PCRE/pcre_compile.o" - CORE_LIBS="$CORE_LIBS $PCRE/pcre_exec.o" - CORE_LIBS="$CORE_LIBS $PCRE/pcre_fullinfo.o" - CORE_LIBS="$CORE_LIBS $PCRE/pcre_globals.o" - CORE_LIBS="$CORE_LIBS $PCRE/pcre_tables.o" - CORE_LIBS="$CORE_LIBS $PCRE/pcre_try_flipped.o" - ;; - - *) - CORE_LIBS="$CORE_LIBS $PCRE/pcre_chartables.o" - CORE_LIBS="$CORE_LIBS $PCRE/pcre_compile.o" - CORE_LIBS="$CORE_LIBS $PCRE/pcre_exec.o" - CORE_LIBS="$CORE_LIBS $PCRE/pcre_fullinfo.o" - CORE_LIBS="$CORE_LIBS $PCRE/pcre_globals.o" - CORE_LIBS="$CORE_LIBS $PCRE/pcre_tables.o" - CORE_LIBS="$CORE_LIBS $PCRE/pcre_try_flipped.o" - CORE_LIBS="$CORE_LIBS $PCRE/pcre_newline.o" - ;; - - esac - ;; - - *) - have=NGX_PCRE . auto/have - - if [ "$NGX_PLATFORM" = win32 ]; then - have=PCRE_STATIC . auto/have - fi - - CORE_DEPS="$CORE_DEPS $PCRE/pcre.h" - LINK_DEPS="$LINK_DEPS $PCRE/.libs/libpcre.a" - CORE_LIBS="$CORE_LIBS $PCRE/.libs/libpcre.a" - ;; - - esac + *) + LINK_DEPS="$LINK_DEPS $PCRE/.libs/libpcre.a" + CORE_LIBS="$CORE_LIBS $PCRE/.libs/libpcre.a" + ;; + esac + fi if [ $PCRE_JIT = YES ]; then have=NGX_HAVE_PCRE_JIT . auto/have @@ -94,8 +69,48 @@ if [ $PCRE != NONE ]; then else if [ "$NGX_PLATFORM" != win32 ]; then - PCRE=NO + fi + + if [ $PCRE = NO -a $PCRE2 != DISABLED ]; then + + ngx_feature="PCRE2 library" + ngx_feature_name="NGX_PCRE2" + ngx_feature_run=no + ngx_feature_incs="#define PCRE2_CODE_UNIT_WIDTH 8 + #include " + ngx_feature_path= + ngx_feature_libs="-lpcre2-8" + ngx_feature_test="pcre2_code *re; + re = pcre2_compile(NULL, 0, 0, NULL, NULL, NULL); + if (re == NULL) return 1" + . auto/feature + + if [ $ngx_found = no ]; then + + # pcre2-config + + ngx_pcre2_prefix=`pcre2-config --prefix 2>/dev/null` + + if [ -n "$ngx_pcre2_prefix" ]; then + ngx_feature="PCRE2 library in $ngx_pcre2_prefix" + ngx_feature_path=`pcre2-config --cflags \ + | sed -n -e 's/.*-I *\([^ ][^ ]*\).*/\1/p'` + ngx_feature_libs=`pcre2-config --libs8` + . auto/feature + fi + fi + + if [ $ngx_found = yes ]; then + have=NGX_PCRE . auto/have + CORE_INCS="$CORE_INCS $ngx_feature_path" + CORE_LIBS="$CORE_LIBS $ngx_feature_libs" + PCRE=YES + PCRE_LIBRARY=PCRE2 + fi + fi + + if [ $PCRE = NO ]; then ngx_feature="PCRE library" ngx_feature_name="NGX_PCRE" @@ -171,6 +186,7 @@ else CORE_INCS="$CORE_INCS $ngx_feature_path" CORE_LIBS="$CORE_LIBS $ngx_feature_libs" PCRE=YES + PCRE_LIBRARY=PCRE fi if [ $PCRE = YES ]; then diff --git a/auto/lib/pcre/make b/auto/lib/pcre/make index 97c9f3b..839ef29 100644 --- a/auto/lib/pcre/make +++ b/auto/lib/pcre/make @@ -3,36 +3,138 @@ # Copyright (C) Nginx, Inc. -case "$NGX_CC_NAME" in +if [ $PCRE_LIBRARY = PCRE2 ]; then - msvc) - ngx_makefile=makefile.msvc - ngx_opt="CPU_OPT=\"$CPU_OPT\" LIBC=$LIBC" - ngx_pcre="PCRE=\"$PCRE\"" - ;; + # PCRE2 - owc) - ngx_makefile=makefile.owc - ngx_opt="CPU_OPT=\"$CPU_OPT\"" - ngx_pcre=`echo PCRE=\"$PCRE\" | sed -e "s/\//$ngx_regex_dirsep/g"` - ;; + if [ $NGX_CC_NAME = msvc ]; then - bcc) - ngx_makefile=makefile.bcc - ngx_opt="-DCPU_OPT=\"$CPU_OPT\"" - ngx_pcre=`echo \-DPCRE=\"$PCRE\" | sed -e "s/\//$ngx_regex_dirsep/g"` - ;; + # With PCRE2, it is not possible to compile all sources. + # Since list of source files changes between versions, we + # test files which might not be present. - *) - ngx_makefile= - ;; + ngx_pcre_srcs="pcre2_auto_possess.c \ + pcre2_chartables.c \ + pcre2_compile.c \ + pcre2_config.c \ + pcre2_context.c \ + pcre2_dfa_match.c \ + pcre2_error.c \ + pcre2_jit_compile.c \ + pcre2_maketables.c \ + pcre2_match.c \ + pcre2_match_data.c \ + pcre2_newline.c \ + pcre2_ord2utf.c \ + pcre2_pattern_info.c \ + pcre2_string_utils.c \ + pcre2_study.c \ + pcre2_substitute.c \ + pcre2_substring.c \ + pcre2_tables.c \ + pcre2_ucd.c \ + pcre2_valid_utf.c \ + pcre2_xclass.c" -esac + ngx_pcre_test="pcre2_convert.c \ + pcre2_extuni.c \ + pcre2_find_bracket.c \ + pcre2_script_run.c \ + pcre2_serialize.c" + + for ngx_src in $ngx_pcre_test + do + if [ -f $PCRE/src/$ngx_src ]; then + ngx_pcre_srcs="$ngx_pcre_srcs $ngx_src" + fi + done + + ngx_pcre_objs=`echo $ngx_pcre_srcs \ + | sed -e "s#\([^ ]*\.\)c#\1$ngx_objext#g"` + + ngx_pcre_srcs=`echo $ngx_pcre_srcs \ + | sed -e "s/ *\([^ ][^ ]*\)/$ngx_regex_cont\1/g"` + ngx_pcre_objs=`echo $ngx_pcre_objs \ + | sed -e "s/ *\([^ ][^ ]*\)/$ngx_regex_cont\1/g"` + + cat << END >> $NGX_MAKEFILE + +PCRE_CFLAGS = -O2 -Ob1 -Oi -Gs $LIBC $CPU_OPT +PCRE_FLAGS = -DHAVE_CONFIG_H -DPCRE2_STATIC -DPCRE2_CODE_UNIT_WIDTH=8 \\ + -DHAVE_MEMMOVE + +PCRE_SRCS = $ngx_pcre_srcs +PCRE_OBJS = $ngx_pcre_objs + +$PCRE/src/pcre2.h: + cd $PCRE/src \\ + && copy /y config.h.generic config.h \\ + && copy /y pcre2.h.generic pcre2.h \\ + && copy /y pcre2_chartables.c.dist pcre2_chartables.c + +$PCRE/src/pcre2-8.lib: $PCRE/src/pcre2.h $NGX_MAKEFILE + cd $PCRE/src \\ + && cl -nologo -c \$(PCRE_CFLAGS) -I . \$(PCRE_FLAGS) \$(PCRE_SRCS) \\ + && link -lib -out:pcre2-8.lib -verbose:lib \$(PCRE_OBJS) + +END + + else + + cat << END >> $NGX_MAKEFILE + +$PCRE/src/pcre2.h: $PCRE/Makefile + +$PCRE/Makefile: $NGX_MAKEFILE + cd $PCRE \\ + && if [ -f Makefile ]; then \$(MAKE) distclean; fi \\ + && CC="\$(CC)" CFLAGS="$PCRE_OPT" \\ + ./configure --disable-shared $PCRE_CONF_OPT + +$PCRE/.libs/libpcre2-8.a: $PCRE/Makefile + cd $PCRE \\ + && \$(MAKE) libpcre2-8.la + +END + + fi -if [ -n "$ngx_makefile" ]; then +else - cat << END >> $NGX_MAKEFILE + # PCRE + + case "$NGX_CC_NAME" in + + msvc) + ngx_makefile=makefile.msvc + ngx_opt="CPU_OPT=\"$CPU_OPT\" LIBC=$LIBC" + ngx_pcre="PCRE=\"$PCRE\"" + ;; + + owc) + ngx_makefile=makefile.owc + ngx_opt="CPU_OPT=\"$CPU_OPT\"" + ngx_pcre=`echo PCRE=\"$PCRE\" | sed -e "s/\//$ngx_regex_dirsep/g"` + ;; + + bcc) + ngx_makefile=makefile.bcc + ngx_opt="-DCPU_OPT=\"$CPU_OPT\"" + ngx_pcre=`echo \-DPCRE=\"$PCRE\" \ + | sed -e "s/\//$ngx_regex_dirsep/g"` + ;; + + *) + ngx_makefile= + ;; + + esac + + + if [ -n "$ngx_makefile" ]; then + + cat << END >> $NGX_MAKEFILE `echo "$PCRE/pcre.lib: $PCRE/pcre.h $NGX_MAKEFILE" \ | sed -e "s/\//$ngx_regex_dirsep/g"` @@ -43,9 +145,9 @@ if [ -n "$ngx_makefile" ]; then END -else + else - cat << END >> $NGX_MAKEFILE + cat << END >> $NGX_MAKEFILE $PCRE/pcre.h: $PCRE/Makefile @@ -61,4 +163,6 @@ $PCRE/.libs/libpcre.a: $PCRE/Makefile END + fi + fi diff --git a/auto/modules b/auto/modules index f5a4597..94867bf 100644 --- a/auto/modules +++ b/auto/modules @@ -102,6 +102,11 @@ if [ $HTTP = YES ]; then fi + if [ $HTTP_V2 = YES ]; then + HTTP_SRCS="$HTTP_SRCS $HTTP_HUFF_SRCS" + fi + + # the module order is important # ngx_http_static_module # ngx_http_gzip_static_module @@ -414,8 +419,6 @@ if [ $HTTP = YES ]; then ngx_module_srcs="src/http/v2/ngx_http_v2.c \ src/http/v2/ngx_http_v2_table.c \ src/http/v2/ngx_http_v2_encode.c \ - src/http/v2/ngx_http_v2_huff_decode.c \ - src/http/v2/ngx_http_v2_huff_encode.c \ src/http/v2/ngx_http_v2_module.c" ngx_module_libs= ngx_module_link=$HTTP_V2 diff --git a/auto/options b/auto/options index 80be906..48f3a1a 100644 --- a/auto/options +++ b/auto/options @@ -146,6 +146,7 @@ PCRE=NONE PCRE_OPT= PCRE_CONF_OPT= PCRE_JIT=NO +PCRE2=YES USE_OPENSSL=NO OPENSSL=NONE @@ -357,6 +358,7 @@ use the \"--with-mail_ssl_module\" option instead" --with-pcre=*) PCRE="$value" ;; --with-pcre-opt=*) PCRE_OPT="$value" ;; --with-pcre-jit) PCRE_JIT=YES ;; + --without-pcre2) PCRE2=DISABLED ;; --with-openssl=*) OPENSSL="$value" ;; --with-openssl-opt=*) OPENSSL_OPT="$value" ;; @@ -573,6 +575,7 @@ cat << END --with-pcre=DIR set path to PCRE library sources --with-pcre-opt=OPTIONS set additional build options for PCRE --with-pcre-jit build PCRE with JIT compilation support + --without-pcre2 do not use PCRE2 library --with-zlib=DIR set path to zlib library sources --with-zlib-opt=OPTIONS set additional build options for zlib diff --git a/auto/os/freebsd b/auto/os/freebsd index 937ca20..870bac4 100644 --- a/auto/os/freebsd +++ b/auto/os/freebsd @@ -44,12 +44,10 @@ if [ $osreldate -gt 300007 ]; then CORE_SRCS="$CORE_SRCS $FREEBSD_SENDFILE_SRCS" fi -if [ $NGX_FILE_AIO = YES ]; then - if [ $osreldate -gt 502103 ]; then - echo " + sendfile()'s SF_NODISKIO found" +if [ $osreldate -gt 1100093 ]; then + echo " + sendfile()'s SF_NODISKIO found" - have=NGX_HAVE_AIO_SENDFILE . auto/have - fi + have=NGX_HAVE_SENDFILE_NODISKIO . auto/have fi # POSIX semaphores diff --git a/auto/sources b/auto/sources index 3dad111..156f797 100644 --- a/auto/sources +++ b/auto/sources @@ -255,3 +255,6 @@ NGX_WIN32_RC="src/os/win32/nginx.rc" HTTP_FILE_CACHE_SRCS=src/http/ngx_http_file_cache.c + +HTTP_HUFF_SRCS="src/http/ngx_http_huff_decode.c + src/http/ngx_http_huff_encode.c" diff --git a/auto/summary b/auto/summary index 9aa776e..b3c07ee 100644 --- a/auto/summary +++ b/auto/summary @@ -16,9 +16,9 @@ if [ $USE_PCRE = DISABLED ]; then else case $PCRE in - YES) echo " + using system PCRE library" ;; + YES) echo " + using system $PCRE_LIBRARY library" ;; NONE) echo " + PCRE library is not used" ;; - *) echo " + using PCRE library: $PCRE" ;; + *) echo " + using $PCRE_LIBRARY library: $PCRE" ;; esac fi diff --git a/conf/mime.types b/conf/mime.types index 2961256..1c00d70 100644 --- a/conf/mime.types +++ b/conf/mime.types @@ -15,6 +15,7 @@ types { text/vnd.wap.wml wml; text/x-component htc; + image/avif avif; image/png png; image/svg+xml svg svgz; image/tiff tif tiff; @@ -51,6 +52,7 @@ types { application/vnd.openxmlformats-officedocument.wordprocessingml.document docx; application/vnd.wap.wmlc wmlc; + application/wasm wasm; application/x-7z-compressed 7z; application/x-cocoa cco; application/x-java-archive-diff jardiff; diff --git a/contrib/vim/syntax/nginx.vim b/contrib/vim/syntax/nginx.vim index 88ec847..6828cd3 100644 --- a/contrib/vim/syntax/nginx.vim +++ b/contrib/vim/syntax/nginx.vim @@ -5,6 +5,9 @@ if exists("b:current_syntax") finish end +let s:save_cpo = &cpo +set cpo&vim + " general syntax if has("patch-7.4.1142") @@ -152,6 +155,8 @@ syn keyword ngxDirective contained auth_jwt_header_set syn keyword ngxDirective contained auth_jwt_key_file syn keyword ngxDirective contained auth_jwt_key_request syn keyword ngxDirective contained auth_jwt_leeway +syn keyword ngxDirective contained auth_jwt_require +syn keyword ngxDirective contained auth_jwt_type syn keyword ngxDirective contained auth_request syn keyword ngxDirective contained auth_request_set syn keyword ngxDirective contained autoindex @@ -332,16 +337,24 @@ syn keyword ngxDirective contained index syn keyword ngxDirective contained iocp_threads syn keyword ngxDirective contained ip_hash syn keyword ngxDirective contained js_access +syn keyword ngxDirective contained js_body_filter syn keyword ngxDirective contained js_content +syn keyword ngxDirective contained js_fetch_ciphers +syn keyword ngxDirective contained js_fetch_protocols +syn keyword ngxDirective contained js_fetch_trusted_certificate +syn keyword ngxDirective contained js_fetch_verify_depth syn keyword ngxDirective contained js_filter +syn keyword ngxDirective contained js_header_filter syn keyword ngxDirective contained js_import syn keyword ngxDirective contained js_include syn keyword ngxDirective contained js_path syn keyword ngxDirective contained js_preread syn keyword ngxDirective contained js_set +syn keyword ngxDirective contained js_var syn keyword ngxDirective contained keepalive syn keyword ngxDirective contained keepalive_disable syn keyword ngxDirective contained keepalive_requests +syn keyword ngxDirective contained keepalive_time syn keyword ngxDirective contained keepalive_timeout syn keyword ngxDirective contained keyval syn keyword ngxDirective contained keyval_zone @@ -373,6 +386,7 @@ syn keyword ngxDirective contained log_subrequest syn keyword ngxDirective contained map_hash_bucket_size syn keyword ngxDirective contained map_hash_max_size syn keyword ngxDirective contained master_process +syn keyword ngxDirective contained max_errors syn keyword ngxDirective contained max_ranges syn keyword ngxDirective contained memcached_bind syn keyword ngxDirective contained memcached_buffer_size @@ -396,6 +410,7 @@ syn keyword ngxDirective contained mp4_buffer_size syn keyword ngxDirective contained mp4_limit_rate syn keyword ngxDirective contained mp4_limit_rate_after syn keyword ngxDirective contained mp4_max_buffer_size +syn keyword ngxDirective contained mp4_start_key_frame syn keyword ngxDirective contained msie_padding syn keyword ngxDirective contained msie_refresh syn keyword ngxDirective contained multi_accept @@ -452,6 +467,7 @@ syn keyword ngxDirective contained proxy_cookie_flags syn keyword ngxDirective contained proxy_cookie_path syn keyword ngxDirective contained proxy_download_rate syn keyword ngxDirective contained proxy_force_ranges +syn keyword ngxDirective contained proxy_half_close syn keyword ngxDirective contained proxy_headers_hash_bucket_size syn keyword ngxDirective contained proxy_headers_hash_max_size syn keyword ngxDirective contained proxy_hide_header @@ -591,6 +607,7 @@ syn keyword ngxDirective contained ssi_min_file_chunk syn keyword ngxDirective contained ssi_silent_errors syn keyword ngxDirective contained ssi_types syn keyword ngxDirective contained ssi_value_length +syn keyword ngxDirective contained ssl_alpn syn keyword ngxDirective contained ssl_buffer_size syn keyword ngxDirective contained ssl_certificate syn keyword ngxDirective contained ssl_certificate_key @@ -782,11 +799,15 @@ syn keyword ngxDirectiveThirdParty contained auth_digest_user_file syn keyword ngxDirectiveThirdParty contained auth_gss syn keyword ngxDirectiveThirdParty contained auth_gss_allow_basic_fallback syn keyword ngxDirectiveThirdParty contained auth_gss_authorized_principal +syn keyword ngxDirectiveThirdParty contained auth_gss_authorized_principal_regex +syn keyword ngxDirectiveThirdParty contained auth_gss_constrained_delegation +syn keyword ngxDirectiveThirdParty contained auth_gss_delegate_credentials syn keyword ngxDirectiveThirdParty contained auth_gss_force_realm syn keyword ngxDirectiveThirdParty contained auth_gss_format_full syn keyword ngxDirectiveThirdParty contained auth_gss_keytab syn keyword ngxDirectiveThirdParty contained auth_gss_map_to_local syn keyword ngxDirectiveThirdParty contained auth_gss_realm +syn keyword ngxDirectiveThirdParty contained auth_gss_service_ccache syn keyword ngxDirectiveThirdParty contained auth_gss_service_name " LDAP Authentication @@ -963,7 +984,6 @@ syn keyword ngxDirectiveThirdParty contained fancyindex_hide_parent_dir syn keyword ngxDirectiveThirdParty contained fancyindex_hide_symlinks syn keyword ngxDirectiveThirdParty contained fancyindex_ignore syn keyword ngxDirectiveThirdParty contained fancyindex_localtime -syn keyword ngxDirectiveThirdParty contained fancyindex_name_length syn keyword ngxDirectiveThirdParty contained fancyindex_show_dotfiles syn keyword ngxDirectiveThirdParty contained fancyindex_show_path syn keyword ngxDirectiveThirdParty contained fancyindex_time_format @@ -1053,7 +1073,9 @@ syn keyword ngxDirectiveThirdParty contained nchan_publisher_upstream_request syn keyword ngxDirectiveThirdParty contained nchan_pubsub syn keyword ngxDirectiveThirdParty contained nchan_pubsub_channel_id syn keyword ngxDirectiveThirdParty contained nchan_pubsub_location +syn keyword ngxDirectiveThirdParty contained nchan_redis_cluster_check_interval syn keyword ngxDirectiveThirdParty contained nchan_redis_connect_timeout +syn keyword ngxDirectiveThirdParty contained nchan_redis_discovered_ip_range_blacklist syn keyword ngxDirectiveThirdParty contained nchan_redis_fakesub_timer_interval syn keyword ngxDirectiveThirdParty contained nchan_redis_idle_channel_cache_timeout syn keyword ngxDirectiveThirdParty contained nchan_redis_namespace @@ -1061,12 +1083,29 @@ syn keyword ngxDirectiveThirdParty contained nchan_redis_nostore_fastpublish syn keyword ngxDirectiveThirdParty contained nchan_redis_optimize_target syn keyword ngxDirectiveThirdParty contained nchan_redis_pass syn keyword ngxDirectiveThirdParty contained nchan_redis_pass_inheritable +syn keyword ngxDirectiveThirdParty contained nchan_redis_password syn keyword ngxDirectiveThirdParty contained nchan_redis_ping_interval syn keyword ngxDirectiveThirdParty contained nchan_redis_publish_msgpacked_max_size syn keyword ngxDirectiveThirdParty contained nchan_redis_server +syn keyword ngxDirectiveThirdParty contained nchan_redis_ssl +syn keyword ngxDirectiveThirdParty contained nchan_redis_ssl_ciphers +syn keyword ngxDirectiveThirdParty contained nchan_redis_ssl_client_certificate +syn keyword ngxDirectiveThirdParty contained nchan_redis_ssl_client_certificate_key +syn keyword ngxDirectiveThirdParty contained nchan_redis_ssl_server_name +syn keyword ngxDirectiveThirdParty contained nchan_redis_ssl_trusted_certificate +syn keyword ngxDirectiveThirdParty contained nchan_redis_ssl_trusted_certificate_path +syn keyword ngxDirectiveThirdParty contained nchan_redis_ssl_verify_certificate syn keyword ngxDirectiveThirdParty contained nchan_redis_storage_mode syn keyword ngxDirectiveThirdParty contained nchan_redis_subscribe_weights +syn keyword ngxDirectiveThirdParty contained nchan_redis_tls +syn keyword ngxDirectiveThirdParty contained nchan_redis_tls_ciphers +syn keyword ngxDirectiveThirdParty contained nchan_redis_tls_client_certificate +syn keyword ngxDirectiveThirdParty contained nchan_redis_tls_server_name +syn keyword ngxDirectiveThirdParty contained nchan_redis_tls_trusted_certificate +syn keyword ngxDirectiveThirdParty contained nchan_redis_tls_trusted_certificate_path +syn keyword ngxDirectiveThirdParty contained nchan_redis_tls_verify_certificate syn keyword ngxDirectiveThirdParty contained nchan_redis_url +syn keyword ngxDirectiveThirdParty contained nchan_redis_username syn keyword ngxDirectiveThirdParty contained nchan_redis_wait_after_connecting syn keyword ngxDirectiveThirdParty contained nchan_shared_memory_size syn keyword ngxDirectiveThirdParty contained nchan_storage_engine @@ -1080,6 +1119,8 @@ syn keyword ngxDirectiveThirdParty contained nchan_subscriber_compound_etag_mess syn keyword ngxDirectiveThirdParty contained nchan_subscribe_request syn keyword ngxDirectiveThirdParty contained nchan_subscriber_first_message syn keyword ngxDirectiveThirdParty contained nchan_subscriber_http_raw_stream_separator +syn keyword ngxDirectiveThirdParty contained nchan_subscriber_info +syn keyword ngxDirectiveThirdParty contained nchan_subscriber_info_string syn keyword ngxDirectiveThirdParty contained nchan_subscriber_last_message_id syn keyword ngxDirectiveThirdParty contained nchan_subscriber_location syn keyword ngxDirectiveThirdParty contained nchan_subscriber_message_id_custom_etag_header @@ -1377,6 +1418,7 @@ syn keyword ngxDirectiveThirdParty contained lua_socket_read_timeout syn keyword ngxDirectiveThirdParty contained lua_socket_send_lowat syn keyword ngxDirectiveThirdParty contained lua_socket_send_timeout syn keyword ngxDirectiveThirdParty contained lua_ssl_ciphers +syn keyword ngxDirectiveThirdParty contained lua_ssl_conf_command syn keyword ngxDirectiveThirdParty contained lua_ssl_crl syn keyword ngxDirectiveThirdParty contained lua_ssl_protocols syn keyword ngxDirectiveThirdParty contained lua_ssl_trusted_certificate @@ -1384,6 +1426,7 @@ syn keyword ngxDirectiveThirdParty contained lua_ssl_verify_depth syn keyword ngxDirectiveThirdParty contained lua_thread_cache_max_entries syn keyword ngxDirectiveThirdParty contained lua_transform_underscores_in_response_headers syn keyword ngxDirectiveThirdParty contained lua_use_default_type +syn keyword ngxDirectiveThirdParty contained lua_worker_thread_vm_pool_size syn keyword ngxDirectiveThirdParty contained rewrite_by_lua syn keyword ngxDirectiveThirdParty contained rewrite_by_lua_block syn keyword ngxDirectiveThirdParty contained rewrite_by_lua_file @@ -1393,6 +1436,8 @@ syn keyword ngxDirectiveThirdParty contained set_by_lua_block syn keyword ngxDirectiveThirdParty contained set_by_lua_file syn keyword ngxDirectiveThirdParty contained ssl_certificate_by_lua_block syn keyword ngxDirectiveThirdParty contained ssl_certificate_by_lua_file +syn keyword ngxDirectiveThirdParty contained ssl_client_hello_by_lua_block +syn keyword ngxDirectiveThirdParty contained ssl_client_hello_by_lua_file syn keyword ngxDirectiveThirdParty contained ssl_session_fetch_by_lua_block syn keyword ngxDirectiveThirdParty contained ssl_session_fetch_by_lua_file syn keyword ngxDirectiveThirdParty contained ssl_session_store_by_lua_block @@ -1711,15 +1756,18 @@ syn keyword ngxDirectiveThirdParty contained set_base32_alphabet syn keyword ngxDirectiveThirdParty contained set_base32_padding syn keyword ngxDirectiveThirdParty contained set_decode_base32 syn keyword ngxDirectiveThirdParty contained set_decode_base64 +syn keyword ngxDirectiveThirdParty contained set_decode_base64url syn keyword ngxDirectiveThirdParty contained set_decode_hex syn keyword ngxDirectiveThirdParty contained set_encode_base32 syn keyword ngxDirectiveThirdParty contained set_encode_base64 +syn keyword ngxDirectiveThirdParty contained set_encode_base64url syn keyword ngxDirectiveThirdParty contained set_encode_hex syn keyword ngxDirectiveThirdParty contained set_escape_uri syn keyword ngxDirectiveThirdParty contained set_formatted_gmt_time syn keyword ngxDirectiveThirdParty contained set_formatted_local_time syn keyword ngxDirectiveThirdParty contained set_hashed_upstream syn keyword ngxDirectiveThirdParty contained set_hmac_sha1 +syn keyword ngxDirectiveThirdParty contained set_hmac_sha256 syn keyword ngxDirectiveThirdParty contained set_if_empty syn keyword ngxDirectiveThirdParty contained set_local_today syn keyword ngxDirectiveThirdParty contained set_misc_base32_padding @@ -1841,6 +1889,7 @@ syn keyword ngxDirectiveThirdParty contained vod_notification_uri syn keyword ngxDirectiveThirdParty contained vod_open_file_thread_pool syn keyword ngxDirectiveThirdParty contained vod_output_buffer_pool syn keyword ngxDirectiveThirdParty contained vod_parse_hdlr_name +syn keyword ngxDirectiveThirdParty contained vod_parse_udta_name syn keyword ngxDirectiveThirdParty contained vod_path_response_postfix syn keyword ngxDirectiveThirdParty contained vod_path_response_prefix syn keyword ngxDirectiveThirdParty contained vod_performance_counters @@ -2368,9 +2417,9 @@ syn keyword ngxDirectiveThirdParty contained websockify_send_timeout " IP2Location Nginx " https://github.com/ip2location/ip2location-nginx -syn keyword ngxDirectiveThirdParty contained ip2location_proxy -syn keyword ngxDirectiveThirdParty contained ip2location_proxy_recursive +syn keyword ngxDirectiveThirdParty contained ip2location_addresstype syn keyword ngxDirectiveThirdParty contained ip2location_areacode +syn keyword ngxDirectiveThirdParty contained ip2location_category syn keyword ngxDirectiveThirdParty contained ip2location_city syn keyword ngxDirectiveThirdParty contained ip2location_country_long syn keyword ngxDirectiveThirdParty contained ip2location_country_short @@ -2384,6 +2433,8 @@ syn keyword ngxDirectiveThirdParty contained ip2location_mcc syn keyword ngxDirectiveThirdParty contained ip2location_mnc syn keyword ngxDirectiveThirdParty contained ip2location_mobilebrand syn keyword ngxDirectiveThirdParty contained ip2location_netspeed +syn keyword ngxDirectiveThirdParty contained ip2location_proxy +syn keyword ngxDirectiveThirdParty contained ip2location_proxy_recursive syn keyword ngxDirectiveThirdParty contained ip2location_region syn keyword ngxDirectiveThirdParty contained ip2location_timezone syn keyword ngxDirectiveThirdParty contained ip2location_usagetype @@ -2403,6 +2454,7 @@ syn keyword ngxDirectiveThirdParty contained ip2proxy_domain syn keyword ngxDirectiveThirdParty contained ip2proxy_isp syn keyword ngxDirectiveThirdParty contained ip2proxy_is_proxy syn keyword ngxDirectiveThirdParty contained ip2proxy_last_seen +syn keyword ngxDirectiveThirdParty contained ip2proxy_provider syn keyword ngxDirectiveThirdParty contained ip2proxy_proxy syn keyword ngxDirectiveThirdParty contained ip2proxy_proxy_recursive syn keyword ngxDirectiveThirdParty contained ip2proxy_proxy_type @@ -2436,4 +2488,7 @@ hi def link ngxDirectiveThirdPartyDeprecated Error hi def link ngxListenOptions Keyword hi def link ngxListenOptionsDeprecated Error +let &cpo = s:save_cpo +unlet s:save_cpo + let b:current_syntax = "nginx" diff --git a/html/50x.html b/html/50x.html index 9071e0a..a57c2f9 100644 --- a/html/50x.html +++ b/html/50x.html @@ -3,11 +3,9 @@ Error diff --git a/html/index.html b/html/index.html index 2ca3b95..e8f5622 100644 --- a/html/index.html +++ b/html/index.html @@ -3,11 +3,9 @@ Welcome to nginx! diff --git a/src/core/nginx.h b/src/core/nginx.h index 7b873a1..329b603 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1020002 -#define NGINX_VERSION "1.20.2" +#define nginx_version 1022000 +#define NGINX_VERSION "1.22.0" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD diff --git a/src/core/ngx_buf.h b/src/core/ngx_buf.h index 4b66562..fdcd0cd 100644 --- a/src/core/ngx_buf.h +++ b/src/core/ngx_buf.h @@ -90,9 +90,6 @@ struct ngx_output_chain_ctx_s { #if (NGX_HAVE_FILE_AIO || NGX_COMPAT) ngx_output_chain_aio_pt aio_handler; -#if (NGX_HAVE_AIO_SENDFILE || NGX_COMPAT) - ssize_t (*aio_preload)(ngx_buf_t *file); -#endif #endif #if (NGX_THREADS || NGX_COMPAT) diff --git a/src/core/ngx_connection.c b/src/core/ngx_connection.c index 8339e2b..fe729a7 100644 --- a/src/core/ngx_connection.c +++ b/src/core/ngx_connection.c @@ -495,21 +495,24 @@ ngx_open_listening_sockets(ngx_cycle_t *cycle) return NGX_ERROR; } - if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, - (const void *) &reuseaddr, sizeof(int)) - == -1) - { - ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, - "setsockopt(SO_REUSEADDR) %V failed", - &ls[i].addr_text); + if (ls[i].type != SOCK_DGRAM || !ngx_test_config) { - if (ngx_close_socket(s) == -1) { + if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, + (const void *) &reuseaddr, sizeof(int)) + == -1) + { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, - ngx_close_socket_n " %V failed", + "setsockopt(SO_REUSEADDR) %V failed", &ls[i].addr_text); - } - return NGX_ERROR; + if (ngx_close_socket(s) == -1) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, + ngx_close_socket_n " %V failed", + &ls[i].addr_text); + } + + return NGX_ERROR; + } } #if (NGX_HAVE_REUSEPORT) diff --git a/src/core/ngx_connection.h b/src/core/ngx_connection.h index 4716da4..8cc1475 100644 --- a/src/core/ngx_connection.h +++ b/src/core/ngx_connection.h @@ -185,7 +185,7 @@ struct ngx_connection_s { unsigned need_last_buf:1; -#if (NGX_HAVE_AIO_SENDFILE || NGX_COMPAT) +#if (NGX_HAVE_SENDFILE_NODISKIO || NGX_COMPAT) unsigned busy_count:2; #endif diff --git a/src/core/ngx_hash.c b/src/core/ngx_hash.c index d9c157c..8215c27 100644 --- a/src/core/ngx_hash.c +++ b/src/core/ngx_hash.c @@ -274,6 +274,10 @@ ngx_hash_init(ngx_hash_init_t *hinit, ngx_hash_key_t *names, ngx_uint_t nelts) } for (n = 0; n < nelts; n++) { + if (names[n].key.data == NULL) { + continue; + } + if (hinit->bucket_size < NGX_HASH_ELT_SIZE(&names[n]) + sizeof(void *)) { ngx_log_error(NGX_LOG_EMERG, hinit->pool->log, 0, diff --git a/src/core/ngx_module.h b/src/core/ngx_module.h index 8cf3210..6fb4554 100644 --- a/src/core/ngx_module.h +++ b/src/core/ngx_module.h @@ -41,7 +41,7 @@ #define NGX_MODULE_SIGNATURE_3 "0" #endif -#if (NGX_HAVE_AIO_SENDFILE || NGX_COMPAT) +#if (NGX_HAVE_SENDFILE_NODISKIO || NGX_COMPAT) #define NGX_MODULE_SIGNATURE_4 "1" #else #define NGX_MODULE_SIGNATURE_4 "0" diff --git a/src/core/ngx_output_chain.c b/src/core/ngx_output_chain.c index 5c3dbe8..8570742 100644 --- a/src/core/ngx_output_chain.c +++ b/src/core/ngx_output_chain.c @@ -29,10 +29,6 @@ static ngx_inline ngx_int_t ngx_output_chain_as_is(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf); -#if (NGX_HAVE_AIO_SENDFILE) -static ngx_int_t ngx_output_chain_aio_setup(ngx_output_chain_ctx_t *ctx, - ngx_file_t *file); -#endif static ngx_int_t ngx_output_chain_add_copy(ngx_pool_t *pool, ngx_chain_t **chain, ngx_chain_t *in); static ngx_int_t ngx_output_chain_align_file_buf(ngx_output_chain_ctx_t *ctx, @@ -260,10 +256,6 @@ ngx_output_chain_as_is(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf) } #endif - if (buf->in_file && buf->file->directio) { - return 0; - } - sendfile = ctx->sendfile; #if (NGX_SENDFILE_LIMIT) @@ -272,6 +264,19 @@ ngx_output_chain_as_is(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf) sendfile = 0; } +#endif + +#if !(NGX_HAVE_SENDFILE_NODISKIO) + + /* + * With DIRECTIO, disable sendfile() unless sendfile(SF_NOCACHE) + * is available. + */ + + if (buf->in_file && buf->file->directio) { + sendfile = 0; + } + #endif if (!sendfile) { @@ -283,12 +288,6 @@ ngx_output_chain_as_is(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf) buf->in_file = 0; } -#if (NGX_HAVE_AIO_SENDFILE) - if (ctx->aio_preload && buf->in_file) { - (void) ngx_output_chain_aio_setup(ctx, buf->file); - } -#endif - if (ctx->need_in_memory && !ngx_buf_in_memory(buf)) { return 0; } @@ -301,28 +300,6 @@ ngx_output_chain_as_is(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf) } -#if (NGX_HAVE_AIO_SENDFILE) - -static ngx_int_t -ngx_output_chain_aio_setup(ngx_output_chain_ctx_t *ctx, ngx_file_t *file) -{ - ngx_event_aio_t *aio; - - if (file->aio == NULL && ngx_file_aio_init(file, ctx->pool) != NGX_OK) { - return NGX_ERROR; - } - - aio = file->aio; - - aio->data = ctx->filter_ctx; - aio->preload_handler = ctx->aio_preload; - - return NGX_OK; -} - -#endif - - static ngx_int_t ngx_output_chain_add_copy(ngx_pool_t *pool, ngx_chain_t **chain, ngx_chain_t *in) @@ -803,6 +780,10 @@ ngx_chain_writer(void *data, ngx_chain_t *in) return NGX_ERROR; } + if (chain && c->write->ready) { + ngx_post_event(c->write, &ngx_posted_next_events); + } + for (cl = ctx->out; cl && cl != chain; /* void */) { ln = cl; cl = cl->next; diff --git a/src/core/ngx_rbtree.h b/src/core/ngx_rbtree.h index 97f0e3e..e8c3582 100644 --- a/src/core/ngx_rbtree.h +++ b/src/core/ngx_rbtree.h @@ -47,6 +47,9 @@ struct ngx_rbtree_s { (tree)->sentinel = s; \ (tree)->insert = i +#define ngx_rbtree_data(node, type, link) \ + (type *) ((u_char *) (node) - offsetof(type, link)) + void ngx_rbtree_insert(ngx_rbtree_t *tree, ngx_rbtree_node_t *node); void ngx_rbtree_delete(ngx_rbtree_t *tree, ngx_rbtree_node_t *node); diff --git a/src/core/ngx_regex.c b/src/core/ngx_regex.c index 52169f6..bebf3b6 100644 --- a/src/core/ngx_regex.c +++ b/src/core/ngx_regex.c @@ -10,15 +10,22 @@ typedef struct { - ngx_flag_t pcre_jit; + ngx_flag_t pcre_jit; + ngx_list_t *studies; } ngx_regex_conf_t; +static ngx_inline void ngx_regex_malloc_init(ngx_pool_t *pool); +static ngx_inline void ngx_regex_malloc_done(void); + +#if (NGX_PCRE2) +static void * ngx_libc_cdecl ngx_regex_malloc(size_t size, void *data); +static void ngx_libc_cdecl ngx_regex_free(void *p, void *data); +#else static void * ngx_libc_cdecl ngx_regex_malloc(size_t size); static void ngx_libc_cdecl ngx_regex_free(void *p); -#if (NGX_HAVE_PCRE_JIT) -static void ngx_pcre_free_studies(void *data); #endif +static void ngx_regex_cleanup(void *data); static ngx_int_t ngx_regex_module_init(ngx_cycle_t *cycle); @@ -65,32 +72,197 @@ ngx_module_t ngx_regex_module = { }; -static ngx_pool_t *ngx_pcre_pool; -static ngx_list_t *ngx_pcre_studies; +static ngx_pool_t *ngx_regex_pool; +static ngx_list_t *ngx_regex_studies; +static ngx_uint_t ngx_regex_direct_alloc; + +#if (NGX_PCRE2) +static pcre2_compile_context *ngx_regex_compile_context; +static pcre2_match_data *ngx_regex_match_data; +static ngx_uint_t ngx_regex_match_data_size; +#endif void ngx_regex_init(void) { +#if !(NGX_PCRE2) pcre_malloc = ngx_regex_malloc; pcre_free = ngx_regex_free; +#endif } static ngx_inline void ngx_regex_malloc_init(ngx_pool_t *pool) { - ngx_pcre_pool = pool; + ngx_regex_pool = pool; + ngx_regex_direct_alloc = (pool == NULL) ? 1 : 0; } static ngx_inline void ngx_regex_malloc_done(void) { - ngx_pcre_pool = NULL; + ngx_regex_pool = NULL; + ngx_regex_direct_alloc = 0; } +#if (NGX_PCRE2) + +ngx_int_t +ngx_regex_compile(ngx_regex_compile_t *rc) +{ + int n, errcode; + char *p; + u_char errstr[128]; + size_t erroff; + uint32_t options; + pcre2_code *re; + ngx_regex_elt_t *elt; + pcre2_general_context *gctx; + pcre2_compile_context *cctx; + + 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. + */ + + ngx_regex_malloc_init(NULL); + + gctx = pcre2_general_context_create(ngx_regex_malloc, ngx_regex_free, + NULL); + if (gctx == NULL) { + ngx_regex_malloc_done(); + goto nomem; + } + + cctx = pcre2_compile_context_create(gctx); + if (cctx == NULL) { + pcre2_general_context_free(gctx); + ngx_regex_malloc_done(); + goto nomem; + } + + ngx_regex_compile_context = cctx; + + pcre2_general_context_free(gctx); + ngx_regex_malloc_done(); + } + + options = 0; + + if (rc->options & NGX_REGEX_CASELESS) { + options |= PCRE2_CASELESS; + } + + if (rc->options & NGX_REGEX_MULTILINE) { + options |= PCRE2_MULTILINE; + } + + if (rc->options & ~(NGX_REGEX_CASELESS|NGX_REGEX_MULTILINE)) { + rc->err.len = ngx_snprintf(rc->err.data, rc->err.len, + "regex \"%V\" compilation failed: invalid options", + &rc->pattern) + - rc->err.data; + return NGX_ERROR; + } + + ngx_regex_malloc_init(rc->pool); + + re = pcre2_compile(rc->pattern.data, rc->pattern.len, options, + &errcode, &erroff, ngx_regex_compile_context); + + /* ensure that there is no current pool */ + ngx_regex_malloc_done(); + + 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; + + /* do not study at runtime */ + + if (ngx_regex_studies != NULL) { + elt = ngx_list_push(ngx_regex_studies); + if (elt == NULL) { + goto nomem; + } + + elt->regex = rc->regex; + elt->name = rc->pattern.data; + } + + n = pcre2_pattern_info(re, PCRE2_INFO_CAPTURECOUNT, &rc->captures); + if (n < 0) { + p = "pcre2_pattern_info(\"%V\", PCRE2_INFO_CAPTURECOUNT) failed: %d"; + goto failed; + } + + if (rc->captures == 0) { + return NGX_OK; + } + + n = pcre2_pattern_info(re, PCRE2_INFO_NAMECOUNT, &rc->named_captures); + if (n < 0) { + p = "pcre2_pattern_info(\"%V\", PCRE2_INFO_NAMECOUNT) failed: %d"; + goto failed; + } + + if (rc->named_captures == 0) { + return NGX_OK; + } + + n = pcre2_pattern_info(re, PCRE2_INFO_NAMEENTRYSIZE, &rc->name_size); + if (n < 0) { + p = "pcre2_pattern_info(\"%V\", PCRE2_INFO_NAMEENTRYSIZE) failed: %d"; + goto failed; + } + + n = pcre2_pattern_info(re, PCRE2_INFO_NAMETABLE, &rc->names); + if (n < 0) { + p = "pcre2_pattern_info(\"%V\", PCRE2_INFO_NAMETABLE) failed: %d"; + goto failed; + } + + 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 + ngx_int_t ngx_regex_compile(ngx_regex_compile_t *rc) { @@ -98,11 +270,30 @@ ngx_regex_compile(ngx_regex_compile_t *rc) char *p; pcre *re; const char *errstr; + ngx_uint_t options; ngx_regex_elt_t *elt; + options = 0; + + if (rc->options & NGX_REGEX_CASELESS) { + options |= PCRE_CASELESS; + } + + if (rc->options & NGX_REGEX_MULTILINE) { + options |= PCRE_MULTILINE; + } + + if (rc->options & ~(NGX_REGEX_CASELESS|NGX_REGEX_MULTILINE)) { + rc->err.len = ngx_snprintf(rc->err.data, rc->err.len, + "regex \"%V\" compilation failed: invalid options", + &rc->pattern) + - rc->err.data; + return NGX_ERROR; + } + ngx_regex_malloc_init(rc->pool); - re = pcre_compile((const char *) rc->pattern.data, (int) rc->options, + re = pcre_compile((const char *) rc->pattern.data, (int) options, &errstr, &erroff, NULL); /* ensure that there is no current pool */ @@ -113,13 +304,13 @@ ngx_regex_compile(ngx_regex_compile_t *rc) rc->err.len = ngx_snprintf(rc->err.data, rc->err.len, "pcre_compile() failed: %s in \"%V\"", errstr, &rc->pattern) - - rc->err.data; + - rc->err.data; } else { rc->err.len = ngx_snprintf(rc->err.data, rc->err.len, "pcre_compile() failed: %s in \"%V\" at \"%s\"", errstr, &rc->pattern, rc->pattern.data + erroff) - - rc->err.data; + - rc->err.data; } return NGX_ERROR; @@ -134,8 +325,8 @@ ngx_regex_compile(ngx_regex_compile_t *rc) /* do not study at runtime */ - if (ngx_pcre_studies != NULL) { - elt = ngx_list_push(ngx_pcre_studies); + if (ngx_regex_studies != NULL) { + elt = ngx_list_push(ngx_regex_studies); if (elt == NULL) { goto nomem; } @@ -193,6 +384,83 @@ nomem: return NGX_ERROR; } +#endif + + +#if (NGX_PCRE2) + +ngx_int_t +ngx_regex_exec(ngx_regex_t *re, ngx_str_t *s, int *captures, ngx_uint_t size) +{ + size_t *ov; + ngx_int_t rc; + ngx_uint_t n, i; + + /* + * The pcre2_match() function might allocate memory for backtracking + * frames, typical allocations are from 40k and above. So the allocator + * is configured to do direct allocations from heap during matching. + */ + + ngx_regex_malloc_init(NULL); + + if (ngx_regex_match_data == NULL + || size > 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 = size; + ngx_regex_match_data = pcre2_match_data_create(size / 3, NULL); + + if (ngx_regex_match_data == NULL) { + rc = PCRE2_ERROR_NOMEMORY; + goto failed; + } + } + + rc = pcre2_match(re, s->data, s->len, 0, 0, ngx_regex_match_data, NULL); + + if (rc < 0) { + goto failed; + } + + n = pcre2_get_ovector_count(ngx_regex_match_data); + ov = pcre2_get_ovector_pointer(ngx_regex_match_data); + + if (n > size / 3) { + n = size / 3; + } + + for (i = 0; i < n; i++) { + captures[i * 2] = ov[i * 2]; + captures[i * 2 + 1] = ov[i * 2 + 1]; + } + +failed: + + ngx_regex_malloc_done(); + + return rc; +} + +#else + +ngx_int_t +ngx_regex_exec(ngx_regex_t *re, ngx_str_t *s, int *captures, ngx_uint_t size) +{ + return pcre_exec(re->code, re->extra, (const char *) s->data, s->len, + 0, 0, captures, size); +} + +#endif + ngx_int_t ngx_regex_exec_array(ngx_array_t *a, ngx_str_t *s, ngx_log_t *log) @@ -227,14 +495,40 @@ ngx_regex_exec_array(ngx_array_t *a, ngx_str_t *s, ngx_log_t *log) } +#if (NGX_PCRE2) + +static void * ngx_libc_cdecl +ngx_regex_malloc(size_t size, void *data) +{ + if (ngx_regex_pool) { + return ngx_palloc(ngx_regex_pool, size); + } + + if (ngx_regex_direct_alloc) { + return ngx_alloc(size, ngx_cycle->log); + } + + return NULL; +} + + +static void ngx_libc_cdecl +ngx_regex_free(void *p, void *data) +{ + if (ngx_regex_direct_alloc) { + ngx_free(p); + } + + return; +} + +#else + static void * ngx_libc_cdecl ngx_regex_malloc(size_t size) { - ngx_pool_t *pool; - pool = ngx_pcre_pool; - - if (pool) { - return ngx_palloc(pool, size); + if (ngx_regex_pool) { + return ngx_palloc(ngx_regex_pool, size); } return NULL; @@ -247,19 +541,20 @@ ngx_regex_free(void *p) return; } +#endif -#if (NGX_HAVE_PCRE_JIT) static void -ngx_pcre_free_studies(void *data) +ngx_regex_cleanup(void *data) { - ngx_list_t *studies = data; +#if (NGX_PCRE2 || NGX_HAVE_PCRE_JIT) + ngx_regex_conf_t *rcf = data; ngx_uint_t i; ngx_list_part_t *part; ngx_regex_elt_t *elts; - part = &studies->part; + part = &rcf->studies->part; elts = part->elts; for (i = 0; /* void */ ; i++) { @@ -274,56 +569,83 @@ ngx_pcre_free_studies(void *data) i = 0; } + /* + * The PCRE JIT compiler uses mmap for its executable codes, so we + * have to explicitly call the pcre_free_study() function to free + * this memory. In PCRE2, we call the pcre2_code_free() function + * for the same reason. + */ + +#if (NGX_PCRE2) + pcre2_code_free(elts[i].regex); +#else if (elts[i].regex->extra != NULL) { pcre_free_study(elts[i].regex->extra); } +#endif + } +#endif + + /* + * On configuration parsing errors ngx_regex_module_init() will not + * be called. Make sure ngx_regex_studies is properly cleared anyway. + */ + + ngx_regex_studies = NULL; + +#if (NGX_PCRE2) + + /* + * Free compile context and match data. If needed at runtime by + * the new cycle, these will be re-allocated. + */ + + if (ngx_regex_compile_context) { + pcre2_compile_context_free(ngx_regex_compile_context); + ngx_regex_compile_context = NULL; + } + + if (ngx_regex_match_data) { + pcre2_match_data_free(ngx_regex_match_data); + ngx_regex_match_data = NULL; + ngx_regex_match_data_size = 0; } -} #endif +} static ngx_int_t ngx_regex_module_init(ngx_cycle_t *cycle) { - int opt; - const char *errstr; - ngx_uint_t i; - ngx_list_part_t *part; - ngx_regex_elt_t *elts; + int opt; +#if !(NGX_PCRE2) + const char *errstr; +#endif + ngx_uint_t i; + ngx_list_part_t *part; + ngx_regex_elt_t *elts; + ngx_regex_conf_t *rcf; opt = 0; -#if (NGX_HAVE_PCRE_JIT) - { - ngx_regex_conf_t *rcf; - ngx_pool_cleanup_t *cln; - rcf = (ngx_regex_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_regex_module); +#if (NGX_PCRE2 || NGX_HAVE_PCRE_JIT) + if (rcf->pcre_jit) { +#if (NGX_PCRE2) + opt = 1; +#else opt = PCRE_STUDY_JIT_COMPILE; - - /* - * The PCRE JIT compiler uses mmap for its executable codes, so we - * have to explicitly call the pcre_free_study() function to free - * this memory. - */ - - cln = ngx_pool_cleanup_add(cycle->pool, 0); - if (cln == NULL) { - return NGX_ERROR; - } - - cln->handler = ngx_pcre_free_studies; - cln->data = ngx_pcre_studies; - } +#endif } + #endif ngx_regex_malloc_init(cycle->pool); - part = &ngx_pcre_studies->part; + part = &rcf->studies->part; elts = part->elts; for (i = 0; /* void */ ; i++) { @@ -338,6 +660,23 @@ ngx_regex_module_init(ngx_cycle_t *cycle) i = 0; } +#if (NGX_PCRE2) + + if (opt) { + int n; + + n = pcre2_jit_compile(elts[i].regex, PCRE2_JIT_COMPLETE); + + if (n != 0) { + ngx_log_error(NGX_LOG_INFO, cycle->log, 0, + "pcre2_jit_compile() failed: %d in \"%s\", " + "ignored", + n, elts[i].name); + } + } + +#else + elts[i].regex->extra = pcre_study(elts[i].regex->code, opt, &errstr); if (errstr != NULL) { @@ -360,12 +699,16 @@ ngx_regex_module_init(ngx_cycle_t *cycle) elts[i].name); } } +#endif #endif } ngx_regex_malloc_done(); - ngx_pcre_studies = NULL; + ngx_regex_studies = NULL; +#if (NGX_PCRE2) + ngx_regex_compile_context = NULL; +#endif return NGX_OK; } @@ -374,7 +717,8 @@ ngx_regex_module_init(ngx_cycle_t *cycle) static void * ngx_regex_create_conf(ngx_cycle_t *cycle) { - ngx_regex_conf_t *rcf; + ngx_regex_conf_t *rcf; + ngx_pool_cleanup_t *cln; rcf = ngx_pcalloc(cycle->pool, sizeof(ngx_regex_conf_t)); if (rcf == NULL) { @@ -383,11 +727,21 @@ ngx_regex_create_conf(ngx_cycle_t *cycle) rcf->pcre_jit = NGX_CONF_UNSET; - ngx_pcre_studies = ngx_list_create(cycle->pool, 8, sizeof(ngx_regex_elt_t)); - if (ngx_pcre_studies == NULL) { + cln = ngx_pool_cleanup_add(cycle->pool, 0); + if (cln == NULL) { return NULL; } + cln->handler = ngx_regex_cleanup; + cln->data = rcf; + + rcf->studies = ngx_list_create(cycle->pool, 8, sizeof(ngx_regex_elt_t)); + if (rcf->studies == NULL) { + return NULL; + } + + ngx_regex_studies = rcf->studies; + return rcf; } @@ -412,7 +766,21 @@ ngx_regex_pcre_jit(ngx_conf_t *cf, void *post, void *data) return NGX_CONF_OK; } -#if (NGX_HAVE_PCRE_JIT) +#if (NGX_PCRE2) + { + int r; + uint32_t jit; + + jit = 0; + r = pcre2_config(PCRE2_CONFIG_JIT, &jit); + + if (r != 0 || jit != 1) { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "PCRE2 library does not support JIT"); + *fp = 0; + } + } +#elif (NGX_HAVE_PCRE_JIT) { int jit, r; diff --git a/src/core/ngx_regex.h b/src/core/ngx_regex.h index 680486c..182373a 100644 --- a/src/core/ngx_regex.h +++ b/src/core/ngx_regex.h @@ -12,24 +12,38 @@ #include #include + +#if (NGX_PCRE2) + +#define PCRE2_CODE_UNIT_WIDTH 8 +#include + +#define NGX_REGEX_NO_MATCHED PCRE2_ERROR_NOMATCH /* -1 */ + +typedef pcre2_code ngx_regex_t; + +#else + #include - -#define NGX_REGEX_NO_MATCHED PCRE_ERROR_NOMATCH /* -1 */ - -#define NGX_REGEX_CASELESS PCRE_CASELESS - +#define NGX_REGEX_NO_MATCHED PCRE_ERROR_NOMATCH /* -1 */ typedef struct { pcre *code; pcre_extra *extra; } ngx_regex_t; +#endif + + +#define NGX_REGEX_CASELESS 0x00000001 +#define NGX_REGEX_MULTILINE 0x00000002 + typedef struct { ngx_str_t pattern; ngx_pool_t *pool; - ngx_int_t options; + ngx_uint_t options; ngx_regex_t *regex; int captures; @@ -49,10 +63,14 @@ typedef struct { void ngx_regex_init(void); ngx_int_t ngx_regex_compile(ngx_regex_compile_t *rc); -#define ngx_regex_exec(re, s, captures, size) \ - pcre_exec(re->code, re->extra, (const char *) (s)->data, (s)->len, 0, 0, \ - captures, size) -#define ngx_regex_exec_n "pcre_exec()" +ngx_int_t ngx_regex_exec(ngx_regex_t *re, ngx_str_t *s, int *captures, + ngx_uint_t size); + +#if (NGX_PCRE2) +#define ngx_regex_exec_n "pcre2_match()" +#else +#define ngx_regex_exec_n "pcre_exec()" +#endif ngx_int_t ngx_regex_exec_array(ngx_array_t *a, ngx_str_t *s, ngx_log_t *log); diff --git a/src/core/ngx_resolver.c b/src/core/ngx_resolver.c index 58d5f3e..6d129e5 100644 --- a/src/core/ngx_resolver.c +++ b/src/core/ngx_resolver.c @@ -51,9 +51,7 @@ typedef struct { } ngx_resolver_an_t; -#define ngx_resolver_node(n) \ - (ngx_resolver_node_t *) \ - ((u_char *) (n) - offsetof(ngx_resolver_node_t, node)) +#define ngx_resolver_node(n) ngx_rbtree_data(n, ngx_resolver_node_t, node) static ngx_int_t ngx_udp_connect(ngx_resolver_connection_t *rec); diff --git a/src/core/ngx_rwlock.c b/src/core/ngx_rwlock.c index ed2b0f8..e7da8a8 100644 --- a/src/core/ngx_rwlock.c +++ b/src/core/ngx_rwlock.c @@ -89,22 +89,10 @@ ngx_rwlock_rlock(ngx_atomic_t *lock) void ngx_rwlock_unlock(ngx_atomic_t *lock) { - ngx_atomic_uint_t readers; - - readers = *lock; - - if (readers == NGX_RWLOCK_WLOCK) { + if (*lock == NGX_RWLOCK_WLOCK) { (void) ngx_atomic_cmp_set(lock, NGX_RWLOCK_WLOCK, 0); - return; - } - - for ( ;; ) { - - if (ngx_atomic_cmp_set(lock, readers, readers - 1)) { - return; - } - - readers = *lock; + } else { + (void) ngx_atomic_fetch_add(lock, -1); } } diff --git a/src/core/ngx_string.c b/src/core/ngx_string.c index 93f32ea..98f270a 100644 --- a/src/core/ngx_string.c +++ b/src/core/ngx_string.c @@ -1493,19 +1493,32 @@ ngx_escape_uri(u_char *dst, u_char *src, size_t size, ngx_uint_t type) uint32_t *escape; static u_char hex[] = "0123456789ABCDEF"; - /* " ", "#", "%", "?", %00-%1F, %7F-%FF */ + /* + * Per RFC 3986 only the following chars are allowed in URIs unescaped: + * + * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" + * gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@" + * sub-delims = "!" / "$" / "&" / "'" / "(" / ")" + * / "*" / "+" / "," / ";" / "=" + * + * And "%" can appear as a part of escaping itself. The following + * characters are not allowed and need to be escaped: %00-%1F, %7F-%FF, + * " ", """, "<", ">", "\", "^", "`", "{", "|", "}". + */ + + /* " ", "#", "%", "?", not allowed */ static uint32_t uri[] = { 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */ - 0x80000029, /* 1000 0000 0000 0000 0000 0000 0010 1001 */ + 0xd000002d, /* 1101 0000 0000 0000 0000 0000 0010 1101 */ /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */ - 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ + 0x50000000, /* 0101 0000 0000 0000 0000 0000 0000 0000 */ /* ~}| {zyx wvut srqp onml kjih gfed cba` */ - 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */ + 0xb8000001, /* 1011 1000 0000 0000 0000 0000 0000 0001 */ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ @@ -1513,19 +1526,19 @@ ngx_escape_uri(u_char *dst, u_char *src, size_t size, ngx_uint_t type) 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */ }; - /* " ", "#", "%", "&", "+", "?", %00-%1F, %7F-%FF */ + /* " ", "#", "%", "&", "+", ";", "?", not allowed */ static uint32_t args[] = { 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */ - 0x88000869, /* 1000 1000 0000 0000 0000 1000 0110 1001 */ + 0xd800086d, /* 1101 1000 0000 0000 0000 1000 0110 1101 */ /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */ - 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ + 0x50000000, /* 0101 0000 0000 0000 0000 0000 0000 0000 */ /* ~}| {zyx wvut srqp onml kjih gfed cba` */ - 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */ + 0xb8000001, /* 1011 1000 0000 0000 0000 0000 0000 0001 */ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ @@ -1553,19 +1566,19 @@ ngx_escape_uri(u_char *dst, u_char *src, size_t size, ngx_uint_t type) 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */ }; - /* " ", "#", """, "%", "'", %00-%1F, %7F-%FF */ + /* " ", "#", """, "%", "'", not allowed */ static uint32_t html[] = { 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */ - 0x000000ad, /* 0000 0000 0000 0000 0000 0000 1010 1101 */ + 0x500000ad, /* 0101 0000 0000 0000 0000 0000 1010 1101 */ /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */ - 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ + 0x50000000, /* 0101 0000 0000 0000 0000 0000 0000 0000 */ /* ~}| {zyx wvut srqp onml kjih gfed cba` */ - 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */ + 0xb8000001, /* 1011 1000 0000 0000 0000 0000 0000 0001 */ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ @@ -1573,19 +1586,19 @@ ngx_escape_uri(u_char *dst, u_char *src, size_t size, ngx_uint_t type) 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */ }; - /* " ", """, "%", "'", %00-%1F, %7F-%FF */ + /* " ", """, "'", not allowed */ static uint32_t refresh[] = { 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */ - 0x00000085, /* 0000 0000 0000 0000 0000 0000 1000 0101 */ + 0x50000085, /* 0101 0000 0000 0000 0000 0000 1000 0101 */ /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */ - 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ + 0x50000000, /* 0101 0000 0000 0000 0000 0000 0000 0000 */ /* ~}| {zyx wvut srqp onml kjih gfed cba` */ - 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */ + 0xd8000001, /* 1011 1000 0000 0000 0000 0000 0000 0001 */ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ diff --git a/src/core/ngx_times.c b/src/core/ngx_times.c index 7964b00..16788c9 100644 --- a/src/core/ngx_times.c +++ b/src/core/ngx_times.c @@ -200,10 +200,6 @@ ngx_monotonic_time(time_t sec, ngx_uint_t msec) #if defined(CLOCK_MONOTONIC_FAST) clock_gettime(CLOCK_MONOTONIC_FAST, &ts); - -#elif defined(CLOCK_MONOTONIC_COARSE) - clock_gettime(CLOCK_MONOTONIC_COARSE, &ts); - #else clock_gettime(CLOCK_MONOTONIC, &ts); #endif diff --git a/src/event/ngx_event.c b/src/event/ngx_event.c index 7777d04..47229b5 100644 --- a/src/event/ngx_event.c +++ b/src/event/ngx_event.c @@ -55,6 +55,7 @@ ngx_uint_t ngx_accept_events; ngx_uint_t ngx_accept_mutex_held; ngx_msec_t ngx_accept_mutex_delay; ngx_int_t ngx_accept_disabled; +ngx_uint_t ngx_use_exclusive_accept; #if (NGX_STAT_STUB) @@ -441,20 +442,23 @@ ngx_event_init_conf(ngx_cycle_t *cycle, void *conf) #if (NGX_HAVE_REUSEPORT) - ls = cycle->listening.elts; - for (i = 0; i < cycle->listening.nelts; i++) { - - if (!ls[i].reuseport || ls[i].worker != 0) { - continue; - } - - if (ngx_clone_listening(cycle, &ls[i]) != NGX_OK) { - return NGX_CONF_ERROR; - } - - /* cloning may change cycle->listening.elts */ + if (!ngx_test_config) { ls = cycle->listening.elts; + for (i = 0; i < cycle->listening.nelts; i++) { + + if (!ls[i].reuseport || ls[i].worker != 0) { + continue; + } + + if (ngx_clone_listening(cycle, &ls[i]) != NGX_OK) { + return NGX_CONF_ERROR; + } + + /* cloning may change cycle->listening.elts */ + + ls = cycle->listening.elts; + } } #endif @@ -641,6 +645,8 @@ ngx_event_process_init(ngx_cycle_t *cycle) #endif + ngx_use_exclusive_accept = 0; + ngx_queue_init(&ngx_posted_accept_events); ngx_queue_init(&ngx_posted_next_events); ngx_queue_init(&ngx_posted_events); @@ -886,6 +892,8 @@ ngx_event_process_init(ngx_cycle_t *cycle) if ((ngx_event_flags & NGX_USE_EPOLL_EVENT) && ccf->worker_processes > 1) { + ngx_use_exclusive_accept = 1; + if (ngx_add_event(rev, NGX_READ_EVENT, NGX_EXCLUSIVE_EVENT) == NGX_ERROR) { diff --git a/src/event/ngx_event.h b/src/event/ngx_event.h index 97f9673..548c906 100644 --- a/src/event/ngx_event.h +++ b/src/event/ngx_event.h @@ -147,10 +147,6 @@ struct ngx_event_aio_s { ngx_fd_t fd; -#if (NGX_HAVE_AIO_SENDFILE || NGX_COMPAT) - ssize_t (*preload_handler)(ngx_buf_t *file); -#endif - #if (NGX_HAVE_EVENTFD) int64_t res; #endif @@ -466,6 +462,7 @@ extern ngx_uint_t ngx_accept_events; extern ngx_uint_t ngx_accept_mutex_held; extern ngx_msec_t ngx_accept_mutex_delay; extern ngx_int_t ngx_accept_disabled; +extern ngx_uint_t ngx_use_exclusive_accept; #if (NGX_STAT_STUB) diff --git a/src/event/ngx_event_accept.c b/src/event/ngx_event_accept.c index b05666c..2703879 100644 --- a/src/event/ngx_event_accept.c +++ b/src/event/ngx_event_accept.c @@ -11,6 +11,9 @@ static ngx_int_t ngx_disable_accept_events(ngx_cycle_t *cycle, ngx_uint_t all); +#if (NGX_HAVE_EPOLLEXCLUSIVE) +static void ngx_reorder_accept_events(ngx_listening_t *ls); +#endif static void ngx_close_accepted_connection(ngx_connection_t *c); @@ -314,6 +317,10 @@ ngx_event_accept(ngx_event_t *ev) } } while (ev->available); + +#if (NGX_HAVE_EPOLLEXCLUSIVE) + ngx_reorder_accept_events(ls); +#endif } @@ -420,6 +427,57 @@ ngx_disable_accept_events(ngx_cycle_t *cycle, ngx_uint_t all) } +#if (NGX_HAVE_EPOLLEXCLUSIVE) + +static void +ngx_reorder_accept_events(ngx_listening_t *ls) +{ + ngx_connection_t *c; + + /* + * Linux with EPOLLEXCLUSIVE usually notifies only the process which + * was first to add the listening socket to the epoll instance. As + * a result most of the connections are handled by the first worker + * process. To fix this, we re-add the socket periodically, so other + * workers will get a chance to accept connections. + */ + + if (!ngx_use_exclusive_accept) { + return; + } + +#if (NGX_HAVE_REUSEPORT) + + if (ls->reuseport) { + return; + } + +#endif + + c = ls->connection; + + if (c->requests++ % 16 != 0 + && ngx_accept_disabled <= 0) + { + return; + } + + if (ngx_del_event(c->read, NGX_READ_EVENT, NGX_DISABLE_EVENT) + == NGX_ERROR) + { + return; + } + + if (ngx_add_event(c->read, NGX_READ_EVENT, NGX_EXCLUSIVE_EVENT) + == NGX_ERROR) + { + return; + } +} + +#endif + + static void ngx_close_accepted_connection(ngx_connection_t *c) { diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c index ce2a566..1e6fc96 100644 --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -47,6 +47,8 @@ static void ngx_ssl_write_handler(ngx_event_t *wev); static ssize_t ngx_ssl_write_early(ngx_connection_t *c, u_char *data, size_t size); #endif +static ssize_t ngx_ssl_sendfile(ngx_connection_t *c, ngx_buf_t *file, + size_t size); static void ngx_ssl_read_handler(ngx_event_t *rev); static void ngx_ssl_shutdown_handler(ngx_event_t *ev); static void ngx_ssl_connection_error(ngx_connection_t *c, int sslerr, @@ -299,11 +301,6 @@ ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_t protocols, void *data) SSL_CTX_set_options(ssl->ctx, SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER); #endif -#ifdef SSL_OP_MSIE_SSLV2_RSA_PADDING - /* this option allow a potential SSL 2.0 rollback (CAN-2005-2969) */ - SSL_CTX_set_options(ssl->ctx, SSL_OP_MSIE_SSLV2_RSA_PADDING); -#endif - #ifdef SSL_OP_SSLEAY_080_CLIENT_DH_BUG SSL_CTX_set_options(ssl->ctx, SSL_OP_SSLEAY_080_CLIENT_DH_BUG); #endif @@ -863,11 +860,6 @@ ngx_ssl_ciphers(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *ciphers, SSL_CTX_set_options(ssl->ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); } -#if (OPENSSL_VERSION_NUMBER < 0x10100001L && !defined LIBRESSL_VERSION_NUMBER) - /* a temporary 512-bit RSA key is required for export versions of MSIE */ - SSL_CTX_set_tmp_rsa_callback(ssl->ctx, ngx_ssl_rsa512_key_callback); -#endif - return NGX_OK; } @@ -1120,32 +1112,6 @@ ngx_ssl_info_callback(const ngx_ssl_conn_t *ssl_conn, int where, int ret) } -#if (OPENSSL_VERSION_NUMBER < 0x10100001L && !defined LIBRESSL_VERSION_NUMBER) - -RSA * -ngx_ssl_rsa512_key_callback(ngx_ssl_conn_t *ssl_conn, int is_export, - int key_length) -{ - static RSA *key; - - if (key_length != 512) { - return NULL; - } - -#ifndef OPENSSL_NO_DEPRECATED - - if (key == NULL) { - key = RSA_generate_key(512, RSA_F4, NULL, NULL); - } - -#endif - - return key; -} - -#endif - - ngx_array_t * ngx_ssl_read_password_file(ngx_conf_t *cf, ngx_str_t *file) { @@ -1417,6 +1383,9 @@ ngx_ssl_dhparam(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file) if (SSL_CTX_set0_tmp_dh_pkey(ssl->ctx, dh) != 1) { ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "SSL_CTX_set0_tmp_dh_pkey(\%s\") failed", file->data); +#if (OPENSSL_VERSION_NUMBER >= 0x3000001fL) + EVP_PKEY_free(dh); +#endif BIO_free(bio); return NGX_ERROR; } @@ -1798,6 +1767,16 @@ ngx_ssl_handshake(ngx_connection_t *c) #endif #endif +#endif + +#ifdef BIO_get_ktls_send + + if (BIO_get_ktls_send(SSL_get_wbio(c->ssl->connection)) == 1) { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, + "BIO_get_ktls_send(): 1"); + c->ssl->sendfile = 1; + } + #endif rc = ngx_ssl_ocsp_validate(c); @@ -1935,6 +1914,16 @@ ngx_ssl_try_early_data(ngx_connection_t *c) c->read->ready = 1; c->write->ready = 1; +#ifdef BIO_get_ktls_send + + if (BIO_get_ktls_send(SSL_get_wbio(c->ssl->connection)) == 1) { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, + "BIO_get_ktls_send(): 1"); + c->ssl->sendfile = 1; + } + +#endif + rc = ngx_ssl_ocsp_validate(c); if (rc == NGX_ERROR) { @@ -2538,10 +2527,11 @@ ngx_ssl_write_handler(ngx_event_t *wev) ngx_chain_t * ngx_ssl_send_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) { - int n; - ngx_uint_t flush; - ssize_t send, size; - ngx_buf_t *buf; + int n; + ngx_uint_t flush; + ssize_t send, size, file_size; + ngx_buf_t *buf; + ngx_chain_t *cl; if (!c->ssl->buffer) { @@ -2615,6 +2605,11 @@ ngx_ssl_send_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) continue; } + if (in->buf->in_file && c->ssl->sendfile) { + flush = 1; + break; + } + size = in->buf->last - in->buf->pos; if (size > buf->end - buf->last) { @@ -2646,8 +2641,35 @@ ngx_ssl_send_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) size = buf->last - buf->pos; if (size == 0) { + + if (in && in->buf->in_file && send < limit) { + + /* coalesce the neighbouring file bufs */ + + cl = in; + file_size = (size_t) ngx_chain_coalesce_file(&cl, limit - send); + + n = ngx_ssl_sendfile(c, in->buf, file_size); + + if (n == NGX_ERROR) { + return NGX_CHAIN_ERROR; + } + + if (n == NGX_AGAIN) { + break; + } + + in = ngx_chain_update_sent(in, n); + + send += n; + flush = 0; + + continue; + } + buf->flush = 0; c->buffered &= ~NGX_SSL_BUFFERED; + return in; } @@ -2672,7 +2694,7 @@ ngx_ssl_send_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) buf->pos = buf->start; buf->last = buf->start; - if (in == NULL || send == limit) { + if (in == NULL || send >= limit) { break; } } @@ -2803,7 +2825,7 @@ ngx_ssl_write(ngx_connection_t *c, u_char *data, size_t size) #ifdef SSL_READ_EARLY_DATA_SUCCESS -ssize_t +static ssize_t ngx_ssl_write_early(ngx_connection_t *c, u_char *data, size_t size) { int n, sslerr; @@ -2918,6 +2940,183 @@ ngx_ssl_write_early(ngx_connection_t *c, u_char *data, size_t size) #endif +static ssize_t +ngx_ssl_sendfile(ngx_connection_t *c, ngx_buf_t *file, size_t size) +{ +#ifdef BIO_get_ktls_send + + int sslerr, flags; + ssize_t n; + ngx_err_t err; + + ngx_ssl_clear_error(c->log); + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "SSL to sendfile: @%O %uz", + file->file_pos, size); + + ngx_set_errno(0); + +#if (NGX_HAVE_SENDFILE_NODISKIO) + + flags = (c->busy_count <= 2) ? SF_NODISKIO : 0; + + if (file->file->directio) { + flags |= SF_NOCACHE; + } + +#else + flags = 0; +#endif + + n = SSL_sendfile(c->ssl->connection, file->file->fd, file->file_pos, + size, flags); + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_sendfile: %d", n); + + if (n > 0) { + + if (c->ssl->saved_read_handler) { + + c->read->handler = c->ssl->saved_read_handler; + c->ssl->saved_read_handler = NULL; + c->read->ready = 1; + + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + return NGX_ERROR; + } + + ngx_post_event(c->read, &ngx_posted_events); + } + +#if (NGX_HAVE_SENDFILE_NODISKIO) + c->busy_count = 0; +#endif + + c->sent += n; + + return n; + } + + if (n == 0) { + + /* + * if sendfile returns zero, then someone has truncated the file, + * so the offset became beyond the end of the file + */ + + ngx_log_error(NGX_LOG_ALERT, c->log, 0, + "SSL_sendfile() reported that \"%s\" was truncated at %O", + file->file->name.data, file->file_pos); + + return NGX_ERROR; + } + + sslerr = SSL_get_error(c->ssl->connection, n); + + if (sslerr == SSL_ERROR_ZERO_RETURN) { + + /* + * OpenSSL fails to return SSL_ERROR_SYSCALL if an error + * happens during writing after close_notify alert from the + * peer, and returns SSL_ERROR_ZERO_RETURN instead + */ + + sslerr = SSL_ERROR_SYSCALL; + } + + if (sslerr == SSL_ERROR_SSL + && ERR_GET_REASON(ERR_peek_error()) == SSL_R_UNINITIALIZED + && ngx_errno != 0) + { + /* + * OpenSSL fails to return SSL_ERROR_SYSCALL if an error + * happens in sendfile(), and returns SSL_ERROR_SSL with + * SSL_R_UNINITIALIZED reason instead + */ + + sslerr = SSL_ERROR_SYSCALL; + } + + err = (sslerr == SSL_ERROR_SYSCALL) ? ngx_errno : 0; + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_get_error: %d", sslerr); + + if (sslerr == SSL_ERROR_WANT_WRITE) { + + if (c->ssl->saved_read_handler) { + + c->read->handler = c->ssl->saved_read_handler; + c->ssl->saved_read_handler = NULL; + c->read->ready = 1; + + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + return NGX_ERROR; + } + + ngx_post_event(c->read, &ngx_posted_events); + } + +#if (NGX_HAVE_SENDFILE_NODISKIO) + + if (ngx_errno == EBUSY) { + c->busy_count++; + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "SSL_sendfile() busy, count:%d", c->busy_count); + + if (c->write->posted) { + ngx_delete_posted_event(c->write); + } + + ngx_post_event(c->write, &ngx_posted_next_events); + } + +#endif + + c->write->ready = 0; + return NGX_AGAIN; + } + + if (sslerr == SSL_ERROR_WANT_READ) { + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, + "SSL_sendfile: want read"); + + c->read->ready = 0; + + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + return NGX_ERROR; + } + + /* + * we do not set the timer because there is already + * the write event timer + */ + + if (c->ssl->saved_read_handler == NULL) { + c->ssl->saved_read_handler = c->read->handler; + c->read->handler = ngx_ssl_read_handler; + } + + return NGX_AGAIN; + } + + c->ssl->no_wait_shutdown = 1; + c->ssl->no_send_shutdown = 1; + c->write->error = 1; + + ngx_ssl_connection_error(c, sslerr, err, "SSL_sendfile() failed"); + +#else + ngx_log_error(NGX_LOG_ALERT, c->log, 0, + "SSL_sendfile() not available"); +#endif + + return NGX_ERROR; +} + + static void ngx_ssl_read_handler(ngx_event_t *rev) { @@ -3169,6 +3368,9 @@ ngx_ssl_connection_error(ngx_connection_t *c, int sslerr, ngx_err_t err, #endif #ifdef SSL_R_CALLBACK_FAILED || n == SSL_R_CALLBACK_FAILED /* 234 */ +#endif +#ifdef SSL_R_NO_APPLICATION_PROTOCOL + || n == SSL_R_NO_APPLICATION_PROTOCOL /* 235 */ #endif || n == SSL_R_UNEXPECTED_MESSAGE /* 244 */ || n == SSL_R_UNEXPECTED_RECORD /* 245 */ @@ -4249,7 +4451,21 @@ ngx_ssl_session_ticket_key_callback(ngx_ssl_conn_t *ssl_conn, return -1; } - return (i == 0) ? 1 : 2 /* renew */; + /* renew if TLSv1.3 */ + +#ifdef TLS1_3_VERSION + if (SSL_version(ssl_conn) == TLS1_3_VERSION) { + return 2; + } +#endif + + /* renew if non-default key */ + + if (i != 0) { + return 2; + } + + return 1; } } @@ -4567,6 +4783,42 @@ ngx_ssl_get_ciphers(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) } +ngx_int_t +ngx_ssl_get_curve(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) +{ +#ifdef SSL_get_negotiated_group + + int nid; + + nid = SSL_get_negotiated_group(c->ssl->connection); + + if (nid != NID_undef) { + + if ((nid & TLSEXT_nid_unknown) == 0) { + s->len = ngx_strlen(OBJ_nid2sn(nid)); + s->data = (u_char *) OBJ_nid2sn(nid); + return NGX_OK; + } + + s->len = sizeof("0x0000") - 1; + + s->data = ngx_pnalloc(pool, s->len); + if (s->data == NULL) { + return NGX_ERROR; + } + + ngx_sprintf(s->data, "0x%04xd", nid & 0xffff); + + return NGX_OK; + } + +#endif + + s->len = 0; + return NGX_OK; +} + + ngx_int_t ngx_ssl_get_curves(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) { @@ -4734,6 +4986,36 @@ ngx_ssl_get_server_name(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) } +ngx_int_t +ngx_ssl_get_alpn_protocol(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) +{ +#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation + + unsigned int len; + const unsigned char *data; + + SSL_get0_alpn_selected(c->ssl->connection, &data, &len); + + if (len > 0) { + + s->data = ngx_pnalloc(pool, len); + if (s->data == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(s->data, data, len); + s->len = len; + + return NGX_OK; + } + +#endif + + s->len = 0; + return NGX_OK; +} + + ngx_int_t ngx_ssl_get_raw_certificate(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) { diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h index 81b87d7..c9e86d9 100644 --- a/src/event/ngx_event_openssl.h +++ b/src/event/ngx_event_openssl.h @@ -29,7 +29,6 @@ #include #endif #include -#include #include #include @@ -110,6 +109,7 @@ struct ngx_ssl_connection_s { unsigned handshake_rejected:1; unsigned renegotiation:1; unsigned buffer:1; + unsigned sendfile:1; unsigned no_wait_shutdown:1; unsigned no_send_shutdown:1; unsigned shutdown_without_free:1; @@ -208,10 +208,6 @@ ngx_int_t ngx_ssl_ocsp_validate(ngx_connection_t *c); ngx_int_t ngx_ssl_ocsp_get_status(ngx_connection_t *c, const char **s); void ngx_ssl_ocsp_cleanup(ngx_connection_t *c); ngx_int_t ngx_ssl_ocsp_cache_init(ngx_shm_zone_t *shm_zone, void *data); -#if (OPENSSL_VERSION_NUMBER < 0x10100001L && !defined LIBRESSL_VERSION_NUMBER) -RSA *ngx_ssl_rsa512_key_callback(ngx_ssl_conn_t *ssl_conn, int is_export, - int key_length); -#endif ngx_array_t *ngx_ssl_read_password_file(ngx_conf_t *cf, ngx_str_t *file); ngx_array_t *ngx_ssl_preserve_passwords(ngx_conf_t *cf, ngx_array_t *passwords); @@ -260,6 +256,8 @@ ngx_int_t ngx_ssl_get_cipher_name(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s); ngx_int_t ngx_ssl_get_ciphers(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s); +ngx_int_t ngx_ssl_get_curve(ngx_connection_t *c, ngx_pool_t *pool, + ngx_str_t *s); ngx_int_t ngx_ssl_get_curves(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s); ngx_int_t ngx_ssl_get_session_id(ngx_connection_t *c, ngx_pool_t *pool, @@ -270,6 +268,8 @@ ngx_int_t ngx_ssl_get_early_data(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s); ngx_int_t ngx_ssl_get_server_name(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s); +ngx_int_t ngx_ssl_get_alpn_protocol(ngx_connection_t *c, ngx_pool_t *pool, + ngx_str_t *s); ngx_int_t ngx_ssl_get_raw_certificate(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s); ngx_int_t ngx_ssl_get_certificate(ngx_connection_t *c, ngx_pool_t *pool, diff --git a/src/event/ngx_event_timer.c b/src/event/ngx_event_timer.c index 698b88f..35052bc 100644 --- a/src/event/ngx_event_timer.c +++ b/src/event/ngx_event_timer.c @@ -73,7 +73,7 @@ ngx_event_expire_timers(void) return; } - ev = (ngx_event_t *) ((char *) node - offsetof(ngx_event_t, timer)); + ev = ngx_rbtree_data(node, ngx_event_t, timer); ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0, "event timer del: %d: %M", @@ -113,7 +113,7 @@ ngx_event_no_timers_left(void) node; node = ngx_rbtree_next(&ngx_event_timer_rbtree, node)) { - ev = (ngx_event_t *) ((char *) node - offsetof(ngx_event_t, timer)); + ev = ngx_rbtree_data(node, ngx_event_t, timer); if (!ev->cancelable) { return NGX_AGAIN; diff --git a/src/http/modules/ngx_http_auth_basic_module.c b/src/http/modules/ngx_http_auth_basic_module.c index ed9df34..0693319 100644 --- a/src/http/modules/ngx_http_auth_basic_module.c +++ b/src/http/modules/ngx_http_auth_basic_module.c @@ -16,7 +16,7 @@ typedef struct { ngx_http_complex_value_t *realm; - ngx_http_complex_value_t user_file; + ngx_http_complex_value_t *user_file; } ngx_http_auth_basic_loc_conf_t; @@ -107,7 +107,7 @@ ngx_http_auth_basic_handler(ngx_http_request_t *r) alcf = ngx_http_get_module_loc_conf(r, ngx_http_auth_basic_module); - if (alcf->realm == NULL || alcf->user_file.value.data == NULL) { + if (alcf->realm == NULL || alcf->user_file == NULL) { return NGX_DECLINED; } @@ -133,7 +133,7 @@ ngx_http_auth_basic_handler(ngx_http_request_t *r) return NGX_HTTP_INTERNAL_SERVER_ERROR; } - if (ngx_http_complex_value(r, &alcf->user_file, &user_file) != NGX_OK) { + if (ngx_http_complex_value(r, alcf->user_file, &user_file) != NGX_OK) { return NGX_ERROR; } @@ -357,6 +357,9 @@ ngx_http_auth_basic_create_loc_conf(ngx_conf_t *cf) return NULL; } + conf->realm = NGX_CONF_UNSET_PTR; + conf->user_file = NGX_CONF_UNSET_PTR; + return conf; } @@ -367,13 +370,8 @@ ngx_http_auth_basic_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_http_auth_basic_loc_conf_t *prev = parent; ngx_http_auth_basic_loc_conf_t *conf = child; - if (conf->realm == NULL) { - conf->realm = prev->realm; - } - - if (conf->user_file.value.data == NULL) { - conf->user_file = prev->user_file; - } + ngx_conf_merge_ptr_value(conf->realm, prev->realm, NULL); + ngx_conf_merge_ptr_value(conf->user_file, prev->user_file, NULL); return NGX_CONF_OK; } @@ -406,17 +404,22 @@ ngx_http_auth_basic_user_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_str_t *value; ngx_http_compile_complex_value_t ccv; - if (alcf->user_file.value.data) { + if (alcf->user_file != NGX_CONF_UNSET_PTR) { return "is duplicate"; } + alcf->user_file = ngx_palloc(cf->pool, sizeof(ngx_http_complex_value_t)); + if (alcf->user_file == NULL) { + return NGX_CONF_ERROR; + } + value = cf->args->elts; ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); ccv.cf = cf; ccv.value = &value[1]; - ccv.complex_value = &alcf->user_file; + ccv.complex_value = alcf->user_file; ccv.zero = 1; ccv.conf_prefix = 1; diff --git a/src/http/modules/ngx_http_dav_module.c b/src/http/modules/ngx_http_dav_module.c index 8b69e6f..0cc9ae1 100644 --- a/src/http/modules/ngx_http_dav_module.c +++ b/src/http/modules/ngx_http_dav_module.c @@ -1072,6 +1072,10 @@ ngx_http_dav_error(ngx_log_t *log, ngx_err_t err, ngx_int_t not_found, static ngx_int_t ngx_http_dav_location(ngx_http_request_t *r) { + u_char *p; + size_t len; + uintptr_t escape; + r->headers_out.location = ngx_list_push(&r->headers_out.headers); if (r->headers_out.location == NULL) { return NGX_ERROR; @@ -1079,7 +1083,26 @@ ngx_http_dav_location(ngx_http_request_t *r) r->headers_out.location->hash = 1; ngx_str_set(&r->headers_out.location->key, "Location"); - r->headers_out.location->value = r->uri; + + escape = 2 * ngx_escape_uri(NULL, r->uri.data, r->uri.len, NGX_ESCAPE_URI); + + if (escape) { + len = r->uri.len + escape; + + p = ngx_pnalloc(r->pool, len); + if (p == NULL) { + ngx_http_clear_location(r); + return NGX_ERROR; + } + + r->headers_out.location->value.len = len; + r->headers_out.location->value.data = p; + + ngx_escape_uri(p, r->uri.data, r->uri.len, NGX_ESCAPE_URI); + + } else { + r->headers_out.location->value = r->uri; + } return NGX_OK; } diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c index 5191880..4a8dc33 100644 --- a/src/http/modules/ngx_http_fastcgi_module.c +++ b/src/http/modules/ngx_http_fastcgi_module.c @@ -2019,10 +2019,12 @@ ngx_http_fastcgi_process_header(ngx_http_request_t *r) break; } - /* there was error while a header line parsing */ + /* rc == NGX_HTTP_PARSE_INVALID_HEADER */ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "upstream sent invalid header"); + "upstream sent invalid header: \"%*s\\x%02xd...\"", + r->header_end - r->header_name_start, + r->header_name_start, *r->header_end); return NGX_HTTP_UPSTREAM_INVALID_HEADER; } diff --git a/src/http/modules/ngx_http_grpc_module.c b/src/http/modules/ngx_http_grpc_module.c index 27a36e8..864fc4f 100644 --- a/src/http/modules/ngx_http_grpc_module.c +++ b/src/http/modules/ngx_http_grpc_module.c @@ -37,9 +37,6 @@ typedef struct { ngx_uint_t ssl_verify_depth; ngx_str_t ssl_trusted_certificate; ngx_str_t ssl_crl; - ngx_str_t ssl_certificate; - ngx_str_t ssl_certificate_key; - ngx_array_t *ssl_passwords; ngx_array_t *ssl_conf_commands; #endif } ngx_http_grpc_loc_conf_t; @@ -426,16 +423,16 @@ static ngx_command_t ngx_http_grpc_commands[] = { { ngx_string("grpc_ssl_certificate"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_conf_set_str_slot, + ngx_http_set_complex_value_zero_slot, NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_grpc_loc_conf_t, ssl_certificate), + offsetof(ngx_http_grpc_loc_conf_t, upstream.ssl_certificate), NULL }, { ngx_string("grpc_ssl_certificate_key"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_conf_set_str_slot, + ngx_http_set_complex_value_zero_slot, NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_grpc_loc_conf_t, ssl_certificate_key), + offsetof(ngx_http_grpc_loc_conf_t, upstream.ssl_certificate_key), NULL }, { ngx_string("grpc_ssl_password_file"), @@ -2180,6 +2177,8 @@ ngx_http_grpc_filter(void *data, ssize_t bytes) } ctx->rst = 1; + + continue; } if (ctx->type == NGX_HTTP_V2_GOAWAY_FRAME) { @@ -3181,10 +3180,10 @@ ngx_http_grpc_parse_fragment(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx, ctx->field_rest -= size; if (ctx->field_huffman) { - if (ngx_http_v2_huff_decode(&ctx->field_state, p, size, - &ctx->field_end, - ctx->field_rest == 0, - r->connection->log) + if (ngx_http_huff_decode(&ctx->field_state, p, size, + &ctx->field_end, + ctx->field_rest == 0, + r->connection->log) != NGX_OK) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, @@ -3290,10 +3289,10 @@ ngx_http_grpc_parse_fragment(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx, ctx->field_rest -= size; if (ctx->field_huffman) { - if (ngx_http_v2_huff_decode(&ctx->field_state, p, size, - &ctx->field_end, - ctx->field_rest == 0, - r->connection->log) + if (ngx_http_huff_decode(&ctx->field_state, p, size, + &ctx->field_end, + ctx->field_rest == 0, + r->connection->log) != NGX_OK) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, @@ -3385,7 +3384,7 @@ ngx_http_grpc_validate_header_name(ngx_http_request_t *r, ngx_str_t *s) return NGX_ERROR; } - if (ch == '\0' || ch == CR || ch == LF) { + if (ch <= 0x20 || ch == 0x7f) { return NGX_ERROR; } } @@ -3487,6 +3486,8 @@ ngx_http_grpc_parse_rst_stream(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx, return NGX_AGAIN; } + ctx->state = ngx_http_grpc_st_start; + return NGX_OK; } @@ -4340,7 +4341,6 @@ ngx_http_grpc_create_loc_conf(ngx_conf_t *cf) * conf->upstream.ignore_headers = 0; * conf->upstream.next_upstream = 0; * conf->upstream.hide_headers_hash = { NULL, 0 }; - * conf->upstream.ssl_name = NULL; * * conf->headers.lengths = NULL; * conf->headers.values = NULL; @@ -4352,8 +4352,6 @@ ngx_http_grpc_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_certificate = { 0, NULL }; - * conf->ssl_certificate_key = { 0, NULL }; */ conf->upstream.local = NGX_CONF_UNSET_PTR; @@ -4373,10 +4371,13 @@ ngx_http_grpc_create_loc_conf(ngx_conf_t *cf) #if (NGX_HTTP_SSL) conf->upstream.ssl_session_reuse = NGX_CONF_UNSET; + conf->upstream.ssl_name = NGX_CONF_UNSET_PTR; conf->upstream.ssl_server_name = NGX_CONF_UNSET; conf->upstream.ssl_verify = NGX_CONF_UNSET; conf->ssl_verify_depth = NGX_CONF_UNSET_UINT; - conf->ssl_passwords = NGX_CONF_UNSET_PTR; + conf->upstream.ssl_certificate = NGX_CONF_UNSET_PTR; + conf->upstream.ssl_certificate_key = NGX_CONF_UNSET_PTR; + conf->upstream.ssl_passwords = NGX_CONF_UNSET_PTR; conf->ssl_conf_commands = NGX_CONF_UNSET_PTR; #endif @@ -4468,10 +4469,8 @@ ngx_http_grpc_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers, "DEFAULT"); - if (conf->upstream.ssl_name == NULL) { - conf->upstream.ssl_name = prev->upstream.ssl_name; - } - + ngx_conf_merge_ptr_value(conf->upstream.ssl_name, + prev->upstream.ssl_name, NULL); ngx_conf_merge_value(conf->upstream.ssl_server_name, prev->upstream.ssl_server_name, 0); ngx_conf_merge_value(conf->upstream.ssl_verify, @@ -4482,11 +4481,12 @@ ngx_http_grpc_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) prev->ssl_trusted_certificate, ""); ngx_conf_merge_str_value(conf->ssl_crl, prev->ssl_crl, ""); - ngx_conf_merge_str_value(conf->ssl_certificate, - prev->ssl_certificate, ""); - ngx_conf_merge_str_value(conf->ssl_certificate_key, - prev->ssl_certificate_key, ""); - ngx_conf_merge_ptr_value(conf->ssl_passwords, prev->ssl_passwords, NULL); + ngx_conf_merge_ptr_value(conf->upstream.ssl_certificate, + prev->upstream.ssl_certificate, NULL); + ngx_conf_merge_ptr_value(conf->upstream.ssl_certificate_key, + prev->upstream.ssl_certificate_key, NULL); + ngx_conf_merge_ptr_value(conf->upstream.ssl_passwords, + prev->upstream.ssl_passwords, NULL); ngx_conf_merge_ptr_value(conf->ssl_conf_commands, prev->ssl_conf_commands, NULL); @@ -4842,15 +4842,15 @@ ngx_http_grpc_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_str_t *value; - if (glcf->ssl_passwords != NGX_CONF_UNSET_PTR) { + if (glcf->upstream.ssl_passwords != NGX_CONF_UNSET_PTR) { return "is duplicate"; } value = cf->args->elts; - glcf->ssl_passwords = ngx_ssl_read_password_file(cf, &value[1]); + glcf->upstream.ssl_passwords = ngx_ssl_read_password_file(cf, &value[1]); - if (glcf->ssl_passwords == NULL) { + if (glcf->upstream.ssl_passwords == NULL) { return NGX_CONF_ERROR; } @@ -4896,29 +4896,43 @@ ngx_http_grpc_set_ssl(ngx_conf_t *cf, ngx_http_grpc_loc_conf_t *glcf) cln->handler = ngx_ssl_cleanup_ctx; cln->data = glcf->upstream.ssl; - if (glcf->ssl_certificate.len) { - - if (glcf->ssl_certificate_key.len == 0) { - ngx_log_error(NGX_LOG_EMERG, cf->log, 0, - "no \"grpc_ssl_certificate_key\" is defined " - "for certificate \"%V\"", &glcf->ssl_certificate); - return NGX_ERROR; - } - - if (ngx_ssl_certificate(cf, glcf->upstream.ssl, &glcf->ssl_certificate, - &glcf->ssl_certificate_key, glcf->ssl_passwords) - != NGX_OK) - { - return NGX_ERROR; - } - } - if (ngx_ssl_ciphers(cf, glcf->upstream.ssl, &glcf->ssl_ciphers, 0) != NGX_OK) { return NGX_ERROR; } + if (glcf->upstream.ssl_certificate) { + + if (glcf->upstream.ssl_certificate_key == NULL) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "no \"grpc_ssl_certificate_key\" is defined " + "for certificate \"%V\"", + &glcf->upstream.ssl_certificate->value); + return NGX_ERROR; + } + + if (glcf->upstream.ssl_certificate->lengths + || glcf->upstream.ssl_certificate_key->lengths) + { + glcf->upstream.ssl_passwords = + ngx_ssl_preserve_passwords(cf, glcf->upstream.ssl_passwords); + if (glcf->upstream.ssl_passwords == NULL) { + return NGX_ERROR; + } + + } else { + if (ngx_ssl_certificate(cf, glcf->upstream.ssl, + &glcf->upstream.ssl_certificate->value, + &glcf->upstream.ssl_certificate_key->value, + glcf->upstream.ssl_passwords) + != NGX_OK) + { + return NGX_ERROR; + } + } + } + if (glcf->upstream.ssl_verify) { if (glcf->ssl_trusted_certificate.len == 0) { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, diff --git a/src/http/modules/ngx_http_mp4_module.c b/src/http/modules/ngx_http_mp4_module.c index 0e93fbd..9c3f627 100644 --- a/src/http/modules/ngx_http_mp4_module.c +++ b/src/http/modules/ngx_http_mp4_module.c @@ -11,31 +11,33 @@ #define NGX_HTTP_MP4_TRAK_ATOM 0 #define NGX_HTTP_MP4_TKHD_ATOM 1 -#define NGX_HTTP_MP4_MDIA_ATOM 2 -#define NGX_HTTP_MP4_MDHD_ATOM 3 -#define NGX_HTTP_MP4_HDLR_ATOM 4 -#define NGX_HTTP_MP4_MINF_ATOM 5 -#define NGX_HTTP_MP4_VMHD_ATOM 6 -#define NGX_HTTP_MP4_SMHD_ATOM 7 -#define NGX_HTTP_MP4_DINF_ATOM 8 -#define NGX_HTTP_MP4_STBL_ATOM 9 -#define NGX_HTTP_MP4_STSD_ATOM 10 -#define NGX_HTTP_MP4_STTS_ATOM 11 -#define NGX_HTTP_MP4_STTS_DATA 12 -#define NGX_HTTP_MP4_STSS_ATOM 13 -#define NGX_HTTP_MP4_STSS_DATA 14 -#define NGX_HTTP_MP4_CTTS_ATOM 15 -#define NGX_HTTP_MP4_CTTS_DATA 16 -#define NGX_HTTP_MP4_STSC_ATOM 17 -#define NGX_HTTP_MP4_STSC_START 18 -#define NGX_HTTP_MP4_STSC_DATA 19 -#define NGX_HTTP_MP4_STSC_END 20 -#define NGX_HTTP_MP4_STSZ_ATOM 21 -#define NGX_HTTP_MP4_STSZ_DATA 22 -#define NGX_HTTP_MP4_STCO_ATOM 23 -#define NGX_HTTP_MP4_STCO_DATA 24 -#define NGX_HTTP_MP4_CO64_ATOM 25 -#define NGX_HTTP_MP4_CO64_DATA 26 +#define NGX_HTTP_MP4_EDTS_ATOM 2 +#define NGX_HTTP_MP4_ELST_ATOM 3 +#define NGX_HTTP_MP4_MDIA_ATOM 4 +#define NGX_HTTP_MP4_MDHD_ATOM 5 +#define NGX_HTTP_MP4_HDLR_ATOM 6 +#define NGX_HTTP_MP4_MINF_ATOM 7 +#define NGX_HTTP_MP4_VMHD_ATOM 8 +#define NGX_HTTP_MP4_SMHD_ATOM 9 +#define NGX_HTTP_MP4_DINF_ATOM 10 +#define NGX_HTTP_MP4_STBL_ATOM 11 +#define NGX_HTTP_MP4_STSD_ATOM 12 +#define NGX_HTTP_MP4_STTS_ATOM 13 +#define NGX_HTTP_MP4_STTS_DATA 14 +#define NGX_HTTP_MP4_STSS_ATOM 15 +#define NGX_HTTP_MP4_STSS_DATA 16 +#define NGX_HTTP_MP4_CTTS_ATOM 17 +#define NGX_HTTP_MP4_CTTS_DATA 18 +#define NGX_HTTP_MP4_STSC_ATOM 19 +#define NGX_HTTP_MP4_STSC_START 20 +#define NGX_HTTP_MP4_STSC_DATA 21 +#define NGX_HTTP_MP4_STSC_END 22 +#define NGX_HTTP_MP4_STSZ_ATOM 23 +#define NGX_HTTP_MP4_STSZ_DATA 24 +#define NGX_HTTP_MP4_STCO_ATOM 25 +#define NGX_HTTP_MP4_STCO_DATA 26 +#define NGX_HTTP_MP4_CO64_ATOM 27 +#define NGX_HTTP_MP4_CO64_DATA 28 #define NGX_HTTP_MP4_LAST_ATOM NGX_HTTP_MP4_CO64_DATA @@ -43,6 +45,7 @@ typedef struct { size_t buffer_size; size_t max_buffer_size; + ngx_flag_t start_key_frame; } ngx_http_mp4_conf_t; @@ -53,6 +56,25 @@ typedef struct { } ngx_mp4_stsc_entry_t; +typedef struct { + u_char size[4]; + u_char name[4]; +} ngx_mp4_edts_atom_t; + + +typedef struct { + u_char size[4]; + u_char name[4]; + u_char version[1]; + u_char flags[3]; + u_char entries[4]; + u_char duration[8]; + u_char media_time[8]; + u_char media_rate[2]; + u_char reserved[2]; +} ngx_mp4_elst_atom_t; + + typedef struct { uint32_t timescale; uint32_t time_to_sample_entries; @@ -70,6 +92,9 @@ typedef struct { ngx_uint_t end_chunk_samples; uint64_t start_chunk_samples_size; uint64_t end_chunk_samples_size; + uint64_t duration; + uint64_t prefix; + uint64_t movie_duration; off_t start_offset; off_t end_offset; @@ -85,6 +110,8 @@ typedef struct { ngx_buf_t trak_atom_buf; ngx_buf_t tkhd_atom_buf; + ngx_buf_t edts_atom_buf; + ngx_buf_t elst_atom_buf; ngx_buf_t mdia_atom_buf; ngx_buf_t mdhd_atom_buf; ngx_buf_t hdlr_atom_buf; @@ -111,6 +138,8 @@ typedef struct { ngx_buf_t co64_atom_buf; ngx_buf_t co64_data_buf; + ngx_mp4_edts_atom_t edts_atom; + ngx_mp4_elst_atom_t elst_atom; ngx_mp4_stsc_entry_t stsc_start_chunk_entry; ngx_mp4_stsc_entry_t stsc_end_chunk_entry; } ngx_http_mp4_trak_t; @@ -186,6 +215,14 @@ typedef struct { ((u_char *) (p))[6] = n3; \ ((u_char *) (p))[7] = n4 +#define ngx_mp4_get_16value(p) \ + ( ((uint16_t) ((u_char *) (p))[0] << 8) \ + + ( ((u_char *) (p))[1]) ) + +#define ngx_mp4_set_16value(p, n) \ + ((u_char *) (p))[0] = (u_char) ((n) >> 8); \ + ((u_char *) (p))[1] = (u_char) (n) + #define ngx_mp4_get_32value(p) \ ( ((uint32_t) ((u_char *) (p))[0] << 24) \ + ( ((u_char *) (p))[1] << 16) \ @@ -253,6 +290,8 @@ static void ngx_http_mp4_update_mdia_atom(ngx_http_mp4_file_t *mp4, ngx_http_mp4_trak_t *trak); static ngx_int_t ngx_http_mp4_read_mdhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size); +static void ngx_http_mp4_update_mdhd_atom(ngx_http_mp4_file_t *mp4, + ngx_http_mp4_trak_t *trak); static ngx_int_t ngx_http_mp4_read_hdlr_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size); static ngx_int_t ngx_http_mp4_read_minf_atom(ngx_http_mp4_file_t *mp4, @@ -267,6 +306,8 @@ static ngx_int_t ngx_http_mp4_read_smhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size); static ngx_int_t ngx_http_mp4_read_stbl_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size); +static void ngx_http_mp4_update_edts_atom(ngx_http_mp4_file_t *mp4, + ngx_http_mp4_trak_t *trak); static void ngx_http_mp4_update_stbl_atom(ngx_http_mp4_file_t *mp4, ngx_http_mp4_trak_t *trak); static ngx_int_t ngx_http_mp4_read_stsd_atom(ngx_http_mp4_file_t *mp4, @@ -277,6 +318,8 @@ static ngx_int_t ngx_http_mp4_update_stts_atom(ngx_http_mp4_file_t *mp4, ngx_http_mp4_trak_t *trak); static ngx_int_t ngx_http_mp4_crop_stts_data(ngx_http_mp4_file_t *mp4, ngx_http_mp4_trak_t *trak, ngx_uint_t start); +static uint32_t ngx_http_mp4_seek_key_frame(ngx_http_mp4_file_t *mp4, + ngx_http_mp4_trak_t *trak, uint32_t start_sample); static ngx_int_t ngx_http_mp4_read_stss_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size); static ngx_int_t ngx_http_mp4_update_stss_atom(ngx_http_mp4_file_t *mp4, @@ -340,6 +383,13 @@ static ngx_command_t ngx_http_mp4_commands[] = { offsetof(ngx_http_mp4_conf_t, max_buffer_size), NULL }, + { ngx_string("mp4_start_key_frame"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_mp4_conf_t, start_key_frame), + NULL }, + ngx_null_command }; @@ -822,10 +872,11 @@ ngx_http_mp4_process(ngx_http_mp4_file_t *mp4) ngx_http_mp4_update_stbl_atom(mp4, &trak[i]); ngx_http_mp4_update_minf_atom(mp4, &trak[i]); - trak[i].size += trak[i].mdhd_size; + ngx_http_mp4_update_mdhd_atom(mp4, &trak[i]); trak[i].size += trak[i].hdlr_size; ngx_http_mp4_update_mdia_atom(mp4, &trak[i]); trak[i].size += trak[i].tkhd_size; + ngx_http_mp4_update_edts_atom(mp4, &trak[i]); ngx_http_mp4_update_trak_atom(mp4, &trak[i]); mp4->moov_size += trak[i].size; @@ -1587,6 +1638,7 @@ ngx_http_mp4_read_tkhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) trak = ngx_mp4_last_trak(mp4); trak->tkhd_size = atom_size; + trak->movie_duration = duration; ngx_mp4_set_32value(tkhd_atom->size, atom_size); @@ -1749,16 +1801,10 @@ ngx_http_mp4_read_mdhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) trak = ngx_mp4_last_trak(mp4); trak->mdhd_size = atom_size; trak->timescale = timescale; + trak->duration = duration; ngx_mp4_set_32value(mdhd_atom->size, atom_size); - if (mdhd_atom->version[0] == 0) { - ngx_mp4_set_32value(mdhd_atom->duration, duration); - - } else { - ngx_mp4_set_64value(mdhd64_atom->duration, duration); - } - atom = &trak->mdhd_atom_buf; atom->temporary = 1; atom->pos = atom_header; @@ -1772,6 +1818,33 @@ ngx_http_mp4_read_mdhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) } +static void +ngx_http_mp4_update_mdhd_atom(ngx_http_mp4_file_t *mp4, + ngx_http_mp4_trak_t *trak) +{ + ngx_buf_t *atom; + ngx_mp4_mdhd_atom_t *mdhd_atom; + ngx_mp4_mdhd64_atom_t *mdhd64_atom; + + atom = trak->out[NGX_HTTP_MP4_MDHD_ATOM].buf; + if (atom == NULL) { + return; + } + + mdhd_atom = (ngx_mp4_mdhd_atom_t *) atom->pos; + mdhd64_atom = (ngx_mp4_mdhd64_atom_t *) atom->pos; + + if (mdhd_atom->version[0] == 0) { + ngx_mp4_set_32value(mdhd_atom->duration, trak->duration); + + } else { + ngx_mp4_set_64value(mdhd64_atom->duration, trak->duration); + } + + trak->size += trak->mdhd_size; +} + + static ngx_int_t ngx_http_mp4_read_hdlr_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) { @@ -1961,6 +2034,59 @@ ngx_http_mp4_read_stbl_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) } +static void +ngx_http_mp4_update_edts_atom(ngx_http_mp4_file_t *mp4, + ngx_http_mp4_trak_t *trak) +{ + ngx_buf_t *atom; + ngx_mp4_elst_atom_t *elst_atom; + ngx_mp4_edts_atom_t *edts_atom; + + if (trak->prefix == 0) { + return; + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, + "mp4 edts atom update prefix:%uL", trak->prefix); + + edts_atom = &trak->edts_atom; + ngx_mp4_set_32value(edts_atom->size, sizeof(ngx_mp4_edts_atom_t) + + sizeof(ngx_mp4_elst_atom_t)); + ngx_mp4_set_atom_name(edts_atom, 'e', 'd', 't', 's'); + + atom = &trak->edts_atom_buf; + atom->temporary = 1; + atom->pos = (u_char *) edts_atom; + atom->last = (u_char *) edts_atom + sizeof(ngx_mp4_edts_atom_t); + + trak->out[NGX_HTTP_MP4_EDTS_ATOM].buf = atom; + + elst_atom = &trak->elst_atom; + ngx_mp4_set_32value(elst_atom->size, sizeof(ngx_mp4_elst_atom_t)); + ngx_mp4_set_atom_name(elst_atom, 'e', 'l', 's', 't'); + + elst_atom->version[0] = 1; + elst_atom->flags[0] = 0; + elst_atom->flags[1] = 0; + elst_atom->flags[2] = 0; + + ngx_mp4_set_32value(elst_atom->entries, 1); + ngx_mp4_set_64value(elst_atom->duration, trak->movie_duration); + ngx_mp4_set_64value(elst_atom->media_time, trak->prefix); + ngx_mp4_set_16value(elst_atom->media_rate, 1); + ngx_mp4_set_16value(elst_atom->reserved, 0); + + atom = &trak->elst_atom_buf; + atom->temporary = 1; + atom->pos = (u_char *) elst_atom; + atom->last = (u_char *) elst_atom + sizeof(ngx_mp4_elst_atom_t); + + trak->out[NGX_HTTP_MP4_ELST_ATOM].buf = atom; + + trak->size += sizeof(ngx_mp4_edts_atom_t) + sizeof(ngx_mp4_elst_atom_t); +} + + static void ngx_http_mp4_update_stbl_atom(ngx_http_mp4_file_t *mp4, ngx_http_mp4_trak_t *trak) @@ -2159,7 +2285,7 @@ static ngx_int_t ngx_http_mp4_crop_stts_data(ngx_http_mp4_file_t *mp4, ngx_http_mp4_trak_t *trak, ngx_uint_t start) { - uint32_t count, duration, rest; + uint32_t count, duration, rest, key_prefix; uint64_t start_time; ngx_buf_t *data; ngx_uint_t start_sample, entries, start_sec; @@ -2183,7 +2309,7 @@ ngx_http_mp4_crop_stts_data(ngx_http_mp4_file_t *mp4, data = trak->out[NGX_HTTP_MP4_STTS_DATA].buf; - start_time = (uint64_t) start_sec * trak->timescale / 1000; + start_time = (uint64_t) start_sec * trak->timescale / 1000 + trak->prefix; entries = trak->time_to_sample_entries; start_sample = 0; @@ -2229,6 +2355,26 @@ ngx_http_mp4_crop_stts_data(ngx_http_mp4_file_t *mp4, found: if (start) { + key_prefix = ngx_http_mp4_seek_key_frame(mp4, trak, start_sample); + + start_sample -= key_prefix; + + while (rest < key_prefix) { + trak->prefix += rest * duration; + key_prefix -= rest; + + entry--; + entries++; + + count = ngx_mp4_get_32value(entry->count); + duration = ngx_mp4_get_32value(entry->duration); + rest = count; + } + + trak->prefix += key_prefix * duration; + trak->duration += trak->prefix; + rest -= key_prefix; + ngx_mp4_set_32value(entry->count, count - rest); data->pos = (u_char *) entry; trak->time_to_sample_entries = entries; @@ -2253,6 +2399,49 @@ found: } +static uint32_t +ngx_http_mp4_seek_key_frame(ngx_http_mp4_file_t *mp4, ngx_http_mp4_trak_t *trak, + uint32_t start_sample) +{ + uint32_t key_prefix, sample, *entry, *end; + ngx_buf_t *data; + ngx_http_mp4_conf_t *conf; + + conf = ngx_http_get_module_loc_conf(mp4->request, ngx_http_mp4_module); + if (!conf->start_key_frame) { + return 0; + } + + data = trak->out[NGX_HTTP_MP4_STSS_DATA].buf; + if (data == NULL) { + return 0; + } + + entry = (uint32_t *) data->pos; + end = (uint32_t *) data->last; + + /* sync samples starts from 1 */ + start_sample++; + + key_prefix = 0; + + while (entry < end) { + sample = ngx_mp4_get_32value(entry); + if (sample > start_sample) { + break; + } + + key_prefix = start_sample - sample; + entry++; + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, + "mp4 key frame prefix:%uD", key_prefix); + + return key_prefix; +} + + typedef struct { u_char size[4]; u_char name[4]; @@ -3590,6 +3779,7 @@ ngx_http_mp4_create_conf(ngx_conf_t *cf) conf->buffer_size = NGX_CONF_UNSET_SIZE; conf->max_buffer_size = NGX_CONF_UNSET_SIZE; + conf->start_key_frame = NGX_CONF_UNSET; return conf; } @@ -3604,6 +3794,7 @@ ngx_http_mp4_merge_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_size_value(conf->buffer_size, prev->buffer_size, 512 * 1024); ngx_conf_merge_size_value(conf->max_buffer_size, prev->max_buffer_size, 10 * 1024 * 1024); + ngx_conf_merge_value(conf->start_key_frame, prev->start_key_frame, 0); return NGX_CONF_OK; } diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c index a63c3ed..7c4061c 100644 --- a/src/http/modules/ngx_http_proxy_module.c +++ b/src/http/modules/ngx_http_proxy_module.c @@ -124,9 +124,6 @@ typedef struct { ngx_uint_t ssl_verify_depth; ngx_str_t ssl_trusted_certificate; ngx_str_t ssl_crl; - ngx_str_t ssl_certificate; - ngx_str_t ssl_certificate_key; - ngx_array_t *ssl_passwords; ngx_array_t *ssl_conf_commands; #endif } ngx_http_proxy_loc_conf_t; @@ -753,16 +750,16 @@ static ngx_command_t ngx_http_proxy_commands[] = { { ngx_string("proxy_ssl_certificate"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_conf_set_str_slot, + ngx_http_set_complex_value_zero_slot, NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_proxy_loc_conf_t, ssl_certificate), + offsetof(ngx_http_proxy_loc_conf_t, upstream.ssl_certificate), NULL }, { ngx_string("proxy_ssl_certificate_key"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_conf_set_str_slot, + ngx_http_set_complex_value_zero_slot, NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_proxy_loc_conf_t, ssl_certificate_key), + offsetof(ngx_http_proxy_loc_conf_t, upstream.ssl_certificate_key), NULL }, { ngx_string("proxy_ssl_password_file"), @@ -1189,7 +1186,7 @@ ngx_http_proxy_create_key(ngx_http_request_t *r) loc_len = (r->valid_location && ctx->vars.uri.len) ? plcf->location.len : 0; - if (r->quoted_uri || r->space_in_uri || r->internal) { + if (r->quoted_uri || r->internal) { escape = 2 * ngx_escape_uri(NULL, r->uri.data + loc_len, r->uri.len - loc_len, NGX_ESCAPE_URI); } else { @@ -1302,7 +1299,7 @@ ngx_http_proxy_create_request(ngx_http_request_t *r) loc_len = (r->valid_location && ctx->vars.uri.len) ? plcf->location.len : 0; - if (r->quoted_uri || r->space_in_uri || r->internal) { + if (r->quoted_uri || r->internal) { escape = 2 * ngx_escape_uri(NULL, r->uri.data + loc_len, r->uri.len - loc_len, NGX_ESCAPE_URI); } @@ -2022,10 +2019,12 @@ ngx_http_proxy_process_header(ngx_http_request_t *r) return NGX_AGAIN; } - /* there was error while a header line parsing */ + /* rc == NGX_HTTP_PARSE_INVALID_HEADER */ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "upstream sent invalid header"); + "upstream sent invalid header: \"%*s\\x%02xd...\"", + r->header_end - r->header_name_start, + r->header_name_start, *r->header_end); return NGX_HTTP_UPSTREAM_INVALID_HEADER; } @@ -2338,6 +2337,7 @@ ngx_http_proxy_non_buffered_copy_filter(void *data, ssize_t bytes) ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, "upstream sent more data than specified in " "\"Content-Length\" header"); + u->keepalive = 0; return NGX_OK; } @@ -3327,9 +3327,7 @@ ngx_http_proxy_create_loc_conf(ngx_conf_t *cf) * conf->upstream.hide_headers_hash = { NULL, 0 }; * conf->upstream.store_lengths = NULL; * conf->upstream.store_values = NULL; - * conf->upstream.ssl_name = NULL; * - * conf->method = NULL; * conf->location = NULL; * conf->url = { 0, NULL }; * conf->headers.lengths = NULL; @@ -3347,8 +3345,6 @@ ngx_http_proxy_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_certificate = { 0, NULL }; - * conf->ssl_certificate_key = { 0, NULL }; */ conf->upstream.store = NGX_CONF_UNSET; @@ -3400,20 +3396,26 @@ ngx_http_proxy_create_loc_conf(ngx_conf_t *cf) #if (NGX_HTTP_SSL) conf->upstream.ssl_session_reuse = NGX_CONF_UNSET; + conf->upstream.ssl_name = NGX_CONF_UNSET_PTR; conf->upstream.ssl_server_name = NGX_CONF_UNSET; conf->upstream.ssl_verify = NGX_CONF_UNSET; + conf->upstream.ssl_certificate = NGX_CONF_UNSET_PTR; + conf->upstream.ssl_certificate_key = NGX_CONF_UNSET_PTR; + conf->upstream.ssl_passwords = NGX_CONF_UNSET_PTR; conf->ssl_verify_depth = NGX_CONF_UNSET_UINT; - conf->ssl_passwords = NGX_CONF_UNSET_PTR; conf->ssl_conf_commands = NGX_CONF_UNSET_PTR; #endif /* "proxy_cyclic_temp_file" is disabled */ conf->upstream.cyclic_temp_file = 0; + conf->upstream.change_buffering = 1; + conf->headers_source = NGX_CONF_UNSET_PTR; + conf->method = NGX_CONF_UNSET_PTR; + conf->redirect = NGX_CONF_UNSET; - conf->upstream.change_buffering = 1; conf->cookie_domains = NGX_CONF_UNSET_PTR; conf->cookie_paths = NGX_CONF_UNSET_PTR; @@ -3708,10 +3710,6 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) #endif - if (conf->method == NULL) { - conf->method = prev->method; - } - ngx_conf_merge_value(conf->upstream.pass_request_headers, prev->upstream.pass_request_headers, 1); ngx_conf_merge_value(conf->upstream.pass_request_body, @@ -3732,10 +3730,8 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers, "DEFAULT"); - if (conf->upstream.ssl_name == NULL) { - conf->upstream.ssl_name = prev->upstream.ssl_name; - } - + ngx_conf_merge_ptr_value(conf->upstream.ssl_name, + prev->upstream.ssl_name, NULL); ngx_conf_merge_value(conf->upstream.ssl_server_name, prev->upstream.ssl_server_name, 0); ngx_conf_merge_value(conf->upstream.ssl_verify, @@ -3746,11 +3742,12 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) prev->ssl_trusted_certificate, ""); ngx_conf_merge_str_value(conf->ssl_crl, prev->ssl_crl, ""); - ngx_conf_merge_str_value(conf->ssl_certificate, - prev->ssl_certificate, ""); - ngx_conf_merge_str_value(conf->ssl_certificate_key, - prev->ssl_certificate_key, ""); - ngx_conf_merge_ptr_value(conf->ssl_passwords, prev->ssl_passwords, NULL); + ngx_conf_merge_ptr_value(conf->upstream.ssl_certificate, + prev->upstream.ssl_certificate, NULL); + ngx_conf_merge_ptr_value(conf->upstream.ssl_certificate_key, + prev->upstream.ssl_certificate_key, NULL); + ngx_conf_merge_ptr_value(conf->upstream.ssl_passwords, + prev->upstream.ssl_passwords, NULL); ngx_conf_merge_ptr_value(conf->ssl_conf_commands, prev->ssl_conf_commands, NULL); @@ -3761,6 +3758,8 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) #endif + ngx_conf_merge_ptr_value(conf->method, prev->method, NULL); + ngx_conf_merge_value(conf->redirect, prev->redirect, 1); if (conf->redirect) { @@ -4859,15 +4858,15 @@ ngx_http_proxy_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_str_t *value; - if (plcf->ssl_passwords != NGX_CONF_UNSET_PTR) { + if (plcf->upstream.ssl_passwords != NGX_CONF_UNSET_PTR) { return "is duplicate"; } value = cf->args->elts; - plcf->ssl_passwords = ngx_ssl_read_password_file(cf, &value[1]); + plcf->upstream.ssl_passwords = ngx_ssl_read_password_file(cf, &value[1]); - if (plcf->ssl_passwords == NULL) { + if (plcf->upstream.ssl_passwords == NULL) { return NGX_CONF_ERROR; } @@ -4946,29 +4945,43 @@ ngx_http_proxy_set_ssl(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *plcf) cln->handler = ngx_ssl_cleanup_ctx; cln->data = plcf->upstream.ssl; - if (plcf->ssl_certificate.len) { - - if (plcf->ssl_certificate_key.len == 0) { - ngx_log_error(NGX_LOG_EMERG, cf->log, 0, - "no \"proxy_ssl_certificate_key\" is defined " - "for certificate \"%V\"", &plcf->ssl_certificate); - return NGX_ERROR; - } - - if (ngx_ssl_certificate(cf, plcf->upstream.ssl, &plcf->ssl_certificate, - &plcf->ssl_certificate_key, plcf->ssl_passwords) - != NGX_OK) - { - return NGX_ERROR; - } - } - if (ngx_ssl_ciphers(cf, plcf->upstream.ssl, &plcf->ssl_ciphers, 0) != NGX_OK) { return NGX_ERROR; } + if (plcf->upstream.ssl_certificate) { + + if (plcf->upstream.ssl_certificate_key == NULL) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "no \"proxy_ssl_certificate_key\" is defined " + "for certificate \"%V\"", + &plcf->upstream.ssl_certificate->value); + return NGX_ERROR; + } + + if (plcf->upstream.ssl_certificate->lengths + || plcf->upstream.ssl_certificate_key->lengths) + { + plcf->upstream.ssl_passwords = + ngx_ssl_preserve_passwords(cf, plcf->upstream.ssl_passwords); + if (plcf->upstream.ssl_passwords == NULL) { + return NGX_ERROR; + } + + } else { + if (ngx_ssl_certificate(cf, plcf->upstream.ssl, + &plcf->upstream.ssl_certificate->value, + &plcf->upstream.ssl_certificate_key->value, + plcf->upstream.ssl_passwords) + != NGX_OK) + { + return NGX_ERROR; + } + } + } + if (plcf->upstream.ssl_verify) { if (plcf->ssl_trusted_certificate.len == 0) { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, diff --git a/src/http/modules/ngx_http_scgi_module.c b/src/http/modules/ngx_http_scgi_module.c index 600999c..e5d31ae 100644 --- a/src/http/modules/ngx_http_scgi_module.c +++ b/src/http/modules/ngx_http_scgi_module.c @@ -1140,10 +1140,12 @@ ngx_http_scgi_process_header(ngx_http_request_t *r) return NGX_AGAIN; } - /* there was error while a header line parsing */ + /* rc == NGX_HTTP_PARSE_INVALID_HEADER */ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "upstream sent invalid header"); + "upstream sent invalid header: \"%*s\\x%02xd...\"", + r->header_end - r->header_name_start, + r->header_name_start, *r->header_end); return NGX_HTTP_UPSTREAM_INVALID_HEADER; } diff --git a/src/http/modules/ngx_http_secure_link_module.c b/src/http/modules/ngx_http_secure_link_module.c index 536e09a..4d4ce6a 100644 --- a/src/http/modules/ngx_http_secure_link_module.c +++ b/src/http/modules/ngx_http_secure_link_module.c @@ -302,11 +302,12 @@ ngx_http_secure_link_create_conf(ngx_conf_t *cf) /* * set by ngx_pcalloc(): * - * conf->variable = NULL; - * conf->md5 = NULL; * conf->secret = { 0, NULL }; */ + conf->variable = NGX_CONF_UNSET_PTR; + conf->md5 = NGX_CONF_UNSET_PTR; + return conf; } @@ -318,6 +319,9 @@ ngx_http_secure_link_merge_conf(ngx_conf_t *cf, void *parent, void *child) ngx_http_secure_link_conf_t *conf = child; if (conf->secret.data) { + ngx_conf_init_ptr_value(conf->variable, NULL); + ngx_conf_init_ptr_value(conf->md5, NULL); + if (conf->variable || conf->md5) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "\"secure_link_secret\" cannot be mixed with " @@ -328,13 +332,8 @@ ngx_http_secure_link_merge_conf(ngx_conf_t *cf, void *parent, void *child) return NGX_CONF_OK; } - if (conf->variable == NULL) { - conf->variable = prev->variable; - } - - if (conf->md5 == NULL) { - conf->md5 = prev->md5; - } + ngx_conf_merge_ptr_value(conf->variable, prev->variable, NULL); + ngx_conf_merge_ptr_value(conf->md5, prev->md5, NULL); if (conf->variable == NULL && conf->md5 == NULL) { conf->secret = prev->secret; diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c index a47d696..d74d460 100644 --- a/src/http/modules/ngx_http_ssl_module.c +++ b/src/http/modules/ngx_http_ssl_module.c @@ -17,7 +17,7 @@ typedef ngx_int_t (*ngx_ssl_variable_handler_pt)(ngx_connection_t *c, #define NGX_DEFAULT_CIPHERS "HIGH:!aNULL:!MD5" #define NGX_DEFAULT_ECDH_CURVE "auto" -#define NGX_HTTP_NPN_ADVERTISE "\x08http/1.1" +#define NGX_HTTP_ALPN_PROTOS "\x08http/1.1\x08http/1.0\x08http/0.9" #ifdef TLSEXT_TYPE_application_layer_protocol_negotiation @@ -26,11 +26,6 @@ static int ngx_http_ssl_alpn_select(ngx_ssl_conn_t *ssl_conn, const unsigned char *in, unsigned int inlen, void *arg); #endif -#ifdef TLSEXT_TYPE_next_proto_neg -static int ngx_http_ssl_npn_advertised(ngx_ssl_conn_t *ssl_conn, - const unsigned char **out, unsigned int *outlen, void *arg); -#endif - static ngx_int_t ngx_http_ssl_static_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_ssl_variable(ngx_http_request_t *r, @@ -347,6 +342,9 @@ static ngx_http_variable_t ngx_http_ssl_vars[] = { { ngx_string("ssl_ciphers"), NULL, ngx_http_ssl_variable, (uintptr_t) ngx_ssl_get_ciphers, NGX_HTTP_VAR_CHANGEABLE, 0 }, + { ngx_string("ssl_curve"), NULL, ngx_http_ssl_variable, + (uintptr_t) ngx_ssl_get_curve, NGX_HTTP_VAR_CHANGEABLE, 0 }, + { ngx_string("ssl_curves"), NULL, ngx_http_ssl_variable, (uintptr_t) ngx_ssl_get_curves, NGX_HTTP_VAR_CHANGEABLE, 0 }, @@ -363,6 +361,9 @@ static ngx_http_variable_t ngx_http_ssl_vars[] = { { ngx_string("ssl_server_name"), NULL, ngx_http_ssl_variable, (uintptr_t) ngx_ssl_get_server_name, NGX_HTTP_VAR_CHANGEABLE, 0 }, + { ngx_string("ssl_alpn_protocol"), NULL, ngx_http_ssl_variable, + (uintptr_t) ngx_ssl_get_alpn_protocol, NGX_HTTP_VAR_CHANGEABLE, 0 }, + { ngx_string("ssl_client_cert"), NULL, ngx_http_ssl_variable, (uintptr_t) ngx_ssl_get_certificate, NGX_HTTP_VAR_CHANGEABLE, 0 }, @@ -444,22 +445,20 @@ ngx_http_ssl_alpn_select(ngx_ssl_conn_t *ssl_conn, const unsigned char **out, hc = c->data; if (hc->addr_conf->http2) { - srv = - (unsigned char *) NGX_HTTP_V2_ALPN_ADVERTISE NGX_HTTP_NPN_ADVERTISE; - srvlen = sizeof(NGX_HTTP_V2_ALPN_ADVERTISE NGX_HTTP_NPN_ADVERTISE) - 1; - + srv = (unsigned char *) NGX_HTTP_V2_ALPN_PROTO NGX_HTTP_ALPN_PROTOS; + srvlen = sizeof(NGX_HTTP_V2_ALPN_PROTO NGX_HTTP_ALPN_PROTOS) - 1; } else #endif { - srv = (unsigned char *) NGX_HTTP_NPN_ADVERTISE; - srvlen = sizeof(NGX_HTTP_NPN_ADVERTISE) - 1; + srv = (unsigned char *) NGX_HTTP_ALPN_PROTOS; + srvlen = sizeof(NGX_HTTP_ALPN_PROTOS) - 1; } if (SSL_select_next_proto((unsigned char **) out, outlen, srv, srvlen, in, inlen) != OPENSSL_NPN_NEGOTIATED) { - return SSL_TLSEXT_ERR_NOACK; + return SSL_TLSEXT_ERR_ALERT_FATAL; } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, @@ -471,44 +470,6 @@ ngx_http_ssl_alpn_select(ngx_ssl_conn_t *ssl_conn, const unsigned char **out, #endif -#ifdef TLSEXT_TYPE_next_proto_neg - -static int -ngx_http_ssl_npn_advertised(ngx_ssl_conn_t *ssl_conn, - const unsigned char **out, unsigned int *outlen, void *arg) -{ -#if (NGX_HTTP_V2 || NGX_DEBUG) - ngx_connection_t *c; - - c = ngx_ssl_get_connection(ssl_conn); - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "SSL NPN advertised"); -#endif - -#if (NGX_HTTP_V2) - { - ngx_http_connection_t *hc; - - hc = c->data; - - if (hc->addr_conf->http2) { - *out = - (unsigned char *) NGX_HTTP_V2_NPN_ADVERTISE NGX_HTTP_NPN_ADVERTISE; - *outlen = sizeof(NGX_HTTP_V2_NPN_ADVERTISE NGX_HTTP_NPN_ADVERTISE) - 1; - - return SSL_TLSEXT_ERR_OK; - } - } -#endif - - *out = (unsigned char *) NGX_HTTP_NPN_ADVERTISE; - *outlen = sizeof(NGX_HTTP_NPN_ADVERTISE) - 1; - - return SSL_TLSEXT_ERR_OK; -} - -#endif - - static ngx_int_t ngx_http_ssl_static_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) @@ -792,10 +753,12 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) SSL_CTX_set_alpn_select_cb(conf->ssl.ctx, ngx_http_ssl_alpn_select, NULL); #endif -#ifdef TLSEXT_TYPE_next_proto_neg - SSL_CTX_set_next_protos_advertised_cb(conf->ssl.ctx, - ngx_http_ssl_npn_advertised, NULL); -#endif + if (ngx_ssl_ciphers(cf, &conf->ssl, &conf->ciphers, + conf->prefer_server_ciphers) + != NGX_OK) + { + return NGX_CONF_ERROR; + } if (ngx_http_ssl_compile_certificates(cf, conf) != NGX_OK) { return NGX_CONF_ERROR; @@ -829,13 +792,6 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) } } - if (ngx_ssl_ciphers(cf, &conf->ssl, &conf->ciphers, - conf->prefer_server_ciphers) - != NGX_OK) - { - return NGX_CONF_ERROR; - } - conf->ssl.buffer_size = conf->buffer_size; if (conf->verify) { diff --git a/src/http/modules/ngx_http_static_module.c b/src/http/modules/ngx_http_static_module.c index 282d6ee..cf29d5a 100644 --- a/src/http/modules/ngx_http_static_module.c +++ b/src/http/modules/ngx_http_static_module.c @@ -50,6 +50,7 @@ ngx_http_static_handler(ngx_http_request_t *r) { u_char *last, *location; size_t root, len; + uintptr_t escape; ngx_str_t path; ngx_int_t rc; ngx_uint_t level; @@ -155,14 +156,18 @@ ngx_http_static_handler(ngx_http_request_t *r) return NGX_HTTP_INTERNAL_SERVER_ERROR; } - len = r->uri.len + 1; + escape = 2 * ngx_escape_uri(NULL, r->uri.data, r->uri.len, + NGX_ESCAPE_URI); - if (!clcf->alias && r->args.len == 0) { + if (!clcf->alias && r->args.len == 0 && escape == 0) { + len = r->uri.len + 1; location = path.data + root; *last = '/'; } else { + len = r->uri.len + escape + 1; + if (r->args.len) { len += r->args.len + 1; } @@ -173,7 +178,13 @@ ngx_http_static_handler(ngx_http_request_t *r) return NGX_HTTP_INTERNAL_SERVER_ERROR; } - last = ngx_copy(location, r->uri.data, r->uri.len); + if (escape) { + last = (u_char *) ngx_escape_uri(location, r->uri.data, + r->uri.len, NGX_ESCAPE_URI); + + } else { + last = ngx_copy(location, r->uri.data, r->uri.len); + } *last = '/'; diff --git a/src/http/modules/ngx_http_uwsgi_module.c b/src/http/modules/ngx_http_uwsgi_module.c index 1334f44..d46741a 100644 --- a/src/http/modules/ngx_http_uwsgi_module.c +++ b/src/http/modules/ngx_http_uwsgi_module.c @@ -54,9 +54,6 @@ typedef struct { ngx_uint_t ssl_verify_depth; ngx_str_t ssl_trusted_certificate; ngx_str_t ssl_crl; - ngx_str_t ssl_certificate; - ngx_str_t ssl_certificate_key; - ngx_array_t *ssl_passwords; ngx_array_t *ssl_conf_commands; #endif } ngx_http_uwsgi_loc_conf_t; @@ -548,16 +545,16 @@ static ngx_command_t ngx_http_uwsgi_commands[] = { { ngx_string("uwsgi_ssl_certificate"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_conf_set_str_slot, + ngx_http_set_complex_value_zero_slot, NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_uwsgi_loc_conf_t, ssl_certificate), + offsetof(ngx_http_uwsgi_loc_conf_t, upstream.ssl_certificate), NULL }, { ngx_string("uwsgi_ssl_certificate_key"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_conf_set_str_slot, + ngx_http_set_complex_value_zero_slot, NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_uwsgi_loc_conf_t, ssl_certificate_key), + offsetof(ngx_http_uwsgi_loc_conf_t, upstream.ssl_certificate_key), NULL }, { ngx_string("uwsgi_ssl_password_file"), @@ -1364,10 +1361,12 @@ ngx_http_uwsgi_process_header(ngx_http_request_t *r) return NGX_AGAIN; } - /* there was error while a header line parsing */ + /* rc == NGX_HTTP_PARSE_INVALID_HEADER */ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "upstream sent invalid header"); + "upstream sent invalid header: \"%*s\\x%02xd...\"", + r->header_end - r->header_name_start, + r->header_name_start, *r->header_end); return NGX_HTTP_UPSTREAM_INVALID_HEADER; } @@ -1509,10 +1508,13 @@ ngx_http_uwsgi_create_loc_conf(ngx_conf_t *cf) #if (NGX_HTTP_SSL) conf->upstream.ssl_session_reuse = NGX_CONF_UNSET; + conf->upstream.ssl_name = NGX_CONF_UNSET_PTR; conf->upstream.ssl_server_name = NGX_CONF_UNSET; conf->upstream.ssl_verify = NGX_CONF_UNSET; conf->ssl_verify_depth = NGX_CONF_UNSET_UINT; - conf->ssl_passwords = NGX_CONF_UNSET_PTR; + conf->upstream.ssl_certificate = NGX_CONF_UNSET_PTR; + conf->upstream.ssl_certificate_key = NGX_CONF_UNSET_PTR; + conf->upstream.ssl_passwords = NGX_CONF_UNSET_PTR; conf->ssl_conf_commands = NGX_CONF_UNSET_PTR; #endif @@ -1824,10 +1826,8 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers, "DEFAULT"); - if (conf->upstream.ssl_name == NULL) { - conf->upstream.ssl_name = prev->upstream.ssl_name; - } - + ngx_conf_merge_ptr_value(conf->upstream.ssl_name, + prev->upstream.ssl_name, NULL); ngx_conf_merge_value(conf->upstream.ssl_server_name, prev->upstream.ssl_server_name, 0); ngx_conf_merge_value(conf->upstream.ssl_verify, @@ -1838,11 +1838,12 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) prev->ssl_trusted_certificate, ""); ngx_conf_merge_str_value(conf->ssl_crl, prev->ssl_crl, ""); - ngx_conf_merge_str_value(conf->ssl_certificate, - prev->ssl_certificate, ""); - ngx_conf_merge_str_value(conf->ssl_certificate_key, - prev->ssl_certificate_key, ""); - ngx_conf_merge_ptr_value(conf->ssl_passwords, prev->ssl_passwords, NULL); + ngx_conf_merge_ptr_value(conf->upstream.ssl_certificate, + prev->upstream.ssl_certificate, NULL); + ngx_conf_merge_ptr_value(conf->upstream.ssl_certificate_key, + prev->upstream.ssl_certificate_key, NULL); + ngx_conf_merge_ptr_value(conf->upstream.ssl_passwords, + prev->upstream.ssl_passwords, NULL); ngx_conf_merge_ptr_value(conf->ssl_conf_commands, prev->ssl_conf_commands, NULL); @@ -2377,15 +2378,15 @@ ngx_http_uwsgi_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_str_t *value; - if (uwcf->ssl_passwords != NGX_CONF_UNSET_PTR) { + if (uwcf->upstream.ssl_passwords != NGX_CONF_UNSET_PTR) { return "is duplicate"; } value = cf->args->elts; - uwcf->ssl_passwords = ngx_ssl_read_password_file(cf, &value[1]); + uwcf->upstream.ssl_passwords = ngx_ssl_read_password_file(cf, &value[1]); - if (uwcf->ssl_passwords == NULL) { + if (uwcf->upstream.ssl_passwords == NULL) { return NGX_CONF_ERROR; } @@ -2431,29 +2432,43 @@ ngx_http_uwsgi_set_ssl(ngx_conf_t *cf, ngx_http_uwsgi_loc_conf_t *uwcf) cln->handler = ngx_ssl_cleanup_ctx; cln->data = uwcf->upstream.ssl; - if (uwcf->ssl_certificate.len) { - - if (uwcf->ssl_certificate_key.len == 0) { - ngx_log_error(NGX_LOG_EMERG, cf->log, 0, - "no \"uwsgi_ssl_certificate_key\" is defined " - "for certificate \"%V\"", &uwcf->ssl_certificate); - return NGX_ERROR; - } - - if (ngx_ssl_certificate(cf, uwcf->upstream.ssl, &uwcf->ssl_certificate, - &uwcf->ssl_certificate_key, uwcf->ssl_passwords) - != NGX_OK) - { - return NGX_ERROR; - } - } - if (ngx_ssl_ciphers(cf, uwcf->upstream.ssl, &uwcf->ssl_ciphers, 0) != NGX_OK) { return NGX_ERROR; } + if (uwcf->upstream.ssl_certificate) { + + if (uwcf->upstream.ssl_certificate_key == NULL) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "no \"uwsgi_ssl_certificate_key\" is defined " + "for certificate \"%V\"", + &uwcf->upstream.ssl_certificate->value); + return NGX_ERROR; + } + + if (uwcf->upstream.ssl_certificate->lengths + || uwcf->upstream.ssl_certificate_key->lengths) + { + uwcf->upstream.ssl_passwords = + ngx_ssl_preserve_passwords(cf, uwcf->upstream.ssl_passwords); + if (uwcf->upstream.ssl_passwords == NULL) { + return NGX_ERROR; + } + + } else { + if (ngx_ssl_certificate(cf, uwcf->upstream.ssl, + &uwcf->upstream.ssl_certificate->value, + &uwcf->upstream.ssl_certificate_key->value, + uwcf->upstream.ssl_passwords) + != NGX_OK) + { + return NGX_ERROR; + } + } + } + if (uwcf->upstream.ssl_verify) { if (uwcf->ssl_trusted_certificate.len == 0) { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, diff --git a/src/http/ngx_http.c b/src/http/ngx_http.c index e1d3d00..73c08d5 100644 --- a/src/http/ngx_http.c +++ b/src/http/ngx_http.c @@ -37,6 +37,8 @@ static ngx_int_t ngx_http_init_locations(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, ngx_http_core_loc_conf_t *pclcf); static ngx_int_t ngx_http_init_static_location_trees(ngx_conf_t *cf, ngx_http_core_loc_conf_t *pclcf); +static ngx_int_t ngx_http_escape_location_name(ngx_conf_t *cf, + ngx_http_core_loc_conf_t *clcf); static ngx_int_t ngx_http_cmp_locations(const ngx_queue_t *one, const ngx_queue_t *two); static ngx_int_t ngx_http_join_exact_locations(ngx_conf_t *cf, @@ -882,6 +884,41 @@ ngx_http_add_location(ngx_conf_t *cf, ngx_queue_t **locations, ngx_queue_insert_tail(*locations, &lq->queue); + if (ngx_http_escape_location_name(cf, clcf) != NGX_OK) { + return NGX_ERROR; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_escape_location_name(ngx_conf_t *cf, ngx_http_core_loc_conf_t *clcf) +{ + u_char *p; + size_t len; + uintptr_t escape; + + escape = 2 * ngx_escape_uri(NULL, clcf->name.data, clcf->name.len, + NGX_ESCAPE_URI); + + if (escape) { + len = clcf->name.len + escape; + + p = ngx_pnalloc(cf->pool, len); + if (p == NULL) { + return NGX_ERROR; + } + + clcf->escaped_name.len = len; + clcf->escaped_name.data = p; + + ngx_escape_uri(p, clcf->name.data, clcf->name.len, NGX_ESCAPE_URI); + + } else { + clcf->escaped_name = clcf->name; + } + return NGX_OK; } @@ -1301,13 +1338,12 @@ ngx_http_add_address(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, } #if (NGX_HTTP_V2 && NGX_HTTP_SSL \ - && !defined TLSEXT_TYPE_application_layer_protocol_negotiation \ - && !defined TLSEXT_TYPE_next_proto_neg) + && !defined TLSEXT_TYPE_application_layer_protocol_negotiation) if (lsopt->http2 && lsopt->ssl) { ngx_conf_log_error(NGX_LOG_WARN, cf, 0, "nginx was built with OpenSSL that lacks ALPN " - "and NPN support, HTTP/2 is not enabled for %V", + "support, HTTP/2 is not enabled for %V", &lsopt->addr_text); } diff --git a/src/http/ngx_http.h b/src/http/ngx_http.h index 8b43857..be8b7cd 100644 --- a/src/http/ngx_http.h +++ b/src/http/ngx_http.h @@ -167,6 +167,14 @@ ngx_uint_t ngx_http_degraded(ngx_http_request_t *); #endif +#if (NGX_HTTP_V2) +ngx_int_t ngx_http_huff_decode(u_char *state, u_char *src, size_t len, + u_char **dst, ngx_uint_t last, ngx_log_t *log); +size_t ngx_http_huff_encode(u_char *src, size_t len, u_char *dst, + ngx_uint_t lower); +#endif + + extern ngx_module_t ngx_http_module; extern ngx_str_t ngx_http_html_default_types[]; diff --git a/src/http/ngx_http_copy_filter_module.c b/src/http/ngx_http_copy_filter_module.c index c8ad5da..bd3028b 100644 --- a/src/http/ngx_http_copy_filter_module.c +++ b/src/http/ngx_http_copy_filter_module.c @@ -19,10 +19,6 @@ typedef struct { static void ngx_http_copy_aio_handler(ngx_output_chain_ctx_t *ctx, ngx_file_t *file); static void ngx_http_copy_aio_event_handler(ngx_event_t *ev); -#if (NGX_HAVE_AIO_SENDFILE) -static ssize_t ngx_http_copy_aio_sendfile_preload(ngx_buf_t *file); -static void ngx_http_copy_aio_sendfile_event_handler(ngx_event_t *ev); -#endif #endif #if (NGX_THREADS) static ngx_int_t ngx_http_copy_thread_handler(ngx_thread_task_t *task, @@ -128,9 +124,6 @@ ngx_http_copy_filter(ngx_http_request_t *r, ngx_chain_t *in) #if (NGX_HAVE_FILE_AIO) if (ngx_file_aio && clcf->aio == NGX_HTTP_AIO_ON) { ctx->aio_handler = ngx_http_copy_aio_handler; -#if (NGX_HAVE_AIO_SENDFILE) - ctx->aio_preload = ngx_http_copy_aio_sendfile_preload; -#endif } #endif @@ -207,53 +200,6 @@ ngx_http_copy_aio_event_handler(ngx_event_t *ev) ngx_http_run_posted_requests(c); } - -#if (NGX_HAVE_AIO_SENDFILE) - -static ssize_t -ngx_http_copy_aio_sendfile_preload(ngx_buf_t *file) -{ - ssize_t n; - static u_char buf[1]; - ngx_event_aio_t *aio; - ngx_http_request_t *r; - ngx_output_chain_ctx_t *ctx; - - n = ngx_file_aio_read(file->file, buf, 1, file->file_pos, NULL); - - if (n == NGX_AGAIN) { - aio = file->file->aio; - aio->handler = ngx_http_copy_aio_sendfile_event_handler; - - r = aio->data; - r->main->blocked++; - r->aio = 1; - - ctx = ngx_http_get_module_ctx(r, ngx_http_copy_filter_module); - ctx->aio = 1; - } - - return n; -} - - -static void -ngx_http_copy_aio_sendfile_event_handler(ngx_event_t *ev) -{ - ngx_event_aio_t *aio; - ngx_http_request_t *r; - - aio = ev->data; - r = aio->data; - - r->main->blocked--; - r->aio = 0; - ev->complete = 0; - - r->connection->write->handler(r->connection->write); -} - -#endif #endif @@ -263,6 +209,7 @@ static ngx_int_t ngx_http_copy_thread_handler(ngx_thread_task_t *task, ngx_file_t *file) { ngx_str_t name; + ngx_connection_t *c; ngx_thread_pool_t *tp; ngx_http_request_t *r; ngx_output_chain_ctx_t *ctx; @@ -270,6 +217,27 @@ ngx_http_copy_thread_handler(ngx_thread_task_t *task, ngx_file_t *file) r = file->thread_ctx; + if (r->aio) { + /* + * tolerate sendfile() calls if another operation is already + * running; this can happen due to subrequests, multiple calls + * of the next body filter from a filter, or in HTTP/2 due to + * a write event on the main connection + */ + + c = r->connection; + +#if (NGX_HTTP_V2) + if (r->stream) { + c = r->stream->connection->connection; + } +#endif + + if (task == c->sendfile_task) { + return NGX_OK; + } + } + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); tp = clcf->thread_pool; @@ -323,6 +291,20 @@ ngx_http_copy_thread_event_handler(ngx_event_t *ev) r->main->blocked--; r->aio = 0; +#if (NGX_HTTP_V2) + + if (r->stream) { + /* + * for HTTP/2, update write event to make sure processing will + * reach the main connection to handle sendfile() in threads + */ + + c->write->ready = 1; + c->write->active = 0; + } + +#endif + if (r->done) { /* * trigger connection event handler if the subrequest was diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c index 6664fa6..c7463dc 100644 --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -1010,10 +1010,10 @@ ngx_http_core_find_config_phase(ngx_http_request_t *r, ngx_str_set(&r->headers_out.location->key, "Location"); if (r->args.len == 0) { - r->headers_out.location->value = clcf->name; + r->headers_out.location->value = clcf->escaped_name; } else { - len = clcf->name.len + 1 + r->args.len; + len = clcf->escaped_name.len + 1 + r->args.len; p = ngx_pnalloc(r->pool, len); if (p == NULL) { @@ -1025,7 +1025,7 @@ ngx_http_core_find_config_phase(ngx_http_request_t *r, r->headers_out.location->value.len = len; r->headers_out.location->value.data = p; - p = ngx_cpymem(p, clcf->name.data, clcf->name.len); + p = ngx_cpymem(p, clcf->escaped_name.data, clcf->escaped_name.len); *p++ = '?'; ngx_memcpy(p, r->args.data, r->args.len); } @@ -3467,6 +3467,7 @@ ngx_http_core_create_loc_conf(ngx_conf_t *cf) /* * set by ngx_pcalloc(): * + * clcf->escaped_name = { 0, NULL }; * clcf->root = { 0, NULL }; * clcf->limit_except = 0; * clcf->post_action = { 0, NULL }; @@ -3479,8 +3480,6 @@ ngx_http_core_create_loc_conf(ngx_conf_t *cf) * clcf->exact_match = 0; * clcf->auto_redirect = 0; * clcf->alias = 0; - * clcf->limit_rate = NULL; - * clcf->limit_rate_after = NULL; * clcf->gzip_proxied = 0; * clcf->keepalive_disable = 0; */ @@ -3512,6 +3511,8 @@ ngx_http_core_create_loc_conf(ngx_conf_t *cf) clcf->send_timeout = NGX_CONF_UNSET_MSEC; clcf->send_lowat = NGX_CONF_UNSET_SIZE; clcf->postpone_output = NGX_CONF_UNSET_SIZE; + clcf->limit_rate = NGX_CONF_UNSET_PTR; + clcf->limit_rate_after = NGX_CONF_UNSET_PTR; clcf->keepalive_time = NGX_CONF_UNSET_MSEC; clcf->keepalive_timeout = NGX_CONF_UNSET_MSEC; clcf->keepalive_header = NGX_CONF_UNSET; @@ -3719,7 +3720,7 @@ ngx_http_core_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_value(conf->internal, prev->internal, 0); ngx_conf_merge_value(conf->sendfile, prev->sendfile, 0); ngx_conf_merge_size_value(conf->sendfile_max_chunk, - prev->sendfile_max_chunk, 0); + prev->sendfile_max_chunk, 2 * 1024 * 1024); ngx_conf_merge_size_value(conf->subrequest_output_buffer_size, prev->subrequest_output_buffer_size, (size_t) ngx_pagesize); @@ -3743,13 +3744,9 @@ ngx_http_core_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_size_value(conf->postpone_output, prev->postpone_output, 1460); - if (conf->limit_rate == NULL) { - conf->limit_rate = prev->limit_rate; - } - - if (conf->limit_rate_after == NULL) { - conf->limit_rate_after = prev->limit_rate_after; - } + ngx_conf_merge_ptr_value(conf->limit_rate, prev->limit_rate, NULL); + ngx_conf_merge_ptr_value(conf->limit_rate_after, + prev->limit_rate_after, NULL); ngx_conf_merge_msec_value(conf->keepalive_time, prev->keepalive_time, 3600000); @@ -4571,19 +4568,6 @@ ngx_http_core_set_aio(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) #endif } -#if (NGX_HAVE_AIO_SENDFILE) - - if (ngx_strcmp(value[1].data, "sendfile") == 0) { - clcf->aio = NGX_HTTP_AIO_ON; - - ngx_conf_log_error(NGX_LOG_WARN, cf, 0, - "the \"sendfile\" parameter of " - "the \"aio\" directive is deprecated"); - return NGX_CONF_OK; - } - -#endif - if (ngx_strncmp(value[1].data, "threads", 7) == 0 && (value[1].len == 7 || value[1].data[7] == '=')) { diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h index 2341fd4..004a98e 100644 --- a/src/http/ngx_http_core_module.h +++ b/src/http/ngx_http_core_module.h @@ -299,6 +299,7 @@ typedef struct { struct ngx_http_core_loc_conf_s { ngx_str_t name; /* location name */ + ngx_str_t escaped_name; #if (NGX_PCRE) ngx_http_regex_t *regex; @@ -501,8 +502,8 @@ ngx_int_t ngx_http_gzip_ok(ngx_http_request_t *r); ngx_int_t ngx_http_subrequest(ngx_http_request_t *r, - ngx_str_t *uri, ngx_str_t *args, ngx_http_request_t **sr, - ngx_http_post_subrequest_t *psr, ngx_uint_t flags); + ngx_str_t *uri, ngx_str_t *args, ngx_http_request_t **psr, + ngx_http_post_subrequest_t *ps, ngx_uint_t flags); ngx_int_t ngx_http_internal_redirect(ngx_http_request_t *r, ngx_str_t *uri, ngx_str_t *args); ngx_int_t ngx_http_named_location(ngx_http_request_t *r, ngx_str_t *name); diff --git a/src/http/ngx_http_header_filter_module.c b/src/http/ngx_http_header_filter_module.c index 9b89405..76f6e96 100644 --- a/src/http/ngx_http_header_filter_module.c +++ b/src/http/ngx_http_header_filter_module.c @@ -197,6 +197,10 @@ ngx_http_header_filter(ngx_http_request_t *r) } } + if (r->keepalive && (ngx_terminate || ngx_exiting)) { + r->keepalive = 0; + } + len = sizeof("HTTP/1.x ") - 1 + sizeof(CRLF) - 1 /* the end of the header */ + sizeof(CRLF) - 1; diff --git a/src/http/v2/ngx_http_v2_huff_decode.c b/src/http/ngx_http_huff_decode.c similarity index 99% rename from src/http/v2/ngx_http_v2_huff_decode.c rename to src/http/ngx_http_huff_decode.c index 49ca576..14b7b78 100644 --- a/src/http/v2/ngx_http_v2_huff_decode.c +++ b/src/http/ngx_http_huff_decode.c @@ -15,14 +15,14 @@ typedef struct { u_char emit; u_char sym; u_char ending; -} ngx_http_v2_huff_decode_code_t; +} ngx_http_huff_decode_code_t; -static ngx_inline ngx_int_t ngx_http_v2_huff_decode_bits(u_char *state, +static ngx_inline ngx_int_t ngx_http_huff_decode_bits(u_char *state, u_char *ending, ngx_uint_t bits, u_char **dst); -static ngx_http_v2_huff_decode_code_t ngx_http_v2_huff_decode_codes[256][16] = +static ngx_http_huff_decode_code_t ngx_http_huff_decode_codes[256][16] = { /* 0 */ { @@ -2640,7 +2640,7 @@ static ngx_http_v2_huff_decode_code_t ngx_http_v2_huff_decode_codes[256][16] = ngx_int_t -ngx_http_v2_huff_decode(u_char *state, u_char *src, size_t len, u_char **dst, +ngx_http_huff_decode(u_char *state, u_char *src, size_t len, u_char **dst, ngx_uint_t last, ngx_log_t *log) { u_char *end, ch, ending; @@ -2653,7 +2653,7 @@ ngx_http_v2_huff_decode(u_char *state, u_char *src, size_t len, u_char **dst, while (src != end) { ch = *src++; - if (ngx_http_v2_huff_decode_bits(state, &ending, ch >> 4, dst) + if (ngx_http_huff_decode_bits(state, &ending, ch >> 4, dst) != NGX_OK) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, log, 0, @@ -2663,7 +2663,7 @@ ngx_http_v2_huff_decode(u_char *state, u_char *src, size_t len, u_char **dst, return NGX_ERROR; } - if (ngx_http_v2_huff_decode_bits(state, &ending, ch & 0xf, dst) + if (ngx_http_huff_decode_bits(state, &ending, ch & 0xf, dst) != NGX_OK) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, log, 0, @@ -2692,12 +2692,12 @@ ngx_http_v2_huff_decode(u_char *state, u_char *src, size_t len, u_char **dst, static ngx_inline ngx_int_t -ngx_http_v2_huff_decode_bits(u_char *state, u_char *ending, ngx_uint_t bits, +ngx_http_huff_decode_bits(u_char *state, u_char *ending, ngx_uint_t bits, u_char **dst) { - ngx_http_v2_huff_decode_code_t code; + ngx_http_huff_decode_code_t code; - code = ngx_http_v2_huff_decode_codes[*state][bits]; + code = ngx_http_huff_decode_codes[*state][bits]; if (code.next == *state) { return NGX_ERROR; diff --git a/src/http/v2/ngx_http_v2_huff_encode.c b/src/http/ngx_http_huff_encode.c similarity index 93% rename from src/http/v2/ngx_http_v2_huff_encode.c rename to src/http/ngx_http_huff_encode.c index 3f822cd..c03b153 100644 --- a/src/http/v2/ngx_http_v2_huff_encode.c +++ b/src/http/ngx_http_huff_encode.c @@ -14,10 +14,10 @@ typedef struct { uint32_t code; uint32_t len; -} ngx_http_v2_huff_encode_code_t; +} ngx_http_huff_encode_code_t; -static ngx_http_v2_huff_encode_code_t ngx_http_v2_huff_encode_table[256] = +static ngx_http_huff_encode_code_t ngx_http_huff_encode_table[256] = { {0x00001ff8, 13}, {0x007fffd8, 23}, {0x0fffffe2, 28}, {0x0fffffe3, 28}, {0x0fffffe4, 28}, {0x0fffffe5, 28}, {0x0fffffe6, 28}, {0x0fffffe7, 28}, @@ -87,7 +87,7 @@ static ngx_http_v2_huff_encode_code_t ngx_http_v2_huff_encode_table[256] = /* same as above, but embeds lowercase transformation */ -static ngx_http_v2_huff_encode_code_t ngx_http_v2_huff_encode_table_lc[256] = +static ngx_http_huff_encode_code_t ngx_http_huff_encode_table_lc[256] = { {0x00001ff8, 13}, {0x007fffd8, 23}, {0x0fffffe2, 28}, {0x0fffffe3, 28}, {0x0fffffe4, 28}, {0x0fffffe5, 28}, {0x0fffffe6, 28}, {0x0fffffe7, 28}, @@ -161,10 +161,10 @@ static ngx_http_v2_huff_encode_code_t ngx_http_v2_huff_encode_table_lc[256] = #if (NGX_HAVE_LITTLE_ENDIAN) #if (NGX_HAVE_GCC_BSWAP64) -#define ngx_http_v2_huff_encode_buf(dst, buf) \ +#define ngx_http_huff_encode_buf(dst, buf) \ (*(uint64_t *) (dst) = __builtin_bswap64(buf)) #else -#define ngx_http_v2_huff_encode_buf(dst, buf) \ +#define ngx_http_huff_encode_buf(dst, buf) \ ((dst)[0] = (u_char) ((buf) >> 56), \ (dst)[1] = (u_char) ((buf) >> 48), \ (dst)[2] = (u_char) ((buf) >> 40), \ @@ -176,28 +176,28 @@ static ngx_http_v2_huff_encode_code_t ngx_http_v2_huff_encode_table_lc[256] = #endif #else /* !NGX_HAVE_LITTLE_ENDIAN */ -#define ngx_http_v2_huff_encode_buf(dst, buf) \ +#define ngx_http_huff_encode_buf(dst, buf) \ (*(uint64_t *) (dst) = (buf)) #endif #else /* NGX_PTR_SIZE == 4 */ -#define ngx_http_v2_huff_encode_buf(dst, buf) \ +#define ngx_http_huff_encode_buf(dst, buf) \ (*(uint32_t *) (dst) = htonl(buf)) #endif size_t -ngx_http_v2_huff_encode(u_char *src, size_t len, u_char *dst, ngx_uint_t lower) +ngx_http_huff_encode(u_char *src, size_t len, u_char *dst, ngx_uint_t lower) { - u_char *end; - size_t hlen; - ngx_uint_t buf, pending, code; - ngx_http_v2_huff_encode_code_t *table, *next; + u_char *end; + size_t hlen; + ngx_uint_t buf, pending, code; + ngx_http_huff_encode_code_t *table, *next; - table = lower ? ngx_http_v2_huff_encode_table_lc - : ngx_http_v2_huff_encode_table; + table = lower ? ngx_http_huff_encode_table_lc + : ngx_http_huff_encode_table; hlen = 0; buf = 0; pending = 0; @@ -224,7 +224,7 @@ ngx_http_v2_huff_encode(u_char *src, size_t len, u_char *dst, ngx_uint_t lower) buf |= code >> pending; - ngx_http_v2_huff_encode_buf(&dst[hlen], buf); + ngx_http_huff_encode_buf(&dst[hlen], buf); hlen += sizeof(buf); diff --git a/src/http/ngx_http_parse.c b/src/http/ngx_http_parse.c index 20ad89a..6460da2 100644 --- a/src/http/ngx_http_parse.c +++ b/src/http/ngx_http_parse.c @@ -11,7 +11,7 @@ static uint32_t usual[] = { - 0xffffdbfe, /* 1111 1111 1111 1111 1101 1011 1111 1110 */ + 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */ 0x7fff37d6, /* 0111 1111 1111 1111 0011 0111 1101 0110 */ @@ -24,7 +24,7 @@ static uint32_t usual[] = { #endif /* ~}| {zyx wvut srqp onml kjih gfed cba` */ - 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + 0x7fffffff, /* 0111 1111 1111 1111 1111 1111 1111 1111 */ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ @@ -116,10 +116,8 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) sw_host_end, sw_host_ip_literal, sw_port, - sw_host_http_09, sw_after_slash_in_uri, sw_check_uri, - sw_check_uri_http_09, sw_uri, sw_http_09, sw_http_H, @@ -246,6 +244,11 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) r->method = NGX_HTTP_OPTIONS; } + if (ngx_str7_cmp(m, 'C', 'O', 'N', 'N', 'E', 'C', 'T', ' ')) + { + r->method = NGX_HTTP_CONNECT; + } + break; case 8: @@ -393,7 +396,7 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) */ r->uri_start = r->schema_end + 1; r->uri_end = r->schema_end + 2; - state = sw_host_http_09; + state = sw_http_09; break; default: return NGX_HTTP_PARSE_INVALID_REQUEST; @@ -467,35 +470,13 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) */ r->uri_start = r->schema_end + 1; r->uri_end = r->schema_end + 2; - state = sw_host_http_09; + state = sw_http_09; break; default: return NGX_HTTP_PARSE_INVALID_REQUEST; } break; - /* space+ after "http://host[:port] " */ - case sw_host_http_09: - switch (ch) { - case ' ': - break; - case CR: - r->http_minor = 9; - state = sw_almost_done; - break; - case LF: - r->http_minor = 9; - goto done; - case 'H': - r->http_protocol.data = p; - state = sw_http_H; - break; - default: - return NGX_HTTP_PARSE_INVALID_REQUEST; - } - break; - - /* check "/.", "//", "%", and "\" (Win32) in URI */ case sw_after_slash_in_uri: @@ -507,7 +488,7 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) switch (ch) { case ' ': r->uri_end = p; - state = sw_check_uri_http_09; + state = sw_http_09; break; case CR: r->uri_end = p; @@ -547,9 +528,10 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) case '+': r->plus_in_uri = 1; break; - case '\0': - return NGX_HTTP_PARSE_INVALID_REQUEST; default: + if (ch < 0x20 || ch == 0x7f) { + return NGX_HTTP_PARSE_INVALID_REQUEST; + } state = sw_check_uri; break; } @@ -579,7 +561,7 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) break; case ' ': r->uri_end = p; - state = sw_check_uri_http_09; + state = sw_http_09; break; case CR: r->uri_end = p; @@ -611,36 +593,14 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) case '+': r->plus_in_uri = 1; break; - case '\0': - return NGX_HTTP_PARSE_INVALID_REQUEST; - } - break; - - /* space+ after URI */ - case sw_check_uri_http_09: - switch (ch) { - case ' ': - break; - case CR: - r->http_minor = 9; - state = sw_almost_done; - break; - case LF: - r->http_minor = 9; - goto done; - case 'H': - r->http_protocol.data = p; - state = sw_http_H; - break; default: - r->space_in_uri = 1; - state = sw_check_uri; - p--; + if (ch < 0x20 || ch == 0x7f) { + return NGX_HTTP_PARSE_INVALID_REQUEST; + } break; } break; - /* URI */ case sw_uri: @@ -665,8 +625,11 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) case '#': r->complex_uri = 1; break; - case '\0': - return NGX_HTTP_PARSE_INVALID_REQUEST; + default: + if (ch < 0x20 || ch == 0x7f) { + return NGX_HTTP_PARSE_INVALID_REQUEST; + } + break; } break; @@ -687,10 +650,7 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) state = sw_http_H; break; default: - r->space_in_uri = 1; - state = sw_uri; - p--; - break; + return NGX_HTTP_PARSE_INVALID_REQUEST; } break; @@ -933,7 +893,8 @@ ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b, break; } - if (ch == '\0') { + if (ch <= 0x20 || ch == 0x7f || ch == ':') { + r->header_end = p; return NGX_HTTP_PARSE_INVALID_HEADER; } @@ -1001,7 +962,8 @@ ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b, break; } - if (ch == '\0') { + if (ch <= 0x20 || ch == 0x7f) { + r->header_end = p; return NGX_HTTP_PARSE_INVALID_HEADER; } @@ -1024,6 +986,7 @@ ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b, r->header_end = p; goto done; case '\0': + r->header_end = p; return NGX_HTTP_PARSE_INVALID_HEADER; default: r->header_start = p; @@ -1047,6 +1010,7 @@ ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b, r->header_end = p; goto done; case '\0': + r->header_end = p; return NGX_HTTP_PARSE_INVALID_HEADER; } break; @@ -1062,6 +1026,7 @@ ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b, case LF: goto done; case '\0': + r->header_end = p; return NGX_HTTP_PARSE_INVALID_HEADER; default: state = sw_value; @@ -1165,10 +1130,6 @@ ngx_http_parse_uri(ngx_http_request_t *r) } switch (ch) { - case ' ': - r->space_in_uri = 1; - state = sw_check_uri; - break; case '.': r->complex_uri = 1; state = sw_uri; @@ -1199,6 +1160,9 @@ ngx_http_parse_uri(ngx_http_request_t *r) r->plus_in_uri = 1; break; default: + if (ch <= 0x20 || ch == 0x7f) { + return NGX_ERROR; + } state = sw_check_uri; break; } @@ -1226,9 +1190,6 @@ ngx_http_parse_uri(ngx_http_request_t *r) case '.': r->uri_ext = p + 1; break; - case ' ': - r->space_in_uri = 1; - break; #if (NGX_WIN32) case '\\': r->complex_uri = 1; @@ -1250,6 +1211,11 @@ ngx_http_parse_uri(ngx_http_request_t *r) case '+': r->plus_in_uri = 1; break; + default: + if (ch <= 0x20 || ch == 0x7f) { + return NGX_ERROR; + } + break; } break; @@ -1261,12 +1227,14 @@ ngx_http_parse_uri(ngx_http_request_t *r) } switch (ch) { - case ' ': - r->space_in_uri = 1; - break; case '#': r->complex_uri = 1; break; + default: + if (ch <= 0x20 || ch == 0x7f) { + return NGX_ERROR; + } + break; } break; } diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 136c461..013b715 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -607,7 +607,7 @@ ngx_http_alloc_request(ngx_connection_t *c) } #if (NGX_HTTP_SSL) - if (c->ssl) { + if (c->ssl && !c->ssl->sendfile) { r->main_filter_need_in_memory = 1; } #endif @@ -806,8 +806,7 @@ ngx_http_ssl_handshake_handler(ngx_connection_t *c) c->ssl->no_wait_shutdown = 1; #if (NGX_HTTP_V2 \ - && (defined TLSEXT_TYPE_application_layer_protocol_negotiation \ - || defined TLSEXT_TYPE_next_proto_neg)) + && defined TLSEXT_TYPE_application_layer_protocol_negotiation) { unsigned int len; const unsigned char *data; @@ -817,19 +816,8 @@ ngx_http_ssl_handshake_handler(ngx_connection_t *c) if (hc->addr_conf->http2) { -#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation SSL_get0_alpn_selected(c->ssl->connection, &data, &len); -#ifdef TLSEXT_TYPE_next_proto_neg - if (len == 0) { - SSL_get0_next_proto_negotiated(c->ssl->connection, &data, &len); - } -#endif - -#else /* TLSEXT_TYPE_next_proto_neg */ - SSL_get0_next_proto_negotiated(c->ssl->connection, &data, &len); -#endif - if (len == 2 && data[0] == 'h' && data[1] == '2') { ngx_http_v2_init(c->read); return; @@ -1043,12 +1031,14 @@ ngx_http_ssl_certificate(ngx_ssl_conn_t *ssl_conn, void *arg) } ngx_http_free_request(r, 0); + c->log->action = "SSL handshaking"; c->destroyed = 0; return 1; failed: ngx_http_free_request(r, 0); + c->log->action = "SSL handshaking"; c->destroyed = 0; return 0; } @@ -1262,7 +1252,7 @@ ngx_http_process_request_uri(ngx_http_request_t *r) r->unparsed_uri.len = r->uri_end - r->uri_start; r->unparsed_uri.data = r->uri_start; - r->valid_unparsed_uri = (r->space_in_uri || r->empty_path_in_uri) ? 0 : 1; + r->valid_unparsed_uri = r->empty_path_in_uri ? 0 : 1; if (r->uri_ext) { if (r->args_start) { @@ -1520,7 +1510,9 @@ ngx_http_process_request_headers(ngx_event_t *rev) /* rc == NGX_HTTP_PARSE_INVALID_HEADER */ ngx_log_error(NGX_LOG_INFO, c->log, 0, - "client sent invalid header line"); + "client sent invalid header line: \"%*s\\x%02xd...\"", + r->header_end - r->header_name_start, + r->header_name_start, *r->header_end); ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); break; @@ -1978,20 +1970,28 @@ ngx_http_process_request_header(ngx_http_request_t *r) } } - if (r->method == NGX_HTTP_TRACE) { - ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, - "client sent TRACE method"); - ngx_http_finalize_request(r, NGX_HTTP_NOT_ALLOWED); - return NGX_ERROR; - } - if (r->headers_in.transfer_encoding) { + if (r->http_version < NGX_HTTP_VERSION_11) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent HTTP/1.0 request with " + "\"Transfer-Encoding\" header"); + ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); + return NGX_ERROR; + } + if (r->headers_in.transfer_encoding->value.len == 7 && ngx_strncasecmp(r->headers_in.transfer_encoding->value.data, (u_char *) "chunked", 7) == 0) { - r->headers_in.content_length = NULL; - r->headers_in.content_length_n = -1; + if (r->headers_in.content_length) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent \"Content-Length\" and " + "\"Transfer-Encoding\" headers " + "at the same time"); + ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); + return NGX_ERROR; + } + r->headers_in.chunked = 1; } else { @@ -2011,6 +2011,20 @@ ngx_http_process_request_header(ngx_http_request_t *r) } } + if (r->method == NGX_HTTP_CONNECT) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent CONNECT method"); + ngx_http_finalize_request(r, NGX_HTTP_NOT_ALLOWED); + return NGX_ERROR; + } + + if (r->method == NGX_HTTP_TRACE) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent TRACE method"); + ngx_http_finalize_request(r, NGX_HTTP_NOT_ALLOWED); + return NGX_ERROR; + } + return NGX_OK; } @@ -2158,15 +2172,16 @@ ngx_http_validate_host(ngx_str_t *host, ngx_pool_t *pool, ngx_uint_t alloc) } break; - case '\0': - return NGX_DECLINED; - default: if (ngx_path_separator(ch)) { return NGX_DECLINED; } + if (ch <= 0x20 || ch == 0x7f) { + return NGX_DECLINED; + } + if (ch >= 'A' && ch <= 'Z') { alloc = 1; } diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h index 6dfb4a4..b1269d2 100644 --- a/src/http/ngx_http_request.h +++ b/src/http/ngx_http_request.h @@ -25,22 +25,23 @@ #define NGX_HTTP_VERSION_11 1001 #define NGX_HTTP_VERSION_20 2000 -#define NGX_HTTP_UNKNOWN 0x0001 -#define NGX_HTTP_GET 0x0002 -#define NGX_HTTP_HEAD 0x0004 -#define NGX_HTTP_POST 0x0008 -#define NGX_HTTP_PUT 0x0010 -#define NGX_HTTP_DELETE 0x0020 -#define NGX_HTTP_MKCOL 0x0040 -#define NGX_HTTP_COPY 0x0080 -#define NGX_HTTP_MOVE 0x0100 -#define NGX_HTTP_OPTIONS 0x0200 -#define NGX_HTTP_PROPFIND 0x0400 -#define NGX_HTTP_PROPPATCH 0x0800 -#define NGX_HTTP_LOCK 0x1000 -#define NGX_HTTP_UNLOCK 0x2000 -#define NGX_HTTP_PATCH 0x4000 -#define NGX_HTTP_TRACE 0x8000 +#define NGX_HTTP_UNKNOWN 0x00000001 +#define NGX_HTTP_GET 0x00000002 +#define NGX_HTTP_HEAD 0x00000004 +#define NGX_HTTP_POST 0x00000008 +#define NGX_HTTP_PUT 0x00000010 +#define NGX_HTTP_DELETE 0x00000020 +#define NGX_HTTP_MKCOL 0x00000040 +#define NGX_HTTP_COPY 0x00000080 +#define NGX_HTTP_MOVE 0x00000100 +#define NGX_HTTP_OPTIONS 0x00000200 +#define NGX_HTTP_PROPFIND 0x00000400 +#define NGX_HTTP_PROPPATCH 0x00000800 +#define NGX_HTTP_LOCK 0x00001000 +#define NGX_HTTP_UNLOCK 0x00002000 +#define NGX_HTTP_PATCH 0x00004000 +#define NGX_HTTP_TRACE 0x00008000 +#define NGX_HTTP_CONNECT 0x00010000 #define NGX_HTTP_CONNECTION_CLOSE 1 #define NGX_HTTP_CONNECTION_KEEP_ALIVE 2 @@ -301,6 +302,9 @@ typedef struct { ngx_chain_t *busy; ngx_http_chunked_t *chunked; ngx_http_client_body_handler_pt post_handler; + unsigned filter_need_buffering:1; + unsigned last_sent:1; + unsigned last_saved:1; } ngx_http_request_body_t; @@ -467,9 +471,6 @@ struct ngx_http_request_s { /* URI with "+" */ unsigned plus_in_uri:1; - /* URI with " " */ - unsigned space_in_uri:1; - /* URI with empty path */ unsigned empty_path_in_uri:1; diff --git a/src/http/ngx_http_request_body.c b/src/http/ngx_http_request_body.c index 0cae88f..ad3549f 100644 --- a/src/http/ngx_http_request_body.c +++ b/src/http/ngx_http_request_body.c @@ -62,11 +62,16 @@ ngx_http_read_client_request_body(ngx_http_request_t *r, /* * set by ngx_pcalloc(): * + * rb->temp_file = NULL; * rb->bufs = NULL; * rb->buf = NULL; * rb->free = NULL; * rb->busy = NULL; * rb->chunked = NULL; + * rb->received = 0; + * rb->filter_need_buffering = 0; + * rb->last_sent = 0; + * rb->last_saved = 0; */ rb->rest = -1; @@ -144,7 +149,7 @@ ngx_http_read_client_request_body(ngx_http_request_t *r, } } - if (rb->rest == 0) { + if (rb->rest == 0 && rb->last_saved) { /* the whole request body was pre-read */ r->request_body_no_buffering = 0; post_handler(r); @@ -172,6 +177,10 @@ ngx_http_read_client_request_body(ngx_http_request_t *r, size += preread; } + if (size == 0) { + size++; + } + } else { size = clcf->client_body_buffer_size; } @@ -270,6 +279,7 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r) size_t size; ssize_t n; ngx_int_t rc; + ngx_uint_t flush; ngx_chain_t out; ngx_connection_t *c; ngx_http_request_body_t *rb; @@ -277,12 +287,17 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r) c = r->connection; rb = r->request_body; + flush = 1; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http read client request body"); for ( ;; ) { for ( ;; ) { + if (rb->rest == 0) { + break; + } + if (rb->buf->last == rb->buf->end) { /* update chains */ @@ -306,12 +321,25 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r) return NGX_AGAIN; } + if (rb->filter_need_buffering) { + clcf = ngx_http_get_module_loc_conf(r, + ngx_http_core_module); + ngx_add_timer(c->read, clcf->client_body_timeout); + + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + return NGX_AGAIN; + } + ngx_log_error(NGX_LOG_ALERT, c->log, 0, "busy buffers after request body flush"); return NGX_HTTP_INTERNAL_SERVER_ERROR; } + flush = 0; rb->buf->pos = rb->buf->start; rb->buf->last = rb->buf->start; } @@ -323,6 +351,10 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r) size = (size_t) rest; } + if (size == 0) { + break; + } + n = c->recv(c, rb->buf->last, size); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, @@ -347,6 +379,7 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r) /* pass buffer to request body filter chain */ + flush = 0; out.buf = rb->buf; out.next = NULL; @@ -368,11 +401,19 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r) ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http client request body rest %O", rb->rest); - if (rb->rest == 0) { + if (flush) { + rc = ngx_http_request_body_filter(r, NULL); + + if (rc != NGX_OK) { + return rc; + } + } + + if (rb->rest == 0 && rb->last_saved) { break; } - if (!c->read->ready) { + if (!c->read->ready || rb->rest == 0) { clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); ngx_add_timer(c->read, clcf->client_body_timeout); @@ -939,15 +980,32 @@ ngx_http_request_body_length_filter(ngx_http_request_t *r, ngx_chain_t *in) rb = r->request_body; + out = NULL; + ll = &out; + if (rb->rest == -1) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http request body content length filter"); rb->rest = r->headers_in.content_length_n; - } - out = NULL; - ll = &out; + if (rb->rest == 0) { + + tl = ngx_chain_get_free_buf(r->pool, &rb->free); + if (tl == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + b = tl->buf; + + ngx_memzero(b, sizeof(ngx_buf_t)); + + b->last_buf = 1; + + *ll = tl; + ll = &tl->next; + } + } for (cl = in; cl; cl = cl->next) { @@ -1011,6 +1069,9 @@ ngx_http_request_body_chunked_filter(ngx_http_request_t *r, ngx_chain_t *in) rb = r->request_body; + out = NULL; + ll = &out; + if (rb->rest == -1) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, @@ -1027,9 +1088,6 @@ ngx_http_request_body_chunked_filter(ngx_http_request_t *r, ngx_chain_t *in) rb->rest = cscf->large_client_header_buffers.size; } - out = NULL; - ll = &out; - for (cl = in; cl; cl = cl->next) { b = NULL; @@ -1186,15 +1244,16 @@ ngx_int_t ngx_http_request_body_save_filter(ngx_http_request_t *r, ngx_chain_t *in) { ngx_buf_t *b; - ngx_chain_t *cl; + ngx_chain_t *cl, *tl, **ll; ngx_http_request_body_t *rb; rb = r->request_body; -#if (NGX_DEBUG) + ll = &rb->bufs; + + for (cl = rb->bufs; cl; cl = cl->next) { #if 0 - for (cl = rb->bufs; cl; cl = cl->next) { ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0, "http body old buf t:%d f:%d %p, pos %p, size: %z " "file: %O, size: %O", @@ -1203,10 +1262,13 @@ ngx_http_request_body_save_filter(ngx_http_request_t *r, ngx_chain_t *in) cl->buf->last - cl->buf->pos, cl->buf->file_pos, cl->buf->file_last - cl->buf->file_pos); - } #endif + ll = &cl->next; + } + for (cl = in; cl; cl = cl->next) { + ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0, "http body new buf t:%d f:%d %p, pos %p, size: %z " "file: %O, size: %O", @@ -1215,15 +1277,31 @@ ngx_http_request_body_save_filter(ngx_http_request_t *r, ngx_chain_t *in) cl->buf->last - cl->buf->pos, cl->buf->file_pos, cl->buf->file_last - cl->buf->file_pos); + + if (cl->buf->last_buf) { + + if (rb->last_saved) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "duplicate last buf in save filter"); + *ll = NULL; + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + rb->last_saved = 1; + } + + tl = ngx_alloc_chain_link(r->pool); + if (tl == NULL) { + *ll = NULL; + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + tl->buf = cl->buf; + *ll = tl; + ll = &tl->next; } -#endif - - /* TODO: coalesce neighbouring buffers */ - - if (ngx_chain_add_copy(r->pool, &rb->bufs, in) != NGX_OK) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } + *ll = NULL; if (r->request_body_no_buffering) { return NGX_OK; @@ -1231,7 +1309,7 @@ ngx_http_request_body_save_filter(ngx_http_request_t *r, ngx_chain_t *in) if (rb->rest > 0) { - if (rb->buf && rb->buf->last == rb->buf->end + if (rb->bufs && rb->buf && rb->buf->last == rb->buf->end && ngx_http_write_request_body(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; @@ -1240,10 +1318,18 @@ ngx_http_request_body_save_filter(ngx_http_request_t *r, ngx_chain_t *in) return NGX_OK; } - /* rb->rest == 0 */ + if (!rb->last_saved) { + return NGX_OK; + } if (rb->temp_file || r->request_body_in_file_only) { + if (rb->bufs && rb->bufs->buf->in_file) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "body already in file"); + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + if (ngx_http_write_request_body(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } diff --git a/src/http/ngx_http_script.c b/src/http/ngx_http_script.c index 13c57d6..bebdbd9 100644 --- a/src/http/ngx_http_script.c +++ b/src/http/ngx_http_script.c @@ -250,7 +250,7 @@ ngx_http_set_complex_value_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) cv = (ngx_http_complex_value_t **) (p + cmd->offset); - if (*cv != NULL) { + if (*cv != NGX_CONF_UNSET_PTR && *cv != NULL) { return "is duplicate"; } @@ -275,6 +275,44 @@ ngx_http_set_complex_value_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } +char * +ngx_http_set_complex_value_zero_slot(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + char *p = conf; + + ngx_str_t *value; + ngx_http_complex_value_t **cv; + ngx_http_compile_complex_value_t ccv; + + cv = (ngx_http_complex_value_t **) (p + cmd->offset); + + if (*cv != NGX_CONF_UNSET_PTR) { + return "is duplicate"; + } + + *cv = ngx_palloc(cf->pool, sizeof(ngx_http_complex_value_t)); + if (*cv == NULL) { + return NGX_CONF_ERROR; + } + + value = cf->args->elts; + + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[1]; + ccv.complex_value = *cv; + ccv.zero = 1; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + + char * ngx_http_set_complex_value_size_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) diff --git a/src/http/ngx_http_script.h b/src/http/ngx_http_script.h index a6b345e..4360038 100644 --- a/src/http/ngx_http_script.h +++ b/src/http/ngx_http_script.h @@ -216,6 +216,8 @@ size_t ngx_http_complex_value_size(ngx_http_request_t *r, ngx_int_t ngx_http_compile_complex_value(ngx_http_compile_complex_value_t *ccv); char *ngx_http_set_complex_value_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +char *ngx_http_set_complex_value_zero_slot(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); char *ngx_http_set_complex_value_size_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c index b682af5..ded833c 100644 --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -187,6 +187,8 @@ static void ngx_http_upstream_ssl_handshake(ngx_http_request_t *, static void ngx_http_upstream_ssl_save_session(ngx_connection_t *c); static ngx_int_t ngx_http_upstream_ssl_name(ngx_http_request_t *r, ngx_http_upstream_t *u, ngx_connection_t *c); +static ngx_int_t ngx_http_upstream_ssl_certificate(ngx_http_request_t *r, + ngx_http_upstream_t *u, ngx_connection_t *c); #endif @@ -1509,8 +1511,9 @@ ngx_http_upstream_check_broken_connection(ngx_http_request_t *r, static void ngx_http_upstream_connect(ngx_http_request_t *r, ngx_http_upstream_t *u) { - ngx_int_t rc; - ngx_connection_t *c; + ngx_int_t rc; + ngx_connection_t *c; + ngx_http_core_loc_conf_t *clcf; r->connection->log->action = "connecting to upstream"; @@ -1597,10 +1600,12 @@ ngx_http_upstream_connect(ngx_http_request_t *r, ngx_http_upstream_t *u) /* init or reinit the ngx_output_chain() and ngx_chain_writer() contexts */ + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + u->writer.out = NULL; u->writer.last = &u->writer.out; u->writer.connection = c; - u->writer.limit = 0; + u->writer.limit = clcf->sendfile_max_chunk; if (u->request_sent) { if (ngx_http_upstream_reinit(r, u) != NGX_OK) { @@ -1681,9 +1686,6 @@ ngx_http_upstream_ssl_init_connection(ngx_http_request_t *r, return; } - c->sendfile = 0; - u->output.sendfile = 0; - if (u->conf->ssl_server_name || u->conf->ssl_verify) { if (ngx_http_upstream_ssl_name(r, u, c) != NGX_OK) { ngx_http_upstream_finalize_request(r, u, @@ -1692,6 +1694,16 @@ ngx_http_upstream_ssl_init_connection(ngx_http_request_t *r, } } + if (u->conf->ssl_certificate && (u->conf->ssl_certificate->lengths + || u->conf->ssl_certificate_key->lengths)) + { + if (ngx_http_upstream_ssl_certificate(r, u, c) != NGX_OK) { + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + } + if (u->conf->ssl_session_reuse) { c->ssl->save_session = ngx_http_upstream_ssl_save_session; @@ -1779,6 +1791,11 @@ ngx_http_upstream_ssl_handshake(ngx_http_request_t *r, ngx_http_upstream_t *u, } } + if (!c->ssl->sendfile) { + c->sendfile = 0; + u->output.sendfile = 0; + } + c->write->handler = ngx_http_upstream_handler; c->read->handler = ngx_http_upstream_handler; @@ -1912,6 +1929,45 @@ done: return NGX_OK; } + +static ngx_int_t +ngx_http_upstream_ssl_certificate(ngx_http_request_t *r, + ngx_http_upstream_t *u, ngx_connection_t *c) +{ + ngx_str_t cert, key; + + if (ngx_http_complex_value(r, u->conf->ssl_certificate, &cert) + != NGX_OK) + { + return NGX_ERROR; + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http upstream ssl cert: \"%s\"", cert.data); + + if (*cert.data == '\0') { + return NGX_OK; + } + + if (ngx_http_complex_value(r, u->conf->ssl_certificate_key, &key) + != NGX_OK) + { + return NGX_ERROR; + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http upstream ssl key: \"%s\"", key.data); + + if (ngx_ssl_connection_certificate(c, r->pool, &cert, &key, + u->conf->ssl_passwords) + != NGX_OK) + { + return NGX_ERROR; + } + + return NGX_OK; +} + #endif @@ -3791,6 +3847,7 @@ ngx_http_upstream_thread_handler(ngx_thread_task_t *task, ngx_file_t *file) { ngx_str_t name; ngx_event_pipe_t *p; + ngx_connection_t *c; ngx_thread_pool_t *tp; ngx_http_request_t *r; ngx_http_core_loc_conf_t *clcf; @@ -3798,6 +3855,27 @@ ngx_http_upstream_thread_handler(ngx_thread_task_t *task, ngx_file_t *file) r = file->thread_ctx; p = r->upstream->pipe; + if (r->aio) { + /* + * tolerate sendfile() calls if another operation is already + * running; this can happen due to subrequests, multiple calls + * of the next body filter from a filter, or in HTTP/2 due to + * a write event on the main connection + */ + + c = r->connection; + +#if (NGX_HTTP_V2) + if (r->stream) { + c = r->stream->connection->connection; + } +#endif + + if (task == c->sendfile_task) { + return NGX_OK; + } + } + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); tp = clcf->thread_pool; @@ -3849,6 +3927,20 @@ ngx_http_upstream_thread_event_handler(ngx_event_t *ev) r->main->blocked--; r->aio = 0; +#if (NGX_HTTP_V2) + + if (r->stream) { + /* + * for HTTP/2, update write event to make sure processing will + * reach the main connection to handle sendfile() in threads + */ + + c->write->ready = 1; + c->write->active = 0; + } + +#endif + if (r->done) { /* * trigger connection event handler if the subrequest was diff --git a/src/http/ngx_http_upstream.h b/src/http/ngx_http_upstream.h index fd642c2..3db7b06 100644 --- a/src/http/ngx_http_upstream.h +++ b/src/http/ngx_http_upstream.h @@ -234,6 +234,10 @@ typedef struct { ngx_http_complex_value_t *ssl_name; ngx_flag_t ssl_server_name; ngx_flag_t ssl_verify; + + ngx_http_complex_value_t *ssl_certificate; + ngx_http_complex_value_t *ssl_certificate_key; + ngx_array_t *ssl_passwords; #endif ngx_str_t module; diff --git a/src/http/ngx_http_write_filter_module.c b/src/http/ngx_http_write_filter_module.c index 6a5d957..932f26d 100644 --- a/src/http/ngx_http_write_filter_module.c +++ b/src/http/ngx_http_write_filter_module.c @@ -321,18 +321,13 @@ ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in) delay = (ngx_msec_t) ((nsent - sent) * 1000 / r->limit_rate); if (delay > 0) { - limit = 0; c->write->delayed = 1; ngx_add_timer(c->write, delay); } } - if (limit - && c->write->ready - && c->sent - sent >= limit - (off_t) (2 * ngx_pagesize)) - { - c->write->delayed = 1; - ngx_add_timer(c->write, 1); + if (chain && c->write->ready && !c->write->delayed) { + ngx_post_event(c->write, &ngx_posted_next_events); } for (cl = r->out; cl && cl != chain; /* void */) { diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c index 3611a2e..0e45a7b 100644 --- a/src/http/v2/ngx_http_v2.c +++ b/src/http/v2/ngx_http_v2.c @@ -173,7 +173,7 @@ static ngx_int_t ngx_http_v2_construct_cookie_header(ngx_http_request_t *r); static void ngx_http_v2_run_request(ngx_http_request_t *r); static void ngx_http_v2_run_request_handler(ngx_event_t *ev); static ngx_int_t ngx_http_v2_process_request_body(ngx_http_request_t *r, - u_char *pos, size_t size, ngx_uint_t last); + u_char *pos, size_t size, ngx_uint_t last, ngx_uint_t flush); static ngx_int_t ngx_http_v2_filter_request_body(ngx_http_request_t *r); static void ngx_http_v2_read_client_request_body_handler(ngx_http_request_t *r); @@ -1140,9 +1140,10 @@ ngx_http_v2_state_read_data(ngx_http_v2_connection_t *h2c, u_char *pos, h2c->payload_bytes += size; if (r->request_body) { - rc = ngx_http_v2_process_request_body(r, pos, size, stream->in_closed); + rc = ngx_http_v2_process_request_body(r, pos, size, + stream->in_closed, 0); - if (rc != NGX_OK) { + if (rc != NGX_OK && rc != NGX_AGAIN) { stream->skip_data = 1; ngx_http_finalize_request(r, rc); } @@ -1599,10 +1600,10 @@ ngx_http_v2_state_field_huff(ngx_http_v2_connection_t *h2c, u_char *pos, h2c->state.length -= size; h2c->state.field_rest -= size; - if (ngx_http_v2_huff_decode(&h2c->state.field_state, pos, size, - &h2c->state.field_end, - h2c->state.field_rest == 0, - h2c->connection->log) + if (ngx_http_huff_decode(&h2c->state.field_state, pos, size, + &h2c->state.field_end, + h2c->state.field_rest == 0, + h2c->connection->log) != NGX_OK) { ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, @@ -3457,7 +3458,7 @@ ngx_http_v2_validate_header(ngx_http_request_t *r, ngx_http_v2_header_t *header) continue; } - if (ch == '\0' || ch == LF || ch == CR || ch == ':' + if (ch <= 0x20 || ch == 0x7f || ch == ':' || (ch >= 'A' && ch <= 'Z')) { ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, @@ -3606,7 +3607,8 @@ ngx_http_v2_parse_method(ngx_http_request_t *r, ngx_str_t *value) { 4, "LOCK", NGX_HTTP_LOCK }, { 6, "UNLOCK", NGX_HTTP_UNLOCK }, { 5, "PATCH", NGX_HTTP_PATCH }, - { 5, "TRACE", NGX_HTTP_TRACE } + { 5, "TRACE", NGX_HTTP_TRACE }, + { 7, "CONNECT", NGX_HTTP_CONNECT } }, *test; if (r->method_name.len) { @@ -4026,16 +4028,30 @@ ngx_http_v2_read_request_body(ngx_http_request_t *r) return NGX_OK; } + rb->rest = 1; + + /* set rb->filter_need_buffering */ + + rc = ngx_http_top_request_body_filter(r, NULL); + + if (rc != NGX_OK) { + stream->skip_data = 1; + return rc; + } + h2scf = ngx_http_get_module_srv_conf(r, ngx_http_v2_module); clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); len = r->headers_in.content_length_n; - if (r->request_body_no_buffering && !stream->in_closed) { + if (len < 0 || len > (off_t) clcf->client_body_buffer_size) { + len = clcf->client_body_buffer_size; - if (len < 0 || len > (off_t) clcf->client_body_buffer_size) { - len = clcf->client_body_buffer_size; - } + } else { + len++; + } + + if (r->request_body_no_buffering || rb->filter_need_buffering) { /* * We need a room to store data up to the stream's initial window size, @@ -4049,57 +4065,54 @@ ngx_http_v2_read_request_body(ngx_http_request_t *r) if (len > NGX_HTTP_V2_MAX_WINDOW) { len = NGX_HTTP_V2_MAX_WINDOW; } - - rb->buf = ngx_create_temp_buf(r->pool, (size_t) len); - - } else if (len >= 0 && len <= (off_t) clcf->client_body_buffer_size - && !r->request_body_in_file_only) - { - rb->buf = ngx_create_temp_buf(r->pool, (size_t) len); - - } else { - rb->buf = ngx_calloc_buf(r->pool); - - if (rb->buf != NULL) { - rb->buf->sync = 1; - } } + rb->buf = ngx_create_temp_buf(r->pool, (size_t) len); + if (rb->buf == NULL) { stream->skip_data = 1; return NGX_HTTP_INTERNAL_SERVER_ERROR; } - rb->rest = 1; - buf = stream->preread; if (stream->in_closed) { - r->request_body_no_buffering = 0; + if (!rb->filter_need_buffering) { + r->request_body_no_buffering = 0; + } if (buf) { rc = ngx_http_v2_process_request_body(r, buf->pos, - buf->last - buf->pos, 1); + buf->last - buf->pos, 1, 0); ngx_pfree(r->pool, buf->start); + + } else { + rc = ngx_http_v2_process_request_body(r, NULL, 0, 1, 0); + } + + if (rc != NGX_AGAIN) { return rc; } - return ngx_http_v2_process_request_body(r, NULL, 0, 1); + r->read_event_handler = ngx_http_v2_read_client_request_body_handler; + r->write_event_handler = ngx_http_request_empty_handler; + + return NGX_AGAIN; } if (buf) { rc = ngx_http_v2_process_request_body(r, buf->pos, - buf->last - buf->pos, 0); + buf->last - buf->pos, 0, 0); ngx_pfree(r->pool, buf->start); - if (rc != NGX_OK) { + if (rc != NGX_OK && rc != NGX_AGAIN) { stream->skip_data = 1; return rc; } } - if (r->request_body_no_buffering) { + if (r->request_body_no_buffering || rb->filter_need_buffering) { size = (size_t) len - h2scf->preread_size; } else { @@ -4141,9 +4154,9 @@ ngx_http_v2_read_request_body(ngx_http_request_t *r) static ngx_int_t ngx_http_v2_process_request_body(ngx_http_request_t *r, u_char *pos, - size_t size, ngx_uint_t last) + size_t size, ngx_uint_t last, ngx_uint_t flush) { - ngx_buf_t *buf; + size_t n; ngx_int_t rc; ngx_connection_t *fc; ngx_http_request_body_t *rb; @@ -4151,77 +4164,122 @@ ngx_http_v2_process_request_body(ngx_http_request_t *r, u_char *pos, fc = r->connection; rb = r->request_body; - buf = rb->buf; - if (size) { - if (buf->sync) { - buf->pos = buf->start = pos; - buf->last = buf->end = pos + size; + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, fc->log, 0, + "http2 process request body"); - r->request_body_in_file_only = 1; + if (size == 0 && !last && !flush) { + return NGX_AGAIN; + } - } else { - if (size > (size_t) (buf->end - buf->last)) { - ngx_log_error(NGX_LOG_INFO, fc->log, 0, - "client intended to send body data " - "larger than declared"); + for ( ;; ) { + for ( ;; ) { + if (rb->buf->last == rb->buf->end && size) { - return NGX_HTTP_BAD_REQUEST; + if (r->request_body_no_buffering) { + + /* should never happen due to flow control */ + + ngx_log_error(NGX_LOG_ALERT, fc->log, 0, + "no space in http2 body buffer"); + + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + /* update chains */ + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, fc->log, 0, + "http2 body update chains"); + + rc = ngx_http_v2_filter_request_body(r); + + if (rc != NGX_OK) { + return rc; + } + + if (rb->busy != NULL) { + ngx_log_error(NGX_LOG_ALERT, fc->log, 0, + "busy buffers after request body flush"); + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + rb->buf->pos = rb->buf->start; + rb->buf->last = rb->buf->start; } - buf->last = ngx_cpymem(buf->last, pos, size); + /* copy body data to the buffer */ + + n = rb->buf->end - rb->buf->last; + + if (n > size) { + n = size; + } + + if (n > 0) { + rb->buf->last = ngx_cpymem(rb->buf->last, pos, n); + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0, + "http2 request body recv %uz", n); + + pos += n; + size -= n; + + if (size == 0 && last) { + rb->rest = 0; + } + + if (size == 0) { + break; + } + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0, + "http2 request body rest %O", rb->rest); + + if (flush) { + rc = ngx_http_v2_filter_request_body(r); + + if (rc != NGX_OK) { + return rc; + } + } + + if (rb->rest == 0 && rb->last_saved) { + break; + } + + if (size == 0) { + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + ngx_add_timer(fc->read, clcf->client_body_timeout); + + if (!flush) { + ngx_post_event(fc->read, &ngx_posted_events); + } + + return NGX_AGAIN; } } - if (last) { - rb->rest = 0; - - if (fc->read->timer_set) { - ngx_del_timer(fc->read); - } - - if (r->request_body_no_buffering) { - ngx_post_event(fc->read, &ngx_posted_events); - return NGX_OK; - } - - rc = ngx_http_v2_filter_request_body(r); - - if (rc != NGX_OK) { - return rc; - } - - if (buf->sync) { - /* prevent reusing this buffer in the upstream module */ - rb->buf = NULL; - } - - if (r->headers_in.chunked) { - r->headers_in.content_length_n = rb->received; - } - - r->read_event_handler = ngx_http_block_reading; - rb->post_handler(r); - - return NGX_OK; + if (fc->read->timer_set) { + ngx_del_timer(fc->read); } - if (size == 0) { - return NGX_OK; - } - - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - ngx_add_timer(fc->read, clcf->client_body_timeout); - if (r->request_body_no_buffering) { - ngx_post_event(fc->read, &ngx_posted_events); + if (!flush) { + ngx_post_event(fc->read, &ngx_posted_events); + } + return NGX_OK; } - if (buf->sync) { - return ngx_http_v2_filter_request_body(r); + if (r->headers_in.chunked) { + r->headers_in.content_length_n = rb->received; } + r->read_event_handler = ngx_http_block_reading; + rb->post_handler(r); + return NGX_OK; } @@ -4238,7 +4296,7 @@ ngx_http_v2_filter_request_body(ngx_http_request_t *r) rb = r->request_body; buf = rb->buf; - if (buf->pos == buf->last && rb->rest) { + if (buf->pos == buf->last && (rb->rest || rb->last_sent)) { cl = NULL; goto update; } @@ -4301,6 +4359,7 @@ ngx_http_v2_filter_request_body(ngx_http_request_t *r) } b->last_buf = 1; + rb->last_sent = 1; } b->tag = (ngx_buf_tag_t) &ngx_http_v2_filter_request_body; @@ -4320,7 +4379,12 @@ update: static void ngx_http_v2_read_client_request_body_handler(ngx_http_request_t *r) { - ngx_connection_t *fc; + size_t window; + ngx_buf_t *buf; + ngx_int_t rc; + ngx_connection_t *fc; + ngx_http_v2_stream_t *stream; + ngx_http_v2_connection_t *h2c; fc = r->connection; @@ -4346,6 +4410,75 @@ ngx_http_v2_read_client_request_body_handler(ngx_http_request_t *r) ngx_http_finalize_request(r, NGX_HTTP_CLIENT_CLOSED_REQUEST); return; } + + rc = ngx_http_v2_process_request_body(r, NULL, 0, r->stream->in_closed, 1); + + if (rc != NGX_OK && rc != NGX_AGAIN) { + r->stream->skip_data = 1; + ngx_http_finalize_request(r, rc); + return; + } + + if (rc == NGX_OK) { + return; + } + + if (r->stream->no_flow_control) { + return; + } + + if (r->request_body->rest == 0) { + return; + } + + if (r->request_body->busy != NULL) { + return; + } + + stream = r->stream; + h2c = stream->connection; + + buf = r->request_body->buf; + + buf->pos = buf->start; + buf->last = buf->start; + + window = buf->end - buf->start; + + if (h2c->state.stream == stream) { + window -= h2c->state.length; + } + + if (window <= stream->recv_window) { + if (window < stream->recv_window) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "http2 negative window update"); + + stream->skip_data = 1; + + ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + + return; + } + + if (ngx_http_v2_send_window_update(h2c, stream->node->id, + window - stream->recv_window) + == NGX_ERROR) + { + stream->skip_data = 1; + ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + + stream->recv_window = window; + + if (ngx_http_v2_send_output_queue(h2c) == NGX_ERROR) { + stream->skip_data = 1; + ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } } @@ -4358,11 +4491,13 @@ ngx_http_v2_read_unbuffered_request_body(ngx_http_request_t *r) ngx_connection_t *fc; ngx_http_v2_stream_t *stream; ngx_http_v2_connection_t *h2c; - ngx_http_core_loc_conf_t *clcf; stream = r->stream; fc = r->connection; + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, fc->log, 0, + "http2 read unbuffered request body"); + if (fc->read->timedout) { if (stream->recv_window) { stream->skip_data = 1; @@ -4379,17 +4514,21 @@ ngx_http_v2_read_unbuffered_request_body(ngx_http_request_t *r) return NGX_HTTP_BAD_REQUEST; } - rc = ngx_http_v2_filter_request_body(r); + rc = ngx_http_v2_process_request_body(r, NULL, 0, r->stream->in_closed, 1); - if (rc != NGX_OK) { + if (rc != NGX_OK && rc != NGX_AGAIN) { stream->skip_data = 1; return rc; } - if (!r->request_body->rest) { + if (rc == NGX_OK) { return NGX_OK; } + if (r->request_body->rest == 0) { + return NGX_AGAIN; + } + if (r->request_body->busy != NULL) { return NGX_AGAIN; } @@ -4430,11 +4569,6 @@ ngx_http_v2_read_unbuffered_request_body(ngx_http_request_t *r) return NGX_HTTP_INTERNAL_SERVER_ERROR; } - if (stream->recv_window == 0) { - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - ngx_add_timer(fc->read, clcf->client_body_timeout); - } - stream->recv_window = window; return NGX_AGAIN; diff --git a/src/http/v2/ngx_http_v2.h b/src/http/v2/ngx_http_v2.h index 3492297..70ee287 100644 --- a/src/http/v2/ngx_http_v2.h +++ b/src/http/v2/ngx_http_v2.h @@ -13,8 +13,7 @@ #include -#define NGX_HTTP_V2_ALPN_ADVERTISE "\x02h2" -#define NGX_HTTP_V2_NPN_ADVERTISE NGX_HTTP_V2_ALPN_ADVERTISE +#define NGX_HTTP_V2_ALPN_PROTO "\x02h2" #define NGX_HTTP_V2_STATE_BUFFER_SIZE 16 @@ -312,12 +311,6 @@ ngx_int_t ngx_http_v2_add_header(ngx_http_v2_connection_t *h2c, ngx_int_t ngx_http_v2_table_size(ngx_http_v2_connection_t *h2c, size_t size); -ngx_int_t ngx_http_v2_huff_decode(u_char *state, u_char *src, size_t len, - u_char **dst, ngx_uint_t last, ngx_log_t *log); -size_t ngx_http_v2_huff_encode(u_char *src, size_t len, u_char *dst, - ngx_uint_t lower); - - #define ngx_http_v2_prefix(bits) ((1 << (bits)) - 1) diff --git a/src/http/v2/ngx_http_v2_encode.c b/src/http/v2/ngx_http_v2_encode.c index ac79208..8798aa9 100644 --- a/src/http/v2/ngx_http_v2_encode.c +++ b/src/http/v2/ngx_http_v2_encode.c @@ -20,7 +20,7 @@ ngx_http_v2_string_encode(u_char *dst, u_char *src, size_t len, u_char *tmp, { size_t hlen; - hlen = ngx_http_v2_huff_encode(src, len, tmp, lower); + hlen = ngx_http_huff_encode(src, len, tmp, lower); if (hlen > 0) { *dst = NGX_HTTP_V2_ENCODE_HUFF; diff --git a/src/http/v2/ngx_http_v2_filter_module.c b/src/http/v2/ngx_http_v2_filter_module.c index a6e5e7d..9ffb155 100644 --- a/src/http/v2/ngx_http_v2_filter_module.c +++ b/src/http/v2/ngx_http_v2_filter_module.c @@ -1432,6 +1432,9 @@ ngx_http_v2_send_chain(ngx_connection_t *fc, ngx_chain_t *in, off_t limit) size = 0; #endif + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0, + "http2 send chain: %p", in); + while (in) { size = ngx_buf_size(in->buf); @@ -1450,12 +1453,8 @@ ngx_http_v2_send_chain(ngx_connection_t *fc, ngx_chain_t *in, off_t limit) return NGX_CHAIN_ERROR; } - if (stream->queued) { - fc->write->active = 1; - fc->write->ready = 0; - - } else { - fc->buffered &= ~NGX_HTTP_V2_BUFFERED; + if (ngx_http_v2_filter_send(fc, stream) == NGX_ERROR) { + return NGX_CHAIN_ERROR; } return NULL; @@ -1464,9 +1463,16 @@ ngx_http_v2_send_chain(ngx_connection_t *fc, ngx_chain_t *in, off_t limit) h2c = stream->connection; if (size && ngx_http_v2_flow_control(h2c, stream) == NGX_DECLINED) { - fc->write->active = 1; - fc->write->ready = 0; - return in; + + if (ngx_http_v2_filter_send(fc, stream) == NGX_ERROR) { + return NGX_CHAIN_ERROR; + } + + if (ngx_http_v2_flow_control(h2c, stream) == NGX_DECLINED) { + fc->write->active = 1; + fc->write->ready = 0; + return in; + } } if (in->buf->tag == (ngx_buf_tag_t) &ngx_http_v2_filter_get_shadow) { @@ -1809,6 +1815,11 @@ ngx_http_v2_waiting_queue(ngx_http_v2_connection_t *h2c, static ngx_inline ngx_int_t ngx_http_v2_filter_send(ngx_connection_t *fc, ngx_http_v2_stream_t *stream) { + if (stream->queued == 0) { + fc->buffered &= ~NGX_HTTP_V2_BUFFERED; + return NGX_OK; + } + stream->blocked = 1; if (ngx_http_v2_send_output_queue(stream->connection) == NGX_ERROR) { diff --git a/src/mail/ngx_mail.h b/src/mail/ngx_mail.h index b865a3b..e0c62b7 100644 --- a/src/mail/ngx_mail.h +++ b/src/mail/ngx_mail.h @@ -115,6 +115,8 @@ typedef struct { ngx_msec_t timeout; ngx_msec_t resolver_timeout; + ngx_uint_t max_errors; + ngx_str_t server_name; u_char *file_name; @@ -231,14 +233,15 @@ typedef struct { ngx_uint_t command; ngx_array_t args; + ngx_uint_t errors; ngx_uint_t login_attempt; /* used to parse POP3/IMAP/SMTP command */ ngx_uint_t state; + u_char *tag_start; u_char *cmd_start; u_char *arg_start; - u_char *arg_end; ngx_uint_t literal_len; } ngx_mail_session_t; @@ -321,6 +324,7 @@ typedef ngx_int_t (*ngx_mail_parse_command_pt)(ngx_mail_session_t *s); struct ngx_mail_protocol_s { ngx_str_t name; + ngx_str_t alpn; in_port_t port[4]; ngx_uint_t type; diff --git a/src/mail/ngx_mail_auth_http_module.c b/src/mail/ngx_mail_auth_http_module.c index 2a198f4..27f64b9 100644 --- a/src/mail/ngx_mail_auth_http_module.c +++ b/src/mail/ngx_mail_auth_http_module.c @@ -1137,8 +1137,8 @@ ngx_mail_auth_http_create_request(ngx_mail_session_t *s, ngx_pool_t *pool, ngx_str_t login, passwd; ngx_connection_t *c; #if (NGX_MAIL_SSL) - ngx_str_t verify, subject, issuer, serial, fingerprint, - raw_cert, cert; + ngx_str_t protocol, cipher, verify, subject, issuer, + serial, fingerprint, raw_cert, cert; ngx_mail_ssl_conf_t *sslcf; #endif ngx_mail_core_srv_conf_t *cscf; @@ -1155,6 +1155,25 @@ ngx_mail_auth_http_create_request(ngx_mail_session_t *s, ngx_pool_t *pool, #if (NGX_MAIL_SSL) + if (c->ssl) { + + if (ngx_ssl_get_protocol(c, pool, &protocol) != NGX_OK) { + return NULL; + } + + protocol.len = ngx_strlen(protocol.data); + + if (ngx_ssl_get_cipher_name(c, pool, &cipher) != NGX_OK) { + return NULL; + } + + cipher.len = ngx_strlen(cipher.data); + + } else { + ngx_str_null(&protocol); + ngx_str_null(&cipher); + } + sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module); if (c->ssl && sslcf->verify) { @@ -1252,6 +1271,10 @@ ngx_mail_auth_http_create_request(ngx_mail_session_t *s, ngx_pool_t *pool, if (c->ssl) { len += sizeof("Auth-SSL: on" CRLF) - 1 + + sizeof("Auth-SSL-Protocol: ") - 1 + protocol.len + + sizeof(CRLF) - 1 + + sizeof("Auth-SSL-Cipher: ") - 1 + cipher.len + + sizeof(CRLF) - 1 + sizeof("Auth-SSL-Verify: ") - 1 + verify.len + sizeof(CRLF) - 1 + sizeof("Auth-SSL-Subject: ") - 1 + subject.len @@ -1373,6 +1396,20 @@ ngx_mail_auth_http_create_request(ngx_mail_session_t *s, ngx_pool_t *pool, b->last = ngx_cpymem(b->last, "Auth-SSL: on" CRLF, sizeof("Auth-SSL: on" CRLF) - 1); + if (protocol.len) { + b->last = ngx_cpymem(b->last, "Auth-SSL-Protocol: ", + sizeof("Auth-SSL-Protocol: ") - 1); + b->last = ngx_copy(b->last, protocol.data, protocol.len); + *b->last++ = CR; *b->last++ = LF; + } + + if (cipher.len) { + b->last = ngx_cpymem(b->last, "Auth-SSL-Cipher: ", + sizeof("Auth-SSL-Cipher: ") - 1); + b->last = ngx_copy(b->last, cipher.data, cipher.len); + *b->last++ = CR; *b->last++ = LF; + } + if (verify.len) { b->last = ngx_cpymem(b->last, "Auth-SSL-Verify: ", sizeof("Auth-SSL-Verify: ") - 1); diff --git a/src/mail/ngx_mail_core_module.c b/src/mail/ngx_mail_core_module.c index 4083124..115671c 100644 --- a/src/mail/ngx_mail_core_module.c +++ b/src/mail/ngx_mail_core_module.c @@ -85,6 +85,13 @@ static ngx_command_t ngx_mail_core_commands[] = { offsetof(ngx_mail_core_srv_conf_t, resolver_timeout), NULL }, + { ngx_string("max_errors"), + NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_MAIL_SRV_CONF_OFFSET, + offsetof(ngx_mail_core_srv_conf_t, max_errors), + NULL }, + ngx_null_command }; @@ -163,6 +170,8 @@ ngx_mail_core_create_srv_conf(ngx_conf_t *cf) cscf->timeout = NGX_CONF_UNSET_MSEC; cscf->resolver_timeout = NGX_CONF_UNSET_MSEC; + cscf->max_errors = NGX_CONF_UNSET_UINT; + cscf->resolver = NGX_CONF_UNSET_PTR; cscf->file_name = cf->conf_file->file.name.data; @@ -182,6 +191,7 @@ ngx_mail_core_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_msec_value(conf->resolver_timeout, prev->resolver_timeout, 30000); + ngx_conf_merge_uint_value(conf->max_errors, prev->max_errors, 5); ngx_conf_merge_str_value(conf->server_name, prev->server_name, ""); diff --git a/src/mail/ngx_mail_handler.c b/src/mail/ngx_mail_handler.c index 0aaa0e7..246ba97 100644 --- a/src/mail/ngx_mail_handler.c +++ b/src/mail/ngx_mail_handler.c @@ -833,20 +833,23 @@ ngx_mail_read_command(ngx_mail_session_t *s, ngx_connection_t *c) ngx_str_t l; ngx_mail_core_srv_conf_t *cscf; - n = c->recv(c, s->buffer->last, s->buffer->end - s->buffer->last); + if (s->buffer->last < s->buffer->end) { - if (n == NGX_ERROR || n == 0) { - ngx_mail_close_connection(c); - return NGX_ERROR; - } + n = c->recv(c, s->buffer->last, s->buffer->end - s->buffer->last); - if (n > 0) { - s->buffer->last += n; - } + if (n == NGX_ERROR || n == 0) { + ngx_mail_close_connection(c); + return NGX_ERROR; + } - if (n == NGX_AGAIN) { - if (s->buffer->pos == s->buffer->last) { - return NGX_AGAIN; + if (n > 0) { + s->buffer->last += n; + } + + if (n == NGX_AGAIN) { + if (s->buffer->pos == s->buffer->last) { + return NGX_AGAIN; + } } } @@ -871,7 +874,20 @@ ngx_mail_read_command(ngx_mail_session_t *s, ngx_connection_t *c) return NGX_MAIL_PARSE_INVALID_COMMAND; } - if (rc == NGX_IMAP_NEXT || rc == NGX_MAIL_PARSE_INVALID_COMMAND) { + if (rc == NGX_MAIL_PARSE_INVALID_COMMAND) { + + s->errors++; + + if (s->errors >= cscf->max_errors) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "client sent too many invalid commands"); + s->quit = 1; + } + + return rc; + } + + if (rc == NGX_IMAP_NEXT) { return rc; } diff --git a/src/mail/ngx_mail_imap_handler.c b/src/mail/ngx_mail_imap_handler.c index 5dfdd76..291e87a 100644 --- a/src/mail/ngx_mail_imap_handler.c +++ b/src/mail/ngx_mail_imap_handler.c @@ -101,10 +101,9 @@ ngx_mail_imap_init_protocol(ngx_event_t *rev) void ngx_mail_imap_auth_state(ngx_event_t *rev) { - u_char *p, *dst, *src, *end; - ngx_str_t *arg; + u_char *p; ngx_int_t rc; - ngx_uint_t tag, i; + ngx_uint_t tag; ngx_connection_t *c; ngx_mail_session_t *s; @@ -158,27 +157,6 @@ ngx_mail_imap_auth_state(ngx_event_t *rev) ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0, "imap auth command: %i", s->command); - if (s->backslash) { - - arg = s->args.elts; - - for (i = 0; i < s->args.nelts; i++) { - dst = arg[i].data; - end = dst + arg[i].len; - - for (src = dst; src < end; dst++) { - *dst = *src; - if (*src++ == '\\') { - *dst = *src++; - } - } - - arg[i].len = dst - arg[i].data; - } - - s->backslash = 0; - } - switch (s->mail_state) { case ngx_imap_start: @@ -248,6 +226,10 @@ ngx_mail_imap_auth_state(ngx_event_t *rev) ngx_str_set(&s->out, imap_next); } + if (s->buffer->pos < s->buffer->last) { + s->blocked = 1; + } + switch (rc) { case NGX_DONE: @@ -297,13 +279,14 @@ ngx_mail_imap_auth_state(ngx_event_t *rev) if (s->state) { /* preserve tag */ - s->arg_start = s->buffer->start + s->tag.len; - s->buffer->pos = s->arg_start; - s->buffer->last = s->arg_start; + s->arg_start = s->buffer->pos; } else { - s->buffer->pos = s->buffer->start; - s->buffer->last = s->buffer->start; + if (s->buffer->pos == s->buffer->last) { + s->buffer->pos = s->buffer->start; + s->buffer->last = s->buffer->start; + } + s->tag.len = 0; } } @@ -481,6 +464,8 @@ ngx_mail_imap_starttls(ngx_mail_session_t *s, ngx_connection_t *c) if (c->ssl == NULL) { sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module); if (sslcf->starttls) { + s->buffer->pos = s->buffer->start; + s->buffer->last = s->buffer->start; c->read->handler = ngx_mail_starttls_handler; return NGX_OK; } diff --git a/src/mail/ngx_mail_imap_module.c b/src/mail/ngx_mail_imap_module.c index 1f187fd..02c684c 100644 --- a/src/mail/ngx_mail_imap_module.c +++ b/src/mail/ngx_mail_imap_module.c @@ -46,6 +46,7 @@ static ngx_str_t ngx_mail_imap_auth_methods_names[] = { static ngx_mail_protocol_t ngx_mail_imap_protocol = { ngx_string("imap"), + ngx_string("\x04imap"), { 143, 993, 0, 0 }, NGX_MAIL_IMAP_PROTOCOL, diff --git a/src/mail/ngx_mail_parse.c b/src/mail/ngx_mail_parse.c index 2c2cdff..4db1f18 100644 --- a/src/mail/ngx_mail_parse.c +++ b/src/mail/ngx_mail_parse.c @@ -21,6 +21,8 @@ ngx_mail_pop3_parse_command(ngx_mail_session_t *s) ngx_str_t *arg; enum { sw_start = 0, + sw_command, + sw_invalid, sw_spaces_before_argument, sw_argument, sw_almost_done @@ -35,8 +37,14 @@ ngx_mail_pop3_parse_command(ngx_mail_session_t *s) /* POP3 command */ case sw_start: + s->cmd_start = p; + state = sw_command; + + /* fall through */ + + case sw_command: if (ch == ' ' || ch == CR || ch == LF) { - c = s->buffer->start; + c = s->cmd_start; if (p - c == 4) { @@ -85,6 +93,9 @@ ngx_mail_pop3_parse_command(ngx_mail_session_t *s) goto invalid; } + s->cmd.data = s->cmd_start; + s->cmd.len = p - s->cmd_start; + switch (ch) { case ' ': state = sw_spaces_before_argument; @@ -104,16 +115,17 @@ ngx_mail_pop3_parse_command(ngx_mail_session_t *s) break; + case sw_invalid: + goto invalid; + case sw_spaces_before_argument: switch (ch) { case ' ': break; case CR: state = sw_almost_done; - s->arg_end = p; break; case LF: - s->arg_end = p; goto done; default: if (s->args.nelts <= 2) { @@ -188,37 +200,39 @@ ngx_mail_pop3_parse_command(ngx_mail_session_t *s) done: s->buffer->pos = p + 1; - - if (s->arg_start) { - arg = ngx_array_push(&s->args); - if (arg == NULL) { - return NGX_ERROR; - } - arg->len = s->arg_end - s->arg_start; - arg->data = s->arg_start; - s->arg_start = NULL; - } - s->state = (s->command != NGX_POP3_AUTH) ? sw_start : sw_argument; return NGX_OK; invalid: - s->state = sw_start; - s->arg_start = NULL; + s->state = sw_invalid; - return NGX_MAIL_PARSE_INVALID_COMMAND; + /* skip invalid command till LF */ + + for ( /* void */ ; p < s->buffer->last; p++) { + if (*p == LF) { + s->state = sw_start; + s->buffer->pos = p + 1; + return NGX_MAIL_PARSE_INVALID_COMMAND; + } + } + + s->buffer->pos = p; + + return NGX_AGAIN; } ngx_int_t ngx_mail_imap_parse_command(ngx_mail_session_t *s) { - u_char ch, *p, *c; + u_char ch, *p, *c, *dst, *src, *end; ngx_str_t *arg; enum { sw_start = 0, + sw_tag, + sw_invalid, sw_spaces_before_command, sw_command, sw_spaces_before_argument, @@ -241,31 +255,45 @@ ngx_mail_imap_parse_command(ngx_mail_session_t *s) /* IMAP tag */ case sw_start: + s->tag_start = p; + state = sw_tag; + + /* fall through */ + + case sw_tag: switch (ch) { case ' ': - s->tag.len = p - s->buffer->start + 1; - s->tag.data = s->buffer->start; + s->tag.len = p - s->tag_start + 1; + s->tag.data = s->tag_start; state = sw_spaces_before_command; break; case CR: - s->state = sw_start; - return NGX_MAIL_PARSE_INVALID_COMMAND; case LF: - s->state = sw_start; - return NGX_MAIL_PARSE_INVALID_COMMAND; + goto invalid; + default: + if ((ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z') + && (ch < '0' || ch > '9') && ch != '-' && ch != '.' + && ch != '_') + { + goto invalid; + } + if (p - s->tag_start > 31) { + goto invalid; + } + break; } break; + case sw_invalid: + goto invalid; + case sw_spaces_before_command: switch (ch) { case ' ': break; case CR: - s->state = sw_start; - return NGX_MAIL_PARSE_INVALID_COMMAND; case LF: - s->state = sw_start; - return NGX_MAIL_PARSE_INVALID_COMMAND; + goto invalid; default: s->cmd_start = p; state = sw_command; @@ -385,6 +413,9 @@ ngx_mail_imap_parse_command(ngx_mail_session_t *s) goto invalid; } + s->cmd.data = s->cmd_start; + s->cmd.len = p - s->cmd_start; + switch (ch) { case ' ': state = sw_spaces_before_argument; @@ -410,10 +441,8 @@ ngx_mail_imap_parse_command(ngx_mail_session_t *s) break; case CR: state = sw_almost_done; - s->arg_end = p; break; case LF: - s->arg_end = p; goto done; case '"': if (s->args.nelts <= 2) { @@ -460,6 +489,22 @@ ngx_mail_imap_parse_command(ngx_mail_session_t *s) } arg->len = p - s->arg_start; arg->data = s->arg_start; + + if (s->backslash) { + dst = s->arg_start; + end = p; + + for (src = dst; src < end; dst++) { + *dst = *src; + if (*src++ == '\\') { + *dst = *src++; + } + } + + arg->len = dst - s->arg_start; + s->backslash = 0; + } + s->arg_start = NULL; switch (ch) { @@ -588,34 +633,46 @@ ngx_mail_imap_parse_command(ngx_mail_session_t *s) done: s->buffer->pos = p + 1; - - if (s->arg_start) { - arg = ngx_array_push(&s->args); - if (arg == NULL) { - return NGX_ERROR; - } - arg->len = s->arg_end - s->arg_start; - arg->data = s->arg_start; - - s->arg_start = NULL; - s->cmd_start = NULL; - s->quoted = 0; - s->no_sync_literal = 0; - s->literal_len = 0; - } - s->state = (s->command != NGX_IMAP_AUTHENTICATE) ? sw_start : sw_argument; return NGX_OK; invalid: - s->state = sw_start; + s->state = sw_invalid; s->quoted = 0; + s->backslash = 0; s->no_sync_literal = 0; s->literal_len = 0; - return NGX_MAIL_PARSE_INVALID_COMMAND; + /* skip invalid command till LF */ + + for ( /* void */ ; p < s->buffer->last; p++) { + if (*p == LF) { + s->state = sw_start; + s->buffer->pos = p + 1; + + /* detect non-synchronizing literals */ + + if ((size_t) (p - s->buffer->start) > sizeof("{1+}") - 1) { + p--; + + if (*p == CR) { + p--; + } + + if (*p == '}' && *(p - 1) == '+') { + s->quit = 1; + } + } + + return NGX_MAIL_PARSE_INVALID_COMMAND; + } + } + + s->buffer->pos = p; + + return NGX_AGAIN; } @@ -758,10 +815,8 @@ ngx_mail_smtp_parse_command(ngx_mail_session_t *s) break; case CR: state = sw_almost_done; - s->arg_end = p; break; case LF: - s->arg_end = p; goto done; default: if (s->args.nelts <= 10) { @@ -821,17 +876,6 @@ ngx_mail_smtp_parse_command(ngx_mail_session_t *s) done: s->buffer->pos = p + 1; - - if (s->arg_start) { - arg = ngx_array_push(&s->args); - if (arg == NULL) { - return NGX_ERROR; - } - arg->len = s->arg_end - s->arg_start; - arg->data = s->arg_start; - s->arg_start = NULL; - } - s->state = (s->command != NGX_SMTP_AUTH) ? sw_start : sw_argument; return NGX_OK; @@ -839,21 +883,20 @@ done: invalid: s->state = sw_invalid; - s->arg_start = NULL; /* skip invalid command till LF */ - for (p = s->buffer->pos; p < s->buffer->last; p++) { + for ( /* void */ ; p < s->buffer->last; p++) { if (*p == LF) { s->state = sw_start; - p++; - break; + s->buffer->pos = p + 1; + return NGX_MAIL_PARSE_INVALID_COMMAND; } } s->buffer->pos = p; - return NGX_MAIL_PARSE_INVALID_COMMAND; + return NGX_AGAIN; } diff --git a/src/mail/ngx_mail_pop3_handler.c b/src/mail/ngx_mail_pop3_handler.c index edfd986..226e741 100644 --- a/src/mail/ngx_mail_pop3_handler.c +++ b/src/mail/ngx_mail_pop3_handler.c @@ -262,6 +262,10 @@ ngx_mail_pop3_auth_state(ngx_event_t *rev) } } + if (s->buffer->pos < s->buffer->last) { + s->blocked = 1; + } + switch (rc) { case NGX_DONE: @@ -283,11 +287,14 @@ ngx_mail_pop3_auth_state(ngx_event_t *rev) case NGX_OK: s->args.nelts = 0; - s->buffer->pos = s->buffer->start; - s->buffer->last = s->buffer->start; + + if (s->buffer->pos == s->buffer->last) { + s->buffer->pos = s->buffer->start; + s->buffer->last = s->buffer->start; + } if (s->state) { - s->arg_start = s->buffer->start; + s->arg_start = s->buffer->pos; } if (ngx_handle_read_event(c->read, 0) != NGX_OK) { @@ -400,6 +407,8 @@ ngx_mail_pop3_stls(ngx_mail_session_t *s, ngx_connection_t *c) if (c->ssl == NULL) { sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module); if (sslcf->starttls) { + s->buffer->pos = s->buffer->start; + s->buffer->last = s->buffer->start; c->read->handler = ngx_mail_starttls_handler; return NGX_OK; } diff --git a/src/mail/ngx_mail_pop3_module.c b/src/mail/ngx_mail_pop3_module.c index a673070..a257b5a 100644 --- a/src/mail/ngx_mail_pop3_module.c +++ b/src/mail/ngx_mail_pop3_module.c @@ -46,6 +46,7 @@ static ngx_str_t ngx_mail_pop3_auth_methods_names[] = { static ngx_mail_protocol_t ngx_mail_pop3_protocol = { ngx_string("pop3"), + ngx_string("\x04pop3"), { 110, 995, 0, 0 }, NGX_MAIL_POP3_PROTOCOL, diff --git a/src/mail/ngx_mail_proxy_module.c b/src/mail/ngx_mail_proxy_module.c index 66aa0ba..a7ab077 100644 --- a/src/mail/ngx_mail_proxy_module.c +++ b/src/mail/ngx_mail_proxy_module.c @@ -327,6 +327,10 @@ ngx_mail_proxy_pop3_handler(ngx_event_t *rev) c->log->action = NULL; ngx_log_error(NGX_LOG_INFO, c->log, 0, "client logged in"); + if (s->buffer->pos < s->buffer->last) { + ngx_post_event(c->write, &ngx_posted_events); + } + ngx_mail_proxy_handler(s->connection->write); return; @@ -482,6 +486,10 @@ ngx_mail_proxy_imap_handler(ngx_event_t *rev) c->log->action = NULL; ngx_log_error(NGX_LOG_INFO, c->log, 0, "client logged in"); + if (s->buffer->pos < s->buffer->last) { + ngx_post_event(c->write, &ngx_posted_events); + } + ngx_mail_proxy_handler(s->connection->write); return; @@ -813,13 +821,12 @@ ngx_mail_proxy_smtp_handler(ngx_event_t *rev) c->log->action = NULL; ngx_log_error(NGX_LOG_INFO, c->log, 0, "client logged in"); - if (s->buffer->pos == s->buffer->last) { - ngx_mail_proxy_handler(s->connection->write); - - } else { - ngx_mail_proxy_handler(c->write); + if (s->buffer->pos < s->buffer->last) { + ngx_post_event(c->write, &ngx_posted_events); } + ngx_mail_proxy_handler(s->connection->write); + return; default: diff --git a/src/mail/ngx_mail_smtp_module.c b/src/mail/ngx_mail_smtp_module.c index 3b5a2d8..0e05fdc 100644 --- a/src/mail/ngx_mail_smtp_module.c +++ b/src/mail/ngx_mail_smtp_module.c @@ -39,6 +39,7 @@ static ngx_str_t ngx_mail_smtp_auth_methods_names[] = { static ngx_mail_protocol_t ngx_mail_smtp_protocol = { ngx_string("smtp"), + ngx_string("\x04smtp"), { 25, 465, 587, 0 }, NGX_MAIL_SMTP_PROTOCOL, diff --git a/src/mail/ngx_mail_ssl_module.c b/src/mail/ngx_mail_ssl_module.c index 7eae83e..2a1043e 100644 --- a/src/mail/ngx_mail_ssl_module.c +++ b/src/mail/ngx_mail_ssl_module.c @@ -14,6 +14,12 @@ #define NGX_DEFAULT_ECDH_CURVE "auto" +#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation +static int ngx_mail_ssl_alpn_select(ngx_ssl_conn_t *ssl_conn, + const unsigned char **out, unsigned char *outlen, + const unsigned char *in, unsigned int inlen, void *arg); +#endif + static void *ngx_mail_ssl_create_conf(ngx_conf_t *cf); static char *ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child); @@ -244,6 +250,54 @@ ngx_module_t ngx_mail_ssl_module = { static ngx_str_t ngx_mail_ssl_sess_id_ctx = ngx_string("MAIL"); +#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation + +static int +ngx_mail_ssl_alpn_select(ngx_ssl_conn_t *ssl_conn, const unsigned char **out, + unsigned char *outlen, const unsigned char *in, unsigned int inlen, + void *arg) +{ + unsigned int srvlen; + unsigned char *srv; + ngx_connection_t *c; + ngx_mail_session_t *s; + ngx_mail_core_srv_conf_t *cscf; +#if (NGX_DEBUG) + unsigned int i; +#endif + + c = ngx_ssl_get_connection(ssl_conn); + s = c->data; + +#if (NGX_DEBUG) + for (i = 0; i < inlen; i += in[i] + 1) { + ngx_log_debug2(NGX_LOG_DEBUG_MAIL, c->log, 0, + "SSL ALPN supported by client: %*s", + (size_t) in[i], &in[i + 1]); + } +#endif + + cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); + + srv = cscf->protocol->alpn.data; + srvlen = cscf->protocol->alpn.len; + + if (SSL_select_next_proto((unsigned char **) out, outlen, srv, srvlen, + in, inlen) + != OPENSSL_NPN_NEGOTIATED) + { + return SSL_TLSEXT_ERR_ALERT_FATAL; + } + + ngx_log_debug2(NGX_LOG_DEBUG_MAIL, c->log, 0, + "SSL ALPN selected: %*s", (size_t) *outlen, *out); + + return SSL_TLSEXT_ERR_OK; +} + +#endif + + static void * ngx_mail_ssl_create_conf(ngx_conf_t *cf) { @@ -394,6 +448,17 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) cln->handler = ngx_ssl_cleanup_ctx; cln->data = &conf->ssl; +#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation + SSL_CTX_set_alpn_select_cb(conf->ssl.ctx, ngx_mail_ssl_alpn_select, NULL); +#endif + + if (ngx_ssl_ciphers(cf, &conf->ssl, &conf->ciphers, + conf->prefer_server_ciphers) + != NGX_OK) + { + return NGX_CONF_ERROR; + } + if (ngx_ssl_certificates(cf, &conf->ssl, conf->certificates, conf->certificate_keys, conf->passwords) != NGX_OK) @@ -430,13 +495,6 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) } } - if (ngx_ssl_ciphers(cf, &conf->ssl, &conf->ciphers, - conf->prefer_server_ciphers) - != NGX_OK) - { - return NGX_CONF_ERROR; - } - if (ngx_ssl_dhparam(cf, &conf->ssl, &conf->dhparam) != NGX_OK) { return NGX_CONF_ERROR; } diff --git a/src/os/unix/ngx_atomic.h b/src/os/unix/ngx_atomic.h index 74b8b7f..fcab2d6 100644 --- a/src/os/unix/ngx_atomic.h +++ b/src/os/unix/ngx_atomic.h @@ -38,6 +38,39 @@ typedef volatile ngx_atomic_uint_t ngx_atomic_t; #define ngx_cpu_pause() +#elif (NGX_HAVE_GCC_ATOMIC) + +/* GCC 4.1 builtin atomic operations */ + +#define NGX_HAVE_ATOMIC_OPS 1 + +typedef long ngx_atomic_int_t; +typedef unsigned long ngx_atomic_uint_t; + +#if (NGX_PTR_SIZE == 8) +#define NGX_ATOMIC_T_LEN (sizeof("-9223372036854775808") - 1) +#else +#define NGX_ATOMIC_T_LEN (sizeof("-2147483648") - 1) +#endif + +typedef volatile ngx_atomic_uint_t ngx_atomic_t; + + +#define ngx_atomic_cmp_set(lock, old, set) \ + __sync_bool_compare_and_swap(lock, old, set) + +#define ngx_atomic_fetch_add(value, add) \ + __sync_fetch_and_add(value, add) + +#define ngx_memory_barrier() __sync_synchronize() + +#if ( __i386__ || __i386 || __amd64__ || __amd64 ) +#define ngx_cpu_pause() __asm__ ("pause") +#else +#define ngx_cpu_pause() +#endif + + #elif (NGX_DARWIN_ATOMIC) /* @@ -88,39 +121,6 @@ typedef uint32_t ngx_atomic_uint_t; typedef volatile ngx_atomic_uint_t ngx_atomic_t; -#elif (NGX_HAVE_GCC_ATOMIC) - -/* GCC 4.1 builtin atomic operations */ - -#define NGX_HAVE_ATOMIC_OPS 1 - -typedef long ngx_atomic_int_t; -typedef unsigned long ngx_atomic_uint_t; - -#if (NGX_PTR_SIZE == 8) -#define NGX_ATOMIC_T_LEN (sizeof("-9223372036854775808") - 1) -#else -#define NGX_ATOMIC_T_LEN (sizeof("-2147483648") - 1) -#endif - -typedef volatile ngx_atomic_uint_t ngx_atomic_t; - - -#define ngx_atomic_cmp_set(lock, old, set) \ - __sync_bool_compare_and_swap(lock, old, set) - -#define ngx_atomic_fetch_add(value, add) \ - __sync_fetch_and_add(value, add) - -#define ngx_memory_barrier() __sync_synchronize() - -#if ( __i386__ || __i386 || __amd64__ || __amd64 ) -#define ngx_cpu_pause() __asm__ ("pause") -#else -#define ngx_cpu_pause() -#endif - - #elif ( __i386__ || __i386 ) typedef int32_t ngx_atomic_int_t; diff --git a/src/os/unix/ngx_freebsd_sendfile_chain.c b/src/os/unix/ngx_freebsd_sendfile_chain.c index 3d415bd..5c6a830 100644 --- a/src/os/unix/ngx_freebsd_sendfile_chain.c +++ b/src/os/unix/ngx_freebsd_sendfile_chain.c @@ -32,23 +32,22 @@ ngx_chain_t * ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) { - int rc, flags; - off_t send, prev_send, sent; - size_t file_size; - ssize_t n; - ngx_uint_t eintr, eagain; - ngx_err_t err; - ngx_buf_t *file; - ngx_event_t *wev; - ngx_chain_t *cl; - ngx_iovec_t header, trailer; - struct sf_hdtr hdtr; - struct iovec headers[NGX_IOVS_PREALLOCATE]; - struct iovec trailers[NGX_IOVS_PREALLOCATE]; -#if (NGX_HAVE_AIO_SENDFILE) - ngx_uint_t ebusy; - ngx_event_aio_t *aio; + int rc, flags; + off_t send, prev_send, sent; + size_t file_size; + ssize_t n; + ngx_err_t err; + ngx_buf_t *file; + ngx_uint_t eintr, eagain; +#if (NGX_HAVE_SENDFILE_NODISKIO) + ngx_uint_t ebusy; #endif + ngx_event_t *wev; + ngx_chain_t *cl; + ngx_iovec_t header, trailer; + struct sf_hdtr hdtr; + struct iovec headers[NGX_IOVS_PREALLOCATE]; + struct iovec trailers[NGX_IOVS_PREALLOCATE]; wev = c->write; @@ -77,11 +76,6 @@ ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) eagain = 0; flags = 0; -#if (NGX_HAVE_AIO_SENDFILE && NGX_SUPPRESS_WARN) - aio = NULL; - file = NULL; -#endif - header.iovs = headers; header.nalloc = NGX_IOVS_PREALLOCATE; @@ -90,7 +84,7 @@ ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) for ( ;; ) { eintr = 0; -#if (NGX_HAVE_AIO_SENDFILE) +#if (NGX_HAVE_SENDFILE_NODISKIO) ebusy = 0; #endif prev_send = send; @@ -179,9 +173,14 @@ ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) sent = 0; -#if (NGX_HAVE_AIO_SENDFILE) - aio = file->file->aio; - flags = (aio && aio->preload_handler) ? SF_NODISKIO : 0; +#if (NGX_HAVE_SENDFILE_NODISKIO) + + flags = (c->busy_count <= 2) ? SF_NODISKIO : 0; + + if (file->file->directio) { + flags |= SF_NOCACHE; + } + #endif rc = sendfile(file->file->fd, c->fd, file->file_pos, @@ -199,7 +198,7 @@ ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) eintr = 1; break; -#if (NGX_HAVE_AIO_SENDFILE) +#if (NGX_HAVE_SENDFILE_NODISKIO) case NGX_EBUSY: ebusy = 1; break; @@ -252,54 +251,30 @@ ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) in = ngx_chain_update_sent(in, sent); -#if (NGX_HAVE_AIO_SENDFILE) +#if (NGX_HAVE_SENDFILE_NODISKIO) if (ebusy) { - if (aio->event.active) { - /* - * tolerate duplicate calls; they can happen due to subrequests - * or multiple calls of the next body filter from a filter - */ - - if (sent) { - c->busy_count = 0; - } - - return in; - } - if (sent == 0) { c->busy_count++; - if (c->busy_count > 2) { - ngx_log_error(NGX_LOG_ALERT, c->log, 0, - "sendfile(%V) returned busy again", - &file->file->name); - - c->busy_count = 0; - aio->preload_handler = NULL; - - send = prev_send; - continue; - } + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "sendfile() busy, count:%d", c->busy_count); } else { c->busy_count = 0; } - n = aio->preload_handler(file); - - if (n > 0) { - send = prev_send + sent; - continue; + if (wev->posted) { + ngx_delete_posted_event(wev); } + ngx_post_event(wev, &ngx_posted_next_events); + + wev->ready = 0; return in; } - if (flags == SF_NODISKIO) { - c->busy_count = 0; - } + c->busy_count = 0; #endif diff --git a/src/os/unix/ngx_linux_sendfile_chain.c b/src/os/unix/ngx_linux_sendfile_chain.c index 5695839..101d91a 100644 --- a/src/os/unix/ngx_linux_sendfile_chain.c +++ b/src/os/unix/ngx_linux_sendfile_chain.c @@ -38,6 +38,9 @@ static void ngx_linux_sendfile_thread_handler(void *data, ngx_log_t *log); * On Linux up to 2.6.16 sendfile() does not allow to pass the count parameter * more than 2G-1 bytes even on 64-bit platforms: it returns EINVAL, * so we limit it to 2G-1 bytes. + * + * On Linux 2.6.16 and later, sendfile() silently limits the count parameter + * to 2G minus the page size, even on 64-bit platforms. */ #define NGX_SENDFILE_MAXSIZE 2147483647L @@ -216,7 +219,6 @@ ngx_linux_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) */ send = prev_send + sent; - continue; } if (send >= limit || in == NULL) { @@ -377,15 +379,6 @@ ngx_linux_sendfile_thread(ngx_connection_t *c, ngx_buf_t *file, size_t size) return ctx->sent; } - if (task->event.active && ctx->file == file) { - /* - * tolerate duplicate calls; they can happen due to subrequests - * or multiple calls of the next body filter from a filter - */ - - return NGX_DONE; - } - ctx->file = file; ctx->socket = c->fd; ctx->size = size; diff --git a/src/os/unix/ngx_process_cycle.c b/src/os/unix/ngx_process_cycle.c index b31485f..07cd05e 100644 --- a/src/os/unix/ngx_process_cycle.c +++ b/src/os/unix/ngx_process_cycle.c @@ -398,6 +398,8 @@ ngx_pass_open_channel(ngx_cycle_t *cycle) ngx_int_t i; ngx_channel_t ch; + ngx_memzero(&ch, sizeof(ngx_channel_t)); + ch.command = NGX_CMD_OPEN_CHANNEL; ch.pid = ngx_processes[ngx_process_slot].pid; ch.slot = ngx_process_slot; diff --git a/src/os/unix/ngx_readv_chain.c b/src/os/unix/ngx_readv_chain.c index a3577ce..b1ae4b5 100644 --- a/src/os/unix/ngx_readv_chain.c +++ b/src/os/unix/ngx_readv_chain.c @@ -96,7 +96,7 @@ ngx_readv_chain(ngx_connection_t *c, ngx_chain_t *chain, off_t limit) iov->iov_len += n; } else { - if (vec.nelts >= IOV_MAX) { + if (vec.nelts == vec.nalloc) { break; } diff --git a/src/stream/ngx_stream.c b/src/stream/ngx_stream.c index 7835675..3304c84 100644 --- a/src/stream/ngx_stream.c +++ b/src/stream/ngx_stream.c @@ -510,6 +510,10 @@ ngx_stream_optimize_servers(ngx_conf_t *cf, ngx_array_t *ports) ls->ipv6only = addr[i].opt.ipv6only; #endif +#if (NGX_HAVE_TCP_FASTOPEN) + ls->fastopen = addr[i].opt.fastopen; +#endif + #if (NGX_HAVE_REUSEPORT) ls->reuseport = addr[i].opt.reuseport; #endif diff --git a/src/stream/ngx_stream.h b/src/stream/ngx_stream.h index 9e35832..46c3622 100644 --- a/src/stream/ngx_stream.h +++ b/src/stream/ngx_stream.h @@ -65,6 +65,9 @@ typedef struct { int backlog; int rcvbuf; int sndbuf; +#if (NGX_HAVE_TCP_FASTOPEN) + int fastopen; +#endif int type; } ngx_stream_listen_t; diff --git a/src/stream/ngx_stream_core_module.c b/src/stream/ngx_stream_core_module.c index 9b6afe9..d96d27a 100644 --- a/src/stream/ngx_stream_core_module.c +++ b/src/stream/ngx_stream_core_module.c @@ -615,6 +615,10 @@ ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ls->type = SOCK_STREAM; ls->ctx = cf->ctx; +#if (NGX_HAVE_TCP_FASTOPEN) + ls->fastopen = -1; +#endif + #if (NGX_HAVE_INET6) ls->ipv6only = 1; #endif @@ -635,6 +639,21 @@ ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) continue; } +#if (NGX_HAVE_TCP_FASTOPEN) + if (ngx_strncmp(value[i].data, "fastopen=", 9) == 0) { + ls->fastopen = ngx_atoi(value[i].data + 9, value[i].len - 9); + ls->bind = 1; + + if (ls->fastopen == NGX_ERROR) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid fastopen \"%V\"", &value[i]); + return NGX_CONF_ERROR; + } + + continue; + } +#endif + if (ngx_strncmp(value[i].data, "backlog=", 8) == 0) { ls->backlog = ngx_atoi(value[i].data + 8, value[i].len - 8); ls->bind = 1; @@ -859,6 +878,12 @@ ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) if (ls->proxy_protocol) { return "\"proxy_protocol\" parameter is incompatible with \"udp\""; } + +#if (NGX_HAVE_TCP_FASTOPEN) + if (ls->fastopen != -1) { + return "\"fastopen\" parameter is incompatible with \"udp\""; + } +#endif } als = cmcf->listen.elts; diff --git a/src/stream/ngx_stream_proxy_module.c b/src/stream/ngx_stream_proxy_module.c index 01cda7a..934e7d8 100644 --- a/src/stream/ngx_stream_proxy_module.c +++ b/src/stream/ngx_stream_proxy_module.c @@ -31,6 +31,7 @@ typedef struct { ngx_uint_t next_upstream_tries; ngx_flag_t next_upstream; ngx_flag_t proxy_protocol; + ngx_flag_t half_close; ngx_stream_upstream_local_t *local; ngx_flag_t socket_keepalive; @@ -46,8 +47,8 @@ typedef struct { ngx_uint_t ssl_verify_depth; ngx_str_t ssl_trusted_certificate; ngx_str_t ssl_crl; - ngx_str_t ssl_certificate; - ngx_str_t ssl_certificate_key; + ngx_stream_complex_value_t *ssl_certificate; + ngx_stream_complex_value_t *ssl_certificate_key; ngx_array_t *ssl_passwords; ngx_array_t *ssl_conf_commands; @@ -101,6 +102,7 @@ static void ngx_stream_proxy_ssl_init_connection(ngx_stream_session_t *s); static void ngx_stream_proxy_ssl_handshake(ngx_connection_t *pc); static void ngx_stream_proxy_ssl_save_session(ngx_connection_t *c); static ngx_int_t ngx_stream_proxy_ssl_name(ngx_stream_session_t *s); +static ngx_int_t ngx_stream_proxy_ssl_certificate(ngx_stream_session_t *s); static ngx_int_t ngx_stream_proxy_set_ssl(ngx_conf_t *cf, ngx_stream_proxy_srv_conf_t *pscf); @@ -244,6 +246,13 @@ static ngx_command_t ngx_stream_proxy_commands[] = { offsetof(ngx_stream_proxy_srv_conf_t, proxy_protocol), NULL }, + { ngx_string("proxy_half_close"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_STREAM_SRV_CONF_OFFSET, + offsetof(ngx_stream_proxy_srv_conf_t, half_close), + NULL }, + #if (NGX_STREAM_SSL) { ngx_string("proxy_ssl"), @@ -318,14 +327,14 @@ static ngx_command_t ngx_stream_proxy_commands[] = { { ngx_string("proxy_ssl_certificate"), NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_str_slot, + ngx_stream_set_complex_value_zero_slot, NGX_STREAM_SRV_CONF_OFFSET, offsetof(ngx_stream_proxy_srv_conf_t, ssl_certificate), NULL }, { ngx_string("proxy_ssl_certificate_key"), NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_str_slot, + ngx_stream_set_complex_value_zero_slot, NGX_STREAM_SRV_CONF_OFFSET, offsetof(ngx_stream_proxy_srv_conf_t, ssl_certificate_key), NULL }, @@ -1060,6 +1069,15 @@ ngx_stream_proxy_ssl_init_connection(ngx_stream_session_t *s) } } + if (pscf->ssl_certificate && (pscf->ssl_certificate->lengths + || pscf->ssl_certificate_key->lengths)) + { + if (ngx_stream_proxy_ssl_certificate(s) != NGX_OK) { + ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); + return; + } + } + if (pscf->ssl_session_reuse) { pc->ssl->save_session = ngx_stream_proxy_ssl_save_session; @@ -1247,6 +1265,50 @@ done: return NGX_OK; } + +static ngx_int_t +ngx_stream_proxy_ssl_certificate(ngx_stream_session_t *s) +{ + ngx_str_t cert, key; + ngx_connection_t *c; + ngx_stream_proxy_srv_conf_t *pscf; + + c = s->upstream->peer.connection; + + pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module); + + if (ngx_stream_complex_value(s, pscf->ssl_certificate, &cert) + != NGX_OK) + { + return NGX_ERROR; + } + + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0, + "stream upstream ssl cert: \"%s\"", cert.data); + + if (*cert.data == '\0') { + return NGX_OK; + } + + if (ngx_stream_complex_value(s, pscf->ssl_certificate_key, &key) + != NGX_OK) + { + return NGX_ERROR; + } + + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0, + "stream upstream ssl key: \"%s\"", key.data); + + if (ngx_ssl_connection_certificate(c, c->pool, &cert, &key, + pscf->ssl_passwords) + != NGX_OK) + { + return NGX_ERROR; + } + + return NGX_OK; +} + #endif @@ -1701,6 +1763,24 @@ ngx_stream_proxy_process(ngx_stream_session_t *s, ngx_uint_t from_upstream, } if (dst) { + + if (dst->type == SOCK_STREAM && pscf->half_close + && src->read->eof && !u->half_closed && !dst->buffered) + { + if (ngx_shutdown_socket(dst->fd, NGX_WRITE_SHUTDOWN) == -1) { + ngx_connection_error(c, ngx_socket_errno, + ngx_shutdown_socket_n " failed"); + + ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); + return; + } + + u->half_closed = 1; + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, + "stream proxy %s socket shutdown", + from_upstream ? "client" : "upstream"); + } + if (ngx_handle_write_event(dst->write, 0) != NGX_OK) { ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); return; @@ -1779,6 +1859,13 @@ ngx_stream_proxy_test_finalize(ngx_stream_session_t *s, return NGX_DECLINED; } + if (pscf->half_close) { + /* avoid closing live connections until both read ends get EOF */ + if (!(c->read->eof && pc->read->eof && !c->buffered && !pc->buffered)) { + return NGX_DECLINED; + } + } + handler = c->log->handler; c->log->handler = NULL; @@ -1977,14 +2064,9 @@ ngx_stream_proxy_create_srv_conf(ngx_conf_t *cf) * * conf->ssl_protocols = 0; * conf->ssl_ciphers = { 0, NULL }; - * conf->ssl_name = NULL; * conf->ssl_trusted_certificate = { 0, NULL }; * conf->ssl_crl = { 0, NULL }; - * conf->ssl_certificate = { 0, NULL }; - * conf->ssl_certificate_key = { 0, NULL }; * - * conf->upload_rate = NULL; - * conf->download_rate = NULL; * conf->ssl = NULL; * conf->upstream = NULL; * conf->upstream_value = NULL; @@ -1994,6 +2076,8 @@ ngx_stream_proxy_create_srv_conf(ngx_conf_t *cf) conf->timeout = NGX_CONF_UNSET_MSEC; conf->next_upstream_timeout = NGX_CONF_UNSET_MSEC; conf->buffer_size = NGX_CONF_UNSET_SIZE; + conf->upload_rate = NGX_CONF_UNSET_PTR; + conf->download_rate = NGX_CONF_UNSET_PTR; conf->requests = NGX_CONF_UNSET_UINT; conf->responses = NGX_CONF_UNSET_UINT; conf->next_upstream_tries = NGX_CONF_UNSET_UINT; @@ -2001,13 +2085,17 @@ ngx_stream_proxy_create_srv_conf(ngx_conf_t *cf) conf->proxy_protocol = NGX_CONF_UNSET; conf->local = NGX_CONF_UNSET_PTR; conf->socket_keepalive = NGX_CONF_UNSET; + conf->half_close = NGX_CONF_UNSET; #if (NGX_STREAM_SSL) conf->ssl_enable = NGX_CONF_UNSET; conf->ssl_session_reuse = NGX_CONF_UNSET; + conf->ssl_name = NGX_CONF_UNSET_PTR; conf->ssl_server_name = NGX_CONF_UNSET; conf->ssl_verify = NGX_CONF_UNSET; conf->ssl_verify_depth = NGX_CONF_UNSET_UINT; + conf->ssl_certificate = NGX_CONF_UNSET_PTR; + conf->ssl_certificate_key = NGX_CONF_UNSET_PTR; conf->ssl_passwords = NGX_CONF_UNSET_PTR; conf->ssl_conf_commands = NGX_CONF_UNSET_PTR; #endif @@ -2034,13 +2122,9 @@ ngx_stream_proxy_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_size_value(conf->buffer_size, prev->buffer_size, 16384); - if (conf->upload_rate == NULL) { - conf->upload_rate = prev->upload_rate; - } + ngx_conf_merge_ptr_value(conf->upload_rate, prev->upload_rate, NULL); - if (conf->download_rate == NULL) { - conf->download_rate = prev->download_rate; - } + ngx_conf_merge_ptr_value(conf->download_rate, prev->download_rate, NULL); ngx_conf_merge_uint_value(conf->requests, prev->requests, 0); @@ -2060,6 +2144,8 @@ ngx_stream_proxy_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_value(conf->socket_keepalive, prev->socket_keepalive, 0); + ngx_conf_merge_value(conf->half_close, prev->half_close, 0); + #if (NGX_STREAM_SSL) ngx_conf_merge_value(conf->ssl_enable, prev->ssl_enable, 0); @@ -2073,9 +2159,7 @@ ngx_stream_proxy_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers, "DEFAULT"); - if (conf->ssl_name == NULL) { - conf->ssl_name = prev->ssl_name; - } + ngx_conf_merge_ptr_value(conf->ssl_name, prev->ssl_name, NULL); ngx_conf_merge_value(conf->ssl_server_name, prev->ssl_server_name, 0); @@ -2089,11 +2173,11 @@ ngx_stream_proxy_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_str_value(conf->ssl_crl, prev->ssl_crl, ""); - ngx_conf_merge_str_value(conf->ssl_certificate, - prev->ssl_certificate, ""); + ngx_conf_merge_ptr_value(conf->ssl_certificate, + prev->ssl_certificate, NULL); - ngx_conf_merge_str_value(conf->ssl_certificate_key, - prev->ssl_certificate_key, ""); + ngx_conf_merge_ptr_value(conf->ssl_certificate_key, + prev->ssl_certificate_key, NULL); ngx_conf_merge_ptr_value(conf->ssl_passwords, prev->ssl_passwords, NULL); @@ -2137,27 +2221,41 @@ ngx_stream_proxy_set_ssl(ngx_conf_t *cf, ngx_stream_proxy_srv_conf_t *pscf) cln->handler = ngx_ssl_cleanup_ctx; cln->data = pscf->ssl; - if (pscf->ssl_certificate.len) { - - if (pscf->ssl_certificate_key.len == 0) { - ngx_log_error(NGX_LOG_EMERG, cf->log, 0, - "no \"proxy_ssl_certificate_key\" is defined " - "for certificate \"%V\"", &pscf->ssl_certificate); - return NGX_ERROR; - } - - if (ngx_ssl_certificate(cf, pscf->ssl, &pscf->ssl_certificate, - &pscf->ssl_certificate_key, pscf->ssl_passwords) - != NGX_OK) - { - return NGX_ERROR; - } - } - if (ngx_ssl_ciphers(cf, pscf->ssl, &pscf->ssl_ciphers, 0) != NGX_OK) { return NGX_ERROR; } + if (pscf->ssl_certificate) { + + if (pscf->ssl_certificate_key == NULL) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "no \"proxy_ssl_certificate_key\" is defined " + "for certificate \"%V\"", + &pscf->ssl_certificate->value); + return NGX_ERROR; + } + + if (pscf->ssl_certificate->lengths + || pscf->ssl_certificate_key->lengths) + { + pscf->ssl_passwords = + ngx_ssl_preserve_passwords(cf, pscf->ssl_passwords); + if (pscf->ssl_passwords == NULL) { + return NGX_ERROR; + } + + } else { + if (ngx_ssl_certificate(cf, pscf->ssl, + &pscf->ssl_certificate->value, + &pscf->ssl_certificate_key->value, + pscf->ssl_passwords) + != NGX_OK) + { + return NGX_ERROR; + } + } + } + if (pscf->ssl_verify) { if (pscf->ssl_trusted_certificate.len == 0) { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, diff --git a/src/stream/ngx_stream_script.c b/src/stream/ngx_stream_script.c index a15f772..c447e15 100644 --- a/src/stream/ngx_stream_script.c +++ b/src/stream/ngx_stream_script.c @@ -252,7 +252,7 @@ ngx_stream_set_complex_value_slot(ngx_conf_t *cf, ngx_command_t *cmd, cv = (ngx_stream_complex_value_t **) (p + cmd->offset); - if (*cv != NULL) { + if (*cv != NGX_CONF_UNSET_PTR && *cv != NULL) { return "is duplicate"; } @@ -277,6 +277,44 @@ ngx_stream_set_complex_value_slot(ngx_conf_t *cf, ngx_command_t *cmd, } +char * +ngx_stream_set_complex_value_zero_slot(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + char *p = conf; + + ngx_str_t *value; + ngx_stream_complex_value_t **cv; + ngx_stream_compile_complex_value_t ccv; + + cv = (ngx_stream_complex_value_t **) (p + cmd->offset); + + if (*cv != NGX_CONF_UNSET_PTR) { + return "is duplicate"; + } + + *cv = ngx_palloc(cf->pool, sizeof(ngx_stream_complex_value_t)); + if (*cv == NULL) { + return NGX_CONF_ERROR; + } + + value = cf->args->elts; + + ngx_memzero(&ccv, sizeof(ngx_stream_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[1]; + ccv.complex_value = *cv; + ccv.zero = 1; + + if (ngx_stream_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + + char * ngx_stream_set_complex_value_size_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) diff --git a/src/stream/ngx_stream_script.h b/src/stream/ngx_stream_script.h index a481ca3..d8f3740 100644 --- a/src/stream/ngx_stream_script.h +++ b/src/stream/ngx_stream_script.h @@ -112,6 +112,8 @@ ngx_int_t ngx_stream_compile_complex_value( ngx_stream_compile_complex_value_t *ccv); char *ngx_stream_set_complex_value_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +char *ngx_stream_set_complex_value_zero_slot(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); char *ngx_stream_set_complex_value_size_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); diff --git a/src/stream/ngx_stream_ssl_module.c b/src/stream/ngx_stream_ssl_module.c index d8c0471..c530832 100644 --- a/src/stream/ngx_stream_ssl_module.c +++ b/src/stream/ngx_stream_ssl_module.c @@ -23,7 +23,13 @@ static ngx_int_t ngx_stream_ssl_init_connection(ngx_ssl_t *ssl, ngx_connection_t *c); static void ngx_stream_ssl_handshake_handler(ngx_connection_t *c); #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME -int ngx_stream_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg); +static int ngx_stream_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, + void *arg); +#endif +#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation +static int ngx_stream_ssl_alpn_select(ngx_ssl_conn_t *ssl_conn, + const unsigned char **out, unsigned char *outlen, + const unsigned char *in, unsigned int inlen, void *arg); #endif #ifdef SSL_R_CERT_CB_ERROR static int ngx_stream_ssl_certificate(ngx_ssl_conn_t *ssl_conn, void *arg); @@ -45,6 +51,8 @@ static char *ngx_stream_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static char *ngx_stream_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static char *ngx_stream_ssl_alpn(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); static char *ngx_stream_ssl_conf_command_check(ngx_conf_t *cf, void *post, void *data); @@ -211,6 +219,13 @@ static ngx_command_t ngx_stream_ssl_commands[] = { offsetof(ngx_stream_ssl_conf_t, conf_commands), &ngx_stream_ssl_conf_command_post }, + { ngx_string("ssl_alpn"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_1MORE, + ngx_stream_ssl_alpn, + NGX_STREAM_SRV_CONF_OFFSET, + 0, + NULL }, + ngx_null_command }; @@ -254,6 +269,9 @@ static ngx_stream_variable_t ngx_stream_ssl_vars[] = { { ngx_string("ssl_ciphers"), NULL, ngx_stream_ssl_variable, (uintptr_t) ngx_ssl_get_ciphers, NGX_STREAM_VAR_CHANGEABLE, 0 }, + { ngx_string("ssl_curve"), NULL, ngx_stream_ssl_variable, + (uintptr_t) ngx_ssl_get_curve, NGX_STREAM_VAR_CHANGEABLE, 0 }, + { ngx_string("ssl_curves"), NULL, ngx_stream_ssl_variable, (uintptr_t) ngx_ssl_get_curves, NGX_STREAM_VAR_CHANGEABLE, 0 }, @@ -266,6 +284,9 @@ static ngx_stream_variable_t ngx_stream_ssl_vars[] = { { ngx_string("ssl_server_name"), NULL, ngx_stream_ssl_variable, (uintptr_t) ngx_ssl_get_server_name, NGX_STREAM_VAR_CHANGEABLE, 0 }, + { ngx_string("ssl_alpn_protocol"), NULL, ngx_stream_ssl_variable, + (uintptr_t) ngx_ssl_get_alpn_protocol, NGX_STREAM_VAR_CHANGEABLE, 0 }, + { ngx_string("ssl_client_cert"), NULL, ngx_stream_ssl_variable, (uintptr_t) ngx_ssl_get_certificate, NGX_STREAM_VAR_CHANGEABLE, 0 }, @@ -434,7 +455,7 @@ ngx_stream_ssl_handshake_handler(ngx_connection_t *c) #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME -int +static int ngx_stream_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg) { return SSL_TLSEXT_ERR_OK; @@ -443,9 +464,49 @@ ngx_stream_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg) #endif +#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation + +static int +ngx_stream_ssl_alpn_select(ngx_ssl_conn_t *ssl_conn, const unsigned char **out, + unsigned char *outlen, const unsigned char *in, unsigned int inlen, + void *arg) +{ + ngx_str_t *alpn; +#if (NGX_DEBUG) + unsigned int i; + ngx_connection_t *c; + + c = ngx_ssl_get_connection(ssl_conn); + + for (i = 0; i < inlen; i += in[i] + 1) { + ngx_log_debug2(NGX_LOG_DEBUG_STREAM, c->log, 0, + "SSL ALPN supported by client: %*s", + (size_t) in[i], &in[i + 1]); + } + +#endif + + alpn = arg; + + if (SSL_select_next_proto((unsigned char **) out, outlen, alpn->data, + alpn->len, in, inlen) + != OPENSSL_NPN_NEGOTIATED) + { + return SSL_TLSEXT_ERR_ALERT_FATAL; + } + + ngx_log_debug2(NGX_LOG_DEBUG_STREAM, c->log, 0, + "SSL ALPN selected: %*s", (size_t) *outlen, *out); + + return SSL_TLSEXT_ERR_OK; +} + +#endif + + #ifdef SSL_R_CERT_CB_ERROR -int +static int ngx_stream_ssl_certificate(ngx_ssl_conn_t *ssl_conn, void *arg) { ngx_str_t cert, key; @@ -602,6 +663,7 @@ ngx_stream_ssl_create_conf(ngx_conf_t *cf) * scf->client_certificate = { 0, NULL }; * scf->trusted_certificate = { 0, NULL }; * scf->crl = { 0, NULL }; + * scf->alpn = { 0, NULL }; * scf->ciphers = { 0, NULL }; * scf->shm_zone = NULL; */ @@ -660,6 +722,7 @@ ngx_stream_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_str_value(conf->trusted_certificate, prev->trusted_certificate, ""); ngx_conf_merge_str_value(conf->crl, prev->crl, ""); + ngx_conf_merge_str_value(conf->alpn, prev->alpn, ""); ngx_conf_merge_str_value(conf->ecdh_curve, prev->ecdh_curve, NGX_DEFAULT_ECDH_CURVE); @@ -720,6 +783,20 @@ ngx_stream_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) ngx_stream_ssl_servername); #endif +#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation + if (conf->alpn.len) { + SSL_CTX_set_alpn_select_cb(conf->ssl.ctx, ngx_stream_ssl_alpn_select, + &conf->alpn); + } +#endif + + if (ngx_ssl_ciphers(cf, &conf->ssl, &conf->ciphers, + conf->prefer_server_ciphers) + != NGX_OK) + { + return NGX_CONF_ERROR; + } + if (ngx_stream_ssl_compile_certificates(cf, conf) != NGX_OK) { return NGX_CONF_ERROR; } @@ -752,13 +829,6 @@ ngx_stream_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) } } - if (ngx_ssl_ciphers(cf, &conf->ssl, &conf->ciphers, - conf->prefer_server_ciphers) - != NGX_OK) - { - return NGX_CONF_ERROR; - } - if (conf->verify) { if (conf->client_certificate.len == 0 && conf->verify != 3) { @@ -1056,6 +1126,60 @@ invalid: } +static char * +ngx_stream_ssl_alpn(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ +#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation + + ngx_stream_ssl_conf_t *scf = conf; + + u_char *p; + size_t len; + ngx_str_t *value; + ngx_uint_t i; + + if (scf->alpn.len) { + return "is duplicate"; + } + + value = cf->args->elts; + + len = 0; + + for (i = 1; i < cf->args->nelts; i++) { + + if (value[i].len > 255) { + return "protocol too long"; + } + + len += value[i].len + 1; + } + + scf->alpn.data = ngx_pnalloc(cf->pool, len); + if (scf->alpn.data == NULL) { + return NGX_CONF_ERROR; + } + + p = scf->alpn.data; + + for (i = 1; i < cf->args->nelts; i++) { + *p++ = value[i].len; + p = ngx_cpymem(p, value[i].data, value[i].len); + } + + scf->alpn.len = len; + + return NGX_CONF_OK; + +#else + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "the \"ssl_alpn\" directive requires OpenSSL " + "with ALPN support"); + return NGX_CONF_ERROR; +#endif +} + + static char * ngx_stream_ssl_conf_command_check(ngx_conf_t *cf, void *post, void *data) { diff --git a/src/stream/ngx_stream_ssl_module.h b/src/stream/ngx_stream_ssl_module.h index c6e24be..e7c825e 100644 --- a/src/stream/ngx_stream_ssl_module.h +++ b/src/stream/ngx_stream_ssl_module.h @@ -42,6 +42,7 @@ typedef struct { ngx_str_t client_certificate; ngx_str_t trusted_certificate; ngx_str_t crl; + ngx_str_t alpn; ngx_str_t ciphers; diff --git a/src/stream/ngx_stream_upstream.h b/src/stream/ngx_stream_upstream.h index 9857e0b..f561779 100644 --- a/src/stream/ngx_stream_upstream.h +++ b/src/stream/ngx_stream_upstream.h @@ -142,6 +142,7 @@ typedef struct { ngx_stream_upstream_state_t *state; unsigned connected:1; unsigned proxy_protocol:1; + unsigned half_closed:1; } ngx_stream_upstream_t; From 24d9bd02907266424ef4a74ad7de298be7723631 Mon Sep 17 00:00:00 2001 From: Thomas Ward Date: Tue, 24 May 2022 14:20:28 -0400 Subject: [PATCH 111/329] Update changelog --- debian/changelog | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/debian/changelog b/debian/changelog index 3b9b5b7..98db79b 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,7 +1,9 @@ -nginx (1.20.2-3) UNRELEASED; urgency=medium +nginx (1.22.0-1) UNRELEASED; urgency=medium - * d/conf/mime.types: Fix a typo in font/woff2 extension in - mime.types. (Closes: #1010798) + * New upstream release (1.22.0) + * Additional changes: + * d/conf/mime.types: Fix a typo in font/woff2 extension in + mime.types. (Closes: #1010798) -- Thomas Ward Tue, 10 May 2022 12:08:02 -0400 From 5900bc832a071308bdd1b10ae01796389fbf4e7b Mon Sep 17 00:00:00 2001 From: Thomas Ward Date: Tue, 24 May 2022 14:24:29 -0400 Subject: [PATCH 112/329] Changelog update --- debian/changelog | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/debian/changelog b/debian/changelog index 98db79b..04b3aa1 100644 --- a/debian/changelog +++ b/debian/changelog @@ -4,6 +4,11 @@ nginx (1.22.0-1) UNRELEASED; urgency=medium * Additional changes: * d/conf/mime.types: Fix a typo in font/woff2 extension in mime.types. (Closes: #1010798) + * d/upstream/signing-key.asc: Additional signing keys observed + in upstream (Konstantin Pavlov ) during + upstream merge/import by Thomas Ward, additional signing key + was added to the keyring while keeping Maxim's key in signing + keys as wel. -- Thomas Ward Tue, 10 May 2022 12:08:02 -0400 From c394d8d99931a56d9a37543e2673caf7b321e8ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Wed, 25 May 2022 07:01:01 +0200 Subject: [PATCH 113/329] d/p/CVE-2021-3618.patch removed, fix is included in new upstream release --- debian/changelog | 5 ++ debian/patches/CVE-2021-3618.patch | 84 ------------------------------ debian/patches/series | 1 - 3 files changed, 5 insertions(+), 85 deletions(-) delete mode 100644 debian/patches/CVE-2021-3618.patch diff --git a/debian/changelog b/debian/changelog index 04b3aa1..16e6b2d 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,5 +1,6 @@ nginx (1.22.0-1) UNRELEASED; urgency=medium + [ Thomas Ward ] * New upstream release (1.22.0) * Additional changes: * d/conf/mime.types: Fix a typo in font/woff2 extension in @@ -10,6 +11,10 @@ nginx (1.22.0-1) UNRELEASED; urgency=medium was added to the keyring while keeping Maxim's key in signing keys as wel. + [ Jan Mojžíš ] + * d/patches/CVE-2021-3618.patch removed, fix is included in new upstream + release + -- Thomas Ward Tue, 10 May 2022 12:08:02 -0400 nginx (1.20.2-2) unstable; urgency=medium diff --git a/debian/patches/CVE-2021-3618.patch b/debian/patches/CVE-2021-3618.patch deleted file mode 100644 index 10f37a9..0000000 --- a/debian/patches/CVE-2021-3618.patch +++ /dev/null @@ -1,84 +0,0 @@ -Subject: Patch mitigation for CVE-2021-3618 - Mail: max_errors directive. - . - Similarly to smtpd_hard_error_limit in Postfix and smtp_max_unknown_commands - in Exim, specifies the number of errors after which the connection is closed. -Origin: upstream, http://hg.nginx.org/nginx/rev/ec1071830799 -Bug-Debian: https://bugs.debian.org/991328 - ---- a/src/mail/ngx_mail.h -+++ b/src/mail/ngx_mail.h -@@ -115,6 +115,8 @@ - ngx_msec_t timeout; - ngx_msec_t resolver_timeout; - -+ ngx_uint_t max_errors; -+ - ngx_str_t server_name; - - u_char *file_name; -@@ -231,6 +233,7 @@ - ngx_uint_t command; - ngx_array_t args; - -+ ngx_uint_t errors; - ngx_uint_t login_attempt; - - /* used to parse POP3/IMAP/SMTP command */ ---- a/src/mail/ngx_mail_core_module.c -+++ b/src/mail/ngx_mail_core_module.c -@@ -85,6 +85,13 @@ - offsetof(ngx_mail_core_srv_conf_t, resolver_timeout), - NULL }, - -+ { ngx_string("max_errors"), -+ NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, -+ ngx_conf_set_num_slot, -+ NGX_MAIL_SRV_CONF_OFFSET, -+ offsetof(ngx_mail_core_srv_conf_t, max_errors), -+ NULL }, -+ - ngx_null_command - }; - -@@ -163,6 +170,8 @@ - cscf->timeout = NGX_CONF_UNSET_MSEC; - cscf->resolver_timeout = NGX_CONF_UNSET_MSEC; - -+ cscf->max_errors = NGX_CONF_UNSET_UINT; -+ - cscf->resolver = NGX_CONF_UNSET_PTR; - - cscf->file_name = cf->conf_file->file.name.data; -@@ -182,6 +191,7 @@ - ngx_conf_merge_msec_value(conf->resolver_timeout, prev->resolver_timeout, - 30000); - -+ ngx_conf_merge_uint_value(conf->max_errors, prev->max_errors, 5); - - ngx_conf_merge_str_value(conf->server_name, prev->server_name, ""); - ---- a/src/mail/ngx_mail_handler.c -+++ b/src/mail/ngx_mail_handler.c -@@ -871,7 +871,20 @@ - return NGX_MAIL_PARSE_INVALID_COMMAND; - } - -- if (rc == NGX_IMAP_NEXT || rc == NGX_MAIL_PARSE_INVALID_COMMAND) { -+ if (rc == NGX_MAIL_PARSE_INVALID_COMMAND) { -+ -+ s->errors++; -+ -+ if (s->errors >= cscf->max_errors) { -+ ngx_log_error(NGX_LOG_INFO, c->log, 0, -+ "client sent too many invalid commands"); -+ s->quit = 1; -+ } -+ -+ return rc; -+ } -+ -+ if (rc == NGX_IMAP_NEXT) { - return rc; - } - diff --git a/debian/patches/series b/debian/patches/series index 4e43575..5b6b799 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -1,3 +1,2 @@ 0002-Make-sure-signature-stays-the-same-in-all-nginx-buil.patch 0003-define_gnu_source-on-other-glibc-based-platforms.patch -CVE-2021-3618.patch From 7224e5e7ca7a1a8bd6f692082b176830ae3657bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Wed, 25 May 2022 11:04:30 +0200 Subject: [PATCH 114/329] d/control: removed ppc64el from list of luajit platforms. --- debian/changelog | 1 + debian/control | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index 16e6b2d..eb42d36 100644 --- a/debian/changelog +++ b/debian/changelog @@ -14,6 +14,7 @@ nginx (1.22.0-1) UNRELEASED; urgency=medium [ Jan Mojžíš ] * d/patches/CVE-2021-3618.patch removed, fix is included in new upstream release + * d/control: removed ppc64el from list of luajit platforms. (Closes: #1011303) -- Thomas Ward Tue, 10 May 2022 12:08:02 -0400 diff --git a/debian/control b/debian/control index cc32589..3a2b586 100644 --- a/debian/control +++ b/debian/control @@ -12,8 +12,8 @@ Build-Depends: debhelper-compat (= 13), libgd-dev, libgeoip-dev, libhiredis-dev, - liblua5.1-0-dev [!i386 !amd64 !kfreebsd-i386 !kfreebsd-amd64 !armel !armhf !powerpc !powerpcspe !mips !mipsel !mips64el !arm64 !ppc64 !ppc64el], - libluajit-5.1-dev [i386 amd64 kfreebsd-i386 kfreebsd-amd64 armel armhf powerpc powerpcspe mips mipsel mips64el arm64 ppc64 ppc64el], + liblua5.1-0-dev [!i386 !amd64 !kfreebsd-i386 !kfreebsd-amd64 !armel !armhf !powerpc !powerpcspe !mips !mipsel !mips64el !arm64 !ppc64], + libluajit-5.1-dev [i386 amd64 kfreebsd-i386 kfreebsd-amd64 armel armhf powerpc powerpcspe mips mipsel mips64el arm64 ppc64], libmaxminddb-dev, libmhash-dev, libpam0g-dev, From a013b18ff66b9ac1d899827ed5725589f9900701 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Wed, 25 May 2022 11:19:06 +0200 Subject: [PATCH 115/329] d/changelog fix whitespaces --- debian/changelog | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/debian/changelog b/debian/changelog index eb42d36..713a937 100644 --- a/debian/changelog +++ b/debian/changelog @@ -3,7 +3,7 @@ nginx (1.22.0-1) UNRELEASED; urgency=medium [ Thomas Ward ] * New upstream release (1.22.0) * Additional changes: - * d/conf/mime.types: Fix a typo in font/woff2 extension in + * d/conf/mime.types: Fix a typo in font/woff2 extension in mime.types. (Closes: #1010798) * d/upstream/signing-key.asc: Additional signing keys observed in upstream (Konstantin Pavlov ) during @@ -21,7 +21,7 @@ nginx (1.22.0-1) UNRELEASED; urgency=medium nginx (1.20.2-2) unstable; urgency=medium [ Thomas Ward ] - * d/patches/CVE-2021-3618.patch: Include upstream changeset from NGINX + * d/patches/CVE-2021-3618.patch: Include upstream changeset from NGINX that adds mitigations into the Mail module for CVE-2021-3618.patch. (Closes: #991328) @@ -46,7 +46,7 @@ nginx (1.20.2-1) unstable; urgency=medium * d/conf/mime.types: Update mime.types to more match upstream mime.types and include upstream changes with mime.types from 1.21.x via nginx.org mercurial repository versions. - * d/control: Remove self from Uploaders per other Debian devs, who want + * d/control: Remove self from Uploaders per other Debian devs, who want that commit to be done by someone on the current uploaders/maintainers group instead. @@ -65,7 +65,7 @@ nginx (1.18.0-9) unstable; urgency=medium * d/watch: Update watch syntax to match all even versions of NGINX releases rather than use a watch syntax that is static to one specific version. This will fix the untracked "New upstream stable versions" problem. - * d/control: Update 'uploaders' as Thomas Ward is now a maintainer in + * d/control: Update 'uploaders' as Thomas Ward is now a maintainer in the Salsa repository. -- Jan Mojžíš Tue, 05 Apr 2022 19:11:47 +0200 From 5eec971e2717232ed1d8a88ce193edccb495e582 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Wed, 25 May 2022 17:13:14 +0200 Subject: [PATCH 116/329] d/copyright: - bump nginx copyright years - added copyright for src/stream/ngx_stream_set_module.c --- debian/changelog | 2 ++ debian/copyright | 9 +++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index 713a937..53399e7 100644 --- a/debian/changelog +++ b/debian/changelog @@ -15,6 +15,8 @@ nginx (1.22.0-1) UNRELEASED; urgency=medium * d/patches/CVE-2021-3618.patch removed, fix is included in new upstream release * d/control: removed ppc64el from list of luajit platforms. (Closes: #1011303) + * d/copyright: bump nginx copyright years + * d/copyright: added copyright for src/stream/ngx_stream_set_module.c -- Thomas Ward Tue, 10 May 2022 12:08:02 -0400 diff --git a/debian/copyright b/debian/copyright index f82fc2d..a3f59eb 100644 --- a/debian/copyright +++ b/debian/copyright @@ -3,8 +3,8 @@ Upstream-Name: nginx Source: https://nginx.org/en/download.html Files: * -Copyright: 2002-2019, Igor Sysoev - 2011-2019, Nginx, Inc. +Copyright: 2002-2021, Igor Sysoev + 2011-2022, Nginx, Inc. Maxim Dounin Valentin V. Bartenev Roman Arutyunyan @@ -15,6 +15,11 @@ Files: src/core/ngx_murmurhash.c Copyright: Copyright (C) Austin Appleby License: BSD-2-clause +Files: src/stream/ngx_stream_set_module.c +Copyright: Copyright (C) Pavel Pautov + Copyright (C) Nginx, Inc. +License: BSD-2-clause + Files: src/http/modules/ngx_http_scgi_module.c src/http/modules/ngx_http_uwsgi_module.c Copyright: 2009-2010, Unbit S.a.s. From c3f9fc730b23255d7b2fce09b34a98583f9dcfc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Wed, 25 May 2022 17:45:49 +0200 Subject: [PATCH 117/329] d/copyright: removed copyright for src/http/v2/ngx_http_v2_huff_encode.c --- debian/changelog | 1 + debian/copyright | 6 ------ 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/debian/changelog b/debian/changelog index 53399e7..1c01d3f 100644 --- a/debian/changelog +++ b/debian/changelog @@ -17,6 +17,7 @@ nginx (1.22.0-1) UNRELEASED; urgency=medium * d/control: removed ppc64el from list of luajit platforms. (Closes: #1011303) * d/copyright: bump nginx copyright years * d/copyright: added copyright for src/stream/ngx_stream_set_module.c + * d/copyright: removed copyright for src/http/v2/ngx_http_v2_huff_encode.c -- Thomas Ward Tue, 10 May 2022 12:08:02 -0400 diff --git a/debian/copyright b/debian/copyright index a3f59eb..d5c191a 100644 --- a/debian/copyright +++ b/debian/copyright @@ -28,12 +28,6 @@ Copyright: 2009-2010, Unbit S.a.s. Nginx, Inc. License: BSD-2-clause -Files: src/http/v2/ngx_http_v2_huff_encode.c -Copyright: 2015, Vlad Krasnov - Nginx, Inc. - Valentin V. Bartenev -License: BSD-2-clause - Files: contrib/geo2nginx.pl Copyright: 2005, Andrei Nigmatulin License: BSD-2-clause From a8ebc4ba0c136b1df2c7bd2effffa467dc821f0d Mon Sep 17 00:00:00 2001 From: Thomas Ward Date: Thu, 26 May 2022 23:15:02 -0400 Subject: [PATCH 118/329] Update d/copyright for murmurhash license being public-domain --- debian/changelog | 5 ++++- debian/copyright | 9 +++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/debian/changelog b/debian/changelog index 1c01d3f..4874df2 100644 --- a/debian/changelog +++ b/debian/changelog @@ -9,7 +9,10 @@ nginx (1.22.0-1) UNRELEASED; urgency=medium in upstream (Konstantin Pavlov ) during upstream merge/import by Thomas Ward, additional signing key was added to the keyring while keeping Maxim's key in signing - keys as wel. + keys as well. + * d/copyright: Updated copyright for src/core/ngx_murmurhash.c + and debian/modules/http-ndk/src/hash/murmurhash2.c to be + public-domain (Closes: #1011936) [ Jan Mojžíš ] * d/patches/CVE-2021-3618.patch removed, fix is included in new upstream diff --git a/debian/copyright b/debian/copyright index d5c191a..59dfc09 100644 --- a/debian/copyright +++ b/debian/copyright @@ -13,7 +13,10 @@ License: BSD-2-clause Files: src/core/ngx_murmurhash.c Copyright: Copyright (C) Austin Appleby -License: BSD-2-clause +License: public-domain + All MurmurHash versions are public domain software, and the author + disclaims all copyright to their code. + Files: src/stream/ngx_stream_set_module.c Copyright: Copyright (C) Pavel Pautov @@ -65,7 +68,9 @@ License: BSD-4-clause Files: debian/modules/http-ndk/src/hash/murmurhash2.c Copyright: Austin Appleby -License: BSD-3-clause +License: public-domain + All MurmurHash versions are public domain software, and the author + disclaims all copyright to their code. Files: debian/modules/http-auth-pam/* Copyright: 2008-2020, Sergio Talens Oliag From 20eb8ab414656c56632795454156ce014532972d Mon Sep 17 00:00:00 2001 From: Thomas Ward Date: Wed, 8 Jun 2022 15:22:49 -0400 Subject: [PATCH 119/329] ppc64el FTBFS fixed in luajit, nginx: no action needed --- debian/changelog | 1 - debian/control | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/debian/changelog b/debian/changelog index 4874df2..3b92437 100644 --- a/debian/changelog +++ b/debian/changelog @@ -17,7 +17,6 @@ nginx (1.22.0-1) UNRELEASED; urgency=medium [ Jan Mojžíš ] * d/patches/CVE-2021-3618.patch removed, fix is included in new upstream release - * d/control: removed ppc64el from list of luajit platforms. (Closes: #1011303) * d/copyright: bump nginx copyright years * d/copyright: added copyright for src/stream/ngx_stream_set_module.c * d/copyright: removed copyright for src/http/v2/ngx_http_v2_huff_encode.c diff --git a/debian/control b/debian/control index 3a2b586..cc32589 100644 --- a/debian/control +++ b/debian/control @@ -12,8 +12,8 @@ Build-Depends: debhelper-compat (= 13), libgd-dev, libgeoip-dev, libhiredis-dev, - liblua5.1-0-dev [!i386 !amd64 !kfreebsd-i386 !kfreebsd-amd64 !armel !armhf !powerpc !powerpcspe !mips !mipsel !mips64el !arm64 !ppc64], - libluajit-5.1-dev [i386 amd64 kfreebsd-i386 kfreebsd-amd64 armel armhf powerpc powerpcspe mips mipsel mips64el arm64 ppc64], + liblua5.1-0-dev [!i386 !amd64 !kfreebsd-i386 !kfreebsd-amd64 !armel !armhf !powerpc !powerpcspe !mips !mipsel !mips64el !arm64 !ppc64 !ppc64el], + libluajit-5.1-dev [i386 amd64 kfreebsd-i386 kfreebsd-amd64 armel armhf powerpc powerpcspe mips mipsel mips64el arm64 ppc64 ppc64el], libmaxminddb-dev, libmhash-dev, libpam0g-dev, From 4b7212e74500151248dab2f0baf45837e39a266d Mon Sep 17 00:00:00 2001 From: Thomas Ward Date: Wed, 8 Jun 2022 16:15:40 -0400 Subject: [PATCH 120/329] Enable luajit for s390x --- debian/changelog | 5 +++++ debian/control | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index 3b92437..48897b5 100644 --- a/debian/changelog +++ b/debian/changelog @@ -13,6 +13,11 @@ nginx (1.22.0-1) UNRELEASED; urgency=medium * d/copyright: Updated copyright for src/core/ngx_murmurhash.c and debian/modules/http-ndk/src/hash/murmurhash2.c to be public-domain (Closes: #1011936) + * d/control: Use libluajit-5.1-dev for s390x. + Due to src:luajit2 landing in Unstable, superseding src:luajit, + and due to luajit2 having s390x support, we can use s390x now + with luajit instead of standard Lua. + Thanks to Paul Gevers for the heads up on luajit2 supporting s390x. [ Jan Mojžíš ] * d/patches/CVE-2021-3618.patch removed, fix is included in new upstream diff --git a/debian/control b/debian/control index cc32589..bbec75a 100644 --- a/debian/control +++ b/debian/control @@ -12,8 +12,8 @@ Build-Depends: debhelper-compat (= 13), libgd-dev, libgeoip-dev, libhiredis-dev, - liblua5.1-0-dev [!i386 !amd64 !kfreebsd-i386 !kfreebsd-amd64 !armel !armhf !powerpc !powerpcspe !mips !mipsel !mips64el !arm64 !ppc64 !ppc64el], - libluajit-5.1-dev [i386 amd64 kfreebsd-i386 kfreebsd-amd64 armel armhf powerpc powerpcspe mips mipsel mips64el arm64 ppc64 ppc64el], + liblua5.1-0-dev [!i386 !amd64 !kfreebsd-i386 !kfreebsd-amd64 !armel !armhf !powerpc !powerpcspe !mips !mipsel !mips64el !arm64 !ppc64 !ppc64el !s390x], + libluajit-5.1-dev [i386 amd64 kfreebsd-i386 kfreebsd-amd64 armel armhf powerpc powerpcspe mips mipsel mips64el arm64 ppc64 ppc64el s390x], libmaxminddb-dev, libmhash-dev, libpam0g-dev, From 333875401c6fa18c4f37d39f6ea6411ef1e1b60a Mon Sep 17 00:00:00 2001 From: Thomas Ward Date: Sat, 25 Jun 2022 17:31:16 -0400 Subject: [PATCH 121/329] Return ppc64el to liblua, luajit2 still broken on ppc64el. --- debian/changelog | 2 ++ debian/control | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index 48897b5..fec8e1d 100644 --- a/debian/changelog +++ b/debian/changelog @@ -18,6 +18,8 @@ nginx (1.22.0-1) UNRELEASED; urgency=medium and due to luajit2 having s390x support, we can use s390x now with luajit instead of standard Lua. Thanks to Paul Gevers for the heads up on luajit2 supporting s390x. + * d/control: Use liblua for ppc64el - src:luajit2 is still not ppc64el + stable and there seems to be nobody willing to support it. [ Jan Mojžíš ] * d/patches/CVE-2021-3618.patch removed, fix is included in new upstream diff --git a/debian/control b/debian/control index bbec75a..5ae14c8 100644 --- a/debian/control +++ b/debian/control @@ -12,8 +12,8 @@ Build-Depends: debhelper-compat (= 13), libgd-dev, libgeoip-dev, libhiredis-dev, - liblua5.1-0-dev [!i386 !amd64 !kfreebsd-i386 !kfreebsd-amd64 !armel !armhf !powerpc !powerpcspe !mips !mipsel !mips64el !arm64 !ppc64 !ppc64el !s390x], - libluajit-5.1-dev [i386 amd64 kfreebsd-i386 kfreebsd-amd64 armel armhf powerpc powerpcspe mips mipsel mips64el arm64 ppc64 ppc64el s390x], + liblua5.1-0-dev [!i386 !amd64 !kfreebsd-i386 !kfreebsd-amd64 !armel !armhf !powerpc !powerpcspe !mips !mipsel !mips64el !arm64 !ppc64 !s390x], + libluajit-5.1-dev [i386 amd64 kfreebsd-i386 kfreebsd-amd64 armel armhf powerpc powerpcspe mips mipsel mips64el arm64 ppc64 s390x], libmaxminddb-dev, libmhash-dev, libpam0g-dev, From d4b9d6a1daf9e64816e6d69d4d10083a032e251c Mon Sep 17 00:00:00 2001 From: Miao Wang Date: Fri, 4 Feb 2022 00:00:41 +0800 Subject: [PATCH 122/329] Adding nginx-dev package for tools for building out-of-tree modules Nginx does not officially provide a mechanism to build out-of-tree modules, however, this can be achieved by using all the headers and the configure scripts in the auto/ directory. As a result, a nginx-dev package can thus be developed for build out-of-tree modules. The detailed steps to build an out-of-tree module in the headers-only nginx source tree is: 1. Execute the configure script of nginx, with the same configure arguments (excluding the reference to other dynamic modules, but including the reference to depending modules as a built-in module). To prevent the configure scripts modifying the nginx ource tree, we can 1. point the build dir to a directory elsewhere, to generate all the build time files outside; 2. slightly patch the configure scripts to prevent generating a makefile directly in the source tree, which simply includes the generated makefile at the build dir. 2. Execute make at the source tree, but providing the generated makefile in the build dir. The command is `make -C /path/to/nginx/source -f /path/to/build_dir/Makefile modules` To make sure the compiled module is compatible with the nginx binary and the nginx binaries with the same upstream version, the key points are: - Module signature: A module signature containing the (upstream) version number and encoding the necessary configuration flags is put in each module as well as the nginx binary itself. When loading a module, nginx will compare the signature on the module with its own. As long as the configure flags, especially those encoded in the signature, and the version of the nginx source used to build the module are the same as thoes used to build the nginx binary, the moudle can pass the signature check. As a result, the module can depend on the exact nginx upstream version, ignoring the debian revison. - ABI compatibility: We should maintain nginx precisely, to prevent making any ABI changes between different debian revisions. - Build check: When building the module, we can perform a simple module loading check via `nginx -t`. This test serves as a "smoking test", to ensure we are actually building loadable modules. Summing all the above up and adding the necessary automation scripts for module packaging, the nginx-dev package can be composed, including the following parts: - The headers and configure scripts: generated and filtered out from the source tree. The scripts are slightly patched to prevent generating a makefile directly in the source tree, as stated above; - The recorded configure options: all the modules built should include these options when configured; - dh_nginx script and its man page: modified from the original dh_nginx script, adding a "--in-nginx-tree" option. When specified, the behavior remains the same as the original version (so the option is added in the rule building the in-package modules). When not specified, the dependency added into misc:Depends will be the exact upstream nginx version, ignoring the debian revision. E.g. nginx-common >= 1.20.2, << 1.20.2.1~ - a debhelper sequence plugin which can be enabled by module packages with `dh --with=nginx`, inserting `dh_nginx` after `dh_install` - a build system plugin which can bu enabled by module packages with `dh --buildsystem=nginx_mod`, automating the module building process using the steps mentioned before. - autoscript templates used by dh_nginx are also installed without modification. Currently. the architecture of nginx-dev is any because nginx has arch related dependencies, which is brought in by http-lua module. After it is removed from the nginx source tree, the architecture can be changed to all since no binary is included in this package. --- debian/control | 13 +++++ debian/debhelper/nginx.pm | 8 +++ debian/debhelper/nginx_mod.pm | 96 +++++++++++++++++++++++++++++++++++ debian/dh_nginx | 18 ++++++- debian/nginx-dev.install | 8 +++ debian/nginx-dev.manpages | 1 + debian/rules | 31 ++++++++--- 7 files changed, 165 insertions(+), 10 deletions(-) create mode 100644 debian/debhelper/nginx.pm create mode 100644 debian/debhelper/nginx_mod.pm create mode 100644 debian/nginx-dev.install create mode 100644 debian/nginx-dev.manpages diff --git a/debian/control b/debian/control index 5ae14c8..9f31ba4 100644 --- a/debian/control +++ b/debian/control @@ -68,6 +68,19 @@ Description: small, powerful, scalable web/proxy server - common files This package contains base configuration files used by all versions of nginx. +Package: nginx-dev +Architecture: any +Depends: ${misc:Depends}, ${S:Build-Depends}, + nginx-core (= ${binary:Version}) | nginx-light (= ${binary:Version}) | nginx-extras (= ${binary:Version}) +Description: nginx web/proxy server - development headers + Nginx ("engine X") is a high-performance web and reverse proxy server + created by Igor Sysoev. It can be used both as a standalone web server + and as a proxy to reduce the load on back-end HTTP or mail servers. + . + This package provides development headers and necessary config scripts + for the nginx web/proxy server, useful to develop and link third party + additions to the Debian nginx web/proxy server packages. + Package: nginx-core Architecture: any Depends: libnginx-mod-http-geoip (= ${binary:Version}), diff --git a/debian/debhelper/nginx.pm b/debian/debhelper/nginx.pm new file mode 100644 index 0000000..0473815 --- /dev/null +++ b/debian/debhelper/nginx.pm @@ -0,0 +1,8 @@ +#!/usr/bin/perl +use warnings; +use strict; +use Debian::Debhelper::Dh_Lib; + +insert_after("dh_install", "dh_nginx"); + +1; diff --git a/debian/debhelper/nginx_mod.pm b/debian/debhelper/nginx_mod.pm new file mode 100644 index 0000000..af37fda --- /dev/null +++ b/debian/debhelper/nginx_mod.pm @@ -0,0 +1,96 @@ +# A build system class for handling nginx modules. +# +# Copyright: © 2022 Miao Wang +# License: MIT + +package Debian::Debhelper::Buildsystem::nginx_mod; + +use strict; +use warnings; +use Debian::Debhelper::Dh_Lib qw(error doit); +use File::Spec; +use parent qw(Debian::Debhelper::Buildsystem::makefile); +use Config; + +sub DESCRIPTION { + "Nginx Module (config)" +} + +sub check_auto_buildable { + my ($this, $step) = @_; + + return 1 if -e $this->get_sourcepath("config"); +} + +sub _NGINX_SRC_DIR { + "/usr/share/nginx/src" +} + +sub new { + my $class=shift; + my $this= $class->SUPER::new(@_); + $this->prefer_out_of_source_building(@_); + return $this; +} + +sub configure { + my $this=shift; + + doit({ + "chdir" => $this->_NGINX_SRC_DIR, + "update_env" => { + "src_dir" => $this->get_sourcedir, + "bld_dir" => $this->get_builddir, + "pwd_dir" => $this->{cwd}, + }, + }, "bash", "-c", '. ./conf_flags + ./configure \\ + --with-cc-opt="$(cd "$pwd_dir/$src_dir"; dpkg-buildflags --get CFLAGS) -fPIC $(cd "$pwd_dir/$src_dir"; dpkg-buildflags --get CPPFLAGS)" \\ + --with-ld-opt="$(cd "$pwd_dir/$src_dir"; dpkg-buildflags --get LDFLAGS) -fPIC" \\ + "${NGX_CONF_FLAGS[@]}" \\ + --add-dynamic-module="$pwd_dir/$src_dir" \\ + --builddir="$pwd_dir/$bld_dir" \\ + "$@"', "dummy", @_); +} + +sub build { + my $this=shift; + + $this->do_make("-f", File::Spec->catfile($this->{cwd}, $this->get_buildpath("Makefile")), "-C", $this->_NGINX_SRC_DIR, "modules"); +} + +sub test { + my $this=shift; + $this->doit_in_builddir("bash", "-e", "-o", "pipefail", "-c", ' + tmp_conf=$(mktemp -p .) + for pre_dep in "$@"; do + echo "load_module modules/$pre_dep;" >> "$tmp_conf" + done + for i in *.so; do + echo "load_module $PWD/$i;" >> "$tmp_conf" + done + echo "events{}" >> "$tmp_conf" + nginx -g "error_log /dev/null; pid /dev/null;" -t -q -c "$PWD/$tmp_conf" + rm -f "$tmp_conf" + ', "dummy", @_); +} + +sub install { + my $this=shift; + my $destdir=shift; + + $this->doit_in_builddir("bash", "-e", "-o", "pipefail", "-c", ' + destdir=$1 + mkdir -p "$destdir/usr/lib/nginx/modules" + for i in *.so; do + cp "$i" "$destdir/usr/lib/nginx/modules/" + done + ', "dummy", $destdir); +} + +sub clean { + my $this=shift; + $this->rmdir_builddir(); +} + +1 diff --git a/debian/dh_nginx b/debian/dh_nginx index 8e6ce3b..4853568 100755 --- a/debian/dh_nginx +++ b/debian/dh_nginx @@ -48,7 +48,7 @@ sub nginx_modules_conf_installdir =head1 SYNOPSIS -B [S>] [B<-n>|B<--noscripts>] +B [S>] [B<-n>|B<--noscripts>] [B<--in-nginx-tree>] =head1 DESCRIPTION @@ -63,6 +63,8 @@ It supports the following configuration types =item * Nginx modules +=back + =head1 INVOCATION %: @@ -128,6 +130,10 @@ configuration by default. Do not modify F/F/F maintainer scripts. +=item B<--in-nginx-tree> + +Specify this option when building in-tree modules along with nginx. When +specified, nginx abi version is not required in package name. =back @@ -150,8 +156,11 @@ dh_nginx is heavily influnced by dh_apache2 written by Arno Toell ## main code starts here ## +my $nginx_in_tree; + init(options => { "e|noenable" => \$dh{NOENABLE}, + "in-nginx-tree" => \$nginx_in_tree, }); foreach my $package ((@{$dh{DOPACKAGES}})) @@ -231,7 +240,12 @@ foreach my $package ((@{$dh{DOPACKAGES}})) { warning("Package $package appears to be an Nginx module. It should comply to the package naming scheme libnginx-mod-\n"); } - addsubstvar($package, "misc:Depends", nginx_depends()); + if ($nginx_in_tree){ + addsubstvar($package, "misc:Depends", nginx_depends()); + } else { + my $ngx_ver = `grep 'define NGINX_VERSION' /usr/share/nginx/src/src/core/nginx.h | sed -e 's/^.*"\\(.*\\)".*/\\1/'`; + addsubstvar($package, "misc:Depends", "nginx-common (>= $ngx_ver), nginx-common (<< $ngx_ver.1~)"); + } my $modules = ""; foreach my $module (@{$PACKAGE_TYPE{'has_a_module'}}) diff --git a/debian/nginx-dev.install b/debian/nginx-dev.install new file mode 100644 index 0000000..6a2ad43 --- /dev/null +++ b/debian/nginx-dev.install @@ -0,0 +1,8 @@ +debian/build-src/auto usr/share/nginx/src/ +debian/build-src/src usr/share/nginx/src/ +debian/build-src/conf_flags usr/share/nginx/src/ +debian/build-src/configure usr/share/nginx/src/ +debian/debhelper/nginx.pm usr/share/perl5/Debian/Debhelper/Sequence/ +debian/dh_nginx usr/bin/ +debian/debhelper/nginx_mod.pm usr/share/perl5/Debian/Debhelper/Buildsystem/ +debian/autoscripts/* usr/share/debhelper/autoscripts/ diff --git a/debian/nginx-dev.manpages b/debian/nginx-dev.manpages new file mode 100644 index 0000000..0ece920 --- /dev/null +++ b/debian/nginx-dev.manpages @@ -0,0 +1 @@ +debian/build-src/dh_nginx.1 diff --git a/debian/rules b/debian/rules index f777843..68ed613 100755 --- a/debian/rules +++ b/debian/rules @@ -32,7 +32,7 @@ DYN_MODS := \ MODULESDIR = $(CURDIR)/debian/modules BASEDIR = $(CURDIR) -$(foreach flavour,$(FLAVOURS),$(eval BUILDDIR_$(flavour) = $(CURDIR)/debian/build-$(flavour))) +$(foreach flavour,$(FLAVOURS) src,$(eval BUILDDIR_$(flavour) = $(CURDIR)/debian/build-$(flavour))) DEB_BUILD_ARCH ?=$(shell dpkg-architecture -qDEB_BUILD_ARCH) ifeq ($(DEB_BUILD_ARCH),sparc) @@ -48,9 +48,7 @@ MODULESPATCHDIR = $(CURDIR)/debian/modules/patches modules_with_patches := $(notdir $(wildcard $(CURDIR)/debian/modules/patches/*)) # configure flags -common_configure_flags := \ - --with-cc-opt="$(debian_cflags)" \ - --with-ld-opt="$(debian_ldflags)" \ +basic_configure_flags := \ --prefix=/usr/share/nginx \ --conf-path=/etc/nginx/nginx.conf \ --http-log-path=/var/log/nginx/access.log \ @@ -75,6 +73,11 @@ common_configure_flags := \ --with-http_slice_module \ --with-threads +common_configure_flags := \ + --with-cc-opt="$(debian_cflags)" \ + --with-ld-opt="$(debian_ldflags)" \ + $(basic_configure_flags) + light_configure_flags := \ $(common_configure_flags) \ --with-http_gzip_static_module \ @@ -132,15 +135,15 @@ extras_configure_flags := \ %: dh $@ --without autoreconf -override_dh_auto_configure: config_patch_modules $(foreach flavour,$(FLAVOURS),config.arch.$(flavour)) -override_dh_auto_build: $(foreach flavour,$(FLAVOURS),build.arch.$(flavour)) +override_dh_auto_configure: config_patch_modules $(foreach flavour,$(FLAVOURS),config.arch.$(flavour)) config.src +override_dh_auto_build: $(foreach flavour,$(FLAVOURS),build.arch.$(flavour)) build.src override_dh_strip: $(foreach flavour,$(FLAVOURS),strip.arch.$(flavour)) $(foreach mod,$(DYN_MODS),strip.mods.$(mod)) -override_dh_clean: clean_patch_modules $(foreach flavour,$(FLAVOURS),clean.$(flavour)) +override_dh_clean: clean_patch_modules $(foreach flavour,$(FLAVOURS),clean.$(flavour)) clean.src dh_clean override_dh_install: dh_install - DH_AUTOSCRIPTDIR=$(CURDIR)/debian/autoscripts debian/dh_nginx + DH_AUTOSCRIPTDIR=$(CURDIR)/debian/autoscripts debian/dh_nginx --in-nginx-tree override_dh_installinit: dh_installinit --no-stop-on-upgrade --no-start --name=nginx @@ -154,6 +157,14 @@ override_dh_installlogrotate: build.arch.%: $(MAKE) -C $(BUILDDIR_$*) build +build.src: + cp -Pa $(CURDIR)/auto $(BUILDDIR_src)/ + sed -i '/^# create Makefile/,/^END$$/d' $(BUILDDIR_src)/auto/make $(BUILDDIR_src)/auto/init $(BUILDDIR_src)/auto/install + find $(CURDIR)/src -type f -name '*.h' -printf 'src/%P\0' | tar -C $(CURDIR) --null --files-from - -c | tar -C $(BUILDDIR_src)/ -x + if [ -e $(CURDIR)/configure ]; then cp $(CURDIR)/configure $(BUILDDIR_src)/; fi + echo "NGX_CONF_FLAGS=(" $(basic_configure_flags) ")" > $(BUILDDIR_src)/conf_flags + pod2man debian/dh_nginx > $(BUILDDIR_src)/dh_nginx.1 + strip.arch.%: dh_strip --package=nginx-$(*) -O--dbgsym-migration='nginx-$(*)-dbg (<< 1.10.1-3~)' @@ -182,6 +193,10 @@ config.arch.%: cp -Pa $(CURDIR)/man $(BUILDDIR_$*)/ cd $(BUILDDIR_$*) && ./configure $($*_configure_flags) +config.src: + dh_testdir + mkdir -p $(BUILDDIR_src) + clean.%: rm -rf $(BUILDDIR_$*) From 87b5e38f6d10b13e7fd567c9e430153c48d7bafc Mon Sep 17 00:00:00 2001 From: Miao Wang Date: Thu, 26 May 2022 15:48:54 +0800 Subject: [PATCH 123/329] nginx-dev: simplify dependencies nginx-dev depends on ${S:Build-Depends} before this commit, to include all the build-depdencies of nginx source packages. However, this also includes build dependency for those in-tree 3rd party modules, which are unnecessary. This commit removes them and explicitly list those packages needed to build a general module. The architecture of nginx-dev can thus be changed to all instead of any. When all 3rd party modules are removed, the dependency can be changed back to ${S:Build-Depends} to make the config less redundant. --- debian/control | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/debian/control b/debian/control index 9f31ba4..f6b11ba 100644 --- a/debian/control +++ b/debian/control @@ -69,9 +69,21 @@ Description: small, powerful, scalable web/proxy server - common files nginx. Package: nginx-dev -Architecture: any -Depends: ${misc:Depends}, ${S:Build-Depends}, - nginx-core (= ${binary:Version}) | nginx-light (= ${binary:Version}) | nginx-extras (= ${binary:Version}) +Architecture: all +Depends: ${misc:Depends}, + debhelper-compat (= 13), + dpkg-dev (>= 1.15.5), + libgd-dev, + libgeoip-dev, + libpcre3-dev, + libperl-dev, + libssl-dev, + libxslt1-dev, + po-debconf, + quilt, + zlib1g-dev, + nginx-core (<< ${source:Version}.1~) | nginx-light (<< ${source:Version}.1~) | nginx-extras (<< ${source:Version}.1~), + nginx-core (>= ${source:Version}) | nginx-light (>= ${source:Version}) | nginx-extras (>= ${source:Version}) Description: nginx web/proxy server - development headers Nginx ("engine X") is a high-performance web and reverse proxy server created by Igor Sysoev. It can be used both as a standalone web server From 2784d3f935d26fab5d485caa6843221f2691686b Mon Sep 17 00:00:00 2001 From: Miao Wang Date: Fri, 27 May 2022 00:09:29 +0800 Subject: [PATCH 124/329] nginx-dev: fix nginx version subtracting in dh_nginx --- debian/dh_nginx | 1 + 1 file changed, 1 insertion(+) diff --git a/debian/dh_nginx b/debian/dh_nginx index 4853568..e07ffe1 100755 --- a/debian/dh_nginx +++ b/debian/dh_nginx @@ -244,6 +244,7 @@ foreach my $package ((@{$dh{DOPACKAGES}})) addsubstvar($package, "misc:Depends", nginx_depends()); } else { my $ngx_ver = `grep 'define NGINX_VERSION' /usr/share/nginx/src/src/core/nginx.h | sed -e 's/^.*"\\(.*\\)".*/\\1/'`; + chomp($ngx_ver); addsubstvar($package, "misc:Depends", "nginx-common (>= $ngx_ver), nginx-common (<< $ngx_ver.1~)"); } From 15c55ec59b0f542e9cecf7205e5e54a0d6beba2e Mon Sep 17 00:00:00 2001 From: Miao Wang Date: Fri, 6 May 2022 18:59:25 +0800 Subject: [PATCH 125/329] dh_nginx: move to debian/debhelper Move dh_nginx script to debian/debhelper so that all debhelper scripts are located together. --- debian/{ => debhelper}/dh_nginx | 0 debian/nginx-dev.install | 2 +- debian/rules | 4 ++-- 3 files changed, 3 insertions(+), 3 deletions(-) rename debian/{ => debhelper}/dh_nginx (100%) diff --git a/debian/dh_nginx b/debian/debhelper/dh_nginx similarity index 100% rename from debian/dh_nginx rename to debian/debhelper/dh_nginx diff --git a/debian/nginx-dev.install b/debian/nginx-dev.install index 6a2ad43..efc1578 100644 --- a/debian/nginx-dev.install +++ b/debian/nginx-dev.install @@ -3,6 +3,6 @@ debian/build-src/src usr/share/nginx/src/ debian/build-src/conf_flags usr/share/nginx/src/ debian/build-src/configure usr/share/nginx/src/ debian/debhelper/nginx.pm usr/share/perl5/Debian/Debhelper/Sequence/ -debian/dh_nginx usr/bin/ +debian/debhelper/dh_nginx usr/bin/ debian/debhelper/nginx_mod.pm usr/share/perl5/Debian/Debhelper/Buildsystem/ debian/autoscripts/* usr/share/debhelper/autoscripts/ diff --git a/debian/rules b/debian/rules index 68ed613..d4ddc7e 100755 --- a/debian/rules +++ b/debian/rules @@ -143,7 +143,7 @@ override_dh_clean: clean_patch_modules $(foreach flavour,$(FLAVOURS),cl override_dh_install: dh_install - DH_AUTOSCRIPTDIR=$(CURDIR)/debian/autoscripts debian/dh_nginx --in-nginx-tree + DH_AUTOSCRIPTDIR=$(CURDIR)/debian/autoscripts debian/debhelper/dh_nginx --in-nginx-tree override_dh_installinit: dh_installinit --no-stop-on-upgrade --no-start --name=nginx @@ -163,7 +163,7 @@ build.src: find $(CURDIR)/src -type f -name '*.h' -printf 'src/%P\0' | tar -C $(CURDIR) --null --files-from - -c | tar -C $(BUILDDIR_src)/ -x if [ -e $(CURDIR)/configure ]; then cp $(CURDIR)/configure $(BUILDDIR_src)/; fi echo "NGX_CONF_FLAGS=(" $(basic_configure_flags) ")" > $(BUILDDIR_src)/conf_flags - pod2man debian/dh_nginx > $(BUILDDIR_src)/dh_nginx.1 + pod2man debian/debhelper/dh_nginx > $(BUILDDIR_src)/dh_nginx.1 strip.arch.%: dh_strip --package=nginx-$(*) -O--dbgsym-migration='nginx-$(*)-dbg (<< 1.10.1-3~)' From 509adba304b06ff3fcb99b0baa8ef689e4bed40d Mon Sep 17 00:00:00 2001 From: Miao Wang Date: Fri, 6 May 2022 19:09:50 +0800 Subject: [PATCH 126/329] dh_nginx: support auto generating module config files This patch adds support of auto generating module config files for modules in the naming pattern of libnginx-mod-* but with missing .nginx file. The module load file and its loading priority is inferred from the package name in this case. Using this feature, the repeated files d/libnginx-mod-*.nginx and d/libnginx-mod.conf/ can be removed, and the packaging for out-of-tree modules can be simplified. --- debian/debhelper/dh_nginx | 122 ++++++++++++++++++++++++-------------- 1 file changed, 79 insertions(+), 43 deletions(-) diff --git a/debian/debhelper/dh_nginx b/debian/debhelper/dh_nginx index e07ffe1..f2b9bb5 100755 --- a/debian/debhelper/dh_nginx +++ b/debian/debhelper/dh_nginx @@ -84,6 +84,11 @@ Lists files to be registered with the Nginx HTTP server. The file is interpreted as line separated list of installation stanzas, where each entry consists of whitespace separated values conforming to the file semantics below. +When this file is missing but the name of the package looks like a nginx module, +the module load file and its loading priority is automatically generated inferring +from the package name. In this case, IB<.install> or other mechanisms +should be used for copying the B<.so> library into the correct place. + =head2 FILE SEMANTICS Each line consists of a triple @@ -171,65 +176,96 @@ foreach my $package ((@{$dh{DOPACKAGES}})) my $file = pkgfile($package, "nginx"); my $tmp = tmpdir($package); + my $installdir = $tmp . "/" . nginx_modules_conf_installdir(); + my $modinstalldir = $tmp . "/" . nginx_api_installdir(); - my @files_to_register = filedoublearray($file, ".") if $file; - foreach my $line (@files_to_register) - { - my $type = lc(shift @{$line}) if $line->[0]; - my $source = shift @{$line} if $line->[0]; - my @arguments = @{$line}; - my $destination; - - $type = "modules" if $type eq "mod"; - my $installdir = $tmp . "/" . nginx_modules_conf_installdir(); - - verbose_print("$type -- $source -- @arguments\n\n"); - - if ($type eq "modules") + if ($file){ + my @files_to_register = filedoublearray($file, ".") if $file; + foreach my $line (@files_to_register) { - my $basesource = basename($source); + my $type = lc(shift @{$line}) if $line->[0]; + my $source = shift @{$line} if $line->[0]; + my @arguments = @{$line}; + my $destination; + + $type = "modules" if $type eq "mod"; + + verbose_print("$type -- $source -- @arguments\n\n"); if ($type eq "modules") { - if ($basesource =~ m/\.conf$/) + my $basesource = basename($source); + + if ($type eq "modules") { - my $enablename = $basesource; - my $prio = $#arguments >= 0 ? $arguments[0] : 50; - $destination = "$prio-$basesource"; - push @{$PACKAGE_TYPE{'has_a_module'}}, "$enablename:$destination"; - verbose_print("Installing module configuration $enablename into $installdir prio:$prio\n"); - } - elsif ($basesource =~ m/\.so$/) - { - my $modinstalldir = $tmp . "/" . nginx_api_installdir(); - verbose_print("Installing module binary $source into $modinstalldir\n"); - if (! -d $modinstalldir) + if ($basesource =~ m/\.conf$/) { - complex_doit("mkdir","-p", $modinstalldir); - complex_doit("chmod","755","$modinstalldir"); + my $enablename = $basesource; + my $prio = $#arguments >= 0 ? $arguments[0] : 50; + $destination = "$prio-$basesource"; + push @{$PACKAGE_TYPE{'has_a_module'}}, "$enablename:$destination"; + verbose_print("Installing module configuration $enablename into $installdir prio:$prio\n"); } - complex_doit("cp", $source, $modinstalldir); - next; + elsif ($basesource =~ m/\.so$/) + { + verbose_print("Installing module binary $source into $modinstalldir\n"); + if (! -d $modinstalldir) + { + complex_doit("mkdir","-p", $modinstalldir); + complex_doit("chmod","755","$modinstalldir"); + } + complex_doit("cp", $source, $modinstalldir); + next; + } + + # TODO + error("module: \"$basesource\" needs .conf, .so or suffix") if $basesource !~ m/\.(conf|so)/; } - # TODO - error("module: \"$basesource\" needs .conf, .so or suffix") if $basesource !~ m/\.(conf|so)/; - } + if (! -d $installdir) + { + complex_doit("mkdir","-p",$installdir); + complex_doit("chmod","755","$installdir"); + } + complex_doit("cp",$source,$installdir); + complex_doit("chmod","644","$installdir/$basesource"); - if (! -d $installdir) + } + else { - complex_doit("mkdir","-p",$installdir); - complex_doit("chmod","755","$installdir"); + error("Unknown parameter: $type\n"); } - complex_doit("cp",$source,$installdir); - complex_doit("chmod","644","$installdir/$basesource"); } - else - { - error("Unknown parameter: $type\n"); - } + } elsif ($package =~ /^libnginx-mod-/){ + verbose_print("$package might be a nginx module\n"); + my $module = $package; + $module =~ s/^libnginx-mod-//; + verbose_print("Guessed module name: $module\n"); + + my $modulepath = $module; + $modulepath =~ s/-/_/g; + + if (-e "$modinstalldir/ngx_${modulepath}_module.so"){ + my $prio = 50; + if ($module =~ /^\w+-/ && !($module =~ /^http-/) ){ + $prio = 70; + } + verbose_print("Guessed load priority: $prio\n"); + + my $conf_name = "mod-$module.conf"; + install_dir($installdir); + verbose_print("Installing module configuration $conf_name into $installdir prio:$prio\n"); + open(MOD_CONF, $dh{NO_ACT} ? ">&STDERR" : ">$installdir/$conf_name") or error("open($installdir/$conf_name): $!"); + print(MOD_CONF "load_module modules/ngx_${modulepath}_module.so;\n"); + close(MOD_CONF); + chmod(0644, "$installdir/$conf_name") or error("chmod(0644, $installdir/$conf_name): $!"); + push @{$PACKAGE_TYPE{'has_a_module'}}, "$conf_name:$prio-$conf_name"; + } else { + verbose_print("$package is not a nginx module because $modinstalldir/ngx_${modulepath}_module.so not found"); + verbose_print("If it is not correct, check if the module is installed before invoking this script"); + } } my @postinst_autoscripts; From ed5bc15213993766af66189792d5a7ed496681e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Sun, 15 May 2022 09:12:16 +0200 Subject: [PATCH 127/329] Remove 0002-Make-sure-signature-stays-the-same-in-all-nginx-buil.patch --- ...ure-stays-the-same-in-all-nginx-buil.patch | 28 ------------------- debian/patches/series | 1 - 2 files changed, 29 deletions(-) delete mode 100644 debian/patches/0002-Make-sure-signature-stays-the-same-in-all-nginx-buil.patch diff --git a/debian/patches/0002-Make-sure-signature-stays-the-same-in-all-nginx-buil.patch b/debian/patches/0002-Make-sure-signature-stays-the-same-in-all-nginx-buil.patch deleted file mode 100644 index 9e27e1a..0000000 --- a/debian/patches/0002-Make-sure-signature-stays-the-same-in-all-nginx-buil.patch +++ /dev/null @@ -1,28 +0,0 @@ -From: Christos Trochalakis -Date: Wed, 30 Mar 2016 09:47:11 +0300 -Subject: Make sure signature stays the same in all nginx builds - -NGX_HTTP_HEADERS is part of nginx signature. When a dyn -modules is loaded the signature of the module is compared -to the one of the nginx binary. - -dyn modules are build from nginx-full, so in order to make -them loadable in other flavors we need to make sure all the -binaries share the same signature. ---- - configure | 4 ++++ - 1 file changed, 4 insertions(+) - ---- a/configure -+++ b/configure -@@ -58,6 +58,10 @@ - . auto/unix - fi - -+# Debian -+# Make sure signature stays the same on all nginx flavors -+have=NGX_HTTP_HEADERS . auto/have -+ - . auto/threads - . auto/modules - . auto/lib/conf diff --git a/debian/patches/series b/debian/patches/series index 5b6b799..04030f9 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -1,2 +1 @@ -0002-Make-sure-signature-stays-the-same-in-all-nginx-buil.patch 0003-define_gnu_source-on-other-glibc-based-platforms.patch From 9f1044b9401f8b40ebefa306761ecd9a951750ba Mon Sep 17 00:00:00 2001 From: Miao Wang Date: Sun, 26 Jun 2022 15:26:40 +0800 Subject: [PATCH 128/329] changelog: update changelog --- debian/changelog | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/debian/changelog b/debian/changelog index fec8e1d..581bd2e 100644 --- a/debian/changelog +++ b/debian/changelog @@ -28,6 +28,14 @@ nginx (1.22.0-1) UNRELEASED; urgency=medium * d/copyright: added copyright for src/stream/ngx_stream_set_module.c * d/copyright: removed copyright for src/http/v2/ngx_http_v2_huff_encode.c + [ Miao Wang ] + * dh_nginx: support auto generating module config files + * adding a new nginx-dev package including necessary headers and debhelper + scripts to build and package a 3rd party module. + * d/p/0002-Make-sure-signature-stays-the-same-in-all-nginx-buil.patch + removed, because feature already implemented with --with-compat configure + option since 1.11.5 + -- Thomas Ward Tue, 10 May 2022 12:08:02 -0400 nginx (1.20.2-2) unstable; urgency=medium From 83ca2994f8be7c48e6cfe82236d5268bc3e29f93 Mon Sep 17 00:00:00 2001 From: Thomas Ward Date: Tue, 17 May 2022 15:42:18 -0400 Subject: [PATCH 129/329] Copyright file needed updated (caught by Bage, who emailed a patch to teward) --- debian/changelog | 3 +++ debian/copyright | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/debian/changelog b/debian/changelog index 581bd2e..542e5a6 100644 --- a/debian/changelog +++ b/debian/changelog @@ -28,6 +28,9 @@ nginx (1.22.0-1) UNRELEASED; urgency=medium * d/copyright: added copyright for src/stream/ngx_stream_set_module.c * d/copyright: removed copyright for src/http/v2/ngx_http_v2_huff_encode.c + [ Bastian Germann ] + * d/copyright: Update copyright for d/debhelper/* + [ Miao Wang ] * dh_nginx: support auto generating module config files * adding a new nginx-dev package including necessary headers and debhelper diff --git a/debian/copyright b/debian/copyright index 59dfc09..6449e69 100644 --- a/debian/copyright +++ b/debian/copyright @@ -47,6 +47,10 @@ Copyright: 2007-2009, Fabio Tranchitella 2020-2022, Ondřej Nový License: BSD-2-clause +Files: debian/debhelper/* +Copyright: 2022 Miao Wang +License: Expat + Files: debian/modules/http-headers-more-filter/* Copyright: 2009-2017, Yichun "agentzh" Zhang (章亦春) , CloudFlare Inc. 2010-2013, Bernd Dorn From bf9c433dbbb5d6accb5546a805dacf59e04f5d99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Sun, 26 Jun 2022 14:35:33 +0200 Subject: [PATCH 130/329] d/control: bump Standards-Version to 4.6.1, no changes --- debian/changelog | 1 + debian/control | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 542e5a6..fe5fc20 100644 --- a/debian/changelog +++ b/debian/changelog @@ -27,6 +27,7 @@ nginx (1.22.0-1) UNRELEASED; urgency=medium * d/copyright: bump nginx copyright years * d/copyright: added copyright for src/stream/ngx_stream_set_module.c * d/copyright: removed copyright for src/http/v2/ngx_http_v2_huff_encode.c + * d/control: bump Standards-Version to 4.6.1, no changes [ Bastian Germann ] * d/copyright: Update copyright for d/debhelper/* diff --git a/debian/control b/debian/control index f6b11ba..21eb530 100644 --- a/debian/control +++ b/debian/control @@ -24,7 +24,7 @@ Build-Depends: debhelper-compat (= 13), po-debconf, quilt, zlib1g-dev -Standards-Version: 4.6.0 +Standards-Version: 4.6.1 Homepage: https://nginx.org Vcs-Git: https://salsa.debian.org/nginx-team/nginx.git Vcs-Browser: https://salsa.debian.org/nginx-team/nginx From 7df2636a9d22b2fb385f06af25a61f929b9b4bc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Sun, 26 Jun 2022 16:16:08 +0200 Subject: [PATCH 131/329] d/changelog fix whitespace --- debian/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index fe5fc20..68a4ac4 100644 --- a/debian/changelog +++ b/debian/changelog @@ -11,7 +11,7 @@ nginx (1.22.0-1) UNRELEASED; urgency=medium was added to the keyring while keeping Maxim's key in signing keys as well. * d/copyright: Updated copyright for src/core/ngx_murmurhash.c - and debian/modules/http-ndk/src/hash/murmurhash2.c to be + and debian/modules/http-ndk/src/hash/murmurhash2.c to be public-domain (Closes: #1011936) * d/control: Use libluajit-5.1-dev for s390x. Due to src:luajit2 landing in Unstable, superseding src:luajit, From 172eb7b12a8ba0bf4667e54835b5d2024adadc23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Sun, 26 Jun 2022 16:16:58 +0200 Subject: [PATCH 132/329] d/changelog close #1013807 bug --- debian/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 68a4ac4..a12536e 100644 --- a/debian/changelog +++ b/debian/changelog @@ -19,7 +19,7 @@ nginx (1.22.0-1) UNRELEASED; urgency=medium with luajit instead of standard Lua. Thanks to Paul Gevers for the heads up on luajit2 supporting s390x. * d/control: Use liblua for ppc64el - src:luajit2 is still not ppc64el - stable and there seems to be nobody willing to support it. + stable and there seems to be nobody willing to support it. (Closes: 1013807) [ Jan Mojžíš ] * d/patches/CVE-2021-3618.patch removed, fix is included in new upstream From 42508c8556723f6e499bba2850f13a97665374fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Sun, 26 Jun 2022 16:20:26 +0200 Subject: [PATCH 133/329] create var/www/html in nginx-common.postinst --- debian/nginx-common.dirs | 1 - debian/nginx-common.lintian-overrides | 2 -- debian/nginx-common.postinst | 1 + 3 files changed, 1 insertion(+), 3 deletions(-) delete mode 100644 debian/nginx-common.lintian-overrides diff --git a/debian/nginx-common.dirs b/debian/nginx-common.dirs index 65bb651..8e5d7bf 100644 --- a/debian/nginx-common.dirs +++ b/debian/nginx-common.dirs @@ -10,4 +10,3 @@ usr/share/vim/addons usr/share/vim/registry var/lib/nginx var/log/nginx -var/www/html diff --git a/debian/nginx-common.lintian-overrides b/debian/nginx-common.lintian-overrides deleted file mode 100644 index 35cc9bc..0000000 --- a/debian/nginx-common.lintian-overrides +++ /dev/null @@ -1,2 +0,0 @@ -# /var/www/html is the default document root -nginx-common: dir-or-file-in-var-www var/www/html/ diff --git a/debian/nginx-common.postinst b/debian/nginx-common.postinst index 9e0610e..0d44608 100644 --- a/debian/nginx-common.postinst +++ b/debian/nginx-common.postinst @@ -39,6 +39,7 @@ case "$1" in # Create a default index page when not already present. if [ ! -e /var/www/html/index.nginx-debian.html ]; then + mkdir -p /var/www/html cp /usr/share/nginx/html/index.html /var/www/html/index.nginx-debian.html fi From 1a3b0014140ee9b085732cf31457435d70f9a713 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Sun, 26 Jun 2022 16:41:06 +0200 Subject: [PATCH 134/329] d/changelog close #985133 bug --- debian/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index a12536e..1409f33 100644 --- a/debian/changelog +++ b/debian/changelog @@ -35,7 +35,7 @@ nginx (1.22.0-1) UNRELEASED; urgency=medium [ Miao Wang ] * dh_nginx: support auto generating module config files * adding a new nginx-dev package including necessary headers and debhelper - scripts to build and package a 3rd party module. + scripts to build and package a 3rd party module. (Closes: 985133) * d/p/0002-Make-sure-signature-stays-the-same-in-all-nginx-buil.patch removed, because feature already implemented with --with-compat configure option since 1.11.5 From 035ed7f34a7c35aee9e008eb26f5a5c99f15ca82 Mon Sep 17 00:00:00 2001 From: Thomas Ward Date: Sat, 9 Jul 2022 20:14:24 -0400 Subject: [PATCH 135/329] Unstable upload --- debian/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 1409f33..46c9e92 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -nginx (1.22.0-1) UNRELEASED; urgency=medium +nginx (1.22.0-1) unstable; urgency=medium [ Thomas Ward ] * New upstream release (1.22.0) From ccd67189200544340c52c67bebd8eeea797a5b01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Sun, 10 Jul 2022 08:21:23 +0200 Subject: [PATCH 136/329] d/nginx-common.nginx.service update --- debian/changelog | 12 ++++++++++++ debian/nginx-common.nginx.service | 3 ++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 46c9e92..609ac41 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,15 @@ +nginx (1.22.0-2) UNRELEASED; urgency=medium + + * d/nginx-common.nginx.service: added Systemd dependency + Wants=network-online.target and updated Systemd "After" dependency to + recommended NGINX values, namely: + - syslog.target + - network-online.target (Closes: 61261) (Closes: 1000406) + - remote-fs.target (Closes: 898896) + - nss-lookup.target + + -- Jan Mojžíš Sun, 10 Jul 2022 07:58:44 +0200 + nginx (1.22.0-1) unstable; urgency=medium [ Thomas Ward ] diff --git a/debian/nginx-common.nginx.service b/debian/nginx-common.nginx.service index 78bf0ce..a46a725 100644 --- a/debian/nginx-common.nginx.service +++ b/debian/nginx-common.nginx.service @@ -13,7 +13,8 @@ [Unit] Description=A high performance web server and a reverse proxy server Documentation=man:nginx(8) -After=network.target nss-lookup.target +After=syslog.target network-online.target remote-fs.target nss-lookup.target +Wants=network-online.target [Service] Type=forking From 88d4d1577a0387abc4cf2d6b039711bfd7c142af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Sun, 10 Jul 2022 08:29:08 +0200 Subject: [PATCH 137/329] d/p/0003-define_gnu_source-on-other-glibc-based-platforms.patch forwarded to upstream --- debian/changelog | 2 ++ .../0003-define_gnu_source-on-other-glibc-based-platforms.patch | 1 + 2 files changed, 3 insertions(+) diff --git a/debian/changelog b/debian/changelog index 609ac41..749ec29 100644 --- a/debian/changelog +++ b/debian/changelog @@ -7,6 +7,8 @@ nginx (1.22.0-2) UNRELEASED; urgency=medium - network-online.target (Closes: 61261) (Closes: 1000406) - remote-fs.target (Closes: 898896) - nss-lookup.target + * d/p/0003-define_gnu_source-on-other-glibc-based-platforms.patch: forwarded + to upstream (Closes: 859082) -- Jan Mojžíš Sun, 10 Jul 2022 07:58:44 +0200 diff --git a/debian/patches/0003-define_gnu_source-on-other-glibc-based-platforms.patch b/debian/patches/0003-define_gnu_source-on-other-glibc-based-platforms.patch index d43fd23..caf155f 100644 --- a/debian/patches/0003-define_gnu_source-on-other-glibc-based-platforms.patch +++ b/debian/patches/0003-define_gnu_source-on-other-glibc-based-platforms.patch @@ -1,6 +1,7 @@ Date: Sat, 16 Jul 2016 23:52:50 +0100 From: Steven Chamberlain Subject: Use _GNU_SOURCE on GNU/kFreeBSD +Forwarded: https://trac.nginx.org/nginx/ticket/2366 Define _GNU_SOURCE not only on GNU/Hurd, but also other glibc-based platforms including GNU/kFreeBSD. From ff7cd7012d526745b8b5bc514877e2be0a487da9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Sun, 10 Jul 2022 18:32:08 +0200 Subject: [PATCH 138/329] d/t/reboot: added, tests if nginx works after reboot --- debian/changelog | 1 + debian/tests/control | 4 ++++ debian/tests/reboot | 15 +++++++++++++++ 3 files changed, 20 insertions(+) create mode 100644 debian/tests/reboot diff --git a/debian/changelog b/debian/changelog index 749ec29..adf2e41 100644 --- a/debian/changelog +++ b/debian/changelog @@ -9,6 +9,7 @@ nginx (1.22.0-2) UNRELEASED; urgency=medium - nss-lookup.target * d/p/0003-define_gnu_source-on-other-glibc-based-platforms.patch: forwarded to upstream (Closes: 859082) + * d/t/reboot: added, tests if nginx works after reboot -- Jan Mojžíš Sun, 10 Jul 2022 07:58:44 +0200 diff --git a/debian/tests/control b/debian/tests/control index 52690ae..4a24735 100644 --- a/debian/tests/control +++ b/debian/tests/control @@ -125,3 +125,7 @@ Depends: nginx-extras, libnginx-mod-stream-geoip, libnginx-mod-stream-geoip2, libnginx-mod-stream, + +Tests: reboot +Restrictions: isolation-container, needs-root, needs-reboot +Depends: nginx-light, curl diff --git a/debian/tests/reboot b/debian/tests/reboot new file mode 100644 index 0000000..a90a6c9 --- /dev/null +++ b/debian/tests/reboot @@ -0,0 +1,15 @@ +#!/bin/sh +# 20220710 +# Jan Mojzis +# Public domain + +#change directory to $AUTOPKGTEST_TMP +cd "${AUTOPKGTEST_TMP}" + +# do simple curl +curl --silent --fail -o /dev/null -w "response_code: %{http_code}\n" http://127.0.0.1/ + +# test if nginx runs after reboot +if [ x"${AUTOPKGTEST_REBOOT_MARK}" = x ]; then + /tmp/autopkgtest-reboot rebootmark +fi From 461acc4f5141c73b01531283c035580608073e97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Sun, 10 Jul 2022 20:12:32 +0200 Subject: [PATCH 139/329] d/nginx-common.nginx.service: remove systemd 'After' dependency syslog.target, is obsolete --- debian/changelog | 1 - debian/nginx-common.nginx.service | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index adf2e41..d9adaf3 100644 --- a/debian/changelog +++ b/debian/changelog @@ -3,7 +3,6 @@ nginx (1.22.0-2) UNRELEASED; urgency=medium * d/nginx-common.nginx.service: added Systemd dependency Wants=network-online.target and updated Systemd "After" dependency to recommended NGINX values, namely: - - syslog.target - network-online.target (Closes: 61261) (Closes: 1000406) - remote-fs.target (Closes: 898896) - nss-lookup.target diff --git a/debian/nginx-common.nginx.service b/debian/nginx-common.nginx.service index a46a725..a63fa0f 100644 --- a/debian/nginx-common.nginx.service +++ b/debian/nginx-common.nginx.service @@ -13,7 +13,7 @@ [Unit] Description=A high performance web server and a reverse proxy server Documentation=man:nginx(8) -After=syslog.target network-online.target remote-fs.target nss-lookup.target +After=network-online.target remote-fs.target nss-lookup.target Wants=network-online.target [Service] From 0d813834ef16b455986c8aea98f9f0a1158eff02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Mon, 11 Jul 2022 20:33:33 +0200 Subject: [PATCH 140/329] http-subs-filter add PCRE2 support --- debian/changelog | 1 + .../patches/http-subs-filter/pcre2.patch | 24 +++++++++++++++++++ .../modules/patches/http-subs-filter/series | 1 + 3 files changed, 26 insertions(+) create mode 100644 debian/modules/patches/http-subs-filter/pcre2.patch diff --git a/debian/changelog b/debian/changelog index d9adaf3..9fb216f 100644 --- a/debian/changelog +++ b/debian/changelog @@ -9,6 +9,7 @@ nginx (1.22.0-2) UNRELEASED; urgency=medium * d/p/0003-define_gnu_source-on-other-glibc-based-platforms.patch: forwarded to upstream (Closes: 859082) * d/t/reboot: added, tests if nginx works after reboot + * d/m/p/http-subs-filter/pcre2.patch: added PCRE2 support -- Jan Mojžíš Sun, 10 Jul 2022 07:58:44 +0200 diff --git a/debian/modules/patches/http-subs-filter/pcre2.patch b/debian/modules/patches/http-subs-filter/pcre2.patch new file mode 100644 index 0000000..692257c --- /dev/null +++ b/debian/modules/patches/http-subs-filter/pcre2.patch @@ -0,0 +1,24 @@ +Author: shmux8 <75251845+shmux8@users.noreply.github.com> +Date: Tue Dec 28 11:15:00 2021 +0300 +Subject: [PATCH] pcre2 support +Origin: https://github.com/yaoweibin/ngx_http_substitutions_filter_module/commit/cc494d7f5c5273a7a8ae503faebf1101689d75c0 + + PCRE2 support added + + Use pcre2_pattern_info call if nginx built with PCRE2. + +diff --git a/debian/modules/http-subs-filter/ngx_http_subs_filter_module.c b/debian/modules/http-subs-filter/ngx_http_subs_filter_module.c +index 483c9c3..11a5b79 100644 +--- a/ngx_http_subs_filter_module.c ++++ b/ngx_http_subs_filter_module.c +@@ -1203,7 +1203,9 @@ ngx_http_subs_regex_capture_count(ngx_regex_t *re) + + n = 0; + +-#if defined(nginx_version) && nginx_version >= 1002002 ++#if (NGX_PCRE2) ++ rc = pcre2_pattern_info(re, PCRE2_INFO_CAPTURECOUNT, &n); ++#elif defined(nginx_version) && nginx_version >= 1002002 + rc = pcre_fullinfo(re->code, NULL, PCRE_INFO_CAPTURECOUNT, &n); + #elif defined(nginx_version) && nginx_version >= 1001012 + rc = pcre_fullinfo(re->pcre, NULL, PCRE_INFO_CAPTURECOUNT, &n); diff --git a/debian/modules/patches/http-subs-filter/series b/debian/modules/patches/http-subs-filter/series index f9b9360..4344c0b 100644 --- a/debian/modules/patches/http-subs-filter/series +++ b/debian/modules/patches/http-subs-filter/series @@ -1 +1,2 @@ dynamic-module.patch +pcre2.patch From 0e2eaec4b255c46654b049f593a03368083d7b48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Sat, 23 Jul 2022 10:40:40 +0200 Subject: [PATCH 141/329] d/gitlab-ci.yml removed in GL switched to salsa-ci team recipes/debian.yml@salsa-ci-team/pipeline --- debian/gitlab-ci.yml | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 debian/gitlab-ci.yml diff --git a/debian/gitlab-ci.yml b/debian/gitlab-ci.yml deleted file mode 100644 index 557434c..0000000 --- a/debian/gitlab-ci.yml +++ /dev/null @@ -1,8 +0,0 @@ ---- -include: - - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/salsa-ci.yml - - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/pipeline-jobs.yml - -# Disable reprotest which is failing now -variables: - SALSA_CI_DISABLE_REPROTEST: 1 From 142c95ade023fd91eed22a5c1b7c2525b79b13d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Sat, 23 Jul 2022 10:46:55 +0200 Subject: [PATCH 142/329] add libnginx-mod-http-ndk-dev to nginx to build ngx-lua --- debian/changelog | 5 +++++ debian/control | 16 +++++++++++++++ debian/libnginx-mod-http-ndk-dev.install | 5 +++++ debian/rules | 26 ++++++++++++++++++++---- 4 files changed, 48 insertions(+), 4 deletions(-) create mode 100644 debian/libnginx-mod-http-ndk-dev.install diff --git a/debian/changelog b/debian/changelog index 9fb216f..194e492 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,5 +1,10 @@ nginx (1.22.0-2) UNRELEASED; urgency=medium + [ Miao Wang ] + * adding a new libnginx-mod-http-ndk-dev package including necessary + headers to build a 3rd party module depending on ndk. + + [ Jan Mojžíš ] * d/nginx-common.nginx.service: added Systemd dependency Wants=network-online.target and updated Systemd "After" dependency to recommended NGINX values, namely: diff --git a/debian/control b/debian/control index 21eb530..4736a9f 100644 --- a/debian/control +++ b/debian/control @@ -398,6 +398,22 @@ Description: Nginx Development Kit module features that are seen from a user's point of view - it's just designed to help reduce the code that Nginx module developers need to write. +Package: libnginx-mod-http-ndk-dev +Architecture: all +Depends: libnginx-mod-http-ndk (<< ${source:Version}.1~), libnginx-mod-http-ndk (>= ${source:Version}), + nginx-dev (>= ${source:Version}), nginx-dev (<< ${source:Version}.1~), ${misc:Depends} +Description: Nginx Development Kit module - development files + The NDK is an Nginx module that is designed to extend the core functionality of + the excellent Nginx webserver in a way that can be used as a basis of other + Nginx modules. + . + This package provides development headers and necessary config scripts + for the Nginx development kit module, useful to develop and link third party + additions to the Debian nginx web/proxy server packages using Nginx + development kit module. + . + Development files. + Package: libnginx-mod-nchan Architecture: any Depends: ${misc:Depends}, ${shlibs:Depends}, diff --git a/debian/libnginx-mod-http-ndk-dev.install b/debian/libnginx-mod-http-ndk-dev.install new file mode 100644 index 0000000..980066f --- /dev/null +++ b/debian/libnginx-mod-http-ndk-dev.install @@ -0,0 +1,5 @@ +debian/build-ndksrc/auto usr/share/nginx-ndk/src/ +debian/build-ndksrc/src usr/share/nginx-ndk/src/ +debian/build-ndksrc/objs usr/share/nginx-ndk/src/ +debian/build-ndksrc/config usr/share/nginx-ndk/src/ +debian/build-ndksrc/ngx_auto_lib_core usr/share/nginx-ndk/src/ \ No newline at end of file diff --git a/debian/rules b/debian/rules index d4ddc7e..4471089 100755 --- a/debian/rules +++ b/debian/rules @@ -32,7 +32,7 @@ DYN_MODS := \ MODULESDIR = $(CURDIR)/debian/modules BASEDIR = $(CURDIR) -$(foreach flavour,$(FLAVOURS) src,$(eval BUILDDIR_$(flavour) = $(CURDIR)/debian/build-$(flavour))) +$(foreach flavour,$(FLAVOURS) src ndksrc,$(eval BUILDDIR_$(flavour) = $(CURDIR)/debian/build-$(flavour))) DEB_BUILD_ARCH ?=$(shell dpkg-architecture -qDEB_BUILD_ARCH) ifeq ($(DEB_BUILD_ARCH),sparc) @@ -135,10 +135,10 @@ extras_configure_flags := \ %: dh $@ --without autoreconf -override_dh_auto_configure: config_patch_modules $(foreach flavour,$(FLAVOURS),config.arch.$(flavour)) config.src -override_dh_auto_build: $(foreach flavour,$(FLAVOURS),build.arch.$(flavour)) build.src +override_dh_auto_configure: config_patch_modules $(foreach flavour,$(FLAVOURS),config.arch.$(flavour)) config.src config.ndksrc +override_dh_auto_build: $(foreach flavour,$(FLAVOURS),build.arch.$(flavour)) build.src build.ndksrc override_dh_strip: $(foreach flavour,$(FLAVOURS),strip.arch.$(flavour)) $(foreach mod,$(DYN_MODS),strip.mods.$(mod)) -override_dh_clean: clean_patch_modules $(foreach flavour,$(FLAVOURS),clean.$(flavour)) clean.src +override_dh_clean: clean_patch_modules $(foreach flavour,$(FLAVOURS),clean.$(flavour)) clean.src clean.ndksrc dh_clean override_dh_install: @@ -165,6 +165,16 @@ build.src: echo "NGX_CONF_FLAGS=(" $(basic_configure_flags) ")" > $(BUILDDIR_src)/conf_flags pod2man debian/debhelper/dh_nginx > $(BUILDDIR_src)/dh_nginx.1 +build.ndksrc: + cp -Pa $(CURDIR)/debian/modules/http-ndk/auto \ + $(CURDIR)/debian/modules/http-ndk/config \ + $(CURDIR)/debian/modules/http-ndk/ngx_auto_lib_core $(BUILDDIR_ndksrc)/ + for i in src objs; do \ + find $(CURDIR)/debian/modules/http-ndk/$$i -type f -name '*.h' -printf "$$i/%P\0" | \ + tar -C $(CURDIR)/debian/modules/http-ndk --null --files-from - -c | tar -C $(BUILDDIR_ndksrc)/ -x; \ + done + chmod +x $(CURDIR)/debian/build-ndksrc/auto/build + strip.arch.%: dh_strip --package=nginx-$(*) -O--dbgsym-migration='nginx-$(*)-dbg (<< 1.10.1-3~)' @@ -192,11 +202,19 @@ config.arch.%: cp -Pa $(CURDIR)/src $(BUILDDIR_$*)/ cp -Pa $(CURDIR)/man $(BUILDDIR_$*)/ cd $(BUILDDIR_$*) && ./configure $($*_configure_flags) + if [ "$(BUILDDIR_$*)" = "$(BUILDDIR_extras)" ]; then \ + have="NDK_SET_VAR"; \ + /bin/echo -e "#ifndef $$have\n#define $$have 1\n#endif" >> $(BUILDDIR_$*)/objs/ngx_auto_config.h; \ + fi config.src: dh_testdir mkdir -p $(BUILDDIR_src) +config.ndksrc: + dh_testdir + mkdir -p $(BUILDDIR_ndksrc) + clean.%: rm -rf $(BUILDDIR_$*) From 43b9a879c9a5b7573336e339a0b43113e45a56ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Sat, 23 Jul 2022 10:48:06 +0200 Subject: [PATCH 143/329] Remove constraints unnecessary since buster * Build-Depends: Drop versioned constraint on dpkg-dev. * nginx-common: Drop versioned constraint on lsb-base in Depends. * nginx-core: Drop versioned constraint on nginx in Breaks. * nginx-full: Drop versioned constraint on nginx in Breaks. * nginx-light: Drop versioned constraint on nginx in Breaks. * nginx-extras: Drop versioned constraint on nginx in Breaks. * libnginx-mod-http-perl: Drop versioned constraint on nginx-extras in Replaces. * Remove 5 maintscript entries from 1 files. --- debian/changelog | 12 ++++++++++++ debian/control | 10 ++-------- debian/nginx-common.maintscript | 8 -------- 3 files changed, 14 insertions(+), 16 deletions(-) delete mode 100644 debian/nginx-common.maintscript diff --git a/debian/changelog b/debian/changelog index 194e492..c0cbcdb 100644 --- a/debian/changelog +++ b/debian/changelog @@ -16,6 +16,18 @@ nginx (1.22.0-2) UNRELEASED; urgency=medium * d/t/reboot: added, tests if nginx works after reboot * d/m/p/http-subs-filter/pcre2.patch: added PCRE2 support + [ Debian Janitor ] + * Remove constraints unnecessary since buster: + + Build-Depends: Drop versioned constraint on dpkg-dev. + + nginx-common: Drop versioned constraint on lsb-base in Depends. + + nginx-core: Drop versioned constraint on nginx in Breaks. + + nginx-full: Drop versioned constraint on nginx in Breaks. + + nginx-light: Drop versioned constraint on nginx in Breaks. + + nginx-extras: Drop versioned constraint on nginx in Breaks. + + libnginx-mod-http-perl: Drop versioned constraint on nginx-extras in + Replaces. + + Remove 5 maintscript entries from 1 files. + -- Jan Mojžíš Sun, 10 Jul 2022 07:58:44 +0200 nginx (1.22.0-1) unstable; urgency=medium diff --git a/debian/control b/debian/control index 4736a9f..c8aa03c 100644 --- a/debian/control +++ b/debian/control @@ -7,7 +7,6 @@ Uploaders: Christos Trochalakis , Thomas Ward , Jan Mojžíš , Build-Depends: debhelper-compat (= 13), - dpkg-dev (>= 1.15.5), libexpat-dev, libgd-dev, libgeoip-dev, @@ -58,7 +57,7 @@ Description: small, powerful, scalable web/proxy server - documentation Package: nginx-common Architecture: all Multi-Arch: foreign -Depends: lsb-base (>= 3.0-6), ${misc:Depends} +Depends: lsb-base, ${misc:Depends} Suggests: fcgiwrap, nginx-doc, ssl-cert Description: small, powerful, scalable web/proxy server - common files Nginx ("engine X") is a high-performance web and reverse proxy server @@ -105,8 +104,7 @@ Depends: libnginx-mod-http-geoip (= ${binary:Version}), iproute2, ${misc:Depends}, ${shlibs:Depends} -Breaks: nginx (<< 1.4.5-1), - nginx-full (<< 1.18.0-1), +Breaks: nginx-full (<< 1.18.0-1), Replaces: nginx-full (<< 1.18.0-1), Provides: httpd, httpd-cgi, nginx Conflicts: nginx-extras, nginx-light @@ -146,7 +144,6 @@ Depends: libnginx-mod-http-auth-pam, nginx-core (<< ${source:Version}.1~), ${misc:Depends}, ${shlibs:Depends} -Breaks: nginx (<< 1.4.5-1) Provides: httpd, httpd-cgi, nginx Suggests: nginx-doc (= ${source:Version}) Description: nginx web/proxy server (standard version with 3rd parties) @@ -181,7 +178,6 @@ Depends: libnginx-mod-http-echo (= ${binary:Version}), iproute2, ${misc:Depends}, ${shlibs:Depends} -Breaks: nginx (<< 1.4.5-1) Provides: httpd, httpd-cgi, nginx Conflicts: nginx-extras, nginx-core Suggests: nginx-doc (= ${source:Version}) @@ -228,7 +224,6 @@ Depends: libnginx-mod-http-auth-pam (= ${binary:Version}), iproute2, ${misc:Depends}, ${shlibs:Depends} -Breaks: nginx (<< 1.4.5-1) Provides: httpd, httpd-cgi, nginx Conflicts: nginx-core, nginx-light Suggests: nginx-doc (= ${source:Version}) @@ -351,7 +346,6 @@ Package: libnginx-mod-http-perl Architecture: any Depends: ${misc:Depends}, ${perl:Depends}, ${shlibs:Depends}, Recommends: nginx, -Replaces: nginx-extras (<< 1.9.14-1) Description: Perl module for Nginx Embed Perl runtime into nginx. . diff --git a/debian/nginx-common.maintscript b/debian/nginx-common.maintscript deleted file mode 100644 index e1e7f53..0000000 --- a/debian/nginx-common.maintscript +++ /dev/null @@ -1,8 +0,0 @@ -# Handle naxsi removal -rm_conffile /etc/nginx/naxsi.rules 1.6.2-2~ -rm_conffile /etc/nginx/naxsi_core.rules 1.6.2-2~ -rm_conffile /etc/nginx/naxsi-ui.conf.1.4.1 1.6.2-2~ -rm_conffile /etc/nginx/naxsi-ui.conf 1.6.2-2~ - -# Handle upstart removal -rm_conffile /etc/init/nginx.conf 1.13.5-1~ From 861f1be8692fccce5996e26ee7f210c927ea6ceb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Sat, 23 Jul 2022 10:49:48 +0200 Subject: [PATCH 144/329] d/p/nginx-fix-pidfile.patch backport from Ubuntu --- debian/changelog | 2 + debian/patches/nginx-fix-pidfile.patch | 89 ++++++++++++++++++++++++++ debian/patches/series | 1 + 3 files changed, 92 insertions(+) create mode 100644 debian/patches/nginx-fix-pidfile.patch diff --git a/debian/changelog b/debian/changelog index c0cbcdb..7d70e35 100644 --- a/debian/changelog +++ b/debian/changelog @@ -15,6 +15,8 @@ nginx (1.22.0-2) UNRELEASED; urgency=medium to upstream (Closes: 859082) * d/t/reboot: added, tests if nginx works after reboot * d/m/p/http-subs-filter/pcre2.patch: added PCRE2 support + * d/p/nginx-fix-pidfile.patch: Fix NGINX PIDfile handling to avoid + SystemD race condition, this fix is backported from Ubuntu (Closes: 876365) [ Debian Janitor ] * Remove constraints unnecessary since buster: diff --git a/debian/patches/nginx-fix-pidfile.patch b/debian/patches/nginx-fix-pidfile.patch new file mode 100644 index 0000000..47a16ff --- /dev/null +++ b/debian/patches/nginx-fix-pidfile.patch @@ -0,0 +1,89 @@ +Description: Fix NGINX pidfile handling +Author: Tj +Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/nginx/+bug/1581864 +Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=876365 +Last-Update: 2020-06-24 +--- +This patch header follows DEP-3: http://dep.debian.net/deps/dep3/ +diff --git a/src/core/nginx.c b/src/core/nginx.c +index 9fcb0eb2..083eba1d 100644 +--- a/src/core/nginx.c ++++ b/src/core/nginx.c +@@ -338,14 +338,21 @@ main(int argc, char *const *argv) + ngx_process = NGX_PROCESS_MASTER; + } + ++ /* tell-tale to detect if this is parent or child process */ ++ ngx_int_t child_pid = NGX_BUSY; ++ + #if !(NGX_WIN32) + + if (ngx_init_signals(cycle->log) != NGX_OK) { + return 1; + } + ++ /* tell-tale that this code has been executed */ ++ child_pid--; ++ + if (!ngx_inherited && ccf->daemon) { +- if (ngx_daemon(cycle->log) != NGX_OK) { ++ child_pid = ngx_daemon(cycle->log); ++ if (child_pid == NGX_ERROR) { + return 1; + } + +@@ -358,8 +365,19 @@ main(int argc, char *const *argv) + + #endif + +- if (ngx_create_pidfile(&ccf->pid, cycle->log) != NGX_OK) { +- return 1; ++ /* If ngx_daemon() returned the child's PID in the parent process ++ * after the fork() set ngx_pid to the child_pid, which gets ++ * written to the PID file, then exit. ++ * For NGX_WIN32 always write the PID file ++ * For others, only write it from the parent process */ ++ if (child_pid < NGX_OK || child_pid > NGX_OK) { ++ ngx_pid = child_pid > NGX_OK ? child_pid : ngx_pid; ++ if (ngx_create_pidfile(&ccf->pid, cycle->log) != NGX_OK) { ++ return 1; ++ } ++ } ++ if (child_pid > NGX_OK) { ++ exit(0); + } + + if (ngx_log_redirect_stderr(cycle) != NGX_OK) { +diff --git a/src/os/unix/ngx_daemon.c b/src/os/unix/ngx_daemon.c +index 385c49b6..3719854c 100644 +--- a/src/os/unix/ngx_daemon.c ++++ b/src/os/unix/ngx_daemon.c +@@ -7,14 +7,17 @@ + + #include + #include ++#include + + + ngx_int_t + ngx_daemon(ngx_log_t *log) + { + int fd; ++ /* retain the return value for passing back to caller */ ++ pid_t pid_child = fork(); + +- switch (fork()) { ++ switch (pid_child) { + case -1: + ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "fork() failed"); + return NGX_ERROR; +@@ -23,7 +26,8 @@ ngx_daemon(ngx_log_t *log) + break; + + default: +- exit(0); ++ /* let caller do the exit() */ ++ return pid_child; + } + + ngx_parent = ngx_pid; diff --git a/debian/patches/series b/debian/patches/series index 04030f9..5e15dcc 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -1 +1,2 @@ 0003-define_gnu_source-on-other-glibc-based-platforms.patch +nginx-fix-pidfile.patch From c9a408aa6f2309b43efaa2b04c5cf788aa546fa2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Sat, 23 Jul 2022 10:50:45 +0200 Subject: [PATCH 145/329] d/apport/source_nginx.py: Add apport hooks for additional bug information gathering, the script is backported from Ubuntu --- debian/apport/source_nginx.py | 19 +++++++++++++++++++ debian/changelog | 3 +++ debian/nginx-common.install | 1 + 3 files changed, 23 insertions(+) create mode 100644 debian/apport/source_nginx.py diff --git a/debian/apport/source_nginx.py b/debian/apport/source_nginx.py new file mode 100644 index 0000000..aec6e8e --- /dev/null +++ b/debian/apport/source_nginx.py @@ -0,0 +1,19 @@ +''' +apport package hook for nginx packages + +Copyright (c) 2015, Thomas Ward +''' + +import apport.hookutils +import os +import subprocess + +def add_info(report, ui): + if (report['Package'].split()[0] != 'nginx-common' + and report['ProblemType'] == 'Package' + and os.path.isdir('/run/systemd/system')): + report['Journalctl_Nginx.txt'] = apport.hookutils.command_output( + ['journalctl', '-xe', '--unit=nginx.service']) + report['SystemctlStatusFull_Nginx.txt'] = subprocess.Popen( + ['systemctl', '-l', 'status', 'nginx.service'], + stdout=subprocess.PIPE).communicate()[0] diff --git a/debian/changelog b/debian/changelog index 7d70e35..0124d12 100644 --- a/debian/changelog +++ b/debian/changelog @@ -17,6 +17,9 @@ nginx (1.22.0-2) UNRELEASED; urgency=medium * d/m/p/http-subs-filter/pcre2.patch: added PCRE2 support * d/p/nginx-fix-pidfile.patch: Fix NGINX PIDfile handling to avoid SystemD race condition, this fix is backported from Ubuntu (Closes: 876365) + * d/apport/source_nginx.py: Add apport hooks for additional bug + information gathering, the script is backported from Ubuntu (Closes: 963668) + * d/nginx-common.install: Add install rule for apport hooks. [ Debian Janitor ] * Remove constraints unnecessary since buster: diff --git a/debian/nginx-common.install b/debian/nginx-common.install index 90f173b..20109fa 100644 --- a/debian/nginx-common.install +++ b/debian/nginx-common.install @@ -1,5 +1,6 @@ contrib/vim/* usr/share/vim/addons debian/conf/* etc/nginx +debian/apport/source_nginx.py usr/share/apport/package-hooks debian/ufw/nginx etc/ufw/applications.d debian/vim/nginx.yaml usr/share/vim/registry html/index.html usr/share/nginx/html/ From 13a5fc3501349113ac90636d8f47d007ffafd033 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Sat, 23 Jul 2022 10:40:40 +0200 Subject: [PATCH 146/329] d/gitlab-ci.yml removed in GL switched to salsa-ci team recipes/debian.yml@salsa-ci-team/pipeline --- debian/gitlab-ci.yml | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 debian/gitlab-ci.yml diff --git a/debian/gitlab-ci.yml b/debian/gitlab-ci.yml deleted file mode 100644 index 557434c..0000000 --- a/debian/gitlab-ci.yml +++ /dev/null @@ -1,8 +0,0 @@ ---- -include: - - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/salsa-ci.yml - - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/pipeline-jobs.yml - -# Disable reprotest which is failing now -variables: - SALSA_CI_DISABLE_REPROTEST: 1 From 08de4d4bc7e6ba11051ab1f6ef5460989b161513 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Lal?= Date: Sun, 7 Aug 2022 16:15:09 +0200 Subject: [PATCH 147/329] Release to unstable --- debian/changelog | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index 0124d12..6bb8afa 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -nginx (1.22.0-2) UNRELEASED; urgency=medium +nginx (1.22.0-2) unstable; urgency=medium [ Miao Wang ] * adding a new libnginx-mod-http-ndk-dev package including necessary @@ -33,7 +33,7 @@ nginx (1.22.0-2) UNRELEASED; urgency=medium Replaces. + Remove 5 maintscript entries from 1 files. - -- Jan Mojžíš Sun, 10 Jul 2022 07:58:44 +0200 + -- Jan Mojžíš Sun, 07 Aug 2022 16:14:59 +0200 nginx (1.22.0-1) unstable; urgency=medium From a316cb99e4dcc4ba7306b4741f474500784c270f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Mon, 8 Aug 2022 12:30:21 +0200 Subject: [PATCH 148/329] d/changelog: fix typo in bug number 61261 -> 861261 --- debian/changelog | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 6bb8afa..9ac858c 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +nginx (1.22.0-3) UNRELEASED; urgency=medium + + * d/changelog: fixed typo in bug number 61261 -> 861261 (Closes: 861261) + + -- Jan Mojžíš Mon, 08 Aug 2022 12:29:34 +0200 + nginx (1.22.0-2) unstable; urgency=medium [ Miao Wang ] @@ -8,7 +14,7 @@ nginx (1.22.0-2) unstable; urgency=medium * d/nginx-common.nginx.service: added Systemd dependency Wants=network-online.target and updated Systemd "After" dependency to recommended NGINX values, namely: - - network-online.target (Closes: 61261) (Closes: 1000406) + - network-online.target (Closes: 861261) (Closes: 1000406) - remote-fs.target (Closes: 898896) - nss-lookup.target * d/p/0003-define_gnu_source-on-other-glibc-based-platforms.patch: forwarded From caf389149afa0b5923116bc4425978a179829c26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Mon, 8 Aug 2022 12:32:23 +0200 Subject: [PATCH 149/329] d/p/nginx-ssl_cert_cb_yield.patch add --- debian/changelog | 1 + debian/patches/nginx-ssl_cert_cb_yield.patch | 40 ++++++++++++++++++++ debian/patches/series | 1 + 3 files changed, 42 insertions(+) create mode 100644 debian/patches/nginx-ssl_cert_cb_yield.patch diff --git a/debian/changelog b/debian/changelog index 9ac858c..a41d64e 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,6 +1,7 @@ nginx (1.22.0-3) UNRELEASED; urgency=medium * d/changelog: fixed typo in bug number 61261 -> 861261 (Closes: 861261) + * d/p/nginx-ssl_cert_cb_yield.patch added (Closes: 884434) -- Jan Mojžíš Mon, 08 Aug 2022 12:29:34 +0200 diff --git a/debian/patches/nginx-ssl_cert_cb_yield.patch b/debian/patches/nginx-ssl_cert_cb_yield.patch new file mode 100644 index 0000000..96e06e1 --- /dev/null +++ b/debian/patches/nginx-ssl_cert_cb_yield.patch @@ -0,0 +1,40 @@ +Description: SSL: handled SSL_CTX_set_cert_cb() callback yielding. +Author: Yichun Zhang +Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=884434 +Origin: https://raw.githubusercontent.com/openresty/openresty/v1.11.2.2/patches/nginx-1.11.2-ssl_cert_cb_yield.patch +Last-Update: 2016-01-02 + +OpenSSL 1.0.2+ introduces SSL_CTX_set_cert_cb() to allow custom +callbacks to serve the SSL certificiates and private keys dynamically +and lazily. The callbacks may yield for nonblocking I/O or sleeping. +Here we added support for such usage in NGINX 3rd-party modules +(like ngx_lua) in NGINX's event handlers for downstream SSL +connections. + +diff -r 78b4e10b4367 -r 449f0461859c src/event/ngx_event_openssl.c +--- a/src/event/ngx_event_openssl.c Thu Dec 17 16:39:15 2015 +0300 ++++ b/src/event/ngx_event_openssl.c Sat Jan 02 11:14:44 2016 -0800 +@@ -1210,6 +1210,23 @@ + return NGX_AGAIN; + } + ++#if OPENSSL_VERSION_NUMBER >= 0x10002000L ++ if (sslerr == SSL_ERROR_WANT_X509_LOOKUP) { ++ c->read->handler = ngx_ssl_handshake_handler; ++ c->write->handler = ngx_ssl_handshake_handler; ++ ++ if (ngx_handle_read_event(c->read, 0) != NGX_OK) { ++ return NGX_ERROR; ++ } ++ ++ if (ngx_handle_write_event(c->write, 0) != NGX_OK) { ++ return NGX_ERROR; ++ } ++ ++ return NGX_AGAIN; ++ } ++#endif ++ + err = (sslerr == SSL_ERROR_SYSCALL) ? ngx_errno : 0; + + c->ssl->no_wait_shutdown = 1; diff --git a/debian/patches/series b/debian/patches/series index 5e15dcc..52e1dc4 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -1,2 +1,3 @@ 0003-define_gnu_source-on-other-glibc-based-platforms.patch nginx-fix-pidfile.patch +nginx-ssl_cert_cb_yield.patch From 212327ed576d26fc3b35feb30a43079d10fc5cea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Mon, 8 Aug 2022 12:34:00 +0200 Subject: [PATCH 150/329] http-lua: remove --- debian/changelog | 1 + debian/control | 18 +- debian/copyright | 9 - debian/libnginx-mod-http-lua.nginx | 13 - debian/modules/http-lua/README.markdown | 8332 ----------------- debian/modules/http-lua/config | 532 -- .../modules/http-lua/doc/HttpLuaModule.wiki | 7073 -------------- .../http-lua/dtrace/ngx_lua_provider.d | 61 - .../http-lua/misc/recv-until-pm/Makefile | 3 - .../misc/recv-until-pm/lib/RecvUntil.pm | 138 - .../http-lua/misc/recv-until-pm/t/sanity.t | 140 - .../http-lua/src/api/ngx_http_lua_api.h | 62 - debian/modules/http-lua/src/ddebug.h | 85 - .../http-lua/src/ngx_http_lua_accessby.c | 398 - .../http-lua/src/ngx_http_lua_accessby.h | 22 - .../modules/http-lua/src/ngx_http_lua_api.c | 216 - .../modules/http-lua/src/ngx_http_lua_args.c | 555 -- .../modules/http-lua/src/ngx_http_lua_args.h | 20 - .../http-lua/src/ngx_http_lua_balancer.c | 763 -- .../http-lua/src/ngx_http_lua_balancer.h | 27 - .../http-lua/src/ngx_http_lua_bodyfilterby.c | 633 -- .../http-lua/src/ngx_http_lua_bodyfilterby.h | 31 - .../modules/http-lua/src/ngx_http_lua_cache.c | 296 - .../modules/http-lua/src/ngx_http_lua_cache.h | 24 - .../http-lua/src/ngx_http_lua_capturefilter.c | 176 - .../http-lua/src/ngx_http_lua_capturefilter.h | 20 - .../http-lua/src/ngx_http_lua_clfactory.c | 887 -- .../http-lua/src/ngx_http_lua_clfactory.h | 22 - .../http-lua/src/ngx_http_lua_common.h | 593 -- .../http-lua/src/ngx_http_lua_config.c | 70 - .../http-lua/src/ngx_http_lua_config.h | 19 - .../http-lua/src/ngx_http_lua_consts.c | 202 - .../http-lua/src/ngx_http_lua_consts.h | 20 - .../http-lua/src/ngx_http_lua_contentby.c | 387 - .../http-lua/src/ngx_http_lua_contentby.h | 26 - .../http-lua/src/ngx_http_lua_control.c | 555 -- .../http-lua/src/ngx_http_lua_control.h | 20 - .../http-lua/src/ngx_http_lua_coroutine.c | 387 - .../http-lua/src/ngx_http_lua_coroutine.h | 23 - .../modules/http-lua/src/ngx_http_lua_ctx.c | 216 - .../modules/http-lua/src/ngx_http_lua_ctx.h | 23 - .../http-lua/src/ngx_http_lua_directive.c | 1831 ---- .../http-lua/src/ngx_http_lua_directive.h | 78 - .../http-lua/src/ngx_http_lua_exception.c | 58 - .../http-lua/src/ngx_http_lua_exception.h | 33 - .../src/ngx_http_lua_headerfilterby.c | 302 - .../src/ngx_http_lua_headerfilterby.h | 29 - .../http-lua/src/ngx_http_lua_headers.c | 1529 --- .../http-lua/src/ngx_http_lua_headers.h | 25 - .../http-lua/src/ngx_http_lua_headers_in.c | 835 -- .../http-lua/src/ngx_http_lua_headers_in.h | 22 - .../http-lua/src/ngx_http_lua_headers_out.c | 637 -- .../http-lua/src/ngx_http_lua_headers_out.h | 23 - .../http-lua/src/ngx_http_lua_initby.c | 42 - .../http-lua/src/ngx_http_lua_initby.h | 23 - .../http-lua/src/ngx_http_lua_initworkerby.c | 357 - .../http-lua/src/ngx_http_lua_initworkerby.h | 25 - .../modules/http-lua/src/ngx_http_lua_lex.c | 8251 ---------------- .../modules/http-lua/src/ngx_http_lua_lex.h | 17 - .../modules/http-lua/src/ngx_http_lua_log.c | 456 - .../modules/http-lua/src/ngx_http_lua_log.h | 24 - .../http-lua/src/ngx_http_lua_log_ringbuf.c | 225 - .../http-lua/src/ngx_http_lua_log_ringbuf.h | 31 - .../modules/http-lua/src/ngx_http_lua_logby.c | 266 - .../modules/http-lua/src/ngx_http_lua_logby.h | 22 - .../modules/http-lua/src/ngx_http_lua_misc.c | 292 - .../modules/http-lua/src/ngx_http_lua_misc.h | 22 - .../http-lua/src/ngx_http_lua_module.c | 1312 --- .../modules/http-lua/src/ngx_http_lua_ndk.c | 191 - .../modules/http-lua/src/ngx_http_lua_ndk.h | 21 - .../http-lua/src/ngx_http_lua_output.c | 808 -- .../http-lua/src/ngx_http_lua_output.h | 28 - .../http-lua/src/ngx_http_lua_pcrefix.c | 106 - .../http-lua/src/ngx_http_lua_pcrefix.h | 23 - .../modules/http-lua/src/ngx_http_lua_phase.c | 128 - .../modules/http-lua/src/ngx_http_lua_phase.h | 13 - .../modules/http-lua/src/ngx_http_lua_probe.h | 86 - .../modules/http-lua/src/ngx_http_lua_regex.c | 2548 ----- .../modules/http-lua/src/ngx_http_lua_regex.h | 24 - .../http-lua/src/ngx_http_lua_req_body.c | 1188 --- .../http-lua/src/ngx_http_lua_req_body.h | 20 - .../http-lua/src/ngx_http_lua_req_method.c | 253 - .../http-lua/src/ngx_http_lua_req_method.h | 19 - .../http-lua/src/ngx_http_lua_rewriteby.c | 380 - .../http-lua/src/ngx_http_lua_rewriteby.h | 22 - .../http-lua/src/ngx_http_lua_script.c | 538 -- .../http-lua/src/ngx_http_lua_script.h | 86 - .../http-lua/src/ngx_http_lua_semaphore.c | 578 -- .../http-lua/src/ngx_http_lua_semaphore.h | 53 - .../modules/http-lua/src/ngx_http_lua_setby.c | 216 - .../modules/http-lua/src/ngx_http_lua_setby.h | 15 - .../http-lua/src/ngx_http_lua_shdict.c | 3027 ------ .../http-lua/src/ngx_http_lua_shdict.h | 67 - .../modules/http-lua/src/ngx_http_lua_sleep.c | 219 - .../modules/http-lua/src/ngx_http_lua_sleep.h | 20 - .../http-lua/src/ngx_http_lua_socket_tcp.c | 5521 ----------- .../http-lua/src/ngx_http_lua_socket_tcp.h | 156 - .../http-lua/src/ngx_http_lua_socket_udp.c | 1657 ---- .../http-lua/src/ngx_http_lua_socket_udp.h | 65 - .../modules/http-lua/src/ngx_http_lua_ssl.c | 37 - .../modules/http-lua/src/ngx_http_lua_ssl.h | 47 - .../http-lua/src/ngx_http_lua_ssl_certby.c | 1325 --- .../http-lua/src/ngx_http_lua_ssl_certby.h | 37 - .../http-lua/src/ngx_http_lua_ssl_ocsp.c | 506 - .../src/ngx_http_lua_ssl_session_fetchby.c | 614 -- .../src/ngx_http_lua_ssl_session_fetchby.h | 38 - .../src/ngx_http_lua_ssl_session_storeby.c | 618 -- .../src/ngx_http_lua_ssl_session_storeby.h | 34 - .../http-lua/src/ngx_http_lua_string.c | 767 -- .../http-lua/src/ngx_http_lua_string.h | 20 - .../http-lua/src/ngx_http_lua_subrequest.c | 1782 ---- .../http-lua/src/ngx_http_lua_subrequest.h | 46 - .../modules/http-lua/src/ngx_http_lua_time.c | 349 - .../modules/http-lua/src/ngx_http_lua_time.h | 21 - .../modules/http-lua/src/ngx_http_lua_timer.c | 909 -- .../modules/http-lua/src/ngx_http_lua_timer.h | 20 - .../modules/http-lua/src/ngx_http_lua_uri.c | 110 - .../modules/http-lua/src/ngx_http_lua_uri.h | 20 - .../http-lua/src/ngx_http_lua_uthread.c | 285 - .../http-lua/src/ngx_http_lua_uthread.h | 36 - .../modules/http-lua/src/ngx_http_lua_util.c | 4132 -------- .../modules/http-lua/src/ngx_http_lua_util.h | 468 - .../http-lua/src/ngx_http_lua_variable.c | 509 - .../http-lua/src/ngx_http_lua_variable.h | 20 - .../http-lua/src/ngx_http_lua_worker.c | 193 - .../http-lua/src/ngx_http_lua_worker.h | 17 - debian/modules/http-lua/t/000--init.t | 85 - debian/modules/http-lua/t/000-sanity.t | 33 - debian/modules/http-lua/t/001-set.t | 797 -- debian/modules/http-lua/t/002-content.t | 844 -- debian/modules/http-lua/t/003-errors.t | 128 - debian/modules/http-lua/t/004-require.t | 211 - debian/modules/http-lua/t/005-exit.t | 725 -- debian/modules/http-lua/t/006-escape.t | 199 - debian/modules/http-lua/t/007-md5.t | 102 - debian/modules/http-lua/t/008-today.t | 38 - debian/modules/http-lua/t/009-log.t | 544 -- debian/modules/http-lua/t/010-request_body.t | 272 - debian/modules/http-lua/t/011-md5_bin.t | 170 - debian/modules/http-lua/t/012-now.t | 118 - debian/modules/http-lua/t/013-base64.t | 245 - debian/modules/http-lua/t/014-bugs.t | 1020 -- debian/modules/http-lua/t/015-status.t | 293 - debian/modules/http-lua/t/016-resp-header.t | 1701 ---- debian/modules/http-lua/t/017-exec.t | 596 -- debian/modules/http-lua/t/018-ndk.t | 173 - debian/modules/http-lua/t/019-const.t | 46 - debian/modules/http-lua/t/020-subrequest.t | 2879 ------ debian/modules/http-lua/t/021-cookie-time.t | 45 - debian/modules/http-lua/t/022-redirect.t | 322 - .../http-lua/t/023-rewrite/client-abort.t | 850 -- debian/modules/http-lua/t/023-rewrite/exec.t | 400 - debian/modules/http-lua/t/023-rewrite/exit.t | 597 -- debian/modules/http-lua/t/023-rewrite/mixed.t | 169 - .../http-lua/t/023-rewrite/multi-capture.t | 394 - .../modules/http-lua/t/023-rewrite/on-abort.t | 656 -- .../modules/http-lua/t/023-rewrite/redirect.t | 164 - .../modules/http-lua/t/023-rewrite/req-body.t | 223 - .../http-lua/t/023-rewrite/req-socket.t | 534 -- .../http-lua/t/023-rewrite/request_body.t | 172 - .../modules/http-lua/t/023-rewrite/sanity.t | 801 -- debian/modules/http-lua/t/023-rewrite/sleep.t | 221 - .../http-lua/t/023-rewrite/socket-keepalive.t | 1009 -- .../http-lua/t/023-rewrite/subrequest.t | 641 -- .../t/023-rewrite/tcp-socket-timeout.t | 606 -- .../http-lua/t/023-rewrite/tcp-socket.t | 2392 ----- .../http-lua/t/023-rewrite/unix-socket.t | 152 - .../http-lua/t/023-rewrite/uthread-exec.t | 345 - .../http-lua/t/023-rewrite/uthread-exit.t | 1331 --- .../http-lua/t/023-rewrite/uthread-redirect.t | 188 - .../http-lua/t/023-rewrite/uthread-spawn.t | 1451 --- debian/modules/http-lua/t/024-access/auth.t | 109 - .../http-lua/t/024-access/client-abort.t | 852 -- debian/modules/http-lua/t/024-access/exec.t | 393 - debian/modules/http-lua/t/024-access/exit.t | 547 -- debian/modules/http-lua/t/024-access/mixed.t | 261 - .../http-lua/t/024-access/multi-capture.t | 394 - .../modules/http-lua/t/024-access/on-abort.t | 651 -- .../modules/http-lua/t/024-access/redirect.t | 124 - .../modules/http-lua/t/024-access/req-body.t | 220 - .../http-lua/t/024-access/request_body.t | 172 - debian/modules/http-lua/t/024-access/sanity.t | 743 -- .../modules/http-lua/t/024-access/satisfy.t | 211 - debian/modules/http-lua/t/024-access/sleep.t | 221 - .../http-lua/t/024-access/subrequest.t | 601 -- .../http-lua/t/024-access/uthread-exec.t | 346 - .../http-lua/t/024-access/uthread-exit.t | 1313 --- .../http-lua/t/024-access/uthread-redirect.t | 189 - .../http-lua/t/024-access/uthread-spawn.t | 1118 --- debian/modules/http-lua/t/025-codecache.t | 1246 --- debian/modules/http-lua/t/026-mysql.t | 130 - debian/modules/http-lua/t/027-multi-capture.t | 754 -- debian/modules/http-lua/t/028-req-header.t | 2010 ---- debian/modules/http-lua/t/029-http-time.t | 87 - debian/modules/http-lua/t/030-uri-args.t | 1549 --- debian/modules/http-lua/t/031-post-args.t | 406 - debian/modules/http-lua/t/032-iolist.t | 78 - debian/modules/http-lua/t/033-ctx.t | 442 - debian/modules/http-lua/t/034-match.t | 1192 --- debian/modules/http-lua/t/035-gmatch.t | 904 -- debian/modules/http-lua/t/036-sub.t | 757 -- debian/modules/http-lua/t/037-gsub.t | 699 -- debian/modules/http-lua/t/038-match-o.t | 742 -- debian/modules/http-lua/t/039-sub-o.t | 580 -- debian/modules/http-lua/t/040-gsub-o.t | 200 - debian/modules/http-lua/t/041-header-filter.t | 796 -- debian/modules/http-lua/t/042-crc32.t | 56 - debian/modules/http-lua/t/043-shdict.t | 2473 ----- debian/modules/http-lua/t/044-req-body.t | 1746 ---- debian/modules/http-lua/t/045-ngx-var.t | 230 - debian/modules/http-lua/t/046-hmac.t | 31 - debian/modules/http-lua/t/047-match-jit.t | 214 - debian/modules/http-lua/t/048-match-dfa.t | 209 - debian/modules/http-lua/t/049-gmatch-jit.t | 228 - debian/modules/http-lua/t/050-gmatch-dfa.t | 338 - debian/modules/http-lua/t/051-sub-jit.t | 149 - debian/modules/http-lua/t/052-sub-dfa.t | 235 - debian/modules/http-lua/t/053-gsub-jit.t | 149 - debian/modules/http-lua/t/054-gsub-dfa.t | 236 - debian/modules/http-lua/t/055-subreq-vars.t | 338 - debian/modules/http-lua/t/056-flush.t | 522 -- debian/modules/http-lua/t/057-flush-timeout.t | 320 - debian/modules/http-lua/t/058-tcp-socket.t | 3810 -------- debian/modules/http-lua/t/059-unix-socket.t | 203 - debian/modules/http-lua/t/060-lua-memcached.t | 168 - debian/modules/http-lua/t/061-lua-redis.t | 184 - debian/modules/http-lua/t/062-count.t | 570 -- debian/modules/http-lua/t/063-abort.t | 1019 -- debian/modules/http-lua/t/064-pcall.t | 106 - .../http-lua/t/065-tcp-socket-timeout.t | 1018 -- .../http-lua/t/066-socket-receiveuntil.t | 1331 --- debian/modules/http-lua/t/067-req-socket.t | 1098 --- .../modules/http-lua/t/068-socket-keepalive.t | 1553 --- debian/modules/http-lua/t/069-null.t | 95 - debian/modules/http-lua/t/070-sha1.t | 70 - debian/modules/http-lua/t/071-idle-socket.t | 433 - .../modules/http-lua/t/072-conditional-get.t | 90 - debian/modules/http-lua/t/073-backtrace.t | 189 - debian/modules/http-lua/t/074-prefix-var.t | 66 - debian/modules/http-lua/t/075-logby.t | 583 -- debian/modules/http-lua/t/076-no-postpone.t | 146 - debian/modules/http-lua/t/077-sleep.t | 502 - debian/modules/http-lua/t/078-hup-vars.t | 64 - .../http-lua/t/079-unused-directives.t | 342 - debian/modules/http-lua/t/080-hup-shdict.t | 84 - debian/modules/http-lua/t/081-bytecode.t | 373 - debian/modules/http-lua/t/082-body-filter.t | 839 -- debian/modules/http-lua/t/083-bad-sock-self.t | 138 - .../http-lua/t/084-inclusive-receiveuntil.t | 745 -- debian/modules/http-lua/t/085-if.t | 200 - debian/modules/http-lua/t/086-init-by.t | 323 - debian/modules/http-lua/t/087-udp-socket.t | 1176 --- debian/modules/http-lua/t/088-req-method.t | 264 - debian/modules/http-lua/t/089-phase.t | 178 - .../http-lua/t/090-log-socket-errors.t | 108 - debian/modules/http-lua/t/091-coroutine.t | 1317 --- debian/modules/http-lua/t/092-eof.t | 82 - debian/modules/http-lua/t/093-uthread-spawn.t | 1674 ---- debian/modules/http-lua/t/094-uthread-exit.t | 1650 ---- debian/modules/http-lua/t/095-uthread-exec.t | 425 - .../modules/http-lua/t/096-uthread-redirect.t | 279 - .../modules/http-lua/t/097-uthread-rewrite.t | 347 - debian/modules/http-lua/t/098-uthread-wait.t | 1323 --- debian/modules/http-lua/t/099-c-api.t | 397 - debian/modules/http-lua/t/100-client-abort.t | 1066 --- debian/modules/http-lua/t/101-on-abort.t | 848 -- .../modules/http-lua/t/102-req-start-time.t | 115 - debian/modules/http-lua/t/103-req-http-ver.t | 48 - .../modules/http-lua/t/104-req-raw-header.t | 990 -- debian/modules/http-lua/t/105-pressure.t | 53 - debian/modules/http-lua/t/106-timer.t | 2195 ----- debian/modules/http-lua/t/107-timer-errors.t | 1422 --- debian/modules/http-lua/t/108-timer-safe.t | 1397 --- debian/modules/http-lua/t/109-timer-hup.t | 502 - debian/modules/http-lua/t/110-etag.t | 83 - debian/modules/http-lua/t/111-req-header-ua.t | 675 -- .../modules/http-lua/t/112-req-header-conn.t | 148 - .../http-lua/t/113-req-header-cookie.t | 249 - debian/modules/http-lua/t/114-config.t | 48 - debian/modules/http-lua/t/115-quote-sql-str.t | 76 - .../modules/http-lua/t/116-raw-req-socket.t | 878 -- .../http-lua/t/117-raw-req-socket-timeout.t | 116 - .../modules/http-lua/t/118-use-default-type.t | 140 - debian/modules/http-lua/t/119-config-prefix.t | 32 - debian/modules/http-lua/t/120-re-find.t | 919 -- debian/modules/http-lua/t/121-version.t | 48 - debian/modules/http-lua/t/122-worker.t | 81 - debian/modules/http-lua/t/123-lua-path.t | 70 - debian/modules/http-lua/t/124-init-worker.t | 955 -- .../modules/http-lua/t/125-configure-args.t | 31 - debian/modules/http-lua/t/126-shdict-frag.t | 1266 --- debian/modules/http-lua/t/127-uthread-kill.t | 507 - .../http-lua/t/128-duplex-tcp-socket.t | 631 -- debian/modules/http-lua/t/129-ssl-socket.t | 2532 ----- debian/modules/http-lua/t/130-internal-api.t | 49 - .../http-lua/t/131-duplex-req-socket.t | 141 - debian/modules/http-lua/t/132-lua-blocks.t | 729 -- debian/modules/http-lua/t/133-worker-count.t | 72 - .../modules/http-lua/t/134-worker-count-5.t | 78 - debian/modules/http-lua/t/135-worker-id.t | 33 - debian/modules/http-lua/t/136-timer-counts.t | 111 - debian/modules/http-lua/t/137-req-misc.t | 61 - debian/modules/http-lua/t/138-balancer.t | 528 -- debian/modules/http-lua/t/139-ssl-cert-by.t | 2077 ---- debian/modules/http-lua/t/140-ssl-c-api.t | 813 -- debian/modules/http-lua/t/141-luajit.t | 48 - .../http-lua/t/142-ssl-session-store.t | 903 -- .../http-lua/t/143-ssl-session-fetch.t | 1116 --- .../modules/http-lua/t/144-shdict-incr-init.t | 226 - debian/modules/http-lua/t/145-shdict-list.t | 745 -- debian/modules/http-lua/t/146-malloc-trim.t | 342 - .../http-lua/t/147-tcp-socket-timeouts.t | 627 -- debian/modules/http-lua/t/148-fake-shm-zone.t | 170 - .../http-lua/t/149-hup-fake-shm-zone.t | 91 - .../http-lua/t/150-fake-delayed-load.t | 56 - debian/modules/http-lua/t/151-initby-hup.t | 168 - debian/modules/http-lua/t/152-timer-every.t | 385 - debian/modules/http-lua/t/153-semaphore-hup.t | 154 - debian/modules/http-lua/t/154-semaphore.t | 120 - debian/modules/http-lua/t/155-tls13.t | 106 - debian/modules/http-lua/t/StapThread.pm | 282 - debian/modules/http-lua/t/cert/dst-ca.crt | 63 - debian/modules/http-lua/t/cert/equifax.crt | 19 - debian/modules/http-lua/t/cert/test.crl | 11 - debian/modules/http-lua/t/cert/test.crt | 17 - debian/modules/http-lua/t/cert/test.key | 15 - debian/modules/http-lua/t/cert/test2.crt | 16 - debian/modules/http-lua/t/cert/test2.key | 15 - debian/modules/http-lua/t/cert/test_ecdsa.crt | 12 - debian/modules/http-lua/t/cert/test_ecdsa.key | 5 - .../t/data/fake-delayed-load-module/config | 3 - .../ngx_http_lua_fake_delayed_load_module.c | 77 - .../http-lua/t/data/fake-module/config | 3 - .../t/data/fake-module/ngx_http_fake_module.c | 118 - .../http-lua/t/data/fake-shm-module/config | 3 - .../ngx_http_lua_fake_shm_module.c | 294 - debian/modules/http-lua/t/lib/CRC32.lua | 173 - debian/modules/http-lua/t/lib/Memcached.lua | 567 -- debian/modules/http-lua/t/lib/Redis.lua | 1120 --- debian/modules/http-lua/t/lib/ljson.lua | 89 - debian/modules/http-lua/tapset/ngx_lua.stp | 5 - debian/modules/http-lua/util/build.sh | 66 - debian/modules/http-lua/util/fix-comments | 27 - debian/modules/http-lua/util/gen-lexer-c | 18 - debian/modules/http-lua/util/ngx-links | 62 - debian/modules/http-lua/util/releng | 8 - debian/modules/http-lua/util/retab | 8 - debian/modules/http-lua/util/revim | 102 - debian/modules/http-lua/util/run_test.sh | 10 - debian/modules/http-lua/util/update-readme.sh | 4 - debian/modules/http-lua/valgrind.suppress | 209 - .../patches/http-lua/CVE-2020-11724.patch | 856 -- .../http-lua/bug-994178-segfault.patch | 31 - .../http-lua/discover-luajit-2.1.patch | 47 - debian/modules/patches/http-lua/series | 3 - debian/rules | 2 - debian/tests/control | 12 +- debian/tests/lua | 18 - 358 files changed, 6 insertions(+), 182310 deletions(-) delete mode 100755 debian/libnginx-mod-http-lua.nginx delete mode 100644 debian/modules/http-lua/README.markdown delete mode 100644 debian/modules/http-lua/config delete mode 100644 debian/modules/http-lua/doc/HttpLuaModule.wiki delete mode 100644 debian/modules/http-lua/dtrace/ngx_lua_provider.d delete mode 100644 debian/modules/http-lua/misc/recv-until-pm/Makefile delete mode 100755 debian/modules/http-lua/misc/recv-until-pm/lib/RecvUntil.pm delete mode 100644 debian/modules/http-lua/misc/recv-until-pm/t/sanity.t delete mode 100644 debian/modules/http-lua/src/api/ngx_http_lua_api.h delete mode 100644 debian/modules/http-lua/src/ddebug.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_accessby.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_accessby.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_api.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_args.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_args.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_balancer.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_balancer.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_bodyfilterby.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_bodyfilterby.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_cache.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_cache.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_capturefilter.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_capturefilter.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_clfactory.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_clfactory.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_common.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_config.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_config.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_consts.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_consts.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_contentby.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_contentby.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_control.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_control.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_coroutine.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_coroutine.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_ctx.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_ctx.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_directive.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_directive.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_exception.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_exception.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_headerfilterby.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_headerfilterby.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_headers.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_headers.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_headers_in.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_headers_in.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_headers_out.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_headers_out.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_initby.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_initby.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_initworkerby.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_initworkerby.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_lex.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_lex.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_log.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_log.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_log_ringbuf.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_log_ringbuf.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_logby.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_logby.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_misc.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_misc.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_module.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_ndk.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_ndk.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_output.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_output.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_pcrefix.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_pcrefix.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_phase.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_phase.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_probe.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_regex.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_regex.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_req_body.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_req_body.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_req_method.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_req_method.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_rewriteby.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_rewriteby.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_script.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_script.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_semaphore.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_semaphore.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_setby.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_setby.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_shdict.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_shdict.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_sleep.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_sleep.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_socket_tcp.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_socket_tcp.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_socket_udp.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_socket_udp.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_ssl.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_ssl.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_ssl_certby.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_ssl_certby.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_ssl_ocsp.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_ssl_session_fetchby.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_ssl_session_fetchby.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_ssl_session_storeby.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_ssl_session_storeby.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_string.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_string.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_subrequest.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_subrequest.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_time.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_time.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_timer.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_timer.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_uri.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_uri.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_uthread.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_uthread.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_util.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_util.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_variable.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_variable.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_worker.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_worker.h delete mode 100644 debian/modules/http-lua/t/000--init.t delete mode 100644 debian/modules/http-lua/t/000-sanity.t delete mode 100644 debian/modules/http-lua/t/001-set.t delete mode 100644 debian/modules/http-lua/t/002-content.t delete mode 100644 debian/modules/http-lua/t/003-errors.t delete mode 100644 debian/modules/http-lua/t/004-require.t delete mode 100644 debian/modules/http-lua/t/005-exit.t delete mode 100644 debian/modules/http-lua/t/006-escape.t delete mode 100644 debian/modules/http-lua/t/007-md5.t delete mode 100644 debian/modules/http-lua/t/008-today.t delete mode 100644 debian/modules/http-lua/t/009-log.t delete mode 100644 debian/modules/http-lua/t/010-request_body.t delete mode 100644 debian/modules/http-lua/t/011-md5_bin.t delete mode 100644 debian/modules/http-lua/t/012-now.t delete mode 100644 debian/modules/http-lua/t/013-base64.t delete mode 100644 debian/modules/http-lua/t/014-bugs.t delete mode 100644 debian/modules/http-lua/t/015-status.t delete mode 100644 debian/modules/http-lua/t/016-resp-header.t delete mode 100644 debian/modules/http-lua/t/017-exec.t delete mode 100644 debian/modules/http-lua/t/018-ndk.t delete mode 100644 debian/modules/http-lua/t/019-const.t delete mode 100644 debian/modules/http-lua/t/020-subrequest.t delete mode 100644 debian/modules/http-lua/t/021-cookie-time.t delete mode 100644 debian/modules/http-lua/t/022-redirect.t delete mode 100644 debian/modules/http-lua/t/023-rewrite/client-abort.t delete mode 100644 debian/modules/http-lua/t/023-rewrite/exec.t delete mode 100644 debian/modules/http-lua/t/023-rewrite/exit.t delete mode 100644 debian/modules/http-lua/t/023-rewrite/mixed.t delete mode 100644 debian/modules/http-lua/t/023-rewrite/multi-capture.t delete mode 100644 debian/modules/http-lua/t/023-rewrite/on-abort.t delete mode 100644 debian/modules/http-lua/t/023-rewrite/redirect.t delete mode 100644 debian/modules/http-lua/t/023-rewrite/req-body.t delete mode 100644 debian/modules/http-lua/t/023-rewrite/req-socket.t delete mode 100644 debian/modules/http-lua/t/023-rewrite/request_body.t delete mode 100644 debian/modules/http-lua/t/023-rewrite/sanity.t delete mode 100644 debian/modules/http-lua/t/023-rewrite/sleep.t delete mode 100644 debian/modules/http-lua/t/023-rewrite/socket-keepalive.t delete mode 100644 debian/modules/http-lua/t/023-rewrite/subrequest.t delete mode 100644 debian/modules/http-lua/t/023-rewrite/tcp-socket-timeout.t delete mode 100644 debian/modules/http-lua/t/023-rewrite/tcp-socket.t delete mode 100644 debian/modules/http-lua/t/023-rewrite/unix-socket.t delete mode 100644 debian/modules/http-lua/t/023-rewrite/uthread-exec.t delete mode 100644 debian/modules/http-lua/t/023-rewrite/uthread-exit.t delete mode 100644 debian/modules/http-lua/t/023-rewrite/uthread-redirect.t delete mode 100644 debian/modules/http-lua/t/023-rewrite/uthread-spawn.t delete mode 100644 debian/modules/http-lua/t/024-access/auth.t delete mode 100644 debian/modules/http-lua/t/024-access/client-abort.t delete mode 100644 debian/modules/http-lua/t/024-access/exec.t delete mode 100644 debian/modules/http-lua/t/024-access/exit.t delete mode 100644 debian/modules/http-lua/t/024-access/mixed.t delete mode 100644 debian/modules/http-lua/t/024-access/multi-capture.t delete mode 100644 debian/modules/http-lua/t/024-access/on-abort.t delete mode 100644 debian/modules/http-lua/t/024-access/redirect.t delete mode 100644 debian/modules/http-lua/t/024-access/req-body.t delete mode 100644 debian/modules/http-lua/t/024-access/request_body.t delete mode 100644 debian/modules/http-lua/t/024-access/sanity.t delete mode 100644 debian/modules/http-lua/t/024-access/satisfy.t delete mode 100644 debian/modules/http-lua/t/024-access/sleep.t delete mode 100644 debian/modules/http-lua/t/024-access/subrequest.t delete mode 100644 debian/modules/http-lua/t/024-access/uthread-exec.t delete mode 100644 debian/modules/http-lua/t/024-access/uthread-exit.t delete mode 100644 debian/modules/http-lua/t/024-access/uthread-redirect.t delete mode 100644 debian/modules/http-lua/t/024-access/uthread-spawn.t delete mode 100644 debian/modules/http-lua/t/025-codecache.t delete mode 100644 debian/modules/http-lua/t/026-mysql.t delete mode 100644 debian/modules/http-lua/t/027-multi-capture.t delete mode 100644 debian/modules/http-lua/t/028-req-header.t delete mode 100644 debian/modules/http-lua/t/029-http-time.t delete mode 100644 debian/modules/http-lua/t/030-uri-args.t delete mode 100644 debian/modules/http-lua/t/031-post-args.t delete mode 100644 debian/modules/http-lua/t/032-iolist.t delete mode 100644 debian/modules/http-lua/t/033-ctx.t delete mode 100644 debian/modules/http-lua/t/034-match.t delete mode 100644 debian/modules/http-lua/t/035-gmatch.t delete mode 100644 debian/modules/http-lua/t/036-sub.t delete mode 100644 debian/modules/http-lua/t/037-gsub.t delete mode 100644 debian/modules/http-lua/t/038-match-o.t delete mode 100644 debian/modules/http-lua/t/039-sub-o.t delete mode 100644 debian/modules/http-lua/t/040-gsub-o.t delete mode 100644 debian/modules/http-lua/t/041-header-filter.t delete mode 100644 debian/modules/http-lua/t/042-crc32.t delete mode 100644 debian/modules/http-lua/t/043-shdict.t delete mode 100644 debian/modules/http-lua/t/044-req-body.t delete mode 100644 debian/modules/http-lua/t/045-ngx-var.t delete mode 100644 debian/modules/http-lua/t/046-hmac.t delete mode 100644 debian/modules/http-lua/t/047-match-jit.t delete mode 100644 debian/modules/http-lua/t/048-match-dfa.t delete mode 100644 debian/modules/http-lua/t/049-gmatch-jit.t delete mode 100644 debian/modules/http-lua/t/050-gmatch-dfa.t delete mode 100644 debian/modules/http-lua/t/051-sub-jit.t delete mode 100644 debian/modules/http-lua/t/052-sub-dfa.t delete mode 100644 debian/modules/http-lua/t/053-gsub-jit.t delete mode 100644 debian/modules/http-lua/t/054-gsub-dfa.t delete mode 100644 debian/modules/http-lua/t/055-subreq-vars.t delete mode 100644 debian/modules/http-lua/t/056-flush.t delete mode 100644 debian/modules/http-lua/t/057-flush-timeout.t delete mode 100644 debian/modules/http-lua/t/058-tcp-socket.t delete mode 100644 debian/modules/http-lua/t/059-unix-socket.t delete mode 100644 debian/modules/http-lua/t/060-lua-memcached.t delete mode 100644 debian/modules/http-lua/t/061-lua-redis.t delete mode 100644 debian/modules/http-lua/t/062-count.t delete mode 100644 debian/modules/http-lua/t/063-abort.t delete mode 100644 debian/modules/http-lua/t/064-pcall.t delete mode 100644 debian/modules/http-lua/t/065-tcp-socket-timeout.t delete mode 100644 debian/modules/http-lua/t/066-socket-receiveuntil.t delete mode 100644 debian/modules/http-lua/t/067-req-socket.t delete mode 100644 debian/modules/http-lua/t/068-socket-keepalive.t delete mode 100644 debian/modules/http-lua/t/069-null.t delete mode 100644 debian/modules/http-lua/t/070-sha1.t delete mode 100644 debian/modules/http-lua/t/071-idle-socket.t delete mode 100644 debian/modules/http-lua/t/072-conditional-get.t delete mode 100644 debian/modules/http-lua/t/073-backtrace.t delete mode 100644 debian/modules/http-lua/t/074-prefix-var.t delete mode 100644 debian/modules/http-lua/t/075-logby.t delete mode 100644 debian/modules/http-lua/t/076-no-postpone.t delete mode 100644 debian/modules/http-lua/t/077-sleep.t delete mode 100644 debian/modules/http-lua/t/078-hup-vars.t delete mode 100644 debian/modules/http-lua/t/079-unused-directives.t delete mode 100644 debian/modules/http-lua/t/080-hup-shdict.t delete mode 100644 debian/modules/http-lua/t/081-bytecode.t delete mode 100644 debian/modules/http-lua/t/082-body-filter.t delete mode 100644 debian/modules/http-lua/t/083-bad-sock-self.t delete mode 100644 debian/modules/http-lua/t/084-inclusive-receiveuntil.t delete mode 100644 debian/modules/http-lua/t/085-if.t delete mode 100644 debian/modules/http-lua/t/086-init-by.t delete mode 100644 debian/modules/http-lua/t/087-udp-socket.t delete mode 100644 debian/modules/http-lua/t/088-req-method.t delete mode 100644 debian/modules/http-lua/t/089-phase.t delete mode 100644 debian/modules/http-lua/t/090-log-socket-errors.t delete mode 100644 debian/modules/http-lua/t/091-coroutine.t delete mode 100644 debian/modules/http-lua/t/092-eof.t delete mode 100644 debian/modules/http-lua/t/093-uthread-spawn.t delete mode 100644 debian/modules/http-lua/t/094-uthread-exit.t delete mode 100644 debian/modules/http-lua/t/095-uthread-exec.t delete mode 100644 debian/modules/http-lua/t/096-uthread-redirect.t delete mode 100644 debian/modules/http-lua/t/097-uthread-rewrite.t delete mode 100644 debian/modules/http-lua/t/098-uthread-wait.t delete mode 100644 debian/modules/http-lua/t/099-c-api.t delete mode 100644 debian/modules/http-lua/t/100-client-abort.t delete mode 100644 debian/modules/http-lua/t/101-on-abort.t delete mode 100644 debian/modules/http-lua/t/102-req-start-time.t delete mode 100644 debian/modules/http-lua/t/103-req-http-ver.t delete mode 100644 debian/modules/http-lua/t/104-req-raw-header.t delete mode 100644 debian/modules/http-lua/t/105-pressure.t delete mode 100644 debian/modules/http-lua/t/106-timer.t delete mode 100644 debian/modules/http-lua/t/107-timer-errors.t delete mode 100644 debian/modules/http-lua/t/108-timer-safe.t delete mode 100644 debian/modules/http-lua/t/109-timer-hup.t delete mode 100644 debian/modules/http-lua/t/110-etag.t delete mode 100644 debian/modules/http-lua/t/111-req-header-ua.t delete mode 100644 debian/modules/http-lua/t/112-req-header-conn.t delete mode 100644 debian/modules/http-lua/t/113-req-header-cookie.t delete mode 100644 debian/modules/http-lua/t/114-config.t delete mode 100644 debian/modules/http-lua/t/115-quote-sql-str.t delete mode 100644 debian/modules/http-lua/t/116-raw-req-socket.t delete mode 100644 debian/modules/http-lua/t/117-raw-req-socket-timeout.t delete mode 100644 debian/modules/http-lua/t/118-use-default-type.t delete mode 100644 debian/modules/http-lua/t/119-config-prefix.t delete mode 100644 debian/modules/http-lua/t/120-re-find.t delete mode 100644 debian/modules/http-lua/t/121-version.t delete mode 100644 debian/modules/http-lua/t/122-worker.t delete mode 100644 debian/modules/http-lua/t/123-lua-path.t delete mode 100644 debian/modules/http-lua/t/124-init-worker.t delete mode 100644 debian/modules/http-lua/t/125-configure-args.t delete mode 100644 debian/modules/http-lua/t/126-shdict-frag.t delete mode 100644 debian/modules/http-lua/t/127-uthread-kill.t delete mode 100644 debian/modules/http-lua/t/128-duplex-tcp-socket.t delete mode 100644 debian/modules/http-lua/t/129-ssl-socket.t delete mode 100644 debian/modules/http-lua/t/130-internal-api.t delete mode 100644 debian/modules/http-lua/t/131-duplex-req-socket.t delete mode 100644 debian/modules/http-lua/t/132-lua-blocks.t delete mode 100644 debian/modules/http-lua/t/133-worker-count.t delete mode 100644 debian/modules/http-lua/t/134-worker-count-5.t delete mode 100644 debian/modules/http-lua/t/135-worker-id.t delete mode 100644 debian/modules/http-lua/t/136-timer-counts.t delete mode 100644 debian/modules/http-lua/t/137-req-misc.t delete mode 100644 debian/modules/http-lua/t/138-balancer.t delete mode 100644 debian/modules/http-lua/t/139-ssl-cert-by.t delete mode 100644 debian/modules/http-lua/t/140-ssl-c-api.t delete mode 100644 debian/modules/http-lua/t/141-luajit.t delete mode 100644 debian/modules/http-lua/t/142-ssl-session-store.t delete mode 100644 debian/modules/http-lua/t/143-ssl-session-fetch.t delete mode 100644 debian/modules/http-lua/t/144-shdict-incr-init.t delete mode 100644 debian/modules/http-lua/t/145-shdict-list.t delete mode 100644 debian/modules/http-lua/t/146-malloc-trim.t delete mode 100644 debian/modules/http-lua/t/147-tcp-socket-timeouts.t delete mode 100644 debian/modules/http-lua/t/148-fake-shm-zone.t delete mode 100644 debian/modules/http-lua/t/149-hup-fake-shm-zone.t delete mode 100644 debian/modules/http-lua/t/150-fake-delayed-load.t delete mode 100644 debian/modules/http-lua/t/151-initby-hup.t delete mode 100644 debian/modules/http-lua/t/152-timer-every.t delete mode 100644 debian/modules/http-lua/t/153-semaphore-hup.t delete mode 100644 debian/modules/http-lua/t/154-semaphore.t delete mode 100644 debian/modules/http-lua/t/155-tls13.t delete mode 100644 debian/modules/http-lua/t/StapThread.pm delete mode 100644 debian/modules/http-lua/t/cert/dst-ca.crt delete mode 100644 debian/modules/http-lua/t/cert/equifax.crt delete mode 100644 debian/modules/http-lua/t/cert/test.crl delete mode 100644 debian/modules/http-lua/t/cert/test.crt delete mode 100644 debian/modules/http-lua/t/cert/test.key delete mode 100644 debian/modules/http-lua/t/cert/test2.crt delete mode 100644 debian/modules/http-lua/t/cert/test2.key delete mode 100644 debian/modules/http-lua/t/cert/test_ecdsa.crt delete mode 100644 debian/modules/http-lua/t/cert/test_ecdsa.key delete mode 100644 debian/modules/http-lua/t/data/fake-delayed-load-module/config delete mode 100644 debian/modules/http-lua/t/data/fake-delayed-load-module/ngx_http_lua_fake_delayed_load_module.c delete mode 100644 debian/modules/http-lua/t/data/fake-module/config delete mode 100644 debian/modules/http-lua/t/data/fake-module/ngx_http_fake_module.c delete mode 100644 debian/modules/http-lua/t/data/fake-shm-module/config delete mode 100644 debian/modules/http-lua/t/data/fake-shm-module/ngx_http_lua_fake_shm_module.c delete mode 100755 debian/modules/http-lua/t/lib/CRC32.lua delete mode 100755 debian/modules/http-lua/t/lib/Memcached.lua delete mode 100644 debian/modules/http-lua/t/lib/Redis.lua delete mode 100644 debian/modules/http-lua/t/lib/ljson.lua delete mode 100644 debian/modules/http-lua/tapset/ngx_lua.stp delete mode 100755 debian/modules/http-lua/util/build.sh delete mode 100644 debian/modules/http-lua/util/fix-comments delete mode 100755 debian/modules/http-lua/util/gen-lexer-c delete mode 100755 debian/modules/http-lua/util/ngx-links delete mode 100755 debian/modules/http-lua/util/releng delete mode 100755 debian/modules/http-lua/util/retab delete mode 100755 debian/modules/http-lua/util/revim delete mode 100755 debian/modules/http-lua/util/run_test.sh delete mode 100755 debian/modules/http-lua/util/update-readme.sh delete mode 100644 debian/modules/http-lua/valgrind.suppress delete mode 100644 debian/modules/patches/http-lua/CVE-2020-11724.patch delete mode 100644 debian/modules/patches/http-lua/bug-994178-segfault.patch delete mode 100644 debian/modules/patches/http-lua/discover-luajit-2.1.patch delete mode 100644 debian/modules/patches/http-lua/series delete mode 100644 debian/tests/lua diff --git a/debian/changelog b/debian/changelog index a41d64e..fff7b8f 100644 --- a/debian/changelog +++ b/debian/changelog @@ -2,6 +2,7 @@ nginx (1.22.0-3) UNRELEASED; urgency=medium * d/changelog: fixed typo in bug number 61261 -> 861261 (Closes: 861261) * d/p/nginx-ssl_cert_cb_yield.patch added (Closes: 884434) + * http-lua: removed the http-lua module and moved it to a separate package -- Jan Mojžíš Mon, 08 Aug 2022 12:29:34 +0200 diff --git a/debian/control b/debian/control index c8aa03c..206523f 100644 --- a/debian/control +++ b/debian/control @@ -11,8 +11,6 @@ Build-Depends: debhelper-compat (= 13), libgd-dev, libgeoip-dev, libhiredis-dev, - liblua5.1-0-dev [!i386 !amd64 !kfreebsd-i386 !kfreebsd-amd64 !armel !armhf !powerpc !powerpcspe !mips !mipsel !mips64el !arm64 !ppc64 !s390x], - libluajit-5.1-dev [i386 amd64 kfreebsd-i386 kfreebsd-amd64 armel armhf powerpc powerpcspe mips mipsel mips64el arm64 ppc64 s390x], libmaxminddb-dev, libmhash-dev, libpam0g-dev, @@ -209,7 +207,7 @@ Depends: libnginx-mod-http-auth-pam (= ${binary:Version}), libnginx-mod-http-geoip2 (= ${binary:Version}), libnginx-mod-http-headers-more-filter (= ${binary:Version}), libnginx-mod-http-image-filter (= ${binary:Version}), - libnginx-mod-http-lua (= ${binary:Version}), + libnginx-mod-http-lua [amd64 arm64 armel armhf i386 mips64el mipsel s390x], libnginx-mod-http-perl (= ${binary:Version}), libnginx-mod-http-subs-filter (= ${binary:Version}), libnginx-mod-http-uploadprogress (= ${binary:Version}), @@ -364,20 +362,6 @@ Description: PAM authentication module for Nginx The module uses PAM as a backend for simple http authentication. It also allows setting the pam service name to allow more fine grained control. -Package: libnginx-mod-http-lua -Architecture: any -Depends: libnginx-mod-http-ndk (= ${binary:Version}), - ${misc:Depends}, - ${shlibs:Depends}, -Recommends: nginx, -Description: Lua module for Nginx - Embed Lua runtime into nginx. - . - This module embeds Lua, via the standard Lua 5.1 interpreter or LuaJIT - 2.0/2.1, into Nginx and by leveraging Nginx's subrequests, allows the - integration of the powerful Lua threads (Lua coroutines) into the Nginx event - model. - Package: libnginx-mod-http-ndk Architecture: any Depends: ${misc:Depends}, ${shlibs:Depends}, diff --git a/debian/copyright b/debian/copyright index 6449e69..2aabc8d 100644 --- a/debian/copyright +++ b/debian/copyright @@ -84,15 +84,6 @@ Files: debian/modules/http-echo/* Copyright: 2009-2014, Yichun "agentzh" Zhang License: BSD-2-clause -Files: debian/modules/http-lua/* -Copyright: 2009-2017, by Xiaozhe Wang (chaoslawful) . - 2009-2018, by Yichun "agentzh" Zhang (章亦春) , OpenResty Inc. -License: BSD-2-clause - -Files: debian/modules/http-lua/t/lib/CRC32.lua -Copyright: 2007-2008, Neil Richardson (nrich@iinet.net.au) -License: Expat - Files: debian/modules/http-upstream-fair/* Copyright: 2007, Grzegorz Nosek Igor Sysoev diff --git a/debian/libnginx-mod-http-lua.nginx b/debian/libnginx-mod-http-lua.nginx deleted file mode 100755 index 78c206f..0000000 --- a/debian/libnginx-mod-http-lua.nginx +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/perl -w - -use File::Basename; - -# Guess module name -$module = basename($0, '.nginx'); -$module =~ s/^libnginx-mod-//; - -$modulepath = $module; -$modulepath =~ s/-/_/g; - -print "mod debian/build-extras/objs/ngx_${modulepath}_module.so\n"; -print "mod debian/libnginx-mod.conf/mod-${module}.conf\n"; diff --git a/debian/modules/http-lua/README.markdown b/debian/modules/http-lua/README.markdown deleted file mode 100644 index 15ad00e..0000000 --- a/debian/modules/http-lua/README.markdown +++ /dev/null @@ -1,8332 +0,0 @@ - - -Name -==== - -ngx_http_lua_module - Embed the power of Lua into Nginx HTTP Servers. - -*This module is not distributed with the Nginx source.* See [the installation instructions](#installation). - -Table of Contents -================= - -* [Name](#name) -* [Status](#status) -* [Version](#version) -* [Synopsis](#synopsis) -* [Description](#description) -* [Typical Uses](#typical-uses) -* [Nginx Compatibility](#nginx-compatibility) -* [Installation](#installation) - * [Building as a dynamic module](#building-as-a-dynamic-module) - * [C Macro Configurations](#c-macro-configurations) - * [Installation on Ubuntu 11.10](#installation-on-ubuntu-1110) -* [Community](#community) - * [English Mailing List](#english-mailing-list) - * [Chinese Mailing List](#chinese-mailing-list) -* [Code Repository](#code-repository) -* [Bugs and Patches](#bugs-and-patches) -* [Lua/LuaJIT bytecode support](#lualuajit-bytecode-support) -* [System Environment Variable Support](#system-environment-variable-support) -* [HTTP 1.0 support](#http-10-support) -* [Statically Linking Pure Lua Modules](#statically-linking-pure-lua-modules) -* [Data Sharing within an Nginx Worker](#data-sharing-within-an-nginx-worker) -* [Known Issues](#known-issues) - * [TCP socket connect operation issues](#tcp-socket-connect-operation-issues) - * [Lua Coroutine Yielding/Resuming](#lua-coroutine-yieldingresuming) - * [Lua Variable Scope](#lua-variable-scope) - * [Locations Configured by Subrequest Directives of Other Modules](#locations-configured-by-subrequest-directives-of-other-modules) - * [Cosockets Not Available Everywhere](#cosockets-not-available-everywhere) - * [Special Escaping Sequences](#special-escaping-sequences) - * [Mixing with SSI Not Supported](#mixing-with-ssi-not-supported) - * [SPDY Mode Not Fully Supported](#spdy-mode-not-fully-supported) - * [Missing data on short circuited requests](#missing-data-on-short-circuited-requests) -* [TODO](#todo) -* [Changes](#changes) -* [Test Suite](#test-suite) -* [Copyright and License](#copyright-and-license) -* [See Also](#see-also) -* [Directives](#directives) -* [Nginx API for Lua](#nginx-api-for-lua) -* [Obsolete Sections](#obsolete-sections) - * [Special PCRE Sequences](#special-pcre-sequences) - -Status -====== - -Production ready. - -Version -======= - -This document describes ngx_lua [v0.10.13](https://github.com/openresty/lua-nginx-module/tags) released on 22 April 2018. - -Synopsis -======== -```nginx - - # set search paths for pure Lua external libraries (';;' is the default path): - lua_package_path '/foo/bar/?.lua;/blah/?.lua;;'; - - # set search paths for Lua external libraries written in C (can also use ';;'): - lua_package_cpath '/bar/baz/?.so;/blah/blah/?.so;;'; - - server { - location /lua_content { - # MIME type determined by default_type: - default_type 'text/plain'; - - content_by_lua_block { - ngx.say('Hello,world!') - } - } - - location /nginx_var { - # MIME type determined by default_type: - default_type 'text/plain'; - - # try access /nginx_var?a=hello,world - content_by_lua_block { - ngx.say(ngx.var.arg_a) - } - } - - location = /request_body { - client_max_body_size 50k; - client_body_buffer_size 50k; - - content_by_lua_block { - ngx.req.read_body() -- explicitly read the req body - local data = ngx.req.get_body_data() - if data then - ngx.say("body data:") - ngx.print(data) - return - end - - -- body may get buffered in a temp file: - local file = ngx.req.get_body_file() - if file then - ngx.say("body is in file ", file) - else - ngx.say("no body found") - end - } - } - - # transparent non-blocking I/O in Lua via subrequests - # (well, a better way is to use cosockets) - location = /lua { - # MIME type determined by default_type: - default_type 'text/plain'; - - content_by_lua_block { - local res = ngx.location.capture("/some_other_location") - if res then - ngx.say("status: ", res.status) - ngx.say("body:") - ngx.print(res.body) - end - } - } - - location = /foo { - rewrite_by_lua_block { - res = ngx.location.capture("/memc", - { args = { cmd = "incr", key = ngx.var.uri } } - ) - } - - proxy_pass http://blah.blah.com; - } - - location = /mixed { - rewrite_by_lua_file /path/to/rewrite.lua; - access_by_lua_file /path/to/access.lua; - content_by_lua_file /path/to/content.lua; - } - - # use nginx var in code path - # CAUTION: contents in nginx var must be carefully filtered, - # otherwise there'll be great security risk! - location ~ ^/app/([-_a-zA-Z0-9/]+) { - set $path $1; - content_by_lua_file /path/to/lua/app/root/$path.lua; - } - - location / { - client_max_body_size 100k; - client_body_buffer_size 100k; - - access_by_lua_block { - -- check the client IP address is in our black list - if ngx.var.remote_addr == "132.5.72.3" then - ngx.exit(ngx.HTTP_FORBIDDEN) - end - - -- check if the URI contains bad words - if ngx.var.uri and - string.match(ngx.var.request_body, "evil") - then - return ngx.redirect("/terms_of_use.html") - end - - -- tests passed - } - - # proxy_pass/fastcgi_pass/etc settings - } - } -``` - -[Back to TOC](#table-of-contents) - -Description -=========== - -This module embeds Lua, via the standard Lua 5.1 interpreter or [LuaJIT 2.0/2.1](http://luajit.org/luajit.html), into Nginx and by leveraging Nginx's subrequests, allows the integration of the powerful Lua threads (Lua coroutines) into the Nginx event model. - -Unlike [Apache's mod_lua](https://httpd.apache.org/docs/trunk/mod/mod_lua.html) and [Lighttpd's mod_magnet](http://redmine.lighttpd.net/wiki/1/Docs:ModMagnet), Lua code executed using this module can be *100% non-blocking* on network traffic as long as the [Nginx API for Lua](#nginx-api-for-lua) provided by this module is used to handle -requests to upstream services such as MySQL, PostgreSQL, Memcached, Redis, or upstream HTTP web services. - -At least the following Lua libraries and Nginx modules can be used with this ngx_lua module: - -* [lua-resty-memcached](https://github.com/openresty/lua-resty-memcached) -* [lua-resty-mysql](https://github.com/openresty/lua-resty-mysql) -* [lua-resty-redis](https://github.com/openresty/lua-resty-redis) -* [lua-resty-dns](https://github.com/openresty/lua-resty-dns) -* [lua-resty-upload](https://github.com/openresty/lua-resty-upload) -* [lua-resty-websocket](https://github.com/openresty/lua-resty-websocket) -* [lua-resty-lock](https://github.com/openresty/lua-resty-lock) -* [lua-resty-logger-socket](https://github.com/cloudflare/lua-resty-logger-socket) -* [lua-resty-lrucache](https://github.com/openresty/lua-resty-lrucache) -* [lua-resty-string](https://github.com/openresty/lua-resty-string) -* [ngx_memc](http://github.com/openresty/memc-nginx-module) -* [ngx_postgres](https://github.com/FRiCKLE/ngx_postgres) -* [ngx_redis2](http://github.com/openresty/redis2-nginx-module) -* [ngx_redis](http://wiki.nginx.org/HttpRedisModule) -* [ngx_proxy](http://nginx.org/en/docs/http/ngx_http_proxy_module.html) -* [ngx_fastcgi](http://nginx.org/en/docs/http/ngx_http_fastcgi_module.html) - -Almost all the Nginx modules can be used with this ngx_lua module by means of [ngx.location.capture](#ngxlocationcapture) or [ngx.location.capture_multi](#ngxlocationcapture_multi) but it is recommended to use those `lua-resty-*` libraries instead of creating subrequests to access the Nginx upstream modules because the former is usually much more flexible and memory-efficient. - -The Lua interpreter or LuaJIT instance is shared across all the requests in a single nginx worker process but request contexts are segregated using lightweight Lua coroutines. - -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 downstream communication protocols in the HTTP family (HTTP 0.9/1.0/1.1/2.0, WebSockets, and etc). -If you want to do generic TCP communications with the downstream clients, then you should use the [ngx_stream_lua](https://github.com/openresty/stream-lua-nginx-module#readme) module instead -which has a compatible Lua API. - -[Back to TOC](#table-of-contents) - -Typical Uses -============ - -Just to name a few: - -* Mashup'ing and processing outputs of various nginx upstream outputs (proxy, drizzle, postgres, redis, memcached, and etc) in Lua, -* doing arbitrarily complex access control and security checks in Lua before requests actually reach the upstream backends, -* manipulating response headers in an arbitrary way (by Lua) -* fetching backend information from external storage backends (like redis, memcached, mysql, postgresql) and use that information to choose which upstream backend to access on-the-fly, -* coding up arbitrarily complex web applications in a content handler using synchronous but still non-blocking access to the database backends and other storage, -* doing very complex URL dispatch in Lua at rewrite phase, -* using Lua to implement advanced caching mechanism for Nginx's subrequests and arbitrary locations. - -The possibilities are unlimited as the module allows bringing together various elements within Nginx as well as exposing the power of the Lua language to the user. The module provides the full flexibility of scripting while offering performance levels comparable with native C language programs both in terms of CPU time as well as memory footprint. This is particularly the case when LuaJIT 2.x is enabled. - -Other scripting language implementations typically struggle to match this performance level. - -The Lua state (Lua VM instance) is shared across all the requests handled by a single nginx worker process to minimize memory use. - -[Back to TOC](#table-of-contents) - -Nginx Compatibility -=================== - -The latest version of this module is compatible with the following versions of Nginx: - -* 1.13.x (last tested: 1.13.6) -* 1.12.x -* 1.11.x (last tested: 1.11.2) -* 1.10.x -* 1.9.x (last tested: 1.9.15) -* 1.8.x -* 1.7.x (last tested: 1.7.10) -* 1.6.x - -Nginx cores older than 1.6.0 (exclusive) are *not* supported. - -[Back to TOC](#table-of-contents) - -Installation -============ - -It is *highly* recommended to use [OpenResty releases](http://openresty.org) which integrate Nginx, ngx_lua, LuaJIT 2.1, as well as other powerful companion Nginx modules and Lua libraries. It is discouraged to build this module with nginx yourself since it is tricky to set up exactly right. Also, the stock nginx cores have various limitations and long standing bugs that can make some of this modules' features become disabled, not work properly, or run slower. The same applies to LuaJIT as well. OpenResty includes its own version of LuaJIT which gets specifically optimized and enhanced for the OpenResty environment. - -Alternatively, ngx_lua can be manually compiled into Nginx: - -1. Install LuaJIT 2.0 or 2.1 (recommended) or Lua 5.1 (Lua 5.2 is *not* supported yet). LuaJIT can be downloaded from the [LuaJIT project website](http://luajit.org/download.html) and Lua 5.1, from the [Lua project website](http://www.lua.org/). Some distribution package managers also distribute LuaJIT and/or Lua. -1. Download the latest version of the ngx_devel_kit (NDK) module [HERE](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 version of Nginx [HERE](http://nginx.org/) (See [Nginx Compatibility](#nginx-compatibility)) - -Build the source with this module: - -```bash - - wget 'http://nginx.org/download/nginx-1.13.6.tar.gz' - tar -xzvf nginx-1.13.6.tar.gz - cd nginx-1.13.6/ - - # tell nginx's build system where to find LuaJIT 2.0: - export LUAJIT_LIB=/path/to/luajit/lib - export LUAJIT_INC=/path/to/luajit/include/luajit-2.0 - - # tell nginx's build system where to find LuaJIT 2.1: - export LUAJIT_LIB=/path/to/luajit/lib - export LUAJIT_INC=/path/to/luajit/include/luajit-2.1 - - # or tell where to find Lua if using Lua instead: - #export LUA_LIB=/path/to/lua/lib - #export LUA_INC=/path/to/lua/include - - # Here we assume Nginx is to be installed under /opt/nginx/. - ./configure --prefix=/opt/nginx \ - --with-ld-opt="-Wl,-rpath,/path/to/luajit-or-lua/lib" \ - --add-module=/path/to/ngx_devel_kit \ - --add-module=/path/to/lua-nginx-module - - # Note that you may also want to add `./configure` options which are used in your - # current nginx build. - # You can get usually those options using command nginx -V - - # you can change the parallism number 2 below to fit the number of spare CPU cores in your - # machine. - make -j2 - make install -``` - -[Back to TOC](#table-of-contents) - -Building as a dynamic module ----------------------------- - -Starting from NGINX 1.9.11, you can also compile this module as a dynamic module, by using the `--add-dynamic-module=PATH` option instead of `--add-module=PATH` on the -`./configure` command line above. And then you can explicitly load the module in your `nginx.conf` via the [load_module](http://nginx.org/en/docs/ngx_core_module.html#load_module) -directive, for example, - -```nginx - - load_module /path/to/modules/ndk_http_module.so; # assuming NDK is built as a dynamic module too - load_module /path/to/modules/ngx_http_lua_module.so; -``` - -[Back to TOC](#table-of-contents) - -C Macro Configurations ----------------------- - -While building this module either via OpenResty or with the NGINX core, you can define the following C macros via the C compiler options: - -* `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 Lua/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. -* `NGX_LUA_NO_FFI_API` - Excludes pure C API functions for FFI-based Lua API for NGINX (as required by [lua-resty-core](https://github.com/openresty/lua-resty-core#readme), for example). Enabling this macro can make the resulting binary code size smaller. - -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, - - - ./configure --with-cc-opt="-DNGX_LUA_USE_ASSERT -DNGX_LUA_ABORT_AT_PANIC" - - -[Back to TOC](#table-of-contents) - -Installation on Ubuntu 11.10 ----------------------------- - -Note that it is recommended to use LuaJIT 2.0 or LuaJIT 2.1 instead of the standard Lua 5.1 interpreter wherever possible. - -If the standard Lua 5.1 interpreter is required however, run the following command to install it from the Ubuntu repository: - -```bash - - apt-get install -y lua5.1 liblua5.1-0 liblua5.1-0-dev -``` - -Everything should be installed correctly, except for one small tweak. - -Library name `liblua.so` has been changed in liblua5.1 package, it only comes with `liblua5.1.so`, which needs to be symlinked to `/usr/lib` so it could be found during the configuration process. - -```bash - - ln -s /usr/lib/x86_64-linux-gnu/liblua5.1.so /usr/lib/liblua.so -``` - -[Back to TOC](#table-of-contents) - -Community -========= - -[Back to TOC](#table-of-contents) - -English Mailing List --------------------- - -The [openresty-en](https://groups.google.com/group/openresty-en) mailing list is for English speakers. - -[Back to TOC](#table-of-contents) - -Chinese Mailing List --------------------- - -The [openresty](https://groups.google.com/group/openresty) mailing list is for Chinese speakers. - -[Back to TOC](#table-of-contents) - -Code Repository -=============== - -The code repository of this project is hosted on github at [openresty/lua-nginx-module](https://github.com/openresty/lua-nginx-module). - -[Back to TOC](#table-of-contents) - -Bugs and Patches -================ - -Please submit bug reports, wishlists, or patches by - -1. creating a ticket on the [GitHub Issue Tracker](https://github.com/openresty/lua-nginx-module/issues), -1. or posting to the [OpenResty community](#community). - -[Back to TOC](#table-of-contents) - -Lua/LuaJIT bytecode support -=========================== - -As from the `v0.5.0rc32` release, all `*_by_lua_file` configure directives (such as [content_by_lua_file](#content_by_lua_file)) support loading Lua 5.1 and LuaJIT 2.0/2.1 raw bytecode files directly. - -Please note that the bytecode format used by LuaJIT 2.0/2.1 is not compatible with that used by the standard Lua 5.1 interpreter. So if using LuaJIT 2.0/2.1 with ngx_lua, LuaJIT compatible bytecode files must be generated as shown: - -```bash - - /path/to/luajit/bin/luajit -b /path/to/input_file.lua /path/to/output_file.ljbc -``` - -The `-bg` option can be used to include debug information in the LuaJIT bytecode file: - -```bash - - /path/to/luajit/bin/luajit -bg /path/to/input_file.lua /path/to/output_file.ljbc -``` - -Please refer to the official LuaJIT documentation on the `-b` option for more details: - - - -Also, the bytecode files generated by LuaJIT 2.1 is *not* compatible with LuaJIT 2.0, and vice versa. The support for LuaJIT 2.1 bytecode was first added in ngx_lua v0.9.3. - -Similarly, if using the standard Lua 5.1 interpreter with ngx_lua, Lua compatible bytecode files must be generated using the `luac` commandline utility as shown: - -```bash - - luac -o /path/to/output_file.luac /path/to/input_file.lua -``` - -Unlike as with LuaJIT, debug information is included in standard Lua 5.1 bytecode files by default. This can be striped out by specifying the `-s` option as shown: - -```bash - - luac -s -o /path/to/output_file.luac /path/to/input_file.lua -``` - -Attempts to load standard Lua 5.1 bytecode files into ngx_lua instances linked to LuaJIT 2.0/2.1 or vice versa, will result in an error message, such as that below, being logged into the Nginx `error.log` file: - - - [error] 13909#0: *1 failed to load Lua inlined code: bad byte-code header in /path/to/test_file.luac - - -Loading bytecode files via the Lua primitives like `require` and `dofile` should always work as expected. - -[Back to TOC](#table-of-contents) - -System Environment Variable Support -=================================== - -If you want to access the system environment variable, say, `foo`, in Lua via the standard Lua API [os.getenv](http://www.lua.org/manual/5.1/manual.html#pdf-os.getenv), then you should also list this environment variable name in your `nginx.conf` file via the [env directive](http://nginx.org/en/docs/ngx_core_module.html#env). For example, - -```nginx - - env foo; -``` - -[Back to TOC](#table-of-contents) - -HTTP 1.0 support -================ - -The HTTP 1.0 protocol does not support chunked output and requires an explicit `Content-Length` header when the response body is not empty in order to support the HTTP 1.0 keep-alive. -So when a HTTP 1.0 request is made and the [lua_http10_buffering](#lua_http10_buffering) directive is turned `on`, ngx_lua will buffer the -output of [ngx.say](#ngxsay) and [ngx.print](#ngxprint) calls and also postpone sending response headers until all the response body output is received. -At that time ngx_lua can calculate the total length of the body and construct a proper `Content-Length` header to return to the HTTP 1.0 client. -If the `Content-Length` response header is set in the running Lua code, however, this buffering will be disabled even if the [lua_http10_buffering](#lua_http10_buffering) directive is turned `on`. - -For large streaming output responses, it is important to disable the [lua_http10_buffering](#lua_http10_buffering) directive to minimise memory usage. - -Note that common HTTP benchmark tools such as `ab` and `http_load` issue HTTP 1.0 requests by default. -To force `curl` to send HTTP 1.0 requests, use the `-0` option. - -[Back to TOC](#table-of-contents) - -Statically Linking Pure Lua Modules -=================================== - -When LuaJIT 2.x is used, it is possible to statically link the bytecode of pure Lua modules into the Nginx executable. - -Basically you use the `luajit` executable to compile `.lua` Lua module files to `.o` object files containing the exported bytecode data, and then link the `.o` files directly in your Nginx build. - -Below is a trivial example to demonstrate this. Consider that we have the following `.lua` file named `foo.lua`: - -```lua - - -- foo.lua - local _M = {} - - function _M.go() - print("Hello from foo") - end - - return _M -``` - -And then we compile this `.lua` file to `foo.o` file: - - /path/to/luajit/bin/luajit -bg foo.lua foo.o - -What matters here is the name of the `.lua` file, which determines how you use this module later on the Lua land. The file name `foo.o` does not matter at all except the `.o` file extension (which tells `luajit` what output format is used). If you want to strip the Lua debug information from the resulting bytecode, you can just specify the `-b` option above instead of `-bg`. - -Then when building Nginx or OpenResty, pass the `--with-ld-opt="foo.o"` option to the `./configure` script: - -```bash - - ./configure --with-ld-opt="/path/to/foo.o" ... -``` - -Finally, you can just do the following in any Lua code run by ngx_lua: - -```lua - - local foo = require "foo" - foo.go() -``` - -And this piece of code no longer depends on the external `foo.lua` file any more because it has already been compiled into the `nginx` executable. - -If you want to use dot in the Lua module name when calling `require`, as in - -```lua - - local foo = require "resty.foo" -``` - -then you need to rename the `foo.lua` file to `resty_foo.lua` before compiling it down to a `.o` file with the `luajit` command-line utility. - -It is important to use exactly the same version of LuaJIT when compiling `.lua` files to `.o` files as building nginx + ngx_lua. This is because the LuaJIT bytecode format may be incompatible between different LuaJIT versions. When the bytecode format is incompatible, you will see a Lua runtime error saying that the Lua module is not found. - -When you have multiple `.lua` files to compile and link, then just specify their `.o` files at the same time in the value of the `--with-ld-opt` option. For instance, - -```bash - - ./configure --with-ld-opt="/path/to/foo.o /path/to/bar.o" ... -``` - -If you have just too many `.o` files, then it might not be feasible to name them all in a single command. In this case, you can build a static library (or archive) for your `.o` files, as in - -```bash - - ar rcus libmyluafiles.a *.o -``` - -then you can link the `myluafiles` archive as a whole to your nginx executable: - -```bash - - ./configure \ - --with-ld-opt="-L/path/to/lib -Wl,--whole-archive -lmyluafiles -Wl,--no-whole-archive" -``` - -where `/path/to/lib` is the path of the directory containing the `libmyluafiles.a` file. It should be noted that the linker option `--whole-archive` is required here because otherwise our archive will be skipped because no symbols in our archive are mentioned in the main parts of the nginx executable. - -[Back to TOC](#table-of-contents) - -Data Sharing within an Nginx Worker -=================================== - -To globally share data among all the requests handled by the same nginx worker process, encapsulate the shared data into a Lua module, use the Lua `require` builtin to import the module, and then manipulate the shared data in Lua. This works because required Lua modules are loaded only once and all coroutines will share the same copy of the module (both its code and data). Note however that Lua global variables (note, not module-level variables) WILL NOT persist between requests because of the one-coroutine-per-request isolation design. - -Here is a complete small example: - -```lua - - -- mydata.lua - local _M = {} - - local data = { - dog = 3, - cat = 4, - pig = 5, - } - - function _M.get_age(name) - return data[name] - end - - return _M -``` - -and then accessing it from `nginx.conf`: - -```nginx - - location /lua { - content_by_lua_block { - local mydata = require "mydata" - ngx.say(mydata.get_age("dog")) - } - } -``` - -The `mydata` module in this example will only be loaded and run on the first request to the location `/lua`, -and all subsequent requests to the same nginx worker process will use the reloaded instance of the -module as well as the same copy of the data in it, until a `HUP` signal is sent to the Nginx master process to force a reload. -This data sharing technique is essential for high performance Lua applications based on this module. - -Note that this data sharing is on a *per-worker* basis and not on a *per-server* basis. That is, when there are multiple nginx worker processes under an Nginx master, data sharing cannot cross the process boundary between these workers. - -It is usually recommended to share read-only data this way. You can also share changeable data among all the concurrent requests of each nginx worker process as -long as there is *no* nonblocking I/O operations (including [ngx.sleep](#ngxsleep)) -in the middle of your calculations. As long as you do not give the -control back to the nginx event loop and ngx_lua's light thread -scheduler (even implicitly), there can never be any race conditions in -between. For this reason, always be very careful when you want to share changeable data on the -worker level. Buggy optimizations can easily lead to hard-to-debug -race conditions under load. - -If server-wide data sharing is required, then use one or more of the following approaches: - -1. Use the [ngx.shared.DICT](#ngxshareddict) API provided by this module. -1. Use only a single nginx worker and a single server (this is however not recommended when there is a multi core CPU or multiple CPUs in a single machine). -1. Use data storage mechanisms such as `memcached`, `redis`, `MySQL` or `PostgreSQL`. [The OpenResty bundle](http://openresty.org) associated with this module comes with a set of companion Nginx modules and Lua libraries that provide interfaces with these data storage mechanisms. - -[Back to TOC](#table-of-contents) - -Known Issues -============ - -[Back to TOC](#table-of-contents) - -TCP socket connect operation issues ------------------------------------ -The [tcpsock:connect](#tcpsockconnect) method may indicate `success` despite connection failures such as with `Connection Refused` errors. - -However, later attempts to manipulate the cosocket object will fail and return the actual error status message generated by the failed connect operation. - -This issue is due to limitations in the Nginx event model and only appears to affect Mac OS X. - -[Back to TOC](#table-of-contents) - -Lua Coroutine Yielding/Resuming -------------------------------- -* Because Lua's `dofile` and `require` builtins are currently implemented as C functions in both Lua 5.1 and LuaJIT 2.0/2.1, if the Lua file being loaded by `dofile` or `require` invokes [ngx.location.capture*](#ngxlocationcapture), [ngx.exec](#ngxexec), [ngx.exit](#ngxexit), or other API functions requiring yielding in the *top-level* scope of the Lua file, then the Lua error "attempt to yield across C-call boundary" will be raised. To avoid this, put these calls requiring yielding into your own Lua functions in the Lua file instead of the top-level scope of the file. -* As the standard Lua 5.1 interpreter's VM is not fully resumable, the methods [ngx.location.capture](#ngxlocationcapture), [ngx.location.capture_multi](#ngxlocationcapture_multi), [ngx.redirect](#ngxredirect), [ngx.exec](#ngxexec), and [ngx.exit](#ngxexit) cannot be used within the context of a Lua [pcall()](http://www.lua.org/manual/5.1/manual.html#pdf-pcall) or [xpcall()](http://www.lua.org/manual/5.1/manual.html#pdf-xpcall) or even the first line of the `for ... in ...` statement when the standard Lua 5.1 interpreter is used and the `attempt to yield across metamethod/C-call boundary` error will be produced. Please use LuaJIT 2.x, which supports a fully resumable VM, to avoid this. - -[Back to TOC](#table-of-contents) - -Lua Variable Scope ------------------- -Care must be taken when importing modules and this form should be used: - -```lua - - local xxx = require('xxx') -``` - -instead of the old deprecated form: - -```lua - - require('xxx') -``` - -Here is the reason: by design, the global environment has exactly the same lifetime as the Nginx request handler associated with it. Each request handler has its own set of Lua global variables and that is the idea of request isolation. The Lua module is actually loaded by the first Nginx request handler and is cached by the `require()` built-in in the `package.loaded` table for later reference, and the `module()` builtin used by some Lua modules has the side effect of setting a global variable to the loaded module table. But this global variable will be cleared at the end of the request handler, and every subsequent request handler all has its own (clean) global environment. So one will get Lua exception for accessing the `nil` value. - -The use of Lua global variables is a generally inadvisable in the ngx_lua context as: - -1. the misuse of Lua globals has detrimental side effects on concurrent requests when such variables should instead be local in scope, -1. Lua global variables require Lua table look-ups in the global environment which is computationally expensive, and -1. some Lua global variable references may include typing errors which make such difficult to debug. - -It is therefore *highly* recommended to always declare such within an appropriate local scope instead. - -```lua - - -- Avoid - foo = 123 - -- Recommended - local foo = 123 - - -- Avoid - function foo() return 123 end - -- Recommended - local function foo() return 123 end -``` - - -To find all instances of Lua global variables in your Lua code, run the [lua-releng tool](https://github.com/openresty/nginx-devel-utils/blob/master/lua-releng) across all `.lua` source files: - - $ lua-releng - Checking use of Lua global variables in file lib/foo/bar.lua ... - 1 [1489] SETGLOBAL 7 -1 ; contains - 55 [1506] GETGLOBAL 7 -3 ; setvar - 3 [1545] GETGLOBAL 3 -4 ; varexpand - -The output says that the line 1489 of file `lib/foo/bar.lua` writes to a global variable named `contains`, the line 1506 reads from the global variable `setvar`, and line 1545 reads the global `varexpand`. - -This tool will guarantee that local variables in the Lua module functions are all declared with the `local` keyword, otherwise a runtime exception will be thrown. It prevents undesirable race conditions while accessing such variables. See [Data Sharing within an Nginx Worker](#data-sharing-within-an-nginx-worker) for the reasons behind this. - -[Back to TOC](#table-of-contents) - -Locations Configured by Subrequest Directives of Other Modules --------------------------------------------------------------- -The [ngx.location.capture](#ngxlocationcapture) and [ngx.location.capture_multi](#ngxlocationcapture_multi) directives cannot capture locations that include the [add_before_body](http://nginx.org/en/docs/http/ngx_http_addition_module.html#add_before_body), [add_after_body](http://nginx.org/en/docs/http/ngx_http_addition_module.html#add_after_body), [auth_request](http://nginx.org/en/docs/http/ngx_http_auth_request_module.html#auth_request), [echo_location](http://github.com/openresty/echo-nginx-module#echo_location), [echo_location_async](http://github.com/openresty/echo-nginx-module#echo_location_async), [echo_subrequest](http://github.com/openresty/echo-nginx-module#echo_subrequest), or [echo_subrequest_async](http://github.com/openresty/echo-nginx-module#echo_subrequest_async) directives. - -```nginx - - location /foo { - content_by_lua_block { - res = ngx.location.capture("/bar") - } - } - location /bar { - echo_location /blah; - } - location /blah { - echo "Success!"; - } -``` - -```nginx - - $ curl -i http://example.com/foo -``` - -will not work as expected. - -[Back to TOC](#table-of-contents) - -Cosockets Not Available Everywhere ----------------------------------- - -Due to internal limitations in the nginx core, the cosocket API is disabled in the following contexts: [set_by_lua*](#set_by_lua), [log_by_lua*](#log_by_lua), [header_filter_by_lua*](#header_filter_by_lua), and [body_filter_by_lua](#body_filter_by_lua). - -The cosockets are currently also disabled in the [init_by_lua*](#init_by_lua) and [init_worker_by_lua*](#init_worker_by_lua) directive contexts but we may add support for these contexts in the future because there is no limitation in the nginx core (or the limitation might be worked around). - -There exists a work-around, however, when the original context does *not* need to wait for the cosocket results. That is, creating a zero-delay timer via the [ngx.timer.at](#ngxtimerat) API and do the cosocket results in the timer handler, which runs asynchronously as to the original context creating the timer. - -[Back to TOC](#table-of-contents) - -Special Escaping Sequences --------------------------- - -**NOTE** Following the `v0.9.17` release, this pitfall can be avoided by using the `*_by_lua_block {}` configuration directives. - -PCRE sequences such as `\d`, `\s`, or `\w`, require special attention because in string literals, the backslash character, `\`, is stripped out by both the Lua language parser and by the nginx config file parser before processing if not within a `*_by_lua_block {}` directive. So the following snippet will not work as expected: - -```nginx - - # nginx.conf - ? location /test { - ? content_by_lua ' - ? local regex = "\d+" -- THIS IS WRONG OUTSIDE OF A *_by_lua_block DIRECTIVE - ? local m = ngx.re.match("hello, 1234", regex) - ? if m then ngx.say(m[0]) else ngx.say("not matched!") end - ? '; - ? } - # evaluates to "not matched!" -``` - -To avoid this, *double* escape the backslash: - -```nginx - - # nginx.conf - location /test { - content_by_lua ' - local regex = "\\\\d+" - local m = ngx.re.match("hello, 1234", regex) - if m then ngx.say(m[0]) else ngx.say("not matched!") end - '; - } - # evaluates to "1234" -``` - -Here, `\\\\d+` is stripped down to `\\d+` by the Nginx config file parser and this is further stripped down to `\d+` by the Lua language parser before running. - -Alternatively, the regex pattern can be presented as a long-bracketed Lua string literal by encasing it in "long brackets", `[[...]]`, in which case backslashes have to only be escaped once for the Nginx config file parser. - -```nginx - - # nginx.conf - location /test { - content_by_lua ' - local regex = [[\\d+]] - local m = ngx.re.match("hello, 1234", regex) - if m then ngx.say(m[0]) else ngx.say("not matched!") end - '; - } - # evaluates to "1234" -``` - -Here, `[[\\d+]]` is stripped down to `[[\d+]]` by the Nginx config file parser and this is processed correctly. - -Note that a longer from of the long bracket, `[=[...]=]`, may be required if the regex pattern contains `[...]` sequences. -The `[=[...]=]` form may be used as the default form if desired. - -```nginx - - # nginx.conf - location /test { - content_by_lua ' - local regex = [=[[0-9]+]=] - local m = ngx.re.match("hello, 1234", regex) - if m then ngx.say(m[0]) else ngx.say("not matched!") end - '; - } - # evaluates to "1234" -``` - -An alternative approach to escaping PCRE sequences is to ensure that Lua code is placed in external script files and executed using the various `*_by_lua_file` directives. -With this approach, the backslashes are only stripped by the Lua language parser and therefore only need to be escaped once each. - -```lua - - -- test.lua - local regex = "\\d+" - local m = ngx.re.match("hello, 1234", regex) - if m then ngx.say(m[0]) else ngx.say("not matched!") end - -- evaluates to "1234" -``` - -Within external script files, PCRE sequences presented as long-bracketed Lua string literals do not require modification. - -```lua - - -- test.lua - local regex = [[\d+]] - local m = ngx.re.match("hello, 1234", regex) - if m then ngx.say(m[0]) else ngx.say("not matched!") end - -- evaluates to "1234" -``` - -As noted earlier, PCRE sequences presented within `*_by_lua_block {}` directives (available following the `v0.9.17` release) do not require modification. - -```nginx - - # nginx.conf - location /test { - content_by_lua_block { - local regex = [[\d+]] - local m = ngx.re.match("hello, 1234", regex) - if m then ngx.say(m[0]) else ngx.say("not matched!") end - } - } - # evaluates to "1234" -``` - - -[Back to TOC](#table-of-contents) - -Mixing with SSI Not Supported ------------------------------ - -Mixing SSI with ngx_lua in the same Nginx request is not supported at all. Just use ngx_lua exclusively. Everything you can do with SSI can be done atop ngx_lua anyway and it can be more efficient when using ngx_lua. - -[Back to TOC](#table-of-contents) - -SPDY Mode Not Fully Supported ------------------------------ - -Certain Lua APIs provided by ngx_lua do not work in Nginx's SPDY mode yet: [ngx.location.capture](#ngxlocationcapture), [ngx.location.capture_multi](#ngxlocationcapture_multi), and [ngx.req.socket](#ngxreqsocket). - -[Back to TOC](#table-of-contents) - -Missing data on short circuited requests ----------------------------------------- - -Nginx may terminate a request early with (at least): - -* 400 (Bad Request) -* 405 (Not Allowed) -* 408 (Request Timeout) -* 413 (Request Entity Too Large) -* 414 (Request URI Too Large) -* 494 (Request Headers Too Large) -* 499 (Client Closed Request) -* 500 (Internal Server Error) -* 501 (Not Implemented) - -This means that phases that normally run are skipped, such as the rewrite or -access phase. This also means that later phases that are run regardless, e.g. -[log_by_lua](#log_by_lua), will not have access to information that is normally set in those -phases. - -[Back to TOC](#table-of-contents) - -TODO -==== - -* cosocket: implement LuaSocket's unconnected UDP API. -* port this module to the "datagram" subsystem of NGINX for implementing general UDP servers instead of HTTP -servers in Lua. For example, -```lua - - datagram { - server { - listen 1953; - handler_by_lua_block { - -- custom Lua code implementing the special UDP server... - } - } - } -``` -* shm: implement a "shared queue API" to complement the existing [shared dict](#lua_shared_dict) API. -* cosocket: add support in the context of [init_by_lua*](#init_by_lua). -* cosocket: implement the `bind()` method for stream-typed cosockets. -* cosocket: pool-based backend concurrency level control: implement automatic `connect` queueing when the backend concurrency exceeds its connection pool limit. -* cosocket: review and merge aviramc's [patch](https://github.com/openresty/lua-nginx-module/pull/290) for adding the `bsdrecv` method. -* add new API function `ngx.resp.add_header` to emulate the standard `add_header` config directive. -* review and apply vadim-pavlov's patch for [ngx.location.capture](#ngxlocationcapture)'s `extra_headers` option -* use `ngx_hash_t` to optimize the built-in header look-up process for [ngx.req.set_header](#ngxreqset_header), [ngx.header.HEADER](#ngxheaderheader), and etc. -* add configure options for different strategies of handling the cosocket connection exceeding in the pools. -* add directives to run Lua codes when nginx stops. -* add `ignore_resp_headers`, `ignore_resp_body`, and `ignore_resp` options to [ngx.location.capture](#ngxlocationcapture) and [ngx.location.capture_multi](#ngxlocationcapture_multi) methods, to allow micro performance tuning on the user side. -* 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) - -Changes -======= - -The changes made in every release of this module are listed in the change logs of the OpenResty bundle: - - - -[Back to TOC](#table-of-contents) - -Test Suite -========== - -The following dependencies are required to run the test suite: - -* Nginx version >= 1.4.2 - -* Perl modules: - * Test::Nginx: - -* Nginx modules: - * [ngx_devel_kit](https://github.com/simplresty/ngx_devel_kit) - * [ngx_set_misc](https://github.com/openresty/set-misc-nginx-module) - * [ngx_auth_request](http://mdounin.ru/files/ngx_http_auth_request_module-0.2.tar.gz) (this is not needed if you're using Nginx 1.5.4+. - * [ngx_echo](https://github.com/openresty/echo-nginx-module) - * [ngx_memc](https://github.com/openresty/memc-nginx-module) - * [ngx_srcache](https://github.com/openresty/srcache-nginx-module) - * ngx_lua (i.e., this module) - * [ngx_lua_upstream](https://github.com/openresty/lua-upstream-nginx-module) - * [ngx_headers_more](https://github.com/openresty/headers-more-nginx-module) - * [ngx_drizzle](https://github.com/openresty/drizzle-nginx-module) - * [ngx_rds_json](https://github.com/openresty/rds-json-nginx-module) - * [ngx_coolkit](https://github.com/FRiCKLE/ngx_coolkit) - * [ngx_redis2](https://github.com/openresty/redis2-nginx-module) - -The order in which these modules are added during configuration is important because the position of any filter module in the -filtering chain determines the final output, for example. The correct adding order is shown above. - -* 3rd-party Lua libraries: - * [lua-cjson](http://www.kyne.com.au/~mark/software/lua-cjson.php) - -* Applications: - * mysql: create database 'ngx_test', grant all privileges to user 'ngx_test', password is 'ngx_test' - * memcached: listening on the default port, 11211. - * redis: listening on the default port, 6379. - -See also the [developer build script](https://github.com/openresty/lua-nginx-module/blob/master/util/build.sh) for more details on setting up the testing environment. - -To run the whole test suite in the default testing mode: - - cd /path/to/lua-nginx-module - export PATH=/path/to/your/nginx/sbin:$PATH - prove -I/path/to/test-nginx/lib -r t - - -To run specific test files: - - cd /path/to/lua-nginx-module - export PATH=/path/to/your/nginx/sbin:$PATH - prove -I/path/to/test-nginx/lib t/002-content.t t/003-errors.t - - -To run a specific test block in a particular test file, add the line `--- ONLY` to the test block you want to run, and then use the `prove` utility to run that `.t` file. - -There are also various testing modes based on mockeagain, valgrind, and etc. Refer to the [Test::Nginx documentation](http://search.cpan.org/perldoc?Test::Nginx) for more details for various advanced testing modes. See also the test reports for the Nginx test cluster running on Amazon EC2: . - -[Back to TOC](#table-of-contents) - -Copyright and License -===================== - -This module is licensed under the BSD license. - -Copyright (C) 2009-2017, by Xiaozhe Wang (chaoslawful) . - -Copyright (C) 2009-2018, by Yichun "agentzh" Zhang (章亦春) , OpenResty Inc. - -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -[Back to TOC](#table-of-contents) - -See Also -======== - -* [ngx_stream_lua_module](https://github.com/openresty/stream-lua-nginx-module#readme) for an official port of this module for the NGINX "stream" subsystem (doing generic downstream TCP communications). -* [lua-resty-memcached](https://github.com/openresty/lua-resty-memcached) library based on ngx_lua cosocket. -* [lua-resty-redis](https://github.com/openresty/lua-resty-redis) library based on ngx_lua cosocket. -* [lua-resty-mysql](https://github.com/openresty/lua-resty-mysql) library based on ngx_lua cosocket. -* [lua-resty-upload](https://github.com/openresty/lua-resty-upload) library based on ngx_lua cosocket. -* [lua-resty-dns](https://github.com/openresty/lua-resty-dns) library based on ngx_lua cosocket. -* [lua-resty-websocket](https://github.com/openresty/lua-resty-websocket) library for both WebSocket server and client, based on ngx_lua cosocket. -* [lua-resty-string](https://github.com/openresty/lua-resty-string) library based on [LuaJIT FFI](http://luajit.org/ext_ffi.html). -* [lua-resty-lock](https://github.com/openresty/lua-resty-lock) library for a nonblocking simple lock API. -* [lua-resty-cookie](https://github.com/cloudflare/lua-resty-cookie) library for HTTP cookie manipulation. -* [Routing requests to different MySQL queries based on URI arguments](http://openresty.org/#RoutingMySQLQueriesBasedOnURIArgs) -* [Dynamic Routing Based on Redis and Lua](http://openresty.org/#DynamicRoutingBasedOnRedis) -* [Using LuaRocks with ngx_lua](http://openresty.org/#UsingLuaRocks) -* [Introduction to ngx_lua](https://github.com/openresty/lua-nginx-module/wiki/Introduction) -* [ngx_devel_kit](https://github.com/simplresty/ngx_devel_kit) -* [echo-nginx-module](http://github.com/openresty/echo-nginx-module) -* [drizzle-nginx-module](http://github.com/openresty/drizzle-nginx-module) -* [postgres-nginx-module](https://github.com/FRiCKLE/ngx_postgres) -* [memc-nginx-module](http://github.com/openresty/memc-nginx-module) -* [The OpenResty bundle](http://openresty.org) -* [Nginx Systemtap Toolkit](https://github.com/openresty/nginx-systemtap-toolkit) - -[Back to TOC](#table-of-contents) - -Directives -========== - -* [lua_capture_error_log](#lua_capture_error_log) -* [lua_use_default_type](#lua_use_default_type) -* [lua_malloc_trim](#lua_malloc_trim) -* [lua_code_cache](#lua_code_cache) -* [lua_regex_cache_max_entries](#lua_regex_cache_max_entries) -* [lua_regex_match_limit](#lua_regex_match_limit) -* [lua_package_path](#lua_package_path) -* [lua_package_cpath](#lua_package_cpath) -* [init_by_lua](#init_by_lua) -* [init_by_lua_block](#init_by_lua_block) -* [init_by_lua_file](#init_by_lua_file) -* [init_worker_by_lua](#init_worker_by_lua) -* [init_worker_by_lua_block](#init_worker_by_lua_block) -* [init_worker_by_lua_file](#init_worker_by_lua_file) -* [set_by_lua](#set_by_lua) -* [set_by_lua_block](#set_by_lua_block) -* [set_by_lua_file](#set_by_lua_file) -* [content_by_lua](#content_by_lua) -* [content_by_lua_block](#content_by_lua_block) -* [content_by_lua_file](#content_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) -* [access_by_lua](#access_by_lua) -* [access_by_lua_block](#access_by_lua_block) -* [access_by_lua_file](#access_by_lua_file) -* [header_filter_by_lua](#header_filter_by_lua) -* [header_filter_by_lua_block](#header_filter_by_lua_block) -* [header_filter_by_lua_file](#header_filter_by_lua_file) -* [body_filter_by_lua](#body_filter_by_lua) -* [body_filter_by_lua_block](#body_filter_by_lua_block) -* [body_filter_by_lua_file](#body_filter_by_lua_file) -* [log_by_lua](#log_by_lua) -* [log_by_lua_block](#log_by_lua_block) -* [log_by_lua_file](#log_by_lua_file) -* [balancer_by_lua_block](#balancer_by_lua_block) -* [balancer_by_lua_file](#balancer_by_lua_file) -* [lua_need_request_body](#lua_need_request_body) -* [ssl_certificate_by_lua_block](#ssl_certificate_by_lua_block) -* [ssl_certificate_by_lua_file](#ssl_certificate_by_lua_file) -* [ssl_session_fetch_by_lua_block](#ssl_session_fetch_by_lua_block) -* [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) -* [lua_shared_dict](#lua_shared_dict) -* [lua_socket_connect_timeout](#lua_socket_connect_timeout) -* [lua_socket_send_timeout](#lua_socket_send_timeout) -* [lua_socket_send_lowat](#lua_socket_send_lowat) -* [lua_socket_read_timeout](#lua_socket_read_timeout) -* [lua_socket_buffer_size](#lua_socket_buffer_size) -* [lua_socket_pool_size](#lua_socket_pool_size) -* [lua_socket_keepalive_timeout](#lua_socket_keepalive_timeout) -* [lua_socket_log_errors](#lua_socket_log_errors) -* [lua_ssl_ciphers](#lua_ssl_ciphers) -* [lua_ssl_crl](#lua_ssl_crl) -* [lua_ssl_protocols](#lua_ssl_protocols) -* [lua_ssl_trusted_certificate](#lua_ssl_trusted_certificate) -* [lua_ssl_verify_depth](#lua_ssl_verify_depth) -* [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) -* [lua_transform_underscores_in_response_headers](#lua_transform_underscores_in_response_headers) -* [lua_check_client_abort](#lua_check_client_abort) -* [lua_max_pending_timers](#lua_max_pending_timers) -* [lua_max_running_timers](#lua_max_running_timers) - - -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) - -[Back to TOC](#table-of-contents) - -lua_capture_error_log ---------------------- -**syntax:** *lua_capture_error_log size* - -**default:** *none* - -**context:** *http* - -Enables a buffer of the specified `size` for capturing all the nginx error log message data (not just those produced -by this module or the nginx http subsystem, but everything) without touching files or disks. - -You can use units like `k` and `m` in the `size` value, as in - -```nginx - - lua_capture_error_log 100k; -``` - -As a rule of thumb, a 4KB buffer can usually hold about 20 typical error log messages. So do the maths! - -This buffer never grows. If it is full, new error log messages will replace the oldest ones in the buffer. - -The size of the buffer must be bigger than the maximum length of a single error log message (which is 4K in OpenResty and 2K in stock NGINX). - -You can read the messages in the buffer on the Lua land via the -[get_logs()](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/errlog.md#get_logs) -function of the -[ngx.errlog](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/errlog.md#readme) -module of the [lua-resty-core](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/errlog.md#readme) -library. This Lua API function will return the captured error log messages and -also remove these already read from the global capturing buffer, making room -for any new error log data. For this reason, the user should not configure this -buffer to be too big if the user read the buffered error log data fast enough. - -Note that the log level specified in the standard [error_log](http://nginx.org/r/error_log) directive -*does* have effect on this capturing facility. It only captures log -messages of a level no lower than the specified log level in the [error_log](http://nginx.org/r/error_log) directive. -The user can still choose to set an even higher filtering log level on the fly via the Lua API function -[errlog.set_filter_level](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/errlog.md#set_filter_level). -So it is more flexible than the static [error_log](http://nginx.org/r/error_log) directive. - -It is worth noting that there is no way to capture the debugging logs -without building OpenResty or NGINX with the `./configure` -option `--with-debug`. And enabling debugging logs is -strongly discouraged in production builds due to high overhead. - -This directive was first introduced in the `v0.10.9` release. - -[Back to TOC](#directives) - -lua_use_default_type --------------------- -**syntax:** *lua_use_default_type on | off* - -**default:** *lua_use_default_type on* - -**context:** *http, server, location, location if* - -Specifies whether to use the MIME type specified by the [default_type](http://nginx.org/en/docs/http/ngx_http_core_module.html#default_type) directive for the default value of the `Content-Type` response header. Deactivate this directive if a default `Content-Type` response header for Lua request handlers is not desired. - -This directive is turned on by default. - -This directive was first introduced in the `v0.9.1` release. - -[Back to TOC](#directives) - -lua_malloc_trim ---------------- -**syntax:** *lua_malloc_trim <request-count>* - -**default:** *lua_malloc_trim 1000* - -**context:** *http* - -Asks the underlying `libc` runtime library to release its cached free memory back to the operating system every -`N` requests processed by the NGINX core. By default, `N` is 1000. You can configure the request count -by using your own numbers. Smaller numbers mean more frequent releases, which may introduce higher CPU time consumption and -smaller memory footprint while larger numbers usually lead to less CPU time overhead and relatively larger memory footprint. -Just tune the number for your own use cases. - -Configuring the argument to `0` essentially turns off the periodical memory trimming altogether. - -```nginx - - lua_malloc_trim 0; # turn off trimming completely -``` - -The current implementation uses an NGINX log phase handler to do the request counting. So the appearance of the -[log_subrequest on](http://nginx.org/en/docs/http/ngx_http_core_module.html#log_subrequest) directives in `nginx.conf` -may make the counting faster when subrequests are involved. By default, only "main requests" count. - -Note that this directive does *not* affect the memory allocated by LuaJIT's own allocator based on the `mmap` -system call. - -This directive was first introduced in the `v0.10.7` release. - -[Back to TOC](#directives) - -lua_code_cache --------------- -**syntax:** *lua_code_cache on | off* - -**default:** *lua_code_cache on* - -**context:** *http, server, location, location if* - -Enables or disables the Lua code cache for Lua code in `*_by_lua_file` directives (like [set_by_lua_file](#set_by_lua_file) and -[content_by_lua_file](#content_by_lua_file)) and Lua modules. - -When turning off, every request served by ngx_lua will run in a separate Lua VM instance, starting from the `0.9.3` release. So the Lua files referenced in [set_by_lua_file](#set_by_lua_file), -[content_by_lua_file](#content_by_lua_file), [access_by_lua_file](#access_by_lua_file), -and etc will not be cached -and all Lua modules used will be loaded from scratch. With this in place, developers can adopt an edit-and-refresh approach. - -Please note however, that Lua code written inlined within nginx.conf -such as those specified by [set_by_lua](#set_by_lua), [content_by_lua](#content_by_lua), -[access_by_lua](#access_by_lua), and [rewrite_by_lua](#rewrite_by_lua) will not be updated when you edit the inlined Lua code in your `nginx.conf` file because only the Nginx config file parser can correctly parse the `nginx.conf` -file and the only way is to reload the config file -by sending a `HUP` signal or just to restart Nginx. - -Even when the code cache is enabled, Lua files which are loaded by `dofile` or `loadfile` -in *_by_lua_file cannot be cached (unless you cache the results yourself). Usually you can either use the [init_by_lua](#init_by_lua) -or [init_by_lua_file](#init-by_lua_file) directives to load all such files or just make these Lua files true Lua modules -and load them via `require`. - -The ngx_lua module does not support the `stat` mode available with the -Apache `mod_lua` module (yet). - -Disabling the Lua code cache is strongly -discouraged for production use and should only be used during -development as it has a significant negative impact on overall performance. For example, the performance of a "hello world" Lua example can drop by an order of magnitude after disabling the Lua code cache. - -[Back to TOC](#directives) - -lua_regex_cache_max_entries ---------------------------- -**syntax:** *lua_regex_cache_max_entries <num>* - -**default:** *lua_regex_cache_max_entries 1024* - -**context:** *http* - -Specifies the maximum number of entries allowed in the worker process level compiled regex cache. - -The regular expressions used in [ngx.re.match](#ngxrematch), [ngx.re.gmatch](#ngxregmatch), [ngx.re.sub](#ngxresub), and [ngx.re.gsub](#ngxregsub) will be cached within this cache if the regex option `o` (i.e., compile-once flag) is specified. - -The default number of entries allowed is 1024 and when this limit is reached, new regular expressions will not be cached (as if the `o` option was not specified) and there will be one, and only one, warning in the `error.log` file: - - - 2011/08/27 23:18:26 [warn] 31997#0: *1 lua exceeding regex cache max entries (1024), ... - - -If you are using the `ngx.re.*` implementation of [lua-resty-core](https://github.com/openresty/lua-resty-core) by loading the `resty.core.regex` module (or just the `resty.core` module), then an LRU cache is used for the regex cache being used here. - -Do not activate the `o` option for regular expressions (and/or `replace` string arguments for [ngx.re.sub](#ngxresub) and [ngx.re.gsub](#ngxregsub)) that are generated *on the fly* and give rise to infinite variations to avoid hitting the specified limit. - -[Back to TOC](#directives) - -lua_regex_match_limit ---------------------- -**syntax:** *lua_regex_match_limit <num>* - -**default:** *lua_regex_match_limit 0* - -**context:** *http* - -Specifies the "match limit" used by the PCRE library when executing the [ngx.re API](#ngxrematch). To quote the PCRE manpage, "the limit ... has the effect of limiting the amount of backtracking that can take place." - -When the limit is hit, the error string "pcre_exec() failed: -8" will be returned by the [ngx.re API](#ngxrematch) functions on the Lua land. - -When setting the limit to 0, the default "match limit" when compiling the PCRE library is used. And this is the default value of this directive. - -This directive was first introduced in the `v0.8.5` release. - -[Back to TOC](#directives) - -lua_package_path ----------------- - -**syntax:** *lua_package_path <lua-style-path-str>* - -**default:** *The content of LUA_PATH environment variable or Lua's compiled-in defaults.* - -**context:** *http* - -Sets the Lua module search path used by scripts specified by [set_by_lua](#set_by_lua), -[content_by_lua](#content_by_lua) and others. The path string is in standard Lua path form, and `;;` -can be used to stand for the original search paths. - -As from the `v0.5.0rc29` release, the special notation `$prefix` or `${prefix}` can be used in the search path string to indicate the path of the `server prefix` usually determined by the `-p PATH` command-line option while starting the Nginx server. - -[Back to TOC](#directives) - -lua_package_cpath ------------------ - -**syntax:** *lua_package_cpath <lua-style-cpath-str>* - -**default:** *The content of LUA_CPATH environment variable or Lua's compiled-in defaults.* - -**context:** *http* - -Sets the Lua C-module search path used by scripts specified by [set_by_lua](#set_by_lua), -[content_by_lua](#content_by_lua) and others. The cpath string is in standard Lua cpath form, and `;;` -can be used to stand for the original cpath. - -As from the `v0.5.0rc29` release, the special notation `$prefix` or `${prefix}` can be used in the search path string to indicate the path of the `server prefix` usually determined by the `-p PATH` command-line option while starting the Nginx server. - -[Back to TOC](#directives) - -init_by_lua ------------ - -**syntax:** *init_by_lua <lua-script-str>* - -**context:** *http* - -**phase:** *loading-config* - -**NOTE** Use of this directive is *discouraged* following the `v0.9.17` release. Use the [init_by_lua_block](#init_by_lua_block) directive instead. - -Runs the Lua code specified by the argument `` on the global Lua VM level when the Nginx master process (if any) is loading the Nginx config file. - -When Nginx receives the `HUP` signal and starts reloading the config file, the Lua VM will also be re-created and `init_by_lua` will run again on the new Lua VM. In case that the [lua_code_cache](#lua_code_cache) directive is turned off (default on), the `init_by_lua` handler will run upon every request because in this special mode a standalone Lua VM is always created for each request. - -Usually you can pre-load Lua modules at server start-up by means of this hook and take advantage of modern operating systems' copy-on-write (COW) optimization. Here is an example for pre-loading Lua modules: - -```nginx - - # this runs before forking out nginx worker processes: - init_by_lua_block { require "cjson" } - - server { - location = /api { - content_by_lua_block { - -- the following require() will just return - -- the alrady loaded module from package.loaded: - ngx.say(require "cjson".encode{dog = 5, cat = 6}) - } - } - } -``` - -You can also initialize the [lua_shared_dict](#lua_shared_dict) shm storage at this phase. Here is an example for this: - -```nginx - - lua_shared_dict dogs 1m; - - init_by_lua_block { - local dogs = ngx.shared.dogs; - dogs:set("Tom", 56) - } - - server { - location = /api { - content_by_lua_block { - local dogs = ngx.shared.dogs; - ngx.say(dogs:get("Tom")) - } - } - } -``` - -But note that, the [lua_shared_dict](#lua_shared_dict)'s shm storage will not be cleared through a config reload (via the `HUP` signal, for example). So if you do *not* want to re-initialize the shm storage in your `init_by_lua` code in this case, then you just need to set a custom flag in the shm storage and always check the flag in your `init_by_lua` code. - -Because the Lua code in this context runs before Nginx forks its worker processes (if any), data or code loaded here will enjoy the [Copy-on-write (COW)](http://en.wikipedia.org/wiki/Copy-on-write) feature provided by many operating systems among all the worker processes, thus saving a lot of memory. - -Do *not* initialize your own Lua global variables in this context because use of Lua global variables have performance penalties and can lead to global namespace pollution (see the [Lua Variable Scope](#lua-variable-scope) section for more details). The recommended way is to use proper [Lua module](http://www.lua.org/manual/5.1/manual.html#5.3) files (but do not use the standard Lua function [module()](http://www.lua.org/manual/5.1/manual.html#pdf-module) to define Lua modules because it pollutes the global namespace as well) and call [require()](http://www.lua.org/manual/5.1/manual.html#pdf-require) to load your own module files in `init_by_lua` or other contexts ([require()](http://www.lua.org/manual/5.1/manual.html#pdf-require) does cache the loaded Lua modules in the global `package.loaded` table in the Lua registry so your modules will only loaded once for the whole Lua VM instance). - -Only a small set of the [Nginx API for Lua](#nginx-api-for-lua) is supported in this context: - -* Logging APIs: [ngx.log](#ngxlog) and [print](#print), -* Shared Dictionary API: [ngx.shared.DICT](#ngxshareddict). - -More Nginx APIs for Lua may be supported in this context upon future user requests. - -Basically you can safely use Lua libraries that do blocking I/O in this very context because blocking the master process during server start-up is completely okay. Even the Nginx core does blocking I/O (at least on resolving upstream's host names) at the configure-loading phase. - -You should be very careful about potential security vulnerabilities in your Lua code registered in this context because the Nginx master process is often run under the `root` account. - -This directive was first introduced in the `v0.5.5` release. - -[Back to TOC](#directives) - -init_by_lua_block ------------------ - -**syntax:** *init_by_lua_block { lua-script }* - -**context:** *http* - -**phase:** *loading-config* - -Similar to the [init_by_lua](#init_by_lua) directive except that this directive inlines -the Lua source directly -inside a pair of curly braces (`{}`) instead of in an NGINX string literal (which requires -special character escaping). - -For instance, - -```nginx - - init_by_lua_block { - print("I need no extra escaping here, for example: \r\nblah") - } -``` - -This directive was first introduced in the `v0.9.17` release. - -[Back to TOC](#directives) - -init_by_lua_file ----------------- - -**syntax:** *init_by_lua_file <path-to-lua-script-file>* - -**context:** *http* - -**phase:** *loading-config* - -Equivalent to [init_by_lua](#init_by_lua), except that the file specified by `` contains the Lua code or [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. - -When a relative path like `foo/bar.lua` is given, they will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option while starting the Nginx server. - -This directive was first introduced in the `v0.5.5` release. - -[Back to TOC](#directives) - -init_worker_by_lua ------------------- - -**syntax:** *init_worker_by_lua <lua-script-str>* - -**context:** *http* - -**phase:** *starting-worker* - -**NOTE** Use of this directive is *discouraged* following the `v0.9.17` release. Use the [init_worker_by_lua_block](#init_worker_by_lua_block) directive instead. - -Runs the specified Lua code upon every Nginx worker process's startup when the master process is enabled. When the master process is disabled, this hook will just run after [init_by_lua*](#init_by_lua). - -This hook is often used to create per-worker reoccurring timers (via the [ngx.timer.at](#ngxtimerat) Lua API), either for backend health-check or other timed routine work. Below is an example, - -```nginx - - init_worker_by_lua ' - local delay = 3 -- in seconds - local new_timer = ngx.timer.at - local log = ngx.log - local ERR = ngx.ERR - local check - - check = function(premature) - if not premature then - -- do the health check or other routine work - local ok, err = new_timer(delay, check) - if not ok then - log(ERR, "failed to create timer: ", err) - return - end - end - end - - local hdl, err = new_timer(delay, check) - if not hdl then - log(ERR, "failed to create timer: ", err) - return - end - '; -``` - -This directive was first introduced in the `v0.9.5` release. - -This hook no longer runs in the cache manager and cache loader processes since the `v0.10.12` release. - -[Back to TOC](#directives) - -init_worker_by_lua_block ------------------------- - -**syntax:** *init_worker_by_lua_block { lua-script }* - -**context:** *http* - -**phase:** *starting-worker* - -Similar to the [init_worker_by_lua](#init_worker_by_lua) directive except that this directive inlines -the Lua source directly -inside a pair of curly braces (`{}`) instead of in an NGINX string literal (which requires -special character escaping). - -For instance, - -```nginx - - init_worker_by_lua_block { - print("I need no extra escaping here, for example: \r\nblah") - } -``` - -This directive was first introduced in the `v0.9.17` release. - -This hook no longer runs in the cache manager and cache loader processes since the `v0.10.12` release. - -[Back to TOC](#directives) - -init_worker_by_lua_file ------------------------ - -**syntax:** *init_worker_by_lua_file <lua-file-path>* - -**context:** *http* - -**phase:** *starting-worker* - -Similar to [init_worker_by_lua](#init_worker_by_lua), but accepts the file path to a Lua source file or Lua bytecode file. - -This directive was first introduced in the `v0.9.5` release. - -This hook no longer runs in the cache manager and cache loader processes since the `v0.10.12` release. - -[Back to TOC](#directives) - -set_by_lua ----------- - -**syntax:** *set_by_lua $res <lua-script-str> [$arg1 $arg2 ...]* - -**context:** *server, server if, location, location if* - -**phase:** *rewrite* - -**NOTE** Use of this directive is *discouraged* following the `v0.9.17` release. Use the [set_by_lua_block](#set_by_lua_block) directive instead. - -Executes code specified in `` with optional input arguments `$arg1 $arg2 ...`, and returns string output to `$res`. -The code in `` can make [API calls](#nginx-api-for-lua) and can retrieve input arguments from the `ngx.arg` table (index starts from `1` and increases sequentially). - -This directive is designed to execute short, fast running code blocks as the Nginx event loop is blocked during code execution. Time consuming code sequences should therefore be avoided. - -This directive is implemented by injecting custom commands into the standard [ngx_http_rewrite_module](http://nginx.org/en/docs/http/ngx_http_rewrite_module.html)'s command list. Because [ngx_http_rewrite_module](http://nginx.org/en/docs/http/ngx_http_rewrite_module.html) does not support nonblocking I/O in its commands, Lua APIs requiring yielding the current Lua "light thread" cannot work in this directive. - -At least the following API functions are currently disabled within the context of `set_by_lua`: - -* Output API functions (e.g., [ngx.say](#ngxsay) and [ngx.send_headers](#ngxsend_headers)) -* Control API functions (e.g., [ngx.exit](#ngxexit)) -* Subrequest API functions (e.g., [ngx.location.capture](#ngxlocationcapture) and [ngx.location.capture_multi](#ngxlocationcapture_multi)) -* Cosocket API functions (e.g., [ngx.socket.tcp](#ngxsockettcp) and [ngx.req.socket](#ngxreqsocket)). -* Sleeping API function [ngx.sleep](#ngxsleep). - -In addition, note that this directive can only write out a value to a single Nginx variable at -a time. However, a workaround is possible using the [ngx.var.VARIABLE](#ngxvarvariable) interface. - -```nginx - - location /foo { - set $diff ''; # we have to predefine the $diff variable here - - set_by_lua $sum ' - local a = 32 - local b = 56 - - ngx.var.diff = a - b; -- write to $diff directly - return a + b; -- return the $sum value normally - '; - - echo "sum = $sum, diff = $diff"; - } -``` - -This directive can be freely mixed with all directives of the [ngx_http_rewrite_module](http://nginx.org/en/docs/http/ngx_http_rewrite_module.html), [set-misc-nginx-module](http://github.com/openresty/set-misc-nginx-module), and [array-var-nginx-module](http://github.com/openresty/array-var-nginx-module) modules. All of these directives will run in the same order as they appear in the config file. - -```nginx - - set $foo 32; - set_by_lua $bar 'return tonumber(ngx.var.foo) + 1'; - set $baz "bar: $bar"; # $baz == "bar: 33" -``` - -As from the `v0.5.0rc29` release, Nginx variable interpolation is disabled in the `` argument of this directive and therefore, the dollar sign character (`$`) can be used directly. - -This directive requires the [ngx_devel_kit](https://github.com/simplresty/ngx_devel_kit) module. - -[Back to TOC](#directives) - -set_by_lua_block ----------------- - -**syntax:** *set_by_lua_block $res { lua-script }* - -**context:** *server, server if, location, location if* - -**phase:** *rewrite* - -Similar to the [set_by_lua](#set_by_lua) directive except that - -1. this directive inlines the Lua source directly -inside a pair of curly braces (`{}`) instead of in an NGINX string literal (which requires -special character escaping), and -1. this directive does not support extra arguments after the Lua script as in [set_by_lua](#set_by_lua). - -For example, - -```nginx - - set_by_lua_block $res { return 32 + math.cos(32) } - # $res now has the value "32.834223360507" or alike. -``` - -No special escaping is required in the Lua code block. - -This directive was first introduced in the `v0.9.17` release. - -[Back to TOC](#directives) - -set_by_lua_file ---------------- -**syntax:** *set_by_lua_file $res <path-to-lua-script-file> [$arg1 $arg2 ...]* - -**context:** *server, server if, location, location if* - -**phase:** *rewrite* - -Equivalent to [set_by_lua](#set_by_lua), except that the file specified by `` contains the Lua code, or, as from the `v0.5.0rc32` release, the [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. - -Nginx variable interpolation is supported in the `` argument string of this directive. But special care must be taken for injection attacks. - -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. - -This directive requires the [ngx_devel_kit](https://github.com/simplresty/ngx_devel_kit) module. - -[Back to TOC](#directives) - -content_by_lua --------------- - -**syntax:** *content_by_lua <lua-script-str>* - -**context:** *location, location if* - -**phase:** *content* - -**NOTE** Use of this directive is *discouraged* following the `v0.9.17` release. Use the [content_by_lua_block](#content_by_lua_block) directive instead. - -Acts as a "content handler" and executes Lua code string specified in `` for every request. -The Lua code may make [API calls](#nginx-api-for-lua) and is executed as a new spawned coroutine in an independent global environment (i.e. a sandbox). - -Do not use this directive and other content handler directives in the same location. For example, this directive and the [proxy_pass](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass) directive should not be used in the same location. - -[Back to TOC](#directives) - -content_by_lua_block --------------------- - -**syntax:** *content_by_lua_block { lua-script }* - -**context:** *location, location if* - -**phase:** *content* - -Similar to the [content_by_lua](#content_by_lua) directive except that this directive inlines -the Lua source directly -inside a pair of curly braces (`{}`) instead of in an NGINX string literal (which requires -special character escaping). - -For instance, - -```nginx - - content_by_lua_block { - ngx.say("I need no extra escaping here, for example: \r\nblah") - } -``` - -This directive was first introduced in the `v0.9.17` release. - -[Back to TOC](#directives) - -content_by_lua_file -------------------- - -**syntax:** *content_by_lua_file <path-to-lua-script-file>* - -**context:** *location, location if* - -**phase:** *content* - -Equivalent to [content_by_lua](#content_by_lua), except that the file specified by `` contains the Lua code, or, as from the `v0.5.0rc32` release, the [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. - -Nginx variables can be used in the `` string to provide flexibility. This however carries some risks and is not ordinarily recommended. - -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. - -Nginx variables are supported in the file path for dynamic dispatch, for example: - -```nginx - - # CAUTION: contents in nginx var must be carefully filtered, - # otherwise there'll be great security risk! - location ~ ^/app/([-_a-zA-Z0-9/]+) { - set $path $1; - content_by_lua_file /path/to/lua/app/root/$path.lua; - } -``` - -But be very careful about malicious user inputs and always carefully validate or filter out the user-supplied path components. - -[Back to TOC](#directives) - -rewrite_by_lua --------------- - -**syntax:** *rewrite_by_lua <lua-script-str>* - -**context:** *http, server, location, location if* - -**phase:** *rewrite tail* - -**NOTE** Use of this directive is *discouraged* following the `v0.9.17` release. Use the [rewrite_by_lua_block](#rewrite_by_lua_block) directive instead. - -Acts as a rewrite phase handler and executes Lua code string specified in `` for every request. -The Lua code may make [API calls](#nginx-api-for-lua) and is executed as a new spawned coroutine in an independent global environment (i.e. a sandbox). - -Note that this handler always runs *after* the standard [ngx_http_rewrite_module](http://nginx.org/en/docs/http/ngx_http_rewrite_module.html). So the following will work as expected: - -```nginx - - location /foo { - set $a 12; # create and initialize $a - set $b ""; # create and initialize $b - rewrite_by_lua 'ngx.var.b = tonumber(ngx.var.a) + 1'; - echo "res = $b"; - } -``` - -because `set $a 12` and `set $b ""` run *before* [rewrite_by_lua](#rewrite_by_lua). - -On the other hand, the following will not work as expected: - -```nginx - - ? location /foo { - ? set $a 12; # create and initialize $a - ? set $b ''; # create and initialize $b - ? rewrite_by_lua 'ngx.var.b = tonumber(ngx.var.a) + 1'; - ? if ($b = '13') { - ? rewrite ^ /bar redirect; - ? break; - ? } - ? - ? echo "res = $b"; - ? } -``` - -because `if` runs *before* [rewrite_by_lua](#rewrite_by_lua) even if it is placed after [rewrite_by_lua](#rewrite_by_lua) in the config. - -The right way of doing this is as follows: - -```nginx - - location /foo { - set $a 12; # create and initialize $a - set $b ''; # create and initialize $b - rewrite_by_lua ' - ngx.var.b = tonumber(ngx.var.a) + 1 - if tonumber(ngx.var.b) == 13 then - return ngx.redirect("/bar"); - end - '; - - echo "res = $b"; - } -``` - -Note that the [ngx_eval](http://www.grid.net.ru/nginx/eval.en.html) module can be approximated by using [rewrite_by_lua](#rewrite_by_lua). For example, - -```nginx - - location / { - eval $res { - proxy_pass http://foo.com/check-spam; - } - - if ($res = 'spam') { - rewrite ^ /terms-of-use.html redirect; - } - - fastcgi_pass ...; - } -``` - -can be implemented in ngx_lua as: - -```nginx - - location = /check-spam { - internal; - proxy_pass http://foo.com/check-spam; - } - - location / { - rewrite_by_lua ' - local res = ngx.location.capture("/check-spam") - if res.body == "spam" then - return ngx.redirect("/terms-of-use.html") - end - '; - - fastcgi_pass ...; - } -``` - -Just as any other rewrite phase handlers, [rewrite_by_lua](#rewrite_by_lua) also runs in subrequests. - -Note that when calling `ngx.exit(ngx.OK)` within a [rewrite_by_lua](#rewrite_by_lua) handler, the nginx request processing control flow will still continue to the content handler. To terminate the current request from within a [rewrite_by_lua](#rewrite_by_lua) handler, calling [ngx.exit](#ngxexit) with status >= 200 (`ngx.HTTP_OK`) and status < 300 (`ngx.HTTP_SPECIAL_RESPONSE`) for successful quits and `ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)` (or its friends) for failures. - -If the [ngx_http_rewrite_module](http://nginx.org/en/docs/http/ngx_http_rewrite_module.html)'s [rewrite](http://nginx.org/en/docs/http/ngx_http_rewrite_module.html#rewrite) directive is used to change the URI and initiate location re-lookups (internal redirections), then any [rewrite_by_lua](#rewrite_by_lua) or [rewrite_by_lua_file](#rewrite_by_lua_file) code sequences within the current location will not be executed. For example, - -```nginx - - location /foo { - rewrite ^ /bar; - rewrite_by_lua 'ngx.exit(503)'; - } - location /bar { - ... - } -``` - -Here the Lua code `ngx.exit(503)` will never run. This will be the case if `rewrite ^ /bar last` is used as this will similarly initiate an internal redirection. If the `break` modifier is used instead, there will be no internal redirection and the `rewrite_by_lua` code will be executed. - -The `rewrite_by_lua` code will always run at the end of the `rewrite` request-processing phase unless [rewrite_by_lua_no_postpone](#rewrite_by_lua_no_postpone) is turned on. - -[Back to TOC](#directives) - -rewrite_by_lua_block --------------------- - -**syntax:** *rewrite_by_lua_block { lua-script }* - -**context:** *http, server, location, location if* - -**phase:** *rewrite tail* - -Similar to the [rewrite_by_lua](#rewrite_by_lua) directive except that this directive inlines -the Lua source directly -inside a pair of curly braces (`{}`) instead of in an NGINX string literal (which requires -special character escaping). - -For instance, - -```nginx - - rewrite_by_lua_block { - do_something("hello, world!\nhiya\n") - } -``` - -This directive was first introduced in the `v0.9.17` release. - -[Back to TOC](#directives) - -rewrite_by_lua_file -------------------- - -**syntax:** *rewrite_by_lua_file <path-to-lua-script-file>* - -**context:** *http, server, location, location if* - -**phase:** *rewrite tail* - -Equivalent to [rewrite_by_lua](#rewrite_by_lua), except that the file specified by `` contains the Lua code, or, as from the `v0.5.0rc32` release, the [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. - -Nginx variables can be used in the `` string to provide flexibility. This however carries some risks and is not ordinarily recommended. - -When a relative path like `foo/bar.lua` is given, they will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option while starting the Nginx server. - -When the Lua code cache is turned on (by default), the user code is loaded once at the first request and cached and the Nginx config must be reloaded each time the Lua source file is modified. The Lua code cache can be temporarily disabled during development by switching [lua_code_cache](#lua_code_cache) `off` in `nginx.conf` to avoid reloading Nginx. - -The `rewrite_by_lua_file` code will always run at the end of the `rewrite` request-processing phase unless [rewrite_by_lua_no_postpone](#rewrite_by_lua_no_postpone) is turned on. - -Nginx variables are supported in the file path for dynamic dispatch just as in [content_by_lua_file](#content_by_lua_file). - -[Back to TOC](#directives) - -access_by_lua -------------- - -**syntax:** *access_by_lua <lua-script-str>* - -**context:** *http, server, location, location if* - -**phase:** *access tail* - -**NOTE** Use of this directive is *discouraged* following the `v0.9.17` release. Use the [access_by_lua_block](#access_by_lua_block) directive instead. - -Acts as an access phase handler and executes Lua code string specified in `` for every request. -The Lua code may make [API calls](#nginx-api-for-lua) and is executed as a new spawned coroutine in an independent global environment (i.e. a sandbox). - -Note that this handler always runs *after* the standard [ngx_http_access_module](http://nginx.org/en/docs/http/ngx_http_access_module.html). So the following will work as expected: - -```nginx - - location / { - deny 192.168.1.1; - allow 192.168.1.0/24; - allow 10.1.1.0/16; - deny all; - - access_by_lua ' - local res = ngx.location.capture("/mysql", { ... }) - ... - '; - - # proxy_pass/fastcgi_pass/... - } -``` - -That is, if a client IP address is in the blacklist, it will be denied before the MySQL query for more complex authentication is executed by [access_by_lua](#access_by_lua). - -Note that the [ngx_auth_request](http://mdounin.ru/hg/ngx_http_auth_request_module/) module can be approximated by using [access_by_lua](#access_by_lua): - -```nginx - - location / { - auth_request /auth; - - # proxy_pass/fastcgi_pass/postgres_pass/... - } -``` - -can be implemented in ngx_lua as: - -```nginx - - location / { - access_by_lua ' - local res = ngx.location.capture("/auth") - - if res.status == ngx.HTTP_OK then - return - end - - if res.status == ngx.HTTP_FORBIDDEN then - ngx.exit(res.status) - end - - ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR) - '; - - # proxy_pass/fastcgi_pass/postgres_pass/... - } -``` - -As with other access phase handlers, [access_by_lua](#access_by_lua) will *not* run in subrequests. - -Note that when calling `ngx.exit(ngx.OK)` within a [access_by_lua](#access_by_lua) handler, the nginx request processing control flow will still continue to the content handler. To terminate the current request from within a [access_by_lua](#access_by_lua) handler, calling [ngx.exit](#ngxexit) with status >= 200 (`ngx.HTTP_OK`) and status < 300 (`ngx.HTTP_SPECIAL_RESPONSE`) for successful quits and `ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)` (or its friends) for failures. - -Starting from the `v0.9.20` release, you can use the [access_by_lua_no_postpone](#access_by_lua_no_postpone) -directive to control when to run this handler inside the "access" request-processing phase -of NGINX. - -[Back to TOC](#directives) - -access_by_lua_block -------------------- - -**syntax:** *access_by_lua_block { lua-script }* - -**context:** *http, server, location, location if* - -**phase:** *access tail* - -Similar to the [access_by_lua](#access_by_lua) directive except that this directive inlines -the Lua source directly -inside a pair of curly braces (`{}`) instead of in an NGINX string literal (which requires -special character escaping). - -For instance, - -```nginx - - access_by_lua_block { - do_something("hello, world!\nhiya\n") - } -``` - -This directive was first introduced in the `v0.9.17` release. - -[Back to TOC](#directives) - -access_by_lua_file ------------------- - -**syntax:** *access_by_lua_file <path-to-lua-script-file>* - -**context:** *http, server, location, location if* - -**phase:** *access tail* - -Equivalent to [access_by_lua](#access_by_lua), except that the file specified by `` contains the Lua code, or, as from the `v0.5.0rc32` release, the [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. - -Nginx variables can be used in the `` string to provide flexibility. This however carries some risks and is not ordinarily recommended. - -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 repeatedly reloading Nginx. - -Nginx variables are supported in the file path for dynamic dispatch just as in [content_by_lua_file](#content_by_lua_file). - -[Back to TOC](#directives) - -header_filter_by_lua --------------------- - -**syntax:** *header_filter_by_lua <lua-script-str>* - -**context:** *http, server, location, location if* - -**phase:** *output-header-filter* - -**NOTE** Use of this directive is *discouraged* following the `v0.9.17` release. Use the [header_filter_by_lua_block](#header_filter_by_lua_block) directive instead. - -Uses Lua code specified in `` to define an output header filter. - -Note that the following API functions are currently disabled within this context: - -* Output API functions (e.g., [ngx.say](#ngxsay) and [ngx.send_headers](#ngxsend_headers)) -* Control API functions (e.g., [ngx.redirect](#ngxredirect) and [ngx.exec](#ngxexec)) -* Subrequest API functions (e.g., [ngx.location.capture](#ngxlocationcapture) and [ngx.location.capture_multi](#ngxlocationcapture_multi)) -* Cosocket API functions (e.g., [ngx.socket.tcp](#ngxsockettcp) and [ngx.req.socket](#ngxreqsocket)). - -Here is an example of overriding a response header (or adding one if absent) in our Lua header filter: - -```nginx - - location / { - proxy_pass http://mybackend; - header_filter_by_lua 'ngx.header.Foo = "blah"'; - } -``` - -This directive was first introduced in the `v0.2.1rc20` release. - -[Back to TOC](#directives) - -header_filter_by_lua_block --------------------------- - -**syntax:** *header_filter_by_lua_block { lua-script }* - -**context:** *http, server, location, location if* - -**phase:** *output-header-filter* - -Similar to the [header_filter_by_lua](#header_filter_by_lua) directive except that this directive inlines -the Lua source directly -inside a pair of curly braces (`{}`) instead of in an NGINX string literal (which requires -special character escaping). - -For instance, - -```nginx - - header_filter_by_lua_block { - ngx.header["content-length"] = nil - } -``` - -This directive was first introduced in the `v0.9.17` release. - -[Back to TOC](#directives) - -header_filter_by_lua_file -------------------------- - -**syntax:** *header_filter_by_lua_file <path-to-lua-script-file>* - -**context:** *http, server, location, location if* - -**phase:** *output-header-filter* - -Equivalent to [header_filter_by_lua](#header_filter_by_lua), except that the file specified by `` contains the Lua code, or as from the `v0.5.0rc32` release, the [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. - -When a relative path like `foo/bar.lua` is given, they will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option while starting the Nginx server. - -This directive was first introduced in the `v0.2.1rc20` release. - -[Back to TOC](#directives) - -body_filter_by_lua ------------------- - -**syntax:** *body_filter_by_lua <lua-script-str>* - -**context:** *http, server, location, location if* - -**phase:** *output-body-filter* - -**NOTE** Use of this directive is *discouraged* following the `v0.9.17` release. Use the [body_filter_by_lua_block](#body_filter_by_lua_block) directive instead. - -Uses Lua code specified in `` to define an output body filter. - -The input data chunk is passed via [ngx.arg](#ngxarg)\[1\] (as a Lua string value) and the "eof" flag indicating the end of the response body data stream is passed via [ngx.arg](#ngxarg)\[2\] (as a Lua boolean value). - -Behind the scene, the "eof" flag is just the `last_buf` (for main requests) or `last_in_chain` (for subrequests) flag of the Nginx chain link buffers. (Before the `v0.7.14` release, the "eof" flag does not work at all in subrequests.) - -The output data stream can be aborted immediately by running the following Lua statement: - -```lua - - return ngx.ERROR -``` - -This will truncate the response body and usually result in incomplete and also invalid responses. - -The Lua code can pass its own modified version of the input data chunk to the downstream Nginx output body filters by overriding [ngx.arg](#ngxarg)\[1\] with a Lua string or a Lua table of strings. For example, to transform all the lowercase letters in the response body, we can just write: - -```nginx - - location / { - proxy_pass http://mybackend; - body_filter_by_lua 'ngx.arg[1] = string.upper(ngx.arg[1])'; - } -``` - -When setting `nil` or an empty Lua string value to `ngx.arg[1]`, no data chunk will be passed to the downstream Nginx output filters at all. - -Likewise, new "eof" flag can also be specified by setting a boolean value to [ngx.arg](#ngxarg)\[2\]. For example, - -```nginx - - location /t { - echo hello world; - echo hiya globe; - - body_filter_by_lua ' - local chunk = ngx.arg[1] - if string.match(chunk, "hello") then - ngx.arg[2] = true -- new eof - return - end - - -- just throw away any remaining chunk data - ngx.arg[1] = nil - '; - } -``` - -Then `GET /t` will just return the output - - - hello world - - -That is, when the body filter sees a chunk containing the word "hello", then it will set the "eof" flag to true immediately, resulting in truncated but still valid responses. - -When the Lua code may change the length of the response body, then it is required to always clear out the `Content-Length` response header (if any) in a header filter to enforce streaming output, as in - -```nginx - - location /foo { - # fastcgi_pass/proxy_pass/... - - header_filter_by_lua_block { ngx.header.content_length = nil } - body_filter_by_lua 'ngx.arg[1] = string.len(ngx.arg[1]) .. "\\n"'; - } -``` - -Note that the following API functions are currently disabled within this context due to the limitations in NGINX output filter's current implementation: - -* Output API functions (e.g., [ngx.say](#ngxsay) and [ngx.send_headers](#ngxsend_headers)) -* Control API functions (e.g., [ngx.exit](#ngxexit) and [ngx.exec](#ngxexec)) -* Subrequest API functions (e.g., [ngx.location.capture](#ngxlocationcapture) and [ngx.location.capture_multi](#ngxlocationcapture_multi)) -* Cosocket API functions (e.g., [ngx.socket.tcp](#ngxsockettcp) and [ngx.req.socket](#ngxreqsocket)). - -Nginx output filters may be called multiple times for a single request because response body may be delivered in chunks. Thus, the Lua code specified by in this directive may also run multiple times in the lifetime of a single HTTP request. - -This directive was first introduced in the `v0.5.0rc32` release. - -[Back to TOC](#directives) - -body_filter_by_lua_block ------------------------- - -**syntax:** *body_filter_by_lua_block { lua-script-str }* - -**context:** *http, server, location, location if* - -**phase:** *output-body-filter* - -Similar to the [body_filter_by_lua](#body_filter_by_lua) directive except that this directive inlines -the Lua source directly -inside a pair of curly braces (`{}`) instead of in an NGINX string literal (which requires -special character escaping). - -For instance, - -```nginx - - body_filter_by_lua_block { - local data, eof = ngx.arg[1], ngx.arg[2] - } -``` - -This directive was first introduced in the `v0.9.17` release. - -[Back to TOC](#directives) - -body_filter_by_lua_file ------------------------ - -**syntax:** *body_filter_by_lua_file <path-to-lua-script-file>* - -**context:** *http, server, location, location if* - -**phase:** *output-body-filter* - -Equivalent to [body_filter_by_lua](#body_filter_by_lua), except that the file specified by `` contains the Lua code, or, as from the `v0.5.0rc32` release, the [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. - -When a relative path like `foo/bar.lua` is given, they will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option while starting the Nginx server. - -This directive was first introduced in the `v0.5.0rc32` release. - -[Back to TOC](#directives) - -log_by_lua ----------- - -**syntax:** *log_by_lua <lua-script-str>* - -**context:** *http, server, location, location if* - -**phase:** *log* - -**NOTE** Use of this directive is *discouraged* following the `v0.9.17` release. Use the [log_by_lua_block](#log_by_lua_block) directive instead. - -Runs the Lua source code inlined as the `` at the `log` request processing phase. This does not replace the current access logs, but runs before. - -Note that the following API functions are currently disabled within this context: - -* Output API functions (e.g., [ngx.say](#ngxsay) and [ngx.send_headers](#ngxsend_headers)) -* Control API functions (e.g., [ngx.exit](#ngxexit)) -* Subrequest API functions (e.g., [ngx.location.capture](#ngxlocationcapture) and [ngx.location.capture_multi](#ngxlocationcapture_multi)) -* Cosocket API functions (e.g., [ngx.socket.tcp](#ngxsockettcp) and [ngx.req.socket](#ngxreqsocket)). - -Here is an example of gathering average data for [$upstream_response_time](http://nginx.org/en/docs/http/ngx_http_upstream_module.html#var_upstream_response_time): - -```nginx - - lua_shared_dict log_dict 5M; - - server { - location / { - proxy_pass http://mybackend; - - log_by_lua ' - local log_dict = ngx.shared.log_dict - local upstream_time = tonumber(ngx.var.upstream_response_time) - - local sum = log_dict:get("upstream_time-sum") or 0 - sum = sum + upstream_time - log_dict:set("upstream_time-sum", sum) - - local newval, err = log_dict:incr("upstream_time-nb", 1) - if not newval and err == "not found" then - log_dict:add("upstream_time-nb", 0) - log_dict:incr("upstream_time-nb", 1) - end - '; - } - - location = /status { - content_by_lua_block { - local log_dict = ngx.shared.log_dict - local sum = log_dict:get("upstream_time-sum") - local nb = log_dict:get("upstream_time-nb") - - if nb and sum then - ngx.say("average upstream response time: ", sum / nb, - " (", nb, " reqs)") - else - ngx.say("no data yet") - end - } - } - } -``` - -This directive was first introduced in the `v0.5.0rc31` release. - -[Back to TOC](#directives) - -log_by_lua_block ----------------- - -**syntax:** *log_by_lua_block { lua-script }* - -**context:** *http, server, location, location if* - -**phase:** *log* - -Similar to the [log_by_lua](#log_by_lua) directive except that this directive inlines -the Lua source directly -inside a pair of curly braces (`{}`) instead of in an NGINX string literal (which requires -special character escaping). - -For instance, - -```nginx - - log_by_lua_block { - print("I need no extra escaping here, for example: \r\nblah") - } -``` - -This directive was first introduced in the `v0.9.17` release. - -[Back to TOC](#directives) - -log_by_lua_file ---------------- - -**syntax:** *log_by_lua_file <path-to-lua-script-file>* - -**context:** *http, server, location, location if* - -**phase:** *log* - -Equivalent to [log_by_lua](#log_by_lua), except that the file specified by `` contains the Lua code, or, as from the `v0.5.0rc32` release, the [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. - -When a relative path like `foo/bar.lua` is given, they will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option while starting the Nginx server. - -This directive was first introduced in the `v0.5.0rc31` release. - -[Back to TOC](#directives) - -balancer_by_lua_block ---------------------- - -**syntax:** *balancer_by_lua_block { lua-script }* - -**context:** *upstream* - -**phase:** *content* - -This directive runs Lua code as an upstream balancer for any upstream entities defined -by the `upstream {}` configuration block. - -For instance, - -```nginx - - upstream foo { - server 127.0.0.1; - balancer_by_lua_block { - -- use Lua to do something interesting here - -- as a dynamic balancer - } - } - - server { - location / { - proxy_pass http://foo; - } - } -``` - -The resulting Lua load balancer can work with any existing nginx upstream modules -like [ngx_proxy](http://nginx.org/en/docs/http/ngx_http_proxy_module.html) and -[ngx_fastcgi](http://nginx.org/en/docs/http/ngx_http_fastcgi_module.html). - -Also, the Lua load balancer can work with the standard upstream connection pool mechanism, -i.e., the standard [keepalive](http://nginx.org/en/docs/http/ngx_http_upstream_module.html#keepalive) directive. -Just ensure that the [keepalive](http://nginx.org/en/docs/http/ngx_http_upstream_module.html#keepalive) directive -is used *after* this `balancer_by_lua_block` directive in a single `upstream {}` configuration block. - -The Lua load balancer can totally ignore the list of servers defined in the `upstream {}` block -and select peer from a completely dynamic server list (even changing per request) via the -[ngx.balancer](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/balancer.md) module -from the [lua-resty-core](https://github.com/openresty/lua-resty-core) library. - -The Lua code handler registered by this directive might get called more than once in a single -downstream request when the nginx upstream mechanism retries the request on conditions -specified by directives like the [proxy_next_upstream](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_next_upstream) -directive. - -This Lua code execution context does not support yielding, so Lua APIs that may yield -(like cosockets and "light threads") are disabled in this context. One can usually work -around this limitation by doing such operations in an earlier phase handler (like -[access_by_lua*](#access_by_lua)) and passing along the result into this context -via the [ngx.ctx](#ngxctx) table. - -This directive was first introduced in the `v0.10.0` release. - -[Back to TOC](#directives) - -balancer_by_lua_file --------------------- - -**syntax:** *balancer_by_lua_file <path-to-lua-script-file>* - -**context:** *upstream* - -**phase:** *content* - -Equivalent to [balancer_by_lua_block](#balancer_by_lua_block), except that the file specified by `` contains the Lua code, or, as from the `v0.5.0rc32` release, the [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. - -When a relative path like `foo/bar.lua` is given, they will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option while starting the Nginx server. - -This directive was first introduced in the `v0.10.0` release. - -[Back to TOC](#directives) - -lua_need_request_body ---------------------- - -**syntax:** *lua_need_request_body <on|off>* - -**default:** *off* - -**context:** *http, server, location, location if* - -**phase:** *depends on usage* - -Determines whether to force the request body data to be read before running rewrite/access/access_by_lua* or not. The Nginx core does not read the client request body by default and if request body data is required, then this directive should be turned `on` or the [ngx.req.read_body](#ngxreqread_body) function should be called within the Lua code. - -To read the request body data within the [$request_body](http://nginx.org/en/docs/http/ngx_http_core_module.html#var_request_body) variable, -[client_body_buffer_size](http://nginx.org/en/docs/http/ngx_http_core_module.html#client_body_buffer_size) must have the same value as [client_max_body_size](http://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size). Because when the content length exceeds [client_body_buffer_size](http://nginx.org/en/docs/http/ngx_http_core_module.html#client_body_buffer_size) but less than [client_max_body_size](http://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size), Nginx will buffer the data into a temporary file on the disk, which will lead to empty value in the [$request_body](http://nginx.org/en/docs/http/ngx_http_core_module.html#var_request_body) variable. - -If the current location includes [rewrite_by_lua*](#rewrite_by_lua) directives, -then the request body will be read just before the [rewrite_by_lua*](#rewrite_by_lua) code is run (and also at the -`rewrite` phase). Similarly, if only [content_by_lua](#content_by_lua) is specified, -the request body will not be read until the content handler's Lua code is -about to run (i.e., the request body will be read during the content phase). - -It is recommended however, to use the [ngx.req.read_body](#ngxreqread_body) and [ngx.req.discard_body](#ngxreqdiscard_body) functions for finer control over the request body reading process instead. - -This also applies to [access_by_lua*](#access_by_lua). - -[Back to TOC](#directives) - -ssl_certificate_by_lua_block ----------------------------- - -**syntax:** *ssl_certificate_by_lua_block { lua-script }* - -**context:** *server* - -**phase:** *right-before-SSL-handshake* - -This directive runs user Lua code when NGINX is about to start the SSL handshake for the downstream -SSL (https) connections. - -It is particularly useful for setting the SSL certificate chain and the corresponding private key on a per-request -basis. It is also useful to load such handshake configurations nonblockingly from the remote (for example, -with the [cosocket](#ngxsockettcp) API). And one can also do per-request OCSP stapling handling in pure -Lua here as well. - -Another typical use case is to do SSL handshake traffic control nonblockingly in this context, -with the help of the [lua-resty-limit-traffic#readme](https://github.com/openresty/lua-resty-limit-traffic) -library, for example. - -One can also do interesting things with the SSL handshake requests from the client side, like -rejecting old SSL clients using the SSLv3 protocol or even below selectively. - -The [ngx.ssl](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ssl.md) -and [ngx.ocsp](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ocsp.md) Lua modules -provided by the [lua-resty-core](https://github.com/openresty/lua-resty-core/#readme) -library are particularly useful in this context. You can use the Lua API offered by these two Lua modules -to manipulate the SSL certificate chain and private key for the current SSL connection -being initiated. - -This Lua handler does not run at all, however, when NGINX/OpenSSL successfully resumes -the SSL session via SSL session IDs or TLS session tickets for the current SSL connection. In -other words, this Lua handler only runs when NGINX has to initiate a full SSL handshake. - -Below is a trivial example using the -[ngx.ssl](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ssl.md) module -at the same time: - -```nginx - - server { - listen 443 ssl; - server_name test.com; - - ssl_certificate_by_lua_block { - print("About to initiate a new SSL handshake!") - } - - location / { - root html; - } - } -``` - -See more complicated examples in the [ngx.ssl](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ssl.md) -and [ngx.ocsp](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ocsp.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, however, you still need to configure the [ssl_certificate](http://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_certificate) and -[ssl_certificate_key](http://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_certificate_key) -directives even though you will not use this static certificate and private key at all. This is -because the NGINX core requires their appearance otherwise you are seeing the following error -while starting NGINX: - - - nginx: [emerg] no ssl configured for the server - - -This directive currently requires the following NGINX core patch to work correctly: - - - -The bundled version of the NGINX core in OpenResty 1.9.7.2 (or above) already has this -patch applied. - -Furthermore, one needs at least OpenSSL 1.0.2e for this directive to work. - -This directive was first introduced in the `v0.10.0` release. - -[Back to TOC](#directives) - -ssl_certificate_by_lua_file ---------------------------- - -**syntax:** *ssl_certificate_by_lua_file <path-to-lua-script-file>* - -**context:** *server* - -**phase:** *right-before-SSL-handshake* - -Equivalent to [ssl_certificate_by_lua_block](#ssl_certificate_by_lua_block), except that the file specified by `` contains the Lua code, or, as from the `v0.5.0rc32` release, the [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. - -When a relative path like `foo/bar.lua` is given, they will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option while starting the Nginx server. - -This directive was first introduced in the `v0.10.0` release. - -[Back to TOC](#directives) - -ssl_session_fetch_by_lua_block ------------------------------- - -**syntax:** *ssl_session_fetch_by_lua_block { lua-script }* - -**context:** *http* - -**phase:** *right-before-SSL-handshake* - -This directive runs Lua code to look up and load the SSL session (if any) according to the session ID -provided by the current SSL handshake request for the downstream. - -The Lua API for obtaining the current session ID and loading a cached SSL session data -is provided in the [ngx.ssl.session](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ssl/session.md) -Lua module shipped with the [lua-resty-core](https://github.com/openresty/lua-resty-core#readme) -library. - -Lua APIs that may yield, like [ngx.sleep](#ngxsleep) and [cosockets](#ngxsockettcp), -are enabled in this context. - -This hook, together with the [ssl_session_store_by_lua*](#ssl_session_store_by_lua_block) hook, -can be used to implement distributed caching mechanisms in pure Lua (based -on the [cosocket](#ngxsockettcp) API, for example). If a cached SSL session is found -and loaded into the current SSL connection context, -SSL session resumption can then get immediately initiated and bypass the full SSL handshake process which is very expensive in terms of CPU time. - -Please note that TLS session tickets are very different and it is the clients' responsibility -to cache the SSL session state when session tickets are used. SSL session resumptions based on -TLS session tickets would happen automatically without going through this hook (nor the -[ssl_session_store_by_lua_block](#ssl_session_store_by_lua) hook). This hook is mainly -for older or less capable SSL clients that can only do SSL sessions by session IDs. - -When [ssl_certificate_by_lua*](#ssl_certificate_by_lua_block) is specified at the same time, -this hook usually runs before [ssl_certificate_by_lua*](#ssl_certificate_by_lua_block). -When the SSL session is found and successfully loaded for the current SSL connection, -SSL session resumption will happen and thus bypass the [ssl_certificate_by_lua*](#ssl_certificate_by_lua_block) -hook completely. In this case, NGINX also bypasses the [ssl_session_store_by_lua_block](#ssl_session_store_by_lua) -hook, for obvious reasons. - -To easily test this hook locally with a modern web browser, you can temporarily put the following line -in your https server block to disable the TLS session ticket support: - - ssl_session_tickets off; - -But do not forget to comment this line out before publishing your site to the world. - -If you are using the [official pre-built packages](http://openresty.org/en/linux-packages.html) for [OpenResty](https://openresty.org/) -1.11.2.1 or later, then everything should work out of the box. - -If you are using OpenSSL libraries not provided by [OpenResty](https://openresty.org), -then you need to apply the following patch for OpenSSL 1.0.2h or later: - - - -If you are not using the NGINX core shipped with [OpenResty](https://openresty.org) 1.11.2.1 or later, then you need to -apply the following patch to the standard NGINX core 1.11.2 or later: - - - -This directive was first introduced in the `v0.10.6` release. - -Note that: this directive is only allowed to used in **http context** from the `v0.10.7` release -(because SSL session resumption happens before server name dispatch). - -[Back to TOC](#directives) - -ssl_session_fetch_by_lua_file ------------------------------ - -**syntax:** *ssl_session_fetch_by_lua_file <path-to-lua-script-file>* - -**context:** *http* - -**phase:** *right-before-SSL-handshake* - -Equivalent to [ssl_session_fetch_by_lua_block](#ssl_session_fetch_by_lua_block), except that the file specified by `` contains the Lua code, or rather, the [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. - -When a relative path like `foo/bar.lua` is given, they will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option while starting the Nginx server. - -This directive was first introduced in the `v0.10.6` release. - -Note that: this directive is only allowed to used in **http context** from the `v0.10.7` release -(because SSL session resumption happens before server name dispatch). - -[Back to TOC](#directives) - -ssl_session_store_by_lua_block ------------------------------- - -**syntax:** *ssl_session_store_by_lua_block { lua-script }* - -**context:** *http* - -**phase:** *right-after-SSL-handshake* - -This directive runs Lua code to fetch and save the SSL session (if any) according to the session ID -provided by the current SSL handshake request for the downstream. The saved or cached SSL -session data can be used for future SSL connections to resume SSL sessions without going -through the full SSL handshake process (which is very expensive in terms of CPU time). - -Lua APIs that may yield, like [ngx.sleep](#ngxsleep) and [cosockets](#ngxsockettcp), -are *disabled* in this context. You can still, however, use the [ngx.timer.at](#ngxtimerat) API -to create 0-delay timers to save the SSL session data asynchronously to external services (like `redis` or `memcached`). - -The Lua API for obtaining the current session ID and the associated session state data -is provided in the [ngx.ssl.session](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ssl/session.md#readme) -Lua module shipped with the [lua-resty-core](https://github.com/openresty/lua-resty-core#readme) -library. - -To easily test this hook locally with a modern web browser, you can temporarily put the following line -in your https server block to disable the TLS session ticket support: - - ssl_session_tickets off; - -But do not forget to comment this line out before publishing your site to the world. - -This directive was first introduced in the `v0.10.6` release. - -Note that: this directive is only allowed to used in **http context** from the `v0.10.7` release -(because SSL session resumption happens before server name dispatch). - -[Back to TOC](#directives) - -ssl_session_store_by_lua_file ------------------------------ - -**syntax:** *ssl_session_store_by_lua_file <path-to-lua-script-file>* - -**context:** *http* - -**phase:** *right-after-SSL-handshake* - -Equivalent to [ssl_session_store_by_lua_block](#ssl_session_store_by_lua_block), except that the file specified by `` contains the Lua code, or rather, the [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. - -When a relative path like `foo/bar.lua` is given, they will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option while starting the Nginx server. - -This directive was first introduced in the `v0.10.6` release. - -Note that: this directive is only allowed to used in **http context** from the `v0.10.7` release -(because SSL session resumption happens before server name dispatch). - -[Back to TOC](#directives) - -lua_shared_dict ---------------- - -**syntax:** *lua_shared_dict <name> <size>* - -**default:** *no* - -**context:** *http* - -**phase:** *depends on usage* - -Declares a shared memory zone, ``, to serve as storage for the shm based Lua dictionary `ngx.shared.`. - -Shared memory zones are always shared by all the nginx worker processes in the current nginx server instance. - -The `` argument accepts size units such as `k` and `m`: - -```nginx - - http { - lua_shared_dict dogs 10m; - ... - } -``` - -The hard-coded minimum size is 8KB while the practical minimum size depends -on actual user data set (some people start with 12KB). - -See [ngx.shared.DICT](#ngxshareddict) for details. - -This directive was first introduced in the `v0.3.1rc22` release. - -[Back to TOC](#directives) - -lua_socket_connect_timeout --------------------------- - -**syntax:** *lua_socket_connect_timeout <time>* - -**default:** *lua_socket_connect_timeout 60s* - -**context:** *http, server, location* - -This directive controls the default timeout value used in TCP/unix-domain socket object's [connect](#tcpsockconnect) method and can be overridden by the [settimeout](#tcpsocksettimeout) or [settimeouts](#tcpsocksettimeouts) methods. - -The `
- -
- live streams - - -
- vod streams - - -
- - - var d=document.getElementById('-'); - d.style.display=d.style.display=='none'?'':'none'; - return false - - - - [EMPTY] - - - -    - - - - - - - - - - - -   - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - -
IdStateAddressFlash versionPage URLSWF URLDroppedTimestampA-VTime
-
- - - http://apps.db.ripe.net/search/query.html?searchtext= - - whois - - - - - - - - - - - - - -
fnamesizedate
") - + entry[i].name.len + entry[i].utf_len + entry[i].escape_html - + alcf->name_length + ngx_sizeof_ssz(">") - + ngx_sizeof_ssz("") - + 20 /* File size */ - + ngx_sizeof_ssz("") /* Date prefix */ - + ngx_sizeof_ssz("
tag */ - b->last = ngx_cpymem_ssz(b->last, t06_list1); - - tp = ngx_timeofday(); - - /* "Parent dir" entry, always first if displayed */ - if (r->uri.len > 1 && alcf->hide_parent == 0) { - b->last = ngx_cpymem_ssz(b->last, - "" - "" - "" - "" - "" - CRLF); - } - - /* Entries for directories and files */ - for (i = 0; i < entries.nelts; i++) { - b->last = ngx_cpymem_ssz(b->last, ""); - - *b->last++ = CR; - *b->last++ = LF; - } - - /* Output table bottom */ - b->last = ngx_cpymem_ssz(b->last, t07_list2); - - *pb = b; - return NGX_OK; -} - - - -static ngx_int_t -ngx_http_fancyindex_handler(ngx_http_request_t *r) -{ - ngx_http_request_t *sr; - ngx_str_t *sr_uri; - ngx_str_t rel_uri; - ngx_int_t rc; - ngx_http_fancyindex_loc_conf_t *alcf; - ngx_chain_t out[3] = { - { NULL, NULL }, { NULL, NULL}, { NULL, NULL }}; - - - if (r->uri.data[r->uri.len - 1] != '/') { - return NGX_DECLINED; - } - - /* TODO: Win32 */ -#if defined(nginx_version) \ - && ((nginx_version < 7066) \ - || ((nginx_version > 8000) && (nginx_version < 8038))) - if (r->zero_in_uri) { - return NGX_DECLINED; - } -#endif - - if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) { - return NGX_DECLINED; - } - - alcf = ngx_http_get_module_loc_conf(r, ngx_http_fancyindex_module); - - if (!alcf->enable) { - return NGX_DECLINED; - } - - if ((rc = make_content_buf(r, &out[0].buf, alcf)) != NGX_OK) - return rc; - - out[0].buf->last_in_chain = 1; - - r->headers_out.status = NGX_HTTP_OK; - r->headers_out.content_type_len = ngx_sizeof_ssz("text/html"); - r->headers_out.content_type.len = ngx_sizeof_ssz("text/html"); - r->headers_out.content_type.data = (u_char *) "text/html"; - - rc = ngx_http_send_header(r); - if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) - return rc; - - if (alcf->header.path.len > 0 && alcf->header.local.len == 0) { - /* URI is configured, make Nginx take care of with a subrequest. */ - sr_uri = &alcf->header.path; - - if (*sr_uri->data != '/') { - /* Relative path */ - rel_uri.len = r->uri.len + alcf->header.path.len; - rel_uri.data = ngx_palloc(r->pool, rel_uri.len); - if (rel_uri.data == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - ngx_memcpy(ngx_cpymem(rel_uri.data, r->uri.data, r->uri.len), - alcf->header.path.data, alcf->header.path.len); - sr_uri = &rel_uri; - } - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http fancyindex: header subrequest \"%V\"", sr_uri); - - rc = ngx_http_subrequest(r, sr_uri, NULL, &sr, NULL, 0); - if (rc == NGX_ERROR || rc == NGX_DONE) { - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http fancyindex: header subrequest for \"%V\" failed", sr_uri); - return rc; - } - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http fancyindex: header subrequest status = %i", - sr->headers_out.status); - /* ngx_http_subrequest returns NGX_OK(0), not NGX_HTTP_OK(200) */ - if (sr->headers_out.status != NGX_OK) { - /* - * XXX: Should we write a message to the error log just in case - * we get something different from a 404? - */ - goto add_builtin_header; - } - } - else { -add_builtin_header: - /* Make space before */ - out[1].next = out[0].next; - out[1].buf = out[0].buf; - /* Chain header buffer */ - out[0].next = &out[1]; - if (alcf->header.local.len > 0) { - /* Header buffer is local, make a buffer pointing to the data. */ - out[0].buf = ngx_calloc_buf(r->pool); - if (out[0].buf == NULL) - return NGX_ERROR; - out[0].buf->memory = 1; - out[0].buf->pos = alcf->header.local.data; - out[0].buf->last = alcf->header.local.data + alcf->header.local.len; - } else { - /* Prepare a buffer with the contents of the builtin header. */ - out[0].buf = make_header_buf(r, alcf->css_href); - } - } - - /* If footer is disabled, chain up footer buffer. */ - if (alcf->footer.path.len == 0 || alcf->footer.local.len > 0) { - ngx_uint_t last = (alcf->header.path.len == 0) ? 2 : 1; - - out[last-1].next = &out[last]; - out[last].buf = ngx_calloc_buf(r->pool); - if (out[last].buf == NULL) - return NGX_ERROR; - - out[last].buf->memory = 1; - if (alcf->footer.local.len > 0) { - out[last].buf->pos = alcf->footer.local.data; - out[last].buf->last = alcf->footer.local.data + alcf->footer.local.len; - } else { - out[last].buf->pos = (u_char*) t08_foot1; - out[last].buf->last = (u_char*) t08_foot1 + sizeof(t08_foot1) - 1; - } - - out[last-1].buf->last_in_chain = 0; - out[last].buf->last_in_chain = 1; - out[last].buf->last_buf = 1; - /* Send everything with a single call :D */ - return ngx_http_output_filter(r, &out[0]); - } - - /* - * If we reach here, we were asked to send a custom footer. We need to: - * partially send whatever is referenced from out[0] and then send the - * footer as a subrequest. If the subrequest fails, we should send the - * standard footer as well. - */ - rc = ngx_http_output_filter(r, &out[0]); - - if (rc != NGX_OK && rc != NGX_AGAIN) - return NGX_HTTP_INTERNAL_SERVER_ERROR; - - /* URI is configured, make Nginx take care of with a subrequest. */ - sr_uri = &alcf->footer.path; - - if (*sr_uri->data != '/') { - /* Relative path */ - rel_uri.len = r->uri.len + alcf->footer.path.len; - rel_uri.data = ngx_palloc(r->pool, rel_uri.len); - if (rel_uri.data == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - ngx_memcpy(ngx_cpymem(rel_uri.data, r->uri.data, r->uri.len), - alcf->footer.path.data, alcf->footer.path.len); - sr_uri = &rel_uri; - } - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http fancyindex: footer subrequest \"%V\"", sr_uri); - - rc = ngx_http_subrequest(r, sr_uri, NULL, &sr, NULL, 0); - if (rc == NGX_ERROR || rc == NGX_DONE) { - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http fancyindex: footer subrequest for \"%V\" failed", sr_uri); - return rc; - } - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http fancyindex: header subrequest status = %i", - sr->headers_out.status); - - /* see above: ngx_http_subrequest resturns NGX_OK (0) not NGX_HTTP_OK (200) */ - if (sr->headers_out.status != NGX_OK) { - /* - * XXX: Should we write a message to the error log just in case - * we get something different from a 404? - */ - out[0].next = NULL; - out[0].buf = ngx_calloc_buf(r->pool); - if (out[0].buf == NULL) - return NGX_ERROR; - out[0].buf->memory = 1; - out[0].buf->pos = (u_char*) t08_foot1; - out[0].buf->last = (u_char*) t08_foot1 + sizeof(t08_foot1) - 1; - out[0].buf->last_in_chain = 1; - out[0].buf->last_buf = 1; - /* Directly send out the builtin footer */ - return ngx_http_output_filter(r, &out[0]); - } - - return (r != r->main) ? rc : ngx_http_send_special(r, NGX_HTTP_LAST); -} - - -static int ngx_libc_cdecl -ngx_http_fancyindex_cmp_entries_name_desc(const void *one, const void *two) -{ - ngx_http_fancyindex_entry_t *first = (ngx_http_fancyindex_entry_t *) one; - ngx_http_fancyindex_entry_t *second = (ngx_http_fancyindex_entry_t *) two; - - return (int) ngx_strcmp(second->name.data, first->name.data); -} - - -static int ngx_libc_cdecl -ngx_http_fancyindex_cmp_entries_size_desc(const void *one, const void *two) -{ - ngx_http_fancyindex_entry_t *first = (ngx_http_fancyindex_entry_t *) one; - ngx_http_fancyindex_entry_t *second = (ngx_http_fancyindex_entry_t *) two; - - return (first->size < second->size) - (first->size > second->size); -} - - -static int ngx_libc_cdecl -ngx_http_fancyindex_cmp_entries_mtime_desc(const void *one, const void *two) -{ - ngx_http_fancyindex_entry_t *first = (ngx_http_fancyindex_entry_t *) one; - ngx_http_fancyindex_entry_t *second = (ngx_http_fancyindex_entry_t *) two; - - return (int) (second->mtime - first->mtime); -} - - -static int ngx_libc_cdecl -ngx_http_fancyindex_cmp_entries_name_asc(const void *one, const void *two) -{ - ngx_http_fancyindex_entry_t *first = (ngx_http_fancyindex_entry_t *) one; - ngx_http_fancyindex_entry_t *second = (ngx_http_fancyindex_entry_t *) two; - - return (int) ngx_strcmp(first->name.data, second->name.data); -} - - -static int ngx_libc_cdecl -ngx_http_fancyindex_cmp_entries_size_asc(const void *one, const void *two) -{ - ngx_http_fancyindex_entry_t *first = (ngx_http_fancyindex_entry_t *) one; - ngx_http_fancyindex_entry_t *second = (ngx_http_fancyindex_entry_t *) two; - - return (first->size > second->size) - (first->size < second->size); -} - - -static int ngx_libc_cdecl -ngx_http_fancyindex_cmp_entries_mtime_asc(const void *one, const void *two) -{ - ngx_http_fancyindex_entry_t *first = (ngx_http_fancyindex_entry_t *) one; - ngx_http_fancyindex_entry_t *second = (ngx_http_fancyindex_entry_t *) two; - - return (int) (first->mtime - second->mtime); -} - - -static ngx_int_t -ngx_http_fancyindex_error(ngx_http_request_t *r, ngx_dir_t *dir, ngx_str_t *name) -{ - if (ngx_close_dir(dir) == NGX_ERROR) { - ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno, - ngx_close_dir_n " \"%V\" failed", name); - } - - return NGX_HTTP_INTERNAL_SERVER_ERROR; -} - - -static void * -ngx_http_fancyindex_create_loc_conf(ngx_conf_t *cf) -{ - ngx_http_fancyindex_loc_conf_t *conf; - - conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_fancyindex_loc_conf_t)); - if (conf == NULL) { - return NGX_CONF_ERROR; - } - - /* - * Set by ngx_pcalloc: - * conf->header.*.len = 0 - * conf->header.*.data = NULL - * conf->footer.*.len = 0 - * conf->footer.*.data = NULL - * conf->css_href.len = 0 - * conf->css_href.data = NULL - * conf->time_format.len = 0 - * conf->time_format.data = NULL - */ - conf->enable = NGX_CONF_UNSET; - conf->default_sort = NGX_CONF_UNSET_UINT; - conf->dirs_first = NGX_CONF_UNSET; - conf->localtime = NGX_CONF_UNSET; - conf->name_length = NGX_CONF_UNSET_UINT; - conf->exact_size = NGX_CONF_UNSET; - conf->ignore = NGX_CONF_UNSET_PTR; - conf->hide_symlinks = NGX_CONF_UNSET; - conf->show_path = NGX_CONF_UNSET; - conf->hide_parent = NGX_CONF_UNSET; - conf->show_dot_files = NGX_CONF_UNSET; - - return conf; -} - - -static char * -ngx_http_fancyindex_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) -{ - ngx_http_fancyindex_loc_conf_t *prev = parent; - ngx_http_fancyindex_loc_conf_t *conf = child; - - (void) cf; /* unused */ - - ngx_conf_merge_value(conf->enable, prev->enable, 0); - ngx_conf_merge_uint_value(conf->default_sort, prev->default_sort, NGX_HTTP_FANCYINDEX_SORT_CRITERION_NAME); - ngx_conf_merge_value(conf->dirs_first, prev->dirs_first, 1); - ngx_conf_merge_value(conf->localtime, prev->localtime, 0); - ngx_conf_merge_value(conf->exact_size, prev->exact_size, 1); - ngx_conf_merge_value(conf->show_path, prev->show_path, 1); - ngx_conf_merge_value(conf->show_dot_files, prev->show_dot_files, 0); - ngx_conf_merge_uint_value(conf->name_length, prev->name_length, 50); - - ngx_conf_merge_str_value(conf->header.path, prev->header.path, ""); - ngx_conf_merge_str_value(conf->header.path, prev->header.local, ""); - ngx_conf_merge_str_value(conf->footer.path, prev->footer.path, ""); - ngx_conf_merge_str_value(conf->footer.path, prev->footer.local, ""); - - ngx_conf_merge_str_value(conf->css_href, prev->css_href, ""); - ngx_conf_merge_str_value(conf->time_format, prev->time_format, "%Y-%b-%d %H:%M"); - - ngx_conf_merge_ptr_value(conf->ignore, prev->ignore, NULL); - ngx_conf_merge_value(conf->hide_symlinks, prev->hide_symlinks, 0); - ngx_conf_merge_value(conf->hide_parent, prev->hide_parent, 0); - - /* Just make sure we haven't disabled the show_path directive without providing a custom header */ - if (conf->show_path == 0 && conf->header.path.len == 0) - { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "FancyIndex : cannot set show_path to off without providing a custom header !"); - return NGX_CONF_ERROR; - } - - return NGX_CONF_OK; -} - - -static char* -ngx_http_fancyindex_ignore(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) -{ - ngx_http_fancyindex_loc_conf_t *alcf = conf; - ngx_str_t *value; - - (void) cmd; /* unused */ - -#if (NGX_PCRE) - ngx_uint_t i; - ngx_regex_elt_t *re; - ngx_regex_compile_t rc; - u_char errstr[NGX_MAX_CONF_ERRSTR]; - - if (alcf->ignore == NGX_CONF_UNSET_PTR) { - alcf->ignore = ngx_array_create(cf->pool, 2, sizeof(ngx_regex_elt_t)); - if (alcf->ignore == NULL) { - return NGX_CONF_ERROR; - } - } - - value = cf->args->elts; - - ngx_memzero(&rc, sizeof(ngx_regex_compile_t)); - - rc.err.data = errstr; - rc.err.len = NGX_MAX_CONF_ERRSTR; - rc.pool = cf->pool; - - for (i = 1; i < cf->args->nelts; i++) { - re = ngx_array_push(alcf->ignore); - if (re == NULL) { - return NGX_CONF_ERROR; - } - - rc.pattern = value[i]; - rc.options = NGX_REGEX_CASELESS; - - if (ngx_regex_compile(&rc) != NGX_OK) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%V", &rc.err); - return NGX_CONF_ERROR; - } - - re->name = value[i].data; - re->regex = rc.regex; - } - - return NGX_CONF_OK; -#else /* !NGX_PCRE */ - ngx_uint_t i; - ngx_str_t *str; - - if (alcf->ignore == NGX_CONF_UNSET_PTR) { - alcf->ignore = ngx_array_create(cf->pool, 2, sizeof(ngx_str_t)); - if (alcf->ignore == NULL) { - return NGX_CONF_ERROR; - } - } - - value = cf->args->elts; - - for (i = 1; i < cf->args->nelts; i++) { - str = ngx_array_push(alcf->ignore); - if (str == NULL) { - return NGX_CONF_ERROR; - } - - str->data = value[i].data; - str->len = value[i].len; - } - - return NGX_CONF_OK; -#endif /* NGX_PCRE */ - -} - - -static ngx_int_t -ngx_http_fancyindex_init(ngx_conf_t *cf) -{ - ngx_http_handler_pt *h; - ngx_http_core_main_conf_t *cmcf; - - cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); - - h = ngx_array_push(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers); - if (h == NULL) { - return NGX_ERROR; - } - - *h = ngx_http_fancyindex_handler; - - return NGX_OK; -} - -/* vim:et:sw=4:ts=4: - */ diff --git a/debian/modules/http-fancyindex/t/00-build-artifacts.test b/debian/modules/http-fancyindex/t/00-build-artifacts.test deleted file mode 100644 index b9bc1ac..0000000 --- a/debian/modules/http-fancyindex/t/00-build-artifacts.test +++ /dev/null @@ -1,22 +0,0 @@ -#! /bin/bash -cat <<--- -This test checks that the built Nginx either has the dynamic fancyindex -module available, or that it's not there (for static builds). --- - -readonly nginx_path="${PREFIX}/sbin/nginx" -readonly so_path="${PREFIX}/modules/ngx_http_fancyindex_module.so" - -if [[ ! -x ${nginx_path} ]] ; then - fail "executable binary not found at '%s'\n" "${nginx_path}" -fi - -if ${DYNAMIC} ; then - if [[ ! -r ${so_path} ]] ; then - fail "module not found at '%s'\n" "${so_path}" - fi -else - if [[ -r ${so_path} ]] ; then - fail "module should not exist at '%s'\n" "${so_path}" - fi -fi diff --git a/debian/modules/http-fancyindex/t/01-smoke-hasindex.test b/debian/modules/http-fancyindex/t/01-smoke-hasindex.test deleted file mode 100644 index 19706a4..0000000 --- a/debian/modules/http-fancyindex/t/01-smoke-hasindex.test +++ /dev/null @@ -1,7 +0,0 @@ -#! /bin/bash -cat <<--- -This test fetches the root directory served by Nginx, which has no index file, -and checks that the output contains something that resembles a directory index. --- -nginx_start -grep 'Index of' <( fetch ) diff --git a/debian/modules/http-fancyindex/t/02-smoke-indexisfancy.test b/debian/modules/http-fancyindex/t/02-smoke-indexisfancy.test deleted file mode 100644 index 10cc403..0000000 --- a/debian/modules/http-fancyindex/t/02-smoke-indexisfancy.test +++ /dev/null @@ -1,11 +0,0 @@ -#! /bin/bash -cat <<--- -This test fetches the root directory served by Nginx, which has no index file, -and checks that the output contains something that resembles the output from -the fancyindex module. --- -nginx_start -content=$(fetch --with-headers) -grep 'Index of /' <<< "${content}" # It is an index -grep '\' <<< "${content}" # It contains a table -grep '^ Content-Type:[[:space:]]*text/html' <<< "${content}" diff --git a/debian/modules/http-fancyindex/t/03-exact_size_off.test b/debian/modules/http-fancyindex/t/03-exact_size_off.test deleted file mode 100644 index cdc61ec..0000000 --- a/debian/modules/http-fancyindex/t/03-exact_size_off.test +++ /dev/null @@ -1,8 +0,0 @@ -#! /bin/bash -cat <<--- -We test if the output from using "fancyindex_exact_size off" looks sane --- -nginx_start 'fancyindex_exact_size off;' -content=$(fetch) -grep -e '[1-9]\.[0-9] KiB' <<< "${content}" -grep -E '[0-9]+ B' <<< "${content}" diff --git a/debian/modules/http-fancyindex/t/04-hasindex-html.test b/debian/modules/http-fancyindex/t/04-hasindex-html.test deleted file mode 100644 index 69ac222..0000000 --- a/debian/modules/http-fancyindex/t/04-hasindex-html.test +++ /dev/null @@ -1,24 +0,0 @@ -#! /bin/bash -cat <<--- -This test fetches the root directory served by Nginx, which has no index -file, and checks the output contains a few HTML elements know to exist in -a directory index. --- -use pup -nginx_start - -content=$( fetch ) - -# Check page title -[[ $(pup -p title text{} <<< "${content}") = 'Index of /' ]] - -# Check table headers -[[ $(pup -n body table thead th a:first-child <<< "${content}") -eq 3 ]] -{ - read -r name_label - read -r size_label - read -r date_label -} < <( pup -p body table thead th a:first-child text{} <<< "${content}" ) -[[ ${name_label} = File\ Name ]] -[[ ${size_label} = File\ Size ]] -[[ ${date_label} = Date ]] diff --git a/debian/modules/http-fancyindex/t/05-sort-by-size.test b/debian/modules/http-fancyindex/t/05-sort-by-size.test deleted file mode 100644 index 23fade9..0000000 --- a/debian/modules/http-fancyindex/t/05-sort-by-size.test +++ /dev/null @@ -1,36 +0,0 @@ -#! /bin/bash -cat <<--- -This test validates that the sorting by file size works. --- -use pup -nginx_start - -# Ascending sort. -previous='' -while read -r size ; do - if [[ ${size} = - ]] ; then - continue - fi - if [[ -z ${previous} ]] ; then - previous=${size} - continue - fi - [[ ${previous} -le ${size} ]] || fail \ - 'Size %d should be smaller than %d\n' "${previous}" "${size}" -done < <( fetch '/?C=S&O=A' \ - | pup -p body table tbody 'td:nth-child(2)' text{} ) - -# Descending sort. -previous='' -while read -r size ; do - if [[ ${size} = - ]] ; then - continue - fi - if [[ -z ${previous} ]] ; then - previous=${size} - continue - fi - [[ ${previous} -ge ${size} ]] || fail \ - 'Size %d should be greater than %d\n' "${previous}" "${size}" -done < <( fetch '/?C=S&O=D' \ - | pup -p body table tbody 'td:nth-child(2)' text{} ) diff --git a/debian/modules/http-fancyindex/t/06-hide_parent.test b/debian/modules/http-fancyindex/t/06-hide_parent.test deleted file mode 100644 index 494c958..0000000 --- a/debian/modules/http-fancyindex/t/06-hide_parent.test +++ /dev/null @@ -1,23 +0,0 @@ -#! /bin/bash -cat <<--- -This test check the output using "fancyindex_hide_parent_dir on" --- -use pup -nginx_start 'fancyindex_hide_parent_dir on;' - -content=$( fetch /child-directory/ ) - -# Check page title -[[ $(pup -p title text{} <<< "${content}") = "Index of /child-directory/" ]] - -# Check table headers -[[ $(pup -n body table tbody tr:first-child td <<< "${content}") -eq 3 ]] -{ - read -r name_label - read -r size_label - read -r date_label -} < <( pup -p body table tbody tr:first-child td text{} <<< "${content}" ) -[[ ${name_label} != Parent\ Directory/ ]] -[[ ${name_label} = empty-file.txt ]] -[[ ${size_label} != - ]] -[[ ${date_label} != - ]] diff --git a/debian/modules/http-fancyindex/t/07-directory-first.test b/debian/modules/http-fancyindex/t/07-directory-first.test deleted file mode 100644 index 82c37cc..0000000 --- a/debian/modules/http-fancyindex/t/07-directory-first.test +++ /dev/null @@ -1,50 +0,0 @@ -#! /bin/bash -cat <<--- -This test check the output using "fancyindex_directories_first on" --- -use pup - -for d in "008d" "000d" "004d" ; do - mkdir -p "${TESTDIR}/dir_first/${d}" -done -for f in "005f" "001f" "003f"; do - touch "${TESTDIR}/dir_first/${f}" -done -for d in "006d" "002d" ; do - mkdir -p "${TESTDIR}/dir_first/${d}" -done - -nginx_start 'fancyindex_directories_first on;' -previous='' -cur_type='' -while read -r name ; do - case "$name" in - *Parent*) - ;; - *d*) - echo "dir $name" - [[ "$cur_type" = f ]] && fail 'Directories should come before Files' - cur_type=d - if [[ -z ${previous} ]] ; then - previous=${name} - else - [[ ${previous} < ${name} ]] || fail \ - 'Name %s should come before %s\n' "${previous}" "${name}" - fi - ;; - *f*) - echo "file $name" - [[ -z "$cur_type" ]] && fail 'Directories should come before Files' - if [[ "$cur_type" = d ]] ; then - cur_type=f - previous=${name} - else - [[ ${previous} < ${name} ]] || fail \ - 'Name %s should come before %s\n' "${previous}" "${name}" - fi - ;; - esac -done < <( fetch '/dir_first/' \ - | pup -p body table tbody 'td:nth-child(1)' text{} ) - -nginx_is_running || fail "Nginx died" diff --git a/debian/modules/http-fancyindex/t/07-show_dotfiles.test b/debian/modules/http-fancyindex/t/07-show_dotfiles.test deleted file mode 100644 index 6b56410..0000000 --- a/debian/modules/http-fancyindex/t/07-show_dotfiles.test +++ /dev/null @@ -1,21 +0,0 @@ -#! /bin/bash -cat <<--- -Test the option to show dotfiles. --- -# Turn it on. -nginx_start 'fancyindex_show_dotfiles on;' -on_content=$(fetch /show_dotfiles/) -nginx_stop -if [ $(grep '.okay' <<< "${on_content}") -ne 0 ] ; then - exit 1 -fi - -# Turn it off. -nginx_start -off_content=$(fetch /show_dotfiles/) -nginx_stop -if [ $(grep '.okay' <<< "${on_content}") -eq 0] ; then - exit 1 -fi - -exit 0 diff --git a/debian/modules/http-fancyindex/t/08-local-footer.test b/debian/modules/http-fancyindex/t/08-local-footer.test deleted file mode 100644 index 6d6318b..0000000 --- a/debian/modules/http-fancyindex/t/08-local-footer.test +++ /dev/null @@ -1,17 +0,0 @@ -#! /bin/bash -cat <<--- -This test checks that a local footer can be included with -"fancyindex_header ... local" --- -use pup - -cat > "${TESTDIR}/footer" <yes -EOF - -nginx_start "fancyindex_footer \"${TESTDIR}/footer\" local;" - -T=$(fetch / | pup -p body 'div#customfooter' text{}) -[[ $T == yes ]] || fail 'Custom header missing' - -nginx_is_running || fail 'Nginx died' diff --git a/debian/modules/http-fancyindex/t/09-local-header.test b/debian/modules/http-fancyindex/t/09-local-header.test deleted file mode 100644 index 455b966..0000000 --- a/debian/modules/http-fancyindex/t/09-local-header.test +++ /dev/null @@ -1,17 +0,0 @@ -#! /bin/bash -cat <<--- -This test checks that a local header can be included with -"fancyindex_header ... local" --- -use pup - -cat > "${TESTDIR}/header" <yes -EOF - -nginx_start "fancyindex_header \"${TESTDIR}/header\" local;" - -T=$(fetch / | pup -p body 'div#customheader' text{}) -[[ $T == yes ]] || fail 'Custom header missing' - -nginx_is_running || fail 'Nginx died' diff --git a/debian/modules/http-fancyindex/t/10-local-headerfooter.test b/debian/modules/http-fancyindex/t/10-local-headerfooter.test deleted file mode 100644 index 6adfb45..0000000 --- a/debian/modules/http-fancyindex/t/10-local-headerfooter.test +++ /dev/null @@ -1,26 +0,0 @@ -#! /bin/bash -cat <<--- -This test checks that both a local header and footer can be included with -"fancyindex_{header,footer} ... local" --- -use pup - -cat > "${TESTDIR}/header" <yes -EOF -cat > "${TESTDIR}/footer" <yes -EOF - -nginx_start "fancyindex_header \"${TESTDIR}/header\" local; - fancyindex_footer \"${TESTDIR}/footer\" local;" - -P=$(fetch /) - -H=$(pup -p body 'div#customheader' text{} <<< "$P") -[[ $H == yes ]] || fail 'Custom header missing' - -F=$(pup -p body 'div#customfooter' text{} <<< "$P") -[[ $F == yes ]] || fail 'Custom footer missing' - -nginx_is_running || fail 'Nginx died' diff --git a/debian/modules/http-fancyindex/t/11-local-footer-nested.test b/debian/modules/http-fancyindex/t/11-local-footer-nested.test deleted file mode 100644 index 0530853..0000000 --- a/debian/modules/http-fancyindex/t/11-local-footer-nested.test +++ /dev/null @@ -1,31 +0,0 @@ -#! /bin/bash -cat <<--- -This test checks that local footers are correctly included in presence of -directives in nested locations: - - fancyindex_footer local; - location /sub { - fancyindex_footer local; - } - --- -use pup - -echo '
yes
' > "${TESTDIR}/top-footer" -echo '
yes
' > "${TESTDIR}/sub-footer" - -nginx_start "fancyindex_footer \"${TESTDIR}/top-footer\" local; - location /child-directory { - fancyindex_footer \"${TESTDIR}/sub-footer\" local; - }" - -T=$(fetch /) -echo "$T" > "$TESTDIR/top.html" -[[ $(pup -p body 'div#topfooter' text{} <<< "$T") = yes ]] || fail 'Custom header missing at /' -[[ -z $(pup -p body 'div#subfooter' text{} <<< "$T") ]] || fail 'Wrong header at /' - -T=$(fetch /child-directory/) -[[ $(pup -p body 'div#subfooter' text{} <<< "$T") = yes ]] || fail 'Custom header missing at /sub/' -[[ -z $(pup -p body 'div#topfooter' text{} <<< "$T") ]] || fail 'Wrong header at /sub/' - -nginx_is_running || fail 'Nginx died' diff --git a/debian/modules/http-fancyindex/t/12-local-footer-nested.test b/debian/modules/http-fancyindex/t/12-local-footer-nested.test deleted file mode 100644 index 7c0aef7..0000000 --- a/debian/modules/http-fancyindex/t/12-local-footer-nested.test +++ /dev/null @@ -1,11 +0,0 @@ -#! /bin/bash -cat <<--- -This test checks that the configuration file is properly parsed if there -is only one parameter passed to the fancyndex_header and fancyindex_footer -configuration directives. --- - -nginx_start 'fancyindex_header "/header"; - fancyindex_footer "/footer";' - -nginx_is_running || fail 'Nginx died' diff --git a/debian/modules/http-fancyindex/t/bug61-empty-file-segfault.test b/debian/modules/http-fancyindex/t/bug61-empty-file-segfault.test deleted file mode 100644 index d9c5a40..0000000 --- a/debian/modules/http-fancyindex/t/bug61-empty-file-segfault.test +++ /dev/null @@ -1,16 +0,0 @@ -#! /bin/bash -cat <<--- -Bug #61: Listing a directory with an empty file crashes Nginx -https://github.com/aperezdc/ngx-fancyindex/issues/61 --- - -# Prepare an empty directory with an empty file -mkdir -p "${TESTDIR}/bug61" -touch "${TESTDIR}/bug61/bug61.txt" - -nginx_start 'fancyindex_exact_size off;' -content=$(fetch /bug61/) -test -n "${content}" || fail "Empty response" -echo "Response:" -echo "${content}" -nginx_is_running || fail "Nginx died" diff --git a/debian/modules/http-fancyindex/t/bug95-square-brackets.test b/debian/modules/http-fancyindex/t/bug95-square-brackets.test deleted file mode 100644 index 16e1ddc..0000000 --- a/debian/modules/http-fancyindex/t/bug95-square-brackets.test +++ /dev/null @@ -1,19 +0,0 @@ -#! /bin/bash -cat <<--- -Bug #95: FancyIndex does not encode square brackets -https://github.com/aperezdc/ngx-fancyindex/issues/95 --- -use pup - -# Prepare a directory with a file that contains square brackets in the name. -mkdir -p "${TESTDIR}/bug95" -touch "${TESTDIR}"/bug95/'bug[95].txt' - -nginx_start -content=$(fetch /bug95/) -test -n "${content}" || fail 'Empty response' - -expected_href='bug%5B95%5D.txt' -obtained_href=$(pup -p body tbody 'tr:nth-child(2)' a 'attr{href}' <<< "${content}") -test "${expected_href}" = "${obtained_href}" || \ - fail 'Expected: %s - Obtained: %s' "${expected_href}" "${obtained_href}" diff --git a/debian/modules/http-fancyindex/t/build-and-run b/debian/modules/http-fancyindex/t/build-and-run deleted file mode 100755 index 68584b7..0000000 --- a/debian/modules/http-fancyindex/t/build-and-run +++ /dev/null @@ -1,25 +0,0 @@ -#! /bin/bash -set -e - -if [[ $# -lt 1 || $# -gt 2 ]] ; then - echo "Usage: $0 [1]" 1>&2 - exit 1 -fi - -readonly NGINX=$1 - -if [[ $2 -eq 1 ]] ; then - readonly DYNAMIC=$2 -fi - -cd "$(dirname "$0")/.." -wget -O - http://nginx.org/download/nginx-${NGINX}.tar.gz | tar -xzf - -rm -rf prefix/ -cd nginx-${NGINX} -./configure \ - --add-${DYNAMIC:+dynamic-}module=.. \ - --with-http_addition_module \ - --prefix="$(pwd)/../prefix" -make install -cd .. -exec ./t/run prefix ${DYNAMIC} diff --git a/debian/modules/http-fancyindex/t/child-directory/empty-file.txt b/debian/modules/http-fancyindex/t/child-directory/empty-file.txt deleted file mode 100644 index e69de29..0000000 diff --git a/debian/modules/http-fancyindex/t/get-pup b/debian/modules/http-fancyindex/t/get-pup deleted file mode 100755 index 613dac7..0000000 --- a/debian/modules/http-fancyindex/t/get-pup +++ /dev/null @@ -1,81 +0,0 @@ -#! /bin/bash -set -e - -declare -r VERSION='0.4.0' -declare -r SHASUMS='\ -75c27caa0008a9cc639beb7506077ad9f32facbffcc4e815e999eaf9588a527e pup_v0.4.0_darwin_386.zip -c539a697efee2f8e56614a54cb3b215338e00de1f6a7c2fa93144ab6e1db8ebe pup_v0.4.0_darwin_amd64.zip -259eee82c7d7d766f1b8f93a382be21dcfefebc855a9ce8124fd78717f9df439 pup_v0.4.0_dragonfly_amd64.zip -ba0fe5e87a24cab818e5d2efdd7540714ddfb1b7246600135915c666fdf1a601 pup_v0.4.0_freebsd_386.zip -1838ef84ec1f961e8009d19a4d1e6a23b926ee315da3d60c08878f3d69af5692 pup_v0.4.0_freebsd_amd64.zip -6886a9c60a912a810d012610bc3f784f0417999ff7d7df833a0695b9af60395b pup_v0.4.0_freebsd_arm.zip -e486b32ca07552cd3aa713cbf2f9d1b6e210ddb51d34b3090c7643f465828057 pup_v0.4.0_linux_386.zip -ec3d29e9fb375b87ac492c8b546ad6be84b0c0b49dab7ff4c6b582eac71ba01c pup_v0.4.0_linux_amd64.zip -c09b669fa8240f4f869dee7d34ee3c7ea620a0280cee1ea7d559593bcdd062c9 pup_v0.4.0_linux_arm64.zip -ebf70b3c76c02e0202c94af7ef06dcb3ecc866d1b9b84453d43fe01fa5dd5870 pup_v0.4.0_linux_arm.zip -a98a4d1f3c3a103e8ebe1a7aba9cb9d3cb045003208ca6f5f3d54889a225f267 pup_v0.4.0_linux_mips64le.zip -8e471cf6cfa118b2497bb3f42a7a48c52d0096107f748f37216855c8ab94f8e5 pup_v0.4.0_linux_mips64.zip -cfda9375eba65f710e052b1b59893c228c3fc92b0510756bb3f02c25938eee30 pup_v0.4.0_linux_ppc64le.zip -91a1e07ffb2c373d6053252e4de732f5db78c8eace49c6e1a0ef52402ecdf56c pup_v0.4.0_linux_ppc64.zip -fdc9b28a3daac5ad096023e1647292a7eccea6d9b1686f871307dae9f3bd064f pup_v0.4.0_nacl_386.zip -c8d3c9b56783bd5a55446f4580e1835606b2b945da2d1417ed509c5927a5f8bc pup_v0.4.0_nacl_amd64p32.zip -48c068c4353672528c8c3447a536208b0719f1e6d0f8fab8416b38b63ad0c1d9 pup_v0.4.0_nacl_arm.zip -7a27497b2f0be95c51bb2cbc25da12efba682c4f766bc5abc5742e9fc8d1eeb0 pup_v0.4.0_netbsd_386.zip -71a1808eb1b6442aa45d1de9e1c4fca543b2754c1aff5ba3d62b3456f9519691 pup_v0.4.0_netbsd_amd64.zip -928e6691b11c68ae3f28826848a13dc5c1c9673848fe7cf7f80dd76c9fb6e8a6 pup_v0.4.0_netbsd_arm.zip -5aca20a9b3264d2fde5a8d32f213c434edf9570ee6fae18953b8fff09d2976e2 pup_v0.4.0_openbsd_386.zip -e965c6f04b897240d84c60e2c18226deb231a657c5583680f58a61051ff5a100 pup_v0.4.0_openbsd_amd64.zip -30bc88a1e06606f4f3449af9fbf586f97c2e958677460a72bb1a168f67c4911c pup_v0.4.0_openbsd_arm.zip -9d50decf4572292f187cfec84660648d648336bc6109e1f032b1699ba1d28549 pup_v0.4.0_plan9_386.zip -1b2a6bd2388ddd691ca429497d88b2b047ec8dfb7bce9436925cb2f30632bf8e pup_v0.4.0_plan9_amd64.zip -0835de9c10a9e2b3b958b82d148da49eaafc695fe4a018cbaf7bb861b455583f pup_v0.4.0_solaris_amd64.zip -01acae220b69fb1ba8477d0e7f4d7669ef5de147966dc819cf75a845af74c5f3 pup_v0.4.0_windows_386.zip -6755cbd43e94eaf173689e93e914c7056a2249c2977e5b90024fb397f9b45ba4 pup_v0.4.0_windows_amd64.zip -' - -declare -r BASEURL="https://github.com/ericchiang/pup/releases/download/v${VERSION}" -declare -r TDIR=$(dirname "$0") -ARCH='' -OS='' - -case $(uname -m) in - x86_64 | amd64 ) ARCH=amd64 ;; - i[3456]86 ) ARCH=386 ;; -esac - -OS=$(uname -s | tr 'A-Z' 'a-z') -case ${OS} in - linux | freebsd | openbsd | netbsd | darwin ) ;; - * ) OS='' -esac - -if [[ -z ${ARCH} || -z ${OS} ]] ; then - echo "pup ${VERSION} is not available for $(uname -s) on $(uname -m)" 1>&2 - exit 1 -fi - -declare -r ZIPFILE="pup_v${VERSION}_${OS}_${ARCH}.zip" -EXPECT_SHA='' - -while read sum fname ; do - if [[ ${fname} = ${ZIPFILE} ]] ; then - EXPECT_SHA=${sum} - break - fi -done <<< "${SHASUMS}" - -wget -cO "${TDIR}/${ZIPFILE}" "${BASEURL}/${ZIPFILE}" - -read -r GOT_SHA _ < <( sha256sum "${TDIR}/${ZIPFILE}" ) -if [[ ${EXPECT_SHA} = ${GOT_SHA} ]] ; then - echo "Checksum for ${ZIPFILE} verified :-)" -else - rm -f "${TDIR}/${ZIPFILE}" "${TDIR}/pup" - echo "Checksum for ${ZIPFILE} does not match :-(" - echo " Expected: ${EXPECT_SHA}" - echo " Got: ${GOT_SHA}" - exit 2 -fi 1>&2 - -rm -f "${TDIR}/pup" -unzip "${TDIR}/${ZIPFILE}" pup -d "${TDIR}" diff --git a/debian/modules/http-fancyindex/t/has-index.test b/debian/modules/http-fancyindex/t/has-index.test deleted file mode 100644 index cf34207..0000000 --- a/debian/modules/http-fancyindex/t/has-index.test +++ /dev/null @@ -1,7 +0,0 @@ -#! /bin/bash -cat <<--- -This test ensures that the "index.html" is returned instead of a directory -listing when fetching a directory which contains an index file. --- -nginx_start -diff -u "${TESTDIR}/has-index/index.html" <( fetch /has-index/ ) 1>&2 diff --git a/debian/modules/http-fancyindex/t/has-index/index.html b/debian/modules/http-fancyindex/t/has-index/index.html deleted file mode 100644 index 419ae86..0000000 --- a/debian/modules/http-fancyindex/t/has-index/index.html +++ /dev/null @@ -1,10 +0,0 @@ - - - - - Index file test - - - This is index.html. - - diff --git a/debian/modules/http-fancyindex/t/nginx.conf b/debian/modules/http-fancyindex/t/nginx.conf deleted file mode 100644 index 2b99a3d..0000000 --- a/debian/modules/http-fancyindex/t/nginx.conf +++ /dev/null @@ -1,25 +0,0 @@ -worker_processes 1; - - -events { - worker_connections 1024; -} - -http { - include mime.types; - default_type application/octet-stream; - sendfile on; - keepalive_timeout 65; - server { - listen 80; - server_name localhost; - location / { - root html; - index index.html index.htm; - } - error_page 500 502 503 504 /50x.html; - location = /50x.html { - root html; - } - } -} diff --git a/debian/modules/http-fancyindex/t/preamble b/debian/modules/http-fancyindex/t/preamble deleted file mode 100644 index 26f2819..0000000 --- a/debian/modules/http-fancyindex/t/preamble +++ /dev/null @@ -1,111 +0,0 @@ -#! /bin/bash -# -# preamble -# Copyright (C) 2016 Adrian Perez -# -# Distributed under terms of the MIT license. -# - -function nginx_conf_generate () { - if ${DYNAMIC} ; then - echo 'load_module modules/ngx_http_fancyindex_module.so;' - fi - cat <<-EOF - worker_processes 1; - events { worker_connections 1024; } - http { - include mime.types; - default_type application/octet-stream; - sendfile on; - keepalive_timeout 65; - server { - server_name localhost; - listen 127.0.0.1:${NGINX_PORT}; - root ${TESTDIR}; - error_page 500 502 503 504 /50x.html; - location = /50x.html { root html; } - location / { - index index.html; - fancyindex on; - $* - } - } - } - EOF -} - -readonly NGINX_CONF="${PREFIX}/conf/nginx.conf" -readonly NGINX_PID="${PREFIX}/logs/nginx.pid" - -NGINX_PORT=$(ss -4Htnl | awk '{ sub("[^:]+:", "", $4) ; seen[$4]=1 } -END { p=1025 ; while (seen[p]) p++; print p}') -readonly NGINX_PORT - -rm -f "${NGINX_CONF}" "${NGINX_PID}" -mkdir -p "${PREFIX}/logs" - -function pup () { - if [[ -x ${TESTDIR}/pup ]] ; then - "${TESTDIR}/pup" "$@" - else - skip 'Test uses "pup", which is not available' - fi -} - -function use () { - case $1 in - pup ) [[ -x ${TESTDIR}/pup ]] \ - || skip 'Test uses "pup", which is unavailable\n' ;; - * ) warn "Invalid 'use' flag: '%s'\n'" "$1" ;; - esac -} - -function nginx () { - env - PATH="${PATH}" "${PREFIX}/sbin/nginx" "$@" -} - -function nginx_conf () { - nginx_conf_generate "$@" > "${NGINX_CONF}" -} - -function nginx_is_running () { - [[ -r ${NGINX_PID} ]] && kill -0 $(< "${NGINX_PID}") -} - -function nginx_stop () { - if nginx_is_running ; then nginx -s stop ; fi - rm -f "${NGINX_PID}" -} -trap nginx_stop EXIT - -function nginx_start () { - if [[ $# -gt 0 || ! -r ${NGINX_CONF} ]] ; then nginx_conf "$@" ; fi - nginx_stop # Ensure that it is not running. - nginx -} - -function fetch () { - local -a opts=( -q ) - if [[ $1 = --with-headers ]] ; then - opts+=( -S ) - shift - fi - wget "${opts[@]}" -O- "http://localhost:${NGINX_PORT}${1:-/}" 2>&1 -} - -function skip () { - printf '(--) ' - printf "$@" - exit 111 -} 1>&2 - -function fail () { - printf '(FF) ' - printf "$@" - exit 1 -} 1>&2 - -function warn () { - printf '(WW) ' - printf "$@" -} 1>&2 diff --git a/debian/modules/http-fancyindex/t/run b/debian/modules/http-fancyindex/t/run deleted file mode 100755 index 9988fa2..0000000 --- a/debian/modules/http-fancyindex/t/run +++ /dev/null @@ -1,86 +0,0 @@ -#!/bin/bash -set -e - -if [[ $# -lt 1 || $# -gt 2 ]] ; then - echo "Usage: $0 [1]" 1>&2 - exit 1 -fi - -# Obtain the absolute path to the tests directory -pushd "$(dirname "$0")" &> /dev/null -readonly T=$(pwd) -popd &> /dev/null -export T - -# Same for the nginx prefix directory -pushd "$1" &> /dev/null -readonly prefix=$(pwd) -popd &> /dev/null - -dynamic=false -if [[ $# -gt 1 && $2 -eq 1 ]] ; then - dynamic=true -fi -readonly dynamic - -declare -a t_pass=( ) -declare -a t_fail=( ) -declare -a t_skip=( ) - -for t in `ls "$T"/*.test | sort -R` ; do - name="t/${t##*/}" - name=${name%.test} - printf "${name} ... " - errfile="${name}.err" - outfile="${name}.out" - shfile="${name}.sh" - cat > "${shfile}" <<-EOF - readonly DYNAMIC=${dynamic} - readonly TESTDIR='$T' - readonly PREFIX='${prefix}' - $(< "$T/preamble") - $(< "$t") - EOF - if bash -e "${shfile}" > "${outfile}" 2> "${errfile}" ; then - t_pass+=( "${name}" ) - printf 'passed\n' - elif [[ $? -eq 111 ]] ; then - t_skip+=( "${name}" ) - printf 'skipped\n' - else - t_fail+=( "${name}" ) - printf 'failed\n' - fi -done - -for name in "${t_fail[@]}" ; do - echo - printf '=== %s.out\n' "${name}" - cat "${name}.out" - echo - printf '=== %s.err\n' "${name}" - cat "${name}.err" - echo -done - -if [[ ${#t_skip[@]} -gt 0 ]] ; then - echo - printf 'Skipped tests:\n' - for name in "${t_skip[@]}" ; do - reason=$(grep '^(\-\-) ' "${name}.err" | head -1) - if [[ -z ${reason} ]] ; then - reason='No reason given' - else - reason=${reason:5} - fi - printf ' - %s: %s\n' "${name}" "${reason:-No reason given}" - done - echo -fi - -printf '=== passed/skipped/failed/total: %d/%d/%d/%d\n' \ - ${#t_pass[@]} ${#t_skip[@]} ${#t_fail[@]} $(( ${#t_pass[@]} + ${#t_fail[@]} )) - -if [[ ${#t_fail[@]} -gt 0 ]] ; then - exit 1 -fi diff --git a/debian/modules/http-fancyindex/t/show_dotfiles/.okay b/debian/modules/http-fancyindex/t/show_dotfiles/.okay deleted file mode 100644 index e69de29..0000000 diff --git a/debian/modules/http-fancyindex/template.awk b/debian/modules/http-fancyindex/template.awk deleted file mode 100755 index f9ec4a6..0000000 --- a/debian/modules/http-fancyindex/template.awk +++ /dev/null @@ -1,52 +0,0 @@ -#! /usr/bin/awk -f -# -# Copyright © Adrian Perez -# -# Converts an HTML template into a C header suitable for inclusion. -# Take a look at the HACKING.rst file to know how to use it :-) -# -# This code is placed in the public domain. - -BEGIN { - varname = 0; - print "/* Automagically generated, do not edit! */" - vars_count = 0; -} - -/^$/ { - if (varname) print ";"; - if ($3 == "NONE") { - varname = 0; - next; - } - varname = $3; - vars[vars_count++] = varname; - print "static const u_char " varname "[] = \"\""; - next; -} - -/^$/ { - if (!varname) next; - print "\"\\n\""; - next; -} - -{ - if (!varname) next; - # Order matters - gsub(/[\t\v\n\r\f]+/, ""); - gsub(/\\/, "\\\\"); - gsub(/"/, "\\\""); - print "\"" $0 "\"" -} - - -END { - if (varname) print ";"; - print "#define NFI_TEMPLATE_SIZE (0 \\"; - for (var in vars) { - print "\t+ nfi_sizeof_ssz(" vars[var] ") \\"; - } - print "\t)" -} - diff --git a/debian/modules/http-fancyindex/template.h b/debian/modules/http-fancyindex/template.h deleted file mode 100644 index 2d6604b..0000000 --- a/debian/modules/http-fancyindex/template.h +++ /dev/null @@ -1,94 +0,0 @@ -/* Automagically generated, do not edit! */ -static const u_char t01_head1[] = "" -"" -"" -"" -"" -"" -"" -"\n" -; -static const u_char t02_head2[] = "" -"\n" -"Index of " -; -static const u_char t03_head3[] = "" -"" -"\n" -"" -; -static const u_char t04_body1[] = "" -"" -"

Index of " -; -static const u_char t05_body2[] = "" -"

" -"\n" -; -static const u_char t06_list1[] = "" -"
last = ngx_cpymem(b->last, - sort_url_args, - ngx_sizeof_ssz("?C=N&O=A")); - } - b->last = ngx_cpymem_ssz(b->last, - "\">Parent directory/--
last, - entry[i].name.data, - entry[i].name.len); - - b->last += entry[i].name.len + entry[i].escape; - - } else { - b->last = ngx_cpymem_str(b->last, entry[i].name); - } - - if (entry[i].dir) { - *b->last++ = '/'; - if (*sort_url_args) { - b->last = ngx_cpymem(b->last, - sort_url_args, - ngx_sizeof_ssz("?C=x&O=y")); - } - } - - *b->last++ = '"'; - b->last = ngx_cpymem_ssz(b->last, " title=\""); - b->last = (u_char *) ngx_escape_html(b->last, entry[i].name.data, entry[i].name.len); - *b->last++ = '"'; - *b->last++ = '>'; - - len = entry[i].utf_len; - - if (entry[i].name.len != len) { - if (len > alcf->name_length) { - copy = alcf->name_length - 3 + 1; - } else { - copy = alcf->name_length + 1; - } - - last = b->last; - b->last = ngx_utf8_cpystrn(b->last, entry[i].name.data, - copy, entry[i].name.len); - - b->last = (u_char *) ngx_escape_html(last, entry[i].name.data, b->last - last); - last = b->last; - - } else { - if (len > alcf->name_length) { - b->last = (u_char *) ngx_escape_html(b->last, entry[i].name.data, alcf->name_length + 1); - } else { - b->last = (u_char *) ngx_escape_html(b->last, entry[i].name.data, entry[i].name.len); - } - last = b->last - 3; - } - - if (len > alcf->name_length) { - b->last = ngx_cpymem_ssz(last, "..>"); - - } else { - if (entry[i].dir && alcf->name_length - len > 0) { - *b->last++ = '/'; - len++; - } - - b->last = ngx_cpymem_ssz(b->last, ""); - } - - if (alcf->exact_size) { - if (entry[i].dir) { - *b->last++ = '-'; - } else { - b->last = ngx_sprintf(b->last, "%19O", entry[i].size); - } - - } else { - if (entry[i].dir) { - *b->last++ = '-'; - } else { - length = entry[i].size; - multiplier = exbibyte; - - for (j = 0; j < DIM(sizes) - 1 && length < multiplier; j++) - multiplier /= 1024; - - /* If we are showing the filesize in bytes, do not show a decimal */ - if (j == DIM(sizes) - 1) - b->last = ngx_sprintf(b->last, "%O %s", length, sizes[j]); - else - b->last = ngx_sprintf(b->last, "%.1f %s", - (float) length / multiplier, sizes[j]); - } - } - - ngx_gmtime(entry[i].mtime + tp->gmtoff * 60 * alcf->localtime, &tm); - b->last = ngx_cpymem_ssz(b->last, ""); - b->last = ngx_fancyindex_timefmt(b->last, &alcf->time_format, &tm); - b->last = ngx_cpymem_ssz(b->last, "
" -"" -"" -"" -"" -"" -"" -"" -"\n" -"" -; -static const u_char t_parentdir_entry[] = "" -"" -"" -"" -"" -"" -"\n" -; -static const u_char t07_list2[] = "" -"" -"
File Name  ↓ File Size  ↓ Date  ↓ 
Parent directory/--
" -; -static const u_char t08_foot1[] = "" -"" -"" -; -#define NFI_TEMPLATE_SIZE (0 \ - + nfi_sizeof_ssz(t01_head1) \ - + nfi_sizeof_ssz(t02_head2) \ - + nfi_sizeof_ssz(t03_head3) \ - + nfi_sizeof_ssz(t04_body1) \ - + nfi_sizeof_ssz(t05_body2) \ - + nfi_sizeof_ssz(t06_list1) \ - + nfi_sizeof_ssz(t_parentdir_entry) \ - + nfi_sizeof_ssz(t07_list2) \ - + nfi_sizeof_ssz(t08_foot1) \ - ) diff --git a/debian/modules/http-fancyindex/template.html b/debian/modules/http-fancyindex/template.html deleted file mode 100644 index b2a3174..0000000 --- a/debian/modules/http-fancyindex/template.html +++ /dev/null @@ -1,93 +0,0 @@ - - - - - - - - - - - Index of -<!-- var NONE --> - /path/to/somewhere -<!-- var t03_head3 --> - - - - - -

Index of - - /path/to/somewhere - -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
File Name  ↓ File Size  ↓ Date  ↓ 
--
test file 1123kBdate
test file 2321MBdate
test file 3666date
- - - diff --git a/debian/modules/http-geoip2/LICENSE b/debian/modules/http-geoip2/LICENSE deleted file mode 100644 index fdc13a7..0000000 --- a/debian/modules/http-geoip2/LICENSE +++ /dev/null @@ -1,23 +0,0 @@ -Copyright (c) 2014, Lee Valentine -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, this - list of conditions and the following disclaimer in the documentation and/or - other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/debian/modules/http-geoip2/README.md b/debian/modules/http-geoip2/README.md deleted file mode 100644 index a5aec97..0000000 --- a/debian/modules/http-geoip2/README.md +++ /dev/null @@ -1,133 +0,0 @@ -Description -=========== - -**ngx_http_geoip2_module** - creates variables with values from the maxmind geoip2 databases based on the client IP (default) or from a specific variable (supports both IPv4 and IPv6) - -The module now supports nginx streams and can be used in the same way the http module can be used. - -## Installing -First install [libmaxminddb](https://github.com/maxmind/libmaxminddb) as described in its [README.md -file](https://github.com/maxmind/libmaxminddb/blob/master/README.md#installing-from-a-tarball). - -#### Download nginx source -``` -wget http://nginx.org/download/nginx-VERSION.tar.gz -tar zxvf nginx-VERSION.tar.gz -cd nginx-VERSION -``` - -##### To build as a dynamic module (nginx 1.9.11+): -``` -./configure --add-dynamic-module=/path/to/ngx_http_geoip2_module -make -make install -``` - -This will produce ```objs/ngx_http_geoip2_module.so```. It can be copied to your nginx module path manually if you wish. - -Add the following line to your nginx.conf: -``` -load_module modules/ngx_http_geoip2_module.so; -``` - -##### To build as a static module: -``` -./configure --add-module=/path/to/ngx_http_geoip2_module -make -make install -``` - -## Download Maxmind GeoLite2 Database (optional) -The free GeoLite2 databases are available from [Maxminds website](http://dev.maxmind.com/geoip/geoip2/geolite2/) - -[GeoLite2 City](http://geolite.maxmind.com/download/geoip/database/GeoLite2-City.mmdb.gz) -[GeoLite2 Country](http://geolite.maxmind.com/download/geoip/database/GeoLite2-Country.mmdb.gz) - -## Example Usage: -``` -http { - ... - geoip2 /etc/maxmind-country.mmdb { - auto_reload 5m; - $geoip2_metadata_country_build metadata build_epoch; - $geoip2_data_country_code default=US source=$variable_with_ip country iso_code; - $geoip2_data_country_name country names en; - } - - geoip2 /etc/maxmind-city.mmdb { - $geoip2_data_city_name default=London city names en; - } - .... - - fastcgi_param COUNTRY_CODE $geoip2_data_country_code; - fastcgi_param COUNTRY_NAME $geoip2_data_country_name; - fastcgi_param CITY_NAME $geoip2_data_city_name; - .... -} - -stream { - ... - geoip2 /etc/maxmind-country.mmdb { - $geoip2_data_country_code default=US source=$remote_addr country iso_code; - } - ... -} -``` - -##### Metadata: -Retrieve metadata regarding the geoip database. -``` -$variable_name metadata -``` -Available fields: - - build_epoch: the build timestamp of the maxmind database. - - last_check: the last time the database was checked for changes (when using auto_reload) - - last_change: the last time the database was reloaded (when using auto_reload) - -##### Autoreload (default: disabled): -Enabling auto reload will have nginx check the modification time of the database at the specified -interval and reload it if it has changed. -``` -auto_reload -``` - -##### GeoIP: -``` -$variable_name [default= - "iso_code": - "US" - "names": - { - "de": - "USA" - "en": - "United States" - } - } - } - -$ mmdblookup --file /usr/share/GeoIP/GeoIP2-Country.mmdb --ip 8.8.8.8 country names en - - "United States" -``` - -This translates to: - -``` -$country_name "default=United States" source=$remote_addr country names en -``` diff --git a/debian/modules/http-geoip2/config b/debian/modules/http-geoip2/config deleted file mode 100644 index 48bf15d..0000000 --- a/debian/modules/http-geoip2/config +++ /dev/null @@ -1,43 +0,0 @@ -ngx_feature="MaxmindDB library" -ngx_feature_name= -ngx_feature_run=no -ngx_feature_incs="#include " -ngx_feature_libs=-lmaxminddb -ngx_feature_test="MMDB_s mmdb" -. auto/feature - -ngx_addon_name="ngx_geoip2_module" - -if [ $ngx_found = yes ]; then - if test -n "$ngx_module_link"; then - if [ $HTTP != NO ]; then - ngx_module_type=HTTP - ngx_module_name="ngx_http_geoip2_module" - ngx_module_incs= - ngx_module_deps= - ngx_module_srcs="$ngx_addon_dir/ngx_http_geoip2_module.c" - ngx_module_libs="$ngx_feature_libs" - . auto/module - fi - - nginx_version=`awk '/^#define nginx_version / {print $3}' src/core/nginx.h` - if [ $STREAM != NO -a $nginx_version -gt 1011001 ]; then - ngx_module_type=STREAM - ngx_module_name="ngx_stream_geoip2_module" - ngx_module_incs= - ngx_module_deps= - ngx_module_srcs="$ngx_addon_dir/ngx_stream_geoip2_module.c" - ngx_module_libs="$ngx_feature_libs" - . auto/module - fi - else - HTTP_MODULES="$HTTP_MODULES ngx_http_geoip2_module" - NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_geoip2_module.c" - CORE_LIBS="$CORE_LIBS $ngx_feature_libs" - fi -else - cat << END -$0: error: the geoip2 module requires the maxminddb library. -END - exit 1 -fi diff --git a/debian/modules/http-geoip2/ngx_http_geoip2_module.c b/debian/modules/http-geoip2/ngx_http_geoip2_module.c deleted file mode 100644 index d27c94d..0000000 --- a/debian/modules/http-geoip2/ngx_http_geoip2_module.c +++ /dev/null @@ -1,793 +0,0 @@ -/* - * Copyright (C) Lee Valentine - * - * Based on nginx's 'ngx_http_geoip_module.c' by Igor Sysoev - */ - - -#include -#include -#include - -#include - - -typedef struct { - MMDB_s mmdb; - MMDB_lookup_result_s result; - time_t last_check; - time_t last_change; - time_t check_interval; -#if (NGX_HAVE_INET6) - uint8_t address[16]; -#else - unsigned long address; -#endif - ngx_queue_t queue; -} ngx_http_geoip2_db_t; - -typedef struct { - ngx_queue_t databases; - ngx_array_t *proxies; - ngx_flag_t proxy_recursive; -} ngx_http_geoip2_conf_t; - -typedef struct { - ngx_http_geoip2_db_t *database; - const char **lookup; - ngx_str_t default_value; - ngx_http_complex_value_t source; -} ngx_http_geoip2_ctx_t; - -typedef struct { - ngx_http_geoip2_db_t *database; - ngx_str_t metavalue; -} ngx_http_geoip2_metadata_t; - - -static ngx_int_t ngx_http_geoip2_variable(ngx_http_request_t *r, - ngx_http_variable_value_t *v, uintptr_t data); -static ngx_int_t ngx_http_geoip2_metadata(ngx_http_request_t *r, - ngx_http_variable_value_t *v, uintptr_t data); -static void *ngx_http_geoip2_create_conf(ngx_conf_t *cf); -static char *ngx_http_geoip2_init_conf(ngx_conf_t *cf, void *conf); -static char *ngx_http_geoip2(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf); -static char *ngx_http_geoip2_parse_config(ngx_conf_t *cf, ngx_command_t *dummy, - void *conf); -static char *ngx_http_geoip2_add_variable(ngx_conf_t *cf, ngx_command_t *dummy, - void *conf); -static char *ngx_http_geoip2_add_variable_geodata(ngx_conf_t *cf, - ngx_http_geoip2_db_t *database); -static char *ngx_http_geoip2_add_variable_metadata(ngx_conf_t *cf, - ngx_http_geoip2_db_t *database); -static char *ngx_http_geoip2_proxy(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf); -static ngx_int_t ngx_http_geoip2_cidr_value(ngx_conf_t *cf, ngx_str_t *net, - ngx_cidr_t *cidr); -static void ngx_http_geoip2_cleanup(void *data); -static ngx_int_t ngx_http_geoip2_init(ngx_conf_t *cf); - - -#define FORMAT(fmt, ...) do { \ - p = ngx_palloc(r->pool, NGX_OFF_T_LEN); \ - if (p == NULL) { \ - return NGX_ERROR; \ - } \ - v->len = ngx_sprintf(p, fmt, __VA_ARGS__) - p; \ - v->data = p; \ -} while (0) - -static ngx_command_t ngx_http_geoip2_commands[] = { - - { ngx_string("geoip2"), - NGX_HTTP_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_TAKE1, - ngx_http_geoip2, - NGX_HTTP_MAIN_CONF_OFFSET, - 0, - NULL }, - - { ngx_string("geoip2_proxy"), - NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1, - ngx_http_geoip2_proxy, - NGX_HTTP_MAIN_CONF_OFFSET, - 0, - NULL }, - - { ngx_string("geoip2_proxy_recursive"), - NGX_HTTP_MAIN_CONF|NGX_CONF_FLAG, - ngx_conf_set_flag_slot, - NGX_HTTP_MAIN_CONF_OFFSET, - offsetof(ngx_http_geoip2_conf_t, proxy_recursive), - NULL }, - - ngx_null_command -}; - - -static ngx_http_module_t ngx_http_geoip2_module_ctx = { - NULL, /* preconfiguration */ - ngx_http_geoip2_init, /* postconfiguration */ - - ngx_http_geoip2_create_conf, /* create main configuration */ - ngx_http_geoip2_init_conf, /* init main configuration */ - - NULL, /* create server configuration */ - NULL, /* merge server configuration */ - - NULL, /* create location configuration */ - NULL /* merge location configuration */ -}; - - -ngx_module_t ngx_http_geoip2_module = { - NGX_MODULE_V1, - &ngx_http_geoip2_module_ctx, /* module context */ - ngx_http_geoip2_commands, /* module directives */ - NGX_HTTP_MODULE, /* module type */ - NULL, /* init master */ - NULL, /* init module */ - NULL, /* init process */ - NULL, /* init thread */ - NULL, /* exit thread */ - NULL, /* exit process */ - NULL, /* exit master */ - NGX_MODULE_V1_PADDING -}; - - -static ngx_int_t -ngx_http_geoip2_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, - uintptr_t data) -{ - ngx_http_geoip2_ctx_t *geoip2 = (ngx_http_geoip2_ctx_t *) data; - ngx_http_geoip2_db_t *database = geoip2->database; - int mmdb_error; - MMDB_entry_data_s entry_data; - ngx_http_geoip2_conf_t *gcf; - ngx_addr_t addr; - ngx_array_t *xfwd; - u_char *p; - ngx_str_t val; - -#if (NGX_HAVE_INET6) - uint8_t address[16], *addressp = address; -#else - unsigned long address; -#endif - - if (geoip2->source.value.len > 0) { - if (ngx_http_complex_value(r, &geoip2->source, &val) != NGX_OK) { - goto not_found; - } - - if (ngx_parse_addr(r->pool, &addr, val.data, val.len) != NGX_OK) { - goto not_found; - } - } else { - gcf = ngx_http_get_module_main_conf(r, ngx_http_geoip2_module); - addr.sockaddr = r->connection->sockaddr; - addr.socklen = r->connection->socklen; - - xfwd = &r->headers_in.x_forwarded_for; - - if (xfwd->nelts > 0 && gcf->proxies != NULL) { - (void) ngx_http_get_forwarded_addr(r, &addr, xfwd, NULL, - gcf->proxies, gcf->proxy_recursive); - } - } - - switch (addr.sockaddr->sa_family) { - case AF_INET: -#if (NGX_HAVE_INET6) - ngx_memset(addressp, 0, 12); - ngx_memcpy(addressp + 12, &((struct sockaddr_in *) - addr.sockaddr)->sin_addr.s_addr, 4); - break; - - case AF_INET6: - ngx_memcpy(addressp, &((struct sockaddr_in6 *) - addr.sockaddr)->sin6_addr.s6_addr, 16); -#else - address = ((struct sockaddr_in *)addr.sockaddr)->sin_addr.s_addr; -#endif - break; - - default: - goto not_found; - } - -#if (NGX_HAVE_INET6) - if (ngx_memcmp(&address, &database->address, sizeof(address)) - != 0) { -#else - if (address != database->address) { -#endif - memcpy(&database->address, &address, sizeof(address)); - database->result = MMDB_lookup_sockaddr(&database->mmdb, - addr.sockaddr, &mmdb_error); - - if (mmdb_error != MMDB_SUCCESS) { - goto not_found; - } - } - - if (!database->result.found_entry - || MMDB_aget_value(&database->result.entry, &entry_data, - geoip2->lookup) != MMDB_SUCCESS) { - goto not_found; - } - - if (!entry_data.has_data) { - goto not_found; - } - - switch (entry_data.type) { - case MMDB_DATA_TYPE_BOOLEAN: - FORMAT("%d", entry_data.boolean); - break; - case MMDB_DATA_TYPE_UTF8_STRING: - v->len = entry_data.data_size; - v->data = ngx_pnalloc(r->pool, v->len); - if (v->data == NULL) { - return NGX_ERROR; - } - ngx_memcpy(v->data, (u_char *) entry_data.utf8_string, v->len); - break; - case MMDB_DATA_TYPE_BYTES: - v->len = entry_data.data_size; - v->data = ngx_pnalloc(r->pool, v->len); - if (v->data == NULL) { - return NGX_ERROR; - } - ngx_memcpy(v->data, (u_char *) entry_data.bytes, v->len); - break; - case MMDB_DATA_TYPE_FLOAT: - FORMAT("%.5f", entry_data.float_value); - break; - case MMDB_DATA_TYPE_DOUBLE: - FORMAT("%.5f", entry_data.double_value); - break; - case MMDB_DATA_TYPE_UINT16: - FORMAT("%uD", entry_data.uint16); - break; - case MMDB_DATA_TYPE_UINT32: - FORMAT("%uD", entry_data.uint32); - break; - case MMDB_DATA_TYPE_INT32: - FORMAT("%D", entry_data.int32); - break; - case MMDB_DATA_TYPE_UINT64: - FORMAT("%uL", entry_data.uint64); - break; - case MMDB_DATA_TYPE_UINT128: ; -#if MMDB_UINT128_IS_BYTE_ARRAY - uint8_t *val = (uint8_t *)entry_data.uint128; - FORMAT( "0x%02x%02x%02x%02x%02x%02x%02x%02x" - "%02x%02x%02x%02x%02x%02x%02x%02x", - val[0], val[1], val[2], val[3], - val[4], val[5], val[6], val[7], - val[8], val[9], val[10], val[11], - val[12], val[13], val[14], val[15]); -#else - mmdb_uint128_t val = entry_data.uint128; - FORMAT("0x%016uxL%016uxL", - (uint64_t) (val >> 64), (uint64_t) val); -#endif - break; - default: - goto not_found; - } - - v->valid = 1; - v->no_cacheable = 0; - v->not_found = 0; - - return NGX_OK; - -not_found: - if (geoip2->default_value.len > 0) { - v->data = geoip2->default_value.data; - v->len = geoip2->default_value.len; - - v->valid = 1; - v->no_cacheable = 0; - v->not_found = 0; - } else { - v->not_found = 1; - } - - return NGX_OK; -} - - -static ngx_int_t -ngx_http_geoip2_metadata(ngx_http_request_t *r, ngx_http_variable_value_t *v, - uintptr_t data) -{ - ngx_http_geoip2_metadata_t *metadata = (ngx_http_geoip2_metadata_t *) data; - ngx_http_geoip2_db_t *database = metadata->database; - u_char *p; - - if (ngx_strncmp(metadata->metavalue.data, "build_epoch", 11) == 0) { - FORMAT("%uL", database->mmdb.metadata.build_epoch); - } else if (ngx_strncmp(metadata->metavalue.data, "last_check", 10) == 0) { - FORMAT("%T", database->last_check); - } else if (ngx_strncmp(metadata->metavalue.data, "last_change", 11) == 0) { - FORMAT("%T", database->last_change); - } else { - v->not_found = 1; - return NGX_OK; - } - - v->valid = 1; - v->no_cacheable = 0; - v->not_found = 0; - - return NGX_OK; -} - - -static void * -ngx_http_geoip2_create_conf(ngx_conf_t *cf) -{ - ngx_pool_cleanup_t *cln; - ngx_http_geoip2_conf_t *conf; - - conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_geoip2_conf_t)); - if (conf == NULL) { - return NULL; - } - - conf->proxy_recursive = NGX_CONF_UNSET; - - cln = ngx_pool_cleanup_add(cf->pool, 0); - if (cln == NULL) { - return NULL; - } - - ngx_queue_init(&conf->databases); - - cln->handler = ngx_http_geoip2_cleanup; - cln->data = conf; - - return conf; -} - - -static char * -ngx_http_geoip2(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) -{ - ngx_http_geoip2_conf_t *gcf = conf; - ngx_str_t *value; - int status; - ngx_http_geoip2_db_t *database; - char *rv; - ngx_conf_t save; - ngx_queue_t *q; - - value = cf->args->elts; - - if (value[1].data && value[1].data[0] != '/') { - if (ngx_conf_full_name(cf->cycle, &value[1], 0) != NGX_OK) { - return NGX_CONF_ERROR; - } - } - - if (!ngx_queue_empty(&gcf->databases)) { - for (q = ngx_queue_head(&gcf->databases); - q != ngx_queue_sentinel(&gcf->databases); - q = ngx_queue_next(q)) - { - database = ngx_queue_data(q, ngx_http_geoip2_db_t, queue); - if (ngx_strcmp(value[1].data, database->mmdb.filename) == 0) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "Duplicate GeoIP2 mmdb - %V", &value[1]); - return NGX_CONF_ERROR; - } - } - } - - database = ngx_pcalloc(cf->pool, sizeof(ngx_http_geoip2_db_t)); - if (database == NULL) { - return NGX_CONF_ERROR; - } - - ngx_queue_insert_tail(&gcf->databases, &database->queue); - database->last_check = database->last_change = ngx_time(); - - status = MMDB_open((char *) value[1].data, MMDB_MODE_MMAP, &database->mmdb); - - if (status != MMDB_SUCCESS) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "MMDB_open(\"%V\") failed - %s", &value[1], - MMDB_strerror(status)); - return NGX_CONF_ERROR; - } - - save = *cf; - cf->handler = ngx_http_geoip2_parse_config; - cf->handler_conf = (void *) database; - - rv = ngx_conf_parse(cf, NULL); - *cf = save; - return rv; -} - - -static char * -ngx_http_geoip2_parse_config(ngx_conf_t *cf, ngx_command_t *dummy, void *conf) -{ - ngx_http_geoip2_db_t *database; - ngx_str_t *value; - time_t interval; - - value = cf->args->elts; - - if (value[0].data[0] == '$') { - return ngx_http_geoip2_add_variable(cf, dummy, conf); - } - - if (value[0].len == 11 - && ngx_strncmp(value[0].data, "auto_reload", 11) == 0) { - if ((int) cf->args->nelts != 2) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid number of arguments for auto_reload"); - return NGX_CONF_ERROR; - } - - interval = ngx_parse_time(&value[1], true); - - if (interval == (time_t) NGX_ERROR) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid interval for auto_reload \"%V\"", - value[1]); - return NGX_CONF_ERROR; - } - - - database = (ngx_http_geoip2_db_t *) conf; - database->check_interval = interval; - return NGX_CONF_OK; - } - - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid setting \"%V\"", &value[0]); - return NGX_CONF_ERROR; -} - - -static char * -ngx_http_geoip2_add_variable(ngx_conf_t *cf, ngx_command_t *dummy, void *conf) -{ - ngx_http_geoip2_db_t *database; - ngx_str_t *value; - int nelts; - - value = cf->args->elts; - - if (value[0].data[0] != '$') { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid variable name \"%V\"", &value[0]); - return NGX_CONF_ERROR; - } - - value[0].len--; - value[0].data++; - - nelts = (int) cf->args->nelts; - database = (ngx_http_geoip2_db_t *) conf; - - if (nelts > 0 && value[1].len == 8 && ngx_strncmp(value[1].data, "metadata", 8) == 0) { - return ngx_http_geoip2_add_variable_metadata(cf, database); - } - - return ngx_http_geoip2_add_variable_geodata(cf, database); -} - - -static char * -ngx_http_geoip2_add_variable_metadata(ngx_conf_t *cf, ngx_http_geoip2_db_t *database) -{ - ngx_http_geoip2_metadata_t *metadata; - ngx_str_t *value, name; - ngx_http_variable_t *var; - - metadata = ngx_pcalloc(cf->pool, sizeof(ngx_http_geoip2_metadata_t)); - if (metadata == NULL) { - return NGX_CONF_ERROR; - } - - value = cf->args->elts; - name = value[0]; - - metadata->database = database; - metadata->metavalue = value[2]; - - var = ngx_http_add_variable(cf, &name, NGX_HTTP_VAR_CHANGEABLE); - if (var == NULL) { - return NGX_CONF_ERROR; - } - - var->get_handler = ngx_http_geoip2_metadata; - var->data = (uintptr_t) metadata; - - return NGX_CONF_OK; -} - - -static char * -ngx_http_geoip2_add_variable_geodata(ngx_conf_t *cf, ngx_http_geoip2_db_t *database) -{ - ngx_http_geoip2_ctx_t *geoip2; - ngx_http_compile_complex_value_t ccv; - ngx_str_t *value, name, source; - ngx_http_variable_t *var; - int i, nelts, idx; - - geoip2 = ngx_pcalloc(cf->pool, sizeof(ngx_http_geoip2_ctx_t)); - if (geoip2 == NULL) { - return NGX_CONF_ERROR; - } - - geoip2->database = database; - ngx_str_null(&source); - - value = cf->args->elts; - name = value[0]; - - nelts = (int) cf->args->nelts; - idx = 1; - - if (nelts > idx) { - for (i = idx; i < nelts; i++) { - if (ngx_strnstr(value[idx].data, "=", value[idx].len) == NULL) { - break; - } - - if (value[idx].len > 8 && ngx_strncmp(value[idx].data, "default=", 8) == 0) { - if (geoip2->default_value.len > 0) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "default has already been declared for \"$%V\"", &name); - return NGX_CONF_ERROR; - } - - geoip2->default_value.len = value[idx].len - 8; - geoip2->default_value.data = value[idx].data + 8; - } else if (value[idx].len > 7 && ngx_strncmp(value[idx].data, "source=", 7) == 0) { - if (source.len > 0) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "source has already been declared for \"$%V\"", &name); - return NGX_CONF_ERROR; - } - - source.len = value[idx].len - 7; - source.data = value[idx].data + 7; - - if (source.data[0] != '$') { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid source variable name \"%V\"", &source); - return NGX_CONF_ERROR; - } - - ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); - ccv.cf = cf; - ccv.value = &source; - ccv.complex_value = &geoip2->source; - - if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "unable to compile \"%V\" for \"$%V\"", &source, &name); - return NGX_CONF_ERROR; - } - } else { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid setting \"%V\" for \"$%V\"", &value[idx], &name); - return NGX_CONF_ERROR; - } - - idx++; - } - } - - var = ngx_http_add_variable(cf, &name, NGX_HTTP_VAR_CHANGEABLE); - if (var == NULL) { - return NGX_CONF_ERROR; - } - - geoip2->lookup = ngx_pcalloc(cf->pool, sizeof(const char *) * - (cf->args->nelts - (idx - 1))); - - if (geoip2->lookup == NULL) { - return NGX_CONF_ERROR; - } - - for (i = idx; i < nelts; i++) { - geoip2->lookup[i - idx] = (char *) value[i].data; - } - geoip2->lookup[i - idx] = NULL; - - var->get_handler = ngx_http_geoip2_variable; - var->data = (uintptr_t) geoip2; - - return NGX_CONF_OK; -} - - -static char * -ngx_http_geoip2_init_conf(ngx_conf_t *cf, void *conf) -{ - ngx_http_geoip2_conf_t *gcf = conf; - ngx_conf_init_value(gcf->proxy_recursive, 0); - return NGX_CONF_OK; -} - - -static char * -ngx_http_geoip2_proxy(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) -{ - ngx_http_geoip2_conf_t *gcf = conf; - ngx_str_t *value; - ngx_cidr_t cidr, *c; - - value = cf->args->elts; - - if (ngx_http_geoip2_cidr_value(cf, &value[1], &cidr) != NGX_OK) { - return NGX_CONF_ERROR; - } - - if (gcf->proxies == NULL) { - gcf->proxies = ngx_array_create(cf->pool, 4, sizeof(ngx_cidr_t)); - if (gcf->proxies == NULL) { - return NGX_CONF_ERROR; - } - } - - c = ngx_array_push(gcf->proxies); - if (c == NULL) { - return NGX_CONF_ERROR; - } - - *c = cidr; - - return NGX_CONF_OK; -} - - -static ngx_int_t -ngx_http_geoip2_cidr_value(ngx_conf_t *cf, ngx_str_t *net, ngx_cidr_t *cidr) -{ - ngx_int_t rc; - - if (ngx_strcmp(net->data, "255.255.255.255") == 0) { - cidr->family = AF_INET; - cidr->u.in.addr = 0xffffffff; - cidr->u.in.mask = 0xffffffff; - - return NGX_OK; - } - - rc = ngx_ptocidr(net, cidr); - - if (rc == NGX_ERROR) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid network \"%V\"", net); - return NGX_ERROR; - } - - if (rc == NGX_DONE) { - ngx_conf_log_error(NGX_LOG_WARN, cf, 0, - "low address bits of %V are meaningless", net); - } - - return NGX_OK; -} - - -static void -ngx_http_geoip2_cleanup(void *data) -{ - ngx_http_geoip2_conf_t *gcf = data; - ngx_queue_t *q; - ngx_http_geoip2_db_t *database; - - while (!ngx_queue_empty(&gcf->databases)) { - q = ngx_queue_head(&gcf->databases); - ngx_queue_remove(q); - database = ngx_queue_data(q, ngx_http_geoip2_db_t, queue); - MMDB_close(&database->mmdb); - } -} - - -static ngx_int_t -ngx_http_geoip2_log_handler(ngx_http_request_t *r) -{ - int status; - MMDB_s tmpdb; - ngx_queue_t *q; - ngx_file_info_t fi; - ngx_http_geoip2_db_t *database; - ngx_http_geoip2_conf_t *gcf; - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "geoip2 http log handler"); - - gcf = ngx_http_get_module_main_conf(r, ngx_http_geoip2_module); - - if (ngx_queue_empty(&gcf->databases)) { - return NGX_OK; - } - - for (q = ngx_queue_head(&gcf->databases); - q != ngx_queue_sentinel(&gcf->databases); - q = ngx_queue_next(q)) - { - database = ngx_queue_data(q, ngx_http_geoip2_db_t, queue); - if (database->check_interval == 0) { - continue; - } - - if ((database->last_check + database->check_interval) - > ngx_time()) - { - continue; - } - - database->last_check = ngx_time(); - - if (ngx_file_info(database->mmdb.filename, &fi) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_EMERG, r->connection->log, ngx_errno, - ngx_file_info_n " \"%s\" failed", - database->mmdb.filename); - - continue; - } - - if (ngx_file_mtime(&fi) <= database->last_change) { - continue; - } - - /* do the reload */ - - ngx_memzero(&tmpdb, sizeof(MMDB_s)); - status = MMDB_open(database->mmdb.filename, MMDB_MODE_MMAP, &tmpdb); - - if (status != MMDB_SUCCESS) { - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "MMDB_open(\"%s\") failed to reload - %s", - database->mmdb.filename, MMDB_strerror(status)); - - continue; - } - - database->last_change = ngx_file_mtime(&fi); - MMDB_close(&database->mmdb); - database->mmdb = tmpdb; - - ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, - "Reload MMDB \"%s\"", - database->mmdb.filename); - } - - return NGX_OK; -} - - -static ngx_int_t -ngx_http_geoip2_init(ngx_conf_t *cf) -{ - ngx_http_handler_pt *h; - ngx_http_core_main_conf_t *cmcf; - - cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); - - h = ngx_array_push(&cmcf->phases[NGX_HTTP_LOG_PHASE].handlers); - if (h == NULL) { - return NGX_ERROR; - } - - *h = ngx_http_geoip2_log_handler; - - return NGX_OK; -} diff --git a/debian/modules/http-geoip2/ngx_stream_geoip2_module.c b/debian/modules/http-geoip2/ngx_stream_geoip2_module.c deleted file mode 100644 index eb59082..0000000 --- a/debian/modules/http-geoip2/ngx_stream_geoip2_module.c +++ /dev/null @@ -1,694 +0,0 @@ -/* - * Copyright (C) Lee Valentine - * Copyright (C) Andrei Belov - * - * Based on nginx's 'ngx_stream_geoip_module.c' by Igor Sysoev - */ - - -#include -#include -#include - -#include - - -typedef struct { - MMDB_s mmdb; - MMDB_lookup_result_s result; - time_t last_check; - time_t last_change; - time_t check_interval; -#if (NGX_HAVE_INET6) - uint8_t address[16]; -#else - unsigned long address; -#endif - ngx_queue_t queue; -} ngx_stream_geoip2_db_t; - -typedef struct { - ngx_queue_t databases; -} ngx_stream_geoip2_conf_t; - -typedef struct { - ngx_stream_geoip2_db_t *database; - const char **lookup; - ngx_str_t default_value; - ngx_stream_complex_value_t source; -} ngx_stream_geoip2_ctx_t; - -typedef struct { - ngx_stream_geoip2_db_t *database; - ngx_str_t metavalue; -} ngx_stream_geoip2_metadata_t; - - -static ngx_int_t ngx_stream_geoip2_variable(ngx_stream_session_t *s, - ngx_stream_variable_value_t *v, uintptr_t data); -static ngx_int_t ngx_stream_geoip2_metadata(ngx_stream_session_t *s, - ngx_stream_variable_value_t *v, uintptr_t data); -static void *ngx_stream_geoip2_create_conf(ngx_conf_t *cf); -static char *ngx_stream_geoip2(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf); -static char *ngx_stream_geoip2_parse_config(ngx_conf_t *cf, ngx_command_t *dummy, - void *conf); -static char *ngx_stream_geoip2(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf); -static char *ngx_stream_geoip2_add_variable(ngx_conf_t *cf, ngx_command_t *dummy, - void *conf); -static char *ngx_stream_geoip2_add_variable_geodata(ngx_conf_t *cf, - ngx_stream_geoip2_db_t *database); -static char *ngx_stream_geoip2_add_variable_metadata(ngx_conf_t *cf, - ngx_stream_geoip2_db_t *database); -static void ngx_stream_geoip2_cleanup(void *data); -static ngx_int_t ngx_stream_geoip2_init(ngx_conf_t *cf); - - -#define FORMAT(fmt, ...) do { \ - p = ngx_palloc(s->connection->pool, NGX_OFF_T_LEN); \ - if (p == NULL) { \ - return NGX_ERROR; \ - } \ - v->len = ngx_sprintf(p, fmt, __VA_ARGS__) - p; \ - v->data = p; \ -} while (0) - -static ngx_command_t ngx_stream_geoip2_commands[] = { - - { ngx_string("geoip2"), - NGX_STREAM_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_TAKE1, - ngx_stream_geoip2, - NGX_STREAM_MAIN_CONF_OFFSET, - 0, - NULL }, - - ngx_null_command -}; - - -static ngx_stream_module_t ngx_stream_geoip2_module_ctx = { - NULL, /* preconfiguration */ - ngx_stream_geoip2_init, /* postconfiguration */ - - ngx_stream_geoip2_create_conf, /* create main configuration */ - NULL, /* init main configuration */ - - NULL, /* create server configuration */ - NULL /* merge server configuration */ -}; - - -ngx_module_t ngx_stream_geoip2_module = { - NGX_MODULE_V1, - &ngx_stream_geoip2_module_ctx, /* module context */ - ngx_stream_geoip2_commands, /* module directives */ - NGX_STREAM_MODULE, /* module type */ - NULL, /* init master */ - NULL, /* init module */ - NULL, /* init process */ - NULL, /* init thread */ - NULL, /* exit thread */ - NULL, /* exit process */ - NULL, /* exit master */ - NGX_MODULE_V1_PADDING -}; - - -static ngx_int_t -ngx_stream_geoip2_variable(ngx_stream_session_t *s, ngx_stream_variable_value_t *v, - uintptr_t data) -{ - int mmdb_error; - u_char *p; - ngx_str_t val; - ngx_addr_t addr; - MMDB_entry_data_s entry_data; - ngx_stream_geoip2_ctx_t *geoip2 = (ngx_stream_geoip2_ctx_t *) data; - ngx_stream_geoip2_db_t *database = geoip2->database; - -#if (NGX_HAVE_INET6) - uint8_t address[16], *addressp = address; -#else - unsigned long address; -#endif - - if (geoip2->source.value.len > 0) { - if (ngx_stream_complex_value(s, &geoip2->source, &val) != NGX_OK) { - goto not_found; - } - - if (ngx_parse_addr(s->connection->pool, &addr, val.data, val.len) != NGX_OK) { - goto not_found; - } - } else { - addr.sockaddr = s->connection->sockaddr; - addr.socklen = s->connection->socklen; - } - - switch (addr.sockaddr->sa_family) { - case AF_INET: -#if (NGX_HAVE_INET6) - ngx_memset(addressp, 0, 12); - ngx_memcpy(addressp + 12, &((struct sockaddr_in *) - addr.sockaddr)->sin_addr.s_addr, 4); - break; - - case AF_INET6: - ngx_memcpy(addressp, &((struct sockaddr_in6 *) - addr.sockaddr)->sin6_addr.s6_addr, 16); -#else - address = ((struct sockaddr_in *)addr.sockaddr)->sin_addr.s_addr; -#endif - break; - - default: - goto not_found; - } - -#if (NGX_HAVE_INET6) - if (ngx_memcmp(&address, &database->address, sizeof(address)) != 0) { -#else - if (address != database->address) { -#endif - memcpy(&database->address, &address, sizeof(address)); - database->result = MMDB_lookup_sockaddr(&database->mmdb, - addr.sockaddr, &mmdb_error); - - if (mmdb_error != MMDB_SUCCESS) { - goto not_found; - } - } - - if (!database->result.found_entry - || MMDB_aget_value(&database->result.entry, &entry_data, geoip2->lookup) - != MMDB_SUCCESS) - { - goto not_found; - } - - if (!entry_data.has_data) { - goto not_found; - } - - switch (entry_data.type) { - case MMDB_DATA_TYPE_BOOLEAN: - FORMAT("%d", entry_data.boolean); - break; - case MMDB_DATA_TYPE_UTF8_STRING: - v->len = entry_data.data_size; - v->data = ngx_pnalloc(s->connection->pool, v->len); - if (v->data == NULL) { - return NGX_ERROR; - } - ngx_memcpy(v->data, (u_char *) entry_data.utf8_string, v->len); - break; - case MMDB_DATA_TYPE_BYTES: - v->len = entry_data.data_size; - v->data = ngx_pnalloc(s->connection->pool, v->len); - if (v->data == NULL) { - return NGX_ERROR; - } - ngx_memcpy(v->data, (u_char *) entry_data.bytes, v->len); - break; - case MMDB_DATA_TYPE_FLOAT: - FORMAT("%.5f", entry_data.float_value); - break; - case MMDB_DATA_TYPE_DOUBLE: - FORMAT("%.5f", entry_data.double_value); - break; - case MMDB_DATA_TYPE_UINT16: - FORMAT("%uD", entry_data.uint16); - break; - case MMDB_DATA_TYPE_UINT32: - FORMAT("%uD", entry_data.uint32); - break; - case MMDB_DATA_TYPE_INT32: - FORMAT("%D", entry_data.int32); - break; - case MMDB_DATA_TYPE_UINT64: - FORMAT("%uL", entry_data.uint64); - break; - case MMDB_DATA_TYPE_UINT128: ; -#if MMDB_UINT128_IS_BYTE_ARRAY - uint8_t *val = (uint8_t *) entry_data.uint128; - FORMAT("0x%02x%02x%02x%02x%02x%02x%02x%02x" - "%02x%02x%02x%02x%02x%02x%02x%02x", - val[0], val[1], val[2], val[3], - val[4], val[5], val[6], val[7], - val[8], val[9], val[10], val[11], - val[12], val[13], val[14], val[15]); -#else - mmdb_uint128_t val = entry_data.uint128; - FORMAT("0x%016uxL%016uxL", - (uint64_t) (val >> 64), (uint64_t) val); -#endif - break; - default: - goto not_found; - } - - v->valid = 1; - v->no_cacheable = 0; - v->not_found = 0; - - return NGX_OK; - -not_found: - if (geoip2->default_value.len > 0) { - v->data = geoip2->default_value.data; - v->len = geoip2->default_value.len; - - v->valid = 1; - v->no_cacheable = 0; - v->not_found = 0; - - return NGX_OK; - } - - v->not_found = 1; - - return NGX_OK; -} - - -static ngx_int_t -ngx_stream_geoip2_metadata(ngx_stream_session_t *s, ngx_stream_variable_value_t *v, - uintptr_t data) -{ - ngx_stream_geoip2_metadata_t *metadata = (ngx_stream_geoip2_metadata_t *) data; - ngx_stream_geoip2_db_t *database = metadata->database; - u_char *p; - - if (ngx_strncmp(metadata->metavalue.data, "build_epoch", 11) == 0) { - FORMAT("%uL", database->mmdb.metadata.build_epoch); - } else if (ngx_strncmp(metadata->metavalue.data, "last_check", 10) == 0) { - FORMAT("%T", database->last_check); - } else if (ngx_strncmp(metadata->metavalue.data, "last_change", 11) == 0) { - FORMAT("%T", database->last_change); - } else { - v->not_found = 1; - return NGX_OK; - } - - v->valid = 1; - v->no_cacheable = 0; - v->not_found = 0; - - return NGX_OK; -} - - -static void * -ngx_stream_geoip2_create_conf(ngx_conf_t *cf) -{ - ngx_pool_cleanup_t *cln; - ngx_stream_geoip2_conf_t *conf; - - conf = ngx_pcalloc(cf->pool, sizeof(ngx_stream_geoip2_conf_t)); - if (conf == NULL) { - return NULL; - } - - cln = ngx_pool_cleanup_add(cf->pool, 0); - if (cln == NULL) { - return NULL; - } - - ngx_queue_init(&conf->databases); - - cln->handler = ngx_stream_geoip2_cleanup; - cln->data = conf; - - return conf; -} - - -static char * -ngx_stream_geoip2(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) -{ - int status; - char *rv; - ngx_str_t *value; - ngx_conf_t save; - ngx_stream_geoip2_db_t *database; - ngx_stream_geoip2_conf_t *gcf = conf; - ngx_queue_t *q; - - value = cf->args->elts; - - if (value[1].data && value[1].data[0] != '/') { - if (ngx_conf_full_name(cf->cycle, &value[1], 0) != NGX_OK) { - return NGX_CONF_ERROR; - } - } - - if (!ngx_queue_empty(&gcf->databases)) { - for (q = ngx_queue_head(&gcf->databases); - q != ngx_queue_sentinel(&gcf->databases); - q = ngx_queue_next(q)) - { - database = ngx_queue_data(q, ngx_stream_geoip2_db_t, queue); - if (ngx_strcmp(value[1].data, database->mmdb.filename) == 0) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "Duplicate GeoIP2 mmdb - %V", &value[1]); - return NGX_CONF_ERROR; - } - } - } - - database = ngx_pcalloc(cf->pool, sizeof(ngx_stream_geoip2_db_t)); - if (database == NULL) { - return NGX_CONF_ERROR; - } - - ngx_queue_insert_tail(&gcf->databases, &database->queue); - database->last_check = database->last_change = ngx_time(); - - status = MMDB_open((char *) value[1].data, MMDB_MODE_MMAP, &database->mmdb); - - if (status != MMDB_SUCCESS) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "MMDB_open(\"%V\") failed - %s", &value[1], - MMDB_strerror(status)); - return NGX_CONF_ERROR; - } - - save = *cf; - cf->handler = ngx_stream_geoip2_parse_config; - cf->handler_conf = (void *) database; - - rv = ngx_conf_parse(cf, NULL); - *cf = save; - return rv; -} - - -static char * -ngx_stream_geoip2_parse_config(ngx_conf_t *cf, ngx_command_t *dummy, void *conf) -{ - ngx_stream_geoip2_db_t *database; - ngx_str_t *value; - time_t interval; - - value = cf->args->elts; - - if (value[0].data[0] == '$') { - return ngx_stream_geoip2_add_variable(cf, dummy, conf); - } - - if (value[0].len == 11 - && ngx_strncmp(value[0].data, "auto_reload", 11) == 0) { - if ((int) cf->args->nelts != 2) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid number of arguments for auto_reload"); - return NGX_CONF_ERROR; - } - - interval = ngx_parse_time(&value[1], true); - - if (interval == (time_t) NGX_ERROR) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid interval for auto_reload \"%V\"", - value[1]); - return NGX_CONF_ERROR; - } - - - database = (ngx_stream_geoip2_db_t *) conf; - database->check_interval = interval; - return NGX_CONF_OK; - } - - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid setting \"%V\"", &value[0]); - return NGX_CONF_ERROR; -} - - -static char * -ngx_stream_geoip2_add_variable(ngx_conf_t *cf, ngx_command_t *dummy, void *conf) -{ - ngx_stream_geoip2_db_t *database; - ngx_str_t *value; - int nelts; - - value = cf->args->elts; - - if (value[0].data[0] != '$') { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid variable name \"%V\"", &value[0]); - return NGX_CONF_ERROR; - } - - value[0].len--; - value[0].data++; - - nelts = (int) cf->args->nelts; - database = (ngx_stream_geoip2_db_t *) conf; - - if (nelts > 0 && value[1].len == 8 && ngx_strncmp(value[1].data, "metadata", 8) == 0) { - return ngx_stream_geoip2_add_variable_metadata(cf, database); - } - - return ngx_stream_geoip2_add_variable_geodata(cf, database); -} - - -static char * -ngx_stream_geoip2_add_variable_metadata(ngx_conf_t *cf, ngx_stream_geoip2_db_t *database) -{ - ngx_stream_geoip2_metadata_t *metadata; - ngx_str_t *value, name; - ngx_stream_variable_t *var; - - metadata = ngx_pcalloc(cf->pool, sizeof(ngx_stream_geoip2_metadata_t)); - if (metadata == NULL) { - return NGX_CONF_ERROR; - } - - value = cf->args->elts; - name = value[0]; - - metadata->database = database; - metadata->metavalue = value[2]; - - var = ngx_stream_add_variable(cf, &name, NGX_STREAM_VAR_CHANGEABLE); - if (var == NULL) { - return NGX_CONF_ERROR; - } - - var->get_handler = ngx_stream_geoip2_metadata; - var->data = (uintptr_t) metadata; - - return NGX_CONF_OK; -} - - -static char * -ngx_stream_geoip2_add_variable_geodata(ngx_conf_t *cf, ngx_stream_geoip2_db_t *database) -{ - ngx_stream_geoip2_ctx_t *geoip2; - ngx_stream_compile_complex_value_t ccv; - ngx_str_t *value, name, source; - ngx_stream_variable_t *var; - int i, nelts, idx; - - geoip2 = ngx_pcalloc(cf->pool, sizeof(ngx_stream_geoip2_ctx_t)); - if (geoip2 == NULL) { - return NGX_CONF_ERROR; - } - - geoip2->database = database; - ngx_str_null(&source); - - value = cf->args->elts; - name = value[0]; - - nelts = (int) cf->args->nelts; - idx = 1; - - if (nelts > idx) { - for (i = idx; i < nelts; i++) { - if (ngx_strnstr(value[idx].data, "=", value[idx].len) == NULL) { - break; - } - - if (value[idx].len > 8 && ngx_strncmp(value[idx].data, "default=", 8) == 0) { - if (geoip2->default_value.len > 0) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "default has already been declared for \"$%V\"", &name); - return NGX_CONF_ERROR; - } - - geoip2->default_value.len = value[idx].len - 8; - geoip2->default_value.data = value[idx].data + 8; - - } else if (value[idx].len > 7 && ngx_strncmp(value[idx].data, "source=", 7) == 0) { - if (source.len > 0) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "source has already been declared for \"$%V\"", &name); - return NGX_CONF_ERROR; - } - - source.len = value[idx].len - 7; - source.data = value[idx].data + 7; - - if (source.data[0] != '$') { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid source variable name \"%V\"", &source); - return NGX_CONF_ERROR; - } - - ngx_memzero(&ccv, sizeof(ngx_stream_compile_complex_value_t)); - ccv.cf = cf; - ccv.value = &source; - ccv.complex_value = &geoip2->source; - - if (ngx_stream_compile_complex_value(&ccv) != NGX_OK) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "unable to compile \"%V\" for \"$%V\"", &source, &name); - return NGX_CONF_ERROR; - } - - } else { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid setting \"%V\" for \"$%V\"", &value[idx], &name); - return NGX_CONF_ERROR; - } - - idx++; - } - } - - var = ngx_stream_add_variable(cf, &name, NGX_STREAM_VAR_CHANGEABLE); - if (var == NULL) { - return NGX_CONF_ERROR; - } - - geoip2->lookup = ngx_pcalloc(cf->pool, - sizeof(const char *) * (cf->args->nelts - (idx - 1))); - - if (geoip2->lookup == NULL) { - return NGX_CONF_ERROR; - } - - for (i = idx; i < nelts; i++) { - geoip2->lookup[i - idx] = (char *) value[i].data; - } - geoip2->lookup[i - idx] = NULL; - - var->get_handler = ngx_stream_geoip2_variable; - var->data = (uintptr_t) geoip2; - - return NGX_CONF_OK; -} - - -static void -ngx_stream_geoip2_cleanup(void *data) -{ - ngx_queue_t *q; - ngx_stream_geoip2_db_t *database; - ngx_stream_geoip2_conf_t *gcf = data; - - while (!ngx_queue_empty(&gcf->databases)) { - q = ngx_queue_head(&gcf->databases); - ngx_queue_remove(q); - database = ngx_queue_data(q, ngx_stream_geoip2_db_t, queue); - MMDB_close(&database->mmdb); - } -} - - -static ngx_int_t -ngx_stream_geoip2_log_handler(ngx_stream_session_t *s) -{ - int status; - MMDB_s tmpdb; - ngx_queue_t *q; - ngx_file_info_t fi; - ngx_stream_geoip2_db_t *database; - ngx_stream_geoip2_conf_t *gcf; - - ngx_log_debug0(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, - "geoip2 stream log handler"); - - gcf = ngx_stream_get_module_main_conf(s, ngx_stream_geoip2_module); - - if (ngx_queue_empty(&gcf->databases)) { - return NGX_OK; - } - - for (q = ngx_queue_head(&gcf->databases); - q != ngx_queue_sentinel(&gcf->databases); - q = ngx_queue_next(q)) - { - database = ngx_queue_data(q, ngx_stream_geoip2_db_t, queue); - if (database->check_interval == 0) { - continue; - } - - if ((database->last_check + database->check_interval) - > ngx_time()) - { - continue; - } - - database->last_check = ngx_time(); - - if (ngx_file_info(database->mmdb.filename, &fi) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_EMERG, s->connection->log, ngx_errno, - ngx_file_info_n " \"%s\" failed", - database->mmdb.filename); - - continue; - } - - if (ngx_file_mtime(&fi) <= database->last_change) { - continue; - } - - /* do the reload */ - - ngx_memzero(&tmpdb, sizeof(MMDB_s)); - status = MMDB_open(database->mmdb.filename, MMDB_MODE_MMAP, &tmpdb); - - if (status != MMDB_SUCCESS) { - ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, - "MMDB_open(\"%s\") failed to reload - %s", - database->mmdb.filename, MMDB_strerror(status)); - - continue; - } - - database->last_change = ngx_file_mtime(&fi); - MMDB_close(&database->mmdb); - database->mmdb = tmpdb; - - ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, - "Reload MMDB \"%s\"", - database->mmdb.filename); - } - - return NGX_OK; -} - - -static ngx_int_t -ngx_stream_geoip2_init(ngx_conf_t *cf) -{ - ngx_stream_handler_pt *h; - ngx_stream_core_main_conf_t *cmcf; - - cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module); - - h = ngx_array_push(&cmcf->phases[NGX_STREAM_LOG_PHASE].handlers); - if (h == NULL) { - return NGX_ERROR; - } - - *h = ngx_stream_geoip2_log_handler; - - return NGX_OK; -} diff --git a/debian/modules/http-headers-more-filter/README.markdown b/debian/modules/http-headers-more-filter/README.markdown deleted file mode 100644 index 452ef1f..0000000 --- a/debian/modules/http-headers-more-filter/README.markdown +++ /dev/null @@ -1,549 +0,0 @@ -Name -==== - -**ngx_headers_more** - Set and clear input and output headers...more than "add"! - -*This module is not distributed with the Nginx source.* See [the installation instructions](#installation). - -Table of Contents -================= - -* [Name](#name) -* [Version](#version) -* [Synopsis](#synopsis) -* [Description](#description) -* [Directives](#directives) - * [more_set_headers](#more_set_headers) - * [more_clear_headers](#more_clear_headers) - * [more_set_input_headers](#more_set_input_headers) - * [more_clear_input_headers](#more_clear_input_headers) -* [Limitations](#limitations) -* [Installation](#installation) -* [Compatibility](#compatibility) -* [Community](#community) - * [English Mailing List](#english-mailing-list) - * [Chinese Mailing List](#chinese-mailing-list) -* [Bugs and Patches](#bugs-and-patches) -* [Source Repository](#source-repository) -* [Changes](#changes) -* [Test Suite](#test-suite) -* [TODO](#todo) -* [Getting involved](#getting-involved) -* [Authors](#authors) -* [Copyright & License](#copyright--license) -* [See Also](#see-also) - -Version -======= - -This document describes headers-more-nginx-module [v0.33](https://github.com/openresty/headers-more-nginx-module/tags) released on 3 November 2017. - -Synopsis -======== - -```nginx - - # set the Server output header - more_set_headers 'Server: my-server'; - - # set and clear output headers - location /bar { - more_set_headers 'X-MyHeader: blah' 'X-MyHeader2: foo'; - more_set_headers -t 'text/plain text/css' 'Content-Type: text/foo'; - more_set_headers -s '400 404 500 503' -s 413 'Foo: Bar'; - more_clear_headers 'Content-Type'; - - # your proxy_pass/memcached_pass/or any other config goes here... - } - - # set output headers - location /type { - more_set_headers 'Content-Type: text/plain'; - # ... - } - - # set input headers - location /foo { - set $my_host 'my dog'; - more_set_input_headers 'Host: $my_host'; - more_set_input_headers -t 'text/plain' 'X-Foo: bah'; - - # now $host and $http_host have their new values... - # ... - } - - # replace input header X-Foo *only* if it already exists - more_set_input_headers -r 'X-Foo: howdy'; -``` - -Description -=========== - -This module allows you to add, set, or clear any output -or input header that you specify. - -This is an enhanced version of the standard -[headers](http://nginx.org/en/docs/http/ngx_http_headers_module.html) module because it provides more utilities like -resetting or clearing "builtin headers" like `Content-Type`, -`Content-Length`, and `Server`. - -It also allows you to specify an optional HTTP status code -criteria using the `-s` option and an optional content -type criteria using the `-t` option while modifying the -output headers with the [more_set_headers](#more_set_headers) and -[more_clear_headers](#more_clear_headers) directives. For example, - -```nginx - more_set_headers -s 404 -t 'text/html' 'X-Foo: Bar'; -``` - -You can also specify multiple MIME types to filter out in a single `-t` option. -For example, - -```nginx -more_set_headers -t 'text/html text/plain' 'X-Foo: Bar'; -``` - -Never use other paramemters like `charset=utf-8` in the `-t` option values; they will not -work as you would expect. - -Input headers can be modified as well. For example - -```nginx - location /foo { - more_set_input_headers 'Host: foo' 'User-Agent: faked'; - # now $host, $http_host, $user_agent, and - # $http_user_agent all have their new values. - } -``` - -The option `-t` is also available in the -[more_set_input_headers](#more_set_input_headers) and -[more_clear_input_headers](#more_clear_input_headers) directives (for request header filtering) while the `-s` option -is not allowed. - -Unlike the standard [headers](http://nginx.org/en/docs/http/ngx_http_headers_module.html) module, this module's directives will by -default apply to all the status codes, including `4xx` and `5xx`. - -[Back to TOC](#table-of-contents) - -Directives -========== - -[Back to TOC](#table-of-contents) - -more_set_headers ----------------- -**syntax:** *more_set_headers [-t <content-type list>]... [-s <status-code list>]... <new-header>...* - -**default:** *no* - -**context:** *http, server, location, location if* - -**phase:** *output-header-filter* - -Replaces (if any) or adds (if not any) the specified output headers when the response status code matches the codes specified by the `-s` option *AND* the response content type matches the types specified by the `-t` option. - -If either `-s` or `-t` is not specified or has an empty list value, then no match is required. Therefore, the following directive set the `Server` output header to the custom value for *any* status code and *any* content type: - -```nginx - - more_set_headers "Server: my_server"; -``` - -Existing response headers with the same name are always overridden. If you want to add headers incrementally, use the standard [add_header](http://nginx.org/en/docs/http/ngx_http_headers_module.html#add_header) directive instead. - -A single directive can set/add multiple output headers. For example - -```nginx - - more_set_headers 'Foo: bar' 'Baz: bah'; -``` - -Multiple occurrences of the options are allowed in a single directive. Their values will be merged together. For instance - -```nginx - - more_set_headers -s 404 -s '500 503' 'Foo: bar'; -``` - -is equivalent to - -```nginx - - more_set_headers -s '404 500 503' 'Foo: bar'; -``` - -The new header should be the one of the forms: - -1. `Name: Value` -1. `Name: ` -1. `Name` - -The last two effectively clear the value of the header `Name`. - -Nginx variables are allowed in header values. For example: - -```nginx - - set $my_var "dog"; - more_set_headers "Server: $my_var"; -``` - -But variables won't work in header keys due to performance considerations. - -Multiple set/clear header directives are allowed in a single location, and they're executed sequentially. - -Directives inherited from an upper level scope (say, http block or server blocks) are executed before the directives in the location block. - -Note that although `more_set_headers` is allowed in *location* if blocks, it is *not* allowed in the *server* if blocks, as in - -```nginx - - ? # This is NOT allowed! - ? server { - ? if ($args ~ 'download') { - ? more_set_headers 'Foo: Bar'; - ? } - ? ... - ? } -``` - -Behind the scene, use of this directive and its friend [more_clear_headers](#more_clear_headers) will (lazily) register an ouput header filter that modifies `r->headers_out` the way you specify. - -[Back to TOC](#table-of-contents) - -more_clear_headers ------------------- -**syntax:** *more_clear_headers [-t <content-type list>]... [-s <status-code list>]... <new-header>...* - -**default:** *no* - -**context:** *http, server, location, location if* - -**phase:** *output-header-filter* - -Clears the specified output headers. - -In fact, - -```nginx - - more_clear_headers -s 404 -t 'text/plain' Foo Baz; -``` - -is exactly equivalent to - -```nginx - - more_set_headers -s 404 -t 'text/plain' "Foo: " "Baz: "; -``` - -or - -```nginx - - more_set_headers -s 404 -t 'text/plain' Foo Baz -``` - -See [more_set_headers](#more_set_headers) for more details. - -The wildcard character, `*`, can also be used at the end of the header name to specify a pattern. For example, the following directive -effectively clears *any* output headers starting by "`X-Hidden-`": - -```nginx - - more_clear_headers 'X-Hidden-*'; -``` - -The `*` wildcard support was first introduced in [v0.09](#v009). - -[Back to TOC](#table-of-contents) - -more_set_input_headers ----------------------- -**syntax:** *more_set_input_headers [-r] [-t <content-type list>]... <new-header>...* - -**default:** *no* - -**context:** *http, server, location, location if* - -**phase:** *rewrite tail* - -Very much like [more_set_headers](#more_set_headers) except that it operates on input headers (or request headers) and it only supports the `-t` option. - -Note that using the `-t` option in this directive means filtering by the `Content-Type` *request* header, rather than the response header. - -Behind the scene, use of this directive and its friend [more_clear_input_headers](#more_clear_input_headers) will (lazily) -register a `rewrite phase` handler that modifies `r->headers_in` the way you specify. Note that it always run at the *end* of -the `rewrite` phase so that it runs *after* the standard [rewrite module](http://nginx.org/en/docs/http/ngx_http_rewrite_module.html) -and works in subrequests as well. - -If the `-r` option is specified, then the headers will be replaced to the new values *only if* they already exist. - -[Back to TOC](#table-of-contents) - -more_clear_input_headers ------------------------- -**syntax:** *more_clear_input_headers [-t <content-type list>]... <new-header>...* - -**default:** *no* - -**context:** *http, server, location, location if* - -**phase:** *rewrite tail* - -Clears the specified input headers. - -In fact, - -```nginx - - more_clear_input_headers -t 'text/plain' Foo Baz; -``` - -is exactly equivalent to - -```nginx - - more_set_input_headers -t 'text/plain' "Foo: " "Baz: "; -``` - -or - -```nginx - - more_set_input_headers -t 'text/plain' Foo Baz -``` - -To remove request headers "Foo" and "Baz" for all incoming requests regardless of the content type, we can write - -```nginx - - more_clear_input_headers "Foo" "Baz"; -``` - -See [more_set_input_headers](#more_set_input_headers) for more details. - -The wildcard character, `*`, can also be used at the end of the header name to specify a pattern. For example, the following directive -effectively clears *any* input headers starting by "`X-Hidden-`": - -```nginx - - more_clear_input_headers 'X-Hidden-*'; -``` - -[Back to TOC](#table-of-contents) - -Limitations -=========== - -* Unlike the standard [headers](http://nginx.org/en/docs/http/ngx_http_headers_module.html) module, this module does not automatically take care of the constraint among the `Expires`, `Cache-Control`, and `Last-Modified` headers. You have to get them right yourself or use the [headers](http://nginx.org/en/docs/http/ngx_http_headers_module.html) module together with this module. -* You cannot remove the `Connection` response header using this module because the `Connection` response header is generated by the standard `ngx_http_header_filter_module` in the Nginx core, whose output header filter runs always *after* the filter of this module. The only way to actually remove the `Connection` header is to patch the Nginx core, that is, editing the C function `ngx_http_header_filter` in the `src/http/ngx_http_header_filter_module.c` file. - -[Back to TOC](#table-of-contents) - -Installation -============ - -Grab the nginx source code from [nginx.org](http://nginx.org/), for example, -the version 1.13.6 (see [nginx compatibility](#compatibility)), and then build the source with this module: - -```bash - - wget 'http://nginx.org/download/nginx-1.13.6.tar.gz' - tar -xzvf nginx-1.13.6.tar.gz - cd nginx-1.13.6/ - - # Here we assume you would install you nginx under /opt/nginx/. - ./configure --prefix=/opt/nginx \ - --add-module=/path/to/headers-more-nginx-module - - make - make install -``` - -Download the latest version of the release tarball of this module from [headers-more-nginx-module file list](https://github.com/openresty/headers-more-nginx-module/tags). - -Starting from NGINX 1.9.11, you can also compile this module as a dynamic module, by using the `--add-dynamic-module=PATH` option instead of `--add-module=PATH` on the -`./configure` command line above. And then you can explicitly load the module in your `nginx.conf` via the [load_module](http://nginx.org/en/docs/ngx_core_module.html#load_module) -directive, for example, - -```nginx -load_module /path/to/modules/ngx_http_headers_more_filter_module.so; -``` - -Also, this module is included and enabled by default in the [OpenResty bundle](http://openresty.org). - -[Back to TOC](#table-of-contents) - -Compatibility -============= - -The following versions of Nginx should work with this module: - -* **1.13.x** (last tested: 1.13.6) -* **1.12.x** -* **1.11.x** (last tested: 1.11.2) -* **1.10.x** -* **1.9.x** (last tested: 1.9.15) -* **1.8.x** -* **1.7.x** (last tested: 1.7.10) -* **1.6.x** (last tested: 1.6.2) -* **1.5.x** (last tested: 1.5.8) -* **1.4.x** (last tested: 1.4.4) -* **1.3.x** (last tested: 1.3.7) -* **1.2.x** (last tested: 1.2.9) -* **1.1.x** (last tested: 1.1.5) -* **1.0.x** (last tested: 1.0.11) -* **0.9.x** (last tested: 0.9.4) -* **0.8.x** (last tested: 0.8.54) -* **0.7.x >= 0.7.44** (last tested: 0.7.68) - -Earlier versions of Nginx like 0.6.x and 0.5.x will *not* work. - -If you find that any particular version of Nginx above 0.7.44 does not work with this module, please consider [reporting a bug](#report-bugs). - -[Back to TOC](#table-of-contents) - -Community -========= - -[Back to TOC](#table-of-contents) - -English Mailing List --------------------- - -The [openresty-en](https://groups.google.com/group/openresty-en) mailing list is for English speakers. - -[Back to TOC](#table-of-contents) - -Chinese Mailing List --------------------- - -The [openresty](https://groups.google.com/group/openresty) mailing list is for Chinese speakers. - -[Back to TOC](#table-of-contents) - -Bugs and Patches -================ - -Please submit bug reports, wishlists, or patches by - -1. creating a ticket on the [GitHub Issue Tracker](https://github.com/chaoslawful/lua-nginx-module/issues), -1. or posting to the [OpenResty community](#community). - -[Back to TOC](#table-of-contents) - -Source Repository -================= - -Available on github at [openresty/headers-more-nginx-module](https://github.com/openresty/headers-more-nginx-module). - -[Back to TOC](#table-of-contents) - -Changes -======= - -The changes of every release of this module can be obtained from the OpenResty bundle's change logs: - - - -[Back to TOC](#table-of-contents) - -Test Suite -========== - -This module comes with a Perl-driven test suite. The [test cases](https://github.com/openresty/headers-more-nginx-module/tree/master/t/) are -[declarative](https://github.com/openresty/headers-more-nginx-module/blob/master/t/sanity.t) too. Thanks to the [Test::Nginx](http://search.cpan.org/perldoc?Test::Nginx) module in the Perl world. - -To run it on your side: - -```bash - - $ PATH=/path/to/your/nginx-with-headers-more-module:$PATH prove -r t -``` - -To run the test suite with valgrind's memcheck, use the following commands: - -```bash - - $ export PATH=/path/to/your/nginx-with-headers-more-module:$PATH - $ TEST_NGINX_USE_VALGRIND=1 prove -r t -``` - -You need to terminate any Nginx processes before running the test suite if you have changed the Nginx server binary. - -Because a single nginx server (by default, `localhost:1984`) is used across all the test scripts (`.t` files), it's meaningless to run the test suite in parallel by specifying `-jN` when invoking the `prove` utility. - -Some parts of the test suite requires modules [proxy](http://nginx.org/en/docs/http/ngx_http_proxy_module.html), [rewrite](http://nginx.org/en/docs/http/ngx_http_rewrite_module.html), and [echo](https://github.com/openresty/echo-nginx-module) to be enabled as well when building Nginx. - -[Back to TOC](#table-of-contents) - -TODO -==== - -* Support variables in new headers' keys. - -[Back to TOC](#table-of-contents) - -Getting involved -================ - -You'll be very welcomed to submit patches to the [author](#author) or just ask for a commit bit to the [source repository](#source-repository) on GitHub. - -[Back to TOC](#table-of-contents) - -Authors -======= - -* Yichun "agentzh" Zhang (章亦春) *<agentzh@gmail.com>*, OpenResty Inc. -* Bernd Dorn ( ) - -This wiki page is also maintained by the author himself, and everybody is encouraged to improve this page as well. - -[Back to TOC](#table-of-contents) - -Copyright & License -=================== - -The code base is borrowed directly from the standard [headers](http://nginx.org/en/docs/http/ngx_http_headers_module.html) module in Nginx 0.8.24. This part of code is copyrighted by Igor Sysoev. - -Copyright (c) 2009-2017, Yichun "agentzh" Zhang (章亦春) , OpenResty Inc. - -Copyright (c) 2010-2013, Bernd Dorn. - -This module is licensed under the terms of the BSD license. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - -* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -[Back to TOC](#table-of-contents) - -See Also -======== - -* The original thread on the Nginx mailing list that inspires this module's development: ["A question about add_header replication"](http://forum.nginx.org/read.php?2,11206,11738). -* The orginal announcement thread on the Nginx mailing list: ["The "headers_more" module: Set and clear output headers...more than 'add'!"](http://forum.nginx.org/read.php?2,23460). -* The original [blog post](http://agentzh.blogspot.com/2009/11/headers-more-module-scripting-input-and.html) about this module's initial development. -* The [echo module](https://github.com/openresty/echo-nginx-module) for Nginx module's automated testing. -* The standard [headers](http://nginx.org/en/docs/http/ngx_http_headers_module.html) module. - -[Back to TOC](#table-of-contents) - diff --git a/debian/modules/http-headers-more-filter/config b/debian/modules/http-headers-more-filter/config deleted file mode 100644 index 5707cc4..0000000 --- a/debian/modules/http-headers-more-filter/config +++ /dev/null @@ -1,32 +0,0 @@ -ngx_addon_name=ngx_http_headers_more_filter_module - -HEADERS_MORE_SRCS=" \ - $ngx_addon_dir/src/ngx_http_headers_more_filter_module.c \ - $ngx_addon_dir/src/ngx_http_headers_more_headers_out.c \ - $ngx_addon_dir/src/ngx_http_headers_more_headers_in.c \ - $ngx_addon_dir/src/ngx_http_headers_more_util.c \ - " - -HEADERS_MORE_DEPS=" \ - $ngx_addon_dir/src/ddebug.h \ - $ngx_addon_dir/src/ngx_http_headers_more_filter_module.h \ - $ngx_addon_dir/src/ngx_http_headers_more_headers_in.h \ - $ngx_addon_dir/src/ngx_http_headers_more_headers_out.h \ - $ngx_addon_dir/src/ngx_http_headers_more_headers_in.h \ - $ngx_addon_dir/src/ngx_http_headers_more_util.h \ - " - -if test -n "$ngx_module_link"; then - ngx_module_type=HTTP_AUX_FILTER - ngx_module_name=$ngx_addon_name - ngx_module_incs= - ngx_module_deps="$HEADERS_MORE_DEPS" - ngx_module_srcs="$HEADERS_MORE_SRCS" - ngx_module_libs= - - . auto/module -else - HTTP_AUX_FILTER_MODULES="$HTTP_AUX_FILTER_MODULES $ngx_addon_name" - NGX_ADDON_SRCS="$NGX_ADDON_SRCS $HEADERS_MORE_SRCS" - NGX_ADDON_DEPS="$NGX_ADDON_DEPS $HEADERS_MORE_DEPS" -fi diff --git a/debian/modules/http-headers-more-filter/src/ddebug.h b/debian/modules/http-headers-more-filter/src/ddebug.h deleted file mode 100644 index 13879af..0000000 --- a/debian/modules/http-headers-more-filter/src/ddebug.h +++ /dev/null @@ -1,124 +0,0 @@ -#ifndef DDEBUG_H -#define DDEBUG_H - - -#include -#include -#include -#include - - -#if defined(DDEBUG) && (DDEBUG) - -# if (NGX_HAVE_VARIADIC_MACROS) - -# define dd(...) fprintf(stderr, "headers-more *** %s: ", __func__); \ - fprintf(stderr, __VA_ARGS__); \ - fprintf(stderr, " at %s line %d.\n", __FILE__, __LINE__) - -# else - -#include -#include - -#include - -static ngx_inline void -dd(const char * fmt, ...) { -} - -# endif - -# if DDEBUG > 1 - -# define dd_enter() dd_enter_helper(r, __func__) - -# if defined(nginx_version) && nginx_version >= 8011 -# define dd_main_req_count r->main->count -# else -# define dd_main_req_count 0 -# endif - -static ngx_inline void -dd_enter_helper(ngx_http_request_t *r, const char *func) -{ - ngx_http_posted_request_t *pr; - - fprintf(stderr, "headers-more *** enter %s %.*s %.*s?%.*s c:%d m:%p r:%p ar:%p pr:%p", - func, - (int) r->method_name.len, r->method_name.data, - (int) r->uri.len, r->uri.data, - (int) r->args.len, r->args.data, - (int) dd_main_req_count, r->main, - r, r->connection->data, r->parent); - - if (r->posted_requests) { - fprintf(stderr, " posted:"); - - for (pr = r->posted_requests; pr; pr = pr->next) { - fprintf(stderr, "%p,", pr); - } - } - - fprintf(stderr, "\n"); -} - -# else - -# define dd_enter() - -# endif - -#else - -# if (NGX_HAVE_VARIADIC_MACROS) - -# define dd(...) - -# define dd_enter() - -# else - -#include - -static ngx_inline void -dd(const char * fmt, ...) { -} - -static ngx_inline void -dd_enter() { -} - -# endif - -#endif - -#if defined(DDEBUG) && (DDEBUG) - -#define dd_check_read_event_handler(r) \ - dd("r->read_event_handler = %s", \ - r->read_event_handler == ngx_http_block_reading ? \ - "ngx_http_block_reading" : \ - r->read_event_handler == ngx_http_test_reading ? \ - "ngx_http_test_reading" : \ - r->read_event_handler == ngx_http_request_empty_handler ? \ - "ngx_http_request_empty_handler" : "UNKNOWN") - -#define dd_check_write_event_handler(r) \ - dd("r->write_event_handler = %s", \ - r->write_event_handler == ngx_http_handler ? \ - "ngx_http_handler" : \ - r->write_event_handler == ngx_http_core_run_phases ? \ - "ngx_http_core_run_phases" : \ - r->write_event_handler == ngx_http_request_empty_handler ? \ - "ngx_http_request_empty_handler" : "UNKNOWN") - -#else - -#define dd_check_read_event_handler(r) -#define dd_check_write_event_handler(r) - -#endif - -#endif /* DDEBUG_H */ - diff --git a/debian/modules/http-headers-more-filter/src/ngx_http_headers_more_filter_module.c b/debian/modules/http-headers-more-filter/src/ngx_http_headers_more_filter_module.c deleted file mode 100644 index 0bb6fec..0000000 --- a/debian/modules/http-headers-more-filter/src/ngx_http_headers_more_filter_module.c +++ /dev/null @@ -1,348 +0,0 @@ - -/* - * Copyright (C) Yichun Zhang (agentzh) - */ - - -#ifndef DDEBUG -#define DDEBUG 0 -#endif -#include "ddebug.h" - - -#include "ngx_http_headers_more_filter_module.h" -#include "ngx_http_headers_more_headers_out.h" -#include "ngx_http_headers_more_headers_in.h" -#include "ngx_http_headers_more_util.h" -#include - - -/* config handlers */ - -static void *ngx_http_headers_more_create_loc_conf(ngx_conf_t *cf); -static char *ngx_http_headers_more_merge_loc_conf(ngx_conf_t *cf, - void *parent, void *child); -static void *ngx_http_headers_more_create_main_conf(ngx_conf_t *cf); -static ngx_int_t ngx_http_headers_more_post_config(ngx_conf_t *cf); - -/* post-read-phase handler */ - -static ngx_int_t ngx_http_headers_more_handler(ngx_http_request_t *r); - -/* filter handlers */ - -static ngx_int_t ngx_http_headers_more_filter_init(ngx_conf_t *cf); - -ngx_uint_t ngx_http_headers_more_location_hash = 0; - - -static ngx_command_t ngx_http_headers_more_filter_commands[] = { - - { ngx_string("more_set_headers"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF - |NGX_CONF_1MORE, - ngx_http_headers_more_set_headers, - NGX_HTTP_LOC_CONF_OFFSET, - 0, - NULL}, - - { ngx_string("more_clear_headers"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF - |NGX_CONF_1MORE, - ngx_http_headers_more_clear_headers, - NGX_HTTP_LOC_CONF_OFFSET, - 0, - NULL}, - - { ngx_string("more_set_input_headers"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF - |NGX_CONF_1MORE, - ngx_http_headers_more_set_input_headers, - NGX_HTTP_LOC_CONF_OFFSET, - 0, - NULL}, - - { ngx_string("more_clear_input_headers"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF - |NGX_CONF_1MORE, - ngx_http_headers_more_clear_input_headers, - NGX_HTTP_LOC_CONF_OFFSET, - 0, - NULL}, - - ngx_null_command -}; - - -static ngx_http_module_t ngx_http_headers_more_filter_module_ctx = { - NULL, /* preconfiguration */ - ngx_http_headers_more_post_config, /* postconfiguration */ - - ngx_http_headers_more_create_main_conf, /* create main configuration */ - NULL, /* init main configuration */ - - NULL, /* create server configuration */ - NULL, /* merge server configuration */ - - ngx_http_headers_more_create_loc_conf, /* create location configuration */ - ngx_http_headers_more_merge_loc_conf /* merge location configuration */ -}; - - -ngx_module_t ngx_http_headers_more_filter_module = { - NGX_MODULE_V1, - &ngx_http_headers_more_filter_module_ctx, /* module context */ - ngx_http_headers_more_filter_commands, /* module directives */ - NGX_HTTP_MODULE, /* module type */ - NULL, /* init master */ - NULL, /* init module */ - NULL, /* init process */ - NULL, /* init thread */ - NULL, /* exit thread */ - NULL, /* exit process */ - NULL, /* exit master */ - NGX_MODULE_V1_PADDING -}; - - -static ngx_http_output_header_filter_pt ngx_http_next_header_filter; - - -static volatile ngx_cycle_t *ngx_http_headers_more_prev_cycle = NULL; - - -static ngx_int_t -ngx_http_headers_more_filter(ngx_http_request_t *r) -{ - ngx_int_t rc; - ngx_uint_t i; - ngx_http_headers_more_loc_conf_t *conf; - ngx_http_headers_more_cmd_t *cmd; - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "headers more header filter, uri \"%V\"", &r->uri); - - conf = ngx_http_get_module_loc_conf(r, ngx_http_headers_more_filter_module); - - if (conf->cmds) { - cmd = conf->cmds->elts; - for (i = 0; i < conf->cmds->nelts; i++) { - if (cmd[i].is_input) { - continue; - } - - rc = ngx_http_headers_more_exec_cmd(r, &cmd[i]); - - if (rc != NGX_OK) { - return rc; - } - } - } - - return ngx_http_next_header_filter(r); -} - - -static ngx_int_t -ngx_http_headers_more_filter_init(ngx_conf_t *cf) -{ - ngx_http_next_header_filter = ngx_http_top_header_filter; - ngx_http_top_header_filter = ngx_http_headers_more_filter; - - return NGX_OK; -} - - -static void * -ngx_http_headers_more_create_loc_conf(ngx_conf_t *cf) -{ - ngx_http_headers_more_loc_conf_t *conf; - - conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_headers_more_loc_conf_t)); - if (conf == NULL) { - return NULL; - } - - /* - * set by ngx_pcalloc(): - * - * conf->cmds = NULL; - */ - - return conf; -} - - -static char * -ngx_http_headers_more_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) -{ - ngx_uint_t i; - ngx_uint_t orig_len; - ngx_http_headers_more_cmd_t *prev_cmd, *cmd; - ngx_http_headers_more_loc_conf_t *prev = parent; - ngx_http_headers_more_loc_conf_t *conf = child; - - if (conf->cmds == NULL || conf->cmds->nelts == 0) { - conf->cmds = prev->cmds; - - } else if (prev->cmds && prev->cmds->nelts) { - orig_len = conf->cmds->nelts; - - (void) ngx_array_push_n(conf->cmds, prev->cmds->nelts); - - cmd = conf->cmds->elts; - - for (i = 0; i < orig_len; i++) { - cmd[conf->cmds->nelts - 1 - i] = cmd[orig_len - 1 - i]; - } - - prev_cmd = prev->cmds->elts; - - for (i = 0; i < prev->cmds->nelts; i++) { - cmd[i] = prev_cmd[i]; - } - } - - return NGX_CONF_OK; -} - - -static ngx_int_t -ngx_http_headers_more_post_config(ngx_conf_t *cf) -{ - int multi_http_blocks; - ngx_int_t rc; - ngx_http_handler_pt *h; - ngx_http_core_main_conf_t *cmcf; - - ngx_http_headers_more_main_conf_t *hmcf; - - ngx_http_headers_more_location_hash = - ngx_http_headers_more_hash_literal("location"); - - hmcf = ngx_http_conf_get_module_main_conf(cf, - ngx_http_headers_more_filter_module); - - if (ngx_http_headers_more_prev_cycle != ngx_cycle) { - ngx_http_headers_more_prev_cycle = ngx_cycle; - multi_http_blocks = 0; - - } else { - multi_http_blocks = 1; - } - - if (multi_http_blocks || hmcf->requires_filter) { - rc = ngx_http_headers_more_filter_init(cf); - if (rc != NGX_OK) { - return rc; - } - } - - if (!hmcf->requires_handler) { - return NGX_OK; - } - - cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); - - h = ngx_array_push(&cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers); - if (h == NULL) { - return NGX_ERROR; - } - - *h = ngx_http_headers_more_handler; - - return NGX_OK; -} - - -static ngx_int_t -ngx_http_headers_more_handler(ngx_http_request_t *r) -{ - ngx_int_t rc; - ngx_uint_t i; - ngx_http_headers_more_loc_conf_t *conf; - ngx_http_headers_more_main_conf_t *hmcf; - ngx_http_headers_more_cmd_t *cmd; - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "headers more rewrite handler, uri \"%V\"", &r->uri); - - hmcf = ngx_http_get_module_main_conf(r, - ngx_http_headers_more_filter_module); - - if (!hmcf->postponed_to_phase_end) { - ngx_http_core_main_conf_t *cmcf; - ngx_http_phase_handler_t tmp; - ngx_http_phase_handler_t *ph; - ngx_http_phase_handler_t *cur_ph; - ngx_http_phase_handler_t *last_ph; - - hmcf->postponed_to_phase_end = 1; - - cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); - - ph = cmcf->phase_engine.handlers; - cur_ph = &ph[r->phase_handler]; - last_ph = &ph[cur_ph->next - 1]; - - if (cur_ph < last_ph) { - dd("swaping the contents of cur_ph and last_ph..."); - - tmp = *cur_ph; - - memmove(cur_ph, cur_ph + 1, - (last_ph - cur_ph) * sizeof (ngx_http_phase_handler_t)); - - *last_ph = tmp; - - r->phase_handler--; /* redo the current ph */ - - return NGX_DECLINED; - } - } - - dd("running phase handler..."); - - conf = ngx_http_get_module_loc_conf(r, ngx_http_headers_more_filter_module); - - if (conf->cmds) { - if (r->http_version < NGX_HTTP_VERSION_10) { - return NGX_DECLINED; - } - - cmd = conf->cmds->elts; - for (i = 0; i < conf->cmds->nelts; i++) { - if (!cmd[i].is_input) { - continue; - } - - rc = ngx_http_headers_more_exec_input_cmd(r, &cmd[i]); - - if (rc != NGX_OK) { - return rc; - } - } - } - - return NGX_DECLINED; -} - - -static void * -ngx_http_headers_more_create_main_conf(ngx_conf_t *cf) -{ - ngx_http_headers_more_main_conf_t *hmcf; - - hmcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_headers_more_main_conf_t)); - if (hmcf == NULL) { - return NULL; - } - - /* set by ngx_pcalloc: - * hmcf->postponed_to_phase_end = 0; - * hmcf->requires_filter = 0; - * hmcf->requires_handler = 0; - */ - - return hmcf; -} diff --git a/debian/modules/http-headers-more-filter/src/ngx_http_headers_more_filter_module.h b/debian/modules/http-headers-more-filter/src/ngx_http_headers_more_filter_module.h deleted file mode 100644 index 72a5317..0000000 --- a/debian/modules/http-headers-more-filter/src/ngx_http_headers_more_filter_module.h +++ /dev/null @@ -1,80 +0,0 @@ - -/* - * Copyright (c) Yichun Zhang (agentzh) - */ - - -#ifndef NGX_HTTP_HEADERS_MORE_FILTER_MODULE_H -#define NGX_HTTP_HEADERS_MORE_FILTER_MODULE_H - - -#include -#include -#include - - -typedef enum { - ngx_http_headers_more_opcode_set, - ngx_http_headers_more_opcode_clear -} ngx_http_headers_more_opcode_t; - - -typedef struct { - ngx_array_t *types; /* of ngx_str_t */ - ngx_array_t *statuses; /* of ngx_uint_t */ - ngx_array_t *headers; /* of ngx_http_header_val_t */ - ngx_flag_t is_input; -} ngx_http_headers_more_cmd_t; - - -typedef struct { - ngx_array_t *cmds; /* of ngx_http_headers_more_cmd_t */ -} ngx_http_headers_more_loc_conf_t; - - -typedef struct { - ngx_int_t postponed_to_phase_end; - ngx_int_t requires_filter; - ngx_int_t requires_handler; -} ngx_http_headers_more_main_conf_t; - - -typedef struct ngx_http_headers_more_header_val_s - ngx_http_headers_more_header_val_t; - - -typedef ngx_int_t (*ngx_http_headers_more_set_header_pt)(ngx_http_request_t *r, - ngx_http_headers_more_header_val_t *hv, ngx_str_t *value); - - -typedef struct { - ngx_str_t name; - ngx_uint_t offset; - ngx_http_headers_more_set_header_pt handler; -} ngx_http_headers_more_set_header_t; - - -struct ngx_http_headers_more_header_val_s { - ngx_http_complex_value_t value; - ngx_uint_t hash; - ngx_str_t key; - ngx_http_headers_more_set_header_pt handler; - ngx_uint_t offset; - ngx_flag_t replace; - ngx_flag_t wildcard; -}; - - -extern ngx_module_t ngx_http_headers_more_filter_module; - - -#ifndef ngx_str_set -#define ngx_str_set(str, text) \ - (str)->len = sizeof(text) - 1; (str)->data = (u_char *) text -#endif - - -#define ngx_http_headers_more_assert(a) assert(a) - - -#endif /* NGX_HTTP_HEADERS_MORE_FILTER_MODULE_H */ diff --git a/debian/modules/http-headers-more-filter/src/ngx_http_headers_more_headers_in.c b/debian/modules/http-headers-more-filter/src/ngx_http_headers_more_headers_in.c deleted file mode 100644 index c3eb8f7..0000000 --- a/debian/modules/http-headers-more-filter/src/ngx_http_headers_more_headers_in.c +++ /dev/null @@ -1,899 +0,0 @@ - -/* - * Copyright (C) Yichun Zhang (agentzh) - */ - - -#ifndef DDEBUG -#define DDEBUG 0 -#endif -#include "ddebug.h" - - -#include "ngx_http_headers_more_headers_in.h" -#include "ngx_http_headers_more_util.h" -#include - - -static char *ngx_http_headers_more_parse_directive(ngx_conf_t *cf, - ngx_command_t *ngx_cmd, void *conf, - ngx_http_headers_more_opcode_t opcode); -static int ngx_http_headers_more_check_type(ngx_http_request_t *r, - ngx_array_t *types); -static ngx_int_t ngx_http_set_header(ngx_http_request_t *r, - ngx_http_headers_more_header_val_t *hv, ngx_str_t *value); -static ngx_int_t ngx_http_set_header_helper(ngx_http_request_t *r, - ngx_http_headers_more_header_val_t *hv, ngx_str_t *value, - ngx_table_elt_t **output_header); -static ngx_int_t ngx_http_set_builtin_header(ngx_http_request_t *r, - ngx_http_headers_more_header_val_t *hv, ngx_str_t *value); -static ngx_int_t ngx_http_set_user_agent_header(ngx_http_request_t *r, - ngx_http_headers_more_header_val_t *hv, ngx_str_t *value); -static ngx_int_t ngx_http_set_content_length_header(ngx_http_request_t *r, - ngx_http_headers_more_header_val_t *hv, ngx_str_t *value); -static ngx_int_t ngx_http_clear_builtin_header(ngx_http_request_t *r, - ngx_http_headers_more_header_val_t *hv, ngx_str_t *value); -static ngx_int_t ngx_http_clear_content_length_header(ngx_http_request_t *r, - ngx_http_headers_more_header_val_t *hv, ngx_str_t *value); -static ngx_int_t ngx_http_set_host_header(ngx_http_request_t *r, - ngx_http_headers_more_header_val_t *hv, ngx_str_t *value); -static ngx_int_t ngx_http_set_connection_header(ngx_http_request_t *r, - ngx_http_headers_more_header_val_t *hv, ngx_str_t *value); -static ngx_int_t ngx_http_set_builtin_multi_header(ngx_http_request_t *r, - ngx_http_headers_more_header_val_t *hv, ngx_str_t *value); -static ngx_int_t ngx_http_headers_more_validate_host(ngx_str_t *host, - ngx_pool_t *pool, ngx_uint_t alloc); - - -static ngx_http_headers_more_set_header_t ngx_http_headers_more_set_handlers[] - = { - - { ngx_string("Host"), - offsetof(ngx_http_headers_in_t, host), - ngx_http_set_host_header }, - - { ngx_string("Connection"), - offsetof(ngx_http_headers_in_t, connection), - ngx_http_set_connection_header }, - - { ngx_string("If-Modified-Since"), - offsetof(ngx_http_headers_in_t, if_modified_since), - ngx_http_set_builtin_header }, - -#if defined(nginx_version) && nginx_version >= 9002 - { ngx_string("If-Unmodified-Since"), - offsetof(ngx_http_headers_in_t, if_unmodified_since), - ngx_http_set_builtin_header }, -#endif - -#if defined(nginx_version) && nginx_version >= 1003003 - { ngx_string("If-Match"), - offsetof(ngx_http_headers_in_t, if_match), - ngx_http_set_builtin_header }, - - { ngx_string("If-None-Match"), - offsetof(ngx_http_headers_in_t, if_none_match), - ngx_http_set_builtin_header }, -#endif - - { ngx_string("User-Agent"), - offsetof(ngx_http_headers_in_t, user_agent), - ngx_http_set_user_agent_header }, - - { ngx_string("Referer"), - offsetof(ngx_http_headers_in_t, referer), - ngx_http_set_builtin_header }, - - { ngx_string("Content-Length"), - offsetof(ngx_http_headers_in_t, content_length), - ngx_http_set_content_length_header }, - - { ngx_string("Content-Type"), - offsetof(ngx_http_headers_in_t, content_type), - ngx_http_set_builtin_header }, - - { ngx_string("Range"), - offsetof(ngx_http_headers_in_t, range), - ngx_http_set_builtin_header }, - - { ngx_string("If-Range"), - offsetof(ngx_http_headers_in_t, if_range), - ngx_http_set_builtin_header }, - - { ngx_string("Transfer-Encoding"), - offsetof(ngx_http_headers_in_t, transfer_encoding), - ngx_http_set_builtin_header }, - - { ngx_string("Expect"), - offsetof(ngx_http_headers_in_t, expect), - ngx_http_set_builtin_header }, - -#if defined(nginx_version) && nginx_version >= 1003013 - { ngx_string("Upgrade"), - offsetof(ngx_http_headers_in_t, upgrade), - ngx_http_set_builtin_header }, -#endif - -#if (NGX_HTTP_GZIP) - { ngx_string("Accept-Encoding"), - offsetof(ngx_http_headers_in_t, accept_encoding), - ngx_http_set_builtin_header }, - - { ngx_string("Via"), offsetof(ngx_http_headers_in_t, via), - ngx_http_set_builtin_header }, -#endif - - { ngx_string("Authorization"), - offsetof(ngx_http_headers_in_t, authorization), - ngx_http_set_builtin_header }, - - { ngx_string("Keep-Alive"), - offsetof(ngx_http_headers_in_t, keep_alive), - ngx_http_set_builtin_header }, - -#if (NGX_HTTP_X_FORWARDED_FOR) - { ngx_string("X-Forwarded-For"), - offsetof(ngx_http_headers_in_t, x_forwarded_for), - ngx_http_set_builtin_multi_header }, - -#endif - -#if (NGX_HTTP_REALIP) - { ngx_string("X-Real-IP"), - offsetof(ngx_http_headers_in_t, x_real_ip), - ngx_http_set_builtin_header }, -#endif - -#if (NGX_HTTP_DAV) - { ngx_string("Depth"), offsetof(ngx_http_headers_in_t, depth), - ngx_http_set_builtin_header }, - - { ngx_string("Destination"), offsetof(ngx_http_headers_in_t, destination), - ngx_http_set_builtin_header }, - - { ngx_string("Overwrite"), offsetof(ngx_http_headers_in_t, overwrite), - ngx_http_set_builtin_header }, - - { ngx_string("Date"), offsetof(ngx_http_headers_in_t, date), - ngx_http_set_builtin_header }, -#endif - - { ngx_string("Cookie"), - offsetof(ngx_http_headers_in_t, cookies), - ngx_http_set_builtin_multi_header }, - - { ngx_null_string, 0, ngx_http_set_header } -}; - - -ngx_int_t -ngx_http_headers_more_exec_input_cmd(ngx_http_request_t *r, - ngx_http_headers_more_cmd_t *cmd) -{ - ngx_str_t value; - ngx_http_headers_more_header_val_t *h; - ngx_uint_t i; - - if (!cmd->headers) { - return NGX_OK; - } - - if (cmd->types && !ngx_http_headers_more_check_type(r, cmd->types)) { - return NGX_OK; - } - - h = cmd->headers->elts; - for (i = 0; i < cmd->headers->nelts; i++) { - - if (ngx_http_complex_value(r, &h[i].value, &value) != NGX_OK) { - return NGX_ERROR; - } - - if (value.len) { - value.len--; /* remove the trailing '\0' added by - ngx_http_headers_more_parse_header */ - } - - if (h[i].handler(r, &h[i], &value) != NGX_OK) { - return NGX_ERROR; - } - } - - return NGX_OK; -} - - -static ngx_int_t -ngx_http_set_header(ngx_http_request_t *r, - ngx_http_headers_more_header_val_t *hv, ngx_str_t *value) -{ - return ngx_http_set_header_helper(r, hv, value, NULL); -} - - -static ngx_int_t -ngx_http_set_header_helper(ngx_http_request_t *r, - ngx_http_headers_more_header_val_t *hv, ngx_str_t *value, - ngx_table_elt_t **output_header) -{ - ngx_table_elt_t *h, *matched; - ngx_list_part_t *part; - ngx_uint_t i; - ngx_uint_t rc; - - dd_enter(); - - matched = NULL; - -retry: - - part = &r->headers_in.headers.part; - h = part->elts; - - for (i = 0; /* void */; i++) { - dd("i: %d, part: %p", (int) i, part); - - if (i >= part->nelts) { - if (part->next == NULL) { - break; - } - - part = part->next; - h = part->elts; - i = 0; - } - - if (!hv->wildcard - && h[i].key.len == hv->key.len - && ngx_strncasecmp(h[i].key.data, hv->key.data, - h[i].key.len) == 0) - { - goto matched; - } - - if (hv->wildcard - && value->len == 0 - && h[i].key.len >= hv->key.len - 1 - && ngx_strncasecmp(h[i].key.data, hv->key.data, - hv->key.len - 1) == 0) - { - goto matched; - } - - /* not matched */ - continue; - -matched: - - if (value->len == 0 || (matched && matched != &h[i])) { - h[i].hash = 0; - - rc = ngx_http_headers_more_rm_header_helper( - &r->headers_in.headers, part, i); - - ngx_http_headers_more_assert( - !(r->headers_in.headers.part.next == NULL - && r->headers_in.headers.last - != &r->headers_in.headers.part)); - - if (rc == NGX_OK) { - if (output_header) { - *output_header = NULL; - } - - goto retry; - } - - return NGX_ERROR; - } - - h[i].value = *value; - - if (output_header) { - *output_header = &h[i]; - dd("setting existing builtin input header"); - } - - if (matched == NULL) { - matched = &h[i]; - } - } - - if (matched) { - return NGX_OK; - } - - if (value->len == 0 || hv->replace) { - return NGX_OK; - } - - if (r->headers_in.headers.last == NULL) { - /* must be 400 bad request */ - return NGX_OK; - } - - h = ngx_list_push(&r->headers_in.headers); - - if (h == NULL) { - return NGX_ERROR; - } - - dd("created new header for %.*s", (int) hv->key.len, hv->key.data); - - if (value->len == 0) { - h->hash = 0; - - } else { - h->hash = hv->hash; - } - - h->key = hv->key; - h->value = *value; - - h->lowcase_key = ngx_pnalloc(r->pool, h->key.len); - if (h->lowcase_key == NULL) { - return NGX_ERROR; - } - - ngx_strlow(h->lowcase_key, h->key.data, h->key.len); - - if (output_header) { - *output_header = h; - - while (r != r->main) { - r->parent->headers_in = r->headers_in; - r = r->parent; - } - } - - return NGX_OK; -} - - -static ngx_int_t -ngx_http_set_builtin_header(ngx_http_request_t *r, - ngx_http_headers_more_header_val_t *hv, ngx_str_t *value) -{ - ngx_table_elt_t *h, **old; - - dd("entered set_builtin_header (input)"); - - if (hv->offset) { - old = (ngx_table_elt_t **) ((char *) &r->headers_in + hv->offset); - - } else { - old = NULL; - } - - dd("old builtin ptr ptr: %p", old); - if (old) { - dd("old builtin ptr: %p", *old); - } - - if (old == NULL || *old == NULL) { - dd("set normal header"); - return ngx_http_set_header_helper(r, hv, value, old); - } - - h = *old; - - if (value->len == 0) { - h->hash = 0; - h->value = *value; - - return ngx_http_set_header_helper(r, hv, value, old); - } - - h->hash = hv->hash; - h->value = *value; - - return NGX_OK; -} - - -static ngx_int_t -ngx_http_set_host_header(ngx_http_request_t *r, - ngx_http_headers_more_header_val_t *hv, ngx_str_t *value) -{ - ngx_str_t host; - - if (value->len) { - host= *value; - - if (ngx_http_headers_more_validate_host(&host, r->pool, 0) != NGX_OK) { - return NGX_ERROR; - } - - r->headers_in.server = host; - - } else { - r->headers_in.server = *value; - } - - return ngx_http_set_builtin_header(r, hv, value); -} - - -static ngx_int_t -ngx_http_set_content_length_header(ngx_http_request_t *r, - ngx_http_headers_more_header_val_t *hv, ngx_str_t *value) -{ - off_t len; - - if (value->len == 0) { - return ngx_http_clear_content_length_header(r, hv, value); - } - - len = ngx_atosz(value->data, value->len); - if (len == NGX_ERROR) { - return NGX_ERROR; - } - - dd("reset headers_in.content_length_n to %d", (int) len); - - r->headers_in.content_length_n = len; - - return ngx_http_set_builtin_header(r, hv, value); -} - - -static ngx_int_t -ngx_http_clear_content_length_header(ngx_http_request_t *r, - ngx_http_headers_more_header_val_t *hv, ngx_str_t *value) -{ - r->headers_in.content_length_n = -1; - - return ngx_http_clear_builtin_header(r, hv, value); -} - - -static ngx_int_t -ngx_http_clear_builtin_header(ngx_http_request_t *r, - ngx_http_headers_more_header_val_t *hv, ngx_str_t *value) -{ - value->len = 0; - return ngx_http_set_builtin_header(r, hv, value); -} - - -char * -ngx_http_headers_more_set_input_headers(ngx_conf_t *cf, - ngx_command_t *cmd, void *conf) -{ - return ngx_http_headers_more_parse_directive(cf, cmd, conf, - ngx_http_headers_more_opcode_set); -} - - -char * -ngx_http_headers_more_clear_input_headers(ngx_conf_t *cf, - ngx_command_t *cmd, void *conf) -{ - return ngx_http_headers_more_parse_directive(cf, cmd, conf, - ngx_http_headers_more_opcode_clear); -} - - -static int -ngx_http_headers_more_check_type(ngx_http_request_t *r, ngx_array_t *types) -{ - ngx_uint_t i; - ngx_str_t *t; - ngx_str_t actual_type; - - if (r->headers_in.content_type == NULL) { - return 0; - } - - actual_type = r->headers_in.content_type->value; - if (actual_type.len == 0) { - return 0; - } - - dd("headers_in->content_type: %.*s", - (int) actual_type.len, - actual_type.data); - - t = types->elts; - for (i = 0; i < types->nelts; i++) { - dd("...comparing with type [%.*s]", (int) t[i].len, t[i].data); - - if (actual_type.len == t[i].len - && ngx_strncmp(actual_type.data, t[i].data, t[i].len) == 0) - { - return 1; - } - } - - return 0; -} - - -static char * -ngx_http_headers_more_parse_directive(ngx_conf_t *cf, ngx_command_t *ngx_cmd, - void *conf, ngx_http_headers_more_opcode_t opcode) -{ - ngx_http_headers_more_loc_conf_t *hlcf = conf; - - ngx_uint_t i; - ngx_http_headers_more_cmd_t *cmd; - ngx_str_t *arg; - ngx_flag_t ignore_next_arg; - ngx_str_t *cmd_name; - ngx_int_t rc; - ngx_flag_t replace = 0; - ngx_http_headers_more_header_val_t *h; - - ngx_http_headers_more_main_conf_t *hmcf; - - if (hlcf->cmds == NULL) { - hlcf->cmds = ngx_array_create(cf->pool, 1, - sizeof(ngx_http_headers_more_cmd_t)); - - if (hlcf->cmds == NULL) { - return NGX_CONF_ERROR; - } - } - - cmd = ngx_array_push(hlcf->cmds); - - if (cmd == NULL) { - return NGX_CONF_ERROR; - } - - cmd->headers = ngx_array_create(cf->pool, 1, - sizeof(ngx_http_headers_more_header_val_t)); - - if (cmd->headers == NULL) { - return NGX_CONF_ERROR; - } - - cmd->types = ngx_array_create(cf->pool, 1, sizeof(ngx_str_t)); - if (cmd->types == NULL) { - return NGX_CONF_ERROR; - } - - cmd->statuses = NULL; - - arg = cf->args->elts; - - cmd_name = &arg[0]; - - ignore_next_arg = 0; - - for (i = 1; i < cf->args->nelts; i++) { - if (ignore_next_arg) { - ignore_next_arg = 0; - continue; - } - - if (arg[i].len == 0) { - continue; - } - - if (arg[i].data[0] != '-') { - rc = ngx_http_headers_more_parse_header(cf, cmd_name, - &arg[i], cmd->headers, - opcode, - ngx_http_headers_more_set_handlers); - - if (rc != NGX_OK) { - return NGX_CONF_ERROR; - } - - continue; - } - - if (arg[i].len == 2) { - if (arg[i].data[1] == 't') { - if (i == cf->args->nelts - 1) { - ngx_log_error(NGX_LOG_ERR, cf->log, 0, - "%V: option -t takes an argument.", - cmd_name); - - return NGX_CONF_ERROR; - } - - rc = ngx_http_headers_more_parse_types(cf->log, cmd_name, - &arg[i + 1], - cmd->types); - - if (rc != NGX_OK) { - return NGX_CONF_ERROR; - } - - ignore_next_arg = 1; - - continue; - } - - if (arg[i].data[1] == 'r') { - dd("Found replace flag"); - replace = 1; - continue; - } - } - - ngx_log_error(NGX_LOG_ERR, cf->log, 0, - "%V: invalid option name: \"%V\"", cmd_name, &arg[i]); - - return NGX_CONF_ERROR; - } - - dd("Found %d types, and %d headers", - (int) cmd->types->nelts, - (int) cmd->headers->nelts); - - if (cmd->headers->nelts == 0) { - ngx_pfree(cf->pool, cmd->headers); - cmd->headers = NULL; - - } else { - h = cmd->headers->elts; - for (i = 0; i < cmd->headers->nelts; i++) { - h[i].replace = replace; - } - } - - if (cmd->types->nelts == 0) { - ngx_pfree(cf->pool, cmd->types); - cmd->types = NULL; - } - - cmd->is_input = 1; - - hmcf = ngx_http_conf_get_module_main_conf(cf, - ngx_http_headers_more_filter_module); - - hmcf->requires_handler = 1; - - return NGX_CONF_OK; -} - - -/* borrowed the code from ngx_http_request.c:ngx_http_process_user_agent */ -static ngx_int_t -ngx_http_set_user_agent_header(ngx_http_request_t *r, - ngx_http_headers_more_header_val_t *hv, ngx_str_t *value) -{ - u_char *user_agent, *msie; - - /* clear existing settings */ - - r->headers_in.msie = 0; - r->headers_in.msie6 = 0; - r->headers_in.opera = 0; - r->headers_in.gecko = 0; - r->headers_in.chrome = 0; - r->headers_in.safari = 0; - r->headers_in.konqueror = 0; - - if (value->len == 0) { - return ngx_http_set_builtin_header(r, hv, value); - } - - /* check some widespread browsers */ - - user_agent = value->data; - - msie = ngx_strstrn(user_agent, "MSIE ", 5 - 1); - - if (msie && msie + 7 < user_agent + value->len) { - - r->headers_in.msie = 1; - - if (msie[6] == '.') { - - switch (msie[5]) { - case '4': - case '5': - r->headers_in.msie6 = 1; - break; - case '6': - if (ngx_strstrn(msie + 8, "SV1", 3 - 1) == NULL) { - r->headers_in.msie6 = 1; - } - break; - } - } - } - - if (ngx_strstrn(user_agent, "Opera", 5 - 1)) { - r->headers_in.opera = 1; - r->headers_in.msie = 0; - r->headers_in.msie6 = 0; - } - - if (!r->headers_in.msie && !r->headers_in.opera) { - - if (ngx_strstrn(user_agent, "Gecko/", 6 - 1)) { - r->headers_in.gecko = 1; - - } else if (ngx_strstrn(user_agent, "Chrome/", 7 - 1)) { - r->headers_in.chrome = 1; - - } else if (ngx_strstrn(user_agent, "Safari/", 7 - 1) - && ngx_strstrn(user_agent, "Mac OS X", 8 - 1)) - { - r->headers_in.safari = 1; - - } else if (ngx_strstrn(user_agent, "Konqueror", 9 - 1)) { - r->headers_in.konqueror = 1; - } - } - - return ngx_http_set_builtin_header(r, hv, value); -} - - -static ngx_int_t -ngx_http_set_connection_header(ngx_http_request_t *r, - ngx_http_headers_more_header_val_t *hv, ngx_str_t *value) -{ - r->headers_in.connection_type = 0; - - if (value->len == 0) { - return ngx_http_set_builtin_header(r, hv, value); - } - - if (ngx_strcasestrn(value->data, "close", 5 - 1)) { - r->headers_in.connection_type = NGX_HTTP_CONNECTION_CLOSE; - r->headers_in.keep_alive_n = -1; - - } else if (ngx_strcasestrn(value->data, "keep-alive", 10 - 1)) { - r->headers_in.connection_type = NGX_HTTP_CONNECTION_KEEP_ALIVE; - } - - return ngx_http_set_builtin_header(r, hv, value); -} - - -static ngx_int_t -ngx_http_set_builtin_multi_header(ngx_http_request_t *r, - ngx_http_headers_more_header_val_t *hv, ngx_str_t *value) -{ - ngx_array_t *headers; - ngx_table_elt_t **v, *h; - - if (r->headers_out.status == 400 || r->headers_in.headers.last == NULL) { - /* must be a 400 Bad Request */ - return NGX_OK; - } - - headers = (ngx_array_t *) ((char *) &r->headers_in + hv->offset); - - if (headers->nelts > 0) { - ngx_array_destroy(headers); - - if (ngx_array_init(headers, r->pool, 2, - sizeof(ngx_table_elt_t *)) - != NGX_OK) - { - return NGX_ERROR; - } - - dd("clear multi-value headers: %d", (int) headers->nelts); - } - -#if 1 - if (headers->nalloc == 0) { - if (ngx_array_init(headers, r->pool, 2, - sizeof(ngx_table_elt_t *)) - != NGX_OK) - { - return NGX_ERROR; - } - } -#endif - - h = NULL; - if (ngx_http_set_header_helper(r, hv, value, &h) == NGX_ERROR) { - return NGX_ERROR; - } - - if (value->len == 0) { - return NGX_OK; - } - - dd("new cookie header: %p", h); - - v = ngx_array_push(headers); - if (v == NULL) { - return NGX_ERROR; - } - - *v = h; - return NGX_OK; -} - - -static ngx_int_t -ngx_http_headers_more_validate_host(ngx_str_t *host, ngx_pool_t *pool, - ngx_uint_t alloc) -{ - u_char *h, ch; - size_t i, dot_pos, host_len; - - enum { - sw_usual = 0, - sw_literal, - sw_rest - } state; - - dot_pos = host->len; - host_len = host->len; - - h = host->data; - - state = sw_usual; - - for (i = 0; i < host->len; i++) { - ch = h[i]; - - switch (ch) { - - case '.': - if (dot_pos == i - 1) { - return NGX_DECLINED; - } - dot_pos = i; - break; - - case ':': - if (state == sw_usual) { - host_len = i; - state = sw_rest; - } - break; - - case '[': - if (i == 0) { - state = sw_literal; - } - break; - - case ']': - if (state == sw_literal) { - host_len = i + 1; - state = sw_rest; - } - break; - - case '\0': - return NGX_DECLINED; - - default: - - if (ngx_path_separator(ch)) { - return NGX_DECLINED; - } - - if (ch >= 'A' && ch <= 'Z') { - alloc = 1; - } - - break; - } - } - - if (dot_pos == host_len - 1) { - host_len--; - } - - if (host_len == 0) { - return NGX_DECLINED; - } - - if (alloc) { - host->data = ngx_pnalloc(pool, host_len); - if (host->data == NULL) { - return NGX_ERROR; - } - - ngx_strlow(host->data, h, host_len); - } - - host->len = host_len; - - return NGX_OK; -} diff --git a/debian/modules/http-headers-more-filter/src/ngx_http_headers_more_headers_in.h b/debian/modules/http-headers-more-filter/src/ngx_http_headers_more_headers_in.h deleted file mode 100644 index d2251da..0000000 --- a/debian/modules/http-headers-more-filter/src/ngx_http_headers_more_headers_in.h +++ /dev/null @@ -1,26 +0,0 @@ - -/* - * Copyright (c) Yichun Zhang (agentzh) - */ - - -#ifndef NGX_HTTP_HEADERS_MORE_INPUT_HEADERS_H -#define NGX_HTTP_HEADERS_MORE_INPUT_HEADERS_H - - -#include "ngx_http_headers_more_filter_module.h" - - -/* output header setters and clearers */ - -ngx_int_t ngx_http_headers_more_exec_input_cmd(ngx_http_request_t *r, - ngx_http_headers_more_cmd_t *cmd); - -char *ngx_http_headers_more_set_input_headers(ngx_conf_t *cf, - ngx_command_t *cmd, void *conf); - -char *ngx_http_headers_more_clear_input_headers(ngx_conf_t *cf, - ngx_command_t *cmd, void *conf); - - -#endif /* NGX_HTTP_HEADERS_MORE_INPUT_HEADERS_H */ diff --git a/debian/modules/http-headers-more-filter/src/ngx_http_headers_more_headers_out.c b/debian/modules/http-headers-more-filter/src/ngx_http_headers_more_headers_out.c deleted file mode 100644 index 0f9bc87..0000000 --- a/debian/modules/http-headers-more-filter/src/ngx_http_headers_more_headers_out.c +++ /dev/null @@ -1,716 +0,0 @@ - -/* - * Copyright (C) Yichun Zhang (agentzh) - */ - - -#ifndef DDEBUG -#define DDEBUG 0 -#endif -#include "ddebug.h" - - -#include "ngx_http_headers_more_headers_out.h" -#include "ngx_http_headers_more_util.h" -#include - - -static char * -ngx_http_headers_more_parse_directive(ngx_conf_t *cf, ngx_command_t *ngx_cmd, - void *conf, ngx_http_headers_more_opcode_t opcode); -static ngx_flag_t ngx_http_headers_more_check_type(ngx_http_request_t *r, - ngx_array_t *types); -static ngx_flag_t ngx_http_headers_more_check_status(ngx_http_request_t *r, - ngx_array_t *statuses); -static ngx_int_t ngx_http_set_header(ngx_http_request_t *r, - ngx_http_headers_more_header_val_t *hv, ngx_str_t *value); -static ngx_int_t ngx_http_set_header_helper(ngx_http_request_t *r, - ngx_http_headers_more_header_val_t *hv, ngx_str_t *value, - ngx_table_elt_t **output_header, ngx_flag_t no_create); -static ngx_int_t ngx_http_set_builtin_header(ngx_http_request_t *r, - ngx_http_headers_more_header_val_t *hv, ngx_str_t *value); -static ngx_int_t ngx_http_set_accept_ranges_header(ngx_http_request_t *r, - ngx_http_headers_more_header_val_t *hv, ngx_str_t *value); -static ngx_int_t ngx_http_set_content_length_header(ngx_http_request_t *r, - ngx_http_headers_more_header_val_t *hv, ngx_str_t *value); -static ngx_int_t ngx_http_set_content_type_header(ngx_http_request_t *r, - ngx_http_headers_more_header_val_t *hv, ngx_str_t *value); -static ngx_int_t ngx_http_clear_builtin_header(ngx_http_request_t *r, - ngx_http_headers_more_header_val_t *hv, ngx_str_t *value); -static ngx_int_t ngx_http_clear_content_length_header(ngx_http_request_t *r, - ngx_http_headers_more_header_val_t *hv, ngx_str_t *value); -static ngx_int_t ngx_http_set_builtin_multi_header(ngx_http_request_t *r, - ngx_http_headers_more_header_val_t *hv, ngx_str_t *value); - - -static ngx_http_headers_more_set_header_t ngx_http_headers_more_set_handlers[] - = { - - { ngx_string("Server"), - offsetof(ngx_http_headers_out_t, server), - ngx_http_set_builtin_header }, - - { ngx_string("Date"), - offsetof(ngx_http_headers_out_t, date), - ngx_http_set_builtin_header }, - - { ngx_string("Content-Encoding"), - offsetof(ngx_http_headers_out_t, content_encoding), - ngx_http_set_builtin_header }, - - { ngx_string("Location"), - offsetof(ngx_http_headers_out_t, location), - ngx_http_set_builtin_header }, - - { ngx_string("Refresh"), - offsetof(ngx_http_headers_out_t, refresh), - ngx_http_set_builtin_header }, - - { ngx_string("Last-Modified"), - offsetof(ngx_http_headers_out_t, last_modified), - ngx_http_set_builtin_header }, - - { ngx_string("Content-Range"), - offsetof(ngx_http_headers_out_t, content_range), - ngx_http_set_builtin_header }, - - { ngx_string("Accept-Ranges"), - offsetof(ngx_http_headers_out_t, accept_ranges), - ngx_http_set_accept_ranges_header }, - - { ngx_string("WWW-Authenticate"), - offsetof(ngx_http_headers_out_t, www_authenticate), - ngx_http_set_builtin_header }, - - { ngx_string("Expires"), - offsetof(ngx_http_headers_out_t, expires), - ngx_http_set_builtin_header }, - - { ngx_string("E-Tag"), - offsetof(ngx_http_headers_out_t, etag), - ngx_http_set_builtin_header }, - - { ngx_string("Content-Length"), - offsetof(ngx_http_headers_out_t, content_length), - ngx_http_set_content_length_header }, - - { ngx_string("Content-Type"), - 0, - ngx_http_set_content_type_header }, - - { ngx_string("Cache-Control"), - offsetof(ngx_http_headers_out_t, cache_control), - ngx_http_set_builtin_multi_header }, - - { ngx_null_string, 0, ngx_http_set_header } -}; - - -ngx_int_t -ngx_http_headers_more_exec_cmd(ngx_http_request_t *r, - ngx_http_headers_more_cmd_t *cmd) -{ - ngx_str_t value; - ngx_http_headers_more_header_val_t *h; - ngx_uint_t i; - - if (!cmd->headers) { - return NGX_OK; - } - - if (cmd->types && !ngx_http_headers_more_check_type(r, cmd->types)) { - return NGX_OK; - } - - if (cmd->statuses - && !ngx_http_headers_more_check_status(r, cmd->statuses)) - { - return NGX_OK; - } - - h = cmd->headers->elts; - for (i = 0; i < cmd->headers->nelts; i++) { - - if (ngx_http_complex_value(r, &h[i].value, &value) != NGX_OK) { - return NGX_ERROR; - } - - if (value.len) { - value.len--; /* remove the trailing '\0' added by - ngx_http_headers_more_parse_header */ - } - - if (h[i].handler(r, &h[i], &value) != NGX_OK) { - return NGX_ERROR; - } - } - - return NGX_OK; -} - - -static ngx_int_t -ngx_http_set_header(ngx_http_request_t *r, - ngx_http_headers_more_header_val_t *hv, ngx_str_t *value) -{ - return ngx_http_set_header_helper(r, hv, value, NULL, 0); -} - - -static ngx_int_t -ngx_http_set_header_helper(ngx_http_request_t *r, - ngx_http_headers_more_header_val_t *hv, ngx_str_t *value, - ngx_table_elt_t **output_header, ngx_flag_t no_create) -{ - ngx_table_elt_t *h; - ngx_list_part_t *part; - ngx_uint_t i; - ngx_flag_t matched = 0; - - dd_enter(); - -#if 1 - if (r->headers_out.location - && r->headers_out.location->value.len - && r->headers_out.location->value.data[0] == '/') - { - /* XXX ngx_http_core_find_config_phase, for example, - * may not initialize the "key" and "hash" fields - * for a nasty optimization purpose, and - * we have to work-around it here */ - - r->headers_out.location->hash = ngx_http_headers_more_location_hash; - ngx_str_set(&r->headers_out.location->key, "Location"); - } -#endif - - part = &r->headers_out.headers.part; - h = part->elts; - - for (i = 0; /* void */; i++) { - - if (i >= part->nelts) { - if (part->next == NULL) { - break; - } - - part = part->next; - h = part->elts; - i = 0; - } - - if (h[i].hash == 0) { - continue; - } - - if (!hv->wildcard - && h[i].key.len == hv->key.len - && ngx_strncasecmp(h[i].key.data, hv->key.data, - h[i].key.len) == 0) - { - goto matched; - } - - if (hv->wildcard - && h[i].key.len >= hv->key.len - 1 - && ngx_strncasecmp(h[i].key.data, hv->key.data, - hv->key.len - 1) == 0) - { - goto matched; - } - - /* not matched */ - continue; - -matched: - - if (value->len == 0 || matched) { - dd("clearing normal header for %.*s", (int) hv->key.len, - hv->key.data); - - h[i].value.len = 0; - h[i].hash = 0; - - } else { - h[i].value = *value; - h[i].hash = hv->hash; - } - - if (output_header) { - *output_header = &h[i]; - } - - matched = 1; - } - - if (matched){ - return NGX_OK; - } - - if ((hv->wildcard || no_create) && value->len == 0) { - return NGX_OK; - } - - /* XXX we still need to create header slot even if the value - * is empty because some builtin headers like Last-Modified - * relies on this to get cleared */ - - h = ngx_list_push(&r->headers_out.headers); - if (h == NULL) { - return NGX_ERROR; - } - - if (value->len == 0) { - h->hash = 0; - - } else { - h->hash = hv->hash; - } - - h->key = hv->key; - h->value = *value; - - h->lowcase_key = ngx_pnalloc(r->pool, h->key.len); - if (h->lowcase_key == NULL) { - return NGX_ERROR; - } - - ngx_strlow(h->lowcase_key, h->key.data, h->key.len); - - if (output_header) { - *output_header = h; - } - - return NGX_OK; -} - - -static ngx_int_t -ngx_http_set_builtin_header(ngx_http_request_t *r, - ngx_http_headers_more_header_val_t *hv, ngx_str_t *value) -{ - ngx_table_elt_t *h, **old; - - dd_enter(); - - if (hv->offset) { - old = (ngx_table_elt_t **) ((char *) &r->headers_out + hv->offset); - - } else { - old = NULL; - } - - if (old == NULL || *old == NULL) { - return ngx_http_set_header_helper(r, hv, value, old, 0); - } - - h = *old; - - if (value->len == 0) { - dd("clearing the builtin header"); - - h->hash = 0; - h->value = *value; - - return NGX_OK; - } - - h->hash = hv->hash; - h->key = hv->key; - h->value = *value; - - return NGX_OK; -} - - -static ngx_int_t -ngx_http_set_builtin_multi_header(ngx_http_request_t *r, - ngx_http_headers_more_header_val_t *hv, ngx_str_t *value) -{ - ngx_array_t *pa; - ngx_table_elt_t *ho, **ph; - ngx_uint_t i; - - pa = (ngx_array_t *) ((char *) &r->headers_out + hv->offset); - - if (pa->elts == NULL) { - if (ngx_array_init(pa, r->pool, 2, sizeof(ngx_table_elt_t *)) - != NGX_OK) - { - return NGX_ERROR; - } - } - - /* override old values (if any) */ - - if (pa->nelts > 0) { - ph = pa->elts; - for (i = 1; i < pa->nelts; i++) { - ph[i]->hash = 0; - ph[i]->value.len = 0; - } - - ph[0]->value = *value; - - if (value->len == 0) { - ph[0]->hash = 0; - - } else { - ph[0]->hash = hv->hash; - } - - return NGX_OK; - } - - ph = ngx_array_push(pa); - if (ph == NULL) { - return NGX_ERROR; - } - - ho = ngx_list_push(&r->headers_out.headers); - if (ho == NULL) { - return NGX_ERROR; - } - - ho->value = *value; - ho->hash = hv->hash; - ngx_str_set(&ho->key, "Cache-Control"); - *ph = ho; - - return NGX_OK; -} - - -static ngx_int_t -ngx_http_set_content_type_header(ngx_http_request_t *r, - ngx_http_headers_more_header_val_t *hv, ngx_str_t *value) -{ - u_char *p, *last, *end; - - r->headers_out.content_type_len = value->len; - r->headers_out.content_type = *value; - r->headers_out.content_type_hash = hv->hash; - r->headers_out.content_type_lowcase = NULL; - - p = value->data; - end = p + value->len; - - for (; p != end; p++) { - - if (*p != ';') { - continue; - } - - last = p; - - while (*++p == ' ') { /* void */ } - - if (p == end) { - break; - } - - if (ngx_strncasecmp(p, (u_char *) "charset=", 8) != 0) { - continue; - } - - p += 8; - - r->headers_out.content_type_len = last - value->data; - - if (*p == '"') { - p++; - } - - last = end; - - if (*(last - 1) == '"') { - last--; - } - - r->headers_out.charset.len = last - p; - r->headers_out.charset.data = p; - - break; - } - - value->len = 0; - - return ngx_http_set_header_helper(r, hv, value, NULL, 1); -} - - -static ngx_int_t -ngx_http_set_content_length_header(ngx_http_request_t *r, - ngx_http_headers_more_header_val_t *hv, ngx_str_t *value) -{ - off_t len; - - if (value->len == 0) { - return ngx_http_clear_content_length_header(r, hv, value); - } - - len = ngx_atosz(value->data, value->len); - if (len == NGX_ERROR) { - return NGX_ERROR; - } - - r->headers_out.content_length_n = len; - - return ngx_http_set_builtin_header(r, hv, value); -} - - -static ngx_int_t -ngx_http_set_accept_ranges_header(ngx_http_request_t *r, - ngx_http_headers_more_header_val_t *hv, ngx_str_t *value) -{ - if (value->len == 0) { - r->allow_ranges = 0; - } - - return ngx_http_set_builtin_header(r, hv, value); -} - - -static ngx_int_t -ngx_http_clear_content_length_header(ngx_http_request_t *r, - ngx_http_headers_more_header_val_t *hv, ngx_str_t *value) -{ - r->headers_out.content_length_n = -1; - - return ngx_http_clear_builtin_header(r, hv, value); -} - - -static ngx_int_t -ngx_http_clear_builtin_header(ngx_http_request_t *r, - ngx_http_headers_more_header_val_t *hv, ngx_str_t *value) -{ - dd_enter(); - - value->len = 0; - - return ngx_http_set_builtin_header(r, hv, value); -} - - -char * -ngx_http_headers_more_set_headers(ngx_conf_t *cf, - ngx_command_t *cmd, void *conf) -{ - return ngx_http_headers_more_parse_directive(cf, cmd, conf, - ngx_http_headers_more_opcode_set); -} - - -char * -ngx_http_headers_more_clear_headers(ngx_conf_t *cf, - ngx_command_t *cmd, void *conf) -{ - return ngx_http_headers_more_parse_directive(cf, cmd, conf, - ngx_http_headers_more_opcode_clear); -} - - -static ngx_flag_t -ngx_http_headers_more_check_type(ngx_http_request_t *r, ngx_array_t *types) -{ - ngx_uint_t i; - ngx_str_t *t; - - dd("headers_out->content_type: %.*s (len %d)", - (int) r->headers_out.content_type.len, - r->headers_out.content_type.data, - (int) r->headers_out.content_type.len); - - t = types->elts; - - for (i = 0; i < types->nelts; i++) { - dd("...comparing with type [%.*s]", (int) t[i].len, t[i].data); - - if (r->headers_out.content_type_len == t[i].len - && ngx_strncmp(r->headers_out.content_type.data, - t[i].data, t[i].len) == 0) - { - return 1; - } - } - - return 0; -} - - -static ngx_flag_t -ngx_http_headers_more_check_status(ngx_http_request_t *r, ngx_array_t *statuses) -{ - ngx_uint_t i; - ngx_uint_t *status; - - dd("headers_out.status = %d", (int) r->headers_out.status); - - status = statuses->elts; - for (i = 0; i < statuses->nelts; i++) { - dd("...comparing with specified status %d", (int) status[i]); - - if (r->headers_out.status == status[i]) { - return 1; - } - } - - return 0; -} - - -static char * -ngx_http_headers_more_parse_directive(ngx_conf_t *cf, ngx_command_t *ngx_cmd, - void *conf, ngx_http_headers_more_opcode_t opcode) -{ - ngx_http_headers_more_loc_conf_t *hlcf = conf; - - ngx_uint_t i; - ngx_http_headers_more_cmd_t *cmd; - ngx_str_t *arg; - ngx_flag_t ignore_next_arg; - ngx_str_t *cmd_name; - ngx_int_t rc; - - ngx_http_headers_more_main_conf_t *hmcf; - - if (hlcf->cmds == NULL) { - hlcf->cmds = ngx_array_create(cf->pool, 1, - sizeof(ngx_http_headers_more_cmd_t)); - - if (hlcf->cmds == NULL) { - return NGX_CONF_ERROR; - } - } - - cmd = ngx_array_push(hlcf->cmds); - if (cmd == NULL) { - return NGX_CONF_ERROR; - } - - cmd->headers = - ngx_array_create(cf->pool, 1, - sizeof(ngx_http_headers_more_header_val_t)); - if (cmd->headers == NULL) { - return NGX_CONF_ERROR; - } - - cmd->types = ngx_array_create(cf->pool, 1, sizeof(ngx_str_t)); - if (cmd->types == NULL) { - return NGX_CONF_ERROR; - } - - cmd->statuses = ngx_array_create(cf->pool, 1, sizeof(ngx_uint_t)); - if (cmd->statuses == NULL) { - return NGX_CONF_ERROR; - } - - arg = cf->args->elts; - - cmd_name = &arg[0]; - - ignore_next_arg = 0; - - for (i = 1; i < cf->args->nelts; i++) { - - if (ignore_next_arg) { - ignore_next_arg = 0; - continue; - } - - if (arg[i].len == 0) { - continue; - } - - if (arg[i].data[0] != '-') { - rc = ngx_http_headers_more_parse_header(cf, cmd_name, - &arg[i], cmd->headers, - opcode, - ngx_http_headers_more_set_handlers); - - if (rc != NGX_OK) { - return NGX_CONF_ERROR; - } - - continue; - } - - if (arg[i].len == 2) { - if (arg[i].data[1] == 't') { - if (i == cf->args->nelts - 1) { - ngx_log_error(NGX_LOG_ERR, cf->log, 0, - "%V: option -t takes an argument.", - cmd_name); - - return NGX_CONF_ERROR; - } - - rc = ngx_http_headers_more_parse_types(cf->log, cmd_name, - &arg[i + 1], - cmd->types); - - if (rc != NGX_OK) { - return NGX_CONF_ERROR; - } - - ignore_next_arg = 1; - - continue; - - } else if (arg[i].data[1] == 's') { - - if (i == cf->args->nelts - 1) { - ngx_log_error(NGX_LOG_ERR, cf->log, 0, - "%V: option -s takes an argument.", - cmd_name); - - return NGX_CONF_ERROR; - } - - rc = ngx_http_headers_more_parse_statuses(cf->log, cmd_name, - &arg[i + 1], - cmd->statuses); - - if (rc != NGX_OK) { - return NGX_CONF_ERROR; - } - - ignore_next_arg = 1; - - continue; - } - } - - ngx_log_error(NGX_LOG_ERR, cf->log, 0, - "%V: invalid option name: \"%V\"", cmd_name, &arg[i]); - - return NGX_CONF_ERROR; - } - - dd("Found %d statuses, %d types, and %d headers", - (int) cmd->statuses->nelts, (int) cmd->types->nelts, - (int) cmd->headers->nelts); - - if (cmd->headers->nelts == 0) { - cmd->headers = NULL; - } - - if (cmd->types->nelts == 0) { - cmd->types = NULL; - } - - if (cmd->statuses->nelts == 0) { - cmd->statuses = NULL; - } - - cmd->is_input = 0; - - hmcf = ngx_http_conf_get_module_main_conf(cf, - ngx_http_headers_more_filter_module); - - hmcf->requires_filter = 1; - - return NGX_CONF_OK; -} diff --git a/debian/modules/http-headers-more-filter/src/ngx_http_headers_more_headers_out.h b/debian/modules/http-headers-more-filter/src/ngx_http_headers_more_headers_out.h deleted file mode 100644 index c939507..0000000 --- a/debian/modules/http-headers-more-filter/src/ngx_http_headers_more_headers_out.h +++ /dev/null @@ -1,26 +0,0 @@ - -/* - * Copyright (c) Yichun Zhang (agentzh) - */ - - -#ifndef NGX_HTTP_HEADERS_MORE_OUTPUT_HEADERS_H -#define NGX_HTTP_HEADERS_MORE_OUTPUT_HEADERS_H - - -#include "ngx_http_headers_more_filter_module.h" - - -/* output header setters and clearers */ - -ngx_int_t ngx_http_headers_more_exec_cmd(ngx_http_request_t *r, - ngx_http_headers_more_cmd_t *cmd); - -char *ngx_http_headers_more_set_headers(ngx_conf_t *cf, - ngx_command_t *cmd, void *conf); - -char *ngx_http_headers_more_clear_headers(ngx_conf_t *cf, - ngx_command_t *cmd, void *conf); - - -#endif /* NGX_HTTP_HEADERS_MORE_OUTPUT_HEADERS_H */ diff --git a/debian/modules/http-headers-more-filter/src/ngx_http_headers_more_util.c b/debian/modules/http-headers-more-filter/src/ngx_http_headers_more_util.c deleted file mode 100644 index caf372e..0000000 --- a/debian/modules/http-headers-more-filter/src/ngx_http_headers_more_util.c +++ /dev/null @@ -1,380 +0,0 @@ - -/* - * Copyright (C) Yichun Zhang (agentzh) - */ - - -#ifndef DDEBUG -#define DDEBUG 0 -#endif -#include "ddebug.h" - - -#include "ngx_http_headers_more_util.h" -#include - - -ngx_int_t -ngx_http_headers_more_parse_header(ngx_conf_t *cf, ngx_str_t *cmd_name, - ngx_str_t *raw_header, ngx_array_t *headers, - ngx_http_headers_more_opcode_t opcode, - ngx_http_headers_more_set_header_t *handlers) -{ - ngx_http_headers_more_header_val_t *hv; - - ngx_uint_t i; - ngx_str_t key = ngx_null_string; - ngx_str_t value = ngx_null_string; - ngx_flag_t seen_end_of_key; - ngx_http_compile_complex_value_t ccv; - u_char *p; - - hv = ngx_array_push(headers); - if (hv == NULL) { - return NGX_ERROR; - } - - seen_end_of_key = 0; - for (i = 0; i < raw_header->len; i++) { - if (key.len == 0) { - if (isspace(raw_header->data[i])) { - continue; - } - - key.data = raw_header->data; - key.len = 1; - - continue; - } - - if (!seen_end_of_key) { - if (raw_header->data[i] == ':' - || isspace(raw_header->data[i])) - { - seen_end_of_key = 1; - continue; - } - - key.len++; - - continue; - } - - if (value.len == 0) { - if (raw_header->data[i] == ':' - || isspace(raw_header->data[i])) - { - continue; - } - - value.data = &raw_header->data[i]; - value.len = 1; - - continue; - } - - value.len++; - } - - if (key.len == 0) { - ngx_log_error(NGX_LOG_ERR, cf->log, 0, - "%V: no key found in the header argument: %V", - cmd_name, raw_header); - - return NGX_ERROR; - } - - hv->wildcard = (key.data[key.len - 1] == '*'); - if (hv->wildcard && key.len<2){ - ngx_log_error(NGX_LOG_ERR, cf->log, 0, - "%V: wildcard key too short: %V", - cmd_name, raw_header); - return NGX_ERROR; - } - - hv->hash = ngx_hash_key_lc(key.data, key.len); - hv->key = key; - - hv->offset = 0; - - 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; - } - - hv->offset = handlers[i].offset; - hv->handler = handlers[i].handler; - - break; - } - - if (handlers[i].name.len == 0 && handlers[i].handler) { - hv->offset = handlers[i].offset; - hv->handler = handlers[i].handler; - } - - if (opcode == ngx_http_headers_more_opcode_clear) { - value.len = 0; - } - - if (value.len == 0) { - ngx_memzero(&hv->value, sizeof(ngx_http_complex_value_t)); - return NGX_OK; - - } - - /* Nginx request header value requires to be a null-terminated - * C string */ - - p = ngx_palloc(cf->pool, value.len + 1); - if (p == NULL) { - return NGX_ERROR; - } - - ngx_memcpy(p, value.data, value.len); - p[value.len] = '\0'; - value.data = p; - value.len++; /* we should also compile the trailing '\0' */ - - /* compile the header value as a complex value */ - - ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); - - ccv.cf = cf; - ccv.value = &value; - ccv.complex_value = &hv->value; - - if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { - return NGX_ERROR; - } - - return NGX_OK; -} - - -ngx_int_t -ngx_http_headers_more_parse_statuses(ngx_log_t *log, ngx_str_t *cmd_name, - ngx_str_t *value, ngx_array_t *statuses) -{ - u_char *p, *last; - ngx_uint_t *s = NULL; - - p = value->data; - last = p + value->len; - - for (; p != last; p++) { - if (s == NULL) { - if (isspace(*p)) { - continue; - } - - s = ngx_array_push(statuses); - if (s == NULL) { - return NGX_ERROR; - } - - if (*p >= '0' && *p <= '9') { - *s = *p - '0'; - - } else { - ngx_log_error(NGX_LOG_ERR, log, 0, - "%V: invalid digit \"%c\" found in " - "the status code list \"%V\"", - cmd_name, *p, value); - - return NGX_ERROR; - } - - continue; - } - - if (isspace(*p)) { - dd("Parsed status %d", (int) *s); - - s = NULL; - continue; - } - - if (*p >= '0' && *p <= '9') { - *s *= 10; - *s += *p - '0'; - - } else { - ngx_log_error(NGX_LOG_ERR, log, 0, - "%V: invalid digit \"%c\" found in " - "the status code list \"%V\"", - cmd_name, *p, value); - - return NGX_ERROR; - } - } - - if (s) { - dd("Parsed status %d", (int) *s); - } - - return NGX_OK; -} - - -ngx_int_t -ngx_http_headers_more_parse_types(ngx_log_t *log, ngx_str_t *cmd_name, - ngx_str_t *value, ngx_array_t *types) -{ - u_char *p, *last; - ngx_str_t *t = NULL; - - p = value->data; - last = p + value->len; - - for (; p != last; p++) { - if (t == NULL) { - if (isspace(*p) || *p == ';') { - continue; - } - - t = ngx_array_push(types); - if (t == NULL) { - return NGX_ERROR; - } - - t->len = 1; - t->data = p; - - continue; - } - - if (isspace(*p) || *p == ';') { - t = NULL; - continue; - } - - t->len++; - } - - return NGX_OK; -} - - -ngx_int_t -ngx_http_headers_more_rm_header_helper(ngx_list_t *l, ngx_list_part_t *cur, - ngx_uint_t i) -{ - ngx_table_elt_t *data; - ngx_list_part_t *new, *part; - - dd("list rm item: part %p, i %d, nalloc %d", cur, (int) i, - (int) l->nalloc); - - data = cur->elts; - - dd("cur: nelts %d, nalloc %d", (int) cur->nelts, - (int) l->nalloc); - - if (i == 0) { - cur->elts = (char *) cur->elts + l->size; - cur->nelts--; - - if (cur == l->last) { - if (cur->nelts == 0) { -#if 1 - part = &l->part; - - if (part == cur) { - cur->elts = (char *) cur->elts - l->size; - /* do nothing */ - - } else { - while (part->next != cur) { - if (part->next == NULL) { - return NGX_ERROR; - } - part = part->next; - } - - l->last = part; - part->next = NULL; - dd("part nelts: %d", (int) part->nelts); - l->nalloc = part->nelts; - } -#endif - - } else { - l->nalloc--; - } - - return NGX_OK; - } - - if (cur->nelts == 0) { - part = &l->part; - - if (part == cur) { - ngx_http_headers_more_assert(cur->next != NULL); - - dd("remove 'cur' from the list by rewriting 'cur': " - "l->last: %p, cur: %p, cur->next: %p, part: %p", - l->last, cur, cur->next, part); - - if (l->last == cur->next) { - dd("last is cur->next"); - l->part = *(cur->next); - l->last = part; - l->nalloc = part->nelts; - - } else { - l->part = *(cur->next); - } - - } else { - dd("remove 'cur' from the list"); - while (part->next != cur) { - if (part->next == NULL) { - return NGX_ERROR; - } - part = part->next; - } - - part->next = cur->next; - } - - return NGX_OK; - } - - return NGX_OK; - } - - if (i == cur->nelts - 1) { - cur->nelts--; - - if (cur == l->last) { - l->nalloc = cur->nelts; - } - - return NGX_OK; - } - - new = ngx_palloc(l->pool, sizeof(ngx_list_part_t)); - if (new == NULL) { - return NGX_ERROR; - } - - new->elts = &data[i + 1]; - new->nelts = cur->nelts - i - 1; - new->next = cur->next; - - cur->nelts = i; - cur->next = new; - if (cur == l->last) { - l->last = new; - l->nalloc = new->nelts; - } - - return NGX_OK; -} diff --git a/debian/modules/http-headers-more-filter/src/ngx_http_headers_more_util.h b/debian/modules/http-headers-more-filter/src/ngx_http_headers_more_util.h deleted file mode 100644 index 6c4614b..0000000 --- a/debian/modules/http-headers-more-filter/src/ngx_http_headers_more_util.h +++ /dev/null @@ -1,52 +0,0 @@ - -/* - * Copyright (c) Yichun Zhang (agentzh) - */ - - -#ifndef NGX_HTTP_HEADERS_MORE_UTIL_H -#define NGX_HTTP_HEADERS_MORE_UTIL_H - - -#include "ngx_http_headers_more_filter_module.h" - - -#define ngx_http_headers_more_hash_literal(s) \ - ngx_http_headers_more_hash_str((u_char *) s, sizeof(s) - 1) - - -static ngx_inline ngx_uint_t -ngx_http_headers_more_hash_str(u_char *src, size_t n) -{ - ngx_uint_t key; - - key = 0; - - while (n--) { - key = ngx_hash(key, *src); - src++; - } - - return key; -} - - -extern ngx_uint_t ngx_http_headers_more_location_hash; - - -ngx_int_t ngx_http_headers_more_parse_header(ngx_conf_t *cf, - ngx_str_t *cmd_name, ngx_str_t *raw_header, ngx_array_t *headers, - ngx_http_headers_more_opcode_t opcode, - ngx_http_headers_more_set_header_t *handlers); - -ngx_int_t ngx_http_headers_more_parse_statuses(ngx_log_t *log, - ngx_str_t *cmd_name, ngx_str_t *value, ngx_array_t *statuses); - -ngx_int_t ngx_http_headers_more_parse_types(ngx_log_t *log, - ngx_str_t *cmd_name, ngx_str_t *value, ngx_array_t *types); - -ngx_int_t ngx_http_headers_more_rm_header_helper(ngx_list_t *l, - ngx_list_part_t *cur, ngx_uint_t i); - - -#endif /* NGX_HTTP_HEADERS_MORE_UTIL_H */ diff --git a/debian/modules/http-headers-more-filter/t/bug.t b/debian/modules/http-headers-more-filter/t/bug.t deleted file mode 100644 index 88cfa09..0000000 --- a/debian/modules/http-headers-more-filter/t/bug.t +++ /dev/null @@ -1,393 +0,0 @@ -# vi:filetype= - -use Test::Nginx::Socket; # 'no_plan'; - -repeat_each(2); - -plan tests => 53 * repeat_each(); - -no_diff; - -run_tests(); - -__DATA__ - -=== TEST 1: set Server ---- config - #more_set_headers 'Last-Modified: x'; - more_clear_headers 'Last-Modified'; ---- request - GET /index.html ---- response_headers -! Last-Modified ---- response_body_like: It works! - - - -=== TEST 2: variables in the Ranges header ---- config - location /index.html { - set $rfrom 1; - set $rto 3; - more_set_input_headers 'Range: bytes=$rfrom - $rto'; - #more_set_input_headers 'Range: bytes=1 - 3'; - #echo $http_range; - } ---- request -GET /index.html ---- error_code: 206 ---- response_body chomp -htm - - - -=== TEST 3: mime type overriding (inlined types) ---- config - more_clear_headers 'X-Powered-By' 'X-Runtime' 'ETag'; - - types { - text/html html htm shtml; - text/css css; - } ---- user_files ->>> a.css -hello ---- request -GET /a.css ---- error_code: 200 ---- response_headers -Content-Type: text/css ---- response_body -hello - - - -=== TEST 4: mime type overriding (included types file) ---- config - more_clear_headers 'X-Powered-By' 'X-Runtime' 'ETag'; - include mime.types; ---- user_files ->>> a.css -hello ->>> ../conf/mime.types -types { - text/html html htm shtml; - text/css css; -} ---- request -GET /a.css ---- error_code: 200 ---- response_headers -Content-Type: text/css ---- response_body -hello - - - -=== TEST 5: empty variable as the header value ---- config - location /foo { - more_set_headers 'X-Foo: $arg_foo'; - echo hi; - } ---- request - GET /foo ---- response_headers -! X-Foo ---- response_body -hi - - - -=== TEST 6: range bug ---- config - location /index.html { - more_clear_input_headers "Range*" ; - more_clear_input_headers "Content-Range*" ; - - more_set_input_headers 'Range: bytes=1-5'; - more_set_headers 'Content-Range: bytes 1-5/1000'; - } ---- request - GET /index.html ---- more_headers -Range: bytes=1-3 ---- raw_response_headers_like: Content-Range: bytes 1-5/1000$ ---- response_body chop -html> ---- error_code: 206 ---- SKIP - - - -=== TEST 7: Allow-Ranges ---- config - location /index.html { - more_clear_headers 'Accept-Ranges'; - } ---- request - GET /index.html ---- response_headers -! Accept-Ranges ---- response_body_like: It works - - - -=== TEST 8: clear hand-written Allow-Ranges headers ---- config - location /index.html { - more_set_headers 'Accept-Ranges: bytes'; - more_clear_headers 'Accept-Ranges'; - } ---- request - GET /index.html ---- response_headers -! Accept-Ranges ---- response_body_like: It works - - - -=== TEST 9: clear first, then add ---- config - location /bug { - more_clear_headers 'Foo'; - more_set_headers 'Foo: a'; - echo hello; - } ---- request - GET /bug ---- raw_response_headers_like eval -".*Foo: a.*" ---- response_body -hello - - - -=== TEST 10: first add, then clear, then add again ---- config - location /bug { - more_set_headers 'Foo: a'; - more_clear_headers 'Foo'; - more_set_headers 'Foo: b'; - echo hello; - } ---- request - GET /bug ---- raw_response_headers_like eval -".*Foo: b.*" ---- response_body -hello - - - -=== TEST 11: override charset ---- config - location /foo { - charset iso-8859-1; - default_type "text/html"; - echo hiya; - } - - location /bug { - more_set_headers "Content-Type: text/html; charset=UTF-8"; - proxy_pass http://127.0.0.1:$server_port/foo; - } ---- request - GET /bug ---- response_body -hiya ---- response_headers -Content-Type: text/html; charset=UTF-8 - - - -=== TEST 12: set multi-value header to a single value ---- config - location /main { - set $footer ''; - proxy_pass http://127.0.0.1:$server_port/foo; - more_set_headers 'Foo: b'; - header_filter_by_lua ' - ngx.var.footer = ngx.header.Foo - '; - echo_after_body $footer; - } - location /foo { - echo foo; - add_header Foo a; - add_header Foo c; - } ---- request - GET /main ---- response_headers -Foo: b ---- response_body -foo -b - - - -=== TEST 13: set multi values to cache-control and override it with multiple values (to reproduce a bug) ---- config - location /lua { - content_by_lua ' - ngx.header.cache_control = { "private", "no-store", "foo", "bar", "baz" } - ngx.send_headers() - ngx.say("Cache-Control: ", ngx.var.sent_http_cache_control) - '; - more_clear_headers Cache-Control; - add_header Cache-Control "blah"; - } ---- request - GET /lua ---- response_headers -Cache-Control: blah ---- response_body -Cache-Control: blah - - - -=== TEST 14: set 20+ headers ---- config - location /test { - more_clear_input_headers "Authorization"; - echo $http_a1; - echo $http_authorization; - echo $http_a2; - echo $http_a3; - echo $http_a23; - echo $http_a24; - echo $http_a25; - } ---- request - GET /test ---- more_headers eval -my $i = 1; -my $s; -while ($i <= 25) { - $s .= "A$i: $i\n"; - if ($i == 22) { - $s .= "Authorization: blah\n"; - } - $i++; -} -#warn $s; -$s ---- response_body -1 - -2 -3 -23 -24 -25 - - - -=== TEST 15: github #20: segfault caused by the nasty optimization in the nginx core (set) ---- config - location = /t/ { - more_set_headers "Foo: 1"; - proxy_pass http://127.0.0.1:$server_port; - } ---- request -GET /t ---- more_headers -Foo: bar -Bah: baz ---- response_body_like: 301 Moved Permanently ---- error_code: 301 ---- no_error_log -[error] - - - -=== TEST 16: github #20: segfault caused by the nasty optimization in the nginx core (clear) ---- config - location = /t/ { - more_clear_headers Foo; - proxy_pass http://127.0.0.1:$server_port; - } ---- request -GET /t ---- more_headers -Foo: bar -Bah: baz ---- response_body_like: 301 Moved Permanently ---- error_code: 301 ---- no_error_log -[error] - - - -=== TEST 17: Content-Type response headers with a charset param (correct -t values) ---- config - location = /t { - more_set_headers -t 'text/html' 'X-Foo: Bar'; - proxy_pass http://127.0.0.1:$server_port/fake; - } - - location = /fake { - default_type text/html; - charset utf-8; - echo ok; - } ---- request -GET /t ---- response_headers -X-Foo: Bar ---- response_body -ok - - - -=== TEST 18: Content-Type response headers with a charset param (WRONG -t values) ---- config - location = /t { - more_set_headers -t 'text/html; charset=utf-8' 'X-Foo: Bar'; - proxy_pass http://127.0.0.1:$server_port/fake; - } - - location = /fake { - default_type text/html; - charset utf-8; - echo ok; - } ---- request -GET /t ---- response_headers -X-Foo: Bar ---- response_body -ok - - - -=== TEST 19: for bad requests (bad request method letter case) ---- config - error_page 400 = /err; - - location = /err { - more_set_input_headers "Foo: bar"; - echo ok; - } ---- raw_request -GeT / HTTP/1.1 ---- response_body -ok ---- no_check_leak - - - -=== TEST 20: for bad requests (bad request method names) ---- config - error_page 400 = /err; - - location = /err { - more_set_input_headers "Foo: bar"; - echo ok; - } ---- raw_request -GET x HTTP/1.1 ---- response_body -ok ---- no_check_leak diff --git a/debian/modules/http-headers-more-filter/t/builtin.t b/debian/modules/http-headers-more-filter/t/builtin.t deleted file mode 100644 index 27b20af..0000000 --- a/debian/modules/http-headers-more-filter/t/builtin.t +++ /dev/null @@ -1,338 +0,0 @@ -# vi:filetype= - -use lib 'lib'; -use Test::Nginx::Socket; # 'no_plan'; - -plan tests => 60; - -no_diff; - -run_tests(); - -__DATA__ - -=== TEST 1: set Server ---- config - location /foo { - echo hi; - more_set_headers 'Server: Foo'; - } ---- request - GET /foo ---- response_headers -Server: Foo ---- response_body -hi - - - -=== TEST 2: clear Server ---- config - location /foo { - echo hi; - more_clear_headers 'Server: '; - } ---- request - GET /foo ---- response_headers -! Server ---- response_body -hi - - - -=== TEST 3: set Content-Type ---- config - location /foo { - default_type 'text/plan'; - more_set_headers 'Content-Type: text/css'; - echo hi; - } ---- request - GET /foo ---- response_headers -Content-Type: text/css ---- response_body -hi - - - -=== TEST 4: set Content-Type ---- config - location /foo { - default_type 'text/plan'; - more_set_headers 'Content-Type: text/css'; - return 404; - } ---- request - GET /foo ---- response_headers -Content-Type: text/css ---- response_body_like: 404 Not Found ---- error_code: 404 - - - -=== TEST 5: clear Content-Type ---- config - location /foo { - default_type 'text/plain'; - more_clear_headers 'Content-Type: '; - return 404; - } ---- request - GET /foo ---- response_headers -! Content-Type ---- response_body_like: 404 Not Found ---- error_code: 404 - - - -=== TEST 6: clear Content-Type (colon not required) ---- config - location /foo { - default_type 'text/plain'; - more_set_headers 'Content-Type: Hello'; - more_clear_headers 'Content-Type'; - return 404; - } ---- request - GET /foo ---- response_headers -! Content-Type ---- response_body_like: 404 Not Found ---- error_code: 404 - - - -=== TEST 7: clear Content-Type (value ignored) ---- config - location /foo { - default_type 'text/plain'; - more_set_headers 'Content-Type: Hello'; - more_clear_headers 'Content-Type: blah'; - return 404; - } ---- request - GET /foo ---- response_headers -! Content-Type ---- response_body_like: 404 Not Found ---- error_code: 404 - - - -=== TEST 8: clear Content-Type (case insensitive) ---- config - location /foo { - default_type 'text/plain'; - more_set_headers 'Content-Type: Hello'; - more_clear_headers 'content-type: blah'; - return 404; - } ---- request - GET /foo ---- response_headers -! Content-Type ---- response_body_like: 404 Not Found ---- error_code: 404 - - - -=== TEST 9: clear Content-Type using set empty ---- config - location /foo { - default_type 'text/plain'; - more_set_headers 'Content-Type: Hello'; - more_set_headers 'content-type:'; - return 404; - } ---- request - GET /foo ---- response_headers -! Content-Type ---- response_body_like: 404 Not Found ---- error_code: 404 - - - -=== TEST 10: clear Content-Type using setting key only ---- config - location /foo { - default_type 'text/plain'; - more_set_headers 'Content-Type: Hello'; - more_set_headers 'content-type'; - return 404; - } ---- request - GET /foo ---- response_headers -! Content-Type ---- response_body_like: 404 Not Found ---- error_code: 404 - - - -=== TEST 11: set content-length ---- config - location /len { - more_set_headers 'Content-Length: 2'; - echo hello; - } ---- request - GET /len ---- response_headers -Content-Length: 2 ---- response_body chop -he - - - -=== TEST 12: set content-length multiple times ---- config - location /len { - more_set_headers 'Content-Length: 2'; - more_set_headers 'Content-Length: 4'; - echo hello; - } ---- request - GET /len ---- response_headers -Content-Length: 4 ---- response_body chop -hell - - - -=== TEST 13: clear content-length ---- config - location /len { - more_set_headers 'Content-Length: 4'; - more_set_headers 'Content-Length:'; - echo hello; - } ---- request - GET /len ---- response_headers -! Content-Length ---- response_body -hello - - - -=== TEST 14: clear content-length (another way) ---- config - location /len { - more_set_headers 'Content-Length: 4'; - more_clear_headers 'Content-Length'; - echo hello; - } ---- request - GET /len ---- response_headers -! Content-Length ---- response_body -hello - - - -=== TEST 15: clear content-type ---- config - location /len { - default_type 'text/plain'; - more_set_headers 'Content-Type:'; - echo hello; - } ---- request - GET /len ---- response_headers -! Content-Type ---- response_body -hello - - - -=== TEST 16: clear content-type (the other way) ---- config - location /len { - default_type 'text/plain'; - more_clear_headers 'Content-Type:'; - echo hello; - } ---- request - GET /len ---- response_headers -! Content-Type ---- response_body -hello - - - -=== TEST 17: set Charset ---- config - location /len { - default_type 'text/plain'; - more_set_headers 'Charset: gbk'; - echo hello; - } ---- request - GET /len ---- response_headers -Charset: gbk ---- response_body -hello - - - -=== TEST 18: clear Charset ---- config - location /len { - default_type 'text/plain'; - more_set_headers 'Charset: gbk'; - more_clear_headers 'Charset'; - echo hello; - } ---- request - GET /len ---- response_headers -! Charset ---- response_body -hello - - - -=== TEST 19: clear Charset (the other way: using set) ---- config - location /len { - default_type 'text/plain'; - more_set_headers 'Charset: gbk'; - more_set_headers 'Charset: '; - echo hello; - } ---- request - GET /len ---- response_headers -! Charset ---- response_body -hello - - - -=== TEST 20: set Vary ---- config - location /foo { - more_set_headers 'Vary: gbk'; - echo hello; - } - location /len { - default_type 'text/plain'; - more_set_headers 'Vary: hello'; - proxy_pass http://127.0.0.1:$server_port/foo; - } ---- request - GET /len ---- response_headers -Vary: hello ---- response_body -hello diff --git a/debian/modules/http-headers-more-filter/t/eval.t b/debian/modules/http-headers-more-filter/t/eval.t deleted file mode 100644 index febd306..0000000 --- a/debian/modules/http-headers-more-filter/t/eval.t +++ /dev/null @@ -1,36 +0,0 @@ -# vi:filetype= - -use lib 'lib'; -use Test::Nginx::Socket; # 'no_plan'; - -repeat_each(3); - -plan tests => repeat_each() * 2 * blocks(); - -#no_long_string(); -#no_diff; - -run_tests(); - -__DATA__ - -=== TEST 1: set request header at client side ---- config - location /foo { - eval_subrequest_in_memory off; - eval_override_content_type text/plain; - eval $res { - echo -n 1; - } - #echo "[$res]"; - if ($res = '1') { - more_set_input_headers 'Foo: Bar'; - echo "OK"; - break; - } - echo "NOT OK"; - } ---- request - GET /foo ---- response_body -OK diff --git a/debian/modules/http-headers-more-filter/t/input-conn.t b/debian/modules/http-headers-more-filter/t/input-conn.t deleted file mode 100644 index f53e80f..0000000 --- a/debian/modules/http-headers-more-filter/t/input-conn.t +++ /dev/null @@ -1,137 +0,0 @@ -# vim:set ft= ts=4 sw=4 et fdm=marker: - -use lib 'lib'; -use Test::Nginx::Socket; - -#worker_connections(1014); -#master_process_enabled(1); -#log_level('warn'); - -repeat_each(2); - -plan tests => repeat_each() * (4 * blocks()); - -#no_diff(); -no_long_string(); - -run_tests(); - -__DATA__ - -=== TEST 1: clear the Connection req header ---- config - location /req-header { - more_clear_input_headers Connection; - echo "connection: $http_connection"; - } ---- request -GET /req-header - ---- stap -F(ngx_http_headers_more_exec_input_cmd) { - printf("rewrite: conn type: %d\n", $r->headers_in->connection_type) -} - - -F(ngx_http_core_content_phase) { - printf("content: conn type: %d\n", $r->headers_in->connection_type) -} - ---- stap_out -rewrite: conn type: 1 -content: conn type: 0 - ---- response_body -connection: ---- no_error_log -[error] - - - -=== TEST 2: set custom Connection req header (close) ---- config - location /req-header { - more_set_input_headers "Connection: CLOSE"; - echo "connection: $http_connection"; - } ---- request -GET /req-header - ---- stap -F(ngx_http_headers_more_exec_input_cmd) { - printf("rewrite: conn type: %d\n", $r->headers_in->connection_type) -} - - -F(ngx_http_core_content_phase) { - printf("content: conn type: %d\n", $r->headers_in->connection_type) -} - ---- stap_out -rewrite: conn type: 1 -content: conn type: 1 - ---- response_body -connection: CLOSE ---- no_error_log -[error] - - - -=== TEST 3: set custom Connection req header (keep-alive) ---- config - location /req-header { - more_set_input_headers "Connection: keep-alive"; - echo "connection: $http_connection"; - } ---- request -GET /req-header - ---- stap -F(ngx_http_headers_more_exec_input_cmd) { - printf("rewrite: conn type: %d\n", $r->headers_in->connection_type) -} - - -F(ngx_http_core_content_phase) { - printf("content: conn type: %d\n", $r->headers_in->connection_type) -} - ---- stap_out -rewrite: conn type: 1 -content: conn type: 2 - ---- response_body -connection: keep-alive ---- no_error_log -[error] - - - -=== TEST 4: set custom Connection req header (bad) ---- config - location /req-header { - more_set_input_headers "Connection: bad"; - echo "connection: $http_connection"; - } ---- request -GET /req-header - ---- stap -F(ngx_http_headers_more_exec_input_cmd) { - printf("rewrite: conn type: %d\n", $r->headers_in->connection_type) -} - - -F(ngx_http_core_content_phase) { - printf("content: conn type: %d\n", $r->headers_in->connection_type) -} - ---- stap_out -rewrite: conn type: 1 -content: conn type: 0 - ---- response_body -connection: bad ---- no_error_log -[error] diff --git a/debian/modules/http-headers-more-filter/t/input-cookie.t b/debian/modules/http-headers-more-filter/t/input-cookie.t deleted file mode 100644 index 68db4d0..0000000 --- a/debian/modules/http-headers-more-filter/t/input-cookie.t +++ /dev/null @@ -1,183 +0,0 @@ -# vim:set ft= ts=4 sw=4 et fdm=marker: - -use lib 'lib'; -use Test::Nginx::Socket; - -#worker_connections(1014); -#master_process_enabled(1); -#log_level('warn'); - -repeat_each(2); - -plan tests => repeat_each() * (4 * blocks()); - -#no_diff(); -no_long_string(); - -run_tests(); - -__DATA__ - -=== TEST 1: clear cookie (with existing cookies) ---- config - location /t { - more_clear_input_headers Cookie; - echo "Cookie foo: $cookie_foo"; - echo "Cookie baz: $cookie_baz"; - echo "Cookie: $http_cookie"; - } ---- request -GET /t ---- more_headers -Cookie: foo=bar -Cookie: baz=blah - ---- stap -F(ngx_http_headers_more_exec_input_cmd) { - printf("rewrite: cookies: %d\n", $r->headers_in->cookies->nelts) -} - -F(ngx_http_core_content_phase) { - printf("content: cookies: %d\n", $r->headers_in->cookies->nelts) -} - ---- stap_out -rewrite: cookies: 2 -content: cookies: 0 - ---- response_body -Cookie foo: -Cookie baz: -Cookie: - ---- no_error_log -[error] - - - -=== TEST 2: clear cookie (without existing cookies) ---- config - location /t { - more_clear_input_headers Cookie; - echo "Cookie foo: $cookie_foo"; - echo "Cookie baz: $cookie_baz"; - echo "Cookie: $http_cookie"; - } ---- request -GET /t - ---- stap -F(ngx_http_headers_more_exec_input_cmd) { - printf("rewrite: cookies: %d\n", $r->headers_in->cookies->nelts) -} - -F(ngx_http_core_content_phase) { - printf("content: cookies: %d\n", $r->headers_in->cookies->nelts) -} - ---- stap_out -rewrite: cookies: 0 -content: cookies: 0 - ---- response_body -Cookie foo: -Cookie baz: -Cookie: - ---- no_error_log -[error] - - - -=== TEST 3: set one custom cookie (with existing cookies) ---- config - location /t { - more_set_input_headers "Cookie: boo=123"; - echo "Cookie foo: $cookie_foo"; - echo "Cookie baz: $cookie_baz"; - echo "Cookie boo: $cookie_boo"; - echo "Cookie: $http_cookie"; - } ---- request -GET /t ---- more_headers -Cookie: foo=bar -Cookie: baz=blah - ---- stap -F(ngx_http_headers_more_exec_input_cmd) { - printf("rewrite: cookies: %d\n", $r->headers_in->cookies->nelts) -} - -F(ngx_http_core_content_phase) { - printf("content: cookies: %d\n", $r->headers_in->cookies->nelts) -} - ---- stap_out -rewrite: cookies: 2 -content: cookies: 1 - ---- response_body -Cookie foo: -Cookie baz: -Cookie boo: 123 -Cookie: boo=123 - ---- no_error_log -[error] - - - -=== TEST 4: set one custom cookie (without existing cookies) ---- config - location /t { - more_set_input_headers "Cookie: boo=123"; - echo "Cookie foo: $cookie_foo"; - echo "Cookie baz: $cookie_baz"; - echo "Cookie boo: $cookie_boo"; - echo "Cookie: $http_cookie"; - } ---- request -GET /t - ---- stap -F(ngx_http_headers_more_exec_input_cmd) { - printf("rewrite: cookies: %d\n", $r->headers_in->cookies->nelts) -} - -F(ngx_http_core_content_phase) { - printf("content: cookies: %d\n", $r->headers_in->cookies->nelts) -} - ---- stap_out -rewrite: cookies: 0 -content: cookies: 1 - ---- response_body -Cookie foo: -Cookie baz: -Cookie boo: 123 -Cookie: boo=123 - ---- no_error_log -[error] - - - -=== TEST 5: for bad requests causing segfaults when setting & getting multi-value headers ---- config - error_page 400 = /err; - - location = /err { - more_set_input_headers "Cookie: foo=bar"; - echo -n $cookie_foo; - echo ok; - } ---- raw_request -GeT / HTTP/1.1 ---- response_body -ok ---- no_error_log -[error] -[alert] ---- no_check_leak diff --git a/debian/modules/http-headers-more-filter/t/input-ua.t b/debian/modules/http-headers-more-filter/t/input-ua.t deleted file mode 100644 index da9a60d..0000000 --- a/debian/modules/http-headers-more-filter/t/input-ua.t +++ /dev/null @@ -1,628 +0,0 @@ -# vim:set ft= ts=4 sw=4 et fdm=marker: - -use lib 'lib'; -use Test::Nginx::Socket; - -#worker_connections(1014); -#master_process_enabled(1); -#log_level('warn'); - -repeat_each(2); - -plan tests => repeat_each() * (4 * blocks()); - -#no_diff(); -no_long_string(); - -run_tests(); - -__DATA__ - -=== TEST 1: clear Opera user-agent ---- config - location /t { - more_clear_input_headers User-Agent; - echo "User-Agent: $http_user_agent"; - } - ---- request -GET /t - ---- more_headers -User-Agent: Opera/9.80 (Macintosh; Intel Mac OS X 10.7.4; U; en) Presto/2.10.229 Version/11.62 - ---- stap -F(ngx_http_headers_more_exec_input_cmd) { - printf("rewrite: opera: %d\n", $r->headers_in->opera) -} - -F(ngx_http_core_content_phase) { - printf("content: opera: %d\n", $r->headers_in->opera) -} - ---- stap_out -rewrite: opera: 1 -content: opera: 0 - ---- response_body -User-Agent: ---- no_error_log -[error] - - - -=== TEST 2: clear MSIE 4 user-agent ---- config - location /t { - more_clear_input_headers User-Agent; - echo "User-Agent: $http_user_agent"; - } - ---- request -GET /t - ---- more_headers -User-Agent: Mozilla/4.0 (compatible; MSIE 4.01; Windows NT 5.0) - ---- stap -F(ngx_http_headers_more_exec_input_cmd) { - printf("rewrite: msie=%d msie6=%d\n", - $r->headers_in->msie, - $r->headers_in->msie6) -} - -F(ngx_http_core_content_phase) { - printf("content: msie=%d msie6=%d\n", - $r->headers_in->msie, - $r->headers_in->msie6) -} - ---- stap_out -rewrite: msie=1 msie6=1 -content: msie=0 msie6=0 - ---- response_body -User-Agent: ---- no_error_log -[error] - - - -=== TEST 3: set custom MSIE 4 user-agent ---- config - location /t { - more_set_input_headers "User-Agent: Mozilla/4.0 (compatible; MSIE 4.01; Windows NT 5.0)"; - echo "User-Agent: $http_user_agent"; - } - ---- request -GET /t - ---- stap -F(ngx_http_headers_more_exec_input_cmd) { - printf("rewrite: msie=%d msie6=%d\n", - $r->headers_in->msie, - $r->headers_in->msie6) -} - -F(ngx_http_core_content_phase) { - printf("content: msie=%d msie6=%d\n", - $r->headers_in->msie, - $r->headers_in->msie6) -} - ---- stap_out -rewrite: msie=0 msie6=0 -content: msie=1 msie6=1 - ---- response_body -User-Agent: Mozilla/4.0 (compatible; MSIE 4.01; Windows NT 5.0) ---- no_error_log -[error] - - - -=== TEST 4: clear MSIE 5 user-agent ---- config - location /t { - more_clear_input_headers User-Agent; - echo "User-Agent: $http_user_agent"; - } - ---- request -GET /t - ---- more_headers -User-Agent: Mozilla/4.0 (compatible; MSIE 5.01; Windows 95; MSIECrawler) - ---- stap -F(ngx_http_headers_more_exec_input_cmd) { - printf("rewrite: msie=%d msie6=%d\n", - $r->headers_in->msie, - $r->headers_in->msie6) -} - -F(ngx_http_core_content_phase) { - printf("content: msie=%d msie6=%d\n", - $r->headers_in->msie, - $r->headers_in->msie6) -} - ---- stap_out -rewrite: msie=1 msie6=1 -content: msie=0 msie6=0 - ---- response_body -User-Agent: ---- no_error_log -[error] - - - -=== TEST 5: set custom MSIE 5 user-agent ---- config - location /t { - more_set_input_headers "User-Agent: Mozilla/4.0 (compatible; MSIE 5.01; Windows 95; MSIECrawler)"; - echo "User-Agent: $http_user_agent"; - } - ---- request -GET /t - ---- stap -F(ngx_http_headers_more_exec_input_cmd) { - printf("rewrite: msie=%d msie6=%d\n", - $r->headers_in->msie, - $r->headers_in->msie6) -} - -F(ngx_http_core_content_phase) { - printf("content: msie=%d msie6=%d\n", - $r->headers_in->msie, - $r->headers_in->msie6) -} - ---- stap_out -rewrite: msie=0 msie6=0 -content: msie=1 msie6=1 - ---- response_body -User-Agent: Mozilla/4.0 (compatible; MSIE 5.01; Windows 95; MSIECrawler) ---- no_error_log -[error] - - - -=== TEST 6: clear MSIE 6 (without SV1) user-agent ---- config - location /t { - more_clear_input_headers User-Agent; - echo "User-Agent: $http_user_agent"; - } - ---- request -GET /t - ---- more_headers -User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Google Wireless Transcoder;) - ---- stap -F(ngx_http_headers_more_exec_input_cmd) { - printf("rewrite: msie=%d msie6=%d\n", - $r->headers_in->msie, - $r->headers_in->msie6) -} - -F(ngx_http_core_content_phase) { - printf("content: msie=%d msie6=%d\n", - $r->headers_in->msie, - $r->headers_in->msie6) -} - ---- stap_out -rewrite: msie=1 msie6=1 -content: msie=0 msie6=0 - ---- response_body -User-Agent: ---- no_error_log -[error] - - - -=== TEST 7: set custom MSIE 6 (without SV1) user-agent ---- config - location /t { - more_set_input_headers "User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Google Wireless Transcoder;)"; - echo "User-Agent: $http_user_agent"; - } - ---- request -GET /t - ---- stap -F(ngx_http_headers_more_exec_input_cmd) { - printf("rewrite: msie=%d msie6=%d\n", - $r->headers_in->msie, - $r->headers_in->msie6) -} - -F(ngx_http_core_content_phase) { - printf("content: msie=%d msie6=%d\n", - $r->headers_in->msie, - $r->headers_in->msie6) -} - ---- stap_out -rewrite: msie=0 msie6=0 -content: msie=1 msie6=1 - ---- response_body -User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Google Wireless Transcoder;) ---- no_error_log -[error] - - - -=== TEST 8: clear MSIE 6 (with SV1) user-agent ---- config - location /t { - more_clear_input_headers User-Agent; - echo "User-Agent: $http_user_agent"; - } - ---- request -GET /t - ---- more_headers -User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; InfoPath.1) - ---- stap -F(ngx_http_headers_more_exec_input_cmd) { - printf("rewrite: msie=%d msie6=%d\n", - $r->headers_in->msie, - $r->headers_in->msie6) -} - -F(ngx_http_core_content_phase) { - printf("content: msie=%d msie6=%d\n", - $r->headers_in->msie, - $r->headers_in->msie6) -} - ---- stap_out -rewrite: msie=1 msie6=0 -content: msie=0 msie6=0 - ---- response_body -User-Agent: ---- no_error_log -[error] - - - -=== TEST 9: set custom MSIE 6 (with SV1) user-agent ---- config - location /t { - more_set_input_headers "User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; InfoPath.1)"; - echo "User-Agent: $http_user_agent"; - } - ---- request -GET /t - ---- stap -F(ngx_http_headers_more_exec_input_cmd) { - printf("rewrite: msie=%d msie6=%d\n", - $r->headers_in->msie, - $r->headers_in->msie6) -} - -F(ngx_http_core_content_phase) { - printf("content: msie=%d msie6=%d\n", - $r->headers_in->msie, - $r->headers_in->msie6) -} - ---- stap_out -rewrite: msie=0 msie6=0 -content: msie=1 msie6=0 - ---- response_body -User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; InfoPath.1) ---- no_error_log -[error] - - - -=== TEST 10: set custom MSIE 7 user-agent ---- config - location /t { - more_set_input_headers "User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; winfx; .NET CLR 1.1.4322; .NET CLR 2.0.50727; Zune 2.0)"; - echo "User-Agent: $http_user_agent"; - } - ---- request -GET /t - ---- stap -F(ngx_http_headers_more_exec_input_cmd) { - printf("rewrite: msie=%d msie6=%d\n", - $r->headers_in->msie, - $r->headers_in->msie6) -} - -F(ngx_http_core_content_phase) { - printf("content: msie=%d msie6=%d\n", - $r->headers_in->msie, - $r->headers_in->msie6) -} - ---- stap_out -rewrite: msie=0 msie6=0 -content: msie=1 msie6=0 - ---- response_body -User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; winfx; .NET CLR 1.1.4322; .NET CLR 2.0.50727; Zune 2.0) ---- no_error_log -[error] - - - -=== TEST 11: clear Gecko user-agent ---- config - location /t { - more_clear_input_headers User-Agent; - echo "User-Agent: $http_user_agent"; - } - ---- request -GET /t - ---- more_headers -User-Agent: Mozilla/5.0 (Android; Mobile; rv:13.0) Gecko/13.0 Firefox/13.0 - ---- stap -F(ngx_http_headers_more_exec_input_cmd) { - printf("rewrite: gecko: %d\n", $r->headers_in->gecko) -} - - -F(ngx_http_core_content_phase) { - printf("content: gecko: %d\n", $r->headers_in->gecko) -} - ---- stap_out -rewrite: gecko: 1 -content: gecko: 0 - ---- response_body -User-Agent: ---- no_error_log -[error] - - - -=== TEST 12: set custom Gecko user-agent ---- config - location /t { - more_set_input_headers "User-Agent: Mozilla/5.0 (Android; Mobile; rv:13.0) Gecko/13.0 Firefox/13.0"; - echo "User-Agent: $http_user_agent"; - } - ---- request -GET /t - ---- stap -F(ngx_http_headers_more_exec_input_cmd) { - printf("rewrite: gecko: %d\n", $r->headers_in->gecko) -} - - -F(ngx_http_core_content_phase) { - printf("content: gecko: %d\n", $r->headers_in->gecko) -} - ---- stap_out -rewrite: gecko: 0 -content: gecko: 1 - ---- response_body -User-Agent: Mozilla/5.0 (Android; Mobile; rv:13.0) Gecko/13.0 Firefox/13.0 ---- no_error_log -[error] - - - -=== TEST 13: clear Chrome user-agent ---- config - location /t { - more_clear_input_headers User-Agent; - echo "User-Agent: $http_user_agent"; - } - ---- request -GET /t - ---- more_headers -User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.151 Safari/535.19 - ---- stap -F(ngx_http_headers_more_exec_input_cmd) { - printf("rewrite: chrome: %d\n", $r->headers_in->chrome) -} - - -F(ngx_http_core_content_phase) { - printf("content: chrome: %d\n", $r->headers_in->chrome) -} - ---- stap_out -rewrite: chrome: 1 -content: chrome: 0 - ---- response_body -User-Agent: ---- no_error_log -[error] - - - -=== TEST 14: set custom Chrome user-agent ---- config - location /t { - more_set_input_headers "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.151 Safari/535.19"; - echo "User-Agent: $http_user_agent"; - } - ---- request -GET /t - ---- stap -F(ngx_http_headers_more_exec_input_cmd) { - printf("rewrite: chrome: %d\n", $r->headers_in->chrome) -} - - -F(ngx_http_core_content_phase) { - printf("content: chrome: %d\n", $r->headers_in->chrome) -} - ---- stap_out -rewrite: chrome: 0 -content: chrome: 1 - ---- response_body -User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.151 Safari/535.19 ---- no_error_log -[error] - - - -=== TEST 15: clear Safari (Mac OS X) user-agent ---- config - location /t { - more_clear_input_headers User-Agent; - echo "User-Agent: $http_user_agent"; - } - ---- request -GET /t - ---- more_headers -User-Agent: Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/125.2 (KHTML, like Gecko) Safari/125.8 - ---- stap -F(ngx_http_headers_more_exec_input_cmd) { - printf("rewrite: safari: %d\n", $r->headers_in->safari) -} - - -F(ngx_http_core_content_phase) { - printf("content: safari: %d\n", $r->headers_in->safari) -} - ---- stap_out -rewrite: safari: 1 -content: safari: 0 - ---- response_body -User-Agent: ---- no_error_log -[error] - - - -=== TEST 16: set custom Safari user-agent ---- config - location /t { - more_set_input_headers "User-Agent: Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/125.2 (KHTML, like Gecko) Safari/125.8"; - echo "User-Agent: $http_user_agent"; - } - ---- request -GET /t - ---- stap -F(ngx_http_headers_more_exec_input_cmd) { - printf("rewrite: safari: %d\n", $r->headers_in->safari) -} - - -F(ngx_http_core_content_phase) { - printf("content: safari: %d\n", $r->headers_in->safari) -} - ---- stap_out -rewrite: safari: 0 -content: safari: 1 - ---- response_body -User-Agent: Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/125.2 (KHTML, like Gecko) Safari/125.8 ---- no_error_log -[error] - - - -=== TEST 17: clear Konqueror user-agent ---- config - location /t { - more_clear_input_headers User-Agent; - echo "User-Agent: $http_user_agent"; - } - ---- request -GET /t - ---- more_headers -User-Agent: Mozilla/5.0 (compatible; Konqueror/3.5; Linux) KHTML/3.5.10 (like Gecko) (Kubuntu) - ---- stap -F(ngx_http_headers_more_exec_input_cmd) { - printf("rewrite: konqueror: %d\n", $r->headers_in->konqueror) -} - - -F(ngx_http_core_content_phase) { - printf("content: konqueror: %d\n", $r->headers_in->konqueror) -} - ---- stap_out -rewrite: konqueror: 1 -content: konqueror: 0 - ---- response_body -User-Agent: ---- no_error_log -[error] - - - -=== TEST 18: set custom Konqueror user-agent ---- config - location /t { - more_set_input_headers "User-Agent: Mozilla/5.0 (compatible; Konqueror/3.5; Linux) KHTML/3.5.10 (like Gecko) (Kubuntu)"; - echo "User-Agent: $http_user_agent"; - } - ---- request -GET /t - ---- stap -F(ngx_http_headers_more_exec_input_cmd) { - printf("rewrite: konqueror: %d\n", $r->headers_in->konqueror) -} - - -F(ngx_http_core_content_phase) { - printf("content: konqueror: %d\n", $r->headers_in->konqueror) -} - ---- stap_out -rewrite: konqueror: 0 -content: konqueror: 1 - ---- response_body -User-Agent: Mozilla/5.0 (compatible; Konqueror/3.5; Linux) KHTML/3.5.10 (like Gecko) (Kubuntu) ---- no_error_log -[error] diff --git a/debian/modules/http-headers-more-filter/t/input.t b/debian/modules/http-headers-more-filter/t/input.t deleted file mode 100644 index 01ae73f..0000000 --- a/debian/modules/http-headers-more-filter/t/input.t +++ /dev/null @@ -1,1331 +0,0 @@ -# vi:filetype= - -use lib 'lib'; -use Test::Nginx::Socket; # 'no_plan'; - -repeat_each(2); - -plan tests => repeat_each() * 128; - -no_long_string(); -#no_diff; - -run_tests(); - -__DATA__ - -=== TEST 1: set request header at client side ---- config - location /foo { - #more_set_input_headers 'X-Foo: howdy'; - echo $http_x_foo; - } ---- request - GET /foo ---- more_headers -X-Foo: blah ---- response_headers -! X-Foo ---- response_body -blah - - - -=== TEST 2: set request header at client side and rewrite it ---- config - location /foo { - more_set_input_headers 'X-Foo: howdy'; - echo $http_x_foo; - } ---- request - GET /foo ---- more_headers -X-Foo: blah ---- response_headers -! X-Foo ---- response_body -howdy - - - -=== TEST 3: rewrite content length ---- config - location /bar { - more_set_input_headers 'Content-Length: 2048'; - echo_read_request_body; - echo_request_body; - } ---- request eval -"POST /bar\n" . -"a" x 4096 ---- response_body eval -"a" x 2048 ---- timeout: 15 - - - -=== TEST 4: try to rewrite content length using the rewrite module -Thisshould not take effect ;) ---- config - location /bar { - set $http_content_length 2048; - echo_read_request_body; - echo_request_body; - } ---- request eval -"POST /bar\n" . -"a" x 4096 ---- response_body eval -"a" x 4096 - - - -=== TEST 5: rewrite host and user-agent ---- config - location /bar { - more_set_input_headers 'Host: foo' 'User-Agent: blah'; - echo "Host: $host"; - echo "User-Agent: $http_user_agent"; - } ---- request -GET /bar ---- response_body -Host: foo -User-Agent: blah - - - -=== TEST 6: clear host and user-agent -$host always has a default value and cannot be really cleared. ---- config - location /bar { - more_clear_input_headers 'Host: foo' 'User-Agent: blah'; - echo "Host: $host"; - echo "Host (2): $http_host"; - echo "User-Agent: $http_user_agent"; - } ---- request -GET /bar ---- response_body -Host: localhost -Host (2): -User-Agent: - - - -=== TEST 7: clear host and user-agent (the other way) ---- config - location /bar { - more_set_input_headers 'Host:' 'User-Agent:' 'X-Foo:'; - echo "Host: $host"; - echo "User-Agent: $http_user_agent"; - echo "X-Foo: $http_x_foo"; - } ---- request -GET /bar ---- more_headers -X-Foo: bar ---- response_body -Host: localhost -User-Agent: -X-Foo: - - - -=== TEST 8: clear content-length ---- config - location /bar { - more_set_input_headers 'Content-Length: '; - echo "Content-Length: $http_content_length"; - } ---- request -POST /bar -hello ---- more_headers ---- response_body -Content-Length: - - - -=== TEST 9: clear content-length (the other way) ---- config - location /bar { - more_clear_input_headers 'Content-Length: '; - echo "Content-Length: $http_content_length"; - } ---- request -POST /bar -hello ---- more_headers ---- response_body -Content-Length: - - - -=== TEST 10: rewrite type ---- config - location /bar { - more_set_input_headers 'Content-Type: text/css'; - echo "Content-Type: $content_type"; - } ---- request -POST /bar -hello ---- more_headers -Content-Type: text/plain ---- response_body -Content-Type: text/css - - - -=== TEST 11: clear type ---- config - location /bar { - more_set_input_headers 'Content-Type:'; - echo "Content-Type: $content_type"; - } ---- request -POST /bar -hello ---- more_headers -Content-Type: text/plain ---- response_body -Content-Type: - - - -=== TEST 12: clear type (the other way) ---- config - location /bar { - more_clear_input_headers 'Content-Type:foo'; - echo "Content-Type: $content_type"; - } ---- request -POST /bar -hello ---- more_headers -Content-Type: text/plain ---- response_body -Content-Type: - - - -=== TEST 13: add type constraints ---- config - location /bar { - more_set_input_headers -t 'text/plain' 'X-Blah:yay'; - echo $http_x_blah; - } ---- request -POST /bar -hello ---- more_headers -Content-Type: text/plain ---- response_body -yay - - - -=== TEST 14: add type constraints (not matched) ---- config - location /bar { - more_set_input_headers -t 'text/plain' 'X-Blah:yay'; - echo $http_x_blah; - } ---- request -POST /bar -hello ---- more_headers -Content-Type: text/css ---- response_body eval: "\n" - - - -=== TEST 15: add type constraints (OR'd) ---- config - location /bar { - more_set_input_headers -t 'text/plain text/css' 'X-Blah:yay'; - echo $http_x_blah; - } ---- request -POST /bar -hello ---- more_headers -Content-Type: text/css ---- response_body -yay - - - -=== TEST 16: add type constraints (OR'd) ---- config - location /bar { - more_set_input_headers -t 'text/plain text/css' 'X-Blah:yay'; - echo $http_x_blah; - } ---- request -POST /bar -hello ---- more_headers -Content-Type: text/plain ---- response_body -yay - - - -=== TEST 17: add type constraints (OR'd) (not matched) ---- config - location /bar { - more_set_input_headers -t 'text/plain text/css' 'X-Blah:yay'; - echo $http_x_blah; - } ---- request -POST /bar -hello ---- more_headers -Content-Type: text/html ---- response_body eval: "\n" - - - -=== TEST 18: mix input and output cmds ---- config - location /bar { - more_set_input_headers 'X-Blah:yay'; - more_set_headers 'X-Blah:hiya'; - echo $http_x_blah; - } ---- request -GET /bar ---- response_headers -X-Blah: hiya ---- response -yay - - - -=== TEST 19: set request header at client side and replace ---- config - location /foo { - more_set_input_headers -r 'X-Foo: howdy'; - echo $http_x_foo; - } ---- request - GET /foo ---- more_headers -X-Foo: blah ---- response_headers -! X-Foo ---- response_body -howdy - - - -=== TEST 20: do no set request header at client, so no replace with -r option ---- config - location /foo { - more_set_input_headers -r 'X-Foo: howdy'; - echo "empty_header:" $http_x_foo; - } ---- request - GET /foo ---- response_headers -! X-Foo ---- response_body -empty_header: - - - -=== TEST 21: clear input headers ---- config - location /foo { - set $val 'dog'; - - more_clear_input_headers 'User-Agent'; - - proxy_pass http://127.0.0.1:$server_port/proxy; - } - location /proxy { - echo -n $echo_client_request_headers; - } ---- request - GET /foo ---- more_headers -User-Agent: my-sock ---- response_body eval -"GET /proxy HTTP/1.0\r -Host: 127.0.0.1:\$ServerPort\r -Connection: close\r -\r -" ---- skip_nginx: 3: < 0.7.46 - - - -=== TEST 22: clear input headers ---- config - location /foo { - more_clear_input_headers 'User-Agent'; - - proxy_pass http://127.0.0.1:$server_port/proxy; - } - location /proxy { - echo -n $echo_client_request_headers; - } ---- request - GET /foo ---- response_body eval -"GET /proxy HTTP/1.0\r -Host: 127.0.0.1:\$ServerPort\r -Connection: close\r -\r -" ---- skip_nginx: 3: < 0.7.46 - - - -=== TEST 23: clear input headers ---- config - location /foo { - more_clear_input_headers 'X-Foo19'; - more_clear_input_headers 'X-Foo20'; - more_clear_input_headers 'X-Foo21'; - - proxy_pass http://127.0.0.1:$server_port/proxy; - } - location /proxy { - echo -n $echo_client_request_headers; - } ---- request - GET /foo ---- more_headers eval -my $s; -for my $i (3..21) { - $s .= "X-Foo$i: $i\n"; -} -$s; ---- response_body eval -"GET /proxy HTTP/1.0\r -Host: 127.0.0.1:\$ServerPort\r -Connection: close\r -X-Foo3: 3\r -X-Foo4: 4\r -X-Foo5: 5\r -X-Foo6: 6\r -X-Foo7: 7\r -X-Foo8: 8\r -X-Foo9: 9\r -X-Foo10: 10\r -X-Foo11: 11\r -X-Foo12: 12\r -X-Foo13: 13\r -X-Foo14: 14\r -X-Foo15: 15\r -X-Foo16: 16\r -X-Foo17: 17\r -X-Foo18: 18\r -\r -" ---- skip_nginx: 3: < 0.7.46 - - - -=== TEST 24: Accept-Encoding ---- config - location /bar { - default_type 'text/plain'; - more_set_input_headers 'Accept-Encoding: gzip'; - gzip on; - gzip_min_length 1; - gzip_buffers 4 8k; - gzip_types text/plain; - } ---- user_files -">>> bar -" . ("hello" x 512) ---- request -GET /bar ---- response_headers -Content-Encoding: gzip ---- response_body_like: . - - - -=== TEST 25: rewrite + set request header ---- config - location /t { - rewrite ^ /foo last; - } - - location /foo { - more_set_input_headers 'X-Foo: howdy'; - proxy_pass http://127.0.0.1:$server_port/echo; - } - - location /echo { - echo "X-Foo: $http_x_foo"; - } ---- request - GET /foo ---- response_headers -! X-Foo ---- response_body -X-Foo: howdy - - - -=== TEST 26: clear_header should clear all the instances of the user custom header ---- config - location = /t { - more_clear_input_headers Foo; - - proxy_pass http://127.0.0.1:$server_port/echo; - } - - location = /echo { - echo "Foo: [$http_foo]"; - echo "Test-Header: [$http_test_header]"; - } ---- request -GET /t ---- more_headers -Foo: foo -Foo: bah -Test-Header: 1 ---- response_body -Foo: [] -Test-Header: [1] - - - -=== TEST 27: clear_header should clear all the instances of the builtin header ---- config - location = /t { - more_clear_input_headers Content-Type; - - proxy_pass http://127.0.0.1:$server_port/echo; - } - - location = /echo { - echo "Content-Type: [$http_content_type]"; - echo "Test-Header: [$http_test_header]"; - #echo $echo_client_request_headers; - } ---- request -GET /t ---- more_headers -Content-Type: foo -Content-Type: bah -Test-Header: 1 ---- response_body -Content-Type: [] -Test-Header: [1] - - - -=== TEST 28: Converting POST to GET - clearing headers (bug found by Matthieu Tourne, 411 error page) ---- config - location /t { - more_clear_input_headers Content-Type; - more_clear_input_headers Content-Length; - - #proxy_pass http://127.0.0.1:8888; - proxy_pass http://127.0.0.1:$server_port/back; - } - - location /back { - echo $echo_client_request_headers; - } ---- request -POST /t -hello world ---- more_headers -Content-Type: application/ocsp-request -Test-Header: 1 ---- response_body_like eval -qr/Connection: close\r -Test-Header: 1\r -\r -$/ ---- no_error_log -[error] - - - -=== TEST 29: clear_header() does not duplicate subsequent headers (old bug) ---- config - location = /t { - more_clear_input_headers Foo; - - proxy_pass http://127.0.0.1:$server_port/echo; - } - - location = /echo { - echo $echo_client_request_headers; - } ---- request -GET /t ---- more_headers -Bah: bah -Foo: foo -Test-Header: 1 -Foo1: foo1 -Foo2: foo2 -Foo3: foo3 -Foo4: foo4 -Foo5: foo5 -Foo6: foo6 -Foo7: foo7 -Foo8: foo8 -Foo9: foo9 -Foo10: foo10 -Foo11: foo11 -Foo12: foo12 -Foo13: foo13 -Foo14: foo14 -Foo15: foo15 -Foo16: foo16 -Foo17: foo17 -Foo18: foo18 -Foo19: foo19 -Foo20: foo20 -Foo21: foo21 -Foo22: foo22 ---- response_body_like eval -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 -/ - - - -=== TEST 30: clear input header (just more than 20 headers) ---- config - location = /t { - more_clear_input_headers "R"; - proxy_pass http://127.0.0.1:$server_port/back; - proxy_set_header Host foo; - #proxy_pass http://127.0.0.1:1234/back; - } - - location = /back { - echo -n $echo_client_request_headers; - } ---- request -GET /t ---- more_headers eval -my $s = "User-Agent: curl\n"; - -for my $i ('a' .. 'r') { - $s .= uc($i) . ": " . "$i\n" -} -$s ---- response_body eval -"GET /back HTTP/1.0\r -Host: foo\r -Connection: close\r -User-Agent: curl\r -A: a\r -B: b\r -C: c\r -D: d\r -E: e\r -F: f\r -G: g\r -H: h\r -I: i\r -J: j\r -K: k\r -L: l\r -M: m\r -N: n\r -O: o\r -P: p\r -Q: q\r -\r -" - - - -=== TEST 31: clear input header (just more than 20 headers, and add more) ---- config - location = /t { - more_clear_input_headers R; - more_set_input_headers "foo-1: 1" "foo-2: 2" "foo-3: 3" "foo-4: 4" - "foo-5: 5" "foo-6: 6" "foo-7: 7" "foo-8: 8" "foo-9: 9" - "foo-10: 10" "foo-11: 11" "foo-12: 12" "foo-13: 13" - "foo-14: 14" "foo-15: 15" "foo-16: 16" "foo-17: 17" "foo-18: 18" - "foo-19: 19" "foo-20: 20" "foo-21: 21"; - - proxy_pass http://127.0.0.1:$server_port/back; - proxy_set_header Host foo; - #proxy_pass http://127.0.0.1:1234/back; - } - - location = /back { - echo -n $echo_client_request_headers; - } ---- request -GET /t ---- more_headers eval -my $s = "User-Agent: curl\n"; - -for my $i ('a' .. 'r') { - $s .= uc($i) . ": " . "$i\n" -} -$s ---- response_body eval -"GET /back HTTP/1.0\r -Host: foo\r -Connection: close\r -User-Agent: curl\r -A: a\r -B: b\r -C: c\r -D: d\r -E: e\r -F: f\r -G: g\r -H: h\r -I: i\r -J: j\r -K: k\r -L: l\r -M: m\r -N: n\r -O: o\r -P: p\r -Q: q\r -foo-1: 1\r -foo-2: 2\r -foo-3: 3\r -foo-4: 4\r -foo-5: 5\r -foo-6: 6\r -foo-7: 7\r -foo-8: 8\r -foo-9: 9\r -foo-10: 10\r -foo-11: 11\r -foo-12: 12\r -foo-13: 13\r -foo-14: 14\r -foo-15: 15\r -foo-16: 16\r -foo-17: 17\r -foo-18: 18\r -foo-19: 19\r -foo-20: 20\r -foo-21: 21\r -\r -" - - - -=== TEST 32: clear input header (just more than 21 headers) ---- config - location = /t { - more_clear_input_headers R Q; - proxy_pass http://127.0.0.1:$server_port/back; - proxy_set_header Host foo; - #proxy_pass http://127.0.0.1:1234/back; - } - - location = /back { - echo -n $echo_client_request_headers; - } ---- request -GET /t ---- more_headers eval -my $s = "User-Agent: curl\nBah: bah\n"; - -for my $i ('a' .. 'r') { - $s .= uc($i) . ": " . "$i\n" -} -$s ---- response_body eval -"GET /back HTTP/1.0\r -Host: foo\r -Connection: close\r -User-Agent: curl\r -Bah: bah\r -A: a\r -B: b\r -C: c\r -D: d\r -E: e\r -F: f\r -G: g\r -H: h\r -I: i\r -J: j\r -K: k\r -L: l\r -M: m\r -N: n\r -O: o\r -P: p\r -\r -" - - - -=== TEST 33: clear input header (just more than 21 headers) ---- config - location = /t { - more_clear_input_headers R Q; - more_set_input_headers "foo-1: 1" "foo-2: 2" "foo-3: 3" "foo-4: 4" - "foo-5: 5" "foo-6: 6" "foo-7: 7" "foo-8: 8" "foo-9: 9" - "foo-10: 10" "foo-11: 11" "foo-12: 12" "foo-13: 13" - "foo-14: 14" "foo-15: 15" "foo-16: 16" "foo-17: 17" "foo-18: 18" - "foo-19: 19" "foo-20: 20" "foo-21: 21"; - - proxy_pass http://127.0.0.1:$server_port/back; - proxy_set_header Host foo; - #proxy_pass http://127.0.0.1:1234/back; - } - - location = /back { - echo -n $echo_client_request_headers; - } ---- request -GET /t ---- more_headers eval -my $s = "User-Agent: curl\nBah: bah\n"; - -for my $i ('a' .. 'r') { - $s .= uc($i) . ": " . "$i\n" -} -$s ---- response_body eval -"GET /back HTTP/1.0\r -Host: foo\r -Connection: close\r -User-Agent: curl\r -Bah: bah\r -A: a\r -B: b\r -C: c\r -D: d\r -E: e\r -F: f\r -G: g\r -H: h\r -I: i\r -J: j\r -K: k\r -L: l\r -M: m\r -N: n\r -O: o\r -P: p\r -foo-1: 1\r -foo-2: 2\r -foo-3: 3\r -foo-4: 4\r -foo-5: 5\r -foo-6: 6\r -foo-7: 7\r -foo-8: 8\r -foo-9: 9\r -foo-10: 10\r -foo-11: 11\r -foo-12: 12\r -foo-13: 13\r -foo-14: 14\r -foo-15: 15\r -foo-16: 16\r -foo-17: 17\r -foo-18: 18\r -foo-19: 19\r -foo-20: 20\r -foo-21: 21\r -\r -" - - - -=== TEST 34: clear X-Real-IP ---- config - location /t { - more_clear_input_headers X-Real-IP; - echo "X-Real-IP: $http_x_real_ip"; - } ---- request -GET /t ---- more_headers -X-Real-IP: 8.8.8.8 - ---- stap -F(ngx_http_headers_more_exec_input_cmd) { - if (@defined($r->headers_in->x_real_ip) && $r->headers_in->x_real_ip) { - printf("rewrite: x-real-ip: %s\n", - user_string_n($r->headers_in->x_real_ip->value->data, - $r->headers_in->x_real_ip->value->len)) - } else { - println("rewrite: no x-real-ip") - } -} - -F(ngx_http_core_content_phase) { - if (@defined($r->headers_in->x_real_ip) && $r->headers_in->x_real_ip) { - printf("content: x-real-ip: %s\n", - user_string_n($r->headers_in->x_real_ip->value->data, - $r->headers_in->x_real_ip->value->len)) - } else { - println("content: no x-real-ip") - } -} - ---- stap_out -rewrite: x-real-ip: 8.8.8.8 -content: no x-real-ip - ---- response_body -X-Real-IP: - ---- no_error_log -[error] - - - -=== TEST 35: set custom X-Real-IP ---- config - location /t { - more_set_input_headers "X-Real-IP: 8.8.4.4"; - echo "X-Real-IP: $http_x_real_ip"; - } ---- request -GET /t - ---- stap -F(ngx_http_headers_more_exec_input_cmd) { - if (@defined($r->headers_in->x_real_ip) && $r->headers_in->x_real_ip) { - printf("rewrite: x-real-ip: %s\n", - user_string_n($r->headers_in->x_real_ip->value->data, - $r->headers_in->x_real_ip->value->len)) - } else { - println("rewrite: no x-real-ip") - } - -} - -F(ngx_http_core_content_phase) { - if (@defined($r->headers_in->x_real_ip) && $r->headers_in->x_real_ip) { - printf("content: x-real-ip: %s\n", - user_string_n($r->headers_in->x_real_ip->value->data, - $r->headers_in->x_real_ip->value->len)) - } else { - println("content: no x-real-ip") - } -} - ---- stap_out -rewrite: no x-real-ip -content: x-real-ip: 8.8.4.4 - ---- response_body -X-Real-IP: 8.8.4.4 - ---- no_error_log -[error] - - - -=== TEST 36: clear Via ---- config - location /t { - more_clear_input_headers Via; - echo "Via: $http_via"; - } ---- request -GET /t ---- more_headers -Via: 1.0 fred, 1.1 nowhere.com (Apache/1.1) - ---- stap -F(ngx_http_headers_more_exec_input_cmd) { - if (@defined($r->headers_in->via) && $r->headers_in->via) { - printf("rewrite: via: %s\n", - user_string_n($r->headers_in->via->value->data, - $r->headers_in->via->value->len)) - } else { - println("rewrite: no via") - } -} - -F(ngx_http_core_content_phase) { - if (@defined($r->headers_in->via) && $r->headers_in->via) { - printf("content: via: %s\n", - user_string_n($r->headers_in->via->value->data, - $r->headers_in->via->value->len)) - } else { - println("content: no via") - } -} - ---- stap_out -rewrite: via: 1.0 fred, 1.1 nowhere.com (Apache/1.1) -content: no via - ---- response_body -Via: - ---- no_error_log -[error] - - - -=== TEST 37: set custom Via ---- config - location /t { - more_set_input_headers "Via: 1.0 fred, 1.1 nowhere.com (Apache/1.1)"; - echo "Via: $http_via"; - } ---- request -GET /t - ---- stap -F(ngx_http_headers_more_exec_input_cmd) { - if (@defined($r->headers_in->via) && $r->headers_in->via) { - printf("rewrite: via: %s\n", - user_string_n($r->headers_in->via->value->data, - $r->headers_in->via->value->len)) - } else { - println("rewrite: no via") - } - -} - -F(ngx_http_core_content_phase) { - if (@defined($r->headers_in->via) && $r->headers_in->via) { - printf("content: via: %s\n", - user_string_n($r->headers_in->via->value->data, - $r->headers_in->via->value->len)) - } else { - println("content: no via") - } -} - ---- stap_out -rewrite: no via -content: via: 1.0 fred, 1.1 nowhere.com (Apache/1.1) - ---- response_body -Via: 1.0 fred, 1.1 nowhere.com (Apache/1.1) - ---- no_error_log -[error] - - - -=== TEST 38: HTTP 0.9 (set) ---- config - location /foo { - more_set_input_headers 'X-Foo: howdy'; - echo "x-foo: $http_x_foo"; - } ---- raw_request eval -"GET /foo\r\n" ---- response_headers -! X-Foo ---- response_body -x-foo: ---- http09 - - - -=== TEST 39: HTTP 0.9 (clear) ---- config - location /foo { - more_clear_input_headers 'X-Foo'; - echo "x-foo: $http_x_foo"; - } ---- raw_request eval -"GET /foo\r\n" ---- response_headers -! X-Foo ---- response_body -x-foo: ---- http09 - - - -=== TEST 40: Host header with port and $host ---- config - location /bar { - more_set_input_headers 'Host: agentzh.org:1984'; - echo "host var: $host"; - echo "http_host var: $http_host"; - } ---- request -GET /bar ---- response_body -host var: agentzh.org -http_host var: agentzh.org:1984 - - - -=== TEST 41: Host header with upper case letters and $host ---- config - location /bar { - more_set_input_headers 'Host: agentZH.org:1984'; - echo "host var: $host"; - echo "http_host var: $http_host"; - } ---- request -GET /bar ---- response_body -host var: agentzh.org -http_host var: agentZH.org:1984 - - - -=== TEST 42: clear all and re-insert ---- config - location = /t { - more_clear_input_headers Host Connection Cache-Control Accept - User-Agent Accept-Encoding Accept-Language - Cookie; - - more_set_input_headers "Host: a" "Connection: b" "Cache-Control: c" - "Accept: d" "User-Agent: e" "Accept-Encoding: f" - "Accept-Language: g" "Cookie: h"; - - more_clear_input_headers Host Connection Cache-Control Accept - User-Agent Accept-Encoding Accept-Language - Cookie; - - more_set_input_headers "Host: a" "Connection: b" "Cache-Control: c" - "Accept: d" "User-Agent: e" "Accept-Encoding: f" - "Accept-Language: g" "Cookie: h"; - - echo ok; - } - ---- raw_request eval -"GET /t HTTP/1.1\r -Host: localhost\r -Connection: close\r -Cache-Control: max-age=0\r -Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8\r -User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.101 Safari/537.36\r -Accept-Encoding: gzip,deflate,sdch\r -Accept-Language: en-US,en;q=0.8\r -Cookie: test=cookie;\r -\r -" ---- response_body -ok ---- no_error_log -[error] - - - -=== TEST 43: more_set_input_header does not override request headers with multiple values ---- config - #lua_code_cache off; - location = /t { - more_set_input_headers "AAA: 111"; - - content_by_lua ' - local headers = ngx.req.get_headers() - ngx.say(headers["AAA"]) - '; - } ---- request -GET /t ---- more_headers -AAA: 123 -AAA: 456 -AAA: 678 - ---- response_body -111 ---- no_error_log -[error] - - - -=== TEST 44: clear If-Unmodified-Since req header ---- config - location = /t { - more_clear_input_headers 'If-Unmodified-Since'; - content_by_lua ' - ngx.header["Last-Modified"] = "Tue, 30 Jun 2011 12:16:36 GMT" - ngx.say("If-Unmodified-Since: ", ngx.var.http_if_unmodified_since) - '; - } ---- request -GET /t ---- more_headers -If-Unmodified-Since: Tue, 28 Jun 2011 12:16:36 GMT ---- response_body -If-Unmodified-Since: nil ---- no_error_log -[error] - - - -=== TEST 45: clear If-Match req header ---- config - location = /t { - more_clear_input_headers 'If-Match'; - echo "If-Match: $http_if_match"; - } ---- request -GET /t ---- more_headers -If-Match: abc ---- response_body -If-Match: ---- no_error_log -[error] - - - -=== TEST 46: clear If-None-Match req header ---- config - location = /t { - more_clear_input_headers 'If-None-Match'; - echo "If-None-Match: $http_if_none_match"; - } ---- request -GET /t ---- more_headers -If-None-Match: * ---- response_body -If-None-Match: ---- no_error_log -[error] - - - -=== TEST 47: set the Destination request header for WebDav ---- config - location = /a.txt { - more_set_input_headers "Destination: /b.txt"; - dav_methods MOVE; - dav_access all:rw; - root html; - } - ---- user_files ->>> a.txt -hello, world! - ---- request -MOVE /a.txt - ---- response_body ---- no_error_log -client sent no "Destination" header -[error] ---- error_code: 204 - - - -=== TEST 48: more_set_input_headers + X-Forwarded-For ---- config - location = /t { - more_set_input_headers "X-Forwarded-For: 8.8.8.8"; - proxy_pass http://127.0.0.1:$server_port/back; - proxy_set_header Foo $proxy_add_x_forwarded_for; - } - - location = /back { - echo "Foo: $http_foo"; - } - ---- request -GET /t - ---- response_body -Foo: 8.8.8.8, 127.0.0.1 ---- no_error_log -[error] - - - -=== TEST 49: more_clear_input_headers + X-Forwarded-For ---- config - location = /t { - more_clear_input_headers "X-Forwarded-For"; - proxy_pass http://127.0.0.1:$server_port/back; - proxy_set_header Foo $proxy_add_x_forwarded_for; - } - - location = /back { - echo "Foo: $http_foo"; - } - ---- request -GET /t - ---- more_headers -X-Forwarded-For: 8.8.8.8 ---- response_body -Foo: 127.0.0.1 ---- no_error_log -[error] - - - -=== TEST 50: clear input headers with wildcard ---- config - location /hello { - more_clear_input_headers 'X-Hidden-*'; - content_by_lua ' - ngx.say("X-Hidden-One: ", ngx.var.http_x_hidden_one) - ngx.say("X-Hidden-Two: ", ngx.var.http_x_hidden_two) - '; - } ---- request - GET /hello ---- more_headers -X-Hidden-One: i am hidden -X-Hidden-Two: me 2 ---- response_body -X-Hidden-One: nil -X-Hidden-Two: nil - - - -=== TEST 51: make sure wildcard doesn't affect more_set_input_headers ---- config - location /hello { - more_set_input_headers 'X-Hidden-*: lol'; - content_by_lua ' - ngx.say("X-Hidden-One: ", ngx.var.http_x_hidden_one) - ngx.say("X-Hidden-Two: ", ngx.var.http_x_hidden_two) - '; - } ---- request - GET /hello ---- more_headers -X-Hidden-One: i am hidden -X-Hidden-Two: me 2 ---- response_body -X-Hidden-One: i am hidden -X-Hidden-Two: me 2 diff --git a/debian/modules/http-headers-more-filter/t/phase.t b/debian/modules/http-headers-more-filter/t/phase.t deleted file mode 100644 index 11183db..0000000 --- a/debian/modules/http-headers-more-filter/t/phase.t +++ /dev/null @@ -1,25 +0,0 @@ -# vi:filetype=perl - -use lib 'lib'; -use Test::Nginx::Socket; - -plan tests => 3; - -no_diff; - -run_tests(); - -__DATA__ - -=== TEST 1: simple set (1 arg) ---- config - location /foo { - deny all; - more_set_headers 'X-Foo: Blah'; - } ---- request - GET /foo ---- response_headers -X-Foo: Blah ---- response_body_like: 403 Forbidden ---- error_code: 403 diff --git a/debian/modules/http-headers-more-filter/t/sanity.t b/debian/modules/http-headers-more-filter/t/sanity.t deleted file mode 100644 index d06f5dc..0000000 --- a/debian/modules/http-headers-more-filter/t/sanity.t +++ /dev/null @@ -1,567 +0,0 @@ -# vi:filetype= - -use lib 'lib'; -use Test::Nginx::Socket; - -repeat_each(2); - -plan tests => repeat_each() * 113; - -#master_on(); -#workers(2); -log_level("warn"); -no_diff; - -run_tests(); - -__DATA__ - -=== TEST 1: simple set (1 arg) ---- config - location /foo { - echo hi; - more_set_headers 'X-Foo: Blah'; - } ---- request - GET /foo ---- response_headers -X-Foo: Blah ---- response_body -hi - - - -=== TEST 2: simple set (2 args) ---- config - location /foo { - echo hi; - more_set_headers 'X-Foo: Blah' 'X-Bar: hi'; - } ---- request - GET /foo ---- response_headers -X-Foo: Blah -X-Bar: hi ---- response_body -hi - - - -=== TEST 3: two sets in a single location ---- config - location /two { - echo hi; - more_set_headers 'X-Foo: Blah' - more_set_headers 'X-Bar: hi'; - } ---- request - GET /two ---- response_headers -X-Foo: Blah -X-Bar: hi ---- response_body -hi - - - -=== TEST 4: two sets in a single location (for 404 too) ---- config - location /two { - more_set_headers 'X-Foo: Blah' - more_set_headers 'X-Bar: hi'; - return 404; - } ---- request - GET /two ---- response_headers -X-Foo: Blah -X-Bar: hi ---- response_body_like: 404 Not Found ---- error_code: 404 - - - -=== TEST 5: set a header then clears it (500) ---- config - location /two { - more_set_headers 'X-Foo: Blah'; - more_set_headers 'X-Foo:'; - return 500; - } ---- request - GET /two ---- response_headers -! X-Foo -! X-Bar ---- response_body_like: 500 Internal Server Error ---- error_code: 500 - - - -=== TEST 6: set a header only when 500 (matched) ---- config - location /bad { - more_set_headers -s 500 'X-Mine: Hiya'; - more_set_headers -s 404 'X-Yours: Blah'; - return 500; - } ---- request - GET /bad ---- response_headers -X-Mine: Hiya -! X-Yours ---- response_body_like: 500 Internal Server Error ---- error_code: 500 - - - -=== TEST 7: set a header only when 500 (not matched with 200) ---- config - location /bad { - more_set_headers -s 500 'X-Mine: Hiya'; - more_set_headers -s 404 'X-Yours: Blah'; - echo hello; - } ---- request - GET /bad ---- response_headers -! X-Mine -! X-Yours ---- response_body -hello ---- error_code: 200 - - - -=== TEST 8: set a header only when 500 (not matched with 404) ---- config - location /bad { - more_set_headers -s 500 'X-Mine: Hiya'; - more_set_headers -s 404 'X-Yours: Blah'; - return 404; - } ---- request - GET /bad ---- response_headers -! X-Mine -X-Yours: Blah ---- response_body_like: 404 Not Found ---- error_code: 404 - - - -=== TEST 9: more conditions ---- config - location /bad { - more_set_headers -s '503 404' 'X-Mine: Hiya'; - more_set_headers -s ' 404 413 ' 'X-Yours: Blah'; - return 503; - } ---- request - GET /bad ---- response_headers -X-Mine: Hiya -! X-Yours ---- response_body_like: 503 Service ---- error_code: 503 - - - -=== TEST 10: more conditions ---- config - location /bad { - more_set_headers -s '503 404' 'X-Mine: Hiya'; - more_set_headers -s ' 404 413 ' 'X-Yours: Blah'; - return 404; - } ---- request - GET /bad ---- response_headers -X-Mine: Hiya -X-Yours: Blah ---- response_body_like: 404 Not Found ---- error_code: 404 - - - -=== TEST 11: more conditions ---- config - location /bad { - more_set_headers -s '503 404' 'X-Mine: Hiya'; - more_set_headers -s ' 404 413 ' 'X-Yours: Blah'; - return 413; - } ---- request - GET /bad ---- response_headers -! X-Mine -X-Yours: Blah ---- response_body_like: 413 Request Entity Too Large ---- error_code: 413 - - - -=== TEST 12: simple -t ---- config - location /bad { - default_type 'text/css'; - more_set_headers -t 'text/css' 'X-CSS: yes'; - echo hi; - } ---- request - GET /bad ---- response_headers -X-CSS: yes ---- response_body -hi - - - -=== TEST 13: simple -t (not matched) ---- config - location /bad { - default_type 'text/plain'; - more_set_headers -t 'text/css' 'X-CSS: yes'; - echo hi; - } ---- request - GET /bad ---- response_headers -! X-CSS ---- response_body -hi - - - -=== TEST 14: multiple -t (not matched) ---- config - location /bad { - default_type 'text/plain'; - more_set_headers -t 'text/javascript' -t 'text/css' 'X-CSS: yes'; - echo hi; - } ---- request - GET /bad ---- response_headers -! X-CSS ---- response_body -hi - - - -=== TEST 15: multiple -t (matched) ---- config - location /bad { - default_type 'text/plain'; - more_set_headers -t 'text/javascript' -t 'text/plain' 'X-CSS: yes'; - echo hi; - } ---- request - GET /bad ---- response_headers -X-CSS: yes ---- response_body -hi - - - -=== TEST 16: multiple -t (matched) ---- config - location /bad { - default_type 'text/javascript'; - more_set_headers -t 'text/javascript' -t 'text/plain' 'X-CSS: yes'; - echo hi; - } ---- request - GET /bad ---- response_headers -X-CSS: yes ---- response_body -hi - - - -=== TEST 17: multiple -t (matched) with extra spaces ---- config - location /bad { - default_type 'text/javascript'; - more_set_headers -t ' text/javascript ' -t 'text/plain' 'X-CSS: yes'; - echo hi; - } ---- request - GET /bad ---- response_headers -X-CSS: yes ---- response_body -hi - - - -=== TEST 18: multiple -t merged ---- config - location /bad { - default_type 'text/javascript'; - more_set_headers -t ' text/javascript text/plain' 'X-CSS: yes'; - echo hi; - } ---- request - GET /bad ---- response_headers -X-CSS: yes ---- response_body -hi - - - -=== TEST 19: multiple -t merged (2) ---- config - location /bad { - default_type 'text/plain'; - more_set_headers -t ' text/javascript text/plain' 'X-CSS: yes'; - echo hi; - } ---- request - GET /bad ---- response_headers -X-CSS: yes ---- response_body -hi - - - -=== TEST 20: multiple -s option in a directive (not matched) ---- config - location /bad { - more_set_headers -s 404 -s 500 'X-status: howdy'; - echo hi; - } ---- request - GET /bad ---- response_headers -! X-status ---- response_body -hi - - - -=== TEST 21: multiple -s option in a directive (matched 404) ---- config - location /bad { - more_set_headers -s 404 -s 500 'X-status: howdy'; - return 404; - } ---- request - GET /bad ---- response_headers -X-status: howdy ---- response_body_like: 404 Not Found ---- error_code: 404 - - - -=== TEST 22: multiple -s option in a directive (matched 500) ---- config - location /bad { - more_set_headers -s 404 -s 500 'X-status: howdy'; - return 500; - } ---- request - GET /bad ---- response_headers -X-status: howdy ---- response_body_like: 500 Internal Server Error ---- error_code: 500 - - - -=== TEST 23: -s mixed with -t ---- config - location /bad { - default_type 'text/html'; - more_set_headers -s 404 -s 200 -t 'text/html' 'X-status: howdy2'; - return 404; - } ---- request - GET /bad ---- response_headers -X-status: howdy2 ---- response_body_like: 404 Not Found ---- error_code: 404 - - - -=== TEST 24: -s mixed with -t ---- config - location /bad { - default_type 'text/html'; - more_set_headers -s 404 -s 200 -t 'text/plain' 'X-status: howdy2'; - return 404; - } ---- request - GET /bad ---- response_headers -! X-status ---- response_body_like: 404 Not Found ---- error_code: 404 - - - -=== TEST 25: -s mixed with -t ---- config - location /bad { - default_type 'text/html'; - more_set_headers -s 404 -s 200 -t 'text/html' 'X-status: howdy2'; - echo hi; - } ---- request - GET /bad ---- response_headers -X-status: howdy2 ---- response_body -hi ---- error_code: 200 - - - -=== TEST 26: -s mixed with -t ---- config - location /bad { - default_type 'text/html'; - more_set_headers -s 500 -s 200 -t 'text/html' 'X-status: howdy2'; - return 404; - } ---- request - GET /bad ---- response_headers -! X-status ---- response_body_like: 404 Not Found ---- error_code: 404 - - - -=== TEST 27: merge from the upper level ---- config - more_set_headers -s 404 -t 'text/html' 'X-status2: howdy3'; - location /bad { - default_type 'text/html'; - more_set_headers -s 500 -s 200 -t 'text/html' 'X-status: howdy2'; - return 404; - } ---- request - GET /bad ---- response_headers -X-status2: howdy3 -! X-status ---- response_body_like: 404 Not Found ---- error_code: 404 - - - -=== TEST 28: merge from the upper level ---- config - more_set_headers -s 404 -t 'text/html' 'X-status2: howdy3'; - location /bad { - default_type 'text/html'; - more_set_headers -s 500 -s 200 -t 'text/html' 'X-status: howdy2'; - echo yeah; - } ---- request - GET /bad ---- response_headers -! X-status2 -X-status: howdy2 ---- response_body -yeah ---- error_code: 200 - - - -=== TEST 29: override settings by inheritance ---- config - more_set_headers -s 404 -t 'text/html' 'X-status: yeah'; - location /bad { - default_type 'text/html'; - more_set_headers -s 404 -t 'text/html' 'X-status: nope'; - return 404; - } ---- request - GET /bad ---- response_headers -X-status: nope ---- response_body_like: 404 Not Found ---- error_code: 404 - - - -=== TEST 30: append settings by inheritance ---- config - more_set_headers -s 404 -t 'text/html' 'X-status: yeah'; - location /bad { - default_type 'text/html'; - more_set_headers -s 404 -t 'text/html' 'X-status2: nope'; - return 404; - } ---- request - GET /bad ---- response_headers -X-status: yeah -X-status2: nope ---- response_body_like: 404 Not Found ---- error_code: 404 - - - -=== TEST 31: clear headers with wildcard ---- config - location = /backend { - add_header X-Hidden-One "i am hidden"; - add_header X-Hidden-Two "me 2"; - echo hi; - } - location /hello { - more_clear_headers 'X-Hidden-*'; - proxy_pass http://127.0.0.1:$server_port/backend; - } ---- request - GET /hello ---- response_headers -! X-Hidden-One -! X-Hidden-Two ---- response_body -hi - - - -=== TEST 32: clear duplicate headers ---- config - location = /backend { - add_header pragma no-cache; - add_header pragma no-cache; - echo hi; - } - location /hello { - more_clear_headers 'pragma'; - proxy_pass http://127.0.0.1:$server_port/backend; - } ---- request - GET /hello ---- response_headers -!pragma ---- response_body -hi - - - -=== TEST 33: HTTP 0.9 (set) ---- config - location /foo { - more_set_headers 'X-Foo: howdy'; - echo ok; - } ---- raw_request eval -"GET /foo\r\n" ---- response_headers -! X-Foo ---- response_body -ok ---- http09 diff --git a/debian/modules/http-headers-more-filter/t/subrequest.t b/debian/modules/http-headers-more-filter/t/subrequest.t deleted file mode 100644 index 9443eca..0000000 --- a/debian/modules/http-headers-more-filter/t/subrequest.t +++ /dev/null @@ -1,68 +0,0 @@ -# vi:filetype= - -use lib 'lib'; -use Test::Nginx::Socket; # 'no_plan'; - -plan tests => blocks() * 3; - -no_diff; - -run_tests(); - -__DATA__ - -=== TEST 1: vars in input header directives ---- config - location /main { - echo_location /foo; - echo "main: $http_user_agent"; - } - location /foo { - set $val 'dog'; - - more_set_input_headers 'User-Agent: $val'; - - proxy_pass http://127.0.0.1:$server_port/proxy; - } - location /proxy { - echo "sub: $http_user_agent"; - } ---- request - GET /main ---- more_headers -User-Agent: my-sock ---- response_body -sub: dog -main: dog ---- response_headers -! Host ---- skip_nginx: 3: < 0.7.46 - - - -=== TEST 2: vars in input header directives ---- config - location /main { - #more_set_input_headers 'User-Agent: cat'; - echo_location /foo; - echo "main: $http_user_agent"; - } - location /foo { - set $val 'dog'; - - more_set_input_headers 'User-Agent: $val'; - - proxy_pass http://127.0.0.1:$server_port/proxy; - #echo $http_user_agent; - } - location /proxy { - echo "sub: $http_user_agent"; - } ---- request - GET /main ---- response_body -sub: dog -main: dog ---- response_headers -! Host ---- skip_nginx: 3: < 0.7.46 diff --git a/debian/modules/http-headers-more-filter/t/unused.t b/debian/modules/http-headers-more-filter/t/unused.t deleted file mode 100644 index c51f91c..0000000 --- a/debian/modules/http-headers-more-filter/t/unused.t +++ /dev/null @@ -1,174 +0,0 @@ -# vi:filetype= - -use lib 'lib'; -use Test::Nginx::Socket; - -repeat_each(2); - -plan tests => repeat_each() * (blocks() * 4 + 2); - -#master_on(); -#workers(2); -log_level("warn"); -no_diff; - -run_tests(); - -__DATA__ - -=== TEST 1: used output filter ---- config - location /foo { - echo hi; - more_set_headers "Foo: bar"; - } ---- request - GET /foo ---- response_headers -Foo: bar ---- response_body -hi ---- error_log -headers more header filter ---- no_error_log -[error] ---- log_level: debug - - - -=== TEST 2: unused output filter (none) ---- config - location /foo { - echo hi; - } ---- request - GET /foo ---- response_body -hi ---- no_error_log -headers more header filter -[error] ---- log_level: debug - - - -=== TEST 3: unused output filter (with more_set_input_headers only) ---- config - location /foo { - more_set_input_headers "Foo: bar"; - echo hi; - } ---- request - GET /foo ---- response_body -hi ---- no_error_log -headers more header filter -[error] ---- log_level: debug - - - -=== TEST 4: used rewrite handler ---- config - location /foo { - more_set_input_headers "Foo: bar"; - echo hi; - } ---- request - GET /foo ---- response_body -hi ---- error_log -headers more rewrite handler ---- no_error_log -[error] ---- log_level: debug - - - -=== TEST 5: unused rewrite handler (none) ---- config - location /foo { - #more_set_input_headers "Foo: bar"; - echo hi; - } ---- request - GET /foo ---- response_body -hi ---- no_error_log -headers more rewrite handler -[error] ---- log_level: debug - - - -=== TEST 6: unused rewrite handler (with output header filters) ---- config - location /foo { - #more_set_input_headers "Foo: bar"; - echo hi; - more_set_headers "Foo: bar"; - } ---- request - GET /foo ---- response_headers -Foo: bar ---- response_body -hi ---- no_error_log -headers more rewrite handler -[error] ---- log_level: debug - - - -=== TEST 7: multiple http {} blocks (filter) -This test case won't run with nginx 1.9.3+ since duplicate http {} blocks -have been prohibited since then. ---- SKIP ---- config - location /foo { - echo hi; - more_set_headers 'Foo: bar'; - } ---- post_main_config - http { - } - ---- request - GET /foo ---- response_body -hi ---- response_headers -Foo: bar ---- no_error_log -[error] ---- error_log -headers more header filter ---- log_level: debug - - - -=== TEST 8: multiple http {} blocks (handler) -This test case won't run with nginx 1.9.3+ since duplicate http {} blocks -have been prohibited since then. ---- SKIP ---- config - location /foo { - more_set_input_headers 'Foo: bar'; - echo $http_foo; - } ---- post_main_config - http { - } - ---- request - GET /foo ---- response_body -bar ---- no_error_log -headers more header handler -[error] ---- log_level: debug diff --git a/debian/modules/http-headers-more-filter/t/vars.t b/debian/modules/http-headers-more-filter/t/vars.t deleted file mode 100644 index 04c75c3..0000000 --- a/debian/modules/http-headers-more-filter/t/vars.t +++ /dev/null @@ -1,58 +0,0 @@ -# vi:ft= - -use lib 'lib'; -use Test::Nginx::Socket; # 'no_plan'; - -plan tests => 9; - -no_diff; - -run_tests(); - -__DATA__ - -=== TEST 1: vars ---- config - location /foo { - echo hi; - set $val 'hello, world'; - more_set_headers 'X-Foo: $val'; - } ---- request - GET /foo ---- response_headers -X-Foo: hello, world ---- response_body -hi - - - -=== TEST 2: vars in both key and val ---- config - location /foo { - echo hi; - set $val 'hello, world'; - more_set_headers '$val: $val'; - } ---- request - GET /foo ---- response_headers -$val: hello, world ---- response_body -hi - - - -=== TEST 3: vars in input header directives ---- config - location /foo { - set $val 'dog'; - more_set_input_headers 'Host: $val'; - echo $host; - } ---- request - GET /foo ---- response_body -dog ---- response_headers -Host: diff --git a/debian/modules/http-headers-more-filter/util/build.sh b/debian/modules/http-headers-more-filter/util/build.sh deleted file mode 100755 index 007194d..0000000 --- a/debian/modules/http-headers-more-filter/util/build.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/bash - -# this file is mostly meant to be used by the author himself. - -root=`pwd` -version=$1 -home=~ -force=$2 - - #--with-cc=gcc46 \ - -ngx-build $force $version \ - --with-ld-opt="-L$PCRE_LIB -Wl,-rpath,$PCRE_LIB:$LIBDRIZZLE_LIB" \ - --without-mail_pop3_module \ - --without-mail_imap_module \ - --without-mail_smtp_module \ - --without-http_upstream_ip_hash_module \ - --without-http_empty_gif_module \ - --without-http_memcached_module \ - --without-http_referer_module \ - --without-http_autoindex_module \ - --without-http_auth_basic_module \ - --without-http_userid_module \ - --with-http_realip_module \ - --with-http_dav_module \ - --add-module=$root/../eval-nginx-module \ - --add-module=$root/../lua-nginx-module \ - --add-module=$root/../echo-nginx-module \ - --add-module=$root $opts \ - --with-debug - #--add-module=$root/../ndk-nginx-module \ - #--without-http_ssi_module # we cannot disable ssi because echo_location_async depends on it (i dunno why?!) - diff --git a/debian/modules/http-headers-more-filter/valgrind.suppress b/debian/modules/http-headers-more-filter/valgrind.suppress deleted file mode 100644 index d51de70..0000000 --- a/debian/modules/http-headers-more-filter/valgrind.suppress +++ /dev/null @@ -1,135 +0,0 @@ -{ - - Memcheck:Leak - fun:malloc - fun:ngx_alloc - obj:* -} -{ - - Memcheck:Leak - fun:malloc - fun:ngx_alloc - fun:ngx_calloc - fun:ngx_event_process_init -} -{ - - Memcheck:Leak - fun:malloc - fun:ngx_alloc - fun:ngx_event_process_init -} -{ - - Memcheck:Param - epoll_ctl(event) - fun:epoll_ctl -} -{ - - Memcheck:Cond - fun:memcpy - fun:ngx_vslprintf - fun:ngx_log_error_core - fun:ngx_http_charset_header_filter -} -{ - nginx-core-process-init - Memcheck:Leak - fun:malloc - fun:ngx_alloc - fun:ngx_event_process_init -} -{ - nginx-core-crc32-init - Memcheck:Leak - fun:malloc - fun:ngx_alloc - fun:ngx_crc32_table_init - fun:main -} -{ - palloc_large_for_init_request - Memcheck:Leak - fun:malloc - fun:ngx_alloc - fun:ngx_palloc_large - fun:ngx_palloc - fun:ngx_pcalloc - fun:ngx_http_init_request - fun:ngx_epoll_process_events - fun:ngx_process_events_and_timers -} -{ - palloc_large_for_create_temp_buf - Memcheck:Leak - fun:malloc - fun:ngx_alloc - fun:ngx_palloc_large - fun:ngx_palloc - fun:ngx_create_temp_buf - fun:ngx_http_init_request - fun:ngx_epoll_process_events - fun:ngx_process_events_and_timers -} -{ - accept_create_pool - Memcheck:Leak - fun:memalign - fun:posix_memalign - fun:ngx_memalign - fun:ngx_create_pool - fun:ngx_event_accept - fun:ngx_epoll_process_events - fun:ngx_process_events_and_timers -} -{ - create_pool_for_init_req - Memcheck:Leak - fun:memalign - fun:posix_memalign - fun:ngx_memalign - fun:ngx_create_pool - fun:ngx_http_init_request - fun:ngx_epoll_process_events - fun:ngx_process_events_and_timers -} -{ - - Memcheck:Addr8 - fun:getenv - fun:gcov_exit - fun:exit - fun:ngx_master_process_exit -} -{ - - Memcheck:Cond - fun:index - fun:expand_dynamic_string_token - fun:_dl_map_object - fun:map_doit - fun:_dl_catch_error - fun:do_preload - fun:dl_main -} -{ - - Memcheck:Leak - match-leak-kinds: definite - fun:malloc - fun:ngx_alloc - fun:ngx_set_environment - fun:ngx_single_process_cycle -} -{ - - Memcheck:Leak - match-leak-kinds: definite - fun:malloc - fun:ngx_alloc - fun:ngx_set_environment - fun:ngx_worker_process_init - fun:ngx_worker_process_cycle -} diff --git a/debian/modules/http-subs-filter/CHANGES b/debian/modules/http-subs-filter/CHANGES deleted file mode 100644 index b8a7ef1..0000000 --- a/debian/modules/http-subs-filter/CHANGES +++ /dev/null @@ -1,37 +0,0 @@ - -Changes with nginx_substitutions_filter 0.6.4 2014-02-15 - - *) Now non-200 response will work - *) added the subs_filter_bypass directive - -Changes with nginx_substitutions_filter 0.6.2 2012-08-26 - - *) fixed a bug of buffer overlap - *) fixed a bug with last zero buffer - -Changes with nginx_substitutions_filter 0.6.0 2012-06-30 - - *) refactor this module - -Changes with nginx_substitutions_filter 0.5.2 2010-08-11 - - *) do many optimizing for this module - *) fix a bug of buffer overlap - *) fix a segment fault bug when output chain return NGX_AGAIN. - *) fix a bug about last buffer with no linefeed. This may cause segment fault. Thanks for Josef Fröhle - -Changes with nginx_substitutions_filter 0.5 2010-04-15 - - *) refactor the source structure, create branches of dev - *) fix a bug of small chunk of buffers causing lose content - *) fix the bug of last_buf and the nginx's compatibility above 0.8.25 - *) fix a bug with unwanted capture config error in fix string substitution - *) add feature of regex captures - -Changes with nginx_substitutions_filter 0.4 2009-12-23 - - *) fix many bugs - -Changes with nginx_substitutions_filter 0.3 2009-02-04 - - *) Initial public release diff --git a/debian/modules/http-subs-filter/README b/debian/modules/http-subs-filter/README deleted file mode 100644 index 1d32e05..0000000 --- a/debian/modules/http-subs-filter/README +++ /dev/null @@ -1,141 +0,0 @@ -nginx_substitutions_filter - *Note: this module is not distributed with the Nginx source. - Installation instructions can be found below.* - - Description - nginx_substitutions_filter is a filter module which can do both regular - expression and fixed string substitutions on response bodies. This - module is quite different from the Nginx's native Substitution Module. - It scans the output chains buffer and matches string line by line, just - like Apache's mod_substitute - (). - - Example - location / { - - subs_filter_types text/html text/css text/xml; - subs_filter st(\d*).example.com $1.example.com ir; - subs_filter a.example.com s.example.com; - - } - - Directives - * subs_filter_types - - * subs_filter - - subs_filter_types - syntax: *subs_filter_types mime-type [mime-types] * - - default: *subs_filter_types text/html* - - context: *http, server, location* - - *subs_filter_types* is used to specify which content types should be - checked for *subs_filter*. The default is only *text/html*. - - This module just works with plain text. If the response is compressed, - it can't uncompress the response and will ignore this response. This - module can be compatible with gzip filter module. But it will not work - with proxy compressed response. You can disable the compressed response - like this: - - proxy_set_header Accept-Encoding ""; - - subs_filter - syntax: *subs_filter source_str destination_str [gior] * - - default: *none* - - context: *http, server, location* - - *subs_filter* allows replacing source string(regular expression or - fixed) in the nginx response with destination string. Substitution text - may contain variables. More than one substitution rules per location is - supported. The meaning of the third flags are: - - * *g*(default): Replace all the match strings. - - * *i*: Perform a case-insensitive match. - - * *o*: Just replace the first one. - - * *r*: The pattern is treated as a regular expression, default is - fixed string. - - subs_filter_bypass - syntax: *subs_filter_bypass $variable1 ...* - - default: *none* - - context: *http, server, location* - - You can sepcify several variables with this directive. If at least one - of the variable is not empty and is not equal to '0', this substitution - filter will be disabled. - - Installation - To install, get the source with subversion: - - git clone - git://github.com/yaoweibin/ngx_http_substitutions_filter_module.git - - and then compile nginx with the following option: - - ./configure --add-module=/path/to/module - - Known issue - * Can't substitute the response header. - - CHANGES - Changes with nginx_substitutions_filter 0.6.4 2014-02-15 - - * Now non-200 response will work - - * added the subs_filter_bypass directive - - Changes with nginx_substitutions_filter 0.6.2 2012-08-26 - - * fixed a bug of buffer overlap - - * fixed a bug with last zero buffer - - Changes with nginx_substitutions_filter 0.6.0 2012-06-30 - - * refactor this module - - Changes with nginx_substitutions_filter 0.5.2 2010-08-11 - - * do many optimizing for this module - - * fix a bug of buffer overlap - - * fix a segment fault bug when output chain return NGX_AGAIN. - - * fix a bug about last buffer with no linefeed. This may cause segment - fault. Thanks for Josef Fröhle - - Changes with nginx_substitutions_filter 0.5 2010-04-15 - - * refactor the source structure, create branches of dev - - * fix a bug of small chunk of buffers causing lose content - - * fix the bug of last_buf and the nginx's compatibility above 0.8.25 - - * fix a bug with unwanted capture config error in fix string - substitution - - * add feature of regex captures - - Changes with nginx_substitutions_filter 0.4 2009-12-23 - - * fix many bugs - - Changes with nginx_substitutions_filter 0.3 2009-02-04 - - * Initial public release - - Reporting a bug - Questions/patches may be directed to Weibin Yao, yaoweibin@gmail.com. - diff --git a/debian/modules/http-subs-filter/config b/debian/modules/http-subs-filter/config deleted file mode 100644 index fdb016c..0000000 --- a/debian/modules/http-subs-filter/config +++ /dev/null @@ -1,3 +0,0 @@ -ngx_addon_name=ngx_http_subs_filter_module -HTTP_AUX_FILTER_MODULES="$HTTP_AUX_FILTER_MODULES ngx_http_subs_filter_module" -NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_subs_filter_module.c" diff --git a/debian/modules/http-subs-filter/doc/README.google_code_home_page.wiki b/debian/modules/http-subs-filter/doc/README.google_code_home_page.wiki deleted file mode 100644 index 6a158a2..0000000 --- a/debian/modules/http-subs-filter/doc/README.google_code_home_page.wiki +++ /dev/null @@ -1,120 +0,0 @@ -= nginx_substitutions_filter = - -_Note: this module is not distributed with the Nginx source. Installation instructions can be found [#Installation below]._ - -== Description == - -`nginx_substitutions_filter` is a filter module which can do both regular expression and fixed string substitutions on response bodies. This module is quite different from the Nginx's native Substitution Module. It scans the output chains buffer and matches string line by line, just like Apache's [http://httpd.apache.org/docs/trunk/mod/mod_substitute.html mod_substitute]. - -== Example == - -{{{ -location / { - - subs_filter_types text/html text/css text/xml; - subs_filter st(\d*).example.com $1.example.com ir; - subs_filter a.example.com s.example.com; - -} -}}} -== Directives == - - * [#subs_filter_types subs_filter_types] - * [#subs_filter subs_filter] - -=== subs_filter_types === - -`syntax:` _subs_filter_types mime-type `[`mime-types`]` _ - -`default:` _subs_filter_types text/html_ - -`context:` _http, server, location_ - -_subs_filter_types_ is used to specify which content types should be checked for _subs_filter_. The default is only _text/html_. - -This module just works with plain text. If the response is compressed, it can't uncompress the response and will ignore this response. This module can be compatible with gzip filter module. But it will not work with proxy compressed response. You can disable the compressed response like this: - -proxy_set_header Accept-Encoding ""; - -=== subs_filter === - -`syntax:` _subs_filter source_str destination_str `[`gior`]` _ - -`default:` _none_ - -`context:` _http, server, location_ - -_subs_filter_ allows replacing source string(regular expression or fixed) in the nginx response with destination string. Substitution text may contain variables. More than one substitution rules per location is supported. The meaning of the third flags are: - * _g_(default): Replace all the match strings. - * _i_: Perform a case-insensitive match. - * _o_: Just replace the first one. - * _r_: The pattern is treated as a regular expression, default is fixed string. - -=== subs_filter_bypass === - -`syntax:` _subs_filter_bypass $variable1 ..._ - -`default:` _none_ - -`context:` _http, server, location_ - -You can sepcify several variables with this directive. If at least one of the variable is not empty and is not equal to '0', this substitution filter will be disabled. - -== Installation == - -To install, get the source with subversion: - -{{{ -git clone git://github.com/yaoweibin/ngx_http_substitutions_filter_module.git -}}} -and then compile nginx with the following option: - -{{{ -./configure --add-module=/path/to/module -}}} -== Known issue == - * Can't substitute the response header. - -== CHANGES == - -Changes with nginx_substitutions_filter 0.6.4 2014-02-15 - - * Now non-200 response will work - * added the subs_filter_bypass directive - -Changes with nginx_substitutions_filter 0.6.2 2012-08-26 - - * fixed a bug of buffer overlap - * fixed a bug with last zero buffer - -Changes with nginx_substitutions_filter 0.6.0 2012-06-30 - - * refactor this module - -Changes with nginx_substitutions_filter 0.5.2 2010-08-11 - - * do many optimizing for this module - * fix a bug of buffer overlap - * fix a segment fault bug when output chain return NGX_AGAIN. - * fix a bug about last buffer with no linefeed. This may cause segment fault. Thanks for Josef Fröhle - -Changes with nginx_substitutions_filter 0.5 2010-04-15 - - * refactor the source structure, create branches of dev - * fix a bug of small chunk of buffers causing lose content - * fix the bug of last_buf and the nginx's compatibility above 0.8.25 - * fix a bug with unwanted capture config error in fix string substitution - * add feature of regex captures - -Changes with nginx_substitutions_filter 0.4 2009-12-23 - - * fix many bugs - -Changes with nginx_substitutions_filter 0.3 2009-02-04 - - * Initial public release - -== Reporting a bug == - -Questions/patches may be directed to Weibin Yao, yaoweibin@gmail.com. - diff --git a/debian/modules/http-subs-filter/doc/README.html b/debian/modules/http-subs-filter/doc/README.html deleted file mode 100644 index 28c6810..0000000 --- a/debian/modules/http-subs-filter/doc/README.html +++ /dev/null @@ -1,199 +0,0 @@ - - - - -nginx_substitutions_filter - - - - - - -

- - - - - -
-

-

-

nginx_substitutions_filter

-

Note: this module is not distributed with the Nginx source. Installation instructions can be found below. >

-

-

-

Description

-

nginx_substitutions_filter is a filter module which can do both regular expression and fixed string substitutions on response bodies. This module is quite different from the Nginx's native Substitution Module. It scans the output chains buffer and matches string line by line, just like Apache's mod_substitute (http://httpd.apache.org/docs/trunk/mod/mod_substitute.html).

-

-

-

Example

-

location / {

-
-    subs_filter_types text/html text/css text/xml;
-    subs_filter st(\d*).example.com $1.example.com ir;
-    subs_filter a.example.com s.example.com;
-

}

-

-

-

Directives

- -

-

-

subs_filter_types

-

syntax: subs_filter_types mime-type [mime-types]

-

default: subs_filter_types text/html

-

context: http, server, location

-

subs_filter_types is used to specify which content types should be checked for subs_filter. The default is only text/html.

-

This module just works with plain text. If the response is compressed, it can't uncompress the response and will ignore this response. This module can be compatible with gzip filter module. But it will not work with proxy compressed response. You can disable the compressed response like this:

-

proxy_set_header Accept-Encoding ``'';

-

-

-

subs_filter

-

syntax: subs_filter source_str destination_str [gior]

-

default: none

-

context: http, server, location

-

subs_filter allows replacing source string(regular expression or fixed) in the nginx response with destination string. Substitution text may contain variables. More than one substitution rules per location is supported. The meaning of the third flags are:

-
    -
  • -

    g(default): Replace all the match strings.

    -
  • -
  • -

    i: Perform a case-insensitive match.

    -
  • -
  • -

    o: Just replace the first one.

    -
  • -
  • -

    r: The pattern is treated as a regular expression, default is fixed string.

    -
  • -
-

-

-

subs_filter_bypass

-

syntax: subs_filter_bypass $variable1 ...

-

default: none

-

context: http, server, location

-

You can sepcify several variables with this directive. If at least one of the variable is not empty and is not equal to '0', this substitution filter will be disabled.

-

-

-

Installation

-

To install, get the source with subversion:

-

git clone git://github.com/yaoweibin/ngx_http_substitutions_filter_module.git

-

and then compile nginx with the following option:

-

./configure --add-module=/path/to/module

-

-

-

Known issue

-
    -
  • -

    Can't substitute the response header.

    -
  • -
-

-

-

CHANGES

-

Changes with nginx_substitutions_filter 0.6.4 2014-02-15

-
    -
  • -

    Now non-200 response will work

    -
  • -
  • -

    added the subs_filter_bypass directive

    -
  • -
-

Changes with nginx_substitutions_filter 0.6.2 2012-08-26

-
    -
  • -

    fixed a bug of buffer overlap

    -
  • -
  • -

    fixed a bug with last zero buffer

    -
  • -
-

Changes with nginx_substitutions_filter 0.6.0 2012-06-30

-
    -
  • -

    refactor this module

    -
  • -
-

Changes with nginx_substitutions_filter 0.5.2 2010-08-11

-
    -
  • -

    do many optimizing for this module

    -
  • -
  • -

    fix a bug of buffer overlap

    -
  • -
  • -

    fix a segment fault bug when output chain return NGX_AGAIN.

    -
  • -
  • -

    fix a bug about last buffer with no linefeed. This may cause segment fault. Thanks for Josef Fröhle

    -
  • -
-

Changes with nginx_substitutions_filter 0.5 2010-04-15

-
    -
  • -

    refactor the source structure, create branches of dev

    -
  • -
  • -

    fix a bug of small chunk of buffers causing lose content

    -
  • -
  • -

    fix the bug of last_buf and the nginx's compatibility above 0.8.25

    -
  • -
  • -

    fix a bug with unwanted capture config error in fix string substitution

    -
  • -
  • -

    add feature of regex captures

    -
  • -
-

Changes with nginx_substitutions_filter 0.4 2009-12-23

-
    -
  • -

    fix many bugs

    -
  • -
-

Changes with nginx_substitutions_filter 0.3 2009-02-04

-
    -
  • -

    Initial public release

    -
  • -
-

-

-

Reporting a bug

-

Questions/patches may be directed to Weibin Yao, yaoweibin@gmail.com.

- - - - diff --git a/debian/modules/http-subs-filter/doc/README.wiki b/debian/modules/http-subs-filter/doc/README.wiki deleted file mode 100644 index b707f45..0000000 --- a/debian/modules/http-subs-filter/doc/README.wiki +++ /dev/null @@ -1,123 +0,0 @@ -= nginx_substitutions_filter = - -''Note: this module is not distributed with the Nginx source. Installation instructions can be found [[#Installation|below]].'' - -== Description == - -'''nginx_substitutions_filter''' is a filter module which can do both regular expression and fixed string substitutions on response bodies. This module is quite different from the Nginx's native Substitution Module. It scans the output chains buffer and matches string line by line, just like Apache's [http://httpd.apache.org/docs/trunk/mod/mod_substitute.html mod_substitute]. - -== Example == - - -location / { - - subs_filter_types text/html text/css text/xml; - subs_filter st(\d*).example.com $1.example.com ir; - subs_filter a.example.com s.example.com; - -} - - -== Directives == - -* [[#subs_filter_types|subs_filter_types]] -* [[#subs_filter|subs_filter]] - -=== subs_filter_types === - -'''syntax:''' ''subs_filter_types mime-type [mime-types] '' - -'''default:''' ''subs_filter_types text/html'' - -'''context:''' ''http, server, location'' - -''subs_filter_types'' is used to specify which content types should be checked for ''subs_filter''. The default is only ''text/html''. - -This module just works with plain text. If the response is compressed, it can't uncompress the response and will ignore this response. This module can be compatible with gzip filter module. But it will not work with proxy compressed response. You can disable the compressed response like this: - -proxy_set_header Accept-Encoding ""; - -=== subs_filter === - -'''syntax:''' ''subs_filter source_str destination_str [gior] '' - -'''default:''' ''none'' - -'''context:''' ''http, server, location'' - -''subs_filter'' allows replacing source string(regular expression or fixed) in the nginx response with destination string. Substitution text may contain variables. More than one substitution rules per location is supported. The meaning of the third flags are: -* ''g''(default): Replace all the match strings. -* ''i'': Perform a case-insensitive match. -* ''o'': Just replace the first one. -* ''r'': The pattern is treated as a regular expression, default is fixed string. - -=== subs_filter_bypass === - -'''syntax:''' ''subs_filter_bypass $variable1 ...'' - -'''default:''' ''none'' - -'''context:''' ''http, server, location'' - -You can sepcify several variables with this directive. If at least one of the variable is not empty and is not equal to '0', this substitution filter will be disabled. - -== Installation == - -To install, get the source with subversion: - - -git clone git://github.com/yaoweibin/ngx_http_substitutions_filter_module.git - - -and then compile nginx with the following option: - - -./configure --add-module=/path/to/module - - -== Known issue == -* Can't substitute the response header. - -== CHANGES == - -Changes with nginx_substitutions_filter 0.6.4 2014-02-15 - -* Now non-200 response will work -* added the subs_filter_bypass directive - -Changes with nginx_substitutions_filter 0.6.2 2012-08-26 - -* fixed a bug of buffer overlap -* fixed a bug with last zero buffer - -Changes with nginx_substitutions_filter 0.6.0 2012-06-30 - -* refactor this module - -Changes with nginx_substitutions_filter 0.5.2 2010-08-11 - -* do many optimizing for this module -* fix a bug of buffer overlap -* fix a segment fault bug when output chain return NGX_AGAIN. -* fix a bug about last buffer with no linefeed. This may cause segment fault. Thanks for Josef Fröhle - -Changes with nginx_substitutions_filter 0.5 2010-04-15 - -* refactor the source structure, create branches of dev -* fix a bug of small chunk of buffers causing lose content -* fix the bug of last_buf and the nginx's compatibility above 0.8.25 -* fix a bug with unwanted capture config error in fix string substitution -* add feature of regex captures - -Changes with nginx_substitutions_filter 0.4 2009-12-23 - -* fix many bugs - -Changes with nginx_substitutions_filter 0.3 2009-02-04 - -* Initial public release - -== Reporting a bug == - -Questions/patches may be directed to Weibin Yao, yaoweibin@gmail.com. - diff --git a/debian/modules/http-subs-filter/ngx_http_subs_filter_module.c b/debian/modules/http-subs-filter/ngx_http_subs_filter_module.c deleted file mode 100644 index 483c9c3..0000000 --- a/debian/modules/http-subs-filter/ngx_http_subs_filter_module.c +++ /dev/null @@ -1,1298 +0,0 @@ -/* - * Author: Weibin Yao(yaoweibin@gmail.com) - * - * Licence: This module could be distributed under the - * same terms as Nginx itself. - */ - - -#include -#include -#include -#include - - -#if (NGX_DEBUG) -#define SUBS_DEBUG 1 -#else -#define SUBS_DEBUG 0 -#endif - - -#ifndef NGX_HTTP_MAX_CAPTURES -#define NGX_HTTP_MAX_CAPTURES 9 -#endif - - -#define ngx_buffer_init(b) b->pos = b->last = b->start; - - -typedef struct { - ngx_flag_t once; - ngx_flag_t regex; - ngx_flag_t insensitive; - - /* If it has captured variables? */ - ngx_flag_t has_captured; - - ngx_str_t match; -#if (NGX_PCRE) - ngx_regex_t *match_regex; - int *captures; - ngx_int_t ncaptures; -#endif - - ngx_str_t sub; - ngx_array_t *sub_lengths; - ngx_array_t *sub_values; - - unsigned matched; -} sub_pair_t; - - -typedef struct { - ngx_hash_t types; - ngx_array_t *sub_pairs; /* array of sub_pair_t */ - ngx_array_t *types_keys; /* array of ngx_hash_key_t */ - ngx_array_t *bypass; /* array of ngx_http_complex_value_t */ - size_t line_buffer_size; - ngx_bufs_t bufs; -} ngx_http_subs_loc_conf_t; - - -typedef struct { - ngx_array_t *sub_pairs; /* array of sub_pair_t */ - - ngx_chain_t *in; - - /* the line input buffer before substitution */ - ngx_buf_t *line_in; - /* the line destination buffer after substitution */ - ngx_buf_t *line_dst; - - /* the last output buffer */ - ngx_buf_t *out_buf; - /* point to the last output chain's next chain */ - ngx_chain_t **last_out; - ngx_chain_t *out; - - ngx_chain_t *busy; - - /* the freed chain buffers. */ - ngx_chain_t *free; - - ngx_int_t bufs; - - unsigned last; - -} ngx_http_subs_ctx_t; - - -static ngx_int_t ngx_http_subs_header_filter(ngx_http_request_t *r); -static ngx_int_t ngx_http_subs_init_context(ngx_http_request_t *r); - -static ngx_int_t ngx_http_subs_body_filter(ngx_http_request_t *r, - ngx_chain_t *in); -static ngx_int_t ngx_http_subs_body_filter_init_context(ngx_http_request_t *r, - ngx_chain_t *in); -static ngx_int_t ngx_http_subs_body_filter_process_buffer(ngx_http_request_t *r, - ngx_buf_t *b); -static ngx_int_t ngx_http_subs_match(ngx_http_request_t *r, - ngx_http_subs_ctx_t *ctx); -#if (NGX_PCRE) -static ngx_int_t ngx_http_subs_match_regex_substituion(ngx_http_request_t *r, - sub_pair_t *pair, ngx_buf_t *b, ngx_buf_t *dst); -#endif -static ngx_int_t ngx_http_subs_match_fix_substituion(ngx_http_request_t *r, - sub_pair_t *pair, ngx_buf_t *b, ngx_buf_t *dst); -static ngx_buf_t * buffer_append_string(ngx_buf_t *b, u_char *s, size_t len, - ngx_pool_t *pool); -static ngx_int_t ngx_http_subs_out_chain_append(ngx_http_request_t *r, - ngx_http_subs_ctx_t *ctx, ngx_buf_t *b); -static ngx_int_t ngx_http_subs_get_chain_buf(ngx_http_request_t *r, - ngx_http_subs_ctx_t *ctx); -static ngx_int_t ngx_http_subs_output(ngx_http_request_t *r, - ngx_http_subs_ctx_t *ctx, ngx_chain_t *in); - -static char * ngx_http_subs_filter(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf); -static ngx_int_t ngx_http_subs_filter_regex_compile(sub_pair_t *pair, - ngx_http_script_compile_t *sc, ngx_conf_t *cf); - - -static void *ngx_http_subs_create_conf(ngx_conf_t *cf); -static char *ngx_http_subs_merge_conf(ngx_conf_t *cf, void *parent, - void *child); - -static ngx_int_t ngx_http_subs_filter_init(ngx_conf_t *cf); - -#if (NGX_PCRE) -static ngx_int_t ngx_http_subs_regex_capture_count(ngx_regex_t *re); -#endif - - -static ngx_command_t ngx_http_subs_filter_commands[] = { - - { ngx_string("subs_filter"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_2MORE, - ngx_http_subs_filter, - NGX_HTTP_LOC_CONF_OFFSET, - 0, - NULL }, - - { ngx_string("subs_filter_bypass"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, - ngx_http_set_predicate_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_subs_loc_conf_t, bypass), - NULL }, - - { ngx_string("subs_filter_types"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, - ngx_http_types_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_subs_loc_conf_t, types_keys), - &ngx_http_html_default_types[0] }, - - { ngx_string("subs_line_buffer_size"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2, - ngx_conf_set_size_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_subs_loc_conf_t, line_buffer_size), - NULL }, - - { ngx_string("subs_buffers"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2, - ngx_conf_set_bufs_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_subs_loc_conf_t, bufs), - NULL }, - - ngx_null_command -}; - - -static ngx_http_module_t ngx_http_subs_filter_module_ctx = { - NULL, /* preconfiguration */ - ngx_http_subs_filter_init, /* postconfiguration */ - - NULL, /* create main configuration */ - NULL, /* init main configuration */ - - NULL, /* create server configuration */ - NULL, /* merge server configuration */ - - ngx_http_subs_create_conf, /* create location configuration */ - ngx_http_subs_merge_conf /* merge location configuration */ -}; - - -ngx_module_t ngx_http_subs_filter_module = { - NGX_MODULE_V1, - &ngx_http_subs_filter_module_ctx, /* module context */ - ngx_http_subs_filter_commands, /* module directives */ - NGX_HTTP_MODULE, /* module type */ - NULL, /* init master */ - NULL, /* init module */ - NULL, /* init process */ - NULL, /* init thread */ - NULL, /* exit thread */ - NULL, /* exit process */ - NULL, /* exit master */ - NGX_MODULE_V1_PADDING -}; - - -static ngx_http_output_header_filter_pt ngx_http_next_header_filter; -static ngx_http_output_body_filter_pt ngx_http_next_body_filter; - -extern volatile ngx_cycle_t *ngx_cycle; - - -static ngx_int_t -ngx_http_subs_header_filter(ngx_http_request_t *r) -{ - ngx_http_subs_loc_conf_t *slcf; - - slcf = ngx_http_get_module_loc_conf(r, ngx_http_subs_filter_module); - - if (slcf->sub_pairs->nelts == 0 - || r->header_only - || r->headers_out.content_type.len == 0 - || r->headers_out.content_length_n == 0) - { - return ngx_http_next_header_filter(r); - } - - if (ngx_http_test_content_type(r, &slcf->types) == NULL) { - return ngx_http_next_header_filter(r); - } - - switch (ngx_http_test_predicates(r, slcf->bypass)) { - - case NGX_ERROR: - /*pass through*/ - - case NGX_DECLINED: - - return ngx_http_next_header_filter(r); - - default: /* NGX_OK */ - break; - } - - /* Don't do substitution with the compressed content */ - if (r->headers_out.content_encoding - && r->headers_out.content_encoding->value.len) { - - ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, - "http subs filter header ignored, this may be a " - "compressed response."); - - return ngx_http_next_header_filter(r); - } - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http subs filter header \"%V\"", &r->uri); - - if (ngx_http_subs_init_context(r) == NGX_ERROR) { - return NGX_ERROR; - } - - r->filter_need_in_memory = 1; - - if (r == r->main) { - ngx_http_clear_content_length(r); - ngx_http_clear_last_modified(r); - } - - return ngx_http_next_header_filter(r); -} - - -static ngx_int_t -ngx_http_subs_init_context(ngx_http_request_t *r) -{ - ngx_uint_t i; - sub_pair_t *src_pair, *dst_pair; - ngx_http_subs_ctx_t *ctx; - ngx_http_subs_loc_conf_t *slcf; - - slcf = ngx_http_get_module_loc_conf(r, ngx_http_subs_filter_module); - - /* Everything in ctx is NULL or 0. */ - ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_subs_ctx_t)); - if (ctx == NULL) { - return NGX_ERROR; - } - - ngx_http_set_ctx(r, ctx, ngx_http_subs_filter_module); - - ctx->sub_pairs = ngx_array_create(r->pool, slcf->sub_pairs->nelts, - sizeof(sub_pair_t)); - if (slcf->sub_pairs == NULL) { - return NGX_ERROR; - } - - /* Deep copy sub_pairs from slcf to ctx, matched and captures need it */ - src_pair = (sub_pair_t *) slcf->sub_pairs->elts; - - for (i = 0; i < slcf->sub_pairs->nelts; i++) { - - dst_pair = ngx_array_push(ctx->sub_pairs); - if (dst_pair == NULL) { - return NGX_ERROR; - } - - ngx_memcpy(dst_pair, src_pair + i, sizeof(sub_pair_t)); - } - - if (ctx->line_in == NULL) { - - ctx->line_in = ngx_create_temp_buf(r->pool, slcf->line_buffer_size); - if (ctx->line_in == NULL) { - return NGX_ERROR; - } - } - - if (ctx->line_dst == NULL) { - - ctx->line_dst = ngx_create_temp_buf(r->pool, slcf->line_buffer_size); - if (ctx->line_dst == NULL) { - return NGX_ERROR; - } - } - - return NGX_OK; -} - - -static ngx_int_t -ngx_http_subs_body_filter(ngx_http_request_t *r, ngx_chain_t *in) -{ - ngx_int_t rc; - ngx_log_t *log; - ngx_chain_t *cl, *temp; - ngx_http_subs_ctx_t *ctx; - ngx_http_subs_loc_conf_t *slcf; - - log = r->connection->log; - - slcf = ngx_http_get_module_loc_conf(r, ngx_http_subs_filter_module); - if (slcf == NULL) { - return ngx_http_next_body_filter(r, in); - } - - ctx = ngx_http_get_module_ctx(r, ngx_http_subs_filter_module); - if (ctx == NULL) { - return ngx_http_next_body_filter(r, in); - } - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, - "http subs filter \"%V\"", &r->uri); - - if (in == NULL && ctx->busy == NULL) { - return ngx_http_next_body_filter(r, in); - } - - if (ngx_http_subs_body_filter_init_context(r, in) != NGX_OK){ - goto failed; - } - - for (cl = ctx->in; cl; cl = cl->next) { - - if (cl->buf->last_buf || cl->buf->last_in_chain){ - ctx->last = 1; - } - - /* TODO: check the flush flag */ - rc = ngx_http_subs_body_filter_process_buffer(r, cl->buf); - - if (rc == NGX_DECLINED) { - continue; - } else if (rc == NGX_ERROR) { - goto failed; - } - - if (cl->next != NULL) { - continue; - } - - if (ctx->last) { - - /* copy line_in to ctx->out. */ - if (ngx_buf_size(ctx->line_in) > 0) { - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, - "[subs_filter] Lost last linefeed, output anyway."); - - if (ngx_http_subs_out_chain_append(r, ctx, ctx->line_in) - != NGX_OK) { - goto failed; - } - } - - if (ctx->out_buf == NULL) { - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, - "[subs_filter] The last buffer is zero size."); - - /* - * This is a zero buffer, it should not be set the temporary - * or memory flag - * */ - ctx->out_buf = ngx_calloc_buf(r->pool); - if (ctx->out_buf == NULL) { - goto failed; - } - - ctx->out_buf->sync = 1; - - temp = ngx_alloc_chain_link(r->pool); - if (temp == NULL) { - goto failed; - } - - temp->buf = ctx->out_buf; - temp->next = NULL; - - *ctx->last_out = temp; - ctx->last_out = &temp->next; - } - - ctx->out_buf->last_buf = (r == r->main) ? 1 : 0; - ctx->out_buf->last_in_chain = cl->buf->last_in_chain; - - break; - } - } - - /* It doesn't output anything, return */ - if ((ctx->out == NULL) && (ctx->busy == NULL)) { - return NGX_OK; - } - - return ngx_http_subs_output(r, ctx, in); - -failed: - - ngx_log_error(NGX_LOG_ERR, log, 0, - "[subs_filter] ngx_http_subs_body_filter error."); - - return NGX_ERROR; -} - - -static ngx_int_t -ngx_http_subs_body_filter_init_context(ngx_http_request_t *r, ngx_chain_t *in) -{ - ngx_http_subs_ctx_t *ctx; - - ctx = ngx_http_get_module_ctx(r, ngx_http_subs_filter_module); - - r->connection->buffered |= NGX_HTTP_SUB_BUFFERED; - - ctx->in = NULL; - - if (in) { - if (ngx_chain_add_copy(r->pool, &ctx->in, in) != NGX_OK) { - return NGX_ERROR; - } - } - -#if SUBS_DEBUG - if (ngx_buf_size(ctx->line_in) > 0) { - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "subs line in buffer: %p, size:%uz", - ctx->line_in, ngx_buf_size(ctx->line_in)); - } -#endif - -#if SUBS_DEBUG - ngx_chain_t *cl; - - for (cl = ctx->in; cl; cl = cl->next) { - if (cl->buf) { - ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "subs in buffer:%p, size:%uz, " - "flush:%d, last_buf:%d", - cl->buf, ngx_buf_size(cl->buf), - cl->buf->flush, cl->buf->last_buf); - } - } -#endif - - ctx->last_out = &ctx->out; - ctx->out_buf = NULL; - - return NGX_OK; -} - - -static ngx_int_t -ngx_http_subs_body_filter_process_buffer(ngx_http_request_t *r, ngx_buf_t *b) -{ - u_char *p, *last, *linefeed; - ngx_int_t len, rc; - ngx_http_subs_ctx_t *ctx; - - ctx = ngx_http_get_module_ctx(r, ngx_http_subs_filter_module); - - if (b == NULL) { - return NGX_DECLINED; - } - - p = b->pos; - last = b->last; - b->pos = b->last; - - ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "subs process in buffer: %p %uz, line_in buffer: %p %uz", - b, last - p, - ctx->line_in, ngx_buf_size(ctx->line_in)); - - if ((last - p) == 0 && ngx_buf_size(ctx->line_in) == 0){ - return NGX_OK; - } - - if ((last - p) == 0 && ngx_buf_size(ctx->line_in) && ctx->last) { - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "the last zero buffer, try to do substitution"); - - rc = ngx_http_subs_match(r, ctx); - if (rc < 0) { - return NGX_ERROR; - } - - return NGX_OK; - } - - while (p < last) { - - linefeed = memchr(p, LF, last - p); - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "find linefeed: %p", - linefeed); - - if (linefeed == NULL) { - - if (ctx->last) { - linefeed = last - 1; - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "the last buffer, not find linefeed"); - } - } - - if (linefeed) { - - len = linefeed - p + 1; - - if (buffer_append_string(ctx->line_in, p, len, r->pool) == NULL) { - return NGX_ERROR; - } - - p += len; - - rc = ngx_http_subs_match(r, ctx); - if (rc < 0) { - return NGX_ERROR; - } - - } else { - - /* Not find linefeed in this chain, save the left data to line_in */ - if (buffer_append_string(ctx->line_in, p, last - p, r->pool) - == NULL) { - return NGX_ERROR; - } - - break; - } - } - - return NGX_OK; -} - - -/* - * Do the substitutions from ctx->line_in - * and output the chain buffers to ctx->out - * */ -static ngx_int_t -ngx_http_subs_match(ngx_http_request_t *r, ngx_http_subs_ctx_t *ctx) -{ - ngx_buf_t *src, *dst, *temp; - ngx_log_t *log; - ngx_int_t count, match_count; - sub_pair_t *pairs, *pair; - ngx_uint_t i; - - count = 0; - match_count = 0; - - log = r->connection->log; - - src = ctx->line_in; - dst = ctx->line_dst; - - pairs = (sub_pair_t *) ctx->sub_pairs->elts; - for (i = 0; i < ctx->sub_pairs->nelts; i++) { - - pair = &pairs[i]; - - if (!pair->has_captured) { - if (pair->sub.data == NULL) { - if (ngx_http_script_run(r, &pair->sub, pair->sub_lengths->elts, - 0, pair->sub_values->elts) == NULL) - { - goto failed; - } - } - - } else { - pair->sub.data = NULL; - pair->sub.len = 0; - } - - /* exchange the src and dst buffer */ - if (dst->pos != dst->last) { - - temp = src; - src = dst; - dst = temp; - - ngx_buffer_init(dst); - } - - if ((!pair->regex) - && ((ngx_uint_t)(src->last - src->pos) < pair->match.len)) { - continue; - } - - if (pair->once && pair->matched) { - continue; - } - - if (pair->sub.data == NULL && !pair->has_captured) { - - if (ngx_http_script_run(r, &pair->sub, pair->sub_lengths->elts, 0, - pair->sub_values->elts) == NULL) - { - goto failed; - } - } - - /* regex substitution */ - if (pair->regex || pair->insensitive) { -#if (NGX_PCRE) - count = ngx_http_subs_match_regex_substituion(r, pair, src, dst); - if (count == NGX_ERROR) { - goto failed; - } -#endif - } else { - /* fixed string substituion */ - count = ngx_http_subs_match_fix_substituion(r, pair, src, dst); - if (count == NGX_ERROR) { - goto failed; - } - } - - /* no match. */ - if (count == 0){ - continue; - } - - if (src->pos < src->last) { - - if (buffer_append_string(dst, src->pos, src->last - src->pos, - r->pool) == NULL) { - goto failed; - } - - src->pos = src->last; - } - - /* match */ - match_count += count; - } - - /* no match last time */ - if (dst->pos == dst->last){ - dst = src; - } - - if (ngx_http_subs_out_chain_append(r, ctx, dst) != NGX_OK) { - goto failed; - } - - ngx_buffer_init(ctx->line_in); - ngx_buffer_init(ctx->line_dst); - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "match counts: %i", match_count); - - return match_count; - -failed: - - ngx_log_error(NGX_LOG_ERR, log, 0, - "[subs_filter] ngx_http_subs_match error."); - - return -1; -} - - -#if (NGX_PCRE) -static ngx_int_t -ngx_http_subs_match_regex_substituion(ngx_http_request_t *r, sub_pair_t *pair, - ngx_buf_t *b, ngx_buf_t *dst) -{ - ngx_str_t line; - ngx_log_t *log; - ngx_int_t rc, count = 0; - - log = r->connection->log; - - if (pair->captures == NULL || pair->ncaptures == 0) { - pair->ncaptures = (NGX_HTTP_MAX_CAPTURES + 1) * 3; - pair->captures = ngx_palloc(r->pool, pair->ncaptures * sizeof(int)); - if (pair->captures == NULL) { - return NGX_ERROR; - } - } - - while (b->pos < b->last) { - - if (pair->once && pair->matched) { - break; - } - - line.data = b->pos; - line.len = b->last - b->pos; - - rc = ngx_regex_exec(pair->match_regex, &line, - (int *) pair->captures, pair->ncaptures); - - if (rc == NGX_REGEX_NO_MATCHED) { - break; - - } else if(rc < 0) { - ngx_log_error(NGX_LOG_ERR, log, 0, - ngx_regex_exec_n " failed: %i on \"%V\" using \"%V\"", - rc, &line, &pair->match); - - return NGX_ERROR; - } - - pair->matched++; - count++; - - ngx_log_debug3(NGX_LOG_DEBUG_HTTP, log, 0, - "regex match:%i, start:%d, end:%d ", - rc, pair->captures[0], pair->captures[1]); - - if (pair->has_captured) { - r->captures = pair->captures; - r->ncaptures = pair->ncaptures; - r->captures_data = line.data; - - if (ngx_http_script_run(r, &pair->sub, pair->sub_lengths->elts, 0, - pair->sub_values->elts) == NULL) - { - ngx_log_error(NGX_LOG_ALERT, log, 0, - "[subs_filter] ngx_http_script_run error."); - return NGX_ERROR; - } - } - - if (buffer_append_string(dst, b->pos, pair->captures[0], - r->pool) == NULL) { - return NGX_ERROR; - } - - if (buffer_append_string(dst, pair->sub.data, pair->sub.len, - r->pool) == NULL) { - return NGX_ERROR; - } - - b->pos = b->pos + pair->captures[1]; - } - - return count; -} -#endif - - -/* - * Thanks to Laurent Ghigonis - * Taken from FreeBSD - * Find the first occurrence of the byte string s in byte string l. - */ -static void * -subs_memmem(const void *l, size_t l_len, const void *s, size_t s_len) -{ - register char *cur, *last; - const char *cl = (const char *)l; - const char *cs = (const char *)s; - - /* we need something to compare */ - if (l_len == 0 || s_len == 0) { - return NULL; - } - - /* "s" must be smaller or equal to "l" */ - if (l_len < s_len) { - return NULL; - } - - /* special case where s_len == 1 */ - if (s_len == 1) { - return memchr(l, (int)*cs, l_len); - } - - /* the last position where its possible to find "s" in "l" */ - last = (char *)cl + l_len - s_len; - - for (cur = (char *)cl; cur <= last; cur++) { - if (cur[0] == cs[0] && memcmp(cur, cs, s_len) == 0) { - return cur; - } - } - - return NULL; -} - - -static ngx_int_t -ngx_http_subs_match_fix_substituion(ngx_http_request_t *r, - sub_pair_t *pair, ngx_buf_t *b, ngx_buf_t *dst) -{ - u_char *sub_start; - ngx_int_t count = 0; - - while(b->pos < b->last) { - if (pair->once && pair->matched) { - break; - } - - sub_start = subs_memmem(b->pos, b->last - b->pos, - pair->match.data, pair->match.len); - if (sub_start == NULL) { - break; - } - - pair->matched++; - count++; - - if (buffer_append_string(dst, b->pos, sub_start - b->pos, - r->pool) == NULL) { - return NGX_ERROR; - } - - if (buffer_append_string(dst, pair->sub.data, pair->sub.len, - r->pool) == NULL) { - return NGX_ERROR; - } - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "fixed string match: %p", sub_start); - - b->pos = sub_start + pair->match.len; - - if ((ngx_uint_t)(b->last - b->pos) < pair->match.len) - break; - } - - return count; -} - - -static ngx_buf_t * -buffer_append_string(ngx_buf_t *b, u_char *s, size_t len, ngx_pool_t *pool) -{ - u_char *p; - ngx_uint_t capacity, size; - - if (len > (size_t) (b->end - b->last)) { - - size = b->last - b->pos; - - capacity = b->end - b->start; - capacity <<= 1; - - if (capacity < (size + len)) { - capacity = size + len; - } - - p = ngx_palloc(pool, capacity); - if (p == NULL) { - return NULL; - } - - b->last = ngx_copy(p, b->pos, size); - - b->start = b->pos = p; - b->end = p + capacity; - } - - b->last = ngx_copy(b->last, s, len); - - return b; -} - - -static ngx_int_t -ngx_http_subs_out_chain_append(ngx_http_request_t *r, - ngx_http_subs_ctx_t *ctx, ngx_buf_t *b) -{ - size_t len, capcity; - - if (b == NULL || ngx_buf_size(b) == 0) { - return NGX_OK; - } - - if (ctx->out_buf == NULL) { - if (ngx_http_subs_get_chain_buf(r, ctx) != NGX_OK) { - return NGX_ERROR; - } - } - - while (1) { - - len = (size_t) ngx_buf_size(b); - if (len == 0) { - break; - } - - capcity = ctx->out_buf->end - ctx->out_buf->last; - - if (len <= capcity) { - ctx->out_buf->last = ngx_copy(ctx->out_buf->last, b->pos, len); - b->pos += len; - break; - - } else { - ctx->out_buf->last = ngx_copy(ctx->out_buf->last, - b->pos, capcity); - } - - b->pos += capcity; - - /* get more buffers */ - if (ngx_http_subs_get_chain_buf(r, ctx) != NGX_OK) { - return NGX_ERROR; - } - } - - return NGX_OK; -} - - -static ngx_int_t -ngx_http_subs_get_chain_buf(ngx_http_request_t *r, - ngx_http_subs_ctx_t *ctx) -{ - ngx_chain_t *temp; - ngx_http_subs_loc_conf_t *slcf; - - slcf = ngx_http_get_module_loc_conf(r, ngx_http_subs_filter_module); - - if (ctx->free) { - temp = ctx->free; - ctx->free = ctx->free->next; - - } else { - temp = ngx_alloc_chain_link(r->pool); - if (temp == NULL) { - return NGX_ERROR; - } - - temp->buf = ngx_create_temp_buf(r->pool, slcf->bufs.size); - if (temp->buf == NULL) { - return NGX_ERROR; - } - - temp->buf->tag = (ngx_buf_tag_t) &ngx_http_subs_filter_module; - temp->buf->recycled = 1; - - /* TODO: limit the buffer number */ - ctx->bufs++; - } - - temp->next = NULL; - - ctx->out_buf = temp->buf; - *ctx->last_out = temp; - ctx->last_out = &temp->next; - - return NGX_OK; -} - - -static ngx_int_t -ngx_http_subs_output(ngx_http_request_t *r, ngx_http_subs_ctx_t *ctx, - ngx_chain_t *in) -{ - ngx_int_t rc; - -#if SUBS_DEBUG - ngx_buf_t *b; - ngx_chain_t *cl; - - for (cl = ctx->out; cl; cl = cl->next) { - - b = cl->buf; - - ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "subs out buffer:%p, size:%uz, t:%d, l:%d", - b, ngx_buf_size(b), b->temporary, b->last_buf); - } -#endif - - /* ctx->out may not output all the data */ - rc = ngx_http_next_body_filter(r, ctx->out); - if (rc == NGX_ERROR) { - return NGX_ERROR; - } - -#if SUBS_DEBUG - for (cl = ctx->out; cl; cl = cl->next) { - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "subs out end: %p %uz", cl->buf, ngx_buf_size(cl->buf)); - } -#endif - -#if defined(nginx_version) && (nginx_version >= 1001004) - ngx_chain_update_chains(r->pool, &ctx->free, &ctx->busy, &ctx->out, - (ngx_buf_tag_t) &ngx_http_subs_filter_module); -#else - ngx_chain_update_chains(&ctx->free, &ctx->busy, &ctx->out, - (ngx_buf_tag_t) &ngx_http_subs_filter_module); -#endif - - if (ctx->last) { - r->connection->buffered &= ~NGX_HTTP_SUB_BUFFERED; - } - - return rc; -} - - -static char * -ngx_http_subs_filter( ngx_conf_t *cf, ngx_command_t *cmd, void *conf) -{ - ngx_int_t n; - ngx_uint_t i; - ngx_str_t *value; - ngx_str_t *option; - sub_pair_t *pair; - ngx_http_subs_loc_conf_t *slcf = conf; - ngx_http_script_compile_t sc; - - value = cf->args->elts; - - if (slcf->sub_pairs == NULL) { - slcf->sub_pairs = ngx_array_create(cf->pool, 4, sizeof(sub_pair_t)); - if (slcf->sub_pairs == NULL) { - return NGX_CONF_ERROR; - } - } - - pair = ngx_array_push(slcf->sub_pairs); - if (pair == NULL) { - return NGX_CONF_ERROR; - } - ngx_memzero(pair, sizeof(sub_pair_t)); - - pair->match = value[1]; - - n = ngx_http_script_variables_count(&value[2]); - if (n != 0) { - ngx_memzero(&sc, sizeof(ngx_http_script_compile_t)); - - sc.cf = cf; - sc.source = &value[2]; - sc.lengths = &pair->sub_lengths; - sc.values = &pair->sub_values; - sc.variables = n; - sc.complete_lengths = 1; - sc.complete_values = 1; - - if (ngx_http_script_compile(&sc) != NGX_OK) { - return NGX_CONF_ERROR; - } - - /* Dirty hack, if it has captured variables */ - if (sc.captures_mask) { - pair->has_captured = 1; - } - - } else { - pair->sub = value[2]; - } - - if (cf->args->nelts > 3) { - option = &value[3]; - for(i = 0; i < option->len; i++) { - - switch (option->data[i]){ - case 'i': - pair->insensitive = 1; - break; - - case 'o': - pair->once = 1; - break; - - case 'r': - pair->regex = 1; - break; - - case 'g': - default: - continue; - } - } - } - - if (pair->regex || pair->insensitive) { - if (ngx_http_subs_filter_regex_compile(pair, &sc, cf) == NGX_ERROR) { - return NGX_CONF_ERROR; - } - } - - return NGX_CONF_OK; -} - - -static ngx_int_t -ngx_http_subs_filter_regex_compile(sub_pair_t *pair, - ngx_http_script_compile_t *sc, ngx_conf_t *cf) -{ - /* Caseless match can only be implemented in regex. */ -#if (NGX_PCRE) - u_char errstr[NGX_MAX_CONF_ERRSTR]; - ngx_int_t n, options; - ngx_str_t err, *value; - ngx_uint_t mask; - - value = cf->args->elts; - - err.len = NGX_MAX_CONF_ERRSTR; - err.data = errstr; - - options = (pair->insensitive ? NGX_REGEX_CASELESS : 0); - - /* make nginx-0.8.25+ happy */ -#if defined(nginx_version) && nginx_version >= 8025 - ngx_regex_compile_t rc; - - rc.pattern = pair->match; - rc.pool = cf->pool; - rc.err = err; - rc.options = options; - - if (ngx_regex_compile(&rc) != NGX_OK) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%V", &rc.err); - return NGX_ERROR; - } - - pair->match_regex = rc.regex; - -#else - pair->match_regex = ngx_regex_compile(&pair->match, options, - cf->pool, &err); -#endif - - if (pair->match_regex == NULL) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%V", &err); - return NGX_ERROR; - } - - n = ngx_http_subs_regex_capture_count(pair->match_regex); - - if (pair->has_captured) { - mask = ((1 << (n + 1)) - 1); - if ( mask < sc->captures_mask ) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "You want to capture too many regex substrings, " - "more than %i in \"%V\"", - n, &value[2]); - - return NGX_ERROR; - } - } -#else - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "the using of the regex \"%V\" requires PCRE library", - &pair->match); - - return NGX_ERROR; -#endif - - return NGX_OK; -} - - -#if (NGX_PCRE) -static ngx_int_t -ngx_http_subs_regex_capture_count(ngx_regex_t *re) -{ - int rc, n; - - n = 0; - -#if defined(nginx_version) && nginx_version >= 1002002 - rc = pcre_fullinfo(re->code, NULL, PCRE_INFO_CAPTURECOUNT, &n); -#elif defined(nginx_version) && nginx_version >= 1001012 - rc = pcre_fullinfo(re->pcre, NULL, PCRE_INFO_CAPTURECOUNT, &n); -#else - rc = pcre_fullinfo(re, NULL, PCRE_INFO_CAPTURECOUNT, &n); -#endif - - if (rc < 0) { - return (ngx_int_t) rc; - } - - return (ngx_int_t) n; -} -#endif - - -static void * -ngx_http_subs_create_conf(ngx_conf_t *cf) -{ - ngx_http_subs_loc_conf_t *conf; - - conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_subs_loc_conf_t)); - if (conf == NULL) { - return NGX_CONF_ERROR; - } - - /* - * set by ngx_pcalloc(): - * - * conf->sub_pairs = NULL; - * conf->types = {NULL, 0}; - * conf->types_keys = NULL; - * conf->bufs.num = 0; - */ - - conf->line_buffer_size = NGX_CONF_UNSET_SIZE; - conf->bypass = NGX_CONF_UNSET_PTR; - - return conf; -} - - -static char * -ngx_http_subs_merge_conf(ngx_conf_t *cf, void *parent, void *child) -{ - ngx_http_subs_loc_conf_t *prev = parent; - ngx_http_subs_loc_conf_t *conf = child; - - if (conf->sub_pairs == NULL) { - if (prev->sub_pairs == NULL) { - conf->sub_pairs = ngx_array_create(cf->pool, 4, sizeof(sub_pair_t)); - if (conf->sub_pairs == NULL) { - return NGX_CONF_ERROR; - } - } else { - conf->sub_pairs = prev->sub_pairs; - } - } - - ngx_conf_merge_ptr_value(conf->bypass, - prev->bypass, NULL); - - if (ngx_http_merge_types(cf, &conf->types_keys, &conf->types, - &prev->types_keys, &prev->types, - ngx_http_html_default_types) - != NGX_OK) - { - return NGX_CONF_ERROR; - } - - ngx_conf_merge_size_value(conf->line_buffer_size, - prev->line_buffer_size, 8 * ngx_pagesize); - - /* Default total buffer size is 128k */ - ngx_conf_merge_bufs_value(conf->bufs, prev->bufs, - (128 * 1024) / ngx_pagesize, ngx_pagesize); - - return NGX_CONF_OK; -} - - -static ngx_int_t -ngx_http_subs_filter_init(ngx_conf_t *cf) -{ - ngx_http_next_header_filter = ngx_http_top_header_filter; - ngx_http_top_header_filter = ngx_http_subs_header_filter; - - ngx_http_next_body_filter = ngx_http_top_body_filter; - ngx_http_top_body_filter = ngx_http_subs_body_filter; - - return NGX_OK; -} diff --git a/debian/modules/http-subs-filter/test/README b/debian/modules/http-subs-filter/test/README deleted file mode 100644 index b9ff21b..0000000 --- a/debian/modules/http-subs-filter/test/README +++ /dev/null @@ -1,275 +0,0 @@ -NAME - Test::Nginx - Testing modules for Nginx C module development - -DESCRIPTION - This distribution provides two testing modules for Nginx C module - development: - - * Test::Nginx::LWP - - * Test::Nginx::Socket - - All of them are based on Test::Base. - - Usually, Test::Nginx::Socket is preferred because it works on a much - lower level and not that fault tolerant like Test::Nginx::LWP. - - Also, a lot of connection hang issues (like wrong "r->main->count" value - in nginx 0.8.x) can only be captured by Test::Nginx::Socket because - Perl's LWP::UserAgent client will close the connection itself which will - conceal such issues from the testers. - - Test::Nginx automatically starts an nginx instance (from the "PATH" env) - rooted at t/servroot/ and the default config template makes this nginx - instance listen on the port 1984 by default. One can specify a different - port number by setting his port number to the "TEST_NGINX_PORT" - environment, as in - - export TEST_NGINX_PORT=1989 - - etcproxy integration - The default settings in etcproxy - (https://github.com/chaoslawful/etcproxy) makes this small TCP proxy - split the TCP packets into bytes and introduce 1 ms latency among them. - - There's usually various TCP chains that we can put etcproxy into, for - example - - Test::Nginx <=> nginx - $ ./etcproxy 1234 1984 - - Here we tell etcproxy to listen on port 1234 and to delegate all the TCP - traffic to the port 1984, the default port that Test::Nginx makes nginx - listen to. - - And then we tell Test::Nginx to test against the port 1234, where - etcproxy listens on, rather than the port 1984 that nginx directly - listens on: - - $ TEST_NGINX_CLIENT_PORT=1234 prove -r t/ - - Then the TCP chain now looks like this: - - Test::Nginx <=> etcproxy (1234) <=> nginx (1984) - - So etcproxy can effectively emulate extreme network conditions and - exercise "unusual" code paths in your nginx server by your tests. - - In practice, *tons* of weird bugs can be captured by this setting. Even - ourselves didn't expect that this simple approach is so effective. - - nginx <=> memcached - We first start the memcached server daemon on port 11211: - - memcached -p 11211 -vv - - and then we another etcproxy instance to listen on port 11984 like this - - $ ./etcproxy 11984 11211 - - Then we tell our t/foo.t test script to connect to 11984 rather than - 11211: - - # foo.t - use Test::Nginx::Socket; - repeat_each(1); - plan tests => 2 * repeat_each() * blocks(); - $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; # make this env take a default value - run_tests(); - - __DATA__ - - === TEST 1: sanity - --- config - location /foo { - set $memc_cmd set; - set $memc_key foo; - set $memc_value bar; - memc_pass 127.0.0.1:$TEST_NGINX_MEMCACHED_PORT; - } - --- request - GET /foo - --- response_body_like: STORED - - The Test::Nginx library will automatically expand the special macro - $TEST_NGINX_MEMCACHED_PORT to the environment with the same name. You - can define your own $TEST_NGINX_BLAH_BLAH_PORT macros as long as its - prefix is "TEST_NGINX_" and all in upper case letters. - - And now we can run your test script against the etcproxy port 11984: - - TEST_NGINX_MEMCACHED_PORT=11984 prove t/foo.t - - Then the TCP chains look like this: - - Test::Nginx <=> nginx (1984) <=> etcproxy (11984) <=> memcached (11211) - - If "TEST_NGINX_MEMCACHED_PORT" is not set, then it will take the default - value 11211, which is what we want when there's no etcproxy configured: - - Test::Nginx <=> nginx (1984) <=> memcached (11211) - - This approach also works for proxied mysql and postgres traffic. Please - see the live test suite of ngx_drizzle and ngx_postgres for more - details. - - Usually we set both "TEST_NGINX_CLIENT_PORT" and - "TEST_NGINX_MEMCACHED_PORT" (and etc) at the same time, effectively - yielding the following chain: - - Test::Nginx <=> etcproxy (1234) <=> nginx (1984) <=> etcproxy (11984) <=> memcached (11211) - - as long as you run two separate etcproxy instances in two separate - terminals. - - It's easy to verify if the traffic actually goes through your etcproxy - server. Just check if the terminal running etcproxy emits outputs. By - default, etcproxy always dump out the incoming and outgoing data to - stdout/stderr. - - valgrind integration - Test::Nginx has integrated support for valgrind () - even though by default it does not bother running it with the tests - because valgrind will significantly slow down the test sutie. - - First ensure that your valgrind executable visible in your PATH env. And - then run your test suite with the "TEST_NGINX_USE_VALGRIND" env set to - true: - - TEST_NGINX_USE_VALGRIND=1 prove -r t - - If you see false alarms, you do have a chance to skip them by defining a - ./valgrind.suppress file at the root of your module source tree, as in - - - - This is the suppression file for ngx_drizzle. Test::Nginx will - automatically use it to start nginx with valgrind memcheck if this file - does exist at the expected location. - - If you do see a lot of "Connection refused" errors while running the - tests this way, then you probably have a slow machine (or a very busy - one) that the default waiting time is not sufficient for valgrind to - start. You can define the sleep time to a larger value by setting the - "TEST_NGINX_SLEEP" env: - - TEST_NGINX_SLEEP=1 prove -r t - - The time unit used here is "second". The default sleep setting just fits - my ThinkPad ("Core2Duo T9600"). - - Applying the no-pool patch to your nginx core is recommended while - running nginx with valgrind: - - - - The nginx memory pool can prevent valgrind from spotting lots of invalid - memory reads/writes as well as certain double-free errors. We did find a - lot more memory issues in many of our modules when we first introduced - the no-pool patch in practice ;) - - There's also more advanced features in Test::Nginx that have never - documented. I'd like to write more about them in the near future ;) - -Nginx C modules that use Test::Nginx to drive their test suites - ngx_echo - - - ngx_headers_more - - - ngx_chunkin - - - ngx_memc - - - ngx_drizzle - - - ngx_rds_json - - - ngx_xss - - - ngx_srcache - - - ngx_lua - - - ngx_set_misc - - - ngx_array_var - - - ngx_form_input - - - ngx_iconv - - - ngx_set_cconv - - - ngx_postgres - - - ngx_coolkit - - -SOURCE REPOSITORY - This module has a Git repository on Github, which has access for all. - - http://github.com/agentzh/test-nginx - - If you want a commit bit, feel free to drop me a line. - -AUTHORS - agentzh (章亦春) "" - - Antoine BONAVITA "" - -COPYRIGHT & LICENSE - Copyright (c) 2009-2011, Taobao Inc., Alibaba Group - (). - - Copyright (c) 2009-2011, agentzh "". - - Copyright (c) 2011, Antoine Bonavita "". - - This module is licensed under the terms of the BSD license. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - * Neither the name of the Taobao Inc. nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -SEE ALSO - Test::Nginx::LWP, Test::Nginx::Socket, Test::Base. - diff --git a/debian/modules/http-subs-filter/test/inc/Module/AutoInstall.pm b/debian/modules/http-subs-filter/test/inc/Module/AutoInstall.pm deleted file mode 100644 index 60b90ea..0000000 --- a/debian/modules/http-subs-filter/test/inc/Module/AutoInstall.pm +++ /dev/null @@ -1,820 +0,0 @@ -#line 1 -package Module::AutoInstall; - -use strict; -use Cwd (); -use ExtUtils::MakeMaker (); - -use vars qw{$VERSION}; -BEGIN { - $VERSION = '1.03'; -} - -# special map on pre-defined feature sets -my %FeatureMap = ( - '' => 'Core Features', # XXX: deprecated - '-core' => 'Core Features', -); - -# various lexical flags -my ( @Missing, @Existing, %DisabledTests, $UnderCPAN, $HasCPANPLUS ); -my ( - $Config, $CheckOnly, $SkipInstall, $AcceptDefault, $TestOnly, $AllDeps -); -my ( $PostambleActions, $PostambleUsed ); - -# See if it's a testing or non-interactive session -_accept_default( $ENV{AUTOMATED_TESTING} or ! -t STDIN ); -_init(); - -sub _accept_default { - $AcceptDefault = shift; -} - -sub missing_modules { - return @Missing; -} - -sub do_install { - __PACKAGE__->install( - [ - $Config - ? ( UNIVERSAL::isa( $Config, 'HASH' ) ? %{$Config} : @{$Config} ) - : () - ], - @Missing, - ); -} - -# initialize various flags, and/or perform install -sub _init { - foreach my $arg ( - @ARGV, - split( - /[\s\t]+/, - $ENV{PERL_AUTOINSTALL} || $ENV{PERL_EXTUTILS_AUTOINSTALL} || '' - ) - ) - { - if ( $arg =~ /^--config=(.*)$/ ) { - $Config = [ split( ',', $1 ) ]; - } - elsif ( $arg =~ /^--installdeps=(.*)$/ ) { - __PACKAGE__->install( $Config, @Missing = split( /,/, $1 ) ); - exit 0; - } - elsif ( $arg =~ /^--default(?:deps)?$/ ) { - $AcceptDefault = 1; - } - elsif ( $arg =~ /^--check(?:deps)?$/ ) { - $CheckOnly = 1; - } - elsif ( $arg =~ /^--skip(?:deps)?$/ ) { - $SkipInstall = 1; - } - elsif ( $arg =~ /^--test(?:only)?$/ ) { - $TestOnly = 1; - } - elsif ( $arg =~ /^--all(?:deps)?$/ ) { - $AllDeps = 1; - } - } -} - -# overrides MakeMaker's prompt() to automatically accept the default choice -sub _prompt { - goto &ExtUtils::MakeMaker::prompt unless $AcceptDefault; - - my ( $prompt, $default ) = @_; - my $y = ( $default =~ /^[Yy]/ ); - - print $prompt, ' [', ( $y ? 'Y' : 'y' ), '/', ( $y ? 'n' : 'N' ), '] '; - print "$default\n"; - return $default; -} - -# the workhorse -sub import { - my $class = shift; - my @args = @_ or return; - my $core_all; - - print "*** $class version " . $class->VERSION . "\n"; - print "*** Checking for Perl dependencies...\n"; - - my $cwd = Cwd::cwd(); - - $Config = []; - - my $maxlen = length( - ( - sort { length($b) <=> length($a) } - grep { /^[^\-]/ } - map { - ref($_) - ? ( ( ref($_) eq 'HASH' ) ? keys(%$_) : @{$_} ) - : '' - } - map { +{@args}->{$_} } - grep { /^[^\-]/ or /^-core$/i } keys %{ +{@args} } - )[0] - ); - - # We want to know if we're under CPAN early to avoid prompting, but - # if we aren't going to try and install anything anyway then skip the - # check entirely since we don't want to have to load (and configure) - # an old CPAN just for a cosmetic message - - $UnderCPAN = _check_lock(1) unless $SkipInstall; - - while ( my ( $feature, $modules ) = splice( @args, 0, 2 ) ) { - my ( @required, @tests, @skiptests ); - my $default = 1; - my $conflict = 0; - - if ( $feature =~ m/^-(\w+)$/ ) { - my $option = lc($1); - - # check for a newer version of myself - _update_to( $modules, @_ ) and return if $option eq 'version'; - - # sets CPAN configuration options - $Config = $modules if $option eq 'config'; - - # promote every features to core status - $core_all = ( $modules =~ /^all$/i ) and next - if $option eq 'core'; - - next unless $option eq 'core'; - } - - print "[" . ( $FeatureMap{ lc($feature) } || $feature ) . "]\n"; - - $modules = [ %{$modules} ] if UNIVERSAL::isa( $modules, 'HASH' ); - - unshift @$modules, -default => &{ shift(@$modules) } - if ( ref( $modules->[0] ) eq 'CODE' ); # XXX: bugward combatability - - while ( my ( $mod, $arg ) = splice( @$modules, 0, 2 ) ) { - if ( $mod =~ m/^-(\w+)$/ ) { - my $option = lc($1); - - $default = $arg if ( $option eq 'default' ); - $conflict = $arg if ( $option eq 'conflict' ); - @tests = @{$arg} if ( $option eq 'tests' ); - @skiptests = @{$arg} if ( $option eq 'skiptests' ); - - next; - } - - printf( "- %-${maxlen}s ...", $mod ); - - if ( $arg and $arg =~ /^\D/ ) { - unshift @$modules, $arg; - $arg = 0; - } - - # XXX: check for conflicts and uninstalls(!) them. - my $cur = _load($mod); - if (_version_cmp ($cur, $arg) >= 0) - { - print "loaded. ($cur" . ( $arg ? " >= $arg" : '' ) . ")\n"; - push @Existing, $mod => $arg; - $DisabledTests{$_} = 1 for map { glob($_) } @skiptests; - } - else { - if (not defined $cur) # indeed missing - { - print "missing." . ( $arg ? " (would need $arg)" : '' ) . "\n"; - } - else - { - # no need to check $arg as _version_cmp ($cur, undef) would satisfy >= above - print "too old. ($cur < $arg)\n"; - } - - push @required, $mod => $arg; - } - } - - next unless @required; - - my $mandatory = ( $feature eq '-core' or $core_all ); - - if ( - !$SkipInstall - and ( - $CheckOnly - or ($mandatory and $UnderCPAN) - or $AllDeps - or _prompt( - qq{==> Auto-install the } - . ( @required / 2 ) - . ( $mandatory ? ' mandatory' : ' optional' ) - . qq{ module(s) from CPAN?}, - $default ? 'y' : 'n', - ) =~ /^[Yy]/ - ) - ) - { - push( @Missing, @required ); - $DisabledTests{$_} = 1 for map { glob($_) } @skiptests; - } - - elsif ( !$SkipInstall - and $default - and $mandatory - and - _prompt( qq{==> The module(s) are mandatory! Really skip?}, 'n', ) - =~ /^[Nn]/ ) - { - push( @Missing, @required ); - $DisabledTests{$_} = 1 for map { glob($_) } @skiptests; - } - - else { - $DisabledTests{$_} = 1 for map { glob($_) } @tests; - } - } - - if ( @Missing and not( $CheckOnly or $UnderCPAN ) ) { - require Config; - print -"*** Dependencies will be installed the next time you type '$Config::Config{make}'.\n"; - - # make an educated guess of whether we'll need root permission. - print " (You may need to do that as the 'root' user.)\n" - if eval '$>'; - } - print "*** $class configuration finished.\n"; - - chdir $cwd; - - # import to main:: - no strict 'refs'; - *{'main::WriteMakefile'} = \&Write if caller(0) eq 'main'; - - return (@Existing, @Missing); -} - -sub _running_under { - my $thing = shift; - print <<"END_MESSAGE"; -*** Since we're running under ${thing}, I'll just let it take care - of the dependency's installation later. -END_MESSAGE - return 1; -} - -# Check to see if we are currently running under CPAN.pm and/or CPANPLUS; -# if we are, then we simply let it taking care of our dependencies -sub _check_lock { - return unless @Missing or @_; - - my $cpan_env = $ENV{PERL5_CPAN_IS_RUNNING}; - - if ($ENV{PERL5_CPANPLUS_IS_RUNNING}) { - return _running_under($cpan_env ? 'CPAN' : 'CPANPLUS'); - } - - require CPAN; - - if ($CPAN::VERSION > '1.89') { - if ($cpan_env) { - return _running_under('CPAN'); - } - return; # CPAN.pm new enough, don't need to check further - } - - # last ditch attempt, this -will- configure CPAN, very sorry - - _load_cpan(1); # force initialize even though it's already loaded - - # Find the CPAN lock-file - my $lock = MM->catfile( $CPAN::Config->{cpan_home}, ".lock" ); - return unless -f $lock; - - # Check the lock - local *LOCK; - return unless open(LOCK, $lock); - - if ( - ( $^O eq 'MSWin32' ? _under_cpan() : == getppid() ) - and ( $CPAN::Config->{prerequisites_policy} || '' ) ne 'ignore' - ) { - print <<'END_MESSAGE'; - -*** Since we're running under CPAN, I'll just let it take care - of the dependency's installation later. -END_MESSAGE - return 1; - } - - close LOCK; - return; -} - -sub install { - my $class = shift; - - my $i; # used below to strip leading '-' from config keys - my @config = ( map { s/^-// if ++$i; $_ } @{ +shift } ); - - my ( @modules, @installed ); - while ( my ( $pkg, $ver ) = splice( @_, 0, 2 ) ) { - - # grep out those already installed - if ( _version_cmp( _load($pkg), $ver ) >= 0 ) { - push @installed, $pkg; - } - else { - push @modules, $pkg, $ver; - } - } - - return @installed unless @modules; # nothing to do - return @installed if _check_lock(); # defer to the CPAN shell - - print "*** Installing dependencies...\n"; - - return unless _connected_to('cpan.org'); - - my %args = @config; - my %failed; - local *FAILED; - if ( $args{do_once} and open( FAILED, '.#autoinstall.failed' ) ) { - while () { chomp; $failed{$_}++ } - close FAILED; - - my @newmod; - while ( my ( $k, $v ) = splice( @modules, 0, 2 ) ) { - push @newmod, ( $k => $v ) unless $failed{$k}; - } - @modules = @newmod; - } - - if ( _has_cpanplus() and not $ENV{PERL_AUTOINSTALL_PREFER_CPAN} ) { - _install_cpanplus( \@modules, \@config ); - } else { - _install_cpan( \@modules, \@config ); - } - - print "*** $class installation finished.\n"; - - # see if we have successfully installed them - while ( my ( $pkg, $ver ) = splice( @modules, 0, 2 ) ) { - if ( _version_cmp( _load($pkg), $ver ) >= 0 ) { - push @installed, $pkg; - } - elsif ( $args{do_once} and open( FAILED, '>> .#autoinstall.failed' ) ) { - print FAILED "$pkg\n"; - } - } - - close FAILED if $args{do_once}; - - return @installed; -} - -sub _install_cpanplus { - my @modules = @{ +shift }; - my @config = _cpanplus_config( @{ +shift } ); - my $installed = 0; - - require CPANPLUS::Backend; - my $cp = CPANPLUS::Backend->new; - my $conf = $cp->configure_object; - - return unless $conf->can('conf') # 0.05x+ with "sudo" support - or _can_write($conf->_get_build('base')); # 0.04x - - # if we're root, set UNINST=1 to avoid trouble unless user asked for it. - my $makeflags = $conf->get_conf('makeflags') || ''; - if ( UNIVERSAL::isa( $makeflags, 'HASH' ) ) { - # 0.03+ uses a hashref here - $makeflags->{UNINST} = 1 unless exists $makeflags->{UNINST}; - - } else { - # 0.02 and below uses a scalar - $makeflags = join( ' ', split( ' ', $makeflags ), 'UNINST=1' ) - if ( $makeflags !~ /\bUNINST\b/ and eval qq{ $> eq '0' } ); - - } - $conf->set_conf( makeflags => $makeflags ); - $conf->set_conf( prereqs => 1 ); - - - - while ( my ( $key, $val ) = splice( @config, 0, 2 ) ) { - $conf->set_conf( $key, $val ); - } - - my $modtree = $cp->module_tree; - while ( my ( $pkg, $ver ) = splice( @modules, 0, 2 ) ) { - print "*** Installing $pkg...\n"; - - MY::preinstall( $pkg, $ver ) or next if defined &MY::preinstall; - - my $success; - my $obj = $modtree->{$pkg}; - - if ( $obj and _version_cmp( $obj->{version}, $ver ) >= 0 ) { - my $pathname = $pkg; - $pathname =~ s/::/\\W/; - - foreach my $inc ( grep { m/$pathname.pm/i } keys(%INC) ) { - delete $INC{$inc}; - } - - my $rv = $cp->install( modules => [ $obj->{module} ] ); - - if ( $rv and ( $rv->{ $obj->{module} } or $rv->{ok} ) ) { - print "*** $pkg successfully installed.\n"; - $success = 1; - } else { - print "*** $pkg installation cancelled.\n"; - $success = 0; - } - - $installed += $success; - } else { - print << "."; -*** Could not find a version $ver or above for $pkg; skipping. -. - } - - MY::postinstall( $pkg, $ver, $success ) if defined &MY::postinstall; - } - - return $installed; -} - -sub _cpanplus_config { - my @config = (); - while ( @_ ) { - my ($key, $value) = (shift(), shift()); - if ( $key eq 'prerequisites_policy' ) { - if ( $value eq 'follow' ) { - $value = CPANPLUS::Internals::Constants::PREREQ_INSTALL(); - } elsif ( $value eq 'ask' ) { - $value = CPANPLUS::Internals::Constants::PREREQ_ASK(); - } elsif ( $value eq 'ignore' ) { - $value = CPANPLUS::Internals::Constants::PREREQ_IGNORE(); - } else { - die "*** Cannot convert option $key = '$value' to CPANPLUS version.\n"; - } - } else { - die "*** Cannot convert option $key to CPANPLUS version.\n"; - } - } - return @config; -} - -sub _install_cpan { - my @modules = @{ +shift }; - my @config = @{ +shift }; - my $installed = 0; - my %args; - - _load_cpan(); - require Config; - - if (CPAN->VERSION < 1.80) { - # no "sudo" support, probe for writableness - return unless _can_write( MM->catfile( $CPAN::Config->{cpan_home}, 'sources' ) ) - and _can_write( $Config::Config{sitelib} ); - } - - # if we're root, set UNINST=1 to avoid trouble unless user asked for it. - my $makeflags = $CPAN::Config->{make_install_arg} || ''; - $CPAN::Config->{make_install_arg} = - join( ' ', split( ' ', $makeflags ), 'UNINST=1' ) - if ( $makeflags !~ /\bUNINST\b/ and eval qq{ $> eq '0' } ); - - # don't show start-up info - $CPAN::Config->{inhibit_startup_message} = 1; - - # set additional options - while ( my ( $opt, $arg ) = splice( @config, 0, 2 ) ) { - ( $args{$opt} = $arg, next ) - if $opt =~ /^force$/; # pseudo-option - $CPAN::Config->{$opt} = $arg; - } - - local $CPAN::Config->{prerequisites_policy} = 'follow'; - - while ( my ( $pkg, $ver ) = splice( @modules, 0, 2 ) ) { - MY::preinstall( $pkg, $ver ) or next if defined &MY::preinstall; - - print "*** Installing $pkg...\n"; - - my $obj = CPAN::Shell->expand( Module => $pkg ); - my $success = 0; - - if ( $obj and _version_cmp( $obj->cpan_version, $ver ) >= 0 ) { - my $pathname = $pkg; - $pathname =~ s/::/\\W/; - - foreach my $inc ( grep { m/$pathname.pm/i } keys(%INC) ) { - delete $INC{$inc}; - } - - my $rv = $args{force} ? CPAN::Shell->force( install => $pkg ) - : CPAN::Shell->install($pkg); - $rv ||= eval { - $CPAN::META->instance( 'CPAN::Distribution', $obj->cpan_file, ) - ->{install} - if $CPAN::META; - }; - - if ( $rv eq 'YES' ) { - print "*** $pkg successfully installed.\n"; - $success = 1; - } - else { - print "*** $pkg installation failed.\n"; - $success = 0; - } - - $installed += $success; - } - else { - print << "."; -*** Could not find a version $ver or above for $pkg; skipping. -. - } - - MY::postinstall( $pkg, $ver, $success ) if defined &MY::postinstall; - } - - return $installed; -} - -sub _has_cpanplus { - return ( - $HasCPANPLUS = ( - $INC{'CPANPLUS/Config.pm'} - or _load('CPANPLUS::Shell::Default') - ) - ); -} - -# make guesses on whether we're under the CPAN installation directory -sub _under_cpan { - require Cwd; - require File::Spec; - - my $cwd = File::Spec->canonpath( Cwd::cwd() ); - my $cpan = File::Spec->canonpath( $CPAN::Config->{cpan_home} ); - - return ( index( $cwd, $cpan ) > -1 ); -} - -sub _update_to { - my $class = __PACKAGE__; - my $ver = shift; - - return - if _version_cmp( _load($class), $ver ) >= 0; # no need to upgrade - - if ( - _prompt( "==> A newer version of $class ($ver) is required. Install?", - 'y' ) =~ /^[Nn]/ - ) - { - die "*** Please install $class $ver manually.\n"; - } - - print << "."; -*** Trying to fetch it from CPAN... -. - - # install ourselves - _load($class) and return $class->import(@_) - if $class->install( [], $class, $ver ); - - print << '.'; exit 1; - -*** Cannot bootstrap myself. :-( Installation terminated. -. -} - -# check if we're connected to some host, using inet_aton -sub _connected_to { - my $site = shift; - - return ( - ( _load('Socket') and Socket::inet_aton($site) ) or _prompt( - qq( -*** Your host cannot resolve the domain name '$site', which - probably means the Internet connections are unavailable. -==> Should we try to install the required module(s) anyway?), 'n' - ) =~ /^[Yy]/ - ); -} - -# check if a directory is writable; may create it on demand -sub _can_write { - my $path = shift; - mkdir( $path, 0755 ) unless -e $path; - - return 1 if -w $path; - - print << "."; -*** You are not allowed to write to the directory '$path'; - the installation may fail due to insufficient permissions. -. - - if ( - eval '$>' and lc(`sudo -V`) =~ /version/ and _prompt( - qq( -==> Should we try to re-execute the autoinstall process with 'sudo'?), - ((-t STDIN) ? 'y' : 'n') - ) =~ /^[Yy]/ - ) - { - - # try to bootstrap ourselves from sudo - print << "."; -*** Trying to re-execute the autoinstall process with 'sudo'... -. - my $missing = join( ',', @Missing ); - my $config = join( ',', - UNIVERSAL::isa( $Config, 'HASH' ) ? %{$Config} : @{$Config} ) - if $Config; - - return - unless system( 'sudo', $^X, $0, "--config=$config", - "--installdeps=$missing" ); - - print << "."; -*** The 'sudo' command exited with error! Resuming... -. - } - - return _prompt( - qq( -==> Should we try to install the required module(s) anyway?), 'n' - ) =~ /^[Yy]/; -} - -# load a module and return the version it reports -sub _load { - my $mod = pop; # class/instance doesn't matter - my $file = $mod; - - $file =~ s|::|/|g; - $file .= '.pm'; - - local $@; - return eval { require $file; $mod->VERSION } || ( $@ ? undef: 0 ); -} - -# Load CPAN.pm and it's configuration -sub _load_cpan { - return if $CPAN::VERSION and $CPAN::Config and not @_; - require CPAN; - - # CPAN-1.82+ adds CPAN::Config::AUTOLOAD to redirect to - # CPAN::HandleConfig->load. CPAN reports that the redirection - # is deprecated in a warning printed at the user. - - # CPAN-1.81 expects CPAN::HandleConfig->load, does not have - # $CPAN::HandleConfig::VERSION but cannot handle - # CPAN::Config->load - - # Which "versions expect CPAN::Config->load? - - if ( $CPAN::HandleConfig::VERSION - || CPAN::HandleConfig->can('load') - ) { - # Newer versions of CPAN have a HandleConfig module - CPAN::HandleConfig->load; - } else { - # Older versions had the load method in Config directly - CPAN::Config->load; - } -} - -# compare two versions, either use Sort::Versions or plain comparison -# return values same as <=> -sub _version_cmp { - my ( $cur, $min ) = @_; - return -1 unless defined $cur; # if 0 keep comparing - return 1 unless $min; - - $cur =~ s/\s+$//; - - # check for version numbers that are not in decimal format - if ( ref($cur) or ref($min) or $cur =~ /v|\..*\./ or $min =~ /v|\..*\./ ) { - if ( ( $version::VERSION or defined( _load('version') )) and - version->can('new') - ) { - - # use version.pm if it is installed. - return version->new($cur) <=> version->new($min); - } - elsif ( $Sort::Versions::VERSION or defined( _load('Sort::Versions') ) ) - { - - # use Sort::Versions as the sorting algorithm for a.b.c versions - return Sort::Versions::versioncmp( $cur, $min ); - } - - warn "Cannot reliably compare non-decimal formatted versions.\n" - . "Please install version.pm or Sort::Versions.\n"; - } - - # plain comparison - local $^W = 0; # shuts off 'not numeric' bugs - return $cur <=> $min; -} - -# nothing; this usage is deprecated. -sub main::PREREQ_PM { return {}; } - -sub _make_args { - my %args = @_; - - $args{PREREQ_PM} = { %{ $args{PREREQ_PM} || {} }, @Existing, @Missing } - if $UnderCPAN or $TestOnly; - - if ( $args{EXE_FILES} and -e 'MANIFEST' ) { - require ExtUtils::Manifest; - my $manifest = ExtUtils::Manifest::maniread('MANIFEST'); - - $args{EXE_FILES} = - [ grep { exists $manifest->{$_} } @{ $args{EXE_FILES} } ]; - } - - $args{test}{TESTS} ||= 't/*.t'; - $args{test}{TESTS} = join( ' ', - grep { !exists( $DisabledTests{$_} ) } - map { glob($_) } split( /\s+/, $args{test}{TESTS} ) ); - - my $missing = join( ',', @Missing ); - my $config = - join( ',', UNIVERSAL::isa( $Config, 'HASH' ) ? %{$Config} : @{$Config} ) - if $Config; - - $PostambleActions = ( - ($missing and not $UnderCPAN) - ? "\$(PERL) $0 --config=$config --installdeps=$missing" - : "\$(NOECHO) \$(NOOP)" - ); - - return %args; -} - -# a wrapper to ExtUtils::MakeMaker::WriteMakefile -sub Write { - require Carp; - Carp::croak "WriteMakefile: Need even number of args" if @_ % 2; - - if ($CheckOnly) { - print << "."; -*** Makefile not written in check-only mode. -. - return; - } - - my %args = _make_args(@_); - - no strict 'refs'; - - $PostambleUsed = 0; - local *MY::postamble = \&postamble unless defined &MY::postamble; - ExtUtils::MakeMaker::WriteMakefile(%args); - - print << "." unless $PostambleUsed; -*** WARNING: Makefile written with customized MY::postamble() without - including contents from Module::AutoInstall::postamble() -- - auto installation features disabled. Please contact the author. -. - - return 1; -} - -sub postamble { - $PostambleUsed = 1; - - return <<"END_MAKE"; - -config :: installdeps -\t\$(NOECHO) \$(NOOP) - -checkdeps :: -\t\$(PERL) $0 --checkdeps - -installdeps :: -\t$PostambleActions - -END_MAKE - -} - -1; - -__END__ - -#line 1071 diff --git a/debian/modules/http-subs-filter/test/inc/Module/Install.pm b/debian/modules/http-subs-filter/test/inc/Module/Install.pm deleted file mode 100644 index 74caf9c..0000000 --- a/debian/modules/http-subs-filter/test/inc/Module/Install.pm +++ /dev/null @@ -1,470 +0,0 @@ -#line 1 -package Module::Install; - -# For any maintainers: -# The load order for Module::Install is a bit magic. -# It goes something like this... -# -# IF ( host has Module::Install installed, creating author mode ) { -# 1. Makefile.PL calls "use inc::Module::Install" -# 2. $INC{inc/Module/Install.pm} set to installed version of inc::Module::Install -# 3. The installed version of inc::Module::Install loads -# 4. inc::Module::Install calls "require Module::Install" -# 5. The ./inc/ version of Module::Install loads -# } ELSE { -# 1. Makefile.PL calls "use inc::Module::Install" -# 2. $INC{inc/Module/Install.pm} set to ./inc/ version of Module::Install -# 3. The ./inc/ version of Module::Install loads -# } - -use 5.005; -use strict 'vars'; -use Cwd (); -use File::Find (); -use File::Path (); - -use vars qw{$VERSION $MAIN}; -BEGIN { - # All Module::Install core packages now require synchronised versions. - # This will be used to ensure we don't accidentally load old or - # different versions of modules. - # This is not enforced yet, but will be some time in the next few - # releases once we can make sure it won't clash with custom - # Module::Install extensions. - $VERSION = '1.01'; - - # Storage for the pseudo-singleton - $MAIN = undef; - - *inc::Module::Install::VERSION = *VERSION; - @inc::Module::Install::ISA = __PACKAGE__; - -} - -sub import { - my $class = shift; - my $self = $class->new(@_); - my $who = $self->_caller; - - #------------------------------------------------------------- - # all of the following checks should be included in import(), - # to allow "eval 'require Module::Install; 1' to test - # installation of Module::Install. (RT #51267) - #------------------------------------------------------------- - - # Whether or not inc::Module::Install is actually loaded, the - # $INC{inc/Module/Install.pm} is what will still get set as long as - # the caller loaded module this in the documented manner. - # If not set, the caller may NOT have loaded the bundled version, and thus - # they may not have a MI version that works with the Makefile.PL. This would - # result in false errors or unexpected behaviour. And we don't want that. - my $file = join( '/', 'inc', split /::/, __PACKAGE__ ) . '.pm'; - unless ( $INC{$file} ) { die <<"END_DIE" } - -Please invoke ${\__PACKAGE__} with: - - use inc::${\__PACKAGE__}; - -not: - - use ${\__PACKAGE__}; - -END_DIE - - # This reportedly fixes a rare Win32 UTC file time issue, but - # as this is a non-cross-platform XS module not in the core, - # we shouldn't really depend on it. See RT #24194 for detail. - # (Also, this module only supports Perl 5.6 and above). - eval "use Win32::UTCFileTime" if $^O eq 'MSWin32' && $] >= 5.006; - - # If the script that is loading Module::Install is from the future, - # then make will detect this and cause it to re-run over and over - # again. This is bad. Rather than taking action to touch it (which - # is unreliable on some platforms and requires write permissions) - # for now we should catch this and refuse to run. - if ( -f $0 ) { - my $s = (stat($0))[9]; - - # If the modification time is only slightly in the future, - # sleep briefly to remove the problem. - my $a = $s - time; - if ( $a > 0 and $a < 5 ) { sleep 5 } - - # Too far in the future, throw an error. - my $t = time; - if ( $s > $t ) { die <<"END_DIE" } - -Your installer $0 has a modification time in the future ($s > $t). - -This is known to create infinite loops in make. - -Please correct this, then run $0 again. - -END_DIE - } - - - # Build.PL was formerly supported, but no longer is due to excessive - # difficulty in implementing every single feature twice. - if ( $0 =~ /Build.PL$/i ) { die <<"END_DIE" } - -Module::Install no longer supports Build.PL. - -It was impossible to maintain duel backends, and has been deprecated. - -Please remove all Build.PL files and only use the Makefile.PL installer. - -END_DIE - - #------------------------------------------------------------- - - # To save some more typing in Module::Install installers, every... - # use inc::Module::Install - # ...also acts as an implicit use strict. - $^H |= strict::bits(qw(refs subs vars)); - - #------------------------------------------------------------- - - unless ( -f $self->{file} ) { - foreach my $key (keys %INC) { - delete $INC{$key} if $key =~ /Module\/Install/; - } - - local $^W; - require "$self->{path}/$self->{dispatch}.pm"; - File::Path::mkpath("$self->{prefix}/$self->{author}"); - $self->{admin} = "$self->{name}::$self->{dispatch}"->new( _top => $self ); - $self->{admin}->init; - @_ = ($class, _self => $self); - goto &{"$self->{name}::import"}; - } - - local $^W; - *{"${who}::AUTOLOAD"} = $self->autoload; - $self->preload; - - # Unregister loader and worker packages so subdirs can use them again - delete $INC{'inc/Module/Install.pm'}; - delete $INC{'Module/Install.pm'}; - - # Save to the singleton - $MAIN = $self; - - return 1; -} - -sub autoload { - my $self = shift; - my $who = $self->_caller; - my $cwd = Cwd::cwd(); - my $sym = "${who}::AUTOLOAD"; - $sym->{$cwd} = sub { - my $pwd = Cwd::cwd(); - if ( my $code = $sym->{$pwd} ) { - # Delegate back to parent dirs - goto &$code unless $cwd eq $pwd; - } - unless ($$sym =~ s/([^:]+)$//) { - # XXX: it looks like we can't retrieve the missing function - # via $$sym (usually $main::AUTOLOAD) in this case. - # I'm still wondering if we should slurp Makefile.PL to - # get some context or not ... - my ($package, $file, $line) = caller; - die <<"EOT"; -Unknown function is found at $file line $line. -Execution of $file aborted due to runtime errors. - -If you're a contributor to a project, you may need to install -some Module::Install extensions from CPAN (or other repository). -If you're a user of a module, please contact the author. -EOT - } - my $method = $1; - if ( uc($method) eq $method ) { - # Do nothing - return; - } elsif ( $method =~ /^_/ and $self->can($method) ) { - # Dispatch to the root M:I class - return $self->$method(@_); - } - - # Dispatch to the appropriate plugin - unshift @_, ( $self, $1 ); - goto &{$self->can('call')}; - }; -} - -sub preload { - my $self = shift; - unless ( $self->{extensions} ) { - $self->load_extensions( - "$self->{prefix}/$self->{path}", $self - ); - } - - my @exts = @{$self->{extensions}}; - unless ( @exts ) { - @exts = $self->{admin}->load_all_extensions; - } - - my %seen; - foreach my $obj ( @exts ) { - while (my ($method, $glob) = each %{ref($obj) . '::'}) { - next unless $obj->can($method); - next if $method =~ /^_/; - next if $method eq uc($method); - $seen{$method}++; - } - } - - my $who = $self->_caller; - foreach my $name ( sort keys %seen ) { - local $^W; - *{"${who}::$name"} = sub { - ${"${who}::AUTOLOAD"} = "${who}::$name"; - goto &{"${who}::AUTOLOAD"}; - }; - } -} - -sub new { - my ($class, %args) = @_; - - delete $INC{'FindBin.pm'}; - { - # to suppress the redefine warning - local $SIG{__WARN__} = sub {}; - require FindBin; - } - - # ignore the prefix on extension modules built from top level. - my $base_path = Cwd::abs_path($FindBin::Bin); - unless ( Cwd::abs_path(Cwd::cwd()) eq $base_path ) { - delete $args{prefix}; - } - return $args{_self} if $args{_self}; - - $args{dispatch} ||= 'Admin'; - $args{prefix} ||= 'inc'; - $args{author} ||= ($^O eq 'VMS' ? '_author' : '.author'); - $args{bundle} ||= 'inc/BUNDLES'; - $args{base} ||= $base_path; - $class =~ s/^\Q$args{prefix}\E:://; - $args{name} ||= $class; - $args{version} ||= $class->VERSION; - unless ( $args{path} ) { - $args{path} = $args{name}; - $args{path} =~ s!::!/!g; - } - $args{file} ||= "$args{base}/$args{prefix}/$args{path}.pm"; - $args{wrote} = 0; - - bless( \%args, $class ); -} - -sub call { - my ($self, $method) = @_; - my $obj = $self->load($method) or return; - splice(@_, 0, 2, $obj); - goto &{$obj->can($method)}; -} - -sub load { - my ($self, $method) = @_; - - $self->load_extensions( - "$self->{prefix}/$self->{path}", $self - ) unless $self->{extensions}; - - foreach my $obj (@{$self->{extensions}}) { - return $obj if $obj->can($method); - } - - my $admin = $self->{admin} or die <<"END_DIE"; -The '$method' method does not exist in the '$self->{prefix}' path! -Please remove the '$self->{prefix}' directory and run $0 again to load it. -END_DIE - - my $obj = $admin->load($method, 1); - push @{$self->{extensions}}, $obj; - - $obj; -} - -sub load_extensions { - my ($self, $path, $top) = @_; - - my $should_reload = 0; - unless ( grep { ! ref $_ and lc $_ eq lc $self->{prefix} } @INC ) { - unshift @INC, $self->{prefix}; - $should_reload = 1; - } - - foreach my $rv ( $self->find_extensions($path) ) { - my ($file, $pkg) = @{$rv}; - next if $self->{pathnames}{$pkg}; - - local $@; - my $new = eval { local $^W; require $file; $pkg->can('new') }; - unless ( $new ) { - warn $@ if $@; - next; - } - $self->{pathnames}{$pkg} = - $should_reload ? delete $INC{$file} : $INC{$file}; - push @{$self->{extensions}}, &{$new}($pkg, _top => $top ); - } - - $self->{extensions} ||= []; -} - -sub find_extensions { - my ($self, $path) = @_; - - my @found; - File::Find::find( sub { - my $file = $File::Find::name; - return unless $file =~ m!^\Q$path\E/(.+)\.pm\Z!is; - my $subpath = $1; - return if lc($subpath) eq lc($self->{dispatch}); - - $file = "$self->{path}/$subpath.pm"; - my $pkg = "$self->{name}::$subpath"; - $pkg =~ s!/!::!g; - - # If we have a mixed-case package name, assume case has been preserved - # correctly. Otherwise, root through the file to locate the case-preserved - # version of the package name. - if ( $subpath eq lc($subpath) || $subpath eq uc($subpath) ) { - my $content = Module::Install::_read($subpath . '.pm'); - my $in_pod = 0; - foreach ( split //, $content ) { - $in_pod = 1 if /^=\w/; - $in_pod = 0 if /^=cut/; - next if ($in_pod || /^=cut/); # skip pod text - next if /^\s*#/; # and comments - if ( m/^\s*package\s+($pkg)\s*;/i ) { - $pkg = $1; - last; - } - } - } - - push @found, [ $file, $pkg ]; - }, $path ) if -d $path; - - @found; -} - - - - - -##################################################################### -# Common Utility Functions - -sub _caller { - my $depth = 0; - my $call = caller($depth); - while ( $call eq __PACKAGE__ ) { - $depth++; - $call = caller($depth); - } - return $call; -} - -# Done in evals to avoid confusing Perl::MinimumVersion -eval( $] >= 5.006 ? <<'END_NEW' : <<'END_OLD' ); die $@ if $@; -sub _read { - local *FH; - open( FH, '<', $_[0] ) or die "open($_[0]): $!"; - my $string = do { local $/; }; - close FH or die "close($_[0]): $!"; - return $string; -} -END_NEW -sub _read { - local *FH; - open( FH, "< $_[0]" ) or die "open($_[0]): $!"; - my $string = do { local $/; }; - close FH or die "close($_[0]): $!"; - return $string; -} -END_OLD - -sub _readperl { - my $string = Module::Install::_read($_[0]); - $string =~ s/(?:\015{1,2}\012|\015|\012)/\n/sg; - $string =~ s/(\n)\n*__(?:DATA|END)__\b.*\z/$1/s; - $string =~ s/\n\n=\w+.+?\n\n=cut\b.+?\n+/\n\n/sg; - return $string; -} - -sub _readpod { - my $string = Module::Install::_read($_[0]); - $string =~ s/(?:\015{1,2}\012|\015|\012)/\n/sg; - return $string if $_[0] =~ /\.pod\z/; - $string =~ s/(^|\n=cut\b.+?\n+)[^=\s].+?\n(\n=\w+|\z)/$1$2/sg; - $string =~ s/\n*=pod\b[^\n]*\n+/\n\n/sg; - $string =~ s/\n*=cut\b[^\n]*\n+/\n\n/sg; - $string =~ s/^\n+//s; - return $string; -} - -# Done in evals to avoid confusing Perl::MinimumVersion -eval( $] >= 5.006 ? <<'END_NEW' : <<'END_OLD' ); die $@ if $@; -sub _write { - local *FH; - open( FH, '>', $_[0] ) or die "open($_[0]): $!"; - foreach ( 1 .. $#_ ) { - print FH $_[$_] or die "print($_[0]): $!"; - } - close FH or die "close($_[0]): $!"; -} -END_NEW -sub _write { - local *FH; - open( FH, "> $_[0]" ) or die "open($_[0]): $!"; - foreach ( 1 .. $#_ ) { - print FH $_[$_] or die "print($_[0]): $!"; - } - close FH or die "close($_[0]): $!"; -} -END_OLD - -# _version is for processing module versions (eg, 1.03_05) not -# Perl versions (eg, 5.8.1). -sub _version ($) { - my $s = shift || 0; - my $d =()= $s =~ /(\.)/g; - if ( $d >= 2 ) { - # Normalise multipart versions - $s =~ s/(\.)(\d{1,3})/sprintf("$1%03d",$2)/eg; - } - $s =~ s/^(\d+)\.?//; - my $l = $1 || 0; - my @v = map { - $_ . '0' x (3 - length $_) - } $s =~ /(\d{1,3})\D?/g; - $l = $l . '.' . join '', @v if @v; - return $l + 0; -} - -sub _cmp ($$) { - _version($_[0]) <=> _version($_[1]); -} - -# Cloned from Params::Util::_CLASS -sub _CLASS ($) { - ( - defined $_[0] - and - ! ref $_[0] - and - $_[0] =~ m/^[^\W\d]\w*(?:::\w+)*\z/s - ) ? $_[0] : undef; -} - -1; - -# Copyright 2008 - 2011 Adam Kennedy. diff --git a/debian/modules/http-subs-filter/test/inc/Module/Install/AutoInstall.pm b/debian/modules/http-subs-filter/test/inc/Module/Install/AutoInstall.pm deleted file mode 100644 index bc3d172..0000000 --- a/debian/modules/http-subs-filter/test/inc/Module/Install/AutoInstall.pm +++ /dev/null @@ -1,82 +0,0 @@ -#line 1 -package Module::Install::AutoInstall; - -use strict; -use Module::Install::Base (); - -use vars qw{$VERSION @ISA $ISCORE}; -BEGIN { - $VERSION = '1.01'; - @ISA = 'Module::Install::Base'; - $ISCORE = 1; -} - -sub AutoInstall { $_[0] } - -sub run { - my $self = shift; - $self->auto_install_now(@_); -} - -sub write { - my $self = shift; - $self->auto_install(@_); -} - -sub auto_install { - my $self = shift; - return if $self->{done}++; - - # Flatten array of arrays into a single array - my @core = map @$_, map @$_, grep ref, - $self->build_requires, $self->requires; - - my @config = @_; - - # We'll need Module::AutoInstall - $self->include('Module::AutoInstall'); - require Module::AutoInstall; - - my @features_require = Module::AutoInstall->import( - (@config ? (-config => \@config) : ()), - (@core ? (-core => \@core) : ()), - $self->features, - ); - - my %seen; - my @requires = map @$_, map @$_, grep ref, $self->requires; - while (my ($mod, $ver) = splice(@requires, 0, 2)) { - $seen{$mod}{$ver}++; - } - my @build_requires = map @$_, map @$_, grep ref, $self->build_requires; - while (my ($mod, $ver) = splice(@build_requires, 0, 2)) { - $seen{$mod}{$ver}++; - } - my @configure_requires = map @$_, map @$_, grep ref, $self->configure_requires; - while (my ($mod, $ver) = splice(@configure_requires, 0, 2)) { - $seen{$mod}{$ver}++; - } - - my @deduped; - while (my ($mod, $ver) = splice(@features_require, 0, 2)) { - push @deduped, $mod => $ver unless $seen{$mod}{$ver}++; - } - - $self->requires(@deduped); - - $self->makemaker_args( Module::AutoInstall::_make_args() ); - - my $class = ref($self); - $self->postamble( - "# --- $class section:\n" . - Module::AutoInstall::postamble() - ); -} - -sub auto_install_now { - my $self = shift; - $self->auto_install(@_); - Module::AutoInstall::do_install(); -} - -1; diff --git a/debian/modules/http-subs-filter/test/inc/Module/Install/Base.pm b/debian/modules/http-subs-filter/test/inc/Module/Install/Base.pm deleted file mode 100644 index d3662c9..0000000 --- a/debian/modules/http-subs-filter/test/inc/Module/Install/Base.pm +++ /dev/null @@ -1,83 +0,0 @@ -#line 1 -package Module::Install::Base; - -use strict 'vars'; -use vars qw{$VERSION}; -BEGIN { - $VERSION = '1.01'; -} - -# Suspend handler for "redefined" warnings -BEGIN { - my $w = $SIG{__WARN__}; - $SIG{__WARN__} = sub { $w }; -} - -#line 42 - -sub new { - my $class = shift; - unless ( defined &{"${class}::call"} ) { - *{"${class}::call"} = sub { shift->_top->call(@_) }; - } - unless ( defined &{"${class}::load"} ) { - *{"${class}::load"} = sub { shift->_top->load(@_) }; - } - bless { @_ }, $class; -} - -#line 61 - -sub AUTOLOAD { - local $@; - my $func = eval { shift->_top->autoload } or return; - goto &$func; -} - -#line 75 - -sub _top { - $_[0]->{_top}; -} - -#line 90 - -sub admin { - $_[0]->_top->{admin} - or - Module::Install::Base::FakeAdmin->new; -} - -#line 106 - -sub is_admin { - ! $_[0]->admin->isa('Module::Install::Base::FakeAdmin'); -} - -sub DESTROY {} - -package Module::Install::Base::FakeAdmin; - -use vars qw{$VERSION}; -BEGIN { - $VERSION = $Module::Install::Base::VERSION; -} - -my $fake; - -sub new { - $fake ||= bless(\@_, $_[0]); -} - -sub AUTOLOAD {} - -sub DESTROY {} - -# Restore warning handler -BEGIN { - $SIG{__WARN__} = $SIG{__WARN__}->(); -} - -1; - -#line 159 diff --git a/debian/modules/http-subs-filter/test/inc/Module/Install/Can.pm b/debian/modules/http-subs-filter/test/inc/Module/Install/Can.pm deleted file mode 100644 index 276409a..0000000 --- a/debian/modules/http-subs-filter/test/inc/Module/Install/Can.pm +++ /dev/null @@ -1,81 +0,0 @@ -#line 1 -package Module::Install::Can; - -use strict; -use Config (); -use File::Spec (); -use ExtUtils::MakeMaker (); -use Module::Install::Base (); - -use vars qw{$VERSION @ISA $ISCORE}; -BEGIN { - $VERSION = '1.01'; - @ISA = 'Module::Install::Base'; - $ISCORE = 1; -} - -# check if we can load some module -### Upgrade this to not have to load the module if possible -sub can_use { - my ($self, $mod, $ver) = @_; - $mod =~ s{::|\\}{/}g; - $mod .= '.pm' unless $mod =~ /\.pm$/i; - - my $pkg = $mod; - $pkg =~ s{/}{::}g; - $pkg =~ s{\.pm$}{}i; - - local $@; - eval { require $mod; $pkg->VERSION($ver || 0); 1 }; -} - -# check if we can run some command -sub can_run { - my ($self, $cmd) = @_; - - my $_cmd = $cmd; - return $_cmd if (-x $_cmd or $_cmd = MM->maybe_command($_cmd)); - - for my $dir ((split /$Config::Config{path_sep}/, $ENV{PATH}), '.') { - next if $dir eq ''; - my $abs = File::Spec->catfile($dir, $_[1]); - return $abs if (-x $abs or $abs = MM->maybe_command($abs)); - } - - return; -} - -# can we locate a (the) C compiler -sub can_cc { - my $self = shift; - my @chunks = split(/ /, $Config::Config{cc}) or return; - - # $Config{cc} may contain args; try to find out the program part - while (@chunks) { - return $self->can_run("@chunks") || (pop(@chunks), next); - } - - return; -} - -# Fix Cygwin bug on maybe_command(); -if ( $^O eq 'cygwin' ) { - require ExtUtils::MM_Cygwin; - require ExtUtils::MM_Win32; - if ( ! defined(&ExtUtils::MM_Cygwin::maybe_command) ) { - *ExtUtils::MM_Cygwin::maybe_command = sub { - my ($self, $file) = @_; - if ($file =~ m{^/cygdrive/}i and ExtUtils::MM_Win32->can('maybe_command')) { - ExtUtils::MM_Win32->maybe_command($file); - } else { - ExtUtils::MM_Unix->maybe_command($file); - } - } - } -} - -1; - -__END__ - -#line 156 diff --git a/debian/modules/http-subs-filter/test/inc/Module/Install/Fetch.pm b/debian/modules/http-subs-filter/test/inc/Module/Install/Fetch.pm deleted file mode 100644 index 093cb7a..0000000 --- a/debian/modules/http-subs-filter/test/inc/Module/Install/Fetch.pm +++ /dev/null @@ -1,93 +0,0 @@ -#line 1 -package Module::Install::Fetch; - -use strict; -use Module::Install::Base (); - -use vars qw{$VERSION @ISA $ISCORE}; -BEGIN { - $VERSION = '1.01'; - @ISA = 'Module::Install::Base'; - $ISCORE = 1; -} - -sub get_file { - my ($self, %args) = @_; - my ($scheme, $host, $path, $file) = - $args{url} =~ m|^(\w+)://([^/]+)(.+)/(.+)| or return; - - if ( $scheme eq 'http' and ! eval { require LWP::Simple; 1 } ) { - $args{url} = $args{ftp_url} - or (warn("LWP support unavailable!\n"), return); - ($scheme, $host, $path, $file) = - $args{url} =~ m|^(\w+)://([^/]+)(.+)/(.+)| or return; - } - - $|++; - print "Fetching '$file' from $host... "; - - unless (eval { require Socket; Socket::inet_aton($host) }) { - warn "'$host' resolve failed!\n"; - return; - } - - return unless $scheme eq 'ftp' or $scheme eq 'http'; - - require Cwd; - my $dir = Cwd::getcwd(); - chdir $args{local_dir} or return if exists $args{local_dir}; - - if (eval { require LWP::Simple; 1 }) { - LWP::Simple::mirror($args{url}, $file); - } - elsif (eval { require Net::FTP; 1 }) { eval { - # use Net::FTP to get past firewall - my $ftp = Net::FTP->new($host, Passive => 1, Timeout => 600); - $ftp->login("anonymous", 'anonymous@example.com'); - $ftp->cwd($path); - $ftp->binary; - $ftp->get($file) or (warn("$!\n"), return); - $ftp->quit; - } } - elsif (my $ftp = $self->can_run('ftp')) { eval { - # no Net::FTP, fallback to ftp.exe - require FileHandle; - my $fh = FileHandle->new; - - local $SIG{CHLD} = 'IGNORE'; - unless ($fh->open("|$ftp -n")) { - warn "Couldn't open ftp: $!\n"; - chdir $dir; return; - } - - my @dialog = split(/\n/, <<"END_FTP"); -open $host -user anonymous anonymous\@example.com -cd $path -binary -get $file $file -quit -END_FTP - foreach (@dialog) { $fh->print("$_\n") } - $fh->close; - } } - else { - warn "No working 'ftp' program available!\n"; - chdir $dir; return; - } - - unless (-f $file) { - warn "Fetching failed: $@\n"; - chdir $dir; return; - } - - return if exists $args{size} and -s $file != $args{size}; - system($args{run}) if exists $args{run}; - unlink($file) if $args{remove}; - - print(((!exists $args{check_for} or -e $args{check_for}) - ? "done!" : "failed! ($!)"), "\n"); - chdir $dir; return !$?; -} - -1; diff --git a/debian/modules/http-subs-filter/test/inc/Module/Install/Include.pm b/debian/modules/http-subs-filter/test/inc/Module/Install/Include.pm deleted file mode 100644 index 90cc979..0000000 --- a/debian/modules/http-subs-filter/test/inc/Module/Install/Include.pm +++ /dev/null @@ -1,34 +0,0 @@ -#line 1 -package Module::Install::Include; - -use strict; -use Module::Install::Base (); - -use vars qw{$VERSION @ISA $ISCORE}; -BEGIN { - $VERSION = '1.01'; - @ISA = 'Module::Install::Base'; - $ISCORE = 1; -} - -sub include { - shift()->admin->include(@_); -} - -sub include_deps { - shift()->admin->include_deps(@_); -} - -sub auto_include { - shift()->admin->auto_include(@_); -} - -sub auto_include_deps { - shift()->admin->auto_include_deps(@_); -} - -sub auto_include_dependent_dists { - shift()->admin->auto_include_dependent_dists(@_); -} - -1; diff --git a/debian/modules/http-subs-filter/test/inc/Module/Install/Makefile.pm b/debian/modules/http-subs-filter/test/inc/Module/Install/Makefile.pm deleted file mode 100644 index 4c71003..0000000 --- a/debian/modules/http-subs-filter/test/inc/Module/Install/Makefile.pm +++ /dev/null @@ -1,415 +0,0 @@ -#line 1 -package Module::Install::Makefile; - -use strict 'vars'; -use ExtUtils::MakeMaker (); -use Module::Install::Base (); -use Fcntl qw/:flock :seek/; - -use vars qw{$VERSION @ISA $ISCORE}; -BEGIN { - $VERSION = '1.01'; - @ISA = 'Module::Install::Base'; - $ISCORE = 1; -} - -sub Makefile { $_[0] } - -my %seen = (); - -sub prompt { - shift; - - # Infinite loop protection - my @c = caller(); - if ( ++$seen{"$c[1]|$c[2]|$_[0]"} > 3 ) { - die "Caught an potential prompt infinite loop ($c[1]|$c[2]|$_[0])"; - } - - # In automated testing or non-interactive session, always use defaults - if ( ($ENV{AUTOMATED_TESTING} or -! -t STDIN) and ! $ENV{PERL_MM_USE_DEFAULT} ) { - local $ENV{PERL_MM_USE_DEFAULT} = 1; - goto &ExtUtils::MakeMaker::prompt; - } else { - goto &ExtUtils::MakeMaker::prompt; - } -} - -# Store a cleaned up version of the MakeMaker version, -# since we need to behave differently in a variety of -# ways based on the MM version. -my $makemaker = eval $ExtUtils::MakeMaker::VERSION; - -# If we are passed a param, do a "newer than" comparison. -# Otherwise, just return the MakeMaker version. -sub makemaker { - ( @_ < 2 or $makemaker >= eval($_[1]) ) ? $makemaker : 0 -} - -# Ripped from ExtUtils::MakeMaker 6.56, and slightly modified -# as we only need to know here whether the attribute is an array -# or a hash or something else (which may or may not be appendable). -my %makemaker_argtype = ( - C => 'ARRAY', - CONFIG => 'ARRAY', -# CONFIGURE => 'CODE', # ignore - DIR => 'ARRAY', - DL_FUNCS => 'HASH', - DL_VARS => 'ARRAY', - EXCLUDE_EXT => 'ARRAY', - EXE_FILES => 'ARRAY', - FUNCLIST => 'ARRAY', - H => 'ARRAY', - IMPORTS => 'HASH', - INCLUDE_EXT => 'ARRAY', - LIBS => 'ARRAY', # ignore '' - MAN1PODS => 'HASH', - MAN3PODS => 'HASH', - META_ADD => 'HASH', - META_MERGE => 'HASH', - PL_FILES => 'HASH', - PM => 'HASH', - PMLIBDIRS => 'ARRAY', - PMLIBPARENTDIRS => 'ARRAY', - PREREQ_PM => 'HASH', - CONFIGURE_REQUIRES => 'HASH', - SKIP => 'ARRAY', - TYPEMAPS => 'ARRAY', - XS => 'HASH', -# VERSION => ['version',''], # ignore -# _KEEP_AFTER_FLUSH => '', - - clean => 'HASH', - depend => 'HASH', - dist => 'HASH', - dynamic_lib=> 'HASH', - linkext => 'HASH', - macro => 'HASH', - postamble => 'HASH', - realclean => 'HASH', - test => 'HASH', - tool_autosplit => 'HASH', - - # special cases where you can use makemaker_append - CCFLAGS => 'APPENDABLE', - DEFINE => 'APPENDABLE', - INC => 'APPENDABLE', - LDDLFLAGS => 'APPENDABLE', - LDFROM => 'APPENDABLE', -); - -sub makemaker_args { - my ($self, %new_args) = @_; - my $args = ( $self->{makemaker_args} ||= {} ); - foreach my $key (keys %new_args) { - if ($makemaker_argtype{$key}) { - if ($makemaker_argtype{$key} eq 'ARRAY') { - $args->{$key} = [] unless defined $args->{$key}; - unless (ref $args->{$key} eq 'ARRAY') { - $args->{$key} = [$args->{$key}] - } - push @{$args->{$key}}, - ref $new_args{$key} eq 'ARRAY' - ? @{$new_args{$key}} - : $new_args{$key}; - } - elsif ($makemaker_argtype{$key} eq 'HASH') { - $args->{$key} = {} unless defined $args->{$key}; - foreach my $skey (keys %{ $new_args{$key} }) { - $args->{$key}{$skey} = $new_args{$key}{$skey}; - } - } - elsif ($makemaker_argtype{$key} eq 'APPENDABLE') { - $self->makemaker_append($key => $new_args{$key}); - } - } - else { - if (defined $args->{$key}) { - warn qq{MakeMaker attribute "$key" is overriden; use "makemaker_append" to append values\n}; - } - $args->{$key} = $new_args{$key}; - } - } - return $args; -} - -# For mm args that take multiple space-seperated args, -# append an argument to the current list. -sub makemaker_append { - my $self = shift; - my $name = shift; - my $args = $self->makemaker_args; - $args->{$name} = defined $args->{$name} - ? join( ' ', $args->{$name}, @_ ) - : join( ' ', @_ ); -} - -sub build_subdirs { - my $self = shift; - my $subdirs = $self->makemaker_args->{DIR} ||= []; - for my $subdir (@_) { - push @$subdirs, $subdir; - } -} - -sub clean_files { - my $self = shift; - my $clean = $self->makemaker_args->{clean} ||= {}; - %$clean = ( - %$clean, - FILES => join ' ', grep { length $_ } ($clean->{FILES} || (), @_), - ); -} - -sub realclean_files { - my $self = shift; - my $realclean = $self->makemaker_args->{realclean} ||= {}; - %$realclean = ( - %$realclean, - FILES => join ' ', grep { length $_ } ($realclean->{FILES} || (), @_), - ); -} - -sub libs { - my $self = shift; - my $libs = ref $_[0] ? shift : [ shift ]; - $self->makemaker_args( LIBS => $libs ); -} - -sub inc { - my $self = shift; - $self->makemaker_args( INC => shift ); -} - -sub _wanted_t { -} - -sub tests_recursive { - my $self = shift; - my $dir = shift || 't'; - unless ( -d $dir ) { - die "tests_recursive dir '$dir' does not exist"; - } - my %tests = map { $_ => 1 } split / /, ($self->tests || ''); - require File::Find; - File::Find::find( - sub { /\.t$/ and -f $_ and $tests{"$File::Find::dir/*.t"} = 1 }, - $dir - ); - $self->tests( join ' ', sort keys %tests ); -} - -sub write { - my $self = shift; - die "&Makefile->write() takes no arguments\n" if @_; - - # Check the current Perl version - my $perl_version = $self->perl_version; - if ( $perl_version ) { - eval "use $perl_version; 1" - or die "ERROR: perl: Version $] is installed, " - . "but we need version >= $perl_version"; - } - - # Make sure we have a new enough MakeMaker - require ExtUtils::MakeMaker; - - if ( $perl_version and $self->_cmp($perl_version, '5.006') >= 0 ) { - # MakeMaker can complain about module versions that include - # an underscore, even though its own version may contain one! - # Hence the funny regexp to get rid of it. See RT #35800 - # for details. - my $v = $ExtUtils::MakeMaker::VERSION =~ /^(\d+\.\d+)/; - $self->build_requires( 'ExtUtils::MakeMaker' => $v ); - $self->configure_requires( 'ExtUtils::MakeMaker' => $v ); - } else { - # Allow legacy-compatibility with 5.005 by depending on the - # most recent EU:MM that supported 5.005. - $self->build_requires( 'ExtUtils::MakeMaker' => 6.42 ); - $self->configure_requires( 'ExtUtils::MakeMaker' => 6.42 ); - } - - # Generate the MakeMaker params - my $args = $self->makemaker_args; - $args->{DISTNAME} = $self->name; - $args->{NAME} = $self->module_name || $self->name; - $args->{NAME} =~ s/-/::/g; - $args->{VERSION} = $self->version or die <<'EOT'; -ERROR: Can't determine distribution version. Please specify it -explicitly via 'version' in Makefile.PL, or set a valid $VERSION -in a module, and provide its file path via 'version_from' (or -'all_from' if you prefer) in Makefile.PL. -EOT - - $DB::single = 1; - if ( $self->tests ) { - my @tests = split ' ', $self->tests; - my %seen; - $args->{test} = { - TESTS => (join ' ', grep {!$seen{$_}++} @tests), - }; - } elsif ( $Module::Install::ExtraTests::use_extratests ) { - # Module::Install::ExtraTests doesn't set $self->tests and does its own tests via harness. - # So, just ignore our xt tests here. - } elsif ( -d 'xt' and ($Module::Install::AUTHOR or $ENV{RELEASE_TESTING}) ) { - $args->{test} = { - TESTS => join( ' ', map { "$_/*.t" } grep { -d $_ } qw{ t xt } ), - }; - } - if ( $] >= 5.005 ) { - $args->{ABSTRACT} = $self->abstract; - $args->{AUTHOR} = join ', ', @{$self->author || []}; - } - if ( $self->makemaker(6.10) ) { - $args->{NO_META} = 1; - #$args->{NO_MYMETA} = 1; - } - if ( $self->makemaker(6.17) and $self->sign ) { - $args->{SIGN} = 1; - } - unless ( $self->is_admin ) { - delete $args->{SIGN}; - } - if ( $self->makemaker(6.31) and $self->license ) { - $args->{LICENSE} = $self->license; - } - - my $prereq = ($args->{PREREQ_PM} ||= {}); - %$prereq = ( %$prereq, - map { @$_ } # flatten [module => version] - map { @$_ } - grep $_, - ($self->requires) - ); - - # Remove any reference to perl, PREREQ_PM doesn't support it - delete $args->{PREREQ_PM}->{perl}; - - # Merge both kinds of requires into BUILD_REQUIRES - my $build_prereq = ($args->{BUILD_REQUIRES} ||= {}); - %$build_prereq = ( %$build_prereq, - map { @$_ } # flatten [module => version] - map { @$_ } - grep $_, - ($self->configure_requires, $self->build_requires) - ); - - # Remove any reference to perl, BUILD_REQUIRES doesn't support it - delete $args->{BUILD_REQUIRES}->{perl}; - - # Delete bundled dists from prereq_pm, add it to Makefile DIR - my $subdirs = ($args->{DIR} || []); - if ($self->bundles) { - my %processed; - foreach my $bundle (@{ $self->bundles }) { - my ($mod_name, $dist_dir) = @$bundle; - delete $prereq->{$mod_name}; - $dist_dir = File::Basename::basename($dist_dir); # dir for building this module - if (not exists $processed{$dist_dir}) { - if (-d $dist_dir) { - # List as sub-directory to be processed by make - push @$subdirs, $dist_dir; - } - # Else do nothing: the module is already present on the system - $processed{$dist_dir} = undef; - } - } - } - - unless ( $self->makemaker('6.55_03') ) { - %$prereq = (%$prereq,%$build_prereq); - delete $args->{BUILD_REQUIRES}; - } - - if ( my $perl_version = $self->perl_version ) { - eval "use $perl_version; 1" - or die "ERROR: perl: Version $] is installed, " - . "but we need version >= $perl_version"; - - if ( $self->makemaker(6.48) ) { - $args->{MIN_PERL_VERSION} = $perl_version; - } - } - - if ($self->installdirs) { - warn qq{old INSTALLDIRS (probably set by makemaker_args) is overriden by installdirs\n} if $args->{INSTALLDIRS}; - $args->{INSTALLDIRS} = $self->installdirs; - } - - my %args = map { - ( $_ => $args->{$_} ) } grep {defined($args->{$_} ) - } keys %$args; - - my $user_preop = delete $args{dist}->{PREOP}; - if ( my $preop = $self->admin->preop($user_preop) ) { - foreach my $key ( keys %$preop ) { - $args{dist}->{$key} = $preop->{$key}; - } - } - - my $mm = ExtUtils::MakeMaker::WriteMakefile(%args); - $self->fix_up_makefile($mm->{FIRST_MAKEFILE} || 'Makefile'); -} - -sub fix_up_makefile { - my $self = shift; - my $makefile_name = shift; - my $top_class = ref($self->_top) || ''; - my $top_version = $self->_top->VERSION || ''; - - my $preamble = $self->preamble - ? "# Preamble by $top_class $top_version\n" - . $self->preamble - : ''; - my $postamble = "# Postamble by $top_class $top_version\n" - . ($self->postamble || ''); - - local *MAKEFILE; - open MAKEFILE, "+< $makefile_name" or die "fix_up_makefile: Couldn't open $makefile_name: $!"; - eval { flock MAKEFILE, LOCK_EX }; - my $makefile = do { local $/; }; - - $makefile =~ s/\b(test_harness\(\$\(TEST_VERBOSE\), )/$1'inc', /; - $makefile =~ s/( -I\$\(INST_ARCHLIB\))/ -Iinc$1/g; - $makefile =~ s/( "-I\$\(INST_LIB\)")/ "-Iinc"$1/g; - $makefile =~ s/^(FULLPERL = .*)/$1 "-Iinc"/m; - $makefile =~ s/^(PERL = .*)/$1 "-Iinc"/m; - - # Module::Install will never be used to build the Core Perl - # Sometimes PERL_LIB and PERL_ARCHLIB get written anyway, which breaks - # PREFIX/PERL5LIB, and thus, install_share. Blank them if they exist - $makefile =~ s/^PERL_LIB = .+/PERL_LIB =/m; - #$makefile =~ s/^PERL_ARCHLIB = .+/PERL_ARCHLIB =/m; - - # Perl 5.005 mentions PERL_LIB explicitly, so we have to remove that as well. - $makefile =~ s/(\"?)-I\$\(PERL_LIB\)\1//g; - - # XXX - This is currently unused; not sure if it breaks other MM-users - # $makefile =~ s/^pm_to_blib\s+:\s+/pm_to_blib :: /mg; - - seek MAKEFILE, 0, SEEK_SET; - truncate MAKEFILE, 0; - print MAKEFILE "$preamble$makefile$postamble" or die $!; - close MAKEFILE or die $!; - - 1; -} - -sub preamble { - my ($self, $text) = @_; - $self->{preamble} = $text . $self->{preamble} if defined $text; - $self->{preamble}; -} - -sub postamble { - my ($self, $text) = @_; - $self->{postamble} ||= $self->admin->postamble; - $self->{postamble} .= $text if defined $text; - $self->{postamble} -} - -1; - -__END__ - -#line 541 diff --git a/debian/modules/http-subs-filter/test/inc/Module/Install/Metadata.pm b/debian/modules/http-subs-filter/test/inc/Module/Install/Metadata.pm deleted file mode 100644 index 3b01e09..0000000 --- a/debian/modules/http-subs-filter/test/inc/Module/Install/Metadata.pm +++ /dev/null @@ -1,716 +0,0 @@ -#line 1 -package Module::Install::Metadata; - -use strict 'vars'; -use Module::Install::Base (); - -use vars qw{$VERSION @ISA $ISCORE}; -BEGIN { - $VERSION = '1.01'; - @ISA = 'Module::Install::Base'; - $ISCORE = 1; -} - -my @boolean_keys = qw{ - sign -}; - -my @scalar_keys = qw{ - name - module_name - abstract - version - distribution_type - tests - installdirs -}; - -my @tuple_keys = qw{ - configure_requires - build_requires - requires - recommends - bundles - resources -}; - -my @resource_keys = qw{ - homepage - bugtracker - repository -}; - -my @array_keys = qw{ - keywords - author -}; - -*authors = \&author; - -sub Meta { shift } -sub Meta_BooleanKeys { @boolean_keys } -sub Meta_ScalarKeys { @scalar_keys } -sub Meta_TupleKeys { @tuple_keys } -sub Meta_ResourceKeys { @resource_keys } -sub Meta_ArrayKeys { @array_keys } - -foreach my $key ( @boolean_keys ) { - *$key = sub { - my $self = shift; - if ( defined wantarray and not @_ ) { - return $self->{values}->{$key}; - } - $self->{values}->{$key} = ( @_ ? $_[0] : 1 ); - return $self; - }; -} - -foreach my $key ( @scalar_keys ) { - *$key = sub { - my $self = shift; - return $self->{values}->{$key} if defined wantarray and !@_; - $self->{values}->{$key} = shift; - return $self; - }; -} - -foreach my $key ( @array_keys ) { - *$key = sub { - my $self = shift; - return $self->{values}->{$key} if defined wantarray and !@_; - $self->{values}->{$key} ||= []; - push @{$self->{values}->{$key}}, @_; - return $self; - }; -} - -foreach my $key ( @resource_keys ) { - *$key = sub { - my $self = shift; - unless ( @_ ) { - return () unless $self->{values}->{resources}; - return map { $_->[1] } - grep { $_->[0] eq $key } - @{ $self->{values}->{resources} }; - } - return $self->{values}->{resources}->{$key} unless @_; - my $uri = shift or die( - "Did not provide a value to $key()" - ); - $self->resources( $key => $uri ); - return 1; - }; -} - -foreach my $key ( grep { $_ ne "resources" } @tuple_keys) { - *$key = sub { - my $self = shift; - return $self->{values}->{$key} unless @_; - my @added; - while ( @_ ) { - my $module = shift or last; - my $version = shift || 0; - push @added, [ $module, $version ]; - } - push @{ $self->{values}->{$key} }, @added; - return map {@$_} @added; - }; -} - -# Resource handling -my %lc_resource = map { $_ => 1 } qw{ - homepage - license - bugtracker - repository -}; - -sub resources { - my $self = shift; - while ( @_ ) { - my $name = shift or last; - my $value = shift or next; - if ( $name eq lc $name and ! $lc_resource{$name} ) { - die("Unsupported reserved lowercase resource '$name'"); - } - $self->{values}->{resources} ||= []; - push @{ $self->{values}->{resources} }, [ $name, $value ]; - } - $self->{values}->{resources}; -} - -# Aliases for build_requires that will have alternative -# meanings in some future version of META.yml. -sub test_requires { shift->build_requires(@_) } -sub install_requires { shift->build_requires(@_) } - -# Aliases for installdirs options -sub install_as_core { $_[0]->installdirs('perl') } -sub install_as_cpan { $_[0]->installdirs('site') } -sub install_as_site { $_[0]->installdirs('site') } -sub install_as_vendor { $_[0]->installdirs('vendor') } - -sub dynamic_config { - my $self = shift; - unless ( @_ ) { - warn "You MUST provide an explicit true/false value to dynamic_config\n"; - return $self; - } - $self->{values}->{dynamic_config} = $_[0] ? 1 : 0; - return 1; -} - -sub perl_version { - my $self = shift; - return $self->{values}->{perl_version} unless @_; - my $version = shift or die( - "Did not provide a value to perl_version()" - ); - - # Normalize the version - $version = $self->_perl_version($version); - - # We don't support the reall old versions - unless ( $version >= 5.005 ) { - die "Module::Install only supports 5.005 or newer (use ExtUtils::MakeMaker)\n"; - } - - $self->{values}->{perl_version} = $version; -} - -sub all_from { - my ( $self, $file ) = @_; - - unless ( defined($file) ) { - my $name = $self->name or die( - "all_from called with no args without setting name() first" - ); - $file = join('/', 'lib', split(/-/, $name)) . '.pm'; - $file =~ s{.*/}{} unless -e $file; - unless ( -e $file ) { - die("all_from cannot find $file from $name"); - } - } - unless ( -f $file ) { - die("The path '$file' does not exist, or is not a file"); - } - - $self->{values}{all_from} = $file; - - # Some methods pull from POD instead of code. - # If there is a matching .pod, use that instead - my $pod = $file; - $pod =~ s/\.pm$/.pod/i; - $pod = $file unless -e $pod; - - # Pull the different values - $self->name_from($file) unless $self->name; - $self->version_from($file) unless $self->version; - $self->perl_version_from($file) unless $self->perl_version; - $self->author_from($pod) unless @{$self->author || []}; - $self->license_from($pod) unless $self->license; - $self->abstract_from($pod) unless $self->abstract; - - return 1; -} - -sub provides { - my $self = shift; - my $provides = ( $self->{values}->{provides} ||= {} ); - %$provides = (%$provides, @_) if @_; - return $provides; -} - -sub auto_provides { - my $self = shift; - return $self unless $self->is_admin; - unless (-e 'MANIFEST') { - warn "Cannot deduce auto_provides without a MANIFEST, skipping\n"; - return $self; - } - # Avoid spurious warnings as we are not checking manifest here. - local $SIG{__WARN__} = sub {1}; - require ExtUtils::Manifest; - local *ExtUtils::Manifest::manicheck = sub { return }; - - require Module::Build; - my $build = Module::Build->new( - dist_name => $self->name, - dist_version => $self->version, - license => $self->license, - ); - $self->provides( %{ $build->find_dist_packages || {} } ); -} - -sub feature { - my $self = shift; - my $name = shift; - my $features = ( $self->{values}->{features} ||= [] ); - my $mods; - - if ( @_ == 1 and ref( $_[0] ) ) { - # The user used ->feature like ->features by passing in the second - # argument as a reference. Accomodate for that. - $mods = $_[0]; - } else { - $mods = \@_; - } - - my $count = 0; - push @$features, ( - $name => [ - map { - ref($_) ? ( ref($_) eq 'HASH' ) ? %$_ : @$_ : $_ - } @$mods - ] - ); - - return @$features; -} - -sub features { - my $self = shift; - while ( my ( $name, $mods ) = splice( @_, 0, 2 ) ) { - $self->feature( $name, @$mods ); - } - return $self->{values}->{features} - ? @{ $self->{values}->{features} } - : (); -} - -sub no_index { - my $self = shift; - my $type = shift; - push @{ $self->{values}->{no_index}->{$type} }, @_ if $type; - return $self->{values}->{no_index}; -} - -sub read { - my $self = shift; - $self->include_deps( 'YAML::Tiny', 0 ); - - require YAML::Tiny; - my $data = YAML::Tiny::LoadFile('META.yml'); - - # Call methods explicitly in case user has already set some values. - while ( my ( $key, $value ) = each %$data ) { - next unless $self->can($key); - if ( ref $value eq 'HASH' ) { - while ( my ( $module, $version ) = each %$value ) { - $self->can($key)->($self, $module => $version ); - } - } else { - $self->can($key)->($self, $value); - } - } - return $self; -} - -sub write { - my $self = shift; - return $self unless $self->is_admin; - $self->admin->write_meta; - return $self; -} - -sub version_from { - require ExtUtils::MM_Unix; - my ( $self, $file ) = @_; - $self->version( ExtUtils::MM_Unix->parse_version($file) ); - - # for version integrity check - $self->makemaker_args( VERSION_FROM => $file ); -} - -sub abstract_from { - require ExtUtils::MM_Unix; - my ( $self, $file ) = @_; - $self->abstract( - bless( - { DISTNAME => $self->name }, - 'ExtUtils::MM_Unix' - )->parse_abstract($file) - ); -} - -# Add both distribution and module name -sub name_from { - my ($self, $file) = @_; - if ( - Module::Install::_read($file) =~ m/ - ^ \s* - package \s* - ([\w:]+) - \s* ; - /ixms - ) { - my ($name, $module_name) = ($1, $1); - $name =~ s{::}{-}g; - $self->name($name); - unless ( $self->module_name ) { - $self->module_name($module_name); - } - } else { - die("Cannot determine name from $file\n"); - } -} - -sub _extract_perl_version { - if ( - $_[0] =~ m/ - ^\s* - (?:use|require) \s* - v? - ([\d_\.]+) - \s* ; - /ixms - ) { - my $perl_version = $1; - $perl_version =~ s{_}{}g; - return $perl_version; - } else { - return; - } -} - -sub perl_version_from { - my $self = shift; - my $perl_version=_extract_perl_version(Module::Install::_read($_[0])); - if ($perl_version) { - $self->perl_version($perl_version); - } else { - warn "Cannot determine perl version info from $_[0]\n"; - return; - } -} - -sub author_from { - my $self = shift; - my $content = Module::Install::_read($_[0]); - if ($content =~ m/ - =head \d \s+ (?:authors?)\b \s* - ([^\n]*) - | - =head \d \s+ (?:licen[cs]e|licensing|copyright|legal)\b \s* - .*? copyright .*? \d\d\d[\d.]+ \s* (?:\bby\b)? \s* - ([^\n]*) - /ixms) { - my $author = $1 || $2; - - # XXX: ugly but should work anyway... - if (eval "require Pod::Escapes; 1") { - # Pod::Escapes has a mapping table. - # It's in core of perl >= 5.9.3, and should be installed - # as one of the Pod::Simple's prereqs, which is a prereq - # of Pod::Text 3.x (see also below). - $author =~ s{ E<( (\d+) | ([A-Za-z]+) )> } - { - defined $2 - ? chr($2) - : defined $Pod::Escapes::Name2character_number{$1} - ? chr($Pod::Escapes::Name2character_number{$1}) - : do { - warn "Unknown escape: E<$1>"; - "E<$1>"; - }; - }gex; - } - elsif (eval "require Pod::Text; 1" && $Pod::Text::VERSION < 3) { - # Pod::Text < 3.0 has yet another mapping table, - # though the table name of 2.x and 1.x are different. - # (1.x is in core of Perl < 5.6, 2.x is in core of - # Perl < 5.9.3) - my $mapping = ($Pod::Text::VERSION < 2) - ? \%Pod::Text::HTML_Escapes - : \%Pod::Text::ESCAPES; - $author =~ s{ E<( (\d+) | ([A-Za-z]+) )> } - { - defined $2 - ? chr($2) - : defined $mapping->{$1} - ? $mapping->{$1} - : do { - warn "Unknown escape: E<$1>"; - "E<$1>"; - }; - }gex; - } - else { - $author =~ s{E}{<}g; - $author =~ s{E}{>}g; - } - $self->author($author); - } else { - warn "Cannot determine author info from $_[0]\n"; - } -} - -#Stolen from M::B -my %license_urls = ( - perl => 'http://dev.perl.org/licenses/', - apache => 'http://apache.org/licenses/LICENSE-2.0', - apache_1_1 => 'http://apache.org/licenses/LICENSE-1.1', - artistic => 'http://opensource.org/licenses/artistic-license.php', - artistic_2 => 'http://opensource.org/licenses/artistic-license-2.0.php', - lgpl => 'http://opensource.org/licenses/lgpl-license.php', - lgpl2 => 'http://opensource.org/licenses/lgpl-2.1.php', - lgpl3 => 'http://opensource.org/licenses/lgpl-3.0.html', - bsd => 'http://opensource.org/licenses/bsd-license.php', - gpl => 'http://opensource.org/licenses/gpl-license.php', - gpl2 => 'http://opensource.org/licenses/gpl-2.0.php', - gpl3 => 'http://opensource.org/licenses/gpl-3.0.html', - mit => 'http://opensource.org/licenses/mit-license.php', - mozilla => 'http://opensource.org/licenses/mozilla1.1.php', - open_source => undef, - unrestricted => undef, - restrictive => undef, - unknown => undef, -); - -sub license { - my $self = shift; - return $self->{values}->{license} unless @_; - my $license = shift or die( - 'Did not provide a value to license()' - ); - $license = __extract_license($license) || lc $license; - $self->{values}->{license} = $license; - - # Automatically fill in license URLs - if ( $license_urls{$license} ) { - $self->resources( license => $license_urls{$license} ); - } - - return 1; -} - -sub _extract_license { - my $pod = shift; - my $matched; - return __extract_license( - ($matched) = $pod =~ m/ - (=head \d \s+ L(?i:ICEN[CS]E|ICENSING)\b.*?) - (=head \d.*|=cut.*|)\z - /xms - ) || __extract_license( - ($matched) = $pod =~ m/ - (=head \d \s+ (?:C(?i:OPYRIGHTS?)|L(?i:EGAL))\b.*?) - (=head \d.*|=cut.*|)\z - /xms - ); -} - -sub __extract_license { - my $license_text = shift or return; - my @phrases = ( - '(?:under )?the same (?:terms|license) as (?:perl|the perl (?:\d )?programming language)' => 'perl', 1, - '(?:under )?the terms of (?:perl|the perl programming language) itself' => 'perl', 1, - 'Artistic and GPL' => 'perl', 1, - 'GNU general public license' => 'gpl', 1, - 'GNU public license' => 'gpl', 1, - 'GNU lesser general public license' => 'lgpl', 1, - 'GNU lesser public license' => 'lgpl', 1, - 'GNU library general public license' => 'lgpl', 1, - 'GNU library public license' => 'lgpl', 1, - 'GNU Free Documentation license' => 'unrestricted', 1, - 'GNU Affero General Public License' => 'open_source', 1, - '(?:Free)?BSD license' => 'bsd', 1, - 'Artistic license 2\.0' => 'artistic_2', 1, - 'Artistic license' => 'artistic', 1, - 'Apache (?:Software )?license' => 'apache', 1, - 'GPL' => 'gpl', 1, - 'LGPL' => 'lgpl', 1, - 'BSD' => 'bsd', 1, - 'Artistic' => 'artistic', 1, - 'MIT' => 'mit', 1, - 'Mozilla Public License' => 'mozilla', 1, - 'Q Public License' => 'open_source', 1, - 'OpenSSL License' => 'unrestricted', 1, - 'SSLeay License' => 'unrestricted', 1, - 'zlib License' => 'open_source', 1, - 'proprietary' => 'proprietary', 0, - ); - while ( my ($pattern, $license, $osi) = splice(@phrases, 0, 3) ) { - $pattern =~ s#\s+#\\s+#gs; - if ( $license_text =~ /\b$pattern\b/i ) { - return $license; - } - } - return ''; -} - -sub license_from { - my $self = shift; - if (my $license=_extract_license(Module::Install::_read($_[0]))) { - $self->license($license); - } else { - warn "Cannot determine license info from $_[0]\n"; - return 'unknown'; - } -} - -sub _extract_bugtracker { - my @links = $_[0] =~ m#L<( - https?\Q://rt.cpan.org/\E[^>]+| - https?\Q://github.com/\E[\w_]+/[\w_]+/issues| - https?\Q://code.google.com/p/\E[\w_\-]+/issues/list - )>#gx; - my %links; - @links{@links}=(); - @links=keys %links; - return @links; -} - -sub bugtracker_from { - my $self = shift; - my $content = Module::Install::_read($_[0]); - my @links = _extract_bugtracker($content); - unless ( @links ) { - warn "Cannot determine bugtracker info from $_[0]\n"; - return 0; - } - if ( @links > 1 ) { - warn "Found more than one bugtracker link in $_[0]\n"; - return 0; - } - - # Set the bugtracker - bugtracker( $links[0] ); - return 1; -} - -sub requires_from { - my $self = shift; - my $content = Module::Install::_readperl($_[0]); - my @requires = $content =~ m/^use\s+([^\W\d]\w*(?:::\w+)*)\s+([\d\.]+)/mg; - while ( @requires ) { - my $module = shift @requires; - my $version = shift @requires; - $self->requires( $module => $version ); - } -} - -sub test_requires_from { - my $self = shift; - my $content = Module::Install::_readperl($_[0]); - my @requires = $content =~ m/^use\s+([^\W\d]\w*(?:::\w+)*)\s+([\d\.]+)/mg; - while ( @requires ) { - my $module = shift @requires; - my $version = shift @requires; - $self->test_requires( $module => $version ); - } -} - -# Convert triple-part versions (eg, 5.6.1 or 5.8.9) to -# numbers (eg, 5.006001 or 5.008009). -# Also, convert double-part versions (eg, 5.8) -sub _perl_version { - my $v = $_[-1]; - $v =~ s/^([1-9])\.([1-9]\d?\d?)$/sprintf("%d.%03d",$1,$2)/e; - $v =~ s/^([1-9])\.([1-9]\d?\d?)\.(0|[1-9]\d?\d?)$/sprintf("%d.%03d%03d",$1,$2,$3 || 0)/e; - $v =~ s/(\.\d\d\d)000$/$1/; - $v =~ s/_.+$//; - if ( ref($v) ) { - # Numify - $v = $v + 0; - } - return $v; -} - -sub add_metadata { - my $self = shift; - my %hash = @_; - for my $key (keys %hash) { - warn "add_metadata: $key is not prefixed with 'x_'.\n" . - "Use appopriate function to add non-private metadata.\n" unless $key =~ /^x_/; - $self->{values}->{$key} = $hash{$key}; - } -} - - -###################################################################### -# MYMETA Support - -sub WriteMyMeta { - die "WriteMyMeta has been deprecated"; -} - -sub write_mymeta_yaml { - my $self = shift; - - # We need YAML::Tiny to write the MYMETA.yml file - unless ( eval { require YAML::Tiny; 1; } ) { - return 1; - } - - # Generate the data - my $meta = $self->_write_mymeta_data or return 1; - - # Save as the MYMETA.yml file - print "Writing MYMETA.yml\n"; - YAML::Tiny::DumpFile('MYMETA.yml', $meta); -} - -sub write_mymeta_json { - my $self = shift; - - # We need JSON to write the MYMETA.json file - unless ( eval { require JSON; 1; } ) { - return 1; - } - - # Generate the data - my $meta = $self->_write_mymeta_data or return 1; - - # Save as the MYMETA.yml file - print "Writing MYMETA.json\n"; - Module::Install::_write( - 'MYMETA.json', - JSON->new->pretty(1)->canonical->encode($meta), - ); -} - -sub _write_mymeta_data { - my $self = shift; - - # If there's no existing META.yml there is nothing we can do - return undef unless -f 'META.yml'; - - # We need Parse::CPAN::Meta to load the file - unless ( eval { require Parse::CPAN::Meta; 1; } ) { - return undef; - } - - # Merge the perl version into the dependencies - my $val = $self->Meta->{values}; - my $perl = delete $val->{perl_version}; - if ( $perl ) { - $val->{requires} ||= []; - my $requires = $val->{requires}; - - # Canonize to three-dot version after Perl 5.6 - if ( $perl >= 5.006 ) { - $perl =~ s{^(\d+)\.(\d\d\d)(\d*)}{join('.', $1, int($2||0), int($3||0))}e - } - unshift @$requires, [ perl => $perl ]; - } - - # Load the advisory META.yml file - my @yaml = Parse::CPAN::Meta::LoadFile('META.yml'); - my $meta = $yaml[0]; - - # Overwrite the non-configure dependency hashs - delete $meta->{requires}; - delete $meta->{build_requires}; - delete $meta->{recommends}; - if ( exists $val->{requires} ) { - $meta->{requires} = { map { @$_ } @{ $val->{requires} } }; - } - if ( exists $val->{build_requires} ) { - $meta->{build_requires} = { map { @$_ } @{ $val->{build_requires} } }; - } - - return $meta; -} - -1; diff --git a/debian/modules/http-subs-filter/test/inc/Module/Install/TestBase.pm b/debian/modules/http-subs-filter/test/inc/Module/Install/TestBase.pm deleted file mode 100644 index e222ac1..0000000 --- a/debian/modules/http-subs-filter/test/inc/Module/Install/TestBase.pm +++ /dev/null @@ -1,29 +0,0 @@ -#line 1 -package Module::Install::TestBase; -use strict; -use warnings; - -use Module::Install::Base; - -use vars qw($VERSION @ISA); -BEGIN { - $VERSION = '0.60'; - @ISA = 'Module::Install::Base'; -} - -sub use_test_base { - my $self = shift; - $self->include('Test::Base'); - $self->include('Test::Base::Filter'); - $self->include('Spiffy'); - $self->include('Test::More'); - $self->include('Test::Builder'); - $self->include('Test::Builder::Module'); - $self->requires('Filter::Util::Call'); -} - -1; - -=encoding utf8 - -#line 70 diff --git a/debian/modules/http-subs-filter/test/inc/Module/Install/Win32.pm b/debian/modules/http-subs-filter/test/inc/Module/Install/Win32.pm deleted file mode 100644 index 3139a63..0000000 --- a/debian/modules/http-subs-filter/test/inc/Module/Install/Win32.pm +++ /dev/null @@ -1,64 +0,0 @@ -#line 1 -package Module::Install::Win32; - -use strict; -use Module::Install::Base (); - -use vars qw{$VERSION @ISA $ISCORE}; -BEGIN { - $VERSION = '1.01'; - @ISA = 'Module::Install::Base'; - $ISCORE = 1; -} - -# determine if the user needs nmake, and download it if needed -sub check_nmake { - my $self = shift; - $self->load('can_run'); - $self->load('get_file'); - - require Config; - return unless ( - $^O eq 'MSWin32' and - $Config::Config{make} and - $Config::Config{make} =~ /^nmake\b/i and - ! $self->can_run('nmake') - ); - - print "The required 'nmake' executable not found, fetching it...\n"; - - require File::Basename; - my $rv = $self->get_file( - url => 'http://download.microsoft.com/download/vc15/Patch/1.52/W95/EN-US/Nmake15.exe', - ftp_url => 'ftp://ftp.microsoft.com/Softlib/MSLFILES/Nmake15.exe', - local_dir => File::Basename::dirname($^X), - size => 51928, - run => 'Nmake15.exe /o > nul', - check_for => 'Nmake.exe', - remove => 1, - ); - - die <<'END_MESSAGE' unless $rv; - -------------------------------------------------------------------------------- - -Since you are using Microsoft Windows, you will need the 'nmake' utility -before installation. It's available at: - - http://download.microsoft.com/download/vc15/Patch/1.52/W95/EN-US/Nmake15.exe - or - ftp://ftp.microsoft.com/Softlib/MSLFILES/Nmake15.exe - -Please download the file manually, save it to a directory in %PATH% (e.g. -C:\WINDOWS\COMMAND\), then launch the MS-DOS command line shell, "cd" to -that directory, and run "Nmake15.exe" from there; that will create the -'nmake.exe' file needed by this module. - -You may then resume the installation process described in README. - -------------------------------------------------------------------------------- -END_MESSAGE - -} - -1; diff --git a/debian/modules/http-subs-filter/test/inc/Module/Install/WriteAll.pm b/debian/modules/http-subs-filter/test/inc/Module/Install/WriteAll.pm deleted file mode 100644 index 1f724a7..0000000 --- a/debian/modules/http-subs-filter/test/inc/Module/Install/WriteAll.pm +++ /dev/null @@ -1,63 +0,0 @@ -#line 1 -package Module::Install::WriteAll; - -use strict; -use Module::Install::Base (); - -use vars qw{$VERSION @ISA $ISCORE}; -BEGIN { - $VERSION = '1.01'; - @ISA = qw{Module::Install::Base}; - $ISCORE = 1; -} - -sub WriteAll { - my $self = shift; - my %args = ( - meta => 1, - sign => 0, - inline => 0, - check_nmake => 1, - @_, - ); - - $self->sign(1) if $args{sign}; - $self->admin->WriteAll(%args) if $self->is_admin; - - $self->check_nmake if $args{check_nmake}; - unless ( $self->makemaker_args->{PL_FILES} ) { - # XXX: This still may be a bit over-defensive... - unless ($self->makemaker(6.25)) { - $self->makemaker_args( PL_FILES => {} ) if -f 'Build.PL'; - } - } - - # Until ExtUtils::MakeMaker support MYMETA.yml, make sure - # we clean it up properly ourself. - $self->realclean_files('MYMETA.yml'); - - if ( $args{inline} ) { - $self->Inline->write; - } else { - $self->Makefile->write; - } - - # The Makefile write process adds a couple of dependencies, - # so write the META.yml files after the Makefile. - if ( $args{meta} ) { - $self->Meta->write; - } - - # Experimental support for MYMETA - if ( $ENV{X_MYMETA} ) { - if ( $ENV{X_MYMETA} eq 'JSON' ) { - $self->Meta->write_mymeta_json; - } else { - $self->Meta->write_mymeta_yaml; - } - } - - return 1; -} - -1; diff --git a/debian/modules/http-subs-filter/test/inc/Spiffy.pm b/debian/modules/http-subs-filter/test/inc/Spiffy.pm deleted file mode 100644 index 7b10f7a..0000000 --- a/debian/modules/http-subs-filter/test/inc/Spiffy.pm +++ /dev/null @@ -1,539 +0,0 @@ -#line 1 -package Spiffy; -use strict; -use 5.006001; -use warnings; -use Carp; -require Exporter; -our $VERSION = '0.30'; -our @EXPORT = (); -our @EXPORT_BASE = qw(field const stub super); -our @EXPORT_OK = (@EXPORT_BASE, qw(id WWW XXX YYY ZZZ)); -our %EXPORT_TAGS = (XXX => [qw(WWW XXX YYY ZZZ)]); - -my $stack_frame = 0; -my $dump = 'yaml'; -my $bases_map = {}; - -sub WWW; sub XXX; sub YYY; sub ZZZ; - -# This line is here to convince "autouse" into believing we are autousable. -sub can { - ($_[1] eq 'import' and caller()->isa('autouse')) - ? \&Exporter::import # pacify autouse's equality test - : $_[0]->SUPER::can($_[1]) # normal case -} - -# TODO -# -# Exported functions like field and super should be hidden so as not to -# be confused with methods that can be inherited. -# - -sub new { - my $class = shift; - $class = ref($class) || $class; - my $self = bless {}, $class; - while (@_) { - my $method = shift; - $self->$method(shift); - } - return $self; -} - -my $filtered_files = {}; -my $filter_dump = 0; -my $filter_save = 0; -our $filter_result = ''; -sub import { - no strict 'refs'; - no warnings; - my $self_package = shift; - - # XXX Using parse_arguments here might cause confusion, because the - # subclass's boolean_arguments and paired_arguments can conflict, causing - # difficult debugging. Consider using something truly local. - my ($args, @export_list) = do { - local *boolean_arguments = sub { - qw( - -base -Base -mixin -selfless - -XXX -dumper -yaml - -filter_dump -filter_save - ) - }; - local *paired_arguments = sub { qw(-package) }; - $self_package->parse_arguments(@_); - }; - return spiffy_mixin_import(scalar(caller(0)), $self_package, @export_list) - if $args->{-mixin}; - - $filter_dump = 1 if $args->{-filter_dump}; - $filter_save = 1 if $args->{-filter_save}; - $dump = 'yaml' if $args->{-yaml}; - $dump = 'dumper' if $args->{-dumper}; - - local @EXPORT_BASE = @EXPORT_BASE; - - if ($args->{-XXX}) { - push @EXPORT_BASE, @{$EXPORT_TAGS{XXX}} - unless grep /^XXX$/, @EXPORT_BASE; - } - - spiffy_filter() - if ($args->{-selfless} or $args->{-Base}) and - not $filtered_files->{(caller($stack_frame))[1]}++; - - my $caller_package = $args->{-package} || caller($stack_frame); - push @{"$caller_package\::ISA"}, $self_package - if $args->{-Base} or $args->{-base}; - - for my $class (@{all_my_bases($self_package)}) { - next unless $class->isa('Spiffy'); - my @export = grep { - not defined &{"$caller_package\::$_"}; - } ( @{"$class\::EXPORT"}, - ($args->{-Base} or $args->{-base}) - ? @{"$class\::EXPORT_BASE"} : (), - ); - my @export_ok = grep { - not defined &{"$caller_package\::$_"}; - } @{"$class\::EXPORT_OK"}; - - # Avoid calling the expensive Exporter::export - # if there is nothing to do (optimization) - my %exportable = map { ($_, 1) } @export, @export_ok; - next unless keys %exportable; - - my @export_save = @{"$class\::EXPORT"}; - my @export_ok_save = @{"$class\::EXPORT_OK"}; - @{"$class\::EXPORT"} = @export; - @{"$class\::EXPORT_OK"} = @export_ok; - my @list = grep { - (my $v = $_) =~ s/^[\!\:]//; - $exportable{$v} or ${"$class\::EXPORT_TAGS"}{$v}; - } @export_list; - Exporter::export($class, $caller_package, @list); - @{"$class\::EXPORT"} = @export_save; - @{"$class\::EXPORT_OK"} = @export_ok_save; - } -} - -sub spiffy_filter { - require Filter::Util::Call; - my $done = 0; - Filter::Util::Call::filter_add( - sub { - return 0 if $done; - my ($data, $end) = ('', ''); - while (my $status = Filter::Util::Call::filter_read()) { - return $status if $status < 0; - if (/^__(?:END|DATA)__\r?$/) { - $end = $_; - last; - } - $data .= $_; - $_ = ''; - } - $_ = $data; - my @my_subs; - s[^(sub\s+\w+\s+\{)(.*\n)] - [${1}my \$self = shift;$2]gm; - s[^(sub\s+\w+)\s*\(\s*\)(\s+\{.*\n)] - [${1}${2}]gm; - s[^my\s+sub\s+(\w+)(\s+\{)(.*)((?s:.*?\n))\}\n] - [push @my_subs, $1; "\$$1 = sub$2my \$self = shift;$3$4\};\n"]gem; - my $preclare = ''; - if (@my_subs) { - $preclare = join ',', map "\$$_", @my_subs; - $preclare = "my($preclare);"; - } - $_ = "use strict;use warnings;$preclare${_};1;\n$end"; - if ($filter_dump) { print; exit } - if ($filter_save) { $filter_result = $_; $_ = $filter_result; } - $done = 1; - } - ); -} - -sub base { - push @_, -base; - goto &import; -} - -sub all_my_bases { - my $class = shift; - - return $bases_map->{$class} - if defined $bases_map->{$class}; - - my @bases = ($class); - no strict 'refs'; - for my $base_class (@{"${class}::ISA"}) { - push @bases, @{all_my_bases($base_class)}; - } - my $used = {}; - $bases_map->{$class} = [grep {not $used->{$_}++} @bases]; -} - -my %code = ( - sub_start => - "sub {\n", - set_default => - " \$_[0]->{%s} = %s\n unless exists \$_[0]->{%s};\n", - init => - " return \$_[0]->{%s} = do { my \$self = \$_[0]; %s }\n" . - " unless \$#_ > 0 or defined \$_[0]->{%s};\n", - weak_init => - " return do {\n" . - " \$_[0]->{%s} = do { my \$self = \$_[0]; %s };\n" . - " Scalar::Util::weaken(\$_[0]->{%s}) if ref \$_[0]->{%s};\n" . - " \$_[0]->{%s};\n" . - " } unless \$#_ > 0 or defined \$_[0]->{%s};\n", - return_if_get => - " return \$_[0]->{%s} unless \$#_ > 0;\n", - set => - " \$_[0]->{%s} = \$_[1];\n", - weaken => - " Scalar::Util::weaken(\$_[0]->{%s}) if ref \$_[0]->{%s};\n", - sub_end => - " return \$_[0]->{%s};\n}\n", -); - -sub field { - my $package = caller; - my ($args, @values) = do { - no warnings; - local *boolean_arguments = sub { (qw(-weak)) }; - local *paired_arguments = sub { (qw(-package -init)) }; - Spiffy->parse_arguments(@_); - }; - my ($field, $default) = @values; - $package = $args->{-package} if defined $args->{-package}; - die "Cannot have a default for a weakened field ($field)" - if defined $default && $args->{-weak}; - return if defined &{"${package}::$field"}; - require Scalar::Util if $args->{-weak}; - my $default_string = - ( ref($default) eq 'ARRAY' and not @$default ) - ? '[]' - : (ref($default) eq 'HASH' and not keys %$default ) - ? '{}' - : default_as_code($default); - - my $code = $code{sub_start}; - if ($args->{-init}) { - my $fragment = $args->{-weak} ? $code{weak_init} : $code{init}; - $code .= sprintf $fragment, $field, $args->{-init}, ($field) x 4; - } - $code .= sprintf $code{set_default}, $field, $default_string, $field - if defined $default; - $code .= sprintf $code{return_if_get}, $field; - $code .= sprintf $code{set}, $field; - $code .= sprintf $code{weaken}, $field, $field - if $args->{-weak}; - $code .= sprintf $code{sub_end}, $field; - - my $sub = eval $code; - die $@ if $@; - no strict 'refs'; - *{"${package}::$field"} = $sub; - return $code if defined wantarray; -} - -sub default_as_code { - require Data::Dumper; - local $Data::Dumper::Sortkeys = 1; - my $code = Data::Dumper::Dumper(shift); - $code =~ s/^\$VAR1 = //; - $code =~ s/;$//; - return $code; -} - -sub const { - my $package = caller; - my ($args, @values) = do { - no warnings; - local *paired_arguments = sub { (qw(-package)) }; - Spiffy->parse_arguments(@_); - }; - my ($field, $default) = @values; - $package = $args->{-package} if defined $args->{-package}; - no strict 'refs'; - return if defined &{"${package}::$field"}; - *{"${package}::$field"} = sub { $default } -} - -sub stub { - my $package = caller; - my ($args, @values) = do { - no warnings; - local *paired_arguments = sub { (qw(-package)) }; - Spiffy->parse_arguments(@_); - }; - my ($field, $default) = @values; - $package = $args->{-package} if defined $args->{-package}; - no strict 'refs'; - return if defined &{"${package}::$field"}; - *{"${package}::$field"} = - sub { - require Carp; - Carp::confess - "Method $field in package $package must be subclassed"; - } -} - -sub parse_arguments { - my $class = shift; - my ($args, @values) = ({}, ()); - my %booleans = map { ($_, 1) } $class->boolean_arguments; - my %pairs = map { ($_, 1) } $class->paired_arguments; - while (@_) { - my $elem = shift; - if (defined $elem and defined $booleans{$elem}) { - $args->{$elem} = (@_ and $_[0] =~ /^[01]$/) - ? shift - : 1; - } - elsif (defined $elem and defined $pairs{$elem} and @_) { - $args->{$elem} = shift; - } - else { - push @values, $elem; - } - } - return wantarray ? ($args, @values) : $args; -} - -sub boolean_arguments { () } -sub paired_arguments { () } - -# get a unique id for any node -sub id { - if (not ref $_[0]) { - return 'undef' if not defined $_[0]; - \$_[0] =~ /\((\w+)\)$/o or die; - return "$1-S"; - } - require overload; - overload::StrVal($_[0]) =~ /\((\w+)\)$/o or die; - return $1; -} - -#=============================================================================== -# It's super, man. -#=============================================================================== -package DB; -{ - no warnings 'redefine'; - sub super_args { - my @dummy = caller(@_ ? $_[0] : 2); - return @DB::args; - } -} - -package Spiffy; -sub super { - my $method; - my $frame = 1; - while ($method = (caller($frame++))[3]) { - $method =~ s/.*::// and last; - } - my @args = DB::super_args($frame); - @_ = @_ ? ($args[0], @_) : @args; - my $class = ref $_[0] ? ref $_[0] : $_[0]; - my $caller_class = caller; - my $seen = 0; - my @super_classes = reverse grep { - ($seen or $seen = ($_ eq $caller_class)) ? 0 : 1; - } reverse @{all_my_bases($class)}; - for my $super_class (@super_classes) { - no strict 'refs'; - next if $super_class eq $class; - if (defined &{"${super_class}::$method"}) { - ${"$super_class\::AUTOLOAD"} = ${"$class\::AUTOLOAD"} - if $method eq 'AUTOLOAD'; - return &{"${super_class}::$method"}; - } - } - return; -} - -#=============================================================================== -# This code deserves a spanking, because it is being very naughty. -# It is exchanging base.pm's import() for its own, so that people -# can use base.pm with Spiffy modules, without being the wiser. -#=============================================================================== -my $real_base_import; -my $real_mixin_import; - -BEGIN { - require base unless defined $INC{'base.pm'}; - $INC{'mixin.pm'} ||= 'Spiffy/mixin.pm'; - $real_base_import = \&base::import; - $real_mixin_import = \&mixin::import; - no warnings; - *base::import = \&spiffy_base_import; - *mixin::import = \&spiffy_mixin_import; -} - -# my $i = 0; -# while (my $caller = caller($i++)) { -# next unless $caller eq 'base' or $caller eq 'mixin'; -# croak <isa('Spiffy'); - } @base_classes; - my $inheritor = caller(0); - for my $base_class (@base_classes) { - next if $inheritor->isa($base_class); - croak "Can't mix Spiffy and non-Spiffy classes in 'use base'.\n", - "See the documentation of Spiffy.pm for details\n " - unless $base_class->isa('Spiffy'); - $stack_frame = 1; # tell import to use different caller - import($base_class, '-base'); - $stack_frame = 0; - } -} - -sub mixin { - my $self = shift; - my $target_class = ref($self); - spiffy_mixin_import($target_class, @_) -} - -sub spiffy_mixin_import { - my $target_class = shift; - $target_class = caller(0) - if $target_class eq 'mixin'; - my $mixin_class = shift - or die "Nothing to mixin"; - eval "require $mixin_class"; - my @roles = @_; - my $pseudo_class = join '-', $target_class, $mixin_class, @roles; - my %methods = spiffy_mixin_methods($mixin_class, @roles); - no strict 'refs'; - no warnings; - @{"$pseudo_class\::ISA"} = @{"$target_class\::ISA"}; - @{"$target_class\::ISA"} = ($pseudo_class); - for (keys %methods) { - *{"$pseudo_class\::$_"} = $methods{$_}; - } -} - -sub spiffy_mixin_methods { - my $mixin_class = shift; - no strict 'refs'; - my %methods = spiffy_all_methods($mixin_class); - map { - $methods{$_} - ? ($_, \ &{"$methods{$_}\::$_"}) - : ($_, \ &{"$mixin_class\::$_"}) - } @_ - ? (get_roles($mixin_class, @_)) - : (keys %methods); -} - -sub get_roles { - my $mixin_class = shift; - my @roles = @_; - while (grep /^!*:/, @roles) { - @roles = map { - s/!!//g; - /^!:(.*)/ ? do { - my $m = "_role_$1"; - map("!$_", $mixin_class->$m); - } : - /^:(.*)/ ? do { - my $m = "_role_$1"; - ($mixin_class->$m); - } : - ($_) - } @roles; - } - if (@roles and $roles[0] =~ /^!/) { - my %methods = spiffy_all_methods($mixin_class); - unshift @roles, keys(%methods); - } - my %roles; - for (@roles) { - s/!!//g; - delete $roles{$1}, next - if /^!(.*)/; - $roles{$_} = 1; - } - keys %roles; -} - -sub spiffy_all_methods { - no strict 'refs'; - my $class = shift; - return if $class eq 'Spiffy'; - my %methods = map { - ($_, $class) - } grep { - defined &{"$class\::$_"} and not /^_/ - } keys %{"$class\::"}; - my %super_methods; - %super_methods = spiffy_all_methods(${"$class\::ISA"}[0]) - if @{"$class\::ISA"}; - %{{%super_methods, %methods}}; -} - - -# END of naughty code. -#=============================================================================== -# Debugging support -#=============================================================================== -sub spiffy_dump { - no warnings; - if ($dump eq 'dumper') { - require Data::Dumper; - $Data::Dumper::Sortkeys = 1; - $Data::Dumper::Indent = 1; - return Data::Dumper::Dumper(@_); - } - require YAML; - $YAML::UseVersion = 0; - return YAML::Dump(@_) . "...\n"; -} - -sub at_line_number { - my ($file_path, $line_number) = (caller(1))[1,2]; - " at $file_path line $line_number\n"; -} - -sub WWW { - warn spiffy_dump(@_) . at_line_number; - return wantarray ? @_ : $_[0]; -} - -sub XXX { - die spiffy_dump(@_) . at_line_number; -} - -sub YYY { - print spiffy_dump(@_) . at_line_number; - return wantarray ? @_ : $_[0]; -} - -sub ZZZ { - require Carp; - Carp::confess spiffy_dump(@_); -} - -1; - -__END__ - -#line 1066 diff --git a/debian/modules/http-subs-filter/test/inc/Test/Base.pm b/debian/modules/http-subs-filter/test/inc/Test/Base.pm deleted file mode 100644 index 8609584..0000000 --- a/debian/modules/http-subs-filter/test/inc/Test/Base.pm +++ /dev/null @@ -1,682 +0,0 @@ -#line 1 -package Test::Base; -use 5.006001; -use Spiffy 0.30 -Base; -use Spiffy ':XXX'; -our $VERSION = '0.60'; - -my @test_more_exports; -BEGIN { - @test_more_exports = qw( - ok isnt like unlike is_deeply cmp_ok - skip todo_skip pass fail - eq_array eq_hash eq_set - plan can_ok isa_ok diag - use_ok - $TODO - ); -} - -use Test::More import => \@test_more_exports; -use Carp; - -our @EXPORT = (@test_more_exports, qw( - is no_diff - - blocks next_block first_block - delimiters spec_file spec_string - filters filters_delay filter_arguments - run run_compare run_is run_is_deeply run_like run_unlike - skip_all_unless_require is_deep run_is_deep - WWW XXX YYY ZZZ - tie_output no_diag_on_only - - find_my_self default_object - - croak carp cluck confess -)); - -field '_spec_file'; -field '_spec_string'; -field _filters => [qw(norm trim)]; -field _filters_map => {}; -field spec => - -init => '$self->_spec_init'; -field block_list => - -init => '$self->_block_list_init'; -field _next_list => []; -field block_delim => - -init => '$self->block_delim_default'; -field data_delim => - -init => '$self->data_delim_default'; -field _filters_delay => 0; -field _no_diag_on_only => 0; - -field block_delim_default => '==='; -field data_delim_default => '---'; - -my $default_class; -my $default_object; -my $reserved_section_names = {}; - -sub default_object { - $default_object ||= $default_class->new; - return $default_object; -} - -my $import_called = 0; -sub import() { - $import_called = 1; - my $class = (grep /^-base$/i, @_) - ? scalar(caller) - : $_[0]; - if (not defined $default_class) { - $default_class = $class; - } -# else { -# croak "Can't use $class after using $default_class" -# unless $default_class->isa($class); -# } - - unless (grep /^-base$/i, @_) { - my @args; - for (my $ii = 1; $ii <= $#_; ++$ii) { - if ($_[$ii] eq '-package') { - ++$ii; - } else { - push @args, $_[$ii]; - } - } - Test::More->import(import => \@test_more_exports, @args) - if @args; - } - - _strict_warnings(); - goto &Spiffy::import; -} - -# Wrap Test::Builder::plan -my $plan_code = \&Test::Builder::plan; -my $Have_Plan = 0; -{ - no warnings 'redefine'; - *Test::Builder::plan = sub { - $Have_Plan = 1; - goto &$plan_code; - }; -} - -my $DIED = 0; -$SIG{__DIE__} = sub { $DIED = 1; die @_ }; - -sub block_class { $self->find_class('Block') } -sub filter_class { $self->find_class('Filter') } - -sub find_class { - my $suffix = shift; - my $class = ref($self) . "::$suffix"; - return $class if $class->can('new'); - $class = __PACKAGE__ . "::$suffix"; - return $class if $class->can('new'); - eval "require $class"; - return $class if $class->can('new'); - die "Can't find a class for $suffix"; -} - -sub check_late { - if ($self->{block_list}) { - my $caller = (caller(1))[3]; - $caller =~ s/.*:://; - croak "Too late to call $caller()" - } -} - -sub find_my_self() { - my $self = ref($_[0]) eq $default_class - ? splice(@_, 0, 1) - : default_object(); - return $self, @_; -} - -sub blocks() { - (my ($self), @_) = find_my_self(@_); - - croak "Invalid arguments passed to 'blocks'" - if @_ > 1; - croak sprintf("'%s' is invalid argument to blocks()", shift(@_)) - if @_ && $_[0] !~ /^[a-zA-Z]\w*$/; - - my $blocks = $self->block_list; - - my $section_name = shift || ''; - my @blocks = $section_name - ? (grep { exists $_->{$section_name} } @$blocks) - : (@$blocks); - - return scalar(@blocks) unless wantarray; - - return (@blocks) if $self->_filters_delay; - - for my $block (@blocks) { - $block->run_filters - unless $block->is_filtered; - } - - return (@blocks); -} - -sub next_block() { - (my ($self), @_) = find_my_self(@_); - my $list = $self->_next_list; - if (@$list == 0) { - $list = [@{$self->block_list}, undef]; - $self->_next_list($list); - } - my $block = shift @$list; - if (defined $block and not $block->is_filtered) { - $block->run_filters; - } - return $block; -} - -sub first_block() { - (my ($self), @_) = find_my_self(@_); - $self->_next_list([]); - $self->next_block; -} - -sub filters_delay() { - (my ($self), @_) = find_my_self(@_); - $self->_filters_delay(defined $_[0] ? shift : 1); -} - -sub no_diag_on_only() { - (my ($self), @_) = find_my_self(@_); - $self->_no_diag_on_only(defined $_[0] ? shift : 1); -} - -sub delimiters() { - (my ($self), @_) = find_my_self(@_); - $self->check_late; - my ($block_delimiter, $data_delimiter) = @_; - $block_delimiter ||= $self->block_delim_default; - $data_delimiter ||= $self->data_delim_default; - $self->block_delim($block_delimiter); - $self->data_delim($data_delimiter); - return $self; -} - -sub spec_file() { - (my ($self), @_) = find_my_self(@_); - $self->check_late; - $self->_spec_file(shift); - return $self; -} - -sub spec_string() { - (my ($self), @_) = find_my_self(@_); - $self->check_late; - $self->_spec_string(shift); - return $self; -} - -sub filters() { - (my ($self), @_) = find_my_self(@_); - if (ref($_[0]) eq 'HASH') { - $self->_filters_map(shift); - } - else { - my $filters = $self->_filters; - push @$filters, @_; - } - return $self; -} - -sub filter_arguments() { - $Test::Base::Filter::arguments; -} - -sub have_text_diff { - eval { require Text::Diff; 1 } && - $Text::Diff::VERSION >= 0.35 && - $Algorithm::Diff::VERSION >= 1.15; -} - -sub is($$;$) { - (my ($self), @_) = find_my_self(@_); - my ($actual, $expected, $name) = @_; - local $Test::Builder::Level = $Test::Builder::Level + 1; - if ($ENV{TEST_SHOW_NO_DIFFS} or - not defined $actual or - not defined $expected or - $actual eq $expected or - not($self->have_text_diff) or - $expected !~ /\n./s - ) { - Test::More::is($actual, $expected, $name); - } - else { - $name = '' unless defined $name; - ok $actual eq $expected, - $name . "\n" . Text::Diff::diff(\$expected, \$actual); - } -} - -sub run(&;$) { - (my ($self), @_) = find_my_self(@_); - my $callback = shift; - for my $block (@{$self->block_list}) { - $block->run_filters unless $block->is_filtered; - &{$callback}($block); - } -} - -my $name_error = "Can't determine section names"; -sub _section_names { - return @_ if @_ == 2; - my $block = $self->first_block - or croak $name_error; - my @names = grep { - $_ !~ /^(ONLY|LAST|SKIP)$/; - } @{$block->{_section_order}[0] || []}; - croak "$name_error. Need two sections in first block" - unless @names == 2; - return @names; -} - -sub _assert_plan { - plan('no_plan') unless $Have_Plan; -} - -sub END { - run_compare() unless $Have_Plan or $DIED or not $import_called; -} - -sub run_compare() { - (my ($self), @_) = find_my_self(@_); - $self->_assert_plan; - my ($x, $y) = $self->_section_names(@_); - local $Test::Builder::Level = $Test::Builder::Level + 1; - for my $block (@{$self->block_list}) { - next unless exists($block->{$x}) and exists($block->{$y}); - $block->run_filters unless $block->is_filtered; - if (ref $block->$x) { - is_deeply($block->$x, $block->$y, - $block->name ? $block->name : ()); - } - elsif (ref $block->$y eq 'Regexp') { - my $regexp = ref $y ? $y : $block->$y; - like($block->$x, $regexp, $block->name ? $block->name : ()); - } - else { - is($block->$x, $block->$y, $block->name ? $block->name : ()); - } - } -} - -sub run_is() { - (my ($self), @_) = find_my_self(@_); - $self->_assert_plan; - my ($x, $y) = $self->_section_names(@_); - local $Test::Builder::Level = $Test::Builder::Level + 1; - for my $block (@{$self->block_list}) { - next unless exists($block->{$x}) and exists($block->{$y}); - $block->run_filters unless $block->is_filtered; - is($block->$x, $block->$y, - $block->name ? $block->name : () - ); - } -} - -sub run_is_deeply() { - (my ($self), @_) = find_my_self(@_); - $self->_assert_plan; - my ($x, $y) = $self->_section_names(@_); - for my $block (@{$self->block_list}) { - next unless exists($block->{$x}) and exists($block->{$y}); - $block->run_filters unless $block->is_filtered; - is_deeply($block->$x, $block->$y, - $block->name ? $block->name : () - ); - } -} - -sub run_like() { - (my ($self), @_) = find_my_self(@_); - $self->_assert_plan; - my ($x, $y) = $self->_section_names(@_); - for my $block (@{$self->block_list}) { - next unless exists($block->{$x}) and defined($y); - $block->run_filters unless $block->is_filtered; - my $regexp = ref $y ? $y : $block->$y; - like($block->$x, $regexp, - $block->name ? $block->name : () - ); - } -} - -sub run_unlike() { - (my ($self), @_) = find_my_self(@_); - $self->_assert_plan; - my ($x, $y) = $self->_section_names(@_); - for my $block (@{$self->block_list}) { - next unless exists($block->{$x}) and defined($y); - $block->run_filters unless $block->is_filtered; - my $regexp = ref $y ? $y : $block->$y; - unlike($block->$x, $regexp, - $block->name ? $block->name : () - ); - } -} - -sub skip_all_unless_require() { - (my ($self), @_) = find_my_self(@_); - my $module = shift; - eval "require $module; 1" - or Test::More::plan( - skip_all => "$module failed to load" - ); -} - -sub is_deep() { - (my ($self), @_) = find_my_self(@_); - require Test::Deep; - Test::Deep::cmp_deeply(@_); -} - -sub run_is_deep() { - (my ($self), @_) = find_my_self(@_); - $self->_assert_plan; - my ($x, $y) = $self->_section_names(@_); - for my $block (@{$self->block_list}) { - next unless exists($block->{$x}) and exists($block->{$y}); - $block->run_filters unless $block->is_filtered; - is_deep($block->$x, $block->$y, - $block->name ? $block->name : () - ); - } -} - -sub _pre_eval { - my $spec = shift; - return $spec unless $spec =~ - s/\A\s*<<<(.*?)>>>\s*$//sm; - my $eval_code = $1; - eval "package main; $eval_code"; - croak $@ if $@; - return $spec; -} - -sub _block_list_init { - my $spec = $self->spec; - $spec = $self->_pre_eval($spec); - my $cd = $self->block_delim; - my @hunks = ($spec =~ /^(\Q${cd}\E.*?(?=^\Q${cd}\E|\z))/msg); - my $blocks = $self->_choose_blocks(@hunks); - $self->block_list($blocks); # Need to set early for possible filter use - my $seq = 1; - for my $block (@$blocks) { - $block->blocks_object($self); - $block->seq_num($seq++); - } - return $blocks; -} - -sub _choose_blocks { - my $blocks = []; - for my $hunk (@_) { - my $block = $self->_make_block($hunk); - if (exists $block->{ONLY}) { - diag "I found ONLY: maybe you're debugging?" - unless $self->_no_diag_on_only; - return [$block]; - } - next if exists $block->{SKIP}; - push @$blocks, $block; - if (exists $block->{LAST}) { - return $blocks; - } - } - return $blocks; -} - -sub _check_reserved { - my $id = shift; - croak "'$id' is a reserved name. Use something else.\n" - if $reserved_section_names->{$id} or - $id =~ /^_/; -} - -sub _make_block { - my $hunk = shift; - my $cd = $self->block_delim; - my $dd = $self->data_delim; - my $block = $self->block_class->new; - $hunk =~ s/\A\Q${cd}\E[ \t]*(.*)\s+// or die; - my $name = $1; - my @parts = split /^\Q${dd}\E +\(?(\w+)\)? *(.*)?\n/m, $hunk; - my $description = shift @parts; - $description ||= ''; - unless ($description =~ /\S/) { - $description = $name; - } - $description =~ s/\s*\z//; - $block->set_value(description => $description); - - my $section_map = {}; - my $section_order = []; - while (@parts) { - my ($type, $filters, $value) = splice(@parts, 0, 3); - $self->_check_reserved($type); - $value = '' unless defined $value; - $filters = '' unless defined $filters; - if ($filters =~ /:(\s|\z)/) { - croak "Extra lines not allowed in '$type' section" - if $value =~ /\S/; - ($filters, $value) = split /\s*:(?:\s+|\z)/, $filters, 2; - $value = '' unless defined $value; - $value =~ s/^\s*(.*?)\s*$/$1/; - } - $section_map->{$type} = { - filters => $filters, - }; - push @$section_order, $type; - $block->set_value($type, $value); - } - $block->set_value(name => $name); - $block->set_value(_section_map => $section_map); - $block->set_value(_section_order => $section_order); - return $block; -} - -sub _spec_init { - return $self->_spec_string - if $self->_spec_string; - local $/; - my $spec; - if (my $spec_file = $self->_spec_file) { - open FILE, $spec_file or die $!; - $spec = ; - close FILE; - } - else { - $spec = do { - package main; - no warnings 'once'; - ; - }; - } - return $spec; -} - -sub _strict_warnings() { - require Filter::Util::Call; - my $done = 0; - Filter::Util::Call::filter_add( - sub { - return 0 if $done; - my ($data, $end) = ('', ''); - while (my $status = Filter::Util::Call::filter_read()) { - return $status if $status < 0; - if (/^__(?:END|DATA)__\r?$/) { - $end = $_; - last; - } - $data .= $_; - $_ = ''; - } - $_ = "use strict;use warnings;$data$end"; - $done = 1; - } - ); -} - -sub tie_output() { - my $handle = shift; - die "No buffer to tie" unless @_; - tie *$handle, 'Test::Base::Handle', $_[0]; -} - -sub no_diff { - $ENV{TEST_SHOW_NO_DIFFS} = 1; -} - -package Test::Base::Handle; - -sub TIEHANDLE() { - my $class = shift; - bless \ $_[0], $class; -} - -sub PRINT { - $$self .= $_ for @_; -} - -#=============================================================================== -# Test::Base::Block -# -# This is the default class for accessing a Test::Base block object. -#=============================================================================== -package Test::Base::Block; -our @ISA = qw(Spiffy); - -our @EXPORT = qw(block_accessor); - -sub AUTOLOAD { - return; -} - -sub block_accessor() { - my $accessor = shift; - no strict 'refs'; - return if defined &$accessor; - *$accessor = sub { - my $self = shift; - if (@_) { - Carp::croak "Not allowed to set values for '$accessor'"; - } - my @list = @{$self->{$accessor} || []}; - return wantarray - ? (@list) - : $list[0]; - }; -} - -block_accessor 'name'; -block_accessor 'description'; -Spiffy::field 'seq_num'; -Spiffy::field 'is_filtered'; -Spiffy::field 'blocks_object'; -Spiffy::field 'original_values' => {}; - -sub set_value { - no strict 'refs'; - my $accessor = shift; - block_accessor $accessor - unless defined &$accessor; - $self->{$accessor} = [@_]; -} - -sub run_filters { - my $map = $self->_section_map; - my $order = $self->_section_order; - Carp::croak "Attempt to filter a block twice" - if $self->is_filtered; - for my $type (@$order) { - my $filters = $map->{$type}{filters}; - my @value = $self->$type; - $self->original_values->{$type} = $value[0]; - for my $filter ($self->_get_filters($type, $filters)) { - $Test::Base::Filter::arguments = - $filter =~ s/=(.*)$// ? $1 : undef; - my $function = "main::$filter"; - no strict 'refs'; - if (defined &$function) { - local $_ = - (@value == 1 and not defined($value[0])) ? undef : - join '', @value; - my $old = $_; - @value = &$function(@value); - if (not(@value) or - @value == 1 and defined($value[0]) and $value[0] =~ /\A(\d+|)\z/ - ) { - if ($value[0] && $_ eq $old) { - Test::Base::diag("Filters returning numbers are supposed to do munging \$_: your filter '$function' apparently doesn't."); - } - @value = ($_); - } - } - else { - my $filter_object = $self->blocks_object->filter_class->new; - die "Can't find a function or method for '$filter' filter\n" - unless $filter_object->can($filter); - $filter_object->current_block($self); - @value = $filter_object->$filter(@value); - } - # Set the value after each filter since other filters may be - # introspecting. - $self->set_value($type, @value); - } - } - $self->is_filtered(1); -} - -sub _get_filters { - my $type = shift; - my $string = shift || ''; - $string =~ s/\s*(.*?)\s*/$1/; - my @filters = (); - my $map_filters = $self->blocks_object->_filters_map->{$type} || []; - $map_filters = [ $map_filters ] unless ref $map_filters; - my @append = (); - for ( - @{$self->blocks_object->_filters}, - @$map_filters, - split(/\s+/, $string), - ) { - my $filter = $_; - last unless length $filter; - if ($filter =~ s/^-//) { - @filters = grep { $_ ne $filter } @filters; - } - elsif ($filter =~ s/^\+//) { - push @append, $filter; - } - else { - push @filters, $filter; - } - } - return @filters, @append; -} - -{ - %$reserved_section_names = map { - ($_, 1); - } keys(%Test::Base::Block::), qw( new DESTROY ); -} - -__DATA__ - -=encoding utf8 - -#line 1374 diff --git a/debian/modules/http-subs-filter/test/inc/Test/Base/Filter.pm b/debian/modules/http-subs-filter/test/inc/Test/Base/Filter.pm deleted file mode 100644 index d7b116b..0000000 --- a/debian/modules/http-subs-filter/test/inc/Test/Base/Filter.pm +++ /dev/null @@ -1,341 +0,0 @@ -#line 1 -#=============================================================================== -# This is the default class for handling Test::Base data filtering. -#=============================================================================== -package Test::Base::Filter; -use Spiffy -Base; -use Spiffy ':XXX'; - -field 'current_block'; - -our $arguments; -sub current_arguments { - return undef unless defined $arguments; - my $args = $arguments; - $args =~ s/(\\s)/ /g; - $args =~ s/(\\[a-z])/'"' . $1 . '"'/gee; - return $args; -} - -sub assert_scalar { - return if @_ == 1; - require Carp; - my $filter = (caller(1))[3]; - $filter =~ s/.*:://; - Carp::croak "Input to the '$filter' filter must be a scalar, not a list"; -} - -sub _apply_deepest { - my $method = shift; - return () unless @_; - if (ref $_[0] eq 'ARRAY') { - for my $aref (@_) { - @$aref = $self->_apply_deepest($method, @$aref); - } - return @_; - } - $self->$method(@_); -} - -sub _split_array { - map { - [$self->split($_)]; - } @_; -} - -sub _peel_deepest { - return () unless @_; - if (ref $_[0] eq 'ARRAY') { - if (ref $_[0]->[0] eq 'ARRAY') { - for my $aref (@_) { - @$aref = $self->_peel_deepest(@$aref); - } - return @_; - } - return map { $_->[0] } @_; - } - return @_; -} - -#=============================================================================== -# these filters work on the leaves of nested arrays -#=============================================================================== -sub Join { $self->_peel_deepest($self->_apply_deepest(join => @_)) } -sub Reverse { $self->_apply_deepest(reverse => @_) } -sub Split { $self->_apply_deepest(_split_array => @_) } -sub Sort { $self->_apply_deepest(sort => @_) } - - -sub append { - my $suffix = $self->current_arguments; - map { $_ . $suffix } @_; -} - -sub array { - return [@_]; -} - -sub base64_decode { - $self->assert_scalar(@_); - require MIME::Base64; - MIME::Base64::decode_base64(shift); -} - -sub base64_encode { - $self->assert_scalar(@_); - require MIME::Base64; - MIME::Base64::encode_base64(shift); -} - -sub chomp { - map { CORE::chomp; $_ } @_; -} - -sub chop { - map { CORE::chop; $_ } @_; -} - -sub dumper { - no warnings 'once'; - require Data::Dumper; - local $Data::Dumper::Sortkeys = 1; - local $Data::Dumper::Indent = 1; - local $Data::Dumper::Terse = 1; - Data::Dumper::Dumper(@_); -} - -sub escape { - $self->assert_scalar(@_); - my $text = shift; - $text =~ s/(\\.)/eval "qq{$1}"/ge; - return $text; -} - -sub eval { - $self->assert_scalar(@_); - my @return = CORE::eval(shift); - return $@ if $@; - return @return; -} - -sub eval_all { - $self->assert_scalar(@_); - my $out = ''; - my $err = ''; - Test::Base::tie_output(*STDOUT, $out); - Test::Base::tie_output(*STDERR, $err); - my $return = CORE::eval(shift); - no warnings; - untie *STDOUT; - untie *STDERR; - return $return, $@, $out, $err; -} - -sub eval_stderr { - $self->assert_scalar(@_); - my $output = ''; - Test::Base::tie_output(*STDERR, $output); - CORE::eval(shift); - no warnings; - untie *STDERR; - return $output; -} - -sub eval_stdout { - $self->assert_scalar(@_); - my $output = ''; - Test::Base::tie_output(*STDOUT, $output); - CORE::eval(shift); - no warnings; - untie *STDOUT; - return $output; -} - -sub exec_perl_stdout { - my $tmpfile = "/tmp/test-blocks-$$"; - $self->_write_to($tmpfile, @_); - open my $execution, "$^X $tmpfile 2>&1 |" - or die "Couldn't open subprocess: $!\n"; - local $/; - my $output = <$execution>; - close $execution; - unlink($tmpfile) - or die "Couldn't unlink $tmpfile: $!\n"; - return $output; -} - -sub flatten { - $self->assert_scalar(@_); - my $ref = shift; - if (ref($ref) eq 'HASH') { - return map { - ($_, $ref->{$_}); - } sort keys %$ref; - } - if (ref($ref) eq 'ARRAY') { - return @$ref; - } - die "Can only flatten a hash or array ref"; -} - -sub get_url { - $self->assert_scalar(@_); - my $url = shift; - CORE::chomp($url); - require LWP::Simple; - LWP::Simple::get($url); -} - -sub hash { - return +{ @_ }; -} - -sub head { - my $size = $self->current_arguments || 1; - return splice(@_, 0, $size); -} - -sub join { - my $string = $self->current_arguments; - $string = '' unless defined $string; - CORE::join $string, @_; -} - -sub lines { - $self->assert_scalar(@_); - my $text = shift; - return () unless length $text; - my @lines = ($text =~ /^(.*\n?)/gm); - return @lines; -} - -sub norm { - $self->assert_scalar(@_); - my $text = shift; - $text = '' unless defined $text; - $text =~ s/\015\012/\n/g; - $text =~ s/\r/\n/g; - return $text; -} - -sub prepend { - my $prefix = $self->current_arguments; - map { $prefix . $_ } @_; -} - -sub read_file { - $self->assert_scalar(@_); - my $file = shift; - CORE::chomp $file; - open my $fh, $file - or die "Can't open '$file' for input:\n$!"; - CORE::join '', <$fh>; -} - -sub regexp { - $self->assert_scalar(@_); - my $text = shift; - my $flags = $self->current_arguments; - if ($text =~ /\n.*?\n/s) { - $flags = 'xism' - unless defined $flags; - } - else { - CORE::chomp($text); - } - $flags ||= ''; - my $regexp = eval "qr{$text}$flags"; - die $@ if $@; - return $regexp; -} - -sub reverse { - CORE::reverse(@_); -} - -sub slice { - die "Invalid args for slice" - unless $self->current_arguments =~ /^(\d+)(?:,(\d))?$/; - my ($x, $y) = ($1, $2); - $y = $x if not defined $y; - die "Invalid args for slice" - if $x > $y; - return splice(@_, $x, 1 + $y - $x); -} - -sub sort { - CORE::sort(@_); -} - -sub split { - $self->assert_scalar(@_); - my $separator = $self->current_arguments; - if (defined $separator and $separator =~ s{^/(.*)/$}{$1}) { - my $regexp = $1; - $separator = qr{$regexp}; - } - $separator = qr/\s+/ unless $separator; - CORE::split $separator, shift; -} - -sub strict { - $self->assert_scalar(@_); - <<'...' . shift; -use strict; -use warnings; -... -} - -sub tail { - my $size = $self->current_arguments || 1; - return splice(@_, @_ - $size, $size); -} - -sub trim { - map { - s/\A([ \t]*\n)+//; - s/(?<=\n)\s*\z//g; - $_; - } @_; -} - -sub unchomp { - map { $_ . "\n" } @_; -} - -sub write_file { - my $file = $self->current_arguments - or die "No file specified for write_file filter"; - if ($file =~ /(.*)[\\\/]/) { - my $dir = $1; - if (not -e $dir) { - require File::Path; - File::Path::mkpath($dir) - or die "Can't create $dir"; - } - } - open my $fh, ">$file" - or die "Can't open '$file' for output\n:$!"; - print $fh @_; - close $fh; - return $file; -} - -sub yaml { - $self->assert_scalar(@_); - require YAML; - return YAML::Load(shift); -} - -sub _write_to { - my $filename = shift; - open my $script, ">$filename" - or die "Couldn't open $filename: $!\n"; - print $script @_; - close $script - or die "Couldn't close $filename: $!\n"; -} - -__DATA__ - -#line 636 diff --git a/debian/modules/http-subs-filter/test/inc/Test/Builder.pm b/debian/modules/http-subs-filter/test/inc/Test/Builder.pm deleted file mode 100644 index 14961dc..0000000 --- a/debian/modules/http-subs-filter/test/inc/Test/Builder.pm +++ /dev/null @@ -1,1413 +0,0 @@ -#line 1 -package Test::Builder; - -use 5.006; -use strict; -use warnings; - -our $VERSION = '0.92'; -$VERSION = eval $VERSION; ## no critic (BuiltinFunctions::ProhibitStringyEval) - -BEGIN { - if( $] < 5.008 ) { - require Test::Builder::IO::Scalar; - } -} - - -# Make Test::Builder thread-safe for ithreads. -BEGIN { - use Config; - # Load threads::shared when threads are turned on. - # 5.8.0's threads are so busted we no longer support them. - if( $] >= 5.008001 && $Config{useithreads} && $INC{'threads.pm'} ) { - require threads::shared; - - # Hack around YET ANOTHER threads::shared bug. It would - # occassionally forget the contents of the variable when sharing it. - # So we first copy the data, then share, then put our copy back. - *share = sub (\[$@%]) { - my $type = ref $_[0]; - my $data; - - if( $type eq 'HASH' ) { - %$data = %{ $_[0] }; - } - elsif( $type eq 'ARRAY' ) { - @$data = @{ $_[0] }; - } - elsif( $type eq 'SCALAR' ) { - $$data = ${ $_[0] }; - } - else { - die( "Unknown type: " . $type ); - } - - $_[0] = &threads::shared::share( $_[0] ); - - if( $type eq 'HASH' ) { - %{ $_[0] } = %$data; - } - elsif( $type eq 'ARRAY' ) { - @{ $_[0] } = @$data; - } - elsif( $type eq 'SCALAR' ) { - ${ $_[0] } = $$data; - } - else { - die( "Unknown type: " . $type ); - } - - return $_[0]; - }; - } - # 5.8.0's threads::shared is busted when threads are off - # and earlier Perls just don't have that module at all. - else { - *share = sub { return $_[0] }; - *lock = sub { 0 }; - } -} - -#line 117 - -my $Test = Test::Builder->new; - -sub new { - my($class) = shift; - $Test ||= $class->create; - return $Test; -} - -#line 139 - -sub create { - my $class = shift; - - my $self = bless {}, $class; - $self->reset; - - return $self; -} - -#line 158 - -our $Level; - -sub reset { ## no critic (Subroutines::ProhibitBuiltinHomonyms) - my($self) = @_; - - # We leave this a global because it has to be localized and localizing - # hash keys is just asking for pain. Also, it was documented. - $Level = 1; - - $self->{Have_Plan} = 0; - $self->{No_Plan} = 0; - $self->{Have_Output_Plan} = 0; - - $self->{Original_Pid} = $$; - - share( $self->{Curr_Test} ); - $self->{Curr_Test} = 0; - $self->{Test_Results} = &share( [] ); - - $self->{Exported_To} = undef; - $self->{Expected_Tests} = 0; - - $self->{Skip_All} = 0; - - $self->{Use_Nums} = 1; - - $self->{No_Header} = 0; - $self->{No_Ending} = 0; - - $self->{Todo} = undef; - $self->{Todo_Stack} = []; - $self->{Start_Todo} = 0; - $self->{Opened_Testhandles} = 0; - - $self->_dup_stdhandles; - - return; -} - -#line 219 - -my %plan_cmds = ( - no_plan => \&no_plan, - skip_all => \&skip_all, - tests => \&_plan_tests, -); - -sub plan { - my( $self, $cmd, $arg ) = @_; - - return unless $cmd; - - local $Level = $Level + 1; - - $self->croak("You tried to plan twice") if $self->{Have_Plan}; - - if( my $method = $plan_cmds{$cmd} ) { - local $Level = $Level + 1; - $self->$method($arg); - } - else { - my @args = grep { defined } ( $cmd, $arg ); - $self->croak("plan() doesn't understand @args"); - } - - return 1; -} - - -sub _plan_tests { - my($self, $arg) = @_; - - if($arg) { - local $Level = $Level + 1; - return $self->expected_tests($arg); - } - elsif( !defined $arg ) { - $self->croak("Got an undefined number of tests"); - } - else { - $self->croak("You said to run 0 tests"); - } - - return; -} - - -#line 275 - -sub expected_tests { - my $self = shift; - my($max) = @_; - - if(@_) { - $self->croak("Number of tests must be a positive integer. You gave it '$max'") - unless $max =~ /^\+?\d+$/; - - $self->{Expected_Tests} = $max; - $self->{Have_Plan} = 1; - - $self->_output_plan($max) unless $self->no_header; - } - return $self->{Expected_Tests}; -} - -#line 299 - -sub no_plan { - my($self, $arg) = @_; - - $self->carp("no_plan takes no arguments") if $arg; - - $self->{No_Plan} = 1; - $self->{Have_Plan} = 1; - - return 1; -} - - -#line 333 - -sub _output_plan { - my($self, $max, $directive, $reason) = @_; - - $self->carp("The plan was already output") if $self->{Have_Output_Plan}; - - my $plan = "1..$max"; - $plan .= " # $directive" if defined $directive; - $plan .= " $reason" if defined $reason; - - $self->_print("$plan\n"); - - $self->{Have_Output_Plan} = 1; - - return; -} - -#line 384 - -sub done_testing { - my($self, $num_tests) = @_; - - # If done_testing() specified the number of tests, shut off no_plan. - if( defined $num_tests ) { - $self->{No_Plan} = 0; - } - else { - $num_tests = $self->current_test; - } - - if( $self->{Done_Testing} ) { - my($file, $line) = @{$self->{Done_Testing}}[1,2]; - $self->ok(0, "done_testing() was already called at $file line $line"); - return; - } - - $self->{Done_Testing} = [caller]; - - if( $self->expected_tests && $num_tests != $self->expected_tests ) { - $self->ok(0, "planned to run @{[ $self->expected_tests ]} ". - "but done_testing() expects $num_tests"); - } - else { - $self->{Expected_Tests} = $num_tests; - } - - $self->_output_plan($num_tests) unless $self->{Have_Output_Plan}; - - $self->{Have_Plan} = 1; - - return 1; -} - - -#line 429 - -sub has_plan { - my $self = shift; - - return( $self->{Expected_Tests} ) if $self->{Expected_Tests}; - return('no_plan') if $self->{No_Plan}; - return(undef); -} - -#line 446 - -sub skip_all { - my( $self, $reason ) = @_; - - $self->{Skip_All} = 1; - - $self->_output_plan(0, "SKIP", $reason) unless $self->no_header; - exit(0); -} - -#line 468 - -sub exported_to { - my( $self, $pack ) = @_; - - if( defined $pack ) { - $self->{Exported_To} = $pack; - } - return $self->{Exported_To}; -} - -#line 498 - -sub ok { - my( $self, $test, $name ) = @_; - - # $test might contain an object which we don't want to accidentally - # store, so we turn it into a boolean. - $test = $test ? 1 : 0; - - lock $self->{Curr_Test}; - $self->{Curr_Test}++; - - # In case $name is a string overloaded object, force it to stringify. - $self->_unoverload_str( \$name ); - - $self->diag(<<"ERR") if defined $name and $name =~ /^[\d\s]+$/; - You named your test '$name'. You shouldn't use numbers for your test names. - Very confusing. -ERR - - # Capture the value of $TODO for the rest of this ok() call - # so it can more easily be found by other routines. - my $todo = $self->todo(); - my $in_todo = $self->in_todo; - local $self->{Todo} = $todo if $in_todo; - - $self->_unoverload_str( \$todo ); - - my $out; - my $result = &share( {} ); - - unless($test) { - $out .= "not "; - @$result{ 'ok', 'actual_ok' } = ( ( $self->in_todo ? 1 : 0 ), 0 ); - } - else { - @$result{ 'ok', 'actual_ok' } = ( 1, $test ); - } - - $out .= "ok"; - $out .= " $self->{Curr_Test}" if $self->use_numbers; - - if( defined $name ) { - $name =~ s|#|\\#|g; # # in a name can confuse Test::Harness. - $out .= " - $name"; - $result->{name} = $name; - } - else { - $result->{name} = ''; - } - - if( $self->in_todo ) { - $out .= " # TODO $todo"; - $result->{reason} = $todo; - $result->{type} = 'todo'; - } - else { - $result->{reason} = ''; - $result->{type} = ''; - } - - $self->{Test_Results}[ $self->{Curr_Test} - 1 ] = $result; - $out .= "\n"; - - $self->_print($out); - - unless($test) { - my $msg = $self->in_todo ? "Failed (TODO)" : "Failed"; - $self->_print_to_fh( $self->_diag_fh, "\n" ) if $ENV{HARNESS_ACTIVE}; - - my( undef, $file, $line ) = $self->caller; - if( defined $name ) { - $self->diag(qq[ $msg test '$name'\n]); - $self->diag(qq[ at $file line $line.\n]); - } - else { - $self->diag(qq[ $msg test at $file line $line.\n]); - } - } - - return $test ? 1 : 0; -} - -sub _unoverload { - my $self = shift; - my $type = shift; - - $self->_try(sub { require overload; }, die_on_fail => 1); - - foreach my $thing (@_) { - if( $self->_is_object($$thing) ) { - if( my $string_meth = overload::Method( $$thing, $type ) ) { - $$thing = $$thing->$string_meth(); - } - } - } - - return; -} - -sub _is_object { - my( $self, $thing ) = @_; - - return $self->_try( sub { ref $thing && $thing->isa('UNIVERSAL') } ) ? 1 : 0; -} - -sub _unoverload_str { - my $self = shift; - - return $self->_unoverload( q[""], @_ ); -} - -sub _unoverload_num { - my $self = shift; - - $self->_unoverload( '0+', @_ ); - - for my $val (@_) { - next unless $self->_is_dualvar($$val); - $$val = $$val + 0; - } - - return; -} - -# This is a hack to detect a dualvar such as $! -sub _is_dualvar { - my( $self, $val ) = @_; - - # Objects are not dualvars. - return 0 if ref $val; - - no warnings 'numeric'; - my $numval = $val + 0; - return $numval != 0 and $numval ne $val ? 1 : 0; -} - -#line 649 - -sub is_eq { - my( $self, $got, $expect, $name ) = @_; - local $Level = $Level + 1; - - $self->_unoverload_str( \$got, \$expect ); - - if( !defined $got || !defined $expect ) { - # undef only matches undef and nothing else - my $test = !defined $got && !defined $expect; - - $self->ok( $test, $name ); - $self->_is_diag( $got, 'eq', $expect ) unless $test; - return $test; - } - - return $self->cmp_ok( $got, 'eq', $expect, $name ); -} - -sub is_num { - my( $self, $got, $expect, $name ) = @_; - local $Level = $Level + 1; - - $self->_unoverload_num( \$got, \$expect ); - - if( !defined $got || !defined $expect ) { - # undef only matches undef and nothing else - my $test = !defined $got && !defined $expect; - - $self->ok( $test, $name ); - $self->_is_diag( $got, '==', $expect ) unless $test; - return $test; - } - - return $self->cmp_ok( $got, '==', $expect, $name ); -} - -sub _diag_fmt { - my( $self, $type, $val ) = @_; - - if( defined $$val ) { - if( $type eq 'eq' or $type eq 'ne' ) { - # quote and force string context - $$val = "'$$val'"; - } - else { - # force numeric context - $self->_unoverload_num($val); - } - } - else { - $$val = 'undef'; - } - - return; -} - -sub _is_diag { - my( $self, $got, $type, $expect ) = @_; - - $self->_diag_fmt( $type, $_ ) for \$got, \$expect; - - local $Level = $Level + 1; - return $self->diag(<<"DIAGNOSTIC"); - got: $got - expected: $expect -DIAGNOSTIC - -} - -sub _isnt_diag { - my( $self, $got, $type ) = @_; - - $self->_diag_fmt( $type, \$got ); - - local $Level = $Level + 1; - return $self->diag(<<"DIAGNOSTIC"); - got: $got - expected: anything else -DIAGNOSTIC -} - -#line 746 - -sub isnt_eq { - my( $self, $got, $dont_expect, $name ) = @_; - local $Level = $Level + 1; - - if( !defined $got || !defined $dont_expect ) { - # undef only matches undef and nothing else - my $test = defined $got || defined $dont_expect; - - $self->ok( $test, $name ); - $self->_isnt_diag( $got, 'ne' ) unless $test; - return $test; - } - - return $self->cmp_ok( $got, 'ne', $dont_expect, $name ); -} - -sub isnt_num { - my( $self, $got, $dont_expect, $name ) = @_; - local $Level = $Level + 1; - - if( !defined $got || !defined $dont_expect ) { - # undef only matches undef and nothing else - my $test = defined $got || defined $dont_expect; - - $self->ok( $test, $name ); - $self->_isnt_diag( $got, '!=' ) unless $test; - return $test; - } - - return $self->cmp_ok( $got, '!=', $dont_expect, $name ); -} - -#line 797 - -sub like { - my( $self, $this, $regex, $name ) = @_; - - local $Level = $Level + 1; - return $self->_regex_ok( $this, $regex, '=~', $name ); -} - -sub unlike { - my( $self, $this, $regex, $name ) = @_; - - local $Level = $Level + 1; - return $self->_regex_ok( $this, $regex, '!~', $name ); -} - -#line 821 - -my %numeric_cmps = map { ( $_, 1 ) } ( "<", "<=", ">", ">=", "==", "!=", "<=>" ); - -sub cmp_ok { - my( $self, $got, $type, $expect, $name ) = @_; - - my $test; - my $error; - { - ## no critic (BuiltinFunctions::ProhibitStringyEval) - - local( $@, $!, $SIG{__DIE__} ); # isolate eval - - my($pack, $file, $line) = $self->caller(); - - $test = eval qq[ -#line 1 "cmp_ok [from $file line $line]" -\$got $type \$expect; -]; - $error = $@; - } - local $Level = $Level + 1; - my $ok = $self->ok( $test, $name ); - - # Treat overloaded objects as numbers if we're asked to do a - # numeric comparison. - my $unoverload - = $numeric_cmps{$type} - ? '_unoverload_num' - : '_unoverload_str'; - - $self->diag(<<"END") if $error; -An error occurred while using $type: ------------------------------------- -$error ------------------------------------- -END - - unless($ok) { - $self->$unoverload( \$got, \$expect ); - - if( $type =~ /^(eq|==)$/ ) { - $self->_is_diag( $got, $type, $expect ); - } - elsif( $type =~ /^(ne|!=)$/ ) { - $self->_isnt_diag( $got, $type ); - } - else { - $self->_cmp_diag( $got, $type, $expect ); - } - } - return $ok; -} - -sub _cmp_diag { - my( $self, $got, $type, $expect ) = @_; - - $got = defined $got ? "'$got'" : 'undef'; - $expect = defined $expect ? "'$expect'" : 'undef'; - - local $Level = $Level + 1; - return $self->diag(<<"DIAGNOSTIC"); - $got - $type - $expect -DIAGNOSTIC -} - -sub _caller_context { - my $self = shift; - - my( $pack, $file, $line ) = $self->caller(1); - - my $code = ''; - $code .= "#line $line $file\n" if defined $file and defined $line; - - return $code; -} - -#line 920 - -sub BAIL_OUT { - my( $self, $reason ) = @_; - - $self->{Bailed_Out} = 1; - $self->_print("Bail out! $reason"); - exit 255; -} - -#line 933 - -*BAILOUT = \&BAIL_OUT; - -#line 944 - -sub skip { - my( $self, $why ) = @_; - $why ||= ''; - $self->_unoverload_str( \$why ); - - lock( $self->{Curr_Test} ); - $self->{Curr_Test}++; - - $self->{Test_Results}[ $self->{Curr_Test} - 1 ] = &share( - { - 'ok' => 1, - actual_ok => 1, - name => '', - type => 'skip', - reason => $why, - } - ); - - my $out = "ok"; - $out .= " $self->{Curr_Test}" if $self->use_numbers; - $out .= " # skip"; - $out .= " $why" if length $why; - $out .= "\n"; - - $self->_print($out); - - return 1; -} - -#line 985 - -sub todo_skip { - my( $self, $why ) = @_; - $why ||= ''; - - lock( $self->{Curr_Test} ); - $self->{Curr_Test}++; - - $self->{Test_Results}[ $self->{Curr_Test} - 1 ] = &share( - { - 'ok' => 1, - actual_ok => 0, - name => '', - type => 'todo_skip', - reason => $why, - } - ); - - my $out = "not ok"; - $out .= " $self->{Curr_Test}" if $self->use_numbers; - $out .= " # TODO & SKIP $why\n"; - - $self->_print($out); - - return 1; -} - -#line 1062 - -sub maybe_regex { - my( $self, $regex ) = @_; - my $usable_regex = undef; - - return $usable_regex unless defined $regex; - - my( $re, $opts ); - - # Check for qr/foo/ - if( _is_qr($regex) ) { - $usable_regex = $regex; - } - # Check for '/foo/' or 'm,foo,' - elsif(( $re, $opts ) = $regex =~ m{^ /(.*)/ (\w*) $ }sx or - ( undef, $re, $opts ) = $regex =~ m,^ m([^\w\s]) (.+) \1 (\w*) $,sx - ) - { - $usable_regex = length $opts ? "(?$opts)$re" : $re; - } - - return $usable_regex; -} - -sub _is_qr { - my $regex = shift; - - # is_regexp() checks for regexes in a robust manner, say if they're - # blessed. - return re::is_regexp($regex) if defined &re::is_regexp; - return ref $regex eq 'Regexp'; -} - -sub _regex_ok { - my( $self, $this, $regex, $cmp, $name ) = @_; - - my $ok = 0; - my $usable_regex = $self->maybe_regex($regex); - unless( defined $usable_regex ) { - local $Level = $Level + 1; - $ok = $self->ok( 0, $name ); - $self->diag(" '$regex' doesn't look much like a regex to me."); - return $ok; - } - - { - ## no critic (BuiltinFunctions::ProhibitStringyEval) - - my $test; - my $code = $self->_caller_context; - - local( $@, $!, $SIG{__DIE__} ); # isolate eval - - # Yes, it has to look like this or 5.4.5 won't see the #line - # directive. - # Don't ask me, man, I just work here. - $test = eval " -$code" . q{$test = $this =~ /$usable_regex/ ? 1 : 0}; - - $test = !$test if $cmp eq '!~'; - - local $Level = $Level + 1; - $ok = $self->ok( $test, $name ); - } - - unless($ok) { - $this = defined $this ? "'$this'" : 'undef'; - my $match = $cmp eq '=~' ? "doesn't match" : "matches"; - - local $Level = $Level + 1; - $self->diag( sprintf <<'DIAGNOSTIC', $this, $match, $regex ); - %s - %13s '%s' -DIAGNOSTIC - - } - - return $ok; -} - -# I'm not ready to publish this. It doesn't deal with array return -# values from the code or context. - -#line 1162 - -sub _try { - my( $self, $code, %opts ) = @_; - - my $error; - my $return; - { - local $!; # eval can mess up $! - local $@; # don't set $@ in the test - local $SIG{__DIE__}; # don't trip an outside DIE handler. - $return = eval { $code->() }; - $error = $@; - } - - die $error if $error and $opts{die_on_fail}; - - return wantarray ? ( $return, $error ) : $return; -} - -#line 1191 - -sub is_fh { - my $self = shift; - my $maybe_fh = shift; - return 0 unless defined $maybe_fh; - - return 1 if ref $maybe_fh eq 'GLOB'; # its a glob ref - return 1 if ref \$maybe_fh eq 'GLOB'; # its a glob - - return eval { $maybe_fh->isa("IO::Handle") } || - # 5.5.4's tied() and can() doesn't like getting undef - eval { ( tied($maybe_fh) || '' )->can('TIEHANDLE') }; -} - -#line 1235 - -sub level { - my( $self, $level ) = @_; - - if( defined $level ) { - $Level = $level; - } - return $Level; -} - -#line 1267 - -sub use_numbers { - my( $self, $use_nums ) = @_; - - if( defined $use_nums ) { - $self->{Use_Nums} = $use_nums; - } - return $self->{Use_Nums}; -} - -#line 1300 - -foreach my $attribute (qw(No_Header No_Ending No_Diag)) { - my $method = lc $attribute; - - my $code = sub { - my( $self, $no ) = @_; - - if( defined $no ) { - $self->{$attribute} = $no; - } - return $self->{$attribute}; - }; - - no strict 'refs'; ## no critic - *{ __PACKAGE__ . '::' . $method } = $code; -} - -#line 1353 - -sub diag { - my $self = shift; - - $self->_print_comment( $self->_diag_fh, @_ ); -} - -#line 1368 - -sub note { - my $self = shift; - - $self->_print_comment( $self->output, @_ ); -} - -sub _diag_fh { - my $self = shift; - - local $Level = $Level + 1; - return $self->in_todo ? $self->todo_output : $self->failure_output; -} - -sub _print_comment { - my( $self, $fh, @msgs ) = @_; - - return if $self->no_diag; - return unless @msgs; - - # Prevent printing headers when compiling (i.e. -c) - return if $^C; - - # Smash args together like print does. - # Convert undef to 'undef' so its readable. - my $msg = join '', map { defined($_) ? $_ : 'undef' } @msgs; - - # Escape the beginning, _print will take care of the rest. - $msg =~ s/^/# /; - - local $Level = $Level + 1; - $self->_print_to_fh( $fh, $msg ); - - return 0; -} - -#line 1418 - -sub explain { - my $self = shift; - - return map { - ref $_ - ? do { - $self->_try(sub { require Data::Dumper }, die_on_fail => 1); - - my $dumper = Data::Dumper->new( [$_] ); - $dumper->Indent(1)->Terse(1); - $dumper->Sortkeys(1) if $dumper->can("Sortkeys"); - $dumper->Dump; - } - : $_ - } @_; -} - -#line 1447 - -sub _print { - my $self = shift; - return $self->_print_to_fh( $self->output, @_ ); -} - -sub _print_to_fh { - my( $self, $fh, @msgs ) = @_; - - # Prevent printing headers when only compiling. Mostly for when - # tests are deparsed with B::Deparse - return if $^C; - - my $msg = join '', @msgs; - - local( $\, $", $, ) = ( undef, ' ', '' ); - - # Escape each line after the first with a # so we don't - # confuse Test::Harness. - $msg =~ s{\n(?!\z)}{\n# }sg; - - # Stick a newline on the end if it needs it. - $msg .= "\n" unless $msg =~ /\n\z/; - - return print $fh $msg; -} - -#line 1506 - -sub output { - my( $self, $fh ) = @_; - - if( defined $fh ) { - $self->{Out_FH} = $self->_new_fh($fh); - } - return $self->{Out_FH}; -} - -sub failure_output { - my( $self, $fh ) = @_; - - if( defined $fh ) { - $self->{Fail_FH} = $self->_new_fh($fh); - } - return $self->{Fail_FH}; -} - -sub todo_output { - my( $self, $fh ) = @_; - - if( defined $fh ) { - $self->{Todo_FH} = $self->_new_fh($fh); - } - return $self->{Todo_FH}; -} - -sub _new_fh { - my $self = shift; - my($file_or_fh) = shift; - - my $fh; - if( $self->is_fh($file_or_fh) ) { - $fh = $file_or_fh; - } - elsif( ref $file_or_fh eq 'SCALAR' ) { - # Scalar refs as filehandles was added in 5.8. - if( $] >= 5.008 ) { - open $fh, ">>", $file_or_fh - or $self->croak("Can't open scalar ref $file_or_fh: $!"); - } - # Emulate scalar ref filehandles with a tie. - else { - $fh = Test::Builder::IO::Scalar->new($file_or_fh) - or $self->croak("Can't tie scalar ref $file_or_fh"); - } - } - else { - open $fh, ">", $file_or_fh - or $self->croak("Can't open test output log $file_or_fh: $!"); - _autoflush($fh); - } - - return $fh; -} - -sub _autoflush { - my($fh) = shift; - my $old_fh = select $fh; - $| = 1; - select $old_fh; - - return; -} - -my( $Testout, $Testerr ); - -sub _dup_stdhandles { - my $self = shift; - - $self->_open_testhandles; - - # Set everything to unbuffered else plain prints to STDOUT will - # come out in the wrong order from our own prints. - _autoflush($Testout); - _autoflush( \*STDOUT ); - _autoflush($Testerr); - _autoflush( \*STDERR ); - - $self->reset_outputs; - - return; -} - -sub _open_testhandles { - my $self = shift; - - return if $self->{Opened_Testhandles}; - - # We dup STDOUT and STDERR so people can change them in their - # test suites while still getting normal test output. - open( $Testout, ">&STDOUT" ) or die "Can't dup STDOUT: $!"; - open( $Testerr, ">&STDERR" ) or die "Can't dup STDERR: $!"; - - # $self->_copy_io_layers( \*STDOUT, $Testout ); - # $self->_copy_io_layers( \*STDERR, $Testerr ); - - $self->{Opened_Testhandles} = 1; - - return; -} - -sub _copy_io_layers { - my( $self, $src, $dst ) = @_; - - $self->_try( - sub { - require PerlIO; - my @src_layers = PerlIO::get_layers($src); - - binmode $dst, join " ", map ":$_", @src_layers if @src_layers; - } - ); - - return; -} - -#line 1631 - -sub reset_outputs { - my $self = shift; - - $self->output ($Testout); - $self->failure_output($Testerr); - $self->todo_output ($Testout); - - return; -} - -#line 1657 - -sub _message_at_caller { - my $self = shift; - - local $Level = $Level + 1; - my( $pack, $file, $line ) = $self->caller; - return join( "", @_ ) . " at $file line $line.\n"; -} - -sub carp { - my $self = shift; - return warn $self->_message_at_caller(@_); -} - -sub croak { - my $self = shift; - return die $self->_message_at_caller(@_); -} - - -#line 1697 - -sub current_test { - my( $self, $num ) = @_; - - lock( $self->{Curr_Test} ); - if( defined $num ) { - $self->{Curr_Test} = $num; - - # If the test counter is being pushed forward fill in the details. - my $test_results = $self->{Test_Results}; - if( $num > @$test_results ) { - my $start = @$test_results ? @$test_results : 0; - for( $start .. $num - 1 ) { - $test_results->[$_] = &share( - { - 'ok' => 1, - actual_ok => undef, - reason => 'incrementing test number', - type => 'unknown', - name => undef - } - ); - } - } - # If backward, wipe history. Its their funeral. - elsif( $num < @$test_results ) { - $#{$test_results} = $num - 1; - } - } - return $self->{Curr_Test}; -} - -#line 1739 - -sub summary { - my($self) = shift; - - return map { $_->{'ok'} } @{ $self->{Test_Results} }; -} - -#line 1794 - -sub details { - my $self = shift; - return @{ $self->{Test_Results} }; -} - -#line 1823 - -sub todo { - my( $self, $pack ) = @_; - - return $self->{Todo} if defined $self->{Todo}; - - local $Level = $Level + 1; - my $todo = $self->find_TODO($pack); - return $todo if defined $todo; - - return ''; -} - -#line 1845 - -sub find_TODO { - my( $self, $pack ) = @_; - - $pack = $pack || $self->caller(1) || $self->exported_to; - return unless $pack; - - no strict 'refs'; ## no critic - return ${ $pack . '::TODO' }; -} - -#line 1863 - -sub in_todo { - my $self = shift; - - local $Level = $Level + 1; - return( defined $self->{Todo} || $self->find_TODO ) ? 1 : 0; -} - -#line 1913 - -sub todo_start { - my $self = shift; - my $message = @_ ? shift : ''; - - $self->{Start_Todo}++; - if( $self->in_todo ) { - push @{ $self->{Todo_Stack} } => $self->todo; - } - $self->{Todo} = $message; - - return; -} - -#line 1935 - -sub todo_end { - my $self = shift; - - if( !$self->{Start_Todo} ) { - $self->croak('todo_end() called without todo_start()'); - } - - $self->{Start_Todo}--; - - if( $self->{Start_Todo} && @{ $self->{Todo_Stack} } ) { - $self->{Todo} = pop @{ $self->{Todo_Stack} }; - } - else { - delete $self->{Todo}; - } - - return; -} - -#line 1968 - -sub caller { ## no critic (Subroutines::ProhibitBuiltinHomonyms) - my( $self, $height ) = @_; - $height ||= 0; - - my $level = $self->level + $height + 1; - my @caller; - do { - @caller = CORE::caller( $level ); - $level--; - } until @caller; - return wantarray ? @caller : $caller[0]; -} - -#line 1985 - -#line 1999 - -#'# -sub _sanity_check { - my $self = shift; - - $self->_whoa( $self->{Curr_Test} < 0, 'Says here you ran a negative number of tests!' ); - $self->_whoa( $self->{Curr_Test} != @{ $self->{Test_Results} }, - 'Somehow you got a different number of results than tests ran!' ); - - return; -} - -#line 2020 - -sub _whoa { - my( $self, $check, $desc ) = @_; - if($check) { - local $Level = $Level + 1; - $self->croak(<<"WHOA"); -WHOA! $desc -This should never happen! Please contact the author immediately! -WHOA - } - - return; -} - -#line 2044 - -sub _my_exit { - $? = $_[0]; ## no critic (Variables::RequireLocalizedPunctuationVars) - - return 1; -} - -#line 2056 - -sub _ending { - my $self = shift; - - my $real_exit_code = $?; - - # Don't bother with an ending if this is a forked copy. Only the parent - # should do the ending. - if( $self->{Original_Pid} != $$ ) { - return; - } - - # Ran tests but never declared a plan or hit done_testing - if( !$self->{Have_Plan} and $self->{Curr_Test} ) { - $self->diag("Tests were run but no plan was declared and done_testing() was not seen."); - } - - # Exit if plan() was never called. This is so "require Test::Simple" - # doesn't puke. - if( !$self->{Have_Plan} ) { - return; - } - - # Don't do an ending if we bailed out. - if( $self->{Bailed_Out} ) { - return; - } - - # Figure out if we passed or failed and print helpful messages. - my $test_results = $self->{Test_Results}; - if(@$test_results) { - # The plan? We have no plan. - if( $self->{No_Plan} ) { - $self->_output_plan($self->{Curr_Test}) unless $self->no_header; - $self->{Expected_Tests} = $self->{Curr_Test}; - } - - # Auto-extended arrays and elements which aren't explicitly - # filled in with a shared reference will puke under 5.8.0 - # ithreads. So we have to fill them in by hand. :( - my $empty_result = &share( {} ); - for my $idx ( 0 .. $self->{Expected_Tests} - 1 ) { - $test_results->[$idx] = $empty_result - unless defined $test_results->[$idx]; - } - - my $num_failed = grep !$_->{'ok'}, @{$test_results}[ 0 .. $self->{Curr_Test} - 1 ]; - - my $num_extra = $self->{Curr_Test} - $self->{Expected_Tests}; - - if( $num_extra != 0 ) { - my $s = $self->{Expected_Tests} == 1 ? '' : 's'; - $self->diag(<<"FAIL"); -Looks like you planned $self->{Expected_Tests} test$s but ran $self->{Curr_Test}. -FAIL - } - - if($num_failed) { - my $num_tests = $self->{Curr_Test}; - my $s = $num_failed == 1 ? '' : 's'; - - my $qualifier = $num_extra == 0 ? '' : ' run'; - - $self->diag(<<"FAIL"); -Looks like you failed $num_failed test$s of $num_tests$qualifier. -FAIL - } - - if($real_exit_code) { - $self->diag(<<"FAIL"); -Looks like your test exited with $real_exit_code just after $self->{Curr_Test}. -FAIL - - _my_exit($real_exit_code) && return; - } - - my $exit_code; - if($num_failed) { - $exit_code = $num_failed <= 254 ? $num_failed : 254; - } - elsif( $num_extra != 0 ) { - $exit_code = 255; - } - else { - $exit_code = 0; - } - - _my_exit($exit_code) && return; - } - elsif( $self->{Skip_All} ) { - _my_exit(0) && return; - } - elsif($real_exit_code) { - $self->diag(<<"FAIL"); -Looks like your test exited with $real_exit_code before it could output anything. -FAIL - _my_exit($real_exit_code) && return; - } - else { - $self->diag("No tests run!\n"); - _my_exit(255) && return; - } - - $self->_whoa( 1, "We fell off the end of _ending()" ); -} - -END { - $Test->_ending if defined $Test and !$Test->no_ending; -} - -#line 2236 - -1; - diff --git a/debian/modules/http-subs-filter/test/inc/Test/Builder/Module.pm b/debian/modules/http-subs-filter/test/inc/Test/Builder/Module.pm deleted file mode 100644 index de793c1..0000000 --- a/debian/modules/http-subs-filter/test/inc/Test/Builder/Module.pm +++ /dev/null @@ -1,81 +0,0 @@ -#line 1 -package Test::Builder::Module; - -use strict; - -use Test::Builder; - -require Exporter; -our @ISA = qw(Exporter); - -our $VERSION = '0.92'; -$VERSION = eval $VERSION; ## no critic (BuiltinFunctions::ProhibitStringyEval) - -# 5.004's Exporter doesn't have export_to_level. -my $_export_to_level = sub { - my $pkg = shift; - my $level = shift; - (undef) = shift; # redundant arg - my $callpkg = caller($level); - $pkg->export( $callpkg, @_ ); -}; - -#line 82 - -sub import { - my($class) = shift; - - # Don't run all this when loading ourself. - return 1 if $class eq 'Test::Builder::Module'; - - my $test = $class->builder; - - my $caller = caller; - - $test->exported_to($caller); - - $class->import_extra( \@_ ); - my(@imports) = $class->_strip_imports( \@_ ); - - $test->plan(@_); - - $class->$_export_to_level( 1, $class, @imports ); -} - -sub _strip_imports { - my $class = shift; - my $list = shift; - - my @imports = (); - my @other = (); - my $idx = 0; - while( $idx <= $#{$list} ) { - my $item = $list->[$idx]; - - if( defined $item and $item eq 'import' ) { - push @imports, @{ $list->[ $idx + 1 ] }; - $idx++; - } - else { - push @other, $item; - } - - $idx++; - } - - @$list = @other; - - return @imports; -} - -#line 145 - -sub import_extra { } - -#line 175 - -sub builder { - return Test::Builder->new; -} - -1; diff --git a/debian/modules/http-subs-filter/test/inc/Test/More.pm b/debian/modules/http-subs-filter/test/inc/Test/More.pm deleted file mode 100644 index 9e98a6a..0000000 --- a/debian/modules/http-subs-filter/test/inc/Test/More.pm +++ /dev/null @@ -1,735 +0,0 @@ -#line 1 -package Test::More; - -use 5.006; -use strict; -use warnings; - -#---- perlcritic exemptions. ----# - -# We use a lot of subroutine prototypes -## no critic (Subroutines::ProhibitSubroutinePrototypes) - -# Can't use Carp because it might cause use_ok() to accidentally succeed -# even though the module being used forgot to use Carp. Yes, this -# actually happened. -sub _carp { - my( $file, $line ) = ( caller(1) )[ 1, 2 ]; - return warn @_, " at $file line $line\n"; -} - -our $VERSION = '0.92'; -$VERSION = eval $VERSION; ## no critic (BuiltinFunctions::ProhibitStringyEval) - -use Test::Builder::Module; -our @ISA = qw(Test::Builder::Module); -our @EXPORT = qw(ok use_ok require_ok - is isnt like unlike is_deeply - cmp_ok - skip todo todo_skip - pass fail - eq_array eq_hash eq_set - $TODO - plan - done_testing - can_ok isa_ok new_ok - diag note explain - BAIL_OUT -); - -#line 163 - -sub plan { - my $tb = Test::More->builder; - - return $tb->plan(@_); -} - -# This implements "use Test::More 'no_diag'" but the behavior is -# deprecated. -sub import_extra { - my $class = shift; - my $list = shift; - - my @other = (); - my $idx = 0; - while( $idx <= $#{$list} ) { - my $item = $list->[$idx]; - - if( defined $item and $item eq 'no_diag' ) { - $class->builder->no_diag(1); - } - else { - push @other, $item; - } - - $idx++; - } - - @$list = @other; - - return; -} - -#line 216 - -sub done_testing { - my $tb = Test::More->builder; - $tb->done_testing(@_); -} - -#line 289 - -sub ok ($;$) { - my( $test, $name ) = @_; - my $tb = Test::More->builder; - - return $tb->ok( $test, $name ); -} - -#line 367 - -sub is ($$;$) { - my $tb = Test::More->builder; - - return $tb->is_eq(@_); -} - -sub isnt ($$;$) { - my $tb = Test::More->builder; - - return $tb->isnt_eq(@_); -} - -*isn't = \&isnt; - -#line 411 - -sub like ($$;$) { - my $tb = Test::More->builder; - - return $tb->like(@_); -} - -#line 426 - -sub unlike ($$;$) { - my $tb = Test::More->builder; - - return $tb->unlike(@_); -} - -#line 471 - -sub cmp_ok($$$;$) { - my $tb = Test::More->builder; - - return $tb->cmp_ok(@_); -} - -#line 506 - -sub can_ok ($@) { - my( $proto, @methods ) = @_; - my $class = ref $proto || $proto; - my $tb = Test::More->builder; - - unless($class) { - my $ok = $tb->ok( 0, "->can(...)" ); - $tb->diag(' can_ok() called with empty class or reference'); - return $ok; - } - - unless(@methods) { - my $ok = $tb->ok( 0, "$class->can(...)" ); - $tb->diag(' can_ok() called with no methods'); - return $ok; - } - - my @nok = (); - foreach my $method (@methods) { - $tb->_try( sub { $proto->can($method) } ) or push @nok, $method; - } - - my $name = (@methods == 1) ? "$class->can('$methods[0]')" : - "$class->can(...)" ; - - my $ok = $tb->ok( !@nok, $name ); - - $tb->diag( map " $class->can('$_') failed\n", @nok ); - - return $ok; -} - -#line 572 - -sub isa_ok ($$;$) { - my( $object, $class, $obj_name ) = @_; - my $tb = Test::More->builder; - - my $diag; - - if( !defined $object ) { - $obj_name = 'The thing' unless defined $obj_name; - $diag = "$obj_name isn't defined"; - } - else { - my $whatami = ref $object ? 'object' : 'class'; - # We can't use UNIVERSAL::isa because we want to honor isa() overrides - my( $rslt, $error ) = $tb->_try( sub { $object->isa($class) } ); - if($error) { - if( $error =~ /^Can't call method "isa" on unblessed reference/ ) { - # Its an unblessed reference - $obj_name = 'The reference' unless defined $obj_name; - if( !UNIVERSAL::isa( $object, $class ) ) { - my $ref = ref $object; - $diag = "$obj_name isn't a '$class' it's a '$ref'"; - } - } - elsif( $error =~ /Can't call method "isa" without a package/ ) { - # It's something that can't even be a class - $diag = "$obj_name isn't a class or reference"; - } - else { - die <isa on your $whatami and got some weird error. -Here's the error. -$error -WHOA - } - } - else { - $obj_name = "The $whatami" unless defined $obj_name; - if( !$rslt ) { - my $ref = ref $object; - $diag = "$obj_name isn't a '$class' it's a '$ref'"; - } - } - } - - my $name = "$obj_name isa $class"; - my $ok; - if($diag) { - $ok = $tb->ok( 0, $name ); - $tb->diag(" $diag\n"); - } - else { - $ok = $tb->ok( 1, $name ); - } - - return $ok; -} - -#line 650 - -sub new_ok { - my $tb = Test::More->builder; - $tb->croak("new_ok() must be given at least a class") unless @_; - - my( $class, $args, $object_name ) = @_; - - $args ||= []; - $object_name = "The object" unless defined $object_name; - - my $obj; - my( $success, $error ) = $tb->_try( sub { $obj = $class->new(@$args); 1 } ); - if($success) { - local $Test::Builder::Level = $Test::Builder::Level + 1; - isa_ok $obj, $class, $object_name; - } - else { - $tb->ok( 0, "new() died" ); - $tb->diag(" Error was: $error"); - } - - return $obj; -} - -#line 690 - -sub pass (;$) { - my $tb = Test::More->builder; - - return $tb->ok( 1, @_ ); -} - -sub fail (;$) { - my $tb = Test::More->builder; - - return $tb->ok( 0, @_ ); -} - -#line 753 - -sub use_ok ($;@) { - my( $module, @imports ) = @_; - @imports = () unless @imports; - my $tb = Test::More->builder; - - my( $pack, $filename, $line ) = caller; - - my $code; - if( @imports == 1 and $imports[0] =~ /^\d+(?:\.\d+)?$/ ) { - # probably a version check. Perl needs to see the bare number - # for it to work with non-Exporter based modules. - $code = <ok( $eval_result, "use $module;" ); - - unless($ok) { - chomp $eval_error; - $@ =~ s{^BEGIN failed--compilation aborted at .*$} - {BEGIN failed--compilation aborted at $filename line $line.}m; - $tb->diag(<builder; - - my $pack = caller; - - # Try to deterine if we've been given a module name or file. - # Module names must be barewords, files not. - $module = qq['$module'] unless _is_module_name($module); - - my $code = <ok( $eval_result, "require $module;" ); - - unless($ok) { - chomp $eval_error; - $tb->diag(<builder; - - unless( @_ == 2 or @_ == 3 ) { - my $msg = <<'WARNING'; -is_deeply() takes two or three args, you gave %d. -This usually means you passed an array or hash instead -of a reference to it -WARNING - chop $msg; # clip off newline so carp() will put in line/file - - _carp sprintf $msg, scalar @_; - - return $tb->ok(0); - } - - my( $got, $expected, $name ) = @_; - - $tb->_unoverload_str( \$expected, \$got ); - - my $ok; - if( !ref $got and !ref $expected ) { # neither is a reference - $ok = $tb->is_eq( $got, $expected, $name ); - } - elsif( !ref $got xor !ref $expected ) { # one's a reference, one isn't - $ok = $tb->ok( 0, $name ); - $tb->diag( _format_stack({ vals => [ $got, $expected ] }) ); - } - else { # both references - local @Data_Stack = (); - if( _deep_check( $got, $expected ) ) { - $ok = $tb->ok( 1, $name ); - } - else { - $ok = $tb->ok( 0, $name ); - $tb->diag( _format_stack(@Data_Stack) ); - } - } - - return $ok; -} - -sub _format_stack { - my(@Stack) = @_; - - my $var = '$FOO'; - my $did_arrow = 0; - foreach my $entry (@Stack) { - my $type = $entry->{type} || ''; - my $idx = $entry->{'idx'}; - if( $type eq 'HASH' ) { - $var .= "->" unless $did_arrow++; - $var .= "{$idx}"; - } - elsif( $type eq 'ARRAY' ) { - $var .= "->" unless $did_arrow++; - $var .= "[$idx]"; - } - elsif( $type eq 'REF' ) { - $var = "\${$var}"; - } - } - - my @vals = @{ $Stack[-1]{vals} }[ 0, 1 ]; - my @vars = (); - ( $vars[0] = $var ) =~ s/\$FOO/ \$got/; - ( $vars[1] = $var ) =~ s/\$FOO/\$expected/; - - my $out = "Structures begin differing at:\n"; - foreach my $idx ( 0 .. $#vals ) { - my $val = $vals[$idx]; - $vals[$idx] - = !defined $val ? 'undef' - : _dne($val) ? "Does not exist" - : ref $val ? "$val" - : "'$val'"; - } - - $out .= "$vars[0] = $vals[0]\n"; - $out .= "$vars[1] = $vals[1]\n"; - - $out =~ s/^/ /msg; - return $out; -} - -sub _type { - my $thing = shift; - - return '' if !ref $thing; - - for my $type (qw(ARRAY HASH REF SCALAR GLOB CODE Regexp)) { - return $type if UNIVERSAL::isa( $thing, $type ); - } - - return ''; -} - -#line 1059 - -sub diag { - return Test::More->builder->diag(@_); -} - -sub note { - return Test::More->builder->note(@_); -} - -#line 1085 - -sub explain { - return Test::More->builder->explain(@_); -} - -#line 1151 - -## no critic (Subroutines::RequireFinalReturn) -sub skip { - my( $why, $how_many ) = @_; - my $tb = Test::More->builder; - - unless( defined $how_many ) { - # $how_many can only be avoided when no_plan is in use. - _carp "skip() needs to know \$how_many tests are in the block" - unless $tb->has_plan eq 'no_plan'; - $how_many = 1; - } - - if( defined $how_many and $how_many =~ /\D/ ) { - _carp - "skip() was passed a non-numeric number of tests. Did you get the arguments backwards?"; - $how_many = 1; - } - - for( 1 .. $how_many ) { - $tb->skip($why); - } - - no warnings 'exiting'; - last SKIP; -} - -#line 1238 - -sub todo_skip { - my( $why, $how_many ) = @_; - my $tb = Test::More->builder; - - unless( defined $how_many ) { - # $how_many can only be avoided when no_plan is in use. - _carp "todo_skip() needs to know \$how_many tests are in the block" - unless $tb->has_plan eq 'no_plan'; - $how_many = 1; - } - - for( 1 .. $how_many ) { - $tb->todo_skip($why); - } - - no warnings 'exiting'; - last TODO; -} - -#line 1293 - -sub BAIL_OUT { - my $reason = shift; - my $tb = Test::More->builder; - - $tb->BAIL_OUT($reason); -} - -#line 1332 - -#'# -sub eq_array { - local @Data_Stack = (); - _deep_check(@_); -} - -sub _eq_array { - my( $a1, $a2 ) = @_; - - if( grep _type($_) ne 'ARRAY', $a1, $a2 ) { - warn "eq_array passed a non-array ref"; - return 0; - } - - return 1 if $a1 eq $a2; - - my $ok = 1; - my $max = $#$a1 > $#$a2 ? $#$a1 : $#$a2; - for( 0 .. $max ) { - my $e1 = $_ > $#$a1 ? $DNE : $a1->[$_]; - my $e2 = $_ > $#$a2 ? $DNE : $a2->[$_]; - - push @Data_Stack, { type => 'ARRAY', idx => $_, vals => [ $e1, $e2 ] }; - $ok = _deep_check( $e1, $e2 ); - pop @Data_Stack if $ok; - - last unless $ok; - } - - return $ok; -} - -sub _deep_check { - my( $e1, $e2 ) = @_; - my $tb = Test::More->builder; - - my $ok = 0; - - # Effectively turn %Refs_Seen into a stack. This avoids picking up - # the same referenced used twice (such as [\$a, \$a]) to be considered - # circular. - local %Refs_Seen = %Refs_Seen; - - { - # Quiet uninitialized value warnings when comparing undefs. - no warnings 'uninitialized'; - - $tb->_unoverload_str( \$e1, \$e2 ); - - # Either they're both references or both not. - my $same_ref = !( !ref $e1 xor !ref $e2 ); - my $not_ref = ( !ref $e1 and !ref $e2 ); - - if( defined $e1 xor defined $e2 ) { - $ok = 0; - } - elsif( !defined $e1 and !defined $e2 ) { - # Shortcut if they're both defined. - $ok = 1; - } - elsif( _dne($e1) xor _dne($e2) ) { - $ok = 0; - } - elsif( $same_ref and( $e1 eq $e2 ) ) { - $ok = 1; - } - elsif($not_ref) { - push @Data_Stack, { type => '', vals => [ $e1, $e2 ] }; - $ok = 0; - } - else { - if( $Refs_Seen{$e1} ) { - return $Refs_Seen{$e1} eq $e2; - } - else { - $Refs_Seen{$e1} = "$e2"; - } - - my $type = _type($e1); - $type = 'DIFFERENT' unless _type($e2) eq $type; - - if( $type eq 'DIFFERENT' ) { - push @Data_Stack, { type => $type, vals => [ $e1, $e2 ] }; - $ok = 0; - } - elsif( $type eq 'ARRAY' ) { - $ok = _eq_array( $e1, $e2 ); - } - elsif( $type eq 'HASH' ) { - $ok = _eq_hash( $e1, $e2 ); - } - elsif( $type eq 'REF' ) { - push @Data_Stack, { type => $type, vals => [ $e1, $e2 ] }; - $ok = _deep_check( $$e1, $$e2 ); - pop @Data_Stack if $ok; - } - elsif( $type eq 'SCALAR' ) { - push @Data_Stack, { type => 'REF', vals => [ $e1, $e2 ] }; - $ok = _deep_check( $$e1, $$e2 ); - pop @Data_Stack if $ok; - } - elsif($type) { - push @Data_Stack, { type => $type, vals => [ $e1, $e2 ] }; - $ok = 0; - } - else { - _whoa( 1, "No type in _deep_check" ); - } - } - } - - return $ok; -} - -sub _whoa { - my( $check, $desc ) = @_; - if($check) { - die <<"WHOA"; -WHOA! $desc -This should never happen! Please contact the author immediately! -WHOA - } -} - -#line 1465 - -sub eq_hash { - local @Data_Stack = (); - return _deep_check(@_); -} - -sub _eq_hash { - my( $a1, $a2 ) = @_; - - if( grep _type($_) ne 'HASH', $a1, $a2 ) { - warn "eq_hash passed a non-hash ref"; - return 0; - } - - return 1 if $a1 eq $a2; - - my $ok = 1; - my $bigger = keys %$a1 > keys %$a2 ? $a1 : $a2; - foreach my $k ( keys %$bigger ) { - my $e1 = exists $a1->{$k} ? $a1->{$k} : $DNE; - my $e2 = exists $a2->{$k} ? $a2->{$k} : $DNE; - - push @Data_Stack, { type => 'HASH', idx => $k, vals => [ $e1, $e2 ] }; - $ok = _deep_check( $e1, $e2 ); - pop @Data_Stack if $ok; - - last unless $ok; - } - - return $ok; -} - -#line 1522 - -sub eq_set { - my( $a1, $a2 ) = @_; - return 0 unless @$a1 == @$a2; - - no warnings 'uninitialized'; - - # It really doesn't matter how we sort them, as long as both arrays are - # sorted with the same algorithm. - # - # Ensure that references are not accidentally treated the same as a - # string containing the reference. - # - # Have to inline the sort routine due to a threading/sort bug. - # See [rt.cpan.org 6782] - # - # I don't know how references would be sorted so we just don't sort - # them. This means eq_set doesn't really work with refs. - return eq_array( - [ grep( ref, @$a1 ), sort( grep( !ref, @$a1 ) ) ], - [ grep( ref, @$a2 ), sort( grep( !ref, @$a2 ) ) ], - ); -} - -#line 1735 - -1; diff --git a/debian/modules/http-subs-filter/test/lib/Test/Nginx.pm b/debian/modules/http-subs-filter/test/lib/Test/Nginx.pm deleted file mode 100644 index 0a1408e..0000000 --- a/debian/modules/http-subs-filter/test/lib/Test/Nginx.pm +++ /dev/null @@ -1,315 +0,0 @@ -package Test::Nginx; - -use strict; -use warnings; - -our $VERSION = '0.17'; - -__END__ - -=encoding utf-8 - -=head1 NAME - -Test::Nginx - Testing modules for Nginx C module development - -=head1 DESCRIPTION - -This distribution provides two testing modules for Nginx C module development: - -=over - -=item * - -L - -=item * - -L - -=back - -All of them are based on L. - -Usually, L is preferred because it works on a much lower -level and not that fault tolerant like L. - -Also, a lot of connection hang issues (like wrong C<< r->main->count >> value in nginx -0.8.x) can only be captured by L because Perl's L client -will close the connection itself which will conceal such issues from -the testers. - -Test::Nginx automatically starts an nginx instance (from the C env) -rooted at t/servroot/ and the default config template makes this nginx -instance listen on the port C<1984> by default. One can specify a different -port number by setting his port number to the C environment, -as in - - export TEST_NGINX_PORT=1989 - -=head2 etcproxy integration - -The default settings in etcproxy (https://github.com/chaoslawful/etcproxy) -makes this small TCP proxy split the TCP packets into bytes and introduce 1 ms latency among them. - -There's usually various TCP chains that we can put etcproxy into, for example - -=head3 Test::Nginx <=> nginx - - $ ./etcproxy 1234 1984 - -Here we tell etcproxy to listen on port 1234 and to delegate all the -TCP traffic to the port 1984, the default port that Test::Nginx makes -nginx listen to. - -And then we tell Test::Nginx to test against the port 1234, where -etcproxy listens on, rather than the port 1984 that nginx directly -listens on: - - $ TEST_NGINX_CLIENT_PORT=1234 prove -r t/ - -Then the TCP chain now looks like this: - - Test::Nginx <=> etcproxy (1234) <=> nginx (1984) - -So etcproxy can effectively emulate extreme network conditions and -exercise "unusual" code paths in your nginx server by your tests. - -In practice, *tons* of weird bugs can be captured by this setting. -Even ourselves didn't expect that this simple approach is so -effective. - -=head3 nginx <=> memcached - -We first start the memcached server daemon on port 11211: - - memcached -p 11211 -vv - -and then we another etcproxy instance to listen on port 11984 like this - - $ ./etcproxy 11984 11211 - -Then we tell our t/foo.t test script to connect to 11984 rather than 11211: - - # foo.t - use Test::Nginx::Socket; - repeat_each(1); - plan tests => 2 * repeat_each() * blocks(); - $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; # make this env take a default value - run_tests(); - - __DATA__ - - === TEST 1: sanity - --- config - location /foo { - set $memc_cmd set; - set $memc_key foo; - set $memc_value bar; - memc_pass 127.0.0.1:$TEST_NGINX_MEMCACHED_PORT; - } - --- request - GET /foo - --- response_body_like: STORED - -The Test::Nginx library will automatically expand the special macro -C<$TEST_NGINX_MEMCACHED_PORT> to the environment with the same name. -You can define your own C<$TEST_NGINX_BLAH_BLAH_PORT> macros as long as -its prefix is C and all in upper case letters. - -And now we can run your test script against the etcproxy port 11984: - - TEST_NGINX_MEMCACHED_PORT=11984 prove t/foo.t - -Then the TCP chains look like this: - - Test::Nginx <=> nginx (1984) <=> etcproxy (11984) <=> memcached (11211) - -If C is not set, then it will take the default -value 11211, which is what we want when there's no etcproxy -configured: - - Test::Nginx <=> nginx (1984) <=> memcached (11211) - -This approach also works for proxied mysql and postgres traffic. -Please see the live test suite of ngx_drizzle and ngx_postgres for -more details. - -Usually we set both C and -C (and etc) at the same time, effectively -yielding the following chain: - - Test::Nginx <=> etcproxy (1234) <=> nginx (1984) <=> etcproxy (11984) <=> memcached (11211) - -as long as you run two separate etcproxy instances in two separate terminals. - -It's easy to verify if the traffic actually goes through your etcproxy -server. Just check if the terminal running etcproxy emits outputs. By -default, etcproxy always dump out the incoming and outgoing data to -stdout/stderr. - -=head2 valgrind integration - -Test::Nginx has integrated support for valgrind (L) even though by -default it does not bother running it with the tests because valgrind -will significantly slow down the test sutie. - -First ensure that your valgrind executable visible in your PATH env. -And then run your test suite with the C env set -to true: - - TEST_NGINX_USE_VALGRIND=1 prove -r t - -If you see false alarms, you do have a chance to skip them by defining -a ./valgrind.suppress file at the root of your module source tree, as -in - -L - -This is the suppression file for ngx_drizzle. Test::Nginx will -automatically use it to start nginx with valgrind memcheck if this -file does exist at the expected location. - -If you do see a lot of "Connection refused" errors while running the -tests this way, then you probably have a slow machine (or a very busy -one) that the default waiting time is not sufficient for valgrind to -start. You can define the sleep time to a larger value by setting the -C env: - - TEST_NGINX_SLEEP=1 prove -r t - -The time unit used here is "second". The default sleep setting just -fits my ThinkPad (C). - -Applying the no-pool patch to your nginx core is recommended while -running nginx with valgrind: - -L - -The nginx memory pool can prevent valgrind from spotting lots of -invalid memory reads/writes as well as certain double-free errors. We -did find a lot more memory issues in many of our modules when we first -introduced the no-pool patch in practice ;) - -There's also more advanced features in Test::Nginx that have never -documented. I'd like to write more about them in the near future ;) - - -=head1 Nginx C modules that use Test::Nginx to drive their test suites - -=over - -=item ngx_echo - -L - -=item ngx_headers_more - -L - -=item ngx_chunkin - -L - -=item ngx_memc - -L - -=item ngx_drizzle - -L - -=item ngx_rds_json - -L - -=item ngx_xss - -L - -=item ngx_srcache - -L - -=item ngx_lua - -L - -=item ngx_set_misc - -L - -=item ngx_array_var - -L - -=item ngx_form_input - -L - -=item ngx_iconv - -L - -=item ngx_set_cconv - -L - -=item ngx_postgres - -L - -=item ngx_coolkit - -L - -=back - -=head1 SOURCE REPOSITORY - -This module has a Git repository on Github, which has access for all. - - http://github.com/agentzh/test-nginx - -If you want a commit bit, feel free to drop me a line. - -=head1 AUTHORS - -agentzh (章亦春) C<< >> - -Antoine BONAVITA C<< >> - -=head1 COPYRIGHT & LICENSE - -Copyright (c) 2009-2011, Taobao Inc., Alibaba Group (L). - -Copyright (c) 2009-2011, agentzh C<< >>. - -Copyright (c) 2011, Antoine Bonavita C<< >>. - -This module is licensed under the terms of the BSD license. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - -=over - -=item * - -Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - -=item * - -Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - -=item * - -Neither the name of the Taobao Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - -=back - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=head1 SEE ALSO - -L, L, L. - diff --git a/debian/modules/http-subs-filter/test/lib/Test/Nginx/LWP.pm b/debian/modules/http-subs-filter/test/lib/Test/Nginx/LWP.pm deleted file mode 100644 index 53f6c85..0000000 --- a/debian/modules/http-subs-filter/test/lib/Test/Nginx/LWP.pm +++ /dev/null @@ -1,524 +0,0 @@ -package Test::Nginx::LWP; - -use lib 'lib'; -use lib 'inc'; -use Test::Base -Base; - -our $VERSION = '0.17'; - -our $NoLongString; - -use LWP::UserAgent; -use Time::HiRes qw(sleep); -use Test::LongString; -use Test::Nginx::Util qw( - setup_server_root - write_config_file - get_canon_version - get_nginx_version - trim - show_all_chars - parse_headers - run_tests - $ServerPortForClient - $PidFile - $ServRoot - $ConfFile - $ServerPort - $RunTestHelper - $NoNginxManager - $RepeatEach - worker_connections - master_process_enabled - config_preamble - repeat_each - no_shuffle - no_root_location -); - -our $UserAgent = LWP::UserAgent->new; -$UserAgent->agent(__PACKAGE__); -#$UserAgent->default_headers(HTTP::Headers->new); - -#use Smart::Comments::JSON '##'; - -our @EXPORT = qw( plan run_tests run_test - repeat_each config_preamble worker_connections - master_process_enabled - no_long_string no_shuffle no_root_location); - -sub no_long_string () { - $NoLongString = 1; -} - -sub run_test_helper ($$); - -$RunTestHelper = \&run_test_helper; - -sub parse_request ($$) { - my ($name, $rrequest) = @_; - open my $in, '<', $rrequest; - my $first = <$in>; - if (!$first) { - Test::More::BAIL_OUT("$name - Request line should be non-empty"); - die; - } - $first =~ s/^\s+|\s+$//g; - my ($meth, $rel_url) = split /\s+/, $first, 2; - my $url = "http://localhost:$ServerPortForClient" . $rel_url; - - my $content = do { local $/; <$in> }; - if ($content) { - $content =~ s/^\s+|\s+$//s; - } - - close $in; - - return { - method => $meth, - url => $url, - content => $content, - }; -} - -sub chunk_it ($$$) { - my ($chunks, $start_delay, $middle_delay) = @_; - my $i = 0; - return sub { - if ($i == 0) { - if ($start_delay) { - sleep($start_delay); - } - } elsif ($middle_delay) { - sleep($middle_delay); - } - return $chunks->[$i++]; - } -} - -sub run_test_helper ($$) { - my ($block, $dry_run) = @_; - - my $request = $block->request; - - my $name = $block->name; - #if (defined $TODO) { - #$name .= "# $TODO"; - #} - - my $req_spec = parse_request($name, \$request); - ## $req_spec - my $method = $req_spec->{method}; - my $req = HTTP::Request->new($method); - my $content = $req_spec->{content}; - - if (defined ($block->request_headers)) { - my $headers = parse_headers($block->request_headers); - while (my ($key, $val) = each %$headers) { - $req->header($key => $val); - } - } - - #$req->header('Accept', '*/*'); - $req->url($req_spec->{url}); - if ($content) { - if ($method eq 'GET' or $method eq 'HEAD') { - croak "HTTP 1.0/1.1 $method request should not have content: $content"; - } - $req->content($content); - } elsif ($method eq 'POST' or $method eq 'PUT') { - my $chunks = $block->chunked_body; - if (defined $chunks) { - if (!ref $chunks or ref $chunks ne 'ARRAY') { - - Test::More::BAIL_OUT("$name - --- chunked_body should takes a Perl array ref as its value"); - } - - my $start_delay = $block->start_chunk_delay || 0; - my $middle_delay = $block->middle_chunk_delay || 0; - $req->content(chunk_it($chunks, $start_delay, $middle_delay)); - if (!defined $req->header('Content-Type')) { - $req->header('Content-Type' => 'text/plain'); - } - } else { - if (!defined $req->header('Content-Type')) { - $req->header('Content-Type' => 'text/plain'); - } - - $req->header('Content-Length' => 0); - } - } - - if ($block->more_headers) { - my @headers = split /\n+/, $block->more_headers; - for my $header (@headers) { - next if $header =~ /^\s*\#/; - my ($key, $val) = split /:\s*/, $header, 2; - #warn "[$key, $val]\n"; - $req->header($key => $val); - } - } - - #warn "req: ", $req->as_string, "\n"; - #warn "DONE!!!!!!!!!!!!!!!!!!!!"; - - my $res = HTTP::Response->new; - unless ($dry_run) { - $res = $UserAgent->request($req); - } - - #warn "res returned!!!"; - - if ($dry_run) { - SKIP: { - Test::More::skip("$name - tests skipped due to the lack of directive $dry_run", 1); - } - } else { - if (defined $block->error_code) { - is($res->code, $block->error_code, "$name - status code ok"); - } else { - is($res->code, 200, "$name - status code ok"); - } - } - - if (defined $block->response_headers) { - my $headers = parse_headers($block->response_headers); - while (my ($key, $val) = each %$headers) { - my $expected_val = $res->header($key); - if (!defined $expected_val) { - $expected_val = ''; - } - if ($dry_run) { - SKIP: { - Test::More::skip("$name - tests skipped due to the lack of directive $dry_run", 1); - } - } else { - is $expected_val, $val, - "$name - header $key ok"; - } - } - } elsif (defined $block->response_headers_like) { - my $headers = parse_headers($block->response_headers_like); - while (my ($key, $val) = each %$headers) { - my $expected_val = $res->header($key); - if (!defined $expected_val) { - $expected_val = ''; - } - if ($dry_run) { - SKIP: { - Test::More::skip("$name - tests skipped due to the lack of directive $dry_run", 1); - } - } else { - like $expected_val, qr/^$val$/, - "$name - header $key like ok"; - } - } - } - - if (defined $block->response_body) { - my $content = $res->content; - if (defined $content) { - $content =~ s/^TE: deflate,gzip;q=0\.3\r\n//gms; - } - - $content =~ s/^Connection: TE, close\r\n//gms; - my $expected = $block->response_body; - $expected =~ s/\$ServerPort\b/$ServerPort/g; - $expected =~ s/\$ServerPortForClient\b/$ServerPortForClient/g; - #warn show_all_chars($content); - - if ($dry_run) { - SKIP: { - Test::More::skip("$name - tests skipped due to the lack of directive $dry_run", 1); - } - } else { - if ($NoLongString) { - is($content, $expected, "$name - response_body - response is expected"); - } else { - is_string($content, $expected, "$name - response_body - response is expected"); - } - #is($content, $expected, "$name - response_body - response is expected"); - } - - } elsif (defined $block->response_body_like) { - my $content = $res->content; - if (defined $content) { - $content =~ s/^TE: deflate,gzip;q=0\.3\r\n//gms; - } - $content =~ s/^Connection: TE, close\r\n//gms; - my $expected_pat = $block->response_body_like; - $expected_pat =~ s/\$ServerPort\b/$ServerPort/g; - $expected_pat =~ s/\$ServerPortForClient\b/$ServerPortForClient/g; - my $summary = trim($content); - - if ($dry_run) { - SKIP: { - Test::More::skip("$name - tests skipped due to the lack of directive $dry_run", 1); - } - } else { - like($content, qr/$expected_pat/s, "$name - response_body_like - response is expected ($summary)"); - } - } elsif (defined $block->response_body_unlike) { - my $content = $res->content; - if (defined $content) { - $content =~ s/^TE: deflate,gzip;q=0\.3\r\n//gms; - } - $content =~ s/^Connection: TE, close\r\n//gms; - my $expected_pat = $block->response_body_unlike; - $expected_pat =~ s/\$ServerPort\b/$ServerPort/g; - $expected_pat =~ s/\$ServerPortForClient\b/$ServerPortForClient/g; - my $summary = trim($content); - - if ($dry_run) { - SKIP: { - Test::More::skip("$name - tests skipped due to the lack of directive $dry_run", 1); - } - } else { - unlike($content, qr/$expected_pat/s, "$name - response_body_like - response is expected ($summary)"); - } - } -} - -1; -__END__ - -=encoding utf-8 - -=head1 NAME - -Test::Nginx::LWP - LWP-backed test scaffold for the Nginx C modules - -=head1 SYNOPSIS - - use Test::Nginx::LWP; - - plan tests => $Test::Nginx::LWP::RepeatEach * 2 * blocks(); - - run_tests(); - - __DATA__ - - === TEST 1: sanity - --- config - location /echo { - echo_before_body hello; - echo world; - } - --- request - GET /echo - --- response_body - hello - world - --- error_code: 200 - - - === TEST 2: set Server - --- config - location /foo { - echo hi; - more_set_headers 'Server: Foo'; - } - --- request - GET /foo - --- response_headers - Server: Foo - --- response_body - hi - - - === TEST 3: clear Server - --- config - location /foo { - echo hi; - more_clear_headers 'Server: '; - } - --- request - GET /foo - --- response_headers_like - Server: nginx.* - --- response_body - hi - - - === TEST 4: set request header at client side and rewrite it - --- config - location /foo { - more_set_input_headers 'X-Foo: howdy'; - echo $http_x_foo; - } - --- request - GET /foo - --- request_headers - X-Foo: blah - --- response_headers - X-Foo: - --- response_body - howdy - - - === TEST 3: rewrite content length - --- config - location /bar { - more_set_input_headers 'Content-Length: 2048'; - echo_read_request_body; - echo_request_body; - } - --- request eval - "POST /bar\n" . - "a" x 4096 - --- response_body eval - "a" x 2048 - - - === TEST 4: timer without explicit reset - --- config - location /timer { - echo_sleep 0.03; - echo "elapsed $echo_timer_elapsed sec."; - } - --- request - GET /timer - --- response_body_like - ^elapsed 0\.0(2[6-9]|3[0-6]) sec\.$ - - - === TEST 5: small buf (using 2-byte buf) - --- config - chunkin on; - location /main { - client_body_buffer_size 2; - echo "body:"; - echo $echo_request_body; - echo_request_body; - } - --- request - POST /main - --- start_chunk_delay: 0.01 - --- middle_chunk_delay: 0.01 - --- chunked_body eval - ["hello", "world"] - --- error_code: 200 - --- response_body eval - "body: - - helloworld" - -=head1 DESCRIPTION - -This module provides a test scaffold based on L for automated testing in Nginx C module development. - -This class inherits from L, thus bringing all its -declarative power to the Nginx C module testing practices. - -You need to terminate or kill any Nginx processes before running the test suite if you have changed the Nginx server binary. Normally it's as simple as - - killall nginx - PATH=/path/to/your/nginx-with-memc-module:$PATH prove -r t - -This module will create a temporary server root under t/servroot/ of the current working directory and starts and uses the nginx executable in the PATH environment. - -You will often want to look into F -when things go wrong ;) - -=head1 Sections supported - -The following sections are supported: - -=over - -=item config - -=item http_config - -=item request - -=item request_headers - -=item more_headers - -=item response_body - -=item response_body_like - -=item response_headers - -=item response_headers_like - -=item error_code - -=item chunked_body - -=item middle_chunk_delay - -=item start_chunk_delay - -=back - -=head1 Samples - -You'll find live samples in the following Nginx 3rd-party modules: - -=over - -=item ngx_echo - -L - -=item ngx_headers_more - -L - -=item ngx_chunkin - -L - -=item ngx_memc - -L - -=back - -=head1 SOURCE REPOSITORY - -This module has a Git repository on Github, which has access for all. - - http://github.com/agentzh/test-nginx - -If you want a commit bit, feel free to drop me a line. - -=head1 AUTHOR - -agentzh (章亦春) C<< >> - -=head1 COPYRIGHT & LICENSE - -Copyright (c) 2009-2011, Taobao Inc., Alibaba Group (L). - -Copyright (c) 2009-2011, agentzh C<< >>. - -This module is licensed under the terms of the BSD license. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - -=over - -=item * - -Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - -=item * - -Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - -=item * - -Neither the name of the Taobao Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - -=back - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=head1 SEE ALSO - -L, L. - diff --git a/debian/modules/http-subs-filter/test/lib/Test/Nginx/Socket.pm b/debian/modules/http-subs-filter/test/lib/Test/Nginx/Socket.pm deleted file mode 100644 index 833c00a..0000000 --- a/debian/modules/http-subs-filter/test/lib/Test/Nginx/Socket.pm +++ /dev/null @@ -1,1749 +0,0 @@ -package Test::Nginx::Socket; - -use lib 'lib'; -use lib 'inc'; - -use Test::Base -Base; - -our $VERSION = '0.17'; - -use Encode; -use Data::Dumper; -use Time::HiRes qw(sleep time); -use Test::LongString; -use List::MoreUtils qw( any ); -use IO::Select (); - -our $ServerAddr = 'localhost'; -our $Timeout = $ENV{TEST_NGINX_TIMEOUT} || 2; - -use Test::Nginx::Util qw( - setup_server_root - write_config_file - get_canon_version - get_nginx_version - trim - show_all_chars - parse_headers - run_tests - $ServerPortForClient - $ServerPort - $PidFile - $ServRoot - $ConfFile - $RunTestHelper - $RepeatEach - worker_connections - master_process_enabled - config_preamble - repeat_each - workers - master_on - log_level - no_shuffle - no_root_location - server_root - html_dir - server_port - no_nginx_manager -); - -#use Smart::Comments::JSON '###'; -use Fcntl qw(F_GETFL F_SETFL O_NONBLOCK); -use POSIX qw(EAGAIN); -use IO::Socket; - -#our ($PrevRequest, $PrevConfig); - -our $NoLongString = undef; - -our @EXPORT = qw( plan run_tests run_test - repeat_each config_preamble worker_connections - master_process_enabled - no_long_string workers master_on - log_level no_shuffle no_root_location - server_addr server_root html_dir server_port - timeout no_nginx_manager -); - -sub send_request ($$$$@); - -sub run_test_helper ($$); - -sub error_event_handler ($); -sub read_event_handler ($); -sub write_event_handler ($); - -sub no_long_string () { - $NoLongString = 1; -} - -sub server_addr (@) { - if (@_) { - - #warn "setting server addr to $_[0]\n"; - $ServerAddr = shift; - } - else { - return $ServerAddr; - } -} - -sub timeout (@) { - if (@_) { - $Timeout = shift; - } - else { - $Timeout; - } -} - -$RunTestHelper = \&run_test_helper; - -# This will parse a "request"" string. The expected format is: -# - One line for the HTTP verb (POST, GET, etc.) plus optional relative URL -# (default is /) plus optional HTTP version (default is HTTP/1.1). -# - More lines considered as the body of the request. -# Most people don't care about headers and this is enough. -# -# This function will return a reference to a hash with the parsed elements -# plus information on the parsing itself like "how many white spaces were -# skipped before the VERB" (skipped_before_method), "was the version provided" -# (http_ver_size = 0). -sub parse_request ($$) { - my ( $name, $rrequest ) = @_; - open my $in, '<', $rrequest; - my $first = <$in>; - if ( !$first ) { - Test::More::BAIL_OUT("$name - Request line should be non-empty"); - die; - } - #$first =~ s/^\s+|\s+$//gs; - my ($before_meth, $meth, $after_meth); - my ($rel_url, $rel_url_size, $after_rel_url); - my ($http_ver, $http_ver_size, $after_http_ver); - my $end_line_size; - if ($first =~ /^(\s*)(\S+)( *)((\S+)( *))?((\S+)( *))?(\s*)/) { - $before_meth = defined $1 ? length($1) : undef; - $meth = $2; - $after_meth = defined $3 ? length($3) : undef; - $rel_url = $5; - $rel_url_size = defined $5 ? length($5) : undef; - $after_rel_url = defined $6 ? length($6) : undef; - $http_ver = $8; - if (!defined $8) { - $http_ver_size = undef; - } else { - $http_ver_size = defined $8 ? length($8) : undef; - } - if (!defined $9) { - $after_http_ver = undef; - } else { - $after_http_ver = defined $9 ? length($9) : undef; - } - $end_line_size = defined $10 ? length($10) : undef; - } else { - Test::More::BAIL_OUT("$name - Request line is not valid. Should be 'meth [url [version]]'"); - die; - } - if ( !defined $rel_url ) { - $rel_url = '/'; - $rel_url_size = 0; - $after_rel_url = 0; - } - if ( !defined $http_ver ) { - $http_ver = 'HTTP/1.1'; - $http_ver_size = 0; - $after_http_ver = 0; - } - - #my $url = "http://localhost:$ServerPortForClient" . $rel_url; - - my $content = do { local $/; <$in> }; - my $content_size; - if ( !defined $content ) { - $content = ""; - $content_size = 0; - } else { - $content_size = length($content); - } - - #warn Dumper($content); - - close $in; - - return { - method => $meth, - url => $rel_url, - content => $content, - http_ver => $http_ver, - skipped_before_method => $before_meth, - method_size => length($meth), - skipped_after_method => $after_meth, - url_size => $rel_url_size, - skipped_after_url => $after_rel_url, - http_ver_size => $http_ver_size, - skipped_after_http_ver => $after_http_ver + $end_line_size, - content_size => $content_size, - }; -} - -# From a parsed request, builds the "moves" to apply to the original request -# to transform it (e.g. add missing version). Elements of the returned array -# are of 2 types: -# - d : number of characters to remove. -# - s_* : number of characters (s_s) to replace by value (s_v). -sub get_moves($) { - my ($parsed_req) = @_; - return ({d => $parsed_req->{skipped_before_method}}, - {s_s => $parsed_req->{method_size}, - s_v => $parsed_req->{method}}, - {d => $parsed_req->{skipped_after_method}}, - {s_s => $parsed_req->{url_size}, - s_v => $parsed_req->{url}}, - {d => $parsed_req->{skipped_after_url}}, - {s_s => $parsed_req->{http_ver_size}, - s_v => $parsed_req->{http_ver}}, - {d => $parsed_req->{skipped_after_http_ver}}, - {s_s => 0, - s_v => $parsed_req->{headers}}, - {s_s => $parsed_req->{content_size}, - s_v => $parsed_req->{content}} - ); -} - -# Apply moves (see above) to an array of packets that correspond to a request. -# The use of this function is explained in the build_request_from_packets -# function. -sub apply_moves($$) { - my ($r_packet, $r_move) = @_; - my $current_packet = shift @$r_packet; - my $current_move = shift @$r_move; - my $in_packet_cursor = 0; - my @result = (); - while (defined $current_packet) { - if (!defined $current_move) { - push @result, $current_packet; - $current_packet = shift @$r_packet; - $in_packet_cursor = 0; - } elsif (defined $current_move->{d}) { - # Remove stuff from packet - if ($current_move->{d} > length($current_packet) - $in_packet_cursor) { - # Eat up what is left of packet. - $current_move->{d} -= length($current_packet) - $in_packet_cursor; - if ($in_packet_cursor > 0) { - # Something in packet from previous iteration. - push @result, $current_packet; - } - $current_packet = shift @$r_packet; - $in_packet_cursor = 0; - } else { - # Remove from current point in current packet - substr($current_packet, $in_packet_cursor, $current_move->{d}) = ''; - $current_move = shift @$r_move; - } - } else { - # Substitute stuff - if ($current_move->{s_s} > length($current_packet) - $in_packet_cursor) { - # {s_s=>3, s_v=>GET} on ['GE', 'T /foo'] - $current_move->{s_s} -= length($current_packet) - $in_packet_cursor; - substr($current_packet, $in_packet_cursor) = substr($current_move->{s_v}, 0, length($current_packet) - $in_packet_cursor); - push @result, $current_packet; - $current_move->{s_v} = substr($current_move->{s_v}, length($current_packet) - $in_packet_cursor); - $current_packet = shift @$r_packet; - $in_packet_cursor = 0; - } else { - substr($current_packet, $in_packet_cursor, $current_move->{s_s}) = $current_move->{s_v}; - $in_packet_cursor += length($current_move->{s_v}); - $current_move = shift @$r_move; - } - } - } - return \@result; -} -# Given a request as an array of packets, will parse it, append the appropriate -# headers and return another array of packets. -# The function implemented here can be high-level summarized as: -# 1 - Concatenate all packets to obtain a string representation of request. -# 2 - Parse the string representation -# 3 - Get the "moves" from the parsing -# 4 - Apply the "moves" to the packets. -sub build_request_from_packets($$$$$) { - my ( $name, $more_headers, $is_chunked, $conn_header, $request_packets ) = @_; - # Concatenate packets as a string - my $parsable_request = ''; - my @packet_length; - for my $one_packet (@$request_packets) { - $parsable_request .= $one_packet; - push @packet_length, length($one_packet); - } - # Parse the string representation. - my $parsed_req = parse_request( $name, \$parsable_request ); - - # Append headers - my $len_header = ''; - if ( !$is_chunked - && defined $parsed_req->{content} - && $parsed_req->{content} ne '' - && $more_headers !~ /\bContent-Length:/ ) - { - $parsed_req->{content} =~ s/^\s+|\s+$//gs; - - $len_header .= - "Content-Length: " . length( $parsed_req->{content} ) . "\r\n"; - } - $parsed_req->{method} .= ' '; - $parsed_req->{url} .= ' '; - $parsed_req->{http_ver} .= "\r\n"; - $parsed_req->{headers} = "Host: localhost\r\nConnection: $conn_header\r\n$more_headers$len_header\r\n"; - - # Get the moves from parsing - my @elements_moves = get_moves($parsed_req); - # Apply them to the packets. - return apply_moves($request_packets, \@elements_moves); -} - -# Returns an array of array of hashes from the block. Each element of -# the first-level array is a request. -# Each request is an array of the "packets" to be sent. Each packet is a -# string to send, with an (optionnal) delay before sending it. -# This function parses (and therefore defines the syntax) of "request*" -# sections. See documentation for supported syntax. -sub get_req_from_block ($) { - my ($block) = @_; - my $name = $block->name; - - my @req_list = (); - - if ( defined $block->raw_request ) { - - # Should be deprecated. - if ( ref $block->raw_request && ref $block->raw_request eq 'ARRAY' ) { - - # User already provided an array. So, he/she specified where the - # data should be split. This allows for backward compatibility but - # should use request with arrays as it provides the same functionnality. - my @rr_list = (); - for my $elt ( @{ $block->raw_request } ) { - push @rr_list, {value => $elt}; - } - push @req_list, \@rr_list; - } - else { - push @req_list, [{value => $block->raw_request}]; - } - } - else { - my $request; - if ( defined $block->request_eval ) { - - diag "$name - request_eval DEPRECATED. Use request eval instead."; - $request = eval $block->request_eval; - if ($@) { - warn $@; - } - } - else { - $request = $block->request; - } - - my $is_chunked = 0; - my $more_headers = ''; - if ( $block->more_headers ) { - my @headers = split /\n+/, $block->more_headers; - for my $header (@headers) { - next if $header =~ /^\s*\#/; - my ( $key, $val ) = split /:\s*/, $header, 2; - if ( lc($key) eq 'transfer-encoding' and $val eq 'chunked' ) { - $is_chunked = 1; - } - - #warn "[$key, $val]\n"; - $more_headers .= "$key: $val\r\n"; - } - } - - if ( $block->pipelined_requests ) { - my $reqs = $block->pipelined_requests; - if ( !ref $reqs || ref $reqs ne 'ARRAY' ) { - Test::More::BAIL_OUT( - "$name - invalid entries in --- pipelined_requests"); - } - my $i = 0; - my $prq = ""; - for my $request (@$reqs) { - my $conn_type; - if ( $i++ == @$reqs - 1 ) { - $conn_type = 'close'; - } - else { - $conn_type = 'keep-alive'; - } - my $r_br = build_request_from_packets($name, $more_headers, - $is_chunked, $conn_type, - [$request] ); - $prq .= $$r_br[0]; - } - push @req_list, [{value =>$prq}]; - } - else { - # request section. - if (!ref $request) { - # One request and it is a good old string. - my $r_br = build_request_from_packets($name, $more_headers, - $is_chunked, 'Close', - [$request] ); - push @req_list, [{value => $$r_br[0]}]; - } elsif (ref $request eq 'ARRAY') { - # A bunch of requests... - for my $one_req (@$request) { - if (!ref $one_req) { - # This request is a good old string. - my $r_br = build_request_from_packets($name, $more_headers, - $is_chunked, 'Close', - [$one_req] ); - push @req_list, [{value => $$r_br[0]}]; - } elsif (ref $one_req eq 'ARRAY') { - # Request expressed as a serie of packets - my @packet_array = (); - for my $one_packet (@$one_req) { - if (!ref $one_packet) { - # Packet is a string. - push @packet_array, $one_packet; - } elsif (ref $one_packet eq 'HASH'){ - # Packet is a hash with a value... - push @packet_array, $one_packet->{value}; - } else { - Test::More::BAIL_OUT "$name - Invalid syntax. $one_packet should be a string or hash with value."; - } - } - my $transformed_packet_array = build_request_from_packets($name, $more_headers, - $is_chunked, 'Close', - \@packet_array); - my @transformed_req = (); - my $idx = 0; - for my $one_transformed_packet (@$transformed_packet_array) { - if (!ref $$one_req[$idx]) { - push @transformed_req, {value => $one_transformed_packet}; - } else { - # Is a HASH (checked above as $one_packet) - $$one_req[$idx]->{value} = $one_transformed_packet; - push @transformed_req, $$one_req[$idx]; - } - $idx++; - } - push @req_list, \@transformed_req; - } else { - Test::More::BAIL_OUT "$name - Invalid syntax. $one_req should be a string or an array of packets."; - } - } - } else { - Test::More::BAIL_OUT( - "$name - invalid ---request : MUST be string or array of requests"); - } - } - - } - return \@req_list; -} - -sub run_test_helper ($$) { - my ( $block, $dry_run ) = @_; - - my $name = $block->name; - - my $r_req_list = get_req_from_block($block); - - if ( $#$r_req_list < 0 ) { - Test::More::BAIL_OUT("$name - request empty"); - } - - #warn "request: $req\n"; - - my $timeout = $block->timeout; - if ( !defined $timeout ) { - $timeout = $Timeout; - } - - my $req_idx = 0; - for my $one_req (@$r_req_list) { - my $raw_resp; - - if ($dry_run) { - $raw_resp = "200 OK HTTP/1.0\r\nContent-Length: 0\r\n\r\n"; - } - else { - $raw_resp = send_request( $one_req, $block->raw_request_middle_delay, - $timeout, $block->name ); - } - - #warn "raw resonse: [$raw_resp]\n"; - - my ($n, $need_array); - - if ($block->pipelined_requests) { - $n = @{ $block->pipelined_requests }; - $need_array = 1; - - } else { - $need_array = $#$r_req_list > 0; - } - -again: - #warn "!!! resp: [$raw_resp]"; - if (!defined $raw_resp) { - $raw_resp = ''; - } - - my ( $res, $raw_headers, $left ) = parse_response( $name, $raw_resp ); - - if (!$n) { - if ($left) { - my $name = $block->name; - $left =~ s/([\0-\037\200-\377])/sprintf('\x{%02x}',ord $1)/eg; - warn "WARNING: $name - unexpected extra bytes after last chunk in ", - "response: \"$left\"\n"; - } - - } else { - $raw_resp = $left; - $n--; - } - - check_error_code($block, $res, $dry_run, $req_idx, $need_array); - check_raw_response_headers($block, $raw_headers, $dry_run, $req_idx, $need_array); - check_response_headers($block, $res, $raw_headers, $dry_run, $req_idx, $need_array); - check_response_body($block, $res, $dry_run, $req_idx, $need_array); - $req_idx++; - - if ($n) { - goto again; - } - } -} - -# Helper function to retrieve a "check" (e.g. error_code) section. This also -# checks that tests with arrays of requests are arrays themselves. -sub get_indexed_value($$$$) { - my ($name, $value, $req_idx, $need_array) = @_; - if ($need_array) { - if (ref $value && ref $value eq 'ARRAY') { - return $$value[$req_idx]; - } else { - Test::More::BAIL_OUT("$name - You asked for many requests, the expected results should be arrays as well."); - } - } else { - # One element but still provided as an array. - if (ref $value && ref $value eq 'ARRAY') { - if ($req_idx != 0) { - Test::More::BAIL_OUT("$name - SHOULD NOT HAPPEN: idx != 0 and don't need array."); - } else { - return $$value[0]; - } - } else { - return $value; - } - } -} -sub check_error_code($$$$$) { - my ($block, $res, $dry_run, $req_idx, $need_array) = @_; - my $name = $block->name; - SKIP: { - skip "$name - tests skipped due to the lack of directive $dry_run", 1 if $dry_run; - if ( defined $block->error_code ) { - is( $res->code || '', - get_indexed_value($name, $block->error_code, $req_idx, $need_array), - "$name - status code ok" ); - } else { - is( $res->code || '', 200, "$name - status code ok" ); - } - } -} -sub check_raw_response_headers($$$$$) { - my ($block, $raw_headers, $dry_run, $req_idx, $need_array) = @_; - my $name = $block->name; - if ( defined $block->raw_response_headers_like ) { - SKIP: { - skip "$name - tests skipped due to the lack of directive $dry_run", 1 if $dry_run; - my $expected = get_indexed_value($name, - $block->raw_response_headers_like, - $req_idx, - $need_array); - like $raw_headers, qr/$expected/s, "$name - raw resp headers like"; - } - } -} -sub check_response_headers($$$$$) { - my ($block, $res, $raw_headers, $dry_run, $req_idx, $need_array) = @_; - my $name = $block->name; - if ( defined $block->response_headers ) { - my $headers = parse_headers( get_indexed_value($name, - $block->response_headers, - $req_idx, - $need_array)); - while ( my ( $key, $val ) = each %$headers ) { - if ( !defined $val ) { - - #warn "HIT"; - SKIP: { - skip "$name - tests skipped due to the lack of directive $dry_run", 1 if $dry_run; - unlike $raw_headers, qr/^\s*\Q$key\E\s*:/ms, - "$name - header $key not present in the raw headers"; - } - next; - } - - my $actual_val = $res->header($key); - if ( !defined $actual_val ) { - $actual_val = ''; - } - - SKIP: { - skip "$name - tests skipped due to the lack of directive $dry_run", 1 if $dry_run; - is $actual_val, $val, "$name - header $key ok"; - } - } - } - elsif ( defined $block->response_headers_like ) { - my $headers = parse_headers( get_indexed_value($name, - $block->response_headers_like, - $req_idx, - $need_array) ); - while ( my ( $key, $val ) = each %$headers ) { - my $expected_val = $res->header($key); - if ( !defined $expected_val ) { - $expected_val = ''; - } - SKIP: { - skip "$name - tests skipped due to the lack of directive $dry_run", 1 if $dry_run; - like $expected_val, qr/^$val$/, "$name - header $key like ok"; - } - } - } -} - -sub check_response_body() { - my ($block, $res, $dry_run, $req_idx, $need_array) = @_; - my $name = $block->name; - if ( defined $block->response_body - || defined $block->response_body_eval ) - { - my $content = $res->content; - if ( defined $content ) { - $content =~ s/^TE: deflate,gzip;q=0\.3\r\n//gms; - $content =~ s/^Connection: TE, close\r\n//gms; - } - - my $expected; - if ( $block->response_body_eval ) { - diag "$name - response_body_eval is DEPRECATED. Use response_body eval instead."; - $expected = eval get_indexed_value($name, - $block->response_body_eval, - $req_idx, - $need_array); - if ($@) { - warn $@; - } - } - else { - $expected = get_indexed_value($name, - $block->response_body, - $req_idx, - $need_array); - } - - if ( $block->charset ) { - Encode::from_to( $expected, 'UTF-8', $block->charset ); - } - - unless (ref $expected) { - $expected =~ s/\$ServerPort\b/$ServerPort/g; - $expected =~ s/\$ServerPortForClient\b/$ServerPortForClient/g; - } - - #warn show_all_chars($content); - - #warn "no long string: $NoLongString"; - SKIP: { - skip "$name - tests skipped due to the lack of directive $dry_run", 1 if $dry_run; - if (ref $expected) { - like $content, $expected, "$name - response_body - like"; - - } else { - if ($NoLongString) { - is( $content, $expected, - "$name - response_body - response is expected" ); - } - else { - is_string( $content, $expected, - "$name - response_body - response is expected" ); - } - } - } - - } - elsif ( defined $block->response_body_like ) { - my $content = $res->content; - if ( defined $content ) { - $content =~ s/^TE: deflate,gzip;q=0\.3\r\n//gms; - } - $content =~ s/^Connection: TE, close\r\n//gms; - my $expected_pat = get_indexed_value($name, - $block->response_body_like, - $req_idx, - $need_array); - $expected_pat =~ s/\$ServerPort\b/$ServerPort/g; - $expected_pat =~ s/\$ServerPortForClient\b/$ServerPortForClient/g; - my $summary = trim($content); - - SKIP: { - skip "$name - tests skipped due to the lack of directive $dry_run", 1 if $dry_run; - like( $content, qr/$expected_pat/s, - "$name - response_body_like - response is expected ($summary)" - ); - } - } elsif ( defined $block->response_body_unlike ) { - my $content = $res->content; - if ( defined $content ) { - $content =~ s/^TE: deflate,gzip;q=0\.3\r\n//gms; - } - $content =~ s/^Connection: TE, close\r\n//gms; - my $expected_pat = get_indexed_value($name, - $block->response_body_unlike, - $req_idx, - $need_array); - $expected_pat =~ s/\$ServerPort\b/$ServerPort/g; - $expected_pat =~ s/\$ServerPortForClient\b/$ServerPortForClient/g; - my $summary = trim($content); - - SKIP: { - skip "$name - tests skipped due to the lack of directive $dry_run", 1 if $dry_run; - unlike( $content, qr/$expected_pat/s, - "$name - response_body_like - response is expected ($summary)" - ); - } -} - -sub parse_response($$) { - my ( $name, $raw_resp ) = @_; - - my $left; - - my $raw_headers = ''; - if ( $raw_resp =~ /(.*?\r\n)\r\n/s ) { - - #warn "\$1: $1"; - $raw_headers = $1; - } - - #warn "raw headers: $raw_headers\n"; - - my $res = HTTP::Response->parse($raw_resp); - my $enc = $res->header('Transfer-Encoding'); - - my $len = $res->header('Content-Length'); - - if ( defined $enc && $enc eq 'chunked' ) { - - #warn "Found chunked!"; - my $raw = $res->content; - if ( !defined $raw ) { - $raw = ''; - } - - my $decoded = ''; - while (1) { - if ( $raw =~ /\G 0 [\ \t]* \r\n \r\n /gcsx ) { - if ( $raw =~ /\G (.+) /gcsx ) { - $left = $1; - } - - last; - } - if ( $raw =~ m{ \G [\ \t]* ( [A-Fa-f0-9]+ ) [\ \t]* \r\n }gcsx ) { - my $rest = hex($1); - - #warn "chunk size: $rest\n"; - my $bit_sz = 32765; - while ( $rest > 0 ) { - my $bit = $rest < $bit_sz ? $rest : $bit_sz; - - #warn "bit: $bit\n"; - if ( $raw =~ /\G(.{$bit})/gcs ) { - $decoded .= $1; - - #warn "decoded: [$1]\n"; - } - else { - fail( -"$name - invalid chunked data received (not enought octets for the data section)" - ); - return; - } - - $rest -= $bit; - } - if ( $raw !~ /\G\r\n/gcs ) { - fail( - "$name - invalid chunked data received (expected CRLF)." - ); - return; - } - } - elsif ( $raw =~ /\G.+/gcs ) { - fail "$name - invalid chunked body received: $&"; - return; - } - else { - fail "$name - no last chunk found - $raw"; - return; - } - } - - #warn "decoded: $decoded\n"; - $res->content($decoded); - - } elsif (defined $len && $len ne '' && $len >= 0) { - my $raw = $res->content; - if (length $raw < $len) { - warn "WARNING: $name - response body truncated: ", - "$len expected, but got ", length $raw, "\n"; - - } elsif (length $raw > $len) { - my $content = substr $raw, 0, $len; - $left = substr $raw, $len; - $res->content($content); - #warn "parsed body: [", $res->content, "]\n"; - } - } - - return ( $res, $raw_headers, $left ); -} - -sub send_request ($$$$@) { - my ( $req, $middle_delay, $timeout, $name, $tries ) = @_; - - my $sock = IO::Socket::INET->new( - PeerAddr => $ServerAddr, - PeerPort => $ServerPortForClient, - Proto => 'tcp' - ); - - if (! defined $sock) { - $tries ||= 0; - if ($tries < 3) { - warn "Can't connect to $ServerAddr:$ServerPortForClient: $!\n"; - sleep 1; - return send_request($req, $middle_delay, $timeout, $name, $tries + 1); - } else { - die "Can't connect to $ServerAddr:$ServerPortForClient: $!\n"; - } - } - - my @req_bits = ref $req ? @$req : ($req); - - my $flags = fcntl $sock, F_GETFL, 0 - or die "Failed to get flags: $!\n"; - - fcntl $sock, F_SETFL, $flags | O_NONBLOCK - or die "Failed to set flags: $!\n"; - - my $ctx = { - resp => '', - write_offset => 0, - buf_size => 1024, - req_bits => \@req_bits, - write_buf => (shift @req_bits)->{"value"}, - middle_delay => $middle_delay, - sock => $sock, - name => $name, - }; - - my $readable_hdls = IO::Select->new($sock); - my $writable_hdls = IO::Select->new($sock); - my $err_hdls = IO::Select->new($sock); - - while (1) { - if ( $readable_hdls->count == 0 - && $writable_hdls->count == 0 - && $err_hdls->count == 0 ) - { - last; - } - - my ( $new_readable, $new_writable, $new_err ) = - IO::Select->select( $readable_hdls, $writable_hdls, $err_hdls, - $timeout ); - - if ( !defined $new_err - && !defined $new_readable - && !defined $new_writable ) - { - - # timed out - timeout_event_handler($ctx); - last; - } - - for my $hdl (@$new_err) { - next if !defined $hdl; - - error_event_handler($ctx); - - if ( $err_hdls->exists($hdl) ) { - $err_hdls->remove($hdl); - } - - if ( $readable_hdls->exists($hdl) ) { - $readable_hdls->remove($hdl); - } - - if ( $writable_hdls->exists($hdl) ) { - $writable_hdls->remove($hdl); - } - - for my $h (@$readable_hdls) { - next if !defined $h; - if ( $h eq $hdl ) { - undef $h; - last; - } - } - - for my $h (@$writable_hdls) { - next if !defined $h; - if ( $h eq $hdl ) { - undef $h; - last; - } - } - - close $hdl; - } - - for my $hdl (@$new_readable) { - next if !defined $hdl; - - my $res = read_event_handler($ctx); - if ( !$res ) { - - # error occured - if ( $err_hdls->exists($hdl) ) { - $err_hdls->remove($hdl); - } - - if ( $readable_hdls->exists($hdl) ) { - $readable_hdls->remove($hdl); - } - - if ( $writable_hdls->exists($hdl) ) { - $writable_hdls->remove($hdl); - } - - for my $h (@$writable_hdls) { - next if !defined $h; - if ( $h eq $hdl ) { - undef $h; - last; - } - } - - close $hdl; - } - } - - for my $hdl (@$new_writable) { - next if !defined $hdl; - - my $res = write_event_handler($ctx); - if ( !$res ) { - - # error occured - if ( $err_hdls->exists($hdl) ) { - $err_hdls->remove($hdl); - } - - if ( $readable_hdls->exists($hdl) ) { - $readable_hdls->remove($hdl); - } - - if ( $writable_hdls->exists($hdl) ) { - $writable_hdls->remove($hdl); - } - - close $hdl; - - } elsif ( $res == 2 ) { - if ( $writable_hdls->exists($hdl) ) { - $writable_hdls->remove($hdl); - } - } - } - } - - return $ctx->{resp}; -} - -sub timeout_event_handler ($) { - my $ctx = shift; - warn "ERROR: socket client: timed out - $ctx->{name}\n"; -} - -sub error_event_handler ($) { - warn "exception occurs on the socket: $!\n"; -} - -sub write_event_handler ($) { - my ($ctx) = @_; - - while (1) { - return undef if !defined $ctx->{write_buf}; - - my $rest = length( $ctx->{write_buf} ) - $ctx->{write_offset}; - - #warn "offset: $write_offset, rest: $rest, length ", length($write_buf), "\n"; - #die; - - if ( $rest > 0 ) { - my $bytes; - eval { - $bytes = syswrite( - $ctx->{sock}, $ctx->{write_buf}, - $rest, $ctx->{write_offset} - ); - }; - - if ($@) { - my $errmsg = "write failed: $@"; - warn "$errmsg\n"; - $ctx->{resp} = $errmsg; - return undef; - } - - if ( !defined $bytes ) { - if ( $! == EAGAIN ) { - - #warn "write again..."; - #sleep 0.002; - return 1; - } - my $errmsg = "write failed: $!"; - warn "$errmsg\n"; - if ( !$ctx->{resp} ) { - $ctx->{resp} = "$errmsg"; - } - return undef; - } - - #warn "wrote $bytes bytes.\n"; - $ctx->{write_offset} += $bytes; - } - else { - my $next_send = shift @{ $ctx->{req_bits} } or return 2; - $ctx->{write_buf} = $next_send->{'value'}; - $ctx->{write_offset} = 0; - my $wait_time; - if (!defined $next_send->{'delay_before'}) { - if (defined $ctx->{middle_delay}) { - $wait_time = $ctx->{middle_delay}; - } - } else { - $wait_time = $next_send->{'delay_before'}; - } - if ($wait_time) { - #warn "sleeping.."; - sleep $wait_time; - } - } - } - - # impossible to reach here... - return undef; -} - -sub read_event_handler ($) { - my ($ctx) = @_; - while (1) { - my $read_buf; - my $bytes = sysread( $ctx->{sock}, $read_buf, $ctx->{buf_size} ); - - if ( !defined $bytes ) { - if ( $! == EAGAIN ) { - - #warn "read again..."; - #sleep 0.002; - return 1; - } - $ctx->{resp} = "500 read failed: $!"; - return undef; - } - - if ( $bytes == 0 ) { - return undef; # connection closed - } - - $ctx->{resp} .= $read_buf; - - #warn "read $bytes ($read_buf) bytes.\n"; - } - - # impossible to reach here... - return undef; -} - -1; -__END__ - -=encoding utf-8 - -=head1 NAME - -Test::Nginx::Socket - Socket-backed test scaffold for the Nginx C modules - -=head1 SYNOPSIS - - use Test::Nginx::Socket; - - plan tests => $Test::Nginx::Socket::RepeatEach * 2 * blocks(); - - run_tests(); - - __DATA__ - - === TEST 1: sanity - --- config - location /echo { - echo_before_body hello; - echo world; - } - --- request - GET /echo - --- response_body - hello - world - --- error_code: 200 - - - === TEST 2: set Server - --- config - location /foo { - echo hi; - more_set_headers 'Server: Foo'; - } - --- request - GET /foo - --- response_headers - Server: Foo - --- response_body - hi - - - === TEST 3: clear Server - --- config - location /foo { - echo hi; - more_clear_headers 'Server: '; - } - --- request - GET /foo - --- response_headers_like - Server: nginx.* - --- response_body - hi - - - === TEST 3: chunk size too small - --- config - chunkin on; - location /main { - echo_request_body; - } - --- more_headers - Transfer-Encoding: chunked - --- request eval - "POST /main - 4\r - hello\r - 0\r - \r - " - --- error_code: 400 - --- response_body_like: 400 Bad Request - -=head1 DESCRIPTION - -This module provides a test scaffold based on non-blocking L for automated testing in Nginx C module development. - -This class inherits from L, thus bringing all its -declarative power to the Nginx C module testing practices. - -You need to terminate or kill any Nginx processes before running the test suite if you have changed the Nginx server binary. Normally it's as simple as - - killall nginx - PATH=/path/to/your/nginx-with-memc-module:$PATH prove -r t - -This module will create a temporary server root under t/servroot/ of the current working directory and starts and uses the nginx executable in the PATH environment. - -You will often want to look into F -when things go wrong ;) - -=head1 Sections supported - -The following sections are supported: - -=head2 config - -Content of this section will be included in the "server" part of the generated -config file. This is the place where you want to put the "location" directive -enabling the module you want to test. Example: - - location /echo { - echo_before_body hello; - echo world; - } - -Sometimes you simply don't want to bother copying ten times the same -configuration for the ten tests you want to run against your module. One way -to do this is to write a config section only for the first test in your C<.t> -file. All subsequent tests will re-use the same config. Please note that this -depends on the order of test, so you should run C with variable -C (see below for more on this variable). - -Please note that config section goes through environment variable expansion -provided the variables to expand start with TEST_NGINX. -So, the following is a perfectly legal (provided C is -set correctly): - - location /main { - echo_subrequest POST /sub -f $TEST_NGINX_HTML_DIR/blah.txt; - } - -=head2 http_config - -Content of this section will be included in the "http" part of the generated -config file. This is the place where you want to put the "upstream" directive -you might want to test. Example: - - upstream database { - postgres_server 127.0.0.1:$TEST_NGINX_POSTGRESQL_PORT - dbname=ngx_test user=ngx_test - password=wrong_pass; - } - -As you guessed from the example above, this section goes through environment -variable expansion (variables have to start with TEST_NGINX). - -=head2 main_config - -Content of this section will be included in the "main" part of the generated -config file. This is very rarely used, except if you are testing nginx core -itself. - -This section goes through environment -variable expansion (variables have to start with TEST_NGINX). - -=head2 request - -This is probably the most important section. It defines the request(s) you -are going to send to the nginx server. It offers a pretty powerful grammar -which we are going to walk through one example at a time. - -In its most basic form, this section looks like that: - - --- request - GET - -This will just do a GET request on the root (i.e. /) of the server using -HTTP/1.1. - -Of course, you might want to test something else than the root of your -web server and even use a different version of HTTP. This is possible: - - --- request - GET /foo HTTP/1.0 - -Please note that specifying HTTP/1.0 will not prevent Test::Nginx from -sending the C header. Actually Test::Nginx always sends 2 headers: -C (with value localhost) and C (with value Close for -simple requests and keep-alive for all but the last pipelined_requests). - -You can also add a content to your request: - - --- request - POST /foo - Hello world - -Test::Nginx will automatically calculate the content length and add the -corresponding header for you. - -This being said, as soon as you want to POST real data, you will be interested -in using the more_headers section and using the power of Test::Base filters -to urlencode the content you are sending. Which gives us a -slightly more realistic example: - - --- more_headers - Content-type: application/x-www-form-urlencoded - --- request eval - use URI::Escape; - "POST /rrd/foo - value=".uri_escape("N:12345") - -Sometimes a test is more than one request. Typically you want to POST some -data and make sure the data has been taken into account with a GET. You can -do it using arrays: - - --- request eval - ["POST /users - name=foo", "GET /users/foo"] - -This way, REST-like interfaces are pretty easy to test. - -When you develop nifty nginx modules you will eventually want to test things -with buffers and "weird" network conditions. This is where you split -your request into network packets: - - --- request eval - [["POST /users\nna", "me=foo"]] - -Here, Test::Nginx will first send the request line, the headers it -automatically added for you and the first two letters of the body ("na" in -our example) in ONE network packet. Then, it will send the next packet (here -it's "me=foo"). When we talk about packets here, this is nto exactly correct -as there is no way to guarantee the behavior of the TCP/IP stack. What -Test::Nginx can guarantee is that this will result in two calls to -C. - -A good way to make I sure the two calls result in two packets is to -introduce a delay (let's say 2 seconds)before sending the second packet: - - --- request eval - [["POST /users\nna", {value => "me=foo", delay_before => 2}]] - -Of course, everything can be combined till your brain starts boiling ;) : - - --- request eval - use URI::Escape; - my $val="value=".uri_escape("N:12346"); - [["POST /rrd/foo - ".substr($val, 0, 6), - {value => substr($val, 6, 5), delay_before=>5}, - substr($val, 11)], "GET /rrd/foo"] - -=head2 request_eval - -Use of this section is deprecated and tests using it should replace it with -a C section with an C filter. More explicitly: - - --- request_eval - "POST /echo_body - hello\x00\x01\x02 - world\x03\x04\xff" - -should be replaced by: - - --- request eval - "POST /echo_body - hello\x00\x01\x02 - world\x03\x04\xff" - -=head2 pipelined_requests - -Specify pipelined requests that use a single keep-alive connection to the server. - -Here is an example from ngx_lua's test suite: - - === TEST 7: discard body - --- config - location = /foo { - content_by_lua ' - ngx.req.discard_body() - ngx.say("body: ", ngx.var.request_body) - '; - } - location = /bar { - content_by_lua ' - ngx.req.read_body() - ngx.say("body: ", ngx.var.request_body) - '; - } - --- pipelined_requests eval - ["POST /foo - hello, world", - "POST /bar - hiya, world"] - --- response_body eval - ["body: nil\n", - "body: hiya, world\n"] - -=head2 more_headers - -Adds the content of this section as headers to the request being sent. Example: - - --- more_headers - X-Foo: blah - -This will add C to the request (on top of the automatically -generated headers like C, C and potentially -C). - -=head2 response_body - -The expected value for the body of the submitted request. - - --- response_body - hello - -If the test is made of multiple requests, then the response_body B -be an array and each request B return the corresponding expected -body: - - --- request eval - ["GET /hello", "GET /world"] - --- response_body eval - ["hello", "world"] - -=head2 response_body_eval - -Use of this section is deprecated and tests using it should replace it -with a C section with an C filter. Therefore: - - --- response_body_eval - "hello\x00\x01\x02 - world\x03\x04\xff" - -should be replaced by: - - --- response_body eval - "hello\x00\x01\x02 - world\x03\x04\xff" - -=head2 response_body_like - -The body returned by the request MUST match the pattern provided by this -section. Example: - - --- response_body_like - ^elapsed 0\.00[0-5] sec\.$ - -If the test is made of multiple requests, then response_body_like B -be an array and each request B match the corresponding pattern. - -=head2 response_headers - -The headers specified in this section are in the response sent by nginx. - - --- response_headers - Content-Type: application/x-resty-dbd-stream - -Of course, you can specify many headers in this section: - - --- response_headers - X-Resty-DBD-Module: - Content-Type: application/x-resty-dbd-stream - -The test will be successful only if all headers are found in the response with -the appropriate values. - -If the test is made of multiple requests, then response_headers B -be an array and each element of the array is checked against the -response to the corresponding request. - -=head2 response_headers_like - -The value of the headers returned by nginx match the patterns. - - --- response_headers_like - X-Resty-DBD-Module: ngx_drizzle \d+\.\d+\.\d+ - Content-Type: application/x-resty-dbd-stream - -This will check that the response's C is -application/x-resty-dbd-stream and that the C matches -C. - -The test will be successful only if all headers are found in the response and -if the values match the patterns. - -If the test is made of multiple requests, then response_headers_like B -be an array and each element of the array is checked against the -response to the corresponding request. - -=head2 raw_response_headers_like - -Checks the headers part of the response against this pattern. This is -particularly useful when you want to write tests of redirect functions -that are not bound to the value of the port your nginx server (under -test) is listening to: - - --- raw_response_headers_like: Location: http://localhost(?::\d+)?/foo\r\n - -As usual, if the test is made of multiple requests, then -raw_response_headers_like B be an array. - -=head2 error_code - -The expected value of the HTTP response code. If not set, this is assumed -to be 200. But you can expect other things such as a redirect: - - --- error_code: 302 - -If the test is made of multiple requests, then -error_code B be an array with the expected value for the response status -of each request in the test. - -=head2 raw_request - -The exact request to send to nginx. This is useful when you want to test -soem behaviors that are not available with "request" such as an erroneous -C header or splitting packets right in the middle of headers: - - --- raw_request eval - ["POST /rrd/taratata HTTP/1.1\r - Host: localhost\r - Connection: Close\r - Content-Type: application/", - "x-www-form-urlencoded\r - Content-Length:15\r\n\r\nvalue=N%3A12345"] - -This can also be useful to tests "invalid" request lines: - - --- raw_request - GET /foo HTTP/2.0 THE_FUTURE_IS_NOW - -=head2 user_files - -With this section you can create a file that will be copied in the -html directory of the nginx server under test. For example: - - --- user_files - >>> blah.txt - Hello, world - -will create a file named C in the html directory of the nginx -server tested. The file will contain the text "Hello, world". - -=head2 skip_nginx - -=head2 skip_nginx2 - -Both string scalar and string arrays are supported as values. - -=head2 raw_request_middle_delay - -Delay in sec between sending successive packets in the "raw_request" array -value. Also used when a request is split in packets. - -=head1 Environment variables - -All environment variables starting with C are expanded in the -sections used to build the configuration of the server that tests automatically -starts. The following environment variables are supported by this module: - -=head2 TEST_NGINX_NO_NGINX_MANAGER - -Defaults to 0. If set to 1, Test::Nginx module will not manage -(configure/start/stop) the C process. Can be useful to run tests -against an already configured (and running) nginx server. - -=head2 TEST_NGINX_NO_SHUFFLE - -Dafaults to 0. If set to 1, will make sure the tests are run in the order -they appear in the test file (and not in random order). - -=head2 TEST_NGINX_USE_VALGRIND - -If set to 1, will start nginx with valgrind. nginx is actually started with -C, -the suppressions option being used only if there is actually -a valgrind.suppress file. - -=head2 TEST_NGINX_BINARY - -The command to start nginx. Defaults to C. Can be used as an alternative -to setting C to run a specific nginx instance. - -=head2 TEST_NGINX_LOG_LEVEL - -Value of the last argument of the C configuration directive. -Defaults to C. - -=head2 TEST_NGINX_MASTER_PROCESS - -Value of the C configuration directive. Defaults to C. - -=head2 TEST_NGINX_SERVER_PORT - -Value of the port the server started by Test::Nginx will listen to. If not -set, C is used. If C is not set, -then C<1984> is used. See below for typical use. - -=head2 TEST_NGINX_CLIENT_PORT - -Value of the port Test::Nginx will diirect requests to. If not -set, C is used. If C is not set, -then C<1984> is used. A typical use of this feature is to test extreme -network conditions by adding a "proxy" between Test::Nginx and nginx -itself. This is described in the C section of this -module README. - -=head2 TEST_NGINX_PORT - -A shortcut for setting both C and -C. - -=head2 TEST_NGINX_SLEEP - -How much time (in seconds) should Test::Nginx sleep between two calls to C when -sending request data. Defaults to 0. - -=head2 TEST_NGINX_FORCE_RESTART_ON_TEST - -Defaults to 1. If set to 0, Test::Nginx will not restart the nginx -server when the config does not change between two tests. - -=head2 TEST_NGINX_SERVROOT - -The root of the nginx "hierarchy" (where you find the conf, *_tmp and logs -directories). This value will be used with the C<-p> option of C. -Defaults to appending C to the current directory. - -=head2 TEST_NGINX_IGNORE_MISSING_DIRECTIVES - -If set to 1 will SKIP all tests which C sections resulted in a -C when trying to start C. Useful when you want to -run tests on a build of nginx that does not include all modules it should. -By default, these tests will FAIL. - -=head2 TEST_NGINX_EVENT_TYPE - -This environment can be used to specify a event API type to be used by Nginx. Possible values are C, C, C