From mdounin at mdounin.ru Wed Aug 1 04:21:33 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Wed, 01 Aug 2018 04:21:33 +0000 Subject: [nginx] Dav: fixed ngx_copy_file() to truncate destination file. Message-ID: details: http://hg.nginx.org/nginx/rev/3c357206a3b8 branches: changeset: 7328:3c357206a3b8 user: Maxim Dounin date: Wed Aug 01 02:11:58 2018 +0300 description: Dav: fixed ngx_copy_file() to truncate destination file. Previously, ngx_open_file(NGX_FILE_CREATE_OR_OPEN) was used, resulting in destination file being partially rewritten if exists. Notably, this affected WebDAV COPY command (ticket #1576). diffstat: src/core/ngx_file.c | 3 +-- 1 files changed, 1 insertions(+), 2 deletions(-) diffs (13 lines): diff --git a/src/core/ngx_file.c b/src/core/ngx_file.c --- a/src/core/ngx_file.c +++ b/src/core/ngx_file.c @@ -839,8 +839,7 @@ ngx_copy_file(u_char *from, u_char *to, goto failed; } - nfd = ngx_open_file(to, NGX_FILE_WRONLY, NGX_FILE_CREATE_OR_OPEN, - cf->access); + nfd = ngx_open_file(to, NGX_FILE_WRONLY, NGX_FILE_TRUNCATE, cf->access); if (nfd == NGX_INVALID_FILE) { ngx_log_error(NGX_LOG_CRIT, cf->log, ngx_errno, From mdounin at mdounin.ru Wed Aug 1 04:21:35 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Wed, 01 Aug 2018 04:21:35 +0000 Subject: [nginx] Dav: changed ngx_copy_file() to preserve access and mtime. Message-ID: details: http://hg.nginx.org/nginx/rev/63a76a594dd8 branches: changeset: 7329:63a76a594dd8 user: Maxim Dounin date: Wed Aug 01 02:12:11 2018 +0300 description: Dav: changed ngx_copy_file() to preserve access and mtime. This fixes wrong permissions and file time after cross-device MOVE in the DAV module (ticket #1577). Broken in 8101d9101ed8 (0.8.9) when cross-device copying was introduced in ngx_ext_rename_file(). With this change, ngx_copy_file() always calls ngx_set_file_time(), either with the time provided, or with the time from the original file. This is considered acceptable given that copying the file is costly anyway, and optimizing cases when we do not need to preserve time will require interface changes. diffstat: src/core/ngx_file.c | 22 +++++++++++++--------- 1 files changed, 13 insertions(+), 9 deletions(-) diffs (65 lines): diff --git a/src/core/ngx_file.c b/src/core/ngx_file.c --- a/src/core/ngx_file.c +++ b/src/core/ngx_file.c @@ -796,10 +796,12 @@ ngx_copy_file(u_char *from, u_char *to, { char *buf; off_t size; + time_t time; size_t len; ssize_t n; ngx_fd_t fd, nfd; ngx_int_t rc; + ngx_uint_t access; ngx_file_info_t fi; rc = NGX_ERROR; @@ -814,8 +816,10 @@ ngx_copy_file(u_char *from, u_char *to, goto failed; } - if (cf->size != -1) { + if (cf->size != -1 && cf->access != 0 && cf->time != -1) { size = cf->size; + access = cf->access; + time = cf->time; } else { if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) { @@ -825,7 +829,9 @@ ngx_copy_file(u_char *from, u_char *to, goto failed; } - size = ngx_file_size(&fi); + size = (cf->size != -1) ? cf->size : ngx_file_size(&fi); + access = cf->access ? cf->access : ngx_file_access(&fi); + time = (cf->time != -1) ? cf->time : ngx_file_mtime(&fi); } len = cf->buf_size ? cf->buf_size : 65536; @@ -839,7 +845,7 @@ ngx_copy_file(u_char *from, u_char *to, goto failed; } - nfd = ngx_open_file(to, NGX_FILE_WRONLY, NGX_FILE_TRUNCATE, cf->access); + nfd = ngx_open_file(to, NGX_FILE_WRONLY, NGX_FILE_TRUNCATE, access); if (nfd == NGX_INVALID_FILE) { ngx_log_error(NGX_LOG_CRIT, cf->log, ngx_errno, @@ -886,12 +892,10 @@ ngx_copy_file(u_char *from, u_char *to, size -= n; } - if (cf->time != -1) { - if (ngx_set_file_time(to, nfd, cf->time) != NGX_OK) { - ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, - ngx_set_file_time_n " \"%s\" failed", to); - goto failed; - } + if (ngx_set_file_time(to, nfd, time) != NGX_OK) { + ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, + ngx_set_file_time_n " \"%s\" failed", to); + goto failed; } rc = NGX_OK; From mdounin at mdounin.ru Wed Aug 1 04:21:37 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Wed, 01 Aug 2018 04:21:37 +0000 Subject: [nginx] Dav: changed COPY of a file to preserve access mask. Message-ID: details: http://hg.nginx.org/nginx/rev/8e7a5de61664 branches: changeset: 7330:8e7a5de61664 user: Maxim Dounin date: Wed Aug 01 02:12:21 2018 +0300 description: Dav: changed COPY of a file to preserve access mask. The behaviour is now in line with COPY of a directory with contents, which preserves access masks on individual files, as well as the "cp" command. Requested by Roman Arutyunyan. diffstat: src/http/modules/ngx_http_dav_module.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diffs (12 lines): diff --git a/src/http/modules/ngx_http_dav_module.c b/src/http/modules/ngx_http_dav_module.c --- a/src/http/modules/ngx_http_dav_module.c +++ b/src/http/modules/ngx_http_dav_module.c @@ -845,7 +845,7 @@ overwrite_done: cf.size = ngx_file_size(&fi); cf.buf_size = 0; - cf.access = dlcf->access; + cf.access = ngx_file_access(&fi); cf.time = ngx_file_mtime(&fi); cf.log = r->connection->log; From robinsonnie at gmail.com Wed Aug 1 07:45:10 2018 From: robinsonnie at gmail.com (Robinson Nie) Date: Wed, 1 Aug 2018 15:45:10 +0800 Subject: [PATCH] ngx_event_pipe: add judgment conditions for downstream errors. In-Reply-To: <20180731145202.GH56558@mdounin.ru> References: <20180730172110.GA56558@mdounin.ru> <20180731145202.GH56558@mdounin.ru> Message-ID: When a downstream error occurs, the reading upstream( p->upstream->recv_chain() ) is executed not only once but multiple times until it triggers p->upstream->read->ready becomes 0, or p-> upstream_eof / p-> upstream_error / p -> upstream_done becomre !0. This patch wants to avoid these invalid reading upstreams and finalize upstream & downstream as soon as possible. Thank you for your advice! 2018-07-31 22:52 GMT+08:00 Maxim Dounin : > 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/ > _______________________________________________ > nginx-devel mailing list > nginx-devel at nginx.org > http://mailman.nginx.org/mailman/listinfo/nginx-devel From mdounin at mdounin.ru Wed Aug 1 13:20:22 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Wed, 1 Aug 2018 16:20:22 +0300 Subject: [PATCH] ngx_event_pipe: add judgment conditions for downstream errors. In-Reply-To: References: <20180730172110.GA56558@mdounin.ru> <20180731145202.GH56558@mdounin.ru> Message-ID: <20180801132022.GM56558@mdounin.ru> Hello! On Wed, Aug 01, 2018 at 03:45:10PM +0800, Robinson Nie wrote: > When a downstream error occurs, the reading upstream( > p->upstream->recv_chain() ) is executed not only once but multiple > times until it triggers p->upstream->read->ready becomes 0, or p-> > upstream_eof / p-> upstream_error / p -> upstream_done becomre !0. I wrote "reading from the upstream till it blocks", and this is what "read->ready becomes 0" means. -- Maxim Dounin http://mdounin.ru/ From xeioex at nginx.com Wed Aug 1 15:37:32 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Wed, 01 Aug 2018 15:37:32 +0000 Subject: [njs] Returning an internal error for not-implemented Function(). Message-ID: details: http://hg.nginx.org/njs/rev/4586ae051111 branches: changeset: 581:4586ae051111 user: Dmitry Volyntsev date: Wed Aug 01 18:37:15 2018 +0300 description: Returning an internal error for not-implemented Function(). This fixes #41 issue on GitHub. diffstat: njs/njs_function.c | 2 ++ njs/test/njs_unit_test.c | 3 +++ 2 files changed, 5 insertions(+), 0 deletions(-) diffs (25 lines): diff -r 72aa4d9aa606 -r 4586ae051111 njs/njs_function.c --- a/njs/njs_function.c Wed Aug 01 18:05:01 2018 +0300 +++ b/njs/njs_function.c Wed Aug 01 18:37:15 2018 +0300 @@ -457,6 +457,8 @@ njs_ret_t njs_function_constructor(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused) { + njs_internal_error(vm, "Not implemented"); + return NXT_ERROR; } diff -r 72aa4d9aa606 -r 4586ae051111 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Wed Aug 01 18:05:01 2018 +0300 +++ b/njs/test/njs_unit_test.c Wed Aug 01 18:37:15 2018 +0300 @@ -6518,6 +6518,9 @@ static njs_unit_test_t njs_test[] = { nxt_string("function f() {} f.__proto__ === Function.prototype"), nxt_string("true") }, + { nxt_string("Function()"), + nxt_string("InternalError: Not implemented") }, + { nxt_string("RegExp()"), nxt_string("/(?:)/") }, From xeioex at nginx.com Wed Aug 1 15:37:32 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Wed, 01 Aug 2018 15:37:32 +0000 Subject: [njs] Adding const qualifiers njs_value_t arguments of public methods. Message-ID: details: http://hg.nginx.org/njs/rev/72aa4d9aa606 branches: changeset: 580:72aa4d9aa606 user: Dmitry Volyntsev date: Wed Aug 01 18:05:01 2018 +0300 description: Adding const qualifiers njs_value_t arguments of public methods. This allows to use the result of safe njs_arg() macro in the methods. diffstat: njs/njs.c | 10 +++++----- njs/njs.h | 41 ++++++++++++++++++++--------------------- njs/njs_extern.c | 2 +- njs/njs_function.c | 2 +- njs/njs_function.h | 2 +- njs/njs_vm.c | 26 +++++++++++++------------- 6 files changed, 41 insertions(+), 42 deletions(-) diffs (284 lines): diff -r c85b07c96e27 -r 72aa4d9aa606 njs/njs.c --- a/njs/njs.c Tue Jul 31 21:11:44 2018 +0300 +++ b/njs/njs.c Wed Aug 01 18:05:01 2018 +0300 @@ -444,7 +444,7 @@ njs_vm_init(njs_vm_t *vm) nxt_int_t -njs_vm_call(njs_vm_t *vm, njs_function_t *function, njs_value_t *args, +njs_vm_call(njs_vm_t *vm, njs_function_t *function, const njs_value_t *args, nxt_uint_t nargs) { u_char *current; @@ -531,7 +531,7 @@ njs_vm_pending(njs_vm_t *vm) nxt_int_t njs_vm_post_event(njs_vm_t *vm, njs_vm_event_t vm_event, - njs_value_t *args, nxt_uint_t nargs) + const njs_value_t *args, nxt_uint_t nargs) { njs_event_t *event; @@ -654,9 +654,9 @@ njs_vm_retval(njs_vm_t *vm) nxt_noinline void -njs_vm_retval_set(njs_vm_t *vm, njs_value_t *value) +njs_vm_retval_set(njs_vm_t *vm, const njs_value_t *value) { - vm->retval = *(njs_value_t *) value; + vm->retval = *value; } @@ -680,7 +680,7 @@ njs_ret_t njs_vm_retval_to_ext_string(nj njs_value_t * -njs_vm_object_prop(njs_vm_t *vm, njs_value_t *value, const nxt_str_t *key) +njs_vm_object_prop(njs_vm_t *vm, const njs_value_t *value, const nxt_str_t *key) { nxt_int_t ret; njs_object_prop_t *prop; diff -r c85b07c96e27 -r 72aa4d9aa606 njs/njs.h --- a/njs/njs.h Tue Jul 31 21:11:44 2018 +0300 +++ b/njs/njs.h Wed Aug 01 18:05:01 2018 +0300 @@ -48,8 +48,7 @@ typedef struct { 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) + ((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); @@ -162,7 +161,7 @@ NXT_EXPORT void njs_vm_destroy(njs_vm_t NXT_EXPORT nxt_int_t njs_vm_compile(njs_vm_t *vm, u_char **start, u_char *end); NXT_EXPORT njs_vm_t *njs_vm_clone(njs_vm_t *vm, njs_external_ptr_t external); NXT_EXPORT nxt_int_t njs_vm_call(njs_vm_t *vm, njs_function_t *function, - njs_value_t *args, nxt_uint_t nargs); + const njs_value_t *args, nxt_uint_t nargs); NXT_EXPORT njs_vm_event_t njs_vm_add_event(njs_vm_t *vm, njs_function_t *function, njs_host_event_t host_ev, @@ -170,7 +169,7 @@ NXT_EXPORT njs_vm_event_t njs_vm_add_eve NXT_EXPORT void njs_vm_del_event(njs_vm_t *vm, njs_vm_event_t vm_event); NXT_EXPORT nxt_int_t njs_vm_pending(njs_vm_t *vm); NXT_EXPORT nxt_int_t njs_vm_post_event(njs_vm_t *vm, njs_vm_event_t vm_event, - njs_value_t *args, nxt_uint_t nargs); + const njs_value_t *args, nxt_uint_t nargs); NXT_EXPORT nxt_int_t njs_vm_run(njs_vm_t *vm); @@ -179,7 +178,7 @@ NXT_EXPORT const njs_extern_t *njs_vm_ex NXT_EXPORT nxt_int_t njs_vm_external_create(njs_vm_t *vm, 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); + const nxt_str_t *var_name, const njs_value_t *value); NXT_EXPORT njs_external_ptr_t njs_vm_external(njs_vm_t *vm, const njs_value_t *value); @@ -188,7 +187,7 @@ NXT_EXPORT nxt_array_t *njs_vm_completio NXT_EXPORT njs_function_t *njs_vm_function(njs_vm_t *vm, nxt_str_t *name); NXT_EXPORT njs_value_t *njs_vm_retval(njs_vm_t *vm); -NXT_EXPORT void njs_vm_retval_set(njs_vm_t *vm, njs_value_t *value); +NXT_EXPORT void njs_vm_retval_set(njs_vm_t *vm, const njs_value_t *value); NXT_EXPORT u_char * njs_string_alloc(njs_vm_t *vm, njs_value_t *value, uint32_t size, uint32_t length); @@ -196,7 +195,7 @@ NXT_EXPORT njs_ret_t njs_string_create(n u_char *start, uint32_t size, uint32_t length); NXT_EXPORT nxt_int_t njs_value_string_copy(njs_vm_t *vm, nxt_str_t *retval, - njs_value_t *value, uintptr_t *next); + const njs_value_t *value, uintptr_t *next); NXT_EXPORT njs_ret_t njs_vm_value_to_ext_string(njs_vm_t *vm, nxt_str_t *dst, const njs_value_t *src, nxt_uint_t handle_exception); @@ -212,24 +211,24 @@ NXT_EXPORT void njs_value_data_set(njs_v NXT_EXPORT void njs_value_error_set(njs_vm_t *vm, njs_value_t *value, const char *fmt, ...); -NXT_EXPORT uint8_t njs_value_bool(njs_value_t *value); -NXT_EXPORT double njs_value_number(njs_value_t *value); -NXT_EXPORT void *njs_value_data(njs_value_t *value); -NXT_EXPORT njs_function_t *njs_value_function(njs_value_t *value); +NXT_EXPORT uint8_t njs_value_bool(const njs_value_t *value); +NXT_EXPORT double njs_value_number(const njs_value_t *value); +NXT_EXPORT void *njs_value_data(const njs_value_t *value); +NXT_EXPORT njs_function_t *njs_value_function(const njs_value_t *value); -NXT_EXPORT nxt_int_t njs_value_is_null(njs_value_t *value); -NXT_EXPORT nxt_int_t njs_value_is_void(njs_value_t *value); -NXT_EXPORT nxt_int_t njs_value_is_boolean(njs_value_t *value); -NXT_EXPORT nxt_int_t njs_value_is_number(njs_value_t *value); -NXT_EXPORT nxt_int_t njs_value_is_valid_number(njs_value_t *value); -NXT_EXPORT nxt_int_t njs_value_is_string(njs_value_t *value); -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 nxt_int_t njs_value_is_null(const njs_value_t *value); +NXT_EXPORT nxt_int_t njs_value_is_void(const njs_value_t *value); +NXT_EXPORT nxt_int_t njs_value_is_boolean(const njs_value_t *value); +NXT_EXPORT nxt_int_t njs_value_is_number(const njs_value_t *value); +NXT_EXPORT nxt_int_t njs_value_is_valid_number(const njs_value_t *value); +NXT_EXPORT nxt_int_t njs_value_is_string(const njs_value_t *value); +NXT_EXPORT nxt_int_t njs_value_is_object(const njs_value_t *value); +NXT_EXPORT nxt_int_t njs_value_is_function(const 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); +NXT_EXPORT njs_value_t *njs_vm_object_prop(njs_vm_t *vm, + const njs_value_t *value, const nxt_str_t *key); extern const nxt_mem_proto_t njs_vm_mem_cache_pool_proto; diff -r c85b07c96e27 -r 72aa4d9aa606 njs/njs_extern.c --- a/njs/njs_extern.c Tue Jul 31 21:11:44 2018 +0300 +++ b/njs/njs_extern.c Wed Aug 01 18:05:01 2018 +0300 @@ -193,7 +193,7 @@ njs_vm_external_create(njs_vm_t *vm, njs nxt_int_t njs_vm_external_bind(njs_vm_t *vm, const nxt_str_t *var_name, - njs_value_t *value) + const njs_value_t *value) { nxt_int_t ret; njs_extern_value_t *ev; diff -r c85b07c96e27 -r 72aa4d9aa606 njs/njs_function.c --- a/njs/njs_function.c Tue Jul 31 21:11:44 2018 +0300 +++ b/njs/njs_function.c Wed Aug 01 18:05:01 2018 +0300 @@ -144,7 +144,7 @@ njs_function_native_frame(njs_vm_t *vm, nxt_noinline njs_ret_t njs_function_frame(njs_vm_t *vm, njs_function_t *function, - const njs_value_t *this, njs_value_t *args, nxt_uint_t nargs, + const njs_value_t *this, const njs_value_t *args, nxt_uint_t nargs, nxt_bool_t ctor) { size_t size; diff -r c85b07c96e27 -r 72aa4d9aa606 njs/njs_function.h --- a/njs/njs_function.h Tue Jul 31 21:11:44 2018 +0300 +++ b/njs/njs_function.h Wed Aug 01 18:05:01 2018 +0300 @@ -158,7 +158,7 @@ njs_ret_t njs_function_native_frame(njs_ const njs_value_t *this, njs_value_t *args, nxt_uint_t nargs, size_t reserve, nxt_bool_t ctor); njs_ret_t njs_function_frame(njs_vm_t *vm, njs_function_t *function, - const njs_value_t *this, njs_value_t *args, nxt_uint_t nargs, + const njs_value_t *this, const njs_value_t *args, nxt_uint_t nargs, nxt_bool_t ctor); njs_ret_t njs_function_call(njs_vm_t *vm, njs_index_t retval, size_t advance); diff -r c85b07c96e27 -r 72aa4d9aa606 njs/njs_vm.c --- a/njs/njs_vm.c Tue Jul 31 21:11:44 2018 +0300 +++ b/njs/njs_vm.c Wed Aug 01 18:05:01 2018 +0300 @@ -3521,63 +3521,63 @@ memory_error: nxt_noinline uint8_t -njs_value_bool(njs_value_t *value) +njs_value_bool(const njs_value_t *value) { return value->data.truth; } nxt_noinline double -njs_value_number(njs_value_t *value) +njs_value_number(const njs_value_t *value) { return value->data.u.number; } nxt_noinline void * -njs_value_data(njs_value_t *value) +njs_value_data(const njs_value_t *value) { return value->data.u.data; } nxt_noinline njs_function_t * -njs_value_function(njs_value_t *value) +njs_value_function(const njs_value_t *value) { return value->data.u.function; } nxt_noinline nxt_int_t -njs_value_is_null(njs_value_t *value) +njs_value_is_null(const njs_value_t *value) { return njs_is_null(value); } nxt_noinline nxt_int_t -njs_value_is_void(njs_value_t *value) +njs_value_is_void(const njs_value_t *value) { return njs_is_void(value); } nxt_noinline nxt_int_t -njs_value_is_boolean(njs_value_t *value) +njs_value_is_boolean(const njs_value_t *value) { return njs_is_boolean(value); } nxt_noinline nxt_int_t -njs_value_is_number(njs_value_t *value) +njs_value_is_number(const njs_value_t *value) { return njs_is_number(value); } nxt_noinline nxt_int_t -njs_value_is_valid_number(njs_value_t *value) +njs_value_is_valid_number(const njs_value_t *value) { return njs_is_number(value) && !isnan(value->data.u.number) @@ -3586,28 +3586,28 @@ njs_value_is_valid_number(njs_value_t *v nxt_noinline nxt_int_t -njs_value_is_string(njs_value_t *value) +njs_value_is_string(const njs_value_t *value) { return njs_is_string(value); } nxt_noinline nxt_int_t -njs_value_is_object(njs_value_t *value) +njs_value_is_object(const njs_value_t *value) { return njs_is_object(value); } nxt_noinline nxt_int_t -njs_value_is_function(njs_value_t *value) +njs_value_is_function(const njs_value_t *value) { return njs_is_function(value); } nxt_int_t -njs_value_string_copy(njs_vm_t *vm, nxt_str_t *retval, njs_value_t *value, +njs_value_string_copy(njs_vm_t *vm, nxt_str_t *retval, const njs_value_t *value, uintptr_t *next) { uintptr_t n; From xeioex at nginx.com Thu Aug 2 16:40:18 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Thu, 02 Aug 2018 16:40:18 +0000 Subject: [njs] Setting exception values where appropriate. Message-ID: details: http://hg.nginx.org/njs/rev/d2cbea77122c branches: changeset: 582:d2cbea77122c user: Dmitry Volyntsev date: Thu Aug 02 19:39:55 2018 +0300 description: Setting exception values where appropriate. This fixes #42 issue on Github. diffstat: njs/njs_array.c | 21 ++++++++++++++++----- njs/njs_crypto.c | 27 ++++++++++----------------- njs/njs_date.c | 7 ++++--- njs/njs_error.c | 22 ++++++++-------------- njs/njs_extern.c | 15 ++++++++++++--- njs/njs_fs.c | 30 ++++++++++-------------------- njs/njs_function.c | 14 ++++++++++++-- njs/njs_json.c | 2 -- njs/njs_object.c | 28 ++++++++++++++++++++++------ njs/njs_regexp.c | 18 +++++++++++++++--- njs/njs_string.c | 8 ++------ njs/njs_time.c | 1 + njs/njs_variable.c | 5 +++++ njs/njs_vm.c | 6 ++++++ njs/test/njs_unit_test.c | 17 +++++++++++++---- 15 files changed, 136 insertions(+), 85 deletions(-) diffs (901 lines): diff -r 4586ae051111 -r d2cbea77122c njs/njs_array.c --- a/njs/njs_array.c Wed Aug 01 18:37:15 2018 +0300 +++ b/njs/njs_array.c Thu Aug 02 19:39:55 2018 +0300 @@ -109,20 +109,24 @@ static njs_ret_t njs_array_prototype_sor nxt_noinline njs_array_t * njs_array_alloc(njs_vm_t *vm, uint32_t length, uint32_t spare) { - uint32_t size; + size_t size; njs_array_t *array; array = nxt_mem_cache_alloc(vm->mem_cache_pool, sizeof(njs_array_t)); if (nxt_slow_path(array == NULL)) { - return NULL; + goto memory_error; } size = length + spare; + if (nxt_slow_path(size * sizeof(njs_value_t) < size)) { + goto memory_error; + } + array->data = nxt_mem_cache_align(vm->mem_cache_pool, sizeof(njs_value_t), size * sizeof(njs_value_t)); if (nxt_slow_path(array->data == NULL)) { - return NULL; + goto memory_error; } array->start = array->data; @@ -136,6 +140,12 @@ njs_array_alloc(njs_vm_t *vm, uint32_t l array->length = length; return array; + +memory_error: + + njs_memory_error(vm); + + return NULL; } @@ -194,6 +204,7 @@ njs_array_expand(njs_vm_t *vm, njs_array start = nxt_mem_cache_align(vm->mem_cache_pool, sizeof(njs_value_t), (prepend + size) * sizeof(njs_value_t)); if (nxt_slow_path(start == NULL)) { + njs_memory_error(vm); return NXT_ERROR; } @@ -230,7 +241,7 @@ njs_array_constructor(njs_vm_t *vm, njs_ size = (uint32_t) num; if ((double) size != num) { - njs_range_error(vm, NULL); + njs_range_error(vm, "Invalid array length"); return NXT_ERROR; } @@ -393,7 +404,6 @@ njs_array_prototype_length(njs_vm_t *vm, if (size > 0) { ret = njs_array_expand(vm, array, 0, size); if (nxt_slow_path(ret != NXT_OK)) { - njs_memory_error(vm); return NJS_ERROR; } @@ -846,6 +856,7 @@ njs_array_prototype_join(njs_vm_t *vm, n values = nxt_mem_cache_align(vm->mem_cache_pool, sizeof(njs_value_t), sizeof(njs_value_t) * max); if (nxt_slow_path(values == NULL)) { + njs_memory_error(vm); return NXT_ERROR; } diff -r 4586ae051111 -r d2cbea77122c njs/njs_crypto.c --- a/njs/njs_crypto.c Wed Aug 01 18:37:15 2018 +0300 +++ b/njs/njs_crypto.c Thu Aug 02 19:39:55 2018 +0300 @@ -142,9 +142,12 @@ njs_crypto_object_value_alloc(njs_vm_t * ov->object.extensible = 1; ov->object.__proto__ = &vm->prototypes[proto].object; + return ov; } - return ov; + njs_memory_error(vm); + + return NULL; } @@ -171,12 +174,13 @@ njs_crypto_create_hash(njs_vm_t *vm, njs hash = njs_crypto_object_value_alloc(vm, NJS_PROTOTYPE_CRYPTO_HASH); if (nxt_slow_path(hash == NULL)) { - goto memory_error; + return NJS_ERROR; } dgst = nxt_mem_cache_alloc(vm->mem_cache_pool, sizeof(njs_digest_t)); if (nxt_slow_path(dgst == NULL)) { - goto memory_error; + njs_memory_error(vm); + return NJS_ERROR; } dgst->alg = alg; @@ -190,12 +194,6 @@ njs_crypto_create_hash(njs_vm_t *vm, njs vm->retval.data.truth = 1; return NJS_OK; - -memory_error: - - njs_memory_error(vm); - - return NJS_ERROR; } @@ -412,7 +410,8 @@ njs_crypto_create_hmac(njs_vm_t *vm, njs ctx = nxt_mem_cache_alloc(vm->mem_cache_pool, sizeof(njs_hmac_t)); if (nxt_slow_path(ctx == NULL)) { - goto memory_error; + njs_memory_error(vm); + return NJS_ERROR; } ctx->alg = alg; @@ -443,7 +442,7 @@ njs_crypto_create_hmac(njs_vm_t *vm, njs hmac = njs_crypto_object_value_alloc(vm, NJS_PROTOTYPE_CRYPTO_HMAC); if (nxt_slow_path(hmac == NULL)) { - goto memory_error; + return NJS_ERROR; } njs_value_data_set(&hmac->value, ctx); @@ -453,12 +452,6 @@ njs_crypto_create_hmac(njs_vm_t *vm, njs vm->retval.data.truth = 1; return NJS_OK; - -memory_error: - - njs_memory_error(vm); - - return NJS_ERROR; } diff -r 4586ae051111 -r d2cbea77122c njs/njs_date.c --- a/njs/njs_date.c Wed Aug 01 18:37:15 2018 +0300 +++ b/njs/njs_date.c Thu Aug 02 19:39:55 2018 +0300 @@ -129,6 +129,7 @@ njs_date_constructor(njs_vm_t *vm, njs_v date = nxt_mem_cache_alloc(vm->mem_cache_pool, sizeof(njs_date_t)); if (nxt_slow_path(date == NULL)) { + njs_memory_error(vm); return NXT_ERROR; } @@ -1052,9 +1053,9 @@ njs_date_to_string(njs_vm_t *vm, njs_val return njs_string_new(vm, retval, buf, size, size); } - njs_range_error(vm, NULL); - - return NXT_ERROR; + vm->retval = njs_string_invalid_date; + + return NXT_OK; } diff -r 4586ae051111 -r d2cbea77122c njs/njs_error.c --- a/njs/njs_error.c Wed Aug 01 18:37:15 2018 +0300 +++ b/njs/njs_error.c Thu Aug 02 19:39:55 2018 +0300 @@ -36,23 +36,15 @@ njs_exception_error_create(njs_vm_t *vm, ret = njs_string_new(vm, &string, (const u_char *) buf, size, size); if (nxt_slow_path(ret != NXT_OK)) { - goto memory_error; + return; } error = njs_error_alloc(vm, type, NULL, &string); - if (nxt_slow_path(error == NULL)) { - goto memory_error; + if (nxt_fast_path(error != NULL)) { + vm->retval.data.u.object = error; + vm->retval.type = type; + vm->retval.data.truth = 1; } - - vm->retval.data.u.object = error; - vm->retval.type = type; - vm->retval.data.truth = 1; - - return; - -memory_error: - - njs_memory_error(vm); } @@ -67,6 +59,7 @@ njs_error_alloc(njs_vm_t *vm, njs_value_ error = nxt_mem_cache_alloc(vm->mem_cache_pool, sizeof(njs_object_t)); if (nxt_slow_path(error == NULL)) { + njs_memory_error(vm); return NULL; } @@ -94,6 +87,7 @@ njs_error_alloc(njs_vm_t *vm, njs_value_ ret = nxt_lvlhsh_insert(&error->hash, &lhq); if (nxt_slow_path(ret != NXT_OK)) { + njs_internal_error(vm, NULL); return NULL; } } @@ -114,6 +108,7 @@ njs_error_alloc(njs_vm_t *vm, njs_value_ ret = nxt_lvlhsh_insert(&error->hash, &lhq); if (nxt_slow_path(ret != NXT_OK)) { + njs_internal_error(vm, NULL); return NULL; } } @@ -138,7 +133,6 @@ njs_error_create(njs_vm_t *vm, njs_value error = njs_error_alloc(vm, type, NULL, value); if (nxt_slow_path(error == NULL)) { - njs_memory_error(vm); return NXT_ERROR; } diff -r 4586ae051111 -r d2cbea77122c njs/njs_extern.c --- a/njs/njs_extern.c Wed Aug 01 18:37:15 2018 +0300 +++ b/njs/njs_extern.c Thu Aug 02 19:39:55 2018 +0300 @@ -81,7 +81,7 @@ njs_vm_external_add(njs_vm_t *vm, nxt_lv do { ext = nxt_mem_cache_alloc(vm->mem_cache_pool, sizeof(njs_extern_t)); if (nxt_slow_path(ext == NULL)) { - return NULL; + goto memory_error; } ext->name = external->name; @@ -100,7 +100,7 @@ njs_vm_external_add(njs_vm_t *vm, nxt_lv function = nxt_mem_cache_zalloc(vm->mem_cache_pool, sizeof(njs_function_t)); if (nxt_slow_path(function == NULL)) { - return NULL; + goto memory_error; } /* @@ -129,7 +129,7 @@ njs_vm_external_add(njs_vm_t *vm, nxt_lv child = njs_vm_external_add(vm, &ext->hash, external->properties, external->nproperties); if (nxt_slow_path(child == NULL)) { - return NULL; + goto memory_error; } } @@ -144,6 +144,7 @@ njs_vm_external_add(njs_vm_t *vm, nxt_lv ret = nxt_lvlhsh_insert(hash, &lhq); if (nxt_slow_path(ret != NXT_OK)) { + njs_internal_error(vm, NULL); return NULL; } } @@ -154,6 +155,12 @@ njs_vm_external_add(njs_vm_t *vm, nxt_lv } while (n != 0); return ext; + +memory_error: + + njs_memory_error(vm); + + return NULL; } @@ -206,6 +213,7 @@ njs_vm_external_bind(njs_vm_t *vm, const ev = nxt_mem_cache_align(vm->mem_cache_pool, sizeof(njs_value_t), sizeof(njs_extern_value_t)); if (nxt_slow_path(ev == NULL)) { + njs_memory_error(vm); return NXT_ERROR; } @@ -221,6 +229,7 @@ njs_vm_external_bind(njs_vm_t *vm, const ret = nxt_lvlhsh_insert(&vm->externals_hash, &lhq); if (nxt_slow_path(ret != NXT_OK)) { + njs_internal_error(vm, NULL); return ret; } diff -r 4586ae051111 -r d2cbea77122c njs/njs_fs.c --- a/njs/njs_fs.c Wed Aug 01 18:37:15 2018 +0300 +++ b/njs/njs_fs.c Thu Aug 02 19:39:55 2018 +0300 @@ -221,7 +221,7 @@ njs_fs_read_file(njs_vm_t *vm, njs_value start = njs_string_alloc(vm, &arguments[2], sb.st_size, length); if (nxt_slow_path(start == NULL)) { - goto memory_error; + goto fail; } p = start; @@ -286,14 +286,12 @@ done: return njs_function_apply(vm, callback->data.u.function, arguments, 3, (njs_index_t) &vm->retval); -memory_error: +fail: if (fd != -1) { (void) close(fd); } - njs_memory_error(vm); - return NJS_ERROR; } @@ -420,7 +418,7 @@ njs_fs_read_file_sync(njs_vm_t *vm, njs_ start = njs_string_alloc(vm, &vm->retval, sb.st_size, length); if (nxt_slow_path(start == NULL)) { - goto memory_error; + goto fail; } p = start; @@ -472,14 +470,12 @@ done: return NJS_OK; -memory_error: +fail: if (fd != -1) { (void) close(fd); } - njs_memory_error(vm); - return NJS_ERROR; } @@ -898,12 +894,12 @@ static njs_ret_t njs_fs_error(njs_vm_t * ret = njs_string_new(vm, &string, (u_char *) description, size, size); if (nxt_slow_path(ret != NXT_OK)) { - goto memory_error; + return NJS_ERROR; } error = njs_error_alloc(vm, NJS_OBJECT_ERROR, NULL, &string); if (nxt_slow_path(error == NULL)) { - goto memory_error; + return NJS_ERROR; } lhq.replace = 0; @@ -920,7 +916,7 @@ static njs_ret_t njs_fs_error(njs_vm_t * prop = njs_object_prop_alloc(vm, &njs_fs_errno_string, &value, 1); if (nxt_slow_path(prop == NULL)) { - goto memory_error; + return NJS_ERROR; } lhq.value = prop; @@ -939,7 +935,7 @@ static njs_ret_t njs_fs_error(njs_vm_t * prop = njs_object_prop_alloc(vm, &njs_fs_path_string, path, 1); if (nxt_slow_path(prop == NULL)) { - goto memory_error; + return NJS_ERROR; } lhq.value = prop; @@ -955,7 +951,7 @@ static njs_ret_t njs_fs_error(njs_vm_t * size = strlen(syscall); ret = njs_string_new(vm, &string, (u_char *) syscall, size, size); if (nxt_slow_path(ret != NXT_OK)) { - goto memory_error; + return NJS_ERROR; } lhq.key = nxt_string_value("sycall"); @@ -964,7 +960,7 @@ static njs_ret_t njs_fs_error(njs_vm_t * prop = njs_object_prop_alloc(vm, &njs_fs_syscall_string, &string, 1); if (nxt_slow_path(prop == NULL)) { - goto memory_error; + return NJS_ERROR; } lhq.value = prop; @@ -981,12 +977,6 @@ static njs_ret_t njs_fs_error(njs_vm_t * retval->data.truth = 1; return NJS_OK; - -memory_error: - - njs_memory_error(vm); - - return NJS_ERROR; } diff -r 4586ae051111 -r d2cbea77122c njs/njs_function.c --- a/njs/njs_function.c Wed Aug 01 18:37:15 2018 +0300 +++ b/njs/njs_function.c Thu Aug 02 19:39:55 2018 +0300 @@ -35,11 +35,16 @@ njs_function_alloc(njs_vm_t *vm) function->u.lambda = nxt_mem_cache_zalloc(vm->mem_cache_pool, sizeof(njs_function_lambda_t)); if (nxt_slow_path(function->u.lambda == NULL)) { + njs_memory_error(vm); return NULL; } + + return function; } - return function; + njs_memory_error(vm); + + return NULL; } @@ -62,7 +67,8 @@ njs_function_value_copy(njs_vm_t *vm, nj copy = nxt_mem_cache_alloc(vm->mem_cache_pool, size); if (nxt_slow_path(copy == NULL)) { - return copy; + njs_memory_error(vm); + return NULL; } value->data.u.function = copy; @@ -247,6 +253,7 @@ njs_function_frame_alloc(njs_vm_t *vm, s frame = nxt_mem_cache_align(vm->mem_cache_pool, sizeof(njs_value_t), spare_size); if (nxt_slow_path(frame == NULL)) { + njs_memory_error(vm); return NULL; } @@ -365,6 +372,7 @@ njs_function_call(njs_vm_t *vm, njs_inde closure = nxt_mem_cache_align(vm->mem_cache_pool, sizeof(njs_value_t), size); if (nxt_slow_path(closure == NULL)) { + njs_memory_error(vm); return NXT_ERROR; } @@ -618,6 +626,7 @@ njs_function_prototype_bind(njs_vm_t *vm function = nxt_mem_cache_alloc(vm->mem_cache_pool, sizeof(njs_function_t)); if (nxt_slow_path(function == NULL)) { + njs_memory_error(vm); return NXT_ERROR; } @@ -640,6 +649,7 @@ njs_function_prototype_bind(njs_vm_t *vm values = nxt_mem_cache_alloc(vm->mem_cache_pool, size); if (nxt_slow_path(values == NULL)) { + njs_memory_error(vm); nxt_mem_cache_free(vm->mem_cache_pool, function); return NXT_ERROR; } diff -r 4586ae051111 -r d2cbea77122c njs/njs_json.c --- a/njs/njs_json.c Wed Aug 01 18:37:15 2018 +0300 +++ b/njs/njs_json.c Thu Aug 02 19:39:55 2018 +0300 @@ -535,7 +535,6 @@ njs_json_parse_array(njs_json_parse_ctx_ array = njs_array_alloc(ctx->vm, 0, 0); if (nxt_slow_path(array == NULL)) { - njs_memory_error(ctx->vm); return NULL; } @@ -812,7 +811,6 @@ njs_json_parse_string(njs_json_parse_ctx ret = njs_string_create(ctx->vm, value, (u_char *) start, size, length); if (nxt_slow_path(ret != NXT_OK)) { - njs_memory_error(ctx->vm); return NULL; } diff -r 4586ae051111 -r d2cbea77122c njs/njs_object.c --- a/njs/njs_object.c Wed Aug 01 18:37:15 2018 +0300 +++ b/njs/njs_object.c Thu Aug 02 19:39:55 2018 +0300 @@ -34,9 +34,12 @@ njs_object_alloc(njs_vm_t *vm) object->type = NJS_OBJECT; object->shared = 0; object->extensible = 1; + return object; } - return object; + njs_memory_error(vm); + + return NULL; } @@ -58,9 +61,12 @@ njs_object_value_copy(njs_vm_t *vm, njs_ object->__proto__ = &vm->prototypes[NJS_PROTOTYPE_OBJECT].object; object->shared = 0; value->data.u.object = object; + return object; } - return object; + njs_memory_error(vm); + + return NULL; } @@ -83,9 +89,13 @@ njs_object_value_alloc(njs_vm_t *vm, con ov->object.__proto__ = &vm->prototypes[index].object; ov->value = *value; + + return &ov->object; } - return &ov->object; + njs_memory_error(vm); + + return NULL; } @@ -107,6 +117,7 @@ njs_object_hash_create(njs_vm_t *vm, nxt ret = nxt_lvlhsh_insert(hash, &lhq); if (nxt_slow_path(ret != NXT_OK)) { + njs_internal_error(vm, NULL); return NXT_ERROR; } @@ -183,9 +194,12 @@ njs_object_prop_alloc(njs_vm_t *vm, cons prop->enumerable = attributes; prop->writable = attributes; prop->configurable = attributes; + return prop; } - return prop; + njs_memory_error(vm); + + return NULL; } @@ -988,6 +1002,7 @@ njs_object_get_own_property_descriptor(n ret = nxt_lvlhsh_insert(&descriptor->hash, &lhq); if (nxt_slow_path(ret != NXT_OK)) { + njs_internal_error(vm, NULL); return NXT_ERROR; } @@ -1005,6 +1020,7 @@ njs_object_get_own_property_descriptor(n ret = nxt_lvlhsh_insert(&descriptor->hash, &lhq); if (nxt_slow_path(ret != NXT_OK)) { + njs_internal_error(vm, NULL); return NXT_ERROR; } @@ -1022,6 +1038,7 @@ njs_object_get_own_property_descriptor(n ret = nxt_lvlhsh_insert(&descriptor->hash, &lhq); if (nxt_slow_path(ret != NXT_OK)) { + njs_internal_error(vm, NULL); return NXT_ERROR; } @@ -1039,6 +1056,7 @@ njs_object_get_own_property_descriptor(n ret = nxt_lvlhsh_insert(&descriptor->hash, &lhq); if (nxt_slow_path(ret != NXT_OK)) { + njs_internal_error(vm, NULL); return NXT_ERROR; } @@ -1395,7 +1413,6 @@ njs_property_prototype_create(njs_vm_t * return &prop->value; } - /* Memory allocation or NXT_DECLINED error. */ njs_internal_error(vm, NULL); return NULL; @@ -1638,7 +1655,6 @@ njs_property_constructor_create(njs_vm_t return &prop->value; } - /* Memory allocation or NXT_DECLINED error. */ njs_internal_error(vm, NULL); return NULL; diff -r 4586ae051111 -r d2cbea77122c njs/njs_regexp.c --- a/njs/njs_regexp.c Wed Aug 01 18:37:15 2018 +0300 +++ b/njs/njs_regexp.c Thu Aug 02 19:39:55 2018 +0300 @@ -34,11 +34,13 @@ njs_regexp_init(njs_vm_t *vm) vm->regex_context = nxt_regex_context_create(njs_regexp_malloc, njs_regexp_free, vm->mem_cache_pool); if (nxt_slow_path(vm->regex_context == NULL)) { + njs_memory_error(vm); return NXT_ERROR; } vm->single_match_data = nxt_regex_match_data(NULL, vm->regex_context); if (nxt_slow_path(vm->single_match_data == NULL)) { + njs_memory_error(vm); return NXT_ERROR; } @@ -66,6 +68,7 @@ njs_ret_t njs_regexp_constructor(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused) { + u_char *start; nxt_str_t string; njs_regexp_flags_t flags; @@ -81,9 +84,12 @@ njs_regexp_constructor(njs_vm_t *vm, njs default: njs_string_get(&args[2], &string); - flags = njs_regexp_flags(&string.start, string.start + string.length, - 1); + start = string.start; + + flags = njs_regexp_flags(&start, start + string.length, 1); if (nxt_slow_path(flags < 0)) { + njs_syntax_error(vm, "Invalid RegExp flags \"%.*s\"", + (int) string.length, string.start); return NXT_ERROR; } @@ -267,6 +273,7 @@ njs_regexp_pattern_create(njs_vm_t *vm, sizeof(njs_regexp_pattern_t) + 1 + length + size + 1); if (nxt_slow_path(pattern == NULL)) { + njs_memory_error(vm); return NULL; } @@ -434,9 +441,12 @@ njs_regexp_alloc(njs_vm_t *vm, njs_regex regexp->object.extensible = 1; regexp->last_index = 0; regexp->pattern = pattern; + return regexp; } - return regexp; + njs_memory_error(vm); + + return NULL; } @@ -655,6 +665,7 @@ njs_regexp_prototype_exec(njs_vm_t *vm, match_data = nxt_regex_match_data(&pattern->regex[type], vm->regex_context); if (nxt_slow_path(match_data == NULL)) { + njs_memory_error(vm); return NXT_ERROR; } @@ -744,6 +755,7 @@ njs_regexp_exec_result(njs_vm_t *vm, njs ret = nxt_lvlhsh_insert(&array->object.hash, &lhq); if (nxt_slow_path(ret != NXT_OK)) { + njs_internal_error(vm, NULL); goto fail; } diff -r 4586ae051111 -r d2cbea77122c njs/njs_string.c --- a/njs/njs_string.c Wed Aug 01 18:37:15 2018 +0300 +++ b/njs/njs_string.c Thu Aug 02 19:39:55 2018 +0300 @@ -147,6 +147,7 @@ njs_string_create(njs_vm_t *vm, njs_valu string = nxt_mem_cache_alloc(vm->mem_cache_pool, sizeof(njs_string_t)); if (nxt_slow_path(string == NULL)) { + njs_memory_error(vm); return NXT_ERROR; } @@ -174,8 +175,6 @@ njs_string_new(njs_vm_t *vm, njs_value_t return NXT_OK; } - njs_memory_error(vm); - return NXT_ERROR; } @@ -293,8 +292,6 @@ njs_string_hex(njs_vm_t *vm, njs_value_t return NXT_OK; } - njs_memory_error(vm); - return NXT_ERROR; } @@ -386,7 +383,6 @@ njs_string_base64(njs_vm_t *vm, njs_valu dst.start = njs_string_alloc(vm, &vm->retval, dst.length, dst.length); if (nxt_slow_path(dst.start == NULL)) { - njs_memory_error(vm); return NXT_ERROR; } @@ -418,7 +414,6 @@ njs_string_base64url(njs_vm_t *vm, njs_v dst.start = njs_string_alloc(vm, &vm->retval, dst.length, dst.length); if (nxt_slow_path(dst.start == NULL)) { - njs_memory_error(vm); return NXT_ERROR; } @@ -491,6 +486,7 @@ njs_string_validate(njs_vm_t *vm, njs_st start = nxt_mem_cache_alloc(vm->mem_cache_pool, new_size); if (nxt_slow_path(start == NULL)) { + njs_memory_error(vm); return NXT_ERROR; } diff -r 4586ae051111 -r d2cbea77122c njs/njs_time.c --- a/njs/njs_time.c Wed Aug 01 18:37:15 2018 +0300 +++ b/njs/njs_time.c Thu Aug 02 19:39:55 2018 +0300 @@ -71,6 +71,7 @@ njs_set_timeout(njs_vm_t *vm, njs_value_ memory_error: njs_memory_error(vm); + return NJS_ERROR; } diff -r 4586ae051111 -r d2cbea77122c njs/njs_variable.c --- a/njs/njs_variable.c Wed Aug 01 18:37:15 2018 +0300 +++ b/njs/njs_variable.c Thu Aug 02 19:39:55 2018 +0300 @@ -83,6 +83,7 @@ njs_builtin_add(njs_vm_t *vm, njs_parser ret = nxt_lvlhsh_insert(&scope->variables, &lhq); if (nxt_fast_path(ret == NXT_OK)) { + njs_internal_error(vm, NULL); return var; } @@ -397,6 +398,7 @@ njs_variable_get(njs_vm_t *vm, njs_parse value = nxt_mem_cache_align(vm->mem_cache_pool, sizeof(njs_value_t), sizeof(njs_value_t)); if (nxt_slow_path(value == NULL)) { + njs_memory_error(vm); return NULL; } @@ -503,6 +505,7 @@ njs_variable_alloc(njs_vm_t *vm, nxt_str var = nxt_mem_cache_zalloc(vm->mem_cache_pool, sizeof(njs_variable_t)); if (nxt_slow_path(var == NULL)) { + njs_memory_error(vm); return NULL; } @@ -533,6 +536,8 @@ njs_name_copy(njs_vm_t *vm, nxt_str_t *d return NXT_OK; } + njs_memory_error(vm); + return NXT_ERROR; } diff -r 4586ae051111 -r d2cbea77122c njs/njs_vm.c --- a/njs/njs_vm.c Wed Aug 01 18:37:15 2018 +0300 +++ b/njs/njs_vm.c Thu Aug 02 19:39:55 2018 +0300 @@ -383,6 +383,7 @@ njs_vmcode_function(njs_vm_t *vm, njs_va function = nxt_mem_cache_zalloc(vm->mem_cache_pool, size); if (nxt_slow_path(function == NULL)) { + njs_memory_error(vm); return NXT_ERROR; } @@ -935,6 +936,7 @@ njs_method_private_copy(njs_vm_t *vm, nj prop = nxt_mem_cache_alloc(vm->mem_cache_pool, sizeof(njs_object_prop_t)); if (nxt_slow_path(prop == NULL)) { + njs_memory_error(vm); return NXT_ERROR; } @@ -968,6 +970,7 @@ njs_vmcode_property_foreach(njs_vm_t *vm next = nxt_mem_cache_alloc(vm->mem_cache_pool, sizeof(njs_property_next_t)); if (nxt_slow_path(next == NULL)) { + njs_memory_error(vm); return NXT_ERROR; } @@ -2721,6 +2724,7 @@ njs_vmcode_try_start(njs_vm_t *vm, njs_v if (vm->top_frame->exception.catch != NULL) { e = nxt_mem_cache_alloc(vm->mem_cache_pool, sizeof(njs_exception_t)); if (nxt_slow_path(e == NULL)) { + njs_memory_error(vm); return NXT_ERROR; } @@ -3298,6 +3302,7 @@ again: if (size != NJS_STRING_LONG) { start = nxt_mem_cache_alloc(vm->mem_cache_pool, size); if (nxt_slow_path(start == NULL)) { + njs_memory_error(vm); return NXT_ERROR; } @@ -3332,6 +3337,7 @@ again: p = nxt_mem_cache_alloc(vm->mem_cache_pool, len); if (p == NULL) { + njs_memory_error(vm); return NXT_ERROR; } diff -r 4586ae051111 -r d2cbea77122c njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Wed Aug 01 18:37:15 2018 +0300 +++ b/njs/test/njs_unit_test.c Thu Aug 02 19:39:55 2018 +0300 @@ -5566,6 +5566,9 @@ static njs_unit_test_t njs_test[] = { nxt_string("var r = new RegExp('abc', 'i'); r.test('00ABC11')"), nxt_string("true") }, + { nxt_string("new RegExp('', 'x')"), + nxt_string("SyntaxError: Invalid RegExp flags \"x\"") }, + { nxt_string("[0].map(RegExp().toString)"), nxt_string("TypeError: 'this' argument is not a regexp") }, @@ -6081,16 +6084,19 @@ static njs_unit_test_t njs_test[] = nxt_string("1,two,3") }, { nxt_string("var a = Array(-1)"), - nxt_string("RangeError") }, + nxt_string("RangeError: Invalid array length") }, { nxt_string("var a = Array(2.5)"), - nxt_string("RangeError") }, + nxt_string("RangeError: Invalid array length") }, { nxt_string("var a = Array(NaN)"), - nxt_string("RangeError") }, + nxt_string("RangeError: Invalid array length") }, { nxt_string("var a = Array(Infinity)"), - nxt_string("RangeError") }, + nxt_string("RangeError: Invalid array length") }, + + { nxt_string("var a = Array(1111111111)"), + nxt_string("MemoryError") }, { nxt_string("var a = new Array(3); a"), nxt_string(",,") }, @@ -7533,6 +7539,9 @@ static njs_unit_test_t njs_test[] = { nxt_string("var d = new Date(); d.__proto__ === Date.prototype"), nxt_string("true") }, + { nxt_string("new Date(NaN)"), + nxt_string("Invalid Date") }, + { nxt_string("[0].map(new Date().getDate)"), nxt_string("TypeError: cannot convert void to date") }, From dnj0496 at gmail.com Thu Aug 2 19:29:14 2018 From: dnj0496 at gmail.com (Dk Jack) Date: Thu, 2 Aug 2018 12:29:14 -0700 Subject: post body Message-ID: Hi, In my module, I'd like to look into the post body to decide if the request should be allowed to proceed to origin server or not. Based on the examples I could find I've coded this in my module. After some trial and error it seems to be working. I am not sure if my implementation is 100% correct. I would appreciate it if someone can go over my code below and let me know if my implementation is correct. Especially, the body_complete_handler. Thanks. Regards, Dk. static ngx_int_t mod_setup_body_handler(ngx_http_request_t* r); static void mod_body_complete_handler(ngx_http_request_t* r); static ngx_int_t mod_extract_post_body(ngx_http_request_t *r, char *data, size_t *dsize); static ngx_int_t ngx_http_request_handler(ngx_http_request_t *r) { .... if ((NGX_HTTP_POST == r->method) || (NGX_HTTP_PUT == r->method)) { return mod_setup_body_handler(r); } ... } ngx_int_t mod_setup_body_handler(ngx_http_request_t* r) { ngx_int_t rc; r->request_body_in_single_buf = 1; r->request_body_in_persistent_file = 1; r->request_body_in_clean_file = 1; rc = ngx_http_read_client_request_body(r, mod_body_complete_handler); if (rc == NGX_ERROR) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "read req. body error"); return rc; } if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "read req. body error. special response"); return rc; } if (rc == NGX_AGAIN) { /* * nginx will call the body_received when needed. Returning * NGX_DONE will prevent nginx from calling ngx_http_finalize_request * (which we will call in body_received) */ return NGX_DONE; } return NGX_DECLINED; } void mod_body_complete_handler(ngx_http_request_t* r) { ngx_http_request_t* r = mNginxRequest; if(r->request_body == NULL) { // callback was called but body is empty. Setup handler again. mod_setup_body_handler(bh_ptr); return; } else if (r->request_body->rest) { // we don't have the complete body. Complete callback will be called again. return; } if (NULL == mNginxRequest->request_body->temp_file) { size_t dsize = 64*1024; char data[dsize] if (mod_extract_post_body(r, data, dsize) == NGX_OK) { // we have the complete body. int rc = mod_allow_request(body, dsize); // returns NGX_OK or 4XX. if (rc != NGX_OK) { // allow req. has already sent a custom response if rc != NGX_OK. ngx_http_finalize_request(r, NGX_OK); return; } } } // ???? not having this cause request to hang. ngx_http_core_run_phases(r); } ngx_int_t mod_extract_post_body(ngx_http_request_t *r, char *data, size_t *dsize) { size_t buf_size = *dsize; if (NULL == r->request_body->temp_file) { // we have body in buffer chain. ngx_buf_t *buf; ngx_chain_t *cl; size_t data_start_pos = 0; cl = r->request_body->bufs; // copy the body into our temporary buffer. for (;NULL != cl; cl = cl->next) { buf = cl->buf; size_t bsize = buf->last - buf->pos; if ((data_start_pos+bsize) > buf_size) { // data is bigger than the input buffer size, abort *dsize = data_start_pos; *(data+*dsize) = '\0'; return NGX_ERROR; } ngx_memcpy((data+data_start_pos), buf->pos, bsize); data_start_pos += bsize; } *dsize = data_start_pos; *(data+*dsize) = '\0'; return NGX_OK; } else { // body in file not implemented yet. } return NGX_ERROR; } -------------- next part -------------- An HTML attachment was scrubbed... URL: From pluknet at nginx.com Mon Aug 6 12:46:18 2018 From: pluknet at nginx.com (Sergey Kandaurov) Date: Mon, 06 Aug 2018 12:46:18 +0000 Subject: [nginx] Dav: removed dead store after 8e7a5de61664. Message-ID: details: http://hg.nginx.org/nginx/rev/bb40db0e380d branches: changeset: 7331:bb40db0e380d user: Sergey Kandaurov date: Thu Aug 02 13:19:48 2018 +0300 description: Dav: removed dead store after 8e7a5de61664. Found by Clang Static Analyzer. diffstat: src/http/modules/ngx_http_dav_module.c | 2 -- 1 files changed, 0 insertions(+), 2 deletions(-) diffs (12 lines): diff -r 8e7a5de61664 -r bb40db0e380d src/http/modules/ngx_http_dav_module.c --- a/src/http/modules/ngx_http_dav_module.c Wed Aug 01 02:12:21 2018 +0300 +++ b/src/http/modules/ngx_http_dav_module.c Thu Aug 02 13:19:48 2018 +0300 @@ -841,8 +841,6 @@ overwrite_done: return NGX_HTTP_INTERNAL_SERVER_ERROR; } - dlcf = ngx_http_get_module_loc_conf(r, ngx_http_dav_module); - cf.size = ngx_file_size(&fi); cf.buf_size = 0; cf.access = ngx_file_access(&fi); From mdounin at mdounin.ru Tue Aug 7 12:58:25 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 07 Aug 2018 12:58:25 +0000 Subject: [nginx] SSL: enabled TLSv1.3 with BoringSSL. Message-ID: details: http://hg.nginx.org/nginx/rev/7ad0f4ace359 branches: changeset: 7332:7ad0f4ace359 user: Maxim Dounin date: Tue Aug 07 02:15:28 2018 +0300 description: SSL: enabled TLSv1.3 with BoringSSL. BoringSSL currently requires SSL_CTX_set_max_proto_version(TLS1_3_VERSION) to be able to enable TLS 1.3. This is because by default max protocol version is set to TLS 1.2, and the SSL_OP_NO_* options are merely used as a blacklist within the version range specified using the SSL_CTX_set_min_proto_version() and SSL_CTX_set_max_proto_version() functions. With this change, we now call SSL_CTX_set_max_proto_version() with an explicit maximum version set. This enables TLS 1.3 with BoringSSL. As a side effect, this change also limits maximum protocol version to the newest protocol we know about, TLS 1.3. This seems to be a good change, as enabling unknown protocols might have unexpected results. Additionally, we now explicitly call SSL_CTX_set_min_proto_version() with 0. This is expected to help with Debian system-wide default of MinProtocol set to TLSv1.2, see http://mailman.nginx.org/pipermail/nginx-ru/2017-October/060411.html. Note that there is no SSL_CTX_set_min_proto_version macro in BoringSSL, so we call SSL_CTX_set_min_proto_version() and SSL_CTX_set_max_proto_version() as long as the TLS1_3_VERSION macro is defined. diffstat: src/event/ngx_event_openssl.c | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-) diffs (15 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 @@ -331,6 +331,11 @@ ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_ } #endif +#ifdef TLS1_3_VERSION + SSL_CTX_set_min_proto_version(ssl->ctx, 0); + SSL_CTX_set_max_proto_version(ssl->ctx, TLS1_3_VERSION); +#endif + #ifdef SSL_OP_NO_COMPRESSION SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_COMPRESSION); #endif From mdounin at mdounin.ru Tue Aug 7 12:58:27 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 07 Aug 2018 12:58:27 +0000 Subject: [nginx] SSL: support for TLSv1.3 early data with BoringSSL. Message-ID: details: http://hg.nginx.org/nginx/rev/ba971deb4b44 branches: changeset: 7333:ba971deb4b44 user: Maxim Dounin date: Tue Aug 07 02:16:07 2018 +0300 description: SSL: support for TLSv1.3 early data with BoringSSL. Early data AKA 0-RTT mode is enabled as long as "ssl_early_data on" is specified in the configuration (default is off). The $ssl_early_data variable evaluates to "1" if the SSL handshake isn't yet completed, and can be used to set the Early-Data header as per draft-ietf-httpbis-replay-04. diffstat: src/event/ngx_event_openssl.c | 38 ++++++++++++++++++++++++++++++++++ src/event/ngx_event_openssl.h | 4 +++ src/http/modules/ngx_http_ssl_module.c | 18 ++++++++++++++++ src/http/modules/ngx_http_ssl_module.h | 1 + 4 files changed, 61 insertions(+), 0 deletions(-) diffs (143 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 @@ -1169,6 +1169,29 @@ ngx_ssl_ecdh_curve(ngx_conf_t *cf, ngx_s ngx_int_t +ngx_ssl_early_data(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_uint_t enable) +{ + if (!enable) { + return NGX_OK; + } + +#ifdef SSL_ERROR_EARLY_DATA_REJECTED + + /* BoringSSL */ + + SSL_CTX_set_early_data_enabled(ssl->ctx, 1); + +#else + ngx_log_error(NGX_LOG_WARN, ssl->log, 0, + "\"ssl_early_data\" is not supported on this platform, " + "ignored"); +#endif + + return NGX_OK; +} + + +ngx_int_t ngx_ssl_client_session_cache(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_uint_t enable) { if (!enable) { @@ -3624,6 +3647,21 @@ ngx_ssl_get_session_reused(ngx_connectio ngx_int_t +ngx_ssl_get_early_data(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) +{ + s->len = 0; + +#ifdef SSL_ERROR_EARLY_DATA_REJECTED + if (SSL_in_early_data(c->ssl->connection)) { + ngx_str_set(s, "1"); + } +#endif + + return NGX_OK; +} + + +ngx_int_t ngx_ssl_get_server_name(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) { #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h --- a/src/event/ngx_event_openssl.h +++ b/src/event/ngx_event_openssl.h @@ -171,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_early_data(ngx_conf_t *cf, ngx_ssl_t *ssl, + ngx_uint_t enable); ngx_int_t ngx_ssl_client_session_cache(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_uint_t enable); ngx_int_t ngx_ssl_session_cache(ngx_ssl_t *ssl, ngx_str_t *sess_ctx, @@ -213,6 +215,8 @@ ngx_int_t ngx_ssl_get_session_id(ngx_con ngx_str_t *s); ngx_int_t ngx_ssl_get_session_reused(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s); +ngx_int_t ngx_ssl_get_early_data(ngx_connection_t *c, ngx_pool_t *pool, + ngx_str_t *s); ngx_int_t ngx_ssl_get_server_name(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s); ngx_int_t ngx_ssl_get_raw_certificate(ngx_connection_t *c, ngx_pool_t *pool, diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c --- a/src/http/modules/ngx_http_ssl_module.c +++ b/src/http/modules/ngx_http_ssl_module.c @@ -239,6 +239,13 @@ static ngx_command_t ngx_http_ssl_comma offsetof(ngx_http_ssl_srv_conf_t, stapling_verify), NULL }, + { ngx_string("ssl_early_data"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_http_ssl_srv_conf_t, early_data), + NULL }, + ngx_null_command }; @@ -294,6 +301,10 @@ static ngx_http_variable_t ngx_http_ssl { ngx_string("ssl_session_reused"), NULL, ngx_http_ssl_variable, (uintptr_t) ngx_ssl_get_session_reused, NGX_HTTP_VAR_CHANGEABLE, 0 }, + { ngx_string("ssl_early_data"), NULL, ngx_http_ssl_variable, + (uintptr_t) ngx_ssl_get_early_data, + NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE, 0 }, + { ngx_string("ssl_server_name"), NULL, ngx_http_ssl_variable, (uintptr_t) ngx_ssl_get_server_name, NGX_HTTP_VAR_CHANGEABLE, 0 }, @@ -552,6 +563,7 @@ ngx_http_ssl_create_srv_conf(ngx_conf_t sscf->enable = NGX_CONF_UNSET; sscf->prefer_server_ciphers = NGX_CONF_UNSET; + sscf->early_data = NGX_CONF_UNSET; sscf->buffer_size = NGX_CONF_UNSET_SIZE; sscf->verify = NGX_CONF_UNSET_UINT; sscf->verify_depth = NGX_CONF_UNSET_UINT; @@ -594,6 +606,8 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t * ngx_conf_merge_value(conf->prefer_server_ciphers, prev->prefer_server_ciphers, 0); + ngx_conf_merge_value(conf->early_data, prev->early_data, 0); + ngx_conf_merge_bitmask_value(conf->protocols, prev->protocols, (NGX_CONF_BITMASK_SET|NGX_SSL_TLSv1 |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2)); @@ -809,6 +823,10 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t * } + if (ngx_ssl_early_data(cf, &conf->ssl, conf->early_data) != NGX_OK) { + return NGX_CONF_ERROR; + } + return NGX_CONF_OK; } diff --git a/src/http/modules/ngx_http_ssl_module.h b/src/http/modules/ngx_http_ssl_module.h --- a/src/http/modules/ngx_http_ssl_module.h +++ b/src/http/modules/ngx_http_ssl_module.h @@ -20,6 +20,7 @@ typedef struct { ngx_ssl_t ssl; ngx_flag_t prefer_server_ciphers; + ngx_flag_t early_data; ngx_uint_t protocols; From kahing at cloudflare.com Tue Aug 7 21:26:01 2018 From: kahing at cloudflare.com (Ka-Hing Cheung) Date: Tue, 7 Aug 2018 14:26:01 -0700 Subject: cache: move open to thread pool Message-ID: commit 0bcfefa040abdff674047c15701d237ff16a5f2b Author: Ka-Hing Cheung Date: Fri Aug 3 13:37:58 2018 -0700 move open to thread pool At cloudflare we found that open() can block a long time, especially at p99 and p999. Moving it to thread pool improved overall p99 by 6x or so during peak time. This has the side effect of disabling nginx's open_file_cache when "aio threads" is turned on. For us we found that to have no impact (probably because we have way too many files for open file cache to be effective anyway). thread pool does increase CPU usage somewhat but we have not measured difference in CPU usage for stock "aio threads" compared to after this patch. Only the cache hit open() is moved to thread pool. We wrote more about it here: https://blog.cloudflare.com/how-we-scaled-nginx-and-saved-the-world-54-years-every-day/ diff --git src/core/ngx_open_file_cache.c src/core/ngx_open_file_cache.c index b23ee78d..9177ebfd 100644 --- src/core/ngx_open_file_cache.c +++ src/core/ngx_open_file_cache.c @@ -35,8 +35,6 @@ static ngx_fd_t ngx_open_file_wrapper(ngx_str_t *name, ngx_int_t access, ngx_log_t *log); static ngx_int_t ngx_file_info_wrapper(ngx_str_t *name, ngx_open_file_info_t *of, ngx_file_info_t *fi, ngx_log_t *log); -static ngx_int_t ngx_open_and_stat_file(ngx_str_t *name, - ngx_open_file_info_t *of, ngx_log_t *log); static void ngx_open_file_add_event(ngx_open_file_cache_t *cache, ngx_cached_open_file_t *file, ngx_open_file_info_t *of, ngx_log_t *log); static void ngx_open_file_cleanup(void *data); @@ -836,7 +834,7 @@ ngx_file_info_wrapper(ngx_str_t *name, ngx_open_file_info_t *of, } -static ngx_int_t +ngx_int_t ngx_open_and_stat_file(ngx_str_t *name, ngx_open_file_info_t *of, ngx_log_t *log) { diff --git src/core/ngx_open_file_cache.h src/core/ngx_open_file_cache.h index d119c129..94b4d552 100644 --- src/core/ngx_open_file_cache.h +++ src/core/ngx_open_file_cache.h @@ -124,6 +124,8 @@ ngx_open_file_cache_t *ngx_open_file_cache_init(ngx_pool_t *pool, ngx_uint_t max, time_t inactive); ngx_int_t ngx_open_cached_file(ngx_open_file_cache_t *cache, ngx_str_t *name, ngx_open_file_info_t *of, ngx_pool_t *pool); +ngx_int_t ngx_open_and_stat_file(ngx_str_t *name, + ngx_open_file_info_t *of, ngx_log_t *log); #endif /* _NGX_OPEN_FILE_CACHE_H_INCLUDED_ */ diff --git src/http/ngx_http_cache.h src/http/ngx_http_cache.h index f9e96640..2910f6a1 100644 --- src/http/ngx_http_cache.h +++ src/http/ngx_http_cache.h @@ -114,6 +114,7 @@ struct ngx_http_cache_s { unsigned exists:1; unsigned temp_file:1; unsigned purged:1; + unsigned opening:1; unsigned reading:1; unsigned secondary:1; unsigned background:1; diff --git src/http/ngx_http_file_cache.c src/http/ngx_http_file_cache.c index 56866fa4..9cb110bf 100644 --- src/http/ngx_http_file_cache.c +++ src/http/ngx_http_file_cache.c @@ -18,6 +18,10 @@ static void ngx_http_file_cache_lock_wait(ngx_http_request_t *r, ngx_http_cache_t *c); static ngx_int_t ngx_http_file_cache_read(ngx_http_request_t *r, ngx_http_cache_t *c); +static ngx_int_t ngx_http_file_cache_aio_open(ngx_http_request_t *r, + ngx_http_cache_t *c, ngx_int_t *rv); +static ngx_int_t ngx_http_file_cache_do_aio_open(ngx_http_request_t *r, + ngx_http_cache_t *c, ngx_open_file_info_t *of, ngx_int_t *rv); static ssize_t ngx_http_file_cache_aio_read(ngx_http_request_t *r, ngx_http_cache_t *c); #if (NGX_HAVE_FILE_AIO) @@ -268,9 +272,7 @@ ngx_http_file_cache_open(ngx_http_request_t *r) ngx_uint_t test; ngx_http_cache_t *c; ngx_pool_cleanup_t *cln; - ngx_open_file_info_t of; ngx_http_file_cache_t *cache; - ngx_http_core_loc_conf_t *clcf; c = r->cache; @@ -278,6 +280,10 @@ ngx_http_file_cache_open(ngx_http_request_t *r) return NGX_AGAIN; } + if (c->opening) { + return ngx_http_file_cache_aio_open(r, c, &rv); + } + if (c->reading) { return ngx_http_file_cache_read(r, c); } @@ -343,23 +349,33 @@ ngx_http_file_cache_open(ngx_http_request_t *r) goto done; } - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + return ngx_http_file_cache_aio_open(r, c, &rv); - ngx_memzero(&of, sizeof(ngx_open_file_info_t)); +done: - of.uniq = c->uniq; - of.valid = clcf->open_file_cache_valid; - of.min_uses = clcf->open_file_cache_min_uses; - of.events = clcf->open_file_cache_events; - of.directio = NGX_OPEN_FILE_DIRECTIO_OFF; - of.read_ahead = clcf->read_ahead; + if (rv == NGX_DECLINED) { + return ngx_http_file_cache_lock(r, c); + } - if (ngx_open_cached_file(clcf->open_file_cache, &c->file.name, &of, r->pool) - != NGX_OK) - { - switch (of.err) { + return rv; +} + +static ngx_int_t +ngx_http_file_cache_aio_open(ngx_http_request_t *r, ngx_http_cache_t *c, + ngx_int_t *rv) +{ + ngx_int_t rc; + ngx_open_file_info_t of; + ngx_http_file_cache_t *cache = c->file_cache; - case 0: + rc = ngx_http_file_cache_do_aio_open(r, c, &of, rv); + if (rc == NGX_AGAIN) { + return rc; + } + + if (rc != NGX_OK) { + switch (of.err) { + case NGX_OK: return NGX_ERROR; case NGX_ENOENT: @@ -391,14 +407,13 @@ ngx_http_file_cache_open(ngx_http_request_t *r) done: - if (rv == NGX_DECLINED) { + if (*rv == NGX_DECLINED) { return ngx_http_file_cache_lock(r, c); } - return rv; + return *rv; } - static ngx_int_t ngx_http_file_cache_lock(ngx_http_request_t *r, ngx_http_cache_t *c) { @@ -663,6 +678,127 @@ ngx_http_file_cache_read(ngx_http_request_t *r, ngx_http_cache_t *c) } +#if (NGX_THREADS) +typedef struct { + ngx_str_t name; + ngx_pool_t *pool; + ngx_open_file_info_t of; + ngx_int_t rv; +} ngx_thread_file_open_ctx_t; + +static void +ngx_http_file_cache_thread_open_handler(void *data, ngx_log_t *log) +{ + ngx_thread_file_open_ctx_t *ctx = data; + ngx_pool_t *pool = ctx->pool; + ngx_open_file_info_t *of = &ctx->of; + ngx_pool_cleanup_t *cln; + ngx_pool_cleanup_file_t *clnf; + ngx_int_t rc; + + ngx_log_debug0(NGX_LOG_DEBUG_CORE, log, 0, "thread read handler"); + + cln = ngx_pool_cleanup_add(pool, sizeof(ngx_pool_cleanup_file_t)); + if (cln == NULL) { + ctx->of.err = NGX_ERROR; + return; + } + + of->fd = NGX_INVALID_FILE; + + rc = ngx_open_and_stat_file(&ctx->name, of, pool->log); + if (rc == NGX_OK && !of->is_dir) { + cln->handler = ngx_pool_cleanup_file; + clnf = cln->data; + + clnf->fd = of->fd; + clnf->name = ctx->name.data; + clnf->log = pool->log; + } +} + + +static ngx_int_t +ngx_http_file_cache_thread_open(ngx_http_cache_t *c, ngx_open_file_info_t *of, + ngx_int_t *rv, ngx_pool_t *pool) +{ + ngx_thread_task_t *task; + ngx_thread_file_open_ctx_t *ctx; + ngx_file_t *file = &c->file; + + task = file->thread_task; + + if (task == NULL) { + task = ngx_thread_task_alloc(pool, sizeof(ngx_thread_file_open_ctx_t)); + if (task == NULL) { + return NGX_ERROR; + } + + file->thread_task = task; + } + + ctx = task->ctx; + + if (task->event.complete) { + task->event.complete = 0; + + *of = ctx->of; + *rv = ctx->rv; + return of->err; + } + + task->handler = ngx_http_file_cache_thread_open_handler; + + ctx->pool = pool; + ctx->name = file->name; + ctx->of = *of; + ctx->rv = *rv; + + if (file->thread_handler(task, file) != NGX_OK) { + return NGX_ERROR; + } + + return NGX_AGAIN; +} +#endif + +static ngx_int_t +ngx_http_file_cache_do_aio_open(ngx_http_request_t *r, ngx_http_cache_t *c, + ngx_open_file_info_t *of, ngx_int_t *rv) +{ + ngx_http_core_loc_conf_t *clcf; + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + ngx_memzero(of, sizeof(ngx_open_file_info_t)); + + of->uniq = c->uniq; + of->valid = clcf->open_file_cache_valid; + of->min_uses = clcf->open_file_cache_min_uses; + of->events = clcf->open_file_cache_events; + of->directio = NGX_OPEN_FILE_DIRECTIO_OFF; + of->read_ahead = clcf->read_ahead; + +#if (NGX_THREADS) + if (clcf->aio == NGX_HTTP_AIO_THREADS) { + ngx_int_t rc; + + c->file.thread_task = c->thread_task; + c->file.thread_handler = ngx_http_cache_thread_handler; + c->file.thread_ctx = r; + + rc = ngx_http_file_cache_thread_open(c, of, rv, r->pool); + + c->thread_task = c->file.thread_task; + c->opening = (rc == NGX_AGAIN); + + return rc; + } +#endif + + return ngx_open_cached_file(clcf->open_file_cache, &c->file.name, of, r->pool); +} + static ssize_t ngx_http_file_cache_aio_read(ngx_http_request_t *r, ngx_http_cache_t *c) { From dnj0496 at gmail.com Wed Aug 8 05:46:08 2018 From: dnj0496 at gmail.com (Dk Jack) Date: Tue, 7 Aug 2018 22:46:08 -0700 Subject: post body In-Reply-To: References: Message-ID: Haven't received any response to inquiry. Would appreciate it if someone can comment. Thanks, Dk. On Thu, Aug 2, 2018 at 12:29 PM Dk Jack wrote: > Hi, > In my module, I'd like to look into the post body to decide if the request > should be allowed to proceed to origin server or not. Based on the examples > I could find I've coded this in my module. After some trial and error it > seems to be working. I am not sure if my implementation is 100% correct. I > would appreciate it if someone can go over my code below and let me know if > my implementation is correct. Especially, the body_complete_handler. Thanks. > > Regards, > Dk. > > > static ngx_int_t mod_setup_body_handler(ngx_http_request_t* r); > static void mod_body_complete_handler(ngx_http_request_t* r); > static ngx_int_t mod_extract_post_body(ngx_http_request_t *r, char *data, > size_t *dsize); > > static ngx_int_t > ngx_http_request_handler(ngx_http_request_t *r) > { > .... > if ((NGX_HTTP_POST == r->method) || (NGX_HTTP_PUT == r->method)) { > return mod_setup_body_handler(r); > } > > ... > } > > ngx_int_t > mod_setup_body_handler(ngx_http_request_t* r) > { > ngx_int_t rc; > > r->request_body_in_single_buf = 1; > r->request_body_in_persistent_file = 1; > r->request_body_in_clean_file = 1; > > rc = ngx_http_read_client_request_body(r, mod_body_complete_handler); > if (rc == NGX_ERROR) { > ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "read req. body > error"); > return rc; > } > > if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { > ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "read req. body > error. special response"); > return rc; > } > > if (rc == NGX_AGAIN) { > /* > * nginx will call the body_received when needed. Returning > * NGX_DONE will prevent nginx from calling ngx_http_finalize_request > * (which we will call in body_received) > */ > return NGX_DONE; > } > > return NGX_DECLINED; > } > > > void > mod_body_complete_handler(ngx_http_request_t* r) > { > ngx_http_request_t* r = mNginxRequest; > > if(r->request_body == NULL) { > // callback was called but body is empty. Setup handler again. > mod_setup_body_handler(bh_ptr); > return; > } else if (r->request_body->rest) { > // we don't have the complete body. Complete callback will be called > again. > return; > } > > if (NULL == mNginxRequest->request_body->temp_file) { > size_t dsize = 64*1024; > char data[dsize] > > if (mod_extract_post_body(r, data, dsize) == NGX_OK) { > // we have the complete body. > int rc = mod_allow_request(body, dsize); // returns NGX_OK or 4XX. > > if (rc != NGX_OK) { > // allow req. has already sent a custom response if rc != NGX_OK. > ngx_http_finalize_request(r, NGX_OK); > return; > } > } > } > > // ???? not having this cause request to hang. > ngx_http_core_run_phases(r); > } > > ngx_int_t > mod_extract_post_body(ngx_http_request_t *r, char *data, size_t *dsize) > { > size_t buf_size = *dsize; > > if (NULL == r->request_body->temp_file) { > // we have body in buffer chain. > ngx_buf_t *buf; > ngx_chain_t *cl; > size_t data_start_pos = 0; > > cl = r->request_body->bufs; > > // copy the body into our temporary buffer. > for (;NULL != cl; cl = cl->next) { > buf = cl->buf; > size_t bsize = buf->last - buf->pos; > > if ((data_start_pos+bsize) > buf_size) { > // data is bigger than the input buffer size, abort > *dsize = data_start_pos; > *(data+*dsize) = '\0'; > return NGX_ERROR; > } > > ngx_memcpy((data+data_start_pos), buf->pos, bsize); > data_start_pos += bsize; > } > > *dsize = data_start_pos; > *(data+*dsize) = '\0'; > return NGX_OK; > } else { > // body in file not implemented yet. > } > > return NGX_ERROR; > } > -------------- next part -------------- An HTML attachment was scrubbed... URL: From mdounin at mdounin.ru Wed Aug 8 18:16:53 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Wed, 8 Aug 2018 21:16:53 +0300 Subject: cache: move open to thread pool In-Reply-To: References: Message-ID: <20180808181653.GX56558@mdounin.ru> Hello! On Tue, Aug 07, 2018 at 02:26:01PM -0700, Ka-Hing Cheung via nginx-devel wrote: > commit 0bcfefa040abdff674047c15701d237ff16a5f2b > Author: Ka-Hing Cheung > Date: Fri Aug 3 13:37:58 2018 -0700 > > move open to thread pool > > At cloudflare we found that open() can block a long time, especially > at p99 and p999. Moving it to thread pool improved overall p99 by 6x > or so during peak time. > > This has the side effect of disabling nginx's open_file_cache when > "aio threads" is turned on. For us we found that to have no impact > (probably because we have way too many files for open file cache to > be effective anyway). > > thread pool does increase CPU usage somewhat but we have not measured > difference in CPU usage for stock "aio threads" compared to after this > patch. > > Only the cache hit open() is moved to thread pool. > > We wrote more about it here: > https://blog.cloudflare.com/how-we-scaled-nginx-and-saved-the-world-54-years-every-day/ First of all, thank you for your work. The numbers provided in the article looks promising. We've thought about offloading more operations to thread pools, and that's basically why "aio_write" is a separate directive, so more directives like "aio_" can be added in the future. It's good to see this is finally happening. Unfortunately, there are number problems with the patch, and it needs more work before it can be committed. In particular: - The open() calls are offloaded to thread pools unconditionally. This may actually reduce performance in various typical workloads where open() does not block. Instead, there should be an "aio_open on|off" directive, similar to "aio_write". - The code bypasses open file cache, and uses a direct call in the http cache code instead. While it might be ok in your setup, it looks like an incomplete solution from the generic point of view. A better solution would be to introduce a generic interface in ngx_open_cached_file() to allow use of thread pools. - The code calls ngx_open_and_stat_file() whithin a thread, which is relatively complex function never designed to be thread safe. While it looks like currently it is, a better solution would be to introduce a separate simple function to execute within a thread, similar to ngx_thread_read_handler(). - In the ngx_http_file_cache_thread_open() function you allocate thread task of size sizeof(ngx_thread_file_open_ctx_t) and store it in the file->thread_task. There is no guarantee that this task will be compatible with other tasks stored in file->thread_task. A better solution would be to extend ngx_thread_file_ctx_t and use the same context for all file-related threaded operations. - A better place for the thread-specific code would be src/os/unix/ngx_files.c, where ngx_thread_file_ctx_t and existing threaded file operations are defined. - The code uses memory pool operations wihin a thread, specifically ngx_pool_cleanup_add(). Memory pools are not thread safe, and the behaviour of this code is therefore undefined. - Also there are various style issues, including wrong capitalization of the commit log summary line, strange commit log indentation and header, missing empty lines. Please take a look at http://nginx.org/en/docs/contributing_changes.html for various hints. In particular, you may want to use Mercurial to submit patches. See also below for some in-line comments. > > diff --git src/core/ngx_open_file_cache.c src/core/ngx_open_file_cache.c > index b23ee78d..9177ebfd 100644 > --- src/core/ngx_open_file_cache.c > +++ src/core/ngx_open_file_cache.c > @@ -35,8 +35,6 @@ static ngx_fd_t ngx_open_file_wrapper(ngx_str_t *name, > ngx_int_t access, ngx_log_t *log); > static ngx_int_t ngx_file_info_wrapper(ngx_str_t *name, > ngx_open_file_info_t *of, ngx_file_info_t *fi, ngx_log_t *log); > -static ngx_int_t ngx_open_and_stat_file(ngx_str_t *name, > - ngx_open_file_info_t *of, ngx_log_t *log); > static void ngx_open_file_add_event(ngx_open_file_cache_t *cache, > ngx_cached_open_file_t *file, ngx_open_file_info_t *of, ngx_log_t *log); > static void ngx_open_file_cleanup(void *data); > @@ -836,7 +834,7 @@ ngx_file_info_wrapper(ngx_str_t *name, > ngx_open_file_info_t *of, > } > > > -static ngx_int_t > +ngx_int_t > ngx_open_and_stat_file(ngx_str_t *name, ngx_open_file_info_t *of, > ngx_log_t *log) > { > diff --git src/core/ngx_open_file_cache.h src/core/ngx_open_file_cache.h > index d119c129..94b4d552 100644 > --- src/core/ngx_open_file_cache.h > +++ src/core/ngx_open_file_cache.h > @@ -124,6 +124,8 @@ ngx_open_file_cache_t > *ngx_open_file_cache_init(ngx_pool_t *pool, > ngx_uint_t max, time_t inactive); > ngx_int_t ngx_open_cached_file(ngx_open_file_cache_t *cache, ngx_str_t *name, > ngx_open_file_info_t *of, ngx_pool_t *pool); > +ngx_int_t ngx_open_and_stat_file(ngx_str_t *name, > + ngx_open_file_info_t *of, ngx_log_t *log); > > > #endif /* _NGX_OPEN_FILE_CACHE_H_INCLUDED_ */ > diff --git src/http/ngx_http_cache.h src/http/ngx_http_cache.h > index f9e96640..2910f6a1 100644 > --- src/http/ngx_http_cache.h > +++ src/http/ngx_http_cache.h > @@ -114,6 +114,7 @@ struct ngx_http_cache_s { > unsigned exists:1; > unsigned temp_file:1; > unsigned purged:1; > + unsigned opening:1; > unsigned reading:1; > unsigned secondary:1; > unsigned background:1; > diff --git src/http/ngx_http_file_cache.c src/http/ngx_http_file_cache.c > index 56866fa4..9cb110bf 100644 > --- src/http/ngx_http_file_cache.c > +++ src/http/ngx_http_file_cache.c > @@ -18,6 +18,10 @@ static void > ngx_http_file_cache_lock_wait(ngx_http_request_t *r, > ngx_http_cache_t *c); > static ngx_int_t ngx_http_file_cache_read(ngx_http_request_t *r, > ngx_http_cache_t *c); > +static ngx_int_t ngx_http_file_cache_aio_open(ngx_http_request_t *r, > + ngx_http_cache_t *c, ngx_int_t *rv); > +static ngx_int_t ngx_http_file_cache_do_aio_open(ngx_http_request_t *r, > + ngx_http_cache_t *c, ngx_open_file_info_t *of, ngx_int_t *rv); > static ssize_t ngx_http_file_cache_aio_read(ngx_http_request_t *r, > ngx_http_cache_t *c); > #if (NGX_HAVE_FILE_AIO) > @@ -268,9 +272,7 @@ ngx_http_file_cache_open(ngx_http_request_t *r) > ngx_uint_t test; > ngx_http_cache_t *c; > ngx_pool_cleanup_t *cln; > - ngx_open_file_info_t of; > ngx_http_file_cache_t *cache; > - ngx_http_core_loc_conf_t *clcf; > > c = r->cache; > > @@ -278,6 +280,10 @@ ngx_http_file_cache_open(ngx_http_request_t *r) > return NGX_AGAIN; > } > > + if (c->opening) { > + return ngx_http_file_cache_aio_open(r, c, &rv); > + } > + The value of rv is uninitialized here. While it is not strictly a bug, but this code indicate bad design. Also, duplicate handling of "rv == NGX_DECLINED" below and in the ngx_http_file_cache_aio_open() function contributes to the problem, as well as passing the rv value to the threaded operation where it is not needed. It might be a good idea to re-think the design. > if (c->reading) { > return ngx_http_file_cache_read(r, c); > } > @@ -343,23 +349,33 @@ ngx_http_file_cache_open(ngx_http_request_t *r) > goto done; > } > > - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); > + return ngx_http_file_cache_aio_open(r, c, &rv); > > - ngx_memzero(&of, sizeof(ngx_open_file_info_t)); > +done: > > - of.uniq = c->uniq; > - of.valid = clcf->open_file_cache_valid; > - of.min_uses = clcf->open_file_cache_min_uses; > - of.events = clcf->open_file_cache_events; > - of.directio = NGX_OPEN_FILE_DIRECTIO_OFF; > - of.read_ahead = clcf->read_ahead; > + if (rv == NGX_DECLINED) { > + return ngx_http_file_cache_lock(r, c); > + } > > - if (ngx_open_cached_file(clcf->open_file_cache, &c->file.name, > &of, r->pool) > - != NGX_OK) > - { > - switch (of.err) { > + return rv; > +} > + > +static ngx_int_t Style: there should be two empty lines between functions. > +ngx_http_file_cache_aio_open(ngx_http_request_t *r, ngx_http_cache_t *c, > + ngx_int_t *rv) Style: function arguments should be indented with 4 spaces. > +{ > + ngx_int_t rc; > + ngx_open_file_info_t of; > + ngx_http_file_cache_t *cache = c->file_cache; > > - case 0: > + rc = ngx_http_file_cache_do_aio_open(r, c, &of, rv); > + if (rc == NGX_AGAIN) { > + return rc; > + } > + > + if (rc != NGX_OK) { > + switch (of.err) { > + case NGX_OK: > return NGX_ERROR; > > case NGX_ENOENT: > @@ -391,14 +407,13 @@ ngx_http_file_cache_open(ngx_http_request_t *r) > > done: > > - if (rv == NGX_DECLINED) { > + if (*rv == NGX_DECLINED) { > return ngx_http_file_cache_lock(r, c); > } > > - return rv; > + return *rv; > } > > - > static ngx_int_t Style: there should be two empty lines between functions: > ngx_http_file_cache_lock(ngx_http_request_t *r, ngx_http_cache_t *c) > { > @@ -663,6 +678,127 @@ ngx_http_file_cache_read(ngx_http_request_t *r, > ngx_http_cache_t *c) > } > > > +#if (NGX_THREADS) > +typedef struct { Style: as long as #if contains something complex, it should be separated with empty lines. > + ngx_str_t name; > + ngx_pool_t *pool; > + ngx_open_file_info_t of; > + ngx_int_t rv; > +} ngx_thread_file_open_ctx_t; > + > +static void > +ngx_http_file_cache_thread_open_handler(void *data, ngx_log_t *log) > +{ > + ngx_thread_file_open_ctx_t *ctx = data; > + ngx_pool_t *pool = ctx->pool; > + ngx_open_file_info_t *of = &ctx->of; > + ngx_pool_cleanup_t *cln; > + ngx_pool_cleanup_file_t *clnf; > + ngx_int_t rc; Style: variable types should be sorted from shortest to longest; variable names should be separated with two spaces from the longest type; assignments should be written separately, except some specific cases where one assignment is allowed in a separate variables block. > + > + ngx_log_debug0(NGX_LOG_DEBUG_CORE, log, 0, "thread read handler"); The "read" here is incorrect, should be "open". > + > + cln = ngx_pool_cleanup_add(pool, sizeof(ngx_pool_cleanup_file_t)); > + if (cln == NULL) { > + ctx->of.err = NGX_ERROR; > + return; > + } The code is executed in a thread, and using request pool here is not allowed. > + > + of->fd = NGX_INVALID_FILE; > + > + rc = ngx_open_and_stat_file(&ctx->name, of, pool->log); > + if (rc == NGX_OK && !of->is_dir) { > + cln->handler = ngx_pool_cleanup_file; > + clnf = cln->data; > + > + clnf->fd = of->fd; > + clnf->name = ctx->name.data; > + clnf->log = pool->log; > + } > +} > + > + > +static ngx_int_t > +ngx_http_file_cache_thread_open(ngx_http_cache_t *c, ngx_open_file_info_t *of, > + ngx_int_t *rv, ngx_pool_t *pool) > +{ > + ngx_thread_task_t *task; > + ngx_thread_file_open_ctx_t *ctx; > + ngx_file_t *file = &c->file; Style, see above. > + > + task = file->thread_task; > + > + if (task == NULL) { > + task = ngx_thread_task_alloc(pool, sizeof(ngx_thread_file_open_ctx_t)); > + if (task == NULL) { > + return NGX_ERROR; > + } > + > + file->thread_task = task; > + } See above, this needs some guarantee that what's stored in file->thread_task is compatible with all operations. > + > + ctx = task->ctx; > + > + if (task->event.complete) { > + task->event.complete = 0; > + > + *of = ctx->of; > + *rv = ctx->rv; > + return of->err; > + } > + > + task->handler = ngx_http_file_cache_thread_open_handler; > + > + ctx->pool = pool; > + ctx->name = file->name; > + ctx->of = *of; > + ctx->rv = *rv; > + > + if (file->thread_handler(task, file) != NGX_OK) { > + return NGX_ERROR; > + } > + > + return NGX_AGAIN; > +} > +#endif > + > +static ngx_int_t Style: there should be an empty line before "#endif", and two empty lines between "#endif" and the next function. > +ngx_http_file_cache_do_aio_open(ngx_http_request_t *r, ngx_http_cache_t *c, > + ngx_open_file_info_t *of, ngx_int_t *rv) > +{ > + ngx_http_core_loc_conf_t *clcf; > + > + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); > + > + ngx_memzero(of, sizeof(ngx_open_file_info_t)); > + > + of->uniq = c->uniq; > + of->valid = clcf->open_file_cache_valid; > + of->min_uses = clcf->open_file_cache_min_uses; > + of->events = clcf->open_file_cache_events; > + of->directio = NGX_OPEN_FILE_DIRECTIO_OFF; > + of->read_ahead = clcf->read_ahead; > + > +#if (NGX_THREADS) > + if (clcf->aio == NGX_HTTP_AIO_THREADS) { > + ngx_int_t rc; Style: there should be two spaces between a type and a variable name; there should be an empty line after #if (and before #endif). > + > + c->file.thread_task = c->thread_task; > + c->file.thread_handler = ngx_http_cache_thread_handler; > + c->file.thread_ctx = r; > + > + rc = ngx_http_file_cache_thread_open(c, of, rv, r->pool); > + > + c->thread_task = c->file.thread_task; > + c->opening = (rc == NGX_AGAIN); > + > + return rc; > + } > +#endif > + > + return ngx_open_cached_file(clcf->open_file_cache, &c->file.name, > of, r->pool); Style: maximum text width is 80 characters. > +} > + > static ssize_t > ngx_http_file_cache_aio_read(ngx_http_request_t *r, ngx_http_cache_t *c) > { > _______________________________________________ > nginx-devel mailing list > nginx-devel at nginx.org > http://mailman.nginx.org/mailman/listinfo/nginx-devel -- Maxim Dounin http://mdounin.ru/ From mdounin at mdounin.ru Wed Aug 8 18:34:05 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Wed, 8 Aug 2018 21:34:05 +0300 Subject: post body In-Reply-To: References: Message-ID: <20180808183405.GY56558@mdounin.ru> Hello! On Tue, Aug 07, 2018 at 10:46:08PM -0700, Dk Jack wrote: > Haven't received any response to inquiry. Would appreciate it if someone > can comment. > > > In my module, I'd like to look into the post body to decide if the request > > should be allowed to proceed to origin server or not. Based on the examples > > I could find I've coded this in my module. After some trial and error it > > seems to be working. I am not sure if my implementation is 100% correct. I > > would appreciate it if someone can go over my code below and let me know if > > my implementation is correct. Especially, the body_complete_handler. Thanks. You may want to read general request body reading guidelines here: http://nginx.org/en/docs/dev/development_guide.html#http_request_body Your code suggests you've never seen these guidelines, so consider re-writing it after reading the above link. Note that the above guidelines cover content phase handling. In other request processing phases reqding the request body might be tricky and will require additional handling (if at all possible). In particular, you'll have to restore request phases processing after the call, and you might have to call ngx_http_finalize_request() yourself. Consider looking into src/http/modules/ngx_http_mirror_module.c for an example. Note well that required handling might depend on the exact request processing phase you are trying to use. Note well that if you are trying to inspec the request body, writing a request body filter might be a better solution. See here for a trivial example: http://mdounin.ru/hg/ngx_http_catch_body_filter_module/file/tip/ngx_http_catch_body_filter_module.c -- Maxim Dounin http://mdounin.ru/ From dnj0496 at gmail.com Wed Aug 8 18:57:33 2018 From: dnj0496 at gmail.com (Dk Jack) Date: Wed, 8 Aug 2018 11:57:33 -0700 Subject: post body In-Reply-To: <20180808183405.GY56558@mdounin.ru> References: <20180808183405.GY56558@mdounin.ru> Message-ID: Thank you. Will looking it and get back. Since I need to inspect, I'll follow your suggestion and see if I can use the body filter option. regards, Dk On Wed, Aug 8, 2018 at 11:34 AM Maxim Dounin wrote: > Hello! > > On Tue, Aug 07, 2018 at 10:46:08PM -0700, Dk Jack wrote: > > > Haven't received any response to inquiry. Would appreciate it if someone > > can comment. > > > > > In my module, I'd like to look into the post body to decide if the > request > > > should be allowed to proceed to origin server or not. Based on the > examples > > > I could find I've coded this in my module. After some trial and error > it > > > seems to be working. I am not sure if my implementation is 100% > correct. I > > > would appreciate it if someone can go over my code below and let me > know if > > > my implementation is correct. Especially, the body_complete_handler. > Thanks. > > You may want to read general request body reading guidelines here: > > http://nginx.org/en/docs/dev/development_guide.html#http_request_body > > Your code suggests you've never seen these guidelines, so consider > re-writing it after reading the above link. > > Note that the above guidelines cover content phase handling. In > other request processing phases reqding the request body might be > tricky and will require additional handling (if at all possible). > In particular, you'll have to restore request phases processing > after the call, and you might have to call > ngx_http_finalize_request() yourself. Consider looking into > src/http/modules/ngx_http_mirror_module.c for an example. Note > well that required handling might depend on the exact request > processing phase you are trying to use. > > Note well that if you are trying to inspec the request body, > writing a request body filter might be a better solution. See > here for a trivial example: > > > http://mdounin.ru/hg/ngx_http_catch_body_filter_module/file/tip/ngx_http_catch_body_filter_module.c > > -- > 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 eran.kornblau at kaltura.com Wed Aug 8 19:44:20 2018 From: eran.kornblau at kaltura.com (Eran Kornblau) Date: Wed, 8 Aug 2018 19:44:20 +0000 Subject: cache: move open to thread pool In-Reply-To: <20180808181653.GX56558@mdounin.ru> References: <20180808181653.GX56558@mdounin.ru> Message-ID: Hi, > > - The code bypasses open file cache, and uses a direct call > in the http cache code instead. While it might be ok in your > setup, it looks like an incomplete solution from the generic point > of view. A better solution would be to introduce a generic > interface in ngx_open_cached_file() to allow use of thread > pools. > A small comment on this - I wrote such an implementation a while ago in my module. We've been using it on production for the last ~3 years. Code is here - https://github.com/kaltura/nginx-vod-module/blob/master/ngx_async_open_file_cache.c (There's a lot of code there that was copied from ngx_open_file_cache.c, I did that since those functions are static, and didn't want to change nginx core. If implemented as part of nginx core, all this duplication can be avoided...) In my implementation, I added a function similar to ngx_open_cached_file - (ngx_async_open_cached_file), that gets a few extra params - 1. The thread pool 2. The thread task (optional) - this was done in order to reuse the task when opening multiple files in a single request 3. Callback + context - invoked once the async open completes This function first checks the cache, if there's a hit, it returns synchronously (NGX_OK). Otherwise, it posts a task that does ngx_open_and_stat_file (NGX_AGAIN). When the task completes, the main nginx thread updates the cache, and invokes the user callback. Hope this helps... Eran From mdounin at mdounin.ru Thu Aug 9 09:26:37 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Thu, 09 Aug 2018 09:26:37 +0000 Subject: [nginx] Skipping spaces in configuration files (ticket #1557). Message-ID: details: http://hg.nginx.org/nginx/rev/f17e313009b0 branches: changeset: 7334:f17e313009b0 user: Maxim Dounin date: Thu Aug 09 12:15:42 2018 +0300 description: Skipping spaces in configuration files (ticket #1557). Previously, a chunk of spaces larger than NGX_CONF_BUFFER (4096 bytes) resulted in the "too long parameter" error during parsing such a configuration. This was because the code only set start and start_line on non-whitespace characters, and hence adjacent whitespace characters were preserved when reading additional data from the configuration file. Fix is to always move start and start_line if the last character was a space. diffstat: src/core/ngx_conf_file.c | 7 ++++--- 1 files changed, 4 insertions(+), 3 deletions(-) diffs (21 lines): diff --git a/src/core/ngx_conf_file.c b/src/core/ngx_conf_file.c --- a/src/core/ngx_conf_file.c +++ b/src/core/ngx_conf_file.c @@ -656,13 +656,14 @@ ngx_conf_read_token(ngx_conf_t *cf) } if (last_space) { + + start = b->pos - 1; + start_line = cf->conf_file->line; + if (ch == ' ' || ch == '\t' || ch == CR || ch == LF) { continue; } - start = b->pos - 1; - start_line = cf->conf_file->line; - switch (ch) { case ';': From mdounin at mdounin.ru Thu Aug 9 17:46:33 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Thu, 09 Aug 2018 17:46:33 +0000 Subject: [nginx] HTTP/2: workaround for clients which fail on table size updates. Message-ID: details: http://hg.nginx.org/nginx/rev/fbb683496705 branches: changeset: 7335:fbb683496705 user: Maxim Dounin date: Thu Aug 09 20:12:17 2018 +0300 description: 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. diffstat: src/http/v2/ngx_http_v2.c | 7 +++++-- 1 files changed, 5 insertions(+), 2 deletions(-) diffs (24 lines): 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; } From kahing at cloudflare.com Thu Aug 9 21:43:19 2018 From: kahing at cloudflare.com (Ka-Hing Cheung) Date: Thu, 9 Aug 2018 14:43:19 -0700 Subject: cache: move open to thread pool In-Reply-To: <20180808181653.GX56558@mdounin.ru> References: <20180808181653.GX56558@mdounin.ru> Message-ID: Very good feedback, we will look into implementing some of them at least. On Wed, Aug 8, 2018 at 11:16 AM, Maxim Dounin wrote: > > We've thought about offloading more operations to thread pools, > and that's basically why "aio_write" is a separate directive, so > more directives like "aio_" can be added in the > future. It's good to see this is finally happening. > > Unfortunately, there are number problems with the patch, and it > needs more work before it can be committed. In particular: > > - The open() calls are offloaded to thread pools unconditionally. > This may actually reduce performance in various typical > workloads where open() does not block. Instead, there should be > an "aio_open on|off" directive, similar to "aio_write". > > - The code bypasses open file cache, and uses a direct call > in the http cache code instead. While it might be ok in your > setup, it looks like an incomplete solution from the generic point > of view. A better solution would be to introduce a generic > interface in ngx_open_cached_file() to allow use of thread > pools. Agreed that not everyone wants threaded open() with aio "threads" (if low CPU overhead is more important than low latency for example). The semantic of "aio_open on" is uncleared though when aio is on but not "threads". Having open file cache working with threaded open is nice to have (although people who need "aio_open" probably also have so much cached assets that they won't need open file cache). > > - The code calls ngx_open_and_stat_file() whithin a thread, which > is relatively complex function never designed to be thread safe. > While it looks like currently it is, a better solution would be to > introduce a separate simple function to execute within a thread, > similar to ngx_thread_read_handler(). agreed. > > - In the ngx_http_file_cache_thread_open() function you allocate > thread task of size sizeof(ngx_thread_file_open_ctx_t) and store > it in the file->thread_task. There is no guarantee that this > task will be compatible with other tasks stored in > file->thread_task. A better solution would be to extend > ngx_thread_file_ctx_t and use the same context for all > file-related threaded operations. does this matter? the different thread_task won't overlap in their usage (you can't read a file until after its opened) so there's no reason they need to be compatible. Isn't that why the task ctx is void * and ngx_thread_task_alloc takes a generic size? > > - A better place for the thread-specific code would be > src/os/unix/ngx_files.c, where ngx_thread_file_ctx_t and > existing threaded file operations are defined. sure > > - The code uses memory pool operations wihin a thread, > specifically ngx_pool_cleanup_add(). Memory pools are not > thread safe, and the behaviour of this code is therefore > undefined. Agreed that it may not be very clean but is this a problem in practice? The pool is tied to the request and shouldn't shared with other threads. Asking mostly to clarify my understandings with nginx memory pools. >> @@ -278,6 +280,10 @@ ngx_http_file_cache_open(ngx_http_request_t *r) >> return NGX_AGAIN; >> } >> >> + if (c->opening) { >> + return ngx_http_file_cache_aio_open(r, c, &rv); >> + } >> + > > The value of rv is uninitialized here. While it is not strictly a > bug, but this code indicate bad design. Also, duplicate handling > of "rv == NGX_DECLINED" below and in the > ngx_http_file_cache_aio_open() function contributes to the > problem, as well as passing the rv value to the threaded operation > where it is not needed. It might be a good idea to re-think the > design. Some of this is because we have other internal changes here. Will try to clean this up better. The rest of the styling suggestions are all reasonable. - Ka-Hing From maxim at nginx.com Fri Aug 10 11:15:20 2018 From: maxim at nginx.com (Maxim Konovalov) Date: Fri, 10 Aug 2018 11:15:20 +0000 Subject: [nginx] A link to the error_log directive on nginx.org removed. Message-ID: details: http://hg.nginx.org/nginx/rev/1cd63ae46243 branches: changeset: 7336:1cd63ae46243 user: Maxim Konovalov date: Fri Aug 10 14:15:05 2018 +0300 description: A link to the error_log directive on nginx.org removed. It makes more harm than good for users and nginx.org infrastructure. diffstat: docs/html/50x.html | 2 +- 1 ?????? ????????, 1 ???????(+), 1 ????????(-) ???????? (12 ?????): diff -r fbb683496705 -r 1cd63ae46243 docs/html/50x.html --- a/docs/html/50x.html Thu Aug 09 20:12:17 2018 +0300 +++ b/docs/html/50x.html Fri Aug 10 14:15:05 2018 +0300 @@ -15,7 +15,7 @@

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

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

+the error log for details.

Faithfully yours, nginx.

From mdounin at mdounin.ru Fri Aug 10 11:39:46 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Fri, 10 Aug 2018 14:39:46 +0300 Subject: cache: move open to thread pool In-Reply-To: References: <20180808181653.GX56558@mdounin.ru> Message-ID: <20180810113946.GG56558@mdounin.ru> Hello! On Thu, Aug 09, 2018 at 02:43:19PM -0700, Ka-Hing Cheung via nginx-devel wrote: > On Wed, Aug 8, 2018 at 11:16 AM, Maxim Dounin wrote: > > > > We've thought about offloading more operations to thread pools, > > and that's basically why "aio_write" is a separate directive, so > > more directives like "aio_" can be added in the > > future. It's good to see this is finally happening. > > > > Unfortunately, there are number problems with the patch, and it > > needs more work before it can be committed. In particular: > > > > - The open() calls are offloaded to thread pools unconditionally. > > This may actually reduce performance in various typical > > workloads where open() does not block. Instead, there should be > > an "aio_open on|off" directive, similar to "aio_write". > > > > - The code bypasses open file cache, and uses a direct call > > in the http cache code instead. While it might be ok in your > > setup, it looks like an incomplete solution from the generic point > > of view. A better solution would be to introduce a generic > > interface in ngx_open_cached_file() to allow use of thread > > pools. > > Agreed that not everyone wants threaded open() with aio "threads" (if > low CPU overhead is more important than low latency for example). The > semantic of "aio_open on" is uncleared though when aio is on but not > "threads". Having open file cache working with threaded open is nice > to have (although people who need "aio_open" probably also have so > much cached assets that they won't need open file cache). As long as the "aio" is set to non-threaded variant so "open" is not available, it is perfectly fine that "aio_open on" won't do anything. This is what currently happens with "aio_write", see http://nginx.org/r/aio_write. [...] > > - In the ngx_http_file_cache_thread_open() function you allocate > > thread task of size sizeof(ngx_thread_file_open_ctx_t) and store > > it in the file->thread_task. There is no guarantee that this > > task will be compatible with other tasks stored in > > file->thread_task. A better solution would be to extend > > ngx_thread_file_ctx_t and use the same context for all > > file-related threaded operations. > > does this matter? the different thread_task won't overlap in their > usage (you can't read a file until after its opened) so there's no > reason they need to be compatible. Isn't that why the task ctx is void > * and ngx_thread_task_alloc takes a generic size? While this probably never happens with the current code, original idea was that file->thread_task can be re-used for other file-related operations. [...] > > - The code uses memory pool operations wihin a thread, > > specifically ngx_pool_cleanup_add(). Memory pools are not > > thread safe, and the behaviour of this code is therefore > > undefined. > > Agreed that it may not be very clean but is this a problem in > practice? The pool is tied to the request and shouldn't shared with > other threads. Asking mostly to clarify my understandings with nginx > memory pools. In practice the pool can be used in the main thread if some request-related events happen, or it can be used by another subrequest. [...] -- Maxim Dounin http://mdounin.ru/ From mdounin at mdounin.ru Fri Aug 10 18:53:14 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Fri, 10 Aug 2018 18:53:14 +0000 Subject: [nginx] SSL: fixed build with LibreSSL 2.8.0 (ticket #1605). Message-ID: details: http://hg.nginx.org/nginx/rev/cab37803ebb3 branches: changeset: 7337:cab37803ebb3 user: Maxim Dounin date: Fri Aug 10 20:49:06 2018 +0300 description: SSL: fixed build with LibreSSL 2.8.0 (ticket #1605). LibreSSL 2.8.0 "added const annotations to many existing APIs from OpenSSL, making interoperability easier for downstream applications". This includes the const change in the SSL_CTX_sess_set_get_cb() callback function (see 9dd43f4ef67e), which breaks compilation. To fix this, added a condition on how we redefine OPENSSL_VERSION_NUMBER when working with LibreSSL (see 382fc7069e3a). With LibreSSL 2.8.0, we now set OPENSSL_VERSION_NUMBER to 0x1010000fL (OpenSSL 1.1.0), so the appropriate conditions in the code will use "const" as it happens with OpenSSL 1.1.0 and later versions. diffstat: src/event/ngx_event_openssl.h | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-) diffs (16 lines): diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h --- a/src/event/ngx_event_openssl.h +++ b/src/event/ngx_event_openssl.h @@ -36,8 +36,12 @@ #if (defined LIBRESSL_VERSION_NUMBER && OPENSSL_VERSION_NUMBER == 0x20000000L) #undef OPENSSL_VERSION_NUMBER +#if (LIBRESSL_VERSION_NUMBER >= 0x2080000fL) +#define OPENSSL_VERSION_NUMBER 0x1010000fL +#else #define OPENSSL_VERSION_NUMBER 0x1000107fL #endif +#endif #if (OPENSSL_VERSION_NUMBER >= 0x10100001L) From mdounin at mdounin.ru Fri Aug 10 20:02:47 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Fri, 10 Aug 2018 20:02:47 +0000 Subject: [nginx] Upstream keepalive: comment added. Message-ID: details: http://hg.nginx.org/nginx/rev/46174066b75f branches: changeset: 7338:46174066b75f user: Maxim Dounin date: Fri Aug 10 21:54:17 2018 +0300 description: Upstream keepalive: comment added. diffstat: src/http/modules/ngx_http_upstream_keepalive_module.c | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diffs (12 lines): diff --git a/src/http/modules/ngx_http_upstream_keepalive_module.c b/src/http/modules/ngx_http_upstream_keepalive_module.c --- a/src/http/modules/ngx_http_upstream_keepalive_module.c +++ b/src/http/modules/ngx_http_upstream_keepalive_module.c @@ -518,6 +518,8 @@ ngx_http_upstream_keepalive(ngx_conf_t * kcf->max_cached = n; + /* init upstream handler */ + uscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_upstream_module); kcf->original_init_upstream = uscf->peer.init_upstream From mdounin at mdounin.ru Fri Aug 10 20:02:48 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Fri, 10 Aug 2018 20:02:48 +0000 Subject: [nginx] Upstream keepalive: keepalive_timeout directive. Message-ID: details: http://hg.nginx.org/nginx/rev/d9029e113a05 branches: changeset: 7339:d9029e113a05 user: Maxim Dounin date: Fri Aug 10 21:54:23 2018 +0300 description: Upstream keepalive: keepalive_timeout directive. The directive configures maximum time a connection can be kept in the cache. By configuring a time which is smaller than the corresponding timeout on the backend side one can avoid the race between closing a connection by the backend and nginx trying to use the same connection to send a request at the same time. diffstat: src/http/modules/ngx_http_upstream_keepalive_module.c | 25 +++++++++++++++--- 1 files changed, 20 insertions(+), 5 deletions(-) diffs (77 lines): diff --git a/src/http/modules/ngx_http_upstream_keepalive_module.c b/src/http/modules/ngx_http_upstream_keepalive_module.c --- a/src/http/modules/ngx_http_upstream_keepalive_module.c +++ b/src/http/modules/ngx_http_upstream_keepalive_module.c @@ -12,6 +12,7 @@ typedef struct { ngx_uint_t max_cached; + ngx_msec_t timeout; ngx_queue_t cache; ngx_queue_t free; @@ -84,6 +85,13 @@ static ngx_command_t ngx_http_upstream_ 0, NULL }, + { ngx_string("keepalive_timeout"), + NGX_HTTP_UPS_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_http_upstream_keepalive_srv_conf_t, timeout), + NULL }, + ngx_null_command }; @@ -133,6 +141,8 @@ ngx_http_upstream_init_keepalive(ngx_con kcf = ngx_http_conf_upstream_srv_conf(us, ngx_http_upstream_keepalive_module); + ngx_conf_init_msec_value(kcf->timeout, 60000); + if (kcf->original_init_upstream(cf, us) != NGX_OK) { return NGX_ERROR; } @@ -261,6 +271,10 @@ found: c->write->log = pc->log; c->pool->log = pc->log; + if (c->read->timer_set) { + ngx_del_timer(c->read); + } + pc->connection = c; pc->cached = 1; @@ -339,10 +353,9 @@ ngx_http_upstream_free_keepalive_peer(ng pc->connection = NULL; - if (c->read->timer_set) { - c->read->delayed = 0; - ngx_del_timer(c->read); - } + c->read->delayed = 0; + ngx_add_timer(c->read, kp->conf->timeout); + if (c->write->timer_set) { ngx_del_timer(c->write); } @@ -393,7 +406,7 @@ ngx_http_upstream_keepalive_close_handle c = ev->data; - if (c->close) { + if (c->close || c->read->timedout) { goto close; } @@ -486,6 +499,8 @@ ngx_http_upstream_keepalive_create_conf( * conf->max_cached = 0; */ + conf->timeout = NGX_CONF_UNSET_MSEC; + return conf; } From mdounin at mdounin.ru Fri Aug 10 20:02:50 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Fri, 10 Aug 2018 20:02:50 +0000 Subject: [nginx] Upstream keepalive: keepalive_requests directive. Message-ID: details: http://hg.nginx.org/nginx/rev/70c6b08973a0 branches: changeset: 7340:70c6b08973a0 user: Maxim Dounin date: Fri Aug 10 21:54:46 2018 +0300 description: Upstream keepalive: keepalive_requests directive. The directive configures maximum number of requests allowed on a connection kept in the cache. Once a connection reaches the number of requests configured, it is no longer saved to the cache. The default is 100. Much like keepalive_requests for client connections, this is mostly a safeguard to make sure connections are closed periodically and the memory allocated from the connection pool is freed. diffstat: src/http/modules/ngx_http_upstream_keepalive_module.c | 14 ++++++++++++++ src/http/ngx_http_upstream.c | 2 ++ 2 files changed, 16 insertions(+), 0 deletions(-) diffs (64 lines): diff --git a/src/http/modules/ngx_http_upstream_keepalive_module.c b/src/http/modules/ngx_http_upstream_keepalive_module.c --- a/src/http/modules/ngx_http_upstream_keepalive_module.c +++ b/src/http/modules/ngx_http_upstream_keepalive_module.c @@ -12,6 +12,7 @@ typedef struct { ngx_uint_t max_cached; + ngx_uint_t requests; ngx_msec_t timeout; ngx_queue_t cache; @@ -92,6 +93,13 @@ static ngx_command_t ngx_http_upstream_ offsetof(ngx_http_upstream_keepalive_srv_conf_t, timeout), NULL }, + { ngx_string("keepalive_requests"), + NGX_HTTP_UPS_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_http_upstream_keepalive_srv_conf_t, requests), + NULL }, + ngx_null_command }; @@ -142,6 +150,7 @@ ngx_http_upstream_init_keepalive(ngx_con ngx_http_upstream_keepalive_module); ngx_conf_init_msec_value(kcf->timeout, 60000); + ngx_conf_init_uint_value(kcf->requests, 100); if (kcf->original_init_upstream(cf, us) != NGX_OK) { return NGX_ERROR; @@ -312,6 +321,10 @@ ngx_http_upstream_free_keepalive_peer(ng goto invalid; } + if (c->requests >= kp->conf->requests) { + goto invalid; + } + if (!u->keepalive) { goto invalid; } @@ -500,6 +513,7 @@ ngx_http_upstream_keepalive_create_conf( */ conf->timeout = NGX_CONF_UNSET_MSEC; + conf->requests = NGX_CONF_UNSET_UINT; return conf; } 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 @@ -1546,6 +1546,8 @@ ngx_http_upstream_connect(ngx_http_reque c = u->peer.connection; + c->requests++; + c->data = r; c->write->handler = ngx_http_upstream_handler; From rpaprocki at fearnothingproductions.net Fri Aug 10 20:50:04 2018 From: rpaprocki at fearnothingproductions.net (Robert Paprocki) Date: Fri, 10 Aug 2018 13:50:04 -0700 Subject: [nginx] Upstream keepalive: keepalive_requests directive. In-Reply-To: References: Message-ID: Quite the patch. I recall this behavior being discussed a number of times in the past. Question: why the default of 100? This feels like a significantly breaking change wrt. the previous behavior. Are there any plans for advanced communication regarding this change, outside of a nominal changelog entry (e.g., "introduced 'keepalive_requests' directive")? On Fri, Aug 10, 2018 at 1:02 PM, Maxim Dounin wrote: > details: http://hg.nginx.org/nginx/rev/70c6b08973a0 > branches: > changeset: 7340:70c6b08973a0 > user: Maxim Dounin > date: Fri Aug 10 21:54:46 2018 +0300 > description: > Upstream keepalive: keepalive_requests directive. > > The directive configures maximum number of requests allowed on > a connection kept in the cache. Once a connection reaches the number > of requests configured, it is no longer saved to the cache. > The default is 100. > > Much like keepalive_requests for client connections, this is mostly > a safeguard to make sure connections are closed periodically and the > memory allocated from the connection pool is freed. > > diffstat: > > src/http/modules/ngx_http_upstream_keepalive_module.c | 14 > ++++++++++++++ > src/http/ngx_http_upstream.c | 2 ++ > 2 files changed, 16 insertions(+), 0 deletions(-) > > diffs (64 lines): > > diff --git a/src/http/modules/ngx_http_upstream_keepalive_module.c > b/src/http/modules/ngx_http_upstream_keepalive_module.c > --- a/src/http/modules/ngx_http_upstream_keepalive_module.c > +++ b/src/http/modules/ngx_http_upstream_keepalive_module.c > @@ -12,6 +12,7 @@ > > typedef struct { > ngx_uint_t max_cached; > + ngx_uint_t requests; > ngx_msec_t timeout; > > ngx_queue_t cache; > @@ -92,6 +93,13 @@ static ngx_command_t ngx_http_upstream_ > offsetof(ngx_http_upstream_keepalive_srv_conf_t, timeout), > NULL }, > > + { ngx_string("keepalive_requests"), > + NGX_HTTP_UPS_CONF|NGX_CONF_TAKE1, > + ngx_conf_set_num_slot, > + NGX_HTTP_SRV_CONF_OFFSET, > + offsetof(ngx_http_upstream_keepalive_srv_conf_t, requests), > + NULL }, > + > ngx_null_command > }; > > @@ -142,6 +150,7 @@ ngx_http_upstream_init_keepalive(ngx_con > ngx_http_upstream_keepalive_ > module); > > ngx_conf_init_msec_value(kcf->timeout, 60000); > + ngx_conf_init_uint_value(kcf->requests, 100); > > if (kcf->original_init_upstream(cf, us) != NGX_OK) { > return NGX_ERROR; > @@ -312,6 +321,10 @@ ngx_http_upstream_free_keepalive_peer(ng > goto invalid; > } > > + if (c->requests >= kp->conf->requests) { > + goto invalid; > + } > + > if (!u->keepalive) { > goto invalid; > } > @@ -500,6 +513,7 @@ ngx_http_upstream_keepalive_create_conf( > */ > > conf->timeout = NGX_CONF_UNSET_MSEC; > + conf->requests = NGX_CONF_UNSET_UINT; > > return conf; > } > 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 > @@ -1546,6 +1546,8 @@ ngx_http_upstream_connect(ngx_http_reque > > c = u->peer.connection; > > + c->requests++; > + > c->data = r; > > c->write->handler = ngx_http_upstream_handler; > _______________________________________________ > 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 urusha.v1.0 at gmail.com Sat Aug 11 05:35:22 2018 From: urusha.v1.0 at gmail.com (urusha) Date: Sat, 11 Aug 2018 08:35:22 +0300 Subject: Can not log in to trac.nginx.org In-Reply-To: References: Message-ID: I'd like to submit an issue to trac, but got "502 Bad Gateway" https://trac.nginx.org/nginx/oauth2callback/github?code=xxx -- Best regards -------------- next part -------------- An HTML attachment was scrubbed... URL: From gfrankliu at gmail.com Sat Aug 11 16:32:44 2018 From: gfrankliu at gmail.com (Frank Liu) Date: Sat, 11 Aug 2018 09:32:44 -0700 Subject: [nginx] Upstream keepalive: keepalive_requests directive. Message-ID: I agree with Robert. When adding those new directives, the "default" should match the old behavior so people who are not aware of the new directives will NOT get any unexpected results while upgrading to this release. People who has a need to change the old behavior now will have the new directives in hand. Can you make keepalive_timeout and keepalive_requests both default to indefinite? Thanks! Frank On Fri Aug 10 20:50:04 UTC 2018, Robert Paprocki wrote: > Quite the patch. I recall this behavior being discussed a number of times > in the past. > > Question: why the default of 100? This feels like a significantly breaking > change wrt. the previous behavior. Are there any plans for advanced > communication regarding this change, outside of a nominal changelog entry > (e.g., "introduced 'keepalive_requests' directive")? -------------- next part -------------- An HTML attachment was scrubbed... URL: From mdounin at mdounin.ru Sun Aug 12 12:41:57 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Sun, 12 Aug 2018 15:41:57 +0300 Subject: [nginx] Upstream keepalive: keepalive_requests directive. In-Reply-To: References: Message-ID: <20180812124157.GH56558@mdounin.ru> Hello! On Fri, Aug 10, 2018 at 01:50:04PM -0700, Robert Paprocki wrote: > Quite the patch. I recall this behavior being discussed a number of times > in the past. > > Question: why the default of 100? This feels like a significantly breaking > change wrt. the previous behavior. Are there any plans for advanced > communication regarding this change, outside of a nominal changelog entry > (e.g., "introduced 'keepalive_requests' directive")? The default is 100 to match the same default of the client-side keepalive_requests, see http://nginx.org/r/keepalive_requests. Also, it is believed that 100 is a good enough number for most setups. While it may be somewhat low for some extreme configurations, it can be easily adjusted using the directive. I don't think that your concerns about "breaking change" are relevant, especially keeping in mind that a) upstream keepalive is off by default and b) event with upstream keepalive configured, requests can easily re-open or close connections for various other reasons, in particular - due to limited number of connections which are kept in the cache. Even assuming ideal conditions, this change can only affect 1 percent of requests. -- Maxim Dounin http://mdounin.ru/ From mdounin at mdounin.ru Sun Aug 12 13:00:48 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Sun, 12 Aug 2018 16:00:48 +0300 Subject: [nginx] Upstream keepalive: keepalive_requests directive. In-Reply-To: References: Message-ID: <20180812130048.GI56558@mdounin.ru> Hello! On Sat, Aug 11, 2018 at 09:32:44AM -0700, Frank Liu wrote: > I agree with Robert. > > When adding those new directives, the "default" should match the old > behavior so people who are not aware of the new directives will NOT get any > unexpected results while upgrading to this release. People who has a need > to change the old behavior now will have the new directives in hand. > > Can you make keepalive_timeout and keepalive_requests both default to > indefinite? Short answer: No. Long anser: The defaults are choosen to mitigate known problems as observed in the wild. While this can somehow affect existing users, presering the old behaviour will affect them as well, and will also affect new users. We try hard to make upgrades as easy as possible, but in this particular case changing the default behaviour will benefit most of the users. In contrast, trying to match the old behaviour implies that users will continue to face the problems these settings are expected to prevent. As such, the defaults are choosen to be reasonable in most cases and to cause minimal amount of problems in the real life usage. -- Maxim Dounin http://mdounin.ru/ From gfrankliu at gmail.com Mon Aug 13 07:30:58 2018 From: gfrankliu at gmail.com (Frank Liu) Date: Mon, 13 Aug 2018 00:30:58 -0700 Subject: [nginx] Upstream keepalive: keepalive_requests directive. In-Reply-To: <20180812124157.GH56558@mdounin.ru> References: <20180812124157.GH56558@mdounin.ru> Message-ID: I don't see why we would want the upstream default be the same as the downstream. Upstream and downstream have different characteristics, as explained in this post http://mailman.nginx.org/pipermail/nginx/2015-December/049445.html why HTTP2 is supported in downstream but not in upstream. Upstream (your own backend) will most likely have configured super long keepalive since the connection is only from trusted client (nginx proxy) and not directly open to the Internet. With the new default, the connection has to be torn down and reestablished every second for a 100TPS link. In old behavior we only need to configure backend to control how long the connection to stay up. Now we have to change both nginx and backend. Thanks! Frank On Sun, Aug 12, 2018 at 5:42 AM Maxim Dounin wrote: > Hello! > > On Fri, Aug 10, 2018 at 01:50:04PM -0700, Robert Paprocki wrote: > > > Quite the patch. I recall this behavior being discussed a number of times > > in the past. > > > > Question: why the default of 100? This feels like a significantly > breaking > > change wrt. the previous behavior. Are there any plans for advanced > > communication regarding this change, outside of a nominal changelog entry > > (e.g., "introduced 'keepalive_requests' directive")? > > The default is 100 to match the same default of the client-side > keepalive_requests, see http://nginx.org/r/keepalive_requests. > Also, it is believed that 100 is a good enough number for most > setups. While it may be somewhat low for some extreme > configurations, it can be easily adjusted using the directive. > > I don't think that your concerns about "breaking change" are > relevant, especially keeping in mind that a) upstream keepalive is > off by default and b) event with upstream keepalive configured, > requests can easily re-open or close connections for various other > reasons, in particular - due to limited number of connections > which are kept in the cache. Even assuming ideal conditions, > this change can only affect 1 percent of requests. > > -- > 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 mdounin at mdounin.ru Mon Aug 13 14:35:03 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Mon, 13 Aug 2018 17:35:03 +0300 Subject: [nginx] Upstream keepalive: keepalive_requests directive. In-Reply-To: References: <20180812124157.GH56558@mdounin.ru> Message-ID: <20180813143503.GN56558@mdounin.ru> Hello! On Mon, Aug 13, 2018 at 12:30:58AM -0700, Frank Liu wrote: > I don't see why we would want the upstream default be the same as the > downstream. > Upstream and downstream have different characteristics, as explained in > this post http://mailman.nginx.org/pipermail/nginx/2015-December/049445.html > why > HTTP2 is supported in downstream but not in upstream. Sure, upstream and downstream defaults are not required to be the same. And, for example, we do not use keepalive with upstream servers by default - at all, unless explicitly configured. Nevertheless, in many cases it is a good idea to keep them the same to avoid needless user confusion. Also, as already said, it is believed that 100 is a good enough number for most setups. -- Maxim Dounin http://mdounin.ru/ From miranovy at gmail.com Tue Aug 14 08:22:14 2018 From: miranovy at gmail.com (Miroslav Novy) Date: Tue, 14 Aug 2018 10:22:14 +0200 Subject: limit_rate_after support variables Message-ID: # HG changeset patch # User Miroslav Nov? # Date 1534234559 0 # Tue Aug 14 08:15:59 2018 +0000 # Node ID 1a8327b50f7844cbe68226f54de60632189327f4 # Parent 70c6b08973a02551612da4a4273757dc77c70ae2 limit_rate_after support variables Example of use: location / { root /var/www/default/; index index.html index.htm; set $my_limit_rate_after 2m; limit_rate_after $my_limit_rate_after; limit_rate 2k; access_by_lua_block { ngx.var.my_limit_rate_after = '10m' } } diff -r 70c6b08973a0 -r 1a8327b50f78 src/http/ngx_http_core_module.c --- a/src/http/ngx_http_core_module.c Fri Aug 10 21:54:46 2018 +0300 +++ b/src/http/ngx_http_core_module.c Tue Aug 14 08:15:59 2018 +0000 @@ -487,7 +487,7 @@ { ngx_string("limit_rate_after"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF |NGX_CONF_TAKE1, - ngx_conf_set_size_slot, + ngx_http_set_complex_value_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_core_loc_conf_t, limit_rate_after), NULL }, @@ -3364,6 +3364,7 @@ * clcf->alias = 0; * clcf->gzip_proxied = 0; * clcf->keepalive_disable = 0; + * clcf->limit_rate_after = NULL; */ clcf->client_max_body_size = NGX_CONF_UNSET; @@ -3393,7 +3394,6 @@ clcf->send_lowat = NGX_CONF_UNSET_SIZE; clcf->postpone_output = NGX_CONF_UNSET_SIZE; clcf->limit_rate = NGX_CONF_UNSET_SIZE; - clcf->limit_rate_after = NGX_CONF_UNSET_SIZE; clcf->keepalive_timeout = NGX_CONF_UNSET_MSEC; clcf->keepalive_header = NGX_CONF_UNSET; clcf->keepalive_requests = NGX_CONF_UNSET_UINT; @@ -3623,8 +3623,8 @@ ngx_conf_merge_size_value(conf->postpone_output, prev->postpone_output, 1460); ngx_conf_merge_size_value(conf->limit_rate, prev->limit_rate, 0); - ngx_conf_merge_size_value(conf->limit_rate_after, prev->limit_rate_after, - 0); + ngx_conf_merge_ptr_value(conf->limit_rate_after, prev->limit_rate_after, + NULL); ngx_conf_merge_msec_value(conf->keepalive_timeout, prev->keepalive_timeout, 75000); ngx_conf_merge_sec_value(conf->keepalive_header, diff -r 70c6b08973a0 -r 1a8327b50f78 src/http/ngx_http_core_module.h --- a/src/http/ngx_http_core_module.h Fri Aug 10 21:54:46 2018 +0300 +++ b/src/http/ngx_http_core_module.h Tue Aug 14 08:15:59 2018 +0000 @@ -351,7 +351,7 @@ size_t send_lowat; /* send_lowat */ size_t postpone_output; /* postpone_output */ size_t limit_rate; /* limit_rate */ - size_t limit_rate_after; /* limit_rate_after */ + ngx_http_complex_value_t *limit_rate_after; /* limit_rate_after */ size_t sendfile_max_chunk; /* sendfile_max_chunk */ size_t read_ahead; /* read_ahead */ size_t subrequest_output_buffer_size; diff -r 70c6b08973a0 -r 1a8327b50f78 src/http/ngx_http_write_filter_module.c --- a/src/http/ngx_http_write_filter_module.c Fri Aug 10 21:54:46 2018 +0300 +++ b/src/http/ngx_http_write_filter_module.c Tue Aug 14 08:15:59 2018 +0000 @@ -220,7 +220,26 @@ if (r->limit_rate) { if (r->limit_rate_after == 0) { - r->limit_rate_after = clcf->limit_rate_after; + r->limit_rate_after = 0; + + if (clcf->limit_rate_after != NULL) { + ngx_str_t res; + size_t st; + + if (ngx_http_complex_value(r, clcf->limit_rate_after, &res) + != NGX_OK) + { + return NGX_ERROR; + } + + st = ngx_parse_size(&res); + if (st != (size_t) NGX_ERROR) { + r->limit_rate_after = st; + } else { + ngx_log_error(NGX_LOG_ALERT, c->log, 0, + "limit_rate_after has bad value"); + } + } } limit = (off_t) r->limit_rate * (ngx_time() - r->start_sec + 1) -------------- next part -------------- An HTML attachment was scrubbed... URL: From jeppojeps at gmail.com Tue Aug 14 16:15:26 2018 From: jeppojeps at gmail.com (Antonio Nappa) Date: Tue, 14 Aug 2018 18:15:26 +0200 Subject: When to delete event timers Message-ID: Hello, I have a module which registers several events and I am using Nginx 1.12.1, it looks like when I do a reload that the worker(s) hang and with the help of strace I see that the events hanging are my events. I have added a function on process exit but it does not get called (probably because of the pending events). So my question is when should I delete the timers if not on process exit? Thanks, Antonio -------------- next part -------------- An HTML attachment was scrubbed... URL: From vbart at nginx.com Tue Aug 14 17:36:12 2018 From: vbart at nginx.com (Valentin V. Bartenev) Date: Tue, 14 Aug 2018 20:36:12 +0300 Subject: When to delete event timers In-Reply-To: References: Message-ID: <2608263.vM3psleB0n@vbart-workstation> On Tuesday 14 August 2018 18:15:26 Antonio Nappa wrote: > Hello, > > I have a module which registers several events and I am using Nginx 1.12.1, > it looks like when I do a reload that the worker(s) hang and with the help > of strace I see that the events hanging are my events. I have added a > function on process exit but it does not get called (probably because of > the pending events). So my question is when should I delete the timers if > not on process exit? [..] If you don't want your timer to delay process exit, there's "cancelable" flag: http://nginx.org/en/docs/dev/development_guide.html#event | cancelable ? Timer event flag indicating that the event should be ignored | while shutting down the worker. Graceful worker shutdown is delayed until | here are no non-cancelable timer events scheduled. wbr, Valentin V. Bartnev From jeppojeps at gmail.com Wed Aug 15 22:36:05 2018 From: jeppojeps at gmail.com (Antonio Nappa) Date: Thu, 16 Aug 2018 00:36:05 +0200 Subject: Output filters and body filters Message-ID: Hello, I have two modules loaded and it looks like when I terminate a request from one module by calling ngx_http_output_filter the body filter in the other module does not get called. The module with the body filter is loaded first in the config (IMO it shouldn't matter). Do you have any suggestion on how I can make the body filter called? Thanks, Antonio -------------- next part -------------- An HTML attachment was scrubbed... URL: From mdounin at mdounin.ru Thu Aug 16 23:28:03 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Fri, 17 Aug 2018 02:28:03 +0300 Subject: Output filters and body filters In-Reply-To: References: Message-ID: <20180816232803.GV56558@mdounin.ru> Hello! On Thu, Aug 16, 2018 at 12:36:05AM +0200, Antonio Nappa wrote: > I have two modules loaded and it looks like when I terminate a request from > one module by calling ngx_http_output_filter the body filter in the other > module does not get called. The module with the body filter is loaded first > in the config (IMO it shouldn't matter). Do you have any suggestion on how > I can make the body filter called? Make sure you've wrote the config file of your module properly. In particular, config file for a typical body filter should look like: ngx_addon_name="ngx_http_foo_filter_module" ngx_module_type=HTTP_AUX_FILTER ngx_module_name=ngx_http_foo_filter_module ngx_module_incs= ngx_module_deps= ngx_module_srcs=$ngx_addon_dir/ngx_http_foo_filter_module.c ngx_module_libs= ngx_module_order= . auto/module Trying to configure a filter module with ngx_module_type=HTTP won't work. -- Maxim Dounin http://mdounin.ru/ From jeppojeps at gmail.com Mon Aug 20 13:33:06 2018 From: jeppojeps at gmail.com (Antonio Nappa) Date: Mon, 20 Aug 2018 15:33:06 +0200 Subject: Output filters and body filters In-Reply-To: <20180816232803.GV56558@mdounin.ru> References: <20180816232803.GV56558@mdounin.ru> Message-ID: Hi Maxim, thanks for you answer. I have the following scenario, I want to finalize the request for example with NGX_ERROR, let's say in REWRITE phase, how could I make the request pass through the filters, I was thinking that something like this would work, but it isn't. ngx_chain_t out; ngx_http_send_header(r); rc = ngx_http_output_filter(r, &out); ngx_http_finalize_request(r, NGX_ERROR); Thanks, Antonio Il giorno ven 17 ago 2018 alle ore 01:28 Maxim Dounin ha scritto: > Hello! > > On Thu, Aug 16, 2018 at 12:36:05AM +0200, Antonio Nappa wrote: > > > I have two modules loaded and it looks like when I terminate a request > from > > one module by calling ngx_http_output_filter the body filter in the other > > module does not get called. The module with the body filter is loaded > first > > in the config (IMO it shouldn't matter). Do you have any suggestion on > how > > I can make the body filter called? > > Make sure you've wrote the config file of your module properly. > In particular, config file for a typical body filter should look > like: > > ngx_addon_name="ngx_http_foo_filter_module" > > ngx_module_type=HTTP_AUX_FILTER > ngx_module_name=ngx_http_foo_filter_module > ngx_module_incs= > ngx_module_deps= > ngx_module_srcs=$ngx_addon_dir/ngx_http_foo_filter_module.c > ngx_module_libs= > ngx_module_order= > > . auto/module > > Trying to configure a filter module with ngx_module_type=HTTP > won't work. > > -- > 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 xeioex at nginx.com Mon Aug 20 15:58:11 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Mon, 20 Aug 2018 15:58:11 +0000 Subject: [njs] Improved wording for primitive type conversion exception. Message-ID: details: http://hg.nginx.org/njs/rev/aa0459712007 branches: changeset: 583:aa0459712007 user: Dmitry Volyntsev date: Mon Aug 20 18:58:03 2018 +0300 description: Improved wording for primitive type conversion exception. diffstat: njs/njs_vm.c | 3 ++- njs/test/njs_interactive_test.c | 2 +- njs/test/njs_unit_test.c | 8 ++++---- 3 files changed, 7 insertions(+), 6 deletions(-) diffs (59 lines): diff -r d2cbea77122c -r aa0459712007 njs/njs_vm.c --- a/njs/njs_vm.c Thu Aug 02 19:39:55 2018 +0300 +++ b/njs/njs_vm.c Mon Aug 20 18:58:03 2018 +0300 @@ -3204,7 +3204,8 @@ njs_primitive_value(njs_vm_t *vm, njs_va } if (ret == NXT_ERROR) { - njs_type_error(vm, "cannot evaluate an object's value"); + njs_type_error(vm, + "Cannot convert object to primitive value"); } return ret; diff -r d2cbea77122c -r aa0459712007 njs/test/njs_interactive_test.c --- a/njs/test/njs_interactive_test.c Thu Aug 02 19:39:55 2018 +0300 +++ b/njs/test/njs_interactive_test.c Mon Aug 20 18:58:03 2018 +0300 @@ -215,7 +215,7 @@ static njs_interactive_test_t njs_test[ { nxt_string("var o = { toString: function() { return [1] } }" ENTER "o" ENTER), - nxt_string("TypeError: cannot evaluate an object's value\n" + nxt_string("TypeError: Cannot convert object to primitive value\n" " at main (native)\n") }, }; diff -r d2cbea77122c -r aa0459712007 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Thu Aug 02 19:39:55 2018 +0300 +++ b/njs/test/njs_unit_test.c Mon Aug 20 18:58:03 2018 +0300 @@ -4322,7 +4322,7 @@ static njs_unit_test_t njs_test[] = { nxt_string("var r = { toString: function() { return /45/ } };" "'123456'.search(r)"), - nxt_string("TypeError: cannot evaluate an object's value") }, + nxt_string("TypeError: Cannot convert object to primitive value") }, { nxt_string("var r = { toString: function() { return /34/ }," " valueOf: function() { return 45 } };" @@ -4456,7 +4456,7 @@ static njs_unit_test_t njs_test[] = { nxt_string("var r = { toString: function() { return /45/ } };" "'123456'.match(r)"), - nxt_string("TypeError: cannot evaluate an object's value") }, + nxt_string("TypeError: Cannot convert object to primitive value") }, { nxt_string("var r = { toString: function() { return /34/ }," " valueOf: function() { return 45 } };" @@ -5927,10 +5927,10 @@ static njs_unit_test_t njs_test[] = nxt_string("o:OK") }, { nxt_string("var o = { toString: function() { return [1] } }; o"), - nxt_string("TypeError: cannot evaluate an object's value") }, + nxt_string("TypeError: Cannot convert object to primitive value") }, { nxt_string("var o = { toString: function() { return [1] } }; 'o:' + o"), - nxt_string("TypeError: cannot evaluate an object's value") }, + nxt_string("TypeError: Cannot convert object to primitive value") }, { nxt_string("var a = { valueOf: function() { return '3' } };" "var b = { toString: function() { return 10 - a + 'OK' } };" From ccaputo at alt.net Wed Aug 22 23:57:02 2018 From: ccaputo at alt.net (Chris Caputo) Date: Wed, 22 Aug 2018 23:57:02 +0000 (UTC) Subject: [PATCH] uwsgi - prevent protocol overflow Message-ID: At present, ngx_http_uwsgi_module.c's ngx_http_uwsgi_create_request() has nothing to stop it from dispatching a request exceeding what is possible per the uwsgi protocol: https://uwsgi-docs.readthedocs.io/en/latest/Protocol.html The limit is 65,535 (0xffff) and when a request exceeds that size, this function is currently just overflowing, with the uwsgi handler receiving a large buffer with a length that doesn't match it. Would someone review and help me get the below code to be accepted? Thank you, Chris --- ngx_http_uwsgi_module.c.original 2018-08-22 23:41:16.309151481 +0000 +++ ngx_http_uwsgi_module.c 2018-08-22 23:43:39.546795158 +0000 @@ -960,6 +960,13 @@ } #endif + /* enforce uwsgi protocol max len of uint16 */ + if (len > 0xffff) { + ngx_log_error (NGX_LOG_ALERT, r->connection->log, 0, + "uwsgi request is too large for uwsgi protocol: %uz", len); + return NGX_ERROR; + } + b = ngx_create_temp_buf(r->pool, len + 4); if (b == NULL) { return NGX_ERROR; From vl at nginx.com Fri Aug 24 15:04:09 2018 From: vl at nginx.com (Vladimir Homutov) Date: Fri, 24 Aug 2018 15:04:09 +0000 Subject: [nginx] Upstream: fixed request chain traversal (ticket #1618). Message-ID: details: http://hg.nginx.org/nginx/rev/15ea84e65d07 branches: changeset: 7341:15ea84e65d07 user: Vladimir Homutov date: Fri Aug 24 12:19:37 2018 +0300 description: Upstream: fixed request chain traversal (ticket #1618). The problem does not manifest itself currently, because in case of non-buffered reading, chain link created by u->create_request method consists of a single element. Found by PVS-Studio. diffstat: src/http/ngx_http_upstream.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diffs (12 lines): diff -r 70c6b08973a0 -r 15ea84e65d07 src/http/ngx_http_upstream.c --- a/src/http/ngx_http_upstream.c Fri Aug 10 21:54:46 2018 +0300 +++ b/src/http/ngx_http_upstream.c Fri Aug 24 12:19:37 2018 +0300 @@ -2135,7 +2135,7 @@ ngx_http_upstream_send_request_body(ngx_ out = u->request_bufs; if (r->request_body->bufs) { - for (cl = out; cl->next; cl = out->next) { /* void */ } + for (cl = out; cl->next; cl = cl->next) { /* void */ } cl->next = r->request_body->bufs; r->request_body->bufs = NULL; } From ru at nginx.com Mon Aug 27 11:28:47 2018 From: ru at nginx.com (Ruslan Ermilov) Date: Mon, 27 Aug 2018 14:28:47 +0300 Subject: limit_rate_after support variables In-Reply-To: References: Message-ID: <20180827112847.GE71000@lo0.su> Hi, On Tue, Aug 14, 2018 at 10:22:14AM +0200, Miroslav Novy wrote: > # HG changeset patch > # User Miroslav Nov? > # Date 1534234559 0 > # Tue Aug 14 08:15:59 2018 +0000 > # Node ID 1a8327b50f7844cbe68226f54de60632189327f4 > # Parent 70c6b08973a02551612da4a4273757dc77c70ae2 > limit_rate_after support variables > > Example of use: > location / { > root /var/www/default/; > index index.html index.htm; > > set $my_limit_rate_after 2m; > > limit_rate_after $my_limit_rate_after; > limit_rate 2k; > > access_by_lua_block { > ngx.var.my_limit_rate_after = '10m' > } > > } > > diff -r 70c6b08973a0 -r 1a8327b50f78 src/http/ngx_http_core_module.c > --- a/src/http/ngx_http_core_module.c Fri Aug 10 21:54:46 2018 +0300 > +++ b/src/http/ngx_http_core_module.c Tue Aug 14 08:15:59 2018 +0000 > @@ -487,7 +487,7 @@ > { ngx_string("limit_rate_after"), > > NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF > |NGX_CONF_TAKE1, > - ngx_conf_set_size_slot, > + ngx_http_set_complex_value_slot, > NGX_HTTP_LOC_CONF_OFFSET, > offsetof(ngx_http_core_loc_conf_t, limit_rate_after), > NULL }, > @@ -3364,6 +3364,7 @@ > * clcf->alias = 0; > * clcf->gzip_proxied = 0; > * clcf->keepalive_disable = 0; > + * clcf->limit_rate_after = NULL; > */ > > clcf->client_max_body_size = NGX_CONF_UNSET; > @@ -3393,7 +3394,6 @@ > clcf->send_lowat = NGX_CONF_UNSET_SIZE; > clcf->postpone_output = NGX_CONF_UNSET_SIZE; > clcf->limit_rate = NGX_CONF_UNSET_SIZE; > - clcf->limit_rate_after = NGX_CONF_UNSET_SIZE; > clcf->keepalive_timeout = NGX_CONF_UNSET_MSEC; > clcf->keepalive_header = NGX_CONF_UNSET; > clcf->keepalive_requests = NGX_CONF_UNSET_UINT; > @@ -3623,8 +3623,8 @@ > ngx_conf_merge_size_value(conf->postpone_output, prev->postpone_output, > 1460); > ngx_conf_merge_size_value(conf->limit_rate, prev->limit_rate, 0); > - ngx_conf_merge_size_value(conf->limit_rate_after, > prev->limit_rate_after, > - 0); > + ngx_conf_merge_ptr_value(conf->limit_rate_after, > prev->limit_rate_after, > + NULL); This won't work because create_loc_conf() initialized clcf->limit_rate_after to NULL instead of NGX_CONF_UNSET_PTR. I suggest using a simple "== NULL" check here. > ngx_conf_merge_msec_value(conf->keepalive_timeout, > prev->keepalive_timeout, 75000); > ngx_conf_merge_sec_value(conf->keepalive_header, > diff -r 70c6b08973a0 -r 1a8327b50f78 src/http/ngx_http_core_module.h > --- a/src/http/ngx_http_core_module.h Fri Aug 10 21:54:46 2018 +0300 > +++ b/src/http/ngx_http_core_module.h Tue Aug 14 08:15:59 2018 +0000 > @@ -351,7 +351,7 @@ > size_t send_lowat; /* send_lowat */ > size_t postpone_output; /* postpone_output */ > size_t limit_rate; /* limit_rate */ > - size_t limit_rate_after; /* limit_rate_after */ > + ngx_http_complex_value_t *limit_rate_after; /* > limit_rate_after */ > size_t sendfile_max_chunk; /* sendfile_max_chunk */ > size_t read_ahead; /* read_ahead */ > size_t subrequest_output_buffer_size; > diff -r 70c6b08973a0 -r 1a8327b50f78 src/http/ngx_http_write_filter_module.c > --- a/src/http/ngx_http_write_filter_module.c Fri Aug 10 21:54:46 2018 +0300 > +++ b/src/http/ngx_http_write_filter_module.c Tue Aug 14 08:15:59 2018 +0000 > @@ -220,7 +220,26 @@ > > if (r->limit_rate) { > if (r->limit_rate_after == 0) { > - r->limit_rate_after = clcf->limit_rate_after; > + r->limit_rate_after = 0; This assignment is pointless. > + > + if (clcf->limit_rate_after != NULL) { You can omit the "!= NULL" part of the check. > + ngx_str_t res; > + size_t st; There are style issues here, please see http://nginx.org/en/docs/dev/development_guide.html#code_style Also, I suggest renaming "st" to "s" here, and changing its type to ssize_t. > + > + if (ngx_http_complex_value(r, clcf->limit_rate_after, &res) > + != NGX_OK) > + { > + return NGX_ERROR; > + } > + > + st = ngx_parse_size(&res); > + if (st != (size_t) NGX_ERROR) { > + r->limit_rate_after = st; > + } else { > + ngx_log_error(NGX_LOG_ALERT, c->log, 0, > + "limit_rate_after has bad value"); > + } > + } > } > > limit = (off_t) r->limit_rate * (ngx_time() - r->start_sec + 1) P.S. Please find another MUA that doesn't break text attachments. -- Ruslan Ermilov Assume stupidity not malice From miranovy at gmail.com Mon Aug 27 13:37:04 2018 From: miranovy at gmail.com (Miroslav Novy) Date: Mon, 27 Aug 2018 15:37:04 +0200 Subject: limit_rate_after support variables In-Reply-To: <20180827112847.GE71000@lo0.su> References: <20180827112847.GE71000@lo0.su> Message-ID: Hello, thank you for your comments. I'm sending their incorporation. Best regards M?ra diff -r 70c6b08973a0 src/http/ngx_http_core_module.c --- a/src/http/ngx_http_core_module.c Fri Aug 10 21:54:46 2018 +0300 +++ b/src/http/ngx_http_core_module.c Mon Aug 27 13:31:45 2018 +0000 @@ -487,7 +487,7 @@ { ngx_string("limit_rate_after"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF |NGX_CONF_TAKE1, - ngx_conf_set_size_slot, + ngx_http_set_complex_value_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_core_loc_conf_t, limit_rate_after), NULL }, @@ -3364,6 +3364,7 @@ * clcf->alias = 0; * clcf->gzip_proxied = 0; * clcf->keepalive_disable = 0; + * clcf->limit_rate_after = NULL; */ clcf->client_max_body_size = NGX_CONF_UNSET; @@ -3393,7 +3394,6 @@ clcf->send_lowat = NGX_CONF_UNSET_SIZE; clcf->postpone_output = NGX_CONF_UNSET_SIZE; clcf->limit_rate = NGX_CONF_UNSET_SIZE; - clcf->limit_rate_after = NGX_CONF_UNSET_SIZE; clcf->keepalive_timeout = NGX_CONF_UNSET_MSEC; clcf->keepalive_header = NGX_CONF_UNSET; clcf->keepalive_requests = NGX_CONF_UNSET_UINT; @@ -3623,8 +3623,11 @@ ngx_conf_merge_size_value(conf->postpone_output, prev->postpone_output, 1460); ngx_conf_merge_size_value(conf->limit_rate, prev->limit_rate, 0); - ngx_conf_merge_size_value(conf->limit_rate_after, prev->limit_rate_after, - 0); + + if (conf->limit_rate_after == NULL) { + conf->limit_rate_after = prev->limit_rate_after; + } + ngx_conf_merge_msec_value(conf->keepalive_timeout, prev->keepalive_timeout, 75000); ngx_conf_merge_sec_value(conf->keepalive_header, diff -r 70c6b08973a0 src/http/ngx_http_core_module.h --- a/src/http/ngx_http_core_module.h Fri Aug 10 21:54:46 2018 +0300 +++ b/src/http/ngx_http_core_module.h Mon Aug 27 13:31:45 2018 +0000 @@ -351,7 +351,7 @@ size_t send_lowat; /* send_lowat */ size_t postpone_output; /* postpone_output */ size_t limit_rate; /* limit_rate */ - size_t limit_rate_after; /* limit_rate_after */ + ngx_http_complex_value_t *limit_rate_after; /* limit_rate_after */ size_t sendfile_max_chunk; /* sendfile_max_chunk */ size_t read_ahead; /* read_ahead */ size_t subrequest_output_buffer_size; diff -r 70c6b08973a0 src/http/ngx_http_write_filter_module.c --- a/src/http/ngx_http_write_filter_module.c Fri Aug 10 21:54:46 2018 +0300 +++ b/src/http/ngx_http_write_filter_module.c Mon Aug 27 13:31:45 2018 +0000 @@ -220,7 +220,24 @@ if (r->limit_rate) { if (r->limit_rate_after == 0) { - r->limit_rate_after = clcf->limit_rate_after; + if (clcf->limit_rate_after) { + ngx_str_t res; + ssize_t s; + + if (ngx_http_complex_value(r, clcf->limit_rate_after, &res) + != NGX_OK) + { + return NGX_ERROR; + } + + s = ngx_parse_size(&res); + if (s == NGX_ERROR) { + ngx_log_error(NGX_LOG_ALERT, c->log, 0, + "limit_rate_after has bad value"); + } else { + r->limit_rate_after = s; + } + } } limit = (off_t) r->limit_rate * (ngx_time() - r->start_sec + 1) po 27. 8. 2018 v 13:28 odes?latel Ruslan Ermilov napsal: > Hi, > > On Tue, Aug 14, 2018 at 10:22:14AM +0200, Miroslav Novy wrote: > > # HG changeset patch > > # User Miroslav Nov? > > # Date 1534234559 0 > > # Tue Aug 14 08:15:59 2018 +0000 > > # Node ID 1a8327b50f7844cbe68226f54de60632189327f4 > > # Parent 70c6b08973a02551612da4a4273757dc77c70ae2 > > limit_rate_after support variables > > > > Example of use: > > location / { > > root /var/www/default/; > > index index.html index.htm; > > > > set $my_limit_rate_after 2m; > > > > limit_rate_after $my_limit_rate_after; > > limit_rate 2k; > > > > access_by_lua_block { > > ngx.var.my_limit_rate_after = '10m' > > } > > > > } > > > > diff -r 70c6b08973a0 -r 1a8327b50f78 src/http/ngx_http_core_module.c > > --- a/src/http/ngx_http_core_module.c Fri Aug 10 21:54:46 2018 +0300 > > +++ b/src/http/ngx_http_core_module.c Tue Aug 14 08:15:59 2018 +0000 > > @@ -487,7 +487,7 @@ > > { ngx_string("limit_rate_after"), > > > > NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF > > |NGX_CONF_TAKE1, > > - ngx_conf_set_size_slot, > > + ngx_http_set_complex_value_slot, > > NGX_HTTP_LOC_CONF_OFFSET, > > offsetof(ngx_http_core_loc_conf_t, limit_rate_after), > > NULL }, > > @@ -3364,6 +3364,7 @@ > > * clcf->alias = 0; > > * clcf->gzip_proxied = 0; > > * clcf->keepalive_disable = 0; > > + * clcf->limit_rate_after = NULL; > > */ > > > > clcf->client_max_body_size = NGX_CONF_UNSET; > > @@ -3393,7 +3394,6 @@ > > clcf->send_lowat = NGX_CONF_UNSET_SIZE; > > clcf->postpone_output = NGX_CONF_UNSET_SIZE; > > clcf->limit_rate = NGX_CONF_UNSET_SIZE; > > - clcf->limit_rate_after = NGX_CONF_UNSET_SIZE; > > clcf->keepalive_timeout = NGX_CONF_UNSET_MSEC; > > clcf->keepalive_header = NGX_CONF_UNSET; > > clcf->keepalive_requests = NGX_CONF_UNSET_UINT; > > @@ -3623,8 +3623,8 @@ > > ngx_conf_merge_size_value(conf->postpone_output, > prev->postpone_output, > > 1460); > > ngx_conf_merge_size_value(conf->limit_rate, prev->limit_rate, 0); > > - ngx_conf_merge_size_value(conf->limit_rate_after, > > prev->limit_rate_after, > > - 0); > > + ngx_conf_merge_ptr_value(conf->limit_rate_after, > > prev->limit_rate_after, > > + NULL); > > This won't work because create_loc_conf() initialized > clcf->limit_rate_after > to NULL instead of NGX_CONF_UNSET_PTR. I suggest using a simple "== NULL" > check here. > > > ngx_conf_merge_msec_value(conf->keepalive_timeout, > > prev->keepalive_timeout, 75000); > > ngx_conf_merge_sec_value(conf->keepalive_header, > > diff -r 70c6b08973a0 -r 1a8327b50f78 src/http/ngx_http_core_module.h > > --- a/src/http/ngx_http_core_module.h Fri Aug 10 21:54:46 2018 +0300 > > +++ b/src/http/ngx_http_core_module.h Tue Aug 14 08:15:59 2018 +0000 > > @@ -351,7 +351,7 @@ > > size_t send_lowat; /* send_lowat */ > > size_t postpone_output; /* postpone_output */ > > size_t limit_rate; /* limit_rate */ > > - size_t limit_rate_after; /* limit_rate_after */ > > + ngx_http_complex_value_t *limit_rate_after; /* > > limit_rate_after */ > > size_t sendfile_max_chunk; /* sendfile_max_chunk */ > > size_t read_ahead; /* read_ahead */ > > size_t subrequest_output_buffer_size; > > diff -r 70c6b08973a0 -r 1a8327b50f78 > src/http/ngx_http_write_filter_module.c > > --- a/src/http/ngx_http_write_filter_module.c Fri Aug 10 21:54:46 2018 > +0300 > > +++ b/src/http/ngx_http_write_filter_module.c Tue Aug 14 08:15:59 2018 > +0000 > > @@ -220,7 +220,26 @@ > > > > if (r->limit_rate) { > > if (r->limit_rate_after == 0) { > > - r->limit_rate_after = clcf->limit_rate_after; > > + r->limit_rate_after = 0; > > This assignment is pointless. > > > + > > + if (clcf->limit_rate_after != NULL) { > > You can omit the "!= NULL" part of the check. > > > + ngx_str_t res; > > + size_t st; > > There are style issues here, please see > http://nginx.org/en/docs/dev/development_guide.html#code_style > > Also, I suggest renaming "st" to "s" here, and changing its type to > ssize_t. > > > + > > + if (ngx_http_complex_value(r, clcf->limit_rate_after, > &res) > > + != NGX_OK) > > + { > > + return NGX_ERROR; > > + } > > + > > + st = ngx_parse_size(&res); > > + if (st != (size_t) NGX_ERROR) { > > + r->limit_rate_after = st; > > + } else { > > + ngx_log_error(NGX_LOG_ALERT, c->log, 0, > > + "limit_rate_after has bad value"); > > + } > > + } > > } > > > > limit = (off_t) r->limit_rate * (ngx_time() - r->start_sec + 1) > > P.S. Please find another MUA that doesn't break text attachments. > > > -- > Ruslan Ermilov > Assume stupidity not malice > _______________________________________________ > 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 xeioex at nginx.com Mon Aug 27 13:55:46 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Mon, 27 Aug 2018 13:55:46 +0000 Subject: [njs] Throwing TypeError for attempts to change frozen properties. Message-ID: details: http://hg.nginx.org/njs/rev/b15051895c8e branches: changeset: 584:b15051895c8e user: Dmitry Volyntsev date: Mon Aug 27 14:59:59 2018 +0300 description: Throwing TypeError for attempts to change frozen properties. This fixes #35 issue on Github. diffstat: njs/njs_vm.c | 39 ++++++++++---- njs/test/njs_unit_test.c | 120 ++++++++++++++++++++++------------------------ 2 files changed, 84 insertions(+), 75 deletions(-) diffs (298 lines): diff -r aa0459712007 -r b15051895c8e njs/njs_vm.c --- a/njs/njs_vm.c Mon Aug 20 18:58:03 2018 +0300 +++ b/njs/njs_vm.c Mon Aug 27 14:59:59 2018 +0300 @@ -645,6 +645,7 @@ njs_vmcode_property_set(njs_vm_t *vm, nj code = (njs_vmcode_prop_set_t *) vm->current; value = njs_vmcode_operand(vm, code->value); + pq.lhq.key.length = 0; pq.query = NJS_PROPERTY_QUERY_SET; ret = njs_property_query(vm, &pq, object, property); @@ -667,8 +668,11 @@ njs_vmcode_property_set(njs_vm_t *vm, nj break; case NXT_DECLINED: - if (!object->data.u.object->extensible) { - return sizeof(njs_vmcode_prop_set_t); + if (nxt_slow_path(!object->data.u.object->extensible)) { + njs_type_error(vm, "Cannot add property '%.*s', " + "object is not extensible", pq.lhq.key.length, + pq.lhq.key.start); + return NXT_ERROR; } prop = njs_object_prop_alloc(vm, &pq.value, &njs_value_void, 1); @@ -736,10 +740,15 @@ njs_vmcode_property_set(njs_vm_t *vm, nj return ret; } - if (prop->writable) { - prop->value = *value; + if (nxt_slow_path(!prop->writable)) { + njs_type_error(vm, "Cannot assign to read-only property '%.*s' of %s", + pq.lhq.key.length, pq.lhq.key.start, + njs_type_string(object->type)); + return NXT_ERROR; } + prop->value = *value; + return sizeof(njs_vmcode_prop_set_t); } @@ -841,6 +850,7 @@ njs_vmcode_property_delete(njs_vm_t *vm, retval = &njs_value_false; + pq.lhq.key.length = 0; pq.query = NJS_PROPERTY_QUERY_DELETE; ret = njs_property_query(vm, &pq, object, property); @@ -850,16 +860,21 @@ njs_vmcode_property_delete(njs_vm_t *vm, case NXT_OK: prop = pq.lhq.value; - if (prop->configurable) { - pq.lhq.pool = vm->mem_cache_pool; - - (void) nxt_lvlhsh_delete(&object->data.u.object->hash, &pq.lhq); - - njs_release(vm, property); - - retval = &njs_value_true; + if (nxt_slow_path(!prop->configurable)) { + njs_type_error(vm, "Cannot delete property '%.*s' of %s", + pq.lhq.key.length, pq.lhq.key.start, + njs_type_string(object->type)); + return NXT_ERROR; } + pq.lhq.pool = vm->mem_cache_pool; + + (void) nxt_lvlhsh_delete(&object->data.u.object->hash, &pq.lhq); + + njs_release(vm, property); + + retval = &njs_value_true; + break; case NXT_DECLINED: diff -r aa0459712007 -r b15051895c8e njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Mon Aug 20 18:58:03 2018 +0300 +++ b/njs/test/njs_unit_test.c Mon Aug 27 14:59:59 2018 +0300 @@ -2817,9 +2817,11 @@ static njs_unit_test_t njs_test[] = /* Array.toString(). */ +# if 0 { nxt_string("var a = [1,2,3]; a.join = 'NO';" "Object.prototype.toString = function () { return 'A' }; a"), nxt_string("[object Array]") }, +#endif { nxt_string("Array.prototype.toString.call(1)"), nxt_string("[object Number]") }, @@ -5699,8 +5701,8 @@ static njs_unit_test_t njs_test[] = /* Memory object is immutable. */ - { nxt_string("var e = MemoryError('e'); e.name = 'E'; e.message = 'e'; e"), - nxt_string("MemoryError") }, + { nxt_string("var e = MemoryError('e'); e.name = 'E'"), + nxt_string("TypeError: Cannot add property 'name', object is not extensible") }, { nxt_string("EvalError.prototype.name"), nxt_string("EvalError") }, @@ -6684,20 +6686,19 @@ static njs_unit_test_t njs_test[] = "Object.keys(o)"), nxt_string("a,c,b") }, - { nxt_string("var o = {}; Object.defineProperty(o, 'a', {}); o.a = 1; o.a"), - nxt_string("undefined") }, - - { nxt_string("var o = {}; Object.defineProperty(o, 'a', {writable:false});" - "o.a = 1; o.a"), - nxt_string("undefined") }, + { nxt_string("var o = {}; Object.defineProperty(o, 'a', {}); o.a = 1"), + nxt_string("TypeError: Cannot assign to read-only property 'a' of object") }, + + { nxt_string("var o = {}; Object.defineProperty(o, 'a', {writable:false}); o.a = 1"), + nxt_string("TypeError: Cannot assign to read-only property 'a' of object") }, { nxt_string("var o = {}; Object.defineProperty(o, 'a', {writable:true});" "o.a = 1; o.a"), nxt_string("1") }, { nxt_string("var o = {};" - "Object.defineProperty(o, 'a', {value:1}); delete o.a; o.a"), - nxt_string("1") }, + "Object.defineProperty(o, 'a', {value:1}); delete o.a"), + nxt_string("TypeError: Cannot delete property 'a' of object") }, { nxt_string("var o = {};" "Object.defineProperty(o, 'a', {value:1, configurable:true});" @@ -6706,8 +6707,8 @@ static njs_unit_test_t njs_test[] = { nxt_string("var o = {};" "Object.defineProperty(o, 'a', {value:1, configurable:false});" - "delete o.a; o.a"), - nxt_string("1") }, + "delete o.a"), + nxt_string("TypeError: Cannot delete property 'a' of object") }, { nxt_string("var o = {};" "Object.defineProperty(o, 'a', Object.create({value:2})); o.a"), @@ -6894,17 +6895,17 @@ static njs_unit_test_t njs_test[] = { nxt_string("Object.freeze()"), nxt_string("undefined") }, - { nxt_string("var o = Object.freeze({a:1}); o.a = 2; o.a"), - nxt_string("1") }, - - { nxt_string("var o = Object.freeze({a:1}); delete o.a; o.a"), - nxt_string("1") }, + { nxt_string("var o = Object.freeze({a:1}); o.a = 2"), + nxt_string("TypeError: Cannot assign to read-only property 'a' of object") }, + + { nxt_string("var o = Object.freeze({a:1}); delete o.a"), + nxt_string("TypeError: Cannot delete property 'a' of object") }, { nxt_string("var o = Object.freeze({a:1}); o.b = 1; o.b"), - nxt_string("undefined") }, + nxt_string("TypeError: Cannot add property 'b', object is not extensible") }, { nxt_string("var o = Object.freeze(Object.create({a:1})); o.a = 2; o.a"), - nxt_string("1") }, + nxt_string("TypeError: Cannot add property 'a', object is not extensible") }, { nxt_string("var o = Object.freeze({a:{b:1}}); o.a.b = 2; o.a.b"), nxt_string("2") }, @@ -6916,16 +6917,14 @@ static njs_unit_test_t njs_test[] = "Object.defineProperty(a, 'a', {value:1}).a"), nxt_string("TypeError: object is not extensible") }, - { nxt_string("var a = [1,2]; a.a = 1; Object.freeze(a);" - "delete a.a; a.a"), - nxt_string("1") }, - - { nxt_string("var a = [1,2]; a.a = 1; Object.freeze(a);" - "a.a = 2; a.a"), - nxt_string("1") }, - - { nxt_string("var a = Object.freeze([1,2]); a.a = 1; a.a"), - nxt_string("undefined") }, + { nxt_string("var a = [1,2]; a.a = 1; Object.freeze(a); delete a.a"), + nxt_string("TypeError: Cannot delete property 'a' of array") }, + + { nxt_string("var a = [1,2]; a.a = 1; Object.freeze(a); a.a = 2"), + nxt_string("TypeError: Cannot assign to read-only property 'a' of array") }, + + { nxt_string("var a = Object.freeze([1,2]); a.a = 1"), + nxt_string("TypeError: Cannot add property 'a', object is not extensible") }, { nxt_string("Object.defineProperty(function() {}, 'a', {value:1}).a"), nxt_string("1") }, @@ -6934,16 +6933,14 @@ static njs_unit_test_t njs_test[] = "Object.defineProperty(f, 'a', {value:1}).a"), nxt_string("TypeError: object is not extensible") }, - { nxt_string("var f = function() {}; f.a = 1; Object.freeze(f);" - "delete f.a; f.a"), - nxt_string("1") }, - - { nxt_string("var f = function() {}; f.a = 1; Object.freeze(f);" - "f.a = 2; f.a"), - nxt_string("1") }, - - { nxt_string("var f = Object.freeze(function() {}); f.a = 1; f.a"), - nxt_string("undefined") }, + { nxt_string("var f = function() {}; f.a = 1; Object.freeze(f); delete f.a"), + nxt_string("TypeError: Cannot delete property 'a' of function") }, + + { nxt_string("var f = function() {}; f.a = 1; Object.freeze(f); f.a = 2"), + nxt_string("TypeError: Cannot assign to read-only property 'a' of function") }, + + { nxt_string("var f = Object.freeze(function() {}); f.a = 1"), + nxt_string("TypeError: Cannot add property 'a', object is not extensible") }, { nxt_string("Object.defineProperty(new Date(''), 'a', {value:1}).a"), nxt_string("1") }, @@ -6953,15 +6950,14 @@ static njs_unit_test_t njs_test[] = nxt_string("TypeError: object is not extensible") }, { nxt_string("var d = new Date(''); d.a = 1; Object.freeze(d);" - "delete d.a; d.a"), - nxt_string("1") }, - - { nxt_string("var d = new Date(''); d.a = 1; Object.freeze(d);" - "d.a = 2; d.a"), - nxt_string("1") }, - - { nxt_string("var d = Object.freeze(new Date('')); d.a = 1; d.a"), - nxt_string("undefined") }, + "delete d.a"), + nxt_string("TypeError: Cannot delete property 'a' of date") }, + + { nxt_string("var d = new Date(''); d.a = 1; Object.freeze(d); d.a = 2"), + nxt_string("TypeError: Cannot assign to read-only property 'a' of date") }, + + { nxt_string("var d = Object.freeze(new Date('')); d.a = 1"), + nxt_string("TypeError: Cannot add property 'a', object is not extensible") }, { nxt_string("Object.defineProperty(new RegExp(''), 'a', {value:1}).a"), nxt_string("1") }, @@ -6970,16 +6966,14 @@ static njs_unit_test_t njs_test[] = "Object.defineProperty(r, 'a', {value:1}).a"), nxt_string("TypeError: object is not extensible") }, - { nxt_string("var r = new RegExp(''); r.a = 1; Object.freeze(r);" - "delete r.a; r.a"), - nxt_string("1") }, - - { nxt_string("var r = new RegExp(''); r.a = 1; Object.freeze(r);" - "r.a = 2; r.a"), - nxt_string("1") }, - - { nxt_string("var r = Object.freeze(new RegExp('')); r.a = 1; r.a"), - nxt_string("undefined") }, + { nxt_string("var r = new RegExp(''); r.a = 1; Object.freeze(r); delete r.a"), + nxt_string("TypeError: Cannot delete property 'a' of regexp") }, + + { nxt_string("var r = new RegExp(''); r.a = 1; Object.freeze(r); r.a = 2"), + nxt_string("TypeError: Cannot assign to read-only property 'a' of regexp") }, + + { nxt_string("var r = Object.freeze(new RegExp('')); r.a = 1"), + nxt_string("TypeError: Cannot add property 'a', object is not extensible") }, { nxt_string("Object.isFrozen({a:1})"), nxt_string("false") }, @@ -7038,14 +7032,14 @@ static njs_unit_test_t njs_test[] = { nxt_string("var o = Object.seal({a:1}); o.a = 2; o.a"), nxt_string("2") }, - { nxt_string("var o = Object.seal({a:1}); delete o.a; o.a"), - nxt_string("1") }, + { nxt_string("var o = Object.seal({a:1}); delete o.a"), + nxt_string("TypeError: Cannot delete property 'a' of object") }, { nxt_string("var o = Object.seal({a:1}); o.b = 1; o.b"), - nxt_string("undefined") }, + nxt_string("TypeError: Cannot add property 'b', object is not extensible") }, { nxt_string("var o = Object.seal(Object.create({a:1})); o.a = 2; o.a"), - nxt_string("1") }, + nxt_string("TypeError: Cannot add property 'a', object is not extensible") }, { nxt_string("var o = Object.seal({a:{b:1}}); o.a.b = 2; o.a.b"), nxt_string("2") }, @@ -7128,7 +7122,7 @@ static njs_unit_test_t njs_test[] = nxt_string("undefined") }, { nxt_string("var o = Object.preventExtensions({a:1}); o.b = 1; o.b"), - nxt_string("undefined") }, + nxt_string("TypeError: Cannot add property 'b', object is not extensible") }, { nxt_string("Object.preventExtensions()"), nxt_string("undefined") }, From xeioex at nginx.com Mon Aug 27 13:55:46 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Mon, 27 Aug 2018 13:55:46 +0000 Subject: [njs] Fixed toString() for -0. Message-ID: details: http://hg.nginx.org/njs/rev/7ce43874f706 branches: changeset: 585:7ce43874f706 user: Dmitry Volyntsev date: Mon Aug 27 16:06:33 2018 +0300 description: Fixed toString() for -0. diffstat: njs/njs_vm.c | 12 +++++++++++- njs/njs_vm.h | 1 + njs/test/njs_unit_test.c | 6 ++++++ nxt/nxt_dtoa.c | 12 ++++++------ 4 files changed, 24 insertions(+), 7 deletions(-) diffs (91 lines): diff -r b15051895c8e -r 7ce43874f706 njs/njs_vm.c --- a/njs/njs_vm.c Mon Aug 27 14:59:59 2018 +0300 +++ b/njs/njs_vm.c Mon Aug 27 16:06:33 2018 +0300 @@ -88,6 +88,7 @@ const njs_value_t njs_string_boolean = const njs_value_t njs_string_false = njs_string("false"); const njs_value_t njs_string_true = njs_string("true"); const njs_value_t njs_string_number = njs_string("number"); +const njs_value_t njs_string_minus_zero = njs_string("-0"); const njs_value_t njs_string_minus_infinity = njs_string("-Infinity"); const njs_value_t njs_string_plus_infinity = @@ -3310,7 +3311,16 @@ again: } } - ret = njs_primitive_value_to_string(vm, &value, &value); + if (nxt_slow_path((value.type == NJS_NUMBER + && value.data.u.number == 0 + && signbit(value.data.u.number)))) + { + value = njs_string_minus_zero; + ret = NXT_OK; + + } else { + ret = njs_primitive_value_to_string(vm, &value, &value); + } if (nxt_fast_path(ret == NXT_OK)) { size = value.short_string.size; diff -r b15051895c8e -r 7ce43874f706 njs/njs_vm.h --- a/njs/njs_vm.h Mon Aug 27 14:59:59 2018 +0300 +++ b/njs/njs_vm.h Mon Aug 27 16:06:33 2018 +0300 @@ -1269,6 +1269,7 @@ extern const njs_value_t njs_string_nul extern const njs_value_t njs_string_false; extern const njs_value_t njs_string_true; extern const njs_value_t njs_string_native; +extern const njs_value_t njs_string_minus_zero; extern const njs_value_t njs_string_minus_infinity; extern const njs_value_t njs_string_plus_infinity; extern const njs_value_t njs_string_nan; diff -r b15051895c8e -r 7ce43874f706 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Mon Aug 27 14:59:59 2018 +0300 +++ b/njs/test/njs_unit_test.c Mon Aug 27 16:06:33 2018 +0300 @@ -420,6 +420,9 @@ static njs_unit_test_t njs_test[] = { nxt_string("1 + 1 + '2' + 1 + 1"), nxt_string("2211") }, + { nxt_string("'gg' + -0"), + nxt_string("gg0") }, + { nxt_string("1.2 - '5.7'"), nxt_string("-4.5") }, @@ -8976,6 +8979,9 @@ static njs_unit_test_t njs_test[] = { nxt_string("JSON.stringify(123)"), nxt_string("123") }, + { nxt_string("JSON.stringify(-0)"), + nxt_string("0") }, + { nxt_string("JSON.stringify(0.00000123)"), nxt_string("0.00000123") }, diff -r b15051895c8e -r 7ce43874f706 nxt/nxt_dtoa.c --- a/nxt/nxt_dtoa.c Mon Aug 27 14:59:59 2018 +0300 +++ b/nxt/nxt_dtoa.c Mon Aug 27 16:06:33 2018 +0300 @@ -346,18 +346,18 @@ nxt_dtoa(double value, char *start) minus = 0; p = start; + if (value == 0) { + *p++ = '0'; + + return (p - start); + } + if (signbit(value)) { *p++ = '-'; value = -value; minus = 1; } - if (value == 0) { - *p++ = '0'; - - return (p - start); - } - length = nxt_grisu2(value, p, &dec_exp); length = nxt_prettify(p, length, dec_exp); From xeioex at nginx.com Mon Aug 27 13:55:46 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Mon, 27 Aug 2018 13:55:46 +0000 Subject: [njs] Fixed Object.defineProperty() for existing properties. Message-ID: details: http://hg.nginx.org/njs/rev/c572768e287b branches: changeset: 586:c572768e287b user: Dmitry Volyntsev date: Mon Aug 27 16:23:08 2018 +0300 description: Fixed Object.defineProperty() for existing properties. This fixes #46 issues on Github. diffstat: njs/njs_object.c | 163 ++++++++++++++++++++++++++++++++++------------ njs/njs_object.h | 19 ++++- njs/test/njs_unit_test.c | 61 +++++++++++++++++ 3 files changed, 194 insertions(+), 49 deletions(-) diffs (306 lines): diff -r 7ce43874f706 -r c572768e287b njs/njs_object.c --- a/njs/njs_object.c Mon Aug 27 16:06:33 2018 +0300 +++ b/njs/njs_object.c Mon Aug 27 16:23:08 2018 +0300 @@ -828,13 +828,72 @@ njs_object_define_properties(njs_vm_t *v } +static uint8_t +njs_descriptor_attribute(njs_vm_t *vm, const njs_object_t *descriptor, + nxt_lvlhsh_query_t *pq, nxt_bool_t unset) +{ + njs_object_prop_t *prop; + + prop = njs_object_property(vm, descriptor, pq); + if (prop != NULL) { + return prop->value.data.truth; + } + + return unset ? NJS_ATTRIBUTE_UNSET : 0; +} + + +static njs_object_prop_t * +njs_descriptor_prop(njs_vm_t *vm, const njs_value_t *name, + const njs_object_t *descriptor, nxt_bool_t unset) +{ + const njs_value_t *value; + njs_object_prop_t *prop, *pr; + nxt_lvlhsh_query_t pq; + + value = unset ? &njs_value_invalid : &njs_value_void; + prop = njs_object_prop_alloc(vm, name, value, 0); + if (nxt_slow_path(prop == NULL)) { + return NULL; + } + + pq.key = nxt_string_value("configurable"); + pq.key_hash = NJS_CONFIGURABLE_HASH; + prop->configurable = njs_descriptor_attribute(vm, descriptor, &pq, unset); + + pq.key = nxt_string_value("enumerable"); + pq.key_hash = NJS_ENUMERABLE_HASH; + prop->enumerable = njs_descriptor_attribute(vm, descriptor, &pq, unset); + + pq.key = nxt_string_value("writable"); + pq.key_hash = NJS_WRITABABLE_HASH; + prop->writable = njs_descriptor_attribute(vm, descriptor, &pq, unset); + + pq.key = nxt_string_value("value"); + pq.key_hash = NJS_VALUE_HASH; + pq.proto = &njs_object_hash_proto; + + pr = njs_object_property(vm, descriptor, &pq); + if (pr != NULL) { + prop->value = pr->value; + } + + return prop; +} + + +/* + * ES5.1, 8.12.9: [[DefineOwnProperty]] + * Only data descriptors are suppored. + */ static njs_ret_t njs_define_property(njs_vm_t *vm, njs_object_t *object, const njs_value_t *name, const njs_object_t *descriptor) { nxt_int_t ret; - njs_object_prop_t *prop, *pr; - nxt_lvlhsh_query_t lhq, pq; + nxt_bool_t unset; + njs_object_prop_t *desc, *current; + nxt_lvlhsh_query_t lhq; njs_string_get(name, &lhq.key); lhq.key_hash = nxt_djb_hash(lhq.key.start, lhq.key.length); @@ -842,65 +901,79 @@ njs_define_property(njs_vm_t *vm, njs_ob ret = nxt_lvlhsh_find(&object->hash, &lhq); - if (ret != NXT_OK) { - prop = njs_object_prop_alloc(vm, name, &njs_value_void, 0); + unset = (ret == NXT_OK); + desc = njs_descriptor_prop(vm, name, descriptor, unset); + if (nxt_slow_path(desc == NULL)) { + return NXT_ERROR; + } - if (nxt_slow_path(prop == NULL)) { + if (nxt_fast_path(ret == NXT_DECLINED)) { + lhq.value = desc; + lhq.replace = 0; + lhq.pool = vm->mem_cache_pool; + + ret = nxt_lvlhsh_insert(&object->hash, &lhq); + if (nxt_slow_path(ret != NXT_OK)) { + njs_internal_error(vm, NULL); return NXT_ERROR; } - lhq.value = prop; - - } else { - prop = lhq.value; - } - - pq.key = nxt_string_value("value"); - pq.key_hash = NJS_VALUE_HASH; - pq.proto = &njs_object_hash_proto; - - pr = njs_object_property(vm, descriptor, &pq); - - if (pr != NULL) { - prop->value = pr->value; - } - - pq.key = nxt_string_value("configurable"); - pq.key_hash = NJS_CONFIGURABLE_HASH; - - pr = njs_object_property(vm, descriptor, &pq); - - if (pr != NULL) { - prop->configurable = pr->value.data.truth; + return NXT_OK; } - pq.key = nxt_string_value("enumerable"); - pq.key_hash = NJS_ENUMERABLE_HASH; + /* Updating existing prop. */ + + current = lhq.value; + + if (!current->configurable) { + if (desc->configurable == NJS_ATTRIBUTE_TRUE) { + goto exception; + } - pr = njs_object_property(vm, descriptor, &pq); + if (desc->enumerable != NJS_ATTRIBUTE_UNSET + && current->enumerable != desc->enumerable) + { + goto exception; + } - if (pr != NULL) { - prop->enumerable = pr->value.data.truth; + if (desc->writable == NJS_ATTRIBUTE_TRUE + && current->writable == NJS_ATTRIBUTE_FALSE) + { + goto exception; + } + + if (njs_is_valid(&desc->value) + && current->writable == NJS_ATTRIBUTE_FALSE + && !njs_values_strict_equal(&desc->value, ¤t->value)) + { + goto exception; + } } - pq.key = nxt_string_value("writable"); - pq.key_hash = NJS_WRITABABLE_HASH; - - pr = njs_object_property(vm, descriptor, &pq); - - if (pr != NULL) { - prop->writable = pr->value.data.truth; + if (desc->configurable != NJS_ATTRIBUTE_UNSET) { + current->configurable = desc->configurable; } - lhq.replace = 0; - lhq.pool = vm->mem_cache_pool; + if (desc->enumerable != NJS_ATTRIBUTE_UNSET) { + current->enumerable = desc->enumerable; + } - ret = nxt_lvlhsh_insert(&object->hash, &lhq); - if (nxt_slow_path(ret != NXT_OK)) { - return NXT_ERROR; + if (desc->writable != NJS_ATTRIBUTE_UNSET) { + current->writable = desc->writable; + } + + if (njs_is_valid(&desc->value)) { + current->value = desc->value; } return NXT_OK; + +exception: + + njs_type_error(vm, "Cannot redefine property: '%.*s'", + (int) lhq.key.length, lhq.key.start); + + return NXT_ERROR; } diff -r 7ce43874f706 -r c572768e287b njs/njs_object.h --- a/njs/njs_object.h Mon Aug 27 16:06:33 2018 +0300 +++ b/njs/njs_object.h Mon Aug 27 16:23:08 2018 +0300 @@ -18,15 +18,26 @@ typedef enum { } njs_object_property_type_t; +/* + * Attributes are generally used as Boolean values. + * The UNSET value is used internally only by njs_define_property(). + */ +typedef enum { + NJS_ATTRIBUTE_FALSE = 0, + NJS_ATTRIBUTE_TRUE = 1, + NJS_ATTRIBUTE_UNSET, +} njs_object_attribute_t; + typedef struct { /* Must be aligned to njs_value_t. */ njs_value_t value; njs_value_t name; - njs_object_property_type_t type:8; /* 3 bits */ - uint8_t enumerable; /* 1 bit */ - uint8_t writable; /* 1 bit */ - uint8_t configurable; /* 1 bit */ + njs_object_property_type_t type:8; /* 3 bits */ + + njs_object_attribute_t enumerable:8; /* 2 bits */ + njs_object_attribute_t writable:8; /* 2 bits */ + njs_object_attribute_t configurable:8; /* 2 bits */ } njs_object_prop_t; diff -r 7ce43874f706 -r c572768e287b njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Mon Aug 27 16:06:33 2018 +0300 +++ b/njs/test/njs_unit_test.c Mon Aug 27 16:23:08 2018 +0300 @@ -6717,6 +6717,67 @@ static njs_unit_test_t njs_test[] = "Object.defineProperty(o, 'a', Object.create({value:2})); o.a"), nxt_string("2") }, + { nxt_string("var o = {};" + "Object.defineProperty(o, 'a', {configurable:false});" + "Object.defineProperty(o, 'a', {configurable:true})"), + nxt_string("TypeError: Cannot redefine property: 'a'") }, + + { nxt_string("var o = {};" + "Object.defineProperty(o, 'a', {configurable:false});" + "Object.defineProperty(o, 'a', {enumerable:true})"), + nxt_string("TypeError: Cannot redefine property: 'a'") }, + + { nxt_string("var o = {};" + "Object.defineProperty(o, 'a', {configurable:false});" + "Object.defineProperty(o, 'a', {writable:true})"), + nxt_string("TypeError: Cannot redefine property: 'a'") }, + + { nxt_string("var o = {};" + "Object.defineProperty(o, 'a', {configurable:false});" + "Object.defineProperty(o, 'a', {enumerable:false}).a"), + nxt_string("undefined") }, + + { nxt_string("var o = {};" + "Object.defineProperty(o, 'a', {configurable:false});" + "Object.defineProperty(o, 'a', {}).a"), + nxt_string("undefined") }, + + { nxt_string("var o = {};" + "Object.defineProperty(o, 'a', {configurable:false, writable:true});" + "Object.defineProperty(o, 'a', {writable:false}).a"), + nxt_string("undefined") }, + + { nxt_string("var o = {};" + "Object.defineProperty(o, 'a', {configurable:true, writable:false});" + "Object.defineProperty(o, 'a', {writable:true}).a"), + nxt_string("undefined") }, + + { nxt_string("var o = {};" + "Object.defineProperty(o, 'a', {});" + "Object.defineProperty(o, 'a', {}).a"), + nxt_string("undefined") }, + + { nxt_string("var o = {};" + "Object.defineProperty(o, 'a', {value:1});" + "Object.defineProperty(o, 'a', {value:1}).a"), + nxt_string("1") }, + + { nxt_string("var o = {};" + "Object.defineProperty(o, 'a', {value:1});" + "Object.defineProperty(o, 'a', {value:2}).a"), + nxt_string("TypeError: Cannot redefine property: 'a'") }, + + { nxt_string("var o = {};" + "Object.defineProperty(o, 'a', {configurable:true});" + "Object.defineProperty(o, 'a', {value:1}).a"), + nxt_string("1") }, + + { nxt_string("var o = {};" + "Object.defineProperty(o, 'a', { configurable: true, value: 0 });" + "Object.defineProperty(o, 'a', { value: 1 });" + "Object.defineProperty(o, 'a', { configurable: false, value: 2 }).a"), + nxt_string("2") }, + { nxt_string("var o = {}; Object.defineProperty()"), nxt_string("TypeError: cannot convert void argument to object") }, From xeioex at nginx.com Mon Aug 27 13:55:47 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Mon, 27 Aug 2018 13:55:47 +0000 Subject: [njs] Respecting the enumerable attribute while iterating by for in. Message-ID: details: http://hg.nginx.org/njs/rev/76cee25a8228 branches: changeset: 587:76cee25a8228 user: Dmitry Volyntsev date: Mon Aug 27 16:37:35 2018 +0300 description: Respecting the enumerable attribute while iterating by for in. diffstat: njs/njs_vm.c | 18 ++++++++++++------ njs/test/njs_unit_test.c | 12 ++++++++++++ 2 files changed, 24 insertions(+), 6 deletions(-) diffs (50 lines): diff -r c572768e287b -r 76cee25a8228 njs/njs_vm.c --- a/njs/njs_vm.c Mon Aug 27 16:23:08 2018 +0300 +++ b/njs/njs_vm.c Mon Aug 27 16:37:35 2018 +0300 @@ -1053,12 +1053,18 @@ njs_vmcode_property_next(njs_vm_t *vm, n next->index = -1; } - prop = nxt_lvlhsh_each(&object->data.u.object->hash, &next->lhe); - - if (prop != NULL) { - *retval = prop->name; - - return code->offset; + for ( ;; ) { + prop = nxt_lvlhsh_each(&object->data.u.object->hash, &next->lhe); + + if (prop == NULL) { + break; + } + + if (prop->enumerable) { + *retval = prop->name; + + return code->offset; + } } nxt_mem_cache_free(vm->mem_cache_pool, next); diff -r c572768e287b -r 76cee25a8228 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Mon Aug 27 16:23:08 2018 +0300 +++ b/njs/test/njs_unit_test.c Mon Aug 27 16:37:35 2018 +0300 @@ -2070,6 +2070,18 @@ static njs_unit_test_t njs_test[] = { nxt_string("for (null in undefined);"), nxt_string("ReferenceError: Invalid left-hand side \"null\" in for-in statement in 1") }, + { nxt_string("var s = ''; for (var p in [1,2]) {s += p}; s"), + nxt_string("01") }, + + { nxt_string("var s = ''; for (var p in {a:1, b:2}) {s += p}; s"), + nxt_string("ab") }, + + { nxt_string("var s = '';" + "var o = Object.defineProperty({}, 'x', {value:1});" + "Object.defineProperty(o, 'y', {value:2, enumerable:true});" + "for (var p in o) {s += p}; s"), + nxt_string("y") }, + /* switch. */ { nxt_string("switch"), From xeioex at nginx.com Mon Aug 27 13:55:47 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Mon, 27 Aug 2018 13:55:47 +0000 Subject: [njs] Respecting writable attribute for property handlers. Message-ID: details: http://hg.nginx.org/njs/rev/ff2007772ec6 branches: changeset: 588:ff2007772ec6 user: Dmitry Volyntsev date: Mon Aug 27 16:37:42 2018 +0300 description: Respecting writable attribute for property handlers. diffstat: njs/njs_vm.c | 2 +- njs/test/njs_unit_test.c | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diffs (27 lines): diff -r 76cee25a8228 -r ff2007772ec6 njs/njs_vm.c --- a/njs/njs_vm.c Mon Aug 27 16:37:35 2018 +0300 +++ b/njs/njs_vm.c Mon Aug 27 16:37:42 2018 +0300 @@ -656,7 +656,7 @@ njs_vmcode_property_set(njs_vm_t *vm, nj case NXT_OK: prop = pq.lhq.value; - if (prop->type == NJS_PROPERTY_HANDLER) { + if (prop->type == NJS_PROPERTY_HANDLER && prop->writable) { ret = prop->value.data.u.prop_handler(vm, object, value, &vm->retval); if (nxt_slow_path(ret != NXT_OK)) { diff -r 76cee25a8228 -r ff2007772ec6 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Mon Aug 27 16:37:35 2018 +0300 +++ b/njs/test/njs_unit_test.c Mon Aug 27 16:37:42 2018 +0300 @@ -6065,10 +6065,7 @@ static njs_unit_test_t njs_test[] = nxt_string("true") }, { nxt_string("({}).__proto__ = 1"), - nxt_string("1") }, - - { nxt_string("var o = {}; o.__proto__ = 1; o.__proto__"), - nxt_string("[object Object]") }, + nxt_string("TypeError: Cannot assign to read-only property '__proto__' of object") }, { nxt_string("({}).__proto__.constructor === Object"), nxt_string("true") }, From ru at nginx.com Mon Aug 27 16:00:21 2018 From: ru at nginx.com (Ruslan Ermilov) Date: Mon, 27 Aug 2018 19:00:21 +0300 Subject: limit_rate_after support variables In-Reply-To: References: <20180827112847.GE71000@lo0.su> Message-ID: <20180827160021.GG71000@lo0.su> Also, Maxim Dounin reminded me that I prepared the patch set to add variables support to limit_rate_after roughly a year ago, which I have successfully forgotten now. Here it is, for your consideration, in the state it was a year ago. # HG changeset patch # Parent e3723f2a11b7ec1c196d59c331739bc21d9d9afd Added post processing to ngx_http_set_complex_value_slot(). diff --git a/src/http/ngx_http_script.c b/src/http/ngx_http_script.c --- a/src/http/ngx_http_script.c +++ b/src/http/ngx_http_script.c @@ -214,6 +214,7 @@ ngx_http_set_complex_value_slot(ngx_conf char *p = conf; ngx_str_t *value; + ngx_conf_post_t *post; ngx_http_complex_value_t **cv; ngx_http_compile_complex_value_t ccv; @@ -240,6 +241,11 @@ ngx_http_set_complex_value_slot(ngx_conf return NGX_CONF_ERROR; } + if (cmd->post) { + post = cmd->post; + return post->post_handler(cf, post, *cv); + } + return NGX_CONF_OK; } # HG changeset patch # Parent 2b522e0bcd9fd218026f923f58a1b8bfed864b2a Added size_t type support to ngx_http_set_complex_value_slot(). If a complex value is expected to be size_t, and the compiled value is constant, the ngx_http_complex_value_size_p post handler will remember the constant size_t value. The value is accessed through ngx_http_complex_value_size() which either returns the remembered constant or evaluates the expression and parses it as size_t. diff --git a/src/http/ngx_http_script.c b/src/http/ngx_http_script.c --- a/src/http/ngx_http_script.c +++ b/src/http/ngx_http_script.c @@ -10,6 +10,13 @@ #include +static char *ngx_http_complex_value_set_size(ngx_conf_t *cf, void *post, + void *data); + +ngx_conf_post_handler_pt ngx_http_complex_value_size_p = + ngx_http_complex_value_set_size; + + static ngx_int_t ngx_http_script_init_arrays(ngx_http_script_compile_t *sc); static ngx_int_t ngx_http_script_done(ngx_http_script_compile_t *sc); static ngx_int_t ngx_http_script_add_copy_code(ngx_http_script_compile_t *sc, @@ -105,6 +112,25 @@ ngx_http_complex_value(ngx_http_request_ ngx_int_t +ngx_http_complex_value_size(ngx_http_request_t *r, + ngx_http_complex_value_t *val, ngx_str_t *value, size_t *size) +{ + if (val->lengths == NULL) { + *size = val->u.size; + return NGX_OK; + } + + if (ngx_http_complex_value(r, val, value) != NGX_OK) { + return NGX_ERROR; + } + + *size = ngx_parse_size(value); + + return NGX_OK; +} + + +ngx_int_t ngx_http_compile_complex_value(ngx_http_compile_complex_value_t *ccv) { ngx_str_t *v; @@ -250,6 +276,24 @@ ngx_http_set_complex_value_slot(ngx_conf } +static char * +ngx_http_complex_value_set_size(ngx_conf_t *cf, void *post, void *data) +{ + ngx_http_complex_value_t *cv = data; + + if (cv->lengths) { + return NGX_CONF_OK; + } + + cv->u.size = ngx_parse_size(&cv->value); + if (cv->u.size == (size_t) NGX_ERROR) { + return "invalid value"; + } + + return NGX_CONF_OK; +} + + ngx_int_t ngx_http_test_predicates(ngx_http_request_t *r, ngx_array_t *predicates) { diff --git a/src/http/ngx_http_script.h b/src/http/ngx_http_script.h --- a/src/http/ngx_http_script.h +++ b/src/http/ngx_http_script.h @@ -68,6 +68,10 @@ typedef struct { ngx_uint_t *flushes; void *lengths; void *values; + + union { + size_t size; + } u; } ngx_http_complex_value_t; @@ -207,6 +211,8 @@ void ngx_http_script_flush_complex_value ngx_http_complex_value_t *val); ngx_int_t ngx_http_complex_value(ngx_http_request_t *r, ngx_http_complex_value_t *val, ngx_str_t *value); +ngx_int_t ngx_http_complex_value_size(ngx_http_request_t *r, + ngx_http_complex_value_t *val, ngx_str_t *value, size_t *size); ngx_int_t ngx_http_compile_complex_value(ngx_http_compile_complex_value_t *ccv); char *ngx_http_set_complex_value_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); @@ -254,4 +260,7 @@ void ngx_http_script_var_code(ngx_http_s void ngx_http_script_nop_code(ngx_http_script_engine_t *e); +extern ngx_conf_post_handler_pt ngx_http_complex_value_size_p; + + #endif /* _NGX_HTTP_SCRIPT_H_INCLUDED_ */ # HG changeset patch # Parent fbf2ea9783be4eeaa938bc4173dbac1149b762dc Variables support in limit_rate and limit_rate_after (ticket #293). diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -474,18 +474,18 @@ static ngx_command_t ngx_http_core_comm { ngx_string("limit_rate"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF |NGX_CONF_TAKE1, - ngx_conf_set_size_slot, + ngx_http_set_complex_value_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_core_loc_conf_t, limit_rate), - NULL }, + &ngx_http_complex_value_size_p }, { ngx_string("limit_rate_after"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF |NGX_CONF_TAKE1, - ngx_conf_set_size_slot, + ngx_http_set_complex_value_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_core_loc_conf_t, limit_rate_after), - NULL }, + &ngx_http_complex_value_size_p }, { ngx_string("keepalive_timeout"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12, @@ -1431,6 +1431,8 @@ ngx_http_core_content_phase(ngx_http_req void ngx_http_update_location_config(ngx_http_request_t *r) { + size_t limit_rate; + ngx_str_t val; ngx_http_core_loc_conf_t *clcf; clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); @@ -1500,8 +1502,18 @@ ngx_http_update_location_config(ngx_http r->connection->tcp_nopush = NGX_TCP_NOPUSH_DISABLED; } - if (r->limit_rate == 0) { - r->limit_rate = clcf->limit_rate; + if (r->limit_rate == 0 + && clcf->limit_rate + && ngx_http_complex_value_size(r, clcf->limit_rate, &val, &limit_rate) + == NGX_OK) + { + if (limit_rate != (size_t) NGX_ERROR) { + r->limit_rate = limit_rate; + + } else if (val.len) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "invalid \"limit_rate\" value \"%V\"", &val); + } } if (clcf->handler) { @@ -3567,6 +3579,8 @@ ngx_http_core_create_loc_conf(ngx_conf_t * clcf->exact_match = 0; * clcf->auto_redirect = 0; * clcf->alias = 0; + * clcf->limit_rate = NULL; + * clcf->limit_rate_after = NULL; * clcf->gzip_proxied = 0; * clcf->keepalive_disable = 0; */ @@ -3596,8 +3610,6 @@ ngx_http_core_create_loc_conf(ngx_conf_t clcf->send_timeout = NGX_CONF_UNSET_MSEC; clcf->send_lowat = NGX_CONF_UNSET_SIZE; clcf->postpone_output = NGX_CONF_UNSET_SIZE; - clcf->limit_rate = NGX_CONF_UNSET_SIZE; - clcf->limit_rate_after = NGX_CONF_UNSET_SIZE; clcf->keepalive_timeout = NGX_CONF_UNSET_MSEC; clcf->keepalive_header = NGX_CONF_UNSET; clcf->keepalive_requests = NGX_CONF_UNSET_UINT; @@ -3785,6 +3797,14 @@ ngx_http_core_merge_loc_conf(ngx_conf_t ngx_conf_merge_msec_value(conf->client_body_timeout, prev->client_body_timeout, 60000); + if (conf->limit_rate == NULL) { + conf->limit_rate = prev->limit_rate; + } + + if (conf->limit_rate_after == NULL) { + conf->limit_rate_after = prev->limit_rate_after; + } + ngx_conf_merge_bitmask_value(conf->keepalive_disable, prev->keepalive_disable, (NGX_CONF_BITMASK_SET @@ -3823,9 +3843,6 @@ ngx_http_core_merge_loc_conf(ngx_conf_t ngx_conf_merge_size_value(conf->send_lowat, prev->send_lowat, 0); ngx_conf_merge_size_value(conf->postpone_output, prev->postpone_output, 1460); - ngx_conf_merge_size_value(conf->limit_rate, prev->limit_rate, 0); - ngx_conf_merge_size_value(conf->limit_rate_after, prev->limit_rate_after, - 0); ngx_conf_merge_msec_value(conf->keepalive_timeout, prev->keepalive_timeout, 75000); ngx_conf_merge_sec_value(conf->keepalive_header, diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h --- a/src/http/ngx_http_core_module.h +++ b/src/http/ngx_http_core_module.h @@ -358,11 +358,12 @@ struct ngx_http_core_loc_conf_s { size_t client_body_buffer_size; /* client_body_buffer_size */ size_t send_lowat; /* send_lowat */ size_t postpone_output; /* postpone_output */ - size_t limit_rate; /* limit_rate */ - size_t limit_rate_after; /* limit_rate_after */ size_t sendfile_max_chunk; /* sendfile_max_chunk */ size_t read_ahead; /* read_ahead */ + ngx_http_complex_value_t *limit_rate; /* limit_rate */ + ngx_http_complex_value_t *limit_rate_after; + ngx_msec_t client_body_timeout; /* client_body_timeout */ ngx_msec_t send_timeout; /* send_timeout */ ngx_msec_t keepalive_timeout; /* keepalive_timeout */ diff --git a/src/http/ngx_http_write_filter_module.c b/src/http/ngx_http_write_filter_module.c --- a/src/http/ngx_http_write_filter_module.c +++ b/src/http/ngx_http_write_filter_module.c @@ -48,6 +48,8 @@ ngx_int_t ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in) { off_t size, sent, nsent, limit; + size_t limit_rate_after; + ngx_str_t val; ngx_uint_t last, flush, sync; ngx_msec_t delay; ngx_chain_t *cl, *ln, **ll, *chain; @@ -219,8 +221,20 @@ ngx_http_write_filter(ngx_http_request_t } if (r->limit_rate) { - if (r->limit_rate_after == 0) { - r->limit_rate_after = clcf->limit_rate_after; + if (r->limit_rate_after == 0 + && clcf->limit_rate_after + && ngx_http_complex_value_size(r, clcf->limit_rate_after, &val, + &limit_rate_after) + == NGX_OK) + { + if (limit_rate_after != (size_t) NGX_ERROR) { + r->limit_rate_after = limit_rate_after; + + } else if (val.len) { + ngx_log_error(NGX_LOG_ERR, c->log, 0, + "invalid \"limit_rate_after\" value \"%V\"", + &val); + } } limit = (off_t) r->limit_rate * (ngx_time() - r->start_sec + 1) From xeioex at nginx.com Mon Aug 27 16:19:57 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Mon, 27 Aug 2018 16:19:57 +0000 Subject: [njs] Added Function.prototype.length. Message-ID: details: http://hg.nginx.org/njs/rev/50dfb4ccbceb branches: changeset: 589:50dfb4ccbceb user: Dmitry Volyntsev date: Mon Aug 27 19:19:25 2018 +0300 description: Added Function.prototype.length. diffstat: njs/njs_function.c | 36 ++++++++++++++++++++++++++++++++++++ njs/test/njs_expect_test.exp | 5 +++++ njs/test/njs_unit_test.c | 21 +++++++++++++++++++++ 3 files changed, 62 insertions(+), 0 deletions(-) diffs (99 lines): diff -r ff2007772ec6 -r 50dfb4ccbceb njs/njs_function.c --- a/njs/njs_function.c Mon Aug 27 16:37:42 2018 +0300 +++ b/njs/njs_function.c Mon Aug 27 19:19:25 2018 +0300 @@ -503,6 +503,36 @@ const njs_object_init_t njs_function_co }; +/* + * ES5.1, 15.3.5.1 length + * the typical number of arguments expected by the function. + */ +static njs_ret_t +njs_function_prototype_length(njs_vm_t *vm, njs_value_t *value, + njs_value_t *setval, njs_value_t *retval) +{ + nxt_uint_t n; + njs_function_t *function; + + function = value->data.u.function; + + if (function->native) { + for (n = function->args_offset; n <= NJS_ARGS_TYPES_MAX; n++) { + if (function->args_types[n] == 0) { + break; + } + } + + } else { + n = function->u.lambda->nargs + 1; + } + + njs_value_number_set(retval, n - function->args_offset); + + return NXT_OK; +} + + static njs_ret_t njs_function_prototype_call(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t retval) @@ -671,6 +701,12 @@ njs_function_prototype_bind(njs_vm_t *vm static const njs_object_prop_t njs_function_prototype_properties[] = { { + .type = NJS_PROPERTY_HANDLER, + .name = njs_string("length"), + .value = njs_prop_handler(njs_function_prototype_length), + }, + + { .type = NJS_METHOD, .name = njs_string("call"), .value = njs_native_function(njs_function_prototype_call, 0, 0), diff -r ff2007772ec6 -r 50dfb4ccbceb njs/test/njs_expect_test.exp --- a/njs/test/njs_expect_test.exp Mon Aug 27 16:37:42 2018 +0300 +++ b/njs/test/njs_expect_test.exp Mon Aug 27 19:19:25 2018 +0300 @@ -183,6 +183,11 @@ njs_test { } njs_test { + {"console.log.length\r\n" + "console.log.length\r\n0"} +} + +njs_test { {"var print = console.log.bind(console); print(1, 'a', [1, 2])\r\n" "1 'a' \\\[1,2]\r\nundefined\r\n>> "} {"var print = console.dump.bind(console); print(1, 'a', [1, 2])\r\n" diff -r ff2007772ec6 -r 50dfb4ccbceb njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Mon Aug 27 16:37:42 2018 +0300 +++ b/njs/test/njs_unit_test.c Mon Aug 27 19:19:25 2018 +0300 @@ -4833,6 +4833,27 @@ static njs_unit_test_t njs_test[] = { nxt_string("function f() { }"), nxt_string("undefined") }, + { nxt_string("function f() { }; f.length"), + nxt_string("0") }, + + { nxt_string("function f() { }; f.length = 1"), + nxt_string("TypeError: Cannot assign to read-only property 'length' of function") }, + + { nxt_string("function f(a,b) { }; f.length"), + nxt_string("2") }, + + { nxt_string("function f(a,b) { }; var ff = f.bind(f, 1); ff.length"), + nxt_string("1") }, + + { nxt_string("JSON.parse.length"), + nxt_string("2") }, + + { nxt_string("JSON.parse.bind(JSON, '[]').length"), + nxt_string("1") }, + + { nxt_string("var o = {}; o.hasOwnProperty.length"), + nxt_string("1") }, + { nxt_string("var x; function f() { }"), nxt_string("undefined") }, From kahing at cloudflare.com Mon Aug 27 21:38:36 2018 From: kahing at cloudflare.com (Ka-Hing Cheung) Date: Mon, 27 Aug 2018 14:38:36 -0700 Subject: cache: move open to thread pool In-Reply-To: <20180810113946.GG56558@mdounin.ru> References: <20180808181653.GX56558@mdounin.ru> <20180810113946.GG56558@mdounin.ru> Message-ID: Thanks for all the feedback! This is an updated version of the patch. There may still be some coding style issues (which will be addressed), but should address most of the comments other than these two: > - The code bypasses open file cache, and uses a direct call > in the http cache code instead. While it might be ok in your > setup, it looks like an incomplete solution from the generic point > of view. A better solution would be to introduce a generic > interface in ngx_open_cached_file() to allow use of thread > pools. The complications with this just didn't seem worth it. aio_open makes the most impact if a large number of distinct files need to be opened and that's when open_file_cache is last effectiv. Instead I made aio_open to only take effect if open_file_cache is off. > - The code calls ngx_open_and_stat_file() whithin a thread, which > is relatively complex function never designed to be thread safe. > While it looks like currently it is, a better solution would be to > introduce a separate simple function to execute within a thread, > similar to ngx_thread_read_handler(). I kept using ngx_open_and_stat_file() as we are looking into moving other types of open into thread pool, so we will probably need to have similar logic anyway. commit 3c67f1d972404bda7713839186a91cb18dbc96be Author: Ka-Hing Cheung Date: Fri Aug 3 13:37:58 2018 -0700 move open to thread pool At cloudflare we found that open() can block a long time, especially at p99 and p999. Moving it to thread pool improved overall p99 by 6x or so during peak time. This introduces an aio_open option. When set to 'on' the open will be done in a thread pool. open_file_cache has to be disabled for aio_open to take effect. thread pool does increase CPU usage somewhat but we have not measured difference in CPU usage for stock "aio threads" compared to after this patch. Only the cache hit open() is moved to thread pool. diff --git src/core/ngx_open_file_cache.c src/core/ngx_open_file_cache.c index b23ee78d..9177ebfd 100644 --- src/core/ngx_open_file_cache.c +++ src/core/ngx_open_file_cache.c @@ -35,8 +35,6 @@ static ngx_fd_t ngx_open_file_wrapper(ngx_str_t *name, ngx_int_t access, ngx_log_t *log); static ngx_int_t ngx_file_info_wrapper(ngx_str_t *name, ngx_open_file_info_t *of, ngx_file_info_t *fi, ngx_log_t *log); -static ngx_int_t ngx_open_and_stat_file(ngx_str_t *name, - ngx_open_file_info_t *of, ngx_log_t *log); static void ngx_open_file_add_event(ngx_open_file_cache_t *cache, ngx_cached_open_file_t *file, ngx_open_file_info_t *of, ngx_log_t *log); static void ngx_open_file_cleanup(void *data); @@ -836,7 +834,7 @@ ngx_file_info_wrapper(ngx_str_t *name, ngx_open_file_info_t *of, } -static ngx_int_t +ngx_int_t ngx_open_and_stat_file(ngx_str_t *name, ngx_open_file_info_t *of, ngx_log_t *log) { diff --git src/core/ngx_open_file_cache.h src/core/ngx_open_file_cache.h index d119c129..144744c0 100644 --- src/core/ngx_open_file_cache.h +++ src/core/ngx_open_file_cache.h @@ -7,6 +7,7 @@ #include #include +#include #ifndef _NGX_OPEN_FILE_CACHE_H_INCLUDED_ @@ -124,6 +125,8 @@ ngx_open_file_cache_t *ngx_open_file_cache_init(ngx_pool_t *pool, ngx_uint_t max, time_t inactive); ngx_int_t ngx_open_cached_file(ngx_open_file_cache_t *cache, ngx_str_t *name, ngx_open_file_info_t *of, ngx_pool_t *pool); +ngx_int_t ngx_open_and_stat_file(ngx_str_t *name, + ngx_open_file_info_t *of, ngx_log_t *log); #endif /* _NGX_OPEN_FILE_CACHE_H_INCLUDED_ */ diff --git src/http/ngx_http_cache.h src/http/ngx_http_cache.h index f9e96640..8940405a 100644 --- src/http/ngx_http_cache.h +++ src/http/ngx_http_cache.h @@ -97,6 +97,7 @@ struct ngx_http_cache_s { #if (NGX_THREADS || NGX_COMPAT) ngx_thread_task_t *thread_task; + ngx_int_t open_rv; #endif ngx_msec_t lock_timeout; @@ -114,6 +115,9 @@ struct ngx_http_cache_s { unsigned exists:1; unsigned temp_file:1; unsigned purged:1; +#if (NGX_THREADS || NGX_COMPAT) + unsigned opening:1; +#endif unsigned reading:1; unsigned secondary:1; unsigned background:1; diff --git src/http/ngx_http_core_module.c src/http/ngx_http_core_module.c index c57ec00c..1c7b26c2 100644 --- src/http/ngx_http_core_module.c +++ src/http/ngx_http_core_module.c @@ -420,6 +420,13 @@ static ngx_command_t ngx_http_core_commands[] = { offsetof(ngx_http_core_loc_conf_t, aio_write), NULL }, + { ngx_string("aio_open"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_core_loc_conf_t, aio_open), + NULL }, + { ngx_string("read_ahead"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_size_slot, @@ -3380,6 +3387,7 @@ ngx_http_core_create_loc_conf(ngx_conf_t *cf) clcf->subrequest_output_buffer_size = NGX_CONF_UNSET_SIZE; clcf->aio = NGX_CONF_UNSET; clcf->aio_write = NGX_CONF_UNSET; + clcf->aio_open = NGX_CONF_UNSET; #if (NGX_THREADS) clcf->thread_pool = NGX_CONF_UNSET_PTR; clcf->thread_pool_value = NGX_CONF_UNSET_PTR; @@ -3605,6 +3613,7 @@ ngx_http_core_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) (size_t) ngx_pagesize); ngx_conf_merge_value(conf->aio, prev->aio, NGX_HTTP_AIO_OFF); ngx_conf_merge_value(conf->aio_write, prev->aio_write, 0); + ngx_conf_merge_value(conf->aio_open, prev->aio_open, 0); #if (NGX_THREADS) ngx_conf_merge_ptr_value(conf->thread_pool, prev->thread_pool, NULL); ngx_conf_merge_ptr_value(conf->thread_pool_value, prev->thread_pool_value, diff --git src/http/ngx_http_core_module.h src/http/ngx_http_core_module.h index 4c6da7c0..8498eb63 100644 --- src/http/ngx_http_core_module.h +++ src/http/ngx_http_core_module.h @@ -382,6 +382,7 @@ struct ngx_http_core_loc_conf_s { ngx_flag_t sendfile; /* sendfile */ ngx_flag_t aio; /* aio */ ngx_flag_t aio_write; /* aio_write */ + ngx_flag_t aio_open; /* aio_open */ ngx_flag_t tcp_nopush; /* tcp_nopush */ ngx_flag_t tcp_nodelay; /* tcp_nodelay */ ngx_flag_t reset_timedout_connection; /* reset_timedout_connection */ diff --git src/http/ngx_http_file_cache.c src/http/ngx_http_file_cache.c index 56866fa4..10a29d93 100644 --- src/http/ngx_http_file_cache.c +++ src/http/ngx_http_file_cache.c @@ -18,6 +18,8 @@ static void ngx_http_file_cache_lock_wait(ngx_http_request_t *r, ngx_http_cache_t *c); static ngx_int_t ngx_http_file_cache_read(ngx_http_request_t *r, ngx_http_cache_t *c); +static ngx_int_t ngx_http_file_cache_aio_open(ngx_http_request_t *r, + ngx_http_cache_t *c, ngx_int_t rv); static ssize_t ngx_http_file_cache_aio_read(ngx_http_request_t *r, ngx_http_cache_t *c); #if (NGX_HAVE_FILE_AIO) @@ -268,9 +270,7 @@ ngx_http_file_cache_open(ngx_http_request_t *r) ngx_uint_t test; ngx_http_cache_t *c; ngx_pool_cleanup_t *cln; - ngx_open_file_info_t of; ngx_http_file_cache_t *cache; - ngx_http_core_loc_conf_t *clcf; c = r->cache; @@ -278,6 +278,12 @@ ngx_http_file_cache_open(ngx_http_request_t *r) return NGX_AGAIN; } +#if (NGX_THREADS) + if (c->opening) { + return ngx_http_file_cache_aio_open(r, c, c->open_rv); + } +#endif + if (c->reading) { return ngx_http_file_cache_read(r, c); } @@ -339,58 +345,10 @@ ngx_http_file_cache_open(ngx_http_request_t *r) return NGX_ERROR; } - if (!test) { - goto done; - } - - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - - ngx_memzero(&of, sizeof(ngx_open_file_info_t)); - - of.uniq = c->uniq; - of.valid = clcf->open_file_cache_valid; - of.min_uses = clcf->open_file_cache_min_uses; - of.events = clcf->open_file_cache_events; - of.directio = NGX_OPEN_FILE_DIRECTIO_OFF; - of.read_ahead = clcf->read_ahead; - - if (ngx_open_cached_file(clcf->open_file_cache, &c->file.name, &of, r->pool) - != NGX_OK) - { - switch (of.err) { - - case 0: - return NGX_ERROR; - - case NGX_ENOENT: - case NGX_ENOTDIR: - goto done; - - default: - ngx_log_error(NGX_LOG_CRIT, r->connection->log, of.err, - ngx_open_file_n " \"%s\" failed", c->file.name.data); - return NGX_ERROR; - } + if (test) { + return ngx_http_file_cache_aio_open(r, c, rv); } - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http file cache fd: %d", of.fd); - - c->file.fd = of.fd; - c->file.log = r->connection->log; - c->uniq = of.uniq; - c->length = of.size; - c->fs_size = (of.fs_size + cache->bsize - 1) / cache->bsize; - - c->buf = ngx_create_temp_buf(r->pool, c->body_start); - if (c->buf == NULL) { - return NGX_ERROR; - } - - return ngx_http_file_cache_read(r, c); - -done: - if (rv == NGX_DECLINED) { return ngx_http_file_cache_lock(r, c); } @@ -398,7 +356,6 @@ done: return rv; } - static ngx_int_t ngx_http_file_cache_lock(ngx_http_request_t *r, ngx_http_cache_t *c) { @@ -663,6 +620,106 @@ ngx_http_file_cache_read(ngx_http_request_t *r, ngx_http_cache_t *c) } +static ngx_int_t +ngx_http_file_cache_aio_open(ngx_http_request_t *r, ngx_http_cache_t *c, + ngx_int_t rv) +{ + ngx_int_t rc; + ngx_open_file_info_t of = { 0 }; + ngx_http_file_cache_t *cache; + ngx_http_core_loc_conf_t *clcf; + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + of.uniq = c->uniq; + of.valid = clcf->open_file_cache_valid; + of.min_uses = clcf->open_file_cache_min_uses; + of.events = clcf->open_file_cache_events; + of.directio = NGX_OPEN_FILE_DIRECTIO_OFF; + of.read_ahead = clcf->read_ahead; + +#if (NGX_THREADS) + if (clcf->aio == NGX_HTTP_AIO_THREADS && clcf->aio_open && + clcf->open_file_cache == NULL) { + + c->file.thread_task = c->thread_task; + c->file.thread_handler = ngx_http_cache_thread_handler; + c->file.thread_ctx = r; + c->open_rv = rv; + + rc = ngx_thread_open(&c->file, &of, r->pool); + + c->opening = (rc == NGX_AGAIN); + c->thread_task = c->file.thread_task; + + if (rc == NGX_AGAIN) { + return rc; + } else if (of.fd != NGX_INVALID_FILE) { + ngx_pool_cleanup_t *cln; + ngx_pool_cleanup_file_t *clnf; + + cln = ngx_pool_cleanup_add(r->pool, sizeof(ngx_pool_cleanup_file_t)); + if (cln == NULL) { + ngx_close_file(of.fd); + goto done; + } + + cln->handler = ngx_pool_cleanup_file; + clnf = cln->data; + + clnf->fd = of.fd; + clnf->name = r->cache->file.name.data; + clnf->log = r->connection->log; + goto post_open; + } + } +#endif + + rc = ngx_open_cached_file(clcf->open_file_cache, &c->file.name, &of, r->pool); + +#if (NGX_THREADS) +post_open: +#endif + + if (rc != NGX_OK) { + switch (of.err) { + case NGX_OK: + return NGX_ERROR; + case NGX_ENOENT: + case NGX_ENOTDIR: + goto done; + + default: + ngx_log_error(NGX_LOG_CRIT, r->connection->log, of.err, + ngx_open_file_n " \"%s\" failed", c->file.name.data); + return NGX_ERROR; + } + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http file cache fd: %d", of.fd); + + cache = c->file_cache; + c->file.fd = of.fd; + c->file.log = r->connection->log; + c->uniq = of.uniq; + c->length = of.size; + c->fs_size = (of.fs_size + cache->bsize - 1) / cache->bsize; + + c->buf = ngx_create_temp_buf(r->pool, c->body_start); + if (c->buf == NULL) { + return NGX_ERROR; + } + + return ngx_http_file_cache_read(r, c); + +done: + if (rv == NGX_DECLINED) { + return ngx_http_file_cache_lock(r, c); + } + return rv; +} + static ssize_t ngx_http_file_cache_aio_read(ngx_http_request_t *r, ngx_http_cache_t *c) { @@ -751,30 +808,14 @@ ngx_http_cache_aio_event_handler(ngx_event_t *ev) static ngx_int_t ngx_http_cache_thread_handler(ngx_thread_task_t *task, ngx_file_t *file) { - ngx_str_t name; ngx_thread_pool_t *tp; ngx_http_request_t *r; - ngx_http_core_loc_conf_t *clcf; r = file->thread_ctx; - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - tp = clcf->thread_pool; - + tp = ngx_http_request_get_thread_pool(r); if (tp == NULL) { - if (ngx_http_complex_value(r, clcf->thread_pool_value, &name) - != NGX_OK) - { - return NGX_ERROR; - } - - tp = ngx_thread_pool_get((ngx_cycle_t *) ngx_cycle, &name); - - if (tp == NULL) { - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "thread pool \"%V\" not found", &name); - return NGX_ERROR; - } + return NGX_ERROR; } task->event.data = r; diff --git src/http/ngx_http_request.c src/http/ngx_http_request.c index 97900915..228cda3d 100644 --- src/http/ngx_http_request.c +++ src/http/ngx_http_request.c @@ -3700,3 +3700,39 @@ ngx_http_log_error_handler(ngx_http_request_t *r, ngx_http_request_t *sr, return buf; } + + +#if (NGX_THREADS) + +ngx_thread_pool_t * +ngx_http_request_get_thread_pool(ngx_http_request_t *r) +{ + ngx_str_t name; + ngx_thread_pool_t *tp; + ngx_http_core_loc_conf_t *clcf; + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + tp = clcf->thread_pool; + + if (tp == NULL) { + if (ngx_http_complex_value(r, clcf->thread_pool_value, &name) + != NGX_OK) + { + return NULL; + } + + tp = ngx_thread_pool_get((ngx_cycle_t *) ngx_cycle, &name); + + if (tp == NULL) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "thread pool \"%V\" not found", &name); + return NULL; + } + + clcf->thread_pool = tp; + } + + return tp; +} + +#endif diff --git src/http/ngx_http_request.h src/http/ngx_http_request.h index 6bfff96e..12df9c76 100644 --- src/http/ngx_http_request.h +++ src/http/ngx_http_request.h @@ -605,4 +605,10 @@ extern ngx_http_header_out_t ngx_http_headers_out[]; ((ngx_http_log_ctx_t *) log->data)->current_request = r +#if (NGX_THREADS) +typedef struct ngx_thread_pool_s ngx_thread_pool_t; + +ngx_thread_pool_t *ngx_http_request_get_thread_pool(ngx_http_request_t *r); +#endif + #endif /* _NGX_HTTP_REQUEST_H_INCLUDED_ */ diff --git src/os/unix/ngx_files.c src/os/unix/ngx_files.c index 482d3276..3260c2aa 100644 --- src/os/unix/ngx_files.c +++ src/os/unix/ngx_files.c @@ -88,15 +88,94 @@ typedef struct { size_t nbytes; ngx_err_t err; +} ngx_thread_file_read_ctx_t; + +typedef struct { + ngx_str_t name; + ngx_pool_t *pool; + ngx_open_file_info_t of; + ngx_int_t rv; +} ngx_thread_file_open_ctx_t; + +typedef struct { + union { + ngx_thread_file_open_ctx_t open; + ngx_thread_file_read_ctx_t read; + }; } ngx_thread_file_ctx_t; +static void +ngx_thread_open_handler(void *data, ngx_log_t *log) +{ + ngx_int_t rc; + ngx_open_file_info_t *of; + ngx_thread_file_open_ctx_t *ctx; + + ngx_log_debug0(NGX_LOG_DEBUG_CORE, log, 0, "thread open handler"); + + ctx = data; + of = &ctx->of; + + of->fd = NGX_INVALID_FILE; + + rc = ngx_open_and_stat_file(&ctx->name, of, log); + if (rc != NGX_OK && of->err == NGX_OK) { + of->err = rc; + } +} + + +ngx_int_t +ngx_thread_open(ngx_file_t *file, ngx_open_file_info_t *of, + ngx_pool_t *pool) +{ + ngx_thread_task_t *task; + ngx_thread_file_open_ctx_t *ctx; + + ngx_log_debug1(NGX_LOG_DEBUG_CORE, file->log, 0, + "thread open: %s", file->name.data); + + task = file->thread_task; + + if (task == NULL) { + task = ngx_thread_task_alloc(pool, sizeof(ngx_thread_file_ctx_t)); + if (task == NULL) { + return NGX_ERROR; + } + + file->thread_task = task; + } + + ctx = task->ctx; + + if (task->event.complete) { + task->event.complete = 0; + *of = ctx->of; + + return of->err; + } + + task->handler = ngx_thread_open_handler; + + ctx->pool = pool; + ctx->name = file->name; + ctx->of = *of; + + if (file->thread_handler(task, file) != NGX_OK) { + return NGX_ERROR; + } + + return NGX_AGAIN; +} + + ssize_t ngx_thread_read(ngx_file_t *file, u_char *buf, size_t size, off_t offset, ngx_pool_t *pool) { ngx_thread_task_t *task; - ngx_thread_file_ctx_t *ctx; + ngx_thread_file_read_ctx_t *ctx; ngx_log_debug4(NGX_LOG_DEBUG_CORE, file->log, 0, "thread read: %d, %p, %uz, %O", @@ -155,7 +234,7 @@ ngx_thread_read(ngx_file_t *file, u_char *buf, size_t size, off_t offset, static void ngx_thread_read_handler(void *data, ngx_log_t *log) { - ngx_thread_file_ctx_t *ctx = data; + ngx_thread_file_read_ctx_t *ctx = data; ssize_t n; @@ -478,7 +557,7 @@ ngx_thread_write_chain_to_file(ngx_file_t *file, ngx_chain_t *cl, off_t offset, ngx_pool_t *pool) { ngx_thread_task_t *task; - ngx_thread_file_ctx_t *ctx; + ngx_thread_file_read_ctx_t *ctx; ngx_log_debug3(NGX_LOG_DEBUG_CORE, file->log, 0, "thread write chain: %d, %p, %O", @@ -488,7 +567,7 @@ ngx_thread_write_chain_to_file(ngx_file_t *file, ngx_chain_t *cl, off_t offset, if (task == NULL) { task = ngx_thread_task_alloc(pool, - sizeof(ngx_thread_file_ctx_t)); + sizeof(ngx_thread_file_read_ctx_t)); if (task == NULL) { return NGX_ERROR; } @@ -536,7 +615,7 @@ ngx_thread_write_chain_to_file(ngx_file_t *file, ngx_chain_t *cl, off_t offset, static void ngx_thread_write_chain_to_file_handler(void *data, ngx_log_t *log) { - ngx_thread_file_ctx_t *ctx = data; + ngx_thread_file_read_ctx_t *ctx = data; #if (NGX_HAVE_PWRITEV) diff --git src/os/unix/ngx_files.h src/os/unix/ngx_files.h index 07872b13..2659c0cb 100644 --- src/os/unix/ngx_files.h +++ src/os/unix/ngx_files.h @@ -12,11 +12,11 @@ #include #include - typedef int ngx_fd_t; typedef struct stat ngx_file_info_t; typedef ino_t ngx_file_uniq_t; +#include typedef struct { u_char *name; @@ -385,6 +385,8 @@ extern ngx_uint_t ngx_file_aio; #endif #if (NGX_THREADS) +ngx_int_t ngx_thread_open(ngx_file_t *file, ngx_open_file_info_t *of, + ngx_pool_t *pool); ssize_t ngx_thread_read(ngx_file_t *file, u_char *buf, size_t size, off_t offset, ngx_pool_t *pool); ssize_t ngx_thread_write_chain_to_file(ngx_file_t *file, ngx_chain_t *cl, From kahing at cloudflare.com Mon Aug 27 21:57:54 2018 From: kahing at cloudflare.com (Ka-Hing Cheung) Date: Mon, 27 Aug 2018 14:57:54 -0700 Subject: cache: move open to thread pool In-Reply-To: References: <20180808181653.GX56558@mdounin.ru> Message-ID: Hi Eran, Happy to see that we are not the only place where we find open to be a problem. I took a look at your module and while the approach is sound, I decided the complexity doesn't seem to be worth it. Hope to see some numbers of how your module works at scale. - Ka-Hing On Wed, Aug 8, 2018 at 12:44 PM, Eran Kornblau wrote: > Hi, > >> >> - The code bypasses open file cache, and uses a direct call >> in the http cache code instead. While it might be ok in your >> setup, it looks like an incomplete solution from the generic point >> of view. A better solution would be to introduce a generic >> interface in ngx_open_cached_file() to allow use of thread >> pools. >> > > A small comment on this - I wrote such an implementation a while ago > in my module. We've been using it on production for the last ~3 years. > > Code is here - > https://github.com/kaltura/nginx-vod-module/blob/master/ngx_async_open_file_cache.c > > (There's a lot of code there that was copied from ngx_open_file_cache.c, > I did that since those functions are static, and didn't want to change nginx core. > If implemented as part of nginx core, all this duplication can be avoided...) > > In my implementation, I added a function similar to ngx_open_cached_file - > (ngx_async_open_cached_file), that gets a few extra params - > 1. The thread pool > 2. The thread task (optional) - this was done in order to reuse the task > when opening multiple files in a single request > 3. Callback + context - invoked once the async open completes > > This function first checks the cache, if there's a hit, it returns synchronously > (NGX_OK). > Otherwise, it posts a task that does ngx_open_and_stat_file (NGX_AGAIN). > When the task completes, the main nginx thread updates the cache, and invokes > the user callback. > > Hope this helps... > > Eran > > _______________________________________________ > nginx-devel mailing list > nginx-devel at nginx.org > http://mailman.nginx.org/mailman/listinfo/nginx-devel From kiriyama.kentaro at tis.co.jp Mon Aug 27 23:35:53 2018 From: kiriyama.kentaro at tis.co.jp (=?iso-2022-jp?B?GyRCNk07MyEhN3JCQE86GyhC?=) Date: Mon, 27 Aug 2018 23:35:53 +0000 Subject: [nginx]access log and error log Message-ID: Hello, I?m suffering a problem with access.log and error.log for nginx.service on RHEL 7.4. The problem is either access.log and error.log are not recording the log. To solve this issue, I have tried multiple time changing logrotation setting for nginx. Below is the setting of logrotation for nginx.service.(/etc/logrotate.d/nginx) /var/log/nginx/*.log { daily missingok rotate 7 compress create 644 nginx adm sharedscripts postrotate if [ -f /var/run/nginx.pid ]; then kill -USR1 'cat /var/run/nginx.pid' fi endscript } By the way, the log will start recording on both log files after restarting the nginx.service. I would like to know the issue on here and how to solve it. Regards, Kentaro -------------- next part -------------- An HTML attachment was scrubbed... URL: From mdounin at mdounin.ru Tue Aug 28 00:34:56 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 28 Aug 2018 03:34:56 +0300 Subject: [nginx]access log and error log In-Reply-To: References: Message-ID: <20180828003456.GO56558@mdounin.ru> Hello! On Mon, Aug 27, 2018 at 11:35:53PM +0000, ?? ??? wrote: > Hello, > > I?m suffering a problem with access.log and error.log for nginx.service on RHEL 7.4. > > The problem is either access.log and error.log are not recording the log. > > To solve this issue, I have tried multiple time changing logrotation setting for nginx. > > Below is the setting of logrotation for nginx.service.(/etc/logrotate.d/nginx) > > /var/log/nginx/*.log { > daily > missingok > rotate 7 > compress > create 644 nginx adm > sharedscripts > postrotate > if [ -f /var/run/nginx.pid ]; then > kill -USR1 'cat /var/run/nginx.pid' > fi > endscript > } > > By the way, the log will start recording on both log files after restarting the nginx.service. > > I would like to know the issue on here and how to solve it. This is a mailing list for developers. For user-level questions like this one, please use the nginx@ mailing list instead. Thank you. -- Maxim Dounin http://mdounin.ru/ From miranovy at gmail.com Tue Aug 28 07:21:31 2018 From: miranovy at gmail.com (Miroslav Novy) Date: Tue, 28 Aug 2018 09:21:31 +0200 Subject: limit_rate_after support variables In-Reply-To: <20180827160021.GG71000@lo0.su> References: <20180827112847.GE71000@lo0.su> <20180827160021.GG71000@lo0.su> Message-ID: Hi, thank you for your patch. I will look at it. Why did not you merge him to repository? M?ra po 27. 8. 2018 v 18:00 odes?latel Ruslan Ermilov napsal: > Also, Maxim Dounin reminded me that I prepared the patch set > to add variables support to limit_rate_after roughly a year ago, > which I have successfully forgotten now. Here it is, for your > consideration, in the state it was a year ago. > > # HG changeset patch > # Parent e3723f2a11b7ec1c196d59c331739bc21d9d9afd > Added post processing to ngx_http_set_complex_value_slot(). > > diff --git a/src/http/ngx_http_script.c b/src/http/ngx_http_script.c > --- a/src/http/ngx_http_script.c > +++ b/src/http/ngx_http_script.c > @@ -214,6 +214,7 @@ ngx_http_set_complex_value_slot(ngx_conf > char *p = conf; > > ngx_str_t *value; > + ngx_conf_post_t *post; > ngx_http_complex_value_t **cv; > ngx_http_compile_complex_value_t ccv; > > @@ -240,6 +241,11 @@ ngx_http_set_complex_value_slot(ngx_conf > return NGX_CONF_ERROR; > } > > + if (cmd->post) { > + post = cmd->post; > + return post->post_handler(cf, post, *cv); > + } > + > return NGX_CONF_OK; > } > > # HG changeset patch > # Parent 2b522e0bcd9fd218026f923f58a1b8bfed864b2a > Added size_t type support to ngx_http_set_complex_value_slot(). > > If a complex value is expected to be size_t, and the compiled value > is constant, the ngx_http_complex_value_size_p post handler will > remember the constant size_t value. > > The value is accessed through ngx_http_complex_value_size() which > either returns the remembered constant or evaluates the expression > and parses it as size_t. > > diff --git a/src/http/ngx_http_script.c b/src/http/ngx_http_script.c > --- a/src/http/ngx_http_script.c > +++ b/src/http/ngx_http_script.c > @@ -10,6 +10,13 @@ > #include > > > +static char *ngx_http_complex_value_set_size(ngx_conf_t *cf, void *post, > + void *data); > + > +ngx_conf_post_handler_pt ngx_http_complex_value_size_p = > + ngx_http_complex_value_set_size; > + > + > static ngx_int_t ngx_http_script_init_arrays(ngx_http_script_compile_t > *sc); > static ngx_int_t ngx_http_script_done(ngx_http_script_compile_t *sc); > static ngx_int_t ngx_http_script_add_copy_code(ngx_http_script_compile_t > *sc, > @@ -105,6 +112,25 @@ ngx_http_complex_value(ngx_http_request_ > > > ngx_int_t > +ngx_http_complex_value_size(ngx_http_request_t *r, > + ngx_http_complex_value_t *val, ngx_str_t *value, size_t *size) > +{ > + if (val->lengths == NULL) { > + *size = val->u.size; > + return NGX_OK; > + } > + > + if (ngx_http_complex_value(r, val, value) != NGX_OK) { > + return NGX_ERROR; > + } > + > + *size = ngx_parse_size(value); > + > + return NGX_OK; > +} > + > + > +ngx_int_t > ngx_http_compile_complex_value(ngx_http_compile_complex_value_t *ccv) > { > ngx_str_t *v; > @@ -250,6 +276,24 @@ ngx_http_set_complex_value_slot(ngx_conf > } > > > +static char * > +ngx_http_complex_value_set_size(ngx_conf_t *cf, void *post, void *data) > +{ > + ngx_http_complex_value_t *cv = data; > + > + if (cv->lengths) { > + return NGX_CONF_OK; > + } > + > + cv->u.size = ngx_parse_size(&cv->value); > + if (cv->u.size == (size_t) NGX_ERROR) { > + return "invalid value"; > + } > + > + return NGX_CONF_OK; > +} > + > + > ngx_int_t > ngx_http_test_predicates(ngx_http_request_t *r, ngx_array_t *predicates) > { > diff --git a/src/http/ngx_http_script.h b/src/http/ngx_http_script.h > --- a/src/http/ngx_http_script.h > +++ b/src/http/ngx_http_script.h > @@ -68,6 +68,10 @@ typedef struct { > ngx_uint_t *flushes; > void *lengths; > void *values; > + > + union { > + size_t size; > + } u; > } ngx_http_complex_value_t; > > > @@ -207,6 +211,8 @@ void ngx_http_script_flush_complex_value > ngx_http_complex_value_t *val); > ngx_int_t ngx_http_complex_value(ngx_http_request_t *r, > ngx_http_complex_value_t *val, ngx_str_t *value); > +ngx_int_t ngx_http_complex_value_size(ngx_http_request_t *r, > + ngx_http_complex_value_t *val, ngx_str_t *value, size_t *size); > ngx_int_t ngx_http_compile_complex_value(ngx_http_compile_complex_value_t > *ccv); > char *ngx_http_set_complex_value_slot(ngx_conf_t *cf, ngx_command_t *cmd, > void *conf); > @@ -254,4 +260,7 @@ void ngx_http_script_var_code(ngx_http_s > void ngx_http_script_nop_code(ngx_http_script_engine_t *e); > > > +extern ngx_conf_post_handler_pt ngx_http_complex_value_size_p; > + > + > #endif /* _NGX_HTTP_SCRIPT_H_INCLUDED_ */ > # HG changeset patch > # Parent fbf2ea9783be4eeaa938bc4173dbac1149b762dc > Variables support in limit_rate and limit_rate_after (ticket #293). > > diff --git a/src/http/ngx_http_core_module.c > b/src/http/ngx_http_core_module.c > --- a/src/http/ngx_http_core_module.c > +++ b/src/http/ngx_http_core_module.c > @@ -474,18 +474,18 @@ static ngx_command_t ngx_http_core_comm > { ngx_string("limit_rate"), > > NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF > |NGX_CONF_TAKE1, > - ngx_conf_set_size_slot, > + ngx_http_set_complex_value_slot, > NGX_HTTP_LOC_CONF_OFFSET, > offsetof(ngx_http_core_loc_conf_t, limit_rate), > - NULL }, > + &ngx_http_complex_value_size_p }, > > { ngx_string("limit_rate_after"), > > NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF > |NGX_CONF_TAKE1, > - ngx_conf_set_size_slot, > + ngx_http_set_complex_value_slot, > NGX_HTTP_LOC_CONF_OFFSET, > offsetof(ngx_http_core_loc_conf_t, limit_rate_after), > - NULL }, > + &ngx_http_complex_value_size_p }, > > { ngx_string("keepalive_timeout"), > > NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12, > @@ -1431,6 +1431,8 @@ ngx_http_core_content_phase(ngx_http_req > void > ngx_http_update_location_config(ngx_http_request_t *r) > { > + size_t limit_rate; > + ngx_str_t val; > ngx_http_core_loc_conf_t *clcf; > > clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); > @@ -1500,8 +1502,18 @@ ngx_http_update_location_config(ngx_http > r->connection->tcp_nopush = NGX_TCP_NOPUSH_DISABLED; > } > > - if (r->limit_rate == 0) { > - r->limit_rate = clcf->limit_rate; > + if (r->limit_rate == 0 > + && clcf->limit_rate > + && ngx_http_complex_value_size(r, clcf->limit_rate, &val, > &limit_rate) > + == NGX_OK) > + { > + if (limit_rate != (size_t) NGX_ERROR) { > + r->limit_rate = limit_rate; > + > + } else if (val.len) { > + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, > + "invalid \"limit_rate\" value \"%V\"", &val); > + } > } > > if (clcf->handler) { > @@ -3567,6 +3579,8 @@ ngx_http_core_create_loc_conf(ngx_conf_t > * clcf->exact_match = 0; > * clcf->auto_redirect = 0; > * clcf->alias = 0; > + * clcf->limit_rate = NULL; > + * clcf->limit_rate_after = NULL; > * clcf->gzip_proxied = 0; > * clcf->keepalive_disable = 0; > */ > @@ -3596,8 +3610,6 @@ ngx_http_core_create_loc_conf(ngx_conf_t > clcf->send_timeout = NGX_CONF_UNSET_MSEC; > clcf->send_lowat = NGX_CONF_UNSET_SIZE; > clcf->postpone_output = NGX_CONF_UNSET_SIZE; > - clcf->limit_rate = NGX_CONF_UNSET_SIZE; > - clcf->limit_rate_after = NGX_CONF_UNSET_SIZE; > clcf->keepalive_timeout = NGX_CONF_UNSET_MSEC; > clcf->keepalive_header = NGX_CONF_UNSET; > clcf->keepalive_requests = NGX_CONF_UNSET_UINT; > @@ -3785,6 +3797,14 @@ ngx_http_core_merge_loc_conf(ngx_conf_t > ngx_conf_merge_msec_value(conf->client_body_timeout, > prev->client_body_timeout, 60000); > > + if (conf->limit_rate == NULL) { > + conf->limit_rate = prev->limit_rate; > + } > + > + if (conf->limit_rate_after == NULL) { > + conf->limit_rate_after = prev->limit_rate_after; > + } > + > ngx_conf_merge_bitmask_value(conf->keepalive_disable, > prev->keepalive_disable, > (NGX_CONF_BITMASK_SET > @@ -3823,9 +3843,6 @@ ngx_http_core_merge_loc_conf(ngx_conf_t > ngx_conf_merge_size_value(conf->send_lowat, prev->send_lowat, 0); > ngx_conf_merge_size_value(conf->postpone_output, > prev->postpone_output, > 1460); > - ngx_conf_merge_size_value(conf->limit_rate, prev->limit_rate, 0); > - ngx_conf_merge_size_value(conf->limit_rate_after, > prev->limit_rate_after, > - 0); > ngx_conf_merge_msec_value(conf->keepalive_timeout, > prev->keepalive_timeout, 75000); > ngx_conf_merge_sec_value(conf->keepalive_header, > diff --git a/src/http/ngx_http_core_module.h > b/src/http/ngx_http_core_module.h > --- a/src/http/ngx_http_core_module.h > +++ b/src/http/ngx_http_core_module.h > @@ -358,11 +358,12 @@ struct ngx_http_core_loc_conf_s { > size_t client_body_buffer_size; /* client_body_buffer_size */ > size_t send_lowat; /* send_lowat */ > size_t postpone_output; /* postpone_output */ > - size_t limit_rate; /* limit_rate */ > - size_t limit_rate_after; /* limit_rate_after */ > size_t sendfile_max_chunk; /* sendfile_max_chunk */ > size_t read_ahead; /* read_ahead */ > > + ngx_http_complex_value_t *limit_rate; /* limit_rate */ > + ngx_http_complex_value_t *limit_rate_after; > + > ngx_msec_t client_body_timeout; /* client_body_timeout */ > ngx_msec_t send_timeout; /* send_timeout */ > ngx_msec_t keepalive_timeout; /* keepalive_timeout */ > diff --git a/src/http/ngx_http_write_filter_module.c > b/src/http/ngx_http_write_filter_module.c > --- a/src/http/ngx_http_write_filter_module.c > +++ b/src/http/ngx_http_write_filter_module.c > @@ -48,6 +48,8 @@ ngx_int_t > ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in) > { > off_t size, sent, nsent, limit; > + size_t limit_rate_after; > + ngx_str_t val; > ngx_uint_t last, flush, sync; > ngx_msec_t delay; > ngx_chain_t *cl, *ln, **ll, *chain; > @@ -219,8 +221,20 @@ ngx_http_write_filter(ngx_http_request_t > } > > if (r->limit_rate) { > - if (r->limit_rate_after == 0) { > - r->limit_rate_after = clcf->limit_rate_after; > + if (r->limit_rate_after == 0 > + && clcf->limit_rate_after > + && ngx_http_complex_value_size(r, clcf->limit_rate_after, > &val, > + &limit_rate_after) > + == NGX_OK) > + { > + if (limit_rate_after != (size_t) NGX_ERROR) { > + r->limit_rate_after = limit_rate_after; > + > + } else if (val.len) { > + ngx_log_error(NGX_LOG_ERR, c->log, 0, > + "invalid \"limit_rate_after\" value \"%V\"", > + &val); > + } > } > > limit = (off_t) r->limit_rate * (ngx_time() - r->start_sec + 1) > _______________________________________________ > 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 eran.kornblau at kaltura.com Tue Aug 28 09:15:32 2018 From: eran.kornblau at kaltura.com (Eran Kornblau) Date: Tue, 28 Aug 2018 09:15:32 +0000 Subject: cache: move open to thread pool In-Reply-To: References: <20180808181653.GX56558@mdounin.ru> Message-ID: Hi, > Hi Eran, > > Happy to see that we are not the only place where we find open to be a problem. I took a look at your module and while the approach is sound, I decided the complexity doesn't seem to be worth it. Hope to see some numbers of how your module works at scale. > > - Ka-Hing > I don't have numbers that show the improvement we got from moving open to a thread pool, but what I can say is that on our environment, open can sometimes take an unreasonable time to complete - several seconds. I noticed it several years ago, after I added a feature of 'performance counters' to my module (posted it here - https://forum.nginx.org/read.php?2,255847,258854#msg-258854). This is the reason I decided to implement the async open - in order to avoid having all worker active requests hang for so long. In my case, I was already using open file cache, and while I got a fairly good hit ratio, these extreme cases of worker hanging for few seconds wasn't something I wanted to accept. Also, in my setup, I'm not using proxy_cache - my servers serve as origin servers behind a CDN, so a solution that is limited to file cache is not something I could use. Eran From mdounin at mdounin.ru Tue Aug 28 14:55:15 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 28 Aug 2018 14:55:15 +0000 Subject: [nginx] Updated OpenSSL used for win32 builds. Message-ID: details: http://hg.nginx.org/nginx/rev/d5da7e71210e branches: changeset: 7342:d5da7e71210e user: Maxim Dounin date: Tue Aug 28 15:05:41 2018 +0300 description: Updated OpenSSL used for win32 builds. diffstat: misc/GNUmakefile | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diffs (12 lines): diff --git a/misc/GNUmakefile b/misc/GNUmakefile --- a/misc/GNUmakefile +++ b/misc/GNUmakefile @@ -6,7 +6,7 @@ TEMP = tmp CC = cl OBJS = objs.msvc8 -OPENSSL = openssl-1.0.2o +OPENSSL = openssl-1.0.2p ZLIB = zlib-1.2.11 PCRE = pcre-8.42 From xeioex at nginx.com Tue Aug 28 15:37:21 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Tue, 28 Aug 2018 15:37:21 +0000 Subject: [njs] Fixed out-of-bounds read. Message-ID: details: http://hg.nginx.org/njs/rev/cfd82c5cfa93 branches: changeset: 590:cfd82c5cfa93 user: Dmitry Volyntsev date: Tue Aug 28 15:37:14 2018 +0300 description: Fixed out-of-bounds read. Found by Coverity (CID 1438786). diffstat: njs/njs_function.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diffs (12 lines): diff -r 50dfb4ccbceb -r cfd82c5cfa93 njs/njs_function.c --- a/njs/njs_function.c Mon Aug 27 19:19:25 2018 +0300 +++ b/njs/njs_function.c Tue Aug 28 15:37:14 2018 +0300 @@ -517,7 +517,7 @@ njs_function_prototype_length(njs_vm_t * function = value->data.u.function; if (function->native) { - for (n = function->args_offset; n <= NJS_ARGS_TYPES_MAX; n++) { + for (n = function->args_offset; n < NJS_ARGS_TYPES_MAX; n++) { if (function->args_types[n] == 0) { break; } From mdounin at mdounin.ru Tue Aug 28 15:38:24 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 28 Aug 2018 15:38:24 +0000 Subject: [nginx] nginx-1.15.3-RELEASE Message-ID: details: http://hg.nginx.org/nginx/rev/28b3e17ca7eb branches: changeset: 7343:28b3e17ca7eb user: Maxim Dounin date: Tue Aug 28 18:36:00 2018 +0300 description: nginx-1.15.3-RELEASE diffstat: docs/xml/nginx/changes.xml | 97 ++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 97 insertions(+), 0 deletions(-) diffs (107 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,103 @@ + + + + +?????? TLSv1.3 ????? ???????????? ? BoringSSL. + + +now TLSv1.3 can be used with BoringSSL. + + + + + +????????? ssl_early_data, +?????? ???????? ??? ????????????? BoringSSL. + + +the "ssl_early_data" directive, +currently available with BoringSSL. + + + + + +????????? keepalive_timeout ? keepalive_requests +? ????? upstream. + + +the "keepalive_timeout" and "keepalive_requests" directives +in the "upstream" block. + + + + + +?????? ngx_http_dav_module +??? ??????????? ????? ?????? ????????????? ????? ? ??????? ?????? COPY +?? ??????? ??????? ????. + + +the ngx_http_dav_module +did not truncate destination file when copying a file over an existing one +with the COPY method. + + + + + +?????? ngx_http_dav_module +??? ??????????? ????? ????? ????????? ????????? ? ??????? ?????? MOVE +???????????? ??????? ????? ??????? ?? ?????????????? ???? +? ?? ???????? ????? ????????? ?????. + + +the ngx_http_dav_module +used zero access rights on the destination file +and did not preserve file modification time +when moving a file between different file systems with the MOVE method. + + + + + +?????? ngx_http_dav_module +??? ??????????? ????? ? ??????? ?????? COPY +??? ??????????????? ????? ??????????? ????? ??????? ?? ?????????. + + +the ngx_http_dav_module +used default access rights +when copying a file with the COPY method. + + + + + +????????? ??????? ????? ?? ???????? ??? ????????????? HTTP/2; +?????? ????????? ? 1.13.5. + + +some clients might not work when using HTTP/2; +the bug had appeared in 1.13.5. + + + + + +nginx ?? ????????? ? LibreSSL 2.8.0. + + +nginx could not be built with LibreSSL 2.8.0. + + + + + + From mdounin at mdounin.ru Tue Aug 28 15:38:26 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 28 Aug 2018 15:38:26 +0000 Subject: [nginx] release-1.15.3 tag Message-ID: details: http://hg.nginx.org/nginx/rev/5f6d2e102f4c branches: changeset: 7344:5f6d2e102f4c user: Maxim Dounin date: Tue Aug 28 18:36:00 2018 +0300 description: release-1.15.3 tag diffstat: .hgtags | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diffs (8 lines): diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -428,3 +428,4 @@ 051e5fa03b92b8a564f6b12debd483d267391e82 990b3e885636d763b97ed02d0d2cfc161a4e0c09 release-1.15.0 4189160cb946bb38d0bc0a452b5eb4cdd8979fb5 release-1.15.1 b234199c7ed8a156a6bb98f7ff58302c857c954f release-1.15.2 +28b3e17ca7eba1e6a0891afde0e4bc5bcc99c861 release-1.15.3 From xeioex at nginx.com Tue Aug 28 16:23:32 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Tue, 28 Aug 2018 16:23:32 +0000 Subject: [njs] Fixed exception handling in arguments of a function. Message-ID: details: http://hg.nginx.org/njs/rev/0191fae31b6d branches: changeset: 591:0191fae31b6d user: Dmitry Volyntsev date: Tue Aug 28 18:42:43 2018 +0300 description: Fixed exception handling in arguments of a function. diffstat: njs/njs_function.c | 2 +- njs/test/njs_unit_test.c | 5 +++++ 2 files changed, 6 insertions(+), 1 deletions(-) diffs (34 lines): diff -r cfd82c5cfa93 -r 0191fae31b6d njs/njs_function.c --- a/njs/njs_function.c Tue Aug 28 15:37:14 2018 +0300 +++ b/njs/njs_function.c Tue Aug 28 18:42:43 2018 +0300 @@ -216,6 +216,7 @@ njs_function_frame(njs_vm_t *vm, njs_fun frame = (njs_frame_t *) native_frame; frame->local = value; + frame->previous_active_frame = vm->active_frame; return NXT_OK; } @@ -392,7 +393,6 @@ njs_function_call(njs_vm_t *vm, njs_inde vm->scopes[NJS_SCOPE_CLOSURE + n] = &closure->u.values; } - frame->previous_active_frame = vm->active_frame; vm->active_frame = frame; return NJS_APPLIED; diff -r cfd82c5cfa93 -r 0191fae31b6d njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Tue Aug 28 15:37:14 2018 +0300 +++ b/njs/test/njs_unit_test.c Tue Aug 28 18:42:43 2018 +0300 @@ -5907,6 +5907,11 @@ static njs_unit_test_t njs_test[] = { nxt_string("try {}"), nxt_string("SyntaxError: Missing catch or finally after try in 1") }, + { nxt_string("function f(a) {return a;}; " + "function thrower() {throw TypeError('Oops')}; " + "f(thrower())"), + nxt_string("TypeError: Oops") }, + { nxt_string("var a = 0; try { a = 5 }" "catch (e) { a = 9 } finally { a++ } a"), nxt_string("6") }, From ru at nginx.com Wed Aug 29 11:42:30 2018 From: ru at nginx.com (Ruslan Ermilov) Date: Wed, 29 Aug 2018 14:42:30 +0300 Subject: limit_rate_after support variables In-Reply-To: References: <20180827112847.GE71000@lo0.su> <20180827160021.GG71000@lo0.su> Message-ID: <20180829114230.GC43480@lo0.su> On Tue, Aug 28, 2018 at 09:21:31AM +0200, Miroslav Novy wrote: > Hi, > thank you for your patch. I will look at it. Why did not you merge him to > repository? Because nobody indicated interest, nor has made a necessary code review. From arut at nginx.com Wed Aug 29 14:09:09 2018 From: arut at nginx.com (Roman Arutyunyan) Date: Wed, 29 Aug 2018 14:09:09 +0000 Subject: [nginx] Stream: avoid potential infinite loop at preread phase. Message-ID: details: http://hg.nginx.org/nginx/rev/fe767c99c2ad branches: changeset: 7345:fe767c99c2ad user: Roman Arutyunyan date: Wed Aug 29 15:56:42 2018 +0300 description: Stream: avoid potential infinite loop at preread phase. Previously the preread phase code ignored NGX_AGAIN value returned from c->recv() and relied only on c->read->ready. But this flag is not reliable and should only be checked for optimization purposes. For example, when using SSL, c->read->ready may be set when no input is available. This can lead to calling preread handler infinitely in a loop. diffstat: src/stream/ngx_stream_core_module.c | 36 +++++++++++++++++++++--------------- 1 files changed, 21 insertions(+), 15 deletions(-) diffs (59 lines): diff -r 5f6d2e102f4c -r fe767c99c2ad src/stream/ngx_stream_core_module.c --- a/src/stream/ngx_stream_core_module.c Tue Aug 28 18:36:00 2018 +0300 +++ b/src/stream/ngx_stream_core_module.c Wed Aug 29 15:56:42 2018 +0300 @@ -249,34 +249,40 @@ ngx_stream_core_preread_phase(ngx_stream } if (!c->read->ready) { - if (ngx_handle_read_event(c->read, 0) != NGX_OK) { - rc = NGX_ERROR; - break; - } - - if (!c->read->timer_set) { - ngx_add_timer(c->read, cscf->preread_timeout); - } - - c->read->handler = ngx_stream_session_handler; - - return NGX_OK; + break; } n = c->recv(c, c->buffer->last, size); - if (n == NGX_ERROR) { + if (n == NGX_ERROR || n == 0) { rc = NGX_STREAM_OK; break; } - if (n > 0) { - c->buffer->last += n; + if (n == NGX_AGAIN) { + break; } + c->buffer->last += n; + rc = ph->handler(s); } + if (rc == NGX_AGAIN) { + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + ngx_stream_finalize_session(s, NGX_STREAM_INTERNAL_SERVER_ERROR); + return NGX_OK; + } + + if (!c->read->timer_set) { + ngx_add_timer(c->read, cscf->preread_timeout); + } + + c->read->handler = ngx_stream_session_handler; + + return NGX_OK; + } + if (c->read->timer_set) { ngx_del_timer(c->read); } From xeioex at nginx.com Wed Aug 29 17:48:49 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Wed, 29 Aug 2018 17:48:49 +0000 Subject: [njs] Fixed Object() constructor for object types arguments. Message-ID: details: http://hg.nginx.org/njs/rev/da97609863ff branches: changeset: 593:da97609863ff user: Dmitry Volyntsev date: Wed Aug 29 20:32:11 2018 +0300 description: Fixed Object() constructor for object types arguments. diffstat: njs/njs_object.c | 10 ++++++---- njs/test/njs_unit_test.c | 3 +++ 2 files changed, 9 insertions(+), 4 deletions(-) diffs (55 lines): diff -r 3d4c542a162b -r da97609863ff njs/njs_object.c --- a/njs/njs_object.c Wed Aug 29 20:31:43 2018 +0300 +++ b/njs/njs_object.c Wed Aug 29 20:32:11 2018 +0300 @@ -535,8 +535,8 @@ njs_object_constructor(njs_vm_t *vm, njs njs_object_t *object; const njs_value_t *value; - type = NJS_OBJECT; value = njs_arg(args, nargs, 1); + type = value->type; if (njs_is_null_or_void(value)) { @@ -545,6 +545,8 @@ njs_object_constructor(njs_vm_t *vm, njs return NXT_ERROR; } + type = NJS_OBJECT; + } else { if (njs_is_object(value)) { @@ -553,16 +555,16 @@ njs_object_constructor(njs_vm_t *vm, njs } else if (njs_is_primitive(value)) { /* value->type is the same as prototype offset. */ - object = njs_object_value_alloc(vm, value, value->type); + object = njs_object_value_alloc(vm, value, type); if (nxt_slow_path(object == NULL)) { return NXT_ERROR; } - type = njs_object_value_type(value->type); + type = njs_object_value_type(type); } else { njs_type_error(vm, "unexpected constructor argument:%s", - njs_type_string(value->type)); + njs_type_string(type)); return NXT_ERROR; } diff -r 3d4c542a162b -r da97609863ff njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Wed Aug 29 20:31:43 2018 +0300 +++ b/njs/test/njs_unit_test.c Wed Aug 29 20:32:11 2018 +0300 @@ -6060,6 +6060,9 @@ static njs_unit_test_t njs_test[] = { nxt_string("var o = {}; o === new Object(o)"), nxt_string("true") }, + { nxt_string("var o = Object([]); Object.prototype.toString.call(o)"), + nxt_string("[object Array]") }, + { nxt_string("Object.name"), nxt_string("Object") }, From xeioex at nginx.com Wed Aug 29 17:48:48 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Wed, 29 Aug 2018 17:48:48 +0000 Subject: [njs] Fixed Object.prototype.toString for different value types. Message-ID: details: http://hg.nginx.org/njs/rev/3d4c542a162b branches: changeset: 592:3d4c542a162b user: Dmitry Volyntsev date: Wed Aug 29 20:31:43 2018 +0300 description: Fixed Object.prototype.toString for different value types. diffstat: njs/njs_object.c | 61 +++++++++-------------------------------------- njs/test/njs_unit_test.c | 9 +++++++ 2 files changed, 21 insertions(+), 49 deletions(-) diffs (118 lines): diff -r 0191fae31b6d -r 3d4c542a162b njs/njs_object.c --- a/njs/njs_object.c Tue Aug 28 18:42:43 2018 +0300 +++ b/njs/njs_object.c Wed Aug 29 20:31:43 2018 +0300 @@ -1768,33 +1768,14 @@ static const njs_value_t njs_object_reg static const njs_value_t njs_object_date_string = njs_string("[object Date]"); static const njs_value_t njs_object_error_string = njs_string("[object Error]"); -static const njs_value_t njs_object_eval_error_string = - njs_long_string("[object EvalError]"); -static const njs_value_t njs_object_internal_error_string = - njs_long_string("[object InternalError]"); -static const njs_value_t njs_object_range_error_string = - njs_long_string("[object RangeError]"); -static const njs_value_t njs_object_ref_error_string = - njs_long_string("[object RefError]"); -static const njs_value_t njs_object_syntax_error_string = - njs_long_string("[object SyntaxError]"); -static const njs_value_t njs_object_type_error_string = - njs_long_string("[object TypeError]"); -static const njs_value_t njs_object_uri_error_string = - njs_long_string("[object URIError]"); -static const njs_value_t njs_object_object_value_string = - njs_long_string("[object ObjectValue]"); - njs_ret_t njs_object_prototype_to_string(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused) { - int32_t index; - njs_object_t *object; - const njs_value_t *value; - njs_object_prototype_t *prototype; + int32_t index; + const njs_value_t *value; static const njs_value_t *class_name[] = { /* Primitives. */ @@ -1826,42 +1807,24 @@ njs_object_prototype_to_string(njs_vm_t &njs_object_regexp_string, &njs_object_date_string, &njs_object_error_string, - &njs_object_eval_error_string, - &njs_object_internal_error_string, - &njs_object_range_error_string, - &njs_object_ref_error_string, - &njs_object_syntax_error_string, - &njs_object_type_error_string, - &njs_object_uri_error_string, - &njs_object_object_value_string, + &njs_object_error_string, + &njs_object_error_string, + &njs_object_error_string, + &njs_object_error_string, + &njs_object_error_string, + &njs_object_error_string, + &njs_object_error_string, + &njs_object_object_string, }; value = &args[0]; index = value->type; - if (njs_is_object(value)) { - object = value->data.u.object; - - do { - prototype = (njs_object_prototype_t *) object; - index = prototype - vm->prototypes; - - if (index >= 0 && index < NJS_PROTOTYPE_MAX) { - index += NJS_OBJECT; - goto found; - } - - object = object->__proto__; - - } while (object != NULL); - - nxt_thread_log_alert("prototype not found"); - + if (nxt_slow_path(class_name[index] == &njs_string_empty)) { + njs_internal_error(vm, "Unknown value type"); return NXT_ERROR; } -found: - vm->retval = *class_name[index]; return NXT_OK; diff -r 0191fae31b6d -r 3d4c542a162b njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Tue Aug 28 18:42:43 2018 +0300 +++ b/njs/test/njs_unit_test.c Wed Aug 29 20:31:43 2018 +0300 @@ -6081,6 +6081,12 @@ static njs_unit_test_t njs_test[] = { nxt_string("Object.prototype.toString.call(Object.prototype)"), nxt_string("[object Object]") }, + { nxt_string("Object.prototype.toString.call(new Array)"), + nxt_string("[object Array]") }, + + { nxt_string("Object.prototype.toString.call(new URIError)"), + nxt_string("[object Error]") }, + { nxt_string("Object.prototype"), nxt_string("[object Object]") }, @@ -9525,6 +9531,9 @@ static njs_unit_test_t njs_test[] = { nxt_string("require('crypto').createHash('sha1')"), nxt_string("[object Hash]") }, + { nxt_string("Object.prototype.toString.call(require('crypto').createHash('sha1'))"), + nxt_string("[object Object]") }, + { nxt_string("var h = require('crypto').createHash('md5');" "h.update('AB').digest('hex')"), nxt_string("b86fc6b051f63d73de262d4c34e3a0a9") }, From miranovy at gmail.com Thu Aug 30 07:01:05 2018 From: miranovy at gmail.com (Miroslav Novy) Date: Thu, 30 Aug 2018 09:01:05 +0200 Subject: limit_rate_after support variables In-Reply-To: <20180829114230.GC43480@lo0.su> References: <20180827112847.GE71000@lo0.su> <20180827160021.GG71000@lo0.su> <20180829114230.GC43480@lo0.su> Message-ID: Hi, we are interested :) I tried your patch with actual sources, the solution is very similar to my, you just use the functions. It is better. I tried it with this configuration: ... location / { root /var/www/default/; index index.html index.htm; set $my_limit_rate 2k; set $my_limit_rate_after 2m; limit_rate $my_limit_rate; limit_rate_after $my_limit_rate_after; access_by_lua_block { ngx.var.my_limit_rate = '4k' ngx.var.my_limit_rate_after = '10m' } } ... Settings of limit_rate_after works good :) But settings of limit_rate throws warning and value is always set to zero. The problem is that they try to retrieve the value of the variable before it is set by the set command. 2018/08/28 10:36:22 [warn] 8180#0: *1 using uninitialized "my_limit_rate" variable, client: 10.255.255.10, server: localhost, request: "GET /iloveyou_words.mp4 HTTP/1.1", host: "mira-nginx.dev.srw.cz" 2018/08/28 10:36:22 [debug] 8180#0: *1 http script var: "" 2018/08/28 10:36:22 [debug] 8180#0: *1 http cl:-1 max:1048576 2018/08/28 10:36:22 [debug] 8180#0: *1 rewrite phase: 2 2018/08/28 10:36:22 [debug] 8180#0: *1 http script value: "2k" 2018/08/28 10:36:22 [debug] 8180#0: *1 http script set $my_limit_rate Can you help me with this? Thanks M?ra Nov? -------------- next part -------------- An HTML attachment was scrubbed... URL: From arut at nginx.com Thu Aug 30 11:45:17 2018 From: arut at nginx.com (Roman Arutyunyan) Date: Thu, 30 Aug 2018 11:45:17 +0000 Subject: [nginx] Version bump. Message-ID: details: http://hg.nginx.org/nginx/rev/039d3eff14a1 branches: changeset: 7346:039d3eff14a1 user: Roman Arutyunyan date: Thu Aug 30 14:42:15 2018 +0300 description: Version bump. diffstat: src/core/nginx.h | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diffs (14 lines): diff -r fe767c99c2ad -r 039d3eff14a1 src/core/nginx.h --- a/src/core/nginx.h Wed Aug 29 15:56:42 2018 +0300 +++ b/src/core/nginx.h Thu Aug 30 14:42:15 2018 +0300 @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1015003 -#define NGINX_VERSION "1.15.3" +#define nginx_version 1015004 +#define NGINX_VERSION "1.15.4" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD From xeioex at nginx.com Thu Aug 30 15:51:47 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Thu, 30 Aug 2018 15:51:47 +0000 Subject: [njs] Improved Object.prototype.toString for invalid values. Message-ID: details: http://hg.nginx.org/njs/rev/6931a42f5bed branches: changeset: 594:6931a42f5bed user: Dmitry Volyntsev date: Thu Aug 30 17:21:51 2018 +0300 description: Improved Object.prototype.toString for invalid values. diffstat: njs/njs_object.c | 35 +++++++++++++++++------------------ 1 files changed, 17 insertions(+), 18 deletions(-) diffs (63 lines): diff -r da97609863ff -r 6931a42f5bed njs/njs_object.c --- a/njs/njs_object.c Wed Aug 29 20:32:11 2018 +0300 +++ b/njs/njs_object.c Thu Aug 30 17:21:51 2018 +0300 @@ -1776,8 +1776,7 @@ njs_ret_t njs_object_prototype_to_string(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused) { - int32_t index; - const njs_value_t *value; + const njs_value_t *name; static const njs_value_t *class_name[] = { /* Primitives. */ @@ -1789,15 +1788,15 @@ njs_object_prototype_to_string(njs_vm_t &njs_object_data_string, &njs_object_exernal_string, - &njs_string_empty, - &njs_string_empty, - &njs_string_empty, - &njs_string_empty, - &njs_string_empty, - &njs_string_empty, - &njs_string_empty, - &njs_string_empty, - &njs_string_empty, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, /* Objects. */ &njs_object_object_string, @@ -1819,17 +1818,17 @@ njs_object_prototype_to_string(njs_vm_t &njs_object_object_string, }; - value = &args[0]; - index = value->type; + name = class_name[args[0].type]; - if (nxt_slow_path(class_name[index] == &njs_string_empty)) { - njs_internal_error(vm, "Unknown value type"); - return NXT_ERROR; + if (nxt_fast_path(name != NULL)) { + vm->retval = *name; + + return NXT_OK; } - vm->retval = *class_name[index]; + njs_internal_error(vm, "Unknown value type"); - return NXT_OK; + return NXT_ERROR; } From xeioex at nginx.com Thu Aug 30 17:37:22 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Thu, 30 Aug 2018 17:37:22 +0000 Subject: [njs] Improved handling of traps inside trap handlers. Message-ID: details: http://hg.nginx.org/njs/rev/7ccb11c88d27 branches: changeset: 596:7ccb11c88d27 user: Dmitry Volyntsev date: Thu Aug 30 20:21:43 2018 +0300 description: Improved handling of traps inside trap handlers. diffstat: njs/njs_vm.c | 6 ++++++ 1 files changed, 6 insertions(+), 0 deletions(-) diffs (16 lines): diff -r 5dd7d38bb08c -r 7ccb11c88d27 njs/njs_vm.c --- a/njs/njs_vm.c Thu Aug 30 20:21:18 2018 +0300 +++ b/njs/njs_vm.c Thu Aug 30 20:21:43 2018 +0300 @@ -3280,6 +3280,12 @@ njs_vmcode_restart(njs_vm_t *vm, njs_val ret = vmcode->code.operation(vm, value1, &frame->trap_values[1]); + if (nxt_slow_path(ret == NJS_TRAP)) { + /* Trap handlers are not reentrant. */ + njs_internal_error(vm, "trap inside restart instruction"); + return NXT_ERROR; + } + retval = njs_vmcode_operand(vm, vmcode->operand1); //njs_release(vm, retval); From xeioex at nginx.com Thu Aug 30 17:37:22 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Thu, 30 Aug 2018 17:37:22 +0000 Subject: [njs] Fixed comparison of objects and strings. Message-ID: details: http://hg.nginx.org/njs/rev/5dd7d38bb08c branches: changeset: 595:5dd7d38bb08c user: Dmitry Volyntsev date: Thu Aug 30 20:21:18 2018 +0300 description: Fixed comparison of objects and strings. diffstat: njs/njs_vm.c | 40 ++++++++++++++++++++++++++-------------- njs/test/njs_unit_test.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 14 deletions(-) diffs (99 lines): diff -r 6931a42f5bed -r 5dd7d38bb08c njs/njs_vm.c --- a/njs/njs_vm.c Thu Aug 30 17:21:51 2018 +0300 +++ b/njs/njs_vm.c Thu Aug 30 20:21:18 2018 +0300 @@ -1814,6 +1814,7 @@ njs_vmcode_greater_or_equal(njs_vm_t *vm /* + * ECMAScript 5.1: 11.8.5 * njs_values_compare() returns * 1 if val1 is less than val2, * 0 if val1 is greater than or equal to val2, @@ -1825,24 +1826,35 @@ static nxt_noinline njs_ret_t 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))) { - - if (nxt_fast_path(njs_is_numeric(val1) && njs_is_numeric(val2))) { - - /* NaN and void values are not comparable with anything. */ - if (isnan(val1->data.u.number) || isnan(val2->data.u.number)) { - return -1; + double num1, num2; + + if (nxt_fast_path(njs_is_primitive(val1) && njs_is_primitive(val2))) { + + if (nxt_fast_path(njs_is_numeric(val1))) { + num1 = val1->data.u.number; + + if (nxt_fast_path(njs_is_numeric(val2))) { + num2 = val2->data.u.number; + + } else { + num2 = njs_string_to_number(val2, 0); } - /* Infinities are handled correctly by comparision. */ - return (val1->data.u.number < val2->data.u.number); + } else if (njs_is_numeric(val2)) { + num1 = njs_string_to_number(val1, 0); + num2 = val2->data.u.number; + + } else { + return (njs_string_cmp(val1, val2) < 0) ? 1 : 0; } - 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; + /* NaN and void values are not comparable with anything. */ + if (isnan(num1) || isnan(num2)) { + return -1; + } + + /* Infinities are handled correctly by comparision. */ + return (num1 < num2); } return njs_trap(vm, NJS_TRAP_COMPARISON); diff -r 6931a42f5bed -r 5dd7d38bb08c njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Thu Aug 30 17:21:51 2018 +0300 +++ b/njs/test/njs_unit_test.c Thu Aug 30 20:21:18 2018 +0300 @@ -1528,6 +1528,34 @@ static njs_unit_test_t njs_test[] = nxt_string("false") }, /**/ + { nxt_string("new String('1') > new Number(1)"), + nxt_string("false") }, + + { nxt_string("new Boolean(true) > '1'"), + nxt_string("false") }, + + { nxt_string("'0' >= new Number(1)"), + nxt_string("false") }, + + { nxt_string("'1' >= new Number(1)"), + nxt_string("true") }, + + { nxt_string("new String('1') < new Number(1)"), + nxt_string("false") }, + + { nxt_string("new Boolean(true) < '1'"), + nxt_string("false") }, + + { nxt_string("new String('1') <= new Number(1)"), + nxt_string("true") }, + + { nxt_string("new Boolean(true) <= '1'"), + nxt_string("true") }, + + { nxt_string("'-1' < {valueOf: function() {return -2}}"), + nxt_string("false") }, + + /**/ { nxt_string("var a; a = 1 ? 2 : 3"), nxt_string("2") }, From xeioex at nginx.com Fri Aug 31 13:56:55 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Fri, 31 Aug 2018 13:56:55 +0000 Subject: [njs] Improved wording for InternalError messages. Message-ID: details: http://hg.nginx.org/njs/rev/25d3bb391edb branches: changeset: 597:25d3bb391edb user: Dmitry Volyntsev date: Fri Aug 31 16:55:35 2018 +0300 description: Improved wording for InternalError messages. diffstat: njs/njs_error.c | 4 ++-- njs/njs_extern.c | 4 ++-- njs/njs_fs.c | 6 +++--- njs/njs_generator.c | 3 ++- njs/njs_json.c | 17 ++++++++++------- njs/njs_object.c | 16 ++++++++-------- njs/njs_regexp.c | 4 ++-- njs/njs_variable.c | 2 +- 8 files changed, 30 insertions(+), 26 deletions(-) diffs (262 lines): diff -r 7ccb11c88d27 -r 25d3bb391edb njs/njs_error.c --- a/njs/njs_error.c Thu Aug 30 20:21:43 2018 +0300 +++ b/njs/njs_error.c Fri Aug 31 16:55:35 2018 +0300 @@ -87,7 +87,7 @@ njs_error_alloc(njs_vm_t *vm, njs_value_ ret = nxt_lvlhsh_insert(&error->hash, &lhq); if (nxt_slow_path(ret != NXT_OK)) { - njs_internal_error(vm, NULL); + njs_internal_error(vm, "lvlhsh insert failed"); return NULL; } } @@ -108,7 +108,7 @@ njs_error_alloc(njs_vm_t *vm, njs_value_ ret = nxt_lvlhsh_insert(&error->hash, &lhq); if (nxt_slow_path(ret != NXT_OK)) { - njs_internal_error(vm, NULL); + njs_internal_error(vm, "lvlhsh insert failed"); return NULL; } } diff -r 7ccb11c88d27 -r 25d3bb391edb njs/njs_extern.c --- a/njs/njs_extern.c Thu Aug 30 20:21:43 2018 +0300 +++ b/njs/njs_extern.c Fri Aug 31 16:55:35 2018 +0300 @@ -144,7 +144,7 @@ njs_vm_external_add(njs_vm_t *vm, nxt_lv ret = nxt_lvlhsh_insert(hash, &lhq); if (nxt_slow_path(ret != NXT_OK)) { - njs_internal_error(vm, NULL); + njs_internal_error(vm, "lvlhsh insert failed"); return NULL; } } @@ -229,7 +229,7 @@ njs_vm_external_bind(njs_vm_t *vm, const ret = nxt_lvlhsh_insert(&vm->externals_hash, &lhq); if (nxt_slow_path(ret != NXT_OK)) { - njs_internal_error(vm, NULL); + njs_internal_error(vm, "lvlhsh insert failed"); return ret; } diff -r 7ccb11c88d27 -r 25d3bb391edb njs/njs_fs.c --- a/njs/njs_fs.c Thu Aug 30 20:21:43 2018 +0300 +++ b/njs/njs_fs.c Fri Aug 31 16:55:35 2018 +0300 @@ -923,7 +923,7 @@ static njs_ret_t njs_fs_error(njs_vm_t * ret = nxt_lvlhsh_insert(&error->hash, &lhq); if (nxt_slow_path(ret != NXT_OK)) { - njs_internal_error(vm, NULL); + njs_internal_error(vm, "lvlhsh insert failed"); return NJS_ERROR; } } @@ -942,7 +942,7 @@ static njs_ret_t njs_fs_error(njs_vm_t * ret = nxt_lvlhsh_insert(&error->hash, &lhq); if (nxt_slow_path(ret != NXT_OK)) { - njs_internal_error(vm, NULL); + njs_internal_error(vm, "lvlhsh insert failed"); return NJS_ERROR; } } @@ -967,7 +967,7 @@ static njs_ret_t njs_fs_error(njs_vm_t * ret = nxt_lvlhsh_insert(&error->hash, &lhq); if (nxt_slow_path(ret != NXT_OK)) { - njs_internal_error(vm, NULL); + njs_internal_error(vm, "lvlhsh insert failed"); return NJS_ERROR; } } diff -r 7ccb11c88d27 -r 25d3bb391edb njs/njs_generator.c --- a/njs/njs_generator.c Thu Aug 30 20:21:43 2018 +0300 +++ b/njs/njs_generator.c Fri Aug 31 16:55:35 2018 +0300 @@ -2066,7 +2066,8 @@ njs_generate_scope(njs_vm_t *vm, njs_par parser->code_size, code_size); if (nxt_slow_path(parser->code_size < code_size)) { - njs_internal_error(vm, NULL); + njs_internal_error(vm, "code size mismatch actual %uz < expected %uz", + parser->code_size, code_size); return NXT_ERROR; } diff -r 7ccb11c88d27 -r 25d3bb391edb njs/njs_json.c --- a/njs/njs_json.c Thu Aug 30 20:21:43 2018 +0300 +++ b/njs/njs_json.c Fri Aug 31 16:55:35 2018 +0300 @@ -474,7 +474,7 @@ njs_json_parse_object(njs_json_parse_ctx ret = nxt_lvlhsh_insert(&object->hash, &lhq); if (nxt_slow_path(ret != NXT_OK)) { - njs_internal_error(ctx->vm, NULL); + njs_internal_error(ctx->vm, "lvlhsh insert/replace failed"); return NULL; } @@ -568,7 +568,6 @@ njs_json_parse_array(njs_json_parse_ctx_ ret = njs_array_add(ctx->vm, array, element); if (nxt_slow_path(ret != NXT_OK)) { - njs_internal_error(ctx->vm, NULL); return NULL; } @@ -982,7 +981,7 @@ njs_json_parse_continuation(njs_vm_t *vm } if (nxt_slow_path(ret != NXT_OK)) { - njs_internal_error(vm, NULL); + njs_internal_error(vm, "lvlhsh insert/replace failed"); return NXT_ERROR; } @@ -1020,7 +1019,8 @@ njs_json_parse_continuation(njs_vm_t *vm break; default: - njs_internal_error(vm, NULL); + njs_internal_error(vm, "Unexpected state %d in JSON.parse()", + state->type); return NXT_ERROR; } } @@ -1062,7 +1062,8 @@ njs_json_parse_continuation_apply(njs_vm break; default: - njs_internal_error(vm, NULL); + njs_internal_error(vm, "Unexpected state %d in JSON.parse() apply", + state->type); return NXT_ERROR; } @@ -1489,7 +1490,8 @@ njs_json_stringify_to_json(njs_vm_t *vm, break; default: - njs_internal_error(vm, NULL); + njs_internal_error(vm, "Unexpected state %d in JSON.stringify() apply", + state->type); return NXT_ERROR; } @@ -1533,7 +1535,8 @@ njs_json_stringify_replacer(njs_vm_t *vm break; default: - njs_internal_error(vm, NULL); + njs_internal_error(vm, "Unexpected state %d in " + "JSON.stringify() replacer", state->type); return NXT_ERROR; } diff -r 7ccb11c88d27 -r 25d3bb391edb njs/njs_object.c --- a/njs/njs_object.c Thu Aug 30 20:21:43 2018 +0300 +++ b/njs/njs_object.c Fri Aug 31 16:55:35 2018 +0300 @@ -117,7 +117,7 @@ njs_object_hash_create(njs_vm_t *vm, nxt ret = nxt_lvlhsh_insert(hash, &lhq); if (nxt_slow_path(ret != NXT_OK)) { - njs_internal_error(vm, NULL); + njs_internal_error(vm, "lvlhsh insert failed"); return NXT_ERROR; } @@ -916,7 +916,7 @@ njs_define_property(njs_vm_t *vm, njs_ob ret = nxt_lvlhsh_insert(&object->hash, &lhq); if (nxt_slow_path(ret != NXT_OK)) { - njs_internal_error(vm, NULL); + njs_internal_error(vm, "lvlhsh insert failed"); return NXT_ERROR; } @@ -1077,7 +1077,7 @@ njs_object_get_own_property_descriptor(n ret = nxt_lvlhsh_insert(&descriptor->hash, &lhq); if (nxt_slow_path(ret != NXT_OK)) { - njs_internal_error(vm, NULL); + njs_internal_error(vm, "lvlhsh insert failed"); return NXT_ERROR; } @@ -1095,7 +1095,7 @@ njs_object_get_own_property_descriptor(n ret = nxt_lvlhsh_insert(&descriptor->hash, &lhq); if (nxt_slow_path(ret != NXT_OK)) { - njs_internal_error(vm, NULL); + njs_internal_error(vm, "lvlhsh insert failed"); return NXT_ERROR; } @@ -1113,7 +1113,7 @@ njs_object_get_own_property_descriptor(n ret = nxt_lvlhsh_insert(&descriptor->hash, &lhq); if (nxt_slow_path(ret != NXT_OK)) { - njs_internal_error(vm, NULL); + njs_internal_error(vm, "lvlhsh insert failed"); return NXT_ERROR; } @@ -1131,7 +1131,7 @@ njs_object_get_own_property_descriptor(n ret = nxt_lvlhsh_insert(&descriptor->hash, &lhq); if (nxt_slow_path(ret != NXT_OK)) { - njs_internal_error(vm, NULL); + njs_internal_error(vm, "lvlhsh insert failed"); return NXT_ERROR; } @@ -1488,7 +1488,7 @@ njs_property_prototype_create(njs_vm_t * return &prop->value; } - njs_internal_error(vm, NULL); + njs_internal_error(vm, "lvlhsh insert failed"); return NULL; } @@ -1730,7 +1730,7 @@ njs_property_constructor_create(njs_vm_t return &prop->value; } - njs_internal_error(vm, NULL); + njs_internal_error(vm, "lvlhsh insert failed"); return NULL; } diff -r 7ccb11c88d27 -r 25d3bb391edb njs/njs_regexp.c --- a/njs/njs_regexp.c Thu Aug 30 20:21:43 2018 +0300 +++ b/njs/njs_regexp.c Fri Aug 31 16:55:35 2018 +0300 @@ -327,7 +327,7 @@ njs_regexp_pattern_create(njs_vm_t *vm, if (nxt_fast_path(ret >= 0)) { if (nxt_slow_path((u_int) ret != pattern->ncaptures)) { - njs_internal_error(vm, NULL); + njs_internal_error(vm, "regexp pattern compile failed"); nxt_mem_cache_free(vm->mem_cache_pool, pattern); return NULL; } @@ -755,7 +755,7 @@ njs_regexp_exec_result(njs_vm_t *vm, njs ret = nxt_lvlhsh_insert(&array->object.hash, &lhq); if (nxt_slow_path(ret != NXT_OK)) { - njs_internal_error(vm, NULL); + njs_internal_error(vm, "lvlhsh insert failed"); goto fail; } diff -r 7ccb11c88d27 -r 25d3bb391edb njs/njs_variable.c --- a/njs/njs_variable.c Thu Aug 30 20:21:43 2018 +0300 +++ b/njs/njs_variable.c Fri Aug 31 16:55:35 2018 +0300 @@ -83,7 +83,7 @@ njs_builtin_add(njs_vm_t *vm, njs_parser ret = nxt_lvlhsh_insert(&scope->variables, &lhq); if (nxt_fast_path(ret == NXT_OK)) { - njs_internal_error(vm, NULL); + njs_internal_error(vm, "lvlhsh insert failed"); return var; }