Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions nginx/config
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ fi

if [ $HTTP != NO ]; then
ngx_module_type=HTTP_AUX_FILTER
ngx_module_name=ngx_http_js_module
ngx_module_name="ngx_http_js_module ngx_http_js_core_module"
ngx_module_incs="$ngx_addon_dir/../src $ngx_addon_dir/../build \
$NJS_QUICKJS_INC"
ngx_module_deps="$NJS_ENGINE_DEP $NJS_DEPS $QJS_DEPS"
Expand All @@ -174,7 +174,7 @@ fi

if [ $STREAM != NO ]; then
ngx_module_type=STREAM
ngx_module_name=ngx_stream_js_module
ngx_module_name="ngx_stream_js_module ngx_stream_js_core_module"
ngx_module_incs="$ngx_addon_dir/../src $ngx_addon_dir/../build \
$NJS_QUICKJS_INC"
ngx_module_deps="$NJS_ENGINE_DEP $NJS_DEPS $QJS_DEPS"
Expand Down
39 changes: 39 additions & 0 deletions nginx/ngx_http_js_module.c
Original file line number Diff line number Diff line change
Expand Up @@ -608,6 +608,42 @@ static ngx_command_t ngx_http_js_commands[] = {
};


static ngx_command_t ngx_js_core_commands[] = {

{ ngx_string("js_load_http_native_module"),
NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE13,
ngx_js_core_load_native_module,
0,
0,
NULL },

ngx_null_command
};


static ngx_core_module_t ngx_js_core_module_ctx = {
ngx_string("ngx_http_js_core"),
ngx_js_core_create_conf,
NULL
};


ngx_module_t ngx_http_js_core_module = {
NGX_MODULE_V1,
&ngx_js_core_module_ctx, /* module context */
ngx_js_core_commands, /* module directives */
NGX_CORE_MODULE, /* module type */
NULL, /* init master */
NULL, /* init module */
NULL, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
NULL, /* exit master */
NGX_MODULE_V1_PADDING
};


static ngx_http_module_t ngx_http_js_module_ctx = {
NULL, /* preconfiguration */
ngx_http_js_init, /* postconfiguration */
Expand Down Expand Up @@ -7760,6 +7796,9 @@ ngx_http_js_init_conf_vm(ngx_conf_t *cf, ngx_js_loc_conf_t *conf)
options.u.qjs.metas = ngx_http_js_uptr;
options.u.qjs.addons = njs_http_qjs_addon_modules;
options.clone = ngx_engine_qjs_clone;

options.core_conf = (ngx_js_core_conf_t *)
ngx_get_conf(cf->cycle->conf_ctx, ngx_http_js_core_module);
}
#endif

Expand Down
228 changes: 224 additions & 4 deletions nginx/ngx_js.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <ngx_config.h>
#include <ngx_core.h>
#include <math.h>
#include <dlfcn.h>
#include "ngx_js.h"
#include "ngx_js_http.h"

Expand Down Expand Up @@ -541,6 +542,8 @@ ngx_create_engine(ngx_engine_opts_t *opts)
engine->string = ngx_engine_qjs_string;
engine->destroy = opts->destroy ? opts->destroy
: ngx_engine_qjs_destroy;

engine->core_conf = opts->core_conf;
break;
#endif

Expand Down Expand Up @@ -1005,6 +1008,7 @@ ngx_qjs_clone(ngx_js_ctx_t *ctx, ngx_js_loc_conf_t *cf, void *external)
ngx_int_t rc;
JSRuntime *rt;
JSContext *cx;
qjs_module_t *mod;
ngx_engine_t *engine;
ngx_js_code_entry_t *pc;

Expand Down Expand Up @@ -1050,6 +1054,19 @@ ngx_qjs_clone(ngx_js_ctx_t *ctx, ngx_js_loc_conf_t *cf, void *external)

JS_SetHostPromiseRejectionTracker(rt, ngx_qjs_rejection_tracker, ctx);

if (engine->native_modules != NULL) {
mod = engine->native_modules->start;
length = engine->native_modules->items;

for (i = 0; i < length; i++) {
if (mod[i].init(cx, mod[i].name) == NULL) {
ngx_log_error(NGX_LOG_ERR, ctx->log, 0,
"js native module init failed: %s", mod[i].name);
goto destroy;
}
}
}

rv = JS_UNDEFINED;
pc = engine->precompiled->start;
length = engine->precompiled->items;
Expand Down Expand Up @@ -2026,6 +2043,55 @@ ngx_qjs_ext_console_time_end(JSContext *cx, JSValueConst this_val, int argc,
}


static JSModuleDef *
ngx_qjs_native_module_lookup(JSContext *cx, const char *module_name,
ngx_js_loc_conf_t *conf)
{
ngx_uint_t i;
JSModuleDef *m;
qjs_module_t *mod, *modules;
ngx_js_core_conf_t *jccf;

jccf = conf->engine->core_conf;
if (jccf == NULL || jccf->native_modules == NULL) {
return NULL;
}

modules = jccf->native_modules->elts;

for (i = 0; i < jccf->native_modules->nelts; i++) {
if (ngx_strcmp(modules[i].name, module_name) == 0) {
m = modules[i].init(cx, module_name);
if (m == NULL) {
return NULL;
}

if (conf->engine->native_modules == NULL) {
conf->engine->native_modules = njs_arr_create(
conf->engine->pool, 4,
sizeof(qjs_module_t));
if (conf->engine->native_modules == NULL) {
JS_ThrowOutOfMemory(cx);
return NULL;
}
}

mod = njs_arr_add(conf->engine->native_modules);
if (mod == NULL) {
JS_ThrowOutOfMemory(cx);
return NULL;
}

*mod = modules[i];

return m;
}
}

return NULL;
}


static JSModuleDef *
ngx_qjs_module_loader(JSContext *cx, const char *module_name, void *opaque)
{
Expand All @@ -2039,6 +2105,11 @@ ngx_qjs_module_loader(JSContext *cx, const char *module_name, void *opaque)

conf = opaque;

m = ngx_qjs_native_module_lookup(cx, module_name, conf);
if (m != NULL) {
return m;
}

njs_memzero(&info, sizeof(njs_module_info_t));

info.name.start = (u_char *) module_name;
Expand Down Expand Up @@ -3597,6 +3668,17 @@ ngx_js_init_preload_vm(njs_vm_t *vm, ngx_js_loc_conf_t *conf)
}


/*
* Merge configuration values used at configuration time.
*/
static void
ngx_js_merge_conftime_loc_conf(ngx_js_loc_conf_t *conf,
ngx_js_loc_conf_t *prev)
{
ngx_conf_merge_uint_value(conf->type, prev->type, NGX_ENGINE_NJS);
}


ngx_int_t
ngx_js_merge_vm(ngx_conf_t *cf, ngx_js_loc_conf_t *conf,
ngx_js_loc_conf_t *prev,
Expand All @@ -3612,6 +3694,9 @@ ngx_js_merge_vm(ngx_conf_t *cf, ngx_js_loc_conf_t *conf,
* special handling to preserve conf->engine
* in the "http" or "stream" section to inherit it to all servers
*/

ngx_js_merge_conftime_loc_conf(prev, conf);

if (init_vm(cf, (ngx_js_loc_conf_t *) prev) != NGX_OK) {
return NGX_ERROR;
}
Expand Down Expand Up @@ -4316,10 +4401,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);
if (prev->type == NGX_CONF_UNSET_UINT) {
prev->type = NGX_ENGINE_NJS;
}
ngx_js_merge_conftime_loc_conf(conf, prev);

ngx_conf_merge_msec_value(conf->timeout, prev->timeout, 60000);
ngx_conf_merge_size_value(conf->reuse, prev->reuse, 128);
Expand Down Expand Up @@ -4380,6 +4462,144 @@ ngx_js_merge_conf(ngx_conf_t *cf, void *parent, void *child,
}


void *
ngx_js_core_create_conf(ngx_cycle_t *cycle)
{
ngx_js_core_conf_t *jccf;

jccf = ngx_pcalloc(cycle->pool, sizeof(ngx_js_core_conf_t));
if (jccf == NULL) {
return NULL;
}

/*
* set by ngx_pcalloc():
*
* jccf->native_modules = NULL;
*/

return jccf;
}


void
ngx_js_native_module_cleanup(void *data)
{
void *handle = data;

if (dlclose(handle) != 0) {
ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
"dlclose() failed: %s", dlerror());
}
}


char *
ngx_js_core_load_native_module(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
#if (NJS_HAVE_QUICKJS)
void *handle;
u_char *p;
ngx_str_t *value, file, name;
qjs_module_t *module;
qjs_addon_init_pt init;
ngx_pool_cleanup_t *cln;

ngx_js_core_conf_t *jccf = conf;

if (cf->cycle->modules_used) {
return "is specified too late";
}

value = cf->args->elts;
file = value[1];

if (ngx_conf_full_name(cf->cycle, &file, 0) != NGX_OK) {
return NGX_CONF_ERROR;
}

if (cf->args->nelts == 4) {
if (ngx_strcmp(value[2].data, "as") != 0) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid parameter \"%V\", expected \"as\"",
&value[2]);
return NGX_CONF_ERROR;
}

name = value[3];

} else {
name = file;

for (p = file.data + file.len - 1; p >= file.data; p--) {
if (*p == '/') {
name.data = p + 1;
name.len = file.data + file.len - name.data;
break;
}
}
}

handle = dlopen((char *) file.data, RTLD_NOW | RTLD_LOCAL);
if (handle == NULL) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"dlopen(\"%V\") failed: %s", &file, dlerror());
return NGX_CONF_ERROR;
}

cln = ngx_pool_cleanup_add(cf->cycle->pool, 0);
if (cln == NULL) {
dlclose(handle);
return NGX_CONF_ERROR;
}

cln->handler = ngx_js_native_module_cleanup;
cln->data = handle;

init = dlsym(handle, "js_init_module");
if (init == NULL) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"dlsym(\"%V\", \"js_init_module\") failed: %s",
&file, dlerror());
return NGX_CONF_ERROR;
}

if (jccf->native_modules == NULL) {
jccf->native_modules = ngx_array_create(cf->cycle->pool, 4,
sizeof(qjs_module_t));
if (jccf->native_modules == NULL) {
return NGX_CONF_ERROR;
}
}

module = ngx_array_push(jccf->native_modules);
if (module == NULL) {
return NGX_CONF_ERROR;
}

p = ngx_palloc(cf->cycle->pool, name.len + 1);
if (p == NULL) {
return NGX_CONF_ERROR;
}

ngx_memcpy(p, name.data, name.len);
p[name.len] = '\0';

module->name = (const char *) p;
module->init = init;

return NGX_CONF_OK;

#else

ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"\"load_js_native_module\" requires QuickJS support");
return NGX_CONF_ERROR;

#endif
}


static uint64_t
ngx_js_monotonic_time(void)
{
Expand Down
Loading