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 return r; 282 283 fail: 284 285 nxt_mp_release(mp); 286 287 return NULL; 288 } 289 290 291 static const nxt_http_request_state_t nxt_http_request_init_state 292 nxt_aligned(64) = 293 { 294 .ready_handler = nxt_http_request_start, 295 .error_handler = nxt_http_request_close_handler, 296 }; 297 298 299 static void 300 nxt_http_request_start(nxt_task_t *task, void *obj, void *data) 301 { 302 nxt_int_t ret; 303 nxt_socket_conf_t *skcf; 304 nxt_http_request_t *r; 305 306 r = obj; 307 308 r->state = &nxt_http_request_body_state; 309 310 skcf = r->conf->socket_conf; 311 312 if (skcf->forwarded != NULL) { 313 ret = nxt_http_request_forward(task, r, skcf->forwarded); 314 if (nxt_slow_path(ret != NXT_OK)) { 315 goto fail; 316 } 317 } 318 319 if (skcf->client_ip != NULL) { 320 ret = nxt_http_request_forward(task, r, skcf->client_ip); 321 if (nxt_slow_path(ret != NXT_OK)) { 322 goto fail; 323 } 324 } 325 326 nxt_http_request_read_body(task, r); 327 328 return; 329 330 fail: 331 nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); 332 } 333 334 335 static nxt_int_t 336 nxt_http_request_forward(nxt_task_t *task, nxt_http_request_t *r, 337 nxt_http_forward_t *forward) 338 { 339 nxt_int_t ret; 340 nxt_array_t *client_ip_fields; 341 nxt_http_field_t *f, **fields, *protocol_field; 342 nxt_http_forward_header_t *client_ip, *protocol; 343 344 ret = nxt_http_route_addr_rule(r, forward->source, r->remote); 345 if (ret <= 0) { 346 return NXT_OK; 347 } 348 349 client_ip = &forward->client_ip; 350 protocol = &forward->protocol; 351 352 if (client_ip->header != NULL) { 353 client_ip_fields = nxt_array_create(r->mem_pool, 1, 354 sizeof(nxt_http_field_t *)); 355 if (nxt_slow_path(client_ip_fields == NULL)) { 356 return NXT_ERROR; 357 } 358 359 } else { 360 client_ip_fields = NULL; 361 } 362 363 protocol_field = NULL; 364 365 nxt_list_each(f, r->fields) { 366 if (client_ip_fields != NULL 367 && f->hash == client_ip->header_hash 368 && f->value_length > 0 369 && f->name_length == client_ip->header->length 370 && nxt_memcasecmp(f->name, client_ip->header->start, 371 client_ip->header->length) == 0) 372 { 373 fields = nxt_array_add(client_ip_fields); 374 if (nxt_slow_path(fields == NULL)) { 375 return NXT_ERROR; 376 } 377 378 *fields = f; 379 } 380 381 if (protocol->header != NULL 382 && protocol_field == NULL 383 && f->hash == protocol->header_hash 384 && f->value_length > 0 385 && f->name_length == protocol->header->length 386 && nxt_memcasecmp(f->name, protocol->header->start, 387 protocol->header->length) == 0) 388 { 389 protocol_field = f; 390 } 391 } nxt_list_loop; 392 393 if (client_ip_fields != NULL) { 394 nxt_http_request_forward_client_ip(r, forward, client_ip_fields); 395 } 396 397 if (protocol_field != NULL) { 398 nxt_http_request_forward_protocol(r, protocol_field); 399 } 400 401 return NXT_OK; 402 } 403 404 405 static void 406 nxt_http_request_forward_client_ip(nxt_http_request_t *r, 407 nxt_http_forward_t *forward, nxt_array_t *fields) 408 { 409 u_char *start, *p; 410 nxt_int_t ret, i, len; 411 nxt_sockaddr_t *sa, *prev_sa; 412 nxt_http_field_t **f; 413 414 prev_sa = r->remote; 415 f = (nxt_http_field_t **) fields->elts; 416 417 i = fields->nelts; 418 419 while (i-- > 0) { 420 start = f[i]->value; 421 len = f[i]->value_length; 422 423 do { 424 for (p = start + len - 1; p > start; p--, len--) { 425 if (*p != ' ' && *p != ',') { 426 break; 427 } 428 } 429 430 for (/* void */; p > start; p--) { 431 if (*p == ' ' || *p == ',') { 432 p++; 433 break; 434 } 435 } 436 437 sa = nxt_http_request_client_ip_sockaddr(r, p, len - (p - start)); 438 if (nxt_slow_path(sa == NULL)) { 439 if (prev_sa != NULL) { 440 r->remote = prev_sa; 441 } 442 443 return; 444 } 445 446 if (!forward->recursive) { 447 r->remote = sa; 448 return; 449 } 450 451 ret = nxt_http_route_addr_rule(r, forward->source, sa); 452 if (ret <= 0 || (i == 0 && p == start)) { 453 r->remote = sa; 454 return; 455 } 456 457 prev_sa = sa; 458 len = p - 1 - start; 459 460 } while (len > 0); 461 } 462 } 463 464 465 static nxt_sockaddr_t * 466 nxt_http_request_client_ip_sockaddr(nxt_http_request_t *r, u_char *start, 467 size_t len) 468 { 469 nxt_str_t addr; 470 nxt_sockaddr_t *sa; 471 472 addr.start = start; 473 addr.length = len; 474 475 sa = nxt_sockaddr_parse_optport(r->mem_pool, &addr); 476 if (nxt_slow_path(sa == NULL)) { 477 return NULL; 478 } 479 480 switch (sa->u.sockaddr.sa_family) { 481 case AF_INET: 482 if (sa->u.sockaddr_in.sin_addr.s_addr == INADDR_ANY) { 483 return NULL; 484 } 485 486 break; 487 488 #if (NXT_INET6) 489 case AF_INET6: 490 if (IN6_IS_ADDR_UNSPECIFIED(&sa->u.sockaddr_in6.sin6_addr)) { 491 return NULL; 492 } 493 494 break; 495 #endif /* NXT_INET6 */ 496 497 default: 498 return NULL; 499 } 500 501 return sa; 502 } 503 504 505 static void 506 nxt_http_request_forward_protocol(nxt_http_request_t *r, 507 nxt_http_field_t *field) 508 { 509 if (field->value_length == 4) { 510 if (nxt_memcasecmp(field->value, "http", 4) == 0) { 511 r->tls = 0; 512 } 513 514 } else if (field->value_length == 5) { 515 if (nxt_memcasecmp(field->value, "https", 5) == 0) { 516 r->tls = 1; 517 } 518 519 } else if (field->value_length == 2) { 520 if (nxt_memcasecmp(field->value, "on", 2) == 0) { 521 r->tls = 1; 522 } 523 } 524 } 525 526 527 static const nxt_http_request_state_t nxt_http_request_body_state 528 nxt_aligned(64) = 529 { 530 .ready_handler = nxt_http_request_ready, 531 .error_handler = nxt_http_request_close_handler, 532 }; 533 534 535 static void 536 nxt_http_request_ready(nxt_task_t *task, void *obj, void *data) 537 { 538 nxt_http_action_t *action; 539 nxt_http_request_t *r; 540 541 r = obj; 542 action = r->conf->socket_conf->action; 543 544 nxt_http_request_action(task, r, action); 545 } 546 547 548 void 549 nxt_http_request_action(nxt_task_t *task, nxt_http_request_t *r, 550 nxt_http_action_t *action) 551 { 552 if (nxt_fast_path(action != NULL)) { 553 554 do { 555 action = action->handler(task, r, action); 556 557 if (action == NULL) { 558 return; 559 } 560 561 if (action == NXT_HTTP_ACTION_ERROR) { 562 break; 563 } 564 565 } while (r->pass_count++ < 255); 566 } 567 568 nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); 569 } 570 571 572 nxt_http_action_t * 573 nxt_http_application_handler(nxt_task_t *task, nxt_http_request_t *r, 574 nxt_http_action_t *action) 575 { 576 nxt_debug(task, "http application handler"); 577 578 /* 579 * TODO: need an application flag to get local address 580 * required by "SERVER_ADDR" in Pyhton and PHP. Not used in Go. 581 */ 582 nxt_http_request_proto_info(task, r); 583 584 if (r->host.length != 0) { 585 r->server_name = r->host; 586 587 } else { 588 nxt_str_set(&r->server_name, "localhost"); 589 } 590 591 nxt_router_process_http_request(task, r, action); 592 593 return NULL; 594 } 595 596 597 static void 598 nxt_http_request_proto_info(nxt_task_t *task, nxt_http_request_t *r) 599 { 600 if (nxt_fast_path(r->proto.any != NULL)) { 601 nxt_http_proto[r->protocol].local_addr(task, r); 602 } 603 } 604 605 606 void 607 nxt_http_request_read_body(nxt_task_t *task, nxt_http_request_t *r) 608 { 609 if (nxt_fast_path(r->proto.any != NULL)) { 610 nxt_http_proto[r->protocol].body_read(task, r); 611 } 612 } 613 614 615 void 616 nxt_http_request_header_send(nxt_task_t *task, nxt_http_request_t *r, 617 nxt_work_handler_t body_handler, void *data) 618 { 619 u_char *p, *end; 620 nxt_http_field_t *server, *date, *content_length; 621 622 /* 623 * TODO: "Server", "Date", and "Content-Length" processing should be moved 624 * to the last header filter. 625 */ 626 627 server = nxt_list_zero_add(r->resp.fields); 628 if (nxt_slow_path(server == NULL)) { 629 goto fail; 630 } 631 632 nxt_http_field_set(server, "Server", NXT_SERVER); 633 634 if (r->resp.date == NULL) { 635 date = nxt_list_zero_add(r->resp.fields); 636 if (nxt_slow_path(date == NULL)) { 637 goto fail; 638 } 639 640 nxt_http_field_name_set(date, "Date"); 641 642 p = nxt_mp_nget(r->mem_pool, nxt_http_date_cache.size); 643 if (nxt_slow_path(p == NULL)) { 644 goto fail; 645 } 646 647 (void) nxt_thread_time_string(task->thread, &nxt_http_date_cache, p); 648 649 date->value = p; 650 date->value_length = nxt_http_date_cache.size; 651 652 r->resp.date = date; 653 } 654 655 if (r->resp.content_length_n != -1 656 && (r->resp.content_length == NULL || r->resp.content_length->skip)) 657 { 658 content_length = nxt_list_zero_add(r->resp.fields); 659 if (nxt_slow_path(content_length == NULL)) { 660 goto fail; 661 } 662 663 nxt_http_field_name_set(content_length, "Content-Length"); 664 665 p = nxt_mp_nget(r->mem_pool, NXT_OFF_T_LEN); 666 if (nxt_slow_path(p == NULL)) { 667 goto fail; 668 } 669 670 content_length->value = p; 671 end = nxt_sprintf(p, p + NXT_OFF_T_LEN, "%O", r->resp.content_length_n); 672 content_length->value_length = end - p; 673 674 r->resp.content_length = content_length; 675 } 676 677 if (nxt_fast_path(r->proto.any != NULL)) { 678 nxt_http_proto[r->protocol].header_send(task, r, body_handler, data); 679 } 680 681 return; 682 683 fail: 684 685 nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); 686 } 687 688 689 void 690 nxt_http_request_ws_frame_start(nxt_task_t *task, nxt_http_request_t *r, 691 nxt_buf_t *ws_frame) 692 { 693 if (r->proto.any != NULL) { 694 nxt_http_proto[r->protocol].ws_frame_start(task, r, ws_frame); 695 } 696 } 697 698 699 void 700 nxt_http_request_send(nxt_task_t *task, nxt_http_request_t *r, nxt_buf_t *out) 701 { 702 if (nxt_fast_path(r->proto.any != NULL)) { 703 nxt_http_proto[r->protocol].send(task, r, out); 704 } 705 } 706 707 708 nxt_buf_t * 709 nxt_http_buf_mem(nxt_task_t *task, nxt_http_request_t *r, size_t size) 710 { 711 nxt_buf_t *b; 712 713 b = nxt_buf_mem_alloc(r->mem_pool, size, 0); 714 if (nxt_fast_path(b != NULL)) { 715 b->completion_handler = nxt_http_request_mem_buf_completion; 716 b->parent = r; 717 nxt_mp_retain(r->mem_pool); 718 719 } else { 720 nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); 721 } 722 723 return b; 724 } 725 726 727 static void 728 nxt_http_request_mem_buf_completion(nxt_task_t *task, void *obj, void *data) 729 { 730 nxt_buf_t *b, *next; 731 nxt_http_request_t *r; 732 733 b = obj; 734 r = data; 735 736 do { 737 next = b->next; 738 739 nxt_mp_free(r->mem_pool, b); 740 nxt_mp_release(r->mem_pool); 741 742 b = next; 743 } while (b != NULL); 744 } 745 746 747 nxt_buf_t * 748 nxt_http_buf_last(nxt_http_request_t *r) 749 { 750 nxt_buf_t *last; 751 752 last = r->last; 753 r->last = NULL; 754 755 return last; 756 } 757 758 759 static void 760 nxt_http_request_done(nxt_task_t *task, void *obj, void *data) 761 { 762 nxt_http_request_t *r; 763 764 r = data; 765 766 nxt_debug(task, "http request done"); 767 768 nxt_http_request_close_handler(task, r, r->proto.any); 769 } 770 771 772 void 773 nxt_http_request_error_handler(nxt_task_t *task, void *obj, void *data) 774 { 775 nxt_http_proto_t proto; 776 nxt_http_request_t *r; 777 778 r = obj; 779 proto.any = data; 780 781 nxt_debug(task, "http request error handler"); 782 783 r->error = 1; 784 785 if (nxt_fast_path(proto.any != NULL)) { 786 nxt_http_proto[r->protocol].discard(task, r, nxt_http_buf_last(r)); 787 } 788 } 789 790 791 void 792 nxt_http_request_close_handler(nxt_task_t *task, void *obj, void *data) 793 { 794 nxt_var_t *log_format; 795 nxt_http_proto_t proto; 796 nxt_http_request_t *r; 797 nxt_http_protocol_t protocol; 798 nxt_socket_conf_joint_t *conf; 799 nxt_router_access_log_t *access_log; 800 801 r = obj; 802 proto.any = data; 803 804 conf = r->conf; 805 806 if (!r->logged) { 807 r->logged = 1; 808 809 access_log = conf->socket_conf->router_conf->access_log; 810 log_format = conf->socket_conf->router_conf->log_format; 811 812 if (access_log != NULL) { 813 access_log->handler(task, r, access_log, log_format); 814 return; 815 } 816 } 817 818 nxt_debug(task, "http request close handler"); 819 820 r->proto.any = NULL; 821 822 if (r->body != NULL && nxt_buf_is_file(r->body) 823 && r->body->file->fd != -1) 824 { 825 nxt_fd_close(r->body->file->fd); 826 827 r->body->file->fd = -1; 828 } 829 830 if (nxt_fast_path(proto.any != NULL)) { 831 protocol = r->protocol; 832 833 nxt_http_proto[protocol].close(task, proto, conf); 834 835 nxt_mp_release(r->mem_pool); 836 } 837 } 838 839 840 static u_char * 841 nxt_http_date_cache_handler(u_char *buf, nxt_realtime_t *now, struct tm *tm, 842 size_t size, const char *format) 843 { 844 return nxt_http_date(buf, tm); 845 } 846 847 848 nxt_array_t * 849 nxt_http_arguments_parse(nxt_http_request_t *r) 850 { 851 size_t name_length; 852 u_char *p, *dst, *dst_start, *start, *end, *name; 853 uint8_t d0, d1; 854 uint32_t hash; 855 nxt_array_t *args; 856 nxt_http_name_value_t *nv; 857 858 if (r->arguments != NULL) { 859 return r->arguments; 860 } 861 862 args = nxt_array_create(r->mem_pool, 2, sizeof(nxt_http_name_value_t)); 863 if (nxt_slow_path(args == NULL)) { 864 return NULL; 865 } 866 867 hash = NXT_HTTP_FIELD_HASH_INIT; 868 name = NULL; 869 name_length = 0; 870 871 dst_start = nxt_mp_nget(r->mem_pool, r->args->length); 872 if (nxt_slow_path(dst_start == NULL)) { 873 return NULL; 874 } 875 876 r->args_decoded.start = dst_start; 877 878 start = r->args->start; 879 end = start + r->args->length; 880 881 for (p = start, dst = dst_start; p < end; p++, dst++) { 882 *dst = *p; 883 884 switch (*p) { 885 case '=': 886 if (name == NULL) { 887 name_length = dst - dst_start; 888 name = dst_start; 889 dst_start = dst + 1; 890 } 891 892 continue; 893 894 case '&': 895 if (name_length != 0 || dst != dst_start) { 896 nv = nxt_http_argument(args, name, name_length, hash, dst_start, 897 dst); 898 if (nxt_slow_path(nv == NULL)) { 899 return NULL; 900 } 901 } 902 903 hash = NXT_HTTP_FIELD_HASH_INIT; 904 name_length = 0; 905 name = NULL; 906 dst_start = dst + 1; 907 908 continue; 909 910 case '+': 911 *dst = ' '; 912 913 break; 914 915 case '%': 916 if (nxt_slow_path(end - p <= 2)) { 917 break; 918 } 919 920 d0 = nxt_hex2int[p[1]]; 921 d1 = nxt_hex2int[p[2]]; 922 923 if (nxt_slow_path((d0 | d1) >= 16)) { 924 break; 925 } 926 927 p += 2; 928 *dst = (d0 << 4) + d1; 929 930 break; 931 } 932 933 if (name == NULL) { 934 hash = nxt_http_field_hash_char(hash, *dst); 935 } 936 } 937 938 r->args_decoded.length = dst - r->args_decoded.start; 939 940 if (name_length != 0 || dst != dst_start) { 941 nv = nxt_http_argument(args, name, name_length, hash, dst_start, dst); 942 if (nxt_slow_path(nv == NULL)) { 943 return NULL; 944 } 945 } 946 947 r->arguments = args; 948 949 return args; 950 } 951 952 953 static nxt_http_name_value_t * 954 nxt_http_argument(nxt_array_t *array, u_char *name, size_t name_length, 955 uint32_t hash, u_char *start, const u_char *end) 956 { 957 size_t length; 958 nxt_http_name_value_t *nv; 959 960 nv = nxt_array_add(array); 961 if (nxt_slow_path(nv == NULL)) { 962 return NULL; 963 } 964 965 nv->hash = nxt_http_field_hash_end(hash) & 0xFFFF; 966 967 length = end - start; 968 969 if (name == NULL) { 970 name_length = length; 971 name = start; 972 length = 0; 973 } 974 975 nv->name_length = name_length; 976 nv->value_length = length; 977 nv->name = name; 978 nv->value = start; 979 980 return nv; 981 } 982 983 984 nxt_array_t * 985 nxt_http_cookies_parse(nxt_http_request_t *r) 986 { 987 nxt_int_t ret; 988 nxt_array_t *cookies; 989 nxt_http_field_t *f; 990 991 if (r->cookies != NULL) { 992 return r->cookies; 993 } 994 995 cookies = nxt_array_create(r->mem_pool, 2, sizeof(nxt_http_name_value_t)); 996 if (nxt_slow_path(cookies == NULL)) { 997 return NULL; 998 } 999 1000 nxt_list_each(f, r->fields) { 1001 1002 if (f->hash != NXT_HTTP_COOKIE_HASH 1003 || f->name_length != 6 1004 || nxt_strncasecmp(f->name, (u_char *) "Cookie", 6) != 0) 1005 { 1006 continue; 1007 } 1008 1009 ret = nxt_http_cookie_parse(cookies, f->value, 1010 f->value + f->value_length); 1011 if (ret != NXT_OK) { 1012 return NULL; 1013 } 1014 1015 } nxt_list_loop; 1016 1017 r->cookies = cookies; 1018 1019 return cookies; 1020 } 1021 1022 1023 static nxt_int_t 1024 nxt_http_cookie_parse(nxt_array_t *cookies, u_char *start, const u_char *end) 1025 { 1026 size_t name_length; 1027 u_char c, *p, *name; 1028 nxt_http_name_value_t *nv; 1029 1030 name = NULL; 1031 name_length = 0; 1032 1033 for (p = start; p < end; p++) { 1034 c = *p; 1035 1036 if (c == '=') { 1037 while (start[0] == ' ') { start++; } 1038 1039 name_length = p - start; 1040 1041 if (name_length != 0) { 1042 name = start; 1043 } 1044 1045 start = p + 1; 1046 1047 } else if (c == ';') { 1048 if (name != NULL) { 1049 nv = nxt_http_cookie(cookies, name, name_length, start, p); 1050 if (nxt_slow_path(nv == NULL)) { 1051 return NXT_ERROR; 1052 } 1053 } 1054 1055 name = NULL; 1056 start = p + 1; 1057 } 1058 } 1059 1060 if (name != NULL) { 1061 nv = nxt_http_cookie(cookies, name, name_length, start, p); 1062 if (nxt_slow_path(nv == NULL)) { 1063 return NXT_ERROR; 1064 } 1065 } 1066 1067 return NXT_OK; 1068 } 1069 1070 1071 static nxt_http_name_value_t * 1072 nxt_http_cookie(nxt_array_t *array, u_char *name, size_t name_length, 1073 u_char *start, const u_char *end) 1074 { 1075 u_char c, *p; 1076 uint32_t hash; 1077 nxt_http_name_value_t *nv; 1078 1079 nv = nxt_array_add(array); 1080 if (nxt_slow_path(nv == NULL)) { 1081 return NULL; 1082 } 1083 1084 nv->name_length = name_length; 1085 nv->name = name; 1086 1087 hash = NXT_HTTP_FIELD_HASH_INIT; 1088 1089 for (p = name; p < name + name_length; p++) { 1090 c = *p; 1091 hash = nxt_http_field_hash_char(hash, c); 1092 } 1093 1094 nv->hash = nxt_http_field_hash_end(hash) & 0xFFFF; 1095 1096 while (start < end && end[-1] == ' ') { end--; } 1097 1098 nv->value_length = end - start; 1099 nv->value = start; 1100 1101 return nv; 1102 } 1103 1104 1105 int64_t 1106 nxt_http_field_hash(nxt_mp_t *mp, nxt_str_t *name, nxt_bool_t case_sensitive, 1107 uint8_t encoding) 1108 { 1109 u_char c, *p, *src, *start, *end, plus; 1110 uint8_t d0, d1; 1111 uint32_t hash; 1112 nxt_str_t str; 1113 nxt_uint_t i; 1114 1115 str.length = name->length; 1116 1117 str.start = nxt_mp_nget(mp, str.length); 1118 if (nxt_slow_path(str.start == NULL)) { 1119 return -1; 1120 } 1121 1122 p = str.start; 1123 1124 hash = NXT_HTTP_FIELD_HASH_INIT; 1125 1126 if (encoding == NXT_HTTP_URI_ENCODING_NONE) { 1127 for (i = 0; i < name->length; i++) { 1128 c = name->start[i]; 1129 *p++ = c; 1130 1131 c = case_sensitive ? c : nxt_lowcase(c); 1132 hash = nxt_http_field_hash_char(hash, c); 1133 } 1134 1135 goto end; 1136 } 1137 1138 plus = (encoding == NXT_HTTP_URI_ENCODING_PLUS) ? ' ' : '+'; 1139 1140 start = name->start; 1141 end = start + name->length; 1142 1143 for (src = start; src < end; src++) { 1144 c = *src; 1145 1146 switch (c) { 1147 case '%': 1148 if (nxt_slow_path(end - src <= 2)) { 1149 return -1; 1150 } 1151 1152 d0 = nxt_hex2int[src[1]]; 1153 d1 = nxt_hex2int[src[2]]; 1154 src += 2; 1155 1156 if (nxt_slow_path((d0 | d1) >= 16)) { 1157 return -1; 1158 } 1159 1160 c = (d0 << 4) + d1; 1161 *p++ = c; 1162 break; 1163 1164 case '+': 1165 c = plus; 1166 *p++ = c; 1167 break; 1168 1169 default: 1170 *p++ = c; 1171 break; 1172 } 1173 1174 c = case_sensitive ? c : nxt_lowcase(c); 1175 hash = nxt_http_field_hash_char(hash, c); 1176 } 1177 1178 str.length = p - str.start; 1179 1180 end: 1181 1182 *name = str; 1183 1184 return nxt_http_field_hash_end(hash) & 0xFFFF; 1185 } 1186 1187 1188 int64_t 1189 nxt_http_argument_hash(nxt_mp_t *mp, nxt_str_t *name) 1190 { 1191 return nxt_http_field_hash(mp, name, 1, NXT_HTTP_URI_ENCODING_PLUS); 1192 } 1193 1194 1195 int64_t 1196 nxt_http_header_hash(nxt_mp_t *mp, nxt_str_t *name) 1197 { 1198 u_char c, *p; 1199 uint32_t i, hash; 1200 nxt_str_t str; 1201 1202 str.length = name->length; 1203 1204 str.start = nxt_mp_nget(mp, str.length); 1205 if (nxt_slow_path(str.start == NULL)) { 1206 return -1; 1207 } 1208 1209 p = str.start; 1210 hash = NXT_HTTP_FIELD_HASH_INIT; 1211 1212 for (i = 0; i < name->length; i++) { 1213 c = name->start[i]; 1214 1215 if (c >= 'A' && c <= 'Z') { 1216 *p = c | 0x20; 1217 1218 } else if (c == '_') { 1219 *p = '-'; 1220 1221 } else { 1222 *p = c; 1223 } 1224 1225 hash = nxt_http_field_hash_char(hash, *p); 1226 p++; 1227 } 1228 1229 *name = str; 1230 1231 return nxt_http_field_hash_end(hash) & 0xFFFF; 1232 } 1233 1234 1235 int64_t 1236 nxt_http_cookie_hash(nxt_mp_t *mp, nxt_str_t *name) 1237 { 1238 return nxt_http_field_hash(mp, name, 1, NXT_HTTP_URI_ENCODING_NONE); 1239 } 1240