From vbart at nginx.com Sun Jul 1 09:20:14 2018 From: vbart at nginx.com (Valentin Bartenev) Date: Sun, 01 Jul 2018 09:20:14 +0000 Subject: [njs] Allowed uppercased O in octal literal values. Message-ID: details: http://hg.nginx.org/njs/rev/1cdf9c1a377d branches: changeset: 544:1cdf9c1a377d user: Valentin Bartenev date: Sun Jul 01 09:59:45 2018 +0300 description: Allowed uppercased O in octal literal values. diffstat: njs/njs_lexer.c | 2 +- njs/test/njs_unit_test.c | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diffs (39 lines): diff -r a361553ce219 -r 1cdf9c1a377d njs/njs_lexer.c --- a/njs/njs_lexer.c Sat Jun 30 20:39:22 2018 +0300 +++ b/njs/njs_lexer.c Sun Jul 01 09:59:45 2018 +0300 @@ -550,7 +550,7 @@ njs_lexer_number(njs_lexer_t *lexer) /* Octal literal values. */ - if (*p == 'o') { + if (*p == 'o' || *p == 'O') { p++; if (p == lexer->end) { diff -r a361553ce219 -r 1cdf9c1a377d njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Sat Jun 30 20:39:22 2018 +0300 +++ b/njs/test/njs_unit_test.c Sun Jul 01 09:59:45 2018 +0300 @@ -118,10 +118,13 @@ static njs_unit_test_t njs_test[] = { nxt_string("0o0"), nxt_string("0") }, + { nxt_string("0O10"), + nxt_string("8") }, + { nxt_string("0o011"), nxt_string("9") }, - { nxt_string("-0o777"), + { nxt_string("-0O777"), nxt_string("-511") }, /* Legacy Octal Numbers are deprecated. */ @@ -141,7 +144,7 @@ static njs_unit_test_t njs_test[] = { nxt_string("0o"), nxt_string("SyntaxError: Unexpected token \"\" in 1") }, - { nxt_string("0o778"), + { nxt_string("0O778"), nxt_string("SyntaxError: Unexpected token \"\" in 1") }, /* Hex Numbers. */ From vbart at nginx.com Sun Jul 1 09:20:14 2018 From: vbart at nginx.com (Valentin Bartenev) Date: Sun, 01 Jul 2018 09:20:14 +0000 Subject: [njs] Added support of binary literals. Message-ID: details: http://hg.nginx.org/njs/rev/e210675daceb branches: changeset: 545:e210675daceb user: Valentin Bartenev date: Sun Jul 01 10:01:53 2018 +0300 description: Added support of binary literals. diffstat: njs/njs_lexer.c | 21 +++++++++++++++++++++ njs/njs_number.c | 29 +++++++++++++++++++++++++++++ njs/njs_number.h | 1 + njs/test/njs_unit_test.c | 20 ++++++++++++++++++++ 4 files changed, 71 insertions(+), 0 deletions(-) diffs (111 lines): diff -r 1cdf9c1a377d -r e210675daceb njs/njs_lexer.c --- a/njs/njs_lexer.c Sun Jul 01 09:59:45 2018 +0300 +++ b/njs/njs_lexer.c Sun Jul 01 10:01:53 2018 +0300 @@ -569,6 +569,27 @@ njs_lexer_number(njs_lexer_t *lexer) return NJS_TOKEN_NUMBER; } + /* Binary literal values. */ + + if (*p == 'b' || *p == 'B') { + p++; + + if (p == lexer->end) { + return NJS_TOKEN_ILLEGAL; + } + + lexer->start = p; + lexer->number = njs_number_bin_parse((const u_char **) &lexer->start, + lexer->end); + p = lexer->start; + + if (p < lexer->end && (*p >= '2' && *p <= '9')) { + return NJS_TOKEN_ILLEGAL; + } + + return NJS_TOKEN_NUMBER; + } + /* Legacy Octal literals are deprecated. */ if (*p >= '0' && *p <= '9') { diff -r 1cdf9c1a377d -r e210675daceb njs/njs_number.c --- a/njs/njs_number.c Sun Jul 01 09:59:45 2018 +0300 +++ b/njs/njs_number.c Sun Jul 01 10:01:53 2018 +0300 @@ -184,6 +184,35 @@ njs_number_oct_parse(const u_char **star uint64_t +njs_number_bin_parse(const u_char **start, const u_char *end) +{ + u_char c; + uint64_t num; + const u_char *p; + + p = *start; + + num = 0; + + while (p < end) { + /* Values less than '0' become >= 208. */ + c = *p - '0'; + + if (nxt_slow_path(c > 1)) { + break; + } + + num = num * 2 + c; + p++; + } + + *start = p; + + return num; +} + + +uint64_t njs_number_hex_parse(const u_char **start, const u_char *end) { u_char c; diff -r 1cdf9c1a377d -r e210675daceb njs/njs_number.h --- a/njs/njs_number.h Sun Jul 01 09:59:45 2018 +0300 +++ b/njs/njs_number.h Sun Jul 01 10:01:53 2018 +0300 @@ -14,6 +14,7 @@ uint32_t njs_value_to_index(const njs_value_t *value); double njs_number_dec_parse(const u_char **start, const u_char *end); uint64_t njs_number_oct_parse(const u_char **start, const u_char *end); +uint64_t njs_number_bin_parse(const u_char **start, const u_char *end); uint64_t njs_number_hex_parse(const u_char **start, const u_char *end); int64_t njs_number_radix_parse(const u_char **start, const u_char *end, uint8_t radix); diff -r 1cdf9c1a377d -r e210675daceb njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Sun Jul 01 09:59:45 2018 +0300 +++ b/njs/test/njs_unit_test.c Sun Jul 01 10:01:53 2018 +0300 @@ -147,6 +147,26 @@ static njs_unit_test_t njs_test[] = { nxt_string("0O778"), nxt_string("SyntaxError: Unexpected token \"\" in 1") }, + /* Binary Numbers. */ + + { nxt_string("0b0"), + nxt_string("0") }, + + { nxt_string("0B10"), + nxt_string("2") }, + + { nxt_string("0b0101"), + nxt_string("5") }, + + { nxt_string("-0B11111111"), + nxt_string("-255") }, + + { nxt_string("0b"), + nxt_string("SyntaxError: Unexpected token \"\" in 1") }, + + { nxt_string("0B12"), + nxt_string("SyntaxError: Unexpected token \"\" in 1") }, + /* Hex Numbers. */ { nxt_string("0x0"), From shawn at git.icu Mon Jul 2 09:40:03 2018 From: shawn at git.icu (Shawn Landden) Date: Mon, 2 Jul 2018 02:40:03 -0700 Subject: [PATCH] Mention GNU/Linux's crypt() function Message-ID: <20180702094003.26347-1-shawn@git.icu> which supports the only secure hash functions available with this module --- xml/en/docs/http/ngx_http_auth_basic_module.xml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/xml/en/docs/http/ngx_http_auth_basic_module.xml b/xml/en/docs/http/ngx_http_auth_basic_module.xml index e68a0f3b..54667305 100644 --- a/xml/en/docs/http/ngx_http_auth_basic_module.xml +++ b/xml/en/docs/http/ngx_http_auth_basic_module.xml @@ -96,7 +96,10 @@ The following password types are supported: encrypted with the crypt function; can be generated using the ?htpasswd? utility from the Apache HTTP Server -distribution or the ?openssl passwd? command; +distribution or the ?openssl passwd? command; On GNU/Linux +crypt supports the better hash function of SHA-512, identified by +$6$ in /etc/shadow (see the crypt man page). Unfortunately there is no +utility for non-root users to produce these better-hashed passwords. -- 2.17.1 From kiriyama.kentaro at tis.co.jp Mon Jul 2 10:25:45 2018 From: kiriyama.kentaro at tis.co.jp (=?iso-2022-jp?B?GyRCNk07MyEhN3JCQE86GyhC?=) Date: Mon, 2 Jul 2018 10:25:45 +0000 Subject: HTTP Error 404 -Not Found Message-ID: Hello, I?m planning to install the nginx and I have created the yum repository by reading the guide on the following link. However, I have failed to install or either list the available version of nginx. Here is the yum repository I have created on the virtual machine. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [nginx] name=nginx repo baseurl=http://nginx.org/packages/rhel/7.4/$basearch/ gpgcheck=0 enabled=1 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Then I have tried ?yum install nginx?, and get the HTTP Error 404 - Not Found. Is there any advice that I can solve this? Regards Kentaro -------------- next part -------------- An HTML attachment was scrubbed... URL: From ben at isitdoneyet.co.uk Mon Jul 2 10:28:46 2018 From: ben at isitdoneyet.co.uk (Ben Brown) Date: Mon, 2 Jul 2018 11:28:46 +0100 Subject: HTTP Error 404 -Not Found In-Reply-To: References: Message-ID: Hi Kentaro, Try changing the 7.4 to just 7. Yum should replace $basearch with the right thing but if that still doesn't work change it to x86_64 - assuming that is the architecture you're using. Ben On 2 July 2018 at 11:25, ?????? wrote: > Hello, > > > > I?m planning to install the nginx and I have created the yum repository by > reading the guide on the following link. > > > > However, I have failed to install or either list the available version of > nginx. > > > > Here is the yum repository I have created on the virtual machine. > > > > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ > > > > [nginx] > > name=nginx repo > > baseurl=http://nginx.org/packages/rhel/7.4/$basearch/ > > gpgcheck=0 > > enabled=1 > > > > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ > > > > Then I have tried ?yum install nginx?, and get the HTTP Error 404 ? Not > Found. > > > > Is there any advice that I can solve this? > > > > Regards > > Kentaro > > > _______________________________________________ > nginx-devel mailing list > nginx-devel at nginx.org > http://mailman.nginx.org/mailman/listinfo/nginx-devel From ru at nginx.com Mon Jul 2 12:45:18 2018 From: ru at nginx.com (Ruslan Ermilov) Date: Mon, 02 Jul 2018 12:45:18 +0000 Subject: [nginx] Added FreeBSD support for "listen ... reuseport". Message-ID: details: http://hg.nginx.org/nginx/rev/5c2ac36fcf56 branches: changeset: 7304:5c2ac36fcf56 user: Ruslan Ermilov date: Mon Jul 02 13:54:33 2018 +0300 description: Added FreeBSD support for "listen ... reuseport". diffstat: src/core/ngx_connection.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 54 insertions(+), 0 deletions(-) diffs (99 lines): diff -r 118885f7a577 -r 5c2ac36fcf56 src/core/ngx_connection.c --- a/src/core/ngx_connection.c Fri Jun 15 17:29:55 2018 +0300 +++ b/src/core/ngx_connection.c Mon Jul 02 13:54:33 2018 +0300 @@ -281,6 +281,22 @@ ngx_set_inherited_sockets(ngx_cycle_t *c reuseport = 0; olen = sizeof(int); +#ifdef SO_REUSEPORT_LB + + if (getsockopt(ls[i].fd, SOL_SOCKET, SO_REUSEPORT_LB, + (void *) &reuseport, &olen) + == -1) + { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno, + "getsockopt(SO_REUSEPORT_LB) %V failed, ignored", + &ls[i].addr_text); + + } else { + ls[i].reuseport = reuseport ? 1 : 0; + } + +#else + if (getsockopt(ls[i].fd, SOL_SOCKET, SO_REUSEPORT, (void *) &reuseport, &olen) == -1) @@ -292,6 +308,7 @@ ngx_set_inherited_sockets(ngx_cycle_t *c } else { ls[i].reuseport = reuseport ? 1 : 0; } +#endif #endif @@ -430,6 +447,20 @@ ngx_open_listening_sockets(ngx_cycle_t * int reuseport = 1; +#ifdef SO_REUSEPORT_LB + + if (setsockopt(ls[i].fd, SOL_SOCKET, SO_REUSEPORT_LB, + (const void *) &reuseport, sizeof(int)) + == -1) + { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno, + "setsockopt(SO_REUSEPORT_LB) %V failed, " + "ignored", + &ls[i].addr_text); + } + +#else + if (setsockopt(ls[i].fd, SOL_SOCKET, SO_REUSEPORT, (const void *) &reuseport, sizeof(int)) == -1) @@ -438,6 +469,7 @@ ngx_open_listening_sockets(ngx_cycle_t * "setsockopt(SO_REUSEPORT) %V failed, ignored", &ls[i].addr_text); } +#endif ls[i].add_reuseport = 0; } @@ -488,6 +520,27 @@ ngx_open_listening_sockets(ngx_cycle_t * reuseport = 1; +#ifdef SO_REUSEPORT_LB + + if (setsockopt(s, SOL_SOCKET, SO_REUSEPORT_LB, + (const void *) &reuseport, sizeof(int)) + == -1) + { + ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, + "setsockopt(SO_REUSEPORT_LB) %V failed", + &ls[i].addr_text); + + if (ngx_close_socket(s) == -1) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, + ngx_close_socket_n " %V failed", + &ls[i].addr_text); + } + + return NGX_ERROR; + } + +#else + if (setsockopt(s, SOL_SOCKET, SO_REUSEPORT, (const void *) &reuseport, sizeof(int)) == -1) @@ -504,6 +557,7 @@ ngx_open_listening_sockets(ngx_cycle_t * return NGX_ERROR; } +#endif } #endif From xeioex at nginx.com Mon Jul 2 13:32:17 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Mon, 02 Jul 2018 13:32:17 +0000 Subject: [njs] Fixed autocompletion for global objects. Message-ID: details: http://hg.nginx.org/njs/rev/f2a2c9674082 branches: changeset: 546:f2a2c9674082 user: Dmitry Volyntsev date: Mon Jul 02 16:10:52 2018 +0300 description: Fixed autocompletion for global objects. This fixes #23 issue on GitHub. diffstat: njs/njs_shell.c | 186 +++++++++++++++++++++++++++++++------------------------ 1 files changed, 104 insertions(+), 82 deletions(-) diffs (227 lines): diff -r e210675daceb -r f2a2c9674082 njs/njs_shell.c --- a/njs/njs_shell.c Sun Jul 01 10:01:53 2018 +0300 +++ b/njs/njs_shell.c Mon Jul 02 16:10:52 2018 +0300 @@ -20,8 +20,9 @@ typedef enum { - NJS_COMPLETION_GLOBAL = 0, + NJS_COMPLETION_VAR = 0, NJS_COMPLETION_SUFFIX, + NJS_COMPLETION_GLOBAL } njs_completion_phase_t; @@ -476,6 +477,11 @@ njs_completion_handler(const char *text, #define njs_completion(c, i) &(((nxt_str_t *) (c)->start)[i]) +#define njs_next_phase(c) \ + (c)->index = 0; \ + (c)->phase++; \ + goto next; + static char * njs_completion_generator(const char *text, int state) { @@ -489,14 +495,108 @@ njs_completion_generator(const char *tex cmpl = &njs_completion; if (state == 0) { + cmpl->phase = 0; cmpl->index = 0; cmpl->length = strlen(text); - cmpl->phase = NJS_COMPLETION_GLOBAL; + cmpl->suffix_completions = NULL; nxt_lvlhsh_each_init(&cmpl->lhe, &njs_variables_hash_proto); } - if (cmpl->phase == NJS_COMPLETION_GLOBAL) { +next: + + switch (cmpl->phase) { + case NJS_COMPLETION_VAR: + if (cmpl->vm->parser == NULL) { + njs_next_phase(cmpl); + } + + for ( ;; ) { + var = nxt_lvlhsh_each(&cmpl->vm->parser->scope->variables, + &cmpl->lhe); + + if (var == NULL) { + break; + } + + if (var->name.length < cmpl->length) { + continue; + } + + if (strncmp(text, (char *) var->name.start, cmpl->length) == 0) { + return njs_editline(&var->name); + } + } + + njs_next_phase(cmpl); + + case NJS_COMPLETION_SUFFIX: + if (cmpl->length == 0) { + njs_next_phase(cmpl); + } + + if (cmpl->suffix_completions == NULL) { + /* Getting the longest prefix before a '.' */ + + p = &text[cmpl->length - 1]; + while (p > text && *p != '.') { p--; } + + if (*p != '.') { + njs_next_phase(cmpl); + } + + expression.start = (u_char *) text; + expression.length = p - text; + + cmpl->suffix_completions = njs_vm_completions(cmpl->vm, + &expression); + if (cmpl->suffix_completions == NULL) { + njs_next_phase(cmpl); + } + } + + /* Getting the right-most suffix after a '.' */ + + len = 0; + p = &text[cmpl->length - 1]; + + while (p > text && *p != '.') { + p--; + len++; + } + + p++; + + for ( ;; ) { + if (cmpl->index >= cmpl->suffix_completions->items) { + njs_next_phase(cmpl); + } + + suffix = njs_completion(cmpl->suffix_completions, cmpl->index++); + + if (len != 0 && strncmp((char *) suffix->start, p, + nxt_min(len, suffix->length)) != 0) + { + continue; + } + + len = suffix->length + (p - text) + 1; + completion = malloc(len); + if (completion == NULL) { + return NULL; + } + + snprintf(completion, len, "%.*s%.*s", (int) (p - text), text, + (int) suffix->length, suffix->start); + return completion; + } + + case NJS_COMPLETION_GLOBAL: + if (cmpl->suffix_completions != NULL) { + /* No global completions if suffixes were found. */ + njs_next_phase(cmpl); + } + for ( ;; ) { if (cmpl->index >= cmpl->completions->items) { break; @@ -508,88 +608,10 @@ njs_completion_generator(const char *tex continue; } - if (strncmp(text, (char *) suffix->start, - nxt_min(suffix->length, cmpl->length)) == 0) - { + if (strncmp(text, (char *) suffix->start, cmpl->length) == 0) { return njs_editline(suffix); } } - - if (cmpl->vm->parser != NULL) { - for ( ;; ) { - var = nxt_lvlhsh_each(&cmpl->vm->parser->scope->variables, - &cmpl->lhe); - if (var == NULL || var->name.length < cmpl->length) { - break; - } - - if (strncmp(text, (char *) var->name.start, - nxt_min(var->name.length, cmpl->length)) == 0) - { - return njs_editline(&var->name); - } - } - } - - if (cmpl->length == 0) { - return NULL; - } - - /* Getting the longest prefix before a '.' */ - - p = &text[cmpl->length - 1]; - while (p > text && *p != '.') { p--; } - - if (*p != '.') { - return NULL; - } - - expression.start = (u_char *) text; - expression.length = p - text; - - cmpl->suffix_completions = njs_vm_completions(cmpl->vm, &expression); - if (cmpl->suffix_completions == NULL) { - return NULL; - } - - cmpl->index = 0; - cmpl->phase = NJS_COMPLETION_SUFFIX; - } - - /* Getting the right-most suffix after a '.' */ - - len = 0; - p = &text[cmpl->length - 1]; - - while (p > text && *p != '.') { - p--; - len++; - } - - p++; - - for ( ;; ) { - if (cmpl->index >= cmpl->suffix_completions->items) { - break; - } - - suffix = njs_completion(cmpl->suffix_completions, cmpl->index++); - - if (len != 0 && strncmp((char *) suffix->start, p, - nxt_min(len, suffix->length)) != 0) - { - continue; - } - - len = suffix->length + (p - text) + 1; - completion = malloc(len); - if (completion == NULL) { - return NULL; - } - - snprintf(completion, len, "%.*s%.*s", (int) (p - text), text, - (int) suffix->length, suffix->start); - return completion; } return NULL; From vbart at nginx.com Mon Jul 2 13:34:31 2018 From: vbart at nginx.com (Valentin Bartenev) Date: Mon, 02 Jul 2018 13:34:31 +0000 Subject: [njs] String.padStart() and String.padEnd() methods. Message-ID: details: http://hg.nginx.org/njs/rev/31e0580b3c02 branches: changeset: 547:31e0580b3c02 user: Valentin Bartenev date: Fri Jun 29 22:36:41 2018 +0300 description: String.padStart() and String.padEnd() methods. diffstat: njs/njs_string.c | 125 +++++++++++++++++++++++++++++++++++++++++++++++ njs/test/njs_unit_test.c | 99 +++++++++++++++++++++++++++++++++++++ 2 files changed, 224 insertions(+), 0 deletions(-) diffs (258 lines): diff -r f2a2c9674082 -r 31e0580b3c02 njs/njs_string.c --- a/njs/njs_string.c Mon Jul 02 16:10:52 2018 +0300 +++ b/njs/njs_string.c Fri Jun 29 22:36:41 2018 +0300 @@ -64,6 +64,8 @@ static njs_ret_t njs_string_from_char_co njs_value_t *args, nxt_uint_t nargs, njs_index_t unused); static njs_ret_t njs_string_starts_or_ends_with(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, nxt_bool_t starts); +static njs_ret_t njs_string_prototype_pad(njs_vm_t *vm, njs_value_t *args, + nxt_uint_t nargs, nxt_bool_t pad_start); static njs_ret_t njs_string_match_multiple(njs_vm_t *vm, njs_value_t *args, njs_regexp_pattern_t *pattern); static njs_ret_t njs_string_split_part_add(njs_vm_t *vm, njs_array_t *array, @@ -2073,6 +2075,113 @@ njs_string_prototype_repeat(njs_vm_t *vm } +static njs_ret_t +njs_string_prototype_pad_start(njs_vm_t *vm, njs_value_t *args, + nxt_uint_t nargs, njs_index_t unused) +{ + return njs_string_prototype_pad(vm, args, nargs, 1); +} + + +static njs_ret_t +njs_string_prototype_pad_end(njs_vm_t *vm, njs_value_t *args, + nxt_uint_t nargs, njs_index_t unused) +{ + return njs_string_prototype_pad(vm, args, nargs, 0); +} + + +static njs_ret_t +njs_string_prototype_pad(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, + nxt_bool_t pad_start) +{ + u_char *p, *start; + size_t padding, trunc, new_size; + int32_t length, new_length; + uint32_t n, pad_length; + const u_char *end; + njs_string_prop_t string, pad_string; + + length = njs_string_prop(&string, &args[0]); + new_length = nargs > 1 ? args[1].data.u.number : 0; + + if (new_length <= length) { + vm->retval = args[0]; + return NJS_OK; + } + + if (nxt_slow_path(new_length >= NJS_STRING_MAX_LENGTH)) { + njs_range_error(vm, NULL); + return NJS_ERROR; + } + + padding = new_length - length; + + /* GCC and Clang complain about uninitialized n and trunc. */ + n = 0; + trunc = 0; + + if (nargs > 2) { + pad_length = njs_string_prop(&pad_string, &args[2]); + + if (pad_string.size == 0) { + vm->retval = args[0]; + return NJS_OK; + } + + if (pad_string.size > 1) { + n = padding / pad_length; + trunc = padding % pad_length; + + if (pad_string.size != (size_t) pad_length) { + /* UTF-8 string. */ + end = pad_string.start + pad_string.size; + end = njs_string_offset(pad_string.start, end, trunc); + + trunc = end - pad_string.start; + padding = pad_string.size * n + trunc; + } + } + } + + new_size = string.size + padding; + + start = njs_string_alloc(vm, &vm->retval, new_size, new_length); + if (nxt_slow_path(start == NULL)) { + return NJS_ERROR; + } + + p = start; + + if (pad_start) { + start += padding; + + } else { + p += string.size; + } + + memcpy(start, string.start, string.size); + + if (nargs == 2) { + memset(p, ' ', padding); + + } else if (pad_string.size == 1) { + memset(p, pad_string.start[0], padding); + + } else { + while (n != 0) { + memcpy(p, pad_string.start, pad_string.size); + p += pad_string.size; + n--; + } + + memcpy(p, pad_string.start, trunc); + } + + return NJS_OK; +} + + /* * String.search([regexp]) */ @@ -3490,6 +3599,22 @@ static const njs_object_prop_t njs_stri NJS_STRING_OBJECT_ARG, NJS_INTEGER_ARG), }, + /* ES8. */ + { + .type = NJS_METHOD, + .name = njs_string("padStart"), + .value = njs_native_function(njs_string_prototype_pad_start, 0, + NJS_STRING_OBJECT_ARG, NJS_INTEGER_ARG, NJS_STRING_ARG), + }, + + /* ES8. */ + { + .type = NJS_METHOD, + .name = njs_string("padEnd"), + .value = njs_native_function(njs_string_prototype_pad_end, 0, + NJS_STRING_OBJECT_ARG, NJS_INTEGER_ARG, NJS_STRING_ARG), + }, + { .type = NJS_METHOD, .name = njs_string("search"), diff -r f2a2c9674082 -r 31e0580b3c02 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Mon Jul 02 16:10:52 2018 +0300 +++ b/njs/test/njs_unit_test.c Fri Jun 29 22:36:41 2018 +0300 @@ -4557,6 +4557,105 @@ static njs_unit_test_t njs_test[] = { nxt_string("''.repeat(NaN)"), nxt_string("") }, + { nxt_string("'abc'.padStart(7)"), + nxt_string(" abc") }, + + { nxt_string("'???'.padStart(7)"), + nxt_string(" ???") }, + + { nxt_string("'abc'.padStart(3)"), + nxt_string("abc") }, + + { nxt_string("'???'.padStart(0)"), + nxt_string("???") }, + + { nxt_string("'abc'.padStart(NaN)"), + nxt_string("abc") }, + + { nxt_string("'abc'.padStart(2147483647)"), + nxt_string("RangeError") }, + + { nxt_string("'abc'.padStart(2147483646, '')"), + nxt_string("abc") }, + + { nxt_string("''.padStart(0, '')"), + nxt_string("") }, + + { nxt_string("'1'.padStart(5, 0)"), + nxt_string("00001") }, + + { nxt_string("''.padStart(1, '?')"), + nxt_string("?") }, + + { nxt_string("'abc'.padStart(6, NaN)"), + nxt_string("NaNabc") }, + + { nxt_string("'abc'.padStart(11, 123)"), + nxt_string("12312312abc") }, + + { nxt_string("'abc'.padStart(6, 12345)"), + nxt_string("123abc") }, + + { nxt_string("'???'.padStart(6, '???')"), + nxt_string("??????") }, + + { nxt_string("'???'.padStart(4, '???')"), + nxt_string("????") }, + + { nxt_string("'???'.padStart(7, '???')"), + nxt_string("???????") }, + + { nxt_string("'???'.padStart(10, '??')"), + nxt_string("??????????") }, + + { nxt_string("'1234'.padEnd(4)"), + nxt_string("1234") }, + + { nxt_string("'1234'.padEnd(-1)"), + nxt_string("1234") }, + + { nxt_string("'?'.padEnd(1)"), + nxt_string("?") }, + + { nxt_string("'1234'.padEnd(5)"), + nxt_string("1234 ") }, + + { nxt_string("'?'.padEnd(6)"), + nxt_string("? ") }, + + { nxt_string("'?'.padEnd(2147483647)"), + nxt_string("RangeError") }, + + { nxt_string("'?'.padEnd(2147483646, '')"), + nxt_string("?") }, + + { nxt_string("''.padEnd(0, '')"), + nxt_string("") }, + + { nxt_string("'??'.padEnd(3, '?')"), + nxt_string("???") }, + + { nxt_string("''.padEnd(1, 0)"), + nxt_string("0") }, + + { nxt_string("'1234'.padEnd(8, 'abcd')"), + nxt_string("1234abcd") }, + + { nxt_string("'1234'.padEnd(10, 'abcd')"), + nxt_string("1234abcdab") }, + + { nxt_string("'1234'.padEnd(7, 'abcd')"), + nxt_string("1234abc") }, + + { nxt_string("'???'.padEnd(5, '??')"), + nxt_string("?????") }, + + { nxt_string("'???'.padEnd(4, '???')"), + nxt_string("????") }, + + { nxt_string("'????'.padEnd(10, '????')"), + nxt_string("??????????") }, + { nxt_string("encodeURI()"), nxt_string("undefined")}, From xeioex at nginx.com Mon Jul 2 15:04:19 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Mon, 02 Jul 2018 15:04:19 +0000 Subject: [njs] Adding support for multiple arguments in console.log(). Message-ID: details: http://hg.nginx.org/njs/rev/649e5804b971 branches: changeset: 548:649e5804b971 user: xeioex at nginx.com date: Tue Jun 26 18:27:33 2018 +0700 description: Adding support for multiple arguments in console.log(). diffstat: njs/njs_shell.c | 24 +++++++++++++++--------- njs/test/njs_expect_test.exp | 6 +++--- 2 files changed, 18 insertions(+), 12 deletions(-) diffs (57 lines): diff -r 31e0580b3c02 -r 649e5804b971 njs/njs_shell.c --- a/njs/njs_shell.c Fri Jun 29 22:36:41 2018 +0300 +++ b/njs/njs_shell.c Tue Jun 26 18:27:33 2018 +0700 @@ -622,20 +622,26 @@ static njs_ret_t njs_ext_console_log(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused) { - nxt_str_t msg; + nxt_str_t msg; + nxt_uint_t n; - msg.length = 0; - msg.start = NULL; + n = 1; - if (nargs >= 2 - && njs_vm_value_to_ext_string(vm, &msg, njs_argument(args, 1), 0) - == NJS_ERROR) - { + while (n < nargs) { + if (njs_vm_value_to_ext_string(vm, &msg, njs_argument(args, n), 0) + == NJS_ERROR) + { + return NJS_ERROR; + } - return NJS_ERROR; + printf("%s%.*s", (n != 1) ? " " : "", (int) msg.length, msg.start); + + n++; } - printf("%.*s\n", (int) msg.length, msg.start); + if (nargs > 1) { + printf("\n"); + } vm->retval = njs_value_void; diff -r 31e0580b3c02 -r 649e5804b971 njs/test/njs_expect_test.exp --- a/njs/test/njs_expect_test.exp Fri Jun 29 22:36:41 2018 +0300 +++ b/njs/test/njs_expect_test.exp Tue Jun 26 18:27:33 2018 +0700 @@ -162,11 +162,11 @@ njs_test { # console object njs_test { {"console.log()\r\n" - "console.log()\r\n\r\nundefined\r\n>> "} + "console.log()\r\nundefined\r\n>> "} {"console.log(1)\r\n" "console.log(1)\r\n1\r\nundefined\r\n>> "} - {"console.log('abc')\r\n" - "console.log('abc')\r\nabc\r\nundefined\r\n>> "} + {"console.log(1, 'a')\r\n" + "console.log(1, 'a')\r\n1 a\r\nundefined\r\n>> "} {"console.help()\r\n" "console.help()\r\nVM built-in objects:"} } From xeioex at nginx.com Mon Jul 2 15:04:20 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Mon, 02 Jul 2018 15:04:20 +0000 Subject: [njs] Returning external methods as native Function objects. Message-ID: details: http://hg.nginx.org/njs/rev/4afaf9e2804c branches: changeset: 549:4afaf9e2804c user: xeioex at nginx.com date: Tue Jun 26 18:30:10 2018 +0700 description: Returning external methods as native Function objects. This fixes #20 issue on GitHub. diffstat: njs/njs_extern.c | 27 +++++++++++++++++++++------ njs/njs_vm.c | 6 ++++++ njs/test/njs_expect_test.exp | 5 +++++ 3 files changed, 32 insertions(+), 6 deletions(-) diffs (78 lines): diff -r 649e5804b971 -r 4afaf9e2804c njs/njs_extern.c --- a/njs/njs_extern.c Tue Jun 26 18:27:33 2018 +0700 +++ b/njs/njs_extern.c Tue Jun 26 18:30:10 2018 +0700 @@ -75,6 +75,7 @@ njs_vm_external_add(njs_vm_t *vm, nxt_lv { nxt_int_t ret; njs_extern_t *ext, *child; + njs_function_t *function; nxt_lvlhsh_query_t lhq; do { @@ -96,15 +97,29 @@ njs_vm_external_add(njs_vm_t *vm, nxt_lv ext->data = external->data; if (external->method != NULL) { - ext->function = nxt_mem_cache_zalloc(vm->mem_cache_pool, - sizeof(njs_function_t)); - if (nxt_slow_path(ext->function == NULL)) { + function = nxt_mem_cache_zalloc(vm->mem_cache_pool, + sizeof(njs_function_t)); + if (nxt_slow_path(function == NULL)) { return NULL; } - ext->function->native = 1; - ext->function->args_offset = 1; - ext->function->u.native = external->method; + /* + * nxt_mem_cache_zalloc() does also: + * nxt_lvlhsh_init(&function->object.hash); + * function->object.__proto__ = NULL; + */ + + function->object.__proto__ = + &vm->prototypes[NJS_CONSTRUCTOR_FUNCTION].object; + function->object.shared_hash = vm->shared->function_prototype_hash; + function->object.type = NJS_FUNCTION; + function->object.shared = 1; + function->object.extensible = 1; + function->args_offset = 1; + function->native = 1; + function->u.native = external->method; + + ext->function = function; } else { ext->function = NULL; diff -r 649e5804b971 -r 4afaf9e2804c njs/njs_vm.c --- a/njs/njs_vm.c Tue Jun 26 18:27:33 2018 +0700 +++ b/njs/njs_vm.c Tue Jun 26 18:30:10 2018 +0700 @@ -588,6 +588,12 @@ njs_vmcode_property_get(njs_vm_t *vm, nj /* The vm->retval is already retained by ext_proto->get(). */ } + if (ext_proto->type == NJS_EXTERN_METHOD) { + vm->retval.data.u.function = ext_proto->function; + vm->retval.type = NJS_FUNCTION; + vm->retval.data.truth = 1; + } + return sizeof(njs_vmcode_prop_get_t); case NJS_TRAP_PROPERTY: diff -r 649e5804b971 -r 4afaf9e2804c njs/test/njs_expect_test.exp --- a/njs/test/njs_expect_test.exp Tue Jun 26 18:27:33 2018 +0700 +++ b/njs/test/njs_expect_test.exp Tue Jun 26 18:30:10 2018 +0700 @@ -176,6 +176,11 @@ njs_test { "console.ll()\r\nTypeError: cannot find property 'll' of an external object"} } +njs_test { + {"var print = console.log.bind(console); print(1, 'a', [1, 2])\r\n" + "var print = console.log.bind(console); print(1, 'a', \\\[1, 2])\r\n1 a 1,2\r\nundefined\r\n>> "} +} + # Backtraces for external objects njs_test { {"console.log(console)\r\n" From xeioex at nginx.com Mon Jul 2 15:04:20 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Mon, 02 Jul 2018 15:04:20 +0000 Subject: [njs] Improved file mode in CLI. Message-ID: details: http://hg.nginx.org/njs/rev/135f33d06df5 branches: changeset: 550:135f33d06df5 user: Dmitry Volyntsev date: Mon Jul 02 18:03:43 2018 +0300 description: Improved file mode in CLI. Reporting of the return value of the last expression is disabled. diffstat: njs/njs_shell.c | 4 ---- 1 files changed, 0 insertions(+), 4 deletions(-) diffs (14 lines): diff -r 4afaf9e2804c -r 135f33d06df5 njs/njs_shell.c --- a/njs/njs_shell.c Tue Jun 26 18:30:10 2018 +0700 +++ b/njs/njs_shell.c Mon Jul 02 18:03:43 2018 +0300 @@ -390,10 +390,6 @@ njs_process_file(njs_opts_t *opts, njs_v goto done; } - if (!opts->disassemble) { - printf("%.*s\n", (int) out.length, out.start); - } - ret = NXT_OK; done: From mdounin at mdounin.ru Mon Jul 2 16:40:19 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Mon, 02 Jul 2018 16:40:19 +0000 Subject: [nginx] gRPC: clearing buffers in ngx_http_grpc_get_buf(). Message-ID: details: http://hg.nginx.org/nginx/rev/6cfd45d4c754 branches: changeset: 7305:6cfd45d4c754 user: Maxim Dounin date: Mon Jul 02 19:02:08 2018 +0300 description: gRPC: clearing buffers in ngx_http_grpc_get_buf(). We copy input buffers to our buffers, so various flags might be unexpectedly set in buffers returned by ngx_chain_get_free_buf(). In particular, the b->in_file flag might be set when the body was written to a file in a different context. With sendfile enabled this in turn might result in protocol corruption if such a buffer was reused for a control frame. Make sure to clear buffers and set only fields we really need to be set. diffstat: src/http/modules/ngx_http_grpc_module.c | 29 +++++++++++++++++------------ 1 files changed, 17 insertions(+), 12 deletions(-) diffs (57 lines): diff --git a/src/http/modules/ngx_http_grpc_module.c b/src/http/modules/ngx_http_grpc_module.c --- a/src/http/modules/ngx_http_grpc_module.c +++ b/src/http/modules/ngx_http_grpc_module.c @@ -3868,6 +3868,7 @@ ngx_http_grpc_send_window_update(ngx_htt static ngx_chain_t * ngx_http_grpc_get_buf(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx) { + u_char *start; ngx_buf_t *b; ngx_chain_t *cl; @@ -3877,29 +3878,33 @@ ngx_http_grpc_get_buf(ngx_http_request_t } b = cl->buf; - - b->tag = (ngx_buf_tag_t) &ngx_http_grpc_body_output_filter; - b->temporary = 1; - b->flush = 1; - - if (b->start == NULL) { + start = b->start; + + if (start == NULL) { /* * each buffer is large enough to hold two window update * frames in a row */ - b->start = ngx_palloc(r->pool, 2 * sizeof(ngx_http_grpc_frame_t) + 8); - if (b->start == NULL) { + start = ngx_palloc(r->pool, 2 * sizeof(ngx_http_grpc_frame_t) + 8); + if (start == NULL) { return NULL; } - b->pos = b->start; - b->last = b->start; - - b->end = b->start + 2 * sizeof(ngx_http_grpc_frame_t) + 8; } + ngx_memzero(b, sizeof(ngx_buf_t)); + + b->start = start; + b->pos = start; + b->last = start; + b->end = start + 2 * sizeof(ngx_http_grpc_frame_t) + 8; + + b->tag = (ngx_buf_tag_t) &ngx_http_grpc_body_output_filter; + b->temporary = 1; + b->flush = 1; + return cl; } From mdounin at mdounin.ru Mon Jul 2 16:40:21 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Mon, 02 Jul 2018 16:40:21 +0000 Subject: [nginx] Upstream: fixed unexpected tcp_nopush usage on peer connections. Message-ID: details: http://hg.nginx.org/nginx/rev/8eab05b83dde branches: changeset: 7306:8eab05b83dde user: Maxim Dounin date: Mon Jul 02 19:02:31 2018 +0300 description: Upstream: fixed unexpected tcp_nopush usage on peer connections. Now tcp_nopush on peer connections is disabled if it is disabled on the client connection, similar to how we handle c->sendfile. Previously, tcp_nopush was always used on upstream connections, regardless of the "tcp_nopush" directive. diffstat: src/http/ngx_http_upstream.c | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-) diffs (14 lines): diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -1556,6 +1556,10 @@ ngx_http_upstream_connect(ngx_http_reque c->sendfile &= r->connection->sendfile; u->output.sendfile = c->sendfile; + if (r->connection->tcp_nopush == NGX_TCP_NOPUSH_DISABLED) { + c->tcp_nopush = NGX_TCP_NOPUSH_DISABLED; + } + if (c->pool == NULL) { /* we need separate pool here to be able to cache SSL connections */ From mdounin at mdounin.ru Mon Jul 2 16:40:22 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Mon, 02 Jul 2018 16:40:22 +0000 Subject: [nginx] Upstream: fixed tcp_nopush with gRPC. Message-ID: details: http://hg.nginx.org/nginx/rev/ece9b5454b8a branches: changeset: 7307:ece9b5454b8a user: Maxim Dounin date: Mon Jul 02 19:03:04 2018 +0300 description: Upstream: fixed tcp_nopush with gRPC. With gRPC it is possible that a request sending is blocked due to flow control. Moreover, further sending might be only allowed once the backend sees all the data we've already sent. With such a backend it is required to clear the TCP_NOPUSH socket option to make sure all the data we've sent are actually delivered to the backend. As such, we now clear TCP_NOPUSH in ngx_http_upstream_send_request() also on NGX_AGAIN if c->write->ready is set. This fixes a test (which waits for all the 64k bytes as per initial window before allowing more bytes) with sendfile enabled when the body was written to a file in a different context. diffstat: src/http/ngx_http_upstream.c | 12 ++++++++++++ 1 files changed, 12 insertions(+), 0 deletions(-) diffs (22 lines): diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -2012,6 +2012,18 @@ ngx_http_upstream_send_request(ngx_http_ return; } + if (c->write->ready && c->tcp_nopush == NGX_TCP_NOPUSH_SET) { + if (ngx_tcp_push(c->fd) == -1) { + ngx_log_error(NGX_LOG_CRIT, c->log, ngx_socket_errno, + ngx_tcp_push_n " failed"); + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + + c->tcp_nopush = NGX_TCP_NOPUSH_UNSET; + } + return; } From kiriyama.kentaro at tis.co.jp Tue Jul 3 02:13:16 2018 From: kiriyama.kentaro at tis.co.jp (=?utf-8?B?5qGQ5bGx44CA5YGl5aSq6YOO?=) Date: Tue, 3 Jul 2018 02:13:16 +0000 Subject: HTTP Error 404 -Not Found In-Reply-To: References: Message-ID: Hi Ben, Thanks for the advice. The issue with HTTP Error have recovered and was able to yum install the nginx. Appreciate for your help. Kentaro -----Original Message----- From: nginx-devel [mailto:nginx-devel-bounces at nginx.org] On Behalf Of Ben Brown Sent: Monday, July 2, 2018 7:29 PM To: nginx-devel at nginx.org Cc: ?????; ?????; ????? Subject: Re: HTTP Error 404 -Not Found Hi Kentaro, Try changing the 7.4 to just 7. Yum should replace $basearch with the right thing but if that still doesn't work change it to x86_64 - assuming that is the architecture you're using. Ben On 2 July 2018 at 11:25, ?????? wrote: > Hello, > > > > I?m planning to install the nginx and I have created the yum repository by > reading the guide on the following link. > > > > However, I have failed to install or either list the available version of > nginx. > > > > Here is the yum repository I have created on the virtual machine. > > > > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ > > > > [nginx] > > name=nginx repo > > baseurl=http://nginx.org/packages/rhel/7.4/$basearch/ > > gpgcheck=0 > > enabled=1 > > > > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ > > > > Then I have tried ?yum install nginx?, and get the HTTP Error 404 ? Not > Found. > > > > Is there any advice that I can solve this? > > > > Regards > > Kentaro > > > _______________________________________________ > nginx-devel mailing list > nginx-devel at nginx.org > http://mailman.nginx.org/mailman/listinfo/nginx-devel _______________________________________________ nginx-devel mailing list nginx-devel at nginx.org http://mailman.nginx.org/mailman/listinfo/nginx-devel From xeioex at nginx.com Tue Jul 3 11:15:42 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Tue, 03 Jul 2018 11:15:42 +0000 Subject: [njs] Fixed Number() with boolean, null and undefined arguments. Message-ID: details: http://hg.nginx.org/njs/rev/f20bf1b5db20 branches: changeset: 551:f20bf1b5db20 user: Dmitry Volyntsev date: Tue Jul 03 14:15:29 2018 +0300 description: Fixed Number() with boolean, null and undefined arguments. This fixes #25 issue on GitHub. diffstat: njs/njs_number.c | 4 ++-- njs/test/njs_unit_test.c | 24 ++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diffs (55 lines): diff -r 135f33d06df5 -r f20bf1b5db20 njs/njs_number.c --- a/njs/njs_number.c Mon Jul 02 18:03:43 2018 +0300 +++ b/njs/njs_number.c Tue Jul 03 14:15:29 2018 +0300 @@ -377,7 +377,7 @@ njs_number_constructor(njs_vm_t *vm, njs } if (vm->top_frame->ctor) { - object = njs_object_value_alloc(vm, value, value->type); + object = njs_object_value_alloc(vm, value, NJS_NUMBER); if (nxt_slow_path(object == NULL)) { return NXT_ERROR; } @@ -387,7 +387,7 @@ njs_number_constructor(njs_vm_t *vm, njs vm->retval.data.truth = 1; } else { - vm->retval = *value; + njs_value_number_set(&vm->retval, value->data.u.number); } return NXT_OK; diff -r 135f33d06df5 -r f20bf1b5db20 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Mon Jul 02 18:03:43 2018 +0300 +++ b/njs/test/njs_unit_test.c Tue Jul 03 14:15:29 2018 +0300 @@ -6117,6 +6117,30 @@ static njs_unit_test_t njs_test[] = { nxt_string("new Number"), nxt_string("0") }, + { nxt_string("new Number(undefined)"), + nxt_string("NaN") }, + + { nxt_string("new Number(null)"), + nxt_string("0") }, + + { nxt_string("new Number(true)"), + nxt_string("1") }, + + { nxt_string("new Number(false)"), + nxt_string("0") }, + + { nxt_string("Number(undefined)"), + nxt_string("NaN") }, + + { nxt_string("Number(null)"), + nxt_string("0") }, + + { nxt_string("Number(true)"), + nxt_string("1") }, + + { nxt_string("Number(false)"), + nxt_string("0") }, + { nxt_string("Number(123)"), nxt_string("123") }, From igor at sysoev.ru Tue Jul 3 12:48:46 2018 From: igor at sysoev.ru (Igor Sysoev) Date: Tue, 03 Jul 2018 12:48:46 +0000 Subject: [njs] Added information about illegal token in number parsing. Message-ID: details: http://hg.nginx.org/njs/rev/3aef480987d6 branches: changeset: 552:3aef480987d6 user: Igor Sysoev date: Tue Jul 03 15:48:03 2018 +0300 description: Added information about illegal token in number parsing. diffstat: njs/njs_lexer.c | 61 +++++++++++++++++++++++++---------------------- njs/test/njs_unit_test.c | 26 ++++++++++---------- 2 files changed, 46 insertions(+), 41 deletions(-) diffs (195 lines): diff -r f20bf1b5db20 -r 3aef480987d6 njs/njs_lexer.c --- a/njs/njs_lexer.c Tue Jul 03 14:15:29 2018 +0300 +++ b/njs/njs_lexer.c Tue Jul 03 15:48:03 2018 +0300 @@ -21,7 +21,7 @@ struct njs_lexer_multi_s { static njs_token_t njs_lexer_next_token(njs_lexer_t *lexer); static njs_token_t njs_lexer_word(njs_lexer_t *lexer, u_char c); static njs_token_t njs_lexer_string(njs_lexer_t *lexer, u_char quote); -static njs_token_t njs_lexer_number(njs_lexer_t *lexer); +static njs_token_t njs_lexer_number(njs_lexer_t *lexer, u_char c); static njs_token_t njs_lexer_multi(njs_lexer_t *lexer, njs_token_t token, nxt_uint_t n, const njs_lexer_multi_t *multi); static njs_token_t njs_lexer_division(njs_lexer_t *lexer, @@ -316,7 +316,7 @@ njs_lexer_next_token(njs_lexer_t *lexer) return njs_lexer_string(lexer, c); case NJS_TOKEN_DIGIT: - return njs_lexer_number(lexer); + return njs_lexer_number(lexer, c); case NJS_TOKEN_ASSIGNMENT: n = nxt_nitems(njs_assignment_token), @@ -523,12 +523,11 @@ njs_lexer_string(njs_lexer_t *lexer, u_c static njs_token_t -njs_lexer_number(njs_lexer_t *lexer) +njs_lexer_number(njs_lexer_t *lexer, u_char c) { - u_char c, *p; + const u_char *p; p = lexer->start; - c = p[-1]; if (c == '0' && p != lexer->end) { @@ -538,14 +537,12 @@ njs_lexer_number(njs_lexer_t *lexer) p++; if (p == lexer->end) { - return NJS_TOKEN_ILLEGAL; + goto illegal_token; } - lexer->start = p; - lexer->number = njs_number_hex_parse((const u_char **) &lexer->start, - lexer->end); + lexer->number = njs_number_hex_parse(&p, lexer->end); - return NJS_TOKEN_NUMBER; + goto done; } /* Octal literal values. */ @@ -554,19 +551,16 @@ njs_lexer_number(njs_lexer_t *lexer) p++; if (p == lexer->end) { - return NJS_TOKEN_ILLEGAL; + goto illegal_token; } - lexer->start = p; - lexer->number = njs_number_oct_parse((const u_char **) &lexer->start, - lexer->end); - p = lexer->start; + lexer->number = njs_number_oct_parse(&p, lexer->end); if (p < lexer->end && (*p == '8' || *p == '9')) { - return NJS_TOKEN_ILLEGAL; + goto illegal_trailer; } - return NJS_TOKEN_NUMBER; + goto done; } /* Binary literal values. */ @@ -575,33 +569,44 @@ njs_lexer_number(njs_lexer_t *lexer) p++; if (p == lexer->end) { - return NJS_TOKEN_ILLEGAL; + goto illegal_token; } - lexer->start = p; - lexer->number = njs_number_bin_parse((const u_char **) &lexer->start, - lexer->end); - p = lexer->start; + lexer->number = njs_number_bin_parse(&p, lexer->end); if (p < lexer->end && (*p >= '2' && *p <= '9')) { - return NJS_TOKEN_ILLEGAL; + goto illegal_trailer; } - return NJS_TOKEN_NUMBER; + goto done; } /* Legacy Octal literals are deprecated. */ if (*p >= '0' && *p <= '9') { - return NJS_TOKEN_ILLEGAL; + goto illegal_trailer; } } - lexer->start = p - 1; - lexer->number = njs_number_dec_parse((const u_char **) &lexer->start, - lexer->end); + p--; + lexer->number = njs_number_dec_parse(&p, lexer->end); + +done: + + lexer->start = (u_char *) p; return NJS_TOKEN_NUMBER; + +illegal_trailer: + + p++; + +illegal_token: + + lexer->text.start = lexer->start - 1; + lexer->text.length = p - lexer->text.start; + + return NJS_TOKEN_ILLEGAL; } diff -r f20bf1b5db20 -r 3aef480987d6 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Tue Jul 03 14:15:29 2018 +0300 +++ b/njs/test/njs_unit_test.c Tue Jul 03 15:48:03 2018 +0300 @@ -127,25 +127,25 @@ static njs_unit_test_t njs_test[] = { nxt_string("-0O777"), nxt_string("-511") }, + { nxt_string("0o"), + nxt_string("SyntaxError: Unexpected token \"0o\" in 1") }, + + { nxt_string("0O778"), + nxt_string("SyntaxError: Unexpected token \"0O778\" in 1") }, + /* Legacy Octal Numbers are deprecated. */ { nxt_string("00"), - nxt_string("SyntaxError: Unexpected token \"\" in 1") }, + nxt_string("SyntaxError: Unexpected token \"00\" in 1") }, { nxt_string("08"), - nxt_string("SyntaxError: Unexpected token \"\" in 1") }, + nxt_string("SyntaxError: Unexpected token \"08\" in 1") }, { nxt_string("09"), - nxt_string("SyntaxError: Unexpected token \"\" in 1") }, + nxt_string("SyntaxError: Unexpected token \"09\" in 1") }, { nxt_string("0011"), - nxt_string("SyntaxError: Unexpected token \"\" in 1") }, - - { nxt_string("0o"), - nxt_string("SyntaxError: Unexpected token \"\" in 1") }, - - { nxt_string("0O778"), - nxt_string("SyntaxError: Unexpected token \"\" in 1") }, + nxt_string("SyntaxError: Unexpected token \"00\" in 1") }, /* Binary Numbers. */ @@ -162,10 +162,10 @@ static njs_unit_test_t njs_test[] = nxt_string("-255") }, { nxt_string("0b"), - nxt_string("SyntaxError: Unexpected token \"\" in 1") }, + nxt_string("SyntaxError: Unexpected token \"0b\" in 1") }, { nxt_string("0B12"), - nxt_string("SyntaxError: Unexpected token \"\" in 1") }, + nxt_string("SyntaxError: Unexpected token \"0B12\" in 1") }, /* Hex Numbers. */ @@ -182,7 +182,7 @@ static njs_unit_test_t njs_test[] = nxt_string("48879") }, { nxt_string("0x"), - nxt_string("SyntaxError: Unexpected token \"\" in 1") }, + nxt_string("SyntaxError: Unexpected token \"0x\" in 1") }, { nxt_string("0xffff."), nxt_string("SyntaxError: Unexpected token \"\" in 1") }, From igor at sysoev.ru Tue Jul 3 12:48:47 2018 From: igor at sysoev.ru (Igor Sysoev) Date: Tue, 03 Jul 2018 12:48:47 +0000 Subject: [njs] Style fixes. Message-ID: details: http://hg.nginx.org/njs/rev/c1f9fe4022bc branches: changeset: 553:c1f9fe4022bc user: Igor Sysoev date: Tue Jul 03 15:48:04 2018 +0300 description: Style fixes. diffstat: njs/njs_error.h | 3 ++- njs/njs_fs.c | 4 ++-- njs/njs_object.c | 3 ++- njs/njs_string.c | 4 ++-- njs/njs_string.h | 4 ++-- 5 files changed, 10 insertions(+), 8 deletions(-) diffs (69 lines): diff -r 3aef480987d6 -r c1f9fe4022bc njs/njs_error.h --- a/njs/njs_error.h Tue Jul 03 15:48:03 2018 +0300 +++ b/njs/njs_error.h Tue Jul 03 15:48:04 2018 +0300 @@ -13,7 +13,8 @@ #define njs_eval_error(vm, fmt, ...) \ njs_exception_error_create(vm, NJS_OBJECT_EVAL_ERROR, fmt, ##__VA_ARGS__) #define njs_internal_error(vm, fmt, ...) \ - njs_exception_error_create(vm, NJS_OBJECT_INTERNAL_ERROR, fmt, ##__VA_ARGS__) + njs_exception_error_create(vm, NJS_OBJECT_INTERNAL_ERROR, fmt, \ + ##__VA_ARGS__) #define njs_range_error(vm, fmt, ...) \ njs_exception_error_create(vm, NJS_OBJECT_RANGE_ERROR, fmt, ##__VA_ARGS__) #define njs_reference_error(vm, fmt, ...) \ diff -r 3aef480987d6 -r c1f9fe4022bc njs/njs_fs.c --- a/njs/njs_fs.c Tue Jul 03 15:48:03 2018 +0300 +++ b/njs/njs_fs.c Tue Jul 03 15:48:04 2018 +0300 @@ -43,8 +43,8 @@ static njs_ret_t njs_fs_write_file_sync( nxt_uint_t nargs, njs_index_t unused); static njs_ret_t njs_fs_write_file_internal(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, int default_flags); -static njs_ret_t njs_fs_write_file_sync_internal(njs_vm_t *vm, njs_value_t *args, - nxt_uint_t nargs, int default_flags); +static njs_ret_t njs_fs_write_file_sync_internal(njs_vm_t *vm, + njs_value_t *args, nxt_uint_t nargs, int default_flags); static njs_ret_t njs_fs_done(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused); diff -r 3aef480987d6 -r c1f9fe4022bc njs/njs_object.c --- a/njs/njs_object.c Tue Jul 03 15:48:03 2018 +0300 +++ b/njs/njs_object.c Tue Jul 03 15:48:04 2018 +0300 @@ -631,7 +631,8 @@ njs_object_keys(njs_vm_t *vm, njs_value_ return NXT_OK; } -njs_array_t* + +njs_array_t * njs_object_keys_array(njs_vm_t *vm, const njs_value_t *object) { size_t size; diff -r 3aef480987d6 -r c1f9fe4022bc njs/njs_string.c --- a/njs/njs_string.c Tue Jul 03 15:48:03 2018 +0300 +++ b/njs/njs_string.c Tue Jul 03 15:48:04 2018 +0300 @@ -716,8 +716,8 @@ njs_string_prototype_value_of(njs_vm_t * */ static njs_ret_t -njs_string_prototype_to_string(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, - njs_index_t unused) +njs_string_prototype_to_string(njs_vm_t *vm, njs_value_t *args, + nxt_uint_t nargs, njs_index_t unused) { nxt_int_t ret; nxt_str_t enc, str; diff -r 3aef480987d6 -r c1f9fe4022bc njs/njs_string.h --- a/njs/njs_string.h Tue Jul 03 15:48:03 2018 +0300 +++ b/njs/njs_string.h Tue Jul 03 15:48:04 2018 +0300 @@ -126,9 +126,9 @@ njs_ret_t njs_string_new(njs_vm_t *vm, n njs_ret_t njs_string_hex(njs_vm_t *vm, njs_value_t *value, const nxt_str_t *src); njs_ret_t njs_string_base64(njs_vm_t *vm, njs_value_t *value, - const nxt_str_t *src); + const nxt_str_t *src); njs_ret_t njs_string_base64url(njs_vm_t *vm, njs_value_t *value, - const nxt_str_t *src); + const nxt_str_t *src); void njs_string_copy(njs_value_t *dst, njs_value_t *src); njs_ret_t njs_string_validate(njs_vm_t *vm, njs_string_prop_t *string, njs_value_t *value); From mdounin at mdounin.ru Tue Jul 3 15:11:27 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 03 Jul 2018 15:11:27 +0000 Subject: [nginx] nginx-1.15.1-RELEASE Message-ID: details: http://hg.nginx.org/nginx/rev/4189160cb946 branches: changeset: 7308:4189160cb946 user: Maxim Dounin date: Tue Jul 03 18:07:43 2018 +0300 description: nginx-1.15.1-RELEASE diffstat: docs/xml/nginx/changes.xml | 67 ++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 67 insertions(+), 0 deletions(-) diffs (77 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,73 @@ + + + + +????????? random ? ????? upstream. + + +the "random" directive inside the "upstream" block. + + + + + +???????? ?????????????????? ??? ????????????? ???????? hash ? ip_hash +????????? ? ?????????? zone. + + +improved performance when using the "hash" and "ip_hash" directives +with the "zone" directive. + + + + + +???????? reuseport ????????? listen +?????? ?????????? SO_REUSEPORT_LB ?? FreeBSD 12. + + +the "reuseport" parameter of the "listen" directive +now uses SO_REUSEPORT_LB on FreeBSD 12. + + + + + +HTTP/2 server push ?? ???????, ???? SSL ?????????????? ??????-???????? +????? nginx'??. + + +HTTP/2 server push did not work if SSL was terminated by a proxy server +in front of nginx. + + + + + +????????? tcp_nopush ?????? ?????????????? ??? ?????????? ? ????????. + + +the "tcp_nopush" directive was always used on backend connections. + + + + + +??? ???????? ???????????? ?? ???? ???? ??????? ?? gRPC-?????? +????? ????????? ??????. + + +sending a disk-buffered request body to a gRPC backend +might fail. + + + + + + From mdounin at mdounin.ru Tue Jul 3 15:11:29 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 03 Jul 2018 15:11:29 +0000 Subject: [nginx] release-1.15.1 tag Message-ID: details: http://hg.nginx.org/nginx/rev/e25319bef66a branches: changeset: 7309:e25319bef66a user: Maxim Dounin date: Tue Jul 03 18:07:44 2018 +0300 description: release-1.15.1 tag diffstat: .hgtags | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diffs (8 lines): diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -426,3 +426,4 @@ 31c929e16910c38492581ef474e72fa67c28f124 64179f242cb55fc206bca59de9bfdc4cf5ebcec7 release-1.13.11 051e5fa03b92b8a564f6b12debd483d267391e82 release-1.13.12 990b3e885636d763b97ed02d0d2cfc161a4e0c09 release-1.15.0 +4189160cb946bb38d0bc0a452b5eb4cdd8979fb5 release-1.15.1 From mdounin at mdounin.ru Thu Jul 5 19:21:08 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Thu, 05 Jul 2018 19:21:08 +0000 Subject: [nginx] Version bump. Message-ID: details: http://hg.nginx.org/nginx/rev/1f410bcef7c1 branches: changeset: 7310:1f410bcef7c1 user: Maxim Dounin date: Thu Jul 05 20:44:58 2018 +0300 description: Version bump. diffstat: src/core/nginx.h | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diffs (14 lines): diff --git a/src/core/nginx.h b/src/core/nginx.h --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1015001 -#define NGINX_VERSION "1.15.1" +#define nginx_version 1015002 +#define NGINX_VERSION "1.15.2" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD From mdounin at mdounin.ru Thu Jul 5 19:21:10 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Thu, 05 Jul 2018 19:21:10 +0000 Subject: [nginx] SSL: logging level of "https proxy request" errors. Message-ID: details: http://hg.nginx.org/nginx/rev/778358452a81 branches: changeset: 7311:778358452a81 user: Maxim Dounin date: Thu Jul 05 20:45:29 2018 +0300 description: SSL: logging level of "https proxy request" errors. The "http request" and "https proxy request" errors cannot happen with HTTP due to pre-handshake checks in ngx_http_ssl_handshake(), but can happen when SSL is used in stream and mail modules. diffstat: src/event/ngx_event_openssl.c | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diffs (12 lines): diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -2062,6 +2062,8 @@ ngx_ssl_connection_error(ngx_connection_ || n == SSL_R_DIGEST_CHECK_FAILED /* 149 */ || n == SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST /* 151 */ || n == SSL_R_EXCESSIVE_MESSAGE_SIZE /* 152 */ + || n == SSL_R_HTTPS_PROXY_REQUEST /* 155 */ + || n == SSL_R_HTTP_REQUEST /* 156 */ || n == SSL_R_LENGTH_MISMATCH /* 159 */ #ifdef SSL_R_NO_CIPHERS_PASSED || n == SSL_R_NO_CIPHERS_PASSED /* 182 */ From mdounin at mdounin.ru Thu Jul 5 19:21:34 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Thu, 05 Jul 2018 19:21:34 +0000 Subject: [nginx] Resolver: retry sending queries on errors (ticket #1511). Message-ID: details: http://hg.nginx.org/nginx/rev/54683f650cbd branches: changeset: 7312:54683f650cbd user: Maxim Dounin date: Thu Jul 05 22:21:14 2018 +0300 description: Resolver: retry sending queries on errors (ticket #1511). Errors when sending UDP datagrams can happen, e.g., when local IP address changes (see fa0e093b64d7), or an unavailable DNS server on the LAN can cause send() to fail with EHOSTDOWN on BSD systems. If this happens during initial query, retry sending immediately, to a different DNS server when possible. If this is not enough, allow normal resend to happen by ignoring the return code of the second ngx_resolver_send_query() call, much like we do in ngx_resolver_resend(). diffstat: src/core/ngx_resolver.c | 20 ++++++++++++++++++-- 1 files changed, 18 insertions(+), 2 deletions(-) diffs (37 lines): diff --git a/src/core/ngx_resolver.c b/src/core/ngx_resolver.c --- a/src/core/ngx_resolver.c +++ b/src/core/ngx_resolver.c @@ -847,7 +847,15 @@ ngx_resolve_name_locked(ngx_resolver_t * rn->nsrvs = 0; if (ngx_resolver_send_query(r, rn) != NGX_OK) { - goto failed; + + /* immediately retry once on failure */ + + rn->last_connection++; + if (rn->last_connection == r->connections.nelts) { + rn->last_connection = 0; + } + + (void) ngx_resolver_send_query(r, rn); } if (ngx_resolver_set_timeout(r, ctx) != NGX_OK) { @@ -1051,7 +1059,15 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx rn->nsrvs = 0; if (ngx_resolver_send_query(r, rn) != NGX_OK) { - goto failed; + + /* immediately retry once on failure */ + + rn->last_connection++; + if (rn->last_connection == r->connections.nelts) { + rn->last_connection = 0; + } + + (void) ngx_resolver_send_query(r, rn); } if (ngx_resolver_set_timeout(r, ctx) != NGX_OK) { From dnj0496 at gmail.com Fri Jul 6 00:44:00 2018 From: dnj0496 at gmail.com (Dk Jack) Date: Thu, 5 Jul 2018 17:44:00 -0700 Subject: header already sent Message-ID: Hi, I have an nginx module. The purpose of my module is to inspect every request and make a binary decision (i.e drop or allow). When dropping, I am sending a custom status code and response message. I've setup my module handler to be called in the NGX_HTTP_REWRITE_PHASE. Things seem to be working fine for the most part except for a small issue. I am seeing 'header already sent' messages in the nginx error.log. In my handler, I create a context for my module and attach it request using the ngx_http_set_ctx call. I am using the context to store some info and also to prevent my module from processing the same request multiple times. My module processes the request only once. I get the 'header already sent' message only for a fraction of the requests. The messages seem to be generated only for requests that I allowed in my module. In my module handler, I return an NGX_DECLINED return code when I allow a request. The message is not generated for every allowed request but only for some of the allowed requests. When the error is generated it is always for POST request and not all POST requests cause this error message to be logged. Could someone explain what could be going on here or where I should look at next to debug this further? Any pointers are appreciated. Thanks. Dk. -------------- next part -------------- An HTML attachment was scrubbed... URL: From mdounin at mdounin.ru Fri Jul 6 01:38:46 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Fri, 6 Jul 2018 04:38:46 +0300 Subject: header already sent In-Reply-To: References: Message-ID: <20180706013846.GV56558@mdounin.ru> Hello! On Thu, Jul 05, 2018 at 05:44:00PM -0700, Dk Jack wrote: > Hi, > I have an nginx module. The purpose of my module is to inspect every > request and make a binary decision (i.e drop or allow). When dropping, I am > sending a custom status code and response message. I've setup my module > handler to be called in the NGX_HTTP_REWRITE_PHASE. Things seem to be > working fine for the most part except for a small issue. > > I am seeing 'header already sent' messages in the nginx error.log. In my > handler, I create a context for my module and attach it request using > the ngx_http_set_ctx call. I am using the context to store some info and > also to prevent my module from processing the same request multiple times. > My module processes the request only once. > > I get the 'header already sent' message only for a fraction of the > requests. The messages seem to be generated only for requests that I > allowed in my module. In my module handler, I return an NGX_DECLINED return > code when I allow a request. The message is not generated for every allowed > request but only for some of the allowed requests. When the error is > generated it is always for POST request and not all POST requests cause > this error message to be logged. > > Could someone explain what could be going on here or where I should look at > next to debug this further? Any pointers are appreciated. Thanks. The "header already sent" alert indicate that there is a serious bug somewhere, resulting in an attempt to send a response header second time. If you see it for POST requests handled by your module, it likely means that you are handling requests with bodies incorrectly. -- Maxim Dounin http://mdounin.ru/ From dnj0496 at gmail.com Fri Jul 6 05:04:28 2018 From: dnj0496 at gmail.com (Dk Jack) Date: Thu, 5 Jul 2018 22:04:28 -0700 Subject: header already sent In-Reply-To: References: Message-ID: After experimenting a little more, it looks it happens when I return error codes that don't fall between NGX_OK - NGX_ABORT. After changing my code to return NGX_DECLINED, the error log went away. On Thu, Jul 5, 2018 at 5:44 PM Dk Jack wrote: > Hi, > I have an nginx module. The purpose of my module is to inspect every > request and make a binary decision (i.e drop or allow). When dropping, I am > sending a custom status code and response message. I've setup my module > handler to be called in the NGX_HTTP_REWRITE_PHASE. Things seem to be > working fine for the most part except for a small issue. > > I am seeing 'header already sent' messages in the nginx error.log. In my > handler, I create a context for my module and attach it request using > the ngx_http_set_ctx call. I am using the context to store some info and > also to prevent my module from processing the same request multiple times. > My module processes the request only once. > > I get the 'header already sent' message only for a fraction of the > requests. The messages seem to be generated only for requests that I > allowed in my module. In my module handler, I return an NGX_DECLINED return > code when I allow a request. The message is not generated for every allowed > request but only for some of the allowed requests. When the error is > generated it is always for POST request and not all POST requests cause > this error message to be logged. > > Could someone explain what could be going on here or where I should look > at next to debug this further? Any pointers are appreciated. Thanks. > > Dk. > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From dnj0496 at gmail.com Fri Jul 6 21:33:32 2018 From: dnj0496 at gmail.com (Dk Jack) Date: Fri, 6 Jul 2018 14:33:32 -0700 Subject: header already sent In-Reply-To: References: Message-ID: Hi, I thought I solved my issue but it looks like I haven't. It just took some time for the log messages to show up. I've attached my code below. In my code, the call HttpModuleProcessRequest returns a non-zero value if the requests needs to be blocked. Would appreciate if some one can help. Thanks ----------------------------------------------------------------------------------------------------------------------------------------------- PS: The issue seems to happen for request that my module blocked, so it seems to be related to the send header call. SendResponseBuffer(ngx_http_request_t *r, ngx_uint_t http_status, char *reason, ngx_int_t rlen) { ngx_int_t rc; ngx_log_t *log = r->connection->log; ngx_buf_t *buf = ngx_create_temp_buf(r->pool, (rlen+16)); // pad. if (NULL == buf) { ngx_log_error(NGX_LOG_ERR, log, 0, "%s: Failed to allocate buffer", __FUNCTION__); return NGX_ERROR; } buf->last = ngx_copy(buf->start, (unsigned char*) data, dlen); rc = ngx_http_discard_request_body(r); if (rc != NGX_OK) { ngx_log_error(NGX_LOG_ERR, log, 0, "%s: Discard req. body failed. rc=%i", __FUNCTION__, rc); return rc; } ngx_chain_t *out_chain = ngx_alloc_chain_link(r->pool); if (NULL == out_chain) { ngx_log_error(NGX_LOG_ERR, log, 0, "%s: Buffer chain alloc failed", __FUNCTION__); return NGX_ERROR; } out_chain->buf = buf; out_chain->next = NULL; buf->last_buf = 1; buf->last_in_chain = 1; r->headers_out.status = http_status; r->headers_out.content_length_n = buf->last - buf->pos; r->headers_out.content_type.len = sizeof("text/plain") - 1; r->headers_out.content_type.data = (u_char *) "text/plain"; r->header_only = 1; r->headers_out.content_length_n = 0; rc = ngx_http_send_header(r); if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { ngx_log_error(NGX_LOG_ERR, log, 0, "%s: Send header failed. rc=%i", __FUNCTION__, rc); return rc; } return ngx_http_output_filter(r, out_chain); } typedef struct { unsigned done:1; } ngx_http_mod_ctx_t; static ngx_int_t ngx_http_request_handler(ngx_http_request_t *r) { ngx_http_mod_ctx_t *ctx = ngx_http_get_module_ctx(r, nginx_http_module); if (ctx) { ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "duplicate invokation"); return NGX_DECLINED; } else { ctx = ngx_palloc(r->connection->pool, sizeof(ngx_http_mod_ctx_t)); if (ctx == NULL) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Out of memory. Cannot allocate context"); return NGX_ERROR; } ctx->done = 0; ngx_http_set_ctx(r, ctx, nginx_http_module); } ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "%s: uri:\"%V\" uuri: \"%V\" call-count:%ud", __FUNCTION__, &r->uri, &r->unparsed_uri, r->main->count); ngx_int_t rc = 0; if (!ctx->done) { char buf[512]; ngx_uint_t len; ngx_uint_t http_status; rc = HttpModuleProcessRequest(r, &http_status, buf, &len); if (!rc) { rc = SendResponseBuffer(r, http_status, buf, len); } } ctx->done = 1; //ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, // "%s: rc = %d, uri:\"%V\"", __FUNCTION__, rc, &r->uri); if ((rc != 0) && (rc != NGX_DECLINED)) { return rc; } // per http://www.nginxguts.com/2011/01/phases/, ACCESS_PHASE handler should return NGX_OK here. // however, returning NGX_OK causes nginx to hang. return NGX_DECLINED; } static ngx_int_t ngx_http_module_init (ngx_conf_t *cf) { ngx_http_handler_pt *hptr; ngx_http_core_main_conf_t *cmcf; cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); hptr = ngx_array_push(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers); if (hptr == NULL) { ngx_log_error(NGX_LOG_ERR, cf->log, 0, "Cannot retrieve Nginx access phase handler pointer"); return NGX_ERROR; } *hptr = ngx_http_request_handler; ngx_log_error(NGX_LOG_INFO, cf->log, 0, "[init] Installed request handler"); return NGX_OK; } On Thu, Jul 5, 2018 at 5:44 PM Dk Jack wrote: > Hi, > I have an nginx module. The purpose of my module is to inspect every > request and make a binary decision (i.e drop or allow). When dropping, I am > sending a custom status code and response message. I've setup my module > handler to be called in the NGX_HTTP_REWRITE_PHASE. Things seem to be > working fine for the most part except for a small issue. > > I am seeing 'header already sent' messages in the nginx error.log. In my > handler, I create a context for my module and attach it request using > the ngx_http_set_ctx call. I am using the context to store some info and > also to prevent my module from processing the same request multiple times. > My module processes the request only once. > > I get the 'header already sent' message only for a fraction of the > requests. The messages seem to be generated only for requests that I > allowed in my module. In my module handler, I return an NGX_DECLINED return > code when I allow a request. The message is not generated for every allowed > request but only for some of the allowed requests. When the error is > generated it is always for POST request and not all POST requests cause > this error message to be logged. > > Could someone explain what could be going on here or where I should look > at next to debug this further? Any pointers are appreciated. Thanks. > > Dk. > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From hungnv at opensource.com.vn Sat Jul 7 01:22:18 2018 From: hungnv at opensource.com.vn (Hung Nguyen) Date: Sat, 7 Jul 2018 08:22:18 +0700 Subject: header already sent In-Reply-To: References: Message-ID: <502136C6-55A6-4E63-8E60-D45EDEFD609A@opensource.com.vn> Hello, I didnt read your code carefully but in case you want to deny request, just return NGX_HTTP_FORBIDDEN, don?t need to send any http header, nginx will take care the rest. If you want to handle 403 error by a custom 403 page, use error handler in nginx configuration file instead. -- H?ng > On Jul 7, 2018, at 04:33, Dk Jack wrote: > > Hi, > I thought I solved my issue but it looks like I haven't. It just took some time for the log messages to show up. > I've attached my code below. In my code, the call HttpModuleProcessRequest returns a non-zero value if > the requests needs to be blocked. Would appreciate if some one can help. Thanks > > ----------------------------------------------------------------------------------------------------------------------------------------------- > PS: The issue seems to happen for request that my module blocked, so it seems to be related to the send header call. > > SendResponseBuffer(ngx_http_request_t *r, ngx_uint_t http_status, char *reason, ngx_int_t rlen) > { > ngx_int_t rc; > ngx_log_t *log = r->connection->log; > ngx_buf_t *buf = ngx_create_temp_buf(r->pool, (rlen+16)); // pad. > if (NULL == buf) { > ngx_log_error(NGX_LOG_ERR, log, 0, "%s: Failed to allocate buffer", __FUNCTION__); > return NGX_ERROR; > } > > buf->last = ngx_copy(buf->start, (unsigned char*) data, dlen); > > rc = ngx_http_discard_request_body(r); > if (rc != NGX_OK) { > ngx_log_error(NGX_LOG_ERR, log, 0, "%s: Discard req. body failed. rc=%i", __FUNCTION__, rc); > return rc; > } > > ngx_chain_t *out_chain = ngx_alloc_chain_link(r->pool); > if (NULL == out_chain) { > ngx_log_error(NGX_LOG_ERR, log, 0, "%s: Buffer chain alloc failed", __FUNCTION__); > return NGX_ERROR; > } > > out_chain->buf = buf; > out_chain->next = NULL; > buf->last_buf = 1; > buf->last_in_chain = 1; > > r->headers_out.status = http_status; > r->headers_out.content_length_n = buf->last - buf->pos; > r->headers_out.content_type.len = sizeof("text/plain") - 1; > r->headers_out.content_type.data = (u_char *) "text/plain"; > r->header_only = 1; > r->headers_out.content_length_n = 0; > > rc = ngx_http_send_header(r); > if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { > ngx_log_error(NGX_LOG_ERR, log, 0, "%s: Send header failed. rc=%i", __FUNCTION__, rc); > return rc; > } > > return ngx_http_output_filter(r, out_chain); > } > > typedef struct { > unsigned done:1; > } ngx_http_mod_ctx_t; > > static ngx_int_t > ngx_http_request_handler(ngx_http_request_t *r) > { > ngx_http_mod_ctx_t *ctx = ngx_http_get_module_ctx(r, nginx_http_module); > if (ctx) { > ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "duplicate invokation"); > return NGX_DECLINED; > } else { > ctx = ngx_palloc(r->connection->pool, sizeof(ngx_http_mod_ctx_t)); > if (ctx == NULL) { > ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, > "Out of memory. Cannot allocate context"); > return NGX_ERROR; > } > > ctx->done = 0; > ngx_http_set_ctx(r, ctx, nginx_http_module); > } > > ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, > "%s: uri:\"%V\" uuri: \"%V\" call-count:%ud", > __FUNCTION__, &r->uri, &r->unparsed_uri, r->main->count); > > ngx_int_t rc = 0; > if (!ctx->done) { > char buf[512]; > ngx_uint_t len; > ngx_uint_t http_status; > > rc = HttpModuleProcessRequest(r, &http_status, buf, &len); > if (!rc) { > rc = SendResponseBuffer(r, http_status, buf, len); > } > } > > ctx->done = 1; > //ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, > // "%s: rc = %d, uri:\"%V\"", __FUNCTION__, rc, &r->uri); > > if ((rc != 0) && (rc != NGX_DECLINED)) { > return rc; > } > > // per http://www.nginxguts.com/2011/01/phases/, ACCESS_PHASE handler should return NGX_OK here. > // however, returning NGX_OK causes nginx to hang. > return NGX_DECLINED; > } > > static ngx_int_t > ngx_http_module_init (ngx_conf_t *cf) > { > ngx_http_handler_pt *hptr; > ngx_http_core_main_conf_t *cmcf; > > cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); > hptr = ngx_array_push(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers); > > if (hptr == NULL) { > ngx_log_error(NGX_LOG_ERR, cf->log, 0, "Cannot retrieve Nginx access phase handler pointer"); > return NGX_ERROR; > } > > *hptr = ngx_http_request_handler; > ngx_log_error(NGX_LOG_INFO, cf->log, 0, "[init] Installed request handler"); > > return NGX_OK; > } > > >> On Thu, Jul 5, 2018 at 5:44 PM Dk Jack wrote: >> Hi, >> I have an nginx module. The purpose of my module is to inspect every request and make a binary decision (i.e drop or allow). When dropping, I am sending a custom status code and response message. I've setup my module handler to be called in the NGX_HTTP_REWRITE_PHASE. Things seem to be working fine for the most part except for a small issue. >> >> I am seeing 'header already sent' messages in the nginx error.log. In my handler, I create a context for my module and attach it request using the ngx_http_set_ctx call. I am using the context to store some info and also to prevent my module from processing the same request multiple times. My module processes the request only once. >> >> I get the 'header already sent' message only for a fraction of the requests. The messages seem to be generated only for requests that I allowed in my module. In my module handler, I return an NGX_DECLINED return code when I allow a request. The message is not generated for every allowed request but only for some of the allowed requests. When the error is generated it is always for POST request and not all POST requests cause this error message to be logged. >> >> Could someone explain what could be going on here or where I should look at next to debug this further? Any pointers are appreciated. Thanks. >> >> Dk. >> > _______________________________________________ > 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 gmm at csdoc.com Sat Jul 7 21:32:08 2018 From: gmm at csdoc.com (Gena Makhomed) Date: Sun, 8 Jul 2018 00:32:08 +0300 Subject: RSS Message-ID: <630adca7-d5b4-5c91-6ddd-6ef05fd63284@csdoc.com> Hello, All! RSS https://hg.nginx.org/nginx/atom-log https://hg.nginx.org/pkg-oss/atom-log https://hg.nginx.org/nginx.org/atom-log stop working, instead of RSS feed html+javascript returned. RSSOwl can't execute javascript and don't see these RSS feeds. Also I can't download http://hg.nginx.org/nginx/archive/tip.tar.gz with curl - also html+javascript returned, which curl don't understand. can you please fix these issues? -- Best regards, Gena From igudger at google.com Mon Jul 9 06:36:45 2018 From: igudger at google.com (Ian Gudger) Date: Sun, 8 Jul 2018 23:36:45 -0700 Subject: [PATCH] Core: remove unused FIOASYNC. In-Reply-To: <20180628114722.GB4858@lo0.su> References: <20180627125705.GE62373@lo0.su> <20180627183139.GL62373@lo0.su> <20180628092740.GA4858@lo0.su> <20180628114722.GB4858@lo0.su> Message-ID: Any update on this? On Thu, Jun 28, 2018 at 4:47 AM Ruslan Ermilov wrote: > > On Thu, Jun 28, 2018 at 12:27:40PM +0300, Ruslan Ermilov wrote: > > On Wed, Jun 27, 2018 at 01:40:26PM -0700, Ian Gudger wrote: > > > Sorry, I understand now. > > > > > > Here is a new patch which removes that too: > > > > > > # HG changeset patch > > > # User Ian Gudger > > > # Date 1529449008 25200 > > > # Tue Jun 19 15:56:48 2018 -0700 > > > # Node ID 8fd0b85081a1cb91fa4495258bb5f9d3a6ef5785 > > > # Parent 118885f7a5774962f1145693d9c26a4c199ca6ea > > > Core: remove FIOASYNC as the SIGIOs it generated were ignored. > > > > > > FIOASYNC and F_SETOWN cause a pid or pgid to receive signals when a file is > > > ready for IO. When using master process mode, this was setup, but the SIGIO > > > signals were ignored. This has been the case since use of FIOASYNC was first > > > added in eaf1f651cf86. Logic ignore the SIGIOs in a case where they > > > unintentionally did something was added in 8abb88374c6c. > > > > > > diff --git a/src/os/unix/ngx_process.c b/src/os/unix/ngx_process.c > > [...] > > > @@ -433,8 +411,6 @@ ngx_signal_handler(int signo, siginfo_t > > > > > > case ngx_signal_value(NGX_RECONFIGURE_SIGNAL): > > > case ngx_signal_value(NGX_CHANGEBIN_SIGNAL): > > > - case SIGIO: > > > - action = ", ignoring"; > > > break; > > > } > > > > On Wed, Jun 27, 2018 at 03:57:05PM +0300, Ruslan Ermilov wrote: > > > Removing setting of an "action" variable looks like an error. > > > > No need to resend the patch. > > Here's a slightly cleaned up patch and commit log: > > # HG changeset patch > # User Ian Gudger > # Date 1529449008 25200 > # Tue Jun 19 15:56:48 2018 -0700 > # Node ID 9d24aafa6626f2915176e80e5279704af6f6d575 > # Parent f2396ecf608bab9acc0545e3e53e36cc2cb9b2e6 > Core: removed FIOASYNC as the SIGIOs it generated were ignored. > > FIOASYNC and F_SETOWN cause a pid or pgid to receive signals when a file is > ready for I/O. When using master process mode, this was set up, but the SIGIO > signals were ignored. This has been the case since use of FIOASYNC was first > added in eaf1f651cf86. Logic to ignore the SIGIOs in a case where they > unintentionally did something was added in 8abb88374c6c. > > diff --git a/src/os/unix/ngx_process.c b/src/os/unix/ngx_process.c > --- a/src/os/unix/ngx_process.c > +++ b/src/os/unix/ngx_process.c > @@ -71,8 +71,6 @@ ngx_signal_t signals[] = { > > { SIGINT, "SIGINT", "", ngx_signal_handler }, > > - { SIGIO, "SIGIO", "", ngx_signal_handler }, > - > { SIGCHLD, "SIGCHLD", "", ngx_signal_handler }, > > { SIGSYS, "SIGSYS, SIG_IGN", "", NULL }, > @@ -87,7 +85,6 @@ ngx_pid_t > ngx_spawn_process(ngx_cycle_t *cycle, ngx_spawn_proc_pt proc, void *data, > char *name, ngx_int_t respawn) > { > - u_long on; > ngx_pid_t pid; > ngx_int_t s; > > @@ -142,21 +139,6 @@ ngx_spawn_process(ngx_cycle_t *cycle, ng > return NGX_INVALID_PID; > } > > - on = 1; > - if (ioctl(ngx_processes[s].channel[0], FIOASYNC, &on) == -1) { > - ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, > - "ioctl(FIOASYNC) failed while spawning \"%s\"", name); > - ngx_close_channel(ngx_processes[s].channel, cycle->log); > - return NGX_INVALID_PID; > - } > - > - if (fcntl(ngx_processes[s].channel[0], F_SETOWN, ngx_pid) == -1) { > - ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, > - "fcntl(F_SETOWN) failed while spawning \"%s\"", name); > - ngx_close_channel(ngx_processes[s].channel, cycle->log); > - return NGX_INVALID_PID; > - } > - > if (fcntl(ngx_processes[s].channel[0], F_SETFD, FD_CLOEXEC) == -1) { > ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, > "fcntl(FD_CLOEXEC) failed while spawning \"%s\"", > @@ -394,10 +376,6 @@ ngx_signal_handler(int signo, siginfo_t > ngx_sigalrm = 1; > break; > > - case SIGIO: > - ngx_sigio = 1; > - break; > - > case SIGCHLD: > ngx_reap = 1; > break; > @@ -433,7 +411,6 @@ ngx_signal_handler(int signo, siginfo_t > > case ngx_signal_value(NGX_RECONFIGURE_SIGNAL): > case ngx_signal_value(NGX_CHANGEBIN_SIGNAL): > - case SIGIO: > action = ", ignoring"; > break; > } > diff --git a/src/os/unix/ngx_process_cycle.c b/src/os/unix/ngx_process_cycle.c > --- a/src/os/unix/ngx_process_cycle.c > +++ b/src/os/unix/ngx_process_cycle.c > @@ -34,7 +34,6 @@ ngx_pid_t ngx_pid; > ngx_pid_t ngx_parent; > > sig_atomic_t ngx_reap; > -sig_atomic_t ngx_sigio; > sig_atomic_t ngx_sigalrm; > sig_atomic_t ngx_terminate; > sig_atomic_t ngx_quit; > @@ -77,7 +76,7 @@ ngx_master_process_cycle(ngx_cycle_t *cy > u_char *p; > size_t size; > ngx_int_t i; > - ngx_uint_t n, sigio; > + ngx_uint_t n; > sigset_t set; > struct itimerval itv; > ngx_uint_t live; > @@ -88,7 +87,6 @@ ngx_master_process_cycle(ngx_cycle_t *cy > sigemptyset(&set); > sigaddset(&set, SIGCHLD); > sigaddset(&set, SIGALRM); > - sigaddset(&set, SIGIO); > sigaddset(&set, SIGINT); > sigaddset(&set, ngx_signal_value(NGX_RECONFIGURE_SIGNAL)); > sigaddset(&set, ngx_signal_value(NGX_REOPEN_SIGNAL)); > @@ -134,13 +132,11 @@ ngx_master_process_cycle(ngx_cycle_t *cy > > ngx_new_binary = 0; > delay = 0; > - sigio = 0; > live = 1; > > for ( ;; ) { > if (delay) { > if (ngx_sigalrm) { > - sigio = 0; > delay *= 2; > ngx_sigalrm = 0; > } > @@ -165,8 +161,7 @@ ngx_master_process_cycle(ngx_cycle_t *cy > > ngx_time_update(); > > - ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, > - "wake up, sigio %i", sigio); > + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "wake up"); > > if (ngx_reap) { > ngx_reap = 0; > @@ -184,13 +179,6 @@ ngx_master_process_cycle(ngx_cycle_t *cy > delay = 50; > } > > - if (sigio) { > - sigio--; > - continue; > - } > - > - sigio = ccf->worker_processes + 2 /* cache processes */; > - > if (delay > 1000) { > ngx_signal_worker_processes(cycle, SIGKILL); > } else { > diff --git a/src/os/unix/ngx_process_cycle.h b/src/os/unix/ngx_process_cycle.h > --- a/src/os/unix/ngx_process_cycle.h > +++ b/src/os/unix/ngx_process_cycle.h > @@ -47,7 +47,6 @@ extern ngx_uint_t ngx_daemonized; > extern ngx_uint_t ngx_exiting; > > extern sig_atomic_t ngx_reap; > -extern sig_atomic_t ngx_sigio; > extern sig_atomic_t ngx_sigalrm; > extern sig_atomic_t ngx_quit; > extern sig_atomic_t ngx_debug_quit; From sb at nginx.com Mon Jul 9 07:41:33 2018 From: sb at nginx.com (Sergey Budnevitch) Date: Mon, 9 Jul 2018 10:41:33 +0300 Subject: RSS In-Reply-To: <630adca7-d5b4-5c91-6ddd-6ef05fd63284@csdoc.com> References: <630adca7-d5b4-5c91-6ddd-6ef05fd63284@csdoc.com> Message-ID: <5EF8161B-256B-4D3D-AC96-C09B1E8B1E50@nginx.com> > On 08 Jul 2018, at 00:32, Gena Makhomed wrote: > > Hello, All! > > RSS > > https://hg.nginx.org/nginx/atom-log > https://hg.nginx.org/pkg-oss/atom-log > https://hg.nginx.org/nginx.org/atom-log > > stop working, instead of RSS feed html+javascript returned. > RSSOwl can't execute javascript and don't see these RSS feeds. > > Also I can't download http://hg.nginx.org/nginx/archive/tip.tar.gz > with curl - also html+javascript returned, which curl don't understand. > > can you please fix these issues? Hi atom-tags, atom-log, archive were removed from bot mitigation mechanism From gmm at csdoc.com Mon Jul 9 08:27:58 2018 From: gmm at csdoc.com (Gena Makhomed) Date: Mon, 9 Jul 2018 11:27:58 +0300 Subject: RSS In-Reply-To: <5EF8161B-256B-4D3D-AC96-C09B1E8B1E50@nginx.com> References: <630adca7-d5b4-5c91-6ddd-6ef05fd63284@csdoc.com> <5EF8161B-256B-4D3D-AC96-C09B1E8B1E50@nginx.com> Message-ID: <564f8af2-cd7b-01fb-62a5-629ca7b306b1@csdoc.com> On 09.07.2018 10:41, Sergey Budnevitch wrote: >> https://hg.nginx.org/nginx/atom-log >> https://hg.nginx.org/pkg-oss/atom-log >> https://hg.nginx.org/nginx.org/atom-log >> >> stop working, instead of RSS feed html+javascript returned. >> RSSOwl can't execute javascript and don't see these RSS feeds. >> >> Also I can't download http://hg.nginx.org/nginx/archive/tip.tar.gz >> with curl - also html+javascript returned, which curl don't understand. >> >> can you please fix these issues? > atom-tags, atom-log, archive were removed from bot mitigation mechanism thank you! but issue not fixed for these urls: http://hg.nginx.org/pkg-oss/atom-log https://hg.nginx.org/pkg-oss/atom-log http://hg.nginx.org/nginx.org/atom-log https://hg.nginx.org/nginx.org/atom-log - they still return html+javascript. P.S. bot mitigation mechanism written as custom "C" module or written using only njs, without 3rd party modules? it is closed source code or will be open source code? bot mitigation mechanism via javascript good for bots, but it also disables site indexing by search engines.(?) it will be good to whitelist search engines by DNS, at least main search engines: Google, Yandex and Bing. https://support.google.com/webmasters/answer/80553?hl=en https://yandex.com/support/webmaster/robot-workings/check-yandex-robots.xml https://www.bing.com/webmaster/help/how-to-verify-bingbot-3905dc26 But even when search engines bots are whitelisted - this can be detected by search engines as https://en.wikipedia.org/wiki/Cloaking Partial solution is to display html+javascript only for bots, which are previously detected as bots by other bot mitigation mechanisms. P.P.S. I write and use other bot mitigation mechanism with nginx: https://github.com/makhomed/autofilter -- Best regards, Gena From vbart at nginx.com Mon Jul 9 08:39:43 2018 From: vbart at nginx.com (Valentin V. Bartenev) Date: Mon, 09 Jul 2018 11:39:43 +0300 Subject: RSS In-Reply-To: <564f8af2-cd7b-01fb-62a5-629ca7b306b1@csdoc.com> References: <630adca7-d5b4-5c91-6ddd-6ef05fd63284@csdoc.com> <5EF8161B-256B-4D3D-AC96-C09B1E8B1E50@nginx.com> <564f8af2-cd7b-01fb-62a5-629ca7b306b1@csdoc.com> Message-ID: <10719933.b5EnhSDhdJ@vbart-laptop> On Monday, 9 July 2018 11:27:58 MSK Gena Makhomed wrote: > On 09.07.2018 10:41, Sergey Budnevitch wrote: > > >> https://hg.nginx.org/nginx/atom-log > >> https://hg.nginx.org/pkg-oss/atom-log > >> https://hg.nginx.org/nginx.org/atom-log > >> > >> stop working, instead of RSS feed html+javascript returned. > >> RSSOwl can't execute javascript and don't see these RSS feeds. > >> > >> Also I can't download http://hg.nginx.org/nginx/archive/tip.tar.gz > >> with curl - also html+javascript returned, which curl don't understand. > >> > >> can you please fix these issues? > > > atom-tags, atom-log, archive were removed from bot mitigation mechanism > > thank you! but issue not fixed for these urls: > > http://hg.nginx.org/pkg-oss/atom-log > https://hg.nginx.org/pkg-oss/atom-log > > http://hg.nginx.org/nginx.org/atom-log > https://hg.nginx.org/nginx.org/atom-log > > - they still return html+javascript. > > P.S. > > bot mitigation mechanism written as custom "C" module > or written using only njs, without 3rd party modules? > It's pretty easy to write one using only njs. > it is closed source code or will be open source code? > > bot mitigation mechanism via javascript good for bots, > but it also disables site indexing by search engines.(?) > > it will be good to whitelist search engines by DNS, > at least main search engines: Google, Yandex and Bing. [..] All main search engines are able to run JS. Nowadays there're a lot of JS-only sites. wbr, Valentin V. Bartenev From gmm at csdoc.com Mon Jul 9 09:12:10 2018 From: gmm at csdoc.com (Gena Makhomed) Date: Mon, 9 Jul 2018 12:12:10 +0300 Subject: RSS In-Reply-To: <5EF8161B-256B-4D3D-AC96-C09B1E8B1E50@nginx.com> References: <630adca7-d5b4-5c91-6ddd-6ef05fd63284@csdoc.com> <5EF8161B-256B-4D3D-AC96-C09B1E8B1E50@nginx.com> Message-ID: <6c492122-4b72-28ff-8d7e-03a38291101b@csdoc.com> On 09.07.2018 10:41, Sergey Budnevitch wrote: > atom-tags, atom-log, archive were removed from bot mitigation mechanism One more bug: If you try to open some page from RSS, for example: http://hg.nginx.org/nginx/rev/54683f650cbd you will see only plain html, this is not expected. Firefox F12/Network show what urls http://hg.nginx.org/nginx/static/mercurial.js http://hg.nginx.org/nginx/static/style-paper.css http://hg.nginx.org/nginx/static/hglogo.png return text/html instead of expected content. -- Best regards, Gena From gmm at csdoc.com Mon Jul 9 09:37:15 2018 From: gmm at csdoc.com (Gena Makhomed) Date: Mon, 9 Jul 2018 12:37:15 +0300 Subject: RSS In-Reply-To: <10719933.b5EnhSDhdJ@vbart-laptop> References: <630adca7-d5b4-5c91-6ddd-6ef05fd63284@csdoc.com> <5EF8161B-256B-4D3D-AC96-C09B1E8B1E50@nginx.com> <564f8af2-cd7b-01fb-62a5-629ca7b306b1@csdoc.com> <10719933.b5EnhSDhdJ@vbart-laptop> Message-ID: On 09.07.2018 11:39, Valentin V. Bartenev wrote: >> bot mitigation mechanism written as custom "C" module >> or written using only njs, without 3rd party modules? > It's pretty easy to write one using only njs. Can you make reference implementation open source under permissive software license? As example of njs features usage and as njs/nginx promotion. May be in future - it will be good to release open source repository of well tested njs code examples, for all customers and nginx users. -- Best regards, Gena From hongzhidao at gmail.com Mon Jul 9 11:51:47 2018 From: hongzhidao at gmail.com (=?UTF-8?B?5rSq5b+X6YGT?=) Date: Mon, 9 Jul 2018 19:51:47 +0800 Subject: [nginx] How to check node has been deleted from rbtree? Message-ID: Hi. As shown the subject, I wonder how to check some node has been deleted from the red-black tree? The case is like the following: Step 1: node1 = ngx_rbtree_insert(...); node2 = ngx_rbtree_insert(...); node3 = ngx_rbtree_insert(...); Step 2: node = find_node_from_rbtree(...); remove_expired_node(...); /* maybe include the node just found. */ new_node = malloc(...); if (new_node == NULL) { return; } /* We should keep the found node alive until the new node is succefully allocated */ if (is_in_rbtree(node)) { /* I wonder how to check */ ngx_rbtree_delete(...); } ngx_rbtree_insert(new_node); Or have other suggestions? Thanks. B.R. -------------- next part -------------- An HTML attachment was scrubbed... URL: From mdounin at mdounin.ru Mon Jul 9 12:23:53 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Mon, 9 Jul 2018 15:23:53 +0300 Subject: [nginx] How to check node has been deleted from rbtree? In-Reply-To: References: Message-ID: <20180709122353.GY56558@mdounin.ru> Hello! On Mon, Jul 09, 2018 at 07:51:47PM +0800, ??? wrote: > As shown the subject, I wonder how to check some node has been deleted from > the red-black tree? No such information is provided. If you need it, you should implement it yourself or rewrite your code to avoid this requirement. In nginx itself, code always knows if a particular node in in the rbtree or not. -- Maxim Dounin http://mdounin.ru/ From hongzhidao at gmail.com Mon Jul 9 12:34:42 2018 From: hongzhidao at gmail.com (=?UTF-8?B?5rSq5b+X6YGT?=) Date: Mon, 9 Jul 2018 20:34:42 +0800 Subject: [nginx] How to check node has been deleted from rbtree? In-Reply-To: <20180709122353.GY56558@mdounin.ru> References: <20180709122353.GY56558@mdounin.ru> Message-ID: Get it now, thank you. On Mon, Jul 9, 2018 at 8:24 PM Maxim Dounin wrote: > Hello! > > On Mon, Jul 09, 2018 at 07:51:47PM +0800, ??? wrote: > > > As shown the subject, I wonder how to check some node has been deleted > from > > the red-black tree? > > No such information is provided. If you need it, you should > implement it yourself or rewrite your code to avoid this > requirement. In nginx itself, code always knows if a particular > node in in the rbtree or not. > > -- > Maxim Dounin > http://mdounin.ru/ > _______________________________________________ > 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 sb at nginx.com Mon Jul 9 14:34:44 2018 From: sb at nginx.com (Sergey Budnevitch) Date: Mon, 9 Jul 2018 17:34:44 +0300 Subject: RSS In-Reply-To: References: <630adca7-d5b4-5c91-6ddd-6ef05fd63284@csdoc.com> <5EF8161B-256B-4D3D-AC96-C09B1E8B1E50@nginx.com> <564f8af2-cd7b-01fb-62a5-629ca7b306b1@csdoc.com> <10719933.b5EnhSDhdJ@vbart-laptop> Message-ID: <6B87F212-D4AC-45E4-A5FB-D157B76088CD@nginx.com> I hope all reported issues were fixed, thank you. > On 9 Jul 2018, at 12:37, Gena Makhomed wrote: > > On 09.07.2018 11:39, Valentin V. Bartenev wrote: > >>> bot mitigation mechanism written as custom "C" module >>> or written using only njs, without 3rd party modules? > >> It's pretty easy to write one using only njs. > > Can you make reference implementation > open source under permissive software license? We should test it ourselves at first, will share it later. From dnj0496 at gmail.com Mon Jul 9 23:41:11 2018 From: dnj0496 at gmail.com (Dk Jack) Date: Mon, 9 Jul 2018 16:41:11 -0700 Subject: header already sent In-Reply-To: References: Message-ID: @Maxim, Sorry did not see your response. Looks like my email settings were incorrect and I was not receiving the emails. I just want to discard the post body and respond with a custom status code and message. In my code, I call ngx_http_discard_request_body before I send the header i.e. the response. Dk. On Thu, Jul 5, 2018 at 5:44 PM Dk Jack wrote: > Hi, > I have an nginx module. The purpose of my module is to inspect every > request and make a binary decision (i.e drop or allow). When dropping, I am > sending a custom status code and response message. I've setup my module > handler to be called in the NGX_HTTP_REWRITE_PHASE. Things seem to be > working fine for the most part except for a small issue. > > I am seeing 'header already sent' messages in the nginx error.log. In my > handler, I create a context for my module and attach it request using > the ngx_http_set_ctx call. I am using the context to store some info and > also to prevent my module from processing the same request multiple times. > My module processes the request only once. > > I get the 'header already sent' message only for a fraction of the > requests. The messages seem to be generated only for requests that I > allowed in my module. In my module handler, I return an NGX_DECLINED return > code when I allow a request. The message is not generated for every allowed > request but only for some of the allowed requests. When the error is > generated it is always for POST request and not all POST requests cause > this error message to be logged. > > Could someone explain what could be going on here or where I should look > at next to debug this further? Any pointers are appreciated. Thanks. > > Dk. > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From dnj0496 at gmail.com Mon Jul 9 23:43:04 2018 From: dnj0496 at gmail.com (Dk Jack) Date: Mon, 9 Jul 2018 16:43:04 -0700 Subject: header already sent In-Reply-To: References: Message-ID: @Hung Nguyen, Sorry did not see your response. Looks like my email settings were incorrect and I was not receiving the emails. I am looking for a way to send custom response without having to change the config. Dk. On Fri, Jul 6, 2018 at 2:33 PM Dk Jack wrote: > Hi, > I thought I solved my issue but it looks like I haven't. It just took some > time for the log messages to show up. > I've attached my code below. In my code, the > call HttpModuleProcessRequest returns a non-zero value if > the requests needs to be blocked. Would appreciate if some one can help. > Thanks > > > ----------------------------------------------------------------------------------------------------------------------------------------------- > PS: The issue seems to happen for request that my module blocked, so it > seems to be related to the send header call. > > SendResponseBuffer(ngx_http_request_t *r, ngx_uint_t http_status, char > *reason, ngx_int_t rlen) > { > ngx_int_t rc; > ngx_log_t *log = r->connection->log; > ngx_buf_t *buf = ngx_create_temp_buf(r->pool, (rlen+16)); // pad. > if (NULL == buf) { > ngx_log_error(NGX_LOG_ERR, log, 0, "%s: Failed to allocate buffer", > __FUNCTION__); > return NGX_ERROR; > } > > buf->last = ngx_copy(buf->start, (unsigned char*) data, dlen); > > rc = ngx_http_discard_request_body(r); > if (rc != NGX_OK) { > ngx_log_error(NGX_LOG_ERR, log, 0, "%s: Discard req. body failed. > rc=%i", __FUNCTION__, rc); > return rc; > } > > ngx_chain_t *out_chain = ngx_alloc_chain_link(r->pool); > if (NULL == out_chain) { > ngx_log_error(NGX_LOG_ERR, log, 0, "%s: Buffer chain alloc failed", > __FUNCTION__); > return NGX_ERROR; > } > > out_chain->buf = buf; > out_chain->next = NULL; > buf->last_buf = 1; > buf->last_in_chain = 1; > > r->headers_out.status = http_status; > r->headers_out.content_length_n = buf->last - buf->pos; > r->headers_out.content_type.len = sizeof("text/plain") - 1; > r->headers_out.content_type.data = (u_char *) "text/plain"; > r->header_only = 1; > r->headers_out.content_length_n = 0; > > rc = ngx_http_send_header(r); > if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { > ngx_log_error(NGX_LOG_ERR, log, 0, "%s: Send header failed. rc=%i", > __FUNCTION__, rc); > return rc; > } > > return ngx_http_output_filter(r, out_chain); > } > > typedef struct { > unsigned done:1; > } ngx_http_mod_ctx_t; > > static ngx_int_t > ngx_http_request_handler(ngx_http_request_t *r) > { > ngx_http_mod_ctx_t *ctx = ngx_http_get_module_ctx(r, nginx_http_module); > if (ctx) { > ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "duplicate > invokation"); > return NGX_DECLINED; > } else { > ctx = ngx_palloc(r->connection->pool, sizeof(ngx_http_mod_ctx_t)); > if (ctx == NULL) { > ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, > "Out of memory. Cannot allocate context"); > return NGX_ERROR; > } > > ctx->done = 0; > ngx_http_set_ctx(r, ctx, nginx_http_module); > } > > ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, > "%s: uri:\"%V\" uuri: \"%V\" call-count:%ud", > __FUNCTION__, &r->uri, &r->unparsed_uri, r->main->count); > > ngx_int_t rc = 0; > if (!ctx->done) { > char buf[512]; > ngx_uint_t len; > ngx_uint_t http_status; > > rc = HttpModuleProcessRequest(r, &http_status, buf, &len); > if (!rc) { > rc = SendResponseBuffer(r, http_status, buf, len); > } > } > > ctx->done = 1; > //ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, > // "%s: rc = %d, uri:\"%V\"", __FUNCTION__, rc, &r->uri); > > if ((rc != 0) && (rc != NGX_DECLINED)) { > return rc; > } > > // per http://www.nginxguts.com/2011/01/phases/, ACCESS_PHASE handler > should return NGX_OK here. > // however, returning NGX_OK causes nginx to hang. > return NGX_DECLINED; > } > > static ngx_int_t > ngx_http_module_init (ngx_conf_t *cf) > { > ngx_http_handler_pt *hptr; > ngx_http_core_main_conf_t *cmcf; > > cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); > hptr = ngx_array_push(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers); > > if (hptr == NULL) { > ngx_log_error(NGX_LOG_ERR, cf->log, 0, "Cannot retrieve Nginx access > phase handler pointer"); > return NGX_ERROR; > } > > *hptr = ngx_http_request_handler; > ngx_log_error(NGX_LOG_INFO, cf->log, 0, "[init] Installed request > handler"); > > return NGX_OK; > } > > > On Thu, Jul 5, 2018 at 5:44 PM Dk Jack wrote: > >> Hi, >> I have an nginx module. The purpose of my module is to inspect every >> request and make a binary decision (i.e drop or allow). When dropping, I am >> sending a custom status code and response message. I've setup my module >> handler to be called in the NGX_HTTP_REWRITE_PHASE. Things seem to be >> working fine for the most part except for a small issue. >> >> I am seeing 'header already sent' messages in the nginx error.log. In my >> handler, I create a context for my module and attach it request using >> the ngx_http_set_ctx call. I am using the context to store some info and >> also to prevent my module from processing the same request multiple times. >> My module processes the request only once. >> >> I get the 'header already sent' message only for a fraction of the >> requests. The messages seem to be generated only for requests that I >> allowed in my module. In my module handler, I return an NGX_DECLINED return >> code when I allow a request. The message is not generated for every allowed >> request but only for some of the allowed requests. When the error is >> generated it is always for POST request and not all POST requests cause >> this error message to be logged. >> >> Could someone explain what could be going on here or where I should look >> at next to debug this further? Any pointers are appreciated. Thanks. >> >> Dk. >> >> -------------- next part -------------- An HTML attachment was scrubbed... URL: From jas594 at optonline.net Tue Jul 10 15:31:45 2018 From: jas594 at optonline.net (Jason Sarnoff) Date: Tue, 10 Jul 2018 11:31:45 -0400 Subject: Supported Versions Message-ID: <02A5E36C-FBAE-4E8F-AD70-B7AB8EC72ACB@optonline.net> Hello, I am seeking support on which nginx versions are still supported in mainline. Although it shows that 1.15.1 is the current mainline version, 1.13 is not in the list of legacy versions. Per Qualys, ?Versions prior to nginx-1.13.5 and nginx-1.12.1 are no longer supported?. Would this mean that versions 1.13.6-1.13.12 are still in mainline and/or are supported? Thanks, Jason From mdounin at mdounin.ru Tue Jul 10 16:49:00 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 10 Jul 2018 19:49:00 +0300 Subject: Supported Versions In-Reply-To: <02A5E36C-FBAE-4E8F-AD70-B7AB8EC72ACB@optonline.net> References: <02A5E36C-FBAE-4E8F-AD70-B7AB8EC72ACB@optonline.net> Message-ID: <20180710164900.GC56558@mdounin.ru> Hello! On Tue, Jul 10, 2018 at 11:31:45AM -0400, Jason Sarnoff wrote: > I am seeking support on which nginx versions are still supported > in mainline. Although it shows that 1.15.1 is the current > mainline version, 1.13 is not in the list of legacy versions. > Per Qualys, ?Versions prior to nginx-1.13.5 and nginx-1.12.1 are > no longer supported?. Would this mean that versions > 1.13.6-1.13.12 are still in mainline and/or are supported? Only latest mainline version is supported. -- Maxim Dounin http://mdounin.ru/ From hongzhidao at gmail.com Wed Jul 11 09:28:22 2018 From: hongzhidao at gmail.com (=?UTF-8?B?5rSq5b+X6YGT?=) Date: Wed, 11 Jul 2018 17:28:22 +0800 Subject: http2 broken Message-ID: Hi. The client can't load the image served by nginx-1.13.6+. [App with Android 7.1.2 4.4.4 4.12 series] It works well in nginx-1.13.5, but go wrong in ngnx-1.13.6+. The change is http://hg.nginx.org/nginx/rev/12cadc4669a7. I found the similar problem. https://github.com/cloudflare/sslconfig/issues/83 Now I don't know where the problem is. NGINX or Client? Does anyone know? Thanks. -------------- next part -------------- An HTML attachment was scrubbed... URL: From hongzhidao at gmail.com Wed Jul 11 09:35:31 2018 From: hongzhidao at gmail.com (=?UTF-8?B?5rSq5b+X6YGT?=) Date: Wed, 11 Jul 2018 17:35:31 +0800 Subject: http2 broken In-Reply-To: References: Message-ID: BTW. It works well by the temporary fix. --- a/src/http/v2/ngx_http_v2_filter_module.c +++ b/src/http/v2/ngx_http_v2_filter_module.c @@ -446,7 +446,6 @@ ngx_http_v2_header_filter(ngx_http_request_t *r) if (h2c->table_update) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, fc->log, 0, "http2 table size update: 0"); - *pos++ = (1 << 5) | 0; h2c->table_update = 0; } @@ -1010,7 +1009,6 @@ ngx_http_v2_push_resource(ngx_http_request_t *r, ngx_str_t *pat if (h2c->table_update) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, fc->log, 0, "http2 table size update: 0"); - *pos++ = (1 << 5) | 0; h2c->table_update = 0; } On Wed, Jul 11, 2018 at 5:28 PM ??? wrote: > Hi. > > The client can't load the image served by nginx-1.13.6+. > [App with Android 7.1.2 4.4.4 4.12 series] > > It works well in nginx-1.13.5, but go wrong in ngnx-1.13.6+. > The change is http://hg.nginx.org/nginx/rev/12cadc4669a7. > > I found the similar problem. > https://github.com/cloudflare/sslconfig/issues/83 > > Now I don't know where the problem is. NGINX or Client? > > Does anyone know? > Thanks. > -------------- next part -------------- An HTML attachment was scrubbed... URL: From zchao1995 at gmail.com Wed Jul 11 09:43:32 2018 From: zchao1995 at gmail.com (tokers) Date: Wed, 11 Jul 2018 11:43:32 +0200 Subject: http2 broken In-Reply-To: References: Message-ID: Hello! There is a known issue caused by some obsolete client like old version okhttp (incomplete protocol implements). Here is the ticket: https://trac.nginx.org/nginx/ticket/1397. -------------- next part -------------- An HTML attachment was scrubbed... URL: From hongzhidao at gmail.com Wed Jul 11 12:56:56 2018 From: hongzhidao at gmail.com (=?UTF-8?B?5rSq5b+X6YGT?=) Date: Wed, 11 Jul 2018 20:56:56 +0800 Subject: http2 broken In-Reply-To: References: Message-ID: Thank you. But there are still some clients use the old version. Is it a way to be compatible with it? Or other suggestions? @Maxim Dounin On Wed, Jul 11, 2018 at 5:43 PM tokers wrote: > Hello! > > There is a known issue caused by some obsolete client like old version > okhttp (incomplete protocol implements). > Here is the ticket: https://trac.nginx.org/nginx/ticket/1397. > _______________________________________________ > 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 ru at nginx.com Wed Jul 11 14:21:03 2018 From: ru at nginx.com (Ruslan Ermilov) Date: Wed, 11 Jul 2018 17:21:03 +0300 Subject: [PATCH] Core: remove unused FIOASYNC. In-Reply-To: References: <20180627125705.GE62373@lo0.su> <20180627183139.GL62373@lo0.su> <20180628092740.GA4858@lo0.su> <20180628114722.GB4858@lo0.su> Message-ID: <20180711142103.GB35930@lo0.su> On Sun, Jul 08, 2018 at 11:36:45PM -0700, Ian Gudger wrote: > Any update on this? The original idea with SIGIO is to wake up master process from sigsuspend() when the message channel is ready for I/O. This feature is currently de-facto unused because if message writing fails, the message is lost and not resent. If this happens in ngx_signal_worker_processes(), the real signal is sent to the worker process as a backup option. If this happens when passing descriptors of inter-worker channels in ngx_pass_open_channel(), there is no backup, but this is not a problem as inter-worker channels aren't currently used. We decided not to commit this patch now because we have plans (https://trac.nginx.org/nginx/ticket/376) to pass descriptors of re-opened log files via the master-to-worker channels, but with reliable delivery (as opposed to the current use cases described above). While using poll() for this could be one of the options, the existing SIGIO mechanism is another one. > On Thu, Jun 28, 2018 at 4:47 AM Ruslan Ermilov wrote: > > > > On Thu, Jun 28, 2018 at 12:27:40PM +0300, Ruslan Ermilov wrote: > > > On Wed, Jun 27, 2018 at 01:40:26PM -0700, Ian Gudger wrote: > > > > Sorry, I understand now. > > > > > > > > Here is a new patch which removes that too: > > > > > > > > # HG changeset patch > > > > # User Ian Gudger > > > > # Date 1529449008 25200 > > > > # Tue Jun 19 15:56:48 2018 -0700 > > > > # Node ID 8fd0b85081a1cb91fa4495258bb5f9d3a6ef5785 > > > > # Parent 118885f7a5774962f1145693d9c26a4c199ca6ea > > > > Core: remove FIOASYNC as the SIGIOs it generated were ignored. > > > > > > > > FIOASYNC and F_SETOWN cause a pid or pgid to receive signals when a file is > > > > ready for IO. When using master process mode, this was setup, but the SIGIO > > > > signals were ignored. This has been the case since use of FIOASYNC was first > > > > added in eaf1f651cf86. Logic ignore the SIGIOs in a case where they > > > > unintentionally did something was added in 8abb88374c6c. > > > > > > > > diff --git a/src/os/unix/ngx_process.c b/src/os/unix/ngx_process.c > > > [...] > > > > @@ -433,8 +411,6 @@ ngx_signal_handler(int signo, siginfo_t > > > > > > > > case ngx_signal_value(NGX_RECONFIGURE_SIGNAL): > > > > case ngx_signal_value(NGX_CHANGEBIN_SIGNAL): > > > > - case SIGIO: > > > > - action = ", ignoring"; > > > > break; > > > > } > > > > > > On Wed, Jun 27, 2018 at 03:57:05PM +0300, Ruslan Ermilov wrote: > > > > Removing setting of an "action" variable looks like an error. > > > > > > No need to resend the patch. > > > > Here's a slightly cleaned up patch and commit log: > > > > # HG changeset patch > > # User Ian Gudger > > # Date 1529449008 25200 > > # Tue Jun 19 15:56:48 2018 -0700 > > # Node ID 9d24aafa6626f2915176e80e5279704af6f6d575 > > # Parent f2396ecf608bab9acc0545e3e53e36cc2cb9b2e6 > > Core: removed FIOASYNC as the SIGIOs it generated were ignored. > > > > FIOASYNC and F_SETOWN cause a pid or pgid to receive signals when a file is > > ready for I/O. When using master process mode, this was set up, but the SIGIO > > signals were ignored. This has been the case since use of FIOASYNC was first > > added in eaf1f651cf86. Logic to ignore the SIGIOs in a case where they > > unintentionally did something was added in 8abb88374c6c. > > > > diff --git a/src/os/unix/ngx_process.c b/src/os/unix/ngx_process.c > > --- a/src/os/unix/ngx_process.c > > +++ b/src/os/unix/ngx_process.c > > @@ -71,8 +71,6 @@ ngx_signal_t signals[] = { > > > > { SIGINT, "SIGINT", "", ngx_signal_handler }, > > > > - { SIGIO, "SIGIO", "", ngx_signal_handler }, > > - > > { SIGCHLD, "SIGCHLD", "", ngx_signal_handler }, > > > > { SIGSYS, "SIGSYS, SIG_IGN", "", NULL }, > > @@ -87,7 +85,6 @@ ngx_pid_t > > ngx_spawn_process(ngx_cycle_t *cycle, ngx_spawn_proc_pt proc, void *data, > > char *name, ngx_int_t respawn) > > { > > - u_long on; > > ngx_pid_t pid; > > ngx_int_t s; > > > > @@ -142,21 +139,6 @@ ngx_spawn_process(ngx_cycle_t *cycle, ng > > return NGX_INVALID_PID; > > } > > > > - on = 1; > > - if (ioctl(ngx_processes[s].channel[0], FIOASYNC, &on) == -1) { > > - ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, > > - "ioctl(FIOASYNC) failed while spawning \"%s\"", name); > > - ngx_close_channel(ngx_processes[s].channel, cycle->log); > > - return NGX_INVALID_PID; > > - } > > - > > - if (fcntl(ngx_processes[s].channel[0], F_SETOWN, ngx_pid) == -1) { > > - ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, > > - "fcntl(F_SETOWN) failed while spawning \"%s\"", name); > > - ngx_close_channel(ngx_processes[s].channel, cycle->log); > > - return NGX_INVALID_PID; > > - } > > - > > if (fcntl(ngx_processes[s].channel[0], F_SETFD, FD_CLOEXEC) == -1) { > > ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, > > "fcntl(FD_CLOEXEC) failed while spawning \"%s\"", > > @@ -394,10 +376,6 @@ ngx_signal_handler(int signo, siginfo_t > > ngx_sigalrm = 1; > > break; > > > > - case SIGIO: > > - ngx_sigio = 1; > > - break; > > - > > case SIGCHLD: > > ngx_reap = 1; > > break; > > @@ -433,7 +411,6 @@ ngx_signal_handler(int signo, siginfo_t > > > > case ngx_signal_value(NGX_RECONFIGURE_SIGNAL): > > case ngx_signal_value(NGX_CHANGEBIN_SIGNAL): > > - case SIGIO: > > action = ", ignoring"; > > break; > > } > > diff --git a/src/os/unix/ngx_process_cycle.c b/src/os/unix/ngx_process_cycle.c > > --- a/src/os/unix/ngx_process_cycle.c > > +++ b/src/os/unix/ngx_process_cycle.c > > @@ -34,7 +34,6 @@ ngx_pid_t ngx_pid; > > ngx_pid_t ngx_parent; > > > > sig_atomic_t ngx_reap; > > -sig_atomic_t ngx_sigio; > > sig_atomic_t ngx_sigalrm; > > sig_atomic_t ngx_terminate; > > sig_atomic_t ngx_quit; > > @@ -77,7 +76,7 @@ ngx_master_process_cycle(ngx_cycle_t *cy > > u_char *p; > > size_t size; > > ngx_int_t i; > > - ngx_uint_t n, sigio; > > + ngx_uint_t n; > > sigset_t set; > > struct itimerval itv; > > ngx_uint_t live; > > @@ -88,7 +87,6 @@ ngx_master_process_cycle(ngx_cycle_t *cy > > sigemptyset(&set); > > sigaddset(&set, SIGCHLD); > > sigaddset(&set, SIGALRM); > > - sigaddset(&set, SIGIO); > > sigaddset(&set, SIGINT); > > sigaddset(&set, ngx_signal_value(NGX_RECONFIGURE_SIGNAL)); > > sigaddset(&set, ngx_signal_value(NGX_REOPEN_SIGNAL)); > > @@ -134,13 +132,11 @@ ngx_master_process_cycle(ngx_cycle_t *cy > > > > ngx_new_binary = 0; > > delay = 0; > > - sigio = 0; > > live = 1; > > > > for ( ;; ) { > > if (delay) { > > if (ngx_sigalrm) { > > - sigio = 0; > > delay *= 2; > > ngx_sigalrm = 0; > > } > > @@ -165,8 +161,7 @@ ngx_master_process_cycle(ngx_cycle_t *cy > > > > ngx_time_update(); > > > > - ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, > > - "wake up, sigio %i", sigio); > > + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "wake up"); > > > > if (ngx_reap) { > > ngx_reap = 0; > > @@ -184,13 +179,6 @@ ngx_master_process_cycle(ngx_cycle_t *cy > > delay = 50; > > } > > > > - if (sigio) { > > - sigio--; > > - continue; > > - } > > - > > - sigio = ccf->worker_processes + 2 /* cache processes */; > > - > > if (delay > 1000) { > > ngx_signal_worker_processes(cycle, SIGKILL); > > } else { > > diff --git a/src/os/unix/ngx_process_cycle.h b/src/os/unix/ngx_process_cycle.h > > --- a/src/os/unix/ngx_process_cycle.h > > +++ b/src/os/unix/ngx_process_cycle.h > > @@ -47,7 +47,6 @@ extern ngx_uint_t ngx_daemonized; > > extern ngx_uint_t ngx_exiting; > > > > extern sig_atomic_t ngx_reap; > > -extern sig_atomic_t ngx_sigio; > > extern sig_atomic_t ngx_sigalrm; > > extern sig_atomic_t ngx_quit; > > extern sig_atomic_t ngx_debug_quit; > -- Ruslan Ermilov Assume stupidity not malice From mdounin at mdounin.ru Wed Jul 11 17:02:05 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Wed, 11 Jul 2018 20:02:05 +0300 Subject: http2 broken In-Reply-To: References: Message-ID: <20180711170205.GM56558@mdounin.ru> Hello! On Wed, Jul 11, 2018 at 08:56:56PM +0800, ??? wrote: > But there are still some clients use the old version. > Is it a way to be compatible with it? > Or other suggestions? > @Maxim Dounin As I already wrote in ticket #1397, we can try introducing a workaround in nginx, but I'm not convinced it worth the effort and, more importantly, associated downsides for non-broken clients. # HG changeset patch # User Maxim Dounin # Date 1531328359 -10800 # Wed Jul 11 19:59:19 2018 +0300 # Node ID f44e74d331885dce8682d2a9802eb707be7ae86f # Parent 54683f650cbdcd73f7f8d845c843295978da5a85 HTTP/2: workaround for clients which fail on table size updates. There are clients which cannot handle HPACK's dynamic table size updates as added in 12cadc4669a7 (1.13.6). Notably, old versions of OkHttp library are known to fail on it (ticket #1397). This change makes it possible to work with such clients by only sending dynamic table size updates in response to SETTINGS_HEADER_TABLE_SIZE. As a downside, clients which do not use SETTINGS_HEADER_TABLE_SIZE will continue to maintain default 4k table. diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c --- a/src/http/v2/ngx_http_v2.c +++ b/src/http/v2/ngx_http_v2.c @@ -270,8 +270,6 @@ ngx_http_v2_init(ngx_event_t *rev) h2c->frame_size = NGX_HTTP_V2_DEFAULT_FRAME_SIZE; - h2c->table_update = 1; - h2scf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_v2_module); h2c->concurrent_pushes = h2scf->concurrent_pushes; @@ -2075,6 +2073,11 @@ ngx_http_v2_state_settings_params(ngx_ht h2c->concurrent_pushes = ngx_min(value, h2scf->concurrent_pushes); break; + case NGX_HTTP_V2_HEADER_TABLE_SIZE_SETTING: + + h2c->table_update = 1; + break; + default: break; } -- Maxim Dounin http://mdounin.ru/ From hongzhidao at gmail.com Wed Jul 11 17:24:53 2018 From: hongzhidao at gmail.com (=?UTF-8?B?5rSq5b+X6YGT?=) Date: Thu, 12 Jul 2018 01:24:53 +0800 Subject: http2 broken In-Reply-To: <20180711170205.GM56558@mdounin.ru> References: <20180711170205.GM56558@mdounin.ru> Message-ID: Get it, I'll try it, thank you again. On Thu, Jul 12, 2018 at 1:02 AM Maxim Dounin wrote: > Hello! > > On Wed, Jul 11, 2018 at 08:56:56PM +0800, ??? wrote: > > > But there are still some clients use the old version. > > Is it a way to be compatible with it? > > Or other suggestions? > > @Maxim Dounin > > As I already wrote in ticket #1397, we can try introducing a > workaround in nginx, but I'm not convinced it worth the effort and, > more importantly, associated downsides for non-broken clients. > > # HG changeset patch > # User Maxim Dounin > # Date 1531328359 -10800 > # Wed Jul 11 19:59:19 2018 +0300 > # Node ID f44e74d331885dce8682d2a9802eb707be7ae86f > # Parent 54683f650cbdcd73f7f8d845c843295978da5a85 > HTTP/2: workaround for clients which fail on table size updates. > > There are clients which cannot handle HPACK's dynamic table size updates > as added in 12cadc4669a7 (1.13.6). Notably, old versions of OkHttp library > are known to fail on it (ticket #1397). > > This change makes it possible to work with such clients by only sending > dynamic table size updates in response to SETTINGS_HEADER_TABLE_SIZE. As > a downside, clients which do not use SETTINGS_HEADER_TABLE_SIZE will > continue to maintain default 4k table. > > diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c > --- a/src/http/v2/ngx_http_v2.c > +++ b/src/http/v2/ngx_http_v2.c > @@ -270,8 +270,6 @@ ngx_http_v2_init(ngx_event_t *rev) > > h2c->frame_size = NGX_HTTP_V2_DEFAULT_FRAME_SIZE; > > - h2c->table_update = 1; > - > h2scf = ngx_http_get_module_srv_conf(hc->conf_ctx, > ngx_http_v2_module); > > h2c->concurrent_pushes = h2scf->concurrent_pushes; > @@ -2075,6 +2073,11 @@ ngx_http_v2_state_settings_params(ngx_ht > h2c->concurrent_pushes = ngx_min(value, > h2scf->concurrent_pushes); > break; > > + case NGX_HTTP_V2_HEADER_TABLE_SIZE_SETTING: > + > + h2c->table_update = 1; > + break; > + > default: > break; > } > > -- > Maxim Dounin > http://mdounin.ru/ > _______________________________________________ > 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 ru at nginx.com Thu Jul 12 09:50:54 2018 From: ru at nginx.com (Ruslan Ermilov) Date: Thu, 12 Jul 2018 09:50:54 +0000 Subject: [nginx] Allow resetting connections closed by "return 444" (ticket #905). Message-ID: details: http://hg.nginx.org/nginx/rev/e45f09198dab branches: changeset: 7313:e45f09198dab user: Ruslan Ermilov date: Thu Jul 12 12:50:20 2018 +0300 description: Allow resetting connections closed by "return 444" (ticket #905). If reset_timedout_connection is on, TCP connections closed by "return 444" will be reset instead of a normal close. diffstat: src/http/ngx_http_request.c | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diffs (11 lines): diff -r 54683f650cbd -r e45f09198dab src/http/ngx_http_request.c --- a/src/http/ngx_http_request.c Thu Jul 05 22:21:14 2018 +0300 +++ b/src/http/ngx_http_request.c Thu Jul 12 12:50:20 2018 +0300 @@ -2353,6 +2353,7 @@ ngx_http_finalize_request(ngx_http_reque || rc == NGX_HTTP_NO_CONTENT) { if (rc == NGX_HTTP_CLOSE) { + c->timedout = 1; ngx_http_terminate_request(r, rc); return; } From xeioex at nginx.com Thu Jul 12 12:24:33 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Thu, 12 Jul 2018 12:24:33 +0000 Subject: [njs] Interactive shell: improved error handling. Message-ID: details: http://hg.nginx.org/njs/rev/0c131f169fe6 branches: changeset: 554:0c131f169fe6 user: Dmitry Volyntsev date: Thu Jul 12 15:24:18 2018 +0300 description: Interactive shell: improved error handling. Previously, compilation errors were not reported in file mode. diffstat: njs/njs_shell.c | 15 ++++----------- 1 files changed, 4 insertions(+), 11 deletions(-) diffs (52 lines): diff -r c1f9fe4022bc -r 0c131f169fe6 njs/njs_shell.c --- a/njs/njs_shell.c Tue Jul 03 15:48:04 2018 +0300 +++ b/njs/njs_shell.c Thu Jul 12 15:24:18 2018 +0300 @@ -229,7 +229,6 @@ static nxt_int_t njs_interactive_shell(njs_opts_t *opts, njs_vm_opt_t *vm_options) { njs_vm_t *vm; - nxt_int_t ret; nxt_str_t line, out; vm = njs_vm_create(vm_options); @@ -266,11 +265,7 @@ njs_interactive_shell(njs_opts_t *opts, add_history((char *) line.start); - ret = njs_process_script(vm, opts, &line, &out); - if (ret != NXT_OK) { - printf("shell: failed to get retval from VM\n"); - continue; - } + njs_process_script(vm, opts, &line, &out); printf("%.*s\n", (int) out.length, out.start); @@ -385,7 +380,7 @@ njs_process_file(njs_opts_t *opts, njs_v ret = njs_process_script(vm, opts, &script, &out); if (ret != NXT_OK) { - fprintf(stderr, "failed to get retval from VM\n"); + fprintf(stderr, "%.*s\n", (int) out.length, out.start); ret = NXT_ERROR; goto done; } @@ -426,16 +421,14 @@ njs_process_script(njs_vm_t *vm, njs_opt } ret = njs_vm_run(vm); - if (ret == NXT_AGAIN) { - return ret; - } } if (njs_vm_retval_to_ext_string(vm, out) != NXT_OK) { + *out = nxt_string_value("failed to get retval from VM"); return NXT_ERROR; } - return NXT_OK; + return ret; } From arut at nginx.com Thu Jul 12 15:50:44 2018 From: arut at nginx.com (Roman Arutyunyan) Date: Thu, 12 Jul 2018 15:50:44 +0000 Subject: [nginx] Stream ssl_preread: $ssl_preread_protocol variable. Message-ID: details: http://hg.nginx.org/nginx/rev/3dfc1584ad75 branches: changeset: 7314:3dfc1584ad75 user: Roman Arutyunyan date: Wed Jul 11 17:56:51 2018 +0300 description: Stream ssl_preread: $ssl_preread_protocol variable. The variable keeps the latest SSL protocol version supported by the client. The variable has the same format as $ssl_protocol. The version is read from the client_version field of ClientHello. If the supported_versions extension is present in the ClientHello, then the version is set to TLSv1.3. diffstat: src/stream/ngx_stream_ssl_preread_module.c | 99 ++++++++++++++++++++++++++++- 1 files changed, 93 insertions(+), 6 deletions(-) diffs (168 lines): diff -r e45f09198dab -r 3dfc1584ad75 src/stream/ngx_stream_ssl_preread_module.c --- a/src/stream/ngx_stream_ssl_preread_module.c Thu Jul 12 12:50:20 2018 +0300 +++ b/src/stream/ngx_stream_ssl_preread_module.c Wed Jul 11 17:56:51 2018 +0300 @@ -21,6 +21,7 @@ typedef struct { u_char *pos; u_char *dst; u_char buf[4]; + u_char version[2]; ngx_str_t host; ngx_str_t alpn; ngx_log_t *log; @@ -32,6 +33,8 @@ typedef struct { static ngx_int_t ngx_stream_ssl_preread_handler(ngx_stream_session_t *s); static ngx_int_t ngx_stream_ssl_preread_parse_record( ngx_stream_ssl_preread_ctx_t *ctx, u_char *pos, u_char *last); +static ngx_int_t ngx_stream_ssl_preread_protocol_variable( + ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_stream_ssl_preread_server_name_variable( ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_stream_ssl_preread_alpn_protocols_variable( @@ -86,6 +89,9 @@ ngx_module_t ngx_stream_ssl_preread_mod static ngx_stream_variable_t ngx_stream_ssl_preread_vars[] = { + { ngx_string("ssl_preread_protocol"), NULL, + ngx_stream_ssl_preread_protocol_variable, 0, 0, 0 }, + { ngx_string("ssl_preread_server_name"), NULL, ngx_stream_ssl_preread_server_name_variable, 0, 0, 0 }, @@ -196,7 +202,8 @@ ngx_stream_ssl_preread_parse_record(ngx_ enum { sw_start = 0, sw_header, /* handshake msg_type, length */ - sw_head_tail, /* version, random */ + sw_version, /* client_version */ + sw_random, /* random */ sw_sid_len, /* session_id length */ sw_sid, /* session_id */ sw_cs_len, /* cipher_suites length */ @@ -210,7 +217,8 @@ ngx_stream_ssl_preread_parse_record(ngx_ sw_sni_host, /* SNI host_name */ sw_alpn_len, /* ALPN length */ sw_alpn_proto_len, /* ALPN protocol_name length */ - sw_alpn_proto_data /* ALPN protocol_name */ + sw_alpn_proto_data, /* ALPN protocol_name */ + sw_supver_len /* supported_versions length */ } state; ngx_log_debug2(NGX_LOG_DEBUG_STREAM, ctx->log, 0, @@ -254,13 +262,19 @@ ngx_stream_ssl_preread_parse_record(ngx_ return NGX_DECLINED; } - state = sw_head_tail; - dst = NULL; - size = 34; + state = sw_version; + dst = ctx->version; + size = 2; left = (p[1] << 16) + (p[2] << 8) + p[3]; break; - case sw_head_tail: + case sw_version: + state = sw_random; + dst = NULL; + size = 32; + break; + + case sw_random: state = sw_sid_len; dst = p; size = 1; @@ -334,6 +348,14 @@ ngx_stream_ssl_preread_parse_record(ngx_ break; } + if (p[0] == 0 && p[1] == 43) { + /* supported_versions extension */ + state = sw_supver_len; + dst = p; + size = 1; + break; + } + state = sw_ext; dst = NULL; size = (p[2] << 8) + p[3]; @@ -434,6 +456,19 @@ ngx_stream_ssl_preread_parse_record(ngx_ dst = NULL; size = 0; break; + + case sw_supver_len: + ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0, + "ssl preread: supported_versions"); + + /* set TLSv1.3 */ + ctx->version[0] = 3; + ctx->version[1] = 4; + + state = sw_ext; + dst = NULL; + size = p[0]; + break; } if (left < size) { @@ -454,6 +489,58 @@ ngx_stream_ssl_preread_parse_record(ngx_ static ngx_int_t +ngx_stream_ssl_preread_protocol_variable(ngx_stream_session_t *s, + ngx_variable_value_t *v, uintptr_t data) +{ + ngx_str_t version; + ngx_stream_ssl_preread_ctx_t *ctx; + + ctx = ngx_stream_get_module_ctx(s, ngx_stream_ssl_preread_module); + + if (ctx == NULL) { + v->not_found = 1; + return NGX_OK; + } + + /* SSL_get_version() format */ + + ngx_str_null(&version); + + switch (ctx->version[0]) { + case 2: + ngx_str_set(&version, "SSLv2"); + break; + case 3: + switch (ctx->version[1]) { + case 0: + ngx_str_set(&version, "SSLv3"); + break; + case 1: + ngx_str_set(&version, "TLSv1"); + break; + case 2: + ngx_str_set(&version, "TLSv1.1"); + break; + case 3: + ngx_str_set(&version, "TLSv1.2"); + break; + case 4: + ngx_str_set(&version, "TLSv1.3"); + break; + } + } + + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->len = version.len; + v->data = version.data; + + return NGX_OK; +} + + +static ngx_int_t ngx_stream_ssl_preread_server_name_variable(ngx_stream_session_t *s, ngx_variable_value_t *v, uintptr_t data) { From mdounin at mdounin.ru Thu Jul 12 17:56:08 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Thu, 12 Jul 2018 17:56:08 +0000 Subject: [nginx] Events: moved sockets cloning to ngx_event_init_conf(). Message-ID: details: http://hg.nginx.org/nginx/rev/e7b2b907c0f8 branches: changeset: 7315:e7b2b907c0f8 user: Maxim Dounin date: Thu Jul 12 19:50:02 2018 +0300 description: Events: moved sockets cloning to ngx_event_init_conf(). Previously, listenings sockets were not cloned if the worker_processes directive was specified after "listen ... reuseport". This also simplifies upcoming configuration check on the number of worker connections, as it needs to know the number of listening sockets before cloning. diffstat: src/core/ngx_connection.c | 9 ++++----- src/core/ngx_connection.h | 2 +- src/event/ngx_event.c | 25 +++++++++++++++++++++++++ src/http/ngx_http.c | 4 ---- src/stream/ngx_stream.c | 4 ---- 5 files changed, 30 insertions(+), 14 deletions(-) diffs (117 lines): diff --git a/src/core/ngx_connection.c b/src/core/ngx_connection.c --- a/src/core/ngx_connection.c +++ b/src/core/ngx_connection.c @@ -96,7 +96,7 @@ ngx_create_listening(ngx_conf_t *cf, str ngx_int_t -ngx_clone_listening(ngx_conf_t *cf, ngx_listening_t *ls) +ngx_clone_listening(ngx_cycle_t *cycle, ngx_listening_t *ls) { #if (NGX_HAVE_REUSEPORT) @@ -104,20 +104,19 @@ ngx_clone_listening(ngx_conf_t *cf, ngx_ ngx_core_conf_t *ccf; ngx_listening_t ols; - if (!ls->reuseport) { + if (!ls->reuseport || ls->worker != 0) { return NGX_OK; } ols = *ls; - ccf = (ngx_core_conf_t *) ngx_get_conf(cf->cycle->conf_ctx, - ngx_core_module); + ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); for (n = 1; n < ccf->worker_processes; n++) { /* create a socket for each worker process */ - ls = ngx_array_push(&cf->cycle->listening); + ls = ngx_array_push(&cycle->listening); if (ls == NULL) { return NGX_ERROR; } diff --git a/src/core/ngx_connection.h b/src/core/ngx_connection.h --- a/src/core/ngx_connection.h +++ b/src/core/ngx_connection.h @@ -210,7 +210,7 @@ struct ngx_connection_s { ngx_listening_t *ngx_create_listening(ngx_conf_t *cf, struct sockaddr *sockaddr, socklen_t socklen); -ngx_int_t ngx_clone_listening(ngx_conf_t *cf, ngx_listening_t *ls); +ngx_int_t ngx_clone_listening(ngx_cycle_t *cycle, ngx_listening_t *ls); ngx_int_t ngx_set_inherited_sockets(ngx_cycle_t *cycle); ngx_int_t ngx_open_listening_sockets(ngx_cycle_t *cycle); void ngx_configure_listening_sockets(ngx_cycle_t *cycle); diff --git a/src/event/ngx_event.c b/src/event/ngx_event.c --- a/src/event/ngx_event.c +++ b/src/event/ngx_event.c @@ -410,12 +410,37 @@ ngx_handle_write_event(ngx_event_t *wev, static char * ngx_event_init_conf(ngx_cycle_t *cycle, void *conf) { +#if (NGX_HAVE_REUSEPORT) + ngx_uint_t i; + ngx_listening_t *ls; +#endif + if (ngx_get_conf(cycle->conf_ctx, ngx_events_module) == NULL) { ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, "no \"events\" section in configuration"); return NGX_CONF_ERROR; } +#if (NGX_HAVE_REUSEPORT) + + ls = cycle->listening.elts; + for (i = 0; i < cycle->listening.nelts; i++) { + + if (!ls[i].reuseport || ls[i].worker != 0) { + continue; + } + + if (ngx_clone_listening(cycle, &ls[i]) != NGX_OK) { + return NGX_CONF_ERROR; + } + + /* cloning may change cycle->listening.elts */ + + ls = cycle->listening.elts; + } + +#endif + return NGX_CONF_OK; } diff --git a/src/http/ngx_http.c b/src/http/ngx_http.c --- a/src/http/ngx_http.c +++ b/src/http/ngx_http.c @@ -1685,10 +1685,6 @@ ngx_http_init_listening(ngx_conf_t *cf, break; } - if (ngx_clone_listening(cf, ls) != NGX_OK) { - return NGX_ERROR; - } - addr++; last--; } diff --git a/src/stream/ngx_stream.c b/src/stream/ngx_stream.c --- a/src/stream/ngx_stream.c +++ b/src/stream/ngx_stream.c @@ -538,10 +538,6 @@ ngx_stream_optimize_servers(ngx_conf_t * break; } - if (ngx_clone_listening(cf, ls) != NGX_OK) { - return NGX_CONF_ERROR; - } - addr++; last--; } From mdounin at mdounin.ru Thu Jul 12 17:56:10 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Thu, 12 Jul 2018 17:56:10 +0000 Subject: [nginx] Events: added configuration check on the number of connections. Message-ID: details: http://hg.nginx.org/nginx/rev/8f152ca81f5f branches: changeset: 7316:8f152ca81f5f user: Maxim Dounin date: Thu Jul 12 19:50:07 2018 +0300 description: Events: added configuration check on the number of connections. There should be at least one worker connection for each listening socket, plus an additional connection for channel between worker and master, or starting worker processes will fail. diffstat: src/event/ngx_event.c | 15 +++++++++++++++ 1 files changed, 15 insertions(+), 0 deletions(-) diffs (25 lines): diff --git a/src/event/ngx_event.c b/src/event/ngx_event.c --- a/src/event/ngx_event.c +++ b/src/event/ngx_event.c @@ -421,6 +421,21 @@ ngx_event_init_conf(ngx_cycle_t *cycle, return NGX_CONF_ERROR; } + if (cycle->connection_n < cycle->listening.nelts + 1) { + + /* + * there should be at least one connection for each listening + * socket, plus an additional connection for channel + */ + + ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, + "%ui worker_connections are not enough " + "for %ui listening sockets", + cycle->connection_n, cycle->listening.nelts); + + return NGX_CONF_ERROR; + } + #if (NGX_HAVE_REUSEPORT) ls = cycle->listening.elts; From dnj0496 at gmail.com Thu Jul 12 20:29:58 2018 From: dnj0496 at gmail.com (Dk Jack) Date: Thu, 12 Jul 2018 13:29:58 -0700 Subject: 2: header already sent Message-ID: Hi, Sorry for sending this again. I haven't been able to resolve my issue. I've read several modules for example and gone over several docs etc. but with no success so far. In my module, I need to either drop the request or allow the request. When I drop the request, I need to send custom response and status. The custom response and status don't come from the config file. When I send the response in the content phase handler, I am am seeing 'header already sent' messages in the error log. How can prevent further processing of the request after my handler is called for the terminal case? Since my module needs to examine all requests irrespective of the uri, I tried registering a content phase handler and send the custom response in that handler. However, my content phase handler is never invoked. I suspect some other content handler is overriding my content handler. Is there a way I can prevent that i.e. for a request, can I force only my content handler to be called. Please let me know what I am doing wrong? I just need to send/perform custom response/actions when a request matches my criteria. I've include a skeleton of my code. Any inputs are greatly appreciated. Thanks. regards, Dk. http_mod_send_response(ngx_http_request_t *r, ngx_uint_t custom_status, char *body, ngx_int_t blen) { ngx_int_t rc; ngx_log_t *log = r->connection->log; ngx_buf_t *buf = ngx_create_temp_buf(r->pool, (blen+16)); // pad. if (NULL == buf) { ngx_log_error(NGX_LOG_ERR, log, 0, "%s: Failed to allocate buffer", __FUNCTION__); return NGX_ERROR; } buf->last = ngx_copy(buf->start, (unsigned char*) data, dlen); rc = ngx_http_discard_request_body(r); if (rc != NGX_OK) { ngx_log_error(NGX_LOG_ERR, log, 0, "%s: Discard req. body failed. rc=%i", __FUNCTION__, rc); return rc; } r->headers_out.status = custom_status; r->headers_out.content_length_n = buf->last - buf->pos; r->headers_out.content_type.len = sizeof("text/plain") - 1; r->headers_out.content_type.data = (u_char *) "text/plain"; rc = ngx_http_send_header(r); if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { ngx_log_error(NGX_LOG_ERR, log, 0, "%s: Send header failed. rc=%i", __FUNCTION__, rc); return rc; } ngx_chain_t *out_chain = ngx_alloc_chain_link(r->pool); if (NULL == out_chain) { ngx_log_error(NGX_LOG_ERR, log, 0, "%s: Buffer chain alloc failed", __FUNCTION__); return NGX_ERROR; } out_chain->buf = buf; out_chain->next = NULL; buf->last_buf = 1; buf->last_in_chain = 1; return ngx_http_output_filter(r, out_chain); } typedef struct { unsigned done:1; } ngx_http_mod_ctx_t; int http_module_process_request(ngx_http_request_t *r, ngx_uint_t *status, char *body, ngx_uint_t *blen) { if (/* request matches criteria */) { /* other boiler plate code */ *status = get_custom_status(); *body = get_custom_body(); *blen = ngx_strlen(body); return *status; // this can be different from custom status. } return NGX_DECLINED; } static ngx_int_t ngx_http_request_handler(ngx_http_request_t *r) { ngx_http_mod_ctx_t *ctx = ngx_http_get_module_ctx(r, nginx_http_module); if (ctx) { ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "duplicate invokation"); return NGX_DECLINED; } else { ctx = ngx_palloc(r->connection->pool, sizeof(ngx_http_mod_ctx_t)); if (ctx == NULL) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Out of memory. Cannot allocate context"); return NGX_ERROR; } ctx->done = 0; ngx_http_set_ctx(r, ctx, nginx_http_module); } ngx_int_t rc = 0; char custom_body[512]; ngx_uint_t blen; ngx_uint_t custom_status; if (!ctx->done) { rc = http_module_process_request(r, &custom_status, custom_body, &blen); } ctx->done = 1; if ((rc != 0) && (rc != NGX_DECLINED)) { return http_mod_send_response(r, custom_status, custom_body, blen); /* alternate implementation, send response in content handler. ngx_buf_t *buf = ngx_create_temp_buf(r->pool, blen); buf->last = ngx_copy(buf->start, (unsigned char*) data, dlen); ctx->custom_body = buf; ctx->rcode = custom_status; */ } return NGX_DECLINED; } static ngx_int_t http_module_content_handler(ngx_http_request_t *r) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "%s: invoked", __FUNCTION__); ngx_http_ss_ctx_t *ctx = ngx_http_get_module_ctx(r, nginx_mitigator_module); if (ctx && ctx->content) { ctx->content = 0; return http_mod_send_response(r, ctx->rcode, ctx->custom_body); } else { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "%s: ctx = %p, content = %d", __FUNCTION__, ctx, ctx ? ctx->content : -1); } return NGX_DECLINED; } static ngx_int_t ngx_http_module_init (ngx_conf_t *cf) { ngx_http_core_main_conf_t *cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); if (!cmcf) { ngx_log_error(NGX_LOG_ERR, cf->log, 0, "Failed to retrieve module main conf"); return NGX_ERROR; } ngx_http_handler_pt *hptr = ngx_array_push(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers); if (hptr == NULL) { ngx_log_error(NGX_LOG_ERR, cf->log, 0, "Could not retrieve access phase handler"); return NGX_ERROR; } *hptr = ngx_http_request_handler; ngx_log_error(NGX_LOG_INFO, cf->log, 0, "[init] Installed request handler"); ngx_http_handler_pt *cptr = ngx_array_push(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers); if (cptr == NULL) { ngx_log_error(NGX_LOG_ERR, cf->log, 0, "Could not retrieve access phase handler"); return NGX_ERROR; } *cptr = ngx_http_request_handler; ngx_log_error(NGX_LOG_INFO, cf->log, 0, "[init] Installed request handler"); return NGX_OK; } -------------- next part -------------- An HTML attachment was scrubbed... URL: From xeioex at nginx.com Fri Jul 13 12:12:30 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Fri, 13 Jul 2018 12:12:30 +0000 Subject: [njs] Returning MemoryError exception without any allocations. Message-ID: details: http://hg.nginx.org/njs/rev/00762256c67a branches: changeset: 555:00762256c67a user: Dmitry Volyntsev date: Fri Jul 13 15:12:11 2018 +0300 description: Returning MemoryError exception without any allocations. diffstat: njs/njs_vm.c | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) diffs (15 lines): diff -r 0c131f169fe6 -r 00762256c67a njs/njs_vm.c --- a/njs/njs_vm.c Thu Jul 12 15:24:18 2018 +0300 +++ b/njs/njs_vm.c Fri Jul 13 15:12:11 2018 +0300 @@ -3162,8 +3162,10 @@ again: if (nxt_slow_path(src->type == NJS_OBJECT_INTERNAL_ERROR)) { /* MemoryError is a nonextensible internal error. */ + if (!src->data.u.object->extensible) { - src = &njs_string_memory_error; + njs_string_get(&njs_string_memory_error, dst); + return NXT_OK; } } From dnj0496 at gmail.com Fri Jul 13 20:18:40 2018 From: dnj0496 at gmail.com (Dk Jack) Date: Fri, 13 Jul 2018 13:18:40 -0700 Subject: 2: header already sent In-Reply-To: References: Message-ID: Sorry, I made a typo in my earlier email. Please read the following sentence: "When I send the response in the *content* phase handler, I am am seeing 'header already sent' messages in the error log." as "When I send the response in the *access* phase handler, I am am seeing 'header already sent' messages in the error log." On Thu, Jul 12, 2018 at 1:29 PM Dk Jack wrote: > Hi, > Sorry for sending this again. I haven't been able to resolve my issue. > I've read several modules for example and gone over several docs etc. but > with no success so far. > > In my module, I need to either drop the request or allow the request. When > I drop the request, I need to send custom response and status. The custom > response and status don't come from the config file. When I send the > response in the content phase handler, I am am seeing 'header already sent' > messages in the error log. How can prevent further processing of the > request after my handler is called for the terminal case? > > Since my module needs to examine all requests irrespective of the uri, I > tried registering a content phase handler and send the custom response in > that handler. However, my content phase handler is never invoked. I suspect > some other content handler is overriding my content handler. Is there a > way I can prevent that i.e. for a request, can I force only my content > handler to be called. > > Please let me know what I am doing wrong? I just need to send/perform > custom response/actions when a request matches my criteria. I've include a > skeleton of my code. > Any inputs are greatly appreciated. Thanks. > > regards, > Dk. > > http_mod_send_response(ngx_http_request_t *r, ngx_uint_t custom_status, > char *body, ngx_int_t blen) > { > ngx_int_t rc; > ngx_log_t *log = r->connection->log; > ngx_buf_t *buf = ngx_create_temp_buf(r->pool, (blen+16)); // pad. > > if (NULL == buf) { > ngx_log_error(NGX_LOG_ERR, log, 0, "%s: Failed to allocate buffer", > __FUNCTION__); > return NGX_ERROR; > } > > buf->last = ngx_copy(buf->start, (unsigned char*) data, dlen); > rc = ngx_http_discard_request_body(r); > if (rc != NGX_OK) { > ngx_log_error(NGX_LOG_ERR, log, 0, "%s: Discard req. body failed. > rc=%i", __FUNCTION__, rc); > return rc; > } > > r->headers_out.status = custom_status; > r->headers_out.content_length_n = buf->last - buf->pos; > r->headers_out.content_type.len = sizeof("text/plain") - 1; > r->headers_out.content_type.data = (u_char *) "text/plain"; > > rc = ngx_http_send_header(r); > if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { > ngx_log_error(NGX_LOG_ERR, log, 0, "%s: Send header failed. rc=%i", > __FUNCTION__, rc); > return rc; > } > > ngx_chain_t *out_chain = ngx_alloc_chain_link(r->pool); > if (NULL == out_chain) { > ngx_log_error(NGX_LOG_ERR, log, 0, "%s: Buffer chain alloc failed", > __FUNCTION__); > return NGX_ERROR; > } > > out_chain->buf = buf; > out_chain->next = NULL; > buf->last_buf = 1; > buf->last_in_chain = 1; > > return ngx_http_output_filter(r, out_chain); > } > > typedef struct { > unsigned done:1; > } ngx_http_mod_ctx_t; > > int > http_module_process_request(ngx_http_request_t *r, ngx_uint_t *status, > char *body, ngx_uint_t *blen) > { > if (/* request matches criteria */) { > /* other boiler plate code */ > *status = get_custom_status(); > *body = get_custom_body(); > *blen = ngx_strlen(body); > return *status; // this can be different from custom status. > } > > return NGX_DECLINED; > } > > static ngx_int_t > ngx_http_request_handler(ngx_http_request_t *r) > { > ngx_http_mod_ctx_t *ctx = ngx_http_get_module_ctx(r, nginx_http_module); > > if (ctx) { > ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "duplicate > invokation"); > return NGX_DECLINED; > } else { > ctx = ngx_palloc(r->connection->pool, sizeof(ngx_http_mod_ctx_t)); > if (ctx == NULL) { > ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, > "Out of memory. Cannot allocate context"); > return NGX_ERROR; > } > > ctx->done = 0; > ngx_http_set_ctx(r, ctx, nginx_http_module); > } > > ngx_int_t rc = 0; > char custom_body[512]; > ngx_uint_t blen; > ngx_uint_t custom_status; > if (!ctx->done) { > rc = http_module_process_request(r, &custom_status, custom_body, > &blen); > } > > ctx->done = 1; > if ((rc != 0) && (rc != NGX_DECLINED)) { > return http_mod_send_response(r, custom_status, custom_body, blen); > /* alternate implementation, send response in content handler. > ngx_buf_t *buf = ngx_create_temp_buf(r->pool, blen); > buf->last = ngx_copy(buf->start, (unsigned char*) data, dlen); > ctx->custom_body = buf; > ctx->rcode = custom_status; > */ > } > > return NGX_DECLINED; > } > > static ngx_int_t > http_module_content_handler(ngx_http_request_t *r) > { > ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "%s: invoked", > __FUNCTION__); > ngx_http_ss_ctx_t *ctx = ngx_http_get_module_ctx(r, > nginx_mitigator_module); > > if (ctx && ctx->content) { > ctx->content = 0; > return http_mod_send_response(r, ctx->rcode, ctx->custom_body); > } else { > ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, > "%s: ctx = %p, content = %d", __FUNCTION__, ctx, ctx ? > ctx->content : -1); > } > > return NGX_DECLINED; > } > > static ngx_int_t > ngx_http_module_init (ngx_conf_t *cf) > { > ngx_http_core_main_conf_t *cmcf = ngx_http_conf_get_module_main_conf(cf, > ngx_http_core_module); > > if (!cmcf) { > ngx_log_error(NGX_LOG_ERR, cf->log, 0, "Failed to retrieve module main > conf"); > return NGX_ERROR; > } > > ngx_http_handler_pt *hptr = > ngx_array_push(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers); > if (hptr == NULL) { > ngx_log_error(NGX_LOG_ERR, cf->log, 0, "Could not retrieve access > phase handler"); > return NGX_ERROR; > } > > *hptr = ngx_http_request_handler; > ngx_log_error(NGX_LOG_INFO, cf->log, 0, "[init] Installed request > handler"); > > ngx_http_handler_pt *cptr = > ngx_array_push(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers); > if (cptr == NULL) { > ngx_log_error(NGX_LOG_ERR, cf->log, 0, "Could not retrieve access > phase handler"); > return NGX_ERROR; > } > > *cptr = ngx_http_request_handler; > ngx_log_error(NGX_LOG_INFO, cf->log, 0, "[init] Installed request > handler"); > > return NGX_OK; > } > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From arut at nginx.com Sat Jul 14 21:36:40 2018 From: arut at nginx.com (Roman Arutyunyan) Date: Sun, 15 Jul 2018 00:36:40 +0300 Subject: 2: header already sent In-Reply-To: References: Message-ID: <20180714213640.GM1406@Romans-MacBook-Air.local> Hi Dk Jack, On Fri, Jul 13, 2018 at 01:18:40PM -0700, Dk Jack wrote: > Sorry, I made a typo in my earlier email. Please read the following > sentence: > > "When I send the response in the *content* phase handler, I am am seeing > 'header already sent' messages in the error log." > > as > > "When I send the response in the *access* phase handler, I am am seeing > 'header already sent' messages in the error log." That's because you do not finalize the request after you send a response in the access handler. A content handler (standard static or another one) is still called at the content phase. It tries to send a second response and obviously gets this error. Finalize the request in the access phase after you send the response with this call: ngx_http_finalize_request(r, rc) where rc is what ngx_http_output_filter() returned. Then return NGX_DONE from the access handler to prevent further request processing. If you want to return a standard error page, simply return its HTTP status code from your access handler instead. > On Thu, Jul 12, 2018 at 1:29 PM Dk Jack wrote: > > > Hi, > > Sorry for sending this again. I haven't been able to resolve my issue. > > I've read several modules for example and gone over several docs etc. but > > with no success so far. > > > > In my module, I need to either drop the request or allow the request. When > > I drop the request, I need to send custom response and status. The custom > > response and status don't come from the config file. When I send the > > response in the content phase handler, I am am seeing 'header already sent' > > messages in the error log. How can prevent further processing of the > > request after my handler is called for the terminal case? > > > > Since my module needs to examine all requests irrespective of the uri, I > > tried registering a content phase handler and send the custom response in > > that handler. However, my content phase handler is never invoked. I suspect > > some other content handler is overriding my content handler. Is there a > > way I can prevent that i.e. for a request, can I force only my content > > handler to be called. > > > > Please let me know what I am doing wrong? I just need to send/perform > > custom response/actions when a request matches my criteria. I've include a > > skeleton of my code. > > Any inputs are greatly appreciated. Thanks. > > > > regards, > > Dk. > > > > http_mod_send_response(ngx_http_request_t *r, ngx_uint_t custom_status, > > char *body, ngx_int_t blen) > > { > > ngx_int_t rc; > > ngx_log_t *log = r->connection->log; > > ngx_buf_t *buf = ngx_create_temp_buf(r->pool, (blen+16)); // pad. > > > > if (NULL == buf) { > > ngx_log_error(NGX_LOG_ERR, log, 0, "%s: Failed to allocate buffer", > > __FUNCTION__); > > return NGX_ERROR; > > } > > > > buf->last = ngx_copy(buf->start, (unsigned char*) data, dlen); > > rc = ngx_http_discard_request_body(r); > > if (rc != NGX_OK) { > > ngx_log_error(NGX_LOG_ERR, log, 0, "%s: Discard req. body failed. > > rc=%i", __FUNCTION__, rc); > > return rc; > > } > > > > r->headers_out.status = custom_status; > > r->headers_out.content_length_n = buf->last - buf->pos; > > r->headers_out.content_type.len = sizeof("text/plain") - 1; > > r->headers_out.content_type.data = (u_char *) "text/plain"; > > > > rc = ngx_http_send_header(r); > > if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { > > ngx_log_error(NGX_LOG_ERR, log, 0, "%s: Send header failed. rc=%i", > > __FUNCTION__, rc); > > return rc; > > } > > > > ngx_chain_t *out_chain = ngx_alloc_chain_link(r->pool); > > if (NULL == out_chain) { > > ngx_log_error(NGX_LOG_ERR, log, 0, "%s: Buffer chain alloc failed", > > __FUNCTION__); > > return NGX_ERROR; > > } > > > > out_chain->buf = buf; > > out_chain->next = NULL; > > buf->last_buf = 1; > > buf->last_in_chain = 1; > > > > return ngx_http_output_filter(r, out_chain); > > } > > > > typedef struct { > > unsigned done:1; > > } ngx_http_mod_ctx_t; > > > > int > > http_module_process_request(ngx_http_request_t *r, ngx_uint_t *status, > > char *body, ngx_uint_t *blen) > > { > > if (/* request matches criteria */) { > > /* other boiler plate code */ > > *status = get_custom_status(); > > *body = get_custom_body(); > > *blen = ngx_strlen(body); > > return *status; // this can be different from custom status. > > } > > > > return NGX_DECLINED; > > } > > > > static ngx_int_t > > ngx_http_request_handler(ngx_http_request_t *r) > > { > > ngx_http_mod_ctx_t *ctx = ngx_http_get_module_ctx(r, nginx_http_module); > > > > if (ctx) { > > ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "duplicate > > invokation"); > > return NGX_DECLINED; > > } else { > > ctx = ngx_palloc(r->connection->pool, sizeof(ngx_http_mod_ctx_t)); > > if (ctx == NULL) { > > ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, > > "Out of memory. Cannot allocate context"); > > return NGX_ERROR; > > } > > > > ctx->done = 0; > > ngx_http_set_ctx(r, ctx, nginx_http_module); > > } > > > > ngx_int_t rc = 0; > > char custom_body[512]; > > ngx_uint_t blen; > > ngx_uint_t custom_status; > > if (!ctx->done) { > > rc = http_module_process_request(r, &custom_status, custom_body, > > &blen); > > } > > > > ctx->done = 1; > > if ((rc != 0) && (rc != NGX_DECLINED)) { > > return http_mod_send_response(r, custom_status, custom_body, blen); > > /* alternate implementation, send response in content handler. > > ngx_buf_t *buf = ngx_create_temp_buf(r->pool, blen); > > buf->last = ngx_copy(buf->start, (unsigned char*) data, dlen); > > ctx->custom_body = buf; > > ctx->rcode = custom_status; > > */ > > } > > > > return NGX_DECLINED; > > } > > > > static ngx_int_t > > http_module_content_handler(ngx_http_request_t *r) > > { > > ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "%s: invoked", > > __FUNCTION__); > > ngx_http_ss_ctx_t *ctx = ngx_http_get_module_ctx(r, > > nginx_mitigator_module); > > > > if (ctx && ctx->content) { > > ctx->content = 0; > > return http_mod_send_response(r, ctx->rcode, ctx->custom_body); > > } else { > > ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, > > "%s: ctx = %p, content = %d", __FUNCTION__, ctx, ctx ? > > ctx->content : -1); > > } > > > > return NGX_DECLINED; > > } > > > > static ngx_int_t > > ngx_http_module_init (ngx_conf_t *cf) > > { > > ngx_http_core_main_conf_t *cmcf = ngx_http_conf_get_module_main_conf(cf, > > ngx_http_core_module); > > > > if (!cmcf) { > > ngx_log_error(NGX_LOG_ERR, cf->log, 0, "Failed to retrieve module main > > conf"); > > return NGX_ERROR; > > } > > > > ngx_http_handler_pt *hptr = > > ngx_array_push(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers); > > if (hptr == NULL) { > > ngx_log_error(NGX_LOG_ERR, cf->log, 0, "Could not retrieve access > > phase handler"); > > return NGX_ERROR; > > } > > > > *hptr = ngx_http_request_handler; > > ngx_log_error(NGX_LOG_INFO, cf->log, 0, "[init] Installed request > > handler"); > > > > ngx_http_handler_pt *cptr = > > ngx_array_push(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers); > > if (cptr == NULL) { > > ngx_log_error(NGX_LOG_ERR, cf->log, 0, "Could not retrieve access > > phase handler"); > > return NGX_ERROR; > > } > > > > *cptr = ngx_http_request_handler; > > ngx_log_error(NGX_LOG_INFO, cf->log, 0, "[init] Installed request > > handler"); > > > > return NGX_OK; > > } > > > > > > > _______________________________________________ > nginx-devel mailing list > nginx-devel at nginx.org > http://mailman.nginx.org/mailman/listinfo/nginx-devel -- Roman Arutyunyan From dnj0496 at gmail.com Sun Jul 15 00:21:02 2018 From: dnj0496 at gmail.com (Dk Jack) Date: Sat, 14 Jul 2018 17:21:02 -0700 Subject: 2: header already sent In-Reply-To: <20180714213640.GM1406@Romans-MacBook-Air.local> References: <20180714213640.GM1406@Romans-MacBook-Air.local> Message-ID: Hi Roman, Thanks for taking the time to respond to my question. I've tried your suggestion. I've done a finalize_req and tried NGX_DONE/OK/... All give me the same result. I get the same result with or without the finalize_req i.e. I still see the 'header already sent' message. I've experimented with the different 'rc' values for the finalize_req i.e. 'rc = NGX_DONE/OK/ERROR' as well. I still see the same result. Please let me know if you have any other suggestions you'd like me to try. Thanks. ./D On Sat, Jul 14, 2018 at 2:37 PM Roman Arutyunyan wrote: > Hi Dk Jack, > > On Fri, Jul 13, 2018 at 01:18:40PM -0700, Dk Jack wrote: > > Sorry, I made a typo in my earlier email. Please read the following > > sentence: > > > > "When I send the response in the *content* phase handler, I am am seeing > > 'header already sent' messages in the error log." > > > > as > > > > "When I send the response in the *access* phase handler, I am am seeing > > 'header already sent' messages in the error log." > > That's because you do not finalize the request after you send a response in > the access handler. A content handler (standard static or another one) is > still called at the content phase. It tries to send a second response and > obviously gets this error. > > Finalize the request in the access phase after you send the response with > this call: > > ngx_http_finalize_request(r, rc) > > where rc is what ngx_http_output_filter() returned. Then return NGX_DONE > from the access handler to prevent further request processing. > > If you want to return a standard error page, simply return its HTTP status > code > from your access handler instead. > > > On Thu, Jul 12, 2018 at 1:29 PM Dk Jack wrote: > > > > > Hi, > > > Sorry for sending this again. I haven't been able to resolve my issue. > > > I've read several modules for example and gone over several docs etc. > but > > > with no success so far. > > > > > > In my module, I need to either drop the request or allow the request. > When > > > I drop the request, I need to send custom response and status. The > custom > > > response and status don't come from the config file. When I send the > > > response in the content phase handler, I am am seeing 'header already > sent' > > > messages in the error log. How can prevent further processing of the > > > request after my handler is called for the terminal case? > > > > > > Since my module needs to examine all requests irrespective of the uri, > I > > > tried registering a content phase handler and send the custom response > in > > > that handler. However, my content phase handler is never invoked. I > suspect > > > some other content handler is overriding my content handler. Is there > a > > > way I can prevent that i.e. for a request, can I force only my content > > > handler to be called. > > > > > > Please let me know what I am doing wrong? I just need to send/perform > > > custom response/actions when a request matches my criteria. I've > include a > > > skeleton of my code. > > > Any inputs are greatly appreciated. Thanks. > > > > > > regards, > > > Dk. > > > > > > http_mod_send_response(ngx_http_request_t *r, ngx_uint_t custom_status, > > > char *body, ngx_int_t blen) > > > { > > > ngx_int_t rc; > > > ngx_log_t *log = r->connection->log; > > > ngx_buf_t *buf = ngx_create_temp_buf(r->pool, (blen+16)); // pad. > > > > > > if (NULL == buf) { > > > ngx_log_error(NGX_LOG_ERR, log, 0, "%s: Failed to allocate buffer", > > > __FUNCTION__); > > > return NGX_ERROR; > > > } > > > > > > buf->last = ngx_copy(buf->start, (unsigned char*) data, dlen); > > > rc = ngx_http_discard_request_body(r); > > > if (rc != NGX_OK) { > > > ngx_log_error(NGX_LOG_ERR, log, 0, "%s: Discard req. body failed. > > > rc=%i", __FUNCTION__, rc); > > > return rc; > > > } > > > > > > r->headers_out.status = custom_status; > > > r->headers_out.content_length_n = buf->last - buf->pos; > > > r->headers_out.content_type.len = sizeof("text/plain") - 1; > > > r->headers_out.content_type.data = (u_char *) "text/plain"; > > > > > > rc = ngx_http_send_header(r); > > > if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { > > > ngx_log_error(NGX_LOG_ERR, log, 0, "%s: Send header failed. rc=%i", > > > __FUNCTION__, rc); > > > return rc; > > > } > > > > > > ngx_chain_t *out_chain = ngx_alloc_chain_link(r->pool); > > > if (NULL == out_chain) { > > > ngx_log_error(NGX_LOG_ERR, log, 0, "%s: Buffer chain alloc failed", > > > __FUNCTION__); > > > return NGX_ERROR; > > > } > > > > > > out_chain->buf = buf; > > > out_chain->next = NULL; > > > buf->last_buf = 1; > > > buf->last_in_chain = 1; > > > > > > return ngx_http_output_filter(r, out_chain); > > > } > > > > > > typedef struct { > > > unsigned done:1; > > > } ngx_http_mod_ctx_t; > > > > > > int > > > http_module_process_request(ngx_http_request_t *r, ngx_uint_t *status, > > > char *body, ngx_uint_t *blen) > > > { > > > if (/* request matches criteria */) { > > > /* other boiler plate code */ > > > *status = get_custom_status(); > > > *body = get_custom_body(); > > > *blen = ngx_strlen(body); > > > return *status; // this can be different from custom status. > > > } > > > > > > return NGX_DECLINED; > > > } > > > > > > static ngx_int_t > > > ngx_http_request_handler(ngx_http_request_t *r) > > > { > > > ngx_http_mod_ctx_t *ctx = ngx_http_get_module_ctx(r, > nginx_http_module); > > > > > > if (ctx) { > > > ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "duplicate > > > invokation"); > > > return NGX_DECLINED; > > > } else { > > > ctx = ngx_palloc(r->connection->pool, sizeof(ngx_http_mod_ctx_t)); > > > if (ctx == NULL) { > > > ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, > > > "Out of memory. Cannot allocate context"); > > > return NGX_ERROR; > > > } > > > > > > ctx->done = 0; > > > ngx_http_set_ctx(r, ctx, nginx_http_module); > > > } > > > > > > ngx_int_t rc = 0; > > > char custom_body[512]; > > > ngx_uint_t blen; > > > ngx_uint_t custom_status; > > > if (!ctx->done) { > > > rc = http_module_process_request(r, &custom_status, custom_body, > > > &blen); > > > } > > > > > > ctx->done = 1; > > > if ((rc != 0) && (rc != NGX_DECLINED)) { > > > return http_mod_send_response(r, custom_status, custom_body, blen); > > > /* alternate implementation, send response in content handler. > > > ngx_buf_t *buf = ngx_create_temp_buf(r->pool, blen); > > > buf->last = ngx_copy(buf->start, (unsigned char*) data, dlen); > > > ctx->custom_body = buf; > > > ctx->rcode = custom_status; > > > */ > > > } > > > > > > return NGX_DECLINED; > > > } > > > > > > static ngx_int_t > > > http_module_content_handler(ngx_http_request_t *r) > > > { > > > ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "%s: invoked", > > > __FUNCTION__); > > > ngx_http_ss_ctx_t *ctx = ngx_http_get_module_ctx(r, > > > nginx_mitigator_module); > > > > > > if (ctx && ctx->content) { > > > ctx->content = 0; > > > return http_mod_send_response(r, ctx->rcode, ctx->custom_body); > > > } else { > > > ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, > > > "%s: ctx = %p, content = %d", __FUNCTION__, ctx, ctx > ? > > > ctx->content : -1); > > > } > > > > > > return NGX_DECLINED; > > > } > > > > > > static ngx_int_t > > > ngx_http_module_init (ngx_conf_t *cf) > > > { > > > ngx_http_core_main_conf_t *cmcf = > ngx_http_conf_get_module_main_conf(cf, > > > ngx_http_core_module); > > > > > > if (!cmcf) { > > > ngx_log_error(NGX_LOG_ERR, cf->log, 0, "Failed to retrieve module > main > > > conf"); > > > return NGX_ERROR; > > > } > > > > > > ngx_http_handler_pt *hptr = > > > ngx_array_push(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers); > > > if (hptr == NULL) { > > > ngx_log_error(NGX_LOG_ERR, cf->log, 0, "Could not retrieve access > > > phase handler"); > > > return NGX_ERROR; > > > } > > > > > > *hptr = ngx_http_request_handler; > > > ngx_log_error(NGX_LOG_INFO, cf->log, 0, "[init] Installed request > > > handler"); > > > > > > ngx_http_handler_pt *cptr = > > > ngx_array_push(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers); > > > if (cptr == NULL) { > > > ngx_log_error(NGX_LOG_ERR, cf->log, 0, "Could not retrieve access > > > phase handler"); > > > return NGX_ERROR; > > > } > > > > > > *cptr = ngx_http_request_handler; > > > ngx_log_error(NGX_LOG_INFO, cf->log, 0, "[init] Installed request > > > handler"); > > > > > > return NGX_OK; > > > } > > > > > > > > > > > > _______________________________________________ > > nginx-devel mailing list > > nginx-devel at nginx.org > > http://mailman.nginx.org/mailman/listinfo/nginx-devel > > > -- > Roman Arutyunyan > _______________________________________________ > 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 arut at nginx.com Sun Jul 15 05:26:10 2018 From: arut at nginx.com (Roman Arutyunyan) Date: Sun, 15 Jul 2018 08:26:10 +0300 Subject: 2: header already sent In-Reply-To: References: <20180714213640.GM1406@Romans-MacBook-Air.local> Message-ID: <20180715052610.GN1406@Romans-MacBook-Air.local> Hi, On Sat, Jul 14, 2018 at 05:21:02PM -0700, Dk Jack wrote: > Hi Roman, > Thanks for taking the time to respond to my question. > > I've tried your suggestion. I've done a finalize_req and tried > NGX_DONE/OK/... All give me the same result. I get the same result with or > without the finalize_req i.e. I still see the 'header already sent' > message. I've experimented with the different 'rc' values for the > finalize_req i.e. 'rc = NGX_DONE/OK/ERROR' as well. I still see the same > result. Please let me know if you have any other suggestions you'd like me > to try. Thanks. Can you show your debug log? https://nginx.org/en/docs/debugging_log.html > On Sat, Jul 14, 2018 at 2:37 PM Roman Arutyunyan wrote: > > > Hi Dk Jack, > > > > On Fri, Jul 13, 2018 at 01:18:40PM -0700, Dk Jack wrote: > > > Sorry, I made a typo in my earlier email. Please read the following > > > sentence: > > > > > > "When I send the response in the *content* phase handler, I am am seeing > > > 'header already sent' messages in the error log." > > > > > > as > > > > > > "When I send the response in the *access* phase handler, I am am seeing > > > 'header already sent' messages in the error log." > > > > That's because you do not finalize the request after you send a response in > > the access handler. A content handler (standard static or another one) is > > still called at the content phase. It tries to send a second response and > > obviously gets this error. > > > > Finalize the request in the access phase after you send the response with > > this call: > > > > ngx_http_finalize_request(r, rc) > > > > where rc is what ngx_http_output_filter() returned. Then return NGX_DONE > > from the access handler to prevent further request processing. > > > > If you want to return a standard error page, simply return its HTTP status > > code > > from your access handler instead. > > > > > On Thu, Jul 12, 2018 at 1:29 PM Dk Jack wrote: > > > > > > > Hi, > > > > Sorry for sending this again. I haven't been able to resolve my issue. > > > > I've read several modules for example and gone over several docs etc. > > but > > > > with no success so far. > > > > > > > > In my module, I need to either drop the request or allow the request. > > When > > > > I drop the request, I need to send custom response and status. The > > custom > > > > response and status don't come from the config file. When I send the > > > > response in the content phase handler, I am am seeing 'header already > > sent' > > > > messages in the error log. How can prevent further processing of the > > > > request after my handler is called for the terminal case? > > > > > > > > Since my module needs to examine all requests irrespective of the uri, > > I > > > > tried registering a content phase handler and send the custom response > > in > > > > that handler. However, my content phase handler is never invoked. I > > suspect > > > > some other content handler is overriding my content handler. Is there > > a > > > > way I can prevent that i.e. for a request, can I force only my content > > > > handler to be called. > > > > > > > > Please let me know what I am doing wrong? I just need to send/perform > > > > custom response/actions when a request matches my criteria. I've > > include a > > > > skeleton of my code. > > > > Any inputs are greatly appreciated. Thanks. > > > > > > > > regards, > > > > Dk. > > > > > > > > http_mod_send_response(ngx_http_request_t *r, ngx_uint_t custom_status, > > > > char *body, ngx_int_t blen) > > > > { > > > > ngx_int_t rc; > > > > ngx_log_t *log = r->connection->log; > > > > ngx_buf_t *buf = ngx_create_temp_buf(r->pool, (blen+16)); // pad. > > > > > > > > if (NULL == buf) { > > > > ngx_log_error(NGX_LOG_ERR, log, 0, "%s: Failed to allocate buffer", > > > > __FUNCTION__); > > > > return NGX_ERROR; > > > > } > > > > > > > > buf->last = ngx_copy(buf->start, (unsigned char*) data, dlen); > > > > rc = ngx_http_discard_request_body(r); > > > > if (rc != NGX_OK) { > > > > ngx_log_error(NGX_LOG_ERR, log, 0, "%s: Discard req. body failed. > > > > rc=%i", __FUNCTION__, rc); > > > > return rc; > > > > } > > > > > > > > r->headers_out.status = custom_status; > > > > r->headers_out.content_length_n = buf->last - buf->pos; > > > > r->headers_out.content_type.len = sizeof("text/plain") - 1; > > > > r->headers_out.content_type.data = (u_char *) "text/plain"; > > > > > > > > rc = ngx_http_send_header(r); > > > > if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { > > > > ngx_log_error(NGX_LOG_ERR, log, 0, "%s: Send header failed. rc=%i", > > > > __FUNCTION__, rc); > > > > return rc; > > > > } > > > > > > > > ngx_chain_t *out_chain = ngx_alloc_chain_link(r->pool); > > > > if (NULL == out_chain) { > > > > ngx_log_error(NGX_LOG_ERR, log, 0, "%s: Buffer chain alloc failed", > > > > __FUNCTION__); > > > > return NGX_ERROR; > > > > } > > > > > > > > out_chain->buf = buf; > > > > out_chain->next = NULL; > > > > buf->last_buf = 1; > > > > buf->last_in_chain = 1; > > > > > > > > return ngx_http_output_filter(r, out_chain); > > > > } > > > > > > > > typedef struct { > > > > unsigned done:1; > > > > } ngx_http_mod_ctx_t; > > > > > > > > int > > > > http_module_process_request(ngx_http_request_t *r, ngx_uint_t *status, > > > > char *body, ngx_uint_t *blen) > > > > { > > > > if (/* request matches criteria */) { > > > > /* other boiler plate code */ > > > > *status = get_custom_status(); > > > > *body = get_custom_body(); > > > > *blen = ngx_strlen(body); > > > > return *status; // this can be different from custom status. > > > > } > > > > > > > > return NGX_DECLINED; > > > > } > > > > > > > > static ngx_int_t > > > > ngx_http_request_handler(ngx_http_request_t *r) > > > > { > > > > ngx_http_mod_ctx_t *ctx = ngx_http_get_module_ctx(r, > > nginx_http_module); > > > > > > > > if (ctx) { > > > > ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "duplicate > > > > invokation"); > > > > return NGX_DECLINED; > > > > } else { > > > > ctx = ngx_palloc(r->connection->pool, sizeof(ngx_http_mod_ctx_t)); > > > > if (ctx == NULL) { > > > > ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, > > > > "Out of memory. Cannot allocate context"); > > > > return NGX_ERROR; > > > > } > > > > > > > > ctx->done = 0; > > > > ngx_http_set_ctx(r, ctx, nginx_http_module); > > > > } > > > > > > > > ngx_int_t rc = 0; > > > > char custom_body[512]; > > > > ngx_uint_t blen; > > > > ngx_uint_t custom_status; > > > > if (!ctx->done) { > > > > rc = http_module_process_request(r, &custom_status, custom_body, > > > > &blen); > > > > } > > > > > > > > ctx->done = 1; > > > > if ((rc != 0) && (rc != NGX_DECLINED)) { > > > > return http_mod_send_response(r, custom_status, custom_body, blen); > > > > /* alternate implementation, send response in content handler. > > > > ngx_buf_t *buf = ngx_create_temp_buf(r->pool, blen); > > > > buf->last = ngx_copy(buf->start, (unsigned char*) data, dlen); > > > > ctx->custom_body = buf; > > > > ctx->rcode = custom_status; > > > > */ > > > > } > > > > > > > > return NGX_DECLINED; > > > > } > > > > > > > > static ngx_int_t > > > > http_module_content_handler(ngx_http_request_t *r) > > > > { > > > > ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "%s: invoked", > > > > __FUNCTION__); > > > > ngx_http_ss_ctx_t *ctx = ngx_http_get_module_ctx(r, > > > > nginx_mitigator_module); > > > > > > > > if (ctx && ctx->content) { > > > > ctx->content = 0; > > > > return http_mod_send_response(r, ctx->rcode, ctx->custom_body); > > > > } else { > > > > ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, > > > > "%s: ctx = %p, content = %d", __FUNCTION__, ctx, ctx > > ? > > > > ctx->content : -1); > > > > } > > > > > > > > return NGX_DECLINED; > > > > } > > > > > > > > static ngx_int_t > > > > ngx_http_module_init (ngx_conf_t *cf) > > > > { > > > > ngx_http_core_main_conf_t *cmcf = > > ngx_http_conf_get_module_main_conf(cf, > > > > ngx_http_core_module); > > > > > > > > if (!cmcf) { > > > > ngx_log_error(NGX_LOG_ERR, cf->log, 0, "Failed to retrieve module > > main > > > > conf"); > > > > return NGX_ERROR; > > > > } > > > > > > > > ngx_http_handler_pt *hptr = > > > > ngx_array_push(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers); > > > > if (hptr == NULL) { > > > > ngx_log_error(NGX_LOG_ERR, cf->log, 0, "Could not retrieve access > > > > phase handler"); > > > > return NGX_ERROR; > > > > } > > > > > > > > *hptr = ngx_http_request_handler; > > > > ngx_log_error(NGX_LOG_INFO, cf->log, 0, "[init] Installed request > > > > handler"); > > > > > > > > ngx_http_handler_pt *cptr = > > > > ngx_array_push(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers); > > > > if (cptr == NULL) { > > > > ngx_log_error(NGX_LOG_ERR, cf->log, 0, "Could not retrieve access > > > > phase handler"); > > > > return NGX_ERROR; > > > > } > > > > > > > > *cptr = ngx_http_request_handler; > > > > ngx_log_error(NGX_LOG_INFO, cf->log, 0, "[init] Installed request > > > > handler"); > > > > > > > > return NGX_OK; > > > > } > > > > > > > > > > > > > > > > > _______________________________________________ > > > nginx-devel mailing list > > > nginx-devel at nginx.org > > > http://mailman.nginx.org/mailman/listinfo/nginx-devel > > > > > > -- > > Roman Arutyunyan > > _______________________________________________ > > nginx-devel mailing list > > nginx-devel at nginx.org > > http://mailman.nginx.org/mailman/listinfo/nginx-devel > > > _______________________________________________ > nginx-devel mailing list > nginx-devel at nginx.org > http://mailman.nginx.org/mailman/listinfo/nginx-devel -- Roman Arutyunyan From dnj0496 at gmail.com Mon Jul 16 01:09:24 2018 From: dnj0496 at gmail.com (Dk Jack) Date: Sun, 15 Jul 2018 18:09:24 -0700 Subject: 2: header already sent In-Reply-To: <20180715052610.GN1406@Romans-MacBook-Air.local> References: <20180714213640.GM1406@Romans-MacBook-Air.local> <20180715052610.GN1406@Romans-MacBook-Air.local> Message-ID: Hi Roman, Sorry, it took a while for me to test the debug build. Since my module was using timers, the debug logs in ngx_event_timer.{c,h} were causing a crash (see end of email for details about the crash). Anyways, the debug log attached at the end of the email. Looking at the debug logs, it looks like the ngx_http_finalize_request is calling ngx_http_special_response_handler for any 'rc >= NGX_HTTP_SPECIAL_RESPONSE (300)'. Since I was passing a 403 for the rc value, it was calling the special_response_handler function which in turn calls the send_header function. Since I had already called the send_header function before calling the finalize_request, it generates the 'header already sent' message. After going over the ngx_http_finalize_request code, I realized, if I invoked the ngx_http_finalize_request function with 'rc = NGX_HTTP_CLOSE', the finalize_request function will terminate the request and will not call the ngx_http_special_response_handler which was causing the problem. I tried it and it seems to work. Not sure if this the correct approach. Please let me know. Thanks for your help. Greatly appreciate it. ./D --------------------------------------------------------------------------------------------------------------- event_timer crash when debug enabled: #define ngx_event_ident(p) ((ngx_connection_t *) (p))->fd ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0, "event timer del: %d: %M", ngx_event_ident(ev->data), ev->timer.key); event_timer.{c,h} files have these sort of debug statements sprinkled all over these two files. The ngx_event_ident macro seems to treat the data pointer as a ngx_connection_t pointer and is attempting to dereference it which causes the crash. In my case, the ev->data was NULL. ------------------------------------------------------------------------------------------------------------------- 2018/07/15 23:28:58 [error] 12381#12381: *2 ngx_http_request_handler: rc = 403, uri:"/a/b/c", client: 10.3.28.146, server: live.testdomain.com, request: "GET /a/b/c HTTP/1.1", host: "live.testdomain.com" 2018/07/15 23:28:58 [error] 12381#12381: *2 ngx_http_request_handler: finalize_req rc = 403, uri:"/a/b/c", client: 10.3.28.146, server: live.testdomain.com, request: "GET /a/b/c HTTP/1.1", host: " live.testdomain.com" 2018/07/15 23:28:58 [debug] 12381#12381: *2 http finalize request: 403, "/a/b/c?" a:1, c:1 2018/07/15 23:28:58 [debug] 12381#12381: *2 http special response: 403, "/a/b/c?" 2018/07/15 23:28:58 [debug] 12381#12381: *2 http set discard body 2018/07/15 23:28:58 [alert] 12381#12381: *2 header already sent, client: 10.3.28.146, server: live.testdomain.com, request: "GET /a/b/c HTTP/1.1", host: "live.testdomain.com" 2018/07/15 23:28:58 [debug] 12381#12381: *2 http finalize request: -1, "/a/b/c?" a:1, c:1 2018/07/15 23:28:58 [debug] 12381#12381: *2 http terminate request count:1 2018/07/15 23:28:58 [debug] 12381#12381: *2 http terminate cleanup count:1 blk:0 2018/07/15 23:28:58 [debug] 12381#12381: *2 http posted request: "/a/b/c?" 2018/07/15 23:28:58 [debug] 12381#12381: *2 http terminate handler count:1 2018/07/15 23:28:58 [debug] 12381#12381: *2 http request count:1 blk:0 2018/07/15 23:28:58 [debug] 12381#12381: *2 http close request 2018/07/15 23:28:58 [debug] 12381#12381: *2 http log handler On Sat, Jul 14, 2018 at 10:26 PM Roman Arutyunyan wrote: > Hi, > > On Sat, Jul 14, 2018 at 05:21:02PM -0700, Dk Jack wrote: > > Hi Roman, > > Thanks for taking the time to respond to my question. > > > > I've tried your suggestion. I've done a finalize_req and tried > > NGX_DONE/OK/... All give me the same result. I get the same result with > or > > without the finalize_req i.e. I still see the 'header already sent' > > message. I've experimented with the different 'rc' values for the > > finalize_req i.e. 'rc = NGX_DONE/OK/ERROR' as well. I still see the same > > result. Please let me know if you have any other suggestions you'd like > me > > to try. Thanks. > > Can you show your debug log? > > https://nginx.org/en/docs/debugging_log.html > > > On Sat, Jul 14, 2018 at 2:37 PM Roman Arutyunyan wrote: > > > > > Hi Dk Jack, > > > > > > On Fri, Jul 13, 2018 at 01:18:40PM -0700, Dk Jack wrote: > > > > Sorry, I made a typo in my earlier email. Please read the following > > > > sentence: > > > > > > > > "When I send the response in the *content* phase handler, I am am > seeing > > > > 'header already sent' messages in the error log." > > > > > > > > as > > > > > > > > "When I send the response in the *access* phase handler, I am am > seeing > > > > 'header already sent' messages in the error log." > > > > > > That's because you do not finalize the request after you send a > response in > > > the access handler. A content handler (standard static or another > one) is > > > still called at the content phase. It tries to send a second response > and > > > obviously gets this error. > > > > > > Finalize the request in the access phase after you send the response > with > > > this call: > > > > > > ngx_http_finalize_request(r, rc) > > > > > > where rc is what ngx_http_output_filter() returned. Then return > NGX_DONE > > > from the access handler to prevent further request processing. > > > > > > If you want to return a standard error page, simply return its HTTP > status > > > code > > > from your access handler instead. > > > > > > > On Thu, Jul 12, 2018 at 1:29 PM Dk Jack wrote: > > > > > > > > > Hi, > > > > > Sorry for sending this again. I haven't been able to resolve my > issue. > > > > > I've read several modules for example and gone over several docs > etc. > > > but > > > > > with no success so far. > > > > > > > > > > In my module, I need to either drop the request or allow the > request. > > > When > > > > > I drop the request, I need to send custom response and status. The > > > custom > > > > > response and status don't come from the config file. When I send > the > > > > > response in the content phase handler, I am am seeing 'header > already > > > sent' > > > > > messages in the error log. How can prevent further processing of > the > > > > > request after my handler is called for the terminal case? > > > > > > > > > > Since my module needs to examine all requests irrespective of the > uri, > > > I > > > > > tried registering a content phase handler and send the custom > response > > > in > > > > > that handler. However, my content phase handler is never invoked. I > > > suspect > > > > > some other content handler is overriding my content handler. Is > there > > > a > > > > > way I can prevent that i.e. for a request, can I force only my > content > > > > > handler to be called. > > > > > > > > > > Please let me know what I am doing wrong? I just need to > send/perform > > > > > custom response/actions when a request matches my criteria. I've > > > include a > > > > > skeleton of my code. > > > > > Any inputs are greatly appreciated. Thanks. > > > > > > > > > > regards, > > > > > Dk. > > > > > > > > > > http_mod_send_response(ngx_http_request_t *r, ngx_uint_t > custom_status, > > > > > char *body, ngx_int_t blen) > > > > > { > > > > > ngx_int_t rc; > > > > > ngx_log_t *log = r->connection->log; > > > > > ngx_buf_t *buf = ngx_create_temp_buf(r->pool, (blen+16)); // pad. > > > > > > > > > > if (NULL == buf) { > > > > > ngx_log_error(NGX_LOG_ERR, log, 0, "%s: Failed to allocate > buffer", > > > > > __FUNCTION__); > > > > > return NGX_ERROR; > > > > > } > > > > > > > > > > buf->last = ngx_copy(buf->start, (unsigned char*) data, dlen); > > > > > rc = ngx_http_discard_request_body(r); > > > > > if (rc != NGX_OK) { > > > > > ngx_log_error(NGX_LOG_ERR, log, 0, "%s: Discard req. body > failed. > > > > > rc=%i", __FUNCTION__, rc); > > > > > return rc; > > > > > } > > > > > > > > > > r->headers_out.status = custom_status; > > > > > r->headers_out.content_length_n = buf->last - buf->pos; > > > > > r->headers_out.content_type.len = sizeof("text/plain") - 1; > > > > > r->headers_out.content_type.data = (u_char *) "text/plain"; > > > > > > > > > > rc = ngx_http_send_header(r); > > > > > if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { > > > > > ngx_log_error(NGX_LOG_ERR, log, 0, "%s: Send header failed. > rc=%i", > > > > > __FUNCTION__, rc); > > > > > return rc; > > > > > } > > > > > > > > > > ngx_chain_t *out_chain = ngx_alloc_chain_link(r->pool); > > > > > if (NULL == out_chain) { > > > > > ngx_log_error(NGX_LOG_ERR, log, 0, "%s: Buffer chain alloc > failed", > > > > > __FUNCTION__); > > > > > return NGX_ERROR; > > > > > } > > > > > > > > > > out_chain->buf = buf; > > > > > out_chain->next = NULL; > > > > > buf->last_buf = 1; > > > > > buf->last_in_chain = 1; > > > > > > > > > > return ngx_http_output_filter(r, out_chain); > > > > > } > > > > > > > > > > typedef struct { > > > > > unsigned done:1; > > > > > } ngx_http_mod_ctx_t; > > > > > > > > > > int > > > > > http_module_process_request(ngx_http_request_t *r, ngx_uint_t > *status, > > > > > char *body, ngx_uint_t *blen) > > > > > { > > > > > if (/* request matches criteria */) { > > > > > /* other boiler plate code */ > > > > > *status = get_custom_status(); > > > > > *body = get_custom_body(); > > > > > *blen = ngx_strlen(body); > > > > > return *status; // this can be different from custom status. > > > > > } > > > > > > > > > > return NGX_DECLINED; > > > > > } > > > > > > > > > > static ngx_int_t > > > > > ngx_http_request_handler(ngx_http_request_t *r) > > > > > { > > > > > ngx_http_mod_ctx_t *ctx = ngx_http_get_module_ctx(r, > > > nginx_http_module); > > > > > > > > > > if (ctx) { > > > > > ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "duplicate > > > > > invokation"); > > > > > return NGX_DECLINED; > > > > > } else { > > > > > ctx = ngx_palloc(r->connection->pool, > sizeof(ngx_http_mod_ctx_t)); > > > > > if (ctx == NULL) { > > > > > ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, > > > > > "Out of memory. Cannot allocate context"); > > > > > return NGX_ERROR; > > > > > } > > > > > > > > > > ctx->done = 0; > > > > > ngx_http_set_ctx(r, ctx, nginx_http_module); > > > > > } > > > > > > > > > > ngx_int_t rc = 0; > > > > > char custom_body[512]; > > > > > ngx_uint_t blen; > > > > > ngx_uint_t custom_status; > > > > > if (!ctx->done) { > > > > > rc = http_module_process_request(r, &custom_status, > custom_body, > > > > > &blen); > > > > > } > > > > > > > > > > ctx->done = 1; > > > > > if ((rc != 0) && (rc != NGX_DECLINED)) { > > > > > return http_mod_send_response(r, custom_status, custom_body, > blen); > > > > > /* alternate implementation, send response in content handler. > > > > > ngx_buf_t *buf = ngx_create_temp_buf(r->pool, blen); > > > > > buf->last = ngx_copy(buf->start, (unsigned char*) data, > dlen); > > > > > ctx->custom_body = buf; > > > > > ctx->rcode = custom_status; > > > > > */ > > > > > } > > > > > > > > > > return NGX_DECLINED; > > > > > } > > > > > > > > > > static ngx_int_t > > > > > http_module_content_handler(ngx_http_request_t *r) > > > > > { > > > > > ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "%s: invoked", > > > > > __FUNCTION__); > > > > > ngx_http_ss_ctx_t *ctx = ngx_http_get_module_ctx(r, > > > > > nginx_mitigator_module); > > > > > > > > > > if (ctx && ctx->content) { > > > > > ctx->content = 0; > > > > > return http_mod_send_response(r, ctx->rcode, ctx->custom_body); > > > > > } else { > > > > > ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, > > > > > "%s: ctx = %p, content = %d", __FUNCTION__, ctx, > ctx > > > ? > > > > > ctx->content : -1); > > > > > } > > > > > > > > > > return NGX_DECLINED; > > > > > } > > > > > > > > > > static ngx_int_t > > > > > ngx_http_module_init (ngx_conf_t *cf) > > > > > { > > > > > ngx_http_core_main_conf_t *cmcf = > > > ngx_http_conf_get_module_main_conf(cf, > > > > > ngx_http_core_module); > > > > > > > > > > if (!cmcf) { > > > > > ngx_log_error(NGX_LOG_ERR, cf->log, 0, "Failed to retrieve > module > > > main > > > > > conf"); > > > > > return NGX_ERROR; > > > > > } > > > > > > > > > > ngx_http_handler_pt *hptr = > > > > > ngx_array_push(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers); > > > > > if (hptr == NULL) { > > > > > ngx_log_error(NGX_LOG_ERR, cf->log, 0, "Could not retrieve > access > > > > > phase handler"); > > > > > return NGX_ERROR; > > > > > } > > > > > > > > > > *hptr = ngx_http_request_handler; > > > > > ngx_log_error(NGX_LOG_INFO, cf->log, 0, "[init] Installed request > > > > > handler"); > > > > > > > > > > ngx_http_handler_pt *cptr = > > > > > ngx_array_push(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers); > > > > > if (cptr == NULL) { > > > > > ngx_log_error(NGX_LOG_ERR, cf->log, 0, "Could not retrieve > access > > > > > phase handler"); > > > > > return NGX_ERROR; > > > > > } > > > > > > > > > > *cptr = ngx_http_request_handler; > > > > > ngx_log_error(NGX_LOG_INFO, cf->log, 0, "[init] Installed request > > > > > handler"); > > > > > > > > > > return NGX_OK; > > > > > } > > > > > > > > > > > > > > > > > > > > > > _______________________________________________ > > > > nginx-devel mailing list > > > > nginx-devel at nginx.org > > > > http://mailman.nginx.org/mailman/listinfo/nginx-devel > > > > > > > > > -- > > > Roman Arutyunyan > > > _______________________________________________ > > > nginx-devel mailing list > > > nginx-devel at nginx.org > > > http://mailman.nginx.org/mailman/listinfo/nginx-devel > > > > > > _______________________________________________ > > nginx-devel mailing list > > nginx-devel at nginx.org > > http://mailman.nginx.org/mailman/listinfo/nginx-devel > > > -- > Roman Arutyunyan > _______________________________________________ > 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 arut at nginx.com Mon Jul 16 11:29:15 2018 From: arut at nginx.com (Roman Arutyunyan) Date: Mon, 16 Jul 2018 14:29:15 +0300 Subject: 2: header already sent In-Reply-To: References: <20180714213640.GM1406@Romans-MacBook-Air.local> <20180715052610.GN1406@Romans-MacBook-Air.local> Message-ID: <20180716112915.GO1406@Romans-MacBook-Air.local> Hi Dk Jack, On Sun, Jul 15, 2018 at 06:09:24PM -0700, Dk Jack wrote: > Hi Roman, > Sorry, it took a while for me to test the debug build. Since my module was > using timers, the debug logs in ngx_event_timer.{c,h} were causing a crash > (see end of email for details about the crash). Anyways, the debug log > attached at the end of the email. > > Looking at the debug logs, it looks like the ngx_http_finalize_request is > calling ngx_http_special_response_handler for any 'rc >= > NGX_HTTP_SPECIAL_RESPONSE (300)'. Since I was passing a 403 for the rc > value, it was calling the special_response_handler function which in turn > calls the send_header function. Since I had already called the send_header > function before calling the finalize_request, it generates the 'header > already sent' message. Yes, you should either produce output by yourself by calling ngx_http_send_header/ngx_http_output_filter, or finalize the request with a code >= 300. In the latter case nginx will output a standard response for this code. But you should never do both. > After going over the ngx_http_finalize_request code, I realized, if I > invoked the ngx_http_finalize_request function with 'rc = NGX_HTTP_CLOSE', > the finalize_request function will terminate the request and will not call > the ngx_http_special_response_handler which was causing the problem. I > tried it and it seems to work. Not sure if this the correct approach. Finalizing a request with NGX_HTTP_CLOSE is probably not a very good idea, unless you are absolutely sure you want to close the client connection for some reason. Normally you should finalize it with NGX_OK after you are done with sending response header and body. A standard approach here is finalizing the response with the result of ngx_http_output_filter(). Keep in mind that if you're doing all this in an access phase handler, the response code from your handler may or may not be passed to ngx_http_finalize_request(). See ngx_http_core_access_phase() function for details. > Please let me know. > > Thanks for your help. Greatly appreciate it. > ./D > > --------------------------------------------------------------------------------------------------------------- > event_timer crash when debug enabled: > #define ngx_event_ident(p) ((ngx_connection_t *) (p))->fd > > ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0, > "event timer del: %d: %M", > ngx_event_ident(ev->data), ev->timer.key); > > event_timer.{c,h} files have these sort of debug statements sprinkled all > over these two files. The ngx_event_ident macro seems to treat the data > pointer as a ngx_connection_t pointer and is attempting to dereference it > which causes the crash. In my case, the ev->data was NULL. Yes, event is supposed to always point to a connection object. However, if you have a different object referenced by ev->data, just make sure it has a properly sized value at offsetof(ngx_connection_t, fd). Having NULL in ev->data is not allowed. > ------------------------------------------------------------------------------------------------------------------- > > 2018/07/15 23:28:58 [error] 12381#12381: *2 ngx_http_request_handler: rc = > 403, uri:"/a/b/c", client: 10.3.28.146, server: live.testdomain.com, > request: "GET /a/b/c HTTP/1.1", host: "live.testdomain.com" > 2018/07/15 23:28:58 [error] 12381#12381: *2 ngx_http_request_handler: > finalize_req rc = 403, uri:"/a/b/c", client: 10.3.28.146, server: > live.testdomain.com, request: "GET /a/b/c HTTP/1.1", host: " > live.testdomain.com" > 2018/07/15 23:28:58 [debug] 12381#12381: *2 http finalize request: 403, > "/a/b/c?" a:1, c:1 > 2018/07/15 23:28:58 [debug] 12381#12381: *2 http special response: 403, > "/a/b/c?" > 2018/07/15 23:28:58 [debug] 12381#12381: *2 http set discard body > 2018/07/15 23:28:58 [alert] 12381#12381: *2 header already sent, client: > 10.3.28.146, server: live.testdomain.com, request: "GET /a/b/c HTTP/1.1", > host: "live.testdomain.com" > 2018/07/15 23:28:58 [debug] 12381#12381: *2 http finalize request: -1, > "/a/b/c?" a:1, c:1 > 2018/07/15 23:28:58 [debug] 12381#12381: *2 http terminate request count:1 > 2018/07/15 23:28:58 [debug] 12381#12381: *2 http terminate cleanup count:1 > blk:0 > 2018/07/15 23:28:58 [debug] 12381#12381: *2 http posted request: "/a/b/c?" > 2018/07/15 23:28:58 [debug] 12381#12381: *2 http terminate handler count:1 > 2018/07/15 23:28:58 [debug] 12381#12381: *2 http request count:1 blk:0 > 2018/07/15 23:28:58 [debug] 12381#12381: *2 http close request > 2018/07/15 23:28:58 [debug] 12381#12381: *2 http log handler > > > On Sat, Jul 14, 2018 at 10:26 PM Roman Arutyunyan wrote: > > > Hi, > > > > On Sat, Jul 14, 2018 at 05:21:02PM -0700, Dk Jack wrote: > > > Hi Roman, > > > Thanks for taking the time to respond to my question. > > > > > > I've tried your suggestion. I've done a finalize_req and tried > > > NGX_DONE/OK/... All give me the same result. I get the same result with > > or > > > without the finalize_req i.e. I still see the 'header already sent' > > > message. I've experimented with the different 'rc' values for the > > > finalize_req i.e. 'rc = NGX_DONE/OK/ERROR' as well. I still see the same > > > result. Please let me know if you have any other suggestions you'd like > > me > > > to try. Thanks. > > > > Can you show your debug log? > > > > https://nginx.org/en/docs/debugging_log.html > > > > > On Sat, Jul 14, 2018 at 2:37 PM Roman Arutyunyan wrote: > > > > > > > Hi Dk Jack, > > > > > > > > On Fri, Jul 13, 2018 at 01:18:40PM -0700, Dk Jack wrote: > > > > > Sorry, I made a typo in my earlier email. Please read the following > > > > > sentence: > > > > > > > > > > "When I send the response in the *content* phase handler, I am am > > seeing > > > > > 'header already sent' messages in the error log." > > > > > > > > > > as > > > > > > > > > > "When I send the response in the *access* phase handler, I am am > > seeing > > > > > 'header already sent' messages in the error log." > > > > > > > > That's because you do not finalize the request after you send a > > response in > > > > the access handler. A content handler (standard static or another > > one) is > > > > still called at the content phase. It tries to send a second response > > and > > > > obviously gets this error. > > > > > > > > Finalize the request in the access phase after you send the response > > with > > > > this call: > > > > > > > > ngx_http_finalize_request(r, rc) > > > > > > > > where rc is what ngx_http_output_filter() returned. Then return > > NGX_DONE > > > > from the access handler to prevent further request processing. > > > > > > > > If you want to return a standard error page, simply return its HTTP > > status > > > > code > > > > from your access handler instead. > > > > > > > > > On Thu, Jul 12, 2018 at 1:29 PM Dk Jack wrote: > > > > > > > > > > > Hi, > > > > > > Sorry for sending this again. I haven't been able to resolve my > > issue. > > > > > > I've read several modules for example and gone over several docs > > etc. > > > > but > > > > > > with no success so far. > > > > > > > > > > > > In my module, I need to either drop the request or allow the > > request. > > > > When > > > > > > I drop the request, I need to send custom response and status. The > > > > custom > > > > > > response and status don't come from the config file. When I send > > the > > > > > > response in the content phase handler, I am am seeing 'header > > already > > > > sent' > > > > > > messages in the error log. How can prevent further processing of > > the > > > > > > request after my handler is called for the terminal case? > > > > > > > > > > > > Since my module needs to examine all requests irrespective of the > > uri, > > > > I > > > > > > tried registering a content phase handler and send the custom > > response > > > > in > > > > > > that handler. However, my content phase handler is never invoked. I > > > > suspect > > > > > > some other content handler is overriding my content handler. Is > > there > > > > a > > > > > > way I can prevent that i.e. for a request, can I force only my > > content > > > > > > handler to be called. > > > > > > > > > > > > Please let me know what I am doing wrong? I just need to > > send/perform > > > > > > custom response/actions when a request matches my criteria. I've > > > > include a > > > > > > skeleton of my code. > > > > > > Any inputs are greatly appreciated. Thanks. > > > > > > > > > > > > regards, > > > > > > Dk. > > > > > > > > > > > > http_mod_send_response(ngx_http_request_t *r, ngx_uint_t > > custom_status, > > > > > > char *body, ngx_int_t blen) > > > > > > { > > > > > > ngx_int_t rc; > > > > > > ngx_log_t *log = r->connection->log; > > > > > > ngx_buf_t *buf = ngx_create_temp_buf(r->pool, (blen+16)); // pad. > > > > > > > > > > > > if (NULL == buf) { > > > > > > ngx_log_error(NGX_LOG_ERR, log, 0, "%s: Failed to allocate > > buffer", > > > > > > __FUNCTION__); > > > > > > return NGX_ERROR; > > > > > > } > > > > > > > > > > > > buf->last = ngx_copy(buf->start, (unsigned char*) data, dlen); > > > > > > rc = ngx_http_discard_request_body(r); > > > > > > if (rc != NGX_OK) { > > > > > > ngx_log_error(NGX_LOG_ERR, log, 0, "%s: Discard req. body > > failed. > > > > > > rc=%i", __FUNCTION__, rc); > > > > > > return rc; > > > > > > } > > > > > > > > > > > > r->headers_out.status = custom_status; > > > > > > r->headers_out.content_length_n = buf->last - buf->pos; > > > > > > r->headers_out.content_type.len = sizeof("text/plain") - 1; > > > > > > r->headers_out.content_type.data = (u_char *) "text/plain"; > > > > > > > > > > > > rc = ngx_http_send_header(r); > > > > > > if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { > > > > > > ngx_log_error(NGX_LOG_ERR, log, 0, "%s: Send header failed. > > rc=%i", > > > > > > __FUNCTION__, rc); > > > > > > return rc; > > > > > > } > > > > > > > > > > > > ngx_chain_t *out_chain = ngx_alloc_chain_link(r->pool); > > > > > > if (NULL == out_chain) { > > > > > > ngx_log_error(NGX_LOG_ERR, log, 0, "%s: Buffer chain alloc > > failed", > > > > > > __FUNCTION__); > > > > > > return NGX_ERROR; > > > > > > } > > > > > > > > > > > > out_chain->buf = buf; > > > > > > out_chain->next = NULL; > > > > > > buf->last_buf = 1; > > > > > > buf->last_in_chain = 1; > > > > > > > > > > > > return ngx_http_output_filter(r, out_chain); > > > > > > } > > > > > > > > > > > > typedef struct { > > > > > > unsigned done:1; > > > > > > } ngx_http_mod_ctx_t; > > > > > > > > > > > > int > > > > > > http_module_process_request(ngx_http_request_t *r, ngx_uint_t > > *status, > > > > > > char *body, ngx_uint_t *blen) > > > > > > { > > > > > > if (/* request matches criteria */) { > > > > > > /* other boiler plate code */ > > > > > > *status = get_custom_status(); > > > > > > *body = get_custom_body(); > > > > > > *blen = ngx_strlen(body); > > > > > > return *status; // this can be different from custom status. > > > > > > } > > > > > > > > > > > > return NGX_DECLINED; > > > > > > } > > > > > > > > > > > > static ngx_int_t > > > > > > ngx_http_request_handler(ngx_http_request_t *r) > > > > > > { > > > > > > ngx_http_mod_ctx_t *ctx = ngx_http_get_module_ctx(r, > > > > nginx_http_module); > > > > > > > > > > > > if (ctx) { > > > > > > ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "duplicate > > > > > > invokation"); > > > > > > return NGX_DECLINED; > > > > > > } else { > > > > > > ctx = ngx_palloc(r->connection->pool, > > sizeof(ngx_http_mod_ctx_t)); > > > > > > if (ctx == NULL) { > > > > > > ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, > > > > > > "Out of memory. Cannot allocate context"); > > > > > > return NGX_ERROR; > > > > > > } > > > > > > > > > > > > ctx->done = 0; > > > > > > ngx_http_set_ctx(r, ctx, nginx_http_module); > > > > > > } > > > > > > > > > > > > ngx_int_t rc = 0; > > > > > > char custom_body[512]; > > > > > > ngx_uint_t blen; > > > > > > ngx_uint_t custom_status; > > > > > > if (!ctx->done) { > > > > > > rc = http_module_process_request(r, &custom_status, > > custom_body, > > > > > > &blen); > > > > > > } > > > > > > > > > > > > ctx->done = 1; > > > > > > if ((rc != 0) && (rc != NGX_DECLINED)) { > > > > > > return http_mod_send_response(r, custom_status, custom_body, > > blen); > > > > > > /* alternate implementation, send response in content handler. > > > > > > ngx_buf_t *buf = ngx_create_temp_buf(r->pool, blen); > > > > > > buf->last = ngx_copy(buf->start, (unsigned char*) data, > > dlen); > > > > > > ctx->custom_body = buf; > > > > > > ctx->rcode = custom_status; > > > > > > */ > > > > > > } > > > > > > > > > > > > return NGX_DECLINED; > > > > > > } > > > > > > > > > > > > static ngx_int_t > > > > > > http_module_content_handler(ngx_http_request_t *r) > > > > > > { > > > > > > ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "%s: invoked", > > > > > > __FUNCTION__); > > > > > > ngx_http_ss_ctx_t *ctx = ngx_http_get_module_ctx(r, > > > > > > nginx_mitigator_module); > > > > > > > > > > > > if (ctx && ctx->content) { > > > > > > ctx->content = 0; > > > > > > return http_mod_send_response(r, ctx->rcode, ctx->custom_body); > > > > > > } else { > > > > > > ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, > > > > > > "%s: ctx = %p, content = %d", __FUNCTION__, ctx, > > ctx > > > > ? > > > > > > ctx->content : -1); > > > > > > } > > > > > > > > > > > > return NGX_DECLINED; > > > > > > } > > > > > > > > > > > > static ngx_int_t > > > > > > ngx_http_module_init (ngx_conf_t *cf) > > > > > > { > > > > > > ngx_http_core_main_conf_t *cmcf = > > > > ngx_http_conf_get_module_main_conf(cf, > > > > > > ngx_http_core_module); > > > > > > > > > > > > if (!cmcf) { > > > > > > ngx_log_error(NGX_LOG_ERR, cf->log, 0, "Failed to retrieve > > module > > > > main > > > > > > conf"); > > > > > > return NGX_ERROR; > > > > > > } > > > > > > > > > > > > ngx_http_handler_pt *hptr = > > > > > > ngx_array_push(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers); > > > > > > if (hptr == NULL) { > > > > > > ngx_log_error(NGX_LOG_ERR, cf->log, 0, "Could not retrieve > > access > > > > > > phase handler"); > > > > > > return NGX_ERROR; > > > > > > } > > > > > > > > > > > > *hptr = ngx_http_request_handler; > > > > > > ngx_log_error(NGX_LOG_INFO, cf->log, 0, "[init] Installed request > > > > > > handler"); > > > > > > > > > > > > ngx_http_handler_pt *cptr = > > > > > > ngx_array_push(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers); > > > > > > if (cptr == NULL) { > > > > > > ngx_log_error(NGX_LOG_ERR, cf->log, 0, "Could not retrieve > > access > > > > > > phase handler"); > > > > > > return NGX_ERROR; > > > > > > } > > > > > > > > > > > > *cptr = ngx_http_request_handler; > > > > > > ngx_log_error(NGX_LOG_INFO, cf->log, 0, "[init] Installed request > > > > > > handler"); > > > > > > > > > > > > return NGX_OK; > > > > > > } > > > > > > > > > > > > > > > > > > > > > > > > > > > _______________________________________________ > > > > > nginx-devel mailing list > > > > > nginx-devel at nginx.org > > > > > http://mailman.nginx.org/mailman/listinfo/nginx-devel > > > > > > > > > > > > -- > > > > Roman Arutyunyan > > > > _______________________________________________ > > > > nginx-devel mailing list > > > > nginx-devel at nginx.org > > > > http://mailman.nginx.org/mailman/listinfo/nginx-devel > > > > > > > > > _______________________________________________ > > > nginx-devel mailing list > > > nginx-devel at nginx.org > > > http://mailman.nginx.org/mailman/listinfo/nginx-devel > > > > > > -- > > Roman Arutyunyan > > _______________________________________________ > > nginx-devel mailing list > > nginx-devel at nginx.org > > http://mailman.nginx.org/mailman/listinfo/nginx-devel > > > _______________________________________________ > nginx-devel mailing list > nginx-devel at nginx.org > http://mailman.nginx.org/mailman/listinfo/nginx-devel -- Roman Arutyunyan From pluknet at nginx.com Mon Jul 16 15:24:40 2018 From: pluknet at nginx.com (Sergey Kandaurov) Date: Mon, 16 Jul 2018 15:24:40 +0000 Subject: [njs] Style. Message-ID: details: http://hg.nginx.org/njs/rev/44cf55b40b6b branches: changeset: 556:44cf55b40b6b user: Sergey Kandaurov date: Mon Jul 16 14:20:16 2018 +0300 description: Style. diffstat: nxt/auto/getrandom | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diffs (11 lines): diff -r 00762256c67a -r 44cf55b40b6b nxt/auto/getrandom --- a/nxt/auto/getrandom Fri Jul 13 15:12:11 2018 +0300 +++ b/nxt/auto/getrandom Mon Jul 16 14:20:16 2018 +0300 @@ -24,6 +24,7 @@ nxt_feature_test="#include }" . ${NXT_AUTO}feature + if [ $nxt_found = no ]; then # Linux 3.17 SYS_getrandom. From pluknet at nginx.com Mon Jul 16 15:24:40 2018 From: pluknet at nginx.com (Sergey Kandaurov) Date: Mon, 16 Jul 2018 15:24:40 +0000 Subject: [njs] Supplied getrandom() test with commentary about supported OSes. Message-ID: details: http://hg.nginx.org/njs/rev/e9d93bfd7714 branches: changeset: 557:e9d93bfd7714 user: Sergey Kandaurov date: Mon Jul 16 14:21:09 2018 +0300 description: Supplied getrandom() test with commentary about supported OSes. diffstat: nxt/auto/getrandom | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diffs (12 lines): diff -r 44cf55b40b6b -r e9d93bfd7714 nxt/auto/getrandom --- a/nxt/auto/getrandom Mon Jul 16 14:20:16 2018 +0300 +++ b/nxt/auto/getrandom Mon Jul 16 14:21:09 2018 +0300 @@ -3,7 +3,7 @@ # Copyright (C) NGINX, Inc. -# getrandom(). +# Linux 3.17 with glibc 2.25, FreeBSD 12, Solaris 11.3. nxt_feature="getrandom()" nxt_feature_name=NXT_HAVE_GETRANDOM From pluknet at nginx.com Mon Jul 16 15:24:41 2018 From: pluknet at nginx.com (Sergey Kandaurov) Date: Mon, 16 Jul 2018 15:24:41 +0000 Subject: [njs] Added getentropy() support. Message-ID: details: http://hg.nginx.org/njs/rev/04dc301f7d5a branches: changeset: 558:04dc301f7d5a user: Sergey Kandaurov date: Mon Jul 16 14:30:41 2018 +0300 description: Added getentropy() support. diffstat: nxt/auto/getrandom | 43 +++++++++++++++++++++++++++++++++++++++++++ nxt/nxt_random.c | 10 ++++++++++ 2 files changed, 53 insertions(+), 0 deletions(-) diffs (77 lines): diff -r e9d93bfd7714 -r 04dc301f7d5a nxt/auto/getrandom --- a/nxt/auto/getrandom Mon Jul 16 14:21:09 2018 +0300 +++ b/nxt/auto/getrandom Mon Jul 16 14:30:41 2018 +0300 @@ -46,3 +46,46 @@ if [ $nxt_found = no ]; then }" . ${NXT_AUTO}feature fi + + +if [ $nxt_found = no ]; then + + # OpenBSD 5.6 lacks . + + nxt_feature="getentropy()" + nxt_feature_name=NXT_HAVE_GETENTROPY + nxt_feature_test="#include + + int main(void) { + char buf[4]; + + if (getentropy(buf, 4) == -1) { + return 1; + } + + return 0; + }" + . ${NXT_AUTO}feature +fi + + +if [ $nxt_found = no ]; then + + # macOS 10.12. + + nxt_feature="getentropy() in sys/random.h" + nxt_feature_name=NXT_HAVE_GETENTROPY_SYS_RANDOM + nxt_feature_test="#include + #include + + int main(void) { + char buf[4]; + + if (getentropy(buf, 4) == -1) { + return 1; + } + + return 0; + }" + . ${NXT_AUTO}feature +fi diff -r e9d93bfd7714 -r 04dc301f7d5a nxt/nxt_random.c --- a/nxt/nxt_random.c Mon Jul 16 14:21:09 2018 +0300 +++ b/nxt/nxt_random.c Mon Jul 16 14:30:41 2018 +0300 @@ -17,6 +17,8 @@ #elif (NXT_HAVE_LINUX_SYS_GETRANDOM) #include #include +#elif (NXT_HAVE_GETENTROPY_SYS_RANDOM) +#include #endif @@ -76,6 +78,14 @@ nxt_random_stir(nxt_random_t *r, nxt_pid n = syscall(SYS_getrandom, &key, NXT_RANDOM_KEY_SIZE, 0); +#elif (NXT_HAVE_GETENTROPY || NXT_HAVE_GETENTROPY_SYS_RANDOM) + + n = 0; + + if (getentropy(&key, NXT_RANDOM_KEY_SIZE) == 0) { + n = NXT_RANDOM_KEY_SIZE; + } + #else n = 0; From mdounin at mdounin.ru Mon Jul 16 17:02:04 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Mon, 16 Jul 2018 17:02:04 +0000 Subject: [nginx] SSL: logging levels of "unsupported protocol", "version too low". Message-ID: details: http://hg.nginx.org/nginx/rev/6565f0dbe8c5 branches: changeset: 7317:6565f0dbe8c5 user: Maxim Dounin date: Mon Jul 16 17:47:18 2018 +0300 description: SSL: logging levels of "unsupported protocol", "version too low". Starting with OpenSSL 1.1.0, SSL_R_UNSUPPORTED_PROTOCOL instead of SSL_R_UNKNOWN_PROTOCOL is reported when a protocol is disabled via an SSL_OP_NO_* option. Additionally, SSL_R_VERSION_TOO_LOW is reported when using MinProtocol or when seclevel checks (as set by @SECLEVEL=n in the cipher string) rejects a protocol, and this is what happens with SSLv3 and @SECLEVEL=1, which is the default. There is also the SSL_R_VERSION_TOO_HIGH error code, but it looks like it is not possible to trigger it. diffstat: src/event/ngx_event_openssl.c | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-) diffs (21 lines): diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -2079,6 +2079,7 @@ ngx_ssl_connection_error(ngx_connection_ || n == SSL_R_UNEXPECTED_RECORD /* 245 */ || n == SSL_R_UNKNOWN_ALERT_TYPE /* 246 */ || n == SSL_R_UNKNOWN_PROTOCOL /* 252 */ + || n == SSL_R_UNSUPPORTED_PROTOCOL /* 258 */ || n == SSL_R_WRONG_VERSION_NUMBER /* 267 */ || n == SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC /* 281 */ #ifdef SSL_R_RENEGOTIATE_EXT_TOO_LONG @@ -2095,6 +2096,9 @@ ngx_ssl_connection_error(ngx_connection_ #ifdef SSL_R_INAPPROPRIATE_FALLBACK || n == SSL_R_INAPPROPRIATE_FALLBACK /* 373 */ #endif +#ifdef SSL_R_VERSION_TOO_LOW + || n == SSL_R_VERSION_TOO_LOW /* 396 */ +#endif || n == 1000 /* SSL_R_SSLV3_ALERT_CLOSE_NOTIFY */ #ifdef SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE || n == SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE /* 1010 */ From mdounin at mdounin.ru Mon Jul 16 17:02:05 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Mon, 16 Jul 2018 17:02:05 +0000 Subject: [nginx] SSL: fixed SSL_clear_options() usage with OpenSSL 1.1.0+. Message-ID: details: http://hg.nginx.org/nginx/rev/3443fe40bdc7 branches: changeset: 7318:3443fe40bdc7 user: Maxim Dounin date: Mon Jul 16 17:47:20 2018 +0300 description: SSL: fixed SSL_clear_options() usage with OpenSSL 1.1.0+. In OpenSSL 1.1.0 the SSL_CTRL_CLEAR_OPTIONS macro was removed, so conditional compilation test on it results in SSL_clear_options() and SSL_CTX_clear_options() not being used. Notably, this caused "ssl_prefer_server_ciphers off" to not work in SNI-based virtual servers if server preference was switched on in the default server. It looks like the only possible fix is to test OPENSSL_VERSION_NUMBER explicitly. diffstat: src/event/ngx_event_openssl.c | 2 +- src/http/ngx_http_request.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diffs (24 lines): diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -295,7 +295,7 @@ ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_ SSL_CTX_set_options(ssl->ctx, SSL_OP_SINGLE_DH_USE); -#ifdef SSL_CTRL_CLEAR_OPTIONS +#if OPENSSL_VERSION_NUMBER >= 0x009080dfL /* only in 0.9.8m+ */ SSL_CTX_clear_options(ssl->ctx, SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_NO_TLSv1); diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -912,7 +912,7 @@ ngx_http_ssl_servername(ngx_ssl_conn_t * SSL_set_verify_depth(ssl_conn, SSL_CTX_get_verify_depth(sscf->ssl.ctx)); -#ifdef SSL_CTRL_CLEAR_OPTIONS +#if OPENSSL_VERSION_NUMBER >= 0x009080dfL /* only in 0.9.8m+ */ SSL_clear_options(ssl_conn, SSL_get_options(ssl_conn) & ~SSL_CTX_get_options(sscf->ssl.ctx)); From mdounin at mdounin.ru Mon Jul 16 17:02:07 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Mon, 16 Jul 2018 17:02:07 +0000 Subject: [nginx] SSL: use of the SSL_OP_NO_RENEGOTIATION option (ticket #1376). Message-ID: details: http://hg.nginx.org/nginx/rev/dcab86115261 branches: changeset: 7319:dcab86115261 user: Maxim Dounin date: Mon Jul 16 17:47:48 2018 +0300 description: SSL: use of the SSL_OP_NO_RENEGOTIATION option (ticket #1376). The SSL_OP_NO_RENEGOTIATION option is available in OpenSSL 1.1.0h+ and can save some CPU cycles on renegotiation attempts. diffstat: src/event/ngx_event_openssl.c | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-) diffs (14 lines): diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -1193,6 +1193,10 @@ ngx_ssl_create_connection(ngx_ssl_t *ssl } else { SSL_set_accept_state(sc->connection); + +#ifdef SSL_OP_NO_RENEGOTIATION + SSL_set_options(sc->connection, SSL_OP_NO_RENEGOTIATION); +#endif } if (SSL_set_ex_data(sc->connection, ngx_ssl_connection_index, c) == 0) { From dnj0496 at gmail.com Tue Jul 17 00:11:12 2018 From: dnj0496 at gmail.com (Dk Jack) Date: Mon, 16 Jul 2018 17:11:12 -0700 Subject: 2: header already sent In-Reply-To: <20180716112915.GO1406@Romans-MacBook-Air.local> References: <20180714213640.GM1406@Romans-MacBook-Air.local> <20180715052610.GN1406@Romans-MacBook-Air.local> <20180716112915.GO1406@Romans-MacBook-Air.local> Message-ID: Thanks Roman, Passing NGX_OK to finalize_request also worked. I'll use that. Thanks for all you help. Dk PS: Requiring ev->data to be of type ngx_conn_t is a strange one. I thought it was for user data. On Mon, Jul 16, 2018 at 4:29 AM Roman Arutyunyan wrote: > Hi Dk Jack, > > On Sun, Jul 15, 2018 at 06:09:24PM -0700, Dk Jack wrote: > > Hi Roman, > > Sorry, it took a while for me to test the debug build. Since my module > was > > using timers, the debug logs in ngx_event_timer.{c,h} were causing a > crash > > (see end of email for details about the crash). Anyways, the debug log > > attached at the end of the email. > > > > Looking at the debug logs, it looks like the ngx_http_finalize_request is > > calling ngx_http_special_response_handler for any 'rc >= > > NGX_HTTP_SPECIAL_RESPONSE (300)'. Since I was passing a 403 for the rc > > value, it was calling the special_response_handler function which in turn > > calls the send_header function. Since I had already called the > send_header > > function before calling the finalize_request, it generates the 'header > > already sent' message. > > Yes, you should either produce output by yourself by calling > ngx_http_send_header/ngx_http_output_filter, or finalize the request with > a code >= 300. In the latter case nginx will output a standard response > for > this code. But you should never do both. > > > After going over the ngx_http_finalize_request code, I realized, if I > > invoked the ngx_http_finalize_request function with 'rc = > NGX_HTTP_CLOSE', > > the finalize_request function will terminate the request and will not > call > > the ngx_http_special_response_handler which was causing the problem. I > > tried it and it seems to work. Not sure if this the correct approach. > > Finalizing a request with NGX_HTTP_CLOSE is probably not a very good idea, > unless you are absolutely sure you want to close the client connection for > some > reason. Normally you should finalize it with NGX_OK after you are done > with > sending response header and body. A standard approach here is finalizing > the > response with the result of ngx_http_output_filter(). > > Keep in mind that if you're doing all this in an access phase handler, the > response code from your handler may or may not be passed to > ngx_http_finalize_request(). See ngx_http_core_access_phase() function for > details. > > > Please let me know. > > > > Thanks for your help. Greatly appreciate it. > > ./D > > > > > --------------------------------------------------------------------------------------------------------------- > > event_timer crash when debug enabled: > > #define ngx_event_ident(p) ((ngx_connection_t *) (p))->fd > > > > ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0, > > "event timer del: %d: %M", > > ngx_event_ident(ev->data), ev->timer.key); > > > > event_timer.{c,h} files have these sort of debug statements sprinkled all > > over these two files. The ngx_event_ident macro seems to treat the data > > pointer as a ngx_connection_t pointer and is attempting to dereference it > > which causes the crash. In my case, the ev->data was NULL. > > Yes, event is supposed to always point to a connection object. However, > if you have a different object referenced by ev->data, just make sure it > has > a properly sized value at offsetof(ngx_connection_t, fd). Having NULL in > ev->data is not allowed. > > > > ------------------------------------------------------------------------------------------------------------------- > > > > 2018/07/15 23:28:58 [error] 12381#12381: *2 ngx_http_request_handler: rc > = > > 403, uri:"/a/b/c", client: 10.3.28.146, server: live.testdomain.com, > > request: "GET /a/b/c HTTP/1.1", host: "live.testdomain.com" > > 2018/07/15 23:28:58 [error] 12381#12381: *2 ngx_http_request_handler: > > finalize_req rc = 403, uri:"/a/b/c", client: 10.3.28.146, server: > > live.testdomain.com, request: "GET /a/b/c HTTP/1.1", host: " > > live.testdomain.com" > > 2018/07/15 23:28:58 [debug] 12381#12381: *2 http finalize request: 403, > > "/a/b/c?" a:1, c:1 > > 2018/07/15 23:28:58 [debug] 12381#12381: *2 http special response: 403, > > "/a/b/c?" > > 2018/07/15 23:28:58 [debug] 12381#12381: *2 http set discard body > > 2018/07/15 23:28:58 [alert] 12381#12381: *2 header already sent, client: > > 10.3.28.146, server: live.testdomain.com, request: "GET /a/b/c > HTTP/1.1", > > host: "live.testdomain.com" > > 2018/07/15 23:28:58 [debug] 12381#12381: *2 http finalize request: -1, > > "/a/b/c?" a:1, c:1 > > 2018/07/15 23:28:58 [debug] 12381#12381: *2 http terminate request > count:1 > > 2018/07/15 23:28:58 [debug] 12381#12381: *2 http terminate cleanup > count:1 > > blk:0 > > 2018/07/15 23:28:58 [debug] 12381#12381: *2 http posted request: > "/a/b/c?" > > 2018/07/15 23:28:58 [debug] 12381#12381: *2 http terminate handler > count:1 > > 2018/07/15 23:28:58 [debug] 12381#12381: *2 http request count:1 blk:0 > > 2018/07/15 23:28:58 [debug] 12381#12381: *2 http close request > > 2018/07/15 23:28:58 [debug] 12381#12381: *2 http log handler > > > > > > On Sat, Jul 14, 2018 at 10:26 PM Roman Arutyunyan > wrote: > > > > > Hi, > > > > > > On Sat, Jul 14, 2018 at 05:21:02PM -0700, Dk Jack wrote: > > > > Hi Roman, > > > > Thanks for taking the time to respond to my question. > > > > > > > > I've tried your suggestion. I've done a finalize_req and tried > > > > NGX_DONE/OK/... All give me the same result. I get the same result > with > > > or > > > > without the finalize_req i.e. I still see the 'header already sent' > > > > message. I've experimented with the different 'rc' values for the > > > > finalize_req i.e. 'rc = NGX_DONE/OK/ERROR' as well. I still see the > same > > > > result. Please let me know if you have any other suggestions you'd > like > > > me > > > > to try. Thanks. > > > > > > Can you show your debug log? > > > > > > https://nginx.org/en/docs/debugging_log.html > > > > > > > On Sat, Jul 14, 2018 at 2:37 PM Roman Arutyunyan > wrote: > > > > > > > > > Hi Dk Jack, > > > > > > > > > > On Fri, Jul 13, 2018 at 01:18:40PM -0700, Dk Jack wrote: > > > > > > Sorry, I made a typo in my earlier email. Please read the > following > > > > > > sentence: > > > > > > > > > > > > "When I send the response in the *content* phase handler, I am am > > > seeing > > > > > > 'header already sent' messages in the error log." > > > > > > > > > > > > as > > > > > > > > > > > > "When I send the response in the *access* phase handler, I am am > > > seeing > > > > > > 'header already sent' messages in the error log." > > > > > > > > > > That's because you do not finalize the request after you send a > > > response in > > > > > the access handler. A content handler (standard static or another > > > one) is > > > > > still called at the content phase. It tries to send a second > response > > > and > > > > > obviously gets this error. > > > > > > > > > > Finalize the request in the access phase after you send the > response > > > with > > > > > this call: > > > > > > > > > > ngx_http_finalize_request(r, rc) > > > > > > > > > > where rc is what ngx_http_output_filter() returned. Then return > > > NGX_DONE > > > > > from the access handler to prevent further request processing. > > > > > > > > > > If you want to return a standard error page, simply return its HTTP > > > status > > > > > code > > > > > from your access handler instead. > > > > > > > > > > > On Thu, Jul 12, 2018 at 1:29 PM Dk Jack > wrote: > > > > > > > > > > > > > Hi, > > > > > > > Sorry for sending this again. I haven't been able to resolve my > > > issue. > > > > > > > I've read several modules for example and gone over several > docs > > > etc. > > > > > but > > > > > > > with no success so far. > > > > > > > > > > > > > > In my module, I need to either drop the request or allow the > > > request. > > > > > When > > > > > > > I drop the request, I need to send custom response and status. > The > > > > > custom > > > > > > > response and status don't come from the config file. When I > send > > > the > > > > > > > response in the content phase handler, I am am seeing 'header > > > already > > > > > sent' > > > > > > > messages in the error log. How can prevent further processing > of > > > the > > > > > > > request after my handler is called for the terminal case? > > > > > > > > > > > > > > Since my module needs to examine all requests irrespective of > the > > > uri, > > > > > I > > > > > > > tried registering a content phase handler and send the custom > > > response > > > > > in > > > > > > > that handler. However, my content phase handler is never > invoked. I > > > > > suspect > > > > > > > some other content handler is overriding my content handler. > Is > > > there > > > > > a > > > > > > > way I can prevent that i.e. for a request, can I force only my > > > content > > > > > > > handler to be called. > > > > > > > > > > > > > > Please let me know what I am doing wrong? I just need to > > > send/perform > > > > > > > custom response/actions when a request matches my criteria. > I've > > > > > include a > > > > > > > skeleton of my code. > > > > > > > Any inputs are greatly appreciated. Thanks. > > > > > > > > > > > > > > regards, > > > > > > > Dk. > > > > > > > > > > > > > > http_mod_send_response(ngx_http_request_t *r, ngx_uint_t > > > custom_status, > > > > > > > char *body, ngx_int_t blen) > > > > > > > { > > > > > > > ngx_int_t rc; > > > > > > > ngx_log_t *log = r->connection->log; > > > > > > > ngx_buf_t *buf = ngx_create_temp_buf(r->pool, (blen+16)); // > pad. > > > > > > > > > > > > > > if (NULL == buf) { > > > > > > > ngx_log_error(NGX_LOG_ERR, log, 0, "%s: Failed to allocate > > > buffer", > > > > > > > __FUNCTION__); > > > > > > > return NGX_ERROR; > > > > > > > } > > > > > > > > > > > > > > buf->last = ngx_copy(buf->start, (unsigned char*) data, > dlen); > > > > > > > rc = ngx_http_discard_request_body(r); > > > > > > > if (rc != NGX_OK) { > > > > > > > ngx_log_error(NGX_LOG_ERR, log, 0, "%s: Discard req. body > > > failed. > > > > > > > rc=%i", __FUNCTION__, rc); > > > > > > > return rc; > > > > > > > } > > > > > > > > > > > > > > r->headers_out.status = custom_status; > > > > > > > r->headers_out.content_length_n = buf->last - buf->pos; > > > > > > > r->headers_out.content_type.len = sizeof("text/plain") - 1; > > > > > > > r->headers_out.content_type.data = (u_char *) "text/plain"; > > > > > > > > > > > > > > rc = ngx_http_send_header(r); > > > > > > > if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { > > > > > > > ngx_log_error(NGX_LOG_ERR, log, 0, "%s: Send header failed. > > > rc=%i", > > > > > > > __FUNCTION__, rc); > > > > > > > return rc; > > > > > > > } > > > > > > > > > > > > > > ngx_chain_t *out_chain = ngx_alloc_chain_link(r->pool); > > > > > > > if (NULL == out_chain) { > > > > > > > ngx_log_error(NGX_LOG_ERR, log, 0, "%s: Buffer chain alloc > > > failed", > > > > > > > __FUNCTION__); > > > > > > > return NGX_ERROR; > > > > > > > } > > > > > > > > > > > > > > out_chain->buf = buf; > > > > > > > out_chain->next = NULL; > > > > > > > buf->last_buf = 1; > > > > > > > buf->last_in_chain = 1; > > > > > > > > > > > > > > return ngx_http_output_filter(r, out_chain); > > > > > > > } > > > > > > > > > > > > > > typedef struct { > > > > > > > unsigned done:1; > > > > > > > } ngx_http_mod_ctx_t; > > > > > > > > > > > > > > int > > > > > > > http_module_process_request(ngx_http_request_t *r, ngx_uint_t > > > *status, > > > > > > > char *body, ngx_uint_t *blen) > > > > > > > { > > > > > > > if (/* request matches criteria */) { > > > > > > > /* other boiler plate code */ > > > > > > > *status = get_custom_status(); > > > > > > > *body = get_custom_body(); > > > > > > > *blen = ngx_strlen(body); > > > > > > > return *status; // this can be different from custom > status. > > > > > > > } > > > > > > > > > > > > > > return NGX_DECLINED; > > > > > > > } > > > > > > > > > > > > > > static ngx_int_t > > > > > > > ngx_http_request_handler(ngx_http_request_t *r) > > > > > > > { > > > > > > > ngx_http_mod_ctx_t *ctx = ngx_http_get_module_ctx(r, > > > > > nginx_http_module); > > > > > > > > > > > > > > if (ctx) { > > > > > > > ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, > "duplicate > > > > > > > invokation"); > > > > > > > return NGX_DECLINED; > > > > > > > } else { > > > > > > > ctx = ngx_palloc(r->connection->pool, > > > sizeof(ngx_http_mod_ctx_t)); > > > > > > > if (ctx == NULL) { > > > > > > > ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, > > > > > > > "Out of memory. Cannot allocate context"); > > > > > > > return NGX_ERROR; > > > > > > > } > > > > > > > > > > > > > > ctx->done = 0; > > > > > > > ngx_http_set_ctx(r, ctx, nginx_http_module); > > > > > > > } > > > > > > > > > > > > > > ngx_int_t rc = 0; > > > > > > > char custom_body[512]; > > > > > > > ngx_uint_t blen; > > > > > > > ngx_uint_t custom_status; > > > > > > > if (!ctx->done) { > > > > > > > rc = http_module_process_request(r, &custom_status, > > > custom_body, > > > > > > > &blen); > > > > > > > } > > > > > > > > > > > > > > ctx->done = 1; > > > > > > > if ((rc != 0) && (rc != NGX_DECLINED)) { > > > > > > > return http_mod_send_response(r, custom_status, > custom_body, > > > blen); > > > > > > > /* alternate implementation, send response in content > handler. > > > > > > > ngx_buf_t *buf = ngx_create_temp_buf(r->pool, blen); > > > > > > > buf->last = ngx_copy(buf->start, (unsigned char*) data, > > > dlen); > > > > > > > ctx->custom_body = buf; > > > > > > > ctx->rcode = custom_status; > > > > > > > */ > > > > > > > } > > > > > > > > > > > > > > return NGX_DECLINED; > > > > > > > } > > > > > > > > > > > > > > static ngx_int_t > > > > > > > http_module_content_handler(ngx_http_request_t *r) > > > > > > > { > > > > > > > ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "%s: > invoked", > > > > > > > __FUNCTION__); > > > > > > > ngx_http_ss_ctx_t *ctx = ngx_http_get_module_ctx(r, > > > > > > > nginx_mitigator_module); > > > > > > > > > > > > > > if (ctx && ctx->content) { > > > > > > > ctx->content = 0; > > > > > > > return http_mod_send_response(r, ctx->rcode, > ctx->custom_body); > > > > > > > } else { > > > > > > > ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, > > > > > > > "%s: ctx = %p, content = %d", __FUNCTION__, > ctx, > > > ctx > > > > > ? > > > > > > > ctx->content : -1); > > > > > > > } > > > > > > > > > > > > > > return NGX_DECLINED; > > > > > > > } > > > > > > > > > > > > > > static ngx_int_t > > > > > > > ngx_http_module_init (ngx_conf_t *cf) > > > > > > > { > > > > > > > ngx_http_core_main_conf_t *cmcf = > > > > > ngx_http_conf_get_module_main_conf(cf, > > > > > > > ngx_http_core_module); > > > > > > > > > > > > > > if (!cmcf) { > > > > > > > ngx_log_error(NGX_LOG_ERR, cf->log, 0, "Failed to retrieve > > > module > > > > > main > > > > > > > conf"); > > > > > > > return NGX_ERROR; > > > > > > > } > > > > > > > > > > > > > > ngx_http_handler_pt *hptr = > > > > > > > ngx_array_push(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers); > > > > > > > if (hptr == NULL) { > > > > > > > ngx_log_error(NGX_LOG_ERR, cf->log, 0, "Could not retrieve > > > access > > > > > > > phase handler"); > > > > > > > return NGX_ERROR; > > > > > > > } > > > > > > > > > > > > > > *hptr = ngx_http_request_handler; > > > > > > > ngx_log_error(NGX_LOG_INFO, cf->log, 0, "[init] Installed > request > > > > > > > handler"); > > > > > > > > > > > > > > ngx_http_handler_pt *cptr = > > > > > > > ngx_array_push(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers); > > > > > > > if (cptr == NULL) { > > > > > > > ngx_log_error(NGX_LOG_ERR, cf->log, 0, "Could not retrieve > > > access > > > > > > > phase handler"); > > > > > > > return NGX_ERROR; > > > > > > > } > > > > > > > > > > > > > > *cptr = ngx_http_request_handler; > > > > > > > ngx_log_error(NGX_LOG_INFO, cf->log, 0, "[init] Installed > request > > > > > > > handler"); > > > > > > > > > > > > > > return NGX_OK; > > > > > > > } > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > _______________________________________________ > > > > > > nginx-devel mailing list > > > > > > nginx-devel at nginx.org > > > > > > http://mailman.nginx.org/mailman/listinfo/nginx-devel > > > > > > > > > > > > > > > -- > > > > > Roman Arutyunyan > > > > > _______________________________________________ > > > > > nginx-devel mailing list > > > > > nginx-devel at nginx.org > > > > > http://mailman.nginx.org/mailman/listinfo/nginx-devel > > > > > > > > > > > > _______________________________________________ > > > > nginx-devel mailing list > > > > nginx-devel at nginx.org > > > > http://mailman.nginx.org/mailman/listinfo/nginx-devel > > > > > > > > > -- > > > Roman Arutyunyan > > > _______________________________________________ > > > nginx-devel mailing list > > > nginx-devel at nginx.org > > > http://mailman.nginx.org/mailman/listinfo/nginx-devel > > > > > > _______________________________________________ > > nginx-devel mailing list > > nginx-devel at nginx.org > > http://mailman.nginx.org/mailman/listinfo/nginx-devel > > > -- > Roman Arutyunyan > _______________________________________________ > 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 pluknet at nginx.com Tue Jul 17 11:50:07 2018 From: pluknet at nginx.com (Sergey Kandaurov) Date: Tue, 17 Jul 2018 11:50:07 +0000 Subject: [nginx] SSL: save sessions for upstream peers using a callback function. Message-ID: details: http://hg.nginx.org/nginx/rev/696df3ac27ac branches: changeset: 7320:696df3ac27ac user: Sergey Kandaurov date: Tue Jul 17 12:53:23 2018 +0300 description: SSL: save sessions for upstream peers using a callback function. In TLSv1.3, NewSessionTicket messages arrive after the handshake and can come at any time. Therefore we use a callback to save the session when we know about it. This approach works for < TLSv1.3 as well. The callback function is set once per location on merge phase. Since SSL_get_session() in BoringSSL returns an unresumable session for TLSv1.3, peer save_session() methods have been updated as well to use a session supplied within the callback. To preserve API, the session is cached in c->ssl->session. It is preferably accessed in save_session() methods by ngx_ssl_get_session() and ngx_ssl_get0_session() wrappers. diffstat: src/event/ngx_event_openssl.c | 63 ++++++++++++++++++++++++++++ src/event/ngx_event_openssl.h | 8 +++- src/http/modules/ngx_http_grpc_module.c | 7 +++ src/http/modules/ngx_http_proxy_module.c | 7 +++ src/http/modules/ngx_http_uwsgi_module.c | 7 +++ src/http/ngx_http_upstream.c | 28 ++++++++++- src/http/ngx_http_upstream_round_robin.c | 2 +- src/stream/ngx_stream_proxy_module.c | 27 +++++++++-- src/stream/ngx_stream_upstream_round_robin.c | 2 +- 9 files changed, 139 insertions(+), 12 deletions(-) diffs (318 lines): diff -r dcab86115261 -r 696df3ac27ac src/event/ngx_event_openssl.c --- a/src/event/ngx_event_openssl.c Mon Jul 16 17:47:48 2018 +0300 +++ b/src/event/ngx_event_openssl.c Tue Jul 17 12:53:23 2018 +0300 @@ -24,6 +24,8 @@ static int ngx_ssl_verify_callback(int o static void ngx_ssl_info_callback(const ngx_ssl_conn_t *ssl_conn, int where, int ret); static void ngx_ssl_passwords_cleanup(void *data); +static int ngx_ssl_new_client_session(ngx_ssl_conn_t *ssl_conn, + ngx_ssl_session_t *sess); static void ngx_ssl_handshake_handler(ngx_event_t *ev); static ngx_int_t ngx_ssl_handle_recv(ngx_connection_t *c, int n); static void ngx_ssl_write_handler(ngx_event_t *wev); @@ -1162,6 +1164,42 @@ ngx_ssl_ecdh_curve(ngx_conf_t *cf, ngx_s ngx_int_t +ngx_ssl_client_session_cache(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_uint_t enable) +{ + if (!enable) { + return NGX_OK; + } + + SSL_CTX_set_session_cache_mode(ssl->ctx, + SSL_SESS_CACHE_CLIENT + |SSL_SESS_CACHE_NO_INTERNAL); + + SSL_CTX_sess_set_new_cb(ssl->ctx, ngx_ssl_new_client_session); + + return NGX_OK; +} + + +static int +ngx_ssl_new_client_session(ngx_ssl_conn_t *ssl_conn, ngx_ssl_session_t *sess) +{ + ngx_connection_t *c; + + c = ngx_ssl_get_connection(ssl_conn); + + if (c->ssl->save_session) { + c->ssl->session = sess; + + c->ssl->save_session(c); + + c->ssl->session = NULL; + } + + return 0; +} + + +ngx_int_t ngx_ssl_create_connection(ngx_ssl_t *ssl, ngx_connection_t *c, ngx_uint_t flags) { ngx_ssl_connection_t *sc; @@ -1210,6 +1248,31 @@ ngx_ssl_create_connection(ngx_ssl_t *ssl } +ngx_ssl_session_t * +ngx_ssl_get_session(ngx_connection_t *c) +{ +#ifdef TLS1_3_VERSION + if (c->ssl->session) { + SSL_SESSION_up_ref(c->ssl->session); + return c->ssl->session; + } +#endif + + return SSL_get1_session(c->ssl->connection); +} + + +ngx_ssl_session_t * +ngx_ssl_get0_session(ngx_connection_t *c) +{ + if (c->ssl->session) { + return c->ssl->session; + } + + return SSL_get0_session(c->ssl->connection); +} + + ngx_int_t ngx_ssl_set_session(ngx_connection_t *c, ngx_ssl_session_t *session) { diff -r dcab86115261 -r 696df3ac27ac src/event/ngx_event_openssl.h --- a/src/event/ngx_event_openssl.h Mon Jul 16 17:47:48 2018 +0300 +++ b/src/event/ngx_event_openssl.h Tue Jul 17 12:53:23 2018 +0300 @@ -77,6 +77,9 @@ struct ngx_ssl_connection_s { ngx_connection_handler_pt handler; + ngx_ssl_session_t *session; + ngx_connection_handler_pt save_session; + ngx_event_handler_pt saved_read_handler; ngx_event_handler_pt saved_write_handler; @@ -168,6 +171,8 @@ RSA *ngx_ssl_rsa512_key_callback(ngx_ssl ngx_array_t *ngx_ssl_read_password_file(ngx_conf_t *cf, ngx_str_t *file); ngx_int_t ngx_ssl_dhparam(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file); ngx_int_t ngx_ssl_ecdh_curve(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *name); +ngx_int_t ngx_ssl_client_session_cache(ngx_conf_t *cf, ngx_ssl_t *ssl, + ngx_uint_t enable); ngx_int_t ngx_ssl_session_cache(ngx_ssl_t *ssl, ngx_str_t *sess_ctx, ssize_t builtin_session_cache, ngx_shm_zone_t *shm_zone, time_t timeout); ngx_int_t ngx_ssl_session_ticket_keys(ngx_conf_t *cf, ngx_ssl_t *ssl, @@ -178,7 +183,8 @@ ngx_int_t ngx_ssl_create_connection(ngx_ void ngx_ssl_remove_cached_session(SSL_CTX *ssl, ngx_ssl_session_t *sess); ngx_int_t ngx_ssl_set_session(ngx_connection_t *c, ngx_ssl_session_t *session); -#define ngx_ssl_get_session(c) SSL_get1_session(c->ssl->connection) +ngx_ssl_session_t *ngx_ssl_get_session(ngx_connection_t *c); +ngx_ssl_session_t *ngx_ssl_get0_session(ngx_connection_t *c); #define ngx_ssl_free_session SSL_SESSION_free #define ngx_ssl_get_connection(ssl_conn) \ SSL_get_ex_data(ssl_conn, ngx_ssl_connection_index) diff -r dcab86115261 -r 696df3ac27ac src/http/modules/ngx_http_grpc_module.c --- a/src/http/modules/ngx_http_grpc_module.c Mon Jul 16 17:47:48 2018 +0300 +++ b/src/http/modules/ngx_http_grpc_module.c Tue Jul 17 12:53:23 2018 +0300 @@ -4627,6 +4627,13 @@ ngx_http_grpc_set_ssl(ngx_conf_t *cf, ng } } + if (ngx_ssl_client_session_cache(cf, glcf->upstream.ssl, + glcf->upstream.ssl_session_reuse) + != NGX_OK) + { + return NGX_ERROR; + } + #ifdef TLSEXT_TYPE_application_layer_protocol_negotiation if (SSL_CTX_set_alpn_protos(glcf->upstream.ssl->ctx, diff -r dcab86115261 -r 696df3ac27ac src/http/modules/ngx_http_proxy_module.c --- a/src/http/modules/ngx_http_proxy_module.c Mon Jul 16 17:47:48 2018 +0300 +++ b/src/http/modules/ngx_http_proxy_module.c Tue Jul 17 12:53:23 2018 +0300 @@ -4308,6 +4308,13 @@ ngx_http_proxy_set_ssl(ngx_conf_t *cf, n } } + if (ngx_ssl_client_session_cache(cf, plcf->upstream.ssl, + plcf->upstream.ssl_session_reuse) + != NGX_OK) + { + return NGX_ERROR; + } + return NGX_OK; } diff -r dcab86115261 -r 696df3ac27ac src/http/modules/ngx_http_uwsgi_module.c --- a/src/http/modules/ngx_http_uwsgi_module.c Mon Jul 16 17:47:48 2018 +0300 +++ b/src/http/modules/ngx_http_uwsgi_module.c Tue Jul 17 12:53:23 2018 +0300 @@ -2391,6 +2391,13 @@ ngx_http_uwsgi_set_ssl(ngx_conf_t *cf, n } } + if (ngx_ssl_client_session_cache(cf, uwcf->upstream.ssl, + uwcf->upstream.ssl_session_reuse) + != NGX_OK) + { + return NGX_ERROR; + } + return NGX_OK; } diff -r dcab86115261 -r 696df3ac27ac src/http/ngx_http_upstream.c --- a/src/http/ngx_http_upstream.c Mon Jul 16 17:47:48 2018 +0300 +++ b/src/http/ngx_http_upstream.c Tue Jul 17 12:53:23 2018 +0300 @@ -187,6 +187,7 @@ static void ngx_http_upstream_ssl_init_c static void ngx_http_upstream_ssl_handshake_handler(ngx_connection_t *c); static void ngx_http_upstream_ssl_handshake(ngx_http_request_t *, ngx_http_upstream_t *u, ngx_connection_t *c); +static void ngx_http_upstream_ssl_save_session(ngx_connection_t *c); static ngx_int_t ngx_http_upstream_ssl_name(ngx_http_request_t *r, ngx_http_upstream_t *u, ngx_connection_t *c); #endif @@ -1675,6 +1676,8 @@ ngx_http_upstream_ssl_init_connection(ng } if (u->conf->ssl_session_reuse) { + c->ssl->save_session = ngx_http_upstream_ssl_save_session; + if (u->peer.set_session(&u->peer, u->peer.data) != NGX_OK) { ngx_http_upstream_finalize_request(r, u, NGX_HTTP_INTERNAL_SERVER_ERROR); @@ -1759,10 +1762,6 @@ ngx_http_upstream_ssl_handshake(ngx_http } } - if (u->conf->ssl_session_reuse) { - u->peer.save_session(&u->peer, u->peer.data); - } - c->write->handler = ngx_http_upstream_handler; c->read->handler = ngx_http_upstream_handler; @@ -1782,6 +1781,27 @@ failed: } +static void +ngx_http_upstream_ssl_save_session(ngx_connection_t *c) +{ + ngx_http_request_t *r; + ngx_http_upstream_t *u; + + if (c->idle) { + return; + } + + r = c->data; + + u = r->upstream; + c = r->connection; + + ngx_http_set_log_request(c->log, r); + + u->peer.save_session(&u->peer, u->peer.data); +} + + static ngx_int_t ngx_http_upstream_ssl_name(ngx_http_request_t *r, ngx_http_upstream_t *u, ngx_connection_t *c) diff -r dcab86115261 -r 696df3ac27ac src/http/ngx_http_upstream_round_robin.c --- a/src/http/ngx_http_upstream_round_robin.c Mon Jul 16 17:47:48 2018 +0300 +++ b/src/http/ngx_http_upstream_round_robin.c Tue Jul 17 12:53:23 2018 +0300 @@ -744,7 +744,7 @@ ngx_http_upstream_save_round_robin_peer_ if (peers->shpool) { - ssl_session = SSL_get0_session(pc->connection->ssl->connection); + ssl_session = ngx_ssl_get0_session(pc->connection); if (ssl_session == NULL) { return; diff -r dcab86115261 -r 696df3ac27ac src/stream/ngx_stream_proxy_module.c --- a/src/stream/ngx_stream_proxy_module.c Mon Jul 16 17:47:48 2018 +0300 +++ b/src/stream/ngx_stream_proxy_module.c Tue Jul 17 12:53:23 2018 +0300 @@ -92,6 +92,7 @@ static char *ngx_stream_proxy_ssl_passwo ngx_command_t *cmd, void *conf); static void ngx_stream_proxy_ssl_init_connection(ngx_stream_session_t *s); static void ngx_stream_proxy_ssl_handshake(ngx_connection_t *pc); +static void ngx_stream_proxy_ssl_save_session(ngx_connection_t *c); static ngx_int_t ngx_stream_proxy_ssl_name(ngx_stream_session_t *s); static ngx_int_t ngx_stream_proxy_set_ssl(ngx_conf_t *cf, ngx_stream_proxy_srv_conf_t *pscf); @@ -1008,6 +1009,8 @@ ngx_stream_proxy_ssl_init_connection(ngx } if (pscf->ssl_session_reuse) { + pc->ssl->save_session = ngx_stream_proxy_ssl_save_session; + if (u->peer.set_session(&u->peer, u->peer.data) != NGX_OK) { ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); return; @@ -1066,11 +1069,6 @@ ngx_stream_proxy_ssl_handshake(ngx_conne } } - if (pscf->ssl_session_reuse) { - u = s->upstream; - u->peer.save_session(&u->peer, u->peer.data); - } - if (pc->write->timer_set) { ngx_del_timer(pc->write); } @@ -1086,6 +1084,19 @@ failed: } +static void +ngx_stream_proxy_ssl_save_session(ngx_connection_t *c) +{ + ngx_stream_session_t *s; + ngx_stream_upstream_t *u; + + s = c->data; + u = s->upstream; + + u->peer.save_session(&u->peer, u->peer.data); +} + + static ngx_int_t ngx_stream_proxy_ssl_name(ngx_stream_session_t *s) { @@ -2051,6 +2062,12 @@ ngx_stream_proxy_set_ssl(ngx_conf_t *cf, } } + if (ngx_ssl_client_session_cache(cf, pscf->ssl, pscf->ssl_session_reuse) + != NGX_OK) + { + return NGX_ERROR; + } + return NGX_OK; } diff -r dcab86115261 -r 696df3ac27ac src/stream/ngx_stream_upstream_round_robin.c --- a/src/stream/ngx_stream_upstream_round_robin.c Mon Jul 16 17:47:48 2018 +0300 +++ b/src/stream/ngx_stream_upstream_round_robin.c Tue Jul 17 12:53:23 2018 +0300 @@ -776,7 +776,7 @@ ngx_stream_upstream_save_round_robin_pee if (peers->shpool) { - ssl_session = SSL_get0_session(pc->connection->ssl->connection); + ssl_session = ngx_ssl_get0_session(pc->connection); if (ssl_session == NULL) { return; From xeioex at nginx.com Tue Jul 17 17:25:52 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Tue, 17 Jul 2018 17:25:52 +0000 Subject: [njs] Fixed exception handling in njs_vm_value_to_ext_string(). Message-ID: details: http://hg.nginx.org/njs/rev/729072cc162f branches: changeset: 559:729072cc162f user: Dmitry Volyntsev date: Tue Jul 17 20:25:47 2018 +0300 description: Fixed exception handling in njs_vm_value_to_ext_string(). diffstat: njs/njs_vm.c | 14 ++++++++++++-- njs/test/njs_expect_test.exp | 7 +++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diffs (55 lines): diff -r 04dc301f7d5a -r 729072cc162f njs/njs_vm.c --- a/njs/njs_vm.c Mon Jul 16 14:30:41 2018 +0300 +++ b/njs/njs_vm.c Tue Jul 17 20:25:47 2018 +0300 @@ -3273,8 +3273,9 @@ fail: static njs_ret_t njs_object_value_to_string(njs_vm_t *vm, njs_value_t *value) { - u_char *current; - njs_ret_t ret; + u_char *current; + njs_ret_t ret; + njs_native_frame_t *previous; static const njs_vmcode_1addr_t value_to_string[] = { { .code = { .operation = njs_vmcode_value_to_string, @@ -3298,6 +3299,14 @@ njs_object_value_to_string(njs_vm_t *vm, njs_set_invalid(&vm->top_frame->trap_scratch); vm->top_frame->trap_values[0] = *value; + /* + * Prevent njs_vmcode_interpreter() to unwind the current frame if + * an exception happens. It preserves the current frame state if + * njs_vm_value_to_ext_string() is called from within njs_vm_run(). + */ + previous = vm->top_frame->previous; + vm->top_frame->previous = NULL; + ret = njs_vmcode_interpreter(vm); if (ret == NJS_STOP) { @@ -3306,6 +3315,7 @@ njs_object_value_to_string(njs_vm_t *vm, } vm->current = current; + vm->top_frame->previous = previous; return ret; } diff -r 04dc301f7d5a -r 729072cc162f njs/test/njs_expect_test.exp --- a/njs/test/njs_expect_test.exp Mon Jul 16 14:30:41 2018 +0300 +++ b/njs/test/njs_expect_test.exp Tue Jul 17 20:25:47 2018 +0300 @@ -203,6 +203,13 @@ njs_test { "JSON.parse(Error()\r\nSyntaxError: Unexpected token \"\" in 1"} } +njs_test { + {"try { console.log({ toString: function() { throw 'test'; } }) } catch (e) {}\r\n" + "undefined"} + {"function f() { throw 't' }; try { console.log({ toString: function() { return f() } }) } catch (e) {}\r\n" + "undefined"} +} + # Non-ASCII characters njs_test { {"'???'\r\n" From xeioex at nginx.com Wed Jul 18 12:42:03 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Wed, 18 Jul 2018 12:42:03 +0000 Subject: [njs] String.bytesFrom() method. Message-ID: details: http://hg.nginx.org/njs/rev/9322e8eab0b6 branches: changeset: 560:9322e8eab0b6 user: Dmitry Volyntsev date: Wed Jul 18 15:41:55 2018 +0300 description: String.bytesFrom() method. The method creates a byte string from an array containing octets: String.bytesFrom(array). The method creates a byte string from an encoded string: String.bytesFrom(string, encoding) where encoding are "hex", "base64", "base64url". This closes #2 issue on Github. diffstat: njs/njs_number.c | 21 +-- njs/njs_number.h | 23 +++ njs/njs_string.c | 315 +++++++++++++++++++++++++++++++++++++++++++++++ njs/njs_string.h | 7 + njs/test/njs_unit_test.c | 63 +++++++++ 5 files changed, 413 insertions(+), 16 deletions(-) diffs (534 lines): diff -r 729072cc162f -r 9322e8eab0b6 njs/njs_number.c --- a/njs/njs_number.c Tue Jul 17 20:25:47 2018 +0300 +++ b/njs/njs_number.c Wed Jul 18 15:41:55 2018 +0300 @@ -215,8 +215,8 @@ njs_number_bin_parse(const u_char **star uint64_t njs_number_hex_parse(const u_char **start, const u_char *end) { - u_char c; uint64_t num; + nxt_int_t n; const u_char *p; p = *start; @@ -224,23 +224,12 @@ njs_number_hex_parse(const u_char **star num = 0; while (p < end) { - c = (u_char) (*p | 0x20); - - /* Values less than '0' become >= 208. */ - c = c - '0'; - - if (c > 9) { - /* Values less than 'a' become >= 159. */ - c = c - ('a' - '0'); - - if (nxt_slow_path(c > 5)) { - break; - } - - c += 10; + n = njs_char_to_hex(*p); + if (nxt_slow_path(n < 0)) { + break; } - num = num * 16 + c; + num = num * 16 + n; p++; } diff -r 729072cc162f -r 9322e8eab0b6 njs/njs_number.h --- a/njs/njs_number.h Tue Jul 17 20:25:47 2018 +0300 +++ b/njs/njs_number.h Wed Jul 18 15:41:55 2018 +0300 @@ -34,6 +34,29 @@ njs_ret_t njs_number_parse_float(njs_vm_ nxt_noinline uint32_t njs_number_to_integer(double num); +nxt_inline nxt_int_t +njs_char_to_hex(u_char c) +{ + c |= 0x20; + + /* Values less than '0' become >= 208. */ + c = c - '0'; + + if (c > 9) { + /* Values less than 'a' become >= 159. */ + c = c - ('a' - '0'); + + if (nxt_slow_path(c > 5)) { + return -1; + } + + c += 10; + } + + return c; +} + + extern const njs_object_init_t njs_number_constructor_init; extern const njs_object_init_t njs_number_prototype_init; diff -r 729072cc162f -r 9322e8eab0b6 njs/njs_string.c --- a/njs/njs_string.c Tue Jul 17 20:25:47 2018 +0300 +++ b/njs/njs_string.c Wed Jul 18 15:41:55 2018 +0300 @@ -56,12 +56,20 @@ typedef struct { static void njs_encode_base64_core(nxt_str_t *dst, const nxt_str_t *src, const u_char *basis, nxt_uint_t padding); +static njs_ret_t njs_decode_base64_core(njs_vm_t *vm, + njs_value_t *value, const nxt_str_t *src, const u_char *basis); static nxt_noinline void njs_string_slice_prop(njs_string_prop_t *string, njs_slice_prop_t *slice, njs_value_t *args, nxt_uint_t nargs); static nxt_noinline void njs_string_slice_args(njs_slice_prop_t *slice, njs_value_t *args, nxt_uint_t nargs); static njs_ret_t njs_string_from_char_code(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused); +static njs_ret_t njs_string_bytes_from(njs_vm_t *vm, njs_value_t *args, + nxt_uint_t nargs, njs_index_t unused); +static njs_ret_t njs_string_bytes_from_array(njs_vm_t *vm, + const njs_value_t *value); +static njs_ret_t njs_string_bytes_from_string(njs_vm_t *vm, + const njs_value_t *args, nxt_uint_t nargs); static njs_ret_t njs_string_starts_or_ends_with(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, nxt_bool_t starts); static njs_ret_t njs_string_prototype_pad(njs_vm_t *vm, njs_value_t *args, @@ -99,6 +107,7 @@ static njs_ret_t njs_string_decode(njs_v #define njs_base64_encoded_length(len) (((len + 2) / 3) * 4) +#define njs_base64_decoded_length(len) (((len + 3) / 4) * 3) njs_ret_t @@ -165,6 +174,8 @@ njs_string_new(njs_vm_t *vm, njs_value_t return NXT_OK; } + njs_memory_error(vm); + return NXT_ERROR; } @@ -222,10 +233,41 @@ njs_string_alloc(njs_vm_t *vm, njs_value return string->start; } + njs_memory_error(vm); + return NULL; } +void +njs_string_truncate(njs_value_t *value, uint32_t size) +{ + u_char *dst, *src; + + if (size <= NJS_STRING_SHORT) { + if (value->short_string.size != NJS_STRING_LONG) { + value->short_string.size = size; + + } else { + value->short_string.size = size; + dst = value->short_string.start; + src = value->long_string.data->start; + + while (size != 0) { + /* The maximum size is just 14 bytes. */ + nxt_pragma_loop_disable_vectorization; + + *dst++ = *src++; + size--; + } + } + + } else { + value->long_string.size = size; + } +} + + nxt_noinline njs_ret_t njs_string_hex(njs_vm_t *vm, njs_value_t *value, const nxt_str_t *src) { @@ -552,6 +594,15 @@ static const njs_object_prop_t njs_stri .value = njs_prop_handler(njs_object_prototype_create), }, + /* String.bytesFrom(). */ + { + .type = NJS_METHOD, + .name = njs_string("bytesFrom"), + .value = njs_native_function(njs_string_bytes_from, 0, NJS_SKIP_ARG, + NJS_SKIP_ARG, NJS_STRING_ARG), + }, + + /* String.fromCharCode(). */ { .type = NJS_METHOD, @@ -1331,6 +1382,270 @@ done: } +/* + * String.bytesFrom(array). + * Converts an array containing octets into a byte string. + * + * String.bytesFrom(string[, encoding]). + * Converts a string using provided encoding: hex, base64, base64url to + * a byte string. + */ + +static njs_ret_t +njs_string_bytes_from(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, + njs_index_t unused) +{ + const njs_value_t *value; + + value = njs_arg(args, nargs, 1); + + if (njs_is_string(value)) { + return njs_string_bytes_from_string(vm, args, nargs); + } + + if (njs_is_array(value)) { + return njs_string_bytes_from_array(vm, njs_arg(args, nargs, 1)); + } + + njs_type_error(vm, "value must be a string or array"); + + return NJS_ERROR; +} + + +static njs_ret_t +njs_string_bytes_from_array(njs_vm_t *vm, const njs_value_t *value) +{ + u_char *p; + uint32_t i, length; + njs_array_t *array; + njs_value_t *octet; + + array = value->data.u.array; + length = array->length; + + for (i = 0; i < length; i++) { + if (!njs_is_numeric(&array->start[i])) { + njs_vm_trap_value(vm, &array->start[i]); + return NJS_TRAP_NUMBER_ARG; + } + } + + p = njs_string_alloc(vm, &vm->retval, length, 0); + if (nxt_slow_path(p == NULL)) { + return NJS_ERROR; + } + + octet = array->start; + + while (length != 0) { + *p++ = (u_char) njs_number_to_integer(octet->data.u.number); + octet++; + length--; + } + + return NJS_OK; +} + + +static njs_ret_t +njs_string_bytes_from_string(njs_vm_t *vm, const njs_value_t *args, + nxt_uint_t nargs) +{ + nxt_str_t enc, str; + const njs_value_t *enc_val; + + enc_val = njs_arg(args, nargs, 2); + + if (nxt_slow_path(nargs > 1 && !njs_is_string(enc_val))) { + njs_type_error(vm, "encoding must be a string"); + return NJS_ERROR; + } + + njs_string_get(enc_val, &enc); + njs_string_get(&args[1], &str); + + if (enc.length == 3 && memcmp(enc.start, "hex", 3) == 0) { + return njs_string_decode_hex(vm, &vm->retval, &str); + + } else if (enc.length == 6 && memcmp(enc.start, "base64", 6) == 0) { + return njs_string_decode_base64(vm, &vm->retval, &str); + + } else if (enc.length == 9 && memcmp(enc.start, "base64url", 6) == 0) { + return njs_string_decode_base64url(vm, &vm->retval, &str); + } + + njs_type_error(vm, "Unknown encoding: '%.*s'", (int) enc.length, + enc.start); + + return NJS_ERROR; +} + + +nxt_noinline njs_ret_t +njs_string_decode_hex(njs_vm_t *vm, njs_value_t *value, const nxt_str_t *src) +{ + u_char *p, *dst; + size_t len; + nxt_int_t c; + nxt_uint_t i, n; + const u_char *start; + + len = src->length; + start = src->start; + + if (nxt_slow_path(len == 0)) { + vm->retval = njs_string_empty; + return NJS_OK; + } + + dst = njs_string_alloc(vm, value, len / 2, 0); + if (nxt_slow_path(dst == NULL)) { + return NJS_ERROR; + } + + n = 0; + p = dst; + + for (i = 0; i < len; i++) { + c = njs_char_to_hex(start[i]); + if (nxt_slow_path(c < 0)) { + break; + } + + n = n * 16 + c; + + if ((i & 1) != 0) { + *p++ = (u_char) n; + n = 0; + } + } + + if (nxt_slow_path((size_t) (p - dst) != (len / 2))) { + njs_string_truncate(value, p - dst); + } + + return NJS_OK; +} + + +nxt_noinline njs_ret_t +njs_string_decode_base64(njs_vm_t *vm, njs_value_t *value, const nxt_str_t *src) +{ + static u_char basis64[] = { + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 62, 77, 77, 77, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 77, 77, 77, 77, 77, 77, + 77, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 77, 77, 77, 77, 77, + 77, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 77, 77, 77, 77, 77, + + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77 + }; + + return njs_decode_base64_core(vm, value, src, basis64); +} + + +nxt_noinline njs_ret_t +njs_string_decode_base64url(njs_vm_t *vm, njs_value_t *value, + const nxt_str_t *src) +{ + static u_char basis64[] = { + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 62, 77, 77, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 77, 77, 77, 77, 77, 77, + 77, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 77, 77, 77, 77, 63, + 77, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 77, 77, 77, 77, 77, + + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77 + }; + + return njs_decode_base64_core(vm, value, src, basis64); +} + + +static njs_ret_t +njs_decode_base64_core(njs_vm_t *vm, njs_value_t *value, const nxt_str_t *src, + const u_char *basis) +{ + size_t len, dst_len; + u_char *d, *s, *dst; + + if (nxt_slow_path(src->length == 0)) { + vm->retval = njs_string_empty; + return NJS_OK; + } + + for (len = 0; len < src->length; len++) { + if (src->start[len] == '=') { + break; + } + + if (basis[src->start[len]] == 77) { + break; + } + } + + if (len % 4 == 1) { + /* Rounding down to integer multiple of 4. */ + len -= 1; + } + + dst_len = njs_base64_decoded_length(len); + + dst = njs_string_alloc(vm, value, dst_len, 0); + if (nxt_slow_path(dst == NULL)) { + return NJS_ERROR; + } + + s = src->start; + d = dst; + + while (len > 3) { + *d++ = (u_char) (basis[s[0]] << 2 | basis[s[1]] >> 4); + *d++ = (u_char) (basis[s[1]] << 4 | basis[s[2]] >> 2); + *d++ = (u_char) (basis[s[2]] << 6 | basis[s[3]]); + + s += 4; + len -= 4; + } + + if (len > 1) { + *d++ = (u_char) (basis[s[0]] << 2 | basis[s[1]] >> 4); + } + + if (len > 2) { + *d++ = (u_char) (basis[s[1]] << 4 | basis[s[2]] >> 2); + } + + if (nxt_slow_path((size_t) (d - dst) != dst_len)) { + njs_string_truncate(value, d - dst); + } + + return NXT_OK; +} + + static njs_ret_t njs_string_from_char_code(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused) diff -r 729072cc162f -r 9322e8eab0b6 njs/njs_string.h --- a/njs/njs_string.h Tue Jul 17 20:25:47 2018 +0300 +++ b/njs/njs_string.h Wed Jul 18 15:41:55 2018 +0300 @@ -129,6 +129,13 @@ njs_ret_t njs_string_base64(njs_vm_t *vm const nxt_str_t *src); njs_ret_t njs_string_base64url(njs_vm_t *vm, njs_value_t *value, const nxt_str_t *src); +njs_ret_t njs_string_decode_hex(njs_vm_t *vm, njs_value_t *value, + const nxt_str_t *src); +njs_ret_t njs_string_decode_base64(njs_vm_t *vm, njs_value_t *value, + const nxt_str_t *src); +njs_ret_t njs_string_decode_base64url(njs_vm_t *vm, njs_value_t *value, + const nxt_str_t *src); +void njs_string_truncate(njs_value_t *value, uint32_t size); void njs_string_copy(njs_value_t *dst, njs_value_t *src); njs_ret_t njs_string_validate(njs_vm_t *vm, njs_string_prop_t *string, njs_value_t *value); diff -r 729072cc162f -r 9322e8eab0b6 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Tue Jul 17 20:25:47 2018 +0300 +++ b/njs/test/njs_unit_test.c Wed Jul 18 15:41:55 2018 +0300 @@ -4656,6 +4656,69 @@ static njs_unit_test_t njs_test[] = { nxt_string("'????'.padEnd(10, '????')"), nxt_string("??????????") }, + { nxt_string("String.bytesFrom({})"), + nxt_string("TypeError: value must be a string or array") }, + + { nxt_string("String.bytesFrom([1, 2, 0.23, '5', 'A']).toString('hex')"), + nxt_string("0102000500") }, + + { nxt_string("String.bytesFrom([NaN, Infinity]).toString('hex')"), + nxt_string("0000") }, + + { nxt_string("String.bytesFrom('', 'hex')"), + nxt_string("") }, + + { nxt_string("String.bytesFrom('00aabbcc', 'hex').toString('hex')"), + nxt_string("00aabbcc") }, + + { nxt_string("String.bytesFrom('deadBEEF##', 'hex').toString('hex')"), + nxt_string("deadbeef") }, + + { nxt_string("String.bytesFrom('aa0', 'hex').toString('hex')"), + nxt_string("aa") }, + + { nxt_string("String.bytesFrom('', 'base64')"), + nxt_string("") }, + + { nxt_string("String.bytesFrom('#', 'base64')"), + nxt_string("") }, + + { nxt_string("String.bytesFrom('QQ==', 'base64')"), + nxt_string("A") }, + + { nxt_string("String.bytesFrom('QQ', 'base64')"), + nxt_string("A") }, + + { nxt_string("String.bytesFrom('QUI=', 'base64')"), + nxt_string("AB") }, + + { nxt_string("String.bytesFrom('QUI', 'base64')"), + nxt_string("AB") }, + + { nxt_string("String.bytesFrom('QUJD', 'base64')"), + nxt_string("ABC") }, + + { nxt_string("String.bytesFrom('QUJDRA==', 'base64')"), + nxt_string("ABCD") }, + + { nxt_string("String.bytesFrom('', 'base64url')"), + nxt_string("") }, + + { nxt_string("String.bytesFrom('QQ', 'base64url')"), + nxt_string("A") }, + + { nxt_string("String.bytesFrom('QUI', 'base64url')"), + nxt_string("AB") }, + + { nxt_string("String.bytesFrom('QUJD', 'base64url')"), + nxt_string("ABC") }, + + { nxt_string("String.bytesFrom('QUJDRA', 'base64url')"), + nxt_string("ABCD") }, + + { nxt_string("String.bytesFrom('QUJDRA#', 'base64url')"), + nxt_string("ABCD") }, + { nxt_string("encodeURI()"), nxt_string("undefined")}, From ru at nginx.com Wed Jul 18 15:33:17 2018 From: ru at nginx.com (Ruslan Ermilov) Date: Wed, 18 Jul 2018 15:33:17 +0000 Subject: [nginx] Fixed invalid access to location defined as an empty string. Message-ID: details: http://hg.nginx.org/nginx/rev/45e513c3540d branches: changeset: 7321:45e513c3540d user: Ruslan Ermilov date: Tue Jul 17 15:30:43 2018 +0300 description: Fixed invalid access to location defined as an empty string. diffstat: src/http/modules/ngx_http_fastcgi_module.c | 2 +- src/http/modules/ngx_http_grpc_module.c | 2 +- src/http/modules/ngx_http_memcached_module.c | 2 +- src/http/modules/ngx_http_proxy_module.c | 2 +- src/http/modules/ngx_http_scgi_module.c | 2 +- src/http/modules/ngx_http_uwsgi_module.c | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diffs (72 lines): diff -r 696df3ac27ac -r 45e513c3540d src/http/modules/ngx_http_fastcgi_module.c --- a/src/http/modules/ngx_http_fastcgi_module.c Tue Jul 17 12:53:23 2018 +0300 +++ b/src/http/modules/ngx_http_fastcgi_module.c Tue Jul 17 15:30:43 2018 +0300 @@ -3501,7 +3501,7 @@ ngx_http_fastcgi_pass(ngx_conf_t *cf, ng clcf->handler = ngx_http_fastcgi_handler; - if (clcf->name.data[clcf->name.len - 1] == '/') { + if (clcf->name.len && clcf->name.data[clcf->name.len - 1] == '/') { clcf->auto_redirect = 1; } diff -r 696df3ac27ac -r 45e513c3540d src/http/modules/ngx_http_grpc_module.c --- a/src/http/modules/ngx_http_grpc_module.c Tue Jul 17 12:53:23 2018 +0300 +++ b/src/http/modules/ngx_http_grpc_module.c Tue Jul 17 15:30:43 2018 +0300 @@ -4525,7 +4525,7 @@ ngx_http_grpc_pass(ngx_conf_t *cf, ngx_c clcf->handler = ngx_http_grpc_handler; - if (clcf->name.data[clcf->name.len - 1] == '/') { + if (clcf->name.len && clcf->name.data[clcf->name.len - 1] == '/') { clcf->auto_redirect = 1; } diff -r 696df3ac27ac -r 45e513c3540d src/http/modules/ngx_http_memcached_module.c --- a/src/http/modules/ngx_http_memcached_module.c Tue Jul 17 12:53:23 2018 +0300 +++ b/src/http/modules/ngx_http_memcached_module.c Tue Jul 17 15:30:43 2018 +0300 @@ -707,7 +707,7 @@ ngx_http_memcached_pass(ngx_conf_t *cf, clcf->handler = ngx_http_memcached_handler; - if (clcf->name.data[clcf->name.len - 1] == '/') { + if (clcf->name.len && clcf->name.data[clcf->name.len - 1] == '/') { clcf->auto_redirect = 1; } diff -r 696df3ac27ac -r 45e513c3540d src/http/modules/ngx_http_proxy_module.c --- a/src/http/modules/ngx_http_proxy_module.c Tue Jul 17 12:53:23 2018 +0300 +++ b/src/http/modules/ngx_http_proxy_module.c Tue Jul 17 15:30:43 2018 +0300 @@ -3580,7 +3580,7 @@ ngx_http_proxy_pass(ngx_conf_t *cf, ngx_ clcf->handler = ngx_http_proxy_handler; - if (clcf->name.data[clcf->name.len - 1] == '/') { + if (clcf->name.len && clcf->name.data[clcf->name.len - 1] == '/') { clcf->auto_redirect = 1; } diff -r 696df3ac27ac -r 45e513c3540d src/http/modules/ngx_http_scgi_module.c --- a/src/http/modules/ngx_http_scgi_module.c Tue Jul 17 12:53:23 2018 +0300 +++ b/src/http/modules/ngx_http_scgi_module.c Tue Jul 17 15:30:43 2018 +0300 @@ -1857,7 +1857,7 @@ ngx_http_scgi_pass(ngx_conf_t *cf, ngx_c return NGX_CONF_ERROR; } - if (clcf->name.data[clcf->name.len - 1] == '/') { + if (clcf->name.len && clcf->name.data[clcf->name.len - 1] == '/') { clcf->auto_redirect = 1; } diff -r 696df3ac27ac -r 45e513c3540d src/http/modules/ngx_http_uwsgi_module.c --- a/src/http/modules/ngx_http_uwsgi_module.c Tue Jul 17 12:53:23 2018 +0300 +++ b/src/http/modules/ngx_http_uwsgi_module.c Tue Jul 17 15:30:43 2018 +0300 @@ -2144,7 +2144,7 @@ ngx_http_uwsgi_pass(ngx_conf_t *cf, ngx_ return NGX_CONF_ERROR; } - if (clcf->name.data[clcf->name.len - 1] == '/') { + if (clcf->name.len && clcf->name.data[clcf->name.len - 1] == '/') { clcf->auto_redirect = 1; } From kiriyama.kentaro at tis.co.jp Thu Jul 19 08:24:55 2018 From: kiriyama.kentaro at tis.co.jp (=?gb2312?B?zanJvaGhvaHMq8DJ?=) Date: Thu, 19 Jul 2018 08:24:55 +0000 Subject: [nginx]empty gif Message-ID: Hello, I have installed the nginx by making yum repository to the RHEL 7.4 server on EC2(AWS) and the architecture is like below. CloudFront-->WAF-->ELB(ALB)-->EC2 Nginx server(as a Reverse proxy)-->ELB(ALB)-->goes to 2 different backend web server A and B. Also, I have configured the conf files as two conf. file other than nginx.conf. The above two conf. file is named RP.conf and ALBHealthcheck.conf and placed those under /etc/nginx/ directory, so that nginx conf. could load those two conf. files. (include /etc/nginx/conf.d/*.conf) As for the ELB health check I would like to use the empty gif, however I couldn?t find the default module ?ngx_http_empty_gif_module? is on the system. I have checked the ?/usr/lib64/nginx/modules/?, but shows there is nothing in it. 1. Do I have to configure the module one by one? Or nginx has the default module? 2. How can I define the list of module for nginx? What command can list all the module with nginx? My goal is to succeed the health check for ELB with an path of ?/healthcheck.html? Regards Kentaro -------------- next part -------------- An HTML attachment was scrubbed... URL: From serg.brester at sebres.de Thu Jul 19 08:51:19 2018 From: serg.brester at sebres.de (Sergey Brester) Date: Thu, 19 Jul 2018 10:51:19 +0200 Subject: [nginx]empty gif In-Reply-To: References: Message-ID: <27627e8b40b5543ff2875bb2a549fd77@sebres.de> So you want something like? location = /healthcheck.gif { empty_gif; } And it does not work? 1. if you've installed nginx via distribution and your nginx version is larger as 1.9 (which supports dynamic modules), you can just install the modules via yum. If not, you should use nginx-extra package or compile nginx with modules you needed (or install from other repository). 2. to load module use load_module [2] directive. to list what it has statically, use "nginx -V" But IMHO for the simple health check would be enough: location = /healthcheck { default_type text/plain; return 200 "OK"; } Regards, sebres. Am 19.07.2018 10:24, schrieb ??????: > Hello, > > I have installed the nginx by making yum repository to the RHEL 7.4 server on EC2(AWS) and the architecture is like below. > > CloudFront?WAF?ELB(ALB)?EC2 Nginx server(as a Reverse proxy)?ELB(ALB)?goes to 2 different backend web server A and B. > > Also, I have configured the conf files as two conf. file other than nginx.conf. > > The above two conf. file is named RP.conf and ALBHealthcheck.conf and placed those under /etc/nginx/ directory, so that nginx conf. could load those two conf. files. (include /etc/nginx/conf.d/*.conf) > > As for the ELB health check I would like to use the empty gif, however I couldn't find the default module 'ngx_http_empty_gif_module" is > on the system. > > I have checked the "/usr/lib64/nginx/modules/", but shows there is nothing in it. > > 1. Do I have to configure the module one by one? Or nginx has the default module? > > 2. How can I define the list of module for nginx? What command can list all the module with nginx? > > My goal is to succeed the health check for ELB with an path of "/healthcheck.html" > > Regards > > Kentaro > > _______________________________________________ > nginx-devel mailing list > nginx-devel at nginx.org > http://mailman.nginx.org/mailman/listinfo/nginx-devel [1] Links: ------ [1] http://mailman.nginx.org/mailman/listinfo/nginx-devel [2] http://nginx.org/en/docs/ngx_core_module.html#load_module -------------- next part -------------- An HTML attachment was scrubbed... URL: From kiriyama.kentaro at tis.co.jp Thu Jul 19 09:03:54 2018 From: kiriyama.kentaro at tis.co.jp (=?utf-8?B?5qGQ5bGx44CA5YGl5aSq6YOO?=) Date: Thu, 19 Jul 2018 09:03:54 +0000 Subject: [nginx]empty gif In-Reply-To: <27627e8b40b5543ff2875bb2a549fd77@sebres.de> References: <27627e8b40b5543ff2875bb2a549fd77@sebres.de> Message-ID: Hi Sebres, Appreciate for your reply. The version of nginx on the RHEL 7.4 is nginx/1.14.0. and installed with the repository which I have created by taking a look at the documentation on Nginx.org. [nginx] name=nginx repo baseurl=http://nginx.org/packages/rhel/7/$basearch/ gpgcheck=0 enabled=1 Anyway, I will take your opinion and try to do the simple health check. If I have further clue, I will come back. Regards Kentaro From: Sergey Brester [mailto:serg.brester at sebres.de] Sent: Thursday, July 19, 2018 5:51 PM To: nginx-devel at nginx.org Cc: ?????; ?????; ?????? Subject: Re: [nginx]empty gif So you want something like? location = /healthcheck.gif { empty_gif; } And it does not work? 1. if you've installed nginx via distribution and your nginx version is larger as 1.9 (which supports dynamic modules), you can just install the modules via yum. If not, you should use nginx-extra package or compile nginx with modules you needed (or install from other repository). 2. to load module use load_module directive. to list what it has statically, use "nginx -V" But IMHO for the simple health check would be enough: location = /healthcheck { default_type text/plain; return 200 "OK"; } Regards, sebres. Am 19.07.2018 10:24, schrieb ??????: Hello, I have installed the nginx by making yum repository to the RHEL 7.4 server on EC2(AWS) and the architecture is like below. CloudFront-->WAF-->ELB(ALB)-->EC2 Nginx server(as a Reverse proxy)-->ELB(ALB)-->goes to 2 different backend web server A and B. Also, I have configured the conf files as two conf. file other than nginx.conf. The above two conf. file is named RP.conf and ALBHealthcheck.conf and placed those under /etc/nginx/ directory, so that nginx conf. could load those two conf. files. (include /etc/nginx/conf.d/*.conf) As for the ELB health check I would like to use the empty gif, however I couldn't find the default module 'ngx_http_empty_gif_module" is on the system. I have checked the "/usr/lib64/nginx/modules/", but shows there is nothing in it. 1. Do I have to configure the module one by one? Or nginx has the default module? 2. How can I define the list of module for nginx? What command can list all the module with nginx? My goal is to succeed the health check for ELB with an path of "/healthcheck.html" Regards Kentaro _______________________________________________ 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 pluknet at nginx.com Thu Jul 19 10:02:08 2018 From: pluknet at nginx.com (Sergey Kandaurov) Date: Thu, 19 Jul 2018 10:02:08 +0000 Subject: [nginx] Stream ssl_preread: added SSLv2 Client Hello support. Message-ID: details: http://hg.nginx.org/nginx/rev/6649d4433266 branches: changeset: 7322:6649d4433266 user: Sergey Kandaurov date: Wed Jul 18 18:51:25 2018 +0300 description: Stream ssl_preread: added SSLv2 Client Hello support. In particular, it was not possible to obtain SSLv2 protocol version. diffstat: src/stream/ngx_stream_ssl_preread_module.c | 16 ++++++++++++++-- 1 files changed, 14 insertions(+), 2 deletions(-) diffs (33 lines): diff -r 45e513c3540d -r 6649d4433266 src/stream/ngx_stream_ssl_preread_module.c --- a/src/stream/ngx_stream_ssl_preread_module.c Tue Jul 17 15:30:43 2018 +0300 +++ b/src/stream/ngx_stream_ssl_preread_module.c Wed Jul 18 18:51:25 2018 +0300 @@ -149,6 +149,14 @@ ngx_stream_ssl_preread_handler(ngx_strea while (last - p >= 5) { + if ((p[0] & 0x80) && p[2] == 1 && (p[3] == 0 || p[3] == 3)) { + ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0, + "ssl preread: version 2 ClientHello"); + ctx->version[0] = p[3]; + ctx->version[1] = p[4]; + return NGX_OK; + } + if (p[0] != 0x16) { ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0, "ssl preread: not a handshake"); @@ -507,8 +515,12 @@ ngx_stream_ssl_preread_protocol_variable ngx_str_null(&version); switch (ctx->version[0]) { - case 2: - ngx_str_set(&version, "SSLv2"); + case 0: + switch (ctx->version[1]) { + case 2: + ngx_str_set(&version, "SSLv2"); + break; + } break; case 3: switch (ctx->version[1]) { From vbart at nginx.com Thu Jul 19 12:06:23 2018 From: vbart at nginx.com (Valentin V. Bartenev) Date: Thu, 19 Jul 2018 15:06:23 +0300 Subject: [nginx]empty gif In-Reply-To: References: <27627e8b40b5543ff2875bb2a549fd77@sebres.de> Message-ID: <2265024.dSIvmKqonV@vbart-laptop> On Thursday, 19 July 2018 12:03:54 MSK ?????? wrote: > Hi Sebres, > > Appreciate for your reply. > > The version of nginx on the RHEL 7.4 is nginx/1.14.0. and installed with the repository which I have created by taking a look at the documentation on Nginx.org. > [..] The empty_gif module is built _statically_ by default. You don't need to specify the "load_module" directive in order to use the module. wbr, Valentin V. Bartenev From xeioex at nginx.com Thu Jul 19 15:12:57 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Thu, 19 Jul 2018 15:12:57 +0000 Subject: [njs] Fixed Number.toString(). Message-ID: details: http://hg.nginx.org/njs/rev/0f9c060a0198 branches: changeset: 561:0f9c060a0198 user: Dmitry Volyntsev date: Thu Jul 19 18:11:52 2018 +0300 description: Fixed Number.toString(). Adding correct dtoa() and strtod() realization. This fixes #28 and #30 issues on GitHub. diffstat: Makefile | 6 + njs/njs_core.h | 2 + njs/njs_json.c | 2 +- njs/njs_number.c | 116 +------------- njs/njs_number.h | 1 - njs/test/njs_unit_test.c | 74 ++++++- nxt/Makefile | 36 ++++ nxt/auto/clang | 26 +++ nxt/nxt_clang.h | 32 +++ nxt/nxt_diyfp.c | 150 +++++++++++++++++ nxt/nxt_diyfp.h | 212 ++++++++++++++++++++++++ nxt/nxt_dtoa.c | 363 ++++++++++++++++++++++++++++++++++++++++++ nxt/nxt_dtoa.h | 12 + nxt/nxt_strtod.c | 403 +++++++++++++++++++++++++++++++++++++++++++++++ nxt/nxt_strtod.h | 12 + nxt/nxt_types.h | 5 + 16 files changed, 1322 insertions(+), 130 deletions(-) diffs (truncated from 1692 to 1000 lines): diff -r 9322e8eab0b6 -r 0f9c060a0198 Makefile --- a/Makefile Wed Jul 18 15:41:55 2018 +0300 +++ b/Makefile Thu Jul 19 18:11:52 2018 +0300 @@ -34,6 +34,9 @@ NXT_BUILDDIR = build $(NXT_BUILDDIR)/njs_parser_expression.o \ $(NXT_BUILDDIR)/njs_generator.o \ $(NXT_BUILDDIR)/njs_disassembler.o \ + $(NXT_BUILDDIR)/nxt_diyfp.o \ + $(NXT_BUILDDIR)/nxt_dtoa.o \ + $(NXT_BUILDDIR)/nxt_strtod.o \ $(NXT_BUILDDIR)/nxt_djb_hash.o \ $(NXT_BUILDDIR)/nxt_utf8.o \ $(NXT_BUILDDIR)/nxt_array.o \ @@ -76,6 +79,9 @@ NXT_BUILDDIR = build $(NXT_BUILDDIR)/njs_parser_expression.o \ $(NXT_BUILDDIR)/njs_generator.o \ $(NXT_BUILDDIR)/njs_disassembler.o \ + $(NXT_BUILDDIR)/nxt_diyfp.o \ + $(NXT_BUILDDIR)/nxt_dtoa.o \ + $(NXT_BUILDDIR)/nxt_strtod.o \ $(NXT_BUILDDIR)/nxt_djb_hash.o \ $(NXT_BUILDDIR)/nxt_utf8.o \ $(NXT_BUILDDIR)/nxt_array.o \ diff -r 9322e8eab0b6 -r 0f9c060a0198 njs/njs_core.h --- a/njs/njs_core.h Wed Jul 18 15:41:55 2018 +0300 +++ b/njs/njs_core.h Thu Jul 19 18:11:52 2018 +0300 @@ -15,6 +15,8 @@ #include #include #include +#include +#include #include #include #include diff -r 9322e8eab0b6 -r 0f9c060a0198 njs/njs_json.c --- a/njs/njs_json.c Wed Jul 18 15:41:55 2018 +0300 +++ b/njs/njs_json.c Thu Jul 19 18:11:52 2018 +0300 @@ -1844,7 +1844,7 @@ njs_json_append_number(njs_json_stringif return NXT_ERROR; } - size = njs_num_to_buf(num, p, 64); + size = nxt_dtoa(num, (char *) p); njs_json_buf_written(stringify, size); } diff -r 9322e8eab0b6 -r 0f9c060a0198 njs/njs_number.c --- a/njs/njs_number.c Wed Jul 18 15:41:55 2018 +0300 +++ b/njs/njs_number.c Thu Jul 19 18:11:52 2018 +0300 @@ -66,91 +66,7 @@ njs_value_to_index(const njs_value_t *va double njs_number_dec_parse(const u_char **start, const u_char *end) { - u_char c; - double num, frac, scale, exponent; - nxt_bool_t minus; - const u_char *e, *p; - - p = *start; - - num = 0; - - while (p < end) { - /* Values less than '0' become >= 208. */ - c = *p - '0'; - - if (nxt_slow_path(c > 9)) { - break; - } - - num = num * 10 + c; - p++; - } - - if (p < end && *p == '.') { - - frac = 0; - scale = 1; - - for (p++; p < end; p++) { - /* Values less than '0' become >= 208. */ - c = *p - '0'; - - if (nxt_slow_path(c > 9)) { - break; - } - - frac = frac * 10 + c; - scale *= 10; - } - - num += frac / scale; - } - - e = p + 1; - - if (e < end && (*p == 'e' || *p == 'E')) { - minus = 0; - - if (e + 1 < end) { - if (*e == '-') { - e++; - minus = 1; - - } else if (*e == '+') { - e++; - } - } - - /* Values less than '0' become >= 208. */ - c = *e - '0'; - - if (nxt_fast_path(c <= 9)) { - exponent = c; - p = e + 1; - - while (p < end) { - /* Values less than '0' become >= 208. */ - c = *p - '0'; - - if (nxt_slow_path(c > 9)) { - break; - } - - exponent = exponent * 10 + c; - p++; - } - - if (num != 0) { - exponent = minus ? -exponent : exponent; - num = num * pow(10.0, exponent); - } - } - } - - *start = p; - - return num; + return nxt_strtod(start, end); } @@ -312,7 +228,7 @@ njs_number_to_string(njs_vm_t *vm, njs_v } } else { - size = njs_num_to_buf(num, buf, sizeof(buf)); + size = nxt_dtoa(num, (char *) buf); return njs_string_new(vm, string, buf, size, size); } @@ -323,34 +239,6 @@ njs_number_to_string(njs_vm_t *vm, njs_v } -size_t -njs_num_to_buf(double num, u_char *buf, size_t size) -{ - double n; - const char *fmt; - - n = fabs(num); - - if (n == 0) { - fmt = "%g"; - - } else if (n < 1) { - fmt = "%f"; - - } else if (n < 1000000) { - fmt = "%g"; - - } else if (n < 1e20) { - fmt = "%1.f"; - - } else { - fmt = "%1.e"; - } - - return snprintf((char *) buf, size, fmt, num); -} - - njs_ret_t njs_number_constructor(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused) diff -r 9322e8eab0b6 -r 0f9c060a0198 njs/njs_number.h --- a/njs/njs_number.h Wed Jul 18 15:41:55 2018 +0300 +++ b/njs/njs_number.h Thu Jul 19 18:11:52 2018 +0300 @@ -20,7 +20,6 @@ int64_t njs_number_radix_parse(const u_c uint8_t radix); njs_ret_t njs_number_to_string(njs_vm_t *vm, njs_value_t *string, const njs_value_t *number); -size_t njs_num_to_buf(double num, u_char *buf, size_t size); njs_ret_t njs_number_constructor(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused); njs_ret_t njs_number_global_is_nan(njs_vm_t *vm, njs_value_t *args, diff -r 9322e8eab0b6 -r 0f9c060a0198 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Wed Jul 18 15:41:55 2018 +0300 +++ b/njs/test/njs_unit_test.c Thu Jul 19 18:11:52 2018 +0300 @@ -93,19 +93,44 @@ static njs_unit_test_t njs_test[] = /* Numbers. */ + { nxt_string("0"), + nxt_string("0") }, + + { nxt_string("-0"), + nxt_string("-0") }, + + { nxt_string("0.1"), + nxt_string("0.1") }, + + { nxt_string("0.000001"), + nxt_string("0.000001") }, + + { nxt_string("0.00000123456"), + nxt_string("0.00000123456") }, + + { nxt_string("0.0000001"), + nxt_string("1e-7") }, + + { nxt_string("1.1000000"), + nxt_string("1.1") }, + + { nxt_string("99999999999999999999"), + nxt_string("100000000000000000000") }, + + { nxt_string("99999999999999999999.111"), + nxt_string("100000000000000000000") }, + { nxt_string("999999999999999999999"), nxt_string("1e+21") }, -#if 0 { nxt_string("9223372036854775808"), - nxt_string("9223372036854775808") }, + nxt_string("9223372036854776000") }, { nxt_string("18446744073709551616"), nxt_string("18446744073709552000") }, { nxt_string("1.7976931348623157E+308"), nxt_string("1.7976931348623157e+308") }, -#endif { nxt_string("+1"), nxt_string("1") }, @@ -223,16 +248,16 @@ static njs_unit_test_t njs_test[] = nxt_string("57") }, { nxt_string("5.7e-1"), - nxt_string("0.570000") }, + nxt_string("0.57") }, { nxt_string("-5.7e-1"), - nxt_string("-0.570000") }, + nxt_string("-0.57") }, { nxt_string("1.1e-01"), - nxt_string("0.110000") }, + nxt_string("0.11") }, { nxt_string("5.7e-2"), - nxt_string("0.057000") }, + nxt_string("0.057") }, { nxt_string("1.1e+01"), nxt_string("11") }, @@ -629,7 +654,7 @@ static njs_unit_test_t njs_test[] = nxt_string("NaN") }, { nxt_string("var a = 0.1; a **= -2"), - nxt_string("100") }, + nxt_string("99.99999999999999") }, { nxt_string("var a = 1; a **= NaN"), nxt_string("NaN") }, @@ -6210,6 +6235,24 @@ static njs_unit_test_t njs_test[] = { nxt_string("Number('123')"), nxt_string("123") }, + { nxt_string("Number('0.'+'1'.repeat(128))"), + nxt_string("0.1111111111111111") }, + + { nxt_string("Number('1'.repeat(128))"), + nxt_string("1.1111111111111113e+127") }, + + { nxt_string("Number('1'.repeat(129))"), + nxt_string("1.1111111111111112e+128") }, + + { nxt_string("Number('1'.repeat(129))"), + nxt_string("1.1111111111111112e+128") }, + + { nxt_string("Number('1'.repeat(129)+'e-100')"), + nxt_string("1.1111111111111112e+28") }, + + { nxt_string("Number('1'.repeat(310))"), + nxt_string("Infinity") }, + { nxt_string("var o = { valueOf: function() { return 123 } };" "Number(o)"), nxt_string("123") }, @@ -7530,7 +7573,7 @@ static njs_unit_test_t njs_test[] = /* Math. */ { nxt_string("Math.PI"), - nxt_string("3.14159") }, + nxt_string("3.141592653589793") }, { nxt_string("Math.abs()"), nxt_string("NaN") }, @@ -7788,8 +7831,8 @@ static njs_unit_test_t njs_test[] = { nxt_string("Math.cbrt(-Infinity)"), nxt_string("-Infinity") }, - { nxt_string("Math.cbrt('27')"), - nxt_string("3") }, + { nxt_string("(Math.cbrt('27') - 3) < 1e-15"), + nxt_string("true") }, { nxt_string("Math.cbrt(-1)"), nxt_string("-1") }, @@ -8570,10 +8613,10 @@ static njs_unit_test_t njs_test[] = nxt_string("57") }, { nxt_string("parseFloat('-5.7e-1')"), - nxt_string("-0.570000") }, + nxt_string("-0.57") }, { nxt_string("parseFloat('-5.e-1')"), - nxt_string("-0.500000") }, + nxt_string("-0.5") }, { nxt_string("parseFloat('5.7e+01')"), nxt_string("57") }, @@ -8582,7 +8625,7 @@ static njs_unit_test_t njs_test[] = nxt_string("57") }, { nxt_string("parseFloat('-5.7e-1abc')"), - nxt_string("-0.570000") }, + nxt_string("-0.57") }, { nxt_string("parseFloat('-5.7e')"), nxt_string("-5.7") }, @@ -8914,6 +8957,9 @@ static njs_unit_test_t njs_test[] = { nxt_string("JSON.stringify(123)"), nxt_string("123") }, + { nxt_string("JSON.stringify(0.00000123)"), + nxt_string("0.00000123") }, + { nxt_string("JSON.stringify(new Number(123))"), nxt_string("123") }, diff -r 9322e8eab0b6 -r 0f9c060a0198 nxt/Makefile --- a/nxt/Makefile Wed Jul 18 15:41:55 2018 +0300 +++ b/nxt/Makefile Thu Jul 19 18:11:52 2018 +0300 @@ -4,6 +4,9 @@ NXT_LIB = nxt $(NXT_BUILDDIR)/libnxt.a: \ $(NXT_LIB)/nxt_auto_config.h \ + $(NXT_BUILDDIR)/nxt_diyfp.o \ + $(NXT_BUILDDIR)/nxt_dtoa.o \ + $(NXT_BUILDDIR)/nxt_strtod.o \ $(NXT_BUILDDIR)/nxt_djb_hash.o \ $(NXT_BUILDDIR)/nxt_utf8.o \ $(NXT_BUILDDIR)/nxt_array.o \ @@ -20,6 +23,9 @@ NXT_LIB = nxt $(NXT_BUILDDIR)/nxt_mem_cache_pool.o \ ar -r -c $(NXT_BUILDDIR)/libnxt.a \ + $(NXT_BUILDDIR)/nxt_diyfp.o \ + $(NXT_BUILDDIR)/nxt_dtoa.o \ + $(NXT_BUILDDIR)/nxt_strtod.o \ $(NXT_BUILDDIR)/nxt_djb_hash.o \ $(NXT_BUILDDIR)/nxt_utf8.o \ $(NXT_BUILDDIR)/nxt_array.o \ @@ -34,6 +40,36 @@ NXT_LIB = nxt $(NXT_BUILDDIR)/nxt_trace.o \ $(NXT_BUILDDIR)/nxt_mem_cache_pool.o \ +$(NXT_BUILDDIR)/nxt_diyfp.o: \ + $(NXT_LIB)/nxt_types.h \ + $(NXT_LIB)/nxt_clang.h \ + $(NXT_LIB)/nxt_diyfp.h \ + $(NXT_LIB)/nxt_diyfp.c \ + + $(NXT_CC) -c -o $(NXT_BUILDDIR)/nxt_diyfp.o $(NXT_CFLAGS) \ + -I$(NXT_LIB) \ + $(NXT_LIB)/nxt_diyfp.c + +$(NXT_BUILDDIR)/nxt_dtoa.o: \ + $(NXT_LIB)/nxt_types.h \ + $(NXT_LIB)/nxt_clang.h \ + $(NXT_LIB)/nxt_dtoa.h \ + $(NXT_LIB)/nxt_dtoa.c \ + + $(NXT_CC) -c -o $(NXT_BUILDDIR)/nxt_dtoa.o $(NXT_CFLAGS) \ + -I$(NXT_LIB) \ + $(NXT_LIB)/nxt_dtoa.c + +$(NXT_BUILDDIR)/nxt_strtod.o: \ + $(NXT_LIB)/nxt_types.h \ + $(NXT_LIB)/nxt_clang.h \ + $(NXT_LIB)/nxt_strtod.h \ + $(NXT_LIB)/nxt_strtod.c \ + + $(NXT_CC) -c -o $(NXT_BUILDDIR)/nxt_strtod.o $(NXT_CFLAGS) \ + -I$(NXT_LIB) \ + $(NXT_LIB)/nxt_strtod.c + $(NXT_BUILDDIR)/nxt_murmur_hash.o: \ $(NXT_LIB)/nxt_types.h \ $(NXT_LIB)/nxt_clang.h \ diff -r 9322e8eab0b6 -r 0f9c060a0198 nxt/auto/clang --- a/nxt/auto/clang Wed Jul 18 15:41:55 2018 +0300 +++ b/nxt/auto/clang Thu Jul 19 18:11:52 2018 +0300 @@ -166,6 +166,18 @@ END # C language features. +nxt_feature="GCC unsigned __int128" +nxt_feature_name=NXT_HAVE_UNSIGNED_INT128 +nxt_feature_run=no +nxt_feature_incs= +nxt_feature_libs= +nxt_feature_test="int main(void) { + unsigned __int128 p = 0; + return (int) p; + }" +. ${NXT_AUTO}feature + + nxt_feature="GCC __builtin_expect()" nxt_feature_name=NXT_HAVE_BUILTIN_EXPECT nxt_feature_run=no @@ -217,6 +229,20 @@ nxt_feature_test="int main(void) { . ${NXT_AUTO}feature +nxt_feature="GCC __builtin_clzll()" +nxt_feature_name=NXT_HAVE_BUILTIN_CLZLL +nxt_feature_run=no +nxt_feature_incs= +nxt_feature_libs= +nxt_feature_test="int main(void) { + if (__builtin_clzll(1ULL) != 63) { + return 1; + } + return 0; + }" +. ${NXT_AUTO}feature + + nxt_feature="GCC __attribute__ visibility" nxt_feature_name=NXT_HAVE_GCC_ATTRIBUTE_VISIBILITY nxt_feature_run=no diff -r 9322e8eab0b6 -r 0f9c060a0198 nxt/nxt_clang.h --- a/nxt/nxt_clang.h Wed Jul 18 15:41:55 2018 +0300 +++ b/nxt/nxt_clang.h Thu Jul 19 18:11:52 2018 +0300 @@ -86,6 +86,38 @@ nxt_leading_zeros(uint32_t x) #endif +#if (NXT_HAVE_BUILTIN_CLZLL) +#define nxt_leading_zeros64(x) (((x) == 0) ? 64 : __builtin_clzll(x)) + +#else + +nxt_inline uint64_t +nxt_leading_zeros64(uint64_t x) +{ + uint64_t n; + + /* + * There is no sense to optimize this function, since almost + * all platforms nowadays support the built-in instruction. + */ + + if (x == 0) { + return 64; + } + + n = 0; + + while ((x & 0x8000000000000000) == 0) { + n++; + x <<= 1; + } + + return n; +} + +#endif + + #if (NXT_HAVE_GCC_ATTRIBUTE_VISIBILITY) #define NXT_EXPORT __attribute__((visibility("default"))) diff -r 9322e8eab0b6 -r 0f9c060a0198 nxt/nxt_diyfp.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nxt/nxt_diyfp.c Thu Jul 19 18:11:52 2018 +0300 @@ -0,0 +1,150 @@ + +/* + * Copyright (C) Dmitry Volyntsev + * Copyright (C) NGINX, Inc. + * + * An internal diy_fp implementation. + * For details, see Loitsch, Florian. "Printing floating-point numbers quickly + * and accurately with integers." ACM Sigplan Notices 45.6 (2010): 233-243. + */ + +#include +#include +#include +#include + + +typedef struct nxt_cpe_s { + uint64_t significand; + int16_t bin_exp; + int16_t dec_exp; +} nxt_cpe_t; + + +static const nxt_cpe_t nxt_cached_powers[] = { + { nxt_uint64(0xfa8fd5a0, 0x081c0288), -1220, -348 }, + { nxt_uint64(0xbaaee17f, 0xa23ebf76), -1193, -340 }, + { nxt_uint64(0x8b16fb20, 0x3055ac76), -1166, -332 }, + { nxt_uint64(0xcf42894a, 0x5dce35ea), -1140, -324 }, + { nxt_uint64(0x9a6bb0aa, 0x55653b2d), -1113, -316 }, + { nxt_uint64(0xe61acf03, 0x3d1a45df), -1087, -308 }, + { nxt_uint64(0xab70fe17, 0xc79ac6ca), -1060, -300 }, + { nxt_uint64(0xff77b1fc, 0xbebcdc4f), -1034, -292 }, + { nxt_uint64(0xbe5691ef, 0x416bd60c), -1007, -284 }, + { nxt_uint64(0x8dd01fad, 0x907ffc3c), -980, -276 }, + { nxt_uint64(0xd3515c28, 0x31559a83), -954, -268 }, + { nxt_uint64(0x9d71ac8f, 0xada6c9b5), -927, -260 }, + { nxt_uint64(0xea9c2277, 0x23ee8bcb), -901, -252 }, + { nxt_uint64(0xaecc4991, 0x4078536d), -874, -244 }, + { nxt_uint64(0x823c1279, 0x5db6ce57), -847, -236 }, + { nxt_uint64(0xc2109436, 0x4dfb5637), -821, -228 }, + { nxt_uint64(0x9096ea6f, 0x3848984f), -794, -220 }, + { nxt_uint64(0xd77485cb, 0x25823ac7), -768, -212 }, + { nxt_uint64(0xa086cfcd, 0x97bf97f4), -741, -204 }, + { nxt_uint64(0xef340a98, 0x172aace5), -715, -196 }, + { nxt_uint64(0xb23867fb, 0x2a35b28e), -688, -188 }, + { nxt_uint64(0x84c8d4df, 0xd2c63f3b), -661, -180 }, + { nxt_uint64(0xc5dd4427, 0x1ad3cdba), -635, -172 }, + { nxt_uint64(0x936b9fce, 0xbb25c996), -608, -164 }, + { nxt_uint64(0xdbac6c24, 0x7d62a584), -582, -156 }, + { nxt_uint64(0xa3ab6658, 0x0d5fdaf6), -555, -148 }, + { nxt_uint64(0xf3e2f893, 0xdec3f126), -529, -140 }, + { nxt_uint64(0xb5b5ada8, 0xaaff80b8), -502, -132 }, + { nxt_uint64(0x87625f05, 0x6c7c4a8b), -475, -124 }, + { nxt_uint64(0xc9bcff60, 0x34c13053), -449, -116 }, + { nxt_uint64(0x964e858c, 0x91ba2655), -422, -108 }, + { nxt_uint64(0xdff97724, 0x70297ebd), -396, -100 }, + { nxt_uint64(0xa6dfbd9f, 0xb8e5b88f), -369, -92 }, + { nxt_uint64(0xf8a95fcf, 0x88747d94), -343, -84 }, + { nxt_uint64(0xb9447093, 0x8fa89bcf), -316, -76 }, + { nxt_uint64(0x8a08f0f8, 0xbf0f156b), -289, -68 }, + { nxt_uint64(0xcdb02555, 0x653131b6), -263, -60 }, + { nxt_uint64(0x993fe2c6, 0xd07b7fac), -236, -52 }, + { nxt_uint64(0xe45c10c4, 0x2a2b3b06), -210, -44 }, + { nxt_uint64(0xaa242499, 0x697392d3), -183, -36 }, + { nxt_uint64(0xfd87b5f2, 0x8300ca0e), -157, -28 }, + { nxt_uint64(0xbce50864, 0x92111aeb), -130, -20 }, + { nxt_uint64(0x8cbccc09, 0x6f5088cc), -103, -12 }, + { nxt_uint64(0xd1b71758, 0xe219652c), -77, -4 }, + { nxt_uint64(0x9c400000, 0x00000000), -50, 4 }, + { nxt_uint64(0xe8d4a510, 0x00000000), -24, 12 }, + { nxt_uint64(0xad78ebc5, 0xac620000), 3, 20 }, + { nxt_uint64(0x813f3978, 0xf8940984), 30, 28 }, + { nxt_uint64(0xc097ce7b, 0xc90715b3), 56, 36 }, + { nxt_uint64(0x8f7e32ce, 0x7bea5c70), 83, 44 }, + { nxt_uint64(0xd5d238a4, 0xabe98068), 109, 52 }, + { nxt_uint64(0x9f4f2726, 0x179a2245), 136, 60 }, + { nxt_uint64(0xed63a231, 0xd4c4fb27), 162, 68 }, + { nxt_uint64(0xb0de6538, 0x8cc8ada8), 189, 76 }, + { nxt_uint64(0x83c7088e, 0x1aab65db), 216, 84 }, + { nxt_uint64(0xc45d1df9, 0x42711d9a), 242, 92 }, + { nxt_uint64(0x924d692c, 0xa61be758), 269, 100 }, + { nxt_uint64(0xda01ee64, 0x1a708dea), 295, 108 }, + { nxt_uint64(0xa26da399, 0x9aef774a), 322, 116 }, + { nxt_uint64(0xf209787b, 0xb47d6b85), 348, 124 }, + { nxt_uint64(0xb454e4a1, 0x79dd1877), 375, 132 }, + { nxt_uint64(0x865b8692, 0x5b9bc5c2), 402, 140 }, + { nxt_uint64(0xc83553c5, 0xc8965d3d), 428, 148 }, + { nxt_uint64(0x952ab45c, 0xfa97a0b3), 455, 156 }, + { nxt_uint64(0xde469fbd, 0x99a05fe3), 481, 164 }, + { nxt_uint64(0xa59bc234, 0xdb398c25), 508, 172 }, + { nxt_uint64(0xf6c69a72, 0xa3989f5c), 534, 180 }, + { nxt_uint64(0xb7dcbf53, 0x54e9bece), 561, 188 }, + { nxt_uint64(0x88fcf317, 0xf22241e2), 588, 196 }, + { nxt_uint64(0xcc20ce9b, 0xd35c78a5), 614, 204 }, + { nxt_uint64(0x98165af3, 0x7b2153df), 641, 212 }, + { nxt_uint64(0xe2a0b5dc, 0x971f303a), 667, 220 }, + { nxt_uint64(0xa8d9d153, 0x5ce3b396), 694, 228 }, + { nxt_uint64(0xfb9b7cd9, 0xa4a7443c), 720, 236 }, + { nxt_uint64(0xbb764c4c, 0xa7a44410), 747, 244 }, + { nxt_uint64(0x8bab8eef, 0xb6409c1a), 774, 252 }, + { nxt_uint64(0xd01fef10, 0xa657842c), 800, 260 }, + { nxt_uint64(0x9b10a4e5, 0xe9913129), 827, 268 }, + { nxt_uint64(0xe7109bfb, 0xa19c0c9d), 853, 276 }, + { nxt_uint64(0xac2820d9, 0x623bf429), 880, 284 }, + { nxt_uint64(0x80444b5e, 0x7aa7cf85), 907, 292 }, + { nxt_uint64(0xbf21e440, 0x03acdd2d), 933, 300 }, + { nxt_uint64(0x8e679c2f, 0x5e44ff8f), 960, 308 }, + { nxt_uint64(0xd433179d, 0x9c8cb841), 986, 316 }, + { nxt_uint64(0x9e19db92, 0xb4e31ba9), 1013, 324 }, + { nxt_uint64(0xeb96bf6e, 0xbadf77d9), 1039, 332 }, + { nxt_uint64(0xaf87023b, 0x9bf0ee6b), 1066, 340 }, +}; + + +#define NXT_D_1_LOG2_10 0.30102999566398114 /* 1 / log2(10). */ + + +nxt_diyfp_t +nxt_cached_power_dec(int exp, int *dec_exp) +{ + u_int index; + const nxt_cpe_t *cp; + + index = (exp + NXT_DECIMAL_EXPONENT_OFF) / NXT_DECIMAL_EXPONENT_DIST; + cp = &nxt_cached_powers[index]; + + *dec_exp = cp->dec_exp; + + return nxt_diyfp(cp->significand, cp->bin_exp); +} + + +nxt_diyfp_t +nxt_cached_power_bin(int exp, int *dec_exp) +{ + int k; + u_int index; + const nxt_cpe_t *cp; + + k = (int) ceil((-61 - exp) * NXT_D_1_LOG2_10) + + NXT_DECIMAL_EXPONENT_OFF - 1; + + index = (unsigned) (k >> 3) + 1; + + cp = &nxt_cached_powers[index]; + + *dec_exp = -(NXT_DECIMAL_EXPONENT_MIN + (int) (index << 3)); + + return nxt_diyfp(cp->significand, cp->bin_exp); +} diff -r 9322e8eab0b6 -r 0f9c060a0198 nxt/nxt_diyfp.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nxt/nxt_diyfp.h Thu Jul 19 18:11:52 2018 +0300 @@ -0,0 +1,212 @@ + +/* + * Copyright (C) Dmitry Volyntsev + * Copyright (C) NGINX, Inc. + * + * An internal diy_fp implementation. + * For details, see Loitsch, Florian. "Printing floating-point numbers quickly + * and accurately with integers." ACM Sigplan Notices 45.6 (2010): 233-243. + */ + +#ifndef _NXT_DIYFP_H_INCLUDED_ +#define _NXT_DIYFP_H_INCLUDED_ + +#include +#include + + +typedef struct { + uint64_t significand; + int exp; +} nxt_diyfp_t; + + +#define nxt_diyfp(_s, _e) (nxt_diyfp_t) \ + { .significand = (_s), .exp = (_e) } +#define nxt_uint64(h, l) (((uint64_t) (h) << 32) + (l)) + + +#define NXT_DBL_SIGNIFICAND_SIZE 52 +#define NXT_DBL_EXPONENT_BIAS (0x3FF + NXT_DBL_SIGNIFICAND_SIZE) +#define NXT_DBL_EXPONENT_MIN (-NXT_DBL_EXPONENT_BIAS) +#define NXT_DBL_EXPONENT_MAX (0x7FF - NXT_DBL_EXPONENT_BIAS) +#define NXT_DBL_EXPONENT_DENORMAL (-NXT_DBL_EXPONENT_BIAS + 1) + +#define NXT_DBL_SIGNIFICAND_MASK nxt_uint64(0x000FFFFF, 0xFFFFFFFF) +#define NXT_DBL_HIDDEN_BIT nxt_uint64(0x00100000, 0x00000000) +#define NXT_DBL_EXPONENT_MASK nxt_uint64(0x7FF00000, 0x00000000) + +#define NXT_DIYFP_SIGNIFICAND_SIZE 64 + +#define NXT_SIGNIFICAND_SIZE 53 +#define NXT_SIGNIFICAND_SHIFT (NXT_DIYFP_SIGNIFICAND_SIZE \ + - NXT_DBL_SIGNIFICAND_SIZE) + +#define NXT_DECIMAL_EXPONENT_OFF 348 +#define NXT_DECIMAL_EXPONENT_MIN (-348) +#define NXT_DECIMAL_EXPONENT_MAX 340 +#define NXT_DECIMAL_EXPONENT_DIST 8 + + +nxt_inline nxt_diyfp_t +nxt_d2diyfp(double d) +{ + int biased_exp; + uint64_t significand; + nxt_diyfp_t r; + + union { + double d; + uint64_t u64; + } u; + + u.d = d; + + biased_exp = (u.u64 & NXT_DBL_EXPONENT_MASK) >> NXT_DBL_SIGNIFICAND_SIZE; + significand = u.u64 & NXT_DBL_SIGNIFICAND_MASK; + + if (biased_exp != 0) { + r.significand = significand + NXT_DBL_HIDDEN_BIT; + r.exp = biased_exp - NXT_DBL_EXPONENT_BIAS; + + } else { + r.significand = significand; + r.exp = NXT_DBL_EXPONENT_MIN + 1; + } + + return r; +} + + +nxt_inline double +nxt_diyfp2d(nxt_diyfp_t v) +{ + int exp; + uint64_t significand, biased_exp; + + union { + double d; + uint64_t u64; + } u; + + exp = v.exp; + significand = v.significand; + + while (significand > NXT_DBL_HIDDEN_BIT + NXT_DBL_SIGNIFICAND_MASK) { + significand >>= 1; + exp++; + } + + if (exp >= NXT_DBL_EXPONENT_MAX) { + return INFINITY; + } + + if (exp < NXT_DBL_EXPONENT_DENORMAL) { + return 0.0; + } + + while (exp > NXT_DBL_EXPONENT_DENORMAL + && (significand & NXT_DBL_HIDDEN_BIT) == 0) + { + significand <<= 1; + exp--; + } + + if (exp == NXT_DBL_EXPONENT_DENORMAL + && (significand & NXT_DBL_HIDDEN_BIT) == 0) + { + biased_exp = 0; + + } else { + biased_exp = (uint64_t) (exp + NXT_DBL_EXPONENT_BIAS); + } + + u.u64 = (significand & NXT_DBL_SIGNIFICAND_MASK) + | (biased_exp << NXT_DBL_SIGNIFICAND_SIZE); + + return u.d; +} + + +nxt_inline nxt_diyfp_t +nxt_diyfp_shift_left(nxt_diyfp_t v, unsigned shift) +{ + return nxt_diyfp(v.significand << shift, v.exp - shift); +} + + +nxt_inline nxt_diyfp_t +nxt_diyfp_shift_right(nxt_diyfp_t v, unsigned shift) +{ + return nxt_diyfp(v.significand >> shift, v.exp + shift); +} + + +nxt_inline nxt_diyfp_t +nxt_diyfp_sub(nxt_diyfp_t lhs, nxt_diyfp_t rhs) +{ + return nxt_diyfp(lhs.significand - rhs.significand, lhs.exp); +} + + +nxt_inline nxt_diyfp_t +nxt_diyfp_mul(nxt_diyfp_t lhs, nxt_diyfp_t rhs) +{ +#if (NXT_HAVE_UNSIGNED_INT128) + + uint64_t l, h; + nxt_uint128_t u128; + + u128 = (nxt_uint128_t) (lhs.significand) + * (nxt_uint128_t) (rhs.significand); + + h = u128 >> 64; + l = (uint64_t) u128; + + /* rounding. */ + + if (l & ((uint64_t) 1 << 63)) { + h++; + } + + return nxt_diyfp(h, lhs.exp + rhs.exp + 64); + +#else + + uint64_t a, b, c, d, ac, bc, ad, bd, tmp; + + a = lhs.significand >> 32; + b = lhs.significand & 0xffffffff; + c = rhs.significand >> 32; + d = rhs.significand & 0xffffffff; + + ac = a * c; + bc = b * c; + ad = a * d; + bd = b * d; + + tmp = (bd >> 32) + (ad & 0xffffffff) + (bc & 0xffffffff); + + /* mult_round. */ + + tmp += 1U << 31; + + return nxt_diyfp(ac + (ad >> 32) + (bc >> 32) + (tmp >> 32), + lhs.exp + rhs.exp + 64); + +#endif +} + + +nxt_inline nxt_diyfp_t +nxt_diyfp_normalize(nxt_diyfp_t v) +{ + return nxt_diyfp_shift_left(v, nxt_leading_zeros64(v.significand)); +} + + +nxt_diyfp_t nxt_cached_power_dec(int exp, int *dec_exp); +nxt_diyfp_t nxt_cached_power_bin(int exp, int *dec_exp); + + +#endif /* _NXT_DIYFP_H_INCLUDED_ */ diff -r 9322e8eab0b6 -r 0f9c060a0198 nxt/nxt_dtoa.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nxt/nxt_dtoa.c Thu Jul 19 18:11:52 2018 +0300 @@ -0,0 +1,363 @@ + +/* + * Copyright (C) Dmitry Volyntsev + * Copyright (C) NGINX, Inc. + * + * Grisu2 algorithm implementation for printing floating-point numbers based + * upon the work of Milo Yip and Doug Currie. + * + * For algorithm information, see Loitsch, Florian. "Printing + * floating-point numbers quickly and accurately with integers." ACM Sigplan + * Notices 45.6 (2010): 233-243. + * + * Copyright (C) 2015 Doug Currie + * based on dtoa_milo.h + * Copyright (C) 2014 Milo Yip + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + + +nxt_inline void +nxt_grisu2_round(char *start, size_t len, uint64_t delta, uint64_t rest, + uint64_t ten_kappa, uint64_t wp_w) +{ + while (rest < wp_w && delta - rest >= ten_kappa + && (rest + ten_kappa < wp_w || /* closer */ + wp_w - rest > rest + ten_kappa - wp_w)) + { + start[len - 1]--; + rest += ten_kappa; + } +} + + +nxt_inline int +nxt_dec_count(uint32_t n) +{ + if (n < 10) return 1; + if (n < 100) return 2; + if (n < 1000) return 3; + if (n < 10000) return 4; + if (n < 100000) return 5; + if (n < 1000000) return 6; + if (n < 10000000) return 7; + if (n < 100000000) return 8; + if (n < 1000000000) return 9; + + return 10; +} + + +nxt_inline size_t +nxt_grisu2_gen(nxt_diyfp_t W, nxt_diyfp_t Mp, uint64_t delta, char *start, + int *dec_exp) +{ + int kappa; + char c, *p; + uint32_t p1, d; + uint64_t p2, tmp; + nxt_diyfp_t one, wp_w; + + static const uint64_t pow10[] = { + 1, + 10, + 100, + 1000, + 10000, + 100000, + 1000000, + 10000000, + 100000000, + 1000000000 + }; + + wp_w = nxt_diyfp_sub(Mp, W); + + one = nxt_diyfp((uint64_t) 1 << -Mp.exp, Mp.exp); + p1 = (uint32_t) (Mp.significand >> -one.exp); + p2 = Mp.significand & (one.significand - 1); + + p = start; + + kappa = nxt_dec_count(p1); + + while (kappa > 0) { + + switch (kappa) { + case 10: d = p1 / 1000000000; p1 %= 1000000000; break; + case 9: d = p1 / 100000000; p1 %= 100000000; break; + case 8: d = p1 / 10000000; p1 %= 10000000; break; + case 7: d = p1 / 1000000; p1 %= 1000000; break; + case 6: d = p1 / 100000; p1 %= 100000; break; + case 5: d = p1 / 10000; p1 %= 10000; break; + case 4: d = p1 / 1000; p1 %= 1000; break; + case 3: d = p1 / 100; p1 %= 100; break; + case 2: d = p1 / 10; p1 %= 10; break; + case 1: d = p1; p1 = 0; break; + default: + nxt_unreachable(); From xeioex at nginx.com Fri Jul 20 13:35:53 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Fri, 20 Jul 2018 13:35:53 +0000 Subject: [njs] Fixed compilation by gcc 4.2. Message-ID: details: http://hg.nginx.org/njs/rev/dc7cfa57a9f4 branches: changeset: 562:dc7cfa57a9f4 user: Dmitry Volyntsev date: Fri Jul 20 15:59:59 2018 +0300 description: Fixed compilation by gcc 4.2. diffstat: nxt/nxt_dtoa.c | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diffs (13 lines): diff -r 0f9c060a0198 -r dc7cfa57a9f4 nxt/nxt_dtoa.c --- a/nxt/nxt_dtoa.c Thu Jul 19 18:11:52 2018 +0300 +++ b/nxt/nxt_dtoa.c Fri Jul 20 15:59:59 2018 +0300 @@ -106,6 +106,9 @@ nxt_grisu2_gen(nxt_diyfp_t W, nxt_diyfp_ p = start; + /* GCC 4.2 complains about uninitialized d. */ + d = 0; + kappa = nxt_dec_count(p1); while (kappa > 0) { From xeioex at nginx.com Fri Jul 20 13:35:54 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Fri, 20 Jul 2018 13:35:54 +0000 Subject: [njs] Silenced Coverity false-positive warning (CID 1438046). Message-ID: details: http://hg.nginx.org/njs/rev/552da720e6e6 branches: changeset: 563:552da720e6e6 user: Dmitry Volyntsev date: Fri Jul 20 16:09:50 2018 +0300 description: Silenced Coverity false-positive warning (CID 1438046). diffstat: nxt/nxt_dtoa.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diffs (21 lines): diff -r dc7cfa57a9f4 -r 552da720e6e6 nxt/nxt_dtoa.c --- a/nxt/nxt_dtoa.c Fri Jul 20 15:59:59 2018 +0300 +++ b/nxt/nxt_dtoa.c Fri Jul 20 16:09:50 2018 +0300 @@ -280,7 +280,7 @@ nxt_prettify(char *start, size_t len, in /* 1234e7 -> 12340000000 */ if (kk - length > 0) { - memset(&start[length], '0', kk - length); + memset(&start[length], (int) '0', kk - length); } return kk; @@ -305,7 +305,7 @@ nxt_prettify(char *start, size_t len, in start[1] = '.'; if (offset - 2 > 0) { - memset(&start[2], '0', offset - 2); + memset(&start[2], (int) '0', offset - 2); } return (length + offset); From xeioex at nginx.com Fri Jul 20 17:11:25 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Fri, 20 Jul 2018 17:11:25 +0000 Subject: [njs] Improved help desrcription of njs shell. Message-ID: details: http://hg.nginx.org/njs/rev/d4697241f506 branches: changeset: 564:d4697241f506 user: Dmitry Volyntsev date: Fri Jul 20 20:11:02 2018 +0300 description: Improved help desrcription of njs shell. diffstat: njs/njs_core.h | 1 + njs/njs_shell.c | 26 +++++++++++++++++--------- nxt/auto/os | 1 + nxt/nxt_unix.h | 23 +++++++++++++++++++++++ 4 files changed, 42 insertions(+), 9 deletions(-) diffs (101 lines): diff -r 552da720e6e6 -r d4697241f506 njs/njs_core.h --- a/njs/njs_core.h Fri Jul 20 16:09:50 2018 +0300 +++ b/njs/njs_core.h Fri Jul 20 20:11:02 2018 +0300 @@ -9,6 +9,7 @@ #include +#include #include #include #include diff -r 552da720e6e6 -r d4697241f506 njs/njs_shell.c --- a/njs/njs_shell.c Fri Jul 20 16:09:50 2018 +0300 +++ b/njs/njs_shell.c Fri Jul 20 20:11:02 2018 +0300 @@ -150,6 +150,14 @@ njs_get_options(njs_opts_t *opts, int ar char *p; nxt_int_t i, ret; + static const char help[] = + "Interactive njs shell.\n" + "\n" + "Options:\n" + " -v print njs version and exit.\n" + " -d print disassembled code.\n" + " | - run code from a file or stdin.\n"; + ret = NXT_DONE; for (i = 1; i < argc; i++) { @@ -165,24 +173,24 @@ njs_get_options(njs_opts_t *opts, int ar p++; switch (*p) { + case '?': + case 'h': + (void) write(STDIN_FILENO, help, nxt_length(help)); + return ret; + case 'd': opts->disassemble = 1; break; + case 'v': case 'V': opts->version = 1; break; default: - fprintf(stderr, "Unknown argument: \"%s\"\n", argv[i]); - ret = NXT_ERROR; - - /* Fall through. */ - - case 'h': - case '?': - printf("Usage: %s [|-] [-dV]\n", argv[0]); - return ret; + fprintf(stderr, "Unknown argument: \"%s\" " + "try \"%s -h\" for available options\n", argv[i], argv[0]); + return NXT_ERROR; } } diff -r 552da720e6e6 -r d4697241f506 nxt/auto/os --- a/nxt/auto/os Fri Jul 20 16:09:50 2018 +0300 +++ b/nxt/auto/os Fri Jul 20 20:11:02 2018 +0300 @@ -9,6 +9,7 @@ NXT_SYSTEM=`uname -s 2>/dev/null` case "$NXT_SYSTEM" in Linux) + nxt_define=NXT_LINUX . ${NXT_AUTO}define NXT_SYSTEM_VERSION=`uname -r 2>/dev/null` # Linux uname -p can return "unknown". NXT_SYSTEM_PLATFORM=`uname -m 2>/dev/null` diff -r 552da720e6e6 -r d4697241f506 nxt/nxt_unix.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nxt/nxt_unix.h Fri Jul 20 20:11:02 2018 +0300 @@ -0,0 +1,23 @@ + +/* + * Copyright (C) Dmitry Volyntsev + * Copyright (C) NGINX, Inc. + */ + + +#ifndef _NXT_UNIX_H_INCLUDED_ +#define _NXT_UNIX_H_INCLUDED_ + +#if (NXT_LINUX) + +#ifdef _FORTIFY_SOURCE +/* + * _FORTIFY_SOURCE + * does not allow to use "(void) write()"; + */ +#undef _FORTIFY_SOURCE +#endif + +#endif /* NXT_LINUX */ + +#endif /* _NXT_UNIX_H_INCLUDED_ */ From fudoshiki.ari at gmail.com Sat Jul 21 15:20:19 2018 From: fudoshiki.ari at gmail.com (Yuri S. (sharevari)) Date: Sat, 21 Jul 2018 20:20:19 +0500 Subject: Add option for configure SSL_CTX_set_ciphersuites (TLS 1.3) References: <7B47A663-3541-4B36-B9DE-601F02AB4679@gmail.com> Message-ID: <88AEC7AD-02CE-441A-995C-42774288CE1B@gmail.com> https://github.com/ssllabs/ssllabs-scan/issues/636#issuecomment-404197571 -------------- next part -------------- An HTML attachment was scrubbed... URL: From mdounin at mdounin.ru Sat Jul 21 16:35:00 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Sat, 21 Jul 2018 19:35:00 +0300 Subject: Add option for configure SSL_CTX_set_ciphersuites (TLS 1.3) In-Reply-To: <88AEC7AD-02CE-441A-995C-42774288CE1B@gmail.com> References: <7B47A663-3541-4B36-B9DE-601F02AB4679@gmail.com> <88AEC7AD-02CE-441A-995C-42774288CE1B@gmail.com> Message-ID: <20180721163500.GQ56558@mdounin.ru> Hello! On Sat, Jul 21, 2018 at 08:20:19PM +0500, Yuri S. (sharevari) wrote: > https://github.com/ssllabs/ssllabs-scan/issues/636#issuecomment-404197571 https://trac.nginx.org/nginx/ticket/1529 -- Maxim Dounin http://mdounin.ru/ From devnexen at gmail.com Sat Jul 21 20:26:47 2018 From: devnexen at gmail.com (David CARLIER) Date: Sat, 21 Jul 2018 21:26:47 +0100 Subject: [PATCH] ngx_thread_id openbsd specific Message-ID: Hi, Here a patch proposal to use specific getthrid function instead of the generic pthread_self. Thanks. Kind regards. -------------- next part -------------- A non-text attachment was scrubbed... Name: patch-ngx_thread_id.diff Type: application/octet-stream Size: 1249 bytes Desc: not available URL: From mdounin at mdounin.ru Sun Jul 22 00:59:18 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Sun, 22 Jul 2018 03:59:18 +0300 Subject: [PATCH] ngx_thread_id openbsd specific In-Reply-To: References: Message-ID: <20180722005918.GR56558@mdounin.ru> Hello! On Sat, Jul 21, 2018 at 09:26:47PM +0100, David CARLIER wrote: > Here a patch proposal to use specific getthrid function instead of the > generic pthread_self. You may be more specific about reasons to use getthrid() instead of pthread_self(). Also, it looks like OpenBSD does not have EVFILT_USER, so compiling nginx with threads support is meaningless anyway. See also http://nginx.org/en/docs/contributing_changes.html for some hints on how to submit patches. > diff -r 6649d4433266 auto/os/conf > --- a/auto/os/conf Wed Jul 18 18:51:25 2018 +0300 > +++ b/auto/os/conf Sat Jul 21 21:24:26 2018 +0100 > @@ -27,6 +27,15 @@ > . auto/os/win32 > ;; > > + OpenBSD:*) > + have=NGX_OPENBSD . auto/have_headers > + CORE_INCS="$UNIX_INCS" > + CORE_DEPS="$UNIX_DEPS $POSIX_DEPS" > + CORE_SRCS="$UNIX_SRCS" > + > + NGX_RPATH=YES This instructs nginx to use rpath on OpenBSD. Are there any reasons to do this? Normally we do not use rpath unless the OS cannot load libraries from their standard locations itself, and it looks like OpenBSD can do this just fine. > + ;; > + > DragonFly:*) > have=NGX_FREEBSD . auto/have_headers > CORE_INCS="$UNIX_INCS" > diff -r 6649d4433266 src/os/unix/ngx_thread.h > --- a/src/os/unix/ngx_thread.h Wed Jul 18 18:51:25 2018 +0300 > +++ b/src/os/unix/ngx_thread.h Sat Jul 21 21:24:26 2018 +0100 > @@ -44,6 +44,11 @@ > typedef uint32_t ngx_tid_t; > #define NGX_TID_T_FMT "%uD" > > +#elif (NGX_OPENBSD) > + > +typedef int64_t ngx_tid_t; This defines ngx_tid_t to int64_t, while getthrid() is expected to return pid_t, see https://man.openbsd.org/getthrid.2. Are there any specific reasons to use int64_t instead of pid_t? > +#define NGX_TID_T_FMT "%lD" This format specification means that nginx will us a signed long argument, followed by the "D" character. Unlikely this is what you mean here. For pid_t, the "%P" format should be used. (BTW, thanks, the format specification for uint64_t as used now looks wrong too, it should be "%uL" instead of "%uA". I'll take care of this.) > + > #elif (NGX_DARWIN) > > typedef uint64_t ngx_tid_t; > diff -r 6649d4433266 src/os/unix/ngx_thread_id.c > --- a/src/os/unix/ngx_thread_id.c Wed Jul 18 18:51:25 2018 +0300 > +++ b/src/os/unix/ngx_thread_id.c Sat Jul 21 21:24:26 2018 +0100 > @@ -33,6 +33,14 @@ > return pthread_getthreadid_np(); > } > > +#elif (NGX_OPENBSD) > + > +ngx_tid_t > +ngx_thread_tid(void) > +{ > + return getthrid(); > +} > + > #elif (NGX_DARWIN) > > /* -- Maxim Dounin http://mdounin.ru/ From xeioex at nginx.com Mon Jul 23 13:35:48 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Mon, 23 Jul 2018 13:35:48 +0000 Subject: [njs] Backed out changeset 552da720e6e6. Message-ID: details: http://hg.nginx.org/njs/rev/b1d34de39abd branches: changeset: 565:b1d34de39abd user: Dmitry Volyntsev date: Mon Jul 23 16:35:32 2018 +0300 description: Backed out changeset 552da720e6e6. The original code was correct, the (int) casting does not change anything because the type of the '0' literal is int. The solution to the original problem is to mark CID 1438046 as false-positive. diffstat: nxt/nxt_dtoa.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diffs (21 lines): diff -r d4697241f506 -r b1d34de39abd nxt/nxt_dtoa.c --- a/nxt/nxt_dtoa.c Fri Jul 20 20:11:02 2018 +0300 +++ b/nxt/nxt_dtoa.c Mon Jul 23 16:35:32 2018 +0300 @@ -280,7 +280,7 @@ nxt_prettify(char *start, size_t len, in /* 1234e7 -> 12340000000 */ if (kk - length > 0) { - memset(&start[length], (int) '0', kk - length); + memset(&start[length], '0', kk - length); } return kk; @@ -305,7 +305,7 @@ nxt_prettify(char *start, size_t len, in start[1] = '.'; if (offset - 2 > 0) { - memset(&start[2], (int) '0', offset - 2); + memset(&start[2], '0', offset - 2); } return (length + offset); From mp.ardhanareeswaran at oracle.com Mon Jul 23 14:45:05 2018 From: mp.ardhanareeswaran at oracle.com (M.P. Ardhanareeswaran) Date: Mon, 23 Jul 2018 10:45:05 -0400 Subject: Routing to a certain worker Message-ID: <5CC7A079-32E6-476F-854E-E04702A9A6FE@oracle.com> All: I am new to NGINX handler development. I see that NGINX can have multiple workers accepting connections on the same port. Is it possible to route the requests to a module but in a CERTAIN worker? I am exploring ways to implement a REST database API in a module. Initially, an application can do a POST to create a database connection and it can go to any worker. I can return a URI in Location header. Subsequent operations on this database connection has to go the same worker. Is this possible? With regards, M.P. Ardhanareeswaran From mdounin at mdounin.ru Mon Jul 23 14:46:38 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Mon, 23 Jul 2018 17:46:38 +0300 Subject: Routing to a certain worker In-Reply-To: <5CC7A079-32E6-476F-854E-E04702A9A6FE@oracle.com> References: <5CC7A079-32E6-476F-854E-E04702A9A6FE@oracle.com> Message-ID: <20180723144638.GX56558@mdounin.ru> Hello! On Mon, Jul 23, 2018 at 10:45:05AM -0400, M.P. Ardhanareeswaran wrote: > I see that NGINX can have multiple workers accepting connections > on the same port. > > Is it possible to route the requests to a module but in a > CERTAIN worker? > > I am exploring ways to implement a REST database API in a > module. Initially, an application can do a POST to create a > database connection and it can go to any worker. I can return a > URI in Location header. Subsequent operations on this database > connection has to go the same worker. > > Is this possible? No. -- Maxim Dounin http://mdounin.ru/ From xeioex at nginx.com Mon Jul 23 15:05:15 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Mon, 23 Jul 2018 15:05:15 +0000 Subject: [njs] Restricted usage of r.subrequest() and r.parent. Message-ID: details: http://hg.nginx.org/njs/rev/673d8a9c92e2 branches: changeset: 566:673d8a9c92e2 user: Dmitry Volyntsev date: Mon Jul 23 18:04:53 2018 +0300 description: Restricted usage of r.subrequest() and r.parent. Thanks to ??? (Hong Zhi Dao). diffstat: nginx/ngx_http_js_module.c | 22 ++++++++++++++++------ 1 files changed, 16 insertions(+), 6 deletions(-) diffs (56 lines): diff -r b1d34de39abd -r 673d8a9c92e2 nginx/ngx_http_js_module.c --- a/nginx/ngx_http_js_module.c Mon Jul 23 16:35:32 2018 +0300 +++ b/nginx/ngx_http_js_module.c Mon Jul 23 18:04:53 2018 +0300 @@ -1825,7 +1825,7 @@ ngx_http_js_ext_get_response(njs_vm_t *v ctx = ngx_http_get_module_ctx(r, ngx_http_js_module); - njs_vm_retval_set(ctx->vm, njs_value_arg(&ctx->args[1])); + njs_vm_retval_set(vm, njs_value_arg(&ctx->args[1])); return NJS_OK; } @@ -1840,6 +1840,7 @@ ngx_http_js_ext_subrequest(njs_vm_t *vm, ngx_uint_t cb_index, method, n, has_body; njs_value_t *arg2, *options, *value; njs_function_t *callback; + ngx_http_js_ctx_t *ctx; ngx_http_request_t *r, *sr; ngx_http_request_body_t *rb; @@ -1875,6 +1876,14 @@ ngx_http_js_ext_subrequest(njs_vm_t *vm, r = njs_value_data(njs_argument(args, 0)); + ctx = ngx_http_get_module_ctx(r, ngx_http_js_module); + + if (ctx->vm != vm) { + njs_vm_error(vm, "subrequest can only be created for " + "the primary request"); + return NJS_ERROR; + } + if (njs_vm_value_to_ext_string(vm, &uri_arg, njs_argument(args, 1), 0) == NJS_ERROR) { @@ -2150,14 +2159,15 @@ ngx_http_js_ext_get_parent(njs_vm_t *vm, r = (ngx_http_request_t *) obj; - ctx = ngx_http_get_module_ctx(r->parent, ngx_http_js_module); - - if (ctx == NULL) { - njs_vm_error(vm, "failed to get the parent context"); + ctx = r->parent ? ngx_http_get_module_ctx(r->parent, ngx_http_js_module) + : NULL; + + if (ctx == NULL || ctx->vm != vm) { + njs_vm_error(vm, "parent can only be returned for a subrequest"); return NJS_ERROR; } - njs_vm_retval_set(ctx->vm, njs_value_arg(&ctx->args[0])); + njs_vm_retval_set(vm, njs_value_arg(&ctx->args[0])); return NJS_OK; } From mp.ardhanareeswaran at oracle.com Mon Jul 23 15:24:30 2018 From: mp.ardhanareeswaran at oracle.com (M.P. Ardhanareeswaran) Date: Mon, 23 Jul 2018 11:24:30 -0400 Subject: Routing to a certain worker In-Reply-To: <20180723144638.GX56558@mdounin.ru> References: <5CC7A079-32E6-476F-854E-E04702A9A6FE@oracle.com> <20180723144638.GX56558@mdounin.ru> Message-ID: Maxim: I am developing a customer, HTTP client application. So the only choice for me, it appears, is to reuse the initial connection (which is persistent) for subsequent operations. Do you see issues there? (I will have clean up issues in the worker if the client application disappears.) With regards, > On Jul 23, 2018, at 10:46 AM, Maxim Dounin wrote: > > Hello! > > On Mon, Jul 23, 2018 at 10:45:05AM -0400, M.P. Ardhanareeswaran wrote: > >> I see that NGINX can have multiple workers accepting connections >> on the same port. >> >> Is it possible to route the requests to a module but in a >> CERTAIN worker? >> >> I am exploring ways to implement a REST database API in a >> module. Initially, an application can do a POST to create a >> database connection and it can go to any worker. I can return a >> URI in Location header. Subsequent operations on this database >> connection has to go the same worker. >> >> Is this possible? > > No. > > -- > Maxim Dounin > https://urldefense.proofpoint.com/v2/url?u=http-3A__mdounin.ru_&d=DwICAg&c=RoP1YumCXCgaWHvlZYR8PZh8Bv7qIrMUB65eapI_JnE&r=c0nJ6OcgTgcBV2N1F7_XcSoSai9fe2ao0-El70rew7s&m=B5ky0Ml5nLkSWmhca2mPQyNNegMAMQNqIKQLeI7JGe0&s=RCnG0nkB-3mTFbLYg97PgrgUuhwb3Bq31b_39q60kks&e= > _______________________________________________ > nginx-devel mailing list > nginx-devel at nginx.org > https://urldefense.proofpoint.com/v2/url?u=http-3A__mailman.nginx.org_mailman_listinfo_nginx-2Ddevel&d=DwICAg&c=RoP1YumCXCgaWHvlZYR8PZh8Bv7qIrMUB65eapI_JnE&r=c0nJ6OcgTgcBV2N1F7_XcSoSai9fe2ao0-El70rew7s&m=B5ky0Ml5nLkSWmhca2mPQyNNegMAMQNqIKQLeI7JGe0&s=1kWrYmRexAC_JXWb8zbVSQvQkfmAw73Dy5egPAJ_1UQ&e= From mdounin at mdounin.ru Mon Jul 23 15:34:23 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Mon, 23 Jul 2018 18:34:23 +0300 Subject: Routing to a certain worker In-Reply-To: References: <5CC7A079-32E6-476F-854E-E04702A9A6FE@oracle.com> <20180723144638.GX56558@mdounin.ru> Message-ID: <20180723153422.GY56558@mdounin.ru> Hello! On Mon, Jul 23, 2018 at 11:24:30AM -0400, M.P. Ardhanareeswaran wrote: > I am developing a customer, HTTP client application. So the > only choice for me, it appears, is to reuse the initial > connection (which is persistent) for subsequent operations. Do > you see issues there? Yes. Any attempt to rely on a connection being persistent contradicts stateless nature of HTTP, and doing so will cause problems. For example, we've all seen how Microsoft's NTLM authentication fails to work through proxy servers. Don't repeat this mistake. Worker processes are expected to be equal, and if you need a particular worker process to handle further requests for some reason - you may want to rethink the architecture. -- Maxim Dounin http://mdounin.ru/ From mdounin at mdounin.ru Mon Jul 23 15:36:47 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Mon, 23 Jul 2018 15:36:47 +0000 Subject: [nginx] Fixed NGX_TID_T_FMT format specification for uint64_t. Message-ID: details: http://hg.nginx.org/nginx/rev/d230c797b168 branches: changeset: 7323:d230c797b168 user: Maxim Dounin date: Sun Jul 22 04:03:40 2018 +0300 description: Fixed NGX_TID_T_FMT format specification for uint64_t. Previously, "%uA" was used, which corresponds to ngx_atomic_uint_t. Size of ngx_atomic_uint_t can be easily different from uint64_t, leading to undefined results. diffstat: src/os/unix/ngx_thread.h | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diffs (18 lines): diff --git a/src/os/unix/ngx_thread.h b/src/os/unix/ngx_thread.h --- a/src/os/unix/ngx_thread.h +++ b/src/os/unix/ngx_thread.h @@ -47,12 +47,12 @@ typedef uint32_t ngx_tid_t; #elif (NGX_DARWIN) typedef uint64_t ngx_tid_t; -#define NGX_TID_T_FMT "%uA" +#define NGX_TID_T_FMT "%uL" #else typedef uint64_t ngx_tid_t; -#define NGX_TID_T_FMT "%uA" +#define NGX_TID_T_FMT "%uL" #endif From mp.ardhanareeswaran at oracle.com Mon Jul 23 17:53:21 2018 From: mp.ardhanareeswaran at oracle.com (M.P. Ardhanareeswaran) Date: Mon, 23 Jul 2018 13:53:21 -0400 Subject: Routing to a certain worker In-Reply-To: <20180723153422.GY56558@mdounin.ru> References: <5CC7A079-32E6-476F-854E-E04702A9A6FE@oracle.com> <20180723144638.GX56558@mdounin.ru> <20180723153422.GY56558@mdounin.ru> Message-ID: <22120AF0-7B53-4FB2-8D55-3EB1041453DF@oracle.com> Maxim: Thanks for your indulgence. I understand the desire for worker processes to be symmetric. ProxyPass and upstream allow sticky session/session affinity which does introduce some skew though mighty useful IMHO. Do you have any thoughts about use of this? I am very new to handler development in NGINX. It appears that the handlers cannot do this and is heavily discouraged. With regards, > On Jul 23, 2018, at 11:34 AM, Maxim Dounin wrote: > > > Worker processes are expected to be equal, and if you need a > particular worker process to handle further requests for some > reason - you may want to rethink the architecture. -------------- next part -------------- An HTML attachment was scrubbed... URL: From mdounin at mdounin.ru Mon Jul 23 19:15:06 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Mon, 23 Jul 2018 22:15:06 +0300 Subject: Routing to a certain worker In-Reply-To: <22120AF0-7B53-4FB2-8D55-3EB1041453DF@oracle.com> References: <5CC7A079-32E6-476F-854E-E04702A9A6FE@oracle.com> <20180723144638.GX56558@mdounin.ru> <20180723153422.GY56558@mdounin.ru> <22120AF0-7B53-4FB2-8D55-3EB1041453DF@oracle.com> Message-ID: <20180723191506.GA56558@mdounin.ru> Hello! On Mon, Jul 23, 2018 at 01:53:21PM -0400, M.P. Ardhanareeswaran wrote: > I understand the desire for worker processes to be symmetric. > > ProxyPass and upstream allow sticky session/session affinity > which does introduce some skew though mighty useful IMHO. > > Do you have any thoughts about use of this? > > I am very new to handler development in NGINX. It appears that > the handlers cannot do this and is heavily discouraged. Normally, if a module needs some information to be shared between worker processes, it uses shared memory zones: http://nginx.org/en/docs/dev/development_guide.html#shared_memory Sticky sessions use shared memory and therefore do not introduce any inequalities between worker processes. Many other modules, such as limit_conn and limit_req, do the same. Unfortunately, your particular case as you've described it is different, as you are trying to open a database connection and keep it open for future requests. Unless a connection is statless and can be re-opened on demand, this is won't be something possible to implement within nginx worker model, because there are no mechanisms to share connections between worker processes. -- Maxim Dounin http://mdounin.ru/ From mdounin at mdounin.ru Tue Jul 24 13:15:25 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 24 Jul 2018 13:15:25 +0000 Subject: [nginx] nginx-1.15.2-RELEASE Message-ID: details: http://hg.nginx.org/nginx/rev/b234199c7ed8 branches: changeset: 7324:b234199c7ed8 user: Maxim Dounin date: Tue Jul 24 16:10:59 2018 +0300 description: nginx-1.15.2-RELEASE diffstat: docs/xml/nginx/changes.xml | 86 ++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 86 insertions(+), 0 deletions(-) diffs (96 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,92 @@ + + + + +?????????? $ssl_preread_protocol +? ?????? ngx_stream_ssl_preread_module. + + +the $ssl_preread_protocol variable +in the ngx_stream_ssl_preread_module. + + + + + +?????? ??? ????????????? ????????? reset_timedout_connection +nginx ?????????? ??????????, ??????????? ? ????? 444. + + +now when using the "reset_timedout_connection" directive +nginx will reset connections being closed with the 444 code. + + + + + +??????? ???????????? ?????? SSL "http request", "https proxy request", +"unsupported protocol" ? "version too low" +??????? ? ?????? crit ?? info. + + +a logging level of the "http request", "https proxy request", +"unsupported protocol", and "version too low" SSL errors +has been lowered from "crit" to "info". + + + + + +??????? ? DNS-??????? ?? ???????????? ????????, +???? ??? ?????? ??????? ???????? ??????????? ??????. + + +DNS requests were not resent +if initial sending of a request failed. + + + + + +???????? reuseport ????????? listen ?????????????, +???? ?????????? ??????? ????????? ???? ?????? ????? ????????? listen. + + +the "reuseport" parameter of the "listen" directive was ignored +if the number of worker processes was specified after the "listen" directive. + + + + + +??? ????????????? OpenSSL 1.1.0 ? ????? +????????? ssl_prefer_server_ciphers ?????? ???? ????????? +? ??????????? ???????, ???? ??? ???? ???????? ? ??????? ?? ?????????. + + +when using OpenSSL 1.1.0 or newer +it was not possible to switch off "ssl_prefer_server_ciphers" in +a virtual server if it was switched on in the default server. + + + + + +????????? ????????????? SSL-?????? ? ???????? +?? ???????? ? ?????????? TLS 1.3. + + +SSL session reuse with upstream servers +did not work with the TLS 1.3 protocol. + + + + + + From mdounin at mdounin.ru Tue Jul 24 13:15:27 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 24 Jul 2018 13:15:27 +0000 Subject: [nginx] release-1.15.2 tag Message-ID: details: http://hg.nginx.org/nginx/rev/6a86f6f10798 branches: changeset: 7325:6a86f6f10798 user: Maxim Dounin date: Tue Jul 24 16:11:00 2018 +0300 description: release-1.15.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 @@ -427,3 +427,4 @@ 64179f242cb55fc206bca59de9bfdc4cf5ebcec7 051e5fa03b92b8a564f6b12debd483d267391e82 release-1.13.12 990b3e885636d763b97ed02d0d2cfc161a4e0c09 release-1.15.0 4189160cb946bb38d0bc0a452b5eb4cdd8979fb5 release-1.15.1 +b234199c7ed8a156a6bb98f7ff58302c857c954f release-1.15.2 From xeioex at nginx.com Tue Jul 24 15:31:48 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Tue, 24 Jul 2018 15:31:48 +0000 Subject: [njs] Fixed typo in njs_arg_type_string() for NJS_DATE_ARG. Message-ID: details: http://hg.nginx.org/njs/rev/a4e5abdc345d branches: changeset: 567:a4e5abdc345d user: Dmitry Volyntsev date: Tue Jul 24 18:29:25 2018 +0300 description: Fixed typo in njs_arg_type_string() for NJS_DATE_ARG. diffstat: njs/njs_vm.c | 2 +- njs/test/njs_unit_test.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diffs (24 lines): diff -r 673d8a9c92e2 -r a4e5abdc345d njs/njs_vm.c --- a/njs/njs_vm.c Mon Jul 23 18:04:53 2018 +0300 +++ b/njs/njs_vm.c Tue Jul 24 18:29:25 2018 +0300 @@ -2441,7 +2441,7 @@ njs_arg_type_string(uint8_t arg) return "regexp"; case NJS_DATE_ARG: - return "regexp"; + return "date"; default: return "unknown"; diff -r 673d8a9c92e2 -r a4e5abdc345d njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Mon Jul 23 18:04:53 2018 +0300 +++ b/njs/test/njs_unit_test.c Tue Jul 24 18:29:25 2018 +0300 @@ -7518,7 +7518,7 @@ static njs_unit_test_t njs_test[] = nxt_string("true") }, { nxt_string("[0].map(new Date().getDate)"), - nxt_string("TypeError: cannot convert void to regexp") }, + nxt_string("TypeError: cannot convert void to date") }, { nxt_string("new Date(eval)"), nxt_string("Invalid Date") }, From pluknet at nginx.com Tue Jul 24 15:49:58 2018 From: pluknet at nginx.com (Sergey Kandaurov) Date: Tue, 24 Jul 2018 15:49:58 +0000 Subject: [nginx] Version bump. Message-ID: details: http://hg.nginx.org/nginx/rev/308819020438 branches: changeset: 7326:308819020438 user: Sergey Kandaurov date: Tue Jul 24 18:46:18 2018 +0300 description: Version bump. diffstat: src/core/nginx.h | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diffs (14 lines): diff -r 6a86f6f10798 -r 308819020438 src/core/nginx.h --- a/src/core/nginx.h Tue Jul 24 16:11:00 2018 +0300 +++ b/src/core/nginx.h Tue Jul 24 18:46:18 2018 +0300 @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1015002 -#define NGINX_VERSION "1.15.2" +#define nginx_version 1015003 +#define NGINX_VERSION "1.15.3" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD From pluknet at nginx.com Tue Jul 24 15:50:00 2018 From: pluknet at nginx.com (Sergey Kandaurov) Date: Tue, 24 Jul 2018 15:50:00 +0000 Subject: [nginx] Configure: fixed compiler warnings with "-Wall -Wextra". Message-ID: details: http://hg.nginx.org/nginx/rev/f7e79596baf2 branches: changeset: 7327:f7e79596baf2 user: Sergey Kandaurov date: Tue Jul 24 18:46:54 2018 +0300 description: Configure: fixed compiler warnings with "-Wall -Wextra". diffstat: auto/lib/google-perftools/conf | 3 ++- auto/lib/libgd/conf | 6 ++++-- auto/lib/libxslt/conf | 4 ++-- auto/os/linux | 2 ++ 4 files changed, 10 insertions(+), 5 deletions(-) diffs (62 lines): diff -r 308819020438 -r f7e79596baf2 auto/lib/google-perftools/conf --- a/auto/lib/google-perftools/conf Tue Jul 24 18:46:18 2018 +0300 +++ b/auto/lib/google-perftools/conf Tue Jul 24 18:46:54 2018 +0300 @@ -9,7 +9,8 @@ ngx_feature_incs= ngx_feature_path= ngx_feature_libs="-lprofiler" - ngx_feature_test="ProfilerStop()" + ngx_feature_test="void ProfilerStop(void); + ProfilerStop()" . auto/feature diff -r 308819020438 -r f7e79596baf2 auto/lib/libgd/conf --- a/auto/lib/libgd/conf Tue Jul 24 18:46:18 2018 +0300 +++ b/auto/lib/libgd/conf Tue Jul 24 18:46:54 2018 +0300 @@ -9,7 +9,8 @@ ngx_feature_incs="#include " ngx_feature_path= ngx_feature_libs="-lgd" - ngx_feature_test="gdImagePtr img = gdImageCreateFromGifPtr(1, NULL);" + ngx_feature_test="gdImagePtr img = gdImageCreateFromGifPtr(1, NULL); + (void) img" . auto/feature @@ -76,7 +77,8 @@ if [ $ngx_found = yes ]; then ngx_feature="GD WebP support" ngx_feature_name="NGX_HAVE_GD_WEBP" - ngx_feature_test="gdImagePtr img = gdImageCreateFromWebpPtr(1, NULL);" + ngx_feature_test="gdImagePtr img = gdImageCreateFromWebpPtr(1, NULL); + (void) img" . auto/feature else diff -r 308819020438 -r f7e79596baf2 auto/lib/libxslt/conf --- a/auto/lib/libxslt/conf Tue Jul 24 18:46:18 2018 +0300 +++ b/auto/lib/libxslt/conf Tue Jul 24 18:46:54 2018 +0300 @@ -16,8 +16,8 @@ ngx_feature_libs="-lxml2 -lxslt" ngx_feature_test="xmlParserCtxtPtr ctxt = NULL; xsltStylesheetPtr sheet = NULL; - xmlDocPtr doc; - doc = xmlParseChunk(ctxt, NULL, 0, 0); + xmlDocPtr doc = NULL; + xmlParseChunk(ctxt, NULL, 0, 0); xsltApplyStylesheet(sheet, doc, NULL);" . auto/feature diff -r 308819020438 -r f7e79596baf2 auto/os/linux --- a/auto/os/linux Tue Jul 24 18:46:18 2018 +0300 +++ b/auto/os/linux Tue Jul 24 18:46:54 2018 +0300 @@ -185,6 +185,8 @@ ngx_feature_test="struct __user_cap_data data.effective = CAP_TO_MASK(CAP_NET_RAW); data.permitted = 0; + (void) header; + (void) data; (void) SYS_capset" . auto/feature From vbart at nginx.com Tue Jul 24 16:33:18 2018 From: vbart at nginx.com (Valentin Bartenev) Date: Tue, 24 Jul 2018 16:33:18 +0000 Subject: [njs] Fixed configure process with non-default locale. Message-ID: details: http://hg.nginx.org/njs/rev/7ccf9c0a412a branches: changeset: 568:7ccf9c0a412a user: Valentin Bartenev date: Tue Jul 24 19:25:39 2018 +0300 description: Fixed configure process with non-default locale. Overriding LANG might not work, since it has less precedence than LC_* settings. LC_ALL has the highest precedence. diffstat: configure | 4 ++-- nxt/auto/configure | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diffs (28 lines): diff -r a4e5abdc345d -r 7ccf9c0a412a configure --- a/configure Tue Jul 24 18:29:25 2018 +0300 +++ b/configure Tue Jul 24 19:25:39 2018 +0300 @@ -5,8 +5,8 @@ # Disable localized program messages. -LANG=C -export LANG +LC_ALL=C +export LC_ALL # Stop on error exit status. set -e diff -r a4e5abdc345d -r 7ccf9c0a412a nxt/auto/configure --- a/nxt/auto/configure Tue Jul 24 18:29:25 2018 +0300 +++ b/nxt/auto/configure Tue Jul 24 19:25:39 2018 +0300 @@ -5,8 +5,8 @@ # Disable localized program messages. -LANG=C -export LANG +LC_ALL=C +export LC_ALL # Stop on error exit status. set -e From igor at sysoev.ru Tue Jul 24 17:09:09 2018 From: igor at sysoev.ru (Igor Sysoev) Date: Tue, 24 Jul 2018 17:09:09 +0000 Subject: [njs] Removed artifacts left after changeset 25bd2742a18b. Message-ID: details: http://hg.nginx.org/njs/rev/8960cef1cd5f branches: changeset: 569:8960cef1cd5f user: Igor Sysoev date: Tue Jul 24 19:50:02 2018 +0300 description: Removed artifacts left after changeset 25bd2742a18b. diffstat: njs/njs_vm.c | 17 +++++------------ 1 files changed, 5 insertions(+), 12 deletions(-) diffs (50 lines): diff -r 7ccf9c0a412a -r 8960cef1cd5f njs/njs_vm.c --- a/njs/njs_vm.c Tue Jul 24 19:25:39 2018 +0300 +++ b/njs/njs_vm.c Tue Jul 24 19:50:02 2018 +0300 @@ -43,7 +43,7 @@ static njs_ret_t njs_function_frame_free static void njs_vm_trap(njs_vm_t *vm, nxt_uint_t trap, njs_value_t *value1, njs_value_t *value2); -static njs_ret_t njs_vm_trap_argument(njs_vm_t *vm, nxt_uint_t trap); +static void njs_vm_trap_argument(njs_vm_t *vm, nxt_uint_t trap); static njs_ret_t njs_vmcode_number_primitive(njs_vm_t *vm, njs_value_t *invld, njs_value_t *narg); static njs_ret_t njs_vmcode_string_primitive(njs_vm_t *vm, njs_value_t *invld, @@ -188,12 +188,9 @@ start: case NJS_TRAP_NUMBER_ARG: case NJS_TRAP_STRING_ARG: - ret = njs_vm_trap_argument(vm, ret - NJS_TRAP_BASE); - if (nxt_fast_path(ret == NXT_OK)) { - goto start; - } - - break; + njs_vm_trap_argument(vm, ret - NJS_TRAP_BASE); + + goto start; default: break; @@ -2875,7 +2872,7 @@ njs_vm_trap(njs_vm_t *vm, nxt_uint_t tra } -static njs_ret_t +static void njs_vm_trap_argument(njs_vm_t *vm, nxt_uint_t trap) { njs_value_t *value; @@ -2888,12 +2885,8 @@ njs_vm_trap_argument(njs_vm_t *vm, nxt_u frame->trap_values[1].data.u.value = value; frame->trap_values[0] = *value; - njs_set_invalid(&frame->trap_scratch); - frame->trap_restart = vm->current; vm->current = (u_char *) njs_vm_traps[trap].code; - - return NXT_OK; } From igor at sysoev.ru Tue Jul 24 17:09:09 2018 From: igor at sysoev.ru (Igor Sysoev) Date: Tue, 24 Jul 2018 17:09:09 +0000 Subject: [njs] Fixed addition operator applied to an object. Message-ID: details: http://hg.nginx.org/njs/rev/766fcec15744 branches: changeset: 571:766fcec15744 user: Igor Sysoev date: Tue Jul 24 19:50:02 2018 +0300 description: Fixed addition operator applied to an object. This fixes #36 issue on Github. diffstat: njs/njs_vm.c | 190 +++++++++++++++++++++++++++++++++++++--------- njs/njs_vm.h | 3 +- njs/test/njs_unit_test.c | 6 + 3 files changed, 160 insertions(+), 39 deletions(-) diffs (314 lines): diff -r 69300ba58603 -r 766fcec15744 njs/njs_vm.c --- a/njs/njs_vm.c Tue Jul 24 19:50:02 2018 +0300 +++ b/njs/njs_vm.c Tue Jul 24 19:50:02 2018 +0300 @@ -23,6 +23,8 @@ struct njs_property_next_s { * and should fit in CPU L1 instruction cache. */ +static nxt_noinline njs_ret_t njs_string_concat(njs_vm_t *vm, + njs_value_t *val1, njs_value_t *val2); static njs_ret_t njs_method_private_copy(njs_vm_t *vm, njs_property_query_t *pq); static nxt_noinline njs_ret_t njs_values_equal(njs_vm_t *vm, @@ -48,6 +50,10 @@ static njs_ret_t njs_vmcode_number_primi njs_value_t *narg); static njs_ret_t njs_vmcode_string_primitive(njs_vm_t *vm, njs_value_t *invld, njs_value_t *narg); +static njs_ret_t njs_vmcode_addition_primitive(njs_vm_t *vm, njs_value_t *invld, + njs_value_t *narg); +static njs_ret_t njs_vmcode_comparison_primitive(njs_vm_t *vm, + njs_value_t *invld, njs_value_t *narg); static njs_ret_t njs_vmcode_number_argument(njs_vm_t *vm, njs_value_t *invld1, njs_value_t *inlvd2); static njs_ret_t njs_vmcode_string_argument(njs_vm_t *vm, njs_value_t *invld1, @@ -181,7 +187,8 @@ start: /* Fall through. */ case NJS_TRAP_NUMBERS: - case NJS_TRAP_STRINGS: + case NJS_TRAP_ADDITION: + case NJS_TRAP_COMPARISON: case NJS_TRAP_INCDEC: case NJS_TRAP_PROPERTY: @@ -1301,10 +1308,9 @@ njs_vmcode_unary_negation(njs_vm_t *vm, njs_ret_t njs_vmcode_addition(njs_vm_t *vm, njs_value_t *val1, njs_value_t *val2) { - double num; - u_char *start; - size_t size, length; - njs_string_prop_t string1, string2; + double num; + njs_ret_t ret; + njs_value_t *s1, *s2, *src, dst; if (nxt_fast_path(njs_is_numeric(val1) && njs_is_numeric(val2))) { @@ -1315,34 +1321,70 @@ njs_vmcode_addition(njs_vm_t *vm, njs_va } if (nxt_fast_path(njs_is_string(val1) && njs_is_string(val2))) { - - (void) njs_string_prop(&string1, val1); - (void) njs_string_prop(&string2, val2); - - if ((string1.length != 0 || string1.size == 0) - && (string2.length != 0 || string2.size == 0)) - { - length = string1.length + string2.length; + return njs_string_concat(vm, val1, val2); + } + + if (nxt_fast_path(njs_is_primitive(val1) && njs_is_primitive(val2))) { + + if (njs_is_string(val1)) { + s1 = val1; + s2 = &dst; + src = val2; } else { - length = 0; + s1 = &dst; + s2 = val2; + src = val1; + } + + ret = njs_primitive_value_to_string(vm, &dst, src); + + if (nxt_fast_path(ret == NXT_OK)) { + return njs_string_concat(vm, s1, s2); } - size = string1.size + string2.size; - - start = njs_string_alloc(vm, &vm->retval, size, length); - - if (nxt_slow_path(start == NULL)) { - return NXT_ERROR; - } - - (void) memcpy(start, string1.start, string1.size); - (void) memcpy(start + string1.size, string2.start, string2.size); - - return sizeof(njs_vmcode_3addr_t); + return ret; } - return njs_trap(vm, NJS_TRAP_STRINGS); + return njs_trap(vm, NJS_TRAP_ADDITION); +} + + +static nxt_noinline njs_ret_t +njs_string_concat(njs_vm_t *vm, njs_value_t *val1, njs_value_t *val2) +{ + u_char *start; + size_t size, length; + njs_string_prop_t string1, string2; + + (void) njs_string_prop(&string1, val1); + (void) njs_string_prop(&string2, val2); + + /* + * A result of concatenation of Byte and ASCII or UTF-8 strings + * is a Byte string. + */ + if ((string1.length != 0 || string1.size == 0) + && (string2.length != 0 || string2.size == 0)) + { + length = string1.length + string2.length; + + } else { + length = 0; + } + + size = string1.size + string2.size; + + start = njs_string_alloc(vm, &vm->retval, size, length); + + if (nxt_slow_path(start == NULL)) { + return NXT_ERROR; + } + + (void) memcpy(start, string1.start, string1.size); + (void) memcpy(start + string1.size, string2.start, string2.size); + + return sizeof(njs_vmcode_3addr_t); } @@ -1778,7 +1820,7 @@ njs_values_compare(njs_vm_t *vm, const n return (njs_string_cmp(val1, val2) < 0) ? 1 : 0; } - return njs_trap(vm, NJS_TRAP_STRINGS); + return njs_trap(vm, NJS_TRAP_COMPARISON); } @@ -2781,15 +2823,11 @@ njs_vmcode_finally(njs_vm_t *vm, njs_val } -static const njs_vmcode_1addr_t njs_trap_strings[] = { - { .code = { .operation = njs_vmcode_string_primitive, +static const njs_vmcode_1addr_t njs_trap_number[] = { + { .code = { .operation = njs_vmcode_number_primitive, .operands = NJS_VMCODE_1OPERAND, .retval = NJS_VMCODE_NO_RETVAL }, .index = 0 }, - { .code = { .operation = njs_vmcode_string_primitive, - .operands = NJS_VMCODE_1OPERAND, - .retval = NJS_VMCODE_NO_RETVAL }, - .index = 1 }, { .code = { .operation = njs_vmcode_restart, .operands = NJS_VMCODE_NO_OPERAND, .retval = NJS_VMCODE_NO_RETVAL } }, @@ -2811,11 +2849,41 @@ static const njs_vmcode_1addr_t njs_tra }; -static const njs_vmcode_1addr_t njs_trap_number[] = { - { .code = { .operation = njs_vmcode_number_primitive, +static const njs_vmcode_1addr_t njs_trap_addition[] = { + { .code = { .operation = njs_vmcode_addition_primitive, .operands = NJS_VMCODE_1OPERAND, .retval = NJS_VMCODE_NO_RETVAL }, .index = 0 }, + { .code = { .operation = njs_vmcode_addition_primitive, + .operands = NJS_VMCODE_1OPERAND, + .retval = NJS_VMCODE_NO_RETVAL }, + .index = 1 }, + { .code = { .operation = njs_vmcode_restart, + .operands = NJS_VMCODE_NO_OPERAND, + .retval = NJS_VMCODE_NO_RETVAL } }, +}; + + +static const njs_vmcode_1addr_t njs_trap_comparison[] = { + { .code = { .operation = njs_vmcode_comparison_primitive, + .operands = NJS_VMCODE_1OPERAND, + .retval = NJS_VMCODE_NO_RETVAL }, + .index = 0 }, + { .code = { .operation = njs_vmcode_comparison_primitive, + .operands = NJS_VMCODE_1OPERAND, + .retval = NJS_VMCODE_NO_RETVAL }, + .index = 1 }, + { .code = { .operation = njs_vmcode_restart, + .operands = NJS_VMCODE_NO_OPERAND, + .retval = NJS_VMCODE_NO_RETVAL } }, +}; + + +static const njs_vmcode_1addr_t njs_trap_property[] = { + { .code = { .operation = njs_vmcode_string_primitive, + .operands = NJS_VMCODE_1OPERAND, + .retval = NJS_VMCODE_NO_RETVAL }, + .index = 1 }, { .code = { .operation = njs_vmcode_restart, .operands = NJS_VMCODE_NO_OPERAND, .retval = NJS_VMCODE_NO_RETVAL } }, @@ -2839,10 +2907,11 @@ static const njs_vmcode_1addr_t njs_tra static const njs_vm_trap_t njs_vm_traps[] = { /* NJS_TRAP_NUMBER */ { .code = &njs_trap_number[0] }, /* NJS_TRAP_NUMBERS */ { .code = &njs_trap_numbers[0] }, + /* NJS_TRAP_ADDITION */ { .code = &njs_trap_addition[0] }, + /* NJS_TRAP_COMPARISON */ { .code = &njs_trap_comparison[0] }, /* NJS_TRAP_INCDEC */ { .code = &njs_trap_numbers[1], .reference = 1 }, - /* NJS_TRAP_STRINGS */ { .code = &njs_trap_strings[0] }, - /* NJS_TRAP_PROPERTY */ { .code = &njs_trap_strings[1] }, + /* NJS_TRAP_PROPERTY */ { .code = &njs_trap_property[0] }, /* NJS_TRAP_NUMBER_ARG */ { .code = &njs_trap_number_argument }, /* NJS_TRAP_STRING_ARG */ { .code = &njs_trap_string_argument }, }; @@ -2951,6 +3020,51 @@ njs_vmcode_string_primitive(njs_vm_t *vm static njs_ret_t +njs_vmcode_addition_primitive(njs_vm_t *vm, njs_value_t *invld, + njs_value_t *narg) +{ + njs_ret_t ret; + nxt_uint_t hint; + njs_value_t *value; + + value = &vm->top_frame->trap_values[(uintptr_t) narg]; + + /* + * ECMAScript 5.1: + * Date should return String, other types sould return Number. + */ + hint = njs_is_date(value); + + ret = njs_primitive_value(vm, value, hint); + + if (nxt_fast_path(ret > 0)) { + return sizeof(njs_vmcode_1addr_t); + } + + return ret; +} + + +static njs_ret_t +njs_vmcode_comparison_primitive(njs_vm_t *vm, njs_value_t *invld, + njs_value_t *narg) +{ + njs_ret_t ret; + njs_value_t *value; + + value = &vm->top_frame->trap_values[(uintptr_t) narg]; + + ret = njs_primitive_value(vm, value, 0); + + if (nxt_fast_path(ret > 0)) { + return sizeof(njs_vmcode_1addr_t); + } + + return ret; +} + + +static njs_ret_t njs_vmcode_number_argument(njs_vm_t *vm, njs_value_t *invld1, njs_value_t *inlvd2) { diff -r 69300ba58603 -r 766fcec15744 njs/njs_vm.h --- a/njs/njs_vm.h Tue Jul 24 19:50:02 2018 +0300 +++ b/njs/njs_vm.h Tue Jul 24 19:50:02 2018 +0300 @@ -41,8 +41,9 @@ typedef enum { NJS_TRAP_NUMBER = 0, NJS_TRAP_NUMBERS, + NJS_TRAP_ADDITION, + NJS_TRAP_COMPARISON, NJS_TRAP_INCDEC, - NJS_TRAP_STRINGS, NJS_TRAP_PROPERTY, NJS_TRAP_NUMBER_ARG, NJS_TRAP_STRING_ARG, diff -r 69300ba58603 -r 766fcec15744 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Tue Jul 24 19:50:02 2018 +0300 +++ b/njs/test/njs_unit_test.c Tue Jul 24 19:50:02 2018 +0300 @@ -386,6 +386,9 @@ static njs_unit_test_t njs_test[] = " toString: function() { return '1' } }; +a"), nxt_string("1") }, + { nxt_string("var a = { valueOf: function() { return 1 } }; ''+a"), + nxt_string("1") }, + { nxt_string("var a = { valueOf: function() { return [] }," " toString: function() { return '1' } }; +a"), nxt_string("1") }, @@ -7159,6 +7162,9 @@ static njs_unit_test_t njs_test[] = { nxt_string("var d = new Date(''); d +' '+ d.getTime()"), nxt_string("Invalid Date NaN") }, + { nxt_string("var d = new Date(1); d = d + ''; d.slice(0, 33)"), + nxt_string("Thu Jan 01 1970 12:45:00 GMT+1245") }, + { nxt_string("var d = new Date(1308895200000); d.getTime()"), nxt_string("1308895200000") }, From igor at sysoev.ru Tue Jul 24 17:09:09 2018 From: igor at sysoev.ru (Igor Sysoev) Date: Tue, 24 Jul 2018 17:09:09 +0000 Subject: [njs] Refactored trap infrastructure. Message-ID: details: http://hg.nginx.org/njs/rev/69300ba58603 branches: changeset: 570:69300ba58603 user: Igor Sysoev date: Tue Jul 24 19:50:02 2018 +0300 description: Refactored trap infrastructure. This change allows to introduce virtually unlimited number of traps. diffstat: njs/njs_array.c | 5 +- njs/njs_date.c | 6 +- njs/njs_math.c | 8 +- njs/njs_object.c | 6 +- njs/njs_string.c | 8 +- njs/njs_vm.c | 162 ++++++++++++++++++++++++++++-------------------------- njs/njs_vm.h | 32 +++++++--- 7 files changed, 126 insertions(+), 101 deletions(-) diffs (658 lines): diff -r 8960cef1cd5f -r 69300ba58603 njs/njs_array.c --- a/njs/njs_array.c Tue Jul 24 19:50:02 2018 +0300 +++ b/njs/njs_array.c Tue Jul 24 19:50:02 2018 +0300 @@ -917,7 +917,7 @@ njs_array_prototype_join_continuation(nj if (!njs_is_string(value)) { njs_vm_trap_value(vm, value); - return NJS_TRAP_STRING_ARG; + return njs_trap(vm, NJS_TRAP_STRING_ARG); } } @@ -1952,7 +1952,8 @@ njs_array_string_sort(njs_vm_t *vm, njs_ for (i = 1; i < nargs; i++) { if (!njs_is_string(&args[i])) { njs_vm_trap_value(vm, &args[i]); - return NJS_TRAP_STRING_ARG; + + return njs_trap(vm, NJS_TRAP_STRING_ARG); } } diff -r 8960cef1cd5f -r 69300ba58603 njs/njs_date.c --- a/njs/njs_date.c Tue Jul 24 19:50:02 2018 +0300 +++ b/njs/njs_date.c Tue Jul 24 19:50:02 2018 +0300 @@ -90,7 +90,8 @@ njs_date_constructor(njs_vm_t *vm, njs_v for (i = 1; i < n; i++) { if (!njs_is_numeric(&args[i])) { njs_vm_trap_value(vm, &args[i]); - return NJS_TRAP_NUMBER_ARG; + + return njs_trap(vm, NJS_TRAP_NUMBER_ARG); } num = args[i].data.u.number; @@ -170,7 +171,8 @@ njs_date_utc(njs_vm_t *vm, njs_value_t * for (i = 1; i < n; i++) { if (!njs_is_numeric(&args[i])) { njs_vm_trap_value(vm, &args[i]); - return NJS_TRAP_NUMBER_ARG; + + return njs_trap(vm, NJS_TRAP_NUMBER_ARG); } num = args[i].data.u.number; diff -r 8960cef1cd5f -r 69300ba58603 njs/njs_math.c --- a/njs/njs_math.c Tue Jul 24 19:50:02 2018 +0300 +++ b/njs/njs_math.c Tue Jul 24 19:50:02 2018 +0300 @@ -365,7 +365,7 @@ njs_object_math_hypot(njs_vm_t *vm, njs_ if (!njs_is_numeric(&args[i])) { njs_vm_trap_value(vm, &args[i]); - return NJS_TRAP_NUMBER_ARG; + return njs_trap(vm, NJS_TRAP_NUMBER_ARG); } } @@ -504,7 +504,8 @@ njs_object_math_max(njs_vm_t *vm, njs_va for (i = 1; i < nargs; i++) { if (!njs_is_numeric(&args[i])) { njs_vm_trap_value(vm, &args[i]); - return NJS_TRAP_NUMBER_ARG; + + return njs_trap(vm, NJS_TRAP_NUMBER_ARG); } } @@ -535,7 +536,8 @@ njs_object_math_min(njs_vm_t *vm, njs_va for (i = 1; i < nargs; i++) { if (!njs_is_numeric(&args[i])) { njs_vm_trap_value(vm, &args[i]); - return NJS_TRAP_NUMBER_ARG; + + return njs_trap(vm, NJS_TRAP_NUMBER_ARG); } } diff -r 8960cef1cd5f -r 69300ba58603 njs/njs_object.c --- a/njs/njs_object.c Tue Jul 24 19:50:02 2018 +0300 +++ b/njs/njs_object.c Tue Jul 24 19:50:02 2018 +0300 @@ -227,7 +227,7 @@ njs_object_property(njs_vm_t *vm, const * NJS_STRING_VALUE property operation was applied to a string, * NJS_ARRAY_VALUE object is array, * NJS_EXTERNAL_VALUE object is external entity, - * NJS_TRAP_PROPERTY the property trap must be called, + * NJS_TRAP the property trap must be called, * NXT_ERROR exception has been thrown. */ @@ -275,7 +275,7 @@ njs_property_query(njs_vm_t *vm, njs_pro } } else { - return NJS_TRAP_PROPERTY; + return njs_trap(vm, NJS_TRAP_PROPERTY); } } @@ -359,7 +359,7 @@ njs_property_query(njs_vm_t *vm, njs_pro return ret; } - return NJS_TRAP_PROPERTY; + return njs_trap(vm, NJS_TRAP_PROPERTY); } diff -r 8960cef1cd5f -r 69300ba58603 njs/njs_string.c --- a/njs/njs_string.c Tue Jul 24 19:50:02 2018 +0300 +++ b/njs/njs_string.c Tue Jul 24 19:50:02 2018 +0300 @@ -842,7 +842,7 @@ njs_string_prototype_concat(njs_vm_t *vm if (!njs_is_string(&args[i])) { njs_vm_trap_value(vm, &args[i]); - return NJS_TRAP_STRING_ARG; + return njs_trap(vm, NJS_TRAP_STRING_ARG); } } @@ -1427,7 +1427,8 @@ njs_string_bytes_from_array(njs_vm_t *vm for (i = 0; i < length; i++) { if (!njs_is_numeric(&array->start[i])) { njs_vm_trap_value(vm, &array->start[i]); - return NJS_TRAP_NUMBER_ARG; + + return njs_trap(vm, NJS_TRAP_NUMBER_ARG); } } @@ -1659,7 +1660,8 @@ njs_string_from_char_code(njs_vm_t *vm, for (i = 1; i < nargs; i++) { if (!njs_is_numeric(&args[i])) { njs_vm_trap_value(vm, &args[i]); - return NJS_TRAP_NUMBER_ARG; + + return njs_trap(vm, NJS_TRAP_NUMBER_ARG); } } diff -r 8960cef1cd5f -r 69300ba58603 njs/njs_vm.c --- a/njs/njs_vm.c Tue Jul 24 19:50:02 2018 +0300 +++ b/njs/njs_vm.c Tue Jul 24 19:50:02 2018 +0300 @@ -25,10 +25,10 @@ struct njs_property_next_s { static njs_ret_t njs_method_private_copy(njs_vm_t *vm, njs_property_query_t *pq); -static nxt_noinline njs_ret_t njs_values_equal(const njs_value_t *val1, - const njs_value_t *val2); -static nxt_noinline njs_ret_t njs_values_compare(const njs_value_t *val1, - const njs_value_t *val2); +static nxt_noinline njs_ret_t njs_values_equal(njs_vm_t *vm, + const njs_value_t *val1, const njs_value_t *val2); +static nxt_noinline njs_ret_t njs_values_compare(njs_vm_t *vm, + const njs_value_t *val1, const njs_value_t *val2); static njs_ret_t njs_function_frame_create(njs_vm_t *vm, njs_value_t *value, const njs_value_t *this, uintptr_t nargs, nxt_bool_t ctor); static njs_object_t *njs_function_new_object(njs_vm_t *vm, njs_value_t *value); @@ -41,9 +41,9 @@ static njs_native_frame_t * static njs_ret_t njs_function_frame_free(njs_vm_t *vm, njs_native_frame_t *frame); -static void njs_vm_trap(njs_vm_t *vm, nxt_uint_t trap, njs_value_t *value1, +static void njs_vm_trap(njs_vm_t *vm, njs_trap_t trap, njs_value_t *value1, njs_value_t *value2); -static void njs_vm_trap_argument(njs_vm_t *vm, nxt_uint_t trap); +static void njs_vm_trap_argument(njs_vm_t *vm, njs_trap_t trap); static njs_ret_t njs_vmcode_number_primitive(njs_vm_t *vm, njs_value_t *invld, njs_value_t *narg); static njs_ret_t njs_vmcode_string_primitive(njs_vm_t *vm, njs_value_t *invld, @@ -105,6 +105,7 @@ njs_vmcode_interpreter(njs_vm_t *vm) { u_char *catch; njs_ret_t ret; + njs_trap_t trap; njs_value_t *retval, *value1, *value2; njs_frame_t *frame; njs_native_frame_t *previous; @@ -169,31 +170,36 @@ start: } } - switch (ret) { - - case NJS_TRAP_NUMBER: - value2 = value1; - - /* Fall through. */ - - case NJS_TRAP_NUMBERS: - case NJS_TRAP_STRINGS: - case NJS_TRAP_INCDEC: - case NJS_TRAP_PROPERTY: - - njs_vm_trap(vm, ret - NJS_TRAP_BASE, value1, value2); - - goto start; - - case NJS_TRAP_NUMBER_ARG: - case NJS_TRAP_STRING_ARG: - - njs_vm_trap_argument(vm, ret - NJS_TRAP_BASE); - - goto start; - - default: - break; + if (ret == NJS_TRAP) { + trap = vm->trap; + + switch (trap) { + + case NJS_TRAP_NUMBER: + value2 = value1; + + /* Fall through. */ + + case NJS_TRAP_NUMBERS: + case NJS_TRAP_STRINGS: + case NJS_TRAP_INCDEC: + case NJS_TRAP_PROPERTY: + + njs_vm_trap(vm, trap, value1, value2); + + goto start; + + case NJS_TRAP_NUMBER_ARG: + case NJS_TRAP_STRING_ARG: + + njs_vm_trap_argument(vm, trap); + + goto start; + + default: + ret = NXT_ERROR; + break; + } } if (ret == NXT_ERROR) { @@ -593,7 +599,7 @@ njs_vmcode_property_get(njs_vm_t *vm, nj return sizeof(njs_vmcode_prop_get_t); - case NJS_TRAP_PROPERTY: + case NJS_TRAP: case NXT_ERROR: default: @@ -715,7 +721,7 @@ njs_vmcode_property_set(njs_vm_t *vm, nj return sizeof(njs_vmcode_prop_set_t); - case NJS_TRAP_PROPERTY: + case NJS_TRAP: case NXT_ERROR: default: @@ -799,7 +805,7 @@ njs_vmcode_property_in(njs_vm_t *vm, njs break; - case NJS_TRAP_PROPERTY: + case NJS_TRAP: case NXT_ERROR: default: @@ -901,7 +907,7 @@ njs_vmcode_property_delete(njs_vm_t *vm, break; - case NJS_TRAP_PROPERTY: + case NJS_TRAP: case NXT_ERROR: default: @@ -1130,7 +1136,7 @@ njs_vmcode_increment(njs_vm_t *vm, njs_v return sizeof(njs_vmcode_3addr_t); } - return NJS_TRAP_INCDEC; + return njs_trap(vm, NJS_TRAP_INCDEC); } @@ -1150,7 +1156,7 @@ njs_vmcode_decrement(njs_vm_t *vm, njs_v return sizeof(njs_vmcode_3addr_t); } - return NJS_TRAP_INCDEC; + return njs_trap(vm, NJS_TRAP_INCDEC); } @@ -1171,7 +1177,7 @@ njs_vmcode_post_increment(njs_vm_t *vm, return sizeof(njs_vmcode_3addr_t); } - return NJS_TRAP_INCDEC; + return njs_trap(vm, NJS_TRAP_INCDEC); } @@ -1192,7 +1198,7 @@ njs_vmcode_post_decrement(njs_vm_t *vm, return sizeof(njs_vmcode_3addr_t); } - return NJS_TRAP_INCDEC; + return njs_trap(vm, NJS_TRAP_INCDEC); } @@ -1276,7 +1282,7 @@ njs_vmcode_unary_plus(njs_vm_t *vm, njs_ return sizeof(njs_vmcode_2addr_t); } - return NJS_TRAP_NUMBER; + return njs_trap(vm, NJS_TRAP_NUMBER); } @@ -1288,7 +1294,7 @@ njs_vmcode_unary_negation(njs_vm_t *vm, return sizeof(njs_vmcode_2addr_t); } - return NJS_TRAP_NUMBER; + return njs_trap(vm, NJS_TRAP_NUMBER); } @@ -1336,7 +1342,7 @@ njs_vmcode_addition(njs_vm_t *vm, njs_va return sizeof(njs_vmcode_3addr_t); } - return NJS_TRAP_STRINGS; + return njs_trap(vm, NJS_TRAP_STRINGS); } @@ -1353,7 +1359,7 @@ njs_vmcode_substraction(njs_vm_t *vm, nj return sizeof(njs_vmcode_3addr_t); } - return NJS_TRAP_NUMBERS; + return njs_trap(vm, NJS_TRAP_NUMBERS); } @@ -1370,7 +1376,7 @@ njs_vmcode_multiplication(njs_vm_t *vm, return sizeof(njs_vmcode_3addr_t); } - return NJS_TRAP_NUMBERS; + return njs_trap(vm, NJS_TRAP_NUMBERS); } @@ -1404,7 +1410,7 @@ njs_vmcode_exponentiation(njs_vm_t *vm, return sizeof(njs_vmcode_3addr_t); } - return NJS_TRAP_NUMBERS; + return njs_trap(vm, NJS_TRAP_NUMBERS); } @@ -1421,7 +1427,7 @@ njs_vmcode_division(njs_vm_t *vm, njs_va return sizeof(njs_vmcode_3addr_t); } - return NJS_TRAP_NUMBERS; + return njs_trap(vm, NJS_TRAP_NUMBERS); } @@ -1438,7 +1444,7 @@ njs_vmcode_remainder(njs_vm_t *vm, njs_v return sizeof(njs_vmcode_3addr_t); } - return NJS_TRAP_NUMBERS; + return njs_trap(vm, NJS_TRAP_NUMBERS); } @@ -1457,7 +1463,7 @@ njs_vmcode_left_shift(njs_vm_t *vm, njs_ return sizeof(njs_vmcode_3addr_t); } - return NJS_TRAP_NUMBERS; + return njs_trap(vm, NJS_TRAP_NUMBERS); } @@ -1476,7 +1482,7 @@ njs_vmcode_right_shift(njs_vm_t *vm, njs return sizeof(njs_vmcode_3addr_t); } - return NJS_TRAP_NUMBERS; + return njs_trap(vm, NJS_TRAP_NUMBERS); } @@ -1496,7 +1502,7 @@ njs_vmcode_unsigned_right_shift(njs_vm_t return sizeof(njs_vmcode_3addr_t); } - return NJS_TRAP_NUMBERS; + return njs_trap(vm, NJS_TRAP_NUMBERS); } @@ -1562,7 +1568,7 @@ njs_vmcode_bitwise_not(njs_vm_t *vm, njs return sizeof(njs_vmcode_2addr_t); } - return NJS_TRAP_NUMBER; + return njs_trap(vm, NJS_TRAP_NUMBER); } @@ -1580,7 +1586,7 @@ njs_vmcode_bitwise_and(njs_vm_t *vm, njs return sizeof(njs_vmcode_3addr_t); } - return NJS_TRAP_NUMBERS; + return njs_trap(vm, NJS_TRAP_NUMBERS); } @@ -1598,7 +1604,7 @@ njs_vmcode_bitwise_xor(njs_vm_t *vm, njs return sizeof(njs_vmcode_3addr_t); } - return NJS_TRAP_NUMBERS; + return njs_trap(vm, NJS_TRAP_NUMBERS); } @@ -1616,7 +1622,7 @@ njs_vmcode_bitwise_or(njs_vm_t *vm, njs_ return sizeof(njs_vmcode_3addr_t); } - return NJS_TRAP_NUMBERS; + return njs_trap(vm, NJS_TRAP_NUMBERS); } @@ -1626,7 +1632,7 @@ njs_vmcode_equal(njs_vm_t *vm, njs_value njs_ret_t ret; const njs_value_t *retval; - ret = njs_values_equal(val1, val2); + ret = njs_values_equal(vm, val1, val2); if (nxt_fast_path(ret >= 0)) { @@ -1646,7 +1652,7 @@ njs_vmcode_not_equal(njs_vm_t *vm, njs_v njs_ret_t ret; const njs_value_t *retval; - ret = njs_values_equal(val1, val2); + ret = njs_values_equal(vm, val1, val2); if (nxt_fast_path(ret >= 0)) { @@ -1661,7 +1667,7 @@ njs_vmcode_not_equal(njs_vm_t *vm, njs_v static nxt_noinline njs_ret_t -njs_values_equal(const njs_value_t *val1, const njs_value_t *val2) +njs_values_equal(njs_vm_t *vm, const njs_value_t *val1, const njs_value_t *val2) { /* Void and null are equal and not comparable with anything else. */ if (njs_is_null_or_void(val1)) { @@ -1682,7 +1688,7 @@ njs_values_equal(const njs_value_t *val1 return (val1->data.u.object == val2->data.u.object); } - return NJS_TRAP_NUMBERS; + return njs_trap(vm, NJS_TRAP_NUMBERS); } @@ -1692,7 +1698,7 @@ njs_vmcode_less(njs_vm_t *vm, njs_value_ njs_ret_t ret; const njs_value_t *retval; - ret = njs_values_compare(val1, val2); + ret = njs_values_compare(vm, val1, val2); if (nxt_fast_path(ret >= -1)) { @@ -1726,7 +1732,7 @@ njs_vmcode_greater_or_equal(njs_vm_t *vm njs_ret_t ret; const njs_value_t *retval; - ret = njs_values_compare(val1, val2); + ret = njs_values_compare(vm, val1, val2); if (nxt_fast_path(ret >= -1)) { @@ -1749,7 +1755,8 @@ njs_vmcode_greater_or_equal(njs_vm_t *vm */ static nxt_noinline njs_ret_t -njs_values_compare(const njs_value_t *val1, const njs_value_t *val2) +njs_values_compare(njs_vm_t *vm, const njs_value_t *val1, + const njs_value_t *val2) { if (nxt_fast_path(njs_is_numeric(val1) || njs_is_numeric(val2))) { @@ -1764,14 +1771,14 @@ njs_values_compare(const njs_value_t *va return (val1->data.u.number < val2->data.u.number); } - return NJS_TRAP_NUMBERS; + return njs_trap(vm, NJS_TRAP_NUMBERS); } if (nxt_fast_path(njs_is_string(val1) && njs_is_string(val2))) { return (njs_string_cmp(val1, val2) < 0) ? 1 : 0; } - return NJS_TRAP_STRINGS; + return njs_trap(vm, NJS_TRAP_STRINGS); } @@ -2200,8 +2207,8 @@ njs_ret_t njs_normalize_args(njs_vm_t *vm, njs_value_t *args, uint8_t *args_types, nxt_uint_t nargs) { - njs_ret_t trap; nxt_uint_t n; + njs_trap_t trap; n = nxt_min(nargs, NJS_ARGS_TYPES_MAX); @@ -2319,7 +2326,7 @@ trap: njs_vm_trap_value(vm, args); - return trap; + return njs_trap(vm, trap); type_error: @@ -2830,18 +2837,19 @@ static const njs_vmcode_1addr_t njs_tra static const njs_vm_trap_t njs_vm_traps[] = { - /* NJS_TRAP_STRING_ARG */ { &njs_trap_string_argument, 0 }, - /* NJS_TRAP_INTEGER_ARG */ { &njs_trap_number_argument, 0 }, - /* NJS_TRAP_PROPERTY */ { &njs_trap_strings[1], 0 }, - /* NJS_TRAP_STRINGS */ { &njs_trap_strings[0], 0 }, - /* NJS_TRAP_INCDEC */ { &njs_trap_numbers[1], 1 }, - /* NJS_TRAP_NUMBERS */ { &njs_trap_numbers[0], 0 }, - /* NJS_TRAP_NUMBER */ { &njs_trap_number[0], 0 }, + /* NJS_TRAP_NUMBER */ { .code = &njs_trap_number[0] }, + /* NJS_TRAP_NUMBERS */ { .code = &njs_trap_numbers[0] }, + /* NJS_TRAP_INCDEC */ { .code = &njs_trap_numbers[1], + .reference = 1 }, + /* NJS_TRAP_STRINGS */ { .code = &njs_trap_strings[0] }, + /* NJS_TRAP_PROPERTY */ { .code = &njs_trap_strings[1] }, + /* NJS_TRAP_NUMBER_ARG */ { .code = &njs_trap_number_argument }, + /* NJS_TRAP_STRING_ARG */ { .code = &njs_trap_string_argument }, }; static void -njs_vm_trap(njs_vm_t *vm, nxt_uint_t trap, njs_value_t *value1, +njs_vm_trap(njs_vm_t *vm, njs_trap_t trap, njs_value_t *value1, njs_value_t *value2) { njs_native_frame_t *frame; @@ -2858,9 +2866,9 @@ njs_vm_trap(njs_vm_t *vm, nxt_uint_t tra */ njs_set_invalid(&frame->trap_scratch); frame->trap_values[1] = *value2; - frame->trap_reference = njs_vm_traps[trap].reference_value; - - if (njs_vm_traps[trap].reference_value) { + frame->trap_reference = njs_vm_traps[trap].reference; + + if (njs_vm_traps[trap].reference) { frame->trap_values[0].data.u.value = value1; } else { @@ -2873,7 +2881,7 @@ njs_vm_trap(njs_vm_t *vm, nxt_uint_t tra static void -njs_vm_trap_argument(njs_vm_t *vm, nxt_uint_t trap) +njs_vm_trap_argument(njs_vm_t *vm, njs_trap_t trap) { njs_value_t *value; njs_native_frame_t *frame; diff -r 8960cef1cd5f -r 69300ba58603 njs/njs_vm.h --- a/njs/njs_vm.h Tue Jul 24 19:50:02 2018 +0300 +++ b/njs/njs_vm.h Tue Jul 24 19:50:02 2018 +0300 @@ -27,22 +27,31 @@ * -3: not used; * -4 (NJS_STOP/NXT_DONE): njs_vmcode_stop() has stopped execution, * execution has completed successfully; - * -5 .. -11: traps to convert objects to primitive values. + * -5 (NJS_TRAP) trap to convert objects to primitive values; + * -6 .. -11: not used. */ #define NJS_STOP NXT_DONE +#define NJS_TRAP (-5) + +/* The last return value which preempts execution. */ +#define NJS_PREEMPT (-11) /* Traps events. */ -#define NJS_TRAP_NUMBER (-5) -#define NJS_TRAP_NUMBERS (-6) -#define NJS_TRAP_INCDEC (-7) -#define NJS_TRAP_STRINGS (-8) -#define NJS_TRAP_PROPERTY (-9) -#define NJS_TRAP_NUMBER_ARG (-10) -#define NJS_TRAP_STRING_ARG (-11) -#define NJS_TRAP_BASE NJS_TRAP_STRING_ARG +typedef enum { + NJS_TRAP_NUMBER = 0, + NJS_TRAP_NUMBERS, + NJS_TRAP_INCDEC, + NJS_TRAP_STRINGS, + NJS_TRAP_PROPERTY, + NJS_TRAP_NUMBER_ARG, + NJS_TRAP_STRING_ARG, +} njs_trap_t; -#define NJS_PREEMPT (-11) + +#define njs_trap(vm, code) \ + vm->trap = code, NJS_TRAP; + /* * A user-defined function is prepared to run. This code is never @@ -983,7 +992,7 @@ enum njs_function_e { typedef struct { const njs_vmcode_1addr_t *code; - nxt_bool_t reference_value; + nxt_bool_t reference; } njs_vm_trap_t; @@ -1062,6 +1071,7 @@ struct njs_vm_s { nxt_array_t *debug; nxt_array_t *backtrace; + njs_trap_t trap:8; uint8_t trailer; /* 1 bit */ uint8_t accumulative; /* 1 bit */ }; From miranovy at gmail.com Thu Jul 26 07:16:38 2018 From: miranovy at gmail.com (Miroslav Novy) Date: Thu, 26 Jul 2018 09:16:38 +0200 Subject: Added limit_rate_after as variable In-Reply-To: References: Message-ID: # HG changeset patch # User Miroslav Nov? # Date 1532521218 0 # Wed Jul 25 12:20:18 2018 +0000 # Node ID f5da29b630f779ab294cc7ff78213a175976424c # Parent f7e79596baf209151682f2f7d220161c034657ac Added limit_rate_after as variable diff -r f7e79596baf2 -r f5da29b630f7 src/http/ngx_http_variables.c --- a/src/http/ngx_http_variables.c Tue Jul 24 18:46:54 2018 +0300 +++ b/src/http/ngx_http_variables.c Wed Jul 25 12:20:18 2018 +0000 @@ -326,6 +326,11 @@ offsetof(ngx_http_request_t, limit_rate), NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE, 0 }, + { ngx_string("limit_rate_after"), ngx_http_variable_request_set_size, + ngx_http_variable_request_get_size, + offsetof(ngx_http_request_t, limit_rate_after), + NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE, 0 }, + { ngx_string("connection"), NULL, ngx_http_variable_connection, 0, 0, 0 }, -------------- next part -------------- An HTML attachment was scrubbed... URL: From mdounin at mdounin.ru Thu Jul 26 13:36:07 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Thu, 26 Jul 2018 16:36:07 +0300 Subject: Added limit_rate_after as variable In-Reply-To: References: Message-ID: <20180726133607.GR56558@mdounin.ru> Hello! On Thu, Jul 26, 2018 at 09:16:38AM +0200, Miroslav Novy wrote: > # HG changeset patch > # User Miroslav Nov? > # Date 1532521218 0 > # Wed Jul 25 12:20:18 2018 +0000 > # Node ID f5da29b630f779ab294cc7ff78213a175976424c > # Parent f7e79596baf209151682f2f7d220161c034657ac > Added limit_rate_after as variable > > diff -r f7e79596baf2 -r f5da29b630f7 src/http/ngx_http_variables.c > --- a/src/http/ngx_http_variables.c Tue Jul 24 18:46:54 2018 +0300 > +++ b/src/http/ngx_http_variables.c Wed Jul 25 12:20:18 2018 +0000 > @@ -326,6 +326,11 @@ > offsetof(ngx_http_request_t, limit_rate), > NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE, 0 }, > > + { ngx_string("limit_rate_after"), ngx_http_variable_request_set_size, > + ngx_http_variable_request_get_size, > + offsetof(ngx_http_request_t, limit_rate_after), > + NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE, 0 }, > + > { ngx_string("connection"), NULL, > ngx_http_variable_connection, 0, 0, 0 }, https://trac.nginx.org/nginx/ticket/293#comment:5 -- Maxim Dounin http://mdounin.ru/ From hongzhidao at gmail.com Fri Jul 27 09:24:46 2018 From: hongzhidao at gmail.com (=?UTF-8?B?5rSq5b+X6YGT?=) Date: Fri, 27 Jul 2018 17:24:46 +0800 Subject: How to checking nginx service is running? Message-ID: Hi. There are three ways we used. 1. Checking nginx processes. ps -Af | grep nginx 2. Checking pid file. /usr/local/nginx/logs/nginx.pid 3. service nginx status | grep running. I'm wondering which is the best way? Or any other suggestion? Thanks. -------------- next part -------------- An HTML attachment was scrubbed... URL: From jrmarsha at mtu.edu Fri Jul 27 13:28:28 2018 From: jrmarsha at mtu.edu (Joshua Marshall) Date: Fri, 27 Jul 2018 09:28:28 -0400 Subject: Hooking up flex/bison to an in progress data stream upload from a client Message-ID: Hello all, I am looking for a way to do two things in particular. The first is the be able to have a way to direct HTTP POST's to a program's stdin with arguments and to then take its stdout and put that back in the stream being uploaded, and then to apply this to a flex/bison program or module. This is to handle 300GB files without saving them to disk, but still getting the important information out of them. Having the general stdin/stdout part is also because I think this should be more generalized for uploads and downloads in general so things like streaming video become less of a problem. Apache does not have their modules set up in such a way as to feasibly do this without a whole new major revision. Looking at nginx, it looks closer but I'm still not expert enough to know without help. -------------- next part -------------- An HTML attachment was scrubbed... URL: From xeioex at nginx.com Fri Jul 27 14:02:21 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Fri, 27 Jul 2018 14:02:21 +0000 Subject: [njs] Added the pretty string representation for values. Message-ID: details: http://hg.nginx.org/njs/rev/058162fce59a branches: changeset: 572:058162fce59a user: Dmitry Volyntsev date: Fri Jul 27 17:01:52 2018 +0300 description: Added the pretty string representation for values. Interactive shell: dumping the pretty string representation of the last expression. >> [1, new Number(2), {a: new String('??Z?')}, true, console.log, /^undef$/m, new Date(0)] [ 1, [Number: 2], { a: [String: '??Z?'] }, true, [Function: native], /^undef$/m, 1970-01-01T00:00:00.000Z ] njs.dump(value[, indent]): Returns the pretty string representation of a value. value - a value of any type. indent - a number. A number of space characters per indentation level. njs.dump({a:[]}) -> '{a:[]}' njs.dump({a:[]}, 1) -> '{\n a: [\n \n ]\n}' console.log([value1[, values]]) Prints to stdout the flat pretty string representation of values (no new lines). console.dump([value1[, values]]) Prints to stdout the pretty string representation of values. This fixes #11 issue on GitHub. diffstat: njs/njs.h | 2 + njs/njs_builtin.c | 29 ++ njs/njs_date.c | 11 +- njs/njs_date.h | 3 + njs/njs_error.c | 28 +- njs/njs_error.h | 2 + njs/njs_extern.c | 54 ++++ njs/njs_extern.h | 1 + njs/njs_json.c | 485 +++++++++++++++++++++++++++++++++++++++++- njs/njs_regexp.c | 37 +- njs/njs_regexp.h | 2 + njs/njs_shell.c | 49 ++++- njs/test/njs_expect_test.exp | 100 ++++++-- njs/test/njs_unit_test.c | 11 + 14 files changed, 738 insertions(+), 76 deletions(-) diffs (truncated from 1288 to 1000 lines): diff -r 766fcec15744 -r 058162fce59a njs/njs.h --- a/njs/njs.h Tue Jul 24 19:50:02 2018 +0300 +++ b/njs/njs.h Fri Jul 27 17:01:52 2018 +0300 @@ -217,6 +217,8 @@ NXT_EXPORT nxt_int_t njs_value_is_string NXT_EXPORT nxt_int_t njs_value_is_object(njs_value_t *value); NXT_EXPORT nxt_int_t njs_value_is_function(njs_value_t *value); +NXT_EXPORT njs_ret_t njs_vm_value_dump(njs_vm_t *vm, nxt_str_t *retval, + const njs_value_t *value, nxt_uint_t indent); NXT_EXPORT njs_value_t *njs_vm_object_prop(njs_vm_t *vm, njs_value_t *value, const nxt_str_t *key); diff -r 766fcec15744 -r 058162fce59a njs/njs_builtin.c --- a/njs/njs_builtin.c Tue Jul 24 19:50:02 2018 +0300 +++ b/njs/njs_builtin.c Fri Jul 27 17:01:52 2018 +0300 @@ -1069,6 +1069,28 @@ njs_builtin_match_native_function(njs_vm } +static njs_ret_t +njs_dump_value(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, + njs_index_t unused) +{ + nxt_str_t str; + nxt_uint_t n; + const njs_value_t *value, *indent; + + value = njs_arg(args, nargs, 1); + indent = njs_arg(args, nargs, 2); + + n = indent->data.u.number; + n = nxt_min(n, 5); + + if (njs_vm_value_dump(vm, &str, value, n) != NXT_OK) { + return NXT_ERROR; + } + + return njs_string_new(vm, &vm->retval, str.start, str.length, 0); +} + + static const njs_object_prop_t njs_njs_object_properties[] = { { @@ -1076,6 +1098,13 @@ static const njs_object_prop_t njs_njs_ .name = njs_string("version"), .value = njs_string(NJS_VERSION), }, + + { + .type = NJS_METHOD, + .name = njs_string("dump"), + .value = njs_native_function(njs_dump_value, 0, + NJS_SKIP_ARG, NJS_SKIP_ARG, NJS_NUMBER_ARG), + }, }; diff -r 766fcec15744 -r 058162fce59a njs/njs_date.c --- a/njs/njs_date.c Tue Jul 24 19:50:02 2018 +0300 +++ b/njs/njs_date.c Fri Jul 27 17:01:52 2018 +0300 @@ -1019,6 +1019,13 @@ static njs_ret_t njs_date_prototype_to_iso_string(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused) { + return njs_date_to_string(vm, &vm->retval, &args[0]); +} + + +njs_ret_t +njs_date_to_string(njs_vm_t *vm, njs_value_t *retval, const njs_value_t *date) +{ int32_t year; double time; size_t size; @@ -1026,7 +1033,7 @@ njs_date_prototype_to_iso_string(njs_vm_ u_char buf[NJS_ISO_DATE_TIME_LEN]; struct tm tm; - time = args[0].data.u.date->time; + time = date->data.u.date->time; if (!isnan(time)) { clock = time / 1000; @@ -1042,7 +1049,7 @@ njs_date_prototype_to_iso_string(njs_vm_ tm.tm_hour, tm.tm_min, tm.tm_sec, (int) ((int64_t) time % 1000)); - return njs_string_new(vm, &vm->retval, buf, size, size); + return njs_string_new(vm, retval, buf, size, size); } njs_range_error(vm, NULL); diff -r 766fcec15744 -r 058162fce59a njs/njs_date.h --- a/njs/njs_date.h Tue Jul 24 19:50:02 2018 +0300 +++ b/njs/njs_date.h Fri Jul 27 17:01:52 2018 +0300 @@ -11,6 +11,9 @@ njs_ret_t njs_date_constructor(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused); +njs_ret_t njs_date_to_string(njs_vm_t *vm, njs_value_t *retval, + const njs_value_t *date); + extern const njs_object_init_t njs_date_constructor_init; extern const njs_object_init_t njs_date_prototype_init; diff -r 766fcec15744 -r 058162fce59a njs/njs_error.c --- a/njs/njs_error.c Tue Jul 24 19:50:02 2018 +0300 +++ b/njs/njs_error.c Fri Jul 27 17:01:52 2018 +0300 @@ -586,6 +586,18 @@ static njs_ret_t njs_error_prototype_to_string(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused) { + if (nargs < 1 || !njs_is_object(&args[0])) { + njs_type_error(vm, "'this' argument is not an object"); + return NXT_ERROR; + } + + return njs_error_to_string(vm, &vm->retval, &args[0]); +} + + +njs_ret_t +njs_error_to_string(njs_vm_t *vm, njs_value_t *retval, const njs_value_t *error) +{ size_t size; u_char *p; nxt_str_t name, message; @@ -595,16 +607,11 @@ njs_error_prototype_to_string(njs_vm_t * static const njs_value_t default_name = njs_string("Error"); - if (nargs < 1 || !njs_is_object(&args[0])) { - njs_type_error(vm, "'this' argument is not an object"); - return NXT_ERROR; - } - lhq.key_hash = NJS_NAME_HASH; lhq.key = nxt_string_value("name"); lhq.proto = &njs_object_hash_proto; - prop = njs_object_property(vm, args[0].data.u.object, &lhq); + prop = njs_object_property(vm, error->data.u.object, &lhq); if (prop != NULL) { name_value = &prop->value; @@ -618,7 +625,7 @@ njs_error_prototype_to_string(njs_vm_t * lhq.key_hash = NJS_MESSAGE_HASH; lhq.key = nxt_string_value("message"); - prop = njs_object_property(vm, args[0].data.u.object, &lhq); + prop = njs_object_property(vm, error->data.u.object, &lhq); if (prop != NULL) { message_value = &prop->value; @@ -630,18 +637,18 @@ njs_error_prototype_to_string(njs_vm_t * njs_string_get(message_value, &message); if (name.length == 0) { - vm->retval = *message_value; + *retval = *message_value; return NJS_OK; } if (message.length == 0) { - vm->retval = *name_value; + *retval = *name_value; return NJS_OK; } size = name.length + message.length + 2; - p = njs_string_alloc(vm, &vm->retval, size, size); + p = njs_string_alloc(vm, retval, size, size); if (nxt_fast_path(p != NULL)) { p = nxt_cpymem(p, name.start, name.length); @@ -653,6 +660,7 @@ njs_error_prototype_to_string(njs_vm_t * } njs_memory_error(vm); + return NJS_ERROR; } diff -r 766fcec15744 -r 058162fce59a njs/njs_error.h --- a/njs/njs_error.h Tue Jul 24 19:50:02 2018 +0300 +++ b/njs/njs_error.h Fri Jul 27 17:01:52 2018 +0300 @@ -53,6 +53,8 @@ njs_ret_t njs_uri_error_constructor(njs_ njs_ret_t njs_memory_error_constructor(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused); +njs_ret_t njs_error_to_string(njs_vm_t *vm, njs_value_t *retval, + const njs_value_t *error); extern const njs_object_init_t njs_error_constructor_init; extern const njs_object_init_t njs_eval_error_constructor_init; diff -r 766fcec15744 -r 058162fce59a njs/njs_extern.c --- a/njs/njs_extern.c Tue Jul 24 19:50:02 2018 +0300 +++ b/njs/njs_extern.c Fri Jul 27 17:01:52 2018 +0300 @@ -228,6 +228,60 @@ njs_vm_external_bind(njs_vm_t *vm, const } +njs_array_t * +njs_extern_keys_array(njs_vm_t *vm, const njs_extern_t *external) +{ + uint32_t n, keys_length; + njs_ret_t ret; + njs_array_t *keys; + const nxt_lvlhsh_t *hash; + nxt_lvlhsh_each_t lhe; + const njs_extern_t *ext; + + keys_length = 0; + + nxt_lvlhsh_each_init(&lhe, &njs_extern_hash_proto); + + hash = &external->hash; + + for ( ;; ) { + ext = nxt_lvlhsh_each(hash, &lhe); + + if (ext == NULL) { + break; + } + + keys_length++; + } + + keys = njs_array_alloc(vm, keys_length, NJS_ARRAY_SPARE); + if (nxt_slow_path(keys == NULL)) { + return NULL; + } + + n = 0; + + nxt_lvlhsh_each_init(&lhe, &njs_extern_hash_proto); + + for ( ;; ) { + ext = nxt_lvlhsh_each(hash, &lhe); + + if (ext == NULL) { + break; + } + + ret = njs_string_create(vm, &keys->start[n++], ext->name.start, + ext->name.length, 0); + + if (ret != NXT_OK) { + return NULL; + } + } + + return keys; +} + + njs_value_t * njs_parser_external(njs_vm_t *vm, njs_parser_t *parser) { diff -r 766fcec15744 -r 058162fce59a njs/njs_extern.h --- a/njs/njs_extern.h Tue Jul 24 19:50:02 2018 +0300 +++ b/njs/njs_extern.h Fri Jul 27 17:01:52 2018 +0300 @@ -38,6 +38,7 @@ typedef struct { } njs_extern_value_t; +njs_array_t *njs_extern_keys_array(njs_vm_t *vm, const njs_extern_t *external); nxt_int_t njs_external_match_native_function(njs_vm_t *vm, njs_function_native_t func, nxt_str_t *name); diff -r 766fcec15744 -r 058162fce59a njs/njs_json.c --- a/njs/njs_json.c Tue Jul 24 19:50:02 2018 +0300 +++ b/njs/njs_json.c Fri Jul 27 17:01:52 2018 +0300 @@ -5,6 +5,9 @@ */ #include +#include +#include +#include #include #include @@ -127,16 +130,16 @@ static njs_ret_t njs_json_stringify_repl static njs_ret_t njs_json_stringify_array(njs_vm_t *vm, njs_json_stringify_t *stringify); static njs_json_state_t *njs_json_push_stringify_state(njs_vm_t *vm, - njs_json_stringify_t *stringify, njs_value_t *value); + njs_json_stringify_t *stringify, const njs_value_t *value); static njs_json_state_t *njs_json_pop_stringify_state( njs_json_stringify_t *stringify); static nxt_int_t njs_json_append_value(njs_json_stringify_t *stringify, - njs_value_t *value); + const njs_value_t *value); static nxt_int_t njs_json_append_string(njs_json_stringify_t *stringify, - njs_value_t *value); + const njs_value_t *value, char quote); static nxt_int_t njs_json_append_number(njs_json_stringify_t *stringify, - njs_value_t *value); + const njs_value_t *value); static njs_value_t *njs_json_wrap_value(njs_vm_t *vm, njs_value_t *value); @@ -1162,7 +1165,7 @@ njs_json_parse_exception(njs_json_parse_ } \ \ state->written = 1; \ - njs_json_append_string(stringify, key); \ + njs_json_append_string(stringify, key, '\"'); \ njs_json_stringify_append(":", 1); \ if (stringify->space.length != 0) { \ njs_json_stringify_append(" ", 1); \ @@ -1621,7 +1624,7 @@ njs_json_stringify_array(njs_vm_t *vm, n static njs_json_state_t * njs_json_push_stringify_state(njs_vm_t *vm, njs_json_stringify_t *stringify, - njs_value_t *value) + const njs_value_t *value) { njs_json_state_t *state; @@ -1654,7 +1657,13 @@ njs_json_push_stringify_state(njs_vm_t * state->keys = stringify->replacer.data.u.array; } else { - state->keys = njs_object_keys_array(vm, value); + if (njs_is_external(value)) { + state->keys = njs_extern_keys_array(vm, value->external.proto); + + } else { + state->keys = njs_object_keys_array(vm, value); + } + if (state->keys == NULL) { return NULL; } @@ -1681,7 +1690,7 @@ njs_json_pop_stringify_state(njs_json_st static nxt_int_t -njs_json_append_value(njs_json_stringify_t *stringify, njs_value_t *value) +njs_json_append_value(njs_json_stringify_t *stringify, const njs_value_t *value) { switch (value->type) { case NJS_OBJECT_STRING: @@ -1689,7 +1698,7 @@ njs_json_append_value(njs_json_stringify /* Fall through. */ case NJS_STRING: - return njs_json_append_string(stringify, value); + return njs_json_append_string(stringify, value, '\"'); case NJS_OBJECT_NUMBER: value = &value->data.u.object_value->value; @@ -1724,7 +1733,8 @@ njs_json_append_value(njs_json_stringify static nxt_int_t -njs_json_append_string(njs_json_stringify_t *stringify, njs_value_t *value) +njs_json_append_string(njs_json_stringify_t *stringify, + const njs_value_t *value, char quote) { u_char c, *dst, *dst_end; size_t length; @@ -1734,7 +1744,7 @@ njs_json_append_string(njs_json_stringif static char hex2char[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; - (void) njs_string_prop(&str, value); + (void) njs_string_prop(&str, (njs_value_t *) value); p = str.start; end = p + str.size; @@ -1747,11 +1757,14 @@ njs_json_append_string(njs_json_stringif dst_end = dst + 64; - *dst++ = '\"'; + *dst++ = quote; while (p < end) { - if (*p < ' ' || *p == '\"' || *p == '\\') { + if (*p < ' ' + || *p == '\\' + || (*p == '\"' && quote == '\"')) + { c = (u_char) *p++; *dst++ = '\\'; @@ -1793,7 +1806,7 @@ njs_json_append_string(njs_json_stringif */ while (p < end && (dst_end - dst) > 6) { - if (*p < ' ' || *p == '\"' || *p == '\\') { + if (*p < ' ' || (*p == '\"' && quote == '\"') || *p == '\\') { break; } @@ -1820,14 +1833,15 @@ njs_json_append_string(njs_json_stringif } njs_json_buf_written(stringify, dst - stringify->last->pos); - njs_json_buf_append(stringify, "\"", 1); + njs_json_buf_append(stringify, "e, 1); return NXT_OK; } static nxt_int_t -njs_json_append_number(njs_json_stringify_t *stringify, njs_value_t *value) +njs_json_append_number(njs_json_stringify_t *stringify, + const njs_value_t *value) { u_char *p; size_t size; @@ -2037,3 +2051,442 @@ const njs_object_init_t njs_json_object njs_json_object_properties, nxt_nitems(njs_json_object_properties), }; + + +#define njs_dump(str) \ + ret = njs_json_buf_append(stringify, str, nxt_length(str)); \ + if (nxt_slow_path(ret != NXT_OK)) { \ + goto memory_error; \ + } + + +#define njs_dump_item(str) \ + if (written) { \ + njs_json_buf_append(stringify, ",", 1); \ + } \ + \ + written = 1; \ + ret = njs_json_buf_append(stringify, str, nxt_length(str)); \ + if (nxt_slow_path(ret != NXT_OK)) { \ + goto memory_error; \ + } + + +static nxt_int_t +njs_dump_value(njs_json_stringify_t *stringify, const njs_value_t *value) +{ + size_t len; + njs_ret_t ret; + nxt_str_t str; + nxt_uint_t written; + njs_value_t str_val; + const njs_extern_t *ext_proto; + char buf[32]; + + njs_ret_t (*to_string)(njs_vm_t *, njs_value_t *, + const njs_value_t *); + + switch (value->type) { + case NJS_OBJECT_STRING: + value = &value->data.u.object_value->value; + + njs_string_get(value, &str); + + njs_dump("[String: "); + njs_json_append_string(stringify, value, '\''); + njs_dump("]") + break; + + case NJS_STRING: + njs_string_get(value, &str); + return njs_json_append_string(stringify, value, '\''); + + case NJS_OBJECT_NUMBER: + value = &value->data.u.object_value->value; + + ret = njs_number_to_string(stringify->vm, &str_val, value); + if (nxt_slow_path(ret != NXT_OK)) { + return NXT_ERROR; + } + + njs_string_get(&str_val, &str); + + njs_dump("[Number: "); + njs_json_buf_append(stringify, (char *) str.start, str.length); + njs_dump("]") + break; + + case NJS_OBJECT_BOOLEAN: + value = &value->data.u.object_value->value; + + if (njs_is_true(value)) { + njs_dump("[Boolean: true]"); + + } else { + njs_dump("[Boolean: false]"); + } + + break; + + case NJS_BOOLEAN: + if (njs_is_true(value)) { + njs_dump("true"); + + } else { + njs_dump("false"); + } + + break; + + case NJS_VOID: + njs_dump("undefined"); + break; + + case NJS_NULL: + njs_dump("null"); + break; + + case NJS_INVALID: + njs_dump(""); + break; + + case NJS_FUNCTION: + if (value->data.u.function->native) { + njs_dump("[Function: native]"); + + } else { + njs_dump("[Function]"); + } + + break; + + case NJS_EXTERNAL: + ext_proto = value->external.proto; + + written = 0; + njs_dump_item("{type:"); + + switch (ext_proto->type) { + case NJS_EXTERN_PROPERTY: + njs_dump("\"property\""); + break; + case NJS_EXTERN_METHOD: + njs_dump("\"method\""); + break; + case NJS_EXTERN_OBJECT: + njs_dump("\"object\""); + break; + case NJS_EXTERN_CASELESS_OBJECT: + njs_dump("\"caseless_object\""); + break; + } + + njs_dump_item("props:["); + written = 0; + + if (ext_proto->get != NULL) { + njs_dump_item("\"getter\""); + } + + if (ext_proto->set != NULL) { + njs_dump_item("\"setter\""); + } + + if (ext_proto->function != NULL) { + njs_dump_item("\"method\""); + } + + if (ext_proto->find != NULL) { + njs_dump_item("\"find\""); + } + + if (ext_proto->foreach != NULL) { + njs_dump_item("\"foreach\""); + } + + if (ext_proto->next != NULL) { + njs_dump_item("\"next\""); + } + + return njs_json_buf_append(stringify, "]}", 2); + + case NJS_NUMBER: + case NJS_REGEXP: + case NJS_DATE: + case NJS_OBJECT_ERROR: + case NJS_OBJECT_EVAL_ERROR: + case NJS_OBJECT_INTERNAL_ERROR: + case NJS_OBJECT_RANGE_ERROR: + case NJS_OBJECT_REF_ERROR: + case NJS_OBJECT_SYNTAX_ERROR: + case NJS_OBJECT_TYPE_ERROR: + case NJS_OBJECT_URI_ERROR: + + switch (value->type) { + case NJS_NUMBER: + to_string = njs_number_to_string; + break; + + case NJS_REGEXP: + to_string = njs_regexp_to_string; + break; + + case NJS_DATE: + to_string = njs_date_to_string; + break; + + default: + to_string = njs_error_to_string; + } + + ret = to_string(stringify->vm, &str_val, value); + if (nxt_slow_path(ret != NXT_OK)) { + return NXT_ERROR; + } + + njs_string_get(&str_val, &str); + + return njs_json_buf_append(stringify, (char *) str.start, str.length); + + default: + len = snprintf(buf, sizeof(buf), "[Unknown value type:%d]", + value->type); + return njs_json_buf_append(stringify, buf, len); + } + + return ret; + +memory_error: + + njs_memory_error(stringify->vm); + + return NXT_ERROR; +} + + +#define njs_dump_is_object(value) \ + (((value)->type == NJS_OBJECT) \ + || ((value)->type == NJS_ARRAY) \ + || ((value)->type == NJS_OBJECT_VALUE) \ + || ((value)->type == NJS_EXTERNAL \ + && !nxt_lvlhsh_is_empty(&(value)->external.proto->hash))) + + +#define njs_dump_append_value(value) \ + state->written = 1; \ + ret = njs_dump_value(stringify, value); \ + if (nxt_slow_path(ret != NXT_OK)) { \ + if (ret == NXT_DECLINED) { \ + goto exception; \ + } \ + \ + goto memory_error; \ + } + + +njs_ret_t +njs_vm_value_dump(njs_vm_t *vm, nxt_str_t *retval, const njs_value_t *value, + nxt_uint_t indent) +{ + nxt_int_t i; + njs_ret_t ret; + nxt_str_t str; + njs_value_t *key, *val, ext_val; + njs_json_state_t *state; + njs_object_prop_t *prop; + nxt_lvlhsh_query_t lhq; + njs_json_stringify_t *stringify; + + if (njs_vm_backtrace(vm) != NULL) { + goto exception; + } + + stringify = nxt_mem_cache_alloc(vm->mem_cache_pool, + sizeof(njs_json_stringify_t)); + + if (nxt_slow_path(stringify == NULL)) { + goto memory_error; + } + + stringify->vm = vm; + stringify->pool = vm->mem_cache_pool; + stringify->nodes = NULL; + stringify->last = NULL; + + if (!njs_dump_is_object(value)) { + ret = njs_dump_value(stringify, value); + if (nxt_slow_path(ret != NXT_OK)) { + goto memory_error; + } + + goto done; + } + + stringify->space.length = indent; + stringify->space.start = nxt_mem_cache_alloc(vm->mem_cache_pool, indent); + if (nxt_slow_path(stringify->space.start == NULL)) { + goto memory_error; + } + + memset(stringify->space.start, ' ', indent); + + if (nxt_array_init(&stringify->stack, NULL, 4, sizeof(njs_json_state_t), + &njs_array_mem_proto, vm->mem_cache_pool) + == NULL) + { + goto memory_error; + } + + if (njs_json_push_stringify_state(vm, stringify, value) == NULL) { + goto memory_error; + } + + state = stringify->state; + + for ( ;; ) { + switch (state->type) { + case NJS_JSON_OBJECT_START: + njs_json_stringify_append("{", 1); + njs_json_stringify_indent(stringify->stack.items + 1); + state->type = NJS_JSON_OBJECT_CONTINUE; + + /* Fall through. */ + + case NJS_JSON_OBJECT_CONTINUE: + if (state->index >= state->keys->length) { + njs_json_stringify_indent(stringify->stack.items); + njs_json_stringify_append("}", 1); + + state = njs_json_pop_stringify_state(stringify); + if (state == NULL) { + goto done; + } + + break; + } + + key = &state->keys->start[state->index++]; + njs_string_get(key, &lhq.key); + lhq.key_hash = nxt_djb_hash(lhq.key.start, lhq.key.length); + + if (njs_is_external(&state->value)) { + lhq.proto = &njs_extern_hash_proto; + + ret = nxt_lvlhsh_find(&state->value.external.proto->hash, &lhq); + if (nxt_slow_path(ret == NXT_DECLINED)) { + break; + } + + ext_val.type = NJS_EXTERNAL; + ext_val.data.truth = 1; + ext_val.external.proto = lhq.value; + + val = &ext_val; + + } else { + lhq.proto = &njs_object_hash_proto; + + ret = nxt_lvlhsh_find(&state->value.data.u.object->hash, &lhq); + if (nxt_slow_path(ret == NXT_DECLINED)) { + break; + } + + prop = lhq.value; + val = &prop->value; + + if (!prop->enumerable) { + break; + } + } + + if (state->written) { + njs_json_stringify_append(",", 1); + njs_json_stringify_indent(stringify->stack.items + 1); + } + + state->written = 1; + njs_json_stringify_append((char *) lhq.key.start, lhq.key.length); + njs_json_stringify_append(":", 1); + if (stringify->space.length != 0) { + njs_json_stringify_append(" ", 1); + } + + if (njs_dump_is_object(val)) { + state = njs_json_push_stringify_state(vm, stringify, val); + if (state == NULL) { + goto exception; + } + + break; + } + + njs_dump_append_value(val); + + break; + + case NJS_JSON_ARRAY_START: + njs_json_stringify_append("[", 1); + njs_json_stringify_indent(stringify->stack.items + 1); + state->type = NJS_JSON_ARRAY_CONTINUE; + + /* Fall through. */ + + case NJS_JSON_ARRAY_CONTINUE: + if (state->index >= state->value.data.u.array->length) { + njs_json_stringify_indent(stringify->stack.items); + njs_json_stringify_append("]", 1); + + state = njs_json_pop_stringify_state(stringify); + if (state == NULL) { + goto done; + } + + break; + } + + if (state->written) { + njs_json_stringify_append(",", 1); + njs_json_stringify_indent(stringify->stack.items + 1); + } + + val = &state->value.data.u.array->start[state->index++]; + + if (njs_dump_is_object(val)) { + state = njs_json_push_stringify_state(vm, stringify, val); + if (state == NULL) { + goto exception; + } + + break; + } + + njs_dump_append_value(val); + + break; + + default: + nxt_unreachable(); + } + } + +done: + + ret = njs_json_buf_pullup(stringify, &str); + if (nxt_slow_path(ret != NXT_OK)) { + goto memory_error; + } + + *retval = str; + + return NXT_OK; + +memory_error: + + njs_memory_error(vm); + +exception: + + njs_vm_value_to_ext_string(vm, retval, &vm->retval, 1); + + return NXT_OK; +} diff -r 766fcec15744 -r 058162fce59a njs/njs_regexp.c --- a/njs/njs_regexp.c Tue Jul 24 19:50:02 2018 +0300 +++ b/njs/njs_regexp.c Fri Jul 27 17:01:52 2018 +0300 @@ -527,22 +527,8 @@ static njs_ret_t njs_regexp_prototype_to_string(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused) { - u_char *source; - int32_t length; - uint32_t size; - njs_value_t *value; - njs_regexp_pattern_t *pattern; - - value = &args[0]; - - if (njs_is_regexp(value)) { - pattern = value->data.u.regexp->pattern; - source = pattern->source; - - size = strlen((char *) source); - length = nxt_utf8_length(source, size); - - return njs_regexp_string_create(vm, &vm->retval, source, size, length); + if (njs_is_regexp(&args[0])) { + return njs_regexp_to_string(vm, &vm->retval, &args[0]); } njs_type_error(vm, "'this' argument is not a regexp"); @@ -551,6 +537,25 @@ njs_regexp_prototype_to_string(njs_vm_t } +njs_ret_t +njs_regexp_to_string(njs_vm_t *vm, njs_value_t *retval, + const njs_value_t *value) +{ + u_char *source; + int32_t length; + uint32_t size; + njs_regexp_pattern_t *pattern; + + pattern = value->data.u.regexp->pattern; + source = pattern->source; + + size = strlen((char *) source); + length = nxt_utf8_length(source, size); + + return njs_regexp_string_create(vm, retval, source, size, length); +} + + static njs_ret_t njs_regexp_prototype_test(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused) diff -r 766fcec15744 -r 058162fce59a njs/njs_regexp.h --- a/njs/njs_regexp.h Tue Jul 24 19:50:02 2018 +0300 +++ b/njs/njs_regexp.h Fri Jul 27 17:01:52 2018 +0300 @@ -31,6 +31,8 @@ njs_regexp_t *njs_regexp_alloc(njs_vm_t njs_ret_t njs_regexp_prototype_exec(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused); +njs_ret_t njs_regexp_to_string(njs_vm_t *vm, njs_value_t *retval, + const njs_value_t *regexp); extern const njs_object_init_t njs_regexp_constructor_init; extern const njs_object_init_t njs_regexp_prototype_init; diff -r 766fcec15744 -r 058162fce59a njs/njs_shell.c --- a/njs/njs_shell.c Tue Jul 24 19:50:02 2018 +0300 +++ b/njs/njs_shell.c Fri Jul 27 17:01:52 2018 +0300 @@ -58,6 +58,8 @@ static char *njs_completion_generator(co static njs_ret_t njs_ext_console_log(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused); +static njs_ret_t njs_ext_console_dump(njs_vm_t *vm, njs_value_t *args, + nxt_uint_t nargs, njs_index_t unused); static njs_ret_t njs_ext_console_help(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused); @@ -76,6 +78,18 @@ static njs_external_t njs_ext_console[] njs_ext_console_log, 0 }, + { nxt_string("dump"), + NJS_EXTERN_METHOD, + NULL, + 0, + NULL, + NULL, + NULL, + NULL, + NULL, + njs_ext_console_dump, + 0 }, + { nxt_string("help"), NJS_EXTERN_METHOD, NULL, @@ -431,7 +445,7 @@ njs_process_script(njs_vm_t *vm, njs_opt ret = njs_vm_run(vm); } - if (njs_vm_retval_to_ext_string(vm, out) != NXT_OK) { + if (njs_vm_value_dump(vm, out, njs_vm_retval(vm), 1) != NXT_OK) { *out = nxt_string_value("failed to get retval from VM"); return NXT_ERROR; } @@ -625,7 +639,38 @@ njs_ext_console_log(njs_vm_t *vm, njs_va n = 1; while (n < nargs) { - if (njs_vm_value_to_ext_string(vm, &msg, njs_argument(args, n), 0) + if (njs_vm_value_dump(vm, &msg, njs_argument(args, n), 0) + == NJS_ERROR) + { + return NJS_ERROR; + } + + printf("%s%.*s", (n != 1) ? " " : "", (int) msg.length, msg.start); + + n++; + } + + if (nargs > 1) { + printf("\n"); + } + + vm->retval = njs_value_void; + + return NJS_OK; +} + + +static njs_ret_t +njs_ext_console_dump(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, + njs_index_t unused) +{ + nxt_str_t msg; From robinsonnie at gmail.com Mon Jul 30 13:33:11 2018 From: robinsonnie at gmail.com (Robinson Nie) Date: Mon, 30 Jul 2018 21:33:11 +0800 Subject: [PATCH] ngx_event_pipe: add judgment conditions for downstream errors. Message-ID: Hello! Here is a patch to solve the following problem: When the proxy is turned on, if the downstream error (p->output_filter() returns an error), the current code will still try to read upstream & write downstream, which is actually unnecessary. # HG changeset patch # User dapeng.ndp # Date 1532956361 -28800 # Mon Jul 30 21:12:41 2018 +0800 # Node ID cbacf180df090540846aefa4a4a5453e307be219 # Parent f7e79596baf209151682f2f7d220161c034657ac ngx_event_pipe: add judgment conditions for downstream errors. Avoid writing downstream & reading upstream, if there is an error due to writing downstream. diff -r f7e79596baf2 -r cbacf180df09 src/event/ngx_event_pipe.c --- a/src/event/ngx_event_pipe.c Tue Jul 24 18:46:54 2018 +0300 +++ b/src/event/ngx_event_pipe.c Mon Jul 30 21:12:41 2018 +0800 @@ -247,6 +247,7 @@ } else if (!p->cacheable && p->downstream->data == p->output_ctx && p->downstream->write->ready + && !p->downstream_error && !p->downstream->write->delayed) { /* -------------- next part -------------- An HTML attachment was scrubbed... URL: From xeioex at nginx.com Mon Jul 30 17:00:51 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Mon, 30 Jul 2018 17:00:51 +0000 Subject: [njs] Making njs_arg() available for external value methods. Message-ID: details: http://hg.nginx.org/njs/rev/8840fd0ff685 branches: changeset: 573:8840fd0ff685 user: Dmitry Volyntsev date: Mon Jul 30 20:00:20 2018 +0300 description: Making njs_arg() available for external value methods. diffstat: njs/njs.h | 7 +++++++ njs/njs_function.h | 3 --- 2 files changed, 7 insertions(+), 3 deletions(-) diffs (30 lines): diff -r 058162fce59a -r 8840fd0ff685 njs/njs.h --- a/njs/njs.h Fri Jul 27 17:01:52 2018 +0300 +++ b/njs/njs.h Mon Jul 30 20:00:20 2018 +0300 @@ -44,6 +44,13 @@ typedef struct { #define njs_argument(args, n) \ (njs_value_t *) ((u_char *) args + n * 16) + +extern const njs_value_t njs_value_void; + +#define njs_arg(args, nargs, n) \ + (njs_value_t *) ((n < nargs) ? njs_argument(args, n) \ + : &njs_value_void) + #define njs_value_assign(dst, src) \ *((njs_opaque_value_t *) dst) = *((njs_opaque_value_t *) src); diff -r 058162fce59a -r 8840fd0ff685 njs/njs_function.h --- a/njs/njs_function.h Fri Jul 27 17:01:52 2018 +0300 +++ b/njs/njs_function.h Mon Jul 30 20:00:20 2018 +0300 @@ -40,9 +40,6 @@ struct njs_function_lambda_s { }; -#define njs_arg(args, nargs, n) \ - ((n < nargs) ? &(args)[n] : &njs_value_void) - /* The frame size must be aligned to njs_value_t. */ #define NJS_NATIVE_FRAME_SIZE \ nxt_align_size(sizeof(njs_native_frame_t), sizeof(njs_value_t)) From xeioex at nginx.com Mon Jul 30 17:00:51 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Mon, 30 Jul 2018 17:00:51 +0000 Subject: [njs] Fixed applying call() to methods of external values. Message-ID: details: http://hg.nginx.org/njs/rev/5f00966ffff8 branches: changeset: 574:5f00966ffff8 user: Dmitry Volyntsev date: Mon Jul 30 20:00:31 2018 +0300 description: Fixed applying call() to methods of external values. This correctly fixes #20 on Github. diffstat: nginx/ngx_http_js_module.c | 38 ++++++++++++--- nginx/ngx_stream_js_module.c | 8 ++- njs/njs.h | 4 +- njs/njs_extern.c | 15 +++++- njs/njs_vm.c | 9 +-- njs/test/njs_unit_test.c | 107 ++++++++++++++++++++++-------------------- 6 files changed, 112 insertions(+), 69 deletions(-) diffs (329 lines): diff -r 8840fd0ff685 -r 5f00966ffff8 nginx/ngx_http_js_module.c --- a/nginx/ngx_http_js_module.c Mon Jul 30 20:00:20 2018 +0300 +++ b/nginx/ngx_http_js_module.c Mon Jul 30 20:00:31 2018 +0300 @@ -1256,7 +1256,10 @@ ngx_http_js_ext_send_header(njs_vm_t *vm { ngx_http_request_t *r; - r = njs_value_data(njs_argument(args, 0)); + r = njs_vm_external(vm, njs_arg(args, nargs, 0)); + if (nxt_slow_path(r == NULL)) { + return NXT_ERROR; + } if (ngx_http_send_header(r) == NGX_ERROR) { return NJS_ERROR; @@ -1278,7 +1281,10 @@ ngx_http_js_ext_send(njs_vm_t *vm, njs_v ngx_chain_t *out, *cl, **ll; ngx_http_request_t *r; - r = njs_value_data(njs_argument(args, 0)); + r = njs_vm_external(vm, njs_arg(args, nargs, 0)); + if (nxt_slow_path(r == NULL)) { + return NXT_ERROR; + } out = NULL; ll = &out; @@ -1343,7 +1349,10 @@ ngx_http_js_ext_finish(njs_vm_t *vm, njs ngx_http_js_ctx_t *ctx; ngx_http_request_t *r; - r = njs_value_data(njs_argument(args, 0)); + r = njs_vm_external(vm, njs_arg(args, nargs, 0)); + if (nxt_slow_path(r == NULL)) { + return NXT_ERROR; + } if (ngx_http_send_special(r, NGX_HTTP_LAST) == NGX_ERROR) { return NJS_ERROR; @@ -1399,7 +1408,10 @@ ngx_http_js_ext_return(njs_vm_t *vm, njs } } - r = njs_value_data(njs_argument(args, 0)); + r = njs_vm_external(vm, njs_argument(args, 0)); + if (nxt_slow_path(r == NULL)) { + return NXT_ERROR; + } ctx = ngx_http_get_module_ctx(r, ngx_http_js_module); @@ -1437,7 +1449,10 @@ ngx_http_js_ext_internal_redirect(njs_vm return NJS_ERROR; } - r = njs_value_data(njs_argument(args, 0)); + r = njs_vm_external(vm, njs_argument(args, 0)); + if (nxt_slow_path(r == NULL)) { + return NXT_ERROR; + } ctx = ngx_http_get_module_ctx(r, ngx_http_js_module); @@ -1495,10 +1510,14 @@ ngx_http_js_ext_log_core(njs_vm_t *vm, n ngx_log_handler_pt handler; ngx_http_request_t *r; - r = njs_value_data(njs_argument(args, 0)); + r = njs_vm_external(vm, njs_arg(args, nargs, 0)); + if (nxt_slow_path(r == NULL)) { + return NXT_ERROR; + } + c = r->connection; - if (njs_vm_value_to_ext_string(vm, &msg, njs_argument(args, 1), 0) + if (njs_vm_value_to_ext_string(vm, &msg, njs_arg(args, nargs, 1), 0) == NJS_ERROR) { return NJS_ERROR; @@ -1874,7 +1893,10 @@ ngx_http_js_ext_subrequest(njs_vm_t *vm, return NJS_ERROR; } - r = njs_value_data(njs_argument(args, 0)); + r = njs_vm_external(vm, njs_argument(args, 0)); + if (nxt_slow_path(r == NULL)) { + return NXT_ERROR; + } ctx = ngx_http_get_module_ctx(r, ngx_http_js_module); diff -r 8840fd0ff685 -r 5f00966ffff8 nginx/ngx_stream_js_module.c --- a/nginx/ngx_stream_js_module.c Mon Jul 30 20:00:20 2018 +0300 +++ b/nginx/ngx_stream_js_module.c Mon Jul 30 20:00:31 2018 +0300 @@ -886,10 +886,14 @@ ngx_stream_js_ext_log_core(njs_vm_t *vm, ngx_log_handler_pt handler; ngx_stream_session_t *s; - s = njs_value_data(njs_argument(args, 0)); + s = njs_vm_external(vm, njs_arg(args, nargs, 0)); + if (nxt_slow_path(s == NULL)) { + return NXT_ERROR; + } + c = s->connection; - if (njs_vm_value_to_ext_string(vm, &msg, njs_argument(args, 1), 0) + if (njs_vm_value_to_ext_string(vm, &msg, njs_arg(args, nargs, 1), 0) == NJS_ERROR) { return NJS_ERROR; diff -r 8840fd0ff685 -r 5f00966ffff8 njs/njs.h --- a/njs/njs.h Mon Jul 30 20:00:20 2018 +0300 +++ b/njs/njs.h Mon Jul 30 20:00:31 2018 +0300 @@ -177,9 +177,11 @@ NXT_EXPORT nxt_int_t njs_vm_run(njs_vm_t NXT_EXPORT const njs_extern_t *njs_vm_external_prototype(njs_vm_t *vm, njs_external_t *external); NXT_EXPORT nxt_int_t njs_vm_external_create(njs_vm_t *vm, - njs_value_t *value, const njs_extern_t *proto, void *object); + njs_value_t *value, const njs_extern_t *proto, njs_external_ptr_t object); NXT_EXPORT nxt_int_t njs_vm_external_bind(njs_vm_t *vm, const nxt_str_t *var_name, njs_value_t *value); +NXT_EXPORT njs_external_ptr_t njs_vm_external(njs_vm_t *vm, + const njs_value_t *value); NXT_EXPORT void njs_disassembler(njs_vm_t *vm); NXT_EXPORT nxt_array_t *njs_vm_completions(njs_vm_t *vm, nxt_str_t *expression); diff -r 8840fd0ff685 -r 5f00966ffff8 njs/njs_extern.c --- a/njs/njs_extern.c Mon Jul 30 20:00:20 2018 +0300 +++ b/njs/njs_extern.c Mon Jul 30 20:00:31 2018 +0300 @@ -166,7 +166,7 @@ njs_vm_external_prototype(njs_vm_t *vm, nxt_int_t njs_vm_external_create(njs_vm_t *vm, njs_value_t *ext_val, - const njs_extern_t *proto, void *object) + const njs_extern_t *proto, njs_external_ptr_t object) { void *obj; @@ -228,6 +228,19 @@ njs_vm_external_bind(njs_vm_t *vm, const } +nxt_noinline njs_external_ptr_t +njs_vm_external(njs_vm_t *vm, const njs_value_t *value) +{ + if (nxt_fast_path(njs_is_external(value))) { + return njs_extern_object(vm, value); + } + + njs_type_error(vm, "external value is expected"); + + return NULL; +} + + njs_array_t * njs_extern_keys_array(njs_vm_t *vm, const njs_extern_t *external) { diff -r 8840fd0ff685 -r 5f00966ffff8 njs/njs_vm.c --- a/njs/njs_vm.c Mon Jul 30 20:00:20 2018 +0300 +++ b/njs/njs_vm.c Mon Jul 30 20:00:31 2018 +0300 @@ -2077,9 +2077,8 @@ njs_function_new_object(njs_vm_t *vm, nj njs_ret_t njs_vmcode_method_frame(njs_vm_t *vm, njs_value_t *object, njs_value_t *name) { - void *obj; njs_ret_t ret; - njs_value_t this, *value; + njs_value_t *value; njs_object_prop_t *prop; njs_property_query_t pq; const njs_extern_t *ext_proto; @@ -2131,11 +2130,7 @@ njs_vmcode_method_frame(njs_vm_t *vm, nj return NXT_ERROR; } - obj = njs_extern_object(vm, object); - - this.data.u.data = obj; - - ret = njs_function_native_frame(vm, ext_proto->function, &this, NULL, + ret = njs_function_native_frame(vm, ext_proto->function, object, NULL, method->nargs, 0, method->code.ctor); break; diff -r 8840fd0ff685 -r 5f00966ffff8 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Mon Jul 30 20:00:20 2018 +0300 +++ b/njs/test/njs_unit_test.c Mon Jul 30 20:00:31 2018 +0300 @@ -3981,13 +3981,20 @@ static njs_unit_test_t njs_test[] = { nxt_string("delete $r.one"), nxt_string("false") }, -#if 0 { nxt_string("$r.some_method.call($r, 'YES')"), nxt_string("???") }, + { nxt_string("var f = $r.some_method.bind($r); f('YES')"), + nxt_string("???") }, + + { nxt_string("function f(fn, arg) {return fn(arg);}; f($r.some_method.bind($r), 'YES')"), + nxt_string("???") }, + { nxt_string("$r.some_method.apply($r, ['YES'])"), nxt_string("???") }, -#endif + + { nxt_string("$r.some_method.call([], 'YES')"), + nxt_string("TypeError: external value is expected") }, { nxt_string("$r.nonexistent"), nxt_string("undefined") }, @@ -9777,25 +9784,22 @@ njs_unit_test_method_external(njs_vm_t * { nxt_int_t ret; nxt_str_t s; - uintptr_t next; njs_unit_test_req_t *r; - next = 0; - - if (nargs > 1) { - - ret = njs_value_string_copy(vm, &s, njs_argument(args, 1), &next); - - if (ret == NXT_OK && s.length == 3 && memcmp(s.start, "YES", 3) == 0) { - r = njs_value_data(njs_argument(args, 0)); - njs_string_create(vm, njs_vm_retval(vm), r->uri.start, - r->uri.length, 0); - - return NXT_OK; - } + r = njs_vm_external(vm, njs_arg(args, nargs, 0)); + if (nxt_slow_path(r == NULL)) { + return NXT_ERROR; } - return NXT_ERROR; + ret = njs_vm_value_to_ext_string(vm, &s, njs_arg(args, nargs, 1), 0); + if (ret == NXT_OK && s.length == 3 && memcmp(s.start, "YES", 3) == 0) { + return njs_string_create(vm, njs_vm_retval(vm), r->uri.start, + r->uri.length, 0); + } + + vm->retval = njs_value_void; + + return NXT_OK; } @@ -9808,41 +9812,44 @@ njs_unit_test_create_external(njs_vm_t * njs_value_t *value; njs_unit_test_req_t *r, *sr; - if (nargs > 1) { - r = njs_value_data(njs_argument(args, 0)); - - if (njs_vm_value_to_ext_string(vm, &uri, njs_argument(args, 1), 0) - == NJS_ERROR) - { - return NJS_ERROR; - } - - value = nxt_mem_cache_zalloc(r->mem_cache_pool, - sizeof(njs_opaque_value_t)); - if (value == NULL) { - return NXT_ERROR; - } - - sr = nxt_mem_cache_zalloc(r->mem_cache_pool, - sizeof(njs_unit_test_req_t)); - if (sr == NULL) { - return NXT_ERROR; - } - - sr->uri = uri; - sr->mem_cache_pool = r->mem_cache_pool; - sr->proto = r->proto; - - ret = njs_vm_external_create(vm, value, sr->proto, sr); - if (ret != NXT_OK) { - return NXT_ERROR; - } - - njs_vm_retval_set(vm, value); - - return NXT_OK; + r = njs_vm_external(vm, njs_arg(args, nargs, 0)); + if (nxt_slow_path(r == NULL)) { + return NXT_ERROR; + } + + if (njs_vm_value_to_ext_string(vm, &uri, njs_arg(args, nargs, 1), 0) + != NJS_OK) + { + return NXT_ERROR; + } + + value = nxt_mem_cache_zalloc(r->mem_cache_pool, sizeof(njs_opaque_value_t)); + if (value == NULL) { + goto memory_error; } + sr = nxt_mem_cache_zalloc(r->mem_cache_pool, sizeof(njs_unit_test_req_t)); + if (sr == NULL) { + goto memory_error; + } + + sr->uri = uri; + sr->mem_cache_pool = r->mem_cache_pool; + sr->proto = r->proto; + + ret = njs_vm_external_create(vm, value, sr->proto, sr); + if (ret != NXT_OK) { + return NXT_ERROR; + } + + njs_vm_retval_set(vm, value); + + return NXT_OK; + +memory_error: + + njs_memory_error(vm); + return NXT_ERROR; } From mdounin at mdounin.ru Mon Jul 30 17:21:10 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Mon, 30 Jul 2018 20:21:10 +0300 Subject: [PATCH] ngx_event_pipe: add judgment conditions for downstream errors. In-Reply-To: References: Message-ID: <20180730172110.GA56558@mdounin.ru> Hello! On Mon, Jul 30, 2018 at 09:33:11PM +0800, Robinson Nie wrote: > Here is a patch to solve the following problem: When the proxy is turned > on, if the downstream error (p->output_filter() returns an error), the > current code will still try to read upstream & write downstream, which is > actually unnecessary. > > # HG changeset patch > # User dapeng.ndp > # Date 1532956361 -28800 > # Mon Jul 30 21:12:41 2018 +0800 > # Node ID cbacf180df090540846aefa4a4a5453e307be219 > # Parent f7e79596baf209151682f2f7d220161c034657ac > ngx_event_pipe: add judgment conditions for downstream errors. > > Avoid writing downstream & reading upstream, if there is an error due to > writing downstream. > > diff -r f7e79596baf2 -r cbacf180df09 src/event/ngx_event_pipe.c > --- a/src/event/ngx_event_pipe.c Tue Jul 24 18:46:54 2018 +0300 > +++ b/src/event/ngx_event_pipe.c Mon Jul 30 21:12:41 2018 +0800 > @@ -247,6 +247,7 @@ > } else if (!p->cacheable > && p->downstream->data == p->output_ctx > && p->downstream->write->ready > + && !p->downstream_error > && !p->downstream->write->delayed) > { > /* If there was a downstream error, nginx won't write to the downstream anymore, see the ngx_event_pipe_write_to_downstream() function. Instead, it will call the ngx_event_pipe_drain_chains() function to discard all pending output buffers. Reading from the upstream may be desired or not depending on additional conditions. In particular, if caching is used, nginx will have to read data from the upstream to save the response to disk even in case of errors. If further reading of the upstream response is not needed and p->downstream_error is set, nginx will stop processing of the request in ngx_http_upstream_process_request(). Assuming p->downstream_error is set, this will happen once reading from the upstream blocks. Note well that the specific condition you are modifying is about flushing the already read buffers if writing to the upstream is possible. From semantic point of view, it is possible when p->downstream_error is set (it will simply discard the buffers), so the change looks wrong. Also, if you are trying to avoid reading from the upstream if p->downstream_error is set, it looks like a suboptimal place, as it will not prevent reading from the upstream unless all buffers are filled. Given the above, it is not clear what you are trying to improve. The commit log is clearly misleading, and needs to be fixed. It is also not clear if any changes are needed here. You may want to elaborate more on what you are trying to improve. -- Maxim Dounin http://mdounin.ru/ From robinsonnie at gmail.com Tue Jul 31 03:35:35 2018 From: robinsonnie at gmail.com (Robinson Nie) Date: Tue, 31 Jul 2018 11:35:35 +0800 Subject: [PATCH] ngx_event_pipe: add judgment conditions for downstream errors. In-Reply-To: <20180730172110.GA56558@mdounin.ru> References: <20180730172110.GA56558@mdounin.ru> Message-ID: Yes, you are right. This patch is somewhat ambiguous, so the updated patch is as follows: # HG changeset patch # User dapeng.ndp # Date 1533007686 -28800 # Tue Jul 31 11:28:06 2018 +0800 # Node ID 5b7a4bba5238658b9b256cea013d07300c29540d # Parent f7e79596baf209151682f2f7d220161c034657ac ngx_event_pipe: When the downstream error occurs, avoid further reading upstream. When the proxy is turned on and there is no need to cache data locally. If the downstream is wrong(p->downstream_error is set), avoid further reading upstream, and finalize upstream & downstream as soon as possible. diff -r f7e79596baf2 -r 5b7a4bba5238 src/event/ngx_event_pipe.c --- a/src/event/ngx_event_pipe.c Tue Jul 24 18:46:54 2018 +0300 +++ b/src/event/ngx_event_pipe.c Tue Jul 31 11:28:06 2018 +0800 @@ -112,6 +112,10 @@ return NGX_OK; } + if (!p->cacheable && p->downstream_error) { + return NGX_OK; + } + #if (NGX_THREADS) if (p->aio) { Please help review, thanks! 2018-07-31 1:21 GMT+08:00 Maxim Dounin : > Hello! > > On Mon, Jul 30, 2018 at 09:33:11PM +0800, Robinson Nie wrote: > >> Here is a patch to solve the following problem: When the proxy is turned >> on, if the downstream error (p->output_filter() returns an error), the >> current code will still try to read upstream & write downstream, which is >> actually unnecessary. >> >> # HG changeset patch >> # User dapeng.ndp >> # Date 1532956361 -28800 >> # Mon Jul 30 21:12:41 2018 +0800 >> # Node ID cbacf180df090540846aefa4a4a5453e307be219 >> # Parent f7e79596baf209151682f2f7d220161c034657ac >> ngx_event_pipe: add judgment conditions for downstream errors. >> >> Avoid writing downstream & reading upstream, if there is an error due to >> writing downstream. >> >> diff -r f7e79596baf2 -r cbacf180df09 src/event/ngx_event_pipe.c >> --- a/src/event/ngx_event_pipe.c Tue Jul 24 18:46:54 2018 +0300 >> +++ b/src/event/ngx_event_pipe.c Mon Jul 30 21:12:41 2018 +0800 >> @@ -247,6 +247,7 @@ >> } else if (!p->cacheable >> && p->downstream->data == p->output_ctx >> && p->downstream->write->ready >> + && !p->downstream_error >> && !p->downstream->write->delayed) >> { >> /* > > If there was a downstream error, nginx won't write to the > downstream anymore, see the ngx_event_pipe_write_to_downstream() > function. Instead, it will call the ngx_event_pipe_drain_chains() > function to discard all pending output buffers. > > Reading from the upstream may be desired or not depending on > additional conditions. In particular, if caching is used, nginx > will have to read data from the upstream to save the response to > disk even in case of errors. If further reading of the upstream > response is not needed and p->downstream_error is set, nginx will > stop processing of the request in ngx_http_upstream_process_request(). > Assuming p->downstream_error is set, this will happen once reading > from the upstream blocks. > > Note well that the specific condition you are modifying is about > flushing the already read buffers if writing to the upstream is > possible. From semantic point of view, it is possible when > p->downstream_error is set (it will simply discard the buffers), > so the change looks wrong. Also, if you are trying to avoid > reading from the upstream if p->downstream_error is set, it looks > like a suboptimal place, as it will not prevent reading from the > upstream unless all buffers are filled. > > Given the above, it is not clear what you are trying to improve. > The commit log is clearly misleading, and needs to be fixed. It > is also not clear if any changes are needed here. You may want to > elaborate more on what you are trying to improve. > > -- > Maxim Dounin > http://mdounin.ru/ > _______________________________________________ > nginx-devel mailing list > nginx-devel at nginx.org > http://mailman.nginx.org/mailman/listinfo/nginx-devel From xeioex at nginx.com Tue Jul 31 11:33:11 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Tue, 31 Jul 2018 11:33:11 +0000 Subject: [njs] Version bump. Message-ID: details: http://hg.nginx.org/njs/rev/162c56aceb68 branches: changeset: 576:162c56aceb68 user: Dmitry Volyntsev date: Tue Jul 31 14:33:01 2018 +0300 description: Version bump. diffstat: njs/njs.h | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diffs (12 lines): diff -r e83f41520613 -r 162c56aceb68 njs/njs.h --- a/njs/njs.h Tue Jul 31 14:32:34 2018 +0300 +++ b/njs/njs.h Tue Jul 31 14:33:01 2018 +0300 @@ -11,7 +11,7 @@ #include -#define NJS_VERSION "0.2.3" +#define NJS_VERSION "0.2.4" #include From xeioex at nginx.com Tue Jul 31 11:33:11 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Tue, 31 Jul 2018 11:33:11 +0000 Subject: [njs] Version 0.2.3. Message-ID: details: http://hg.nginx.org/njs/rev/e83f41520613 branches: changeset: 575:e83f41520613 user: Dmitry Volyntsev date: Tue Jul 31 14:32:34 2018 +0300 description: Version 0.2.3. diffstat: CHANGES | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 45 insertions(+), 0 deletions(-) diffs (52 lines): diff -r 5f00966ffff8 -r e83f41520613 CHANGES --- a/CHANGES Mon Jul 30 20:00:31 2018 +0300 +++ b/CHANGES Tue Jul 31 14:32:34 2018 +0300 @@ -1,3 +1,48 @@ + +Changes with njs 0.2.3 31 Jul 2018 + + nginx modules: + + *) Bugfix: making a subrequest from a Reply object caused + a segmentation fault. + + *) Bugfix: getting the parent property of the main Request + object caused a segmentation fault. + + Core: + + *) Feature: added the pretty string representation for values. + + *) Feature: correctly printing floating point numbers. + + *) Feature: correctly parsing floating point numbers. + + *) Feature: String.bytesFrom() method (decoding hex, base64, + base64url into a byte string). + + *) Feature: String.padStart() and String.padEnd() methods. + + *) Feature: added support of binary literals. + + *) Improvement: added information about illegal token in number parsing. + + *) Improvement: allowed uppercased O in octal literal values. + + *) Improvement: added support for multiple arguments in console.log(). + + *) Bugfix: fixed applying call() to methods of external values. + + *) Bugfix: fixed addition operator applied to an object. + + *) Bugfix: fixed exception handling in njs_vm_value_to_ext_string(). + + *) Bugfix: fixed Number() with boolean, null and undefined arguments. + + *) Bugfix: fixed error handling of setting non-numeric Array.length. + + *) Bugfix: fixed autocompletion for global objects. + + *) Bugfix: miscellaneous additional bugs have been fixed. Changes with njs 0.2.2 19 Jun 2018 From xeioex at nginx.com Tue Jul 31 11:45:21 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Tue, 31 Jul 2018 11:45:21 +0000 Subject: [njs] Added tag 0.2.3 for changeset e83f41520613 Message-ID: details: http://hg.nginx.org/njs/rev/d36e4cf4f9dc branches: changeset: 577:d36e4cf4f9dc user: Dmitry Volyntsev date: Tue Jul 31 14:45:16 2018 +0300 description: Added tag 0.2.3 for changeset e83f41520613 diffstat: .hgtags | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diffs (8 lines): diff -r 162c56aceb68 -r d36e4cf4f9dc .hgtags --- a/.hgtags Tue Jul 31 14:33:01 2018 +0300 +++ b/.hgtags Tue Jul 31 14:45:16 2018 +0300 @@ -17,3 +17,4 @@ 215ca47b9167d513fd58ac88de97659377e45275 ddd1b2c9c64b2d459e9c399554dfaadcaabcc364 0.2.0 2a0a59728b5f197379ca62a334a516fabd4ea392 0.2.1 4adbb035caa39dae58611a061d78bc974652231e 0.2.2 +e83f41520613987542472275d49633a9aa5955d1 0.2.3 From xeioex at nginx.com Tue Jul 31 12:59:31 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Tue, 31 Jul 2018 12:59:31 +0000 Subject: [njs] Improved JSON.stringify() for external values. Message-ID: details: http://hg.nginx.org/njs/rev/9d9dfeb98aff branches: changeset: 578:9d9dfeb98aff user: Dmitry Volyntsev date: Tue Jul 31 15:30:01 2018 +0300 description: Improved JSON.stringify() for external values. diffstat: njs/njs_json.c | 5 +---- njs/test/njs_unit_test.c | 4 ++-- 2 files changed, 3 insertions(+), 6 deletions(-) diffs (30 lines): diff -r d36e4cf4f9dc -r 9d9dfeb98aff njs/njs_json.c --- a/njs/njs_json.c Tue Jul 31 14:45:16 2018 +0300 +++ b/njs/njs_json.c Tue Jul 31 15:30:01 2018 +0300 @@ -1723,11 +1723,8 @@ njs_json_append_value(njs_json_stringify case NJS_NULL: case NJS_INVALID: case NJS_FUNCTION: + default: return njs_json_buf_append(stringify, "null", 4); - - default: - njs_type_error(stringify->vm, "Non-serializable object"); - return NXT_DECLINED; } } diff -r d36e4cf4f9dc -r 9d9dfeb98aff njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Tue Jul 31 14:45:16 2018 +0300 +++ b/njs/test/njs_unit_test.c Tue Jul 31 15:30:01 2018 +0300 @@ -9035,8 +9035,8 @@ static njs_unit_test_t njs_test[] = { nxt_string("var e = URIError('e'); e.foo = 'E'; JSON.stringify(e)"), nxt_string("{\"foo\":\"E\"}") }, - { nxt_string("JSON.stringify($r)"), - nxt_string("TypeError: Non-serializable object") }, + { nxt_string("JSON.stringify([$r])"), + nxt_string("[null]") }, /* Ignoring named properties of an array. */ From mdounin at mdounin.ru Tue Jul 31 14:52:02 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 31 Jul 2018 17:52:02 +0300 Subject: [PATCH] ngx_event_pipe: add judgment conditions for downstream errors. In-Reply-To: References: <20180730172110.GA56558@mdounin.ru> Message-ID: <20180731145202.GH56558@mdounin.ru> Hello! On Tue, Jul 31, 2018 at 11:35:35AM +0800, Robinson Nie wrote: > Yes, you are right. > > This patch is somewhat ambiguous, so the updated patch is as follows: > > # HG changeset patch > # User dapeng.ndp > # Date 1533007686 -28800 > # Tue Jul 31 11:28:06 2018 +0800 > # Node ID 5b7a4bba5238658b9b256cea013d07300c29540d > # Parent f7e79596baf209151682f2f7d220161c034657ac > ngx_event_pipe: When the downstream error occurs, avoid further > reading upstream. > > When the proxy is turned on and there is no need to cache data locally. If the > downstream is wrong(p->downstream_error is set), avoid further reading upstream, > and finalize upstream & downstream as soon as possible. > > diff -r f7e79596baf2 -r 5b7a4bba5238 src/event/ngx_event_pipe.c > --- a/src/event/ngx_event_pipe.c Tue Jul 24 18:46:54 2018 +0300 > +++ b/src/event/ngx_event_pipe.c Tue Jul 31 11:28:06 2018 +0800 > @@ -112,6 +112,10 @@ > return NGX_OK; > } > > + if (!p->cacheable && p->downstream_error) { > + return NGX_OK; > + } > + > #if (NGX_THREADS) > > if (p->aio) { > > > Please help review, thanks! As far as I see, this patch will prevent correct operation with threaded writes. As previously suggested, you may want to first elaborate on what problem you are trying to fix. With the current code, the decision on whether nginx needs to stop reading from the upstream in case of downstream error is made by the caller (in the ngx_http_upstream_process_request() in case of the upstream module). While moving this decision from the caller to the event pipe code is possible, it certainly have some downsides. And the possible benefits - saving one iteration of reading from the upstream till it blocks - might not be a good enough reason for the change. I suspect that what you are trying to address is actually worker monopolization while working with fast clients / upstream servers, as described here: https://trac.nginx.org/nginx/ticket/1431 With the downstream error such monopolization is more likely since there is no client to block on, and "one iteration of reading from the upstream till it blocks" might be actually something important enough. This problem is not limited to the downstream error case though, and not even to the event pipe, and addressing it via trying to improve some corner cases in the event pipe code looks wrong. -- Maxim Dounin http://mdounin.ru/ From xeioex at nginx.com Tue Jul 31 18:12:01 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Tue, 31 Jul 2018 18:12:01 +0000 Subject: [njs] Fixed error code typo introduced in 5f00966ffff8. Message-ID: details: http://hg.nginx.org/njs/rev/c85b07c96e27 branches: changeset: 579:c85b07c96e27 user: Dmitry Volyntsev date: Tue Jul 31 21:11:44 2018 +0300 description: Fixed error code typo introduced in 5f00966ffff8. diffstat: nginx/ngx_http_js_module.c | 14 +++++++------- nginx/ngx_stream_js_module.c | 2 +- njs/test/njs_unit_test.c | 12 ++++++------ 3 files changed, 14 insertions(+), 14 deletions(-) diffs (130 lines): diff -r 9d9dfeb98aff -r c85b07c96e27 nginx/ngx_http_js_module.c --- a/nginx/ngx_http_js_module.c Tue Jul 31 15:30:01 2018 +0300 +++ b/nginx/ngx_http_js_module.c Tue Jul 31 21:11:44 2018 +0300 @@ -1258,7 +1258,7 @@ ngx_http_js_ext_send_header(njs_vm_t *vm r = njs_vm_external(vm, njs_arg(args, nargs, 0)); if (nxt_slow_path(r == NULL)) { - return NXT_ERROR; + return NJS_ERROR; } if (ngx_http_send_header(r) == NGX_ERROR) { @@ -1283,7 +1283,7 @@ ngx_http_js_ext_send(njs_vm_t *vm, njs_v r = njs_vm_external(vm, njs_arg(args, nargs, 0)); if (nxt_slow_path(r == NULL)) { - return NXT_ERROR; + return NJS_ERROR; } out = NULL; @@ -1351,7 +1351,7 @@ ngx_http_js_ext_finish(njs_vm_t *vm, njs r = njs_vm_external(vm, njs_arg(args, nargs, 0)); if (nxt_slow_path(r == NULL)) { - return NXT_ERROR; + return NJS_ERROR; } if (ngx_http_send_special(r, NGX_HTTP_LAST) == NGX_ERROR) { @@ -1410,7 +1410,7 @@ ngx_http_js_ext_return(njs_vm_t *vm, njs r = njs_vm_external(vm, njs_argument(args, 0)); if (nxt_slow_path(r == NULL)) { - return NXT_ERROR; + return NJS_ERROR; } ctx = ngx_http_get_module_ctx(r, ngx_http_js_module); @@ -1451,7 +1451,7 @@ ngx_http_js_ext_internal_redirect(njs_vm r = njs_vm_external(vm, njs_argument(args, 0)); if (nxt_slow_path(r == NULL)) { - return NXT_ERROR; + return NJS_ERROR; } ctx = ngx_http_get_module_ctx(r, ngx_http_js_module); @@ -1512,7 +1512,7 @@ ngx_http_js_ext_log_core(njs_vm_t *vm, n r = njs_vm_external(vm, njs_arg(args, nargs, 0)); if (nxt_slow_path(r == NULL)) { - return NXT_ERROR; + return NJS_ERROR; } c = r->connection; @@ -1895,7 +1895,7 @@ ngx_http_js_ext_subrequest(njs_vm_t *vm, r = njs_vm_external(vm, njs_argument(args, 0)); if (nxt_slow_path(r == NULL)) { - return NXT_ERROR; + return NJS_ERROR; } ctx = ngx_http_get_module_ctx(r, ngx_http_js_module); diff -r 9d9dfeb98aff -r c85b07c96e27 nginx/ngx_stream_js_module.c --- a/nginx/ngx_stream_js_module.c Tue Jul 31 15:30:01 2018 +0300 +++ b/nginx/ngx_stream_js_module.c Tue Jul 31 21:11:44 2018 +0300 @@ -888,7 +888,7 @@ ngx_stream_js_ext_log_core(njs_vm_t *vm, s = njs_vm_external(vm, njs_arg(args, nargs, 0)); if (nxt_slow_path(s == NULL)) { - return NXT_ERROR; + return NJS_ERROR; } c = s->connection; diff -r 9d9dfeb98aff -r c85b07c96e27 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Tue Jul 31 15:30:01 2018 +0300 +++ b/njs/test/njs_unit_test.c Tue Jul 31 21:11:44 2018 +0300 @@ -9788,7 +9788,7 @@ njs_unit_test_method_external(njs_vm_t * r = njs_vm_external(vm, njs_arg(args, nargs, 0)); if (nxt_slow_path(r == NULL)) { - return NXT_ERROR; + return NJS_ERROR; } ret = njs_vm_value_to_ext_string(vm, &s, njs_arg(args, nargs, 1), 0); @@ -9799,7 +9799,7 @@ njs_unit_test_method_external(njs_vm_t * vm->retval = njs_value_void; - return NXT_OK; + return NJS_OK; } @@ -9814,13 +9814,13 @@ njs_unit_test_create_external(njs_vm_t * r = njs_vm_external(vm, njs_arg(args, nargs, 0)); if (nxt_slow_path(r == NULL)) { - return NXT_ERROR; + return NJS_ERROR; } if (njs_vm_value_to_ext_string(vm, &uri, njs_arg(args, nargs, 1), 0) != NJS_OK) { - return NXT_ERROR; + return NJS_ERROR; } value = nxt_mem_cache_zalloc(r->mem_cache_pool, sizeof(njs_opaque_value_t)); @@ -9839,12 +9839,12 @@ njs_unit_test_create_external(njs_vm_t * ret = njs_vm_external_create(vm, value, sr->proto, sr); if (ret != NXT_OK) { - return NXT_ERROR; + return NJS_ERROR; } njs_vm_retval_set(vm, value); - return NXT_OK; + return NJS_OK; memory_error: