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