Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement process.kill() function #808

Merged
merged 4 commits into from
Nov 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
122 changes: 10 additions & 112 deletions external/njs_shell.c
Original file line number Diff line number Diff line change
Expand Up @@ -1901,15 +1901,17 @@ njs_qjs_clear_timeout(JSContext *ctx, JSValueConst this_val, int argc,
}


static JSValue
njs_qjs_console_to_string_tag(JSContext *ctx, JSValueConst this_val)
{
return JS_NewString(ctx, "Console");
}


static JSValue
njs_qjs_process_getter(JSContext *ctx, JSValueConst this_val)
{
char **ep;
JSAtom atom;
JSValue obj, val, str, name, env;
njs_int_t ret;
njs_uint_t i;
const char *entry, *value;
JSValue obj;
njs_console_t *console;

console = JS_GetRuntimeOpaque(JS_GetRuntime(ctx));
Expand All @@ -1918,106 +1920,8 @@ njs_qjs_process_getter(JSContext *ctx, JSValueConst this_val)
return JS_DupValue(ctx, console->process);
}

obj = JS_NewObject(ctx);
if (JS_IsException(obj)) {
return JS_EXCEPTION;
}

ret = qjs_set_to_string_tag(ctx, obj, "process");
if (ret == -1) {
JS_FreeValue(ctx, obj);
return JS_EXCEPTION;
}

val = JS_NewArray(ctx);
if (JS_IsException(val)) {
JS_FreeValue(ctx, obj);
return JS_EXCEPTION;
}

ret = JS_SetPropertyStr(ctx, obj, "argv", val);
if (ret == -1) {
JS_FreeValue(ctx, obj);
JS_FreeValue(ctx, val);
return JS_EXCEPTION;
}

for (i = 0; i < console->argc; i++) {
str = JS_NewStringLen(ctx, console->argv[i],
njs_strlen(console->argv[i]));
if (JS_IsException(str)) {
JS_FreeValue(ctx, obj);
return JS_EXCEPTION;
}

ret = JS_DefinePropertyValueUint32(ctx, val, i, str, JS_PROP_C_W_E);
if (ret == -1) {
JS_FreeValue(ctx, obj);
return JS_EXCEPTION;
}
}

env = JS_NewObject(ctx);
obj = qjs_process_object(ctx, console->argc, (const char **) console->argv);
if (JS_IsException(obj)) {
JS_FreeValue(ctx, obj);
return JS_EXCEPTION;
}

ret = JS_SetPropertyStr(ctx, obj, "env", env);
if (ret == -1) {
JS_FreeValue(ctx, obj);
JS_FreeValue(ctx, env);
return JS_EXCEPTION;
}

ep = environ;

while (*ep != NULL) {
entry = *ep++;

value = (const char *) njs_strchr(entry, '=');
if (njs_slow_path(value == NULL)) {
continue;
}

str = JS_UNDEFINED;
name = JS_NewStringLen(ctx, entry, value - entry);
if (JS_IsException(name)) {
goto error;
}

str = JS_NewStringLen(ctx, value, njs_strlen(value));
if (JS_IsException(str)) {
goto error;
}

atom = JS_ValueToAtom(ctx, name);
if (atom == JS_ATOM_NULL) {
goto error;
}

ret = JS_DefinePropertyValue(ctx, env, atom, str, JS_PROP_C_W_E);
JS_FreeAtom(ctx, atom);
if (ret == -1) {
error:
JS_FreeValue(ctx, name);
JS_FreeValue(ctx, str);
JS_FreeValue(ctx, obj);
return JS_EXCEPTION;
}

JS_FreeValue(ctx, name);
}

ret = JS_SetPropertyStr(ctx, obj, "pid", JS_NewInt32(ctx, getpid()));
if (ret == -1) {
JS_FreeValue(ctx, obj);
return JS_EXCEPTION;
}

ret = JS_SetPropertyStr(ctx, obj, "ppid", JS_NewInt32(ctx, getppid()));
if (ret == -1) {
JS_FreeValue(ctx, obj);
return JS_EXCEPTION;
}

Expand Down Expand Up @@ -2583,6 +2487,7 @@ static const JSCFunctionListEntry njs_qjs_global_proto[] = {


static const JSCFunctionListEntry njs_qjs_console_proto[] = {
JS_CGETSET_DEF("[Symbol.toStringTag]", njs_qjs_console_to_string_tag, NULL),
JS_CFUNC_MAGIC_DEF("error", 0, njs_qjs_console_log, NJS_LOG_ERROR),
JS_CFUNC_MAGIC_DEF("info", 0, njs_qjs_console_log, NJS_LOG_INFO),
JS_CFUNC_MAGIC_DEF("log", 0, njs_qjs_console_log, NJS_LOG_INFO),
Expand Down Expand Up @@ -2759,13 +2664,6 @@ njs_engine_qjs_init(njs_engine_t *engine, njs_opts_t *opts)
goto done;
}

ret = qjs_set_to_string_tag(ctx, obj, "Console");
if (ret == -1) {
njs_stderror("qjs_set_to_string_tag() failed\n");
ret = NJS_ERROR;
goto done;
}

JS_SetOpaque(obj, &njs_console);

JS_SetPropertyFunctionList(ctx, obj, njs_qjs_console_proto,
Expand Down
13 changes: 13 additions & 0 deletions nginx/ngx_js.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ static ngx_int_t ngx_engine_qjs_pending(ngx_engine_t *engine);
static ngx_int_t ngx_engine_qjs_string(ngx_engine_t *e,
njs_opaque_value_t *value, ngx_str_t *str);

static JSValue ngx_qjs_process_getter(JSContext *ctx, JSValueConst this_val);
static JSValue ngx_qjs_ext_set_timeout(JSContext *cx, JSValueConst this_val,
int argc, JSValueConst *argv, int immediate);
static JSValue ngx_qjs_ext_clear_timeout(JSContext *cx, JSValueConst this_val,
Expand Down Expand Up @@ -457,6 +458,7 @@ static const JSCFunctionListEntry ngx_qjs_ext_console[] = {


static const JSCFunctionListEntry ngx_qjs_ext_global[] = {
JS_CGETSET_DEF("process", ngx_qjs_process_getter, NULL),
JS_CFUNC_MAGIC_DEF("setTimeout", 1, ngx_qjs_ext_set_timeout, 0),
JS_CFUNC_MAGIC_DEF("setImmediate", 1, ngx_qjs_ext_set_timeout, 1),
JS_CFUNC_DEF("clearTimeout", 1, ngx_qjs_ext_clear_timeout),
Expand Down Expand Up @@ -1566,6 +1568,13 @@ ngx_qjs_clear_timer(ngx_qjs_event_t *event)
}


static JSValue
ngx_qjs_process_getter(JSContext *cx, JSValueConst this_val)
{
return qjs_process_object(cx, ngx_argc, (const char **) ngx_argv);
}


static JSValue
ngx_qjs_ext_set_timeout(JSContext *cx, JSValueConst this_val, int argc,
JSValueConst *argv, int immediate)
Expand Down Expand Up @@ -3823,6 +3832,10 @@ ngx_js_init_conf_vm(ngx_conf_t *cf, ngx_js_loc_conf_t *conf,
ngx_pool_cleanup_t *cln;
ngx_js_named_path_t *import;

if (ngx_set_environment(cf->cycle, NULL) == NULL) {
return NGX_ERROR;
}

if (conf->preload_objects != NGX_CONF_UNSET_PTR) {
if (ngx_js_init_preload_vm(cf, (ngx_js_loc_conf_t *)conf) != NGX_OK) {
return NGX_ERROR;
Expand Down
84 changes: 84 additions & 0 deletions nginx/t/js_process.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
#!/usr/bin/perl

# (C) Dmitry Volyntsev
# (C) Nginx, Inc.

# Tests for http njs module, process object.

###############################################################################

use warnings;
use strict;

use Test::More;
use Socket qw/ CRLF /;

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 {
}

env FOO=bar;
env BAR=baz;

http {
%%TEST_GLOBALS_HTTP%%

js_import test.js;

server {
listen 127.0.0.1:8080;
server_name localhost;

location /argv {
js_content test.argv;
}

location /env {
js_content test.env;
}
}
}

EOF

$t->write_file('test.js', <<EOF);
function argv(r) {
var av = process.argv;
r.return(200,`\${Array.isArray(av)} \${av[0].indexOf('nginx') >= 0}`);
}

function env(r) {
var e = process.env[r.args.var];
r.return(200, e ? e : 'undefined');
}

export default { argv, env };

EOF

$t->try_run('no njs process object')->plan(4);

###############################################################################

like(http_get('/argv'), qr/true true/, 'argv');
like(http_get('/env?var=FOO'), qr/bar/, 'env FOO');
like(http_get('/env?var=BAR'), qr/baz/, 'env BAR');
like(http_get('/env?var=HOME'), qr/undefined/, 'env HOME');

###############################################################################
108 changes: 108 additions & 0 deletions nginx/t/stream_js_process.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
#!/usr/bin/perl

# (C) Dmitry Volyntsev
# (C) Nginx, Inc.

# Tests for stream njs module, process object.

###############################################################################

use warnings;
use strict;

use Test::More;

BEGIN { use FindBin; chdir($FindBin::Bin); }

use lib 'lib';
use Test::Nginx;
use Test::Nginx::Stream qw/ stream /;

###############################################################################

select STDERR; $| = 1;
select STDOUT; $| = 1;

my $t = Test::Nginx->new()->has(qw/stream stream_return/)
->write_file_expand('nginx.conf', <<'EOF');

%%TEST_GLOBALS%%

daemon off;

events {
}

env FOO=bar;
env BAR=baz;

stream {
%%TEST_GLOBALS_STREAM%%

js_import test.js;

js_set $env_foo test.env_foo;
js_set $env_bar test.env_bar;
js_set $env_home test.env_home;
js_set $argv test.argv;

server {
listen 127.0.0.1:8081;
return $env_foo;
}

server {
listen 127.0.0.1:8082;
return $env_bar;
}

server {
listen 127.0.0.1:8083;
return $env_home;
}

server {
listen 127.0.0.1:8084;
return $argv;
}
}

EOF

$t->write_file('test.js', <<EOF);
function env(s, v) {
var e = process.env[v];
return e ? e : 'undefined';
}

function env_foo(s) {
return env(s, 'FOO');
}

function env_bar(s) {
return env(s, 'BAR');
}

function env_home(s) {
return env(s, 'HOME');
}

function argv(r) {
var av = process.argv;
return `\${Array.isArray(av)} \${av[0].indexOf('nginx') >= 0}`;
}

export default { env_foo, env_bar, env_home, argv };

EOF

$t->try_run('no njs stream session object')->plan(4);

###############################################################################

is(stream('127.0.0.1:' . port(8081))->read(), 'bar', 'env.FOO');
is(stream('127.0.0.1:' . port(8082))->read(), 'baz', 'env.BAR');
is(stream('127.0.0.1:' . port(8083))->read(), 'undefined', 'env HOME');
is(stream('127.0.0.1:' . port(8084))->read(), 'true true', 'argv');

###############################################################################
Loading