1 2 /* 3 * Copyright (C) Igor Sysoev 4 * Copyright (C) NGINX, Inc. 5 */ 6 7 #include <nxt_router.h> 8 #include <nxt_http.h> 9 #include <nxt_sockaddr.h> 10 #include <nxt_http_route_addr.h> 11 #include <nxt_regex.h> 12 13 14 typedef enum { 15 NXT_HTTP_ROUTE_TABLE = 0, 16 NXT_HTTP_ROUTE_STRING, 17 NXT_HTTP_ROUTE_STRING_PTR, 18 NXT_HTTP_ROUTE_HEADER, 19 NXT_HTTP_ROUTE_ARGUMENT, 20 NXT_HTTP_ROUTE_COOKIE, 21 NXT_HTTP_ROUTE_SCHEME, 22 NXT_HTTP_ROUTE_SOURCE, 23 NXT_HTTP_ROUTE_DESTINATION, 24 } nxt_http_route_object_t; 25 26 27 typedef enum { 28 NXT_HTTP_ROUTE_PATTERN_EXACT = 0, 29 NXT_HTTP_ROUTE_PATTERN_BEGIN, 30 NXT_HTTP_ROUTE_PATTERN_END, 31 NXT_HTTP_ROUTE_PATTERN_SUBSTRING, 32 } nxt_http_route_pattern_type_t; 33 34 35 typedef enum { 36 NXT_HTTP_ROUTE_PATTERN_NOCASE = 0, 37 NXT_HTTP_ROUTE_PATTERN_LOWCASE, 38 NXT_HTTP_ROUTE_PATTERN_UPCASE, 39 } nxt_http_route_pattern_case_t; 40 41 42 typedef enum { 43 NXT_HTTP_ROUTE_ENCODING_NONE = 0, 44 NXT_HTTP_ROUTE_ENCODING_URI, 45 NXT_HTTP_ROUTE_ENCODING_URI_PLUS 46 } nxt_http_route_encoding_t; 47 48 49 typedef struct { 50 nxt_conf_value_t *host; 51 nxt_conf_value_t *uri; 52 nxt_conf_value_t *method; 53 nxt_conf_value_t *headers; 54 nxt_conf_value_t *arguments; 55 nxt_conf_value_t *cookies; 56 nxt_conf_value_t *scheme; 57 nxt_conf_value_t *source; 58 nxt_conf_value_t *destination; 59 } nxt_http_route_match_conf_t; 60 61 62 typedef struct { 63 u_char *start; 64 uint32_t length; 65 nxt_http_route_pattern_type_t type:8; 66 } nxt_http_route_pattern_slice_t; 67 68 69 typedef struct { 70 union { 71 nxt_array_t *pattern_slices; 72 #if (NXT_HAVE_REGEX) 73 nxt_regex_t *regex; 74 #endif 75 } u; 76 uint32_t min_length; 77 78 uint8_t case_sensitive; /* 1 bit */ 79 uint8_t negative; /* 1 bit */ 80 uint8_t any; /* 1 bit */ 81 #if (NXT_HAVE_REGEX) 82 uint8_t regex; /* 1 bit */ 83 #endif 84 } nxt_http_route_pattern_t; 85 86 87 typedef struct { 88 uint16_t hash; 89 uint16_t name_length; 90 uint32_t value_length; 91 u_char *name; 92 u_char *value; 93 } nxt_http_name_value_t; 94 95 96 typedef struct { 97 uint16_t hash; 98 uint16_t name_length; 99 uint32_t value_length; 100 u_char *name; 101 u_char *value; 102 } nxt_http_cookie_t; 103 104 105 struct nxt_http_route_rule_s { 106 /* The object must be the first field. */ 107 nxt_http_route_object_t object:8; 108 uint32_t items; 109 110 union { 111 uintptr_t offset; 112 113 struct { 114 u_char *start; 115 uint16_t hash; 116 uint16_t length; 117 } name; 118 } u; 119 120 nxt_http_route_pattern_t pattern[0]; 121 }; 122 123 124 typedef struct { 125 uint32_t items; 126 nxt_http_route_rule_t *rule[0]; 127 } nxt_http_route_ruleset_t; 128 129 130 typedef struct { 131 /* The object must be the first field. */ 132 nxt_http_route_object_t object:8; 133 uint32_t items; 134 nxt_http_route_ruleset_t *ruleset[0]; 135 } nxt_http_route_table_t; 136 137 138 typedef struct { 139 /* The object must be the first field. */ 140 nxt_http_route_object_t object:8; 141 uint32_t items; 142 nxt_http_route_addr_pattern_t addr_pattern[0]; 143 } nxt_http_route_addr_rule_t; 144 145 146 typedef union { 147 nxt_http_route_rule_t *rule; 148 nxt_http_route_table_t *table; 149 nxt_http_route_addr_rule_t *addr_rule; 150 } nxt_http_route_test_t; 151 152 153 typedef struct { 154 uint32_t items; 155 nxt_http_action_t action; 156 nxt_http_route_test_t test[0]; 157 } nxt_http_route_match_t; 158 159 160 struct nxt_http_route_s { 161 nxt_str_t name; 162 uint32_t items; 163 nxt_http_route_match_t *match[0]; 164 }; 165 166 167 struct nxt_http_routes_s { 168 uint32_t items; 169 nxt_http_route_t *route[0]; 170 }; 171 172 173 #define NXT_COOKIE_HASH \ 174 (nxt_http_field_hash_end( \ 175 nxt_http_field_hash_char( \ 176 nxt_http_field_hash_char( \ 177 nxt_http_field_hash_char( \ 178 nxt_http_field_hash_char( \ 179 nxt_http_field_hash_char( \ 180 nxt_http_field_hash_char(NXT_HTTP_FIELD_HASH_INIT, \ 181 'c'), 'o'), 'o'), 'k'), 'i'), 'e')) & 0xFFFF) 182 183 184 static nxt_http_route_t *nxt_http_route_create(nxt_task_t *task, 185 nxt_router_temp_conf_t *tmcf, nxt_conf_value_t *cv); 186 static nxt_http_route_match_t *nxt_http_route_match_create(nxt_task_t *task, 187 nxt_router_temp_conf_t *tmcf, nxt_conf_value_t *cv); 188 static nxt_http_route_table_t *nxt_http_route_table_create(nxt_task_t *task, 189 nxt_mp_t *mp, nxt_conf_value_t *table_cv, nxt_http_route_object_t object, 190 nxt_bool_t case_sensitive, nxt_http_route_encoding_t encoding); 191 static nxt_http_route_ruleset_t *nxt_http_route_ruleset_create(nxt_task_t *task, 192 nxt_mp_t *mp, nxt_conf_value_t *ruleset_cv, nxt_http_route_object_t object, 193 nxt_bool_t case_sensitive, nxt_http_route_encoding_t encoding); 194 static nxt_http_route_rule_t *nxt_http_route_rule_name_create(nxt_task_t *task, 195 nxt_mp_t *mp, nxt_conf_value_t *rule_cv, nxt_str_t *name, 196 nxt_bool_t case_sensitive, nxt_http_route_encoding_t encoding); 197 static nxt_http_route_addr_rule_t *nxt_http_route_addr_rule_create( 198 nxt_task_t *task, nxt_mp_t *mp, nxt_conf_value_t *cv); 199 static nxt_http_route_rule_t *nxt_http_route_rule_create(nxt_task_t *task, 200 nxt_mp_t *mp, nxt_conf_value_t *cv, nxt_bool_t case_sensitive, 201 nxt_http_route_pattern_case_t pattern_case, 202 nxt_http_route_encoding_t encoding); 203 static int nxt_http_pattern_compare(const void *one, const void *two); 204 static int nxt_http_addr_pattern_compare(const void *one, const void *two); 205 static nxt_int_t nxt_http_route_pattern_create(nxt_task_t *task, nxt_mp_t *mp, 206 nxt_conf_value_t *cv, nxt_http_route_pattern_t *pattern, 207 nxt_http_route_pattern_case_t pattern_case, 208 nxt_http_route_encoding_t encoding); 209 static nxt_int_t nxt_http_route_decode_str(nxt_str_t *str, 210 nxt_http_route_encoding_t encoding); 211 static nxt_int_t nxt_http_route_pattern_slice(nxt_array_t *slices, 212 nxt_str_t *test, 213 nxt_http_route_pattern_type_t type, 214 nxt_http_route_encoding_t encoding, 215 nxt_http_route_pattern_case_t pattern_case); 216 217 static nxt_int_t nxt_http_route_resolve(nxt_task_t *task, 218 nxt_router_temp_conf_t *tmcf, nxt_http_route_t *route); 219 static nxt_int_t nxt_http_action_resolve(nxt_task_t *task, 220 nxt_router_temp_conf_t *tmcf, nxt_http_action_t *action); 221 static nxt_http_action_t *nxt_http_action_pass_var(nxt_task_t *task, 222 nxt_http_request_t *r, nxt_http_action_t *action); 223 static void nxt_http_action_pass_var_ready(nxt_task_t *task, void *obj, 224 void *data); 225 static void nxt_http_action_pass_var_error(nxt_task_t *task, void *obj, 226 void *data); 227 static nxt_int_t nxt_http_pass_find(nxt_task_t *task, nxt_mp_t *mp, 228 nxt_router_conf_t *rtcf, nxt_http_action_t *action); 229 static nxt_int_t nxt_http_route_find(nxt_http_routes_t *routes, nxt_str_t *name, 230 nxt_http_action_t *action); 231 232 static nxt_http_action_t *nxt_http_route_handler(nxt_task_t *task, 233 nxt_http_request_t *r, nxt_http_action_t *start); 234 static nxt_http_action_t *nxt_http_route_match(nxt_task_t *task, 235 nxt_http_request_t *r, nxt_http_route_match_t *match); 236 static nxt_int_t nxt_http_route_table(nxt_http_request_t *r, 237 nxt_http_route_table_t *table); 238 static nxt_int_t nxt_http_route_ruleset(nxt_http_request_t *r, 239 nxt_http_route_ruleset_t *ruleset); 240 static nxt_int_t nxt_http_route_addr_rule(nxt_http_request_t *r, 241 nxt_http_route_addr_rule_t *addr_rule, nxt_sockaddr_t *sockaddr); 242 static nxt_int_t nxt_http_route_rule(nxt_http_request_t *r, 243 nxt_http_route_rule_t *rule); 244 static nxt_int_t nxt_http_route_header(nxt_http_request_t *r, 245 nxt_http_route_rule_t *rule); 246 static nxt_int_t nxt_http_route_arguments(nxt_http_request_t *r, 247 nxt_http_route_rule_t *rule); 248 static nxt_array_t *nxt_http_route_arguments_parse(nxt_http_request_t *r); 249 static nxt_http_name_value_t *nxt_http_route_argument(nxt_array_t *array, 250 u_char *name, size_t name_length, uint32_t hash, u_char *start, 251 u_char *end); 252 static nxt_int_t nxt_http_route_test_argument(nxt_http_request_t *r, 253 nxt_http_route_rule_t *rule, nxt_array_t *array); 254 static nxt_int_t nxt_http_route_scheme(nxt_http_request_t *r, 255 nxt_http_route_rule_t *rule); 256 static nxt_int_t nxt_http_route_cookies(nxt_http_request_t *r, 257 nxt_http_route_rule_t *rule); 258 static nxt_array_t *nxt_http_route_cookies_parse(nxt_http_request_t *r); 259 static nxt_int_t nxt_http_route_cookie_parse(nxt_array_t *cookies, 260 u_char *start, u_char *end); 261 static nxt_http_name_value_t *nxt_http_route_cookie(nxt_array_t *array, 262 u_char *name, size_t name_length, u_char *start, u_char *end); 263 static nxt_int_t nxt_http_route_test_cookie(nxt_http_request_t *r, 264 nxt_http_route_rule_t *rule, nxt_array_t *array); 265 static nxt_int_t nxt_http_route_pattern(nxt_http_request_t *r, 266 nxt_http_route_pattern_t *pattern, u_char *start, size_t length); 267 static nxt_int_t nxt_http_route_memcmp(u_char *start, u_char *test, 268 size_t length, nxt_bool_t case_sensitive); 269 270 271 nxt_http_routes_t * 272 nxt_http_routes_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 273 nxt_conf_value_t *routes_conf) 274 { 275 size_t size; 276 uint32_t i, n, next; 277 nxt_mp_t *mp; 278 nxt_str_t name, *string; 279 nxt_bool_t object; 280 nxt_conf_value_t *route_conf; 281 nxt_http_route_t *route; 282 nxt_http_routes_t *routes; 283 284 object = (nxt_conf_type(routes_conf) == NXT_CONF_OBJECT); 285 n = object ? nxt_conf_object_members_count(routes_conf) : 1; 286 size = sizeof(nxt_http_routes_t) + n * sizeof(nxt_http_route_t *); 287 288 mp = tmcf->router_conf->mem_pool; 289 290 routes = nxt_mp_alloc(mp, size); 291 if (nxt_slow_path(routes == NULL)) { 292 return NULL; 293 } 294 295 routes->items = n; 296 297 if (object) { 298 next = 0; 299 300 for (i = 0; i < n; i++) { 301 route_conf = nxt_conf_next_object_member(routes_conf, &name, &next); 302 303 route = nxt_http_route_create(task, tmcf, route_conf); 304 if (nxt_slow_path(route == NULL)) { 305 return NULL; 306 } 307 308 routes->route[i] = route; 309 310 string = nxt_str_dup(mp, &route->name, &name); 311 if (nxt_slow_path(string == NULL)) { 312 return NULL; 313 } 314 } 315 316 } else { 317 route = nxt_http_route_create(task, tmcf, routes_conf); 318 if (nxt_slow_path(route == NULL)) { 319 return NULL; 320 } 321 322 routes->route[0] = route; 323 324 route->name.length = 0; 325 route->name.start = NULL; 326 } 327 328 return routes; 329 } 330 331 332 static nxt_conf_map_t nxt_http_route_match_conf[] = { 333 { 334 nxt_string("scheme"), 335 NXT_CONF_MAP_PTR, 336 offsetof(nxt_http_route_match_conf_t, scheme) 337 }, 338 { 339 nxt_string("host"), 340 NXT_CONF_MAP_PTR, 341 offsetof(nxt_http_route_match_conf_t, host), 342 }, 343 344 { 345 nxt_string("uri"), 346 NXT_CONF_MAP_PTR, 347 offsetof(nxt_http_route_match_conf_t, uri), 348 }, 349 350 { 351 nxt_string("method"), 352 NXT_CONF_MAP_PTR, 353 offsetof(nxt_http_route_match_conf_t, method), 354 }, 355 356 { 357 nxt_string("headers"), 358 NXT_CONF_MAP_PTR, 359 offsetof(nxt_http_route_match_conf_t, headers), 360 }, 361 362 { 363 nxt_string("arguments"), 364 NXT_CONF_MAP_PTR, 365 offsetof(nxt_http_route_match_conf_t, arguments), 366 }, 367 368 { 369 nxt_string("cookies"), 370 NXT_CONF_MAP_PTR, 371 offsetof(nxt_http_route_match_conf_t, cookies), 372 }, 373 374 { 375 nxt_string("source"), 376 NXT_CONF_MAP_PTR, 377 offsetof(nxt_http_route_match_conf_t, source), 378 }, 379 380 { 381 nxt_string("destination"), 382 NXT_CONF_MAP_PTR, 383 offsetof(nxt_http_route_match_conf_t, destination), 384 }, 385 }; 386 387 388 static nxt_http_route_t * 389 nxt_http_route_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 390 nxt_conf_value_t *cv) 391 { 392 size_t size; 393 uint32_t i, n; 394 nxt_conf_value_t *value; 395 nxt_http_route_t *route; 396 nxt_http_route_match_t *match, **m; 397 398 n = nxt_conf_array_elements_count(cv); 399 size = sizeof(nxt_http_route_t) + n * sizeof(nxt_http_route_match_t *); 400 401 route = nxt_mp_alloc(tmcf->router_conf->mem_pool, size); 402 if (nxt_slow_path(route == NULL)) { 403 return NULL; 404 } 405 406 route->items = n; 407 m = &route->match[0]; 408 409 for (i = 0; i < n; i++) { 410 value = nxt_conf_get_array_element(cv, i); 411 412 match = nxt_http_route_match_create(task, tmcf, value); 413 if (match == NULL) { 414 return NULL; 415 } 416 417 *m++ = match; 418 } 419 420 return route; 421 } 422 423 424 static nxt_http_route_match_t * 425 nxt_http_route_match_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 426 nxt_conf_value_t *cv) 427 { 428 size_t size; 429 uint32_t n; 430 nxt_mp_t *mp; 431 nxt_int_t ret; 432 nxt_conf_value_t *match_conf, *action_conf; 433 nxt_http_route_test_t *test; 434 nxt_http_route_rule_t *rule; 435 nxt_http_route_table_t *table; 436 nxt_http_route_match_t *match; 437 nxt_http_route_addr_rule_t *addr_rule; 438 nxt_http_route_match_conf_t mtcf; 439 440 static nxt_str_t match_path = nxt_string("/match"); 441 static nxt_str_t action_path = nxt_string("/action"); 442 443 match_conf = nxt_conf_get_path(cv, &match_path); 444 445 n = (match_conf != NULL) ? nxt_conf_object_members_count(match_conf) : 0; 446 size = sizeof(nxt_http_route_match_t) + n * sizeof(nxt_http_route_test_t *); 447 448 mp = tmcf->router_conf->mem_pool; 449 450 match = nxt_mp_alloc(mp, size); 451 if (nxt_slow_path(match == NULL)) { 452 return NULL; 453 } 454 455 match->items = n; 456 457 action_conf = nxt_conf_get_path(cv, &action_path); 458 if (nxt_slow_path(action_conf == NULL)) { 459 return NULL; 460 } 461 462 ret = nxt_http_action_init(task, tmcf, action_conf, &match->action); 463 if (nxt_slow_path(ret != NXT_OK)) { 464 return NULL; 465 } 466 467 if (n == 0) { 468 return match; 469 } 470 471 nxt_memzero(&mtcf, sizeof(mtcf)); 472 473 ret = nxt_conf_map_object(tmcf->mem_pool, 474 match_conf, nxt_http_route_match_conf, 475 nxt_nitems(nxt_http_route_match_conf), &mtcf); 476 if (ret != NXT_OK) { 477 return NULL; 478 } 479 480 test = &match->test[0]; 481 482 if (mtcf.scheme != NULL) { 483 rule = nxt_http_route_rule_create(task, mp, mtcf.scheme, 1, 484 NXT_HTTP_ROUTE_PATTERN_NOCASE, 485 NXT_HTTP_ROUTE_ENCODING_NONE); 486 if (rule == NULL) { 487 return NULL; 488 } 489 490 rule->object = NXT_HTTP_ROUTE_SCHEME; 491 test->rule = rule; 492 test++; 493 } 494 495 if (mtcf.host != NULL) { 496 rule = nxt_http_route_rule_create(task, mp, mtcf.host, 1, 497 NXT_HTTP_ROUTE_PATTERN_LOWCASE, 498 NXT_HTTP_ROUTE_ENCODING_NONE); 499 if (rule == NULL) { 500 return NULL; 501 } 502 503 rule->u.offset = offsetof(nxt_http_request_t, host); 504 rule->object = NXT_HTTP_ROUTE_STRING; 505 test->rule = rule; 506 test++; 507 } 508 509 if (mtcf.uri != NULL) { 510 rule = nxt_http_route_rule_create(task, mp, mtcf.uri, 1, 511 NXT_HTTP_ROUTE_PATTERN_NOCASE, 512 NXT_HTTP_ROUTE_ENCODING_URI); 513 if (rule == NULL) { 514 return NULL; 515 } 516 517 rule->u.offset = offsetof(nxt_http_request_t, path); 518 rule->object = NXT_HTTP_ROUTE_STRING_PTR; 519 test->rule = rule; 520 test++; 521 } 522 523 if (mtcf.method != NULL) { 524 rule = nxt_http_route_rule_create(task, mp, mtcf.method, 1, 525 NXT_HTTP_ROUTE_PATTERN_UPCASE, 526 NXT_HTTP_ROUTE_ENCODING_NONE); 527 if (rule == NULL) { 528 return NULL; 529 } 530 531 rule->u.offset = offsetof(nxt_http_request_t, method); 532 rule->object = NXT_HTTP_ROUTE_STRING_PTR; 533 test->rule = rule; 534 test++; 535 } 536 537 if (mtcf.headers != NULL) { 538 table = nxt_http_route_table_create(task, mp, mtcf.headers, 539 NXT_HTTP_ROUTE_HEADER, 0, 540 NXT_HTTP_ROUTE_ENCODING_NONE); 541 if (table == NULL) { 542 return NULL; 543 } 544 545 test->table = table; 546 test++; 547 } 548 549 if (mtcf.arguments != NULL) { 550 table = nxt_http_route_table_create(task, mp, mtcf.arguments, 551 NXT_HTTP_ROUTE_ARGUMENT, 1, 552 NXT_HTTP_ROUTE_ENCODING_URI_PLUS); 553 if (table == NULL) { 554 return NULL; 555 } 556 557 test->table = table; 558 test++; 559 } 560 561 if (mtcf.cookies != NULL) { 562 table = nxt_http_route_table_create(task, mp, mtcf.cookies, 563 NXT_HTTP_ROUTE_COOKIE, 1, 564 NXT_HTTP_ROUTE_ENCODING_NONE); 565 if (table == NULL) { 566 return NULL; 567 } 568 569 test->table = table; 570 test++; 571 } 572 573 if (mtcf.source != NULL) { 574 addr_rule = nxt_http_route_addr_rule_create(task, mp, mtcf.source); 575 if (addr_rule == NULL) { 576 return NULL; 577 } 578 579 addr_rule->object = NXT_HTTP_ROUTE_SOURCE; 580 test->addr_rule = addr_rule; 581 test++; 582 } 583 584 if (mtcf.destination != NULL) { 585 addr_rule = nxt_http_route_addr_rule_create(task, mp, mtcf.destination); 586 if (addr_rule == NULL) { 587 return NULL; 588 } 589 590 addr_rule->object = NXT_HTTP_ROUTE_DESTINATION; 591 test->addr_rule = addr_rule; 592 test++; 593 } 594 595 return match; 596 } 597 598 599 static nxt_conf_map_t nxt_http_route_action_conf[] = { 600 { 601 nxt_string("pass"), 602 NXT_CONF_MAP_PTR, 603 offsetof(nxt_http_action_conf_t, pass) 604 }, 605 { 606 nxt_string("return"), 607 NXT_CONF_MAP_PTR, 608 offsetof(nxt_http_action_conf_t, ret) 609 }, 610 { 611 nxt_string("location"), 612 NXT_CONF_MAP_STR, 613 offsetof(nxt_http_action_conf_t, location) 614 }, 615 { 616 nxt_string("proxy"), 617 NXT_CONF_MAP_PTR, 618 offsetof(nxt_http_action_conf_t, proxy) 619 }, 620 { 621 nxt_string("share"), 622 NXT_CONF_MAP_PTR, 623 offsetof(nxt_http_action_conf_t, share) 624 }, 625 { 626 nxt_string("chroot"), 627 NXT_CONF_MAP_STR, 628 offsetof(nxt_http_action_conf_t, chroot) 629 }, 630 { 631 nxt_string("follow_symlinks"), 632 NXT_CONF_MAP_PTR, 633 offsetof(nxt_http_action_conf_t, follow_symlinks) 634 }, 635 { 636 nxt_string("traverse_mounts"), 637 NXT_CONF_MAP_PTR, 638 offsetof(nxt_http_action_conf_t, traverse_mounts) 639 }, 640 { 641 nxt_string("types"), 642 NXT_CONF_MAP_PTR, 643 offsetof(nxt_http_action_conf_t, types) 644 }, 645 { 646 nxt_string("fallback"), 647 NXT_CONF_MAP_PTR, 648 offsetof(nxt_http_action_conf_t, fallback) 649 }, 650 }; 651 652 653 nxt_int_t 654 nxt_http_action_init(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 655 nxt_conf_value_t *cv, nxt_http_action_t *action) 656 { 657 nxt_mp_t *mp; 658 nxt_int_t ret; 659 nxt_str_t name, *string; 660 nxt_conf_value_t *conf; 661 nxt_http_action_conf_t acf; 662 663 nxt_memzero(&acf, sizeof(acf)); 664 665 ret = nxt_conf_map_object(tmcf->mem_pool, cv, nxt_http_route_action_conf, 666 nxt_nitems(nxt_http_route_action_conf), &acf); 667 if (ret != NXT_OK) { 668 return ret; 669 } 670 671 nxt_memzero(action, sizeof(nxt_http_action_t)); 672 673 mp = tmcf->router_conf->mem_pool; 674 675 if (acf.ret != NULL) { 676 return nxt_http_return_init(mp, action, &acf); 677 } 678 679 if (acf.share != NULL) { 680 return nxt_http_static_init(task, tmcf, action, &acf); 681 } 682 683 if (acf.proxy != NULL) { 684 conf = acf.proxy; 685 686 } else { 687 conf = acf.pass; 688 } 689 690 nxt_conf_get_string(conf, &name); 691 692 string = nxt_str_dup(mp, &action->name, &name); 693 if (nxt_slow_path(string == NULL)) { 694 return NXT_ERROR; 695 } 696 697 if (acf.proxy != NULL) { 698 return nxt_http_proxy_create(mp, action); 699 } 700 701 return NXT_OK; 702 } 703 704 705 static nxt_http_route_table_t * 706 nxt_http_route_table_create(nxt_task_t *task, nxt_mp_t *mp, 707 nxt_conf_value_t *table_cv, nxt_http_route_object_t object, 708 nxt_bool_t case_sensitive, nxt_http_route_encoding_t encoding) 709 { 710 size_t size; 711 uint32_t i, n; 712 nxt_bool_t array; 713 nxt_conf_value_t *ruleset_cv; 714 nxt_http_route_table_t *table; 715 nxt_http_route_ruleset_t *ruleset; 716 717 array = (nxt_conf_type(table_cv) == NXT_CONF_ARRAY); 718 n = array ? nxt_conf_array_elements_count(table_cv) : 1; 719 size = sizeof(nxt_http_route_table_t) 720 + n * sizeof(nxt_http_route_ruleset_t *); 721 722 table = nxt_mp_alloc(mp, size); 723 if (nxt_slow_path(table == NULL)) { 724 return NULL; 725 } 726 727 table->items = n; 728 table->object = NXT_HTTP_ROUTE_TABLE; 729 730 if (!array) { 731 ruleset = nxt_http_route_ruleset_create(task, mp, table_cv, object, 732 case_sensitive, encoding); 733 if (nxt_slow_path(ruleset == NULL)) { 734 return NULL; 735 } 736 737 table->ruleset[0] = ruleset; 738 739 return table; 740 } 741 742 for (i = 0; i < n; i++) { 743 ruleset_cv = nxt_conf_get_array_element(table_cv, i); 744 745 ruleset = nxt_http_route_ruleset_create(task, mp, ruleset_cv, object, 746 case_sensitive, encoding); 747 if (nxt_slow_path(ruleset == NULL)) { 748 return NULL; 749 } 750 751 table->ruleset[i] = ruleset; 752 } 753 754 return table; 755 } 756 757 758 static nxt_http_route_ruleset_t * 759 nxt_http_route_ruleset_create(nxt_task_t *task, nxt_mp_t *mp, 760 nxt_conf_value_t *ruleset_cv, nxt_http_route_object_t object, 761 nxt_bool_t case_sensitive, nxt_http_route_encoding_t encoding) 762 { 763 size_t size; 764 uint32_t i, n, next; 765 nxt_str_t name; 766 nxt_conf_value_t *rule_cv; 767 nxt_http_route_rule_t *rule; 768 nxt_http_route_ruleset_t *ruleset; 769 770 n = nxt_conf_object_members_count(ruleset_cv); 771 size = sizeof(nxt_http_route_ruleset_t) 772 + n * sizeof(nxt_http_route_rule_t *); 773 774 ruleset = nxt_mp_alloc(mp, size); 775 if (nxt_slow_path(ruleset == NULL)) { 776 return NULL; 777 } 778 779 ruleset->items = n; 780 781 next = 0; 782 783 /* 784 * A workaround for GCC 10 with -flto -O2 flags that warns about "name" 785 * may be uninitialized in nxt_http_route_rule_name_create(). 786 */ 787 nxt_str_null(&name); 788 789 for (i = 0; i < n; i++) { 790 rule_cv = nxt_conf_next_object_member(ruleset_cv, &name, &next); 791 792 rule = nxt_http_route_rule_name_create(task, mp, rule_cv, &name, 793 case_sensitive, encoding); 794 if (nxt_slow_path(rule == NULL)) { 795 return NULL; 796 } 797 798 rule->object = object; 799 ruleset->rule[i] = rule; 800 } 801 802 return ruleset; 803 } 804 805 806 static nxt_http_route_rule_t * 807 nxt_http_route_rule_name_create(nxt_task_t *task, nxt_mp_t *mp, 808 nxt_conf_value_t *rule_cv, nxt_str_t *name, nxt_bool_t case_sensitive, 809 nxt_http_route_encoding_t encoding) 810 { 811 u_char c, *p, *src, *start, *end, plus; 812 uint8_t d0, d1; 813 uint32_t hash; 814 nxt_uint_t i; 815 nxt_http_route_rule_t *rule; 816 817 rule = nxt_http_route_rule_create(task, mp, rule_cv, case_sensitive, 818 NXT_HTTP_ROUTE_PATTERN_NOCASE, 819 encoding); 820 if (nxt_slow_path(rule == NULL)) { 821 return NULL; 822 } 823 824 rule->u.name.length = name->length; 825 826 p = nxt_mp_nget(mp, name->length); 827 if (nxt_slow_path(p == NULL)) { 828 return NULL; 829 } 830 831 hash = NXT_HTTP_FIELD_HASH_INIT; 832 rule->u.name.start = p; 833 834 if (encoding == NXT_HTTP_ROUTE_ENCODING_NONE) { 835 for (i = 0; i < name->length; i++) { 836 c = name->start[i]; 837 *p++ = c; 838 839 c = case_sensitive ? c : nxt_lowcase(c); 840 hash = nxt_http_field_hash_char(hash, c); 841 } 842 843 goto end; 844 } 845 846 plus = (encoding == NXT_HTTP_ROUTE_ENCODING_URI_PLUS) ? ' ' : '+'; 847 848 start = name->start; 849 end = start + name->length; 850 851 for (src = start; src < end; src++) { 852 c = *src; 853 854 switch (c) { 855 case '%': 856 if (nxt_slow_path(end - src <= 2)) { 857 return NULL; 858 } 859 860 d0 = nxt_hex2int[src[1]]; 861 d1 = nxt_hex2int[src[2]]; 862 src += 2; 863 864 if (nxt_slow_path((d0 | d1) >= 16)) { 865 return NULL; 866 } 867 868 c = (d0 << 4) + d1; 869 *p++ = c; 870 break; 871 872 case '+': 873 c = plus; 874 *p++ = c; 875 break; 876 877 default: 878 *p++ = c; 879 break; 880 } 881 882 c = case_sensitive ? c : nxt_lowcase(c); 883 hash = nxt_http_field_hash_char(hash, c); 884 } 885 886 rule->u.name.length = p - rule->u.name.start; 887 888 end: 889 890 rule->u.name.hash = nxt_http_field_hash_end(hash) & 0xFFFF; 891 892 return rule; 893 } 894 895 896 static nxt_http_route_rule_t * 897 nxt_http_route_rule_create(nxt_task_t *task, nxt_mp_t *mp, 898 nxt_conf_value_t *cv, nxt_bool_t case_sensitive, 899 nxt_http_route_pattern_case_t pattern_case, 900 nxt_http_route_encoding_t encoding) 901 { 902 size_t size; 903 uint32_t i, n; 904 nxt_int_t ret; 905 nxt_bool_t string; 906 nxt_conf_value_t *value; 907 nxt_http_route_rule_t *rule; 908 nxt_http_route_pattern_t *pattern; 909 910 string = (nxt_conf_type(cv) != NXT_CONF_ARRAY); 911 n = string ? 1 : nxt_conf_array_elements_count(cv); 912 size = sizeof(nxt_http_route_rule_t) + n * sizeof(nxt_http_route_pattern_t); 913 914 rule = nxt_mp_alloc(mp, size); 915 if (nxt_slow_path(rule == NULL)) { 916 return NULL; 917 } 918 919 rule->items = n; 920 921 pattern = &rule->pattern[0]; 922 923 if (string) { 924 pattern[0].case_sensitive = case_sensitive; 925 ret = nxt_http_route_pattern_create(task, mp, cv, &pattern[0], 926 pattern_case, encoding); 927 if (nxt_slow_path(ret != NXT_OK)) { 928 return NULL; 929 } 930 931 return rule; 932 } 933 934 nxt_conf_array_qsort(cv, nxt_http_pattern_compare); 935 936 for (i = 0; i < n; i++) { 937 pattern[i].case_sensitive = case_sensitive; 938 value = nxt_conf_get_array_element(cv, i); 939 940 ret = nxt_http_route_pattern_create(task, mp, value, &pattern[i], 941 pattern_case, encoding); 942 if (nxt_slow_path(ret != NXT_OK)) { 943 return NULL; 944 } 945 } 946 947 return rule; 948 } 949 950 951 static nxt_http_route_addr_rule_t * 952 nxt_http_route_addr_rule_create(nxt_task_t *task, nxt_mp_t *mp, 953 nxt_conf_value_t *cv) 954 { 955 size_t size; 956 uint32_t i, n; 957 nxt_bool_t array; 958 nxt_conf_value_t *value; 959 nxt_http_route_addr_rule_t *addr_rule; 960 nxt_http_route_addr_pattern_t *pattern; 961 962 array = (nxt_conf_type(cv) == NXT_CONF_ARRAY); 963 n = array ? nxt_conf_array_elements_count(cv) : 1; 964 965 size = sizeof(nxt_http_route_addr_rule_t) 966 + n * sizeof(nxt_http_route_addr_pattern_t); 967 968 addr_rule = nxt_mp_alloc(mp, size); 969 if (nxt_slow_path(addr_rule == NULL)) { 970 return NULL; 971 } 972 973 addr_rule->items = n; 974 975 if (!array) { 976 pattern = &addr_rule->addr_pattern[0]; 977 978 if (nxt_http_route_addr_pattern_parse(mp, pattern, cv) != NXT_OK) { 979 return NULL; 980 } 981 982 return addr_rule; 983 } 984 985 for (i = 0; i < n; i++) { 986 pattern = &addr_rule->addr_pattern[i]; 987 value = nxt_conf_get_array_element(cv, i); 988 989 if (nxt_http_route_addr_pattern_parse(mp, pattern, value) != NXT_OK) { 990 return NULL; 991 } 992 } 993 994 if (n > 1) { 995 nxt_qsort(addr_rule->addr_pattern, addr_rule->items, 996 sizeof(nxt_http_route_addr_pattern_t), 997 nxt_http_addr_pattern_compare); 998 } 999 1000 return addr_rule; 1001 } 1002 1003 1004 nxt_http_route_rule_t * 1005 nxt_http_route_types_rule_create(nxt_task_t *task, nxt_mp_t *mp, 1006 nxt_conf_value_t *types) 1007 { 1008 return nxt_http_route_rule_create(task, mp, types, 0, 1009 NXT_HTTP_ROUTE_PATTERN_LOWCASE, 1010 NXT_HTTP_ROUTE_ENCODING_NONE); 1011 } 1012 1013 1014 static int 1015 nxt_http_pattern_compare(const void *one, const void *two) 1016 { 1017 nxt_str_t test; 1018 nxt_bool_t negative1, negative2; 1019 nxt_conf_value_t *value; 1020 1021 value = (nxt_conf_value_t *) one; 1022 nxt_conf_get_string(value, &test); 1023 negative1 = (test.length != 0 && test.start[0] == '!'); 1024 1025 value = (nxt_conf_value_t *) two; 1026 nxt_conf_get_string(value, &test); 1027 negative2 = (test.length != 0 && test.start[0] == '!'); 1028 1029 return (negative2 - negative1); 1030 } 1031 1032 1033 static int 1034 nxt_http_addr_pattern_compare(const void *one, const void *two) 1035 { 1036 const nxt_http_route_addr_pattern_t *p1, *p2; 1037 1038 p1 = one; 1039 p2 = two; 1040 1041 return (p2->base.negative - p1->base.negative); 1042 } 1043 1044 1045 static nxt_int_t 1046 nxt_http_route_pattern_create(nxt_task_t *task, nxt_mp_t *mp, 1047 nxt_conf_value_t *cv, nxt_http_route_pattern_t *pattern, 1048 nxt_http_route_pattern_case_t pattern_case, 1049 nxt_http_route_encoding_t encoding) 1050 { 1051 u_char c, *p, *end; 1052 nxt_str_t test, tmp; 1053 nxt_int_t ret; 1054 nxt_array_t *slices; 1055 #if (NXT_HAVE_REGEX) 1056 nxt_regex_t *re; 1057 nxt_regex_err_t err; 1058 #endif 1059 nxt_http_route_pattern_type_t type; 1060 nxt_http_route_pattern_slice_t *slice; 1061 1062 type = NXT_HTTP_ROUTE_PATTERN_EXACT; 1063 1064 nxt_conf_get_string(cv, &test); 1065 1066 pattern->u.pattern_slices = NULL; 1067 pattern->negative = 0; 1068 pattern->any = 1; 1069 pattern->min_length = 0; 1070 #if (NXT_HAVE_REGEX) 1071 pattern->regex = 0; 1072 #endif 1073 1074 if (test.length != 0 && test.start[0] == '!') { 1075 test.start++; 1076 test.length--; 1077 1078 pattern->negative = 1; 1079 pattern->any = 0; 1080 } 1081 1082 if (test.length > 0 && test.start[0] == '~') { 1083 #if (NXT_HAVE_REGEX) 1084 test.start++; 1085 test.length--; 1086 1087 re = nxt_regex_compile(mp, &test, &err); 1088 if (nxt_slow_path(re == NULL)) { 1089 if (err.offset < test.length) { 1090 nxt_alert(task, "nxt_regex_compile(%V) failed: %s at offset %d", 1091 &test, err.msg, (int) err.offset); 1092 return NXT_ERROR; 1093 } 1094 1095 nxt_alert(task, "nxt_regex_compile(%V) failed %s", &test, err.msg); 1096 1097 return NXT_ERROR; 1098 } 1099 1100 pattern->u.regex = re; 1101 pattern->regex = 1; 1102 1103 return NXT_OK; 1104 1105 #else 1106 return NXT_ERROR; 1107 #endif 1108 } 1109 1110 slices = nxt_array_create(mp, 1, sizeof(nxt_http_route_pattern_slice_t)); 1111 if (nxt_slow_path(slices == NULL)) { 1112 return NXT_ERROR; 1113 } 1114 1115 pattern->u.pattern_slices = slices; 1116 1117 if (test.length == 0) { 1118 slice = nxt_array_add(slices); 1119 if (nxt_slow_path(slice == NULL)) { 1120 return NXT_ERROR; 1121 } 1122 1123 slice->type = NXT_HTTP_ROUTE_PATTERN_EXACT; 1124 slice->start = NULL; 1125 slice->length = 0; 1126 1127 return NXT_OK; 1128 } 1129 1130 if (test.start[0] == '*') { 1131 /* 'type' is no longer 'EXACT', assume 'END'. */ 1132 type = NXT_HTTP_ROUTE_PATTERN_END; 1133 test.start++; 1134 test.length--; 1135 } 1136 1137 if (type == NXT_HTTP_ROUTE_PATTERN_EXACT) { 1138 tmp.start = test.start; 1139 1140 p = nxt_memchr(test.start, '*', test.length); 1141 1142 if (p == NULL) { 1143 /* No '*' found - EXACT pattern. */ 1144 tmp.length = test.length; 1145 type = NXT_HTTP_ROUTE_PATTERN_EXACT; 1146 1147 test.start += test.length; 1148 test.length = 0; 1149 1150 } else { 1151 /* '*' found - BEGIN pattern. */ 1152 tmp.length = p - test.start; 1153 type = NXT_HTTP_ROUTE_PATTERN_BEGIN; 1154 1155 test.start = p + 1; 1156 test.length -= tmp.length + 1; 1157 } 1158 1159 ret = nxt_http_route_pattern_slice(slices, &tmp, type, encoding, 1160 pattern_case); 1161 if (nxt_slow_path(ret != NXT_OK)) { 1162 return ret; 1163 } 1164 1165 pattern->min_length += tmp.length; 1166 } 1167 1168 end = test.start + test.length; 1169 1170 if (test.length != 0 && end[-1] != '*') { 1171 p = end - 1; 1172 1173 while (p != test.start) { 1174 c = *p--; 1175 1176 if (c == '*') { 1177 p += 2; 1178 break; 1179 } 1180 } 1181 1182 tmp.start = p; 1183 tmp.length = end - p; 1184 1185 test.length -= tmp.length; 1186 end = p; 1187 1188 ret = nxt_http_route_pattern_slice(slices, &tmp, 1189 NXT_HTTP_ROUTE_PATTERN_END, 1190 encoding, pattern_case); 1191 if (nxt_slow_path(ret != NXT_OK)) { 1192 return ret; 1193 } 1194 1195 pattern->min_length += tmp.length; 1196 } 1197 1198 tmp.start = test.start; 1199 tmp.length = 0; 1200 1201 p = tmp.start; 1202 1203 while (p != end) { 1204 c = *p++; 1205 1206 if (c != '*') { 1207 tmp.length++; 1208 continue; 1209 } 1210 1211 if (tmp.length == 0) { 1212 tmp.start = p; 1213 continue; 1214 } 1215 1216 ret = nxt_http_route_pattern_slice(slices, &tmp, 1217 NXT_HTTP_ROUTE_PATTERN_SUBSTRING, 1218 encoding, pattern_case); 1219 if (nxt_slow_path(ret != NXT_OK)) { 1220 return ret; 1221 } 1222 1223 pattern->min_length += tmp.length; 1224 1225 tmp.start = p; 1226 tmp.length = 0; 1227 } 1228 1229 if (tmp.length != 0) { 1230 ret = nxt_http_route_pattern_slice(slices, &tmp, 1231 NXT_HTTP_ROUTE_PATTERN_SUBSTRING, 1232 encoding, pattern_case); 1233 if (nxt_slow_path(ret != NXT_OK)) { 1234 return ret; 1235 } 1236 1237 pattern->min_length += tmp.length; 1238 } 1239 1240 return NXT_OK; 1241 } 1242 1243 1244 static nxt_int_t 1245 nxt_http_route_decode_str(nxt_str_t *str, nxt_http_route_encoding_t encoding) 1246 { 1247 u_char *start, *end; 1248 1249 switch (encoding) { 1250 case NXT_HTTP_ROUTE_ENCODING_NONE: 1251 break; 1252 1253 case NXT_HTTP_ROUTE_ENCODING_URI: 1254 start = str->start; 1255 1256 end = nxt_decode_uri(start, start, str->length); 1257 if (nxt_slow_path(end == NULL)) { 1258 return NXT_ERROR; 1259 } 1260 1261 str->length = end - start; 1262 break; 1263 1264 case NXT_HTTP_ROUTE_ENCODING_URI_PLUS: 1265 start = str->start; 1266 1267 end = nxt_decode_uri_plus(start, start, str->length); 1268 if (nxt_slow_path(end == NULL)) { 1269 return NXT_ERROR; 1270 } 1271 1272 str->length = end - start; 1273 break; 1274 1275 default: 1276 nxt_unreachable(); 1277 } 1278 1279 return NXT_OK; 1280 } 1281 1282 1283 static nxt_int_t 1284 nxt_http_route_pattern_slice(nxt_array_t *slices, 1285 nxt_str_t *test, 1286 nxt_http_route_pattern_type_t type, 1287 nxt_http_route_encoding_t encoding, 1288 nxt_http_route_pattern_case_t pattern_case) 1289 { 1290 u_char *start; 1291 nxt_int_t ret; 1292 nxt_http_route_pattern_slice_t *slice; 1293 1294 ret = nxt_http_route_decode_str(test, encoding); 1295 if (nxt_slow_path(ret != NXT_OK)) { 1296 return ret; 1297 } 1298 1299 start = nxt_mp_nget(slices->mem_pool, test->length); 1300 if (nxt_slow_path(start == NULL)) { 1301 return NXT_ERROR; 1302 } 1303 1304 switch (pattern_case) { 1305 1306 case NXT_HTTP_ROUTE_PATTERN_UPCASE: 1307 nxt_memcpy_upcase(start, test->start, test->length); 1308 break; 1309 1310 case NXT_HTTP_ROUTE_PATTERN_LOWCASE: 1311 nxt_memcpy_lowcase(start, test->start, test->length); 1312 break; 1313 1314 case NXT_HTTP_ROUTE_PATTERN_NOCASE: 1315 nxt_memcpy(start, test->start, test->length); 1316 break; 1317 } 1318 1319 slice = nxt_array_add(slices); 1320 if (nxt_slow_path(slice == NULL)) { 1321 return NXT_ERROR; 1322 } 1323 1324 slice->type = type; 1325 slice->start = start; 1326 slice->length = test->length; 1327 1328 return NXT_OK; 1329 } 1330 1331 1332 nxt_int_t 1333 nxt_http_routes_resolve(nxt_task_t *task, nxt_router_temp_conf_t *tmcf) 1334 { 1335 nxt_int_t ret; 1336 nxt_http_route_t **route, **end; 1337 nxt_http_routes_t *routes; 1338 1339 routes = tmcf->router_conf->routes; 1340 1341 if (routes != NULL) { 1342 route = &routes->route[0]; 1343 end = route + routes->items; 1344 1345 while (route < end) { 1346 ret = nxt_http_route_resolve(task, tmcf, *route); 1347 if (nxt_slow_path(ret != NXT_OK)) { 1348 return NXT_ERROR; 1349 } 1350 1351 route++; 1352 } 1353 } 1354 1355 return NXT_OK; 1356 } 1357 1358 1359 static nxt_int_t 1360 nxt_http_route_resolve(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 1361 nxt_http_route_t *route) 1362 { 1363 nxt_int_t ret; 1364 nxt_http_route_match_t **match, **end; 1365 1366 match = &route->match[0]; 1367 end = match + route->items; 1368 1369 while (match < end) { 1370 ret = nxt_http_action_resolve(task, tmcf, &(*match)->action); 1371 if (nxt_slow_path(ret != NXT_OK)) { 1372 return NXT_ERROR; 1373 } 1374 1375 match++; 1376 } 1377 1378 return NXT_OK; 1379 } 1380 1381 1382 static nxt_int_t 1383 nxt_http_action_resolve(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 1384 nxt_http_action_t *action) 1385 { 1386 nxt_int_t ret; 1387 nxt_var_t *var; 1388 1389 if (action->handler != NULL) { 1390 if (action->fallback != NULL) { 1391 return nxt_http_action_resolve(task, tmcf, action->fallback); 1392 } 1393 1394 return NXT_OK; 1395 } 1396 1397 if (nxt_is_var(&action->name)) { 1398 var = nxt_var_compile(&action->name, tmcf->router_conf->mem_pool); 1399 if (nxt_slow_path(var == NULL)) { 1400 return NXT_ERROR; 1401 } 1402 1403 action->u.var = var; 1404 action->handler = nxt_http_action_pass_var; 1405 return NXT_OK; 1406 } 1407 1408 ret = nxt_http_pass_find(task, tmcf->mem_pool, tmcf->router_conf, action); 1409 if (nxt_slow_path(ret != NXT_OK)) { 1410 return NXT_ERROR; 1411 } 1412 1413 return NXT_OK; 1414 } 1415 1416 1417 static nxt_http_action_t * 1418 nxt_http_action_pass_var(nxt_task_t *task, nxt_http_request_t *r, 1419 nxt_http_action_t *action) 1420 { 1421 nxt_var_t *var; 1422 nxt_int_t ret; 1423 1424 ret = nxt_var_query_init(&r->var_query, r, r->mem_pool); 1425 if (nxt_slow_path(ret != NXT_OK)) { 1426 goto fail; 1427 } 1428 1429 var = action->u.var; 1430 1431 action = nxt_mp_get(r->mem_pool, sizeof(nxt_http_action_t)); 1432 if (nxt_slow_path(action == NULL)) { 1433 goto fail; 1434 } 1435 1436 nxt_var_query(task, r->var_query, var, &action->name); 1437 nxt_var_query_resolve(task, r->var_query, action, 1438 nxt_http_action_pass_var_ready, 1439 nxt_http_action_pass_var_error); 1440 return NULL; 1441 1442 fail: 1443 1444 nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); 1445 return NULL; 1446 } 1447 1448 1449 static void 1450 nxt_http_action_pass_var_ready(nxt_task_t *task, void *obj, void *data) 1451 { 1452 nxt_int_t ret; 1453 nxt_router_conf_t *rtcf; 1454 nxt_http_action_t *action; 1455 nxt_http_status_t status; 1456 nxt_http_request_t *r; 1457 1458 r = obj; 1459 action = data; 1460 rtcf = r->conf->socket_conf->router_conf; 1461 1462 nxt_debug(task, "http pass lookup: %V", &action->name); 1463 1464 ret = nxt_http_pass_find(task, r->mem_pool, rtcf, action); 1465 1466 if (ret != NXT_OK) { 1467 status = (ret == NXT_DECLINED) ? NXT_HTTP_NOT_FOUND 1468 : NXT_HTTP_INTERNAL_SERVER_ERROR; 1469 1470 nxt_http_request_error(task, r, status); 1471 return; 1472 } 1473 1474 nxt_http_request_action(task, r, action); 1475 } 1476 1477 1478 static void 1479 nxt_http_action_pass_var_error(nxt_task_t *task, void *obj, void *data) 1480 { 1481 nxt_http_request_t *r; 1482 1483 r = obj; 1484 1485 nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); 1486 } 1487 1488 1489 static nxt_int_t 1490 nxt_http_pass_find(nxt_task_t *task, nxt_mp_t *mp, nxt_router_conf_t *rtcf, 1491 nxt_http_action_t *action) 1492 { 1493 nxt_str_t *targets; 1494 nxt_int_t ret; 1495 nxt_uint_t i; 1496 nxt_str_t segments[3]; 1497 1498 ret = nxt_http_pass_segments(mp, &action->name, segments, 3); 1499 if (nxt_slow_path(ret != NXT_OK)) { 1500 return ret; 1501 } 1502 1503 if (nxt_str_eq(&segments[0], "applications", 12)) { 1504 ret = nxt_router_listener_application(rtcf, &segments[1], action); 1505 1506 if (ret != NXT_OK) { 1507 return ret; 1508 } 1509 1510 if (segments[2].length != 0) { 1511 targets = action->u.app.application->targets; 1512 1513 for (i = 0; !nxt_strstr_eq(&segments[2], &targets[i]); i++); 1514 1515 action->u.app.target = i; 1516 1517 } else { 1518 action->u.app.target = 0; 1519 } 1520 1521 return NXT_OK; 1522 } 1523 1524 if (segments[2].length == 0) { 1525 if (nxt_str_eq(&segments[0], "upstreams", 9)) { 1526 return nxt_upstream_find(rtcf->upstreams, &segments[1], action); 1527 } 1528 1529 if (nxt_str_eq(&segments[0], "routes", 6)) { 1530 return nxt_http_route_find(rtcf->routes, &segments[1], action); 1531 } 1532 } 1533 1534 return NXT_DECLINED; 1535 } 1536 1537 1538 nxt_int_t 1539 nxt_http_pass_segments(nxt_mp_t *mp, nxt_str_t *pass, nxt_str_t *segments, 1540 nxt_uint_t n) 1541 { 1542 u_char *p; 1543 nxt_str_t rest; 1544 1545 if (nxt_slow_path(nxt_str_dup(mp, &rest, pass) == NULL)) { 1546 return NXT_ERROR; 1547 } 1548 1549 nxt_memzero(segments, n * sizeof(nxt_str_t)); 1550 1551 do { 1552 p = nxt_memchr(rest.start, '/', rest.length); 1553 1554 if (p != NULL) { 1555 n--; 1556 1557 if (n == 0) { 1558 return NXT_DECLINED; 1559 } 1560 1561 segments->length = p - rest.start; 1562 segments->start = rest.start; 1563 1564 rest.length -= segments->length + 1; 1565 rest.start = p + 1; 1566 1567 } else { 1568 n = 0; 1569 *segments = rest; 1570 } 1571 1572 if (segments->length == 0) { 1573 return NXT_DECLINED; 1574 } 1575 1576 p = nxt_decode_uri(segments->start, segments->start, segments->length); 1577 if (p == NULL) { 1578 return NXT_DECLINED; 1579 } 1580 1581 segments->length = p - segments->start; 1582 segments++; 1583 1584 } while (n); 1585 1586 return NXT_OK; 1587 } 1588 1589 1590 static nxt_int_t 1591 nxt_http_route_find(nxt_http_routes_t *routes, nxt_str_t *name, 1592 nxt_http_action_t *action) 1593 { 1594 nxt_http_route_t **route, **end; 1595 1596 route = &routes->route[0]; 1597 end = route + routes->items; 1598 1599 while (route < end) { 1600 if (nxt_strstr_eq(&(*route)->name, name)) { 1601 action->u.route = *route; 1602 action->handler = nxt_http_route_handler; 1603 1604 return NXT_OK; 1605 } 1606 1607 route++; 1608 } 1609 1610 return NXT_DECLINED; 1611 } 1612 1613 1614 nxt_http_action_t * 1615 nxt_http_action_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 1616 nxt_str_t *name) 1617 { 1618 nxt_int_t ret; 1619 nxt_http_action_t *action; 1620 1621 action = nxt_mp_alloc(tmcf->router_conf->mem_pool, 1622 sizeof(nxt_http_action_t)); 1623 if (nxt_slow_path(action == NULL)) { 1624 return NULL; 1625 } 1626 1627 action->name = *name; 1628 action->handler = NULL; 1629 1630 ret = nxt_http_action_resolve(task, tmcf, action); 1631 if (nxt_slow_path(ret != NXT_OK)) { 1632 return NULL; 1633 } 1634 1635 return action; 1636 } 1637 1638 1639 /* COMPATIBILITY: listener application. */ 1640 1641 nxt_http_action_t * 1642 nxt_http_pass_application(nxt_task_t *task, nxt_router_conf_t *rtcf, 1643 nxt_str_t *name) 1644 { 1645 nxt_http_action_t *action; 1646 1647 action = nxt_mp_alloc(rtcf->mem_pool, sizeof(nxt_http_action_t)); 1648 if (nxt_slow_path(action == NULL)) { 1649 return NULL; 1650 } 1651 1652 action->name = *name; 1653 1654 (void) nxt_router_listener_application(rtcf, name, action); 1655 1656 action->u.app.target = 0; 1657 1658 return action; 1659 } 1660 1661 1662 static nxt_http_action_t * 1663 nxt_http_route_handler(nxt_task_t *task, nxt_http_request_t *r, 1664 nxt_http_action_t *start) 1665 { 1666 nxt_http_route_t *route; 1667 nxt_http_action_t *action; 1668 nxt_http_route_match_t **match, **end; 1669 1670 route = start->u.route; 1671 match = &route->match[0]; 1672 end = match + route->items; 1673 1674 while (match < end) { 1675 action = nxt_http_route_match(task, r, *match); 1676 if (action != NULL) { 1677 return action; 1678 } 1679 1680 match++; 1681 } 1682 1683 nxt_http_request_error(task, r, NXT_HTTP_NOT_FOUND); 1684 1685 return NULL; 1686 } 1687 1688 1689 static nxt_http_action_t * 1690 nxt_http_route_match(nxt_task_t *task, nxt_http_request_t *r, 1691 nxt_http_route_match_t *match) 1692 { 1693 nxt_int_t ret; 1694 nxt_http_route_test_t *test, *end; 1695 1696 test = &match->test[0]; 1697 end = test + match->items; 1698 1699 while (test < end) { 1700 switch (test->rule->object) { 1701 case NXT_HTTP_ROUTE_TABLE: 1702 ret = nxt_http_route_table(r, test->table); 1703 break; 1704 case NXT_HTTP_ROUTE_SOURCE: 1705 ret = nxt_http_route_addr_rule(r, test->addr_rule, r->remote); 1706 break; 1707 case NXT_HTTP_ROUTE_DESTINATION: 1708 if (r->local == NULL && nxt_fast_path(r->proto.any != NULL)) { 1709 nxt_http_proto[r->protocol].local_addr(task, r); 1710 } 1711 1712 ret = nxt_http_route_addr_rule(r, test->addr_rule, r->local); 1713 break; 1714 default: 1715 ret = nxt_http_route_rule(r, test->rule); 1716 break; 1717 } 1718 1719 if (ret <= 0) { 1720 /* 0 => NULL, -1 => NXT_HTTP_ACTION_ERROR. */ 1721 return (nxt_http_action_t *) (intptr_t) ret; 1722 } 1723 1724 test++; 1725 } 1726 1727 return &match->action; 1728 } 1729 1730 1731 static nxt_int_t 1732 nxt_http_route_table(nxt_http_request_t *r, nxt_http_route_table_t *table) 1733 { 1734 nxt_int_t ret; 1735 nxt_http_route_ruleset_t **ruleset, **end; 1736 1737 ret = 1; 1738 ruleset = &table->ruleset[0]; 1739 end = ruleset + table->items; 1740 1741 while (ruleset < end) { 1742 ret = nxt_http_route_ruleset(r, *ruleset); 1743 1744 if (ret != 0) { 1745 return ret; 1746 } 1747 1748 ruleset++; 1749 } 1750 1751 return ret; 1752 } 1753 1754 1755 static nxt_int_t 1756 nxt_http_route_ruleset(nxt_http_request_t *r, nxt_http_route_ruleset_t *ruleset) 1757 { 1758 nxt_int_t ret; 1759 nxt_http_route_rule_t **rule, **end; 1760 1761 rule = &ruleset->rule[0]; 1762 end = rule + ruleset->items; 1763 1764 while (rule < end) { 1765 ret = nxt_http_route_rule(r, *rule); 1766 1767 if (ret <= 0) { 1768 return ret; 1769 } 1770 1771 rule++; 1772 } 1773 1774 return 1; 1775 } 1776 1777 1778 static nxt_int_t 1779 nxt_http_route_rule(nxt_http_request_t *r, nxt_http_route_rule_t *rule) 1780 { 1781 void *p, **pp; 1782 u_char *start; 1783 size_t length; 1784 nxt_str_t *s; 1785 1786 switch (rule->object) { 1787 1788 case NXT_HTTP_ROUTE_HEADER: 1789 return nxt_http_route_header(r, rule); 1790 1791 case NXT_HTTP_ROUTE_ARGUMENT: 1792 return nxt_http_route_arguments(r, rule); 1793 1794 case NXT_HTTP_ROUTE_COOKIE: 1795 return nxt_http_route_cookies(r, rule); 1796 1797 case NXT_HTTP_ROUTE_SCHEME: 1798 return nxt_http_route_scheme(r, rule); 1799 1800 default: 1801 break; 1802 } 1803 1804 p = nxt_pointer_to(r, rule->u.offset); 1805 1806 if (rule->object == NXT_HTTP_ROUTE_STRING) { 1807 s = p; 1808 1809 } else { 1810 /* NXT_HTTP_ROUTE_STRING_PTR */ 1811 pp = p; 1812 s = *pp; 1813 1814 if (s == NULL) { 1815 return 0; 1816 } 1817 } 1818 1819 length = s->length; 1820 start = s->start; 1821 1822 return nxt_http_route_test_rule(r, rule, start, length); 1823 } 1824 1825 1826 static nxt_int_t 1827 nxt_http_route_addr_pattern_match(nxt_http_route_addr_pattern_t *p, 1828 nxt_sockaddr_t *sa) 1829 { 1830 #if (NXT_INET6) 1831 uint32_t i; 1832 #endif 1833 in_port_t in_port; 1834 nxt_int_t match; 1835 struct sockaddr_in *sin; 1836 #if (NXT_INET6) 1837 struct sockaddr_in6 *sin6; 1838 #endif 1839 nxt_http_route_addr_base_t *base; 1840 1841 base = &p->base; 1842 1843 switch (sa->u.sockaddr.sa_family) { 1844 1845 case AF_INET: 1846 1847 match = (base->addr_family == AF_INET 1848 || base->addr_family == AF_UNSPEC); 1849 if (!match) { 1850 break; 1851 } 1852 1853 sin = &sa->u.sockaddr_in; 1854 in_port = ntohs(sin->sin_port); 1855 1856 match = (in_port >= base->port.start && in_port <= base->port.end); 1857 if (!match) { 1858 break; 1859 } 1860 1861 switch (base->match_type) { 1862 1863 case NXT_HTTP_ROUTE_ADDR_ANY: 1864 break; 1865 1866 case NXT_HTTP_ROUTE_ADDR_EXACT: 1867 match = (nxt_memcmp(&sin->sin_addr, &p->addr.v4.start, 1868 sizeof(struct in_addr)) 1869 == 0); 1870 break; 1871 1872 case NXT_HTTP_ROUTE_ADDR_RANGE: 1873 match = (nxt_memcmp(&sin->sin_addr, &p->addr.v4.start, 1874 sizeof(struct in_addr)) >= 0 1875 && nxt_memcmp(&sin->sin_addr, &p->addr.v4.end, 1876 sizeof(struct in_addr)) <= 0); 1877 break; 1878 1879 case NXT_HTTP_ROUTE_ADDR_CIDR: 1880 match = ((sin->sin_addr.s_addr & p->addr.v4.end) 1881 == p->addr.v4.start); 1882 break; 1883 1884 default: 1885 nxt_unreachable(); 1886 } 1887 1888 break; 1889 1890 #if (NXT_INET6) 1891 case AF_INET6: 1892 1893 match = (base->addr_family == AF_INET6 1894 || base->addr_family == AF_UNSPEC); 1895 if (!match) { 1896 break; 1897 } 1898 1899 sin6 = &sa->u.sockaddr_in6; 1900 in_port = ntohs(sin6->sin6_port); 1901 1902 match = (in_port >= base->port.start && in_port <= base->port.end); 1903 if (!match) { 1904 break; 1905 } 1906 1907 switch (base->match_type) { 1908 1909 case NXT_HTTP_ROUTE_ADDR_ANY: 1910 break; 1911 1912 case NXT_HTTP_ROUTE_ADDR_EXACT: 1913 match = (nxt_memcmp(&sin6->sin6_addr, &p->addr.v6.start, 1914 sizeof(struct in6_addr)) 1915 == 0); 1916 break; 1917 1918 case NXT_HTTP_ROUTE_ADDR_RANGE: 1919 match = (nxt_memcmp(&sin6->sin6_addr, &p->addr.v6.start, 1920 sizeof(struct in6_addr)) >= 0 1921 && nxt_memcmp(&sin6->sin6_addr, &p->addr.v6.end, 1922 sizeof(struct in6_addr)) <= 0); 1923 break; 1924 1925 case NXT_HTTP_ROUTE_ADDR_CIDR: 1926 for (i = 0; i < 16; i++) { 1927 match = ((sin6->sin6_addr.s6_addr[i] 1928 & p->addr.v6.end.s6_addr[i]) 1929 == p->addr.v6.start.s6_addr[i]); 1930 1931 if (!match) { 1932 break; 1933 } 1934 } 1935 1936 break; 1937 1938 default: 1939 nxt_unreachable(); 1940 } 1941 1942 break; 1943 #endif 1944 1945 default: 1946 match = 0; 1947 break; 1948 } 1949 1950 return match ^ base->negative; 1951 } 1952 1953 1954 static nxt_int_t 1955 nxt_http_route_addr_rule(nxt_http_request_t *r, 1956 nxt_http_route_addr_rule_t *addr_rule, nxt_sockaddr_t *sa) 1957 { 1958 uint32_t n; 1959 nxt_bool_t matches; 1960 nxt_http_route_addr_pattern_t *p; 1961 1962 n = addr_rule->items; 1963 p = &addr_rule->addr_pattern[0] - 1; 1964 1965 do { 1966 p++; 1967 n--; 1968 1969 matches = nxt_http_route_addr_pattern_match(p, sa); 1970 1971 if (p->base.negative) { 1972 if (matches) { 1973 continue; 1974 } 1975 1976 return 0; 1977 } 1978 1979 if (matches) { 1980 return 1; 1981 } 1982 1983 } while (n > 0); 1984 1985 return p->base.negative; 1986 } 1987 1988 1989 static nxt_int_t 1990 nxt_http_route_header(nxt_http_request_t *r, nxt_http_route_rule_t *rule) 1991 { 1992 nxt_int_t ret; 1993 nxt_http_field_t *f; 1994 1995 ret = 0; 1996 1997 nxt_list_each(f, r->fields) { 1998 1999 if (rule->u.name.hash != f->hash 2000 || rule->u.name.length != f->name_length 2001 || nxt_strncasecmp(rule->u.name.start, f->name, f->name_length) 2002 != 0) 2003 { 2004 continue; 2005 } 2006 2007 ret = nxt_http_route_test_rule(r, rule, f->value, f->value_length); 2008 if (nxt_slow_path(ret == NXT_ERROR)) { 2009 return NXT_ERROR; 2010 } 2011 2012 if (ret == 0) { 2013 return ret; 2014 } 2015 2016 } nxt_list_loop; 2017 2018 return ret; 2019 } 2020 2021 2022 static nxt_int_t 2023 nxt_http_route_arguments(nxt_http_request_t *r, nxt_http_route_rule_t *rule) 2024 { 2025 nxt_array_t *arguments; 2026 2027 if (r->args == NULL) { 2028 return 0; 2029 } 2030 2031 arguments = nxt_http_route_arguments_parse(r); 2032 if (nxt_slow_path(arguments == NULL)) { 2033 return -1; 2034 } 2035 2036 return nxt_http_route_test_argument(r, rule, arguments); 2037 } 2038 2039 2040 static nxt_array_t * 2041 nxt_http_route_arguments_parse(nxt_http_request_t *r) 2042 { 2043 size_t name_length; 2044 u_char c, *p, *dst, *dst_start, *start, *end, *name; 2045 uint8_t d0, d1; 2046 uint32_t hash; 2047 nxt_bool_t valid; 2048 nxt_array_t *args; 2049 nxt_http_name_value_t *nv; 2050 2051 if (r->arguments != NULL) { 2052 return r->arguments; 2053 } 2054 2055 args = nxt_array_create(r->mem_pool, 2, sizeof(nxt_http_name_value_t)); 2056 if (nxt_slow_path(args == NULL)) { 2057 return NULL; 2058 } 2059 2060 hash = NXT_HTTP_FIELD_HASH_INIT; 2061 valid = 1; 2062 name = NULL; 2063 name_length = 0; 2064 2065 dst_start = nxt_mp_nget(r->mem_pool, r->args->length); 2066 if (nxt_slow_path(dst_start == NULL)) { 2067 return NULL; 2068 } 2069 2070 start = r->args->start; 2071 end = start + r->args->length; 2072 2073 for (p = start, dst = dst_start; p < end; p++, dst++) { 2074 c = *p; 2075 *dst = c; 2076 2077 switch (c) { 2078 case '=': 2079 if (name != NULL) { 2080 break; 2081 } 2082 2083 name_length = dst - dst_start; 2084 valid = (name_length != 0); 2085 name = dst_start; 2086 dst_start = dst + 1; 2087 2088 continue; 2089 2090 case '&': 2091 if (valid) { 2092 nv = nxt_http_route_argument(args, name, name_length, hash, 2093 dst_start, dst); 2094 if (nxt_slow_path(nv == NULL)) { 2095 return NULL; 2096 } 2097 } 2098 2099 hash = NXT_HTTP_FIELD_HASH_INIT; 2100 name_length = 0; 2101 valid = 1; 2102 name = NULL; 2103 dst_start = dst + 1; 2104 2105 continue; 2106 2107 case '+': 2108 c = ' '; 2109 *dst = ' '; 2110 2111 break; 2112 2113 case '%': 2114 if (nxt_slow_path(end - p <= 2)) { 2115 break; 2116 } 2117 2118 d0 = nxt_hex2int[p[1]]; 2119 d1 = nxt_hex2int[p[2]]; 2120 2121 if (nxt_slow_path((d0 | d1) >= 16)) { 2122 break; 2123 } 2124 2125 p += 2; 2126 c = (d0 << 4) + d1; 2127 *dst = c; 2128 2129 break; 2130 } 2131 2132 if (name == NULL) { 2133 hash = nxt_http_field_hash_char(hash, c); 2134 } 2135 } 2136 2137 if (valid) { 2138 nv = nxt_http_route_argument(args, name, name_length, hash, dst_start, 2139 dst); 2140 if (nxt_slow_path(nv == NULL)) { 2141 return NULL; 2142 } 2143 } 2144 2145 r->arguments = args; 2146 2147 return args; 2148 } 2149 2150 2151 static nxt_http_name_value_t * 2152 nxt_http_route_argument(nxt_array_t *array, u_char *name, size_t name_length, 2153 uint32_t hash, u_char *start, u_char *end) 2154 { 2155 size_t length; 2156 nxt_http_name_value_t *nv; 2157 2158 nv = nxt_array_add(array); 2159 if (nxt_slow_path(nv == NULL)) { 2160 return NULL; 2161 } 2162 2163 nv->hash = nxt_http_field_hash_end(hash) & 0xFFFF; 2164 2165 length = end - start; 2166 2167 if (name == NULL) { 2168 name_length = length; 2169 name = start; 2170 length = 0; 2171 } 2172 2173 nv->name_length = name_length; 2174 nv->value_length = length; 2175 nv->name = name; 2176 nv->value = start; 2177 2178 return nv; 2179 } 2180 2181 2182 static nxt_int_t 2183 nxt_http_route_test_argument(nxt_http_request_t *r, 2184 nxt_http_route_rule_t *rule, nxt_array_t *array) 2185 { 2186 nxt_int_t ret; 2187 nxt_http_name_value_t *nv, *end; 2188 2189 ret = 0; 2190 2191 nv = array->elts; 2192 end = nv + array->nelts; 2193 2194 while (nv < end) { 2195 2196 if (rule->u.name.hash == nv->hash 2197 && rule->u.name.length == nv->name_length 2198 && nxt_memcmp(rule->u.name.start, nv->name, nv->name_length) == 0) 2199 { 2200 ret = nxt_http_route_test_rule(r, rule, nv->value, 2201 nv->value_length); 2202 if (nxt_slow_path(ret == NXT_ERROR)) { 2203 return NXT_ERROR; 2204 } 2205 2206 if (ret == 0) { 2207 break; 2208 } 2209 } 2210 2211 nv++; 2212 } 2213 2214 return ret; 2215 } 2216 2217 2218 static nxt_int_t 2219 nxt_http_route_scheme(nxt_http_request_t *r, nxt_http_route_rule_t *rule) 2220 { 2221 nxt_bool_t tls, https; 2222 nxt_http_route_pattern_slice_t *pattern_slice; 2223 2224 pattern_slice = rule->pattern[0].u.pattern_slices->elts; 2225 https = (pattern_slice->length == nxt_length("https")); 2226 tls = (r->tls != NULL); 2227 2228 return (tls == https); 2229 } 2230 2231 2232 static nxt_int_t 2233 nxt_http_route_cookies(nxt_http_request_t *r, nxt_http_route_rule_t *rule) 2234 { 2235 nxt_array_t *cookies; 2236 2237 cookies = nxt_http_route_cookies_parse(r); 2238 if (nxt_slow_path(cookies == NULL)) { 2239 return -1; 2240 } 2241 2242 return nxt_http_route_test_cookie(r, rule, cookies); 2243 } 2244 2245 2246 static nxt_array_t * 2247 nxt_http_route_cookies_parse(nxt_http_request_t *r) 2248 { 2249 nxt_int_t ret; 2250 nxt_array_t *cookies; 2251 nxt_http_field_t *f; 2252 2253 if (r->cookies != NULL) { 2254 return r->cookies; 2255 } 2256 2257 cookies = nxt_array_create(r->mem_pool, 2, sizeof(nxt_http_name_value_t)); 2258 if (nxt_slow_path(cookies == NULL)) { 2259 return NULL; 2260 } 2261 2262 nxt_list_each(f, r->fields) { 2263 2264 if (f->hash != NXT_COOKIE_HASH 2265 || f->name_length != 6 2266 || nxt_strncasecmp(f->name, (u_char *) "Cookie", 6) != 0) 2267 { 2268 continue; 2269 } 2270 2271 ret = nxt_http_route_cookie_parse(cookies, f->value, 2272 f->value + f->value_length); 2273 if (ret != NXT_OK) { 2274 return NULL; 2275 } 2276 2277 } nxt_list_loop; 2278 2279 r->cookies = cookies; 2280 2281 return cookies; 2282 } 2283 2284 2285 static nxt_int_t 2286 nxt_http_route_cookie_parse(nxt_array_t *cookies, u_char *start, u_char *end) 2287 { 2288 size_t name_length; 2289 u_char c, *p, *name; 2290 nxt_http_name_value_t *nv; 2291 2292 name = NULL; 2293 name_length = 0; 2294 2295 for (p = start; p < end; p++) { 2296 c = *p; 2297 2298 if (c == '=') { 2299 while (start[0] == ' ') { start++; } 2300 2301 name_length = p - start; 2302 2303 if (name_length != 0) { 2304 name = start; 2305 } 2306 2307 start = p + 1; 2308 2309 } else if (c == ';') { 2310 if (name != NULL) { 2311 nv = nxt_http_route_cookie(cookies, name, name_length, 2312 start, p); 2313 if (nxt_slow_path(nv == NULL)) { 2314 return NXT_ERROR; 2315 } 2316 } 2317 2318 name = NULL; 2319 start = p + 1; 2320 } 2321 } 2322 2323 if (name != NULL) { 2324 nv = nxt_http_route_cookie(cookies, name, name_length, start, p); 2325 if (nxt_slow_path(nv == NULL)) { 2326 return NXT_ERROR; 2327 } 2328 } 2329 2330 return NXT_OK; 2331 } 2332 2333 2334 static nxt_http_name_value_t * 2335 nxt_http_route_cookie(nxt_array_t *array, u_char *name, size_t name_length, 2336 u_char *start, u_char *end) 2337 { 2338 u_char c, *p; 2339 uint32_t hash; 2340 nxt_http_name_value_t *nv; 2341 2342 nv = nxt_array_add(array); 2343 if (nxt_slow_path(nv == NULL)) { 2344 return NULL; 2345 } 2346 2347 nv->name_length = name_length; 2348 nv->name = name; 2349 2350 hash = NXT_HTTP_FIELD_HASH_INIT; 2351 2352 for (p = name; p < name + name_length; p++) { 2353 c = *p; 2354 hash = nxt_http_field_hash_char(hash, c); 2355 } 2356 2357 nv->hash = nxt_http_field_hash_end(hash) & 0xFFFF; 2358 2359 while (start < end && end[-1] == ' ') { end--; } 2360 2361 nv->value_length = end - start; 2362 nv->value = start; 2363 2364 return nv; 2365 } 2366 2367 2368 static nxt_int_t 2369 nxt_http_route_test_cookie(nxt_http_request_t *r, 2370 nxt_http_route_rule_t *rule, nxt_array_t *array) 2371 { 2372 nxt_int_t ret; 2373 nxt_http_name_value_t *nv, *end; 2374 2375 ret = 0; 2376 2377 nv = array->elts; 2378 end = nv + array->nelts; 2379 2380 while (nv < end) { 2381 2382 if (rule->u.name.hash == nv->hash 2383 && rule->u.name.length == nv->name_length 2384 && nxt_memcmp(rule->u.name.start, nv->name, nv->name_length) == 0) 2385 { 2386 ret = nxt_http_route_test_rule(r, rule, nv->value, 2387 nv->value_length); 2388 if (nxt_slow_path(ret == NXT_ERROR)) { 2389 return NXT_ERROR; 2390 } 2391 2392 if (ret == 0) { 2393 break; 2394 } 2395 } 2396 2397 nv++; 2398 } 2399 2400 return ret; 2401 } 2402 2403 2404 nxt_int_t 2405 nxt_http_route_test_rule(nxt_http_request_t *r, nxt_http_route_rule_t *rule, 2406 u_char *start, size_t length) 2407 { 2408 nxt_int_t ret; 2409 nxt_http_route_pattern_t *pattern, *end; 2410 2411 ret = 1; 2412 pattern = &rule->pattern[0]; 2413 end = pattern + rule->items; 2414 2415 while (pattern < end) { 2416 ret = nxt_http_route_pattern(r, pattern, start, length); 2417 if (nxt_slow_path(ret == NXT_ERROR)) { 2418 return NXT_ERROR; 2419 } 2420 2421 /* nxt_http_route_pattern() returns either 1 or 0. */ 2422 ret ^= pattern->negative; 2423 2424 if (pattern->any == ret) { 2425 return ret; 2426 } 2427 2428 pattern++; 2429 } 2430 2431 return ret; 2432 } 2433 2434 2435 static nxt_int_t 2436 nxt_http_route_pattern(nxt_http_request_t *r, nxt_http_route_pattern_t *pattern, 2437 u_char *start, size_t length) 2438 { 2439 u_char *p, *end, *test; 2440 size_t test_length; 2441 uint32_t i; 2442 nxt_array_t *pattern_slices; 2443 nxt_http_route_pattern_slice_t *pattern_slice; 2444 2445 #if (NXT_HAVE_REGEX) 2446 if (pattern->regex) { 2447 if (r->regex_match == NULL) { 2448 r->regex_match = nxt_regex_match_create(r->mem_pool, 0); 2449 if (nxt_slow_path(r->regex_match == NULL)) { 2450 return NXT_ERROR; 2451 } 2452 } 2453 2454 return nxt_regex_match(pattern->u.regex, start, length, r->regex_match); 2455 } 2456 #endif 2457 2458 if (length < pattern->min_length) { 2459 return 0; 2460 } 2461 2462 nxt_assert(pattern->u.pattern_slices != NULL); 2463 2464 pattern_slices = pattern->u.pattern_slices; 2465 pattern_slice = pattern_slices->elts; 2466 end = start + length; 2467 2468 for (i = 0; i < pattern_slices->nelts; i++, pattern_slice++) { 2469 test = pattern_slice->start; 2470 test_length = pattern_slice->length; 2471 2472 switch (pattern_slice->type) { 2473 case NXT_HTTP_ROUTE_PATTERN_EXACT: 2474 return ((length == pattern->min_length) && 2475 nxt_http_route_memcmp(start, test, test_length, 2476 pattern->case_sensitive)); 2477 2478 case NXT_HTTP_ROUTE_PATTERN_BEGIN: 2479 if (nxt_http_route_memcmp(start, test, test_length, 2480 pattern->case_sensitive)) 2481 { 2482 start += test_length; 2483 break; 2484 } 2485 2486 return 0; 2487 2488 case NXT_HTTP_ROUTE_PATTERN_END: 2489 p = end - test_length; 2490 2491 if (nxt_http_route_memcmp(p, test, test_length, 2492 pattern->case_sensitive)) 2493 { 2494 end = p; 2495 break; 2496 } 2497 2498 return 0; 2499 2500 case NXT_HTTP_ROUTE_PATTERN_SUBSTRING: 2501 if (pattern->case_sensitive) { 2502 p = nxt_memstrn(start, end, (char *) test, test_length); 2503 2504 } else { 2505 p = nxt_memcasestrn(start, end, (char *) test, test_length); 2506 } 2507 2508 if (p == NULL) { 2509 return 0; 2510 } 2511 2512 start = p + test_length; 2513 } 2514 } 2515 2516 return 1; 2517 } 2518 2519 2520 static nxt_int_t 2521 nxt_http_route_memcmp(u_char *start, u_char *test, size_t test_length, 2522 nxt_bool_t case_sensitive) 2523 { 2524 nxt_int_t n; 2525 2526 if (case_sensitive) { 2527 n = nxt_memcmp(start, test, test_length); 2528 2529 } else { 2530 n = nxt_memcasecmp(start, test, test_length); 2531 } 2532 2533 return (n == 0); 2534 } 2535