summaryrefslogtreecommitdiffhomepage
path: root/src/nxt_js.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nxt_js.c')
-rw-r--r--src/nxt_js.c299
1 files changed, 299 insertions, 0 deletions
diff --git a/src/nxt_js.c b/src/nxt_js.c
new file mode 100644
index 00000000..aa3c4af5
--- /dev/null
+++ b/src/nxt_js.c
@@ -0,0 +1,299 @@
+
+/*
+ * Copyright (C) NGINX, Inc.
+ */
+
+#include <nxt_main.h>
+
+
+struct nxt_js_s {
+ uint32_t index;
+ njs_vm_t *vm;
+};
+
+
+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)
+{
+ njs_vm_opt_t opts;
+ nxt_js_conf_t *jcf;
+
+ jcf = nxt_mp_zget(mp, sizeof(nxt_js_conf_t));
+ if (nxt_slow_path(jcf == NULL)) {
+ return NULL;
+ }
+
+ jcf->pool = mp;
+
+ njs_vm_opt_init(&opts);
+
+ jcf->vm = njs_vm_create(&opts);
+ if (nxt_slow_path(jcf->vm == NULL)) {
+ return NULL;
+ }
+
+ jcf->funcs = nxt_array_create(mp, 4, sizeof(nxt_str_t));
+ if (nxt_slow_path(jcf->funcs == NULL)) {
+ return NULL;
+ }
+
+ return jcf;
+}
+
+
+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)
+{
+ size_t size;
+ u_char *p, *start;
+ nxt_js_t *js;
+ nxt_str_t *func;
+
+ static nxt_str_t func_str = nxt_string("function(uri, host, remoteAddr, "
+ "args, headers, cookies) {"
+ " return ");
+
+ /*
+ * Appending a terminating null character if strz is true.
+ */
+ static nxt_str_t strz_str = nxt_string(" + '\\x00'");
+
+ size = func_str.length + str->length + 1;
+
+ if (strz) {
+ size += strz_str.length;
+ }
+
+ start = nxt_mp_nget(jcf->pool, size);
+ if (nxt_slow_path(start == NULL)) {
+ return NULL;
+ }
+
+ p = start;
+
+ p = nxt_cpymem(p, func_str.start, func_str.length);
+ p = nxt_cpymem(p, str->start, str->length);
+
+ if (strz) {
+ p = nxt_cpymem(p, strz_str.start, strz_str.length);
+ }
+
+ *p++ = '}';
+
+ js = nxt_mp_get(jcf->pool, sizeof(nxt_js_t));
+ if (nxt_slow_path(js == NULL)) {
+ return NULL;
+ }
+
+ js->vm = jcf->vm;
+
+ func = nxt_array_add(jcf->funcs);
+ if (nxt_slow_path(func == NULL)) {
+ return NULL;
+ }
+
+ func->start = start;
+ func->length = p - start;
+
+ js->index = jcf->funcs->nelts - 1;
+
+ return js;
+}
+
+
+nxt_int_t
+nxt_js_compile(nxt_js_conf_t *jcf)
+{
+ size_t size;
+ u_char *p, *start;
+ njs_int_t ret;
+ nxt_str_t *func;
+ nxt_uint_t i;
+
+ size = 2;
+ func = jcf->funcs->elts;
+
+ for (i = 0; i < jcf->funcs->nelts; i++) {
+ size += func[i].length + 1;
+ }
+
+ start = nxt_mp_nget(jcf->pool, size);
+ if (nxt_slow_path(start == NULL)) {
+ return NXT_ERROR;
+ }
+
+ p = start;
+ *p++ = '[';
+
+ func = jcf->funcs->elts;
+
+ for (i = 0; i < jcf->funcs->nelts; i++) {
+ p = nxt_cpymem(p, func[i].start, func[i].length);
+ *p++ = ',';
+ }
+
+ *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;
+}
+
+
+nxt_int_t
+nxt_js_test(nxt_js_conf_t *jcf, nxt_str_t *str, u_char *error)
+{
+ u_char *start;
+ nxt_str_t err;
+ njs_int_t ret;
+ njs_str_t res;
+
+ start = nxt_mp_nget(jcf->pool, str->length);
+ if (nxt_slow_path(start == NULL)) {
+ return NXT_ERROR;
+ }
+
+ nxt_memcpy(start, str->start, str->length);
+
+ ret = njs_vm_compile(jcf->vm, &start, start + str->length);
+
+ if (nxt_slow_path(ret != NJS_OK)) {
+ (void) njs_vm_retval_string(jcf->vm, &res);
+
+ err.start = res.start;
+ err.length = res.length;
+
+ nxt_sprintf(error, error + NXT_MAX_ERROR_STR, "\"%V\"%Z", &err);
+
+ return NXT_ERROR;
+ }
+
+ return NXT_OK;
+}
+
+
+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)
+{
+ njs_vm_t *vm;
+ njs_int_t rc, ret;
+ njs_str_t res;
+ njs_value_t *array, *value;
+ njs_function_t *func;
+ 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;
+
+ if (vm == NULL) {
+ vm = njs_vm_clone(js->vm, ctx);
+ if (nxt_slow_path(vm == NULL)) {
+ return NXT_ERROR;
+ }
+
+ ret = njs_vm_start(vm);
+ if (ret != NJS_OK) {
+ return NXT_ERROR;
+ }
+
+ array = njs_vm_retval(vm);
+
+ cache->vm = vm;
+ cache->array = *array;
+ }
+
+ value = njs_vm_array_prop(vm, &cache->array, js->index, &opaque_value);
+ func = njs_value_function(value);
+
+ 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) {
+ return NXT_ERROR;
+ }
+
+ if (ret != NJS_OK) {
+ nxt_alert(task, "js exception: %V", &res);
+ return NXT_ERROR;
+ }
+
+ str->length = res.length;
+ str->start = res.start;
+
+ return NXT_OK;
+}