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> 9*1324Saxel.duch@nginx.com #include <nxt_sockaddr.h> 10*1324Saxel.duch@nginx.com #include <nxt_http_route_addr.h> 11964Sigor@sysoev.ru 12964Sigor@sysoev.ru 13964Sigor@sysoev.ru typedef enum { 141059Sigor@sysoev.ru NXT_HTTP_ROUTE_TABLE = 0, 151059Sigor@sysoev.ru NXT_HTTP_ROUTE_STRING, 16964Sigor@sysoev.ru NXT_HTTP_ROUTE_STRING_PTR, 17964Sigor@sysoev.ru NXT_HTTP_ROUTE_HEADER, 18964Sigor@sysoev.ru NXT_HTTP_ROUTE_ARGUMENT, 19964Sigor@sysoev.ru NXT_HTTP_ROUTE_COOKIE, 201110Saxel.duch@nginx.com NXT_HTTP_ROUTE_SCHEME, 21*1324Saxel.duch@nginx.com NXT_HTTP_ROUTE_SOURCE, 22964Sigor@sysoev.ru } nxt_http_route_object_t; 23964Sigor@sysoev.ru 24964Sigor@sysoev.ru 25964Sigor@sysoev.ru typedef enum { 26964Sigor@sysoev.ru NXT_HTTP_ROUTE_PATTERN_EXACT = 0, 27964Sigor@sysoev.ru NXT_HTTP_ROUTE_PATTERN_BEGIN, 281032Sigor@sysoev.ru NXT_HTTP_ROUTE_PATTERN_MIDDLE, 29964Sigor@sysoev.ru NXT_HTTP_ROUTE_PATTERN_END, 30964Sigor@sysoev.ru NXT_HTTP_ROUTE_PATTERN_SUBSTRING, 31964Sigor@sysoev.ru } nxt_http_route_pattern_type_t; 32964Sigor@sysoev.ru 33964Sigor@sysoev.ru 34964Sigor@sysoev.ru typedef enum { 35964Sigor@sysoev.ru NXT_HTTP_ROUTE_PATTERN_NOCASE = 0, 36964Sigor@sysoev.ru NXT_HTTP_ROUTE_PATTERN_LOWCASE, 37964Sigor@sysoev.ru NXT_HTTP_ROUTE_PATTERN_UPCASE, 38964Sigor@sysoev.ru } nxt_http_route_pattern_case_t; 39964Sigor@sysoev.ru 40964Sigor@sysoev.ru 41964Sigor@sysoev.ru typedef struct { 421264Sigor@sysoev.ru nxt_conf_value_t *pass; 431264Sigor@sysoev.ru nxt_conf_value_t *share; 441270Sigor@sysoev.ru nxt_conf_value_t *proxy; 451264Sigor@sysoev.ru } nxt_http_route_action_conf_t; 461264Sigor@sysoev.ru 471264Sigor@sysoev.ru 481264Sigor@sysoev.ru typedef struct { 49964Sigor@sysoev.ru nxt_conf_value_t *host; 50964Sigor@sysoev.ru nxt_conf_value_t *uri; 51964Sigor@sysoev.ru nxt_conf_value_t *method; 521059Sigor@sysoev.ru nxt_conf_value_t *headers; 531061Sigor@sysoev.ru nxt_conf_value_t *arguments; 541062Sigor@sysoev.ru nxt_conf_value_t *cookies; 551110Saxel.duch@nginx.com nxt_conf_value_t *scheme; 56*1324Saxel.duch@nginx.com nxt_conf_value_t *source; 57964Sigor@sysoev.ru } nxt_http_route_match_conf_t; 58964Sigor@sysoev.ru 59964Sigor@sysoev.ru 60964Sigor@sysoev.ru typedef struct { 611032Sigor@sysoev.ru u_char *start1; 621032Sigor@sysoev.ru u_char *start2; 631032Sigor@sysoev.ru uint32_t length1; 641032Sigor@sysoev.ru uint32_t length2; 65964Sigor@sysoev.ru uint32_t min_length; 66964Sigor@sysoev.ru 67964Sigor@sysoev.ru nxt_http_route_pattern_type_t type:8; 68964Sigor@sysoev.ru uint8_t case_sensitive; /* 1 bit */ 69964Sigor@sysoev.ru uint8_t negative; /* 1 bit */ 70964Sigor@sysoev.ru uint8_t any; /* 1 bit */ 71964Sigor@sysoev.ru } nxt_http_route_pattern_t; 72964Sigor@sysoev.ru 73964Sigor@sysoev.ru 74964Sigor@sysoev.ru typedef struct { 751061Sigor@sysoev.ru uint16_t hash; 761061Sigor@sysoev.ru uint16_t name_length; 771061Sigor@sysoev.ru uint32_t value_length; 781061Sigor@sysoev.ru u_char *name; 791061Sigor@sysoev.ru u_char *value; 801061Sigor@sysoev.ru } nxt_http_name_value_t; 811061Sigor@sysoev.ru 821061Sigor@sysoev.ru 831061Sigor@sysoev.ru typedef struct { 841062Sigor@sysoev.ru uint16_t hash; 851062Sigor@sysoev.ru uint16_t name_length; 861062Sigor@sysoev.ru uint32_t value_length; 871062Sigor@sysoev.ru u_char *name; 881062Sigor@sysoev.ru u_char *value; 891062Sigor@sysoev.ru } nxt_http_cookie_t; 901062Sigor@sysoev.ru 911062Sigor@sysoev.ru 921062Sigor@sysoev.ru typedef struct { 931059Sigor@sysoev.ru /* The object must be the first field. */ 941059Sigor@sysoev.ru nxt_http_route_object_t object:8; 95964Sigor@sysoev.ru uint32_t items; 961059Sigor@sysoev.ru 971059Sigor@sysoev.ru union { 981059Sigor@sysoev.ru uintptr_t offset; 991059Sigor@sysoev.ru 1001059Sigor@sysoev.ru struct { 1011059Sigor@sysoev.ru u_char *start; 1021059Sigor@sysoev.ru uint16_t hash; 1031059Sigor@sysoev.ru uint16_t length; 1041059Sigor@sysoev.ru } name; 1051059Sigor@sysoev.ru } u; 1061059Sigor@sysoev.ru 107964Sigor@sysoev.ru nxt_http_route_pattern_t pattern[0]; 108964Sigor@sysoev.ru } nxt_http_route_rule_t; 109964Sigor@sysoev.ru 110964Sigor@sysoev.ru 111964Sigor@sysoev.ru typedef struct { 112964Sigor@sysoev.ru uint32_t items; 1131059Sigor@sysoev.ru nxt_http_route_rule_t *rule[0]; 1141059Sigor@sysoev.ru } nxt_http_route_ruleset_t; 1151059Sigor@sysoev.ru 1161059Sigor@sysoev.ru 1171059Sigor@sysoev.ru typedef struct { 1181059Sigor@sysoev.ru /* The object must be the first field. */ 1191059Sigor@sysoev.ru nxt_http_route_object_t object:8; 1201059Sigor@sysoev.ru uint32_t items; 1211059Sigor@sysoev.ru nxt_http_route_ruleset_t *ruleset[0]; 1221059Sigor@sysoev.ru } nxt_http_route_table_t; 1231059Sigor@sysoev.ru 1241059Sigor@sysoev.ru 125*1324Saxel.duch@nginx.com typedef struct { 126*1324Saxel.duch@nginx.com /* The object must be the first field. */ 127*1324Saxel.duch@nginx.com nxt_http_route_object_t object:8; 128*1324Saxel.duch@nginx.com uint32_t items; 129*1324Saxel.duch@nginx.com nxt_http_route_addr_pattern_t addr_pattern[0]; 130*1324Saxel.duch@nginx.com } nxt_http_route_addr_rule_t; 131*1324Saxel.duch@nginx.com 132*1324Saxel.duch@nginx.com 1331059Sigor@sysoev.ru typedef union { 1341059Sigor@sysoev.ru nxt_http_route_rule_t *rule; 1351059Sigor@sysoev.ru nxt_http_route_table_t *table; 136*1324Saxel.duch@nginx.com nxt_http_route_addr_rule_t *addr_rule; 1371059Sigor@sysoev.ru } nxt_http_route_test_t; 1381059Sigor@sysoev.ru 1391059Sigor@sysoev.ru 1401059Sigor@sysoev.ru typedef struct { 1411059Sigor@sysoev.ru uint32_t items; 1421264Sigor@sysoev.ru nxt_http_action_t action; 1431059Sigor@sysoev.ru nxt_http_route_test_t test[0]; 144964Sigor@sysoev.ru } nxt_http_route_match_t; 145964Sigor@sysoev.ru 146964Sigor@sysoev.ru 147964Sigor@sysoev.ru struct nxt_http_route_s { 148964Sigor@sysoev.ru nxt_str_t name; 149964Sigor@sysoev.ru uint32_t items; 150964Sigor@sysoev.ru nxt_http_route_match_t *match[0]; 151964Sigor@sysoev.ru }; 152964Sigor@sysoev.ru 153964Sigor@sysoev.ru 154964Sigor@sysoev.ru struct nxt_http_routes_s { 155964Sigor@sysoev.ru uint32_t items; 156964Sigor@sysoev.ru nxt_http_route_t *route[0]; 157964Sigor@sysoev.ru }; 158964Sigor@sysoev.ru 159964Sigor@sysoev.ru 1601062Sigor@sysoev.ru #define NJS_COOKIE_HASH \ 1611062Sigor@sysoev.ru (nxt_http_field_hash_end( \ 1621062Sigor@sysoev.ru nxt_http_field_hash_char( \ 1631062Sigor@sysoev.ru nxt_http_field_hash_char( \ 1641062Sigor@sysoev.ru nxt_http_field_hash_char( \ 1651062Sigor@sysoev.ru nxt_http_field_hash_char( \ 1661062Sigor@sysoev.ru nxt_http_field_hash_char( \ 1671062Sigor@sysoev.ru nxt_http_field_hash_char(NXT_HTTP_FIELD_HASH_INIT, \ 1681062Sigor@sysoev.ru 'c'), 'o'), 'o'), 'k'), 'i'), 'e')) & 0xFFFF) 1691062Sigor@sysoev.ru 1701062Sigor@sysoev.ru 171964Sigor@sysoev.ru static nxt_http_route_t *nxt_http_route_create(nxt_task_t *task, 172964Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, nxt_conf_value_t *cv); 173964Sigor@sysoev.ru static nxt_http_route_match_t *nxt_http_route_match_create(nxt_task_t *task, 174964Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, nxt_conf_value_t *cv); 1751264Sigor@sysoev.ru static nxt_int_t nxt_http_route_action_create(nxt_router_temp_conf_t *tmcf, 1761264Sigor@sysoev.ru nxt_conf_value_t *cv, nxt_http_route_match_t *match); 1771059Sigor@sysoev.ru static nxt_http_route_table_t *nxt_http_route_table_create(nxt_task_t *task, 1781061Sigor@sysoev.ru nxt_mp_t *mp, nxt_conf_value_t *table_cv, nxt_http_route_object_t object, 1791061Sigor@sysoev.ru nxt_bool_t case_sensitive); 1801059Sigor@sysoev.ru static nxt_http_route_ruleset_t *nxt_http_route_ruleset_create(nxt_task_t *task, 1811061Sigor@sysoev.ru nxt_mp_t *mp, nxt_conf_value_t *ruleset_cv, nxt_http_route_object_t object, 1821061Sigor@sysoev.ru nxt_bool_t case_sensitive); 1831061Sigor@sysoev.ru static nxt_http_route_rule_t *nxt_http_route_rule_name_create(nxt_task_t *task, 1841061Sigor@sysoev.ru nxt_mp_t *mp, nxt_conf_value_t *rule_cv, nxt_str_t *name, 1851061Sigor@sysoev.ru nxt_bool_t case_sensitive); 186*1324Saxel.duch@nginx.com static nxt_http_route_addr_rule_t *nxt_http_route_addr_rule_create( 187*1324Saxel.duch@nginx.com nxt_task_t *task, nxt_mp_t *mp, nxt_conf_value_t *cv); 188964Sigor@sysoev.ru static nxt_http_route_rule_t *nxt_http_route_rule_create(nxt_task_t *task, 1891059Sigor@sysoev.ru nxt_mp_t *mp, nxt_conf_value_t *cv, nxt_bool_t case_sensitive, 1901059Sigor@sysoev.ru nxt_http_route_pattern_case_t pattern_case); 191964Sigor@sysoev.ru static int nxt_http_pattern_compare(const void *one, const void *two); 192964Sigor@sysoev.ru static nxt_int_t nxt_http_route_pattern_create(nxt_task_t *task, nxt_mp_t *mp, 193964Sigor@sysoev.ru nxt_conf_value_t *cv, nxt_http_route_pattern_t *pattern, 194964Sigor@sysoev.ru nxt_http_route_pattern_case_t pattern_case); 1951032Sigor@sysoev.ru static u_char *nxt_http_route_pattern_copy(nxt_mp_t *mp, nxt_str_t *test, 1961032Sigor@sysoev.ru nxt_http_route_pattern_case_t pattern_case); 197964Sigor@sysoev.ru 198964Sigor@sysoev.ru static void nxt_http_route_resolve(nxt_task_t *task, 199964Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, nxt_http_route_t *route); 2001264Sigor@sysoev.ru static void nxt_http_action_resolve(nxt_task_t *task, 2011264Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, nxt_http_action_t *action); 202964Sigor@sysoev.ru static nxt_http_route_t *nxt_http_route_find(nxt_http_routes_t *routes, 203964Sigor@sysoev.ru nxt_str_t *name); 204964Sigor@sysoev.ru static void nxt_http_route_cleanup(nxt_task_t *task, nxt_http_route_t *routes); 205964Sigor@sysoev.ru 2061264Sigor@sysoev.ru static nxt_http_action_t *nxt_http_route_handler(nxt_task_t *task, 2071264Sigor@sysoev.ru nxt_http_request_t *r, nxt_http_action_t *start); 2081264Sigor@sysoev.ru static nxt_http_action_t *nxt_http_route_match(nxt_http_request_t *r, 209964Sigor@sysoev.ru nxt_http_route_match_t *match); 2101060Sigor@sysoev.ru static nxt_int_t nxt_http_route_table(nxt_http_request_t *r, 2111059Sigor@sysoev.ru nxt_http_route_table_t *table); 2121060Sigor@sysoev.ru static nxt_int_t nxt_http_route_ruleset(nxt_http_request_t *r, 2131059Sigor@sysoev.ru nxt_http_route_ruleset_t *ruleset); 214*1324Saxel.duch@nginx.com static nxt_int_t nxt_http_route_addr_rule(nxt_http_request_t *r, 215*1324Saxel.duch@nginx.com nxt_http_route_addr_rule_t *addr_rule, nxt_sockaddr_t *sockaddr); 2161060Sigor@sysoev.ru static nxt_int_t nxt_http_route_rule(nxt_http_request_t *r, 217964Sigor@sysoev.ru nxt_http_route_rule_t *rule); 2181060Sigor@sysoev.ru static nxt_int_t nxt_http_route_header(nxt_http_request_t *r, 2191059Sigor@sysoev.ru nxt_http_route_rule_t *rule); 2201061Sigor@sysoev.ru static nxt_int_t nxt_http_route_arguments(nxt_http_request_t *r, 2211061Sigor@sysoev.ru nxt_http_route_rule_t *rule); 2221061Sigor@sysoev.ru static nxt_array_t *nxt_http_route_arguments_parse(nxt_http_request_t *r); 2231061Sigor@sysoev.ru static nxt_http_name_value_t *nxt_http_route_argument(nxt_array_t *array, 2241061Sigor@sysoev.ru u_char *name, size_t name_length, uint32_t hash, u_char *start, 2251061Sigor@sysoev.ru u_char *end); 2261061Sigor@sysoev.ru static nxt_int_t nxt_http_route_test_argument(nxt_http_request_t *r, 2271061Sigor@sysoev.ru nxt_http_route_rule_t *rule, nxt_array_t *array); 2281110Saxel.duch@nginx.com static nxt_int_t nxt_http_route_scheme(nxt_http_request_t *r, 2291110Saxel.duch@nginx.com nxt_http_route_rule_t *rule); 2301062Sigor@sysoev.ru static nxt_int_t nxt_http_route_cookies(nxt_http_request_t *r, 2311062Sigor@sysoev.ru nxt_http_route_rule_t *rule); 2321062Sigor@sysoev.ru static nxt_array_t *nxt_http_route_cookies_parse(nxt_http_request_t *r); 2331062Sigor@sysoev.ru static nxt_int_t nxt_http_route_cookie_parse(nxt_array_t *cookies, 2341062Sigor@sysoev.ru u_char *start, u_char *end); 2351062Sigor@sysoev.ru static nxt_http_name_value_t *nxt_http_route_cookie(nxt_array_t *array, 2361062Sigor@sysoev.ru u_char *name, size_t name_length, u_char *start, u_char *end); 2371062Sigor@sysoev.ru static nxt_int_t nxt_http_route_test_cookie(nxt_http_request_t *r, 2381062Sigor@sysoev.ru nxt_http_route_rule_t *rule, nxt_array_t *array); 2391060Sigor@sysoev.ru static nxt_int_t nxt_http_route_test_rule(nxt_http_request_t *r, 2401059Sigor@sysoev.ru nxt_http_route_rule_t *rule, u_char *start, size_t length); 2411060Sigor@sysoev.ru static nxt_int_t nxt_http_route_pattern(nxt_http_request_t *r, 242964Sigor@sysoev.ru nxt_http_route_pattern_t *pattern, u_char *start, size_t length); 2431060Sigor@sysoev.ru static nxt_int_t nxt_http_route_memcmp(u_char *start, u_char *test, 2441032Sigor@sysoev.ru size_t length, nxt_bool_t case_sensitive); 245964Sigor@sysoev.ru 246964Sigor@sysoev.ru 247964Sigor@sysoev.ru nxt_http_routes_t * 248964Sigor@sysoev.ru nxt_http_routes_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 249964Sigor@sysoev.ru nxt_conf_value_t *routes_conf) 250964Sigor@sysoev.ru { 251964Sigor@sysoev.ru size_t size; 252964Sigor@sysoev.ru uint32_t i, n, next; 253964Sigor@sysoev.ru nxt_mp_t *mp; 254964Sigor@sysoev.ru nxt_str_t name, *string; 255964Sigor@sysoev.ru nxt_bool_t object; 256964Sigor@sysoev.ru nxt_conf_value_t *route_conf; 257964Sigor@sysoev.ru nxt_http_route_t *route; 258964Sigor@sysoev.ru nxt_http_routes_t *routes; 259964Sigor@sysoev.ru 260964Sigor@sysoev.ru object = (nxt_conf_type(routes_conf) == NXT_CONF_OBJECT); 261964Sigor@sysoev.ru n = object ? nxt_conf_object_members_count(routes_conf) : 1; 262964Sigor@sysoev.ru size = sizeof(nxt_http_routes_t) + n * sizeof(nxt_http_route_t *); 263964Sigor@sysoev.ru 264964Sigor@sysoev.ru mp = tmcf->router_conf->mem_pool; 265964Sigor@sysoev.ru 266964Sigor@sysoev.ru routes = nxt_mp_alloc(mp, size); 267964Sigor@sysoev.ru if (nxt_slow_path(routes == NULL)) { 268964Sigor@sysoev.ru return NULL; 269964Sigor@sysoev.ru } 270964Sigor@sysoev.ru 271964Sigor@sysoev.ru routes->items = n; 272964Sigor@sysoev.ru 273964Sigor@sysoev.ru if (object) { 274964Sigor@sysoev.ru next = 0; 275964Sigor@sysoev.ru 276964Sigor@sysoev.ru for (i = 0; i < n; i++) { 277964Sigor@sysoev.ru route_conf = nxt_conf_next_object_member(routes_conf, &name, &next); 278964Sigor@sysoev.ru 279964Sigor@sysoev.ru route = nxt_http_route_create(task, tmcf, route_conf); 280964Sigor@sysoev.ru if (nxt_slow_path(route == NULL)) { 281964Sigor@sysoev.ru return NULL; 282964Sigor@sysoev.ru } 283964Sigor@sysoev.ru 284964Sigor@sysoev.ru routes->route[i] = route; 285964Sigor@sysoev.ru 286964Sigor@sysoev.ru string = nxt_str_dup(mp, &route->name, &name); 287964Sigor@sysoev.ru if (nxt_slow_path(string == NULL)) { 288964Sigor@sysoev.ru return NULL; 289964Sigor@sysoev.ru } 290964Sigor@sysoev.ru } 291964Sigor@sysoev.ru 292964Sigor@sysoev.ru } else { 293964Sigor@sysoev.ru route = nxt_http_route_create(task, tmcf, routes_conf); 294964Sigor@sysoev.ru if (nxt_slow_path(route == NULL)) { 295964Sigor@sysoev.ru return NULL; 296964Sigor@sysoev.ru } 297964Sigor@sysoev.ru 298964Sigor@sysoev.ru routes->route[0] = route; 299964Sigor@sysoev.ru 300964Sigor@sysoev.ru route->name.length = 0; 301964Sigor@sysoev.ru route->name.start = NULL; 302964Sigor@sysoev.ru } 303964Sigor@sysoev.ru 304964Sigor@sysoev.ru return routes; 305964Sigor@sysoev.ru } 306964Sigor@sysoev.ru 307964Sigor@sysoev.ru 308964Sigor@sysoev.ru static nxt_conf_map_t nxt_http_route_match_conf[] = { 309964Sigor@sysoev.ru { 3101110Saxel.duch@nginx.com nxt_string("scheme"), 3111110Saxel.duch@nginx.com NXT_CONF_MAP_PTR, 3121110Saxel.duch@nginx.com offsetof(nxt_http_route_match_conf_t, scheme) 3131110Saxel.duch@nginx.com }, 3141110Saxel.duch@nginx.com { 315964Sigor@sysoev.ru nxt_string("host"), 316964Sigor@sysoev.ru NXT_CONF_MAP_PTR, 317964Sigor@sysoev.ru offsetof(nxt_http_route_match_conf_t, host), 318964Sigor@sysoev.ru }, 319964Sigor@sysoev.ru 320964Sigor@sysoev.ru { 321964Sigor@sysoev.ru nxt_string("uri"), 322964Sigor@sysoev.ru NXT_CONF_MAP_PTR, 323964Sigor@sysoev.ru offsetof(nxt_http_route_match_conf_t, uri), 324964Sigor@sysoev.ru }, 325964Sigor@sysoev.ru 326964Sigor@sysoev.ru { 327964Sigor@sysoev.ru nxt_string("method"), 328964Sigor@sysoev.ru NXT_CONF_MAP_PTR, 329964Sigor@sysoev.ru offsetof(nxt_http_route_match_conf_t, method), 330964Sigor@sysoev.ru }, 3311059Sigor@sysoev.ru 3321059Sigor@sysoev.ru { 3331059Sigor@sysoev.ru nxt_string("headers"), 3341059Sigor@sysoev.ru NXT_CONF_MAP_PTR, 3351059Sigor@sysoev.ru offsetof(nxt_http_route_match_conf_t, headers), 3361059Sigor@sysoev.ru }, 3371061Sigor@sysoev.ru 3381061Sigor@sysoev.ru { 3391061Sigor@sysoev.ru nxt_string("arguments"), 3401061Sigor@sysoev.ru NXT_CONF_MAP_PTR, 3411061Sigor@sysoev.ru offsetof(nxt_http_route_match_conf_t, arguments), 3421061Sigor@sysoev.ru }, 3431062Sigor@sysoev.ru 3441062Sigor@sysoev.ru { 3451062Sigor@sysoev.ru nxt_string("cookies"), 3461062Sigor@sysoev.ru NXT_CONF_MAP_PTR, 3471062Sigor@sysoev.ru offsetof(nxt_http_route_match_conf_t, cookies), 3481062Sigor@sysoev.ru }, 349*1324Saxel.duch@nginx.com 350*1324Saxel.duch@nginx.com { 351*1324Saxel.duch@nginx.com nxt_string("source"), 352*1324Saxel.duch@nginx.com NXT_CONF_MAP_PTR, 353*1324Saxel.duch@nginx.com offsetof(nxt_http_route_match_conf_t, source), 354*1324Saxel.duch@nginx.com }, 355964Sigor@sysoev.ru }; 356964Sigor@sysoev.ru 357964Sigor@sysoev.ru 358964Sigor@sysoev.ru static nxt_http_route_t * 359964Sigor@sysoev.ru nxt_http_route_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 360964Sigor@sysoev.ru nxt_conf_value_t *cv) 361964Sigor@sysoev.ru { 362964Sigor@sysoev.ru size_t size; 363964Sigor@sysoev.ru uint32_t i, n; 364964Sigor@sysoev.ru nxt_conf_value_t *value; 365964Sigor@sysoev.ru nxt_http_route_t *route; 366964Sigor@sysoev.ru nxt_http_route_match_t *match, **m; 367964Sigor@sysoev.ru 368964Sigor@sysoev.ru n = nxt_conf_array_elements_count(cv); 369964Sigor@sysoev.ru size = sizeof(nxt_http_route_t) + n * sizeof(nxt_http_route_match_t *); 370964Sigor@sysoev.ru 371964Sigor@sysoev.ru route = nxt_mp_alloc(tmcf->router_conf->mem_pool, size); 372964Sigor@sysoev.ru if (nxt_slow_path(route == NULL)) { 373964Sigor@sysoev.ru return NULL; 374964Sigor@sysoev.ru } 375964Sigor@sysoev.ru 376964Sigor@sysoev.ru route->items = n; 377964Sigor@sysoev.ru m = &route->match[0]; 378964Sigor@sysoev.ru 379964Sigor@sysoev.ru for (i = 0; i < n; i++) { 380964Sigor@sysoev.ru value = nxt_conf_get_array_element(cv, i); 381964Sigor@sysoev.ru 382964Sigor@sysoev.ru match = nxt_http_route_match_create(task, tmcf, value); 383964Sigor@sysoev.ru if (match == NULL) { 384964Sigor@sysoev.ru return NULL; 385964Sigor@sysoev.ru } 386964Sigor@sysoev.ru 387964Sigor@sysoev.ru *m++ = match; 388964Sigor@sysoev.ru } 389964Sigor@sysoev.ru 390964Sigor@sysoev.ru return route; 391964Sigor@sysoev.ru } 392964Sigor@sysoev.ru 393964Sigor@sysoev.ru 394964Sigor@sysoev.ru static nxt_http_route_match_t * 395964Sigor@sysoev.ru nxt_http_route_match_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 396964Sigor@sysoev.ru nxt_conf_value_t *cv) 397964Sigor@sysoev.ru { 398964Sigor@sysoev.ru size_t size; 399964Sigor@sysoev.ru uint32_t n; 4001059Sigor@sysoev.ru nxt_mp_t *mp; 401964Sigor@sysoev.ru nxt_int_t ret; 4021264Sigor@sysoev.ru nxt_conf_value_t *match_conf; 4031059Sigor@sysoev.ru nxt_http_route_test_t *test; 4041059Sigor@sysoev.ru nxt_http_route_rule_t *rule; 4051059Sigor@sysoev.ru nxt_http_route_table_t *table; 406964Sigor@sysoev.ru nxt_http_route_match_t *match; 407*1324Saxel.duch@nginx.com nxt_http_route_addr_rule_t *addr_rule; 408964Sigor@sysoev.ru nxt_http_route_match_conf_t mtcf; 409964Sigor@sysoev.ru 410964Sigor@sysoev.ru static nxt_str_t match_path = nxt_string("/match"); 411964Sigor@sysoev.ru 412964Sigor@sysoev.ru match_conf = nxt_conf_get_path(cv, &match_path); 413964Sigor@sysoev.ru 414964Sigor@sysoev.ru n = (match_conf != NULL) ? nxt_conf_object_members_count(match_conf) : 0; 415964Sigor@sysoev.ru size = sizeof(nxt_http_route_match_t) + n * sizeof(nxt_http_route_rule_t *); 416964Sigor@sysoev.ru 4171059Sigor@sysoev.ru mp = tmcf->router_conf->mem_pool; 4181059Sigor@sysoev.ru 4191059Sigor@sysoev.ru match = nxt_mp_alloc(mp, size); 420964Sigor@sysoev.ru if (nxt_slow_path(match == NULL)) { 421964Sigor@sysoev.ru return NULL; 422964Sigor@sysoev.ru } 423964Sigor@sysoev.ru 4241264Sigor@sysoev.ru match->action.u.route = NULL; 4251264Sigor@sysoev.ru match->action.handler = NULL; 426964Sigor@sysoev.ru match->items = n; 427964Sigor@sysoev.ru 4281264Sigor@sysoev.ru ret = nxt_http_route_action_create(tmcf, cv, match); 4291264Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 430964Sigor@sysoev.ru return NULL; 431964Sigor@sysoev.ru } 432964Sigor@sysoev.ru 433964Sigor@sysoev.ru if (n == 0) { 434964Sigor@sysoev.ru return match; 435964Sigor@sysoev.ru } 436964Sigor@sysoev.ru 437964Sigor@sysoev.ru nxt_memzero(&mtcf, sizeof(mtcf)); 438964Sigor@sysoev.ru 439964Sigor@sysoev.ru ret = nxt_conf_map_object(tmcf->mem_pool, 440964Sigor@sysoev.ru match_conf, nxt_http_route_match_conf, 441964Sigor@sysoev.ru nxt_nitems(nxt_http_route_match_conf), &mtcf); 442964Sigor@sysoev.ru if (ret != NXT_OK) { 443964Sigor@sysoev.ru return NULL; 444964Sigor@sysoev.ru } 445964Sigor@sysoev.ru 4461059Sigor@sysoev.ru test = &match->test[0]; 447964Sigor@sysoev.ru 4481110Saxel.duch@nginx.com if (mtcf.scheme != NULL) { 4491110Saxel.duch@nginx.com rule = nxt_http_route_rule_create(task, mp, mtcf.scheme, 1, 4501110Saxel.duch@nginx.com NXT_HTTP_ROUTE_PATTERN_NOCASE); 4511110Saxel.duch@nginx.com if (rule == NULL) { 4521110Saxel.duch@nginx.com return NULL; 4531110Saxel.duch@nginx.com } 4541110Saxel.duch@nginx.com 4551110Saxel.duch@nginx.com rule->object = NXT_HTTP_ROUTE_SCHEME; 4561110Saxel.duch@nginx.com test->rule = rule; 4571110Saxel.duch@nginx.com test++; 4581110Saxel.duch@nginx.com } 4591110Saxel.duch@nginx.com 460964Sigor@sysoev.ru if (mtcf.host != NULL) { 4611059Sigor@sysoev.ru rule = nxt_http_route_rule_create(task, mp, mtcf.host, 1, 462964Sigor@sysoev.ru NXT_HTTP_ROUTE_PATTERN_LOWCASE); 463964Sigor@sysoev.ru if (rule == NULL) { 464964Sigor@sysoev.ru return NULL; 465964Sigor@sysoev.ru } 466964Sigor@sysoev.ru 4671059Sigor@sysoev.ru rule->u.offset = offsetof(nxt_http_request_t, host); 468964Sigor@sysoev.ru rule->object = NXT_HTTP_ROUTE_STRING; 4691059Sigor@sysoev.ru test->rule = rule; 4701059Sigor@sysoev.ru test++; 471964Sigor@sysoev.ru } 472964Sigor@sysoev.ru 473964Sigor@sysoev.ru if (mtcf.uri != NULL) { 4741059Sigor@sysoev.ru rule = nxt_http_route_rule_create(task, mp, mtcf.uri, 1, 475964Sigor@sysoev.ru NXT_HTTP_ROUTE_PATTERN_NOCASE); 476964Sigor@sysoev.ru if (rule == NULL) { 477964Sigor@sysoev.ru return NULL; 478964Sigor@sysoev.ru } 479964Sigor@sysoev.ru 4801059Sigor@sysoev.ru rule->u.offset = offsetof(nxt_http_request_t, path); 481964Sigor@sysoev.ru rule->object = NXT_HTTP_ROUTE_STRING_PTR; 4821059Sigor@sysoev.ru test->rule = rule; 4831059Sigor@sysoev.ru test++; 484964Sigor@sysoev.ru } 485964Sigor@sysoev.ru 486964Sigor@sysoev.ru if (mtcf.method != NULL) { 4871059Sigor@sysoev.ru rule = nxt_http_route_rule_create(task, mp, mtcf.method, 1, 488964Sigor@sysoev.ru NXT_HTTP_ROUTE_PATTERN_UPCASE); 489964Sigor@sysoev.ru if (rule == NULL) { 490964Sigor@sysoev.ru return NULL; 491964Sigor@sysoev.ru } 492964Sigor@sysoev.ru 4931059Sigor@sysoev.ru rule->u.offset = offsetof(nxt_http_request_t, method); 494964Sigor@sysoev.ru rule->object = NXT_HTTP_ROUTE_STRING_PTR; 4951059Sigor@sysoev.ru test->rule = rule; 4961059Sigor@sysoev.ru test++; 4971059Sigor@sysoev.ru } 4981059Sigor@sysoev.ru 4991059Sigor@sysoev.ru if (mtcf.headers != NULL) { 5001061Sigor@sysoev.ru table = nxt_http_route_table_create(task, mp, mtcf.headers, 5011061Sigor@sysoev.ru NXT_HTTP_ROUTE_HEADER, 0); 5021061Sigor@sysoev.ru if (table == NULL) { 5031061Sigor@sysoev.ru return NULL; 5041061Sigor@sysoev.ru } 5051061Sigor@sysoev.ru 5061061Sigor@sysoev.ru test->table = table; 5071061Sigor@sysoev.ru test++; 5081061Sigor@sysoev.ru } 5091061Sigor@sysoev.ru 5101061Sigor@sysoev.ru if (mtcf.arguments != NULL) { 5111061Sigor@sysoev.ru table = nxt_http_route_table_create(task, mp, mtcf.arguments, 5121061Sigor@sysoev.ru NXT_HTTP_ROUTE_ARGUMENT, 1); 5131059Sigor@sysoev.ru if (table == NULL) { 5141059Sigor@sysoev.ru return NULL; 5151059Sigor@sysoev.ru } 5161059Sigor@sysoev.ru 5171059Sigor@sysoev.ru test->table = table; 5181059Sigor@sysoev.ru test++; 519964Sigor@sysoev.ru } 520964Sigor@sysoev.ru 5211062Sigor@sysoev.ru if (mtcf.cookies != NULL) { 5221062Sigor@sysoev.ru table = nxt_http_route_table_create(task, mp, mtcf.cookies, 5231079Sigor@sysoev.ru NXT_HTTP_ROUTE_COOKIE, 1); 5241062Sigor@sysoev.ru if (table == NULL) { 5251062Sigor@sysoev.ru return NULL; 5261062Sigor@sysoev.ru } 5271062Sigor@sysoev.ru 5281062Sigor@sysoev.ru test->table = table; 5291062Sigor@sysoev.ru test++; 5301062Sigor@sysoev.ru } 5311062Sigor@sysoev.ru 532*1324Saxel.duch@nginx.com if (mtcf.source != NULL) { 533*1324Saxel.duch@nginx.com addr_rule = nxt_http_route_addr_rule_create(task, mp, mtcf.source); 534*1324Saxel.duch@nginx.com if (addr_rule == NULL) { 535*1324Saxel.duch@nginx.com return NULL; 536*1324Saxel.duch@nginx.com } 537*1324Saxel.duch@nginx.com 538*1324Saxel.duch@nginx.com addr_rule->object = NXT_HTTP_ROUTE_SOURCE; 539*1324Saxel.duch@nginx.com test->addr_rule = addr_rule; 540*1324Saxel.duch@nginx.com test++; 541*1324Saxel.duch@nginx.com } 542*1324Saxel.duch@nginx.com 543964Sigor@sysoev.ru return match; 544964Sigor@sysoev.ru } 545964Sigor@sysoev.ru 546964Sigor@sysoev.ru 5471264Sigor@sysoev.ru static nxt_conf_map_t nxt_http_route_action_conf[] = { 5481264Sigor@sysoev.ru { 5491264Sigor@sysoev.ru nxt_string("pass"), 5501264Sigor@sysoev.ru NXT_CONF_MAP_PTR, 5511264Sigor@sysoev.ru offsetof(nxt_http_route_action_conf_t, pass) 5521264Sigor@sysoev.ru }, 5531264Sigor@sysoev.ru { 5541264Sigor@sysoev.ru nxt_string("share"), 5551264Sigor@sysoev.ru NXT_CONF_MAP_PTR, 5561264Sigor@sysoev.ru offsetof(nxt_http_route_action_conf_t, share) 5571264Sigor@sysoev.ru }, 5581270Sigor@sysoev.ru { 5591270Sigor@sysoev.ru nxt_string("proxy"), 5601270Sigor@sysoev.ru NXT_CONF_MAP_PTR, 5611270Sigor@sysoev.ru offsetof(nxt_http_route_action_conf_t, proxy) 5621270Sigor@sysoev.ru }, 5631264Sigor@sysoev.ru }; 5641264Sigor@sysoev.ru 5651264Sigor@sysoev.ru 5661264Sigor@sysoev.ru static nxt_int_t 5671264Sigor@sysoev.ru nxt_http_route_action_create(nxt_router_temp_conf_t *tmcf, nxt_conf_value_t *cv, 5681264Sigor@sysoev.ru nxt_http_route_match_t *match) 5691264Sigor@sysoev.ru { 5701270Sigor@sysoev.ru nxt_mp_t *mp; 5711264Sigor@sysoev.ru nxt_int_t ret; 5721264Sigor@sysoev.ru nxt_str_t name, *string; 5731264Sigor@sysoev.ru nxt_conf_value_t *conf, *action_conf; 5741264Sigor@sysoev.ru nxt_http_route_action_conf_t accf; 5751264Sigor@sysoev.ru 5761264Sigor@sysoev.ru static nxt_str_t action_path = nxt_string("/action"); 5771264Sigor@sysoev.ru 5781264Sigor@sysoev.ru action_conf = nxt_conf_get_path(cv, &action_path); 5791264Sigor@sysoev.ru if (action_conf == NULL) { 5801264Sigor@sysoev.ru return NXT_ERROR; 5811264Sigor@sysoev.ru } 5821264Sigor@sysoev.ru 5831264Sigor@sysoev.ru nxt_memzero(&accf, sizeof(accf)); 5841264Sigor@sysoev.ru 5851264Sigor@sysoev.ru ret = nxt_conf_map_object(tmcf->mem_pool, 5861264Sigor@sysoev.ru action_conf, nxt_http_route_action_conf, 5871264Sigor@sysoev.ru nxt_nitems(nxt_http_route_action_conf), &accf); 5881264Sigor@sysoev.ru if (ret != NXT_OK) { 5891264Sigor@sysoev.ru return ret; 5901264Sigor@sysoev.ru } 5911264Sigor@sysoev.ru 5921264Sigor@sysoev.ru conf = accf.pass; 5931264Sigor@sysoev.ru 5941264Sigor@sysoev.ru if (accf.share != NULL) { 5951264Sigor@sysoev.ru conf = accf.share; 5961264Sigor@sysoev.ru match->action.handler = nxt_http_static_handler; 5971270Sigor@sysoev.ru 5981270Sigor@sysoev.ru } else if (accf.proxy != NULL) { 5991270Sigor@sysoev.ru conf = accf.proxy; 6001264Sigor@sysoev.ru } 6011264Sigor@sysoev.ru 6021264Sigor@sysoev.ru nxt_conf_get_string(conf, &name); 6031264Sigor@sysoev.ru 6041270Sigor@sysoev.ru mp = tmcf->router_conf->mem_pool; 6051270Sigor@sysoev.ru 6061270Sigor@sysoev.ru string = nxt_str_dup(mp, &match->action.name, &name); 6071264Sigor@sysoev.ru if (nxt_slow_path(string == NULL)) { 6081264Sigor@sysoev.ru return NXT_ERROR; 6091264Sigor@sysoev.ru } 6101264Sigor@sysoev.ru 6111270Sigor@sysoev.ru if (accf.proxy != NULL) { 6121270Sigor@sysoev.ru return nxt_http_proxy_create(mp, &match->action); 6131270Sigor@sysoev.ru } 6141270Sigor@sysoev.ru 6151264Sigor@sysoev.ru return NXT_OK; 6161264Sigor@sysoev.ru } 6171264Sigor@sysoev.ru 6181264Sigor@sysoev.ru 6191059Sigor@sysoev.ru static nxt_http_route_table_t * 6201059Sigor@sysoev.ru nxt_http_route_table_create(nxt_task_t *task, nxt_mp_t *mp, 6211061Sigor@sysoev.ru nxt_conf_value_t *table_cv, nxt_http_route_object_t object, 6221061Sigor@sysoev.ru nxt_bool_t case_sensitive) 6231059Sigor@sysoev.ru { 6241059Sigor@sysoev.ru size_t size; 6251059Sigor@sysoev.ru uint32_t i, n; 6261059Sigor@sysoev.ru nxt_bool_t array; 6271059Sigor@sysoev.ru nxt_conf_value_t *ruleset_cv; 6281059Sigor@sysoev.ru nxt_http_route_table_t *table; 6291059Sigor@sysoev.ru nxt_http_route_ruleset_t *ruleset; 6301059Sigor@sysoev.ru 6311059Sigor@sysoev.ru array = (nxt_conf_type(table_cv) == NXT_CONF_ARRAY); 6321059Sigor@sysoev.ru n = array ? nxt_conf_array_elements_count(table_cv) : 1; 6331059Sigor@sysoev.ru size = sizeof(nxt_http_route_table_t) 6341059Sigor@sysoev.ru + n * sizeof(nxt_http_route_ruleset_t *); 6351059Sigor@sysoev.ru 6361059Sigor@sysoev.ru table = nxt_mp_alloc(mp, size); 6371059Sigor@sysoev.ru if (nxt_slow_path(table == NULL)) { 6381059Sigor@sysoev.ru return NULL; 6391059Sigor@sysoev.ru } 6401059Sigor@sysoev.ru 6411059Sigor@sysoev.ru table->items = n; 6421059Sigor@sysoev.ru table->object = NXT_HTTP_ROUTE_TABLE; 6431059Sigor@sysoev.ru 6441059Sigor@sysoev.ru if (!array) { 6451061Sigor@sysoev.ru ruleset = nxt_http_route_ruleset_create(task, mp, table_cv, 6461061Sigor@sysoev.ru object, case_sensitive); 6471059Sigor@sysoev.ru if (nxt_slow_path(ruleset == NULL)) { 6481059Sigor@sysoev.ru return NULL; 6491059Sigor@sysoev.ru } 6501059Sigor@sysoev.ru 6511059Sigor@sysoev.ru table->ruleset[0] = ruleset; 6521059Sigor@sysoev.ru 6531059Sigor@sysoev.ru return table; 6541059Sigor@sysoev.ru } 6551059Sigor@sysoev.ru 6561059Sigor@sysoev.ru for (i = 0; i < n; i++) { 6571059Sigor@sysoev.ru ruleset_cv = nxt_conf_get_array_element(table_cv, i); 6581059Sigor@sysoev.ru 6591061Sigor@sysoev.ru ruleset = nxt_http_route_ruleset_create(task, mp, ruleset_cv, 6601061Sigor@sysoev.ru object, case_sensitive); 6611059Sigor@sysoev.ru if (nxt_slow_path(ruleset == NULL)) { 6621059Sigor@sysoev.ru return NULL; 6631059Sigor@sysoev.ru } 6641059Sigor@sysoev.ru 6651059Sigor@sysoev.ru table->ruleset[i] = ruleset; 6661059Sigor@sysoev.ru } 6671059Sigor@sysoev.ru 6681059Sigor@sysoev.ru return table; 6691059Sigor@sysoev.ru } 6701059Sigor@sysoev.ru 6711059Sigor@sysoev.ru 6721059Sigor@sysoev.ru static nxt_http_route_ruleset_t * 6731059Sigor@sysoev.ru nxt_http_route_ruleset_create(nxt_task_t *task, nxt_mp_t *mp, 6741061Sigor@sysoev.ru nxt_conf_value_t *ruleset_cv, nxt_http_route_object_t object, 6751061Sigor@sysoev.ru nxt_bool_t case_sensitive) 6761059Sigor@sysoev.ru { 6771059Sigor@sysoev.ru size_t size; 6781059Sigor@sysoev.ru uint32_t i, n, next; 6791059Sigor@sysoev.ru nxt_str_t name; 6801059Sigor@sysoev.ru nxt_conf_value_t *rule_cv; 6811059Sigor@sysoev.ru nxt_http_route_rule_t *rule; 6821059Sigor@sysoev.ru nxt_http_route_ruleset_t *ruleset; 6831059Sigor@sysoev.ru 6841059Sigor@sysoev.ru n = nxt_conf_object_members_count(ruleset_cv); 6851059Sigor@sysoev.ru size = sizeof(nxt_http_route_ruleset_t) 6861059Sigor@sysoev.ru + n * sizeof(nxt_http_route_rule_t *); 6871059Sigor@sysoev.ru 6881059Sigor@sysoev.ru ruleset = nxt_mp_alloc(mp, size); 6891059Sigor@sysoev.ru if (nxt_slow_path(ruleset == NULL)) { 6901059Sigor@sysoev.ru return NULL; 6911059Sigor@sysoev.ru } 6921059Sigor@sysoev.ru 6931059Sigor@sysoev.ru ruleset->items = n; 6941059Sigor@sysoev.ru 6951059Sigor@sysoev.ru next = 0; 6961059Sigor@sysoev.ru 6971059Sigor@sysoev.ru for (i = 0; i < n; i++) { 6981059Sigor@sysoev.ru rule_cv = nxt_conf_next_object_member(ruleset_cv, &name, &next); 6991059Sigor@sysoev.ru 7001061Sigor@sysoev.ru rule = nxt_http_route_rule_name_create(task, mp, rule_cv, &name, 7011061Sigor@sysoev.ru case_sensitive); 7021059Sigor@sysoev.ru if (nxt_slow_path(rule == NULL)) { 7031059Sigor@sysoev.ru return NULL; 7041059Sigor@sysoev.ru } 7051059Sigor@sysoev.ru 7061061Sigor@sysoev.ru rule->object = object; 7071059Sigor@sysoev.ru ruleset->rule[i] = rule; 7081059Sigor@sysoev.ru } 7091059Sigor@sysoev.ru 7101059Sigor@sysoev.ru return ruleset; 7111059Sigor@sysoev.ru } 7121059Sigor@sysoev.ru 7131059Sigor@sysoev.ru 714964Sigor@sysoev.ru static nxt_http_route_rule_t * 7151061Sigor@sysoev.ru nxt_http_route_rule_name_create(nxt_task_t *task, nxt_mp_t *mp, 7161061Sigor@sysoev.ru nxt_conf_value_t *rule_cv, nxt_str_t *name, nxt_bool_t case_sensitive) 7171059Sigor@sysoev.ru { 7181059Sigor@sysoev.ru u_char c, *p; 7191059Sigor@sysoev.ru uint32_t hash; 7201059Sigor@sysoev.ru nxt_uint_t i; 7211059Sigor@sysoev.ru nxt_http_route_rule_t *rule; 7221059Sigor@sysoev.ru 7231061Sigor@sysoev.ru rule = nxt_http_route_rule_create(task, mp, rule_cv, case_sensitive, 7241059Sigor@sysoev.ru NXT_HTTP_ROUTE_PATTERN_NOCASE); 7251059Sigor@sysoev.ru if (nxt_slow_path(rule == NULL)) { 7261059Sigor@sysoev.ru return NULL; 7271059Sigor@sysoev.ru } 7281059Sigor@sysoev.ru 7291059Sigor@sysoev.ru rule->u.name.length = name->length; 7301059Sigor@sysoev.ru 7311059Sigor@sysoev.ru p = nxt_mp_nget(mp, name->length); 7321059Sigor@sysoev.ru if (nxt_slow_path(p == NULL)) { 7331059Sigor@sysoev.ru return NULL; 7341059Sigor@sysoev.ru } 7351059Sigor@sysoev.ru 7361059Sigor@sysoev.ru rule->u.name.start = p; 7371059Sigor@sysoev.ru 7381059Sigor@sysoev.ru hash = NXT_HTTP_FIELD_HASH_INIT; 7391059Sigor@sysoev.ru 7401059Sigor@sysoev.ru for (i = 0; i < name->length; i++) { 7411059Sigor@sysoev.ru c = name->start[i]; 7421059Sigor@sysoev.ru *p++ = c; 7431059Sigor@sysoev.ru 7441079Sigor@sysoev.ru c = case_sensitive ? c : nxt_lowcase(c); 7451059Sigor@sysoev.ru hash = nxt_http_field_hash_char(hash, c); 7461059Sigor@sysoev.ru } 7471059Sigor@sysoev.ru 7481059Sigor@sysoev.ru rule->u.name.hash = nxt_http_field_hash_end(hash) & 0xFFFF; 7491059Sigor@sysoev.ru 7501059Sigor@sysoev.ru return rule; 7511059Sigor@sysoev.ru } 7521059Sigor@sysoev.ru 7531059Sigor@sysoev.ru 7541059Sigor@sysoev.ru static nxt_http_route_rule_t * 7551059Sigor@sysoev.ru nxt_http_route_rule_create(nxt_task_t *task, nxt_mp_t *mp, 756964Sigor@sysoev.ru nxt_conf_value_t *cv, nxt_bool_t case_sensitive, 757964Sigor@sysoev.ru nxt_http_route_pattern_case_t pattern_case) 758964Sigor@sysoev.ru { 759964Sigor@sysoev.ru size_t size; 760964Sigor@sysoev.ru uint32_t i, n; 761964Sigor@sysoev.ru nxt_int_t ret; 762964Sigor@sysoev.ru nxt_bool_t string; 763964Sigor@sysoev.ru nxt_conf_value_t *value; 764964Sigor@sysoev.ru nxt_http_route_rule_t *rule; 765964Sigor@sysoev.ru nxt_http_route_pattern_t *pattern; 766964Sigor@sysoev.ru 767964Sigor@sysoev.ru string = (nxt_conf_type(cv) != NXT_CONF_ARRAY); 768964Sigor@sysoev.ru n = string ? 1 : nxt_conf_array_elements_count(cv); 769964Sigor@sysoev.ru size = sizeof(nxt_http_route_rule_t) + n * sizeof(nxt_http_route_pattern_t); 770964Sigor@sysoev.ru 771964Sigor@sysoev.ru rule = nxt_mp_alloc(mp, size); 772964Sigor@sysoev.ru if (nxt_slow_path(rule == NULL)) { 773964Sigor@sysoev.ru return NULL; 774964Sigor@sysoev.ru } 775964Sigor@sysoev.ru 776964Sigor@sysoev.ru rule->items = n; 777964Sigor@sysoev.ru 778964Sigor@sysoev.ru pattern = &rule->pattern[0]; 779964Sigor@sysoev.ru 780964Sigor@sysoev.ru if (string) { 781964Sigor@sysoev.ru pattern[0].case_sensitive = case_sensitive; 782964Sigor@sysoev.ru ret = nxt_http_route_pattern_create(task, mp, cv, &pattern[0], 783964Sigor@sysoev.ru pattern_case); 784964Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 785964Sigor@sysoev.ru return NULL; 786964Sigor@sysoev.ru } 787964Sigor@sysoev.ru 788964Sigor@sysoev.ru return rule; 789964Sigor@sysoev.ru } 790964Sigor@sysoev.ru 791964Sigor@sysoev.ru nxt_conf_array_qsort(cv, nxt_http_pattern_compare); 792964Sigor@sysoev.ru 793964Sigor@sysoev.ru for (i = 0; i < n; i++) { 794964Sigor@sysoev.ru pattern[i].case_sensitive = case_sensitive; 795964Sigor@sysoev.ru value = nxt_conf_get_array_element(cv, i); 796964Sigor@sysoev.ru 797964Sigor@sysoev.ru ret = nxt_http_route_pattern_create(task, mp, value, &pattern[i], 798964Sigor@sysoev.ru pattern_case); 799964Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 800964Sigor@sysoev.ru return NULL; 801964Sigor@sysoev.ru } 802964Sigor@sysoev.ru } 803964Sigor@sysoev.ru 804964Sigor@sysoev.ru return rule; 805964Sigor@sysoev.ru } 806964Sigor@sysoev.ru 807964Sigor@sysoev.ru 808*1324Saxel.duch@nginx.com static nxt_http_route_addr_rule_t * 809*1324Saxel.duch@nginx.com nxt_http_route_addr_rule_create(nxt_task_t *task, nxt_mp_t *mp, 810*1324Saxel.duch@nginx.com nxt_conf_value_t *cv) 811*1324Saxel.duch@nginx.com { 812*1324Saxel.duch@nginx.com size_t size; 813*1324Saxel.duch@nginx.com uint32_t i, n; 814*1324Saxel.duch@nginx.com nxt_bool_t array; 815*1324Saxel.duch@nginx.com nxt_conf_value_t *value; 816*1324Saxel.duch@nginx.com nxt_http_route_addr_rule_t *addr_rule; 817*1324Saxel.duch@nginx.com nxt_http_route_addr_pattern_t *pattern; 818*1324Saxel.duch@nginx.com 819*1324Saxel.duch@nginx.com array = (nxt_conf_type(cv) == NXT_CONF_ARRAY); 820*1324Saxel.duch@nginx.com n = array ? nxt_conf_array_elements_count(cv) : 1; 821*1324Saxel.duch@nginx.com 822*1324Saxel.duch@nginx.com size = sizeof(nxt_http_route_addr_rule_t) 823*1324Saxel.duch@nginx.com + n * sizeof(nxt_http_route_addr_pattern_t); 824*1324Saxel.duch@nginx.com 825*1324Saxel.duch@nginx.com addr_rule = nxt_mp_alloc(mp, size); 826*1324Saxel.duch@nginx.com if (nxt_slow_path(addr_rule == NULL)) { 827*1324Saxel.duch@nginx.com return NULL; 828*1324Saxel.duch@nginx.com } 829*1324Saxel.duch@nginx.com 830*1324Saxel.duch@nginx.com addr_rule->items = n; 831*1324Saxel.duch@nginx.com 832*1324Saxel.duch@nginx.com if (!array) { 833*1324Saxel.duch@nginx.com pattern = &addr_rule->addr_pattern[0]; 834*1324Saxel.duch@nginx.com 835*1324Saxel.duch@nginx.com if (nxt_http_route_addr_pattern_parse(mp, pattern, cv) != NXT_OK) { 836*1324Saxel.duch@nginx.com return NULL; 837*1324Saxel.duch@nginx.com } 838*1324Saxel.duch@nginx.com 839*1324Saxel.duch@nginx.com return addr_rule; 840*1324Saxel.duch@nginx.com } 841*1324Saxel.duch@nginx.com 842*1324Saxel.duch@nginx.com for (i = 0; i < n; i++) { 843*1324Saxel.duch@nginx.com pattern = &addr_rule->addr_pattern[i]; 844*1324Saxel.duch@nginx.com value = nxt_conf_get_array_element(cv, i); 845*1324Saxel.duch@nginx.com 846*1324Saxel.duch@nginx.com if (nxt_http_route_addr_pattern_parse(mp, pattern, value) != NXT_OK) { 847*1324Saxel.duch@nginx.com return NULL; 848*1324Saxel.duch@nginx.com } 849*1324Saxel.duch@nginx.com } 850*1324Saxel.duch@nginx.com 851*1324Saxel.duch@nginx.com return addr_rule; 852*1324Saxel.duch@nginx.com } 853*1324Saxel.duch@nginx.com 854*1324Saxel.duch@nginx.com 855964Sigor@sysoev.ru static int 856964Sigor@sysoev.ru nxt_http_pattern_compare(const void *one, const void *two) 857964Sigor@sysoev.ru { 858964Sigor@sysoev.ru nxt_str_t test; 859964Sigor@sysoev.ru nxt_bool_t negative1, negative2; 860964Sigor@sysoev.ru nxt_conf_value_t *value; 861964Sigor@sysoev.ru 862964Sigor@sysoev.ru value = (nxt_conf_value_t *) one; 863964Sigor@sysoev.ru nxt_conf_get_string(value, &test); 864964Sigor@sysoev.ru negative1 = (test.length != 0 && test.start[0] == '!'); 865964Sigor@sysoev.ru 866964Sigor@sysoev.ru value = (nxt_conf_value_t *) two; 867964Sigor@sysoev.ru nxt_conf_get_string(value, &test); 868964Sigor@sysoev.ru negative2 = (test.length != 0 && test.start[0] == '!'); 869964Sigor@sysoev.ru 870964Sigor@sysoev.ru return (negative2 - negative1); 871964Sigor@sysoev.ru } 872964Sigor@sysoev.ru 873964Sigor@sysoev.ru 874964Sigor@sysoev.ru static nxt_int_t 875964Sigor@sysoev.ru nxt_http_route_pattern_create(nxt_task_t *task, nxt_mp_t *mp, 876964Sigor@sysoev.ru nxt_conf_value_t *cv, nxt_http_route_pattern_t *pattern, 877964Sigor@sysoev.ru nxt_http_route_pattern_case_t pattern_case) 878964Sigor@sysoev.ru { 879964Sigor@sysoev.ru u_char *start; 880964Sigor@sysoev.ru nxt_str_t test; 8811032Sigor@sysoev.ru nxt_uint_t n, length; 882964Sigor@sysoev.ru nxt_http_route_pattern_type_t type; 883964Sigor@sysoev.ru 8841032Sigor@sysoev.ru /* Suppress warning about uninitialized variable. */ 8851032Sigor@sysoev.ru length = 0; 8861032Sigor@sysoev.ru 887964Sigor@sysoev.ru type = NXT_HTTP_ROUTE_PATTERN_EXACT; 888964Sigor@sysoev.ru 889964Sigor@sysoev.ru nxt_conf_get_string(cv, &test); 890964Sigor@sysoev.ru 891964Sigor@sysoev.ru pattern->negative = 0; 892964Sigor@sysoev.ru pattern->any = 1; 893964Sigor@sysoev.ru 894964Sigor@sysoev.ru if (test.length != 0) { 895964Sigor@sysoev.ru 896964Sigor@sysoev.ru if (test.start[0] == '!') { 897964Sigor@sysoev.ru test.start++; 898964Sigor@sysoev.ru test.length--; 899964Sigor@sysoev.ru 900964Sigor@sysoev.ru pattern->negative = 1; 901964Sigor@sysoev.ru pattern->any = 0; 902964Sigor@sysoev.ru } 903964Sigor@sysoev.ru 904964Sigor@sysoev.ru if (test.length != 0) { 905964Sigor@sysoev.ru 906964Sigor@sysoev.ru if (test.start[0] == '*') { 907964Sigor@sysoev.ru test.start++; 908964Sigor@sysoev.ru test.length--; 909964Sigor@sysoev.ru 910964Sigor@sysoev.ru if (test.length != 0) { 911964Sigor@sysoev.ru if (test.start[test.length - 1] == '*') { 912964Sigor@sysoev.ru test.length--; 913964Sigor@sysoev.ru type = NXT_HTTP_ROUTE_PATTERN_SUBSTRING; 914964Sigor@sysoev.ru 915964Sigor@sysoev.ru } else { 916964Sigor@sysoev.ru type = NXT_HTTP_ROUTE_PATTERN_END; 917964Sigor@sysoev.ru } 918964Sigor@sysoev.ru 919964Sigor@sysoev.ru } else { 920964Sigor@sysoev.ru type = NXT_HTTP_ROUTE_PATTERN_BEGIN; 921964Sigor@sysoev.ru } 922964Sigor@sysoev.ru 923964Sigor@sysoev.ru } else if (test.start[test.length - 1] == '*') { 924964Sigor@sysoev.ru test.length--; 925964Sigor@sysoev.ru type = NXT_HTTP_ROUTE_PATTERN_BEGIN; 9261032Sigor@sysoev.ru 9271032Sigor@sysoev.ru } else { 9281032Sigor@sysoev.ru length = test.length - 1; 9291032Sigor@sysoev.ru 9301032Sigor@sysoev.ru for (n = 1; n < length; n++) { 9311032Sigor@sysoev.ru if (test.start[n] == '*') { 9321032Sigor@sysoev.ru test.length = n; 9331032Sigor@sysoev.ru type = NXT_HTTP_ROUTE_PATTERN_MIDDLE; 9341032Sigor@sysoev.ru break; 9351032Sigor@sysoev.ru } 9361032Sigor@sysoev.ru } 937964Sigor@sysoev.ru } 938964Sigor@sysoev.ru } 939964Sigor@sysoev.ru } 940964Sigor@sysoev.ru 941964Sigor@sysoev.ru pattern->type = type; 942964Sigor@sysoev.ru pattern->min_length = test.length; 9431032Sigor@sysoev.ru pattern->length1 = test.length; 944964Sigor@sysoev.ru 9451032Sigor@sysoev.ru start = nxt_http_route_pattern_copy(mp, &test, pattern_case); 946964Sigor@sysoev.ru if (nxt_slow_path(start == NULL)) { 947964Sigor@sysoev.ru return NXT_ERROR; 948964Sigor@sysoev.ru } 949964Sigor@sysoev.ru 9501032Sigor@sysoev.ru pattern->start1 = start; 9511032Sigor@sysoev.ru 9521032Sigor@sysoev.ru if (type == NXT_HTTP_ROUTE_PATTERN_MIDDLE) { 9531032Sigor@sysoev.ru length -= test.length; 9541032Sigor@sysoev.ru pattern->length2 = length; 9551032Sigor@sysoev.ru pattern->min_length += length; 9561032Sigor@sysoev.ru 9571032Sigor@sysoev.ru test.start = &test.start[test.length + 1]; 9581032Sigor@sysoev.ru test.length = length; 9591032Sigor@sysoev.ru 9601032Sigor@sysoev.ru start = nxt_http_route_pattern_copy(mp, &test, pattern_case); 9611032Sigor@sysoev.ru if (nxt_slow_path(start == NULL)) { 9621032Sigor@sysoev.ru return NXT_ERROR; 9631032Sigor@sysoev.ru } 9641032Sigor@sysoev.ru 9651032Sigor@sysoev.ru pattern->start2 = start; 9661032Sigor@sysoev.ru } 9671032Sigor@sysoev.ru 9681032Sigor@sysoev.ru return NXT_OK; 9691032Sigor@sysoev.ru } 9701032Sigor@sysoev.ru 9711032Sigor@sysoev.ru 9721032Sigor@sysoev.ru static u_char * 9731032Sigor@sysoev.ru nxt_http_route_pattern_copy(nxt_mp_t *mp, nxt_str_t *test, 9741032Sigor@sysoev.ru nxt_http_route_pattern_case_t pattern_case) 9751032Sigor@sysoev.ru { 9761032Sigor@sysoev.ru u_char *start; 9771032Sigor@sysoev.ru 9781032Sigor@sysoev.ru start = nxt_mp_nget(mp, test->length); 9791032Sigor@sysoev.ru if (nxt_slow_path(start == NULL)) { 9801032Sigor@sysoev.ru return start; 9811032Sigor@sysoev.ru } 982964Sigor@sysoev.ru 983964Sigor@sysoev.ru switch (pattern_case) { 984964Sigor@sysoev.ru 985964Sigor@sysoev.ru case NXT_HTTP_ROUTE_PATTERN_UPCASE: 9861032Sigor@sysoev.ru nxt_memcpy_upcase(start, test->start, test->length); 987964Sigor@sysoev.ru break; 988964Sigor@sysoev.ru 989964Sigor@sysoev.ru case NXT_HTTP_ROUTE_PATTERN_LOWCASE: 9901032Sigor@sysoev.ru nxt_memcpy_lowcase(start, test->start, test->length); 991964Sigor@sysoev.ru break; 992964Sigor@sysoev.ru 993964Sigor@sysoev.ru case NXT_HTTP_ROUTE_PATTERN_NOCASE: 9941032Sigor@sysoev.ru nxt_memcpy(start, test->start, test->length); 995964Sigor@sysoev.ru break; 996964Sigor@sysoev.ru } 997964Sigor@sysoev.ru 9981032Sigor@sysoev.ru return start; 999964Sigor@sysoev.ru } 1000964Sigor@sysoev.ru 1001964Sigor@sysoev.ru 1002964Sigor@sysoev.ru void 1003964Sigor@sysoev.ru nxt_http_routes_resolve(nxt_task_t *task, nxt_router_temp_conf_t *tmcf) 1004964Sigor@sysoev.ru { 10051033Svbart@nginx.com nxt_http_route_t **route, **end; 1006964Sigor@sysoev.ru nxt_http_routes_t *routes; 1007964Sigor@sysoev.ru 1008964Sigor@sysoev.ru routes = tmcf->router_conf->routes; 10091059Sigor@sysoev.ru 1010964Sigor@sysoev.ru if (routes != NULL) { 1011964Sigor@sysoev.ru route = &routes->route[0]; 10121033Svbart@nginx.com end = route + routes->items; 1013964Sigor@sysoev.ru 10141033Svbart@nginx.com while (route < end) { 1015964Sigor@sysoev.ru nxt_http_route_resolve(task, tmcf, *route); 1016964Sigor@sysoev.ru 1017964Sigor@sysoev.ru route++; 1018964Sigor@sysoev.ru } 1019964Sigor@sysoev.ru } 1020964Sigor@sysoev.ru } 1021964Sigor@sysoev.ru 1022964Sigor@sysoev.ru 1023964Sigor@sysoev.ru static void 1024964Sigor@sysoev.ru nxt_http_route_resolve(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 1025964Sigor@sysoev.ru nxt_http_route_t *route) 1026964Sigor@sysoev.ru { 10271264Sigor@sysoev.ru nxt_http_action_t *action; 10281033Svbart@nginx.com nxt_http_route_match_t **match, **end; 1029964Sigor@sysoev.ru 1030964Sigor@sysoev.ru match = &route->match[0]; 10311033Svbart@nginx.com end = match + route->items; 1032964Sigor@sysoev.ru 10331033Svbart@nginx.com while (match < end) { 10341264Sigor@sysoev.ru action = &(*match)->action; 10351183Svbart@nginx.com 10361264Sigor@sysoev.ru if (action->handler == NULL) { 10371264Sigor@sysoev.ru nxt_http_action_resolve(task, tmcf, &(*match)->action); 10381183Svbart@nginx.com } 1039964Sigor@sysoev.ru 1040964Sigor@sysoev.ru match++; 1041964Sigor@sysoev.ru } 1042964Sigor@sysoev.ru } 1043964Sigor@sysoev.ru 1044964Sigor@sysoev.ru 1045964Sigor@sysoev.ru static void 10461264Sigor@sysoev.ru nxt_http_action_resolve(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 10471264Sigor@sysoev.ru nxt_http_action_t *action) 1048964Sigor@sysoev.ru { 1049964Sigor@sysoev.ru nxt_str_t name; 1050964Sigor@sysoev.ru 10511264Sigor@sysoev.ru name = action->name; 1052964Sigor@sysoev.ru 1053964Sigor@sysoev.ru if (nxt_str_start(&name, "applications/", 13)) { 1054964Sigor@sysoev.ru name.length -= 13; 1055964Sigor@sysoev.ru name.start += 13; 1056964Sigor@sysoev.ru 10571264Sigor@sysoev.ru action->u.application = nxt_router_listener_application(tmcf, &name); 10581264Sigor@sysoev.ru nxt_router_app_use(task, action->u.application, 1); 1059964Sigor@sysoev.ru 10601264Sigor@sysoev.ru action->handler = nxt_http_application_handler; 1061964Sigor@sysoev.ru 1062964Sigor@sysoev.ru } else if (nxt_str_start(&name, "routes", 6)) { 1063964Sigor@sysoev.ru 1064964Sigor@sysoev.ru if (name.length == 6) { 1065964Sigor@sysoev.ru name.length = 0; 1066964Sigor@sysoev.ru name.start = NULL; 1067964Sigor@sysoev.ru 1068964Sigor@sysoev.ru } else if (name.start[6] == '/') { 1069964Sigor@sysoev.ru name.length -= 7; 1070964Sigor@sysoev.ru name.start += 7; 1071964Sigor@sysoev.ru } 1072964Sigor@sysoev.ru 10731264Sigor@sysoev.ru action->u.route = nxt_http_route_find(tmcf->router_conf->routes, &name); 1074964Sigor@sysoev.ru 10751264Sigor@sysoev.ru action->handler = nxt_http_route_handler; 1076964Sigor@sysoev.ru } 1077964Sigor@sysoev.ru } 1078964Sigor@sysoev.ru 1079964Sigor@sysoev.ru 1080964Sigor@sysoev.ru static nxt_http_route_t * 1081964Sigor@sysoev.ru nxt_http_route_find(nxt_http_routes_t *routes, nxt_str_t *name) 1082964Sigor@sysoev.ru { 10831033Svbart@nginx.com nxt_http_route_t **route, **end; 1084964Sigor@sysoev.ru 1085964Sigor@sysoev.ru route = &routes->route[0]; 10861033Svbart@nginx.com end = route + routes->items; 1087964Sigor@sysoev.ru 10881058Sigor@sysoev.ru while (route < end) { 1089964Sigor@sysoev.ru if (nxt_strstr_eq(&(*route)->name, name)) { 1090964Sigor@sysoev.ru return *route; 1091964Sigor@sysoev.ru } 1092964Sigor@sysoev.ru 1093964Sigor@sysoev.ru route++; 10941058Sigor@sysoev.ru } 1095964Sigor@sysoev.ru 1096964Sigor@sysoev.ru return NULL; 1097964Sigor@sysoev.ru } 1098964Sigor@sysoev.ru 1099964Sigor@sysoev.ru 11001264Sigor@sysoev.ru nxt_http_action_t * 11011264Sigor@sysoev.ru nxt_http_action_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 1102964Sigor@sysoev.ru nxt_str_t *name) 1103964Sigor@sysoev.ru { 11041264Sigor@sysoev.ru nxt_http_action_t *action; 1105964Sigor@sysoev.ru 11061264Sigor@sysoev.ru action = nxt_mp_alloc(tmcf->router_conf->mem_pool, 11071264Sigor@sysoev.ru sizeof(nxt_http_action_t)); 11081264Sigor@sysoev.ru if (nxt_slow_path(action == NULL)) { 1109964Sigor@sysoev.ru return NULL; 1110964Sigor@sysoev.ru } 1111964Sigor@sysoev.ru 11121264Sigor@sysoev.ru action->name = *name; 11131270Sigor@sysoev.ru action->handler = NULL; 1114964Sigor@sysoev.ru 11151264Sigor@sysoev.ru nxt_http_action_resolve(task, tmcf, action); 1116964Sigor@sysoev.ru 11171264Sigor@sysoev.ru return action; 1118964Sigor@sysoev.ru } 1119964Sigor@sysoev.ru 1120964Sigor@sysoev.ru 1121964Sigor@sysoev.ru /* COMPATIBILITY: listener application. */ 1122964Sigor@sysoev.ru 11231264Sigor@sysoev.ru nxt_http_action_t * 1124964Sigor@sysoev.ru nxt_http_pass_application(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 1125964Sigor@sysoev.ru nxt_str_t *name) 1126964Sigor@sysoev.ru { 11271264Sigor@sysoev.ru nxt_http_action_t *action; 1128964Sigor@sysoev.ru 11291264Sigor@sysoev.ru action = nxt_mp_alloc(tmcf->router_conf->mem_pool, 11301264Sigor@sysoev.ru sizeof(nxt_http_action_t)); 11311264Sigor@sysoev.ru if (nxt_slow_path(action == NULL)) { 1132964Sigor@sysoev.ru return NULL; 1133964Sigor@sysoev.ru } 1134964Sigor@sysoev.ru 11351264Sigor@sysoev.ru action->name = *name; 1136964Sigor@sysoev.ru 11371264Sigor@sysoev.ru action->u.application = nxt_router_listener_application(tmcf, name); 11381264Sigor@sysoev.ru nxt_router_app_use(task, action->u.application, 1); 1139964Sigor@sysoev.ru 11401264Sigor@sysoev.ru action->handler = nxt_http_application_handler; 1141964Sigor@sysoev.ru 11421264Sigor@sysoev.ru return action; 1143964Sigor@sysoev.ru } 1144964Sigor@sysoev.ru 1145964Sigor@sysoev.ru 1146964Sigor@sysoev.ru void 1147964Sigor@sysoev.ru nxt_http_routes_cleanup(nxt_task_t *task, nxt_http_routes_t *routes) 1148964Sigor@sysoev.ru { 11491033Svbart@nginx.com nxt_http_route_t **route, **end; 1150964Sigor@sysoev.ru 1151964Sigor@sysoev.ru if (routes != NULL) { 1152964Sigor@sysoev.ru route = &routes->route[0]; 11531033Svbart@nginx.com end = route + routes->items; 1154964Sigor@sysoev.ru 11551058Sigor@sysoev.ru while (route < end) { 1156964Sigor@sysoev.ru nxt_http_route_cleanup(task, *route); 1157964Sigor@sysoev.ru 1158964Sigor@sysoev.ru route++; 11591058Sigor@sysoev.ru } 1160964Sigor@sysoev.ru } 1161964Sigor@sysoev.ru } 1162964Sigor@sysoev.ru 1163964Sigor@sysoev.ru 1164964Sigor@sysoev.ru static void 1165964Sigor@sysoev.ru nxt_http_route_cleanup(nxt_task_t *task, nxt_http_route_t *route) 1166964Sigor@sysoev.ru { 11671033Svbart@nginx.com nxt_http_route_match_t **match, **end; 1168964Sigor@sysoev.ru 1169964Sigor@sysoev.ru match = &route->match[0]; 11701033Svbart@nginx.com end = match + route->items; 1171964Sigor@sysoev.ru 11721058Sigor@sysoev.ru while (match < end) { 11731264Sigor@sysoev.ru nxt_http_action_cleanup(task, &(*match)->action); 1174964Sigor@sysoev.ru 1175964Sigor@sysoev.ru match++; 11761058Sigor@sysoev.ru } 1177964Sigor@sysoev.ru } 1178964Sigor@sysoev.ru 1179964Sigor@sysoev.ru 1180964Sigor@sysoev.ru void 11811264Sigor@sysoev.ru nxt_http_action_cleanup(nxt_task_t *task, nxt_http_action_t *action) 1182964Sigor@sysoev.ru { 11831264Sigor@sysoev.ru if (action->handler == nxt_http_application_handler) { 11841264Sigor@sysoev.ru nxt_router_app_use(task, action->u.application, -1); 1185964Sigor@sysoev.ru } 1186964Sigor@sysoev.ru } 1187964Sigor@sysoev.ru 1188964Sigor@sysoev.ru 11891264Sigor@sysoev.ru static nxt_http_action_t * 11901264Sigor@sysoev.ru nxt_http_route_handler(nxt_task_t *task, nxt_http_request_t *r, 11911264Sigor@sysoev.ru nxt_http_action_t *start) 1192964Sigor@sysoev.ru { 1193964Sigor@sysoev.ru nxt_http_route_t *route; 11941264Sigor@sysoev.ru nxt_http_action_t *action; 11951033Svbart@nginx.com nxt_http_route_match_t **match, **end; 1196964Sigor@sysoev.ru 1197964Sigor@sysoev.ru route = start->u.route; 1198964Sigor@sysoev.ru match = &route->match[0]; 11991033Svbart@nginx.com end = match + route->items; 1200964Sigor@sysoev.ru 12011033Svbart@nginx.com while (match < end) { 12021264Sigor@sysoev.ru action = nxt_http_route_match(r, *match); 12031264Sigor@sysoev.ru if (action != NULL) { 12041264Sigor@sysoev.ru return action; 1205964Sigor@sysoev.ru } 1206964Sigor@sysoev.ru 1207964Sigor@sysoev.ru match++; 1208964Sigor@sysoev.ru } 1209964Sigor@sysoev.ru 1210964Sigor@sysoev.ru nxt_http_request_error(task, r, NXT_HTTP_NOT_FOUND); 1211964Sigor@sysoev.ru 1212964Sigor@sysoev.ru return NULL; 1213964Sigor@sysoev.ru } 1214964Sigor@sysoev.ru 1215964Sigor@sysoev.ru 12161264Sigor@sysoev.ru static nxt_http_action_t * 1217964Sigor@sysoev.ru nxt_http_route_match(nxt_http_request_t *r, nxt_http_route_match_t *match) 1218964Sigor@sysoev.ru { 12191060Sigor@sysoev.ru nxt_int_t ret; 12201059Sigor@sysoev.ru nxt_http_route_test_t *test, *end; 12211059Sigor@sysoev.ru 12221059Sigor@sysoev.ru test = &match->test[0]; 12231059Sigor@sysoev.ru end = test + match->items; 1224964Sigor@sysoev.ru 12251059Sigor@sysoev.ru while (test < end) { 1226*1324Saxel.duch@nginx.com switch (test->rule->object) { 1227*1324Saxel.duch@nginx.com case NXT_HTTP_ROUTE_TABLE: 1228*1324Saxel.duch@nginx.com ret = nxt_http_route_table(r, test->table); 1229*1324Saxel.duch@nginx.com break; 1230*1324Saxel.duch@nginx.com case NXT_HTTP_ROUTE_SOURCE: 1231*1324Saxel.duch@nginx.com ret = nxt_http_route_addr_rule(r, test->addr_rule, r->remote); 1232*1324Saxel.duch@nginx.com break; 1233*1324Saxel.duch@nginx.com default: 12341059Sigor@sysoev.ru ret = nxt_http_route_rule(r, test->rule); 1235*1324Saxel.duch@nginx.com break; 12361059Sigor@sysoev.ru } 12371059Sigor@sysoev.ru 12381060Sigor@sysoev.ru if (ret <= 0) { 12391264Sigor@sysoev.ru /* 0 => NULL, -1 => NXT_HTTP_ACTION_ERROR. */ 12401264Sigor@sysoev.ru return (nxt_http_action_t *) (intptr_t) ret; 1241964Sigor@sysoev.ru } 1242964Sigor@sysoev.ru 12431059Sigor@sysoev.ru test++; 1244964Sigor@sysoev.ru } 1245964Sigor@sysoev.ru 12461264Sigor@sysoev.ru return &match->action; 1247964Sigor@sysoev.ru } 1248964Sigor@sysoev.ru 1249964Sigor@sysoev.ru 12501060Sigor@sysoev.ru static nxt_int_t 12511059Sigor@sysoev.ru nxt_http_route_table(nxt_http_request_t *r, nxt_http_route_table_t *table) 1252964Sigor@sysoev.ru { 12531060Sigor@sysoev.ru nxt_int_t ret; 12541059Sigor@sysoev.ru nxt_http_route_ruleset_t **ruleset, **end; 12551059Sigor@sysoev.ru 12561059Sigor@sysoev.ru ret = 1; 12571059Sigor@sysoev.ru ruleset = &table->ruleset[0]; 12581059Sigor@sysoev.ru end = ruleset + table->items; 12591059Sigor@sysoev.ru 12601059Sigor@sysoev.ru while (ruleset < end) { 12611059Sigor@sysoev.ru ret = nxt_http_route_ruleset(r, *ruleset); 12621059Sigor@sysoev.ru 12631060Sigor@sysoev.ru if (ret != 0) { 12641059Sigor@sysoev.ru return ret; 12651059Sigor@sysoev.ru } 1266964Sigor@sysoev.ru 12671059Sigor@sysoev.ru ruleset++; 12681059Sigor@sysoev.ru } 12691059Sigor@sysoev.ru 12701059Sigor@sysoev.ru return ret; 12711059Sigor@sysoev.ru } 12721059Sigor@sysoev.ru 1273964Sigor@sysoev.ru 12741060Sigor@sysoev.ru static nxt_int_t 12751059Sigor@sysoev.ru nxt_http_route_ruleset(nxt_http_request_t *r, nxt_http_route_ruleset_t *ruleset) 12761059Sigor@sysoev.ru { 12771060Sigor@sysoev.ru nxt_int_t ret; 12781059Sigor@sysoev.ru nxt_http_route_rule_t **rule, **end; 1279964Sigor@sysoev.ru 12801059Sigor@sysoev.ru rule = &ruleset->rule[0]; 12811059Sigor@sysoev.ru end = rule + ruleset->items; 1282964Sigor@sysoev.ru 12831059Sigor@sysoev.ru while (rule < end) { 12841060Sigor@sysoev.ru ret = nxt_http_route_rule(r, *rule); 12851060Sigor@sysoev.ru 12861060Sigor@sysoev.ru if (ret <= 0) { 12871060Sigor@sysoev.ru return ret; 1288964Sigor@sysoev.ru } 1289964Sigor@sysoev.ru 12901059Sigor@sysoev.ru rule++; 12911059Sigor@sysoev.ru } 12921059Sigor@sysoev.ru 12931059Sigor@sysoev.ru return 1; 12941059Sigor@sysoev.ru } 12951059Sigor@sysoev.ru 1296964Sigor@sysoev.ru 12971060Sigor@sysoev.ru static nxt_int_t 12981059Sigor@sysoev.ru nxt_http_route_rule(nxt_http_request_t *r, nxt_http_route_rule_t *rule) 12991059Sigor@sysoev.ru { 13001059Sigor@sysoev.ru void *p, **pp; 13011059Sigor@sysoev.ru u_char *start; 13021059Sigor@sysoev.ru size_t length; 13031059Sigor@sysoev.ru nxt_str_t *s; 13041059Sigor@sysoev.ru 13051059Sigor@sysoev.ru switch (rule->object) { 13061059Sigor@sysoev.ru 13071059Sigor@sysoev.ru case NXT_HTTP_ROUTE_HEADER: 13081059Sigor@sysoev.ru return nxt_http_route_header(r, rule); 1309964Sigor@sysoev.ru 13101059Sigor@sysoev.ru case NXT_HTTP_ROUTE_ARGUMENT: 13111061Sigor@sysoev.ru return nxt_http_route_arguments(r, rule); 1312964Sigor@sysoev.ru 13131059Sigor@sysoev.ru case NXT_HTTP_ROUTE_COOKIE: 13141062Sigor@sysoev.ru return nxt_http_route_cookies(r, rule); 13151059Sigor@sysoev.ru 13161110Saxel.duch@nginx.com case NXT_HTTP_ROUTE_SCHEME: 13171110Saxel.duch@nginx.com return nxt_http_route_scheme(r, rule); 13181110Saxel.duch@nginx.com 13191059Sigor@sysoev.ru default: 13201059Sigor@sysoev.ru break; 13211059Sigor@sysoev.ru } 1322964Sigor@sysoev.ru 13231059Sigor@sysoev.ru p = nxt_pointer_to(r, rule->u.offset); 13241059Sigor@sysoev.ru 13251059Sigor@sysoev.ru if (rule->object == NXT_HTTP_ROUTE_STRING) { 13261059Sigor@sysoev.ru s = p; 1327964Sigor@sysoev.ru 13281059Sigor@sysoev.ru } else { 13291059Sigor@sysoev.ru /* NXT_HTTP_ROUTE_STRING_PTR */ 13301059Sigor@sysoev.ru pp = p; 13311059Sigor@sysoev.ru s = *pp; 1332964Sigor@sysoev.ru 13331059Sigor@sysoev.ru if (s == NULL) { 1334964Sigor@sysoev.ru return 0; 1335964Sigor@sysoev.ru } 1336964Sigor@sysoev.ru } 1337964Sigor@sysoev.ru 13381059Sigor@sysoev.ru length = s->length; 13391059Sigor@sysoev.ru start = s->start; 13401059Sigor@sysoev.ru 13411059Sigor@sysoev.ru return nxt_http_route_test_rule(r, rule, start, length); 13421059Sigor@sysoev.ru } 13431059Sigor@sysoev.ru 13441059Sigor@sysoev.ru 13451060Sigor@sysoev.ru static nxt_int_t 1346*1324Saxel.duch@nginx.com nxt_http_route_addr_pattern_match(nxt_http_route_addr_pattern_t *p, 1347*1324Saxel.duch@nginx.com nxt_sockaddr_t *sa) 1348*1324Saxel.duch@nginx.com { 1349*1324Saxel.duch@nginx.com #if (NXT_INET6) 1350*1324Saxel.duch@nginx.com uint32_t i; 1351*1324Saxel.duch@nginx.com #endif 1352*1324Saxel.duch@nginx.com in_port_t in_port; 1353*1324Saxel.duch@nginx.com nxt_int_t match; 1354*1324Saxel.duch@nginx.com struct sockaddr_in *sin; 1355*1324Saxel.duch@nginx.com #if (NXT_INET6) 1356*1324Saxel.duch@nginx.com struct sockaddr_in6 *sin6; 1357*1324Saxel.duch@nginx.com #endif 1358*1324Saxel.duch@nginx.com nxt_http_route_addr_base_t *base; 1359*1324Saxel.duch@nginx.com 1360*1324Saxel.duch@nginx.com base = &p->base; 1361*1324Saxel.duch@nginx.com 1362*1324Saxel.duch@nginx.com switch (sa->u.sockaddr.sa_family) { 1363*1324Saxel.duch@nginx.com 1364*1324Saxel.duch@nginx.com case AF_INET: 1365*1324Saxel.duch@nginx.com 1366*1324Saxel.duch@nginx.com match = (base->addr_family == AF_INET 1367*1324Saxel.duch@nginx.com || base->addr_family == AF_UNSPEC); 1368*1324Saxel.duch@nginx.com if (!match) { 1369*1324Saxel.duch@nginx.com break; 1370*1324Saxel.duch@nginx.com } 1371*1324Saxel.duch@nginx.com 1372*1324Saxel.duch@nginx.com sin = &sa->u.sockaddr_in; 1373*1324Saxel.duch@nginx.com in_port = ntohs(sin->sin_port); 1374*1324Saxel.duch@nginx.com 1375*1324Saxel.duch@nginx.com match = (in_port >= base->port.start && in_port <= base->port.end); 1376*1324Saxel.duch@nginx.com if (!match) { 1377*1324Saxel.duch@nginx.com break; 1378*1324Saxel.duch@nginx.com } 1379*1324Saxel.duch@nginx.com 1380*1324Saxel.duch@nginx.com switch (base->match_type) { 1381*1324Saxel.duch@nginx.com 1382*1324Saxel.duch@nginx.com case NXT_HTTP_ROUTE_ADDR_ANY: 1383*1324Saxel.duch@nginx.com break; 1384*1324Saxel.duch@nginx.com 1385*1324Saxel.duch@nginx.com case NXT_HTTP_ROUTE_ADDR_EXACT: 1386*1324Saxel.duch@nginx.com match = (nxt_memcmp(&sin->sin_addr, &p->addr.v4.start, 1387*1324Saxel.duch@nginx.com sizeof(struct in_addr)) 1388*1324Saxel.duch@nginx.com == 0); 1389*1324Saxel.duch@nginx.com break; 1390*1324Saxel.duch@nginx.com 1391*1324Saxel.duch@nginx.com case NXT_HTTP_ROUTE_ADDR_RANGE: 1392*1324Saxel.duch@nginx.com match = (nxt_memcmp(&sin->sin_addr, &p->addr.v4.start, 1393*1324Saxel.duch@nginx.com sizeof(struct in_addr)) >= 0 1394*1324Saxel.duch@nginx.com && nxt_memcmp(&sin->sin_addr, &p->addr.v4.end, 1395*1324Saxel.duch@nginx.com sizeof(struct in_addr)) <= 0); 1396*1324Saxel.duch@nginx.com break; 1397*1324Saxel.duch@nginx.com 1398*1324Saxel.duch@nginx.com case NXT_HTTP_ROUTE_ADDR_CIDR: 1399*1324Saxel.duch@nginx.com match = ((sin->sin_addr.s_addr & p->addr.v4.end) 1400*1324Saxel.duch@nginx.com == p->addr.v4.start); 1401*1324Saxel.duch@nginx.com break; 1402*1324Saxel.duch@nginx.com 1403*1324Saxel.duch@nginx.com default: 1404*1324Saxel.duch@nginx.com nxt_unreachable(); 1405*1324Saxel.duch@nginx.com } 1406*1324Saxel.duch@nginx.com 1407*1324Saxel.duch@nginx.com break; 1408*1324Saxel.duch@nginx.com 1409*1324Saxel.duch@nginx.com #if (NXT_INET6) 1410*1324Saxel.duch@nginx.com case AF_INET6: 1411*1324Saxel.duch@nginx.com 1412*1324Saxel.duch@nginx.com match = (base->addr_family == AF_INET6 1413*1324Saxel.duch@nginx.com || base->addr_family == AF_UNSPEC); 1414*1324Saxel.duch@nginx.com if (!match) { 1415*1324Saxel.duch@nginx.com break; 1416*1324Saxel.duch@nginx.com } 1417*1324Saxel.duch@nginx.com 1418*1324Saxel.duch@nginx.com sin6 = &sa->u.sockaddr_in6; 1419*1324Saxel.duch@nginx.com in_port = ntohs(sin6->sin6_port); 1420*1324Saxel.duch@nginx.com 1421*1324Saxel.duch@nginx.com match = (in_port >= base->port.start && in_port <= base->port.end); 1422*1324Saxel.duch@nginx.com if (!match) { 1423*1324Saxel.duch@nginx.com break; 1424*1324Saxel.duch@nginx.com } 1425*1324Saxel.duch@nginx.com 1426*1324Saxel.duch@nginx.com switch (base->match_type) { 1427*1324Saxel.duch@nginx.com 1428*1324Saxel.duch@nginx.com case NXT_HTTP_ROUTE_ADDR_ANY: 1429*1324Saxel.duch@nginx.com break; 1430*1324Saxel.duch@nginx.com 1431*1324Saxel.duch@nginx.com case NXT_HTTP_ROUTE_ADDR_EXACT: 1432*1324Saxel.duch@nginx.com match = (nxt_memcmp(&sin6->sin6_addr, &p->addr.v6.start, 1433*1324Saxel.duch@nginx.com sizeof(struct in6_addr)) 1434*1324Saxel.duch@nginx.com == 0); 1435*1324Saxel.duch@nginx.com break; 1436*1324Saxel.duch@nginx.com 1437*1324Saxel.duch@nginx.com case NXT_HTTP_ROUTE_ADDR_RANGE: 1438*1324Saxel.duch@nginx.com match = (nxt_memcmp(&sin6->sin6_addr, &p->addr.v6.start, 1439*1324Saxel.duch@nginx.com sizeof(struct in6_addr)) >= 0 1440*1324Saxel.duch@nginx.com && nxt_memcmp(&sin6->sin6_addr, &p->addr.v6.end, 1441*1324Saxel.duch@nginx.com sizeof(struct in6_addr)) <= 0); 1442*1324Saxel.duch@nginx.com break; 1443*1324Saxel.duch@nginx.com 1444*1324Saxel.duch@nginx.com case NXT_HTTP_ROUTE_ADDR_CIDR: 1445*1324Saxel.duch@nginx.com for (i = 0; i < 16; i++) { 1446*1324Saxel.duch@nginx.com match = ((sin6->sin6_addr.s6_addr[i] 1447*1324Saxel.duch@nginx.com & p->addr.v6.end.s6_addr[i]) 1448*1324Saxel.duch@nginx.com == p->addr.v6.start.s6_addr[i]); 1449*1324Saxel.duch@nginx.com 1450*1324Saxel.duch@nginx.com if (!match) { 1451*1324Saxel.duch@nginx.com break; 1452*1324Saxel.duch@nginx.com } 1453*1324Saxel.duch@nginx.com } 1454*1324Saxel.duch@nginx.com 1455*1324Saxel.duch@nginx.com break; 1456*1324Saxel.duch@nginx.com 1457*1324Saxel.duch@nginx.com default: 1458*1324Saxel.duch@nginx.com nxt_unreachable(); 1459*1324Saxel.duch@nginx.com } 1460*1324Saxel.duch@nginx.com 1461*1324Saxel.duch@nginx.com break; 1462*1324Saxel.duch@nginx.com #endif 1463*1324Saxel.duch@nginx.com 1464*1324Saxel.duch@nginx.com default: 1465*1324Saxel.duch@nginx.com match = 0; 1466*1324Saxel.duch@nginx.com break; 1467*1324Saxel.duch@nginx.com } 1468*1324Saxel.duch@nginx.com 1469*1324Saxel.duch@nginx.com return match ^ base->negative; 1470*1324Saxel.duch@nginx.com } 1471*1324Saxel.duch@nginx.com 1472*1324Saxel.duch@nginx.com 1473*1324Saxel.duch@nginx.com static nxt_int_t 1474*1324Saxel.duch@nginx.com nxt_http_route_addr_rule(nxt_http_request_t *r, 1475*1324Saxel.duch@nginx.com nxt_http_route_addr_rule_t *addr_rule, nxt_sockaddr_t *sa) 1476*1324Saxel.duch@nginx.com { 1477*1324Saxel.duch@nginx.com uint32_t i, n; 1478*1324Saxel.duch@nginx.com nxt_http_route_addr_pattern_t *p; 1479*1324Saxel.duch@nginx.com 1480*1324Saxel.duch@nginx.com n = addr_rule->items; 1481*1324Saxel.duch@nginx.com 1482*1324Saxel.duch@nginx.com for (i = 0; i < n; i++) { 1483*1324Saxel.duch@nginx.com p = &addr_rule->addr_pattern[i]; 1484*1324Saxel.duch@nginx.com if (nxt_http_route_addr_pattern_match(p, sa)) { 1485*1324Saxel.duch@nginx.com return 1; 1486*1324Saxel.duch@nginx.com } 1487*1324Saxel.duch@nginx.com } 1488*1324Saxel.duch@nginx.com 1489*1324Saxel.duch@nginx.com return 0; 1490*1324Saxel.duch@nginx.com } 1491*1324Saxel.duch@nginx.com 1492*1324Saxel.duch@nginx.com 1493*1324Saxel.duch@nginx.com static nxt_int_t 14941059Sigor@sysoev.ru nxt_http_route_header(nxt_http_request_t *r, nxt_http_route_rule_t *rule) 14951059Sigor@sysoev.ru { 14961060Sigor@sysoev.ru nxt_int_t ret; 14971059Sigor@sysoev.ru nxt_http_field_t *f; 14981059Sigor@sysoev.ru 14991059Sigor@sysoev.ru ret = 0; 15001059Sigor@sysoev.ru 15011059Sigor@sysoev.ru nxt_list_each(f, r->fields) { 15021059Sigor@sysoev.ru 15031059Sigor@sysoev.ru if (rule->u.name.hash != f->hash 15041059Sigor@sysoev.ru || rule->u.name.length != f->name_length 15051059Sigor@sysoev.ru || nxt_strncasecmp(rule->u.name.start, f->name, f->name_length) 15061059Sigor@sysoev.ru != 0) 15071059Sigor@sysoev.ru { 15081059Sigor@sysoev.ru continue; 15091059Sigor@sysoev.ru } 15101059Sigor@sysoev.ru 15111059Sigor@sysoev.ru ret = nxt_http_route_test_rule(r, rule, f->value, f->value_length); 15121059Sigor@sysoev.ru 15131060Sigor@sysoev.ru if (ret == 0) { 15141059Sigor@sysoev.ru return ret; 15151059Sigor@sysoev.ru } 15161059Sigor@sysoev.ru 15171059Sigor@sysoev.ru } nxt_list_loop; 15181059Sigor@sysoev.ru 15191059Sigor@sysoev.ru return ret; 15201059Sigor@sysoev.ru } 15211059Sigor@sysoev.ru 15221059Sigor@sysoev.ru 15231060Sigor@sysoev.ru static nxt_int_t 15241061Sigor@sysoev.ru nxt_http_route_arguments(nxt_http_request_t *r, nxt_http_route_rule_t *rule) 15251061Sigor@sysoev.ru { 15261061Sigor@sysoev.ru nxt_array_t *arguments; 15271061Sigor@sysoev.ru 15281061Sigor@sysoev.ru if (r->args == NULL) { 15291061Sigor@sysoev.ru return 0; 15301061Sigor@sysoev.ru } 15311061Sigor@sysoev.ru 15321061Sigor@sysoev.ru arguments = nxt_http_route_arguments_parse(r); 15331061Sigor@sysoev.ru if (nxt_slow_path(arguments == NULL)) { 15341061Sigor@sysoev.ru return -1; 15351061Sigor@sysoev.ru } 15361061Sigor@sysoev.ru 15371061Sigor@sysoev.ru return nxt_http_route_test_argument(r, rule, arguments); 15381061Sigor@sysoev.ru } 15391061Sigor@sysoev.ru 15401061Sigor@sysoev.ru 15411061Sigor@sysoev.ru static nxt_array_t * 15421061Sigor@sysoev.ru nxt_http_route_arguments_parse(nxt_http_request_t *r) 15431061Sigor@sysoev.ru { 15441061Sigor@sysoev.ru size_t name_length; 15451061Sigor@sysoev.ru u_char c, *p, *start, *end, *name; 15461061Sigor@sysoev.ru uint32_t hash; 15471061Sigor@sysoev.ru nxt_bool_t valid; 15481061Sigor@sysoev.ru nxt_array_t *args; 15491061Sigor@sysoev.ru nxt_http_name_value_t *nv; 15501061Sigor@sysoev.ru 15511061Sigor@sysoev.ru if (r->arguments != NULL) { 15521061Sigor@sysoev.ru return r->arguments; 15531061Sigor@sysoev.ru } 15541061Sigor@sysoev.ru 15551061Sigor@sysoev.ru args = nxt_array_create(r->mem_pool, 2, sizeof(nxt_http_name_value_t)); 15561061Sigor@sysoev.ru if (nxt_slow_path(args == NULL)) { 15571061Sigor@sysoev.ru return NULL; 15581061Sigor@sysoev.ru } 15591061Sigor@sysoev.ru 15601061Sigor@sysoev.ru hash = NXT_HTTP_FIELD_HASH_INIT; 15611061Sigor@sysoev.ru valid = 1; 15621061Sigor@sysoev.ru name = NULL; 15631061Sigor@sysoev.ru name_length = 0; 15641061Sigor@sysoev.ru 15651061Sigor@sysoev.ru start = r->args->start; 15661061Sigor@sysoev.ru end = start + r->args->length; 15671061Sigor@sysoev.ru 15681061Sigor@sysoev.ru for (p = start; p < end; p++) { 15691061Sigor@sysoev.ru c = *p; 15701061Sigor@sysoev.ru 15711061Sigor@sysoev.ru if (c == '=') { 15721061Sigor@sysoev.ru name_length = p - start; 15731061Sigor@sysoev.ru name = start; 15741061Sigor@sysoev.ru start = p + 1; 15751061Sigor@sysoev.ru valid = (name_length != 0); 15761061Sigor@sysoev.ru 15771061Sigor@sysoev.ru } else if (c == '&') { 15781061Sigor@sysoev.ru if (valid) { 15791061Sigor@sysoev.ru nv = nxt_http_route_argument(args, name, name_length, hash, 15801061Sigor@sysoev.ru start, p); 15811061Sigor@sysoev.ru if (nxt_slow_path(nv == NULL)) { 15821061Sigor@sysoev.ru return NULL; 15831061Sigor@sysoev.ru } 15841061Sigor@sysoev.ru } 15851061Sigor@sysoev.ru 15861061Sigor@sysoev.ru hash = NXT_HTTP_FIELD_HASH_INIT; 15871061Sigor@sysoev.ru valid = 1; 15881061Sigor@sysoev.ru name = NULL; 15891061Sigor@sysoev.ru start = p + 1; 15901061Sigor@sysoev.ru 15911061Sigor@sysoev.ru } else if (name == NULL) { 15921061Sigor@sysoev.ru hash = nxt_http_field_hash_char(hash, c); 15931061Sigor@sysoev.ru } 15941061Sigor@sysoev.ru } 15951061Sigor@sysoev.ru 15961061Sigor@sysoev.ru if (valid) { 15971061Sigor@sysoev.ru nv = nxt_http_route_argument(args, name, name_length, hash, start, p); 15981061Sigor@sysoev.ru if (nxt_slow_path(nv == NULL)) { 15991061Sigor@sysoev.ru return NULL; 16001061Sigor@sysoev.ru } 16011061Sigor@sysoev.ru } 16021061Sigor@sysoev.ru 16031061Sigor@sysoev.ru r->arguments = args; 16041061Sigor@sysoev.ru 16051061Sigor@sysoev.ru return args; 16061061Sigor@sysoev.ru } 16071061Sigor@sysoev.ru 16081061Sigor@sysoev.ru 16091061Sigor@sysoev.ru static nxt_http_name_value_t * 16101061Sigor@sysoev.ru nxt_http_route_argument(nxt_array_t *array, u_char *name, size_t name_length, 16111061Sigor@sysoev.ru uint32_t hash, u_char *start, u_char *end) 16121061Sigor@sysoev.ru { 16131061Sigor@sysoev.ru size_t length; 16141061Sigor@sysoev.ru nxt_http_name_value_t *nv; 16151061Sigor@sysoev.ru 16161061Sigor@sysoev.ru nv = nxt_array_add(array); 16171061Sigor@sysoev.ru if (nxt_slow_path(nv == NULL)) { 16181061Sigor@sysoev.ru return NULL; 16191061Sigor@sysoev.ru } 16201061Sigor@sysoev.ru 16211061Sigor@sysoev.ru nv->hash = nxt_http_field_hash_end(hash) & 0xFFFF; 16221061Sigor@sysoev.ru 16231061Sigor@sysoev.ru length = end - start; 16241061Sigor@sysoev.ru 16251061Sigor@sysoev.ru if (name == NULL) { 16261061Sigor@sysoev.ru name_length = length; 16271061Sigor@sysoev.ru name = start; 16281061Sigor@sysoev.ru length = 0; 16291061Sigor@sysoev.ru } 16301061Sigor@sysoev.ru 16311061Sigor@sysoev.ru nv->name_length = name_length; 16321061Sigor@sysoev.ru nv->value_length = length; 16331061Sigor@sysoev.ru nv->name = name; 16341061Sigor@sysoev.ru nv->value = start; 16351061Sigor@sysoev.ru 16361061Sigor@sysoev.ru return nv; 16371061Sigor@sysoev.ru } 16381061Sigor@sysoev.ru 16391061Sigor@sysoev.ru 16401061Sigor@sysoev.ru static nxt_int_t 16411061Sigor@sysoev.ru nxt_http_route_test_argument(nxt_http_request_t *r, 16421061Sigor@sysoev.ru nxt_http_route_rule_t *rule, nxt_array_t *array) 16431061Sigor@sysoev.ru { 16441061Sigor@sysoev.ru nxt_bool_t ret; 16451061Sigor@sysoev.ru nxt_http_name_value_t *nv, *end; 16461061Sigor@sysoev.ru 16471061Sigor@sysoev.ru ret = 0; 16481061Sigor@sysoev.ru 16491061Sigor@sysoev.ru nv = array->elts; 16501061Sigor@sysoev.ru end = nv + array->nelts; 16511061Sigor@sysoev.ru 16521061Sigor@sysoev.ru while (nv < end) { 16531061Sigor@sysoev.ru 16541061Sigor@sysoev.ru if (rule->u.name.hash == nv->hash 16551061Sigor@sysoev.ru && rule->u.name.length == nv->name_length 16561061Sigor@sysoev.ru && nxt_memcmp(rule->u.name.start, nv->name, nv->name_length) == 0) 16571061Sigor@sysoev.ru { 16581061Sigor@sysoev.ru ret = nxt_http_route_test_rule(r, rule, nv->value, 16591061Sigor@sysoev.ru nv->value_length); 16601061Sigor@sysoev.ru if (ret == 0) { 16611061Sigor@sysoev.ru break; 16621061Sigor@sysoev.ru } 16631061Sigor@sysoev.ru } 16641061Sigor@sysoev.ru 16651061Sigor@sysoev.ru nv++; 16661061Sigor@sysoev.ru } 16671061Sigor@sysoev.ru 16681061Sigor@sysoev.ru return ret; 16691061Sigor@sysoev.ru } 16701061Sigor@sysoev.ru 16711061Sigor@sysoev.ru 16721061Sigor@sysoev.ru static nxt_int_t 16731110Saxel.duch@nginx.com nxt_http_route_scheme(nxt_http_request_t *r, nxt_http_route_rule_t *rule) 16741110Saxel.duch@nginx.com { 16751110Saxel.duch@nginx.com nxt_bool_t tls, https; 16761110Saxel.duch@nginx.com 16771110Saxel.duch@nginx.com https = (rule->pattern[0].length1 == nxt_length("https")); 16781110Saxel.duch@nginx.com tls = (r->tls != NULL); 16791110Saxel.duch@nginx.com 16801110Saxel.duch@nginx.com return (tls == https); 16811110Saxel.duch@nginx.com } 16821110Saxel.duch@nginx.com 16831110Saxel.duch@nginx.com 16841110Saxel.duch@nginx.com static nxt_int_t 16851062Sigor@sysoev.ru nxt_http_route_cookies(nxt_http_request_t *r, nxt_http_route_rule_t *rule) 16861062Sigor@sysoev.ru { 16871062Sigor@sysoev.ru nxt_array_t *cookies; 16881062Sigor@sysoev.ru 16891062Sigor@sysoev.ru cookies = nxt_http_route_cookies_parse(r); 16901062Sigor@sysoev.ru if (nxt_slow_path(cookies == NULL)) { 16911062Sigor@sysoev.ru return -1; 16921062Sigor@sysoev.ru } 16931062Sigor@sysoev.ru 16941062Sigor@sysoev.ru return nxt_http_route_test_cookie(r, rule, cookies); 16951062Sigor@sysoev.ru } 16961062Sigor@sysoev.ru 16971062Sigor@sysoev.ru 16981062Sigor@sysoev.ru static nxt_array_t * 16991062Sigor@sysoev.ru nxt_http_route_cookies_parse(nxt_http_request_t *r) 17001062Sigor@sysoev.ru { 17011062Sigor@sysoev.ru nxt_int_t ret; 17021062Sigor@sysoev.ru nxt_array_t *cookies; 17031062Sigor@sysoev.ru nxt_http_field_t *f; 17041062Sigor@sysoev.ru 17051062Sigor@sysoev.ru if (r->cookies != NULL) { 17061062Sigor@sysoev.ru return r->cookies; 17071062Sigor@sysoev.ru } 17081062Sigor@sysoev.ru 17091062Sigor@sysoev.ru cookies = nxt_array_create(r->mem_pool, 2, sizeof(nxt_http_name_value_t)); 17101062Sigor@sysoev.ru if (nxt_slow_path(cookies == NULL)) { 17111062Sigor@sysoev.ru return NULL; 17121062Sigor@sysoev.ru } 17131062Sigor@sysoev.ru 17141062Sigor@sysoev.ru nxt_list_each(f, r->fields) { 17151062Sigor@sysoev.ru 17161062Sigor@sysoev.ru if (f->hash != NJS_COOKIE_HASH 17171062Sigor@sysoev.ru || f->name_length != 6 17181062Sigor@sysoev.ru || nxt_strncasecmp(f->name, (u_char *) "Cookie", 6) != 0) 17191062Sigor@sysoev.ru { 17201062Sigor@sysoev.ru continue; 17211062Sigor@sysoev.ru } 17221062Sigor@sysoev.ru 17231062Sigor@sysoev.ru ret = nxt_http_route_cookie_parse(cookies, f->value, 17241062Sigor@sysoev.ru f->value + f->value_length); 17251062Sigor@sysoev.ru if (ret != NXT_OK) { 17261062Sigor@sysoev.ru return NULL; 17271062Sigor@sysoev.ru } 17281062Sigor@sysoev.ru 17291062Sigor@sysoev.ru } nxt_list_loop; 17301062Sigor@sysoev.ru 17311062Sigor@sysoev.ru r->cookies = cookies; 17321062Sigor@sysoev.ru 17331062Sigor@sysoev.ru return cookies; 17341062Sigor@sysoev.ru } 17351062Sigor@sysoev.ru 17361062Sigor@sysoev.ru 17371062Sigor@sysoev.ru static nxt_int_t 17381062Sigor@sysoev.ru nxt_http_route_cookie_parse(nxt_array_t *cookies, u_char *start, u_char *end) 17391062Sigor@sysoev.ru { 17401062Sigor@sysoev.ru size_t name_length; 17411062Sigor@sysoev.ru u_char c, *p, *name; 17421062Sigor@sysoev.ru nxt_http_name_value_t *nv; 17431062Sigor@sysoev.ru 17441062Sigor@sysoev.ru name = NULL; 17451062Sigor@sysoev.ru name_length = 0; 17461062Sigor@sysoev.ru 17471062Sigor@sysoev.ru for (p = start; p < end; p++) { 17481062Sigor@sysoev.ru c = *p; 17491062Sigor@sysoev.ru 17501062Sigor@sysoev.ru if (c == '=') { 17511062Sigor@sysoev.ru while (start[0] == ' ') { start++; } 17521062Sigor@sysoev.ru 17531062Sigor@sysoev.ru name_length = p - start; 17541062Sigor@sysoev.ru 17551062Sigor@sysoev.ru if (name_length != 0) { 17561062Sigor@sysoev.ru name = start; 17571062Sigor@sysoev.ru } 17581062Sigor@sysoev.ru 17591062Sigor@sysoev.ru start = p + 1; 17601062Sigor@sysoev.ru 17611062Sigor@sysoev.ru } else if (c == ';') { 17621062Sigor@sysoev.ru if (name != NULL) { 17631062Sigor@sysoev.ru nv = nxt_http_route_cookie(cookies, name, name_length, 17641062Sigor@sysoev.ru start, p); 17651062Sigor@sysoev.ru if (nxt_slow_path(nv == NULL)) { 17661062Sigor@sysoev.ru return NXT_ERROR; 17671062Sigor@sysoev.ru } 17681062Sigor@sysoev.ru } 17691062Sigor@sysoev.ru 17701062Sigor@sysoev.ru name = NULL; 17711062Sigor@sysoev.ru start = p + 1; 17721062Sigor@sysoev.ru } 17731062Sigor@sysoev.ru } 17741062Sigor@sysoev.ru 17751062Sigor@sysoev.ru if (name != NULL) { 17761062Sigor@sysoev.ru nv = nxt_http_route_cookie(cookies, name, name_length, start, p); 17771062Sigor@sysoev.ru if (nxt_slow_path(nv == NULL)) { 17781062Sigor@sysoev.ru return NXT_ERROR; 17791062Sigor@sysoev.ru } 17801062Sigor@sysoev.ru } 17811062Sigor@sysoev.ru 17821062Sigor@sysoev.ru return NXT_OK; 17831062Sigor@sysoev.ru } 17841062Sigor@sysoev.ru 17851062Sigor@sysoev.ru 17861062Sigor@sysoev.ru static nxt_http_name_value_t * 17871062Sigor@sysoev.ru nxt_http_route_cookie(nxt_array_t *array, u_char *name, size_t name_length, 17881062Sigor@sysoev.ru u_char *start, u_char *end) 17891062Sigor@sysoev.ru { 17901062Sigor@sysoev.ru u_char c, *p; 17911062Sigor@sysoev.ru uint32_t hash; 17921062Sigor@sysoev.ru nxt_http_name_value_t *nv; 17931062Sigor@sysoev.ru 17941062Sigor@sysoev.ru nv = nxt_array_add(array); 17951062Sigor@sysoev.ru if (nxt_slow_path(nv == NULL)) { 17961062Sigor@sysoev.ru return NULL; 17971062Sigor@sysoev.ru } 17981062Sigor@sysoev.ru 17991062Sigor@sysoev.ru nv->name_length = name_length; 18001062Sigor@sysoev.ru nv->name = name; 18011062Sigor@sysoev.ru 18021062Sigor@sysoev.ru hash = NXT_HTTP_FIELD_HASH_INIT; 18031062Sigor@sysoev.ru 18041062Sigor@sysoev.ru for (p = name; p < name + name_length; p++) { 18051062Sigor@sysoev.ru c = *p; 18061062Sigor@sysoev.ru hash = nxt_http_field_hash_char(hash, c); 18071062Sigor@sysoev.ru } 18081062Sigor@sysoev.ru 18091062Sigor@sysoev.ru nv->hash = nxt_http_field_hash_end(hash) & 0xFFFF; 18101062Sigor@sysoev.ru 18111062Sigor@sysoev.ru while (start < end && end[-1] == ' ') { end--; } 18121062Sigor@sysoev.ru 18131062Sigor@sysoev.ru nv->value_length = end - start; 18141062Sigor@sysoev.ru nv->value = start; 18151062Sigor@sysoev.ru 18161062Sigor@sysoev.ru return nv; 18171062Sigor@sysoev.ru } 18181062Sigor@sysoev.ru 18191062Sigor@sysoev.ru 18201062Sigor@sysoev.ru static nxt_int_t 18211062Sigor@sysoev.ru nxt_http_route_test_cookie(nxt_http_request_t *r, 18221062Sigor@sysoev.ru nxt_http_route_rule_t *rule, nxt_array_t *array) 18231062Sigor@sysoev.ru { 18241062Sigor@sysoev.ru nxt_bool_t ret; 18251062Sigor@sysoev.ru nxt_http_name_value_t *nv, *end; 18261062Sigor@sysoev.ru 18271062Sigor@sysoev.ru ret = 0; 18281062Sigor@sysoev.ru 18291062Sigor@sysoev.ru nv = array->elts; 18301062Sigor@sysoev.ru end = nv + array->nelts; 18311062Sigor@sysoev.ru 18321062Sigor@sysoev.ru while (nv < end) { 18331062Sigor@sysoev.ru 18341062Sigor@sysoev.ru if (rule->u.name.hash == nv->hash 18351062Sigor@sysoev.ru && rule->u.name.length == nv->name_length 18361079Sigor@sysoev.ru && nxt_memcmp(rule->u.name.start, nv->name, nv->name_length) == 0) 18371062Sigor@sysoev.ru { 18381062Sigor@sysoev.ru ret = nxt_http_route_test_rule(r, rule, nv->value, 18391062Sigor@sysoev.ru nv->value_length); 18401062Sigor@sysoev.ru if (ret == 0) { 18411062Sigor@sysoev.ru break; 18421062Sigor@sysoev.ru } 18431062Sigor@sysoev.ru } 18441062Sigor@sysoev.ru 18451062Sigor@sysoev.ru nv++; 18461062Sigor@sysoev.ru } 18471062Sigor@sysoev.ru 18481062Sigor@sysoev.ru return ret; 18491062Sigor@sysoev.ru } 18501062Sigor@sysoev.ru 18511062Sigor@sysoev.ru 18521062Sigor@sysoev.ru static nxt_int_t 18531059Sigor@sysoev.ru nxt_http_route_test_rule(nxt_http_request_t *r, nxt_http_route_rule_t *rule, 18541059Sigor@sysoev.ru u_char *start, size_t length) 18551059Sigor@sysoev.ru { 18561060Sigor@sysoev.ru nxt_int_t ret; 18571059Sigor@sysoev.ru nxt_http_route_pattern_t *pattern, *end; 18581059Sigor@sysoev.ru 18591057Sigor@sysoev.ru ret = 1; 1860964Sigor@sysoev.ru pattern = &rule->pattern[0]; 18611033Svbart@nginx.com end = pattern + rule->items; 1862964Sigor@sysoev.ru 18631057Sigor@sysoev.ru while (pattern < end) { 1864964Sigor@sysoev.ru ret = nxt_http_route_pattern(r, pattern, start, length); 1865964Sigor@sysoev.ru 18661060Sigor@sysoev.ru /* nxt_http_route_pattern() returns either 1 or 0. */ 1867964Sigor@sysoev.ru ret ^= pattern->negative; 1868964Sigor@sysoev.ru 1869964Sigor@sysoev.ru if (pattern->any == ret) { 1870964Sigor@sysoev.ru return ret; 1871964Sigor@sysoev.ru } 1872964Sigor@sysoev.ru 1873964Sigor@sysoev.ru pattern++; 18741057Sigor@sysoev.ru } 1875964Sigor@sysoev.ru 1876964Sigor@sysoev.ru return ret; 1877964Sigor@sysoev.ru } 1878964Sigor@sysoev.ru 1879964Sigor@sysoev.ru 18801060Sigor@sysoev.ru static nxt_int_t 1881964Sigor@sysoev.ru nxt_http_route_pattern(nxt_http_request_t *r, nxt_http_route_pattern_t *pattern, 1882964Sigor@sysoev.ru u_char *start, size_t length) 1883964Sigor@sysoev.ru { 18841060Sigor@sysoev.ru u_char *p, *end, *test; 18851060Sigor@sysoev.ru size_t test_length; 18861060Sigor@sysoev.ru nxt_int_t ret; 1887964Sigor@sysoev.ru 1888964Sigor@sysoev.ru if (length < pattern->min_length) { 1889964Sigor@sysoev.ru return 0; 1890964Sigor@sysoev.ru } 1891964Sigor@sysoev.ru 18921032Sigor@sysoev.ru test = pattern->start1; 18931032Sigor@sysoev.ru test_length = pattern->length1; 1894964Sigor@sysoev.ru 1895964Sigor@sysoev.ru switch (pattern->type) { 1896964Sigor@sysoev.ru 1897964Sigor@sysoev.ru case NXT_HTTP_ROUTE_PATTERN_EXACT: 18981032Sigor@sysoev.ru if (length != test_length) { 1899964Sigor@sysoev.ru return 0; 1900964Sigor@sysoev.ru } 1901964Sigor@sysoev.ru 1902964Sigor@sysoev.ru break; 1903964Sigor@sysoev.ru 1904964Sigor@sysoev.ru case NXT_HTTP_ROUTE_PATTERN_BEGIN: 1905964Sigor@sysoev.ru break; 1906964Sigor@sysoev.ru 19071032Sigor@sysoev.ru case NXT_HTTP_ROUTE_PATTERN_MIDDLE: 19081032Sigor@sysoev.ru ret = nxt_http_route_memcmp(start, test, test_length, 19091032Sigor@sysoev.ru pattern->case_sensitive); 19101032Sigor@sysoev.ru if (!ret) { 19111032Sigor@sysoev.ru return ret; 19121032Sigor@sysoev.ru } 19131032Sigor@sysoev.ru 19141032Sigor@sysoev.ru test = pattern->start2; 19151032Sigor@sysoev.ru test_length = pattern->length2; 19161032Sigor@sysoev.ru 19171032Sigor@sysoev.ru /* Fall through. */ 19181032Sigor@sysoev.ru 1919964Sigor@sysoev.ru case NXT_HTTP_ROUTE_PATTERN_END: 19201032Sigor@sysoev.ru start += length - test_length; 1921964Sigor@sysoev.ru break; 1922964Sigor@sysoev.ru 1923964Sigor@sysoev.ru case NXT_HTTP_ROUTE_PATTERN_SUBSTRING: 19241032Sigor@sysoev.ru end = start + length; 19251032Sigor@sysoev.ru 1926964Sigor@sysoev.ru if (pattern->case_sensitive) { 19271032Sigor@sysoev.ru p = nxt_memstrn(start, end, (char *) test, test_length); 19281032Sigor@sysoev.ru 19291032Sigor@sysoev.ru } else { 19301032Sigor@sysoev.ru p = nxt_memcasestrn(start, end, (char *) test, test_length); 1931964Sigor@sysoev.ru } 1932964Sigor@sysoev.ru 19331032Sigor@sysoev.ru return (p != NULL); 1934964Sigor@sysoev.ru } 1935964Sigor@sysoev.ru 19361032Sigor@sysoev.ru return nxt_http_route_memcmp(start, test, test_length, 19371032Sigor@sysoev.ru pattern->case_sensitive); 19381032Sigor@sysoev.ru } 19391032Sigor@sysoev.ru 19401032Sigor@sysoev.ru 19411060Sigor@sysoev.ru static nxt_int_t 19421032Sigor@sysoev.ru nxt_http_route_memcmp(u_char *start, u_char *test, size_t test_length, 19431032Sigor@sysoev.ru nxt_bool_t case_sensitive) 19441032Sigor@sysoev.ru { 19451032Sigor@sysoev.ru nxt_int_t n; 19461032Sigor@sysoev.ru 19471032Sigor@sysoev.ru if (case_sensitive) { 19481032Sigor@sysoev.ru n = nxt_memcmp(start, test, test_length); 19491032Sigor@sysoev.ru 19501032Sigor@sysoev.ru } else { 19511032Sigor@sysoev.ru n = nxt_memcasecmp(start, test, test_length); 1952964Sigor@sysoev.ru } 1953964Sigor@sysoev.ru 19541032Sigor@sysoev.ru return (n == 0); 1955964Sigor@sysoev.ru } 1956