From: Dmitry Volyntsev Date: Thu, 2 Jul 2026 23:19:32 +0000 (-0700) Subject: QuickJS: fix unhandled rejection tracking in reused contexts X-Git-Url: http://git.kaiwu.me/$%7BGITURL%7D/static/gitweb.js?a=commitdiff_plain;ds=inline;p=njs.git QuickJS: fix unhandled rejection tracking in reused contexts ngx_qjs_destroy() unregisters the host promise rejection tracker on the runtime, but ngx_qjs_clone() did not re-register it when a context was popped from the reuse queue. Every request served by a reused context then silently dropped unhandled rejections instead of reporting them, which also defeated any caller relying on ctx->rejected_promises. --- diff --git a/nginx/ngx_js.c b/nginx/ngx_js.c index 34fc23a4..3b69cea5 100644 --- a/nginx/ngx_js.c +++ b/nginx/ngx_js.c @@ -1062,6 +1062,10 @@ ngx_qjs_clone(ngx_js_ctx_t *ctx, ngx_js_loc_conf_t *cf, void *external) ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0, "js reused context: %p", engine->u.qjs.ctx); JS_SetContextOpaque(engine->u.qjs.ctx, external); + + JS_SetHostPromiseRejectionTracker( + JS_GetRuntime(engine->u.qjs.ctx), + ngx_qjs_rejection_tracker, ctx); return engine; } } diff --git a/nginx/t/js_context_reuse.t b/nginx/t/js_context_reuse.t new file mode 100644 index 00000000..97a1a227 --- /dev/null +++ b/nginx/t/js_context_reuse.t @@ -0,0 +1,81 @@ +#!/usr/bin/perl + +# (C) Dmitry Volyntsev +# (C) F5, Inc. + +# Tests for QuickJS context reuse. An unhandled rejection must keep being +# reported after the per-worker context is reused, not only on its first use. + +############################################################################### + +use warnings; +use strict; + +use Test::More; + +BEGIN { use FindBin; chdir($FindBin::Bin); } + +use lib 'lib'; +use Test::Nginx; + +############################################################################### + +select STDERR; $| = 1; +select STDOUT; $| = 1; + +my $t = Test::Nginx->new()->has(qw/http/) + ->write_file_expand('nginx.conf', <<'EOF'); + +%%TEST_GLOBALS%% + +daemon off; + +events { +} + +http { + %%TEST_GLOBALS_HTTP%% + + js_import test.js; + + server { + listen 127.0.0.1:8080; + server_name localhost; + + location /reject { + js_content test.reject; + } + } +} + +EOF + +$t->write_file('test.js', <try_run('no njs available')->plan(4); + +############################################################################### + +# The first request runs in a fresh context, the following ones reuse it +# (with the QuickJS engine). Every unhandled rejection must be reported. + +like(http_get('/reject'), qr/200 OK/, 'reject 1 (fresh context)'); +like(http_get('/reject'), qr/200 OK/, 'reject 2 (reused context)'); +like(http_get('/reject'), qr/200 OK/, 'reject 3 (reused context)'); + +$t->stop(); + +my $log = $t->read_file('error.log'); +my $count = () = $log =~ /js unhandled rejection/g; + +is($count, 3, 'unhandled rejection reported for every request'); + +###############################################################################