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