1964Sigor@sysoev.ru 2964Sigor@sysoev.ru /* 3964Sigor@sysoev.ru * Copyright (C) Igor Sysoev 4964Sigor@sysoev.ru * Copyright (C) NGINX, Inc. 5964Sigor@sysoev.ru */ 6964Sigor@sysoev.ru 7964Sigor@sysoev.ru #include <nxt_router.h> 8964Sigor@sysoev.ru #include <nxt_http.h> 9964Sigor@sysoev.ru 10964Sigor@sysoev.ru 11964Sigor@sysoev.ru typedef enum { 121059Sigor@sysoev.ru NXT_HTTP_ROUTE_TABLE = 0, 131059Sigor@sysoev.ru NXT_HTTP_ROUTE_STRING, 14964Sigor@sysoev.ru NXT_HTTP_ROUTE_STRING_PTR, 15964Sigor@sysoev.ru NXT_HTTP_ROUTE_HEADER, 16964Sigor@sysoev.ru NXT_HTTP_ROUTE_ARGUMENT, 17964Sigor@sysoev.ru NXT_HTTP_ROUTE_COOKIE, 18964Sigor@sysoev.ru } nxt_http_route_object_t; 19964Sigor@sysoev.ru 20964Sigor@sysoev.ru 21964Sigor@sysoev.ru typedef enum { 22964Sigor@sysoev.ru NXT_HTTP_ROUTE_PATTERN_EXACT = 0, 23964Sigor@sysoev.ru NXT_HTTP_ROUTE_PATTERN_BEGIN, 241032Sigor@sysoev.ru NXT_HTTP_ROUTE_PATTERN_MIDDLE, 25964Sigor@sysoev.ru NXT_HTTP_ROUTE_PATTERN_END, 26964Sigor@sysoev.ru NXT_HTTP_ROUTE_PATTERN_SUBSTRING, 27964Sigor@sysoev.ru } nxt_http_route_pattern_type_t; 28964Sigor@sysoev.ru 29964Sigor@sysoev.ru 30964Sigor@sysoev.ru typedef enum { 31964Sigor@sysoev.ru NXT_HTTP_ROUTE_PATTERN_NOCASE = 0, 32964Sigor@sysoev.ru NXT_HTTP_ROUTE_PATTERN_LOWCASE, 33964Sigor@sysoev.ru NXT_HTTP_ROUTE_PATTERN_UPCASE, 34964Sigor@sysoev.ru } nxt_http_route_pattern_case_t; 35964Sigor@sysoev.ru 36964Sigor@sysoev.ru 37964Sigor@sysoev.ru typedef struct { 38964Sigor@sysoev.ru nxt_conf_value_t *host; 39964Sigor@sysoev.ru nxt_conf_value_t *uri; 40964Sigor@sysoev.ru nxt_conf_value_t *method; 411059Sigor@sysoev.ru nxt_conf_value_t *headers; 42*1061Sigor@sysoev.ru nxt_conf_value_t *arguments; 43964Sigor@sysoev.ru } nxt_http_route_match_conf_t; 44964Sigor@sysoev.ru 45964Sigor@sysoev.ru 46964Sigor@sysoev.ru typedef struct { 471032Sigor@sysoev.ru u_char *start1; 481032Sigor@sysoev.ru u_char *start2; 491032Sigor@sysoev.ru uint32_t length1; 501032Sigor@sysoev.ru uint32_t length2; 51964Sigor@sysoev.ru uint32_t min_length; 52964Sigor@sysoev.ru 53964Sigor@sysoev.ru nxt_http_route_pattern_type_t type:8; 54964Sigor@sysoev.ru uint8_t case_sensitive; /* 1 bit */ 55964Sigor@sysoev.ru uint8_t negative; /* 1 bit */ 56964Sigor@sysoev.ru uint8_t any; /* 1 bit */ 57964Sigor@sysoev.ru } nxt_http_route_pattern_t; 58964Sigor@sysoev.ru 59964Sigor@sysoev.ru 60964Sigor@sysoev.ru typedef struct { 61*1061Sigor@sysoev.ru uint16_t hash; 62*1061Sigor@sysoev.ru uint16_t name_length; 63*1061Sigor@sysoev.ru uint32_t value_length; 64*1061Sigor@sysoev.ru u_char *name; 65*1061Sigor@sysoev.ru u_char *value; 66*1061Sigor@sysoev.ru } nxt_http_name_value_t; 67*1061Sigor@sysoev.ru 68*1061Sigor@sysoev.ru 69*1061Sigor@sysoev.ru typedef struct { 701059Sigor@sysoev.ru /* The object must be the first field. */ 711059Sigor@sysoev.ru nxt_http_route_object_t object:8; 72964Sigor@sysoev.ru uint32_t items; 731059Sigor@sysoev.ru 741059Sigor@sysoev.ru union { 751059Sigor@sysoev.ru uintptr_t offset; 761059Sigor@sysoev.ru 771059Sigor@sysoev.ru struct { 781059Sigor@sysoev.ru u_char *start; 791059Sigor@sysoev.ru uint16_t hash; 801059Sigor@sysoev.ru uint16_t length; 811059Sigor@sysoev.ru } name; 821059Sigor@sysoev.ru } u; 831059Sigor@sysoev.ru 84964Sigor@sysoev.ru nxt_http_route_pattern_t pattern[0]; 85964Sigor@sysoev.ru } nxt_http_route_rule_t; 86964Sigor@sysoev.ru 87964Sigor@sysoev.ru 88964Sigor@sysoev.ru typedef struct { 89964Sigor@sysoev.ru uint32_t items; 901059Sigor@sysoev.ru nxt_http_route_rule_t *rule[0]; 911059Sigor@sysoev.ru } nxt_http_route_ruleset_t; 921059Sigor@sysoev.ru 931059Sigor@sysoev.ru 941059Sigor@sysoev.ru typedef struct { 951059Sigor@sysoev.ru /* The object must be the first field. */ 961059Sigor@sysoev.ru nxt_http_route_object_t object:8; 971059Sigor@sysoev.ru uint32_t items; 981059Sigor@sysoev.ru nxt_http_route_ruleset_t *ruleset[0]; 991059Sigor@sysoev.ru } nxt_http_route_table_t; 1001059Sigor@sysoev.ru 1011059Sigor@sysoev.ru 1021059Sigor@sysoev.ru typedef union { 1031059Sigor@sysoev.ru nxt_http_route_rule_t *rule; 1041059Sigor@sysoev.ru nxt_http_route_table_t *table; 1051059Sigor@sysoev.ru } nxt_http_route_test_t; 1061059Sigor@sysoev.ru 1071059Sigor@sysoev.ru 1081059Sigor@sysoev.ru typedef struct { 1091059Sigor@sysoev.ru uint32_t items; 110964Sigor@sysoev.ru nxt_http_pass_t pass; 1111059Sigor@sysoev.ru nxt_http_route_test_t test[0]; 112964Sigor@sysoev.ru } nxt_http_route_match_t; 113964Sigor@sysoev.ru 114964Sigor@sysoev.ru 115964Sigor@sysoev.ru struct nxt_http_route_s { 116964Sigor@sysoev.ru nxt_str_t name; 117964Sigor@sysoev.ru uint32_t items; 118964Sigor@sysoev.ru nxt_http_route_match_t *match[0]; 119964Sigor@sysoev.ru }; 120964Sigor@sysoev.ru 121964Sigor@sysoev.ru 122964Sigor@sysoev.ru struct nxt_http_routes_s { 123964Sigor@sysoev.ru uint32_t items; 124964Sigor@sysoev.ru nxt_http_route_t *route[0]; 125964Sigor@sysoev.ru }; 126964Sigor@sysoev.ru 127964Sigor@sysoev.ru 128964Sigor@sysoev.ru static nxt_http_route_t *nxt_http_route_create(nxt_task_t *task, 129964Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, nxt_conf_value_t *cv); 130964Sigor@sysoev.ru static nxt_http_route_match_t *nxt_http_route_match_create(nxt_task_t *task, 131964Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, nxt_conf_value_t *cv); 1321059Sigor@sysoev.ru static nxt_http_route_table_t *nxt_http_route_table_create(nxt_task_t *task, 133*1061Sigor@sysoev.ru nxt_mp_t *mp, nxt_conf_value_t *table_cv, nxt_http_route_object_t object, 134*1061Sigor@sysoev.ru nxt_bool_t case_sensitive); 1351059Sigor@sysoev.ru static nxt_http_route_ruleset_t *nxt_http_route_ruleset_create(nxt_task_t *task, 136*1061Sigor@sysoev.ru nxt_mp_t *mp, nxt_conf_value_t *ruleset_cv, nxt_http_route_object_t object, 137*1061Sigor@sysoev.ru nxt_bool_t case_sensitive); 138*1061Sigor@sysoev.ru static nxt_http_route_rule_t *nxt_http_route_rule_name_create(nxt_task_t *task, 139*1061Sigor@sysoev.ru nxt_mp_t *mp, nxt_conf_value_t *rule_cv, nxt_str_t *name, 140*1061Sigor@sysoev.ru nxt_bool_t case_sensitive); 141964Sigor@sysoev.ru static nxt_http_route_rule_t *nxt_http_route_rule_create(nxt_task_t *task, 1421059Sigor@sysoev.ru nxt_mp_t *mp, nxt_conf_value_t *cv, nxt_bool_t case_sensitive, 1431059Sigor@sysoev.ru nxt_http_route_pattern_case_t pattern_case); 144964Sigor@sysoev.ru static int nxt_http_pattern_compare(const void *one, const void *two); 145964Sigor@sysoev.ru static nxt_int_t nxt_http_route_pattern_create(nxt_task_t *task, nxt_mp_t *mp, 146964Sigor@sysoev.ru nxt_conf_value_t *cv, nxt_http_route_pattern_t *pattern, 147964Sigor@sysoev.ru nxt_http_route_pattern_case_t pattern_case); 1481032Sigor@sysoev.ru static u_char *nxt_http_route_pattern_copy(nxt_mp_t *mp, nxt_str_t *test, 1491032Sigor@sysoev.ru nxt_http_route_pattern_case_t pattern_case); 150964Sigor@sysoev.ru 151964Sigor@sysoev.ru static void nxt_http_route_resolve(nxt_task_t *task, 152964Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, nxt_http_route_t *route); 153964Sigor@sysoev.ru static void nxt_http_pass_resolve(nxt_task_t *task, 154964Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, nxt_http_pass_t *pass); 155964Sigor@sysoev.ru static nxt_http_route_t *nxt_http_route_find(nxt_http_routes_t *routes, 156964Sigor@sysoev.ru nxt_str_t *name); 157964Sigor@sysoev.ru static void nxt_http_route_cleanup(nxt_task_t *task, nxt_http_route_t *routes); 158964Sigor@sysoev.ru 159964Sigor@sysoev.ru static nxt_http_pass_t *nxt_http_route_pass(nxt_task_t *task, 160964Sigor@sysoev.ru nxt_http_request_t *r, nxt_http_pass_t *start); 161964Sigor@sysoev.ru static nxt_http_pass_t *nxt_http_route_match(nxt_http_request_t *r, 162964Sigor@sysoev.ru nxt_http_route_match_t *match); 1631060Sigor@sysoev.ru static nxt_int_t nxt_http_route_table(nxt_http_request_t *r, 1641059Sigor@sysoev.ru nxt_http_route_table_t *table); 1651060Sigor@sysoev.ru static nxt_int_t nxt_http_route_ruleset(nxt_http_request_t *r, 1661059Sigor@sysoev.ru nxt_http_route_ruleset_t *ruleset); 1671060Sigor@sysoev.ru static nxt_int_t nxt_http_route_rule(nxt_http_request_t *r, 168964Sigor@sysoev.ru nxt_http_route_rule_t *rule); 1691060Sigor@sysoev.ru static nxt_int_t nxt_http_route_header(nxt_http_request_t *r, 1701059Sigor@sysoev.ru nxt_http_route_rule_t *rule); 171*1061Sigor@sysoev.ru static nxt_int_t nxt_http_route_arguments(nxt_http_request_t *r, 172*1061Sigor@sysoev.ru nxt_http_route_rule_t *rule); 173*1061Sigor@sysoev.ru static nxt_array_t *nxt_http_route_arguments_parse(nxt_http_request_t *r); 174*1061Sigor@sysoev.ru static nxt_http_name_value_t *nxt_http_route_argument(nxt_array_t *array, 175*1061Sigor@sysoev.ru u_char *name, size_t name_length, uint32_t hash, u_char *start, 176*1061Sigor@sysoev.ru u_char *end); 177*1061Sigor@sysoev.ru static nxt_int_t nxt_http_route_test_argument(nxt_http_request_t *r, 178*1061Sigor@sysoev.ru nxt_http_route_rule_t *rule, nxt_array_t *array); 1791060Sigor@sysoev.ru static nxt_int_t nxt_http_route_test_rule(nxt_http_request_t *r, 1801059Sigor@sysoev.ru nxt_http_route_rule_t *rule, u_char *start, size_t length); 1811060Sigor@sysoev.ru static nxt_int_t nxt_http_route_pattern(nxt_http_request_t *r, 182964Sigor@sysoev.ru nxt_http_route_pattern_t *pattern, u_char *start, size_t length); 1831060Sigor@sysoev.ru static nxt_int_t nxt_http_route_memcmp(u_char *start, u_char *test, 1841032Sigor@sysoev.ru size_t length, nxt_bool_t case_sensitive); 185964Sigor@sysoev.ru 186964Sigor@sysoev.ru 187964Sigor@sysoev.ru nxt_http_routes_t * 188964Sigor@sysoev.ru nxt_http_routes_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 189964Sigor@sysoev.ru nxt_conf_value_t *routes_conf) 190964Sigor@sysoev.ru { 191964Sigor@sysoev.ru size_t size; 192964Sigor@sysoev.ru uint32_t i, n, next; 193964Sigor@sysoev.ru nxt_mp_t *mp; 194964Sigor@sysoev.ru nxt_str_t name, *string; 195964Sigor@sysoev.ru nxt_bool_t object; 196964Sigor@sysoev.ru nxt_conf_value_t *route_conf; 197964Sigor@sysoev.ru nxt_http_route_t *route; 198964Sigor@sysoev.ru nxt_http_routes_t *routes; 199964Sigor@sysoev.ru 200964Sigor@sysoev.ru object = (nxt_conf_type(routes_conf) == NXT_CONF_OBJECT); 201964Sigor@sysoev.ru n = object ? nxt_conf_object_members_count(routes_conf) : 1; 202964Sigor@sysoev.ru size = sizeof(nxt_http_routes_t) + n * sizeof(nxt_http_route_t *); 203964Sigor@sysoev.ru 204964Sigor@sysoev.ru mp = tmcf->router_conf->mem_pool; 205964Sigor@sysoev.ru 206964Sigor@sysoev.ru routes = nxt_mp_alloc(mp, size); 207964Sigor@sysoev.ru if (nxt_slow_path(routes == NULL)) { 208964Sigor@sysoev.ru return NULL; 209964Sigor@sysoev.ru } 210964Sigor@sysoev.ru 211964Sigor@sysoev.ru routes->items = n; 212964Sigor@sysoev.ru 213964Sigor@sysoev.ru if (object) { 214964Sigor@sysoev.ru next = 0; 215964Sigor@sysoev.ru 216964Sigor@sysoev.ru for (i = 0; i < n; i++) { 217964Sigor@sysoev.ru route_conf = nxt_conf_next_object_member(routes_conf, &name, &next); 218964Sigor@sysoev.ru 219964Sigor@sysoev.ru route = nxt_http_route_create(task, tmcf, route_conf); 220964Sigor@sysoev.ru if (nxt_slow_path(route == NULL)) { 221964Sigor@sysoev.ru return NULL; 222964Sigor@sysoev.ru } 223964Sigor@sysoev.ru 224964Sigor@sysoev.ru routes->route[i] = route; 225964Sigor@sysoev.ru 226964Sigor@sysoev.ru string = nxt_str_dup(mp, &route->name, &name); 227964Sigor@sysoev.ru if (nxt_slow_path(string == NULL)) { 228964Sigor@sysoev.ru return NULL; 229964Sigor@sysoev.ru } 230964Sigor@sysoev.ru } 231964Sigor@sysoev.ru 232964Sigor@sysoev.ru } else { 233964Sigor@sysoev.ru route = nxt_http_route_create(task, tmcf, routes_conf); 234964Sigor@sysoev.ru if (nxt_slow_path(route == NULL)) { 235964Sigor@sysoev.ru return NULL; 236964Sigor@sysoev.ru } 237964Sigor@sysoev.ru 238964Sigor@sysoev.ru routes->route[0] = route; 239964Sigor@sysoev.ru 240964Sigor@sysoev.ru route->name.length = 0; 241964Sigor@sysoev.ru route->name.start = NULL; 242964Sigor@sysoev.ru } 243964Sigor@sysoev.ru 244964Sigor@sysoev.ru return routes; 245964Sigor@sysoev.ru } 246964Sigor@sysoev.ru 247964Sigor@sysoev.ru 248964Sigor@sysoev.ru static nxt_conf_map_t nxt_http_route_match_conf[] = { 249964Sigor@sysoev.ru { 250964Sigor@sysoev.ru nxt_string("host"), 251964Sigor@sysoev.ru NXT_CONF_MAP_PTR, 252964Sigor@sysoev.ru offsetof(nxt_http_route_match_conf_t, host), 253964Sigor@sysoev.ru }, 254964Sigor@sysoev.ru 255964Sigor@sysoev.ru { 256964Sigor@sysoev.ru nxt_string("uri"), 257964Sigor@sysoev.ru NXT_CONF_MAP_PTR, 258964Sigor@sysoev.ru offsetof(nxt_http_route_match_conf_t, uri), 259964Sigor@sysoev.ru }, 260964Sigor@sysoev.ru 261964Sigor@sysoev.ru { 262964Sigor@sysoev.ru nxt_string("method"), 263964Sigor@sysoev.ru NXT_CONF_MAP_PTR, 264964Sigor@sysoev.ru offsetof(nxt_http_route_match_conf_t, method), 265964Sigor@sysoev.ru }, 2661059Sigor@sysoev.ru 2671059Sigor@sysoev.ru { 2681059Sigor@sysoev.ru nxt_string("headers"), 2691059Sigor@sysoev.ru NXT_CONF_MAP_PTR, 2701059Sigor@sysoev.ru offsetof(nxt_http_route_match_conf_t, headers), 2711059Sigor@sysoev.ru }, 272*1061Sigor@sysoev.ru 273*1061Sigor@sysoev.ru { 274*1061Sigor@sysoev.ru nxt_string("arguments"), 275*1061Sigor@sysoev.ru NXT_CONF_MAP_PTR, 276*1061Sigor@sysoev.ru offsetof(nxt_http_route_match_conf_t, arguments), 277*1061Sigor@sysoev.ru }, 278964Sigor@sysoev.ru }; 279964Sigor@sysoev.ru 280964Sigor@sysoev.ru 281964Sigor@sysoev.ru static nxt_http_route_t * 282964Sigor@sysoev.ru nxt_http_route_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 283964Sigor@sysoev.ru nxt_conf_value_t *cv) 284964Sigor@sysoev.ru { 285964Sigor@sysoev.ru size_t size; 286964Sigor@sysoev.ru uint32_t i, n; 287964Sigor@sysoev.ru nxt_conf_value_t *value; 288964Sigor@sysoev.ru nxt_http_route_t *route; 289964Sigor@sysoev.ru nxt_http_route_match_t *match, **m; 290964Sigor@sysoev.ru 291964Sigor@sysoev.ru n = nxt_conf_array_elements_count(cv); 292964Sigor@sysoev.ru size = sizeof(nxt_http_route_t) + n * sizeof(nxt_http_route_match_t *); 293964Sigor@sysoev.ru 294964Sigor@sysoev.ru route = nxt_mp_alloc(tmcf->router_conf->mem_pool, size); 295964Sigor@sysoev.ru if (nxt_slow_path(route == NULL)) { 296964Sigor@sysoev.ru return NULL; 297964Sigor@sysoev.ru } 298964Sigor@sysoev.ru 299964Sigor@sysoev.ru route->items = n; 300964Sigor@sysoev.ru m = &route->match[0]; 301964Sigor@sysoev.ru 302964Sigor@sysoev.ru for (i = 0; i < n; i++) { 303964Sigor@sysoev.ru value = nxt_conf_get_array_element(cv, i); 304964Sigor@sysoev.ru 305964Sigor@sysoev.ru match = nxt_http_route_match_create(task, tmcf, value); 306964Sigor@sysoev.ru if (match == NULL) { 307964Sigor@sysoev.ru return NULL; 308964Sigor@sysoev.ru } 309964Sigor@sysoev.ru 310964Sigor@sysoev.ru *m++ = match; 311964Sigor@sysoev.ru } 312964Sigor@sysoev.ru 313964Sigor@sysoev.ru return route; 314964Sigor@sysoev.ru } 315964Sigor@sysoev.ru 316964Sigor@sysoev.ru 317964Sigor@sysoev.ru static nxt_http_route_match_t * 318964Sigor@sysoev.ru nxt_http_route_match_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 319964Sigor@sysoev.ru nxt_conf_value_t *cv) 320964Sigor@sysoev.ru { 321964Sigor@sysoev.ru size_t size; 322964Sigor@sysoev.ru uint32_t n; 3231059Sigor@sysoev.ru nxt_mp_t *mp; 324964Sigor@sysoev.ru nxt_int_t ret; 325964Sigor@sysoev.ru nxt_str_t pass, *string; 326964Sigor@sysoev.ru nxt_conf_value_t *match_conf, *pass_conf; 3271059Sigor@sysoev.ru nxt_http_route_test_t *test; 3281059Sigor@sysoev.ru nxt_http_route_rule_t *rule; 3291059Sigor@sysoev.ru nxt_http_route_table_t *table; 330964Sigor@sysoev.ru nxt_http_route_match_t *match; 331964Sigor@sysoev.ru nxt_http_route_match_conf_t mtcf; 332964Sigor@sysoev.ru 333964Sigor@sysoev.ru static nxt_str_t pass_path = nxt_string("/action/pass"); 334964Sigor@sysoev.ru static nxt_str_t match_path = nxt_string("/match"); 335964Sigor@sysoev.ru 336964Sigor@sysoev.ru pass_conf = nxt_conf_get_path(cv, &pass_path); 337964Sigor@sysoev.ru if (nxt_slow_path(pass_conf == NULL)) { 338964Sigor@sysoev.ru return NULL; 339964Sigor@sysoev.ru } 340964Sigor@sysoev.ru 341964Sigor@sysoev.ru nxt_conf_get_string(pass_conf, &pass); 342964Sigor@sysoev.ru 343964Sigor@sysoev.ru match_conf = nxt_conf_get_path(cv, &match_path); 344964Sigor@sysoev.ru 345964Sigor@sysoev.ru n = (match_conf != NULL) ? nxt_conf_object_members_count(match_conf) : 0; 346964Sigor@sysoev.ru size = sizeof(nxt_http_route_match_t) + n * sizeof(nxt_http_route_rule_t *); 347964Sigor@sysoev.ru 3481059Sigor@sysoev.ru mp = tmcf->router_conf->mem_pool; 3491059Sigor@sysoev.ru 3501059Sigor@sysoev.ru match = nxt_mp_alloc(mp, size); 351964Sigor@sysoev.ru if (nxt_slow_path(match == NULL)) { 352964Sigor@sysoev.ru return NULL; 353964Sigor@sysoev.ru } 354964Sigor@sysoev.ru 355964Sigor@sysoev.ru match->pass.u.route = NULL; 356964Sigor@sysoev.ru match->pass.handler = NULL; 357964Sigor@sysoev.ru match->items = n; 358964Sigor@sysoev.ru 3591059Sigor@sysoev.ru string = nxt_str_dup(mp, &match->pass.name, &pass); 360964Sigor@sysoev.ru if (nxt_slow_path(string == NULL)) { 361964Sigor@sysoev.ru return NULL; 362964Sigor@sysoev.ru } 363964Sigor@sysoev.ru 364964Sigor@sysoev.ru if (n == 0) { 365964Sigor@sysoev.ru return match; 366964Sigor@sysoev.ru } 367964Sigor@sysoev.ru 368964Sigor@sysoev.ru nxt_memzero(&mtcf, sizeof(mtcf)); 369964Sigor@sysoev.ru 370964Sigor@sysoev.ru ret = nxt_conf_map_object(tmcf->mem_pool, 371964Sigor@sysoev.ru match_conf, nxt_http_route_match_conf, 372964Sigor@sysoev.ru nxt_nitems(nxt_http_route_match_conf), &mtcf); 373964Sigor@sysoev.ru if (ret != NXT_OK) { 374964Sigor@sysoev.ru return NULL; 375964Sigor@sysoev.ru } 376964Sigor@sysoev.ru 3771059Sigor@sysoev.ru test = &match->test[0]; 378964Sigor@sysoev.ru 379964Sigor@sysoev.ru if (mtcf.host != NULL) { 3801059Sigor@sysoev.ru rule = nxt_http_route_rule_create(task, mp, mtcf.host, 1, 381964Sigor@sysoev.ru NXT_HTTP_ROUTE_PATTERN_LOWCASE); 382964Sigor@sysoev.ru if (rule == NULL) { 383964Sigor@sysoev.ru return NULL; 384964Sigor@sysoev.ru } 385964Sigor@sysoev.ru 3861059Sigor@sysoev.ru rule->u.offset = offsetof(nxt_http_request_t, host); 387964Sigor@sysoev.ru rule->object = NXT_HTTP_ROUTE_STRING; 3881059Sigor@sysoev.ru test->rule = rule; 3891059Sigor@sysoev.ru test++; 390964Sigor@sysoev.ru } 391964Sigor@sysoev.ru 392964Sigor@sysoev.ru if (mtcf.uri != NULL) { 3931059Sigor@sysoev.ru rule = nxt_http_route_rule_create(task, mp, mtcf.uri, 1, 394964Sigor@sysoev.ru NXT_HTTP_ROUTE_PATTERN_NOCASE); 395964Sigor@sysoev.ru if (rule == NULL) { 396964Sigor@sysoev.ru return NULL; 397964Sigor@sysoev.ru } 398964Sigor@sysoev.ru 3991059Sigor@sysoev.ru rule->u.offset = offsetof(nxt_http_request_t, path); 400964Sigor@sysoev.ru rule->object = NXT_HTTP_ROUTE_STRING_PTR; 4011059Sigor@sysoev.ru test->rule = rule; 4021059Sigor@sysoev.ru test++; 403964Sigor@sysoev.ru } 404964Sigor@sysoev.ru 405964Sigor@sysoev.ru if (mtcf.method != NULL) { 4061059Sigor@sysoev.ru rule = nxt_http_route_rule_create(task, mp, mtcf.method, 1, 407964Sigor@sysoev.ru NXT_HTTP_ROUTE_PATTERN_UPCASE); 408964Sigor@sysoev.ru if (rule == NULL) { 409964Sigor@sysoev.ru return NULL; 410964Sigor@sysoev.ru } 411964Sigor@sysoev.ru 4121059Sigor@sysoev.ru rule->u.offset = offsetof(nxt_http_request_t, method); 413964Sigor@sysoev.ru rule->object = NXT_HTTP_ROUTE_STRING_PTR; 4141059Sigor@sysoev.ru test->rule = rule; 4151059Sigor@sysoev.ru test++; 4161059Sigor@sysoev.ru } 4171059Sigor@sysoev.ru 4181059Sigor@sysoev.ru if (mtcf.headers != NULL) { 419*1061Sigor@sysoev.ru table = nxt_http_route_table_create(task, mp, mtcf.headers, 420*1061Sigor@sysoev.ru NXT_HTTP_ROUTE_HEADER, 0); 421*1061Sigor@sysoev.ru if (table == NULL) { 422*1061Sigor@sysoev.ru return NULL; 423*1061Sigor@sysoev.ru } 424*1061Sigor@sysoev.ru 425*1061Sigor@sysoev.ru test->table = table; 426*1061Sigor@sysoev.ru test++; 427*1061Sigor@sysoev.ru } 428*1061Sigor@sysoev.ru 429*1061Sigor@sysoev.ru if (mtcf.arguments != NULL) { 430*1061Sigor@sysoev.ru table = nxt_http_route_table_create(task, mp, mtcf.arguments, 431*1061Sigor@sysoev.ru NXT_HTTP_ROUTE_ARGUMENT, 1); 4321059Sigor@sysoev.ru if (table == NULL) { 4331059Sigor@sysoev.ru return NULL; 4341059Sigor@sysoev.ru } 4351059Sigor@sysoev.ru 4361059Sigor@sysoev.ru test->table = table; 4371059Sigor@sysoev.ru test++; 438964Sigor@sysoev.ru } 439964Sigor@sysoev.ru 440964Sigor@sysoev.ru return match; 441964Sigor@sysoev.ru } 442964Sigor@sysoev.ru 443964Sigor@sysoev.ru 4441059Sigor@sysoev.ru static nxt_http_route_table_t * 4451059Sigor@sysoev.ru nxt_http_route_table_create(nxt_task_t *task, nxt_mp_t *mp, 446*1061Sigor@sysoev.ru nxt_conf_value_t *table_cv, nxt_http_route_object_t object, 447*1061Sigor@sysoev.ru nxt_bool_t case_sensitive) 4481059Sigor@sysoev.ru { 4491059Sigor@sysoev.ru size_t size; 4501059Sigor@sysoev.ru uint32_t i, n; 4511059Sigor@sysoev.ru nxt_bool_t array; 4521059Sigor@sysoev.ru nxt_conf_value_t *ruleset_cv; 4531059Sigor@sysoev.ru nxt_http_route_table_t *table; 4541059Sigor@sysoev.ru nxt_http_route_ruleset_t *ruleset; 4551059Sigor@sysoev.ru 4561059Sigor@sysoev.ru array = (nxt_conf_type(table_cv) == NXT_CONF_ARRAY); 4571059Sigor@sysoev.ru n = array ? nxt_conf_array_elements_count(table_cv) : 1; 4581059Sigor@sysoev.ru size = sizeof(nxt_http_route_table_t) 4591059Sigor@sysoev.ru + n * sizeof(nxt_http_route_ruleset_t *); 4601059Sigor@sysoev.ru 4611059Sigor@sysoev.ru table = nxt_mp_alloc(mp, size); 4621059Sigor@sysoev.ru if (nxt_slow_path(table == NULL)) { 4631059Sigor@sysoev.ru return NULL; 4641059Sigor@sysoev.ru } 4651059Sigor@sysoev.ru 4661059Sigor@sysoev.ru table->items = n; 4671059Sigor@sysoev.ru table->object = NXT_HTTP_ROUTE_TABLE; 4681059Sigor@sysoev.ru 4691059Sigor@sysoev.ru if (!array) { 470*1061Sigor@sysoev.ru ruleset = nxt_http_route_ruleset_create(task, mp, table_cv, 471*1061Sigor@sysoev.ru object, case_sensitive); 4721059Sigor@sysoev.ru if (nxt_slow_path(ruleset == NULL)) { 4731059Sigor@sysoev.ru return NULL; 4741059Sigor@sysoev.ru } 4751059Sigor@sysoev.ru 4761059Sigor@sysoev.ru table->ruleset[0] = ruleset; 4771059Sigor@sysoev.ru 4781059Sigor@sysoev.ru return table; 4791059Sigor@sysoev.ru } 4801059Sigor@sysoev.ru 4811059Sigor@sysoev.ru for (i = 0; i < n; i++) { 4821059Sigor@sysoev.ru ruleset_cv = nxt_conf_get_array_element(table_cv, i); 4831059Sigor@sysoev.ru 484*1061Sigor@sysoev.ru ruleset = nxt_http_route_ruleset_create(task, mp, ruleset_cv, 485*1061Sigor@sysoev.ru object, case_sensitive); 4861059Sigor@sysoev.ru if (nxt_slow_path(ruleset == NULL)) { 4871059Sigor@sysoev.ru return NULL; 4881059Sigor@sysoev.ru } 4891059Sigor@sysoev.ru 4901059Sigor@sysoev.ru table->ruleset[i] = ruleset; 4911059Sigor@sysoev.ru } 4921059Sigor@sysoev.ru 4931059Sigor@sysoev.ru return table; 4941059Sigor@sysoev.ru } 4951059Sigor@sysoev.ru 4961059Sigor@sysoev.ru 4971059Sigor@sysoev.ru static nxt_http_route_ruleset_t * 4981059Sigor@sysoev.ru nxt_http_route_ruleset_create(nxt_task_t *task, nxt_mp_t *mp, 499*1061Sigor@sysoev.ru nxt_conf_value_t *ruleset_cv, nxt_http_route_object_t object, 500*1061Sigor@sysoev.ru nxt_bool_t case_sensitive) 5011059Sigor@sysoev.ru { 5021059Sigor@sysoev.ru size_t size; 5031059Sigor@sysoev.ru uint32_t i, n, next; 5041059Sigor@sysoev.ru nxt_str_t name; 5051059Sigor@sysoev.ru nxt_conf_value_t *rule_cv; 5061059Sigor@sysoev.ru nxt_http_route_rule_t *rule; 5071059Sigor@sysoev.ru nxt_http_route_ruleset_t *ruleset; 5081059Sigor@sysoev.ru 5091059Sigor@sysoev.ru n = nxt_conf_object_members_count(ruleset_cv); 5101059Sigor@sysoev.ru size = sizeof(nxt_http_route_ruleset_t) 5111059Sigor@sysoev.ru + n * sizeof(nxt_http_route_rule_t *); 5121059Sigor@sysoev.ru 5131059Sigor@sysoev.ru ruleset = nxt_mp_alloc(mp, size); 5141059Sigor@sysoev.ru if (nxt_slow_path(ruleset == NULL)) { 5151059Sigor@sysoev.ru return NULL; 5161059Sigor@sysoev.ru } 5171059Sigor@sysoev.ru 5181059Sigor@sysoev.ru ruleset->items = n; 5191059Sigor@sysoev.ru 5201059Sigor@sysoev.ru next = 0; 5211059Sigor@sysoev.ru 5221059Sigor@sysoev.ru for (i = 0; i < n; i++) { 5231059Sigor@sysoev.ru rule_cv = nxt_conf_next_object_member(ruleset_cv, &name, &next); 5241059Sigor@sysoev.ru 525*1061Sigor@sysoev.ru rule = nxt_http_route_rule_name_create(task, mp, rule_cv, &name, 526*1061Sigor@sysoev.ru case_sensitive); 5271059Sigor@sysoev.ru if (nxt_slow_path(rule == NULL)) { 5281059Sigor@sysoev.ru return NULL; 5291059Sigor@sysoev.ru } 5301059Sigor@sysoev.ru 531*1061Sigor@sysoev.ru rule->object = object; 5321059Sigor@sysoev.ru ruleset->rule[i] = rule; 5331059Sigor@sysoev.ru } 5341059Sigor@sysoev.ru 5351059Sigor@sysoev.ru return ruleset; 5361059Sigor@sysoev.ru } 5371059Sigor@sysoev.ru 5381059Sigor@sysoev.ru 539964Sigor@sysoev.ru static nxt_http_route_rule_t * 540*1061Sigor@sysoev.ru nxt_http_route_rule_name_create(nxt_task_t *task, nxt_mp_t *mp, 541*1061Sigor@sysoev.ru nxt_conf_value_t *rule_cv, nxt_str_t *name, nxt_bool_t case_sensitive) 5421059Sigor@sysoev.ru { 5431059Sigor@sysoev.ru u_char c, *p; 5441059Sigor@sysoev.ru uint32_t hash; 5451059Sigor@sysoev.ru nxt_uint_t i; 5461059Sigor@sysoev.ru nxt_http_route_rule_t *rule; 5471059Sigor@sysoev.ru 548*1061Sigor@sysoev.ru rule = nxt_http_route_rule_create(task, mp, rule_cv, case_sensitive, 5491059Sigor@sysoev.ru NXT_HTTP_ROUTE_PATTERN_NOCASE); 5501059Sigor@sysoev.ru if (nxt_slow_path(rule == NULL)) { 5511059Sigor@sysoev.ru return NULL; 5521059Sigor@sysoev.ru } 5531059Sigor@sysoev.ru 5541059Sigor@sysoev.ru rule->u.name.length = name->length; 5551059Sigor@sysoev.ru 5561059Sigor@sysoev.ru p = nxt_mp_nget(mp, name->length); 5571059Sigor@sysoev.ru if (nxt_slow_path(p == NULL)) { 5581059Sigor@sysoev.ru return NULL; 5591059Sigor@sysoev.ru } 5601059Sigor@sysoev.ru 5611059Sigor@sysoev.ru rule->u.name.start = p; 5621059Sigor@sysoev.ru 5631059Sigor@sysoev.ru hash = NXT_HTTP_FIELD_HASH_INIT; 5641059Sigor@sysoev.ru 5651059Sigor@sysoev.ru for (i = 0; i < name->length; i++) { 5661059Sigor@sysoev.ru c = name->start[i]; 5671059Sigor@sysoev.ru *p++ = c; 5681059Sigor@sysoev.ru 5691059Sigor@sysoev.ru c = nxt_lowcase(c); 5701059Sigor@sysoev.ru hash = nxt_http_field_hash_char(hash, c); 5711059Sigor@sysoev.ru } 5721059Sigor@sysoev.ru 5731059Sigor@sysoev.ru rule->u.name.hash = nxt_http_field_hash_end(hash) & 0xFFFF; 5741059Sigor@sysoev.ru 5751059Sigor@sysoev.ru return rule; 5761059Sigor@sysoev.ru } 5771059Sigor@sysoev.ru 5781059Sigor@sysoev.ru 5791059Sigor@sysoev.ru static nxt_http_route_rule_t * 5801059Sigor@sysoev.ru nxt_http_route_rule_create(nxt_task_t *task, nxt_mp_t *mp, 581964Sigor@sysoev.ru nxt_conf_value_t *cv, nxt_bool_t case_sensitive, 582964Sigor@sysoev.ru nxt_http_route_pattern_case_t pattern_case) 583964Sigor@sysoev.ru { 584964Sigor@sysoev.ru size_t size; 585964Sigor@sysoev.ru uint32_t i, n; 586964Sigor@sysoev.ru nxt_int_t ret; 587964Sigor@sysoev.ru nxt_bool_t string; 588964Sigor@sysoev.ru nxt_conf_value_t *value; 589964Sigor@sysoev.ru nxt_http_route_rule_t *rule; 590964Sigor@sysoev.ru nxt_http_route_pattern_t *pattern; 591964Sigor@sysoev.ru 592964Sigor@sysoev.ru string = (nxt_conf_type(cv) != NXT_CONF_ARRAY); 593964Sigor@sysoev.ru n = string ? 1 : nxt_conf_array_elements_count(cv); 594964Sigor@sysoev.ru size = sizeof(nxt_http_route_rule_t) + n * sizeof(nxt_http_route_pattern_t); 595964Sigor@sysoev.ru 596964Sigor@sysoev.ru rule = nxt_mp_alloc(mp, size); 597964Sigor@sysoev.ru if (nxt_slow_path(rule == NULL)) { 598964Sigor@sysoev.ru return NULL; 599964Sigor@sysoev.ru } 600964Sigor@sysoev.ru 601964Sigor@sysoev.ru rule->items = n; 602964Sigor@sysoev.ru 603964Sigor@sysoev.ru pattern = &rule->pattern[0]; 604964Sigor@sysoev.ru 605964Sigor@sysoev.ru if (string) { 606964Sigor@sysoev.ru pattern[0].case_sensitive = case_sensitive; 607964Sigor@sysoev.ru ret = nxt_http_route_pattern_create(task, mp, cv, &pattern[0], 608964Sigor@sysoev.ru pattern_case); 609964Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 610964Sigor@sysoev.ru return NULL; 611964Sigor@sysoev.ru } 612964Sigor@sysoev.ru 613964Sigor@sysoev.ru return rule; 614964Sigor@sysoev.ru } 615964Sigor@sysoev.ru 616964Sigor@sysoev.ru nxt_conf_array_qsort(cv, nxt_http_pattern_compare); 617964Sigor@sysoev.ru 618964Sigor@sysoev.ru for (i = 0; i < n; i++) { 619964Sigor@sysoev.ru pattern[i].case_sensitive = case_sensitive; 620964Sigor@sysoev.ru value = nxt_conf_get_array_element(cv, i); 621964Sigor@sysoev.ru 622964Sigor@sysoev.ru ret = nxt_http_route_pattern_create(task, mp, value, &pattern[i], 623964Sigor@sysoev.ru pattern_case); 624964Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 625964Sigor@sysoev.ru return NULL; 626964Sigor@sysoev.ru } 627964Sigor@sysoev.ru } 628964Sigor@sysoev.ru 629964Sigor@sysoev.ru return rule; 630964Sigor@sysoev.ru } 631964Sigor@sysoev.ru 632964Sigor@sysoev.ru 633964Sigor@sysoev.ru static int 634964Sigor@sysoev.ru nxt_http_pattern_compare(const void *one, const void *two) 635964Sigor@sysoev.ru { 636964Sigor@sysoev.ru nxt_str_t test; 637964Sigor@sysoev.ru nxt_bool_t negative1, negative2; 638964Sigor@sysoev.ru nxt_conf_value_t *value; 639964Sigor@sysoev.ru 640964Sigor@sysoev.ru value = (nxt_conf_value_t *) one; 641964Sigor@sysoev.ru nxt_conf_get_string(value, &test); 642964Sigor@sysoev.ru negative1 = (test.length != 0 && test.start[0] == '!'); 643964Sigor@sysoev.ru 644964Sigor@sysoev.ru value = (nxt_conf_value_t *) two; 645964Sigor@sysoev.ru nxt_conf_get_string(value, &test); 646964Sigor@sysoev.ru negative2 = (test.length != 0 && test.start[0] == '!'); 647964Sigor@sysoev.ru 648964Sigor@sysoev.ru return (negative2 - negative1); 649964Sigor@sysoev.ru } 650964Sigor@sysoev.ru 651964Sigor@sysoev.ru 652964Sigor@sysoev.ru static nxt_int_t 653964Sigor@sysoev.ru nxt_http_route_pattern_create(nxt_task_t *task, nxt_mp_t *mp, 654964Sigor@sysoev.ru nxt_conf_value_t *cv, nxt_http_route_pattern_t *pattern, 655964Sigor@sysoev.ru nxt_http_route_pattern_case_t pattern_case) 656964Sigor@sysoev.ru { 657964Sigor@sysoev.ru u_char *start; 658964Sigor@sysoev.ru nxt_str_t test; 6591032Sigor@sysoev.ru nxt_uint_t n, length; 660964Sigor@sysoev.ru nxt_http_route_pattern_type_t type; 661964Sigor@sysoev.ru 6621032Sigor@sysoev.ru /* Suppress warning about uninitialized variable. */ 6631032Sigor@sysoev.ru length = 0; 6641032Sigor@sysoev.ru 665964Sigor@sysoev.ru type = NXT_HTTP_ROUTE_PATTERN_EXACT; 666964Sigor@sysoev.ru 667964Sigor@sysoev.ru nxt_conf_get_string(cv, &test); 668964Sigor@sysoev.ru 669964Sigor@sysoev.ru pattern->negative = 0; 670964Sigor@sysoev.ru pattern->any = 1; 671964Sigor@sysoev.ru 672964Sigor@sysoev.ru if (test.length != 0) { 673964Sigor@sysoev.ru 674964Sigor@sysoev.ru if (test.start[0] == '!') { 675964Sigor@sysoev.ru test.start++; 676964Sigor@sysoev.ru test.length--; 677964Sigor@sysoev.ru 678964Sigor@sysoev.ru pattern->negative = 1; 679964Sigor@sysoev.ru pattern->any = 0; 680964Sigor@sysoev.ru } 681964Sigor@sysoev.ru 682964Sigor@sysoev.ru if (test.length != 0) { 683964Sigor@sysoev.ru 684964Sigor@sysoev.ru if (test.start[0] == '*') { 685964Sigor@sysoev.ru test.start++; 686964Sigor@sysoev.ru test.length--; 687964Sigor@sysoev.ru 688964Sigor@sysoev.ru if (test.length != 0) { 689964Sigor@sysoev.ru if (test.start[test.length - 1] == '*') { 690964Sigor@sysoev.ru test.length--; 691964Sigor@sysoev.ru type = NXT_HTTP_ROUTE_PATTERN_SUBSTRING; 692964Sigor@sysoev.ru 693964Sigor@sysoev.ru } else { 694964Sigor@sysoev.ru type = NXT_HTTP_ROUTE_PATTERN_END; 695964Sigor@sysoev.ru } 696964Sigor@sysoev.ru 697964Sigor@sysoev.ru } else { 698964Sigor@sysoev.ru type = NXT_HTTP_ROUTE_PATTERN_BEGIN; 699964Sigor@sysoev.ru } 700964Sigor@sysoev.ru 701964Sigor@sysoev.ru } else if (test.start[test.length - 1] == '*') { 702964Sigor@sysoev.ru test.length--; 703964Sigor@sysoev.ru type = NXT_HTTP_ROUTE_PATTERN_BEGIN; 7041032Sigor@sysoev.ru 7051032Sigor@sysoev.ru } else { 7061032Sigor@sysoev.ru length = test.length - 1; 7071032Sigor@sysoev.ru 7081032Sigor@sysoev.ru for (n = 1; n < length; n++) { 7091032Sigor@sysoev.ru if (test.start[n] == '*') { 7101032Sigor@sysoev.ru test.length = n; 7111032Sigor@sysoev.ru type = NXT_HTTP_ROUTE_PATTERN_MIDDLE; 7121032Sigor@sysoev.ru break; 7131032Sigor@sysoev.ru } 7141032Sigor@sysoev.ru } 715964Sigor@sysoev.ru } 716964Sigor@sysoev.ru } 717964Sigor@sysoev.ru } 718964Sigor@sysoev.ru 719964Sigor@sysoev.ru pattern->type = type; 720964Sigor@sysoev.ru pattern->min_length = test.length; 7211032Sigor@sysoev.ru pattern->length1 = test.length; 722964Sigor@sysoev.ru 7231032Sigor@sysoev.ru start = nxt_http_route_pattern_copy(mp, &test, pattern_case); 724964Sigor@sysoev.ru if (nxt_slow_path(start == NULL)) { 725964Sigor@sysoev.ru return NXT_ERROR; 726964Sigor@sysoev.ru } 727964Sigor@sysoev.ru 7281032Sigor@sysoev.ru pattern->start1 = start; 7291032Sigor@sysoev.ru 7301032Sigor@sysoev.ru if (type == NXT_HTTP_ROUTE_PATTERN_MIDDLE) { 7311032Sigor@sysoev.ru length -= test.length; 7321032Sigor@sysoev.ru pattern->length2 = length; 7331032Sigor@sysoev.ru pattern->min_length += length; 7341032Sigor@sysoev.ru 7351032Sigor@sysoev.ru test.start = &test.start[test.length + 1]; 7361032Sigor@sysoev.ru test.length = length; 7371032Sigor@sysoev.ru 7381032Sigor@sysoev.ru start = nxt_http_route_pattern_copy(mp, &test, pattern_case); 7391032Sigor@sysoev.ru if (nxt_slow_path(start == NULL)) { 7401032Sigor@sysoev.ru return NXT_ERROR; 7411032Sigor@sysoev.ru } 7421032Sigor@sysoev.ru 7431032Sigor@sysoev.ru pattern->start2 = start; 7441032Sigor@sysoev.ru } 7451032Sigor@sysoev.ru 7461032Sigor@sysoev.ru return NXT_OK; 7471032Sigor@sysoev.ru } 7481032Sigor@sysoev.ru 7491032Sigor@sysoev.ru 7501032Sigor@sysoev.ru static u_char * 7511032Sigor@sysoev.ru nxt_http_route_pattern_copy(nxt_mp_t *mp, nxt_str_t *test, 7521032Sigor@sysoev.ru nxt_http_route_pattern_case_t pattern_case) 7531032Sigor@sysoev.ru { 7541032Sigor@sysoev.ru u_char *start; 7551032Sigor@sysoev.ru 7561032Sigor@sysoev.ru start = nxt_mp_nget(mp, test->length); 7571032Sigor@sysoev.ru if (nxt_slow_path(start == NULL)) { 7581032Sigor@sysoev.ru return start; 7591032Sigor@sysoev.ru } 760964Sigor@sysoev.ru 761964Sigor@sysoev.ru switch (pattern_case) { 762964Sigor@sysoev.ru 763964Sigor@sysoev.ru case NXT_HTTP_ROUTE_PATTERN_UPCASE: 7641032Sigor@sysoev.ru nxt_memcpy_upcase(start, test->start, test->length); 765964Sigor@sysoev.ru break; 766964Sigor@sysoev.ru 767964Sigor@sysoev.ru case NXT_HTTP_ROUTE_PATTERN_LOWCASE: 7681032Sigor@sysoev.ru nxt_memcpy_lowcase(start, test->start, test->length); 769964Sigor@sysoev.ru break; 770964Sigor@sysoev.ru 771964Sigor@sysoev.ru case NXT_HTTP_ROUTE_PATTERN_NOCASE: 7721032Sigor@sysoev.ru nxt_memcpy(start, test->start, test->length); 773964Sigor@sysoev.ru break; 774964Sigor@sysoev.ru } 775964Sigor@sysoev.ru 7761032Sigor@sysoev.ru return start; 777964Sigor@sysoev.ru } 778964Sigor@sysoev.ru 779964Sigor@sysoev.ru 780964Sigor@sysoev.ru void 781964Sigor@sysoev.ru nxt_http_routes_resolve(nxt_task_t *task, nxt_router_temp_conf_t *tmcf) 782964Sigor@sysoev.ru { 7831033Svbart@nginx.com nxt_http_route_t **route, **end; 784964Sigor@sysoev.ru nxt_http_routes_t *routes; 785964Sigor@sysoev.ru 786964Sigor@sysoev.ru routes = tmcf->router_conf->routes; 7871059Sigor@sysoev.ru 788964Sigor@sysoev.ru if (routes != NULL) { 789964Sigor@sysoev.ru route = &routes->route[0]; 7901033Svbart@nginx.com end = route + routes->items; 791964Sigor@sysoev.ru 7921033Svbart@nginx.com while (route < end) { 793964Sigor@sysoev.ru nxt_http_route_resolve(task, tmcf, *route); 794964Sigor@sysoev.ru 795964Sigor@sysoev.ru route++; 796964Sigor@sysoev.ru } 797964Sigor@sysoev.ru } 798964Sigor@sysoev.ru } 799964Sigor@sysoev.ru 800964Sigor@sysoev.ru 801964Sigor@sysoev.ru static void 802964Sigor@sysoev.ru nxt_http_route_resolve(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 803964Sigor@sysoev.ru nxt_http_route_t *route) 804964Sigor@sysoev.ru { 8051033Svbart@nginx.com nxt_http_route_match_t **match, **end; 806964Sigor@sysoev.ru 807964Sigor@sysoev.ru match = &route->match[0]; 8081033Svbart@nginx.com end = match + route->items; 809964Sigor@sysoev.ru 8101033Svbart@nginx.com while (match < end) { 811964Sigor@sysoev.ru nxt_http_pass_resolve(task, tmcf, &(*match)->pass); 812964Sigor@sysoev.ru 813964Sigor@sysoev.ru match++; 814964Sigor@sysoev.ru } 815964Sigor@sysoev.ru } 816964Sigor@sysoev.ru 817964Sigor@sysoev.ru 818964Sigor@sysoev.ru static void 819964Sigor@sysoev.ru nxt_http_pass_resolve(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 820964Sigor@sysoev.ru nxt_http_pass_t *pass) 821964Sigor@sysoev.ru { 822964Sigor@sysoev.ru nxt_str_t name; 823964Sigor@sysoev.ru 824964Sigor@sysoev.ru name = pass->name; 825964Sigor@sysoev.ru 826964Sigor@sysoev.ru if (nxt_str_start(&name, "applications/", 13)) { 827964Sigor@sysoev.ru name.length -= 13; 828964Sigor@sysoev.ru name.start += 13; 829964Sigor@sysoev.ru 830964Sigor@sysoev.ru pass->u.application = nxt_router_listener_application(tmcf, &name); 831964Sigor@sysoev.ru nxt_router_app_use(task, pass->u.application, 1); 832964Sigor@sysoev.ru 833964Sigor@sysoev.ru pass->handler = nxt_http_request_application; 834964Sigor@sysoev.ru 835964Sigor@sysoev.ru } else if (nxt_str_start(&name, "routes", 6)) { 836964Sigor@sysoev.ru 837964Sigor@sysoev.ru if (name.length == 6) { 838964Sigor@sysoev.ru name.length = 0; 839964Sigor@sysoev.ru name.start = NULL; 840964Sigor@sysoev.ru 841964Sigor@sysoev.ru } else if (name.start[6] == '/') { 842964Sigor@sysoev.ru name.length -= 7; 843964Sigor@sysoev.ru name.start += 7; 844964Sigor@sysoev.ru } 845964Sigor@sysoev.ru 846964Sigor@sysoev.ru pass->u.route = nxt_http_route_find(tmcf->router_conf->routes, &name); 847964Sigor@sysoev.ru 848964Sigor@sysoev.ru pass->handler = nxt_http_route_pass; 849964Sigor@sysoev.ru } 850964Sigor@sysoev.ru } 851964Sigor@sysoev.ru 852964Sigor@sysoev.ru 853964Sigor@sysoev.ru static nxt_http_route_t * 854964Sigor@sysoev.ru nxt_http_route_find(nxt_http_routes_t *routes, nxt_str_t *name) 855964Sigor@sysoev.ru { 8561033Svbart@nginx.com nxt_http_route_t **route, **end; 857964Sigor@sysoev.ru 858964Sigor@sysoev.ru route = &routes->route[0]; 8591033Svbart@nginx.com end = route + routes->items; 860964Sigor@sysoev.ru 8611058Sigor@sysoev.ru while (route < end) { 862964Sigor@sysoev.ru if (nxt_strstr_eq(&(*route)->name, name)) { 863964Sigor@sysoev.ru return *route; 864964Sigor@sysoev.ru } 865964Sigor@sysoev.ru 866964Sigor@sysoev.ru route++; 8671058Sigor@sysoev.ru } 868964Sigor@sysoev.ru 869964Sigor@sysoev.ru return NULL; 870964Sigor@sysoev.ru } 871964Sigor@sysoev.ru 872964Sigor@sysoev.ru 873964Sigor@sysoev.ru nxt_http_pass_t * 874964Sigor@sysoev.ru nxt_http_pass_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 875964Sigor@sysoev.ru nxt_str_t *name) 876964Sigor@sysoev.ru { 877964Sigor@sysoev.ru nxt_http_pass_t *pass; 878964Sigor@sysoev.ru 879964Sigor@sysoev.ru pass = nxt_mp_alloc(tmcf->router_conf->mem_pool, sizeof(nxt_http_pass_t)); 880964Sigor@sysoev.ru if (nxt_slow_path(pass == NULL)) { 881964Sigor@sysoev.ru return NULL; 882964Sigor@sysoev.ru } 883964Sigor@sysoev.ru 884964Sigor@sysoev.ru pass->name = *name; 885964Sigor@sysoev.ru 886964Sigor@sysoev.ru nxt_http_pass_resolve(task, tmcf, pass); 887964Sigor@sysoev.ru 888964Sigor@sysoev.ru return pass; 889964Sigor@sysoev.ru } 890964Sigor@sysoev.ru 891964Sigor@sysoev.ru 892964Sigor@sysoev.ru /* COMPATIBILITY: listener application. */ 893964Sigor@sysoev.ru 894964Sigor@sysoev.ru nxt_http_pass_t * 895964Sigor@sysoev.ru nxt_http_pass_application(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 896964Sigor@sysoev.ru nxt_str_t *name) 897964Sigor@sysoev.ru { 898964Sigor@sysoev.ru nxt_http_pass_t *pass; 899964Sigor@sysoev.ru 900964Sigor@sysoev.ru pass = nxt_mp_alloc(tmcf->router_conf->mem_pool, sizeof(nxt_http_pass_t)); 901964Sigor@sysoev.ru if (nxt_slow_path(pass == NULL)) { 902964Sigor@sysoev.ru return NULL; 903964Sigor@sysoev.ru } 904964Sigor@sysoev.ru 905964Sigor@sysoev.ru pass->name = *name; 906964Sigor@sysoev.ru 907964Sigor@sysoev.ru pass->u.application = nxt_router_listener_application(tmcf, name); 908964Sigor@sysoev.ru nxt_router_app_use(task, pass->u.application, 1); 909964Sigor@sysoev.ru 910964Sigor@sysoev.ru pass->handler = nxt_http_request_application; 911964Sigor@sysoev.ru 912964Sigor@sysoev.ru return pass; 913964Sigor@sysoev.ru } 914964Sigor@sysoev.ru 915964Sigor@sysoev.ru 916964Sigor@sysoev.ru void 917964Sigor@sysoev.ru nxt_http_routes_cleanup(nxt_task_t *task, nxt_http_routes_t *routes) 918964Sigor@sysoev.ru { 9191033Svbart@nginx.com nxt_http_route_t **route, **end; 920964Sigor@sysoev.ru 921964Sigor@sysoev.ru if (routes != NULL) { 922964Sigor@sysoev.ru route = &routes->route[0]; 9231033Svbart@nginx.com end = route + routes->items; 924964Sigor@sysoev.ru 9251058Sigor@sysoev.ru while (route < end) { 926964Sigor@sysoev.ru nxt_http_route_cleanup(task, *route); 927964Sigor@sysoev.ru 928964Sigor@sysoev.ru route++; 9291058Sigor@sysoev.ru } 930964Sigor@sysoev.ru } 931964Sigor@sysoev.ru } 932964Sigor@sysoev.ru 933964Sigor@sysoev.ru 934964Sigor@sysoev.ru static void 935964Sigor@sysoev.ru nxt_http_route_cleanup(nxt_task_t *task, nxt_http_route_t *route) 936964Sigor@sysoev.ru { 9371033Svbart@nginx.com nxt_http_route_match_t **match, **end; 938964Sigor@sysoev.ru 939964Sigor@sysoev.ru match = &route->match[0]; 9401033Svbart@nginx.com end = match + route->items; 941964Sigor@sysoev.ru 9421058Sigor@sysoev.ru while (match < end) { 943964Sigor@sysoev.ru nxt_http_pass_cleanup(task, &(*match)->pass); 944964Sigor@sysoev.ru 945964Sigor@sysoev.ru match++; 9461058Sigor@sysoev.ru } 947964Sigor@sysoev.ru } 948964Sigor@sysoev.ru 949964Sigor@sysoev.ru 950964Sigor@sysoev.ru void 951964Sigor@sysoev.ru nxt_http_pass_cleanup(nxt_task_t *task, nxt_http_pass_t *pass) 952964Sigor@sysoev.ru { 953964Sigor@sysoev.ru if (pass->handler == nxt_http_request_application) { 954964Sigor@sysoev.ru nxt_router_app_use(task, pass->u.application, -1); 955964Sigor@sysoev.ru } 956964Sigor@sysoev.ru } 957964Sigor@sysoev.ru 958964Sigor@sysoev.ru 959964Sigor@sysoev.ru static nxt_http_pass_t * 960964Sigor@sysoev.ru nxt_http_route_pass(nxt_task_t *task, nxt_http_request_t *r, 961964Sigor@sysoev.ru nxt_http_pass_t *start) 962964Sigor@sysoev.ru { 963964Sigor@sysoev.ru nxt_http_pass_t *pass; 964964Sigor@sysoev.ru nxt_http_route_t *route; 9651033Svbart@nginx.com nxt_http_route_match_t **match, **end; 966964Sigor@sysoev.ru 967964Sigor@sysoev.ru route = start->u.route; 968964Sigor@sysoev.ru match = &route->match[0]; 9691033Svbart@nginx.com end = match + route->items; 970964Sigor@sysoev.ru 9711033Svbart@nginx.com while (match < end) { 972964Sigor@sysoev.ru pass = nxt_http_route_match(r, *match); 973964Sigor@sysoev.ru if (pass != NULL) { 974964Sigor@sysoev.ru return pass; 975964Sigor@sysoev.ru } 976964Sigor@sysoev.ru 977964Sigor@sysoev.ru match++; 978964Sigor@sysoev.ru } 979964Sigor@sysoev.ru 980964Sigor@sysoev.ru nxt_http_request_error(task, r, NXT_HTTP_NOT_FOUND); 981964Sigor@sysoev.ru 982964Sigor@sysoev.ru return NULL; 983964Sigor@sysoev.ru } 984964Sigor@sysoev.ru 985964Sigor@sysoev.ru 986964Sigor@sysoev.ru static nxt_http_pass_t * 987964Sigor@sysoev.ru nxt_http_route_match(nxt_http_request_t *r, nxt_http_route_match_t *match) 988964Sigor@sysoev.ru { 9891060Sigor@sysoev.ru nxt_int_t ret; 9901059Sigor@sysoev.ru nxt_http_route_test_t *test, *end; 9911059Sigor@sysoev.ru 9921059Sigor@sysoev.ru test = &match->test[0]; 9931059Sigor@sysoev.ru end = test + match->items; 994964Sigor@sysoev.ru 9951059Sigor@sysoev.ru while (test < end) { 9961059Sigor@sysoev.ru if (test->rule->object != NXT_HTTP_ROUTE_TABLE) { 9971059Sigor@sysoev.ru ret = nxt_http_route_rule(r, test->rule); 998964Sigor@sysoev.ru 9991059Sigor@sysoev.ru } else { 10001059Sigor@sysoev.ru ret = nxt_http_route_table(r, test->table); 10011059Sigor@sysoev.ru } 10021059Sigor@sysoev.ru 10031060Sigor@sysoev.ru if (ret <= 0) { 10041060Sigor@sysoev.ru /* 0 => NULL, -1 => NXT_HTTP_PASS_ERROR. */ 10051060Sigor@sysoev.ru return (nxt_http_pass_t *) (intptr_t) ret; 1006964Sigor@sysoev.ru } 1007964Sigor@sysoev.ru 10081059Sigor@sysoev.ru test++; 1009964Sigor@sysoev.ru } 1010964Sigor@sysoev.ru 1011964Sigor@sysoev.ru return &match->pass; 1012964Sigor@sysoev.ru } 1013964Sigor@sysoev.ru 1014964Sigor@sysoev.ru 10151060Sigor@sysoev.ru static nxt_int_t 10161059Sigor@sysoev.ru nxt_http_route_table(nxt_http_request_t *r, nxt_http_route_table_t *table) 1017964Sigor@sysoev.ru { 10181060Sigor@sysoev.ru nxt_int_t ret; 10191059Sigor@sysoev.ru nxt_http_route_ruleset_t **ruleset, **end; 10201059Sigor@sysoev.ru 10211059Sigor@sysoev.ru ret = 1; 10221059Sigor@sysoev.ru ruleset = &table->ruleset[0]; 10231059Sigor@sysoev.ru end = ruleset + table->items; 10241059Sigor@sysoev.ru 10251059Sigor@sysoev.ru while (ruleset < end) { 10261059Sigor@sysoev.ru ret = nxt_http_route_ruleset(r, *ruleset); 10271059Sigor@sysoev.ru 10281060Sigor@sysoev.ru if (ret != 0) { 10291059Sigor@sysoev.ru return ret; 10301059Sigor@sysoev.ru } 1031964Sigor@sysoev.ru 10321059Sigor@sysoev.ru ruleset++; 10331059Sigor@sysoev.ru } 10341059Sigor@sysoev.ru 10351059Sigor@sysoev.ru return ret; 10361059Sigor@sysoev.ru } 10371059Sigor@sysoev.ru 1038964Sigor@sysoev.ru 10391060Sigor@sysoev.ru static nxt_int_t 10401059Sigor@sysoev.ru nxt_http_route_ruleset(nxt_http_request_t *r, nxt_http_route_ruleset_t *ruleset) 10411059Sigor@sysoev.ru { 10421060Sigor@sysoev.ru nxt_int_t ret; 10431059Sigor@sysoev.ru nxt_http_route_rule_t **rule, **end; 1044964Sigor@sysoev.ru 10451059Sigor@sysoev.ru rule = &ruleset->rule[0]; 10461059Sigor@sysoev.ru end = rule + ruleset->items; 1047964Sigor@sysoev.ru 10481059Sigor@sysoev.ru while (rule < end) { 10491060Sigor@sysoev.ru ret = nxt_http_route_rule(r, *rule); 10501060Sigor@sysoev.ru 10511060Sigor@sysoev.ru if (ret <= 0) { 10521060Sigor@sysoev.ru return ret; 1053964Sigor@sysoev.ru } 1054964Sigor@sysoev.ru 10551059Sigor@sysoev.ru rule++; 10561059Sigor@sysoev.ru } 10571059Sigor@sysoev.ru 10581059Sigor@sysoev.ru return 1; 10591059Sigor@sysoev.ru } 10601059Sigor@sysoev.ru 1061964Sigor@sysoev.ru 10621060Sigor@sysoev.ru static nxt_int_t 10631059Sigor@sysoev.ru nxt_http_route_rule(nxt_http_request_t *r, nxt_http_route_rule_t *rule) 10641059Sigor@sysoev.ru { 10651059Sigor@sysoev.ru void *p, **pp; 10661059Sigor@sysoev.ru u_char *start; 10671059Sigor@sysoev.ru size_t length; 10681059Sigor@sysoev.ru nxt_str_t *s; 10691059Sigor@sysoev.ru 10701059Sigor@sysoev.ru switch (rule->object) { 10711059Sigor@sysoev.ru 10721059Sigor@sysoev.ru case NXT_HTTP_ROUTE_HEADER: 10731059Sigor@sysoev.ru return nxt_http_route_header(r, rule); 1074964Sigor@sysoev.ru 10751059Sigor@sysoev.ru case NXT_HTTP_ROUTE_ARGUMENT: 1076*1061Sigor@sysoev.ru return nxt_http_route_arguments(r, rule); 1077964Sigor@sysoev.ru 10781059Sigor@sysoev.ru case NXT_HTTP_ROUTE_COOKIE: 10791059Sigor@sysoev.ru return 0; 10801059Sigor@sysoev.ru 10811059Sigor@sysoev.ru default: 10821059Sigor@sysoev.ru break; 10831059Sigor@sysoev.ru } 1084964Sigor@sysoev.ru 10851059Sigor@sysoev.ru p = nxt_pointer_to(r, rule->u.offset); 10861059Sigor@sysoev.ru 10871059Sigor@sysoev.ru if (rule->object == NXT_HTTP_ROUTE_STRING) { 10881059Sigor@sysoev.ru s = p; 1089964Sigor@sysoev.ru 10901059Sigor@sysoev.ru } else { 10911059Sigor@sysoev.ru /* NXT_HTTP_ROUTE_STRING_PTR */ 10921059Sigor@sysoev.ru pp = p; 10931059Sigor@sysoev.ru s = *pp; 1094964Sigor@sysoev.ru 10951059Sigor@sysoev.ru if (s == NULL) { 1096964Sigor@sysoev.ru return 0; 1097964Sigor@sysoev.ru } 1098964Sigor@sysoev.ru } 1099964Sigor@sysoev.ru 11001059Sigor@sysoev.ru length = s->length; 11011059Sigor@sysoev.ru start = s->start; 11021059Sigor@sysoev.ru 11031059Sigor@sysoev.ru return nxt_http_route_test_rule(r, rule, start, length); 11041059Sigor@sysoev.ru } 11051059Sigor@sysoev.ru 11061059Sigor@sysoev.ru 11071060Sigor@sysoev.ru static nxt_int_t 11081059Sigor@sysoev.ru nxt_http_route_header(nxt_http_request_t *r, nxt_http_route_rule_t *rule) 11091059Sigor@sysoev.ru { 11101060Sigor@sysoev.ru nxt_int_t ret; 11111059Sigor@sysoev.ru nxt_http_field_t *f; 11121059Sigor@sysoev.ru 11131059Sigor@sysoev.ru ret = 0; 11141059Sigor@sysoev.ru 11151059Sigor@sysoev.ru nxt_list_each(f, r->fields) { 11161059Sigor@sysoev.ru 11171059Sigor@sysoev.ru if (rule->u.name.hash != f->hash 11181059Sigor@sysoev.ru || rule->u.name.length != f->name_length 11191059Sigor@sysoev.ru || nxt_strncasecmp(rule->u.name.start, f->name, f->name_length) 11201059Sigor@sysoev.ru != 0) 11211059Sigor@sysoev.ru { 11221059Sigor@sysoev.ru continue; 11231059Sigor@sysoev.ru } 11241059Sigor@sysoev.ru 11251059Sigor@sysoev.ru ret = nxt_http_route_test_rule(r, rule, f->value, f->value_length); 11261059Sigor@sysoev.ru 11271060Sigor@sysoev.ru if (ret == 0) { 11281059Sigor@sysoev.ru return ret; 11291059Sigor@sysoev.ru } 11301059Sigor@sysoev.ru 11311059Sigor@sysoev.ru } nxt_list_loop; 11321059Sigor@sysoev.ru 11331059Sigor@sysoev.ru return ret; 11341059Sigor@sysoev.ru } 11351059Sigor@sysoev.ru 11361059Sigor@sysoev.ru 11371060Sigor@sysoev.ru static nxt_int_t 1138*1061Sigor@sysoev.ru nxt_http_route_arguments(nxt_http_request_t *r, nxt_http_route_rule_t *rule) 1139*1061Sigor@sysoev.ru { 1140*1061Sigor@sysoev.ru nxt_array_t *arguments; 1141*1061Sigor@sysoev.ru 1142*1061Sigor@sysoev.ru if (r->args == NULL) { 1143*1061Sigor@sysoev.ru return 0; 1144*1061Sigor@sysoev.ru } 1145*1061Sigor@sysoev.ru 1146*1061Sigor@sysoev.ru arguments = nxt_http_route_arguments_parse(r); 1147*1061Sigor@sysoev.ru if (nxt_slow_path(arguments == NULL)) { 1148*1061Sigor@sysoev.ru return -1; 1149*1061Sigor@sysoev.ru } 1150*1061Sigor@sysoev.ru 1151*1061Sigor@sysoev.ru return nxt_http_route_test_argument(r, rule, arguments); 1152*1061Sigor@sysoev.ru } 1153*1061Sigor@sysoev.ru 1154*1061Sigor@sysoev.ru 1155*1061Sigor@sysoev.ru static nxt_array_t * 1156*1061Sigor@sysoev.ru nxt_http_route_arguments_parse(nxt_http_request_t *r) 1157*1061Sigor@sysoev.ru { 1158*1061Sigor@sysoev.ru size_t name_length; 1159*1061Sigor@sysoev.ru u_char c, *p, *start, *end, *name; 1160*1061Sigor@sysoev.ru uint32_t hash; 1161*1061Sigor@sysoev.ru nxt_bool_t valid; 1162*1061Sigor@sysoev.ru nxt_array_t *args; 1163*1061Sigor@sysoev.ru nxt_http_name_value_t *nv; 1164*1061Sigor@sysoev.ru 1165*1061Sigor@sysoev.ru if (r->arguments != NULL) { 1166*1061Sigor@sysoev.ru return r->arguments; 1167*1061Sigor@sysoev.ru } 1168*1061Sigor@sysoev.ru 1169*1061Sigor@sysoev.ru args = nxt_array_create(r->mem_pool, 2, sizeof(nxt_http_name_value_t)); 1170*1061Sigor@sysoev.ru if (nxt_slow_path(args == NULL)) { 1171*1061Sigor@sysoev.ru return NULL; 1172*1061Sigor@sysoev.ru } 1173*1061Sigor@sysoev.ru 1174*1061Sigor@sysoev.ru hash = NXT_HTTP_FIELD_HASH_INIT; 1175*1061Sigor@sysoev.ru valid = 1; 1176*1061Sigor@sysoev.ru name = NULL; 1177*1061Sigor@sysoev.ru name_length = 0; 1178*1061Sigor@sysoev.ru 1179*1061Sigor@sysoev.ru start = r->args->start; 1180*1061Sigor@sysoev.ru end = start + r->args->length; 1181*1061Sigor@sysoev.ru 1182*1061Sigor@sysoev.ru for (p = start; p < end; p++) { 1183*1061Sigor@sysoev.ru c = *p; 1184*1061Sigor@sysoev.ru 1185*1061Sigor@sysoev.ru if (c == '=') { 1186*1061Sigor@sysoev.ru name_length = p - start; 1187*1061Sigor@sysoev.ru name = start; 1188*1061Sigor@sysoev.ru start = p + 1; 1189*1061Sigor@sysoev.ru valid = (name_length != 0); 1190*1061Sigor@sysoev.ru 1191*1061Sigor@sysoev.ru } else if (c == '&') { 1192*1061Sigor@sysoev.ru if (valid) { 1193*1061Sigor@sysoev.ru nv = nxt_http_route_argument(args, name, name_length, hash, 1194*1061Sigor@sysoev.ru start, p); 1195*1061Sigor@sysoev.ru if (nxt_slow_path(nv == NULL)) { 1196*1061Sigor@sysoev.ru return NULL; 1197*1061Sigor@sysoev.ru } 1198*1061Sigor@sysoev.ru } 1199*1061Sigor@sysoev.ru 1200*1061Sigor@sysoev.ru hash = NXT_HTTP_FIELD_HASH_INIT; 1201*1061Sigor@sysoev.ru valid = 1; 1202*1061Sigor@sysoev.ru name = NULL; 1203*1061Sigor@sysoev.ru start = p + 1; 1204*1061Sigor@sysoev.ru 1205*1061Sigor@sysoev.ru } else if (name == NULL) { 1206*1061Sigor@sysoev.ru hash = nxt_http_field_hash_char(hash, c); 1207*1061Sigor@sysoev.ru } 1208*1061Sigor@sysoev.ru } 1209*1061Sigor@sysoev.ru 1210*1061Sigor@sysoev.ru if (valid) { 1211*1061Sigor@sysoev.ru nv = nxt_http_route_argument(args, name, name_length, hash, start, p); 1212*1061Sigor@sysoev.ru if (nxt_slow_path(nv == NULL)) { 1213*1061Sigor@sysoev.ru return NULL; 1214*1061Sigor@sysoev.ru } 1215*1061Sigor@sysoev.ru } 1216*1061Sigor@sysoev.ru 1217*1061Sigor@sysoev.ru r->arguments = args; 1218*1061Sigor@sysoev.ru 1219*1061Sigor@sysoev.ru return args; 1220*1061Sigor@sysoev.ru } 1221*1061Sigor@sysoev.ru 1222*1061Sigor@sysoev.ru 1223*1061Sigor@sysoev.ru static nxt_http_name_value_t * 1224*1061Sigor@sysoev.ru nxt_http_route_argument(nxt_array_t *array, u_char *name, size_t name_length, 1225*1061Sigor@sysoev.ru uint32_t hash, u_char *start, u_char *end) 1226*1061Sigor@sysoev.ru { 1227*1061Sigor@sysoev.ru size_t length; 1228*1061Sigor@sysoev.ru nxt_http_name_value_t *nv; 1229*1061Sigor@sysoev.ru 1230*1061Sigor@sysoev.ru nv = nxt_array_add(array); 1231*1061Sigor@sysoev.ru if (nxt_slow_path(nv == NULL)) { 1232*1061Sigor@sysoev.ru return NULL; 1233*1061Sigor@sysoev.ru } 1234*1061Sigor@sysoev.ru 1235*1061Sigor@sysoev.ru nv->hash = nxt_http_field_hash_end(hash) & 0xFFFF; 1236*1061Sigor@sysoev.ru 1237*1061Sigor@sysoev.ru length = end - start; 1238*1061Sigor@sysoev.ru 1239*1061Sigor@sysoev.ru if (name == NULL) { 1240*1061Sigor@sysoev.ru name_length = length; 1241*1061Sigor@sysoev.ru name = start; 1242*1061Sigor@sysoev.ru length = 0; 1243*1061Sigor@sysoev.ru } 1244*1061Sigor@sysoev.ru 1245*1061Sigor@sysoev.ru nv->name_length = name_length; 1246*1061Sigor@sysoev.ru nv->value_length = length; 1247*1061Sigor@sysoev.ru nv->name = name; 1248*1061Sigor@sysoev.ru nv->value = start; 1249*1061Sigor@sysoev.ru 1250*1061Sigor@sysoev.ru return nv; 1251*1061Sigor@sysoev.ru } 1252*1061Sigor@sysoev.ru 1253*1061Sigor@sysoev.ru 1254*1061Sigor@sysoev.ru static nxt_int_t 1255*1061Sigor@sysoev.ru nxt_http_route_test_argument(nxt_http_request_t *r, 1256*1061Sigor@sysoev.ru nxt_http_route_rule_t *rule, nxt_array_t *array) 1257*1061Sigor@sysoev.ru { 1258*1061Sigor@sysoev.ru nxt_bool_t ret; 1259*1061Sigor@sysoev.ru nxt_http_name_value_t *nv, *end; 1260*1061Sigor@sysoev.ru 1261*1061Sigor@sysoev.ru ret = 0; 1262*1061Sigor@sysoev.ru 1263*1061Sigor@sysoev.ru nv = array->elts; 1264*1061Sigor@sysoev.ru end = nv + array->nelts; 1265*1061Sigor@sysoev.ru 1266*1061Sigor@sysoev.ru while (nv < end) { 1267*1061Sigor@sysoev.ru 1268*1061Sigor@sysoev.ru if (rule->u.name.hash == nv->hash 1269*1061Sigor@sysoev.ru && rule->u.name.length == nv->name_length 1270*1061Sigor@sysoev.ru && nxt_memcmp(rule->u.name.start, nv->name, nv->name_length) == 0) 1271*1061Sigor@sysoev.ru { 1272*1061Sigor@sysoev.ru ret = nxt_http_route_test_rule(r, rule, nv->value, 1273*1061Sigor@sysoev.ru nv->value_length); 1274*1061Sigor@sysoev.ru if (ret == 0) { 1275*1061Sigor@sysoev.ru break; 1276*1061Sigor@sysoev.ru } 1277*1061Sigor@sysoev.ru } 1278*1061Sigor@sysoev.ru 1279*1061Sigor@sysoev.ru nv++; 1280*1061Sigor@sysoev.ru } 1281*1061Sigor@sysoev.ru 1282*1061Sigor@sysoev.ru return ret; 1283*1061Sigor@sysoev.ru } 1284*1061Sigor@sysoev.ru 1285*1061Sigor@sysoev.ru 1286*1061Sigor@sysoev.ru static nxt_int_t 12871059Sigor@sysoev.ru nxt_http_route_test_rule(nxt_http_request_t *r, nxt_http_route_rule_t *rule, 12881059Sigor@sysoev.ru u_char *start, size_t length) 12891059Sigor@sysoev.ru { 12901060Sigor@sysoev.ru nxt_int_t ret; 12911059Sigor@sysoev.ru nxt_http_route_pattern_t *pattern, *end; 12921059Sigor@sysoev.ru 12931057Sigor@sysoev.ru ret = 1; 1294964Sigor@sysoev.ru pattern = &rule->pattern[0]; 12951033Svbart@nginx.com end = pattern + rule->items; 1296964Sigor@sysoev.ru 12971057Sigor@sysoev.ru while (pattern < end) { 1298964Sigor@sysoev.ru ret = nxt_http_route_pattern(r, pattern, start, length); 1299964Sigor@sysoev.ru 13001060Sigor@sysoev.ru /* nxt_http_route_pattern() returns either 1 or 0. */ 1301964Sigor@sysoev.ru ret ^= pattern->negative; 1302964Sigor@sysoev.ru 1303964Sigor@sysoev.ru if (pattern->any == ret) { 1304964Sigor@sysoev.ru return ret; 1305964Sigor@sysoev.ru } 1306964Sigor@sysoev.ru 1307964Sigor@sysoev.ru pattern++; 13081057Sigor@sysoev.ru } 1309964Sigor@sysoev.ru 1310964Sigor@sysoev.ru return ret; 1311964Sigor@sysoev.ru } 1312964Sigor@sysoev.ru 1313964Sigor@sysoev.ru 13141060Sigor@sysoev.ru static nxt_int_t 1315964Sigor@sysoev.ru nxt_http_route_pattern(nxt_http_request_t *r, nxt_http_route_pattern_t *pattern, 1316964Sigor@sysoev.ru u_char *start, size_t length) 1317964Sigor@sysoev.ru { 13181060Sigor@sysoev.ru u_char *p, *end, *test; 13191060Sigor@sysoev.ru size_t test_length; 13201060Sigor@sysoev.ru nxt_int_t ret; 1321964Sigor@sysoev.ru 1322964Sigor@sysoev.ru if (length < pattern->min_length) { 1323964Sigor@sysoev.ru return 0; 1324964Sigor@sysoev.ru } 1325964Sigor@sysoev.ru 13261032Sigor@sysoev.ru test = pattern->start1; 13271032Sigor@sysoev.ru test_length = pattern->length1; 1328964Sigor@sysoev.ru 1329964Sigor@sysoev.ru switch (pattern->type) { 1330964Sigor@sysoev.ru 1331964Sigor@sysoev.ru case NXT_HTTP_ROUTE_PATTERN_EXACT: 13321032Sigor@sysoev.ru if (length != test_length) { 1333964Sigor@sysoev.ru return 0; 1334964Sigor@sysoev.ru } 1335964Sigor@sysoev.ru 1336964Sigor@sysoev.ru break; 1337964Sigor@sysoev.ru 1338964Sigor@sysoev.ru case NXT_HTTP_ROUTE_PATTERN_BEGIN: 1339964Sigor@sysoev.ru break; 1340964Sigor@sysoev.ru 13411032Sigor@sysoev.ru case NXT_HTTP_ROUTE_PATTERN_MIDDLE: 13421032Sigor@sysoev.ru ret = nxt_http_route_memcmp(start, test, test_length, 13431032Sigor@sysoev.ru pattern->case_sensitive); 13441032Sigor@sysoev.ru if (!ret) { 13451032Sigor@sysoev.ru return ret; 13461032Sigor@sysoev.ru } 13471032Sigor@sysoev.ru 13481032Sigor@sysoev.ru test = pattern->start2; 13491032Sigor@sysoev.ru test_length = pattern->length2; 13501032Sigor@sysoev.ru 13511032Sigor@sysoev.ru /* Fall through. */ 13521032Sigor@sysoev.ru 1353964Sigor@sysoev.ru case NXT_HTTP_ROUTE_PATTERN_END: 13541032Sigor@sysoev.ru start += length - test_length; 1355964Sigor@sysoev.ru break; 1356964Sigor@sysoev.ru 1357964Sigor@sysoev.ru case NXT_HTTP_ROUTE_PATTERN_SUBSTRING: 13581032Sigor@sysoev.ru end = start + length; 13591032Sigor@sysoev.ru 1360964Sigor@sysoev.ru if (pattern->case_sensitive) { 13611032Sigor@sysoev.ru p = nxt_memstrn(start, end, (char *) test, test_length); 13621032Sigor@sysoev.ru 13631032Sigor@sysoev.ru } else { 13641032Sigor@sysoev.ru p = nxt_memcasestrn(start, end, (char *) test, test_length); 1365964Sigor@sysoev.ru } 1366964Sigor@sysoev.ru 13671032Sigor@sysoev.ru return (p != NULL); 1368964Sigor@sysoev.ru } 1369964Sigor@sysoev.ru 13701032Sigor@sysoev.ru return nxt_http_route_memcmp(start, test, test_length, 13711032Sigor@sysoev.ru pattern->case_sensitive); 13721032Sigor@sysoev.ru } 13731032Sigor@sysoev.ru 13741032Sigor@sysoev.ru 13751060Sigor@sysoev.ru static nxt_int_t 13761032Sigor@sysoev.ru nxt_http_route_memcmp(u_char *start, u_char *test, size_t test_length, 13771032Sigor@sysoev.ru nxt_bool_t case_sensitive) 13781032Sigor@sysoev.ru { 13791032Sigor@sysoev.ru nxt_int_t n; 13801032Sigor@sysoev.ru 13811032Sigor@sysoev.ru if (case_sensitive) { 13821032Sigor@sysoev.ru n = nxt_memcmp(start, test, test_length); 13831032Sigor@sysoev.ru 13841032Sigor@sysoev.ru } else { 13851032Sigor@sysoev.ru n = nxt_memcasecmp(start, test, test_length); 1386964Sigor@sysoev.ru } 1387964Sigor@sysoev.ru 13881032Sigor@sysoev.ru return (n == 0); 1389964Sigor@sysoev.ru } 1390