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("proxy"), 631 NXT_CONF_MAP_PTR, 632 offsetof(nxt_http_route_action_conf_t, proxy) 633 }, 634 { 635 nxt_string("share"), 636 NXT_CONF_MAP_PTR, 637 offsetof(nxt_http_route_action_conf_t, share) 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 if (accf.share != NULL) { 704 conf = accf.share; 705 706 } else if (accf.proxy != NULL) { 707 conf = accf.proxy; 708 709 } else { 710 conf = accf.pass; 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.share != NULL) { 721 action->handler = nxt_http_static_handler; 722 723 if (accf.fallback != NULL) { 724 action->u.share.fallback = nxt_mp_alloc(mp, 725 sizeof(nxt_http_action_t)); 726 if (nxt_slow_path(action->u.share.fallback == NULL)) { 727 return NXT_ERROR; 728 } 729 730 return nxt_http_route_action_create(tmcf, accf.fallback, 731 action->u.share.fallback); 732 } 733 734 return NXT_OK; 735 } 736 737 if (accf.proxy != NULL) { 738 return nxt_http_proxy_create(mp, action); 739 } 740 741 return NXT_OK; 742 } 743 744 745 static nxt_http_route_table_t * 746 nxt_http_route_table_create(nxt_task_t *task, nxt_mp_t *mp, 747 nxt_conf_value_t *table_cv, nxt_http_route_object_t object, 748 nxt_bool_t case_sensitive, nxt_http_route_encoding_t encoding) 749 { 750 size_t size; 751 uint32_t i, n; 752 nxt_bool_t array; 753 nxt_conf_value_t *ruleset_cv; 754 nxt_http_route_table_t *table; 755 nxt_http_route_ruleset_t *ruleset; 756 757 array = (nxt_conf_type(table_cv) == NXT_CONF_ARRAY); 758 n = array ? nxt_conf_array_elements_count(table_cv) : 1; 759 size = sizeof(nxt_http_route_table_t) 760 + n * sizeof(nxt_http_route_ruleset_t *); 761 762 table = nxt_mp_alloc(mp, size); 763 if (nxt_slow_path(table == NULL)) { 764 return NULL; 765 } 766 767 table->items = n; 768 table->object = NXT_HTTP_ROUTE_TABLE; 769 770 if (!array) { 771 ruleset = nxt_http_route_ruleset_create(task, mp, table_cv, object, 772 case_sensitive, encoding); 773 if (nxt_slow_path(ruleset == NULL)) { 774 return NULL; 775 } 776 777 table->ruleset[0] = ruleset; 778 779 return table; 780 } 781 782 for (i = 0; i < n; i++) { 783 ruleset_cv = nxt_conf_get_array_element(table_cv, i); 784 785 ruleset = nxt_http_route_ruleset_create(task, mp, ruleset_cv, object, 786 case_sensitive, encoding); 787 if (nxt_slow_path(ruleset == NULL)) { 788 return NULL; 789 } 790 791 table->ruleset[i] = ruleset; 792 } 793 794 return table; 795 } 796 797 798 static nxt_http_route_ruleset_t * 799 nxt_http_route_ruleset_create(nxt_task_t *task, nxt_mp_t *mp, 800 nxt_conf_value_t *ruleset_cv, nxt_http_route_object_t object, 801 nxt_bool_t case_sensitive, nxt_http_route_encoding_t encoding) 802 { 803 size_t size; 804 uint32_t i, n, next; 805 nxt_str_t name; 806 nxt_conf_value_t *rule_cv; 807 nxt_http_route_rule_t *rule; 808 nxt_http_route_ruleset_t *ruleset; 809 810 n = nxt_conf_object_members_count(ruleset_cv); 811 size = sizeof(nxt_http_route_ruleset_t) 812 + n * sizeof(nxt_http_route_rule_t *); 813 814 ruleset = nxt_mp_alloc(mp, size); 815 if (nxt_slow_path(ruleset == NULL)) { 816 return NULL; 817 } 818 819 ruleset->items = n; 820 821 next = 0; 822 823 /* 824 * A workaround for GCC 10 with -flto -O2 flags that warns about "name" 825 * may be uninitialized in nxt_http_route_rule_name_create(). 826 */ 827 nxt_str_null(&name); 828 829 for (i = 0; i < n; i++) { 830 rule_cv = nxt_conf_next_object_member(ruleset_cv, &name, &next); 831 832 rule = nxt_http_route_rule_name_create(task, mp, rule_cv, &name, 833 case_sensitive, encoding); 834 if (nxt_slow_path(rule == NULL)) { 835 return NULL; 836 } 837 838 rule->object = object; 839 ruleset->rule[i] = rule; 840 } 841 842 return ruleset; 843 } 844 845 846 static nxt_http_route_rule_t * 847 nxt_http_route_rule_name_create(nxt_task_t *task, nxt_mp_t *mp, 848 nxt_conf_value_t *rule_cv, nxt_str_t *name, nxt_bool_t case_sensitive, 849 nxt_http_route_encoding_t encoding) 850 { 851 u_char c, *p, *src, *start, *end, plus; 852 uint8_t d0, d1; 853 uint32_t hash; 854 nxt_uint_t i; 855 nxt_http_route_rule_t *rule; 856 857 rule = nxt_http_route_rule_create(task, mp, rule_cv, case_sensitive, 858 NXT_HTTP_ROUTE_PATTERN_NOCASE, 859 encoding); 860 if (nxt_slow_path(rule == NULL)) { 861 return NULL; 862 } 863 864 rule->u.name.length = name->length; 865 866 p = nxt_mp_nget(mp, name->length); 867 if (nxt_slow_path(p == NULL)) { 868 return NULL; 869 } 870 871 hash = NXT_HTTP_FIELD_HASH_INIT; 872 rule->u.name.start = p; 873 874 if (encoding == NXT_HTTP_ROUTE_ENCODING_NONE) { 875 for (i = 0; i < name->length; i++) { 876 c = name->start[i]; 877 *p++ = c; 878 879 c = case_sensitive ? c : nxt_lowcase(c); 880 hash = nxt_http_field_hash_char(hash, c); 881 } 882 883 goto end; 884 } 885 886 plus = (encoding == NXT_HTTP_ROUTE_ENCODING_URI_PLUS) ? ' ' : '+'; 887 888 start = name->start; 889 end = start + name->length; 890 891 for (src = start; src < end; src++) { 892 c = *src; 893 894 switch (c) { 895 case '%': 896 if (nxt_slow_path(end - src <= 2)) { 897 return NULL; 898 } 899 900 d0 = nxt_hex2int[src[1]]; 901 d1 = nxt_hex2int[src[2]]; 902 src += 2; 903 904 if (nxt_slow_path((d0 | d1) >= 16)) { 905 return NULL; 906 } 907 908 c = (d0 << 4) + d1; 909 *p++ = c; 910 break; 911 912 case '+': 913 c = plus; 914 *p++ = c; 915 break; 916 917 default: 918 *p++ = c; 919 break; 920 } 921 922 c = case_sensitive ? c : nxt_lowcase(c); 923 hash = nxt_http_field_hash_char(hash, c); 924 } 925 926 rule->u.name.length = p - rule->u.name.start; 927 928 end: 929 930 rule->u.name.hash = nxt_http_field_hash_end(hash) & 0xFFFF; 931 932 return rule; 933 } 934 935 936 static nxt_http_route_rule_t * 937 nxt_http_route_rule_create(nxt_task_t *task, nxt_mp_t *mp, 938 nxt_conf_value_t *cv, nxt_bool_t case_sensitive, 939 nxt_http_route_pattern_case_t pattern_case, 940 nxt_http_route_encoding_t encoding) 941 { 942 size_t size; 943 uint32_t i, n; 944 nxt_int_t ret; 945 nxt_bool_t string; 946 nxt_conf_value_t *value; 947 nxt_http_route_rule_t *rule; 948 nxt_http_route_pattern_t *pattern; 949 950 string = (nxt_conf_type(cv) != NXT_CONF_ARRAY); 951 n = string ? 1 : nxt_conf_array_elements_count(cv); 952 size = sizeof(nxt_http_route_rule_t) + n * sizeof(nxt_http_route_pattern_t); 953 954 rule = nxt_mp_alloc(mp, size); 955 if (nxt_slow_path(rule == NULL)) { 956 return NULL; 957 } 958 959 rule->items = n; 960 961 pattern = &rule->pattern[0]; 962 963 if (string) { 964 pattern[0].case_sensitive = case_sensitive; 965 ret = nxt_http_route_pattern_create(task, mp, cv, &pattern[0], 966 pattern_case, encoding); 967 if (nxt_slow_path(ret != NXT_OK)) { 968 return NULL; 969 } 970 971 return rule; 972 } 973 974 nxt_conf_array_qsort(cv, nxt_http_pattern_compare); 975 976 for (i = 0; i < n; i++) { 977 pattern[i].case_sensitive = case_sensitive; 978 value = nxt_conf_get_array_element(cv, i); 979 980 ret = nxt_http_route_pattern_create(task, mp, value, &pattern[i], 981 pattern_case, encoding); 982 if (nxt_slow_path(ret != NXT_OK)) { 983 return NULL; 984 } 985 } 986 987 return rule; 988 } 989 990 991 static nxt_http_route_addr_rule_t * 992 nxt_http_route_addr_rule_create(nxt_task_t *task, nxt_mp_t *mp, 993 nxt_conf_value_t *cv) 994 { 995 size_t size; 996 uint32_t i, n; 997 nxt_bool_t array; 998 nxt_conf_value_t *value; 999 nxt_http_route_addr_rule_t *addr_rule; 1000 nxt_http_route_addr_pattern_t *pattern; 1001 1002 array = (nxt_conf_type(cv) == NXT_CONF_ARRAY); 1003 n = array ? nxt_conf_array_elements_count(cv) : 1; 1004 1005 size = sizeof(nxt_http_route_addr_rule_t) 1006 + n * sizeof(nxt_http_route_addr_pattern_t); 1007 1008 addr_rule = nxt_mp_alloc(mp, size); 1009 if (nxt_slow_path(addr_rule == NULL)) { 1010 return NULL; 1011 } 1012 1013 addr_rule->items = n; 1014 1015 if (!array) { 1016 pattern = &addr_rule->addr_pattern[0]; 1017 1018 if (nxt_http_route_addr_pattern_parse(mp, pattern, cv) != NXT_OK) { 1019 return NULL; 1020 } 1021 1022 return addr_rule; 1023 } 1024 1025 for (i = 0; i < n; i++) { 1026 pattern = &addr_rule->addr_pattern[i]; 1027 value = nxt_conf_get_array_element(cv, i); 1028 1029 if (nxt_http_route_addr_pattern_parse(mp, pattern, value) != NXT_OK) { 1030 return NULL; 1031 } 1032 } 1033 1034 if (n > 1) { 1035 nxt_qsort(addr_rule->addr_pattern, addr_rule->items, 1036 sizeof(nxt_http_route_addr_pattern_t), 1037 nxt_http_addr_pattern_compare); 1038 } 1039 1040 return addr_rule; 1041 } 1042 1043 1044 static int 1045 nxt_http_pattern_compare(const void *one, const void *two) 1046 { 1047 nxt_str_t test; 1048 nxt_bool_t negative1, negative2; 1049 nxt_conf_value_t *value; 1050 1051 value = (nxt_conf_value_t *) one; 1052 nxt_conf_get_string(value, &test); 1053 negative1 = (test.length != 0 && test.start[0] == '!'); 1054 1055 value = (nxt_conf_value_t *) two; 1056 nxt_conf_get_string(value, &test); 1057 negative2 = (test.length != 0 && test.start[0] == '!'); 1058 1059 return (negative2 - negative1); 1060 } 1061 1062 1063 static int 1064 nxt_http_addr_pattern_compare(const void *one, const void *two) 1065 { 1066 const nxt_http_route_addr_pattern_t *p1, *p2; 1067 1068 p1 = one; 1069 p2 = two; 1070 1071 return (p2->base.negative - p1->base.negative); 1072 } 1073 1074 1075 static nxt_int_t 1076 nxt_http_route_pattern_create(nxt_task_t *task, nxt_mp_t *mp, 1077 nxt_conf_value_t *cv, nxt_http_route_pattern_t *pattern, 1078 nxt_http_route_pattern_case_t pattern_case, 1079 nxt_http_route_encoding_t encoding) 1080 { 1081 u_char c, *p, *end; 1082 nxt_str_t test, tmp; 1083 nxt_int_t ret; 1084 nxt_array_t *slices; 1085 #if (NXT_HAVE_REGEX) 1086 nxt_regex_t *re; 1087 nxt_regex_err_t err; 1088 #endif 1089 nxt_http_route_pattern_type_t type; 1090 nxt_http_route_pattern_slice_t *slice; 1091 1092 type = NXT_HTTP_ROUTE_PATTERN_EXACT; 1093 1094 nxt_conf_get_string(cv, &test); 1095 1096 pattern->u.pattern_slices = NULL; 1097 pattern->negative = 0; 1098 pattern->any = 1; 1099 pattern->min_length = 0; 1100 #if (NXT_HAVE_REGEX) 1101 pattern->regex = 0; 1102 #endif 1103 1104 if (test.length != 0 && test.start[0] == '!') { 1105 test.start++; 1106 test.length--; 1107 1108 pattern->negative = 1; 1109 pattern->any = 0; 1110 } 1111 1112 if (test.length > 0 && test.start[0] == '~') { 1113 #if (NXT_HAVE_REGEX) 1114 test.start++; 1115 test.length--; 1116 1117 re = nxt_regex_compile(mp, &test, &err); 1118 if (nxt_slow_path(re == NULL)) { 1119 if (err.offset < test.length) { 1120 nxt_alert(task, "nxt_regex_compile(%V) failed: %s at offset %d", 1121 &test, err.msg, (int) err.offset); 1122 return NXT_ERROR; 1123 } 1124 1125 nxt_alert(task, "nxt_regex_compile(%V) failed %s", &test, err.msg); 1126 1127 return NXT_ERROR; 1128 } 1129 1130 pattern->u.regex = re; 1131 pattern->regex = 1; 1132 1133 return NXT_OK; 1134 1135 #else 1136 return NXT_ERROR; 1137 #endif 1138 } 1139 1140 slices = nxt_array_create(mp, 1, sizeof(nxt_http_route_pattern_slice_t)); 1141 if (nxt_slow_path(slices == NULL)) { 1142 return NXT_ERROR; 1143 } 1144 1145 pattern->u.pattern_slices = slices; 1146 1147 if (test.length == 0) { 1148 slice = nxt_array_add(slices); 1149 if (nxt_slow_path(slice == NULL)) { 1150 return NXT_ERROR; 1151 } 1152 1153 slice->type = NXT_HTTP_ROUTE_PATTERN_EXACT; 1154 slice->start = NULL; 1155 slice->length = 0; 1156 1157 return NXT_OK; 1158 } 1159 1160 if (test.start[0] == '*') { 1161 /* 'type' is no longer 'EXACT', assume 'END'. */ 1162 type = NXT_HTTP_ROUTE_PATTERN_END; 1163 test.start++; 1164 test.length--; 1165 } 1166 1167 if (type == NXT_HTTP_ROUTE_PATTERN_EXACT) { 1168 tmp.start = test.start; 1169 1170 p = nxt_memchr(test.start, '*', test.length); 1171 1172 if (p == NULL) { 1173 /* No '*' found - EXACT pattern. */ 1174 tmp.length = test.length; 1175 type = NXT_HTTP_ROUTE_PATTERN_EXACT; 1176 1177 test.start += test.length; 1178 test.length = 0; 1179 1180 } else { 1181 /* '*' found - BEGIN pattern. */ 1182 tmp.length = p - test.start; 1183 type = NXT_HTTP_ROUTE_PATTERN_BEGIN; 1184 1185 test.start = p + 1; 1186 test.length -= tmp.length + 1; 1187 } 1188 1189 ret = nxt_http_route_pattern_slice(slices, &tmp, type, encoding, 1190 pattern_case); 1191 if (nxt_slow_path(ret != NXT_OK)) { 1192 return ret; 1193 } 1194 1195 pattern->min_length += tmp.length; 1196 } 1197 1198 end = test.start + test.length; 1199 1200 if (test.length != 0 && end[-1] != '*') { 1201 p = end - 1; 1202 1203 while (p != test.start) { 1204 c = *p--; 1205 1206 if (c == '*') { 1207 p += 2; 1208 break; 1209 } 1210 } 1211 1212 tmp.start = p; 1213 tmp.length = end - p; 1214 1215 test.length -= tmp.length; 1216 end = p; 1217 1218 ret = nxt_http_route_pattern_slice(slices, &tmp, 1219 NXT_HTTP_ROUTE_PATTERN_END, 1220 encoding, pattern_case); 1221 if (nxt_slow_path(ret != NXT_OK)) { 1222 return ret; 1223 } 1224 1225 pattern->min_length += tmp.length; 1226 } 1227 1228 tmp.start = test.start; 1229 tmp.length = 0; 1230 1231 p = tmp.start; 1232 1233 while (p != end) { 1234 c = *p++; 1235 1236 if (c != '*') { 1237 tmp.length++; 1238 continue; 1239 } 1240 1241 if (tmp.length == 0) { 1242 tmp.start = p; 1243 continue; 1244 } 1245 1246 ret = nxt_http_route_pattern_slice(slices, &tmp, 1247 NXT_HTTP_ROUTE_PATTERN_SUBSTRING, 1248 encoding, pattern_case); 1249 if (nxt_slow_path(ret != NXT_OK)) { 1250 return ret; 1251 } 1252 1253 pattern->min_length += tmp.length; 1254 1255 tmp.start = p; 1256 tmp.length = 0; 1257 } 1258 1259 if (tmp.length != 0) { 1260 ret = nxt_http_route_pattern_slice(slices, &tmp, 1261 NXT_HTTP_ROUTE_PATTERN_SUBSTRING, 1262 encoding, pattern_case); 1263 if (nxt_slow_path(ret != NXT_OK)) { 1264 return ret; 1265 } 1266 1267 pattern->min_length += tmp.length; 1268 } 1269 1270 return NXT_OK; 1271 } 1272 1273 1274 static nxt_int_t 1275 nxt_http_route_decode_str(nxt_str_t *str, nxt_http_route_encoding_t encoding) 1276 { 1277 u_char *start, *end; 1278 1279 switch (encoding) { 1280 case NXT_HTTP_ROUTE_ENCODING_NONE: 1281 break; 1282 1283 case NXT_HTTP_ROUTE_ENCODING_URI: 1284 start = str->start; 1285 1286 end = nxt_decode_uri(start, start, str->length); 1287 if (nxt_slow_path(end == NULL)) { 1288 return NXT_ERROR; 1289 } 1290 1291 str->length = end - start; 1292 break; 1293 1294 case NXT_HTTP_ROUTE_ENCODING_URI_PLUS: 1295 start = str->start; 1296 1297 end = nxt_decode_uri_plus(start, start, str->length); 1298 if (nxt_slow_path(end == NULL)) { 1299 return NXT_ERROR; 1300 } 1301 1302 str->length = end - start; 1303 break; 1304 1305 default: 1306 nxt_unreachable(); 1307 } 1308 1309 return NXT_OK; 1310 } 1311 1312 1313 static nxt_int_t 1314 nxt_http_route_pattern_slice(nxt_array_t *slices, 1315 nxt_str_t *test, 1316 nxt_http_route_pattern_type_t type, 1317 nxt_http_route_encoding_t encoding, 1318 nxt_http_route_pattern_case_t pattern_case) 1319 { 1320 u_char *start; 1321 nxt_int_t ret; 1322 nxt_http_route_pattern_slice_t *slice; 1323 1324 ret = nxt_http_route_decode_str(test, encoding); 1325 if (nxt_slow_path(ret != NXT_OK)) { 1326 return ret; 1327 } 1328 1329 start = nxt_mp_nget(slices->mem_pool, test->length); 1330 if (nxt_slow_path(start == NULL)) { 1331 return NXT_ERROR; 1332 } 1333 1334 switch (pattern_case) { 1335 1336 case NXT_HTTP_ROUTE_PATTERN_UPCASE: 1337 nxt_memcpy_upcase(start, test->start, test->length); 1338 break; 1339 1340 case NXT_HTTP_ROUTE_PATTERN_LOWCASE: 1341 nxt_memcpy_lowcase(start, test->start, test->length); 1342 break; 1343 1344 case NXT_HTTP_ROUTE_PATTERN_NOCASE: 1345 nxt_memcpy(start, test->start, test->length); 1346 break; 1347 } 1348 1349 slice = nxt_array_add(slices); 1350 if (nxt_slow_path(slice == NULL)) { 1351 return NXT_ERROR; 1352 } 1353 1354 slice->type = type; 1355 slice->start = start; 1356 slice->length = test->length; 1357 1358 return NXT_OK; 1359 } 1360 1361 1362 nxt_int_t 1363 nxt_http_routes_resolve(nxt_task_t *task, nxt_router_temp_conf_t *tmcf) 1364 { 1365 nxt_int_t ret; 1366 nxt_http_route_t **route, **end; 1367 nxt_http_routes_t *routes; 1368 1369 routes = tmcf->router_conf->routes; 1370 1371 if (routes != NULL) { 1372 route = &routes->route[0]; 1373 end = route + routes->items; 1374 1375 while (route < end) { 1376 ret = nxt_http_route_resolve(task, tmcf, *route); 1377 if (nxt_slow_path(ret != NXT_OK)) { 1378 return NXT_ERROR; 1379 } 1380 1381 route++; 1382 } 1383 } 1384 1385 return NXT_OK; 1386 } 1387 1388 1389 static nxt_int_t 1390 nxt_http_route_resolve(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 1391 nxt_http_route_t *route) 1392 { 1393 nxt_int_t ret; 1394 nxt_http_route_match_t **match, **end; 1395 1396 match = &route->match[0]; 1397 end = match + route->items; 1398 1399 while (match < end) { 1400 ret = nxt_http_action_resolve(task, tmcf, &(*match)->action); 1401 if (nxt_slow_path(ret != NXT_OK)) { 1402 return NXT_ERROR; 1403 } 1404 1405 match++; 1406 } 1407 1408 return NXT_OK; 1409 } 1410 1411 1412 static nxt_int_t 1413 nxt_http_action_resolve(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 1414 nxt_http_action_t *action) 1415 { 1416 nxt_var_t *var; 1417 nxt_int_t ret; 1418 1419 if (action->handler != NULL) { 1420 if (action->handler == nxt_http_static_handler 1421 && action->u.share.fallback != NULL) 1422 { 1423 return nxt_http_action_resolve(task, tmcf, 1424 action->u.share.fallback); 1425 } 1426 1427 return NXT_OK; 1428 } 1429 1430 if (nxt_is_var(&action->name)) { 1431 var = nxt_var_compile(&action->name, tmcf->router_conf->mem_pool); 1432 if (nxt_slow_path(var == NULL)) { 1433 return NXT_ERROR; 1434 } 1435 1436 action->u.var = var; 1437 action->handler = nxt_http_action_pass_var; 1438 return NXT_OK; 1439 } 1440 1441 ret = nxt_http_pass_find(task, tmcf->mem_pool, tmcf->router_conf, action); 1442 if (nxt_slow_path(ret != NXT_OK)) { 1443 return NXT_ERROR; 1444 } 1445 1446 return NXT_OK; 1447 } 1448 1449 1450 static nxt_http_action_t * 1451 nxt_http_action_pass_var(nxt_task_t *task, nxt_http_request_t *r, 1452 nxt_http_action_t *action) 1453 { 1454 nxt_var_t *var; 1455 nxt_int_t ret; 1456 1457 ret = nxt_var_query_init(&r->var_query, r, r->mem_pool); 1458 if (nxt_slow_path(ret != NXT_OK)) { 1459 goto fail; 1460 } 1461 1462 var = action->u.var; 1463 1464 action = nxt_mp_get(r->mem_pool, sizeof(nxt_http_action_t)); 1465 if (nxt_slow_path(action == NULL)) { 1466 goto fail; 1467 } 1468 1469 nxt_var_query(task, r->var_query, var, &action->name); 1470 nxt_var_query_resolve(task, r->var_query, action, 1471 nxt_http_action_pass_var_ready, 1472 nxt_http_action_pass_var_error); 1473 return NULL; 1474 1475 fail: 1476 1477 nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); 1478 return NULL; 1479 } 1480 1481 1482 static void 1483 nxt_http_action_pass_var_ready(nxt_task_t *task, void *obj, void *data) 1484 { 1485 nxt_int_t ret; 1486 nxt_router_conf_t *rtcf; 1487 nxt_http_action_t *action; 1488 nxt_http_status_t status; 1489 nxt_http_request_t *r; 1490 1491 r = obj; 1492 action = data; 1493 rtcf = r->conf->socket_conf->router_conf; 1494 1495 nxt_debug(task, "http pass lookup: %V", &action->name); 1496 1497 ret = nxt_http_pass_find(task, r->mem_pool, rtcf, action); 1498 1499 if (ret != NXT_OK) { 1500 status = (ret == NXT_DECLINED) ? NXT_HTTP_NOT_FOUND 1501 : NXT_HTTP_INTERNAL_SERVER_ERROR; 1502 1503 nxt_http_request_error(task, r, status); 1504 return; 1505 } 1506 1507 nxt_http_request_action(task, r, action); 1508 } 1509 1510 1511 static void 1512 nxt_http_action_pass_var_error(nxt_task_t *task, void *obj, void *data) 1513 { 1514 nxt_http_request_t *r; 1515 1516 r = obj; 1517 1518 nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); 1519 } 1520 1521 1522 static nxt_int_t 1523 nxt_http_pass_find(nxt_task_t *task, nxt_mp_t *mp, nxt_router_conf_t *rtcf, 1524 nxt_http_action_t *action) 1525 { 1526 nxt_str_t *targets; 1527 nxt_int_t ret; 1528 nxt_uint_t i; 1529 nxt_str_t segments[3]; 1530 1531 ret = nxt_http_pass_segments(mp, &action->name, segments, 3); 1532 if (nxt_slow_path(ret != NXT_OK)) { 1533 return ret; 1534 } 1535 1536 if (nxt_str_eq(&segments[0], "applications", 12)) { 1537 ret = nxt_router_listener_application(rtcf, &segments[1], action); 1538 1539 if (ret != NXT_OK) { 1540 return ret; 1541 } 1542 1543 if (segments[2].length != 0) { 1544 targets = action->u.app.application->targets; 1545 1546 for (i = 0; !nxt_strstr_eq(&segments[2], &targets[i]); i++); 1547 1548 action->u.app.target = i; 1549 1550 } else { 1551 action->u.app.target = 0; 1552 } 1553 1554 return NXT_OK; 1555 } 1556 1557 if (segments[2].length == 0) { 1558 if (nxt_str_eq(&segments[0], "upstreams", 9)) { 1559 return nxt_upstream_find(rtcf->upstreams, &segments[1], action); 1560 } 1561 1562 if (nxt_str_eq(&segments[0], "routes", 6)) { 1563 return nxt_http_route_find(rtcf->routes, &segments[1], action); 1564 } 1565 } 1566 1567 return NXT_DECLINED; 1568 } 1569 1570 1571 nxt_int_t 1572 nxt_http_pass_segments(nxt_mp_t *mp, nxt_str_t *pass, nxt_str_t *segments, 1573 nxt_uint_t n) 1574 { 1575 u_char *p; 1576 nxt_str_t rest; 1577 1578 if (nxt_slow_path(nxt_str_dup(mp, &rest, pass) == NULL)) { 1579 return NXT_ERROR; 1580 } 1581 1582 nxt_memzero(segments, n * sizeof(nxt_str_t)); 1583 1584 do { 1585 p = nxt_memchr(rest.start, '/', rest.length); 1586 1587 if (p != NULL) { 1588 n--; 1589 1590 if (n == 0) { 1591 return NXT_DECLINED; 1592 } 1593 1594 segments->length = p - rest.start; 1595 segments->start = rest.start; 1596 1597 rest.length -= segments->length + 1; 1598 rest.start = p + 1; 1599 1600 } else { 1601 n = 0; 1602 *segments = rest; 1603 } 1604 1605 if (segments->length == 0) { 1606 return NXT_DECLINED; 1607 } 1608 1609 p = nxt_decode_uri(segments->start, segments->start, segments->length); 1610 if (p == NULL) { 1611 return NXT_DECLINED; 1612 } 1613 1614 segments->length = p - segments->start; 1615 segments++; 1616 1617 } while (n); 1618 1619 return NXT_OK; 1620 } 1621 1622 1623 static nxt_int_t 1624 nxt_http_route_find(nxt_http_routes_t *routes, nxt_str_t *name, 1625 nxt_http_action_t *action) 1626 { 1627 nxt_http_route_t **route, **end; 1628 1629 route = &routes->route[0]; 1630 end = route + routes->items; 1631 1632 while (route < end) { 1633 if (nxt_strstr_eq(&(*route)->name, name)) { 1634 action->u.route = *route; 1635 action->handler = nxt_http_route_handler; 1636 1637 return NXT_OK; 1638 } 1639 1640 route++; 1641 } 1642 1643 return NXT_DECLINED; 1644 } 1645 1646 1647 nxt_http_action_t * 1648 nxt_http_action_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 1649 nxt_str_t *name) 1650 { 1651 nxt_int_t ret; 1652 nxt_http_action_t *action; 1653 1654 action = nxt_mp_alloc(tmcf->router_conf->mem_pool, 1655 sizeof(nxt_http_action_t)); 1656 if (nxt_slow_path(action == NULL)) { 1657 return NULL; 1658 } 1659 1660 action->name = *name; 1661 action->handler = NULL; 1662 1663 ret = nxt_http_action_resolve(task, tmcf, action); 1664 if (nxt_slow_path(ret != NXT_OK)) { 1665 return NULL; 1666 } 1667 1668 return action; 1669 } 1670 1671 1672 /* COMPATIBILITY: listener application. */ 1673 1674 nxt_http_action_t * 1675 nxt_http_pass_application(nxt_task_t *task, nxt_router_conf_t *rtcf, 1676 nxt_str_t *name) 1677 { 1678 nxt_http_action_t *action; 1679 1680 action = nxt_mp_alloc(rtcf->mem_pool, sizeof(nxt_http_action_t)); 1681 if (nxt_slow_path(action == NULL)) { 1682 return NULL; 1683 } 1684 1685 action->name = *name; 1686 1687 (void) nxt_router_listener_application(rtcf, name, action); 1688 1689 action->u.app.target = 0; 1690 1691 return action; 1692 } 1693 1694 1695 static nxt_http_action_t * 1696 nxt_http_route_handler(nxt_task_t *task, nxt_http_request_t *r, 1697 nxt_http_action_t *start) 1698 { 1699 nxt_http_route_t *route; 1700 nxt_http_action_t *action; 1701 nxt_http_route_match_t **match, **end; 1702 1703 route = start->u.route; 1704 match = &route->match[0]; 1705 end = match + route->items; 1706 1707 while (match < end) { 1708 action = nxt_http_route_match(task, r, *match); 1709 if (action != NULL) { 1710 return action; 1711 } 1712 1713 match++; 1714 } 1715 1716 nxt_http_request_error(task, r, NXT_HTTP_NOT_FOUND); 1717 1718 return NULL; 1719 } 1720 1721 1722 static nxt_http_action_t * 1723 nxt_http_route_match(nxt_task_t *task, nxt_http_request_t *r, 1724 nxt_http_route_match_t *match) 1725 { 1726 nxt_int_t ret; 1727 nxt_http_route_test_t *test, *end; 1728 1729 test = &match->test[0]; 1730 end = test + match->items; 1731 1732 while (test < end) { 1733 switch (test->rule->object) { 1734 case NXT_HTTP_ROUTE_TABLE: 1735 ret = nxt_http_route_table(r, test->table); 1736 break; 1737 case NXT_HTTP_ROUTE_SOURCE: 1738 ret = nxt_http_route_addr_rule(r, test->addr_rule, r->remote); 1739 break; 1740 case NXT_HTTP_ROUTE_DESTINATION: 1741 if (r->local == NULL && nxt_fast_path(r->proto.any != NULL)) { 1742 nxt_http_proto[r->protocol].local_addr(task, r); 1743 } 1744 1745 ret = nxt_http_route_addr_rule(r, test->addr_rule, r->local); 1746 break; 1747 default: 1748 ret = nxt_http_route_rule(r, test->rule); 1749 break; 1750 } 1751 1752 if (ret <= 0) { 1753 /* 0 => NULL, -1 => NXT_HTTP_ACTION_ERROR. */ 1754 return (nxt_http_action_t *) (intptr_t) ret; 1755 } 1756 1757 test++; 1758 } 1759 1760 return &match->action; 1761 } 1762 1763 1764 static nxt_int_t 1765 nxt_http_route_table(nxt_http_request_t *r, nxt_http_route_table_t *table) 1766 { 1767 nxt_int_t ret; 1768 nxt_http_route_ruleset_t **ruleset, **end; 1769 1770 ret = 1; 1771 ruleset = &table->ruleset[0]; 1772 end = ruleset + table->items; 1773 1774 while (ruleset < end) { 1775 ret = nxt_http_route_ruleset(r, *ruleset); 1776 1777 if (ret != 0) { 1778 return ret; 1779 } 1780 1781 ruleset++; 1782 } 1783 1784 return ret; 1785 } 1786 1787 1788 static nxt_int_t 1789 nxt_http_route_ruleset(nxt_http_request_t *r, nxt_http_route_ruleset_t *ruleset) 1790 { 1791 nxt_int_t ret; 1792 nxt_http_route_rule_t **rule, **end; 1793 1794 rule = &ruleset->rule[0]; 1795 end = rule + ruleset->items; 1796 1797 while (rule < end) { 1798 ret = nxt_http_route_rule(r, *rule); 1799 1800 if (ret <= 0) { 1801 return ret; 1802 } 1803 1804 rule++; 1805 } 1806 1807 return 1; 1808 } 1809 1810 1811 static nxt_int_t 1812 nxt_http_route_rule(nxt_http_request_t *r, nxt_http_route_rule_t *rule) 1813 { 1814 void *p, **pp; 1815 u_char *start; 1816 size_t length; 1817 nxt_str_t *s; 1818 1819 switch (rule->object) { 1820 1821 case NXT_HTTP_ROUTE_HEADER: 1822 return nxt_http_route_header(r, rule); 1823 1824 case NXT_HTTP_ROUTE_ARGUMENT: 1825 return nxt_http_route_arguments(r, rule); 1826 1827 case NXT_HTTP_ROUTE_COOKIE: 1828 return nxt_http_route_cookies(r, rule); 1829 1830 case NXT_HTTP_ROUTE_SCHEME: 1831 return nxt_http_route_scheme(r, rule); 1832 1833 default: 1834 break; 1835 } 1836 1837 p = nxt_pointer_to(r, rule->u.offset); 1838 1839 if (rule->object == NXT_HTTP_ROUTE_STRING) { 1840 s = p; 1841 1842 } else { 1843 /* NXT_HTTP_ROUTE_STRING_PTR */ 1844 pp = p; 1845 s = *pp; 1846 1847 if (s == NULL) { 1848 return 0; 1849 } 1850 } 1851 1852 length = s->length; 1853 start = s->start; 1854 1855 return nxt_http_route_test_rule(r, rule, start, length); 1856 } 1857 1858 1859 static nxt_int_t 1860 nxt_http_route_addr_pattern_match(nxt_http_route_addr_pattern_t *p, 1861 nxt_sockaddr_t *sa) 1862 { 1863 #if (NXT_INET6) 1864 uint32_t i; 1865 #endif 1866 in_port_t in_port; 1867 nxt_int_t match; 1868 struct sockaddr_in *sin; 1869 #if (NXT_INET6) 1870 struct sockaddr_in6 *sin6; 1871 #endif 1872 nxt_http_route_addr_base_t *base; 1873 1874 base = &p->base; 1875 1876 switch (sa->u.sockaddr.sa_family) { 1877 1878 case AF_INET: 1879 1880 match = (base->addr_family == AF_INET 1881 || base->addr_family == AF_UNSPEC); 1882 if (!match) { 1883 break; 1884 } 1885 1886 sin = &sa->u.sockaddr_in; 1887 in_port = ntohs(sin->sin_port); 1888 1889 match = (in_port >= base->port.start && in_port <= base->port.end); 1890 if (!match) { 1891 break; 1892 } 1893 1894 switch (base->match_type) { 1895 1896 case NXT_HTTP_ROUTE_ADDR_ANY: 1897 break; 1898 1899 case NXT_HTTP_ROUTE_ADDR_EXACT: 1900 match = (nxt_memcmp(&sin->sin_addr, &p->addr.v4.start, 1901 sizeof(struct in_addr)) 1902 == 0); 1903 break; 1904 1905 case NXT_HTTP_ROUTE_ADDR_RANGE: 1906 match = (nxt_memcmp(&sin->sin_addr, &p->addr.v4.start, 1907 sizeof(struct in_addr)) >= 0 1908 && nxt_memcmp(&sin->sin_addr, &p->addr.v4.end, 1909 sizeof(struct in_addr)) <= 0); 1910 break; 1911 1912 case NXT_HTTP_ROUTE_ADDR_CIDR: 1913 match = ((sin->sin_addr.s_addr & p->addr.v4.end) 1914 == p->addr.v4.start); 1915 break; 1916 1917 default: 1918 nxt_unreachable(); 1919 } 1920 1921 break; 1922 1923 #if (NXT_INET6) 1924 case AF_INET6: 1925 1926 match = (base->addr_family == AF_INET6 1927 || base->addr_family == AF_UNSPEC); 1928 if (!match) { 1929 break; 1930 } 1931 1932 sin6 = &sa->u.sockaddr_in6; 1933 in_port = ntohs(sin6->sin6_port); 1934 1935 match = (in_port >= base->port.start && in_port <= base->port.end); 1936 if (!match) { 1937 break; 1938 } 1939 1940 switch (base->match_type) { 1941 1942 case NXT_HTTP_ROUTE_ADDR_ANY: 1943 break; 1944 1945 case NXT_HTTP_ROUTE_ADDR_EXACT: 1946 match = (nxt_memcmp(&sin6->sin6_addr, &p->addr.v6.start, 1947 sizeof(struct in6_addr)) 1948 == 0); 1949 break; 1950 1951 case NXT_HTTP_ROUTE_ADDR_RANGE: 1952 match = (nxt_memcmp(&sin6->sin6_addr, &p->addr.v6.start, 1953 sizeof(struct in6_addr)) >= 0 1954 && nxt_memcmp(&sin6->sin6_addr, &p->addr.v6.end, 1955 sizeof(struct in6_addr)) <= 0); 1956 break; 1957 1958 case NXT_HTTP_ROUTE_ADDR_CIDR: 1959 for (i = 0; i < 16; i++) { 1960 match = ((sin6->sin6_addr.s6_addr[i] 1961 & p->addr.v6.end.s6_addr[i]) 1962 == p->addr.v6.start.s6_addr[i]); 1963 1964 if (!match) { 1965 break; 1966 } 1967 } 1968 1969 break; 1970 1971 default: 1972 nxt_unreachable(); 1973 } 1974 1975 break; 1976 #endif 1977 1978 default: 1979 match = 0; 1980 break; 1981 } 1982 1983 return match ^ base->negative; 1984 } 1985 1986 1987 static nxt_int_t 1988 nxt_http_route_addr_rule(nxt_http_request_t *r, 1989 nxt_http_route_addr_rule_t *addr_rule, nxt_sockaddr_t *sa) 1990 { 1991 uint32_t n; 1992 nxt_bool_t matches; 1993 nxt_http_route_addr_pattern_t *p; 1994 1995 n = addr_rule->items; 1996 p = &addr_rule->addr_pattern[0] - 1; 1997 1998 do { 1999 p++; 2000 n--; 2001 2002 matches = nxt_http_route_addr_pattern_match(p, sa); 2003 2004 if (p->base.negative) { 2005 if (matches) { 2006 continue; 2007 } 2008 2009 return 0; 2010 } 2011 2012 if (matches) { 2013 return 1; 2014 } 2015 2016 } while (n > 0); 2017 2018 return p->base.negative; 2019 } 2020 2021 2022 static nxt_int_t 2023 nxt_http_route_header(nxt_http_request_t *r, nxt_http_route_rule_t *rule) 2024 { 2025 nxt_int_t ret; 2026 nxt_http_field_t *f; 2027 2028 ret = 0; 2029 2030 nxt_list_each(f, r->fields) { 2031 2032 if (rule->u.name.hash != f->hash 2033 || rule->u.name.length != f->name_length 2034 || nxt_strncasecmp(rule->u.name.start, f->name, f->name_length) 2035 != 0) 2036 { 2037 continue; 2038 } 2039 2040 ret = nxt_http_route_test_rule(r, rule, f->value, f->value_length); 2041 if (nxt_slow_path(ret == NXT_ERROR)) { 2042 return NXT_ERROR; 2043 } 2044 2045 if (ret == 0) { 2046 return ret; 2047 } 2048 2049 } nxt_list_loop; 2050 2051 return ret; 2052 } 2053 2054 2055 static nxt_int_t 2056 nxt_http_route_arguments(nxt_http_request_t *r, nxt_http_route_rule_t *rule) 2057 { 2058 nxt_array_t *arguments; 2059 2060 if (r->args == NULL) { 2061 return 0; 2062 } 2063 2064 arguments = nxt_http_route_arguments_parse(r); 2065 if (nxt_slow_path(arguments == NULL)) { 2066 return -1; 2067 } 2068 2069 return nxt_http_route_test_argument(r, rule, arguments); 2070 } 2071 2072 2073 static nxt_array_t * 2074 nxt_http_route_arguments_parse(nxt_http_request_t *r) 2075 { 2076 size_t name_length; 2077 u_char c, *p, *dst, *dst_start, *start, *end, *name; 2078 uint8_t d0, d1; 2079 uint32_t hash; 2080 nxt_bool_t valid; 2081 nxt_array_t *args; 2082 nxt_http_name_value_t *nv; 2083 2084 if (r->arguments != NULL) { 2085 return r->arguments; 2086 } 2087 2088 args = nxt_array_create(r->mem_pool, 2, sizeof(nxt_http_name_value_t)); 2089 if (nxt_slow_path(args == NULL)) { 2090 return NULL; 2091 } 2092 2093 hash = NXT_HTTP_FIELD_HASH_INIT; 2094 valid = 1; 2095 name = NULL; 2096 name_length = 0; 2097 2098 dst_start = nxt_mp_nget(r->mem_pool, r->args->length); 2099 if (nxt_slow_path(dst_start == NULL)) { 2100 return NULL; 2101 } 2102 2103 start = r->args->start; 2104 end = start + r->args->length; 2105 2106 for (p = start, dst = dst_start; p < end; p++, dst++) { 2107 c = *p; 2108 *dst = c; 2109 2110 switch (c) { 2111 case '=': 2112 if (name != NULL) { 2113 break; 2114 } 2115 2116 name_length = dst - dst_start; 2117 valid = (name_length != 0); 2118 name = dst_start; 2119 dst_start = dst + 1; 2120 2121 continue; 2122 2123 case '&': 2124 if (valid) { 2125 nv = nxt_http_route_argument(args, name, name_length, hash, 2126 dst_start, dst); 2127 if (nxt_slow_path(nv == NULL)) { 2128 return NULL; 2129 } 2130 } 2131 2132 hash = NXT_HTTP_FIELD_HASH_INIT; 2133 name_length = 0; 2134 valid = 1; 2135 name = NULL; 2136 dst_start = dst + 1; 2137 2138 continue; 2139 2140 case '+': 2141 c = ' '; 2142 *dst = ' '; 2143 2144 break; 2145 2146 case '%': 2147 if (nxt_slow_path(end - p <= 2)) { 2148 break; 2149 } 2150 2151 d0 = nxt_hex2int[p[1]]; 2152 d1 = nxt_hex2int[p[2]]; 2153 2154 if (nxt_slow_path((d0 | d1) >= 16)) { 2155 break; 2156 } 2157 2158 p += 2; 2159 c = (d0 << 4) + d1; 2160 *dst = c; 2161 2162 break; 2163 } 2164 2165 if (name == NULL) { 2166 hash = nxt_http_field_hash_char(hash, c); 2167 } 2168 } 2169 2170 if (valid) { 2171 nv = nxt_http_route_argument(args, name, name_length, hash, dst_start, 2172 dst); 2173 if (nxt_slow_path(nv == NULL)) { 2174 return NULL; 2175 } 2176 } 2177 2178 r->arguments = args; 2179 2180 return args; 2181 } 2182 2183 2184 static nxt_http_name_value_t * 2185 nxt_http_route_argument(nxt_array_t *array, u_char *name, size_t name_length, 2186 uint32_t hash, u_char *start, u_char *end) 2187 { 2188 size_t length; 2189 nxt_http_name_value_t *nv; 2190 2191 nv = nxt_array_add(array); 2192 if (nxt_slow_path(nv == NULL)) { 2193 return NULL; 2194 } 2195 2196 nv->hash = nxt_http_field_hash_end(hash) & 0xFFFF; 2197 2198 length = end - start; 2199 2200 if (name == NULL) { 2201 name_length = length; 2202 name = start; 2203 length = 0; 2204 } 2205 2206 nv->name_length = name_length; 2207 nv->value_length = length; 2208 nv->name = name; 2209 nv->value = start; 2210 2211 return nv; 2212 } 2213 2214 2215 static nxt_int_t 2216 nxt_http_route_test_argument(nxt_http_request_t *r, 2217 nxt_http_route_rule_t *rule, nxt_array_t *array) 2218 { 2219 nxt_int_t ret; 2220 nxt_http_name_value_t *nv, *end; 2221 2222 ret = 0; 2223 2224 nv = array->elts; 2225 end = nv + array->nelts; 2226 2227 while (nv < end) { 2228 2229 if (rule->u.name.hash == nv->hash 2230 && rule->u.name.length == nv->name_length 2231 && nxt_memcmp(rule->u.name.start, nv->name, nv->name_length) == 0) 2232 { 2233 ret = nxt_http_route_test_rule(r, rule, nv->value, 2234 nv->value_length); 2235 if (nxt_slow_path(ret == NXT_ERROR)) { 2236 return NXT_ERROR; 2237 } 2238 2239 if (ret == 0) { 2240 break; 2241 } 2242 } 2243 2244 nv++; 2245 } 2246 2247 return ret; 2248 } 2249 2250 2251 static nxt_int_t 2252 nxt_http_route_scheme(nxt_http_request_t *r, nxt_http_route_rule_t *rule) 2253 { 2254 nxt_bool_t tls, https; 2255 nxt_http_route_pattern_slice_t *pattern_slice; 2256 2257 pattern_slice = rule->pattern[0].u.pattern_slices->elts; 2258 https = (pattern_slice->length == nxt_length("https")); 2259 tls = (r->tls != NULL); 2260 2261 return (tls == https); 2262 } 2263 2264 2265 static nxt_int_t 2266 nxt_http_route_cookies(nxt_http_request_t *r, nxt_http_route_rule_t *rule) 2267 { 2268 nxt_array_t *cookies; 2269 2270 cookies = nxt_http_route_cookies_parse(r); 2271 if (nxt_slow_path(cookies == NULL)) { 2272 return -1; 2273 } 2274 2275 return nxt_http_route_test_cookie(r, rule, cookies); 2276 } 2277 2278 2279 static nxt_array_t * 2280 nxt_http_route_cookies_parse(nxt_http_request_t *r) 2281 { 2282 nxt_int_t ret; 2283 nxt_array_t *cookies; 2284 nxt_http_field_t *f; 2285 2286 if (r->cookies != NULL) { 2287 return r->cookies; 2288 } 2289 2290 cookies = nxt_array_create(r->mem_pool, 2, sizeof(nxt_http_name_value_t)); 2291 if (nxt_slow_path(cookies == NULL)) { 2292 return NULL; 2293 } 2294 2295 nxt_list_each(f, r->fields) { 2296 2297 if (f->hash != NXT_COOKIE_HASH 2298 || f->name_length != 6 2299 || nxt_strncasecmp(f->name, (u_char *) "Cookie", 6) != 0) 2300 { 2301 continue; 2302 } 2303 2304 ret = nxt_http_route_cookie_parse(cookies, f->value, 2305 f->value + f->value_length); 2306 if (ret != NXT_OK) { 2307 return NULL; 2308 } 2309 2310 } nxt_list_loop; 2311 2312 r->cookies = cookies; 2313 2314 return cookies; 2315 } 2316 2317 2318 static nxt_int_t 2319 nxt_http_route_cookie_parse(nxt_array_t *cookies, u_char *start, u_char *end) 2320 { 2321 size_t name_length; 2322 u_char c, *p, *name; 2323 nxt_http_name_value_t *nv; 2324 2325 name = NULL; 2326 name_length = 0; 2327 2328 for (p = start; p < end; p++) { 2329 c = *p; 2330 2331 if (c == '=') { 2332 while (start[0] == ' ') { start++; } 2333 2334 name_length = p - start; 2335 2336 if (name_length != 0) { 2337 name = start; 2338 } 2339 2340 start = p + 1; 2341 2342 } else if (c == ';') { 2343 if (name != NULL) { 2344 nv = nxt_http_route_cookie(cookies, name, name_length, 2345 start, p); 2346 if (nxt_slow_path(nv == NULL)) { 2347 return NXT_ERROR; 2348 } 2349 } 2350 2351 name = NULL; 2352 start = p + 1; 2353 } 2354 } 2355 2356 if (name != NULL) { 2357 nv = nxt_http_route_cookie(cookies, name, name_length, start, p); 2358 if (nxt_slow_path(nv == NULL)) { 2359 return NXT_ERROR; 2360 } 2361 } 2362 2363 return NXT_OK; 2364 } 2365 2366 2367 static nxt_http_name_value_t * 2368 nxt_http_route_cookie(nxt_array_t *array, u_char *name, size_t name_length, 2369 u_char *start, u_char *end) 2370 { 2371 u_char c, *p; 2372 uint32_t hash; 2373 nxt_http_name_value_t *nv; 2374 2375 nv = nxt_array_add(array); 2376 if (nxt_slow_path(nv == NULL)) { 2377 return NULL; 2378 } 2379 2380 nv->name_length = name_length; 2381 nv->name = name; 2382 2383 hash = NXT_HTTP_FIELD_HASH_INIT; 2384 2385 for (p = name; p < name + name_length; p++) { 2386 c = *p; 2387 hash = nxt_http_field_hash_char(hash, c); 2388 } 2389 2390 nv->hash = nxt_http_field_hash_end(hash) & 0xFFFF; 2391 2392 while (start < end && end[-1] == ' ') { end--; } 2393 2394 nv->value_length = end - start; 2395 nv->value = start; 2396 2397 return nv; 2398 } 2399 2400 2401 static nxt_int_t 2402 nxt_http_route_test_cookie(nxt_http_request_t *r, 2403 nxt_http_route_rule_t *rule, nxt_array_t *array) 2404 { 2405 nxt_int_t ret; 2406 nxt_http_name_value_t *nv, *end; 2407 2408 ret = 0; 2409 2410 nv = array->elts; 2411 end = nv + array->nelts; 2412 2413 while (nv < end) { 2414 2415 if (rule->u.name.hash == nv->hash 2416 && rule->u.name.length == nv->name_length 2417 && nxt_memcmp(rule->u.name.start, nv->name, nv->name_length) == 0) 2418 { 2419 ret = nxt_http_route_test_rule(r, rule, nv->value, 2420 nv->value_length); 2421 if (nxt_slow_path(ret == NXT_ERROR)) { 2422 return NXT_ERROR; 2423 } 2424 2425 if (ret == 0) { 2426 break; 2427 } 2428 } 2429 2430 nv++; 2431 } 2432 2433 return ret; 2434 } 2435 2436 2437 static nxt_int_t 2438 nxt_http_route_test_rule(nxt_http_request_t *r, nxt_http_route_rule_t *rule, 2439 u_char *start, size_t length) 2440 { 2441 nxt_int_t ret; 2442 nxt_http_route_pattern_t *pattern, *end; 2443 2444 ret = 1; 2445 pattern = &rule->pattern[0]; 2446 end = pattern + rule->items; 2447 2448 while (pattern < end) { 2449 ret = nxt_http_route_pattern(r, pattern, start, length); 2450 if (nxt_slow_path(ret == NXT_ERROR)) { 2451 return NXT_ERROR; 2452 } 2453 2454 /* nxt_http_route_pattern() returns either 1 or 0. */ 2455 ret ^= pattern->negative; 2456 2457 if (pattern->any == ret) { 2458 return ret; 2459 } 2460 2461 pattern++; 2462 } 2463 2464 return ret; 2465 } 2466 2467 2468 static nxt_int_t 2469 nxt_http_route_pattern(nxt_http_request_t *r, nxt_http_route_pattern_t *pattern, 2470 u_char *start, size_t length) 2471 { 2472 u_char *p, *end, *test; 2473 size_t test_length; 2474 uint32_t i; 2475 nxt_array_t *pattern_slices; 2476 nxt_http_route_pattern_slice_t *pattern_slice; 2477 2478 #if (NXT_HAVE_REGEX) 2479 if (pattern->regex) { 2480 if (r->regex_match == NULL) { 2481 r->regex_match = nxt_regex_match_create(r->mem_pool, 0); 2482 if (nxt_slow_path(r->regex_match == NULL)) { 2483 return NXT_ERROR; 2484 } 2485 } 2486 2487 return nxt_regex_match(pattern->u.regex, start, length, r->regex_match); 2488 } 2489 #endif 2490 2491 if (length < pattern->min_length) { 2492 return 0; 2493 } 2494 2495 nxt_assert(pattern->u.pattern_slices != NULL); 2496 2497 pattern_slices = pattern->u.pattern_slices; 2498 pattern_slice = pattern_slices->elts; 2499 end = start + length; 2500 2501 for (i = 0; i < pattern_slices->nelts; i++, pattern_slice++) { 2502 test = pattern_slice->start; 2503 test_length = pattern_slice->length; 2504 2505 switch (pattern_slice->type) { 2506 case NXT_HTTP_ROUTE_PATTERN_EXACT: 2507 return ((length == pattern->min_length) && 2508 nxt_http_route_memcmp(start, test, test_length, 2509 pattern->case_sensitive)); 2510 2511 case NXT_HTTP_ROUTE_PATTERN_BEGIN: 2512 if (nxt_http_route_memcmp(start, test, test_length, 2513 pattern->case_sensitive)) 2514 { 2515 start += test_length; 2516 break; 2517 } 2518 2519 return 0; 2520 2521 case NXT_HTTP_ROUTE_PATTERN_END: 2522 p = end - test_length; 2523 2524 if (nxt_http_route_memcmp(p, test, test_length, 2525 pattern->case_sensitive)) 2526 { 2527 end = p; 2528 break; 2529 } 2530 2531 return 0; 2532 2533 case NXT_HTTP_ROUTE_PATTERN_SUBSTRING: 2534 if (pattern->case_sensitive) { 2535 p = nxt_memstrn(start, end, (char *) test, test_length); 2536 2537 } else { 2538 p = nxt_memcasestrn(start, end, (char *) test, test_length); 2539 } 2540 2541 if (p == NULL) { 2542 return 0; 2543 } 2544 2545 start = p + test_length; 2546 } 2547 } 2548 2549 return 1; 2550 } 2551 2552 2553 static nxt_int_t 2554 nxt_http_route_memcmp(u_char *start, u_char *test, size_t test_length, 2555 nxt_bool_t case_sensitive) 2556 { 2557 nxt_int_t n; 2558 2559 if (case_sensitive) { 2560 n = nxt_memcmp(start, test, test_length); 2561 2562 } else { 2563 n = nxt_memcasecmp(start, test, test_length); 2564 } 2565 2566 return (n == 0); 2567 } 2568