diff options
author | Dmitry Volyntsev <xeioex@nginx.com> | 2024-01-18 18:03:35 -0800 |
---|---|---|
committer | Dmitry Volyntsev <xeioex@nginx.com> | 2024-01-18 18:03:35 -0800 |
commit | 6dae86bc2d822e64cd83d057b48077c2691006d4 (patch) | |
tree | 2e394ba9869eddfd570eca0300989aae85080a9b /nginx/ngx_js.c | |
parent | e1120a2d82468fe7e403c12ab7b37e779f1160fd (diff) | |
download | njs-6dae86bc2d822e64cd83d057b48077c2691006d4.tar.gz njs-6dae86bc2d822e64cd83d057b48077c2691006d4.zip |
Moving out HostPromiseRejectionTracker from njs core.
HostPromiseRejectionTracker should be implemented by host
environment according to ECMAScript specs.
The following method was removed: njs_vm_unhandled_rejection().
The following method was introduced: njs_vm_set_rejection_tracker().
Diffstat (limited to 'nginx/ngx_js.c')
-rw-r--r-- | nginx/ngx_js.c | 101 |
1 files changed, 94 insertions, 7 deletions
diff --git a/nginx/ngx_js.c b/nginx/ngx_js.c index 6ebc873b..27fbfd29 100644 --- a/nginx/ngx_js.c +++ b/nginx/ngx_js.c @@ -12,17 +12,23 @@ typedef struct { - ngx_queue_t labels; + ngx_queue_t labels; } ngx_js_console_t; typedef struct { - njs_str_t name; - uint64_t time; - ngx_queue_t queue; + njs_str_t name; + uint64_t time; + ngx_queue_t queue; } ngx_js_timelabel_t; +typedef struct { + void *promise; + njs_opaque_value_t message; +} ngx_js_rejected_promise_t; + + static njs_int_t ngx_js_ext_build(njs_vm_t *vm, njs_object_prop_t *prop, njs_value_t *value, njs_value_t *setval, njs_value_t *retval); static njs_int_t ngx_js_ext_conf_file_path(njs_vm_t *vm, @@ -49,6 +55,7 @@ static njs_int_t njs_set_immediate(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused, njs_value_t *retval); static njs_int_t njs_clear_timeout(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused, njs_value_t *retval); +static njs_int_t ngx_js_unhandled_rejection(ngx_js_ctx_t *ctx); static void ngx_js_cleanup_vm(void *data); static njs_int_t ngx_js_core_init(njs_vm_t *vm); @@ -429,15 +436,15 @@ ngx_js_name_invoke(njs_vm_t *vm, ngx_str_t *fname, ngx_log_t *log, } } - if (njs_vm_unhandled_rejection(vm)) { + ctx = ngx_external_ctx(vm, njs_vm_external_ptr(vm)); + + if (ngx_js_unhandled_rejection(ctx)) { ngx_js_exception(vm, &exception); ngx_log_error(NGX_LOG_ERR, log, 0, "js exception: %V", &exception); return NGX_ERROR; } - ctx = ngx_external_ctx(vm, njs_vm_external_ptr(vm)); - return njs_rbtree_is_empty(&ctx->waiting_events) ? NGX_OK : NGX_AGAIN; } @@ -1661,6 +1668,53 @@ ngx_js_merge_vm(ngx_conf_t *cf, ngx_js_loc_conf_t *conf, } +static void +ngx_js_rejection_tracker(njs_vm_t *vm, njs_external_ptr_t unused, + njs_bool_t is_handled, njs_value_t *promise, njs_value_t *reason) +{ + void *promise_obj; + uint32_t i, length; + ngx_js_ctx_t *ctx; + ngx_js_rejected_promise_t *rejected_promise; + + ctx = ngx_external_ctx(vm, njs_vm_external_ptr(vm)); + + if (is_handled && ctx->rejected_promises != NULL) { + rejected_promise = ctx->rejected_promises->start; + length = ctx->rejected_promises->items; + + promise_obj = njs_value_ptr(promise); + + for (i = 0; i < length; i++) { + if (rejected_promise[i].promise == promise_obj) { + njs_arr_remove(ctx->rejected_promises, + &rejected_promise[i]); + + break; + } + } + + return; + } + + if (ctx->rejected_promises == NULL) { + ctx->rejected_promises = njs_arr_create(njs_vm_memory_pool(vm), 4, + sizeof(ngx_js_rejected_promise_t)); + if (njs_slow_path(ctx->rejected_promises == NULL)) { + return; + } + } + + rejected_promise = njs_arr_add(ctx->rejected_promises); + if (njs_slow_path(rejected_promise == NULL)) { + return; + } + + rejected_promise->promise = njs_value_ptr(promise); + njs_value_assign(&rejected_promise->message, reason); +} + + ngx_int_t ngx_js_init_conf_vm(ngx_conf_t *cf, ngx_js_loc_conf_t *conf, njs_vm_opt_t *options) @@ -1738,6 +1792,9 @@ ngx_js_init_conf_vm(ngx_conf_t *cf, ngx_js_loc_conf_t *conf, cln->handler = ngx_js_cleanup_vm; cln->data = conf; + njs_vm_set_rejection_tracker(conf->vm, ngx_js_rejection_tracker, + NULL); + path.start = ngx_cycle->conf_prefix.data; path.length = ngx_cycle->conf_prefix.len; @@ -1810,6 +1867,36 @@ ngx_js_init_conf_vm(ngx_conf_t *cf, ngx_js_loc_conf_t *conf, } +static njs_int_t +ngx_js_unhandled_rejection(ngx_js_ctx_t *ctx) +{ + njs_int_t ret; + njs_str_t message; + ngx_js_rejected_promise_t *rejected_promise; + + if (ctx->rejected_promises == NULL + || ctx->rejected_promises->items == 0) + { + return 0; + } + + rejected_promise = ctx->rejected_promises->start; + + ret = njs_vm_value_to_string(ctx->vm, &message, + njs_value_arg(&rejected_promise->message)); + if (njs_slow_path(ret != NJS_OK)) { + return -1; + } + + njs_vm_error(ctx->vm, "unhandled promise rejection: %V", &message); + + njs_arr_destroy(ctx->rejected_promises); + ctx->rejected_promises = NULL; + + return 1; +} + + static void ngx_js_cleanup_vm(void *data) { |