NJS: added http request prototype.

This commit is contained in:
Zhidao HONG
2022-11-22 10:13:18 +08:00
parent 4d6d146e92
commit e3bbf5b3b5
7 changed files with 359 additions and 4 deletions

273
src/nxt_http_js.c Normal file
View File

@@ -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;
}

View File

@@ -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) {

View File

@@ -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_ */

View File

@@ -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;

View File

@@ -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) \

View File

@@ -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_ */