[njs] Modules: introduced Buffer alternatives for object properties.
Dmitry Volyntsev
xeioex at nginx.com
Wed Nov 25 11:09:23 UTC 2020
details: https://hg.nginx.org/njs/rev/434f20c29f4c
branches:
changeset: 1571:434f20c29f4c
user: Dmitry Volyntsev <xeioex at nginx.com>
date: Wed Nov 25 10:47:47 2020 +0000
description:
Modules: introduced Buffer alternatives for object properties.
Buffer variant returns the property bytes as is, whereas the string
version may convert bytes invalid in UTF-8 encoding into replacement
character.
HTTP
new request object properties:
r.reqBody (r.requestBody),
r.resBody (r.responseBody),
r.vars (r.variables).
Stream
new stream object properties:
s.vars (s.variables).
new events:
The events' callbacks are identical to the string counterparts, except the data
argument:
upstream (upload),
downstream (download).
diffstat:
nginx/ngx_http_js_module.c | 71 +++++++++++++++++++++++--
nginx/ngx_js.h | 10 +++
nginx/ngx_stream_js_module.c | 117 ++++++++++++++++++++++++++++++++----------
src/njs.h | 2 +
src/njs_extern.c | 1 +
src/njs_value.c | 8 ++
src/njs_value.h | 1 +
7 files changed, 175 insertions(+), 35 deletions(-)
diffs (517 lines):
diff -r 0684301385d9 -r 434f20c29f4c nginx/ngx_http_js_module.c
--- a/nginx/ngx_http_js_module.c Wed Nov 25 10:47:25 2020 +0000
+++ b/nginx/ngx_http_js_module.c Wed Nov 25 10:47:47 2020 +0000
@@ -43,6 +43,7 @@ typedef struct {
ngx_int_t status;
njs_opaque_value_t request;
njs_opaque_value_t request_body;
+ njs_opaque_value_t response_body;
ngx_str_t redirect_uri;
ngx_array_t promise_callbacks;
} ngx_http_js_ctx_t;
@@ -319,9 +320,19 @@ static njs_external_t ngx_http_js_ext_r
{
.flags = NJS_EXTERN_PROPERTY,
.name.string = njs_str("requestBody"),
+ .u.property = {
+ .handler = ngx_http_js_ext_get_request_body,
+ .magic32 = NGX_JS_STRING,
+ }
+ },
+
+ {
+ .flags = NJS_EXTERN_PROPERTY,
+ .name.string = njs_str("reqBody"),
.enumerable = 1,
.u.property = {
.handler = ngx_http_js_ext_get_request_body,
+ .magic32 = NGX_JS_BUFFER,
}
},
@@ -336,9 +347,19 @@ static njs_external_t ngx_http_js_ext_r
{
.flags = NJS_EXTERN_PROPERTY,
.name.string = njs_str("responseBody"),
+ .u.property = {
+ .handler = ngx_http_js_ext_get_response_body,
+ .magic32 = NGX_JS_STRING,
+ }
+ },
+
+ {
+ .flags = NJS_EXTERN_PROPERTY,
+ .name.string = njs_str("resBody"),
.enumerable = 1,
.u.property = {
.handler = ngx_http_js_ext_get_response_body,
+ .magic32 = NGX_JS_BUFFER,
}
},
@@ -379,6 +400,17 @@ static njs_external_t ngx_http_js_ext_r
.u.object = {
.writable = 1,
.prop_handler = ngx_http_js_ext_variables,
+ .magic32 = NGX_JS_STRING,
+ }
+ },
+
+ {
+ .flags = NJS_EXTERN_OBJECT,
+ .name.string = njs_str("vars"),
+ .u.object = {
+ .writable = 1,
+ .prop_handler = ngx_http_js_ext_variables,
+ .magic32 = NGX_JS_BUFFER,
}
},
@@ -1891,8 +1923,12 @@ ngx_http_js_ext_get_request_body(njs_vm_
request_body = (njs_value_t *) &ctx->request_body;
if (!njs_value_is_null(request_body)) {
- njs_value_assign(retval, request_body);
- return NJS_OK;
+ if ((njs_vm_prop_magic32(prop) == NGX_JS_BUFFER)
+ == (uint32_t) njs_value_is_buffer(request_body))
+ {
+ njs_value_assign(retval, request_body);
+ return NJS_OK;
+ }
}
if (r->request_body == NULL || r->request_body->bufs == NULL) {
@@ -1939,8 +1975,7 @@ ngx_http_js_ext_get_request_body(njs_vm_
done:
- ret = njs_vm_value_string_set(vm, request_body, body, len);
-
+ ret = ngx_js_prop(vm, njs_vm_prop_magic32(prop), request_body, body, len);
if (ret != NJS_OK) {
return NJS_ERROR;
}
@@ -2220,7 +2255,8 @@ ngx_http_js_ext_variables(njs_vm_t *vm,
return NJS_DECLINED;
}
- return njs_vm_value_string_set(vm, retval, vv->data, vv->len);
+ return ngx_js_prop(vm, njs_vm_prop_magic32(prop), retval, vv->data,
+ vv->len);
}
cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
@@ -2743,7 +2779,10 @@ ngx_http_js_ext_get_response_body(njs_vm
{
size_t len;
u_char *p;
+ njs_int_t ret;
ngx_buf_t *b;
+ njs_value_t *response_body;
+ ngx_http_js_ctx_t *ctx;
ngx_http_request_t *r;
r = njs_vm_external(vm, value);
@@ -2752,6 +2791,18 @@ ngx_http_js_ext_get_response_body(njs_vm
return NJS_DECLINED;
}
+ ctx = ngx_http_get_module_ctx(r, ngx_http_js_module);
+ response_body = (njs_value_t *) &ctx->response_body;
+
+ if (!njs_value_is_null(response_body)) {
+ if ((njs_vm_prop_magic32(prop) == NGX_JS_BUFFER)
+ == (uint32_t) njs_value_is_buffer(response_body))
+ {
+ njs_value_assign(retval, response_body);
+ return NJS_OK;
+ }
+ }
+
b = r->out ? r->out->buf : NULL;
if (b == NULL) {
@@ -2761,8 +2812,9 @@ ngx_http_js_ext_get_response_body(njs_vm
len = b->last - b->pos;
- p = njs_vm_value_string_alloc(vm, retval, len);
+ p = ngx_pnalloc(r->pool, len);
if (p == NULL) {
+ njs_vm_memory_error(vm);
return NJS_ERROR;
}
@@ -2770,6 +2822,13 @@ ngx_http_js_ext_get_response_body(njs_vm
ngx_memcpy(p, b->pos, len);
}
+ ret = ngx_js_prop(vm, njs_vm_prop_magic32(prop), response_body, p, len);
+ if (ret != NJS_OK) {
+ return NJS_ERROR;
+ }
+
+ njs_value_assign(retval, response_body);
+
return NJS_OK;
}
diff -r 0684301385d9 -r 434f20c29f4c nginx/ngx_js.h
--- a/nginx/ngx_js.h Wed Nov 25 10:47:25 2020 +0000
+++ b/nginx/ngx_js.h Wed Nov 25 10:47:47 2020 +0000
@@ -15,10 +15,20 @@
#include <njs.h>
+#define NGX_JS_UNSET 0
+#define NGX_JS_STRING 1
+#define NGX_JS_BUFFER 2
+
+
#define ngx_external_connection(vm, ext) \
(*((ngx_connection_t **) ((u_char *) ext + njs_vm_meta(vm, 0))))
+#define ngx_js_prop(vm, type, value, start, len) \
+ ((type == NGX_JS_STRING) ? njs_vm_value_string_set(vm, value, start, len) \
+ : njs_vm_value_buffer_set(vm, value, start, len))
+
+
ngx_int_t ngx_js_call(njs_vm_t *vm, ngx_str_t *s, njs_opaque_value_t *value,
ngx_log_t *log);
diff -r 0684301385d9 -r 434f20c29f4c nginx/ngx_stream_js_module.c
--- a/nginx/ngx_stream_js_module.c Wed Nov 25 10:47:25 2020 +0000
+++ b/nginx/ngx_stream_js_module.c Wed Nov 25 10:47:47 2020 +0000
@@ -39,6 +39,12 @@ typedef struct {
typedef struct {
+ njs_vm_event_t ev;
+ ngx_uint_t data_type;
+} ngx_stream_js_ev_t;
+
+
+typedef struct {
njs_vm_t *vm;
ngx_log_t *log;
njs_opaque_value_t args[3];
@@ -51,7 +57,7 @@ typedef struct {
#define NGX_JS_EVENT_UPLOAD 0
#define NGX_JS_EVENT_DOWNLOAD 1
#define NGX_JS_EVENT_MAX 2
- njs_vm_event_t events[2];
+ ngx_stream_js_ev_t events[2];
unsigned from_upstream:1;
unsigned filter:1;
unsigned in_progress:1;
@@ -79,7 +85,7 @@ static void ngx_stream_js_drop_events(ng
static void ngx_stream_js_cleanup_ctx(void *data);
static void ngx_stream_js_cleanup_vm(void *data);
static njs_int_t ngx_stream_js_buffer_arg(ngx_stream_session_t *s,
- njs_value_t *buffer);
+ njs_value_t *buffer, ngx_uint_t data_type);
static njs_int_t ngx_stream_js_flags_arg(ngx_stream_session_t *s,
njs_value_t *flags);
static njs_vm_event_t *ngx_stream_js_event(ngx_stream_session_t *s,
@@ -233,6 +239,17 @@ static njs_external_t ngx_stream_js_ext
.u.object = {
.writable = 1,
.prop_handler = ngx_stream_js_ext_variables,
+ .magic32 = NGX_JS_STRING,
+ }
+ },
+
+ {
+ .flags = NJS_EXTERN_OBJECT,
+ .name.string = njs_str("vars"),
+ .u.object = {
+ .writable = 1,
+ .prop_handler = ngx_stream_js_ext_variables,
+ .magic32 = NGX_JS_BUFFER,
}
},
@@ -412,6 +429,7 @@ ngx_stream_js_phase_handler(ngx_stream_s
njs_int_t ret;
ngx_int_t rc;
ngx_connection_t *c;
+ ngx_stream_js_ev_t *event;
ngx_stream_js_ctx_t *ctx;
if (name->len == 0) {
@@ -444,8 +462,11 @@ ngx_stream_js_phase_handler(ngx_stream_s
}
}
- if (ctx->events[NGX_JS_EVENT_UPLOAD] != NULL) {
- ret = ngx_stream_js_buffer_arg(s, njs_value_arg(&ctx->args[1]));
+ event = &ctx->events[NGX_JS_EVENT_UPLOAD];
+
+ if (event->ev != NULL) {
+ ret = ngx_stream_js_buffer_arg(s, njs_value_arg(&ctx->args[1]),
+ event->data_type);
if (ret != NJS_OK) {
goto exception;
}
@@ -455,8 +476,7 @@ ngx_stream_js_phase_handler(ngx_stream_s
goto exception;
}
- njs_vm_post_event(ctx->vm, ctx->events[NGX_JS_EVENT_UPLOAD],
- njs_value_arg(&ctx->args[1]), 2);
+ njs_vm_post_event(ctx->vm, event->ev, njs_value_arg(&ctx->args[1]), 2);
rc = njs_vm_run(ctx->vm);
if (rc == NJS_ERROR) {
@@ -466,7 +486,7 @@ ngx_stream_js_phase_handler(ngx_stream_s
if (njs_vm_pending(ctx->vm)) {
ctx->in_progress = 1;
- rc = ctx->events[NGX_JS_EVENT_UPLOAD] ? NGX_AGAIN : NGX_DONE;
+ rc = ctx->events[NGX_JS_EVENT_UPLOAD].ev ? NGX_AGAIN : NGX_DONE;
} else {
ctx->in_progress = 0;
@@ -490,8 +510,8 @@ exception:
#define ngx_stream_event(from_upstream) \
- (from_upstream ? ctx->events[NGX_JS_EVENT_DOWNLOAD] \
- : ctx->events[NGX_JS_EVENT_UPLOAD])
+ (from_upstream ? &ctx->events[NGX_JS_EVENT_DOWNLOAD] \
+ : &ctx->events[NGX_JS_EVENT_UPLOAD])
static ngx_int_t
@@ -503,6 +523,7 @@ ngx_stream_js_body_filter(ngx_stream_ses
ngx_int_t rc;
ngx_chain_t *out, *cl;
ngx_connection_t *c;
+ ngx_stream_js_ev_t *event;
ngx_stream_js_ctx_t *ctx;
ngx_stream_js_srv_conf_t *jscf;
@@ -543,8 +564,11 @@ ngx_stream_js_body_filter(ngx_stream_ses
while (in) {
ctx->buf = in->buf;
- if (ngx_stream_event(from_upstream) != NULL) {
- ret = ngx_stream_js_buffer_arg(s, njs_value_arg(&ctx->args[1]));
+ event = ngx_stream_event(from_upstream);
+
+ if (event->ev != NULL) {
+ ret = ngx_stream_js_buffer_arg(s, njs_value_arg(&ctx->args[1]),
+ event->data_type);
if (ret != NJS_OK) {
goto exception;
}
@@ -554,7 +578,7 @@ ngx_stream_js_body_filter(ngx_stream_ses
goto exception;
}
- njs_vm_post_event(ctx->vm, ngx_stream_event(from_upstream),
+ njs_vm_post_event(ctx->vm, event->ev,
njs_value_arg(&ctx->args[1]), 2);
rc = njs_vm_run(ctx->vm);
@@ -729,9 +753,9 @@ ngx_stream_js_drop_events(ngx_stream_js_
ngx_uint_t i;
for (i = 0; i < NGX_JS_EVENT_MAX; i++) {
- if (ctx->events[i] != NULL) {
- njs_vm_del_event(ctx->vm, ctx->events[i]);
- ctx->events[i] = NULL;
+ if (ctx->events[i].ev != NULL) {
+ njs_vm_del_event(ctx->vm, ctx->events[i].ev);
+ ctx->events[i].ev = NULL;
}
}
}
@@ -762,7 +786,8 @@ ngx_stream_js_cleanup_vm(void *data)
static njs_int_t
-ngx_stream_js_buffer_arg(ngx_stream_session_t *s, njs_value_t *buffer)
+ngx_stream_js_buffer_arg(ngx_stream_session_t *s, njs_value_t *buffer,
+ ngx_uint_t data_type)
{
size_t len;
u_char *p;
@@ -777,8 +802,9 @@ ngx_stream_js_buffer_arg(ngx_stream_sess
len = b ? b->last - b->pos : 0;
- p = njs_vm_value_string_alloc(ctx->vm, buffer, len);
+ p = ngx_pnalloc(c->pool, len);
if (p == NULL) {
+ njs_vm_memory_error(ctx->vm);
return NJS_ERROR;
}
@@ -786,11 +812,10 @@ ngx_stream_js_buffer_arg(ngx_stream_sess
ngx_memcpy(p, b->pos, len);
}
- return NJS_OK;
+ return ngx_js_prop(ctx->vm, data_type, buffer, p, len);
}
-
static njs_int_t
ngx_stream_js_flags_arg(ngx_stream_session_t *s, njs_value_t *flags)
{
@@ -821,12 +846,37 @@ ngx_stream_js_flags_arg(ngx_stream_sessi
static njs_vm_event_t *
ngx_stream_js_event(ngx_stream_session_t *s, njs_str_t *event)
{
- ngx_uint_t i, n;
+ ngx_uint_t i, n, type;
ngx_stream_js_ctx_t *ctx;
- static const njs_str_t events[] = {
- njs_str("upload"),
- njs_str("download")
+ static const struct {
+ ngx_str_t name;
+ ngx_uint_t data_type;
+ ngx_uint_t id;
+ } events[] = {
+ {
+ ngx_string("upload"),
+ NGX_JS_STRING,
+ NGX_JS_EVENT_UPLOAD,
+ },
+
+ {
+ ngx_string("download"),
+ NGX_JS_STRING,
+ NGX_JS_EVENT_DOWNLOAD,
+ },
+
+ {
+ ngx_string("upstream"),
+ NGX_JS_BUFFER,
+ NGX_JS_EVENT_UPLOAD,
+ },
+
+ {
+ ngx_string("downstream"),
+ NGX_JS_BUFFER,
+ NGX_JS_EVENT_DOWNLOAD,
+ },
};
ctx = ngx_stream_get_module_ctx(s, ngx_stream_js_module);
@@ -835,8 +885,9 @@ ngx_stream_js_event(ngx_stream_session_t
n = sizeof(events) / sizeof(events[0]);
while (i < n) {
- if (event->length == events[i].length
- && ngx_memcmp(event->start, events[i].start, event->length) == 0)
+ if (event->length == events[i].name.len
+ && ngx_memcmp(event->start, events[i].name.data, event->length)
+ == 0)
{
break;
}
@@ -849,11 +900,18 @@ ngx_stream_js_event(ngx_stream_session_t
return NULL;
}
- if (i == 0) {
- return &ctx->events[NGX_JS_EVENT_UPLOAD];
+ ctx->events[events[i].id].data_type = events[i].data_type;
+
+ for (n = 0; n < NGX_JS_EVENT_MAX; n++) {
+ type = ctx->events[n].data_type;
+ if (type != NGX_JS_UNSET && type != events[i].data_type) {
+ njs_vm_error(ctx->vm, "mixing string and buffer events"
+ " is not allowed");
+ return NULL;
+ }
}
- return &ctx->events[NGX_JS_EVENT_DOWNLOAD];
+ return &ctx->events[events[i].id].ev;
}
@@ -1131,7 +1189,8 @@ ngx_stream_js_ext_variables(njs_vm_t *vm
return NJS_DECLINED;
}
- return njs_vm_value_string_set(vm, retval, vv->data, vv->len);
+ return ngx_js_prop(vm, njs_vm_prop_magic32(prop), retval, vv->data,
+ vv->len);
}
cmcf = ngx_stream_get_module_main_conf(s, ngx_stream_core_module);
diff -r 0684301385d9 -r 434f20c29f4c src/njs.h
--- a/src/njs.h Wed Nov 25 10:47:25 2020 +0000
+++ b/src/njs.h Wed Nov 25 10:47:47 2020 +0000
@@ -144,6 +144,7 @@ struct njs_external_s {
unsigned configurable;
unsigned enumerable;
njs_prop_handler_t prop_handler;
+ uint32_t magic32;
njs_exotic_keys_t keys;
} object;
} u;
@@ -389,6 +390,7 @@ NJS_EXPORT njs_int_t njs_value_is_string
NJS_EXPORT njs_int_t njs_value_is_object(const njs_value_t *value);
NJS_EXPORT njs_int_t njs_value_is_array(const njs_value_t *value);
NJS_EXPORT njs_int_t njs_value_is_function(const njs_value_t *value);
+NJS_EXPORT njs_int_t njs_value_is_buffer(const njs_value_t *value);
NJS_EXPORT njs_int_t njs_vm_object_alloc(njs_vm_t *vm, njs_value_t *retval,
...);
diff -r 0684301385d9 -r 434f20c29f4c src/njs_extern.c
--- a/src/njs_extern.c Wed Nov 25 10:47:25 2020 +0000
+++ b/src/njs_extern.c Wed Nov 25 10:47:47 2020 +0000
@@ -132,6 +132,7 @@ njs_external_add(njs_vm_t *vm, njs_arr_t
next->configurable = external->u.object.configurable;
next->enumerable = external->u.object.enumerable;
next->prop_handler = external->u.object.prop_handler;
+ next->magic32 = external->u.object.magic32;
next->keys = external->u.object.keys;
break;
diff -r 0684301385d9 -r 434f20c29f4c src/njs_value.c
--- a/src/njs_value.c Wed Nov 25 10:47:25 2020 +0000
+++ b/src/njs_value.c Wed Nov 25 10:47:47 2020 +0000
@@ -492,6 +492,13 @@ njs_value_is_function(const njs_value_t
}
+njs_int_t
+njs_value_is_buffer(const njs_value_t *value)
+{
+ return njs_is_typed_array(value);
+}
+
+
/*
* ES5.1, 8.12.1: [[GetOwnProperty]], [[GetProperty]].
* The njs_property_query() returns values
@@ -932,6 +939,7 @@ njs_external_property_query(njs_vm_t *vm
* njs_set_null(&prop->setter);
*/
+ prop->value.data.magic32 = slots->magic32;
prop->name = pq->key;
pq->lhq.value = prop;
diff -r 0684301385d9 -r 434f20c29f4c src/njs_value.h
--- a/src/njs_value.h Wed Nov 25 10:47:25 2020 +0000
+++ b/src/njs_value.h Wed Nov 25 10:47:47 2020 +0000
@@ -189,6 +189,7 @@ union njs_value_s {
typedef struct {
/* Get, also Set if writable, also Delete if configurable. */
njs_prop_handler_t prop_handler;
+ uint32_t magic32;
unsigned writable:1;
unsigned configurable:1;
unsigned enumerable:1;
More information about the nginx-devel
mailing list