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_var_ready(nxt_task_t *task, void *obj, void *data); 197 static void nxt_http_pass_var_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_http_action_conf_t acf; 647 648 nxt_memzero(&acf, sizeof(acf)); 649 650 ret = nxt_conf_map_object(tmcf->mem_pool, cv, nxt_http_route_action_conf, 651 nxt_nitems(nxt_http_route_action_conf), &acf); 652 if (ret != NXT_OK) { 653 return ret; 654 } 655 656 nxt_memzero(action, sizeof(nxt_http_action_t)); 657 658 mp = tmcf->router_conf->mem_pool; 659 660 if (acf.ret != NULL) { 661 return nxt_http_return_init(mp, action, &acf); 662 } 663 664 if (acf.share != NULL) { 665 return nxt_http_static_init(task, tmcf, action, &acf); 666 } 667 668 if (acf.proxy != NULL) { 669 return nxt_http_proxy_init(mp, action, &acf); 670 } 671 672 nxt_conf_get_string(acf.pass, &pass); 673 674 action->u.var = nxt_var_compile(&pass, mp, 0); 675 if (nxt_slow_path(action->u.var == NULL)) { 676 return NXT_ERROR; 677 } 678 679 return NXT_OK; 680 } 681 682 683 static nxt_http_route_table_t * 684 nxt_http_route_table_create(nxt_task_t *task, nxt_mp_t *mp, 685 nxt_conf_value_t *table_cv, nxt_http_route_object_t object, 686 nxt_bool_t case_sensitive, nxt_http_uri_encoding_t encoding) 687 { 688 size_t size; 689 uint32_t i, n; 690 nxt_conf_value_t *ruleset_cv; 691 nxt_http_route_table_t *table; 692 nxt_http_route_ruleset_t *ruleset; 693 694 n = nxt_conf_array_elements_count_or_1(table_cv); 695 size = sizeof(nxt_http_route_table_t) 696 + n * sizeof(nxt_http_route_ruleset_t *); 697 698 table = nxt_mp_alloc(mp, size); 699 if (nxt_slow_path(table == NULL)) { 700 return NULL; 701 } 702 703 table->items = n; 704 table->object = NXT_HTTP_ROUTE_TABLE; 705 706 for (i = 0; i < n; i++) { 707 ruleset_cv = nxt_conf_get_array_element_or_itself(table_cv, i); 708 709 ruleset = nxt_http_route_ruleset_create(task, mp, ruleset_cv, object, 710 case_sensitive, encoding); 711 if (nxt_slow_path(ruleset == NULL)) { 712 return NULL; 713 } 714 715 table->ruleset[i] = ruleset; 716 } 717 718 return table; 719 } 720 721 722 static nxt_http_route_ruleset_t * 723 nxt_http_route_ruleset_create(nxt_task_t *task, nxt_mp_t *mp, 724 nxt_conf_value_t *ruleset_cv, nxt_http_route_object_t object, 725 nxt_bool_t case_sensitive, nxt_http_uri_encoding_t encoding) 726 { 727 size_t size; 728 uint32_t i, n, next; 729 nxt_str_t name; 730 nxt_conf_value_t *rule_cv; 731 nxt_http_route_rule_t *rule; 732 nxt_http_route_ruleset_t *ruleset; 733 734 n = nxt_conf_object_members_count(ruleset_cv); 735 size = sizeof(nxt_http_route_ruleset_t) 736 + n * sizeof(nxt_http_route_rule_t *); 737 738 ruleset = nxt_mp_alloc(mp, size); 739 if (nxt_slow_path(ruleset == NULL)) { 740 return NULL; 741 } 742 743 ruleset->items = n; 744 745 next = 0; 746 747 /* 748 * A workaround for GCC 10 with -flto -O2 flags that warns about "name" 749 * may be uninitialized in nxt_http_route_rule_name_create(). 750 */ 751 nxt_str_null(&name); 752 753 for (i = 0; i < n; i++) { 754 rule_cv = nxt_conf_next_object_member(ruleset_cv, &name, &next); 755 756 rule = nxt_http_route_rule_name_create(task, mp, rule_cv, &name, 757 case_sensitive, encoding); 758 if (nxt_slow_path(rule == NULL)) { 759 return NULL; 760 } 761 762 rule->object = object; 763 ruleset->rule[i] = rule; 764 } 765 766 return ruleset; 767 } 768 769 770 static nxt_http_route_rule_t * 771 nxt_http_route_rule_name_create(nxt_task_t *task, nxt_mp_t *mp, 772 nxt_conf_value_t *rule_cv, nxt_str_t *name, nxt_bool_t case_sensitive, 773 nxt_http_uri_encoding_t encoding) 774 { 775 int64_t hash; 776 nxt_http_route_rule_t *rule; 777 778 rule = nxt_http_route_rule_create(task, mp, rule_cv, case_sensitive, 779 NXT_HTTP_ROUTE_PATTERN_NOCASE, 780 encoding); 781 if (nxt_slow_path(rule == NULL)) { 782 return NULL; 783 } 784 785 hash = nxt_http_field_hash(mp, name, case_sensitive, encoding); 786 if (nxt_slow_path(hash == -1)) { 787 return NULL; 788 } 789 790 rule->u.name.hash = hash; 791 rule->u.name.start = name->start; 792 rule->u.name.length = name->length; 793 794 return rule; 795 } 796 797 798 static nxt_http_route_rule_t * 799 nxt_http_route_rule_create(nxt_task_t *task, nxt_mp_t *mp, 800 nxt_conf_value_t *cv, nxt_bool_t case_sensitive, 801 nxt_http_route_pattern_case_t pattern_case, 802 nxt_http_uri_encoding_t encoding) 803 { 804 size_t size; 805 uint32_t i, n; 806 nxt_int_t ret; 807 nxt_conf_value_t *value; 808 nxt_http_route_rule_t *rule; 809 nxt_http_route_pattern_t *pattern; 810 811 n = nxt_conf_array_elements_count_or_1(cv); 812 size = sizeof(nxt_http_route_rule_t) + n * sizeof(nxt_http_route_pattern_t); 813 814 rule = nxt_mp_alloc(mp, size); 815 if (nxt_slow_path(rule == NULL)) { 816 return NULL; 817 } 818 819 rule->items = n; 820 821 pattern = &rule->pattern[0]; 822 823 nxt_conf_array_qsort(cv, nxt_http_pattern_compare); 824 825 for (i = 0; i < n; i++) { 826 pattern[i].case_sensitive = case_sensitive; 827 value = nxt_conf_get_array_element_or_itself(cv, i); 828 829 ret = nxt_http_route_pattern_create(task, mp, value, &pattern[i], 830 pattern_case, encoding); 831 if (nxt_slow_path(ret != NXT_OK)) { 832 return NULL; 833 } 834 } 835 836 return rule; 837 } 838 839 840 nxt_http_route_addr_rule_t * 841 nxt_http_route_addr_rule_create(nxt_task_t *task, nxt_mp_t *mp, 842 nxt_conf_value_t *cv) 843 { 844 size_t size; 845 uint32_t i, n; 846 nxt_conf_value_t *value; 847 nxt_http_route_addr_rule_t *addr_rule; 848 nxt_http_route_addr_pattern_t *pattern; 849 850 n = nxt_conf_array_elements_count_or_1(cv); 851 852 size = sizeof(nxt_http_route_addr_rule_t) 853 + n * sizeof(nxt_http_route_addr_pattern_t); 854 855 addr_rule = nxt_mp_alloc(mp, size); 856 if (nxt_slow_path(addr_rule == NULL)) { 857 return NULL; 858 } 859 860 addr_rule->items = n; 861 862 for (i = 0; i < n; i++) { 863 pattern = &addr_rule->addr_pattern[i]; 864 value = nxt_conf_get_array_element_or_itself(cv, i); 865 866 if (nxt_http_route_addr_pattern_parse(mp, pattern, value) != NXT_OK) { 867 return NULL; 868 } 869 } 870 871 if (n > 1) { 872 nxt_qsort(addr_rule->addr_pattern, addr_rule->items, 873 sizeof(nxt_http_route_addr_pattern_t), 874 nxt_http_addr_pattern_compare); 875 } 876 877 return addr_rule; 878 } 879 880 881 nxt_http_route_rule_t * 882 nxt_http_route_types_rule_create(nxt_task_t *task, nxt_mp_t *mp, 883 nxt_conf_value_t *types) 884 { 885 return nxt_http_route_rule_create(task, mp, types, 0, 886 NXT_HTTP_ROUTE_PATTERN_LOWCASE, 887 NXT_HTTP_URI_ENCODING_NONE); 888 } 889 890 891 static int 892 nxt_http_pattern_compare(const void *one, const void *two) 893 { 894 nxt_str_t test; 895 nxt_bool_t negative1, negative2; 896 nxt_conf_value_t *value; 897 898 value = (nxt_conf_value_t *) one; 899 nxt_conf_get_string(value, &test); 900 negative1 = (test.length != 0 && test.start[0] == '!'); 901 902 value = (nxt_conf_value_t *) two; 903 nxt_conf_get_string(value, &test); 904 negative2 = (test.length != 0 && test.start[0] == '!'); 905 906 return (negative2 - negative1); 907 } 908 909 910 static int 911 nxt_http_addr_pattern_compare(const void *one, const void *two) 912 { 913 const nxt_http_route_addr_pattern_t *p1, *p2; 914 915 p1 = one; 916 p2 = two; 917 918 return (p2->base.negative - p1->base.negative); 919 } 920 921 922 static nxt_int_t 923 nxt_http_route_pattern_create(nxt_task_t *task, nxt_mp_t *mp, 924 nxt_conf_value_t *cv, nxt_http_route_pattern_t *pattern, 925 nxt_http_route_pattern_case_t pattern_case, 926 nxt_http_uri_encoding_t encoding) 927 { 928 u_char c, *p, *end; 929 nxt_str_t test, tmp; 930 nxt_int_t ret; 931 nxt_array_t *slices; 932 #if (NXT_HAVE_REGEX) 933 nxt_regex_t *re; 934 nxt_regex_err_t err; 935 #endif 936 nxt_http_route_pattern_type_t type; 937 nxt_http_route_pattern_slice_t *slice; 938 939 type = NXT_HTTP_ROUTE_PATTERN_EXACT; 940 941 nxt_conf_get_string(cv, &test); 942 943 pattern->u.pattern_slices = NULL; 944 pattern->negative = 0; 945 pattern->any = 1; 946 pattern->min_length = 0; 947 #if (NXT_HAVE_REGEX) 948 pattern->regex = 0; 949 #endif 950 951 if (test.length != 0 && test.start[0] == '!') { 952 test.start++; 953 test.length--; 954 955 pattern->negative = 1; 956 pattern->any = 0; 957 } 958 959 if (test.length > 0 && test.start[0] == '~') { 960 #if (NXT_HAVE_REGEX) 961 test.start++; 962 test.length--; 963 964 re = nxt_regex_compile(mp, &test, &err); 965 if (nxt_slow_path(re == NULL)) { 966 if (err.offset < test.length) { 967 nxt_alert(task, "nxt_regex_compile(%V) failed: %s at offset %d", 968 &test, err.msg, (int) err.offset); 969 return NXT_ERROR; 970 } 971 972 nxt_alert(task, "nxt_regex_compile(%V) failed %s", &test, err.msg); 973 974 return NXT_ERROR; 975 } 976 977 pattern->u.regex = re; 978 pattern->regex = 1; 979 980 return NXT_OK; 981 982 #else 983 return NXT_ERROR; 984 #endif 985 } 986 987 slices = nxt_array_create(mp, 1, sizeof(nxt_http_route_pattern_slice_t)); 988 if (nxt_slow_path(slices == NULL)) { 989 return NXT_ERROR; 990 } 991 992 pattern->u.pattern_slices = slices; 993 994 if (test.length == 0) { 995 slice = nxt_array_add(slices); 996 if (nxt_slow_path(slice == NULL)) { 997 return NXT_ERROR; 998 } 999 1000 slice->type = NXT_HTTP_ROUTE_PATTERN_EXACT; 1001 slice->start = NULL; 1002 slice->length = 0; 1003 1004 return NXT_OK; 1005 } 1006 1007 if (test.start[0] == '*') { 1008 /* 'type' is no longer 'EXACT', assume 'END'. */ 1009 type = NXT_HTTP_ROUTE_PATTERN_END; 1010 test.start++; 1011 test.length--; 1012 } 1013 1014 if (type == NXT_HTTP_ROUTE_PATTERN_EXACT) { 1015 tmp.start = test.start; 1016 1017 p = nxt_memchr(test.start, '*', test.length); 1018 1019 if (p == NULL) { 1020 /* No '*' found - EXACT pattern. */ 1021 tmp.length = test.length; 1022 type = NXT_HTTP_ROUTE_PATTERN_EXACT; 1023 1024 test.start += test.length; 1025 test.length = 0; 1026 1027 } else { 1028 /* '*' found - BEGIN pattern. */ 1029 tmp.length = p - test.start; 1030 type = NXT_HTTP_ROUTE_PATTERN_BEGIN; 1031 1032 test.start = p + 1; 1033 test.length -= tmp.length + 1; 1034 } 1035 1036 ret = nxt_http_route_pattern_slice(slices, &tmp, type, encoding, 1037 pattern_case); 1038 if (nxt_slow_path(ret != NXT_OK)) { 1039 return ret; 1040 } 1041 1042 pattern->min_length += tmp.length; 1043 } 1044 1045 end = test.start + test.length; 1046 1047 if (test.length != 0 && end[-1] != '*') { 1048 p = end - 1; 1049 1050 while (p != test.start) { 1051 c = *p--; 1052 1053 if (c == '*') { 1054 p += 2; 1055 break; 1056 } 1057 } 1058 1059 tmp.start = p; 1060 tmp.length = end - p; 1061 1062 test.length -= tmp.length; 1063 end = p; 1064 1065 ret = nxt_http_route_pattern_slice(slices, &tmp, 1066 NXT_HTTP_ROUTE_PATTERN_END, 1067 encoding, pattern_case); 1068 if (nxt_slow_path(ret != NXT_OK)) { 1069 return ret; 1070 } 1071 1072 pattern->min_length += tmp.length; 1073 } 1074 1075 tmp.start = test.start; 1076 tmp.length = 0; 1077 1078 p = tmp.start; 1079 1080 while (p != end) { 1081 c = *p++; 1082 1083 if (c != '*') { 1084 tmp.length++; 1085 continue; 1086 } 1087 1088 if (tmp.length == 0) { 1089 tmp.start = p; 1090 continue; 1091 } 1092 1093 ret = nxt_http_route_pattern_slice(slices, &tmp, 1094 NXT_HTTP_ROUTE_PATTERN_SUBSTRING, 1095 encoding, pattern_case); 1096 if (nxt_slow_path(ret != NXT_OK)) { 1097 return ret; 1098 } 1099 1100 pattern->min_length += tmp.length; 1101 1102 tmp.start = p; 1103 tmp.length = 0; 1104 } 1105 1106 if (tmp.length != 0) { 1107 ret = nxt_http_route_pattern_slice(slices, &tmp, 1108 NXT_HTTP_ROUTE_PATTERN_SUBSTRING, 1109 encoding, pattern_case); 1110 if (nxt_slow_path(ret != NXT_OK)) { 1111 return ret; 1112 } 1113 1114 pattern->min_length += tmp.length; 1115 } 1116 1117 return NXT_OK; 1118 } 1119 1120 1121 static nxt_int_t 1122 nxt_http_route_decode_str(nxt_str_t *str, nxt_http_uri_encoding_t encoding) 1123 { 1124 u_char *start, *end; 1125 1126 switch (encoding) { 1127 case NXT_HTTP_URI_ENCODING_NONE: 1128 break; 1129 1130 case NXT_HTTP_URI_ENCODING: 1131 start = str->start; 1132 1133 end = nxt_decode_uri(start, start, str->length); 1134 if (nxt_slow_path(end == NULL)) { 1135 return NXT_ERROR; 1136 } 1137 1138 str->length = end - start; 1139 break; 1140 1141 case NXT_HTTP_URI_ENCODING_PLUS: 1142 start = str->start; 1143 1144 end = nxt_decode_uri_plus(start, start, str->length); 1145 if (nxt_slow_path(end == NULL)) { 1146 return NXT_ERROR; 1147 } 1148 1149 str->length = end - start; 1150 break; 1151 1152 default: 1153 nxt_unreachable(); 1154 } 1155 1156 return NXT_OK; 1157 } 1158 1159 1160 static nxt_int_t 1161 nxt_http_route_pattern_slice(nxt_array_t *slices, 1162 nxt_str_t *test, nxt_http_route_pattern_type_t type, 1163 nxt_http_uri_encoding_t encoding, 1164 nxt_http_route_pattern_case_t pattern_case) 1165 { 1166 u_char *start; 1167 nxt_int_t ret; 1168 nxt_http_route_pattern_slice_t *slice; 1169 1170 ret = nxt_http_route_decode_str(test, encoding); 1171 if (nxt_slow_path(ret != NXT_OK)) { 1172 return ret; 1173 } 1174 1175 start = nxt_mp_nget(slices->mem_pool, test->length); 1176 if (nxt_slow_path(start == NULL)) { 1177 return NXT_ERROR; 1178 } 1179 1180 switch (pattern_case) { 1181 1182 case NXT_HTTP_ROUTE_PATTERN_UPCASE: 1183 nxt_memcpy_upcase(start, test->start, test->length); 1184 break; 1185 1186 case NXT_HTTP_ROUTE_PATTERN_LOWCASE: 1187 nxt_memcpy_lowcase(start, test->start, test->length); 1188 break; 1189 1190 case NXT_HTTP_ROUTE_PATTERN_NOCASE: 1191 nxt_memcpy(start, test->start, test->length); 1192 break; 1193 } 1194 1195 slice = nxt_array_add(slices); 1196 if (nxt_slow_path(slice == NULL)) { 1197 return NXT_ERROR; 1198 } 1199 1200 slice->type = type; 1201 slice->start = start; 1202 slice->length = test->length; 1203 1204 return NXT_OK; 1205 } 1206 1207 1208 nxt_int_t 1209 nxt_http_routes_resolve(nxt_task_t *task, nxt_router_temp_conf_t *tmcf) 1210 { 1211 nxt_int_t ret; 1212 nxt_http_route_t **route, **end; 1213 nxt_http_routes_t *routes; 1214 1215 routes = tmcf->router_conf->routes; 1216 1217 if (routes != NULL) { 1218 route = &routes->route[0]; 1219 end = route + routes->items; 1220 1221 while (route < end) { 1222 ret = nxt_http_route_resolve(task, tmcf, *route); 1223 if (nxt_slow_path(ret != NXT_OK)) { 1224 return NXT_ERROR; 1225 } 1226 1227 route++; 1228 } 1229 } 1230 1231 return NXT_OK; 1232 } 1233 1234 1235 static nxt_int_t 1236 nxt_http_route_resolve(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 1237 nxt_http_route_t *route) 1238 { 1239 nxt_int_t ret; 1240 nxt_http_route_match_t **match, **end; 1241 1242 match = &route->match[0]; 1243 end = match + route->items; 1244 1245 while (match < end) { 1246 ret = nxt_http_action_resolve(task, tmcf, &(*match)->action); 1247 if (nxt_slow_path(ret != NXT_OK)) { 1248 return NXT_ERROR; 1249 } 1250 1251 match++; 1252 } 1253 1254 return NXT_OK; 1255 } 1256 1257 1258 static nxt_int_t 1259 nxt_http_action_resolve(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 1260 nxt_http_action_t *action) 1261 { 1262 nxt_int_t ret; 1263 nxt_str_t pass; 1264 1265 if (action->handler != NULL) { 1266 if (action->fallback != NULL) { 1267 return nxt_http_action_resolve(task, tmcf, action->fallback); 1268 } 1269 1270 return NXT_OK; 1271 } 1272 1273 if (nxt_var_is_const(action->u.var)) { 1274 nxt_var_raw(action->u.var, &pass); 1275 1276 ret = nxt_http_pass_find(tmcf->mem_pool, tmcf->router_conf, &pass, 1277 action); 1278 if (nxt_slow_path(ret != NXT_OK)) { 1279 return NXT_ERROR; 1280 } 1281 1282 } else { 1283 action->handler = nxt_http_pass_var; 1284 } 1285 1286 return NXT_OK; 1287 } 1288 1289 1290 static nxt_http_action_t * 1291 nxt_http_pass_var(nxt_task_t *task, nxt_http_request_t *r, 1292 nxt_http_action_t *action) 1293 { 1294 nxt_int_t ret; 1295 nxt_str_t str; 1296 nxt_var_t *var; 1297 1298 var = action->u.var; 1299 1300 nxt_var_raw(var, &str); 1301 1302 nxt_debug(task, "http pass: \"%V\"", &str); 1303 1304 ret = nxt_var_query_init(&r->var_query, r, r->mem_pool); 1305 if (nxt_slow_path(ret != NXT_OK)) { 1306 goto fail; 1307 } 1308 1309 action = nxt_mp_get(r->mem_pool, 1310 sizeof(nxt_http_action_t) + sizeof(nxt_str_t)); 1311 if (nxt_slow_path(action == NULL)) { 1312 goto fail; 1313 } 1314 1315 action->u.pass = nxt_pointer_to(action, sizeof(nxt_http_action_t)); 1316 1317 nxt_var_query(task, r->var_query, var, action->u.pass); 1318 nxt_var_query_resolve(task, r->var_query, action, 1319 nxt_http_pass_var_ready, 1320 nxt_http_pass_var_error); 1321 return NULL; 1322 1323 fail: 1324 1325 nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); 1326 return NULL; 1327 } 1328 1329 1330 static void 1331 nxt_http_pass_var_ready(nxt_task_t *task, void *obj, void *data) 1332 { 1333 nxt_int_t ret; 1334 nxt_router_conf_t *rtcf; 1335 nxt_http_action_t *action; 1336 nxt_http_status_t status; 1337 nxt_http_request_t *r; 1338 1339 r = obj; 1340 action = data; 1341 rtcf = r->conf->socket_conf->router_conf; 1342 1343 nxt_debug(task, "http pass lookup: %V", action->u.pass); 1344 1345 ret = nxt_http_pass_find(r->mem_pool, rtcf, action->u.pass, action); 1346 1347 if (ret != NXT_OK) { 1348 status = (ret == NXT_DECLINED) ? NXT_HTTP_NOT_FOUND 1349 : NXT_HTTP_INTERNAL_SERVER_ERROR; 1350 1351 nxt_http_request_error(task, r, status); 1352 return; 1353 } 1354 1355 nxt_http_request_action(task, r, action); 1356 } 1357 1358 1359 static void 1360 nxt_http_pass_var_error(nxt_task_t *task, void *obj, void *data) 1361 { 1362 nxt_http_request_t *r; 1363 1364 r = obj; 1365 1366 nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); 1367 } 1368 1369 1370 static nxt_int_t 1371 nxt_http_pass_find(nxt_mp_t *mp, nxt_router_conf_t *rtcf, nxt_str_t *pass, 1372 nxt_http_action_t *action) 1373 { 1374 nxt_int_t ret; 1375 nxt_str_t segments[3]; 1376 1377 ret = nxt_http_pass_segments(mp, pass, segments, 3); 1378 if (nxt_slow_path(ret != NXT_OK)) { 1379 return ret; 1380 } 1381 1382 if (nxt_str_eq(&segments[0], "applications", 12)) { 1383 return nxt_router_application_init(rtcf, &segments[1], &segments[2], 1384 action); 1385 } 1386 1387 if (segments[2].length == 0) { 1388 if (nxt_str_eq(&segments[0], "upstreams", 9)) { 1389 return nxt_upstream_find(rtcf->upstreams, &segments[1], action); 1390 } 1391 1392 if (nxt_str_eq(&segments[0], "routes", 6)) { 1393 return nxt_http_route_find(rtcf->routes, &segments[1], action); 1394 } 1395 } 1396 1397 return NXT_DECLINED; 1398 } 1399 1400 1401 nxt_int_t 1402 nxt_http_pass_segments(nxt_mp_t *mp, nxt_str_t *pass, nxt_str_t *segments, 1403 nxt_uint_t n) 1404 { 1405 u_char *p; 1406 nxt_str_t rest; 1407 1408 if (nxt_slow_path(nxt_str_dup(mp, &rest, pass) == NULL)) { 1409 return NXT_ERROR; 1410 } 1411 1412 nxt_memzero(segments, n * sizeof(nxt_str_t)); 1413 1414 do { 1415 p = nxt_memchr(rest.start, '/', rest.length); 1416 1417 if (p != NULL) { 1418 n--; 1419 1420 if (n == 0) { 1421 return NXT_DECLINED; 1422 } 1423 1424 segments->length = p - rest.start; 1425 segments->start = rest.start; 1426 1427 rest.length -= segments->length + 1; 1428 rest.start = p + 1; 1429 1430 } else { 1431 n = 0; 1432 *segments = rest; 1433 } 1434 1435 if (segments->length == 0) { 1436 return NXT_DECLINED; 1437 } 1438 1439 p = nxt_decode_uri(segments->start, segments->start, segments->length); 1440 if (p == NULL) { 1441 return NXT_DECLINED; 1442 } 1443 1444 segments->length = p - segments->start; 1445 segments++; 1446 1447 } while (n); 1448 1449 return NXT_OK; 1450 } 1451 1452 1453 static nxt_int_t 1454 nxt_http_route_find(nxt_http_routes_t *routes, nxt_str_t *name, 1455 nxt_http_action_t *action) 1456 { 1457 nxt_http_route_t **route, **end; 1458 1459 if (routes == NULL) { 1460 return NXT_DECLINED; 1461 } 1462 1463 route = &routes->route[0]; 1464 end = route + routes->items; 1465 1466 while (route < end) { 1467 if (nxt_strstr_eq(&(*route)->name, name)) { 1468 action->u.route = *route; 1469 action->handler = nxt_http_route_handler; 1470 1471 return NXT_OK; 1472 } 1473 1474 route++; 1475 } 1476 1477 return NXT_DECLINED; 1478 } 1479 1480 1481 nxt_http_action_t * 1482 nxt_http_action_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 1483 nxt_str_t *pass) 1484 { 1485 nxt_mp_t *mp; 1486 nxt_int_t ret; 1487 nxt_http_action_t *action; 1488 1489 mp = tmcf->router_conf->mem_pool; 1490 1491 action = nxt_mp_alloc(mp, sizeof(nxt_http_action_t)); 1492 if (nxt_slow_path(action == NULL)) { 1493 return NULL; 1494 } 1495 1496 action->u.var = nxt_var_compile(pass, mp, 0); 1497 if (nxt_slow_path(action->u.var == NULL)) { 1498 return NULL; 1499 } 1500 1501 action->handler = NULL; 1502 1503 ret = nxt_http_action_resolve(task, tmcf, action); 1504 if (nxt_slow_path(ret != NXT_OK)) { 1505 return NULL; 1506 } 1507 1508 return action; 1509 } 1510 1511 1512 /* COMPATIBILITY: listener application. */ 1513 1514 nxt_http_action_t * 1515 nxt_http_pass_application(nxt_task_t *task, nxt_router_conf_t *rtcf, 1516 nxt_str_t *name) 1517 { 1518 nxt_http_action_t *action; 1519 1520 action = nxt_mp_alloc(rtcf->mem_pool, sizeof(nxt_http_action_t)); 1521 if (nxt_slow_path(action == NULL)) { 1522 return NULL; 1523 } 1524 1525 (void) nxt_router_application_init(rtcf, name, NULL, action); 1526 1527 return action; 1528 } 1529 1530 1531 static nxt_http_action_t * 1532 nxt_http_route_handler(nxt_task_t *task, nxt_http_request_t *r, 1533 nxt_http_action_t *start) 1534 { 1535 nxt_http_route_t *route; 1536 nxt_http_action_t *action; 1537 nxt_http_route_match_t **match, **end; 1538 1539 route = start->u.route; 1540 match = &route->match[0]; 1541 end = match + route->items; 1542 1543 while (match < end) { 1544 action = nxt_http_route_match(task, r, *match); 1545 if (action != NULL) { 1546 return action; 1547 } 1548 1549 match++; 1550 } 1551 1552 nxt_http_request_error(task, r, NXT_HTTP_NOT_FOUND); 1553 1554 return NULL; 1555 } 1556 1557 1558 static nxt_http_action_t * 1559 nxt_http_route_match(nxt_task_t *task, nxt_http_request_t *r, 1560 nxt_http_route_match_t *match) 1561 { 1562 nxt_int_t ret; 1563 nxt_http_route_test_t *test, *end; 1564 1565 test = &match->test[0]; 1566 end = test + match->items; 1567 1568 while (test < end) { 1569 switch (test->rule->object) { 1570 case NXT_HTTP_ROUTE_TABLE: 1571 ret = nxt_http_route_table(r, test->table); 1572 break; 1573 case NXT_HTTP_ROUTE_SOURCE: 1574 ret = nxt_http_route_addr_rule(r, test->addr_rule, r->remote); 1575 break; 1576 case NXT_HTTP_ROUTE_DESTINATION: 1577 if (r->local == NULL && nxt_fast_path(r->proto.any != NULL)) { 1578 nxt_http_proto[r->protocol].local_addr(task, r); 1579 } 1580 1581 ret = nxt_http_route_addr_rule(r, test->addr_rule, r->local); 1582 break; 1583 default: 1584 ret = nxt_http_route_rule(r, test->rule); 1585 break; 1586 } 1587 1588 if (ret <= 0) { 1589 /* 0 => NULL, -1 => NXT_HTTP_ACTION_ERROR. */ 1590 return (nxt_http_action_t *) (intptr_t) ret; 1591 } 1592 1593 test++; 1594 } 1595 1596 return &match->action; 1597 } 1598 1599 1600 static nxt_int_t 1601 nxt_http_route_table(nxt_http_request_t *r, nxt_http_route_table_t *table) 1602 { 1603 nxt_int_t ret; 1604 nxt_http_route_ruleset_t **ruleset, **end; 1605 1606 ret = 1; 1607 ruleset = &table->ruleset[0]; 1608 end = ruleset + table->items; 1609 1610 while (ruleset < end) { 1611 ret = nxt_http_route_ruleset(r, *ruleset); 1612 1613 if (ret != 0) { 1614 return ret; 1615 } 1616 1617 ruleset++; 1618 } 1619 1620 return ret; 1621 } 1622 1623 1624 static nxt_int_t 1625 nxt_http_route_ruleset(nxt_http_request_t *r, nxt_http_route_ruleset_t *ruleset) 1626 { 1627 nxt_int_t ret; 1628 nxt_http_route_rule_t **rule, **end; 1629 1630 rule = &ruleset->rule[0]; 1631 end = rule + ruleset->items; 1632 1633 while (rule < end) { 1634 ret = nxt_http_route_rule(r, *rule); 1635 1636 if (ret <= 0) { 1637 return ret; 1638 } 1639 1640 rule++; 1641 } 1642 1643 return 1; 1644 } 1645 1646 1647 static nxt_int_t 1648 nxt_http_route_rule(nxt_http_request_t *r, nxt_http_route_rule_t *rule) 1649 { 1650 void *p, **pp; 1651 u_char *start; 1652 size_t length; 1653 nxt_str_t *s; 1654 1655 switch (rule->object) { 1656 1657 case NXT_HTTP_ROUTE_HEADER: 1658 return nxt_http_route_header(r, rule); 1659 1660 case NXT_HTTP_ROUTE_ARGUMENT: 1661 return nxt_http_route_arguments(r, rule); 1662 1663 case NXT_HTTP_ROUTE_COOKIE: 1664 return nxt_http_route_cookies(r, rule); 1665 1666 case NXT_HTTP_ROUTE_SCHEME: 1667 return nxt_http_route_scheme(r, rule); 1668 1669 case NXT_HTTP_ROUTE_QUERY: 1670 return nxt_http_route_query(r, rule); 1671 1672 default: 1673 break; 1674 } 1675 1676 p = nxt_pointer_to(r, rule->u.offset); 1677 1678 if (rule->object == NXT_HTTP_ROUTE_STRING) { 1679 s = p; 1680 1681 } else { 1682 /* NXT_HTTP_ROUTE_STRING_PTR */ 1683 pp = p; 1684 s = *pp; 1685 1686 if (s == NULL) { 1687 return 0; 1688 } 1689 } 1690 1691 length = s->length; 1692 start = s->start; 1693 1694 return nxt_http_route_test_rule(r, rule, start, length); 1695 } 1696 1697 1698 static nxt_int_t 1699 nxt_http_route_addr_pattern_match(nxt_http_route_addr_pattern_t *p, 1700 nxt_sockaddr_t *sa) 1701 { 1702 #if (NXT_INET6) 1703 uint32_t i; 1704 #endif 1705 in_port_t in_port; 1706 nxt_int_t match; 1707 struct sockaddr_in *sin; 1708 #if (NXT_INET6) 1709 struct sockaddr_in6 *sin6; 1710 #endif 1711 nxt_http_route_addr_base_t *base; 1712 1713 base = &p->base; 1714 1715 switch (sa->u.sockaddr.sa_family) { 1716 1717 case AF_INET: 1718 1719 match = (base->addr_family == AF_INET 1720 || base->addr_family == AF_UNSPEC); 1721 if (!match) { 1722 break; 1723 } 1724 1725 sin = &sa->u.sockaddr_in; 1726 in_port = ntohs(sin->sin_port); 1727 1728 match = (in_port >= base->port.start && in_port <= base->port.end); 1729 if (!match) { 1730 break; 1731 } 1732 1733 switch (base->match_type) { 1734 1735 case NXT_HTTP_ROUTE_ADDR_ANY: 1736 break; 1737 1738 case NXT_HTTP_ROUTE_ADDR_EXACT: 1739 match = (nxt_memcmp(&sin->sin_addr, &p->addr.v4.start, 1740 sizeof(struct in_addr)) 1741 == 0); 1742 break; 1743 1744 case NXT_HTTP_ROUTE_ADDR_RANGE: 1745 match = (nxt_memcmp(&sin->sin_addr, &p->addr.v4.start, 1746 sizeof(struct in_addr)) >= 0 1747 && nxt_memcmp(&sin->sin_addr, &p->addr.v4.end, 1748 sizeof(struct in_addr)) <= 0); 1749 break; 1750 1751 case NXT_HTTP_ROUTE_ADDR_CIDR: 1752 match = ((sin->sin_addr.s_addr & p->addr.v4.end) 1753 == p->addr.v4.start); 1754 break; 1755 1756 default: 1757 nxt_unreachable(); 1758 } 1759 1760 break; 1761 1762 #if (NXT_INET6) 1763 case AF_INET6: 1764 1765 match = (base->addr_family == AF_INET6 1766 || base->addr_family == AF_UNSPEC); 1767 if (!match) { 1768 break; 1769 } 1770 1771 sin6 = &sa->u.sockaddr_in6; 1772 in_port = ntohs(sin6->sin6_port); 1773 1774 match = (in_port >= base->port.start && in_port <= base->port.end); 1775 if (!match) { 1776 break; 1777 } 1778 1779 switch (base->match_type) { 1780 1781 case NXT_HTTP_ROUTE_ADDR_ANY: 1782 break; 1783 1784 case NXT_HTTP_ROUTE_ADDR_EXACT: 1785 match = (nxt_memcmp(&sin6->sin6_addr, &p->addr.v6.start, 1786 sizeof(struct in6_addr)) 1787 == 0); 1788 break; 1789 1790 case NXT_HTTP_ROUTE_ADDR_RANGE: 1791 match = (nxt_memcmp(&sin6->sin6_addr, &p->addr.v6.start, 1792 sizeof(struct in6_addr)) >= 0 1793 && nxt_memcmp(&sin6->sin6_addr, &p->addr.v6.end, 1794 sizeof(struct in6_addr)) <= 0); 1795 break; 1796 1797 case NXT_HTTP_ROUTE_ADDR_CIDR: 1798 for (i = 0; i < 16; i++) { 1799 match = ((sin6->sin6_addr.s6_addr[i] 1800 & p->addr.v6.end.s6_addr[i]) 1801 == p->addr.v6.start.s6_addr[i]); 1802 1803 if (!match) { 1804 break; 1805 } 1806 } 1807 1808 break; 1809 1810 default: 1811 nxt_unreachable(); 1812 } 1813 1814 break; 1815 #endif 1816 1817 default: 1818 match = 0; 1819 break; 1820 } 1821 1822 return match ^ base->negative; 1823 } 1824 1825 1826 nxt_int_t 1827 nxt_http_route_addr_rule(nxt_http_request_t *r, 1828 nxt_http_route_addr_rule_t *addr_rule, nxt_sockaddr_t *sa) 1829 { 1830 uint32_t n; 1831 nxt_bool_t matches; 1832 nxt_http_route_addr_pattern_t *p; 1833 1834 n = addr_rule->items; 1835 1836 if (n == 0) { 1837 return 0; 1838 } 1839 1840 p = &addr_rule->addr_pattern[0] - 1; 1841 1842 do { 1843 p++; 1844 n--; 1845 1846 matches = nxt_http_route_addr_pattern_match(p, sa); 1847 1848 if (p->base.negative) { 1849 if (matches) { 1850 continue; 1851 } 1852 1853 return 0; 1854 } 1855 1856 if (matches) { 1857 return 1; 1858 } 1859 1860 } while (n > 0); 1861 1862 return p->base.negative; 1863 } 1864 1865 1866 static nxt_int_t 1867 nxt_http_route_header(nxt_http_request_t *r, nxt_http_route_rule_t *rule) 1868 { 1869 nxt_int_t ret; 1870 nxt_http_field_t *f; 1871 1872 ret = 0; 1873 1874 nxt_list_each(f, r->fields) { 1875 1876 if (rule->u.name.hash != f->hash 1877 || rule->u.name.length != f->name_length 1878 || nxt_strncasecmp(rule->u.name.start, f->name, f->name_length) 1879 != 0) 1880 { 1881 continue; 1882 } 1883 1884 ret = nxt_http_route_test_rule(r, rule, f->value, f->value_length); 1885 if (nxt_slow_path(ret == NXT_ERROR)) { 1886 return NXT_ERROR; 1887 } 1888 1889 if (ret == 0) { 1890 return ret; 1891 } 1892 1893 } nxt_list_loop; 1894 1895 return ret; 1896 } 1897 1898 1899 static nxt_int_t 1900 nxt_http_route_arguments(nxt_http_request_t *r, nxt_http_route_rule_t *rule) 1901 { 1902 nxt_array_t *arguments; 1903 1904 arguments = nxt_http_arguments_parse(r); 1905 if (nxt_slow_path(arguments == NULL)) { 1906 return -1; 1907 } 1908 1909 return nxt_http_route_test_argument(r, rule, arguments); 1910 } 1911 1912 1913 static nxt_int_t 1914 nxt_http_route_test_argument(nxt_http_request_t *r, 1915 nxt_http_route_rule_t *rule, nxt_array_t *array) 1916 { 1917 nxt_int_t ret; 1918 nxt_http_name_value_t *nv, *end; 1919 1920 ret = 0; 1921 1922 nv = array->elts; 1923 end = nv + array->nelts; 1924 1925 while (nv < end) { 1926 1927 if (rule->u.name.hash == nv->hash 1928 && rule->u.name.length == nv->name_length 1929 && nxt_memcmp(rule->u.name.start, nv->name, nv->name_length) == 0) 1930 { 1931 ret = nxt_http_route_test_rule(r, rule, nv->value, 1932 nv->value_length); 1933 if (nxt_slow_path(ret == NXT_ERROR)) { 1934 return NXT_ERROR; 1935 } 1936 1937 if (ret == 0) { 1938 break; 1939 } 1940 } 1941 1942 nv++; 1943 } 1944 1945 return ret; 1946 } 1947 1948 1949 static nxt_int_t 1950 nxt_http_route_scheme(nxt_http_request_t *r, nxt_http_route_rule_t *rule) 1951 { 1952 nxt_bool_t tls, https; 1953 nxt_http_route_pattern_slice_t *pattern_slice; 1954 1955 pattern_slice = rule->pattern[0].u.pattern_slices->elts; 1956 https = (pattern_slice->length == nxt_length("https")); 1957 tls = (r->tls != NULL); 1958 1959 return (tls == https); 1960 } 1961 1962 1963 static nxt_int_t 1964 nxt_http_route_query(nxt_http_request_t *r, nxt_http_route_rule_t *rule) 1965 { 1966 nxt_array_t *arguments; 1967 1968 arguments = nxt_http_arguments_parse(r); 1969 if (nxt_slow_path(arguments == NULL)) { 1970 return -1; 1971 } 1972 1973 return nxt_http_route_test_rule(r, rule, r->args_decoded.start, 1974 r->args_decoded.length); 1975 } 1976 1977 1978 static nxt_int_t 1979 nxt_http_route_cookies(nxt_http_request_t *r, nxt_http_route_rule_t *rule) 1980 { 1981 nxt_array_t *cookies; 1982 1983 cookies = nxt_http_cookies_parse(r); 1984 if (nxt_slow_path(cookies == NULL)) { 1985 return -1; 1986 } 1987 1988 return nxt_http_route_test_cookie(r, rule, cookies); 1989 } 1990 1991 1992 static nxt_int_t 1993 nxt_http_route_test_cookie(nxt_http_request_t *r, 1994 nxt_http_route_rule_t *rule, nxt_array_t *array) 1995 { 1996 nxt_int_t ret; 1997 nxt_http_name_value_t *nv, *end; 1998 1999 ret = 0; 2000 2001 nv = array->elts; 2002 end = nv + array->nelts; 2003 2004 while (nv < end) { 2005 2006 if (rule->u.name.hash == nv->hash 2007 && rule->u.name.length == nv->name_length 2008 && nxt_memcmp(rule->u.name.start, nv->name, nv->name_length) == 0) 2009 { 2010 ret = nxt_http_route_test_rule(r, rule, nv->value, 2011 nv->value_length); 2012 if (nxt_slow_path(ret == NXT_ERROR)) { 2013 return NXT_ERROR; 2014 } 2015 2016 if (ret == 0) { 2017 break; 2018 } 2019 } 2020 2021 nv++; 2022 } 2023 2024 return ret; 2025 } 2026 2027 2028 nxt_int_t 2029 nxt_http_route_test_rule(nxt_http_request_t *r, nxt_http_route_rule_t *rule, 2030 u_char *start, size_t length) 2031 { 2032 nxt_int_t ret; 2033 nxt_http_route_pattern_t *pattern, *end; 2034 2035 ret = 1; 2036 pattern = &rule->pattern[0]; 2037 end = pattern + rule->items; 2038 2039 while (pattern < end) { 2040 ret = nxt_http_route_pattern(r, pattern, start, length); 2041 if (nxt_slow_path(ret == NXT_ERROR)) { 2042 return NXT_ERROR; 2043 } 2044 2045 /* nxt_http_route_pattern() returns either 1 or 0. */ 2046 ret ^= pattern->negative; 2047 2048 if (pattern->any == ret) { 2049 return ret; 2050 } 2051 2052 pattern++; 2053 } 2054 2055 return ret; 2056 } 2057 2058 2059 static nxt_int_t 2060 nxt_http_route_pattern(nxt_http_request_t *r, nxt_http_route_pattern_t *pattern, 2061 u_char *start, size_t length) 2062 { 2063 u_char *p, *end, *test; 2064 size_t test_length; 2065 uint32_t i; 2066 nxt_array_t *pattern_slices; 2067 nxt_http_route_pattern_slice_t *pattern_slice; 2068 2069 #if (NXT_HAVE_REGEX) 2070 if (pattern->regex) { 2071 if (r->regex_match == NULL) { 2072 r->regex_match = nxt_regex_match_create(r->mem_pool, 0); 2073 if (nxt_slow_path(r->regex_match == NULL)) { 2074 return NXT_ERROR; 2075 } 2076 } 2077 2078 return nxt_regex_match(pattern->u.regex, start, length, r->regex_match); 2079 } 2080 #endif 2081 2082 if (length < pattern->min_length) { 2083 return 0; 2084 } 2085 2086 nxt_assert(pattern->u.pattern_slices != NULL); 2087 2088 pattern_slices = pattern->u.pattern_slices; 2089 pattern_slice = pattern_slices->elts; 2090 end = start + length; 2091 2092 for (i = 0; i < pattern_slices->nelts; i++, pattern_slice++) { 2093 test = pattern_slice->start; 2094 test_length = pattern_slice->length; 2095 2096 switch (pattern_slice->type) { 2097 case NXT_HTTP_ROUTE_PATTERN_EXACT: 2098 return ((length == pattern->min_length) && 2099 nxt_http_route_memcmp(start, test, test_length, 2100 pattern->case_sensitive)); 2101 2102 case NXT_HTTP_ROUTE_PATTERN_BEGIN: 2103 if (nxt_http_route_memcmp(start, test, test_length, 2104 pattern->case_sensitive)) 2105 { 2106 start += test_length; 2107 break; 2108 } 2109 2110 return 0; 2111 2112 case NXT_HTTP_ROUTE_PATTERN_END: 2113 p = end - test_length; 2114 2115 if (nxt_http_route_memcmp(p, test, test_length, 2116 pattern->case_sensitive)) 2117 { 2118 end = p; 2119 break; 2120 } 2121 2122 return 0; 2123 2124 case NXT_HTTP_ROUTE_PATTERN_SUBSTRING: 2125 if (pattern->case_sensitive) { 2126 p = nxt_memstrn(start, end, (char *) test, test_length); 2127 2128 } else { 2129 p = nxt_memcasestrn(start, end, (char *) test, test_length); 2130 } 2131 2132 if (p == NULL) { 2133 return 0; 2134 } 2135 2136 start = p + test_length; 2137 } 2138 } 2139 2140 return 1; 2141 } 2142 2143 2144 static nxt_int_t 2145 nxt_http_route_memcmp(u_char *start, u_char *test, size_t test_length, 2146 nxt_bool_t case_sensitive) 2147 { 2148 nxt_int_t n; 2149 2150 if (case_sensitive) { 2151 n = nxt_memcmp(start, test, test_length); 2152 2153 } else { 2154 n = nxt_memcasecmp(start, test, test_length); 2155 } 2156 2157 return (n == 0); 2158 } 2159