comparison src/http/modules/ngx_http_fastcgi_module.c @ 8020: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
8019:0e562a332529 8020: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(&params->hash, hash, lowcase_key, n)) { 968 if (ngx_hash_find(&params->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