Welcome! Log In Create A New Profile

Advanced

[njs] Modules: introduced engine API.

Anonymous User
September 17, 2024 09:08PM
details: https://github.com/nginx/njs/commit/9b6744129ce4c18e74b5e41cd1da66f2cbadcf36
branches: master
commit: 9b6744129ce4c18e74b5e41cd1da66f2cbadcf36
user: Dmitry Volyntsev <xeioex@nginx.com>
date: Mon, 10 Jun 2024 22:58:24 -0700
description:
Modules: introduced engine API.

No functional changes.

---
nginx/ngx_http_js_module.c | 337 ++++++++++++++-------------
nginx/ngx_js.c | 533 ++++++++++++++++++++++++++++++++-----------
nginx/ngx_js.h | 98 ++++++--
nginx/ngx_js_fetch.c | 12 +-
nginx/ngx_stream_js_module.c | 385 +++++++++++++++++--------------
5 files changed, 873 insertions(+), 492 deletions(-)

diff --git a/nginx/ngx_http_js_module.c b/nginx/ngx_http_js_module.c
index 7f2eded2..35f988d0 100644
--- a/nginx/ngx_http_js_module.c
+++ b/nginx/ngx_http_js_module.c
@@ -48,14 +48,13 @@ typedef struct {
#define NJS_HEADER_ARRAY 0x4


-typedef struct {
+typedef struct ngx_http_js_ctx_s ngx_http_js_ctx_t;
+
+struct ngx_http_js_ctx_s {
NGX_JS_COMMON_CTX;
- ngx_log_t *log;
ngx_uint_t done;
ngx_int_t status;
- njs_opaque_value_t retval;
- njs_opaque_value_t request;
- njs_opaque_value_t args;
+ njs_opaque_value_t rargs;
njs_opaque_value_t request_body;
njs_opaque_value_t response_body;
ngx_str_t redirect_uri;
@@ -65,9 +64,13 @@ typedef struct {
ngx_chain_t **last_out;
ngx_chain_t *free;
ngx_chain_t *busy;
+ ngx_int_t (*body_filter)(ngx_http_request_t *r,
+ ngx_http_js_loc_conf_t *jlcf,
+ ngx_http_js_ctx_t *ctx,
+ ngx_chain_t *in);

ngx_js_periodic_t *periodic;
-} ngx_http_js_ctx_t;
+};


typedef struct {
@@ -299,6 +302,11 @@ static ngx_flag_t ngx_http_js_ssl_verify(ngx_http_request_t *r);
static ngx_int_t ngx_http_js_parse_unsafe_uri(ngx_http_request_t *r,
njs_str_t *uri, njs_str_t *args);

+static ngx_conf_bitmask_t ngx_http_js_engines[] = {
+ { ngx_string("njs"), NGX_ENGINE_NJS },
+ { ngx_null_string, 0 }
+};
+
#if (NGX_HTTP_SSL)

static ngx_conf_bitmask_t ngx_http_js_ssl_protocols[] = {
@@ -313,6 +321,13 @@ static ngx_conf_bitmask_t ngx_http_js_ssl_protocols[] = {

static ngx_command_t ngx_http_js_commands[] = {

+ { ngx_string("js_engine"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+ ngx_js_engine,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_js_loc_conf_t, type),
+ &ngx_http_js_engines },
+
{ ngx_string("js_import"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE13,
ngx_js_import,
@@ -960,8 +975,8 @@ ngx_http_js_content_event_handler(ngx_http_request_t *r)

ctx->status = NGX_HTTP_INTERNAL_SERVER_ERROR;

- rc = ngx_js_name_call(ctx->vm, &jlcf->content, r->connection->log,
- &ctx->request, 1);
+ rc = ctx->engine->call((ngx_js_ctx_t *) ctx, &jlcf->content, &ctx->args[0],
+ 1);

if (rc == NGX_ERROR) {
ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
@@ -990,7 +1005,7 @@ ngx_http_js_content_write_event_handler(ngx_http_request_t *r)

ctx = ngx_http_get_module_ctx(r, ngx_http_js_module);

- if (!ngx_vm_pending(ctx)) {
+ if (!ngx_js_ctx_pending(ctx)) {
ngx_http_js_content_finalize(r, ctx);
return;
}
@@ -1086,13 +1101,13 @@ ngx_http_js_header_filter(ngx_http_request_t *r)
ctx = ngx_http_get_module_ctx(r, ngx_http_js_module);

ctx->filter = 1;
- pending = ngx_vm_pending(ctx);
+ pending = ngx_js_ctx_pending(ctx);

ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http js header call \"%V\"", &jlcf->header_filter);

- rc = ngx_js_name_call(ctx->vm, &jlcf->header_filter, r->connection->log,
- &ctx->request, 1);
+ rc = ctx->engine->call((ngx_js_ctx_t *) ctx, &jlcf->header_filter,
+ &ctx->args[0], 1);

if (rc == NGX_ERROR) {
return NGX_ERROR;
@@ -1110,51 +1125,28 @@ ngx_http_js_header_filter(ngx_http_request_t *r)


static ngx_int_t
-ngx_http_js_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
+ngx_http_njs_body_filter(ngx_http_request_t *r, ngx_http_js_loc_conf_t *jlcf,
+ ngx_http_js_ctx_t *ctx, ngx_chain_t *in)
{
- size_t len;
- u_char *p;
- ngx_int_t rc;
- njs_int_t ret, pending;
- ngx_buf_t *b;
- ngx_chain_t *out, *cl;
- ngx_connection_t *c;
- ngx_http_js_ctx_t *ctx;
- njs_opaque_value_t last_key, last;
- ngx_http_js_loc_conf_t *jlcf;
- njs_opaque_value_t arguments[3];
+ size_t len;
+ u_char *p;
+ njs_vm_t *vm;
+ ngx_int_t rc;
+ njs_int_t ret, pending;
+ ngx_buf_t *b;
+ ngx_chain_t *cl;
+ ngx_connection_t *c;
+ njs_opaque_value_t last_key, last;
+ njs_opaque_value_t arguments[3];

static const njs_str_t last_str = njs_str("last");

- jlcf = ngx_http_get_module_loc_conf(r, ngx_http_js_module);
-
- if (jlcf->body_filter.len == 0 || in == NULL) {
- return ngx_http_next_body_filter(r, in);
- }
-
- ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
- "http js body filter");
-
- rc = ngx_http_js_init_vm(r, ngx_http_js_request_proto_id);
-
- if (rc == NGX_ERROR || rc == NGX_DECLINED) {
- return NGX_ERROR;
- }
-
- ctx = ngx_http_get_module_ctx(r, ngx_http_js_module);
-
- if (ctx->done) {
- return ngx_http_next_body_filter(r, in);
- }
-
c = r->connection;
+ vm = ctx->engine->u.njs.vm;

- ctx->filter = 1;
- ctx->last_out = &out;
+ njs_value_assign(&arguments[0], &ctx->args[0]);

- njs_value_assign(&arguments[0], &ctx->request);
-
- njs_vm_value_string_create(ctx->vm, njs_value_arg(&last_key),
+ njs_vm_value_string_create(vm, njs_value_arg(&last_key),
last_str.start, last_str.length);

while (in != NULL) {
@@ -1166,7 +1158,7 @@ ngx_http_js_body_filter(ngx_http_request_t *r, ngx_chain_t *in)

p = ngx_pnalloc(r->pool, len);
if (p == NULL) {
- njs_vm_memory_error(ctx->vm);
+ njs_vm_memory_error(vm);
return NJS_ERROR;
}

@@ -1174,7 +1166,7 @@ ngx_http_js_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
ngx_memcpy(p, b->pos, len);
}

- ret = ngx_js_prop(ctx->vm, jlcf->buffer_type,
+ ret = ngx_js_prop(vm, jlcf->buffer_type,
njs_value_arg(&arguments[1]), p, len);
if (ret != NJS_OK) {
return ret;
@@ -1182,20 +1174,20 @@ ngx_http_js_body_filter(ngx_http_request_t *r, ngx_chain_t *in)

njs_value_boolean_set(njs_value_arg(&last), b->last_buf);

- ret = njs_vm_object_alloc(ctx->vm, njs_value_arg(&arguments[2]),
+ ret = njs_vm_object_alloc(vm, njs_value_arg(&arguments[2]),
njs_value_arg(&last_key),
njs_value_arg(&last), NULL);
if (ret != NJS_OK) {
return ret;
}

- pending = ngx_vm_pending(ctx);
+ pending = ngx_js_ctx_pending(ctx);

ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
"http js body call \"%V\"", &jlcf->body_filter);

- rc = ngx_js_name_call(ctx->vm, &jlcf->body_filter, c->log,
- &arguments[0], 3);
+ rc = ctx->engine->call((ngx_js_ctx_t *) ctx, &jlcf->body_filter,
+ &arguments[0], 3);

if (rc == NGX_ERROR) {
return NGX_ERROR;
@@ -1225,13 +1217,54 @@ ngx_http_js_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
in = in->next;
}

+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_js_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
+{
+ ngx_int_t rc;
+ ngx_chain_t *out;
+ ngx_http_js_ctx_t *ctx;
+ ngx_http_js_loc_conf_t *jlcf;
+
+ jlcf = ngx_http_get_module_loc_conf(r, ngx_http_js_module);
+
+ if (jlcf->body_filter.len == 0 || in == NULL) {
+ return ngx_http_next_body_filter(r, in);
+ }
+
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http js body filter");
+
+ rc = ngx_http_js_init_vm(r, ngx_http_js_request_proto_id);
+
+ if (rc == NGX_ERROR || rc == NGX_DECLINED) {
+ return NGX_ERROR;
+ }
+
+ ctx = ngx_http_get_module_ctx(r, ngx_http_js_module);
+
+ if (ctx->done) {
+ return ngx_http_next_body_filter(r, in);
+ }
+
+ ctx->filter = 1;
+ ctx->last_out = &out;
+
+ rc = ctx->body_filter(r, jlcf, ctx, in);
+ if (rc != NGX_OK) {
+ return NGX_ERROR;
+ }
+
*ctx->last_out = NULL;

- if (out != NULL || c->buffered) {
+ if (out != NULL || r->connection->buffered) {
rc = ngx_http_next_body_filter(r, out);

- ngx_chain_update_chains(c->pool, &ctx->free, &ctx->busy, &out,
- (ngx_buf_tag_t) &ngx_http_js_module);
+ ngx_chain_update_chains(r->connection->pool, &ctx->free, &ctx->busy,
+ &out, (ngx_buf_tag_t) &ngx_http_js_module);

} else {
rc = NGX_OK;
@@ -1249,8 +1282,7 @@ ngx_http_js_variable_set(ngx_http_request_t *r, ngx_http_variable_value_t *v,

ngx_int_t rc;
njs_int_t pending;
- ngx_str_t *fname;
- njs_str_t value;
+ ngx_str_t *fname, value;
ngx_http_js_ctx_t *ctx;

fname = &vdata->fname;
@@ -1271,10 +1303,9 @@ ngx_http_js_variable_set(ngx_http_request_t *r, ngx_http_variable_value_t *v,

ctx = ngx_http_get_module_ctx(r, ngx_http_js_module);

- pending = ngx_vm_pending(ctx);
+ pending = ngx_js_ctx_pending(ctx);

- rc = ngx_js_name_invoke(ctx->vm, fname, r->connection->log, &ctx->request,
- 1, &ctx->retval);
+ rc = ctx->engine->call((ngx_js_ctx_t *) ctx, fname, &ctx->args[0], 1);

if (rc == NGX_ERROR) {
v->not_found = 1;
@@ -1287,15 +1318,15 @@ ngx_http_js_variable_set(ngx_http_request_t *r, ngx_http_variable_value_t *v,
return NGX_ERROR;
}

- if (ngx_js_string(ctx->vm, njs_value_arg(&ctx->retval), &value) != NGX_OK) {
+ if (ctx->engine->string(ctx->engine, &ctx->retval, &value) != NGX_OK) {
return NGX_ERROR;
}

- v->len = value.length;
+ v->len = value.len;
v->valid = 1;
v->no_cacheable = vdata->flags & NGX_NJS_VAR_NOCACHE;
v->not_found = 0;
- v->data = value.start;
+ v->data = value.data;

return NGX_OK;
}
@@ -1331,18 +1362,12 @@ ngx_http_js_variable_var(ngx_http_request_t *r, ngx_http_variable_value_t *v,
static ngx_int_t
ngx_http_js_init_vm(ngx_http_request_t *r, njs_int_t proto_id)
{
- njs_int_t rc;
- ngx_str_t exception;
- njs_str_t key;
- ngx_uint_t i;
ngx_http_js_ctx_t *ctx;
- njs_opaque_value_t retval;
ngx_pool_cleanup_t *cln;
- ngx_js_named_path_t *preload;
ngx_http_js_loc_conf_t *jlcf;

jlcf = ngx_http_get_module_loc_conf(r, ngx_http_js_module);
- if (jlcf->vm == NULL) {
+ if (jlcf->engine == NULL) {
return NGX_DECLINED;
}

@@ -1354,71 +1379,33 @@ ngx_http_js_init_vm(ngx_http_request_t *r, njs_int_t proto_id)
return NGX_ERROR;
}

- ngx_js_ctx_init((ngx_js_ctx_t *) ctx);
-
- njs_value_invalid_set(njs_value_arg(&ctx->retval));
+ ngx_js_ctx_init((ngx_js_ctx_t *) ctx, r->connection->log);

ngx_http_set_ctx(r, ctx, ngx_http_js_module);
}

- if (ctx->vm) {
+ if (ctx->engine) {
return NGX_OK;
}

- ctx->vm = njs_vm_clone(jlcf->vm, r);
- if (ctx->vm == NULL) {
+ ctx->engine = jlcf->engine->clone((ngx_js_ctx_t *) ctx,
+ (ngx_js_loc_conf_t *) jlcf, proto_id, r);
+ if (ctx->engine == NULL) {
return NGX_ERROR;
}

- ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
- "http js vm clone: %p from: %p", ctx->vm, jlcf->vm);
+ ngx_log_debug3(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
+ "http js vm clone %s: %p from: %p", jlcf->engine->name,
+ ctx->engine, jlcf->engine);

cln = ngx_pool_cleanup_add(r->pool, 0);
if (cln == NULL) {
return NGX_ERROR;
}

- ctx->log = r->connection->log;
-
cln->handler = ngx_http_js_cleanup_ctx;
cln->data = ctx;

- /* bind objects from preload vm */
-
- if (jlcf->preload_objects != NGX_CONF_UNSET_PTR) {
- preload = jlcf->preload_objects->elts;
-
- for (i = 0; i < jlcf->preload_objects->nelts; i++) {
- key.start = preload[i].name.data;
- key.length = preload[i].name.len;
-
- rc = njs_vm_value(jlcf->preload_vm, &key, njs_value_arg(&retval));
- if (rc != NJS_OK) {
- return NGX_ERROR;
- }
-
- rc = njs_vm_bind(ctx->vm, &key, njs_value_arg(&retval), 0);
- if (rc != NJS_OK) {
- return NGX_ERROR;
- }
- }
- }
-
- if (njs_vm_start(ctx->vm, njs_value_arg(&retval)) == NJS_ERROR) {
- ngx_js_exception(ctx->vm, &exception);
-
- ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
- "js exception: %V", &exception);
-
- return NGX_ERROR;
- }
-
- rc = njs_vm_external_create(ctx->vm, njs_value_arg(&ctx->request),
- proto_id, r, 0);
- if (rc != NJS_OK) {
- return NGX_ERROR;
- }
-
return NGX_OK;
}

@@ -1426,16 +1413,22 @@ ngx_http_js_init_vm(ngx_http_request_t *r, njs_int_t proto_id)
static void
ngx_http_js_cleanup_ctx(void *data)
{
- ngx_http_js_ctx_t *ctx = data;
+ ngx_http_request_t *r;
+ ngx_http_js_loc_conf_t *jlcf;
+
+ ngx_http_js_ctx_t *ctx = data;

- if (ngx_vm_pending(ctx)) {
+ if (ngx_js_ctx_pending(ctx)) {
ngx_log_error(NGX_LOG_ERR, ctx->log, 0, "pending events");
}

ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0, "http js vm destroy: %p",
- ctx->vm);
+ ctx->engine);
+
+ r = ngx_js_ctx_external(ctx);
+ jlcf = ngx_http_get_module_loc_conf(r, ngx_http_js_module);

- ngx_js_ctx_destroy((ngx_js_ctx_t *) ctx);
+ ngx_js_ctx_destroy((ngx_js_ctx_t *) ctx, (ngx_js_loc_conf_t *) jlcf);
}


@@ -2657,7 +2650,7 @@ ngx_http_js_ext_get_args(njs_vm_t *vm, njs_object_prop_t *prop,

ctx = ngx_http_get_module_ctx(r, ngx_http_js_module);

- args = njs_value_arg(&ctx->args);
+ args = njs_value_arg(&ctx->rargs);

if (njs_value_is_null(args)) {
data = (r->args.len != 0) ? r->args.data : (u_char *) "";
@@ -3109,9 +3102,8 @@ ngx_http_js_ext_subrequest(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
ngx_str_t uri, rargs;
ngx_uint_t method, methods_max, has_body, detached,
promise;
- njs_value_t *value, *arg, *options;
+ njs_value_t *value, *arg, *options, *callback;
ngx_js_event_t *event;
- njs_function_t *callback;
ngx_http_js_ctx_t *ctx;
njs_opaque_value_t lvalue;
ngx_http_request_t *r, *sr;
@@ -3168,7 +3160,7 @@ ngx_http_js_ext_subrequest(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
}

} else if (njs_value_is_function(arg)) {
- callback = njs_value_function(arg);
+ callback = arg;

} else if (njs_value_is_object(arg)) {
options = arg;
@@ -3237,7 +3229,7 @@ ngx_http_js_ext_subrequest(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
return NJS_ERROR;

} else {
- callback = njs_value_function(arg);
+ callback = arg;
}
}

@@ -3254,35 +3246,33 @@ ngx_http_js_ext_subrequest(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
if (!detached) {
ps = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t));
if (ps == NULL) {
- njs_vm_memory_error(ctx->vm);
+ njs_vm_memory_error(vm);
return NJS_ERROR;
}

promise = !!(callback == NULL);

- event = njs_mp_zalloc(njs_vm_memory_pool(ctx->vm),
+ event = njs_mp_zalloc(njs_vm_memory_pool(vm),
sizeof(ngx_js_event_t)
+ promise * (sizeof(njs_opaque_value_t) * 2));
if (njs_slow_path(event == NULL)) {
- njs_vm_memory_error(ctx->vm);
+ njs_vm_memory_error(vm);
return NJS_ERROR;
}

- event->vm = ctx->vm;
event->fd = ctx->event_id++;

if (promise) {
- event->args = (njs_value_t *) &event[1];
- rc = njs_vm_promise_create(ctx->vm, retval,
- njs_value_arg(event->args));
+ event->args = (njs_opaque_value_t *) &event[1];
+ rc = njs_vm_promise_create(vm, retval, njs_value_arg(event->args));
if (rc != NJS_OK) {
return NJS_ERROR;
}

- callback = njs_value_function(njs_value_arg(event->args));
+ callback = njs_value_arg(event->args);
}

- event->function = callback;
+ njs_value_assign(&event->function, callback);

ps->handler = ngx_http_js_subrequest_done;
ps->data = event;
@@ -3303,7 +3293,7 @@ ngx_http_js_ext_subrequest(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
if (ngx_http_subrequest(r, &uri, rargs.len ? &rargs : NULL, &sr, ps, flags)
!= NGX_OK)
{
- njs_vm_error(ctx->vm, "subrequest creation failed");
+ njs_vm_error(vm, "subrequest creation failed");
return NJS_ERROR;
}

@@ -3358,7 +3348,7 @@ ngx_http_js_ext_subrequest(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,

memory_error:

- njs_vm_error(ctx->vm, "internal error");
+ njs_vm_error(vm, "internal error");

return NJS_ERROR;
}
@@ -3370,6 +3360,7 @@ ngx_http_js_subrequest_done(ngx_http_request_t *r, void *data, ngx_int_t rc)
ngx_js_event_t *event = data;

njs_int_t ret;
+ njs_vm_t *vm;
ngx_http_js_ctx_t *ctx;
njs_opaque_value_t reply;

@@ -3407,7 +3398,9 @@ ngx_http_js_subrequest_done(ngx_http_request_t *r, void *data, ngx_int_t rc)
return NGX_ERROR;
}

- ret = njs_vm_external_create(ctx->vm, njs_value_arg(&reply),
+ vm = ctx->engine->u.njs.vm;
+
+ ret = njs_vm_external_create(vm, njs_value_arg(&reply),
ngx_http_js_request_proto_id, r, 0);
if (ret != NJS_OK) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
@@ -3416,7 +3409,8 @@ ngx_http_js_subrequest_done(ngx_http_request_t *r, void *data, ngx_int_t rc)
return NGX_ERROR;
}

- rc = ngx_js_call(ctx->vm, event->function, njs_value_arg(&reply), 1);
+ rc = ngx_js_call(vm, njs_value_function(njs_value_arg(&event->function)),
+ &reply, 1);

ngx_js_del_event(ctx, event);

@@ -3447,7 +3441,7 @@ ngx_http_js_ext_get_parent(njs_vm_t *vm, njs_object_prop_t *prop,
return NJS_DECLINED;
}

- njs_value_assign(retval, njs_value_arg(&ctx->request));
+ njs_value_assign(retval, njs_value_arg(&ctx->args[0]));

return NJS_OK;
}
@@ -4182,8 +4176,8 @@ ngx_http_js_periodic_handler(ngx_event_t *ev)

r->count++;

- rc = ngx_js_name_invoke(ctx->vm, &periodic->method, &periodic->log,
- &ctx->request, 1, &ctx->retval);
+ rc = ctx->engine->call((ngx_js_ctx_t *) ctx, &periodic->method,
+ &ctx->args[0], 1);

if (rc == NGX_AGAIN) {
rc = NGX_OK;
@@ -4210,7 +4204,7 @@ ngx_http_js_periodic_write_handler(ngx_event_t *ev)

ctx = ngx_http_get_module_ctx(r, ngx_http_js_module);

- if (!ngx_vm_pending(ctx)) {
+ if (!ngx_js_ctx_pending(ctx)) {
ngx_http_js_periodic_finalize(r, NGX_OK);
return;
}
@@ -4247,9 +4241,9 @@ ngx_http_js_periodic_finalize(ngx_http_request_t *r, ngx_int_t rc)
ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http js periodic finalize: \"%V\" rc: %i c: %i pending: %i",
&ctx->periodic->method, rc, r->count,
- ngx_vm_pending(ctx));
+ ngx_js_ctx_pending(ctx));

- if (r->count > 1 || (rc == NGX_OK && ngx_vm_pending(ctx))) {
+ if (r->count > 1 || (rc == NGX_OK && ngx_js_ctx_pending(ctx))) {
return;
}

@@ -4426,22 +4420,51 @@ ngx_js_http_init(njs_vm_t *vm)
}


+static ngx_engine_t *
+ngx_engine_njs_clone(ngx_js_ctx_t *ctx, ngx_js_loc_conf_t *cf,
+ njs_int_t proto_id, void *external)
+{
+ njs_int_t rc;
+ ngx_engine_t *engine;
+ ngx_http_js_ctx_t *hctx;
+
+ engine = ngx_njs_clone(ctx, cf, external);
+ if (engine == NULL) {
+ return NULL;
+ }
+
+ rc = njs_vm_external_create(engine->u.njs.vm, njs_value_arg(&ctx->args[0]),
+ proto_id, njs_vm_external_ptr(engine->u.njs.vm),
+ 0);
+ if (rc != NJS_OK) {
+ return NULL;
+ }
+
+ hctx = (ngx_http_js_ctx_t *) ctx;
+ hctx->body_filter = ngx_http_njs_body_filter;
+
+ return engine;
+}
+
+
static ngx_int_t
ngx_http_js_init_conf_vm(ngx_conf_t *cf, ngx_js_loc_conf_t *conf)
{
- njs_vm_opt_t options;
+ ngx_engine_opts_t options;
ngx_js_main_conf_t *jmcf;

- njs_vm_opt_init(&options);
+ memset(&options, 0, sizeof(ngx_engine_opts_t));

- jmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_js_module);
- ngx_http_js_uptr[NGX_JS_MAIN_CONF_INDEX] = (uintptr_t) jmcf;
+ options.engine = conf->type;

- options.backtrace = 1;
- options.metas = &ngx_http_js_metas;
- options.addons = njs_http_js_addon_modules;
- options.argv = ngx_argv;
- options.argc = ngx_argc;
+ if (conf->type == NGX_ENGINE_NJS) {
+ jmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_js_module);
+ ngx_http_js_uptr[NGX_JS_MAIN_CONF_INDEX] = (uintptr_t) jmcf;
+
+ options.u.njs.metas = &ngx_http_js_metas;
+ options.u.njs.addons = njs_http_js_addon_modules;
+ options.clone = ngx_engine_njs_clone;
+ }

return ngx_js_init_conf_vm(cf, conf, &options);
}
diff --git a/nginx/ngx_js.c b/nginx/ngx_js.c
index 4c1f29f3..ce4988f9 100644
--- a/nginx/ngx_js.c
+++ b/nginx/ngx_js.c
@@ -24,7 +24,8 @@ typedef struct {


typedef struct {
- void *promise;
+ void *promise_obj;
+ njs_opaque_value_t promise;
njs_opaque_value_t message;
} ngx_js_rejected_promise_t;

@@ -43,6 +44,19 @@ typedef struct {
} njs_module_info_t;


+static ngx_int_t ngx_engine_njs_init(ngx_engine_t *engine,
+ ngx_engine_opts_t *opts);
+static ngx_int_t ngx_engine_njs_compile(ngx_js_loc_conf_t *conf, ngx_log_t *log,
+ u_char *start, size_t size);
+static ngx_int_t ngx_engine_njs_call(ngx_js_ctx_t *ctx, ngx_str_t *fname,
+ njs_opaque_value_t *args, njs_uint_t nargs);
+static void *ngx_engine_njs_external(ngx_engine_t *engine);
+static ngx_int_t ngx_engine_njs_pending(ngx_engine_t *engine);
+static ngx_int_t ngx_engine_njs_string(ngx_engine_t *e,
+ njs_opaque_value_t *value, ngx_str_t *str);
+static void ngx_engine_njs_destroy(ngx_engine_t *e, ngx_js_ctx_t *ctx,
+ ngx_js_loc_conf_t *conf);
+
static njs_int_t ngx_js_ext_build(njs_vm_t *vm, njs_object_prop_t *prop,
njs_value_t *value, njs_value_t *setval, njs_value_t *retval);
static njs_int_t ngx_js_ext_conf_file_path(njs_vm_t *vm,
@@ -70,6 +84,15 @@ static njs_int_t njs_set_immediate(njs_vm_t *vm, njs_value_t *args,
static njs_int_t njs_clear_timeout(njs_vm_t *vm, njs_value_t *args,
njs_uint_t nargs, njs_index_t unused, njs_value_t *retval);
static njs_int_t ngx_js_unhandled_rejection(ngx_js_ctx_t *ctx);
+static void ngx_js_rejection_tracker(njs_vm_t *vm, njs_external_ptr_t unused,
+ njs_bool_t is_handled, njs_value_t *promise, njs_value_t *reason);
+static njs_mod_t *ngx_js_module_loader(njs_vm_t *vm,
+ njs_external_ptr_t external, njs_str_t *name);
+static njs_int_t ngx_js_module_lookup(ngx_js_loc_conf_t *conf,
+ njs_module_info_t *info);
+static njs_int_t ngx_js_module_read(njs_mp_t *mp, int fd, njs_str_t *text);
+static njs_int_t ngx_js_set_cwd(njs_mp_t *mp, ngx_js_loc_conf_t *conf,
+ njs_str_t *path);
static void ngx_js_cleanup_vm(void *data);

static njs_int_t ngx_js_core_init(njs_vm_t *vm);
@@ -354,82 +377,234 @@ njs_module_t *njs_js_addon_modules_shared[] = {
static njs_int_t ngx_js_console_proto_id;


-ngx_int_t
-ngx_js_call(njs_vm_t *vm, njs_function_t *func, njs_value_t *args,
- njs_uint_t nargs)
+static ngx_engine_t *
+ngx_create_engine(ngx_engine_opts_t *opts)
{
- njs_int_t ret;
- ngx_str_t exception;
- ngx_connection_t *c;
+ njs_mp_t *mp;
+ ngx_int_t rc;
+ ngx_engine_t *engine;

- ret = njs_vm_call(vm, func, args, nargs);
- if (ret == NJS_ERROR) {
- ngx_js_exception(vm, &exception);
+ mp = njs_mp_fast_create(2 * getpagesize(), 128, 512, 16);
+ if (mp == NULL) {
+ return NULL;
+ }

- c = ngx_external_connection(vm, njs_vm_external_ptr(vm));
+ engine = njs_mp_zalloc(mp, sizeof(ngx_engine_t));
+ if (engine == NULL) {
+ return NULL;
+ }

- ngx_log_error(NGX_LOG_ERR, c->log, 0,
- "js exception: %V", &exception);
+ engine->pool = mp;
+ engine->clone = opts->clone;
+
+ switch (opts->engine) {
+ case NGX_ENGINE_NJS:
+ rc = ngx_engine_njs_init(engine, opts);
+ if (rc != NGX_OK) {
+ return NULL;
+ }
+
+ engine->name = "njs";
+ engine->type = NGX_ENGINE_NJS;
+ engine->compile = ngx_engine_njs_compile;
+ engine->call = ngx_engine_njs_call;
+ engine->external = ngx_engine_njs_external;
+ engine->pending = ngx_engine_njs_pending;
+ engine->string = ngx_engine_njs_string;
+ engine->destroy = opts->destroy ? opts->destroy
+ : ngx_engine_njs_destroy;
+ break;
+
+ default:
+ return NULL;
+ }
+
+ return engine;
+}
+
+
+static ngx_int_t
+ngx_engine_njs_init(ngx_engine_t *engine, ngx_engine_opts_t *opts)
+{
+ njs_vm_t *vm;
+ ngx_int_t rc;
+ njs_vm_opt_t vm_options;
+
+ njs_vm_opt_init(&vm_options);
+
+ vm_options.backtrace = 1;
+ vm_options.addons = opts->u.njs.addons;
+ vm_options.metas = opts->u.njs.metas;
+ vm_options.file = opts->file;
+ vm_options.argv = ngx_argv;
+ vm_options.argc = ngx_argc;
+
+ vm = njs_vm_create(&vm_options);
+ if (vm == NULL) {
return NGX_ERROR;
}

- for ( ;; ) {
- ret = njs_vm_execute_pending_job(vm);
- if (ret <= NJS_OK) {
- c = ngx_external_connection(vm, njs_vm_external_ptr(vm));
+ njs_vm_set_rejection_tracker(vm, ngx_js_rejection_tracker, NULL);

- if (ret == NJS_ERROR) {
- ngx_js_exception(vm, &exception);
+ rc = ngx_js_set_cwd(njs_vm_memory_pool(vm), opts->conf, &vm_options.file);
+ if (rc != NGX_OK) {
+ return NGX_ERROR;
+ }

- ngx_log_error(NGX_LOG_ERR, c->log, 0,
- "js job exception: %V", &exception);
- return NGX_ERROR;
- }
+ njs_vm_set_module_loader(vm, ngx_js_module_loader, opts->conf);

- break;
+ engine->u.njs.vm = vm;
+
+ return NJS_OK;
+}
+
+
+static ngx_int_t
+ngx_engine_njs_compile(ngx_js_loc_conf_t *conf, ngx_log_t *log, u_char *start,
+ size_t size)
+{
+ u_char *end;
+ njs_vm_t *vm;
+ njs_int_t rc;
+ njs_str_t text;
+ ngx_uint_t i;
+ njs_value_t *value;
+ njs_opaque_value_t exception, lvalue;
+ ngx_js_named_path_t *import;
+
+ static const njs_str_t line_number_key = njs_str("lineNumber");
+ static const njs_str_t file_name_key = njs_str("fileName");
+
+ vm = conf->engine->u.njs.vm;
+ end = start + size;
+
+ rc = njs_vm_compile(vm, &start, end);
+
+ if (rc != NJS_OK) {
+ njs_vm_exception_get(vm, njs_value_arg(&exception));
+ njs_vm_value_string(vm, &text, njs_value_arg(&exception));
+
+ value = njs_vm_object_prop(vm, njs_value_arg(&exception),
+ &file_name_key, &lvalue);
+ if (value == NULL) {
+ value = njs_vm_object_prop(vm, njs_value_arg(&exception),
+ &line_number_key, &lvalue);
+
+ if (value != NULL) {
+ i = njs_value_number(value) - 1;
+
+ if (i < conf->imports->nelts) {
+ import = conf->imports->elts;
+ ngx_log_error(NGX_LOG_EMERG, log, 0,
+ "%*s, included in %s:%ui", text.length,
+ text.start, import[i].file, import[i].line);
+ return NGX_ERROR;
+ }
+ }
}
+
+ ngx_log_error(NGX_LOG_EMERG, log, 0, "%*s", text.length, text.start);
+ return NGX_ERROR;
+ }
+
+ if (start != end) {
+ ngx_log_error(NGX_LOG_EMERG, log, 0,
+ "extra characters in js script: \"%*s\"",
+ end - start, start);
+ return NGX_ERROR;
}

return NGX_OK;
}


-ngx_int_t
-ngx_js_name_call(njs_vm_t *vm, ngx_str_t *fname, ngx_log_t *log,
- njs_opaque_value_t *args, njs_uint_t nargs)
+ngx_engine_t *
+ngx_njs_clone(ngx_js_ctx_t *ctx, ngx_js_loc_conf_t *cf, void *external)
{
- njs_opaque_value_t unused;
+ njs_vm_t *vm;
+ njs_int_t rc;
+ njs_str_t key;
+ ngx_str_t exception;
+ ngx_uint_t i;
+ ngx_engine_t *engine;
+ njs_opaque_value_t retval;
+ ngx_js_named_path_t *preload;
+
+ vm = njs_vm_clone(cf->engine->u.njs.vm, external);
+ if (vm == NULL) {
+ return NULL;
+ }
+
+ engine = njs_mp_alloc(njs_vm_memory_pool(vm), sizeof(ngx_engine_t));
+ if (engine == NULL) {
+ return NULL;
+ }

- return ngx_js_name_invoke(vm, fname, log, args, nargs, &unused);
+ memcpy(engine, cf->engine, sizeof(ngx_engine_t));
+ engine->pool = njs_vm_memory_pool(vm);
+ engine->u.njs.vm = vm;
+
+ /* bind objects from preload vm */
+
+ if (cf->preload_objects != NGX_CONF_UNSET_PTR) {
+ preload = cf->preload_objects->elts;
+
+ for (i = 0; i < cf->preload_objects->nelts; i++) {
+ key.start = preload[i].name.data;
+ key.length = preload[i].name.len;
+
+ rc = njs_vm_value(cf->preload_vm, &key, njs_value_arg(&retval));
+ if (rc != NJS_OK) {
+ return NULL;
+ }
+
+ rc = njs_vm_bind(vm, &key, njs_value_arg(&retval), 0);
+ if (rc != NJS_OK) {
+ return NULL;
+ }
+ }
+ }
+
+ if (njs_vm_start(vm, njs_value_arg(&retval)) == NJS_ERROR) {
+ ngx_js_exception(vm, &exception);
+
+ ngx_log_error(NGX_LOG_ERR, ctx->log, 0, "js exception: %V", &exception);
+
+ return NULL;
+ }
+
+ return engine;
}


-ngx_int_t
-ngx_js_name_invoke(njs_vm_t *vm, ngx_str_t *fname, ngx_log_t *log,
- njs_opaque_value_t *args, njs_uint_t nargs, njs_opaque_value_t *retval)
+static ngx_int_t
+ngx_engine_njs_call(ngx_js_ctx_t *ctx, ngx_str_t *fname,
+ njs_opaque_value_t *args, njs_uint_t nargs)
{
+ njs_vm_t *vm;
njs_int_t ret;
njs_str_t name;
ngx_str_t exception;
- ngx_js_ctx_t *ctx;
njs_function_t *func;

name.start = fname->data;
name.length = fname->len;

+ vm = ctx->engine->u.njs.vm;
+
func = njs_vm_function(vm, &name);
if (func == NULL) {
- ngx_log_error(NGX_LOG_ERR, log, 0,
+ ngx_log_error(NGX_LOG_ERR, ctx->log, 0,
"js function \"%V\" not found", fname);
return NGX_ERROR;
}

ret = njs_vm_invoke(vm, func, njs_value_arg(args), nargs,
- njs_value_arg(retval));
+ njs_value_arg(&ctx->retval));
if (ret == NJS_ERROR) {
ngx_js_exception(vm, &exception);

- ngx_log_error(NGX_LOG_ERR, log, 0,
+ ngx_log_error(NGX_LOG_ERR, ctx->log, 0,
"js exception: %V", &exception);

return NGX_ERROR;
@@ -441,7 +616,7 @@ ngx_js_name_invoke(njs_vm_t *vm, ngx_str_t *fname, ngx_log_t *log,
if (ret == NJS_ERROR) {
ngx_js_exception(vm, &exception);

- ngx_log_error(NGX_LOG_ERR, log, 0,
+ ngx_log_error(NGX_LOG_ERR, ctx->log, 0,
"js job exception: %V", &exception);
return NGX_ERROR;
}
@@ -450,12 +625,10 @@ ngx_js_name_invoke(njs_vm_t *vm, ngx_str_t *fname, ngx_log_t *log,
}
}

- ctx = ngx_external_ctx(vm, njs_vm_external_ptr(vm));
-
if (ngx_js_unhandled_rejection(ctx)) {
ngx_js_exception(vm, &exception);

- ngx_log_error(NGX_LOG_ERR, log, 0, "js exception: %V", &exception);
+ ngx_log_error(NGX_LOG_ERR, ctx->log, 0, "js exception: %V", &exception);
return NGX_ERROR;
}

@@ -463,6 +636,110 @@ ngx_js_name_invoke(njs_vm_t *vm, ngx_str_t *fname, ngx_log_t *log,
}


+static void *
+ngx_engine_njs_external(ngx_engine_t *engine)
+{
+ return njs_vm_external_ptr(engine->u.njs.vm);
+}
+
+static ngx_int_t
+ngx_engine_njs_pending(ngx_engine_t *e)
+{
+ return njs_vm_pending(e->u.njs.vm);
+}
+
+
+static ngx_int_t
+ngx_engine_njs_string(ngx_engine_t *e, njs_opaque_value_t *value,
+ ngx_str_t *str)
+{
+ ngx_int_t rc;
+ njs_str_t s;
+
+ rc = ngx_js_string(e->u.njs.vm, njs_value_arg(value), &s);
+
+ str->data = s.start;
+ str->len = s.length;
+
+ return rc;
+}
+
+
+static void
+ngx_engine_njs_destroy(ngx_engine_t *e, ngx_js_ctx_t *ctx,
+ ngx_js_loc_conf_t *conf)
+{
+ ngx_js_event_t *event;
+ njs_rbtree_node_t *node;
+
+ if (ctx != NULL) {
+ node = njs_rbtree_min(&ctx->waiting_events);
+
+ while (njs_rbtree_is_there_successor(&ctx->waiting_events, node)) {
+ event = (ngx_js_event_t *) ((u_char *) node
+ - offsetof(ngx_js_event_t, node));
+
+ if (event->destructor != NULL) {
+ event->destructor(event);
+ }
+
+ node = njs_rbtree_node_successor(&ctx->waiting_events, node);
+ }
+ }
+
+ njs_vm_destroy(e->u.njs.vm);
+
+ /*
+ * when ctx !=NULL e->pool is vm pool, in such case it is destroyed
+ * by njs_vm_destroy().
+ */
+
+ if (ctx == NULL) {
+ njs_mp_destroy(e->pool);
+ }
+}
+
+
+ngx_int_t
+ngx_js_call(njs_vm_t *vm, njs_function_t *func, njs_opaque_value_t *args,
+ njs_uint_t nargs)
+{
+ njs_int_t ret;
+ ngx_str_t exception;
+ ngx_connection_t *c;
+
+ ret = njs_vm_call(vm, func, njs_value_arg(args), nargs);
+ if (ret == NJS_ERROR) {
+ ngx_js_exception(vm, &exception);
+
+ c = ngx_external_connection(vm, njs_vm_external_ptr(vm));
+
+ ngx_log_error(NGX_LOG_ERR, c->log, 0,
+ "js exception: %V", &exception);
+ return NGX_ERROR;
+ }
+
+ for ( ;; ) {
+ ret = njs_vm_execute_pending_job(vm);
+ if (ret <= NJS_OK) {
+ c = ngx_external_connection(vm, njs_vm_external_ptr(vm));
+
+ if (ret == NJS_ERROR) {
+ ngx_js_exception(vm, &exception);
+
+ ngx_log_error(NGX_LOG_ERR, c->log, 0,
+ "js job exception: %V", &exception);
+ return NGX_ERROR;
+ }
+
+ break;
+ }
+ }
+
+ return NGX_OK;
+}
+
+
ngx_int_t
ngx_js_exception(njs_vm_t *vm, ngx_str_t *s)
{
@@ -554,33 +831,18 @@ ngx_js_event_rbtree_compare(njs_rbtree_node_t *node1, njs_rbtree_node_t *node2)


void
-ngx_js_ctx_init(ngx_js_ctx_t *ctx)
+ngx_js_ctx_init(ngx_js_ctx_t *ctx, ngx_log_t *log)
{
+ ctx->log = log;
ctx->event_id = 0;
njs_rbtree_init(&ctx->waiting_events, ngx_js_event_rbtree_compare);
}


void
-ngx_js_ctx_destroy(ngx_js_ctx_t *ctx)
+ngx_js_ctx_destroy(ngx_js_ctx_t *ctx, ngx_js_loc_conf_t *conf)
{
- ngx_js_event_t *event;
- njs_rbtree_node_t *node;
-
- node = njs_rbtree_min(&ctx->waiting_events);
-
- while (njs_rbtree_is_there_successor(&ctx->waiting_events, node)) {
- event = (ngx_js_event_t *) ((u_char *) node
- - offsetof(ngx_js_event_t, node));
-
- if (event->destructor != NULL) {
- event->destructor(njs_vm_external_ptr(event->vm), event);
- }
-
- node = njs_rbtree_node_successor(&ctx->waiting_events, node);
- }
-
- njs_vm_destroy(ctx->vm);
+ ctx->engine->destroy(ctx->engine, ctx, conf);
}


@@ -1047,9 +1309,10 @@ ngx_js_timer_handler(ngx_event_t *ev)

event = (ngx_js_event_t *) ((u_char *) ev - offsetof(ngx_js_event_t, ev));

- vm = event->vm;
+ vm = event->ctx;

- rc = ngx_js_call(vm, event->function, event->args, event->nargs);
+ rc = ngx_js_call(vm, njs_value_function(njs_value_arg(&event->function)),
+ event->args, event->nargs);

ctx = ngx_external_ctx(vm, njs_vm_external_ptr(vm));
ngx_js_del_event(ctx, event);
@@ -1059,7 +1322,7 @@ ngx_js_timer_handler(ngx_event_t *ev)


static void
-ngx_js_clear_timer(njs_external_ptr_t external, ngx_js_event_t *event)
+ngx_js_clear_timer(ngx_js_event_t *event)
{
if (event->ev.timer_set) {
ngx_del_timer(&event->ev);
@@ -1106,10 +1369,10 @@ njs_set_timer(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
return NJS_ERROR;
}

- event->vm = vm;
- event->function = njs_value_function(njs_argument(args, 1));
+ event->ctx = vm;
+ njs_value_assign(&event->function, njs_argument(args, 1));
event->nargs = nargs;
- event->args = (njs_value_t *) ((u_char *) event + sizeof(ngx_js_event_t));
+ event->args = (njs_opaque_value_t *) &event[1];
event->destructor = ngx_js_clear_timer;

ctx = ngx_external_ctx(vm, njs_vm_external_ptr(vm));
@@ -1343,6 +1606,47 @@ ngx_js_import(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
}


+char *
+ngx_js_engine(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ char *p = conf;
+
+ ngx_str_t *value;
+ ngx_uint_t *type, m;
+ ngx_conf_bitmask_t *mask;
+
+ type = (size_t *) (p + cmd->offset);
+ if (*type != NGX_CONF_UNSET_UINT) {
+ return "is duplicate";
+ }
+
+ value = cf->args->elts;
+ mask = cmd->post;
+
+ for (m = 0; mask[m].name.len != 0; m++) {
+
+ if (mask[m].name.len != value[1].len
+ || ngx_strcasecmp(mask[m].name.data, value[1].data) != 0)
+ {
+ continue;
+ }
+
+ *type = mask[m].mask;
+
+ break;
+ }
+
+ if (mask[m].name.len == 0) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid value \"%s\"", value[1].data);
+
+ return NGX_CONF_ERROR;
+ }
+
+ return NGX_CONF_OK;
+}
+
+
char *
ngx_js_preload_object(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
@@ -1552,14 +1856,16 @@ ngx_js_merge_vm(ngx_conf_t *cf, ngx_js_loc_conf_t *conf,
ngx_js_named_path_t *import, *pi, *pij, *preload;

if (conf->imports == NGX_CONF_UNSET_PTR
+ && conf->type == NGX_CONF_UNSET_UINT
&& conf->paths == NGX_CONF_UNSET_PTR
&& conf->preload_objects == NGX_CONF_UNSET_PTR)
{
- if (prev->vm != NULL) {
+ if (prev->engine != NULL) {
conf->preload_objects = prev->preload_objects;
conf->imports = prev->imports;
+ conf->type = prev->type;
conf->paths = prev->paths;
- conf->vm = prev->vm;
+ conf->engine = prev->engine;

conf->preload_vm = prev->preload_vm;

@@ -1703,9 +2009,10 @@ ngx_js_rejection_tracker(njs_vm_t *vm, njs_external_ptr_t unused,
promise_obj = njs_value_ptr(promise);

for (i = 0; i < length; i++) {
- if (rejected_promise[i].promise == promise_obj) {
- njs_arr_remove(ctx->rejected_promises,
- &rejected_promise[i]);
+ if (njs_value_ptr(njs_value_arg(&rejected_promise[i].promise))
+ == promise_obj)
+ {
+ njs_arr_remove(ctx->rejected_promises, &rejected_promise[i]);

break;
}
@@ -1727,7 +2034,7 @@ ngx_js_rejection_tracker(njs_vm_t *vm, njs_external_ptr_t unused,
return;
}

- rejected_promise->promise = njs_value_ptr(promise);
+ njs_value_assign(&rejected_promise->promise, promise);
njs_value_assign(&rejected_promise->message, reason);
}

@@ -1918,13 +2225,13 @@ current_dir:


static njs_int_t
-ngx_js_set_cwd(njs_vm_t *vm, ngx_js_loc_conf_t *conf, njs_str_t *path)
+ngx_js_set_cwd(njs_mp_t *mp, ngx_js_loc_conf_t *conf, njs_str_t *path)
{
ngx_str_t cwd;

ngx_js_file_dirname(path, &cwd);

- conf->cwd.data = njs_mp_alloc(njs_vm_memory_pool(vm), cwd.len);
+ conf->cwd.data = njs_mp_alloc(mp, cwd.len);
if (conf->cwd.data == NULL) {
return NJS_ERROR;
}
@@ -1969,7 +2276,7 @@ ngx_js_module_loader(njs_vm_t *vm, njs_external_ptr_t external, njs_str_t *name)

prev_cwd = conf->cwd;

- ret = ngx_js_set_cwd(vm, conf, &info.file);
+ ret = ngx_js_set_cwd(njs_vm_memory_pool(vm), conf, &info.file);
if (ret != NJS_OK) {
njs_vm_internal_error(vm, "while setting cwd for \"%V\" module",
&info.file);
@@ -1992,22 +2299,15 @@ ngx_js_module_loader(njs_vm_t *vm, njs_external_ptr_t external, njs_str_t *name)

ngx_int_t
ngx_js_init_conf_vm(ngx_conf_t *cf, ngx_js_loc_conf_t *conf,
- njs_vm_opt_t *options)
+ ngx_engine_opts_t *options)
{
+ u_char *start, *p;
size_t size;
- u_char *start, *end, *p;
ngx_str_t *m, file;
- njs_int_t rc;
- njs_str_t text;
ngx_uint_t i;
- njs_value_t *value;
ngx_pool_cleanup_t *cln;
- njs_opaque_value_t lvalue, exception;
ngx_js_named_path_t *import;

- static const njs_str_t line_number_key = njs_str("lineNumber");
- static const njs_str_t file_name_key = njs_str("fileName");
-
if (conf->preload_objects != NGX_CONF_UNSET_PTR) {
if (ngx_js_init_preload_vm(cf, (ngx_js_loc_conf_t *)conf) != NGX_OK) {
return NGX_ERROR;
@@ -2054,9 +2354,10 @@ ngx_js_init_conf_vm(ngx_conf_t *cf, ngx_js_loc_conf_t *conf,

options->file.start = file.data;
options->file.length = file.len;
+ options->conf = conf;

- conf->vm = njs_vm_create(options);
- if (conf->vm == NULL) {
+ conf->engine = ngx_create_engine(options);
+ if (conf->engine == NULL) {
ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "failed to create js VM");
return NGX_ERROR;
}
@@ -2069,17 +2370,6 @@ ngx_js_init_conf_vm(ngx_conf_t *cf, ngx_js_loc_conf_t *conf,
cln->handler = ngx_js_cleanup_vm;
cln->data = conf;

- njs_vm_set_rejection_tracker(conf->vm, ngx_js_rejection_tracker,
- NULL);
-
- rc = ngx_js_set_cwd(conf->vm, conf, &options->file);
- if (rc != NJS_OK) {
- ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "failed to set cwd");
- return NGX_ERROR;
- }
-
- njs_vm_set_module_loader(conf->vm, ngx_js_module_loader, conf);
-
if (conf->paths != NGX_CONF_UNSET_PTR) {
m = conf->paths->elts;

@@ -2090,52 +2380,14 @@ ngx_js_init_conf_vm(ngx_conf_t *cf, ngx_js_loc_conf_t *conf,
}
}

- end = start + size;
-
- rc = njs_vm_compile(conf->vm, &start, end);
-
- if (rc != NJS_OK) {
- njs_vm_exception_get(conf->vm, njs_value_arg(&exception));
- njs_vm_value_string(conf->vm, &text, njs_value_arg(&exception));
-
- value = njs_vm_object_prop(conf->vm, njs_value_arg(&exception),
- &file_name_key, &lvalue);
- if (value == NULL) {
- value = njs_vm_object_prop(conf->vm, njs_value_arg(&exception),
- &line_number_key, &lvalue);
-
- if (value != NULL) {
- i = njs_value_number(value) - 1;
-
- if (i < conf->imports->nelts) {
- import = conf->imports->elts;
- ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
- "%*s, included in %s:%ui", text.length,
- text.start, import[i].file, import[i].line);
- return NGX_ERROR;
- }
- }
- }
-
- ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "%*s", text.length,
- text.start);
- return NGX_ERROR;
- }
-
- if (start != end) {
- ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
- "extra characters in js script: \"%*s\"",
- end - start, start);
- return NGX_ERROR;
- }
-
- return NGX_OK;
+ return conf->engine->compile(conf, cf->log, start, size);
}


static njs_int_t
ngx_js_unhandled_rejection(ngx_js_ctx_t *ctx)
{
+ njs_vm_t *vm;
njs_int_t ret;
njs_str_t message;
ngx_js_rejected_promise_t *rejected_promise;
@@ -2146,15 +2398,16 @@ ngx_js_unhandled_rejection(ngx_js_ctx_t *ctx)
return 0;
}

+ vm = ctx->engine->u.njs.vm;
rejected_promise = ctx->rejected_promises->start;

- ret = njs_vm_value_to_string(ctx->vm, &message,
+ ret = njs_vm_value_to_string(vm, &message,
njs_value_arg(&rejected_promise->message));
if (njs_slow_path(ret != NJS_OK)) {
return -1;
}

- njs_vm_error(ctx->vm, "unhandled promise rejection: %V", &message);
+ njs_vm_error(vm, "unhandled promise rejection: %V", &message);

njs_arr_destroy(ctx->rejected_promises);
ctx->rejected_promises = NULL;
@@ -2168,7 +2421,7 @@ ngx_js_cleanup_vm(void *data)
{
ngx_js_loc_conf_t *jscf = data;

- njs_vm_destroy(jscf->vm);
+ jscf->engine->destroy(jscf->engine, NULL, NULL);

if (jscf->preload_objects != NGX_CONF_UNSET_PTR) {
njs_vm_destroy(jscf->preload_vm);
@@ -2187,6 +2440,7 @@ ngx_js_create_conf(ngx_conf_t *cf, size_t size)
}

conf->paths = NGX_CONF_UNSET_PTR;
+ conf->type = NGX_CONF_UNSET_UINT;
conf->imports = NGX_CONF_UNSET_PTR;
conf->preload_objects = NGX_CONF_UNSET_PTR;

@@ -2251,6 +2505,7 @@ ngx_js_merge_conf(ngx_conf_t *cf, void *parent, void *child,
ngx_js_loc_conf_t *prev = parent;
ngx_js_loc_conf_t *conf = child;

+ ngx_conf_merge_uint_value(conf->type, prev->type, NGX_ENGINE_NJS);
ngx_conf_merge_msec_value(conf->timeout, prev->timeout, 60000);
ngx_conf_merge_size_value(conf->buffer_size, prev->buffer_size, 16384);
ngx_conf_merge_size_value(conf->max_response_body_size,
diff --git a/nginx/ngx_js.h b/nginx/ngx_js.h
index 373dd499..a3bbd541 100644
--- a/nginx/ngx_js.h
+++ b/nginx/ngx_js.h
@@ -20,6 +20,8 @@
#include "ngx_js_shared_dict.h"


+#define NGX_ENGINE_NJS 1
+
#define NGX_JS_UNSET 0
#define NGX_JS_DEPRECATED 1
#define NGX_JS_STRING 2
@@ -36,9 +38,11 @@
#define ngx_js_buffer_type(btype) ((btype) & ~NGX_JS_DEPRECATED)


+typedef struct ngx_js_loc_conf_s ngx_js_loc_conf_t;
typedef struct ngx_js_event_s ngx_js_event_t;
typedef struct ngx_js_dict_s ngx_js_dict_t;
typedef struct ngx_js_ctx_s ngx_js_ctx_t;
+typedef struct ngx_engine_s ngx_engine_t;


typedef ngx_pool_t *(*ngx_external_pool_pt)(njs_external_ptr_t e);
@@ -60,14 +64,13 @@ typedef struct {


struct ngx_js_event_s {
- njs_vm_t *vm;
- njs_function_t *function;
- njs_value_t *args;
+ void *ctx;
+ njs_opaque_value_t function;
+ njs_opaque_value_t *args;
ngx_socket_t fd;
NJS_RBTREE_NODE (node);
njs_uint_t nargs;
- void (*destructor)(njs_external_ptr_t external,
- ngx_js_event_t *event);
+ void (*destructor)(ngx_js_event_t *event);
ngx_event_t ev;
void *data;
};
@@ -79,7 +82,8 @@ struct ngx_js_event_s {


#define _NGX_JS_COMMON_LOC_CONF \
- njs_vm_t *vm; \
+ ngx_uint_t type; \
+ ngx_engine_t *engine; \
ngx_str_t cwd; \
ngx_array_t *imports; \
ngx_array_t *paths; \
@@ -109,7 +113,10 @@ struct ngx_js_event_s {


#define NGX_JS_COMMON_CTX \
- njs_vm_t *vm; \
+ ngx_engine_t *engine; \
+ ngx_log_t *log; \
+ njs_opaque_value_t args[3]; \
+ njs_opaque_value_t retval; \
njs_arr_t *rejected_promises; \
njs_rbtree_t waiting_events; \
ngx_socket_t event_id
@@ -122,7 +129,7 @@ struct ngx_js_event_s {
#define ngx_js_del_event(ctx, event) \
do { \
if ((event)->destructor) { \
- (event)->destructor(njs_vm_external_ptr((event)->vm), event); \
+ (event)->destructor(event); \
} \
\
njs_rbtree_delete(&(ctx)->waiting_events, &(event)->node); \
@@ -134,9 +141,9 @@ typedef struct {
} ngx_js_main_conf_t;


-typedef struct {
+struct ngx_js_loc_conf_s {
NGX_JS_COMMON_LOC_CONF;
-} ngx_js_loc_conf_t;
+};


typedef struct {
@@ -150,6 +157,54 @@ struct ngx_js_ctx_s {
};


+typedef struct ngx_engine_opts_s {
+ unsigned engine;
+ union {
+ struct {
+ njs_vm_meta_t *metas;
+ njs_module_t **addons;
+ } njs;
+ } u;
+
+ njs_str_t file;
+ ngx_js_loc_conf_t *conf;
+ ngx_engine_t *(*clone)(ngx_js_ctx_t *ctx,
+ ngx_js_loc_conf_t *cf, njs_int_t pr_id,
+ void *external);
+ void (*destroy)(ngx_engine_t *e, ngx_js_ctx_t *ctx,
+ ngx_js_loc_conf_t *conf);
+} ngx_engine_opts_t;
+
+
+struct ngx_engine_s {
+ union {
+ struct {
+ njs_vm_t *vm;
+ } njs;
+ } u;
+
+ ngx_int_t (*compile)(ngx_js_loc_conf_t *conf, ngx_log_t *lg,
+ u_char *start, size_t size);
+ ngx_int_t (*call)(ngx_js_ctx_t *ctx, ngx_str_t *fname,
+ njs_opaque_value_t *args,
+ njs_uint_t nargs);
+ ngx_engine_t *(*clone)(ngx_js_ctx_t *ctx,
+ ngx_js_loc_conf_t *cf, njs_int_t pr_id,
+ void *external);
+ void *(*external)(ngx_engine_t *e);
+ ngx_int_t (*pending)(ngx_engine_t *e);
+ ngx_int_t (*string)(ngx_engine_t *e,
+ njs_opaque_value_t *value,
+ ngx_str_t *str);
+ void (*destroy)(ngx_engine_t *e, ngx_js_ctx_t *ctx,
+ ngx_js_loc_conf_t *conf);
+
+ unsigned type;
+ const char *name;
+ njs_mp_t *pool;
+};
+
+
#define ngx_external_connection(vm, e) \
(*((ngx_connection_t **) ((u_char *) (e) + njs_vm_meta(vm, 0))))
#define ngx_external_pool(vm, e) \
@@ -182,19 +237,21 @@ struct ngx_js_ctx_s {
: njs_vm_value_buffer_set(vm, value, start, len))


-#define ngx_vm_pending(ctx) \
- (njs_vm_pending((ctx)->vm) || !njs_rbtree_is_empty(&(ctx)->waiting_events))
+void ngx_js_ctx_init(ngx_js_ctx_t *ctx, ngx_log_t *log);
+
+#define ngx_js_ctx_pending(ctx) \
+ ((ctx)->engine->pending(ctx->engine) \
+ || !njs_rbtree_is_empty(&(ctx)->waiting_events))

+#define ngx_js_ctx_external(ctx) \
+ ((ctx)->engine->external(ctx->engine))

-void ngx_js_ctx_init(ngx_js_ctx_t *ctx);
-void ngx_js_ctx_destroy(ngx_js_ctx_t *ctx);
-ngx_int_t ngx_js_call(njs_vm_t *vm, njs_function_t *func, njs_value_t *args,
- njs_uint_t nargs);
-ngx_int_t ngx_js_name_call(njs_vm_t *vm, ngx_str_t *fname, ngx_log_t *log,
+void ngx_js_ctx_destroy(ngx_js_ctx_t *ctx, ngx_js_loc_conf_t *conf);
+ngx_int_t ngx_js_call(njs_vm_t *vm, njs_function_t *func,
njs_opaque_value_t *args, njs_uint_t nargs);
-ngx_int_t ngx_js_name_invoke(njs_vm_t *vm, ngx_str_t *fname, ngx_log_t *log,
- njs_opaque_value_t *args, njs_uint_t nargs, njs_opaque_value_t *retval);
ngx_int_t ngx_js_exception(njs_vm_t *vm, ngx_str_t *s);
+ngx_engine_t *ngx_njs_clone(ngx_js_ctx_t *ctx, ngx_js_loc_conf_t *cf,
+ void *external);

njs_int_t ngx_js_ext_log(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
njs_index_t level, njs_value_t *retval);
@@ -203,13 +260,14 @@ void ngx_js_log(njs_vm_t *vm, njs_external_ptr_t external,
void ngx_js_logger(ngx_connection_t *c, ngx_uint_t level,
const u_char *start, size_t length);
char * ngx_js_import(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
+char * ngx_js_engine(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
char * ngx_js_preload_object(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
ngx_int_t ngx_js_init_preload_vm(ngx_conf_t *cf, ngx_js_loc_conf_t *conf);
ngx_int_t ngx_js_merge_vm(ngx_conf_t *cf, ngx_js_loc_conf_t *conf,
ngx_js_loc_conf_t *prev,
ngx_int_t (*init_vm)(ngx_conf_t *cf, ngx_js_loc_conf_t *conf));
ngx_int_t ngx_js_init_conf_vm(ngx_conf_t *cf, ngx_js_loc_conf_t *conf,
- njs_vm_opt_t *options);
+ ngx_engine_opts_t *opt);
ngx_js_loc_conf_t *ngx_js_create_conf(ngx_conf_t *cf, size_t size);
char * ngx_js_merge_conf(ngx_conf_t *cf, void *parent, void *child,
ngx_int_t (*init_vm)(ngx_conf_t *cf, ngx_js_loc_conf_t *conf));
diff --git a/nginx/ngx_js_fetch.c b/nginx/ngx_js_fetch.c
index cea80469..1c5a961d 100644
--- a/nginx/ngx_js_fetch.c
+++ b/nginx/ngx_js_fetch.c
@@ -174,8 +174,7 @@ static njs_int_t ngx_js_headers_fill(njs_vm_t *vm, ngx_js_headers_t *headers,
njs_value_t *init);
static ngx_js_http_t *ngx_js_http_alloc(njs_vm_t *vm, ngx_pool_t *pool,
ngx_log_t *log);
-static void njs_js_http_destructor(njs_external_ptr_t external,
- ngx_js_event_t *event);
+static void njs_js_http_destructor(ngx_js_event_t *event);
static void ngx_js_resolve_handler(ngx_resolver_ctx_t *ctx);
static njs_int_t ngx_js_fetch_promissified_result(njs_vm_t *vm,
njs_value_t *result, njs_int_t rc, njs_value_t *retval);
@@ -1309,8 +1308,8 @@ ngx_js_http_alloc(njs_vm_t *vm, ngx_pool_t *pool, ngx_log_t *log)

ctx = ngx_external_ctx(vm, njs_vm_external_ptr(vm));

- event->vm = vm;
- event->function = callback;
+ event->ctx = vm;
+ njs_value_function_set(njs_value_arg(&event->function), callback);
event->destructor = njs_js_http_destructor;
event->fd = ctx->event_id++;
event->data = http;
@@ -1439,7 +1438,7 @@ ngx_js_http_close_connection(ngx_connection_t *c)


static void
-njs_js_http_destructor(njs_external_ptr_t external, ngx_js_event_t *event)
+njs_js_http_destructor(ngx_js_event_t *event)
{
ngx_js_http_t *http;

@@ -1530,7 +1529,8 @@ ngx_js_http_fetch_done(ngx_js_http_t *http, njs_opaque_value_t *retval,
vm = http->vm;
event = http->event;

- rc = ngx_js_call(vm, event->function, njs_value_arg(&arguments), 2);
+ rc = ngx_js_call(vm, njs_value_function(njs_value_arg(&event->function)),
+ &arguments[0], 2);

ctx = ngx_external_ctx(vm, njs_vm_external_ptr(vm));
ngx_js_del_event(ctx, event);
diff --git a/nginx/ngx_stream_js_module.c b/nginx/ngx_stream_js_module.c
index 295b2fcf..565f4e66 100644
--- a/nginx/ngx_stream_js_module.c
+++ b/nginx/ngx_stream_js_module.c
@@ -12,6 +12,8 @@
#include "ngx_js.h"


+typedef struct ngx_stream_js_ctx_s ngx_stream_js_ctx_t;
+
typedef struct {
NGX_JS_COMMON_LOC_CONF;

@@ -22,7 +24,7 @@ typedef struct {


typedef struct {
- njs_function_t *function;
+ njs_opaque_value_t function;
ngx_uint_t data_type;
} ngx_stream_js_ev_t;

@@ -47,30 +49,34 @@ typedef struct {
} ngx_js_periodic_t;


-typedef struct {
+struct ngx_stream_js_ctx_s {
NGX_JS_COMMON_CTX;
- njs_opaque_value_t retval;
- njs_opaque_value_t args[3];
ngx_buf_t *buf;
ngx_chain_t **last_out;
ngx_chain_t *free;
ngx_chain_t *upstream_busy;
ngx_chain_t *downstream_busy;
ngx_int_t status;
+ ngx_int_t (*run_event)(ngx_stream_session_t *s,
+ ngx_stream_js_ctx_t *ctx,
+ ngx_stream_js_ev_t *event,
+ ngx_uint_t from_upstream);
+ ngx_int_t (*body_filter)(ngx_stream_session_t *s,
+ ngx_stream_js_ctx_t *ctx,
+ ngx_chain_t *in,
+ ngx_uint_t from_upstream);
#define NGX_JS_EVENT_UPLOAD 0
#define NGX_JS_EVENT_DOWNLOAD 1
#define NGX_JS_EVENT_MAX 2
- ngx_stream_js_ev_t events[2];
+ ngx_stream_js_ev_t events[NGX_JS_EVENT_MAX];
unsigned filter:1;
unsigned in_progress:1;
ngx_js_periodic_t *periodic;
-} ngx_stream_js_ctx_t;
+};


#define ngx_stream_pending(ctx) \
- (ngx_vm_pending(ctx) \
- || (ctx)->events[NGX_JS_EVENT_UPLOAD].function != NULL \
- || (ctx)->events[NGX_JS_EVENT_DOWNLOAD].function != NULL)
+ (ngx_js_ctx_pending(ctx) || ngx_stream_js_pending_events(ctx))


static ngx_int_t ngx_stream_js_access_handler(ngx_stream_session_t *s);
@@ -79,6 +85,8 @@ static ngx_int_t ngx_stream_js_phase_handler(ngx_stream_session_t *s,
ngx_str_t *name);
static ngx_int_t ngx_stream_js_body_filter(ngx_stream_session_t *s,
ngx_chain_t *in, ngx_uint_t from_upstream);
+static ngx_int_t ngx_stream_njs_body_filter(ngx_stream_session_t *s,
+ ngx_stream_js_ctx_t *ctx, ngx_chain_t *in, ngx_uint_t from_upstream);
static ngx_int_t ngx_stream_js_next_filter(ngx_stream_session_t *s,
ngx_stream_js_ctx_t *ctx, ngx_chain_t *out, ngx_uint_t from_upstream);
static ngx_int_t ngx_stream_js_variable_set(ngx_stream_session_t *s,
@@ -87,12 +95,13 @@ static ngx_int_t ngx_stream_js_variable_var(ngx_stream_session_t *s,
ngx_stream_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_stream_js_init_vm(ngx_stream_session_t *s,
njs_int_t proto_id);
+static ngx_int_t ngx_stream_js_pending_events(ngx_stream_js_ctx_t *ctx);
static void ngx_stream_js_drop_events(ngx_stream_js_ctx_t *ctx);
static void ngx_stream_js_cleanup(void *data);
-static njs_int_t ngx_stream_js_run_event(ngx_stream_session_t *s,
+static ngx_int_t ngx_stream_js_run_event(ngx_stream_session_t *s,
ngx_stream_js_ctx_t *ctx, ngx_stream_js_ev_t *event,
ngx_uint_t from_upstream);
-static njs_function_t **ngx_stream_js_event(ngx_stream_session_t *s,
+static ngx_stream_js_ev_t *ngx_stream_js_event(ngx_stream_session_t *s,
njs_str_t *event);

static njs_int_t ngx_stream_js_ext_get_remote_address(njs_vm_t *vm,
@@ -156,6 +165,11 @@ static char *ngx_stream_js_shared_dict_zone(ngx_conf_t *cf, ngx_command_t *cmd,
static ngx_ssl_t *ngx_stream_js_ssl(ngx_stream_session_t *s);
static ngx_flag_t ngx_stream_js_ssl_verify(ngx_stream_session_t *s);

+static ngx_conf_bitmask_t ngx_stream_js_engines[] = {
+ { ngx_string("njs"), NGX_ENGINE_NJS },
+ { ngx_null_string, 0 }
+};
+
#if (NGX_STREAM_SSL)

static ngx_conf_bitmask_t ngx_stream_js_ssl_protocols[] = {
@@ -170,6 +184,13 @@ static ngx_conf_bitmask_t ngx_stream_js_ssl_protocols[] = {

static ngx_command_t ngx_stream_js_commands[] = {

+ { ngx_string("js_engine"),
+ NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_1MORE,
+ ngx_js_engine,
+ NGX_STREAM_SRV_CONF_OFFSET,
+ offsetof(ngx_stream_js_srv_conf_t, type),
+ &ngx_stream_js_engines },
+
{ ngx_string("js_import"),
NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE13,
ngx_js_import,
@@ -693,10 +714,7 @@ ngx_stream_js_preread_handler(ngx_stream_session_t *s)
static ngx_int_t
ngx_stream_js_phase_handler(ngx_stream_session_t *s, ngx_str_t *name)
{
- ngx_str_t exception;
- njs_int_t ret;
ngx_int_t rc;
- ngx_connection_t *c;
ngx_stream_js_ctx_t *ctx;

if (name->len == 0) {
@@ -711,8 +729,6 @@ ngx_stream_js_phase_handler(ngx_stream_session_t *s, ngx_str_t *name)
return rc;
}

- c = s->connection;
-
ctx = ngx_stream_get_module_ctx(s, ngx_stream_js_module);

if (!ctx->in_progress) {
@@ -723,36 +739,33 @@ ngx_stream_js_phase_handler(ngx_stream_session_t *s, ngx_str_t *name)

ctx->status = NGX_ERROR;

- ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0,
+ ngx_log_debug1(NGX_LOG_DEBUG_STREAM, ctx->log, 0,
"stream js phase call \"%V\"", name);

- rc = ngx_js_name_call(ctx->vm, name, c->log, &ctx->args[0], 1);
+ rc = ctx->engine->call((ngx_js_ctx_t *) ctx, name, &ctx->args[0], 1);

if (rc == NGX_ERROR) {
return rc;
}
}

- ret = ngx_stream_js_run_event(s, ctx, &ctx->events[NGX_JS_EVENT_UPLOAD], 0);
- if (ret != NJS_OK) {
- ngx_js_exception(ctx->vm, &exception);
-
- ngx_log_error(NGX_LOG_ERR, c->log, 0, "js exception: %V",
- &exception);
-
+ rc = ctx->run_event(s, ctx, &ctx->events[NGX_JS_EVENT_UPLOAD], 0);
+ if (rc != NGX_OK) {
return NGX_ERROR;
}

if (ngx_stream_pending(ctx)) {
ctx->in_progress = 1;
- rc = ctx->events[NGX_JS_EVENT_UPLOAD].function ? NGX_AGAIN : NGX_DONE;
+ rc = (ctx->events[NGX_JS_EVENT_UPLOAD].data_type != NGX_JS_UNSET)
+ ? NGX_AGAIN
+ : NGX_DONE;

} else {
ctx->in_progress = 0;
rc = ctx->status;
}

- ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0, "stream js phase rc: %i",
+ ngx_log_debug1(NGX_LOG_DEBUG_STREAM, ctx->log, 0, "stream js phase rc: %i",
rc);

return rc;
@@ -769,11 +782,8 @@ ngx_stream_js_body_filter(ngx_stream_session_t *s, ngx_chain_t *in,
ngx_uint_t from_upstream)
{
ngx_int_t rc;
- ngx_str_t exception;
- njs_int_t ret;
- ngx_chain_t *out, *cl;
+ ngx_chain_t *out;
ngx_connection_t *c;
- ngx_stream_js_ev_t *event;
ngx_stream_js_ctx_t *ctx;
ngx_stream_js_srv_conf_t *jscf;

@@ -803,7 +813,8 @@ ngx_stream_js_body_filter(ngx_stream_session_t *s, ngx_chain_t *in,
ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0,
"stream js filter call \"%V\"" , &jscf->filter);

- rc = ngx_js_name_call(ctx->vm, &jscf->filter, c->log, &ctx->args[0], 1);
+ rc = ctx->engine->call((ngx_js_ctx_t *) ctx, &jscf->filter,
+ &ctx->args[0], 1);

if (rc == NGX_ERROR) {
return rc;
@@ -814,37 +825,9 @@ ngx_stream_js_body_filter(ngx_stream_session_t *s, ngx_chain_t *in,

ctx->last_out = &out;

- while (in) {
- ctx->buf = in->buf;
-
- event = ngx_stream_event(from_upstream);
-
- if (event->function != NULL) {
- ret = ngx_stream_js_run_event(s, ctx, event, from_upstream);
- if (ret != NJS_OK) {
- ngx_js_exception(ctx->vm, &exception);
-
- ngx_log_error(NGX_LOG_ERR, c->log, 0, "js exception: %V",
- &exception);
-
- return NGX_ERROR;
- }
-
- ctx->buf->pos = ctx->buf->last;
-
- } else {
- cl = ngx_alloc_chain_link(c->pool);
- if (cl == NULL) {
- return NGX_ERROR;
- }
-
- cl->buf = ctx->buf;
-
- *ctx->last_out = cl;
- ctx->last_out = &cl->next;
- }
-
- in = in->next;
+ rc = ctx->body_filter(s, ctx, in, from_upstream);
+ if (rc != NGX_OK) {
+ return NGX_ERROR;
}

ctx->buf = NULL;
@@ -895,8 +878,7 @@ ngx_stream_js_variable_set(ngx_stream_session_t *s,

ngx_int_t rc;
njs_int_t pending;
- ngx_str_t *fname;
- njs_str_t value;
+ ngx_str_t *fname, value;
ngx_stream_js_ctx_t *ctx;

fname = &vdata->fname;
@@ -919,8 +901,7 @@ ngx_stream_js_variable_set(ngx_stream_session_t *s,

pending = ngx_stream_pending(ctx);

- rc = ngx_js_name_invoke(ctx->vm, fname, s->connection->log, &ctx->args[0],
- 1, &ctx->retval);
+ rc = ctx->engine->call((ngx_js_ctx_t *) ctx, fname, &ctx->args[0], 1);

if (rc == NGX_ERROR) {
v->not_found = 1;
@@ -933,15 +914,15 @@ ngx_stream_js_variable_set(ngx_stream_session_t *s,
return NGX_ERROR;
}

- if (ngx_js_string(ctx->vm, njs_value_arg(&ctx->retval), &value) != NGX_OK) {
+ if (ctx->engine->string(ctx->engine, &ctx->retval, &value) != NGX_OK) {
return NGX_ERROR;
}

- v->len = value.length;
+ v->len = value.len;
v->valid = 1;
v->no_cacheable = vdata->flags & NGX_NJS_VAR_NOCACHE;
v->not_found = 0;
- v->data = value.start;
+ v->data = value.data;

return NGX_OK;
}
@@ -977,18 +958,12 @@ ngx_stream_js_variable_var(ngx_stream_session_t *s,
static ngx_int_t
ngx_stream_js_init_vm(ngx_stream_session_t *s, njs_int_t proto_id)
{
- njs_int_t rc;
- njs_str_t key;
- ngx_str_t exception;
- ngx_uint_t i;
- njs_opaque_value_t retval;
ngx_pool_cleanup_t *cln;
- ngx_js_named_path_t *preload;
ngx_stream_js_ctx_t *ctx;
ngx_stream_js_srv_conf_t *jscf;

jscf = ngx_stream_get_module_srv_conf(s, ngx_stream_js_module);
- if (jscf->vm == NULL) {
+ if (jscf->engine == NULL) {
return NGX_DECLINED;
}

@@ -1000,24 +975,24 @@ ngx_stream_js_init_vm(ngx_stream_session_t *s, njs_int_t proto_id)
return NGX_ERROR;
}

- ngx_js_ctx_init((ngx_js_ctx_t *) ctx);
-
- njs_value_invalid_set(njs_value_arg(&ctx->retval));
+ ngx_js_ctx_init((ngx_js_ctx_t *) ctx, s->connection->log);

ngx_stream_set_ctx(s, ctx, ngx_stream_js_module);
}

- if (ctx->vm) {
+ if (ctx->engine) {
return NGX_OK;
}

- ctx->vm = njs_vm_clone(jscf->vm, s);
- if (ctx->vm == NULL) {
+ ctx->engine = jscf->engine->clone((ngx_js_ctx_t *) ctx,
+ (ngx_js_loc_conf_t *) jscf, proto_id, s);
+ if (ctx->engine == NULL) {
return NGX_ERROR;
}

- ngx_log_debug2(NGX_LOG_DEBUG_STREAM, s->connection->log, 0,
- "stream js vm clone: %p from: %p", ctx->vm, jscf->vm);
+ ngx_log_debug2(NGX_LOG_DEBUG_STREAM, ctx->log, 0,
+ "stream js vm clone: %p from: %p", ctx->engine,
+ jscf->engine);

cln = ngx_pool_cleanup_add(s->connection->pool, 0);
if (cln == NULL) {
@@ -1027,43 +1002,22 @@ ngx_stream_js_init_vm(ngx_stream_session_t *s, njs_int_t proto_id)
cln->handler = ngx_stream_js_cleanup;
cln->data = s;

- /* bind objects from preload vm */
-
- if (jscf->preload_objects != NGX_CONF_UNSET_PTR) {
- preload = jscf->preload_objects->elts;
+ return NGX_OK;
+}

- for (i = 0; i < jscf->preload_objects->nelts; i++) {
- key.start = preload[i].name.data;
- key.length = preload[i].name.len;

- rc = njs_vm_value(jscf->preload_vm, &key, njs_value_arg(&retval));
- if (rc != NJS_OK) {
- return NGX_ERROR;
- }
+static ngx_int_t
+ngx_stream_js_pending_events(ngx_stream_js_ctx_t *ctx)
+{
+ ngx_uint_t i;

- rc = njs_vm_bind(ctx->vm, &key, njs_value_arg(&retval), 0);
- if (rc != NJS_OK) {
- return NGX_ERROR;
- }
+ for (i = 0; i < NGX_JS_EVENT_MAX; i++) {
+ if (ctx->events[i].data_type != NGX_JS_UNSET) {
+ return 1;
}
}

- if (njs_vm_start(ctx->vm, njs_value_arg(&retval)) == NJS_ERROR) {
- ngx_js_exception(ctx->vm, &exception);
-
- ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
- "js exception: %V", &exception);
-
- return NGX_ERROR;
- }
-
- rc = njs_vm_external_create(ctx->vm, njs_value_arg(&ctx->args[0]),
- proto_id, s, 0);
- if (rc != NJS_OK) {
- return NGX_ERROR;
- }
-
- return NGX_OK;
+ return 0;
}


@@ -1073,9 +1027,11 @@ ngx_stream_js_drop_events(ngx_stream_js_ctx_t *ctx)
ngx_uint_t i;

for (i = 0; i < NGX_JS_EVENT_MAX; i++) {
- if (ctx->events[i].function != NULL) {
- ctx->events[i].function = NULL;
- }
+ /*
+ * event[i].data_type = NGX_JS_UNSET
+ * event[i].function = JS_NULL
+ */
+ memset(&ctx->events[i], 0, sizeof(ngx_stream_js_ev_t));
}
}

@@ -1083,38 +1039,41 @@ ngx_stream_js_drop_events(ngx_stream_js_ctx_t *ctx)
static void
ngx_stream_js_cleanup(void *data)
{
- ngx_stream_js_ctx_t *ctx;
+ ngx_stream_js_ctx_t *ctx;
+ ngx_stream_js_srv_conf_t *jscf;

ngx_stream_session_t *s = data;

ctx = ngx_stream_get_module_ctx(s, ngx_stream_js_module);

- ngx_stream_js_drop_events(ctx);
-
- if (ngx_vm_pending(ctx)) {
- ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "pending events");
+ if (ngx_js_ctx_pending(ctx)) {
+ ngx_log_error(NGX_LOG_ERR, ctx->log, 0, "pending events");
}

- ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0,
- "stream js vm destroy: %p", ctx->vm);
+ ngx_log_debug1(NGX_LOG_DEBUG_STREAM, ctx->log, 0,
+ "stream js vm destroy: %p", ctx->engine);
+
+ jscf = ngx_stream_get_module_srv_conf(s, ngx_stream_js_module);

- ngx_js_ctx_destroy((ngx_js_ctx_t *) ctx);
+ ngx_js_ctx_destroy((ngx_js_ctx_t *) ctx, (ngx_js_loc_conf_t *) jscf);
}


-static njs_int_t
+static ngx_int_t
ngx_stream_js_run_event(ngx_stream_session_t *s, ngx_stream_js_ctx_t *ctx,
ngx_stream_js_ev_t *event, ngx_uint_t from_upstream)
{
size_t len;
u_char *p;
+ njs_vm_t *vm;
njs_int_t ret;
+ ngx_str_t exception;
ngx_buf_t *b;
uintptr_t flags;
ngx_connection_t *c;

- if (event->function == NULL) {
- return NJS_OK;
+ if (!njs_value_is_function(njs_value_arg(&event->function))) {
+ return NGX_OK;
}

c = s->connection;
@@ -1122,36 +1081,90 @@ ngx_stream_js_run_event(ngx_stream_session_t *s, ngx_stream_js_ctx_t *ctx,

len = b ? b->last - b->pos : 0;

+ vm = ctx->engine->u.njs.vm;
+
p = ngx_pnalloc(c->pool, len);
if (p == NULL) {
- njs_vm_memory_error(ctx->vm);
- return NJS_ERROR;
+ njs_vm_memory_error(vm);
+ goto error;
}

if (len) {
ngx_memcpy(p, b->pos, len);
}

- ret = ngx_js_prop(ctx->vm, event->data_type, njs_value_arg(&ctx->args[1]),
+ ret = ngx_js_prop(vm, event->data_type, njs_value_arg(&ctx->args[1]),
p, len);
if (ret != NJS_OK) {
- return ret;
+ goto error;
}

flags = from_upstream << 1 | (uintptr_t) (b && b->last_buf);

- ret = njs_vm_external_create(ctx->vm, njs_value_arg(&ctx->args[2]),
+ ret = njs_vm_external_create(vm, njs_value_arg(&ctx->args[2]),
ngx_stream_js_session_flags_proto_id, (void *) flags, 0);
if (ret != NJS_OK) {
+ goto error;
+ }
+
+ ret = ngx_js_call(vm, njs_value_function(njs_value_arg(&event->function)),
+ &ctx->args[1], 2);
+
+ if (ret == NJS_ERROR) {
+error:
+ ngx_js_exception(vm, &exception);
+
+ ngx_log_error(NGX_LOG_ERR, c->log, 0, "js exception: %V",
+ &exception);
+
return NGX_ERROR;
}

- return ngx_js_call(ctx->vm, event->function, njs_value_arg(&ctx->args[1]),
- 2);
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_stream_njs_body_filter(ngx_stream_session_t *s, ngx_stream_js_ctx_t *ctx,
+ ngx_chain_t *in, ngx_uint_t from_upstream)
+{
+ ngx_int_t rc;
+ ngx_chain_t *cl;
+ ngx_stream_js_ev_t *event;
+
+ while (in) {
+ ctx->buf = in->buf;
+
+ event = ngx_stream_event(from_upstream);
+
+ if (njs_value_is_function(njs_value_arg(&event->function))) {
+ rc = ngx_stream_js_run_event(s, ctx, event, from_upstream);
+ if (rc != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+ ctx->buf->pos = ctx->buf->last;
+
+ } else {
+ cl = ngx_alloc_chain_link(s->connection->pool);
+ if (cl == NULL) {
+ return NGX_ERROR;
+ }
+
+ cl->buf = ctx->buf;
+
+ *ctx->last_out = cl;
+ ctx->last_out = &cl->next;
+ }
+
+ in = in->next;
+ }
+
+ return NGX_OK;
}


-static njs_function_t **
+static ngx_stream_js_ev_t *
ngx_stream_js_event(ngx_stream_session_t *s, njs_str_t *event)
{
ngx_uint_t i, n, type;
@@ -1204,7 +1217,7 @@ ngx_stream_js_event(ngx_stream_session_t *s, njs_str_t *event)
}

if (i == n) {
- njs_vm_error(ctx->vm, "unknown event \"%V\"", event);
+ njs_vm_error(ctx->engine->u.njs.vm, "unknown event \"%V\"", event);
return NULL;
}

@@ -1213,13 +1226,13 @@ ngx_stream_js_event(ngx_stream_session_t *s, njs_str_t *event)
for (n = 0; n < NGX_JS_EVENT_MAX; n++) {
type = ctx->events[n].data_type;
if (type != NGX_JS_UNSET && type != events[i].data_type) {
- njs_vm_error(ctx->vm, "mixing string and buffer events"
- " is not allowed");
+ njs_vm_error(ctx->engine->u.njs.vm, "mixing string and buffer"
+ " events is not allowed");
return NULL;
}
}

- return &ctx->events[events[i].id].function;
+ return &ctx->events[events[i].id];
}


@@ -1305,10 +1318,10 @@ static njs_int_t
ngx_stream_js_ext_on(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
njs_index_t unused, njs_value_t *retval)
{
- njs_str_t name;
- njs_value_t *callback;
- njs_function_t **cb;
- ngx_stream_session_t *s;
+ njs_str_t name;
+ njs_value_t *callback;
+ ngx_stream_js_ev_t *event;
+ ngx_stream_session_t *s;

s = njs_vm_external(vm, ngx_stream_js_session_proto_id,
njs_argument(args, 0));
@@ -1328,17 +1341,17 @@ ngx_stream_js_ext_on(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
return NJS_ERROR;
}

- cb = ngx_stream_js_event(s, &name);
- if (cb == NULL) {
+ event = ngx_stream_js_event(s, &name);
+ if (event == NULL) {
return NJS_ERROR;
}

- if (*cb != NULL) {
+ if (njs_value_is_function(njs_value_arg(&event->function))) {
njs_vm_error(vm, "event handler \"%V\" is already set", &name);
return NJS_ERROR;
}

- *cb = njs_value_function(callback);
+ njs_value_assign(&event->function, callback);

njs_value_undefined_set(retval);

@@ -1350,9 +1363,9 @@ static njs_int_t
ngx_stream_js_ext_off(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
njs_index_t unused, njs_value_t *retval)
{
- njs_str_t name;
- njs_function_t **callback;
- ngx_stream_session_t *s;
+ njs_str_t name;
+ ngx_stream_js_ev_t *event;
+ ngx_stream_session_t *s;

s = njs_vm_external(vm, ngx_stream_js_session_proto_id,
njs_argument(args, 0));
@@ -1366,12 +1379,13 @@ ngx_stream_js_ext_off(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
return NJS_ERROR;
}

- callback = ngx_stream_js_event(s, &name);
- if (callback == NULL) {
+ event = ngx_stream_js_event(s, &name);
+ if (event == NULL) {
return NJS_ERROR;
}

- *callback = NULL;
+ njs_value_null_set(njs_value_arg(&event->function));
+ event->data_type = NGX_JS_UNSET;

njs_value_undefined_set(retval);

@@ -1764,22 +1778,52 @@ ngx_js_stream_init(njs_vm_t *vm)
}


+static ngx_engine_t *
+ngx_engine_njs_clone(ngx_js_ctx_t *ctx, ngx_js_loc_conf_t *cf,
+ njs_int_t proto_id, void *external)
+{
+ njs_int_t rc;
+ ngx_engine_t *engine;
+ ngx_stream_js_ctx_t *sctx;
+
+ engine = ngx_njs_clone(ctx, cf, external);
+ if (engine == NULL) {
+ return NULL;
+ }
+
+ sctx = (ngx_stream_js_ctx_t *) ctx;
+ sctx->run_event = ngx_stream_js_run_event;
+ sctx->body_filter = ngx_stream_njs_body_filter;
+
+ rc = njs_vm_external_create(engine->u.njs.vm, njs_value_arg(&ctx->args[0]),
+ proto_id, njs_vm_external_ptr(engine->u.njs.vm),
+ 0);
+ if (rc != NJS_OK) {
+ return NULL;
+ }
+
+ return engine;
+}
+
+
static ngx_int_t
ngx_stream_js_init_conf_vm(ngx_conf_t *cf, ngx_js_loc_conf_t *conf)
{
- njs_vm_opt_t options;
+ ngx_engine_opts_t options;
ngx_js_main_conf_t *jmcf;

- njs_vm_opt_init(&options);
+ memset(&options, 0, sizeof(ngx_engine_opts_t));

- jmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_js_module);
- ngx_stream_js_uptr[NGX_JS_MAIN_CONF_INDEX] = (uintptr_t) jmcf;
+ options.engine = conf->type;

- options.backtrace = 1;
- options.metas = &ngx_stream_js_metas;
- options.addons = njs_stream_js_addon_modules;
- options.argv = ngx_argv;
- options.argc = ngx_argc;
+ if (conf->type == NGX_ENGINE_NJS) {
+ jmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_js_module);
+ ngx_stream_js_uptr[NGX_JS_MAIN_CONF_INDEX] = (uintptr_t) jmcf;
+
+ options.u.njs.metas = &ngx_stream_js_metas;
+ options.u.njs.addons = njs_stream_js_addon_modules;
+ options.clone = ngx_engine_njs_clone;
+ }

return ngx_js_init_conf_vm(cf, conf, &options);
}
@@ -1881,8 +1925,8 @@ ngx_stream_js_periodic_handler(ngx_event_t *ev)

s->received++;

- rc = ngx_js_name_invoke(ctx->vm, &periodic->method, &periodic->log,
- &ctx->args[0], 1, &ctx->retval);
+ rc = ctx->engine->call((ngx_js_ctx_t *) ctx, &periodic->method,
+ &ctx->args[0], 1);

if (rc == NGX_AGAIN) {
rc = NGX_OK;
@@ -1925,7 +1969,7 @@ ngx_stream_js_periodic_event_handler(ngx_event_t *ev)

ctx = ngx_stream_get_module_ctx(s, ngx_stream_js_module);

- if (!ngx_vm_pending(ctx)) {
+ if (!ngx_js_ctx_pending(ctx)) {
ngx_stream_js_periodic_finalize(s, NGX_OK);
return;
}
@@ -1942,9 +1986,9 @@ ngx_stream_js_periodic_finalize(ngx_stream_session_t *s, ngx_int_t rc)
ngx_log_debug4(NGX_LOG_DEBUG_STREAM, s->connection->log, 0,
"stream js periodic finalize: \"%V\" rc: %i c: %i "
"pending: %i", &ctx->periodic->method, rc, s->received,
- ngx_vm_pending(ctx));
+ ngx_js_ctx_pending(ctx));

- if (s->received > 1 || (rc == NGX_OK && ngx_vm_pending(ctx))) {
+ if (s->received > 1 || (rc == NGX_OK && ngx_js_ctx_pending(ctx))) {
return;
}

@@ -2348,6 +2392,7 @@ ngx_stream_js_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_stream_js_srv_conf_t *prev = parent;
ngx_stream_js_srv_conf_t *conf = child;

+ ngx_conf_merge_uint_value(conf->type, prev->type, NGX_ENGINE_NJS);
ngx_conf_merge_str_value(conf->access, prev->access, "");
ngx_conf_merge_str_value(conf->preread, prev->preread, "");
ngx_conf_merge_str_value(conf->filter, prev->filter, "");
_______________________________________________
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel
Subject Author Views Posted

[njs] Modules: introduced engine API.

Anonymous User 123 September 17, 2024 09:08PM



Sorry, you do not have permission to post/reply in this forum.

Online Users

Guests: 122
Record Number of Users: 8 on April 13, 2023
Record Number of Guests: 500 on July 15, 2024
Powered by nginx      Powered by FreeBSD      PHP Powered      Powered by MariaDB      ipv6 ready