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