]> git.kaiwu.me - njs.git/commitdiff
Fetch: making sure catch handler is executed asynchronously.
authorVadim Zhestikov <v.zhestikov@f5.com>
Mon, 27 Oct 2025 21:14:02 +0000 (14:14 -0700)
committerVadimZhestikov <108960056+VadimZhestikov@users.noreply.github.com>
Wed, 29 Oct 2025 17:00:51 +0000 (10:00 -0700)
nginx/ngx_js_fetch.c
nginx/ngx_qjs_fetch.c
nginx/t/js_fetch.t

index 09d0e19476597018b8d8916af37e47b2996c383c..fd40a5bad38a746ed8e77e4ab357483b806277d7 100644 (file)
@@ -668,13 +668,13 @@ 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_js_fetch_done(fetch, &lvalue, NJS_ERROR);
+    ngx_log_debug2(NGX_LOG_DEBUG_EVENT, http->log, 0,
+                   "js http done fetch:%p rc:%d", fetch, NJS_ERROR);
 
-    njs_value_assign(retval, njs_value_arg(&fetch->promise));
+    ngx_js_del_event(ngx_external_ctx(vm,  njs_vm_external_ptr(vm)),
+                     fetch->event);
 
-    return NJS_OK;
+    return ngx_js_fetch_promissified_result(vm, NULL, NJS_ERROR, retval);
 }
 
 
index 0b3f3269c3f27caf47996d55a05f163dd24fa0e6..731fba44b6d76c3cfb7c68d089774b89f98accd2 100644 (file)
@@ -401,11 +401,14 @@ 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:%d", fetch, NGX_ERROR);
 
-    ngx_qjs_fetch_done(fetch, fetch->response_value, NGX_ERROR);
+    ngx_js_del_event(ngx_qjs_external_ctx(cx, external), fetch->event);
 
-    return promise;
+    JS_FreeValue(cx, promise);
+
+    return qjs_promise_result(cx, JS_EXCEPTION);
 }
 
 
index 9bbacf5bc50c59f8b20e4908e19171ee9cd0661e..f3601b8229bdffb550483272f6bdcc69c0d6e2de 100644 (file)
@@ -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');