]> git.kaiwu.me - njs.git/commitdiff
Reverted changes introduced in 7eaaa7d57636 (not released) back.
authorDmitry Volyntsev <xeioex@nginx.com>
Wed, 7 Feb 2024 03:32:08 +0000 (19:32 -0800)
committerDmitry Volyntsev <xeioex@nginx.com>
Wed, 7 Feb 2024 03:32:08 +0000 (19:32 -0800)
Relative importing is again supported.

external/njs_shell.c
nginx/ngx_js.c
nginx/ngx_js.h
nginx/t/js_import_relative.t [new file with mode: 0644]
test/js/import_relative_path.t.js [new file with mode: 0644]
test/js/module/libs/hash.js
test/js/module/sub/sub3.js [new file with mode: 0644]

index 2a22223897e2ba1bfeb9e5bcd12042ae9dccb6b3..9af73b7384453df769515dd35748302ffde1e545 100644 (file)
@@ -115,6 +115,8 @@ typedef struct {
 
     njs_queue_t             labels;
 
+    njs_str_t               cwd;
+
     njs_arr_t               *rejected_promises;
 
     njs_bool_t              suppress_stdout;
@@ -693,6 +695,8 @@ njs_console_init(njs_vm_t *vm, njs_console_t *console)
     njs_queue_init(&console->posted_events);
     njs_queue_init(&console->labels);
 
+    njs_memzero(&console->cwd, sizeof(njs_str_t));
+
     console->rejected_promises = NULL;
 
     console->completion.completions = njs_vm_completions(vm, NULL);
@@ -869,7 +873,7 @@ njs_module_path(const njs_str_t *dir, njs_module_info_t *info)
     if (dir != NULL) {
         length += dir->length;
 
-        if (length == 0) {
+        if (length == 0 || dir->length == 0) {
             return NJS_DECLINED;
         }
 
@@ -915,7 +919,8 @@ njs_module_path(const njs_str_t *dir, njs_module_info_t *info)
 
 
 static njs_int_t
-njs_module_lookup(njs_opts_t *opts, njs_module_info_t *info)
+njs_module_lookup(njs_opts_t *opts, const njs_str_t *cwd,
+    njs_module_info_t *info)
 {
     njs_int_t   ret;
     njs_str_t   *path;
@@ -925,6 +930,12 @@ njs_module_lookup(njs_opts_t *opts, njs_module_info_t *info)
         return njs_module_path(NULL, info);
     }
 
+    ret = njs_module_path(cwd, info);
+
+    if (ret != NJS_DECLINED) {
+        return ret;
+    }
+
     path = opts->paths;
 
     for (i = 0; i < opts->n_paths; i++) {
@@ -980,23 +991,86 @@ fail:
 }
 
 
+static void
+njs_file_dirname(const njs_str_t *path, njs_str_t *name)
+{
+    const u_char  *p, *end;
+
+    if (path->length == 0) {
+        goto current_dir;
+    }
+
+    p = path->start + path->length - 1;
+
+    /* Stripping basename. */
+
+    while (p >= path->start && *p != '/') { p--; }
+
+    end = p + 1;
+
+    if (end == path->start) {
+        goto current_dir;
+    }
+
+    /* Stripping trailing slashes. */
+
+    while (p >= path->start && *p == '/') { p--; }
+
+    p++;
+
+    if (p == path->start) {
+        p = end;
+    }
+
+    name->start = path->start;
+    name->length = p - path->start;
+
+    return;
+
+current_dir:
+
+    *name = njs_str_value(".");
+}
+
+
+static njs_int_t
+njs_console_set_cwd(njs_vm_t *vm, njs_console_t *console, njs_str_t *file)
+{
+    njs_str_t  cwd;
+
+    njs_file_dirname(file, &cwd);
+
+    console->cwd.start = njs_mp_alloc(njs_vm_memory_pool(vm), cwd.length);
+    if (njs_slow_path(console->cwd.start == NULL)) {
+        return NJS_ERROR;
+    }
+
+    memcpy(console->cwd.start, cwd.start, cwd.length);
+    console->cwd.length = cwd.length;
+
+    return NJS_OK;
+}
+
+
 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_str_t          text, prev_cwd;
     njs_mod_t          *module;
     njs_opts_t         *opts;
+    njs_console_t      *console;
     njs_module_info_t  info;
 
     opts = external;
+    console = njs_vm_external_ptr(vm);
 
     njs_memzero(&info, sizeof(njs_module_info_t));
 
     info.name = *name;
 
-    ret = njs_module_lookup(opts, &info);
+    ret = njs_module_lookup(opts, &console->cwd, &info);
     if (njs_slow_path(ret != NJS_OK)) {
         return NULL;
     }
@@ -1010,11 +1084,23 @@ njs_module_loader(njs_vm_t *vm, njs_external_ptr_t external, njs_str_t *name)
         return NULL;
     }
 
+    prev_cwd = console->cwd;
+
+    ret = njs_console_set_cwd(vm, console, &info.file);
+    if (njs_slow_path(ret != NJS_OK)) {
+        njs_vm_internal_error(vm, "while setting cwd for \"%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), console->cwd.start);
+    console->cwd = prev_cwd;
+
     njs_mp_free(njs_vm_memory_pool(vm), text.start);
 
     return module;
@@ -1025,6 +1111,7 @@ static njs_vm_t *
 njs_create_vm(njs_opts_t *opts)
 {
     njs_vm_t      *vm;
+    njs_int_t     ret;
     njs_vm_opt_t  vm_options;
 
     njs_vm_opt_init(&vm_options);
@@ -1068,6 +1155,12 @@ njs_create_vm(njs_opts_t *opts)
                                      njs_vm_external_ptr(vm));
     }
 
+    ret = njs_console_set_cwd(vm, njs_vm_external_ptr(vm), &vm_options.file);
+    if (njs_slow_path(ret != NJS_OK)) {
+        njs_stderror("failed to set cwd\n");
+        return NULL;
+    }
+
     njs_vm_set_module_loader(vm, njs_module_loader, opts);
 
     return vm;
index dd9d98b762935df0b4c9639b07442c643bc77ace..d171995129ea6ce05db50ca0bd36650aa5620d15 100644 (file)
@@ -1743,7 +1743,7 @@ ngx_js_module_path(const ngx_str_t *dir, njs_module_info_t *info)
     if (dir != NULL) {
         length += dir->len;
 
-        if (length == 0) {
+        if (length == 0 || dir->len == 0) {
             return NJS_DECLINED;
         }
 
@@ -1799,6 +1799,12 @@ ngx_js_module_lookup(ngx_js_loc_conf_t *conf, njs_module_info_t *info)
         return ngx_js_module_path(NULL, info);
     }
 
+    ret = ngx_js_module_path(&conf->cwd, info);
+
+    if (ret != NJS_DECLINED) {
+        return ret;
+    }
+
     ret = ngx_js_module_path((const ngx_str_t *) &ngx_cycle->conf_prefix, info);
 
     if (ret != NJS_DECLINED) {
@@ -1864,12 +1870,74 @@ fail:
 }
 
 
+static void
+ngx_js_file_dirname(const njs_str_t *path, ngx_str_t *name)
+{
+    const u_char  *p, *end;
+
+    if (path->length == 0) {
+        goto current_dir;
+    }
+
+    p = path->start + path->length - 1;
+
+    /* Stripping basename. */
+
+    while (p >= path->start && *p != '/') { p--; }
+
+    end = p + 1;
+
+    if (end == path->start) {
+        goto current_dir;
+    }
+
+    /* Stripping trailing slashes. */
+
+    while (p >= path->start && *p == '/') { p--; }
+
+    p++;
+
+    if (p == path->start) {
+        p = end;
+    }
+
+    name->data = path->start;
+    name->len = p - path->start;
+
+    return;
+
+current_dir:
+
+    ngx_str_set(name, ".");
+}
+
+
+static njs_int_t
+ngx_js_set_cwd(njs_vm_t *vm, 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);
+    if (conf->cwd.data == NULL) {
+        return NJS_ERROR;
+    }
+
+    memcpy(conf->cwd.data, cwd.data, cwd.len);
+    conf->cwd.len = cwd.len;
+
+    return NJS_OK;
+}
+
+
 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;
+    ngx_str_t           prev_cwd;
     njs_mod_t          *module;
     ngx_js_loc_conf_t  *conf;
     njs_module_info_t   info;
@@ -1894,11 +1962,23 @@ ngx_js_module_loader(njs_vm_t *vm, njs_external_ptr_t external, njs_str_t *name)
         return NULL;
     }
 
+    prev_cwd = conf->cwd;
+
+    ret = ngx_js_set_cwd(vm, conf, &info.file);
+    if (ret != NJS_OK) {
+        njs_vm_internal_error(vm, "while setting cwd for \"%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), conf->cwd.data);
+    conf->cwd = prev_cwd;
+
     njs_mp_free(njs_vm_memory_pool(vm), text.start);
 
     return module;
@@ -1985,6 +2065,12 @@ 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);
 
+    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) {
index 1f95c7c3a8dc9a03a811ae78b91a6e015f825100..a84058f360f3fc6746c32784624ca07fbb2b8dda 100644 (file)
@@ -83,6 +83,7 @@ struct ngx_js_event_s {
 
 #define _NGX_JS_COMMON_LOC_CONF                                               \
     njs_vm_t              *vm;                                                \
+    ngx_str_t              cwd;                                               \
     ngx_array_t           *imports;                                           \
     ngx_array_t           *paths;                                             \
                                                                               \
diff --git a/nginx/t/js_import_relative.t b/nginx/t/js_import_relative.t
new file mode 100644 (file)
index 0000000..9f5f2fe
--- /dev/null
@@ -0,0 +1,100 @@
+#!/usr/bin/perl
+
+# (C) Dmitry Volyntsev
+# (c) Nginx, Inc.
+
+# Tests for http njs module, js_import directive, importing relative paths.
+
+###############################################################################
+
+use warnings;
+use strict;
+
+use Test::More;
+
+BEGIN { use FindBin; chdir($FindBin::Bin); }
+
+use lib 'lib';
+use Test::Nginx;
+
+###############################################################################
+
+select STDERR; $| = 1;
+select STDOUT; $| = 1;
+
+my $t = Test::Nginx->new()->has(qw/http/)
+       ->write_file_expand('nginx.conf', <<'EOF');
+
+%%TEST_GLOBALS%%
+
+daemon off;
+
+events {
+}
+
+http {
+    %%TEST_GLOBALS_HTTP%%
+
+    js_import main from lib/main.js;
+
+    server {
+        listen       127.0.0.1:8080;
+        server_name  localhost;
+
+        location /local {
+            js_content main.test_local;
+        }
+
+        location /top {
+            js_content main.test_top;
+        }
+    }
+}
+
+EOF
+
+my $d = $t->testdir();
+
+mkdir("$d/lib");
+mkdir("$d/lib/sub");
+
+$t->write_file('lib/main.js', <<EOF);
+    import sub from './sub/foo.js';
+    import local from './foo.js';
+    import top from '../foo.js';
+
+    function test_local(r) {
+        r.return(200, local.test);
+    }
+
+    function test_top(r) {
+        r.return(200, top.test);
+    }
+
+    export default {test_local, test_top};
+
+EOF
+
+$t->write_file('lib/sub/foo.js', <<EOF);
+    export default {test: "SUB"};
+
+EOF
+
+$t->write_file('lib/foo.js', <<EOF);
+    export default {test: "LOCAL"};
+
+EOF
+
+$t->write_file('foo.js', <<EOF);
+    export default {test: "TOP"};
+
+EOF
+
+$t->try_run('no njs available')->plan(2);
+
+###############################################################################
+
+like(http_get('/local'), qr/LOCAL/s, 'local relative import');
+like(http_get('/top'), qr/TOP/s, 'local relative import 2');
+
+###############################################################################
diff --git a/test/js/import_relative_path.t.js b/test/js/import_relative_path.t.js
new file mode 100644 (file)
index 0000000..2a297f2
--- /dev/null
@@ -0,0 +1,9 @@
+/*---
+includes: []
+flags: []
+paths: [test/js/module/]
+---*/
+
+import hash from 'libs/hash.js';
+
+assert.sameValue(hash.name, "libs.name");
index 85f91ef87f382f673c3b8849e71f7f1c0237ea2a..2eb3728cfaaab138e947c369835e16e6ebee31dc 100644 (file)
@@ -4,6 +4,7 @@ function hash() {
     return v;
 }
 
+import sub from 'sub/sub3.js';
 import name from 'name.js';
 import crypto from 'crypto';
 
diff --git a/test/js/module/sub/sub3.js b/test/js/module/sub/sub3.js
new file mode 100644 (file)
index 0000000..54ff718
--- /dev/null
@@ -0,0 +1 @@
+export default { name: "SUB3" };