From piotrsikora at google.com Fri Jul 1 21:31:43 2016 From: piotrsikora at google.com (Piotr Sikora) Date: Fri, 01 Jul 2016 14:31:43 -0700 Subject: [PATCH] Configure: remove tests for a few standard C types Message-ID: <3bd4707f1bc170859f27.1467408703@piotrsikora.sfo.corp.google.com> # HG changeset patch # User Piotr Sikora # Date 1467064813 25200 # Mon Jun 27 15:00:13 2016 -0700 # Node ID 3bd4707f1bc170859f27a8de6451531a675b5f3b # Parent d452cb27639f714bc43b7f3ede417e3e7f8efdd6 Configure: remove tests for a few standard C types. Results of those tests were unused since a88a3e4e158f (0.1.5). Also, this fixes build with -Werror=long-long, since ./configure script was the only place where "long long" type was used. Signed-off-by: Piotr Sikora diff -r d452cb27639f -r 3bd4707f1bc1 auto/unix --- a/auto/unix +++ b/auto/unix @@ -584,12 +584,6 @@ ngx_feature_libs= # C types -ngx_type="int"; . auto/types/sizeof - -ngx_type="long"; . auto/types/sizeof - -ngx_type="long long"; . auto/types/sizeof - ngx_type="void *"; . auto/types/sizeof; ngx_ptr_size=$ngx_size ngx_param=NGX_PTR_SIZE; ngx_value=$ngx_size; . auto/types/value From piotrsikora at google.com Fri Jul 1 21:31:41 2016 From: piotrsikora at google.com (Piotr Sikora) Date: Fri, 01 Jul 2016 14:31:41 -0700 Subject: [PATCH] Core: detect valid error numbers at run-time Message-ID: # HG changeset patch # User Piotr Sikora # Date 1467064814 25200 # Mon Jun 27 15:00:14 2016 -0700 # Node ID be7eadea3d089f18c5ea685c09824ddcd99c3fe5 # Parent d452cb27639f714bc43b7f3ede417e3e7f8efdd6 Core: detect valid error numbers at run-time. Strings for some error numbers might be omitted, at least on Linux, so stop after 3 unknown errors in a row and not after the first one. Signed-off-by: Piotr Sikora diff -r d452cb27639f -r be7eadea3d08 auto/unix --- a/auto/unix +++ b/auto/unix @@ -697,60 +697,6 @@ ngx_feature_test="char buf[1]; struct io . auto/feature -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 - - -if [ $ngx_found = no ]; then - - # Cygiwn defines _sys_nerr - 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 - - # 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 -r d452cb27639f -r be7eadea3d08 src/os/unix/ngx_errno.c --- a/src/os/unix/ngx_errno.c +++ b/src/os/unix/ngx_errno.c @@ -26,6 +26,7 @@ static ngx_str_t *ngx_sys_errlist; +static ngx_err_t ngx_sys_errlist_n; static ngx_str_t ngx_unknown_error = ngx_string("Unknown error"); @@ -34,8 +35,8 @@ ngx_strerror(ngx_err_t err, u_char *errs { ngx_str_t *msg; - msg = ((ngx_uint_t) err < NGX_SYS_NERR) ? &ngx_sys_errlist[err]: - &ngx_unknown_error; + msg = (err < ngx_sys_errlist_n) ? &ngx_sys_errlist[err] + : &ngx_unknown_error; size = ngx_min(size, msg->len); return ngx_cpymem(errstr, msg->data, size); @@ -45,25 +46,58 @@ ngx_strerror(ngx_err_t err, u_char *errs ngx_int_t ngx_strerror_init(void) { - char *msg; - u_char *p; - size_t len; - ngx_err_t err; + char *msg; + u_char *p; + size_t len; + ngx_err_t err; + ngx_uint_t count; /* * 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); + count = 0; + ngx_sys_errlist_n = 1000; + + for (err = 0; err < ngx_sys_errlist_n; err++) { + + errno = 0; + msg = strerror(err); + if (errno == EINVAL + || msg == NULL + || ngx_strncmp(msg, "Unknown error", 13) == 0) + { + if (++count > 2) { + ngx_sys_errlist_n = err - 2; + break; + } + + continue; + } + + count = 0; + } + + len = ngx_sys_errlist_n * 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 = 0; err < ngx_sys_errlist_n; err++) { + + errno = 0; msg = strerror(err); + if (errno == EINVAL + || msg == NULL + || ngx_strncmp(msg, "Unknown error", 13) == 0) + { + ngx_sys_errlist[err] = ngx_unknown_error; + continue; + } + len = ngx_strlen(msg); p = malloc(len); From piotrsikora at google.com Sat Jul 2 00:05:18 2016 From: piotrsikora at google.com (Piotr Sikora) Date: Fri, 01 Jul 2016 17:05:18 -0700 Subject: [PATCH] Configure: remove test based on Linux kernel version Message-ID: <7da099858a643bc63a26.1467417918@piotrsikora.sfo.corp.google.com> # HG changeset patch # User Piotr Sikora # Date 1467064815 25200 # Mon Jun 27 15:00:15 2016 -0700 # Node ID 7da099858a643bc63a26082604f01910df444ad6 # Parent d452cb27639f714bc43b7f3ede417e3e7f8efdd6 Configure: remove test based on Linux kernel version. Proper test for posix_fadvise() is done as part of auto/unix. Signed-off-by: Piotr Sikora diff -r d452cb27639f -r 7da099858a64 auto/os/linux --- a/auto/os/linux +++ b/auto/os/linux @@ -16,22 +16,6 @@ cc_aux_flags="$CC_AUX_FLAGS" CC_AUX_FLAGS="$cc_aux_flags -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64" -# Linux kernel version - -version=$((`uname -r \ - | sed -n -e 's/^\([0-9][0-9]*\)\.\([0-9][0-9]*\)\.\([0-9][0-9]*\).*/ \ - \1*256*256+\2*256+\3/p' \ - -e 's/^\([0-9][0-9]*\)\.\([0-9][0-9]*\).*/\1*256*256+\2*256/p'`)) - -version=${version:-0} - - -# posix_fadvise64() had been implemented in 2.5.60 - -if [ $version -lt 132412 ]; then - have=NGX_HAVE_POSIX_FADVISE . auto/nohave -fi - # epoll, EPOLLET version ngx_feature="epoll" From mdounin at mdounin.ru Sat Jul 2 12:12:51 2016 From: mdounin at mdounin.ru (Maxim Dounin) Date: Sat, 2 Jul 2016 15:12:51 +0300 Subject: [PATCH] Configure: remove test based on Linux kernel version In-Reply-To: <7da099858a643bc63a26.1467417918@piotrsikora.sfo.corp.google.com> References: <7da099858a643bc63a26.1467417918@piotrsikora.sfo.corp.google.com> Message-ID: <20160702121251.GO30781@mdounin.ru> Hello! On Fri, Jul 01, 2016 at 05:05:18PM -0700, Piotr Sikora wrote: > # HG changeset patch > # User Piotr Sikora > # Date 1467064815 25200 > # Mon Jun 27 15:00:15 2016 -0700 > # Node ID 7da099858a643bc63a26082604f01910df444ad6 > # Parent d452cb27639f714bc43b7f3ede417e3e7f8efdd6 > Configure: remove test based on Linux kernel version. > > Proper test for posix_fadvise() is done as part of auto/unix. > > Signed-off-by: Piotr Sikora > > diff -r d452cb27639f -r 7da099858a64 auto/os/linux > --- a/auto/os/linux > +++ b/auto/os/linux > @@ -16,22 +16,6 @@ cc_aux_flags="$CC_AUX_FLAGS" > CC_AUX_FLAGS="$cc_aux_flags -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64" > > > -# Linux kernel version > - > -version=$((`uname -r \ > - | sed -n -e 's/^\([0-9][0-9]*\)\.\([0-9][0-9]*\)\.\([0-9][0-9]*\).*/ \ > - \1*256*256+\2*256+\3/p' \ > - -e 's/^\([0-9][0-9]*\)\.\([0-9][0-9]*\).*/\1*256*256+\2*256/p'`)) > - > -version=${version:-0} > - > - > -# posix_fadvise64() had been implemented in 2.5.60 > - > -if [ $version -lt 132412 ]; then > - have=NGX_HAVE_POSIX_FADVISE . auto/nohave > -fi > - > # epoll, EPOLLET version > > ngx_feature="epoll" The code in question disables posix_fadvise() on old kernels, as the test in auto/unix can lead to false positive results. -- Maxim Dounin http://nginx.org/ From arut at nginx.com Sat Jul 2 13:01:51 2016 From: arut at nginx.com (Roman Arutyunyan) Date: Sat, 02 Jul 2016 13:01:51 +0000 Subject: [nginx] Sub filter: introduced the ngx_http_sub_match() function. Message-ID: details: http://hg.nginx.org/nginx/rev/0e0adbbc8752 branches: changeset: 6604:0e0adbbc8752 user: Roman Arutyunyan date: Sat Jul 02 15:59:52 2016 +0300 description: Sub filter: introduced the ngx_http_sub_match() function. No functional changes. diffstat: src/http/modules/ngx_http_sub_filter_module.c | 83 ++++++++++++++++---------- 1 files changed, 52 insertions(+), 31 deletions(-) diffs (119 lines): diff -r 9eefb38f0005 -r 0e0adbbc8752 src/http/modules/ngx_http_sub_filter_module.c --- a/src/http/modules/ngx_http_sub_filter_module.c Thu Jun 30 18:57:39 2016 +0300 +++ b/src/http/modules/ngx_http_sub_filter_module.c Sat Jul 02 15:59:52 2016 +0300 @@ -84,6 +84,8 @@ static ngx_int_t ngx_http_sub_output(ngx ngx_http_sub_ctx_t *ctx); static ngx_int_t ngx_http_sub_parse(ngx_http_request_t *r, ngx_http_sub_ctx_t *ctx); +static ngx_int_t ngx_http_sub_match(ngx_http_sub_ctx_t *ctx, ngx_int_t start, + ngx_str_t *m); static char * ngx_http_sub_filter(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); @@ -592,7 +594,7 @@ ngx_http_sub_output(ngx_http_request_t * static ngx_int_t ngx_http_sub_parse(ngx_http_request_t *r, ngx_http_sub_ctx_t *ctx) { - u_char *p, *last, *pat, *pat_end, c; + u_char *p, c; ngx_str_t *m; ngx_int_t offset, start, next, end, len, rc; ngx_uint_t shift, i, j; @@ -641,41 +643,15 @@ ngx_http_sub_parse(ngx_http_request_t *r m = &match[i].match; - pat = m->data; - pat_end = m->data + m->len; - - if (start >= 0) { - p = ctx->pos + start; - - } else { - last = ctx->looked.data + ctx->looked.len; - p = last + start; + rc = ngx_http_sub_match(ctx, start, m); - while (p < last && pat < pat_end) { - if (ngx_tolower(*p) != *pat) { - goto next; - } - - p++; - pat++; - } - - p = ctx->pos; - } - - while (p < ctx->buf->last && pat < pat_end) { - if (ngx_tolower(*p) != *pat) { - goto next; - } - - p++; - pat++; + if (rc == NGX_DECLINED) { + goto next; } ctx->index = i; - if (pat != pat_end) { - /* partial match */ + if (rc == NGX_AGAIN) { goto again; } @@ -731,6 +707,51 @@ done: } +static ngx_int_t +ngx_http_sub_match(ngx_http_sub_ctx_t *ctx, ngx_int_t start, ngx_str_t *m) +{ + u_char *p, *last, *pat, *pat_end; + + pat = m->data; + pat_end = m->data + m->len; + + if (start >= 0) { + p = ctx->pos + start; + + } else { + last = ctx->looked.data + ctx->looked.len; + p = last + start; + + while (p < last && pat < pat_end) { + if (ngx_tolower(*p) != *pat) { + return NGX_DECLINED; + } + + p++; + pat++; + } + + p = ctx->pos; + } + + while (p < ctx->buf->last && pat < pat_end) { + if (ngx_tolower(*p) != *pat) { + return NGX_DECLINED; + } + + p++; + pat++; + } + + if (pat != pat_end) { + /* partial match */ + return NGX_AGAIN; + } + + return NGX_OK; +} + + static char * ngx_http_sub_filter(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { From arut at nginx.com Sat Jul 2 13:01:54 2016 From: arut at nginx.com (Roman Arutyunyan) Date: Sat, 02 Jul 2016 13:01:54 +0000 Subject: [nginx] Sub filter: eliminate unnecessary buffering. Message-ID: details: http://hg.nginx.org/nginx/rev/f379b32e4733 branches: changeset: 6605:f379b32e4733 user: Roman Arutyunyan date: Sat Jul 02 15:59:53 2016 +0300 description: Sub filter: eliminate unnecessary buffering. Previously, when a buffer was processed by the sub filter, its final bytes could be buffered by the filter even if they don't match any pattern. This happened because the Boyer-Moore algorithm, employed by the sub filter since b9447fc457b4 (1.9.4), matches the last characters of patterns prior to checking other characters. If the last character is out of scope, initial bytes of a potential match are buffered until the last character is available. Now, after receiving a flush or recycled buffer, the filter performs additional checks to reduce the number of buffered bytes. The potential match is checked against the initial parts of all patterns. Non-matching bytes are not buffered. This improves processing of a chunked response from upstream by sending the entire chunks without buffering unless a partial match is found at the end of a chunk. diffstat: src/http/modules/ngx_http_sub_filter_module.c | 41 ++++++++++++++++++++++++-- 1 files changed, 37 insertions(+), 4 deletions(-) diffs (104 lines): diff -r 0e0adbbc8752 -r f379b32e4733 src/http/modules/ngx_http_sub_filter_module.c --- a/src/http/modules/ngx_http_sub_filter_module.c Sat Jul 02 15:59:52 2016 +0300 +++ b/src/http/modules/ngx_http_sub_filter_module.c Sat Jul 02 15:59:53 2016 +0300 @@ -83,7 +83,7 @@ static ngx_uint_t ngx_http_sub_cmp_index static ngx_int_t ngx_http_sub_output(ngx_http_request_t *r, ngx_http_sub_ctx_t *ctx); static ngx_int_t ngx_http_sub_parse(ngx_http_request_t *r, - ngx_http_sub_ctx_t *ctx); + ngx_http_sub_ctx_t *ctx, ngx_uint_t flush); static ngx_int_t ngx_http_sub_match(ngx_http_sub_ctx_t *ctx, ngx_int_t start, ngx_str_t *m); @@ -287,6 +287,7 @@ ngx_http_sub_body_filter(ngx_http_reques ngx_int_t rc; ngx_buf_t *b; ngx_str_t *sub; + ngx_uint_t flush, last; ngx_chain_t *cl; ngx_http_sub_ctx_t *ctx; ngx_http_sub_match_t *match; @@ -328,6 +329,9 @@ ngx_http_sub_body_filter(ngx_http_reques ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http sub filter \"%V\"", &r->uri); + flush = 0; + last = 0; + while (ctx->in || ctx->buf) { if (ctx->buf == NULL) { @@ -336,11 +340,19 @@ ngx_http_sub_body_filter(ngx_http_reques ctx->pos = ctx->buf->pos; } + if (ctx->buf->flush || ctx->buf->recycled) { + flush = 1; + } + + if (ctx->in == NULL) { + last = flush; + } + b = NULL; while (ctx->pos < ctx->buf->last) { - rc = ngx_http_sub_parse(r, ctx); + rc = ngx_http_sub_parse(r, ctx, last); ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "parse: %i, looked: \"%V\" %p-%p", @@ -592,7 +604,8 @@ ngx_http_sub_output(ngx_http_request_t * static ngx_int_t -ngx_http_sub_parse(ngx_http_request_t *r, ngx_http_sub_ctx_t *ctx) +ngx_http_sub_parse(ngx_http_request_t *r, ngx_http_sub_ctx_t *ctx, + ngx_uint_t flush) { u_char *p, c; ngx_str_t *m; @@ -604,6 +617,7 @@ ngx_http_sub_parse(ngx_http_request_t *r slcf = ngx_http_get_module_loc_conf(r, ngx_http_sub_filter_module); tables = ctx->tables; + match = ctx->matches->elts; offset = ctx->offset; end = ctx->buf->last - ctx->pos; @@ -630,7 +644,6 @@ ngx_http_sub_parse(ngx_http_request_t *r /* a potential match */ start = offset - (ngx_int_t) tables->min_match_len + 1; - match = ctx->matches->elts; i = ngx_max(tables->index[c], ctx->index); j = tables->index[c + 1]; @@ -671,6 +684,26 @@ ngx_http_sub_parse(ngx_http_request_t *r ctx->index = 0; } + if (flush) { + for ( ;; ) { + start = offset - (ngx_int_t) tables->min_match_len + 1; + + if (start >= end) { + break; + } + + for (i = 0; i < ctx->matches->nelts; i++) { + m = &match[i].match; + + if (ngx_http_sub_match(ctx, start, m) == NGX_AGAIN) { + goto again; + } + } + + offset++; + } + } + again: ctx->offset = offset; From mdounin at mdounin.ru Mon Jul 4 14:21:36 2016 From: mdounin at mdounin.ru (Maxim Dounin) Date: Mon, 4 Jul 2016 17:21:36 +0300 Subject: [PATCH 1 of 2] HTTP: add support for trailers in HTTP responses In-Reply-To: References: <20160627134500.GZ30781@mdounin.ru> <20160627175338.GD30781@mdounin.ru> Message-ID: <20160704142135.GZ30781@mdounin.ru> Hello! On Thu, Jun 30, 2016 at 12:56:50PM -0700, Piotr Sikora wrote: > Hey Maxim, > > > Would adding r->trailers_emit (or r->expect_trailers, whichever you > > prefer) make you happy? > > Ping. I'm not convinced this feature is needed at all. It looks more like a Google-specific experiment, and this is not something I would like to see in nginx code. If at all implemented, I would rather prefer adding trailers if a transfer encoding used allows this, and discrading them otherwise. This is something that anyway will happen if a protocol used does not allow trailers at all (e.g., HTTP/1.0). -- Maxim Dounin http://nginx.org/ From vl at nginx.com Mon Jul 4 14:50:11 2016 From: vl at nginx.com (Vladimir Homutov) Date: Mon, 04 Jul 2016 14:50:11 +0000 Subject: [nginx] Stream: added preconfiguration step. Message-ID: details: http://hg.nginx.org/nginx/rev/2f41d383c9c7 branches: changeset: 6606:2f41d383c9c7 user: Vladimir Homutov date: Wed Jun 15 15:10:24 2016 +0300 description: Stream: added preconfiguration step. diffstat: src/stream/ngx_stream.c | 19 +++++++++++++++++-- src/stream/ngx_stream.h | 1 + src/stream/ngx_stream_access_module.c | 1 + src/stream/ngx_stream_core_module.c | 1 + src/stream/ngx_stream_limit_conn_module.c | 1 + src/stream/ngx_stream_proxy_module.c | 1 + src/stream/ngx_stream_ssl_module.c | 1 + src/stream/ngx_stream_upstream.c | 1 + src/stream/ngx_stream_upstream_hash_module.c | 1 + src/stream/ngx_stream_upstream_least_conn_module.c | 1 + src/stream/ngx_stream_upstream_zone_module.c | 1 + 11 files changed, 27 insertions(+), 2 deletions(-) diffs (142 lines): diff -r f379b32e4733 -r 2f41d383c9c7 src/stream/ngx_stream.c --- a/src/stream/ngx_stream.c Sat Jul 02 15:59:53 2016 +0300 +++ b/src/stream/ngx_stream.c Wed Jun 15 15:10:24 2016 +0300 @@ -143,11 +143,26 @@ ngx_stream_block(ngx_conf_t *cf, ngx_com } - /* parse inside the stream{} block */ - pcf = *cf; cf->ctx = ctx; + for (m = 0; cf->cycle->modules[m]; m++) { + if (cf->cycle->modules[m]->type != NGX_STREAM_MODULE) { + continue; + } + + module = cf->cycle->modules[m]->ctx; + + if (module->preconfiguration) { + if (module->preconfiguration(cf) != NGX_OK) { + return NGX_CONF_ERROR; + } + } + } + + + /* parse inside the stream{} block */ + cf->module_type = NGX_STREAM_MODULE; cf->cmd_type = NGX_STREAM_MAIN_CONF; rv = ngx_conf_parse(cf, NULL); diff -r f379b32e4733 -r 2f41d383c9c7 src/stream/ngx_stream.h --- a/src/stream/ngx_stream.h Sat Jul 02 15:59:53 2016 +0300 +++ b/src/stream/ngx_stream.h Wed Jun 15 15:10:24 2016 +0300 @@ -145,6 +145,7 @@ struct ngx_stream_session_s { typedef struct { + ngx_int_t (*preconfiguration)(ngx_conf_t *cf); ngx_int_t (*postconfiguration)(ngx_conf_t *cf); void *(*create_main_conf)(ngx_conf_t *cf); diff -r f379b32e4733 -r 2f41d383c9c7 src/stream/ngx_stream_access_module.c --- a/src/stream/ngx_stream_access_module.c Sat Jul 02 15:59:53 2016 +0300 +++ b/src/stream/ngx_stream_access_module.c Wed Jun 15 15:10:24 2016 +0300 @@ -88,6 +88,7 @@ static ngx_command_t ngx_stream_access_ static ngx_stream_module_t ngx_stream_access_module_ctx = { + NULL, /* preconfiguration */ ngx_stream_access_init, /* postconfiguration */ NULL, /* create main configuration */ diff -r f379b32e4733 -r 2f41d383c9c7 src/stream/ngx_stream_core_module.c --- a/src/stream/ngx_stream_core_module.c Sat Jul 02 15:59:53 2016 +0300 +++ b/src/stream/ngx_stream_core_module.c Wed Jun 15 15:10:24 2016 +0300 @@ -57,6 +57,7 @@ static ngx_command_t ngx_stream_core_co static ngx_stream_module_t ngx_stream_core_module_ctx = { + NULL, /* preconfiguration */ NULL, /* postconfiguration */ ngx_stream_core_create_main_conf, /* create main configuration */ diff -r f379b32e4733 -r 2f41d383c9c7 src/stream/ngx_stream_limit_conn_module.c --- a/src/stream/ngx_stream_limit_conn_module.c Sat Jul 02 15:59:53 2016 +0300 +++ b/src/stream/ngx_stream_limit_conn_module.c Wed Jun 15 15:10:24 2016 +0300 @@ -93,6 +93,7 @@ static ngx_command_t ngx_stream_limit_c static ngx_stream_module_t ngx_stream_limit_conn_module_ctx = { + NULL, /* preconfiguration */ ngx_stream_limit_conn_init, /* postconfiguration */ NULL, /* create main configuration */ diff -r f379b32e4733 -r 2f41d383c9c7 src/stream/ngx_stream_proxy_module.c --- a/src/stream/ngx_stream_proxy_module.c Sat Jul 02 15:59:53 2016 +0300 +++ b/src/stream/ngx_stream_proxy_module.c Wed Jun 15 15:10:24 2016 +0300 @@ -314,6 +314,7 @@ static ngx_command_t ngx_stream_proxy_c static ngx_stream_module_t ngx_stream_proxy_module_ctx = { + NULL, /* preconfiguration */ NULL, /* postconfiguration */ NULL, /* create main configuration */ diff -r f379b32e4733 -r 2f41d383c9c7 src/stream/ngx_stream_ssl_module.c --- a/src/stream/ngx_stream_ssl_module.c Sat Jul 02 15:59:53 2016 +0300 +++ b/src/stream/ngx_stream_ssl_module.c Wed Jun 15 15:10:24 2016 +0300 @@ -132,6 +132,7 @@ static ngx_command_t ngx_stream_ssl_com static ngx_stream_module_t ngx_stream_ssl_module_ctx = { + NULL, /* preconfiguration */ NULL, /* postconfiguration */ NULL, /* create main configuration */ diff -r f379b32e4733 -r 2f41d383c9c7 src/stream/ngx_stream_upstream.c --- a/src/stream/ngx_stream_upstream.c Sat Jul 02 15:59:53 2016 +0300 +++ b/src/stream/ngx_stream_upstream.c Wed Jun 15 15:10:24 2016 +0300 @@ -39,6 +39,7 @@ static ngx_command_t ngx_stream_upstrea static ngx_stream_module_t ngx_stream_upstream_module_ctx = { + NULL, /* preconfiguration */ NULL, /* postconfiguration */ ngx_stream_upstream_create_main_conf, /* create main configuration */ diff -r f379b32e4733 -r 2f41d383c9c7 src/stream/ngx_stream_upstream_hash_module.c --- a/src/stream/ngx_stream_upstream_hash_module.c Sat Jul 02 15:59:53 2016 +0300 +++ b/src/stream/ngx_stream_upstream_hash_module.c Wed Jun 15 15:10:24 2016 +0300 @@ -76,6 +76,7 @@ static ngx_command_t ngx_stream_upstrea static ngx_stream_module_t ngx_stream_upstream_hash_module_ctx = { + NULL, /* preconfiguration */ NULL, /* postconfiguration */ NULL, /* create main configuration */ diff -r f379b32e4733 -r 2f41d383c9c7 src/stream/ngx_stream_upstream_least_conn_module.c --- a/src/stream/ngx_stream_upstream_least_conn_module.c Sat Jul 02 15:59:53 2016 +0300 +++ b/src/stream/ngx_stream_upstream_least_conn_module.c Wed Jun 15 15:10:24 2016 +0300 @@ -32,6 +32,7 @@ static ngx_command_t ngx_stream_upstrea static ngx_stream_module_t ngx_stream_upstream_least_conn_module_ctx = { + NULL, /* preconfiguration */ NULL, /* postconfiguration */ NULL, /* create main configuration */ diff -r f379b32e4733 -r 2f41d383c9c7 src/stream/ngx_stream_upstream_zone_module.c --- a/src/stream/ngx_stream_upstream_zone_module.c Sat Jul 02 15:59:53 2016 +0300 +++ b/src/stream/ngx_stream_upstream_zone_module.c Wed Jun 15 15:10:24 2016 +0300 @@ -32,6 +32,7 @@ static ngx_command_t ngx_stream_upstrea static ngx_stream_module_t ngx_stream_upstream_zone_module_ctx = { + NULL, /* preconfiguration */ NULL, /* postconfiguration */ NULL, /* create main configuration */ From vl at nginx.com Mon Jul 4 14:50:14 2016 From: vl at nginx.com (Vladimir Homutov) Date: Mon, 04 Jul 2016 14:50:14 +0000 Subject: [nginx] Stream: variables and script. Message-ID: details: http://hg.nginx.org/nginx/rev/c70b7f4537e1 branches: changeset: 6607:c70b7f4537e1 user: Vladimir Homutov date: Mon Jul 04 16:37:36 2016 +0300 description: Stream: variables and script. This is a port of corresponding http code with unrelated features excluded. diffstat: auto/modules | 4 + src/stream/ngx_stream.c | 4 + src/stream/ngx_stream.h | 139 +++-- src/stream/ngx_stream_core_module.c | 49 +- src/stream/ngx_stream_handler.c | 9 + src/stream/ngx_stream_script.c | 852 ++++++++++++++++++++++++++++++++++++ src/stream/ngx_stream_script.h | 123 +++++ src/stream/ngx_stream_variables.c | 621 ++++++++++++++++++++++++++ src/stream/ngx_stream_variables.h | 109 ++++ 9 files changed, 1851 insertions(+), 59 deletions(-) diffs (truncated from 2092 to 1000 lines): diff -r 2f41d383c9c7 -r c70b7f4537e1 auto/modules --- a/auto/modules Wed Jun 15 15:10:24 2016 +0300 +++ b/auto/modules Mon Jul 04 16:37:36 2016 +0300 @@ -976,9 +976,13 @@ if [ $STREAM != NO ]; then ngx_stream_upstream_module" ngx_module_incs="src/stream" ngx_module_deps="src/stream/ngx_stream.h \ + src/stream/ngx_stream_variables.h \ + src/stream/ngx_stream_script.h \ src/stream/ngx_stream_upstream.h \ src/stream/ngx_stream_upstream_round_robin.h" ngx_module_srcs="src/stream/ngx_stream.c \ + src/stream/ngx_stream_variables.c \ + src/stream/ngx_stream_script.c \ src/stream/ngx_stream_handler.c \ src/stream/ngx_stream_core_module.c \ src/stream/ngx_stream_proxy_module.c \ diff -r 2f41d383c9c7 -r c70b7f4537e1 src/stream/ngx_stream.c --- a/src/stream/ngx_stream.c Wed Jun 15 15:10:24 2016 +0300 +++ b/src/stream/ngx_stream.c Mon Jul 04 16:37:36 2016 +0300 @@ -230,6 +230,10 @@ ngx_stream_block(ngx_conf_t *cf, ngx_com } } + if (ngx_stream_variables_init_vars(cf) != NGX_OK) { + return NGX_CONF_ERROR; + } + *cf = pcf; diff -r 2f41d383c9c7 -r c70b7f4537e1 src/stream/ngx_stream.h --- a/src/stream/ngx_stream.h Wed Jun 15 15:10:24 2016 +0300 +++ b/src/stream/ngx_stream.h Mon Jul 04 16:37:36 2016 +0300 @@ -20,64 +20,66 @@ typedef struct ngx_stream_session_s ngx_stream_session_t; +#include +#include #include #include typedef struct { - void **main_conf; - void **srv_conf; + void **main_conf; + void **srv_conf; } ngx_stream_conf_ctx_t; typedef struct { - ngx_sockaddr_t sockaddr; - socklen_t socklen; + ngx_sockaddr_t sockaddr; + socklen_t socklen; /* server ctx */ - ngx_stream_conf_ctx_t *ctx; + ngx_stream_conf_ctx_t *ctx; - unsigned bind:1; - unsigned wildcard:1; + unsigned bind:1; + unsigned wildcard:1; #if (NGX_STREAM_SSL) - unsigned ssl:1; + unsigned ssl:1; #endif #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) - unsigned ipv6only:1; + unsigned ipv6only:1; #endif #if (NGX_HAVE_REUSEPORT) - unsigned reuseport:1; + unsigned reuseport:1; #endif - unsigned so_keepalive:2; + unsigned so_keepalive:2; #if (NGX_HAVE_KEEPALIVE_TUNABLE) - int tcp_keepidle; - int tcp_keepintvl; - int tcp_keepcnt; + int tcp_keepidle; + int tcp_keepintvl; + int tcp_keepcnt; #endif - int backlog; - int type; + int backlog; + int type; } ngx_stream_listen_t; typedef struct { - ngx_stream_conf_ctx_t *ctx; - ngx_str_t addr_text; + ngx_stream_conf_ctx_t *ctx; + ngx_str_t addr_text; #if (NGX_STREAM_SSL) - ngx_uint_t ssl; /* unsigned ssl:1; */ + ngx_uint_t ssl; /* unsigned ssl:1; */ #endif } ngx_stream_addr_conf_t; typedef struct { - in_addr_t addr; - ngx_stream_addr_conf_t conf; + in_addr_t addr; + ngx_stream_addr_conf_t conf; } ngx_stream_in_addr_t; #if (NGX_HAVE_INET6) typedef struct { - struct in6_addr addr6; - ngx_stream_addr_conf_t conf; + struct in6_addr addr6; + ngx_stream_addr_conf_t conf; } ngx_stream_in6_addr_t; #endif @@ -85,21 +87,21 @@ typedef struct { typedef struct { /* ngx_stream_in_addr_t or ngx_stream_in6_addr_t */ - void *addrs; - ngx_uint_t naddrs; + void *addrs; + ngx_uint_t naddrs; } ngx_stream_port_t; typedef struct { - int family; - int type; - in_port_t port; - ngx_array_t addrs; /* array of ngx_stream_conf_addr_t */ + int family; + int type; + in_port_t port; + ngx_array_t addrs; /* array of ngx_stream_conf_addr_t */ } ngx_stream_conf_port_t; typedef struct { - ngx_stream_listen_t opt; + ngx_stream_listen_t opt; } ngx_stream_conf_addr_t; @@ -107,10 +109,21 @@ typedef ngx_int_t (*ngx_stream_access_pt typedef struct { - ngx_array_t servers; /* ngx_stream_core_srv_conf_t */ - ngx_array_t listen; /* ngx_stream_listen_t */ - ngx_stream_access_pt limit_conn_handler; - ngx_stream_access_pt access_handler; + ngx_array_t servers; /* ngx_stream_core_srv_conf_t */ + ngx_array_t listen; /* ngx_stream_listen_t */ + + ngx_stream_access_pt limit_conn_handler; + ngx_stream_access_pt access_handler; + + ngx_hash_t variables_hash; + + ngx_array_t variables; /* ngx_stream_variable_t */ + ngx_uint_t ncaptures; + + ngx_uint_t variables_hash_max_size; + ngx_uint_t variables_hash_bucket_size; + + ngx_hash_keys_arrays_t *variables_keys; } ngx_stream_core_main_conf_t; @@ -118,42 +131,54 @@ typedef void (*ngx_stream_handler_pt)(ng typedef struct { - ngx_stream_handler_pt handler; - ngx_stream_conf_ctx_t *ctx; - u_char *file_name; - ngx_int_t line; - ngx_log_t *error_log; - ngx_flag_t tcp_nodelay; + ngx_stream_handler_pt handler; + + ngx_stream_conf_ctx_t *ctx; + + u_char *file_name; + ngx_int_t line; + + ngx_flag_t tcp_nodelay; + + ngx_log_t *error_log; } ngx_stream_core_srv_conf_t; struct ngx_stream_session_s { - uint32_t signature; /* "STRM" */ - - ngx_connection_t *connection; - - off_t received; + uint32_t signature; /* "STRM" */ - ngx_log_handler_pt log_handler; + ngx_connection_t *connection; - void **ctx; - void **main_conf; - void **srv_conf; + off_t received; - ngx_stream_upstream_t *upstream; + ngx_log_handler_pt log_handler; + + void **ctx; + void **main_conf; + void **srv_conf; + + ngx_stream_upstream_t *upstream; + + ngx_stream_variable_value_t *variables; + +#if (NGX_PCRE) + ngx_uint_t ncaptures; + int *captures; + u_char *captures_data; +#endif }; typedef struct { - ngx_int_t (*preconfiguration)(ngx_conf_t *cf); - ngx_int_t (*postconfiguration)(ngx_conf_t *cf); + ngx_int_t (*preconfiguration)(ngx_conf_t *cf); + ngx_int_t (*postconfiguration)(ngx_conf_t *cf); - void *(*create_main_conf)(ngx_conf_t *cf); - char *(*init_main_conf)(ngx_conf_t *cf, void *conf); + void *(*create_main_conf)(ngx_conf_t *cf); + char *(*init_main_conf)(ngx_conf_t *cf, void *conf); - void *(*create_srv_conf)(ngx_conf_t *cf); - char *(*merge_srv_conf)(ngx_conf_t *cf, void *prev, - void *conf); + void *(*create_srv_conf)(ngx_conf_t *cf); + char *(*merge_srv_conf)(ngx_conf_t *cf, void *prev, + void *conf); } ngx_stream_module_t; diff -r 2f41d383c9c7 -r c70b7f4537e1 src/stream/ngx_stream_core_module.c --- a/src/stream/ngx_stream_core_module.c Wed Jun 15 15:10:24 2016 +0300 +++ b/src/stream/ngx_stream_core_module.c Mon Jul 04 16:37:36 2016 +0300 @@ -10,7 +10,9 @@ #include +static ngx_int_t ngx_stream_core_preconfiguration(ngx_conf_t *cf); static void *ngx_stream_core_create_main_conf(ngx_conf_t *cf); +static char *ngx_stream_core_init_main_conf(ngx_conf_t *cf, void *conf); static void *ngx_stream_core_create_srv_conf(ngx_conf_t *cf); static char *ngx_stream_core_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child); @@ -24,6 +26,20 @@ static char *ngx_stream_core_listen(ngx_ static ngx_command_t ngx_stream_core_commands[] = { + { ngx_string("variables_hash_max_size"), + NGX_STREAM_MAIN_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_STREAM_MAIN_CONF_OFFSET, + offsetof(ngx_stream_core_main_conf_t, variables_hash_max_size), + NULL }, + + { ngx_string("variables_hash_bucket_size"), + NGX_STREAM_MAIN_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_STREAM_MAIN_CONF_OFFSET, + offsetof(ngx_stream_core_main_conf_t, variables_hash_bucket_size), + NULL }, + { ngx_string("server"), NGX_STREAM_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS, ngx_stream_core_server, @@ -57,11 +73,11 @@ static ngx_command_t ngx_stream_core_co static ngx_stream_module_t ngx_stream_core_module_ctx = { - NULL, /* preconfiguration */ + ngx_stream_core_preconfiguration, /* preconfiguration */ NULL, /* postconfiguration */ ngx_stream_core_create_main_conf, /* create main configuration */ - NULL, /* init main configuration */ + ngx_stream_core_init_main_conf, /* init main configuration */ ngx_stream_core_create_srv_conf, /* create server configuration */ ngx_stream_core_merge_srv_conf /* merge server configuration */ @@ -84,6 +100,13 @@ ngx_module_t ngx_stream_core_module = { }; +static ngx_int_t +ngx_stream_core_preconfiguration(ngx_conf_t *cf) +{ + return ngx_stream_variables_add_core_vars(cf); +} + + static void * ngx_stream_core_create_main_conf(ngx_conf_t *cf) { @@ -107,10 +130,32 @@ ngx_stream_core_create_main_conf(ngx_con return NULL; } + cmcf->variables_hash_max_size = NGX_CONF_UNSET_UINT; + cmcf->variables_hash_bucket_size = NGX_CONF_UNSET_UINT; + return cmcf; } +static char * +ngx_stream_core_init_main_conf(ngx_conf_t *cf, void *conf) +{ + ngx_stream_core_main_conf_t *cmcf = conf; + + ngx_conf_init_uint_value(cmcf->variables_hash_max_size, 1024); + ngx_conf_init_uint_value(cmcf->variables_hash_bucket_size, 64); + + cmcf->variables_hash_bucket_size = + ngx_align(cmcf->variables_hash_bucket_size, ngx_cacheline_size); + + if (cmcf->ncaptures) { + cmcf->ncaptures = (cmcf->ncaptures + 1) * 3; + } + + return NGX_CONF_OK; +} + + static void * ngx_stream_core_create_srv_conf(ngx_conf_t *cf) { diff -r 2f41d383c9c7 -r c70b7f4537e1 src/stream/ngx_stream_handler.c --- a/src/stream/ngx_stream_handler.c Wed Jun 15 15:10:24 2016 +0300 +++ b/src/stream/ngx_stream_handler.c Mon Jul 04 16:37:36 2016 +0300 @@ -149,6 +149,15 @@ ngx_stream_init_connection(ngx_connectio cmcf = ngx_stream_get_module_main_conf(s, ngx_stream_core_module); + s->variables = ngx_pcalloc(s->connection->pool, + cmcf->variables.nelts + * sizeof(ngx_stream_variable_value_t)); + + if (s->variables == NULL) { + ngx_stream_close_connection(c); + return; + } + if (cmcf->limit_conn_handler) { rc = cmcf->limit_conn_handler(s); diff -r 2f41d383c9c7 -r c70b7f4537e1 src/stream/ngx_stream_script.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/stream/ngx_stream_script.c Mon Jul 04 16:37:36 2016 +0300 @@ -0,0 +1,852 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include + + +static ngx_int_t ngx_stream_script_init_arrays( + ngx_stream_script_compile_t *sc); +static ngx_int_t ngx_stream_script_done(ngx_stream_script_compile_t *sc); +static ngx_int_t ngx_stream_script_add_copy_code( + ngx_stream_script_compile_t *sc, ngx_str_t *value, ngx_uint_t last); +static ngx_int_t ngx_stream_script_add_var_code( + ngx_stream_script_compile_t *sc, ngx_str_t *name); +#if (NGX_PCRE) +static ngx_int_t ngx_stream_script_add_capture_code( + ngx_stream_script_compile_t *sc, ngx_uint_t n); +#endif +static ngx_int_t ngx_stream_script_add_full_name_code( + ngx_stream_script_compile_t *sc); +static size_t ngx_stream_script_full_name_len_code( + ngx_stream_script_engine_t *e); +static void ngx_stream_script_full_name_code(ngx_stream_script_engine_t *e); + + +#define ngx_stream_script_exit (u_char *) &ngx_stream_script_exit_code + +static uintptr_t ngx_stream_script_exit_code = (uintptr_t) NULL; + + +void +ngx_stream_script_flush_complex_value(ngx_stream_session_t *s, + ngx_stream_complex_value_t *val) +{ + ngx_uint_t *index; + + index = val->flushes; + + if (index) { + while (*index != (ngx_uint_t) -1) { + + if (s->variables[*index].no_cacheable) { + s->variables[*index].valid = 0; + s->variables[*index].not_found = 0; + } + + index++; + } + } +} + + +ngx_int_t +ngx_stream_complex_value(ngx_stream_session_t *s, + ngx_stream_complex_value_t *val, ngx_str_t *value) +{ + size_t len; + ngx_stream_script_code_pt code; + ngx_stream_script_engine_t e; + ngx_stream_script_len_code_pt lcode; + + if (val->lengths == NULL) { + *value = val->value; + return NGX_OK; + } + + ngx_stream_script_flush_complex_value(s, val); + + ngx_memzero(&e, sizeof(ngx_stream_script_engine_t)); + + e.ip = val->lengths; + e.session = s; + e.flushed = 1; + + len = 0; + + while (*(uintptr_t *) e.ip) { + lcode = *(ngx_stream_script_len_code_pt *) e.ip; + len += lcode(&e); + } + + value->len = len; + value->data = ngx_pnalloc(s->connection->pool, len); + if (value->data == NULL) { + return NGX_ERROR; + } + + e.ip = val->values; + e.pos = value->data; + e.buf = *value; + + while (*(uintptr_t *) e.ip) { + code = *(ngx_stream_script_code_pt *) e.ip; + code((ngx_stream_script_engine_t *) &e); + } + + *value = e.buf; + + return NGX_OK; +} + + +ngx_int_t +ngx_stream_compile_complex_value(ngx_stream_compile_complex_value_t *ccv) +{ + ngx_str_t *v; + ngx_uint_t i, n, nv, nc; + ngx_array_t flushes, lengths, values, *pf, *pl, *pv; + ngx_stream_script_compile_t sc; + + v = ccv->value; + + nv = 0; + nc = 0; + + for (i = 0; i < v->len; i++) { + if (v->data[i] == '$') { + if (v->data[i + 1] >= '1' && v->data[i + 1] <= '9') { + nc++; + + } else { + nv++; + } + } + } + + if ((v->len == 0 || v->data[0] != '$') + && (ccv->conf_prefix || ccv->root_prefix)) + { + if (ngx_conf_full_name(ccv->cf->cycle, v, ccv->conf_prefix) != NGX_OK) { + return NGX_ERROR; + } + + ccv->conf_prefix = 0; + ccv->root_prefix = 0; + } + + ccv->complex_value->value = *v; + ccv->complex_value->flushes = NULL; + ccv->complex_value->lengths = NULL; + ccv->complex_value->values = NULL; + + if (nv == 0 && nc == 0) { + return NGX_OK; + } + + n = nv + 1; + + if (ngx_array_init(&flushes, ccv->cf->pool, n, sizeof(ngx_uint_t)) + != NGX_OK) + { + return NGX_ERROR; + } + + n = nv * (2 * sizeof(ngx_stream_script_copy_code_t) + + sizeof(ngx_stream_script_var_code_t)) + + sizeof(uintptr_t); + + if (ngx_array_init(&lengths, ccv->cf->pool, n, 1) != NGX_OK) { + return NGX_ERROR; + } + + n = (nv * (2 * sizeof(ngx_stream_script_copy_code_t) + + sizeof(ngx_stream_script_var_code_t)) + + sizeof(uintptr_t) + + v->len + + sizeof(uintptr_t) - 1) + & ~(sizeof(uintptr_t) - 1); + + if (ngx_array_init(&values, ccv->cf->pool, n, 1) != NGX_OK) { + return NGX_ERROR; + } + + pf = &flushes; + pl = &lengths; + pv = &values; + + ngx_memzero(&sc, sizeof(ngx_stream_script_compile_t)); + + sc.cf = ccv->cf; + sc.source = v; + sc.flushes = &pf; + sc.lengths = &pl; + sc.values = &pv; + sc.complete_lengths = 1; + sc.complete_values = 1; + sc.zero = ccv->zero; + sc.conf_prefix = ccv->conf_prefix; + sc.root_prefix = ccv->root_prefix; + + if (ngx_stream_script_compile(&sc) != NGX_OK) { + return NGX_ERROR; + } + + if (flushes.nelts) { + ccv->complex_value->flushes = flushes.elts; + ccv->complex_value->flushes[flushes.nelts] = (ngx_uint_t) -1; + } + + ccv->complex_value->lengths = lengths.elts; + ccv->complex_value->values = values.elts; + + return NGX_OK; +} + + +char * +ngx_stream_set_complex_value_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 != NULL) { + return "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; + + if (ngx_stream_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + + +ngx_uint_t +ngx_stream_script_variables_count(ngx_str_t *value) +{ + ngx_uint_t i, n; + + for (n = 0, i = 0; i < value->len; i++) { + if (value->data[i] == '$') { + n++; + } + } + + return n; +} + + +ngx_int_t +ngx_stream_script_compile(ngx_stream_script_compile_t *sc) +{ + u_char ch; + ngx_str_t name; + ngx_uint_t i, bracket; + + if (ngx_stream_script_init_arrays(sc) != NGX_OK) { + return NGX_ERROR; + } + + for (i = 0; i < sc->source->len; /* void */ ) { + + name.len = 0; + + if (sc->source->data[i] == '$') { + + if (++i == sc->source->len) { + goto invalid_variable; + } + +#if (NGX_PCRE) + { + ngx_uint_t n; + + if (sc->source->data[i] >= '1' && sc->source->data[i] <= '9') { + + n = sc->source->data[i] - '0'; + + if (ngx_stream_script_add_capture_code(sc, n) != NGX_OK) { + return NGX_ERROR; + } + + i++; + + continue; + } + } +#endif + + if (sc->source->data[i] == '{') { + bracket = 1; + + if (++i == sc->source->len) { + goto invalid_variable; + } + + name.data = &sc->source->data[i]; + + } else { + bracket = 0; + name.data = &sc->source->data[i]; + } + + for ( /* void */ ; i < sc->source->len; i++, name.len++) { + ch = sc->source->data[i]; + + if (ch == '}' && bracket) { + i++; + bracket = 0; + break; + } + + if ((ch >= 'A' && ch <= 'Z') + || (ch >= 'a' && ch <= 'z') + || (ch >= '0' && ch <= '9') + || ch == '_') + { + continue; + } + + break; + } + + if (bracket) { + ngx_conf_log_error(NGX_LOG_EMERG, sc->cf, 0, + "the closing bracket in \"%V\" " + "variable is missing", &name); + return NGX_ERROR; + } + + if (name.len == 0) { + goto invalid_variable; + } + + sc->variables++; + + if (ngx_stream_script_add_var_code(sc, &name) != NGX_OK) { + return NGX_ERROR; + } + + continue; + } + + name.data = &sc->source->data[i]; + + while (i < sc->source->len) { + + if (sc->source->data[i] == '$') { + break; + } + + i++; + name.len++; + } + + sc->size += name.len; + + if (ngx_stream_script_add_copy_code(sc, &name, (i == sc->source->len)) + != NGX_OK) + { + return NGX_ERROR; + } + } + + return ngx_stream_script_done(sc); + +invalid_variable: + + ngx_conf_log_error(NGX_LOG_EMERG, sc->cf, 0, "invalid variable name"); + + return NGX_ERROR; +} + + +static ngx_int_t +ngx_stream_script_init_arrays(ngx_stream_script_compile_t *sc) +{ + ngx_uint_t n; + + if (sc->flushes && *sc->flushes == NULL) { + n = sc->variables ? sc->variables : 1; + *sc->flushes = ngx_array_create(sc->cf->pool, n, sizeof(ngx_uint_t)); + if (*sc->flushes == NULL) { + return NGX_ERROR; + } + } + + if (*sc->lengths == NULL) { + n = sc->variables * (2 * sizeof(ngx_stream_script_copy_code_t) + + sizeof(ngx_stream_script_var_code_t)) + + sizeof(uintptr_t); + + *sc->lengths = ngx_array_create(sc->cf->pool, n, 1); + if (*sc->lengths == NULL) { + return NGX_ERROR; + } + } + + if (*sc->values == NULL) { + n = (sc->variables * (2 * sizeof(ngx_stream_script_copy_code_t) + + sizeof(ngx_stream_script_var_code_t)) + + sizeof(uintptr_t) + + sc->source->len + + sizeof(uintptr_t) - 1) + & ~(sizeof(uintptr_t) - 1); + + *sc->values = ngx_array_create(sc->cf->pool, n, 1); + if (*sc->values == NULL) { + return NGX_ERROR; + } + } + + sc->variables = 0; + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_script_done(ngx_stream_script_compile_t *sc) +{ + ngx_str_t zero; + uintptr_t *code; + + if (sc->zero) { + + zero.len = 1; + zero.data = (u_char *) "\0"; + + if (ngx_stream_script_add_copy_code(sc, &zero, 0) != NGX_OK) { + return NGX_ERROR; + } + } + + if (sc->conf_prefix || sc->root_prefix) { + if (ngx_stream_script_add_full_name_code(sc) != NGX_OK) { + return NGX_ERROR; + } + } + + if (sc->complete_lengths) { + code = ngx_stream_script_add_code(*sc->lengths, sizeof(uintptr_t), + NULL); + if (code == NULL) { + return NGX_ERROR; + } + + *code = (uintptr_t) NULL; + } + + if (sc->complete_values) { + code = ngx_stream_script_add_code(*sc->values, sizeof(uintptr_t), + &sc->main); + if (code == NULL) { + return NGX_ERROR; + } + + *code = (uintptr_t) NULL; + } + + return NGX_OK; +} + + +void * +ngx_stream_script_add_code(ngx_array_t *codes, size_t size, void *code) +{ + u_char *elts, **p; + void *new; + + elts = codes->elts; + + new = ngx_array_push_n(codes, size); + if (new == NULL) { + return NULL; + } + + if (code) { + if (elts != codes->elts) { + p = code; + *p += (u_char *) codes->elts - elts; + } + } + + return new; +} + + +static ngx_int_t +ngx_stream_script_add_copy_code(ngx_stream_script_compile_t *sc, + ngx_str_t *value, ngx_uint_t last) +{ + u_char *p; + size_t size, len, zero; + ngx_stream_script_copy_code_t *code; + + zero = (sc->zero && last); + len = value->len + zero; + + code = ngx_stream_script_add_code(*sc->lengths, + sizeof(ngx_stream_script_copy_code_t), + NULL); + if (code == NULL) { + return NGX_ERROR; + } + + code->code = (ngx_stream_script_code_pt) ngx_stream_script_copy_len_code; + code->len = len; + + size = (sizeof(ngx_stream_script_copy_code_t) + len + sizeof(uintptr_t) - 1) + & ~(sizeof(uintptr_t) - 1); + + code = ngx_stream_script_add_code(*sc->values, size, &sc->main); + if (code == NULL) { + return NGX_ERROR; + } + + code->code = ngx_stream_script_copy_code; + code->len = len; + + p = ngx_cpymem((u_char *) code + sizeof(ngx_stream_script_copy_code_t), + value->data, value->len); + + if (zero) { + *p = '\0'; + sc->zero = 0; + } + + return NGX_OK; +} + + +size_t +ngx_stream_script_copy_len_code(ngx_stream_script_engine_t *e) +{ + ngx_stream_script_copy_code_t *code; + + code = (ngx_stream_script_copy_code_t *) e->ip; + + e->ip += sizeof(ngx_stream_script_copy_code_t); + + return code->len; +} + + +void +ngx_stream_script_copy_code(ngx_stream_script_engine_t *e) +{ + u_char *p; + ngx_stream_script_copy_code_t *code; + + code = (ngx_stream_script_copy_code_t *) e->ip; + + p = e->pos; + + if (!e->skip) { + e->pos = ngx_copy(p, e->ip + sizeof(ngx_stream_script_copy_code_t), + code->len); + } + + e->ip += sizeof(ngx_stream_script_copy_code_t) + + ((code->len + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1)); + + ngx_log_debug2(NGX_LOG_DEBUG_STREAM, e->session->connection->log, 0, + "stream script copy: \"%*s\"", e->pos - p, p); +} + + +static ngx_int_t +ngx_stream_script_add_var_code(ngx_stream_script_compile_t *sc, ngx_str_t *name) +{ + ngx_int_t index, *p; + ngx_stream_script_var_code_t *code; + + index = ngx_stream_get_variable_index(sc->cf, name); + + if (index == NGX_ERROR) { + return NGX_ERROR; + } + + if (sc->flushes) { + p = ngx_array_push(*sc->flushes); + if (p == NULL) { + return NGX_ERROR; + } + + *p = index; + } + + code = ngx_stream_script_add_code(*sc->lengths, + sizeof(ngx_stream_script_var_code_t), + NULL); + if (code == NULL) { + return NGX_ERROR; + } + + code->code = (ngx_stream_script_code_pt) + ngx_stream_script_copy_var_len_code; + code->index = (uintptr_t) index; + + code = ngx_stream_script_add_code(*sc->values, + sizeof(ngx_stream_script_var_code_t), + &sc->main); + if (code == NULL) { + return NGX_ERROR; + } + + code->code = ngx_stream_script_copy_var_code; + code->index = (uintptr_t) index; + + return NGX_OK; From vl at nginx.com Mon Jul 4 14:50:17 2016 From: vl at nginx.com (Vladimir Homutov) Date: Mon, 04 Jul 2016 14:50:17 +0000 Subject: [nginx] Stream: core module variables. Message-ID: details: http://hg.nginx.org/nginx/rev/eb4293155e87 branches: changeset: 6608:eb4293155e87 user: Vladimir Homutov date: Tue Jun 14 18:28:14 2016 +0300 description: Stream: core module variables. diffstat: src/stream/ngx_stream_variables.c | 350 ++++++++++++++++++++++++++++++++++++++ 1 files changed, 350 insertions(+), 0 deletions(-) diffs (383 lines): diff -r c70b7f4537e1 -r eb4293155e87 src/stream/ngx_stream_variables.c --- a/src/stream/ngx_stream_variables.c Mon Jul 04 16:37:36 2016 +0300 +++ b/src/stream/ngx_stream_variables.c Tue Jun 14 18:28:14 2016 +0300 @@ -11,15 +11,76 @@ #include +static ngx_int_t ngx_stream_variable_binary_remote_addr( + ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_stream_variable_remote_addr(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_stream_variable_remote_port(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_stream_variable_server_addr(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_stream_variable_server_port(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_stream_variable_bytes_sent(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_stream_variable_connection(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data); + static ngx_int_t ngx_stream_variable_nginx_version(ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_stream_variable_hostname(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_stream_variable_pid(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_stream_variable_msec(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_stream_variable_time_iso8601(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_stream_variable_time_local(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data); static ngx_stream_variable_t ngx_stream_core_variables[] = { + { ngx_string("binary_remote_addr"), NULL, + ngx_stream_variable_binary_remote_addr, 0, 0, 0 }, + + { ngx_string("remote_addr"), NULL, + ngx_stream_variable_remote_addr, 0, 0, 0 }, + + { ngx_string("remote_port"), NULL, + ngx_stream_variable_remote_port, 0, 0, 0 }, + + { ngx_string("server_addr"), NULL, + ngx_stream_variable_server_addr, 0, 0, 0 }, + + { ngx_string("server_port"), NULL, + ngx_stream_variable_server_port, 0, 0, 0 }, + + { ngx_string("bytes_sent"), NULL, ngx_stream_variable_bytes_sent, + 0, 0, 0 }, + + { ngx_string("connection"), NULL, + ngx_stream_variable_connection, 0, 0, 0 }, + { ngx_string("nginx_version"), NULL, ngx_stream_variable_nginx_version, 0, 0, 0 }, + { ngx_string("hostname"), NULL, ngx_stream_variable_hostname, + 0, 0, 0 }, + + { ngx_string("pid"), NULL, ngx_stream_variable_pid, + 0, 0, 0 }, + + { ngx_string("msec"), NULL, ngx_stream_variable_msec, + 0, NGX_STREAM_VAR_NOCACHEABLE, 0 }, + + { ngx_string("time_iso8601"), NULL, ngx_stream_variable_time_iso8601, + 0, NGX_STREAM_VAR_NOCACHEABLE, 0 }, + + { ngx_string("time_local"), NULL, ngx_stream_variable_time_local, + 0, NGX_STREAM_VAR_NOCACHEABLE, 0 }, + { ngx_null_string, NULL, NULL, 0, 0, 0 } }; @@ -259,6 +320,189 @@ ngx_stream_get_variable(ngx_stream_sessi static ngx_int_t +ngx_stream_variable_binary_remote_addr(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data) + { + struct sockaddr_in *sin; +#if (NGX_HAVE_INET6) + struct sockaddr_in6 *sin6; +#endif + + switch (s->connection->sockaddr->sa_family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + sin6 = (struct sockaddr_in6 *) s->connection->sockaddr; + + v->len = sizeof(struct in6_addr); + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = sin6->sin6_addr.s6_addr; + + break; +#endif + + default: /* AF_INET */ + sin = (struct sockaddr_in *) s->connection->sockaddr; + + v->len = sizeof(in_addr_t); + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = (u_char *) &sin->sin_addr; + + break; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_variable_remote_addr(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data) +{ + v->len = s->connection->addr_text.len; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = s->connection->addr_text.data; + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_variable_remote_port(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data) +{ + ngx_uint_t port; + + v->len = 0; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + + v->data = ngx_pnalloc(s->connection->pool, sizeof("65535") - 1); + if (v->data == NULL) { + return NGX_ERROR; + } + + port = ngx_inet_get_port(s->connection->sockaddr); + + if (port > 0 && port < 65536) { + v->len = ngx_sprintf(v->data, "%ui", port) - v->data; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_variable_server_addr(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data) +{ + ngx_str_t str; + u_char addr[NGX_SOCKADDR_STRLEN]; + + str.len = NGX_SOCKADDR_STRLEN; + str.data = addr; + + if (ngx_connection_local_sockaddr(s->connection, &str, 0) != NGX_OK) { + return NGX_ERROR; + } + + str.data = ngx_pnalloc(s->connection->pool, str.len); + if (str.data == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(str.data, addr, str.len); + + v->len = str.len; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = str.data; + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_variable_server_port(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data) +{ + ngx_uint_t port; + + v->len = 0; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + + if (ngx_connection_local_sockaddr(s->connection, NULL, 0) != NGX_OK) { + return NGX_ERROR; + } + + v->data = ngx_pnalloc(s->connection->pool, sizeof("65535") - 1); + if (v->data == NULL) { + return NGX_ERROR; + } + + port = ngx_inet_get_port(s->connection->local_sockaddr); + + if (port > 0 && port < 65536) { + v->len = ngx_sprintf(v->data, "%ui", port) - v->data; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_variable_bytes_sent(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data) +{ + u_char *p; + + p = ngx_pnalloc(s->connection->pool, NGX_OFF_T_LEN); + if (p == NULL) { + return NGX_ERROR; + } + + v->len = ngx_sprintf(p, "%O", s->connection->sent) - p; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = p; + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_variable_connection(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data) +{ + u_char *p; + + p = ngx_pnalloc(s->connection->pool, NGX_ATOMIC_T_LEN); + if (p == NULL) { + return NGX_ERROR; + } + + v->len = ngx_sprintf(p, "%uA", s->connection->number) - p; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = p; + + return NGX_OK; +} + + +static ngx_int_t ngx_stream_variable_nginx_version(ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data) { @@ -272,6 +516,112 @@ ngx_stream_variable_nginx_version(ngx_st } +static ngx_int_t +ngx_stream_variable_hostname(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data) +{ + v->len = ngx_cycle->hostname.len; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = ngx_cycle->hostname.data; + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_variable_pid(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data) +{ + u_char *p; + + p = ngx_pnalloc(s->connection->pool, NGX_INT64_LEN); + if (p == NULL) { + return NGX_ERROR; + } + + v->len = ngx_sprintf(p, "%P", ngx_pid) - p; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = p; + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_variable_msec(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data) +{ + u_char *p; + ngx_time_t *tp; + + p = ngx_pnalloc(s->connection->pool, NGX_TIME_T_LEN + 4); + if (p == NULL) { + return NGX_ERROR; + } + + tp = ngx_timeofday(); + + v->len = ngx_sprintf(p, "%T.%03M", tp->sec, tp->msec) - p; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = p; + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_variable_time_iso8601(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data) +{ + u_char *p; + + p = ngx_pnalloc(s->connection->pool, ngx_cached_http_log_iso8601.len); + if (p == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(p, ngx_cached_http_log_iso8601.data, + ngx_cached_http_log_iso8601.len); + + v->len = ngx_cached_http_log_iso8601.len; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = p; + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_variable_time_local(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data) +{ + u_char *p; + + p = ngx_pnalloc(s->connection->pool, ngx_cached_http_log_time.len); + if (p == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(p, ngx_cached_http_log_time.data, ngx_cached_http_log_time.len); + + v->len = ngx_cached_http_log_time.len; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = p; + + return NGX_OK; +} + + void * ngx_stream_map_find(ngx_stream_session_t *s, ngx_stream_map_t *map, ngx_str_t *match) From vl at nginx.com Mon Jul 4 14:50:20 2016 From: vl at nginx.com (Vladimir Homutov) Date: Mon, 04 Jul 2016 14:50:20 +0000 Subject: [nginx] Stream: map module. Message-ID: details: http://hg.nginx.org/nginx/rev/73543af69f14 branches: changeset: 6609:73543af69f14 user: Vladimir Homutov date: Wed Jun 29 12:46:12 2016 +0300 description: Stream: map module. diffstat: auto/modules | 8 + auto/options | 3 + src/stream/ngx_stream_map_module.c | 574 +++++++++++++++++++++++++++++++++++++ 3 files changed, 585 insertions(+), 0 deletions(-) diffs (623 lines): diff -r eb4293155e87 -r 73543af69f14 auto/modules --- a/auto/modules Tue Jun 14 18:28:14 2016 +0300 +++ b/auto/modules Wed Jun 29 12:46:12 2016 +0300 @@ -1020,6 +1020,14 @@ if [ $STREAM != NO ]; then . auto/module fi + if [ $STREAM_MAP = YES ]; then + ngx_module_name=ngx_stream_map_module + ngx_module_deps= + ngx_module_srcs=src/stream/ngx_stream_map_module.c + + . auto/module + fi + if [ $STREAM_UPSTREAM_HASH = YES ]; then ngx_module_name=ngx_stream_upstream_hash_module ngx_module_deps= diff -r eb4293155e87 -r 73543af69f14 auto/options --- a/auto/options Tue Jun 14 18:28:14 2016 +0300 +++ b/auto/options Wed Jun 29 12:46:12 2016 +0300 @@ -117,6 +117,7 @@ STREAM=NO STREAM_SSL=NO STREAM_LIMIT_CONN=YES STREAM_ACCESS=YES +STREAM_MAP=YES STREAM_UPSTREAM_HASH=YES STREAM_UPSTREAM_LEAST_CONN=YES STREAM_UPSTREAM_ZONE=YES @@ -294,6 +295,7 @@ use the \"--with-mail_ssl_module\" optio --without-stream_limit_conn_module) STREAM_LIMIT_CONN=NO ;; --without-stream_access_module) STREAM_ACCESS=NO ;; + --without-stream_map_module) STREAM_MAP=NO ;; --without-stream_upstream_hash_module) STREAM_UPSTREAM_HASH=NO ;; --without-stream_upstream_least_conn_module) @@ -492,6 +494,7 @@ cat << END --with-stream_ssl_module enable ngx_stream_ssl_module --without-stream_limit_conn_module disable ngx_stream_limit_conn_module --without-stream_access_module disable ngx_stream_access_module + --without-stream_map_module disable ngx_stream_map_module --without-stream_upstream_hash_module disable ngx_stream_upstream_hash_module --without-stream_upstream_least_conn_module diff -r eb4293155e87 -r 73543af69f14 src/stream/ngx_stream_map_module.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/stream/ngx_stream_map_module.c Wed Jun 29 12:46:12 2016 +0300 @@ -0,0 +1,574 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include + + +typedef struct { + ngx_uint_t hash_max_size; + ngx_uint_t hash_bucket_size; +} ngx_stream_map_conf_t; + + +typedef struct { + ngx_hash_keys_arrays_t keys; + + ngx_array_t *values_hash; +#if (NGX_PCRE) + ngx_array_t regexes; +#endif + + ngx_stream_variable_value_t *default_value; + ngx_conf_t *cf; + ngx_uint_t hostnames; /* unsigned hostnames:1 */ +} ngx_stream_map_conf_ctx_t; + + +typedef struct { + ngx_stream_map_t map; + ngx_stream_complex_value_t value; + ngx_stream_variable_value_t *default_value; + ngx_uint_t hostnames; /* unsigned hostnames:1 */ +} ngx_stream_map_ctx_t; + + +static int ngx_libc_cdecl ngx_stream_map_cmp_dns_wildcards(const void *one, + const void *two); +static void *ngx_stream_map_create_conf(ngx_conf_t *cf); +static char *ngx_stream_map_block(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static char *ngx_stream_map(ngx_conf_t *cf, ngx_command_t *dummy, void *conf); + + +static ngx_command_t ngx_stream_map_commands[] = { + + { ngx_string("map"), + NGX_STREAM_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_TAKE2, + ngx_stream_map_block, + NGX_STREAM_MAIN_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("map_hash_max_size"), + NGX_STREAM_MAIN_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_STREAM_MAIN_CONF_OFFSET, + offsetof(ngx_stream_map_conf_t, hash_max_size), + NULL }, + + { ngx_string("map_hash_bucket_size"), + NGX_STREAM_MAIN_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_STREAM_MAIN_CONF_OFFSET, + offsetof(ngx_stream_map_conf_t, hash_bucket_size), + NULL }, + + ngx_null_command +}; + + +static ngx_stream_module_t ngx_stream_map_module_ctx = { + NULL, /* preconfiguration */ + NULL, /* postconfiguration */ + + ngx_stream_map_create_conf, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ +}; + + +ngx_module_t ngx_stream_map_module = { + NGX_MODULE_V1, + &ngx_stream_map_module_ctx, /* module context */ + ngx_stream_map_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_map_variable(ngx_stream_session_t *s, ngx_stream_variable_value_t *v, + uintptr_t data) +{ + ngx_stream_map_ctx_t *map = (ngx_stream_map_ctx_t *) data; + + ngx_str_t val, str; + ngx_stream_complex_value_t *cv; + ngx_stream_variable_value_t *value; + + ngx_log_debug0(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, + "stream map started"); + + if (ngx_stream_complex_value(s, &map->value, &val) != NGX_OK) { + return NGX_ERROR; + } + + if (map->hostnames && val.len > 0 && val.data[val.len - 1] == '.') { + val.len--; + } + + value = ngx_stream_map_find(s, &map->map, &val); + + if (value == NULL) { + value = map->default_value; + } + + if (!value->valid) { + cv = (ngx_stream_complex_value_t *) value->data; + + if (ngx_stream_complex_value(s, cv, &str) != NGX_OK) { + return NGX_ERROR; + } + + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->len = str.len; + v->data = str.data; + + } else { + *v = *value; + } + + ngx_log_debug2(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, + "stream map: \"%V\" \"%v\"", &val, v); + + return NGX_OK; +} + + +static void * +ngx_stream_map_create_conf(ngx_conf_t *cf) +{ + ngx_stream_map_conf_t *mcf; + + mcf = ngx_palloc(cf->pool, sizeof(ngx_stream_map_conf_t)); + if (mcf == NULL) { + return NULL; + } + + mcf->hash_max_size = NGX_CONF_UNSET_UINT; + mcf->hash_bucket_size = NGX_CONF_UNSET_UINT; + + return mcf; +} + + +static char * +ngx_stream_map_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_stream_map_conf_t *mcf = conf; + + char *rv; + ngx_str_t *value, name; + ngx_conf_t save; + ngx_pool_t *pool; + ngx_hash_init_t hash; + ngx_stream_map_ctx_t *map; + ngx_stream_variable_t *var; + ngx_stream_map_conf_ctx_t ctx; + ngx_stream_compile_complex_value_t ccv; + + if (mcf->hash_max_size == NGX_CONF_UNSET_UINT) { + mcf->hash_max_size = 2048; + } + + if (mcf->hash_bucket_size == NGX_CONF_UNSET_UINT) { + mcf->hash_bucket_size = ngx_cacheline_size; + + } else { + mcf->hash_bucket_size = ngx_align(mcf->hash_bucket_size, + ngx_cacheline_size); + } + + map = ngx_pcalloc(cf->pool, sizeof(ngx_stream_map_ctx_t)); + if (map == 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 = &map->value; + + if (ngx_stream_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + name = value[2]; + + if (name.data[0] != '$') { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid variable name \"%V\"", &name); + return NGX_CONF_ERROR; + } + + name.len--; + name.data++; + + var = ngx_stream_add_variable(cf, &name, NGX_STREAM_VAR_CHANGEABLE); + if (var == NULL) { + return NGX_CONF_ERROR; + } + + var->get_handler = ngx_stream_map_variable; + var->data = (uintptr_t) map; + + pool = ngx_create_pool(NGX_DEFAULT_POOL_SIZE, cf->log); + if (pool == NULL) { + return NGX_CONF_ERROR; + } + + ctx.keys.pool = cf->pool; + ctx.keys.temp_pool = pool; + + if (ngx_hash_keys_array_init(&ctx.keys, NGX_HASH_LARGE) != NGX_OK) { + ngx_destroy_pool(pool); + return NGX_CONF_ERROR; + } + + ctx.values_hash = ngx_pcalloc(pool, sizeof(ngx_array_t) * ctx.keys.hsize); + if (ctx.values_hash == NULL) { + ngx_destroy_pool(pool); + return NGX_CONF_ERROR; + } + +#if (NGX_PCRE) + if (ngx_array_init(&ctx.regexes, cf->pool, 2, + sizeof(ngx_stream_map_regex_t)) + != NGX_OK) + { + ngx_destroy_pool(pool); + return NGX_CONF_ERROR; + } +#endif + + ctx.default_value = NULL; + ctx.cf = &save; + ctx.hostnames = 0; + + save = *cf; + cf->pool = pool; + cf->ctx = &ctx; + cf->handler = ngx_stream_map; + cf->handler_conf = conf; + + rv = ngx_conf_parse(cf, NULL); + + *cf = save; + + if (rv != NGX_CONF_OK) { + ngx_destroy_pool(pool); + return rv; + } + + map->default_value = ctx.default_value ? ctx.default_value: + &ngx_stream_variable_null_value; + + map->hostnames = ctx.hostnames; + + hash.key = ngx_hash_key_lc; + hash.max_size = mcf->hash_max_size; + hash.bucket_size = mcf->hash_bucket_size; + hash.name = "map_hash"; + hash.pool = cf->pool; + + if (ctx.keys.keys.nelts) { + hash.hash = &map->map.hash.hash; + hash.temp_pool = NULL; + + if (ngx_hash_init(&hash, ctx.keys.keys.elts, ctx.keys.keys.nelts) + != NGX_OK) + { + ngx_destroy_pool(pool); + return NGX_CONF_ERROR; + } + } + + if (ctx.keys.dns_wc_head.nelts) { + + ngx_qsort(ctx.keys.dns_wc_head.elts, + (size_t) ctx.keys.dns_wc_head.nelts, + sizeof(ngx_hash_key_t), ngx_stream_map_cmp_dns_wildcards); + + hash.hash = NULL; + hash.temp_pool = pool; + + if (ngx_hash_wildcard_init(&hash, ctx.keys.dns_wc_head.elts, + ctx.keys.dns_wc_head.nelts) + != NGX_OK) + { + ngx_destroy_pool(pool); + return NGX_CONF_ERROR; + } + + map->map.hash.wc_head = (ngx_hash_wildcard_t *) hash.hash; + } + + if (ctx.keys.dns_wc_tail.nelts) { + + ngx_qsort(ctx.keys.dns_wc_tail.elts, + (size_t) ctx.keys.dns_wc_tail.nelts, + sizeof(ngx_hash_key_t), ngx_stream_map_cmp_dns_wildcards); + + hash.hash = NULL; + hash.temp_pool = pool; + + if (ngx_hash_wildcard_init(&hash, ctx.keys.dns_wc_tail.elts, + ctx.keys.dns_wc_tail.nelts) + != NGX_OK) + { + ngx_destroy_pool(pool); + return NGX_CONF_ERROR; + } + + map->map.hash.wc_tail = (ngx_hash_wildcard_t *) hash.hash; + } + +#if (NGX_PCRE) + + if (ctx.regexes.nelts) { + map->map.regex = ctx.regexes.elts; + map->map.nregex = ctx.regexes.nelts; + } + +#endif + + ngx_destroy_pool(pool); + + return rv; +} + + +static int ngx_libc_cdecl +ngx_stream_map_cmp_dns_wildcards(const void *one, const void *two) +{ + ngx_hash_key_t *first, *second; + + first = (ngx_hash_key_t *) one; + second = (ngx_hash_key_t *) two; + + return ngx_dns_strcmp(first->key.data, second->key.data); +} + + +static char * +ngx_stream_map(ngx_conf_t *cf, ngx_command_t *dummy, void *conf) +{ + u_char *data; + size_t len; + ngx_int_t rv; + ngx_str_t *value, v; + ngx_uint_t i, key; + ngx_stream_map_conf_ctx_t *ctx; + ngx_stream_complex_value_t cv, *cvp; + ngx_stream_variable_value_t *var, **vp; + ngx_stream_compile_complex_value_t ccv; + + ctx = cf->ctx; + + value = cf->args->elts; + + if (cf->args->nelts == 1 + && ngx_strcmp(value[0].data, "hostnames") == 0) + { + ctx->hostnames = 1; + return NGX_CONF_OK; + + } else if (cf->args->nelts != 2) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid number of the map parameters"); + return NGX_CONF_ERROR; + } + + if (ngx_strcmp(value[0].data, "include") == 0) { + return ngx_conf_include(cf, dummy, conf); + } + + key = 0; + + for (i = 0; i < value[1].len; i++) { + key = ngx_hash(key, value[1].data[i]); + } + + key %= ctx->keys.hsize; + + vp = ctx->values_hash[key].elts; + + if (vp) { + for (i = 0; i < ctx->values_hash[key].nelts; i++) { + + if (vp[i]->valid) { + data = vp[i]->data; + len = vp[i]->len; + + } else { + cvp = (ngx_stream_complex_value_t *) vp[i]->data; + data = cvp->value.data; + len = cvp->value.len; + } + + if (value[1].len != len) { + continue; + } + + if (ngx_strncmp(value[1].data, data, len) == 0) { + var = vp[i]; + goto found; + } + } + + } else { + if (ngx_array_init(&ctx->values_hash[key], cf->pool, 4, + sizeof(ngx_stream_variable_value_t *)) + != NGX_OK) + { + return NGX_CONF_ERROR; + } + } + + var = ngx_palloc(ctx->keys.pool, sizeof(ngx_stream_variable_value_t)); + if (var == NULL) { + return NGX_CONF_ERROR; + } + + v.len = value[1].len; + v.data = ngx_pstrdup(ctx->keys.pool, &value[1]); + if (v.data == NULL) { + return NGX_CONF_ERROR; + } + + ngx_memzero(&ccv, sizeof(ngx_stream_compile_complex_value_t)); + + ccv.cf = ctx->cf; + ccv.value = &v; + ccv.complex_value = &cv; + + if (ngx_stream_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + if (cv.lengths != NULL) { + cvp = ngx_palloc(ctx->keys.pool, sizeof(ngx_stream_complex_value_t)); + if (cvp == NULL) { + return NGX_CONF_ERROR; + } + + *cvp = cv; + + var->len = 0; + var->data = (u_char *) cvp; + var->valid = 0; + + } else { + var->len = v.len; + var->data = v.data; + var->valid = 1; + } + + var->no_cacheable = 0; + var->not_found = 0; + + vp = ngx_array_push(&ctx->values_hash[key]); + if (vp == NULL) { + return NGX_CONF_ERROR; + } + + *vp = var; + +found: + + if (ngx_strcmp(value[0].data, "default") == 0) { + + if (ctx->default_value) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "duplicate default map parameter"); + return NGX_CONF_ERROR; + } + + ctx->default_value = var; + + return NGX_CONF_OK; + } + +#if (NGX_PCRE) + + if (value[0].len && value[0].data[0] == '~') { + ngx_regex_compile_t rc; + ngx_stream_map_regex_t *regex; + u_char errstr[NGX_MAX_CONF_ERRSTR]; + + regex = ngx_array_push(&ctx->regexes); + if (regex == NULL) { + return NGX_CONF_ERROR; + } + + value[0].len--; + value[0].data++; + + ngx_memzero(&rc, sizeof(ngx_regex_compile_t)); + + if (value[0].data[0] == '*') { + value[0].len--; + value[0].data++; + rc.options = NGX_REGEX_CASELESS; + } + + rc.pattern = value[0]; + rc.err.len = NGX_MAX_CONF_ERRSTR; + rc.err.data = errstr; + + regex->regex = ngx_stream_regex_compile(ctx->cf, &rc); + if (regex->regex == NULL) { + return NGX_CONF_ERROR; + } + + regex->value = var; + + return NGX_CONF_OK; + } + +#endif + + if (value[0].len && value[0].data[0] == '\\') { + value[0].len--; + value[0].data++; + } + + rv = ngx_hash_add_key(&ctx->keys, &value[0], var, + (ctx->hostnames) ? NGX_HASH_WILDCARD_KEY : 0); + + if (rv == NGX_OK) { + return NGX_CONF_OK; + } + + if (rv == NGX_DECLINED) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid hostname or wildcard \"%V\"", &value[0]); + } + + if (rv == NGX_BUSY) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "conflicting parameter \"%V\"", &value[0]); + } + + return NGX_CONF_ERROR; +} From vl at nginx.com Mon Jul 4 14:50:23 2016 From: vl at nginx.com (Vladimir Homutov) Date: Mon, 04 Jul 2016 14:50:23 +0000 Subject: [nginx] Stream: got rid of pseudo variables. Message-ID: details: http://hg.nginx.org/nginx/rev/d5b5866c06c4 branches: changeset: 6610:d5b5866c06c4 user: Vladimir Homutov date: Wed Jun 29 12:46:12 2016 +0300 description: Stream: got rid of pseudo variables. Stream limit_conn, upstream_hash and proxy modules now use complex values. diffstat: src/stream/ngx_stream_limit_conn_module.c | 121 ++++++++++++++------------ src/stream/ngx_stream_proxy_module.c | 76 ++++++++++------ src/stream/ngx_stream_upstream_hash_module.c | 23 +++- 3 files changed, 126 insertions(+), 94 deletions(-) diffs (381 lines): diff -r 73543af69f14 -r d5b5866c06c4 src/stream/ngx_stream_limit_conn_module.c --- a/src/stream/ngx_stream_limit_conn_module.c Wed Jun 29 12:46:12 2016 +0300 +++ b/src/stream/ngx_stream_limit_conn_module.c Wed Jun 29 12:46:12 2016 +0300 @@ -11,33 +11,34 @@ typedef struct { - u_char color; - u_char len; - u_short conn; - u_char data[1]; + u_char color; + u_char len; + u_short conn; + u_char data[1]; } ngx_stream_limit_conn_node_t; typedef struct { - ngx_shm_zone_t *shm_zone; - ngx_rbtree_node_t *node; + ngx_shm_zone_t *shm_zone; + ngx_rbtree_node_t *node; } ngx_stream_limit_conn_cleanup_t; typedef struct { - ngx_rbtree_t *rbtree; + ngx_rbtree_t *rbtree; + ngx_stream_complex_value_t key; } ngx_stream_limit_conn_ctx_t; typedef struct { - ngx_shm_zone_t *shm_zone; - ngx_uint_t conn; + ngx_shm_zone_t *shm_zone; + ngx_uint_t conn; } ngx_stream_limit_conn_limit_t; typedef struct { - ngx_array_t limits; - ngx_uint_t log_level; + ngx_array_t limits; + ngx_uint_t log_level; } ngx_stream_limit_conn_conf_t; @@ -130,48 +131,36 @@ ngx_stream_limit_conn_handler(ngx_stream ngx_slab_pool_t *shpool; ngx_rbtree_node_t *node; ngx_pool_cleanup_t *cln; - struct sockaddr_in *sin; -#if (NGX_HAVE_INET6) - struct sockaddr_in6 *sin6; -#endif ngx_stream_limit_conn_ctx_t *ctx; ngx_stream_limit_conn_node_t *lc; ngx_stream_limit_conn_conf_t *lccf; ngx_stream_limit_conn_limit_t *limits; ngx_stream_limit_conn_cleanup_t *lccln; - switch (s->connection->sockaddr->sa_family) { - - case AF_INET: - sin = (struct sockaddr_in *) s->connection->sockaddr; - - key.len = sizeof(in_addr_t); - key.data = (u_char *) &sin->sin_addr; - - break; - -#if (NGX_HAVE_INET6) - case AF_INET6: - sin6 = (struct sockaddr_in6 *) s->connection->sockaddr; - - key.len = sizeof(struct in6_addr); - key.data = sin6->sin6_addr.s6_addr; - - break; -#endif - - default: - return NGX_DECLINED; - } - - hash = ngx_crc32_short(key.data, key.len); - lccf = ngx_stream_get_module_srv_conf(s, ngx_stream_limit_conn_module); limits = lccf->limits.elts; for (i = 0; i < lccf->limits.nelts; i++) { ctx = limits[i].shm_zone->data; + if (ngx_stream_complex_value(s, &ctx->key, &key) != NGX_OK) { + return NGX_ERROR; + } + + if (key.len == 0) { + continue; + } + + if (key.len > 255) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "the value of the \"%V\" key " + "is more than 255 bytes: \"%V\"", + &ctx->key.value, &key); + continue; + } + + hash = ngx_crc32_short(key.data, key.len); + shpool = (ngx_slab_pool_t *) limits[i].shm_zone->shm.addr; ngx_shmtx_lock(&shpool->mutex); @@ -383,6 +372,19 @@ ngx_stream_limit_conn_init_zone(ngx_shm_ ctx = shm_zone->data; if (octx) { + if (ctx->key.value.len != octx->key.value.len + || ngx_strncmp(ctx->key.value.data, octx->key.value.data, + ctx->key.value.len) + != 0) + { + ngx_log_error(NGX_LOG_EMERG, shm_zone->shm.log, 0, + "limit_conn_zone \"%V\" uses the \"%V\" key " + "while previously it used the \"%V\" key", + &shm_zone->shm.name, &ctx->key.value, + &octx->key.value); + return NGX_ERROR; + } + ctx->rbtree = octx->rbtree; return NGX_OK; @@ -466,12 +468,13 @@ ngx_stream_limit_conn_merge_conf(ngx_con static char * ngx_stream_limit_conn_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { - u_char *p; - ssize_t size; - ngx_str_t *value, name, s; - ngx_uint_t i; - ngx_shm_zone_t *shm_zone; - ngx_stream_limit_conn_ctx_t *ctx; + u_char *p; + ssize_t size; + ngx_str_t *value, name, s; + ngx_uint_t i; + ngx_shm_zone_t *shm_zone; + ngx_stream_limit_conn_ctx_t *ctx; + ngx_stream_compile_complex_value_t ccv; value = cf->args->elts; @@ -480,6 +483,16 @@ ngx_stream_limit_conn_zone(ngx_conf_t *c return NGX_CONF_ERROR; } + ngx_memzero(&ccv, sizeof(ngx_stream_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[1]; + ccv.complex_value = &ctx->key; + + if (ngx_stream_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + size = 0; name.len = 0; @@ -538,17 +551,11 @@ ngx_stream_limit_conn_zone(ngx_conf_t *c } if (shm_zone->data) { + ctx = shm_zone->data; + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "%V \"%V\" is already bound to key " - "\"$binary_remote_addr\"", - &cmd->name, &name); - return NGX_CONF_ERROR; - } - - if (ngx_strcmp(value[1].data, "$binary_remote_addr") != 0) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "unsupported key \"%V\", use " - "$binary_remote_addr", &value[1]); + "%V \"%V\" is already bound to key \"%V\"", + &cmd->name, &name, &ctx->key.value); return NGX_CONF_ERROR; } diff -r 73543af69f14 -r d5b5866c06c4 src/stream/ngx_stream_proxy_module.c --- a/src/stream/ngx_stream_proxy_module.c Wed Jun 29 12:46:12 2016 +0300 +++ b/src/stream/ngx_stream_proxy_module.c Wed Jun 29 12:46:12 2016 +0300 @@ -12,10 +12,10 @@ typedef struct { ngx_addr_t *addr; + ngx_stream_complex_value_t *value; #if (NGX_HAVE_TRANSPARENT_PROXY) - unsigned transparent:1; + ngx_uint_t transparent; /* unsigned transparent:1; */ #endif - unsigned no_port:1; } ngx_stream_upstream_local_t; @@ -448,8 +448,9 @@ static ngx_int_t ngx_stream_proxy_set_local(ngx_stream_session_t *s, ngx_stream_upstream_t *u, ngx_stream_upstream_local_t *local) { - ngx_addr_t *addr; - ngx_connection_t *c; + ngx_int_t rc; + ngx_str_t val; + ngx_addr_t *addr; if (local == NULL) { u->peer.local = NULL; @@ -460,36 +461,36 @@ ngx_stream_proxy_set_local(ngx_stream_se u->peer.transparent = local->transparent; #endif - if (local->addr) { + if (local->value == NULL) { u->peer.local = local->addr; return NGX_OK; } - /* $remote_addr, $remote_addr:$remote_port, [$remote_addr]:$remote_port */ + if (ngx_stream_complex_value(s, local->value, &val) != NGX_OK) { + return NGX_ERROR; + } - c = s->connection; + if (val.len == 0) { + return NGX_OK; + } - addr = ngx_palloc(c->pool, sizeof(ngx_addr_t)); + addr = ngx_palloc(s->connection->pool, sizeof(ngx_addr_t)); if (addr == NULL) { return NGX_ERROR; } - addr->socklen = c->socklen; - - if (local->no_port) { - addr->sockaddr = ngx_palloc(c->pool, addr->socklen); - if (addr->sockaddr == NULL) { - return NGX_ERROR; - } - - ngx_memcpy(addr->sockaddr, c->sockaddr, c->socklen); - ngx_inet_set_port(addr->sockaddr, 0); - - } else { - addr->sockaddr = c->sockaddr; + rc = ngx_parse_addr_port(s->connection->pool, addr, val.data, val.len); + if (rc == NGX_ERROR) { + return NGX_ERROR; } - addr->name = c->addr_text; + if (rc != NGX_OK) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "invalid local address \"%V\"", &val); + return NGX_OK; + } + + addr->name = val; u->peer.local = addr; return NGX_OK; @@ -1699,9 +1700,11 @@ ngx_stream_proxy_bind(ngx_conf_t *cf, ng { ngx_stream_proxy_srv_conf_t *pscf = conf; - ngx_int_t rc; - ngx_str_t *value; - ngx_stream_upstream_local_t *local; + ngx_int_t rc; + ngx_str_t *value; + ngx_stream_complex_value_t cv; + ngx_stream_upstream_local_t *local; + ngx_stream_compile_complex_value_t ccv; if (pscf->local != NGX_CONF_UNSET_PTR) { return "is duplicate"; @@ -1714,6 +1717,16 @@ ngx_stream_proxy_bind(ngx_conf_t *cf, ng return NGX_CONF_OK; } + ngx_memzero(&ccv, sizeof(ngx_stream_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[1]; + ccv.complex_value = &cv; + + if (ngx_stream_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + local = ngx_pcalloc(cf->pool, sizeof(ngx_stream_upstream_local_t)); if (local == NULL) { return NGX_CONF_ERROR; @@ -1721,12 +1734,15 @@ ngx_stream_proxy_bind(ngx_conf_t *cf, ng pscf->local = local; - if (ngx_strcmp(value[1].data, "$remote_addr") == 0) { - local->no_port = 1; + if (cv.lengths) { + local->value = ngx_palloc(cf->pool, sizeof(ngx_stream_complex_value_t)); + if (local->value == NULL) { + return NGX_CONF_ERROR; + } - } else if (ngx_strcmp(value[1].data, "$remote_addr:$remote_port") != 0 - && ngx_strcmp(value[1].data, "[$remote_addr]:$remote_port") != 0) - { + *local->value = cv; + + } else { local->addr = ngx_palloc(cf->pool, sizeof(ngx_addr_t)); if (local->addr == NULL) { return NGX_CONF_ERROR; diff -r 73543af69f14 -r d5b5866c06c4 src/stream/ngx_stream_upstream_hash_module.c --- a/src/stream/ngx_stream_upstream_hash_module.c Wed Jun 29 12:46:12 2016 +0300 +++ b/src/stream/ngx_stream_upstream_hash_module.c Wed Jun 29 12:46:12 2016 +0300 @@ -23,6 +23,7 @@ typedef struct { typedef struct { + ngx_stream_complex_value_t key; ngx_stream_upstream_chash_points_t *points; } ngx_stream_upstream_hash_srv_conf_t; @@ -141,7 +142,9 @@ ngx_stream_upstream_init_hash_peer(ngx_s hcf = ngx_stream_conf_upstream_srv_conf(us, ngx_stream_upstream_hash_module); - hp->key = s->connection->addr_text; + if (ngx_stream_complex_value(s, &hcf->key, &hp->key) != NGX_OK) { + return NGX_ERROR; + } ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, "upstream hash key:\"%V\"", &hp->key); @@ -616,15 +619,21 @@ ngx_stream_upstream_hash_create_conf(ngx static char * ngx_stream_upstream_hash(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { - ngx_str_t *value; - ngx_stream_upstream_srv_conf_t *uscf; + ngx_stream_upstream_hash_srv_conf_t *hcf = conf; + + ngx_str_t *value; + ngx_stream_upstream_srv_conf_t *uscf; + ngx_stream_compile_complex_value_t ccv; value = cf->args->elts; - if (ngx_strcmp(value[1].data, "$remote_addr")) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "unsupported hash key \"%V\", use $remote_addr", - &value[1]); + ngx_memzero(&ccv, sizeof(ngx_stream_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[1]; + ccv.complex_value = &hcf->key; + + if (ngx_stream_compile_complex_value(&ccv) != NGX_OK) { return NGX_CONF_ERROR; } From vl at nginx.com Mon Jul 4 14:50:25 2016 From: vl at nginx.com (Vladimir Homutov) Date: Mon, 04 Jul 2016 14:50:25 +0000 Subject: [nginx] Stream: SSL-related variables. Message-ID: details: http://hg.nginx.org/nginx/rev/85e7bcb37d6b branches: changeset: 6611:85e7bcb37d6b user: Vladimir Homutov date: Wed Jun 29 12:52:52 2016 +0300 description: Stream: SSL-related variables. diffstat: src/stream/ngx_stream_ssl_module.c | 115 ++++++++++++++++++++++++++++++++++++- 1 files changed, 114 insertions(+), 1 deletions(-) diffs (146 lines): diff -r d5b5866c06c4 -r 85e7bcb37d6b src/stream/ngx_stream_ssl_module.c --- a/src/stream/ngx_stream_ssl_module.c Wed Jun 29 12:46:12 2016 +0300 +++ b/src/stream/ngx_stream_ssl_module.c Wed Jun 29 12:52:52 2016 +0300 @@ -10,10 +10,20 @@ #include +typedef ngx_int_t (*ngx_ssl_variable_handler_pt)(ngx_connection_t *c, + ngx_pool_t *pool, ngx_str_t *s); + + #define NGX_DEFAULT_CIPHERS "HIGH:!aNULL:!MD5" #define NGX_DEFAULT_ECDH_CURVE "auto" +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, + ngx_stream_variable_value_t *v, uintptr_t data); + +static ngx_int_t ngx_stream_ssl_add_variables(ngx_conf_t *cf); 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); @@ -132,7 +142,7 @@ static ngx_command_t ngx_stream_ssl_com static ngx_stream_module_t ngx_stream_ssl_module_ctx = { - NULL, /* preconfiguration */ + ngx_stream_ssl_add_variables, /* preconfiguration */ NULL, /* postconfiguration */ NULL, /* create main configuration */ @@ -159,9 +169,112 @@ ngx_module_t ngx_stream_ssl_module = { }; +static ngx_stream_variable_t ngx_stream_ssl_vars[] = { + + { ngx_string("ssl_protocol"), NULL, ngx_stream_ssl_static_variable, + (uintptr_t) ngx_ssl_get_protocol, NGX_STREAM_VAR_CHANGEABLE, 0 }, + + { ngx_string("ssl_cipher"), NULL, ngx_stream_ssl_static_variable, + (uintptr_t) ngx_ssl_get_cipher_name, NGX_STREAM_VAR_CHANGEABLE, 0 }, + + { ngx_string("ssl_session_id"), NULL, ngx_stream_ssl_variable, + (uintptr_t) ngx_ssl_get_session_id, NGX_STREAM_VAR_CHANGEABLE, 0 }, + + { ngx_string("ssl_session_reused"), NULL, ngx_stream_ssl_variable, + (uintptr_t) ngx_ssl_get_session_reused, NGX_STREAM_VAR_CHANGEABLE, 0 }, + + { ngx_string("ssl_server_name"), NULL, ngx_stream_ssl_variable, + (uintptr_t) ngx_ssl_get_server_name, NGX_STREAM_VAR_CHANGEABLE, 0 }, + + { ngx_null_string, NULL, NULL, 0, 0, 0 } +}; + + static ngx_str_t ngx_stream_ssl_sess_id_ctx = ngx_string("STREAM"); +static ngx_int_t +ngx_stream_ssl_static_variable(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data) +{ + ngx_ssl_variable_handler_pt handler = (ngx_ssl_variable_handler_pt) data; + + size_t len; + ngx_str_t str; + + if (s->connection->ssl) { + + (void) handler(s->connection, NULL, &str); + + v->data = str.data; + + for (len = 0; v->data[len]; len++) { /* void */ } + + v->len = 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_ssl_variable(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data) +{ + ngx_ssl_variable_handler_pt handler = (ngx_ssl_variable_handler_pt) data; + + ngx_str_t str; + + if (s->connection->ssl) { + + if (handler(s->connection, s->connection->pool, &str) != NGX_OK) { + return NGX_ERROR; + } + + v->len = str.len; + v->data = str.data; + + if (v->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_ssl_add_variables(ngx_conf_t *cf) +{ + ngx_stream_variable_t *var, *v; + + for (v = ngx_stream_ssl_vars; v->name.len; v++) { + var = ngx_stream_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 void * ngx_stream_ssl_create_conf(ngx_conf_t *cf) { From vl at nginx.com Mon Jul 4 14:50:28 2016 From: vl at nginx.com (Vladimir Homutov) Date: Mon, 04 Jul 2016 14:50:28 +0000 Subject: [nginx] Stream: return module. Message-ID: details: http://hg.nginx.org/nginx/rev/4c4ac9e335c4 branches: changeset: 6612:4c4ac9e335c4 user: Roman Arutyunyan date: Wed May 18 22:08:49 2016 +0300 description: Stream: return module. diffstat: auto/modules | 8 + auto/options | 3 + src/stream/ngx_stream_return_module.c | 207 ++++++++++++++++++++++++++++++++++ 3 files changed, 218 insertions(+), 0 deletions(-) diffs (256 lines): diff -r 85e7bcb37d6b -r 4c4ac9e335c4 auto/modules --- a/auto/modules Wed Jun 29 12:52:52 2016 +0300 +++ b/auto/modules Wed May 18 22:08:49 2016 +0300 @@ -1028,6 +1028,14 @@ if [ $STREAM != NO ]; then . auto/module fi + if [ $STREAM_RETURN = YES ]; then + ngx_module_name=ngx_stream_return_module + ngx_module_deps= + ngx_module_srcs=src/stream/ngx_stream_return_module.c + + . auto/module + fi + if [ $STREAM_UPSTREAM_HASH = YES ]; then ngx_module_name=ngx_stream_upstream_hash_module ngx_module_deps= diff -r 85e7bcb37d6b -r 4c4ac9e335c4 auto/options --- a/auto/options Wed Jun 29 12:52:52 2016 +0300 +++ b/auto/options Wed May 18 22:08:49 2016 +0300 @@ -118,6 +118,7 @@ STREAM_SSL=NO STREAM_LIMIT_CONN=YES STREAM_ACCESS=YES STREAM_MAP=YES +STREAM_RETURN=YES STREAM_UPSTREAM_HASH=YES STREAM_UPSTREAM_LEAST_CONN=YES STREAM_UPSTREAM_ZONE=YES @@ -296,6 +297,7 @@ use the \"--with-mail_ssl_module\" optio STREAM_LIMIT_CONN=NO ;; --without-stream_access_module) STREAM_ACCESS=NO ;; --without-stream_map_module) STREAM_MAP=NO ;; + --without-stream_return_module) STREAM_RETURN=NO ;; --without-stream_upstream_hash_module) STREAM_UPSTREAM_HASH=NO ;; --without-stream_upstream_least_conn_module) @@ -495,6 +497,7 @@ cat << END --without-stream_limit_conn_module disable ngx_stream_limit_conn_module --without-stream_access_module disable ngx_stream_access_module --without-stream_map_module disable ngx_stream_map_module + --without-stream_return_module disable ngx_stream_return_module --without-stream_upstream_hash_module disable ngx_stream_upstream_hash_module --without-stream_upstream_least_conn_module diff -r 85e7bcb37d6b -r 4c4ac9e335c4 src/stream/ngx_stream_return_module.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/stream/ngx_stream_return_module.c Wed May 18 22:08:49 2016 +0300 @@ -0,0 +1,207 @@ + +/* + * Copyright (C) Roman Arutyunyan + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include + + +typedef struct { + ngx_stream_complex_value_t text; +} ngx_stream_return_srv_conf_t; + + +typedef struct { + ngx_buf_t buf; +} ngx_stream_return_ctx_t; + + +static void ngx_stream_return_handler(ngx_stream_session_t *s); +static void ngx_stream_return_write_handler(ngx_event_t *ev); + +static void *ngx_stream_return_create_srv_conf(ngx_conf_t *cf); +static char *ngx_stream_return(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); + + +static ngx_command_t ngx_stream_return_commands[] = { + + { ngx_string("return"), + NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, + ngx_stream_return, + NGX_STREAM_SRV_CONF_OFFSET, + 0, + NULL }, + + ngx_null_command +}; + + +static ngx_stream_module_t ngx_stream_return_module_ctx = { + NULL, /* preconfiguration */ + NULL, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + ngx_stream_return_create_srv_conf, /* create server configuration */ + NULL, /* merge server configuration */ +}; + + +ngx_module_t ngx_stream_return_module = { + NGX_MODULE_V1, + &ngx_stream_return_module_ctx, /* module context */ + ngx_stream_return_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 void +ngx_stream_return_handler(ngx_stream_session_t *s) +{ + ngx_str_t text; + ngx_connection_t *c; + ngx_stream_return_ctx_t *ctx; + ngx_stream_return_srv_conf_t *rscf; + + c = s->connection; + + c->log->action = "returning text"; + + rscf = ngx_stream_get_module_srv_conf(s, ngx_stream_return_module); + + if (ngx_stream_complex_value(s, &rscf->text, &text) != NGX_OK) { + ngx_stream_close_connection(c); + return; + } + + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0, + "stream return text: \"%V\"", &text); + + if (text.len == 0) { + ngx_stream_close_connection(c); + return; + } + + ctx = ngx_pcalloc(c->pool, sizeof(ngx_stream_return_ctx_t)); + if (ctx == NULL) { + ngx_stream_close_connection(c); + return; + } + + ngx_stream_set_ctx(s, ctx, ngx_stream_return_module); + + ctx->buf.pos = text.data; + ctx->buf.last = text.data + text.len; + + c->write->handler = ngx_stream_return_write_handler; + + ngx_stream_return_write_handler(c->write); +} + + +static void +ngx_stream_return_write_handler(ngx_event_t *ev) +{ + ssize_t n; + ngx_buf_t *b; + ngx_connection_t *c; + ngx_stream_session_t *s; + ngx_stream_return_ctx_t *ctx; + + c = ev->data; + s = c->data; + + if (ev->timedout) { + ngx_connection_error(c, NGX_ETIMEDOUT, "connection timed out"); + ngx_stream_close_connection(c); + return; + } + + if (ev->ready) { + ctx = ngx_stream_get_module_ctx(s, ngx_stream_return_module); + + b = &ctx->buf; + + n = c->send(c, b->pos, b->last - b->pos); + if (n == NGX_ERROR) { + ngx_stream_close_connection(c); + return; + } + + if (n > 0) { + b->pos += n; + + if (b->pos == b->last) { + ngx_stream_close_connection(c); + return; + } + } + } + + if (ngx_handle_write_event(ev, 0) != NGX_OK) { + ngx_stream_close_connection(c); + return; + } + + ngx_add_timer(ev, 5000); +} + + +static void * +ngx_stream_return_create_srv_conf(ngx_conf_t *cf) +{ + ngx_stream_return_srv_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_stream_return_srv_conf_t)); + if (conf == NULL) { + return NULL; + } + + return conf; +} + + +static char * +ngx_stream_return(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_stream_return_srv_conf_t *rscf = conf; + + ngx_str_t *value; + ngx_stream_core_srv_conf_t *cscf; + ngx_stream_compile_complex_value_t ccv; + + if (rscf->text.value.data) { + return "is duplicate"; + } + + value = cf->args->elts; + + ngx_memzero(&ccv, sizeof(ngx_stream_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[1]; + ccv.complex_value = &rscf->text; + + if (ngx_stream_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + cscf = ngx_stream_conf_get_module_srv_conf(cf, ngx_stream_core_module); + + cscf->handler = ngx_stream_return_handler; + + return NGX_CONF_OK; +} From gopal.raghavan at here.com Mon Jul 4 21:51:39 2016 From: gopal.raghavan at here.com (Raghavan, Gopal) Date: Mon, 4 Jul 2016 21:51:39 +0000 Subject: Order of execution of nginx filters Message-ID: Hi I have the following three directives: location = /hello { hello_world; hola_mundo on; bonjour_monde on; } hello_world is an nginx handler module that provides content ?hello world? hola_mundo and bonjour_monde are filters that add to the chain strings ?hola mundo? and ?bonjour monde? respectively. Here is the output: curl "http://localhost:8090/hello" hello worldhola mundobonjour monde Switching the filter directives in location block has no impact on output string. For eg: location = /hello { hello_world; bonjour_monde on; hola_mundo on; } Here is the output: curl "http://localhost:8090/hello" hello worldhola mundobonjour monde How do I control the order of execution of filters? I already looked at objs/ngx_modules.c and auto/modules. My custom handlers and filters are not listed there. One thing that I observed is that the order of listing the load_module modules/*.so in conf/nginx.conf does impact the order of execution of the filters. Is there any other trick to adjust the execution order within the location block? Thanks, -- Gopal -------------- next part -------------- An HTML attachment was scrubbed... URL: From ahutchings at nginx.com Tue Jul 5 09:40:02 2016 From: ahutchings at nginx.com (Andrew Hutchings) Date: Tue, 5 Jul 2016 10:40:02 +0100 Subject: Order of execution of nginx filters In-Reply-To: References: Message-ID: <1679837c-11ae-d1b7-9e76-f881b6f01371@nginx.com> Hi Gopal, If you are compiling as dynamic modules you can specify filter order in the module's 'config' file: https://www.nginx.com/resources/wiki/extending/new_config/#key-ngx_module_order Hope this helps. Kind Regards Andrew On 04/07/16 22:51, Raghavan, Gopal wrote: > Hi > > > > I have the following three directives: > > > > location = /hello { > > hello_world; > > hola_mundo on; > > bonjour_monde on; > > } > > > > hello_world is an nginx handler module that provides content ?hello world? > > hola_mundo and bonjour_monde are filters that add to the chain strings > ?hola mundo? and ?bonjour monde? respectively. > > > > > > Here is the output: > > curl "http://localhost:8090/hello" > > hello worldhola mundobonjour monde > > > > > > Switching the filter directives in location block has no impact on > output string. > > > > For eg: > > > > location = /hello { > > hello_world; > > bonjour_monde on; > > hola_mundo on; > > } > > > > Here is the output: > > curl "http://localhost:8090/hello" > > hello worldhola mundobonjour monde > > > > > > How do I control the order of execution of filters? > > I already looked at objs/ngx_modules.c and auto/modules. My custom > handlers and filters are not listed there. > > > > One thing that I observed is that the order of listing the load_module > modules/*.so in conf/nginx.conf does impact the order of execution of > the filters. > > > > Is there any other trick to adjust the execution order within the > location block? > > > > Thanks, > > -- > > Gopal > > > > > > > > > > > > > > > > _______________________________________________ > nginx-devel mailing list > nginx-devel at nginx.org > http://mailman.nginx.org/mailman/listinfo/nginx-devel > -- Andrew Hutchings (LinuxJedi) Technical Product Manager, NGINX Inc. From igor at sysoev.ru Tue Jul 5 13:12:41 2016 From: igor at sysoev.ru (Igor Sysoev) Date: Tue, 05 Jul 2016 13:12:41 +0000 Subject: [njs] String.split() method. Message-ID: details: http://hg.nginx.org/njs/rev/41404eee5063 branches: changeset: 114:41404eee5063 user: Igor Sysoev date: Tue Jun 28 19:28:00 2016 +0300 description: String.split() method. diffstat: njs/njs_array.c | 62 +++++------------ njs/njs_array.h | 2 + njs/njs_string.c | 161 +++++++++++++++++++++++++++++++++++++++++++++++ njs/njscript.h | 3 - njs/test/njs_unit_test.c | 42 ++++++++++++ 5 files changed, 223 insertions(+), 47 deletions(-) diffs (333 lines): diff -r c72fd0d1fabc -r 41404eee5063 njs/njs_array.c --- a/njs/njs_array.c Wed Jun 01 15:31:34 2016 +0300 +++ b/njs/njs_array.c Tue Jun 28 19:28:00 2016 +0300 @@ -63,50 +63,6 @@ static nxt_noinline njs_ret_t njs_array_ njs_array_next_t *next, njs_value_t *args, nxt_uint_t nargs); -njs_value_t * -njs_array_add(njs_vm_t *vm, njs_value_t *value, u_char *start, size_t size) -{ - njs_ret_t ret; - njs_array_t *array; - - if (value != NULL) { - array = value->data.u.array; - - if (array->size == array->length) { - ret = njs_array_realloc(vm, array, 0, array->size + 1); - if (nxt_slow_path(ret != NXT_OK)) { - return NULL; - } - } - - } else { - value = nxt_mem_cache_align(vm->mem_cache_pool, sizeof(njs_value_t), - sizeof(njs_value_t)); - - if (nxt_slow_path(value == NULL)) { - return NULL; - } - - array = njs_array_alloc(vm, 0, NJS_ARRAY_SPARE); - if (nxt_slow_path(array == NULL)) { - return NULL; - } - - value->data.u.array = array; - value->type = NJS_ARRAY; - value->data.truth = 1; - } - - ret = njs_string_create(vm, &array->start[array->length++], start, size, 0); - - if (nxt_fast_path(ret == NXT_OK)) { - return value; - } - - return NULL; -} - - nxt_noinline njs_array_t * njs_array_alloc(njs_vm_t *vm, uint32_t length, uint32_t spare) { @@ -139,6 +95,24 @@ njs_array_alloc(njs_vm_t *vm, uint32_t l njs_ret_t +njs_array_string_add(njs_vm_t *vm, njs_array_t *array, u_char *start, + size_t size, size_t length) +{ + njs_ret_t ret; + + if (array->size == array->length) { + ret = njs_array_realloc(vm, array, 0, array->size + 1); + if (nxt_slow_path(ret != NXT_OK)) { + return ret; + } + } + + return njs_string_create(vm, &array->start[array->length++], + start, size, length); +} + + +njs_ret_t njs_array_realloc(njs_vm_t *vm, njs_array_t *array, uint32_t prepend, uint32_t size) { diff -r c72fd0d1fabc -r 41404eee5063 njs/njs_array.h --- a/njs/njs_array.h Wed Jun 01 15:31:34 2016 +0300 +++ b/njs/njs_array.h Tue Jun 28 19:28:00 2016 +0300 @@ -21,6 +21,8 @@ struct njs_array_s { njs_array_t *njs_array_alloc(njs_vm_t *vm, uint32_t length, uint32_t spare); +njs_ret_t njs_array_string_add(njs_vm_t *vm, njs_array_t *array, u_char *start, + size_t size, size_t length); njs_ret_t njs_array_realloc(njs_vm_t *vm, njs_array_t *array, uint32_t prepend, uint32_t size); njs_ret_t njs_array_constructor(njs_vm_t *vm, njs_value_t *args, diff -r c72fd0d1fabc -r 41404eee5063 njs/njs_string.c --- a/njs/njs_string.c Wed Jun 01 15:31:34 2016 +0300 +++ b/njs/njs_string.c Tue Jun 28 19:28:00 2016 +0300 @@ -1645,6 +1645,160 @@ empty: } +/* + * String.split([string|regexp[, limit]]) + */ + +static njs_ret_t +njs_string_prototype_split(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, + njs_index_t unused) +{ + int ret, *captures; + u_char *p, *start, *next; + size_t size, length; + uint32_t limit; + nxt_uint_t n; + njs_array_t *array; + const u_char *end; + njs_string_prop_t string, split; + njs_regexp_pattern_t *pattern; + + array = njs_array_alloc(vm, 0, NJS_ARRAY_SPARE); + if (nxt_slow_path(array == NULL)) { + return NXT_ERROR; + } + + if (nargs > 1) { + + if (nargs > 2) { + limit = args[2].data.u.number; + + if (limit == 0) { + goto done; + } + + } else { + limit = (uint32_t) -1; + } + + switch (args[1].type) { + + case NJS_STRING: + (void) njs_string_prop(&split, &args[1]); + + length = njs_string_prop(&string, &args[0]); + + if (string.size < split.size) { + goto single; + } + + start = string.start; + end = string.start + string.size; + + do { + for (p = start; p < end; p++) { + if (memcmp(p, split.start, split.size) == 0) { + break; + } + } + + next = p + split.size; + + /* Empty split string. */ + if (p == next) { + p++; + next++; + } + + size = p - start; + length = nxt_utf8_length(start, size); + + ret = njs_array_string_add(vm, array, start, size, length); + if (nxt_slow_path(ret != NXT_OK)) { + return ret; + } + + start = next; + limit--; + + } while (limit != 0 && p < end); + + goto done; + + case NJS_REGEXP: + pattern = args[1].data.u.regexp->pattern; + + (void) njs_string_prop(&string, &args[0]); + + n = (string.length != 0 && string.length != string.size); + + if (!nxt_regex_is_valid(&pattern->regex[n])) { + goto single; + } + + start = string.start; + end = string.start + string.size; + + do { + ret = nxt_regex_match(&pattern->regex[n], start, end - start, + vm->single_match_data, vm->regex_context); + if (ret >= 0) { + captures = nxt_regex_captures(vm->single_match_data); + + p = start + captures[0]; + next = start + captures[1]; + + } else if (ret == NGX_REGEX_NOMATCH) { + p = (u_char *) end; + next = (u_char *) end + 1; + + } else { + return njs_string_exception(vm, NJS_INTERNAL_ERROR, + vm->regex_context->error); + } + + /* Empty split regexp. */ + if (p == next) { + p++; + next++; + } + + size = p - start; + length = nxt_utf8_length(start, size); + + ret = njs_array_string_add(vm, array, start, size, length); + if (nxt_slow_path(ret != NXT_OK)) { + return ret; + } + + start = next; + limit--; + + } while (limit != 0 && p < end); + + goto done; + + default: /* NJS_VOID */ + break; + } + } + +single: + + /* GC: retain. */ + array->start[0] = args[0]; + array->length = 1; + +done: + + vm->retval.data.u.array = array; + vm->retval.type = NJS_ARRAY; + vm->retval.data.truth = 1; + + return NXT_OK; +} + + njs_ret_t njs_primitive_value_to_string(njs_vm_t *vm, njs_value_t *dst, const njs_value_t *src) @@ -1901,6 +2055,13 @@ static const njs_object_prop_t njs_stri .value = njs_native_function(njs_string_prototype_match, 0, NJS_STRING_ARG, NJS_REGEXP_ARG), }, + + { + .type = NJS_METHOD, + .name = njs_string("split"), + .value = njs_native_function(njs_string_prototype_split, 0, + NJS_STRING_OBJECT_ARG, NJS_REGEXP_ARG, NJS_INTEGER_ARG), + }, }; diff -r c72fd0d1fabc -r 41404eee5063 njs/njscript.h --- a/njs/njscript.h Wed Jun 01 15:31:34 2016 +0300 +++ b/njs/njscript.h Tue Jun 28 19:28:00 2016 +0300 @@ -106,8 +106,5 @@ NXT_EXPORT void *njs_value_data(njs_valu NXT_EXPORT nxt_int_t njs_value_string_copy(njs_vm_t *vm, nxt_str_t *retval, njs_value_t *value, uintptr_t *next); -NXT_EXPORT njs_value_t *njs_array_add(njs_vm_t *vm, njs_value_t *array, - u_char *start, size_t size); - #endif /* _NJSCRIPT_H_INCLUDED_ */ diff -r c72fd0d1fabc -r 41404eee5063 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Wed Jun 01 15:31:34 2016 +0300 +++ b/njs/test/njs_unit_test.c Tue Jun 28 19:28:00 2016 +0300 @@ -2924,6 +2924,48 @@ static njs_unit_test_t njs_test[] = "a +' '+ a.length"), nxt_string("?? 4") }, + { nxt_string("'abc'.split()"), + nxt_string("abc") }, + + { nxt_string("'abc'.split(undefined)"), + nxt_string("abc") }, + + { nxt_string("''.split('').length"), + nxt_string("1") }, + + { nxt_string("'abc'.split('')"), + nxt_string("a,b,c") }, + + { nxt_string("'a bc def'.split(' ')"), + nxt_string("a,bc,def") }, + + { nxt_string("'a bc def'.split(' ')"), + nxt_string("a,bc,,def") }, + + { nxt_string("'a bc def'.split(' ', 3)"), + nxt_string("a,bc,") }, + + { nxt_string("'abc'.split('abc')"), + nxt_string(",") }, + + { nxt_string("'ab'.split('123')"), + nxt_string("ab") }, + + { nxt_string("''.split(/0/).length"), + nxt_string("1") }, + + { nxt_string("'abc'.split(/(?:)/)"), + nxt_string("a,b,c") }, + + { nxt_string("'a bc def'.split(/ /)"), + nxt_string("a,bc,def") }, + + { nxt_string("'a bc def'.split(/ /)"), + nxt_string("a,bc,,def") }, + + { nxt_string("'abc'.split(/abc/)"), + nxt_string(",") }, + /* Functions. */ { nxt_string("function f() { } f()"), From igor at sysoev.ru Tue Jul 5 13:12:42 2016 From: igor at sysoev.ru (Igor Sysoev) Date: Tue, 05 Jul 2016 13:12:42 +0000 Subject: [njs] Array.reverse() method. Message-ID: details: http://hg.nginx.org/njs/rev/ef2b708510b1 branches: changeset: 115:ef2b708510b1 user: Igor Sysoev date: Wed Jun 29 13:38:20 2016 +0300 description: Array.reverse() method. diffstat: njs/njs_array.c | 40 ++++++++++++++++++++++++++++++++++++++++ njs/test/njs_unit_test.c | 18 ++++++++++++++++++ 2 files changed, 58 insertions(+), 0 deletions(-) diffs (92 lines): diff -r 41404eee5063 -r ef2b708510b1 njs/njs_array.c --- a/njs/njs_array.c Tue Jun 28 19:28:00 2016 +0300 +++ b/njs/njs_array.c Wed Jun 29 13:38:20 2016 +0300 @@ -464,6 +464,39 @@ njs_array_prototype_shift(njs_vm_t *vm, } +static njs_ret_t +njs_array_prototype_reverse(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, + njs_index_t unused) +{ + nxt_uint_t i, n, length; + njs_value_t value; + njs_array_t *array; + + if (njs_is_array(&args[0])) { + array = args[0].data.u.array; + length = array->length; + + if (length > 1) { + for (i = 0, n = length - 1; i < n; i++, n--) { + value = array->start[i]; + array->start[i] = array->start[n]; + array->start[n] = value; + } + } + + vm->retval.data.u.array = array; + vm->retval.type = NJS_ARRAY; + vm->retval.data.truth = 1; + + } else { + /* STUB */ + vm->retval = args[0]; + } + + return NXT_OK; +} + + /* * ECMAScript 5.1: try first to use object method "join", then * use the standard built-in method Object.prototype.toString(). @@ -971,6 +1004,13 @@ static const njs_object_prop_t njs_arra { .type = NJS_METHOD, + .name = njs_string("reverse"), + .value = njs_native_function(njs_array_prototype_reverse, 0, + NJS_OBJECT_ARG), + }, + + { + .type = NJS_METHOD, .name = njs_string("toString"), .value = njs_native_function(njs_array_prototype_to_string, NJS_CONTINUATION_SIZE, 0), diff -r 41404eee5063 -r ef2b708510b1 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Tue Jun 28 19:28:00 2016 +0300 +++ b/njs/test/njs_unit_test.c Wed Jun 29 13:38:20 2016 +0300 @@ -2186,6 +2186,21 @@ static njs_unit_test_t njs_test[] = "len +' '+ a +' '+ a.shift()"), nxt_string("5 3,4,5,1,2 3") }, + { nxt_string("var a = []; a.reverse()"), + nxt_string("") }, + + { nxt_string("var a = [1]; a.reverse()"), + nxt_string("1") }, + + { nxt_string("var a = [1,2]; a.reverse()"), + nxt_string("2,1") }, + + { nxt_string("var a = [1,2,3]; a.reverse()"), + nxt_string("3,2,1") }, + + { nxt_string("var a = [1,2,3,4]; a.reverse()"), + nxt_string("4,3,2,1") }, + { nxt_string("var a = []; var s = { sum: 0 };" "a.forEach(function(v, i, a) { this.sum += v }, s); s.sum"), nxt_string("0") }, @@ -2966,6 +2981,9 @@ static njs_unit_test_t njs_test[] = { nxt_string("'abc'.split(/abc/)"), nxt_string(",") }, + { nxt_string("'0123456789'.split('').reverse().join('')"), + nxt_string("9876543210") }, + /* Functions. */ { nxt_string("function f() { } f()"), From mdounin at mdounin.ru Tue Jul 5 15:32:16 2016 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 05 Jul 2016 15:32:16 +0000 Subject: [nginx] Updated PCRE used for win32 builds. Message-ID: details: http://hg.nginx.org/nginx/rev/4a32b3ac54c6 branches: changeset: 6613:4a32b3ac54c6 user: Maxim Dounin date: Tue Jul 05 18:30:56 2016 +0300 description: Updated PCRE used for win32 builds. diffstat: misc/GNUmakefile | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diffs (12 lines): diff --git a/misc/GNUmakefile b/misc/GNUmakefile --- a/misc/GNUmakefile +++ b/misc/GNUmakefile @@ -7,7 +7,7 @@ TEMP = tmp OBJS = objs.msvc8 OPENSSL = openssl-1.0.2h ZLIB = zlib-1.2.8 -PCRE = pcre-8.38 +PCRE = pcre-8.39 release: export From mdounin at mdounin.ru Tue Jul 5 15:59:26 2016 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 05 Jul 2016 15:59:26 +0000 Subject: [nginx] nginx-1.11.2-RELEASE Message-ID: details: http://hg.nginx.org/nginx/rev/4d3b3a13a8cf branches: changeset: 6614:4d3b3a13a8cf user: Maxim Dounin date: Tue Jul 05 18:56:14 2016 +0300 description: nginx-1.11.2-RELEASE diffstat: docs/xml/nginx/changes.xml | 113 +++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 113 insertions(+), 0 deletions(-) diffs (123 lines): diff --git a/docs/xml/nginx/changes.xml b/docs/xml/nginx/changes.xml --- a/docs/xml/nginx/changes.xml +++ b/docs/xml/nginx/changes.xml @@ -5,6 +5,119 @@ + + + + +?????? nginx ?????? ?????????? ?????????? ?????????? MD5 ? SHA1; +????????? configure --with-md5 ? --with-sha1 ??????????. + + +now nginx always uses internal MD5 and SHA1 implementations; +the --with-md5 and --with-sha1 configure options were canceled. + + + + + +????????? ?????????? ? ?????? stream. + + +variables support in the stream module. + + + + + +?????? ngx_stream_map_module. + + +the ngx_stream_map_module. + + + + + +?????? ngx_stream_return_module. + + +the ngx_stream_return_module. + + + + + +? ?????????? proxy_bind, fastcgi_bind, memcached_bind, scgi_bind ? uwsgi_bind +?????? ????? ????????? ????. + + +a port can be specified in the "proxy_bind", "fastcgi_bind", +"memcached_bind", "scgi_bind", and "uwsgi_bind" directives. + + + + + +?????? nginx ?????????? ????? ?????? IP_BIND_ADDRESS_NO_PORT, ???? ??? ????????. + + +now nginx uses the IP_BIND_ADDRESS_NO_PORT socket option when available. + + + + + +??? ????????????? HTTP/2 ? ????????? proxy_request_buffering +? ??????? ???????? ??? ????????? segmentation fault. + + +a segmentation fault might occur in a worker process +when using HTTP/2 and the "proxy_request_buffering" directive. + + + + + +??? ????????????? HTTP/2 +? ????????, ???????????? ?? ??????, +?????? ??????????? ?????? ????????? "Content-Length", +???? ???? ? ??????? ?? ???? ????. + + +the "Content-Length" request header line +was always added to requests passed to backends, +including requests without body, +when using HTTP/2. + + + + + +??? ????????????? HTTP/2 +? ????? ????? ?????????? ????????? "http request count is zero". + + +"http request count is zero" alerts might appear in logs +when using HTTP/2. + + + + + +??? ????????????? ????????? sub_filter +????? ???????????????? ?????? ??????, ??? ??? ??????????; +???????? ????????? ? 1.9.4. + + +unnecessary buffering might occur +when using the "sub_filter" directive; +the issue had appeared in 1.9.4. + + + + + + From mdounin at mdounin.ru Tue Jul 5 15:59:28 2016 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 05 Jul 2016 15:59:28 +0000 Subject: [nginx] release-1.11.2 tag Message-ID: details: http://hg.nginx.org/nginx/rev/365b31afd276 branches: changeset: 6615:365b31afd276 user: Maxim Dounin date: Tue Jul 05 18:56:14 2016 +0300 description: release-1.11.2 tag diffstat: .hgtags | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diffs (8 lines): diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -400,3 +400,4 @@ 4106db71cbcb9c8274700199ac17e520902c6c0f 13070ecfda67397985f0e986eb9c42ecb46d05b5 release-1.9.15 271ee30c6791847980cd139d31807541f5e569bf release-1.11.0 cb783d9cc19761e14e1285d91c38f4b84d0b8756 release-1.11.1 +4d3b3a13a8cf5fc3351a7f167d1c13325e00f21c release-1.11.2 From luky-37 at hotmail.com Tue Jul 5 22:35:53 2016 From: luky-37 at hotmail.com (Lukas Tribus) Date: Tue, 5 Jul 2016 22:35:53 +0000 Subject: AW: [nginx] Set IP_BIND_ADDRESS_NO_PORT socket option for upstream sockets. In-Reply-To: References: Message-ID: Hello, > if (setsockopt(s, IPPROTO_IP, IP_BIND_ADDRESS_NO_PORT, Isn't this a SOL_IP socket option? Also, does this cover IPv6? Thanks, Lukas From luky-37 at hotmail.com Tue Jul 5 22:49:01 2016 From: luky-37 at hotmail.com (Lukas Tribus) Date: Tue, 5 Jul 2016 22:49:01 +0000 Subject: AW: [nginx] Set IP_BIND_ADDRESS_NO_PORT socket option for upstream sockets. In-Reply-To: References: , Message-ID: >> if (setsockopt(s, IPPROTO_IP, IP_BIND_ADDRESS_NO_PORT > Isn't this a SOL_IP socket option? Actually SOL_IP and IPPROTO_IP are the same thing, so it doesn't make any difference. Sorry for the noise, Lukas From defan at nginx.com Wed Jul 6 03:58:22 2016 From: defan at nginx.com (Andrei Belov) Date: Wed, 6 Jul 2016 06:58:22 +0300 Subject: [nginx] Set IP_BIND_ADDRESS_NO_PORT socket option for upstream sockets. In-Reply-To: References: Message-ID: Hi Lukas, > On 06 Jul 2016, at 01:49, Lukas Tribus wrote: > >>> if (setsockopt(s, IPPROTO_IP, IP_BIND_ADDRESS_NO_PORT >> Isn't this a SOL_IP socket option? > > Actually SOL_IP and IPPROTO_IP are the same thing, so it doesn't make any difference. Correct. And yes, it does cover IPv6 as well. From hongzhidao at gmail.com Wed Jul 6 11:14:16 2016 From: hongzhidao at gmail.com (=?UTF-8?B?5rSq5b+X6YGT?=) Date: Wed, 6 Jul 2016 19:14:16 +0800 Subject: http 2 status Message-ID: Hi, Could anybody tell me the http 2 status, and what's level of support by nginx? Thanks so much! B.R. -------------- next part -------------- An HTML attachment was scrubbed... URL: From ru at nginx.com Wed Jul 6 13:19:56 2016 From: ru at nginx.com (Ruslan Ermilov) Date: Wed, 06 Jul 2016 13:19:56 +0000 Subject: [nginx] Version bump. Message-ID: details: http://hg.nginx.org/nginx/rev/82b0cd4a0324 branches: changeset: 6616:82b0cd4a0324 user: Ruslan Ermilov date: Wed Jul 06 13:10:06 2016 +0300 description: Version bump. diffstat: src/core/nginx.h | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diffs (14 lines): diff -r 365b31afd276 -r 82b0cd4a0324 src/core/nginx.h --- a/src/core/nginx.h Tue Jul 05 18:56:14 2016 +0300 +++ b/src/core/nginx.h Wed Jul 06 13:10:06 2016 +0300 @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1011002 -#define NGINX_VERSION "1.11.2" +#define nginx_version 1011003 +#define NGINX_VERSION "1.11.3" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD From ru at nginx.com Wed Jul 6 13:19:59 2016 From: ru at nginx.com (Ruslan Ermilov) Date: Wed, 06 Jul 2016 13:19:59 +0000 Subject: [nginx] Use NGX_MAX_PATH_LEVEL where appropriate. Message-ID: details: http://hg.nginx.org/nginx/rev/8bf484eef9ab branches: changeset: 6617:8bf484eef9ab user: Ruslan Ermilov date: Wed Jul 06 13:22:29 2016 +0300 description: Use NGX_MAX_PATH_LEVEL where appropriate. The macro was unused since 0.7.44. diffstat: src/core/ngx_file.c | 19 +++++++++---------- src/core/ngx_file.h | 4 ++-- src/http/ngx_http_file_cache.c | 10 +++++----- 3 files changed, 16 insertions(+), 17 deletions(-) diffs (126 lines): diff -r 82b0cd4a0324 -r 8bf484eef9ab src/core/ngx_file.c --- a/src/core/ngx_file.c Wed Jul 06 13:10:06 2016 +0300 +++ b/src/core/ngx_file.c Wed Jul 06 13:22:29 2016 +0300 @@ -225,7 +225,7 @@ ngx_create_hashed_filename(ngx_path_t *p file[path->name.len + path->len] = '/'; - for (n = 0; n < 3; n++) { + for (n = 0; n < NGX_MAX_PATH_LEVEL; n++) { level = path->level[n]; if (level == 0) { @@ -249,7 +249,7 @@ ngx_create_path(ngx_file_t *file, ngx_pa pos = path->name.len; - for (i = 0; i < 3; i++) { + for (i = 0; i < NGX_MAX_PATH_LEVEL; i++) { if (path->level[i] == 0) { break; } @@ -399,6 +399,8 @@ char * ngx_conf_merge_path_value(ngx_conf_t *cf, ngx_path_t **path, ngx_path_t *prev, ngx_path_init_t *init) { + ngx_uint_t i; + if (*path) { return NGX_CONF_OK; } @@ -419,13 +421,10 @@ ngx_conf_merge_path_value(ngx_conf_t *cf return NGX_CONF_ERROR; } - (*path)->level[0] = init->level[0]; - (*path)->level[1] = init->level[1]; - (*path)->level[2] = init->level[2]; - - (*path)->len = init->level[0] + (init->level[0] ? 1 : 0) - + init->level[1] + (init->level[1] ? 1 : 0) - + init->level[2] + (init->level[2] ? 1 : 0); + for (i = 0; i < NGX_MAX_PATH_LEVEL; i++) { + (*path)->level[i] = init->level[i]; + (*path)->len += init->level[i] + (init->level[i] ? 1 : 0); + } if (ngx_add_path(cf, path) != NGX_OK) { return NGX_CONF_ERROR; @@ -518,7 +517,7 @@ ngx_add_path(ngx_conf_t *cf, ngx_path_t return NGX_ERROR; } - for (n = 0; n < 3; n++) { + for (n = 0; n < NGX_MAX_PATH_LEVEL; n++) { if (p[i]->level[n] != path->level[n]) { if (path->conf_file == NULL) { if (p[i]->conf_file == NULL) { diff -r 82b0cd4a0324 -r 8bf484eef9ab src/core/ngx_file.h --- a/src/core/ngx_file.h Wed Jul 06 13:10:06 2016 +0300 +++ b/src/core/ngx_file.h Wed Jul 06 13:22:29 2016 +0300 @@ -49,7 +49,7 @@ typedef void (*ngx_path_loader_pt) (void typedef struct { ngx_str_t name; size_t len; - size_t level[3]; + size_t level[NGX_MAX_PATH_LEVEL]; ngx_path_manager_pt manager; ngx_path_loader_pt loader; @@ -62,7 +62,7 @@ typedef struct { typedef struct { ngx_str_t name; - size_t level[3]; + size_t level[NGX_MAX_PATH_LEVEL]; } ngx_path_init_t; diff -r 82b0cd4a0324 -r 8bf484eef9ab src/http/ngx_http_file_cache.c --- a/src/http/ngx_http_file_cache.c Wed Jul 06 13:10:06 2016 +0300 +++ b/src/http/ngx_http_file_cache.c Wed Jul 06 13:22:29 2016 +0300 @@ -101,7 +101,7 @@ ngx_http_file_cache_init(ngx_shm_zone_t return NGX_ERROR; } - for (n = 0; n < 3; n++) { + for (n = 0; n < NGX_MAX_PATH_LEVEL; n++) { if (cache->path->level[n] != ocache->path->level[n]) { ngx_log_error(NGX_LOG_EMERG, shm_zone->shm.log, 0, "cache \"%V\" had previously different levels", @@ -2257,7 +2257,7 @@ ngx_http_file_cache_set_slot(ngx_conf_t p = value[i].data + 7; last = value[i].data + value[i].len; - for (n = 0; n < 3 && p < last; n++) { + for (n = 0; n < NGX_MAX_PATH_LEVEL && p < last; n++) { if (*p > '0' && *p < '3') { @@ -2268,7 +2268,7 @@ ngx_http_file_cache_set_slot(ngx_conf_t break; } - if (*p++ == ':' && n < 2 && p != last) { + if (*p++ == ':' && n < NGX_MAX_PATH_LEVEL - 1 && p < last) { continue; } @@ -2278,7 +2278,7 @@ ngx_http_file_cache_set_slot(ngx_conf_t goto invalid_levels; } - if (cache->path->len < 10 + 3) { + if (cache->path->len < 10 + NGX_MAX_PATH_LEVEL) { continue; } @@ -2450,7 +2450,7 @@ ngx_http_file_cache_set_slot(ngx_conf_t ngx_memcpy(p, "/temp", sizeof("/temp")); ngx_memcpy(&cache->temp_path->level, &cache->path->level, - 3 * sizeof(size_t)); + NGX_MAX_PATH_LEVEL * sizeof(size_t)); cache->temp_path->len = cache->path->len; cache->temp_path->conf_file = cf->conf_file->file.name.data; From piotrsikora at google.com Wed Jul 6 21:02:19 2016 From: piotrsikora at google.com (Piotr Sikora) Date: Wed, 6 Jul 2016 14:02:19 -0700 Subject: [PATCH 1 of 2] HTTP: add support for trailers in HTTP responses In-Reply-To: <20160704142135.GZ30781@mdounin.ru> References: <20160627134500.GZ30781@mdounin.ru> <20160627175338.GD30781@mdounin.ru> <20160704142135.GZ30781@mdounin.ru> Message-ID: Hey Maxim, > I'm not convinced this feature is needed at all. It looks more > like a Google-specific experiment, and this is not something I > would like to see in nginx code. Wait, what? Are you talking about trailers as defined in RFC7230 (and previously in RFC2616 from 1999, when Google barely existed)? There is nothing Google-specific about them. Also, you had people from 3 different companies asking and/or commenting about trailers on this very mailing list in the last 6 weeks, I'm not sure why you chose to ignore that. > If at all implemented, I would rather prefer adding trailers if a > transfer encoding used allows this, and discrading them otherwise. > This is something that anyway will happen if a protocol used does > not allow trailers at all (e.g., HTTP/1.0). I'm confused, this is exactly what my patch is doing... unless you want to completely ignore "TE" request header? Just keep in mind that per RFC7230, sec. 4.1.2: Unless the request includes a TE header field indicating "trailers" is acceptable, as described in Section 4.3, a server SHOULD NOT generate trailer fields that it believes are necessary for the user agent to receive. Without a TE containing "trailers", the server ought to assume that the trailer fields might be silently discarded along the path to the user agent. This requirement allows intermediaries to forward a de-chunked message to an HTTP/1.0 recipient without buffering the entire response. and sec. 4.3: The presence of the keyword "trailers" indicates that the client is willing to accept trailer fields in a chunked transfer coding, as defined in Section 4.1.2, on behalf of itself and any downstream clients. Best regards, Piotr Sikora From hongzhidao at gmail.com Thu Jul 7 02:25:44 2016 From: hongzhidao at gmail.com (=?UTF-8?B?5rSq5b+X6YGT?=) Date: Thu, 7 Jul 2016 10:25:44 +0800 Subject: unused ngx_http_headers_out Message-ID: Hi, It seems the global variable 'ngx_http_headers_out' in src/http/ngx_http_header_filter_module.c isn't used at any where. B.R. -------------- next part -------------- An HTML attachment was scrubbed... URL: From ru at nginx.com Thu Jul 7 06:54:33 2016 From: ru at nginx.com (Ruslan Ermilov) Date: Thu, 7 Jul 2016 09:54:33 +0300 Subject: unused ngx_http_headers_out In-Reply-To: References: Message-ID: <20160707065433.GB3078@lo0.su> On Thu, Jul 07, 2016 at 10:25:44AM +0800, ??? wrote: > Hi, > > It seems the global variable 'ngx_http_headers_out' in > src/http/ngx_http_header_filter_module.c isn't used at any where. > > B.R. Yes. From vl at nginx.com Thu Jul 7 11:32:03 2016 From: vl at nginx.com (Vladimir Homutov) Date: Thu, 07 Jul 2016 11:32:03 +0000 Subject: [nginx] Stream: resolver. Message-ID: details: http://hg.nginx.org/nginx/rev/070c31a482e6 branches: changeset: 6618:070c31a482e6 user: Vladimir Homutov date: Thu Jul 07 13:15:31 2016 +0300 description: Stream: resolver. diffstat: src/stream/ngx_stream.h | 3 + src/stream/ngx_stream_core_module.c | 60 +++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 0 deletions(-) diffs (108 lines): diff -r 8bf484eef9ab -r 070c31a482e6 src/stream/ngx_stream.h --- a/src/stream/ngx_stream.h Wed Jul 06 13:22:29 2016 +0300 +++ b/src/stream/ngx_stream.h Thu Jul 07 13:15:31 2016 +0300 @@ -141,6 +141,9 @@ typedef struct { ngx_flag_t tcp_nodelay; ngx_log_t *error_log; + + ngx_msec_t resolver_timeout; + ngx_resolver_t *resolver; } ngx_stream_core_srv_conf_t; diff -r 8bf484eef9ab -r 070c31a482e6 src/stream/ngx_stream_core_module.c --- a/src/stream/ngx_stream_core_module.c Wed Jul 06 13:22:29 2016 +0300 +++ b/src/stream/ngx_stream_core_module.c Thu Jul 07 13:15:31 2016 +0300 @@ -22,6 +22,8 @@ static char *ngx_stream_core_server(ngx_ void *conf); static char *ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static char *ngx_stream_core_resolver(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); static ngx_command_t ngx_stream_core_commands[] = { @@ -61,6 +63,20 @@ static ngx_command_t ngx_stream_core_co 0, NULL }, + { ngx_string("resolver"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_1MORE, + ngx_stream_core_resolver, + NGX_STREAM_SRV_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("resolver_timeout"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_STREAM_SRV_CONF_OFFSET, + offsetof(ngx_stream_core_srv_conf_t, resolver_timeout), + NULL }, + { ngx_string("tcp_nodelay"), NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, @@ -175,6 +191,7 @@ ngx_stream_core_create_srv_conf(ngx_conf cscf->file_name = cf->conf_file->file.name.data; cscf->line = cf->conf_file->line; + cscf->resolver_timeout = NGX_CONF_UNSET_MSEC; cscf->tcp_nodelay = NGX_CONF_UNSET; return cscf; @@ -187,6 +204,27 @@ ngx_stream_core_merge_srv_conf(ngx_conf_ ngx_stream_core_srv_conf_t *prev = parent; ngx_stream_core_srv_conf_t *conf = child; + ngx_conf_merge_msec_value(conf->resolver_timeout, + prev->resolver_timeout, 30000); + + if (conf->resolver == NULL) { + + if (prev->resolver == NULL) { + + /* + * create dummy resolver in stream {} context + * to inherit it in all servers + */ + + prev->resolver = ngx_resolver_create(cf, NULL, 0); + if (prev->resolver == NULL) { + return NGX_CONF_ERROR; + } + } + + conf->resolver = prev->resolver; + } + if (conf->handler == NULL) { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "no handler for server in %s:%ui", @@ -565,3 +603,25 @@ ngx_stream_core_listen(ngx_conf_t *cf, n return NGX_CONF_OK; } + + +static char * +ngx_stream_core_resolver(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_stream_core_srv_conf_t *cscf = conf; + + ngx_str_t *value; + + if (cscf->resolver) { + return "is duplicate"; + } + + value = cf->args->elts; + + cscf->resolver = ngx_resolver_create(cf, &value[1], cf->args->nelts - 1); + if (cscf->resolver == NULL) { + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} From mdounin at mdounin.ru Thu Jul 7 13:51:17 2016 From: mdounin at mdounin.ru (Maxim Dounin) Date: Thu, 07 Jul 2016 13:51:17 +0000 Subject: [nginx] Configure: remove auto/lib/test, unused since nginx-0.1.2. Message-ID: details: http://hg.nginx.org/nginx/rev/67938e63758d branches: changeset: 6619:67938e63758d user: Piotr Sikora date: Fri Oct 23 18:21:33 2015 -0700 description: Configure: remove auto/lib/test, unused since nginx-0.1.2. Signed-off-by: Piotr Sikora diffstat: auto/lib/test | 40 ---------------------------------------- 1 files changed, 0 insertions(+), 40 deletions(-) diffs (45 lines): diff --git a/auto/lib/test b/auto/lib/test deleted file mode 100644 --- a/auto/lib/test +++ /dev/null @@ -1,40 +0,0 @@ - -# Copyright (C) Igor Sysoev -# Copyright (C) Nginx, Inc. - - -echo $ngx_n "checking for $ngx_lib ...$ngx_c" - -cat << END >> $NGX_AUTOCONF_ERR - ----------------------------------------- -checking for $ngx_lib - -END - -ngx_found=no - -cat << END > $NGX_AUTOTEST.c - -$ngx_lib_incs - -int main() { - $ngx_lib_test; - return 0; -} - - -eval "$CC $cc_test_flags $ngx_lib_cflags \ - -o $NGX_AUTOTEST $NGX_AUTOTEST.c $ngx_libs \ - >> $NGX_ERR 2>&1" - -if [ -x $NGX_AUTOTEST ]; then - echo " found" - - ngx_found=yes - -else - echo " not found" -fi - -rm -rf $NGX_AUTOTEST* From mdounin at mdounin.ru Thu Jul 7 13:51:20 2016 From: mdounin at mdounin.ru (Maxim Dounin) Date: Thu, 07 Jul 2016 13:51:20 +0000 Subject: [nginx] Configure: style. Message-ID: details: http://hg.nginx.org/nginx/rev/b2ae25f274ad branches: changeset: 6620:b2ae25f274ad user: Piotr Sikora date: Mon Jun 27 15:00:01 2016 -0700 description: Configure: style. Signed-off-by: Piotr Sikora diffstat: auto/unix | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diffs (21 lines): diff --git a/auto/unix b/auto/unix --- a/auto/unix +++ b/auto/unix @@ -264,7 +264,7 @@ ngx_feature_test="dlopen(NULL, RTLD_NOW . auto/feature -if [ $ngx_found != yes ]; then +if [ $ngx_found = no ]; then ngx_feature="dlopen() in libdl" ngx_feature_libs="-ldl" @@ -287,7 +287,7 @@ ngx_feature_test="sched_yield()" . auto/feature -if [ $ngx_found != yes ]; then +if [ $ngx_found = no ]; then ngx_feature="sched_yield() in librt" ngx_feature_libs="-lrt" From mdounin at mdounin.ru Thu Jul 7 13:51:23 2016 From: mdounin at mdounin.ru (Maxim Dounin) Date: Thu, 07 Jul 2016 13:51:23 +0000 Subject: [nginx] Configure: fix build with -Werror=unused-value. Message-ID: details: http://hg.nginx.org/nginx/rev/0c3e464682e2 branches: changeset: 6621:0c3e464682e2 user: Piotr Sikora date: Mon Jun 27 15:00:02 2016 -0700 description: Configure: fix build with -Werror=unused-value. Signed-off-by: Piotr Sikora diffstat: auto/cc/conf | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diffs (12 lines): diff --git a/auto/cc/conf b/auto/cc/conf --- a/auto/cc/conf +++ b/auto/cc/conf @@ -231,7 +231,7 @@ if [ "$NGX_PLATFORM" != win32 ]; then ngx_feature_incs= ngx_feature_path= ngx_feature_libs= - ngx_feature_test="__builtin_bswap64(0)" + ngx_feature_test="if (__builtin_bswap64(0)) return 1" . auto/feature From mdounin at mdounin.ru Thu Jul 7 13:51:25 2016 From: mdounin at mdounin.ru (Maxim Dounin) Date: Thu, 07 Jul 2016 13:51:25 +0000 Subject: [nginx] Configure: fix build with -Werror=unused-but-set-variable. Message-ID: details: http://hg.nginx.org/nginx/rev/e393c0bf53d3 branches: changeset: 6622:e393c0bf53d3 user: Piotr Sikora date: Mon Jun 27 15:00:03 2016 -0700 description: Configure: fix build with -Werror=unused-but-set-variable. Signed-off-by: Piotr Sikora diffstat: auto/os/darwin | 4 ++-- auto/os/linux | 1 + auto/os/solaris | 2 +- auto/unix | 22 +++++++++++++--------- 4 files changed, 17 insertions(+), 12 deletions(-) diffs (112 lines): diff --git a/auto/os/darwin b/auto/os/darwin --- a/auto/os/darwin +++ b/auto/os/darwin @@ -113,6 +113,6 @@ ngx_feature_run=no ngx_feature_incs="#include " ngx_feature_path= ngx_feature_libs= -ngx_feature_test="int32_t lock, n; - n = OSAtomicCompareAndSwap32Barrier(0, 1, &lock)" +ngx_feature_test="int32_t lock = 0; + if (!OSAtomicCompareAndSwap32Barrier(0, 1, &lock)) return 1" . auto/feature diff --git a/auto/os/linux b/auto/os/linux --- a/auto/os/linux +++ b/auto/os/linux @@ -44,6 +44,7 @@ ngx_feature_test="int efd = 0; struct epoll_event ee; ee.events = EPOLLIN|EPOLLOUT|EPOLLET; ee.data.ptr = NULL; + (void) ee; efd = epoll_create(100); if (efd == -1) return 1;" . auto/feature diff --git a/auto/os/solaris b/auto/os/solaris --- a/auto/os/solaris +++ b/auto/os/solaris @@ -52,7 +52,7 @@ ngx_feature_run=no ngx_feature_incs="#include " ngx_feature_path= ngx_feature_libs= -ngx_feature_test="int n = port_create()" +ngx_feature_test="(void) port_create()" . auto/feature if [ $ngx_found = yes ]; then diff --git a/auto/unix b/auto/unix --- a/auto/unix +++ b/auto/unix @@ -75,7 +75,7 @@ if test -z "$NGX_KQUEUE_CHECKED"; then ngx_feature_incs="#include " ngx_feature_path= ngx_feature_libs= - ngx_feature_test="int kq; kq = kqueue()" + ngx_feature_test="(void) kqueue()" . auto/feature if [ $ngx_found = yes ]; then @@ -92,7 +92,8 @@ if test -z "$NGX_KQUEUE_CHECKED"; then ngx_feature_path= ngx_feature_libs= ngx_feature_test="struct kevent kev; - kev.fflags = NOTE_LOWAT;" + kev.fflags = NOTE_LOWAT; + (void) kev" . auto/feature @@ -492,9 +493,9 @@ if [ $NGX_FILE_AIO = YES ]; then ngx_feature_incs="#include " ngx_feature_path= ngx_feature_libs= - ngx_feature_test="int n; struct aiocb iocb; + ngx_feature_test="struct aiocb iocb; iocb.aio_sigevent.sigev_notify = SIGEV_KEVENT; - n = aio_read(&iocb)" + (void) aio_read(&iocb)" . auto/feature if [ $ngx_found = yes ]; then @@ -514,6 +515,7 @@ if [ $NGX_FILE_AIO = YES ]; then iocb.aio_lio_opcode = IOCB_CMD_PREAD; iocb.aio_flags = IOCB_FLAG_RESFD; iocb.aio_resfd = -1; + (void) iocb; (void) eventfd(0, 0)" . auto/feature @@ -529,11 +531,12 @@ if [ $NGX_FILE_AIO = YES ]; then ngx_feature="Linux AIO support (SYS_eventfd)" ngx_feature_incs="#include #include " - ngx_feature_test="int n = SYS_eventfd; - struct iocb iocb; + ngx_feature_test="struct iocb iocb; iocb.aio_lio_opcode = IOCB_CMD_PREAD; iocb.aio_flags = IOCB_FLAG_RESFD; - iocb.aio_resfd = -1;" + iocb.aio_resfd = -1; + (void) iocb; + (void) SYS_eventfd" . auto/feature if [ $ngx_found = yes ]; then @@ -571,7 +574,7 @@ else ngx_feature="eventfd() (SYS_eventfd)" ngx_feature_incs="#include " - ngx_feature_test="int n = SYS_eventfd" + ngx_feature_test="(void) SYS_eventfd" . auto/feature fi fi @@ -644,7 +647,8 @@ if [ $NGX_IPV6 = YES ]; then ngx_feature_path= ngx_feature_libs= ngx_feature_test="struct sockaddr_in6 sin6; - sin6.sin6_family = AF_INET6;" + sin6.sin6_family = AF_INET6; + (void) sin6" . auto/feature fi From mdounin at mdounin.ru Thu Jul 7 13:51:28 2016 From: mdounin at mdounin.ru (Maxim Dounin) Date: Thu, 07 Jul 2016 13:51:28 +0000 Subject: [nginx] Configure: fix build with -Werror=nonnull. Message-ID: details: http://hg.nginx.org/nginx/rev/0bf08d9c82c1 branches: changeset: 6623:0bf08d9c82c1 user: Piotr Sikora date: Mon Jun 27 15:00:04 2016 -0700 description: Configure: fix build with -Werror=nonnull. Signed-off-by: Piotr Sikora diffstat: auto/unix | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diffs (12 lines): diff --git a/auto/unix b/auto/unix --- a/auto/unix +++ b/auto/unix @@ -261,7 +261,7 @@ ngx_feature_run=no ngx_feature_incs="#include " ngx_feature_path= ngx_feature_libs= -ngx_feature_test="dlopen(NULL, RTLD_NOW | RTLD_GLOBAL); dlsym(NULL, NULL)" +ngx_feature_test="dlopen(NULL, RTLD_NOW | RTLD_GLOBAL); dlsym(NULL, \"\")" . auto/feature From mdounin at mdounin.ru Thu Jul 7 13:51:30 2016 From: mdounin at mdounin.ru (Maxim Dounin) Date: Thu, 07 Jul 2016 13:51:30 +0000 Subject: [nginx] Configure: fix build with -Werror=old-style-definition. Message-ID: details: http://hg.nginx.org/nginx/rev/e3faa5fb7772 branches: changeset: 6624:e3faa5fb7772 user: Piotr Sikora date: Mon Jun 27 15:00:05 2016 -0700 description: Configure: fix build with -Werror=old-style-definition. Signed-off-by: Piotr Sikora diffstat: auto/cc/sunc | 5 ++++- auto/endianness | 2 +- auto/feature | 2 +- auto/include | 2 +- auto/types/sizeof | 2 +- auto/types/typedef | 2 +- auto/types/uintptr_t | 2 +- 7 files changed, 10 insertions(+), 7 deletions(-) diffs (87 lines): diff --git a/auto/cc/sunc b/auto/cc/sunc --- a/auto/cc/sunc +++ b/auto/cc/sunc @@ -20,7 +20,10 @@ have=NGX_COMPILER value="\"Sun C $NGX_SU cat << END > $NGX_AUTOTEST.c -int main() { printf("%d", __SUNPRO_C); } +int main(void) { + printf("%d", __SUNPRO_C); + return 0; +} END diff --git a/auto/endianness b/auto/endianness --- a/auto/endianness +++ b/auto/endianness @@ -15,7 +15,7 @@ END cat << END > $NGX_AUTOTEST.c -int main() { +int main(void) { int i = 0x11223344; char *p; diff --git a/auto/feature b/auto/feature --- a/auto/feature +++ b/auto/feature @@ -31,7 +31,7 @@ cat << END > $NGX_AUTOTEST.c $NGX_INCLUDE_UNISTD_H $ngx_feature_incs -int main() { +int main(void) { $ngx_feature_test; return 0; } diff --git a/auto/include b/auto/include --- a/auto/include +++ b/auto/include @@ -20,7 +20,7 @@ cat << END > $NGX_AUTOTEST.c $NGX_INCLUDE_SYS_PARAM_H #include <$ngx_include> -int main() { +int main(void) { return 0; } diff --git a/auto/types/sizeof b/auto/types/sizeof --- a/auto/types/sizeof +++ b/auto/types/sizeof @@ -25,7 +25,7 @@ cat << END > $NGX_AUTOTEST.c $NGX_INCLUDE_INTTYPES_H $NGX_INCLUDE_AUTO_CONFIG_H -int main() { +int main(void) { printf("%d", (int) sizeof($ngx_type)); return 0; } diff --git a/auto/types/typedef b/auto/types/typedef --- a/auto/types/typedef +++ b/auto/types/typedef @@ -27,7 +27,7 @@ do #include $NGX_INCLUDE_INTTYPES_H -int main() { +int main(void) { $ngx_try i = 0; return (int) i; } diff --git a/auto/types/uintptr_t b/auto/types/uintptr_t --- a/auto/types/uintptr_t +++ b/auto/types/uintptr_t @@ -19,7 +19,7 @@ cat << END > $NGX_AUTOTEST.c #include $NGX_INTTYPES_H -int main() { +int main(void) { uintptr_t i = 0; return (int) i; } From mdounin at mdounin.ru Thu Jul 7 13:51:32 2016 From: mdounin at mdounin.ru (Maxim Dounin) Date: Thu, 07 Jul 2016 13:51:32 +0000 Subject: [nginx] Configure: stop polluting NGX_ namespace. Message-ID: details: http://hg.nginx.org/nginx/rev/a616bdc38645 branches: changeset: 6625:a616bdc38645 user: Piotr Sikora date: Mon Jun 27 15:00:06 2016 -0700 description: Configure: stop polluting NGX_ namespace. While there, fix the only test that used alternative variable name. Signed-off-by: Piotr Sikora diffstat: auto/include | 3 --- auto/types/uintptr_t | 2 +- 2 files changed, 1 insertions(+), 4 deletions(-) diffs (25 lines): diff --git a/auto/include b/auto/include --- a/auto/include +++ b/auto/include @@ -45,9 +45,6 @@ if [ -x $NGX_AUTOTEST ]; then eval "NGX_INCLUDE_$ngx_name='#include <$ngx_include>'" - #STUB - eval "NGX_$ngx_name='#include <$ngx_include>'" - else echo " not found" diff --git a/auto/types/uintptr_t b/auto/types/uintptr_t --- a/auto/types/uintptr_t +++ b/auto/types/uintptr_t @@ -17,7 +17,7 @@ found=no cat << END > $NGX_AUTOTEST.c #include -$NGX_INTTYPES_H +$NGX_INCLUDE_INTTYPES_H int main(void) { uintptr_t i = 0; From mdounin at mdounin.ru Thu Jul 7 13:53:41 2016 From: mdounin at mdounin.ru (Maxim Dounin) Date: Thu, 7 Jul 2016 16:53:41 +0300 Subject: [PATCH] Remove auto/lib/test, unused since nginx-0.1.2 In-Reply-To: References: Message-ID: <20160707135341.GB30781@mdounin.ru> Hello! On Sat, Oct 24, 2015 at 04:26:04PM -0700, Piotr Sikora wrote: > # HG changeset patch > # User Piotr Sikora > # Date 1445649693 25200 > # Fri Oct 23 18:21:33 2015 -0700 > # Node ID a8be1943bde3ea151ade97149856684db4066fe3 > # Parent ee16fb0db905cfb858a929374cf623cdf1a0f9d3 > Remove auto/lib/test, unused since nginx-0.1.2. [...] Committed with slightly modified commit log, thanks. http://hg.nginx.org/nginx/rev/67938e63758d -- Maxim Dounin http://nginx.org/ From mdounin at mdounin.ru Thu Jul 7 13:54:18 2016 From: mdounin at mdounin.ru (Maxim Dounin) Date: Thu, 7 Jul 2016 16:54:18 +0300 Subject: [PATCH] Configure: style In-Reply-To: References: Message-ID: <20160707135418.GC30781@mdounin.ru> Hello! On Mon, Jun 27, 2016 at 03:59:16PM -0700, Piotr Sikora wrote: > # HG changeset patch > # User Piotr Sikora > # Date 1467064801 25200 > # Mon Jun 27 15:00:01 2016 -0700 > # Node ID d183012fa3d130b8de922d1c8eafd77ae94f8a51 > # Parent d452cb27639f714bc43b7f3ede417e3e7f8efdd6 > Configure: style. Committed, thanks. -- Maxim Dounin http://nginx.org/ From mdounin at mdounin.ru Thu Jul 7 13:55:28 2016 From: mdounin at mdounin.ru (Maxim Dounin) Date: Thu, 7 Jul 2016 16:55:28 +0300 Subject: [PATCH] Configure: fix build with -Werror=nonnull In-Reply-To: <2c14d7fb1d96c3a1bfb7.1467068360@piotrsikora.sfo.corp.google.com> References: <2c14d7fb1d96c3a1bfb7.1467068360@piotrsikora.sfo.corp.google.com> Message-ID: <20160707135527.GD30781@mdounin.ru> Hello! On Mon, Jun 27, 2016 at 03:59:20PM -0700, Piotr Sikora wrote: > # HG changeset patch > # User Piotr Sikora > # Date 1467064804 25200 > # Mon Jun 27 15:00:04 2016 -0700 > # Node ID 2c14d7fb1d96c3a1bfb7e22383bef895287bf7d7 > # Parent d452cb27639f714bc43b7f3ede417e3e7f8efdd6 > Configure: fix build with -Werror=nonnull. > > Signed-off-by: Piotr Sikora > > diff -r d452cb27639f -r 2c14d7fb1d96 auto/unix > --- a/auto/unix > +++ b/auto/unix > @@ -260,7 +260,8 @@ ngx_feature_run=no > ngx_feature_incs="#include " > ngx_feature_path= > ngx_feature_libs= > -ngx_feature_test="dlopen(NULL, RTLD_NOW | RTLD_GLOBAL); dlsym(NULL, NULL)" > +ngx_feature_test="dlopen(\"/dev/null\", RTLD_NOW | RTLD_GLOBAL); > + dlsym(NULL, \"dummy\")" > . auto/feature First argument of dlopen() can be NULL, http://pubs.opengroup.org/onlinepubs/9699919799/functions/dlopen.html: : If file is a null pointer, dlopen() shall return a global symbol : table handle for the currently running process image. Linux seems to use nonnull for the second argument of dlsym(), something like -ngx_feature_test="dlopen(NULL, RTLD_NOW | RTLD_GLOBAL); dlsym(NULL, NULL)" +ngx_feature_test="dlopen(NULL, RTLD_NOW | RTLD_GLOBAL); dlsym(NULL, \"\")" should be enough to silence the warning. Committed with the above modification, thanks. http://hg.nginx.org/nginx/rev/0bf08d9c82c1 -- Maxim Dounin http://nginx.org/ From mdounin at mdounin.ru Thu Jul 7 13:58:05 2016 From: mdounin at mdounin.ru (Maxim Dounin) Date: Thu, 7 Jul 2016 16:58:05 +0300 Subject: [PATCH] Configure: fix build with -Werror=unused-but-set-variable In-Reply-To: References: Message-ID: <20160707135804.GE30781@mdounin.ru> Hello! On Mon, Jun 27, 2016 at 03:59:19PM -0700, Piotr Sikora wrote: > # HG changeset patch > # User Piotr Sikora > # Date 1467064803 25200 > # Mon Jun 27 15:00:03 2016 -0700 > # Node ID ad603262a99df74951b05ce30c81ebc381694162 > # Parent d452cb27639f714bc43b7f3ede417e3e7f8efdd6 > Configure: fix build with -Werror=unused-but-set-variable. > > Signed-off-by: Piotr Sikora > > diff -r d452cb27639f -r ad603262a99d auto/os/linux > --- a/auto/os/linux > +++ b/auto/os/linux > @@ -44,6 +44,7 @@ ngx_feature_test="int efd = 0; > struct epoll_event ee; > ee.events = EPOLLIN|EPOLLOUT|EPOLLET; > ee.data.ptr = NULL; > + (void) ee; > efd = epoll_create(100); > if (efd == -1) return 1;" > . auto/feature > diff -r d452cb27639f -r ad603262a99d auto/unix > --- a/auto/unix > +++ b/auto/unix > @@ -644,7 +644,8 @@ if [ $NGX_IPV6 = YES ]; then > ngx_feature_path= > ngx_feature_libs= > ngx_feature_test="struct sockaddr_in6 sin6; > - sin6.sin6_family = AF_INET6;" > + sin6.sin6_family = AF_INET6; > + (void) sin6" > . auto/feature > fi > Quick look reveals at least the following additional places where the same warning is generated: diff --git a/auto/os/darwin b/auto/os/darwin --- a/auto/os/darwin +++ b/auto/os/darwin @@ -113,6 +113,6 @@ ngx_feature_run=no ngx_feature_incs="#include " ngx_feature_path= ngx_feature_libs= -ngx_feature_test="int32_t lock, n; - n = OSAtomicCompareAndSwap32Barrier(0, 1, &lock)" +ngx_feature_test="int32_t lock = 0; + if (!OSAtomicCompareAndSwap32Barrier(0, 1, &lock)) return 1" . auto/feature diff --git a/auto/os/solaris b/auto/os/solaris --- a/auto/os/solaris +++ b/auto/os/solaris @@ -52,7 +52,7 @@ ngx_feature_run=no ngx_feature_incs="#include " ngx_feature_path= ngx_feature_libs= -ngx_feature_test="int n = port_create()" +ngx_feature_test="(void) port_create()" . auto/feature if [ $ngx_found = yes ]; then diff --git a/auto/unix b/auto/unix --- a/auto/unix +++ b/auto/unix @@ -75,7 +75,7 @@ if test -z "$NGX_KQUEUE_CHECKED"; then ngx_feature_incs="#include " ngx_feature_path= ngx_feature_libs= - ngx_feature_test="int kq; kq = kqueue()" + ngx_feature_test="(void) kqueue()" . auto/feature if [ $ngx_found = yes ]; then @@ -92,7 +92,8 @@ if test -z "$NGX_KQUEUE_CHECKED"; then ngx_feature_path= ngx_feature_libs= ngx_feature_test="struct kevent kev; - kev.fflags = NOTE_LOWAT;" + kev.fflags = NOTE_LOWAT; + (void) kev" . auto/feature @@ -492,9 +493,9 @@ if [ $NGX_FILE_AIO = YES ]; then ngx_feature_incs="#include " ngx_feature_path= ngx_feature_libs= - ngx_feature_test="int n; struct aiocb iocb; + ngx_feature_test="struct aiocb iocb; iocb.aio_sigevent.sigev_notify = SIGEV_KEVENT; - n = aio_read(&iocb)" + (void) aio_read(&iocb)" . auto/feature if [ $ngx_found = yes ]; then @@ -514,6 +515,7 @@ if [ $NGX_FILE_AIO = YES ]; then iocb.aio_lio_opcode = IOCB_CMD_PREAD; iocb.aio_flags = IOCB_FLAG_RESFD; iocb.aio_resfd = -1; + (void) iocb; (void) eventfd(0, 0)" . auto/feature @@ -529,11 +531,12 @@ if [ $NGX_FILE_AIO = YES ]; then ngx_feature="Linux AIO support (SYS_eventfd)" ngx_feature_incs="#include #include " - ngx_feature_test="int n = SYS_eventfd; - struct iocb iocb; + ngx_feature_test="struct iocb iocb; iocb.aio_lio_opcode = IOCB_CMD_PREAD; iocb.aio_flags = IOCB_FLAG_RESFD; - iocb.aio_resfd = -1;" + iocb.aio_resfd = -1; + (void) iocb; + (void) SYS_eventfd" . auto/feature if [ $ngx_found = yes ]; then @@ -571,7 +574,7 @@ else ngx_feature="eventfd() (SYS_eventfd)" ngx_feature_incs="#include " - ngx_feature_test="int n = SYS_eventfd" + ngx_feature_test="(void) SYS_eventfd" . auto/feature fi fi Likely there are others as well (and I'm a bit sceptical about attempts to run configure with -Werror enabled), but probably committing this improves things anyway. Committed with the above additions, thanks. http://hg.nginx.org/nginx/rev/e393c0bf53d3 -- Maxim Dounin http://nginx.org/ From mdounin at mdounin.ru Thu Jul 7 13:58:48 2016 From: mdounin at mdounin.ru (Maxim Dounin) Date: Thu, 7 Jul 2016 16:58:48 +0300 Subject: [PATCH] Configure: fix build with -Werror=unused-value In-Reply-To: References: Message-ID: <20160707135848.GF30781@mdounin.ru> Hello! On Mon, Jun 27, 2016 at 03:59:18PM -0700, Piotr Sikora wrote: > # HG changeset patch > # User Piotr Sikora > # Date 1467064802 25200 > # Mon Jun 27 15:00:02 2016 -0700 > # Node ID f5ece83dbcc4c46bcda51511e4fbf8fb90aa9432 > # Parent d452cb27639f714bc43b7f3ede417e3e7f8efdd6 > Configure: fix build with -Werror=unused-value. > > Signed-off-by: Piotr Sikora > > diff -r d452cb27639f -r f5ece83dbcc4 auto/cc/conf > --- a/auto/cc/conf > +++ b/auto/cc/conf > @@ -231,7 +231,7 @@ if [ "$NGX_PLATFORM" != win32 ]; then > ngx_feature_incs= > ngx_feature_path= > ngx_feature_libs= > - ngx_feature_test="__builtin_bswap64(0)" > + ngx_feature_test="if (__builtin_bswap64(0)) return 1" > . auto/feature Committed, thanks. -- Maxim Dounin http://nginx.org/ From mdounin at mdounin.ru Thu Jul 7 13:59:18 2016 From: mdounin at mdounin.ru (Maxim Dounin) Date: Thu, 7 Jul 2016 16:59:18 +0300 Subject: [PATCH] Configure: fix build with -Werror=old-style-definition In-Reply-To: <3ba6126630ceec0767e7.1467068362@piotrsikora.sfo.corp.google.com> References: <3ba6126630ceec0767e7.1467068362@piotrsikora.sfo.corp.google.com> Message-ID: <20160707135917.GG30781@mdounin.ru> Hello! On Mon, Jun 27, 2016 at 03:59:22PM -0700, Piotr Sikora wrote: > # HG changeset patch > # User Piotr Sikora > # Date 1467064805 25200 > # Mon Jun 27 15:00:05 2016 -0700 > # Node ID 3ba6126630ceec0767e70b88be1a004d82e2c27e > # Parent d452cb27639f714bc43b7f3ede417e3e7f8efdd6 > Configure: fix build with -Werror=old-style-definition. Committed, thanks. -- Maxim Dounin http://nginx.org/ From mdounin at mdounin.ru Thu Jul 7 13:59:57 2016 From: mdounin at mdounin.ru (Maxim Dounin) Date: Thu, 7 Jul 2016 16:59:57 +0300 Subject: [PATCH] Configure: stop polluting NGX_ namespace In-Reply-To: <388cf446fe903cfdf0d1.1467068363@piotrsikora.sfo.corp.google.com> References: <388cf446fe903cfdf0d1.1467068363@piotrsikora.sfo.corp.google.com> Message-ID: <20160707135957.GH30781@mdounin.ru> Hello! On Mon, Jun 27, 2016 at 03:59:23PM -0700, Piotr Sikora wrote: > # HG changeset patch > # User Piotr Sikora > # Date 1467064806 25200 > # Mon Jun 27 15:00:06 2016 -0700 > # Node ID 388cf446fe903cfdf0d13740ab3489cc14a3f377 > # Parent d452cb27639f714bc43b7f3ede417e3e7f8efdd6 > Configure: stop polluting NGX_ namespace. > > While there, fix the only test that used alternative variable name. Committed, thanks. -- Maxim Dounin http://nginx.org/ From mdounin at mdounin.ru Thu Jul 7 15:01:26 2016 From: mdounin at mdounin.ru (Maxim Dounin) Date: Thu, 7 Jul 2016 18:01:26 +0300 Subject: [PATCH 1 of 2] HTTP: add support for trailers in HTTP responses In-Reply-To: References: <20160627134500.GZ30781@mdounin.ru> <20160627175338.GD30781@mdounin.ru> <20160704142135.GZ30781@mdounin.ru> Message-ID: <20160707150047.GJ30781@mdounin.ru> Hello! On Wed, Jul 06, 2016 at 02:02:19PM -0700, Piotr Sikora wrote: > Hey Maxim, > > > I'm not convinced this feature is needed at all. It looks more > > like a Google-specific experiment, and this is not something I > > would like to see in nginx code. > > Wait, what? Are you talking about trailers as defined in RFC7230 (and > previously in RFC2616 from 1999, when Google barely existed)? There is > nothing Google-specific about them. > > Also, you had people from 3 different companies asking and/or > commenting about trailers on this very mailing list in the last 6 > weeks, I'm not sure why you chose to ignore that. And these 3 people are the only people asking/commenting about trailers during the whole nginx history, AFAIR. And none of them provided any real-world use for trailers. On the other hand, your motivation is quite clear, it's about Google pushing it's own library, nothing more. > > If at all implemented, I would rather prefer adding trailers if a > > transfer encoding used allows this, and discrading them otherwise. > > This is something that anyway will happen if a protocol used does > > not allow trailers at all (e.g., HTTP/1.0). > > I'm confused, this is exactly what my patch is doing... unless you > want to completely ignore "TE" request header? Your patch forces use of chunked transfer encoding, and that's the point where I disagree. The "TE: trailers" request header means that client is able to understand trailers, but it doesn't mean that chunked encoding must be used even if content length is known. Using chunked transfer encoding instead of Content-Length may or may not be justified by trailers, and this depends on a particular use case. -- Maxim Dounin http://nginx.org/ From pluknet at nginx.com Thu Jul 7 18:08:21 2016 From: pluknet at nginx.com (Sergey Kandaurov) Date: Thu, 07 Jul 2016 18:08:21 +0000 Subject: [nginx] Avoid left-shifting integers into the sign bit, which is undefined. Message-ID: details: http://hg.nginx.org/nginx/rev/b3682580c1bd branches: changeset: 6626:b3682580c1bd user: Sergey Kandaurov date: Thu Jul 07 21:02:28 2016 +0300 description: Avoid left-shifting integers into the sign bit, which is undefined. Found with UndefinedBehaviorSanitizer. diffstat: src/core/ngx_string.c | 4 ++-- src/http/modules/ngx_http_log_module.c | 4 ++-- src/http/modules/ngx_http_userid_filter_module.c | 2 +- src/http/ngx_http_parse.c | 22 +++++++++++----------- 4 files changed, 16 insertions(+), 16 deletions(-) diffs (156 lines): diff -r a616bdc38645 -r b3682580c1bd src/core/ngx_string.c --- a/src/core/ngx_string.c Mon Jun 27 15:00:06 2016 -0700 +++ b/src/core/ngx_string.c Thu Jul 07 21:02:28 2016 +0300 @@ -1563,7 +1563,7 @@ ngx_escape_uri(u_char *dst, u_char *src, n = 0; while (size) { - if (escape[*src >> 5] & (1 << (*src & 0x1f))) { + if (escape[*src >> 5] & (1U << (*src & 0x1f))) { n++; } src++; @@ -1574,7 +1574,7 @@ ngx_escape_uri(u_char *dst, u_char *src, } while (size) { - if (escape[*src >> 5] & (1 << (*src & 0x1f))) { + if (escape[*src >> 5] & (1U << (*src & 0x1f))) { *dst++ = '%'; *dst++ = hex[*src >> 4]; *dst++ = hex[*src & 0xf]; diff -r a616bdc38645 -r b3682580c1bd src/http/modules/ngx_http_log_module.c --- a/src/http/modules/ngx_http_log_module.c Mon Jun 27 15:00:06 2016 -0700 +++ b/src/http/modules/ngx_http_log_module.c Thu Jul 07 21:02:28 2016 +0300 @@ -1000,7 +1000,7 @@ ngx_http_log_escape(u_char *dst, u_char n = 0; while (size) { - if (escape[*src >> 5] & (1 << (*src & 0x1f))) { + if (escape[*src >> 5] & (1U << (*src & 0x1f))) { n++; } src++; @@ -1011,7 +1011,7 @@ ngx_http_log_escape(u_char *dst, u_char } while (size) { - if (escape[*src >> 5] & (1 << (*src & 0x1f))) { + if (escape[*src >> 5] & (1U << (*src & 0x1f))) { *dst++ = '\\'; *dst++ = 'x'; *dst++ = hex[*src >> 4]; diff -r a616bdc38645 -r b3682580c1bd src/http/modules/ngx_http_userid_filter_module.c --- a/src/http/modules/ngx_http_userid_filter_module.c Mon Jun 27 15:00:06 2016 -0700 +++ b/src/http/modules/ngx_http_userid_filter_module.c Thu Jul 07 21:02:28 2016 +0300 @@ -836,7 +836,7 @@ ngx_http_userid_init_worker(ngx_cycle_t ngx_gettimeofday(&tp); /* use the most significant usec part that fits to 16 bits */ - start_value = ((tp.tv_usec / 20) << 16) | ngx_pid; + start_value = (((uint32_t) tp.tv_usec / 20) << 16) | ngx_pid; return NGX_OK; } diff -r a616bdc38645 -r b3682580c1bd src/http/ngx_http_parse.c --- a/src/http/ngx_http_parse.c Mon Jun 27 15:00:06 2016 -0700 +++ b/src/http/ngx_http_parse.c Thu Jul 07 21:02:28 2016 +0300 @@ -481,7 +481,7 @@ ngx_http_parse_request_line(ngx_http_req /* check "/.", "//", "%", and "\" (Win32) in URI */ case sw_after_slash_in_uri: - if (usual[ch >> 5] & (1 << (ch & 0x1f))) { + if (usual[ch >> 5] & (1U << (ch & 0x1f))) { state = sw_check_uri; break; } @@ -540,7 +540,7 @@ ngx_http_parse_request_line(ngx_http_req /* check "/", "%" and "\" (Win32) in URI */ case sw_check_uri: - if (usual[ch >> 5] & (1 << (ch & 0x1f))) { + if (usual[ch >> 5] & (1U << (ch & 0x1f))) { break; } @@ -626,7 +626,7 @@ ngx_http_parse_request_line(ngx_http_req /* URI */ case sw_uri: - if (usual[ch >> 5] & (1 << (ch & 0x1f))) { + if (usual[ch >> 5] & (1U << (ch & 0x1f))) { break; } @@ -1131,7 +1131,7 @@ ngx_http_parse_uri(ngx_http_request_t *r /* check "/.", "//", "%", and "\" (Win32) in URI */ case sw_after_slash_in_uri: - if (usual[ch >> 5] & (1 << (ch & 0x1f))) { + if (usual[ch >> 5] & (1U << (ch & 0x1f))) { state = sw_check_uri; break; } @@ -1179,7 +1179,7 @@ ngx_http_parse_uri(ngx_http_request_t *r /* check "/", "%" and "\" (Win32) in URI */ case sw_check_uri: - if (usual[ch >> 5] & (1 << (ch & 0x1f))) { + if (usual[ch >> 5] & (1U << (ch & 0x1f))) { break; } @@ -1228,7 +1228,7 @@ ngx_http_parse_uri(ngx_http_request_t *r /* URI */ case sw_uri: - if (usual[ch >> 5] & (1 << (ch & 0x1f))) { + if (usual[ch >> 5] & (1U << (ch & 0x1f))) { break; } @@ -1289,7 +1289,7 @@ ngx_http_parse_complex_uri(ngx_http_requ case sw_usual: - if (usual[ch >> 5] & (1 << (ch & 0x1f))) { + if (usual[ch >> 5] & (1U << (ch & 0x1f))) { *u++ = ch; ch = *p++; break; @@ -1358,7 +1358,7 @@ ngx_http_parse_complex_uri(ngx_http_requ case sw_slash: - if (usual[ch >> 5] & (1 << (ch & 0x1f))) { + if (usual[ch >> 5] & (1U << (ch & 0x1f))) { state = sw_usual; *u++ = ch; ch = *p++; @@ -1401,7 +1401,7 @@ ngx_http_parse_complex_uri(ngx_http_requ case sw_dot: - if (usual[ch >> 5] & (1 << (ch & 0x1f))) { + if (usual[ch >> 5] & (1U << (ch & 0x1f))) { state = sw_usual; *u++ = ch; ch = *p++; @@ -1442,7 +1442,7 @@ ngx_http_parse_complex_uri(ngx_http_requ case sw_dot_dot: - if (usual[ch >> 5] & (1 << (ch & 0x1f))) { + if (usual[ch >> 5] & (1U << (ch & 0x1f))) { state = sw_usual; *u++ = ch; ch = *p++; @@ -1836,7 +1836,7 @@ ngx_http_parse_unsafe_uri(ngx_http_reque continue; } - if (usual[ch >> 5] & (1 << (ch & 0x1f))) { + if (usual[ch >> 5] & (1U << (ch & 0x1f))) { continue; } From pluknet at nginx.com Thu Jul 7 18:08:24 2016 From: pluknet at nginx.com (Sergey Kandaurov) Date: Thu, 07 Jul 2016 18:08:24 +0000 Subject: [nginx] HTTP/2: avoid left-shifting signed integer into the sign bit. Message-ID: details: http://hg.nginx.org/nginx/rev/ad736705a744 branches: changeset: 6627:ad736705a744 user: Sergey Kandaurov date: Thu Jul 07 21:03:21 2016 +0300 description: HTTP/2: avoid left-shifting signed integer into the sign bit. On non-aligned platforms, properly cast argument before left-shifting it in ngx_http_v2_parse_uint32 that is used with u_char. Otherwise it propagates to int to hold the value and can step over the sign bit. Usually, on known compilers, this results in negation. Furthermore, a subsequent store into a wider type, that is ngx_uint_t on 64-bit platforms, results in sign-extension. In practice, this can be observed in debug log as a very large exclusive bit value, when client sent PRIORITY frame with exclusive bit set: : *14 http2 PRIORITY frame sid:5 on 1 excl:8589934591 weight:17 Found with UndefinedBehaviorSanitizer. diffstat: src/http/v2/ngx_http_v2.h | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diffs (12 lines): diff -r b3682580c1bd -r ad736705a744 src/http/v2/ngx_http_v2.h --- a/src/http/v2/ngx_http_v2.h Thu Jul 07 21:02:28 2016 +0300 +++ b/src/http/v2/ngx_http_v2.h Thu Jul 07 21:03:21 2016 +0300 @@ -298,7 +298,7 @@ size_t ngx_http_v2_huff_encode(u_char *s #define ngx_http_v2_parse_uint16(p) ((p)[0] << 8 | (p)[1]) #define ngx_http_v2_parse_uint32(p) \ - ((p)[0] << 24 | (p)[1] << 16 | (p)[2] << 8 | (p)[3]) + ((uint32_t) (p)[0] << 24 | (p)[1] << 16 | (p)[2] << 8 | (p)[3]) #endif From piotrsikora at google.com Thu Jul 7 20:08:46 2016 From: piotrsikora at google.com (Piotr Sikora) Date: Thu, 7 Jul 2016 13:08:46 -0700 Subject: [PATCH 1 of 2] HTTP: add support for trailers in HTTP responses In-Reply-To: <20160707150047.GJ30781@mdounin.ru> References: <20160627134500.GZ30781@mdounin.ru> <20160627175338.GD30781@mdounin.ru> <20160704142135.GZ30781@mdounin.ru> <20160707150047.GJ30781@mdounin.ru> Message-ID: Hey Maxim, > And these 3 people are the only people asking/commenting about > trailers during the whole nginx history, AFAIR. And none of them > provided any real-world use for trailers. That's true... Wesley, Shuxin, would you mind sharing your use cases? > On the other hand, your > motivation is quite clear, it's about Google pushing it's own > library, nothing more. I disagree. There is nothing gRPC-specific about trailers, the protocol is just layered on top of HTTP standard. Furthermore, like you previously noted, official gRPC clients & server are using HTTP/2, so there is absolutely no Google-agenda in pushing HTTP/1.1 trailers, other than me wanting to add proper support for trailers. > Your patch forces use of chunked transfer encoding, and that's the > point where I disagree. OK, that wasn't clear before. > The "TE: trailers" request header means > that client is able to understand trailers, but it doesn't mean > that chunked encoding must be used even if content length is > known. Using chunked transfer encoding instead of Content-Length > may or may not be justified by trailers, and this depends on a > particular use case. Well, I think that if someone decides to add trailers in nginx.conf (either via "add_trailer" or "proxy_pass_trailers" in the future), then forcing chunked encoding and emitting those trailers is much closer to the intent of the person that configured NGINX than silently dropping them. If that's a blocker for you, then I can change this behavior, but I think that most people would be quite surprised by explicitly configured trailers that are silently dropped from the response. Best regard, Piotr Sikora From mdounin at mdounin.ru Thu Jul 7 23:20:29 2016 From: mdounin at mdounin.ru (Maxim Dounin) Date: Fri, 8 Jul 2016 02:20:29 +0300 Subject: [PATCH 1 of 2] HTTP: add support for trailers in HTTP responses In-Reply-To: References: <20160627134500.GZ30781@mdounin.ru> <20160627175338.GD30781@mdounin.ru> <20160704142135.GZ30781@mdounin.ru> <20160707150047.GJ30781@mdounin.ru> Message-ID: <20160707232029.GO30781@mdounin.ru> Hello! On Thu, Jul 07, 2016 at 01:08:46PM -0700, Piotr Sikora wrote: [...] > Furthermore, like you previously noted, official gRPC clients & server > are using HTTP/2, so there is absolutely no Google-agenda in pushing > HTTP/1.1 trailers, other than me wanting to add proper support for > trailers. So the question remains: are there any real-world use cases? May be someone will be able to provide some. Without real-world use cases I don't think this should be added, as in general trailers is quite external concept to how nginx works and also may have various security implications. > > Your patch forces use of chunked transfer encoding, and that's the > > point where I disagree. > > OK, that wasn't clear before. > > > The "TE: trailers" request header means > > that client is able to understand trailers, but it doesn't mean > > that chunked encoding must be used even if content length is > > known. Using chunked transfer encoding instead of Content-Length > > may or may not be justified by trailers, and this depends on a > > particular use case. > > Well, I think that if someone decides to add trailers in nginx.conf > (either via "add_trailer" or "proxy_pass_trailers" in the future), > then forcing chunked encoding and emitting those trailers is much > closer to the intent of the person that configured NGINX than silently > dropping them. > > If that's a blocker for you, then I can change this behavior, but I > think that most people would be quite surprised by explicitly > configured trailers that are silently dropped from the response. Silently dropping trailers is what anyway happens if the client doesn't support chunked encoding at all (e.g., uses HTTP/1.0). And this is also what happens in your patch if there is no "TE: trailers". I think that whether to drop Content-Length and switch to chunked encoding is highly use-case specific question. In some cases it may be appropriate, in some cases not, and in some cases one may want to add trailers even without "TE: trailers". So forcing chunked encoding probably should be configured separately. On the other hand, it's very hard to decide something given there are no real use cases known. -- Maxim Dounin http://nginx.org/ From piotrsikora at google.com Thu Jul 7 23:51:08 2016 From: piotrsikora at google.com (Piotr Sikora) Date: Thu, 7 Jul 2016 16:51:08 -0700 Subject: [PATCH] Configure: fix build with -Werror=unused-but-set-variable In-Reply-To: <20160707135804.GE30781@mdounin.ru> References: <20160707135804.GE30781@mdounin.ru> Message-ID: Hey Maxim, > Quick look reveals at least the following additional places where the same > warning is generated: Ooops, looks that I've tested this only on Linux. Sorry about that, and thanks for catching other cases! Best regards, Piotr Sikora From piotrsikora at google.com Fri Jul 8 00:04:48 2016 From: piotrsikora at google.com (Piotr Sikora) Date: Thu, 7 Jul 2016 17:04:48 -0700 Subject: [PATCH] Configure: fix build with -Werror=nonnull In-Reply-To: <20160707135527.GD30781@mdounin.ru> References: <2c14d7fb1d96c3a1bfb7.1467068360@piotrsikora.sfo.corp.google.com> <20160707135527.GD30781@mdounin.ru> Message-ID: Hey Maxim, > First argument of dlopen() can be NULL, > http://pubs.opengroup.org/onlinepubs/9699919799/functions/dlopen.html: > > : If file is a null pointer, dlopen() shall return a global symbol > : table handle for the currently running process image. > > Linux seems to use nonnull for the second argument of dlsym(), > something like > > -ngx_feature_test="dlopen(NULL, RTLD_NOW | RTLD_GLOBAL); dlsym(NULL, NULL)" > +ngx_feature_test="dlopen(NULL, RTLD_NOW | RTLD_GLOBAL); dlsym(NULL, \"\")" > > should be enough to silence the warning. Weird, I was sure it was marked __nonnull for both arguments, but I cannot replicate it now and your fix is indeed enough to silence the warning. Thanks for double-checking! Best regards, Piotr Sikora From mdounin at mdounin.ru Fri Jul 8 00:43:23 2016 From: mdounin at mdounin.ru (Maxim Dounin) Date: Fri, 8 Jul 2016 03:43:23 +0300 Subject: [PATCH] Core: remove unused ngx_tm_zone In-Reply-To: <890dc5e6a88c49a9d724.1467068366@piotrsikora.sfo.corp.google.com> References: <890dc5e6a88c49a9d724.1467068366@piotrsikora.sfo.corp.google.com> Message-ID: <20160708004323.GP30781@mdounin.ru> Hello! On Mon, Jun 27, 2016 at 03:59:26PM -0700, Piotr Sikora wrote: > # HG changeset patch > # User Piotr Sikora > # Date 1467064808 25200 > # Mon Jun 27 15:00:08 2016 -0700 > # Node ID 890dc5e6a88c49a9d724cc7da1d0eb20fcc70768 > # Parent d452cb27639f714bc43b7f3ede417e3e7f8efdd6 > Core: remove unused ngx_tm_zone. > > Unused since 9c2f3ed7a247 (0.3.3). > > Signed-off-by: Piotr Sikora > > diff -r d452cb27639f -r 890dc5e6a88c src/os/unix/ngx_time.h > --- a/src/os/unix/ngx_time.h > +++ b/src/os/unix/ngx_time.h > @@ -38,7 +38,6 @@ typedef struct tm ngx_tm_t; > > #if (NGX_HAVE_GMTOFF) > #define ngx_tm_gmtoff tm_gmtoff > -#define ngx_tm_zone tm_zone > #endif > I would rather preserve this. Both tm_gmtoff and tm_zone are part of a popular extension to struct tm, and tm_zone may be useable in some cases. I see no downsides in preserving it even if it's not used now by nginx itself. -- Maxim Dounin http://nginx.org/ From mdounin at mdounin.ru Fri Jul 8 00:44:57 2016 From: mdounin at mdounin.ru (Maxim Dounin) Date: Fri, 8 Jul 2016 03:44:57 +0300 Subject: [PATCH] Core: remove unused NGX_INVALID_ARRAY_INDEX In-Reply-To: <8666abaeb43294edd5b9.1467068364@piotrsikora.sfo.corp.google.com> References: <8666abaeb43294edd5b9.1467068364@piotrsikora.sfo.corp.google.com> Message-ID: <20160708004457.GQ30781@mdounin.ru> Hello! On Mon, Jun 27, 2016 at 03:59:24PM -0700, Piotr Sikora wrote: > # HG changeset patch > # User Piotr Sikora > # Date 1467064807 25200 > # Mon Jun 27 15:00:07 2016 -0700 > # Node ID 8666abaeb43294edd5b93852bad2a42a27dd651b > # Parent d452cb27639f714bc43b7f3ede417e3e7f8efdd6 > Core: remove unused NGX_INVALID_ARRAY_INDEX. > > Unused since ae4744c28620 (0.7.51). > > Signed-off-by: Piotr Sikora > > diff -r d452cb27639f -r 8666abaeb432 src/core/ngx_config.h > --- a/src/core/ngx_config.h > +++ b/src/core/ngx_config.h > @@ -105,10 +105,6 @@ typedef intptr_t ngx_flag_t; > #define ngx_abort abort > > > -/* TODO: platform specific: array[NGX_INVALID_ARRAY_INDEX] must cause SIGSEGV */ > -#define NGX_INVALID_ARRAY_INDEX 0x80000000 > - > - > /* TODO: auto_conf: ngx_inline inline __inline __inline__ */ > #ifndef ngx_inline > #define ngx_inline inline I would rather preserve this either. It may be useable in some cases. -- Maxim Dounin http://nginx.org/ From mdounin at mdounin.ru Fri Jul 8 01:12:32 2016 From: mdounin at mdounin.ru (Maxim Dounin) Date: Fri, 8 Jul 2016 04:12:32 +0300 Subject: [PATCH 2 of 2] Core: remove NGX_TIME_T_SIZE In-Reply-To: References: <1059f59c44039020843c.1467077402@piotrsikora.sfo.corp.google.com> Message-ID: <20160708011232.GR30781@mdounin.ru> Hello! On Mon, Jun 27, 2016 at 06:30:03PM -0700, Piotr Sikora wrote: > # HG changeset patch > # User Piotr Sikora > # Date 1467064810 25200 > # Mon Jun 27 15:00:10 2016 -0700 > # Node ID a2892701d91e6aba62719b54792e1e14eeea11a0 > # Parent 1059f59c44039020843ced5bca39f165c322bacb > Core: remove NGX_TIME_T_SIZE. > > Replace ./configure-time test with equivalent compile-time test. > > Signed-off-by: Piotr Sikora > > diff -r 1059f59c4403 -r a2892701d91e auto/unix > --- a/auto/unix > +++ b/auto/unix > @@ -624,7 +624,6 @@ ngx_param=NGX_MAX_OFF_T_VALUE; ngx_value > ngx_param=NGX_OFF_T_LEN; ngx_value=$ngx_max_len; . auto/types/value > > ngx_type="time_t"; . auto/types/sizeof > -ngx_param=NGX_TIME_T_SIZE; ngx_value=$ngx_size; . auto/types/value > ngx_param=NGX_TIME_T_LEN; ngx_value=$ngx_max_len; . auto/types/value > ngx_param=NGX_MAX_TIME_T_VALUE; ngx_value=$ngx_max_value; . auto/types/value > > diff -r 1059f59c4403 -r a2892701d91e src/core/ngx_module.h > --- a/src/core/ngx_module.h > +++ b/src/core/ngx_module.h > @@ -18,9 +18,7 @@ > #define NGX_MODULE_UNSET_INDEX (ngx_uint_t) -1 > > > -#define NGX_MODULE_SIGNATURE_0 \ > - ngx_value(NGX_PTR_SIZE) "," \ > - ngx_value(NGX_TIME_T_SIZE) "," > +#define NGX_MODULE_SIGNATURE_0 ngx_value(NGX_PTR_SIZE) "," > > #if (NGX_HAVE_KQUEUE) > #define NGX_MODULE_SIGNATURE_1 "1" I don't think that size of time_t should be removed from module signatures. E.g., OpenBSD switched to 64-bit time_t on 32-bit hosts a couple of years ago, and I would expect similar things to happen on other platforms as well. Signatures were designed to prevent loading of incompatible modules in such cases. It can be replaced with, e.g., NGX_TIME_T_LEN, but I don't see reasoning behind these changes. Are you trying to make it possible to build nginx as a multiarchitecture binary? [...] -- Maxim Dounin http://nginx.org/ From mdounin at mdounin.ru Fri Jul 8 01:47:50 2016 From: mdounin at mdounin.ru (Maxim Dounin) Date: Fri, 8 Jul 2016 04:47:50 +0300 Subject: [PATCH] Core: detect valid error numbers at run-time In-Reply-To: References: Message-ID: <20160708014750.GS30781@mdounin.ru> Hello! On Fri, Jul 01, 2016 at 02:31:41PM -0700, Piotr Sikora wrote: > # HG changeset patch > # User Piotr Sikora > # Date 1467064814 25200 > # Mon Jun 27 15:00:14 2016 -0700 > # Node ID be7eadea3d089f18c5ea685c09824ddcd99c3fe5 > # Parent d452cb27639f714bc43b7f3ede417e3e7f8efdd6 > Core: detect valid error numbers at run-time. > > Strings for some error numbers might be omitted, at least on Linux, > so stop after 3 unknown errors in a row and not after the first one. > > Signed-off-by: Piotr Sikora > > diff -r d452cb27639f -r be7eadea3d08 auto/unix > --- a/auto/unix > +++ b/auto/unix > @@ -697,60 +697,6 @@ ngx_feature_test="char buf[1]; struct io > . auto/feature > > > -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 This looks utterly wrong. You are removing proper support for platforms with sys_nerr (including Linux and FreeBSD) and use instead the workaround designed to somehow work on other platforms. [...] -- Maxim Dounin http://nginx.org/ From mdounin at mdounin.ru Fri Jul 8 01:49:11 2016 From: mdounin at mdounin.ru (Maxim Dounin) Date: Fri, 8 Jul 2016 04:49:11 +0300 Subject: [PATCH] Configure: remove tests for a few standard C types In-Reply-To: <3bd4707f1bc170859f27.1467408703@piotrsikora.sfo.corp.google.com> References: <3bd4707f1bc170859f27.1467408703@piotrsikora.sfo.corp.google.com> Message-ID: <20160708014911.GT30781@mdounin.ru> Hello! On Fri, Jul 01, 2016 at 02:31:43PM -0700, Piotr Sikora wrote: > # HG changeset patch > # User Piotr Sikora > # Date 1467064813 25200 > # Mon Jun 27 15:00:13 2016 -0700 > # Node ID 3bd4707f1bc170859f27a8de6451531a675b5f3b > # Parent d452cb27639f714bc43b7f3ede417e3e7f8efdd6 > Configure: remove tests for a few standard C types. > > Results of those tests were unused since a88a3e4e158f (0.1.5). > > Also, this fixes build with -Werror=long-long, since ./configure > script was the only place where "long long" type was used. > > Signed-off-by: Piotr Sikora > > diff -r d452cb27639f -r 3bd4707f1bc1 auto/unix > --- a/auto/unix > +++ b/auto/unix > @@ -584,12 +584,6 @@ ngx_feature_libs= > > # C types > > -ngx_type="int"; . auto/types/sizeof > - > -ngx_type="long"; . auto/types/sizeof > - > -ngx_type="long long"; . auto/types/sizeof > - > ngx_type="void *"; . auto/types/sizeof; ngx_ptr_size=$ngx_size > ngx_param=NGX_PTR_SIZE; ngx_value=$ngx_size; . auto/types/value I would rather not, as result of these tests are useful when manually looking into configure output. -- Maxim Dounin http://nginx.org/ From mdounin at mdounin.ru Fri Jul 8 14:11:55 2016 From: mdounin at mdounin.ru (Maxim Dounin) Date: Fri, 8 Jul 2016 17:11:55 +0300 Subject: [PATCH] Core: reorder #ifdef in .h file to match order in .c file In-Reply-To: <11a53446bd90b8927cb9.1467082518@piotrsikora.sfo.corp.google.com> References: <11a53446bd90b8927cb9.1467082518@piotrsikora.sfo.corp.google.com> Message-ID: <20160708141155.GV30781@mdounin.ru> Hello! On Mon, Jun 27, 2016 at 07:55:18PM -0700, Piotr Sikora wrote: > # HG changeset patch > # User Piotr Sikora > # Date 1467064811 25200 > # Mon Jun 27 15:00:11 2016 -0700 > # Node ID 11a53446bd90b8927cb93847c98672a8f056d182 > # Parent d452cb27639f714bc43b7f3ede417e3e7f8efdd6 > Core: reorder #ifdef in .h file to match order in .c file. Current order matches one used in #if in the same .h file, and I don't think this order needs to be changed. -- Maxim Dounin http://nginx.org/ From manole at amazon.com Sun Jul 10 07:50:36 2016 From: manole at amazon.com (Manole, Sorin) Date: Sun, 10 Jul 2016 07:50:36 +0000 Subject: error_page redirect sends incomplete request to upstream Message-ID: <253bc8b8e00b4d60975eea4cb6f9f618@EX13D06EUA003.ant.amazon.com> Hello, I opened https://trac.nginx.org/nginx/ticket/1010 for this. The bug appears when request_body_buffering is off (but maybe not only), and error pages are set to be served from an upstream using an internal redirect. If a problem happens while the request body is read/sent to the upstream in a non-buffered fashion, and nginx tries to serve an error page, it rewrites the HTTP method from POST to GET request, but keeps the old value of the Content-Length header when trying to serve the error page from the upstream. This is done here: https://trac.nginx.org/nginx/browser/nginx/src/http/ngx_http_special_response.c#L575 No body data is sent in the error page upstream request, even though it is declared in the header, which can cause the upstream server to wait for it. This is seen by the client as the request hanging until the configured upstream timeout. Can this be fixed by clearing any Content-Length or Transfer-Encoding headers when error pages are served? Thank you. From liulele at yunify.com Mon Jul 11 08:22:39 2016 From: liulele at yunify.com (Lele Liu) Date: Mon, 11 Jul 2016 16:22:39 +0800 (CST) Subject: Add a postpone-mode to transfer request body to upstream Message-ID: <23eb55bb.1805b.155d90d0e4b.Coremail.liulele@yunify.com> Hi, I want to add a postpone mode to nginx for transfer data to upstream as described bellow. Any opinions? ##Purpose Purpose of this change is to provide a mode among nginx non-buffered mode and buffered mode. We call this mode `postpone mode`. In this mode, 1) request body is transferred to upstream in a bulk mode. 2) Connection to upstream is established on first time transferring. ##implementation 1. Use a ping-pong buffer to receive client request body. By default, nginx use only one buffer (i.e. request_body->buf) to receive client request body. When this buffer is full nginx will stop receiving and wait it to be free (wait `rb->busy` to be null). A ping-pong buffer will reduce the chance of waiting. When one buffer is used for upstream sending, the other buffer can be used to receive client data. In postpone mode, receive buffer (`rb->buf`) is send to upstream only when it is full. This is different than the original nginx behavior, that send received data to upstream immediately regardless of the data length. 2. The moment to call `ngx_http_upstream_init` `ngx_http_upstream_init` is called to establish connection to upstream. By default, nginx call this function in two places depends on upstream transfer mode. - for buffered mode, this init function is called after whole request body is received and buffered. - for non-buffered mode, this init function is called after first call to `ngx_http_do_read_client_request_body` in `ngx_http_read_client_request_body` regardless the whole body is received or not. For postpone mode, the init function will be called on first time there's need send data to upstream. i.e. the first time the receive buffer is full, since postpone mode transfer data when receive buffer is full. Best Regards LiuLele -------------- next part -------------- An HTML attachment was scrubbed... URL: From igor at sysoev.ru Mon Jul 11 12:10:01 2016 From: igor at sysoev.ru (Igor Sysoev) Date: Mon, 11 Jul 2016 12:10:01 +0000 Subject: [njs] Byte string processing was fixed in String.split(), Message-ID: details: http://hg.nginx.org/njs/rev/73dc069a08c0 branches: changeset: 116:73dc069a08c0 user: Igor Sysoev date: Thu Jul 07 20:49:57 2016 +0300 description: Byte string processing was fixed in String.split(), the issue has been found by Coverity Scan. diffstat: njs/njs_string.c | 69 ++++++++++++++++++++++++++++++++++++++--------- njs/test/njs_unit_test.c | 3 ++ 2 files changed, 59 insertions(+), 13 deletions(-) diffs (139 lines): diff -r ef2b708510b1 -r 73dc069a08c0 njs/njs_string.c --- a/njs/njs_string.c Wed Jun 29 13:38:20 2016 +0300 +++ b/njs/njs_string.c Thu Jul 07 20:49:57 2016 +0300 @@ -40,6 +40,8 @@ static njs_ret_t njs_string_prototype_fr njs_value_t *args, nxt_uint_t nargs, njs_index_t unused); static nxt_noinline ssize_t njs_string_index_of(njs_vm_t *vm, njs_value_t *src, njs_value_t *search_string, size_t index); +static njs_ret_t njs_string_split_part_add(njs_vm_t *vm, njs_array_t *array, + u_char *start, size_t size, nxt_uint_t utf8); njs_ret_t @@ -1657,7 +1659,7 @@ njs_string_prototype_split(njs_vm_t *vm, u_char *p, *start, *next; size_t size, length; uint32_t limit; - nxt_uint_t n; + nxt_uint_t n, utf8; njs_array_t *array; const u_char *end; njs_string_prop_t string, split; @@ -1681,13 +1683,32 @@ njs_string_prototype_split(njs_vm_t *vm, limit = (uint32_t) -1; } + length = njs_string_prop(&string, &args[0]); + + if (string.size == 0) { + goto single; + } + + /* Byte string. */ + utf8 = 0; + n = 0; + + if (string.length != 0) { + /* ASCII string. */ + utf8 = 1; + n = 1; + + if (string.length != string.size) { + /* UTF-8 string. */ + utf8 = 2; + } + } + switch (args[1].type) { case NJS_STRING: (void) njs_string_prop(&split, &args[1]); - length = njs_string_prop(&string, &args[0]); - if (string.size < split.size) { goto single; } @@ -1711,9 +1732,8 @@ njs_string_prototype_split(njs_vm_t *vm, } size = p - start; - length = nxt_utf8_length(start, size); - - ret = njs_array_string_add(vm, array, start, size, length); + + ret = njs_string_split_part_add(vm, array, start, size, utf8); if (nxt_slow_path(ret != NXT_OK)) { return ret; } @@ -1728,10 +1748,6 @@ njs_string_prototype_split(njs_vm_t *vm, case NJS_REGEXP: pattern = args[1].data.u.regexp->pattern; - (void) njs_string_prop(&string, &args[0]); - - n = (string.length != 0 && string.length != string.size); - if (!nxt_regex_is_valid(&pattern->regex[n])) { goto single; } @@ -1764,9 +1780,8 @@ njs_string_prototype_split(njs_vm_t *vm, } size = p - start; - length = nxt_utf8_length(start, size); - - ret = njs_array_string_add(vm, array, start, size, length); + + ret = njs_string_split_part_add(vm, array, start, size, utf8); if (nxt_slow_path(ret != NXT_OK)) { return ret; } @@ -1799,6 +1814,34 @@ done: } +static njs_ret_t +njs_string_split_part_add(njs_vm_t *vm, njs_array_t *array, u_char *start, + size_t size, nxt_uint_t utf8) +{ + uint32_t length; + + switch (utf8) { + case 0: + length = 0; + break; + + case 1: + length = size; + break; + + default: + length = nxt_utf8_length(start, size); + + if (nxt_slow_path(length < 0)) { + vm->exception = &njs_exception_internal_error; + return NXT_ERROR; + } + } + + return njs_array_string_add(vm, array, start, size, length); +} + + njs_ret_t njs_primitive_value_to_string(njs_vm_t *vm, njs_value_t *dst, const njs_value_t *src) diff -r ef2b708510b1 -r 73dc069a08c0 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Wed Jun 29 13:38:20 2016 +0300 +++ b/njs/test/njs_unit_test.c Thu Jul 07 20:49:57 2016 +0300 @@ -2951,6 +2951,9 @@ static njs_unit_test_t njs_test[] = { nxt_string("'abc'.split('')"), nxt_string("a,b,c") }, + { nxt_string("'abc'.split('abc')"), + nxt_string(",") }, + { nxt_string("'a bc def'.split(' ')"), nxt_string("a,bc,def") }, From igor at sysoev.ru Mon Jul 11 12:10:03 2016 From: igor at sysoev.ru (Igor Sysoev) Date: Mon, 11 Jul 2016 12:10:03 +0000 Subject: [njs] Now ASCII strings use UTF8 variant of PCRE code. Message-ID: details: http://hg.nginx.org/njs/rev/6888c62477a0 branches: changeset: 117:6888c62477a0 user: Igor Sysoev date: Fri Jul 08 18:07:57 2016 +0300 description: Now ASCII strings use UTF8 variant of PCRE code. diffstat: njs/njs_regexp.c | 5 ++++- njs/njs_string.c | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diffs (55 lines): diff -r 73dc069a08c0 -r 6888c62477a0 njs/njs_regexp.c --- a/njs/njs_regexp.c Thu Jul 07 20:49:57 2016 +0300 +++ b/njs/njs_regexp.c Fri Jul 08 18:07:57 2016 +0300 @@ -476,7 +476,7 @@ njs_regexp_prototype_test(njs_vm_t *vm, (void) njs_string_prop(&string, value); - n = (string.length != 0 && string.length != string.size); + n = (string.length != 0); pattern = args[0].data.u.regexp->pattern; @@ -527,14 +527,17 @@ njs_regexp_prototype_exec(njs_vm_t *vm, (void) njs_string_prop(&string, value); + /* Byte string. */ utf8 = 0; n = 0; if (string.length != 0) { + /* ASCII string. */ utf8 = 1; n = 1; if (string.length != string.size) { + /* UTF-8 string. */ utf8 = 2; } } diff -r 73dc069a08c0 -r 6888c62477a0 njs/njs_string.c --- a/njs/njs_string.c Thu Jul 07 20:49:57 2016 +0300 +++ b/njs/njs_string.c Fri Jul 08 18:07:57 2016 +0300 @@ -1450,7 +1450,7 @@ njs_string_prototype_search(njs_vm_t *vm (void) njs_string_prop(&string, &args[0]); - n = (string.length != 0 && string.length != string.size); + n = (string.length != 0); if (nxt_regex_is_valid(&pattern->regex[n])) { ret = nxt_regex_match(&pattern->regex[n], string.start, string.size, @@ -1696,11 +1696,11 @@ njs_string_prototype_split(njs_vm_t *vm, if (string.length != 0) { /* ASCII string. */ utf8 = 1; - n = 1; if (string.length != string.size) { /* UTF-8 string. */ utf8 = 2; + n = 1; } } From igor at sysoev.ru Mon Jul 11 12:10:05 2016 From: igor at sysoev.ru (Igor Sysoev) Date: Mon, 11 Jul 2016 12:10:05 +0000 Subject: [njs] Needless argument checkers for String.toLowerCase() Message-ID: details: http://hg.nginx.org/njs/rev/e4a0f80610b2 branches: changeset: 118:e4a0f80610b2 user: Igor Sysoev date: Fri Jul 08 18:13:00 2016 +0300 description: Needless argument checkers for String.toLowerCase() and String.toUpperCase() have been removed. diffstat: njs/njs_string.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diffs (20 lines): diff -r 6888c62477a0 -r e4a0f80610b2 njs/njs_string.c --- a/njs/njs_string.c Fri Jul 08 18:07:57 2016 +0300 +++ b/njs/njs_string.c Fri Jul 08 18:13:00 2016 +0300 @@ -2075,14 +2075,14 @@ static const njs_object_prop_t njs_stri .type = NJS_METHOD, .name = njs_string("toLowerCase"), .value = njs_native_function(njs_string_prototype_to_lower_case, 0, - NJS_STRING_OBJECT_ARG, NJS_REGEXP_ARG), + NJS_STRING_OBJECT_ARG), }, { .type = NJS_METHOD, .name = njs_string("toUpperCase"), .value = njs_native_function(njs_string_prototype_to_upper_case, 0, - NJS_STRING_OBJECT_ARG, NJS_REGEXP_ARG), + NJS_STRING_OBJECT_ARG), }, { From igor at sysoev.ru Mon Jul 11 12:24:44 2016 From: igor at sysoev.ru (Igor Sysoev) Date: Mon, 11 Jul 2016 12:24:44 +0000 Subject: [njs] Fixed building by modern GCC versions. Message-ID: details: http://hg.nginx.org/njs/rev/5e7e498eb90d branches: changeset: 119:5e7e498eb90d user: Igor Sysoev date: Mon Jul 11 15:24:29 2016 +0300 description: Fixed building by modern GCC versions. diffstat: njs/njs_string.c | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diffs (30 lines): diff -r e4a0f80610b2 -r 5e7e498eb90d njs/njs_string.c --- a/njs/njs_string.c Fri Jul 08 18:13:00 2016 +0300 +++ b/njs/njs_string.c Mon Jul 11 15:24:29 2016 +0300 @@ -1657,7 +1657,7 @@ njs_string_prototype_split(njs_vm_t *vm, { int ret, *captures; u_char *p, *start, *next; - size_t size, length; + size_t size; uint32_t limit; nxt_uint_t n, utf8; njs_array_t *array; @@ -1683,7 +1683,7 @@ njs_string_prototype_split(njs_vm_t *vm, limit = (uint32_t) -1; } - length = njs_string_prop(&string, &args[0]); + (void) njs_string_prop(&string, &args[0]); if (string.size == 0) { goto single; @@ -1818,7 +1818,7 @@ static njs_ret_t njs_string_split_part_add(njs_vm_t *vm, njs_array_t *array, u_char *start, size_t size, nxt_uint_t utf8) { - uint32_t length; + ssize_t length; switch (utf8) { case 0: From mdounin at mdounin.ru Mon Jul 11 14:36:30 2016 From: mdounin at mdounin.ru (Maxim Dounin) Date: Mon, 11 Jul 2016 17:36:30 +0300 Subject: error_page redirect sends incomplete request to upstream In-Reply-To: <253bc8b8e00b4d60975eea4cb6f9f618@EX13D06EUA003.ant.amazon.com> References: <253bc8b8e00b4d60975eea4cb6f9f618@EX13D06EUA003.ant.amazon.com> Message-ID: <20160711143630.GD57459@mdounin.ru> Hello! On Sun, Jul 10, 2016 at 07:50:36AM +0000, Manole, Sorin wrote: > Hello, > > I opened https://trac.nginx.org/nginx/ticket/1010 for this. > > The bug appears when request_body_buffering is off (but maybe not only), and error pages are set to be served from an upstream using an internal redirect. > > If a problem happens while the request body is read/sent to the upstream in a non-buffered fashion, and nginx tries to serve an error page, it rewrites the HTTP method from POST to GET request, but keeps the old value of the Content-Length header when trying to serve the error page from the upstream. > This is done here: https://trac.nginx.org/nginx/browser/nginx/src/http/ngx_http_special_response.c#L575 > No body data is sent in the error page upstream request, even though it is declared in the header, which can cause the upstream server to wait for it. This is seen by the client as the request hanging until the configured upstream timeout. > > Can this be fixed by clearing any Content-Length or Transfer-Encoding headers when error pages are served? When using error_page with "proxy_request_buffering off" it is not possible to re-send a request to upstream as is, as the body is no longer available (or only partially available). If you want to redirect errors after a failed proxy_pass with disabled request body bufferng to an upstream server, consider using "proxy_pass_request_body off" and clearing Content-Length/Transfer-Encoding headers with proxy_set_header, e.g.: location /upload/ { proxy_pass ... proxy_request_buffering off; error_page 502 /error; } location /error { proxy_pass ... proxy_pass_request_body off; proxy_set_header Content-Length ""; proxy_set_header Transfer-Encoding ""; } As of now it is not something handled automatically and probably won't be in the near future, "proxy_request_buffering off" is a special mode and it is to be used with care. I personally wouldn't recommend redirecting any errors after a failed proxy_pass with disabled request body buffering to anything but a static file (if at all). -- Maxim Dounin http://nginx.org/ From rajalakshmi.iyer at blis.com Mon Jul 11 23:35:39 2016 From: rajalakshmi.iyer at blis.com (Rajalakshmi Iyer) Date: Tue, 12 Jul 2016 00:35:39 +0100 Subject: Need help with sub-request handling Message-ID: Hello, I am trying to write an Nginx module that tries to do the following in the content phase handler - - Read the POST body - Call a sub-request to another location module within the same server - Return a 204 response after the sub-request is completed (for test purposes only) Here is the pseudo code for the handler (Apologies for the longish description, I have tried to keep the code to a minimum required to describe the issue I am facing) - ngx_int_t ngx_http_test_handler(ngx_http_request_t* r) { ngx_http_test_ctx_t* ctx = ngx_http_get_module_ctx(r, ngx_http_test_module); // Initialize request context if (ctx == NULL) { ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_test_ctx_t)); ctx->waiting_more_body = false; ctx->read_body_done = false; ctx->sub_request = NULL; ngx_http_set_ctx(r, ctx, ngx_http_test_module); } // If sub-request is in progress if (ctx->sub_request && !ctx->sub_request->done) { return NGX_DONE; } // If awaiting more POST body if (ctx->waiting_more_body) { return NGX_DONE; } // If POST body not yet read if (!ctx->read_body_done) { rc = ngx_http_read_client_request_body(r, ngx_http_test_content_phase_post_read); if (rc == NGX_AGAIN) { ctx->waiting_more_body = true; return NGX_DONE; } } // If body read if (ctx->read_body_done) { // Initiate sub-request if not yet done if (!ctx->sub_request) { ngx_http_test_subrequest(r); return NGX_DONE; } // If sub-request completed if (ctx->sub_request->done) { // Return test response r->headers_out.status = NGX_HTTP_NO_CONTENT; ngx_http_send_header(r); ngx_http_finalize_request(r, NGX_HTTP_NO_CONTENT); } // Sub-request is in progress return NGX_DONE; } return NGX_OK; } This is the post read callback hander - static void ngx_http_ssp_content_phase_post_read(ngx_http_request_t *r) { ngx_http_test_ctx_t* ctx = ngx_http_get_module_ctx(r, ngx_http_test_module); ctx->read_body_done = true; if (ctx->waiting_more_body) { ctx->waiting_more_body = false; ngx_http_finalize_request(r, ngx_http_test_request_handler(r)); } else { r->main->count--; } } And here is the pseudo code for the function that initiates the sub-request - ngx_int_t ngx_http_ssp_auction_subrequest(ngx_http_request_t* r) { ngx_http_test_ctx_t* ctx = ngx_http_get_module_ctx(r, ngx_http_test_module); // Setup post sub-request handler ngx_http_post_subrequest_t* psr = ngx_pcalloc(r->pool, sizeof(ngx_http_post_subrequest_t)); psr->handler = ngx_http_test_post_subrequest; return ngx_http_subrequest(r, &location, url_args, &ctx->sub_request, psr, 0); } And finally the post sub-request handler - ngx_int_t ngx_http_test_auction_post_subrequest(ngx_http_request_t *r, void* data, ngx_int_t rc) { // Mark the sub-request as done r->done = true; return NGX_DONE; } When I run this, here are the observations - - The ngx_http_test_auction_post_subrequest is being called twice - - First via the sub-request location module handler's ngx_http_finalize_request - Second via the core content phase's call to ngx_http_finalize_request Is this expected? - When I issue a request at the main module's entry point, I can see everything working, until the post subrequest handler is called twice. Thereafter, I don't see the test response (204) and the request just hangs. If I terminate nginx, I can see the 204 response. Any pointers on what is going wrong and how to correct it is greatly appreciated. Thanks in advance, Raj -- This email and any attachments to it may be confidential and are intended solely for the use of the individual to whom it is addressed. Any views or opinions expressed are solely those of the author and do not necessarily represent those of Blis Ltd, a company registered in England and Wales with registered number 06455773. Its registered office is 5th Floor, 85 Tottenham Court Road, London, W1T 4TQ, United Kingdom. If you are not the intended recipient of this email, you must neither take any action based upon its contents, nor copy or show it to anyone. Please contact the sender if you believe you have received this email in error. -------------- next part -------------- An HTML attachment was scrubbed... URL: From vl at nginx.com Tue Jul 12 09:41:21 2016 From: vl at nginx.com (Vladimir Homutov) Date: Tue, 12 Jul 2016 09:41:21 +0000 Subject: [nginx] Stream: individual build options for modules. Message-ID: details: http://hg.nginx.org/nginx/rev/7cbc6bc63228 branches: changeset: 6628:7cbc6bc63228 user: Vladimir Homutov date: Tue Jul 12 12:38:01 2016 +0300 description: Stream: individual build options for modules. diffstat: auto/modules | 18 ++++++++++++++++-- 1 files changed, 16 insertions(+), 2 deletions(-) diffs (84 lines): diff -r ad736705a744 -r 7cbc6bc63228 auto/modules --- a/auto/modules Thu Jul 07 21:03:21 2016 +0300 +++ b/auto/modules Tue Jul 12 12:38:01 2016 +0300 @@ -965,8 +965,6 @@ if [ $STREAM != NO ]; then STREAM_INCS= ngx_module_type=STREAM - ngx_module_libs= - ngx_module_link=YES ngx_module_order= @@ -1000,6 +998,8 @@ if [ $STREAM != NO ]; then ngx_module_name=ngx_stream_ssl_module ngx_module_deps=src/stream/ngx_stream_ssl_module.h ngx_module_srcs=src/stream/ngx_stream_ssl_module.c + ngx_module_libs= + ngx_module_link=$STREAM_SSL . auto/module fi @@ -1008,6 +1008,8 @@ if [ $STREAM != NO ]; then ngx_module_name=ngx_stream_limit_conn_module ngx_module_deps= ngx_module_srcs=src/stream/ngx_stream_limit_conn_module.c + ngx_module_libs= + ngx_module_link=$STREAM_LIMIT_CONN . auto/module fi @@ -1016,6 +1018,8 @@ if [ $STREAM != NO ]; then ngx_module_name=ngx_stream_access_module ngx_module_deps= ngx_module_srcs=src/stream/ngx_stream_access_module.c + ngx_module_libs= + ngx_module_link=$STREAM_ACCESS . auto/module fi @@ -1024,6 +1028,8 @@ if [ $STREAM != NO ]; then ngx_module_name=ngx_stream_map_module ngx_module_deps= ngx_module_srcs=src/stream/ngx_stream_map_module.c + ngx_module_libs= + ngx_module_link=$STREAM_MAP . auto/module fi @@ -1032,6 +1038,8 @@ if [ $STREAM != NO ]; then ngx_module_name=ngx_stream_return_module ngx_module_deps= ngx_module_srcs=src/stream/ngx_stream_return_module.c + ngx_module_libs= + ngx_module_link=$STREAM_RETURN . auto/module fi @@ -1040,6 +1048,8 @@ if [ $STREAM != NO ]; then ngx_module_name=ngx_stream_upstream_hash_module ngx_module_deps= ngx_module_srcs=src/stream/ngx_stream_upstream_hash_module.c + ngx_module_libs= + ngx_module_link=$STREAM_UPSTREAM_HASH . auto/module fi @@ -1048,6 +1058,8 @@ if [ $STREAM != NO ]; then ngx_module_name=ngx_stream_upstream_least_conn_module ngx_module_deps= ngx_module_srcs=src/stream/ngx_stream_upstream_least_conn_module.c + ngx_module_libs= + ngx_module_link=$STREAM_UPSTREAM_LEAST_CONN . auto/module fi @@ -1058,6 +1070,8 @@ if [ $STREAM != NO ]; then ngx_module_name=ngx_stream_upstream_zone_module ngx_module_deps= ngx_module_srcs=src/stream/ngx_stream_upstream_zone_module.c + ngx_module_libs= + ngx_module_link=$STREAM_UPSTREAM_ZONE . auto/module fi From vl at nginx.com Tue Jul 12 14:37:53 2016 From: vl at nginx.com (Vladimir Homutov) Date: Tue, 12 Jul 2016 14:37:53 +0000 Subject: [nginx] Stream: style. Message-ID: details: http://hg.nginx.org/nginx/rev/8ed51b02f655 branches: changeset: 6629:8ed51b02f655 user: Vladimir Homutov date: Tue Jul 12 17:34:40 2016 +0300 description: Stream: style. diffstat: src/stream/ngx_stream_limit_conn_module.c | 2 +- src/stream/ngx_stream_map_module.c | 2 +- src/stream/ngx_stream_return_module.c | 2 +- src/stream/ngx_stream_upstream.c | 2 +- src/stream/ngx_stream_upstream_hash_module.c | 2 +- src/stream/ngx_stream_upstream_least_conn_module.c | 2 +- src/stream/ngx_stream_upstream_zone_module.c | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diffs (84 lines): diff -r 7cbc6bc63228 -r 8ed51b02f655 src/stream/ngx_stream_limit_conn_module.c --- a/src/stream/ngx_stream_limit_conn_module.c Tue Jul 12 12:38:01 2016 +0300 +++ b/src/stream/ngx_stream_limit_conn_module.c Tue Jul 12 17:34:40 2016 +0300 @@ -101,7 +101,7 @@ static ngx_stream_module_t ngx_stream_l NULL, /* init main configuration */ ngx_stream_limit_conn_create_conf, /* create server configuration */ - ngx_stream_limit_conn_merge_conf, /* merge server configuration */ + ngx_stream_limit_conn_merge_conf /* merge server configuration */ }; diff -r 7cbc6bc63228 -r 8ed51b02f655 src/stream/ngx_stream_map_module.c --- a/src/stream/ngx_stream_map_module.c Tue Jul 12 12:38:01 2016 +0300 +++ b/src/stream/ngx_stream_map_module.c Tue Jul 12 17:34:40 2016 +0300 @@ -81,7 +81,7 @@ static ngx_stream_module_t ngx_stream_m NULL, /* init main configuration */ NULL, /* create server configuration */ - NULL, /* merge server configuration */ + NULL /* merge server configuration */ }; diff -r 7cbc6bc63228 -r 8ed51b02f655 src/stream/ngx_stream_return_module.c --- a/src/stream/ngx_stream_return_module.c Tue Jul 12 12:38:01 2016 +0300 +++ b/src/stream/ngx_stream_return_module.c Tue Jul 12 17:34:40 2016 +0300 @@ -48,7 +48,7 @@ static ngx_stream_module_t ngx_stream_r NULL, /* init main configuration */ ngx_stream_return_create_srv_conf, /* create server configuration */ - NULL, /* merge server configuration */ + NULL /* merge server configuration */ }; diff -r 7cbc6bc63228 -r 8ed51b02f655 src/stream/ngx_stream_upstream.c --- a/src/stream/ngx_stream_upstream.c Tue Jul 12 12:38:01 2016 +0300 +++ b/src/stream/ngx_stream_upstream.c Tue Jul 12 17:34:40 2016 +0300 @@ -46,7 +46,7 @@ static ngx_stream_module_t ngx_stream_u ngx_stream_upstream_init_main_conf, /* init main configuration */ NULL, /* create server configuration */ - NULL, /* merge server configuration */ + NULL /* merge server configuration */ }; diff -r 7cbc6bc63228 -r 8ed51b02f655 src/stream/ngx_stream_upstream_hash_module.c --- a/src/stream/ngx_stream_upstream_hash_module.c Tue Jul 12 12:38:01 2016 +0300 +++ b/src/stream/ngx_stream_upstream_hash_module.c Tue Jul 12 17:34:40 2016 +0300 @@ -84,7 +84,7 @@ static ngx_stream_module_t ngx_stream_u NULL, /* init main configuration */ ngx_stream_upstream_hash_create_conf, /* create server configuration */ - NULL, /* merge server configuration */ + NULL /* merge server configuration */ }; diff -r 7cbc6bc63228 -r 8ed51b02f655 src/stream/ngx_stream_upstream_least_conn_module.c --- a/src/stream/ngx_stream_upstream_least_conn_module.c Tue Jul 12 12:38:01 2016 +0300 +++ b/src/stream/ngx_stream_upstream_least_conn_module.c Tue Jul 12 17:34:40 2016 +0300 @@ -39,7 +39,7 @@ static ngx_stream_module_t ngx_stream_u NULL, /* init main configuration */ NULL, /* create server configuration */ - NULL, /* merge server configuration */ + NULL /* merge server configuration */ }; diff -r 7cbc6bc63228 -r 8ed51b02f655 src/stream/ngx_stream_upstream_zone_module.c --- a/src/stream/ngx_stream_upstream_zone_module.c Tue Jul 12 12:38:01 2016 +0300 +++ b/src/stream/ngx_stream_upstream_zone_module.c Tue Jul 12 17:34:40 2016 +0300 @@ -39,7 +39,7 @@ static ngx_stream_module_t ngx_stream_u NULL, /* init main configuration */ NULL, /* create server configuration */ - NULL, /* merge server configuration */ + NULL /* merge server configuration */ }; From vl at nginx.com Tue Jul 12 14:37:56 2016 From: vl at nginx.com (Vladimir Homutov) Date: Tue, 12 Jul 2016 14:37:56 +0000 Subject: [nginx] Stream: geoip module. Message-ID: details: http://hg.nginx.org/nginx/rev/558db057adaa branches: changeset: 6630:558db057adaa user: Vladimir Homutov date: Tue Jul 12 17:34:43 2016 +0300 description: Stream: geoip module. diffstat: auto/modules | 10 + auto/options | 6 + src/stream/ngx_stream_geoip_module.c | 814 +++++++++++++++++++++++++++++++++++ 3 files changed, 830 insertions(+), 0 deletions(-) diffs (868 lines): diff -r 8ed51b02f655 -r 558db057adaa auto/modules --- a/auto/modules Tue Jul 12 17:34:40 2016 +0300 +++ b/auto/modules Tue Jul 12 17:34:43 2016 +0300 @@ -1024,6 +1024,16 @@ if [ $STREAM != NO ]; then . auto/module fi + if [ $STREAM_GEOIP != NO ]; then + ngx_module_name=ngx_stream_geoip_module + ngx_module_deps= + ngx_module_srcs=src/stream/ngx_stream_geoip_module.c + ngx_module_libs=GEOIP + ngx_module_link=$STREAM_GEOIP + + . auto/module + fi + if [ $STREAM_MAP = YES ]; then ngx_module_name=ngx_stream_map_module ngx_module_deps= diff -r 8ed51b02f655 -r 558db057adaa auto/options --- a/auto/options Tue Jul 12 17:34:40 2016 +0300 +++ b/auto/options Tue Jul 12 17:34:43 2016 +0300 @@ -117,6 +117,7 @@ STREAM=NO STREAM_SSL=NO STREAM_LIMIT_CONN=YES STREAM_ACCESS=YES +STREAM_GEOIP=NO STREAM_MAP=YES STREAM_RETURN=YES STREAM_UPSTREAM_HASH=YES @@ -293,6 +294,9 @@ use the \"--with-mail_ssl_module\" optio --with-stream) STREAM=YES ;; --with-stream=dynamic) STREAM=DYNAMIC ;; --with-stream_ssl_module) STREAM_SSL=YES ;; + --with-stream_geoip_module) STREAM_GEOIP=YES ;; + --with-stream_geoip_module=dynamic) + STREAM_GEOIP=DYNAMIC ;; --without-stream_limit_conn_module) STREAM_LIMIT_CONN=NO ;; --without-stream_access_module) STREAM_ACCESS=NO ;; @@ -494,6 +498,8 @@ cat << END --with-stream enable TCP/UDP proxy module --with-stream=dynamic enable dynamic TCP/UDP proxy module --with-stream_ssl_module enable ngx_stream_ssl_module + --with-stream_geoip_module enable ngx_stream_geoip_module + --with-stream_geoip_module=dynamic enable dynamic ngx_stream_geoip_module --without-stream_limit_conn_module disable ngx_stream_limit_conn_module --without-stream_access_module disable ngx_stream_access_module --without-stream_map_module disable ngx_stream_map_module diff -r 8ed51b02f655 -r 558db057adaa src/stream/ngx_stream_geoip_module.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/stream/ngx_stream_geoip_module.c Tue Jul 12 17:34:43 2016 +0300 @@ -0,0 +1,814 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include + +#include +#include + + +#define NGX_GEOIP_COUNTRY_CODE 0 +#define NGX_GEOIP_COUNTRY_CODE3 1 +#define NGX_GEOIP_COUNTRY_NAME 2 + + +typedef struct { + GeoIP *country; + GeoIP *org; + GeoIP *city; +#if (NGX_HAVE_GEOIP_V6) + unsigned country_v6:1; + unsigned org_v6:1; + unsigned city_v6:1; +#endif +} ngx_stream_geoip_conf_t; + + +typedef struct { + ngx_str_t *name; + uintptr_t data; +} ngx_stream_geoip_var_t; + + +typedef const char *(*ngx_stream_geoip_variable_handler_pt)(GeoIP *, + u_long addr); + + +ngx_stream_geoip_variable_handler_pt ngx_stream_geoip_country_functions[] = { + GeoIP_country_code_by_ipnum, + GeoIP_country_code3_by_ipnum, + GeoIP_country_name_by_ipnum, +}; + + +#if (NGX_HAVE_GEOIP_V6) + +typedef const char *(*ngx_stream_geoip_variable_handler_v6_pt)(GeoIP *, + geoipv6_t addr); + + +ngx_stream_geoip_variable_handler_v6_pt + ngx_stream_geoip_country_v6_functions[] = +{ + GeoIP_country_code_by_ipnum_v6, + GeoIP_country_code3_by_ipnum_v6, + GeoIP_country_name_by_ipnum_v6, +}; + +#endif + + +static ngx_int_t ngx_stream_geoip_country_variable(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_stream_geoip_org_variable(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_stream_geoip_city_variable(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_stream_geoip_region_name_variable(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_stream_geoip_city_float_variable(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_stream_geoip_city_int_variable(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data); +static GeoIPRecord *ngx_stream_geoip_get_city_record(ngx_stream_session_t *s); + +static ngx_int_t ngx_stream_geoip_add_variables(ngx_conf_t *cf); +static void *ngx_stream_geoip_create_conf(ngx_conf_t *cf); +static char *ngx_stream_geoip_country(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static char *ngx_stream_geoip_org(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static char *ngx_stream_geoip_city(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static void ngx_stream_geoip_cleanup(void *data); + + +static ngx_command_t ngx_stream_geoip_commands[] = { + + { ngx_string("geoip_country"), + NGX_STREAM_MAIN_CONF|NGX_CONF_TAKE12, + ngx_stream_geoip_country, + NGX_STREAM_MAIN_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("geoip_org"), + NGX_STREAM_MAIN_CONF|NGX_CONF_TAKE12, + ngx_stream_geoip_org, + NGX_STREAM_MAIN_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("geoip_city"), + NGX_STREAM_MAIN_CONF|NGX_CONF_TAKE12, + ngx_stream_geoip_city, + NGX_STREAM_MAIN_CONF_OFFSET, + 0, + NULL }, + + ngx_null_command +}; + + +static ngx_stream_module_t ngx_stream_geoip_module_ctx = { + ngx_stream_geoip_add_variables, /* preconfiguration */ + NULL, /* postconfiguration */ + + ngx_stream_geoip_create_conf, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL /* merge server configuration */ +}; + + +ngx_module_t ngx_stream_geoip_module = { + NGX_MODULE_V1, + &ngx_stream_geoip_module_ctx, /* module context */ + ngx_stream_geoip_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_stream_variable_t ngx_stream_geoip_vars[] = { + + { ngx_string("geoip_country_code"), NULL, + ngx_stream_geoip_country_variable, + NGX_GEOIP_COUNTRY_CODE, 0, 0 }, + + { ngx_string("geoip_country_code3"), NULL, + ngx_stream_geoip_country_variable, + NGX_GEOIP_COUNTRY_CODE3, 0, 0 }, + + { ngx_string("geoip_country_name"), NULL, + ngx_stream_geoip_country_variable, + NGX_GEOIP_COUNTRY_NAME, 0, 0 }, + + { ngx_string("geoip_org"), NULL, + ngx_stream_geoip_org_variable, + 0, 0, 0 }, + + { ngx_string("geoip_city_continent_code"), NULL, + ngx_stream_geoip_city_variable, + offsetof(GeoIPRecord, continent_code), 0, 0 }, + + { ngx_string("geoip_city_country_code"), NULL, + ngx_stream_geoip_city_variable, + offsetof(GeoIPRecord, country_code), 0, 0 }, + + { ngx_string("geoip_city_country_code3"), NULL, + ngx_stream_geoip_city_variable, + offsetof(GeoIPRecord, country_code3), 0, 0 }, + + { ngx_string("geoip_city_country_name"), NULL, + ngx_stream_geoip_city_variable, + offsetof(GeoIPRecord, country_name), 0, 0 }, + + { ngx_string("geoip_region"), NULL, + ngx_stream_geoip_city_variable, + offsetof(GeoIPRecord, region), 0, 0 }, + + { ngx_string("geoip_region_name"), NULL, + ngx_stream_geoip_region_name_variable, + 0, 0, 0 }, + + { ngx_string("geoip_city"), NULL, + ngx_stream_geoip_city_variable, + offsetof(GeoIPRecord, city), 0, 0 }, + + { ngx_string("geoip_postal_code"), NULL, + ngx_stream_geoip_city_variable, + offsetof(GeoIPRecord, postal_code), 0, 0 }, + + { ngx_string("geoip_latitude"), NULL, + ngx_stream_geoip_city_float_variable, + offsetof(GeoIPRecord, latitude), 0, 0 }, + + { ngx_string("geoip_longitude"), NULL, + ngx_stream_geoip_city_float_variable, + offsetof(GeoIPRecord, longitude), 0, 0 }, + + { ngx_string("geoip_dma_code"), NULL, + ngx_stream_geoip_city_int_variable, + offsetof(GeoIPRecord, dma_code), 0, 0 }, + + { ngx_string("geoip_area_code"), NULL, + ngx_stream_geoip_city_int_variable, + offsetof(GeoIPRecord, area_code), 0, 0 }, + + { ngx_null_string, NULL, NULL, 0, 0, 0 } +}; + + +static u_long +ngx_stream_geoip_addr(ngx_stream_session_t *s, ngx_stream_geoip_conf_t *gcf) +{ + ngx_addr_t addr; + struct sockaddr_in *sin; + + addr.sockaddr = s->connection->sockaddr; + addr.socklen = s->connection->socklen; + /* addr.name = s->connection->addr_text; */ + +#if (NGX_HAVE_INET6) + + if (addr.sockaddr->sa_family == AF_INET6) { + u_char *p; + in_addr_t inaddr; + struct in6_addr *inaddr6; + + inaddr6 = &((struct sockaddr_in6 *) addr.sockaddr)->sin6_addr; + + if (IN6_IS_ADDR_V4MAPPED(inaddr6)) { + p = inaddr6->s6_addr; + + inaddr = p[12] << 24; + inaddr += p[13] << 16; + inaddr += p[14] << 8; + inaddr += p[15]; + + return inaddr; + } + } + +#endif + + if (addr.sockaddr->sa_family != AF_INET) { + return INADDR_NONE; + } + + sin = (struct sockaddr_in *) addr.sockaddr; + return ntohl(sin->sin_addr.s_addr); +} + + +#if (NGX_HAVE_GEOIP_V6) + +static geoipv6_t +ngx_stream_geoip_addr_v6(ngx_stream_session_t *s, ngx_stream_geoip_conf_t *gcf) +{ + ngx_addr_t addr; + in_addr_t addr4; + struct in6_addr addr6; + struct sockaddr_in *sin; + struct sockaddr_in6 *sin6; + + addr.sockaddr = s->connection->sockaddr; + addr.socklen = s->connection->socklen; + /* addr.name = s->connection->addr_text; */ + + switch (addr.sockaddr->sa_family) { + + case AF_INET: + /* Produce IPv4-mapped IPv6 address. */ + sin = (struct sockaddr_in *) addr.sockaddr; + addr4 = ntohl(sin->sin_addr.s_addr); + + ngx_memzero(&addr6, sizeof(struct in6_addr)); + addr6.s6_addr[10] = 0xff; + addr6.s6_addr[11] = 0xff; + addr6.s6_addr[12] = addr4 >> 24; + addr6.s6_addr[13] = addr4 >> 16; + addr6.s6_addr[14] = addr4 >> 8; + addr6.s6_addr[15] = addr4; + return addr6; + + case AF_INET6: + sin6 = (struct sockaddr_in6 *) addr.sockaddr; + return sin6->sin6_addr; + + default: + return in6addr_any; + } +} + +#endif + + +static ngx_int_t +ngx_stream_geoip_country_variable(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data) +{ + ngx_stream_geoip_variable_handler_pt handler = + ngx_stream_geoip_country_functions[data]; +#if (NGX_HAVE_GEOIP_V6) + ngx_stream_geoip_variable_handler_v6_pt handler_v6 = + ngx_stream_geoip_country_v6_functions[data]; +#endif + + const char *val; + ngx_stream_geoip_conf_t *gcf; + + gcf = ngx_stream_get_module_main_conf(s, ngx_stream_geoip_module); + + if (gcf->country == NULL) { + goto not_found; + } + +#if (NGX_HAVE_GEOIP_V6) + val = gcf->country_v6 + ? handler_v6(gcf->country, ngx_stream_geoip_addr_v6(s, gcf)) + : handler(gcf->country, ngx_stream_geoip_addr(s, gcf)); +#else + val = handler(gcf->country, ngx_stream_geoip_addr(s, gcf)); +#endif + + if (val == NULL) { + goto not_found; + } + + v->len = ngx_strlen(val); + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = (u_char *) val; + + return NGX_OK; + +not_found: + + v->not_found = 1; + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_geoip_org_variable(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data) +{ + size_t len; + char *val; + ngx_stream_geoip_conf_t *gcf; + + gcf = ngx_stream_get_module_main_conf(s, ngx_stream_geoip_module); + + if (gcf->org == NULL) { + goto not_found; + } + +#if (NGX_HAVE_GEOIP_V6) + val = gcf->org_v6 + ? GeoIP_name_by_ipnum_v6(gcf->org, + ngx_stream_geoip_addr_v6(s, gcf)) + : GeoIP_name_by_ipnum(gcf->org, + ngx_stream_geoip_addr(s, gcf)); +#else + val = GeoIP_name_by_ipnum(gcf->org, ngx_stream_geoip_addr(s, gcf)); +#endif + + if (val == NULL) { + goto not_found; + } + + len = ngx_strlen(val); + v->data = ngx_pnalloc(s->connection->pool, len); + if (v->data == NULL) { + ngx_free(val); + return NGX_ERROR; + } + + ngx_memcpy(v->data, val, len); + + v->len = len; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + + ngx_free(val); + + return NGX_OK; + +not_found: + + v->not_found = 1; + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_geoip_city_variable(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data) +{ + char *val; + size_t len; + GeoIPRecord *gr; + + gr = ngx_stream_geoip_get_city_record(s); + if (gr == NULL) { + goto not_found; + } + + val = *(char **) ((char *) gr + data); + if (val == NULL) { + goto no_value; + } + + len = ngx_strlen(val); + v->data = ngx_pnalloc(s->connection->pool, len); + if (v->data == NULL) { + GeoIPRecord_delete(gr); + return NGX_ERROR; + } + + ngx_memcpy(v->data, val, len); + + v->len = len; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + + GeoIPRecord_delete(gr); + + return NGX_OK; + +no_value: + + GeoIPRecord_delete(gr); + +not_found: + + v->not_found = 1; + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_geoip_region_name_variable(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data) +{ + size_t len; + const char *val; + GeoIPRecord *gr; + + gr = ngx_stream_geoip_get_city_record(s); + if (gr == NULL) { + goto not_found; + } + + val = GeoIP_region_name_by_code(gr->country_code, gr->region); + + GeoIPRecord_delete(gr); + + if (val == NULL) { + goto not_found; + } + + len = ngx_strlen(val); + v->data = ngx_pnalloc(s->connection->pool, len); + if (v->data == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(v->data, val, len); + + v->len = len; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + + return NGX_OK; + +not_found: + + v->not_found = 1; + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_geoip_city_float_variable(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data) +{ + float val; + GeoIPRecord *gr; + + gr = ngx_stream_geoip_get_city_record(s); + if (gr == NULL) { + v->not_found = 1; + return NGX_OK; + } + + v->data = ngx_pnalloc(s->connection->pool, NGX_INT64_LEN + 5); + if (v->data == NULL) { + GeoIPRecord_delete(gr); + return NGX_ERROR; + } + + val = *(float *) ((char *) gr + data); + + v->len = ngx_sprintf(v->data, "%.4f", val) - v->data; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + + GeoIPRecord_delete(gr); + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_geoip_city_int_variable(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data) +{ + int val; + GeoIPRecord *gr; + + gr = ngx_stream_geoip_get_city_record(s); + if (gr == NULL) { + v->not_found = 1; + return NGX_OK; + } + + v->data = ngx_pnalloc(s->connection->pool, NGX_INT64_LEN); + if (v->data == NULL) { + GeoIPRecord_delete(gr); + return NGX_ERROR; + } + + val = *(int *) ((char *) gr + data); + + v->len = ngx_sprintf(v->data, "%d", val) - v->data; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + + GeoIPRecord_delete(gr); + + return NGX_OK; +} + + +static GeoIPRecord * +ngx_stream_geoip_get_city_record(ngx_stream_session_t *s) +{ + ngx_stream_geoip_conf_t *gcf; + + gcf = ngx_stream_get_module_main_conf(s, ngx_stream_geoip_module); + + if (gcf->city) { +#if (NGX_HAVE_GEOIP_V6) + return gcf->city_v6 + ? GeoIP_record_by_ipnum_v6(gcf->city, + ngx_stream_geoip_addr_v6(s, gcf)) + : GeoIP_record_by_ipnum(gcf->city, + ngx_stream_geoip_addr(s, gcf)); +#else + return GeoIP_record_by_ipnum(gcf->city, ngx_stream_geoip_addr(s, gcf)); +#endif + } + + return NULL; +} + + +static ngx_int_t +ngx_stream_geoip_add_variables(ngx_conf_t *cf) +{ + ngx_stream_variable_t *var, *v; + + for (v = ngx_stream_geoip_vars; v->name.len; v++) { + var = ngx_stream_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 void * +ngx_stream_geoip_create_conf(ngx_conf_t *cf) +{ + ngx_pool_cleanup_t *cln; + ngx_stream_geoip_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_stream_geoip_conf_t)); + if (conf == NULL) { + return NULL; + } + + cln = ngx_pool_cleanup_add(cf->pool, 0); + if (cln == NULL) { + return NULL; + } + + cln->handler = ngx_stream_geoip_cleanup; + cln->data = conf; + + return conf; +} + + +static char * +ngx_stream_geoip_country(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_stream_geoip_conf_t *gcf = conf; + + ngx_str_t *value; + + if (gcf->country) { + return "is duplicate"; + } + + value = cf->args->elts; + + gcf->country = GeoIP_open((char *) value[1].data, GEOIP_MEMORY_CACHE); + + if (gcf->country == NULL) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "GeoIP_open(\"%V\") failed", &value[1]); + + return NGX_CONF_ERROR; + } + + if (cf->args->nelts == 3) { + if (ngx_strcmp(value[2].data, "utf8") == 0) { + GeoIP_set_charset(gcf->country, GEOIP_CHARSET_UTF8); + + } else { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid parameter \"%V\"", &value[2]); + return NGX_CONF_ERROR; + } + } + + switch (gcf->country->databaseType) { + + case GEOIP_COUNTRY_EDITION: + + return NGX_CONF_OK; + +#if (NGX_HAVE_GEOIP_V6) + case GEOIP_COUNTRY_EDITION_V6: + + gcf->country_v6 = 1; + return NGX_CONF_OK; +#endif + + default: + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid GeoIP database \"%V\" type:%d", + &value[1], gcf->country->databaseType); + return NGX_CONF_ERROR; + } +} + + +static char * +ngx_stream_geoip_org(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_stream_geoip_conf_t *gcf = conf; + + ngx_str_t *value; + + if (gcf->org) { + return "is duplicate"; + } + + value = cf->args->elts; + + gcf->org = GeoIP_open((char *) value[1].data, GEOIP_MEMORY_CACHE); + + if (gcf->org == NULL) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "GeoIP_open(\"%V\") failed", &value[1]); + + return NGX_CONF_ERROR; + } + + if (cf->args->nelts == 3) { + if (ngx_strcmp(value[2].data, "utf8") == 0) { + GeoIP_set_charset(gcf->org, GEOIP_CHARSET_UTF8); + + } else { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid parameter \"%V\"", &value[2]); + return NGX_CONF_ERROR; + } + } + + switch (gcf->org->databaseType) { + + case GEOIP_ISP_EDITION: + case GEOIP_ORG_EDITION: + case GEOIP_DOMAIN_EDITION: + case GEOIP_ASNUM_EDITION: + + return NGX_CONF_OK; + +#if (NGX_HAVE_GEOIP_V6) + case GEOIP_ISP_EDITION_V6: + case GEOIP_ORG_EDITION_V6: + case GEOIP_DOMAIN_EDITION_V6: + case GEOIP_ASNUM_EDITION_V6: + + gcf->org_v6 = 1; + return NGX_CONF_OK; +#endif + + default: + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid GeoIP database \"%V\" type:%d", + &value[1], gcf->org->databaseType); + return NGX_CONF_ERROR; + } +} + + +static char * +ngx_stream_geoip_city(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_stream_geoip_conf_t *gcf = conf; + + ngx_str_t *value; + + if (gcf->city) { + return "is duplicate"; + } + + value = cf->args->elts; + + gcf->city = GeoIP_open((char *) value[1].data, GEOIP_MEMORY_CACHE); + + if (gcf->city == NULL) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "GeoIP_open(\"%V\") failed", &value[1]); + + return NGX_CONF_ERROR; + } + + if (cf->args->nelts == 3) { + if (ngx_strcmp(value[2].data, "utf8") == 0) { + GeoIP_set_charset(gcf->city, GEOIP_CHARSET_UTF8); + + } else { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid parameter \"%V\"", &value[2]); + return NGX_CONF_ERROR; + } + } + + switch (gcf->city->databaseType) { + + case GEOIP_CITY_EDITION_REV0: + case GEOIP_CITY_EDITION_REV1: + + return NGX_CONF_OK; + +#if (NGX_HAVE_GEOIP_V6) + case GEOIP_CITY_EDITION_REV0_V6: + case GEOIP_CITY_EDITION_REV1_V6: + + gcf->city_v6 = 1; + return NGX_CONF_OK; +#endif + + default: + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid GeoIP City database \"%V\" type:%d", + &value[1], gcf->city->databaseType); + return NGX_CONF_ERROR; + } +} + + +static void +ngx_stream_geoip_cleanup(void *data) +{ + ngx_stream_geoip_conf_t *gcf = data; + + if (gcf->country) { + GeoIP_delete(gcf->country); + } + + if (gcf->org) { + GeoIP_delete(gcf->org); + } + + if (gcf->city) { + GeoIP_delete(gcf->city); + } +} From vl at nginx.com Tue Jul 12 14:37:59 2016 From: vl at nginx.com (Vladimir Homutov) Date: Tue, 12 Jul 2016 14:37:59 +0000 Subject: [nginx] Stream: geo module. Message-ID: details: http://hg.nginx.org/nginx/rev/80875b75d27e branches: changeset: 6631:80875b75d27e user: Vladimir Homutov date: Thu Jun 30 16:12:50 2016 +0300 description: Stream: geo module. diffstat: auto/modules | 10 + auto/options | 3 + src/stream/ngx_stream_geo_module.c | 1572 ++++++++++++++++++++++++++++++++++++ 3 files changed, 1585 insertions(+), 0 deletions(-) diffs (truncated from 1623 to 1000 lines): diff -r 558db057adaa -r 80875b75d27e auto/modules --- a/auto/modules Tue Jul 12 17:34:43 2016 +0300 +++ b/auto/modules Thu Jun 30 16:12:50 2016 +0300 @@ -1024,6 +1024,16 @@ if [ $STREAM != NO ]; then . auto/module fi + if [ $STREAM_GEO = YES ]; then + ngx_module_name=ngx_stream_geo_module + ngx_module_deps= + ngx_module_srcs=src/stream/ngx_stream_geo_module.c + ngx_module_libs= + ngx_module_link=$STREAM_GEO + + . auto/module + fi + if [ $STREAM_GEOIP != NO ]; then ngx_module_name=ngx_stream_geoip_module ngx_module_deps= diff -r 558db057adaa -r 80875b75d27e auto/options --- a/auto/options Tue Jul 12 17:34:43 2016 +0300 +++ b/auto/options Thu Jun 30 16:12:50 2016 +0300 @@ -117,6 +117,7 @@ STREAM=NO STREAM_SSL=NO STREAM_LIMIT_CONN=YES STREAM_ACCESS=YES +STREAM_GEO=YES STREAM_GEOIP=NO STREAM_MAP=YES STREAM_RETURN=YES @@ -300,6 +301,7 @@ use the \"--with-mail_ssl_module\" optio --without-stream_limit_conn_module) STREAM_LIMIT_CONN=NO ;; --without-stream_access_module) STREAM_ACCESS=NO ;; + --without-stream_geo_module) STREAM_GEO=NO ;; --without-stream_map_module) STREAM_MAP=NO ;; --without-stream_return_module) STREAM_RETURN=NO ;; --without-stream_upstream_hash_module) @@ -502,6 +504,7 @@ cat << END --with-stream_geoip_module=dynamic enable dynamic ngx_stream_geoip_module --without-stream_limit_conn_module disable ngx_stream_limit_conn_module --without-stream_access_module disable ngx_stream_access_module + --without-stream_geo_module disable ngx_stream_geo_module --without-stream_map_module disable ngx_stream_map_module --without-stream_return_module disable ngx_stream_return_module --without-stream_upstream_hash_module diff -r 558db057adaa -r 80875b75d27e src/stream/ngx_stream_geo_module.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/stream/ngx_stream_geo_module.c Thu Jun 30 16:12:50 2016 +0300 @@ -0,0 +1,1572 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include + + +typedef struct { + ngx_stream_variable_value_t *value; + u_short start; + u_short end; +} ngx_stream_geo_range_t; + + +typedef struct { + ngx_radix_tree_t *tree; +#if (NGX_HAVE_INET6) + ngx_radix_tree_t *tree6; +#endif +} ngx_stream_geo_trees_t; + + +typedef struct { + ngx_stream_geo_range_t **low; + ngx_stream_variable_value_t *default_value; +} ngx_stream_geo_high_ranges_t; + + +typedef struct { + ngx_str_node_t sn; + ngx_stream_variable_value_t *value; + size_t offset; +} ngx_stream_geo_variable_value_node_t; + + +typedef struct { + ngx_stream_variable_value_t *value; + ngx_str_t *net; + ngx_stream_geo_high_ranges_t high; + ngx_radix_tree_t *tree; +#if (NGX_HAVE_INET6) + ngx_radix_tree_t *tree6; +#endif + ngx_rbtree_t rbtree; + ngx_rbtree_node_t sentinel; + ngx_pool_t *pool; + ngx_pool_t *temp_pool; + + size_t data_size; + + ngx_str_t include_name; + ngx_uint_t includes; + ngx_uint_t entries; + + unsigned ranges:1; + unsigned outside_entries:1; + unsigned allow_binary_include:1; + unsigned binary_include:1; +} ngx_stream_geo_conf_ctx_t; + + +typedef struct { + union { + ngx_stream_geo_trees_t trees; + ngx_stream_geo_high_ranges_t high; + } u; + + ngx_int_t index; +} ngx_stream_geo_ctx_t; + + +static ngx_int_t ngx_stream_geo_addr(ngx_stream_session_t *s, + ngx_stream_geo_ctx_t *ctx, ngx_addr_t *addr); + +static char *ngx_stream_geo_block(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static char *ngx_stream_geo(ngx_conf_t *cf, ngx_command_t *dummy, void *conf); +static char *ngx_stream_geo_range(ngx_conf_t *cf, + ngx_stream_geo_conf_ctx_t *ctx, ngx_str_t *value); +static char *ngx_stream_geo_add_range(ngx_conf_t *cf, + ngx_stream_geo_conf_ctx_t *ctx, in_addr_t start, in_addr_t end); +static ngx_uint_t ngx_stream_geo_delete_range(ngx_conf_t *cf, + ngx_stream_geo_conf_ctx_t *ctx, in_addr_t start, in_addr_t end); +static char *ngx_stream_geo_cidr(ngx_conf_t *cf, + ngx_stream_geo_conf_ctx_t *ctx, ngx_str_t *value); +static char *ngx_stream_geo_cidr_add(ngx_conf_t *cf, + ngx_stream_geo_conf_ctx_t *ctx, ngx_cidr_t *cidr, ngx_str_t *value, + ngx_str_t *net); +static ngx_stream_variable_value_t *ngx_stream_geo_value(ngx_conf_t *cf, + ngx_stream_geo_conf_ctx_t *ctx, ngx_str_t *value); +static ngx_int_t ngx_stream_geo_cidr_value(ngx_conf_t *cf, ngx_str_t *net, + ngx_cidr_t *cidr); +static char *ngx_stream_geo_include(ngx_conf_t *cf, + ngx_stream_geo_conf_ctx_t *ctx, ngx_str_t *name); +static ngx_int_t ngx_stream_geo_include_binary_base(ngx_conf_t *cf, + ngx_stream_geo_conf_ctx_t *ctx, ngx_str_t *name); +static void ngx_stream_geo_create_binary_base(ngx_stream_geo_conf_ctx_t *ctx); +static u_char *ngx_stream_geo_copy_values(u_char *base, u_char *p, + ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); + + +static ngx_command_t ngx_stream_geo_commands[] = { + + { ngx_string("geo"), + NGX_STREAM_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_TAKE12, + ngx_stream_geo_block, + 0, + 0, + NULL }, + + ngx_null_command +}; + + +static ngx_stream_module_t ngx_stream_geo_module_ctx = { + NULL, /* preconfiguration */ + NULL, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL /* merge server configuration */ +}; + + +ngx_module_t ngx_stream_geo_module = { + NGX_MODULE_V1, + &ngx_stream_geo_module_ctx, /* module context */ + ngx_stream_geo_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 +}; + + +typedef struct { + u_char GEORNG[6]; + u_char version; + u_char ptr_size; + uint32_t endianness; + uint32_t crc32; +} ngx_stream_geo_header_t; + + +static ngx_stream_geo_header_t ngx_stream_geo_header = { + { 'G', 'E', 'O', 'R', 'N', 'G' }, 0, sizeof(void *), 0x12345678, 0 +}; + + +/* geo range is AF_INET only */ + +static ngx_int_t +ngx_stream_geo_cidr_variable(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data) +{ + ngx_stream_geo_ctx_t *ctx = (ngx_stream_geo_ctx_t *) data; + + in_addr_t inaddr; + ngx_addr_t addr; + struct sockaddr_in *sin; + ngx_stream_variable_value_t *vv; +#if (NGX_HAVE_INET6) + u_char *p; + struct in6_addr *inaddr6; +#endif + + if (ngx_stream_geo_addr(s, ctx, &addr) != NGX_OK) { + vv = (ngx_stream_variable_value_t *) + ngx_radix32tree_find(ctx->u.trees.tree, INADDR_NONE); + goto done; + } + + switch (addr.sockaddr->sa_family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + inaddr6 = &((struct sockaddr_in6 *) addr.sockaddr)->sin6_addr; + p = inaddr6->s6_addr; + + if (IN6_IS_ADDR_V4MAPPED(inaddr6)) { + inaddr = p[12] << 24; + inaddr += p[13] << 16; + inaddr += p[14] << 8; + inaddr += p[15]; + + vv = (ngx_stream_variable_value_t *) + ngx_radix32tree_find(ctx->u.trees.tree, inaddr); + + } else { + vv = (ngx_stream_variable_value_t *) + ngx_radix128tree_find(ctx->u.trees.tree6, p); + } + + break; +#endif + + default: /* AF_INET */ + sin = (struct sockaddr_in *) addr.sockaddr; + inaddr = ntohl(sin->sin_addr.s_addr); + + vv = (ngx_stream_variable_value_t *) + ngx_radix32tree_find(ctx->u.trees.tree, inaddr); + + break; + } + +done: + + *v = *vv; + + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, + "stream geo: %v", v); + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_geo_range_variable(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data) +{ + ngx_stream_geo_ctx_t *ctx = (ngx_stream_geo_ctx_t *) data; + + in_addr_t inaddr; + ngx_addr_t addr; + ngx_uint_t n; + struct sockaddr_in *sin; + ngx_stream_geo_range_t *range; +#if (NGX_HAVE_INET6) + u_char *p; + struct in6_addr *inaddr6; +#endif + + *v = *ctx->u.high.default_value; + + if (ngx_stream_geo_addr(s, ctx, &addr) == NGX_OK) { + + switch (addr.sockaddr->sa_family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + inaddr6 = &((struct sockaddr_in6 *) addr.sockaddr)->sin6_addr; + + if (IN6_IS_ADDR_V4MAPPED(inaddr6)) { + p = inaddr6->s6_addr; + + inaddr = p[12] << 24; + inaddr += p[13] << 16; + inaddr += p[14] << 8; + inaddr += p[15]; + + } else { + inaddr = INADDR_NONE; + } + + break; +#endif + + default: /* AF_INET */ + sin = (struct sockaddr_in *) addr.sockaddr; + inaddr = ntohl(sin->sin_addr.s_addr); + break; + } + + } else { + inaddr = INADDR_NONE; + } + + if (ctx->u.high.low) { + range = ctx->u.high.low[inaddr >> 16]; + + if (range) { + n = inaddr & 0xffff; + do { + if (n >= (ngx_uint_t) range->start + && n <= (ngx_uint_t) range->end) + { + *v = *range->value; + break; + } + } while ((++range)->value); + } + } + + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, + "stream geo: %v", v); + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_geo_addr(ngx_stream_session_t *s, ngx_stream_geo_ctx_t *ctx, + ngx_addr_t *addr) +{ + ngx_stream_variable_value_t *v; + + if (ctx->index == -1) { + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, + "stream geo started: %V", &s->connection->addr_text); + + addr->sockaddr = s->connection->sockaddr; + addr->socklen = s->connection->socklen; + /* addr->name = s->connection->addr_text; */ + + return NGX_OK; + } + + v = ngx_stream_get_flushed_variable(s, ctx->index); + + if (v == NULL || v->not_found) { + ngx_log_debug0(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, + "stream geo not found"); + + return NGX_ERROR; + } + + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, + "stream geo started: %v", v); + + if (ngx_parse_addr(s->connection->pool, addr, v->data, v->len) == NGX_OK) { + return NGX_OK; + } + + return NGX_ERROR; +} + + +static char * +ngx_stream_geo_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + char *rv; + size_t len; + ngx_str_t *value, name; + ngx_uint_t i; + ngx_conf_t save; + ngx_pool_t *pool; + ngx_array_t *a; + ngx_stream_variable_t *var; + ngx_stream_geo_ctx_t *geo; + ngx_stream_geo_conf_ctx_t ctx; +#if (NGX_HAVE_INET6) + static struct in6_addr zero; +#endif + + value = cf->args->elts; + + geo = ngx_palloc(cf->pool, sizeof(ngx_stream_geo_ctx_t)); + if (geo == NULL) { + return NGX_CONF_ERROR; + } + + name = value[1]; + + if (name.data[0] != '$') { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid variable name \"%V\"", &name); + return NGX_CONF_ERROR; + } + + name.len--; + name.data++; + + if (cf->args->nelts == 3) { + + geo->index = ngx_stream_get_variable_index(cf, &name); + if (geo->index == NGX_ERROR) { + return NGX_CONF_ERROR; + } + + name = value[2]; + + if (name.data[0] != '$') { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid variable name \"%V\"", &name); + return NGX_CONF_ERROR; + } + + name.len--; + name.data++; + + } else { + geo->index = -1; + } + + var = ngx_stream_add_variable(cf, &name, NGX_STREAM_VAR_CHANGEABLE); + if (var == NULL) { + return NGX_CONF_ERROR; + } + + pool = ngx_create_pool(NGX_DEFAULT_POOL_SIZE, cf->log); + if (pool == NULL) { + return NGX_CONF_ERROR; + } + + ngx_memzero(&ctx, sizeof(ngx_stream_geo_conf_ctx_t)); + + ctx.temp_pool = ngx_create_pool(NGX_DEFAULT_POOL_SIZE, cf->log); + if (ctx.temp_pool == NULL) { + return NGX_CONF_ERROR; + } + + ngx_rbtree_init(&ctx.rbtree, &ctx.sentinel, ngx_str_rbtree_insert_value); + + ctx.pool = cf->pool; + ctx.data_size = sizeof(ngx_stream_geo_header_t) + + sizeof(ngx_stream_variable_value_t) + + 0x10000 * sizeof(ngx_stream_geo_range_t *); + ctx.allow_binary_include = 1; + + save = *cf; + cf->pool = pool; + cf->ctx = &ctx; + cf->handler = ngx_stream_geo; + cf->handler_conf = conf; + + rv = ngx_conf_parse(cf, NULL); + + *cf = save; + + if (ctx.ranges) { + + if (ctx.high.low && !ctx.binary_include) { + for (i = 0; i < 0x10000; i++) { + a = (ngx_array_t *) ctx.high.low[i]; + + if (a == NULL || a->nelts == 0) { + continue; + } + + len = a->nelts * sizeof(ngx_stream_geo_range_t); + + ctx.high.low[i] = ngx_palloc(cf->pool, len + sizeof(void *)); + if (ctx.high.low[i] == NULL) { + return NGX_CONF_ERROR; + } + + ngx_memcpy(ctx.high.low[i], a->elts, len); + ctx.high.low[i][a->nelts].value = NULL; + ctx.data_size += len + sizeof(void *); + } + + if (ctx.allow_binary_include + && !ctx.outside_entries + && ctx.entries > 100000 + && ctx.includes == 1) + { + ngx_stream_geo_create_binary_base(&ctx); + } + } + + if (ctx.high.default_value == NULL) { + ctx.high.default_value = &ngx_stream_variable_null_value; + } + + geo->u.high = ctx.high; + + var->get_handler = ngx_stream_geo_range_variable; + var->data = (uintptr_t) geo; + + ngx_destroy_pool(ctx.temp_pool); + ngx_destroy_pool(pool); + + } else { + if (ctx.tree == NULL) { + ctx.tree = ngx_radix_tree_create(cf->pool, -1); + if (ctx.tree == NULL) { + return NGX_CONF_ERROR; + } + } + + geo->u.trees.tree = ctx.tree; + +#if (NGX_HAVE_INET6) + if (ctx.tree6 == NULL) { + ctx.tree6 = ngx_radix_tree_create(cf->pool, -1); + if (ctx.tree6 == NULL) { + return NGX_CONF_ERROR; + } + } + + geo->u.trees.tree6 = ctx.tree6; +#endif + + var->get_handler = ngx_stream_geo_cidr_variable; + var->data = (uintptr_t) geo; + + ngx_destroy_pool(ctx.temp_pool); + ngx_destroy_pool(pool); + + if (ngx_radix32tree_insert(ctx.tree, 0, 0, + (uintptr_t) &ngx_stream_variable_null_value) + == NGX_ERROR) + { + return NGX_CONF_ERROR; + } + + /* NGX_BUSY is okay (default was set explicitly) */ + +#if (NGX_HAVE_INET6) + if (ngx_radix128tree_insert(ctx.tree6, zero.s6_addr, zero.s6_addr, + (uintptr_t) &ngx_stream_variable_null_value) + == NGX_ERROR) + { + return NGX_CONF_ERROR; + } +#endif + } + + return rv; +} + + +static char * +ngx_stream_geo(ngx_conf_t *cf, ngx_command_t *dummy, void *conf) +{ + char *rv; + ngx_str_t *value; + ngx_stream_geo_conf_ctx_t *ctx; + + ctx = cf->ctx; + + value = cf->args->elts; + + if (cf->args->nelts == 1) { + + if (ngx_strcmp(value[0].data, "ranges") == 0) { + + if (ctx->tree +#if (NGX_HAVE_INET6) + || ctx->tree6 +#endif + ) + { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "the \"ranges\" directive must be " + "the first directive inside \"geo\" block"); + goto failed; + } + + ctx->ranges = 1; + + rv = NGX_CONF_OK; + + goto done; + } + } + + if (cf->args->nelts != 2) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid number of the geo parameters"); + goto failed; + } + + if (ngx_strcmp(value[0].data, "include") == 0) { + + rv = ngx_stream_geo_include(cf, ctx, &value[1]); + + goto done; + } + + if (ctx->ranges) { + rv = ngx_stream_geo_range(cf, ctx, value); + + } else { + rv = ngx_stream_geo_cidr(cf, ctx, value); + } + +done: + + ngx_reset_pool(cf->pool); + + return rv; + +failed: + + ngx_reset_pool(cf->pool); + + return NGX_CONF_ERROR; +} + + +static char * +ngx_stream_geo_range(ngx_conf_t *cf, ngx_stream_geo_conf_ctx_t *ctx, + ngx_str_t *value) +{ + u_char *p, *last; + in_addr_t start, end; + ngx_str_t *net; + ngx_uint_t del; + + if (ngx_strcmp(value[0].data, "default") == 0) { + + if (ctx->high.default_value) { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "duplicate default geo range value: \"%V\", old value: \"%v\"", + &value[1], ctx->high.default_value); + } + + ctx->high.default_value = ngx_stream_geo_value(cf, ctx, &value[1]); + if (ctx->high.default_value == NULL) { + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; + } + + if (ctx->binary_include) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "binary geo range base \"%s\" cannot be mixed with usual entries", + ctx->include_name.data); + return NGX_CONF_ERROR; + } + + if (ctx->high.low == NULL) { + ctx->high.low = ngx_pcalloc(ctx->pool, + 0x10000 * sizeof(ngx_stream_geo_range_t *)); + if (ctx->high.low == NULL) { + return NGX_CONF_ERROR; + } + } + + ctx->entries++; + ctx->outside_entries = 1; + + if (ngx_strcmp(value[0].data, "delete") == 0) { + net = &value[1]; + del = 1; + + } else { + net = &value[0]; + del = 0; + } + + last = net->data + net->len; + + p = ngx_strlchr(net->data, last, '-'); + + if (p == NULL) { + goto invalid; + } + + start = ngx_inet_addr(net->data, p - net->data); + + if (start == INADDR_NONE) { + goto invalid; + } + + start = ntohl(start); + + p++; + + end = ngx_inet_addr(p, last - p); + + if (end == INADDR_NONE) { + goto invalid; + } + + end = ntohl(end); + + if (start > end) { + goto invalid; + } + + if (del) { + if (ngx_stream_geo_delete_range(cf, ctx, start, end)) { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "no address range \"%V\" to delete", net); + } + + return NGX_CONF_OK; + } + + ctx->value = ngx_stream_geo_value(cf, ctx, &value[1]); + + if (ctx->value == NULL) { + return NGX_CONF_ERROR; + } + + ctx->net = net; + + return ngx_stream_geo_add_range(cf, ctx, start, end); + +invalid: + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid range \"%V\"", net); + + return NGX_CONF_ERROR; +} + + +/* the add procedure is optimized to add a growing up sequence */ + +static char * +ngx_stream_geo_add_range(ngx_conf_t *cf, ngx_stream_geo_conf_ctx_t *ctx, + in_addr_t start, in_addr_t end) +{ + in_addr_t n; + ngx_uint_t h, i, s, e; + ngx_array_t *a; + ngx_stream_geo_range_t *range; + + for (n = start; n <= end; n = (n + 0x10000) & 0xffff0000) { + + h = n >> 16; + + if (n == start) { + s = n & 0xffff; + } else { + s = 0; + } + + if ((n | 0xffff) > end) { + e = end & 0xffff; + + } else { + e = 0xffff; + } + + a = (ngx_array_t *) ctx->high.low[h]; + + if (a == NULL) { + a = ngx_array_create(ctx->temp_pool, 64, + sizeof(ngx_stream_geo_range_t)); + if (a == NULL) { + return NGX_CONF_ERROR; + } + + ctx->high.low[h] = (ngx_stream_geo_range_t *) a; + } + + i = a->nelts; + range = a->elts; + + while (i) { + + i--; + + if (e < (ngx_uint_t) range[i].start) { + continue; + } + + if (s > (ngx_uint_t) range[i].end) { + + /* add after the range */ + + range = ngx_array_push(a); + if (range == NULL) { + return NGX_CONF_ERROR; + } + + range = a->elts; + + ngx_memmove(&range[i + 2], &range[i + 1], + (a->nelts - 2 - i) * sizeof(ngx_stream_geo_range_t)); + + range[i + 1].start = (u_short) s; + range[i + 1].end = (u_short) e; + range[i + 1].value = ctx->value; + + goto next; + } + + if (s == (ngx_uint_t) range[i].start + && e == (ngx_uint_t) range[i].end) + { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "duplicate range \"%V\", value: \"%v\", old value: \"%v\"", + ctx->net, ctx->value, range[i].value); + + range[i].value = ctx->value; + + goto next; + } + + if (s > (ngx_uint_t) range[i].start + && e < (ngx_uint_t) range[i].end) + { + /* split the range and insert the new one */ + + range = ngx_array_push(a); + if (range == NULL) { + return NGX_CONF_ERROR; + } + + range = ngx_array_push(a); + if (range == NULL) { + return NGX_CONF_ERROR; + } + + range = a->elts; + + ngx_memmove(&range[i + 3], &range[i + 1], + (a->nelts - 3 - i) * sizeof(ngx_stream_geo_range_t)); + + range[i + 2].start = (u_short) (e + 1); + range[i + 2].end = range[i].end; + range[i + 2].value = range[i].value; + + range[i + 1].start = (u_short) s; + range[i + 1].end = (u_short) e; + range[i + 1].value = ctx->value; + + range[i].end = (u_short) (s - 1); + + goto next; + } + + if (s == (ngx_uint_t) range[i].start + && e < (ngx_uint_t) range[i].end) + { + /* shift the range start and insert the new range */ + + range = ngx_array_push(a); + if (range == NULL) { + return NGX_CONF_ERROR; + } + + range = a->elts; + + ngx_memmove(&range[i + 1], &range[i], + (a->nelts - 1 - i) * sizeof(ngx_stream_geo_range_t)); + + range[i + 1].start = (u_short) (e + 1); + + range[i].start = (u_short) s; + range[i].end = (u_short) e; + range[i].value = ctx->value; + + goto next; + } + + if (s > (ngx_uint_t) range[i].start + && e == (ngx_uint_t) range[i].end) + { + /* shift the range end and insert the new range */ + + range = ngx_array_push(a); + if (range == NULL) { + return NGX_CONF_ERROR; + } + + range = a->elts; + + ngx_memmove(&range[i + 2], &range[i + 1], + (a->nelts - 2 - i) * sizeof(ngx_stream_geo_range_t)); + + range[i + 1].start = (u_short) s; + range[i + 1].end = (u_short) e; + range[i + 1].value = ctx->value; + + range[i].end = (u_short) (s - 1); + + goto next; + } + + s = (ngx_uint_t) range[i].start; + e = (ngx_uint_t) range[i].end; + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "range \"%V\" overlaps \"%d.%d.%d.%d-%d.%d.%d.%d\"", + ctx->net, + h >> 8, h & 0xff, s >> 8, s & 0xff, + h >> 8, h & 0xff, e >> 8, e & 0xff); + + return NGX_CONF_ERROR; + } + + /* add the first range */ + + range = ngx_array_push(a); + if (range == NULL) { + return NGX_CONF_ERROR; + } + + range->start = (u_short) s; + range->end = (u_short) e; + range->value = ctx->value; + + next: + + continue; + } + + return NGX_CONF_OK; +} + + +static ngx_uint_t +ngx_stream_geo_delete_range(ngx_conf_t *cf, ngx_stream_geo_conf_ctx_t *ctx, + in_addr_t start, in_addr_t end) +{ + in_addr_t n; + ngx_uint_t h, i, s, e, warn; + ngx_array_t *a; + ngx_stream_geo_range_t *range; + + warn = 0; + + for (n = start; n <= end; n += 0x10000) { + + h = n >> 16; + + if (n == start) { + s = n & 0xffff; + } else { + s = 0; + } + + if ((n | 0xffff) > end) { + e = end & 0xffff; + + } else { + e = 0xffff; + } + + a = (ngx_array_t *) ctx->high.low[h]; + + if (a == NULL) { + warn = 1; + continue; + } + + range = a->elts; + for (i = 0; i < a->nelts; i++) { + + if (s == (ngx_uint_t) range[i].start + && e == (ngx_uint_t) range[i].end) + { + ngx_memmove(&range[i], &range[i + 1], + (a->nelts - 1 - i) * sizeof(ngx_stream_geo_range_t)); + + a->nelts--; + + break; + } + From vl at nginx.com Tue Jul 12 14:38:02 2016 From: vl at nginx.com (Vladimir Homutov) Date: Tue, 12 Jul 2016 14:38:02 +0000 Subject: [nginx] Stream: split_clients module. Message-ID: details: http://hg.nginx.org/nginx/rev/787dcc15b802 branches: changeset: 6632:787dcc15b802 user: Vladimir Homutov date: Tue Jul 12 17:34:52 2016 +0300 description: Stream: split_clients module. diffstat: auto/modules | 10 + auto/options | 5 + src/stream/ngx_stream_split_clients_module.c | 244 +++++++++++++++++++++++++++ 3 files changed, 259 insertions(+), 0 deletions(-) diffs (297 lines): diff -r 80875b75d27e -r 787dcc15b802 auto/modules --- a/auto/modules Thu Jun 30 16:12:50 2016 +0300 +++ b/auto/modules Tue Jul 12 17:34:52 2016 +0300 @@ -1054,6 +1054,16 @@ if [ $STREAM != NO ]; then . auto/module fi + if [ $STREAM_SPLIT_CLIENTS = YES ]; then + ngx_module_name=ngx_stream_split_clients_module + ngx_module_deps= + ngx_module_srcs=src/stream/ngx_stream_split_clients_module.c + ngx_module_libs= + ngx_module_link=$STREAM_SPLIT_CLIENTS + + . auto/module + fi + if [ $STREAM_RETURN = YES ]; then ngx_module_name=ngx_stream_return_module ngx_module_deps= diff -r 80875b75d27e -r 787dcc15b802 auto/options --- a/auto/options Thu Jun 30 16:12:50 2016 +0300 +++ b/auto/options Tue Jul 12 17:34:52 2016 +0300 @@ -120,6 +120,7 @@ STREAM_ACCESS=YES STREAM_GEO=YES STREAM_GEOIP=NO STREAM_MAP=YES +STREAM_SPLIT_CLIENTS=YES STREAM_RETURN=YES STREAM_UPSTREAM_HASH=YES STREAM_UPSTREAM_LEAST_CONN=YES @@ -303,6 +304,8 @@ use the \"--with-mail_ssl_module\" optio --without-stream_access_module) STREAM_ACCESS=NO ;; --without-stream_geo_module) STREAM_GEO=NO ;; --without-stream_map_module) STREAM_MAP=NO ;; + --without-stream_split_clients_module) + STREAM_SPLIT_CLIENTS=NO ;; --without-stream_return_module) STREAM_RETURN=NO ;; --without-stream_upstream_hash_module) STREAM_UPSTREAM_HASH=NO ;; @@ -506,6 +509,8 @@ cat << END --without-stream_access_module disable ngx_stream_access_module --without-stream_geo_module disable ngx_stream_geo_module --without-stream_map_module disable ngx_stream_map_module + --without-stream_split_clients_module + disable ngx_stream_split_clients_module --without-stream_return_module disable ngx_stream_return_module --without-stream_upstream_hash_module disable ngx_stream_upstream_hash_module diff -r 80875b75d27e -r 787dcc15b802 src/stream/ngx_stream_split_clients_module.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/stream/ngx_stream_split_clients_module.c Tue Jul 12 17:34:52 2016 +0300 @@ -0,0 +1,244 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include + + +typedef struct { + uint32_t percent; + ngx_stream_variable_value_t value; +} ngx_stream_split_clients_part_t; + + +typedef struct { + ngx_stream_complex_value_t value; + ngx_array_t parts; +} ngx_stream_split_clients_ctx_t; + + +static char *ngx_conf_split_clients_block(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static char *ngx_stream_split_clients(ngx_conf_t *cf, ngx_command_t *dummy, + void *conf); + +static ngx_command_t ngx_stream_split_clients_commands[] = { + + { ngx_string("split_clients"), + NGX_STREAM_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_TAKE2, + ngx_conf_split_clients_block, + NGX_STREAM_MAIN_CONF_OFFSET, + 0, + NULL }, + + ngx_null_command +}; + + +static ngx_stream_module_t ngx_stream_split_clients_module_ctx = { + NULL, /* preconfiguration */ + NULL, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL /* merge server configuration */ +}; + + +ngx_module_t ngx_stream_split_clients_module = { + NGX_MODULE_V1, + &ngx_stream_split_clients_module_ctx, /* module context */ + ngx_stream_split_clients_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_split_clients_variable(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data) +{ + ngx_stream_split_clients_ctx_t *ctx = + (ngx_stream_split_clients_ctx_t *) data; + + uint32_t hash; + ngx_str_t val; + ngx_uint_t i; + ngx_stream_split_clients_part_t *part; + + *v = ngx_stream_variable_null_value; + + if (ngx_stream_complex_value(s, &ctx->value, &val) != NGX_OK) { + return NGX_OK; + } + + hash = ngx_murmur_hash2(val.data, val.len); + + part = ctx->parts.elts; + + for (i = 0; i < ctx->parts.nelts; i++) { + + ngx_log_debug2(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, + "stream split: %uD %uD", hash, part[i].percent); + + if (hash < part[i].percent || part[i].percent == 0) { + *v = part[i].value; + return NGX_OK; + } + } + + return NGX_OK; +} + + +static char * +ngx_conf_split_clients_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + char *rv; + uint32_t sum, last; + ngx_str_t *value, name; + ngx_uint_t i; + ngx_conf_t save; + ngx_stream_variable_t *var; + ngx_stream_split_clients_ctx_t *ctx; + ngx_stream_split_clients_part_t *part; + ngx_stream_compile_complex_value_t ccv; + + ctx = ngx_pcalloc(cf->pool, sizeof(ngx_stream_split_clients_ctx_t)); + if (ctx == 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 = &ctx->value; + + if (ngx_stream_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + name = value[2]; + + if (name.data[0] != '$') { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid variable name \"%V\"", &name); + return NGX_CONF_ERROR; + } + + name.len--; + name.data++; + + var = ngx_stream_add_variable(cf, &name, NGX_STREAM_VAR_CHANGEABLE); + if (var == NULL) { + return NGX_CONF_ERROR; + } + + var->get_handler = ngx_stream_split_clients_variable; + var->data = (uintptr_t) ctx; + + if (ngx_array_init(&ctx->parts, cf->pool, 2, + sizeof(ngx_stream_split_clients_part_t)) + != NGX_OK) + { + return NGX_CONF_ERROR; + } + + save = *cf; + cf->ctx = ctx; + cf->handler = ngx_stream_split_clients; + cf->handler_conf = conf; + + rv = ngx_conf_parse(cf, NULL); + + *cf = save; + + if (rv != NGX_CONF_OK) { + return rv; + } + + sum = 0; + last = 0; + part = ctx->parts.elts; + + for (i = 0; i < ctx->parts.nelts; i++) { + sum = part[i].percent ? sum + part[i].percent : 10000; + if (sum > 10000) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "percent total is greater than 100%%"); + return NGX_CONF_ERROR; + } + + if (part[i].percent) { + last += part[i].percent * (uint64_t) 0xffffffff / 10000; + part[i].percent = last; + } + } + + return rv; +} + + +static char * +ngx_stream_split_clients(ngx_conf_t *cf, ngx_command_t *dummy, void *conf) +{ + ngx_int_t n; + ngx_str_t *value; + ngx_stream_split_clients_ctx_t *ctx; + ngx_stream_split_clients_part_t *part; + + ctx = cf->ctx; + value = cf->args->elts; + + part = ngx_array_push(&ctx->parts); + if (part == NULL) { + return NGX_CONF_ERROR; + } + + if (value[0].len == 1 && value[0].data[0] == '*') { + part->percent = 0; + + } else { + if (value[0].len == 0 || value[0].data[value[0].len - 1] != '%') { + goto invalid; + } + + n = ngx_atofp(value[0].data, value[0].len - 1, 2); + if (n == NGX_ERROR || n == 0) { + goto invalid; + } + + part->percent = (uint32_t) n; + } + + part->value.len = value[1].len; + part->value.valid = 1; + part->value.no_cacheable = 0; + part->value.not_found = 0; + part->value.data = value[1].data; + + return NGX_CONF_OK; + +invalid: + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid percent value \"%V\"", &value[0]); + return NGX_CONF_ERROR; +} From igor at sysoev.ru Wed Jul 13 12:28:13 2016 From: igor at sysoev.ru (Igor Sysoev) Date: Wed, 13 Jul 2016 12:28:13 +0000 Subject: [njs] Syntax error messages are more verbose and have line number. Message-ID: details: http://hg.nginx.org/njs/rev/07d2be75a7db branches: changeset: 120:07d2be75a7db user: Igor Sysoev date: Wed Jul 13 13:56:12 2016 +0300 description: Syntax error messages are more verbose and have line number. diffstat: njs/njs_builtin.c | 2 + njs/njs_generator.c | 66 +++++++++++-- njs/njs_lexer.c | 23 ++++- njs/njs_nonrecursive_parser.c | 2 +- njs/njs_parser.c | 187 ++++++++++++++++++++++++++++++++--------- njs/njs_parser.h | 16 +++ njs/njs_parser_expression.c | 35 ++++++- njs/njs_regexp.c | 89 +++++++++++++++---- njs/njs_regexp.h | 3 +- njs/njs_string.c | 60 +------------ njs/njs_string.h | 2 - njs/njs_vm.c | 24 +++++- njs/njs_vm.h | 7 +- njs/njscript.c | 3 +- njs/test/njs_unit_test.c | 100 +++++++++++++++++----- 15 files changed, 442 insertions(+), 177 deletions(-) diffs (truncated from 1568 to 1000 lines): diff -r 5e7e498eb90d -r 07d2be75a7db njs/njs_builtin.c --- a/njs/njs_builtin.c Mon Jul 11 15:24:29 2016 +0300 +++ b/njs/njs_builtin.c Wed Jul 13 13:56:12 2016 +0300 @@ -19,6 +19,8 @@ #include #include #include +#include +#include #include #include #include diff -r 5e7e498eb90d -r 07d2be75a7db njs/njs_generator.c --- a/njs/njs_generator.c Mon Jul 11 15:24:29 2016 +0300 +++ b/njs/njs_generator.c Wed Jul 13 13:56:12 2016 +0300 @@ -20,6 +20,13 @@ #include #include #include +#include + + +typedef enum { + NJS_GENERATOR_ERROR_ILLEGAL_CONTINUE = 0, + NJS_GENERATOR_ERROR_ILLEGAL_BREAK, +} njs_generator_error_t; static nxt_int_t njs_generator(njs_vm_t *vm, njs_parser_t *parser, @@ -117,6 +124,8 @@ static nxt_noinline nxt_int_t njs_genera static nxt_noinline nxt_int_t njs_generator_index_release(njs_vm_t *vm, njs_parser_t *parser, njs_index_t index); nxt_inline nxt_bool_t njs_generator_is_constant(njs_parser_node_t *node); +static nxt_int_t njs_generator_error(njs_vm_t *vm, njs_parser_node_t *node, + njs_generator_error_t err); static const nxt_str_t no_label = { 0, NULL }; @@ -1067,19 +1076,20 @@ njs_generate_continue_statement(njs_vm_t { njs_vmcode_jump_t *jump; njs_parser_patch_t *patch; - - if (parser->block == NULL) { - vm->exception = &njs_exception_syntax_error; - return NXT_ERROR; + njs_parser_block_t *block; + + for (block = parser->block; block != NULL; block = block->next) { + if (block->type == NJS_PARSER_LOOP) { + goto found; + } } + return njs_generator_error(vm, node, NJS_GENERATOR_ERROR_ILLEGAL_CONTINUE); + +found: + /* TODO: LABEL */ - if (parser->block->type != NJS_PARSER_LOOP) { - vm->exception = &njs_exception_syntax_error; - return NXT_ERROR; - } - patch = nxt_mem_cache_alloc(vm->mem_cache_pool, sizeof(njs_parser_patch_t)); if (nxt_fast_path(patch != NULL)) { @@ -1105,12 +1115,20 @@ njs_generate_break_statement(njs_vm_t *v { njs_vmcode_jump_t *jump; njs_parser_patch_t *patch; - - if (parser->block == NULL) { - vm->exception = &njs_exception_syntax_error; - return NXT_ERROR; + njs_parser_block_t *block; + + for (block = parser->block; block != NULL; block = block->next) { + if (block->type == NJS_PARSER_LOOP + || block->type == NJS_PARSER_SWITCH) + { + goto found; + } } + return njs_generator_error(vm, node, NJS_GENERATOR_ERROR_ILLEGAL_BREAK); + +found: + /* TODO: LABEL: loop and switch may have label, block must have label. */ patch = nxt_mem_cache_alloc(vm->mem_cache_pool, sizeof(njs_parser_patch_t)); @@ -2466,3 +2484,25 @@ njs_generator_is_constant(njs_parser_nod return (node->token >= NJS_TOKEN_FIRST_CONST && node->token <= NJS_TOKEN_LAST_CONST); } + + +static nxt_int_t +njs_generator_error(njs_vm_t *vm, njs_parser_node_t *node, + njs_generator_error_t err) +{ + uint32_t size; + const char *msg; + u_char buf[NJS_EXCEPTION_BUF_LENGTH]; + + static const char *errors[] = { + "SyntaxError: Illegal continue statement in %u", + "SyntaxError: Illegal break statement in %u", + }; + + msg = errors[err]; + + size = snprintf((char *) buf, NJS_EXCEPTION_BUF_LENGTH, + msg, node->token_line); + + return njs_vm_throw_exception(vm, buf, size); +} diff -r 5e7e498eb90d -r 07d2be75a7db njs/njs_lexer.c --- a/njs/njs_lexer.c Mon Jul 11 15:24:29 2016 +0300 +++ b/njs/njs_lexer.c Wed Jul 13 13:56:12 2016 +0300 @@ -47,7 +47,7 @@ static const uint8_t njs_tokens[256] n NJS_TOKEN_ILLEGAL, NJS_TOKEN_ILLEGAL, /* \t */ NJS_TOKEN_ILLEGAL, NJS_TOKEN_SPACE, /* \n */ NJS_TOKEN_LINE_END, NJS_TOKEN_ILLEGAL, - /* \r */ NJS_TOKEN_ILLEGAL, NJS_TOKEN_LINE_END, + /* \r */ NJS_TOKEN_ILLEGAL, NJS_TOKEN_SPACE, NJS_TOKEN_ILLEGAL, NJS_TOKEN_ILLEGAL, /* 0x10 */ NJS_TOKEN_ILLEGAL, NJS_TOKEN_ILLEGAL, @@ -300,6 +300,8 @@ njs_lexer_next_token(njs_lexer_t *lexer) njs_token_t token; const njs_lexer_multi_t *multi; + lexer->text.data = lexer->start; + while (lexer->start < lexer->end) { c = *lexer->start++; @@ -308,6 +310,7 @@ njs_lexer_next_token(njs_lexer_t *lexer) switch (token) { case NJS_TOKEN_SPACE: + lexer->text.data = lexer->start; continue; case NJS_TOKEN_LETTER: @@ -396,6 +399,10 @@ njs_lexer_next_token(njs_lexer_t *lexer) goto multi; case NJS_TOKEN_LINE_END: + lexer->line++; + + /* Fall through. */ + case NJS_TOKEN_BITWISE_NOT: case NJS_TOKEN_OPEN_PARENTHESIS: case NJS_TOKEN_CLOSE_PARENTHESIS: @@ -408,6 +415,7 @@ njs_lexer_next_token(njs_lexer_t *lexer) case NJS_TOKEN_COLON: case NJS_TOKEN_SEMICOLON: case NJS_TOKEN_CONDITIONAL: + lexer->text.len = lexer->start - lexer->text.data; return token; default: /* NJS_TOKEN_ILLEGAL */ @@ -449,6 +457,7 @@ njs_lexer_word(njs_lexer_t *lexer, u_cha 0x00, 0x00, 0x00, 0x00, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ }; + lexer->token_line = lexer->line; lexer->key_hash = nxt_djb_hash_add(NXT_DJB_HASH_INIT, c); lexer->text.data = lexer->start - 1; @@ -489,7 +498,7 @@ njs_lexer_string(njs_lexer_t *lexer, u_c if (c == '\\') { if (p == lexer->end) { - return NJS_TOKEN_ILLEGAL; + break; } p++; @@ -510,7 +519,10 @@ njs_lexer_string(njs_lexer_t *lexer, u_c } } - return NJS_TOKEN_ILLEGAL; + lexer->text.data--; + lexer->text.len = p - lexer->text.data; + + return NJS_TOKEN_UNTERMINATED_STRING; } @@ -590,7 +602,8 @@ njs_lexer_multi(njs_lexer_t *lexer, njs_ lexer->start++; if (multi->count == 0) { - return multi->token; + token = multi->token; + break; } return njs_lexer_multi(lexer, multi->token, multi->count, @@ -603,6 +616,8 @@ njs_lexer_multi(njs_lexer_t *lexer, njs_ } while (n != 0); } + lexer->text.len = lexer->start - lexer->text.data; + return token; } diff -r 5e7e498eb90d -r 07d2be75a7db njs/njs_nonrecursive_parser.c --- a/njs/njs_nonrecursive_parser.c Mon Jul 11 15:24:29 2016 +0300 +++ b/njs/njs_nonrecursive_parser.c Wed Jul 13 13:56:12 2016 +0300 @@ -16,9 +16,9 @@ #include #include #include -#include #include #include +#include #include diff -r 5e7e498eb90d -r 07d2be75a7db njs/njs_parser.c --- a/njs/njs_parser.c Mon Jul 11 15:24:29 2016 +0300 +++ b/njs/njs_parser.c Wed Jul 13 13:56:12 2016 +0300 @@ -18,10 +18,11 @@ #include #include #include -#include #include #include +#include #include +#include /* @@ -52,18 +53,22 @@ static njs_token_t njs_parser_var_statem static njs_token_t njs_parser_if_statement(njs_vm_t *vm, njs_parser_t *parser); static njs_token_t njs_parser_switch_statement(njs_vm_t *vm, njs_parser_t *parser); +static njs_token_t njs_parser_duplicate_default_branch(njs_vm_t *vm, + njs_parser_t *parser); static njs_token_t njs_parser_while_statement(njs_vm_t *vm, njs_parser_t *parser); static njs_token_t njs_parser_do_while_statement(njs_vm_t *vm, njs_parser_t *parser); static njs_token_t njs_parser_for_statement(njs_vm_t *vm, njs_parser_t *parser); static njs_token_t njs_parser_for_in_statement(njs_vm_t *vm, - njs_parser_t *parser, njs_token_t token); + njs_parser_t *parser, nxt_str_t *name, njs_token_t token); static njs_token_t njs_parser_continue_statement(njs_vm_t *vm, njs_parser_t *parser); static njs_token_t njs_parser_break_statement(njs_vm_t *vm, njs_parser_t *parser); static njs_token_t njs_parser_try_statement(njs_vm_t *vm, njs_parser_t *parser); +static njs_token_t njs_parser_missing_catch_or_finally(njs_vm_t *vm, + njs_parser_t *parser); static njs_token_t njs_parser_try_block(njs_vm_t *vm, njs_parser_t *parser); static njs_token_t njs_parser_throw_statement(njs_vm_t *vm, njs_parser_t *parser); @@ -78,7 +83,9 @@ static njs_token_t njs_parser_object(njs static njs_token_t njs_parser_array(njs_vm_t *vm, njs_parser_t *parser, njs_parser_node_t *obj); static njs_token_t njs_parser_escape_string_create(njs_vm_t *vm, - njs_value_t *value); + njs_parser_t *parser, njs_value_t *value); +static njs_token_t njs_parser_unexpected_token(njs_vm_t *vm, + njs_parser_t *parser, njs_token_t token); njs_parser_node_t * @@ -154,7 +161,7 @@ njs_parser_statement_chain(njs_vm_t *vm, } } else if (vm->exception == NULL) { - vm->exception = &njs_exception_syntax_error; + (void) njs_parser_unexpected_token(vm, parser, token); } return token; @@ -269,14 +276,14 @@ njs_parser_block(njs_vm_t *vm, njs_parse nxt_inline njs_token_t -njs_parser_match(njs_parser_t *parser, njs_token_t token, +njs_parser_match(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token, njs_token_t match) { if (nxt_fast_path(token == match)) { return njs_parser_token(parser); } - return NJS_TOKEN_ILLEGAL; + return njs_parser_unexpected_token(vm, parser, token); } @@ -303,7 +310,7 @@ njs_parser_function_declaration(njs_vm_t } if (token != NJS_TOKEN_NAME) { - return NJS_TOKEN_ERROR; + return NJS_TOKEN_ILLEGAL; } var = njs_parser_variable(vm, parser, &level); @@ -463,7 +470,7 @@ njs_parser_function_lambda(njs_vm_t *vm, parser = lambda->u.parser; - token = njs_parser_match(parser, token, NJS_TOKEN_OPEN_PARENTHESIS); + token = njs_parser_match(vm, parser, token, NJS_TOKEN_OPEN_PARENTHESIS); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { return token; } @@ -640,12 +647,9 @@ njs_parser_var_statement(njs_vm_t *vm, n } if (token != NJS_TOKEN_NAME) { - /* TODO: message. */ return NJS_TOKEN_ILLEGAL; } - nxt_thread_log_debug("JS: %V", &parser->lexer->text); - var = njs_parser_variable(vm, parser, &level); if (nxt_slow_path(var == NULL)) { return NJS_TOKEN_ERROR; @@ -802,7 +806,7 @@ njs_parser_switch_statement(njs_vm_t *vm swtch->left = parser->node; last = &swtch->right; - token = njs_parser_match(parser, token, NJS_TOKEN_OPEN_BRACE); + token = njs_parser_match(vm, parser, token, NJS_TOKEN_OPEN_BRACE); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { return token; } @@ -841,8 +845,7 @@ njs_parser_switch_statement(njs_vm_t *vm } else { if (dflt != NULL) { - /* A duplicate "default" branch. */ - return NJS_TOKEN_ILLEGAL; + return njs_parser_duplicate_default_branch(vm, parser); } branch = node; @@ -858,7 +861,7 @@ njs_parser_switch_statement(njs_vm_t *vm *last = branch; last = &branch->left; - token = njs_parser_match(parser, token, NJS_TOKEN_COLON); + token = njs_parser_match(vm, parser, token, NJS_TOKEN_COLON); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { return token; } @@ -888,6 +891,22 @@ njs_parser_switch_statement(njs_vm_t *vm static njs_token_t +njs_parser_duplicate_default_branch(njs_vm_t *vm, njs_parser_t *parser) +{ + uint32_t size; + u_char buf[NJS_EXCEPTION_BUF_LENGTH]; + + size = snprintf((char *) buf, NJS_EXCEPTION_BUF_LENGTH, + "SyntaxError: More than one default clause " + "in switch statement in %u", parser->lexer->line); + + (void) njs_vm_throw_exception(vm, buf, size); + + return NJS_TOKEN_ILLEGAL; +} + + +static njs_token_t njs_parser_while_statement(njs_vm_t *vm, njs_parser_t *parser) { njs_token_t token; @@ -954,7 +973,7 @@ njs_parser_do_while_statement(njs_vm_t * node = njs_parser_node_alloc(vm); if (nxt_slow_path(node == NULL)) { - return NJS_TOKEN_ILLEGAL; + return NJS_TOKEN_ERROR; } node->token = NJS_TOKEN_DO; @@ -970,6 +989,7 @@ njs_parser_do_while_statement(njs_vm_t * static njs_token_t njs_parser_for_statement(njs_vm_t *vm, njs_parser_t *parser) { + nxt_str_t name; njs_token_t token; njs_parser_node_t *node, *init, *condition, *update, *cond, *body; @@ -984,12 +1004,13 @@ njs_parser_for_statement(njs_vm_t *vm, n return token; } - token = njs_parser_match(parser, token, NJS_TOKEN_OPEN_PARENTHESIS); + token = njs_parser_match(vm, parser, token, NJS_TOKEN_OPEN_PARENTHESIS); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { return token; } if (token != NJS_TOKEN_SEMICOLON) { + name = parser->lexer->text; token = njs_parser_expression(vm, parser, token); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { @@ -999,11 +1020,11 @@ njs_parser_for_statement(njs_vm_t *vm, n init = parser->node; if (init->token == NJS_TOKEN_IN) { - return njs_parser_for_in_statement(vm, parser, token); + return njs_parser_for_in_statement(vm, parser, &name, token); } } - token = njs_parser_match(parser, token, NJS_TOKEN_SEMICOLON); + token = njs_parser_match(vm, parser, token, NJS_TOKEN_SEMICOLON); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { return token; } @@ -1018,7 +1039,7 @@ njs_parser_for_statement(njs_vm_t *vm, n condition = parser->node; } - token = njs_parser_match(parser, token, NJS_TOKEN_SEMICOLON); + token = njs_parser_match(vm, parser, token, NJS_TOKEN_SEMICOLON); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { return token; } @@ -1033,7 +1054,7 @@ njs_parser_for_statement(njs_vm_t *vm, n update = parser->node; } - token = njs_parser_match(parser, token, NJS_TOKEN_CLOSE_PARENTHESIS); + token = njs_parser_match(vm, parser, token, NJS_TOKEN_CLOSE_PARENTHESIS); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { return token; } @@ -1076,14 +1097,23 @@ njs_parser_for_statement(njs_vm_t *vm, n static njs_token_t -njs_parser_for_in_statement(njs_vm_t *vm, njs_parser_t *parser, +njs_parser_for_in_statement(njs_vm_t *vm, njs_parser_t *parser, nxt_str_t *name, njs_token_t token) { + uint32_t size; njs_parser_node_t *node; + u_char buf[NJS_EXCEPTION_BUF_LENGTH]; node = parser->node->left; if (node->token != NJS_TOKEN_NAME) { + size = snprintf((char *) buf, NJS_EXCEPTION_BUF_LENGTH, + "ReferenceError: Invalid left-hand side \"%.*s\" " + "in for-in statement in %u", + (int) name->len, name->data, parser->lexer->line); + + (void) njs_vm_throw_exception(vm, buf, size); + return NJS_TOKEN_ILLEGAL; } @@ -1097,7 +1127,7 @@ njs_parser_for_in_statement(njs_vm_t *vm node->token = NJS_TOKEN_FOR_IN; node->left = parser->node; - token = njs_parser_match(parser, token, NJS_TOKEN_CLOSE_PARENTHESIS); + token = njs_parser_match(vm, parser, token, NJS_TOKEN_CLOSE_PARENTHESIS); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { return token; } @@ -1127,6 +1157,7 @@ njs_parser_continue_statement(njs_vm_t * } node->token = NJS_TOKEN_CONTINUE; + node->token_line = parser->lexer->token_line; parser->node = node; parser->code_size += sizeof(njs_vmcode_jump_t); @@ -1161,6 +1192,7 @@ njs_parser_break_statement(njs_vm_t *vm, } node->token = NJS_TOKEN_BREAK; + node->token_line = parser->lexer->token_line; parser->node = node; parser->code_size += sizeof(njs_vmcode_jump_t); @@ -1214,7 +1246,7 @@ njs_parser_try_statement(njs_vm_t *vm, n return token; } - token = njs_parser_match(parser, token, NJS_TOKEN_OPEN_PARENTHESIS); + token = njs_parser_match(vm, parser, token, NJS_TOKEN_OPEN_PARENTHESIS); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { return token; } @@ -1223,8 +1255,6 @@ njs_parser_try_statement(njs_vm_t *vm, n return NJS_TOKEN_ILLEGAL; } - nxt_thread_log_debug("CATCH: %V", &parser->lexer->text); - catch = njs_parser_node_alloc(vm); if (nxt_slow_path(catch == NULL)) { return NJS_TOKEN_ERROR; @@ -1297,8 +1327,7 @@ njs_parser_try_statement(njs_vm_t *vm, n } if (try->right == NULL) { - /* TODO: message */ - return NJS_TOKEN_ILLEGAL; + return njs_parser_missing_catch_or_finally(vm, parser); } parser->node = try; @@ -1309,6 +1338,22 @@ njs_parser_try_statement(njs_vm_t *vm, n static njs_token_t +njs_parser_missing_catch_or_finally(njs_vm_t *vm, njs_parser_t *parser) +{ + uint32_t size; + u_char buf[NJS_EXCEPTION_BUF_LENGTH]; + + size = snprintf((char *) buf, NJS_EXCEPTION_BUF_LENGTH, + "SyntaxError: Missing catch or finally after try in %u", + parser->lexer->line); + + (void) njs_vm_throw_exception(vm, buf, size); + + return NJS_TOKEN_ILLEGAL; +} + + +static njs_token_t njs_parser_try_block(njs_vm_t *vm, njs_parser_t *parser) { njs_token_t token; @@ -1366,7 +1411,7 @@ njs_parser_grouping_expression(njs_vm_t return token; } - token = njs_parser_match(parser, token, NJS_TOKEN_OPEN_PARENTHESIS); + token = njs_parser_match(vm, parser, token, NJS_TOKEN_OPEN_PARENTHESIS); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { return token; } @@ -1376,7 +1421,7 @@ njs_parser_grouping_expression(njs_vm_t return token; } - return njs_parser_match(parser, token, NJS_TOKEN_CLOSE_PARENTHESIS); + return njs_parser_match(vm, parser, token, NJS_TOKEN_CLOSE_PARENTHESIS); } @@ -1435,7 +1480,7 @@ njs_parser_terminal(njs_vm_t *vm, njs_pa return token; } - return njs_parser_match(parser, token, NJS_TOKEN_CLOSE_PARENTHESIS); + return njs_parser_match(vm, parser, token, NJS_TOKEN_CLOSE_PARENTHESIS); } if (token == NJS_TOKEN_FUNCTION) { @@ -1534,9 +1579,9 @@ njs_parser_terminal(njs_vm_t *vm, njs_pa return token; case NJS_TOKEN_DIVISION: - ret = njs_regexp_literal(vm, parser, &node->u.value); - if (nxt_slow_path(ret != NXT_OK)) { - return NJS_TOKEN_ILLEGAL; + token = njs_regexp_literal(vm, parser, &node->u.value); + if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { + return token; } nxt_thread_log_debug("REGEX: '%V'", &parser->lexer->text); @@ -1561,13 +1606,17 @@ njs_parser_terminal(njs_vm_t *vm, njs_pa nxt_thread_log_debug("JS: '%V'", &parser->lexer->text); - ret = njs_parser_escape_string_create(vm, &node->u.value); + ret = njs_parser_escape_string_create(vm, parser, &node->u.value); if (nxt_slow_path(ret != NJS_TOKEN_STRING)) { return ret; } break; + case NJS_TOKEN_UNTERMINATED_STRING: + return njs_parser_error(vm, parser, + NJS_PARSER_ERROR_UNTERMINATED_STRING); + case NJS_TOKEN_NUMBER: nxt_thread_log_debug("JS: %f", parser->lexer->number); @@ -1652,8 +1701,7 @@ njs_parser_terminal(njs_vm_t *vm, njs_pa return njs_parser_builtin_function(vm, parser, node); default: - vm->exception = &njs_exception_syntax_error; - return NJS_TOKEN_ILLEGAL; + return njs_parser_unexpected_token(vm, parser, token); } parser->node = node; @@ -1769,7 +1817,7 @@ njs_parser_object(njs_vm_t *vm, njs_pars return token; } - token = njs_parser_match(parser, token, NJS_TOKEN_COLON); + token = njs_parser_match(vm, parser, token, NJS_TOKEN_COLON); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { return token; } @@ -1944,7 +1992,8 @@ njs_parser_string_create(njs_vm_t *vm, n static njs_token_t -njs_parser_escape_string_create(njs_vm_t *vm, njs_value_t *value) +njs_parser_escape_string_create(njs_vm_t *vm, njs_parser_t *parser, + njs_value_t *value) { u_char c, *p, *start, *dst, *src, *end, *hex_end; size_t size, length, hex_length, skip; @@ -1962,8 +2011,8 @@ njs_parser_escape_string_create(njs_vm_t size = 0; length = 0; - src = vm->parser->lexer->text.data; - end = src + vm->parser->lexer->text.len; + src = parser->lexer->text.data; + end = src + parser->lexer->text.len; while (src < end) { c = *src++; @@ -1995,7 +2044,8 @@ njs_parser_escape_string_create(njs_vm_t } if (hex_length == 0 || hex_length > 6) { - return NJS_TOKEN_ILLEGAL; + return njs_parser_error(vm, parser, + NJS_PARSER_ERROR_UNICODE); } skip = 1; @@ -2070,12 +2120,12 @@ njs_parser_escape_string_create(njs_vm_t hex_end = src + hex_length; if (hex_end > end) { - return NJS_TOKEN_ILLEGAL; + return njs_parser_error(vm, parser, NJS_PARSER_ERROR_UNICODE); } u = njs_number_radix_parse(src, hex_end, 16, 1); if (nxt_slow_path(u < 0)) { - return NJS_TOKEN_ILLEGAL; + return njs_parser_error(vm, parser, NJS_PARSER_ERROR_UNICODE); } src = hex_end + skip; @@ -2154,3 +2204,52 @@ njs_parser_has_side_effect(njs_parser_no return side_effect; } + + +static njs_token_t +njs_parser_unexpected_token(njs_vm_t *vm, njs_parser_t *parser, + njs_token_t token) +{ + uint32_t size; + u_char buf[NJS_EXCEPTION_BUF_LENGTH]; + + if (token != NJS_TOKEN_END) { + return njs_parser_error(vm, parser, NJS_PARSER_ERROR_UNEXPECTED_TOKEN); + } + + size = snprintf((char *) buf, NJS_EXCEPTION_BUF_LENGTH, + "SyntaxError: Unexpected end of input in %u", + parser->lexer->line); + + (void) njs_vm_throw_exception(vm, buf, size); + + return NJS_TOKEN_ILLEGAL; +} + + +njs_token_t +njs_parser_error(njs_vm_t *vm, njs_parser_t *parser, njs_parser_error_t err) +{ + uint32_t size; + njs_lexer_t *lexer; + const char *msg; + u_char buf[NJS_EXCEPTION_BUF_LENGTH]; + + static const char *errors[] = { + "SyntaxError: Unexpected token \"%.*s\" in %u", + "SyntaxError: Unterminated string \"%.*s\" in %u", + "SyntaxError: Invalid Unicode code point \"%.*s\" in %u", + "SyntaxError: Unterminated RegExp \"%.*s\" in %u", + "SyntaxError: Invalid RegExp flags \"%.*s\" in %u", + }; + + msg = errors[err]; + lexer = parser->lexer; + + size = snprintf((char *) buf, NJS_EXCEPTION_BUF_LENGTH, + msg, (int) lexer->text.len, lexer->text.data, lexer->line); + + (void) njs_vm_throw_exception(vm, buf, size); + + return NJS_TOKEN_ILLEGAL; +} diff -r 5e7e498eb90d -r 07d2be75a7db njs/njs_parser.h --- a/njs/njs_parser.h Mon Jul 11 15:24:29 2016 +0300 +++ b/njs/njs_parser.h Wed Jul 13 13:56:12 2016 +0300 @@ -117,6 +117,7 @@ typedef enum { #define NJS_TOKEN_LAST_CONST NJS_TOKEN_STRING NJS_TOKEN_ESCAPE_STRING, + NJS_TOKEN_UNTERMINATED_STRING, NJS_TOKEN_NAME, NJS_TOKEN_OBJECT, @@ -191,6 +192,9 @@ typedef struct { uint8_t property; /* 1 bit */ uint32_t key_hash; + uint32_t token_line; + uint32_t line; + nxt_str_t text; double number; @@ -224,6 +228,7 @@ struct njs_parser_node_s { njs_lvalue_state_t lvalue:2; /* 2 bits */ uint8_t ctor:1; /* 1 bit */ uint8_t temporary; /* 1 bit */ + uint32_t token_line; union { uint32_t length; @@ -313,6 +318,15 @@ struct njs_parser_s { }; +typedef enum { + NJS_PARSER_ERROR_UNEXPECTED_TOKEN = 0, + NJS_PARSER_ERROR_UNTERMINATED_STRING, + NJS_PARSER_ERROR_UNICODE, + NJS_PARSER_ERROR_UNTERMINATED_REGEXP, + NJS_PARSER_ERROR_REGEXP_FLAGS, +} njs_parser_error_t; + + njs_token_t njs_lexer_token(njs_lexer_t *lexer); nxt_int_t njs_lexer_keywords_init(nxt_mem_cache_pool_t *mcp, nxt_lvlhsh_t *hash); @@ -339,6 +353,8 @@ njs_token_t njs_parser_token(njs_parser_ nxt_int_t njs_parser_string_create(njs_vm_t *vm, njs_value_t *value); njs_index_t njs_parser_index(njs_parser_t *parser, uint32_t scope); nxt_bool_t njs_parser_has_side_effect(njs_parser_node_t *node); +njs_token_t njs_parser_error(njs_vm_t *vm, njs_parser_t *parser, + njs_parser_error_t err); nxt_int_t njs_generate_scope(njs_vm_t *vm, njs_parser_t *parser, njs_parser_node_t *node); diff -r 5e7e498eb90d -r 07d2be75a7db njs/njs_parser_expression.c --- a/njs/njs_parser_expression.c Mon Jul 11 15:24:29 2016 +0300 +++ b/njs/njs_parser_expression.c Wed Jul 13 13:56:12 2016 +0300 @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -16,11 +17,13 @@ #include #include #include +#include #include #include #include #include #include +#include typedef struct { @@ -71,6 +74,8 @@ static njs_token_t njs_parser_property_e njs_parser_t *parser, njs_token_t token); static njs_token_t njs_parser_property_brackets(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token); +static njs_token_t njs_parser_invalid_lvalue(njs_vm_t *vm, + njs_parser_t *parser, const char* operation); static const njs_parser_expression_t @@ -288,8 +293,7 @@ njs_parser_var_expression(njs_vm_t *vm, node = parser->node; if (node->lvalue == NJS_LVALUE_NONE) { - nxt_thread_log_error(NXT_LOG_ALERT, "lvalue required"); - return NJS_TOKEN_ILLEGAL; + return njs_parser_invalid_lvalue(vm, parser, "assignment"); } pending = NULL; @@ -434,8 +438,7 @@ njs_parser_assignment_expression(njs_vm_ node = parser->node; if (node->lvalue == NJS_LVALUE_NONE) { - nxt_thread_log_error(NXT_LOG_ALERT, "lvalue required"); - return NJS_TOKEN_ILLEGAL; + return njs_parser_invalid_lvalue(vm, parser, "assignment"); } pending = NULL; @@ -807,8 +810,7 @@ njs_parser_inc_dec_expression(njs_vm_t * } if (parser->node->lvalue == NJS_LVALUE_NONE) { - nxt_thread_log_error(NXT_LOG_ALERT, "lvalue required"); - return NJS_TOKEN_ILLEGAL; + return njs_parser_invalid_lvalue(vm, parser, "prefix operation"); } node = njs_parser_node_alloc(vm); @@ -860,8 +862,7 @@ njs_parser_post_inc_dec_expression(njs_v } if (parser->node->lvalue == NJS_LVALUE_NONE) { - nxt_thread_log_error(NXT_LOG_ALERT, "lvalue required"); - return NJS_TOKEN_ILLEGAL; + return njs_parser_invalid_lvalue(vm, parser, "postfix operation"); } node = njs_parser_node_alloc(vm); @@ -1142,3 +1143,21 @@ njs_parser_arguments(njs_vm_t *vm, njs_p return token; } + + +static njs_token_t +njs_parser_invalid_lvalue(njs_vm_t *vm, njs_parser_t *parser, + const char *operation) +{ + uint32_t size; + u_char buf[NJS_EXCEPTION_BUF_LENGTH]; + + size = snprintf((char *) buf, NJS_EXCEPTION_BUF_LENGTH, + "ReferenceError: Invalid left-hand side in %s in %u", + operation, parser->lexer->line); + + (void) njs_vm_throw_exception(vm, buf, size); + + return NJS_TOKEN_ILLEGAL; + +} diff -r 5e7e498eb90d -r 07d2be75a7db njs/njs_regexp.c --- a/njs/njs_regexp.c Mon Jul 11 15:24:29 2016 +0300 +++ b/njs/njs_regexp.c Wed Jul 13 13:56:12 2016 +0300 @@ -24,11 +24,12 @@ #include #include #include +#include +#include #include #include -#include -#include #include +#include static void *njs_regexp_malloc(size_t size, void *memory_data); @@ -133,7 +134,7 @@ njs_regexp_constructor(njs_vm_t *vm, njs } -nxt_int_t +njs_token_t njs_regexp_literal(njs_vm_t *vm, njs_parser_t *parser, njs_value_t *value) { u_char *p; @@ -154,11 +155,15 @@ njs_regexp_literal(njs_vm_t *vm, njs_par lexer->text.data = lexer->start; lexer->text.len = p - lexer->text.data; p++; + lexer->start = p; flags = njs_regexp_flags(&p, lexer->end, 0); if (nxt_slow_path(flags < 0)) { - return NXT_ERROR; + lexer->text.data = lexer->start; + lexer->text.len = p - lexer->text.data; + return njs_parser_error(vm, parser, + NJS_PARSER_ERROR_REGEXP_FLAGS); } lexer->start = p; @@ -166,16 +171,19 @@ njs_regexp_literal(njs_vm_t *vm, njs_par pattern = njs_regexp_pattern_create(vm, lexer->text.data, lexer->text.len, flags); if (nxt_slow_path(pattern == NULL)) { - return NXT_ERROR; + return NJS_TOKEN_ILLEGAL; } value->data.u.data = pattern; - return NXT_OK; + return NJS_TOKEN_REGEXP; } } - return NXT_ERROR; + lexer->text.data = lexer->start - 1; + lexer->text.len = p - lexer->text.data; + + return njs_parser_error(vm, parser, NJS_PARSER_ERROR_UNTERMINATED_REGEXP); } @@ -203,16 +211,28 @@ njs_regexp_flags(u_char **start, u_char flag = NJS_REGEXP_MULTILINE; break; - default: - if (bound) { - return NJS_REGEXP_INVALID_FLAG; + case ';': + case ' ': + case '\t': + case '\r': + case '\n': + case ',': + case ')': + case ']': + case '}': + case '.': + if (!bound) { + goto done; } - goto done; + /* Fall through. */ + + default: + goto invalid; } if (nxt_slow_path((flags & flag) != 0)) { - return NJS_REGEXP_INVALID_FLAG; + goto invalid; } flags |= flag; @@ -223,6 +243,12 @@ done: *start = p; return flags; + +invalid: + + *start = p + 1; + + return NJS_REGEXP_INVALID_FLAG; } @@ -298,10 +324,7 @@ njs_regexp_pattern_create(njs_vm_t *vm, if (nxt_fast_path(ret >= 0)) { if (nxt_slow_path((u_int) ret != pattern->ncaptures)) { - nxt_thread_log_error(NXT_LOG_ERR, "numbers of captures in byte " - "and UTF-8 versions of RegExp \"%s\" vary: %d vs %d", From piotrsikora at google.com Wed Jul 13 17:25:57 2016 From: piotrsikora at google.com (Piotr Sikora) Date: Wed, 13 Jul 2016 10:25:57 -0700 Subject: [PATCH 1 of 2] HTTP: add support for trailers in HTTP responses In-Reply-To: <20160707232029.GO30781@mdounin.ru> References: <20160627134500.GZ30781@mdounin.ru> <20160627175338.GD30781@mdounin.ru> <20160704142135.GZ30781@mdounin.ru> <20160707150047.GJ30781@mdounin.ru> <20160707232029.GO30781@mdounin.ru> Message-ID: Hey Maxim, > So the question remains: are there any real-world use cases? May > be someone will be able to provide some. It's a chicken-and-egg problem. It's hard to use a feature that's not supported by one of the most popular web servers. > Without real-world use cases I don't think this should be added, > as in general trailers is quite external concept to how nginx > works and also may have various security implications. Just to be clear, are you talking about HTTP/1.1 trailers or trailers in general? The patch also includes HTTP/2 trailers and it's not clear which one you don't like. > Silently dropping trailers is what anyway happens if the client > doesn't support chunked encoding at all (e.g., uses HTTP/1.0). > And this is also what happens in your patch if there is no "TE: > trailers". Yes, but then it happens for a reason (client doesn't support trailers) and not "just because". > I think that whether to drop Content-Length and switch to chunked > encoding is highly use-case specific question. In some cases it > may be appropriate, in some cases not, and in some cases one may > want to add trailers even without "TE: trailers". So forcing > chunked encoding probably should be configured separately. On the > other hand, it's very hard to decide something given there are no > real use cases known. Why? I don't see anyone making a big deal out of forced chunked encoding with "gzip on". Best regards, Piotr Sikora From piotrsikora at google.com Wed Jul 13 17:27:56 2016 From: piotrsikora at google.com (Piotr Sikora) Date: Wed, 13 Jul 2016 10:27:56 -0700 Subject: [PATCH] Core: detect valid error numbers at run-time In-Reply-To: <20160708014750.GS30781@mdounin.ru> References: <20160708014750.GS30781@mdounin.ru> Message-ID: Hey Maxim, > This looks utterly wrong. You are removing proper support for > platforms with sys_nerr (including Linux and FreeBSD) and use > instead the workaround designed to somehow work on other > platforms. Use of sys_nerr is deprecated, so it's not a perfect solution, but fair enough, I'll rework this... Best regards, Piotr Sikora From piotrsikora at google.com Wed Jul 13 17:29:04 2016 From: piotrsikora at google.com (Piotr Sikora) Date: Wed, 13 Jul 2016 10:29:04 -0700 Subject: [PATCH] Core: reorder #ifdef in .h file to match order in .c file In-Reply-To: <20160708141155.GV30781@mdounin.ru> References: <11a53446bd90b8927cb9.1467082518@piotrsikora.sfo.corp.google.com> <20160708141155.GV30781@mdounin.ru> Message-ID: Hey Maxim, > Current order matches one used in #if in the same .h file, and I > don't think this order needs to be changed. Hmm? Are we looking at the same files? http://hg.nginx.org/nginx/file/tip/src/os/unix/ngx_setaffinity.h: #if (NGX_HAVE_SCHED_SETAFFINITY) ... #elif (NGX_HAVE_CPUSET_SETAFFINITY) ... #endif http://hg.nginx.org/nginx/file/tip/src/os/unix/ngx_setaffinity.c: #if (NGX_HAVE_CPUSET_SETAFFINITY) .... #elif (NGX_HAVE_SCHED_SETAFFINITY) .... #endif The order is different... And yes, I know that's nitpicking. Best regards, Piotr Sikora From piotrsikora at google.com Wed Jul 13 18:00:06 2016 From: piotrsikora at google.com (Piotr Sikora) Date: Wed, 13 Jul 2016 11:00:06 -0700 Subject: [PATCH 2 of 2] Core: remove NGX_TIME_T_SIZE In-Reply-To: <20160708011232.GR30781@mdounin.ru> References: <1059f59c44039020843c.1467077402@piotrsikora.sfo.corp.google.com> <20160708011232.GR30781@mdounin.ru> Message-ID: Hey Maxim, > I don't think that size of time_t should be removed from module > signatures. E.g., OpenBSD switched to 64-bit time_t on 32-bit > hosts a couple of years ago, and I would expect similar things to > happen on other platforms as well. Signatures were designed to > prevent loading of incompatible modules in such cases. I'm aware of that change... I don't have a way to test this, but I assume that modules wouldn't load even without NGX_TIME_T_SIZE being in the signature, because of the libc and/or kernel ABI bump. Also, it's not clear to me why time_t is part of the signature, but ino_t and off_t (for example) aren't. > It can be replaced with, e.g., NGX_TIME_T_LEN, but I don't see > reasoning behind these changes. Are you trying to make it > possible to build nginx as a multiarchitecture binary? Removal of values detected at the ./configure-time is one of the ways to enable cross-compilation, since the autotest binary cannot be run on the system running ./configure script. Best regards, Piotr Sikora From mdounin at mdounin.ru Wed Jul 13 18:01:03 2016 From: mdounin at mdounin.ru (Maxim Dounin) Date: Wed, 13 Jul 2016 21:01:03 +0300 Subject: [PATCH] Core: reorder #ifdef in .h file to match order in .c file In-Reply-To: References: <11a53446bd90b8927cb9.1467082518@piotrsikora.sfo.corp.google.com> <20160708141155.GV30781@mdounin.ru> Message-ID: <20160713180103.GP57459@mdounin.ru> Hello! On Wed, Jul 13, 2016 at 10:29:04AM -0700, Piotr Sikora wrote: > Hey Maxim, > > > Current order matches one used in #if in the same .h file, and I > > don't think this order needs to be changed. > > Hmm? Are we looking at the same files? > > http://hg.nginx.org/nginx/file/tip/src/os/unix/ngx_setaffinity.h: > > #if (NGX_HAVE_SCHED_SETAFFINITY) > ... > #elif (NGX_HAVE_CPUSET_SETAFFINITY) > ... > #endif > > http://hg.nginx.org/nginx/file/tip/src/os/unix/ngx_setaffinity.c: > > #if (NGX_HAVE_CPUSET_SETAFFINITY) > .... > #elif (NGX_HAVE_SCHED_SETAFFINITY) > .... > #endif > > The order is different... And yes, I know that's nitpicking. I wrote "in #if in the same .h file", that is, http://hg.nginx.org/nginx/file/tip/src/os/unix/ngx_setaffinity.h#l10: #if (NGX_HAVE_SCHED_SETAFFINITY || NGX_HAVE_CPUSET_SETAFFINITY) ... #if (NGX_HAVE_SCHED_SETAFFINITY) ... #elif (NGX_HAVE_CPUSET_SETAFFINITY) ... #endif ... -- Maxim Dounin http://nginx.org/ From mdounin at mdounin.ru Wed Jul 13 18:43:31 2016 From: mdounin at mdounin.ru (Maxim Dounin) Date: Wed, 13 Jul 2016 21:43:31 +0300 Subject: [PATCH 1 of 2] HTTP: add support for trailers in HTTP responses In-Reply-To: References: <20160627175338.GD30781@mdounin.ru> <20160704142135.GZ30781@mdounin.ru> <20160707150047.GJ30781@mdounin.ru> <20160707232029.GO30781@mdounin.ru> Message-ID: <20160713184331.GQ57459@mdounin.ru> Hello! On Wed, Jul 13, 2016 at 10:25:57AM -0700, Piotr Sikora wrote: > > So the question remains: are there any real-world use cases? May > > be someone will be able to provide some. > > It's a chicken-and-egg problem. It's hard to use a feature that's not > supported by one of the most popular web servers. The feature was there for years before nginx became popular. And no one prevents it to be used with other servers, including more popular ones. The fact that there are no real-world use cases suggests that there is something wrong with the feature. > > Without real-world use cases I don't think this should be added, > > as in general trailers is quite external concept to how nginx > > works and also may have various security implications. > > Just to be clear, are you talking about HTTP/1.1 trailers or trailers > in general? The patch also includes HTTP/2 trailers and it's not clear > which one you don't like. I'm talking about trailers in general (though it's more about requests than responses). Normal request (and response) processing in nginx assumes that headers are processed before the body, and adding trailers (which are headers "to be added later") to the picture are likely to have various security implications. > > Silently dropping trailers is what anyway happens if the client > > doesn't support chunked encoding at all (e.g., uses HTTP/1.0). > > And this is also what happens in your patch if there is no "TE: > > trailers". > > Yes, but then it happens for a reason (client doesn't support > trailers) and not "just because". "Transfer encoding used doesn't allow trailers" looks like a reason for me. > > I think that whether to drop Content-Length and switch to chunked > > encoding is highly use-case specific question. In some cases it > > may be appropriate, in some cases not, and in some cases one may > > want to add trailers even without "TE: trailers". So forcing > > chunked encoding probably should be configured separately. On the > > other hand, it's very hard to decide something given there are no > > real use cases known. > > Why? I don't see anyone making a big deal out of forced chunked > encoding with "gzip on". Gzip drops Content-Length because it's not possible to know it in advice. And does so only for some responses, with various configuration options available to prevent this happening for clients who can't handle it and/or for responses where it is not beneficial. -- Maxim Dounin http://nginx.org/ From mdounin at mdounin.ru Wed Jul 13 19:01:31 2016 From: mdounin at mdounin.ru (Maxim Dounin) Date: Wed, 13 Jul 2016 22:01:31 +0300 Subject: [PATCH 2 of 2] Core: remove NGX_TIME_T_SIZE In-Reply-To: References: <1059f59c44039020843c.1467077402@piotrsikora.sfo.corp.google.com> <20160708011232.GR30781@mdounin.ru> Message-ID: <20160713190131.GR57459@mdounin.ru> Hello! On Wed, Jul 13, 2016 at 11:00:06AM -0700, Piotr Sikora wrote: > Hey Maxim, > > > I don't think that size of time_t should be removed from module > > signatures. E.g., OpenBSD switched to 64-bit time_t on 32-bit > > hosts a couple of years ago, and I would expect similar things to > > happen on other platforms as well. Signatures were designed to > > prevent loading of incompatible modules in such cases. > > I'm aware of that change... I don't have a way to test this, but I > assume that modules wouldn't load even without NGX_TIME_T_SIZE being > in the signature, because of the libc and/or kernel ABI bump. > > Also, it's not clear to me why time_t is part of the signature, but > ino_t and off_t (for example) aren't. Because we don't have NGX_INO_T_SIZE/NGX_OFF_T_SIZE readily available and decided that adding them don't worth the effort. > > It can be replaced with, e.g., NGX_TIME_T_LEN, but I don't see > > reasoning behind these changes. Are you trying to make it > > possible to build nginx as a multiarchitecture binary? > > Removal of values detected at the ./configure-time is one of the ways > to enable cross-compilation, since the autotest binary cannot be run > on the system running ./configure script. For cross-compilation it might be more reasonable to use static/compile-time assertions in auto/types/sizeof instead. There were previous attempts to introduce such changes. -- Maxim Dounin http://nginx.org/ From piotrsikora at google.com Thu Jul 14 00:34:32 2016 From: piotrsikora at google.com (Piotr Sikora) Date: Wed, 13 Jul 2016 17:34:32 -0700 Subject: [PATCH 1 of 2] HTTP: add support for trailers in HTTP responses In-Reply-To: <20160713184331.GQ57459@mdounin.ru> References: <20160627175338.GD30781@mdounin.ru> <20160704142135.GZ30781@mdounin.ru> <20160707150047.GJ30781@mdounin.ru> <20160707232029.GO30781@mdounin.ru> <20160713184331.GQ57459@mdounin.ru> Message-ID: Hey Maxim, > I'm talking about trailers in general (though it's more about > requests than responses). Normal request (and response) > processing in nginx assumes that headers are processed before the > body, and adding trailers (which are headers "to be added later") > to the picture are likely to have various security implications. Let's step back a bit... I have no plans to change the processing logic nor merge trailers with headers. Trailers are going to be ignored (passed, but not processed) by NGINX, not discarded. AFAIK, Apache does the same thing. Basically, at this point, trailers act as metadata for the application (browser, gRPC, 3rd-party NGINX module, etc.), with no HTTP semantics, so there are no security implications for NGINX itself. Best regards, Piotr Sikora From igor at sysoev.ru Thu Jul 14 16:50:12 2016 From: igor at sysoev.ru (Igor Sysoev) Date: Thu, 14 Jul 2016 16:50:12 +0000 Subject: [njs] njs_vm_function() interface to get a function by name. Message-ID: details: http://hg.nginx.org/njs/rev/74246210aa9d branches: changeset: 121:74246210aa9d user: Igor Sysoev date: Thu Jul 14 19:24:51 2016 +0300 description: njs_vm_function() interface to get a function by name. diffstat: njs/njs_variable.c | 24 ++++++++++++++++++++++++ njs/njscript.h | 1 + 2 files changed, 25 insertions(+), 0 deletions(-) diffs (45 lines): diff -r 07d2be75a7db -r 74246210aa9d njs/njs_variable.c --- a/njs/njs_variable.c Wed Jul 13 13:56:12 2016 +0300 +++ b/njs/njs_variable.c Thu Jul 14 19:24:51 2016 +0300 @@ -119,6 +119,30 @@ njs_parser_variable(njs_vm_t *vm, njs_pa } +njs_function_t * +njs_vm_function(njs_vm_t *vm, nxt_str_t *name) +{ + njs_value_t *value; + njs_variable_t *var; + nxt_lvlhsh_query_t lhq; + + lhq.key_hash = nxt_djb_hash(name->data, name->len); + lhq.key = *name; + lhq.proto = &njs_variables_hash_proto; + + if (nxt_slow_path(nxt_lvlhsh_find(&vm->variables_hash, &lhq) != NXT_OK)) { + return NULL; + } + + var = lhq.value; + + value = (njs_value_t *) ((u_char *) vm->scopes[NJS_SCOPE_GLOBAL] + + njs_offset(var->index)); + + return value->data.u.function; +} + + static njs_variable_t * njs_variable_alloc(njs_vm_t *vm, njs_parser_t *parser, nxt_str_t *name) { diff -r 07d2be75a7db -r 74246210aa9d njs/njscript.h --- a/njs/njscript.h Wed Jul 13 13:56:12 2016 +0300 +++ b/njs/njscript.h Thu Jul 14 19:24:51 2016 +0300 @@ -91,6 +91,7 @@ NXT_EXPORT nxt_int_t njs_vm_call(njs_vm_ njs_opaque_value_t *args, nxt_uint_t nargs); NXT_EXPORT nxt_int_t njs_vm_run(njs_vm_t *vm); +NXT_EXPORT njs_function_t *njs_vm_function(njs_vm_t *vm, nxt_str_t *name); NXT_EXPORT njs_ret_t njs_vm_return_string(njs_vm_t *vm, u_char *start, size_t size); NXT_EXPORT nxt_int_t njs_vm_retval(njs_vm_t *vm, nxt_str_t *retval); From linnading1989 at gmail.com Thu Jul 14 17:49:17 2016 From: linnading1989 at gmail.com (Linna.Ding) Date: Thu, 14 Jul 2016 13:49:17 -0400 Subject: Nginx map value not matched when used as input of another map Message-ID: Hi there, I am having an issue with Nginx map that seems to not match values when the output variable is the input of another map. *Case 1: cachestatus_user_agent map is defined separately, not used as input of wordpress_key map* *Case 2: cachestatus_user_agent is used as input of wordpress_key map* Here's my logformat I use to see the results of our maps: *nginx_logformat.conf* log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$host" "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for" ' '"$upstream_cache_status" "$request_length" ' '"$request_time" "$upstream_response_time" ' '"$pipe" "$bytes_sent" "$http_pragma" ' '"$http_cache_control" "{external_ip}" "{instance_name}" ' '"$scheme" "$upstream_status" "cachestatus_map:$cachestatus_user_agent" ' '"wordpress_key_map:$wordpress_key"'; And then I configure some maps like so: *nginx.conf* http { limit_req_zone $wordpress_key zone=wordpress_host:1m rate=1r/m; * # Here's my initial map* map $upstream_cache_status $cachestatus_user_agent { HIT $http_user_agent; EXPIRED $http_user_agent; - $http_user_agent; default ""; } *# Successful case, because it starts with a non-mapped var* map $http_user_agent $wordpress_key { *# Failure case, because it starts with a mapped var* map $cachestatus_user_agent $wordpress_key { ~(WordPress) $host; default ""; } We can see the results below; in the successful case, we see both cachestatus_map and wordpress_key_map have the expected values: *Access.log:* 127.0.0.1 - - [13/Jul/2016:16:21:49 -0400] "HEAD / HTTP/1.1" 200 0 " www.linna-test.com" "-" "WordPress/2.1.1" "-" "HIT" "87" "0.000" "-" "." "293" "-" "-" "{external_ip}" "{instance_name}" "http" "-" "cachestatus_map:WordPress/2.1.1" "wordpress_key_map:www.linna-test.com" In the failure case, neither value matches. This is especially weird, because the first map didn't even change between the two cases. *Access.log:* 127.0.0.1 - - [13/Jul/2016:16:27:32 -0400] "HEAD / HTTP/1.1" 200 0 " www.linna-test.com" "-" "WordPress/2.1.1" "-" "HIT" "87" "0.000" "-" "." "293" "-" "-" "{external_ip}" "{instance_name}" "http" "-" "cachestatus_map:" "wordpress_key_map:" What's weird is that I have another limit_req_zone defined with the same pattern: two maps linked together, and it works. The limit_req_zone and maps are defined as below. Both $post_remote_addr and $post_limited_binary_remote_addr were printed out when I log them. limit_req_zone $post_limited_binary_remote_addr zone=post_ip:1m rate=1r/m; map $request_method $post_remote_addr { POST $remote_addr; default ""; } map $post_remote_addr $post_limited_binary_remote_addr { "" ""; default $binary_remote_addr; } It seems only $upstream_cache_status has this issue, and I searched around a bit and couldn't find any public issues related to this. Does anyone have any thoughts on this? Thanks! ~Linna -------------- next part -------------- An HTML attachment was scrubbed... URL: From vbart at nginx.com Fri Jul 15 12:35:35 2016 From: vbart at nginx.com (Valentin Bartenev) Date: Fri, 15 Jul 2016 12:35:35 +0000 Subject: [nginx] Events: the "accept_mutex" directive is turned off by default. Message-ID: details: http://hg.nginx.org/nginx/rev/d82b3c344e7e branches: changeset: 6633:d82b3c344e7e user: Valentin Bartenev date: Fri Jul 15 15:18:57 2016 +0300 description: Events: the "accept_mutex" directive is turned off by default. Now it is believed that the accept mutex brings more harm than benefits. Especially in various benchmarks it often results in situation where only one worker grabs all connections. diffstat: src/event/ngx_event.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diffs (12 lines): diff -r 787dcc15b802 -r d82b3c344e7e src/event/ngx_event.c --- a/src/event/ngx_event.c Tue Jul 12 17:34:52 2016 +0300 +++ b/src/event/ngx_event.c Fri Jul 15 15:18:57 2016 +0300 @@ -1261,7 +1261,7 @@ ngx_event_core_init_conf(ngx_cycle_t *cy ngx_conf_init_ptr_value(ecf->name, event_module->name->data); ngx_conf_init_value(ecf->multi_accept, 0); - ngx_conf_init_value(ecf->accept_mutex, 1); + ngx_conf_init_value(ecf->accept_mutex, 0); ngx_conf_init_msec_value(ecf->accept_mutex_delay, 500); return NGX_CONF_OK; From vbart at nginx.com Fri Jul 15 12:35:39 2016 From: vbart at nginx.com (Valentin Bartenev) Date: Fri, 15 Jul 2016 12:35:39 +0000 Subject: [nginx] Style: sorted epoll flags. Message-ID: details: http://hg.nginx.org/nginx/rev/18f6120e3b7a branches: changeset: 6634:18f6120e3b7a user: Valentin Bartenev date: Fri Jul 15 15:18:57 2016 +0300 description: Style: sorted epoll flags. diffstat: src/event/modules/ngx_epoll_module.c | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diffs (25 lines): diff -r d82b3c344e7e -r 18f6120e3b7a src/event/modules/ngx_epoll_module.c --- a/src/event/modules/ngx_epoll_module.c Fri Jul 15 15:18:57 2016 +0300 +++ b/src/event/modules/ngx_epoll_module.c Fri Jul 15 15:18:57 2016 +0300 @@ -17,18 +17,18 @@ #define EPOLLIN 0x001 #define EPOLLPRI 0x002 #define EPOLLOUT 0x004 +#define EPOLLERR 0x008 +#define EPOLLHUP 0x010 #define EPOLLRDNORM 0x040 #define EPOLLRDBAND 0x080 #define EPOLLWRNORM 0x100 #define EPOLLWRBAND 0x200 #define EPOLLMSG 0x400 -#define EPOLLERR 0x008 -#define EPOLLHUP 0x010 #define EPOLLRDHUP 0x2000 +#define EPOLLONESHOT 0x40000000 #define EPOLLET 0x80000000 -#define EPOLLONESHOT 0x40000000 #define EPOLL_CTL_ADD 1 #define EPOLL_CTL_DEL 2 From vbart at nginx.com Fri Jul 15 12:35:41 2016 From: vbart at nginx.com (Valentin Bartenev) Date: Fri, 15 Jul 2016 12:35:41 +0000 Subject: [nginx] Events: support for EPOLLEXCLUSIVE. Message-ID: details: http://hg.nginx.org/nginx/rev/6acaa638fa07 branches: changeset: 6635:6acaa638fa07 user: Valentin Bartenev date: Fri Jul 15 15:18:57 2016 +0300 description: Events: support for EPOLLEXCLUSIVE. This flag appeared in Linux 4.5 and is useful for avoiding thundering herd problem. The current Linux kernel implementation walks the list of exclusive waiters, and queues an event to each epfd, until it finds the first waiter that has threads blocked on it via epoll_wait(). diffstat: auto/modules | 1 + auto/os/linux | 16 ++++++++++++++++ src/event/modules/ngx_epoll_module.c | 7 +++++++ src/event/ngx_event.c | 33 ++++++++++++++++++++++++++++----- src/event/ngx_event.h | 8 ++++++++ 5 files changed, 60 insertions(+), 5 deletions(-) diffs (133 lines): diff -r 18f6120e3b7a -r 6acaa638fa07 auto/modules --- a/auto/modules Fri Jul 15 15:18:57 2016 +0300 +++ b/auto/modules Fri Jul 15 15:18:57 2016 +0300 @@ -43,6 +43,7 @@ fi if [ $NGX_TEST_BUILD_EPOLL = YES ]; then have=NGX_HAVE_EPOLL . auto/have have=NGX_HAVE_EPOLLRDHUP . auto/have + have=NGX_HAVE_EPOLLEXCLUSIVE . auto/have have=NGX_HAVE_EVENTFD . auto/have have=NGX_TEST_BUILD_EPOLL . auto/have EVENT_MODULES="$EVENT_MODULES $EPOLL_MODULE" diff -r 18f6120e3b7a -r 6acaa638fa07 auto/os/linux --- a/auto/os/linux Fri Jul 15 15:18:57 2016 +0300 +++ b/auto/os/linux Fri Jul 15 15:18:57 2016 +0300 @@ -70,6 +70,22 @@ if [ $ngx_found = yes ]; then ee.data.ptr = NULL; epoll_ctl(efd, EPOLL_CTL_ADD, fd, &ee)" . auto/feature + + + # EPOLLEXCLUSIVE appeared in Linux 4.5, glibc 2.24 + + ngx_feature="EPOLLEXCLUSIVE" + ngx_feature_name="NGX_HAVE_EPOLLEXCLUSIVE" + ngx_feature_run=no + ngx_feature_incs="#include " + ngx_feature_path= + ngx_feature_libs= + ngx_feature_test="int efd = 0, fd = 0; + struct epoll_event ee; + ee.events = EPOLLIN|EPOLLEXCLUSIVE; + ee.data.ptr = NULL; + epoll_ctl(efd, EPOLL_CTL_ADD, fd, &ee)" + . auto/feature fi diff -r 18f6120e3b7a -r 6acaa638fa07 src/event/modules/ngx_epoll_module.c --- a/src/event/modules/ngx_epoll_module.c Fri Jul 15 15:18:57 2016 +0300 +++ b/src/event/modules/ngx_epoll_module.c Fri Jul 15 15:18:57 2016 +0300 @@ -27,6 +27,7 @@ #define EPOLLRDHUP 0x2000 +#define EPOLLEXCLUSIVE 0x10000000 #define EPOLLONESHOT 0x40000000 #define EPOLLET 0x80000000 @@ -610,6 +611,12 @@ ngx_epoll_add_event(ngx_event_t *ev, ngx op = EPOLL_CTL_ADD; } +#if (NGX_HAVE_EPOLLEXCLUSIVE && NGX_HAVE_EPOLLRDHUP) + if (flags & NGX_EXCLUSIVE_EVENT) { + events &= ~EPOLLRDHUP; + } +#endif + ee.events = events | (uint32_t) flags; ee.data.ptr = (void *) ((uintptr_t) c | ev->instance); diff -r 18f6120e3b7a -r 6acaa638fa07 src/event/ngx_event.c --- a/src/event/ngx_event.c Fri Jul 15 15:18:57 2016 +0300 +++ b/src/event/ngx_event.c Fri Jul 15 15:18:57 2016 +0300 @@ -822,15 +822,38 @@ ngx_event_process_init(ngx_cycle_t *cycl rev->handler = (c->type == SOCK_STREAM) ? ngx_event_accept : ngx_event_recvmsg; - if (ngx_use_accept_mutex #if (NGX_HAVE_REUSEPORT) - && !ls[i].reuseport -#endif - ) - { + + if (ls[i].reuseport) { + if (ngx_add_event(rev, NGX_READ_EVENT, 0) == NGX_ERROR) { + return NGX_ERROR; + } + continue; } +#endif + + if (ngx_use_accept_mutex) { + continue; + } + +#if (NGX_HAVE_EPOLLEXCLUSIVE) + + if ((ngx_event_flags & NGX_USE_EPOLL_EVENT) + && ccf->worker_processes > 1) + { + if (ngx_add_event(rev, NGX_READ_EVENT, NGX_EXCLUSIVE_EVENT) + == NGX_ERROR) + { + return NGX_ERROR; + } + + continue; + } + +#endif + if (ngx_add_event(rev, NGX_READ_EVENT, 0) == NGX_ERROR) { return NGX_ERROR; } diff -r 18f6120e3b7a -r 6acaa638fa07 src/event/ngx_event.h --- a/src/event/ngx_event.h Fri Jul 15 15:18:57 2016 +0300 +++ b/src/event/ngx_event.h Fri Jul 15 15:18:57 2016 +0300 @@ -367,6 +367,9 @@ extern ngx_uint_t ngx_use_epo #define NGX_ONESHOT_EVENT EPOLLONESHOT #endif +#if (NGX_HAVE_EPOLLEXCLUSIVE) +#define NGX_EXCLUSIVE_EVENT EPOLLEXCLUSIVE +#endif #elif (NGX_HAVE_POLL) @@ -395,6 +398,11 @@ extern ngx_uint_t ngx_use_epo #endif +#if (NGX_TEST_BUILD_EPOLL) +#define NGX_EXCLUSIVE_EVENT 0 +#endif + + #ifndef NGX_CLEAR_EVENT #define NGX_CLEAR_EVENT 0 /* dummy declaration */ #endif From vbart at nginx.com Fri Jul 15 12:40:24 2016 From: vbart at nginx.com (Valentin V. Bartenev) Date: Fri, 15 Jul 2016 15:40:24 +0300 Subject: Nginx map value not matched when used as input of another map In-Reply-To: References: Message-ID: <1969358.3ZQhnZXUAO@vbart-workstation> On Thursday 14 July 2016 13:49:17 Linna.Ding wrote: [..] > limit_req_zone $wordpress_key zone=wordpress_host:1m rate=1r/m; [..] > It seems only $upstream_cache_status has this issue, and I searched around > a bit and couldn't find any public issues related to this. Does anyone have > any thoughts on this? [..] The $upstream_cache_status isn't available at the moment when the $wordpress_key is checked. wbr, Valentin V. Bartenev From igor at sysoev.ru Fri Jul 15 12:50:49 2016 From: igor at sysoev.ru (Igor Sysoev) Date: Fri, 15 Jul 2016 12:50:49 +0000 Subject: [njs] njs_vm_function() and njs_vm_external() functions name and Message-ID: details: http://hg.nginx.org/njs/rev/a3e7ebdf9fa7 branches: changeset: 122:a3e7ebdf9fa7 user: Igor Sysoev date: Fri Jul 15 15:50:13 2016 +0300 description: njs_vm_function() and njs_vm_external() functions name and behavior unification. The function can be used with both original compiled VM and its clones. diffstat: nginx/ngx_http_js_module.c | 8 ++++---- njs/njs_extern.c | 6 +++--- njs/njs_variable.c | 4 ++-- njs/njscript.c | 1 + njs/njscript.h | 4 ++-- njs/test/njs_unit_test.c | 6 +++--- 6 files changed, 15 insertions(+), 14 deletions(-) diffs (126 lines): diff -r 74246210aa9d -r a3e7ebdf9fa7 nginx/ngx_http_js_module.c --- a/nginx/ngx_http_js_module.c Thu Jul 14 19:24:51 2016 +0300 +++ b/nginx/ngx_http_js_module.c Fri Jul 15 15:50:13 2016 +0300 @@ -1152,8 +1152,8 @@ ngx_http_js_compile(ngx_conf_t *cf, ngx_ nxt_lvlhsh_init(&externals); - if (njs_add_external(&externals, mcp, 0, ngx_http_js_externals, - nxt_nitems(ngx_http_js_externals)) + if (njs_vm_external_add(&externals, mcp, 0, ngx_http_js_externals, + nxt_nitems(ngx_http_js_externals)) != NJS_OK) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "could not add js externals"); @@ -1191,7 +1191,7 @@ ngx_http_js_compile(ngx_conf_t *cf, ngx_ if (function) { ngx_str_set(&name, "$r"); - rc = njs_external_get(vm, NULL, &name, &js->args[0]); + rc = njs_vm_external(vm, NULL, &name, &js->args[0]); if (rc != NXT_OK) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "could not get $r external"); @@ -1200,7 +1200,7 @@ ngx_http_js_compile(ngx_conf_t *cf, ngx_ ngx_str_set(&name, "response"); - rc = njs_external_get(vm, &js->args[0], &name, &js->args[1]); + rc = njs_vm_external(vm, &js->args[0], &name, &js->args[1]); if (rc != NXT_OK) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "could not get $r.response external"); diff -r 74246210aa9d -r a3e7ebdf9fa7 njs/njs_extern.c --- a/njs/njs_extern.c Thu Jul 14 19:24:51 2016 +0300 +++ b/njs/njs_extern.c Fri Jul 15 15:50:13 2016 +0300 @@ -51,7 +51,7 @@ const nxt_lvlhsh_proto_t njs_extern_has nxt_int_t -njs_add_external(nxt_lvlhsh_t *hash, nxt_mem_cache_pool_t *mcp, +njs_vm_external_add(nxt_lvlhsh_t *hash, nxt_mem_cache_pool_t *mcp, uintptr_t object, njs_external_t *external, nxt_uint_t n) { nxt_int_t ret; @@ -111,7 +111,7 @@ njs_add_external(nxt_lvlhsh_t *hash, nxt } if (external->properties != NULL) { - ret = njs_add_external(&ext->hash, mcp, object, + ret = njs_vm_external_add(&ext->hash, mcp, object, external->properties, external->nproperties); if (nxt_slow_path(ret != NXT_OK)) { return ret; @@ -128,7 +128,7 @@ njs_add_external(nxt_lvlhsh_t *hash, nxt nxt_int_t -njs_external_get(njs_vm_t *vm, njs_opaque_value_t *obj, nxt_str_t *property, +njs_vm_external(njs_vm_t *vm, njs_opaque_value_t *obj, nxt_str_t *property, njs_opaque_value_t *value) { uint32_t (*key_hash)(const void *, size_t); diff -r 74246210aa9d -r a3e7ebdf9fa7 njs/njs_variable.c --- a/njs/njs_variable.c Thu Jul 14 19:24:51 2016 +0300 +++ b/njs/njs_variable.c Fri Jul 15 15:50:13 2016 +0300 @@ -136,8 +136,8 @@ njs_vm_function(njs_vm_t *vm, nxt_str_t var = lhq.value; - value = (njs_value_t *) ((u_char *) vm->scopes[NJS_SCOPE_GLOBAL] - + njs_offset(var->index)); + value = (njs_value_t *) ((u_char *) vm->global_scope + + njs_offset(var->index) - NJS_INDEX_GLOBAL_OFFSET); return value->data.u.function; } diff -r 74246210aa9d -r a3e7ebdf9fa7 njs/njscript.c --- a/njs/njscript.c Thu Jul 14 19:24:51 2016 +0300 +++ b/njs/njscript.c Fri Jul 15 15:50:13 2016 +0300 @@ -280,6 +280,7 @@ njs_vm_clone(njs_vm_t *vm, nxt_mem_cache nvm->variables_hash = vm->variables_hash; nvm->values_hash = vm->values_hash; + nvm->externals_hash = vm->externals_hash; nvm->retval = njs_value_void; nvm->current = vm->current; diff -r 74246210aa9d -r a3e7ebdf9fa7 njs/njscript.h --- a/njs/njscript.h Thu Jul 14 19:24:51 2016 +0300 +++ b/njs/njscript.h Fri Jul 15 15:50:13 2016 +0300 @@ -73,10 +73,10 @@ struct njs_external_s { #define NJS_DONE NXT_DONE -NXT_EXPORT nxt_int_t njs_add_external(nxt_lvlhsh_t *hash, +NXT_EXPORT nxt_int_t njs_vm_external_add(nxt_lvlhsh_t *hash, nxt_mem_cache_pool_t *mcp, uintptr_t object, njs_external_t *external, nxt_uint_t n); -NXT_EXPORT nxt_int_t njs_external_get(njs_vm_t *vm, njs_opaque_value_t *object, +NXT_EXPORT nxt_int_t njs_vm_external(njs_vm_t *vm, njs_opaque_value_t *object, nxt_str_t *property, njs_opaque_value_t *value); NXT_EXPORT njs_vm_t *njs_vm_create(nxt_mem_cache_pool_t *mcp, diff -r 74246210aa9d -r a3e7ebdf9fa7 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Thu Jul 14 19:24:51 2016 +0300 +++ b/njs/test/njs_unit_test.c Fri Jul 15 15:50:13 2016 +0300 @@ -4811,8 +4811,8 @@ njs_unit_test_externals(nxt_lvlhsh_t *ex { nxt_lvlhsh_init(externals); - return njs_add_external(externals, mcp, 0, nxt_test_external, - nxt_nitems(nxt_test_external)); + return njs_vm_external_add(externals, mcp, 0, nxt_test_external, + nxt_nitems(nxt_test_external)); } @@ -4937,7 +4937,7 @@ njs_unit_test(nxt_bool_t disassemble) r_name.len = 2; r_name.data = (u_char *) "$r"; - ret = njs_external_get(vm, NULL, &r_name, &value); + ret = njs_vm_external(nvm, NULL, &r_name, &value); if (ret != NXT_OK) { return NXT_ERROR; } From pankajitbhu at gmail.com Mon Jul 18 06:58:34 2016 From: pankajitbhu at gmail.com (Pankaj Chaudhary) Date: Mon, 18 Jul 2016 12:28:34 +0530 Subject: while building own nginx module error to find user defined header file Message-ID: Hi All, I have written my own nginx module and i have my user defined header files but while building i am getting error header file not found. my module will act as a filter. Please help me. Regards, Pankaj -------------- next part -------------- An HTML attachment was scrubbed... URL: From mdounin at mdounin.ru Mon Jul 18 13:09:29 2016 From: mdounin at mdounin.ru (Maxim Dounin) Date: Mon, 18 Jul 2016 16:09:29 +0300 Subject: while building own nginx module error to find user defined header file In-Reply-To: References: Message-ID: <20160718130929.GA57459@mdounin.ru> Hello! On Mon, Jul 18, 2016 at 12:28:34PM +0530, Pankaj Chaudhary wrote: > I have written my own nginx module and i have my user defined header files > but while building i am getting error header file not found. If you are using header files in your module, you have to add your module directory to the list of include paths. Assuming you are using auto/module script to configure your module, you should do something like this in your module ./config script: ngx_module_type=HTTP_AUX_FILTER ngx_module_name=ngx_http_example_filter_module ngx_module_incs=$ngx_addon_dir ngx_module_deps= ngx_module_srcs=$ngx_addon_dir/ngx_http_example_filter_module.c ngx_module_libs= . auto/module -- Maxim Dounin http://nginx.org/ From linnading1989 at gmail.com Mon Jul 18 17:59:06 2016 From: linnading1989 at gmail.com (Linna.Ding) Date: Mon, 18 Jul 2016 13:59:06 -0400 Subject: Nginx map value not matched when used as input of another map Message-ID: I just tested with a single map "cache_key", and the rate limiting doesn't work, the $cache_key was logged as empty string. But changing $upstream_cache_status to non-upstream variables like $remote_addr and adding an IP match value will make the rate limiting work. The zone I defined like so: limit_req_zone $cache_key zone=cache_host:1m rate=1r/m; map $upstream_cache_status $cache_key { HIT $host; EXPIRED $host; - $host; default ""; } And I use it in one of my server chunk with limit_req directive below: limit_req zone=cache_host busrt=1; Since I am using Nginx as reverse proxy, is this because $upstream_cache_status value is set after the request is sent to origin server and got the response, while $cache_key is used in rate limit zone which checked before the request was sent to origin server? If so, is there a recommended way to implement rate limiting only for request that MISS cache? Thanks! -------------- next part -------------- An HTML attachment was scrubbed... URL: From mdounin at mdounin.ru Mon Jul 18 18:10:01 2016 From: mdounin at mdounin.ru (Maxim Dounin) Date: Mon, 18 Jul 2016 21:10:01 +0300 Subject: Nginx map value not matched when used as input of another map In-Reply-To: References: Message-ID: <20160718181001.GH57459@mdounin.ru> Hello! On Mon, Jul 18, 2016 at 01:59:06PM -0400, Linna.Ding wrote: > I just tested with a single map "cache_key", and the rate limiting doesn't > work, the $cache_key was logged as empty string. But changing > $upstream_cache_status to non-upstream variables like $remote_addr and > adding an IP match value will make the rate limiting work. > The zone I defined like so: > limit_req_zone $cache_key zone=cache_host:1m rate=1r/m; > map $upstream_cache_status $cache_key { > HIT $host; > EXPIRED $host; > - $host; > default ""; > } > And I use it in one of my server chunk with limit_req directive below: > limit_req zone=cache_host busrt=1; > > Since I am using Nginx as reverse proxy, is this because > $upstream_cache_status value is set after the request is sent to origin > server and got the response, while $cache_key is used in rate limit zone > which checked before the request was sent to origin server? > If so, is there a recommended way to implement rate limiting only for > request that MISS cache? This doesn't looks like a development-related question. Please use the nginx@ mailing list instead, see http://nginx.org/en/support.html. -- Maxim Dounin http://nginx.org/ From mikesir87 at gmail.com Mon Jul 18 19:58:13 2016 From: mikesir87 at gmail.com (Michael Irwin) Date: Mon, 18 Jul 2016 19:58:13 +0000 Subject: Proxy Protocol Support Message-ID: I saw with 1.11.0 that support was added to support a variable named proxy_protocol_port. Looking at the documentation, I see it makes the client port (from the protocol) available. But, it looks like the proxy port is not being made available. I was working on a patch to submit, but figured I'd seek some input first, as I'm concerned that there will be some naming confusion. proxy_protocol_port = client port (what it is now) and proxy_protocol_proxy_port is the new proxy port? If I could start over, I'd say _port is the proxy port and _client_port is the client port, but that's a breaking change. Still go with _proxy_port to differentiate the two? (ps... if anyone else wants to do the quick patch, I'm happy to pass it off too ;) ) Thoughts? -- Michael Irwin -------------- next part -------------- An HTML attachment was scrubbed... URL: From mdounin at mdounin.ru Tue Jul 19 12:46:44 2016 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 19 Jul 2016 15:46:44 +0300 Subject: Proxy Protocol Support In-Reply-To: References: Message-ID: <20160719124644.GJ57459@mdounin.ru> Hello! On Mon, Jul 18, 2016 at 07:58:13PM +0000, Michael Irwin wrote: > I saw with 1.11.0 that support was added to support a variable named > proxy_protocol_port. Looking at the documentation, I see it makes the > client port (from the protocol) available. But, it looks like the proxy > port is not being made available. > > I was working on a patch to submit, but figured I'd seek some input first, > as I'm concerned that there will be some naming confusion. > proxy_protocol_port = client port (what it is now) and > proxy_protocol_proxy_port is the new proxy port? If I could start over, > I'd say _port is the proxy port and _client_port is the client port, but > that's a breaking change. Still go with _proxy_port to differentiate the > two? > > (ps... if anyone else wants to do the quick patch, I'm happy to pass it off > too ;) ) > > Thoughts? PROXY protocol contains source and destination addresses and ports. Neither destination address nor destination port are provided in nginx variables. If you want to add some, consider using $proxy_protocol_server_addr and $proxy_protocol_server_port, to be in line with $server_addr and $server_port variables. -- Maxim Dounin http://nginx.org/ From whissi at whissi.de Tue Jul 19 13:48:16 2016 From: whissi at whissi.de (Thomas Deutschmann) Date: Tue, 19 Jul 2016 15:48:16 +0200 Subject: Should nginx' default shipped fastcgi_param file updated to mitigate httpoxy? Message-ID: -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA512 Hi, I am proxy maintaining the nginx package on Gentoo. Regarding the recent "httpoxy" problem (you already published a blog posting [1] with instructions how to mitigate the problem) we are unsure if we should update our package to ship your mitigation per default, i.e. altering your "fastcgi_param" file and add > fastcgi_param HTTP_PROXY ""; This would protect default configurations. However some setups might require a proxy which could break when fastcgi_param file will be sourced after user's configuration. - From my point of view this is a user education problem: If they know what they are doing they won't have to do anything: They should be fine already or at least will set their required values *after* sourcing the default fastcgi_param file. For Gentoo we would use our elog and/or news system to tell the user about the changes. However we want to know if you, upstream, are going to change the default shipped fastcgi_param file (don't forget the .conf file) with the next upcoming release to include a "safer" default configuration as well or if there are reasons not to ship such a default and maybe you recommend us also to do nothing. Thanks. [1] https://www.nginx.com/blog/mitigating-the-httpoxy-vulnerability-with-ngi nx/ - -- Regards, Thomas -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.1 iQJ8BAEBCgBmBQJXji+LXxSAAAAAAC4AKGlzc3Vlci1mcHJAbm90YXRpb25zLm9w ZW5wZ3AuZmlmdGhob3JzZW1hbi5uZXQzM0M1ODQ4MkM0MDIyOTJEMkUzQzVDMDY5 NzA5RjkwQzNDOTZGRkM4AAoJEJcJ+Qw8lv/IIFMQAIl3gyTbLRVnX22RPrQcV/Be NI5WSp+hd+D2DMSxunf5Rljedt2Yw7ODCtq3GCF3bC0xDMuMwsyHzxlUtvhUYqz1 PYz8n/b/76ba/rN0mMu3HWiCBbvnJ+gFd0QMNL8vP4ucabqYyPteTYN7ksSROh6C hDej3VFDYYQsTHLhG8E8q4l9FcxEuOFnOK4H1B1aR9ti+juwysALbXa8rHx5JgYU mgYbJvajB59gf6ks5VhN3HKHxZLdpvL8fPHwQw+pQIEpKRG5Qe11bOzRmsqQ7zvo UagfvkIUHtBMnj5HH9mHGHY/Y1CVVWLwD81mC1kDpvJzlaKBhWPGm4a1g4Lnm+B4 sm5xQXF2s21mdp+PTB2qn6AujC5Lh4WPcHM0ZhJ4HTo15L0Z/4sbt/dh6s99I6Va 1G1YXDzZSUB9N777YYjIslNKXGFHM1oBx2UsChVo40PnvmQidZKJ1z9n0cOaiUVd IRM1DAL6FCNCrPpPhgRKVs+VfJoNwCndD47zLhhy2xGvJUbUr9i3u6pF9THf3Nhp LCaIQunB1r01QY0aUJT3WK6NfFcdyXy8SCtrTT8PWa/cNLCZ0yCe4DYLczgnby9F dyTHXg8BjP/o+kQHl4e+Z7tEuAmmRgQ/BUehWyJppp/VuCVfILBfthquO++ItGCP Z4yj87/isys7QInSO7I1 =H+YL -----END PGP SIGNATURE----- From mdounin at mdounin.ru Tue Jul 19 14:16:55 2016 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 19 Jul 2016 17:16:55 +0300 Subject: Should nginx' default shipped fastcgi_param file updated to mitigate httpoxy? In-Reply-To: References: Message-ID: <20160719141655.GK57459@mdounin.ru> Hello! On Tue, Jul 19, 2016 at 03:48:16PM +0200, Thomas Deutschmann wrote: > -----BEGIN PGP SIGNED MESSAGE----- > Hash: SHA512 > > Hi, > > I am proxy maintaining the nginx package on Gentoo. > > Regarding the recent "httpoxy" problem (you already published a blog > posting [1] with instructions how to mitigate the problem) we are > unsure if we should update our package to ship your mitigation per > default, i.e. altering your "fastcgi_param" file and add > > > fastcgi_param HTTP_PROXY ""; > > This would protect default configurations. However some setups might > require a proxy which could break when fastcgi_param file will be > sourced after user's configuration. > > > - From my point of view this is a user education problem: If they know > what they are doing they won't have to do anything: They should be > fine already or at least will set their required values *after* > sourcing the default fastcgi_param file. > > For Gentoo we would use our elog and/or news system to tell the user > about the changes. > > > However we want to know if you, upstream, are going to change the > default shipped fastcgi_param file (don't forget the .conf file) with > the next upcoming release to include a "safer" default configuration > as well or if there are reasons not to ship such a default and maybe > you recommend us also to do nothing. I don't think that the default should be changed. The problem is about improperly using the HTTP_PROXY environment variable in CGI[-like] contexts. And this is what should be fixed. Much like any other uses of HTTP_* environment variables. While filtering particular headers can be effectively used as a mitigation before all the affected uses are fixed, it doesn't looks like a good long-term solution. -- Maxim Dounin http://nginx.org/ From vbart at nginx.com Tue Jul 19 17:26:26 2016 From: vbart at nginx.com (Valentin Bartenev) Date: Tue, 19 Jul 2016 17:26:26 +0000 Subject: [nginx] HTTP/2: always send GOAWAY while worker is shutting down. Message-ID: details: http://hg.nginx.org/nginx/rev/ea284434db0f branches: changeset: 6636:ea284434db0f user: Valentin Bartenev date: Tue Jul 19 20:22:44 2016 +0300 description: HTTP/2: always send GOAWAY while worker is shutting down. Previously, if the worker process exited, GOAWAY was sent to connections in idle state, but connections with active streams were closed without GOAWAY. diffstat: src/http/v2/ngx_http_v2.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diffs (12 lines): diff -r 6acaa638fa07 -r ea284434db0f src/http/v2/ngx_http_v2.c --- a/src/http/v2/ngx_http_v2.c Fri Jul 15 15:18:57 2016 +0300 +++ b/src/http/v2/ngx_http_v2.c Tue Jul 19 20:22:44 2016 +0300 @@ -615,7 +615,7 @@ ngx_http_v2_handle_connection(ngx_http_v } if (ngx_terminate || ngx_exiting) { - ngx_http_close_connection(c); + ngx_http_v2_finalize_connection(h2c, NGX_HTTP_V2_NO_ERROR); return; } From vbart at nginx.com Tue Jul 19 17:26:29 2016 From: vbart at nginx.com (Valentin Bartenev) Date: Tue, 19 Jul 2016 17:26:29 +0000 Subject: [nginx] HTTP/2: prevented output of the HEADERS frame for canceled streams. Message-ID: details: http://hg.nginx.org/nginx/rev/699e409a3e0c branches: changeset: 6637:699e409a3e0c user: Valentin Bartenev date: Tue Jul 19 20:22:44 2016 +0300 description: HTTP/2: prevented output of the HEADERS frame for canceled streams. It's useless to generate HEADERS if the stream has been canceled already. diffstat: src/http/v2/ngx_http_v2_filter_module.c | 8 ++++++-- 1 files changed, 6 insertions(+), 2 deletions(-) diffs (25 lines): diff -r ea284434db0f -r 699e409a3e0c src/http/v2/ngx_http_v2_filter_module.c --- a/src/http/v2/ngx_http_v2_filter_module.c Tue Jul 19 20:22:44 2016 +0300 +++ b/src/http/v2/ngx_http_v2_filter_module.c Tue Jul 19 20:22:44 2016 +0300 @@ -165,6 +165,12 @@ ngx_http_v2_header_filter(ngx_http_reque return NGX_OK; } + fc = r->connection; + + if (fc->error) { + return NGX_ERROR; + } + if (r->method == NGX_HTTP_HEAD) { r->header_only = 1; } @@ -255,8 +261,6 @@ ngx_http_v2_header_filter(ngx_http_reque len += 1 + ngx_http_v2_literal_size("Wed, 31 Dec 1986 18:00:00 GMT"); } - fc = r->connection; - if (r->headers_out.location && r->headers_out.location->value.len) { if (r->headers_out.location->value.data[0] == '/') { From vbart at nginx.com Tue Jul 19 17:26:31 2016 From: vbart at nginx.com (Valentin Bartenev) Date: Tue, 19 Jul 2016 17:26:31 +0000 Subject: [nginx] HTTP/2: always handle streams in error state. Message-ID: details: http://hg.nginx.org/nginx/rev/a2b310a8b2af branches: changeset: 6638:a2b310a8b2af user: Valentin Bartenev date: Tue Jul 19 20:22:44 2016 +0300 description: HTTP/2: always handle streams in error state. Previously, a stream could be closed by timeout if it was canceled while its send window was exhausted. diffstat: src/http/v2/ngx_http_v2_filter_module.c | 14 ++++++++------ 1 files changed, 8 insertions(+), 6 deletions(-) diffs (30 lines): diff -r 699e409a3e0c -r a2b310a8b2af src/http/v2/ngx_http_v2_filter_module.c --- a/src/http/v2/ngx_http_v2_filter_module.c Tue Jul 19 20:22:44 2016 +0300 +++ b/src/http/v2/ngx_http_v2_filter_module.c Tue Jul 19 20:22:44 2016 +0300 @@ -1294,18 +1294,20 @@ static ngx_inline void ngx_http_v2_handle_stream(ngx_http_v2_connection_t *h2c, ngx_http_v2_stream_t *stream) { - ngx_event_t *wev; + ngx_connection_t *fc; - if (stream->handled || stream->blocked || stream->exhausted) { + if (stream->handled || stream->blocked) { return; } - wev = stream->request->connection->write; + fc = stream->request->connection; - if (!wev->delayed) { - stream->handled = 1; - ngx_queue_insert_tail(&h2c->posted, &stream->queue); + if (!fc->error && (stream->exhausted || fc->write->delayed)) { + return; } + + stream->handled = 1; + ngx_queue_insert_tail(&h2c->posted, &stream->queue); } From vbart at nginx.com Tue Jul 19 17:37:17 2016 From: vbart at nginx.com (Valentin Bartenev) Date: Tue, 19 Jul 2016 17:37:17 +0000 Subject: [nginx] HTTP/2: avoid sending output queue if there's nothing to send. Message-ID: details: http://hg.nginx.org/nginx/rev/82efcedb310b branches: changeset: 6639:82efcedb310b user: Valentin Bartenev date: Tue Jul 19 20:30:21 2016 +0300 description: HTTP/2: avoid sending output queue if there's nothing to send. Particularly this fixes alerts on OS X and NetBSD systems when HTTP/2 is configured over plain TCP sockets. On these systems calling writev() with no data leads to EINVAL errors being logged as "writev() failed (22: Invalid argument) while processing HTTP/2 connection". diffstat: src/http/v2/ngx_http_v2.c | 10 ++++++++++ 1 files changed, 10 insertions(+), 0 deletions(-) diffs (20 lines): diff -r a2b310a8b2af -r 82efcedb310b src/http/v2/ngx_http_v2.c --- a/src/http/v2/ngx_http_v2.c Tue Jul 19 20:22:44 2016 +0300 +++ b/src/http/v2/ngx_http_v2.c Tue Jul 19 20:30:21 2016 +0300 @@ -410,6 +410,16 @@ ngx_http_v2_write_handler(ngx_event_t *w ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http2 write handler"); + if (h2c->last_out == NULL && !c->buffered) { + + if (wev->timer_set) { + ngx_del_timer(wev); + } + + ngx_http_v2_handle_connection(h2c); + return; + } + h2c->blocked = 1; rc = ngx_http_v2_send_output_queue(h2c); From vbart at nginx.com Tue Jul 19 17:37:19 2016 From: vbart at nginx.com (Valentin Bartenev) Date: Tue, 19 Jul 2016 17:37:19 +0000 Subject: [nginx] HTTP/2: fixed send timer handling. Message-ID: details: http://hg.nginx.org/nginx/rev/e78eca6bfaf0 branches: changeset: 6640:e78eca6bfaf0 user: Valentin Bartenev date: Tue Jul 19 20:31:09 2016 +0300 description: HTTP/2: fixed send timer handling. Checking for return value of c->send_chain() isn't sufficient since there are data can be left in the SSL buffer. Now the wew->ready flag is used instead. In particular, this fixed a connection leak in cases when all streams were closed, but there's still some data to be sent in the SSL buffer and the client forgot about the connection. diffstat: src/http/v2/ngx_http_v2.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diffs (12 lines): diff -r 82efcedb310b -r e78eca6bfaf0 src/http/v2/ngx_http_v2.c --- a/src/http/v2/ngx_http_v2.c Tue Jul 19 20:30:21 2016 +0300 +++ b/src/http/v2/ngx_http_v2.c Tue Jul 19 20:31:09 2016 +0300 @@ -549,7 +549,7 @@ ngx_http_v2_send_output_queue(ngx_http_v c->tcp_nodelay = NGX_TCP_NODELAY_SET; } - if (cl) { + if (!wev->ready) { ngx_add_timer(wev, clcf->send_timeout); } else { From vbart at nginx.com Tue Jul 19 17:37:22 2016 From: vbart at nginx.com (Valentin Bartenev) Date: Tue, 19 Jul 2016 17:37:22 +0000 Subject: [nginx] HTTP/2: refactored ngx_http_v2_send_output_queue(). Message-ID: details: http://hg.nginx.org/nginx/rev/b5d1c17181ca branches: changeset: 6641:b5d1c17181ca user: Valentin Bartenev date: Tue Jul 19 20:34:02 2016 +0300 description: HTTP/2: refactored ngx_http_v2_send_output_queue(). Now it returns NGX_AGAIN if there's still data to be sent. diffstat: src/http/v2/ngx_http_v2.c | 20 ++++++++++---------- 1 files changed, 10 insertions(+), 10 deletions(-) diffs (44 lines): diff -r e78eca6bfaf0 -r b5d1c17181ca src/http/v2/ngx_http_v2.c --- a/src/http/v2/ngx_http_v2.c Tue Jul 19 20:31:09 2016 +0300 +++ b/src/http/v2/ngx_http_v2.c Tue Jul 19 20:34:02 2016 +0300 @@ -478,7 +478,7 @@ ngx_http_v2_send_output_queue(ngx_http_v wev = c->write; if (!wev->ready) { - return NGX_OK; + return NGX_AGAIN; } cl = NULL; @@ -549,15 +549,6 @@ ngx_http_v2_send_output_queue(ngx_http_v c->tcp_nodelay = NGX_TCP_NODELAY_SET; } - if (!wev->ready) { - ngx_add_timer(wev, clcf->send_timeout); - - } else { - if (wev->timer_set) { - ngx_del_timer(wev); - } - } - for ( /* void */ ; out; out = fn) { fn = out->next; @@ -582,6 +573,15 @@ ngx_http_v2_send_output_queue(ngx_http_v h2c->last_out = frame; + if (!wev->ready) { + ngx_add_timer(wev, clcf->send_timeout); + return NGX_AGAIN; + } + + if (wev->timer_set) { + ngx_del_timer(wev); + } + return NGX_OK; error: From vbart at nginx.com Tue Jul 19 17:37:24 2016 From: vbart at nginx.com (Valentin Bartenev) Date: Tue, 19 Jul 2016 17:37:24 +0000 Subject: [nginx] HTTP/2: flushing of the SSL buffer in transition to the idle state. Message-ID: details: http://hg.nginx.org/nginx/rev/72282dd5884e branches: changeset: 6642:72282dd5884e user: Valentin Bartenev date: Tue Jul 19 20:34:17 2016 +0300 description: HTTP/2: flushing of the SSL buffer in transition to the idle state. It fixes potential connection leak if some unsent data was left in the SSL buffer. Particularly, that could happen when a client canceled the stream after the HEADERS frame has already been created. In this case no other frames might be produced and the HEADERS frame alone didn't flush the buffer. diffstat: src/http/v2/ngx_http_v2.c | 20 ++++++++++++++++++-- 1 files changed, 18 insertions(+), 2 deletions(-) diffs (37 lines): diff -r b5d1c17181ca -r 72282dd5884e src/http/v2/ngx_http_v2.c --- a/src/http/v2/ngx_http_v2.c Tue Jul 19 20:34:02 2016 +0300 +++ b/src/http/v2/ngx_http_v2.c Tue Jul 19 20:34:17 2016 +0300 @@ -599,7 +599,8 @@ error: static void ngx_http_v2_handle_connection(ngx_http_v2_connection_t *h2c) { - ngx_connection_t *c; + ngx_int_t rc; + ngx_connection_t *c; ngx_http_v2_srv_conf_t *h2scf; if (h2c->last_out || h2c->processing) { @@ -614,7 +615,22 @@ ngx_http_v2_handle_connection(ngx_http_v } if (c->buffered) { - return; + h2c->blocked = 1; + + rc = ngx_http_v2_send_output_queue(h2c); + + h2c->blocked = 0; + + if (rc == NGX_ERROR) { + ngx_http_close_connection(c); + return; + } + + if (rc == NGX_AGAIN) { + return; + } + + /* rc == NGX_OK */ } h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, From pankajitbhu at gmail.com Wed Jul 20 09:03:28 2016 From: pankajitbhu at gmail.com (Pankaj Chaudhary) Date: Wed, 20 Jul 2016 14:33:28 +0530 Subject: error nginx: [emerg] dlopen() "/usr/local/nginx/modules/ds_http_module.so" failed (/usr/local/nginx/modules/ds_http_module.so: undefined symbol: ds_http_module Message-ID: Hi All, I am getting error below error for own written module ds_http_module. nginx: [emerg] dlopen() "/usr/local/nginx/modules/ds_http_module.so" failed (/usr/local/nginx/modules/ds_http_module.so: undefined symbol: ds_http_module Please let me know what could be the reason of this error. Regards, Pankaj -------------- next part -------------- An HTML attachment was scrubbed... URL: From pankajitbhu at gmail.com Wed Jul 20 14:12:58 2016 From: pankajitbhu at gmail.com (Pankaj Chaudhary) Date: Wed, 20 Jul 2016 19:42:58 +0530 Subject: error while building own nginx module Message-ID: Hi i have written own nginx module and i have many header ,src and makefiles files . my nginx module folder structure look like below /product/src/nginx/ngx_http_auth_module.cpp /product/src/nginx/Makefile /product/src/nginx/config(nginx config file) /product/src/common/.cpp files /product/lib/.so files /product/src/utility/.c and .h files i have written my config file like this *************************************************************** ngx_module_type=HTTP_AUX_FILTER_MODULES ngx_module_name=ngx_http_auth_module ngx_module_incs=$ngx_addon_dir ngx_module_deps= ngx_module_srcs=$ngx_addon_dir/ngx_http_auth_module.cpp \ $ngx_addon_dir/Makefile ngx_module_libs= . auto/module *************************************************************************** code build successfully and generated ngx_http_auth_module.so file but not correctly since i am getting below error while loading in nginx.conf file. nginx: [emerg] dlopen() "/usr/local/nginx/modules/ngx_http_auth_module.so" failed (/usr/local/nginx/modules/ngx_http_auth_module.so: undefined symbol: ngx_http_auth_module Please let me know correct way to do. Thanks & Regards, Pankaj Chaudhary -------------- next part -------------- An HTML attachment was scrubbed... URL: From arut at nginx.com Wed Jul 20 16:39:27 2016 From: arut at nginx.com (Roman Arutyunyan) Date: Wed, 20 Jul 2016 16:39:27 +0000 Subject: [njs] New http js module syntax. Message-ID: details: http://hg.nginx.org/njs/rev/252409c490bc branches: changeset: 123:252409c490bc user: Roman Arutyunyan date: Wed Jul 20 18:20:13 2016 +0300 description: New http js module syntax. - the js_include directive is introduced - all js code is now located in a separate file diffstat: nginx/ngx_http_js_module.c | 523 +++++++++++++++++++++++++++++++------------- nxt/nxt_stub.h | 14 + 2 files changed, 377 insertions(+), 160 deletions(-) diffs (740 lines): diff -r a3e7ebdf9fa7 -r 252409c490bc nginx/ngx_http_js_module.c --- a/nginx/ngx_http_js_module.c Fri Jul 15 15:50:13 2016 +0300 +++ b/nginx/ngx_http_js_module.c Wed Jul 20 18:20:13 2016 +0300 @@ -12,9 +12,14 @@ #include #include #include +#include +#include #include #include + #include +#include +#include #define NGX_HTTP_JS_MCP_CLUSTER_SIZE (2 * ngx_pagesize) @@ -33,14 +38,15 @@ typedef struct { njs_vm_t *vm; - njs_function_t *function; njs_opaque_value_t args[2]; -} ngx_http_js_ctx_t; + ngx_str_t content; +} ngx_http_js_loc_conf_t; typedef struct { - ngx_http_js_ctx_t js; -} ngx_http_js_loc_conf_t; + njs_vm_t *vm; + njs_opaque_value_t *args; +} ngx_http_js_ctx_t; typedef struct { @@ -52,8 +58,7 @@ typedef struct { static ngx_int_t ngx_http_js_handler(ngx_http_request_t *r); static ngx_int_t ngx_http_js_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); -static ngx_int_t ngx_http_js_vm_run(ngx_http_request_t *r, - ngx_http_js_ctx_t *js, nxt_str_t *value); +static ngx_int_t ngx_http_js_init_vm(ngx_http_request_t *r); static void ngx_http_js_cleanup_mem_cache_pool(void *data); static void *ngx_http_js_alloc(void *mem, size_t size); @@ -91,6 +96,8 @@ static njs_ret_t ngx_http_js_ext_send(nj nxt_uint_t nargs, njs_index_t unused); static njs_ret_t ngx_http_js_ext_finish(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused); +static njs_ret_t ngx_http_js_ext_log(njs_vm_t *vm, njs_value_t *args, + nxt_uint_t nargs, njs_index_t unused); static njs_ret_t ngx_http_js_ext_get_http_version(njs_vm_t *vm, njs_value_t *value, void *obj, uintptr_t data); static njs_ret_t ngx_http_js_ext_get_remote_address(njs_vm_t *vm, @@ -105,11 +112,14 @@ static njs_ret_t ngx_http_js_ext_foreach void *next); static njs_ret_t ngx_http_js_ext_next_arg(njs_vm_t *vm, njs_value_t *value, void *obj, void *next); +static njs_ret_t ngx_http_js_ext_get_variable(njs_vm_t *vm, njs_value_t *value, + void *obj, uintptr_t data); -static char *ngx_http_js_run(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static char *ngx_http_js_include(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); static char *ngx_http_js_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); -static char *ngx_http_js_compile(ngx_conf_t *cf, ngx_http_js_ctx_t *jctx, - ngx_str_t *script); +static char *ngx_http_js_content(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); static void *ngx_http_js_create_loc_conf(ngx_conf_t *cf); static char *ngx_http_js_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child); @@ -117,20 +127,27 @@ static char *ngx_http_js_merge_loc_conf( static ngx_command_t ngx_http_js_commands[] = { - { ngx_string("js_run"), - NGX_HTTP_LOC_CONF|NGX_HTTP_LMT_CONF|NGX_CONF_TAKE1, - ngx_http_js_run, + { ngx_string("js_include"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_http_js_include, NGX_HTTP_LOC_CONF_OFFSET, 0, NULL }, { ngx_string("js_set"), - NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE2, + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2, ngx_http_js_set, NGX_HTTP_LOC_CONF_OFFSET, 0, NULL }, + { ngx_string("js_content"), + NGX_HTTP_LOC_CONF|NGX_HTTP_LMT_CONF|NGX_CONF_TAKE1, + ngx_http_js_content, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + ngx_null_command }; @@ -279,6 +296,18 @@ static njs_external_t ngx_http_js_ext_r NULL, 0 }, + { nxt_string("log"), + NJS_EXTERN_METHOD, + NULL, + 0, + NULL, + NULL, + NULL, + NULL, + NULL, + ngx_http_js_ext_log, + 0 }, + { nxt_string("uri"), NJS_EXTERN_PROPERTY, NULL, @@ -350,6 +379,18 @@ static njs_external_t ngx_http_js_ext_r ngx_http_js_ext_next_arg, NULL, 0 }, + + { nxt_string("variables"), + NJS_EXTERN_OBJECT, + NULL, + 0, + ngx_http_js_ext_get_variable, + NULL, + NULL, + NULL, + NULL, + NULL, + 0 }, }; @@ -373,20 +414,44 @@ static ngx_int_t ngx_http_js_handler(ngx_http_request_t *r) { ngx_int_t rc; + nxt_str_t name, exception; + njs_function_t *func; + ngx_http_js_ctx_t *ctx; ngx_http_js_loc_conf_t *jlcf; - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http js handler"); + rc = ngx_http_js_init_vm(r); + + if (rc == NGX_ERROR || rc == NGX_DECLINED) { + return rc; + } jlcf = ngx_http_get_module_loc_conf(r, ngx_http_js_module); - rc = ngx_http_js_vm_run(r, &jlcf->js, NULL); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http js content call \"%V\"" , &jlcf->content); - if (rc == NGX_OK) { - return rc; + ctx = ngx_http_get_module_ctx(r, ngx_http_js_module); + + name.data = jlcf->content.data; + name.len = jlcf->content.len; + + func = njs_vm_function(ctx->vm, &name); + if (func == NULL) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "js function \"%V\" not found", &jlcf->content); + return NGX_DECLINED; } - return NGX_ERROR; + if (njs_vm_call(ctx->vm, func, ctx->args, 2) != NJS_OK) { + njs_vm_exception(ctx->vm, &exception); + + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "js exception: %*s", exception.len, exception.data); + + return NGX_ERROR; + } + + return NGX_OK; } @@ -394,47 +459,92 @@ static ngx_int_t ngx_http_js_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) { - ngx_http_js_ctx_t *js = (ngx_http_js_ctx_t *) data; - - ngx_int_t rc; - nxt_str_t value; + ngx_str_t *fname = (ngx_str_t *) data; - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http js variable handler"); + ngx_int_t rc; + nxt_str_t name, value, exception; + njs_function_t *func; + ngx_http_js_ctx_t *ctx; - rc = ngx_http_js_vm_run(r, js, &value); + rc = ngx_http_js_init_vm(r); - if (rc == NXT_ERROR) { + if (rc == NGX_ERROR) { return NGX_ERROR; } - if (rc == NGX_OK) { - v->len = value.len; - v->valid = 1; - v->no_cacheable = 0; - v->not_found = 0; - v->data = value.data; - - } else { + if (rc == NGX_DECLINED) { v->not_found = 1; + return NGX_OK; } - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http js variable done"); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http js variable call \"%V\"", fname); + + ctx = ngx_http_get_module_ctx(r, ngx_http_js_module); + + name.data = fname->data; + name.len = fname->len; + + func = njs_vm_function(ctx->vm, &name); + if (func == NULL) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "js function \"%V\" not found", fname); + v->not_found = 1; + return NGX_OK; + } + + if (njs_vm_call(ctx->vm, func, ctx->args, 2) != NJS_OK) { + njs_vm_exception(ctx->vm, &exception); + + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "js exception: %*s", exception.len, exception.data); + + v->not_found = 1; + return NGX_OK; + } + + if (njs_vm_retval(ctx->vm, &value) != NJS_OK) { + return NGX_ERROR; + } + + v->len = value.len; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = value.data; return NGX_OK; } static ngx_int_t -ngx_http_js_vm_run(ngx_http_request_t *r, ngx_http_js_ctx_t *js, - nxt_str_t *value) +ngx_http_js_init_vm(ngx_http_request_t *r) { - njs_vm_t *nvm; - nxt_int_t ret; - nxt_str_t exception; - ngx_pool_cleanup_t *cln; - nxt_mem_cache_pool_t *mcp; + void **ext; + ngx_http_js_ctx_t *ctx; + ngx_pool_cleanup_t *cln; + nxt_mem_cache_pool_t *mcp; + ngx_http_js_loc_conf_t *jlcf; + + jlcf = ngx_http_get_module_loc_conf(r, ngx_http_js_module); + if (jlcf->vm == NULL) { + return NGX_DECLINED; + } + + ctx = ngx_http_get_module_ctx(r, ngx_http_js_module); + + if (ctx == NULL) { + ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_js_ctx_t)); + if (ctx == NULL) { + return NGX_ERROR; + } + + ngx_http_set_ctx(r, ctx, ngx_http_js_module); + } + + if (ctx->vm) { + return NGX_OK; + } mcp = ngx_http_js_create_mem_cache_pool(); if (mcp == NULL) { @@ -449,35 +559,19 @@ ngx_http_js_vm_run(ngx_http_request_t *r cln->handler = ngx_http_js_cleanup_mem_cache_pool; cln->data = mcp; - /* The double cast is required by GCC 4.1. */ - nvm = njs_vm_clone(js->vm, mcp, (void **) (void *) &r); - if (nvm == NULL) { + ext = ngx_palloc(r->pool, sizeof(void *)); + if (ext == NULL) { return NGX_ERROR; } - if (js->function) { - ret = njs_vm_call(nvm, js->function, js->args, 2); + *ext = r; - } else { - ret = njs_vm_run(nvm); + ctx->vm = njs_vm_clone(jlcf->vm, mcp, ext); + if (ctx->vm == NULL) { + return NGX_ERROR; } - if (ret == NJS_OK) { - - if (value != NULL) { - if (njs_vm_retval(nvm, value) != NJS_OK) { - return NGX_ERROR; - } - } - - } else { - njs_vm_exception(nvm, &exception); - - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "js exception: %*s", exception.len, exception.data); - - return NGX_DECLINED; - } + ctx->args = &jlcf->args[0]; return NGX_OK; } @@ -911,6 +1005,34 @@ ngx_http_js_ext_finish(njs_vm_t *vm, njs static njs_ret_t +ngx_http_js_ext_log(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, + njs_index_t unused) +{ + nxt_str_t msg; + ngx_connection_t *c; + ngx_log_handler_pt handler; + ngx_http_request_t *r; + + r = njs_value_data(njs_argument(args, 0)); + c = r->connection; + + if (njs_value_to_ext_string(vm, &msg, njs_argument(args, 1)) == NJS_ERROR) + { + return NJS_ERROR; + } + + handler = c->log->handler; + c->log->handler = NULL; + + ngx_log_error(NGX_LOG_INFO, c->log, 0, "js: %*s", msg.len, msg.data); + + c->log->handler = handler; + + return NJS_OK; +} + + +static njs_ret_t ngx_http_js_ext_get_http_version(njs_vm_t *vm, njs_value_t *value, void *obj, uintptr_t data) { @@ -1061,30 +1183,173 @@ ngx_http_js_ext_next_arg(njs_vm_t *vm, n } +static njs_ret_t +ngx_http_js_ext_get_variable(njs_vm_t *vm, njs_value_t *value, void *obj, + uintptr_t data) +{ + nxt_str_t *v; + ngx_str_t name; + ngx_uint_t key; + ngx_http_request_t *r; + ngx_http_variable_value_t *vv; + + r = (ngx_http_request_t *) obj; + v = (nxt_str_t *) data; + + name.data = v->data; + name.len = v->len; + + key = ngx_hash_strlow(name.data, name.data, name.len); + + vv = ngx_http_get_variable(r, &name, key); + if (vv == NULL || vv->not_found) { + return njs_string_create(vm, value, NULL, 0, 0); + } + + return njs_string_create(vm, value, vv->data, vv->len, 0); +} + + static char * -ngx_http_js_run(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +ngx_http_js_include(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_http_js_loc_conf_t *jlcf = conf; - char *ret; - ngx_str_t *value; - ngx_http_core_loc_conf_t *clcf; + size_t size; + u_char *start, *end; + ssize_t n; + ngx_fd_t fd; + ngx_str_t *value, file; + nxt_int_t rc; + nxt_str_t text, ext; + nxt_lvlhsh_t externals; + ngx_file_info_t fi; + njs_vm_shared_t *shared; + ngx_pool_cleanup_t *cln; + nxt_mem_cache_pool_t *mcp; + + if (jlcf->vm) { + return "is duplicate"; + } value = cf->args->elts; + file = value[1]; - if (jlcf->js.vm) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "duplicate js handler \"%V\"", &value[1]); + if (ngx_conf_full_name(cf->cycle, &file, 1) != NGX_OK) { return NGX_CONF_ERROR; } - ret = ngx_http_js_compile(cf, &jlcf->js, &value[1]); - if (ret != NGX_CONF_OK) { - return ret; + fd = ngx_open_file(file.data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0); + if (fd == NGX_INVALID_FILE) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno, + ngx_open_file_n " \"%s\" failed", file.data); + return NGX_CONF_ERROR; } - clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); - clcf->handler = ngx_http_js_handler; + if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_EMERG, cf->log, ngx_errno, + ngx_fd_info_n " \"%s\" failed", file.data); + return NGX_CONF_ERROR; + } + + size = ngx_file_size(&fi); + + start = ngx_pnalloc(cf->pool, size); + if (start == NULL) { + return NGX_CONF_ERROR; + } + + n = ngx_read_fd(fd, start, size); + + if (n == -1) { + ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, + ngx_read_fd_n " \"%s\" failed", file.data); + + ngx_close_file(fd); + return NGX_CONF_ERROR; + } + + if ((size_t) n != size) { + ngx_log_error(NGX_LOG_ALERT, cf->log, 0, + ngx_read_fd_n " has read only %z of %O from \"%s\"", + n, size, file.data); + + ngx_close_file(fd); + return NGX_CONF_ERROR; + } + + if (ngx_close_file(fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, + ngx_close_file_n " %s failed", file.data); + } + + end = start + size; + + mcp = ngx_http_js_create_mem_cache_pool(); + if (mcp == NULL) { + return NGX_CONF_ERROR; + } + + cln = ngx_pool_cleanup_add(cf->pool, 0); + if (cln == NULL) { + return NULL; + } + + cln->handler = ngx_http_js_cleanup_mem_cache_pool; + cln->data = mcp; + + shared = NULL; + + nxt_lvlhsh_init(&externals); + + if (njs_vm_external_add(&externals, mcp, 0, ngx_http_js_externals, + nxt_nitems(ngx_http_js_externals)) + != NJS_OK) + { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "could not add js externals"); + return NGX_CONF_ERROR; + } + + jlcf->vm = njs_vm_create(mcp, &shared, &externals); + if (jlcf->vm == NULL) { + return NGX_CONF_ERROR; + } + + rc = njs_vm_compile(jlcf->vm, &start, end, NULL); + + if (rc != NJS_OK) { + njs_vm_exception(jlcf->vm, &text); + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "%*s, included", + text.len, text.data); + return NGX_CONF_ERROR; + } + + if (start != end) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "extra characters in js script: \"%*s\", included", + end - start, start); + return NGX_CONF_ERROR; + } + + nxt_str_set(&ext, "$r"); + + if (njs_vm_external(jlcf->vm, NULL, &ext, &jlcf->args[0]) != NJS_OK) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "js external \"%*s\" not found", ext.len, ext.data); + return NGX_CONF_ERROR; + } + + nxt_str_set(&ext, "response"); + + rc = njs_vm_external(jlcf->vm, &jlcf->args[0], &ext, &jlcf->args[1]); + if (rc != NXT_OK) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "js external \"$r.%*s\" not found", + ext.len, ext.data); + return NGX_CONF_ERROR; + } return NGX_CONF_OK; } @@ -1093,9 +1358,7 @@ ngx_http_js_run(ngx_conf_t *cf, ngx_comm static char * ngx_http_js_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { - char *ret; - ngx_str_t *value; - ngx_http_js_ctx_t *js; + ngx_str_t *value, *fname; ngx_http_variable_t *v; value = cf->args->elts; @@ -1114,99 +1377,37 @@ ngx_http_js_set(ngx_conf_t *cf, ngx_comm return NGX_CONF_ERROR; } - js = ngx_palloc(cf->pool, sizeof(ngx_http_js_ctx_t)); - if (js == NULL) { + fname = ngx_palloc(cf->pool, sizeof(ngx_str_t)); + if (fname == NULL) { return NGX_CONF_ERROR; } - ret = ngx_http_js_compile(cf, js, &value[2]); - if (ret != NGX_CONF_OK) { - return ret; - } + *fname = value[2]; v->get_handler = ngx_http_js_variable; - v->data = (uintptr_t) js; + v->data = (uintptr_t) fname; return NGX_CONF_OK; } static char * -ngx_http_js_compile(ngx_conf_t *cf, ngx_http_js_ctx_t *js, ngx_str_t *script) +ngx_http_js_content(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { - u_char *start, *end; - nxt_int_t rc; - nxt_str_t s, name; - njs_vm_t *vm; - nxt_lvlhsh_t externals; - njs_function_t *function; - njs_vm_shared_t *shared; - nxt_mem_cache_pool_t *mcp; + ngx_http_js_loc_conf_t *jlcf = conf; - mcp = ngx_http_js_create_mem_cache_pool(); - if (mcp == NULL) { - return NGX_CONF_ERROR; - } - - shared = NULL; - - nxt_lvlhsh_init(&externals); + ngx_str_t *value; + ngx_http_core_loc_conf_t *clcf; - if (njs_vm_external_add(&externals, mcp, 0, ngx_http_js_externals, - nxt_nitems(ngx_http_js_externals)) - != NJS_OK) - { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "could not add js externals"); - return NGX_CONF_ERROR; - } - - vm = njs_vm_create(mcp, &shared, &externals); - if (vm == NULL) { - return NGX_CONF_ERROR; + if (jlcf->content.data) { + return "is duplicate"; } - start = script->data; - end = start + script->len; - - rc = njs_vm_compile(vm, &start, end, &function); - - if (rc != NJS_OK) { - njs_vm_exception(vm, &s); - - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "js compilation error: \"%*s\"", s.len, s.data); - return NGX_CONF_ERROR; - } - - if (start != end) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "extra characters in js script: \"%*s\"", - end - start, start); - return NGX_CONF_ERROR; - } + value = cf->args->elts; + jlcf->content = value[1]; - js->vm = vm; - js->function = function; - - if (function) { - ngx_str_set(&name, "$r"); - - rc = njs_vm_external(vm, NULL, &name, &js->args[0]); - if (rc != NXT_OK) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "could not get $r external"); - return NGX_CONF_ERROR; - } - - ngx_str_set(&name, "response"); - - rc = njs_vm_external(vm, &js->args[0], &name, &js->args[1]); - if (rc != NXT_OK) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "could not get $r.response external"); - return NGX_CONF_ERROR; - } - } + clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); + clcf->handler = ngx_http_js_handler; return NGX_CONF_OK; } @@ -1238,8 +1439,10 @@ ngx_http_js_merge_loc_conf(ngx_conf_t *c ngx_http_js_loc_conf_t *prev = parent; ngx_http_js_loc_conf_t *conf = child; - if (conf->js.vm == NULL) { - conf->js = prev->js; + if (conf->vm == NULL) { + conf->vm = prev->vm; + conf->args[0] = prev->args[0]; + conf->args[1] = prev->args[1]; } return NGX_CONF_OK; diff -r a3e7ebdf9fa7 -r 252409c490bc nxt/nxt_stub.h --- a/nxt/nxt_stub.h Fri Jul 15 15:50:13 2016 +0300 +++ b/nxt/nxt_stub.h Wed Jul 20 18:20:13 2016 +0300 @@ -58,6 +58,20 @@ typedef struct { } nxt_str_t; +#define nxt_str_set(str, text) \ + do { \ + (str)->len = sizeof(text) - 1; \ + (str)->data = (u_char *) text; \ + } while (0) + + +#define nxt_str_null(str) \ + do { \ + (str)->len = 0; \ + (str)->data = NULL; \ + } while (0) + + #define nxt_string(str) { sizeof(str) - 1, (u_char *) str } #define nxt_string_zero(str) { sizeof(str), (u_char *) str } #define nxt_null_string { 0, NULL } From arut at nginx.com Wed Jul 20 16:39:29 2016 From: arut at nginx.com (Roman Arutyunyan) Date: Wed, 20 Jul 2016 16:39:29 +0000 Subject: [njs] Stream njs module. Message-ID: details: http://hg.nginx.org/njs/rev/740defed7584 branches: changeset: 124:740defed7584 user: Roman Arutyunyan date: Wed Jul 20 18:20:17 2016 +0300 description: Stream njs module. diffstat: nginx/config | 15 +- nginx/ngx_stream_js_module.c | 624 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 637 insertions(+), 2 deletions(-) diffs (660 lines): diff -r 252409c490bc -r 740defed7584 nginx/config --- a/nginx/config Wed Jul 20 18:20:13 2016 +0300 +++ b/nginx/config Wed Jul 20 18:20:17 2016 +0300 @@ -1,4 +1,4 @@ -ngx_addon_name="ngx_http_js_module" +ngx_addon_name="ngx_js_module" USE_PCRE=YES @@ -10,10 +10,21 @@ if test -n "$ngx_module_link"; then ngx_module_libs="$ngx_addon_dir/../build/libnjs.a -lm" . auto/module + + ngx_module_type=STREAM + ngx_module_name=ngx_stream_js_module + ngx_module_incs="$ngx_addon_dir/../nxt $ngx_addon_dir/../njs" + ngx_module_srcs="$ngx_addon_dir/ngx_stream_js_module.c" + ngx_module_libs="$ngx_addon_dir/../build/libnjs.a -lm" + + . auto/module else HTTP_MODULES="$HTTP_MODULES ngx_http_js_module" + STREAM_MODULES="$STREAM_MODULES ngx_stream_js_module" CORE_INCS="$CORE_INCS $ngx_addon_dir/../nxt $ngx_addon_dir/../njs" - NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_js_module.c" + NGX_ADDON_SRCS="$NGX_ADDON_SRCS \ + $ngx_addon_dir/ngx_http_js_module.c \ + $ngx_addon_dir/ngx_stream_js_module.c" CORE_LIBS="$CORE_LIBS $ngx_addon_dir/../build/libnjs.a -lm" fi diff -r 252409c490bc -r 740defed7584 nginx/ngx_stream_js_module.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nginx/ngx_stream_js_module.c Wed Jul 20 18:20:17 2016 +0300 @@ -0,0 +1,624 @@ + +/* + * Copyright (C) Roman Arutyunyan + * Copyright (C) NGINX, Inc. + */ + + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +#define NGX_STREAM_JS_MCP_CLUSTER_SIZE (2 * ngx_pagesize) +#define NGX_STREAM_JS_MCP_PAGE_ALIGNMENT 128 +#define NGX_STREAM_JS_MCP_PAGE_SIZE 512 +#define NGX_STREAM_JS_MCP_MIN_CHUNK_SIZE 16 + + +#define ngx_stream_js_create_mem_cache_pool() \ + nxt_mem_cache_pool_create(&ngx_stream_js_mem_cache_pool_proto, NULL, NULL,\ + NGX_STREAM_JS_MCP_CLUSTER_SIZE, \ + NGX_STREAM_JS_MCP_PAGE_ALIGNMENT, \ + NGX_STREAM_JS_MCP_PAGE_SIZE, \ + NGX_STREAM_JS_MCP_MIN_CHUNK_SIZE) + + +typedef struct { + njs_vm_t *vm; + njs_opaque_value_t arg; +} ngx_stream_js_srv_conf_t; + + +typedef struct { + njs_vm_t *vm; + njs_opaque_value_t *arg; +} ngx_stream_js_ctx_t; + + +static ngx_int_t ngx_stream_js_variable(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data); +static void ngx_stream_js_cleanup_mem_cache_pool(void *data); +static ngx_int_t ngx_stream_js_init_vm(ngx_stream_session_t *s); + +static void *ngx_stream_js_alloc(void *mem, size_t size); +static void *ngx_stream_js_calloc(void *mem, size_t size); +static void *ngx_stream_js_memalign(void *mem, size_t alignment, size_t size); +static void ngx_stream_js_free(void *mem, void *p); + +static njs_ret_t ngx_stream_js_ext_get_remote_address(njs_vm_t *vm, + njs_value_t *value, void *obj, uintptr_t data); +static njs_ret_t ngx_stream_js_ext_log(njs_vm_t *vm, njs_value_t *args, + nxt_uint_t nargs, njs_index_t unused); +static njs_ret_t ngx_stream_js_ext_get_variable(njs_vm_t *vm, + njs_value_t *value, void *obj, uintptr_t data); + +static char *ngx_stream_js_include(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static char *ngx_stream_js_set(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static void *ngx_stream_js_create_srv_conf(ngx_conf_t *cf); +static char *ngx_stream_js_merge_srv_conf(ngx_conf_t *cf, void *parent, + void *child); + + +static ngx_command_t ngx_stream_js_commands[] = { + + { ngx_string("js_include"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, + ngx_stream_js_include, + NGX_STREAM_SRV_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("js_set"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE2, + ngx_stream_js_set, + NGX_STREAM_SRV_CONF_OFFSET, + 0, + NULL }, + + ngx_null_command +}; + + +static ngx_stream_module_t ngx_stream_js_module_ctx = { + NULL, /* preconfiguration */ + NULL, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + ngx_stream_js_create_srv_conf, /* create server configuration */ + ngx_stream_js_merge_srv_conf, /* merge server configuration */ +}; + + +ngx_module_t ngx_stream_js_module = { + NGX_MODULE_V1, + &ngx_stream_js_module_ctx, /* module context */ + ngx_stream_js_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 const nxt_mem_proto_t ngx_stream_js_mem_cache_pool_proto = { + ngx_stream_js_alloc, + ngx_stream_js_calloc, + ngx_stream_js_memalign, + NULL, + ngx_stream_js_free, + NULL, + NULL, +}; + + +static njs_external_t ngx_stream_js_ext_session[] = { + + { nxt_string("remoteAddress"), + NJS_EXTERN_PROPERTY, + NULL, + 0, + ngx_stream_js_ext_get_remote_address, + NULL, + NULL, + NULL, + NULL, + NULL, + 0 }, + + { nxt_string("log"), + NJS_EXTERN_METHOD, + NULL, + 0, + NULL, + NULL, + NULL, + NULL, + NULL, + ngx_stream_js_ext_log, + 0 }, + + { nxt_string("variables"), + NJS_EXTERN_OBJECT, + NULL, + 0, + ngx_stream_js_ext_get_variable, + NULL, + NULL, + NULL, + NULL, + NULL, + 0 }, +}; + + +static njs_external_t ngx_stream_js_externals[] = { + + { nxt_string("$s"), + NJS_EXTERN_OBJECT, + ngx_stream_js_ext_session, + nxt_nitems(ngx_stream_js_ext_session), + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + 0 }, +}; + + +static ngx_int_t +ngx_stream_js_variable(ngx_stream_session_t *s, ngx_stream_variable_value_t *v, + uintptr_t data) +{ + ngx_str_t *fname = (ngx_str_t *) data; + + ngx_int_t rc; + nxt_str_t name, value, exception; + njs_function_t *func; + ngx_stream_js_ctx_t *ctx; + + rc = ngx_stream_js_init_vm(s); + + if (rc == NGX_ERROR) { + return NGX_ERROR; + } + + if (rc == NGX_DECLINED) { + v->not_found = 1; + return NGX_OK; + } + + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, + "stream js variable call \"%V\"", fname); + + ctx = ngx_stream_get_module_ctx(s, ngx_stream_js_module); + + name.data = fname->data; + name.len = fname->len; + + func = njs_vm_function(ctx->vm, &name); + if (func == NULL) { + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, + "js function \"%V\" not found", fname); + v->not_found = 1; + return NGX_OK; + } + + if (njs_vm_call(ctx->vm, func, ctx->arg, 1) != NJS_OK) { + njs_vm_exception(ctx->vm, &exception); + + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "js exception: %*s", exception.len, exception.data); + + v->not_found = 1; + return NGX_OK; + } + + if (njs_vm_retval(ctx->vm, &value) != NJS_OK) { + return NGX_ERROR; + } + + v->len = value.len; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = value.data; + + return NGX_OK; +} + + +static ngx_int_t +ngx_stream_js_init_vm(ngx_stream_session_t *s) +{ + void **ext; + ngx_pool_cleanup_t *cln; + nxt_mem_cache_pool_t *mcp; + ngx_stream_js_ctx_t *ctx; + ngx_stream_js_srv_conf_t *jscf; + + jscf = ngx_stream_get_module_srv_conf(s, ngx_stream_js_module); + if (jscf->vm == NULL) { + return NGX_DECLINED; + } + + ctx = ngx_stream_get_module_ctx(s, ngx_stream_js_module); + + if (ctx == NULL) { + ctx = ngx_pcalloc(s->connection->pool, sizeof(ngx_stream_js_ctx_t)); + if (ctx == NULL) { + return NGX_ERROR; + } + + ngx_stream_set_ctx(s, ctx, ngx_stream_js_module); + } + + if (ctx->vm) { + return NGX_OK; + } + + mcp = ngx_stream_js_create_mem_cache_pool(); + if (mcp == NULL) { + return NGX_ERROR; + } + + cln = ngx_pool_cleanup_add(s->connection->pool, 0); + if (cln == NULL) { + return NGX_ERROR; + } + + cln->handler = ngx_stream_js_cleanup_mem_cache_pool; + cln->data = mcp; + + ext = ngx_palloc(s->connection->pool, sizeof(void *)); + if (ext == NULL) { + return NGX_ERROR; + } + + *ext = s; + + ctx->vm = njs_vm_clone(jscf->vm, mcp, ext); + if (ctx->vm == NULL) { + return NGX_ERROR; + } + + ctx->arg = &jscf->arg; + + return NGX_OK; +} + + +static void +ngx_stream_js_cleanup_mem_cache_pool(void *data) +{ + nxt_mem_cache_pool_t *mcp = data; + + nxt_mem_cache_pool_destroy(mcp); +} + + +static void * +ngx_stream_js_alloc(void *mem, size_t size) +{ + return ngx_alloc(size, ngx_cycle->log); +} + + +static void * +ngx_stream_js_calloc(void *mem, size_t size) +{ + return ngx_calloc(size, ngx_cycle->log); +} + + +static void * +ngx_stream_js_memalign(void *mem, size_t alignment, size_t size) +{ + return ngx_memalign(alignment, size, ngx_cycle->log); +} + + +static void +ngx_stream_js_free(void *mem, void *p) +{ + ngx_free(p); +} + + +static njs_ret_t +ngx_stream_js_ext_get_remote_address(njs_vm_t *vm, njs_value_t *value, + void *obj, uintptr_t data) +{ + ngx_connection_t *c; + ngx_stream_session_t *s; + + s = (ngx_stream_session_t *) obj; + c = s->connection; + + return njs_string_create(vm, value, c->addr_text.data, c->addr_text.len, 0); +} + + +static njs_ret_t +ngx_stream_js_ext_log(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, + njs_index_t unused) +{ + nxt_str_t msg; + ngx_connection_t *c; + ngx_log_handler_pt handler; + ngx_stream_session_t *s; + + s = njs_value_data(njs_argument(args, 0)); + c = s->connection; + + if (njs_value_to_ext_string(vm, &msg, njs_argument(args, 1)) == NJS_ERROR) + { + return NJS_ERROR; + } + + handler = c->log->handler; + c->log->handler = NULL; + + ngx_log_error(NGX_LOG_INFO, c->log, 0, "js: %*s", msg.len, msg.data); + + c->log->handler = handler; + + return NJS_OK; +} + + +static njs_ret_t +ngx_stream_js_ext_get_variable(njs_vm_t *vm, njs_value_t *value, void *obj, + uintptr_t data) +{ + nxt_str_t *v; + ngx_str_t name; + ngx_uint_t key; + ngx_stream_session_t *s; + ngx_stream_variable_value_t *vv; + + s = (ngx_stream_session_t *) obj; + v = (nxt_str_t *) data; + + name.data = v->data; + name.len = v->len; + + key = ngx_hash_strlow(name.data, name.data, name.len); + + vv = ngx_stream_get_variable(s, &name, key); + if (vv == NULL || vv->not_found) { + return njs_string_create(vm, value, NULL, 0, 0); + } + + return njs_string_create(vm, value, vv->data, vv->len, 0); +} + + +static char * +ngx_stream_js_include(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_stream_js_srv_conf_t *jscf = conf; + + size_t size; + u_char *start, *end; + ssize_t n; + ngx_fd_t fd; + ngx_str_t *value, file; + nxt_int_t rc; + nxt_str_t text, ext; + nxt_lvlhsh_t externals; + ngx_file_info_t fi; + njs_vm_shared_t *shared; + ngx_pool_cleanup_t *cln; + nxt_mem_cache_pool_t *mcp; + + if (jscf->vm) { + return "is duplicate"; + } + + value = cf->args->elts; + file = value[1]; + + if (ngx_conf_full_name(cf->cycle, &file, 1) != NGX_OK) { + return NGX_CONF_ERROR; + } + + fd = ngx_open_file(file.data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0); + if (fd == NGX_INVALID_FILE) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno, + ngx_open_file_n " \"%s\" failed", file.data); + return NGX_CONF_ERROR; + } + + if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_EMERG, cf->log, ngx_errno, + ngx_fd_info_n " \"%s\" failed", file.data); + return NGX_CONF_ERROR; + } + + size = ngx_file_size(&fi); + + start = ngx_pnalloc(cf->pool, size); + if (start == NULL) { + return NGX_CONF_ERROR; + } + + n = ngx_read_fd(fd, start, size); + + if (n == -1) { + ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, + ngx_read_fd_n " \"%s\" failed", file.data); + + ngx_close_file(fd); + return NGX_CONF_ERROR; + } + + if ((size_t) n != size) { + ngx_log_error(NGX_LOG_ALERT, cf->log, 0, + ngx_read_fd_n " has read only %z of %O from \"%s\"", + n, size, file.data); + + ngx_close_file(fd); + return NGX_CONF_ERROR; + } + + if (ngx_close_file(fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, + ngx_close_file_n " %s failed", file.data); + } + + end = start + size; + + mcp = ngx_stream_js_create_mem_cache_pool(); + if (mcp == NULL) { + return NGX_CONF_ERROR; + } + + cln = ngx_pool_cleanup_add(cf->pool, 0); + if (cln == NULL) { + return NULL; + } + + cln->handler = ngx_stream_js_cleanup_mem_cache_pool; + cln->data = mcp; + + shared = NULL; + + nxt_lvlhsh_init(&externals); + + if (njs_vm_external_add(&externals, mcp, 0, ngx_stream_js_externals, + nxt_nitems(ngx_stream_js_externals)) + != NJS_OK) + { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "could not add js externals"); + return NGX_CONF_ERROR; + } + + jscf->vm = njs_vm_create(mcp, &shared, &externals); + if (jscf->vm == NULL) { + return NGX_CONF_ERROR; + } + + rc = njs_vm_compile(jscf->vm, &start, end, NULL); + + if (rc != NJS_OK) { + njs_vm_exception(jscf->vm, &text); + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "%*s, included", + text.len, text.data); + return NGX_CONF_ERROR; + } + + if (start != end) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "extra characters in js script: \"%*s\", included", + end - start, start); + return NGX_CONF_ERROR; + } + + nxt_str_set(&ext, "$s"); + + if (njs_vm_external(jscf->vm, NULL, &ext, &jscf->arg) != NJS_OK) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "js external \"%*s\" not found", ext.len, ext.data); + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + + +static char * +ngx_stream_js_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_str_t *value, *fname; + ngx_stream_variable_t *v; + + value = cf->args->elts; + + if (value[1].data[0] != '$') { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid variable name \"%V\"", &value[1]); + return NGX_CONF_ERROR; + } + + value[1].len--; + value[1].data++; + + v = ngx_stream_add_variable(cf, &value[1], NGX_STREAM_VAR_CHANGEABLE); + if (v == NULL) { + return NGX_CONF_ERROR; + } + + fname = ngx_palloc(cf->pool, sizeof(ngx_str_t)); + if (fname == NULL) { + return NGX_CONF_ERROR; + } + + *fname = value[2]; + + v->get_handler = ngx_stream_js_variable; + v->data = (uintptr_t) fname; + + return NGX_CONF_OK; +} + + +static void * +ngx_stream_js_create_srv_conf(ngx_conf_t *cf) +{ + ngx_stream_js_srv_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_stream_js_srv_conf_t)); + if (conf == NULL) { + return NULL; + } + + /* + * set by ngx_pcalloc(): + * + * conf->vm = NULL; + * conf->arg = NULL; + */ + + return conf; +} + + +static char * +ngx_stream_js_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_stream_js_srv_conf_t *prev = parent; + ngx_stream_js_srv_conf_t *conf = child; + + if (conf->vm == NULL) { + conf->vm = prev->vm; + conf->arg = prev->arg; + } + + return NGX_CONF_OK; +} From arut at nginx.com Wed Jul 20 16:39:30 2016 From: arut at nginx.com (Roman Arutyunyan) Date: Wed, 20 Jul 2016 16:39:30 +0000 Subject: [njs] Updated README to reflect changes in HTTP and Stream modules. Message-ID: details: http://hg.nginx.org/njs/rev/3f8f801e2f53 branches: changeset: 125:3f8f801e2f53 user: Roman Arutyunyan date: Wed Jul 20 19:38:00 2016 +0300 description: Updated README to reflect changes in HTTP and Stream modules. diffstat: README | 225 +++++++++++++++++++++++++++++++++++++++++----------------------- 1 files changed, 144 insertions(+), 81 deletions(-) diffs (264 lines): diff -r 740defed7584 -r 3f8f801e2f53 README --- a/README Wed Jul 20 18:20:17 2016 +0300 +++ b/README Wed Jul 20 19:38:00 2016 +0300 @@ -1,5 +1,6 @@ -Configure nginx with HTTP JavaScript module using the --add-module option: +Configure nginx with HTTP and Stream JavaScript modules using the --add-module +option: ./configure --add-module=/nginx @@ -14,30 +15,39 @@ and add the following line to nginx.conf Please report your experiences to the NGINX development mailing list nginx-devel at nginx.org (http://mailman.nginx.org/mailman/listinfo/nginx-devel). -JavaScript objects ------------------- -$r -|- uri -|- method -|- httpVersion -|- remoteAddress -|- headers{} -|- args{} -|- response - |- status - |- headers{} - |- contentType - |- contentLength - |- sendHeader() - |- send(data) - |- finish() +HTTP JavaScript module +---------------------- + +Each HTTP JavaScript handler receives two arguments - request and response. + + function foo(req, res) { + .. + } + +The following properties are available: + +req + - uri + - method + - httpVersion + - remoteAddress + - headers{} + - args{} + - variables{} + - log() + +res + - status + - headers{} + - contentType + - contentLength + - sendHeader() + - send() + - finish() -Example -------- - -Create nginx.conf: +Example nginx.conf: worker_processes 1; pid logs/nginx.pid; @@ -47,79 +57,132 @@ Create nginx.conf: } http { - js_set $summary " - var a, s, h; - - s = 'JS summary\n\n'; - - s += 'Method: ' + $r.method + '\n'; - s += 'HTTP version: ' + $r.httpVersion + '\n'; - s += 'Host: ' + $r.headers.host + '\n'; - s += 'Remote Address: ' + $r.remoteAddress + '\n'; - s += 'URI: ' + $r.uri + '\n'; - - s += 'Headers:\n'; - for (h in $r.headers) { - s += ' header \"' + h + '\" is \"' + $r.headers[h] + '\"\n'; - } - - s += 'Args:\n'; - for (a in $r.args) { - s += ' arg \"' + a + '\" is \"' + $r.args[a] + '\"\n'; - } - - s; - "; + # include JavaScript file + js_include js-http.js; server { listen 8000; location / { - js_run " - var res; - res = $r.response; - res.headers.foo = 1234; - res.status = 302; - res.contentType = 'text/plain; charset=utf-8'; - res.contentLength = 15; - res.sendHeader(); - res.send('nginx'); - res.send('java'); - res.send('script'); - res.finish(); - "; + # create $foo variable and set JavaScript function foo() + # from the included JavaScript file as its handler + js_set $foo foo; + + add_header X-Foo $foo; + + # register JavaScript function bar() as content handler + js_content baz; } location /summary { + js_set $summary summary; + return 200 $summary; } } } -Run nginx & test the output: - -$ curl 127.0.0.1:8000 - -nginxjavascript - -$ curl -H "Foo: 1099" '127.0.0.1:8000/summary?a=1&fooo=bar&zyx=xyz' - -JS summary -Method: GET -HTTP version: 1.1 -Host: 127.0.0.1:8000 -Remote Address: 127.0.0.1 -URI: /summary -Headers: - header "Host" is "127.0.0.1:8000" - header "User-Agent" is "curl/7.43.0" - header "Accept" is "*/*" - header "Foo" is "1099" -Args: - arg "a" is "1" - arg "fooo" is "bar" - arg "zyx" is "xyz" +js-http.js: + + function foo(req, res) { + req.log("hello from foo() handler"); + return "foo"; + } + + function summary(req, res) { + var a, s, h; + + s = "JS summary\n\n"; + + s += "Method: " + req.method + "\n"; + s += "HTTP version: " + req.httpVersion + "\n"; + s += "Host: " + req.headers.host + "\n"; + s += "Remote Address: " + req.remoteAddress + "\n"; + s += "URI: " + req.uri + "\n"; + + s += "Headers:\n"; + for (h in req.headers) { + s += " header '" + h + "' is '" + req.headers[h] + "'\n"; + } + + s += "Args:\n"; + for (a in req.args) { + s += " arg '" + a + "' is '" + req.args[a] + "'\n"; + } + + return s; + } + + function baz(req, res) { + res.headers.foo = 1234; + res.status = 200; + res.contentType = "text/plain; charset=utf-8"; + res.contentLength = 15; + res.sendHeader(); + res.send("nginx"); + res.send("java"); + res.send("script"); + + res.finish(); + } + + +Stream JavaScript module +------------------------ + +Each Stream JavaScript handler receives one argument - stream session object. + + function foo(s) { + .. + } + +The following properties are available in the session object: + + - remoteAddress + - variables{} + - log() + + +Example nginx.conf: + + worker_processes 1; + pid logs/nginx.pid; + + events { + worker_connections 256; + } + + stream { + # include JavaScript file + js_include js-stream.js; + + server { + listen 8000; + + # create $foo and $bar variables and set JavaScript + # functions foo() and bar() from the included JavaScript + # file as their handlers + js_set $foo foo; + js_set $bar bar; + + return $foo-$bar; + } + } + + +js-stream.js: + + function foo(s) { + s.log("hello from foo() handler!"); + return s.remoteAddress; + } + + function bar(s) { + var v = s.variables; + s.log("hello from bar() handler!"); + return "foo-var" + v.remote_port + "; pid=" + v.pid; + } -- From arut at nginx.com Wed Jul 20 18:41:49 2016 From: arut at nginx.com (Roman Arutyunyan) Date: Wed, 20 Jul 2016 18:41:49 +0000 Subject: [njs] Updated README. Message-ID: details: http://hg.nginx.org/njs/rev/faab537db6f8 branches: changeset: 126:faab537db6f8 user: Roman Arutyunyan date: Wed Jul 20 21:40:34 2016 +0300 description: Updated README. diffstat: README | 19 +++++++++++++------ 1 files changed, 13 insertions(+), 6 deletions(-) diffs (76 lines): diff -r 3f8f801e2f53 -r faab537db6f8 README --- a/README Wed Jul 20 19:38:00 2016 +0300 +++ b/README Wed Jul 20 21:40:34 2016 +0300 @@ -4,13 +4,14 @@ option: ./configure --add-module=/nginx -Alternatively, you can build a dynamic version of the njs module +Alternatively, you can build a dynamic version of the modules ./configure --add-dynamic-module=/nginx -and add the following line to nginx.conf and reload nginx: +and add the following lines to nginx.conf to load them load_module modules/ngx_http_js_module.so; + load_module modules/ngx_stream_js_module.so; Please report your experiences to the NGINX development mailing list nginx-devel at nginx.org (http://mailman.nginx.org/mailman/listinfo/nginx-devel). @@ -49,6 +50,9 @@ res Example nginx.conf: + # load dynamic HTTP JavaScript module + load_module modules/ngx_http_js_module.so; + worker_processes 1; pid logs/nginx.pid; @@ -58,7 +62,7 @@ Example nginx.conf: http { # include JavaScript file - js_include js-http.js; + js_include http.js; server { listen 8000; @@ -83,7 +87,7 @@ Example nginx.conf: } -js-http.js: +http.js: function foo(req, res) { req.log("hello from foo() handler"); @@ -146,6 +150,9 @@ The following properties are available i Example nginx.conf: + # load dynamic Stream JavaScript module + load_module modules/ngx_stream_js_module.so; + worker_processes 1; pid logs/nginx.pid; @@ -155,7 +162,7 @@ Example nginx.conf: stream { # include JavaScript file - js_include js-stream.js; + js_include stream.js; server { listen 8000; @@ -171,7 +178,7 @@ Example nginx.conf: } -js-stream.js: +stream.js: function foo(s) { s.log("hello from foo() handler!"); From tfransosi at gmail.com Wed Jul 20 19:51:16 2016 From: tfransosi at gmail.com (Thiago Farina) Date: Wed, 20 Jul 2016 16:51:16 -0300 Subject: how can i get nginx lib In-Reply-To: References: Message-ID: On Mon, Jun 27, 2016 at 8:37 AM, Pankaj Chaudhary wrote: > > > Is there such thing? As far as I know it is distributed only as binary. -- Thiago Farina -------------- next part -------------- An HTML attachment was scrubbed... URL: From savetherbtz at gmail.com Wed Jul 20 22:34:46 2016 From: savetherbtz at gmail.com (Alexey Ivanov) Date: Wed, 20 Jul 2016 15:34:46 -0700 Subject: [PATCH 1 of 2] HTTP: add support for trailers in HTTP responses In-Reply-To: References: <20160627175338.GD30781@mdounin.ru> <20160704142135.GZ30781@mdounin.ru> <20160707150047.GJ30781@mdounin.ru> <20160707232029.GO30781@mdounin.ru> <20160713184331.GQ57459@mdounin.ru> Message-ID: <56CE925B-66FF-47B6-A468-64289F47D39E@gmail.com> Speaking of trailers: we had couple of use cases for HTTP trailers, most of them were around streaming data to user. For example, when webpage is generated we send headers and part of the body(usually up to ``) almost immediately, but then we start querying all the micro services for the content (SOA, yay!). The problem is that upstreams will inevitably fail/timeout, and when that happens there is no way to pass any metadata about the error to nginx, since headers are already sent. Using trailers here may improve MTTR since backend metadata is available on the frontend. Another example may be computing checksums for data while you stream it and putting it in the trailer. This should reduce TTFB by quite a lot on some workloads we have. > On Jul 13, 2016, at 5:34 PM, Piotr Sikora wrote: > > Hey Maxim, > >> I'm talking about trailers in general (though it's more about >> requests than responses). Normal request (and response) >> processing in nginx assumes that headers are processed before the >> body, and adding trailers (which are headers "to be added later") >> to the picture are likely to have various security implications. > > Let's step back a bit... I have no plans to change the processing > logic nor merge trailers with headers. Trailers are going to be > ignored (passed, but not processed) by NGINX, not discarded. > > AFAIK, Apache does the same thing. > > Basically, at this point, trailers act as metadata for the application > (browser, gRPC, 3rd-party NGINX module, etc.), with no HTTP semantics, > so there are no security implications for NGINX itself. > > Best regards, > Piotr Sikora > > _______________________________________________ > nginx-devel mailing list > nginx-devel at nginx.org > http://mailman.nginx.org/mailman/listinfo/nginx-devel -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 842 bytes Desc: Message signed with OpenPGP using GPGMail URL: From mdounin at mdounin.ru Thu Jul 21 01:23:23 2016 From: mdounin at mdounin.ru (Maxim Dounin) Date: Thu, 21 Jul 2016 04:23:23 +0300 Subject: [PATCH 1 of 2] HTTP: add support for trailers in HTTP responses In-Reply-To: <56CE925B-66FF-47B6-A468-64289F47D39E@gmail.com> References: <20160704142135.GZ30781@mdounin.ru> <20160707150047.GJ30781@mdounin.ru> <20160707232029.GO30781@mdounin.ru> <20160713184331.GQ57459@mdounin.ru> <56CE925B-66FF-47B6-A468-64289F47D39E@gmail.com> Message-ID: <20160721012322.GT57459@mdounin.ru> Hello! On Wed, Jul 20, 2016 at 03:34:46PM -0700, Alexey Ivanov wrote: > Speaking of trailers: we had couple of use cases for HTTP > trailers, most of them were around streaming data to user. > > For example, when webpage is generated we send headers and part > of the body(usually up to ``) almost immediately, but > then we start querying all the micro services for the content > (SOA, yay!). > The problem is that upstreams will inevitably fail/timeout, and > when that happens there is no way to pass any metadata about the > error to nginx, since headers are already sent. Using trailers > here may improve MTTR since backend metadata is available on the > frontend. > > Another example may be computing checksums for data while you > stream it and putting it in the trailer. This should reduce TTFB > by quite a lot on some workloads we have. Do you actually use something like this, or know places where something like this is actually used? Obviously enough, trailers have lots of theoretical use cases, and that's why there were introduced in HTTP/1.1 in the first place. The problem is that it doesn't seem to be used in the real world though. -- Maxim Dounin http://nginx.org/ From savetherbtz at gmail.com Thu Jul 21 01:33:11 2016 From: savetherbtz at gmail.com (Alexey Ivanov) Date: Wed, 20 Jul 2016 18:33:11 -0700 Subject: [PATCH 1 of 2] HTTP: add support for trailers in HTTP responses In-Reply-To: <20160721012322.GT57459@mdounin.ru> References: <20160704142135.GZ30781@mdounin.ru> <20160707150047.GJ30781@mdounin.ru> <20160707232029.GO30781@mdounin.ru> <20160713184331.GQ57459@mdounin.ru> <56CE925B-66FF-47B6-A468-64289F47D39E@gmail.com> <20160721012322.GT57459@mdounin.ru> Message-ID: <09C74FD3-25B0-45D8-8EA4-84DCDFD77CC5@gmail.com> > On Jul 20, 2016, at 6:23 PM, Maxim Dounin wrote: > > Hello! > > On Wed, Jul 20, 2016 at 03:34:46PM -0700, Alexey Ivanov wrote: > >> Speaking of trailers: we had couple of use cases for HTTP >> trailers, most of them were around streaming data to user. >> >> For example, when webpage is generated we send headers and part >> of the body(usually up to ``) almost immediately, but >> then we start querying all the micro services for the content >> (SOA, yay!). >> The problem is that upstreams will inevitably fail/timeout, and >> when that happens there is no way to pass any metadata about the >> error to nginx, since headers are already sent. Using trailers >> here may improve MTTR since backend metadata is available on the >> frontend. >> >> Another example may be computing checksums for data while you >> stream it and putting it in the trailer. This should reduce TTFB >> by quite a lot on some workloads we have. > > Do you actually use something like this, or know places where > something like this is actually used? These are examples from our production. Currently we are using workarounds for both of these problems. Though I'm not sure that we would use trailers if they were supported, since it's one of very obscure HTTP/1.1 features that people do not usually know about. That is starting to change bit by bit though, since people try using gRPC more and more. > > Obviously enough, trailers have lots of theoretical use cases, and > that's why there were introduced in HTTP/1.1 in the first place. > The problem is that it doesn't seem to be used in the real world > though. > > -- > Maxim Dounin > http://nginx.org/ > > _______________________________________________ > nginx-devel mailing list > nginx-devel at nginx.org > http://mailman.nginx.org/mailman/listinfo/nginx-devel -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 842 bytes Desc: Message signed with OpenPGP using GPGMail URL: From vl at nginx.com Thu Jul 21 05:38:33 2016 From: vl at nginx.com (Vladimir Homutov) Date: Thu, 21 Jul 2016 05:38:33 +0000 Subject: [nginx] Stream: variables in proxy_pass and proxy_ssl_name. Message-ID: details: http://hg.nginx.org/nginx/rev/9757cffc1e2f branches: changeset: 6643:9757cffc1e2f user: Vladimir Homutov date: Tue Jun 14 18:29:46 2016 +0300 description: Stream: variables in proxy_pass and proxy_ssl_name. diffstat: src/stream/ngx_stream_proxy_module.c | 390 ++++++++++++++++++++++---- src/stream/ngx_stream_upstream.h | 16 + src/stream/ngx_stream_upstream_round_robin.c | 135 +++++++++ src/stream/ngx_stream_upstream_round_robin.h | 2 + 4 files changed, 483 insertions(+), 60 deletions(-) diffs (709 lines): diff -r 72282dd5884e -r 9757cffc1e2f src/stream/ngx_stream_proxy_module.c --- a/src/stream/ngx_stream_proxy_module.c Tue Jul 19 20:34:17 2016 +0300 +++ b/src/stream/ngx_stream_proxy_module.c Tue Jun 14 18:29:46 2016 +0300 @@ -37,7 +37,7 @@ typedef struct { ngx_flag_t ssl_session_reuse; ngx_uint_t ssl_protocols; ngx_str_t ssl_ciphers; - ngx_str_t ssl_name; + ngx_stream_complex_value_t *ssl_name; ngx_flag_t ssl_server_name; ngx_flag_t ssl_verify; @@ -52,14 +52,18 @@ typedef struct { #endif ngx_stream_upstream_srv_conf_t *upstream; + ngx_stream_complex_value_t *upstream_value; } ngx_stream_proxy_srv_conf_t; static void ngx_stream_proxy_handler(ngx_stream_session_t *s); +static ngx_int_t ngx_stream_proxy_eval(ngx_stream_session_t *s, + ngx_stream_proxy_srv_conf_t *pscf); static ngx_int_t ngx_stream_proxy_set_local(ngx_stream_session_t *s, ngx_stream_upstream_t *u, ngx_stream_upstream_local_t *local); static void ngx_stream_proxy_connect(ngx_stream_session_t *s); static void ngx_stream_proxy_init_upstream(ngx_stream_session_t *s); +static void ngx_stream_proxy_resolve_handler(ngx_resolver_ctx_t *ctx); static void ngx_stream_proxy_upstream_handler(ngx_event_t *ev); static void ngx_stream_proxy_downstream_handler(ngx_event_t *ev); static void ngx_stream_proxy_process_connection(ngx_event_t *ev, @@ -246,7 +250,7 @@ static ngx_command_t ngx_stream_proxy_c { ngx_string("proxy_ssl_name"), NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_str_slot, + ngx_stream_set_complex_value_slot, NGX_STREAM_SRV_CONF_OFFSET, offsetof(ngx_stream_proxy_srv_conf_t, ssl_name), NULL }, @@ -344,11 +348,16 @@ ngx_module_t ngx_stream_proxy_module = static void ngx_stream_proxy_handler(ngx_stream_session_t *s) { - u_char *p; - ngx_connection_t *c; - ngx_stream_upstream_t *u; - ngx_stream_proxy_srv_conf_t *pscf; - ngx_stream_upstream_srv_conf_t *uscf; + u_char *p; + ngx_str_t *host; + ngx_uint_t i; + ngx_connection_t *c; + ngx_resolver_ctx_t *ctx, temp; + ngx_stream_upstream_t *u; + ngx_stream_core_srv_conf_t *cscf; + ngx_stream_proxy_srv_conf_t *pscf; + ngx_stream_upstream_srv_conf_t *uscf, **uscfp; + ngx_stream_upstream_main_conf_t *umcf; c = s->connection; @@ -377,7 +386,161 @@ ngx_stream_proxy_handler(ngx_stream_sess u->peer.type = c->type; - uscf = pscf->upstream; + u->proxy_protocol = pscf->proxy_protocol; + u->start_sec = ngx_time(); + + c->write->handler = ngx_stream_proxy_downstream_handler; + c->read->handler = ngx_stream_proxy_downstream_handler; + + if (c->type == SOCK_STREAM) { + p = ngx_pnalloc(c->pool, pscf->buffer_size); + if (p == NULL) { + ngx_stream_proxy_finalize(s, NGX_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; + + if (u->proxy_protocol +#if (NGX_STREAM_SSL) + && pscf->ssl == NULL +#endif + && pscf->buffer_size >= NGX_PROXY_PROTOCOL_MAX_HEADER) + { + /* optimization for a typical case */ + + ngx_log_debug0(NGX_LOG_DEBUG_STREAM, c->log, 0, + "stream proxy send PROXY protocol header"); + + p = ngx_proxy_protocol_write(c, u->downstream_buf.last, + u->downstream_buf.end); + if (p == NULL) { + ngx_stream_proxy_finalize(s, NGX_ERROR); + return; + } + + u->downstream_buf.last = p; + u->proxy_protocol = 0; + } + + if (c->read->ready) { + ngx_post_event(c->read, &ngx_posted_events); + } + } + + if (pscf->upstream_value) { + if (ngx_stream_proxy_eval(s, pscf) != NGX_OK) { + ngx_stream_proxy_finalize(s, NGX_ERROR); + return; + } + } + + if (u->resolved == NULL) { + + uscf = pscf->upstream; + + } else { + +#if (NGX_STREAM_SSL) + u->ssl_name = u->resolved->host; +#endif + + host = &u->resolved->host; + + if (u->resolved->sockaddr) { + + if (u->resolved->port == 0 + && u->resolved->sockaddr->sa_family != AF_UNIX) + { + ngx_log_error(NGX_LOG_ERR, c->log, 0, + "no port in upstream \"%V\"", host); + ngx_stream_proxy_finalize(s, NGX_ERROR); + return; + } + + if (ngx_stream_upstream_create_round_robin_peer(s, u->resolved) + != NGX_OK) + { + ngx_stream_proxy_finalize(s, NGX_ERROR); + return; + } + + ngx_stream_proxy_connect(s); + + return; + } + + umcf = ngx_stream_get_module_main_conf(s, ngx_stream_upstream_module); + + uscfp = umcf->upstreams.elts; + + for (i = 0; i < umcf->upstreams.nelts; i++) { + + uscf = uscfp[i]; + + if (uscf->host.len == host->len + && ((uscf->port == 0 && u->resolved->no_port) + || uscf->port == u->resolved->port) + && ngx_strncasecmp(uscf->host.data, host->data, host->len) == 0) + { + goto found; + } + } + + if (u->resolved->port == 0) { + ngx_log_error(NGX_LOG_ERR, c->log, 0, + "no port in upstream \"%V\"", host); + ngx_stream_proxy_finalize(s, NGX_ERROR); + return; + } + + temp.name = *host; + + cscf = ngx_stream_get_module_srv_conf(s, ngx_stream_core_module); + + ctx = ngx_resolve_start(cscf->resolver, &temp); + if (ctx == NULL) { + ngx_stream_proxy_finalize(s, NGX_ERROR); + return; + } + + if (ctx == NGX_NO_RESOLVER) { + ngx_log_error(NGX_LOG_ERR, c->log, 0, + "no resolver defined to resolve %V", host); + ngx_stream_proxy_finalize(s, NGX_ERROR); + return; + } + + ctx->name = *host; + ctx->handler = ngx_stream_proxy_resolve_handler; + ctx->data = s; + ctx->timeout = cscf->resolver_timeout; + + u->resolved->ctx = ctx; + + if (ngx_resolve_name(ctx) != NGX_OK) { + u->resolved->ctx = NULL; + ngx_stream_proxy_finalize(s, NGX_ERROR); + return; + } + + return; + } + +found: + + if (uscf == NULL) { + ngx_log_error(NGX_LOG_ALERT, c->log, 0, "no upstream configuration"); + ngx_stream_proxy_finalize(s, NGX_ERROR); + return; + } + +#if (NGX_HTTP_SSL) + u->ssl_name = uscf->host; +#endif if (uscf->peer.init(s, uscf) != NGX_OK) { ngx_stream_proxy_finalize(s, NGX_ERROR); @@ -392,55 +555,58 @@ ngx_stream_proxy_handler(ngx_stream_sess u->peer.tries = pscf->next_upstream_tries; } - u->proxy_protocol = pscf->proxy_protocol; - u->start_sec = ngx_time(); - - c->write->handler = ngx_stream_proxy_downstream_handler; - c->read->handler = ngx_stream_proxy_downstream_handler; - - if (c->type == SOCK_DGRAM) { - ngx_stream_proxy_connect(s); - return; - } - - p = ngx_pnalloc(c->pool, pscf->buffer_size); - if (p == NULL) { - ngx_stream_proxy_finalize(s, NGX_ERROR); - return; + ngx_stream_proxy_connect(s); +} + + +static ngx_int_t +ngx_stream_proxy_eval(ngx_stream_session_t *s, + ngx_stream_proxy_srv_conf_t *pscf) +{ + ngx_str_t host; + ngx_url_t url; + ngx_stream_upstream_t *u; + + if (ngx_stream_complex_value(s, pscf->upstream_value, &host) != NGX_OK) { + return NGX_ERROR; } - u->downstream_buf.start = p; - u->downstream_buf.end = p + pscf->buffer_size; - u->downstream_buf.pos = p; - u->downstream_buf.last = p; - - if (u->proxy_protocol -#if (NGX_STREAM_SSL) - && pscf->ssl == NULL -#endif - && pscf->buffer_size >= NGX_PROXY_PROTOCOL_MAX_HEADER) - { - /* optimization for a typical case */ - - ngx_log_debug0(NGX_LOG_DEBUG_STREAM, c->log, 0, - "stream proxy send PROXY protocol header"); - - p = ngx_proxy_protocol_write(c, u->downstream_buf.last, - u->downstream_buf.end); - if (p == NULL) { - ngx_stream_proxy_finalize(s, NGX_ERROR); - return; + ngx_memzero(&url, sizeof(ngx_url_t)); + + url.url = host; + url.no_resolve = 1; + + if (ngx_parse_url(s->connection->pool, &url) != NGX_OK) { + if (url.err) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "%s in upstream \"%V\"", url.err, &url.url); } - u->downstream_buf.last = p; - u->proxy_protocol = 0; + return NGX_ERROR; } - if (c->read->ready) { - ngx_post_event(c->read, &ngx_posted_events); + u = s->upstream; + + u->resolved = ngx_pcalloc(s->connection->pool, + sizeof(ngx_stream_upstream_resolved_t)); + if (u->resolved == NULL) { + return NGX_ERROR; } - ngx_stream_proxy_connect(s); + if (url.addrs && url.addrs[0].sockaddr) { + 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 = url.host; + } + + u->resolved->port = url.port; + u->resolved->no_port = url.no_port; + + return NGX_OK; } @@ -883,10 +1049,13 @@ ngx_stream_proxy_ssl_name(ngx_stream_ses u = s->upstream; - name = pscf->ssl_name; - - if (name.len == 0) { - name = pscf->upstream->host; + if (pscf->ssl_name) { + if (ngx_stream_complex_value(s, pscf->ssl_name, &name) != NGX_OK) { + return NGX_ERROR; + } + + } else { + name = u->ssl_name; } if (name.len == 0) { @@ -976,6 +1145,75 @@ ngx_stream_proxy_downstream_handler(ngx_ static void +ngx_stream_proxy_resolve_handler(ngx_resolver_ctx_t *ctx) +{ + ngx_stream_session_t *s; + ngx_stream_upstream_t *u; + ngx_stream_proxy_srv_conf_t *pscf; + ngx_stream_upstream_resolved_t *ur; + + s = ctx->data; + + u = s->upstream; + ur = u->resolved; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, s->connection->log, 0, + "stream upstream resolve"); + + if (ctx->state) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "%V could not be resolved (%i: %s)", + &ctx->name, ctx->state, + ngx_resolver_strerror(ctx->state)); + + ngx_stream_proxy_finalize(s, NGX_ERROR); + return; + } + + ur->naddrs = ctx->naddrs; + ur->addrs = ctx->addrs; + +#if (NGX_DEBUG) + { + u_char text[NGX_SOCKADDR_STRLEN]; + ngx_str_t addr; + ngx_uint_t i; + + addr.data = text; + + for (i = 0; i < ctx->naddrs; i++) { + addr.len = ngx_sock_ntop(ur->addrs[i].sockaddr, ur->addrs[i].socklen, + text, NGX_SOCKADDR_STRLEN, 0); + + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, + "name was resolved to %V", &addr); + } + } +#endif + + if (ngx_stream_upstream_create_round_robin_peer(s, ur) != NGX_OK) { + ngx_stream_proxy_finalize(s, NGX_ERROR); + return; + } + + ngx_resolve_name_done(ctx); + ur->ctx = NULL; + + u->peer.start_time = ngx_current_msec; + + pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module); + + if (pscf->next_upstream_tries + && u->peer.tries > pscf->next_upstream_tries) + { + u->peer.tries = pscf->next_upstream_tries; + } + + ngx_stream_proxy_connect(s); +} + + +static void ngx_stream_proxy_upstream_handler(ngx_event_t *ev) { ngx_stream_proxy_process_connection(ev, !ev->write); @@ -1397,6 +1635,11 @@ ngx_stream_proxy_finalize(ngx_stream_ses goto noupstream; } + if (u->resolved && u->resolved->ctx) { + ngx_resolve_name_done(u->resolved->ctx); + u->resolved->ctx = NULL; + } + if (u->peer.free && u->peer.sockaddr) { u->peer.free(&u->peer, u->peer.data, 0); u->peer.sockaddr = NULL; @@ -1471,7 +1714,7 @@ ngx_stream_proxy_create_srv_conf(ngx_con * * conf->ssl_protocols = 0; * conf->ssl_ciphers = { 0, NULL }; - * conf->ssl_name = { 0, NULL }; + * conf->ssl_name = NULL; * conf->ssl_trusted_certificate = { 0, NULL }; * conf->ssl_crl = { 0, NULL }; * conf->ssl_certificate = { 0, NULL }; @@ -1479,6 +1722,7 @@ ngx_stream_proxy_create_srv_conf(ngx_con * * conf->ssl = NULL; * conf->upstream = NULL; + * conf->upstream_value = NULL; */ conf->connect_timeout = NGX_CONF_UNSET_MSEC; @@ -1555,7 +1799,9 @@ ngx_stream_proxy_merge_srv_conf(ngx_conf ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers, "DEFAULT"); - ngx_conf_merge_str_value(conf->ssl_name, prev->ssl_name, ""); + if (conf->ssl_name == NULL) { + conf->ssl_name = prev->ssl_name; + } ngx_conf_merge_value(conf->ssl_server_name, prev->ssl_server_name, 0); @@ -1665,11 +1911,13 @@ ngx_stream_proxy_pass(ngx_conf_t *cf, ng { ngx_stream_proxy_srv_conf_t *pscf = conf; - ngx_url_t u; - ngx_str_t *value, *url; - ngx_stream_core_srv_conf_t *cscf; - - if (pscf->upstream) { + ngx_url_t u; + ngx_str_t *value, *url; + ngx_stream_complex_value_t cv; + ngx_stream_core_srv_conf_t *cscf; + ngx_stream_compile_complex_value_t ccv; + + if (pscf->upstream || pscf->upstream_value) { return "is duplicate"; } @@ -1681,6 +1929,28 @@ ngx_stream_proxy_pass(ngx_conf_t *cf, ng url = &value[1]; + ngx_memzero(&ccv, sizeof(ngx_stream_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = url; + ccv.complex_value = &cv; + + if (ngx_stream_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + if (cv.lengths) { + pscf->upstream_value = ngx_palloc(cf->pool, + sizeof(ngx_stream_complex_value_t)); + if (pscf->upstream_value == NULL) { + return NGX_CONF_ERROR; + } + + *pscf->upstream_value = cv; + + return NGX_CONF_OK; + } + ngx_memzero(&u, sizeof(ngx_url_t)); u.url = *url; diff -r 72282dd5884e -r 9757cffc1e2f src/stream/ngx_stream_upstream.h --- a/src/stream/ngx_stream_upstream.h Tue Jul 19 20:34:17 2016 +0300 +++ b/src/stream/ngx_stream_upstream.h Tue Jun 14 18:29:46 2016 +0300 @@ -79,6 +79,21 @@ struct ngx_stream_upstream_srv_conf_s { typedef struct { + ngx_str_t host; + in_port_t port; + ngx_uint_t no_port; /* unsigned no_port:1 */ + + ngx_uint_t naddrs; + ngx_resolver_addr_t *addrs; + + struct sockaddr *sockaddr; + socklen_t socklen; + + ngx_resolver_ctx_t *ctx; +} ngx_stream_upstream_resolved_t; + + +typedef struct { ngx_peer_connection_t peer; ngx_buf_t downstream_buf; ngx_buf_t upstream_buf; @@ -88,6 +103,7 @@ typedef struct { #if (NGX_STREAM_SSL) ngx_str_t ssl_name; #endif + ngx_stream_upstream_resolved_t *resolved; unsigned connected:1; unsigned proxy_protocol:1; } ngx_stream_upstream_t; diff -r 72282dd5884e -r 9757cffc1e2f src/stream/ngx_stream_upstream_round_robin.c --- a/src/stream/ngx_stream_upstream_round_robin.c Tue Jul 19 20:34:17 2016 +0300 +++ b/src/stream/ngx_stream_upstream_round_robin.c Tue Jun 14 18:29:46 2016 +0300 @@ -23,6 +23,10 @@ static ngx_int_t ngx_stream_upstream_set ngx_peer_connection_t *pc, void *data); static void ngx_stream_upstream_save_round_robin_peer_session( ngx_peer_connection_t *pc, void *data); +static ngx_int_t ngx_stream_upstream_empty_set_session( + ngx_peer_connection_t *pc, void *data); +static void ngx_stream_upstream_empty_save_session(ngx_peer_connection_t *pc, + void *data); #endif @@ -293,6 +297,123 @@ ngx_stream_upstream_init_round_robin_pee ngx_int_t +ngx_stream_upstream_create_round_robin_peer(ngx_stream_session_t *s, + ngx_stream_upstream_resolved_t *ur) +{ + u_char *p; + size_t len; + socklen_t socklen; + ngx_uint_t i, n; + struct sockaddr *sockaddr; + ngx_stream_upstream_rr_peer_t *peer, **peerp; + ngx_stream_upstream_rr_peers_t *peers; + ngx_stream_upstream_rr_peer_data_t *rrp; + + rrp = s->upstream->peer.data; + + if (rrp == NULL) { + rrp = ngx_palloc(s->connection->pool, + sizeof(ngx_stream_upstream_rr_peer_data_t)); + if (rrp == NULL) { + return NGX_ERROR; + } + + s->upstream->peer.data = rrp; + } + + peers = ngx_pcalloc(s->connection->pool, + sizeof(ngx_stream_upstream_rr_peers_t)); + if (peers == NULL) { + return NGX_ERROR; + } + + peer = ngx_pcalloc(s->connection->pool, + sizeof(ngx_stream_upstream_rr_peer_t) * ur->naddrs); + if (peer == NULL) { + return NGX_ERROR; + } + + peers->single = (ur->naddrs == 1); + peers->number = ur->naddrs; + peers->name = &ur->host; + + if (ur->sockaddr) { + peer[0].sockaddr = ur->sockaddr; + peer[0].socklen = ur->socklen; + peer[0].name = ur->host; + peer[0].weight = 1; + peer[0].effective_weight = 1; + peer[0].current_weight = 0; + peer[0].max_fails = 1; + peer[0].fail_timeout = 10; + peers->peer = peer; + + } else { + peerp = &peers->peer; + + for (i = 0; i < ur->naddrs; i++) { + + socklen = ur->addrs[i].socklen; + + sockaddr = ngx_palloc(s->connection->pool, socklen); + if (sockaddr == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(sockaddr, ur->addrs[i].sockaddr, socklen); + ngx_inet_set_port(sockaddr, ur->port); + + p = ngx_pnalloc(s->connection->pool, NGX_SOCKADDR_STRLEN); + if (p == NULL) { + return NGX_ERROR; + } + + len = ngx_sock_ntop(sockaddr, socklen, p, NGX_SOCKADDR_STRLEN, 1); + + peer[i].sockaddr = sockaddr; + peer[i].socklen = socklen; + peer[i].name.len = len; + peer[i].name.data = p; + peer[i].weight = 1; + peer[i].effective_weight = 1; + peer[i].current_weight = 0; + peer[i].max_fails = 1; + peer[i].fail_timeout = 10; + *peerp = &peer[i]; + peerp = &peer[i].next; + } + } + + rrp->peers = peers; + rrp->current = NULL; + + if (rrp->peers->number <= 8 * sizeof(uintptr_t)) { + rrp->tried = &rrp->data; + rrp->data = 0; + + } else { + n = (rrp->peers->number + (8 * sizeof(uintptr_t) - 1)) + / (8 * sizeof(uintptr_t)); + + rrp->tried = ngx_pcalloc(s->connection->pool, n * sizeof(uintptr_t)); + if (rrp->tried == NULL) { + return NGX_ERROR; + } + } + + s->upstream->peer.get = ngx_stream_upstream_get_round_robin_peer; + s->upstream->peer.free = ngx_stream_upstream_free_round_robin_peer; + s->upstream->peer.tries = ngx_stream_upstream_tries(rrp->peers); +#if (NGX_STREAM_SSL) + s->upstream->peer.set_session = ngx_stream_upstream_empty_set_session; + s->upstream->peer.save_session = ngx_stream_upstream_empty_save_session; +#endif + + return NGX_OK; +} + + +ngx_int_t ngx_stream_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, void *data) { ngx_stream_upstream_rr_peer_data_t *rrp = data; @@ -699,4 +820,18 @@ ngx_stream_upstream_save_round_robin_pee } } + +static ngx_int_t +ngx_stream_upstream_empty_set_session(ngx_peer_connection_t *pc, void *data) +{ + return NGX_OK; +} + + +static void +ngx_stream_upstream_empty_save_session(ngx_peer_connection_t *pc, void *data) +{ + return; +} + #endif diff -r 72282dd5884e -r 9757cffc1e2f src/stream/ngx_stream_upstream_round_robin.h --- a/src/stream/ngx_stream_upstream_round_robin.h Tue Jul 19 20:34:17 2016 +0300 +++ b/src/stream/ngx_stream_upstream_round_robin.h Tue Jun 14 18:29:46 2016 +0300 @@ -130,6 +130,8 @@ ngx_int_t ngx_stream_upstream_init_round ngx_stream_upstream_srv_conf_t *us); ngx_int_t ngx_stream_upstream_init_round_robin_peer(ngx_stream_session_t *s, ngx_stream_upstream_srv_conf_t *us); +ngx_int_t ngx_stream_upstream_create_round_robin_peer(ngx_stream_session_t *s, + ngx_stream_upstream_resolved_t *ur); ngx_int_t ngx_stream_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, void *data); void ngx_stream_upstream_free_round_robin_peer(ngx_peer_connection_t *pc, From arut at nginx.com Thu Jul 21 10:33:03 2016 From: arut at nginx.com (Roman Arutyunyan) Date: Thu, 21 Jul 2016 10:33:03 +0000 Subject: [njs] Fixed closing file descriptor on error. Message-ID: details: http://hg.nginx.org/njs/rev/1cfc38ab7ba1 branches: changeset: 127:1cfc38ab7ba1 user: Roman Arutyunyan date: Thu Jul 21 11:39:00 2016 +0300 description: Fixed closing file descriptor on error. Found by Coverity (CID 1364196, 1364197, 1364198, 1364199). diffstat: nginx/ngx_http_js_module.c | 6 ++++-- nginx/ngx_stream_js_module.c | 8 +++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diffs (76 lines): diff -r faab537db6f8 -r 1cfc38ab7ba1 nginx/ngx_http_js_module.c --- a/nginx/ngx_http_js_module.c Wed Jul 20 21:40:34 2016 +0300 +++ b/nginx/ngx_http_js_module.c Thu Jul 21 11:39:00 2016 +0300 @@ -1249,6 +1249,7 @@ ngx_http_js_include(ngx_conf_t *cf, ngx_ if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_EMERG, cf->log, ngx_errno, ngx_fd_info_n " \"%s\" failed", file.data); + (void) ngx_close_file(fd); return NGX_CONF_ERROR; } @@ -1256,6 +1257,7 @@ ngx_http_js_include(ngx_conf_t *cf, ngx_ start = ngx_pnalloc(cf->pool, size); if (start == NULL) { + (void) ngx_close_file(fd); return NGX_CONF_ERROR; } @@ -1265,7 +1267,7 @@ ngx_http_js_include(ngx_conf_t *cf, ngx_ ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, ngx_read_fd_n " \"%s\" failed", file.data); - ngx_close_file(fd); + (void) ngx_close_file(fd); return NGX_CONF_ERROR; } @@ -1274,7 +1276,7 @@ ngx_http_js_include(ngx_conf_t *cf, ngx_ ngx_read_fd_n " has read only %z of %O from \"%s\"", n, size, file.data); - ngx_close_file(fd); + (void) ngx_close_file(fd); return NGX_CONF_ERROR; } diff -r faab537db6f8 -r 1cfc38ab7ba1 nginx/ngx_stream_js_module.c --- a/nginx/ngx_stream_js_module.c Wed Jul 20 21:40:34 2016 +0300 +++ b/nginx/ngx_stream_js_module.c Thu Jul 21 11:39:00 2016 +0300 @@ -456,6 +456,7 @@ ngx_stream_js_include(ngx_conf_t *cf, ng if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_EMERG, cf->log, ngx_errno, ngx_fd_info_n " \"%s\" failed", file.data); + (void) ngx_close_file(fd); return NGX_CONF_ERROR; } @@ -463,6 +464,7 @@ ngx_stream_js_include(ngx_conf_t *cf, ng start = ngx_pnalloc(cf->pool, size); if (start == NULL) { + (void) ngx_close_file(fd); return NGX_CONF_ERROR; } @@ -472,16 +474,16 @@ ngx_stream_js_include(ngx_conf_t *cf, ng ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, ngx_read_fd_n " \"%s\" failed", file.data); - ngx_close_file(fd); + (void) ngx_close_file(fd); return NGX_CONF_ERROR; } if ((size_t) n != size) { ngx_log_error(NGX_LOG_ALERT, cf->log, 0, - ngx_read_fd_n " has read only %z of %O from \"%s\"", + ngx_read_fd_n " has read only %z of %uz from \"%s\"", n, size, file.data); - ngx_close_file(fd); + (void) ngx_close_file(fd); return NGX_CONF_ERROR; } From mdounin at mdounin.ru Thu Jul 21 13:44:30 2016 From: mdounin at mdounin.ru (Maxim Dounin) Date: Thu, 21 Jul 2016 16:44:30 +0300 Subject: [PATCH 1 of 2] HTTP: add support for trailers in HTTP responses In-Reply-To: <09C74FD3-25B0-45D8-8EA4-84DCDFD77CC5@gmail.com> References: <20160707150047.GJ30781@mdounin.ru> <20160707232029.GO30781@mdounin.ru> <20160713184331.GQ57459@mdounin.ru> <56CE925B-66FF-47B6-A468-64289F47D39E@gmail.com> <20160721012322.GT57459@mdounin.ru> <09C74FD3-25B0-45D8-8EA4-84DCDFD77CC5@gmail.com> Message-ID: <20160721134430.GV57459@mdounin.ru> Hello! On Wed, Jul 20, 2016 at 06:33:11PM -0700, Alexey Ivanov wrote: > > > On Jul 20, 2016, at 6:23 PM, Maxim Dounin wrote: > > > > Hello! > > > > On Wed, Jul 20, 2016 at 03:34:46PM -0700, Alexey Ivanov wrote: > > > >> Speaking of trailers: we had couple of use cases for HTTP > >> trailers, most of them were around streaming data to user. > >> > >> For example, when webpage is generated we send headers and part > >> of the body(usually up to ``) almost immediately, but > >> then we start querying all the micro services for the content > >> (SOA, yay!). > >> The problem is that upstreams will inevitably fail/timeout, and > >> when that happens there is no way to pass any metadata about the > >> error to nginx, since headers are already sent. Using trailers > >> here may improve MTTR since backend metadata is available on the > >> frontend. > >> > >> Another example may be computing checksums for data while you > >> stream it and putting it in the trailer. This should reduce TTFB > >> by quite a lot on some workloads we have. > > > > Do you actually use something like this, or know places where > > something like this is actually used? > These are examples from our production. Currently we are using > workarounds for both of these problems. Though I'm not sure that > we would use trailers if they were supported, since it's one of > very obscure HTTP/1.1 features that people do not usually know > about. > > That is starting to change bit by bit though, since people try > using gRPC more and more. Could you please elaborate what exactly you do use now and if you know any examples of trailers being used instead? -- Maxim Dounin http://nginx.org/ From pankajitbhu at gmail.com Fri Jul 22 03:09:52 2016 From: pankajitbhu at gmail.com (Pankaj Chaudhary) Date: Fri, 22 Jul 2016 08:39:52 +0530 Subject: how i can use third party library while building own nginx module Message-ID: Hi, how i can use third party library while building own nginx module as i am using third party libraries. Thanks, Pankaj -------------- next part -------------- An HTML attachment was scrubbed... URL: From ranier.vf at gmail.com Fri Jul 22 11:24:38 2016 From: ranier.vf at gmail.com (Ranier Vf) Date: Fri, 22 Jul 2016 08:24:38 -0300 Subject: how i can use third party library while building own nginx module In-Reply-To: References: Message-ID: Hi, Can you read documentation before? https://nginx.org/en/docs/configure.html https://nginx.org/en/docs/howto_build_on_win32.html http://www.evanmiller.org/nginx-modules-guide.html Last link is useful for you I think. Best, Ranier Vilela p.s: Try make objective questions. 2016-07-22 0:09 GMT-03:00 Pankaj Chaudhary : > Hi, > > how i can use third party library while building own nginx module as i am > using third party libraries. > > Thanks, > Pankaj > > _______________________________________________ > nginx-devel mailing list > nginx-devel at nginx.org > http://mailman.nginx.org/mailman/listinfo/nginx-devel > -------------- next part -------------- An HTML attachment was scrubbed... URL: From igor at sysoev.ru Fri Jul 22 12:04:47 2016 From: igor at sysoev.ru (Igor Sysoev) Date: Fri, 22 Jul 2016 12:04:47 +0000 Subject: [njs] njs_vm_function() must return only function. Message-ID: details: http://hg.nginx.org/njs/rev/f59ab0fccecb branches: changeset: 128:f59ab0fccecb user: Igor Sysoev date: Thu Jul 21 20:51:22 2016 +0300 description: njs_vm_function() must return only function. diffstat: njs/njs_variable.c | 6 +++++- 1 files changed, 5 insertions(+), 1 deletions(-) diffs (16 lines): diff -r 1cfc38ab7ba1 -r f59ab0fccecb njs/njs_variable.c --- a/njs/njs_variable.c Thu Jul 21 11:39:00 2016 +0300 +++ b/njs/njs_variable.c Thu Jul 21 20:51:22 2016 +0300 @@ -139,7 +139,11 @@ njs_vm_function(njs_vm_t *vm, nxt_str_t value = (njs_value_t *) ((u_char *) vm->global_scope + njs_offset(var->index) - NJS_INDEX_GLOBAL_OFFSET); - return value->data.u.function; + if (njs_is_function(value)) { + return value->data.u.function; + } + + return NULL; } From igor at sysoev.ru Fri Jul 22 12:04:49 2016 From: igor at sysoev.ru (Igor Sysoev) Date: Fri, 22 Jul 2016 12:04:49 +0000 Subject: [njs] A fix of code generation of logical operations. Message-ID: details: http://hg.nginx.org/njs/rev/41689f60372a branches: changeset: 129:41689f60372a user: Igor Sysoev date: Thu Jul 21 21:37:46 2016 +0300 description: A fix of code generation of logical operations. diffstat: njs/njs_generator.c | 5 ----- njs/test/njs_unit_test.c | 3 +++ 2 files changed, 3 insertions(+), 5 deletions(-) diffs (28 lines): diff -r f59ab0fccecb -r 41689f60372a njs/njs_generator.c --- a/njs/njs_generator.c Thu Jul 21 20:51:22 2016 +0300 +++ b/njs/njs_generator.c Thu Jul 21 21:37:46 2016 +0300 @@ -1666,11 +1666,6 @@ njs_generate_test_jump_expression(njs_vm test_jump->code.retval = NJS_VMCODE_RETVAL; test_jump->value = node->left->index; - ret = njs_generator_node_index_release(vm, parser, node->left); - if (nxt_slow_path(ret != NXT_OK)) { - return ret; - } - node->index = njs_generator_dest_index(vm, parser, node); if (nxt_slow_path(node->index == NJS_INDEX_ERROR)) { return node->index; diff -r f59ab0fccecb -r 41689f60372a njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Thu Jul 21 20:51:22 2016 +0300 +++ b/njs/test/njs_unit_test.c Thu Jul 21 21:37:46 2016 +0300 @@ -1476,6 +1476,9 @@ static njs_unit_test_t njs_test[] = { nxt_string("var a = 3; if (true) if (false); else; a = 2; a"), nxt_string("2") }, + { nxt_string("var a = [3], b; if (1==1||2==2) { b = '1'+'2'+a[0] }; b }"), + nxt_string("123") }, + /* do while. */ { nxt_string("do { break } if (false)"), From igor at sysoev.ru Fri Jul 22 12:04:50 2016 From: igor at sysoev.ru (Igor Sysoev) Date: Fri, 22 Jul 2016 12:04:50 +0000 Subject: [njs] A line number in error messages was incorrect if a script Message-ID: details: http://hg.nginx.org/njs/rev/eae6c48ff5c1 branches: changeset: 130:eae6c48ff5c1 user: Igor Sysoev date: Thu Jul 21 21:42:58 2016 +0300 description: A line number in error messages was incorrect if a script has comments. diffstat: njs/njs_lexer.c | 8 +++++++- njs/test/njs_unit_test.c | 6 ++++++ 2 files changed, 13 insertions(+), 1 deletions(-) diffs (42 lines): diff -r 41689f60372a -r eae6c48ff5c1 njs/njs_lexer.c --- a/njs/njs_lexer.c Thu Jul 21 21:37:46 2016 +0300 +++ b/njs/njs_lexer.c Thu Jul 21 21:42:58 2016 +0300 @@ -636,8 +636,9 @@ njs_lexer_division(njs_lexer_t *lexer, n for (p = lexer->start; p < lexer->end; p++) { - if (*p == '\r' || *p == '\n') { + if (*p == '\n') { lexer->start = p + 1; + lexer->line++; return NJS_TOKEN_LINE_END; } } @@ -647,6 +648,11 @@ njs_lexer_division(njs_lexer_t *lexer, n for (p = lexer->start; p < lexer->end; p++) { + if (*p == '\n') { + lexer->line++; + continue; + } + if (*p == '*') { p++; diff -r 41689f60372a -r eae6c48ff5c1 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Thu Jul 21 21:37:46 2016 +0300 +++ b/njs/test/njs_unit_test.c Thu Jul 21 21:42:58 2016 +0300 @@ -52,6 +52,12 @@ static njs_unit_test_t njs_test[] = { nxt_string("var + a"), nxt_string("SyntaxError: Unexpected token \"+\" in 1") }, + { nxt_string("//\r\n; var + a"), + nxt_string("SyntaxError: Unexpected token \"+\" in 2") }, + + { nxt_string("/*\n*/; var + a"), + nxt_string("SyntaxError: Unexpected token \"+\" in 2") }, + { nxt_string("var \n a \n = 1; a"), nxt_string("1") }, From igor at sysoev.ru Fri Jul 22 12:04:51 2016 From: igor at sysoev.ru (Igor Sysoev) Date: Fri, 22 Jul 2016 12:04:51 +0000 Subject: [njs] Now a make command does not fail for obscure reason at Message-ID: details: http://hg.nginx.org/njs/rev/f0c94dd2bdb3 branches: changeset: 131:f0c94dd2bdb3 user: Igor Sysoev date: Fri Jul 22 14:15:54 2016 +0300 description: Now a make command does not fail for obscure reason at the very start or after "make clean" command but it offers to run the ./configure command instead. This change is not compatible with BSD PMake which does not support both "-include" and "sinclude" directives but only ".sinclude" directive so GNU Make should be used. diffstat: Makefile | 10 ++++++++-- nxt/auto/configure | 7 +++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diffs (44 lines): diff -r eae6c48ff5c1 -r f0c94dd2bdb3 Makefile --- a/Makefile Thu Jul 21 21:42:58 2016 +0300 +++ b/Makefile Fri Jul 22 14:15:54 2016 +0300 @@ -3,10 +3,16 @@ NJS_VER = 20150922 NXT_LIB = nxt -include $(NXT_LIB)/Makefile.conf +-include $(NXT_LIB)/Makefile.conf NXT_BUILDDIR = build +unconfigured: + @echo + @echo " Please run ./configure before make" + @echo + +main: $(NXT_BUILDDIR)/libnjs.a $(NXT_BUILDDIR)/libnjs.a: \ $(NXT_BUILDDIR)/njscript.o \ @@ -81,7 +87,7 @@ test: \ clean: rm -rf $(NXT_BUILDDIR) - rm $(NXT_LIB)/Makefile.conf $(NXT_LIB)/nxt_auto_config.h + rm -f $(NXT_LIB)/Makefile.conf $(NXT_LIB)/nxt_auto_config.h tarball: make clean diff -r eae6c48ff5c1 -r f0c94dd2bdb3 nxt/auto/configure --- a/nxt/auto/configure Thu Jul 21 21:42:58 2016 +0300 +++ b/nxt/auto/configure Fri Jul 22 14:15:54 2016 +0300 @@ -55,3 +55,10 @@ END . ${NXT_AUTO}memalign . ${NXT_AUTO}getrandom . ${NXT_AUTO}pcre + + +cat << END >> $NXT_MAKEFILE_CONF + +target: main + +END From igor at sysoev.ru Fri Jul 22 12:04:53 2016 From: igor at sysoev.ru (Igor Sysoev) Date: Fri, 22 Jul 2016 12:04:53 +0000 Subject: [njs] Duplicate function names are disabled. Message-ID: details: http://hg.nginx.org/njs/rev/cdb8d20935ee branches: changeset: 132:cdb8d20935ee user: Igor Sysoev date: Fri Jul 22 14:38:06 2016 +0300 description: Duplicate function names are disabled. diffstat: njs/njs_parser.c | 4 ++-- njs/njs_parser.h | 1 + njs/njs_variable.c | 31 +++++++++++++++++++++++++++++++ njs/njs_variable.h | 1 + njs/test/njs_unit_test.c | 9 +++++++++ 5 files changed, 44 insertions(+), 2 deletions(-) diffs (110 lines): diff -r f0c94dd2bdb3 -r cdb8d20935ee njs/njs_parser.c --- a/njs/njs_parser.c Fri Jul 22 14:15:54 2016 +0300 +++ b/njs/njs_parser.c Fri Jul 22 14:38:06 2016 +0300 @@ -290,7 +290,6 @@ njs_parser_match(njs_vm_t *vm, njs_parse static njs_token_t njs_parser_function_declaration(njs_vm_t *vm, njs_parser_t *parser) { - nxt_uint_t level; njs_token_t token; njs_value_t *value; njs_variable_t *var; @@ -313,7 +312,7 @@ njs_parser_function_declaration(njs_vm_t return NJS_TOKEN_ILLEGAL; } - var = njs_parser_variable(vm, parser, &level); + var = njs_parser_name_alloc(vm, parser); if (nxt_slow_path(var == NULL)) { return NJS_TOKEN_ERROR; } @@ -2241,6 +2240,7 @@ njs_parser_error(njs_vm_t *vm, njs_parse "SyntaxError: Invalid Unicode code point \"%.*s\" in %u", "SyntaxError: Unterminated RegExp \"%.*s\" in %u", "SyntaxError: Invalid RegExp flags \"%.*s\" in %u", + "SyntaxError: Duplicate declaration \"%.*s\" in %u", }; msg = errors[err]; diff -r f0c94dd2bdb3 -r cdb8d20935ee njs/njs_parser.h --- a/njs/njs_parser.h Fri Jul 22 14:15:54 2016 +0300 +++ b/njs/njs_parser.h Fri Jul 22 14:38:06 2016 +0300 @@ -324,6 +324,7 @@ typedef enum { NJS_PARSER_ERROR_UNICODE, NJS_PARSER_ERROR_UNTERMINATED_REGEXP, NJS_PARSER_ERROR_REGEXP_FLAGS, + NJS_PARSER_ERROR_DUPLICATE_DECLARATION, } njs_parser_error_t; diff -r f0c94dd2bdb3 -r cdb8d20935ee njs/njs_variable.c --- a/njs/njs_variable.c Fri Jul 22 14:15:54 2016 +0300 +++ b/njs/njs_variable.c Fri Jul 22 14:38:06 2016 +0300 @@ -54,6 +54,37 @@ static const nxt_lvlhsh_proto_t njs_var njs_variable_t * +njs_parser_name_alloc(njs_vm_t *vm, njs_parser_t *parser) +{ + nxt_int_t ret; + njs_variable_t *var; + nxt_lvlhsh_query_t lhq; + + var = njs_variable_alloc(vm, parser, &parser->lexer->text); + if (nxt_slow_path(var == NULL)) { + return NULL; + } + + lhq.key_hash = parser->lexer->key_hash; + lhq.key = parser->lexer->text; + lhq.replace = 0; + lhq.value = var; + lhq.proto = &njs_variables_hash_proto; + lhq.pool = vm->mem_cache_pool; + + ret = nxt_lvlhsh_insert(&parser->variables_hash, &lhq); + + if (nxt_fast_path(ret == NXT_OK)) { + return var; + } + + (void) njs_parser_error(vm, parser, NJS_PARSER_ERROR_DUPLICATE_DECLARATION); + + return NULL; +} + + +njs_variable_t * njs_parser_variable(njs_vm_t *vm, njs_parser_t *parser, nxt_uint_t *level) { nxt_int_t ret; diff -r f0c94dd2bdb3 -r cdb8d20935ee njs/njs_variable.h --- a/njs/njs_variable.h Fri Jul 22 14:15:54 2016 +0300 +++ b/njs/njs_variable.h Fri Jul 22 14:38:06 2016 +0300 @@ -26,6 +26,7 @@ typedef struct { } njs_variable_t; +njs_variable_t *njs_parser_name_alloc(njs_vm_t *vm, njs_parser_t *parser); njs_variable_t *njs_parser_variable(njs_vm_t *vm, njs_parser_t *parser, nxt_uint_t *level); njs_value_t *njs_variable_value(njs_parser_t *parser, njs_index_t index); diff -r f0c94dd2bdb3 -r cdb8d20935ee njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Fri Jul 22 14:15:54 2016 +0300 +++ b/njs/test/njs_unit_test.c Fri Jul 22 14:38:06 2016 +0300 @@ -67,6 +67,15 @@ static njs_unit_test_t njs_test[] = { nxt_string("var a = 1; var b; a"), nxt_string("1") }, + { nxt_string("function f(){} function f(){}"), + nxt_string("SyntaxError: Duplicate declaration \"f\" in 1") }, + + { nxt_string("var f = 1; function f() {}"), + nxt_string("SyntaxError: Duplicate declaration \"f\" in 1") }, + + { nxt_string("function f() {} var f = 1; f"), + nxt_string("1") }, + /* Numbers. */ { nxt_string("999999999999999999999"), From igor at sysoev.ru Fri Jul 22 14:00:34 2016 From: igor at sysoev.ru (Igor Sysoev) Date: Fri, 22 Jul 2016 14:00:34 +0000 Subject: [njs] Added tag 0.1.0 for changeset cdb8d20935ee Message-ID: details: http://hg.nginx.org/njs/rev/37373519f505 branches: changeset: 133:37373519f505 user: Igor Sysoev date: Fri Jul 22 17:00:05 2016 +0300 description: Added tag 0.1.0 for changeset cdb8d20935ee diffstat: .hgtags | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diffs (6 lines): diff -r cdb8d20935ee -r 37373519f505 .hgtags --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.hgtags Fri Jul 22 17:00:05 2016 +0300 @@ -0,0 +1,2 @@ +cdb8d20935ee96f1fa0c99d994d4b11cefcbc119 help +cdb8d20935ee96f1fa0c99d994d4b11cefcbc119 0.1.0 From vl at nginx.com Fri Jul 22 14:46:23 2016 From: vl at nginx.com (Vladimir Homutov) Date: Fri, 22 Jul 2016 14:46:23 +0000 Subject: [nginx] Fixed regex captures handling without PCRE. Message-ID: details: http://hg.nginx.org/nginx/rev/af642539cd53 branches: changeset: 6644:af642539cd53 user: Vladimir Homutov date: Wed Jul 06 14:33:40 2016 +0300 description: Fixed regex captures handling without PCRE. If PCRE is disabled, captures were treated as normal variables in ngx_http_script_compile(), while code calculating flushes array length in ngx_http_compile_complex_value() did not account captures as variables. This could lead to write outside of the array boundary when setting last element to -1. Found with AddressSanitizer. diffstat: src/http/ngx_http_script.c | 14 ++++++++------ src/stream/ngx_stream_script.c | 14 ++++++++------ 2 files changed, 16 insertions(+), 12 deletions(-) diffs (66 lines): diff -r 9757cffc1e2f -r af642539cd53 src/http/ngx_http_script.c --- a/src/http/ngx_http_script.c Tue Jun 14 18:29:46 2016 +0300 +++ b/src/http/ngx_http_script.c Wed Jul 06 14:33:40 2016 +0300 @@ -350,11 +350,9 @@ ngx_http_script_compile(ngx_http_script_ goto invalid_variable; } + if (sc->source->data[i] >= '1' && sc->source->data[i] <= '9') { #if (NGX_PCRE) - { - ngx_uint_t n; - - if (sc->source->data[i] >= '1' && sc->source->data[i] <= '9') { + ngx_uint_t n; n = sc->source->data[i] - '0'; @@ -371,9 +369,13 @@ ngx_http_script_compile(ngx_http_script_ i++; continue; +#else + ngx_conf_log_error(NGX_LOG_EMERG, sc->cf, 0, + "using variable \"$%c\" requires " + "PCRE library", sc->source->data[i]); + return NGX_ERROR; +#endif } - } -#endif if (sc->source->data[i] == '{') { bracket = 1; diff -r 9757cffc1e2f -r af642539cd53 src/stream/ngx_stream_script.c --- a/src/stream/ngx_stream_script.c Tue Jun 14 18:29:46 2016 +0300 +++ b/src/stream/ngx_stream_script.c Wed Jul 06 14:33:40 2016 +0300 @@ -282,11 +282,9 @@ ngx_stream_script_compile(ngx_stream_scr goto invalid_variable; } + if (sc->source->data[i] >= '1' && sc->source->data[i] <= '9') { #if (NGX_PCRE) - { - ngx_uint_t n; - - if (sc->source->data[i] >= '1' && sc->source->data[i] <= '9') { + ngx_uint_t n; n = sc->source->data[i] - '0'; @@ -297,9 +295,13 @@ ngx_stream_script_compile(ngx_stream_scr i++; continue; +#else + ngx_conf_log_error(NGX_LOG_EMERG, sc->cf, 0, + "using variable \"$%c\" requires " + "PCRE library", sc->source->data[i]); + return NGX_ERROR; +#endif } - } -#endif if (sc->source->data[i] == '{') { bracket = 1; From lee at leev.net Fri Jul 22 15:56:56 2016 From: lee at leev.net (Lee Valentine) Date: Fri, 22 Jul 2016 16:56:56 +0100 Subject: Nested block config Message-ID: Hi, Is it possible to create a module with a nested block config. Eg, this works: command { command1 ...; command2 ...; } However, this doesn't: command { command1 { commandA; } command2 { commandB; } } The code that fails doesn't allow it is https://github.com/nginx/nginx/blob/4c03c80e12158bd6daf3c6608aca3e3acce56640/src/core/ngx_conf_file.c#L263:L266 If I remove those lines, everything works as expected. Is there a reason for not allowing the second style config? Cheers, Lee -------------- next part -------------- An HTML attachment was scrubbed... URL: From wperry at SonicWALL.com Sun Jul 24 23:09:11 2016 From: wperry at SonicWALL.com (Perry, William) Date: Sun, 24 Jul 2016 23:09:11 +0000 Subject: Any way to allow secure SSL renegotiation? Message-ID: <99047693-A839-4191-91F1-147ABE89D26B@sonicwall.com> ?Secure? meaning using TLS only, RFC5746 style. I would like to have a module that decides which certificate authorities are valid based on aspects of a request (location, type of authentication required, etc). Some user populations will require client certificates from one CA, others from another, and others will not use client certificates at all. Specifying SSL client certificates as ?optional? for the entire server is not exactly a great user experience, and I would prefer not to send the trusted CAs for all user populations to every user. Currently works in Apache and mod_ssl with some extra protections to only allow renegotiation to be triggered by the server, but I want to get NGINX handling all of the TLS traffic. Has anyone come up with a relatively simple patch to allow NGINX to start the renegotiation process? Figured I would check before reinventing the wheel. -Bill Perry From igor at sysoev.ru Mon Jul 25 12:18:17 2016 From: igor at sysoev.ru (Igor Sysoev) Date: Mon, 25 Jul 2016 12:18:17 +0000 Subject: [njs] Removed tag help Message-ID: details: http://hg.nginx.org/njs/rev/be657808a12b branches: changeset: 134:be657808a12b user: Igor Sysoev date: Mon Jul 25 15:17:51 2016 +0300 description: Removed tag help diffstat: .hgtags | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diffs (8 lines): diff -r 37373519f505 -r be657808a12b .hgtags --- a/.hgtags Fri Jul 22 17:00:05 2016 +0300 +++ b/.hgtags Mon Jul 25 15:17:51 2016 +0300 @@ -1,2 +1,4 @@ cdb8d20935ee96f1fa0c99d994d4b11cefcbc119 help cdb8d20935ee96f1fa0c99d994d4b11cefcbc119 0.1.0 +cdb8d20935ee96f1fa0c99d994d4b11cefcbc119 help +0000000000000000000000000000000000000000 help From igor at sysoev.ru Mon Jul 25 12:35:15 2016 From: igor at sysoev.ru (Igor Sysoev) Date: Mon, 25 Jul 2016 12:35:15 +0000 Subject: [njs] Removed tag help from .hgtags Message-ID: details: http://hg.nginx.org/njs/rev/1792ce945acf branches: changeset: 135:1792ce945acf user: Igor Sysoev date: Mon Jul 25 15:34:53 2016 +0300 description: Removed tag help from .hgtags diffstat: .hgtags | 3 --- 1 files changed, 0 insertions(+), 3 deletions(-) diffs (8 lines): diff -r be657808a12b -r 1792ce945acf .hgtags --- a/.hgtags Mon Jul 25 15:17:51 2016 +0300 +++ b/.hgtags Mon Jul 25 15:34:53 2016 +0300 @@ -1,4 +1,1 @@ -cdb8d20935ee96f1fa0c99d994d4b11cefcbc119 help cdb8d20935ee96f1fa0c99d994d4b11cefcbc119 0.1.0 -cdb8d20935ee96f1fa0c99d994d4b11cefcbc119 help -0000000000000000000000000000000000000000 help From mdounin at mdounin.ru Tue Jul 26 14:02:12 2016 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 26 Jul 2016 14:02:12 +0000 Subject: [nginx] nginx-1.11.3-RELEASE Message-ID: details: http://hg.nginx.org/nginx/rev/b83a067949a3 branches: changeset: 6645:b83a067949a3 user: Maxim Dounin date: Tue Jul 26 16:58:58 2016 +0300 description: nginx-1.11.3-RELEASE diffstat: docs/xml/nginx/changes.xml | 81 ++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 81 insertions(+), 0 deletions(-) diffs (91 lines): diff --git a/docs/xml/nginx/changes.xml b/docs/xml/nginx/changes.xml --- a/docs/xml/nginx/changes.xml +++ b/docs/xml/nginx/changes.xml @@ -5,6 +5,87 @@ + + + + +?????? accept_mutex ?? ????????? ????????. + + +now the "accept_mutex" directive is turned off by default. + + + + + +?????? nginx ?????????? EPOLLEXCLUSIVE ?? Linux. + + +now nginx uses EPOLLEXCLUSIVE on Linux. + + + + + +?????? ngx_stream_geo_module. + + +the ngx_stream_geo_module. + + + + + +?????? ngx_stream_geoip_module. + + +the ngx_stream_geoip_module. + + + + + +?????? ngx_stream_split_clients_module. + + +the ngx_stream_split_clients_module. + + + + + +????????? proxy_pass ? proxy_ssl_name ? ?????? stream +???????????? ??????????. + + +variables support +in the "proxy_pass" and "proxy_ssl_name" directives in the stream module. + + + + + +?????? ??????? ??? ????????????? HTTP/2. + + +socket leak when using HTTP/2. + + + + + +? configure.
+??????? Piotr Sikora. +
+ +in configure tests.
+Thanks to Piotr Sikora. +
+
+ +
+ + From mdounin at mdounin.ru Tue Jul 26 14:02:15 2016 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 26 Jul 2016 14:02:15 +0000 Subject: [nginx] release-1.11.3 tag Message-ID: details: http://hg.nginx.org/nginx/rev/eaba11dddc70 branches: changeset: 6646:eaba11dddc70 user: Maxim Dounin date: Tue Jul 26 16:58:58 2016 +0300 description: release-1.11.3 tag diffstat: .hgtags | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diffs (8 lines): diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -401,3 +401,4 @@ 13070ecfda67397985f0e986eb9c42ecb46d05b5 271ee30c6791847980cd139d31807541f5e569bf release-1.11.0 cb783d9cc19761e14e1285d91c38f4b84d0b8756 release-1.11.1 4d3b3a13a8cf5fc3351a7f167d1c13325e00f21c release-1.11.2 +b83a067949a3384a49fd3d943eb8d0997b31f87b release-1.11.3 From igor at sysoev.ru Tue Jul 26 14:58:16 2016 From: igor at sysoev.ru (Igor Sysoev) Date: Tue, 26 Jul 2016 14:58:16 +0000 Subject: [njs] A dist target in Makefile. Message-ID: details: http://hg.nginx.org/njs/rev/44e1a8aaa04e branches: changeset: 136:44e1a8aaa04e user: Igor Sysoev date: Tue Jul 26 15:09:07 2016 +0300 description: A dist target in Makefile. diffstat: Makefile | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diffs (19 lines): diff -r 1792ce945acf -r 44e1a8aaa04e Makefile --- a/Makefile Mon Jul 25 15:34:53 2016 +0300 +++ b/Makefile Tue Jul 26 15:09:07 2016 +0300 @@ -1,5 +1,5 @@ -NJS_VER = 20150922 +NJS_VER = 0.1.0 NXT_LIB = nxt @@ -89,7 +89,7 @@ clean: rm -rf $(NXT_BUILDDIR) rm -f $(NXT_LIB)/Makefile.conf $(NXT_LIB)/nxt_auto_config.h -tarball: +dist: make clean mkdir njs-$(NJS_VER) cp -rp configure Makefile LICENSE README $(NXT_LIB) njs nginx \ From igor at sysoev.ru Tue Jul 26 14:58:18 2016 From: igor at sysoev.ru (Igor Sysoev) Date: Tue, 26 Jul 2016 14:58:18 +0000 Subject: [njs] Segfaults have been fixed when incorrect operands were used Message-ID: details: http://hg.nginx.org/njs/rev/e4f1fda52fe8 branches: changeset: 137:e4f1fda52fe8 user: Igor Sysoev date: Tue Jul 26 16:25:58 2016 +0300 description: Segfaults have been fixed when incorrect operands were used in left-hand side expressions. diffstat: njs/njs_generator.c | 4 ---- njs/njs_nonrecursive_parser.c | 1 - njs/njs_parser.c | 2 -- njs/njs_parser.h | 1 - njs/njs_parser_expression.c | 15 ++++++++++----- njs/test/njs_unit_test.c | 13 +++++++++++-- 6 files changed, 21 insertions(+), 15 deletions(-) diffs (145 lines): diff -r 44e1a8aaa04e -r e4f1fda52fe8 njs/njs_generator.c --- a/njs/njs_generator.c Tue Jul 26 15:09:07 2016 +0300 +++ b/njs/njs_generator.c Tue Jul 26 16:25:58 2016 +0300 @@ -1263,7 +1263,6 @@ njs_generate_assignment(njs_vm_t *vm, nj } if (lvalue->state == NJS_VARIABLE_FIRST_ASSIGNMENT) { - lvalue->lvalue = NJS_LVALUE_ASSIGNED; value = njs_variable_value(parser, lvalue->index); *value = expr->u.value; node->index = expr->index; @@ -2336,8 +2335,6 @@ njs_generator_dest_index(njs_vm_t *vm, n dest = node->dest; if (dest != NULL && dest->index != NJS_INDEX_NONE) { - dest->lvalue = NJS_LVALUE_ASSIGNED; - return dest->index; } @@ -2363,7 +2360,6 @@ njs_generator_object_dest_index(njs_pars if (node->left == NULL) { /* Assign empty object directly to variable */ - dest->lvalue = NJS_LVALUE_ASSIGNED; return index; } } diff -r 44e1a8aaa04e -r e4f1fda52fe8 njs/njs_nonrecursive_parser.c --- a/njs/njs_nonrecursive_parser.c Tue Jul 26 15:09:07 2016 +0300 +++ b/njs/njs_nonrecursive_parser.c Tue Jul 26 16:25:58 2016 +0300 @@ -569,7 +569,6 @@ njs_parser_name_expression(njs_vm_t *vm, break; } - node->lvalue = NJS_LVALUE_ENABLED; node->u.variable = var; } } diff -r 44e1a8aaa04e -r e4f1fda52fe8 njs/njs_parser.c --- a/njs/njs_parser.c Tue Jul 26 15:09:07 2016 +0300 +++ b/njs/njs_parser.c Tue Jul 26 16:25:58 2016 +0300 @@ -681,7 +681,6 @@ njs_parser_var_statement(njs_vm_t *vm, n } name->token = NJS_TOKEN_NAME; - name->lvalue = NJS_LVALUE_ENABLED; name->u.variable = var; if (first) { @@ -1535,7 +1534,6 @@ njs_parser_terminal(njs_vm_t *vm, njs_pa } parser->code_size += sizeof(njs_vmcode_object_copy_t); - node->lvalue = NJS_LVALUE_ENABLED; node->u.variable = var; break; diff -r 44e1a8aaa04e -r e4f1fda52fe8 njs/njs_parser.h --- a/njs/njs_parser.h Tue Jul 26 15:09:07 2016 +0300 +++ b/njs/njs_parser.h Tue Jul 26 16:25:58 2016 +0300 @@ -225,7 +225,6 @@ typedef struct njs_parser_node_s njs_ struct njs_parser_node_s { njs_token_t token:8; njs_variable_node_state_t state:8; /* 2 bits */ - njs_lvalue_state_t lvalue:2; /* 2 bits */ uint8_t ctor:1; /* 1 bit */ uint8_t temporary; /* 1 bit */ uint32_t token_line; diff -r 44e1a8aaa04e -r e4f1fda52fe8 njs/njs_parser_expression.c --- a/njs/njs_parser_expression.c Tue Jul 26 15:09:07 2016 +0300 +++ b/njs/njs_parser_expression.c Tue Jul 26 16:25:58 2016 +0300 @@ -292,7 +292,7 @@ njs_parser_var_expression(njs_vm_t *vm, node = parser->node; - if (node->lvalue == NJS_LVALUE_NONE) { + if (parser->node->token != NJS_TOKEN_NAME) { return njs_parser_invalid_lvalue(vm, parser, "assignment"); } @@ -437,7 +437,9 @@ njs_parser_assignment_expression(njs_vm_ node = parser->node; - if (node->lvalue == NJS_LVALUE_NONE) { + if (parser->node->token != NJS_TOKEN_NAME + && parser->node->token != NJS_TOKEN_PROPERTY) + { return njs_parser_invalid_lvalue(vm, parser, "assignment"); } @@ -809,7 +811,9 @@ njs_parser_inc_dec_expression(njs_vm_t * return next; } - if (parser->node->lvalue == NJS_LVALUE_NONE) { + if (parser->node->token != NJS_TOKEN_NAME + && parser->node->token != NJS_TOKEN_PROPERTY) + { return njs_parser_invalid_lvalue(vm, parser, "prefix operation"); } @@ -861,7 +865,9 @@ njs_parser_post_inc_dec_expression(njs_v return token; } - if (parser->node->lvalue == NJS_LVALUE_NONE) { + if (parser->node->token != NJS_TOKEN_NAME + && parser->node->token != NJS_TOKEN_PROPERTY) + { return njs_parser_invalid_lvalue(vm, parser, "postfix operation"); } @@ -1015,7 +1021,6 @@ njs_parser_property_expression(njs_vm_t } node->token = NJS_TOKEN_PROPERTY; - node->lvalue = NJS_LVALUE_ENABLED; node->u.operation = njs_vmcode_property_get; node->left = parser->node; diff -r 44e1a8aaa04e -r e4f1fda52fe8 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Tue Jul 26 15:09:07 2016 +0300 +++ b/njs/test/njs_unit_test.c Tue Jul 26 16:25:58 2016 +0300 @@ -73,8 +73,17 @@ static njs_unit_test_t njs_test[] = { nxt_string("var f = 1; function f() {}"), nxt_string("SyntaxError: Duplicate declaration \"f\" in 1") }, - { nxt_string("function f() {} var f = 1; f"), - nxt_string("1") }, + { nxt_string("f() = 1"), + nxt_string("ReferenceError: Invalid left-hand side in assignment in 1") }, + + { nxt_string("f.a() = 1"), + nxt_string("ReferenceError: Invalid left-hand side in assignment in 1") }, + + { nxt_string("++f()"), + nxt_string("ReferenceError: Invalid left-hand side in prefix operation in 1") }, + + { nxt_string("f()++"), + nxt_string("ReferenceError: Invalid left-hand side in postfix operation in 1") }, /* Numbers. */ From vl at nginx.com Tue Jul 26 16:34:41 2016 From: vl at nginx.com (Vladimir Homutov) Date: Tue, 26 Jul 2016 16:34:41 +0000 Subject: [nginx] Version bump. Message-ID: details: http://hg.nginx.org/nginx/rev/0b4249f975eb branches: changeset: 6647:0b4249f975eb user: Vladimir Homutov date: Tue Jul 26 19:07:18 2016 +0300 description: Version bump. diffstat: src/core/nginx.h | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diffs (14 lines): diff -r eaba11dddc70 -r 0b4249f975eb src/core/nginx.h --- a/src/core/nginx.h Tue Jul 26 16:58:58 2016 +0300 +++ b/src/core/nginx.h Tue Jul 26 19:07:18 2016 +0300 @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1011003 -#define NGINX_VERSION "1.11.3" +#define nginx_version 1011004 +#define NGINX_VERSION "1.11.4" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD From vl at nginx.com Tue Jul 26 16:34:44 2016 From: vl at nginx.com (Vladimir Homutov) Date: Tue, 26 Jul 2016 16:34:44 +0000 Subject: [nginx] Stream: fixed build without stream_ssl_module (ticket #1032). Message-ID: details: http://hg.nginx.org/nginx/rev/d43ee392e825 branches: changeset: 6648:d43ee392e825 user: Vladimir Homutov date: Tue Jul 26 19:34:12 2016 +0300 description: Stream: fixed build without stream_ssl_module (ticket #1032). diffstat: src/stream/ngx_stream_proxy_module.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diffs (21 lines): diff -r 0b4249f975eb -r d43ee392e825 src/stream/ngx_stream_proxy_module.c --- a/src/stream/ngx_stream_proxy_module.c Tue Jul 26 19:07:18 2016 +0300 +++ b/src/stream/ngx_stream_proxy_module.c Tue Jul 26 19:34:12 2016 +0300 @@ -538,7 +538,7 @@ found: return; } -#if (NGX_HTTP_SSL) +#if (NGX_STREAM_SSL) u->ssl_name = uscf->host; #endif @@ -1157,7 +1157,7 @@ ngx_stream_proxy_resolve_handler(ngx_res u = s->upstream; ur = u->resolved; - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, s->connection->log, 0, + ngx_log_debug0(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, "stream upstream resolve"); if (ctx->state) { From sepherosa at gmail.com Wed Jul 27 05:35:45 2016 From: sepherosa at gmail.com (Sepherosa Ziehau) Date: Wed, 27 Jul 2016 13:35:45 +0800 Subject: How to build nginx on Windows? Message-ID: Hi all, Any idea about how to build nginx on Windows? Thanks, sephe -- Tomorrow Will Never Die From pavel2000 at ngs.ru Wed Jul 27 06:03:10 2016 From: pavel2000 at ngs.ru (Pavel V.) Date: Wed, 27 Jul 2016 13:03:10 +0700 Subject: How to build nginx on Windows? In-Reply-To: References: Message-ID: <165080691.20160727130310@ngs.ru> Hi, Sephe. > Any idea about how to build nginx on Windows? http://nginx.org/en/docs/howto_build_on_win32.html http://nginx.org/en/docs/ http://nginx.org/ -- Regards, Pavel mailto:pavel2000 at ngs.ru From sepherosa at gmail.com Wed Jul 27 06:58:03 2016 From: sepherosa at gmail.com (Sepherosa Ziehau) Date: Wed, 27 Jul 2016 14:58:03 +0800 Subject: How to build nginx on Windows? In-Reply-To: <165080691.20160727130310@ngs.ru> References: <165080691.20160727130310@ngs.ru> Message-ID: Thank you! On Wed, Jul 27, 2016 at 2:03 PM, Pavel V. wrote: > > Hi, Sephe. > >> Any idea about how to build nginx on Windows? > > http://nginx.org/en/docs/howto_build_on_win32.html > http://nginx.org/en/docs/ > http://nginx.org/ > > > > -- > Regards, > Pavel mailto:pavel2000 at ngs.ru > > _______________________________________________ > nginx-devel mailing list > nginx-devel at nginx.org > http://mailman.nginx.org/mailman/listinfo/nginx-devel -- Tomorrow Will Never Die From crasyangel at 163.com Wed Jul 27 08:34:02 2016 From: crasyangel at 163.com (baidu) Date: Wed, 27 Jul 2016 16:34:02 +0800 Subject: When nginx support tcp splicing? Message-ID: Do have any plan for tcp splicing? -------------- next part -------------- An HTML attachment was scrubbed... URL: From al-nginx at none.at Wed Jul 27 12:08:13 2016 From: al-nginx at none.at (Aleksandar Lazic) Date: Wed, 27 Jul 2016 14:08:13 +0200 Subject: When nginx support tcp splicing? In-Reply-To: References: Message-ID: Hi. Am 27-07-2016 10:34, schrieb baidu: > Do have any plan for tcp splicing? This was asked in the past http://mailman.nginx.org/pipermail/nginx/2015-December/thread.html#49398 Best regards Aleks