Created
October 29, 2025 04:57
-
-
Save xeioex/8aba0e4599b4e3484a7be544be4509a4 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 33a12604f3081cb68b77a91b2b04ce6023b2e1d1 | |
| Author: Vadim Zhestikov <[email protected]> | |
| Date: Mon Oct 27 14:14:02 2025 -0700 | |
| Fetch: making sure catch handler is executed asynchronously. | |
| diff --git a/nginx/ngx_js_fetch.c b/nginx/ngx_js_fetch.c | |
| index 09d0e194..91698d11 100644 | |
| --- a/nginx/ngx_js_fetch.c | |
| +++ b/nginx/ngx_js_fetch.c | |
| @@ -668,11 +668,20 @@ ngx_js_ext_fetch(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, | |
| fail: | |
| - njs_vm_exception_get(vm, njs_value_arg(&lvalue)); | |
| + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, http->log, 0, | |
| + "js http done fetch:%p rc:%i", fetch, NJS_ERROR); | |
| - ngx_js_fetch_done(fetch, &lvalue, NJS_ERROR); | |
| + ngx_js_http_close_peer(&fetch->http); | |
| - njs_value_assign(retval, njs_value_arg(&fetch->promise)); | |
| + if (fetch->event != NULL) { | |
| + ret = ngx_js_fetch_promissified_result(vm, njs_value_arg(&lvalue), | |
| + NJS_ERROR, retval); | |
| + | |
| + ngx_js_del_event(ngx_external_ctx(vm, njs_vm_external_ptr(vm)), | |
| + fetch->event); | |
| + | |
| + ngx_external_event_finalize(vm)(njs_vm_external_ptr(vm), ret); | |
| + } | |
| return NJS_OK; | |
| } | |
| diff --git a/nginx/ngx_qjs_fetch.c b/nginx/ngx_qjs_fetch.c | |
| index 0b3f3269..2c2ef18c 100644 | |
| --- a/nginx/ngx_qjs_fetch.c | |
| +++ b/nginx/ngx_qjs_fetch.c | |
| @@ -401,9 +401,20 @@ ngx_qjs_ext_fetch(JSContext *cx, JSValueConst this_val, int argc, | |
| fail: | |
| - fetch->response_value = JS_GetException(cx); | |
| + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, (&fetch->http)->log, 0, | |
| + "js http done fetch:%p rc:%i", fetch, NGX_ERROR); | |
| - ngx_qjs_fetch_done(fetch, fetch->response_value, NGX_ERROR); | |
| + ngx_js_http_close_peer(&fetch->http); | |
| + | |
| + if (fetch->event != NULL) { | |
| + JS_FreeValue(cx, promise); | |
| + promise = qjs_promise_result(cx, JS_EXCEPTION); | |
| + | |
| + ctx = ngx_qjs_external_ctx(cx, external); | |
| + ngx_js_del_event(ctx, fetch->event); | |
| + | |
| + ngx_qjs_external_event_finalize(cx)(external, rc); | |
| + } | |
| return promise; | |
| } | |
| diff --git a/nginx/t/js_fetch.t b/nginx/t/js_fetch.t | |
| index 9bbacf5b..bc9ee4c5 100644 | |
| --- a/nginx/t/js_fetch.t | |
| +++ b/nginx/t/js_fetch.t | |
| @@ -60,6 +60,10 @@ http { | |
| js_content test.broken_response; | |
| } | |
| + location /broken_catch { | |
| + js_content test.broken_catch; | |
| + } | |
| + | |
| location /body { | |
| js_content test.body; | |
| } | |
| @@ -234,6 +238,38 @@ $t->write_file('test.js', <<EOF); | |
| return process_errors(r, tests); | |
| } | |
| + function process_errors_catch(r, tests) { | |
| + var results = []; | |
| + | |
| + var sync_catch = 'sync'; | |
| + | |
| + tests.forEach(args => { | |
| + ngx.fetch.apply(r, args) | |
| + .then(reply => { | |
| + r.return(400, '["unexpected then"]'); | |
| + }) | |
| + .catch(e => { | |
| + results.push(sync_catch); | |
| + | |
| + if (results.length == tests.length) { | |
| + r.return(200, JSON.stringify(results)); | |
| + } | |
| + }) | |
| + }) | |
| + | |
| + sync_catch = 'async'; | |
| + } | |
| + | |
| + function broken_catch(r) { | |
| + var tests = [ | |
| + ['http://127.0.0.1:1/loc'], | |
| + ['http://127.0.0.1:80800/loc'], | |
| + [Symbol.toStringTag], | |
| + ]; | |
| + | |
| + return process_errors_catch(r, tests); | |
| + } | |
| + | |
| function chain(r) { | |
| var results = []; | |
| var reqs = [ | |
| @@ -428,15 +464,15 @@ $t->write_file('test.js', <<EOF); | |
| r.return(c, `\${v.request_method}:\${bar}:\${body}`); | |
| } | |
| - export default {njs: test_njs, body, broken, broken_response, body_special, | |
| - chain, chunked_ok, chunked_fail, header, header_iter, | |
| - host_header, multi, loc, property, body_content_length, | |
| - user_agent_header }; | |
| + export default {njs: test_njs, body, broken, broken_response, broken_catch, | |
| + body_special,chain, chunked_ok, chunked_fail, header, | |
| + header_iter, host_header, multi, loc, property, | |
| + body_content_length, user_agent_header }; | |
| EOF | |
| $t->try_run('no njs.fetch'); | |
| -$t->plan(40); | |
| +$t->plan(41); | |
| $t->run_daemon(\&http_daemon, port(8082)); | |
| $t->waitforsocket('127.0.0.1:' . port(8082)); | |
| @@ -495,6 +531,8 @@ is(get_json('/multi'), | |
| like(http_get('/multi?throw=1'), qr/500/s, 'fetch destructor'); | |
| like(http_get('/broken'), qr/200/s, 'fetch broken'); | |
| like(http_get('/broken_response'), qr/200/s, 'fetch broken response'); | |
| +like(http_get('/broken_catch'), qr/\["async","async","async"]$/s, | |
| + 'fetch broken catch'); | |
| like(http_get('/chunked_ok'), qr/200/s, 'fetch chunked ok'); | |
| like(http_get('/chunked_fail'), qr/200/s, 'fetch chunked fail'); | |
| like(http_get('/chain'), qr/200 OK.*SUCCESS$/s, 'fetch chain'); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment