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