ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_js_variable_var(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
-static ngx_int_t ngx_http_js_init_vm(ngx_http_request_t *r,
- unsigned inject_request);
+static ngx_int_t ngx_http_js_init_vm(ngx_http_request_t *r, njs_int_t proto_id);
static void ngx_http_js_cleanup_ctx(void *data);
static njs_int_t ngx_http_js_ext_keys_header(njs_vm_t *vm, njs_value_t *value,
static njs_int_t ngx_http_js_ext_variables(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_http_js_periodic_session_variables(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_http_js_ext_subrequest(njs_vm_t *vm, njs_value_t *args,
njs_uint_t nargs, njs_index_t unused, njs_value_t *retval);
static ngx_int_t ngx_http_js_subrequest(ngx_http_request_t *r,
static njs_int_t ngx_http_js_request_proto_id;
+static njs_int_t ngx_http_js_periodic_session_proto_id;
static njs_external_t ngx_http_js_ext_request[] = {
};
+static njs_external_t ngx_http_js_ext_periodic_session[] = {
+
+ {
+ .flags = NJS_EXTERN_PROPERTY | NJS_EXTERN_SYMBOL,
+ .name.symbol = NJS_SYMBOL_TO_STRING_TAG,
+ .u.property = {
+ .value = "PeriodicSession",
+ }
+ },
+
+ {
+ .flags = NJS_EXTERN_OBJECT,
+ .name.string = njs_str("rawVariables"),
+ .u.object = {
+ .writable = 1,
+ .prop_handler = ngx_http_js_periodic_session_variables,
+ .magic32 = NGX_JS_BUFFER,
+ }
+ },
+
+ {
+ .flags = NJS_EXTERN_OBJECT,
+ .name.string = njs_str("variables"),
+ .u.object = {
+ .writable = 1,
+ .prop_handler = ngx_http_js_periodic_session_variables,
+ .magic32 = NGX_JS_STRING,
+ }
+ },
+};
+
+
static njs_vm_ops_t ngx_http_js_ops = {
ngx_http_js_set_timer,
ngx_http_js_clear_timer,
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http js content event handler");
- rc = ngx_http_js_init_vm(r, 1);
+ rc = ngx_http_js_init_vm(r, ngx_http_js_request_proto_id);
if (rc == NGX_ERROR || rc == NGX_DECLINED) {
ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
return ngx_http_next_header_filter(r);
}
- rc = ngx_http_js_init_vm(r, 1);
+ rc = ngx_http_js_init_vm(r, ngx_http_js_request_proto_id);
if (rc == NGX_ERROR || rc == NGX_DECLINED) {
return NGX_ERROR;
return ngx_http_next_body_filter(r, in);
}
- rc = ngx_http_js_init_vm(r, 1);
+ rc = ngx_http_js_init_vm(r, ngx_http_js_request_proto_id);
if (rc == NGX_ERROR || rc == NGX_DECLINED) {
return NGX_ERROR;
ngx_str_t value;
ngx_http_js_ctx_t *ctx;
- rc = ngx_http_js_init_vm(r, 1);
+ rc = ngx_http_js_init_vm(r, ngx_http_js_request_proto_id);
if (rc == NGX_ERROR) {
return NGX_ERROR;
static ngx_int_t
-ngx_http_js_init_vm(ngx_http_request_t *r, unsigned inject_request)
+ngx_http_js_init_vm(ngx_http_request_t *r, njs_int_t proto_id)
{
njs_int_t rc;
ngx_str_t exception;
return NGX_ERROR;
}
- if (inject_request) {
- rc = njs_vm_external_create(ctx->vm, njs_value_arg(&ctx->request),
- ngx_http_js_request_proto_id, r, 0);
- if (rc != NJS_OK) {
- return NGX_ERROR;
- }
+ rc = njs_vm_external_create(ctx->vm, njs_value_arg(&ctx->request),
+ proto_id, r, 0);
+ if (rc != NJS_OK) {
+ return NGX_ERROR;
}
return NGX_OK;
static njs_int_t
-ngx_http_js_ext_variables(njs_vm_t *vm, njs_object_prop_t *prop,
- njs_value_t *value, njs_value_t *setval, njs_value_t *retval)
+ngx_http_js_request_variables(njs_vm_t *vm, njs_object_prop_t *prop,
+ ngx_http_request_t *r, njs_value_t *setval, njs_value_t *retval)
{
njs_int_t rc;
njs_str_t val, s;
ngx_str_t name;
ngx_uint_t key;
- ngx_http_request_t *r;
ngx_http_variable_t *v;
ngx_http_core_main_conf_t *cmcf;
ngx_http_variable_value_t *vv;
- r = njs_vm_external(vm, ngx_http_js_request_proto_id, value);
- if (r == NULL) {
- njs_value_undefined_set(retval);
- return NJS_DECLINED;
- }
-
rc = njs_vm_prop_name(vm, prop, &val);
if (rc != NJS_OK) {
njs_value_undefined_set(retval);
}
+static njs_int_t
+ngx_http_js_ext_variables(njs_vm_t *vm, njs_object_prop_t *prop,
+ njs_value_t *value, njs_value_t *setval, njs_value_t *retval)
+{
+ ngx_http_request_t *r;
+
+ r = njs_vm_external(vm, ngx_http_js_request_proto_id, value);
+ if (r == NULL) {
+ njs_value_undefined_set(retval);
+ return NJS_DECLINED;
+ }
+
+ return ngx_http_js_request_variables(vm, prop, r, setval, retval);
+}
+
+
+static njs_int_t
+ngx_http_js_periodic_session_variables(njs_vm_t *vm, njs_object_prop_t *prop,
+ njs_value_t *value, njs_value_t *setval, njs_value_t *retval)
+{
+ ngx_http_request_t *r;
+
+ r = njs_vm_external(vm, ngx_http_js_periodic_session_proto_id, value);
+ if (r == NULL) {
+ njs_value_undefined_set(retval);
+ return NJS_DECLINED;
+ }
+
+ return ngx_http_js_request_variables(vm, prop, r, setval, retval);
+}
+
+
static njs_int_t
ngx_http_js_promise_trampoline(njs_vm_t *vm, njs_value_t *args,
njs_uint_t nargs, njs_index_t unused, njs_value_t *retval)
r->health_check = 1;
r->write_event_handler = ngx_http_js_periodic_write_event_handler;
- rc = ngx_http_js_init_vm(r, 0);
+ rc = ngx_http_js_init_vm(r, ngx_http_js_periodic_session_proto_id);
if (rc != NGX_OK) {
ngx_http_js_periodic_destroy(r, periodic);
r->count++;
- rc = ngx_js_invoke(ctx->vm, &periodic->method, &periodic->log, NULL, 0,
- &ctx->retval);
+ rc = ngx_js_invoke(ctx->vm, &periodic->method, &periodic->log,
+ &ctx->request, 1, &ctx->retval);
if (rc == NGX_AGAIN) {
rc = NGX_OK;
return NJS_ERROR;
}
+ ngx_http_js_periodic_session_proto_id = njs_vm_external_prototype(vm,
+ ngx_http_js_ext_periodic_session,
+ njs_nitems(ngx_http_js_ext_periodic_session));
+ if (ngx_http_js_periodic_session_proto_id < 0) {
+ return NJS_ERROR;
+ }
+
return NJS_OK;
}
static ngx_int_t ngx_stream_js_variable_var(ngx_stream_session_t *s,
ngx_stream_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_stream_js_init_vm(ngx_stream_session_t *s,
- unsigned inject_session);
+ njs_int_t proto_id);
static void ngx_stream_js_drop_events(ngx_stream_js_ctx_t *ctx);
static void ngx_stream_js_cleanup(void *data);
static njs_int_t ngx_stream_js_run_event(ngx_stream_session_t *s,
static njs_int_t ngx_stream_js_ext_variables(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_stream_js_periodic_variables(njs_vm_t *vm,
+ njs_object_prop_t *prop, njs_value_t *value, njs_value_t *setval,
+ njs_value_t *retval);
static njs_host_event_t ngx_stream_js_set_timer(njs_external_ptr_t external,
uint64_t delay, njs_vm_event_t vm_event);
};
+static njs_external_t ngx_stream_js_ext_periodic_session[] = {
+
+ {
+ .flags = NJS_EXTERN_PROPERTY | NJS_EXTERN_SYMBOL,
+ .name.symbol = NJS_SYMBOL_TO_STRING_TAG,
+ .u.property = {
+ .value = "PeriodicSession",
+ }
+ },
+
+ {
+ .flags = NJS_EXTERN_OBJECT,
+ .name.string = njs_str("rawVariables"),
+ .u.object = {
+ .writable = 1,
+ .prop_handler = ngx_stream_js_periodic_variables,
+ .magic32 = NGX_JS_BUFFER,
+ }
+ },
+
+ {
+ .flags = NJS_EXTERN_OBJECT,
+ .name.string = njs_str("variables"),
+ .u.object = {
+ .writable = 1,
+ .prop_handler = ngx_stream_js_periodic_variables,
+ .magic32 = NGX_JS_STRING,
+ }
+ },
+};
+
+
static njs_external_t ngx_stream_js_ext_session_flags[] = {
{
static njs_int_t ngx_stream_js_session_proto_id;
+static njs_int_t ngx_stream_js_periodic_session_proto_id;
static njs_int_t ngx_stream_js_session_flags_proto_id;
return NGX_DECLINED;
}
- rc = ngx_stream_js_init_vm(s, 1);
+ rc = ngx_stream_js_init_vm(s, ngx_stream_js_session_proto_id);
if (rc != NGX_OK) {
return rc;
}
ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0, "stream js filter u:%ui",
from_upstream);
- rc = ngx_stream_js_init_vm(s, 1);
+ rc = ngx_stream_js_init_vm(s, ngx_stream_js_session_proto_id);
if (rc == NGX_ERROR) {
return NGX_ERROR;
ngx_str_t value;
ngx_stream_js_ctx_t *ctx;
- rc = ngx_stream_js_init_vm(s, 1);
+ rc = ngx_stream_js_init_vm(s, ngx_stream_js_session_proto_id);
if (rc == NGX_ERROR) {
return NGX_ERROR;
static ngx_int_t
-ngx_stream_js_init_vm(ngx_stream_session_t *s, unsigned inject_session)
+ngx_stream_js_init_vm(ngx_stream_session_t *s, njs_int_t proto_id)
{
njs_int_t rc;
njs_str_t key;
return NGX_ERROR;
}
- if (inject_session) {
- rc = njs_vm_external_create(ctx->vm, njs_value_arg(&ctx->args[0]),
- ngx_stream_js_session_proto_id, s, 0);
- if (rc != NJS_OK) {
- return NGX_ERROR;
- }
+ rc = njs_vm_external_create(ctx->vm, njs_value_arg(&ctx->args[0]),
+ proto_id, s, 0);
+ if (rc != NJS_OK) {
+ return NGX_ERROR;
}
return NGX_OK;
static njs_int_t
-ngx_stream_js_ext_variables(njs_vm_t *vm, njs_object_prop_t *prop,
- njs_value_t *value, njs_value_t *setval, njs_value_t *retval)
+ngx_stream_js_session_variables(njs_vm_t *vm, njs_object_prop_t *prop,
+ ngx_stream_session_t *s, njs_value_t *setval, njs_value_t *retval)
{
njs_int_t rc;
njs_str_t val;
ngx_str_t name;
ngx_uint_t key;
ngx_stream_variable_t *v;
- ngx_stream_session_t *s;
ngx_stream_core_main_conf_t *cmcf;
ngx_stream_variable_value_t *vv;
- s = njs_vm_external(vm, ngx_stream_js_session_proto_id, value);
- if (s == NULL) {
- njs_value_undefined_set(retval);
- return NJS_DECLINED;
- }
-
rc = njs_vm_prop_name(vm, prop, &val);
if (rc != NJS_OK) {
njs_value_undefined_set(retval);
}
+static njs_int_t
+ngx_stream_js_ext_variables(njs_vm_t *vm, njs_object_prop_t *prop,
+ njs_value_t *value, njs_value_t *setval, njs_value_t *retval)
+{
+ ngx_stream_session_t *s;
+
+ s = njs_vm_external(vm, ngx_stream_js_session_proto_id, value);
+ if (s == NULL) {
+ njs_value_undefined_set(retval);
+ return NJS_DECLINED;
+ }
+
+ return ngx_stream_js_session_variables(vm, prop, s, setval, retval);
+}
+
+
+static njs_int_t
+ngx_stream_js_periodic_variables(njs_vm_t *vm, njs_object_prop_t *prop,
+ njs_value_t *value, njs_value_t *setval, njs_value_t *retval)
+{
+ ngx_stream_session_t *s;
+
+ s = njs_vm_external(vm, ngx_stream_js_periodic_session_proto_id, value);
+ if (s == NULL) {
+ njs_value_undefined_set(retval);
+ return NJS_DECLINED;
+ }
+
+ return ngx_stream_js_session_variables(vm, prop, s, setval, retval);
+}
+
+
static njs_host_event_t
ngx_stream_js_set_timer(njs_external_ptr_t external, uint64_t delay,
njs_vm_event_t vm_event)
return NJS_ERROR;
}
+ ngx_stream_js_periodic_session_proto_id = njs_vm_external_prototype(vm,
+ ngx_stream_js_ext_periodic_session,
+ njs_nitems(ngx_stream_js_ext_periodic_session));
+ if (ngx_stream_js_periodic_session_proto_id < 0) {
+ return NJS_ERROR;
+ }
+
ngx_stream_js_session_flags_proto_id = njs_vm_external_prototype(vm,
ngx_stream_js_ext_session_flags,
njs_nitems(ngx_stream_js_ext_session_flags));
s->health_check = 1;
- rc = ngx_stream_js_init_vm(s, 0);
+ rc = ngx_stream_js_init_vm(s, ngx_stream_js_periodic_session_proto_id);
if (rc != NGX_OK) {
ngx_stream_js_periodic_destroy(s, periodic);
s->received++;
- rc = ngx_js_invoke(ctx->vm, &periodic->method, &periodic->log, NULL, 0,
- &ctx->retval);
+ rc = ngx_js_invoke(ctx->vm, &periodic->method, &periodic->log,
+ &ctx->args[0], 1, &ctx->retval);
if (rc == NGX_AGAIN) {
rc = NGX_OK;
js_shared_dict_zone zone=strings:32k;
js_shared_dict_zone zone=workers:32k type=number;
+ js_set $js_set test.js_set;
+ js_var $js_var JS-VAR;
+ map _ $map_var {
+ default "MAP-VAR";
+ }
+
server {
listen 127.0.0.1:8080;
server_name localhost;
js_periodic test.fetch interval=40ms;
js_periodic test.multiple_fetches interval=1s;
js_periodic test.affinity interval=50ms worker_affinity=0101;
+ js_periodic test.vars interval=10s;
js_periodic test.fetch_exception interval=1s;
js_periodic test.tick_exception interval=1s;
location /test_timeout_exception {
js_content test.test_timeout_exception;
}
+
+ location /test_vars {
+ js_content test.test_vars;
+ }
}
}
ngx.shared.strings.set('fetch', v + body);
}
+ function js_set() {
+ return 'JS-SET';
+ }
+
async function multiple_fetches() {
let reply = await ngx.fetch('http://127.0.0.1:$p0/fetch_ok');
let reply2 = await ngx.fetch('http://127.0.0.1:$p0/fetch_foo');
}, 1);
}
+ function vars(s) {
+ var v = s.variables;
+ ngx.shared.strings.set('vars',
+ `\${v.js_var}|\${v.js_set}|\${v.map_var}`);
+ }
+
function test_affinity(r) {
r.return(200, `[\${ngx.shared.workers.keys().toSorted()}]`);
}
r.return(200, ngx.shared.nums.get('timeout_exception') >= 2);
}
- export default { affinity, fetch, fetch_exception, file, multiple_fetches,
- overrun, test_affinity, test_fetch, test_file,
- test_multiple_fetches, test_tick, test_timeout_exception,
- test_timer, tick, tick_exception, timer, timer_exception,
+ function test_vars(r) {
+ r.return(200, ngx.shared.strings.get('vars'));
+ }
+
+ export default { affinity, fetch, fetch_exception, file, js_set,
+ multiple_fetches, overrun, vars, test_affinity, test_fetch,
+ test_file, test_multiple_fetches, test_tick,
+ test_timeout_exception, test_timer, test_vars, tick,
+ tick_exception, timer, timer_exception,
timeout_exception };
EOF
-$t->try_run('no js_periodic')->plan(8);
+$t->try_run('no js_periodic')->plan(9);
###############################################################################
like(http_get('/test_multiple_fetches'), qr/true/, 'multiple fetch test');
like(http_get('/test_timeout_exception'), qr/true/, 'timeout exception test');
+like(http_get('/test_vars'), qr/JS-VAR\|JS-SET\|MAP-VAR/, 'vars test');
$t->stop();
js_shared_dict_zone zone=strings:32k;
js_shared_dict_zone zone=workers:32k type=number;
+ js_set $js_set test.js_set;
+ js_var $js_var JS-VAR;
+ map _ $map_var {
+ default "MAP-VAR";
+ }
+
server {
listen 127.0.0.1:8080;
js_periodic test.fetch interval=40ms;
js_periodic test.multiple_fetches interval=1s;
js_periodic test.affinity interval=50ms worker_affinity=0101;
+ js_periodic test.vars interval=10s;
js_periodic test.fetch_exception interval=1s;
js_periodic test.tick_exception interval=1s;
let reply = await ngx.fetch('garbage');
}
+ function js_set() {
+ return 'JS-SET';
+ }
+
async function multiple_fetches() {
let reply = await ngx.fetch('http://127.0.0.1:$p1/fetch_ok');
let reply2 = await ngx.fetch('http://127.0.0.1:$p1/fetch_foo');
}, 1);
}
+ function vars(s) {
+ var v = s.variables;
+ ngx.shared.strings.set('vars',
+ `\${v.js_var}|\${v.js_set}|\${v.map_var}`);
+ }
+
function test(s) {
s.on('upload', function (data) {
if (data.length > 0) {
break;
+ case 'vars':
+ var vars = ngx.shared.strings.get('vars');
+ if (vars === 'JS-VAR|JS-SET|MAP-VAR') {
+ s.done();
+ return;
+ }
+
+ break;
+
default:
throw new Error(`Unknown test "\${data}"`);
}
});
}
- export default { affinity, fetch, fetch_exception, multiple_fetches, file,
- overrun, test, tick, tick_exception, timer,
- timer_exception, timeout_exception };
+ export default { affinity, fetch, fetch_exception, js_set, multiple_fetches,
+ file, overrun, test, tick, tick_exception, timer,
+ timer_exception, timeout_exception, vars };
EOF
$t->run_daemon(\&stream_daemon, port(8090));
-$t->try_run('no js_periodic')->plan(8);
+$t->try_run('no js_periodic')->plan(9);
$t->waitforsocket('127.0.0.1:' . port(8090));
###############################################################################
'multiple_fetches', 'muliple fetches test');
is(stream('127.0.0.1:' . port(8080))->io('timeout_exception'),
'timeout_exception', 'timeout exception test');
+is(stream('127.0.0.1:' . port(8080))->io('vars'), 'vars', 'vars test');
$t->stop();
*/
warn(message: NjsStringOrBuffer): void;
}
+
+
+/**
+ * NginxPeriodicSession object is available as the first argument in the js_periodic handler.
+ * @since 0.8.1
+ */
+interface NginxPeriodicSession {
+ /**
+ * nginx variables as Buffers.
+ *
+ * @see variables
+ */
+ readonly rawVariables: NginxRawVariables;
+ /**
+ * nginx variables as strings.
+ *
+ * **Warning:** Bytes invalid in UTF-8 encoding may be converted into the replacement character.
+ *
+ * @see rawVariables
+ */
+ readonly variables: NginxVariables;
+}
*/
warn(message: NjsStringOrBuffer): void;
}
+
+
+/**
+ * NginxPeriodicSession object is available as the first argument in the js_periodic handler.
+ * @since 0.8.1
+ */
+interface NginxPeriodicSession {
+ /**
+ * nginx variables as Buffers.
+ *
+ * @see variables
+ */
+ readonly rawVariables: NginxRawVariables;
+ /**
+ * nginx variables as strings.
+ *
+ * **Warning:** Bytes invalid in UTF-8 encoding may be converted into the replacement character.
+ *
+ * @see rawVariables
+ */
+ readonly variables: NginxVariables;
+}