summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--auto/sources2
-rw-r--r--src/nxt_http_js.c273
-rw-r--r--src/nxt_js.c75
-rw-r--r--src/nxt_js.h4
-rw-r--r--src/nxt_router.c4
-rw-r--r--src/nxt_runtime.h3
-rw-r--r--src/nxt_var.h2
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_ */