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