Mercurial > hg > nginx-quic
comparison src/http/modules/ngx_http_fastcgi_module.c @ 8869:f8f6b9fee66a
FastCGI: combining headers with identical names (ticket #1724).
FastCGI responder is expected to receive CGI/1.1 environment variables
in the parameters (see section "6.2 Responder" of the FastCGI specification).
Obviously enough, there cannot be multiple environment variables with
the same name.
Further, CGI specification (RFC 3875, section "4.1.18. Protocol-Specific
Meta-Variables") explicitly requires to combine headers: "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:27 +0300 |
parents | 2f443cac3f1e |
children | 2bf7792c262e |
comparison
equal
deleted
inserted
replaced
8868:0e562a332529 | 8869:f8f6b9fee66a |
---|---|
833 | 833 |
834 static ngx_int_t | 834 static ngx_int_t |
835 ngx_http_fastcgi_create_request(ngx_http_request_t *r) | 835 ngx_http_fastcgi_create_request(ngx_http_request_t *r) |
836 { | 836 { |
837 off_t file_pos; | 837 off_t file_pos; |
838 u_char ch, *pos, *lowcase_key; | 838 u_char ch, sep, *pos, *lowcase_key; |
839 size_t size, len, key_len, val_len, padding, | 839 size_t size, len, key_len, val_len, padding, |
840 allocated; | 840 allocated; |
841 ngx_uint_t i, n, next, hash, skip_empty, header_params; | 841 ngx_uint_t i, n, next, hash, skip_empty, header_params; |
842 ngx_buf_t *b; | 842 ngx_buf_t *b; |
843 ngx_chain_t *cl, *body; | 843 ngx_chain_t *cl, *body; |
844 ngx_list_part_t *part; | 844 ngx_list_part_t *part; |
845 ngx_table_elt_t *header, **ignored; | 845 ngx_table_elt_t *header, *hn, **ignored; |
846 ngx_http_upstream_t *u; | 846 ngx_http_upstream_t *u; |
847 ngx_http_script_code_pt code; | 847 ngx_http_script_code_pt code; |
848 ngx_http_script_engine_t e, le; | 848 ngx_http_script_engine_t e, le; |
849 ngx_http_fastcgi_header_t *h; | 849 ngx_http_fastcgi_header_t *h; |
850 ngx_http_fastcgi_params_t *params; | 850 ngx_http_fastcgi_params_t *params; |
898 if (flcf->upstream.pass_request_headers) { | 898 if (flcf->upstream.pass_request_headers) { |
899 | 899 |
900 allocated = 0; | 900 allocated = 0; |
901 lowcase_key = NULL; | 901 lowcase_key = NULL; |
902 | 902 |
903 if (params->number) { | 903 if (ngx_http_link_multi_headers(r) != NGX_OK) { |
904 return NGX_ERROR; | |
905 } | |
906 | |
907 if (params->number || r->headers_in.multi) { | |
904 n = 0; | 908 n = 0; |
905 part = &r->headers_in.headers.part; | 909 part = &r->headers_in.headers.part; |
906 | 910 |
907 while (part) { | 911 while (part) { |
908 n += part->nelts; | 912 n += part->nelts; |
926 } | 930 } |
927 | 931 |
928 part = part->next; | 932 part = part->next; |
929 header = part->elts; | 933 header = part->elts; |
930 i = 0; | 934 i = 0; |
935 } | |
936 | |
937 for (n = 0; n < header_params; n++) { | |
938 if (&header[i] == ignored[n]) { | |
939 goto next_length; | |
940 } | |
931 } | 941 } |
932 | 942 |
933 if (params->number) { | 943 if (params->number) { |
934 if (allocated < header[i].key.len) { | 944 if (allocated < header[i].key.len) { |
935 allocated = header[i].key.len + 16; | 945 allocated = header[i].key.len + 16; |
957 | 967 |
958 if (ngx_hash_find(¶ms->hash, hash, lowcase_key, n)) { | 968 if (ngx_hash_find(¶ms->hash, hash, lowcase_key, n)) { |
959 ignored[header_params++] = &header[i]; | 969 ignored[header_params++] = &header[i]; |
960 continue; | 970 continue; |
961 } | 971 } |
962 | 972 } |
963 n += sizeof("HTTP_") - 1; | 973 |
964 | 974 key_len = sizeof("HTTP_") - 1 + header[i].key.len; |
965 } else { | 975 |
966 n = sizeof("HTTP_") - 1 + header[i].key.len; | 976 val_len = header[i].value.len; |
967 } | 977 |
968 | 978 for (hn = header[i].next; hn; hn = hn->next) { |
969 len += ((n > 127) ? 4 : 1) + ((header[i].value.len > 127) ? 4 : 1) | 979 val_len += hn->value.len + 2; |
970 + n + header[i].value.len; | 980 ignored[header_params++] = hn; |
981 } | |
982 | |
983 len += ((key_len > 127) ? 4 : 1) + key_len | |
984 + ((val_len > 127) ? 4 : 1) + val_len; | |
985 | |
986 next_length: | |
987 | |
988 continue; | |
971 } | 989 } |
972 } | 990 } |
973 | 991 |
974 | 992 |
975 if (len > 65535) { | 993 if (len > 65535) { |
1107 i = 0; | 1125 i = 0; |
1108 } | 1126 } |
1109 | 1127 |
1110 for (n = 0; n < header_params; n++) { | 1128 for (n = 0; n < header_params; n++) { |
1111 if (&header[i] == ignored[n]) { | 1129 if (&header[i] == ignored[n]) { |
1112 goto next; | 1130 goto next_value; |
1113 } | 1131 } |
1114 } | 1132 } |
1115 | 1133 |
1116 key_len = sizeof("HTTP_") - 1 + header[i].key.len; | 1134 key_len = sizeof("HTTP_") - 1 + header[i].key.len; |
1117 if (key_len > 127) { | 1135 if (key_len > 127) { |
1123 } else { | 1141 } else { |
1124 *b->last++ = (u_char) key_len; | 1142 *b->last++ = (u_char) key_len; |
1125 } | 1143 } |
1126 | 1144 |
1127 val_len = header[i].value.len; | 1145 val_len = header[i].value.len; |
1146 | |
1147 for (hn = header[i].next; hn; hn = hn->next) { | |
1148 val_len += hn->value.len + 2; | |
1149 } | |
1150 | |
1128 if (val_len > 127) { | 1151 if (val_len > 127) { |
1129 *b->last++ = (u_char) (((val_len >> 24) & 0x7f) | 0x80); | 1152 *b->last++ = (u_char) (((val_len >> 24) & 0x7f) | 0x80); |
1130 *b->last++ = (u_char) ((val_len >> 16) & 0xff); | 1153 *b->last++ = (u_char) ((val_len >> 16) & 0xff); |
1131 *b->last++ = (u_char) ((val_len >> 8) & 0xff); | 1154 *b->last++ = (u_char) ((val_len >> 8) & 0xff); |
1132 *b->last++ = (u_char) (val_len & 0xff); | 1155 *b->last++ = (u_char) (val_len & 0xff); |
1148 } | 1171 } |
1149 | 1172 |
1150 *b->last++ = ch; | 1173 *b->last++ = ch; |
1151 } | 1174 } |
1152 | 1175 |
1153 b->last = ngx_copy(b->last, header[i].value.data, val_len); | 1176 b->last = ngx_copy(b->last, header[i].value.data, |
1177 header[i].value.len); | |
1178 | |
1179 if (header[i].next) { | |
1180 | |
1181 if (header[i].key.len == sizeof("Cookie") - 1 | |
1182 && ngx_strncasecmp(header[i].key.data, (u_char *) "Cookie", | |
1183 sizeof("Cookie") - 1) | |
1184 == 0) | |
1185 { | |
1186 sep = ';'; | |
1187 | |
1188 } else { | |
1189 sep = ','; | |
1190 } | |
1191 | |
1192 for (hn = header[i].next; hn; hn = hn->next) { | |
1193 *b->last++ = sep; | |
1194 *b->last++ = ' '; | |
1195 b->last = ngx_copy(b->last, hn->value.data, hn->value.len); | |
1196 } | |
1197 } | |
1154 | 1198 |
1155 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | 1199 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
1156 "fastcgi param: \"%*s: %*s\"", | 1200 "fastcgi param: \"%*s: %*s\"", |
1157 key_len, b->last - (key_len + val_len), | 1201 key_len, b->last - (key_len + val_len), |
1158 val_len, b->last - val_len); | 1202 val_len, b->last - val_len); |
1159 next: | 1203 next_value: |
1160 | 1204 |
1161 continue; | 1205 continue; |
1162 } | 1206 } |
1163 } | 1207 } |
1164 | 1208 |