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