[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