[njs] Added process global object.

Dmitry Volyntsev xeioex at nginx.com
Tue Jun 18 14:57:57 UTC 2019


details:   https://hg.nginx.org/njs/rev/e18ee27ce760
branches:  
changeset: 1008:e18ee27ce760
user:      Dmitry Volyntsev <xeioex at nginx.com>
date:      Tue Jun 18 17:57:38 2019 +0300
description:
Added process global object.

process object properties:
    argv - an array containing the command line arguments
    env - an object containing the user environment
    pid - process PID
    ppid - process parent PID

This closes #84 issue on Github.

diffstat:

 nginx/ngx_http_js_module.c   |    2 +
 nginx/ngx_stream_js_module.c |    2 +
 njs/njs.h                    |    3 +
 njs/njs_builtin.c            |  274 +++++++++++++++++++++++++++++++++++++++---
 njs/njs_generator.c          |    1 +
 njs/njs_lexer.h              |    1 +
 njs/njs_lexer_keyword.c      |    1 +
 njs/njs_object_hash.h        |   15 ++
 njs/njs_parser_terminal.c    |    1 +
 njs/njs_shell.c              |    2 +
 njs/njs_vm.h                 |    2 +
 njs/test/njs_expect_test.exp |   14 ++
 12 files changed, 298 insertions(+), 20 deletions(-)

diffs (497 lines):

diff -r 2cb51aab7e78 -r e18ee27ce760 nginx/ngx_http_js_module.c
--- a/nginx/ngx_http_js_module.c	Tue Jun 18 17:57:22 2019 +0300
+++ b/nginx/ngx_http_js_module.c	Tue Jun 18 17:57:38 2019 +0300
@@ -2283,6 +2283,8 @@ ngx_http_js_include(ngx_conf_t *cf, ngx_
 
     options.backtrace = 1;
     options.ops = &ngx_http_js_ops;
+    options.argv = ngx_argv;
+    options.argc = ngx_argc;
 
     file = value[1];
     options.file.start = file.data;
diff -r 2cb51aab7e78 -r e18ee27ce760 nginx/ngx_stream_js_module.c
--- a/nginx/ngx_stream_js_module.c	Tue Jun 18 17:57:22 2019 +0300
+++ b/nginx/ngx_stream_js_module.c	Tue Jun 18 17:57:38 2019 +0300
@@ -1473,6 +1473,8 @@ ngx_stream_js_include(ngx_conf_t *cf, ng
 
     options.backtrace = 1;
     options.ops = &ngx_stream_js_ops;
+    options.argv = ngx_argv;
+    options.argc = ngx_argc;
 
     file = value[1];
     options.file.start = file.data;
diff -r 2cb51aab7e78 -r e18ee27ce760 njs/njs.h
--- a/njs/njs.h	Tue Jun 18 17:57:22 2019 +0300
+++ b/njs/njs.h	Tue Jun 18 17:57:38 2019 +0300
@@ -143,6 +143,9 @@ typedef struct {
     njs_vm_ops_t                    *ops;
     nxt_str_t                       file;
 
+    char                            **argv;
+    nxt_uint_t                      argc;
+
     uint8_t                         trailer;         /* 1 bit */
     uint8_t                         init;            /* 1 bit */
     uint8_t                         accumulative;    /* 1 bit */
diff -r 2cb51aab7e78 -r e18ee27ce760 njs/njs_builtin.c
--- a/njs/njs_builtin.c	Tue Jun 18 17:57:22 2019 +0300
+++ b/njs/njs_builtin.c	Tue Jun 18 17:57:38 2019 +0300
@@ -28,17 +28,21 @@ static njs_ret_t njs_prototype_function(
 static nxt_array_t *njs_vm_expression_completions(njs_vm_t *vm,
     nxt_str_t *expression);
 static nxt_array_t *njs_object_completions(njs_vm_t *vm, njs_object_t *object);
+static nxt_int_t njs_env_hash_init(njs_vm_t *vm, nxt_lvlhsh_t *hash,
+    char **environment);
 
 
+const njs_object_init_t  njs_global_this_init;
 const njs_object_init_t  njs_njs_object_init;
-const njs_object_init_t  njs_global_this_init;
+const njs_object_init_t  njs_process_object_init;
 
 
 const njs_object_init_t  *njs_object_init[] = {
-    &njs_global_this_init,        /* global this        */
-    &njs_njs_object_init,         /* global njs object  */
-    &njs_math_object_init,        /* Math               */
-    &njs_json_object_init,        /* JSON               */
+    &njs_global_this_init,
+    &njs_njs_object_init,
+    &njs_process_object_init,
+    &njs_math_object_init,
+    &njs_json_object_init,
     NULL
 };
 
@@ -214,6 +218,9 @@ const njs_object_prototype_t  njs_protot
 };
 
 
+extern char  **environ;
+
+
 nxt_inline nxt_int_t
 njs_object_hash_init(njs_vm_t *vm, nxt_lvlhsh_t *hash,
     const njs_object_init_t *init)
@@ -229,8 +236,8 @@ njs_builtin_objects_create(njs_vm_t *vm)
     njs_module_t               *module;
     njs_object_t               *object, *string_object;
     njs_function_t             *func;
+    njs_vm_shared_t            *shared;
     nxt_lvlhsh_query_t         lhq;
-    njs_vm_shared_t            *shared;
     njs_object_prototype_t     *prototype;
     const njs_object_init_t    *obj, **p;
     const njs_function_init_t  *f;
@@ -285,6 +292,11 @@ njs_builtin_objects_create(njs_vm_t *vm)
         object++;
     }
 
+    ret = njs_env_hash_init(vm, &shared->env_hash, environ);
+    if (nxt_slow_path(ret != NXT_OK)) {
+        return NXT_ERROR;
+    }
+
     lhq.replace = 0;
     lhq.pool = vm->mem_pool;
 
@@ -1075,6 +1087,35 @@ njs_dump_value(njs_vm_t *vm, njs_value_t
 }
 
 
+static const njs_object_prop_t  njs_global_this_object_properties[] =
+{
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("NaN"),
+        .value = njs_value(NJS_NUMBER, 0, NAN),
+    },
+
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("Infinity"),
+        .value = njs_value(NJS_NUMBER, 0, INFINITY),
+    },
+
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("undefined"),
+        .value = njs_value(NJS_UNDEFINED, 0, NAN),
+    },
+};
+
+
+const njs_object_init_t  njs_global_this_init = {
+    nxt_string("this"),
+    njs_global_this_object_properties,
+    nxt_nitems(njs_global_this_object_properties)
+};
+
+
 static const njs_object_prop_t  njs_njs_object_properties[] =
 {
     {
@@ -1102,30 +1143,223 @@ const njs_object_init_t  njs_njs_object_
 };
 
 
-static const njs_object_prop_t  njs_global_this_object_properties[] =
+static njs_ret_t
+njs_process_object_argv(njs_vm_t *vm, njs_value_t *process,
+    njs_value_t *unused, njs_value_t *retval)
+{
+    char                **arg;
+    nxt_int_t           ret;
+    nxt_uint_t          i;
+    njs_array_t         *argv;
+    njs_object_prop_t   *prop;
+    nxt_lvlhsh_query_t  lhq;
+
+    static const njs_value_t  argv_string = njs_string("argv");
+
+    if (nxt_slow_path(vm->options.argv == NULL)) {
+        njs_internal_error(vm, "argv was not provided by host environment");
+        return NXT_ERROR;
+    }
+
+    argv = njs_array_alloc(vm, vm->options.argc, 0);
+    if (nxt_slow_path(argv == NULL)) {
+        return NXT_ERROR;
+    }
+
+    i = 0;
+
+    for (arg = vm->options.argv; i < vm->options.argc; arg++) {
+        njs_string_set(vm, &argv->start[i++], (u_char *) *arg,
+                       nxt_strlen(*arg));
+    }
+
+    prop = njs_object_prop_alloc(vm, &argv_string, &njs_value_undefined, 1);
+    if (nxt_slow_path(prop == NULL)) {
+        return NJS_ERROR;
+    }
+
+    prop->value.data.u.array = argv;
+    prop->value.type = NJS_ARRAY;
+    prop->value.data.truth = 1;
+
+    lhq.value = prop;
+    lhq.key_hash = NJS_ARGV_HASH;
+    lhq.key = nxt_string_value("argv");
+    lhq.replace = 0;
+    lhq.pool = vm->mem_pool;
+    lhq.proto = &njs_object_hash_proto;
+
+    ret = nxt_lvlhsh_insert(&process->data.u.object->hash, &lhq);
+
+    if (nxt_fast_path(ret == NXT_OK)) {
+        *retval = prop->value;
+        return NXT_OK;
+    }
+
+    njs_internal_error(vm, "lvlhsh insert failed");
+
+    return NXT_ERROR;
+}
+
+
+static nxt_int_t
+njs_env_hash_init(njs_vm_t *vm, nxt_lvlhsh_t *hash, char **environment)
+{
+    char                **ep;
+    u_char              *val, *entry;
+    nxt_int_t           ret;
+    njs_object_prop_t   *prop;
+    nxt_lvlhsh_query_t  lhq;
+
+    lhq.replace = 0;
+    lhq.pool = vm->mem_pool;
+    lhq.proto = &njs_object_hash_proto;
+
+    ep = environment;
+
+    while (*ep != NULL) {
+        prop = njs_object_prop_alloc(vm, &njs_value_undefined,
+                                     &njs_value_undefined, 1);
+        if (nxt_slow_path(prop == NULL)) {
+            return NXT_ERROR;
+        }
+
+        entry = (u_char *) *ep++;
+
+        val = nxt_strchr(entry, '=');
+        if (nxt_slow_path(val == NULL)) {
+            continue;
+        }
+
+        ret = njs_string_set(vm, &prop->name, entry, val - entry);
+        if (nxt_slow_path(ret != NXT_OK)) {
+            return NXT_ERROR;
+        }
+
+        val++;
+
+        ret = njs_string_set(vm, &prop->value, val, nxt_strlen(val));
+        if (nxt_slow_path(ret != NXT_OK)) {
+            return NXT_ERROR;
+        }
+
+        lhq.value = prop;
+        njs_string_get(&prop->name, &lhq.key);
+        lhq.key_hash = nxt_djb_hash(lhq.key.start, lhq.key.length);
+
+        ret = nxt_lvlhsh_insert(hash, &lhq);
+        if (nxt_slow_path(ret != NXT_OK)) {
+            njs_internal_error(vm, "lvlhsh insert failed");
+            return NXT_ERROR;
+        }
+    }
+
+    return NXT_OK;
+}
+
+
+static njs_ret_t
+njs_process_object_env(njs_vm_t *vm, njs_value_t *process,
+    njs_value_t *unused, njs_value_t *retval)
+{
+    nxt_int_t           ret;
+    njs_object_t        *env;
+    njs_object_prop_t   *prop;
+    nxt_lvlhsh_query_t  lhq;
+
+    static const njs_value_t  env_string = njs_string("env");
+
+    env = njs_object_alloc(vm);
+    if (nxt_slow_path(env == NULL)) {
+        return NXT_ERROR;
+    }
+
+    env->shared_hash = vm->shared->env_hash;
+
+    prop = njs_object_prop_alloc(vm, &env_string, &njs_value_undefined, 1);
+    if (nxt_slow_path(prop == NULL)) {
+        return NXT_ERROR;
+    }
+
+    prop->value.data.u.object = env;
+    prop->value.type = NJS_OBJECT;
+    prop->value.data.truth = 1;
+
+    lhq.replace = 0;
+    lhq.pool = vm->mem_pool;
+    lhq.proto = &njs_object_hash_proto;
+    lhq.value = prop;
+    lhq.key = nxt_string_value("env");
+    lhq.key_hash = NJS_ENV_HASH;
+
+    ret = nxt_lvlhsh_insert(&process->data.u.object->hash, &lhq);
+
+    if (nxt_fast_path(ret == NXT_OK)) {
+        *retval = prop->value;
+        return NXT_OK;
+    }
+
+    njs_internal_error(vm, "lvlhsh insert failed");
+
+    return NXT_ERROR;
+}
+
+
+static njs_ret_t
+njs_process_object_pid(njs_vm_t *vm, njs_value_t *unused,
+    njs_value_t *unused2, njs_value_t *retval)
+{
+    retval->data.u.number = getpid();
+    retval->type = NJS_NUMBER;
+    retval->data.truth = njs_is_number_true(retval->data.u.number);
+
+    return NJS_OK;
+}
+
+
+static njs_ret_t
+njs_process_object_ppid(njs_vm_t *vm, njs_value_t *unused,
+    njs_value_t *unused2, njs_value_t *retval)
+{
+    retval->data.u.number = getppid();
+    retval->type = NJS_NUMBER;
+    retval->data.truth = njs_is_number_true(retval->data.u.number);
+
+    return NJS_OK;
+}
+
+
+static const njs_object_prop_t  njs_process_object_properties[] =
 {
     {
-        .type = NJS_PROPERTY,
-        .name = njs_string("NaN"),
-        .value = njs_value(NJS_NUMBER, 0, NAN),
+        .type = NJS_PROPERTY_HANDLER,
+        .name = njs_string("argv"),
+        .value = njs_prop_handler(njs_process_object_argv),
     },
 
     {
-        .type = NJS_PROPERTY,
-        .name = njs_string("Infinity"),
-        .value = njs_value(NJS_NUMBER, 0, INFINITY),
+        .type = NJS_PROPERTY_HANDLER,
+        .name = njs_string("env"),
+        .value = njs_prop_handler(njs_process_object_env),
+    },
+
+    {
+        .type = NJS_PROPERTY_HANDLER,
+        .name = njs_string("pid"),
+        .value = njs_prop_handler(njs_process_object_pid),
     },
 
     {
-        .type = NJS_PROPERTY,
-        .name = njs_string("undefined"),
-        .value = njs_value(NJS_UNDEFINED, 0, NAN),
+        .type = NJS_PROPERTY_HANDLER,
+        .name = njs_string("ppid"),
+        .value = njs_prop_handler(njs_process_object_ppid),
     },
+
 };
 
 
-const njs_object_init_t  njs_global_this_init = {
-    nxt_string("this"),
-    njs_global_this_object_properties,
-    nxt_nitems(njs_global_this_object_properties)
+const njs_object_init_t  njs_process_object_init = {
+    nxt_string("process"),
+    njs_process_object_properties,
+    nxt_nitems(njs_process_object_properties),
 };
diff -r 2cb51aab7e78 -r e18ee27ce760 njs/njs_generator.c
--- a/njs/njs_generator.c	Tue Jun 18 17:57:22 2019 +0300
+++ b/njs/njs_generator.c	Tue Jun 18 17:57:38 2019 +0300
@@ -451,6 +451,7 @@ njs_generator(njs_vm_t *vm, njs_generato
         /* Fall through. */
 
     case NJS_TOKEN_NJS:
+    case NJS_TOKEN_PROCESS:
     case NJS_TOKEN_MATH:
     case NJS_TOKEN_JSON:
     case NJS_TOKEN_EVAL:
diff -r 2cb51aab7e78 -r e18ee27ce760 njs/njs_lexer.h
--- a/njs/njs_lexer.h	Tue Jun 18 17:57:22 2019 +0300
+++ b/njs/njs_lexer.h	Tue Jun 18 17:57:38 2019 +0300
@@ -171,6 +171,7 @@ typedef enum {
 
     NJS_TOKEN_GLOBAL_THIS,
     NJS_TOKEN_NJS,
+    NJS_TOKEN_PROCESS,
     NJS_TOKEN_MATH,
     NJS_TOKEN_JSON,
 
diff -r 2cb51aab7e78 -r e18ee27ce760 njs/njs_lexer_keyword.c
--- a/njs/njs_lexer_keyword.c	Tue Jun 18 17:57:22 2019 +0300
+++ b/njs/njs_lexer_keyword.c	Tue Jun 18 17:57:38 2019 +0300
@@ -55,6 +55,7 @@ static const njs_keyword_t  njs_keywords
     { nxt_string("this"),          NJS_TOKEN_THIS, 0 },
     { nxt_string("arguments"),     NJS_TOKEN_ARGUMENTS, 0 },
     { nxt_string("njs"),           NJS_TOKEN_NJS, 0 },
+    { nxt_string("process"),       NJS_TOKEN_PROCESS, 0 },
     { nxt_string("Math"),          NJS_TOKEN_MATH, 0 },
     { nxt_string("JSON"),          NJS_TOKEN_JSON, 0 },
 
diff -r 2cb51aab7e78 -r e18ee27ce760 njs/njs_object_hash.h
--- a/njs/njs_object_hash.h	Tue Jun 18 17:57:22 2019 +0300
+++ b/njs/njs_object_hash.h	Tue Jun 18 17:57:38 2019 +0300
@@ -8,6 +8,14 @@
 #define _NJS_OBJECT_HASH_H_INCLUDED_
 
 
+#define NJS_ARGV_HASH                                                         \
+    nxt_djb_hash_add(                                                         \
+    nxt_djb_hash_add(                                                         \
+    nxt_djb_hash_add(                                                         \
+    nxt_djb_hash_add(NXT_DJB_HASH_INIT,                                       \
+        'a'), 'r'), 'g'), 'v')
+
+
 #define NJS_CONFIGURABLE_HASH                                                 \
     nxt_djb_hash_add(                                                         \
     nxt_djb_hash_add(                                                         \
@@ -74,6 +82,13 @@
         'e'), 'n'), 'c'), 'o'), 'd'), 'i'), 'n'), 'g')
 
 
+#define NJS_ENV_HASH                                                          \
+    nxt_djb_hash_add(                                                         \
+    nxt_djb_hash_add(                                                         \
+    nxt_djb_hash_add(NXT_DJB_HASH_INIT,                                       \
+        'e'), 'n'), 'v')
+
+
 #define NJS_FLAG_HASH                                                         \
     nxt_djb_hash_add(                                                         \
     nxt_djb_hash_add(                                                         \
diff -r 2cb51aab7e78 -r e18ee27ce760 njs/njs_parser_terminal.c
--- a/njs/njs_parser_terminal.c	Tue Jun 18 17:57:22 2019 +0300
+++ b/njs/njs_parser_terminal.c	Tue Jun 18 17:57:38 2019 +0300
@@ -270,6 +270,7 @@ njs_parser_reference(njs_vm_t *vm, njs_p
         /* Fall through. */
 
     case NJS_TOKEN_NJS:
+    case NJS_TOKEN_PROCESS:
     case NJS_TOKEN_MATH:
     case NJS_TOKEN_JSON:
         ret = njs_parser_builtin(vm, parser, node, NJS_OBJECT, name, hash);
diff -r 2cb51aab7e78 -r e18ee27ce760 njs/njs_shell.c
--- a/njs/njs_shell.c	Tue Jun 18 17:57:22 2019 +0300
+++ b/njs/njs_shell.c	Tue Jun 18 17:57:38 2019 +0300
@@ -265,6 +265,8 @@ main(int argc, char **argv)
 
     vm_options.ops = &njs_console_ops;
     vm_options.external = &njs_console;
+    vm_options.argv = argv;
+    vm_options.argc = argc;
 
     if (opts.interactive) {
         ret = njs_interactive_shell(&opts, &vm_options);
diff -r 2cb51aab7e78 -r e18ee27ce760 njs/njs_vm.h
--- a/njs/njs_vm.h	Tue Jun 18 17:57:22 2019 +0300
+++ b/njs/njs_vm.h	Tue Jun 18 17:57:38 2019 +0300
@@ -1154,6 +1154,8 @@ struct njs_vm_shared_s {
     nxt_lvlhsh_t             arrow_instance_hash;
     nxt_lvlhsh_t             arguments_object_instance_hash;
 
+    nxt_lvlhsh_t             env_hash;
+
     njs_object_t             string_object;
     njs_object_t             objects[NJS_OBJECT_MAX];
     njs_function_t           functions[NJS_FUNCTION_MAX];
diff -r 2cb51aab7e78 -r e18ee27ce760 njs/test/njs_expect_test.exp
--- a/njs/test/njs_expect_test.exp	Tue Jun 18 17:57:22 2019 +0300
+++ b/njs/test/njs_expect_test.exp	Tue Jun 18 17:57:38 2019 +0300
@@ -658,6 +658,20 @@ njs_run {"-c" "console.log(\"a b c\")"} 
 njs_run {"-c" "console.log("} "SyntaxError: Unexpected end of input in string:1"
 
 
+# process
+
+njs_run {"-c" "console.log(typeof process.argv)"} "object"
+njs_run {"-c" "console.log(process.argv[3])" "AAA"} "AAA"
+
+njs_run {"-c" "console.log(typeof process.env)"} "object"
+njs_run {"-c" "console.log(process.env.HOME != undefined)"} "true"
+njs_run {"-c" "console.log(process.env.___UNDECLARED != undefined)"} "false"
+
+njs_run {"-c" "console.log(process.pid)"} "\\d+"
+
+njs_run {"-c" "console.log(process.ppid)"} "\\d+"
+
+
 # disassemble
 
 njs_test {


More information about the nginx-devel mailing list