From 2c1fee612af42ee7979e9e3c219ae728bd3645d5 Mon Sep 17 00:00:00 2001 From: Dmitry Volyntsev Date: Tue, 23 Jan 2024 16:34:10 -0800 Subject: [PATCH] Moving out HostLoadImportedModule from njs core. HostLoadImportedModule should be implemented by host environment according to ECMAScript specs. The following method was removed: njs_vm_add_path(). --- external/njs_shell.c | 228 +++++++++++++++++++++++++++++++++++++----- nginx/ngx_js.c | 211 +++++++++++++++++++++++++++++++++++---- src/njs.h | 2 - src/njs_module.c | 230 ------------------------------------------- src/njs_module.h | 1 - src/njs_parser.c | 39 ++++++++ src/njs_vm.c | 23 ----- src/njs_vm.h | 1 - 8 files changed, 437 insertions(+), 298 deletions(-) diff --git a/external/njs_shell.c b/external/njs_shell.c index 805615c9..83ca4aca 100644 --- a/external/njs_shell.c +++ b/external/njs_shell.c @@ -47,7 +47,7 @@ typedef struct { char *file; njs_str_t command; size_t n_paths; - char **paths; + njs_str_t *paths; char **argv; njs_uint_t argc; } njs_opts_t; @@ -98,6 +98,14 @@ typedef struct { } njs_rejected_promise_t; +typedef struct { + int fd; + njs_str_t name; + njs_str_t file; + char path[NJS_MAX_PATH + 1]; +} njs_module_info_t; + + typedef struct { njs_vm_t *vm; @@ -129,6 +137,8 @@ static njs_int_t njs_process_script(njs_vm_t *vm, void *runtime, #ifndef NJS_FUZZER_TARGET static njs_int_t njs_options_parse(njs_opts_t *opts, int argc, char **argv); +static njs_int_t njs_options_add_path(njs_opts_t *opts, u_char *path, + size_t len); static void njs_options_free(njs_opts_t *opts); #ifdef NJS_HAVE_READLINE @@ -390,7 +400,7 @@ done: static njs_int_t njs_options_parse(njs_opts_t *opts, int argc, char **argv) { - char *p, **paths; + char *p; njs_int_t i, ret; njs_uint_t n; @@ -516,15 +526,13 @@ njs_options_parse(njs_opts_t *opts, int argc, char **argv) case 'p': if (++i < argc) { - opts->n_paths++; - paths = realloc(opts->paths, opts->n_paths * sizeof(char *)); - if (paths == NULL) { + ret = njs_options_add_path(opts, (u_char *) argv[i], + njs_strlen(argv[i])); + if (ret != NJS_OK) { njs_stderror("failed to add path\n"); return NJS_ERROR; } - opts->paths = paths; - opts->paths[opts->n_paths - 1] = argv[i]; break; } @@ -595,6 +603,27 @@ done: } +static njs_int_t +njs_options_add_path(njs_opts_t *opts, u_char *path, size_t len) +{ + njs_str_t *paths; + + opts->n_paths++; + + paths = realloc(opts->paths, opts->n_paths * sizeof(njs_str_t)); + if (paths == NULL) { + njs_stderror("failed to add path\n"); + return NJS_ERROR; + } + + opts->paths = paths; + opts->paths[opts->n_paths - 1].start = path; + opts->paths[opts->n_paths - 1].length = len; + + return NJS_OK; +} + + static void njs_options_free(njs_opts_t *opts) { @@ -806,14 +835,179 @@ njs_rejection_tracker(njs_vm_t *vm, njs_external_ptr_t external, } +static njs_int_t +njs_module_path(const njs_str_t *dir, njs_module_info_t *info) +{ + char *p; + size_t length; + njs_bool_t trail; + char src[NJS_MAX_PATH + 1]; + + trail = 0; + length = info->name.length; + + if (dir != NULL) { + length += dir->length; + + if (length == 0) { + return NJS_DECLINED; + } + + trail = (dir->start[dir->length - 1] != '/'); + + if (trail) { + length++; + } + } + + if (njs_slow_path(length > NJS_MAX_PATH)) { + return NJS_ERROR; + } + + p = &src[0]; + + if (dir != NULL) { + p = (char *) njs_cpymem(p, dir->start, dir->length); + + if (trail) { + *p++ = '/'; + } + } + + p = (char *) njs_cpymem(p, info->name.start, info->name.length); + *p = '\0'; + + p = realpath(&src[0], &info->path[0]); + if (p == NULL) { + return NJS_DECLINED; + } + + info->fd = open(&info->path[0], O_RDONLY); + if (info->fd < 0) { + return NJS_DECLINED; + } + + info->file.start = (u_char *) &info->path[0]; + info->file.length = njs_strlen(info->file.start); + + return NJS_OK; +} + + +static njs_int_t +njs_module_lookup(njs_opts_t *opts, njs_module_info_t *info) +{ + njs_int_t ret; + njs_str_t *path; + njs_uint_t i; + + if (info->name.start[0] == '/') { + return njs_module_path(NULL, info); + } + + path = opts->paths; + + for (i = 0; i < opts->n_paths; i++) { + ret = njs_module_path(&path[i], info); + + if (ret != NJS_DECLINED) { + return ret; + } + } + + return NJS_DECLINED; +} + + +static njs_int_t +njs_module_read(njs_mp_t *mp, int fd, njs_str_t *text) +{ + ssize_t n; + struct stat sb; + + text->start = NULL; + + if (fstat(fd, &sb) == -1) { + goto fail; + } + + if (!S_ISREG(sb.st_mode)) { + goto fail; + } + + text->length = sb.st_size; + + text->start = njs_mp_alloc(mp, text->length); + if (text->start == NULL) { + goto fail; + } + + n = read(fd, text->start, sb.st_size); + + if (n < 0 || n != sb.st_size) { + goto fail; + } + + return NJS_OK; + +fail: + + if (text->start != NULL) { + njs_mp_free(mp, text->start); + } + + return NJS_ERROR; +} + + +static njs_mod_t * +njs_module_loader(njs_vm_t *vm, njs_external_ptr_t external, njs_str_t *name) +{ + u_char *start; + njs_int_t ret; + njs_str_t text; + njs_mod_t *module; + njs_opts_t *opts; + njs_module_info_t info; + + opts = external; + + njs_memzero(&info, sizeof(njs_module_info_t)); + + info.name = *name; + + ret = njs_module_lookup(opts, &info); + if (njs_slow_path(ret != NJS_OK)) { + return NULL; + } + + ret = njs_module_read(njs_vm_memory_pool(vm), info.fd, &text); + + (void) close(info.fd); + + if (njs_slow_path(ret != NJS_OK)) { + njs_vm_internal_error(vm, "while reading \"%V\" module", &info.file); + return NULL; + } + + start = text.start; + + module = njs_vm_compile_module(vm, &info.file, &start, + &text.start[text.length]); + + njs_mp_free(njs_vm_memory_pool(vm), text.start); + + return module; +} + + static njs_vm_t * njs_create_vm(njs_opts_t *opts) { + size_t len; u_char *p, *start; njs_vm_t *vm; njs_int_t ret; - njs_str_t path; - njs_uint_t i; njs_vm_opt_t vm_options; njs_vm_opt_init(&vm_options); @@ -857,16 +1051,7 @@ njs_create_vm(njs_opts_t *opts) njs_vm_external_ptr(vm)); } - for (i = 0; i < opts->n_paths; i++) { - path.start = (u_char *) opts->paths[i]; - path.length = njs_strlen(opts->paths[i]); - - ret = njs_vm_add_path(vm, &path); - if (ret != NJS_OK) { - njs_stderror("failed to add path\n"); - return NULL; - } - } + njs_vm_set_module_loader(vm, njs_module_loader, opts); start = (u_char *) getenv("NJS_PATH"); if (start == NULL) { @@ -876,10 +1061,9 @@ njs_create_vm(njs_opts_t *opts) for ( ;; ) { p = njs_strchr(start, ':'); - path.start = start; - path.length = (p != NULL) ? (size_t) (p - start) : njs_strlen(start); + len = (p != NULL) ? (size_t) (p - start) : njs_strlen(start); - ret = njs_vm_add_path(vm, &path); + ret = njs_options_add_path(opts, start, len); if (ret != NJS_OK) { njs_stderror("failed to add path\n"); return NULL; diff --git a/nginx/ngx_js.c b/nginx/ngx_js.c index 27fbfd29..dd9d98b7 100644 --- a/nginx/ngx_js.c +++ b/nginx/ngx_js.c @@ -29,6 +29,20 @@ typedef struct { } ngx_js_rejected_promise_t; +#if defined(PATH_MAX) +#define NGX_MAX_PATH PATH_MAX +#else +#define NGX_MAX_PATH 4096 +#endif + +typedef struct { + int fd; + njs_str_t name; + njs_str_t file; + char path[NGX_MAX_PATH + 1]; +} njs_module_info_t; + + 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, @@ -1715,6 +1729,182 @@ ngx_js_rejection_tracker(njs_vm_t *vm, njs_external_ptr_t unused, } +static njs_int_t +ngx_js_module_path(const ngx_str_t *dir, njs_module_info_t *info) +{ + char *p; + size_t length; + njs_bool_t trail; + char src[NGX_MAX_PATH + 1]; + + trail = 0; + length = info->name.length; + + if (dir != NULL) { + length += dir->len; + + if (length == 0) { + return NJS_DECLINED; + } + + trail = (dir->data[dir->len - 1] != '/'); + + if (trail) { + length++; + } + } + + if (njs_slow_path(length > NGX_MAX_PATH)) { + return NJS_ERROR; + } + + p = &src[0]; + + if (dir != NULL) { + p = (char *) njs_cpymem(p, dir->data, dir->len); + + if (trail) { + *p++ = '/'; + } + } + + p = (char *) njs_cpymem(p, info->name.start, info->name.length); + *p = '\0'; + + p = realpath(&src[0], &info->path[0]); + if (p == NULL) { + return NJS_DECLINED; + } + + info->fd = open(&info->path[0], O_RDONLY); + if (info->fd < 0) { + return NJS_DECLINED; + } + + info->file.start = (u_char *) &info->path[0]; + info->file.length = njs_strlen(info->file.start); + + return NJS_OK; +} + + +static njs_int_t +ngx_js_module_lookup(ngx_js_loc_conf_t *conf, njs_module_info_t *info) +{ + njs_int_t ret; + ngx_str_t *path; + njs_uint_t i; + + if (info->name.start[0] == '/') { + return ngx_js_module_path(NULL, info); + } + + ret = ngx_js_module_path((const ngx_str_t *) &ngx_cycle->conf_prefix, info); + + if (ret != NJS_DECLINED) { + return ret; + } + + if (conf->paths == NGX_CONF_UNSET_PTR) { + return NJS_DECLINED; + } + + path = conf->paths->elts; + + for (i = 0; i < conf->paths->nelts; i++) { + ret = ngx_js_module_path(&path[i], info); + + if (ret != NJS_DECLINED) { + return ret; + } + } + + return NJS_DECLINED; +} + + +static njs_int_t +ngx_js_module_read(njs_mp_t *mp, int fd, njs_str_t *text) +{ + ssize_t n; + struct stat sb; + + text->start = NULL; + + if (fstat(fd, &sb) == -1) { + goto fail; + } + + if (!S_ISREG(sb.st_mode)) { + goto fail; + } + + text->length = sb.st_size; + + text->start = njs_mp_alloc(mp, text->length); + if (text->start == NULL) { + goto fail; + } + + n = read(fd, text->start, sb.st_size); + + if (n < 0 || n != sb.st_size) { + goto fail; + } + + return NJS_OK; + +fail: + + if (text->start != NULL) { + njs_mp_free(mp, text->start); + } + + return NJS_ERROR; +} + + +static njs_mod_t * +ngx_js_module_loader(njs_vm_t *vm, njs_external_ptr_t external, njs_str_t *name) +{ + u_char *start; + njs_int_t ret; + njs_str_t text; + njs_mod_t *module; + ngx_js_loc_conf_t *conf; + njs_module_info_t info; + + conf = external; + + njs_memzero(&info, sizeof(njs_module_info_t)); + + info.name = *name; + + ret = ngx_js_module_lookup(conf, &info); + if (njs_slow_path(ret != NJS_OK)) { + return NULL; + } + + ret = ngx_js_module_read(njs_vm_memory_pool(vm), info.fd, &text); + + (void) close(info.fd); + + if (ret != NJS_OK) { + njs_vm_internal_error(vm, "while reading \"%V\" module", &info.file); + return NULL; + } + + start = text.start; + + module = njs_vm_compile_module(vm, &info.file, &start, + &text.start[text.length]); + + njs_mp_free(njs_vm_memory_pool(vm), text.start); + + return module; +} + + ngx_int_t ngx_js_init_conf_vm(ngx_conf_t *cf, ngx_js_loc_conf_t *conf, njs_vm_opt_t *options) @@ -1723,7 +1913,7 @@ ngx_js_init_conf_vm(ngx_conf_t *cf, ngx_js_loc_conf_t *conf, u_char *start, *end, *p; ngx_str_t *m, file; njs_int_t rc; - njs_str_t text, path; + njs_str_t text; ngx_uint_t i; njs_value_t *value; ngx_pool_cleanup_t *cln; @@ -1795,14 +1985,7 @@ ngx_js_init_conf_vm(ngx_conf_t *cf, ngx_js_loc_conf_t *conf, njs_vm_set_rejection_tracker(conf->vm, ngx_js_rejection_tracker, NULL); - path.start = ngx_cycle->conf_prefix.data; - path.length = ngx_cycle->conf_prefix.len; - - rc = njs_vm_add_path(conf->vm, &path); - if (rc != NJS_OK) { - ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "failed to add \"js_path\""); - 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; @@ -1811,16 +1994,6 @@ ngx_js_init_conf_vm(ngx_conf_t *cf, ngx_js_loc_conf_t *conf, if (ngx_conf_full_name(cf->cycle, &m[i], 1) != NGX_OK) { return NGX_ERROR; } - - path.start = m[i].data; - path.length = m[i].len; - - rc = njs_vm_add_path(conf->vm, &path); - if (rc != NJS_OK) { - ngx_log_error(NGX_LOG_EMERG, cf->log, 0, - "failed to add \"js_path\""); - return NGX_ERROR; - } } } diff --git a/src/njs.h b/src/njs.h index 57e3610b..888f0c61 100644 --- a/src/njs.h +++ b/src/njs.h @@ -327,8 +327,6 @@ NJS_EXPORT njs_int_t njs_vm_invoke(njs_vm_t *vm, njs_function_t *function, */ NJS_EXPORT njs_int_t njs_vm_start(njs_vm_t *vm, njs_value_t *retval); -NJS_EXPORT njs_int_t njs_vm_add_path(njs_vm_t *vm, const njs_str_t *path); - #define NJS_PROTO_ID_ANY (-1) NJS_EXPORT njs_int_t njs_vm_external_prototype(njs_vm_t *vm, diff --git a/src/njs_module.c b/src/njs_module.c index 61989985..859d96a8 100644 --- a/src/njs_module.c +++ b/src/njs_module.c @@ -8,197 +8,6 @@ #include -typedef struct { - int fd; - njs_str_t name; - njs_str_t file; - char path[NJS_MAX_PATH + 1]; -} njs_module_info_t; - - -static njs_int_t njs_module_lookup(njs_vm_t *vm, njs_module_info_t *info); -static njs_int_t njs_module_path(njs_vm_t *vm, const njs_str_t *dir, - njs_module_info_t *info); -static njs_int_t njs_module_read(njs_vm_t *vm, int fd, njs_str_t *body); -static njs_mod_t *njs_default_module_loader(njs_vm_t *vm, - njs_external_ptr_t external, njs_str_t *name); - - -njs_mod_t * -njs_parser_module(njs_parser_t *parser, njs_str_t *name) -{ - njs_mod_t *module; - njs_vm_t *vm; - njs_external_ptr_t external; - njs_module_loader_t loader; - - vm = parser->vm; - - if (name->length == 0) { - njs_parser_syntax_error(parser, "Cannot find module \"%V\"", name); - return NULL; - } - - module = njs_module_find(vm, name, 1); - if (module != NULL) { - goto done; - } - - external = NULL; - loader = njs_default_module_loader; - - if (vm->module_loader != NULL) { - loader = vm->module_loader; - external = vm->module_loader_opaque; - } - - module = loader(vm, external, name); - if (module == NULL) { - njs_parser_syntax_error(parser, "Cannot find module \"%V\"", name); - return NULL; - } - -done: - - if (module->index == 0) { - module->index = vm->shared->module_items++; - } - - return module; -} - - -static njs_int_t -njs_module_lookup(njs_vm_t *vm, njs_module_info_t *info) -{ - njs_int_t ret; - njs_str_t *path; - njs_uint_t i; - - if (info->name.start[0] == '/') { - return njs_module_path(vm, NULL, info); - } - - if (vm->paths == NULL) { - return NJS_DECLINED; - } - - path = vm->paths->start; - - for (i = 0; i < vm->paths->items; i++) { - ret = njs_module_path(vm, path, info); - - if (ret != NJS_DECLINED) { - return ret; - } - - path++; - } - - return NJS_DECLINED; -} - - -static njs_int_t -njs_module_path(njs_vm_t *vm, const njs_str_t *dir, njs_module_info_t *info) -{ - char *p; - size_t length; - njs_bool_t trail; - char src[NJS_MAX_PATH + 1]; - - trail = 0; - length = info->name.length; - - if (dir != NULL) { - length += dir->length; - - if (length == 0) { - return NJS_DECLINED; - } - - trail = (dir->start[dir->length - 1] != '/'); - - if (trail) { - length++; - } - } - - if (njs_slow_path(length > NJS_MAX_PATH)) { - return NJS_ERROR; - } - - p = &src[0]; - - if (dir != NULL) { - p = (char *) njs_cpymem(p, dir->start, dir->length); - - if (trail) { - *p++ = '/'; - } - } - - p = (char *) njs_cpymem(p, info->name.start, info->name.length); - *p = '\0'; - - p = realpath(&src[0], &info->path[0]); - if (p == NULL) { - return NJS_DECLINED; - } - - info->fd = open(&info->path[0], O_RDONLY); - if (info->fd < 0) { - return NJS_DECLINED; - } - - info->file.start = (u_char *) &info->path[0]; - info->file.length = njs_strlen(info->file.start); - - return NJS_OK; -} - - -static njs_int_t -njs_module_read(njs_vm_t *vm, int fd, njs_str_t *text) -{ - ssize_t n; - struct stat sb; - - text->start = NULL; - - if (fstat(fd, &sb) == -1) { - goto fail; - } - - if (!S_ISREG(sb.st_mode)) { - goto fail; - } - - text->length = sb.st_size; - - text->start = njs_mp_alloc(vm->mem_pool, text->length); - if (text->start == NULL) { - goto fail; - } - - n = read(fd, text->start, sb.st_size); - - if (n < 0 || n != sb.st_size) { - goto fail; - } - - return NJS_OK; - -fail: - - if (text->start != NULL) { - njs_mp_free(vm->mem_pool, text->start); - } - - return NJS_ERROR; -} - - static njs_int_t njs_module_hash_test(njs_lvlhsh_query_t *lhq, void *data) { @@ -348,42 +157,3 @@ njs_module_require(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, return NJS_OK; } - - -static njs_mod_t * -njs_default_module_loader(njs_vm_t *vm, njs_external_ptr_t unused, - njs_str_t *name) -{ - u_char *start; - njs_int_t ret; - njs_str_t text; - njs_mod_t *module; - njs_module_info_t info; - - njs_memzero(&info, sizeof(njs_module_info_t)); - - info.name = *name; - - ret = njs_module_lookup(vm, &info); - if (njs_slow_path(ret != NJS_OK)) { - return NULL; - } - - ret = njs_module_read(vm, info.fd, &text); - - (void) close(info.fd); - - if (njs_slow_path(ret != NJS_OK)) { - njs_internal_error(vm, "while reading \"%V\" module", &info.file); - return NULL; - } - - start = text.start; - - module = njs_vm_compile_module(vm, &info.file, &start, - &text.start[text.length]); - - njs_mp_free(vm->mem_pool, text.start); - - return module; -} diff --git a/src/njs_module.h b/src/njs_module.h index 5502d0d1..23853ad0 100644 --- a/src/njs_module.h +++ b/src/njs_module.h @@ -19,7 +19,6 @@ struct njs_mod_s { njs_mod_t *njs_module_add(njs_vm_t *vm, njs_str_t *name, njs_value_t *value); njs_mod_t *njs_module_find(njs_vm_t *vm, njs_str_t *name, njs_bool_t shared); -njs_mod_t *njs_parser_module(njs_parser_t *parser, njs_str_t *name); njs_int_t njs_module_require(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused, njs_value_t *retval); diff --git a/src/njs_parser.c b/src/njs_parser.c index 6b729193..6a7696b2 100644 --- a/src/njs_parser.c +++ b/src/njs_parser.c @@ -8123,6 +8123,45 @@ njs_parser_export_after(njs_parser_t *parser, njs_lexer_token_t *token, } +static njs_mod_t * +njs_parser_module(njs_parser_t *parser, njs_str_t *name) +{ + njs_vm_t *vm; + njs_mod_t *module; + + vm = parser->vm; + + if (name->length == 0) { + njs_parser_syntax_error(parser, "Cannot find module \"%V\"", name); + return NULL; + } + + module = njs_module_find(vm, name, 1); + if (module != NULL) { + goto done; + } + + if (vm->module_loader == NULL) { + njs_parser_syntax_error(parser, "Cannot load module \"%V\"", name); + return NULL; + } + + module = vm->module_loader(vm, vm->module_loader_opaque, name); + if (module == NULL) { + njs_parser_syntax_error(parser, "Cannot find module \"%V\"", name); + return NULL; + } + +done: + + if (module->index == 0) { + module->index = vm->shared->module_items++; + } + + return module; +} + + static njs_int_t njs_parser_import(njs_parser_t *parser, njs_lexer_token_t *token, njs_queue_link_t *current) diff --git a/src/njs_vm.c b/src/njs_vm.c index 656839da..fa8a19ba 100644 --- a/src/njs_vm.c +++ b/src/njs_vm.c @@ -716,29 +716,6 @@ njs_vm_set_rejection_tracker(njs_vm_t *vm, } -njs_int_t -njs_vm_add_path(njs_vm_t *vm, const njs_str_t *path) -{ - njs_str_t *item; - - if (vm->paths == NULL) { - vm->paths = njs_arr_create(vm->mem_pool, 4, sizeof(njs_str_t)); - if (njs_slow_path(vm->paths == NULL)) { - return NJS_ERROR; - } - } - - item = njs_arr_add(vm->paths); - if (njs_slow_path(item == NULL)) { - return NJS_ERROR; - } - - *item = *path; - - return NJS_OK; -} - - njs_value_t njs_vm_exception(njs_vm_t *vm) { diff --git a/src/njs_vm.h b/src/njs_vm.h index 2d72f939..6d09caf8 100644 --- a/src/njs_vm.h +++ b/src/njs_vm.h @@ -118,7 +118,6 @@ typedef enum { struct njs_vm_s { njs_value_t exception; - njs_arr_t *paths; njs_arr_t *protos; njs_arr_t *scope_absolute; -- 2.47.3