Created
November 6, 2025 17:25
-
-
Save xeioex/6d3eb6c3bc7a0d9975da289b8e72c40f to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| commit f97144b9be3fc6957374a11d8e401702cc77e2d6 | |
| Author: Dmitry Volyntsev <[email protected]> | |
| Date: Wed Nov 5 21:59:07 2025 -0800 | |
| fixup! Modules: improved handling of results of async handlers. | |
| diff --git a/external/njs_shell.c b/external/njs_shell.c | |
| index 570da13b..b29ccee2 100644 | |
| --- a/external/njs_shell.c | |
| +++ b/external/njs_shell.c | |
| @@ -2703,7 +2703,7 @@ njs_engine_qjs_destroy(njs_engine_t *engine) | |
| njs_queue_link_t *link; | |
| njs_rejected_promise_t *rejected_promise; | |
| - (void) qjs_call_exit_hook(engine->u.qjs.ctx); | |
| + qjs_call_exit_hook(engine->u.qjs.ctx); | |
| console = JS_GetRuntimeOpaque(engine->u.qjs.rt); | |
| diff --git a/nginx/ngx_js.c b/nginx/ngx_js.c | |
| index c29b912f..b4e78159 100644 | |
| --- a/nginx/ngx_js.c | |
| +++ b/nginx/ngx_js.c | |
| @@ -55,11 +55,13 @@ static void ngx_engine_njs_destroy(ngx_engine_t *e, ngx_js_ctx_t *ctx, | |
| static ngx_int_t ngx_js_init_preload_vm(njs_vm_t *vm, ngx_js_loc_conf_t *conf); | |
| static ngx_int_t ngx_njs_execute_pending_jobs(njs_vm_t *vm, ngx_log_t *log); | |
| -static njs_int_t ngx_njs_await(ngx_js_ctx_t *ctx, njs_opaque_value_t *retval); | |
| +static njs_int_t ngx_njs_await(njs_vm_t *vm, ngx_log_t *log, | |
| + njs_value_t *value); | |
| #if (NJS_HAVE_QUICKJS) | |
| -static ngx_int_t ngx_qjs_execute_pending_jobs(JSContext *ctx, ngx_log_t *log); | |
| -static njs_int_t ngx_qjs_await(ngx_js_ctx_t *ctx, JSValue *obj); | |
| +static ngx_int_t ngx_qjs_execute_pending_jobs(JSContext *cx, ngx_log_t *log); | |
| +static ngx_int_t ngx_qjs_await(JSContext *cx, ngx_log_t *log, | |
| + JSValueConst *value); | |
| static ngx_int_t ngx_engine_qjs_init(ngx_engine_t *engine, | |
| ngx_engine_opts_t *opts); | |
| static ngx_int_t ngx_engine_qjs_compile(ngx_js_loc_conf_t *conf, ngx_log_t *log, | |
| @@ -666,17 +668,18 @@ static ngx_int_t | |
| ngx_njs_execute_pending_jobs(njs_vm_t *vm, ngx_log_t *log) | |
| { | |
| njs_int_t ret; | |
| - njs_str_t exception_string; | |
| + njs_str_t exception; | |
| for ( ;; ) { | |
| ret = njs_vm_execute_pending_job(vm); | |
| - if (ret < NJS_OK) { | |
| - njs_vm_exception_string(vm, &exception_string); | |
| - ngx_log_error(NGX_LOG_ERR, log, 0, "js job exception: %V", | |
| - &exception_string); | |
| - return NGX_ERROR; | |
| - } | |
| - if (ret == NJS_OK) { | |
| + if (ret <= NJS_OK) { | |
| + if (ret == NJS_ERROR) { | |
| + njs_vm_exception_string(vm, &exception); | |
| + ngx_log_error(NGX_LOG_ERR, log, 0, "js job exception: %V", | |
| + &exception); | |
| + return NGX_ERROR; | |
| + } | |
| + | |
| break; | |
| } | |
| } | |
| @@ -686,30 +689,24 @@ ngx_njs_execute_pending_jobs(njs_vm_t *vm, ngx_log_t *log) | |
| static njs_int_t | |
| -ngx_njs_await(ngx_js_ctx_t *ctx, njs_opaque_value_t *retval) | |
| +ngx_njs_await(njs_vm_t *vm, ngx_log_t *log, njs_value_t *value) | |
| { | |
| - njs_vm_t *vm; | |
| ngx_int_t ret; | |
| - njs_value_t *val; | |
| njs_promise_type_t state; | |
| - vm = ctx->engine->u.njs.vm; | |
| - | |
| - ret = ngx_njs_execute_pending_jobs(vm, ctx->log); | |
| + ret = ngx_njs_execute_pending_jobs(vm, log); | |
| if (ret != NGX_OK) { | |
| return NGX_ERROR; | |
| } | |
| - val = njs_value_arg(retval); | |
| - if (njs_value_is_promise(val)) { | |
| - state = njs_promise_state(val); | |
| + if (njs_value_is_promise(value)) { | |
| + state = njs_promise_state(value); | |
| if (state == NJS_PROMISE_FULFILL) { | |
| - njs_value_assign(val, njs_promise_result(val)); | |
| + njs_value_assign(value, njs_promise_result(value)); | |
| } else if (state == NJS_PROMISE_REJECTED) { | |
| - njs_vm_throw(vm, njs_promise_result(val)); | |
| - | |
| + njs_vm_throw(vm, njs_promise_result(value)); | |
| } | |
| } | |
| @@ -732,22 +729,19 @@ ngx_njs_clone(ngx_js_ctx_t *ctx, ngx_js_loc_conf_t *cf, void *external) | |
| engine = njs_mp_alloc(njs_vm_memory_pool(vm), sizeof(ngx_engine_t)); | |
| if (engine == NULL) { | |
| - njs_vm_destroy(vm); | |
| - return NULL; | |
| + goto destroy; | |
| } | |
| memcpy(engine, cf->engine, sizeof(ngx_engine_t)); | |
| engine->pool = njs_vm_memory_pool(vm); | |
| engine->u.njs.vm = vm; | |
| - ctx->engine = engine; | |
| - | |
| if (njs_vm_start(vm, njs_value_arg(&retval)) == NJS_ERROR) { | |
| ngx_js_log_exception(vm, ctx->log, "exception"); | |
| goto destroy; | |
| } | |
| - ret = ngx_njs_await(ctx, &retval); | |
| + ret = ngx_njs_await(vm, ctx->log, njs_value_arg(&retval)); | |
| if (ret == NGX_ERROR) { | |
| goto destroy; | |
| } | |
| @@ -756,7 +750,8 @@ ngx_njs_clone(ngx_js_ctx_t *ctx, ngx_js_loc_conf_t *cf, void *external) | |
| destroy: | |
| - ngx_engine_njs_destroy(engine, ctx, cf); | |
| + njs_vm_destroy(vm); | |
| + | |
| return NULL; | |
| } | |
| @@ -790,7 +785,7 @@ ngx_engine_njs_call(ngx_js_ctx_t *ctx, ngx_str_t *fname, | |
| return NGX_ERROR; | |
| } | |
| - ret = ngx_njs_await(ctx, &ctx->retval); | |
| + ret = ngx_njs_await(vm, ctx->log, njs_value_arg(&ctx->retval)); | |
| if (ret == NGX_ERROR) { | |
| return NGX_ERROR; | |
| } | |
| @@ -868,67 +863,61 @@ ngx_engine_njs_destroy(ngx_engine_t *e, ngx_js_ctx_t *ctx, | |
| #if (NJS_HAVE_QUICKJS) | |
| + | |
| static ngx_int_t | |
| -ngx_qjs_execute_pending_jobs(JSContext *ctx, ngx_log_t *log) | |
| +ngx_qjs_execute_pending_jobs(JSContext *cx, ngx_log_t *log) | |
| { | |
| int rc; | |
| - JSValue exception_val, exception_str;; | |
| - JSContext *cx; | |
| + JSValue value; | |
| + JSContext *cx1; | |
| const char *exception; | |
| for ( ;; ) { | |
| - rc = JS_ExecutePendingJob(JS_GetRuntime(ctx), &cx); | |
| - if (rc < 0) { | |
| - exception_val = JS_GetException(ctx); | |
| - | |
| - exception_str = JS_ToString(ctx, exception_val); | |
| - JS_FreeValue(ctx, exception_val); | |
| + rc = JS_ExecutePendingJob(JS_GetRuntime(cx), &cx1); | |
| + if (rc <= 0) { | |
| + if (rc == 0) { | |
| + break; | |
| + } | |
| - exception = JS_ToCString(ctx, exception_str); | |
| - JS_FreeValue(ctx, exception_str); | |
| + value = JS_GetException(cx); | |
| + exception = JS_ToCString(cx, value); | |
| + JS_FreeValue(cx, value); | |
| ngx_log_error(NGX_LOG_ERR, log, 0, "js job exception: %s", | |
| exception); | |
| - JS_FreeCString(ctx, exception); | |
| + JS_FreeCString(cx, exception); | |
| return NGX_ERROR; | |
| } | |
| - if (rc == 0) { | |
| - break; | |
| - } | |
| } | |
| return NGX_OK; | |
| } | |
| -static njs_int_t | |
| -ngx_qjs_await(ngx_js_ctx_t *ctx, JSValue *obj) | |
| +static ngx_int_t | |
| +ngx_qjs_await(JSContext *cx, ngx_log_t *log, JSValue *value) | |
| { | |
| - JSValue ret, rejection; | |
| - ngx_int_t rc; | |
| - JSContext *cx; | |
| - JSPromiseStateEnum state; | |
| - | |
| - cx = ctx->engine->u.qjs.ctx; | |
| + JSValue ret; | |
| + ngx_int_t rc; | |
| + JSPromiseStateEnum state; | |
| - rc = ngx_qjs_execute_pending_jobs(cx, ctx->log); | |
| + rc = ngx_qjs_execute_pending_jobs(cx, log); | |
| if (rc != NGX_OK) { | |
| return NGX_ERROR; | |
| } | |
| - if (JS_IsObject(*obj)) { | |
| - state = JS_PromiseState(cx, *obj); | |
| - if (state == JS_PROMISE_FULFILLED) { | |
| - ret = JS_PromiseResult(cx, *obj); | |
| - JS_FreeValue(cx, *obj); | |
| - *obj = ret; | |
| - } else if (state == JS_PROMISE_REJECTED) { | |
| - rejection = JS_PromiseResult(cx, *obj); | |
| - JS_FreeValue(cx, *obj); | |
| - *obj = JS_Throw(cx, rejection); | |
| - } | |
| + state = JS_PromiseState(cx, *value); | |
| + if (state == JS_PROMISE_FULFILLED) { | |
| + ret = JS_PromiseResult(cx, *value); | |
| + JS_FreeValue(cx, *value); | |
| + *value = ret; | |
| + | |
| + } else if (state == JS_PROMISE_REJECTED) { | |
| + ret = JS_Throw(cx, JS_PromiseResult(cx, *value)); | |
| + JS_FreeValue(cx, *value); | |
| + *value = ret; | |
| } | |
| return NGX_OK; | |
| @@ -1002,10 +991,10 @@ ngx_engine_qjs_compile(ngx_js_loc_conf_t *conf, ngx_log_t *log, u_char *start, | |
| ngx_engine_t * | |
| ngx_qjs_clone(ngx_js_ctx_t *ctx, ngx_js_loc_conf_t *cf, void *external) | |
| { | |
| - int rc; | |
| JSValue rv; | |
| njs_mp_t *mp; | |
| uint32_t i, length; | |
| + ngx_int_t rc; | |
| JSRuntime *rt; | |
| JSContext *cx; | |
| ngx_engine_t *engine; | |
| @@ -1076,8 +1065,6 @@ ngx_qjs_clone(ngx_js_ctx_t *ctx, ngx_js_loc_conf_t *cf, void *external) | |
| goto destroy; | |
| } | |
| - ctx->engine = engine; | |
| - | |
| rv = JS_EvalFunction(cx, rv); | |
| if (JS_IsException(rv)) { | |
| @@ -1085,11 +1072,10 @@ ngx_qjs_clone(ngx_js_ctx_t *ctx, ngx_js_loc_conf_t *cf, void *external) | |
| goto destroy; | |
| } | |
| - rc = ngx_qjs_await(ctx, &rv); | |
| - | |
| + rc = ngx_qjs_await(cx, ctx->log, &rv); | |
| JS_FreeValue(cx, rv); | |
| - | |
| if (rc == NGX_ERROR) { | |
| + ngx_qjs_log_exception(engine, ctx->log, "await exception"); | |
| goto destroy; | |
| } | |
| @@ -1109,8 +1095,8 @@ static ngx_int_t | |
| ngx_engine_qjs_call(ngx_js_ctx_t *ctx, ngx_str_t *fname, | |
| njs_opaque_value_t *args, njs_uint_t nargs) | |
| { | |
| - int rc; | |
| JSValue fn, val; | |
| + ngx_int_t rc; | |
| JSContext *cx; | |
| cx = ctx->engine->u.qjs.ctx; | |
| @@ -1128,15 +1114,16 @@ ngx_engine_qjs_call(ngx_js_ctx_t *ctx, ngx_str_t *fname, | |
| JS_FreeValue(cx, fn); | |
| if (JS_IsException(val)) { | |
| ngx_qjs_log_exception(ctx->engine, ctx->log, "call exception"); | |
| + | |
| return NGX_ERROR; | |
| } | |
| JS_FreeValue(cx, ngx_qjs_arg(ctx->retval)); | |
| ngx_qjs_arg(ctx->retval) = val; | |
| - rc = ngx_qjs_await(ctx, &ngx_qjs_arg(ctx->retval)); | |
| - | |
| + rc = ngx_qjs_await(cx, ctx->log, &ngx_qjs_arg(ctx->retval)); | |
| if (rc == NGX_ERROR) { | |
| + ngx_qjs_log_exception(ctx->engine, ctx->log, "await exception"); | |
| return NGX_ERROR; | |
| } | |
| @@ -1458,6 +1445,7 @@ ngx_qjs_call(JSContext *cx, JSValue fn, JSValue *argv, int argc) | |
| ret = JS_Call(cx, fn, JS_UNDEFINED, argc, argv); | |
| if (JS_IsException(ret)) { | |
| ngx_qjs_log_exception(ctx->engine, ctx->log, "call exception"); | |
| + | |
| return NGX_ERROR; | |
| } | |
| @@ -2276,16 +2264,18 @@ ngx_js_call(njs_vm_t *vm, njs_function_t *func, njs_opaque_value_t *args, | |
| ngx_js_ctx_t *ctx; | |
| ngx_connection_t *c; | |
| - ctx = ngx_external_ctx(vm, njs_vm_external_ptr(vm)); | |
| - | |
| ret = njs_vm_call(vm, func, njs_value_arg(args), nargs); | |
| if (ret == NJS_ERROR) { | |
| + | |
| c = ngx_external_connection(vm, njs_vm_external_ptr(vm)); | |
| ngx_js_log_exception(vm, c->log, "exception"); | |
| + | |
| return NGX_ERROR; | |
| } | |
| + ctx = ngx_external_ctx(vm, njs_vm_external_ptr(vm)); | |
| + | |
| ret = ngx_njs_execute_pending_jobs(vm, ctx->log); | |
| if (ret != NGX_OK) { | |
| return NGX_ERROR; | |
| diff --git a/nginx/ngx_js.h b/nginx/ngx_js.h | |
| index 521d1f20..f3c2493b 100644 | |
| --- a/nginx/ngx_js.h | |
| +++ b/nginx/ngx_js.h | |
| @@ -438,7 +438,6 @@ void ngx_js_log(njs_vm_t *vm, njs_external_ptr_t external, | |
| ngx_uint_t level, const char *fmt, ...); | |
| void ngx_js_logger(ngx_connection_t *c, ngx_uint_t level, | |
| const u_char *start, size_t length); | |
| - | |
| char * ngx_js_import(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); | |
| char * ngx_js_engine(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); | |
| char * ngx_js_preload_object(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); | |
| diff --git a/nginx/t/js_promise_pending.t b/nginx/t/js_promise_pending.t | |
| deleted file mode 100644 | |
| index 521d6454..00000000 | |
| --- a/nginx/t/js_promise_pending.t | |
| +++ /dev/null | |
| @@ -1,114 +0,0 @@ | |
| -#!/usr/bin/perl | |
| - | |
| -# (C) F5, Inc. | |
| - | |
| -# Tests for proper handling of pending promises with no waiting events. | |
| - | |
| -############################################################################### | |
| - | |
| -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 rewrite/) | |
| - ->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 /njs { | |
| - js_content test.njs; | |
| - } | |
| - | |
| - location /promise_never_resolves { | |
| - js_content test.promise_never_resolves; | |
| - } | |
| - | |
| - location /promise_with_timeout { | |
| - js_content test.promise_with_timeout; | |
| - } | |
| - | |
| - | |
| - } | |
| -} | |
| - | |
| -EOF | |
| - | |
| -$t->write_file('test.js', <<'EOF'); | |
| - function test_njs(r) { | |
| - r.return(200, njs.version); | |
| - } | |
| - | |
| - function promise_never_resolves(r) { | |
| - return new Promise((resolve, reject) => { | |
| - }); | |
| - } | |
| - | |
| - function promise_with_timeout(r) { | |
| - const p = new Promise((resolve, reject) => { | |
| - setTimeout(() => { | |
| - resolve("timeout resolved"); | |
| - }, 10); | |
| - }); | |
| - | |
| - return p.then((value) => { | |
| - r.return(200, "resolved: " + value); | |
| - }); | |
| - } | |
| - | |
| - export default {njs: test_njs, promise_never_resolves, | |
| - promise_with_timeout}; | |
| - | |
| -EOF | |
| - | |
| -$t->try_run('no njs available')->plan(4); | |
| - | |
| -############################################################################### | |
| - | |
| -# Test basic functionality | |
| -like(http_get('/njs'), qr/\d+\.\d+\.\d+/, 'njs version'); | |
| - | |
| -# Test promise with timeout (should work - has waiting events) | |
| -like(http_get('/promise_with_timeout'), qr/resolved: timeout resolved/, | |
| - 'promise with timeout resolves'); | |
| - | |
| -# Test pending promise scenario - should trigger error response | |
| -# because it returns a promise that will never resolve with no waiting events | |
| -my $never_resolves_response = http_get('/promise_never_resolves'); | |
| -like($never_resolves_response, qr/HTTP\/1\.[01] 500|Internal Server Error/, | |
| - 'never resolving promise causes error'); | |
| - | |
| -$t->stop(); | |
| - | |
| -# Check error log for the specific pending promise error message | |
| -my $error_log = $t->read_file('error.log'); | |
| - | |
| -# Should have no error for promises with waiting events | |
| -unlike($error_log, qr/js exception.*timeout resolved/, | |
| - 'no error for promise with waiting events'); | |
| - | |
| -############################################################################### | |
| diff --git a/nginx/t/js_promise_top_level_await.t b/nginx/t/js_promise_top_level_await.t | |
| index def5da13..29dc6322 100644 | |
| --- a/nginx/t/js_promise_top_level_await.t | |
| +++ b/nginx/t/js_promise_top_level_await.t | |
| @@ -1,14 +1,9 @@ | |
| #!/usr/bin/perl | |
| # (C) F5, Inc. | |
| +# Vadim Zhestikov | |
| -# Tests for proper handling of promises in ngx_qjs_await() with: | |
| -# - Job queue processing limits | |
| -# - Waiting events detection | |
| -# - Promise state handling after job processing | |
| -# | |
| -# Note: ngx_qjs_await() is called during global code evaluation, | |
| -# not function calls. | |
| +# Tests for top-level await of promises in QuickJS engine. | |
| ############################################################################### | |
| @@ -47,10 +42,6 @@ http { | |
| listen 127.0.0.1:8080; | |
| server_name localhost; | |
| - location /njs { | |
| - js_content test.njs; | |
| - } | |
| - | |
| location /resolved { | |
| js_content test.test; | |
| } | |
| @@ -64,48 +55,38 @@ http { | |
| EOF | |
| $t->write_file('test.js', <<'EOF'); | |
| -var globalResult = await Promise.resolve("resolved value"); | |
| + var globalResult = await Promise.resolve("resolved value"); | |
| -function test_njs(r) { | |
| - r.return(200, njs.version); | |
| -} | |
| + function test(r) { | |
| + r.return(200, "global result: " + globalResult); | |
| + } | |
| -function test(r) { | |
| - r.return(200, "global result: " + globalResult); | |
| -} | |
| + export default {test}; | |
| -export default {njs: test_njs, test}; | |
| EOF | |
| $t->write_file('fulfilled_test.js', <<'EOF'); | |
| -var globalResult = await new Promise((resolve) => { | |
| - Promise.resolve().then(() => { | |
| - resolve("fulfilled value"); | |
| + var globalResult = await new Promise((resolve) => { | |
| + Promise.resolve().then(() => { | |
| + resolve("fulfilled value"); | |
| + }); | |
| }); | |
| -}); | |
| -function test(r) { | |
| - r.return(200, "fulfilled result: " + globalResult); | |
| -} | |
| + function test(r) { | |
| + r.return(200, "fulfilled result: " + globalResult); | |
| + } | |
| + | |
| + export default {test}; | |
| -export default {test}; | |
| EOF | |
| -$t->try_run('no qjs engine available')->plan(3); | |
| +$t->try_run('no top-level await support')->plan(2); | |
| ############################################################################### | |
| -# Test basic functionality | |
| -like(http_get('/njs'), qr/\d+\.\d+\.\d+/, 'njs version'); | |
| - | |
| -# Test basic global await with resolved promise | |
| like(http_get('/resolved'), qr/global result: resolved value/, | |
| 'basic global await works'); | |
| - | |
| -# Test global await with fulfilled promise (via microtask) | |
| like(http_get('/fulfilled'), qr/fulfilled result: fulfilled value/, | |
| 'fulfilled promise via microtask works'); | |
| -$t->stop(); | |
| - | |
| ############################################################################### | |
| diff --git a/nginx/t/js_promise_top_level_await_pending.t b/nginx/t/js_promise_top_level_await_pending.t | |
| deleted file mode 100644 | |
| index 0a237c0e..00000000 | |
| --- a/nginx/t/js_promise_top_level_await_pending.t | |
| +++ /dev/null | |
| @@ -1,86 +0,0 @@ | |
| -#!/usr/bin/perl | |
| - | |
| -# (C) F5, Inc. | |
| - | |
| -# This test specifically validates the waiting_events checking functionality | |
| -# in ngx_qjs_await() for promises that remain pending with no waiting events. | |
| - | |
| -############################################################################### | |
| - | |
| -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 rewrite/) | |
| - ->write_file_expand('nginx.conf', <<'EOF'); | |
| - | |
| -%%TEST_GLOBALS%% | |
| - | |
| -daemon off; | |
| - | |
| -events { | |
| -} | |
| - | |
| -http { | |
| - %%TEST_GLOBALS_HTTP%% | |
| - | |
| - js_import pending_test.js; | |
| - | |
| - server { | |
| - listen 127.0.0.1:8080; | |
| - server_name localhost; | |
| - | |
| - location /njs { | |
| - js_content pending_test.njs; | |
| - } | |
| - | |
| - location /pending_no_events { | |
| - js_content pending_test.test; | |
| - } | |
| - } | |
| -} | |
| - | |
| -EOF | |
| - | |
| -$t->write_file('pending_test.js', <<'EOF'); | |
| -var globalResult = await new Promise((resolve, reject) => { | |
| -}); | |
| - | |
| -function test_njs(r) { | |
| - r.return(200, njs.version); | |
| -} | |
| - | |
| -function test(r) { | |
| - r.return(200, "should never reach this: " + globalResult); | |
| -} | |
| - | |
| -export default {njs: test_njs, test}; | |
| -EOF | |
| - | |
| -$t->try_run('no qjs engine available')->plan(2); | |
| - | |
| -############################################################################### | |
| - | |
| -# Test basic functionality (this should also fail due to the pending promise | |
| -# in global code) | |
| -my $njs_response = http_get('/njs'); | |
| -like($njs_response, qr/HTTP\/1\.[01] 500|Internal Server Error/, | |
| - 'njs version endpoint fails due to pending promise in global code'); | |
| - | |
| -# Test pending promise with no waiting events (should cause error) | |
| -my $pending_response = http_get('/pending_no_events'); | |
| -like($pending_response, qr/HTTP\/1\.[01] 500|Internal Server Error/, | |
| - 'pending promise with no waiting events causes error'); | |
| - | |
| -############################################################################### | |
| diff --git a/nginx/t/stream_js.t b/nginx/t/stream_js.t | |
| index 7105c1e9..56f5699e 100644 | |
| --- a/nginx/t/stream_js.t | |
| +++ b/nginx/t/stream_js.t | |
| @@ -441,7 +441,6 @@ stream('127.0.0.1:' . port(8098))->io('x'); | |
| stream('127.0.0.1:' . port(8099))->io('x'); | |
| is(stream('127.0.0.1:' . port(8100))->read(), 'retval: 30', 'asyncf'); | |
| - | |
| is(stream('127.0.0.1:' . port(8102))->read(), 'retval: 30', 'asyncf1'); | |
| TODO: { | |
| diff --git a/src/njs.h b/src/njs.h | |
| index 85e87af9..1592a234 100644 | |
| --- a/src/njs.h | |
| +++ b/src/njs.h | |
| @@ -14,6 +14,7 @@ | |
| #define NJS_VERSION "0.9.5" | |
| #define NJS_VERSION_NUMBER 0x000905 | |
| + | |
| #include <string.h> | |
| #include <njs_types.h> | |
| #include <njs_clang.h> | |
| diff --git a/src/qjs.c b/src/qjs.c | |
| index 47782815..b7899158 100644 | |
| --- a/src/qjs.c | |
| +++ b/src/qjs.c | |
| @@ -6,7 +6,6 @@ | |
| #include <qjs.h> | |
| #include <njs.h> /* NJS_VERSION */ | |
| -#include <njs_rbtree.h> | |
| #include <sys/types.h> | |
| #include <unistd.h> | |
| diff --git a/src/qjs.h b/src/qjs.h | |
| index 85c245fa..df5bfd11 100644 | |
| --- a/src/qjs.h | |
| +++ b/src/qjs.h | |
| @@ -52,6 +52,7 @@ typedef struct { | |
| JSContext *qjs_new_context(JSRuntime *rt, qjs_module_t **addons); | |
| JSValue qjs_call_exit_hook(JSContext *ctx); | |
| + | |
| JSValue qjs_new_uint8_array(JSContext *ctx, int argc, JSValueConst *argv); | |
| JSValue qjs_new_array_buffer(JSContext *cx, uint8_t *src, size_t len); | |
| JSValue qjs_buffer_alloc(JSContext *ctx, size_t size); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment