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