Mercurial > hg > nginx
comparison src/http/modules/ngx_http_scgi_module.c @ 8021:75af96daee97
SCGI: combining headers with identical names (ticket #1724).
SCGI specification explicitly forbids headers with duplicate names
(section "3. Request Format"): "Duplicate names are not allowed in
the headers".
Further, provided headers are expected to follow CGI specification,
which also requires to combine headers (RFC 3875, section "4.1.18.
Protocol-Specific Meta-Variables"): "If multiple header fields with
the same field-name are received then the server MUST rewrite them
as a single value having the same semantics".
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Mon, 30 May 2022 21:25:28 +0300 |
parents | 2f443cac3f1e |
children | 2bf7792c262e |
comparison
equal
deleted
inserted
replaced
8020:f8f6b9fee66a | 8021:75af96daee97 |
---|---|
631 | 631 |
632 static ngx_int_t | 632 static ngx_int_t |
633 ngx_http_scgi_create_request(ngx_http_request_t *r) | 633 ngx_http_scgi_create_request(ngx_http_request_t *r) |
634 { | 634 { |
635 off_t content_length_n; | 635 off_t content_length_n; |
636 u_char ch, *key, *val, *lowcase_key; | 636 u_char ch, sep, *key, *val, *lowcase_key; |
637 size_t len, key_len, val_len, allocated; | 637 size_t len, key_len, val_len, allocated; |
638 ngx_buf_t *b; | 638 ngx_buf_t *b; |
639 ngx_str_t content_length; | 639 ngx_str_t content_length; |
640 ngx_uint_t i, n, hash, skip_empty, header_params; | 640 ngx_uint_t i, n, hash, skip_empty, header_params; |
641 ngx_chain_t *cl, *body; | 641 ngx_chain_t *cl, *body; |
642 ngx_list_part_t *part; | 642 ngx_list_part_t *part; |
643 ngx_table_elt_t *header, **ignored; | 643 ngx_table_elt_t *header, *hn, **ignored; |
644 ngx_http_scgi_params_t *params; | 644 ngx_http_scgi_params_t *params; |
645 ngx_http_script_code_pt code; | 645 ngx_http_script_code_pt code; |
646 ngx_http_script_engine_t e, le; | 646 ngx_http_script_engine_t e, le; |
647 ngx_http_scgi_loc_conf_t *scf; | 647 ngx_http_scgi_loc_conf_t *scf; |
648 ngx_http_script_len_code_pt lcode; | 648 ngx_http_script_len_code_pt lcode; |
705 if (scf->upstream.pass_request_headers) { | 705 if (scf->upstream.pass_request_headers) { |
706 | 706 |
707 allocated = 0; | 707 allocated = 0; |
708 lowcase_key = NULL; | 708 lowcase_key = NULL; |
709 | 709 |
710 if (params->number) { | 710 if (ngx_http_link_multi_headers(r) != NGX_OK) { |
711 return NGX_ERROR; | |
712 } | |
713 | |
714 if (params->number || r->headers_in.multi) { | |
711 n = 0; | 715 n = 0; |
712 part = &r->headers_in.headers.part; | 716 part = &r->headers_in.headers.part; |
713 | 717 |
714 while (part) { | 718 while (part) { |
715 n += part->nelts; | 719 n += part->nelts; |
733 } | 737 } |
734 | 738 |
735 part = part->next; | 739 part = part->next; |
736 header = part->elts; | 740 header = part->elts; |
737 i = 0; | 741 i = 0; |
742 } | |
743 | |
744 for (n = 0; n < header_params; n++) { | |
745 if (&header[i] == ignored[n]) { | |
746 goto next_length; | |
747 } | |
738 } | 748 } |
739 | 749 |
740 if (params->number) { | 750 if (params->number) { |
741 if (allocated < header[i].key.len) { | 751 if (allocated < header[i].key.len) { |
742 allocated = header[i].key.len + 16; | 752 allocated = header[i].key.len + 16; |
768 } | 778 } |
769 } | 779 } |
770 | 780 |
771 len += sizeof("HTTP_") - 1 + header[i].key.len + 1 | 781 len += sizeof("HTTP_") - 1 + header[i].key.len + 1 |
772 + header[i].value.len + 1; | 782 + header[i].value.len + 1; |
783 | |
784 for (hn = header[i].next; hn; hn = hn->next) { | |
785 len += hn->value.len + 2; | |
786 ignored[header_params++] = hn; | |
787 } | |
788 | |
789 next_length: | |
790 | |
791 continue; | |
773 } | 792 } |
774 } | 793 } |
775 | 794 |
776 /* netstring: "length:" + packet + "," */ | 795 /* netstring: "length:" + packet + "," */ |
777 | 796 |
867 i = 0; | 886 i = 0; |
868 } | 887 } |
869 | 888 |
870 for (n = 0; n < header_params; n++) { | 889 for (n = 0; n < header_params; n++) { |
871 if (&header[i] == ignored[n]) { | 890 if (&header[i] == ignored[n]) { |
872 goto next; | 891 goto next_value; |
873 } | 892 } |
874 } | 893 } |
875 | 894 |
876 key = b->last; | 895 key = b->last; |
877 b->last = ngx_cpymem(key, "HTTP_", sizeof("HTTP_") - 1); | 896 b->last = ngx_cpymem(key, "HTTP_", sizeof("HTTP_") - 1); |
891 | 910 |
892 *b->last++ = (u_char) 0; | 911 *b->last++ = (u_char) 0; |
893 | 912 |
894 val = b->last; | 913 val = b->last; |
895 b->last = ngx_copy(val, header[i].value.data, header[i].value.len); | 914 b->last = ngx_copy(val, header[i].value.data, header[i].value.len); |
915 | |
916 if (header[i].next) { | |
917 | |
918 if (header[i].key.len == sizeof("Cookie") - 1 | |
919 && ngx_strncasecmp(header[i].key.data, (u_char *) "Cookie", | |
920 sizeof("Cookie") - 1) | |
921 == 0) | |
922 { | |
923 sep = ';'; | |
924 | |
925 } else { | |
926 sep = ','; | |
927 } | |
928 | |
929 for (hn = header[i].next; hn; hn = hn->next) { | |
930 *b->last++ = sep; | |
931 *b->last++ = ' '; | |
932 b->last = ngx_copy(b->last, hn->value.data, hn->value.len); | |
933 } | |
934 } | |
935 | |
896 *b->last++ = (u_char) 0; | 936 *b->last++ = (u_char) 0; |
897 | 937 |
898 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | 938 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
899 "scgi param: \"%s: %s\"", key, val); | 939 "scgi param: \"%s: %s\"", key, val); |
900 | 940 |
901 next: | 941 next_value: |
902 | 942 |
903 continue; | 943 continue; |
904 } | 944 } |
905 } | 945 } |
906 | 946 |