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 10 11 static nxt_int_t nxt_http_validate_host(nxt_str_t *host, nxt_mp_t *mp); 12 static void nxt_http_request_start(nxt_task_t *task, void *obj, void *data); 13 static nxt_int_t nxt_http_request_forward(nxt_task_t *task, 14 nxt_http_request_t *r, nxt_http_forward_t *forward); 15 static void nxt_http_request_forward_client_ip(nxt_http_request_t *r, 16 nxt_http_forward_t *forward, nxt_array_t *fields); 17 static nxt_sockaddr_t *nxt_http_request_client_ip_sockaddr( 18 nxt_http_request_t *r, u_char *start, size_t len); 19 static void nxt_http_request_forward_protocol(nxt_http_request_t *r, 20 nxt_http_field_t *field); 21 static void nxt_http_request_ready(nxt_task_t *task, void *obj, void *data); 22 static void nxt_http_request_proto_info(nxt_task_t *task, 23 nxt_http_request_t *r); 24 static void nxt_http_request_mem_buf_completion(nxt_task_t *task, void *obj, 25 void *data); 26 static void nxt_http_request_done(nxt_task_t *task, void *obj, void *data); 27 28 static u_char *nxt_http_date_cache_handler(u_char *buf, nxt_realtime_t *now, 29 struct tm *tm, size_t size, const char *format); 30 31 static nxt_http_name_value_t *nxt_http_argument(nxt_array_t *array, 32 u_char *name, size_t name_length, uint32_t hash, u_char *start, 33 const u_char *end); 34 static nxt_int_t nxt_http_cookie_parse(nxt_array_t *cookies, u_char *start, 35 const u_char *end); 36 static nxt_http_name_value_t *nxt_http_cookie(nxt_array_t *array, u_char *name, 37 size_t name_length, u_char *start, const u_char *end); 38 39 40 #define NXT_HTTP_COOKIE_HASH \ 41 (nxt_http_field_hash_end( \ 42 nxt_http_field_hash_char( \ 43 nxt_http_field_hash_char( \ 44 nxt_http_field_hash_char( \ 45 nxt_http_field_hash_char( \ 46 nxt_http_field_hash_char( \ 47 nxt_http_field_hash_char(NXT_HTTP_FIELD_HASH_INIT, \ 48 'c'), 'o'), 'o'), 'k'), 'i'), 'e')) & 0xFFFF) 49 50 51 static const nxt_http_request_state_t nxt_http_request_init_state; 52 static const nxt_http_request_state_t nxt_http_request_body_state; 53 54 55 nxt_time_string_t nxt_http_date_cache = { 56 (nxt_atomic_uint_t) -1, 57 nxt_http_date_cache_handler, 58 NULL, 59 NXT_HTTP_DATE_LEN, 60 NXT_THREAD_TIME_GMT, 61 NXT_THREAD_TIME_SEC, 62 }; 63 64 65 nxt_int_t 66 nxt_http_init(nxt_task_t *task) 67 { 68 nxt_int_t ret; 69 70 ret = nxt_h1p_init(task); 71 72 if (ret != NXT_OK) { 73 return ret; 74 } 75 76 return nxt_http_response_hash_init(task); 77 } 78 79 80 nxt_int_t 81 nxt_http_request_host(void *ctx, nxt_http_field_t *field, uintptr_t data) 82 { 83 nxt_int_t ret; 84 nxt_str_t host; 85 nxt_http_request_t *r; 86 87 r = ctx; 88 89 if (nxt_slow_path(r->host.start != NULL)) { 90 return NXT_HTTP_BAD_REQUEST; 91 } 92 93 host.length = field->value_length; 94 host.start = field->value; 95 96 ret = nxt_http_validate_host(&host, r->mem_pool); 97 98 if (nxt_fast_path(ret == NXT_OK)) { 99 r->host = host; 100 } 101 102 return ret; 103 } 104 105 106 static nxt_int_t 107 nxt_http_validate_host(nxt_str_t *host, nxt_mp_t *mp) 108 { 109 u_char *h, ch; 110 size_t i, dot_pos, host_length; 111 nxt_bool_t lowcase; 112 113 enum { 114 sw_usual, 115 sw_literal, 116 sw_rest 117 } state; 118 119 dot_pos = host->length; 120 host_length = host->length; 121 122 h = host->start; 123 124 lowcase = 0; 125 state = sw_usual; 126 127 for (i = 0; i < host->length; i++) { 128 ch = h[i]; 129 130 if (ch > ']') { 131 /* Short path. */ 132 continue; 133 } 134 135 switch (ch) { 136 137 case '.': 138 if (dot_pos == i - 1) { 139 return NXT_HTTP_BAD_REQUEST; 140 } 141 142 dot_pos = i; 143 break; 144 145 case ':': 146 if (state == sw_usual) { 147 host_length = i; 148 state = sw_rest; 149 } 150 151 break; 152 153 case '[': 154 if (i == 0) { 155 state = sw_literal; 156 } 157 158 break; 159 160 case ']': 161 if (state == sw_literal) { 162 host_length = i + 1; 163 state = sw_rest; 164 } 165 166 break; 167 168 case '/': 169 return NXT_HTTP_BAD_REQUEST; 170 171 default: 172 if (ch >= 'A' && ch <= 'Z') { 173 lowcase = 1; 174 } 175 176 break; 177 } 178 } 179 180 if (dot_pos == host_length - 1) { 181 host_length--; 182 } 183 184 host->length = host_length; 185 186 if (lowcase) { 187 host->start = nxt_mp_nget(mp, host_length); 188 if (nxt_slow_path(host->start == NULL)) { 189 return NXT_HTTP_INTERNAL_SERVER_ERROR; 190 } 191 192 nxt_memcpy_lowcase(host->start, h, host_length); 193 } 194 195 return NXT_OK; 196 } 197 198 199 nxt_int_t 200 nxt_http_request_field(void *ctx, nxt_http_field_t *field, uintptr_t offset) 201 { 202 nxt_http_request_t *r; 203 204 r = ctx; 205 206 nxt_value_at(nxt_http_field_t *, r, offset) = field; 207 208 return NXT_OK; 209 } 210 211 212 nxt_int_t 213 nxt_http_request_content_length(void *ctx, nxt_http_field_t *field, 214 uintptr_t data) 215 { 216 nxt_off_t n, max_body_size; 217 nxt_http_request_t *r; 218 219 r = ctx; 220 221 if (nxt_fast_path(r->content_length == NULL)) { 222 r->content_length = field; 223 224 n = nxt_off_t_parse(field->value, field->value_length); 225 226 if (nxt_fast_path(n >= 0)) { 227 r->content_length_n = n; 228 229 max_body_size = r->conf->socket_conf->max_body_size; 230 231 if (nxt_slow_path(n > max_body_size)) { 232 return NXT_HTTP_PAYLOAD_TOO_LARGE; 233 } 234 235 return NXT_OK; 236 } 237 } 238 239 return NXT_HTTP_BAD_REQUEST; 240 } 241 242 243 nxt_http_request_t * 244 nxt_http_request_create(nxt_task_t *task) 245 { 246 nxt_mp_t *mp; 247 nxt_buf_t *last; 248 nxt_http_request_t *r; 249 250 mp = nxt_mp_create(4096, 128, 512, 32); 251 if (nxt_slow_path(mp == NULL)) { 252 return NULL; 253 } 254 255 r = nxt_mp_zget(mp, sizeof(nxt_http_request_t)); 256 if (nxt_slow_path(r == NULL)) { 257 goto fail; 258 } 259 260 r->resp.fields = nxt_list_create(mp, 8, sizeof(nxt_http_field_t)); 261 if (nxt_slow_path(r->resp.fields == NULL)) { 262 goto fail; 263 } 264 265 last = nxt_mp_zget(mp, NXT_BUF_SYNC_SIZE); 266 if (nxt_slow_path(last == NULL)) { 267 goto fail; 268 } 269 270 nxt_buf_set_sync(last); 271 nxt_buf_set_last(last); 272 last->completion_handler = nxt_http_request_done; 273 last->parent = r; 274 r->last = last; 275 276 r->mem_pool = mp; 277 r->content_length_n = -1; 278 r->resp.content_length_n = -1; 279 r->state = &nxt_http_request_init_state; 280 281 r->start_time = nxt_thread_monotonic_time(task->thread); 282 283 task->thread->engine->requests_cnt++; 284 285 return r; 286 287 fail: 288 289 nxt_mp_release(mp); 290 291 return NULL; 292 } 293 294 295 static const nxt_http_request_state_t nxt_http_request_init_state 296 nxt_aligned(64) = 297 { 298 .ready_handler = nxt_http_request_start, 299 .error_handler = nxt_http_request_close_handler, 300 }; 301 302 303 static void 304 nxt_http_request_start(nxt_task_t *task, void *obj, void *data) 305 { 306 nxt_int_t ret; 307 nxt_socket_conf_t *skcf; 308 nxt_http_request_t *r; 309 310 r = obj; 311 312 r->state = &nxt_http_request_body_state; 313 314 skcf = r->conf->socket_conf; 315 316 if (skcf->forwarded != NULL) { 317 ret = nxt_http_request_forward(task, r, skcf->forwarded); 318 if (nxt_slow_path(ret != NXT_OK)) { 319 goto fail; 320 } 321 } 322 323 if (skcf->client_ip != NULL) { 324 ret = nxt_http_request_forward(task, r, skcf->client_ip); 325 if (nxt_slow_path(ret != NXT_OK)) { 326 goto fail; 327 } 328 } 329 330 nxt_http_request_read_body(task, r); 331 332 return; 333 334 fail: 335 nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); 336 } 337 338 339 static nxt_int_t 340 nxt_http_request_forward(nxt_task_t *task, nxt_http_request_t *r, 341 nxt_http_forward_t *forward) 342 { 343 nxt_int_t ret; 344 nxt_array_t *client_ip_fields; 345 nxt_http_field_t *f, **fields, *protocol_field; 346 nxt_http_forward_header_t *client_ip, *protocol; 347 348 ret = nxt_http_route_addr_rule(r, forward->source, r->remote); 349 if (ret <= 0) { 350 return NXT_OK; 351 } 352 353 client_ip = &forward->client_ip; 354 protocol = &forward->protocol; 355 356 if (client_ip->header != NULL) { 357 client_ip_fields = nxt_array_create(r->mem_pool, 1, 358 sizeof(nxt_http_field_t *)); 359 if (nxt_slow_path(client_ip_fields == NULL)) { 360 return NXT_ERROR; 361 } 362 363 } else { 364 client_ip_fields = NULL; 365 } 366 367 protocol_field = NULL; 368 369 nxt_list_each(f, r->fields) { 370 if (client_ip_fields != NULL 371 && f->hash == client_ip->header_hash 372 && f->value_length > 0 373 && f->name_length == client_ip->header->length 374 && nxt_memcasecmp(f->name, client_ip->header->start, 375 client_ip->header->length) == 0) 376 { 377 fields = nxt_array_add(client_ip_fields); 378 if (nxt_slow_path(fields == NULL)) { 379 return NXT_ERROR; 380 } 381 382 *fields = f; 383 } 384 385 if (protocol->header != NULL 386 && protocol_field == NULL 387 && f->hash == protocol->header_hash 388 && f->value_length > 0 389 && f->name_length == protocol->header->length 390 && nxt_memcasecmp(f->name, protocol->header->start, 391 protocol->header->length) == 0) 392 { 393 protocol_field = f; 394 } 395 } nxt_list_loop; 396 397 if (client_ip_fields != NULL) { 398 nxt_http_request_forward_client_ip(r, forward, client_ip_fields); 399 } 400 401 if (protocol_field != NULL) { 402 nxt_http_request_forward_protocol(r, protocol_field); 403 } 404 405 return NXT_OK; 406 } 407 408 409 static void 410 nxt_http_request_forward_client_ip(nxt_http_request_t *r, 411 nxt_http_forward_t *forward, nxt_array_t *fields) 412 { 413 u_char *start, *p; 414 nxt_int_t ret, i, len; 415 nxt_sockaddr_t *sa, *prev_sa; 416 nxt_http_field_t **f; 417 418 prev_sa = r->remote; 419 f = (nxt_http_field_t **) fields->elts; 420 421 i = fields->nelts; 422 423 while (i-- > 0) { 424 start = f[i]->value; 425 len = f[i]->value_length; 426 427 do { 428 for (p = start + len - 1; p > start; p--, len--) { 429 if (*p != ' ' && *p != ',') { 430 break; 431 } 432 } 433 434 for (/* void */; p > start; p--) { 435 if (*p == ' ' || *p == ',') { 436 p++; 437 break; 438 } 439 } 440 441 sa = nxt_http_request_client_ip_sockaddr(r, p, len - (p - start)); 442 if (nxt_slow_path(sa == NULL)) { 443 if (prev_sa != NULL) { 444 r->remote = prev_sa; 445 } 446 447 return; 448 } 449 450 if (!forward->recursive) { 451 r->remote = sa; 452 return; 453 } 454 455 ret = nxt_http_route_addr_rule(r, forward->source, sa); 456 if (ret <= 0 || (i == 0 && p == start)) { 457 r->remote = sa; 458 return; 459 } 460 461 prev_sa = sa; 462 len = p - 1 - start; 463 464 } while (len > 0); 465 } 466 } 467 468 469 static nxt_sockaddr_t * 470 nxt_http_request_client_ip_sockaddr(nxt_http_request_t *r, u_char *start, 471 size_t len) 472 { 473 nxt_str_t addr; 474 nxt_sockaddr_t *sa; 475 476 addr.start = start; 477 addr.length = len; 478 479 sa = nxt_sockaddr_parse_optport(r->mem_pool, &addr); 480 if (nxt_slow_path(sa == NULL)) { 481 return NULL; 482 } 483 484 switch (sa->u.sockaddr.sa_family) { 485 case AF_INET: 486 if (sa->u.sockaddr_in.sin_addr.s_addr == INADDR_ANY) { 487 return NULL; 488 } 489 490 break; 491 492 #if (NXT_INET6) 493 case AF_INET6: 494 if (IN6_IS_ADDR_UNSPECIFIED(&sa->u.sockaddr_in6.sin6_addr)) { 495 return NULL; 496 } 497 498 break; 499 #endif /* NXT_INET6 */ 500 501 default: 502 return NULL; 503 } 504 505 return sa; 506 } 507 508 509 static void 510 nxt_http_request_forward_protocol(nxt_http_request_t *r, 511 nxt_http_field_t *field) 512 { 513 if (field->value_length == 4) { 514 if (nxt_memcasecmp(field->value, "http", 4) == 0) { 515 r->tls = 0; 516 } 517 518 } else if (field->value_length == 5) { 519 if (nxt_memcasecmp(field->value, "https", 5) == 0) { 520 r->tls = 1; 521 } 522 523 } else if (field->value_length == 2) { 524 if (nxt_memcasecmp(field->value, "on", 2) == 0) { 525 r->tls = 1; 526 } 527 } 528 } 529 530 531 static const nxt_http_request_state_t nxt_http_request_body_state 532 nxt_aligned(64) = 533 { 534 .ready_handler = nxt_http_request_ready, 535 .error_handler = nxt_http_request_close_handler, 536 }; 537 538 539 static void 540 nxt_http_request_ready(nxt_task_t *task, void *obj, void *data) 541 { 542 nxt_http_action_t *action; 543 nxt_http_request_t *r; 544 545 r = obj; 546 action = r->conf->socket_conf->action; 547 548 nxt_http_request_action(task, r, action); 549 } 550 551 552 void 553 nxt_http_request_action(nxt_task_t *task, nxt_http_request_t *r, 554 nxt_http_action_t *action) 555 { 556 if (nxt_fast_path(action != NULL)) { 557 558 do { 559 action = action->handler(task, r, action); 560 561 if (action == NULL) { 562 return; 563 } 564 565 if (action == NXT_HTTP_ACTION_ERROR) { 566 break; 567 } 568 569 } while (r->pass_count++ < 255); 570 } 571 572 nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); 573 } 574 575 576 nxt_http_action_t * 577 nxt_http_application_handler(nxt_task_t *task, nxt_http_request_t *r, 578 nxt_http_action_t *action) 579 { 580 nxt_debug(task, "http application handler"); 581 582 /* 583 * TODO: need an application flag to get local address 584 * required by "SERVER_ADDR" in Pyhton and PHP. Not used in Go. 585 */ 586 nxt_http_request_proto_info(task, r); 587 588 if (r->host.length != 0) { 589 r->server_name = r->host; 590 591 } else { 592 nxt_str_set(&r->server_name, "localhost"); 593 } 594 595 nxt_router_process_http_request(task, r, action); 596 597 return NULL; 598 } 599 600 601 static void 602 nxt_http_request_proto_info(nxt_task_t *task, nxt_http_request_t *r) 603 { 604 if (nxt_fast_path(r->proto.any != NULL)) { 605 nxt_http_proto[r->protocol].local_addr(task, r); 606 } 607 } 608 609 610 void 611 nxt_http_request_read_body(nxt_task_t *task, nxt_http_request_t *r) 612 { 613 if (nxt_fast_path(r->proto.any != NULL)) { 614 nxt_http_proto[r->protocol].body_read(task, r); 615 } 616 } 617 618 619 void 620 nxt_http_request_header_send(nxt_task_t *task, nxt_http_request_t *r, 621 nxt_work_handler_t body_handler, void *data) 622 { 623 u_char *p, *end; 624 nxt_http_field_t *server, *date, *content_length; 625 626 /* 627 * TODO: "Server", "Date", and "Content-Length" processing should be moved 628 * to the last header filter. 629 */ 630 631 server = nxt_list_zero_add(r->resp.fields); 632 if (nxt_slow_path(server == NULL)) { 633 goto fail; 634 } 635 636 nxt_http_field_set(server, "Server", NXT_SERVER); 637 638 if (r->resp.date == NULL) { 639 date = nxt_list_zero_add(r->resp.fields); 640 if (nxt_slow_path(date == NULL)) { 641 goto fail; 642 } 643 644 nxt_http_field_name_set(date, "Date"); 645 646 p = nxt_mp_nget(r->mem_pool, nxt_http_date_cache.size); 647 if (nxt_slow_path(p == NULL)) { 648 goto fail; 649 } 650 651 (void) nxt_thread_time_string(task->thread, &nxt_http_date_cache, p); 652 653 date->value = p; 654 date->value_length = nxt_http_date_cache.size; 655 656 r->resp.date = date; 657 } 658 659 if (r->resp.content_length_n != -1 660 && (r->resp.content_length == NULL || r->resp.content_length->skip)) 661 { 662 content_length = nxt_list_zero_add(r->resp.fields); 663 if (nxt_slow_path(content_length == NULL)) { 664 goto fail; 665 } 666 667 nxt_http_field_name_set(content_length, "Content-Length"); 668 669 p = nxt_mp_nget(r->mem_pool, NXT_OFF_T_LEN); 670 if (nxt_slow_path(p == NULL)) { 671 goto fail; 672 } 673 674 content_length->value = p; 675 end = nxt_sprintf(p, p + NXT_OFF_T_LEN, "%O", r->resp.content_length_n); 676 content_length->value_length = end - p; 677 678 r->resp.content_length = content_length; 679 } 680 681 if (nxt_fast_path(r->proto.any != NULL)) { 682 nxt_http_proto[r->protocol].header_send(task, r, body_handler, data); 683 } 684 685 return; 686 687 fail: 688 689 nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); 690 } 691 692 693 void 694 nxt_http_request_ws_frame_start(nxt_task_t *task, nxt_http_request_t *r, 695 nxt_buf_t *ws_frame) 696 { 697 if (r->proto.any != NULL) { 698 nxt_http_proto[r->protocol].ws_frame_start(task, r, ws_frame); 699 } 700 } 701 702 703 void 704 nxt_http_request_send(nxt_task_t *task, nxt_http_request_t *r, nxt_buf_t *out) 705 { 706 if (nxt_fast_path(r->proto.any != NULL)) { 707 nxt_http_proto[r->protocol].send(task, r, out); 708 } 709 } 710 711 712 nxt_buf_t * 713 nxt_http_buf_mem(nxt_task_t *task, nxt_http_request_t *r, size_t size) 714 { 715 nxt_buf_t *b; 716 717 b = nxt_buf_mem_alloc(r->mem_pool, size, 0); 718 if (nxt_fast_path(b != NULL)) { 719 b->completion_handler = nxt_http_request_mem_buf_completion; 720 b->parent = r; 721 nxt_mp_retain(r->mem_pool); 722 723 } else { 724 nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); 725 } 726 727 return b; 728 } 729 730 731 static void 732 nxt_http_request_mem_buf_completion(nxt_task_t *task, void *obj, void *data) 733 { 734 nxt_buf_t *b, *next; 735 nxt_http_request_t *r; 736 737 b = obj; 738 r = data; 739 740 do { 741 next = b->next; 742 743 nxt_mp_free(r->mem_pool, b); 744 nxt_mp_release(r->mem_pool); 745 746 b = next; 747 } while (b != NULL); 748 } 749 750 751 nxt_buf_t * 752 nxt_http_buf_last(nxt_http_request_t *r) 753 { 754 nxt_buf_t *last; 755 756 last = r->last; 757 r->last = NULL; 758 759 return last; 760 } 761 762 763 static void 764 nxt_http_request_done(nxt_task_t *task, void *obj, void *data) 765 { 766 nxt_http_request_t *r; 767 768 r = data; 769 770 nxt_debug(task, "http request done"); 771 772 nxt_http_request_close_handler(task, r, r->proto.any); 773 } 774 775 776 void 777 nxt_http_request_error_handler(nxt_task_t *task, void *obj, void *data) 778 { 779 nxt_http_proto_t proto; 780 nxt_http_request_t *r; 781 782 r = obj; 783 proto.any = data; 784 785 nxt_debug(task, "http request error handler"); 786 787 r->error = 1; 788 789 if (nxt_fast_path(proto.any != NULL)) { 790 nxt_http_proto[r->protocol].discard(task, r, nxt_http_buf_last(r)); 791 } 792 } 793 794 795 void 796 nxt_http_request_close_handler(nxt_task_t *task, void *obj, void *data) 797 { 798 nxt_var_t *log_format; 799 nxt_http_proto_t proto; 800 nxt_http_request_t *r; 801 nxt_http_protocol_t protocol; 802 nxt_socket_conf_joint_t *conf; 803 nxt_router_access_log_t *access_log; 804 805 r = obj; 806 proto.any = data; 807 808 conf = r->conf; 809 810 if (!r->logged) { 811 r->logged = 1; 812 813 access_log = conf->socket_conf->router_conf->access_log; 814 log_format = conf->socket_conf->router_conf->log_format; 815 816 if (access_log != NULL) { 817 access_log->handler(task, r, access_log, log_format); 818 return; 819 } 820 } 821 822 nxt_debug(task, "http request close handler"); 823 824 r->proto.any = NULL; 825 826 if (r->body != NULL && nxt_buf_is_file(r->body) 827 && r->body->file->fd != -1) 828 { 829 nxt_fd_close(r->body->file->fd); 830 831 r->body->file->fd = -1; 832 } 833 834 if (nxt_fast_path(proto.any != NULL)) { 835 protocol = r->protocol; 836 837 nxt_http_proto[protocol].close(task, proto, conf); 838 839 nxt_mp_release(r->mem_pool); 840 } 841 } 842 843 844 static u_char * 845 nxt_http_date_cache_handler(u_char *buf, nxt_realtime_t *now, struct tm *tm, 846 size_t size, const char *format) 847 { 848 return nxt_http_date(buf, tm); 849 } 850 851 852 nxt_array_t * 853 nxt_http_arguments_parse(nxt_http_request_t *r) 854 { 855 size_t name_length; 856 u_char *p, *dst, *dst_start, *start, *end, *name; 857 uint8_t d0, d1; 858 uint32_t hash; 859 nxt_array_t *args; 860 nxt_http_name_value_t *nv; 861 862 if (r->arguments != NULL) { 863 return r->arguments; 864 } 865 866 args = nxt_array_create(r->mem_pool, 2, sizeof(nxt_http_name_value_t)); 867 if (nxt_slow_path(args == NULL)) { 868 return NULL; 869 } 870 871 hash = NXT_HTTP_FIELD_HASH_INIT; 872 name = NULL; 873 name_length = 0; 874 875 dst_start = nxt_mp_nget(r->mem_pool, r->args->length); 876 if (nxt_slow_path(dst_start == NULL)) { 877 return NULL; 878 } 879 880 r->args_decoded.start = dst_start; 881 882 start = r->args->start; 883 end = start + r->args->length; 884 885 for (p = start, dst = dst_start; p < end; p++, dst++) { 886 *dst = *p; 887 888 switch (*p) { 889 case '=': 890 if (name == NULL) { 891 name_length = dst - dst_start; 892 name = dst_start; 893 dst_start = dst + 1; 894 } 895 896 continue; 897 898 case '&': 899 if (name_length != 0 || dst != dst_start) { 900 nv = nxt_http_argument(args, name, name_length, hash, dst_start, 901 dst); 902 if (nxt_slow_path(nv == NULL)) { 903 return NULL; 904 } 905 } 906 907 hash = NXT_HTTP_FIELD_HASH_INIT; 908 name_length = 0; 909 name = NULL; 910 dst_start = dst + 1; 911 912 continue; 913 914 case '+': 915 *dst = ' '; 916 917 break; 918 919 case '%': 920 if (nxt_slow_path(end - p <= 2)) { 921 break; 922 } 923 924 d0 = nxt_hex2int[p[1]]; 925 d1 = nxt_hex2int[p[2]]; 926 927 if (nxt_slow_path((d0 | d1) >= 16)) { 928 break; 929 } 930 931 p += 2; 932 *dst = (d0 << 4) + d1; 933 934 break; 935 } 936 937 if (name == NULL) { 938 hash = nxt_http_field_hash_char(hash, *dst); 939 } 940 } 941 942 r->args_decoded.length = dst - r->args_decoded.start; 943 944 if (name_length != 0 || dst != dst_start) { 945 nv = nxt_http_argument(args, name, name_length, hash, dst_start, dst); 946 if (nxt_slow_path(nv == NULL)) { 947 return NULL; 948 } 949 } 950 951 r->arguments = args; 952 953 return args; 954 } 955 956 957 static nxt_http_name_value_t * 958 nxt_http_argument(nxt_array_t *array, u_char *name, size_t name_length, 959 uint32_t hash, u_char *start, const u_char *end) 960 { 961 size_t length; 962 nxt_http_name_value_t *nv; 963 964 nv = nxt_array_add(array); 965 if (nxt_slow_path(nv == NULL)) { 966 return NULL; 967 } 968 969 nv->hash = nxt_http_field_hash_end(hash) & 0xFFFF; 970 971 length = end - start; 972 973 if (name == NULL) { 974 name_length = length; 975 name = start; 976 length = 0; 977 } 978 979 nv->name_length = name_length; 980 nv->value_length = length; 981 nv->name = name; 982 nv->value = start; 983 984 return nv; 985 } 986 987 988 nxt_array_t * 989 nxt_http_cookies_parse(nxt_http_request_t *r) 990 { 991 nxt_int_t ret; 992 nxt_array_t *cookies; 993 nxt_http_field_t *f; 994 995 if (r->cookies != NULL) { 996 return r->cookies; 997 } 998 999 cookies = nxt_array_create(r->mem_pool, 2, sizeof(nxt_http_name_value_t)); 1000 if (nxt_slow_path(cookies == NULL)) { 1001 return NULL; 1002 } 1003 1004 nxt_list_each(f, r->fields) { 1005 1006 if (f->hash != NXT_HTTP_COOKIE_HASH 1007 || f->name_length != 6 1008 || nxt_strncasecmp(f->name, (u_char *) "Cookie", 6) != 0) 1009 { 1010 continue; 1011 } 1012 1013 ret = nxt_http_cookie_parse(cookies, f->value, 1014 f->value + f->value_length); 1015 if (ret != NXT_OK) { 1016 return NULL; 1017 } 1018 1019 } nxt_list_loop; 1020 1021 r->cookies = cookies; 1022 1023 return cookies; 1024 } 1025 1026 1027 static nxt_int_t 1028 nxt_http_cookie_parse(nxt_array_t *cookies, u_char *start, const u_char *end) 1029 { 1030 size_t name_length; 1031 u_char c, *p, *name; 1032 nxt_http_name_value_t *nv; 1033 1034 name = NULL; 1035 name_length = 0; 1036 1037 for (p = start; p < end; p++) { 1038 c = *p; 1039 1040 if (c == '=' && name == NULL) { 1041 while (start[0] == ' ') { start++; } 1042 1043 name_length = p - start; 1044 name = start; 1045 1046 start = p + 1; 1047 1048 } else if (c == ';') { 1049 if (name != NULL) { 1050 nv = nxt_http_cookie(cookies, name, name_length, start, p); 1051 if (nxt_slow_path(nv == NULL)) { 1052 return NXT_ERROR; 1053 } 1054 } 1055 1056 name = NULL; 1057 start = p + 1; 1058 } 1059 } 1060 1061 if (name != NULL) { 1062 nv = nxt_http_cookie(cookies, name, name_length, start, p); 1063 if (nxt_slow_path(nv == NULL)) { 1064 return NXT_ERROR; 1065 } 1066 } 1067 1068 return NXT_OK; 1069 } 1070 1071 1072 static nxt_http_name_value_t * 1073 nxt_http_cookie(nxt_array_t *array, u_char *name, size_t name_length, 1074 u_char *start, const u_char *end) 1075 { 1076 u_char c, *p; 1077 uint32_t hash; 1078 nxt_http_name_value_t *nv; 1079 1080 nv = nxt_array_add(array); 1081 if (nxt_slow_path(nv == NULL)) { 1082 return NULL; 1083 } 1084 1085 nv->name_length = name_length; 1086 nv->name = name; 1087 1088 hash = NXT_HTTP_FIELD_HASH_INIT; 1089 1090 for (p = name; p < name + name_length; p++) { 1091 c = *p; 1092 hash = nxt_http_field_hash_char(hash, c); 1093 } 1094 1095 nv->hash = nxt_http_field_hash_end(hash) & 0xFFFF; 1096 1097 while (start < end && end[-1] == ' ') { end--; } 1098 1099 nv->value_length = end - start; 1100 nv->value = start; 1101 1102 return nv; 1103 } 1104 1105 1106 int64_t 1107 nxt_http_field_hash(nxt_mp_t *mp, nxt_str_t *name, nxt_bool_t case_sensitive, 1108 uint8_t encoding) 1109 { 1110 u_char c, *p, *src, *start, *end, plus; 1111 uint8_t d0, d1; 1112 uint32_t hash; 1113 nxt_str_t str; 1114 nxt_uint_t i; 1115 1116 str.length = name->length; 1117 1118 str.start = nxt_mp_nget(mp, str.length); 1119 if (nxt_slow_path(str.start == NULL)) { 1120 return -1; 1121 } 1122 1123 p = str.start; 1124 1125 hash = NXT_HTTP_FIELD_HASH_INIT; 1126 1127 if (encoding == NXT_HTTP_URI_ENCODING_NONE) { 1128 for (i = 0; i < name->length; i++) { 1129 c = name->start[i]; 1130 *p++ = c; 1131 1132 c = case_sensitive ? c : nxt_lowcase(c); 1133 hash = nxt_http_field_hash_char(hash, c); 1134 } 1135 1136 goto end; 1137 } 1138 1139 plus = (encoding == NXT_HTTP_URI_ENCODING_PLUS) ? ' ' : '+'; 1140 1141 start = name->start; 1142 end = start + name->length; 1143 1144 for (src = start; src < end; src++) { 1145 c = *src; 1146 1147 switch (c) { 1148 case '%': 1149 if (nxt_slow_path(end - src <= 2)) { 1150 return -1; 1151 } 1152 1153 d0 = nxt_hex2int[src[1]]; 1154 d1 = nxt_hex2int[src[2]]; 1155 src += 2; 1156 1157 if (nxt_slow_path((d0 | d1) >= 16)) { 1158 return -1; 1159 } 1160 1161 c = (d0 << 4) + d1; 1162 *p++ = c; 1163 break; 1164 1165 case '+': 1166 c = plus; 1167 *p++ = c; 1168 break; 1169 1170 default: 1171 *p++ = c; 1172 break; 1173 } 1174 1175 c = case_sensitive ? c : nxt_lowcase(c); 1176 hash = nxt_http_field_hash_char(hash, c); 1177 } 1178 1179 str.length = p - str.start; 1180 1181 end: 1182 1183 *name = str; 1184 1185 return nxt_http_field_hash_end(hash) & 0xFFFF; 1186 } 1187 1188 1189 int64_t 1190 nxt_http_argument_hash(nxt_mp_t *mp, nxt_str_t *name) 1191 { 1192 return nxt_http_field_hash(mp, name, 1, NXT_HTTP_URI_ENCODING_PLUS); 1193 } 1194 1195 1196 int64_t 1197 nxt_http_header_hash(nxt_mp_t *mp, nxt_str_t *name) 1198 { 1199 u_char c, *p; 1200 uint32_t i, hash; 1201 nxt_str_t str; 1202 1203 str.length = name->length; 1204 1205 str.start = nxt_mp_nget(mp, str.length); 1206 if (nxt_slow_path(str.start == NULL)) { 1207 return -1; 1208 } 1209 1210 p = str.start; 1211 hash = NXT_HTTP_FIELD_HASH_INIT; 1212 1213 for (i = 0; i < name->length; i++) { 1214 c = name->start[i]; 1215 1216 if (c >= 'A' && c <= 'Z') { 1217 *p = c | 0x20; 1218 1219 } else if (c == '_') { 1220 *p = '-'; 1221 1222 } else { 1223 *p = c; 1224 } 1225 1226 hash = nxt_http_field_hash_char(hash, *p); 1227 p++; 1228 } 1229 1230 *name = str; 1231 1232 return nxt_http_field_hash_end(hash) & 0xFFFF; 1233 } 1234 1235 1236 int64_t 1237 nxt_http_cookie_hash(nxt_mp_t *mp, nxt_str_t *name) 1238 { 1239 return nxt_http_field_hash(mp, name, 1, NXT_HTTP_URI_ENCODING_NONE); 1240 } 1241