Skip to content

Commit 9a5430e

Browse files
Modules: improved handling of results of async handlers.
Previously, r.setReturnValue() had to be used when returning a value from async js_set handler. async function hash(r) { let hash = await crypto.subtle.digest('SHA-512', r.headersIn.host); r.setReturnValue(Buffer.from(hash).toString('hex')); } Now r.setReturnValue() is not needed: async function hash(r) { let hash = await crypto.subtle.digest('SHA-512', r.headersIn.host); return Buffer.from(hash).toString('hex'); } Also added promise handling in global qjs code.
1 parent ee8cbf4 commit 9a5430e

File tree

4 files changed

+290
-117
lines changed

4 files changed

+290
-117
lines changed

nginx/ngx_js.c

Lines changed: 153 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,14 @@ static void ngx_engine_njs_destroy(ngx_engine_t *e, ngx_js_ctx_t *ctx,
5454
ngx_js_loc_conf_t *conf);
5555
static ngx_int_t ngx_js_init_preload_vm(njs_vm_t *vm, ngx_js_loc_conf_t *conf);
5656

57+
static ngx_int_t ngx_njs_execute_pending_jobs(njs_vm_t *vm, ngx_log_t *log);
58+
static njs_int_t ngx_njs_await(njs_vm_t *vm, ngx_log_t *log,
59+
njs_value_t *value);
60+
5761
#if (NJS_HAVE_QUICKJS)
62+
static ngx_int_t ngx_qjs_execute_pending_jobs(JSContext *cx, ngx_log_t *log);
63+
static ngx_int_t ngx_qjs_await(JSContext *cx, ngx_log_t *log,
64+
JSValueConst *value);
5865
static ngx_int_t ngx_engine_qjs_init(ngx_engine_t *engine,
5966
ngx_engine_opts_t *opts);
6067
static ngx_int_t ngx_engine_qjs_compile(ngx_js_loc_conf_t *conf, ngx_log_t *log,
@@ -657,10 +664,61 @@ ngx_engine_njs_compile(ngx_js_loc_conf_t *conf, ngx_log_t *log, u_char *start,
657664
}
658665

659666

667+
static ngx_int_t
668+
ngx_njs_execute_pending_jobs(njs_vm_t *vm, ngx_log_t *log)
669+
{
670+
njs_int_t ret;
671+
njs_str_t exception;
672+
673+
for ( ;; ) {
674+
ret = njs_vm_execute_pending_job(vm);
675+
if (ret <= NJS_OK) {
676+
if (ret == NJS_ERROR) {
677+
njs_vm_exception_string(vm, &exception);
678+
ngx_log_error(NGX_LOG_ERR, log, 0, "js job exception: %V",
679+
&exception);
680+
return NGX_ERROR;
681+
}
682+
683+
break;
684+
}
685+
}
686+
687+
return NGX_OK;
688+
}
689+
690+
691+
static njs_int_t
692+
ngx_njs_await(njs_vm_t *vm, ngx_log_t *log, njs_value_t *value)
693+
{
694+
ngx_int_t ret;
695+
njs_promise_type_t state;
696+
697+
ret = ngx_njs_execute_pending_jobs(vm, log);
698+
if (ret != NGX_OK) {
699+
return NGX_ERROR;
700+
}
701+
702+
if (njs_value_is_promise(value)) {
703+
state = njs_promise_state(value);
704+
705+
if (state == NJS_PROMISE_FULFILL) {
706+
njs_value_assign(value, njs_promise_result(value));
707+
708+
} else if (state == NJS_PROMISE_REJECTED) {
709+
njs_vm_throw(vm, njs_promise_result(value));
710+
}
711+
}
712+
713+
return NGX_OK;
714+
}
715+
716+
660717
ngx_engine_t *
661718
ngx_njs_clone(ngx_js_ctx_t *ctx, ngx_js_loc_conf_t *cf, void *external)
662719
{
663720
njs_vm_t *vm;
721+
njs_int_t ret;
664722
ngx_engine_t *engine;
665723
njs_opaque_value_t retval;
666724

@@ -671,8 +729,7 @@ ngx_njs_clone(ngx_js_ctx_t *ctx, ngx_js_loc_conf_t *cf, void *external)
671729

672730
engine = njs_mp_alloc(njs_vm_memory_pool(vm), sizeof(ngx_engine_t));
673731
if (engine == NULL) {
674-
njs_vm_destroy(vm);
675-
return NULL;
732+
goto destroy;
676733
}
677734

678735
memcpy(engine, cf->engine, sizeof(ngx_engine_t));
@@ -681,13 +738,21 @@ ngx_njs_clone(ngx_js_ctx_t *ctx, ngx_js_loc_conf_t *cf, void *external)
681738

682739
if (njs_vm_start(vm, njs_value_arg(&retval)) == NJS_ERROR) {
683740
ngx_js_log_exception(vm, ctx->log, "exception");
741+
goto destroy;
742+
}
684743

685-
njs_vm_destroy(vm);
686-
687-
return NULL;
744+
ret = ngx_njs_await(vm, ctx->log, njs_value_arg(&retval));
745+
if (ret == NGX_ERROR) {
746+
goto destroy;
688747
}
689748

690749
return engine;
750+
751+
destroy:
752+
753+
njs_vm_destroy(vm);
754+
755+
return NULL;
691756
}
692757

693758

@@ -720,17 +785,9 @@ ngx_engine_njs_call(ngx_js_ctx_t *ctx, ngx_str_t *fname,
720785
return NGX_ERROR;
721786
}
722787

723-
for ( ;; ) {
724-
ret = njs_vm_execute_pending_job(vm);
725-
if (ret <= NJS_OK) {
726-
if (ret == NJS_ERROR) {
727-
ngx_js_log_exception(vm, ctx->log, "exception");
728-
729-
return NGX_ERROR;
730-
}
731-
732-
break;
733-
}
788+
ret = ngx_njs_await(vm, ctx->log, njs_value_arg(&ctx->retval));
789+
if (ret == NGX_ERROR) {
790+
return NGX_ERROR;
734791
}
735792

736793
return njs_rbtree_is_empty(&ctx->waiting_events) ? NGX_OK : NGX_AGAIN;
@@ -807,6 +864,66 @@ ngx_engine_njs_destroy(ngx_engine_t *e, ngx_js_ctx_t *ctx,
807864

808865
#if (NJS_HAVE_QUICKJS)
809866

867+
static ngx_int_t
868+
ngx_qjs_execute_pending_jobs(JSContext *cx, ngx_log_t *log)
869+
{
870+
int rc;
871+
JSValue value;
872+
JSContext *cx1;
873+
const char *exception;
874+
875+
for ( ;; ) {
876+
rc = JS_ExecutePendingJob(JS_GetRuntime(cx), &cx1);
877+
if (rc <= 0) {
878+
if (rc == 0) {
879+
break;
880+
}
881+
882+
value = JS_GetException(cx);
883+
exception = JS_ToCString(cx, value);
884+
JS_FreeValue(cx, value);
885+
886+
ngx_log_error(NGX_LOG_ERR, log, 0, "js job exception: %s",
887+
exception);
888+
889+
JS_FreeCString(cx, exception);
890+
891+
return NGX_ERROR;
892+
}
893+
}
894+
895+
return NGX_OK;
896+
}
897+
898+
899+
static ngx_int_t
900+
ngx_qjs_await(JSContext *cx, ngx_log_t *log, JSValue *value)
901+
{
902+
JSValue ret;
903+
ngx_int_t rc;
904+
JSPromiseStateEnum state;
905+
906+
rc = ngx_qjs_execute_pending_jobs(cx, log);
907+
if (rc != NGX_OK) {
908+
return NGX_ERROR;
909+
}
910+
911+
state = JS_PromiseState(cx, *value);
912+
if (state == JS_PROMISE_FULFILLED) {
913+
ret = JS_PromiseResult(cx, *value);
914+
JS_FreeValue(cx, *value);
915+
*value = ret;
916+
917+
} else if (state == JS_PROMISE_REJECTED) {
918+
ret = JS_Throw(cx, JS_PromiseResult(cx, *value));
919+
JS_FreeValue(cx, *value);
920+
*value = ret;
921+
}
922+
923+
return NGX_OK;
924+
}
925+
926+
810927
static ngx_int_t
811928
ngx_engine_qjs_init(ngx_engine_t *engine, ngx_engine_opts_t *opts)
812929
{
@@ -871,48 +988,13 @@ ngx_engine_qjs_compile(ngx_js_loc_conf_t *conf, ngx_log_t *log, u_char *start,
871988
}
872989

873990

874-
static JSValue
875-
js_std_await(JSContext *ctx, JSValue obj)
876-
{
877-
int state, err;
878-
JSValue ret;
879-
JSContext *ctx1;
880-
881-
for (;;) {
882-
state = JS_PromiseState(ctx, obj);
883-
if (state == JS_PROMISE_FULFILLED) {
884-
ret = JS_PromiseResult(ctx, obj);
885-
JS_FreeValue(ctx, obj);
886-
break;
887-
888-
} else if (state == JS_PROMISE_REJECTED) {
889-
ret = JS_Throw(ctx, JS_PromiseResult(ctx, obj));
890-
JS_FreeValue(ctx, obj);
891-
break;
892-
893-
} else if (state == JS_PROMISE_PENDING) {
894-
err = JS_ExecutePendingJob(JS_GetRuntime(ctx), &ctx1);
895-
if (err < 0) {
896-
/* js_std_dump_error(ctx1); */
897-
}
898-
899-
} else {
900-
/* not a promise */
901-
ret = obj;
902-
break;
903-
}
904-
}
905-
906-
return ret;
907-
}
908-
909-
910991
ngx_engine_t *
911992
ngx_qjs_clone(ngx_js_ctx_t *ctx, ngx_js_loc_conf_t *cf, void *external)
912993
{
913994
JSValue rv;
914995
njs_mp_t *mp;
915996
uint32_t i, length;
997+
ngx_int_t rc;
916998
JSRuntime *rt;
917999
JSContext *cx;
9181000
ngx_engine_t *engine;
@@ -990,14 +1072,13 @@ ngx_qjs_clone(ngx_js_ctx_t *ctx, ngx_js_loc_conf_t *cf, void *external)
9901072
goto destroy;
9911073
}
9921074

993-
rv = js_std_await(cx, rv);
994-
if (JS_IsException(rv)) {
995-
ngx_qjs_log_exception(engine, ctx->log, "eval exception");
1075+
rc = ngx_qjs_await(cx, ctx->log, &rv);
1076+
JS_FreeValue(cx, rv);
1077+
if (rc == NGX_ERROR) {
1078+
ngx_qjs_log_exception(engine, ctx->log, "await exception");
9961079
goto destroy;
9971080
}
9981081

999-
JS_FreeValue(cx, rv);
1000-
10011082
return engine;
10021083

10031084
destroy:
@@ -1014,10 +1095,9 @@ static ngx_int_t
10141095
ngx_engine_qjs_call(ngx_js_ctx_t *ctx, ngx_str_t *fname,
10151096
njs_opaque_value_t *args, njs_uint_t nargs)
10161097
{
1017-
int rc;
10181098
JSValue fn, val;
1019-
JSRuntime *rt;
1020-
JSContext *cx, *cx1;
1099+
ngx_int_t rc;
1100+
JSContext *cx;
10211101

10221102
cx = ctx->engine->u.qjs.ctx;
10231103

@@ -1041,19 +1121,10 @@ ngx_engine_qjs_call(ngx_js_ctx_t *ctx, ngx_str_t *fname,
10411121
JS_FreeValue(cx, ngx_qjs_arg(ctx->retval));
10421122
ngx_qjs_arg(ctx->retval) = val;
10431123

1044-
rt = JS_GetRuntime(cx);
1045-
1046-
for ( ;; ) {
1047-
rc = JS_ExecutePendingJob(rt, &cx1);
1048-
if (rc <= 0) {
1049-
if (rc == -1) {
1050-
ngx_qjs_log_exception(ctx->engine, ctx->log, "job exception");
1051-
1052-
return NGX_ERROR;
1053-
}
1054-
1055-
break;
1056-
}
1124+
rc = ngx_qjs_await(cx, ctx->log, &ngx_qjs_arg(ctx->retval));
1125+
if (rc == NGX_ERROR) {
1126+
ngx_qjs_log_exception(ctx->engine, ctx->log, "await exception");
1127+
return NGX_ERROR;
10571128
}
10581129

10591130
return njs_rbtree_is_empty(&ctx->waiting_events) ? NGX_OK : NGX_AGAIN;
@@ -1365,10 +1436,8 @@ ngx_qjs_dump_obj(ngx_engine_t *e, JSValueConst val, ngx_str_t *dst)
13651436
ngx_int_t
13661437
ngx_qjs_call(JSContext *cx, JSValue fn, JSValue *argv, int argc)
13671438
{
1368-
int rc;
13691439
JSValue ret;
1370-
JSRuntime *rt;
1371-
JSContext *cx1;
1440+
ngx_int_t rc;
13721441
ngx_js_ctx_t *ctx;
13731442

13741443
ctx = ngx_qjs_external_ctx(cx, JS_GetContextOpaque(cx));
@@ -1382,19 +1451,9 @@ ngx_qjs_call(JSContext *cx, JSValue fn, JSValue *argv, int argc)
13821451

13831452
JS_FreeValue(cx, ret);
13841453

1385-
rt = JS_GetRuntime(cx);
1386-
1387-
for ( ;; ) {
1388-
rc = JS_ExecutePendingJob(rt, &cx1);
1389-
if (rc <= 0) {
1390-
if (rc == -1) {
1391-
ngx_qjs_log_exception(ctx->engine, ctx->log, "job exception");
1392-
1393-
return NGX_ERROR;
1394-
}
1395-
1396-
break;
1397-
}
1454+
rc = ngx_qjs_execute_pending_jobs(cx, ctx->log);
1455+
if (rc != NGX_OK) {
1456+
return NGX_ERROR;
13981457
}
13991458

14001459
return NGX_OK;
@@ -2202,6 +2261,7 @@ ngx_js_call(njs_vm_t *vm, njs_function_t *func, njs_opaque_value_t *args,
22022261
njs_uint_t nargs)
22032262
{
22042263
njs_int_t ret;
2264+
ngx_js_ctx_t *ctx;
22052265
ngx_connection_t *c;
22062266

22072267
ret = njs_vm_call(vm, func, njs_value_arg(args), nargs);
@@ -2214,19 +2274,11 @@ ngx_js_call(njs_vm_t *vm, njs_function_t *func, njs_opaque_value_t *args,
22142274
return NGX_ERROR;
22152275
}
22162276

2217-
for ( ;; ) {
2218-
ret = njs_vm_execute_pending_job(vm);
2219-
if (ret <= NJS_OK) {
2220-
c = ngx_external_connection(vm, njs_vm_external_ptr(vm));
2221-
2222-
if (ret == NJS_ERROR) {
2223-
ngx_js_log_exception(vm, c->log, "job exception");
2224-
2225-
return NGX_ERROR;
2226-
}
2277+
ctx = ngx_external_ctx(vm, njs_vm_external_ptr(vm));
22272278

2228-
break;
2229-
}
2279+
ret = ngx_njs_execute_pending_jobs(vm, ctx->log);
2280+
if (ret != NGX_OK) {
2281+
return NGX_ERROR;
22302282
}
22312283

22322284
return NGX_OK;

0 commit comments

Comments
 (0)