From xeioex at nginx.com Mon Apr 1 16:12:22 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Mon, 01 Apr 2019 16:12:22 +0000 Subject: [njs] Refactored function object creation. Message-ID: details: https://hg.nginx.org/njs/rev/b38fe378d900 branches: changeset: 862:b38fe378d900 user: Dmitry Volyntsev date: Mon Apr 01 19:11:39 2019 +0300 description: Refactored function object creation. diffstat: njs/njs_function.c | 62 ++++++++++++++++++++++++++++++++++------------------- njs/njs_function.h | 3 +- njs/njs_parser.c | 21 ++++++++++++++--- njs/njs_vm.c | 29 +----------------------- 4 files changed, 61 insertions(+), 54 deletions(-) diffs (172 lines): diff -r 1bce636aed3d -r b38fe378d900 njs/njs_function.c --- a/njs/njs_function.c Sun Mar 31 22:59:04 2019 +0800 +++ b/njs/njs_function.c Mon Apr 01 19:11:39 2019 +0300 @@ -14,35 +14,53 @@ static njs_ret_t njs_normalize_args(njs_ njs_function_t * -njs_function_alloc(njs_vm_t *vm) +njs_function_alloc(njs_vm_t *vm, njs_function_lambda_t *lambda, + njs_closure_t *closures[], nxt_bool_t shared) { + size_t size; + nxt_uint_t n, nesting; njs_function_t *function; - function = nxt_mp_zalloc(vm->mem_pool, sizeof(njs_function_t)); + nesting = lambda->nesting; + size = sizeof(njs_function_t) + nesting * sizeof(njs_closure_t *); + + function = nxt_mp_zalloc(vm->mem_pool, size); + if (nxt_slow_path(function == NULL)) { + goto fail; + } + - if (nxt_fast_path(function != NULL)) { - /* - * nxt_mp_zalloc() does also: - * nxt_lvlhsh_init(&function->object.hash); - * function->object.__proto__ = NULL; - */ + /* + * nxt_mp_zalloc() does also: + * nxt_lvlhsh_init(&function->object.hash); + * function->object.__proto__ = NULL; + */ + + function->ctor = 1; + function->args_offset = 1; + function->u.lambda = lambda; - function->object.shared_hash = vm->shared->function_prototype_hash; - function->object.type = NJS_FUNCTION; - function->object.shared = 1; - function->object.extensible = 1; - function->args_offset = 1; - function->ctor = 1; + function->object.shared_hash = vm->shared->function_prototype_hash; + function->object.__proto__ = &vm->prototypes[NJS_PROTOTYPE_FUNCTION].object; + function->object.type = NJS_FUNCTION; + function->object.shared = shared; + function->object.extensible = 1; + + if (nesting != 0 && closures != NULL) { + function->closure = 1; + + n = 0; - function->u.lambda = nxt_mp_zalloc(vm->mem_pool, - sizeof(njs_function_lambda_t)); - if (nxt_slow_path(function->u.lambda == NULL)) { - njs_memory_error(vm); - return NULL; - } + do { + /* GC: retain closure. */ + function->closures[n] = closures[n]; + n++; + } while (n < nesting); + } - return function; - } + return function; + +fail: njs_memory_error(vm); diff -r 1bce636aed3d -r b38fe378d900 njs/njs_function.h --- a/njs/njs_function.h Sun Mar 31 22:59:04 2019 +0800 +++ b/njs/njs_function.h Mon Apr 01 19:11:39 2019 +0300 @@ -147,7 +147,8 @@ struct njs_frame_s { }; -njs_function_t *njs_function_alloc(njs_vm_t *vm); +njs_function_t *njs_function_alloc(njs_vm_t *vm, njs_function_lambda_t *lambda, + njs_closure_t *closures[], nxt_bool_t shared); njs_function_t *njs_function_value_copy(njs_vm_t *vm, njs_value_t *value); njs_ret_t njs_function_arguments_object_init(njs_vm_t *vm, njs_native_frame_t *frame); diff -r 1bce636aed3d -r b38fe378d900 njs/njs_parser.c --- a/njs/njs_parser.c Sun Mar 31 22:59:04 2019 +0800 +++ b/njs/njs_parser.c Mon Apr 01 19:11:39 2019 +0300 @@ -552,10 +552,23 @@ static njs_function_t * njs_parser_function_alloc(njs_vm_t *vm, njs_parser_t *parser, njs_variable_t *var) { - njs_value_t *value; - njs_function_t *function; - - function = njs_function_alloc(vm); + njs_value_t *value; + njs_function_t *function; + njs_function_lambda_t *lambda; + + lambda = nxt_mp_zalloc(vm->mem_pool, sizeof(njs_function_lambda_t)); + if (nxt_slow_path(lambda == NULL)) { + njs_memory_error(vm); + return NULL; + } + + /* TODO: + * njs_function_t is used to pass lambda to + * njs_generate_function_declaration() and is not actually needed. + * real njs_function_t is created by njs_vmcode_function() in runtime. + */ + + function = njs_function_alloc(vm, lambda, NULL, 1); if (nxt_slow_path(function == NULL)) { return NULL; } diff -r 1bce636aed3d -r b38fe378d900 njs/njs_vm.c --- a/njs/njs_vm.c Sun Mar 31 22:59:04 2019 +0800 +++ b/njs/njs_vm.c Mon Apr 01 19:11:39 2019 +0300 @@ -371,43 +371,18 @@ njs_vmcode_array(njs_vm_t *vm, njs_value njs_ret_t njs_vmcode_function(njs_vm_t *vm, njs_value_t *invld1, njs_value_t *invld2) { - size_t size; - nxt_uint_t n, nesting; njs_function_t *function; njs_function_lambda_t *lambda; njs_vmcode_function_t *code; code = (njs_vmcode_function_t *) vm->current; lambda = code->lambda; - nesting = lambda->nesting; - - size = sizeof(njs_function_t) + nesting * sizeof(njs_closure_t *); - - function = nxt_mp_zalloc(vm->mem_pool, size); + + function = njs_function_alloc(vm, lambda, vm->active_frame->closures, 0); if (nxt_slow_path(function == NULL)) { - njs_memory_error(vm); return NXT_ERROR; } - function->u.lambda = lambda; - function->object.shared_hash = vm->shared->function_prototype_hash; - function->object.__proto__ = &vm->prototypes[NJS_PROTOTYPE_FUNCTION].object; - function->object.extensible = 1; - function->args_offset = 1; - function->ctor = 1; - - if (nesting != 0) { - function->closure = 1; - - n = 0; - - do { - /* GC: retain closure. */ - function->closures[n] = vm->active_frame->closures[n]; - n++; - } while (n < nesting); - } - vm->retval.data.u.function = function; vm->retval.type = NJS_FUNCTION; vm->retval.data.truth = 1; From igor at sysoev.ru Tue Apr 2 14:18:26 2019 From: igor at sysoev.ru (Igor Sysoev) Date: Tue, 02 Apr 2019 14:18:26 +0000 Subject: [njs] Fixed editline detection. Message-ID: details: https://hg.nginx.org/njs/rev/61f2616e21c7 branches: changeset: 863:61f2616e21c7 user: Igor Sysoev date: Tue Apr 02 17:17:49 2019 +0300 description: Fixed editline detection. This simplifies building on modern macOS. diffstat: auto/editline | 37 +++++++++++++++++++++++++------------ njs/njs_shell.c | 8 +++++++- 2 files changed, 32 insertions(+), 13 deletions(-) diffs (92 lines): diff -r b38fe378d900 -r 61f2616e21c7 auto/editline --- a/auto/editline Mon Apr 01 19:11:39 2019 +0300 +++ b/auto/editline Tue Apr 02 17:17:49 2019 +0300 @@ -7,26 +7,33 @@ NXT_EDITLINE_LIB= nxt_found=no -nxt_feature="editline library" +nxt_feature="editline library in editline/readline.h" nxt_feature_name=NXT_HAVE_EDITLINE nxt_feature_run=no -nxt_feature_incs="-I/usr/include/editline" +nxt_feature_incs= nxt_feature_libs="-ledit" nxt_feature_test="#include - #include + #include - int main(void) { - add_history(NULL); - return 0; - }" + int main(void) { + add_history(NULL); + return 0; + }" . auto/feature if [ $nxt_found = no ]; then # FreeBSD port - nxt_feature="editline in /usr/include/edit" - nxt_feature_incs="-I/usr/include/edit/readline" + nxt_feature_name=NXT_HAVE_EDIT_READLINE + nxt_feature="editline in edit/readline/readline.h" + nxt_feature_test="#include + #include + + int main(void) { + add_history(NULL); + return 0; + }" . auto/feature fi @@ -35,9 +42,15 @@ if [ $nxt_found = no ]; then # NetBSD - nxt_feature="editline in /usr/include" - nxt_feature_incs="-I/usr/include/readline" + nxt_feature_name=NXT_HAVE_READLINE + nxt_feature="editline in readline/readline.h" + nxt_feature_test="#include + #include + int main(void) { + add_history(NULL); + return 0; + }" . auto/feature fi @@ -47,8 +60,8 @@ if [ $nxt_found = yes ]; then NXT_HAVE_LIBEDIT=YES NXT_EDITLINE_CFLAGS=$nxt_feature_incs NXT_EDITLINE_LIB=$nxt_feature_libs + NXT_DEFAULT_TARGET="$NXT_DEFAULT_TARGET njs" - NXT_DEFAULT_TARGET="$NXT_DEFAULT_TARGET njs" else NXT_HAVE_LIBEDIT=NO $echo " - building interactive shell is not possible" diff -r b38fe378d900 -r 61f2616e21c7 njs/njs_shell.c --- a/njs/njs_shell.c Mon Apr 01 19:11:39 2019 +0300 +++ b/njs/njs_shell.c Tue Apr 02 17:17:49 2019 +0300 @@ -17,7 +17,13 @@ #include #include -#include +#if (NXT_HAVE_EDITLINE) +#include +#elif (NXT_HAVE_EDIT_READLINE) +#include +#else +#include +#endif typedef struct { From xeioex at nginx.com Tue Apr 2 14:46:21 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Tue, 02 Apr 2019 14:46:21 +0000 Subject: [njs] Making __proto__ accessor descriptor of Object mutable. Message-ID: details: https://hg.nginx.org/njs/rev/8d9585e9cc8b branches: changeset: 864:8d9585e9cc8b user: Dmitry Volyntsev date: Tue Apr 02 17:45:38 2019 +0300 description: Making __proto__ accessor descriptor of Object mutable. diffstat: njs/njs_builtin.c | 2 +- njs/njs_math.c | 2 +- njs/njs_object.c | 73 +++++++++++++++++++++++++++++++++++++++++++---- njs/njs_object.h | 2 +- njs/test/njs_unit_test.c | 14 ++++++++- 5 files changed, 82 insertions(+), 11 deletions(-) diffs (167 lines): diff -r 61f2616e21c7 -r 8d9585e9cc8b njs/njs_builtin.c --- a/njs/njs_builtin.c Tue Apr 02 17:17:49 2019 +0300 +++ b/njs/njs_builtin.c Tue Apr 02 17:45:38 2019 +0300 @@ -414,7 +414,7 @@ njs_prototype_function(njs_vm_t *vm, njs * Object(), * Object.__proto__ -> Function_Prototype, * Object_Prototype.__proto__ -> null, - * the null value is handled by njs_object_prototype_get_proto(), + * the null value is handled by njs_object_prototype_proto(), * * Array(), * Array.__proto__ -> Function_Prototype, diff -r 61f2616e21c7 -r 8d9585e9cc8b njs/njs_math.c --- a/njs/njs_math.c Tue Apr 02 17:17:49 2019 +0300 +++ b/njs/njs_math.c Tue Apr 02 17:45:38 2019 +0300 @@ -819,7 +819,7 @@ static const njs_object_prop_t njs_math { .type = NJS_PROPERTY_HANDLER, .name = njs_string("__proto__"), - .value = njs_prop_handler(njs_object_prototype_get_proto), + .value = njs_prop_handler(njs_object_prototype_proto), }, { diff -r 61f2616e21c7 -r 8d9585e9cc8b njs/njs_object.c --- a/njs/njs_object.c Tue Apr 02 17:17:49 2019 +0300 +++ b/njs/njs_object.c Tue Apr 02 17:45:38 2019 +0300 @@ -1889,8 +1889,8 @@ njs_object_get_prototype_of(njs_vm_t *vm value = njs_arg(args, nargs, 1); if (njs_is_object(value)) { - njs_object_prototype_get_proto(vm, (njs_value_t *) value, NULL, - &vm->retval); + njs_object_prototype_proto(vm, (njs_value_t *) value, NULL, + &vm->retval); return NXT_OK; } @@ -2393,13 +2393,71 @@ const njs_object_init_t njs_object_cons }; +/* + * ES6, 9.1.2: [[SetPrototypeOf]]. + */ +static nxt_bool_t +njs_object_set_prototype_of(njs_vm_t *vm, njs_object_t *object, + const njs_value_t *value) +{ + const njs_object_t *proto; + + proto = njs_is_object(value) ? value->data.u.object->__proto__ + : NULL; + + if (nxt_slow_path(object->__proto__ == proto)) { + return 1; + } + + if (nxt_slow_path(proto == NULL)) { + object->__proto__ = NULL; + return 1; + } + + do { + if (proto == object) { + return 0; + } + + proto = proto->__proto__; + + } while (proto != NULL); + + object->__proto__ = value->data.u.object; + + return 1; +} + + njs_ret_t -njs_object_prototype_get_proto(njs_vm_t *vm, njs_value_t *value, +njs_object_prototype_proto(njs_vm_t *vm, njs_value_t *value, njs_value_t *setval, njs_value_t *retval) { - njs_object_t *proto; - - proto = value->data.u.object->__proto__; + nxt_bool_t ret; + njs_object_t *proto, *object; + + if (!njs_is_object(value)) { + *retval = *value; + return NJS_OK; + } + + object = value->data.u.object; + + if (setval != NULL) { + if (njs_is_object(setval) || njs_is_null(setval)) { + ret = njs_object_set_prototype_of(vm, object, setval); + if (nxt_slow_path(!ret)) { + njs_type_error(vm, "Cyclic __proto__ value"); + return NXT_ERROR; + } + } + + *retval = njs_value_undefined; + + return NJS_OK; + } + + proto = object->__proto__; if (nxt_fast_path(proto != NULL)) { retval->data.u.object = proto; @@ -2722,7 +2780,8 @@ static const njs_object_prop_t njs_obje { .type = NJS_PROPERTY_HANDLER, .name = njs_string("__proto__"), - .value = njs_prop_handler(njs_object_prototype_get_proto), + .value = njs_prop_handler(njs_object_prototype_proto), + .writable = 1, }, { diff -r 61f2616e21c7 -r 8d9585e9cc8b njs/njs_object.h --- a/njs/njs_object.h Tue Apr 02 17:17:49 2019 +0300 +++ b/njs/njs_object.h Tue Apr 02 17:45:38 2019 +0300 @@ -106,7 +106,7 @@ njs_ret_t njs_object_prototype_create(nj njs_value_t *setval, njs_value_t *retval); njs_value_t *njs_property_prototype_create(njs_vm_t *vm, nxt_lvlhsh_t *hash, njs_object_t *prototype); -njs_ret_t njs_object_prototype_get_proto(njs_vm_t *vm, njs_value_t *value, +njs_ret_t njs_object_prototype_proto(njs_vm_t *vm, njs_value_t *value, njs_value_t *setval, njs_value_t *retval); njs_value_t *njs_property_constructor_create(njs_vm_t *vm, nxt_lvlhsh_t *hash, njs_value_t *constructor); diff -r 61f2616e21c7 -r 8d9585e9cc8b njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Tue Apr 02 17:17:49 2019 +0300 +++ b/njs/test/njs_unit_test.c Tue Apr 02 17:45:38 2019 +0300 @@ -7507,6 +7507,12 @@ static njs_unit_test_t njs_test[] = { nxt_string("Object.prototype.__proto__ === null"), nxt_string("true") }, + { nxt_string("Object.prototype.__proto__ = {}"), + nxt_string("TypeError: Cyclic __proto__ value") }, + + { nxt_string("var o = {}; var o2 = Object.create(o); o.__proto__ = o2"), + nxt_string("TypeError: Cyclic __proto__ value") }, + { nxt_string("Object.prototype.__proto__.f()"), nxt_string("TypeError: cannot get property \"f\" of undefined") }, @@ -7529,7 +7535,13 @@ static njs_unit_test_t njs_test[] = nxt_string("true") }, { nxt_string("({}).__proto__ = 1"), - nxt_string("TypeError: Cannot assign to read-only property \"__proto__\" of object") }, + nxt_string("1") }, + + { nxt_string("({}).__proto__ = null"), + nxt_string("null") }, + + { nxt_string("({__proto__: []}) instanceof Array"), + nxt_string("true") }, { nxt_string("({}).__proto__.constructor === Object"), nxt_string("true") }, From xeioex at nginx.com Tue Apr 2 16:48:33 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Tue, 02 Apr 2019 16:48:33 +0000 Subject: [njs] Introduced njs_parser_variable_node(). Message-ID: details: https://hg.nginx.org/njs/rev/bbba5c9fcbf1 branches: changeset: 865:bbba5c9fcbf1 user: Dmitry Volyntsev date: Tue Apr 02 19:32:43 2019 +0300 description: Introduced njs_parser_variable_node(). diffstat: njs/njs_parser.c | 91 +++++++++++++++++++++++++------------------------------ 1 files changed, 41 insertions(+), 50 deletions(-) diffs (175 lines): diff -r 8d9585e9cc8b -r bbba5c9fcbf1 njs/njs_parser.c --- a/njs/njs_parser.c Tue Apr 02 17:45:38 2019 +0300 +++ b/njs/njs_parser.c Tue Apr 02 19:32:43 2019 +0300 @@ -491,6 +491,34 @@ njs_parser_block(njs_vm_t *vm, njs_parse } +static njs_parser_node_t * +njs_parser_variable_node(njs_vm_t *vm, njs_parser_t *parser, nxt_str_t *name, + uint32_t hash, njs_variable_type_t type) +{ + nxt_int_t ret; + njs_variable_t *var; + njs_parser_node_t *node; + + var = njs_variable_add(vm, parser->scope, name, hash, type); + if (nxt_slow_path(var == NULL)) { + return NULL; + } + + node = njs_parser_node_new(vm, parser, NJS_TOKEN_NAME); + if (nxt_slow_path(node == NULL)) { + return NULL; + } + + ret = njs_variable_reference(vm, parser->scope, node, name, hash, + NJS_DECLARATION); + if (nxt_slow_path(ret != NXT_OK)) { + return NULL; + } + + return node; +} + + static njs_token_t njs_parser_labelled_statement(njs_vm_t *vm, njs_parser_t *parser) { @@ -983,9 +1011,7 @@ njs_parser_return_statement(njs_vm_t *vm static njs_token_t njs_parser_var_statement(njs_vm_t *vm, njs_parser_t *parser) { - njs_ret_t ret; njs_token_t token; - njs_variable_t *var; njs_parser_node_t *left, *stmt, *name, *assign, *expr; parser->node = NULL; @@ -1007,21 +1033,14 @@ njs_parser_var_statement(njs_vm_t *vm, n return NJS_TOKEN_ILLEGAL; } - var = njs_parser_variable_add(vm, parser, NJS_VARIABLE_VAR); - if (nxt_slow_path(var == NULL)) { - return NJS_TOKEN_ERROR; - } - - name = njs_parser_node_new(vm, parser, NJS_TOKEN_NAME); + + name = njs_parser_variable_node(vm, parser, njs_parser_text(parser), + njs_parser_key_hash(parser), + NJS_VARIABLE_VAR); if (nxt_slow_path(name == NULL)) { return NJS_TOKEN_ERROR; } - ret = njs_parser_variable_reference(vm, parser, name, NJS_DECLARATION); - if (nxt_slow_path(ret != NXT_OK)) { - return NJS_TOKEN_ERROR; - } - token = njs_parser_token(vm, parser); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { return token; @@ -1435,9 +1454,7 @@ njs_parser_for_statement(njs_vm_t *vm, n static njs_token_t njs_parser_for_var_statement(njs_vm_t *vm, njs_parser_t *parser) { - njs_ret_t ret; njs_token_t token; - njs_variable_t *var; njs_parser_node_t *left, *stmt, *name, *assign, *expr; parser->node = NULL; @@ -1459,21 +1476,13 @@ njs_parser_for_var_statement(njs_vm_t *v return NJS_TOKEN_ILLEGAL; } - var = njs_parser_variable_add(vm, parser, NJS_VARIABLE_VAR); - if (nxt_slow_path(var == NULL)) { - return NJS_TOKEN_ERROR; - } - - name = njs_parser_node_new(vm, parser, NJS_TOKEN_NAME); + name = njs_parser_variable_node(vm, parser, njs_parser_text(parser), + njs_parser_key_hash(parser), + NJS_VARIABLE_VAR); if (nxt_slow_path(name == NULL)) { return NJS_TOKEN_ERROR; } - ret = njs_parser_variable_reference(vm, parser, name, NJS_DECLARATION); - if (nxt_slow_path(ret != NXT_OK)) { - return NJS_TOKEN_ERROR; - } - token = njs_parser_token(vm, parser); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { return token; @@ -1672,7 +1681,6 @@ njs_parser_try_statement(njs_vm_t *vm, n { njs_ret_t ret; njs_token_t token; - njs_variable_t *var; njs_parser_node_t *node, *try, *catch; token = njs_parser_try_block(vm, parser); @@ -1718,21 +1726,13 @@ njs_parser_try_statement(njs_vm_t *vm, n return NJS_TOKEN_ERROR; } - var = njs_parser_variable_add(vm, parser, NJS_VARIABLE_CATCH); - if (nxt_slow_path(var == NULL)) { - return NJS_TOKEN_ERROR; - } - - node = njs_parser_node_new(vm, parser, NJS_TOKEN_NAME); + node = njs_parser_variable_node(vm, parser, njs_parser_text(parser), + njs_parser_key_hash(parser), + NJS_VARIABLE_CATCH); if (nxt_slow_path(node == NULL)) { return NJS_TOKEN_ERROR; } - ret = njs_parser_variable_reference(vm, parser, node, NJS_DECLARATION); - if (nxt_slow_path(ret != NXT_OK)) { - return NJS_TOKEN_ERROR; - } - catch->left = node; token = njs_parser_token(vm, parser); @@ -1857,7 +1857,6 @@ njs_parser_import_statement(njs_vm_t *vm { njs_ret_t ret; njs_token_t token; - njs_variable_t *var; njs_parser_node_t *name, *import; if (parser->scope->type != NJS_SCOPE_GLOBAL @@ -1879,21 +1878,13 @@ njs_parser_import_statement(njs_vm_t *vm return NJS_TOKEN_ILLEGAL; } - var = njs_parser_variable_add(vm, parser, NJS_VARIABLE_VAR); - if (nxt_slow_path(var == NULL)) { - return NJS_TOKEN_ERROR; - } - - name = njs_parser_node_new(vm, parser, NJS_TOKEN_NAME); + name = njs_parser_variable_node(vm, parser, njs_parser_text(parser), + njs_parser_key_hash(parser), + NJS_VARIABLE_VAR); if (nxt_slow_path(name == NULL)) { return NJS_TOKEN_ERROR; } - ret = njs_parser_variable_reference(vm, parser, name, NJS_DECLARATION); - if (nxt_slow_path(ret != NXT_OK)) { - return NJS_TOKEN_ERROR; - } - token = njs_parser_token(vm, parser); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { return token; From eran.kornblau at kaltura.com Wed Apr 3 11:59:35 2019 From: eran.kornblau at kaltura.com (Eran Kornblau) Date: Wed, 3 Apr 2019 11:59:35 +0000 Subject: Forcing request body read into memory Message-ID: Hi all, Tried googling for this and didn't find an answer... Is it possible to force nginx to read the request body into memory (not temp file) via code? I tried request_body_in_single_buf, but it seems it only prevents the request body from being split between memory + file (probably need to update http://nginx.org/en/docs/dev/development_guide.html#http_request_body...) I guess I can accomplish this by setting client_max_body_size and client_body_buffer_size to the same value in nginx.conf, but don't know if there's a way to do it in code. Thanks! Eran -------------- next part -------------- An HTML attachment was scrubbed... URL: From pluknet at nginx.com Wed Apr 3 12:46:08 2019 From: pluknet at nginx.com (Sergey Kandaurov) Date: Wed, 03 Apr 2019 12:46:08 +0000 Subject: [nginx] OCSP stapling: open ssl_stapling_file in binary-mode. Message-ID: details: https://hg.nginx.org/nginx/rev/edf5cd6c56fa branches: changeset: 7485:edf5cd6c56fa user: Sergey Kandaurov date: Wed Apr 03 15:35:39 2019 +0300 description: OCSP stapling: open ssl_stapling_file in binary-mode. OCSP response uses the DER format and as such needs to be opened in binary-mode. This only has any effect under Win32. diffstat: src/event/ngx_event_openssl_stapling.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diffs (12 lines): diff -r 65074e13f171 -r edf5cd6c56fa src/event/ngx_event_openssl_stapling.c --- a/src/event/ngx_event_openssl_stapling.c Tue Mar 26 09:33:57 2019 +0300 +++ b/src/event/ngx_event_openssl_stapling.c Wed Apr 03 15:35:39 2019 +0300 @@ -227,7 +227,7 @@ ngx_ssl_stapling_file(ngx_conf_t *cf, ng return NGX_ERROR; } - bio = BIO_new_file((char *) file->data, "r"); + bio = BIO_new_file((char *) file->data, "rb"); if (bio == NULL) { ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "BIO_new_file(\"%s\") failed", file->data); From hellobhaskar at yahoo.co.in Wed Apr 3 12:52:22 2019 From: hellobhaskar at yahoo.co.in (Ramachandra Bhaskar) Date: Wed, 3 Apr 2019 12:52:22 +0000 (UTC) Subject: secondary auth caching References: <1949051676.16102920.1554295942975.ref@mail.yahoo.com> Message-ID: <1949051676.16102920.1554295942975@mail.yahoo.com> Hello We are having a legacy system which uses http basic authentication (username/password)Currently we are using nginx ingress controller to pass all the requests coming to webserver using kubernetes "auth-url" annotation to the legacy system and if successful we are forwarding to our application server. We want to do few things? we want a consolidated nginx server(/container) which can use do secondary authentication with legacy system and also cache successful requests.is that possible ? We want to reduce number of hits going to legacy system for authentication thats our end goal https://docs.nginx.com/nginx/admin-guide/security-controls/configuring-subrequest-authentication/#https://docs.nginx.com/nginx/admin-guide/content-cache/content-caching/ RegardsBhaskar -------------- next part -------------- An HTML attachment was scrubbed... URL: From mdounin at mdounin.ru Wed Apr 3 12:56:47 2019 From: mdounin at mdounin.ru (Maxim Dounin) Date: Wed, 3 Apr 2019 15:56:47 +0300 Subject: secondary auth caching In-Reply-To: <1949051676.16102920.1554295942975@mail.yahoo.com> References: <1949051676.16102920.1554295942975.ref@mail.yahoo.com> <1949051676.16102920.1554295942975@mail.yahoo.com> Message-ID: <20190403125647.GZ1877@mdounin.ru> Hello! On Wed, Apr 03, 2019 at 12:52:22PM +0000, Ramachandra Bhaskar via nginx-devel wrote: > Hello > We are having a legacy system which uses http basic authentication (username/password)Currently we are using nginx ingress controller to pass all the requests coming to webserver using kubernetes "auth-url" annotation to the legacy system and if successful we are forwarding to our application server. > We want to do few things? > we want a consolidated nginx server(/container) which can use do secondary authentication with legacy system and also cache successful requests.is that possible ? We want to reduce number of hits going to legacy system for authentication thats our end goal > https://docs.nginx.com/nginx/admin-guide/security-controls/configuring-subrequest-authentication/#https://docs.nginx.com/nginx/admin-guide/content-cache/content-caching/ > RegardsBhaskar This mailing list is about nginx development. For questions on how to configure nginx please use the nginx@ mailing list instead. See http://nginx.org/en/support.html for details. Thank you. -- Maxim Dounin http://mdounin.ru/ From xeioex at nginx.com Wed Apr 3 14:27:11 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Wed, 03 Apr 2019 14:27:11 +0000 Subject: [njs] Refactored njs_parser_object() and njs_parser_array(). Message-ID: details: https://hg.nginx.org/njs/rev/42da1521a827 branches: changeset: 866:42da1521a827 user: hongzhidao date: Wed Apr 03 11:19:14 2019 +0800 description: Refactored njs_parser_object() and njs_parser_array(). diffstat: njs/njs_parser_terminal.c | 210 ++++++++++++++++++++++----------------------- 1 files changed, 102 insertions(+), 108 deletions(-) diffs (316 lines): diff -r bbba5c9fcbf1 -r 42da1521a827 njs/njs_parser_terminal.c --- a/njs/njs_parser_terminal.c Tue Apr 02 19:32:43 2019 +0300 +++ b/njs/njs_parser_terminal.c Wed Apr 03 11:19:14 2019 +0800 @@ -17,8 +17,13 @@ static nxt_int_t njs_parser_builtin(njs_ uint32_t hash); static njs_token_t njs_parser_object(njs_vm_t *vm, njs_parser_t *parser, njs_parser_node_t *obj); +static nxt_int_t njs_parser_object_property(njs_vm_t *vm, njs_parser_t *parser, + njs_parser_node_t *parent, njs_parser_node_t *property, + njs_parser_node_t *value); static njs_token_t njs_parser_array(njs_vm_t *vm, njs_parser_t *parser, - njs_parser_node_t *obj); + njs_parser_node_t *array); +static nxt_int_t njs_parser_array_item(njs_vm_t *vm, njs_parser_t *parser, + njs_parser_node_t *array, njs_parser_node_t *value); static njs_token_t njs_parser_escape_string_create(njs_vm_t *vm, njs_parser_t *parser, njs_value_t *value); @@ -59,17 +64,7 @@ njs_parser_terminal(njs_vm_t *vm, njs_pa return NJS_TOKEN_ERROR; } - parser->node = node; - - token = njs_parser_object(vm, parser, node); - - if (parser->node != node) { - /* The object is not empty. */ - node->left = parser->node; - parser->node = node; - } - - return token; + return njs_parser_object(vm, parser, node); case NJS_TOKEN_OPEN_BRACKET: nxt_thread_log_debug("JS: ARRAY"); @@ -79,17 +74,7 @@ njs_parser_terminal(njs_vm_t *vm, njs_pa return NJS_TOKEN_ERROR; } - parser->node = node; - - token = njs_parser_array(vm, parser, node); - - if (parser->node != node) { - /* The array is not empty. */ - node->left = parser->node; - parser->node = node; - } - - return token; + return njs_parser_array(vm, parser, node); case NJS_TOKEN_DIVISION: node = njs_parser_node_new(vm, parser, NJS_TOKEN_REGEXP); @@ -445,12 +430,12 @@ static njs_token_t njs_parser_object(njs_vm_t *vm, njs_parser_t *parser, njs_parser_node_t *obj) { uint32_t hash, token_line; + nxt_int_t ret; nxt_str_t name; njs_token_t token; njs_lexer_t *lexer; - njs_parser_node_t *stmt, *assign, *object, *propref, *left, *expression; + njs_parser_node_t *object, *property, *expression; - left = NULL; lexer = parser->lexer; /* GCC and Clang complain about uninitialized hash. */ @@ -467,13 +452,14 @@ njs_parser_object(njs_vm_t *vm, njs_pars for ( ;; ) { token = njs_parser_property_token(vm, parser); + if (token == NJS_TOKEN_CLOSE_BRACE) { + break; + } + name.start = NULL; switch (token) { - case NJS_TOKEN_CLOSE_BRACE: - return njs_parser_token(vm, parser); - case NJS_TOKEN_NAME: name = *njs_parser_text(parser); @@ -497,13 +483,7 @@ njs_parser_object(njs_vm_t *vm, njs_pars return token; } - propref = njs_parser_node_new(vm, parser, NJS_TOKEN_PROPERTY); - if (nxt_slow_path(propref == NULL)) { - return NJS_TOKEN_ERROR; - } - - propref->left = object; - propref->right = parser->node; + property = parser->node; if (name.start != NULL && (token == NJS_TOKEN_COMMA || token == NJS_TOKEN_CLOSE_BRACE) @@ -530,47 +510,75 @@ njs_parser_object(njs_vm_t *vm, njs_pars expression = parser->node; } - assign = njs_parser_node_new(vm, parser, NJS_TOKEN_ASSIGNMENT); - if (nxt_slow_path(assign == NULL)) { + ret = njs_parser_object_property(vm, parser, obj, property, expression); + if (nxt_slow_path(ret != NXT_OK)) { return NJS_TOKEN_ERROR; } - assign->u.operation = njs_vmcode_move; - assign->left = propref; - assign->right = expression; - - stmt = njs_parser_node_new(vm, parser, NJS_TOKEN_STATEMENT); - if (nxt_slow_path(stmt == NULL)) { - return NJS_TOKEN_ERROR; - } - - stmt->left = left; - stmt->right = assign; - - parser->node = stmt; - - left = stmt; - if (token == NJS_TOKEN_CLOSE_BRACE) { - return njs_parser_token(vm, parser); + break; } if (nxt_slow_path(token != NJS_TOKEN_COMMA)) { return NJS_TOKEN_ILLEGAL; } } + + parser->node = obj; + + return njs_parser_token(vm, parser); +} + + +static nxt_int_t +njs_parser_object_property(njs_vm_t *vm, njs_parser_t *parser, + njs_parser_node_t *parent, njs_parser_node_t *property, + njs_parser_node_t *value) +{ + njs_parser_node_t *stmt, *assign, *object, *propref; + + object = njs_parser_node_new(vm, parser, NJS_TOKEN_OBJECT_VALUE); + if (nxt_slow_path(object == NULL)) { + return NJS_TOKEN_ERROR; + } + + object->u.object = parent; + + propref = njs_parser_node_new(vm, parser, NJS_TOKEN_PROPERTY); + if (nxt_slow_path(propref == NULL)) { + return NXT_ERROR; + } + + propref->left = object; + propref->right = property; + + assign = njs_parser_node_new(vm, parser, NJS_TOKEN_ASSIGNMENT); + if (nxt_slow_path(assign == NULL)) { + return NXT_ERROR; + } + + assign->u.operation = njs_vmcode_move; + assign->left = propref; + assign->right = value; + + stmt = njs_parser_node_new(vm, parser, NJS_TOKEN_STATEMENT); + if (nxt_slow_path(stmt == NULL)) { + return NXT_ERROR; + } + + stmt->right = assign; + stmt->left = parent->left; + parent->left = stmt; + + return NXT_OK; } static njs_token_t -njs_parser_array(njs_vm_t *vm, njs_parser_t *parser, njs_parser_node_t *obj) +njs_parser_array(njs_vm_t *vm, njs_parser_t *parser, njs_parser_node_t *array) { - nxt_uint_t index; - njs_token_t token; - njs_parser_node_t *stmt, *assign, *object, *propref, *left, *node; - - index = 0; - left = NULL; + nxt_int_t ret; + njs_token_t token; for ( ;; ) { token = njs_parser_token(vm, parser); @@ -583,63 +591,21 @@ njs_parser_array(njs_vm_t *vm, njs_parse } if (token == NJS_TOKEN_COMMA) { - obj->ctor = 1; - index++; + array->ctor = 1; + array->u.length++; continue; } - node = njs_parser_node_new(vm, parser, NJS_TOKEN_NUMBER); - if (nxt_slow_path(node == NULL)) { - return NJS_TOKEN_ERROR; - } - - node->u.value.data.u.number = index; - node->u.value.type = NJS_NUMBER; - node->u.value.data.truth = (index != 0); - index++; - - object = njs_parser_node_new(vm, parser, NJS_TOKEN_OBJECT_VALUE); - if (nxt_slow_path(object == NULL)) { - return NJS_TOKEN_ERROR; - } - - object->u.object = obj; - - propref = njs_parser_node_new(vm, parser, NJS_TOKEN_PROPERTY); - if (nxt_slow_path(propref == NULL)) { - return NJS_TOKEN_ERROR; - } - - propref->left = object; - propref->right = node; - token = njs_parser_assignment_expression(vm, parser, token); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { return token; } - assign = njs_parser_node_new(vm, parser, NJS_TOKEN_ASSIGNMENT); - if (nxt_slow_path(assign == NULL)) { + ret = njs_parser_array_item(vm, parser, array, parser->node); + if (nxt_slow_path(ret != NXT_OK)) { return NJS_TOKEN_ERROR; } - assign->u.operation = njs_vmcode_move; - assign->left = propref; - assign->right = parser->node; - - stmt = njs_parser_node_new(vm, parser, NJS_TOKEN_STATEMENT); - if (nxt_slow_path(stmt == NULL)) { - return NJS_TOKEN_ERROR; - } - - stmt->left = left; - stmt->right = assign; - - parser->node = stmt; - left = stmt; - - obj->ctor = 0; - if (token == NJS_TOKEN_CLOSE_BRACKET) { break; } @@ -649,12 +615,40 @@ njs_parser_array(njs_vm_t *vm, njs_parse } } - obj->u.length = index; + parser->node = array; return njs_parser_token(vm, parser); } +static nxt_int_t +njs_parser_array_item(njs_vm_t *vm, njs_parser_t *parser, + njs_parser_node_t *array, njs_parser_node_t *value) +{ + nxt_int_t ret; + njs_parser_node_t *number; + + number = njs_parser_node_new(vm, parser, NJS_TOKEN_NUMBER); + if (nxt_slow_path(number == NULL)) { + return NXT_ERROR; + } + + number->u.value.data.u.number = array->u.length; + number->u.value.type = NJS_NUMBER; + number->u.value.data.truth = (array->u.length != 0); + + ret = njs_parser_object_property(vm, parser, array, number, value); + if (nxt_slow_path(ret != NXT_OK)) { + return NXT_ERROR; + } + + array->ctor = 0; + array->u.length++; + + return NXT_OK; +} + + nxt_int_t njs_parser_string_create(njs_vm_t *vm, njs_value_t *value) { From xeioex at nginx.com Wed Apr 3 15:16:47 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Wed, 03 Apr 2019 15:16:47 +0000 Subject: [njs] Refactored njs_parser_call_expression(). Message-ID: details: https://hg.nginx.org/njs/rev/d1cedbc86bc2 branches: changeset: 867:d1cedbc86bc2 user: hongzhidao date: Wed Apr 03 11:27:05 2019 +0800 description: Refactored njs_parser_call_expression(). diffstat: njs/njs_parser.h | 2 + njs/njs_parser_expression.c | 164 ++++++++++++++++++------------------------- 2 files changed, 71 insertions(+), 95 deletions(-) diffs (247 lines): diff -r 42da1521a827 -r d1cedbc86bc2 njs/njs_parser.h --- a/njs/njs_parser.h Wed Apr 03 11:19:14 2019 +0800 +++ b/njs/njs_parser.h Wed Apr 03 11:27:05 2019 +0800 @@ -87,6 +87,8 @@ njs_token_t njs_parser_function_expressi njs_token_t njs_parser_module_lambda(njs_vm_t *vm, njs_parser_t *parser); njs_token_t njs_parser_terminal(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token); +njs_parser_node_t *njs_parser_argument(njs_vm_t *vm, njs_parser_t *parser, + njs_parser_node_t *expr, njs_index_t index); njs_token_t njs_parser_property_token(njs_vm_t *vm, njs_parser_t *parser); nxt_int_t njs_parser_string_create(njs_vm_t *vm, njs_value_t *value); njs_token_t njs_parser_lambda_statements(njs_vm_t *vm, njs_parser_t *parser, diff -r 42da1521a827 -r d1cedbc86bc2 njs/njs_parser_expression.c --- a/njs/njs_parser_expression.c Wed Apr 03 11:19:14 2019 +0800 +++ b/njs/njs_parser_expression.c Wed Apr 03 11:27:05 2019 +0800 @@ -62,6 +62,8 @@ static njs_token_t njs_parser_property_e njs_parser_t *parser, njs_token_t token); static njs_token_t njs_parser_property_brackets(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token); +static njs_token_t njs_parser_call(njs_vm_t *vm, njs_parser_t *parser, + njs_token_t token, uint8_t ctor); static njs_token_t njs_parser_arguments(njs_vm_t *vm, njs_parser_t *parser, njs_parser_node_t *parent); @@ -787,8 +789,6 @@ static njs_token_t njs_parser_call_expression(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token) { - njs_parser_node_t *func, *node; - if (token == NJS_TOKEN_NEW) { token = njs_parser_new_expression(vm, parser, token); @@ -806,66 +806,11 @@ njs_parser_call_expression(njs_vm_t *vm, return token; } - node = parser->node; - if (token != NJS_TOKEN_OPEN_PARENTHESIS) { return token; } - switch (node->token) { - - case NJS_TOKEN_NAME: - func = node; - func->token = NJS_TOKEN_FUNCTION_CALL; - func->scope = parser->scope; - - break; - - case NJS_TOKEN_PROPERTY: - func = njs_parser_node_new(vm, parser, NJS_TOKEN_METHOD_CALL); - if (nxt_slow_path(func == NULL)) { - return NJS_TOKEN_ERROR; - } - - func->left = node; - - break; - - default: - /* - * NJS_TOKEN_METHOD_CALL, - * NJS_TOKEN_FUNCTION_CALL, - * NJS_TOKEN_FUNCTION_EXPRESSION, - * NJS_TOKEN_OPEN_PARENTHESIS, - * NJS_TOKEN_OBJECT_CONSTRUCTOR, - * NJS_TOKEN_ARRAY_CONSTRUCTOR, - * NJS_TOKEN_BOOLEAN_CONSTRUCTOR, - * NJS_TOKEN_NUMBER_CONSTRUCTOR, - * NJS_TOKEN_STRING_CONSTRUCTOR, - * NJS_TOKEN_FUNCTION_CONSTRUCTOR, - * NJS_TOKEN_REGEXP_CONSTRUCTOR, - * NJS_TOKEN_EVAL. - */ - func = njs_parser_node_new(vm, parser, NJS_TOKEN_FUNCTION_CALL); - if (nxt_slow_path(func == NULL)) { - return NJS_TOKEN_ERROR; - } - - func->left = node; - - break; - } - - func->ctor = 0; - - token = njs_parser_arguments(vm, parser, func); - if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { - return token; - } - - parser->node = func; - - token = njs_parser_token(vm, parser); + token = njs_parser_call(vm, parser, token, 0); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { return token; } @@ -874,32 +819,11 @@ njs_parser_call_expression(njs_vm_t *vm, static njs_token_t -njs_parser_new_expression(njs_vm_t *vm, njs_parser_t *parser, - njs_token_t token) +njs_parser_call(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token, + uint8_t ctor) { njs_parser_node_t *func, *node; - token = njs_parser_token(vm, parser); - if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { - return token; - } - - if (token == NJS_TOKEN_NEW) { - token = njs_parser_new_expression(vm, parser, token); - - } else { - token = njs_parser_terminal(vm, parser, token); - if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { - return token; - } - - token = njs_parser_property_expression(vm, parser, token); - } - - if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { - return token; - } - node = parser->node; switch (node->token) { @@ -945,21 +869,54 @@ njs_parser_new_expression(njs_vm_t *vm, break; } - func->ctor = 1; + func->ctor = ctor; + + switch (token) { - if (token != NJS_TOKEN_OPEN_PARENTHESIS) { - parser->node = func; - return token; + case NJS_TOKEN_OPEN_PARENTHESIS: + token = njs_parser_arguments(vm, parser, func); + if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { + return token; + } + + break; + + default: + break; } - token = njs_parser_arguments(vm, parser, func); + parser->node = func; + + return token; +} + + +static njs_token_t +njs_parser_new_expression(njs_vm_t *vm, njs_parser_t *parser, + njs_token_t token) +{ + token = njs_parser_token(vm, parser); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { return token; } - parser->node = func; + if (token == NJS_TOKEN_NEW) { + token = njs_parser_new_expression(vm, parser, token); + + } else { + token = njs_parser_terminal(vm, parser, token); + if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { + return token; + } - return njs_parser_token(vm, parser); + token = njs_parser_property_expression(vm, parser, token); + } + + if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { + return token; + } + + return njs_parser_call(vm, parser, token, 1); } @@ -1058,24 +1015,41 @@ njs_parser_arguments(njs_vm_t *vm, njs_p return token; } - node = njs_parser_node_new(vm, parser, NJS_TOKEN_ARGUMENT); + node = njs_parser_argument(vm, parser, parser->node, index); if (nxt_slow_path(node == NULL)) { return NJS_TOKEN_ERROR; } - node->index = index; - index += sizeof(njs_value_t); - - node->left = parser->node; - parser->node->dest = node; parent->right = node; parent = node; + index += sizeof(njs_value_t); + } while (token == NJS_TOKEN_COMMA); if (nxt_slow_path(token != NJS_TOKEN_CLOSE_PARENTHESIS)) { return NJS_TOKEN_ILLEGAL; } - return token; + return njs_parser_token(vm, parser); } + + +njs_parser_node_t * +njs_parser_argument(njs_vm_t *vm, njs_parser_t *parser, + njs_parser_node_t *expr, njs_index_t index) +{ + njs_parser_node_t *node; + + node = njs_parser_node_new(vm, parser, NJS_TOKEN_ARGUMENT); + if (nxt_slow_path(node == NULL)) { + return NULL; + } + + node->index = index; + + node->left = expr; + expr->dest = node; + + return node; +} From xeioex at nginx.com Thu Apr 4 13:59:24 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Thu, 04 Apr 2019 13:59:24 +0000 Subject: [njs] Arguments object as a variable. Message-ID: details: https://hg.nginx.org/njs/rev/b137489312e1 branches: changeset: 868:b137489312e1 user: hongzhidao date: Tue Mar 26 00:42:39 2019 +0800 description: Arguments object as a variable. diffstat: njs/njs_function.c | 7 ----- njs/njs_function.h | 1 - njs/njs_generator.c | 63 ++++++++++++++-------------------------------- njs/njs_parser.h | 1 - njs/njs_parser_terminal.c | 42 ++++++++++++++++++++---------- njs/njs_variable.h | 1 + njs/njs_vm.c | 16 +++++++---- njs/njs_vm.h | 2 +- 8 files changed, 60 insertions(+), 73 deletions(-) diffs (303 lines): diff -r d1cedbc86bc2 -r b137489312e1 njs/njs_function.c --- a/njs/njs_function.c Wed Apr 03 11:27:05 2019 +0800 +++ b/njs/njs_function.c Tue Mar 26 00:42:39 2019 +0800 @@ -495,13 +495,6 @@ njs_function_lambda_call(njs_vm_t *vm, n vm->scopes[NJS_SCOPE_CLOSURE + n] = &closure->u.values; } - if (lambda->arguments_object) { - ret = njs_function_arguments_object_init(vm, &frame->native); - if (nxt_slow_path(ret != NXT_OK)) { - return NXT_ERROR; - } - } - if (lambda->rest_parameters) { ret = njs_function_rest_parameters_init(vm, &frame->native); if (nxt_slow_path(ret != NXT_OK)) { diff -r d1cedbc86bc2 -r b137489312e1 njs/njs_function.h --- a/njs/njs_function.h Wed Apr 03 11:27:05 2019 +0800 +++ b/njs/njs_function.h Tue Mar 26 00:42:39 2019 +0800 @@ -30,7 +30,6 @@ struct njs_function_lambda_s { /* Function internal block closures levels. */ uint8_t block_closures; /* 4 bits */ - uint8_t arguments_object; /* 1 bit */ uint8_t rest_parameters; /* 1 bit */ /* Initial values of local scope. */ diff -r d1cedbc86bc2 -r b137489312e1 njs/njs_generator.c --- a/njs/njs_generator.c Wed Apr 03 11:27:05 2019 +0800 +++ b/njs/njs_generator.c Tue Mar 26 00:42:39 2019 +0800 @@ -61,8 +61,6 @@ static nxt_int_t njs_generate_name(njs_v njs_parser_node_t *node); static nxt_int_t njs_generate_builtin_object(njs_vm_t *vm, njs_generator_t *generator, njs_parser_node_t *node); -static nxt_int_t njs_generate_arguments_object(njs_vm_t *vm, - njs_generator_t *generator, njs_parser_node_t *node); static nxt_int_t njs_generate_variable(njs_vm_t *vm, njs_generator_t *generator, njs_parser_node_t *node); static nxt_int_t njs_generate_var_statement(njs_vm_t *vm, @@ -140,7 +138,7 @@ static nxt_int_t njs_generate_function_d static nxt_int_t njs_generate_function_scope(njs_vm_t *vm, njs_function_lambda_t *lambda, njs_parser_node_t *node, const nxt_str_t *name); -static nxt_int_t njs_generate_argument_closures(njs_vm_t *vm, +static nxt_int_t njs_generate_lambda_variables(njs_vm_t *vm, njs_generator_t *generator, njs_parser_node_t *node); static nxt_int_t njs_generate_return_statement(njs_vm_t *vm, njs_generator_t *generator, njs_parser_node_t *node); @@ -429,6 +427,7 @@ njs_generator(njs_vm_t *vm, njs_generato return NXT_OK; case NJS_TOKEN_NAME: + case NJS_TOKEN_ARGUMENTS: return njs_generate_name(vm, generator, node); case NJS_TOKEN_GLOBAL_THIS: @@ -451,9 +450,6 @@ njs_generator(njs_vm_t *vm, njs_generato case NJS_TOKEN_CLEAR_TIMEOUT: return njs_generate_builtin_object(vm, generator, node); - case NJS_TOKEN_ARGUMENTS: - return njs_generate_arguments_object(vm, generator, node); - case NJS_TOKEN_FUNCTION: return njs_generate_function_declaration(vm, generator, node); @@ -586,25 +582,6 @@ njs_generate_builtin_object(njs_vm_t *vm static nxt_int_t -njs_generate_arguments_object(njs_vm_t *vm, njs_generator_t *generator, - njs_parser_node_t *node) -{ - njs_vmcode_arguments_t *gen; - - node->index = njs_generate_object_dest_index(vm, generator, node); - if (nxt_slow_path(node->index == NJS_INDEX_ERROR)) { - return NXT_ERROR; - } - - njs_generate_code(generator, njs_vmcode_arguments_t, gen, - njs_vmcode_arguments, 1, 1); - gen->retval = node->index; - - return NXT_OK; -} - - -static nxt_int_t njs_generate_variable(njs_vm_t *vm, njs_generator_t *generator, njs_parser_node_t *node) { @@ -2329,7 +2306,6 @@ njs_generate_function_scope(njs_vm_t *vm lambda->closure_size = size; lambda->nesting = node->scope->nesting; - lambda->arguments_object = node->scope->arguments_object; lambda->start = generator.code_start; lambda->local_size = generator.scope_size; @@ -2362,7 +2338,7 @@ njs_generate_scope(njs_vm_t *vm, njs_gen generator->code_start = p; generator->code_end = p; - ret = njs_generate_argument_closures(vm, generator, scope->top); + ret = njs_generate_lambda_variables(vm, generator, scope->top); if (nxt_slow_path(ret != NXT_OK)) { return NXT_ERROR; } @@ -2420,35 +2396,36 @@ njs_generate_scope(njs_vm_t *vm, njs_gen static nxt_int_t -njs_generate_argument_closures(njs_vm_t *vm, njs_generator_t *generator, +njs_generate_lambda_variables(njs_vm_t *vm, njs_generator_t *generator, njs_parser_node_t *node) { - nxt_uint_t n; - njs_index_t index; - njs_variable_t *var; - njs_vmcode_move_t *move; - nxt_lvlhsh_each_t lhe; - - n = node->scope->argument_closures; - - if (n == 0) { - return NXT_OK; - } + njs_index_t index; + njs_variable_t *var; + njs_vmcode_move_t *move; + nxt_lvlhsh_each_t lhe; + njs_vmcode_arguments_t *arguments; nxt_lvlhsh_each_init(&lhe, &njs_variables_hash_proto); - do { + for ( ;; ) { var = nxt_lvlhsh_each(&node->scope->variables, &lhe); + if (var == NULL) { + break; + } + if (var->argument != 0) { index = njs_scope_index((var->argument - 1), NJS_SCOPE_ARGUMENTS); njs_generate_code_move(generator, move, var->index, index); - - n--; } - } while (n != 0); + if (var->arguments_object) { + njs_generate_code(generator, njs_vmcode_arguments_t, arguments, + njs_vmcode_arguments, 1, 0); + arguments->dst = var->index; + } + } return NXT_OK; } diff -r d1cedbc86bc2 -r b137489312e1 njs/njs_parser.h --- a/njs/njs_parser.h Wed Apr 03 11:27:05 2019 +0800 +++ b/njs/njs_parser.h Tue Mar 26 00:42:39 2019 +0800 @@ -31,7 +31,6 @@ struct njs_parser_scope_s { njs_scope_t type:8; uint8_t nesting; /* 4 bits */ uint8_t argument_closures; - uint8_t arguments_object; uint8_t module; }; diff -r d1cedbc86bc2 -r b137489312e1 njs/njs_parser_terminal.c --- a/njs/njs_parser_terminal.c Wed Apr 03 11:27:05 2019 +0800 +++ b/njs/njs_parser_terminal.c Tue Mar 26 00:42:39 2019 +0800 @@ -185,6 +185,7 @@ njs_parser_reference(njs_vm_t *vm, njs_p { njs_ret_t ret; njs_value_t *ext; + njs_variable_t *var; njs_parser_node_t *node; njs_parser_scope_t *scope; @@ -239,20 +240,6 @@ njs_parser_reference(njs_vm_t *vm, njs_p break; - case NJS_TOKEN_ARGUMENTS: - nxt_thread_log_debug("JS: arguments"); - - if (parser->scope->type <= NJS_SCOPE_GLOBAL) { - njs_parser_syntax_error(vm, parser, "\"%V\" object " - "in global scope", name); - - return NULL; - } - - parser->scope->arguments_object = 1; - - break; - case NJS_TOKEN_OBJECT_CONSTRUCTOR: node->index = NJS_INDEX_OBJECT; break; @@ -342,6 +329,33 @@ njs_parser_reference(njs_vm_t *vm, njs_p break; + case NJS_TOKEN_ARGUMENTS: + nxt_thread_log_debug("JS: arguments"); + + if (parser->scope->type <= NJS_SCOPE_GLOBAL) { + njs_parser_syntax_error(vm, parser, "\"%V\" object " + "in global scope", name); + + return NULL; + } + + node->token_line = token_line; + + ret = njs_variable_reference(vm, parser->scope, node, name, hash, + NJS_REFERENCE); + if (nxt_slow_path(ret != NXT_OK)) { + return NULL; + } + + var = njs_variable_add(vm, parser->scope, name, hash, NJS_VARIABLE_VAR); + if (nxt_slow_path(var == NULL)) { + return NULL; + } + + var->arguments_object = 1; + + break; + case NJS_TOKEN_NAME: nxt_thread_log_debug("JS: %V", name); diff -r d1cedbc86bc2 -r b137489312e1 njs/njs_variable.h --- a/njs/njs_variable.h Wed Apr 03 11:27:05 2019 +0800 +++ b/njs/njs_variable.h Tue Mar 26 00:42:39 2019 +0800 @@ -23,6 +23,7 @@ typedef struct { njs_variable_type_t type:8; /* 3 bits */ uint8_t argument; + uint8_t arguments_object; njs_index_t index; njs_value_t value; diff -r d1cedbc86bc2 -r b137489312e1 njs/njs_vm.c --- a/njs/njs_vm.c Wed Apr 03 11:27:05 2019 +0800 +++ b/njs/njs_vm.c Tue Mar 26 00:42:39 2019 +0800 @@ -9,7 +9,6 @@ #include - struct njs_property_next_s { int32_t index; nxt_lvlhsh_each_t lhe; @@ -394,8 +393,10 @@ njs_vmcode_function(njs_vm_t *vm, njs_va njs_ret_t njs_vmcode_arguments(njs_vm_t *vm, njs_value_t *invld1, njs_value_t *invld2) { - njs_ret_t ret; - njs_frame_t *frame; + nxt_int_t ret; + njs_frame_t *frame; + njs_value_t *value; + njs_vmcode_arguments_t *code; frame = (njs_frame_t *) vm->active_frame; @@ -406,9 +407,12 @@ njs_vmcode_arguments(njs_vm_t *vm, njs_v } } - vm->retval.data.u.object = frame->native.arguments_object; - vm->retval.type = NJS_OBJECT; - vm->retval.data.truth = 1; + code = (njs_vmcode_arguments_t *) vm->current; + + value = njs_vmcode_operand(vm, code->dst); + value->data.u.object = frame->native.arguments_object; + value->type = NJS_OBJECT; + value->data.truth = 1; return sizeof(njs_vmcode_arguments_t); } diff -r d1cedbc86bc2 -r b137489312e1 njs/njs_vm.h --- a/njs/njs_vm.h Wed Apr 03 11:27:05 2019 +0800 +++ b/njs/njs_vm.h Tue Mar 26 00:42:39 2019 +0800 @@ -639,7 +639,7 @@ typedef struct { typedef struct { njs_vmcode_t code; - njs_index_t retval; + njs_index_t dst; } njs_vmcode_arguments_t; From pluknet at nginx.com Thu Apr 4 15:35:14 2019 From: pluknet at nginx.com (Sergey Kandaurov) Date: Thu, 04 Apr 2019 15:35:14 +0000 Subject: [nginx] Win32: skip building OpenSSL tests to conserve time and space. Message-ID: details: https://hg.nginx.org/nginx/rev/52d3600bc25e branches: changeset: 7486:52d3600bc25e user: Sergey Kandaurov date: Thu Apr 04 16:22:03 2019 +0300 description: Win32: skip building OpenSSL tests to conserve time and space. When building OpenSSL 1.1.1b, as used for win32 builds, with tests it takes about twice as long and near ~1GB of additional disk space. Using "no-tests" OpenSSL configuration option allows to skip them. Since such an option is supported since OpenSSL 1.1.1 only, it is residing here and not in configure. diffstat: misc/GNUmakefile | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diffs (12 lines): diff -r edf5cd6c56fa -r 52d3600bc25e misc/GNUmakefile --- a/misc/GNUmakefile Wed Apr 03 15:35:39 2019 +0300 +++ b/misc/GNUmakefile Thu Apr 04 16:22:03 2019 +0300 @@ -82,7 +82,7 @@ win32: --with-mail \ --with-stream \ --with-openssl=$(OBJS)/lib/$(OPENSSL) \ - --with-openssl-opt=no-asm \ + --with-openssl-opt="no-asm no-tests" \ --with-http_ssl_module \ --with-mail_ssl_module \ --with-stream_ssl_module From pluknet at nginx.com Thu Apr 4 15:35:16 2019 From: pluknet at nginx.com (Sergey Kandaurov) Date: Thu, 04 Apr 2019 15:35:16 +0000 Subject: [nginx] Win32: preserving binary compatibility with Windows XP - Vista. Message-ID: details: https://hg.nginx.org/nginx/rev/7da71a7b141a branches: changeset: 7487:7da71a7b141a user: Sergey Kandaurov date: Thu Apr 04 16:26:56 2019 +0300 description: Win32: preserving binary compatibility with Windows XP - Vista. OpenSSL 1.1.0 and above uses BCrypt if available (Windows 7 or higher). This results in an unusable binary on older Windows versions, when building with newer Windows SDK (such as 7.0A). Using CFLAGS to define _WIN32_WINNT allows to set a desired ABI and make sure the binary works with Windows XP. To not mix with other potential CFLAGS uses, it is set in GNUmakefile. diffstat: misc/GNUmakefile | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diffs (13 lines): diff -r 52d3600bc25e -r 7da71a7b141a misc/GNUmakefile --- a/misc/GNUmakefile Thu Apr 04 16:22:03 2019 +0300 +++ b/misc/GNUmakefile Thu Apr 04 16:26:56 2019 +0300 @@ -82,7 +82,8 @@ win32: --with-mail \ --with-stream \ --with-openssl=$(OBJS)/lib/$(OPENSSL) \ - --with-openssl-opt="no-asm no-tests" \ + --with-openssl-opt="no-asm no-tests \ + CFLAGS=-D_WIN32_WINNT=0x0501" \ --with-http_ssl_module \ --with-mail_ssl_module \ --with-stream_ssl_module From xoiss at yandex-team.ru Thu Apr 4 16:56:23 2019 From: xoiss at yandex-team.ru (=?utf-8?B?0JDQu9C10LrRgdCw0L3QtNGAINCQLiDQodGC0YDQtdC70LXRhg==?=) Date: Thu, 04 Apr 2019 19:56:23 +0300 Subject: [PATCH] Core: print "(null)" on NULL for "%s" in ngx_vslprintf Message-ID: <270701554396983@vla1-9d3c37294942.qloud-c.yandex.net> # HG changeset patch # User Alexander A. Strelets # Date 1554396620 -10800 # Thu Apr 04 19:50:20 2019 +0300 # Node ID cf212fc46cb7025b33dfb7313b5191eb09330446 # Parent 7da71a7b141abf417d334dfaca8a13f01c9fe3f5 Core: print "(null)" on NULL for "%s" in ngx_vslprintf When NULL is passes with arguments for "%s" format specifier to ngx_vslprintf (or other ngx_printf-like derivative), ngx_vslprintf really tries to access 0 address which triggers SIGSEGV, while conventional printf just literally prints "(null)" without an error. This is a reach source of hidden bugs in numerous calls to ngx_log_error, ngx_log_debug, etc. which are normally not called and not covered with tests. This case may be hit, for example, with ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno, "pread() \"%s\" failed", file->name.data); in nginx/src/os/unix/ngx_files.c, lines 40-46, in case file->name.data was left initially assigned with NULL (i.e. the user gets SIGSEGV instead of an [error]-record in the log). diff -r 7da71a7b141a -r cf212fc46cb7 src/core/ngx_string.c --- a/src/core/ngx_string.c Thu Apr 04 16:26:56 2019 +0300 +++ b/src/core/ngx_string.c Thu Apr 04 19:50:20 2019 +0300 @@ -16,6 +16,8 @@ static ngx_int_t ngx_decode_base64_internal(ngx_str_t *dst, ngx_str_t *src, const u_char *basis); +static const char ngx_string_literal_null[] = "(null)"; + void ngx_strlow(u_char *dst, u_char *src, size_t n) @@ -268,6 +270,13 @@ case 's': p = va_arg(args, u_char *); + if (p == NULL) { + p = (u_char *) ngx_string_literal_null; + if (slen != (size_t) -1) { + slen = ngx_min(slen, sizeof(ngx_string_literal_null) - 1); + } + } + if (slen == (size_t) -1) { while (*p && buf < last) { *buf++ = *p++; From mdounin at mdounin.ru Thu Apr 4 18:59:15 2019 From: mdounin at mdounin.ru (Maxim Dounin) Date: Thu, 04 Apr 2019 18:59:15 +0000 Subject: [nginx] Win32: defined pdb path. Message-ID: details: https://hg.nginx.org/nginx/rev/955c4b186354 branches: changeset: 7488:955c4b186354 user: Maxim Dounin date: Thu Apr 04 19:30:47 2019 +0300 description: Win32: defined pdb path. By default, MSVC uses vc.pdb in the current directory. With the "-Fd" switch it is directed to be in the objs directory instead. diffstat: auto/cc/msvc | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diffs (12 lines): diff --git a/auto/cc/msvc b/auto/cc/msvc --- a/auto/cc/msvc +++ b/auto/cc/msvc @@ -108,7 +108,7 @@ CORE_LIBS="$CORE_LIBS kernel32.lib user3 # msvc under Wine issues # C1902: Program database manager mismatch; please check your installation if [ -z "$NGX_WINE" ]; then - CFLAGS="$CFLAGS -Zi" + CFLAGS="$CFLAGS -Zi -Fd$NGX_OBJS/nginx.pdb" CORE_LINK="$CORE_LINK -debug" fi From mdounin at mdounin.ru Thu Apr 4 20:19:32 2019 From: mdounin at mdounin.ru (Maxim Dounin) Date: Thu, 4 Apr 2019 23:19:32 +0300 Subject: [PATCH] Core: print "(null)" on NULL for "%s" in ngx_vslprintf In-Reply-To: <270701554396983@vla1-9d3c37294942.qloud-c.yandex.net> References: <270701554396983@vla1-9d3c37294942.qloud-c.yandex.net> Message-ID: <20190404201932.GG1877@mdounin.ru> Hello! On Thu, Apr 04, 2019 at 07:56:23PM +0300, ????????? ?. ??????? wrote: > # HG changeset patch > # User Alexander A. Strelets > # Date 1554396620 -10800 > # Thu Apr 04 19:50:20 2019 +0300 > # Node ID cf212fc46cb7025b33dfb7313b5191eb09330446 > # Parent 7da71a7b141abf417d334dfaca8a13f01c9fe3f5 > Core: print "(null)" on NULL for "%s" in ngx_vslprintf > > When NULL is passes with arguments for "%s" format specifier to ngx_vslprintf (or other ngx_printf-like derivative), ngx_vslprintf really tries to access 0 address which triggers SIGSEGV, while conventional printf just literally prints "(null)" without an error. This is a reach source of hidden bugs in numerous calls to ngx_log_error, ngx_log_debug, etc. which are normally not called and not covered with tests. This case may be hit, for example, with ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno, "pread() \"%s\" failed", file->name.data); in nginx/src/os/unix/ngx_files.c, lines 40-46, in case file->name.data was left initially assigned with NULL (i.e. the user gets SIGSEGV instead of an [error]-record in the log). Thank you for your patch. Unfortunately, such approach does not help to identify such hidden bugs you've mentioned, but rather further hides them. As such, I would rather prefer to keep the code as is - intolerant to incorrect pointers. This makes finding bugs easier. If you think you know any bugs like this in nginx code - please report. Note well that "conventional printf" behaviour is undefined when NULL is used as an argument to %s. It may print "(null)", or erase your hard drive, or make demons fly out of your nose. You probably don't want to rely on "(null)" - unless you are actually trying to summon nasal demons. -- Maxim Dounin http://mdounin.ru/ From mdounin at mdounin.ru Thu Apr 4 21:29:23 2019 From: mdounin at mdounin.ru (Maxim Dounin) Date: Thu, 04 Apr 2019 21:29:23 +0000 Subject: [nginx] Win32: avoid using CFLAGS, just add define instead. Message-ID: details: https://hg.nginx.org/nginx/rev/af8abe105348 branches: changeset: 7489:af8abe105348 user: Maxim Dounin date: Thu Apr 04 22:56:41 2019 +0300 description: Win32: avoid using CFLAGS, just add define instead. With CFLAGS set as in 7da71a7b141a, OpenSSL compilation drops various non-important compiler options. To avoid this, a define is added instead - OpenSSL is smart enough to recognize -D... in Configure arguments. diffstat: misc/GNUmakefile | 3 +-- 1 files changed, 1 insertions(+), 2 deletions(-) diffs (13 lines): diff --git a/misc/GNUmakefile b/misc/GNUmakefile --- a/misc/GNUmakefile +++ b/misc/GNUmakefile @@ -82,8 +82,7 @@ win32: --with-mail \ --with-stream \ --with-openssl=$(OBJS)/lib/$(OPENSSL) \ - --with-openssl-opt="no-asm no-tests \ - CFLAGS=-D_WIN32_WINNT=0x0501" \ + --with-openssl-opt="no-asm no-tests -D_WIN32_WINNT=0x0501" \ --with-http_ssl_module \ --with-mail_ssl_module \ --with-stream_ssl_module From xeioex at nginx.com Fri Apr 5 14:16:57 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Fri, 05 Apr 2019 14:16:57 +0000 Subject: [njs] Adding const qualifier to njs_value_property(). Message-ID: details: https://hg.nginx.org/njs/rev/38262ccd9571 branches: changeset: 869:38262ccd9571 user: Dmitry Volyntsev date: Fri Apr 05 16:49:21 2019 +0300 description: Adding const qualifier to njs_value_property(). diffstat: njs/njs_object.h | 2 +- njs/njs_vm.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diffs (44 lines): diff -r b137489312e1 -r 38262ccd9571 njs/njs_object.h --- a/njs/njs_object.h Tue Mar 26 00:42:39 2019 +0800 +++ b/njs/njs_object.h Fri Apr 05 16:49:21 2019 +0300 @@ -88,7 +88,7 @@ njs_object_t *njs_object_value_alloc(njs nxt_uint_t type); njs_array_t *njs_object_enumerate(njs_vm_t *vm, const njs_value_t *value, njs_object_enum_t kind, nxt_bool_t all); -njs_ret_t njs_value_property(njs_vm_t *vm, njs_value_t *value, +njs_ret_t njs_value_property(njs_vm_t *vm, const njs_value_t *value, const njs_value_t *property, njs_value_t *retval); njs_object_prop_t *njs_object_property(njs_vm_t *vm, const njs_object_t *obj, nxt_lvlhsh_query_t *lhq); diff -r b137489312e1 -r 38262ccd9571 njs/njs_vm.c --- a/njs/njs_vm.c Tue Mar 26 00:42:39 2019 +0800 +++ b/njs/njs_vm.c Fri Apr 05 16:49:21 2019 +0300 @@ -2956,7 +2956,7 @@ njs_primitive_value(njs_vm_t *vm, njs_va * retval will contain undefined */ njs_ret_t -njs_value_property(njs_vm_t *vm, njs_value_t *value, +njs_value_property(njs_vm_t *vm, const njs_value_t *value, const njs_value_t *property, njs_value_t *retval) { njs_ret_t ret; @@ -2965,7 +2965,7 @@ njs_value_property(njs_vm_t *vm, njs_val njs_property_query_init(&pq, NJS_PROPERTY_QUERY_GET, 0); - ret = njs_property_query(vm, &pq, value, property); + ret = njs_property_query(vm, &pq, (njs_value_t *) value, property); switch (ret) { @@ -2994,8 +2994,8 @@ njs_value_property(njs_vm_t *vm, njs_val case NJS_PROPERTY_HANDLER: pq.scratch = *prop; prop = &pq.scratch; - ret = prop->value.data.u.prop_handler(vm, value, NULL, - &prop->value); + ret = prop->value.data.u.prop_handler(vm, (njs_value_t *) value, + NULL, &prop->value); if (nxt_slow_path(ret != NXT_OK)) { return ret; From xeioex at nginx.com Fri Apr 5 14:16:57 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Fri, 05 Apr 2019 14:16:57 +0000 Subject: [njs] Removed unnecessary njs_parser_var_expression(). Message-ID: details: https://hg.nginx.org/njs/rev/5224c5969233 branches: changeset: 870:5224c5969233 user: hongzhidao date: Fri Apr 05 20:59:15 2019 +0800 description: Removed unnecessary njs_parser_var_expression(). diffstat: njs/njs_parser.c | 4 +- njs/njs_parser.h | 2 - njs/njs_parser_expression.c | 53 --------------------------------------------- 3 files changed, 2 insertions(+), 57 deletions(-) diffs (96 lines): diff -r 38262ccd9571 -r 5224c5969233 njs/njs_parser.c --- a/njs/njs_parser.c Fri Apr 05 16:49:21 2019 +0300 +++ b/njs/njs_parser.c Fri Apr 05 20:59:15 2019 +0800 @@ -1055,7 +1055,7 @@ njs_parser_var_statement(njs_vm_t *vm, n return token; } - token = njs_parser_var_expression(vm, parser, token); + token = njs_parser_assignment_expression(vm, parser, token); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { return token; } @@ -1501,7 +1501,7 @@ njs_parser_for_var_statement(njs_vm_t *v return token; } - token = njs_parser_var_expression(vm, parser, token); + token = njs_parser_assignment_expression(vm, parser, token); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { return token; } diff -r 38262ccd9571 -r 5224c5969233 njs/njs_parser.h --- a/njs/njs_parser.h Fri Apr 05 16:49:21 2019 +0300 +++ b/njs/njs_parser.h Fri Apr 05 20:59:15 2019 +0800 @@ -78,8 +78,6 @@ nxt_int_t njs_parser(njs_vm_t *vm, njs_p njs_parser_t *prev); njs_token_t njs_parser_expression(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token); -njs_token_t njs_parser_var_expression(njs_vm_t *vm, njs_parser_t *parser, - njs_token_t token); njs_token_t njs_parser_assignment_expression(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token); njs_token_t njs_parser_function_expression(njs_vm_t *vm, njs_parser_t *parser); diff -r 38262ccd9571 -r 5224c5969233 njs/njs_parser_expression.c --- a/njs/njs_parser_expression.c Fri Apr 05 16:49:21 2019 +0300 +++ b/njs/njs_parser_expression.c Fri Apr 05 20:59:15 2019 +0800 @@ -210,59 +210,6 @@ njs_parser_expression(njs_vm_t *vm, njs_ } -njs_token_t -njs_parser_var_expression(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token) -{ - njs_parser_node_t *node; - njs_vmcode_operation_t operation; - - token = njs_parser_assignment_expression(vm, parser, token); - if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { - return token; - } - - for ( ;; ) { - switch (token) { - - case NJS_TOKEN_ASSIGNMENT: - nxt_thread_log_debug("JS: ="); - operation = njs_vmcode_move; - break; - - default: - return token; - } - - if (!njs_parser_is_lvalue(parser->node)) { - njs_parser_ref_error(vm, parser, - "Invalid left-hand side in assignment"); - return NJS_TOKEN_ILLEGAL; - } - - node = njs_parser_node_new(vm, parser, token); - if (nxt_slow_path(node == NULL)) { - return NJS_TOKEN_ERROR; - } - - node->u.operation = operation; - node->left = parser->node; - - token = njs_parser_token(vm, parser); - if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { - return token; - } - - token = njs_parser_var_expression(vm, parser, token); - if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { - return token; - } - - node->right = parser->node; - parser->node = node; - } -} - - static njs_token_t njs_parser_any_expression(njs_vm_t *vm, njs_parser_t *parser, const njs_parser_expression_t *expr, njs_token_t token) From xeioex at nginx.com Fri Apr 5 14:16:57 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Fri, 05 Apr 2019 14:16:57 +0000 Subject: [njs] Making njs_parser_var_statement() more generic. Message-ID: details: https://hg.nginx.org/njs/rev/f189d8b1c237 branches: changeset: 871:f189d8b1c237 user: hongzhidao date: Fri Apr 05 21:16:41 2019 +0800 description: Making njs_parser_var_statement() more generic. diffstat: njs/njs_parser.c | 111 +++++++----------------------------------------------- 1 files changed, 16 insertions(+), 95 deletions(-) diffs (176 lines): diff -r 5224c5969233 -r f189d8b1c237 njs/njs_parser.c --- a/njs/njs_parser.c Fri Apr 05 20:59:15 2019 +0800 +++ b/njs/njs_parser.c Fri Apr 05 21:16:41 2019 +0800 @@ -37,7 +37,8 @@ static njs_parser_node_t *njs_parser_ret njs_parser_t *parser, njs_parser_node_t *expr); static njs_token_t njs_parser_return_statement(njs_vm_t *vm, njs_parser_t *parser); -static njs_token_t njs_parser_var_statement(njs_vm_t *vm, njs_parser_t *parser); +static njs_token_t njs_parser_var_statement(njs_vm_t *vm, njs_parser_t *parser, + nxt_bool_t var_in); static njs_token_t njs_parser_if_statement(njs_vm_t *vm, njs_parser_t *parser); static njs_token_t njs_parser_switch_statement(njs_vm_t *vm, njs_parser_t *parser); @@ -46,9 +47,7 @@ static njs_token_t njs_parser_while_stat static njs_token_t njs_parser_do_while_statement(njs_vm_t *vm, njs_parser_t *parser); static njs_token_t njs_parser_for_statement(njs_vm_t *vm, njs_parser_t *parser); -static njs_token_t njs_parser_for_var_statement(njs_vm_t *vm, - njs_parser_t *parser); -static njs_token_t njs_parser_for_var_in_statement(njs_vm_t *vm, +static njs_token_t njs_parser_var_in_statement(njs_vm_t *vm, njs_parser_t *parser, njs_parser_node_t *name); static njs_token_t njs_parser_for_in_statement(njs_vm_t *vm, njs_parser_t *parser, nxt_str_t *name, njs_token_t token); @@ -358,7 +357,7 @@ njs_parser_statement(njs_vm_t *vm, njs_p switch (token) { case NJS_TOKEN_VAR: - token = njs_parser_var_statement(vm, parser); + token = njs_parser_var_statement(vm, parser, 0); break; case NJS_TOKEN_RETURN: @@ -1009,7 +1008,7 @@ njs_parser_return_statement(njs_vm_t *vm static njs_token_t -njs_parser_var_statement(njs_vm_t *vm, njs_parser_t *parser) +njs_parser_var_statement(njs_vm_t *vm, njs_parser_t *parser, nxt_bool_t var_in) { njs_token_t token; njs_parser_node_t *left, *stmt, *name, *assign, *expr; @@ -1026,15 +1025,17 @@ njs_parser_var_statement(njs_vm_t *vm, n if (token != NJS_TOKEN_NAME) { if (token == NJS_TOKEN_ARGUMENTS || token == NJS_TOKEN_EVAL) { njs_parser_syntax_error(vm, parser, "Identifier \"%V\" " - "is forbidden in var declaration", - njs_parser_text(parser)); + "is forbidden in %s declaration", + njs_parser_text(parser), + var_in ? "for-in var" : "var"); } return NJS_TOKEN_ILLEGAL; } - name = njs_parser_variable_node(vm, parser, njs_parser_text(parser), + name = njs_parser_variable_node(vm, parser, + njs_parser_text(parser), njs_parser_key_hash(parser), NJS_VARIABLE_VAR); if (nxt_slow_path(name == NULL)) { @@ -1046,6 +1047,10 @@ njs_parser_var_statement(njs_vm_t *vm, n return token; } + if (var_in && token == NJS_TOKEN_IN) { + return njs_parser_var_in_statement(vm, parser, name); + } + expr = NULL; if (token == NJS_TOKEN_ASSIGNMENT) { @@ -1353,7 +1358,7 @@ njs_parser_for_statement(njs_vm_t *vm, n if (token == NJS_TOKEN_VAR) { - token = njs_parser_for_var_statement(vm, parser); + token = njs_parser_var_statement(vm, parser, 1); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { return token; } @@ -1452,91 +1457,7 @@ njs_parser_for_statement(njs_vm_t *vm, n static njs_token_t -njs_parser_for_var_statement(njs_vm_t *vm, njs_parser_t *parser) -{ - njs_token_t token; - njs_parser_node_t *left, *stmt, *name, *assign, *expr; - - parser->node = NULL; - left = NULL; - - do { - token = njs_parser_token(vm, parser); - if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { - return token; - } - - if (token != NJS_TOKEN_NAME) { - if (token == NJS_TOKEN_ARGUMENTS || token == NJS_TOKEN_EVAL) { - njs_parser_syntax_error(vm, parser, "Identifier \"%V\" " - "is forbidden in for-in var declaration", - njs_parser_text(parser)); - } - - return NJS_TOKEN_ILLEGAL; - } - - name = njs_parser_variable_node(vm, parser, njs_parser_text(parser), - njs_parser_key_hash(parser), - NJS_VARIABLE_VAR); - if (nxt_slow_path(name == NULL)) { - return NJS_TOKEN_ERROR; - } - - token = njs_parser_token(vm, parser); - if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { - return token; - } - - if (token == NJS_TOKEN_IN) { - return njs_parser_for_var_in_statement(vm, parser, name); - } - - expr = NULL; - - if (token == NJS_TOKEN_ASSIGNMENT) { - - token = njs_parser_token(vm, parser); - if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { - return token; - } - - token = njs_parser_assignment_expression(vm, parser, token); - if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { - return token; - } - - expr = parser->node; - } - - assign = njs_parser_node_new(vm, parser, NJS_TOKEN_VAR); - if (nxt_slow_path(assign == NULL)) { - return NJS_TOKEN_ERROR; - } - - assign->u.operation = njs_vmcode_move; - assign->left = name; - assign->right = expr; - - stmt = njs_parser_node_new(vm, parser, NJS_TOKEN_STATEMENT); - if (nxt_slow_path(stmt == NULL)) { - return NJS_TOKEN_ERROR; - } - - stmt->left = left; - stmt->right = assign; - parser->node = stmt; - - left = stmt; - - } while (token == NJS_TOKEN_COMMA); - - return token; -} - - -static njs_token_t -njs_parser_for_var_in_statement(njs_vm_t *vm, njs_parser_t *parser, +njs_parser_var_in_statement(njs_vm_t *vm, njs_parser_t *parser, njs_parser_node_t *name) { njs_token_t token; From xeioex at nginx.com Sat Apr 6 17:51:06 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Sat, 06 Apr 2019 17:51:06 +0000 Subject: [njs] Fixed Function.prototype.bind(). Message-ID: details: https://hg.nginx.org/njs/rev/84cb61f23b7e branches: changeset: 873:84cb61f23b7e user: hongzhidao date: Sun Apr 07 00:09:09 2019 +0800 description: Fixed Function.prototype.bind(). Making a correct copy of a function. diffstat: njs/njs_function.c | 33 ++++++++++++++++++++++----------- njs/test/njs_unit_test.c | 10 ++++++++++ 2 files changed, 32 insertions(+), 11 deletions(-) diffs (96 lines): diff -r 7dba758fda64 -r 84cb61f23b7e njs/njs_function.c --- a/njs/njs_function.c Fri Apr 05 17:49:22 2019 +0300 +++ b/njs/njs_function.c Sun Apr 07 00:09:09 2019 +0800 @@ -8,6 +8,8 @@ #include +static njs_function_t *njs_function_copy(njs_vm_t *vm, + const njs_function_t *function); static njs_native_frame_t *njs_function_frame_alloc(njs_vm_t *vm, size_t size); static njs_ret_t njs_normalize_args(njs_vm_t *vm, njs_value_t *args, uint8_t *args_types, nxt_uint_t nargs); @@ -71,8 +73,6 @@ fail: njs_function_t * njs_function_value_copy(njs_vm_t *vm, njs_value_t *value) { - size_t size; - nxt_uint_t n, nesting; njs_function_t *function, *copy; function = value->data.u.function; @@ -81,6 +81,25 @@ njs_function_value_copy(njs_vm_t *vm, nj return function; } + copy = njs_function_copy(vm, function); + if (nxt_slow_path(copy == NULL)) { + njs_memory_error(vm); + return NULL; + } + + value->data.u.function = copy; + + return copy; +} + + +static njs_function_t * +njs_function_copy(njs_vm_t *vm, const njs_function_t *function) +{ + size_t size; + nxt_uint_t n, nesting; + njs_function_t *copy; + nesting = (function->native) ? 0 : function->u.lambda->nesting; size = sizeof(njs_function_t) + nesting * sizeof(njs_closure_t *); @@ -91,8 +110,6 @@ njs_function_value_copy(njs_vm_t *vm, nj return NULL; } - value->data.u.function = copy; - *copy = *function; copy->object.__proto__ = &vm->prototypes[NJS_PROTOTYPE_FUNCTION].object; copy->object.shared = 0; @@ -1050,18 +1067,12 @@ njs_function_prototype_bind(njs_vm_t *vm return NXT_ERROR; } - function = nxt_mp_alloc(vm->mem_pool, sizeof(njs_function_t)); + function = njs_function_copy(vm, args[0].data.u.function); if (nxt_slow_path(function == NULL)) { njs_memory_error(vm); return NXT_ERROR; } - *function = *args[0].data.u.function; - - function->object.__proto__ = &vm->prototypes[NJS_PROTOTYPE_FUNCTION].object; - function->object.shared = 0; - function->object.extensible = 1; - if (nargs == 1) { args = (njs_value_t *) &njs_value_undefined; diff -r 7dba758fda64 -r 84cb61f23b7e njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Fri Apr 05 17:49:22 2019 +0300 +++ b/njs/test/njs_unit_test.c Sun Apr 07 00:09:09 2019 +0800 @@ -6356,6 +6356,16 @@ static njs_unit_test_t njs_test[] = "var b = f.bind('1', '2', '3'); b.apply()"), nxt_string("123") }, + { nxt_string("function f() { var a; return (function() { a = 1; return a; }).bind()() } f()"), + nxt_string("1") }, + + { nxt_string("function f() { var a; function baz() { a = 1; return a; } return baz.bind()(); } f()"), + nxt_string("1") }, + + { nxt_string("function f(a, b) { return a + b }" + "f(3,4) === f.bind()(3,4)"), + nxt_string("true") }, + { nxt_string("var obj = {prop:'abc'}; " "var func = function(x) { " " return this === obj && x === 1 && arguments[0] === 1 " From eran.kornblau at kaltura.com Mon Apr 8 12:16:00 2019 From: eran.kornblau at kaltura.com (Eran Kornblau) Date: Mon, 8 Apr 2019 12:16:00 +0000 Subject: Issuing an HTTP request from a stream module Message-ID: Hi all, I would like to issue HTTP requests from an nginx stream module. In my understanding, I need to use ngx_event_connect_peer to connect, and implement my own write/read event handlers in order to build the request/parse the response. Is there some other solution that takes advantage of all the code that already exists in nginx for doing that? Also, does anyone happen to have some code that does something similar? Thank you! Eran -------------- next part -------------- An HTML attachment was scrubbed... URL: From arut at nginx.com Mon Apr 8 14:22:53 2019 From: arut at nginx.com (Roman Arutyunyan) Date: Mon, 8 Apr 2019 17:22:53 +0300 Subject: Issuing an HTTP request from a stream module In-Reply-To: References: Message-ID: <20190408142253.GA20152@Romans-MacBook-Air.local> Hi Eran, On Mon, Apr 08, 2019 at 12:16:00PM +0000, Eran Kornblau wrote: > Hi all, > > I would like to issue HTTP requests from an nginx stream module. > In my understanding, I need to use ngx_event_connect_peer to connect, and implement my own write/read event handlers > in order to build the request/parse the response. Yes. > Is there some other solution that takes advantage of all the code that already exists in nginx for doing that? > Also, does anyone happen to have some code that does something similar? In nginx source there are at least 2 examples of how to write an HTTP client: - OCSP stapling (src/event/ngx_event_openssl_stapling.c) - mail_auth module (src/mail/ngx_mail_auth_http_module.c) Also, the HTTP proxy module does this as well, but the entire module is much more complicated. -- Roman Arutyunyan From careygister at outlook.com Mon Apr 8 16:32:35 2019 From: careygister at outlook.com (Carey Gister) Date: Mon, 8 Apr 2019 16:32:35 +0000 Subject: HTTP Data Buffering-- Look-a-Head Message-ID: Hi, I have an interesting requirement. I am reading large files (on the order of 1 GB+) for connected clients. The clients may view part of the data and then cancel it, so I don't want to issue a request for an return the entire document. What I am interested in doing is fetching part pf the document, say 6 MB, and returning it. Then, I want to pre-fetch another 6 MB slice and hold it until/if the client requests it. If the client requests it, I want to return it and pre-fetch another slice. The slice module reads the entire document and returns it in slices. Unfortunately, this means I'm reading far more of the document than most clients will read. Is there existing code that solves this problem, or something close to it? It seems to me that in order to implement this solution I have to know how fast data is being consumed so I can know if I need to pre-fetch another slice. If there isn't an existing solution, what is the best way to know how fast data is being consumed? Thank you in advance, Carey Gister 415-310-5304 -------------- next part -------------- An HTML attachment was scrubbed... URL: From mdounin at mdounin.ru Tue Apr 9 13:03:43 2019 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 09 Apr 2019 13:03:43 +0000 Subject: [nginx] nginx-1.15.11-RELEASE Message-ID: details: https://hg.nginx.org/nginx/rev/5155d0296a5e branches: changeset: 7490:5155d0296a5e user: Maxim Dounin date: Tue Apr 09 16:00:30 2019 +0300 description: nginx-1.15.11-RELEASE diffstat: docs/xml/nginx/changes.xml | 14 ++++++++++++++ 1 files changed, 14 insertions(+), 0 deletions(-) diffs (24 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,20 @@ + + + + +? ????????? ssl_stapling_file ?? Windows. + + +in the "ssl_stapling_file" directive on Windows. + + + + + + From mdounin at mdounin.ru Tue Apr 9 13:03:44 2019 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 09 Apr 2019 13:03:44 +0000 Subject: [nginx] release-1.15.11 tag Message-ID: details: https://hg.nginx.org/nginx/rev/a6e23e343081 branches: changeset: 7491:a6e23e343081 user: Maxim Dounin date: Tue Apr 09 16:00:30 2019 +0300 description: release-1.15.11 tag diffstat: .hgtags | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diffs (8 lines): diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -436,3 +436,4 @@ 051a039ce1c7e09144de4a4846669ec7116cecea ee551e3f6dba336c0d875e266d7d55385f379b42 release-1.15.8 d2fd76709909767fc727a5b4affcf1dc9ca488a7 release-1.15.9 75f5c7f628411c79c7044102049f7ab4f7a246e7 release-1.15.10 +5155d0296a5ef9841f035920527ffdb771076b44 release-1.15.11 From efish at yotpo.com Tue Apr 9 14:09:28 2019 From: efish at yotpo.com (Eli Fish) Date: Tue, 9 Apr 2019 17:09:28 +0300 Subject: redirect from api.example.com/service/{domain} to other servers Message-ID: We have nginx server that redirect service requests by server_name using proxy_pass to upstream: nginx conf: server { server_name requestsproxy-rest.us.example.com; .... location / { ..... proxy_pass http://Requestsproxy-Rest; and the upstream file: upstream Requestsproxy-Rest { least_conn; server 10.1.1.1:29257 max_fails=4 fail_timeout=1s weight=1; server 10.1.1.2:21591 max_fails=4 fail_timeout=1s weight=1; } We want to create nginx rewrite rule that will be able to be accessed via " api.example.com/service/{domain}" and the nginx will forward/redirect the request to different address by the {service} to the nginx. for example: api.example.com/service/{requestsproxy-rest} --> {requestsproxy-rest}.us.example.com how do you think we can manage it via nginx configurations? I try something like: > location /{(?:[a-zA-Z0-9][a-zA-Z0-9]+$)} { > rewrite (.*) $1.example.com; Thanks in advanced. -- [image: photo] Eli Fish Devops Engineer m: +(972) 50-5781700 e: efish at yotpo.com| Check out the Yotpo blog! -------------- next part -------------- An HTML attachment was scrubbed... URL: From mdounin at mdounin.ru Tue Apr 9 14:23:07 2019 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 9 Apr 2019 17:23:07 +0300 Subject: redirect from api.example.com/service/{domain} to other servers In-Reply-To: References: Message-ID: <20190409142306.GU1877@mdounin.ru> Hello! On Tue, Apr 09, 2019 at 05:09:28PM +0300, Eli Fish wrote: > We have nginx server that redirect service requests by server_name using > proxy_pass to upstream: [...] This is a mailing list dedicated to nginx development. For question on how to configure nginx, please use nginx@ mailing list instead, see http://nginx.org/en/support.html for details. Thank you. -- Maxim Dounin http://mdounin.ru/ From pluknet at nginx.com Wed Apr 10 10:35:13 2019 From: pluknet at nginx.com (Sergey Kandaurov) Date: Wed, 10 Apr 2019 10:35:13 +0000 Subject: [njs] Fixed using %*s format in nxt_printf(). Message-ID: details: https://hg.nginx.org/njs/rev/d92dc72dd58d branches: changeset: 874:d92dc72dd58d user: Sergey Kandaurov date: Tue Apr 09 15:00:27 2019 +0300 description: Fixed using %*s format in nxt_printf(). diffstat: njs/njs_disassembler.c | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diffs (29 lines): diff -r 84cb61f23b7e -r d92dc72dd58d njs/njs_disassembler.c --- a/njs/njs_disassembler.c Sun Apr 07 00:09:09 2019 +0800 +++ b/njs/njs_disassembler.c Tue Apr 09 15:00:27 2019 +0300 @@ -420,7 +420,7 @@ njs_disassemble(u_char *start, u_char *e code3 = (njs_vmcode_3addr_t *) p; nxt_printf("%05uz %*s %04Xz %04Xz %04Xz\n", - p - start, (int) name->length, name->start, + p - start, name->length, name->start, (size_t) code3->dst, (size_t) code3->src1, (size_t) code3->src2); @@ -428,14 +428,14 @@ njs_disassemble(u_char *start, u_char *e code2 = (njs_vmcode_2addr_t *) p; nxt_printf("%05uz %*s %04Xz %04Xz\n", - p - start, (int) name->length, name->start, + p - start, name->length, name->start, (size_t) code2->dst, (size_t) code2->src); } else if (code_name->size == sizeof(njs_vmcode_1addr_t)) { code1 = (njs_vmcode_1addr_t *) p; nxt_printf("%05uz %*s %04Xz\n", - p - start, (int) name->length, name->start, + p - start, name->length, name->start, (size_t) code1->index); } From benishay at mellanox.com Wed Apr 10 11:45:52 2019 From: benishay at mellanox.com (ben ben ishay) Date: Wed, 10 Apr 2019 14:45:52 +0300 Subject: [PATCH] Add support for using sendfile when openssl support ktls Message-ID: <87938decdb98bf4a06ed.1554896752@gen-l-vrt-211> # HG changeset patch # User ben ben ishay # Date 1554896607 -10800 # Wed Apr 10 14:43:27 2019 +0300 # Node ID 87938decdb98bf4a06ed18002a15156a5e8fbd67 # Parent 65074e13f1716e09c28d730586babad7930b7a98 Add support for using sendfile when openssl support ktls when we need to transfer data between file and socket we prefer to use sendfile instead of write because we save the copy to a buffer. the use of sendfile is possible in openssl only if it support ktls(the master of openssl support ktls) otherwise there is a copy of the data to userspace for encryption in any case (this paper explain this https://netdevconf.org/1.2/papers/ktls.pdf ). the patch change the flow when the request is to send data over ssl and also the nginx use openssl that support ktls, the new flow using the sendfile function that tcp use for send data (ngx_linux_sendfile_chain). the performence with this patch applied was check with apib benchmark(https://github.com/apigee/apib), one machine run nginx and the other machine that connect back to back to the first one run apib with this comand: ./apib -c -d 30 https:///. the file size was 100K. the result display in this table , each value represnt average throughput in GBps of 10 runs. num of connection | regular nginx | new nginx 1 5 5.2 2 7.5 8.5 3 7.7 9 this result prove that this patch increase nginx performance and thus is useful. diff -r 65074e13f171 -r 87938decdb98 auto/feature --- a/auto/feature Tue Mar 26 09:33:57 2019 +0300 +++ b/auto/feature Wed Apr 10 14:43:27 2019 +0300 @@ -41,6 +41,10 @@ ngx_test="$CC $CC_TEST_FLAGS $CC_AUX_FLAGS $ngx_feature_inc_path \ -o $NGX_AUTOTEST $NGX_AUTOTEST.c $NGX_TEST_LD_OPT $ngx_feature_libs" +if [ "$ngx_feature_name" == "NGX_OPENSSL_KTLS" ];then + ngx_test="$CC $CC_TEST_FLAGS $CC_AUX_FLAGS $ngx_feature_inc_path -I$OPENSSL/include \ + -o $NGX_AUTOTEST $NGX_AUTOTEST.c $NGX_TEST_LD_OPT $ngx_feature_libs" +fi ngx_feature_inc_path= diff -r 65074e13f171 -r 87938decdb98 auto/lib/openssl/conf --- a/auto/lib/openssl/conf Tue Mar 26 09:33:57 2019 +0300 +++ b/auto/lib/openssl/conf Wed Apr 10 14:43:27 2019 +0300 @@ -140,3 +140,12 @@ fi fi +ngx_feature="OpenSSL library with KTLS" +ngx_feature_name="NGX_OPENSSL_KTLS" +ngx_feature_run=no +ngx_feature_incs="#include \"openssl/bio.h\" " +ngx_feature_path= +ngx_feature_libs="-lssl -lcrypto $NGX_LIBDL $NGX_LIBPTHREAD" +ngx_feature_test="BIO_get_ktls_send(NULL)" +. auto/feature + diff -r 65074e13f171 -r 87938decdb98 src/event/ngx_event_openssl.c --- a/src/event/ngx_event_openssl.c Tue Mar 26 09:33:57 2019 +0300 +++ b/src/event/ngx_event_openssl.c Wed Apr 10 14:43:27 2019 +0300 @@ -1528,6 +1528,9 @@ #endif sc->connection = SSL_new(ssl->ctx); +#if (NGX_OPENSSL_KTLS) + sc->ktls = 0; +#endif if (sc->connection == NULL) { ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "SSL_new() failed"); @@ -1639,6 +1642,12 @@ c->recv_chain = ngx_ssl_recv_chain; c->send_chain = ngx_ssl_send_chain; +#if (NGX_OPENSSL_KTLS) + if(BIO_get_ktls_send(SSL_get_wbio(c->ssl->connection))){ + c->ssl->ktls = 1; + c->send_chain = ngx_linux_sendfile_chain; + } +#endif #ifndef SSL_OP_NO_RENEGOTIATION #if OPENSSL_VERSION_NUMBER < 0x10100000L #ifdef SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS diff -r 65074e13f171 -r 87938decdb98 src/event/ngx_event_openssl.h --- a/src/event/ngx_event_openssl.h Tue Mar 26 09:33:57 2019 +0300 +++ b/src/event/ngx_event_openssl.h Wed Apr 10 14:43:27 2019 +0300 @@ -99,6 +99,9 @@ unsigned in_early:1; unsigned early_preread:1; unsigned write_blocked:1; +#if (NGX_OPENSSL_KTLS) + unsigned ktls:1; +#endif }; diff -r 65074e13f171 -r 87938decdb98 src/http/ngx_http_request.c --- a/src/http/ngx_http_request.c Tue Mar 26 09:33:57 2019 +0300 +++ b/src/http/ngx_http_request.c Wed Apr 10 14:43:27 2019 +0300 @@ -604,9 +604,15 @@ } #if (NGX_HTTP_SSL) - if (c->ssl) { +#ifndef NGX_OPENSSL_KTLS + if (c->ssl){ r->main_filter_need_in_memory = 1; } +#else + if(!c->ssl->ktls && c->ssl){ + r->main_filter_need_in_memory = 1; + } +#endif #endif r->main = r; From xeioex at nginx.com Wed Apr 10 14:28:17 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Wed, 10 Apr 2019 14:28:17 +0000 Subject: [njs] Fixed njs_function_copy(). Message-ID: details: https://hg.nginx.org/njs/rev/0781f269a0e2 branches: changeset: 875:0781f269a0e2 user: Dmitry Volyntsev date: Sun Apr 07 13:38:04 2019 +0800 description: Fixed njs_function_copy(). diffstat: njs/njs_function.c | 14 ++++++++++---- njs/test/njs_unit_test.c | 6 ++++++ 2 files changed, 16 insertions(+), 4 deletions(-) diffs (72 lines): diff -r d92dc72dd58d -r 0781f269a0e2 njs/njs_function.c --- a/njs/njs_function.c Tue Apr 09 15:00:27 2019 +0300 +++ b/njs/njs_function.c Sun Apr 07 13:38:04 2019 +0800 @@ -15,6 +15,11 @@ static njs_ret_t njs_normalize_args(njs_ uint8_t *args_types, nxt_uint_t nargs); +#define njs_function_closures(vm, function) \ + (njs_closure_t **) ((function->closure) ? function->closures \ + : vm->active_frame->closures) + + njs_function_t * njs_function_alloc(njs_vm_t *vm, njs_function_lambda_t *lambda, njs_closure_t *closures[], nxt_bool_t shared) @@ -98,6 +103,7 @@ njs_function_copy(njs_vm_t *vm, const nj { size_t size; nxt_uint_t n, nesting; + njs_closure_t **closures; njs_function_t *copy; nesting = (function->native) ? 0 : function->u.lambda->nesting; @@ -106,7 +112,6 @@ njs_function_copy(njs_vm_t *vm, const nj copy = nxt_mp_alloc(vm->mem_pool, size); if (nxt_slow_path(copy == NULL)) { - njs_memory_error(vm); return NULL; } @@ -120,11 +125,13 @@ njs_function_copy(njs_vm_t *vm, const nj copy->closure = 1; + closures = njs_function_closures(vm, function); + n = 0; do { /* GC: retain closure. */ - copy->closures[n] = vm->active_frame->closures[n]; + copy->closures[n] = closures[n]; n++; } while (n < nesting); @@ -470,8 +477,7 @@ njs_function_lambda_call(njs_vm_t *vm, n nesting = lambda->nesting; if (nesting != 0) { - closures = (function->closure) ? function->closures - : vm->active_frame->closures; + closures = njs_function_closures(vm, function); do { closure = *closures++; diff -r d92dc72dd58d -r 0781f269a0e2 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Tue Apr 09 15:00:27 2019 +0300 +++ b/njs/test/njs_unit_test.c Sun Apr 07 13:38:04 2019 +0800 @@ -6362,6 +6362,12 @@ static njs_unit_test_t njs_test[] = { nxt_string("function f() { var a; function baz() { a = 1; return a; } return baz.bind()(); } f()"), nxt_string("1") }, + { nxt_string("(function(){ var a = 1; return (function() { return a; })})().bind()()"), + nxt_string("1") }, + + { nxt_string("function f() { var a = 1; function baz() { return a; } return baz; } f().bind()()"), + nxt_string("1") }, + { nxt_string("function f(a, b) { return a + b }" "f(3,4) === f.bind()(3,4)"), nxt_string("true") }, From xeioex at nginx.com Wed Apr 10 14:46:20 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Wed, 10 Apr 2019 14:46:20 +0000 Subject: [njs] Making njs_function_closures() inline function. Message-ID: details: https://hg.nginx.org/njs/rev/dd44fdfef2de branches: changeset: 876:dd44fdfef2de user: Dmitry Volyntsev date: Wed Apr 10 17:46:14 2019 +0300 description: Making njs_function_closures() inline function. diffstat: njs/njs_function.c | 17 ++++++++++------- 1 files changed, 10 insertions(+), 7 deletions(-) diffs (40 lines): diff -r 0781f269a0e2 -r dd44fdfef2de njs/njs_function.c --- a/njs/njs_function.c Sun Apr 07 13:38:04 2019 +0800 +++ b/njs/njs_function.c Wed Apr 10 17:46:14 2019 +0300 @@ -9,17 +9,12 @@ static njs_function_t *njs_function_copy(njs_vm_t *vm, - const njs_function_t *function); + njs_function_t *function); static njs_native_frame_t *njs_function_frame_alloc(njs_vm_t *vm, size_t size); static njs_ret_t njs_normalize_args(njs_vm_t *vm, njs_value_t *args, uint8_t *args_types, nxt_uint_t nargs); -#define njs_function_closures(vm, function) \ - (njs_closure_t **) ((function->closure) ? function->closures \ - : vm->active_frame->closures) - - njs_function_t * njs_function_alloc(njs_vm_t *vm, njs_function_lambda_t *lambda, njs_closure_t *closures[], nxt_bool_t shared) @@ -98,8 +93,16 @@ njs_function_value_copy(njs_vm_t *vm, nj } +nxt_inline njs_closure_t ** +njs_function_closures(njs_vm_t *vm, njs_function_t *function) +{ + return (function->closure) ? function->closures + : vm->active_frame->closures; +} + + static njs_function_t * -njs_function_copy(njs_vm_t *vm, const njs_function_t *function) +njs_function_copy(njs_vm_t *vm, njs_function_t *function) { size_t size; nxt_uint_t n, nesting; From mdounin at mdounin.ru Wed Apr 10 15:04:22 2019 From: mdounin at mdounin.ru (Maxim Dounin) Date: Wed, 10 Apr 2019 18:04:22 +0300 Subject: [PATCH] Add support for using sendfile when openssl support ktls In-Reply-To: <87938decdb98bf4a06ed.1554896752@gen-l-vrt-211> References: <87938decdb98bf4a06ed.1554896752@gen-l-vrt-211> Message-ID: <20190410150422.GA1877@mdounin.ru> Hello! On Wed, Apr 10, 2019 at 02:45:52PM +0300, ben ben ishay wrote: > # HG changeset patch > # User ben ben ishay > # Date 1554896607 -10800 > # Wed Apr 10 14:43:27 2019 +0300 > # Node ID 87938decdb98bf4a06ed18002a15156a5e8fbd67 > # Parent 65074e13f1716e09c28d730586babad7930b7a98 > Add support for using sendfile when openssl support ktls > > when we need to transfer data between file and socket we prefer to use sendfile instead of write because we save the copy to a buffer. > the use of sendfile is possible in openssl only if it support ktls(the master of openssl support ktls) otherwise there is a copy of the data to userspace for encryption in any case (this paper explain this https://netdevconf.org/1.2/papers/ktls.pdf ). > the patch change the flow when the request is to send data over ssl and also the nginx use openssl that support ktls, the new flow using the sendfile function that tcp use for send data (ngx_linux_sendfile_chain). > the performence with this patch applied was check with apib benchmark(https://github.com/apigee/apib), one machine run nginx and the other machine that connect back to back to the first one run apib with this comand: ./apib -c -d 30 https:///. > the file size was 100K. > > the result display in this table , each value represnt average throughput in GBps of 10 runs. > > num of connection | regular nginx | new nginx > 1 5 5.2 > 2 7.5 8.5 > 3 7.7 9 > > this result prove that this patch increase nginx performance and thus is useful. Thank you for your patch. We've helped to develop similar functionality by Netflix for in-kernel TLS on FreeBSD (an earlier paper is referenced by the ktls.pdf you've linked). See, for example, this post for a high-level description: https://lists.freebsd.org/pipermail/freebsd-transport/2018-February/000196.html The most obvious difference one can observe is that the application-level code instead uses SSL_sendfile() call as provided by the SSL library, and it is library responsibility to make sure keys are properly synced with the kernel when kernel-level functions are called. In contrast, in your patch you assume that as long as BIO_get_ktls_send() returns true it is safe to use native kernel functions. This looks unsafe, at least without a documentation which explicitly states otherwise, as various control messages might interfere with direct calls on the socket. Moreover, quick look at the code seems to suggest that this is indeed might be unsafe - before writing anything to the socket OpenSSL checks if there are any pending control messages, and using sendfile() directly won't allow this to happen: https://github.com/openssl/openssl/commit/6ba76c4f23e4b4ddc27b9e7234c8b9c3bcff5eff#diff-869032903e697780f95495f7e44410b1R127 As such, the patch doesn't look correct to me (or at least OpenSSL's interface needs further clarification). [...] > @@ -140,3 +140,12 @@ > fi > > fi > +ngx_feature="OpenSSL library with KTLS" > +ngx_feature_name="NGX_OPENSSL_KTLS" > +ngx_feature_run=no > +ngx_feature_incs="#include \"openssl/bio.h\" " > +ngx_feature_path= > +ngx_feature_libs="-lssl -lcrypto $NGX_LIBDL $NGX_LIBPTHREAD" > +ngx_feature_test="BIO_get_ktls_send(NULL)" > +. auto/feature > + Note that we don't really use configure-time feature tests for OpenSSL. Instead, consider checking appropriate #define, such as #ifdef BIO_get_ktls_send. > diff -r 65074e13f171 -r 87938decdb98 src/event/ngx_event_openssl.c > --- a/src/event/ngx_event_openssl.c Tue Mar 26 09:33:57 2019 +0300 > +++ b/src/event/ngx_event_openssl.c Wed Apr 10 14:43:27 2019 +0300 > @@ -1528,6 +1528,9 @@ > #endif > > sc->connection = SSL_new(ssl->ctx); > +#if (NGX_OPENSSL_KTLS) > + sc->ktls = 0; > +#endif > > if (sc->connection == NULL) { > ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "SSL_new() failed"); > @@ -1639,6 +1642,12 @@ > c->recv_chain = ngx_ssl_recv_chain; > c->send_chain = ngx_ssl_send_chain; > > +#if (NGX_OPENSSL_KTLS) > + if(BIO_get_ktls_send(SSL_get_wbio(c->ssl->connection))){ > + c->ssl->ktls = 1; > + c->send_chain = ngx_linux_sendfile_chain; > + } > +#endif Note that compiling this will fail on anything but Linux as long as BIO_get_ktls_send() is present in the OpenSSL library, as ngx_linux_sendfile_chain() is only available on Linux. [...] -- Maxim Dounin http://mdounin.ru/ From xeioex at nginx.com Thu Apr 11 12:00:24 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Thu, 11 Apr 2019 12:00:24 +0000 Subject: [njs] HTTP: documenting props removal in changelog. Message-ID: details: https://hg.nginx.org/njs/rev/0c8a6246a4af branches: changeset: 877:0c8a6246a4af user: Dmitry Volyntsev date: Thu Apr 11 15:00:17 2019 +0300 description: HTTP: documenting props removal in changelog. res.contentLength and res.contentType were deprecated in 0.2.2 and removed in 0.2.8. diffstat: CHANGES | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-) diffs (14 lines): diff -r dd44fdfef2de -r 0c8a6246a4af CHANGES --- a/CHANGES Wed Apr 10 17:46:14 2019 +0300 +++ b/CHANGES Thu Apr 11 15:00:17 2019 +0300 @@ -318,6 +318,10 @@ Changes with njs 0.2.2 req.headers (use req.headersIn or req.headersOut) req.response + Deprecated members of Response: + res.contentLength (use req.headersOut['Content-Length']) + res.contentType (use req.headersOut['Content-Type']) + The deprecated properties will be removed in the following releases. From sharpobject at gmail.com Thu Apr 11 12:51:57 2019 From: sharpobject at gmail.com (Robert Burke) Date: Thu, 11 Apr 2019 05:51:57 -0700 Subject: [PATCH] Range filter: always support ascending multipart ranges. Message-ID: Hello, At Cloudflare we'd like to support multiple byte-ranges if they are non-overlapping and in ascending order on cache miss or when using slice. This patch adds support for that. It preserves the existing multipart range support for response bodies that are in a single buffer. It does not remove buffers from the passed-in chain, which seems like it was the biggest issue mdounin raised with the previous patch. I was not sure what semantics proxy_cache_max_range_offset should have for multipart range requests, but the TODO tests seemed to think that it should apply to requests that have any range beyond the limit. This could get silly, like it could apply to bytes=5-6,7-8 but not apply to bytes=5-8. Oh well. I just made it work like the tests say it should. On second thought, maybe it would be better not to make a totally new chain here. I could instead set unused buffers to length 0 and sync and leave them in the chain as we found them. Below is first the patch for nginx, then the patch for nginx-tests. Looking forward to your thoughts. Thanks! # HG changeset patch # User Robert Burke # Date 1554985755 25200 # Thu Apr 11 05:29:15 2019 -0700 # Node ID 75b953a2f40d0083ff9aa9585dd6f5e061cf964c # Parent a6e23e343081b79eb924da985a414909310aa7a3 Range filter: always support ascending multipart ranges. Arbitrary multipart ranges still work if the body is in a single buffer. This patch is based on hucongcong's similar patch from 2017. diff -r a6e23e343081 -r 75b953a2f40d src/http/modules/ngx_http_mp4_module.c --- a/src/http/modules/ngx_http_mp4_module.c Tue Apr 09 16:00:30 2019 +0300 +++ b/src/http/modules/ngx_http_mp4_module.c Thu Apr 11 05:29:15 2019 -0700 @@ -568,7 +568,7 @@ } if (start >= 0) { - r->single_range = 1; + r->ascending_ranges = 1; mp4 = ngx_pcalloc(r->pool, sizeof(ngx_http_mp4_file_t)); if (mp4 == NULL) { diff -r a6e23e343081 -r 75b953a2f40d src/http/modules/ngx_http_range_filter_module.c --- a/src/http/modules/ngx_http_range_filter_module.c Tue Apr 09 16:00:30 2019 +0300 +++ b/src/http/modules/ngx_http_range_filter_module.c Thu Apr 11 05:29:15 2019 -0700 @@ -54,6 +54,8 @@ typedef struct { off_t offset; + ngx_uint_t index; + ngx_uint_t descending; ngx_str_t boundary_header; ngx_array_t ranges; } ngx_http_range_filter_ctx_t; @@ -72,6 +74,10 @@ ngx_http_range_filter_ctx_t *ctx, ngx_chain_t *in); static ngx_int_t ngx_http_range_multipart_body(ngx_http_request_t *r, ngx_http_range_filter_ctx_t *ctx, ngx_chain_t *in); +static ngx_int_t ngx_http_range_link_boundary_header(ngx_http_request_t *r, + ngx_http_range_filter_ctx_t *ctx, ngx_chain_t **ll); +static ngx_int_t ngx_http_range_link_last_boundary(ngx_http_request_t *r, + ngx_http_range_filter_ctx_t *ctx, ngx_chain_t **ll); static ngx_int_t ngx_http_range_header_filter_init(ngx_conf_t *cf); static ngx_int_t ngx_http_range_body_filter_init(ngx_conf_t *cf); @@ -148,7 +154,6 @@ { time_t if_range_time; ngx_str_t *if_range, *etag; - ngx_uint_t ranges; ngx_http_core_loc_conf_t *clcf; ngx_http_range_filter_ctx_t *ctx; @@ -222,11 +227,10 @@ return NGX_ERROR; } + ctx->index = (ngx_uint_t) -1; ctx->offset = r->headers_out.content_offset; - ranges = r->single_range ? 1 : clcf->max_ranges; - - switch (ngx_http_range_parse(r, ctx, ranges)) { + switch (ngx_http_range_parse(r, ctx, clcf->max_ranges)) { case NGX_OK: ngx_http_set_ctx(r, ctx, ngx_http_range_body_filter_module); @@ -281,6 +285,7 @@ ngx_http_range_body_filter_module); if (mctx) { ctx->ranges = mctx->ranges; + ctx->boundary_header = mctx->boundary_header; return NGX_OK; } } @@ -293,6 +298,8 @@ p = r->headers_in.range->value.data + 6; size = 0; + range = NULL; + ctx->descending = 0; content_length = r->headers_out.content_length_n; cutoff = NGX_MAX_OFF_T_VALUE / 10; @@ -369,6 +376,10 @@ found: if (start < end) { + if (range && start < range->end) { + ctx->descending = 1; + } + range = ngx_array_push(&ctx->ranges); if (range == NULL) { return NGX_ERROR; @@ -383,10 +394,6 @@ size += end - start; - if (ranges-- == 0) { - return NGX_DECLINED; - } - } else if (start == 0) { return NGX_DECLINED; } @@ -400,7 +407,9 @@ return NGX_HTTP_RANGE_NOT_SATISFIABLE; } - if (size > content_length) { + if (ctx->ranges.nelts > ranges || + (ctx->descending && r->ascending_ranges) || + size > content_length) { return NGX_DECLINED; } @@ -469,6 +478,22 @@ ngx_http_range_t *range; ngx_atomic_uint_t boundary; + if (ctx->index == (ngx_uint_t) -1) { + ctx->index = 0; + range = ctx->ranges.elts; + + for (i = 0; i < ctx->ranges.nelts; i++) { + if (ctx->offset < range[i].end) { + ctx->index = i; + break; + } + } + } + + if (r != r->main) { + return ngx_http_next_header_filter(r); + } + size = sizeof(CRLF "--") - 1 + NGX_ATOMIC_T_LEN + sizeof(CRLF "Content-Type: ") - 1 + r->headers_out.content_type.len @@ -574,6 +599,7 @@ } r->headers_out.content_length_n = len; + r->headers_out.content_offset = range[0].start; if (r->headers_out.content_length) { r->headers_out.content_length->hash = 0; @@ -640,14 +666,16 @@ } /* - * multipart ranges are supported only if whole body is in a single buffer + * descending or overlapping ranges are supported only if whole body is + * in a single buffer */ - if (ngx_buf_special(in->buf)) { + if (ctx->descending && ngx_buf_special(in->buf)) { return ngx_http_next_body_filter(r, in); } - if (ngx_http_range_test_overlapped(r, ctx, in) != NGX_OK) { + if (ctx->descending && + ngx_http_range_test_overlapped(r, ctx, in) != NGX_OK) { return NGX_ERROR; } @@ -659,7 +687,7 @@ ngx_http_range_test_overlapped(ngx_http_request_t *r, ngx_http_range_filter_ctx_t *ctx, ngx_chain_t *in) { - off_t start, last; + off_t last; ngx_buf_t *buf; ngx_uint_t i; ngx_http_range_t *range; @@ -671,19 +699,16 @@ buf = in->buf; if (!buf->last_buf) { - start = ctx->offset; - last = ctx->offset + ngx_buf_size(buf); + last = ngx_buf_size(buf); range = ctx->ranges.elts; for (i = 0; i < ctx->ranges.nelts; i++) { - if (start > range[i].start || last < range[i].end) { + if (last < range[i].end) { goto overlapped; } } } - ctx->offset = ngx_buf_size(buf); - return NGX_OK; overlapped: @@ -701,7 +726,7 @@ { off_t start, last; ngx_buf_t *buf; - ngx_chain_t *out, *cl, **ll; + ngx_chain_t *out, *cl, *tl, **ll; ngx_http_range_t *range; out = NULL; @@ -721,8 +746,16 @@ "http range body buf: %O-%O", start, last); if (ngx_buf_special(buf)) { - *ll = cl; - ll = &cl->next; + tl = ngx_alloc_chain_link(r->pool); + if (tl == NULL) { + return NGX_ERROR; + } + + tl->buf = buf; + tl->next = NULL; + *ll = tl; + ll = &tl->next; + continue; } @@ -741,6 +774,14 @@ continue; } + tl = ngx_alloc_chain_link(r->pool); + if (tl == NULL) { + return NGX_ERROR; + } + + tl->buf = buf; + tl->next = NULL; + if (range->start > start) { if (buf->in_file) { @@ -764,14 +805,13 @@ buf->last_buf = (r == r->main) ? 1 : 0; buf->last_in_chain = 1; - *ll = cl; - cl->next = NULL; + *ll = tl; break; } - *ll = cl; - ll = &cl->next; + *ll = tl; + ll = &tl->next; } if (out == NULL) { @@ -787,95 +827,193 @@ ngx_http_range_filter_ctx_t *ctx, ngx_chain_t *in) { ngx_buf_t *b, *buf; - ngx_uint_t i; - ngx_chain_t *out, *hcl, *rcl, *dcl, **ll; - ngx_http_range_t *range; + off_t start, last; + ngx_chain_t *out, *cl, *tl, **ll; + ngx_http_range_t *range, *tail; + b = NULL; + out = NULL; ll = &out; - buf = in->buf; + range = ctx->ranges.elts; - - for (i = 0; i < ctx->ranges.nelts; i++) { + tail = range + ctx->ranges.nelts; + range += ctx->index; - /* - * The boundary header of the range: - * CRLF - * "--0123456789" CRLF - * "Content-Type: image/jpeg" CRLF - * "Content-Range: bytes " - */ + for (cl = in; cl; cl = cl->next) { + + buf = cl->buf; + + start = ctx->offset; + last = ctx->offset + ngx_buf_size(buf); - b = ngx_calloc_buf(r->pool); - if (b == NULL) { - return NGX_ERROR; + ctx->offset = last; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http range multipart body buf: %O-%O", start, last); + + if (ngx_buf_special(buf)) { + continue; } - b->memory = 1; - b->pos = ctx->boundary_header.data; - b->last = ctx->boundary_header.data + ctx->boundary_header.len; + if (range->end <= start || range->start >= last) { - hcl = ngx_alloc_chain_link(r->pool); - if (hcl == NULL) { - return NGX_ERROR; - } + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http range multipart body skip"); - hcl->buf = b; - + if (buf->in_file) { + buf->file_pos = buf->file_last; + } - /* "SSSS-EEEE/TTTT" CRLF CRLF */ + buf->pos = buf->last; + buf->sync = 1; - b = ngx_calloc_buf(r->pool); - if (b == NULL) { - return NGX_ERROR; + continue; } - b->temporary = 1; - b->pos = range[i].content_range.data; - b->last = range[i].content_range.data + range[i].content_range.len; + buf->last_in_chain = 0; + buf->last_buf = 0; + + while (range < tail && range->start < last) { + + if (range + 1 < tail && range[1].start < last) { + b = ngx_alloc_buf(r->pool); + if (b == NULL) { + return NGX_ERROR; + } - rcl = ngx_alloc_chain_link(r->pool); - if (rcl == NULL) { - return NGX_ERROR; - } + ngx_memcpy(b, buf, sizeof(ngx_buf_t)); + } else { + b = buf; + } + + tl = ngx_alloc_chain_link(r->pool); + if (tl == NULL) { + return NGX_ERROR; + } + + tl->buf = b; + tl->next = NULL; + + if (range->start >= start) { - rcl->buf = b; + if (ngx_http_range_link_boundary_header(r, ctx, ll) != NGX_OK) { + return NGX_ERROR; + } + + ll = &(*ll)->next->next; + if (b->in_file) { + b->file_pos += range->start - start; + } + + if (ngx_buf_in_memory(b)) { + b->pos += (size_t) (range->start - start); + } + } - /* the range data */ + *ll = tl; + ll = &tl->next; + + if (range->end <= last) { + if (b->in_file) { + b->file_last -= last - range->end; + } - b = ngx_calloc_buf(r->pool); - if (b == NULL) { - return NGX_ERROR; + if (ngx_buf_in_memory(b)) { + b->last -= (size_t) (last - range->end); + } + + ctx->index++; + range++; + } else { + break; + } } - b->in_file = buf->in_file; - b->temporary = buf->temporary; - b->memory = buf->memory; - b->mmap = buf->mmap; - b->file = buf->file; + if (range == tail) { + if (ngx_http_range_link_last_boundary(r, ctx, ll) != NGX_OK) { + return NGX_ERROR; + } + + break; + } + } + + if (out == NULL) { + return NGX_OK; + } + + return ngx_http_next_body_filter(r, out); +} + - if (buf->in_file) { - b->file_pos = buf->file_pos + range[i].start; - b->file_last = buf->file_pos + range[i].end; - } +static ngx_int_t +ngx_http_range_link_boundary_header(ngx_http_request_t *r, + ngx_http_range_filter_ctx_t *ctx, ngx_chain_t **ll) +{ + ngx_buf_t *b; + ngx_chain_t *hcl, *rcl; + ngx_http_range_t *range; + + /* + * The boundary header of the range: + * CRLF + * "--0123456789" CRLF + * "Content-Type: image/jpeg" CRLF + * "Content-Range: bytes " + */ + + b = ngx_calloc_buf(r->pool); + if (b == NULL) { + return NGX_ERROR; + } + + b->memory = 1; + b->pos = ctx->boundary_header.data; + b->last = ctx->boundary_header.data + ctx->boundary_header.len; - if (ngx_buf_in_memory(buf)) { - b->pos = buf->pos + (size_t) range[i].start; - b->last = buf->pos + (size_t) range[i].end; - } + hcl = ngx_alloc_chain_link(r->pool); + if (hcl == NULL) { + return NGX_ERROR; + } + + hcl->buf = b; + + + /* "SSSS-EEEE/TTTT" CRLF CRLF */ + + b = ngx_calloc_buf(r->pool); + if (b == NULL) { + return NGX_ERROR; + } + + range = ctx->ranges.elts; + b->temporary = 1; + b->pos = range[ctx->index].content_range.data; + b->last = range[ctx->index].content_range.data + + range[ctx->index].content_range.len; - dcl = ngx_alloc_chain_link(r->pool); - if (dcl == NULL) { - return NGX_ERROR; - } + rcl = ngx_alloc_chain_link(r->pool); + if (rcl == NULL) { + return NGX_ERROR; + } + + rcl->buf = b; + + rcl->next = NULL; + hcl->next = rcl; + *ll = hcl; - dcl->buf = b; + return NGX_OK; +} + - *ll = hcl; - hcl->next = rcl; - rcl->next = dcl; - ll = &dcl->next; - } +static ngx_int_t +ngx_http_range_link_last_boundary(ngx_http_request_t *r, + ngx_http_range_filter_ctx_t *ctx, ngx_chain_t **ll) +{ + ngx_buf_t *b; + ngx_chain_t *hcl; /* the last boundary CRLF "--0123456789--" CRLF */ @@ -885,7 +1023,8 @@ } b->temporary = 1; - b->last_buf = 1; + b->last_in_chain = 1; + b->last_buf = (r == r->main) ? 1 : 0; b->pos = ngx_pnalloc(r->pool, sizeof(CRLF "--") - 1 + NGX_ATOMIC_T_LEN + sizeof("--" CRLF) - 1); @@ -908,7 +1047,7 @@ *ll = hcl; - return ngx_http_next_body_filter(r, out); + return NGX_OK; } diff -r a6e23e343081 -r 75b953a2f40d src/http/modules/ngx_http_slice_filter_module.c --- a/src/http/modules/ngx_http_slice_filter_module.c Tue Apr 09 16:00:30 2019 +0300 +++ b/src/http/modules/ngx_http_slice_filter_module.c Thu Apr 11 05:29:15 2019 -0700 @@ -182,7 +182,7 @@ r->allow_ranges = 1; r->subrequest_ranges = 1; - r->single_range = 1; + r->ascending_ranges = 1; rc = ngx_http_next_header_filter(r); diff -r a6e23e343081 -r 75b953a2f40d src/http/ngx_http_request.h --- a/src/http/ngx_http_request.h Tue Apr 09 16:00:30 2019 +0300 +++ b/src/http/ngx_http_request.h Thu Apr 11 05:29:15 2019 -0700 @@ -547,7 +547,7 @@ unsigned preserve_body:1; unsigned allow_ranges:1; unsigned subrequest_ranges:1; - unsigned single_range:1; + unsigned ascending_ranges:1; unsigned disable_not_modified:1; unsigned stat_reading:1; unsigned stat_writing:1; diff -r a6e23e343081 -r 75b953a2f40d src/http/ngx_http_upstream.c --- a/src/http/ngx_http_upstream.c Tue Apr 09 16:00:30 2019 +0300 +++ b/src/http/ngx_http_upstream.c Thu Apr 11 05:29:15 2019 -0700 @@ -1157,20 +1157,42 @@ p = h->value.data + 6; - while (*p == ' ') { p++; } - - if (*p == '-') { - return NGX_DECLINED; - } - - start = p; - - while (*p >= '0' && *p <= '9') { p++; } - - offset = ngx_atoof(start, p - start); - - if (offset >= u->conf->cache_max_range_offset) { - return NGX_DECLINED; + for ( ;; ) { + while (*p == ' ') { p++; } + + if (*p == '-') { + return NGX_DECLINED; + } + + start = p; + + while (*p >= '0' && *p <= '9') { p++; } + + offset = ngx_atoof(start, p - start); + + if (offset >= u->conf->cache_max_range_offset) { + return NGX_DECLINED; + } + + while (*p == ' ') { p++; } + + if (*p++ != '-') { + return NGX_DECLINED; + } + + while (*p == ' ') { p++; } + + while (*p >= '0' && *p <= '9') { p++; } + + while (*p == ' ') { p++; } + + if (*p == '\0') { + break; + } + + if (*p++ != ',') { + return NGX_DECLINED; + } } return NGX_OK; @@ -2839,11 +2861,11 @@ if (u->conf->force_ranges) { r->allow_ranges = 1; - r->single_range = 1; + r->ascending_ranges = 1; #if (NGX_HTTP_CACHE) if (r->cached) { - r->single_range = 0; + r->ascending_ranges = 0; } #endif } @@ -5204,7 +5226,7 @@ if (r->upstream->cacheable) { r->allow_ranges = 1; - r->single_range = 1; + r->ascending_ranges = 1; return NGX_OK; } # HG changeset patch # User Robert Burke # Date 1554986947 25200 # Thu Apr 11 05:49:07 2019 -0700 # Node ID 118b3d5f356f5d881029b6b42c49625310ec7de1 # Parent fe886814b25a5842f4ee3844ac68e3bafbfd8458 Tests: uncomment multipart range tests Fix mp4 multipart range test. diff -r fe886814b25a -r 118b3d5f356f proxy_cache_max_range_offset.t --- a/proxy_cache_max_range_offset.t Tue Apr 09 18:52:53 2019 +0300 +++ b/proxy_cache_max_range_offset.t Thu Apr 11 05:49:07 2019 -0700 @@ -85,14 +85,7 @@ unlike(get('/t.html?1', 'bytes=1-'), qr/X-Range/, 'range - below'); like(get('/t.html?2', 'bytes=3-'), qr/X-Range/, 'range - above'); like(get('/t.html?3', 'bytes=-1'), qr/X-Range/, 'range - last'); - -TODO: { -local $TODO = 'not yet'; - like(get('/t.html?4', 'bytes=1-1,3-'), qr/X-Range/, 'range - multipart above'); - -} - like(get('/zero/t.html?5', 'bytes=0-0'), qr/X-Range/, 'always non-cacheable'); like(get('/min_uses/t.html?6', 'bytes=1-'), qr/X-Range/, 'below min_uses'); diff -r fe886814b25a -r 118b3d5f356f proxy_cache_range.t --- a/proxy_cache_range.t Tue Apr 09 18:52:53 2019 +0300 +++ b/proxy_cache_range.t Thu Apr 11 05:49:07 2019 -0700 @@ -84,12 +84,8 @@ like(http_get_range('/t.html?1', 'Range: bytes=4-'), qr/^THIS/m, 'range on first request'); -{ -local $TODO = 'not yet'; - like(http_get_range('/t.html?2', 'Range: bytes=0-2,4-'), qr/^SEE.*^THIS/ms, 'multipart range on first request'); -} like(http_get_range('/t.html?1', 'Range: bytes=4-'), qr/^THIS/m, 'cached range'); diff -r fe886814b25a -r 118b3d5f356f range_mp4.t --- a/range_mp4.t Tue Apr 09 18:52:53 2019 +0300 +++ b/range_mp4.t Thu Apr 11 05:49:07 2019 -0700 @@ -54,7 +54,7 @@ . "-pix_fmt yuv420p -c:v libx264 ${\($t->testdir())}/test.mp4") == 0 or die "Can't create mp4 file: $!"; -$t->run()->plan(13); +$t->run()->plan(14); ############################################################################### @@ -88,23 +88,20 @@ like($t1, qr/Content-Range: bytes 0-99\/$fsz/, 'multi buffers - content range'); -TODO: { -local $TODO = 'multipart range on mp4'; - $t1 = http_get_range('/test.mp4?start=1', 'Range: bytes=0-10,11-99'); like($t1, qr/ 206 /, 'multipart range - 206 partial reply'); -like($t1, qr/Content-Length: 100/, 'multipart range - content length'); -like($t1, qr/Content-Range: bytes 0-10,11-99\/$fsz/, +like($t1, qr/Content-Length: 303/, 'multipart range - content length'); +like($t1, qr/Content-Range: bytes 0-10\/$fsz/, 'multipart range - content range'); - -} +like($t1, qr/Content-Range: bytes 11-99\/$fsz/, + 'multipart range - content range'); ############################################################################### sub http_get_range { my ($url, $extra) = @_; return http(< details: https://hg.nginx.org/njs/rev/b9d619068453 branches: changeset: 878:b9d619068453 user: Dmitry Volyntsev date: Thu Apr 11 16:32:06 2019 +0300 description: Allowing to output large values in console.log(). Previously, the size was limited to 2048 bytes. This closes #127 issue on Github. diffstat: njs/njs_shell.c | 9 ++++++--- nxt/nxt_sprintf.c | 41 ++++++++++++++++++++++++----------------- nxt/nxt_sprintf.h | 6 +++++- 3 files changed, 35 insertions(+), 21 deletions(-) diffs (106 lines): diff -r 0c8a6246a4af -r b9d619068453 njs/njs_shell.c --- a/njs/njs_shell.c Thu Apr 11 15:00:17 2019 +0300 +++ b/njs/njs_shell.c Thu Apr 11 16:32:06 2019 +0300 @@ -645,7 +645,8 @@ njs_output(njs_vm_t *vm, njs_opts_t *opt nxt_error("%V\n", &out); } else if (opts->interactive) { - nxt_printf("%V\n", &out); + nxt_print(out.start, out.length); + nxt_printf("\n"); } } @@ -919,7 +920,8 @@ njs_ext_console_log(njs_vm_t *vm, njs_va return NJS_ERROR; } - nxt_printf("%s%V", (n != 1) ? " " : "", &msg); + nxt_printf("%s", (n != 1) ? " " : ""); + nxt_print(msg.start, msg.length); n++; } @@ -950,7 +952,8 @@ njs_ext_console_dump(njs_vm_t *vm, njs_v return NJS_ERROR; } - nxt_printf("%s%V", (n != 1) ? " " : "", &msg); + nxt_printf("%s", (n != 1) ? " " : ""); + nxt_print(msg.start, msg.length); n++; } diff -r 0c8a6246a4af -r b9d619068453 nxt/nxt_sprintf.c --- a/nxt/nxt_sprintf.c Thu Apr 11 15:00:17 2019 +0300 +++ b/nxt/nxt_sprintf.c Thu Apr 11 16:32:06 2019 +0300 @@ -64,23 +64,6 @@ nxt_sprintf(u_char *buf, u_char *end, co } -int -nxt_dprintf(int fd, const char *fmt, ...) -{ - size_t size; - u_char text[2048], *p; - va_list args; - - va_start(args, fmt); - p = nxt_vsprintf(text, text + sizeof(text), fmt, args); - va_end(args); - - size = p - text; - - return write(fd, text, size); -} - - /* * nxt_sprintf_t is used: * to pass several parameters of nxt_integer() via single pointer @@ -602,3 +585,27 @@ nxt_number(nxt_sprintf_t *spf, u_char *b return buf; } + + +NXT_EXPORT +int nxt_dprint(int fd, u_char *buf, size_t size) +{ + return write(fd, buf, size); +} + + +int +nxt_dprintf(int fd, const char *fmt, ...) +{ + size_t size; + u_char text[2048], *p; + va_list args; + + va_start(args, fmt); + p = nxt_vsprintf(text, text + sizeof(text), fmt, args); + va_end(args); + + size = p - text; + + return write(fd, text, size); +} diff -r 0c8a6246a4af -r b9d619068453 nxt/nxt_sprintf.h --- a/nxt/nxt_sprintf.h Thu Apr 11 15:00:17 2019 +0300 +++ b/nxt/nxt_sprintf.h Thu Apr 11 16:32:06 2019 +0300 @@ -12,9 +12,13 @@ NXT_EXPORT u_char *nxt_sprintf(u_char *b NXT_EXPORT u_char *nxt_vsprintf(u_char *buf, u_char *end, const char *fmt, va_list args); +NXT_EXPORT int nxt_dprint(int fd, u_char *buf, size_t size); NXT_EXPORT int nxt_dprintf(int fd, const char *fmt, ...); -#define nxt_printf(fmt, ...) \ +#define nxt_print(buf, size) \ + nxt_dprint(STDOUT_FILENO, (u_char *) buf, size) + +#define nxt_printf(fmt, ...) \ nxt_dprintf(STDOUT_FILENO, fmt, ##__VA_ARGS__) #define nxt_error(fmt, ...) \ From xeioex at nginx.com Thu Apr 11 14:29:00 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Thu, 11 Apr 2019 14:29:00 +0000 Subject: [njs] Checking for duplicate function parameter names. Message-ID: details: https://hg.nginx.org/njs/rev/4df50ca085e7 branches: changeset: 879:4df50ca085e7 user: hongzhidao date: Thu Apr 11 21:13:03 2019 +0800 description: Checking for duplicate function parameter names. This closes #80 issue on Github. diffstat: njs/njs_parser.c | 6 ++++++ njs/test/njs_unit_test.c | 21 +++++++++++++++++++++ 2 files changed, 27 insertions(+), 0 deletions(-) diffs (47 lines): diff -r b9d619068453 -r 4df50ca085e7 njs/njs_parser.c --- a/njs/njs_parser.c Thu Apr 11 16:32:06 2019 +0300 +++ b/njs/njs_parser.c Thu Apr 11 21:13:03 2019 +0800 @@ -837,6 +837,12 @@ njs_parser_lambda_argument(njs_vm_t *vm, return NJS_TOKEN_ERROR; } + if (arg->index > 0) { + njs_parser_syntax_error(vm, parser, "Duplicate parameter names"); + + return NJS_TOKEN_ILLEGAL; + } + arg->index = index; ret = njs_name_copy(vm, &arg->name, njs_parser_text(parser)); diff -r b9d619068453 -r 4df50ca085e7 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Thu Apr 11 16:32:06 2019 +0300 +++ b/njs/test/njs_unit_test.c Thu Apr 11 21:13:03 2019 +0800 @@ -5716,6 +5716,27 @@ static njs_unit_test_t njs_test[] = "binded.length"), nxt_string("0") }, + { nxt_string("function f(a,a) { };"), + nxt_string("SyntaxError: Duplicate parameter names in 1") }, + + { nxt_string("function f(a,b,a) { };"), + nxt_string("SyntaxError: Duplicate parameter names in 1") }, + + { nxt_string("function f(a, ...a) { };"), + nxt_string("SyntaxError: Duplicate parameter names in 1") }, + + { nxt_string("(function(a,a) { })"), + nxt_string("SyntaxError: Duplicate parameter names in 1") }, + + { nxt_string("(function(a,...a) { })"), + nxt_string("SyntaxError: Duplicate parameter names in 1") }, + + { nxt_string("(function f(a,a) { })"), + nxt_string("SyntaxError: Duplicate parameter names in 1") }, + + { nxt_string("(function f(a,...a) { })"), + nxt_string("SyntaxError: Duplicate parameter names in 1") }, + { nxt_string("function f(a,b) { }; f.length"), nxt_string("2") }, From xeioex at nginx.com Thu Apr 11 17:14:35 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Thu, 11 Apr 2019 17:14:35 +0000 Subject: [njs] Improved console.log() for string values. Message-ID: details: https://hg.nginx.org/njs/rev/bcf988ed8c08 branches: changeset: 880:bcf988ed8c08 user: Dmitry Volyntsev date: Thu Apr 11 18:53:19 2019 +0300 description: Improved console.log() for string values. Outputting string values without quotes. diffstat: njs/njs_json.c | 19 ++++++++++- njs/test/njs_expect_test.exp | 68 ++++++++++++++++++++++---------------------- 2 files changed, 50 insertions(+), 37 deletions(-) diffs (332 lines): diff -r 4df50ca085e7 -r bcf988ed8c08 njs/njs_json.c --- a/njs/njs_json.c Thu Apr 11 21:13:03 2019 +0800 +++ b/njs/njs_json.c Thu Apr 11 18:53:19 2019 +0300 @@ -1798,7 +1798,9 @@ njs_json_append_string(njs_json_stringif dst_end = dst + 64; - *dst++ = quote; + if (quote) { + *dst++ = quote; + } while (p < end) { @@ -1874,7 +1876,10 @@ njs_json_append_string(njs_json_stringif } njs_json_buf_written(stringify, dst - stringify->last->pos); - njs_json_buf_append(stringify, "e, 1); + + if (quote) { + njs_json_buf_append(stringify, "e, 1); + } return NXT_OK; } @@ -2116,6 +2121,7 @@ const njs_object_init_t njs_json_object static nxt_int_t njs_dump_value(njs_json_stringify_t *stringify, const njs_value_t *value) { + char quote; njs_ret_t ret; nxt_str_t str; nxt_uint_t written; @@ -2139,7 +2145,13 @@ njs_dump_value(njs_json_stringify_t *str case NJS_STRING: njs_string_get(value, &str); - return njs_json_append_string(stringify, value, '\''); + + quote = '\0'; + if (stringify->stack.items != 0) { + quote = '\''; + } + + return njs_json_append_string(stringify, value, quote); case NJS_OBJECT_NUMBER: value = &value->data.u.object_value->value; @@ -2351,6 +2363,7 @@ njs_vm_value_dump(njs_vm_t *vm, nxt_str_ stringify->pool = vm->mem_pool; stringify->nodes = NULL; stringify->last = NULL; + stringify->stack.items = 0; if (!njs_dump_is_object(value)) { ret = njs_dump_value(stringify, value); diff -r 4df50ca085e7 -r bcf988ed8c08 njs/test/njs_expect_test.exp --- a/njs/test/njs_expect_test.exp Thu Apr 11 21:13:03 2019 +0800 +++ b/njs/test/njs_expect_test.exp Thu Apr 11 18:53:19 2019 +0300 @@ -191,13 +191,13 @@ njs_test { {"console.log(1)\r\n" "console.log(1)\r\n1\r\nundefined\r\n>> "} {"console.log(1, 'a')\r\n" - "console.log(1, 'a')\r\n1 'a'\r\nundefined\r\n>> "} + "console.log(1, 'a')\r\n1 a\r\nundefined\r\n>> "} {"console.dump()\r\n" "console.dump()\r\nundefined\r\n>> "} {"console.dump(1)\r\n" "console.dump(1)\r\n1\r\nundefined\r\n>> "} {"console.dump(1, 'a')\r\n" - "console.dump(1, 'a')\r\n1 'a'\r\nundefined\r\n>> "} + "console.dump(1, 'a')\r\n1 a\r\nundefined\r\n>> "} {"console.help()\r\n" "console.help()\r\nVM built-in objects:"} } @@ -230,9 +230,9 @@ njs_test { njs_test { {"var print = console.log.bind(console); print(1, 'a', [1, 2])\r\n" - "1 'a' \\\[1,2]\r\nundefined\r\n>> "} + "1 a \\\[1,2]\r\nundefined\r\n>> "} {"var print = console.dump.bind(console); print(1, 'a', [1, 2])\r\n" - "1 'a' \\\[\r\n 1,\r\n 2\r\n]\r\nundefined\r\n>> "} + "1 a \\\[\r\n 1,\r\n 2\r\n]\r\nundefined\r\n>> "} } # Backtraces for external objects @@ -268,7 +268,7 @@ njs_test { # except '\"' njs_test { {"\"\\r\\0\\\"\"\r\n" - "'\\\\r\\\\u0000\"'"} + "\\\\r\\\\u0000\""} } njs_test { @@ -299,23 +299,23 @@ njs_test { # Non-ASCII characters njs_test { {"'???'\r\n" - "'???'"} + "???"} {"var v = '?????????????';v[10]\r\n" - "'?'"} + "?"} } # Immediate events njs_test { {"var t = setImmediate(console.log, 'a', 'aa')\r\n" - "undefined\r\n'a' 'aa'"} + "undefined\r\na aa"} } njs_test { {"var a = 1 + 1; setTimeout(function (x) {a = x}, 0, 'a'); a\r\n" "2"} {"a\r\n" - "a\r\n'a'"} + "a\r\na"} } njs_test { @@ -327,14 +327,14 @@ njs_test { {"var a = 1 + 1; setTimeout(function (x) { setTimeout(function (y) {a = y}, 0, x)}, 0, 'a'); a\r\n" "2"} {"a\r\n" - "a\r\n'a'"} + "a\r\na"} } njs_test { {"var a = 1 + 1; setImmediate(function (x) { setImmediate(function (y) {a = y}, x)}, 'a'); a\r\n" "2"} {"a\r\n" - "a\r\n'a'"} + "a\r\na"} } njs_test { @@ -362,7 +362,7 @@ njs_test { {"var i = 0, queue = []; (function x() { if (i < 5) setImmediate(x); queue.push(i++); })()\r\n" "undefined"} {"queue.toString()\r\n" - "queue.toString()\r\n'0,1,2,3,4,5'"} + "queue.toString()\r\n0,1,2,3,4,5"} } # require('fs') @@ -380,37 +380,37 @@ njs_test { {"var fs = require('fs')\r\n" "undefined\r\n>> "} {"fs.readFile('njs/test/fs/utf8', 'utf8', function (e, data) {console.log(data[2]+data.length)})\r\n" - "'Z4'\r\nundefined\r\n>> "} + "Z4\r\nundefined\r\n>> "} } njs_test { {"var fs = require('fs')\r\n" "undefined\r\n>> "} {"fs.readFile('njs/test/fs/utf8', function (e, data) {console.log(data[4]+data.length)})\r\n" - "'Z7'\r\nundefined\r\n>> "} + "Z7\r\nundefined\r\n>> "} } njs_test { {"var fs = require('fs')\r\n" "undefined\r\n>> "} {"fs.readFile('njs/test/fs/utf8', {encoding:'utf8',flag:'r+'}, function (e, data) {console.log(data)})\r\n" - "'??Z?'\r\nundefined\r\n>> "} + "??Z?\r\nundefined\r\n>> "} } njs_test { {"var fs = require('fs')\r\n" "undefined\r\n>> "} {"fs.readFile('njs/test/fs/ascii', function (e, data) {console.log(data[599])})\r\n" - "'x'\r\nundefined\r\n>> "} + "x\r\nundefined\r\n>> "} {"fs.readFile('njs/test/fs/ascii', {encoding:'utf8',flag:'r+'}, function (e, data) {console.log(data[599])})\r\n" - "'x'\r\nundefined\r\n>> "} + "x\r\nundefined\r\n>> "} } njs_test { {"var fs = require('fs'); \r\n" "undefined\r\n>> "} {"fs.readFile('njs/test/fs/nonexistent', 'utf8', function (e) {console.log(JSON.stringify(e))})\r\n" - "'{\"errno\":2,\"path\":\"njs/test/fs/nonexistent\",\"syscall\":\"open\"}'\r\nundefined\r\n>> "} + "{\"errno\":2,\"path\":\"njs/test/fs/nonexistent\",\"syscall\":\"open\"}\r\nundefined\r\n>> "} } njs_test { @@ -426,42 +426,42 @@ njs_test { {"var fs = require('fs')\r\n" "undefined\r\n>> "} {"fs.readFileSync('njs/test/fs/utf8').toString('base64')\r\n" - "'zrHOslrOsw=='\r\n>> "} + "zrHOslrOsw==\r\n>> "} } njs_test { {"var fs = require('fs')\r\n" "undefined\r\n>> "} {"fs.readFileSync('njs/test/fs/utf8', 'utf8')[2]\r\n" - "'Z'\r\n>> "} + "Z\r\n>> "} } njs_test { {"var fs = require('fs')\r\n" "undefined\r\n>> "} {"fs.readFileSync('njs/test/fs/utf8')[4]\r\n" - "'Z'\r\n>> "} + "Z\r\n>> "} } njs_test { {"var fs = require('fs')\r\n" "undefined\r\n>> "} {"fs.readFileSync('njs/test/fs/utf8', {encoding:'utf8',flag:'r+'})\r\n" - "'??Z?'\r\n>> "} + "??Z?\r\n>> "} } njs_test { {"var fs = require('fs'), fn = 'njs/test/fs/ascii'\r\n" "undefined\r\n>> "} {"fs.readFileSync(fn)[599] + fs.readFileSync(fn, 'utf8')[599]\r\n" - "'xx'\r\n>> "} + "xx\r\n>> "} } njs_test { {"var fs = require('fs'); \r\n" "undefined\r\n>> "} {"try { fs.readFileSync('njs/test/fs/nonexistent')} catch (e) {console.log(JSON.stringify(e))}\r\n" - "'{\"errno\":2,\"path\":\"njs/test/fs/nonexistent\",\"syscall\":\"open\"}'\r\nundefined\r\n>> "} + "{\"errno\":2,\"path\":\"njs/test/fs/nonexistent\",\"syscall\":\"open\"}\r\nundefined\r\n>> "} } njs_test { @@ -489,21 +489,21 @@ njs_test { {"function h1(e) {if (e) {throw e}; console.log(fs.readFileSync('njs_test_file2'))}\r\n" "undefined\r\n>> "} {"fs.writeFile('njs_test_file2', 'ABC', h1)\r\n" - "'ABC'\r\nundefined\r\n>> "} + "ABC\r\nundefined\r\n>> "} } njs_test { {"var fs = require('fs')\r\n" "undefined\r\n>> "} {"fs.writeFile('njs_test_file2', 'ABC', 'utf8', function (e) { if (e) {throw e}; console.log(fs.readFileSync('njs_test_file2'))})\r\n" - "'ABC'\r\nundefined\r\n>> "} + "ABC\r\nundefined\r\n>> "} } njs_test { {"var fs = require('fs')\r\n" "undefined\r\n>> "} {"fs.writeFile('njs_test_file2', 'ABC', {encoding:'utf8', mode:0o666}, function (e) { if (e) {throw e}; console.log(fs.readFileSync('njs_test_file2'))})\r\n" - "'ABC'\r\nundefined\r\n>> "} + "ABC\r\nundefined\r\n>> "} } exec rm -fr njs_wo_file @@ -519,7 +519,7 @@ njs_test { {"var fs = require('fs')\r\n" "undefined\r\n>> "} {"fs.writeFile('/invalid_path', 'ABC', function (e) { console.log(JSON.stringify(e))})\r\n" - "'{\"errno\":13,\"path\":\"/invalid_path\",\"syscall\":\"open\"}'\r\nundefined\r\n>> "} + "{\"errno\":13,\"path\":\"/invalid_path\",\"syscall\":\"open\"}\r\nundefined\r\n>> "} } # require('fs').writeFileSync() @@ -532,7 +532,7 @@ njs_test { {"fs.writeFileSync('njs_test_file2', 'ABC')\r\n" "undefined\r\n>> "} {"fs.readFileSync('njs_test_file2')\r\n" - "'ABC'\r\n>> "} + "ABC\r\n>> "} } njs_test { @@ -541,7 +541,7 @@ njs_test { {"fs.writeFileSync('njs_test_file2', 'ABC', 'utf8')\r\n" "undefined\r\n>> "} {"fs.readFileSync('njs_test_file2')\r\n" - "'ABC'\r\n>> "} + "ABC\r\n>> "} } njs_test { @@ -552,7 +552,7 @@ njs_test { {"fs.writeFileSync('njs_test_file2', 'ABC')\r\n" "undefined\r\n>> "} {"fs.readFileSync('njs_test_file2')\r\n" - "'ABC'\r\n>> "} + "ABC\r\n>> "} } njs_test { @@ -561,7 +561,7 @@ njs_test { {"fs.writeFileSync('njs_test_file2', 'ABC', {encoding:'utf8', mode:0o666})\r\n" "undefined\r\n>> "} {"fs.readFileSync('njs_test_file2')\r\n" - "'ABC'\r\n>> "} + "ABC\r\n>> "} } exec rm -fr njs_wo_file @@ -585,7 +585,7 @@ njs_test { {"function h2(e) {fs.appendFile('njs_test_file2', 'ABC', h1)}\r\n" "undefined\r\n>> "} {"fs.appendFile('njs_test_file2', 'ABC', h2)\r\n" - "'ABCABC'\r\nundefined\r\n>> "} + "ABCABC\r\nundefined\r\n>> "} } # require('fs').appendFileSync() @@ -600,7 +600,7 @@ njs_test { {"fs.appendFileSync('njs_test_file2', 'ABC')\r\n" "undefined\r\n>> "} {"fs.readFileSync('njs_test_file2')\r\n" - "'ABCABC'\r\n>> "} + "ABCABC\r\n>> "} } # Modules From xeioex at nginx.com Thu Apr 11 17:14:36 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Thu, 11 Apr 2019 17:14:36 +0000 Subject: [njs] UNIT style indentation in njs_string.h. Message-ID: details: https://hg.nginx.org/njs/rev/5c6ca5b99ab0 branches: changeset: 881:5c6ca5b99ab0 user: Dmitry Volyntsev date: Thu Apr 11 20:09:41 2019 +0300 description: UNIT style indentation in njs_string.h. diffstat: nxt/nxt_string.h | 27 +++++++++++++++++++-------- 1 files changed, 19 insertions(+), 8 deletions(-) diffs (55 lines): diff -r bcf988ed8c08 -r 5c6ca5b99ab0 nxt/nxt_string.h --- a/nxt/nxt_string.h Thu Apr 11 18:53:19 2019 +0300 +++ b/nxt/nxt_string.h Thu Apr 11 20:09:41 2019 +0300 @@ -41,24 +41,34 @@ nxt_upper_case(u_char c) } -#define nxt_cpymem(dst, src, n) (((u_char *) memcpy(dst, src, n)) + (n)) +#define \ +nxt_cpymem(dst, src, n) \ + (((u_char *) memcpy(dst, src, n)) + (n)) -#define nxt_strncmp(s1, s2, n) strncmp((char *) s1, (char *) s2, n) +#define \ +nxt_strncmp(s1, s2, n) \ + strncmp((char *) s1, (char *) s2, n) -#define nxt_memset(buf, c, length) (void) (memset(buf, c, length)) +#define \ +nxt_memset(buf, c, length) \ + (void) memset(buf, c, length) -#define nxt_memzero(buf, length) (void) (memset(buf, 0, length)) +#define \ +nxt_memzero(buf, length) \ + (void) memset(buf, 0, length) #if (NXT_HAVE_EXPLICIT_BZERO) -#define nxt_explicit_memzero(buf, length) \ +#define \ +nxt_explicit_memzero(buf, length) \ explicit_bzero(buf, length) #elif (NXT_HAVE_EXPLICIT_MEMSET) -#define nxt_explicit_memzero(buf, length) \ - (void) (explicit_memset(buf, 0, length)) +#define \ +nxt_explicit_memzero(buf, length) \ + (void) explicit_memset(buf, 0, length) #else nxt_inline void nxt_explicit_memzero(u_char *buf, size_t length) @@ -73,7 +83,8 @@ nxt_explicit_memzero(u_char *buf, size_t #endif -#define nxt_strstr_eq(s1, s2) \ +#define \ +nxt_strstr_eq(s1, s2) \ (((s1)->length == (s2)->length) \ && (memcmp((s1)->start, (s2)->start, (s1)->length) == 0)) From xeioex at nginx.com Thu Apr 11 17:14:37 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Thu, 11 Apr 2019 17:14:37 +0000 Subject: [njs] Added string functions wrappers. Message-ID: details: https://hg.nginx.org/njs/rev/e05e9b801355 branches: changeset: 882:e05e9b801355 user: Dmitry Volyntsev date: Thu Apr 11 20:09:41 2019 +0300 description: Added string functions wrappers. nxt_strlen(), nxt_strchr(), nxt_strlchr(). diffstat: njs/njs_fs.c | 4 ++-- njs/njs_regexp.c | 4 ++-- njs/njs_shell.c | 20 ++++++++++---------- nxt/nxt_string.h | 26 ++++++++++++++++++++++++++ 4 files changed, 40 insertions(+), 14 deletions(-) diffs (160 lines): diff -r 5c6ca5b99ab0 -r e05e9b801355 njs/njs_fs.c --- a/njs/njs_fs.c Thu Apr 11 20:09:41 2019 +0300 +++ b/njs/njs_fs.c Thu Apr 11 20:09:41 2019 +0300 @@ -899,7 +899,7 @@ static njs_ret_t njs_fs_error(njs_vm_t * njs_object_prop_t *prop; nxt_lvlhsh_query_t lhq; - size = description != NULL ? strlen(description) : 0; + size = description != NULL ? nxt_strlen(description) : 0; ret = njs_string_new(vm, &string, (u_char *) description, size, size); if (nxt_slow_path(ret != NXT_OK)) { @@ -957,7 +957,7 @@ static njs_ret_t njs_fs_error(njs_vm_t * } if (syscall != NULL) { - size = strlen(syscall); + size = nxt_strlen(syscall); ret = njs_string_new(vm, &string, (u_char *) syscall, size, size); if (nxt_slow_path(ret != NXT_OK)) { return NJS_ERROR; diff -r 5c6ca5b99ab0 -r e05e9b801355 njs/njs_regexp.c --- a/njs/njs_regexp.c Thu Apr 11 20:09:41 2019 +0300 +++ b/njs/njs_regexp.c Thu Apr 11 20:09:41 2019 +0300 @@ -526,7 +526,7 @@ njs_regexp_prototype_source(njs_vm_t *vm /* Skip starting "/". */ source = pattern->source + 1; - size = strlen((char *) source) - pattern->flags; + size = nxt_strlen(source) - pattern->flags; length = nxt_utf8_length(source, size); return njs_regexp_string_create(vm, retval, source, size, length); @@ -559,7 +559,7 @@ njs_regexp_to_string(njs_vm_t *vm, njs_v pattern = value->data.u.regexp->pattern; source = pattern->source; - size = strlen((char *) source); + size = nxt_strlen(source); length = nxt_utf8_length(source, size); return njs_regexp_string_create(vm, retval, source, size, length); diff -r 5c6ca5b99ab0 -r e05e9b801355 njs/njs_shell.c --- a/njs/njs_shell.c Thu Apr 11 20:09:41 2019 +0300 +++ b/njs/njs_shell.c Thu Apr 11 20:09:41 2019 +0300 @@ -236,12 +236,12 @@ main(int argc, char **argv) goto done; } - memcpy(path + strlen(path), "/shell", sizeof("/shell")); + memcpy(path + nxt_strlen(path), "/shell", sizeof("/shell")); opts.file = path; } vm_options.file.start = (u_char *) opts.file; - vm_options.file.length = strlen(opts.file); + vm_options.file.length = nxt_strlen(opts.file); } vm_options.init = !opts.interactive; @@ -438,7 +438,7 @@ njs_interactive_shell(njs_opts_t *opts, break; } - line.length = strlen((char *) line.start); + line.length = nxt_strlen(line.start); if (line.length == 0) { continue; } @@ -575,7 +575,7 @@ close_fd: static njs_vm_t * njs_create_vm(njs_opts_t *opts, njs_vm_opt_t *vm_options) { - char *p, *start; + u_char *p, *start; njs_vm_t *vm; nxt_int_t ret; nxt_str_t path; @@ -594,7 +594,7 @@ njs_create_vm(njs_opts_t *opts, njs_vm_o for (i = 0; i < opts->n_paths; i++) { path.start = (u_char *) opts->paths[i]; - path.length = strlen(opts->paths[i]); + path.length = nxt_strlen(opts->paths[i]); ret = njs_vm_add_path(vm, &path); if (ret != NXT_OK) { @@ -603,16 +603,16 @@ njs_create_vm(njs_opts_t *opts, njs_vm_o } } - start = getenv("NJS_PATH"); + start = (u_char *) getenv("NJS_PATH"); if (start == NULL) { return vm; } for ( ;; ) { - p = strchr(start, ':'); + p = nxt_strchr(start, ':'); - path.start = (u_char *) start; - path.length = (p != NULL) ? (size_t) (p - start) : strlen(start); + path.start = start; + path.length = (p != NULL) ? (size_t) (p - start) : nxt_strlen(start); ret = njs_vm_add_path(vm, &path); if (ret != NXT_OK) { @@ -784,7 +784,7 @@ njs_completion_generator(const char *tex if (state == 0) { cmpl->phase = 0; cmpl->index = 0; - cmpl->length = strlen(text); + cmpl->length = nxt_strlen(text); cmpl->suffix_completions = NULL; nxt_lvlhsh_each_init(&cmpl->lhe, &njs_variables_hash_proto); diff -r 5c6ca5b99ab0 -r e05e9b801355 nxt/nxt_string.h --- a/nxt/nxt_string.h Thu Apr 11 20:09:41 2019 +0300 +++ b/nxt/nxt_string.h Thu Apr 11 20:09:41 2019 +0300 @@ -41,6 +41,27 @@ nxt_upper_case(u_char c) } +nxt_inline u_char * +nxt_strlchr(u_char *p, u_char *last, u_char c) +{ + while (p < last) { + + if (*p == c) { + return p; + } + + p++; + } + + return NULL; +} + + +#define \ +nxt_strlen(s) \ + strlen((char *) s) + + #define \ nxt_cpymem(dst, src, n) \ (((u_char *) memcpy(dst, src, n)) + (n)) @@ -52,6 +73,11 @@ nxt_strncmp(s1, s2, n) #define \ +nxt_strchr(s1, c) \ + (u_char *) strchr((const char *) s1, (int) c) + + +#define \ nxt_memset(buf, c, length) \ (void) memset(buf, c, length) From xeioex at nginx.com Thu Apr 11 17:14:37 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Thu, 11 Apr 2019 17:14:37 +0000 Subject: [njs] Shell: added shebang support. Message-ID: details: https://hg.nginx.org/njs/rev/442f18a804b0 branches: changeset: 883:442f18a804b0 user: Dmitry Volyntsev date: Thu Apr 11 20:09:42 2019 +0300 description: Shell: added shebang support. diffstat: njs/njs_shell.c | 40 ++++++++++++++++++++++++++++------------ 1 files changed, 28 insertions(+), 12 deletions(-) diffs (95 lines): diff -r e05e9b801355 -r 442f18a804b0 njs/njs_shell.c --- a/njs/njs_shell.c Thu Apr 11 20:09:41 2019 +0300 +++ b/njs/njs_shell.c Thu Apr 11 20:09:42 2019 +0300 @@ -465,7 +465,7 @@ njs_process_file(njs_opts_t *opts, njs_v ssize_t n; njs_vm_t *vm; nxt_int_t ret; - nxt_str_t script; + nxt_str_t source, script; struct stat sb; file = opts->file; @@ -495,15 +495,15 @@ njs_process_file(njs_opts_t *opts, njs_v size = sb.st_size; } - script.length = 0; - script.start = realloc(NULL, size); - if (script.start == NULL) { + source.length = 0; + source.start = realloc(NULL, size); + if (source.start == NULL) { nxt_error("alloc failed while reading '%s'\n", file); ret = NXT_ERROR; goto done; } - p = script.start; + p = source.start; end = p + size; for ( ;; ) { @@ -523,23 +523,23 @@ njs_process_file(njs_opts_t *opts, njs_v if (p + n > end) { size *= 2; - start = realloc(script.start, size); + start = realloc(source.start, size); if (start == NULL) { nxt_error("alloc failed while reading '%s'\n", file); ret = NXT_ERROR; goto done; } - script.start = start; + source.start = start; - p = script.start + script.length; - end = script.start + size; + p = source.start + source.length; + end = source.start + size; } memcpy(p, buf, n); p += n; - script.length += n; + source.length += n; } vm = njs_create_vm(opts, vm_options); @@ -548,6 +548,22 @@ njs_process_file(njs_opts_t *opts, njs_v goto done; } + script = source; + + /* shebang */ + + if (script.length > 2 && memcmp(script.start, "#!", 2) == 0) { + p = nxt_strlchr(script.start, script.start + script.length, '\n'); + + if (p != NULL) { + script.length -= (p + 1 - script.start); + script.start = p + 1; + + } else { + script.length = 0; + } + } + ret = njs_process_script(vm_options->external, opts, &script); if (ret != NXT_OK) { ret = NXT_ERROR; @@ -558,8 +574,8 @@ njs_process_file(njs_opts_t *opts, njs_v done: - if (script.start != NULL) { - free(script.start); + if (source.start != NULL) { + free(source.start); } close_fd: From xeioex at nginx.com Thu Apr 11 18:24:46 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Thu, 11 Apr 2019 18:24:46 +0000 Subject: [njs] Shell: improved njs_vm_value_dump(). Message-ID: details: https://hg.nginx.org/njs/rev/ff7760036c67 branches: changeset: 884:ff7760036c67 user: Dmitry Volyntsev date: Thu Apr 11 21:24:16 2019 +0300 description: Shell: improved njs_vm_value_dump(). njs_vm_value_dump() is used in two modes: 1) printing value of the previous expression in the shell. 2) console.log(). The behavior is different. Strings are printed with quotes in the first case, but without in the second. Also special ASCII symbols should not be escaped in console.log(). diffstat: njs/njs.c | 2 +- njs/njs.h | 2 +- njs/njs_builtin.c | 2 +- njs/njs_json.c | 27 ++++++++++++--------------- njs/njs_shell.c | 4 ++-- njs/test/njs_expect_test.exp | 30 ++++++++++++++++-------------- 6 files changed, 33 insertions(+), 34 deletions(-) diffs (272 lines): diff -r 442f18a804b0 -r ff7760036c67 njs/njs.c --- a/njs/njs.c Thu Apr 11 20:09:42 2019 +0300 +++ b/njs/njs.c Thu Apr 11 21:24:16 2019 +0300 @@ -706,7 +706,7 @@ njs_vm_retval_dump(njs_vm_t *vm, nxt_str njs_vm_init(vm); } - return njs_vm_value_dump(vm, dst, &vm->retval, 1); + return njs_vm_value_dump(vm, dst, &vm->retval, 0, 1); } diff -r 442f18a804b0 -r ff7760036c67 njs/njs.h --- a/njs/njs.h Thu Apr 11 20:09:42 2019 +0300 +++ b/njs/njs.h Thu Apr 11 21:24:16 2019 +0300 @@ -249,7 +249,7 @@ NXT_EXPORT njs_ret_t njs_vm_value_to_ext NXT_EXPORT njs_ret_t njs_vm_retval_to_ext_string(njs_vm_t *vm, nxt_str_t *dst); NXT_EXPORT njs_ret_t njs_vm_value_dump(njs_vm_t *vm, nxt_str_t *dst, - const njs_value_t *value, nxt_uint_t indent); + const njs_value_t *value, nxt_uint_t console, nxt_uint_t indent); NXT_EXPORT njs_ret_t njs_vm_retval_dump(njs_vm_t *vm, nxt_str_t *dst, nxt_uint_t indent); diff -r 442f18a804b0 -r ff7760036c67 njs/njs_builtin.c --- a/njs/njs_builtin.c Thu Apr 11 20:09:42 2019 +0300 +++ b/njs/njs_builtin.c Thu Apr 11 21:24:16 2019 +0300 @@ -1057,7 +1057,7 @@ njs_dump_value(njs_vm_t *vm, njs_value_t n = njs_primitive_value_to_integer(indent); n = nxt_min(n, 5); - if (njs_vm_value_dump(vm, &str, value, n) != NXT_OK) { + if (njs_vm_value_dump(vm, &str, value, 1, n) != NXT_OK) { return NXT_ERROR; } diff -r 442f18a804b0 -r ff7760036c67 njs/njs_json.c --- a/njs/njs_json.c Thu Apr 11 20:09:42 2019 +0300 +++ b/njs/njs_json.c Thu Apr 11 21:24:16 2019 +0300 @@ -1798,9 +1798,7 @@ njs_json_append_string(njs_json_stringif dst_end = dst + 64; - if (quote) { - *dst++ = quote; - } + *dst++ = quote; while (p < end) { @@ -1877,9 +1875,7 @@ njs_json_append_string(njs_json_stringif njs_json_buf_written(stringify, dst - stringify->last->pos); - if (quote) { - njs_json_buf_append(stringify, "e, 1); - } + njs_json_buf_append(stringify, "e, 1); return NXT_OK; } @@ -2119,9 +2115,9 @@ const njs_object_init_t njs_json_object static nxt_int_t -njs_dump_value(njs_json_stringify_t *stringify, const njs_value_t *value) +njs_dump_value(njs_json_stringify_t *stringify, const njs_value_t *value, + nxt_uint_t console) { - char quote; njs_ret_t ret; nxt_str_t str; nxt_uint_t written; @@ -2146,12 +2142,13 @@ njs_dump_value(njs_json_stringify_t *str case NJS_STRING: njs_string_get(value, &str); - quote = '\0'; - if (stringify->stack.items != 0) { - quote = '\''; + if (!console || stringify->stack.items != 0) { + return njs_json_append_string(stringify, value, '\''); } - return njs_json_append_string(stringify, value, quote); + return njs_json_buf_append(stringify, (char *) str.start, str.length); + + break; case NJS_OBJECT_NUMBER: value = &value->data.u.object_value->value; @@ -2326,7 +2323,7 @@ memory_error: #define njs_dump_append_value(value) \ state->written = 1; \ - ret = njs_dump_value(stringify, value); \ + ret = njs_dump_value(stringify, value, console); \ if (nxt_slow_path(ret != NXT_OK)) { \ if (ret == NXT_DECLINED) { \ goto exception; \ @@ -2338,7 +2335,7 @@ memory_error: njs_ret_t njs_vm_value_dump(njs_vm_t *vm, nxt_str_t *retval, const njs_value_t *value, - nxt_uint_t indent) + nxt_uint_t console, nxt_uint_t indent) { nxt_int_t i; njs_ret_t ret; @@ -2366,7 +2363,7 @@ njs_vm_value_dump(njs_vm_t *vm, nxt_str_ stringify->stack.items = 0; if (!njs_dump_is_object(value)) { - ret = njs_dump_value(stringify, value); + ret = njs_dump_value(stringify, value, console); if (nxt_slow_path(ret != NXT_OK)) { goto memory_error; } diff -r 442f18a804b0 -r ff7760036c67 njs/njs_shell.c --- a/njs/njs_shell.c Thu Apr 11 20:09:42 2019 +0300 +++ b/njs/njs_shell.c Thu Apr 11 21:24:16 2019 +0300 @@ -930,7 +930,7 @@ njs_ext_console_log(njs_vm_t *vm, njs_va n = 1; while (n < nargs) { - if (njs_vm_value_dump(vm, &msg, njs_argument(args, n), 0) + if (njs_vm_value_dump(vm, &msg, njs_argument(args, n), 1, 0) == NJS_ERROR) { return NJS_ERROR; @@ -962,7 +962,7 @@ njs_ext_console_dump(njs_vm_t *vm, njs_v n = 1; while (n < nargs) { - if (njs_vm_value_dump(vm, &msg, njs_argument(args, n), 1) + if (njs_vm_value_dump(vm, &msg, njs_argument(args, n), 1, 1) == NJS_ERROR) { return NJS_ERROR; diff -r 442f18a804b0 -r ff7760036c67 njs/test/njs_expect_test.exp --- a/njs/test/njs_expect_test.exp Thu Apr 11 20:09:42 2019 +0300 +++ b/njs/test/njs_expect_test.exp Thu Apr 11 21:24:16 2019 +0300 @@ -192,6 +192,8 @@ njs_test { "console.log(1)\r\n1\r\nundefined\r\n>> "} {"console.log(1, 'a')\r\n" "console.log(1, 'a')\r\n1 a\r\nundefined\r\n>> "} + {"console.log('\\t???\\n??')\r\n" + "console.log('\\\\t???\\\\n??')\r\n\t???\r\n??\r\nundefined\r\n>> "} {"console.dump()\r\n" "console.dump()\r\nundefined\r\n>> "} {"console.dump(1)\r\n" @@ -315,7 +317,7 @@ njs_test { {"var a = 1 + 1; setTimeout(function (x) {a = x}, 0, 'a'); a\r\n" "2"} {"a\r\n" - "a\r\na"} + "a\r\n'a'"} } njs_test { @@ -327,14 +329,14 @@ njs_test { {"var a = 1 + 1; setTimeout(function (x) { setTimeout(function (y) {a = y}, 0, x)}, 0, 'a'); a\r\n" "2"} {"a\r\n" - "a\r\na"} + "a\r\n'a'"} } njs_test { {"var a = 1 + 1; setImmediate(function (x) { setImmediate(function (y) {a = y}, x)}, 'a'); a\r\n" "2"} {"a\r\n" - "a\r\na"} + "a\r\n'a'"} } njs_test { @@ -362,7 +364,7 @@ njs_test { {"var i = 0, queue = []; (function x() { if (i < 5) setImmediate(x); queue.push(i++); })()\r\n" "undefined"} {"queue.toString()\r\n" - "queue.toString()\r\n0,1,2,3,4,5"} + "queue.toString()\r\n'0,1,2,3,4,5'"} } # require('fs') @@ -426,35 +428,35 @@ njs_test { {"var fs = require('fs')\r\n" "undefined\r\n>> "} {"fs.readFileSync('njs/test/fs/utf8').toString('base64')\r\n" - "zrHOslrOsw==\r\n>> "} + "'zrHOslrOsw=='\r\n>> "} } njs_test { {"var fs = require('fs')\r\n" "undefined\r\n>> "} {"fs.readFileSync('njs/test/fs/utf8', 'utf8')[2]\r\n" - "Z\r\n>> "} + "'Z'\r\n>> "} } njs_test { {"var fs = require('fs')\r\n" "undefined\r\n>> "} {"fs.readFileSync('njs/test/fs/utf8')[4]\r\n" - "Z\r\n>> "} + "'Z'\r\n>> "} } njs_test { {"var fs = require('fs')\r\n" "undefined\r\n>> "} {"fs.readFileSync('njs/test/fs/utf8', {encoding:'utf8',flag:'r+'})\r\n" - "??Z?\r\n>> "} + "'??Z?'\r\n>> "} } njs_test { {"var fs = require('fs'), fn = 'njs/test/fs/ascii'\r\n" "undefined\r\n>> "} {"fs.readFileSync(fn)[599] + fs.readFileSync(fn, 'utf8')[599]\r\n" - "xx\r\n>> "} + "'xx'\r\n>> "} } njs_test { @@ -532,7 +534,7 @@ njs_test { {"fs.writeFileSync('njs_test_file2', 'ABC')\r\n" "undefined\r\n>> "} {"fs.readFileSync('njs_test_file2')\r\n" - "ABC\r\n>> "} + "'ABC'\r\n>> "} } njs_test { @@ -541,7 +543,7 @@ njs_test { {"fs.writeFileSync('njs_test_file2', 'ABC', 'utf8')\r\n" "undefined\r\n>> "} {"fs.readFileSync('njs_test_file2')\r\n" - "ABC\r\n>> "} + "'ABC'\r\n>> "} } njs_test { @@ -552,7 +554,7 @@ njs_test { {"fs.writeFileSync('njs_test_file2', 'ABC')\r\n" "undefined\r\n>> "} {"fs.readFileSync('njs_test_file2')\r\n" - "ABC\r\n>> "} + "'ABC'\r\n>> "} } njs_test { @@ -561,7 +563,7 @@ njs_test { {"fs.writeFileSync('njs_test_file2', 'ABC', {encoding:'utf8', mode:0o666})\r\n" "undefined\r\n>> "} {"fs.readFileSync('njs_test_file2')\r\n" - "ABC\r\n>> "} + "'ABC'\r\n>> "} } exec rm -fr njs_wo_file @@ -600,7 +602,7 @@ njs_test { {"fs.appendFileSync('njs_test_file2', 'ABC')\r\n" "undefined\r\n>> "} {"fs.readFileSync('njs_test_file2')\r\n" - "ABCABC\r\n>> "} + "'ABCABC'\r\n>> "} } # Modules From i at morfi.ru Fri Apr 12 13:36:09 2019 From: i at morfi.ru (i at morfi.ru) Date: Fri, 12 Apr 2019 13:36:09 +0000 Subject: [PATCH] Avoid multiple bind for the same address during config test Message-ID: <549f07c848d82ef152ed.1555076169@08319b44732f> # HG changeset patch # User Andrey Kolyshkin # Date 1555075759 -10800 # Fri Apr 12 16:29:19 2019 +0300 # Node ID 549f07c848d82ef152ed54f31b25dcfe89452a66 # Parent 5155d0296a5ef9841f035920527ffdb771076b44 Avoid multiple bind for the same address during config test If reuseport is specified in the config, then during config test nginx makes multiple calls to the bind function for the same address. It causes a problem when large number of connections goes to the server and bind (inet_csk_bind_conflict) loads cpu multiple times. After fixing, bind is called only 1 time per address while testing of the config. diff -r 5155d0296a5e -r 549f07c848d8 src/core/ngx_connection.c --- a/src/core/ngx_connection.c Tue Apr 09 16:00:30 2019 +0300 +++ b/src/core/ngx_connection.c Fri Apr 12 16:29:19 2019 +0300 @@ -104,7 +104,7 @@ ngx_core_conf_t *ccf; ngx_listening_t ols; - if (!ls->reuseport || ls->worker != 0) { + if (!ls->reuseport || ls->worker != 0 || ngx_test_config) { return NGX_OK; } From xeioex at nginx.com Fri Apr 12 15:36:12 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Fri, 12 Apr 2019 15:36:12 +0000 Subject: [njs] Fixed objects instance properties. Message-ID: details: https://hg.nginx.org/njs/rev/1213e0a2b485 branches: changeset: 885:1213e0a2b485 user: Dmitry Volyntsev date: Fri Apr 12 18:36:02 2019 +0300 description: Fixed objects instance properties. Some properties like 'length' of Array, String or Function objects should be instance properties not prototype properties. diffstat: njs/njs_array.c | 26 +++++++- njs/njs_array.h | 1 + njs/njs_builtin.c | 92 ++++++++++++++++-------------- njs/njs_extern.c | 2 +- njs/njs_function.c | 58 +++++++++++++++++-- njs/njs_function.h | 4 +- njs/njs_number.c | 88 ++++++++++++++++++++++++++-- njs/njs_object.c | 40 +++++-------- njs/njs_string.c | 141 +++++++++++++++++++++++++++++++++++++++++----- njs/njs_string.h | 1 + njs/njs_vm.h | 9 ++- njs/test/njs_unit_test.c | 60 +++++++++++++++++++- 12 files changed, 411 insertions(+), 111 deletions(-) diffs (truncated from 1033 to 1000 lines): diff -r ff7760036c67 -r 1213e0a2b485 njs/njs_array.c --- a/njs/njs_array.c Thu Apr 11 21:24:16 2019 +0300 +++ b/njs/njs_array.c Fri Apr 12 18:36:02 2019 +0300 @@ -149,7 +149,7 @@ njs_array_alloc(njs_vm_t *vm, uint32_t l array->start = array->data; nxt_lvlhsh_init(&array->object.hash); - nxt_lvlhsh_init(&array->object.shared_hash); + array->object.shared_hash = vm->shared->array_instance_hash; array->object.__proto__ = &vm->prototypes[NJS_PROTOTYPE_ARRAY].object; array->object.type = NJS_ARRAY; array->object.shared = 0; @@ -401,8 +401,8 @@ const njs_object_init_t njs_array_const static njs_ret_t -njs_array_prototype_length(njs_vm_t *vm, njs_value_t *value, - njs_value_t *setval, njs_value_t *retval) +njs_array_length(njs_vm_t *vm, njs_value_t *value, njs_value_t *setval, + njs_value_t *retval) { double num; int64_t size; @@ -2214,7 +2214,7 @@ static const njs_object_prop_t njs_arra { .type = NJS_PROPERTY_HANDLER, .name = njs_string("length"), - .value = njs_prop_handler(njs_array_prototype_length), + .value = njs_prop_handler(njs_array_length), .writable = 1 }, @@ -2395,3 +2395,21 @@ const njs_object_init_t njs_array_proto njs_array_prototype_properties, nxt_nitems(njs_array_prototype_properties), }; + + +const njs_object_prop_t njs_array_instance_properties[] = +{ + { + .type = NJS_PROPERTY_HANDLER, + .name = njs_string("length"), + .value = njs_prop_handler(njs_array_length), + .writable = 1 + }, +}; + + +const njs_object_init_t njs_array_instance_init = { + nxt_string("Array instance"), + njs_array_instance_properties, + nxt_nitems(njs_array_instance_properties), +}; diff -r ff7760036c67 -r 1213e0a2b485 njs/njs_array.h --- a/njs/njs_array.h Thu Apr 11 21:24:16 2019 +0300 +++ b/njs/njs_array.h Fri Apr 12 18:36:02 2019 +0300 @@ -26,6 +26,7 @@ njs_ret_t njs_array_constructor(njs_vm_t extern const njs_object_init_t njs_array_constructor_init; extern const njs_object_init_t njs_array_prototype_init; +extern const njs_object_init_t njs_array_instance_init; #endif /* _NJS_ARRAY_H_INCLUDED_ */ diff -r ff7760036c67 -r 1213e0a2b485 njs/njs_builtin.c --- a/njs/njs_builtin.c Thu Apr 11 21:24:16 2019 +0300 +++ b/njs/njs_builtin.c Fri Apr 12 18:36:02 2019 +0300 @@ -138,22 +138,6 @@ const njs_function_init_t njs_native_fu }; -const njs_object_prop_t njs_arguments_object_properties[] = -{ - { - .type = NJS_PROPERTY_HANDLER, - .name = njs_string("caller"), - .value = njs_prop_handler(njs_function_arguments_thrower), - }, - - { - .type = NJS_PROPERTY_HANDLER, - .name = njs_string("callee"), - .value = njs_prop_handler(njs_function_arguments_thrower), - }, -}; - - const njs_function_init_t njs_native_constructors[] = { /* SunC does not allow empty array initialization. */ { njs_object_constructor, { 0 } }, @@ -230,48 +214,61 @@ const njs_object_prototype_t njs_protot }; +nxt_inline nxt_int_t +njs_object_hash_init(njs_vm_t *vm, nxt_lvlhsh_t *hash, + const njs_object_init_t *init) +{ + return njs_object_hash_create(vm, hash, init->properties, init->items); +} + nxt_int_t njs_builtin_objects_create(njs_vm_t *vm) { nxt_int_t ret; njs_module_t *module; - njs_object_t *object; + njs_object_t *object, *string_object; njs_function_t *func; nxt_lvlhsh_query_t lhq; + njs_vm_shared_t *shared; njs_object_prototype_t *prototype; const njs_object_init_t *obj, **p; const njs_function_init_t *f; - static const njs_object_prop_t function_prototype_property = { - .type = NJS_PROPERTY_HANDLER, - .name = njs_string("prototype"), - .value = njs_prop_handler(njs_function_prototype_create), - }; - static const nxt_str_t sandbox_key = nxt_string("sandbox"); - ret = njs_object_hash_create(vm, &vm->shared->function_prototype_hash, - &function_prototype_property, 1); + shared = vm->shared; + + ret = njs_object_hash_init(vm, &shared->array_instance_hash, + &njs_array_instance_init); + if (nxt_slow_path(ret != NXT_OK)) { + return NXT_ERROR; + } + + ret = njs_object_hash_init(vm, &shared->string_instance_hash, + &njs_string_instance_init); if (nxt_slow_path(ret != NXT_OK)) { return NXT_ERROR; } - ret = njs_object_hash_create(vm, &vm->shared->arguments_object_hash, - njs_arguments_object_properties, - nxt_nitems(njs_arguments_object_properties)); + ret = njs_object_hash_init(vm, &shared->function_instance_hash, + &njs_function_instance_init); if (nxt_slow_path(ret != NXT_OK)) { return NXT_ERROR; } - object = vm->shared->objects; + ret = njs_object_hash_init(vm, &shared->arguments_object_instance_hash, + &njs_arguments_object_instance_init); + if (nxt_slow_path(ret != NXT_OK)) { + return NXT_ERROR; + } + + object = shared->objects; for (p = njs_object_init; *p != NULL; p++) { obj = *p; - ret = njs_object_hash_create(vm, &object->shared_hash, - obj->properties, obj->items); - + ret = njs_object_hash_init(vm, &object->shared_hash, obj); if (nxt_slow_path(ret != NXT_OK)) { return NXT_ERROR; } @@ -295,8 +292,7 @@ njs_builtin_objects_create(njs_vm_t *vm) module->function.native = 1; - ret = njs_object_hash_create(vm, &module->object.shared_hash, - obj->properties, obj->items); + ret = njs_object_hash_init(vm, &module->object.shared_hash, obj); if (nxt_slow_path(ret != NXT_OK)) { return NXT_ERROR; } @@ -327,13 +323,12 @@ njs_builtin_objects_create(njs_vm_t *vm) } f = njs_native_functions; - func = vm->shared->functions; + func = shared->functions; for (p = njs_function_init; *p != NULL; p++) { obj = *p; - ret = njs_object_hash_create(vm, &func->object.shared_hash, - obj->properties, obj->items); + ret = njs_object_hash_init(vm, &func->object.shared_hash, obj); if (nxt_slow_path(ret != NXT_OK)) { return NXT_ERROR; } @@ -350,14 +345,13 @@ njs_builtin_objects_create(njs_vm_t *vm) func++; } - prototype = vm->shared->prototypes; + prototype = shared->prototypes; memcpy(prototype, njs_prototype_values, sizeof(njs_prototype_values)); for (p = njs_prototype_init; *p != NULL; p++) { obj = *p; - ret = njs_object_hash_create(vm, &prototype->object.shared_hash, - obj->properties, obj->items); + ret = njs_object_hash_init(vm, &prototype->object.shared_hash, obj); if (nxt_slow_path(ret != NXT_OK)) { return NXT_ERROR; } @@ -367,11 +361,19 @@ njs_builtin_objects_create(njs_vm_t *vm) prototype++; } - vm->shared->prototypes[NJS_PROTOTYPE_REGEXP].regexp.pattern = + shared->prototypes[NJS_PROTOTYPE_REGEXP].regexp.pattern = vm->shared->empty_regexp_pattern; + string_object = &shared->string_object; + nxt_lvlhsh_init(&string_object->hash); + string_object->shared_hash = vm->shared->string_instance_hash; + string_object->type = NJS_OBJECT_STRING; + string_object->shared = 1; + string_object->extensible = 0; + string_object->__proto__ = &vm->prototypes[NJS_PROTOTYPE_STRING].object; + f = njs_native_constructors; - func = vm->shared->constructors; + func = shared->constructors; for (p = njs_constructor_init; *p != NULL; p++) { obj = *p; @@ -386,8 +388,7 @@ njs_builtin_objects_create(njs_vm_t *vm) memcpy(func->args_types, f->args_types, NJS_ARGS_TYPES_MAX); - ret = njs_object_hash_create(vm, &func->object.shared_hash, - obj->properties, obj->items); + ret = njs_object_hash_init(vm, &func->object.shared_hash, obj); if (nxt_slow_path(ret != NXT_OK)) { return NXT_ERROR; } @@ -523,6 +524,9 @@ njs_builtin_objects_clone(njs_vm_t *vm) vm->constructors[i].object.__proto__ = function_prototype; } + vm->string_object = vm->shared->string_object; + vm->string_object.__proto__ = &vm->prototypes[NJS_PROTOTYPE_STRING].object; + return NXT_OK; } diff -r ff7760036c67 -r 1213e0a2b485 njs/njs_extern.c --- a/njs/njs_extern.c Thu Apr 11 21:24:16 2019 +0300 +++ b/njs/njs_extern.c Fri Apr 12 18:36:02 2019 +0300 @@ -109,7 +109,7 @@ njs_vm_external_add(njs_vm_t *vm, nxt_lv function->object.__proto__ = &vm->prototypes[NJS_CONSTRUCTOR_FUNCTION].object; - function->object.shared_hash = vm->shared->function_prototype_hash; + function->object.shared_hash = vm->shared->function_instance_hash; function->object.type = NJS_FUNCTION; function->object.shared = 1; function->object.extensible = 1; diff -r ff7760036c67 -r 1213e0a2b485 njs/njs_function.c --- a/njs/njs_function.c Thu Apr 11 21:24:16 2019 +0300 +++ b/njs/njs_function.c Fri Apr 12 18:36:02 2019 +0300 @@ -42,7 +42,7 @@ njs_function_alloc(njs_vm_t *vm, njs_fun function->args_offset = 1; function->u.lambda = lambda; - function->object.shared_hash = vm->shared->function_prototype_hash; + function->object.shared_hash = vm->shared->function_instance_hash; function->object.__proto__ = &vm->prototypes[NJS_PROTOTYPE_FUNCTION].object; function->object.type = NJS_FUNCTION; function->object.shared = shared; @@ -162,7 +162,7 @@ njs_function_arguments_object_init(njs_v return NXT_ERROR; } - arguments->shared_hash = vm->shared->arguments_object_hash; + arguments->shared_hash = vm->shared->arguments_object_instance_hash; nargs = frame->nargs; @@ -250,7 +250,7 @@ njs_function_rest_parameters_init(njs_vm } -njs_ret_t +static njs_ret_t njs_function_arguments_thrower(njs_vm_t *vm, njs_value_t *value, njs_value_t *setval, njs_value_t *retval) { @@ -259,6 +259,29 @@ njs_function_arguments_thrower(njs_vm_t } +const njs_object_prop_t njs_arguments_object_instance_properties[] = +{ + { + .type = NJS_PROPERTY_HANDLER, + .name = njs_string("caller"), + .value = njs_prop_handler(njs_function_arguments_thrower), + }, + + { + .type = NJS_PROPERTY_HANDLER, + .name = njs_string("callee"), + .value = njs_prop_handler(njs_function_arguments_thrower), + }, +}; + + +const njs_object_init_t njs_arguments_object_instance_init = { + nxt_string("Argument object instance"), + njs_arguments_object_instance_properties, + nxt_nitems(njs_arguments_object_instance_properties), +}; + + njs_ret_t njs_function_native_frame(njs_vm_t *vm, njs_function_t *function, const njs_value_t *this, const njs_value_t *args, nxt_uint_t nargs, @@ -861,7 +884,7 @@ const njs_object_init_t njs_function_co * 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_function_instance_length(njs_vm_t *vm, njs_value_t *value, njs_value_t *setval, njs_value_t *retval) { nxt_uint_t n; @@ -1117,9 +1140,9 @@ njs_function_prototype_bind(njs_vm_t *vm static const njs_object_prop_t njs_function_prototype_properties[] = { { - .type = NJS_PROPERTY_HANDLER, + .type = NJS_PROPERTY, .name = njs_string("length"), - .value = njs_prop_handler(njs_function_prototype_length), + .value = njs_value(NJS_NUMBER, 0, 0.0), }, { @@ -1149,6 +1172,29 @@ const njs_object_init_t njs_function_pr }; +const njs_object_prop_t njs_function_instance_properties[] = +{ + { + .type = NJS_PROPERTY_HANDLER, + .name = njs_string("length"), + .value = njs_prop_handler(njs_function_instance_length), + }, + + { + .type = NJS_PROPERTY_HANDLER, + .name = njs_string("prototype"), + .value = njs_prop_handler(njs_function_prototype_create), + }, +}; + + +const njs_object_init_t njs_function_instance_init = { + nxt_string("Function instance"), + njs_function_instance_properties, + nxt_nitems(njs_function_instance_properties), +}; + + njs_ret_t njs_eval_function(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused) diff -r ff7760036c67 -r 1213e0a2b485 njs/njs_function.h --- a/njs/njs_function.h Thu Apr 11 21:24:16 2019 +0300 +++ b/njs/njs_function.h Fri Apr 12 18:36:02 2019 +0300 @@ -153,8 +153,6 @@ njs_ret_t njs_function_arguments_object_ njs_native_frame_t *frame); njs_ret_t njs_function_rest_parameters_init(njs_vm_t *vm, njs_native_frame_t *frame); -njs_ret_t njs_function_arguments_thrower(njs_vm_t *vm, njs_value_t *value, - njs_value_t *setval, njs_value_t *retval); njs_ret_t njs_function_prototype_create(njs_vm_t *vm, njs_value_t *value, njs_value_t *setval, njs_value_t *retval); njs_value_t *njs_function_property_prototype_create(njs_vm_t *vm, @@ -219,6 +217,8 @@ njs_function_previous_frame(njs_native_f extern const njs_object_init_t njs_function_constructor_init; extern const njs_object_init_t njs_function_prototype_init; +extern const njs_object_init_t njs_function_instance_init; +extern const njs_object_init_t njs_arguments_object_instance_init; njs_ret_t njs_eval_function(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused); diff -r ff7760036c67 -r 1213e0a2b485 njs/njs_number.c --- a/njs/njs_number.c Thu Apr 11 21:24:16 2019 +0300 +++ b/njs/njs_number.c Fri Apr 12 18:36:02 2019 +0300 @@ -820,29 +820,101 @@ njs_number_to_integer(double num) } +static const njs_object_prop_t njs_is_nan_function_properties[] = +{ + /* isNaN.name == "isNaN". */ + { + .type = NJS_PROPERTY, + .name = njs_string("name"), + .value = njs_string("isNaN"), + }, + + /* isNaN.length == 1. */ + { + .type = NJS_PROPERTY, + .name = njs_string("length"), + .value = njs_value(NJS_NUMBER, 1, 1.0), + }, +}; + + const njs_object_init_t njs_is_nan_function_init = { nxt_string("isNaN"), - NULL, - 0, + njs_is_nan_function_properties, + nxt_nitems(njs_is_nan_function_properties), +}; + + +static const njs_object_prop_t njs_is_finite_function_properties[] = +{ + /* isFinite.name == "isFinite". */ + { + .type = NJS_PROPERTY, + .name = njs_string("name"), + .value = njs_string("isFinite"), + }, + + /* isFinite.length == 1. */ + { + .type = NJS_PROPERTY, + .name = njs_string("length"), + .value = njs_value(NJS_NUMBER, 1, 1.0), + }, }; const njs_object_init_t njs_is_finite_function_init = { nxt_string("isFinite"), - NULL, - 0, + njs_is_finite_function_properties, + nxt_nitems(njs_is_finite_function_properties), +}; + + +static const njs_object_prop_t njs_parse_int_function_properties[] = +{ + /* parseInt.name == "parseInt". */ + { + .type = NJS_PROPERTY, + .name = njs_string("name"), + .value = njs_string("parseInt"), + }, + + /* parseInt.length == 2. */ + { + .type = NJS_PROPERTY, + .name = njs_string("length"), + .value = njs_value(NJS_NUMBER, 1, 2.0), + }, }; const njs_object_init_t njs_parse_int_function_init = { nxt_string("parseInt"), - NULL, - 0, + njs_parse_int_function_properties, + nxt_nitems(njs_parse_int_function_properties), +}; + + +static const njs_object_prop_t njs_parse_float_function_properties[] = +{ + /* parseFloat.name == "parseFloat". */ + { + .type = NJS_PROPERTY, + .name = njs_string("name"), + .value = njs_string("parseFloat"), + }, + + /* parseFloat.length == 1. */ + { + .type = NJS_PROPERTY, + .name = njs_string("length"), + .value = njs_value(NJS_NUMBER, 1, 1.0), + }, }; const njs_object_init_t njs_parse_float_function_init = { nxt_string("parseFloat"), - NULL, - 0, + njs_parse_float_function_properties, + nxt_nitems(njs_parse_float_function_properties), }; diff -r ff7760036c67 -r 1213e0a2b485 njs/njs_object.c --- a/njs/njs_object.c Thu Apr 11 21:24:16 2019 +0300 +++ b/njs/njs_object.c Fri Apr 12 18:36:02 2019 +0300 @@ -294,7 +294,7 @@ njs_property_query(njs_vm_t *vm, njs_pro } } - obj = &vm->prototypes[NJS_PROTOTYPE_STRING].object; + obj = &vm->string_object; break; case NJS_OBJECT_STRING: @@ -764,6 +764,8 @@ njs_method_private_copy(njs_vm_t *vm, nj return NXT_ERROR; } + function->object.shared_hash = vm->shared->function_instance_hash; + pq->lhq.replace = 0; pq->lhq.value = prop; pq->lhq.pool = vm->mem_pool; @@ -954,25 +956,20 @@ njs_array_t * njs_object_enumerate(njs_vm_t *vm, const njs_value_t *value, njs_object_enum_t kind, nxt_bool_t all) { - nxt_bool_t exotic_length; u_char *dst; uint32_t i, length, size, items_length, properties; njs_value_t *string, *item; njs_array_t *items, *array, *entry; nxt_lvlhsh_t *hash; const u_char *src, *end; + njs_object_t *object; njs_object_prop_t *prop; njs_string_prop_t string_prop; nxt_lvlhsh_each_t lhe; - static const njs_value_t njs_string_length = njs_string("length"); - - /* TODO: "length" is in a shared_hash. */ - - exotic_length = 0; - array = NULL; length = 0; + object = NULL; items_length = 0; switch (value->type) { @@ -986,8 +983,6 @@ njs_object_enumerate(njs_vm_t *vm, const } } - exotic_length = all; - break; case NJS_STRING: @@ -997,19 +992,14 @@ njs_object_enumerate(njs_vm_t *vm, const } else { string = (njs_value_t *) value; + object = &vm->string_object; } length = njs_string_prop(&string_prop, string); items_length += length; - exotic_length = all; break; - case NJS_FUNCTION: - exotic_length = all && (value->data.u.function->native == 0); - - /* Fall through. */ - default: break; } @@ -1019,8 +1009,12 @@ njs_object_enumerate(njs_vm_t *vm, const properties = 0; if (nxt_fast_path(njs_is_object(value))) { + object = value->data.u.object; + } + + if (object != NULL) { nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto); - hash = &value->data.u.object->hash; + hash = &object->hash; for ( ;; ) { prop = nxt_lvlhsh_each(hash, &lhe); @@ -1036,7 +1030,7 @@ njs_object_enumerate(njs_vm_t *vm, const if (nxt_slow_path(all)) { nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto); - hash = &value->data.u.object->shared_hash; + hash = &object->shared_hash; for ( ;; ) { prop = nxt_lvlhsh_each(hash, &lhe); @@ -1052,7 +1046,7 @@ njs_object_enumerate(njs_vm_t *vm, const items_length += properties; } - items = njs_array_alloc(vm, items_length + exotic_length, NJS_ARRAY_SPARE); + items = njs_array_alloc(vm, items_length, NJS_ARRAY_SPARE); if (nxt_slow_path(items == NULL)) { return NULL; } @@ -1210,14 +1204,10 @@ njs_object_enumerate(njs_vm_t *vm, const } } - if (nxt_slow_path(exotic_length != 0)) { - *item++ = njs_string_length; - } - if (nxt_fast_path(properties != 0)) { nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto); - hash = &value->data.u.object->hash; + hash = &object->hash; switch (kind) { @@ -1236,7 +1226,7 @@ njs_object_enumerate(njs_vm_t *vm, const if (nxt_slow_path(all)) { nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto); - hash = &value->data.u.object->shared_hash; + hash = &object->shared_hash; for ( ;; ) { prop = nxt_lvlhsh_each(hash, &lhe); diff -r ff7760036c67 -r 1213e0a2b485 njs/njs_string.c --- a/njs/njs_string.c Thu Apr 11 21:24:16 2019 +0300 +++ b/njs/njs_string.c Fri Apr 12 18:36:02 2019 +0300 @@ -555,6 +555,8 @@ njs_string_constructor(njs_vm_t *vm, njs return NXT_ERROR; } + object->shared_hash = vm->shared->string_instance_hash; + vm->retval.data.u.object = object; vm->retval.type = NJS_OBJECT_STRING; vm->retval.data.truth = 1; @@ -623,7 +625,7 @@ const njs_object_init_t njs_string_cons static njs_ret_t -njs_string_prototype_length(njs_vm_t *vm, njs_value_t *value, +njs_string_instance_length(njs_vm_t *vm, njs_value_t *value, njs_value_t *setval, njs_value_t *retval) { size_t size; @@ -3752,15 +3754,15 @@ njs_string_to_c_string(njs_vm_t *vm, njs static const njs_object_prop_t njs_string_prototype_properties[] = { { - .type = NJS_PROPERTY_HANDLER, - .name = njs_string("__proto__"), - .value = njs_prop_handler(njs_primitive_prototype_get_proto), + .type = NJS_PROPERTY, + .name = njs_string("length"), + .value = njs_value(NJS_NUMBER, 0, 0.0), }, { .type = NJS_PROPERTY_HANDLER, - .name = njs_string("length"), - .value = njs_prop_handler(njs_string_prototype_length), + .name = njs_string("__proto__"), + .value = njs_prop_handler(njs_primitive_prototype_get_proto), }, { @@ -3973,6 +3975,23 @@ const njs_object_init_t njs_string_prot }; +const njs_object_prop_t njs_string_instance_properties[] = +{ + { + .type = NJS_PROPERTY_HANDLER, + .name = njs_string("length"), + .value = njs_prop_handler(njs_string_instance_length), + }, +}; + + +const njs_object_init_t njs_string_instance_init = { + nxt_string("String instance"), + njs_string_instance_properties, + nxt_nitems(njs_string_instance_properties), +}; + + /* * encodeURI(string) */ @@ -4448,36 +4467,126 @@ njs_value_index(njs_vm_t *vm, const njs_ } +static const njs_object_prop_t njs_to_string_function_properties[] = +{ + /* toString.name == "toString". */ + { + .type = NJS_PROPERTY, + .name = njs_string("name"), + .value = njs_string("toString"), + }, + + /* toString.length == 0. */ + { + .type = NJS_PROPERTY, + .name = njs_string("length"), + .value = njs_value(NJS_NUMBER, 0, 0.0), + }, +}; + + const njs_object_init_t njs_to_string_function_init = { nxt_string("toString"), - NULL, - 0, + njs_to_string_function_properties, + nxt_nitems(njs_to_string_function_properties), +}; + + +static const njs_object_prop_t njs_encode_uri_function_properties[] = +{ + /* encodeURI.name == "encodeURI". */ + { + .type = NJS_PROPERTY, + .name = njs_string("name"), + .value = njs_string("encodeURI"), + }, + + /* encodeURI.length == 1. */ + { + .type = NJS_PROPERTY, + .name = njs_string("length"), + .value = njs_value(NJS_NUMBER, 1, 1.0), + }, }; const njs_object_init_t njs_encode_uri_function_init = { nxt_string("encodeURI"), - NULL, - 0, + njs_encode_uri_function_properties, + nxt_nitems(njs_encode_uri_function_properties), +}; + + +static const njs_object_prop_t njs_encode_uri_component_function_properties[] = +{ + /* encodeURIComponent.name == "encodeURIComponent". */ + { + .type = NJS_PROPERTY, + .name = njs_string("name"), + .value = njs_long_string("encodeURIComponent"), + }, + + /* encodeURIComponent.length == 1. */ + { + .type = NJS_PROPERTY, + .name = njs_string("length"), + .value = njs_value(NJS_NUMBER, 1, 1.0), + }, }; const njs_object_init_t njs_encode_uri_component_function_init = { nxt_string("encodeURIComponent"), - NULL, - 0, + njs_encode_uri_component_function_properties, + nxt_nitems(njs_encode_uri_component_function_properties), +}; + + +static const njs_object_prop_t njs_decode_uri_function_properties[] = +{ + /* decodeURI.name == "decodeURI". */ + { + .type = NJS_PROPERTY, + .name = njs_string("name"), + .value = njs_string("decodeURI"), + }, + + /* decodeURI.length == 1. */ + { + .type = NJS_PROPERTY, + .name = njs_string("length"), + .value = njs_value(NJS_NUMBER, 1, 1.0), + }, }; const njs_object_init_t njs_decode_uri_function_init = { nxt_string("decodeURI"), - NULL, - 0, + njs_decode_uri_function_properties, + nxt_nitems(njs_decode_uri_function_properties), +}; + + +static const njs_object_prop_t njs_decode_uri_component_function_properties[] = +{ + /* decodeURIComponent.name == "decodeURIComponent". */ + { + .type = NJS_PROPERTY, + .name = njs_string("name"), + .value = njs_long_string("decodeURIComponent"), + }, + + /* decodeURIComponent.length == 1. */ + { + .type = NJS_PROPERTY, + .name = njs_string("length"), + .value = njs_value(NJS_NUMBER, 1, 1.0), + }, }; const njs_object_init_t njs_decode_uri_component_function_init = { nxt_string("decodeURIComponent"), - NULL, - 0, + njs_decode_uri_component_function_properties, + nxt_nitems(njs_decode_uri_component_function_properties), }; diff -r ff7760036c67 -r 1213e0a2b485 njs/njs_string.h --- a/njs/njs_string.h Thu Apr 11 21:24:16 2019 +0300 +++ b/njs/njs_string.h Fri Apr 12 18:36:02 2019 +0300 @@ -177,6 +177,7 @@ njs_index_t njs_value_index(njs_vm_t *vm extern const njs_object_init_t njs_string_constructor_init; extern const njs_object_init_t njs_string_prototype_init; +extern const njs_object_init_t njs_string_instance_init; extern const njs_object_init_t njs_to_string_function_init; extern const njs_object_init_t njs_encode_uri_function_init; diff -r ff7760036c67 -r 1213e0a2b485 njs/njs_vm.h --- a/njs/njs_vm.h Thu Apr 11 21:24:16 2019 +0300 +++ b/njs/njs_vm.h Fri Apr 12 18:36:02 2019 +0300 @@ -1078,6 +1078,8 @@ struct njs_vm_s { */ njs_object_t memory_error_object; + njs_object_t string_object; + nxt_array_t *code; /* of njs_vm_code_t */ nxt_trace_t trace; @@ -1108,9 +1110,12 @@ typedef struct { struct njs_vm_shared_s { nxt_lvlhsh_t keywords_hash; nxt_lvlhsh_t values_hash; - nxt_lvlhsh_t function_prototype_hash; - nxt_lvlhsh_t arguments_object_hash; + nxt_lvlhsh_t array_instance_hash; + nxt_lvlhsh_t string_instance_hash; + nxt_lvlhsh_t function_instance_hash; + nxt_lvlhsh_t arguments_object_instance_hash; + njs_object_t string_object; njs_object_t objects[NJS_OBJECT_MAX]; njs_function_t functions[NJS_FUNCTION_MAX]; diff -r ff7760036c67 -r 1213e0a2b485 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Thu Apr 11 21:24:16 2019 +0300 +++ b/njs/test/njs_unit_test.c Fri Apr 12 18:36:02 2019 +0300 @@ -3134,7 +3134,7 @@ static njs_unit_test_t njs_test[] = nxt_string("true") }, { nxt_string("var a = [1,2]; delete a.length"), - nxt_string("false") }, + nxt_string("TypeError: Cannot delete property \"length\" of array") }, { nxt_string("var a = [1,2,3]; a.x = 10; delete a[1]"), nxt_string("true") }, @@ -5638,6 +5638,12 @@ static njs_unit_test_t njs_test[] = { nxt_string("String.bytesFrom('QUJDRA#', 'base64url')"), nxt_string("ABCD") }, + { nxt_string("encodeURI.name"), + nxt_string("encodeURI")}, + + { nxt_string("encodeURI.length"), + nxt_string("1")}, + { nxt_string("encodeURI()"), nxt_string("undefined")}, @@ -5647,9 +5653,21 @@ static njs_unit_test_t njs_test[] = { nxt_string("encodeURI('~}|{`_^]\\\\[@?>=<;:/.-,+*)(\\\'&%$#\"! ')"), nxt_string("~%7D%7C%7B%60_%5E%5D%5C%5B@?%3E=%3C;:/.-,+*)('&%25$#%22!%20")}, + { nxt_string("encodeURIComponent.name"), + nxt_string("encodeURIComponent")}, + + { nxt_string("encodeURIComponent.length"), + nxt_string("1")}, + { nxt_string("encodeURIComponent('~}|{`_^]\\\\[@?>=<;:/.-,+*)(\\\'&%$#\"! ')"), nxt_string("~%7D%7C%7B%60_%5E%5D%5C%5B%40%3F%3E%3D%3C%3B%3A%2F.-%2C%2B*)('%26%25%24%23%22!%20")}, + { nxt_string("decodeURI.name"), + nxt_string("decodeURI")}, + + { nxt_string("decodeURI.length"), + nxt_string("1")}, + { nxt_string("decodeURI()"), nxt_string("undefined")}, @@ -5671,6 +5689,12 @@ static njs_unit_test_t njs_test[] = { nxt_string("decodeURI('%7e%7d%7c%7b%60%5f%5e%5d%5c%5b%40%3f%3e%3d%3c%3b%3a%2f%2e%2c%2b%2a%29%28%27%26%25%24%23%22%21%20')"), nxt_string("~}|{`_^]\\[%40%3f>%3d<%3b%3a%2f.%2c%2b*)('%26%%24%23\"! ")}, + { nxt_string("decodeURIComponent.name"), + nxt_string("decodeURIComponent")}, + + { nxt_string("decodeURIComponent.length"), + nxt_string("1")}, + { nxt_string("decodeURIComponent('%7e%7d%7c%7b%60%5f%5e%5d%5c%5b%40%3f%3e%3d%3c%3b%3a%2f%2e%2c%2b%2a%29%28%27%26%25%24%23%22%21%20')"), nxt_string("~}|{`_^]\\[@?>=<;:/.,+*)('&%$#\"! ")}, @@ -7700,6 +7724,9 @@ static njs_unit_test_t njs_test[] = { nxt_string("Array.prototype"), nxt_string("") }, + { nxt_string("Array.prototype.length"), + nxt_string("0") }, + { nxt_string("Array.constructor === Function"), nxt_string("true") }, @@ -8132,6 +8159,9 @@ static njs_unit_test_t njs_test[] = { nxt_string("Function.prototype"), nxt_string("[object Function]") }, + { nxt_string("Function.prototype.length"), + nxt_string("0") }, + { nxt_string("Function.constructor === Function"), nxt_string("true") }, @@ -8801,10 +8831,10 @@ static njs_unit_test_t njs_test[] = nxt_string("a,b") }, { nxt_string("Object.getOwnPropertyNames(Object.defineProperty([], 'b', {}))"), - nxt_string("length,b") }, + nxt_string("b,length") }, { nxt_string("Object.getOwnPropertyNames(Object.defineProperty(new String(), 'b', {}))"), - nxt_string("length,b") }, + nxt_string("b,length") }, { nxt_string("Object.getOwnPropertyNames([1,2,3])"), nxt_string("0,1,2,length") }, @@ -10483,6 +10513,12 @@ static njs_unit_test_t njs_test[] = { nxt_string("isNaN"), nxt_string("[object Function]") }, + { nxt_string("isNaN.name"), + nxt_string("isNaN") }, + + { nxt_string("isNaN.length"), + nxt_string("1") }, + { nxt_string("isNaN()"), nxt_string("true") }, @@ -10501,6 +10537,12 @@ static njs_unit_test_t njs_test[] = { nxt_string("isFinite"), nxt_string("[object Function]") }, + { nxt_string("isFinite.name"), + nxt_string("isFinite") }, From mdounin at mdounin.ru Fri Apr 12 16:09:07 2019 From: mdounin at mdounin.ru (Maxim Dounin) Date: Fri, 12 Apr 2019 19:09:07 +0300 Subject: [PATCH] Avoid multiple bind for the same address during config test In-Reply-To: <549f07c848d82ef152ed.1555076169@08319b44732f> References: <549f07c848d82ef152ed.1555076169@08319b44732f> Message-ID: <20190412160907.GK1877@mdounin.ru> Hello! On Fri, Apr 12, 2019 at 01:36:09PM +0000, i at morfi.ru wrote: > # HG changeset patch > # User Andrey Kolyshkin > # Date 1555075759 -10800 > # Fri Apr 12 16:29:19 2019 +0300 > # Node ID 549f07c848d82ef152ed54f31b25dcfe89452a66 > # Parent 5155d0296a5ef9841f035920527ffdb771076b44 > Avoid multiple bind for the same address during config test > > If reuseport is specified in the config, then during config test nginx makes multiple calls to the bind function for the same address. > It causes a problem when large number of connections goes to the server and bind (inet_csk_bind_conflict) loads cpu multiple times. > After fixing, bind is called only 1 time per address while testing of the config. > > diff -r 5155d0296a5e -r 549f07c848d8 src/core/ngx_connection.c > --- a/src/core/ngx_connection.c Tue Apr 09 16:00:30 2019 +0300 > +++ b/src/core/ngx_connection.c Fri Apr 12 16:29:19 2019 +0300 > @@ -104,7 +104,7 @@ > ngx_core_conf_t *ccf; > ngx_listening_t ols; > > - if (!ls->reuseport || ls->worker != 0) { > + if (!ls->reuseport || ls->worker != 0 || ngx_test_config) { > return NGX_OK; > } > Thank you for the patch. Configuration testing is expected to do the same thing as normal process of applying configuration, except when it is not possible to do so due to external limitations. Trying to optimize various places when testing configuration to minimize resource consumption looks like a wrong way to go, as a) you'll anyway end up with the resource usage in question when actually applying the configuration, and b) doing so makes configuration testing less likely to catch various problems. If you have problems due to resource usage during configuration testing, consider re-evaluating your configuration to reduce resource usage, and/or consider calling configuration testing less often or on dedicated servers. -- Maxim Dounin http://mdounin.ru/ From xeioex at nginx.com Fri Apr 12 16:58:14 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Fri, 12 Apr 2019 16:58:14 +0000 Subject: [njs] Added support for module mode of execution. Message-ID: details: https://hg.nginx.org/njs/rev/f582672967ad branches: changeset: 886:f582672967ad user: Dmitry Volyntsev date: Wed Apr 10 17:46:29 2019 +0300 description: Added support for module mode of execution. According to ES6:15.2 global this is undefined in module mode. diffstat: njs/njs.h | 1 + njs/njs_generator.c | 13 ++++++++++++- njs/njs_parser_terminal.c | 5 +++++ njs/njs_shell.c | 34 +++++++++++++++++++++++++++------- njs/test/njs_expect_test.exp | 12 ++++++++++++ 5 files changed, 57 insertions(+), 8 deletions(-) diffs (144 lines): diff -r 1213e0a2b485 -r f582672967ad njs/njs.h --- a/njs/njs.h Fri Apr 12 18:36:02 2019 +0300 +++ b/njs/njs.h Wed Apr 10 17:46:29 2019 +0300 @@ -148,6 +148,7 @@ typedef struct { uint8_t accumulative; /* 1 bit */ uint8_t backtrace; /* 1 bit */ uint8_t sandbox; /* 1 bit */ + uint8_t module; /* 1 bit */ } njs_vm_opt_t; diff -r 1213e0a2b485 -r f582672967ad njs/njs_generator.c --- a/njs/njs_generator.c Fri Apr 12 18:36:02 2019 +0300 +++ b/njs/njs_generator.c Wed Apr 10 17:46:29 2019 +0300 @@ -382,7 +382,6 @@ njs_generator(njs_vm_t *vm, njs_generato case NJS_TOKEN_NUMBER: case NJS_TOKEN_STRING: node->index = njs_value_index(vm, &node->u.value, generator->runtime); - if (nxt_fast_path(node->index != NJS_INDEX_NONE)) { return NXT_OK; } @@ -431,6 +430,18 @@ njs_generator(njs_vm_t *vm, njs_generato return njs_generate_name(vm, generator, node); case NJS_TOKEN_GLOBAL_THIS: + if (vm->options.module) { + node->index = njs_value_index(vm, &node->u.value, + generator->runtime); + if (nxt_fast_path(node->index != NJS_INDEX_NONE)) { + return NXT_OK; + } + + return NXT_ERROR; + } + + /* Fall through. */ + case NJS_TOKEN_NJS: case NJS_TOKEN_MATH: case NJS_TOKEN_JSON: diff -r 1213e0a2b485 -r f582672967ad njs/njs_parser_terminal.c --- a/njs/njs_parser_terminal.c Fri Apr 12 18:36:02 2019 +0300 +++ b/njs/njs_parser_terminal.c Wed Apr 10 17:46:29 2019 +0300 @@ -228,6 +228,11 @@ njs_parser_reference(njs_vm_t *vm, njs_p node->token = NJS_TOKEN_GLOBAL_THIS; + if (vm->options.module) { + node->u.value = njs_value_undefined; + break; + } + /* Fall through. */ case NJS_TOKEN_NJS: diff -r 1213e0a2b485 -r f582672967ad njs/njs_shell.c --- a/njs/njs_shell.c Fri Apr 12 18:36:02 2019 +0300 +++ b/njs/njs_shell.c Wed Apr 10 17:46:29 2019 +0300 @@ -35,6 +35,7 @@ typedef struct { nxt_int_t interactive; nxt_int_t sandbox; nxt_int_t quiet; + nxt_int_t module; } njs_opts_t; @@ -248,6 +249,7 @@ main(int argc, char **argv) vm_options.accumulative = opts.interactive; vm_options.backtrace = 1; vm_options.sandbox = opts.sandbox; + vm_options.module = opts.module; vm_options.ops = &njs_console_ops; vm_options.external = &njs_console; @@ -278,12 +280,13 @@ njs_get_options(njs_opts_t *opts, int ar "Interactive njs shell.\n" "\n" "Options:\n" - " -d print disassembled code.\n" - " -q disable interactive introduction prompt.\n" - " -s sandbox mode.\n" - " -p set path prefix for modules.\n" - " -v print njs version and exit.\n" - " | - run code from a file or stdin.\n"; + " -d print disassembled code.\n" + " -q disable interactive introduction prompt.\n" + " -s sandbox mode.\n" + " -t script|module source code type (script is default).\n" + " -p set path prefix for modules.\n" + " -v print njs version and exit.\n" + " | - run code from a file or stdin.\n"; ret = NXT_DONE; @@ -317,8 +320,25 @@ njs_get_options(njs_opts_t *opts, int ar opts->sandbox = 1; break; + case 't': + if (++i < argc) { + if (strcmp(argv[i], "module") == 0) { + opts->module = 1; + + } else if (strcmp(argv[i], "script") != 0) { + nxt_error("option \"-t\" unexpected source type: %s\n", + argv[i]); + return NXT_ERROR; + } + + break; + } + + nxt_error("option \"-t\" requires source type\n"); + return NXT_ERROR; + case 'p': - if (argv[++i] != NULL) { + if (++i < argc) { opts->n_paths++; paths = realloc(opts->paths, opts->n_paths * sizeof(char *)); if (paths == NULL) { diff -r 1213e0a2b485 -r f582672967ad njs/test/njs_expect_test.exp --- a/njs/test/njs_expect_test.exp Fri Apr 12 18:36:02 2019 +0300 +++ b/njs/test/njs_expect_test.exp Wed Apr 10 17:46:29 2019 +0300 @@ -658,6 +658,18 @@ njs_test { "undefined\r\n"} } "-s" +# source type + +njs_test { + {"this\r\n" + "this\r\nundefined"} +} "-t module" + +njs_test { + {"this.NaN\r\n" + "this.NaN\r\nNaN"} +} "-t script" + # modules njs_test { From xeioex at nginx.com Fri Apr 12 16:58:15 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Fri, 12 Apr 2019 16:58:15 +0000 Subject: [njs] This object as a variable. Message-ID: details: https://hg.nginx.org/njs/rev/070b635928a9 branches: changeset: 887:070b635928a9 user: Dmitry Volyntsev date: Wed Apr 10 17:46:29 2019 +0300 description: This object as a variable. Non-local this is introduced to support arrow functions. this is non-local when reference scope != first non-arrow function scope. diffstat: njs/njs_disassembler.c | 2 ++ njs/njs_generator.c | 8 ++++++++ njs/njs_lexer.h | 1 + njs/njs_parser.h | 15 +++++++++++++++ njs/njs_parser_terminal.c | 28 ++++++++++++++++++++++++++-- njs/njs_variable.h | 1 + njs/njs_vm.c | 17 +++++++++++++++++ njs/njs_vm.h | 8 ++++++++ 8 files changed, 78 insertions(+), 2 deletions(-) diffs (187 lines): diff -r f582672967ad -r 070b635928a9 njs/njs_disassembler.c --- a/njs/njs_disassembler.c Wed Apr 10 17:46:29 2019 +0300 +++ b/njs/njs_disassembler.c Wed Apr 10 17:46:29 2019 +0300 @@ -23,6 +23,8 @@ static njs_code_name_t code_names[] = { nxt_string("OBJECT ") }, { njs_vmcode_function, sizeof(njs_vmcode_function_t), nxt_string("FUNCTION ") }, + { njs_vmcode_this, sizeof(njs_vmcode_this_t), + nxt_string("THIS ") }, { njs_vmcode_arguments, sizeof(njs_vmcode_arguments_t), nxt_string("ARGUMENTS ") }, { njs_vmcode_regexp, sizeof(njs_vmcode_regexp_t), diff -r f582672967ad -r 070b635928a9 njs/njs_generator.c --- a/njs/njs_generator.c Wed Apr 10 17:46:29 2019 +0300 +++ b/njs/njs_generator.c Wed Apr 10 17:46:29 2019 +0300 @@ -427,6 +427,7 @@ njs_generator(njs_vm_t *vm, njs_generato case NJS_TOKEN_NAME: case NJS_TOKEN_ARGUMENTS: + case NJS_TOKEN_NON_LOCAL_THIS: return njs_generate_name(vm, generator, node); case NJS_TOKEN_GLOBAL_THIS: @@ -2414,6 +2415,7 @@ njs_generate_lambda_variables(njs_vm_t * njs_variable_t *var; njs_vmcode_move_t *move; nxt_lvlhsh_each_t lhe; + njs_vmcode_this_t *this; njs_vmcode_arguments_t *arguments; nxt_lvlhsh_each_init(&lhe, &njs_variables_hash_proto); @@ -2431,6 +2433,12 @@ njs_generate_lambda_variables(njs_vm_t * njs_generate_code_move(generator, move, var->index, index); } + if (var->this_object) { + njs_generate_code(generator, njs_vmcode_this_t, this, + njs_vmcode_this, 1, 0); + this->dst = var->index; + } + if (var->arguments_object) { njs_generate_code(generator, njs_vmcode_arguments_t, arguments, njs_vmcode_arguments, 1, 0); diff -r f582672967ad -r 070b635928a9 njs/njs_lexer.h --- a/njs/njs_lexer.h Wed Apr 10 17:46:29 2019 +0300 +++ b/njs/njs_lexer.h Wed Apr 10 17:46:29 2019 +0300 @@ -159,6 +159,7 @@ typedef enum { NJS_TOKEN_THROW, NJS_TOKEN_THIS, + NJS_TOKEN_NON_LOCAL_THIS, NJS_TOKEN_ARGUMENTS, #define NJS_TOKEN_FIRST_OBJECT NJS_TOKEN_GLOBAL_THIS diff -r f582672967ad -r 070b635928a9 njs/njs_parser.h --- a/njs/njs_parser.h Wed Apr 10 17:46:29 2019 +0300 +++ b/njs/njs_parser.h Wed Apr 10 17:46:29 2019 +0300 @@ -225,6 +225,21 @@ njs_parser_global_scope(njs_vm_t *vm) } +nxt_inline njs_parser_scope_t * +njs_function_scope(njs_parser_scope_t *scope) +{ + while (scope->type != NJS_SCOPE_GLOBAL) { + if (scope->type == NJS_SCOPE_FUNCTION) { + return scope; + } + + scope = scope->parent; + } + + return NULL; +} + + extern const nxt_lvlhsh_proto_t njs_keyword_hash_proto; diff -r f582672967ad -r 070b635928a9 njs/njs_parser_terminal.c --- a/njs/njs_parser_terminal.c Wed Apr 10 17:46:29 2019 +0300 +++ b/njs/njs_parser_terminal.c Wed Apr 10 17:46:29 2019 +0300 @@ -215,14 +215,38 @@ njs_parser_reference(njs_vm_t *vm, njs_p while (scope->type != NJS_SCOPE_GLOBAL) { if (scope->type == NJS_SCOPE_FUNCTION) { - node->index = NJS_INDEX_THIS; break; } scope = scope->parent; } - if (node->index == NJS_INDEX_THIS) { + if (scope->type != NJS_SCOPE_GLOBAL) { + if (njs_function_scope(scope) + == njs_function_scope(parser->scope)) + { + node->index = NJS_INDEX_THIS; + + } else { + node->token = NJS_TOKEN_NON_LOCAL_THIS; + + node->token_line = token_line; + + ret = njs_variable_reference(vm, parser->scope, node, name, + hash, NJS_REFERENCE); + if (nxt_slow_path(ret != NXT_OK)) { + return NULL; + } + + var = njs_variable_add(vm, parser->scope, name, hash, + NJS_VARIABLE_VAR); + if (nxt_slow_path(var == NULL)) { + return NULL; + } + + var->this_object = 1; + } + break; } diff -r f582672967ad -r 070b635928a9 njs/njs_variable.h --- a/njs/njs_variable.h Wed Apr 10 17:46:29 2019 +0300 +++ b/njs/njs_variable.h Wed Apr 10 17:46:29 2019 +0300 @@ -23,6 +23,7 @@ typedef struct { njs_variable_type_t type:8; /* 3 bits */ uint8_t argument; + uint8_t this_object; uint8_t arguments_object; njs_index_t index; diff -r f582672967ad -r 070b635928a9 njs/njs_vm.c --- a/njs/njs_vm.c Wed Apr 10 17:46:29 2019 +0300 +++ b/njs/njs_vm.c Wed Apr 10 17:46:29 2019 +0300 @@ -391,6 +391,23 @@ njs_vmcode_function(njs_vm_t *vm, njs_va njs_ret_t +njs_vmcode_this(njs_vm_t *vm, njs_value_t *invld1, njs_value_t *invld2) +{ + njs_frame_t *frame; + njs_value_t *value; + njs_vmcode_this_t *code; + + frame = (njs_frame_t *) vm->active_frame; + code = (njs_vmcode_this_t *) vm->current; + + value = njs_vmcode_operand(vm, code->dst); + *value = frame->native.arguments[0]; + + return sizeof(njs_vmcode_this_t); +} + + +njs_ret_t njs_vmcode_arguments(njs_vm_t *vm, njs_value_t *invld1, njs_value_t *invld2) { nxt_int_t ret; diff -r f582672967ad -r 070b635928a9 njs/njs_vm.h --- a/njs/njs_vm.h Wed Apr 10 17:46:29 2019 +0300 +++ b/njs/njs_vm.h Wed Apr 10 17:46:29 2019 +0300 @@ -638,6 +638,12 @@ typedef struct { typedef struct { + njs_vmcode_t code; + njs_index_t dst; +} njs_vmcode_this_t; + + +typedef struct { njs_vmcode_t code; njs_index_t dst; } njs_vmcode_arguments_t; @@ -1141,6 +1147,8 @@ njs_ret_t njs_vmcode_array(njs_vm_t *vm, njs_value_t *inlvd2); njs_ret_t njs_vmcode_function(njs_vm_t *vm, njs_value_t *inlvd1, njs_value_t *invld2); +njs_ret_t njs_vmcode_this(njs_vm_t *vm, njs_value_t *inlvd1, + njs_value_t *invld2); njs_ret_t njs_vmcode_arguments(njs_vm_t *vm, njs_value_t *inlvd1, njs_value_t *invld2); njs_ret_t njs_vmcode_regexp(njs_vm_t *vm, njs_value_t *inlvd1, From xeioex at nginx.com Fri Apr 12 16:58:15 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Fri, 12 Apr 2019 16:58:15 +0000 Subject: [njs] Added arrow function support. Message-ID: details: https://hg.nginx.org/njs/rev/d7a0eb59a7e7 branches: changeset: 888:d7a0eb59a7e7 user: hongzhidao date: Sun Apr 07 14:26:13 2019 +0800 description: Added arrow function support. This closes #106 issue on Github. In collaboration with Artem S. Povalyukhin. diffstat: njs/njs_builtin.c | 6 + njs/njs_extern.c | 3 +- njs/njs_function.c | 27 ++++++- njs/njs_function.h | 2 + njs/njs_lexer.c | 1 + njs/njs_lexer.h | 1 + njs/njs_object.c | 7 +- njs/njs_parser.c | 166 +++++++++++++++++++++++++++++++++++++++++++ njs/njs_parser.h | 11 ++- njs/njs_parser_terminal.c | 36 ++++----- njs/njs_vm.h | 1 + njs/test/njs_expect_test.exp | 2 + njs/test/njs_unit_test.c | 144 +++++++++++++++++++++++++++++++++++++ 13 files changed, 381 insertions(+), 26 deletions(-) diffs (633 lines): diff -r 070b635928a9 -r d7a0eb59a7e7 njs/njs_builtin.c --- a/njs/njs_builtin.c Wed Apr 10 17:46:29 2019 +0300 +++ b/njs/njs_builtin.c Sun Apr 07 14:26:13 2019 +0800 @@ -257,6 +257,12 @@ njs_builtin_objects_create(njs_vm_t *vm) return NXT_ERROR; } + ret = njs_object_hash_init(vm, &shared->arrow_instance_hash, + &njs_arrow_instance_init); + if (nxt_slow_path(ret != NXT_OK)) { + return NXT_ERROR; + } + ret = njs_object_hash_init(vm, &shared->arguments_object_instance_hash, &njs_arguments_object_instance_init); if (nxt_slow_path(ret != NXT_OK)) { diff -r 070b635928a9 -r d7a0eb59a7e7 njs/njs_extern.c --- a/njs/njs_extern.c Wed Apr 10 17:46:29 2019 +0300 +++ b/njs/njs_extern.c Sun Apr 07 14:26:13 2019 +0800 @@ -105,11 +105,12 @@ njs_vm_external_add(njs_vm_t *vm, nxt_lv * nxt_mp_zalloc() does also: * nxt_lvlhsh_init(&function->object.hash); * function->object.__proto__ = NULL; + * function->ctor = 0; */ function->object.__proto__ = &vm->prototypes[NJS_CONSTRUCTOR_FUNCTION].object; - function->object.shared_hash = vm->shared->function_instance_hash; + function->object.shared_hash = vm->shared->arrow_instance_hash; function->object.type = NJS_FUNCTION; function->object.shared = 1; function->object.extensible = 1; diff -r 070b635928a9 -r d7a0eb59a7e7 njs/njs_function.c --- a/njs/njs_function.c Wed Apr 10 17:46:29 2019 +0300 +++ b/njs/njs_function.c Sun Apr 07 14:26:13 2019 +0800 @@ -38,11 +38,17 @@ njs_function_alloc(njs_vm_t *vm, njs_fun * function->object.__proto__ = NULL; */ - function->ctor = 1; + function->ctor = !lambda->arrow; function->args_offset = 1; function->u.lambda = lambda; - function->object.shared_hash = vm->shared->function_instance_hash; + if (lambda->arrow || !function->ctor) { + function->object.shared_hash = vm->shared->arrow_instance_hash; + + } else { + function->object.shared_hash = vm->shared->function_instance_hash; + } + function->object.__proto__ = &vm->prototypes[NJS_PROTOTYPE_FUNCTION].object; function->object.type = NJS_FUNCTION; function->object.shared = shared; @@ -1195,6 +1201,23 @@ const njs_object_init_t njs_function_in }; +const njs_object_prop_t njs_arrow_instance_properties[] = +{ + { + .type = NJS_PROPERTY_HANDLER, + .name = njs_string("length"), + .value = njs_prop_handler(njs_function_instance_length), + }, +}; + + +const njs_object_init_t njs_arrow_instance_init = { + nxt_string("Arrow instance"), + njs_arrow_instance_properties, + nxt_nitems(njs_arrow_instance_properties), +}; + + njs_ret_t njs_eval_function(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused) diff -r 070b635928a9 -r d7a0eb59a7e7 njs/njs_function.h --- a/njs/njs_function.h Wed Apr 10 17:46:29 2019 +0300 +++ b/njs/njs_function.h Sun Apr 07 14:26:13 2019 +0800 @@ -30,6 +30,7 @@ struct njs_function_lambda_s { /* Function internal block closures levels. */ uint8_t block_closures; /* 4 bits */ + uint8_t arrow; /* 1 bit */ uint8_t rest_parameters; /* 1 bit */ /* Initial values of local scope. */ @@ -218,6 +219,7 @@ njs_function_previous_frame(njs_native_f extern const njs_object_init_t njs_function_constructor_init; extern const njs_object_init_t njs_function_prototype_init; extern const njs_object_init_t njs_function_instance_init; +extern const njs_object_init_t njs_arrow_instance_init; extern const njs_object_init_t njs_arguments_object_instance_init; njs_ret_t njs_eval_function(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, diff -r 070b635928a9 -r d7a0eb59a7e7 njs/njs_lexer.c --- a/njs/njs_lexer.c Wed Apr 10 17:46:29 2019 +0300 +++ b/njs/njs_lexer.c Sun Apr 07 14:26:13 2019 +0800 @@ -278,6 +278,7 @@ static const njs_lexer_multi_t njs_grea static const njs_lexer_multi_t njs_assignment_token[] = { { '=', NJS_TOKEN_EQUAL, 1, njs_strict_equal_token }, + { '>', NJS_TOKEN_ARROW, 0, NULL }, }; diff -r 070b635928a9 -r d7a0eb59a7e7 njs/njs_lexer.h --- a/njs/njs_lexer.h Wed Apr 10 17:46:29 2019 +0300 +++ b/njs/njs_lexer.h Sun Apr 07 14:26:13 2019 +0800 @@ -36,6 +36,7 @@ typedef enum { NJS_TOKEN_CONDITIONAL, NJS_TOKEN_ASSIGNMENT, + NJS_TOKEN_ARROW, NJS_TOKEN_ADDITION_ASSIGNMENT, NJS_TOKEN_SUBSTRACTION_ASSIGNMENT, NJS_TOKEN_MULTIPLICATION_ASSIGNMENT, diff -r 070b635928a9 -r d7a0eb59a7e7 njs/njs_object.c --- a/njs/njs_object.c Wed Apr 10 17:46:29 2019 +0300 +++ b/njs/njs_object.c Sun Apr 07 14:26:13 2019 +0800 @@ -764,7 +764,12 @@ njs_method_private_copy(njs_vm_t *vm, nj return NXT_ERROR; } - function->object.shared_hash = vm->shared->function_instance_hash; + if (function->ctor) { + function->object.shared_hash = vm->shared->function_instance_hash; + + } else { + function->object.shared_hash = vm->shared->arrow_instance_hash; + } pq->lhq.replace = 0; pq->lhq.value = prop; diff -r 070b635928a9 -r d7a0eb59a7e7 njs/njs_parser.c --- a/njs/njs_parser.c Wed Apr 10 17:46:29 2019 +0300 +++ b/njs/njs_parser.c Sun Apr 07 14:26:13 2019 +0800 @@ -2103,6 +2103,172 @@ njs_parser_property_token(njs_vm_t *vm, } +nxt_int_t +njs_parser_match_arrow_expression(njs_vm_t *vm, njs_parser_t *parser, + njs_token_t token) +{ + size_t offset; + nxt_bool_t rest_parameters; + + if (token != NJS_TOKEN_OPEN_PARENTHESIS && token != NJS_TOKEN_NAME) { + return NXT_DECLINED; + } + + offset = 0; + + if (token == NJS_TOKEN_NAME) { + goto arrow; + } + + token = njs_parser_peek_token(vm, parser, &offset); + if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { + return NXT_DECLINED; + } + + rest_parameters = 0; + + while (token != NJS_TOKEN_CLOSE_PARENTHESIS) { + + if (rest_parameters) { + return NXT_DECLINED; + } + + if (nxt_slow_path(token == NJS_TOKEN_ELLIPSIS)) { + rest_parameters = 1; + + token = njs_parser_peek_token(vm, parser, &offset); + if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { + return NXT_DECLINED; + } + } + + if (nxt_slow_path(token != NJS_TOKEN_NAME)) { + return NXT_DECLINED; + } + + token = njs_parser_peek_token(vm, parser, &offset); + if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { + return token; + } + + if (token == NJS_TOKEN_COMMA) { + token = njs_parser_peek_token(vm, parser, &offset); + if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { + return NXT_DECLINED; + } + } + } + +arrow: + + token = njs_parser_peek_token(vm, parser, &offset); + if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { + return NXT_DECLINED; + } + + if (parser->lexer->prev_token == NJS_TOKEN_LINE_END) { + return NXT_DECLINED; + } + + if (nxt_slow_path(token != NJS_TOKEN_ARROW)) { + return NXT_DECLINED; + } + + return NXT_OK; +} + + +njs_token_t +njs_parser_arrow_expression(njs_vm_t *vm, njs_parser_t *parser, + njs_token_t token) +{ + njs_ret_t ret; + njs_index_t index; + njs_parser_node_t *node, *body, *parent; + njs_function_lambda_t *lambda; + + node = njs_parser_node_new(vm, parser, NJS_TOKEN_FUNCTION_EXPRESSION); + if (nxt_slow_path(node == NULL)) { + return NJS_TOKEN_ERROR; + } + + node->token_line = njs_parser_token_line(parser); + parser->node = node; + + lambda = nxt_mp_zalloc(vm->mem_pool, sizeof(njs_function_lambda_t)); + if (nxt_slow_path(lambda == NULL)) { + return NJS_TOKEN_ERROR; + } + + lambda->arrow = 1; + + node->u.value.data.u.lambda = lambda; + + ret = njs_parser_scope_begin(vm, parser, NJS_SCOPE_FUNCTION); + if (nxt_slow_path(ret != NXT_OK)) { + return NJS_TOKEN_ERROR; + } + + parser->scope->arrow_function = 1; + + index = NJS_SCOPE_ARGUMENTS; + + /* A "this" reservation. */ + index += sizeof(njs_value_t); + + if (token == NJS_TOKEN_OPEN_PARENTHESIS) { + token = njs_parser_lambda_arguments(vm, parser, lambda, index, token); + if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { + return token; + } + + } else { + token = njs_parser_lambda_argument(vm, parser, index); + if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { + return token; + } + + lambda->nargs = 1; + } + + if (parser->lexer->prev_token == NJS_TOKEN_LINE_END) { + return NJS_TOKEN_ILLEGAL; + } + + token = njs_parser_match(vm, parser, token, NJS_TOKEN_ARROW); + if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { + return token; + } + + if (token == NJS_TOKEN_OPEN_BRACE) { + token = njs_parser_lambda_body(vm, parser, token); + if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { + return token; + } + + } else { + parent = parser->node; + + token = njs_parser_assignment_expression(vm, parser, token); + if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { + return token; + } + + body = njs_parser_return_set(vm, parser, parser->node); + if (nxt_slow_path(body == NULL)) { + return NJS_TOKEN_ERROR; + } + + parent->right = body; + parser->node = parent; + } + + njs_parser_scope_end(vm, parser); + + return token; +} + + nxt_bool_t njs_parser_has_side_effect(njs_parser_node_t *node) { diff -r 070b635928a9 -r d7a0eb59a7e7 njs/njs_parser.h --- a/njs/njs_parser.h Wed Apr 10 17:46:29 2019 +0300 +++ b/njs/njs_parser.h Sun Apr 07 14:26:13 2019 +0800 @@ -32,6 +32,7 @@ struct njs_parser_scope_s { uint8_t nesting; /* 4 bits */ uint8_t argument_closures; uint8_t module; + uint8_t arrow_function; }; @@ -81,6 +82,10 @@ njs_token_t njs_parser_expression(njs_vm njs_token_t njs_parser_assignment_expression(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token); njs_token_t njs_parser_function_expression(njs_vm_t *vm, njs_parser_t *parser); +nxt_int_t njs_parser_match_arrow_expression(njs_vm_t *vm, njs_parser_t *parser, + njs_token_t token); +njs_token_t njs_parser_arrow_expression(njs_vm_t *vm, njs_parser_t *parser, + njs_token_t token); njs_token_t njs_parser_module_lambda(njs_vm_t *vm, njs_parser_t *parser); njs_token_t njs_parser_terminal(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token); @@ -226,10 +231,12 @@ njs_parser_global_scope(njs_vm_t *vm) nxt_inline njs_parser_scope_t * -njs_function_scope(njs_parser_scope_t *scope) +njs_function_scope(njs_parser_scope_t *scope, nxt_bool_t any) { while (scope->type != NJS_SCOPE_GLOBAL) { - if (scope->type == NJS_SCOPE_FUNCTION) { + if (scope->type == NJS_SCOPE_FUNCTION + && (any || !scope->arrow_function)) + { return scope; } diff -r 070b635928a9 -r d7a0eb59a7e7 njs/njs_parser_terminal.c --- a/njs/njs_parser_terminal.c Wed Apr 10 17:46:29 2019 +0300 +++ b/njs/njs_parser_terminal.c Sun Apr 07 14:26:13 2019 +0800 @@ -35,6 +35,11 @@ njs_parser_terminal(njs_vm_t *vm, njs_pa njs_ret_t ret; njs_parser_node_t *node; + ret = njs_parser_match_arrow_expression(vm, parser, token); + if (ret == NXT_OK) { + return njs_parser_arrow_expression(vm, parser, token); + } + if (token == NJS_TOKEN_OPEN_PARENTHESIS) { token = njs_parser_token(vm, parser); @@ -211,20 +216,10 @@ njs_parser_reference(njs_vm_t *vm, njs_p case NJS_TOKEN_THIS: nxt_thread_log_debug("JS: this"); - scope = parser->scope; - - while (scope->type != NJS_SCOPE_GLOBAL) { - if (scope->type == NJS_SCOPE_FUNCTION) { - break; - } + scope = njs_function_scope(parser->scope, 0); - scope = scope->parent; - } - - if (scope->type != NJS_SCOPE_GLOBAL) { - if (njs_function_scope(scope) - == njs_function_scope(parser->scope)) - { + if (scope != NULL) { + if (scope == njs_function_scope(parser->scope, 1)) { node->index = NJS_INDEX_THIS; } else { @@ -232,14 +227,13 @@ njs_parser_reference(njs_vm_t *vm, njs_p node->token_line = token_line; - ret = njs_variable_reference(vm, parser->scope, node, name, - hash, NJS_REFERENCE); + ret = njs_variable_reference(vm, scope, node, name, hash, + NJS_REFERENCE); if (nxt_slow_path(ret != NXT_OK)) { return NULL; } - var = njs_variable_add(vm, parser->scope, name, hash, - NJS_VARIABLE_VAR); + var = njs_variable_add(vm, scope, name, hash, NJS_VARIABLE_VAR); if (nxt_slow_path(var == NULL)) { return NULL; } @@ -361,7 +355,9 @@ njs_parser_reference(njs_vm_t *vm, njs_p case NJS_TOKEN_ARGUMENTS: nxt_thread_log_debug("JS: arguments"); - if (parser->scope->type <= NJS_SCOPE_GLOBAL) { + scope = njs_function_scope(parser->scope, 0); + + if (scope == NULL) { njs_parser_syntax_error(vm, parser, "\"%V\" object " "in global scope", name); @@ -370,13 +366,13 @@ njs_parser_reference(njs_vm_t *vm, njs_p node->token_line = token_line; - ret = njs_variable_reference(vm, parser->scope, node, name, hash, + ret = njs_variable_reference(vm, scope, node, name, hash, NJS_REFERENCE); if (nxt_slow_path(ret != NXT_OK)) { return NULL; } - var = njs_variable_add(vm, parser->scope, name, hash, NJS_VARIABLE_VAR); + var = njs_variable_add(vm, scope, name, hash, NJS_VARIABLE_VAR); if (nxt_slow_path(var == NULL)) { return NULL; } diff -r 070b635928a9 -r d7a0eb59a7e7 njs/njs_vm.h --- a/njs/njs_vm.h Wed Apr 10 17:46:29 2019 +0300 +++ b/njs/njs_vm.h Sun Apr 07 14:26:13 2019 +0800 @@ -1119,6 +1119,7 @@ struct njs_vm_shared_s { nxt_lvlhsh_t array_instance_hash; nxt_lvlhsh_t string_instance_hash; nxt_lvlhsh_t function_instance_hash; + nxt_lvlhsh_t arrow_instance_hash; nxt_lvlhsh_t arguments_object_instance_hash; njs_object_t string_object; diff -r 070b635928a9 -r d7a0eb59a7e7 njs/test/njs_expect_test.exp --- a/njs/test/njs_expect_test.exp Wed Apr 10 17:46:29 2019 +0300 +++ b/njs/test/njs_expect_test.exp Sun Apr 07 14:26:13 2019 +0800 @@ -663,6 +663,8 @@ njs_test { njs_test { {"this\r\n" "this\r\nundefined"} + {"(() => this)()\r\n" + "(() => this)()\r\nundefined"} } "-t module" njs_test { diff -r 070b635928a9 -r d7a0eb59a7e7 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Wed Apr 10 17:46:29 2019 +0300 +++ b/njs/test/njs_unit_test.c Sun Apr 07 14:26:13 2019 +0800 @@ -6526,6 +6526,12 @@ static njs_unit_test_t njs_test[] = /* arguments object. */ + { nxt_string("arguments"), + nxt_string("SyntaxError: \"arguments\" object in global scope in 1") }, + + { nxt_string("{arguments}"), + nxt_string("SyntaxError: \"arguments\" object in global scope in 1") }, + { nxt_string("var arguments"), nxt_string("SyntaxError: Identifier \"arguments\" is forbidden in var declaration in 1") }, @@ -6625,6 +6631,138 @@ static njs_unit_test_t njs_test[] = "myFoo(1,2);" ), nxt_string("") }, + /* arrow functions. */ + + { nxt_string("()"), + nxt_string("SyntaxError: Unexpected token \")\" in 1") }, + + { nxt_string("() => "), + nxt_string("SyntaxError: Unexpected end of input in 1") }, + + { nxt_string("() => {"), + nxt_string("SyntaxError: Unexpected end of input in 1") }, + + { nxt_string("a\n => 1"), + nxt_string("SyntaxError: Unexpected token \"=>\" in 2") }, + + { nxt_string("new (()=>1)"), + nxt_string("TypeError: function is not a constructor")}, + + { nxt_string("(\n) => {}"), + nxt_string("[object Function]") }, + + { nxt_string("a => 1"), + nxt_string("[object Function]") }, + + { nxt_string("({f:()=>1, g:()=>2}).f()"), + nxt_string("1") }, + + { nxt_string("var f = f => {return 1;}; f()"), + nxt_string("1") }, + + { nxt_string("var f = (f) => {return 1;}; f()"), + nxt_string("1") }, + + { nxt_string("var f = (f, a, b) => {return 1;}; f()"), + nxt_string("1") }, + + { nxt_string("var f = () => {return 1;}; f()"), + nxt_string("1") }, + + { nxt_string("(f => {return 1;})()"), + nxt_string("1") }, + + { nxt_string("((f) => {return 1;})()"), + nxt_string("1") }, + + { nxt_string("(((f) => {return 1;}))()"), + nxt_string("1") }, + + { nxt_string("var f = f => 1; f()"), + nxt_string("1") }, + + { nxt_string("() => 1"), + nxt_string("[object Function]") }, + + { nxt_string("var f = ()=>{}; f()"), + nxt_string("undefined") }, + + { nxt_string("var f = ()=>({}); f()"), + nxt_string("[object Object]") }, + + { nxt_string("var materials = ['Hydrogen', 'Helium', 'Lithium', 'Beryllium'];" + "materials.map(material => { return material.length; });"), + nxt_string("8,6,7,9") }, + + { nxt_string("var materials = ['Hydrogen', 'Helium', 'Lithium', 'Beryllium'];" + "materials.map(material => material.length);"), + nxt_string("8,6,7,9") }, + + { nxt_string("var materials = ['Hydrogen', 'Helium', 'Lithium', 'Beryllium'];" + "materials.map(material => { material.length });"), + nxt_string(",,,") }, + + { nxt_string("function f(a, b, c) {a = 1; return () => { return arguments[1]; };};" + "f(1, 2, 3)('a', 'b');"), + nxt_string("2") }, + + { nxt_string("var f = (...c) => { return (function() { return arguments.length; }).bind(null, c); };" + "var x = f(1,'a',false, {}); x()"), + nxt_string("1") }, + + { nxt_string("var f = (...c) => { return (function() { return arguments.length; }).bind(null, c); };" + "var x = f(1,'a',false, {}); x(1,2,3)"), + nxt_string("4") }, + + { nxt_string("function Car(){ this.age = 0; (() => { this.age++;})();}" + "(new Car()).age"), + nxt_string("1") }, + + { nxt_string("function Car(){ this.age = 0; (function(){ this.age++;})();}" + "(new Car()).age"), + nxt_string("TypeError: cannot get property \"age\" of undefined") }, + + /* arrow functions + global this. */ + + { nxt_string("(() => this)()"), + nxt_string("[object Object]") }, + + { nxt_string("(() => this).call('abc')"), + nxt_string("[object Object]") }, + + { nxt_string("(() => this).apply('abc')"), + nxt_string("[object Object]") }, + + { nxt_string("(() => this).bind('abc')()"), + nxt_string("[object Object]") }, + + { nxt_string("(function() { return (() => this); })()()"), + nxt_string("undefined") }, + + { nxt_string("(function() { return (() => this); }).call('abc')()"), + nxt_string("abc") }, + + { nxt_string("(function() { return (() => this); }).bind('abc')()()"), + nxt_string("abc") }, + + { nxt_string("(function() { return (() => this); })" + ".call('abc').call('bca')"), + nxt_string("abc") }, + + { nxt_string("(function() { return (() => this); })" + ".call('abc').bind('bca')()"), + nxt_string("abc") }, + + { nxt_string("(function() { return function() { return () => this; }; })" + ".call('bca').call('abc')()"), + nxt_string("abc") }, + + { nxt_string("var f = () => 1; f.prototype"), + nxt_string("undefined") }, + + { nxt_string("var f = (a,b) => 0; f.length"), + nxt_string("2") }, + /* Scopes. */ { nxt_string("function f(x) { a = x } var a; f(5); a"), @@ -7568,6 +7706,9 @@ static njs_unit_test_t njs_test[] = { nxt_string("this.NaN + 1"), nxt_string("NaN") }, + { nxt_string("{this}"), + nxt_string("undefined") }, + { nxt_string("if (1) {new this}"), nxt_string("TypeError: object is not a function") }, @@ -7640,6 +7781,9 @@ static njs_unit_test_t njs_test[] = { nxt_string("Object.prototype"), nxt_string("[object Object]") }, + { nxt_string("Object.prototype.valueOf.prototype"), + nxt_string("undefined") }, + { nxt_string("Object.constructor === Function"), nxt_string("true") }, From xeioex at nginx.com Fri Apr 12 17:49:09 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Fri, 12 Apr 2019 17:49:09 +0000 Subject: [njs] Added quiet option for vm to support bit-exact output in test262. Message-ID: details: https://hg.nginx.org/njs/rev/802fe99c8881 branches: changeset: 889:802fe99c8881 user: Dmitry Volyntsev date: Fri Apr 12 20:48:44 2019 +0300 description: Added quiet option for vm to support bit-exact output in test262. diffstat: njs/njs.h | 1 + njs/njs_generator.c | 9 ++++++++- njs/njs_parser.c | 2 +- njs/njs_shell.c | 26 +++++++++++++------------- njs/test/njs_expect_test.exp | 3 +++ 5 files changed, 26 insertions(+), 15 deletions(-) diffs (99 lines): diff -r d7a0eb59a7e7 -r 802fe99c8881 njs/njs.h --- a/njs/njs.h Sun Apr 07 14:26:13 2019 +0800 +++ b/njs/njs.h Fri Apr 12 20:48:44 2019 +0300 @@ -149,6 +149,7 @@ typedef struct { uint8_t backtrace; /* 1 bit */ uint8_t sandbox; /* 1 bit */ uint8_t module; /* 1 bit */ + uint8_t quiet; /* 1 bit */ } njs_vm_opt_t; diff -r d7a0eb59a7e7 -r 802fe99c8881 njs/njs_generator.c --- a/njs/njs_generator.c Sun Apr 07 14:26:13 2019 +0800 +++ b/njs/njs_generator.c Fri Apr 12 20:48:44 2019 +0300 @@ -3246,7 +3246,14 @@ njs_generate_function_debug(njs_vm_t *vm debug->lambda = lambda; debug->line = node->token_line; - debug->file = node->scope->file; + + if (!vm->options.quiet) { + debug->file = node->scope->file; + + } else { + debug->file = nxt_string_value(""); + } + debug->name = (name != NULL) ? *name : no_label; return NXT_OK; diff -r d7a0eb59a7e7 -r 802fe99c8881 njs/njs_parser.c --- a/njs/njs_parser.c Sun Apr 07 14:26:13 2019 +0800 +++ b/njs/njs_parser.c Fri Apr 12 20:48:44 2019 +0300 @@ -2378,7 +2378,7 @@ njs_parser_scope_error(njs_vm_t *vm, njs p = end - width; } - if (file->length != 0) { + if (file->length != 0 && !vm->options.quiet) { p = nxt_sprintf(p, end, " in %V:%uD", file, line); } else { diff -r d7a0eb59a7e7 -r 802fe99c8881 njs/njs_shell.c --- a/njs/njs_shell.c Sun Apr 07 14:26:13 2019 +0800 +++ b/njs/njs_shell.c Fri Apr 12 20:48:44 2019 +0300 @@ -228,28 +228,28 @@ main(int argc, char **argv) nxt_memzero(&vm_options, sizeof(njs_vm_opt_t)); - if (!opts.quiet) { - if (opts.file == NULL) { - p = getcwd(path, sizeof(path)); - if (p == NULL) { - nxt_error("getcwd() failed:%s\n", strerror(errno)); - ret = NXT_ERROR; - goto done; - } - - memcpy(path + nxt_strlen(path), "/shell", sizeof("/shell")); - opts.file = path; + if (opts.file == NULL) { + p = getcwd(path, sizeof(path)); + if (p == NULL) { + nxt_error("getcwd() failed:%s\n", strerror(errno)); + ret = NXT_ERROR; + goto done; } - vm_options.file.start = (u_char *) opts.file; - vm_options.file.length = nxt_strlen(opts.file); + memcpy(path + nxt_strlen(path), "/shell", sizeof("/shell")); + opts.file = path; } + vm_options.file.start = (u_char *) opts.file; + vm_options.file.length = nxt_strlen(opts.file); + vm_options.init = !opts.interactive; vm_options.accumulative = opts.interactive; vm_options.backtrace = 1; + vm_options.quiet = opts.quiet; vm_options.sandbox = opts.sandbox; vm_options.module = opts.module; + vm_options.ops = &njs_console_ops; vm_options.external = &njs_console; diff -r d7a0eb59a7e7 -r 802fe99c8881 njs/test/njs_expect_test.exp --- a/njs/test/njs_expect_test.exp Sun Apr 07 14:26:13 2019 +0800 +++ b/njs/test/njs_expect_test.exp Fri Apr 12 20:48:44 2019 +0300 @@ -715,5 +715,8 @@ njs_test { "12\r\n"} } "-p njs/test/module/" +njs_run "-q ./njs/test/module/normal.js" \ + "SyntaxError: Cannot find module \"hash.js\" in 5" + njs_run "-p njs/test/module/libs/ -d ./njs/test/module/normal.js" \ "passed!" From xeioex at nginx.com Fri Apr 12 17:49:09 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Fri, 12 Apr 2019 17:49:09 +0000 Subject: [njs] Renaming node->label to node->name. Message-ID: details: https://hg.nginx.org/njs/rev/de5127995b43 branches: changeset: 890:de5127995b43 user: hongzhidao date: Sat Apr 13 01:07:34 2019 +0800 description: Renaming node->label to node->name. To reuse it for function name without introducing newly field. diffstat: njs/njs_generator.c | 16 ++++++++-------- njs/njs_parser.c | 4 ++-- njs/njs_parser.h | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diffs (108 lines): diff -r 802fe99c8881 -r de5127995b43 njs/njs_generator.c --- a/njs/njs_generator.c Fri Apr 12 20:48:44 2019 +0300 +++ b/njs/njs_generator.c Sat Apr 13 01:07:34 2019 +0800 @@ -847,7 +847,7 @@ njs_generate_switch_statement(njs_vm_t * } ret = njs_generate_start_block(vm, generator, NJS_GENERATOR_SWITCH, - &swtch->label); + &swtch->name); if (nxt_slow_path(ret != NXT_OK)) { return ret; } @@ -966,7 +966,7 @@ njs_generate_while_statement(njs_vm_t *v /* The loop body. */ ret = njs_generate_start_block(vm, generator, NJS_GENERATOR_LOOP, - &node->label); + &node->name); if (nxt_slow_path(ret != NXT_OK)) { return ret; } @@ -1014,7 +1014,7 @@ njs_generate_do_while_statement(njs_vm_t /* The loop body. */ ret = njs_generate_start_block(vm, generator, NJS_GENERATOR_LOOP, - &node->label); + &node->name); if (nxt_slow_path(ret != NXT_OK)) { return ret; } @@ -1059,7 +1059,7 @@ njs_generate_for_statement(njs_vm_t *vm, njs_vmcode_cond_jump_t *cond_jump; ret = njs_generate_start_block(vm, generator, NJS_GENERATOR_LOOP, - &node->label); + &node->name); if (nxt_slow_path(ret != NXT_OK)) { return ret; } @@ -1162,7 +1162,7 @@ njs_generate_for_in_statement(njs_vm_t * njs_vmcode_prop_foreach_t *prop_foreach; ret = njs_generate_start_block(vm, generator, NJS_GENERATOR_LOOP, - &node->label); + &node->name); if (nxt_slow_path(ret != NXT_OK)) { return ret; } @@ -1441,7 +1441,7 @@ njs_generate_continue_statement(njs_vm_t njs_generator_patch_t *patch; njs_generator_block_t *block; - label = &node->label; + label = &node->name; block = njs_generate_find_block(generator->block, NJS_GENERATOR_LOOP, label); @@ -1489,7 +1489,7 @@ njs_generate_break_statement(njs_vm_t *v njs_generator_patch_t *patch; njs_generator_block_t *block; - label = &node->label; + label = &node->name; block = njs_generate_find_block(generator->block, NJS_GENERATOR_ALL, label); if (nxt_slow_path(block == NULL)) { @@ -1548,7 +1548,7 @@ njs_generate_block_statement(njs_vm_t *v nxt_int_t ret; ret = njs_generate_start_block(vm, generator, NJS_GENERATOR_BLOCK, - &node->label); + &node->name); if (nxt_slow_path(ret != NXT_OK)) { return ret; } diff -r 802fe99c8881 -r de5127995b43 njs/njs_parser.c --- a/njs/njs_parser.c Fri Apr 12 20:48:44 2019 +0300 +++ b/njs/njs_parser.c Sat Apr 13 01:07:34 2019 +0800 @@ -559,7 +559,7 @@ njs_parser_labelled_statement(njs_vm_t * if (parser->node != NULL) { /* The statement is not empty block or just semicolon. */ - ret = njs_name_copy(vm, &parser->node->label, &name); + ret = njs_name_copy(vm, &parser->node->name, &name); if (nxt_slow_path(ret != NXT_OK)) { return NJS_TOKEN_ERROR; } @@ -1584,7 +1584,7 @@ njs_parser_brk_statement(njs_vm_t *vm, n return NJS_TOKEN_ILLEGAL; } - ret = njs_name_copy(vm, &parser->node->label, &name); + ret = njs_name_copy(vm, &parser->node->name, &name); if (nxt_slow_path(ret != NXT_OK)) { return NJS_TOKEN_ERROR; } diff -r 802fe99c8881 -r de5127995b43 njs/njs_parser.h --- a/njs/njs_parser.h Fri Apr 12 20:48:44 2019 +0300 +++ b/njs/njs_parser.h Sat Apr 13 01:07:34 2019 +0800 @@ -50,7 +50,7 @@ struct njs_parser_node_s { njs_parser_node_t *object; } u; - nxt_str_t label; + nxt_str_t name; njs_index_t index; From xeioex at nginx.com Fri Apr 12 17:49:10 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Fri, 12 Apr 2019 17:49:10 +0000 Subject: [njs] Making parser hoist more generic. Message-ID: details: https://hg.nginx.org/njs/rev/ace6f73dff8d branches: changeset: 891:ace6f73dff8d user: hongzhidao date: Sat Apr 13 01:11:49 2019 +0800 description: Making parser hoist more generic. diffstat: njs/njs_parser.c | 121 ++++++++++++++++++++++-------------------------------- njs/njs_parser.h | 1 + 2 files changed, 51 insertions(+), 71 deletions(-) diffs (207 lines): diff -r de5127995b43 -r ace6f73dff8d njs/njs_parser.c --- a/njs/njs_parser.c Sat Apr 13 01:07:34 2019 +0800 +++ b/njs/njs_parser.c Sat Apr 13 01:11:49 2019 +0800 @@ -13,7 +13,7 @@ static njs_ret_t njs_parser_scope_begin( njs_scope_t type); static void njs_parser_scope_end(njs_vm_t *vm, njs_parser_t *parser); static njs_token_t njs_parser_statement_chain(njs_vm_t *vm, - njs_parser_t *parser, njs_token_t token, njs_parser_node_t **dest); + njs_parser_t *parser, njs_token_t token, nxt_bool_t top); static njs_token_t njs_parser_statement(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token); static njs_token_t njs_parser_block_statement(njs_vm_t *vm, @@ -61,8 +61,6 @@ static njs_token_t njs_parser_import_sta njs_parser_t *parser); static njs_token_t njs_parser_export_statement(njs_vm_t *vm, njs_parser_t *parser); -static nxt_int_t njs_parser_import_hoist(njs_vm_t *vm, njs_parser_t *parser, - njs_parser_node_t *new_node); static nxt_int_t njs_parser_export_sink(njs_vm_t *vm, njs_parser_t *parser); static njs_token_t njs_parser_grouping_expression(njs_vm_t *vm, njs_parser_t *parser); @@ -130,8 +128,7 @@ njs_parser(njs_vm_t *vm, njs_parser_t *p while (token != NJS_TOKEN_END) { - token = njs_parser_statement_chain(vm, parser, token, - &njs_parser_chain_top(parser)); + token = njs_parser_statement_chain(vm, parser, token, 1); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { return NXT_ERROR; } @@ -271,35 +268,58 @@ njs_parser_scope_end(njs_vm_t *vm, njs_p static njs_token_t njs_parser_statement_chain(njs_vm_t *vm, njs_parser_t *parser, - njs_token_t token, njs_parser_node_t **dest) + njs_token_t token, nxt_bool_t top) { - njs_parser_node_t *node, *last; - - last = *dest; + njs_parser_node_t *stmt, *last, *node, *new_node, **child; + + child = top ? &njs_parser_chain_top(parser) + : &njs_parser_chain_current(parser); + + last = *child; token = njs_parser_statement(vm, parser, token); - if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { return njs_parser_unexpected_token(vm, parser, token); } - if (parser->node != NULL) { - /* The statement is not empty block or just semicolon. */ - - node = njs_parser_node_new(vm, parser, NJS_TOKEN_STATEMENT); - if (nxt_slow_path(node == NULL)) { - return NJS_TOKEN_ERROR; - } - - node->left = last; - node->right = parser->node; - *dest = node; - - while (token == NJS_TOKEN_SEMICOLON) { - token = njs_parser_token(vm, parser); - if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { + if (parser->node == NULL) { + /* The statement is empty block or just semicolon. */ + return token; + } + + new_node = parser->node; + + if (new_node->hoist) { + child = &njs_parser_chain_top(parser); + + while (*child != NULL) { + node = *child; + + if (node->hoist) { break; } + + child = &node->left; + } + + last = *child; + } + + stmt = njs_parser_node_new(vm, parser, NJS_TOKEN_STATEMENT); + if (nxt_slow_path(stmt == NULL)) { + return NJS_TOKEN_ERROR; + } + + stmt->hoist = new_node->hoist; + stmt->left = last; + stmt->right = new_node; + + *child = stmt; + + while (token == NJS_TOKEN_SEMICOLON) { + token = njs_parser_token(vm, parser); + if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { + break; } } @@ -442,8 +462,7 @@ njs_parser_block_statement(njs_vm_t *vm, parser->node = NULL; while (token != NJS_TOKEN_CLOSE_BRACE) { - token = njs_parser_statement_chain(vm, parser, token, - &njs_parser_chain_current(parser)); + token = njs_parser_statement_chain(vm, parser, token, 0); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { return token; } @@ -940,8 +959,7 @@ njs_parser_lambda_statements(njs_vm_t *v parser->node = NULL; while (token != NJS_TOKEN_CLOSE_BRACE) { - token = njs_parser_statement_chain(vm, parser, token, - &njs_parser_chain_top(parser)); + token = njs_parser_statement_chain(vm, parser, token, 1); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { return token; } @@ -1253,8 +1271,7 @@ njs_parser_switch_statement(njs_vm_t *vm return NJS_TOKEN_ILLEGAL; } - token = njs_parser_statement_chain(vm, parser, token, - &njs_parser_chain_current(parser)); + token = njs_parser_statement_chain(vm, parser, token, 0); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { return token; } @@ -1839,12 +1856,8 @@ njs_parser_import_statement(njs_vm_t *vm import->left = name; import->right = parser->node; - ret = njs_parser_import_hoist(vm, parser, import); - if (nxt_slow_path(ret != NXT_OK)) { - return NJS_TOKEN_ERROR; - } - - parser->node = NULL; + parser->node = import; + parser->node->hoist = 1; return njs_parser_token(vm, parser); } @@ -1961,40 +1974,6 @@ njs_parser_export_statement(njs_vm_t *vm static nxt_int_t -njs_parser_import_hoist(njs_vm_t *vm, njs_parser_t *parser, - njs_parser_node_t *new_node) -{ - njs_parser_node_t *node, *stmt, **child; - - child = &njs_parser_chain_top(parser); - - while (*child != NULL) { - node = *child; - - if (node->right != NULL - && node->right->token == NJS_TOKEN_IMPORT) - { - break; - } - - child = &node->left; - } - - stmt = njs_parser_node_new(vm, parser, NJS_TOKEN_STATEMENT); - if (nxt_slow_path(stmt == NULL)) { - return NXT_ERROR; - } - - stmt->left = *child; - stmt->right = new_node; - - *child = stmt; - - return NXT_OK; -} - - -static nxt_int_t njs_parser_export_sink(njs_vm_t *vm, njs_parser_t *parser) { nxt_uint_t n; diff -r de5127995b43 -r ace6f73dff8d njs/njs_parser.h --- a/njs/njs_parser.h Sat Apr 13 01:07:34 2019 +0800 +++ b/njs/njs_parser.h Sat Apr 13 01:11:49 2019 +0800 @@ -40,6 +40,7 @@ struct njs_parser_node_s { njs_token_t token:16; uint8_t ctor:1; uint8_t temporary; /* 1 bit */ + uint8_t hoist; /* 1 bit */ uint32_t token_line; union { From eran.kornblau at kaltura.com Sun Apr 14 13:24:35 2019 From: eran.kornblau at kaltura.com (Eran Kornblau) Date: Sun, 14 Apr 2019 13:24:35 +0000 Subject: Issuing an HTTP request from a stream module In-Reply-To: <20190408142253.GA20152@Romans-MacBook-Air.local> References: <20190408142253.GA20152@Romans-MacBook-Air.local> Message-ID: Thank you, Roman, this is very helpful! > In nginx source there are at least 2 examples of how to write an HTTP client: > > - OCSP stapling (src/event/ngx_event_openssl_stapling.c) > - mail_auth module (src/mail/ngx_mail_auth_http_module.c) > > Also, the HTTP proxy module does this as well, but the entire module is much more complicated. > I was familiar with the proxy module, but since it depends on 'upstream' it is harder to derive the required code from it, wasn't familiar with the 2 other implementations you mentioned... I looked at ngx_event_openssl_stapling, something small that I noticed - I didn't see any handling for the case in which the response headers are larger than the allocated buffer (16K). While it is an edge case, unless I'm missing something, the code will call recv with decreasing sizes, until the buffer will eventually get full, and recv will be called with size=0. I think it makes sense to check the size and print some error if this happens. > -- > Roman Arutyunyan > _______________________________________________ > nginx-devel mailing list > nginx-devel at nginx.org > https://eur02.safelinks.protection.outlook.com/?url=http%3A%2F%2Fmailman.nginx.org%2Fmailman%2Flistinfo%2Fnginx-devel&data=02%7C01%7Ceran.kornblau%40kaltura.com%7Cb0737c825fe744818b6608d6bc2db562%7C0c503748de3f4e2597e26819d53a42b6%7C0%7C0%7C636903301834679796&sdata=Qf53use9qeujNa2g4MKBy2DBtgLCeEi7D3j3M%2BftGXg%3D&reserved=0 > Thanks, Eran From xeioex at nginx.com Mon Apr 15 13:37:49 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Mon, 15 Apr 2019 13:37:49 +0000 Subject: [njs] Fixed function declaration with the same name as a variable. Message-ID: details: https://hg.nginx.org/njs/rev/d3743d248ade branches: changeset: 892:d3743d248ade user: hongzhidao date: Sat Apr 13 23:38:53 2019 +0800 description: Fixed function declaration with the same name as a variable. This closes #126 issue on Github. diffstat: njs/njs_variable.c | 5 +++++ njs/test/njs_unit_test.c | 10 ++++++++++ 2 files changed, 15 insertions(+), 0 deletions(-) diffs (35 lines): diff -r ace6f73dff8d -r d3743d248ade njs/njs_variable.c --- a/njs/njs_variable.c Sat Apr 13 01:11:49 2019 +0800 +++ b/njs/njs_variable.c Sat Apr 13 23:38:53 2019 +0800 @@ -65,6 +65,11 @@ njs_variable_add(njs_vm_t *vm, njs_parse if (nxt_lvlhsh_find(&scope->variables, &lhq) == NXT_OK) { var = lhq.value; + + if (type == NJS_VARIABLE_FUNCTION) { + var->type = type; + } + return var; } diff -r ace6f73dff8d -r d3743d248ade njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Sat Apr 13 01:11:49 2019 +0800 +++ b/njs/test/njs_unit_test.c Sat Apr 13 23:38:53 2019 +0800 @@ -6413,6 +6413,16 @@ static njs_unit_test_t njs_test[] = { nxt_string("function f() { var a = 1; function baz() { return a; } return baz; } f().bind()()"), nxt_string("1") }, + { nxt_string("function f() { var t = 1; function baz() { return t; } return baz; }" + "f().bind()();"), + nxt_string("1") }, + + { nxt_string("(function(a) { var s = typeof g, q = g; var g = 1; s += typeof g; function g(b) { return a + b }; return q; })(1)(2)"), + nxt_string("3")}, + + { nxt_string("(function(a) { var g = f; var f = 1; function f() { return a; } return g; })(42)()"), + nxt_string("42") }, + { nxt_string("function f(a, b) { return a + b }" "f(3,4) === f.bind()(3,4)"), nxt_string("true") }, From alexander.borisov at nginx.com Mon Apr 15 14:45:48 2019 From: alexander.borisov at nginx.com (Alexander Borisov) Date: Mon, 15 Apr 2019 14:45:48 +0000 Subject: [njs] Fixed ToInteger function in accordance with the specification. Message-ID: details: https://hg.nginx.org/njs/rev/f0b5b01a7c55 branches: changeset: 893:f0b5b01a7c55 user: Alexander Borisov date: Mon Apr 15 17:23:21 2019 +0300 description: Fixed ToInteger function in accordance with the specification. According to ES6 type conversion 7.1.4. diffstat: njs/njs_array.c | 4 ++-- njs/njs_number.c | 22 ++++++++++++---------- njs/njs_number.h | 4 ++-- 3 files changed, 16 insertions(+), 14 deletions(-) diffs (91 lines): diff -r d3743d248ade -r f0b5b01a7c55 njs/njs_array.c --- a/njs/njs_array.c Sat Apr 13 23:38:53 2019 +0800 +++ b/njs/njs_array.c Mon Apr 15 17:23:21 2019 +0300 @@ -493,7 +493,7 @@ njs_array_prototype_slice_continuation(n return njs_trap(vm, NJS_TRAP_NUMBER_ARG); } - start = (int32_t) njs_primitive_value_to_integer(njs_arg(args, nargs, 1)); + start = njs_primitive_value_to_integer(njs_arg(args, nargs, 1)); length = njs_primitive_value_to_integer(&slice->length); if (start < 0) { @@ -510,7 +510,7 @@ njs_array_prototype_slice_continuation(n } else { if (!njs_is_undefined(njs_arg(args, nargs, 2))) { - end = (int32_t) njs_primitive_value_to_integer(&args[2]); + end = njs_primitive_value_to_integer(&args[2]); } else { end = length; diff -r d3743d248ade -r f0b5b01a7c55 njs/njs_number.c --- a/njs/njs_number.c Sat Apr 13 23:38:53 2019 +0800 +++ b/njs/njs_number.c Mon Apr 15 17:23:21 2019 +0300 @@ -73,7 +73,7 @@ njs_primitive_value_to_number(const njs_ } -uint32_t +int32_t njs_primitive_value_to_integer(const njs_value_t *value) { return njs_number_to_integer(njs_primitive_value_to_number(value)); @@ -783,11 +783,9 @@ njs_number_parse_float(njs_vm_t *vm, njs } -nxt_noinline uint32_t -njs_number_to_integer(double num) +nxt_inline int64_t +njs_number_to_int64(double num) { - int64_t i64; - #if (NXT_NAN_TO_UINT_CONVERSION != 0) /* * PPC32: NaN and Inf are converted to 0x8000000080000000 @@ -810,13 +808,17 @@ njs_number_to_integer(double num) */ if (fabs(num) > 9007199254740992.0) { - i64 = fmod(num, 4294967296.0); - - } else { - i64 = num; + return (int64_t) fmod(num, 4294967296.0); } - return (uint32_t) i64; + return (int64_t) num; +} + + +nxt_noinline int32_t +njs_number_to_integer(double num) +{ + return (int32_t) njs_number_to_int64(num); } diff -r d3743d248ade -r f0b5b01a7c55 njs/njs_number.h --- a/njs/njs_number.h Sat Apr 13 23:38:53 2019 +0800 +++ b/njs/njs_number.h Mon Apr 15 17:23:21 2019 +0300 @@ -13,7 +13,7 @@ uint32_t njs_value_to_index(const njs_value_t *value); double njs_primitive_value_to_number(const njs_value_t *value); -uint32_t njs_primitive_value_to_integer(const njs_value_t *value); +int32_t njs_primitive_value_to_integer(const njs_value_t *value); double njs_number_dec_parse(const u_char **start, const u_char *end); uint64_t njs_number_oct_parse(const u_char **start, const u_char *end); uint64_t njs_number_bin_parse(const u_char **start, const u_char *end); @@ -32,7 +32,7 @@ njs_ret_t njs_number_parse_int(njs_vm_t nxt_uint_t nargs, njs_index_t unused); njs_ret_t njs_number_parse_float(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused); -nxt_noinline uint32_t njs_number_to_integer(double num); +nxt_noinline int32_t njs_number_to_integer(double num); nxt_inline nxt_int_t From alexander.borisov at nginx.com Mon Apr 15 14:45:49 2019 From: alexander.borisov at nginx.com (Alexander Borisov) Date: Mon, 15 Apr 2019 14:45:49 +0000 Subject: [njs] Added implementation of functions: ToInt32, ToUint32, ToLength. Message-ID: details: https://hg.nginx.org/njs/rev/381086beb15f branches: changeset: 894:381086beb15f user: Alexander Borisov date: Mon Apr 15 17:23:02 2019 +0300 description: Added implementation of functions: ToInt32, ToUint32, ToLength. According to ES6 type conversion: 7.1.5, 7.1.6, and 7.1.15. diffstat: njs/njs_array.c | 2 +- njs/njs_function.c | 2 +- njs/njs_math.c | 6 ++-- njs/njs_number.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++ njs/njs_number.h | 7 +++++- njs/njs_string.c | 2 +- njs/njs_vm.c | 19 +++++++-------- njs/test/njs_unit_test.c | 2 +- 8 files changed, 78 insertions(+), 18 deletions(-) diffs (221 lines): diff -r f0b5b01a7c55 -r 381086beb15f njs/njs_array.c --- a/njs/njs_array.c Mon Apr 15 17:23:21 2019 +0300 +++ b/njs/njs_array.c Mon Apr 15 17:23:02 2019 +0300 @@ -494,7 +494,7 @@ njs_array_prototype_slice_continuation(n } start = njs_primitive_value_to_integer(njs_arg(args, nargs, 1)); - length = njs_primitive_value_to_integer(&slice->length); + length = njs_primitive_value_to_length(&slice->length); if (start < 0) { start += length; diff -r f0b5b01a7c55 -r 381086beb15f njs/njs_function.c --- a/njs/njs_function.c Mon Apr 15 17:23:21 2019 +0300 +++ b/njs/njs_function.c Mon Apr 15 17:23:02 2019 +0300 @@ -1022,7 +1022,7 @@ njs_function_prototype_apply(njs_vm_t *v return NXT_ERROR; } - nargs = njs_primitive_value_to_number(&length); + nargs = njs_primitive_value_to_length(&length); arr = njs_array_alloc(vm, nargs, NJS_ARRAY_SPARE); if (nxt_slow_path(arr == NULL)) { diff -r f0b5b01a7c55 -r 381086beb15f njs/njs_math.c --- a/njs/njs_math.c Mon Apr 15 17:23:21 2019 +0300 +++ b/njs/njs_math.c Mon Apr 15 17:23:02 2019 +0300 @@ -227,7 +227,7 @@ njs_object_math_clz32(njs_vm_t *vm, njs_ uint32_t ui32; if (nargs > 1) { - ui32 = njs_number_to_integer(args[1].data.u.number); + ui32 = njs_number_to_uint32(args[1].data.u.number); num = nxt_leading_zeros(ui32); } else { @@ -393,8 +393,8 @@ njs_object_math_imul(njs_vm_t *vm, njs_v uint32_t a, b; if (nargs > 2) { - a = njs_number_to_integer(args[1].data.u.number); - b = njs_number_to_integer(args[2].data.u.number); + a = njs_number_to_uint32(args[1].data.u.number); + b = njs_number_to_uint32(args[2].data.u.number); num = (int32_t) (a * b); diff -r f0b5b01a7c55 -r 381086beb15f njs/njs_number.c --- a/njs/njs_number.c Mon Apr 15 17:23:21 2019 +0300 +++ b/njs/njs_number.c Mon Apr 15 17:23:02 2019 +0300 @@ -80,6 +80,27 @@ njs_primitive_value_to_integer(const njs } +int32_t +njs_primitive_value_to_int32(const njs_value_t *value) +{ + return njs_number_to_int32(njs_primitive_value_to_number(value)); +} + + +uint32_t +njs_primitive_value_to_uint32(const njs_value_t *value) +{ + return njs_number_to_uint32(njs_primitive_value_to_number(value)); +} + + +uint32_t +njs_primitive_value_to_length(const njs_value_t *value) +{ + return njs_number_to_length(njs_primitive_value_to_number(value)); +} + + double njs_number_dec_parse(const u_char **start, const u_char *end) { @@ -822,6 +843,41 @@ njs_number_to_integer(double num) } +nxt_noinline int32_t +njs_number_to_int32(double num) +{ + return (int32_t) njs_number_to_int64(num); +} + + +nxt_noinline uint32_t +njs_number_to_uint32(double num) +{ + return (uint32_t) njs_number_to_int64(num); +} + + +nxt_noinline uint32_t +njs_number_to_length(double num) +{ +#if (NXT_NAN_TO_UINT_CONVERSION != 0) + if (isnan(num)) { + return 0; + } +#endif + + if (num > UINT32_MAX) { + return UINT32_MAX; + + } else if (num < 0.0) { + return 0; + } + + return (uint32_t) (int64_t) num; +} + + + static const njs_object_prop_t njs_is_nan_function_properties[] = { /* isNaN.name == "isNaN". */ diff -r f0b5b01a7c55 -r 381086beb15f njs/njs_number.h --- a/njs/njs_number.h Mon Apr 15 17:23:21 2019 +0300 +++ b/njs/njs_number.h Mon Apr 15 17:23:02 2019 +0300 @@ -14,6 +14,9 @@ uint32_t njs_value_to_index(const njs_value_t *value); double njs_primitive_value_to_number(const njs_value_t *value); int32_t njs_primitive_value_to_integer(const njs_value_t *value); +int32_t njs_primitive_value_to_int32(const njs_value_t *value); +uint32_t njs_primitive_value_to_uint32(const njs_value_t *value); +uint32_t njs_primitive_value_to_length(const njs_value_t *value); double njs_number_dec_parse(const u_char **start, const u_char *end); uint64_t njs_number_oct_parse(const u_char **start, const u_char *end); uint64_t njs_number_bin_parse(const u_char **start, const u_char *end); @@ -33,7 +36,9 @@ njs_ret_t njs_number_parse_int(njs_vm_t njs_ret_t njs_number_parse_float(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused); nxt_noinline int32_t njs_number_to_integer(double num); - +nxt_noinline int32_t njs_number_to_int32(double num); +nxt_noinline uint32_t njs_number_to_uint32(double num); +nxt_noinline uint32_t njs_number_to_length(double num); nxt_inline nxt_int_t njs_char_to_hex(u_char c) diff -r f0b5b01a7c55 -r 381086beb15f njs/njs_string.c --- a/njs/njs_string.c Mon Apr 15 17:23:21 2019 +0300 +++ b/njs/njs_string.c Mon Apr 15 17:23:02 2019 +0300 @@ -1445,7 +1445,7 @@ njs_string_bytes_from_array(njs_vm_t *vm octet = array->start; while (length != 0) { - *p++ = (u_char) njs_number_to_integer(octet->data.u.number); + *p++ = (u_char) njs_number_to_uint32(octet->data.u.number); octet++; length--; } diff -r f0b5b01a7c55 -r 381086beb15f njs/njs_vm.c --- a/njs/njs_vm.c Mon Apr 15 17:23:21 2019 +0300 +++ b/njs/njs_vm.c Mon Apr 15 17:23:02 2019 +0300 @@ -1303,8 +1303,8 @@ njs_vmcode_left_shift(njs_vm_t *vm, njs_ if (nxt_fast_path(njs_is_numeric(val1) && njs_is_numeric(val2))) { - num1 = njs_number_to_integer(val1->data.u.number); - num2 = njs_number_to_integer(val2->data.u.number); + num1 = njs_number_to_int32(val1->data.u.number); + num2 = njs_number_to_uint32(val2->data.u.number); njs_value_number_set(&vm->retval, num1 << (num2 & 0x1f)); return sizeof(njs_vmcode_3addr_t); @@ -1322,8 +1322,8 @@ njs_vmcode_right_shift(njs_vm_t *vm, njs if (nxt_fast_path(njs_is_numeric(val1) && njs_is_numeric(val2))) { - num1 = njs_number_to_integer(val1->data.u.number); - num2 = njs_number_to_integer(val2->data.u.number); + num1 = njs_number_to_int32(val1->data.u.number); + num2 = njs_number_to_uint32(val2->data.u.number); njs_value_number_set(&vm->retval, num1 >> (num2 & 0x1f)); return sizeof(njs_vmcode_3addr_t); @@ -1337,13 +1337,12 @@ njs_ret_t njs_vmcode_unsigned_right_shift(njs_vm_t *vm, njs_value_t *val1, njs_value_t *val2) { - int32_t num2; - uint32_t num1; + uint32_t num1, num2; if (nxt_fast_path(njs_is_numeric(val1) && njs_is_numeric(val2))) { - num1 = njs_number_to_integer(val1->data.u.number); - num2 = njs_number_to_integer(val2->data.u.number); + num1 = njs_number_to_uint32(val1->data.u.number); + num2 = njs_number_to_uint32(val2->data.u.number); njs_value_number_set(&vm->retval, num1 >> (num2 & 0x1f)); return sizeof(njs_vmcode_3addr_t); @@ -1462,8 +1461,8 @@ njs_vmcode_bitwise_or(njs_vm_t *vm, njs_ if (nxt_fast_path(njs_is_numeric(val1) && njs_is_numeric(val2))) { - num1 = njs_number_to_integer(val1->data.u.number); - num2 = njs_number_to_integer(val2->data.u.number); + num1 = njs_number_to_uint32(val1->data.u.number); + num2 = njs_number_to_uint32(val2->data.u.number); njs_value_number_set(&vm->retval, num1 | num2); return sizeof(njs_vmcode_3addr_t); diff -r f0b5b01a7c55 -r 381086beb15f njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Mon Apr 15 17:23:21 2019 +0300 +++ b/njs/test/njs_unit_test.c Mon Apr 15 17:23:02 2019 +0300 @@ -3617,7 +3617,7 @@ static njs_unit_test_t njs_test[] = nxt_string("TypeError: Cannot convert object to primitive value") }, { nxt_string("Array.prototype.slice.call({length:-1})"), - nxt_string("MemoryError") }, + nxt_string("") }, { nxt_string("Array.prototype.slice.call('??Z?')"), nxt_string("?,?,Z,?") }, From mdounin at mdounin.ru Mon Apr 15 17:13:58 2019 From: mdounin at mdounin.ru (Maxim Dounin) Date: Mon, 15 Apr 2019 17:13:58 +0000 Subject: [nginx] Version bump. Message-ID: details: https://hg.nginx.org/nginx/rev/ce9942d4df55 branches: changeset: 7492:ce9942d4df55 user: Maxim Dounin date: Mon Apr 15 19:13:06 2019 +0300 description: Version bump. diffstat: src/core/nginx.h | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diffs (14 lines): diff --git a/src/core/nginx.h b/src/core/nginx.h --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1015011 -#define NGINX_VERSION "1.15.11" +#define nginx_version 1015012 +#define NGINX_VERSION "1.15.12" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD From mdounin at mdounin.ru Mon Apr 15 17:14:00 2019 From: mdounin at mdounin.ru (Maxim Dounin) Date: Mon, 15 Apr 2019 17:14:00 +0000 Subject: [nginx] OCSP stapling: fixed segfault with dynamic certificate loading. Message-ID: details: https://hg.nginx.org/nginx/rev/dbebbb25ae92 branches: changeset: 7493:dbebbb25ae92 user: Maxim Dounin date: Mon Apr 15 19:13:09 2019 +0300 description: OCSP stapling: fixed segfault with dynamic certificate loading. If OCSP stapling was enabled with dynamic certificate loading, with some OpenSSL versions (1.0.2o and older, 1.1.0h and older; fixed in 1.0.2p, 1.1.0i, 1.1.1) a segmentation fault might happen. The reason is that during an abbreviated handshake the certificate callback is not called, but the certificate status callback was called (https://github.com/openssl/openssl/issues/1662), leading to NULL being returned from SSL_get_certificate(). Fix is to explicitly check SSL_get_certificate() result. diffstat: src/event/ngx_event_openssl_stapling.c | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-) diffs (15 lines): diff --git a/src/event/ngx_event_openssl_stapling.c b/src/event/ngx_event_openssl_stapling.c --- a/src/event/ngx_event_openssl_stapling.c +++ b/src/event/ngx_event_openssl_stapling.c @@ -511,6 +511,11 @@ ngx_ssl_certificate_status_callback(ngx_ rc = SSL_TLSEXT_ERR_NOACK; cert = SSL_get_certificate(ssl_conn); + + if (cert == NULL) { + return rc; + } + staple = X509_get_ex_data(cert, ngx_ssl_stapling_index); if (staple == NULL) { From mdounin at mdounin.ru Mon Apr 15 18:41:59 2019 From: mdounin at mdounin.ru (Maxim Dounin) Date: Mon, 15 Apr 2019 18:41:59 +0000 Subject: [nginx] Fixed incorrect length handling in ngx_utf8_length(). Message-ID: details: https://hg.nginx.org/nginx/rev/a42a6dfeb01a branches: changeset: 7494:a42a6dfeb01a user: Maxim Dounin date: Mon Apr 15 20:14:07 2019 +0300 description: Fixed incorrect length handling in ngx_utf8_length(). Previously, ngx_utf8_decode() was called from ngx_utf8_length() with incorrect length, potentially resulting in out-of-bounds read when handling invalid UTF-8 strings. In practice out-of-bounds reads are not possible though, as autoindex, the only user of ngx_utf8_length(), provides null-terminated strings, and ngx_utf8_decode() anyway returns an errors when it sees a null in the middle of an UTF-8 sequence. Reported by Yunbin Liu. diffstat: src/core/ngx_string.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diffs (12 lines): diff --git a/src/core/ngx_string.c b/src/core/ngx_string.c --- a/src/core/ngx_string.c +++ b/src/core/ngx_string.c @@ -1381,7 +1381,7 @@ ngx_utf8_length(u_char *p, size_t n) continue; } - if (ngx_utf8_decode(&p, n) > 0x10ffff) { + if (ngx_utf8_decode(&p, last - p) > 0x10ffff) { /* invalid UTF-8 */ return n; } From xeioex at nginx.com Tue Apr 16 14:31:06 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Tue, 16 Apr 2019 14:31:06 +0000 Subject: [njs] Version 0.3.1. Message-ID: details: https://hg.nginx.org/njs/rev/ebfbdb8d8fe2 branches: changeset: 895:ebfbdb8d8fe2 user: Dmitry Volyntsev date: Tue Apr 16 17:30:11 2019 +0300 description: Version 0.3.1. diffstat: CHANGES | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 43 insertions(+), 0 deletions(-) diffs (50 lines): diff -r 381086beb15f -r ebfbdb8d8fe2 CHANGES --- a/CHANGES Mon Apr 15 17:23:02 2019 +0300 +++ b/CHANGES Tue Apr 16 17:30:11 2019 +0300 @@ -1,3 +1,46 @@ + +Changes with njs 0.3.1 16 Apr 2019 + + Core: + + *) Feature: added arrow functions support. + Thanks to ??? (Hong Zhi Dao) and Artem S. Povalyukhin. + + *) Feature: added Added Object.getOwnPropertyNames(). + Thanks to Artem S. Povalyukhin. + + *) Feature: added Added Object.getOwnPropertyDescriptors(). + Thanks to Artem S. Povalyukhin. + + *) Feature: making __proto__ accessor descriptor of Object instances + mutable. + + *) Feature: added shebang support in CLI. + + *) Feature: added support for module mode execution in CLI. In module + mode global this is unavailable. + + *) Bugfix: fixed editline detection. + + *) Bugfix: fixed Function.prototype.bind(). + Thanks to ??? (Hong Zhi Dao). + + *) Bugfix: fixed checking of duplication of parameters for functions. + Thanks to ??? (Hong Zhi Dao). + + *) Bugfix: fixed function declaration with the same name as a variable. + Thanks to ??? (Hong Zhi Dao). + + *) Improvement: code related to parsing of objects, variables and + functions is refactored. + Thanks to ??? (Hong Zhi Dao). + + *) Improvement: console.log() improved for outputting large values. + + *) Improvement: console.log() improved for outputting strings in a + compliant way (without escaping and quotes). + + *) Improvement: using ES6 version of ToInt32(), ToUint32(), ToLength(). Changes with njs 0.3.0 26 Mar 2019 From xeioex at nginx.com Tue Apr 16 14:31:07 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Tue, 16 Apr 2019 14:31:07 +0000 Subject: [njs] Added tag 0.3.1 for changeset ebfbdb8d8fe2 Message-ID: details: https://hg.nginx.org/njs/rev/a2ae6774b194 branches: changeset: 896:a2ae6774b194 user: Dmitry Volyntsev date: Tue Apr 16 17:30:56 2019 +0300 description: Added tag 0.3.1 for changeset ebfbdb8d8fe2 diffstat: .hgtags | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diffs (8 lines): diff -r ebfbdb8d8fe2 -r a2ae6774b194 .hgtags --- a/.hgtags Tue Apr 16 17:30:11 2019 +0300 +++ b/.hgtags Tue Apr 16 17:30:56 2019 +0300 @@ -24,3 +24,4 @@ 0709b8b4f11ebec95dd4f72d5bb38044682f77e6 4624ba4f6497a3d10fe1c0a6f45fb453579502f5 0.2.7 ee190d3ace005f8eb063d4763b578f44d3028c68 0.2.8 1935ab4643fdaec5b4a8c36070f4d2cb8e3799d7 0.3.0 +ebfbdb8d8fe2f640d880359575657cb53e38328f 0.3.1 From mdounin at mdounin.ru Tue Apr 16 14:45:03 2019 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 16 Apr 2019 14:45:03 +0000 Subject: [nginx] Updated PCRE used for win32 builds. Message-ID: details: https://hg.nginx.org/nginx/rev/938661c0f212 branches: changeset: 7495:938661c0f212 user: Maxim Dounin date: Tue Apr 16 16:32:44 2019 +0300 description: Updated PCRE used for win32 builds. diffstat: misc/GNUmakefile | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diffs (12 lines): diff --git a/misc/GNUmakefile b/misc/GNUmakefile --- a/misc/GNUmakefile +++ b/misc/GNUmakefile @@ -8,7 +8,7 @@ CC = cl OBJS = objs.msvc8 OPENSSL = openssl-1.1.1b ZLIB = zlib-1.2.11 -PCRE = pcre-8.42 +PCRE = pcre-8.43 release: export From mdounin at mdounin.ru Tue Apr 16 14:57:37 2019 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 16 Apr 2019 14:57:37 +0000 Subject: [nginx] nginx-1.15.12-RELEASE Message-ID: details: https://hg.nginx.org/nginx/rev/0130ca3d5843 branches: changeset: 7496:0130ca3d5843 user: Maxim Dounin date: Tue Apr 16 17:54:58 2019 +0300 description: nginx-1.15.12-RELEASE diffstat: docs/xml/nginx/changes.xml | 20 ++++++++++++++++++++ 1 files changed, 20 insertions(+), 0 deletions(-) diffs (30 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,26 @@ + + + + +? ??????? ???????? ??? ????????? segmentation fault, +???? ? ?????????? ssl_certificate ??? ssl_certificate_key +?????????????? ?????????? +? ??? ??????? OCSP stapling. + + +a segmentation fault might occur in a worker process +if variables were used +in the "ssl_certificate" or "ssl_certificate_key" directives +and OCSP stapling was enabled. + + + + + + From mdounin at mdounin.ru Tue Apr 16 14:57:39 2019 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 16 Apr 2019 14:57:39 +0000 Subject: [nginx] release-1.15.12 tag Message-ID: details: https://hg.nginx.org/nginx/rev/10db363fcf57 branches: changeset: 7497:10db363fcf57 user: Maxim Dounin date: Tue Apr 16 17:54:59 2019 +0300 description: release-1.15.12 tag diffstat: .hgtags | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diffs (8 lines): diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -437,3 +437,4 @@ ee551e3f6dba336c0d875e266d7d55385f379b42 d2fd76709909767fc727a5b4affcf1dc9ca488a7 release-1.15.9 75f5c7f628411c79c7044102049f7ab4f7a246e7 release-1.15.10 5155d0296a5ef9841f035920527ffdb771076b44 release-1.15.11 +0130ca3d58437b3c7c707cdddd813d530c68da9a release-1.15.12 From xeioex at nginx.com Tue Apr 16 15:35:41 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Tue, 16 Apr 2019 15:35:41 +0000 Subject: [njs] Fixed changelog 0.3.1 description. Message-ID: details: https://hg.nginx.org/njs/rev/8cf41df5ee6b branches: changeset: 897:8cf41df5ee6b user: Dmitry Volyntsev date: Tue Apr 16 18:34:18 2019 +0300 description: Fixed changelog 0.3.1 description. diffstat: CHANGES | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diffs (16 lines): diff -r a2ae6774b194 -r 8cf41df5ee6b CHANGES --- a/CHANGES Tue Apr 16 17:30:56 2019 +0300 +++ b/CHANGES Tue Apr 16 18:34:18 2019 +0300 @@ -6,10 +6,10 @@ Changes with njs 0.3.1 *) Feature: added arrow functions support. Thanks to ??? (Hong Zhi Dao) and Artem S. Povalyukhin. - *) Feature: added Added Object.getOwnPropertyNames(). + *) Feature: added Object.getOwnPropertyNames(). Thanks to Artem S. Povalyukhin. - *) Feature: added Added Object.getOwnPropertyDescriptors(). + *) Feature: added Object.getOwnPropertyDescriptors(). Thanks to Artem S. Povalyukhin. *) Feature: making __proto__ accessor descriptor of Object instances From xeioex at nginx.com Tue Apr 16 15:35:41 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Tue, 16 Apr 2019 15:35:41 +0000 Subject: [njs] Version bump. Message-ID: details: https://hg.nginx.org/njs/rev/a88bf03264b4 branches: changeset: 898:a88bf03264b4 user: Dmitry Volyntsev date: Tue Apr 16 18:34:57 2019 +0300 description: Version bump. diffstat: njs/njs.h | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diffs (12 lines): diff -r 8cf41df5ee6b -r a88bf03264b4 njs/njs.h --- a/njs/njs.h Tue Apr 16 18:34:18 2019 +0300 +++ b/njs/njs.h Tue Apr 16 18:34:57 2019 +0300 @@ -11,7 +11,7 @@ #include -#define NJS_VERSION "0.3.1" +#define NJS_VERSION "0.3.2" #include From xeioex at nginx.com Wed Apr 17 15:50:40 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Wed, 17 Apr 2019 15:50:40 +0000 Subject: [njs] Fixed handling of unicode only regexp expressions. Message-ID: details: https://hg.nginx.org/njs/rev/39790a9d9b58 branches: changeset: 899:39790a9d9b58 user: Dmitry Volyntsev date: Wed Apr 17 18:43:13 2019 +0300 description: Fixed handling of unicode only regexp expressions. This fixes #125 issue on Github. diffstat: njs/njs_regexp.c | 31 +++++++-- njs/test/njs_unit_test.c | 144 +++++++++++++++++++++++++++++++++++++--------- nxt/nxt_pcre.c | 2 + 3 files changed, 139 insertions(+), 38 deletions(-) diffs (259 lines): diff -r a88bf03264b4 -r 39790a9d9b58 njs/njs_regexp.c --- a/njs/njs_regexp.c Tue Apr 16 18:34:57 2019 +0300 +++ b/njs/njs_regexp.c Wed Apr 17 18:43:13 2019 +0300 @@ -315,30 +315,43 @@ njs_regexp_pattern_create(njs_vm_t *vm, ret = njs_regexp_pattern_compile(vm, &pattern->regex[0], &pattern->source[1], options); - if (nxt_slow_path(ret < 0)) { - return NULL; + + if (nxt_fast_path(ret >= 0)) { + pattern->ncaptures = ret; + + } else if (ret < 0 && ret != NXT_DECLINED) { + goto fail; } - pattern->ncaptures = ret; - ret = njs_regexp_pattern_compile(vm, &pattern->regex[1], &pattern->source[1], options | PCRE_UTF8); if (nxt_fast_path(ret >= 0)) { - if (nxt_slow_path((u_int) ret != pattern->ncaptures)) { + if (nxt_slow_path(nxt_regex_is_valid(&pattern->regex[0]) + && (u_int) ret != pattern->ncaptures)) + { njs_internal_error(vm, "regexp pattern compile failed"); - nxt_mp_free(vm->mem_pool, pattern); - return NULL; + goto fail; } } else if (ret != NXT_DECLINED) { - nxt_mp_free(vm->mem_pool, pattern); - return NULL; + goto fail; + } + + if (!nxt_regex_is_valid(&pattern->regex[0]) + && !nxt_regex_is_valid(&pattern->regex[1])) + { + goto fail; } *end = '/'; return pattern; + +fail: + + nxt_mp_free(vm->mem_pool, pattern); + return NULL; } diff -r a88bf03264b4 -r 39790a9d9b58 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Tue Apr 16 18:34:57 2019 +0300 +++ b/njs/test/njs_unit_test.c Wed Apr 17 18:43:13 2019 +0300 @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -4451,6 +4452,12 @@ static njs_unit_test_t njs_test[] = { nxt_string("'?'.toUTF8()[0]"), nxt_string("\xCE") }, + { nxt_string("var r = /^\\x80$/; r.source + r.source.length"), + nxt_string("^\\x80$6") }, + + { nxt_string("var r = /^\\\\x80$/; r.source + r.source.length"), + nxt_string("^\\\\x80$7") }, + { nxt_string("/^\\x80$/.test('\\x80'.toBytes())"), nxt_string("true") }, @@ -11957,6 +11964,25 @@ static njs_unit_test_t njs_tz_test[] = }; +static njs_unit_test_t njs_regexp_test[] = +{ + { nxt_string("/[\\\\u02E0-\\\\u02E4]/"), + nxt_string("/[\\\\u02E0-\\\\u02E4]/") }, + + { nxt_string("/[\\u02E0-\\u02E4]/"), + nxt_string("/[\\u02E0-\\u02E4]/") }, + + { nxt_string("RegExp('[\\\\u02E0-\\\\u02E4]')"), + nxt_string("/[\\u02E0-\\u02E4]/") }, + + { nxt_string("/[\\u0430-\\u044f]+/.test('????')"), + nxt_string("true") }, + + { nxt_string("RegExp('[\\\\u0430-\\\\u044f]+').test('????')"), + nxt_string("true") }, +}; + + typedef struct { nxt_lvlhsh_t hash; const njs_extern_t *proto; @@ -12715,6 +12741,85 @@ done: static nxt_int_t +njs_timezone_optional_test(nxt_bool_t disassemble, nxt_bool_t verbose) +{ + size_t size; + u_char buf[16]; + time_t clock; + struct tm tm; + nxt_int_t ret; + + /* + * Chatham Islands NZ-CHAT time zone. + * Standard time: UTC+12:45, Daylight Saving time: UTC+13:45. + */ + (void) putenv((char *) "TZ=Pacific/Chatham"); + tzset(); + + clock = 0; + localtime_r(&clock, &tm); + + size = strftime((char *) buf, sizeof(buf), "%z", &tm); + + if (memcmp(buf, "+1245", size) == 0) { + ret = njs_unit_test(njs_tz_test, nxt_nitems(njs_tz_test), disassemble, + verbose); + if (ret != NXT_OK) { + return ret; + } + + nxt_printf("njs timezone tests passed\n"); + + } else { + nxt_printf("njs timezone tests skipped, timezone is unavailable\n"); + } + + return NXT_OK; +} + +static nxt_int_t +njs_regexp_optional_test(nxt_bool_t disassemble, nxt_bool_t verbose) +{ + int erroff; + pcre *re1, *re2; + njs_ret_t ret; + const char *errstr; + + /* + * pcre-8.21 crashes when it compiles unicode escape codes inside + * square brackets when PCRE_UTF8 option is provided. + * Catching it in runtime by compiling it without PCRE_UTF8. Normally it + * should return NULL and "character value in \u.... sequence is too large" + * error string. + */ + re1 = pcre_compile("/[\\u0410]/", PCRE_JAVASCRIPT_COMPAT, &errstr, &erroff, + NULL); + + /* + * pcre-7.8 fails to compile unicode escape codes inside square brackets + * even when PCRE_UTF8 option is provided. + */ + re2 = pcre_compile("/[\\u0410]/", PCRE_JAVASCRIPT_COMPAT | PCRE_UTF8, + &errstr, &erroff, NULL); + + if (re1 == NULL && re2 != NULL) { + ret = njs_unit_test(njs_regexp_test, nxt_nitems(njs_regexp_test), + disassemble, verbose); + if (ret != NXT_OK) { + return ret; + } + + nxt_printf("njs unicode regexp tests passed\n"); + + } else { + nxt_printf("njs unicode regexp tests skipped, libpcre fails\n"); + } + + return NXT_OK; +} + + +static nxt_int_t njs_vm_json_test(nxt_bool_t disassemble, nxt_bool_t verbose) { njs_vm_t *vm; @@ -13025,10 +13130,6 @@ done: int nxt_cdecl main(int argc, char **argv) { - size_t size; - u_char buf[16]; - time_t clock; - struct tm tm; nxt_int_t ret; nxt_bool_t disassemble, verbose; @@ -13059,33 +13160,18 @@ main(int argc, char **argv) return ret; } + ret = njs_timezone_optional_test(disassemble, verbose); + if (ret != NXT_OK) { + return ret; + } + + ret = njs_regexp_optional_test(disassemble, verbose); + if (ret != NXT_OK) { + return ret; + } + nxt_printf("njs unit tests passed\n"); - /* - * Chatham Islands NZ-CHAT time zone. - * Standard time: UTC+12:45, Daylight Saving time: UTC+13:45. - */ - (void) putenv((char *) "TZ=Pacific/Chatham"); - tzset(); - - clock = 0; - localtime_r(&clock, &tm); - - size = strftime((char *) buf, sizeof(buf), "%z", &tm); - - if (memcmp(buf, "+1245", size) == 0) { - ret = njs_unit_test(njs_tz_test, nxt_nitems(njs_tz_test), disassemble, - verbose); - if (ret != NXT_OK) { - return ret; - } - - nxt_printf("njs timezone tests passed\n"); - - } else { - nxt_printf("njs timezone tests skipped, timezone is unavailable\n"); - } - ret = njs_vm_json_test(disassemble, verbose); if (ret != NXT_OK) { return ret; diff -r a88bf03264b4 -r 39790a9d9b58 nxt/nxt_pcre.c --- a/nxt/nxt_pcre.c Tue Apr 16 18:34:57 2019 +0300 +++ b/nxt/nxt_pcre.c Wed Apr 17 18:43:13 2019 +0300 @@ -92,6 +92,8 @@ nxt_regex_compile(nxt_regex_t *regex, u_ "pcre_compile(\"%s\") failed: %s", pattern, errstr); } + ret = NXT_DECLINED; + goto done; } From xeioex at nginx.com Wed Apr 17 18:12:43 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Wed, 17 Apr 2019 18:12:43 +0000 Subject: [njs] Fixed Regexp.prototype.exec() for unicode only regexps. Message-ID: details: https://hg.nginx.org/njs/rev/9c67f7d03672 branches: changeset: 900:9c67f7d03672 user: Dmitry Volyntsev date: Wed Apr 17 21:12:21 2019 +0300 description: Fixed Regexp.prototype.exec() for unicode only regexps. This closes #138 issue on Github. diffstat: njs/njs_regexp.c | 8 +++++--- njs/test/njs_unit_test.c | 3 +++ 2 files changed, 8 insertions(+), 3 deletions(-) diffs (51 lines): diff -r 39790a9d9b58 -r 9c67f7d03672 njs/njs_regexp.c --- a/njs/njs_regexp.c Wed Apr 17 18:43:13 2019 +0300 +++ b/njs/njs_regexp.c Wed Apr 17 21:12:21 2019 +0300 @@ -334,6 +334,8 @@ njs_regexp_pattern_create(njs_vm_t *vm, goto fail; } + pattern->ncaptures = ret; + } else if (ret != NXT_DECLINED) { goto fail; } @@ -633,14 +635,14 @@ njs_regexp_prototype_exec(njs_vm_t *vm, { njs_ret_t ret; njs_utf8_t utf8; - njs_value_t *value; njs_regexp_t *regexp; njs_string_prop_t string; njs_regexp_utf8_t type; + const njs_value_t *value; njs_regexp_pattern_t *pattern; nxt_regex_match_data_t *match_data; - if (!njs_is_regexp(&args[0])) { + if (!njs_is_regexp(njs_arg(args, nargs, 0))) { njs_type_error(vm, "\"this\" argument is not a regexp"); return NXT_ERROR; } @@ -649,7 +651,7 @@ njs_regexp_prototype_exec(njs_vm_t *vm, value = &args[1]; } else { - value = (njs_value_t *) &njs_string_undefined; + value = &njs_string_undefined; } regexp = args[0].data.u.regexp; diff -r 39790a9d9b58 -r 9c67f7d03672 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Wed Apr 17 18:43:13 2019 +0300 +++ b/njs/test/njs_unit_test.c Wed Apr 17 21:12:21 2019 +0300 @@ -11980,6 +11980,9 @@ static njs_unit_test_t njs_regexp_test[ { nxt_string("RegExp('[\\\\u0430-\\\\u044f]+').test('????')"), nxt_string("true") }, + + { nxt_string("RegExp('[\\\\u0430-\\\\u044f]+').exec('????')[0]"), + nxt_string("????") }, }; From benishay at mellanox.com Thu Apr 18 07:32:56 2019 From: benishay at mellanox.com (ben ben ishay) Date: Thu, 18 Apr 2019 10:32:56 +0300 Subject: [PATCH] when we need to transfer data between file and socket we prefer to use sendfile instead of write because we save the copy to a buffer Message-ID: # HG changeset patch # User ben ben ishay # Date 1555572726 -10800 # Thu Apr 18 10:32:06 2019 +0300 # Node ID bb4c564a9f1c5c721c192e6188967c19aabbc0b9 # Parent a6e23e343081b79eb924da985a414909310aa7a3 when we need to transfer data between file and socket we prefer to use sendfile instead of write because we save the copy to a buffer. the use of sendfile is possible in openssl only if it support ktls(the master of openssl support ktls) otherwise there is a copy of the data to userspace for encryption in any case (this paper explain this https://netdevconf.org/1.2/papers/ktls.pdf ). the patch change the flow when the request is to send data over ssl and also the nginx use openssl that support ktls, the new flow using the sendfile function that tcp use for send data (ngx_linux_sendfile_chain). the performence with this patch applied was check with apib benchmark(this is the source https://github.com/apigee/apib),one machine run nginx and the other machine that connect back to back to the first one run apib with this comand: ./apib -c -d 30 https:///. the file size was 100K. the result display in this table , each value represnt average throughput in GBps of 10 runs. num of connection | regular nginx | new nginx 1 5 5.2 2 7.5 8.5 3 7.7 9 this result prove that this patch increase nginx performance and thus is useful. diff -r a6e23e343081 -r bb4c564a9f1c src/event/ngx_event_openssl.c --- a/src/event/ngx_event_openssl.c Tue Apr 09 16:00:30 2019 +0300 +++ b/src/event/ngx_event_openssl.c Thu Apr 18 10:32:06 2019 +0300 @@ -1529,6 +1529,9 @@ sc->connection = SSL_new(ssl->ctx); +#ifdef BIO_get_ktls_send + sc->ktls = 0; +#endif if (sc->connection == NULL) { ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "SSL_new() failed"); return NGX_ERROR; @@ -1639,6 +1642,13 @@ c->recv_chain = ngx_ssl_recv_chain; c->send_chain = ngx_ssl_send_chain; +#if (NGX_LINUX) +#ifdef BIO_get_ktls_send + if(BIO_get_ktls_send(SSL_get_wbio(c->ssl->connection))) + c->ssl->ktls = 1; + c->send_chain = ngx_send_chain; +#endif +#endif #ifndef SSL_OP_NO_RENEGOTIATION #if OPENSSL_VERSION_NUMBER < 0x10100000L #ifdef SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS diff -r a6e23e343081 -r bb4c564a9f1c src/event/ngx_event_openssl.h --- a/src/event/ngx_event_openssl.h Tue Apr 09 16:00:30 2019 +0300 +++ b/src/event/ngx_event_openssl.h Thu Apr 18 10:32:06 2019 +0300 @@ -99,6 +99,9 @@ unsigned in_early:1; unsigned early_preread:1; unsigned write_blocked:1; +#ifdef BIO_get_ktls_send + unsigned ktls:1; +#endif }; diff -r a6e23e343081 -r bb4c564a9f1c src/http/ngx_http_request.c --- a/src/http/ngx_http_request.c Tue Apr 09 16:00:30 2019 +0300 +++ b/src/http/ngx_http_request.c Thu Apr 18 10:32:06 2019 +0300 @@ -604,9 +604,15 @@ } #if (NGX_HTTP_SSL) - if (c->ssl) { +#ifndef BIO_get_ktls_send + if (c->ssl){ r->main_filter_need_in_memory = 1; } +#else + if(c->ssl && !c->ssl->ktls){ + r->main_filter_need_in_memory = 1; + } +#endif #endif r->main = r; diff -r a6e23e343081 -r bb4c564a9f1c src/os/unix/ngx_linux_sendfile_chain.c --- a/src/os/unix/ngx_linux_sendfile_chain.c Tue Apr 09 16:00:30 2019 +0300 +++ b/src/os/unix/ngx_linux_sendfile_chain.c Thu Apr 18 10:32:06 2019 +0300 @@ -256,7 +256,15 @@ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, "sendfile: @%O %uz", file->file_pos, size); +#if (NGX_HTTP_SSL) + if (c->ssl) { + n = SSL_sendfile(c->ssl->connection, file->file->fd, offset, size, 0); + } else { + n = sendfile(c->fd, file->file->fd, &offset, size); + } +#else n = sendfile(c->fd, file->file->fd, &offset, size); +#endif if (n == -1) { err = ngx_errno; From benishay at mellanox.com Thu Apr 18 07:50:14 2019 From: benishay at mellanox.com (Ben Ben Ishay) Date: Thu, 18 Apr 2019 07:50:14 +0000 Subject: [PATCH] Add support for using sendfile when openssl support ktls In-Reply-To: <20190410150422.GA1877@mdounin.ru> References: <87938decdb98bf4a06ed.1554896752@gen-l-vrt-211> <20190410150422.GA1877@mdounin.ru> Message-ID: <3dc2c2f8-a55a-3947-576e-8974fd054c00@mellanox.com> Hello! Thank you for the review. we create another patch that take care of your notes.(https://forum.nginx.org/read.php?29,283833) On 4/10/2019 6:04 PM, Maxim Dounin wrote: > Hello! > > On Wed, Apr 10, 2019 at 02:45:52PM +0300, ben ben ishay wrote: > >> # HG changeset patch >> # User ben ben ishay >> # Date 1554896607 -10800 >> # Wed Apr 10 14:43:27 2019 +0300 >> # Node ID 87938decdb98bf4a06ed18002a15156a5e8fbd67 >> # Parent 65074e13f1716e09c28d730586babad7930b7a98 >> Add support for using sendfile when openssl support ktls >> >> when we need to transfer data between file and socket we prefer to use sendfile instead of write because we save the copy to a buffer. >> the use of sendfile is possible in openssl only if it support ktls(the master of openssl support ktls) otherwise there is a copy of the data to userspace for encryption in any case (this paper explain this https://netdevconf.org/1.2/papers/ktls.pdf ). >> the patch change the flow when the request is to send data over ssl and also the nginx use openssl that support ktls, the new flow using the sendfile function that tcp use for send data (ngx_linux_sendfile_chain). >> the performence with this patch applied was check with apib benchmarkhttps://github.com/apigee/apib), one machine run nginx and the other machine that connect back to back to the first one run apib with this comand: ./apib -c -d 30 https:///. >> the file size was 100K. >> >> the result display in this table , each value represnt average throughput in GBps of 10 runs. >> >> num of connection | regular nginx | new nginx >> 1 5 5.2 >> 2 7.5 8.5 >> 3 7.7 9 >> >> this result prove that this patch increase nginx performance and thus is useful. > > Thank you for your patch. We've helped to develop similar > functionality by Netflix for in-kernel TLS on FreeBSD (an earlier > paper is referenced by the ktls.pdf you've linked). See, for > example, this post for a high-level description: > >[...] > > The most obvious difference one can observe is that the > application-level code instead uses SSL_sendfile() call as > provided by the SSL library, and it is library responsibility to > make sure keys are properly synced with the kernel when > kernel-level functions are called. > > In contrast, in your patch you assume that as long as > BIO_get_ktls_send() returns true it is safe to use native kernel > functions. This looks unsafe, at least without a documentation > which explicitly states otherwise, as various control messages > might interfere with direct calls on the socket. Moreover, quick > look at the code seems to suggest that this is indeed might be > unsafe - before writing anything to the socket OpenSSL checks if > there are any pending control messages, and using sendfile() > directly won't allow this to happen: > > [...] > > As such, the patch doesn't look correct to me (or at least > OpenSSL's interface needs further clarification). > > [...] we have a patch for openssl that introduces SSL_sendfile (https://github.com/openssl/openssl/pull/8727), this function handled the control message and we use it instead of the regular sendfile. > >> @@ -140,3 +140,12 @@ >> fi >> >> fi >> +ngx_feature="OpenSSL library with KTLS" >> +ngx_feature_name="NGX_OPENSSL_KTLS" >> +ngx_feature_run=no >> +ngx_feature_incs="#include \"openssl/bio.h\" " >> +ngx_feature_path= >> +ngx_feature_libs="-lssl -lcrypto $NGX_LIBDL $NGX_LIBPTHREAD" >> +ngx_feature_test="BIO_get_ktls_send(NULL)" >> +. auto/feature >> + > > Note that we don't really use configure-time feature tests for > OpenSSL. Instead, consider checking appropriate #define, such as > #ifdef BIO_get_ktls_send. > >> diff -r 65074e13f171 -r 87938decdb98 src/event/ngx_event_openssl.c >> --- a/src/event/ngx_event_openssl.c Tue Mar 26 09:33:57 2019 +0300 >> +++ b/src/event/ngx_event_openssl.c Wed Apr 10 14:43:27 2019 +0300 >> @@ -1528,6 +1528,9 @@ >> #endif >> >> sc->connection = SSL_new(ssl->ctx); >> +#if (NGX_OPENSSL_KTLS) >> + sc->ktls = 0; >> +#endif >> >> if (sc->connection == NULL) { >> ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "SSL_new() failed"); >> @@ -1639,6 +1642,12 @@ >> c->recv_chain = ngx_ssl_recv_chain; >> c->send_chain = ngx_ssl_send_chain; >> >> +#if (NGX_OPENSSL_KTLS) >> + if(BIO_get_ktls_send(SSL_get_wbio(c->ssl->connection))){ >> + c->ssl->ktls = 1; >> + c->send_chain = ngx_linux_sendfile_chain; >> + } >> +#endif > > Note that compiling this will fail on anything but Linux as long > as BIO_get_ktls_send() is present in the OpenSSL library, as > ngx_linux_sendfile_chain() is only available on Linux. > > [...] > In these days the BIO_get_ktls_send supported only in linux, we add to the new patch a #if (NGX_LINUX) that ensure this code will compile only if the nginx runs on linux, thus we can use the generic fucntion ngx_send_chain instead. we want to hear your opinion about this, we didnt change the no-linux sendfile function to support SSL_sendfile cause we cant check the correctness of this on our system, and the openssl dont support it as well. if you think we need to implement this although we cant verify it Please let us know what you think. From spacewanderlzx at gmail.com Thu Apr 18 10:13:16 2019 From: spacewanderlzx at gmail.com (Zexuan Luo) Date: Thu, 18 Apr 2019 18:13:16 +0800 Subject: [PATCH] Events: closed unused listening fds in worker processes. Message-ID: # HG changeset patch # User spacewander # Date 1555581540 -28800 # Thu Apr 18 17:59:00 2019 +0800 # Branch ident # Node ID 4fb5603514f2d324c50cb7e12c6ed0dc8935de0f # Parent e0834ca20c9c68c4f0728f85efb3651732134ee2 Events: closed unused listening fds in worker processes. It doesn't affect the listening socket, since there is only one used fd which associates to the socket with or without this change. diff -r e0834ca20c9c -r 4fb5603514f2 src/core/ngx_connection.c --- a/src/core/ngx_connection.c Thu Apr 05 12:33:14 2018 +0800 +++ b/src/core/ngx_connection.c Thu Apr 18 17:59:00 2019 +0800 @@ -975,6 +975,14 @@ ls = cycle->listening.elts; for (i = 0; i < cycle->listening.nelts; i++) { +#if (NGX_HAVE_REUSEPORT) + + if (ls[i].fd == (ngx_socket_t) -1) { + continue; + } + +#endif + c = ls[i].connection; if (c) { diff -r e0834ca20c9c -r 4fb5603514f2 src/event/ngx_event.c --- a/src/event/ngx_event.c Thu Apr 05 12:33:14 2018 +0800 +++ b/src/event/ngx_event.c Thu Apr 18 17:59:00 2019 +0800 @@ -735,6 +735,18 @@ #if (NGX_HAVE_REUSEPORT) if (ls[i].reuseport && ls[i].worker != ngx_worker) { + ngx_log_debug2(NGX_LOG_DEBUG_CORE, cycle->log, 0, + "close unused listening %V #%d ", + &ls[i].addr_text, ls[i].fd); + + if (ngx_close_socket(ls[i].fd) == -1) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno, + ngx_close_socket_n " %V failed", + &ls[i].addr_text); + } + + ls[i].fd = (ngx_socket_t) -1; + continue; } #endif From spacewanderlzx at gmail.com Thu Apr 18 10:18:09 2019 From: spacewanderlzx at gmail.com (Zexuan Luo) Date: Thu, 18 Apr 2019 18:18:09 +0800 Subject: [PATCH] Events: closed unused listening fds in worker processes. In-Reply-To: References: Message-ID: When reuseport is enabled in the 'listen ...' directive and a great number of worker processes are used, each worker will inherit lots of listening fds from the master process. In one of our environments, one worker could have 1.5k fds before it starts to accept any request. This situation is too scary to the system administrator. Zexuan Luo ?2019?4?18??? ??6:13??? > > # HG changeset patch > # User spacewander > # Date 1555581540 -28800 > # Thu Apr 18 17:59:00 2019 +0800 > # Branch ident > # Node ID 4fb5603514f2d324c50cb7e12c6ed0dc8935de0f > # Parent e0834ca20c9c68c4f0728f85efb3651732134ee2 > Events: closed unused listening fds in worker processes. > > It doesn't affect the listening socket, since there is > only one used fd which associates to the socket with or > without this change. > > diff -r e0834ca20c9c -r 4fb5603514f2 src/core/ngx_connection.c > --- a/src/core/ngx_connection.c Thu Apr 05 12:33:14 2018 +0800 > +++ b/src/core/ngx_connection.c Thu Apr 18 17:59:00 2019 +0800 > @@ -975,6 +975,14 @@ > ls = cycle->listening.elts; > for (i = 0; i < cycle->listening.nelts; i++) { > > +#if (NGX_HAVE_REUSEPORT) > + > + if (ls[i].fd == (ngx_socket_t) -1) { > + continue; > + } > + > +#endif > + > c = ls[i].connection; > > if (c) { > diff -r e0834ca20c9c -r 4fb5603514f2 src/event/ngx_event.c > --- a/src/event/ngx_event.c Thu Apr 05 12:33:14 2018 +0800 > +++ b/src/event/ngx_event.c Thu Apr 18 17:59:00 2019 +0800 > @@ -735,6 +735,18 @@ > > #if (NGX_HAVE_REUSEPORT) > if (ls[i].reuseport && ls[i].worker != ngx_worker) { > + ngx_log_debug2(NGX_LOG_DEBUG_CORE, cycle->log, 0, > + "close unused listening %V #%d ", > + &ls[i].addr_text, ls[i].fd); > + > + if (ngx_close_socket(ls[i].fd) == -1) { > + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno, > + ngx_close_socket_n " %V failed", > + &ls[i].addr_text); > + } > + > + ls[i].fd = (ngx_socket_t) -1; > + > continue; > } > #endif From xeioex at nginx.com Thu Apr 18 12:20:12 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Thu, 18 Apr 2019 12:20:12 +0000 Subject: [njs] Shell: fixed njs_vm_value_dump() for empty string values. Message-ID: details: https://hg.nginx.org/njs/rev/108ef0cd302d branches: changeset: 901:108ef0cd302d user: Dmitry Volyntsev date: Thu Apr 18 15:05:27 2019 +0300 description: Shell: fixed njs_vm_value_dump() for empty string values. This closes #139 issue on Github. diffstat: njs/njs_json.c | 16 +++++++++------- njs/test/njs_expect_test.exp | 2 ++ 2 files changed, 11 insertions(+), 7 deletions(-) diffs (40 lines): diff -r 9c67f7d03672 -r 108ef0cd302d njs/njs_json.c --- a/njs/njs_json.c Wed Apr 17 21:12:21 2019 +0300 +++ b/njs/njs_json.c Thu Apr 18 15:05:27 2019 +0300 @@ -1961,15 +1961,17 @@ njs_json_buf_append(njs_json_stringify_t { u_char *p; - p = njs_json_buf_reserve(stringify, len); - if (nxt_slow_path(p == NULL)) { - return NXT_ERROR; + if (len != 0) { + p = njs_json_buf_reserve(stringify, len); + if (nxt_slow_path(p == NULL)) { + return NXT_ERROR; + } + + memcpy(p, msg, len); + + njs_json_buf_written(stringify, len); } - memcpy(p, msg, len); - - njs_json_buf_written(stringify, len); - return NXT_OK; } diff -r 9c67f7d03672 -r 108ef0cd302d njs/test/njs_expect_test.exp --- a/njs/test/njs_expect_test.exp Wed Apr 17 21:12:21 2019 +0300 +++ b/njs/test/njs_expect_test.exp Thu Apr 18 15:05:27 2019 +0300 @@ -188,6 +188,8 @@ njs_test { njs_test { {"console.log()\r\n" "console.log()\r\nundefined\r\n>> "} + {"console.log('')\r\n" + "console.log('')\r\n\r\nundefined\r\n>> "} {"console.log(1)\r\n" "console.log(1)\r\n1\r\nundefined\r\n>> "} {"console.log(1, 'a')\r\n" From mdounin at mdounin.ru Thu Apr 18 13:07:33 2019 From: mdounin at mdounin.ru (Maxim Dounin) Date: Thu, 18 Apr 2019 16:07:33 +0300 Subject: [PATCH] when we need to transfer data between file and socket we prefer to use sendfile instead of write because we save the copy to a buffer In-Reply-To: References: Message-ID: <20190418130733.GZ1877@mdounin.ru> Hello! On Thu, Apr 18, 2019 at 10:32:56AM +0300, ben ben ishay wrote: > # HG changeset patch > # User ben ben ishay > # Date 1555572726 -10800 > # Thu Apr 18 10:32:06 2019 +0300 > # Node ID bb4c564a9f1c5c721c192e6188967c19aabbc0b9 > # Parent a6e23e343081b79eb924da985a414909310aa7a3 > when we need to transfer data between file and socket we prefer to use sendfile instead of write because we save the copy to a buffer. > the use of sendfile is possible in openssl only if it support ktls(the master of openssl support ktls) otherwise there is a copy of the data to userspace for encryption in any case (this paper explain this https://netdevconf.org/1.2/papers/ktls.pdf ). > the patch change the flow when the request is to send data over ssl and also the nginx use openssl that support ktls, the new flow using the sendfile function that tcp use for send data (ngx_linux_sendfile_chain). > the performence with this patch applied was check with apib benchmark(this is the source https://github.com/apigee/apib),one machine run nginx and the other machine that connect back to back to the first one run apib with this comand: ./apib -c -d 30 https:///. > the file size was 100K. > > the result display in this table , each value represnt average throughput in GBps of 10 runs. > > num of connection | regular nginx | new nginx > 1 5 5.2 > 2 7.5 8.5 > 3 7.7 9 > > this result prove that this patch increase nginx performance and thus is useful. In no particular order: - Please read http://nginx.org/en/docs/contributing_changes.html for basic tips on how to submit patches. In particular, please make sure to follow nginx coding style. - Note well that at least one bug in your code is directly related to incorrect indentation and failure to properly use curly brackets as explicitly required by the coding style. The style is there to prevent such accidental bugs. - When you update your patches based on the feedback given, consider replying to the thread in question instead of posting a new thread. If for some reason you think a new thread will be better, describe these reasons and post a reference to the old thread. Also, make sure to describe changes you've made based on the feedback. - The SSL_sendfile() call you are using in this version does not seem to exists in any published version of OpenSSL, including github repo. This is not going to work. - The approach you are using - that is, introducing changes into ngx_linux_sendfile_chain.c - is not portable, and is not going to work on other platforms if/when appropriate kernel level and OpenSSL level support will be available. As suggested in the previous thread, this should be something handled at the ngx_event_openssl.c level. [...] -- Maxim Dounin http://mdounin.ru/ From mdounin at mdounin.ru Thu Apr 18 13:32:54 2019 From: mdounin at mdounin.ru (Maxim Dounin) Date: Thu, 18 Apr 2019 16:32:54 +0300 Subject: [PATCH] Events: closed unused listening fds in worker processes. In-Reply-To: References: Message-ID: <20190418133254.GA1877@mdounin.ru> Hello! On Thu, Apr 18, 2019 at 06:18:09PM +0800, Zexuan Luo wrote: > When reuseport is enabled in the 'listen ...' directive and a great > number of worker processes are used, each worker will inherit lots of > listening fds from the master process. > In one of our environments, one worker could have 1.5k fds before it > starts to accept any request. This situation is too scary to the > system administrator. Thank you for your patch. If the problem is how scared your system administrators are, I think one of these approaches might be better: - Avoid configuring things which scare them. In particular, you may want to avoid using reuseport when using very large number of worker processes and large number of distinct listening sockets. - Train your system administrators to not be scared in such cases. Note well that regardless of the number of file descriptors open by a particular worker process, corresponding listening sockets are open. Closing this file descriptors might save some slots in the process file descriptor table, but that's all. And that's more or less nothing in terms of resources, even with 1.5k file descriptors. -- Maxim Dounin http://mdounin.ru/ From xeioex at nginx.com Thu Apr 18 15:15:04 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Thu, 18 Apr 2019 15:15:04 +0000 Subject: [njs] Improved working with arguments in Regexp.prototype methods. Message-ID: details: https://hg.nginx.org/njs/rev/e4ba35c2844b branches: changeset: 902:e4ba35c2844b user: Dmitry Volyntsev date: Thu Apr 18 15:44:37 2019 +0300 description: Improved working with arguments in Regexp.prototype methods. diffstat: njs/njs_regexp.c | 21 ++++++++------------- 1 files changed, 8 insertions(+), 13 deletions(-) diffs (54 lines): diff -r 108ef0cd302d -r e4ba35c2844b njs/njs_regexp.c --- a/njs/njs_regexp.c Thu Apr 18 15:05:27 2019 +0300 +++ b/njs/njs_regexp.c Thu Apr 18 15:44:37 2019 +0300 @@ -552,7 +552,7 @@ static njs_ret_t njs_regexp_prototype_to_string(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused) { - if (njs_is_regexp(&args[0])) { + if (njs_is_regexp(njs_arg(args, nargs, 0))) { return njs_regexp_to_string(vm, &vm->retval, &args[0]); } @@ -587,23 +587,20 @@ njs_regexp_prototype_test(njs_vm_t *vm, { njs_ret_t ret; nxt_uint_t n; - njs_value_t *value; - const njs_value_t *retval; + const njs_value_t *value, *retval; njs_string_prop_t string; njs_regexp_pattern_t *pattern; - if (!njs_is_regexp(&args[0])) { + if (!njs_is_regexp(njs_arg(args, nargs, 0))) { njs_type_error(vm, "\"this\" argument is not a regexp"); return NXT_ERROR; } retval = &njs_value_false; - if (nargs > 1) { - value = &args[1]; - - } else { - value = (njs_value_t *) &njs_string_undefined; + value = njs_arg(args, nargs, 1); + if (njs_is_undefined(value)) { + value = &njs_string_undefined; } (void) njs_string_prop(&string, value); @@ -647,10 +644,8 @@ njs_regexp_prototype_exec(njs_vm_t *vm, return NXT_ERROR; } - if (nargs > 1) { - value = &args[1]; - - } else { + value = njs_arg(args, nargs, 1); + if (njs_is_undefined(value)) { value = &njs_string_undefined; } From xeioex at nginx.com Thu Apr 18 15:15:04 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Thu, 18 Apr 2019 15:15:04 +0000 Subject: [njs] Fixed RegExp constructor for regexp value arguments. Message-ID: details: https://hg.nginx.org/njs/rev/664d366b515a branches: changeset: 903:664d366b515a user: Dmitry Volyntsev date: Thu Apr 18 18:14:56 2019 +0300 description: Fixed RegExp constructor for regexp value arguments. This closes #59 issue on Github. diffstat: njs/njs_builtin.c | 3 +- njs/njs_regexp.c | 101 ++++++++++++++++++++++++++++++++++++++-------- njs/test/njs_unit_test.c | 33 +++++++++++++++ 3 files changed, 117 insertions(+), 20 deletions(-) diffs (193 lines): diff -r e4ba35c2844b -r 664d366b515a njs/njs_builtin.c --- a/njs/njs_builtin.c Thu Apr 18 15:44:37 2019 +0300 +++ b/njs/njs_builtin.c Thu Apr 18 18:14:56 2019 +0300 @@ -146,8 +146,7 @@ const njs_function_init_t njs_native_co { njs_number_constructor, { NJS_SKIP_ARG, NJS_NUMBER_ARG } }, { njs_string_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, { njs_function_constructor, { 0 } }, - { njs_regexp_constructor, - { NJS_SKIP_ARG, NJS_STRING_ARG, NJS_STRING_ARG } }, + { njs_regexp_constructor, { 0 } }, { njs_date_constructor, { 0 } }, { njs_hash_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, { njs_hmac_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG, diff -r e4ba35c2844b -r 664d366b515a njs/njs_regexp.c --- a/njs/njs_regexp.c Thu Apr 18 15:44:37 2019 +0300 +++ b/njs/njs_regexp.c Thu Apr 18 18:14:56 2019 +0300 @@ -15,6 +15,8 @@ static void *njs_regexp_malloc(size_t si static void njs_regexp_free(void *p, void *memory_data); static njs_regexp_flags_t njs_regexp_flags(u_char **start, u_char *end, nxt_bool_t bound); +static njs_ret_t njs_regexp_prototype_source(njs_vm_t *vm, njs_value_t *value, + njs_value_t *setval, njs_value_t *retval); static int njs_regexp_pattern_compile(njs_vm_t *vm, nxt_regex_t *regex, u_char *source, int options); static u_char *njs_regexp_compile_trace_handler(nxt_trace_t *trace, @@ -63,43 +65,106 @@ njs_regexp_free(void *p, void *memory_da } +static njs_regexp_flags_t +njs_regexp_value_flags(njs_vm_t *vm, const njs_value_t *regexp) +{ + njs_regexp_flags_t flags; + njs_regexp_pattern_t *pattern; + + flags = 0; + + pattern = regexp->data.u.regexp->pattern; + + if (pattern->global) { + flags |= NJS_REGEXP_GLOBAL; + } + + if (pattern->ignore_case) { + flags |= NJS_REGEXP_IGNORE_CASE; + } + + if (pattern->multiline) { + flags |= NJS_REGEXP_MULTILINE; + } + + return flags; +} + + 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; + njs_ret_t ret; nxt_str_t string; - njs_regexp_flags_t flags; + njs_value_t source, flags_string; + const njs_value_t *pattern, *flags; + njs_regexp_flags_t re_flags; + + pattern = njs_arg(args, nargs, 1); + + if (!njs_is_regexp(pattern) && !njs_is_primitive(pattern)) { + njs_vm_trap_value(vm, &args[1]); - flags = 0; + return njs_trap(vm, NJS_TRAP_STRING_ARG); + } + + flags = njs_arg(args, nargs, 2); - switch (nargs) { + if (!njs_is_primitive(flags)) { + njs_vm_trap_value(vm, &args[2]); + + return njs_trap(vm, NJS_TRAP_STRING_ARG); + } + + re_flags = 0; - case 1: - string.start = NULL; - string.length = 0; - break; + if (njs_is_regexp(pattern)) { + ret = njs_regexp_prototype_source(vm, (njs_value_t *) pattern, NULL, + &source); + if (nxt_slow_path(ret != NXT_OK)) { + return ret; + } + + re_flags = njs_regexp_value_flags(vm, pattern); + + pattern = &source; + + } else { + if (njs_is_undefined(pattern)) { + pattern = &njs_string_empty; + } - default: - njs_string_get(&args[2], &string); + ret = njs_primitive_value_to_string(vm, &source, pattern); + if (nxt_slow_path(ret != NXT_OK)) { + return ret; + } + + pattern = &source; + } + + if (!njs_is_undefined(flags)) { + ret = njs_primitive_value_to_string(vm, &flags_string, flags); + if (nxt_slow_path(ret != NXT_OK)) { + return ret; + } + + njs_string_get(&flags_string, &string); start = string.start; - flags = njs_regexp_flags(&start, start + string.length, 1); - if (nxt_slow_path(flags < 0)) { + re_flags = njs_regexp_flags(&start, start + string.length, 1); + if (nxt_slow_path(re_flags < 0)) { njs_syntax_error(vm, "Invalid RegExp flags \"%V\"", &string); return NXT_ERROR; } - - /* Fall through. */ - - case 2: - njs_string_get(&args[1], &string); - break; } + njs_string_get(pattern, &string); + return njs_regexp_create(vm, &vm->retval, string.start, string.length, - flags); + re_flags); } diff -r e4ba35c2844b -r 664d366b515a njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Thu Apr 18 15:44:37 2019 +0300 +++ b/njs/test/njs_unit_test.c Thu Apr 18 18:14:56 2019 +0300 @@ -6967,6 +6967,39 @@ static njs_unit_test_t njs_test[] = { nxt_string("new RegExp('', 'x')"), nxt_string("SyntaxError: Invalid RegExp flags \"x\"") }, + { nxt_string("RegExp({})"), + nxt_string("/[object Object]/") }, + + { nxt_string("RegExp(true)"), + nxt_string("/true/") }, + + { nxt_string("RegExp(undefined)"), + nxt_string("/(?:)/") }, + + { nxt_string("RegExp('abc', undefined)"), + nxt_string("/abc/") }, + + { nxt_string("RegExp('abc', {})"), + nxt_string("SyntaxError: Invalid RegExp flags \"[object Object]\"") }, + + { nxt_string("RegExp(/expr/)"), + nxt_string("/expr/") }, + + { nxt_string("RegExp(/expr/i).ignoreCase"), + nxt_string("true") }, + + { nxt_string("RegExp(/expr/, 'x')"), + nxt_string("SyntaxError: Invalid RegExp flags \"x\"") }, + + { nxt_string("RegExp(new RegExp('expr'))"), + nxt_string("/expr/") }, + + { nxt_string("RegExp(new RegExp('expr')).multiline"), + nxt_string("false") }, + + { nxt_string("RegExp(new RegExp('expr'), 'm').multiline"), + nxt_string("true") }, + { nxt_string("new RegExp('[')"), nxt_string("SyntaxError: pcre_compile(\"[\") failed: missing terminating ] for character class") }, From alexander.borisov at nginx.com Thu Apr 18 16:10:16 2019 From: alexander.borisov at nginx.com (Alexander Borisov) Date: Thu, 18 Apr 2019 16:10:16 +0000 Subject: [njs] Saving hash key to result for each() function in level hash. Message-ID: details: https://hg.nginx.org/njs/rev/91a74d5ffc5d branches: changeset: 904:91a74d5ffc5d user: Alexander Borisov date: Mon Apr 08 19:01:56 2019 +0300 description: Saving hash key to result for each() function in level hash. diffstat: nxt/nxt_lvlhsh.c | 1 + nxt/nxt_lvlhsh.h | 1 + 2 files changed, 2 insertions(+), 0 deletions(-) diffs (22 lines): diff -r 664d366b515a -r 91a74d5ffc5d nxt/nxt_lvlhsh.c --- a/nxt/nxt_lvlhsh.c Thu Apr 18 18:14:56 2019 +0300 +++ b/nxt/nxt_lvlhsh.c Mon Apr 08 19:01:56 2019 +0300 @@ -842,6 +842,7 @@ nxt_lvlhsh_bucket_each(nxt_lvlhsh_each_t } while (nxt_lvlhsh_free_entry(bucket)); value = nxt_lvlhsh_entry_value(bucket); + lhe->key_hash = nxt_lvlhsh_entry_key(bucket); lhe->entries--; diff -r 664d366b515a -r 91a74d5ffc5d nxt/nxt_lvlhsh.h --- a/nxt/nxt_lvlhsh.h Thu Apr 18 18:14:56 2019 +0300 +++ b/nxt/nxt_lvlhsh.h Mon Apr 08 19:01:56 2019 +0300 @@ -171,6 +171,7 @@ typedef struct { uint32_t current; uint32_t entry; uint32_t entries; + uint32_t key_hash; } nxt_lvlhsh_each_t; From alexander.borisov at nginx.com Thu Apr 18 16:10:17 2019 From: alexander.borisov at nginx.com (Alexander Borisov) Date: Thu, 18 Apr 2019 16:10:17 +0000 Subject: [njs] Added function to get length of the string. Message-ID: details: https://hg.nginx.org/njs/rev/e4f3b3b97990 branches: changeset: 905:e4f3b3b97990 user: Alexander Borisov date: Wed Apr 17 17:13:39 2019 +0300 description: Added function to get length of the string. Renamed function njs_string_length() to njs_string_eval_length(). diffstat: njs/njs_regexp.c | 2 +- njs/njs_string.c | 8 ++++---- njs/njs_string.h | 20 +++++++++++++++++++- 3 files changed, 24 insertions(+), 6 deletions(-) diffs (88 lines): diff -r 91a74d5ffc5d -r e4f3b3b97990 njs/njs_regexp.c --- a/njs/njs_regexp.c Mon Apr 08 19:01:56 2019 +0300 +++ b/njs/njs_regexp.c Wed Apr 17 17:13:39 2019 +0300 @@ -797,7 +797,7 @@ njs_regexp_exec_result(njs_vm_t *vm, njs start = &string[captures[n]]; size = captures[n + 1] - captures[n]; - length = njs_string_length(utf8, start, size); + length = njs_string_calc_length(utf8, start, size); ret = njs_regexp_string_create(vm, &array->start[i], start, size, length); diff -r 91a74d5ffc5d -r e4f3b3b97990 njs/njs_string.c --- a/njs/njs_string.c Mon Apr 08 19:01:56 2019 +0300 +++ b/njs/njs_string.c Wed Apr 17 17:13:39 2019 +0300 @@ -2691,7 +2691,7 @@ njs_string_match_multiple(njs_vm_t *vm, size = captures[1] - captures[0]; - length = njs_string_length(utf8, start, size); + length = njs_string_calc_length(utf8, start, size); ret = njs_string_new(vm, &array->start[array->length], start, size, length); @@ -2890,7 +2890,7 @@ njs_string_split_part_add(njs_vm_t *vm, { ssize_t length; - length = njs_string_length(utf8, start, size); + length = njs_string_calc_length(utf8, start, size); return njs_array_string_add(vm, array, start, size, length); } @@ -3133,7 +3133,7 @@ njs_string_replace_regexp_function(njs_v size = captures[k + 1] - captures[k]; k += 2; - length = njs_string_length(r->utf8, start, size); + length = njs_string_calc_length(r->utf8, start, size); ret = njs_string_new(vm, &arguments[i], start, size, length); if (nxt_slow_path(ret != NXT_OK)) { @@ -3145,7 +3145,7 @@ njs_string_replace_regexp_function(njs_v njs_value_number_set(&arguments[n + 1], captures[0]); /* The whole string being examined. */ - length = njs_string_length(r->utf8, r->part[0].start, r->part[0].size); + length = njs_string_calc_length(r->utf8, r->part[0].start, r->part[0].size); ret = njs_string_new(vm, &arguments[n + 2], r->part[0].start, r->part[0].size, length); diff -r 91a74d5ffc5d -r e4f3b3b97990 njs/njs_string.h --- a/njs/njs_string.h Mon Apr 08 19:01:56 2019 +0300 +++ b/njs/njs_string.h Wed Apr 17 17:13:39 2019 +0300 @@ -100,7 +100,7 @@ typedef enum { nxt_inline uint32_t -njs_string_length(njs_utf8_t utf8, const u_char *start, size_t size) +njs_string_calc_length(njs_utf8_t utf8, const u_char *start, size_t size) { ssize_t length; @@ -121,6 +121,24 @@ njs_string_length(njs_utf8_t utf8, const } +nxt_inline uint32_t +njs_string_length(njs_value_t *string) +{ + uint32_t length, size; + + if (string->short_string.size != NJS_STRING_LONG) { + size = string->short_string.size; + length = string->short_string.length; + + } else { + size = string->long_string.size; + length = string->long_string.data->length; + } + + return (length == 0) ? size : length; +} + + njs_ret_t njs_string_set(njs_vm_t *vm, njs_value_t *value, const u_char *start, uint32_t size); u_char *njs_string_alloc(njs_vm_t *vm, njs_value_t *value, uint32_t size, From alexander.borisov at nginx.com Thu Apr 18 16:10:17 2019 From: alexander.borisov at nginx.com (Alexander Borisov) Date: Thu, 18 Apr 2019 16:10:17 +0000 Subject: [njs] Walking over prototypes chain during iteration over an object. Message-ID: details: https://hg.nginx.org/njs/rev/7d2d28095c42 branches: changeset: 907:7d2d28095c42 user: Alexander Borisov date: Wed Apr 17 18:00:56 2019 +0300 description: Walking over prototypes chain during iteration over an object. This closes #33 issue on Github. diffstat: njs/njs_vm.c | 93 ++++++++++++++++++----------------------------- njs/test/njs_unit_test.c | 56 ++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+), 58 deletions(-) diffs (209 lines): diff -r 519785f57b81 -r 7d2d28095c42 njs/njs_vm.c --- a/njs/njs_vm.c Wed Apr 17 17:27:14 2019 +0300 +++ b/njs/njs_vm.c Wed Apr 17 18:00:56 2019 +0300 @@ -10,8 +10,8 @@ struct njs_property_next_s { - int32_t index; - nxt_lvlhsh_each_t lhe; + uint32_t index; + njs_array_t *array; }; @@ -764,23 +764,7 @@ njs_vmcode_property_foreach(njs_vm_t *vm const njs_extern_t *ext_proto; njs_vmcode_prop_foreach_t *code; - if (njs_is_object(object)) { - next = nxt_mp_alloc(vm->mem_pool, sizeof(njs_property_next_t)); - if (nxt_slow_path(next == NULL)) { - njs_memory_error(vm); - return NXT_ERROR; - } - - vm->retval.data.u.next = next; - - nxt_lvlhsh_each_init(&next->lhe, &njs_object_hash_proto); - next->index = -1; - - if (njs_is_array(object) && object->data.u.array->length != 0) { - next->index = 0; - } - - } else if (njs_is_external(object)) { + if (njs_is_external(object)) { ext_proto = object->external.proto; if (ext_proto->foreach != NULL) { @@ -791,8 +775,27 @@ njs_vmcode_property_foreach(njs_vm_t *vm return ret; } } + + goto done; } + next = nxt_mp_alloc(vm->mem_pool, sizeof(njs_property_next_t)); + if (nxt_slow_path(next == NULL)) { + njs_memory_error(vm); + return NXT_ERROR; + } + + next->index = 0; + next->array = njs_value_enumerate(vm, object, NJS_ENUM_KEYS, 0); + if (nxt_slow_path(next->array == NULL)) { + njs_memory_error(vm); + return NXT_ERROR; + } + + vm->retval.data.u.next = next; + +done: + code = (njs_vmcode_prop_foreach_t *) vm->current; return code->offset; @@ -804,10 +807,7 @@ njs_vmcode_property_next(njs_vm_t *vm, n { void *obj; njs_ret_t ret; - nxt_uint_t n; njs_value_t *retval; - njs_array_t *array; - njs_object_prop_t *prop; njs_property_next_t *next; const njs_extern_t *ext_proto; njs_vmcode_prop_next_t *code; @@ -815,42 +815,7 @@ njs_vmcode_property_next(njs_vm_t *vm, n code = (njs_vmcode_prop_next_t *) vm->current; retval = njs_vmcode_operand(vm, code->retval); - if (njs_is_object(object)) { - next = value->data.u.next; - - if (next->index >= 0) { - array = object->data.u.array; - - while ((uint32_t) next->index < array->length) { - n = next->index++; - - if (njs_is_valid(&array->start[n])) { - njs_uint32_to_string(retval, n); - - return code->offset; - } - } - - next->index = -1; - } - - for ( ;; ) { - prop = nxt_lvlhsh_each(&object->data.u.object->hash, &next->lhe); - - if (prop == NULL) { - break; - } - - if (prop->type != NJS_WHITEOUT && prop->enumerable) { - *retval = prop->name; - - return code->offset; - } - } - - nxt_mp_free(vm->mem_pool, next); - - } else if (njs_is_external(object)) { + if (njs_is_external(object)) { ext_proto = object->external.proto; if (ext_proto->next != NULL) { @@ -868,8 +833,20 @@ njs_vmcode_property_next(njs_vm_t *vm, n /* ret == NJS_DONE. */ } + + return sizeof(njs_vmcode_prop_next_t); } + next = value->data.u.next; + + if (next->index < next->array->length) { + *retval = next->array->data[ next->index++ ]; + + return code->offset; + } + + nxt_mp_free(vm->mem_pool, next); + return sizeof(njs_vmcode_prop_next_t); } diff -r 519785f57b81 -r 7d2d28095c42 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Wed Apr 17 17:27:14 2019 +0300 +++ b/njs/test/njs_unit_test.c Wed Apr 17 18:00:56 2019 +0300 @@ -7819,6 +7819,62 @@ static njs_unit_test_t njs_test[] = { nxt_string("Object.prototype.__proto__.f()"), nxt_string("TypeError: cannot get property \"f\" of undefined") }, + { nxt_string("var obj = Object.create(null); obj.one = 1;" + "var res = [];" + "for (var val in obj) res.push(val); res"), + nxt_string("one") }, + + { nxt_string("var o1 = Object.create(null); o1.one = 1;" + "var o2 = Object.create(o1); o2.two = 2;" + "var o3 = Object.create(o2); o3.three = 3;" + "var res = [];" + "for (var val in o3) res.push(val); res"), + nxt_string("three,two,one") }, + + { nxt_string("var o1 = Object.create(null); o1.one = 1;" + "var o2 = Object.create(o1);" + "var o3 = Object.create(o2); o3.three = 3;" + "var res = [];" + "for (var val in o3) res.push(val); res"), + nxt_string("three,one") }, + + { nxt_string("var o1 = Object.create(null); o1.one = 1;" + "var o2 = Object.create(o1);" + "var o3 = Object.create(o2);" + "var res = [];" + "for (var val in o3) res.push(val); res"), + nxt_string("one") }, + + { nxt_string("var o1 = Object.create(null); o1.one = 1;" + "var o2 = Object.create(o1); o2.two = 2;" + "var o3 = Object.create(o2); o3.three = 3;" + "o3.two = -2; o3.one = -1;" + "var res = [];" + "for (var val in o3) res.push(val); res"), + nxt_string("three,two,one") }, + + { nxt_string("var a = []; for(var p in 'abc') a.push(p); a"), + nxt_string("0,1,2") }, + + { nxt_string("var a = []; for(var p in Object('abc')) a.push(p); a"), + nxt_string("0,1,2") }, + + { nxt_string("var o = Object('abc'); var x = Object.create(o);" + "x.a = 1; x.b = 2;" + "var a = []; for(var p in x) a.push(p); a"), + nxt_string("a,b,0,1,2") }, + +#if 0 + /* TODO: No properties implementation for array type + * (enumerable, writable, configurable). + */ + + { nxt_string("var o = Object("abc"); var x = Object.create(o);" + "x['sd'] = 44; x[1] = 8; x[55] = 8;" + "Object.keys(x)"), + nxt_string("55,sd") }, +#endif + { nxt_string("Object.prototype.toString.call(Object.prototype)"), nxt_string("[object Object]") }, From alexander.borisov at nginx.com Thu Apr 18 16:10:17 2019 From: alexander.borisov at nginx.com (Alexander Borisov) Date: Thu, 18 Apr 2019 16:10:17 +0000 Subject: [njs] Added two new function for working with enumerate value. Message-ID: details: https://hg.nginx.org/njs/rev/519785f57b81 branches: changeset: 906:519785f57b81 user: Alexander Borisov date: Wed Apr 17 17:27:14 2019 +0300 description: Added two new function for working with enumerate value. New functions njs_value_enumerate() and njs_value_own_enumerate(). Changed function njs_object_enumerate() for working only with object. diffstat: njs/njs_json.c | 5 +- njs/njs_object.c | 966 +++++++++++++++++++++++++++++++++++++++--------------- njs/njs_object.h | 11 +- njs/njs_vm.c | 42 ++ njs/njs_vm.h | 11 + 5 files changed, 751 insertions(+), 284 deletions(-) diffs (truncated from 1205 to 1000 lines): diff -r e4f3b3b97990 -r 519785f57b81 njs/njs_json.c --- a/njs/njs_json.c Wed Apr 17 17:13:39 2019 +0300 +++ b/njs/njs_json.c Wed Apr 17 17:27:14 2019 +0300 @@ -1127,7 +1127,7 @@ njs_json_push_parse_state(njs_vm_t *vm, } else { state->type = NJS_JSON_OBJECT_START; state->prop_value = NULL; - state->keys = njs_object_enumerate(vm, value, NJS_ENUM_KEYS, 0); + state->keys = njs_value_own_enumerate(vm, value, NJS_ENUM_KEYS, 0); if (state->keys == NULL) { return NULL; } @@ -1705,7 +1705,8 @@ njs_json_push_stringify_state(njs_vm_t * state->keys = njs_extern_keys_array(vm, value->external.proto); } else { - state->keys = njs_object_enumerate(vm, value, NJS_ENUM_KEYS, 0); + state->keys = njs_value_own_enumerate(vm, value, NJS_ENUM_KEYS, + 0); } if (state->keys == NULL) { diff -r e4f3b3b97990 -r 519785f57b81 njs/njs_object.c --- a/njs/njs_object.c Wed Apr 17 17:13:39 2019 +0300 +++ b/njs/njs_object.c Wed Apr 17 17:27:14 2019 +0300 @@ -27,6 +27,25 @@ static njs_ret_t njs_object_query_prop_h static njs_ret_t njs_define_property(njs_vm_t *vm, njs_value_t *object, const njs_value_t *name, const njs_object_t *descriptor); +static njs_object_prop_t * njs_object_exist_in_proto(const njs_object_t *begin, + const njs_object_t *end, nxt_lvlhsh_query_t *lhq); +static uint32_t njs_object_enumerate_array_length(const njs_object_t *object); +static uint32_t njs_object_enumerate_string_length(const njs_object_t *object); +static uint32_t njs_object_enumerate_object_length(const njs_object_t *object, + nxt_bool_t all); +static uint32_t njs_object_own_enumerate_object_length( + const njs_object_t *object, const njs_object_t *parent, nxt_bool_t all); +static njs_ret_t njs_object_enumerate_array(njs_vm_t *vm, + const njs_array_t *array, njs_array_t *items, njs_object_enum_t kind); +static njs_ret_t njs_object_enumerate_string(njs_vm_t *vm, + const njs_value_t *value, njs_array_t *items, njs_object_enum_t kind); +static njs_ret_t njs_object_enumerate_object(njs_vm_t *vm, + const njs_object_t *object, njs_array_t *items, njs_object_enum_t kind, + nxt_bool_t all); +static njs_ret_t njs_object_own_enumerate_object(njs_vm_t *vm, + const njs_object_t *object, const njs_object_t *parent, njs_array_t *items, + njs_object_enum_t kind, nxt_bool_t all); + nxt_noinline njs_object_t * njs_object_alloc(njs_vm_t *vm) @@ -886,7 +905,7 @@ njs_object_keys(njs_vm_t *vm, njs_value_ return NXT_ERROR; } - keys = njs_object_enumerate(vm, value, NJS_ENUM_KEYS, 0); + keys = njs_value_own_enumerate(vm, value, NJS_ENUM_KEYS, 0); if (keys == NULL) { return NXT_ERROR; } @@ -915,7 +934,7 @@ njs_object_values(njs_vm_t *vm, njs_valu return NXT_ERROR; } - array = njs_object_enumerate(vm, value, NJS_ENUM_VALUES, 0); + array = njs_value_own_enumerate(vm, value, NJS_ENUM_VALUES, 0); if (array == NULL) { return NXT_ERROR; } @@ -944,7 +963,7 @@ njs_object_entries(njs_vm_t *vm, njs_val return NXT_ERROR; } - array = njs_object_enumerate(vm, value, NJS_ENUM_BOTH, 0); + array = njs_value_own_enumerate(vm, value, NJS_ENUM_BOTH, 0); if (array == NULL) { return NXT_ERROR; } @@ -957,69 +976,306 @@ njs_object_entries(njs_vm_t *vm, njs_val } -njs_array_t * -njs_object_enumerate(njs_vm_t *vm, const njs_value_t *value, - njs_object_enum_t kind, nxt_bool_t all) +static njs_object_prop_t * +njs_object_exist_in_proto(const njs_object_t *begin, const njs_object_t *end, + nxt_lvlhsh_query_t *lhq) { - u_char *dst; - uint32_t i, length, size, items_length, properties; - njs_value_t *string, *item; - njs_array_t *items, *array, *entry; - nxt_lvlhsh_t *hash; - const u_char *src, *end; - njs_object_t *object; + nxt_int_t ret; njs_object_prop_t *prop; - njs_string_prop_t string_prop; - nxt_lvlhsh_each_t lhe; - - array = NULL; - length = 0; - object = NULL; - items_length = 0; - - switch (value->type) { + + lhq->proto = &njs_object_hash_proto; + + while (begin != end) { + ret = nxt_lvlhsh_find(&begin->hash, lhq); + + if (nxt_fast_path(ret == NXT_OK)) { + prop = lhq->value; + + if (prop->type == NJS_WHITEOUT) { + goto next; + } + + return lhq->value; + } + + ret = nxt_lvlhsh_find(&begin->shared_hash, lhq); + + if (nxt_fast_path(ret == NXT_OK)) { + return lhq->value; + } + +next: + + begin = begin->__proto__; + } + + return NULL; +} + + +nxt_inline uint32_t +njs_object_enumerate_length(const njs_object_t *object, nxt_bool_t all) +{ + uint32_t length; + + length = njs_object_enumerate_object_length(object, all); + + switch (object->type) { case NJS_ARRAY: - array = value->data.u.array; - length = array->length; - - for (i = 0; i < length; i++) { - if (njs_is_valid(&array->start[i])) { - items_length++; - } - } - + length += njs_object_enumerate_array_length(object); + break; + + case NJS_OBJECT_STRING: + length += njs_object_enumerate_string_length(object); + break; + + default: break; - - case NJS_STRING: + } + + return length; +} + + +nxt_inline uint32_t +njs_object_own_enumerate_length(const njs_object_t *object, + const njs_object_t *parent, nxt_bool_t all) +{ + uint32_t length; + + length = njs_object_own_enumerate_object_length(object, parent, all); + + switch (object->type) { + case NJS_ARRAY: + length += njs_object_enumerate_array_length(object); + break; + case NJS_OBJECT_STRING: - if (value->type == NJS_OBJECT_STRING) { - string = &value->data.u.object_value->value; - - } else { - string = (njs_value_t *) value; - object = &vm->string_object; - } - - length = njs_string_prop(&string_prop, string); - items_length += length; - + length += njs_object_enumerate_string_length(object); break; default: break; } - /* GCC 4 and Clang 3 complain about uninitialized hash. */ - hash = NULL; - properties = 0; - - if (nxt_fast_path(njs_is_object(value))) { - object = value->data.u.object; + return length; +} + + +nxt_inline njs_ret_t +njs_object_enumerate_value(njs_vm_t *vm, const njs_object_t *object, + njs_array_t *items, njs_object_enum_t kind, nxt_bool_t all) +{ + njs_ret_t ret; + njs_object_value_t *obj_val; + + switch (object->type) { + case NJS_ARRAY: + ret = njs_object_enumerate_array(vm, (njs_array_t *) object, items, + kind); + break; + + case NJS_OBJECT_STRING: + obj_val = (njs_object_value_t *) object; + + ret = njs_object_enumerate_string(vm, &obj_val->value, items, kind); + break; + + default: + goto object; + } + + if (nxt_slow_path(ret != NJS_OK)) { + return NJS_ERROR; + } + +object: + + ret = njs_object_enumerate_object(vm, object, items, kind, all); + if (nxt_slow_path(ret != NJS_OK)) { + return NJS_ERROR; + } + + return NJS_OK; +} + + +nxt_inline njs_ret_t +njs_object_own_enumerate_value(njs_vm_t *vm, const njs_object_t *object, + const njs_object_t *parent, njs_array_t *items, njs_object_enum_t kind, + nxt_bool_t all) +{ + njs_ret_t ret; + njs_object_value_t *obj_val; + + switch (object->type) { + case NJS_ARRAY: + ret = njs_object_enumerate_array(vm, (njs_array_t *) object, items, + kind); + break; + + case NJS_OBJECT_STRING: + obj_val = (njs_object_value_t *) object; + + ret = njs_object_enumerate_string(vm, &obj_val->value, items, kind); + break; + + default: + goto object; + } + + if (nxt_slow_path(ret != NJS_OK)) { + return NJS_ERROR; + } + +object: + + ret = njs_object_own_enumerate_object(vm, object, parent, items, kind, all); + if (nxt_slow_path(ret != NJS_OK)) { + return NJS_ERROR; + } + + return NJS_OK; +} + + +njs_array_t * +njs_object_enumerate(njs_vm_t *vm, const njs_object_t *object, + njs_object_enum_t kind, nxt_bool_t all) +{ + uint32_t length; + njs_ret_t ret; + njs_array_t *items; + + length = njs_object_enumerate_length(object, all); + + items = njs_array_alloc(vm, length, NJS_ARRAY_SPARE); + if (nxt_slow_path(items == NULL)) { + return NULL; + } + + ret = njs_object_enumerate_value(vm, object, items, kind, all); + if (nxt_slow_path(ret != NJS_OK)) { + return NULL; } - if (object != NULL) { + items->start -= items->length; + + return items; +} + + +njs_array_t * +njs_object_own_enumerate(njs_vm_t *vm, const njs_object_t *object, + njs_object_enum_t kind, nxt_bool_t all) +{ + uint32_t length; + njs_ret_t ret; + njs_array_t *items; + + length = njs_object_own_enumerate_length(object, object, all); + + items = njs_array_alloc(vm, length, NJS_ARRAY_SPARE); + if (nxt_slow_path(items == NULL)) { + return NULL; + } + + ret = njs_object_own_enumerate_value(vm, object, object, items, kind, all); + if (nxt_slow_path(ret != NJS_OK)) { + return NULL; + } + + items->start -= items->length; + + return items; +} + + +static uint32_t +njs_object_enumerate_array_length(const njs_object_t *object) +{ + uint32_t i, length; + njs_array_t *array; + + length = 0; + array = (njs_array_t *) object; + + for (i = 0; i < array->length; i++) { + if (njs_is_valid(&array->start[i])) { + length++; + } + } + + return length; +} + + +static uint32_t +njs_object_enumerate_string_length(const njs_object_t *object) +{ + njs_object_value_t *obj_val; + + obj_val = (njs_object_value_t *) object; + + return njs_string_length(&obj_val->value); +} + + +static uint32_t +njs_object_enumerate_object_length(const njs_object_t *object, nxt_bool_t all) +{ + uint32_t length; + const njs_object_t *ptr; + + length = njs_object_own_enumerate_object_length(object, object, all); + + for (ptr = object->__proto__; ptr != NULL; ptr = ptr->__proto__) { + + length += njs_object_own_enumerate_length(ptr, object, all); + } + + return length; +} + + +static uint32_t +njs_object_own_enumerate_object_length(const njs_object_t *object, + const njs_object_t *parent, nxt_bool_t all) +{ + uint32_t length; + nxt_int_t ret; + nxt_lvlhsh_each_t lhe; + njs_object_prop_t *prop, *ext_prop; + nxt_lvlhsh_query_t lhq; + const nxt_lvlhsh_t *hash; + + nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto); + hash = &object->hash; + + length = 0; + + for ( ;; ) { + prop = nxt_lvlhsh_each(hash, &lhe); + + if (prop == NULL) { + break; + } + + lhq.key_hash = lhe.key_hash; + njs_string_get(&prop->name, &lhq.key); + + ext_prop = njs_object_exist_in_proto(parent, object, &lhq); + + if (ext_prop == NULL && prop->type != NJS_WHITEOUT + && (prop->enumerable || all)) + { + length++; + } + } + + if (nxt_slow_path(all)) { nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto); - hash = &object->hash; + hash = &object->shared_hash; for ( ;; ) { prop = nxt_lvlhsh_each(hash, &lhe); @@ -1028,8 +1284,271 @@ njs_object_enumerate(njs_vm_t *vm, const break; } - if (prop->type != NJS_WHITEOUT && (prop->enumerable || all)) { - properties++; + lhq.key_hash = lhe.key_hash; + njs_string_get(&prop->name, &lhq.key); + + lhq.proto = &njs_object_hash_proto; + ret = nxt_lvlhsh_find(&object->hash, &lhq); + + if (ret != NXT_OK) { + ext_prop = njs_object_exist_in_proto(parent, object, &lhq); + + if (ext_prop == NULL) { + length++; + } + } + } + } + + return length; +} + + +static njs_ret_t +njs_object_enumerate_array(njs_vm_t *vm, const njs_array_t *array, + njs_array_t *items, njs_object_enum_t kind) +{ + uint32_t i; + njs_value_t *item; + njs_array_t *entry; + + item = items->start; + + switch (kind) { + case NJS_ENUM_KEYS: + for (i = 0; i < array->length; i++) { + if (njs_is_valid(&array->start[i])) { + njs_uint32_to_string(item++, i); + } + } + + break; + + case NJS_ENUM_VALUES: + for (i = 0; i < array->length; i++) { + if (njs_is_valid(&array->start[i])) { + /* GC: retain. */ + *item++ = array->start[i]; + } + } + + break; + + case NJS_ENUM_BOTH: + for (i = 0; i < array->length; i++) { + if (njs_is_valid(&array->start[i])) { + + entry = njs_array_alloc(vm, 2, 0); + if (nxt_slow_path(entry == NULL)) { + return NJS_ERROR; + } + + njs_uint32_to_string(&entry->start[0], i); + + /* GC: retain. */ + entry->start[1] = array->start[i]; + + item->data.u.array = entry; + item->type = NJS_ARRAY; + item->data.truth = 1; + + item++; + } + } + + break; + } + + items->start = item; + + return NJS_OK; +} + + +static njs_ret_t +njs_object_enumerate_string(njs_vm_t *vm, const njs_value_t *value, + njs_array_t *items, njs_object_enum_t kind) +{ + u_char *begin; + uint32_t i, len, size; + njs_value_t *item, *string; + njs_array_t *entry; + const u_char *src, *end; + njs_string_prop_t str_prop; + + item = items->start; + len = (uint32_t) njs_string_prop(&str_prop, value); + + switch (kind) { + case NJS_ENUM_KEYS: + for (i = 0; i < len; i++) { + njs_uint32_to_string(item++, i); + } + + break; + + case NJS_ENUM_VALUES: + if (str_prop.size == (size_t) len) { + /* Byte or ASCII string. */ + + for (i = 0; i < len; i++) { + begin = njs_string_short_start(item); + *begin = str_prop.start[i]; + + njs_string_short_set(item, 1, 1); + + item++; + } + + } else { + /* UTF-8 string. */ + + src = str_prop.start; + end = src + str_prop.size; + + do { + begin = (u_char *) src; + nxt_utf8_copy(njs_string_short_start(item), &src, end); + size = (uint32_t) (src - begin); + + njs_string_short_set(item, size, 1); + + item++; + + } while (src != end); + } + + break; + + case NJS_ENUM_BOTH: + if (str_prop.size == (size_t) len) { + /* Byte or ASCII string. */ + + for (i = 0; i < len; i++) { + + entry = njs_array_alloc(vm, 2, 0); + if (nxt_slow_path(entry == NULL)) { + return NJS_ERROR; + } + + njs_uint32_to_string(&entry->start[0], i); + + string = &entry->start[1]; + + begin = njs_string_short_start(string); + *begin = str_prop.start[i]; + + njs_string_short_set(string, 1, 1); + + item->data.u.array = entry; + item->type = NJS_ARRAY; + item->data.truth = 1; + + item++; + } + + } else { + /* UTF-8 string. */ + + src = str_prop.start; + end = src + str_prop.size; + i = 0; + + do { + entry = njs_array_alloc(vm, 2, 0); + if (nxt_slow_path(entry == NULL)) { + return NJS_ERROR; + } + + njs_uint32_to_string(&entry->start[0], i++); + + string = &entry->start[1]; + + begin = (u_char *) src; + nxt_utf8_copy(njs_string_short_start(string), &src, end); + size = (uint32_t) (src - begin); + + njs_string_short_set(string, size, 1); + + item->data.u.array = entry; + item->type = NJS_ARRAY; + item->data.truth = 1; + + item++; + + } while (src != end); + } + + break; + } + + items->start = item; + + return NJS_OK; +} + + +static njs_ret_t +njs_object_enumerate_object(njs_vm_t *vm, const njs_object_t *object, + njs_array_t *items, njs_object_enum_t kind, nxt_bool_t all) +{ + njs_ret_t ret; + const njs_object_t *ptr; + + ret = njs_object_own_enumerate_object(vm, object, object, items, kind, all); + if (nxt_slow_path(ret != NXT_OK)) { + return NXT_ERROR; + } + + for (ptr = object->__proto__; ptr != NULL; ptr = ptr->__proto__) { + + ret = njs_object_own_enumerate_value(vm, ptr, object, items, kind, + all); + if (nxt_slow_path(ret != NXT_OK)) { + return NXT_ERROR; + } + } + + return NJS_OK; +} + + +static njs_ret_t +njs_object_own_enumerate_object(njs_vm_t *vm, const njs_object_t *object, + const njs_object_t *parent, njs_array_t *items, njs_object_enum_t kind, + nxt_bool_t all) +{ + nxt_int_t ret; + njs_value_t *item; + njs_array_t *entry; + nxt_lvlhsh_each_t lhe; + njs_object_prop_t *prop, *ext_prop; + nxt_lvlhsh_query_t lhq; + const nxt_lvlhsh_t *hash; + + nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto); + + item = items->start; + hash = &object->hash; + + switch (kind) { + case NJS_ENUM_KEYS: + for ( ;; ) { + prop = nxt_lvlhsh_each(hash, &lhe); + + if (prop == NULL) { + break; + } + + lhq.key_hash = lhe.key_hash; + njs_string_get(&prop->name, &lhq.key); + + ext_prop = njs_object_exist_in_proto(parent, object, &lhq); + + if (ext_prop == NULL && prop->type != NJS_WHITEOUT + && (prop->enumerable || all)) + { + njs_string_copy(item++, &prop->name); } } @@ -1044,179 +1563,49 @@ njs_object_enumerate(njs_vm_t *vm, const break; } - properties++; - } - } - - items_length += properties; - } - - items = njs_array_alloc(vm, items_length, NJS_ARRAY_SPARE); - if (nxt_slow_path(items == NULL)) { - return NULL; - } - - item = items->start; - - if (array != NULL) { - - switch (kind) { - case NJS_ENUM_KEYS: - for (i = 0; i < length; i++) { - if (njs_is_valid(&array->start[i])) { - njs_uint32_to_string(item++, i); - } - } - - break; - - case NJS_ENUM_VALUES: - for (i = 0; i < length; i++) { - if (njs_is_valid(&array->start[i])) { - /* GC: retain. */ - *item++ = array->start[i]; - } - } - - break; - - case NJS_ENUM_BOTH: - for (i = 0; i < length; i++) { - if (njs_is_valid(&array->start[i])) { - entry = njs_array_alloc(vm, 2, 0); - if (nxt_slow_path(entry == NULL)) { - return NULL; + lhq.key_hash = lhe.key_hash; + njs_string_get(&prop->name, &lhq.key); + + lhq.proto = &njs_object_hash_proto; + ret = nxt_lvlhsh_find(&object->hash, &lhq); + + if (ret != NXT_OK) { + ext_prop = njs_object_exist_in_proto(parent, object, &lhq); + + if (ext_prop == NULL) { + njs_string_copy(item++, &prop->name); } - - njs_uint32_to_string(&entry->start[0], i); - - /* GC: retain. */ - entry->start[1] = array->start[i]; - - item->data.u.array = entry; - item->type = NJS_ARRAY; - item->data.truth = 1; - - item++; } } - - break; } - } else if (length != 0) { - - switch (kind) { - case NJS_ENUM_KEYS: - for (i = 0; i < length; i++) { - njs_uint32_to_string(item++, i); - } - - break; - - case NJS_ENUM_VALUES: - if (string_prop.size == (size_t) length) { - /* Byte or ASCII string. */ - - for (i = 0; i < length; i++) { - dst = njs_string_short_start(item); - dst[0] = string_prop.start[i]; - - njs_string_short_set(item, 1, 1); - - item++; - } - - } else { - /* UTF-8 string. */ - - src = string_prop.start; - end = src + string_prop.size; - - do { - dst = njs_string_short_start(item); - dst = nxt_utf8_copy(dst, &src, end); - size = dst - njs_string_short_start(value); - - njs_string_short_set(item, size, 1); - - item++; - - } while (src != end); + break; + + case NJS_ENUM_VALUES: + for ( ;; ) { + prop = nxt_lvlhsh_each(hash, &lhe); + + if (prop == NULL) { + break; } - break; - - case NJS_ENUM_BOTH: - if (string_prop.size == (size_t) length) { - /* Byte or ASCII string. */ - - for (i = 0; i < length; i++) { - entry = njs_array_alloc(vm, 2, 0); - if (nxt_slow_path(entry == NULL)) { - return NULL; - } - - njs_uint32_to_string(&entry->start[0], i); - - string = &entry->start[1]; - - dst = njs_string_short_start(string); - dst[0] = string_prop.start[i]; - - njs_string_short_set(string, 1, 1); - - item->data.u.array = entry; - item->type = NJS_ARRAY; - item->data.truth = 1; - - item++; - } - - } else { - /* UTF-8 string. */ - - src = string_prop.start; - end = src + string_prop.size; - i = 0; - - do { - entry = njs_array_alloc(vm, 2, 0); - if (nxt_slow_path(entry == NULL)) { - return NULL; - } - - njs_uint32_to_string(&entry->start[0], i++); - - string = &entry->start[1]; - - dst = njs_string_short_start(string); - dst = nxt_utf8_copy(dst, &src, end); - size = dst - njs_string_short_start(value); - - njs_string_short_set(string, size, 1); - - item->data.u.array = entry; - item->type = NJS_ARRAY; - item->data.truth = 1; - - item++; - - } while (src != end); + lhq.key_hash = lhe.key_hash; + njs_string_get(&prop->name, &lhq.key); + + ext_prop = njs_object_exist_in_proto(parent, object, &lhq); + + if (ext_prop == NULL && prop->type != NJS_WHITEOUT + && (prop->enumerable || all)) + { + /* GC: retain. */ + *item++ = prop->value; } - - break; } - } - - if (nxt_fast_path(properties != 0)) { - nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto); - - hash = &object->hash; - - switch (kind) { - - case NJS_ENUM_KEYS: + + if (nxt_slow_path(all)) { + nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto); + hash = &object->shared_hash; + for ( ;; ) { prop = nxt_lvlhsh_each(hash, &lhe); @@ -1224,29 +1613,62 @@ njs_object_enumerate(njs_vm_t *vm, const break; } - if (prop->type != NJS_WHITEOUT && (prop->enumerable || all)) { - njs_string_copy(item++, &prop->name); + lhq.key_hash = lhe.key_hash; + njs_string_get(&prop->name, &lhq.key); + + lhq.proto = &njs_object_hash_proto; + ret = nxt_lvlhsh_find(&object->hash, &lhq); + + if (ret != NXT_OK) { + ext_prop = njs_object_exist_in_proto(parent, object, &lhq); + + if (ext_prop == NULL) { + *item++ = prop->value; + } } } - - if (nxt_slow_path(all)) { - nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto); - hash = &object->shared_hash; - - for ( ;; ) { - prop = nxt_lvlhsh_each(hash, &lhe); - - if (prop == NULL) { - break; - } - - njs_string_copy(item++, &prop->name); + } + + break; + + case NJS_ENUM_BOTH: + for ( ;; ) { + prop = nxt_lvlhsh_each(hash, &lhe); + + if (prop == NULL) { + break; + } + + lhq.key_hash = lhe.key_hash; + njs_string_get(&prop->name, &lhq.key); + + ext_prop = njs_object_exist_in_proto(parent, object, &lhq); + + if (ext_prop == NULL && prop->type != NJS_WHITEOUT + && (prop->enumerable || all)) + { + entry = njs_array_alloc(vm, 2, 0); + if (nxt_slow_path(entry == NULL)) { + return NJS_ERROR; } + + njs_string_copy(&entry->start[0], &prop->name); + + /* GC: retain. */ + entry->start[1] = prop->value; + + item->data.u.array = entry; + item->type = NJS_ARRAY; + item->data.truth = 1; + + item++; } - - break; - - case NJS_ENUM_VALUES: + } + + if (nxt_slow_path(all)) { + nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto); + hash = &object->shared_hash; From xeioex at nginx.com Thu Apr 18 16:17:47 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Thu, 18 Apr 2019 16:17:47 +0000 Subject: [njs] Tests: freeing pcre structs to silence leak-sanitizer. Message-ID: details: https://hg.nginx.org/njs/rev/fca54d073408 branches: changeset: 908:fca54d073408 user: Dmitry Volyntsev date: Thu Apr 18 19:17:22 2019 +0300 description: Tests: freeing pcre structs to silence leak-sanitizer. diffstat: njs/test/njs_unit_test.c | 8 ++++++++ 1 files changed, 8 insertions(+), 0 deletions(-) diffs (18 lines): diff -r 7d2d28095c42 -r fca54d073408 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Wed Apr 17 18:00:56 2019 +0300 +++ b/njs/test/njs_unit_test.c Thu Apr 18 19:17:22 2019 +0300 @@ -12907,6 +12907,14 @@ njs_regexp_optional_test(nxt_bool_t disa nxt_printf("njs unicode regexp tests skipped, libpcre fails\n"); } + if (re1 != NULL) { + pcre_free(re1); + } + + if (re2 != NULL) { + pcre_free(re2); + } + return NXT_OK; } From xeioex at nginx.com Thu Apr 18 17:20:44 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Thu, 18 Apr 2019 17:20:44 +0000 Subject: [njs] Refactored variable reference. Message-ID: details: https://hg.nginx.org/njs/rev/ec44a042cf15 branches: changeset: 909:ec44a042cf15 user: hongzhidao date: Fri Apr 19 00:28:31 2019 +0800 description: Refactored variable reference. diffstat: njs/njs_generator.c | 9 ++++----- njs/njs_parser.c | 24 ++++++++++++++++++++++-- njs/njs_variable.c | 10 +--------- 3 files changed, 27 insertions(+), 16 deletions(-) diffs (110 lines): diff -r fca54d073408 -r ec44a042cf15 njs/njs_generator.c --- a/njs/njs_generator.c Thu Apr 18 19:17:22 2019 +0300 +++ b/njs/njs_generator.c Fri Apr 19 00:28:31 2019 +0800 @@ -1648,13 +1648,11 @@ njs_generate_assignment(njs_vm_t *vm, nj if (lvalue->token == NJS_TOKEN_NAME) { - index = njs_variable_index(vm, lvalue); - if (nxt_slow_path(index == NJS_INDEX_ERROR)) { - return NXT_ERROR; + ret = njs_generate_variable(vm, generator, lvalue); + if (nxt_slow_path(ret != NXT_OK)) { + return ret; } - lvalue->index = index; - expr->dest = lvalue; ret = njs_generator(vm, generator, expr); @@ -1757,6 +1755,7 @@ njs_generate_operation_assignment(njs_vm lvalue = node->left; if (lvalue->token == NJS_TOKEN_NAME) { + ret = njs_generate_variable(vm, generator, lvalue); if (nxt_slow_path(ret != NXT_OK)) { return ret; diff -r fca54d073408 -r ec44a042cf15 njs/njs_parser.c --- a/njs/njs_parser.c Thu Apr 18 19:17:22 2019 +0300 +++ b/njs/njs_parser.c Fri Apr 19 00:28:31 2019 +0800 @@ -522,6 +522,19 @@ njs_parser_variable_node(njs_vm_t *vm, n return NULL; } + if (njs_is_null(&var->value)) { + + switch (type) { + + case NJS_VARIABLE_VAR: + var->value = njs_value_undefined; + break; + + default: + break; + } + } + node = njs_parser_node_new(vm, parser, NJS_TOKEN_NAME); if (nxt_slow_path(node == NULL)) { return NULL; @@ -1389,7 +1402,7 @@ njs_parser_for_statement(njs_vm_t *vm, n init = parser->node; if (init->token == NJS_TOKEN_FOR_IN) { - return token; + goto done; } } else { @@ -1404,7 +1417,12 @@ njs_parser_for_statement(njs_vm_t *vm, n init = parser->node; if (init->token == NJS_TOKEN_IN) { - return njs_parser_for_in_statement(vm, parser, &name, token); + token = njs_parser_for_in_statement(vm, parser, &name, token); + if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { + return token; + } + + goto done; } } } @@ -1475,6 +1493,8 @@ njs_parser_for_statement(njs_vm_t *vm, n parser->node = node; +done: + return token; } diff -r fca54d073408 -r ec44a042cf15 njs/njs_variable.c --- a/njs/njs_variable.c Thu Apr 18 19:17:22 2019 +0300 +++ b/njs/njs_variable.c Fri Apr 19 00:28:31 2019 +0800 @@ -360,7 +360,6 @@ njs_variable_resolve(njs_vm_t *vm, njs_p nxt_uint_t scope_index; njs_index_t index; njs_variable_t *var; - const njs_value_t *default_value; njs_variable_reference_t *vr; vr = &node->u.reference; @@ -398,14 +397,7 @@ njs_variable_resolve(njs_vm_t *vm, njs_p var->argument = index; } - if (vr->type != NJS_DECLARATION && var->type <= NJS_VARIABLE_LET) { - goto not_found; - } - - default_value = njs_is_object(&var->value) ? &var->value : - &njs_value_undefined; - - index = njs_scope_next_index(vm, vr->scope, scope_index, default_value); + index = njs_scope_next_index(vm, vr->scope, scope_index, &var->value); if (nxt_slow_path(index == NJS_INDEX_ERROR)) { return NULL; From xeioex at nginx.com Thu Apr 18 17:53:59 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Thu, 18 Apr 2019 17:53:59 +0000 Subject: [njs] Style. Message-ID: details: https://hg.nginx.org/njs/rev/6d7a4fb82b25 branches: changeset: 910:6d7a4fb82b25 user: Dmitry Volyntsev date: Thu Apr 18 20:51:53 2019 +0300 description: Style. diffstat: njs/njs_generator.c | 4 +- njs/njs_object.c | 35 +++++++++++-------- njs/njs_vm.c | 86 ++++++++++++++++++++++++------------------------ njs/test/module/lib1.js | 4 +- nxt/nxt_clang.h | 1 - 5 files changed, 68 insertions(+), 62 deletions(-) diffs (263 lines): diff -r ec44a042cf15 -r 6d7a4fb82b25 njs/njs_generator.c --- a/njs/njs_generator.c Fri Apr 19 00:28:31 2019 +0800 +++ b/njs/njs_generator.c Thu Apr 18 20:51:53 2019 +0300 @@ -1606,7 +1606,8 @@ njs_generate_stop_statement(njs_vm_t *vm } if (index == NJS_INDEX_NONE) { - index = njs_value_index(vm, &njs_value_undefined, generator->runtime); + index = njs_value_index(vm, &njs_value_undefined, + generator->runtime); } stop->retval = index; @@ -2548,6 +2549,7 @@ njs_generate_function_call(njs_vm_t *vm, if (nxt_slow_path(ret != NXT_OK)) { return ret; } + name = node; } diff -r ec44a042cf15 -r 6d7a4fb82b25 njs/njs_object.c --- a/njs/njs_object.c Fri Apr 19 00:28:31 2019 +0800 +++ b/njs/njs_object.c Thu Apr 18 20:51:53 2019 +0300 @@ -27,7 +27,7 @@ static njs_ret_t njs_object_query_prop_h static njs_ret_t njs_define_property(njs_vm_t *vm, njs_value_t *object, const njs_value_t *name, const njs_object_t *descriptor); -static njs_object_prop_t * njs_object_exist_in_proto(const njs_object_t *begin, +static njs_object_prop_t *njs_object_exist_in_proto(const njs_object_t *begin, const njs_object_t *end, nxt_lvlhsh_query_t *lhq); static uint32_t njs_object_enumerate_array_length(const njs_object_t *object); static uint32_t njs_object_enumerate_string_length(const njs_object_t *object); @@ -977,7 +977,7 @@ njs_object_entries(njs_vm_t *vm, njs_val static njs_object_prop_t * -njs_object_exist_in_proto(const njs_object_t *begin, const njs_object_t *end, +njs_object_exist_in_proto(const njs_object_t *object, const njs_object_t *end, nxt_lvlhsh_query_t *lhq) { nxt_int_t ret; @@ -985,8 +985,8 @@ njs_object_exist_in_proto(const njs_obje lhq->proto = &njs_object_hash_proto; - while (begin != end) { - ret = nxt_lvlhsh_find(&begin->hash, lhq); + while (object != end) { + ret = nxt_lvlhsh_find(&object->hash, lhq); if (nxt_fast_path(ret == NXT_OK)) { prop = lhq->value; @@ -998,7 +998,7 @@ njs_object_exist_in_proto(const njs_obje return lhq->value; } - ret = nxt_lvlhsh_find(&begin->shared_hash, lhq); + ret = nxt_lvlhsh_find(&object->shared_hash, lhq); if (nxt_fast_path(ret == NXT_OK)) { return lhq->value; @@ -1006,7 +1006,7 @@ njs_object_exist_in_proto(const njs_obje next: - begin = begin->__proto__; + object = object->__proto__; } return NULL; @@ -1111,7 +1111,7 @@ njs_object_own_enumerate_value(njs_vm_t switch (object->type) { case NJS_ARRAY: ret = njs_object_enumerate_array(vm, (njs_array_t *) object, items, - kind); + kind); break; case NJS_OBJECT_STRING: @@ -1225,13 +1225,15 @@ static uint32_t njs_object_enumerate_object_length(const njs_object_t *object, nxt_bool_t all) { uint32_t length; - const njs_object_t *ptr; + const njs_object_t *proto; length = njs_object_own_enumerate_object_length(object, object, all); - for (ptr = object->__proto__; ptr != NULL; ptr = ptr->__proto__) { - - length += njs_object_own_enumerate_length(ptr, object, all); + proto = object->__proto__; + + while (proto != NULL) { + length += njs_object_own_enumerate_length(proto, object, all); + proto = proto->__proto__; } return length; @@ -1493,20 +1495,23 @@ njs_object_enumerate_object(njs_vm_t *vm njs_array_t *items, njs_object_enum_t kind, nxt_bool_t all) { njs_ret_t ret; - const njs_object_t *ptr; + const njs_object_t *proto; ret = njs_object_own_enumerate_object(vm, object, object, items, kind, all); if (nxt_slow_path(ret != NXT_OK)) { return NXT_ERROR; } - for (ptr = object->__proto__; ptr != NULL; ptr = ptr->__proto__) { - - ret = njs_object_own_enumerate_value(vm, ptr, object, items, kind, + proto = object->__proto__; + + while (proto != NULL) { + ret = njs_object_own_enumerate_value(vm, proto, object, items, kind, all); if (nxt_slow_path(ret != NXT_OK)) { return NXT_ERROR; } + + proto = proto->__proto__; } return NJS_OK; diff -r ec44a042cf15 -r 6d7a4fb82b25 njs/njs_vm.c --- a/njs/njs_vm.c Fri Apr 19 00:28:31 2019 +0800 +++ b/njs/njs_vm.c Thu Apr 18 20:51:53 2019 +0300 @@ -840,7 +840,7 @@ njs_vmcode_property_next(njs_vm_t *vm, n next = value->data.u.next; if (next->index < next->array->length) { - *retval = next->array->data[ next->index++ ]; + *retval = next->array->data[next->index++]; return code->offset; } @@ -3023,6 +3023,48 @@ njs_value_property(njs_vm_t *vm, const n } +njs_array_t * +njs_value_enumerate(njs_vm_t *vm, const njs_value_t *value, + njs_object_enum_t kind, nxt_bool_t all) +{ + njs_object_value_t obj_val; + + if (njs_is_object(value)) { + return njs_object_enumerate(vm, value->data.u.object, kind, all); + } + + if (value->type != NJS_STRING) { + return njs_array_alloc(vm, 0, NJS_ARRAY_SPARE); + } + + obj_val.object = vm->string_object; + obj_val.value = *value; + + return njs_object_enumerate(vm, (njs_object_t *) &obj_val, kind, all); +} + + +njs_array_t * +njs_value_own_enumerate(njs_vm_t *vm, const njs_value_t *value, + njs_object_enum_t kind, nxt_bool_t all) +{ + njs_object_value_t obj_val; + + if (njs_is_object(value)) { + return njs_object_own_enumerate(vm, value->data.u.object, kind, all); + } + + if (value->type != NJS_STRING) { + return njs_array_alloc(vm, 0, NJS_ARRAY_SPARE); + } + + obj_val.object = vm->string_object; + obj_val.value = *value; + + return njs_object_own_enumerate(vm, (njs_object_t *) &obj_val, kind, all); +} + + 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) @@ -3613,45 +3655,3 @@ njs_lvlhsh_free(void *data, void *p, siz { nxt_mp_free(data, p); } - - -njs_array_t * -njs_value_enumerate(njs_vm_t *vm, const njs_value_t *value, - njs_object_enum_t kind, nxt_bool_t all) -{ - njs_object_value_t obj_val; - - if (njs_is_object(value)) { - return njs_object_enumerate(vm, value->data.u.object, kind, all); - } - - if (value->type != NJS_STRING) { - return njs_array_alloc(vm, 0, NJS_ARRAY_SPARE); - } - - obj_val.object = vm->string_object; - obj_val.value = *value; - - return njs_object_enumerate(vm, (njs_object_t *) &obj_val, kind, all); -} - - -njs_array_t * -njs_value_own_enumerate(njs_vm_t *vm, const njs_value_t *value, - njs_object_enum_t kind, nxt_bool_t all) -{ - njs_object_value_t obj_val; - - if (njs_is_object(value)) { - return njs_object_own_enumerate(vm, value->data.u.object, kind, all); - } - - if (value->type != NJS_STRING) { - return njs_array_alloc(vm, 0, NJS_ARRAY_SPARE); - } - - obj_val.object = vm->string_object; - obj_val.value = *value; - - return njs_object_own_enumerate(vm, (njs_object_t *) &obj_val, kind, all); -} diff -r ec44a042cf15 -r 6d7a4fb82b25 njs/test/module/lib1.js --- a/njs/test/module/lib1.js Fri Apr 19 00:28:31 2019 +0800 +++ b/njs/test/module/lib1.js Thu Apr 18 20:51:53 2019 +0300 @@ -9,11 +9,11 @@ import crypto from 'crypto'; var state = {count:0} function inc() { - state.count++; + state.count++; } function get() { - return state.count; + return state.count; } export default {hash, inc, get}; diff -r ec44a042cf15 -r 6d7a4fb82b25 nxt/nxt_clang.h --- a/nxt/nxt_clang.h Fri Apr 19 00:28:31 2019 +0800 +++ b/nxt/nxt_clang.h Thu Apr 18 20:51:53 2019 +0300 @@ -25,7 +25,6 @@ (sizeof(x) / sizeof((x)[0])) - #if (NXT_HAVE_BUILTIN_EXPECT) #define nxt_expect(c, x) __builtin_expect((long) (x), (c)) #define nxt_fast_path(x) nxt_expect(1, x) From xeioex at nginx.com Fri Apr 19 13:05:00 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Fri, 19 Apr 2019 13:05:00 +0000 Subject: [njs] Simplified typeof operation. Message-ID: details: https://hg.nginx.org/njs/rev/a6c82ddff460 branches: changeset: 911:a6c82ddff460 user: hongzhidao date: Fri Apr 19 20:03:49 2019 +0800 description: Simplified typeof operation. diffstat: njs/njs_generator.c | 23 +++++++++++++++++------ njs/njs_variable.c | 2 +- njs/njs_vm.c | 7 +------ 3 files changed, 19 insertions(+), 13 deletions(-) diffs (111 lines): diff -r 6d7a4fb82b25 -r a6c82ddff460 njs/njs_generator.c --- a/njs/njs_generator.c Thu Apr 18 20:51:53 2019 +0300 +++ b/njs/njs_generator.c Fri Apr 19 20:03:49 2019 +0800 @@ -575,7 +575,7 @@ njs_generate_builtin_object(njs_vm_t *vm njs_vmcode_object_copy_t *copy; index = njs_variable_index(vm, node); - if (nxt_slow_path(index == NJS_INDEX_ERROR)) { + if (nxt_slow_path(index == NJS_INDEX_NONE)) { return NXT_ERROR; } @@ -600,7 +600,7 @@ njs_generate_variable(njs_vm_t *vm, njs_ njs_index_t index; index = njs_variable_index(vm, node); - if (nxt_slow_path(index == NJS_INDEX_ERROR)) { + if (nxt_slow_path(index == NJS_INDEX_NONE)) { return NXT_ERROR; } @@ -622,7 +622,7 @@ njs_generate_var_statement(njs_vm_t *vm, lvalue = node->left; index = njs_variable_index(vm, lvalue); - if (nxt_slow_path(index == NJS_INDEX_ERROR)) { + if (nxt_slow_path(index == NJS_INDEX_NONE)) { return NXT_ERROR; } @@ -2128,6 +2128,17 @@ njs_generate_typeof_operation(njs_vm_t * if (expr->token == NJS_TOKEN_NAME) { expr->index = njs_variable_typeof(vm, expr); + if (expr->u.reference.variable) { + ret = njs_generate_variable(vm, generator, expr); + if (nxt_slow_path(ret != NXT_OK)) { + return NXT_ERROR; + } + + } else { + expr->index = njs_value_index(vm, &njs_value_undefined, + generator->runtime); + } + } else { ret = njs_generator(vm, generator, node->left); if (nxt_slow_path(ret != NXT_OK)) { @@ -2794,7 +2805,7 @@ njs_generate_try_statement(njs_vm_t *vm, /* A "try/catch" case. */ catch_index = njs_variable_index(vm, node->left); - if (nxt_slow_path(catch_index == NJS_INDEX_ERROR)) { + if (nxt_slow_path(catch_index == NJS_INDEX_NONE)) { return NXT_ERROR; } @@ -2853,7 +2864,7 @@ njs_generate_try_statement(njs_vm_t *vm, /* A try/catch/finally case. */ catch_index = njs_variable_index(vm, node->left->left); - if (nxt_slow_path(catch_index == NJS_INDEX_ERROR)) { + if (nxt_slow_path(catch_index == NJS_INDEX_NONE)) { return NXT_ERROR; } @@ -3039,7 +3050,7 @@ njs_generate_import_statement(njs_vm_t * expr = node->right; index = njs_variable_index(vm, lvalue); - if (nxt_slow_path(index == NJS_INDEX_ERROR)) { + if (nxt_slow_path(index == NJS_INDEX_NONE)) { return NXT_ERROR; } diff -r 6d7a4fb82b25 -r a6c82ddff460 njs/njs_variable.c --- a/njs/njs_variable.c Thu Apr 18 20:51:53 2019 +0300 +++ b/njs/njs_variable.c Fri Apr 19 20:03:49 2019 +0800 @@ -349,7 +349,7 @@ njs_variable_index(njs_vm_t *vm, njs_par return var->index; } - return NJS_INDEX_ERROR; + return NJS_INDEX_NONE; } diff -r 6d7a4fb82b25 -r a6c82ddff460 njs/njs_vm.c --- a/njs/njs_vm.c Thu Apr 18 20:51:53 2019 +0300 +++ b/njs/njs_vm.c Fri Apr 19 20:03:49 2019 +0800 @@ -993,8 +993,6 @@ njs_vmcode_post_decrement(njs_vm_t *vm, njs_ret_t njs_vmcode_typeof(njs_vm_t *vm, njs_value_t *value, njs_value_t *invld) { - nxt_uint_t type; - /* ECMAScript 5.1: null, array and regexp are objects. */ static const njs_value_t *types[NJS_TYPE_MAX] = { @@ -1034,10 +1032,7 @@ njs_vmcode_typeof(njs_vm_t *vm, njs_valu &njs_string_object, }; - /* A zero index means non-declared variable. */ - type = (value != NULL) ? value->type : NJS_UNDEFINED; - - vm->retval = *types[type]; + vm->retval = *types[value->type]; return sizeof(njs_vmcode_2addr_t); } From alexander.borisov at nginx.com Fri Apr 19 17:12:03 2019 From: alexander.borisov at nginx.com (Alexander Borisov) Date: Fri, 19 Apr 2019 17:12:03 +0000 Subject: [njs] Added uint32_t overflow check for njs_array_alloc() function. Message-ID: details: https://hg.nginx.org/njs/rev/434c654ef638 branches: changeset: 912:434c654ef638 user: Alexander Borisov date: Fri Apr 19 17:48:39 2019 +0300 description: Added uint32_t overflow check for njs_array_alloc() function. diffstat: njs/njs_array.c | 24 +++++++++++++++++------- njs/njs_array.h | 10 +++++----- njs/njs_object.c | 4 ++-- njs/test/njs_unit_test.c | 6 ++++++ 4 files changed, 30 insertions(+), 14 deletions(-) diffs (110 lines): diff -r a6c82ddff460 -r 434c654ef638 njs/njs_array.c --- a/njs/njs_array.c Fri Apr 19 20:03:49 2019 +0800 +++ b/njs/njs_array.c Fri Apr 19 17:48:39 2019 +0300 @@ -125,22 +125,26 @@ 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) +njs_array_alloc(njs_vm_t *vm, uint64_t length, uint32_t spare) { uint64_t size; njs_array_t *array; + if (nxt_slow_path(length > UINT32_MAX)) { + goto overflow; + } + + size = length + spare; + + if (nxt_slow_path(size > NJS_ARRAY_MAX_LENGTH)) { + goto memory_error; + } + array = nxt_mp_alloc(vm->mem_pool, sizeof(njs_array_t)); if (nxt_slow_path(array == NULL)) { goto memory_error; } - size = (uint64_t) length + spare; - - if (nxt_slow_path((size * sizeof(njs_value_t)) >= UINT32_MAX)) { - goto memory_error; - } - array->data = nxt_mp_align(vm->mem_pool, sizeof(njs_value_t), size * sizeof(njs_value_t)); if (nxt_slow_path(array->data == NULL)) { @@ -164,6 +168,12 @@ memory_error: njs_memory_error(vm); return NULL; + +overflow: + + njs_range_error(vm, "Invalid array length"); + + return NULL; } diff -r a6c82ddff460 -r 434c654ef638 njs/njs_array.h --- a/njs/njs_array.h Fri Apr 19 20:03:49 2019 +0800 +++ b/njs/njs_array.h Fri Apr 19 17:48:39 2019 +0300 @@ -8,14 +8,14 @@ #define _NJS_ARRAY_H_INCLUDED_ -#define NJS_ARRAY_MAX_LENGTH 0xffffffff -/* The maximum valid array index is the maximum array length minus 1. */ -#define NJS_ARRAY_INVALID_INDEX NJS_ARRAY_MAX_LENGTH +#define NJS_ARRAY_MAX_INDEX 0xffffffff +#define NJS_ARRAY_INVALID_INDEX NJS_ARRAY_MAX_INDEX -#define NJS_ARRAY_SPARE 8 +#define NJS_ARRAY_SPARE 8 +#define NJS_ARRAY_MAX_LENGTH (UINT32_MAX/ sizeof(njs_value_t)) -njs_array_t *njs_array_alloc(njs_vm_t *vm, uint32_t length, uint32_t spare); +njs_array_t *njs_array_alloc(njs_vm_t *vm, uint64_t length, uint32_t spare); njs_ret_t njs_array_add(njs_vm_t *vm, njs_array_t *array, njs_value_t *value); njs_ret_t njs_array_string_add(njs_vm_t *vm, njs_array_t *array, const u_char *start, size_t size, size_t length); diff -r a6c82ddff460 -r 434c654ef638 njs/njs_object.c --- a/njs/njs_object.c Fri Apr 19 20:03:49 2019 +0800 +++ b/njs/njs_object.c Fri Apr 19 17:48:39 2019 +0300 @@ -338,7 +338,7 @@ njs_property_query(njs_vm_t *vm, njs_pro if (nxt_fast_path(!njs_is_null_or_undefined_or_boolean(property))) { index = njs_value_to_index(property); - if (nxt_fast_path(index < NJS_ARRAY_MAX_LENGTH)) { + if (nxt_fast_path(index < NJS_ARRAY_MAX_INDEX)) { return njs_array_property_query(vm, pq, object->data.u.array, index); } @@ -459,7 +459,7 @@ njs_object_property_query(njs_vm_t *vm, switch (proto->type) { case NJS_ARRAY: index = njs_value_to_index(property); - if (nxt_fast_path(index < NJS_ARRAY_MAX_LENGTH)) { + if (nxt_fast_path(index < NJS_ARRAY_MAX_INDEX)) { array = (njs_array_t *) proto; return njs_array_property_query(vm, pq, array, index); } diff -r a6c82ddff460 -r 434c654ef638 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Fri Apr 19 20:03:49 2019 +0800 +++ b/njs/test/njs_unit_test.c Fri Apr 19 17:48:39 2019 +0300 @@ -7950,6 +7950,12 @@ static njs_unit_test_t njs_test[] = { nxt_string("var a = Array(1111111111)"), nxt_string("MemoryError") }, + { nxt_string("var x = Array(2**32)"), + nxt_string("RangeError: Invalid array length") }, + + { nxt_string("var x = Array(2**28)"), + nxt_string("MemoryError") }, + { nxt_string("var a = new Array(3); a"), nxt_string(",,") }, From alexander.borisov at nginx.com Fri Apr 19 17:12:04 2019 From: alexander.borisov at nginx.com (Alexander Borisov) Date: Fri, 19 Apr 2019 17:12:04 +0000 Subject: [njs] Fixed overflow in Array.prototype.concat(). Message-ID: details: https://hg.nginx.org/njs/rev/8f87e3ef4a4d branches: changeset: 913:8f87e3ef4a4d user: Alexander Borisov date: Fri Apr 19 17:24:29 2019 +0300 description: Fixed overflow in Array.prototype.concat(). This closes #131 issue on GitHub. diffstat: njs/njs_array.c | 2 +- njs/test/njs_unit_test.c | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletions(-) diffs (30 lines): diff -r 434c654ef638 -r 8f87e3ef4a4d njs/njs_array.c --- a/njs/njs_array.c Fri Apr 19 17:48:39 2019 +0300 +++ b/njs/njs_array.c Fri Apr 19 17:24:29 2019 +0300 @@ -1125,7 +1125,7 @@ static njs_ret_t njs_array_prototype_concat(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused) { - size_t length; + uint64_t length; nxt_uint_t i; njs_value_t *value; njs_array_t *array; diff -r 434c654ef638 -r 8f87e3ef4a4d njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Fri Apr 19 17:48:39 2019 +0300 +++ b/njs/test/njs_unit_test.c Fri Apr 19 17:24:29 2019 +0300 @@ -7956,6 +7956,14 @@ static njs_unit_test_t njs_test[] = { nxt_string("var x = Array(2**28)"), nxt_string("MemoryError") }, + { nxt_string("var r; try {" + " var x = Array(2**27), y = Array(2**5).fill(x);" + " Array.prototype.concat.apply(y[0], y.slice(1));" + "} catch (e) {" + " r = e.name == 'InternalError' || e.name == 'RangeError'" + "} r"), + nxt_string("true") }, + { nxt_string("var a = new Array(3); a"), nxt_string(",,") }, From xeioex at nginx.com Mon Apr 22 13:28:07 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Mon, 22 Apr 2019 13:28:07 +0000 Subject: [njs] Restricted function declaration to top level or inside a block. Message-ID: details: https://hg.nginx.org/njs/rev/3869b6e1f296 branches: changeset: 915:3869b6e1f296 user: hongzhidao date: Sun Apr 21 17:36:25 2019 +0800 description: Restricted function declaration to top level or inside a block. diffstat: njs/njs_parser.c | 6 ++++++ njs/test/njs_unit_test.c | 21 +++++++++++++++++++++ 2 files changed, 27 insertions(+), 0 deletions(-) diffs (47 lines): diff -r 4883fe429836 -r 3869b6e1f296 njs/njs_parser.c --- a/njs/njs_parser.c Sun Apr 21 17:33:31 2019 +0800 +++ b/njs/njs_parser.c Sun Apr 21 17:36:25 2019 +0800 @@ -492,6 +492,12 @@ njs_parser_block(njs_vm_t *vm, njs_parse { njs_parser_node_t *node; + if (token == NJS_TOKEN_FUNCTION) { + njs_parser_syntax_error(vm, parser, + "Functions can only be declared at top level or inside a block"); + return NJS_TOKEN_ILLEGAL; + } + token = njs_parser_statement(vm, parser, token); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { return token; diff -r 4883fe429836 -r 3869b6e1f296 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Sun Apr 21 17:33:31 2019 +0800 +++ b/njs/test/njs_unit_test.c Sun Apr 21 17:36:25 2019 +0800 @@ -5725,6 +5725,27 @@ static njs_unit_test_t njs_test[] = { nxt_string("\n{\nreturn;\n}"), nxt_string("SyntaxError: Illegal return statement in 3") }, + { nxt_string("if (1) function f(){}"), + nxt_string("SyntaxError: Functions can only be declared at top level or inside a block in 1") }, + + { nxt_string("if (1) { function f(){}}"), + nxt_string("undefined") }, + + { nxt_string("while (1) function f() { }"), + nxt_string("SyntaxError: Functions can only be declared at top level or inside a block in 1") }, + + { nxt_string("while (1) { break; function f(){}}"), + nxt_string("undefined") }, + + { nxt_string("for (;;) function f() { }"), + nxt_string("SyntaxError: Functions can only be declared at top level or inside a block in 1") }, + + { nxt_string("for (;;) { break; function f(){}}"), + nxt_string("undefined") }, + + { nxt_string("do function f() { } while (0)"), + nxt_string("SyntaxError: Functions can only be declared at top level or inside a block in 1") }, + { nxt_string("function f() { return f() } f()"), nxt_string("RangeError: Maximum call stack size exceeded") }, From xeioex at nginx.com Mon Apr 22 13:28:07 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Mon, 22 Apr 2019 13:28:07 +0000 Subject: [njs] Added option to run unit tests in module mode. Message-ID: details: https://hg.nginx.org/njs/rev/4883fe429836 branches: changeset: 914:4883fe429836 user: hongzhidao date: Sun Apr 21 17:33:31 2019 +0800 description: Added option to run unit tests in module mode. diffstat: njs/test/njs_unit_test.c | 30 ++++++++++++++++-------------- 1 files changed, 16 insertions(+), 14 deletions(-) diffs (107 lines): diff -r 8f87e3ef4a4d -r 4883fe429836 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Fri Apr 19 17:24:29 2019 +0300 +++ b/njs/test/njs_unit_test.c Sun Apr 21 17:33:31 2019 +0800 @@ -12746,8 +12746,8 @@ njs_externals_init(njs_vm_t *vm) static nxt_int_t -njs_unit_test(njs_unit_test_t tests[], size_t num, nxt_bool_t disassemble, - nxt_bool_t verbose) +njs_unit_test(njs_unit_test_t tests[], size_t num, nxt_bool_t module, + nxt_bool_t disassemble, nxt_bool_t verbose) { u_char *start; njs_vm_t *vm, *nvm; @@ -12765,11 +12765,13 @@ njs_unit_test(njs_unit_test_t tests[], s for (i = 0; i < num; i++) { if (verbose) { - nxt_printf("\"%V\"\n", &njs_test[i].script); + nxt_printf("\"%V\"\n", &tests[i].script); } nxt_memzero(&options, sizeof(njs_vm_opt_t)); + options.module = module; + vm = njs_vm_create(&options); if (vm == NULL) { nxt_printf("njs_vm_create() failed\n"); @@ -12781,9 +12783,9 @@ njs_unit_test(njs_unit_test_t tests[], s goto done; } - start = njs_test[i].script.start; - - ret = njs_vm_compile(vm, &start, start + njs_test[i].script.length); + start = tests[i].script.start; + + ret = njs_vm_compile(vm, &start, start + tests[i].script.length); if (ret == NXT_OK) { if (disassemble) { @@ -12810,7 +12812,7 @@ njs_unit_test(njs_unit_test_t tests[], s } } - success = nxt_strstr_eq(&njs_test[i].ret, &s); + success = nxt_strstr_eq(&tests[i].ret, &s); if (success) { if (nvm != NULL) { @@ -12825,7 +12827,7 @@ njs_unit_test(njs_unit_test_t tests[], s } nxt_printf("njs(\"%V\")\nexpected: \"%V\"\n got: \"%V\"\n", - &njs_test[i].script, &njs_test[i].ret, &s); + &tests[i].script, &tests[i].ret, &s); goto done; } @@ -12868,8 +12870,8 @@ njs_timezone_optional_test(nxt_bool_t di size = strftime((char *) buf, sizeof(buf), "%z", &tm); if (memcmp(buf, "+1245", size) == 0) { - ret = njs_unit_test(njs_tz_test, nxt_nitems(njs_tz_test), disassemble, - verbose); + ret = njs_unit_test(njs_tz_test, nxt_nitems(njs_tz_test), 0, + disassemble, verbose); if (ret != NXT_OK) { return ret; } @@ -12883,6 +12885,7 @@ njs_timezone_optional_test(nxt_bool_t di return NXT_OK; } + static nxt_int_t njs_regexp_optional_test(nxt_bool_t disassemble, nxt_bool_t verbose) { @@ -12909,7 +12912,7 @@ njs_regexp_optional_test(nxt_bool_t disa &errstr, &erroff, NULL); if (re1 == NULL && re2 != NULL) { - ret = njs_unit_test(njs_regexp_test, nxt_nitems(njs_regexp_test), + ret = njs_unit_test(njs_regexp_test, nxt_nitems(njs_regexp_test), 0, disassemble, verbose); if (ret != NXT_OK) { return ret; @@ -13056,8 +13059,6 @@ done: } - - static nxt_int_t njs_vm_object_alloc_test(njs_vm_t * vm, nxt_bool_t disassemble, nxt_bool_t verbose) @@ -13269,7 +13270,8 @@ main(int argc, char **argv) (void) putenv((char *) "TZ=UTC"); tzset(); - ret = njs_unit_test(njs_test, nxt_nitems(njs_test), disassemble, verbose); + ret = njs_unit_test(njs_test, nxt_nitems(njs_test), 0, + disassemble, verbose); if (ret != NXT_OK) { return ret; } From alexander.borisov at nginx.com Mon Apr 22 15:06:51 2019 From: alexander.borisov at nginx.com (Alexander Borisov) Date: Mon, 22 Apr 2019 15:06:51 +0000 Subject: [njs] Improved array allocation test for low memory machines. Message-ID: details: https://hg.nginx.org/njs/rev/72252310ae3f branches: changeset: 916:72252310ae3f user: Alexander Borisov date: Mon Apr 22 18:06:17 2019 +0300 description: Improved array allocation test for low memory machines. diffstat: njs/test/njs_unit_test.c | 10 +++------- 1 files changed, 3 insertions(+), 7 deletions(-) diffs (20 lines): diff -r 3869b6e1f296 -r 72252310ae3f njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Sun Apr 21 17:36:25 2019 +0800 +++ b/njs/test/njs_unit_test.c Mon Apr 22 18:06:17 2019 +0300 @@ -7977,13 +7977,9 @@ static njs_unit_test_t njs_test[] = { nxt_string("var x = Array(2**28)"), nxt_string("MemoryError") }, - { nxt_string("var r; try {" - " var x = Array(2**27), y = Array(2**5).fill(x);" - " Array.prototype.concat.apply(y[0], y.slice(1));" - "} catch (e) {" - " r = e.name == 'InternalError' || e.name == 'RangeError'" - "} r"), - nxt_string("true") }, + { nxt_string("var x = Array(2**20), y = Array(2**12).fill(x);" + "Array.prototype.concat.apply(y[0], y.slice(1))"), + nxt_string("RangeError: Invalid array length") }, { nxt_string("var a = new Array(3); a"), nxt_string(",,") }, From sharpobject at gmail.com Mon Apr 22 16:51:49 2019 From: sharpobject at gmail.com (Robert Burke) Date: Mon, 22 Apr 2019 09:51:49 -0700 Subject: [PATCH] Range filter: always support ascending multipart ranges. In-Reply-To: References: Message-ID: Hello, I'd love to hear any comments about this :) On Thu, Apr 11, 2019 at 5:51 AM Robert Burke wrote: > > Hello, > > At Cloudflare we'd like to support multiple byte-ranges if they are > non-overlapping and in ascending order on cache miss or when using > slice. This patch adds support for that. It preserves the existing > multipart range support for response bodies that are in a single > buffer. It does not remove buffers from the passed-in chain, which > seems like it was the biggest issue mdounin raised with the previous > patch. From xeioex at nginx.com Mon Apr 22 16:52:54 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Mon, 22 Apr 2019 16:52:54 +0000 Subject: [njs] Added block scoped function definitions support. Message-ID: details: https://hg.nginx.org/njs/rev/31232e755143 branches: changeset: 917:31232e755143 user: hongzhidao date: Sun Apr 21 18:11:58 2019 +0800 description: Added block scoped function definitions support. This closes #134 issue on Github. diffstat: njs/njs_parser.c | 1 + njs/njs_variable.c | 77 ++++++++++++++++++++++++------- njs/test/module/declaration_exception.js | 10 ++++ njs/test/njs_expect_test.exp | 2 + njs/test/njs_unit_test.c | 46 ++++++++++++++++++- 5 files changed, 117 insertions(+), 19 deletions(-) diffs (228 lines): diff -r 72252310ae3f -r 31232e755143 njs/njs_parser.c --- a/njs/njs_parser.c Mon Apr 22 18:06:17 2019 +0300 +++ b/njs/njs_parser.c Sun Apr 21 18:11:58 2019 +0800 @@ -203,6 +203,7 @@ njs_parser_scope_begin(njs_vm_t *vm, njs } else { if (type == NJS_SCOPE_GLOBAL) { type += NJS_INDEX_GLOBAL_OFFSET; + scope->module = vm->options.module; } scope->next_index[0] = type; diff -r 72252310ae3f -r 31232e755143 njs/njs_variable.c --- a/njs/njs_variable.c Mon Apr 22 18:06:17 2019 +0300 +++ b/njs/njs_variable.c Sun Apr 21 18:11:58 2019 +0800 @@ -9,6 +9,9 @@ #include +static njs_variable_t *njs_variable_scope_add(njs_vm_t *vm, + njs_parser_scope_t *scope, nxt_lvlhsh_query_t *lhq, + njs_variable_type_t type); static njs_ret_t njs_variable_reference_resolve(njs_vm_t *vm, njs_variable_reference_t *vr, njs_parser_scope_t *node_scope); static njs_variable_t *njs_variable_alloc(njs_vm_t *vm, nxt_str_t *name, @@ -45,7 +48,6 @@ njs_variable_t * njs_variable_add(njs_vm_t *vm, njs_parser_scope_t *scope, nxt_str_t *name, uint32_t hash, njs_variable_type_t type) { - nxt_int_t ret; njs_variable_t *var; nxt_lvlhsh_query_t lhq; @@ -53,36 +55,68 @@ njs_variable_add(njs_vm_t *vm, njs_parse lhq.key = *name; lhq.proto = &njs_variables_hash_proto; - if (type >= NJS_VARIABLE_VAR) { - /* - * A "var" and "function" declarations are - * stored in function or global scope. - */ - while (scope->type == NJS_SCOPE_BLOCK) { + var = njs_variable_scope_add(vm, scope, &lhq, type); + if (nxt_slow_path(var == NULL)) { + return NULL; + } + + if (type == NJS_VARIABLE_VAR && scope->type == NJS_SCOPE_BLOCK) { + /* A "var" declaration is stored in function or global scope. */ + do { scope = scope->parent; - } + + var = njs_variable_scope_add(vm, scope, &lhq, type); + if (nxt_slow_path(var == NULL)) { + return NULL; + } + + } while (scope->type == NJS_SCOPE_BLOCK); + } + + if (type == NJS_VARIABLE_FUNCTION) { + var->type = type; } - if (nxt_lvlhsh_find(&scope->variables, &lhq) == NXT_OK) { - var = lhq.value; + return var; +} + + +static njs_variable_t * +njs_variable_scope_add(njs_vm_t *vm, njs_parser_scope_t *scope, + nxt_lvlhsh_query_t *lhq, njs_variable_type_t type) +{ + nxt_int_t ret; + njs_variable_t *var; - if (type == NJS_VARIABLE_FUNCTION) { - var->type = type; + if (nxt_lvlhsh_find(&scope->variables, lhq) == NXT_OK) { + var = lhq->value; + + if (!scope->module && scope->type != NJS_SCOPE_BLOCK) { + return var; + } + + if (type == NJS_VARIABLE_FUNCTION + || var->type == NJS_VARIABLE_FUNCTION) + { + njs_parser_syntax_error(vm, vm->parser, + "\"%V\" has already been declared", + &lhq->key); + return NULL; } return var; } - var = njs_variable_alloc(vm, &lhq.key, type); + var = njs_variable_alloc(vm, &lhq->key, type); if (nxt_slow_path(var == NULL)) { - return var; + return NULL; } - lhq.replace = 0; - lhq.value = var; - lhq.pool = vm->mem_pool; + lhq->replace = 0; + lhq->value = var; + lhq->pool = vm->mem_pool; - ret = nxt_lvlhsh_insert(&scope->variables, &lhq); + ret = nxt_lvlhsh_insert(&scope->variables, lhq); if (nxt_fast_path(ret == NXT_OK)) { return var; @@ -459,6 +493,13 @@ njs_variable_reference_resolve(njs_vm_t if (nxt_lvlhsh_find(&scope->variables, &lhq) == NXT_OK) { vr->variable = lhq.value; + if (scope->type == NJS_SCOPE_BLOCK + && vr->variable->type == NJS_VARIABLE_VAR) + { + scope = scope->parent; + continue; + } + if (scope->type == NJS_SCOPE_SHIM) { scope = previous; diff -r 72252310ae3f -r 31232e755143 njs/test/module/declaration_exception.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/njs/test/module/declaration_exception.js Sun Apr 21 18:11:58 2019 +0800 @@ -0,0 +1,10 @@ + +function f() { + return 1; +} + +function f() { + return 2; +} + +export default f; diff -r 72252310ae3f -r 31232e755143 njs/test/njs_expect_test.exp --- a/njs/test/njs_expect_test.exp Mon Apr 22 18:06:17 2019 +0300 +++ b/njs/test/njs_expect_test.exp Sun Apr 21 18:11:58 2019 +0800 @@ -699,6 +699,8 @@ njs_test { "undefined\r\n"} {"import ref from 'ref_exception.js'\r\n" "ReferenceError: \"undeclared\" is not defined in ref_exception.js:1"} + {"import m from 'declaration_exception.js'\r\n" + "SyntaxError: \"f\" has already been declared in declaration_exception.js:6"} {"import m from 'loading_exception.js'\r\n" "Error: loading exception\r\n at module \\(loading_exception.js:1\\)"} {"import lib3 from 'lib1.js'\r\n" diff -r 72252310ae3f -r 31232e755143 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Mon Apr 22 18:06:17 2019 +0300 +++ b/njs/test/njs_unit_test.c Sun Apr 21 18:11:58 2019 +0800 @@ -5746,6 +5746,21 @@ static njs_unit_test_t njs_test[] = { nxt_string("do function f() { } while (0)"), nxt_string("SyntaxError: Functions can only be declared at top level or inside a block in 1") }, + { nxt_string("function f() { return 1; } { function f() { return 2; } } f()"), + nxt_string("1") }, + + { nxt_string("function f() { return 1; } { function f() { return 2; } { function f() { return 3; } }} f()"), + nxt_string("1") }, + + { nxt_string("{ var f; function f() {} }"), + nxt_string("SyntaxError: \"f\" has already been declared in 1") }, + + { nxt_string("{ function f() {} var f; }"), + nxt_string("SyntaxError: \"f\" has already been declared in 1") }, + + { nxt_string("{ function f() {} { var f }}"), + nxt_string("SyntaxError: \"f\" has already been declared in 1") }, + { nxt_string("function f() { return f() } f()"), nxt_string("RangeError: Maximum call stack size exceeded") }, @@ -11998,6 +12013,25 @@ static njs_unit_test_t njs_test[] = }; +static njs_unit_test_t njs_module_test[] = +{ + { nxt_string("function f(){return 2}; var f; f()"), + nxt_string("SyntaxError: \"f\" has already been declared in 1") }, + + { nxt_string("function f(){return 2}; var f = 1; f()"), + nxt_string("SyntaxError: \"f\" has already been declared in 1") }, + + { nxt_string("function f(){return 1}; function f(){return 2}; f()"), + nxt_string("SyntaxError: \"f\" has already been declared in 1") }, + + { nxt_string("var f = 1; function f() {};"), + nxt_string("SyntaxError: \"f\" has already been declared in 1") }, + + { nxt_string("{ var f = 1; } function f() {};"), + nxt_string("SyntaxError: \"f\" has already been declared in 1") }, +}; + + static njs_unit_test_t njs_tz_test[] = { { nxt_string("var d = new Date(1); d = d + ''; d.slice(0, 33)"), @@ -13287,7 +13321,17 @@ main(int argc, char **argv) (void) putenv((char *) "TZ=UTC"); tzset(); - ret = njs_unit_test(njs_test, nxt_nitems(njs_test), 0, + /* script tests. */ + + ret = njs_unit_test(njs_test, nxt_nitems(njs_test), 0, disassemble, + verbose); + if (ret != NXT_OK) { + return ret; + } + + /* module tests. */ + + ret = njs_unit_test(njs_module_test, nxt_nitems(njs_module_test), 1, disassemble, verbose); if (ret != NXT_OK) { return ret; From xeioex at nginx.com Mon Apr 22 18:19:49 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Mon, 22 Apr 2019 18:19:49 +0000 Subject: [njs] Added support for template literals. Message-ID: details: https://hg.nginx.org/njs/rev/52983554e61f branches: changeset: 918:52983554e61f user: hongzhidao date: Mon Apr 22 19:53:41 2019 +0300 description: Added support for template literals. What is supported: 1) Multiline strings `string text line 1 string text line 2` 2) Expression interpolation `string text ${expression} string text` 3) Nested templates 4) Tagged templates This closes #107 issue on Github. In collaboration with Artem S. Povalyukhin. diffstat: njs/njs_disassembler.c | 2 + njs/njs_generator.c | 27 +++++ njs/njs_lexer.c | 2 +- njs/njs_lexer.h | 3 + njs/njs_parser.h | 2 + njs/njs_parser_expression.c | 10 +- njs/njs_parser_terminal.c | 199 ++++++++++++++++++++++++++++++++++++++++++++ njs/njs_string.c | 2 +- njs/njs_string.h | 4 + njs/njs_vm.c | 33 +++++++ njs/njs_vm.h | 8 + njs/test/njs_unit_test.c | 63 +++++++++++++ 12 files changed, 352 insertions(+), 3 deletions(-) diffs (517 lines): diff -r 31232e755143 -r 52983554e61f njs/njs_disassembler.c --- a/njs/njs_disassembler.c Sun Apr 21 18:11:58 2019 +0800 +++ b/njs/njs_disassembler.c Mon Apr 22 19:53:41 2019 +0300 @@ -29,6 +29,8 @@ static njs_code_name_t code_names[] = { nxt_string("ARGUMENTS ") }, { njs_vmcode_regexp, sizeof(njs_vmcode_regexp_t), nxt_string("REGEXP ") }, + { njs_vmcode_template_literal, sizeof(njs_vmcode_template_literal_t), + nxt_string("TEMPLATE LITERAL") }, { njs_vmcode_object_copy, sizeof(njs_vmcode_object_copy_t), nxt_string("OBJECT COPY ") }, diff -r 31232e755143 -r 52983554e61f njs/njs_generator.c --- a/njs/njs_generator.c Sun Apr 21 18:11:58 2019 +0800 +++ b/njs/njs_generator.c Mon Apr 22 19:53:41 2019 +0300 @@ -123,6 +123,8 @@ static nxt_int_t njs_generate_function(n njs_parser_node_t *node); static nxt_int_t njs_generate_regexp(njs_vm_t *vm, njs_generator_t *generator, njs_parser_node_t *node); +static nxt_int_t njs_generate_template_literal(njs_vm_t *vm, + njs_generator_t *generator, njs_parser_node_t *node); static nxt_int_t njs_generate_test_jump_expression(njs_vm_t *vm, njs_generator_t *generator, njs_parser_node_t *node); static nxt_int_t njs_generate_3addr_operation(njs_vm_t *vm, @@ -404,6 +406,9 @@ njs_generator(njs_vm_t *vm, njs_generato case NJS_TOKEN_REGEXP: return njs_generate_regexp(vm, generator, node); + case NJS_TOKEN_TEMPLATE_LITERAL: + return njs_generate_template_literal(vm, generator, node); + case NJS_TOKEN_THIS: case NJS_TOKEN_OBJECT_CONSTRUCTOR: case NJS_TOKEN_ARRAY_CONSTRUCTOR: @@ -1969,6 +1974,28 @@ njs_generate_regexp(njs_vm_t *vm, njs_ge static nxt_int_t +njs_generate_template_literal(njs_vm_t *vm, njs_generator_t *generator, + njs_parser_node_t *node) +{ + nxt_int_t ret; + njs_vmcode_template_literal_t *code; + + ret = njs_generator(vm, generator, node->left); + if (nxt_slow_path(ret != NXT_OK)) { + return ret; + } + + njs_generate_code(generator, njs_vmcode_template_literal_t, code, + njs_vmcode_template_literal, 1, 1); + code->retval = node->left->index; + + node->index = node->left->index; + + return NXT_OK; +} + + +static nxt_int_t njs_generate_test_jump_expression(njs_vm_t *vm, njs_generator_t *generator, njs_parser_node_t *node) { diff -r 31232e755143 -r 52983554e61f njs/njs_lexer.c --- a/njs/njs_lexer.c Sun Apr 21 18:11:58 2019 +0800 +++ b/njs/njs_lexer.c Mon Apr 22 19:53:41 2019 +0300 @@ -93,7 +93,7 @@ static const uint8_t njs_tokens[256] n /* \ ] */ NJS_TOKEN_ILLEGAL, NJS_TOKEN_CLOSE_BRACKET, /* ^ _ */ NJS_TOKEN_BITWISE_XOR, NJS_TOKEN_LETTER, - /* ` a */ NJS_TOKEN_ILLEGAL, NJS_TOKEN_LETTER, + /* ` a */ NJS_TOKEN_GRAVE, NJS_TOKEN_LETTER, /* b c */ NJS_TOKEN_LETTER, NJS_TOKEN_LETTER, /* d e */ NJS_TOKEN_LETTER, NJS_TOKEN_LETTER, /* f g */ NJS_TOKEN_LETTER, NJS_TOKEN_LETTER, diff -r 31232e755143 -r 52983554e61f njs/njs_lexer.h --- a/njs/njs_lexer.h Sun Apr 21 18:11:58 2019 +0800 +++ b/njs/njs_lexer.h Mon Apr 22 19:53:41 2019 +0300 @@ -127,6 +127,9 @@ typedef enum { NJS_TOKEN_ARRAY, + NJS_TOKEN_GRAVE, + NJS_TOKEN_TEMPLATE_LITERAL, + NJS_TOKEN_FUNCTION, NJS_TOKEN_FUNCTION_EXPRESSION, NJS_TOKEN_FUNCTION_CALL, diff -r 31232e755143 -r 52983554e61f njs/njs_parser.h --- a/njs/njs_parser.h Sun Apr 21 18:11:58 2019 +0800 +++ b/njs/njs_parser.h Mon Apr 22 19:53:41 2019 +0300 @@ -90,6 +90,8 @@ njs_token_t njs_parser_arrow_expression( njs_token_t njs_parser_module_lambda(njs_vm_t *vm, njs_parser_t *parser); njs_token_t njs_parser_terminal(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token); +njs_token_t njs_parser_template_literal(njs_vm_t *vm, njs_parser_t *parser, + njs_parser_node_t *parent); njs_parser_node_t *njs_parser_argument(njs_vm_t *vm, njs_parser_t *parser, njs_parser_node_t *expr, njs_index_t index); njs_token_t njs_parser_property_token(njs_vm_t *vm, njs_parser_t *parser); diff -r 31232e755143 -r 52983554e61f njs/njs_parser_expression.c --- a/njs/njs_parser_expression.c Sun Apr 21 18:11:58 2019 +0800 +++ b/njs/njs_parser_expression.c Mon Apr 22 19:53:41 2019 +0300 @@ -753,7 +753,7 @@ njs_parser_call_expression(njs_vm_t *vm, return token; } - if (token != NJS_TOKEN_OPEN_PARENTHESIS) { + if (token != NJS_TOKEN_OPEN_PARENTHESIS && token != NJS_TOKEN_GRAVE) { return token; } @@ -828,6 +828,14 @@ njs_parser_call(njs_vm_t *vm, njs_parser break; + case NJS_TOKEN_GRAVE: + token = njs_parser_template_literal(vm, parser, func); + if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { + return token; + } + + break; + default: break; } diff -r 31232e755143 -r 52983554e61f njs/njs_parser_terminal.c --- a/njs/njs_parser_terminal.c Sun Apr 21 18:11:58 2019 +0800 +++ b/njs/njs_parser_terminal.c Mon Apr 22 19:53:41 2019 +0300 @@ -24,6 +24,10 @@ static njs_token_t njs_parser_array(njs_ njs_parser_node_t *array); static nxt_int_t njs_parser_array_item(njs_vm_t *vm, njs_parser_t *parser, njs_parser_node_t *array, njs_parser_node_t *value); +static nxt_int_t njs_parser_template_expression(njs_vm_t *vm, + njs_parser_t *parser); +static nxt_int_t njs_parser_template_string(njs_vm_t *vm, + njs_parser_t *parser); static njs_token_t njs_parser_escape_string_create(njs_vm_t *vm, njs_parser_t *parser, njs_value_t *value); @@ -81,6 +85,16 @@ njs_parser_terminal(njs_vm_t *vm, njs_pa return njs_parser_array(vm, parser, node); + case NJS_TOKEN_GRAVE: + nxt_thread_log_debug("JS: TEMPLATE LITERAL"); + + node = njs_parser_node_new(vm, parser, NJS_TOKEN_TEMPLATE_LITERAL); + if (nxt_slow_path(node == NULL)) { + return NJS_TOKEN_ERROR; + } + + return njs_parser_template_literal(vm, parser, node); + case NJS_TOKEN_DIVISION: node = njs_parser_node_new(vm, parser, NJS_TOKEN_REGEXP); if (nxt_slow_path(node == NULL)) { @@ -688,6 +702,191 @@ njs_parser_array_item(njs_vm_t *vm, njs_ } +njs_token_t +njs_parser_template_literal(njs_vm_t *vm, njs_parser_t *parser, + njs_parser_node_t *parent) +{ + uint8_t tagged_template; + nxt_int_t ret; + nxt_bool_t expression; + njs_index_t index; + njs_parser_node_t *node, *array; + + tagged_template = (parent->token != NJS_TOKEN_TEMPLATE_LITERAL); + + index = NJS_SCOPE_CALLEE_ARGUMENTS; + + array = njs_parser_node_new(vm, parser, NJS_TOKEN_ARRAY); + if (nxt_slow_path(array == NULL)) { + return NJS_TOKEN_ERROR; + } + + if (tagged_template) { + node = njs_parser_argument(vm, parser, array, index); + if (nxt_slow_path(node == NULL)) { + return NJS_TOKEN_ERROR; + } + + parent->right = node; + parent = node; + + index += sizeof(njs_value_t); + + } else { + parent->left = array; + } + + expression = 0; + + for ( ;; ) { + ret = expression ? njs_parser_template_expression(vm, parser) + : njs_parser_template_string(vm, parser); + + if (ret == NXT_ERROR) { + njs_parser_syntax_error(vm, parser, + "Unterminated template literal"); + return NJS_TOKEN_ILLEGAL; + } + + node = parser->node; + + if (ret == NXT_DONE) { + ret = njs_parser_array_item(vm, parser, array, node); + if (nxt_slow_path(ret != NXT_OK)) { + return NJS_TOKEN_ERROR; + } + + parser->node = parent; + + return njs_parser_token(vm, parser); + } + + /* NXT_OK */ + + if (tagged_template && expression) { + node = njs_parser_argument(vm, parser, node, index); + if (nxt_slow_path(node == NULL)) { + return NJS_TOKEN_ERROR; + } + + parent->right = node; + parent = node; + + index += sizeof(njs_value_t); + + } else { + ret = njs_parser_array_item(vm, parser, array, node); + if (nxt_slow_path(ret != NXT_OK)) { + return NJS_TOKEN_ERROR; + } + } + + expression = !expression; + } +} + + +static nxt_int_t +njs_parser_template_expression(njs_vm_t *vm, njs_parser_t *parser) +{ + njs_token_t token; + + token = njs_parser_token(vm, parser); + if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { + return NXT_ERROR; + } + + token = njs_parser_expression(vm, parser, token); + if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { + return NXT_ERROR; + } + + if (token != NJS_TOKEN_CLOSE_BRACE) { + njs_parser_syntax_error(vm, parser, + "Missing \"}\" in template expression"); + return NXT_ERROR; + } + + return NXT_OK; +} + + +static nxt_int_t +njs_parser_template_string(njs_vm_t *vm, njs_parser_t *parser) +{ + u_char *p, c; + nxt_int_t ret; + nxt_str_t *text; + nxt_bool_t escape; + njs_lexer_t *lexer; + njs_parser_node_t *node; + + lexer = parser->lexer; + text = &lexer->lexer_token->text; + + text->start = lexer->start; + + escape = 0; + p = lexer->start; + + while (p < lexer->end) { + + c = *p++; + + if (c == '\\') { + if (p == lexer->end) { + break; + } + + p++; + escape = 1; + + continue; + } + + if (c == '`') { + text->length = p - text->start - 1; + goto done; + } + + if (c == '$') { + if (p < lexer->end && *p == '{') { + p++; + text->length = p - text->start - 2; + goto done; + } + } + } + + return NXT_ERROR; + +done: + + node = njs_parser_node_new(vm, parser, NJS_TOKEN_STRING); + if (nxt_slow_path(node == NULL)) { + return NXT_ERROR; + } + + if (escape) { + ret = njs_parser_escape_string_create(vm, parser, &node->u.value); + if (nxt_slow_path(ret != NJS_TOKEN_STRING)) { + return NXT_ERROR; + } + + } else { + ret = njs_parser_string_create(vm, &node->u.value); + if (nxt_slow_path(ret != NXT_OK)) { + return NXT_ERROR; + } + } + + lexer->start = p; + parser->node = node; + + return c == '`' ? NXT_DONE : NXT_OK; +} + + nxt_int_t njs_parser_string_create(njs_vm_t *vm, njs_value_t *value) { diff -r 31232e755143 -r 52983554e61f njs/njs_string.c --- a/njs/njs_string.c Sun Apr 21 18:11:58 2019 +0800 +++ b/njs/njs_string.c Mon Apr 22 19:53:41 2019 +0300 @@ -822,7 +822,7 @@ njs_string_prototype_to_string(njs_vm_t * JavaScript 1.2, ECMAScript 3. */ -static njs_ret_t +njs_ret_t njs_string_prototype_concat(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused) { diff -r 31232e755143 -r 52983554e61f njs/njs_string.h --- a/njs/njs_string.h Sun Apr 21 18:11:58 2019 +0800 +++ b/njs/njs_string.h Mon Apr 22 19:53:41 2019 +0300 @@ -193,6 +193,10 @@ njs_ret_t njs_string_decode_uri_componen njs_index_t njs_value_index(njs_vm_t *vm, const njs_value_t *src, nxt_uint_t runtime); +njs_ret_t njs_string_prototype_concat(njs_vm_t *vm, njs_value_t *args, + nxt_uint_t nargs, njs_index_t unused); + + extern const njs_object_init_t njs_string_constructor_init; extern const njs_object_init_t njs_string_prototype_init; extern const njs_object_init_t njs_string_instance_init; diff -r 31232e755143 -r 52983554e61f njs/njs_vm.c --- a/njs/njs_vm.c Sun Apr 21 18:11:58 2019 +0800 +++ b/njs/njs_vm.c Mon Apr 22 19:53:41 2019 +0300 @@ -458,6 +458,39 @@ njs_vmcode_regexp(njs_vm_t *vm, njs_valu njs_ret_t +njs_vmcode_template_literal(njs_vm_t *vm, njs_value_t *invld1, + njs_value_t *retval) +{ + nxt_int_t ret; + njs_array_t *array; + njs_value_t *value; + + static const njs_function_t concat = { + .native = 1, + .args_offset = 1, + .u.native = njs_string_prototype_concat + }; + + value = njs_vmcode_operand(vm, retval); + + if (!njs_is_primitive(value)) { + array = value->data.u.array; + + ret = njs_function_activate(vm, (njs_function_t *) &concat, + &njs_string_empty, array->start, + array->length, (njs_index_t) retval, 0); + if (ret == NJS_APPLIED) { + return 0; + } + + return NXT_ERROR; + } + + return sizeof(njs_vmcode_template_literal_t); +} + + +njs_ret_t njs_vmcode_object_copy(njs_vm_t *vm, njs_value_t *value, njs_value_t *invld) { njs_object_t *object; diff -r 31232e755143 -r 52983554e61f njs/njs_vm.h --- a/njs/njs_vm.h Sun Apr 21 18:11:58 2019 +0800 +++ b/njs/njs_vm.h Mon Apr 22 19:53:41 2019 +0300 @@ -657,6 +657,12 @@ typedef struct { typedef struct { + njs_vmcode_t code; + njs_index_t retval; +} njs_vmcode_template_literal_t; + + +typedef struct { njs_vmcode_t code; njs_index_t retval; njs_function_lambda_t *lambda; @@ -1161,6 +1167,8 @@ njs_ret_t njs_vmcode_arguments(njs_vm_t njs_value_t *invld2); njs_ret_t njs_vmcode_regexp(njs_vm_t *vm, njs_value_t *inlvd1, njs_value_t *invld2); +njs_ret_t njs_vmcode_template_literal(njs_vm_t *vm, njs_value_t *inlvd1, + njs_value_t *inlvd2); njs_ret_t njs_vmcode_object_copy(njs_vm_t *vm, njs_value_t *value, njs_value_t *invld); diff -r 31232e755143 -r 52983554e61f njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Sun Apr 21 18:11:58 2019 +0800 +++ b/njs/test/njs_unit_test.c Mon Apr 22 19:53:41 2019 +0300 @@ -4207,6 +4207,69 @@ static njs_unit_test_t njs_test[] = "a.sort(function(x, y) { return x - y })"), nxt_string("1,") }, + /* Template literal. */ + + { nxt_string("`"), + nxt_string("SyntaxError: Unterminated template literal in 1") }, + + { nxt_string("`$"), + nxt_string("SyntaxError: Unterminated template literal in 1") }, + + { nxt_string("`${"), + nxt_string("SyntaxError: Unexpected end of input in 1") }, + + { nxt_string("`${a"), + nxt_string("SyntaxError: Missing \"}\" in template expression in 1") }, + + { nxt_string("`${}"), + nxt_string("SyntaxError: Unexpected token \"}\" in 1") }, + + { nxt_string("`${a}"), + nxt_string("SyntaxError: Unterminated template literal in 1") }, + + { nxt_string("`${a}bc"), + nxt_string("SyntaxError: Unterminated template literal in 1") }, + + { nxt_string("`\\"), + nxt_string("SyntaxError: Unterminated template literal in 1") }, + + { nxt_string("`\\${a}bc"), + nxt_string("SyntaxError: Unterminated template literal in 1") }, + + { nxt_string("`text1\ntext2`;"), + nxt_string("text1\ntext2") }, + + { nxt_string("var o = 1; `o = \\`${o}\\``"), + nxt_string("o = `1`") }, + + { nxt_string("`\\unicode`"), + nxt_string("SyntaxError: Invalid Unicode code point \"\\unicode\" in 1") }, + + { nxt_string("var a = 5; var b = 10;" + "`Fifteen is ${a + b} and \nnot ${2 * a + b}.`;"), + nxt_string("Fifteen is 15 and \nnot 20.") }, + + { nxt_string("var s = `1undefined`; s;"), + nxt_string("1undefined") }, + + { nxt_string("var s = '0'; s = `x${s += '1'}`;"), + nxt_string("x01") }, + + { nxt_string("var d = new Date(2011, 5, 24, 18, 45, 12, 625);" + "var something = 'test'; var one = 1; var two = 2;" + "`[${d.toISOString()}] the message contents ${something} ${one + two}`"), + nxt_string("[2011-06-24T18:45:12.625Z] the message contents test 3") }, + + { nxt_string("function isLargeScreen() { return false; }" + "var item = { isCollapsed: true };" + "`header ${ isLargeScreen() ? '' : `icon-${item.isCollapsed ? 'expander' : 'collapser'}` }`;"), + nxt_string("header icon-expander") }, + + { nxt_string("function foo(strings, person, age) { return `${strings[0]}${strings[1]}${person}${age}` };" + "var person = 'Mike'; var age = 21;" + "foo`That ${person} is a ${age}`;"), + nxt_string("That is a Mike21") }, + /* Strings. */ { nxt_string("var a = '0123456789' + '012345';" From xeioex at nginx.com Tue Apr 23 12:46:52 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Tue, 23 Apr 2019 12:46:52 +0000 Subject: [njs] Fixed condition on already been declared exception. Message-ID: details: https://hg.nginx.org/njs/rev/ad1be10fba80 branches: changeset: 919:ad1be10fba80 user: Dmitry Volyntsev date: Tue Apr 23 15:31:40 2019 +0300 description: Fixed condition on already been declared exception. diffstat: njs/njs_parser.c | 1 - njs/njs_variable.c | 20 ++++++++++---------- 2 files changed, 10 insertions(+), 11 deletions(-) diffs (42 lines): diff -r 52983554e61f -r ad1be10fba80 njs/njs_parser.c --- a/njs/njs_parser.c Mon Apr 22 19:53:41 2019 +0300 +++ b/njs/njs_parser.c Tue Apr 23 15:31:40 2019 +0300 @@ -203,7 +203,6 @@ njs_parser_scope_begin(njs_vm_t *vm, njs } else { if (type == NJS_SCOPE_GLOBAL) { type += NJS_INDEX_GLOBAL_OFFSET; - scope->module = vm->options.module; } scope->next_index[0] = type; diff -r 52983554e61f -r ad1be10fba80 njs/njs_variable.c --- a/njs/njs_variable.c Mon Apr 22 19:53:41 2019 +0300 +++ b/njs/njs_variable.c Tue Apr 23 15:31:40 2019 +0300 @@ -91,17 +91,17 @@ njs_variable_scope_add(njs_vm_t *vm, njs if (nxt_lvlhsh_find(&scope->variables, lhq) == NXT_OK) { var = lhq->value; - if (!scope->module && scope->type != NJS_SCOPE_BLOCK) { - return var; - } - - if (type == NJS_VARIABLE_FUNCTION - || var->type == NJS_VARIABLE_FUNCTION) + if (scope->module || scope->type == NJS_SCOPE_BLOCK + || (scope->type == NJS_SCOPE_GLOBAL && vm->options.module)) { - njs_parser_syntax_error(vm, vm->parser, - "\"%V\" has already been declared", - &lhq->key); - return NULL; + if (type == NJS_VARIABLE_FUNCTION + || var->type == NJS_VARIABLE_FUNCTION) + { + njs_parser_syntax_error(vm, vm->parser, + "\"%V\" has already been declared", + &lhq->key); + return NULL; + } } return var; From mdounin at mdounin.ru Tue Apr 23 13:57:58 2019 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 23 Apr 2019 13:57:58 +0000 Subject: [nginx] Stable branch. Message-ID: details: https://hg.nginx.org/nginx/rev/163f99493970 branches: stable-1.16 changeset: 7498:163f99493970 user: Maxim Dounin date: Tue Apr 23 16:12:17 2019 +0300 description: Stable branch. diffstat: src/core/nginx.h | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diffs (14 lines): diff --git a/src/core/nginx.h b/src/core/nginx.h --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1015012 -#define NGINX_VERSION "1.15.12" +#define nginx_version 1016000 +#define NGINX_VERSION "1.16.0" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD From mdounin at mdounin.ru Tue Apr 23 13:58:00 2019 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 23 Apr 2019 13:58:00 +0000 Subject: [nginx] nginx-1.16.0-RELEASE Message-ID: details: https://hg.nginx.org/nginx/rev/abd40ce603fa branches: stable-1.16 changeset: 7499:abd40ce603fa user: Maxim Dounin date: Tue Apr 23 16:12:57 2019 +0300 description: nginx-1.16.0-RELEASE diffstat: docs/xml/nginx/changes.xml | 14 ++++++++++++++ 1 files changed, 14 insertions(+), 0 deletions(-) diffs (24 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,20 @@ + + + + +?????????? ????? 1.16.x. + + +1.16.x stable branch. + + + + + + From mdounin at mdounin.ru Tue Apr 23 13:58:02 2019 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 23 Apr 2019 13:58:02 +0000 Subject: [nginx] release-1.16.0 tag Message-ID: details: https://hg.nginx.org/nginx/rev/37dd6e2bfe8d branches: stable-1.16 changeset: 7500:37dd6e2bfe8d user: Maxim Dounin date: Tue Apr 23 16:12:58 2019 +0300 description: release-1.16.0 tag diffstat: .hgtags | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diffs (8 lines): diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -438,3 +438,4 @@ d2fd76709909767fc727a5b4affcf1dc9ca488a7 75f5c7f628411c79c7044102049f7ab4f7a246e7 release-1.15.10 5155d0296a5ef9841f035920527ffdb771076b44 release-1.15.11 0130ca3d58437b3c7c707cdddd813d530c68da9a release-1.15.12 +abd40ce603fa49b2b8b1cca622c96093b1e14275 release-1.16.0 From alexander.borisov at nginx.com Tue Apr 23 14:47:26 2019 From: alexander.borisov at nginx.com (Alexander Borisov) Date: Tue, 23 Apr 2019 14:47:26 +0000 Subject: [njs] Fixed length calculation for UTF-8 string with escape characters. Message-ID: details: https://hg.nginx.org/njs/rev/b3eb60707479 branches: changeset: 920:b3eb60707479 user: Alexander Borisov date: Mon Apr 22 16:23:43 2019 +0300 description: Fixed length calculation for UTF-8 string with escape characters. This closes #133 issue on GitHub. diffstat: njs/njs_parser_terminal.c | 329 +++++++++++++++++++++++++++++---------------- njs/test/njs_unit_test.c | 6 + 2 files changed, 216 insertions(+), 119 deletions(-) diffs (413 lines): diff -r ad1be10fba80 -r b3eb60707479 njs/njs_parser_terminal.c --- a/njs/njs_parser_terminal.c Tue Apr 23 15:31:40 2019 +0300 +++ b/njs/njs_parser_terminal.c Mon Apr 22 16:23:43 2019 +0300 @@ -28,6 +28,8 @@ static nxt_int_t njs_parser_template_exp njs_parser_t *parser); static nxt_int_t njs_parser_template_string(njs_vm_t *vm, njs_parser_t *parser); +static njs_ret_t njs_parser_escape_string_calc_length(njs_vm_t *vm, + njs_parser_t *parser, size_t *out_size, size_t *out_length); static njs_token_t njs_parser_escape_string_create(njs_vm_t *vm, njs_parser_t *parser, njs_value_t *value); @@ -923,176 +925,265 @@ njs_parser_escape_string_create(njs_vm_t njs_value_t *value) { u_char c, *start, *dst; - size_t size,length, hex_length; - uint64_t u; + size_t size, length, hex_length; + uint64_t cp; + njs_ret_t ret; nxt_str_t *string; - const u_char *p, *src, *end, *hex_end; + const u_char *src, *end, *hex_end; - start = NULL; - dst = NULL; + ret = njs_parser_escape_string_calc_length(vm, parser, &size, &length); + if (nxt_slow_path(ret != NXT_OK)) { + return NJS_TOKEN_ILLEGAL; + } + + start = njs_string_alloc(vm, value, size, length); + if (nxt_slow_path(start == NULL)) { + return NJS_TOKEN_ERROR; + } - for ( ;; ) { - /* - * The loop runs twice: at the first step string size and - * UTF-8 length are evaluated. Then the string is allocated - * and at the second step string content is copied. - */ - size = 0; - length = 0; + dst = start; + + string = njs_parser_text(parser); + src = string->start; + end = src + string->length; - string = njs_parser_text(parser); - src = string->start; - end = src + string->length; + while (src < end) { + c = *src++; - while (src < end) { + if (c == '\\') { + /* + * Testing "src == end" is not required here + * since this has been already tested by lexer. + */ + c = *src++; - if (c == '\\') { + switch (c) { + case 'u': /* - * Testing "src == end" is not required here - * since this has been already tested by lexer. + * A character after "u" can be safely tested here + * because there is always a closing quote at the + * end of string: ...\u". */ - c = *src++; + + if (*src != '{') { + hex_length = 4; + goto hex_length; + } + + src++; + hex_length = 0; + hex_end = end; - switch (c) { + goto hex; + + case 'x': + hex_length = 2; + goto hex_length; + + case '0': + c = '\0'; + break; - case 'u': - hex_length = 4; - /* - * A character after "u" can be safely tested here - * because there is always a closing quote at the - * end of string: ...\u". - */ - if (*src != '{') { - goto hex_length_test; - } + case 'b': + c = '\b'; + break; + + case 'f': + c = '\f'; + break; + + case 'n': + c = '\n'; + break; + + case 'r': + c = '\r'; + break; + case 't': + c = '\t'; + break; + + case 'v': + c = '\v'; + break; + + case '\r': + /* + * A character after "\r" can be safely tested here + * because there is always a closing quote at the + * end of string: ...\\r". + */ + + if (*src == '\n') { src++; - hex_length = 0; - hex_end = end; + } - goto hex; + continue; - case 'x': - hex_length = 2; - goto hex_length_test; + case '\n': + continue; - case '0': - c = '\0'; - break; + default: + break; + } + } - case 'b': - c = '\b'; - break; + *dst++ = c; - case 'f': - c = '\f'; - break; + continue; + + hex_length: - case 'n': - c = '\n'; - break; + hex_end = src + hex_length; + + hex: + cp = njs_number_hex_parse(&src, hex_end); - case 'r': - c = '\r'; - break; + dst = nxt_utf8_encode(dst, (uint32_t) cp); + if (nxt_slow_path(dst == NULL)) { + njs_parser_syntax_error(vm, parser, + "Invalid Unicode code point \"%V\"", + njs_parser_text(parser)); + + return NJS_TOKEN_ILLEGAL; + } - case 't': - c = '\t'; - break; + /* Skip '}' character */ + + if (hex_length == 0) { + src++; + } + } + + if (length > NJS_STRING_MAP_STRIDE && length != size) { + njs_string_offset_map_init(start, size); + } - case 'v': - c = '\v'; - break; + return NJS_TOKEN_STRING; +} + - case '\r': - /* - * A character after "\r" can be safely tested here - * because there is always a closing quote at the - * end of string: ...\\r". - */ - if (*src == '\n') { - src++; - } +static njs_ret_t +njs_parser_escape_string_calc_length(njs_vm_t *vm, njs_parser_t *parser, + size_t *out_size, size_t *out_length) +{ + size_t size, length, hex_length; + uint64_t cp; + nxt_str_t *string; + const u_char *ptr, *src, *end, *hex_end; + + size = 0; + length = 0; + + string = njs_parser_text(parser); + src = string->start; + end = src + string->length; + + while (src < end) { - continue; + if (*src == '\\') { + src++; - case '\n': - continue; + switch (*src) { + case 'u': + src++; - default: - break; + if (*src != '{') { + hex_length = 4; + goto hex_length; } - } + + src++; + hex_length = 0; + hex_end = end; + + goto hex; + + case 'x': + src++; + hex_length = 2; + goto hex_length; - size++; - length++; + case '\r': + src++; - if (dst != NULL) { - *dst++ = c; - } + if (*src == '\n') { + src++; + } + + continue; - continue; - - hex_length_test: + case '\n': + src++; + continue; - hex_end = src + hex_length; + default: + break; + } + } - if (hex_end > end) { + if (*src >= 0x80) { + ptr = src; + + if (nxt_slow_path(nxt_utf8_decode(&src, end) == 0xffffffff)) { goto invalid; } - hex: + size += src - ptr; + length++; + + continue; + } - p = src; - u = njs_number_hex_parse(&src, hex_end); + src++; + size++; + length++; + + continue; + + hex_length: - if (hex_length != 0) { - if (src != hex_end) { - goto invalid; - } + hex_end = src + hex_length; + + if (nxt_slow_path(hex_end > end)) { + goto invalid; + } - } else { - if (src == p || (src - p) > 6) { - goto invalid; - } + hex: - if (src == end || *src++ != '}') { - goto invalid; - } + ptr = src; + cp = njs_number_hex_parse(&src, hex_end); + + if (hex_length != 0) { + if (src != hex_end) { + goto invalid; } - size += nxt_utf8_size(u); - length++; + } else { + if (src == ptr || (src - ptr) > 6) { + goto invalid; + } - if (dst != NULL) { - dst = nxt_utf8_encode(dst, (uint32_t) u); - if (dst == NULL) { - goto invalid; - } + if (src == end || *src++ != '}') { + goto invalid; } } - if (start != NULL) { - if (length > NJS_STRING_MAP_STRIDE && length != size) { - njs_string_offset_map_init(start, size); - } - - return NJS_TOKEN_STRING; - } + size += nxt_utf8_size(cp); + length++; + } - start = njs_string_alloc(vm, value, size, length); - if (nxt_slow_path(start == NULL)) { - return NJS_TOKEN_ERROR; - } + *out_size = size; + *out_length = length; - dst = start; - } + return NXT_OK; invalid: njs_parser_syntax_error(vm, parser, "Invalid Unicode code point \"%V\"", njs_parser_text(parser)); - return NJS_TOKEN_ILLEGAL; + return NJS_ERROR; } diff -r ad1be10fba80 -r b3eb60707479 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Tue Apr 23 15:31:40 2019 +0300 +++ b/njs/test/njs_unit_test.c Mon Apr 22 16:23:43 2019 +0300 @@ -4381,6 +4381,12 @@ static njs_unit_test_t njs_test[] = { nxt_string("'abc'.length"), nxt_string("3") }, + { nxt_string("'??????\\n'.length"), + nxt_string("7") }, + + { nxt_string("'??????\\n\\u{61}\\u{3B1}\\u{20AC}'.length"), + nxt_string("10") }, + { nxt_string("''.hasOwnProperty('length')"), nxt_string("true") }, From alexander.borisov at nginx.com Tue Apr 23 14:47:26 2019 From: alexander.borisov at nginx.com (Alexander Borisov) Date: Tue, 23 Apr 2019 14:47:26 +0000 Subject: [njs] Fixed parsing surrogate pair presents as UTF-16 escape sequences. Message-ID: details: https://hg.nginx.org/njs/rev/724c31e77d2a branches: changeset: 921:724c31e77d2a user: Alexander Borisov date: Mon Apr 22 16:23:50 2019 +0300 description: Fixed parsing surrogate pair presents as UTF-16 escape sequences. This closes #96 issue on GitHub. diffstat: njs/njs_parser_terminal.c | 55 ++++++++++++++++++++++++++++++++++++++++------ njs/test/njs_unit_test.c | 17 ++++++++++++++ 2 files changed, 64 insertions(+), 8 deletions(-) diffs (137 lines): diff -r b3eb60707479 -r 724c31e77d2a njs/njs_parser_terminal.c --- a/njs/njs_parser_terminal.c Mon Apr 22 16:23:43 2019 +0300 +++ b/njs/njs_parser_terminal.c Mon Apr 22 16:23:50 2019 +0300 @@ -926,7 +926,7 @@ njs_parser_escape_string_create(njs_vm_t { u_char c, *start, *dst; size_t size, length, hex_length; - uint64_t cp; + uint64_t cp, cp_pair; njs_ret_t ret; nxt_str_t *string; const u_char *src, *end, *hex_end; @@ -942,6 +942,7 @@ njs_parser_escape_string_create(njs_vm_t } dst = start; + cp_pair = 0; string = njs_parser_text(parser); src = string->start; @@ -1041,6 +1042,23 @@ njs_parser_escape_string_create(njs_vm_t hex: cp = njs_number_hex_parse(&src, hex_end); + /* Skip '}' character. */ + + if (hex_length == 0) { + src++; + } + + /* Surrogate pair. */ + + if (cp_pair != 0) { + cp = 0x10000 + ((cp_pair - 0xd800) << 10) + (cp - 0xdc00); + cp_pair = 0; + + } else if (cp >= 0xd800 && cp <= 0xdfff) { + cp_pair = cp; + continue; + } + dst = nxt_utf8_encode(dst, (uint32_t) cp); if (nxt_slow_path(dst == NULL)) { njs_parser_syntax_error(vm, parser, @@ -1049,12 +1067,6 @@ njs_parser_escape_string_create(njs_vm_t return NJS_TOKEN_ILLEGAL; } - - /* Skip '}' character */ - - if (hex_length == 0) { - src++; - } } if (length > NJS_STRING_MAP_STRIDE && length != size) { @@ -1070,12 +1082,13 @@ njs_parser_escape_string_calc_length(njs size_t *out_size, size_t *out_length) { size_t size, length, hex_length; - uint64_t cp; + uint64_t cp, cp_pair; nxt_str_t *string; const u_char *ptr, *src, *end, *hex_end; size = 0; length = 0; + cp_pair = 0; string = njs_parser_text(parser); src = string->start; @@ -1171,6 +1184,25 @@ njs_parser_escape_string_calc_length(njs } } + /* Surrogate pair. */ + + if (cp_pair != 0) { + if (nxt_slow_path(cp < 0xdc00 || cp > 0xdfff)) { + goto invalid_pair; + } + + cp = 0x10000 + ((cp_pair - 0xd800) << 10) + (cp - 0xdc00); + cp_pair = 0; + + } else if (cp >= 0xd800 && cp <= 0xdfff) { + if (nxt_slow_path(cp > 0xdbff || src[0] != '\\' || src[1] != 'u')) { + goto invalid_pair; + } + + cp_pair = cp; + continue; + } + size += nxt_utf8_size(cp); length++; } @@ -1186,4 +1218,11 @@ invalid: njs_parser_text(parser)); return NJS_ERROR; + +invalid_pair: + + njs_parser_syntax_error(vm, parser, "Invalid surrogate pair \"%V\"", + njs_parser_text(parser)); + + return NJS_ERROR; } diff -r b3eb60707479 -r 724c31e77d2a njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Mon Apr 22 16:23:43 2019 +0300 +++ b/njs/test/njs_unit_test.c Mon Apr 22 16:23:50 2019 +0300 @@ -4387,6 +4387,23 @@ static njs_unit_test_t njs_test[] = { nxt_string("'??????\\n\\u{61}\\u{3B1}\\u{20AC}'.length"), nxt_string("10") }, + { nxt_string("'\\ud83d\\udc4d'"), + nxt_string("\xf0\x9f\x91\x8d") }, + + { nxt_string("'\\ud83d\\udc4d'.length"), + nxt_string("1") }, + + { nxt_string("'\\ud83d abc \\udc4d'"), + nxt_string("SyntaxError: Invalid surrogate pair " + "\"\\ud83d abc \\udc4d\" in 1") }, + + { nxt_string("'\\ud83d'"), + nxt_string("SyntaxError: Invalid surrogate pair \"\\ud83d\" in 1") }, + + { nxt_string("'\\ud83d\\uabcd'"), + nxt_string("SyntaxError: Invalid surrogate pair " + "\"\\ud83d\\uabcd\" in 1") }, + { nxt_string("''.hasOwnProperty('length')"), nxt_string("true") }, From alexander.borisov at nginx.com Tue Apr 23 15:11:25 2019 From: alexander.borisov at nginx.com (Alexander Borisov) Date: Tue, 23 Apr 2019 15:11:25 +0000 Subject: [njs] Added macro for converting surrogate pair to code point. Message-ID: details: https://hg.nginx.org/njs/rev/1c1732696e98 branches: changeset: 922:1c1732696e98 user: Alexander Borisov date: Tue Apr 23 18:10:37 2019 +0300 description: Added macro for converting surrogate pair to code point. diffstat: njs/njs_json.c | 2 +- njs/njs_parser_terminal.c | 8 ++------ njs/njs_string.h | 4 ++++ 3 files changed, 7 insertions(+), 7 deletions(-) diffs (57 lines): diff -r 724c31e77d2a -r 1c1732696e98 njs/njs_json.c --- a/njs/njs_json.c Mon Apr 22 16:23:50 2019 +0300 +++ b/njs/njs_json.c Tue Apr 23 18:10:37 2019 +0300 @@ -820,7 +820,7 @@ njs_json_parse_string(njs_json_parse_ctx return NULL; } - utf = 0x10000 + ((utf - 0xd800) << 10) + (utf_low - 0xdc00); + utf = njs_string_surrogate_pair(utf, utf_low); } s = nxt_utf8_encode(s, utf); diff -r 724c31e77d2a -r 1c1732696e98 njs/njs_parser_terminal.c --- a/njs/njs_parser_terminal.c Mon Apr 22 16:23:50 2019 +0300 +++ b/njs/njs_parser_terminal.c Tue Apr 23 18:10:37 2019 +0300 @@ -1048,10 +1048,8 @@ njs_parser_escape_string_create(njs_vm_t src++; } - /* Surrogate pair. */ - if (cp_pair != 0) { - cp = 0x10000 + ((cp_pair - 0xd800) << 10) + (cp - 0xdc00); + cp = njs_string_surrogate_pair(cp_pair, cp); cp_pair = 0; } else if (cp >= 0xd800 && cp <= 0xdfff) { @@ -1184,14 +1182,12 @@ njs_parser_escape_string_calc_length(njs } } - /* Surrogate pair. */ - if (cp_pair != 0) { if (nxt_slow_path(cp < 0xdc00 || cp > 0xdfff)) { goto invalid_pair; } - cp = 0x10000 + ((cp_pair - 0xd800) << 10) + (cp - 0xdc00); + cp = njs_string_surrogate_pair(cp_pair, cp); cp_pair = 0; } else if (cp >= 0xd800 && cp <= 0xdfff) { diff -r 724c31e77d2a -r 1c1732696e98 njs/njs_string.h --- a/njs/njs_string.h Mon Apr 22 16:23:50 2019 +0300 +++ b/njs/njs_string.h Tue Apr 23 18:10:37 2019 +0300 @@ -27,6 +27,10 @@ /* The maximum signed int32_t. */ #define NJS_STRING_MAX_LENGTH 0x7fffffff +/* Converting surrogate pair to code point. */ +#define njs_string_surrogate_pair(high, low) \ + (0x10000 + ((high - 0xd800) << 10) + (low - 0xdc00)) + /* * NJS_STRING_MAP_STRIDE should be power of two to use shift and binary * AND operations instead of division and remainder operations but no From mdounin at mdounin.ru Tue Apr 23 16:45:20 2019 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 23 Apr 2019 19:45:20 +0300 Subject: [PATCH] Range filter: always support ascending multipart ranges. In-Reply-To: References: Message-ID: <20190423164520.GN1877@mdounin.ru> Hello! On Mon, Apr 22, 2019 at 09:51:49AM -0700, Robert Burke wrote: > Hello, > > I'd love to hear any comments about this :) > > On Thu, Apr 11, 2019 at 5:51 AM Robert Burke wrote: > > > > Hello, > > > > At Cloudflare we'd like to support multiple byte-ranges if they are > > non-overlapping and in ascending order on cache miss or when using > > slice. This patch adds support for that. It preserves the existing > > multipart range support for response bodies that are in a single > > buffer. It does not remove buffers from the passed-in chain, which > > seems like it was the biggest issue mdounin raised with the previous > > patch. Actually, the biggest issue is "if it worth the added complexity", and issues with the patch as originally reviewed[1] was an additional reason to say "no". If you think you want to add support nevertheless, you may want to elaborate more on why you need it. In my practice there are very few legitimate users of multipart ranges, and at least some of these actually benefit from disabling ranges support completely. [1] http://mailman.nginx.org/pipermail/nginx-devel/2017-November/010623.html -- Maxim Dounin http://mdounin.ru/ From mat999 at gmail.com Wed Apr 24 00:38:30 2019 From: mat999 at gmail.com (Mathew Heard) Date: Wed, 24 Apr 2019 10:38:30 +1000 Subject: SO_REUSEPORT In-Reply-To: References: <20190201141331.GT1877@mdounin.ru> <20190201154822.GV1877@mdounin.ru> Message-ID: Yesterday one of my techs reported that a production server had a nginx worker sitting at 99.9% CPU usage in top and not accepting new connections (but getting it's share distributed due to SO_REUSEPORT). I thought this might be related. The workers age was significantly older than it's peers so it appears to have been a worker left from a previous configuration reload. It was child to the single running master process and there was nothing of interest in the error logs. Just sharing this here as it sounds related. On Tue, Feb 5, 2019 at 11:25 PM Tomas Kvasnicka wrote: > Hi! > > I just wanted to add my 2 cents here?. > > - We are facing a very similar issue. During reloads of reuseport enabled > configuration it sometimes happens that no workers accept new connections, > bandwidth basically drops to 0 and it all reverts back to normal within few > seconds. Hurts but not deadly. > - Our nginx uses the Intel QAT card which allows only a limited number of > user-space processes using the card at any given moment. Therefore, our HUP > handler has been patched quite a bit to shutdown workers one-by-one and > then use the ngx_reap_child to start a new worker with updated > configuration. > - We only use the reuseport option in combination with the QAT-based > servers (servers with the patched HUP behaviour). Therefore, I am not yet > sure if changes in the reload mechanism are the cause of the issue - still > investigating. > - Thanks a lot for the ?ss -nltp? tip. > - Currently testing the ?iptables-drop-empty-ACKs? workaround. > - No two nginx masters are running simultaneously. > - Reducing the number of workers is also not happening, due to the changes > described above - the new value of worker_processes will simply be ignored. > > Thanks, > Tomas > _______________________________________________ > 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 vl at nginx.com Wed Apr 24 11:30:44 2019 From: vl at nginx.com (Vladimir Homutov) Date: Wed, 24 Apr 2019 11:30:44 +0000 Subject: [nginx] Version bump. Message-ID: details: https://hg.nginx.org/nginx/rev/88fd9f3976f6 branches: changeset: 7501:88fd9f3976f6 user: Vladimir Homutov date: Wed Apr 24 13:41:29 2019 +0300 description: Version bump. diffstat: src/core/nginx.h | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diffs (14 lines): diff -r 10db363fcf57 -r 88fd9f3976f6 src/core/nginx.h --- a/src/core/nginx.h Tue Apr 16 17:54:59 2019 +0300 +++ b/src/core/nginx.h Wed Apr 24 13:41:29 2019 +0300 @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1015012 -#define NGINX_VERSION "1.15.12" +#define nginx_version 1017000 +#define NGINX_VERSION "1.17.0" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD From vl at nginx.com Wed Apr 24 11:30:46 2019 From: vl at nginx.com (Vladimir Homutov) Date: Wed, 24 Apr 2019 11:30:46 +0000 Subject: [nginx] Core: enabled "include" in any context (ticket #1615). Message-ID: details: https://hg.nginx.org/nginx/rev/b7a7c02aea3a branches: changeset: 7502:b7a7c02aea3a user: Vladimir Homutov date: Tue Apr 09 11:40:20 2019 +0300 description: Core: enabled "include" in any context (ticket #1615). diffstat: src/core/ngx_conf_file.h | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diffs (12 lines): diff -r 88fd9f3976f6 -r b7a7c02aea3a src/core/ngx_conf_file.h --- a/src/core/ngx_conf_file.h Wed Apr 24 13:41:29 2019 +0300 +++ b/src/core/ngx_conf_file.h Tue Apr 09 11:40:20 2019 +0300 @@ -49,7 +49,7 @@ #define NGX_DIRECT_CONF 0x00010000 #define NGX_MAIN_CONF 0x01000000 -#define NGX_ANY_CONF 0x1F000000 +#define NGX_ANY_CONF 0xFF000000 From alexander.borisov at nginx.com Wed Apr 24 16:04:57 2019 From: alexander.borisov at nginx.com (Alexander Borisov) Date: Wed, 24 Apr 2019 16:04:57 +0000 Subject: [njs] Improved String.prototype.match() function. Message-ID: details: https://hg.nginx.org/njs/rev/cbb1817c5a39 branches: changeset: 924:cbb1817c5a39 user: Alexander Borisov date: Wed Apr 24 19:04:23 2019 +0300 description: Improved String.prototype.match() function. diffstat: njs/njs_string.c | 91 +++++++++++++++++++++++++++---------------------------- 1 files changed, 45 insertions(+), 46 deletions(-) diffs (114 lines): diff -r 24d109826d6d -r cbb1817c5a39 njs/njs_string.c --- a/njs/njs_string.c Wed Apr 24 19:04:22 2019 +0300 +++ b/njs/njs_string.c Wed Apr 24 19:04:23 2019 +0300 @@ -2660,65 +2660,64 @@ njs_string_match_multiple(njs_vm_t *vm, } if (nxt_regex_is_valid(&pattern->regex[type])) { - array = NULL; + + array = njs_array_alloc(vm, 0, NJS_ARRAY_SPARE); + if (nxt_slow_path(array == NULL)) { + return NXT_ERROR; + } + p = string.start; end = p + string.size; do { ret = njs_regexp_match(vm, &pattern->regex[type], p, string.size, vm->single_match_data); - if (ret >= 0) { - if (array != NULL) { - ret = njs_array_expand(vm, array, 0, 1); - if (nxt_slow_path(ret != NXT_OK)) { - return ret; - } - - } else { - array = njs_array_alloc(vm, 0, NJS_ARRAY_SPARE); - if (nxt_slow_path(array == NULL)) { - return NXT_ERROR; - } - - vm->retval.data.u.array = array; - vm->retval.type = NJS_ARRAY; - vm->retval.data.truth = 1; + if (ret < 0) { + if (nxt_fast_path(ret == NXT_REGEX_NOMATCH)) { + break; } - captures = nxt_regex_captures(vm->single_match_data); - start = p + captures[0]; - - if (captures[1] == 0) { - p = nxt_utf8_next(start, end); - string.size = end - p; - - size = 0; - length = 0; - - } else { - p += captures[1]; - string.size -= captures[1]; - - size = captures[1] - captures[0]; - length = njs_string_calc_length(utf8, start, size); - } - - ret = njs_string_new(vm, &array->start[array->length], - start, size, length); - if (nxt_slow_path(ret != NXT_OK)) { - return ret; - } - - array->length++; - - } else if (ret == NXT_REGEX_NOMATCH) { - break; + njs_internal_error(vm, "njs_regexp_match() failed"); + + return NXT_ERROR; + } + + ret = njs_array_expand(vm, array, 0, 1); + if (nxt_slow_path(ret != NXT_OK)) { + return ret; + } + + captures = nxt_regex_captures(vm->single_match_data); + start = p + captures[0]; + + if (captures[1] == 0) { + p = nxt_utf8_next(start, end); + string.size = end - p; + + size = 0; + length = 0; } else { - return NXT_ERROR; + p += captures[1]; + string.size -= captures[1]; + + size = captures[1] - captures[0]; + length = njs_string_calc_length(utf8, start, size); } + ret = njs_string_new(vm, &array->start[array->length], + start, size, length); + if (nxt_slow_path(ret != NXT_OK)) { + return ret; + } + + array->length++; + } while (p <= end); + + vm->retval.data.u.array = array; + vm->retval.type = NJS_ARRAY; + vm->retval.data.truth = 1; } return NXT_OK; From alexander.borisov at nginx.com Wed Apr 24 16:04:56 2019 From: alexander.borisov at nginx.com (Alexander Borisov) Date: Wed, 24 Apr 2019 16:04:56 +0000 Subject: [njs] Added processing asterisk quantifier for String.prototype.match(). Message-ID: details: https://hg.nginx.org/njs/rev/24d109826d6d branches: changeset: 923:24d109826d6d user: Alexander Borisov date: Wed Apr 24 19:04:22 2019 +0300 description: Added processing asterisk quantifier for String.prototype.match(). The lack of processing asterisk quantification in regexp led to infinity loop in String.prototype.match() function. diffstat: njs/njs_string.c | 34 ++++++++++++++++++++++------------ njs/test/njs_unit_test.c | 27 +++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 12 deletions(-) diffs (108 lines): diff -r 1c1732696e98 -r 24d109826d6d njs/njs_string.c --- a/njs/njs_string.c Tue Apr 23 18:10:37 2019 +0300 +++ b/njs/njs_string.c Wed Apr 24 19:04:22 2019 +0300 @@ -2634,11 +2634,11 @@ njs_string_match_multiple(njs_vm_t *vm, njs_regexp_pattern_t *pattern) { int *captures; - u_char *start; int32_t size, length; njs_ret_t ret; njs_utf8_t utf8; njs_array_t *array; + const u_char *p, *start, *end; njs_regexp_utf8_t type; njs_string_prop_t string; @@ -2661,10 +2661,12 @@ njs_string_match_multiple(njs_vm_t *vm, if (nxt_regex_is_valid(&pattern->regex[type])) { array = NULL; + p = string.start; + end = p + string.size; do { - ret = njs_regexp_match(vm, &pattern->regex[type], string.start, - string.size, vm->single_match_data); + ret = njs_regexp_match(vm, &pattern->regex[type], p, string.size, + vm->single_match_data); if (ret >= 0) { if (array != NULL) { ret = njs_array_expand(vm, array, 0, 1); @@ -2684,14 +2686,22 @@ njs_string_match_multiple(njs_vm_t *vm, } captures = nxt_regex_captures(vm->single_match_data); - start = &string.start[captures[0]]; - - string.start += captures[1]; - string.size -= captures[1]; - - size = captures[1] - captures[0]; - - length = njs_string_calc_length(utf8, start, size); + start = p + captures[0]; + + if (captures[1] == 0) { + p = nxt_utf8_next(start, end); + string.size = end - p; + + size = 0; + length = 0; + + } else { + p += captures[1]; + string.size -= captures[1]; + + size = captures[1] - captures[0]; + length = njs_string_calc_length(utf8, start, size); + } ret = njs_string_new(vm, &array->start[array->length], start, size, length); @@ -2708,7 +2718,7 @@ njs_string_match_multiple(njs_vm_t *vm, return NXT_ERROR; } - } while (string.size > 0); + } while (p <= end); } return NXT_OK; diff -r 1c1732696e98 -r 24d109826d6d njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Tue Apr 23 18:10:37 2019 +0300 +++ b/njs/test/njs_unit_test.c Wed Apr 24 19:04:22 2019 +0300 @@ -5375,6 +5375,33 @@ static njs_unit_test_t njs_test[] = { nxt_string("('?' + '?'.repeat(33)+'?').replace(/(?+)(?+)/, function(m, p1) { return p1[32]; })"), nxt_string("??") }, + { nxt_string("'abc'.match(/a*/g)"), + nxt_string("a,,,") }, + + { nxt_string("'abc'.match(/z*/g)"), + nxt_string(",,,") }, + + { nxt_string("'abc'.match(/.?/g)"), + nxt_string("a,b,c,") }, + + { nxt_string("''.match(/a*/g)"), + nxt_string("") }, + + { nxt_string("''.match(/.?/g)"), + nxt_string("") }, + + { nxt_string("'???'.match(/??/g)"), + nxt_string(",,,") }, + + { nxt_string("'???'.match(/z*/g)"), + nxt_string(",,,") }, + + { nxt_string("'???'.match(/z*/g)"), + nxt_string(",,,") }, + + { nxt_string("'????'.match(/z*/g)"), + nxt_string(",,,,") }, + { nxt_string("'abcdefgh'.match()"), nxt_string("") }, From ru at nginx.com Wed Apr 24 18:47:24 2019 From: ru at nginx.com (Ruslan Ermilov) Date: Wed, 24 Apr 2019 18:47:24 +0000 Subject: [nginx] Added ngx_http_set_complex_value_size_slot(). Message-ID: details: https://hg.nginx.org/nginx/rev/b82162b8496a branches: changeset: 7503:b82162b8496a user: Ruslan Ermilov date: Wed Apr 24 16:38:51 2019 +0300 description: Added ngx_http_set_complex_value_size_slot(). If a complex value is expected to be of type size_t, and the compiled value is constant, the constant size_t value is remembered at compile time. 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. diffstat: src/http/ngx_http_script.c | 61 ++++++++++++++++++++++++++++++++++++++++++ src/http/ngx_http_script.h | 8 +++++ src/stream/ngx_stream_script.c | 61 ++++++++++++++++++++++++++++++++++++++++++ src/stream/ngx_stream_script.h | 8 +++++ 4 files changed, 138 insertions(+), 0 deletions(-) diffs (213 lines): diff -r b7a7c02aea3a -r b82162b8496a src/http/ngx_http_script.c --- a/src/http/ngx_http_script.c Tue Apr 09 11:40:20 2019 +0300 +++ b/src/http/ngx_http_script.c Wed Apr 24 16:38:51 2019 +0300 @@ -104,6 +104,37 @@ ngx_http_complex_value(ngx_http_request_ } +size_t +ngx_http_complex_value_size(ngx_http_request_t *r, + ngx_http_complex_value_t *val, size_t default_value) +{ + size_t size; + ngx_str_t value; + + if (val == NULL) { + return default_value; + } + + if (val->lengths == NULL) { + return val->u.size; + } + + if (ngx_http_complex_value(r, val, &value) != NGX_OK) { + return default_value; + } + + size = ngx_parse_size(&value); + + if (size == (size_t) NGX_ERROR) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "invalid size \"%V\"", &value); + return default_value; + } + + return size; +} + + ngx_int_t ngx_http_compile_complex_value(ngx_http_compile_complex_value_t *ccv) { @@ -244,6 +275,36 @@ ngx_http_set_complex_value_slot(ngx_conf } +char * +ngx_http_set_complex_value_size_slot(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + char *p = conf; + + char *rv; + ngx_http_complex_value_t *cv; + + rv = ngx_http_set_complex_value_slot(cf, cmd, conf); + + if (rv != NGX_CONF_OK) { + return rv; + } + + cv = *(ngx_http_complex_value_t **) (p + cmd->offset); + + 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 -r b7a7c02aea3a -r b82162b8496a src/http/ngx_http_script.h --- a/src/http/ngx_http_script.h Tue Apr 09 11:40:20 2019 +0300 +++ b/src/http/ngx_http_script.h Wed Apr 24 16:38:51 2019 +0300 @@ -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,9 +211,13 @@ 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); +size_t ngx_http_complex_value_size(ngx_http_request_t *r, + ngx_http_complex_value_t *val, size_t default_value); ngx_int_t ngx_http_compile_complex_value(ngx_http_compile_complex_value_t *ccv); char *ngx_http_set_complex_value_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +char *ngx_http_set_complex_value_size_slot(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); ngx_int_t ngx_http_test_predicates(ngx_http_request_t *r, diff -r b7a7c02aea3a -r b82162b8496a src/stream/ngx_stream_script.c --- a/src/stream/ngx_stream_script.c Tue Apr 09 11:40:20 2019 +0300 +++ b/src/stream/ngx_stream_script.c Wed Apr 24 16:38:51 2019 +0300 @@ -105,6 +105,37 @@ ngx_stream_complex_value(ngx_stream_sess } +size_t +ngx_stream_complex_value_size(ngx_stream_session_t *s, + ngx_stream_complex_value_t *val, size_t default_value) +{ + size_t size; + ngx_str_t value; + + if (val == NULL) { + return default_value; + } + + if (val->lengths == NULL) { + return val->u.size; + } + + if (ngx_stream_complex_value(s, val, &value) != NGX_OK) { + return default_value; + } + + size = ngx_parse_size(&value); + + if (size == (size_t) NGX_ERROR) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "invalid size \"%V\"", &value); + return default_value; + } + + return size; +} + + ngx_int_t ngx_stream_compile_complex_value(ngx_stream_compile_complex_value_t *ccv) { @@ -246,6 +277,36 @@ ngx_stream_set_complex_value_slot(ngx_co } +char * +ngx_stream_set_complex_value_size_slot(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + char *p = conf; + + char *rv; + ngx_stream_complex_value_t *cv; + + rv = ngx_stream_set_complex_value_slot(cf, cmd, conf); + + if (rv != NGX_CONF_OK) { + return rv; + } + + cv = *(ngx_stream_complex_value_t **) (p + cmd->offset); + + 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_uint_t ngx_stream_script_variables_count(ngx_str_t *value) { diff -r b7a7c02aea3a -r b82162b8496a src/stream/ngx_stream_script.h --- a/src/stream/ngx_stream_script.h Tue Apr 09 11:40:20 2019 +0300 +++ b/src/stream/ngx_stream_script.h Wed Apr 24 16:38:51 2019 +0300 @@ -56,6 +56,10 @@ typedef struct { ngx_uint_t *flushes; void *lengths; void *values; + + union { + size_t size; + } u; } ngx_stream_complex_value_t; @@ -102,10 +106,14 @@ void ngx_stream_script_flush_complex_val ngx_stream_complex_value_t *val); ngx_int_t ngx_stream_complex_value(ngx_stream_session_t *s, ngx_stream_complex_value_t *val, ngx_str_t *value); +size_t ngx_stream_complex_value_size(ngx_stream_session_t *s, + ngx_stream_complex_value_t *val, size_t default_value); ngx_int_t ngx_stream_compile_complex_value( ngx_stream_compile_complex_value_t *ccv); char *ngx_stream_set_complex_value_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +char *ngx_stream_set_complex_value_size_slot(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); ngx_uint_t ngx_stream_script_variables_count(ngx_str_t *value); From ru at nginx.com Wed Apr 24 18:47:26 2019 From: ru at nginx.com (Ruslan Ermilov) Date: Wed, 24 Apr 2019 18:47:26 +0000 Subject: [nginx] Variables support in limit_rate and limit_rate_after (ticket #293). Message-ID: details: https://hg.nginx.org/nginx/rev/c19ca381b2e6 branches: changeset: 7504:c19ca381b2e6 user: Ruslan Ermilov date: Wed Apr 24 16:38:54 2019 +0300 description: Variables support in limit_rate and limit_rate_after (ticket #293). diffstat: src/http/ngx_http_core_module.c | 24 +++++++------ src/http/ngx_http_core_module.h | 5 +- src/http/ngx_http_request.h | 3 + src/http/ngx_http_upstream.c | 2 + src/http/ngx_http_variables.c | 55 +++++++++++++++----------------- src/http/ngx_http_write_filter_module.c | 12 ++++++- 6 files changed, 57 insertions(+), 44 deletions(-) diffs (237 lines): diff -r b82162b8496a -r c19ca381b2e6 src/http/ngx_http_core_module.c --- a/src/http/ngx_http_core_module.c Wed Apr 24 16:38:51 2019 +0300 +++ b/src/http/ngx_http_core_module.c Wed Apr 24 16:38:54 2019 +0300 @@ -479,7 +479,7 @@ 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_size_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_core_loc_conf_t, limit_rate), NULL }, @@ -487,7 +487,7 @@ static ngx_command_t ngx_http_core_comm { 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_size_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_core_loc_conf_t, limit_rate_after), NULL }, @@ -1281,10 +1281,6 @@ 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 (clcf->handler) { r->content_handler = clcf->handler; } @@ -3387,6 +3383,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; */ @@ -3417,8 +3415,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; @@ -3647,9 +3643,15 @@ 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); + + 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_msec_value(conf->keepalive_timeout, prev->keepalive_timeout, 75000); ngx_conf_merge_sec_value(conf->keepalive_header, diff -r b82162b8496a -r c19ca381b2e6 src/http/ngx_http_core_module.h --- a/src/http/ngx_http_core_module.h Wed Apr 24 16:38:51 2019 +0300 +++ b/src/http/ngx_http_core_module.h Wed Apr 24 16:38:54 2019 +0300 @@ -349,13 +349,14 @@ 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 */ size_t subrequest_output_buffer_size; /* subrequest_output_buffer_size */ + ngx_http_complex_value_t *limit_rate; /* limit_rate */ + ngx_http_complex_value_t *limit_rate_after; /* 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 -r b82162b8496a -r c19ca381b2e6 src/http/ngx_http_request.h --- a/src/http/ngx_http_request.h Wed Apr 24 16:38:51 2019 +0300 +++ b/src/http/ngx_http_request.h Wed Apr 24 16:38:54 2019 +0300 @@ -515,6 +515,9 @@ struct ngx_http_request_s { unsigned limit_conn_set:1; unsigned limit_req_set:1; + unsigned limit_rate_set:1; + unsigned limit_rate_after_set:1; + #if 0 unsigned cacheable:1; #endif diff -r b82162b8496a -r c19ca381b2e6 src/http/ngx_http_upstream.c --- a/src/http/ngx_http_upstream.c Wed Apr 24 16:38:51 2019 +0300 +++ b/src/http/ngx_http_upstream.c Wed Apr 24 16:38:54 2019 +0300 @@ -2979,6 +2979,7 @@ ngx_http_upstream_send_response(ngx_http ngx_http_upstream_process_non_buffered_downstream; r->limit_rate = 0; + r->limit_rate_set = 1; if (u->input_filter_init(u->input_filter_ctx) == NGX_ERROR) { ngx_http_upstream_finalize_request(r, u, NGX_ERROR); @@ -4806,6 +4807,7 @@ ngx_http_upstream_process_limit_rate(ngx if (n != NGX_ERROR) { r->limit_rate = (size_t) n; + r->limit_rate_set = 1; } return NGX_OK; diff -r b82162b8496a -r c19ca381b2e6 src/http/ngx_http_variables.c --- a/src/http/ngx_http_variables.c Wed Apr 24 16:38:51 2019 +0300 +++ b/src/http/ngx_http_variables.c Wed Apr 24 16:38:54 2019 +0300 @@ -22,8 +22,6 @@ static void ngx_http_variable_request_se #endif static ngx_int_t ngx_http_variable_request_get_size(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); -static void ngx_http_variable_request_set_size(ngx_http_request_t *r, - ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_variable_header(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); @@ -124,6 +122,8 @@ static ngx_int_t ngx_http_variable_sent_ ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_variable_sent_transfer_encoding(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); +static void ngx_http_variable_set_limit_rate(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_variable_connection(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); @@ -321,7 +321,7 @@ static ngx_http_variable_t ngx_http_cor { ngx_string("sent_http_link"), NULL, ngx_http_variable_headers, offsetof(ngx_http_request_t, headers_out.link), 0, 0 }, - { ngx_string("limit_rate"), ngx_http_variable_request_set_size, + { ngx_string("limit_rate"), ngx_http_variable_set_limit_rate, ngx_http_variable_request_get_size, offsetof(ngx_http_request_t, limit_rate), NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE, 0 }, @@ -788,32 +788,6 @@ ngx_http_variable_request_get_size(ngx_h } -static void -ngx_http_variable_request_set_size(ngx_http_request_t *r, - ngx_http_variable_value_t *v, uintptr_t data) -{ - ssize_t s, *sp; - ngx_str_t val; - - val.len = v->len; - val.data = v->data; - - s = ngx_parse_size(&val); - - if (s == NGX_ERROR) { - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "invalid size \"%V\"", &val); - return; - } - - sp = (ssize_t *) ((char *) r + data); - - *sp = s; - - return; -} - - static ngx_int_t ngx_http_variable_header(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) @@ -1993,6 +1967,29 @@ ngx_http_variable_sent_transfer_encoding } +static void +ngx_http_variable_set_limit_rate(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + ssize_t s; + ngx_str_t val; + + val.len = v->len; + val.data = v->data; + + s = ngx_parse_size(&val); + + if (s == NGX_ERROR) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "invalid $limit_rate \"%V\"", &val); + return; + } + + r->limit_rate = s; + r->limit_rate_set = 1; +} + + static ngx_int_t ngx_http_variable_request_completion(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) diff -r b82162b8496a -r c19ca381b2e6 src/http/ngx_http_write_filter_module.c --- a/src/http/ngx_http_write_filter_module.c Wed Apr 24 16:38:51 2019 +0300 +++ b/src/http/ngx_http_write_filter_module.c Wed Apr 24 16:38:54 2019 +0300 @@ -250,9 +250,17 @@ ngx_http_write_filter(ngx_http_request_t return NGX_ERROR; } + if (!r->limit_rate_set) { + r->limit_rate = ngx_http_complex_value_size(r, clcf->limit_rate, 0); + r->limit_rate_set = 1; + } + if (r->limit_rate) { - if (r->limit_rate_after == 0) { - r->limit_rate_after = clcf->limit_rate_after; + + if (!r->limit_rate_after_set) { + r->limit_rate_after = ngx_http_complex_value_size(r, + clcf->limit_rate_after, 0); + r->limit_rate_after_set = 1; } limit = (off_t) r->limit_rate * (ngx_time() - r->start_sec + 1) From ru at nginx.com Wed Apr 24 18:47:27 2019 From: ru at nginx.com (Ruslan Ermilov) Date: Wed, 24 Apr 2019 18:47:27 +0000 Subject: [nginx] Variables support in proxy_upload_rate and proxy_download_rate. Message-ID: details: https://hg.nginx.org/nginx/rev/16a1adadf437 branches: changeset: 7505:16a1adadf437 user: Ruslan Ermilov date: Wed Apr 24 16:38:56 2019 +0300 description: Variables support in proxy_upload_rate and proxy_download_rate. diffstat: src/stream/ngx_stream_proxy_module.c | 31 ++++++++++++++++++------------- src/stream/ngx_stream_upstream.h | 3 +++ 2 files changed, 21 insertions(+), 13 deletions(-) diffs (109 lines): diff -r c19ca381b2e6 -r 16a1adadf437 src/stream/ngx_stream_proxy_module.c --- a/src/stream/ngx_stream_proxy_module.c Wed Apr 24 16:38:54 2019 +0300 +++ b/src/stream/ngx_stream_proxy_module.c Wed Apr 24 16:38:56 2019 +0300 @@ -24,8 +24,8 @@ typedef struct { ngx_msec_t timeout; ngx_msec_t next_upstream_timeout; size_t buffer_size; - size_t upload_rate; - size_t download_rate; + ngx_stream_complex_value_t *upload_rate; + ngx_stream_complex_value_t *download_rate; ngx_uint_t requests; ngx_uint_t responses; ngx_uint_t next_upstream_tries; @@ -184,14 +184,14 @@ static ngx_command_t ngx_stream_proxy_c { ngx_string("proxy_upload_rate"), NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_size_slot, + ngx_stream_set_complex_value_size_slot, NGX_STREAM_SRV_CONF_OFFSET, offsetof(ngx_stream_proxy_srv_conf_t, upload_rate), NULL }, { ngx_string("proxy_download_rate"), NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_size_slot, + ngx_stream_set_complex_value_size_slot, NGX_STREAM_SRV_CONF_OFFSET, offsetof(ngx_stream_proxy_srv_conf_t, download_rate), NULL }, @@ -895,6 +895,9 @@ ngx_stream_proxy_init_upstream(ngx_strea u->proxy_protocol = 0; } + u->upload_rate = ngx_stream_complex_value_size(s, pscf->upload_rate, 0); + u->download_rate = ngx_stream_complex_value_size(s, pscf->download_rate, 0); + u->connected = 1; pc->read->handler = ngx_stream_proxy_upstream_handler; @@ -1532,7 +1535,7 @@ ngx_stream_proxy_process(ngx_stream_sess src = pc; dst = c; b = &u->upstream_buf; - limit_rate = pscf->download_rate; + limit_rate = u->download_rate; received = &u->received; packets = &u->responses; out = &u->downstream_out; @@ -1544,7 +1547,7 @@ ngx_stream_proxy_process(ngx_stream_sess src = c; dst = pc; b = &u->downstream_buf; - limit_rate = pscf->upload_rate; + limit_rate = u->upload_rate; received = &s->received; packets = &u->requests; out = &u->upstream_out; @@ -1955,6 +1958,8 @@ ngx_stream_proxy_create_srv_conf(ngx_con * conf->ssl_certificate = { 0, NULL }; * conf->ssl_certificate_key = { 0, NULL }; * + * conf->upload_rate = NULL; + * conf->download_rate = NULL; * conf->ssl = NULL; * conf->upstream = NULL; * conf->upstream_value = NULL; @@ -1964,8 +1969,6 @@ ngx_stream_proxy_create_srv_conf(ngx_con conf->timeout = NGX_CONF_UNSET_MSEC; conf->next_upstream_timeout = NGX_CONF_UNSET_MSEC; conf->buffer_size = NGX_CONF_UNSET_SIZE; - conf->upload_rate = NGX_CONF_UNSET_SIZE; - conf->download_rate = NGX_CONF_UNSET_SIZE; conf->requests = NGX_CONF_UNSET_UINT; conf->responses = NGX_CONF_UNSET_UINT; conf->next_upstream_tries = NGX_CONF_UNSET_UINT; @@ -2005,11 +2008,13 @@ ngx_stream_proxy_merge_srv_conf(ngx_conf ngx_conf_merge_size_value(conf->buffer_size, prev->buffer_size, 16384); - ngx_conf_merge_size_value(conf->upload_rate, - prev->upload_rate, 0); - - ngx_conf_merge_size_value(conf->download_rate, - prev->download_rate, 0); + if (conf->upload_rate == NULL) { + conf->upload_rate = prev->upload_rate; + } + + if (conf->download_rate == NULL) { + conf->download_rate = prev->download_rate; + } ngx_conf_merge_uint_value(conf->requests, prev->requests, 0); diff -r c19ca381b2e6 -r 16a1adadf437 src/stream/ngx_stream_upstream.h --- a/src/stream/ngx_stream_upstream.h Wed Apr 24 16:38:54 2019 +0300 +++ b/src/stream/ngx_stream_upstream.h Wed Apr 24 16:38:56 2019 +0300 @@ -132,6 +132,9 @@ typedef struct { ngx_uint_t responses; ngx_msec_t start_time; + size_t upload_rate; + size_t download_rate; + ngx_str_t ssl_name; ngx_stream_upstream_srv_conf_t *upstream; From xeioex at nginx.com Thu Apr 25 12:19:45 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Thu, 25 Apr 2019 12:19:45 +0000 Subject: [njs] Fixed string object creation using Object() constructor. Message-ID: details: https://hg.nginx.org/njs/rev/e104c8c583c2 branches: changeset: 925:e104c8c583c2 user: Dmitry Volyntsev date: Thu Apr 25 15:19:36 2019 +0300 description: Fixed string object creation using Object() constructor. diffstat: njs/njs_object.c | 9 ++++++++- njs/njs_string.c | 2 -- njs/test/njs_unit_test.c | 3 +++ 3 files changed, 11 insertions(+), 3 deletions(-) diffs (44 lines): diff -r cbb1817c5a39 -r e104c8c583c2 njs/njs_object.c --- a/njs/njs_object.c Wed Apr 24 19:04:23 2019 +0300 +++ b/njs/njs_object.c Thu Apr 25 15:19:36 2019 +0300 @@ -107,7 +107,14 @@ njs_object_value_alloc(njs_vm_t *vm, con if (nxt_fast_path(ov != NULL)) { nxt_lvlhsh_init(&ov->object.hash); - nxt_lvlhsh_init(&ov->object.shared_hash); + + if (type == NJS_STRING) { + ov->object.shared_hash = vm->shared->string_instance_hash; + + } else { + nxt_lvlhsh_init(&ov->object.shared_hash); + } + ov->object.type = njs_object_value_type(type); ov->object.shared = 0; ov->object.extensible = 1; diff -r cbb1817c5a39 -r e104c8c583c2 njs/njs_string.c --- a/njs/njs_string.c Wed Apr 24 19:04:23 2019 +0300 +++ b/njs/njs_string.c Thu Apr 25 15:19:36 2019 +0300 @@ -555,8 +555,6 @@ njs_string_constructor(njs_vm_t *vm, njs return NXT_ERROR; } - object->shared_hash = vm->shared->string_instance_hash; - vm->retval.data.u.object = object; vm->retval.type = NJS_OBJECT_STRING; vm->retval.data.truth = 1; diff -r cbb1817c5a39 -r e104c8c583c2 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Wed Apr 24 19:04:23 2019 +0300 +++ b/njs/test/njs_unit_test.c Thu Apr 25 15:19:36 2019 +0300 @@ -8437,6 +8437,9 @@ static njs_unit_test_t njs_test[] = { nxt_string("new String(123)"), nxt_string("123") }, + { nxt_string("Object('123').length"), + nxt_string("3") }, + { nxt_string("new String(123).length"), nxt_string("3") }, From xeioex at nginx.com Thu Apr 25 12:19:45 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Thu, 25 Apr 2019 12:19:45 +0000 Subject: [njs] Fixed special getters for objects created using Object.create(). Message-ID: details: https://hg.nginx.org/njs/rev/f5bdddca3252 branches: changeset: 926:f5bdddca3252 user: Dmitry Volyntsev date: Thu Apr 25 15:19:37 2019 +0300 description: Fixed special getters for objects created using Object.create(). This closes #124 issue on Github. diffstat: njs/njs_array.c | 15 +++++++++++++-- njs/njs_function.c | 13 ++++++++++++- njs/njs_object.c | 1 - njs/njs_string.c | 23 +++++++++++++++++++---- njs/test/njs_unit_test.c | 12 ++++++++++++ 5 files changed, 56 insertions(+), 8 deletions(-) diffs (124 lines): diff -r e104c8c583c2 -r f5bdddca3252 njs/njs_array.c --- a/njs/njs_array.c Thu Apr 25 15:19:36 2019 +0300 +++ b/njs/njs_array.c Thu Apr 25 15:19:37 2019 +0300 @@ -420,8 +420,19 @@ njs_array_length(njs_vm_t *vm, njs_value njs_ret_t ret; njs_value_t *val; njs_array_t *array; - - array = value->data.u.array; + njs_object_t *proto; + + proto = value->data.u.object; + + do { + if (nxt_fast_path(proto->type == NJS_ARRAY)) { + break; + } + + proto = proto->__proto__; + } while (proto != NULL); + + array = (njs_array_t *) proto; if (setval != NULL) { if (!njs_is_number(setval)) { diff -r e104c8c583c2 -r f5bdddca3252 njs/njs_function.c --- a/njs/njs_function.c Thu Apr 25 15:19:36 2019 +0300 +++ b/njs/njs_function.c Thu Apr 25 15:19:37 2019 +0300 @@ -894,10 +894,21 @@ njs_function_instance_length(njs_vm_t *v njs_value_t *setval, njs_value_t *retval) { nxt_uint_t n; + njs_object_t *proto; njs_function_t *function; njs_function_lambda_t *lambda; - function = value->data.u.function; + proto = value->data.u.object; + + do { + if (nxt_fast_path(proto->type == NJS_FUNCTION)) { + break; + } + + proto = proto->__proto__; + } while (proto != NULL); + + function = (njs_function_t *) proto; if (function->native) { for (n = function->args_offset; n < NJS_ARGS_TYPES_MAX; n++) { diff -r e104c8c583c2 -r f5bdddca3252 njs/njs_object.c --- a/njs/njs_object.c Thu Apr 25 15:19:36 2019 +0300 +++ b/njs/njs_object.c Thu Apr 25 15:19:37 2019 +0300 @@ -283,7 +283,6 @@ njs_object_property(njs_vm_t *vm, const * NXT_ERROR exception has been thrown. * * TODO: - * Object.create([1,2]).length * Object.defineProperty([1,2], '1', {configurable:false}) */ diff -r e104c8c583c2 -r f5bdddca3252 njs/njs_string.c --- a/njs/njs_string.c Thu Apr 25 15:19:36 2019 +0300 +++ b/njs/njs_string.c Thu Apr 25 15:19:37 2019 +0300 @@ -626,8 +626,10 @@ static njs_ret_t njs_string_instance_length(njs_vm_t *vm, njs_value_t *value, njs_value_t *setval, njs_value_t *retval) { - size_t size; - uintptr_t length; + size_t size; + uintptr_t length; + njs_object_t *proto; + njs_object_value_t *ov; /* * This getter can be called for string primitive, String object, @@ -635,8 +637,21 @@ njs_string_instance_length(njs_vm_t *vm, */ length = 0; - if (value->type == NJS_OBJECT_STRING) { - value = &value->data.u.object_value->value; + if (nxt_slow_path(njs_is_object(value))) { + proto = value->data.u.object; + + do { + if (nxt_fast_path(proto->type == NJS_OBJECT_STRING)) { + break; + } + + proto = proto->__proto__; + } while (proto != NULL); + + if (proto != NULL) { + ov = (njs_object_value_t *) proto; + value = &ov->value; + } } if (njs_is_string(value)) { diff -r e104c8c583c2 -r f5bdddca3252 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Thu Apr 25 15:19:36 2019 +0300 +++ b/njs/test/njs_unit_test.c Thu Apr 25 15:19:37 2019 +0300 @@ -9110,6 +9110,18 @@ static njs_unit_test_t njs_test[] = "1..isPrototypeOf(p)"), nxt_string("false") }, + { nxt_string("Object.create(new String('asdf')).length"), + nxt_string("4") }, + + { nxt_string("Object.create(Object('123')).length"), + nxt_string("3") }, + + { nxt_string("Object.create([1,2]).length"), + nxt_string("2") }, + + { nxt_string("Object.create(function(a,b,c){}).length"), + nxt_string("3") }, + { nxt_string("Object.getOwnPropertyDescriptor({a:1}, 'a').value"), nxt_string("1") }, From xeioex at nginx.com Thu Apr 25 12:50:10 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Thu, 25 Apr 2019 12:50:10 +0000 Subject: [njs] Disabling njs_retain() and njs_release(). Message-ID: details: https://hg.nginx.org/njs/rev/793161f2708c branches: changeset: 927:793161f2708c user: Dmitry Volyntsev date: Thu Apr 25 15:50:03 2019 +0300 description: Disabling njs_retain() and njs_release(). Until there is a working GC. diffstat: njs/njs_vm.c | 4 ++-- njs/njs_vm.h | 11 +++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diffs (49 lines): diff -r f5bdddca3252 -r 793161f2708c njs/njs_vm.c --- a/njs/njs_vm.c Thu Apr 25 15:19:37 2019 +0300 +++ b/njs/njs_vm.c Thu Apr 25 15:50:03 2019 +0300 @@ -172,7 +172,7 @@ start: if (vmcode->code.retval) { retval = njs_vmcode_operand(vm, vmcode->operand1); - //njs_release(vm, retval); + njs_release(vm, retval); *retval = vm->retval; } } @@ -2860,7 +2860,7 @@ njs_vmcode_restart(njs_vm_t *vm, njs_val retval = njs_vmcode_operand(vm, vmcode->operand1); - //njs_release(vm, retval); + njs_release(vm, retval); *retval = vm->retval; diff -r f5bdddca3252 -r 793161f2708c njs/njs_vm.h --- a/njs/njs_vm.h Thu Apr 25 15:19:37 2019 +0300 +++ b/njs/njs_vm.h Thu Apr 25 15:50:03 2019 +0300 @@ -562,6 +562,8 @@ typedef njs_ret_t (*njs_vmcode_operation (value)->type = NJS_INVALID +#if 0 /* GC: todo */ + #define njs_retain(value) \ do { \ if ((value)->data.truth == NJS_STRING_LONG) { \ @@ -577,6 +579,15 @@ typedef njs_ret_t (*njs_vmcode_operation } \ } while (0) +#else + +#define njs_retain(value) + + +#define njs_release(vm, value) + +#endif + #define NJS_VMCODE_3OPERANDS 0 #define NJS_VMCODE_2OPERANDS 1 From xeioex at nginx.com Thu Apr 25 16:50:39 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Thu, 25 Apr 2019 16:50:39 +0000 Subject: [njs] Improved text for method frame exception. Message-ID: details: https://hg.nginx.org/njs/rev/65d6076eb349 branches: changeset: 929:65d6076eb349 user: Dmitry Volyntsev date: Thu Apr 25 19:33:35 2019 +0300 description: Improved text for method frame exception. diffstat: njs/njs_vm.c | 3 ++- njs/test/njs_expect_test.exp | 2 +- njs/test/njs_unit_test.c | 9 ++++++--- 3 files changed, 9 insertions(+), 5 deletions(-) diffs (60 lines): diff -r 9ca942bc0792 -r 65d6076eb349 njs/njs_vm.c --- a/njs/njs_vm.c Thu Apr 25 15:56:44 2019 +0300 +++ b/njs/njs_vm.c Thu Apr 25 19:33:35 2019 +0300 @@ -1997,7 +1997,8 @@ njs_vmcode_method_frame(njs_vm_t *vm, nj if (value == NULL || !njs_is_function(value)) { njs_string_get(name, &string); - njs_type_error(vm, "\"%V\" is not a function", &string); + njs_type_error(vm, "(intermediate value)[\"%V\"] is not a function", + &string); return NXT_ERROR; } diff -r 9ca942bc0792 -r 65d6076eb349 njs/test/njs_expect_test.exp --- a/njs/test/njs_expect_test.exp Thu Apr 25 15:56:44 2019 +0300 +++ b/njs/test/njs_expect_test.exp Thu Apr 25 19:33:35 2019 +0300 @@ -224,7 +224,7 @@ njs_test { njs_test { {"console.ll()\r\n" - "console.ll()\r\nTypeError: \"ll\" is not a function"} + "console.ll()\r\nTypeError: (intermediate value)\\\[\"ll\"] is not a function"} } njs_test { diff -r 9ca942bc0792 -r 65d6076eb349 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Thu Apr 25 15:56:44 2019 +0300 +++ b/njs/test/njs_unit_test.c Thu Apr 25 19:33:35 2019 +0300 @@ -1645,6 +1645,9 @@ static njs_unit_test_t njs_test[] = { nxt_string("'-1' < {valueOf: function() {return -2}}"), nxt_string("false") }, + { nxt_string("new 0[isNaN]"), + nxt_string("TypeError: (intermediate value)[\"[object Function]\"] is not a function") }, + /**/ { nxt_string("var a; a = 1 ? 2 : 3"), @@ -5990,7 +5993,7 @@ static njs_unit_test_t njs_test[] = nxt_string("TypeError: number is not a function") }, { nxt_string("var o = {a:1}; o.a()"), - nxt_string("TypeError: \"a\" is not a function") }, + nxt_string("TypeError: (intermediate value)[\"a\"] is not a function") }, { nxt_string("(function(){})()"), nxt_string("undefined") }, @@ -7444,10 +7447,10 @@ static njs_unit_test_t njs_test[] = nxt_string("SyntaxError: Unexpected token \"null\" in 1") }, { nxt_string("'a'.f()"), - nxt_string("TypeError: \"f\" is not a function") }, + nxt_string("TypeError: (intermediate value)[\"f\"] is not a function") }, { nxt_string("1..f()"), - nxt_string("TypeError: \"f\" is not a function") }, + nxt_string("TypeError: (intermediate value)[\"f\"] is not a function") }, { nxt_string("try {}"), nxt_string("SyntaxError: Missing catch or finally after try in 1") }, From xeioex at nginx.com Thu Apr 25 16:50:39 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Thu, 25 Apr 2019 16:50:39 +0000 Subject: [njs] Fixed njs_vmcode_restart(). Message-ID: details: https://hg.nginx.org/njs/rev/9ca942bc0792 branches: changeset: 928:9ca942bc0792 user: hongzhidao date: Thu Apr 25 15:56:44 2019 +0300 description: Fixed njs_vmcode_restart(). diffstat: njs/njs_vm.c | 14 +++++++++----- 1 files changed, 9 insertions(+), 5 deletions(-) diffs (30 lines): diff -r 793161f2708c -r 9ca942bc0792 njs/njs_vm.c --- a/njs/njs_vm.c Thu Apr 25 15:50:03 2019 +0300 +++ b/njs/njs_vm.c Thu Apr 25 15:56:44 2019 +0300 @@ -2852,17 +2852,21 @@ 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_ERROR)) { + return ret; + } + 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); - - *retval = vm->retval; + if (vmcode->code.retval) { + retval = njs_vmcode_operand(vm, vmcode->operand1); + njs_release(vm, retval); + *retval = vm->retval; + } return ret; } From xeioex at nginx.com Thu Apr 25 16:50:40 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Thu, 25 Apr 2019 16:50:40 +0000 Subject: [njs] Fixed Date() constructor with one argument. Message-ID: details: https://hg.nginx.org/njs/rev/43dc900bc914 branches: changeset: 930:43dc900bc914 user: Dmitry Volyntsev date: Thu Apr 25 19:50:20 2019 +0300 description: Fixed Date() constructor with one argument. This closes #144 issue on Github. diffstat: njs/njs_date.c | 64 +++++++++++++++++++++++++++++++---------------- njs/njs_number.c | 2 +- njs/njs_number.h | 1 + njs/njs_vm.c | 53 +++++++++++++++++++++++++++++++++------ njs/njs_vm.h | 1 + njs/test/njs_unit_test.c | 36 +++++++++++++++++++++++++++ 6 files changed, 125 insertions(+), 32 deletions(-) diffs (274 lines): diff -r 65d6076eb349 -r 43dc900bc914 njs/njs_date.c --- a/njs/njs_date.c Thu Apr 25 19:33:35 2019 +0300 +++ b/njs/njs_date.c Thu Apr 25 19:50:20 2019 +0300 @@ -61,6 +61,17 @@ njs_gettime(void) } +static nxt_noinline double +njs_timeclip(double time) +{ + if (isinf(time) || isnan(time) || fabs(time) > 8.64e15) { + return NAN; + } + + return njs_number_to_int64(time); +} + + njs_ret_t njs_date_constructor(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused) @@ -76,8 +87,22 @@ njs_date_constructor(njs_vm_t *vm, njs_v if (nargs == 1) { time = njs_gettime(); - } else if (nargs == 2 && njs_is_string(&args[1])) { - time = njs_date_string_parse(&args[1]); + } else if (nargs == 2) { + if (njs_is_object(&args[1])) { + if (!njs_is_date(&args[1])) { + njs_vm_trap_value(vm, &args[1]); + + return njs_trap(vm, NJS_TRAP_PRIMITIVE_ARG); + } + + time = args[1].data.u.date->time; + + } else if (njs_is_string(&args[1])) { + time = njs_date_string_parse(&args[1]); + + } else { + time = args[1].data.u.number; + } } else { nxt_memzero(values, 8 * sizeof(int64_t)); @@ -103,25 +128,20 @@ njs_date_constructor(njs_vm_t *vm, njs_v values[i] = num; } - if (nargs > 2) { - /* Year. */ - if (values[1] > 99) { - values[1] -= 1900; - } - - tm.tm_year = values[1]; - tm.tm_mon = values[2]; - tm.tm_mday = values[3]; - tm.tm_hour = values[4]; - tm.tm_min = values[5]; - tm.tm_sec = values[6]; - tm.tm_isdst = -1; - - time = (int64_t) mktime(&tm) * 1000 + values[7]; - - } else { - time = values[1]; + /* Year. */ + if (values[1] > 99) { + values[1] -= 1900; } + + tm.tm_year = values[1]; + tm.tm_mon = values[2]; + tm.tm_mday = values[3]; + tm.tm_hour = values[4]; + tm.tm_min = values[5]; + tm.tm_sec = values[6]; + tm.tm_isdst = -1; + + time = (int64_t) mktime(&tm) * 1000 + values[7]; } done: @@ -139,7 +159,7 @@ njs_date_constructor(njs_vm_t *vm, njs_v date->object.extensible = 1; date->object.__proto__ = &vm->prototypes[NJS_PROTOTYPE_DATE].object; - date->time = time; + date->time = njs_timeclip(time); vm->retval.data.u.date = date; vm->retval.type = NJS_DATE; @@ -1048,7 +1068,7 @@ njs_date_to_string(njs_vm_t *vm, njs_val return njs_string_new(vm, retval, buf, p - buf, p - buf); } - vm->retval = njs_string_invalid_date; + *retval = njs_string_invalid_date; return NXT_OK; } diff -r 65d6076eb349 -r 43dc900bc914 njs/njs_number.c --- a/njs/njs_number.c Thu Apr 25 19:33:35 2019 +0300 +++ b/njs/njs_number.c Thu Apr 25 19:50:20 2019 +0300 @@ -804,7 +804,7 @@ njs_number_parse_float(njs_vm_t *vm, njs } -nxt_inline int64_t +int64_t njs_number_to_int64(double num) { #if (NXT_NAN_TO_UINT_CONVERSION != 0) diff -r 65d6076eb349 -r 43dc900bc914 njs/njs_number.h --- a/njs/njs_number.h Thu Apr 25 19:33:35 2019 +0300 +++ b/njs/njs_number.h Thu Apr 25 19:50:20 2019 +0300 @@ -35,6 +35,7 @@ njs_ret_t njs_number_parse_int(njs_vm_t nxt_uint_t nargs, njs_index_t unused); njs_ret_t njs_number_parse_float(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused); +int64_t njs_number_to_int64(double num); nxt_noinline int32_t njs_number_to_integer(double num); nxt_noinline int32_t njs_number_to_int32(double num); nxt_noinline uint32_t njs_number_to_uint32(double num); diff -r 65d6076eb349 -r 43dc900bc914 njs/njs_vm.c --- a/njs/njs_vm.c Thu Apr 25 19:33:35 2019 +0300 +++ b/njs/njs_vm.c Thu Apr 25 19:50:20 2019 +0300 @@ -50,6 +50,8 @@ static njs_ret_t njs_vmcode_number_argum njs_value_t *inlvd2); static njs_ret_t njs_vmcode_string_argument(njs_vm_t *vm, njs_value_t *invld1, njs_value_t *inlvd2); +static njs_ret_t njs_vmcode_primitive_argument(njs_vm_t *vm, + njs_value_t *invld1, njs_value_t *inlvd2); static njs_ret_t njs_primitive_value(njs_vm_t *vm, njs_value_t *value, nxt_uint_t hint); static njs_ret_t njs_vmcode_restart(njs_vm_t *vm, njs_value_t *invld1, @@ -199,6 +201,7 @@ start: case NJS_TRAP_NUMBER_ARG: case NJS_TRAP_STRING_ARG: + case NJS_TRAP_PRIMITIVE_ARG: njs_vm_trap_argument(vm, trap); @@ -2608,16 +2611,24 @@ static const njs_vmcode_1addr_t njs_tra }; +static const njs_vmcode_1addr_t njs_trap_primitive_argument = { + .code = { .operation = njs_vmcode_primitive_argument, + .operands = NJS_VMCODE_NO_OPERAND, + .retval = NJS_VMCODE_NO_RETVAL } +}; + + static const njs_vm_trap_t njs_vm_traps[] = { - /* NJS_TRAP_NUMBER */ { .code = &njs_trap_number[0] }, - /* NJS_TRAP_NUMBERS */ { .code = &njs_trap_numbers[0] }, - /* NJS_TRAP_ADDITION */ { .code = &njs_trap_addition[0] }, - /* NJS_TRAP_COMPARISON */ { .code = &njs_trap_comparison[0] }, - /* NJS_TRAP_INCDEC */ { .code = &njs_trap_numbers[1], - .reference = 1 }, - /* NJS_TRAP_PROPERTY */ { .code = &njs_trap_property[0] }, - /* NJS_TRAP_NUMBER_ARG */ { .code = &njs_trap_number_argument }, - /* NJS_TRAP_STRING_ARG */ { .code = &njs_trap_string_argument }, + /* NJS_TRAP_NUMBER */ { .code = &njs_trap_number[0] }, + /* NJS_TRAP_NUMBERS */ { .code = &njs_trap_numbers[0] }, + /* NJS_TRAP_ADDITION */ { .code = &njs_trap_addition[0] }, + /* NJS_TRAP_COMPARISON */ { .code = &njs_trap_comparison[0] }, + /* NJS_TRAP_INCDEC */ { .code = &njs_trap_numbers[1], + .reference = 1 }, + /* NJS_TRAP_PROPERTY */ { .code = &njs_trap_property[0] }, + /* NJS_TRAP_NUMBER_ARG */ { .code = &njs_trap_number_argument }, + /* NJS_TRAP_STRING_ARG */ { .code = &njs_trap_string_argument }, + /* NJS_TRAP_PRIMITIVE_ARG */ { .code = &njs_trap_primitive_argument }, }; @@ -2831,6 +2842,30 @@ njs_vmcode_string_argument(njs_vm_t *vm, static njs_ret_t +njs_vmcode_primitive_argument(njs_vm_t *vm, njs_value_t *invld1, + njs_value_t *inlvd2) +{ + njs_ret_t ret; + njs_value_t *value; + + value = &vm->top_frame->trap_values[0]; + + ret = njs_primitive_value(vm, value, 0); + + if (nxt_fast_path(ret > 0)) { + *vm->top_frame->trap_values[1].data.u.value = *value; + + vm->current = vm->top_frame->trap_restart; + vm->top_frame->trap_restart = NULL; + + return 0; + } + + return ret; +} + + +static njs_ret_t njs_vmcode_restart(njs_vm_t *vm, njs_value_t *invld1, njs_value_t *invld2) { u_char *restart; diff -r 65d6076eb349 -r 43dc900bc914 njs/njs_vm.h --- a/njs/njs_vm.h Thu Apr 25 19:33:35 2019 +0300 +++ b/njs/njs_vm.h Thu Apr 25 19:50:20 2019 +0300 @@ -47,6 +47,7 @@ typedef enum { NJS_TRAP_PROPERTY, NJS_TRAP_NUMBER_ARG, NJS_TRAP_STRING_ARG, + NJS_TRAP_PRIMITIVE_ARG, } njs_trap_t; diff -r 65d6076eb349 -r 43dc900bc914 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Thu Apr 25 19:33:35 2019 +0300 +++ b/njs/test/njs_unit_test.c Thu Apr 25 19:50:20 2019 +0300 @@ -9563,12 +9563,48 @@ static njs_unit_test_t njs_test[] = { nxt_string("Object.isExtensible(Object.freeze([]))"), nxt_string("false") }, + { nxt_string("new Date(undefined)"), + nxt_string("Invalid Date") }, + + { nxt_string("new Date(Infinity)"), + nxt_string("Invalid Date") }, + + { nxt_string("new Date(NaN)"), + nxt_string("Invalid Date") }, + + { nxt_string("new Date(8.65e15)"), + nxt_string("Invalid Date") }, + + { nxt_string("new Date(0e0.o0)"), + nxt_string("Invalid Date") }, + + { nxt_string("(new Date(8.639e15)).getTime()"), + nxt_string("8639000000000000") }, + + { nxt_string("new Date(8.641e15)"), + nxt_string("Invalid Date") }, + + { nxt_string("(new Date(null)).getTime()"), + nxt_string("0") }, + + { nxt_string("(new Date(86400)).getTime()"), + nxt_string("86400") }, + { nxt_string("var d = new Date(''); d +' '+ d.getTime()"), nxt_string("Invalid Date NaN") }, { nxt_string("var d = new Date(1); d = d + ''; d.slice(0, 33)"), nxt_string("Thu Jan 01 1970 00:00:00 GMT+0000") }, + { nxt_string("var d = new Date({valueOf:()=>86400000}); d = d + ''; d.slice(0, 33)"), + nxt_string("Fri Jan 02 1970 00:00:00 GMT+0000") }, + + { nxt_string("(new Date({toString:()=>'2011'})).getTime()"), + nxt_string("1293840000000") }, + + { nxt_string("(new Date({valueOf: ()=>86400, toString:()=>'2011'})).getTime()"), + nxt_string("86400") }, + { nxt_string("var d = new Date(1308895200000); d.getTime()"), nxt_string("1308895200000") }, From vbart at nginx.com Fri Apr 26 14:59:59 2019 From: vbart at nginx.com (Valentin Bartenev) Date: Fri, 26 Apr 2019 14:59:59 +0000 Subject: [njs] Support for building with GNU Readline library. Message-ID: details: https://hg.nginx.org/njs/rev/760d38110fd9 branches: changeset: 931:760d38110fd9 user: Valentin Bartenev date: Fri Apr 26 17:59:42 2019 +0300 description: Support for building with GNU Readline library. diffstat: auto/editline | 68 --------------------------------------------- auto/expect | 2 +- auto/make | 4 +- auto/readline | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ configure | 2 +- njs/njs_shell.c | 3 ++ 6 files changed, 92 insertions(+), 72 deletions(-) diffs (214 lines): diff -r 43dc900bc914 -r 760d38110fd9 auto/editline --- a/auto/editline Thu Apr 25 19:50:20 2019 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,68 +0,0 @@ -# Copyright (C) Dmitry Volyntsev -# Copyright (C) NGINX, Inc. - - -NXT_EDITLINE_CFLAGS= -NXT_EDITLINE_LIB= - -nxt_found=no - -nxt_feature="editline library in editline/readline.h" -nxt_feature_name=NXT_HAVE_EDITLINE -nxt_feature_run=no -nxt_feature_incs= -nxt_feature_libs="-ledit" -nxt_feature_test="#include - #include - - int main(void) { - add_history(NULL); - return 0; - }" -. auto/feature - -if [ $nxt_found = no ]; then - - # FreeBSD port - - nxt_feature_name=NXT_HAVE_EDIT_READLINE - nxt_feature="editline in edit/readline/readline.h" - nxt_feature_test="#include - #include - - int main(void) { - add_history(NULL); - return 0; - }" - - . auto/feature -fi - -if [ $nxt_found = no ]; then - - # NetBSD - - nxt_feature_name=NXT_HAVE_READLINE - nxt_feature="editline in readline/readline.h" - nxt_feature_test="#include - #include - - int main(void) { - add_history(NULL); - return 0; - }" - . auto/feature -fi - -NXT_DEFAULT_TARGET=libnjs - -if [ $nxt_found = yes ]; then - NXT_HAVE_LIBEDIT=YES - NXT_EDITLINE_CFLAGS=$nxt_feature_incs - NXT_EDITLINE_LIB=$nxt_feature_libs - NXT_DEFAULT_TARGET="$NXT_DEFAULT_TARGET njs" - -else - NXT_HAVE_LIBEDIT=NO - $echo " - building interactive shell is not possible" -fi diff -r 43dc900bc914 -r 760d38110fd9 auto/expect --- a/auto/expect Thu Apr 25 19:50:20 2019 +0300 +++ b/auto/expect Fri Apr 26 17:59:42 2019 +0300 @@ -17,7 +17,7 @@ else $echo " not found" fi -if [ $nxt_found = yes -a $NXT_HAVE_LIBEDIT = YES ]; then +if [ $nxt_found = yes -a $NXT_HAVE_READLINE = YES ]; then cat << END >> $NXT_MAKEFILE njs_expect_test: njs njs/test/njs_expect_test.exp diff -r 43dc900bc914 -r 760d38110fd9 auto/make --- a/auto/make Thu Apr 25 19:50:20 2019 +0300 +++ b/auto/make Fri Apr 26 17:59:42 2019 +0300 @@ -178,10 +178,10 @@ cat << END >> $NXT_MAKEFILE njs/njs_shell.c \$(NXT_CC) -o $NXT_BUILD_DIR/njs \$(NXT_CFLAGS) \\ $NXT_LIB_AUX_CFLAGS \$(NXT_LIB_INCS) \\ - $NXT_EDITLINE_CFLAGS -Injs \\ + $NXT_READLINE_CFLAGS -Injs \\ njs/njs_shell.c \\ $NXT_BUILD_DIR/libnjs.a \\ - -lm $NXT_LIBS $NXT_LIB_AUX_LIBS $NXT_EDITLINE_LIB + -lm $NXT_LIBS $NXT_LIB_AUX_LIBS $NXT_READLINE_LIB END diff -r 43dc900bc914 -r 760d38110fd9 auto/readline --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/auto/readline Fri Apr 26 17:59:42 2019 +0300 @@ -0,0 +1,85 @@ +# Copyright (C) Dmitry Volyntsev +# Copyright (C) NGINX, Inc. + + +NXT_READLINE_CFLAGS= +NXT_READLINE_LIB= + +nxt_found=no + +nxt_feature="GNU readline library" +nxt_feature_name=NXT_HAVE_GNU_READLINE +nxt_feature_run=no +nxt_feature_incs= +nxt_feature_libs="-lreadline" +nxt_feature_test="#include + #include + #include + + int main(void) { + add_history(NULL); + return 0; + }" +. auto/feature + +if [ $nxt_found = no ]; then + nxt_feature="editline library in editline/readline.h" + nxt_feature_name=NXT_HAVE_EDITLINE + nxt_feature_libs="-ledit" + nxt_feature_test="#include + #include + + int main(void) { + add_history(NULL); + return 0; + }" + . auto/feature +fi + +if [ $nxt_found = no ]; then + + # FreeBSD port + + nxt_feature_name=NXT_HAVE_EDIT_READLINE + nxt_feature="editline in edit/readline/readline.h" + nxt_feature_test="#include + #include + + int main(void) { + add_history(NULL); + return 0; + }" + + . auto/feature +fi + +if [ $nxt_found = no ]; then + + # NetBSD + + nxt_feature_name=NXT_HAVE_NETBSD_READLINE + nxt_feature="editline in readline/readline.h" + nxt_feature_test="#include + #include + + int main(void) { + add_history(NULL); + return 0; + }" + . auto/feature +fi + + + +NXT_DEFAULT_TARGET=libnjs + +if [ $nxt_found = yes ]; then + NXT_HAVE_READLINE=YES + NXT_READLINE_CFLAGS=$nxt_feature_incs + NXT_READLINE_LIB=$nxt_feature_libs + NXT_DEFAULT_TARGET="$NXT_DEFAULT_TARGET njs" + +else + NXT_HAVE_READLINE=NO + $echo " - building interactive shell is not possible" +fi diff -r 43dc900bc914 -r 760d38110fd9 configure --- a/configure Thu Apr 25 19:50:20 2019 +0300 +++ b/configure Fri Apr 26 17:59:42 2019 +0300 @@ -52,7 +52,7 @@ NXT_LIBRT= . auto/getrandom . auto/explicit_bzero . auto/pcre -. auto/editline +. auto/readline . auto/sources NXT_LIB_AUX_CFLAGS="$NXT_PCRE_CFLAGS" diff -r 43dc900bc914 -r 760d38110fd9 njs/njs_shell.c --- a/njs/njs_shell.c Thu Apr 25 19:50:20 2019 +0300 +++ b/njs/njs_shell.c Fri Apr 26 17:59:42 2019 +0300 @@ -23,6 +23,9 @@ #include #else #include +#if (NXT_HAVE_GNU_READLINE) +#include +#endif #endif From vbart at nginx.com Fri Apr 26 16:31:41 2019 From: vbart at nginx.com (Valentin Bartenev) Date: Fri, 26 Apr 2019 16:31:41 +0000 Subject: [njs] Removed NXT_READLINE_CFLAGS. Message-ID: details: https://hg.nginx.org/njs/rev/60e98e247a53 branches: changeset: 932:60e98e247a53 user: Valentin Bartenev date: Fri Apr 26 19:30:43 2019 +0300 description: Removed NXT_READLINE_CFLAGS. It's not needed after 61f2616e21c7. diffstat: auto/make | 3 +-- auto/readline | 4 ---- 2 files changed, 1 insertions(+), 6 deletions(-) diffs (38 lines): diff -r 760d38110fd9 -r 60e98e247a53 auto/make --- a/auto/make Fri Apr 26 17:59:42 2019 +0300 +++ b/auto/make Fri Apr 26 19:30:43 2019 +0300 @@ -177,8 +177,7 @@ cat << END >> $NXT_MAKEFILE $NXT_BUILD_DIR/libnjs.a \\ njs/njs_shell.c \$(NXT_CC) -o $NXT_BUILD_DIR/njs \$(NXT_CFLAGS) \\ - $NXT_LIB_AUX_CFLAGS \$(NXT_LIB_INCS) \\ - $NXT_READLINE_CFLAGS -Injs \\ + $NXT_LIB_AUX_CFLAGS \$(NXT_LIB_INCS) -Injs \\ njs/njs_shell.c \\ $NXT_BUILD_DIR/libnjs.a \\ -lm $NXT_LIBS $NXT_LIB_AUX_LIBS $NXT_READLINE_LIB diff -r 760d38110fd9 -r 60e98e247a53 auto/readline --- a/auto/readline Fri Apr 26 17:59:42 2019 +0300 +++ b/auto/readline Fri Apr 26 19:30:43 2019 +0300 @@ -2,7 +2,6 @@ # Copyright (C) NGINX, Inc. -NXT_READLINE_CFLAGS= NXT_READLINE_LIB= nxt_found=no @@ -69,13 +68,10 @@ if [ $nxt_found = no ]; then . auto/feature fi - - NXT_DEFAULT_TARGET=libnjs if [ $nxt_found = yes ]; then NXT_HAVE_READLINE=YES - NXT_READLINE_CFLAGS=$nxt_feature_incs NXT_READLINE_LIB=$nxt_feature_libs NXT_DEFAULT_TARGET="$NXT_DEFAULT_TARGET njs" From jung.jinki at gmail.com Sat Apr 27 08:09:28 2019 From: jung.jinki at gmail.com (jung.jinki at gmail.com) Date: Sat, 27 Apr 2019 17:09:28 +0900 Subject: source download from trac Message-ID: <0c18408d-4057-7e2e-7ca6-e657bed4c5df@gmail.com> Hello Nginx.devel I am pleased to join this group of wonderful software. I am trying to build from source for my mac partially study purpose. Due to unfamiliarity of trac, I am still struggling to find the way to download source. It would be appreciated if anyone give me howto. Regards, jung.jinki at gmail.com From xeioex at nginx.com Sat Apr 27 14:32:39 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Sat, 27 Apr 2019 14:32:39 +0000 Subject: [njs] Improved njs_function_native_call(). Message-ID: details: https://hg.nginx.org/njs/rev/b9becf29a21d branches: changeset: 933:b9becf29a21d user: hongzhidao date: Fri Apr 26 19:57:54 2019 +0800 description: Improved njs_function_native_call(). diffstat: njs/njs_function.c | 4 +++- njs/njs_function.h | 2 +- njs/njs_vm.c | 33 ++++++--------------------------- 3 files changed, 10 insertions(+), 29 deletions(-) diffs (99 lines): diff -r 60e98e247a53 -r b9becf29a21d njs/njs_function.c --- a/njs/njs_function.c Fri Apr 26 19:30:43 2019 +0300 +++ b/njs/njs_function.c Fri Apr 26 19:57:54 2019 +0800 @@ -566,7 +566,7 @@ njs_function_lambda_call(njs_vm_t *vm, n njs_ret_t njs_function_native_call(njs_vm_t *vm, njs_function_native_t native, njs_value_t *args, uint8_t *args_types, nxt_uint_t nargs, - njs_index_t retval) + njs_index_t retval, u_char *return_address) { njs_ret_t ret; njs_value_t *value; @@ -617,6 +617,8 @@ njs_function_native_call(njs_vm_t *vm, n *value = vm->retval; } + vm->current = return_address; + njs_function_frame_free(vm, frame); return NXT_OK; diff -r 60e98e247a53 -r b9becf29a21d njs/njs_function.h --- a/njs/njs_function.h Fri Apr 26 19:30:43 2019 +0300 +++ b/njs/njs_function.h Fri Apr 26 19:57:54 2019 +0800 @@ -173,7 +173,7 @@ njs_ret_t njs_function_lambda_call(njs_v u_char *return_address); njs_ret_t njs_function_native_call(njs_vm_t *vm, njs_function_native_t native, njs_value_t *args, uint8_t *args_types, nxt_uint_t nargs, - njs_index_t retval); + njs_index_t retval, u_char *return_address); void njs_function_frame_free(njs_vm_t *vm, njs_native_frame_t *frame); diff -r 60e98e247a53 -r b9becf29a21d njs/njs_vm.c --- a/njs/njs_vm.c Fri Apr 26 19:30:43 2019 +0300 +++ b/njs/njs_vm.c Fri Apr 26 19:57:54 2019 +0800 @@ -2047,7 +2047,8 @@ njs_vmcode_function_call(njs_vm_t *vm, n ret = njs_function_native_call(vm, function->u.native, frame->arguments, function->args_types, frame->nargs, - (njs_index_t) retval); + (njs_index_t) retval, + return_address); } } else { @@ -2055,16 +2056,7 @@ njs_vmcode_function_call(njs_vm_t *vm, n return_address); } - switch (ret) { - case NXT_OK: - return sizeof(njs_vmcode_function_call_t); - - case NJS_APPLIED: - return 0; - - default: - return ret; - } + return (ret == NJS_APPLIED) ? 0 : ret; } @@ -2292,31 +2284,18 @@ const njs_vmcode_generic_t njs_continua static njs_ret_t njs_vmcode_continuation(njs_vm_t *vm, njs_value_t *invld1, njs_value_t *invld2) { - u_char *return_address; njs_ret_t ret; njs_native_frame_t *frame; njs_continuation_t *cont; frame = vm->top_frame; - cont = njs_vm_continuation(vm); - return_address = cont->return_address; ret = njs_function_native_call(vm, cont->function, frame->arguments, cont->args_types, frame->nargs, - cont->retval); - - switch (ret) { - case NXT_OK: - vm->current = return_address; - /* Fall through. */ - - case NJS_APPLIED: - return 0; - - default: - return ret; - } + cont->retval, cont->return_address); + + return (ret == NJS_APPLIED) ? 0 : ret; } From xeioex at nginx.com Sat Apr 27 14:32:40 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Sat, 27 Apr 2019 14:32:40 +0000 Subject: [njs] Improved njs_vm_continuation(). Message-ID: details: https://hg.nginx.org/njs/rev/28c972d5416d branches: changeset: 934:28c972d5416d user: hongzhidao date: Fri Apr 26 21:30:04 2019 +0800 description: Improved njs_vm_continuation(). This closes #142 issue on Github. diffstat: njs/njs_function.c | 13 ++++++++++++- njs/njs_function.h | 7 +++---- njs/test/njs_unit_test.c | 18 ++++++++++++++++++ 3 files changed, 33 insertions(+), 5 deletions(-) diffs (89 lines): diff -r b9becf29a21d -r 28c972d5416d njs/njs_function.c --- a/njs/njs_function.c Fri Apr 26 19:57:54 2019 +0800 +++ b/njs/njs_function.c Fri Apr 26 21:30:04 2019 +0800 @@ -294,6 +294,7 @@ njs_function_native_frame(njs_vm_t *vm, size_t continuation_size, nxt_bool_t ctor) { size_t size; + u_char *continuation; nxt_uint_t n; njs_value_t *value, *bound; njs_native_frame_t *frame; @@ -312,7 +313,13 @@ njs_function_native_frame(njs_vm_t *vm, frame->nargs = function->args_offset + nargs; frame->ctor = ctor; - value = (njs_value_t *) (njs_continuation(frame) + continuation_size); + continuation = (u_char *) frame + NJS_NATIVE_FRAME_SIZE; + + if (continuation_size > 0) { + frame->continuation = (njs_continuation_t *) continuation; + } + + value = (njs_value_t *) (continuation + continuation_size); frame->arguments = value; bound = function->bound; @@ -770,6 +777,10 @@ njs_function_frame_free(njs_vm_t *vm, nj do { previous = frame->previous; + if (frame->continuation != NULL) { + vm->current = frame->continuation->return_address; + } + /* GC: free frame->local, etc. */ if (frame->size != 0) { diff -r b9becf29a21d -r 28c972d5416d njs/njs_function.h --- a/njs/njs_function.h Fri Apr 26 19:57:54 2019 +0800 +++ b/njs/njs_function.h Fri Apr 26 21:30:04 2019 +0800 @@ -66,10 +66,7 @@ typedef struct { #define njs_vm_continuation(vm) \ - (void *) njs_continuation((vm)->top_frame) - -#define njs_continuation(frame) \ - ((u_char *) frame + NJS_NATIVE_FRAME_SIZE) + (void *) ((vm)->top_frame->continuation) #define njs_continuation_size(size) \ nxt_align_size(sizeof(size), sizeof(njs_value_t)) @@ -104,6 +101,8 @@ struct njs_native_frame_s { njs_function_t *function; njs_native_frame_t *previous; + njs_continuation_t *continuation; + njs_value_t *arguments; njs_object_t *arguments_object; diff -r b9becf29a21d -r 28c972d5416d njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Fri Apr 26 19:57:54 2019 +0800 +++ b/njs/test/njs_unit_test.c Fri Apr 26 21:30:04 2019 +0800 @@ -6039,6 +6039,24 @@ static njs_unit_test_t njs_test[] = { nxt_string("function f (x){ return x**2}; f(2\n)"), nxt_string("4") }, + { nxt_string("var fn = Function.prototype.call; fn.call(() => 1)"), + nxt_string("1") }, + + { nxt_string("var fn = Function.prototype.call; fn.call(fn, () => 1)"), + nxt_string("1") }, + + { nxt_string("var fn = Function.prototype.call; fn.call(fn, fn, () => 1)"), + nxt_string("1") }, + + { nxt_string("eval.call.call(Number)"), + nxt_string("0") }, + + { nxt_string("URIError.apply.apply(RegExp)"), + nxt_string("/(?:)/") }, + + { nxt_string("[0].some(function(){return Array.call.bind(isNaN)}())"), + nxt_string("false") }, + /* Recursive factorial. */ { nxt_string("function f(a) {" From al-nginx at none.at Sat Apr 27 16:09:04 2019 From: al-nginx at none.at (Aleksandar Lazic) Date: Sat, 27 Apr 2019 18:09:04 +0200 Subject: source download from trac In-Reply-To: <0c18408d-4057-7e2e-7ca6-e657bed4c5df@gmail.com> References: <0c18408d-4057-7e2e-7ca6-e657bed4c5df@gmail.com> Message-ID: Ho. Am 27.04.2019 um 10:09 schrieb jung.jinki at gmail.com: > Hello Nginx.devel > > I am pleased to join this group of wonderful software. > > I am trying to build from source for my mac partially study purpose. > > Due to unfamiliarity of trac, I am still struggling to find the way to > > download source. > > It would be appreciated if anyone give me howto. You can find the source here. https://nginx.org/en/download.html The doc how to build it is here. https://nginx.org/en/docs/configure.html In gernerall is the link https://nginx.org/en/docs/ a good start point for new nginx users, IMHO. > Regards, > > > jung.jinki at gmail.com Regards Aleks From xeioex at nginx.com Sat Apr 27 17:45:07 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Sat, 27 Apr 2019 17:45:07 +0000 Subject: [njs] Fixed null pointer dereferences introduced in f5bdddca3252. Message-ID: details: https://hg.nginx.org/njs/rev/277845bea37a branches: changeset: 935:277845bea37a user: Dmitry Volyntsev date: Sat Apr 27 20:28:37 2019 +0300 description: Fixed null pointer dereferences introduced in f5bdddca3252. CID 1444775, CID 1444776. diffstat: njs/njs_array.c | 5 +++++ njs/njs_function.c | 5 +++++ 2 files changed, 10 insertions(+), 0 deletions(-) diffs (30 lines): diff -r 28c972d5416d -r 277845bea37a njs/njs_array.c --- a/njs/njs_array.c Fri Apr 26 21:30:04 2019 +0800 +++ b/njs/njs_array.c Sat Apr 27 20:28:37 2019 +0300 @@ -432,6 +432,11 @@ njs_array_length(njs_vm_t *vm, njs_value proto = proto->__proto__; } while (proto != NULL); + if (nxt_slow_path(proto == NULL)) { + njs_internal_error(vm, "no array in proto chain"); + return NJS_ERROR; + } + array = (njs_array_t *) proto; if (setval != NULL) { diff -r 28c972d5416d -r 277845bea37a njs/njs_function.c --- a/njs/njs_function.c Fri Apr 26 21:30:04 2019 +0800 +++ b/njs/njs_function.c Sat Apr 27 20:28:37 2019 +0300 @@ -921,6 +921,11 @@ njs_function_instance_length(njs_vm_t *v proto = proto->__proto__; } while (proto != NULL); + if (nxt_slow_path(proto == NULL)) { + njs_internal_error(vm, "no function in proto chain"); + return NJS_ERROR; + } + function = (njs_function_t *) proto; if (function->native) { From xeioex at nginx.com Sat Apr 27 17:45:08 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Sat, 27 Apr 2019 17:45:08 +0000 Subject: [njs] Improved njs_lexer_rollback(). Message-ID: details: https://hg.nginx.org/njs/rev/2f1f71863953 branches: changeset: 936:2f1f71863953 user: hongzhidao date: Sat Apr 27 09:04:24 2019 +0800 description: Improved njs_lexer_rollback(). diffstat: njs/njs_lexer.c | 14 ++++++++------ njs/njs_lexer.h | 1 - njs/test/njs_unit_test.c | 6 ++++++ 3 files changed, 14 insertions(+), 7 deletions(-) diffs (58 lines): diff -r 277845bea37a -r 2f1f71863953 njs/njs_lexer.c --- a/njs/njs_lexer.c Sat Apr 27 20:28:37 2019 +0300 +++ b/njs/njs_lexer.c Sat Apr 27 09:04:24 2019 +0800 @@ -307,11 +307,6 @@ njs_lexer_token(njs_vm_t *vm, njs_lexer_ lexer->prev_start = lexer->start; - if (lexer->lexer_token != NULL) { - lexer->prev_token = lexer->lexer_token->token; - nxt_mp_free(vm->mem_pool, lexer->lexer_token); - } - if (nxt_queue_is_empty(&lexer->preread)) { lt = njs_lexer_token_push(vm, lexer); if (nxt_slow_path(lt == NULL)) { @@ -319,7 +314,14 @@ njs_lexer_token(njs_vm_t *vm, njs_lexer_ } } - lexer->lexer_token = njs_lexer_token_pop(lexer); + lt = njs_lexer_token_pop(lexer); + + if (lexer->lexer_token != NULL && lexer->lexer_token != lt) { + lexer->prev_token = lexer->lexer_token->token; + nxt_mp_free(vm->mem_pool, lexer->lexer_token); + } + + lexer->lexer_token = lt; return njs_lexer_token_name_resolve(lexer, lexer->lexer_token); } diff -r 277845bea37a -r 2f1f71863953 njs/njs_lexer.h --- a/njs/njs_lexer.h Sat Apr 27 20:28:37 2019 +0300 +++ b/njs/njs_lexer.h Sat Apr 27 09:04:24 2019 +0800 @@ -264,7 +264,6 @@ void njs_lexer_keyword(njs_lexer_t *lexe #define njs_lexer_rollback(lexer) \ do { \ nxt_queue_insert_head(&(lexer)->preread, &(lexer)->lexer_token->link); \ - (lexer)->lexer_token = NULL; \ } while (0) diff -r 277845bea37a -r 2f1f71863953 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Sat Apr 27 20:28:37 2019 +0300 +++ b/njs/test/njs_unit_test.c Sat Apr 27 09:04:24 2019 +0800 @@ -2157,6 +2157,12 @@ static njs_unit_test_t njs_test[] = /* automatic semicolon insertion. */ + { nxt_string("(a\n--"), + nxt_string("SyntaxError: Unexpected token \"--\" in 2") }, + + { nxt_string("(a\n++"), + nxt_string("SyntaxError: Unexpected token \"++\" in 2") }, + { nxt_string("var x = 0, y = 2; x\n--\ny; [x,y]"), nxt_string("0,1") }, From xeioex at nginx.com Sun Apr 28 12:17:17 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Sun, 28 Apr 2019 12:17:17 +0000 Subject: [njs] Added extra tests for assignment expression. Message-ID: details: https://hg.nginx.org/njs/rev/9753a6388cb3 branches: changeset: 937:9753a6388cb3 user: Dmitry Volyntsev date: Sun Apr 28 14:56:33 2019 +0300 description: Added extra tests for assignment expression. This closes #52 issue on Github. diffstat: njs/test/njs_unit_test.c | 8 ++++++++ 1 files changed, 8 insertions(+), 0 deletions(-) diffs (18 lines): diff -r 2f1f71863953 -r 9753a6388cb3 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Sat Apr 27 09:04:24 2019 +0800 +++ b/njs/test/njs_unit_test.c Sun Apr 28 14:56:33 2019 +0300 @@ -4975,6 +4975,14 @@ static njs_unit_test_t njs_test[] = " valueOf: function() { return 1 } }; a"), nxt_string("1") }, + { nxt_string("var a = { toString: function() { return [] }," + " valueOf: function() { return 1 } };" + "var o = {}; o[a] = 'test'"), + nxt_string("test") }, + + { nxt_string("({})[{}] = 'test'"), + nxt_string("test") }, + { nxt_string("var o = {b:$r.props.b}; o.b"), nxt_string("42") }, From xeioex at nginx.com Mon Apr 29 13:13:08 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Mon, 29 Apr 2019 13:13:08 +0000 Subject: [njs] Simplified parsing of var statements. Message-ID: details: https://hg.nginx.org/njs/rev/601a52c421d1 branches: changeset: 939:601a52c421d1 user: hongzhidao date: Mon Apr 29 15:57:36 2019 +0300 description: Simplified parsing of var statements. diffstat: njs/njs_parser.c | 37 +++++++++++++------------------------ njs/njs_variable.c | 28 +++++++++++++++++++++------- 2 files changed, 34 insertions(+), 31 deletions(-) diffs (144 lines): diff -r 8f9f3d1e454e -r 601a52c421d1 njs/njs_parser.c --- a/njs/njs_parser.c Mon Apr 29 13:31:16 2019 +0800 +++ b/njs/njs_parser.c Mon Apr 29 15:57:36 2019 +0300 @@ -38,7 +38,7 @@ static njs_parser_node_t *njs_parser_ret static njs_token_t njs_parser_return_statement(njs_vm_t *vm, njs_parser_t *parser); static njs_token_t njs_parser_var_statement(njs_vm_t *vm, njs_parser_t *parser, - nxt_bool_t var_in); + njs_token_t parent, nxt_bool_t var_in); static njs_token_t njs_parser_if_statement(njs_vm_t *vm, njs_parser_t *parser); static njs_token_t njs_parser_switch_statement(njs_vm_t *vm, njs_parser_t *parser); @@ -377,7 +377,7 @@ njs_parser_statement(njs_vm_t *vm, njs_p switch (token) { case NJS_TOKEN_VAR: - token = njs_parser_var_statement(vm, parser, 0); + token = njs_parser_var_statement(vm, parser, token, 0); break; case NJS_TOKEN_RETURN: @@ -490,28 +490,13 @@ njs_parser_block_statement(njs_vm_t *vm, static njs_token_t njs_parser_block(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token) { - njs_parser_node_t *node; - if (token == NJS_TOKEN_FUNCTION) { njs_parser_syntax_error(vm, parser, "Functions can only be declared at top level or inside a block"); return NJS_TOKEN_ILLEGAL; } - token = njs_parser_statement(vm, parser, token); - if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { - return token; - } - - node = parser->node; - - if (node != NULL && node->token == NJS_TOKEN_BLOCK) { - parser->node = node->left; - - nxt_mp_free(vm->mem_pool, node); - } - - return token; + return njs_parser_statement(vm, parser, token); } @@ -1051,10 +1036,14 @@ njs_parser_return_statement(njs_vm_t *vm static njs_token_t -njs_parser_var_statement(njs_vm_t *vm, njs_parser_t *parser, nxt_bool_t var_in) +njs_parser_var_statement(njs_vm_t *vm, njs_parser_t *parser, njs_token_t parent, + nxt_bool_t var_in) { - njs_token_t token; - njs_parser_node_t *left, *stmt, *name, *assign, *expr; + njs_token_t token; + njs_parser_node_t *left, *stmt, *name, *assign, *expr; + njs_variable_type_t type; + + type = NJS_VARIABLE_VAR; parser->node = NULL; left = NULL; @@ -1080,7 +1069,7 @@ njs_parser_var_statement(njs_vm_t *vm, n name = njs_parser_variable_node(vm, parser, njs_parser_text(parser), njs_parser_key_hash(parser), - NJS_VARIABLE_VAR); + type); if (nxt_slow_path(name == NULL)) { return NJS_TOKEN_ERROR; } @@ -1111,7 +1100,7 @@ njs_parser_var_statement(njs_vm_t *vm, n expr = parser->node; } - assign = njs_parser_node_new(vm, parser, NJS_TOKEN_VAR); + assign = njs_parser_node_new(vm, parser, parent); if (nxt_slow_path(assign == NULL)) { return NJS_TOKEN_ERROR; } @@ -1400,7 +1389,7 @@ njs_parser_for_statement(njs_vm_t *vm, n if (token == NJS_TOKEN_VAR) { - token = njs_parser_var_statement(vm, parser, 1); + token = njs_parser_var_statement(vm, parser, token, 1); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { return token; } diff -r 8f9f3d1e454e -r 601a52c421d1 njs/njs_variable.c --- a/njs/njs_variable.c Mon Apr 29 13:31:16 2019 +0800 +++ b/njs/njs_variable.c Mon Apr 29 15:57:36 2019 +0300 @@ -91,16 +91,23 @@ njs_variable_scope_add(njs_vm_t *vm, njs if (nxt_lvlhsh_find(&scope->variables, lhq) == NXT_OK) { var = lhq->value; - if (scope->module || scope->type == NJS_SCOPE_BLOCK - || (scope->type == NJS_SCOPE_GLOBAL && vm->options.module)) - { + if (scope->module || scope->type == NJS_SCOPE_BLOCK) { + if (type == NJS_VARIABLE_FUNCTION || var->type == NJS_VARIABLE_FUNCTION) { - njs_parser_syntax_error(vm, vm->parser, - "\"%V\" has already been declared", - &lhq->key); - return NULL; + goto fail; + } + } + + if (scope->type == NJS_SCOPE_GLOBAL) { + + if (vm->options.module) { + if (type == NJS_VARIABLE_FUNCTION + || var->type == NJS_VARIABLE_FUNCTION) + { + goto fail; + } } } @@ -128,6 +135,13 @@ njs_variable_scope_add(njs_vm_t *vm, njs njs_type_error(vm, "lvlhsh insert failed"); return NULL; + +fail: + + njs_parser_syntax_error(vm, vm->parser, + "\"%V\" has already been declared", + &lhq->key); + return NULL; } From xeioex at nginx.com Mon Apr 29 13:13:07 2019 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Mon, 29 Apr 2019 13:13:07 +0000 Subject: [njs] Making njs_lexer_rollback() more generic. Message-ID: details: https://hg.nginx.org/njs/rev/8f9f3d1e454e branches: changeset: 938:8f9f3d1e454e user: hongzhidao date: Mon Apr 29 13:31:16 2019 +0800 description: Making njs_lexer_rollback() more generic. diffstat: njs/njs_lexer.c | 32 ++++++++++++++++++++++++-------- njs/njs_lexer.h | 6 +----- njs/njs_parser_expression.c | 7 ++++++- 3 files changed, 31 insertions(+), 14 deletions(-) diffs (98 lines): diff -r 9753a6388cb3 -r 8f9f3d1e454e njs/njs_lexer.c --- a/njs/njs_lexer.c Sun Apr 28 14:56:33 2019 +0300 +++ b/njs/njs_lexer.c Mon Apr 29 13:31:16 2019 +0800 @@ -307,6 +307,11 @@ njs_lexer_token(njs_vm_t *vm, njs_lexer_ lexer->prev_start = lexer->start; + if (lexer->lexer_token != NULL) { + lexer->prev_token = lexer->lexer_token->token; + nxt_mp_free(vm->mem_pool, lexer->lexer_token); + } + if (nxt_queue_is_empty(&lexer->preread)) { lt = njs_lexer_token_push(vm, lexer); if (nxt_slow_path(lt == NULL)) { @@ -314,14 +319,7 @@ njs_lexer_token(njs_vm_t *vm, njs_lexer_ } } - lt = njs_lexer_token_pop(lexer); - - if (lexer->lexer_token != NULL && lexer->lexer_token != lt) { - lexer->prev_token = lexer->lexer_token->token; - nxt_mp_free(vm->mem_pool, lexer->lexer_token); - } - - lexer->lexer_token = lt; + lexer->lexer_token = njs_lexer_token_pop(lexer); return njs_lexer_token_name_resolve(lexer, lexer->lexer_token); } @@ -399,6 +397,24 @@ njs_lexer_token_pop(njs_lexer_t *lexer) } +nxt_int_t +njs_lexer_rollback(njs_vm_t *vm, njs_lexer_t *lexer) +{ + njs_lexer_token_t *lt; + + lt = nxt_mp_zalloc(vm->mem_pool, sizeof(njs_lexer_token_t)); + if (nxt_slow_path(lt == NULL)) { + return NXT_ERROR; + } + + *lt = *lexer->lexer_token; + + nxt_queue_insert_head(&lexer->preread, <->link); + + return NXT_OK; +} + + static njs_token_t njs_lexer_token_name_resolve(njs_lexer_t *lexer, njs_lexer_token_t *lt) { diff -r 9753a6388cb3 -r 8f9f3d1e454e njs/njs_lexer.h --- a/njs/njs_lexer.h Sun Apr 28 14:56:33 2019 +0300 +++ b/njs/njs_lexer.h Mon Apr 29 13:31:16 2019 +0800 @@ -258,13 +258,9 @@ nxt_int_t njs_lexer_init(njs_vm_t *vm, n njs_token_t njs_lexer_token(njs_vm_t *vm, njs_lexer_t *lexer); njs_token_t njs_lexer_peek_token(njs_vm_t *vm, njs_lexer_t *lexer, size_t offset); +nxt_int_t njs_lexer_rollback(njs_vm_t *vm, njs_lexer_t *lexer); nxt_int_t njs_lexer_keywords_init(nxt_mp_t *mp, nxt_lvlhsh_t *hash); void njs_lexer_keyword(njs_lexer_t *lexer, njs_lexer_token_t *lt); -#define njs_lexer_rollback(lexer) \ - do { \ - nxt_queue_insert_head(&(lexer)->preread, &(lexer)->lexer_token->link); \ - } while (0) - #endif /* _NJS_LEXER_H_INCLUDED_ */ diff -r 9753a6388cb3 -r 8f9f3d1e454e njs/njs_parser_expression.c --- a/njs/njs_parser_expression.c Sun Apr 28 14:56:33 2019 +0300 +++ b/njs/njs_parser_expression.c Mon Apr 29 13:31:16 2019 +0800 @@ -682,6 +682,7 @@ static njs_token_t njs_parser_post_inc_dec_expression(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token) { + nxt_int_t ret; njs_parser_node_t *node; njs_vmcode_operation_t operation; @@ -709,7 +710,11 @@ njs_parser_post_inc_dec_expression(njs_v /* Automatic semicolon insertion. */ if (parser->lexer->prev_token == NJS_TOKEN_LINE_END) { - njs_lexer_rollback(parser->lexer); + ret = njs_lexer_rollback(vm, parser->lexer); + if (nxt_slow_path(ret != NXT_OK)) { + return NJS_TOKEN_ERROR; + } + return NJS_TOKEN_SEMICOLON; } From junghoon.seo.dev at gmail.com Tue Apr 30 07:16:29 2019 From: junghoon.seo.dev at gmail.com (=?UTF-8?B?7ISc7KCV7ZuI?=) Date: Tue, 30 Apr 2019 16:16:29 +0900 Subject: user-agent parsing issue (IE11, windows10) Message-ID: Hi. The user-agent of ie11 running on windows10 can not be parsed by "MSIE". This causes headers_in.msie to remain zero. source code location: https://github.com/nginx/nginx/blob/master/src/http/ngx_http_request.c#L1823 When I checked it, I found that it was possible to parse it with "rv:11.0". Is there any reason not to patch this? thanks. -------------- next part -------------- An HTML attachment was scrubbed... URL: From mdounin at mdounin.ru Tue Apr 30 15:09:52 2019 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 30 Apr 2019 18:09:52 +0300 Subject: user-agent parsing issue (IE11, windows10) In-Reply-To: References: Message-ID: <20190430150952.GX1877@mdounin.ru> Hello! On Tue, Apr 30, 2019 at 04:16:29PM +0900, ??? wrote: > Hi. > > The user-agent of ie11 running on windows10 can not be parsed by "MSIE". > > This causes headers_in.msie to remain zero. > > source code location: > https://github.com/nginx/nginx/blob/master/src/http/ngx_http_request.c#L1823 > > When I checked it, I found that it was possible to parse it with "rv:11.0". > > Is there any reason not to patch this? I don't think it worth fixing. This was IE team deleberate decision to stop being detected as IE[1], and I generally agree - browser detection is evil and should not be used as soon as there are other options. In nginx, there is no real need to detect IE11 (and probably nobody cares about IE now anyway). [1] https://blogs.msdn.microsoft.com/ieinternals/2013/09/21/internet-explorer-11s-many-user-agent-strings/ -- Maxim Dounin http://mdounin.ru/