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