diff options
-rw-r--r-- | auto/sources | 2 | ||||
-rw-r--r-- | src/nxt_http_js.c | 273 | ||||
-rw-r--r-- | src/nxt_js.c | 75 | ||||
-rw-r--r-- | src/nxt_js.h | 4 | ||||
-rw-r--r-- | src/nxt_router.c | 4 | ||||
-rw-r--r-- | src/nxt_runtime.h | 3 | ||||
-rw-r--r-- | src/nxt_var.h | 2 |
7 files changed, 359 insertions, 4 deletions
diff --git a/auto/sources b/auto/sources index 9f9a27f7..cebced3a 100644 --- a/auto/sources +++ b/auto/sources @@ -136,7 +136,7 @@ NXT_LIB_PCRE_SRCS="src/nxt_pcre.c" NXT_LIB_PCRE2_SRCS="src/nxt_pcre2.c" if [ "$NXT_NJS" != "NO" ]; then - NXT_LIB_SRCS="$NXT_LIB_SRCS src/nxt_js.c" + NXT_LIB_SRCS="$NXT_LIB_SRCS src/nxt_js.c src/nxt_http_js.c" fi NXT_LIB_EPOLL_SRCS="src/nxt_epoll_engine.c" diff --git a/src/nxt_http_js.c b/src/nxt_http_js.c new file mode 100644 index 00000000..5a08a309 --- /dev/null +++ b/src/nxt_http_js.c @@ -0,0 +1,273 @@ + +/* + * Copyright (C) NGINX, Inc. + */ + +#include <nxt_router.h> +#include <nxt_http.h> +#include <njs.h> + + +static njs_int_t nxt_http_js_ext_uri(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 nxt_http_js_ext_host(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 nxt_http_js_ext_remote_addr(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 nxt_http_js_ext_get_arg(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 nxt_http_js_ext_get_header(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 nxt_http_js_ext_get_cookie(njs_vm_t *vm, + njs_object_prop_t *prop, njs_value_t *value, njs_value_t *setval, + njs_value_t *retval); + + +static njs_external_t nxt_http_js_proto[] = { + { + .flags = NJS_EXTERN_PROPERTY, + .name.string = njs_str("uri"), + .enumerable = 1, + .u.property = { + .handler = nxt_http_js_ext_uri, + } + }, + + { + .flags = NJS_EXTERN_PROPERTY, + .name.string = njs_str("host"), + .enumerable = 1, + .u.property = { + .handler = nxt_http_js_ext_host, + } + }, + + { + .flags = NJS_EXTERN_PROPERTY, + .name.string = njs_str("remoteAddr"), + .enumerable = 1, + .u.property = { + .handler = nxt_http_js_ext_remote_addr, + } + }, + + { + .flags = NJS_EXTERN_OBJECT, + .name.string = njs_str("args"), + .enumerable = 1, + .u.object = { + .enumerable = 1, + .prop_handler = nxt_http_js_ext_get_arg, + } + }, + + { + .flags = NJS_EXTERN_OBJECT, + .name.string = njs_str("headers"), + .enumerable = 1, + .u.object = { + .enumerable = 1, + .prop_handler = nxt_http_js_ext_get_header, + } + }, + + { + .flags = NJS_EXTERN_OBJECT, + .name.string = njs_str("cookies"), + .enumerable = 1, + .u.object = { + .enumerable = 1, + .prop_handler = nxt_http_js_ext_get_cookie, + } + }, +}; + + +void +nxt_http_register_js_proto(nxt_js_conf_t *jcf) +{ + nxt_js_set_proto(jcf, nxt_http_js_proto, njs_nitems(nxt_http_js_proto)); +} + + +static njs_int_t +nxt_http_js_ext_uri(njs_vm_t *vm, njs_object_prop_t *prop, + njs_value_t *value, njs_value_t *setval, njs_value_t *retval) +{ + nxt_http_request_t *r; + + r = njs_vm_external(vm, nxt_js_proto_id, value); + if (r == NULL) { + njs_value_undefined_set(retval); + return NJS_DECLINED; + } + + return njs_vm_value_string_set(vm, retval, r->path->start, r->path->length); +} + + +static njs_int_t +nxt_http_js_ext_host(njs_vm_t *vm, njs_object_prop_t *prop, + njs_value_t *value, njs_value_t *setval, njs_value_t *retval) +{ + nxt_http_request_t *r; + + r = njs_vm_external(vm, nxt_js_proto_id, value); + if (r == NULL) { + njs_value_undefined_set(retval); + return NJS_DECLINED; + } + + return njs_vm_value_string_set(vm, retval, r->host.start, r->host.length); +} + + +static njs_int_t +nxt_http_js_ext_remote_addr(njs_vm_t *vm, njs_object_prop_t *prop, + njs_value_t *value, njs_value_t *setval, njs_value_t *retval) +{ + nxt_http_request_t *r; + + r = njs_vm_external(vm, nxt_js_proto_id, value); + if (r == NULL) { + njs_value_undefined_set(retval); + return NJS_DECLINED; + } + + return njs_vm_value_string_set(vm, retval, + nxt_sockaddr_address(r->remote), + r->remote->address_length); +} + + +static njs_int_t +nxt_http_js_ext_get_arg(njs_vm_t *vm, njs_object_prop_t *prop, + njs_value_t *value, njs_value_t *setval, njs_value_t *retval) +{ + njs_int_t rc; + njs_str_t key; + nxt_array_t *args; + nxt_http_request_t *r; + nxt_http_name_value_t *nv, *start, *end; + + r = njs_vm_external(vm, nxt_js_proto_id, value); + if (r == NULL) { + njs_value_undefined_set(retval); + return NJS_DECLINED; + } + + rc = njs_vm_prop_name(vm, prop, &key); + if (rc != NJS_OK) { + njs_value_undefined_set(retval); + return NJS_DECLINED; + } + + args = nxt_http_arguments_parse(r); + if (nxt_slow_path(args == NULL)) { + return NJS_ERROR; + } + + start = args->elts; + end = start + args->nelts; + + for (nv = start; nv < end; nv++) { + + if (key.length == nv->name_length + && memcmp(key.start, nv->name, nv->name_length) == 0) + { + return njs_vm_value_string_set(vm, retval, nv->value, + nv->value_length); + } + } + + njs_value_undefined_set(retval); + + return NJS_DECLINED; +} + + +static njs_int_t +nxt_http_js_ext_get_header(njs_vm_t *vm, njs_object_prop_t *prop, + njs_value_t *value, njs_value_t *setval, njs_value_t *retval) +{ + njs_int_t rc; + njs_str_t key; + nxt_http_field_t *f; + nxt_http_request_t *r; + + r = njs_vm_external(vm, nxt_js_proto_id, value); + if (r == NULL) { + njs_value_undefined_set(retval); + return NJS_DECLINED; + } + + rc = njs_vm_prop_name(vm, prop, &key); + if (rc != NJS_OK) { + njs_value_undefined_set(retval); + return NJS_DECLINED; + } + + nxt_list_each(f, r->fields) { + + if (key.length == f->name_length + && memcmp(key.start, f->name, f->name_length) == 0) + { + return njs_vm_value_string_set(vm, retval, f->value, + f->value_length); + } + + } nxt_list_loop; + + njs_value_undefined_set(retval); + + return NJS_DECLINED; +} + + +static njs_int_t +nxt_http_js_ext_get_cookie(njs_vm_t *vm, njs_object_prop_t *prop, + njs_value_t *value, njs_value_t *setval, njs_value_t *retval) +{ + njs_int_t rc; + njs_str_t key; + nxt_array_t *cookies; + nxt_http_request_t *r; + nxt_http_name_value_t *nv, *start, *end; + + r = njs_vm_external(vm, nxt_js_proto_id, value); + if (r == NULL) { + njs_value_undefined_set(retval); + return NJS_DECLINED; + } + + rc = njs_vm_prop_name(vm, prop, &key); + if (rc != NJS_OK) { + njs_value_undefined_set(retval); + return NJS_DECLINED; + } + + cookies = nxt_http_cookies_parse(r); + if (nxt_slow_path(cookies == NULL)) { + return NJS_ERROR; + } + + start = cookies->elts; + end = start + cookies->nelts; + + for (nv = start; nv < end; nv++) { + + if (key.length == nv->name_length + && memcmp(key.start, nv->name, nv->name_length) == 0) + { + return njs_vm_value_string_set(vm, retval, nv->value, + nv->value_length); + } + } + + njs_value_undefined_set(retval); + + return NJS_DECLINED; +} diff --git a/src/nxt_js.c b/src/nxt_js.c index 52596fe6..aa3c4af5 100644 --- a/src/nxt_js.c +++ b/src/nxt_js.c @@ -15,10 +15,15 @@ struct nxt_js_s { struct nxt_js_conf_s { nxt_mp_t *pool; njs_vm_t *vm; + njs_uint_t protos; + njs_external_t *proto; nxt_array_t *funcs; }; +njs_int_t nxt_js_proto_id; + + nxt_js_conf_t * nxt_js_conf_new(nxt_mp_t *mp) { @@ -48,6 +53,14 @@ nxt_js_conf_new(nxt_mp_t *mp) } +void +nxt_js_set_proto(nxt_js_conf_t *jcf, njs_external_t *proto, njs_uint_t n) +{ + jcf->protos = n; + jcf->proto = proto; +} + + nxt_js_t * nxt_js_add_tpl(nxt_js_conf_t *jcf, nxt_str_t *str, nxt_bool_t strz) { @@ -56,7 +69,8 @@ nxt_js_add_tpl(nxt_js_conf_t *jcf, nxt_str_t *str, nxt_bool_t strz) nxt_js_t *js; nxt_str_t *func; - static nxt_str_t func_str = nxt_string("function() {" + static nxt_str_t func_str = nxt_string("function(uri, host, remoteAddr, " + "args, headers, cookies) {" " return "); /* @@ -140,6 +154,12 @@ nxt_js_compile(nxt_js_conf_t *jcf) *p++ = ']'; + nxt_js_proto_id = njs_vm_external_prototype(jcf->vm, jcf->proto, + jcf->protos); + if (nxt_slow_path(nxt_js_proto_id < 0)) { + return NXT_ERROR; + } + ret = njs_vm_compile(jcf->vm, &start, p); return (ret == NJS_OK) ? NXT_OK : NXT_ERROR; @@ -187,7 +207,14 @@ nxt_js_call(nxt_task_t *task, nxt_js_cache_t *cache, nxt_js_t *js, njs_str_t res; njs_value_t *array, *value; njs_function_t *func; - njs_opaque_value_t opaque_value; + njs_opaque_value_t opaque_value, arguments[6]; + + static const njs_str_t uri_str = njs_str("uri"); + static const njs_str_t host_str = njs_str("host"); + static const njs_str_t remote_addr_str = njs_str("remoteAddr"); + static const njs_str_t args_str = njs_str("args"); + static const njs_str_t headers_str = njs_str("headers"); + static const njs_str_t cookies_str = njs_str("cookies"); vm = cache->vm; @@ -211,7 +238,49 @@ nxt_js_call(nxt_task_t *task, nxt_js_cache_t *cache, nxt_js_t *js, value = njs_vm_array_prop(vm, &cache->array, js->index, &opaque_value); func = njs_value_function(value); - ret = njs_vm_call(vm, func, NULL, 0); + ret = njs_vm_external_create(vm, njs_value_arg(&opaque_value), + nxt_js_proto_id, ctx, 0); + if (nxt_slow_path(ret != NJS_OK)) { + return NXT_ERROR; + } + + value = njs_vm_object_prop(vm, njs_value_arg(&opaque_value), &uri_str, + &arguments[0]); + if (nxt_slow_path(value == NULL)) { + return NXT_ERROR; + } + + value = njs_vm_object_prop(vm, njs_value_arg(&opaque_value), &host_str, + &arguments[1]); + if (nxt_slow_path(value == NULL)) { + return NXT_ERROR; + } + + value = njs_vm_object_prop(vm, njs_value_arg(&opaque_value), + &remote_addr_str, &arguments[2]); + if (nxt_slow_path(value == NULL)) { + return NXT_ERROR; + } + + value = njs_vm_object_prop(vm, njs_value_arg(&opaque_value), &args_str, + &arguments[3]); + if (nxt_slow_path(value == NULL)) { + return NXT_ERROR; + } + + value = njs_vm_object_prop(vm, njs_value_arg(&opaque_value), &headers_str, + &arguments[4]); + if (nxt_slow_path(value == NULL)) { + return NXT_ERROR; + } + + value = njs_vm_object_prop(vm, njs_value_arg(&opaque_value), &cookies_str, + &arguments[5]); + if (nxt_slow_path(value == NULL)) { + return NXT_ERROR; + } + + ret = njs_vm_call(vm, func, njs_value_arg(&arguments), 6); rc = njs_vm_retval_string(vm, &res); if (rc != NJS_OK) { diff --git a/src/nxt_js.h b/src/nxt_js.h index 321041ae..dea43fe3 100644 --- a/src/nxt_js.h +++ b/src/nxt_js.h @@ -22,6 +22,7 @@ typedef struct { nxt_js_conf_t *nxt_js_conf_new(nxt_mp_t *mp); +void nxt_js_set_proto(nxt_js_conf_t *jcf, njs_external_t *proto, nxt_uint_t n); nxt_js_t *nxt_js_add_tpl(nxt_js_conf_t *jcf, nxt_str_t *str, nxt_bool_t strz); nxt_int_t nxt_js_compile(nxt_js_conf_t *jcf); nxt_int_t nxt_js_test(nxt_js_conf_t *jcf, nxt_str_t *str, u_char *error); @@ -29,6 +30,9 @@ nxt_int_t nxt_js_call(nxt_task_t *task, nxt_js_cache_t *cache, nxt_js_t *js, nxt_str_t *str, void *ctx); +extern njs_int_t nxt_js_proto_id; + + #endif /* NXT_HAVE_NJS */ #endif /* _NXT_JS_H_INCLUDED_ */ diff --git a/src/nxt_router.c b/src/nxt_router.c index 26aa9fb1..edc015c5 100644 --- a/src/nxt_router.c +++ b/src/nxt_router.c @@ -1065,6 +1065,10 @@ nxt_router_temp_conf(nxt_task_t *task) goto fail; } +#if (NXT_HAVE_NJS) + nxt_http_register_js_proto(rtcf->tstr_state->jcf); +#endif + tmp = nxt_mp_create(1024, 128, 256, 32); if (nxt_slow_path(tmp == NULL)) { goto fail; diff --git a/src/nxt_runtime.h b/src/nxt_runtime.h index d7fe2f38..687914f0 100644 --- a/src/nxt_runtime.h +++ b/src/nxt_runtime.h @@ -138,6 +138,9 @@ void nxt_cdecl nxt_log_time_handler(nxt_uint_t level, nxt_log_t *log, void nxt_stream_connection_init(nxt_task_t *task, void *obj, void *data); nxt_int_t nxt_http_register_variables(void); +#if (NXT_HAVE_NJS) +void nxt_http_register_js_proto(nxt_js_conf_t *jcf); +#endif #define nxt_runtime_process_each(rt, process) \ diff --git a/src/nxt_var.h b/src/nxt_var.h index 4f30a002..ab25800d 100644 --- a/src/nxt_var.h +++ b/src/nxt_var.h @@ -49,6 +49,8 @@ nxt_int_t nxt_var_test(nxt_str_t *str, nxt_array_t *fields, u_char *error); nxt_int_t nxt_var_interpreter(nxt_task_t *task, nxt_var_cache_t *cache, nxt_var_t *var, nxt_str_t *str, void *ctx, nxt_bool_t logging); +nxt_str_t *nxt_var_get(nxt_task_t *task, nxt_var_cache_t *cache, + nxt_str_t *name, void *ctx); #endif /* _NXT_VAR_H_INCLUDED_ */ |