diff --git a/src/nxt_conf_validation.c b/src/nxt_conf_validation.c index 04091745c..fa8027992 100644 --- a/src/nxt_conf_validation.c +++ b/src/nxt_conf_validation.c @@ -684,6 +684,10 @@ static nxt_conf_vldt_object_t nxt_conf_vldt_match_members[] = { .type = NXT_CONF_VLDT_OBJECT | NXT_CONF_VLDT_ARRAY, .validator = nxt_conf_vldt_match_patterns_sets, .u.string = "cookies" + }, { + .name = nxt_string("if"), + .type = NXT_CONF_VLDT_STRING, + .validator = nxt_conf_vldt_if, }, NXT_CONF_VLDT_END diff --git a/src/nxt_http_route.c b/src/nxt_http_route.c index a82518a4a..cfdf3b4a7 100644 --- a/src/nxt_http_route.c +++ b/src/nxt_http_route.c @@ -51,6 +51,7 @@ typedef struct { nxt_conf_value_t *query; nxt_conf_value_t *source; nxt_conf_value_t *destination; + nxt_conf_value_t *condition; } nxt_http_route_match_conf_t; @@ -138,6 +139,8 @@ typedef union { typedef struct { uint32_t items; + nxt_tstr_t *condition; + uint8_t cond_negate; /* 1 bit */ nxt_http_action_t action; nxt_http_route_test_t test[]; } nxt_http_route_match_t; @@ -204,6 +207,8 @@ static nxt_http_action_t *nxt_http_route_handler(nxt_task_t *task, nxt_http_request_t *r, nxt_http_action_t *start); static nxt_http_action_t *nxt_http_route_match(nxt_task_t *task, nxt_http_request_t *r, nxt_http_route_match_t *match); +static nxt_int_t nxt_http_route_match_if(nxt_task_t *task, + nxt_http_request_t *r, nxt_http_route_match_t *match); static nxt_int_t nxt_http_route_table(nxt_http_request_t *r, nxt_http_route_table_t *table); static nxt_int_t nxt_http_route_ruleset(nxt_http_request_t *r, @@ -350,6 +355,12 @@ static nxt_conf_map_t nxt_http_route_match_conf[] = { NXT_CONF_MAP_PTR, offsetof(nxt_http_route_match_conf_t, destination), }, + + { + nxt_string("if"), + NXT_CONF_MAP_PTR, + offsetof(nxt_http_route_match_conf_t, condition), + }, }; @@ -397,7 +408,9 @@ nxt_http_route_match_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, uint32_t n; nxt_mp_t *mp; nxt_int_t ret; - nxt_conf_value_t *match_conf, *action_conf; + nxt_str_t str; + nxt_conf_value_t *match_conf, *action_conf, *condition; + nxt_router_conf_t *rtcf; nxt_http_route_test_t *test; nxt_http_route_rule_t *rule; nxt_http_route_table_t *table; @@ -405,6 +418,7 @@ nxt_http_route_match_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, nxt_http_route_addr_rule_t *addr_rule; nxt_http_route_match_conf_t mtcf; + static const nxt_str_t if_path = nxt_string("/if"); static const nxt_str_t match_path = nxt_string("/match"); static const nxt_str_t action_path = nxt_string("/action"); @@ -413,9 +427,21 @@ nxt_http_route_match_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, n = (match_conf != NULL) ? nxt_conf_object_members_count(match_conf) : 0; size = sizeof(nxt_http_route_match_t) + n * sizeof(nxt_http_route_test_t *); - mp = tmcf->router_conf->mem_pool; + rtcf = tmcf->router_conf; + mp = rtcf->mem_pool; + + condition = NULL; + + if (match_conf != NULL) { + condition = nxt_conf_get_path(match_conf, &if_path); + + if (condition != NULL) { + n--; + size -= sizeof(nxt_http_route_test_t *); + } + } - match = nxt_mp_alloc(mp, size); + match = nxt_mp_zalloc(mp, size); if (nxt_slow_path(match == NULL)) { return NULL; } @@ -432,7 +458,7 @@ nxt_http_route_match_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, return NULL; } - if (n == 0) { + if (n == 0 && condition == NULL) { return match; } @@ -445,6 +471,22 @@ nxt_http_route_match_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, return NULL; } + if (condition != NULL) { + nxt_conf_get_string(condition, &str); + + if (str.length > 0 && str.start[0] == '!') { + match->cond_negate = 1; + + str.start++; + str.length--; + } + + match->condition = nxt_tstr_compile(rtcf->tstr_state, &str, 0); + if (nxt_slow_path(match->condition == NULL)) { + return NULL; + } + } + test = &match->test[0]; if (mtcf.scheme != NULL) { @@ -1594,8 +1636,17 @@ nxt_http_route_match(nxt_task_t *task, nxt_http_request_t *r, nxt_http_route_match_t *match) { nxt_int_t ret; + nxt_http_action_t *action; nxt_http_route_test_t *test, *end; + if (match->condition != NULL) { + ret = nxt_http_route_match_if(task, r, match); + if (ret <= 0) { + action = (nxt_http_action_t *) (intptr_t) ret; + return action; + } + } + test = &match->test[0]; end = test + match->items; @@ -1631,6 +1682,44 @@ nxt_http_route_match(nxt_task_t *task, nxt_http_request_t *r, } +static nxt_int_t +nxt_http_route_match_if(nxt_task_t *task, nxt_http_request_t *r, + nxt_http_route_match_t *match) +{ + nxt_int_t ret, expr; + nxt_str_t str; + nxt_router_conf_t *rtcf; + + expr = 1; + + if (match->condition != NULL) { + rtcf = r->conf->socket_conf->router_conf; + + ret = nxt_tstr_query_init(&r->tstr_query, rtcf->tstr_state, + &r->tstr_cache, r, r->mem_pool); + if (nxt_slow_path(ret != NXT_OK)) { + return NXT_ERROR; + } + + ret = nxt_tstr_query(task, r->tstr_query, match->condition, &str); + if (nxt_slow_path(ret != NXT_OK)) { + return NXT_ERROR; + } + + if (str.length == 0 + || nxt_str_eq(&str, "0", 1) + || nxt_str_eq(&str, "false", 5) + || nxt_str_eq(&str, "null", 4) + || nxt_str_eq(&str, "undefined", 9)) + { + expr = 0; + } + } + + return match->cond_negate ^ expr; +} + + static nxt_int_t nxt_http_route_table(nxt_http_request_t *r, nxt_http_route_table_t *table) {