details: https://hg.nginx.org/njs/rev/52b3e1f2a3e1 branches: changeset: 1957:52b3e1f2a3e1 user: Vadim Zhestikov <v.zhesti...@f5.com> date: Fri Sep 16 12:27:40 2022 -0700 description: Modules: added js_preload_object directive.
diffstat: nginx/ngx_http_js_module.c | 100 +++++++++++++++++++- nginx/ngx_js.c | 200 +++++++++++++++++++++++++++++++++++++++++++ nginx/ngx_js.h | 7 +- nginx/ngx_stream_js_module.c | 100 +++++++++++++++++++- 4 files changed, 392 insertions(+), 15 deletions(-) diffs (599 lines): diff -r 82f41f43abd4 -r 52b3e1f2a3e1 nginx/ngx_http_js_module.c --- a/nginx/ngx_http_js_module.c Thu Sep 15 20:20:11 2022 -0700 +++ b/nginx/ngx_http_js_module.c Fri Sep 16 12:27:40 2022 -0700 @@ -294,6 +294,13 @@ static ngx_command_t ngx_http_js_comman 0, NULL }, + { ngx_string("js_preload_object"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE13, + ngx_js_preload_object, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + { ngx_string("js_path"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_str_array_slot, @@ -1212,8 +1219,12 @@ ngx_http_js_init_vm(ngx_http_request_t * { 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); @@ -1253,6 +1264,27 @@ ngx_http_js_init_vm(ngx_http_request_t * 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_ERROR) { ngx_js_retval(ctx->vm, NULL, &exception); @@ -1288,9 +1320,13 @@ ngx_http_js_cleanup_ctx(void *data) static void ngx_http_js_cleanup_vm(void *data) { - njs_vm_t *vm = data; - - njs_vm_destroy(vm); + ngx_http_js_loc_conf_t *jlcf = data; + + njs_vm_destroy(jlcf->vm); + + if (jlcf->preload_objects != NGX_CONF_UNSET_PTR) { + njs_vm_destroy(jlcf->preload_vm); + } } @@ -4172,8 +4208,8 @@ ngx_http_js_merge_vm(ngx_conf_t *cf, ngx { ngx_str_t *path, *s; ngx_uint_t i; - ngx_array_t *imports, *paths; - ngx_js_named_path_t *import, *pi; + ngx_array_t *imports, *preload_objects, *paths; + ngx_js_named_path_t *import, *pi, *pij, *preload; if (prev->imports != NGX_CONF_UNSET_PTR && prev->vm == NULL) { if (ngx_http_js_init_conf_vm(cf, prev) != NGX_OK) { @@ -4182,16 +4218,58 @@ ngx_http_js_merge_vm(ngx_conf_t *cf, ngx } if (conf->imports == NGX_CONF_UNSET_PTR - && conf->paths == NGX_CONF_UNSET_PTR) + && conf->paths == NGX_CONF_UNSET_PTR + && conf->preload_objects == NGX_CONF_UNSET_PTR) { if (prev->vm != NULL) { + conf->preload_objects = prev->preload_objects; conf->imports = prev->imports; conf->paths = prev->paths; conf->vm = prev->vm; + + conf->preload_vm = prev->preload_vm; + return NGX_OK; } } + if (prev->preload_objects != NGX_CONF_UNSET_PTR) { + if (conf->preload_objects == NGX_CONF_UNSET_PTR) { + conf->preload_objects = prev->preload_objects; + + } else { + preload_objects = ngx_array_create(cf->pool, 4, + sizeof(ngx_js_named_path_t)); + if (preload_objects == NULL) { + return NGX_ERROR; + } + + pij = prev->preload_objects->elts; + + for (i = 0; i < prev->preload_objects->nelts; i++) { + preload = ngx_array_push(preload_objects); + if (preload == NULL) { + return NGX_ERROR; + } + + *preload = pij[i]; + } + + pij = conf->preload_objects->elts; + + for (i = 0; i < conf->preload_objects->nelts; i++) { + preload = ngx_array_push(preload_objects); + if (preload == NULL) { + return NGX_ERROR; + } + + *preload = pij[i]; + } + + conf->preload_objects = preload_objects; + } + } + if (prev->imports != NGX_CONF_UNSET_PTR) { if (conf->imports == NGX_CONF_UNSET_PTR) { conf->imports = prev->imports; @@ -4291,6 +4369,12 @@ ngx_http_js_init_conf_vm(ngx_conf_t *cf, 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_conf_t *)conf) != NGX_OK) { + return NGX_ERROR; + } + } + size = 0; import = conf->imports->elts; @@ -4352,7 +4436,7 @@ ngx_http_js_init_conf_vm(ngx_conf_t *cf, } cln->handler = ngx_http_js_cleanup_vm; - cln->data = conf->vm; + cln->data = conf; path.start = ngx_cycle->conf_prefix.data; path.length = ngx_cycle->conf_prefix.len; @@ -4619,6 +4703,7 @@ ngx_http_js_create_loc_conf(ngx_conf_t * * set by ngx_pcalloc(): * * conf->vm = NULL; + * conf->preload_vm = NULL; * conf->content = { 0, NULL }; * conf->header_filter = { 0, NULL }; * conf->body_filter = { 0, NULL }; @@ -4630,6 +4715,7 @@ ngx_http_js_create_loc_conf(ngx_conf_t * conf->paths = NGX_CONF_UNSET_PTR; conf->imports = NGX_CONF_UNSET_PTR; + conf->preload_objects = NGX_CONF_UNSET_PTR; conf->buffer_size = NGX_CONF_UNSET_SIZE; conf->max_response_body_size = NGX_CONF_UNSET_SIZE; diff -r 82f41f43abd4 -r 52b3e1f2a3e1 nginx/ngx_js.c --- a/nginx/ngx_js.c Thu Sep 15 20:20:11 2022 -0700 +++ b/nginx/ngx_js.c Fri Sep 16 12:27:40 2022 -0700 @@ -493,3 +493,203 @@ ngx_js_import(ngx_conf_t *cf, ngx_comman return NGX_CONF_OK; } + +char * +ngx_js_preload_object(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_js_conf_t *jscf = conf; + + u_char *p, *end, c; + ngx_int_t from; + ngx_str_t *value, name, path; + ngx_js_named_path_t *preload; + + value = cf->args->elts; + from = (cf->args->nelts == 4); + + if (from) { + if (ngx_strcmp(value[2].data, "from") != 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid parameter \"%V\"", &value[2]); + return NGX_CONF_ERROR; + } + } + + name = value[1]; + path = (from ? value[3] : value[1]); + + if (!from) { + end = name.data + name.len; + + for (p = end - 1; p >= name.data; p--) { + if (*p == '/') { + break; + } + } + + name.data = p + 1; + name.len = end - p - 1; + + if (name.len < 5 + || ngx_memcmp(&name.data[name.len - 5], ".json", 5) != 0) + { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "cannot extract export name from file path " + "\"%V\", use extended \"from\" syntax", &path); + return NGX_CONF_ERROR; + } + + name.len -= 5; + } + + if (name.len == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "empty global name"); + return NGX_CONF_ERROR; + } + + p = name.data; + end = name.data + name.len; + + while (p < end) { + c = ngx_tolower(*p); + + if (*p != '_' && (c < 'a' || c > 'z')) { + if (p == name.data) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "cannot start " + "with \"%c\" in global name \"%V\"", *p, + &name); + return NGX_CONF_ERROR; + } + + if (*p < '0' || *p > '9' || *p == '.') { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid character " + "\"%c\" in global name \"%V\"", *p, + &name); + return NGX_CONF_ERROR; + } + } + + p++; + } + + if (ngx_strchr(path.data, '\'') != NULL) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid character \"'\" " + "in file path \"%V\"", &path); + return NGX_CONF_ERROR; + } + + if (jscf->preload_objects == NGX_CONF_UNSET_PTR) { + jscf->preload_objects = ngx_array_create(cf->pool, 4, + sizeof(ngx_js_named_path_t)); + if (jscf->preload_objects == NULL) { + return NGX_CONF_ERROR; + } + } + + preload = ngx_array_push(jscf->preload_objects); + if (preload == NULL) { + return NGX_CONF_ERROR; + } + + preload->name = name; + preload->path = path; + preload->file = cf->conf_file->file.name.data; + preload->line = cf->conf_file->line; + + return NGX_CONF_OK; +} + + +ngx_int_t +ngx_js_init_preload_vm(ngx_conf_t *cf, ngx_js_conf_t *conf) +{ + u_char *p, *start; + size_t size; + njs_vm_t *vm; + njs_int_t ret; + ngx_uint_t i; + njs_vm_opt_t options; + ngx_js_named_path_t *preload; + + njs_vm_opt_init(&options); + + options.init = 1; + + vm = njs_vm_create(&options); + if (vm == NULL) { + goto error; + } + + ret = ngx_js_core_init(vm, cf->log); + if (njs_slow_path(ret != NJS_OK)) { + goto error; + } + + njs_str_t str = njs_str( + "import fs from 'fs';" + + "let g = (function (np, no, nf, nsp, r) {" + "return function (n, p) {" + "p = (p[0] == '/') ? p : ngx.conf_prefix + p;" + "let o = r(p);" + "globalThis[n] = np(" + "o," + "function (k, v) {" + "if (v instanceof no) {" + "nf(nsp(v, null));" + "}" + "return v;" + "}" + ");" + "return;" + "}" + "})(JSON.parse,Object,Object.freeze," + "Object.setPrototypeOf,fs.readFileSync);\n" + ); + + size = str.length; + + preload = conf->preload_objects->elts; + for (i = 0; i < conf->preload_objects->nelts; i++) { + size += sizeof("g('','');\n") - 1 + preload[i].name.len + + preload[i].path.len; + } + + start = ngx_pnalloc(cf->pool, size); + if (start == NULL) { + return NGX_ERROR; + } + + p = ngx_cpymem(start, str.start, str.length); + + preload = conf->preload_objects->elts; + for (i = 0; i < conf->preload_objects->nelts; i++) { + p = ngx_cpymem(p, "g('", sizeof("g('") - 1); + p = ngx_cpymem(p, preload[i].name.data, preload[i].name.len); + p = ngx_cpymem(p, "','", sizeof("','") - 1); + p = ngx_cpymem(p, preload[i].path.data, preload[i].path.len); + p = ngx_cpymem(p, "');\n", sizeof("');\n") - 1); + } + + ret = njs_vm_compile(vm, &start, start + size); + if (ret != NJS_OK) { + goto error; + } + + ret = njs_vm_start(vm); + if (ret != NJS_OK) { + goto error; + } + + conf->preload_vm = vm; + + return NGX_OK; + +error: + + if (vm != NULL) { + njs_vm_destroy(vm); + } + + return NGX_ERROR; +} diff -r 82f41f43abd4 -r 52b3e1f2a3e1 nginx/ngx_js.h --- a/nginx/ngx_js.h Thu Sep 15 20:20:11 2022 -0700 +++ b/nginx/ngx_js.h Fri Sep 16 12:27:40 2022 -0700 @@ -49,7 +49,10 @@ typedef struct { #define NGX_JS_COMMON_CONF \ njs_vm_t *vm; \ ngx_array_t *imports; \ - ngx_array_t *paths \ + ngx_array_t *paths; \ + \ + njs_vm_t *preload_vm; \ + ngx_array_t *preload_objects \ typedef struct { NGX_JS_COMMON_CONF; @@ -93,6 +96,8 @@ njs_int_t ngx_js_ext_log(njs_vm_t *vm, n void ngx_js_logger(njs_vm_t *vm, njs_external_ptr_t external, njs_log_level_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_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_conf_t *conf); njs_int_t ngx_js_ext_string(njs_vm_t *vm, njs_object_prop_t *prop, njs_value_t *value, njs_value_t *setval, njs_value_t *retval); diff -r 82f41f43abd4 -r 52b3e1f2a3e1 nginx/ngx_stream_js_module.c --- a/nginx/ngx_stream_js_module.c Thu Sep 15 20:20:11 2022 -0700 +++ b/nginx/ngx_stream_js_module.c Fri Sep 16 12:27:40 2022 -0700 @@ -169,6 +169,13 @@ static ngx_command_t ngx_stream_js_comm 0, NULL }, + { ngx_string("js_preload_object"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE13, + ngx_js_preload_object, + NGX_STREAM_SRV_CONF_OFFSET, + 0, + NULL }, + { ngx_string("js_path"), NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, ngx_conf_set_str_array_slot, @@ -858,8 +865,12 @@ static ngx_int_t ngx_stream_js_init_vm(ngx_stream_session_t *s) { 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; @@ -898,6 +909,27 @@ ngx_stream_js_init_vm(ngx_stream_session 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; + + 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; + } + + 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_ERROR) { ngx_js_retval(ctx->vm, NULL, &exception); @@ -953,9 +985,13 @@ ngx_stream_js_cleanup(void *data) static void ngx_stream_js_cleanup_vm(void *data) { - njs_vm_t *vm = data; - - njs_vm_destroy(vm); + ngx_stream_js_srv_conf_t *jscf = data; + + njs_vm_destroy(jscf->vm); + + if (jscf->preload_objects != NGX_CONF_UNSET_PTR) { + njs_vm_destroy(jscf->preload_vm); + } } @@ -1644,8 +1680,8 @@ ngx_stream_js_merge_vm(ngx_conf_t *cf, n { ngx_str_t *path, *s; ngx_uint_t i; - ngx_array_t *imports, *paths; - ngx_js_named_path_t *import, *pi; + ngx_array_t *imports, *preload_objects, *paths; + ngx_js_named_path_t *import, *pi, *pij, *preload; if (prev->imports != NGX_CONF_UNSET_PTR && prev->vm == NULL) { if (ngx_stream_js_init_conf_vm(cf, prev) != NGX_OK) { @@ -1654,16 +1690,58 @@ ngx_stream_js_merge_vm(ngx_conf_t *cf, n } if (conf->imports == NGX_CONF_UNSET_PTR - && conf->paths == NGX_CONF_UNSET_PTR) + && conf->paths == NGX_CONF_UNSET_PTR + && conf->preload_objects == NGX_CONF_UNSET_PTR) { if (prev->vm != NULL) { + conf->preload_objects = prev->preload_objects; conf->imports = prev->imports; conf->paths = prev->paths; conf->vm = prev->vm; + + conf->preload_vm = prev->preload_vm; + return NGX_OK; } } + if (prev->preload_objects != NGX_CONF_UNSET_PTR) { + if (conf->preload_objects == NGX_CONF_UNSET_PTR) { + conf->preload_objects = prev->preload_objects; + + } else { + preload_objects = ngx_array_create(cf->pool, 4, + sizeof(ngx_js_named_path_t)); + if (preload_objects == NULL) { + return NGX_ERROR; + } + + pij = prev->preload_objects->elts; + + for (i = 0; i < prev->preload_objects->nelts; i++) { + preload = ngx_array_push(preload_objects); + if (preload == NULL) { + return NGX_ERROR; + } + + *preload = pij[i]; + } + + pij = conf->preload_objects->elts; + + for (i = 0; i < conf->preload_objects->nelts; i++) { + preload = ngx_array_push(preload_objects); + if (preload == NULL) { + return NGX_ERROR; + } + + *preload = pij[i]; + } + + conf->preload_objects = preload_objects; + } + } + if (prev->imports != NGX_CONF_UNSET_PTR) { if (conf->imports == NGX_CONF_UNSET_PTR) { conf->imports = prev->imports; @@ -1763,6 +1841,12 @@ ngx_stream_js_init_conf_vm(ngx_conf_t *c 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_conf_t *)conf) != NGX_OK) { + return NGX_ERROR; + } + } + size = 0; import = conf->imports->elts; @@ -1823,7 +1907,7 @@ ngx_stream_js_init_conf_vm(ngx_conf_t *c } cln->handler = ngx_stream_js_cleanup_vm; - cln->data = conf->vm; + cln->data = conf; path.start = ngx_cycle->conf_prefix.data; path.length = ngx_cycle->conf_prefix.len; @@ -2026,6 +2110,7 @@ ngx_stream_js_create_srv_conf(ngx_conf_t * set by ngx_pcalloc(): * * conf->vm = NULL; + * conf->preload_vm = NULL; * conf->access = { 0, NULL }; * conf->preread = { 0, NULL }; * conf->filter = { 0, NULL }; @@ -2040,6 +2125,7 @@ ngx_stream_js_create_srv_conf(ngx_conf_t conf->buffer_size = NGX_CONF_UNSET_SIZE; conf->max_response_body_size = NGX_CONF_UNSET_SIZE; conf->timeout = NGX_CONF_UNSET_MSEC; + conf->preload_objects = NGX_CONF_UNSET_PTR; #if (NGX_STREAM_SSL) conf->ssl_verify = NGX_CONF_UNSET; _______________________________________________ nginx-devel mailing list -- nginx-devel@nginx.org To unsubscribe send an email to nginx-devel-le...@nginx.org