[njs] HTTP: introduced promise support in r.subrequest().

Dmitry Volyntsev xeioex at nginx.com
Thu Jan 16 16:35:02 UTC 2020


details:   https://hg.nginx.org/njs/rev/6fccbc9f1288
branches:  
changeset: 1301:6fccbc9f1288
user:      Dmitry Volyntsev <xeioex at nginx.com>
date:      Thu Jan 16 19:18:39 2020 +0300
description:
HTTP: introduced promise support in r.subrequest().

If callback is not provided r.subrequest() returns an ordinary
Promise object that resolves to subrequest response object.

diffstat:

 nginx/ngx_http_js_module.c |  86 ++++++++++++++++++++++++++++++++-------------
 src/njs.h                  |  10 +++++
 src/njs_function.c         |  18 +++++++++
 src/njs_promise.c          |  22 +++++++++++
 src/njs_value.h            |   2 -
 5 files changed, 111 insertions(+), 27 deletions(-)

diffs (254 lines):

diff -r cb4f1052954f -r 6fccbc9f1288 nginx/ngx_http_js_module.c
--- a/nginx/ngx_http_js_module.c	Thu Jan 16 15:14:38 2020 +0300
+++ b/nginx/ngx_http_js_module.c	Thu Jan 16 19:18:39 2020 +0300
@@ -32,6 +32,7 @@ typedef struct {
     njs_opaque_value_t   request;
     njs_opaque_value_t   request_body;
     ngx_str_t            redirect_uri;
+    njs_opaque_value_t   promise_callbacks[2];
 } ngx_http_js_ctx_t;
 
 
@@ -1760,10 +1761,30 @@ ngx_http_js_ext_set_variable(njs_vm_t *v
 
 
 static njs_int_t
+ngx_http_js_promise_trampoline(njs_vm_t *vm, njs_value_t *args,
+    njs_uint_t nargs, njs_index_t unused)
+{
+    njs_function_t      *callback;
+    ngx_http_js_ctx_t   *ctx;
+    ngx_http_request_t  *r;
+
+    r = njs_vm_external(vm, njs_argument(args, 1));
+    ctx = ngx_http_get_module_ctx(r, ngx_http_js_module);
+
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "js subrequest promise trampoline ctx: %p", ctx);
+
+    callback = njs_value_function(njs_value_arg(&ctx->promise_callbacks[0]));
+
+    return njs_vm_call(vm, callback, njs_argument(args, 1), 1);
+}
+
+
+static njs_int_t
 ngx_http_js_ext_subrequest(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     njs_index_t unused)
 {
-    ngx_int_t                 rc;
+    ngx_int_t                 rc, promise;
     njs_str_t                 uri_arg, args_arg, method_name, body_arg;
     ngx_uint_t                method, methods_max, has_body;
     njs_value_t              *value, *arg, *options;
@@ -1799,6 +1820,7 @@ ngx_http_js_ext_subrequest(njs_vm_t *vm,
 
     r = njs_vm_external(vm, njs_arg(args, nargs, 0));
     if (njs_slow_path(r == NULL)) {
+        njs_vm_error(vm, "this is not an external");
         return NJS_ERROR;
     }
 
@@ -1829,6 +1851,7 @@ ngx_http_js_ext_subrequest(njs_vm_t *vm,
     args_arg.length = 0;
     args_arg.start = NULL;
     has_body = 0;
+    promise = 0;
 
     arg = njs_arg(args, nargs, 2);
 
@@ -1901,6 +1924,15 @@ ngx_http_js_ext_subrequest(njs_vm_t *vm,
         }
     }
 
+    if (callback == NULL) {
+        callback = njs_vm_function_alloc(vm, ngx_http_js_promise_trampoline);
+        if (callback == NULL) {
+            goto memory_error;
+        }
+
+        promise = 1;
+    }
+
     rc  = ngx_http_js_subrequest(r, &uri_arg, &args_arg, callback, &sr);
     if (rc != NGX_OK) {
         return NJS_ERROR;
@@ -1916,7 +1948,7 @@ ngx_http_js_ext_subrequest(njs_vm_t *vm,
         sr->method_name.data = method_name.start;
     }
 
-    sr->header_only = (sr->method == NGX_HTTP_HEAD) || (callback == NULL);
+    sr->header_only = (sr->method == NGX_HTTP_HEAD);
 
     if (has_body) {
         rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t));
@@ -1949,6 +1981,18 @@ ngx_http_js_ext_subrequest(njs_vm_t *vm,
         sr->headers_in.chunked = 0;
     }
 
+    if (promise) {
+        ctx = ngx_pcalloc(sr->pool, sizeof(ngx_http_js_ctx_t));
+        if (ctx == NULL) {
+            return NGX_ERROR;
+        }
+
+        ngx_http_set_ctx(sr, ctx, ngx_http_js_module);
+
+        return njs_vm_promise_create(vm, njs_vm_retval(vm),
+                                     njs_value_arg(&ctx->promise_callbacks));
+    }
+
     return NJS_OK;
 
 memory_error:
@@ -1971,31 +2015,23 @@ ngx_http_js_subrequest(ngx_http_request_
 
     ctx = ngx_http_get_module_ctx(r, ngx_http_js_module);
 
-    flags = NGX_HTTP_SUBREQUEST_BACKGROUND;
-
-    if (callback != NULL) {
-        ps = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t));
-        if (ps == NULL) {
-            njs_vm_error(ctx->vm, "internal error");
-            return NJS_ERROR;
-        }
-
-        vm_event = njs_vm_add_event(ctx->vm, callback, 1, NULL, NULL);
-        if (vm_event == NULL) {
-            njs_vm_error(ctx->vm, "internal error");
-            return NJS_ERROR;
-        }
-
-        ps->handler = ngx_http_js_subrequest_done;
-        ps->data = vm_event;
-
-        flags |= NGX_HTTP_SUBREQUEST_IN_MEMORY;
-
-    } else {
-        ps = NULL;
-        vm_event = NULL;
+    flags = NGX_HTTP_SUBREQUEST_BACKGROUND | NGX_HTTP_SUBREQUEST_IN_MEMORY;
+
+    ps = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t));
+    if (ps == NULL) {
+        njs_vm_error(ctx->vm, "internal error");
+        return NJS_ERROR;
     }
 
+    vm_event = njs_vm_add_event(ctx->vm, callback, 1, NULL, NULL);
+    if (vm_event == NULL) {
+        njs_vm_error(ctx->vm, "internal error");
+        return NJS_ERROR;
+    }
+
+    ps->handler = ngx_http_js_subrequest_done;
+    ps->data = vm_event;
+
     uri.len = uri_arg->length;
     uri.data = uri_arg->start;
 
diff -r cb4f1052954f -r 6fccbc9f1288 src/njs.h
--- a/src/njs.h	Thu Jan 16 15:14:38 2020 +0300
+++ b/src/njs.h	Thu Jan 16 19:18:39 2020 +0300
@@ -102,6 +102,9 @@ struct njs_external_s {
 };
 
 
+typedef njs_int_t (*njs_function_native_t) (njs_vm_t *vm, njs_value_t *args,
+    njs_uint_t nargs, njs_index_t retval);
+
 /*
  * NJS and event loops.
  *
@@ -238,6 +241,9 @@ NJS_EXPORT njs_int_t njs_vm_external_cre
 NJS_EXPORT njs_external_ptr_t njs_vm_external(njs_vm_t *vm,
     const njs_value_t *value);
 
+NJS_EXPORT njs_function_t *njs_vm_function_alloc(njs_vm_t *vm,
+    njs_function_native_t native);
+
 NJS_EXPORT void njs_disassembler(njs_vm_t *vm);
 NJS_EXPORT void njs_disassemble(u_char *start, u_char *end);
 
@@ -316,4 +322,8 @@ NJS_EXPORT njs_int_t njs_vm_json_parse(n
 NJS_EXPORT njs_int_t njs_vm_json_stringify(njs_vm_t *vm, njs_value_t *args,
     njs_uint_t nargs);
 
+NJS_EXPORT njs_int_t njs_vm_promise_create(njs_vm_t *vm, njs_value_t *retval,
+    njs_value_t *callbacks);
+
+
 #endif /* _NJS_H_INCLUDED_ */
diff -r cb4f1052954f -r 6fccbc9f1288 src/njs_function.c
--- a/src/njs_function.c	Thu Jan 16 15:14:38 2020 +0300
+++ b/src/njs_function.c	Thu Jan 16 19:18:39 2020 +0300
@@ -74,6 +74,24 @@ fail:
 
 
 njs_function_t *
+njs_vm_function_alloc(njs_vm_t *vm, njs_function_native_t native)
+{
+    njs_function_t  *function;
+
+    function = njs_mp_zalloc(vm->mem_pool, sizeof(njs_function_t));
+    if (njs_slow_path(function == NULL)) {
+        return NULL;
+    }
+
+    function->native = 1;
+    function->args_offset = 1;
+    function->u.native = native;
+
+    return function;
+}
+
+
+njs_function_t *
 njs_function_value_copy(njs_vm_t *vm, njs_value_t *value)
 {
     njs_function_t  *function, *copy;
diff -r cb4f1052954f -r 6fccbc9f1288 src/njs_promise.c
--- a/src/njs_promise.c	Thu Jan 16 15:14:38 2020 +0300
+++ b/src/njs_promise.c	Thu Jan 16 19:18:39 2020 +0300
@@ -140,6 +140,28 @@ njs_promise_constructor(njs_vm_t *vm, nj
 }
 
 
+njs_int_t
+njs_vm_promise_create(njs_vm_t *vm, njs_value_t *retval, njs_value_t *callbacks)
+{
+    njs_int_t      ret;
+    njs_promise_t  *promise;
+
+    promise = njs_promise_alloc(vm);
+    if (njs_slow_path(promise == NULL)) {
+        return NJS_ERROR;
+    }
+
+    ret = njs_promise_create_resolving_functions(vm, promise, callbacks);
+    if (njs_slow_path(ret != NJS_OK)) {
+        return NJS_ERROR;
+    }
+
+    njs_set_promise(retval, promise);
+
+    return NJS_OK;
+}
+
+
 static njs_promise_t *
 njs_promise_constructor_call(njs_vm_t *vm, njs_function_t *function)
 {
diff -r cb4f1052954f -r 6fccbc9f1288 src/njs_value.h
--- a/src/njs_value.h	Thu Jan 16 15:14:38 2020 +0300
+++ b/src/njs_value.h	Thu Jan 16 19:18:39 2020 +0300
@@ -108,8 +108,6 @@ typedef struct njs_object_init_s      nj
  */
 typedef njs_int_t (*njs_prop_handler_t) (njs_vm_t *vm, njs_object_prop_t *prop,
     njs_value_t *value, njs_value_t *setval, njs_value_t *retval);
-typedef njs_int_t (*njs_function_native_t) (njs_vm_t *vm, njs_value_t *args,
-    njs_uint_t nargs, njs_index_t retval);
 
 #if (!NJS_HAVE_GCC_ATTRIBUTE_ALIGNED)
 #error "aligned attribute is required"


More information about the nginx-devel mailing list