Basic variables support.
This commit is contained in:
@@ -31,6 +31,7 @@ NXT_LIB_SRCS=" \
|
||||
src/nxt_utf8.c \
|
||||
src/nxt_parse.c \
|
||||
src/nxt_sprintf.c \
|
||||
src/nxt_var.c \
|
||||
src/nxt_file_name.c \
|
||||
src/nxt_log.c \
|
||||
src/nxt_djb_hash.c \
|
||||
@@ -91,6 +92,7 @@ NXT_LIB_SRCS=" \
|
||||
src/nxt_http_static.c \
|
||||
src/nxt_http_proxy.c \
|
||||
src/nxt_http_chunk_parse.c \
|
||||
src/nxt_http_variables.c \
|
||||
src/nxt_application.c \
|
||||
src/nxt_external.c \
|
||||
src/nxt_port_hash.c \
|
||||
|
||||
@@ -51,7 +51,7 @@ nxt_array_add(nxt_array_t *array)
|
||||
|
||||
if (nalloc < 16) {
|
||||
/* Allocate new array twice larger than current. */
|
||||
new_alloc = nalloc * 2;
|
||||
new_alloc = (nalloc == 0) ? 4 : nalloc * 2;
|
||||
|
||||
} else {
|
||||
/* Allocate new array 1.5 times larger than current. */
|
||||
|
||||
@@ -18,6 +18,14 @@ typedef struct {
|
||||
} nxt_array_t;
|
||||
|
||||
|
||||
nxt_inline void
|
||||
nxt_array_init(nxt_array_t *array, nxt_mp_t *mp, size_t size)
|
||||
{
|
||||
array->elts = nxt_pointer_to(array, sizeof(nxt_array_t));
|
||||
array->size = size;
|
||||
array->mem_pool = mp;
|
||||
}
|
||||
|
||||
NXT_EXPORT nxt_array_t *nxt_array_create(nxt_mp_t *mp, nxt_uint_t n,
|
||||
size_t size);
|
||||
NXT_EXPORT void nxt_array_destroy(nxt_array_t *array);
|
||||
|
||||
@@ -64,6 +64,8 @@ static nxt_int_t nxt_conf_vldt_type(nxt_conf_validation_t *vldt,
|
||||
nxt_str_t *name, nxt_conf_value_t *value, nxt_conf_vldt_type_t type);
|
||||
static nxt_int_t nxt_conf_vldt_error(nxt_conf_validation_t *vldt,
|
||||
const char *fmt, ...);
|
||||
static nxt_int_t nxt_conf_vldt_var(nxt_conf_validation_t *vldt,
|
||||
const char *option, nxt_str_t *value);
|
||||
|
||||
static nxt_int_t nxt_conf_vldt_mtypes(nxt_conf_validation_t *vldt,
|
||||
nxt_conf_value_t *value, void *data);
|
||||
@@ -1065,6 +1067,21 @@ nxt_conf_vldt_error(nxt_conf_validation_t *vldt, const char *fmt, ...)
|
||||
}
|
||||
|
||||
|
||||
static nxt_int_t
|
||||
nxt_conf_vldt_var(nxt_conf_validation_t *vldt, const char *option,
|
||||
nxt_str_t *value)
|
||||
{
|
||||
u_char error[NXT_MAX_ERROR_STR];
|
||||
|
||||
if (nxt_var_test(value, error) != NXT_OK) {
|
||||
return nxt_conf_vldt_error(vldt, "%s in the \"%s\" value.",
|
||||
error, option);
|
||||
}
|
||||
|
||||
return NXT_OK;
|
||||
}
|
||||
|
||||
|
||||
typedef struct {
|
||||
nxt_mp_t *pool;
|
||||
nxt_str_t *type;
|
||||
@@ -1242,6 +1259,10 @@ nxt_conf_vldt_pass(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
|
||||
|
||||
nxt_conf_get_string(value, &pass);
|
||||
|
||||
if (nxt_is_var(&pass)) {
|
||||
return nxt_conf_vldt_var(vldt, "pass", &pass);
|
||||
}
|
||||
|
||||
ret = nxt_http_pass_segments(vldt->pool, &pass, segments, 3);
|
||||
|
||||
if (ret != NXT_OK) {
|
||||
|
||||
@@ -164,6 +164,8 @@ struct nxt_http_request_s {
|
||||
nxt_timer_t timer;
|
||||
void *timer_data;
|
||||
|
||||
nxt_var_query_t *var_query;
|
||||
|
||||
void *req_rpc_data;
|
||||
|
||||
nxt_http_peer_t *peer;
|
||||
@@ -202,6 +204,7 @@ struct nxt_http_action_s {
|
||||
nxt_upstream_t *upstream;
|
||||
uint32_t upstream_number;
|
||||
nxt_http_status_t return_code;
|
||||
nxt_var_t *var;
|
||||
} u;
|
||||
|
||||
nxt_str_t name;
|
||||
@@ -287,15 +290,16 @@ nxt_int_t nxt_http_routes_resolve(nxt_task_t *task,
|
||||
nxt_int_t nxt_http_pass_segments(nxt_mp_t *mp, nxt_str_t *pass,
|
||||
nxt_str_t *segments, nxt_uint_t n);
|
||||
nxt_http_action_t *nxt_http_pass_application(nxt_task_t *task,
|
||||
nxt_router_temp_conf_t *tmcf, nxt_str_t *name);
|
||||
void nxt_http_routes_cleanup(nxt_task_t *task, nxt_http_routes_t *routes);
|
||||
void nxt_http_action_cleanup(nxt_task_t *task, nxt_http_action_t *action);
|
||||
nxt_router_conf_t *rtcf, nxt_str_t *name);
|
||||
|
||||
nxt_int_t nxt_upstreams_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
|
||||
nxt_conf_value_t *conf);
|
||||
nxt_int_t nxt_upstreams_joint_create(nxt_router_temp_conf_t *tmcf,
|
||||
nxt_upstream_t ***upstream_joint);
|
||||
|
||||
void nxt_http_request_action(nxt_task_t *task, nxt_http_request_t *r,
|
||||
nxt_http_action_t *action);
|
||||
|
||||
nxt_http_action_t *nxt_http_return_handler(nxt_task_t *task,
|
||||
nxt_http_request_t *r, nxt_http_action_t *action);
|
||||
|
||||
@@ -309,7 +313,7 @@ nxt_str_t *nxt_http_static_mtypes_hash_find(nxt_lvlhsh_t *hash,
|
||||
|
||||
nxt_http_action_t *nxt_http_application_handler(nxt_task_t *task,
|
||||
nxt_http_request_t *r, nxt_http_action_t *action);
|
||||
void nxt_upstream_find(nxt_upstreams_t *upstreams, nxt_str_t *name,
|
||||
nxt_int_t nxt_upstream_find(nxt_upstreams_t *upstreams, nxt_str_t *name,
|
||||
nxt_http_action_t *action);
|
||||
nxt_http_action_t *nxt_upstream_proxy_handler(nxt_task_t *task,
|
||||
nxt_http_request_t *r, nxt_upstream_t *upstream);
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
static nxt_int_t nxt_http_validate_host(nxt_str_t *host, nxt_mp_t *mp);
|
||||
static void nxt_http_request_start(nxt_task_t *task, void *obj, void *data);
|
||||
static void nxt_http_request_action(nxt_task_t *task, void *obj, void *data);
|
||||
static void nxt_http_request_ready(nxt_task_t *task, void *obj, void *data);
|
||||
static void nxt_http_request_proto_info(nxt_task_t *task,
|
||||
nxt_http_request_t *r);
|
||||
static void nxt_http_request_mem_buf_completion(nxt_task_t *task, void *obj,
|
||||
@@ -285,21 +285,28 @@ nxt_http_request_start(nxt_task_t *task, void *obj, void *data)
|
||||
static const nxt_http_request_state_t nxt_http_request_body_state
|
||||
nxt_aligned(64) =
|
||||
{
|
||||
.ready_handler = nxt_http_request_action,
|
||||
.ready_handler = nxt_http_request_ready,
|
||||
.error_handler = nxt_http_request_close_handler,
|
||||
};
|
||||
|
||||
|
||||
static void
|
||||
nxt_http_request_action(nxt_task_t *task, void *obj, void *data)
|
||||
nxt_http_request_ready(nxt_task_t *task, void *obj, void *data)
|
||||
{
|
||||
nxt_http_action_t *action;
|
||||
nxt_http_request_t *r;
|
||||
|
||||
r = obj;
|
||||
|
||||
action = r->conf->socket_conf->action;
|
||||
|
||||
nxt_http_request_action(task, r, action);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
nxt_http_request_action(nxt_task_t *task, nxt_http_request_t *r,
|
||||
nxt_http_action_t *action)
|
||||
{
|
||||
if (nxt_fast_path(action != NULL)) {
|
||||
|
||||
do {
|
||||
|
||||
@@ -221,9 +221,16 @@ static nxt_int_t nxt_http_route_resolve(nxt_task_t *task,
|
||||
nxt_router_temp_conf_t *tmcf, nxt_http_route_t *route);
|
||||
static nxt_int_t nxt_http_action_resolve(nxt_task_t *task,
|
||||
nxt_router_temp_conf_t *tmcf, nxt_http_action_t *action);
|
||||
static void nxt_http_route_find(nxt_http_routes_t *routes, nxt_str_t *name,
|
||||
static nxt_http_action_t *nxt_http_action_pass_var(nxt_task_t *task,
|
||||
nxt_http_request_t *r, nxt_http_action_t *action);
|
||||
static void nxt_http_action_pass_var_ready(nxt_task_t *task, void *obj,
|
||||
void *data);
|
||||
static void nxt_http_action_pass_var_error(nxt_task_t *task, void *obj,
|
||||
void *data);
|
||||
static nxt_int_t nxt_http_pass_find(nxt_task_t *task, nxt_mp_t *mp,
|
||||
nxt_router_conf_t *rtcf, nxt_http_action_t *action);
|
||||
static nxt_int_t nxt_http_route_find(nxt_http_routes_t *routes, nxt_str_t *name,
|
||||
nxt_http_action_t *action);
|
||||
static void nxt_http_route_cleanup(nxt_task_t *task, nxt_http_route_t *routes);
|
||||
|
||||
static nxt_http_action_t *nxt_http_route_handler(nxt_task_t *task,
|
||||
nxt_http_request_t *r, nxt_http_action_t *start);
|
||||
@@ -1353,10 +1360,8 @@ static nxt_int_t
|
||||
nxt_http_action_resolve(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
|
||||
nxt_http_action_t *action)
|
||||
{
|
||||
nxt_str_t *targets;
|
||||
nxt_var_t *var;
|
||||
nxt_int_t ret;
|
||||
nxt_uint_t i;
|
||||
nxt_str_t segments[3];
|
||||
|
||||
if (action->handler != NULL) {
|
||||
if (action->handler == nxt_http_static_handler
|
||||
@@ -1368,14 +1373,118 @@ nxt_http_action_resolve(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
|
||||
return NXT_OK;
|
||||
}
|
||||
|
||||
ret = nxt_http_pass_segments(tmcf->mem_pool, &action->name, segments, 3);
|
||||
if (nxt_is_var(&action->name)) {
|
||||
var = nxt_var_compile(&action->name, tmcf->router_conf->mem_pool);
|
||||
if (nxt_slow_path(var == NULL)) {
|
||||
return NXT_ERROR;
|
||||
}
|
||||
|
||||
action->u.var = var;
|
||||
action->handler = nxt_http_action_pass_var;
|
||||
return NXT_OK;
|
||||
}
|
||||
|
||||
ret = nxt_http_pass_find(task, tmcf->mem_pool, tmcf->router_conf, action);
|
||||
if (nxt_slow_path(ret != NXT_OK)) {
|
||||
return NXT_ERROR;
|
||||
}
|
||||
|
||||
return NXT_OK;
|
||||
}
|
||||
|
||||
|
||||
static nxt_http_action_t *
|
||||
nxt_http_action_pass_var(nxt_task_t *task, nxt_http_request_t *r,
|
||||
nxt_http_action_t *action)
|
||||
{
|
||||
nxt_var_t *var;
|
||||
nxt_int_t ret;
|
||||
|
||||
ret = nxt_var_query_init(&r->var_query, r, r->mem_pool);
|
||||
if (nxt_slow_path(ret != NXT_OK)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
var = action->u.var;
|
||||
|
||||
action = nxt_mp_get(r->mem_pool, sizeof(nxt_http_action_t));
|
||||
if (nxt_slow_path(action == NULL)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
nxt_var_query(task, r->var_query, var, &action->name);
|
||||
nxt_var_query_resolve(task, r->var_query, action,
|
||||
nxt_http_action_pass_var_ready,
|
||||
nxt_http_action_pass_var_error);
|
||||
return NULL;
|
||||
|
||||
fail:
|
||||
|
||||
nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
nxt_http_action_pass_var_ready(nxt_task_t *task, void *obj, void *data)
|
||||
{
|
||||
nxt_int_t ret;
|
||||
nxt_router_conf_t *rtcf;
|
||||
nxt_http_action_t *action;
|
||||
nxt_http_status_t status;
|
||||
nxt_http_request_t *r;
|
||||
|
||||
r = obj;
|
||||
action = data;
|
||||
rtcf = r->conf->socket_conf->router_conf;
|
||||
|
||||
nxt_debug(task, "http pass lookup: %V", &action->name);
|
||||
|
||||
ret = nxt_http_pass_find(task, r->mem_pool, rtcf, action);
|
||||
|
||||
if (ret != NXT_OK) {
|
||||
status = (ret == NXT_DECLINED) ? NXT_HTTP_NOT_FOUND
|
||||
: NXT_HTTP_INTERNAL_SERVER_ERROR;
|
||||
|
||||
nxt_http_request_error(task, r, status);
|
||||
return;
|
||||
}
|
||||
|
||||
nxt_http_request_action(task, r, action);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
nxt_http_action_pass_var_error(nxt_task_t *task, void *obj, void *data)
|
||||
{
|
||||
nxt_http_request_t *r;
|
||||
|
||||
r = obj;
|
||||
|
||||
nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
|
||||
static nxt_int_t
|
||||
nxt_http_pass_find(nxt_task_t *task, nxt_mp_t *mp, nxt_router_conf_t *rtcf,
|
||||
nxt_http_action_t *action)
|
||||
{
|
||||
nxt_str_t *targets;
|
||||
nxt_int_t ret;
|
||||
nxt_uint_t i;
|
||||
nxt_str_t segments[3];
|
||||
|
||||
ret = nxt_http_pass_segments(mp, &action->name, segments, 3);
|
||||
if (nxt_slow_path(ret != NXT_OK)) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (nxt_str_eq(&segments[0], "applications", 12)) {
|
||||
nxt_router_listener_application(tmcf, &segments[1], action);
|
||||
nxt_router_app_use(task, action->u.application, 1);
|
||||
ret = nxt_router_listener_application(rtcf, &segments[1], action);
|
||||
|
||||
if (ret != NXT_OK) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (segments[2].length != 0) {
|
||||
targets = action->u.application->targets;
|
||||
@@ -1388,14 +1497,20 @@ nxt_http_action_resolve(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
|
||||
action->target = 0;
|
||||
}
|
||||
|
||||
} else if (nxt_str_eq(&segments[0], "upstreams", 9)) {
|
||||
nxt_upstream_find(tmcf->router_conf->upstreams, &segments[1], action);
|
||||
|
||||
} else if (nxt_str_eq(&segments[0], "routes", 6)) {
|
||||
nxt_http_route_find(tmcf->router_conf->routes, &segments[1], action);
|
||||
return NXT_OK;
|
||||
}
|
||||
|
||||
return NXT_OK;
|
||||
if (segments[2].length == 0) {
|
||||
if (nxt_str_eq(&segments[0], "upstreams", 9)) {
|
||||
return nxt_upstream_find(rtcf->upstreams, &segments[1], action);
|
||||
}
|
||||
|
||||
if (nxt_str_eq(&segments[0], "routes", 6)) {
|
||||
return nxt_http_route_find(rtcf->routes, &segments[1], action);
|
||||
}
|
||||
}
|
||||
|
||||
return NXT_DECLINED;
|
||||
}
|
||||
|
||||
|
||||
@@ -1451,7 +1566,7 @@ nxt_http_pass_segments(nxt_mp_t *mp, nxt_str_t *pass, nxt_str_t *segments,
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
static nxt_int_t
|
||||
nxt_http_route_find(nxt_http_routes_t *routes, nxt_str_t *name,
|
||||
nxt_http_action_t *action)
|
||||
{
|
||||
@@ -1465,11 +1580,13 @@ nxt_http_route_find(nxt_http_routes_t *routes, nxt_str_t *name,
|
||||
action->u.route = *route;
|
||||
action->handler = nxt_http_route_handler;
|
||||
|
||||
return;
|
||||
return NXT_OK;
|
||||
}
|
||||
|
||||
route++;
|
||||
}
|
||||
|
||||
return NXT_DECLINED;
|
||||
}
|
||||
|
||||
|
||||
@@ -1497,21 +1614,19 @@ nxt_http_action_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
|
||||
/* COMPATIBILITY: listener application. */
|
||||
|
||||
nxt_http_action_t *
|
||||
nxt_http_pass_application(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
|
||||
nxt_http_pass_application(nxt_task_t *task, nxt_router_conf_t *rtcf,
|
||||
nxt_str_t *name)
|
||||
{
|
||||
nxt_http_action_t *action;
|
||||
|
||||
action = nxt_mp_alloc(tmcf->router_conf->mem_pool,
|
||||
sizeof(nxt_http_action_t));
|
||||
action = nxt_mp_alloc(rtcf->mem_pool, sizeof(nxt_http_action_t));
|
||||
if (nxt_slow_path(action == NULL)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
action->name = *name;
|
||||
|
||||
nxt_router_listener_application(tmcf, name, action);
|
||||
nxt_router_app_use(task, action->u.application, 1);
|
||||
(void) nxt_router_listener_application(rtcf, name, action);
|
||||
|
||||
action->target = 0;
|
||||
|
||||
@@ -1519,56 +1634,6 @@ nxt_http_pass_application(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
nxt_http_routes_cleanup(nxt_task_t *task, nxt_http_routes_t *routes)
|
||||
{
|
||||
nxt_http_route_t **route, **end;
|
||||
|
||||
if (routes != NULL) {
|
||||
route = &routes->route[0];
|
||||
end = route + routes->items;
|
||||
|
||||
while (route < end) {
|
||||
nxt_http_route_cleanup(task, *route);
|
||||
|
||||
route++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
nxt_http_route_cleanup(nxt_task_t *task, nxt_http_route_t *route)
|
||||
{
|
||||
nxt_http_route_match_t **match, **end;
|
||||
|
||||
match = &route->match[0];
|
||||
end = match + route->items;
|
||||
|
||||
while (match < end) {
|
||||
nxt_http_action_cleanup(task, &(*match)->action);
|
||||
|
||||
match++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
nxt_http_action_cleanup(nxt_task_t *task, nxt_http_action_t *action)
|
||||
{
|
||||
if (action->handler == nxt_http_application_handler) {
|
||||
nxt_router_app_use(task, action->u.application, -1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (action->handler == nxt_http_static_handler
|
||||
&& action->u.fallback != NULL)
|
||||
{
|
||||
nxt_http_action_cleanup(task, action->u.fallback);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static nxt_http_action_t *
|
||||
nxt_http_route_handler(nxt_task_t *task, nxt_http_request_t *r,
|
||||
nxt_http_action_t *start)
|
||||
|
||||
59
src/nxt_http_variables.c
Normal file
59
src/nxt_http_variables.c
Normal file
@@ -0,0 +1,59 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) NGINX, Inc.
|
||||
*/
|
||||
|
||||
#include <nxt_router.h>
|
||||
#include <nxt_http.h>
|
||||
|
||||
|
||||
static nxt_int_t nxt_http_var_method(nxt_task_t *task, nxt_var_query_t *query,
|
||||
nxt_str_t *str, void *ctx);
|
||||
static nxt_int_t nxt_http_var_uri(nxt_task_t *task, nxt_var_query_t *query,
|
||||
nxt_str_t *str, void *ctx);
|
||||
|
||||
|
||||
static nxt_var_decl_t nxt_http_vars[] = {
|
||||
{ nxt_string("method"),
|
||||
&nxt_http_var_method,
|
||||
0 },
|
||||
|
||||
{ nxt_string("uri"),
|
||||
&nxt_http_var_uri,
|
||||
0 },
|
||||
};
|
||||
|
||||
|
||||
nxt_int_t
|
||||
nxt_http_register_variables(void)
|
||||
{
|
||||
return nxt_var_register(nxt_http_vars, nxt_nitems(nxt_http_vars));
|
||||
}
|
||||
|
||||
|
||||
static nxt_int_t
|
||||
nxt_http_var_method(nxt_task_t *task, nxt_var_query_t *query, nxt_str_t *str,
|
||||
void *ctx)
|
||||
{
|
||||
nxt_http_request_t *r;
|
||||
|
||||
r = ctx;
|
||||
|
||||
*str = *r->method;
|
||||
|
||||
return NXT_OK;
|
||||
}
|
||||
|
||||
|
||||
static nxt_int_t
|
||||
nxt_http_var_uri(nxt_task_t *task, nxt_var_query_t *query, nxt_str_t *str,
|
||||
void *ctx)
|
||||
{
|
||||
nxt_http_request_t *r;
|
||||
|
||||
r = ctx;
|
||||
|
||||
*str = *r->path;
|
||||
|
||||
return NXT_OK;
|
||||
}
|
||||
@@ -66,6 +66,7 @@ typedef uint16_t nxt_port_id_t;
|
||||
|
||||
#include <nxt_sprintf.h>
|
||||
#include <nxt_parse.h>
|
||||
#include <nxt_var.h>
|
||||
|
||||
|
||||
/* TODO: remove unused */
|
||||
|
||||
14
src/nxt_mp.c
14
src/nxt_mp.c
@@ -1059,3 +1059,17 @@ nxt_mp_cleanup(nxt_mp_t *mp, nxt_work_handler_t handler,
|
||||
|
||||
return NXT_OK;
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
nxt_mp_lvlhsh_alloc(void *pool, size_t size)
|
||||
{
|
||||
return nxt_mp_align(pool, size, size);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
nxt_mp_lvlhsh_free(void *pool, void *p)
|
||||
{
|
||||
nxt_mp_free(pool, p);
|
||||
}
|
||||
|
||||
@@ -112,4 +112,8 @@ NXT_EXPORT nxt_int_t nxt_mp_cleanup(nxt_mp_t *mp, nxt_work_handler_t handler,
|
||||
|
||||
NXT_EXPORT void nxt_mp_thread_adopt(nxt_mp_t *mp);
|
||||
|
||||
|
||||
NXT_EXPORT void *nxt_mp_lvlhsh_alloc(void *pool, size_t size);
|
||||
NXT_EXPORT void nxt_mp_lvlhsh_free(void *pool, void *p);
|
||||
|
||||
#endif /* _NXT_MP_H_INCLUDED_ */
|
||||
|
||||
179
src/nxt_router.c
179
src/nxt_router.c
@@ -93,7 +93,16 @@ static nxt_int_t nxt_router_conf_create(nxt_task_t *task,
|
||||
nxt_router_temp_conf_t *tmcf, u_char *start, u_char *end);
|
||||
static nxt_int_t nxt_router_conf_process_static(nxt_task_t *task,
|
||||
nxt_router_conf_t *rtcf, nxt_conf_value_t *conf);
|
||||
|
||||
static nxt_app_t *nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name);
|
||||
static nxt_int_t nxt_router_apps_hash_test(nxt_lvlhsh_query_t *lhq, void *data);
|
||||
static nxt_int_t nxt_router_apps_hash_add(nxt_router_conf_t *rtcf,
|
||||
nxt_app_t *app);
|
||||
static nxt_app_t *nxt_router_apps_hash_get(nxt_router_conf_t *rtcf,
|
||||
nxt_str_t *name);
|
||||
static void nxt_router_apps_hash_use(nxt_task_t *task, nxt_router_conf_t *rtcf,
|
||||
int i);
|
||||
|
||||
static nxt_int_t nxt_router_app_queue_init(nxt_task_t *task,
|
||||
nxt_port_t *port);
|
||||
static nxt_int_t nxt_router_port_queue_init(nxt_task_t *task,
|
||||
@@ -198,6 +207,7 @@ static nxt_int_t nxt_router_app_shared_port_send(nxt_task_t *task,
|
||||
static void nxt_router_app_port_error(nxt_task_t *task,
|
||||
nxt_port_recv_msg_t *msg, void *data);
|
||||
|
||||
static void nxt_router_app_use(nxt_task_t *task, nxt_app_t *app, int i);
|
||||
static void nxt_router_app_unlink(nxt_task_t *task, nxt_app_t *app);
|
||||
|
||||
static void nxt_router_app_port_release(nxt_task_t *task, nxt_port_t *port,
|
||||
@@ -954,6 +964,8 @@ nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data)
|
||||
|
||||
nxt_router_apps_sort(task, router, tmcf);
|
||||
|
||||
nxt_router_apps_hash_use(task, rtcf, 1);
|
||||
|
||||
nxt_router_engines_post(router, tmcf);
|
||||
|
||||
nxt_queue_add(&router->sockets, &updating_sockets);
|
||||
@@ -1012,7 +1024,7 @@ nxt_router_conf_ready(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
|
||||
nxt_debug(task, "rtcf %p: %D", rtcf, count);
|
||||
|
||||
if (count == 0) {
|
||||
nxt_http_routes_cleanup(task, rtcf->routes);
|
||||
nxt_router_apps_hash_use(task, rtcf, -1);
|
||||
|
||||
nxt_router_access_log_release(task, lock, rtcf->access_log);
|
||||
|
||||
@@ -1057,16 +1069,6 @@ nxt_router_conf_error(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
|
||||
|
||||
rtcf = tmcf->router_conf;
|
||||
|
||||
nxt_http_routes_cleanup(task, rtcf->routes);
|
||||
|
||||
nxt_queue_each(skcf, &new_socket_confs, nxt_socket_conf_t, link) {
|
||||
|
||||
if (skcf->action != NULL) {
|
||||
nxt_http_action_cleanup(task, skcf->action);
|
||||
}
|
||||
|
||||
} nxt_queue_loop;
|
||||
|
||||
nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) {
|
||||
|
||||
nxt_router_app_unlink(task, app);
|
||||
@@ -1406,6 +1408,12 @@ nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
|
||||
|
||||
nxt_queue_remove(&prev->link);
|
||||
nxt_queue_insert_tail(&tmcf->previous, &prev->link);
|
||||
|
||||
ret = nxt_router_apps_hash_add(tmcf->router_conf, prev);
|
||||
if (nxt_slow_path(ret != NXT_OK)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1543,6 +1551,11 @@ nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
|
||||
|
||||
nxt_queue_insert_tail(&tmcf->apps, &app->link);
|
||||
|
||||
ret = nxt_router_apps_hash_add(tmcf->router_conf, app);
|
||||
if (nxt_slow_path(ret != NXT_OK)) {
|
||||
goto app_fail;
|
||||
}
|
||||
|
||||
nxt_router_app_use(task, app, 1);
|
||||
|
||||
app->joint = app_joint;
|
||||
@@ -1717,7 +1730,8 @@ nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
|
||||
|
||||
/* COMPATIBILITY: listener application. */
|
||||
} else if (lscf.application.length > 0) {
|
||||
skcf->action = nxt_http_pass_application(task, tmcf,
|
||||
skcf->action = nxt_http_pass_application(task,
|
||||
tmcf->router_conf,
|
||||
&lscf.application);
|
||||
}
|
||||
}
|
||||
@@ -1959,20 +1973,106 @@ nxt_router_port_queue_map(nxt_task_t *task, nxt_port_t *port, nxt_fd_t fd)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
nxt_router_listener_application(nxt_router_temp_conf_t *tmcf, nxt_str_t *name,
|
||||
static const nxt_lvlhsh_proto_t nxt_router_apps_hash_proto nxt_aligned(64) = {
|
||||
NXT_LVLHSH_DEFAULT,
|
||||
nxt_router_apps_hash_test,
|
||||
nxt_mp_lvlhsh_alloc,
|
||||
nxt_mp_lvlhsh_free,
|
||||
};
|
||||
|
||||
|
||||
static nxt_int_t
|
||||
nxt_router_apps_hash_test(nxt_lvlhsh_query_t *lhq, void *data)
|
||||
{
|
||||
nxt_app_t *app;
|
||||
|
||||
app = data;
|
||||
|
||||
return nxt_strstr_eq(&lhq->key, &app->name) ? NXT_OK : NXT_DECLINED;
|
||||
}
|
||||
|
||||
|
||||
static nxt_int_t
|
||||
nxt_router_apps_hash_add(nxt_router_conf_t *rtcf, nxt_app_t *app)
|
||||
{
|
||||
nxt_lvlhsh_query_t lhq;
|
||||
|
||||
lhq.key_hash = nxt_djb_hash(app->name.start, app->name.length);
|
||||
lhq.replace = 0;
|
||||
lhq.key = app->name;
|
||||
lhq.value = app;
|
||||
lhq.proto = &nxt_router_apps_hash_proto;
|
||||
lhq.pool = rtcf->mem_pool;
|
||||
|
||||
switch (nxt_lvlhsh_insert(&rtcf->apps_hash, &lhq)) {
|
||||
|
||||
case NXT_OK:
|
||||
return NXT_OK;
|
||||
|
||||
case NXT_DECLINED:
|
||||
nxt_thread_log_alert("router app hash adding failed: "
|
||||
"\"%V\" is already in hash", &lhq.key);
|
||||
/* Fall through. */
|
||||
default:
|
||||
return NXT_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static nxt_app_t *
|
||||
nxt_router_apps_hash_get(nxt_router_conf_t *rtcf, nxt_str_t *name)
|
||||
{
|
||||
nxt_lvlhsh_query_t lhq;
|
||||
|
||||
lhq.key_hash = nxt_djb_hash(name->start, name->length);
|
||||
lhq.key = *name;
|
||||
lhq.proto = &nxt_router_apps_hash_proto;
|
||||
|
||||
if (nxt_lvlhsh_find(&rtcf->apps_hash, &lhq) != NXT_OK) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return lhq.value;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
nxt_router_apps_hash_use(nxt_task_t *task, nxt_router_conf_t *rtcf, int i)
|
||||
{
|
||||
nxt_app_t *app;
|
||||
nxt_lvlhsh_each_t lhe;
|
||||
|
||||
nxt_lvlhsh_each_init(&lhe, &nxt_router_apps_hash_proto);
|
||||
|
||||
for ( ;; ) {
|
||||
app = nxt_lvlhsh_each(&rtcf->apps_hash, &lhe);
|
||||
|
||||
if (app == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
nxt_router_app_use(task, app, i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
nxt_int_t
|
||||
nxt_router_listener_application(nxt_router_conf_t *rtcf, nxt_str_t *name,
|
||||
nxt_http_action_t *action)
|
||||
{
|
||||
nxt_app_t *app;
|
||||
|
||||
app = nxt_router_app_find(&tmcf->apps, name);
|
||||
app = nxt_router_apps_hash_get(rtcf, name);
|
||||
|
||||
if (app == NULL) {
|
||||
app = nxt_router_app_find(&tmcf->previous, name);
|
||||
return NXT_DECLINED;
|
||||
}
|
||||
|
||||
action->u.application = app;
|
||||
action->handler = nxt_http_application_handler;
|
||||
|
||||
return NXT_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -3201,24 +3301,18 @@ nxt_router_conf_release(nxt_task_t *task, nxt_socket_conf_joint_t *joint)
|
||||
|
||||
nxt_thread_spin_unlock(lock);
|
||||
|
||||
if (skcf != NULL) {
|
||||
if (skcf->action != NULL) {
|
||||
nxt_http_action_cleanup(task, skcf->action);
|
||||
}
|
||||
|
||||
#if (NXT_TLS)
|
||||
if (skcf->tls != NULL) {
|
||||
if (skcf != NULL && skcf->tls != NULL) {
|
||||
task->thread->runtime->tls->server_free(task, skcf->tls);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* TODO remove engine->port */
|
||||
|
||||
if (rtcf != NULL) {
|
||||
nxt_debug(task, "old router conf is destroyed");
|
||||
|
||||
nxt_http_routes_cleanup(task, rtcf->routes);
|
||||
nxt_router_apps_hash_use(task, rtcf, -1);
|
||||
|
||||
nxt_router_access_log_release(task, lock, rtcf->access_log);
|
||||
|
||||
@@ -4126,24 +4220,6 @@ nxt_router_app_port_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
nxt_router_app_use(nxt_task_t *task, nxt_app_t *app, int i)
|
||||
{
|
||||
int c;
|
||||
|
||||
c = nxt_atomic_fetch_add(&app->use_count, i);
|
||||
|
||||
if (i < 0 && c == -i) {
|
||||
|
||||
if (task->thread->engine != app->engine) {
|
||||
nxt_event_engine_post(app->engine, &app->joint->free_app_work);
|
||||
|
||||
} else {
|
||||
nxt_router_free_app(task, app->joint, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
nxt_inline nxt_port_t *
|
||||
nxt_router_app_get_port_for_quit(nxt_task_t *task, nxt_app_t *app)
|
||||
@@ -4183,6 +4259,25 @@ nxt_router_app_get_port_for_quit(nxt_task_t *task, nxt_app_t *app)
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
nxt_router_app_use(nxt_task_t *task, nxt_app_t *app, int i)
|
||||
{
|
||||
int c;
|
||||
|
||||
c = nxt_atomic_fetch_add(&app->use_count, i);
|
||||
|
||||
if (i < 0 && c == -i) {
|
||||
|
||||
if (task->thread->engine != app->engine) {
|
||||
nxt_event_engine_post(app->engine, &app->joint->free_app_work);
|
||||
|
||||
} else {
|
||||
nxt_router_free_app(task, app->joint, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
nxt_router_app_unlink(nxt_task_t *task, nxt_app_t *app)
|
||||
{
|
||||
|
||||
@@ -48,6 +48,7 @@ typedef struct {
|
||||
nxt_upstreams_t *upstreams;
|
||||
|
||||
nxt_lvlhsh_t mtypes_hash;
|
||||
nxt_lvlhsh_t apps_hash;
|
||||
|
||||
nxt_router_access_log_t *access_log;
|
||||
} nxt_router_conf_t;
|
||||
@@ -221,9 +222,8 @@ struct nxt_router_access_log_s {
|
||||
void nxt_router_process_http_request(nxt_task_t *task, nxt_http_request_t *r,
|
||||
nxt_app_t *app);
|
||||
void nxt_router_app_port_close(nxt_task_t *task, nxt_port_t *port);
|
||||
void nxt_router_listener_application(nxt_router_temp_conf_t *tmcf,
|
||||
nxt_int_t nxt_router_listener_application(nxt_router_conf_t *rtcf,
|
||||
nxt_str_t *name, nxt_http_action_t *action);
|
||||
void nxt_router_app_use(nxt_task_t *task, nxt_app_t *app, int i);
|
||||
void nxt_router_listen_event_release(nxt_task_t *task, nxt_listen_event_t *lev,
|
||||
nxt_socket_conf_joint_t *joint);
|
||||
void nxt_router_conf_release(nxt_task_t *task, nxt_socket_conf_joint_t *joint);
|
||||
|
||||
@@ -124,6 +124,14 @@ nxt_runtime_create(nxt_task_t *task)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (nxt_slow_path(nxt_http_register_variables() != NXT_OK)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (nxt_slow_path(nxt_var_index_init() != NXT_OK)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
nxt_work_queue_add(&task->thread->engine->fast_work_queue,
|
||||
nxt_runtime_start, task, rt, NULL);
|
||||
|
||||
|
||||
@@ -135,6 +135,8 @@ 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);
|
||||
|
||||
|
||||
#define nxt_runtime_process_each(rt, process) \
|
||||
do { \
|
||||
|
||||
@@ -71,7 +71,7 @@ nxt_upstreams_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
nxt_int_t
|
||||
nxt_upstream_find(nxt_upstreams_t *upstreams, nxt_str_t *name,
|
||||
nxt_http_action_t *action)
|
||||
{
|
||||
@@ -86,9 +86,11 @@ nxt_upstream_find(nxt_upstreams_t *upstreams, nxt_str_t *name,
|
||||
action->u.upstream_number = i;
|
||||
action->handler = nxt_upstream_handler;
|
||||
|
||||
return;
|
||||
return NXT_DECLINED;
|
||||
}
|
||||
}
|
||||
|
||||
return NXT_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
616
src/nxt_var.c
Normal file
616
src/nxt_var.c
Normal file
@@ -0,0 +1,616 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) NGINX, Inc.
|
||||
*/
|
||||
|
||||
#include <nxt_main.h>
|
||||
|
||||
|
||||
struct nxt_var_s {
|
||||
size_t plain;
|
||||
nxt_uint_t vars;
|
||||
u_char data[];
|
||||
|
||||
/*
|
||||
uint32_t indexes[vars];
|
||||
size_t positions[vars];
|
||||
u_char chars[plain];
|
||||
*/
|
||||
};
|
||||
|
||||
|
||||
typedef struct {
|
||||
nxt_var_t *var;
|
||||
nxt_str_t *value;
|
||||
} nxt_var_value_t;
|
||||
|
||||
|
||||
struct nxt_var_query_s {
|
||||
nxt_array_t values; /* of nxt_var_value_t */
|
||||
nxt_array_t parts; /* of nxt_str_t * */
|
||||
|
||||
nxt_lvlhsh_t cache;
|
||||
|
||||
nxt_str_t *spare;
|
||||
nxt_uint_t waiting;
|
||||
nxt_uint_t failed; /* 1 bit */
|
||||
|
||||
void *ctx;
|
||||
void *data;
|
||||
|
||||
nxt_work_handler_t ready;
|
||||
nxt_work_handler_t error;
|
||||
};
|
||||
|
||||
|
||||
#define nxt_var_indexes(var) ((uint32_t *) (var)->data)
|
||||
|
||||
#define nxt_var_positions(var) \
|
||||
((size_t *) ((var)->data + (var)->vars * sizeof(uint32_t)))
|
||||
|
||||
#define nxt_var_plain_start(var) \
|
||||
((var)->data + (var)->vars * (sizeof(uint32_t) + sizeof(size_t)))
|
||||
|
||||
|
||||
static nxt_int_t nxt_var_hash_test(nxt_lvlhsh_query_t *lhq, void *data);
|
||||
static nxt_var_decl_t *nxt_var_hash_find(nxt_str_t *name);
|
||||
|
||||
static nxt_int_t nxt_var_cache_test(nxt_lvlhsh_query_t *lhq, void *data);
|
||||
static nxt_str_t *nxt_var_cache_find(nxt_lvlhsh_t *lh, uint32_t index);
|
||||
static nxt_int_t nxt_var_cache_add(nxt_lvlhsh_t *lh, uint32_t index,
|
||||
nxt_str_t *value, nxt_mp_t *mp);
|
||||
|
||||
static u_char *nxt_var_next_part(u_char *start, size_t length, nxt_str_t *part,
|
||||
nxt_bool_t *is_var);
|
||||
|
||||
static void nxt_var_query_finish(nxt_task_t *task, nxt_var_query_t *query);
|
||||
|
||||
|
||||
static const nxt_lvlhsh_proto_t nxt_var_hash_proto nxt_aligned(64) = {
|
||||
NXT_LVLHSH_DEFAULT,
|
||||
nxt_var_hash_test,
|
||||
nxt_lvlhsh_alloc,
|
||||
nxt_lvlhsh_free,
|
||||
};
|
||||
|
||||
static const nxt_lvlhsh_proto_t nxt_var_cache_proto nxt_aligned(64) = {
|
||||
NXT_LVLHSH_DEFAULT,
|
||||
nxt_var_cache_test,
|
||||
nxt_mp_lvlhsh_alloc,
|
||||
nxt_mp_lvlhsh_free,
|
||||
};
|
||||
|
||||
|
||||
static nxt_lvlhsh_t nxt_var_hash;
|
||||
static uint32_t nxt_var_count;
|
||||
|
||||
static nxt_var_handler_t *nxt_var_index;
|
||||
|
||||
|
||||
static nxt_int_t
|
||||
nxt_var_hash_test(nxt_lvlhsh_query_t *lhq, void *data)
|
||||
{
|
||||
nxt_var_decl_t *decl;
|
||||
|
||||
decl = data;
|
||||
|
||||
return nxt_strstr_eq(&lhq->key, &decl->name) ? NXT_OK : NXT_DECLINED;
|
||||
}
|
||||
|
||||
|
||||
static nxt_var_decl_t *
|
||||
nxt_var_hash_find(nxt_str_t *name)
|
||||
{
|
||||
nxt_lvlhsh_query_t lhq;
|
||||
|
||||
lhq.key_hash = nxt_djb_hash(name->start, name->length);
|
||||
lhq.key = *name;
|
||||
lhq.proto = &nxt_var_hash_proto;
|
||||
|
||||
if (nxt_lvlhsh_find(&nxt_var_hash, &lhq) != NXT_OK) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return lhq.value;
|
||||
}
|
||||
|
||||
|
||||
static nxt_int_t
|
||||
nxt_var_cache_test(nxt_lvlhsh_query_t *lhq, void *data)
|
||||
{
|
||||
return NXT_OK;
|
||||
}
|
||||
|
||||
|
||||
static nxt_str_t *
|
||||
nxt_var_cache_find(nxt_lvlhsh_t *lh, uint32_t index)
|
||||
{
|
||||
nxt_lvlhsh_query_t lhq;
|
||||
|
||||
lhq.key_hash = nxt_murmur_hash2_uint32(&index);
|
||||
lhq.key.length = sizeof(uint32_t);
|
||||
lhq.key.start = (u_char *) &index;
|
||||
lhq.proto = &nxt_var_cache_proto;
|
||||
|
||||
if (nxt_lvlhsh_find(lh, &lhq) != NXT_OK) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return lhq.value;
|
||||
}
|
||||
|
||||
|
||||
static nxt_int_t
|
||||
nxt_var_cache_add(nxt_lvlhsh_t *lh, uint32_t index, nxt_str_t *value,
|
||||
nxt_mp_t *mp)
|
||||
{
|
||||
nxt_lvlhsh_query_t lhq;
|
||||
|
||||
lhq.key_hash = nxt_murmur_hash2_uint32(&index);
|
||||
lhq.replace = 0;
|
||||
lhq.key.length = sizeof(uint32_t);
|
||||
lhq.key.start = (u_char *) &index;
|
||||
lhq.value = value;
|
||||
lhq.proto = &nxt_var_cache_proto;
|
||||
lhq.pool = mp;
|
||||
|
||||
return nxt_lvlhsh_insert(lh, &lhq);
|
||||
}
|
||||
|
||||
|
||||
nxt_int_t
|
||||
nxt_var_register(nxt_var_decl_t *decl, size_t n)
|
||||
{
|
||||
nxt_uint_t i;
|
||||
nxt_lvlhsh_query_t lhq;
|
||||
|
||||
lhq.replace = 0;
|
||||
lhq.proto = &nxt_var_hash_proto;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
lhq.key = decl[i].name;
|
||||
lhq.key_hash = nxt_djb_hash(lhq.key.start, lhq.key.length);
|
||||
lhq.value = &decl[i];
|
||||
|
||||
if (nxt_slow_path(nxt_lvlhsh_insert(&nxt_var_hash, &lhq) != NXT_OK)) {
|
||||
return NXT_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
nxt_var_count += n;
|
||||
|
||||
return NXT_OK;
|
||||
}
|
||||
|
||||
|
||||
nxt_int_t
|
||||
nxt_var_index_init(void)
|
||||
{
|
||||
nxt_uint_t i;
|
||||
nxt_var_decl_t *decl;
|
||||
nxt_var_handler_t *index;
|
||||
nxt_lvlhsh_each_t lhe;
|
||||
|
||||
index = nxt_memalign(64, nxt_var_count * sizeof(nxt_var_handler_t));
|
||||
if (index == NULL) {
|
||||
return NXT_ERROR;
|
||||
}
|
||||
|
||||
nxt_lvlhsh_each_init(&lhe, &nxt_var_hash_proto);
|
||||
|
||||
for (i = 0; i < nxt_var_count; i++) {
|
||||
decl = nxt_lvlhsh_each(&nxt_var_hash, &lhe);
|
||||
decl->index = i;
|
||||
index[i] = decl->handler;
|
||||
}
|
||||
|
||||
nxt_var_index = index;
|
||||
|
||||
return NXT_OK;
|
||||
}
|
||||
|
||||
|
||||
nxt_var_t *
|
||||
nxt_var_compile(nxt_str_t *str, nxt_mp_t *mp)
|
||||
{
|
||||
u_char *p, *end, *plain_pos;
|
||||
size_t plain, size, *positions;
|
||||
uint32_t *indexes;
|
||||
nxt_var_t *var;
|
||||
nxt_str_t part;
|
||||
nxt_uint_t n;
|
||||
nxt_bool_t is_var;
|
||||
nxt_var_decl_t *decl;
|
||||
|
||||
plain = 0;
|
||||
n = 0;
|
||||
|
||||
p = str->start;
|
||||
end = p + str->length;
|
||||
|
||||
while (p < end) {
|
||||
p = nxt_var_next_part(p, end - p, &part, &is_var);
|
||||
|
||||
if (nxt_slow_path(p == NULL)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (is_var) {
|
||||
n++;
|
||||
|
||||
} else {
|
||||
plain += part.length;
|
||||
}
|
||||
}
|
||||
|
||||
size = sizeof(nxt_var_t)
|
||||
+ n * (sizeof(nxt_var_handler_t) + sizeof (size_t))
|
||||
+ plain;
|
||||
|
||||
var = nxt_mp_get(mp, size);
|
||||
if (nxt_slow_path(var == NULL)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
var->plain = plain;
|
||||
var->vars = n;
|
||||
|
||||
indexes = nxt_var_indexes(var);
|
||||
positions = nxt_var_positions(var);
|
||||
plain_pos = nxt_var_plain_start(var);
|
||||
|
||||
plain = 0;
|
||||
n = 0;
|
||||
|
||||
p = str->start;
|
||||
|
||||
while (p < end) {
|
||||
p = nxt_var_next_part(p, end - p, &part, &is_var);
|
||||
|
||||
if (is_var) {
|
||||
decl = nxt_var_hash_find(&part);
|
||||
|
||||
if (nxt_slow_path(decl == NULL)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
indexes[n] = decl->index;
|
||||
positions[n] = plain;
|
||||
|
||||
n++;
|
||||
|
||||
} else {
|
||||
plain_pos = nxt_cpymem(plain_pos, part.start, part.length);
|
||||
plain += part.length;
|
||||
}
|
||||
}
|
||||
|
||||
return var;
|
||||
}
|
||||
|
||||
|
||||
nxt_int_t
|
||||
nxt_var_test(nxt_str_t *str, u_char *error)
|
||||
{
|
||||
u_char *p, *end, *next;
|
||||
nxt_str_t part;
|
||||
nxt_bool_t is_var;
|
||||
nxt_var_decl_t *decl;
|
||||
|
||||
p = str->start;
|
||||
end = p + str->length;
|
||||
|
||||
while (p < end) {
|
||||
next = nxt_var_next_part(p, end - p, &part, &is_var);
|
||||
|
||||
if (next == NULL) {
|
||||
nxt_sprintf(error, error + NXT_MAX_ERROR_STR,
|
||||
"Invalid variable at position %uz%Z", p - str->start);
|
||||
|
||||
return NXT_ERROR;
|
||||
}
|
||||
|
||||
if (is_var) {
|
||||
decl = nxt_var_hash_find(&part);
|
||||
|
||||
if (decl == NULL) {
|
||||
nxt_sprintf(error, error + NXT_MAX_ERROR_STR,
|
||||
"Unknown variable \"%V\"%Z", &part);
|
||||
|
||||
return NXT_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
p = next;
|
||||
}
|
||||
|
||||
return NXT_OK;
|
||||
}
|
||||
|
||||
|
||||
static u_char *
|
||||
nxt_var_next_part(u_char *start, size_t length, nxt_str_t *part,
|
||||
nxt_bool_t *is_var)
|
||||
{
|
||||
u_char *p, *end, ch, c;
|
||||
nxt_bool_t bracket;
|
||||
|
||||
end = start + length;
|
||||
|
||||
p = nxt_memchr(start, '$', length);
|
||||
|
||||
if (p == start) {
|
||||
*is_var = 1;
|
||||
|
||||
p++;
|
||||
|
||||
if (p == end) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (*p == '{') {
|
||||
bracket = 1;
|
||||
|
||||
if (end - p < 2) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
p++;
|
||||
|
||||
} else {
|
||||
bracket = 0;
|
||||
}
|
||||
|
||||
start = p;
|
||||
|
||||
for ( ;; ) {
|
||||
ch = *p;
|
||||
|
||||
c = (u_char) (ch | 0x20);
|
||||
if ((c < 'a' || c > 'z') && ch != '_') {
|
||||
|
||||
if (bracket && ch != '}') {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
p++;
|
||||
|
||||
if (p == end) {
|
||||
if (bracket) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
length = p - start;
|
||||
end = p + bracket;
|
||||
|
||||
} else {
|
||||
*is_var = 0;
|
||||
|
||||
if (p != NULL) {
|
||||
length = p - start;
|
||||
end = p;
|
||||
}
|
||||
}
|
||||
|
||||
part->length = length;
|
||||
part->start = start;
|
||||
|
||||
return end;
|
||||
}
|
||||
|
||||
|
||||
nxt_int_t
|
||||
nxt_var_query_init(nxt_var_query_t **query_p, void *ctx, nxt_mp_t *mp)
|
||||
{
|
||||
nxt_var_query_t *query;
|
||||
|
||||
query = *query_p;
|
||||
|
||||
if (*query_p == NULL) {
|
||||
query = nxt_mp_zget(mp, sizeof(nxt_var_query_t));
|
||||
if (nxt_slow_path(query == NULL)) {
|
||||
return NXT_ERROR;
|
||||
}
|
||||
|
||||
nxt_array_init(&query->values, mp, sizeof(nxt_var_value_t));
|
||||
nxt_array_init(&query->parts, mp, sizeof(nxt_str_t *));
|
||||
|
||||
} else {
|
||||
nxt_array_reset(&query->values);
|
||||
}
|
||||
|
||||
query->ctx = ctx;
|
||||
|
||||
*query_p = query;
|
||||
|
||||
return NXT_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
nxt_var_query(nxt_task_t *task, nxt_var_query_t *query, nxt_var_t *var,
|
||||
nxt_str_t *str)
|
||||
{
|
||||
uint32_t *indexes;
|
||||
nxt_mp_t *mp;
|
||||
nxt_str_t *value;
|
||||
nxt_int_t ret;
|
||||
nxt_uint_t i;
|
||||
nxt_var_value_t *val;
|
||||
|
||||
if (var->vars == 0) {
|
||||
str->length = var->plain;
|
||||
str->start = nxt_var_plain_start(var);
|
||||
return;
|
||||
}
|
||||
|
||||
if (nxt_slow_path(query->failed)) {
|
||||
return;
|
||||
}
|
||||
|
||||
mp = query->values.mem_pool;
|
||||
indexes = nxt_var_indexes(var);
|
||||
value = query->spare;
|
||||
|
||||
for (i = 0; i < var->vars; i++) {
|
||||
|
||||
if (value == NULL) {
|
||||
value = nxt_mp_zget(mp, sizeof(nxt_str_t));
|
||||
if (nxt_slow_path(value == NULL)) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
ret = nxt_var_cache_add(&query->cache, indexes[i], value, mp);
|
||||
|
||||
if (ret != NXT_OK) {
|
||||
if (nxt_slow_path(ret == NXT_ERROR)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
continue; /* NXT_DECLINED */
|
||||
}
|
||||
|
||||
ret = nxt_var_index[indexes[i]](task, query, value, query->ctx);
|
||||
|
||||
value = NULL;
|
||||
|
||||
if (ret != NXT_OK) {
|
||||
if (nxt_slow_path(ret != NXT_AGAIN)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
query->waiting++;
|
||||
}
|
||||
}
|
||||
|
||||
query->spare = value;
|
||||
|
||||
val = nxt_array_add(&query->values);
|
||||
if (nxt_slow_path(val == NULL)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
val->var = var;
|
||||
val->value = str;
|
||||
|
||||
return;
|
||||
|
||||
fail:
|
||||
|
||||
query->failed = 1;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
nxt_var_query_resolve(nxt_task_t *task, nxt_var_query_t *query, void *data,
|
||||
nxt_work_handler_t ready, nxt_work_handler_t error)
|
||||
{
|
||||
query->data = data;
|
||||
query->ready = ready;
|
||||
query->error = error;
|
||||
|
||||
if (query->waiting == 0) {
|
||||
nxt_var_query_finish(task, query);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
nxt_var_query_handle(nxt_task_t *task, nxt_var_query_t *query,
|
||||
nxt_bool_t failed)
|
||||
{
|
||||
query->failed |= failed;
|
||||
|
||||
if (--query->waiting == 0) {
|
||||
nxt_var_query_finish(task, query);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
nxt_var_query_finish(nxt_task_t *task, nxt_var_query_t *query)
|
||||
{
|
||||
u_char *p, *src;
|
||||
size_t length, plain, next, *positions;
|
||||
uint32_t *indexes;
|
||||
nxt_str_t *str, **part;
|
||||
nxt_var_t *var;
|
||||
nxt_uint_t i, j;
|
||||
nxt_var_value_t *val;
|
||||
|
||||
if (query->failed) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
val = query->values.elts;
|
||||
|
||||
for (i = 0; i < query->values.nelts; i++) {
|
||||
var = val[i].var;
|
||||
|
||||
length = var->plain;
|
||||
indexes = nxt_var_indexes(var);
|
||||
|
||||
for (j = 0; j < var->vars; j++) {
|
||||
str = nxt_var_cache_find(&query->cache, indexes[j]);
|
||||
|
||||
nxt_assert(str != NULL);
|
||||
|
||||
part = nxt_array_add(&query->parts);
|
||||
|
||||
if (nxt_slow_path(part == NULL)) {
|
||||
query->failed = 1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
*part = str;
|
||||
|
||||
length += str->length;
|
||||
}
|
||||
|
||||
p = nxt_mp_nget(query->values.mem_pool, length);
|
||||
if (nxt_slow_path(p == NULL)) {
|
||||
query->failed = 1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
val[i].value->length = length;
|
||||
val[i].value->start = p;
|
||||
|
||||
part = query->parts.elts;
|
||||
positions = nxt_var_positions(var);
|
||||
src = nxt_var_plain_start(var);
|
||||
|
||||
plain = 0;
|
||||
|
||||
for (j = 0; j < var->vars; j++) {
|
||||
next = positions[j];
|
||||
|
||||
if (next != plain) {
|
||||
p = nxt_cpymem(p, &src[plain], next - plain);
|
||||
plain = next;
|
||||
}
|
||||
|
||||
p = nxt_cpymem(p, part[j]->start, part[j]->length);
|
||||
}
|
||||
|
||||
if (plain != var->plain) {
|
||||
nxt_memcpy(p, &src[plain], var->plain - plain);
|
||||
}
|
||||
|
||||
nxt_array_reset(&query->parts);
|
||||
}
|
||||
|
||||
done:
|
||||
|
||||
nxt_work_queue_add(&task->thread->engine->fast_work_queue,
|
||||
query->failed ? query->error : query->ready,
|
||||
task, query->ctx, query->data);
|
||||
}
|
||||
48
src/nxt_var.h
Normal file
48
src/nxt_var.h
Normal file
@@ -0,0 +1,48 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) NGINX, Inc.
|
||||
*/
|
||||
|
||||
#ifndef _NXT_VAR_H_INCLUDED_
|
||||
#define _NXT_VAR_H_INCLUDED_
|
||||
|
||||
|
||||
typedef struct nxt_var_s nxt_var_t;
|
||||
typedef struct nxt_var_query_s nxt_var_query_t;
|
||||
|
||||
|
||||
typedef nxt_int_t (*nxt_var_handler_t)(nxt_task_t *task,
|
||||
nxt_var_query_t *query,
|
||||
nxt_str_t *str,
|
||||
void *ctx);
|
||||
|
||||
typedef struct {
|
||||
nxt_str_t name;
|
||||
nxt_var_handler_t handler;
|
||||
uint32_t index;
|
||||
} nxt_var_decl_t;
|
||||
|
||||
|
||||
nxt_inline nxt_bool_t
|
||||
nxt_is_var(nxt_str_t *str)
|
||||
{
|
||||
return (nxt_memchr(str->start, '$', str->length) != NULL);
|
||||
}
|
||||
|
||||
|
||||
nxt_int_t nxt_var_register(nxt_var_decl_t *decl, size_t n);
|
||||
nxt_int_t nxt_var_index_init(void);
|
||||
nxt_var_t *nxt_var_compile(nxt_str_t *str, nxt_mp_t *mp);
|
||||
nxt_int_t nxt_var_test(nxt_str_t *str, u_char *error);
|
||||
|
||||
nxt_int_t nxt_var_query_init(nxt_var_query_t **query_p, void *ctx,
|
||||
nxt_mp_t *mp);
|
||||
void nxt_var_query(nxt_task_t *task, nxt_var_query_t *query,
|
||||
nxt_var_t *var, nxt_str_t *str);
|
||||
void nxt_var_query_resolve(nxt_task_t *task, nxt_var_query_t *query, void *data,
|
||||
nxt_work_handler_t ready, nxt_work_handler_t error);
|
||||
void nxt_var_query_handle(nxt_task_t *task, nxt_var_query_t *query,
|
||||
nxt_bool_t failed);
|
||||
|
||||
|
||||
#endif /* _NXT_VAR_H_INCLUDED_ */
|
||||
@@ -19,20 +19,6 @@ nxt_lvlhsh_test_key_test(nxt_lvlhsh_query_t *lhq, void *data)
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
nxt_lvlhsh_test_pool_alloc(void *pool, size_t size)
|
||||
{
|
||||
return nxt_mp_align(pool, size, size);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
nxt_lvlhsh_test_pool_free(void *pool, void *p)
|
||||
{
|
||||
nxt_mp_free(pool, p);
|
||||
}
|
||||
|
||||
|
||||
static const nxt_lvlhsh_proto_t malloc_proto nxt_aligned(64) = {
|
||||
//NXT_LVLHSH_LARGE_MEMALIGN,
|
||||
NXT_LVLHSH_DEFAULT,
|
||||
@@ -44,8 +30,8 @@ static const nxt_lvlhsh_proto_t malloc_proto nxt_aligned(64) = {
|
||||
static const nxt_lvlhsh_proto_t pool_proto nxt_aligned(64) = {
|
||||
NXT_LVLHSH_LARGE_SLAB,
|
||||
nxt_lvlhsh_test_key_test,
|
||||
nxt_lvlhsh_test_pool_alloc,
|
||||
nxt_lvlhsh_test_pool_free,
|
||||
nxt_mp_lvlhsh_alloc,
|
||||
nxt_mp_lvlhsh_free,
|
||||
};
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user