[njs] http subrequest() method.
Dmitry Volyntsev
xeioex at nginx.com
Wed Mar 21 14:33:27 UTC 2018
details: http://hg.nginx.org/njs/rev/750f7c6f071c
branches:
changeset: 465:750f7c6f071c
user: Dmitry Volyntsev <xeioex at nginx.com>
date: Wed Mar 21 17:33:13 2018 +0300
description:
http subrequest() method.
Creates an nginx's subrequest with the specified arguments and
registers a finalization callback.
req.subrequest(<uri>[, <options>[, <callback>]]):
uri - string.
options - string | object.
string value - uri arguments.
object value can contain:
args, body, method all are string values.
callback - function with the following argument:
reply - the result object with the following properties:
uri, method, status, contentType, contentLength,
headers, args, body, parent.
diffstat:
nginx/ngx_http_js_module.c | 558 +++++++++++++++++++++++++++++++++++++++++++-
njs/njs_error.c | 16 +-
njs/njs_error.h | 1 +
njs/njs_vm.c | 92 +++++++-
njs/njscript.c | 78 ++++++-
njs/njscript.h | 19 +-
njs/test/njs_unit_test.c | 25 ++
7 files changed, 754 insertions(+), 35 deletions(-)
diffs (truncated from 1043 to 1000 lines):
diff -r fa22235730b1 -r 750f7c6f071c nginx/ngx_http_js_module.c
--- a/nginx/ngx_http_js_module.c Wed Mar 21 17:33:12 2018 +0300
+++ b/nginx/ngx_http_js_module.c Wed Mar 21 17:33:13 2018 +0300
@@ -24,6 +24,7 @@ typedef struct {
ngx_str_t content;
const njs_extern_t *req_proto;
const njs_extern_t *res_proto;
+ const njs_extern_t *rep_proto;
} ngx_http_js_loc_conf_t;
@@ -31,6 +32,7 @@ typedef struct {
njs_vm_t *vm;
ngx_log_t *log;
njs_opaque_value_t args[2];
+ ngx_uint_t done;
} ngx_http_js_ctx_t;
@@ -107,6 +109,17 @@ static njs_ret_t ngx_http_js_ext_get_var
void *obj, uintptr_t data);
static njs_ret_t ngx_http_js_ext_get_response(njs_vm_t *vm, njs_value_t *value,
void *obj, uintptr_t data);
+static njs_ret_t ngx_http_js_ext_subrequest(njs_vm_t *vm, njs_value_t *args,
+ nxt_uint_t nargs, njs_index_t unused);
+static ngx_int_t ngx_http_js_subrequest(ngx_http_request_t *r,
+ nxt_str_t *uri_arg, nxt_str_t *args_arg, njs_function_t *callback,
+ ngx_http_request_t **sr);
+static ngx_int_t ngx_http_js_subrequest_done(ngx_http_request_t *r,
+ void *data, ngx_int_t rc);
+static njs_ret_t ngx_http_js_ext_get_parent(njs_vm_t *vm, njs_value_t *value,
+ void *obj, uintptr_t data);
+static njs_ret_t ngx_http_js_ext_get_body(njs_vm_t *vm, njs_value_t *value,
+ void *obj, uintptr_t data);
static njs_host_event_t ngx_http_js_set_timer(njs_external_ptr_t external,
uint64_t delay, njs_vm_event_t vm_event);
@@ -114,7 +127,7 @@ static void ngx_http_js_clear_timer(njs_
njs_host_event_t event);
static void ngx_http_js_timer_handler(ngx_event_t *ev);
static void ngx_http_js_handle_event(ngx_http_request_t *r,
- njs_vm_event_t vm_event);
+ njs_vm_event_t vm_event, njs_opaque_value_t *args, nxt_uint_t nargs);
static char *ngx_http_js_include(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
@@ -381,6 +394,118 @@ static njs_external_t ngx_http_js_ext_r
NULL,
NULL,
0 },
+
+ { nxt_string("subrequest"),
+ NJS_EXTERN_METHOD,
+ NULL,
+ 0,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ ngx_http_js_ext_subrequest,
+ 0 },
+};
+
+
+static njs_external_t ngx_http_js_ext_reply[] = {
+
+ { nxt_string("headers"),
+ NJS_EXTERN_OBJECT,
+ NULL,
+ 0,
+ ngx_http_js_ext_get_header_out,
+ NULL,
+ NULL,
+ ngx_http_js_ext_foreach_header_out,
+ ngx_http_js_ext_next_header,
+ NULL,
+ 0 },
+
+ { nxt_string("status"),
+ NJS_EXTERN_PROPERTY,
+ NULL,
+ 0,
+ ngx_http_js_ext_get_status,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ offsetof(ngx_http_request_t, headers_out.status) },
+
+ { nxt_string("uri"),
+ NJS_EXTERN_PROPERTY,
+ NULL,
+ 0,
+ ngx_http_js_ext_get_string,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ offsetof(ngx_http_request_t, uri) },
+
+ { nxt_string("method"),
+ NJS_EXTERN_PROPERTY,
+ NULL,
+ 0,
+ ngx_http_js_ext_get_string,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ offsetof(ngx_http_request_t, method_name) },
+
+ { nxt_string("contentType"),
+ NJS_EXTERN_PROPERTY,
+ NULL,
+ 0,
+ ngx_http_js_ext_get_string,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ offsetof(ngx_http_request_t, headers_out.content_type) },
+
+ { nxt_string("contentLength"),
+ NJS_EXTERN_PROPERTY,
+ NULL,
+ 0,
+ ngx_http_js_ext_get_content_length,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ 0 },
+
+ { nxt_string("parent"),
+ NJS_EXTERN_PROPERTY,
+ NULL,
+ 0,
+ ngx_http_js_ext_get_parent,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ 0 },
+
+ { nxt_string("body"),
+ NJS_EXTERN_PROPERTY,
+ NULL,
+ 0,
+ ngx_http_js_ext_get_body,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ 0 },
};
@@ -409,6 +534,18 @@ static njs_external_t ngx_http_js_exter
NULL,
NULL,
0 },
+
+ { nxt_string("reply"),
+ NJS_EXTERN_OBJECT,
+ ngx_http_js_ext_reply,
+ nxt_nitems(ngx_http_js_ext_reply),
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ 0 },
};
@@ -916,20 +1053,13 @@ static njs_ret_t
ngx_http_js_ext_get_status(njs_vm_t *vm, njs_value_t *value, void *obj,
uintptr_t data)
{
- size_t len;
- u_char *p;
ngx_http_request_t *r;
r = (ngx_http_request_t *) obj;
- p = ngx_pnalloc(r->pool, 3);
- if (p == NULL) {
- return NJS_ERROR;
- }
-
- len = ngx_snprintf(p, 3, "%ui", r->headers_out.status) - p;
-
- return njs_string_create(vm, value, p, len, 0);
+ njs_value_number_set(njs_vm_retval(vm), r->headers_out.status);
+
+ return NJS_OK;
}
@@ -957,20 +1087,13 @@ static njs_ret_t
ngx_http_js_ext_get_content_length(njs_vm_t *vm, njs_value_t *value, void *obj,
uintptr_t data)
{
- size_t len;
- u_char *p;
ngx_http_request_t *r;
r = (ngx_http_request_t *) obj;
- p = ngx_pnalloc(r->pool, NGX_OFF_T_LEN);
- if (p == NULL) {
- return NJS_ERROR;
- }
-
- len = ngx_sprintf(p, "%O", r->headers_out.content_length_n) - p;
-
- return njs_string_create(vm, value, p, len, 0);
+ njs_value_number_set(njs_vm_retval(vm), r->headers_out.content_length_n);
+
+ return NJS_OK;
}
@@ -1324,6 +1447,383 @@ ngx_http_js_ext_get_response(njs_vm_t *v
}
+static njs_ret_t
+ngx_http_js_ext_subrequest(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
+ njs_index_t unused)
+{
+ ngx_int_t rc;
+ nxt_str_t uri_arg, args_arg, method_name, body_arg;
+ ngx_uint_t cb_index, method, n, has_body;
+ const char *description;
+ njs_value_t *arg2, *options, *value;
+ njs_function_t *callback;
+ ngx_http_request_t *r, *sr;
+ ngx_http_request_body_t *rb;
+
+ static const struct {
+ ngx_str_t name;
+ ngx_uint_t value;
+ } methods[] = {
+ { ngx_string("GET"), NGX_HTTP_GET },
+ { ngx_string("POST"), NGX_HTTP_POST },
+ { ngx_string("HEAD"), NGX_HTTP_HEAD },
+ { ngx_string("OPTIONS"), NGX_HTTP_OPTIONS },
+ { ngx_string("PROPFIND"), NGX_HTTP_PROPFIND },
+ { ngx_string("PUT"), NGX_HTTP_PUT },
+ { ngx_string("MKCOL"), NGX_HTTP_MKCOL },
+ { ngx_string("DELETE"), NGX_HTTP_DELETE },
+ { ngx_string("COPY"), NGX_HTTP_COPY },
+ { ngx_string("MOVE"), NGX_HTTP_MOVE },
+ { ngx_string("PROPPATCH"), NGX_HTTP_PROPPATCH },
+ { ngx_string("LOCK"), NGX_HTTP_LOCK },
+ { ngx_string("UNLOCK"), NGX_HTTP_UNLOCK },
+ { ngx_string("PATCH"), NGX_HTTP_PATCH },
+ { ngx_string("TRACE"), NGX_HTTP_TRACE },
+ };
+
+ static const nxt_str_t args_key = nxt_string("args");
+ static const nxt_str_t method_key = nxt_string("method");
+ static const nxt_str_t body_key = nxt_string("body");
+
+ if (nargs < 2) {
+ description = "too few arguments";
+ goto exception;
+ }
+
+ r = njs_value_data(njs_argument(args, 0));
+
+ if (njs_vm_value_to_ext_string(vm, &uri_arg, njs_argument(args, 1), 0)
+ == NJS_ERROR)
+ {
+ description = "failed to convert uri arg";
+ goto exception;
+ }
+
+ options = NULL;
+
+ method = 0;
+ args_arg.length = 0;
+ body_arg.length = 0;
+ has_body = 0;
+
+ if (nargs > 2 && !njs_value_is_function(njs_argument(args, 2))) {
+ arg2 = njs_argument(args, 2);
+
+ if (njs_value_is_object(arg2)) {
+ options = arg2;
+
+ } else if (njs_value_is_string(arg2)) {
+ if (njs_vm_value_to_ext_string(vm, &args_arg, arg2, 0)
+ == NJS_ERROR)
+ {
+ description = "failed to convert args";
+ goto exception;
+ }
+
+ } else {
+ description = "failed to convert args";
+ goto exception;
+ }
+
+ cb_index = 3;
+
+ } else {
+ cb_index = 2;
+ }
+
+ if (options != NULL) {
+ value = njs_vm_object_prop(vm, options, &args_key);
+ if (value != NULL) {
+ if (njs_vm_value_to_ext_string(vm, &args_arg, value, 0)
+ == NJS_ERROR)
+ {
+ description = "failed to convert options.args";
+ goto exception;
+ }
+ }
+
+ value = njs_vm_object_prop(vm, options, &method_key);
+ if (value != NULL) {
+ if (njs_vm_value_to_ext_string(vm, &method_name, value, 0)
+ == NJS_ERROR)
+ {
+ description = "failed to convert options.method";
+ goto exception;
+ }
+
+ n = sizeof(methods) / sizeof(methods[0]);
+
+ while (method < n) {
+ if (method_name.length == methods[method].name.len
+ && ngx_memcmp(method_name.start, methods[method].name.data,
+ method_name.length)
+ == 0)
+ {
+ break;
+ }
+
+ method++;
+ }
+
+ if (method == n) {
+ njs_value_error_set(vm, njs_vm_retval(vm),
+ "unknown method \"%.*s\"",
+ (int) method_name.length,
+ method_name.start);
+
+ return NJS_ERROR;
+ }
+ }
+
+ value = njs_vm_object_prop(vm, options, &body_key);
+ if (value != NULL) {
+ if (njs_vm_value_to_ext_string(vm, &body_arg, value, 0)
+ == NJS_ERROR)
+ {
+ description = "failed to convert options.body";
+ goto exception;
+ }
+
+ has_body = 1;
+ }
+ }
+
+ callback = NULL;
+
+ if (cb_index < nargs) {
+ if (!njs_value_is_function(njs_argument(args, cb_index))) {
+ description = "callback is not a function";
+ goto exception;
+
+ } else {
+ callback = njs_value_function(njs_argument(args, cb_index));
+ }
+ }
+
+ rc = ngx_http_js_subrequest(r, &uri_arg, &args_arg, callback, &sr);
+ if (rc != NGX_OK) {
+ return NJS_ERROR;
+ }
+
+ sr->method = methods[method].value;
+ sr->method_name = methods[method].name;
+ sr->header_only = (sr->method == NGX_HTTP_HEAD) || (callback == NULL);
+
+ if (has_body) {
+ rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t));
+ if (rb == NULL) {
+ return NJS_ERROR;
+ }
+
+ rb->bufs = ngx_alloc_chain_link(r->pool);
+ if (rb->bufs == NULL) {
+ return NJS_ERROR;
+ }
+
+ rb->bufs->next = NULL;
+
+ rb->bufs->buf = ngx_calloc_buf(r->pool);
+ if (rb->bufs->buf == NULL) {
+ return NJS_ERROR;
+ }
+
+ rb->bufs->buf->memory = 1;
+ rb->bufs->buf->last_buf = 1;
+
+ rb->bufs->buf->pos = body_arg.start;
+ rb->bufs->buf->last = body_arg.start + body_arg.length;
+
+ sr->request_body = rb;
+ sr->headers_in.content_length_n = body_arg.length;
+ sr->headers_in.chunked = 0;
+ }
+
+ return NJS_OK;
+
+exception:
+
+ njs_value_error_set(vm, njs_vm_retval(vm), description, NULL);
+
+ return NJS_ERROR;
+}
+
+
+static ngx_int_t
+ngx_http_js_subrequest(ngx_http_request_t *r, nxt_str_t *uri_arg,
+ nxt_str_t *args_arg, njs_function_t *callback, ngx_http_request_t **sr)
+{
+ ngx_int_t flags;
+ ngx_str_t uri, args;
+ const char *description;
+ njs_vm_event_t vm_event;
+ ngx_http_js_ctx_t *ctx;
+ ngx_http_post_subrequest_t *ps;
+
+ 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) {
+ description = "internal error";
+ goto exception;
+ }
+
+ vm_event = njs_vm_add_event(ctx->vm, callback, NULL, NULL);
+ if (vm_event == NULL) {
+ description = "internal error";
+ goto exception;
+ }
+
+ ps->handler = ngx_http_js_subrequest_done;
+ ps->data = vm_event;
+
+ flags |= NGX_HTTP_SUBREQUEST_IN_MEMORY;
+
+ } else {
+ ps = NULL;
+ vm_event = NULL;
+ }
+
+ uri.len = uri_arg->length;
+ uri.data = uri_arg->start;
+
+ args.len = args_arg->length;
+ args.data = args_arg->start;
+
+ if (ngx_http_subrequest(r, &uri, args.len ? &args : NULL, sr, ps, flags)
+ != NGX_OK)
+ {
+ if (vm_event != NULL) {
+ njs_vm_del_event(ctx->vm, vm_event);
+ }
+
+ description = "subrequest creation failed";
+ goto exception;
+ }
+
+ return NJS_OK;
+
+exception:
+
+ njs_value_error_set(ctx->vm, njs_vm_retval(ctx->vm), description, NULL);
+
+ return NJS_ERROR;
+}
+
+
+static ngx_int_t
+ngx_http_js_subrequest_done(ngx_http_request_t *r, void *data, ngx_int_t rc)
+{
+ njs_vm_event_t vm_event = data;
+
+ nxt_int_t ret;
+ ngx_http_js_ctx_t *ctx;
+ njs_opaque_value_t reply;
+ ngx_http_js_loc_conf_t *jlcf;
+
+ if (rc != NGX_OK || r->connection->error || r->buffered) {
+ return rc;
+ }
+
+ ctx = ngx_http_get_module_ctx(r, ngx_http_js_module);
+
+ if (ctx && ctx->done) {
+ return NGX_OK;
+ }
+
+ if (ctx == NULL) {
+ ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_js_ctx_t));
+ if (ctx == NULL) {
+ return NGX_ERROR;
+ }
+
+ ngx_http_set_ctx(r, ctx, ngx_http_js_module);
+ }
+
+ ctx->done = 1;
+
+ jlcf = ngx_http_get_module_loc_conf(r->parent, ngx_http_js_module);
+
+ ctx = ngx_http_get_module_ctx(r->parent, ngx_http_js_module);
+
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "js subrequest done s: %ui parent ctx: %p",
+ r->headers_out.status, ctx);
+
+ if (ctx == NULL) {
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+ "js subrequest: failed to get the parent context");
+
+ return NGX_ERROR;
+ }
+
+ ret = njs_vm_external_create(ctx->vm, &reply, jlcf->rep_proto, r);
+ if (ret != NXT_OK) {
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+ "js subrequest reply creation failed");
+
+ return NGX_ERROR;
+ }
+
+ ngx_http_js_handle_event(r->parent, vm_event, &reply, 1);
+
+ return NGX_OK;
+}
+
+
+static njs_ret_t
+ngx_http_js_ext_get_parent(njs_vm_t *vm, njs_value_t *value, void *obj,
+ uintptr_t data)
+{
+ ngx_http_js_ctx_t *ctx;
+ ngx_http_request_t *r;
+
+ r = (ngx_http_request_t *) obj;
+
+ ctx = ngx_http_get_module_ctx(r->parent, ngx_http_js_module);
+
+ if (ctx == NULL) {
+ njs_value_error_set(vm, njs_vm_retval(vm),
+ "failed to get the parent context", NULL);
+ return NJS_ERROR;
+ }
+
+ njs_vm_retval_set(ctx->vm, &ctx->args[0]);
+
+ return NJS_OK;
+}
+
+
+static njs_ret_t
+ngx_http_js_ext_get_body(njs_vm_t *vm, njs_value_t *value, void *obj,
+ uintptr_t data)
+{
+ size_t len;
+ u_char *p;
+ ngx_buf_t *b;
+ ngx_http_request_t *r;
+
+ r = (ngx_http_request_t *) obj;
+
+ b = r->out ? r->out->buf : NULL;
+
+ len = b ? b->last - b->pos : 0;
+
+ p = njs_string_alloc(vm, value, len, 0);
+ if (p == NULL) {
+ return NJS_ERROR;
+ }
+
+ if (len) {
+ ngx_memcpy(p, b->pos, len);
+ }
+
+ return NJS_OK;
+}
+
+
static njs_host_event_t
ngx_http_js_set_timer(njs_external_ptr_t external, uint64_t delay,
njs_vm_event_t vm_event)
@@ -1382,14 +1882,15 @@ ngx_http_js_timer_handler(ngx_event_t *e
c = r->connection;
- ngx_http_js_handle_event(r, js_event->vm_event);
+ ngx_http_js_handle_event(r, js_event->vm_event, NULL, 0);
ngx_http_run_posted_requests(c);
}
static void
-ngx_http_js_handle_event(ngx_http_request_t *r, njs_vm_event_t vm_event)
+ngx_http_js_handle_event(ngx_http_request_t *r, njs_vm_event_t vm_event,
+ njs_opaque_value_t *args, nxt_uint_t nargs)
{
njs_ret_t rc;
nxt_str_t exception;
@@ -1397,7 +1898,7 @@ ngx_http_js_handle_event(ngx_http_reques
ctx = ngx_http_get_module_ctx(r, ngx_http_js_module);
- njs_vm_post_event(ctx->vm, vm_event);
+ njs_vm_post_event(ctx->vm, vm_event, args, nargs);
rc = njs_vm_run(ctx->vm);
@@ -1525,6 +2026,13 @@ ngx_http_js_include(ngx_conf_t *cf, ngx_
return NGX_CONF_ERROR;
}
+ jlcf->rep_proto = njs_vm_external_prototype(jlcf->vm,
+ &ngx_http_js_externals[2]);
+ if (jlcf->rep_proto == NULL) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "failed to add reply proto");
+ return NGX_CONF_ERROR;
+ }
+
rc = njs_vm_compile(jlcf->vm, &start, end);
if (rc != NJS_OK) {
@@ -1621,6 +2129,7 @@ ngx_http_js_create_loc_conf(ngx_conf_t *
* conf->vm = NULL;
* conf->req_proto = NULL;
* conf->res_proto = NULL;
+ * conf->rep_proto = NULL;
*/
return conf;
@@ -1637,6 +2146,7 @@ ngx_http_js_merge_loc_conf(ngx_conf_t *c
conf->vm = prev->vm;
conf->req_proto = prev->req_proto;
conf->res_proto = prev->res_proto;
+ conf->rep_proto = prev->rep_proto;
}
return NGX_CONF_OK;
diff -r fa22235730b1 -r 750f7c6f071c njs/njs_error.c
--- a/njs/njs_error.c Wed Mar 21 17:33:12 2018 +0300
+++ b/njs/njs_error.c Wed Mar 21 17:33:13 2018 +0300
@@ -486,8 +486,8 @@ const njs_object_init_t njs_uri_error_c
};
-static void
-njs_set_memory_error(njs_vm_t *vm)
+void
+njs_set_memory_error(njs_vm_t *vm, njs_value_t *value)
{
njs_object_t *object;
njs_object_prototype_t *prototypes;
@@ -507,17 +507,17 @@ njs_set_memory_error(njs_vm_t *vm)
*/
object->extensible = 0;
- vm->retval.data.type = NJS_OBJECT_INTERNAL_ERROR;
- vm->retval.data.truth = 1;
- vm->retval.data.u.number = NAN;
- vm->retval.data.u.object = object;
+ value->data.type = NJS_OBJECT_INTERNAL_ERROR;
+ value->data.truth = 1;
+ value->data.u.number = NAN;
+ value->data.u.object = object;
}
void
njs_exception_memory_error(njs_vm_t *vm)
{
- njs_set_memory_error(vm);
+ njs_set_memory_error(vm, &vm->retval);
}
@@ -525,7 +525,7 @@ njs_ret_t
njs_memory_error_constructor(njs_vm_t *vm, njs_value_t *args,
nxt_uint_t nargs, njs_index_t unused)
{
- njs_set_memory_error(vm);
+ njs_set_memory_error(vm, &vm->retval);
return NXT_OK;
}
diff -r fa22235730b1 -r 750f7c6f071c njs/njs_error.h
--- a/njs/njs_error.h Wed Mar 21 17:33:12 2018 +0300
+++ b/njs/njs_error.h Wed Mar 21 17:33:13 2018 +0300
@@ -29,6 +29,7 @@ void njs_exception_error_create(njs_vm_t
const char* fmt, ...);
void njs_exception_memory_error(njs_vm_t *vm);
+void njs_set_memory_error(njs_vm_t *vm, njs_value_t *value);
njs_object_t *njs_error_alloc(njs_vm_t *vm, njs_value_type_t type,
const njs_value_t *name, const njs_value_t *message);
diff -r fa22235730b1 -r 750f7c6f071c njs/njs_vm.c
--- a/njs/njs_vm.c Wed Mar 21 17:33:12 2018 +0300
+++ b/njs/njs_vm.c Wed Mar 21 17:33:13 2018 +0300
@@ -3655,6 +3655,54 @@ njs_value_number_set(njs_value_t *value,
}
+void
+njs_value_error_set(njs_vm_t *vm, njs_value_t *value, const char *fmt, ...)
+{
+ size_t size;
+ va_list args;
+ nxt_int_t ret;
+ njs_value_t string;
+ njs_object_t *error;
+ char buf[256];
+
+ if (fmt != NULL) {
+ va_start(args, fmt);
+ size = vsnprintf(buf, sizeof(buf), fmt, args);
+ va_end(args);
+
+ } else {
+ size = 0;
+ }
+
+ ret = njs_string_new(vm, &string, (u_char *) buf, size, size);
+ if (nxt_slow_path(ret != NXT_OK)) {
+ goto memory_error;
+ }
+
+ error = njs_error_alloc(vm, NJS_OBJECT_ERROR, NULL, &string);
+ if (nxt_slow_path(error == NULL)) {
+ goto memory_error;
+ }
+
+ value->data.u.object = error;
+ value->type = NJS_OBJECT_ERROR;
+ value->data.truth = 1;
+
+ return;
+
+memory_error:
+
+ njs_set_memory_error(vm, value);
+}
+
+
+nxt_noinline double
+njs_value_number(njs_value_t *value)
+{
+ return value->data.u.number;
+}
+
+
nxt_noinline void *
njs_value_data(njs_value_t *value)
{
@@ -3662,10 +3710,52 @@ njs_value_data(njs_value_t *value)
}
+nxt_noinline njs_function_t *
+njs_value_function(njs_value_t *value)
+{
+ return value->data.u.function;
+}
+
+
nxt_noinline nxt_int_t
njs_value_is_void(njs_value_t *value)
{
- return value->type == NJS_VOID;
+ return njs_is_void(value);
+}
+
+
+nxt_noinline nxt_int_t
+njs_value_is_true(njs_value_t *value)
+{
+ return njs_is_true(value);
+}
+
+
+nxt_noinline nxt_int_t
+njs_value_is_number(njs_value_t *value)
+{
+ return njs_is_number(value);
+}
+
+
+nxt_noinline nxt_int_t
+njs_value_is_string(njs_value_t *value)
+{
+ return njs_is_string(value);
+}
+
+
+nxt_noinline nxt_int_t
+njs_value_is_object(njs_value_t *value)
+{
+ return njs_is_object(value);
+}
+
+
+nxt_noinline nxt_int_t
+njs_value_is_function(njs_value_t *value)
+{
+ return njs_is_function(value);
}
diff -r fa22235730b1 -r 750f7c6f071c njs/njscript.c
--- a/njs/njscript.c Wed Mar 21 17:33:12 2018 +0300
+++ b/njs/njscript.c Wed Mar 21 17:33:13 2018 +0300
@@ -14,6 +14,7 @@
#include <nxt_lvlhsh.h>
#include <nxt_random.h>
#include <nxt_malloc.h>
+#include <nxt_djb_hash.h>
#include <nxt_mem_cache_pool.h>
#include <njscript.h>
#include <njs_vm.h>
@@ -503,6 +504,43 @@ njs_vm_call(njs_vm_t *vm, njs_function_t
}
+njs_vm_event_t
+njs_vm_add_event(njs_vm_t *vm, njs_function_t *function,
+ njs_host_event_t host_ev, njs_event_destructor destructor)
+{
+ njs_event_t *event;
+
+ event = nxt_mem_cache_alloc(vm->mem_cache_pool, sizeof(njs_event_t));
+ if (nxt_slow_path(event == NULL)) {
+ return NULL;
+ }
+
+ event->host_event = host_ev;
+ event->destructor = destructor;
+ event->function = function;
+ event->posted = 0;
+ event->nargs = 0;
+ event->args = NULL;
+
+ if (njs_add_event(vm, event) != NJS_OK) {
+ return NULL;
+ }
+
+ return event;
+}
+
+
+void
+njs_vm_del_event(njs_vm_t *vm, njs_vm_event_t vm_event)
+{
+ njs_event_t *event;
+
+ event = (njs_event_t *) vm_event;
+
+ njs_del_event(vm, event, NJS_EVENT_RELEASE | NJS_EVENT_DELETE);
+}
+
+
nxt_int_t
njs_vm_pending(njs_vm_t *vm)
{
@@ -511,12 +549,24 @@ njs_vm_pending(njs_vm_t *vm)
nxt_int_t
-njs_vm_post_event(njs_vm_t *vm, njs_vm_event_t vm_event)
+njs_vm_post_event(njs_vm_t *vm, njs_vm_event_t vm_event,
+ njs_opaque_value_t *args, nxt_uint_t nargs)
{
njs_event_t *event;
event = (njs_event_t *) vm_event;
+ if (nargs != 0 && !event->posted) {
+ event->nargs = nargs;
+ event->args = nxt_mem_cache_alloc(vm->mem_cache_pool,
+ sizeof(njs_opaque_value_t) * nargs);
+ if (nxt_slow_path(event->args == NULL)) {
+ return NJS_ERROR;
+ }
+
+ memcpy(event->args, args, sizeof(njs_opaque_value_t) * nargs);
+ }
+
if (!event->posted) {
event->posted = 1;
nxt_queue_insert_tail(&vm->posted_events, &event->link);
@@ -639,3 +689,29 @@ njs_ret_t njs_vm_retval_to_ext_string(nj
return njs_vm_value_to_ext_string(vm, retval, &vm->retval, 1);
}
+
+
+njs_value_t *
+njs_vm_object_prop(njs_vm_t *vm, njs_value_t *value, const nxt_str_t *key)
+{
+ nxt_int_t ret;
+ njs_object_prop_t *prop;
+ nxt_lvlhsh_query_t lhq;
+
+ if (nxt_slow_path(!njs_is_object(value))) {
+ return NULL;
+ }
+
+ lhq.key = *key;
+ lhq.key_hash = nxt_djb_hash(lhq.key.start, lhq.key.length);
+ lhq.proto = &njs_object_hash_proto;
+
+ ret = nxt_lvlhsh_find(&value->data.u.object->hash, &lhq);
+ if (nxt_slow_path(ret != NXT_OK)) {
+ return NULL;
+ }
+
+ prop = lhq.value;
+
+ return &prop->value;
+}
diff -r fa22235730b1 -r 750f7c6f071c njs/njscript.h
--- a/njs/njscript.h Wed Mar 21 17:33:12 2018 +0300
+++ b/njs/njscript.h Wed Mar 21 17:33:13 2018 +0300
@@ -139,8 +139,13 @@ NXT_EXPORT njs_vm_t *njs_vm_clone(njs_vm
NXT_EXPORT nxt_int_t njs_vm_call(njs_vm_t *vm, njs_function_t *function,
njs_opaque_value_t *args, nxt_uint_t nargs);
+NXT_EXPORT njs_vm_event_t njs_vm_add_event(njs_vm_t *vm,
+ njs_function_t *function, njs_host_event_t host_ev,
+ njs_event_destructor destructor);
+NXT_EXPORT void njs_vm_del_event(njs_vm_t *vm, njs_vm_event_t vm_event);
NXT_EXPORT nxt_int_t njs_vm_pending(njs_vm_t *vm);
-NXT_EXPORT nxt_int_t njs_vm_post_event(njs_vm_t *vm, njs_vm_event_t vm_event);
+NXT_EXPORT nxt_int_t njs_vm_post_event(njs_vm_t *vm, njs_vm_event_t vm_event,
+ njs_opaque_value_t *args, nxt_uint_t nargs);
NXT_EXPORT nxt_int_t njs_vm_run(njs_vm_t *vm);
@@ -174,10 +179,22 @@ NXT_EXPORT njs_ret_t njs_vm_retval_to_ex
NXT_EXPORT void njs_value_void_set(njs_value_t *value);
NXT_EXPORT void njs_value_boolean_set(njs_value_t *value, int yn);
NXT_EXPORT void njs_value_number_set(njs_value_t *value, double num);
+NXT_EXPORT void njs_value_error_set(njs_vm_t *vm, njs_value_t *value,
+ const char *fmt, ...);
+
+NXT_EXPORT double njs_value_number(njs_value_t *value);
NXT_EXPORT void *njs_value_data(njs_value_t *value);
+NXT_EXPORT njs_function_t *njs_value_function(njs_value_t *value);
NXT_EXPORT nxt_int_t njs_value_is_void(njs_value_t *value);
+NXT_EXPORT nxt_int_t njs_value_is_true(njs_value_t *value);
+NXT_EXPORT nxt_int_t njs_value_is_number(njs_value_t *value);
+NXT_EXPORT nxt_int_t njs_value_is_string(njs_value_t *value);
+NXT_EXPORT nxt_int_t njs_value_is_object(njs_value_t *value);
+NXT_EXPORT nxt_int_t njs_value_is_function(njs_value_t *value);
+NXT_EXPORT njs_value_t *njs_vm_object_prop(njs_vm_t *vm, njs_value_t *value,
+ const nxt_str_t *key);
extern const nxt_mem_proto_t njs_vm_mem_cache_pool_proto;
diff -r fa22235730b1 -r 750f7c6f071c njs/test/njs_unit_test.c
--- a/njs/test/njs_unit_test.c Wed Mar 21 17:33:12 2018 +0300
+++ b/njs/test/njs_unit_test.c Wed Mar 21 17:33:13 2018 +0300
@@ -3867,6 +3867,9 @@ static njs_unit_test_t njs_test[] =
" valueOf: function() { return 1 } }; a"),
nxt_string("1") },
More information about the nginx-devel
mailing list