Mercurial > hg > nginx
comparison src/http/modules/ngx_http_uwsgi_module.c @ 8022:8b7a96fdd54c
Uwsgi: combining headers with identical names (ticket #1724).
The uwsgi specification states that "The uwsgi block vars represent a
dictionary/hash". This implies that no duplicate headers are expected.
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:30 +0300 |
parents | 2f443cac3f1e |
children | 2bf7792c262e |
comparison
equal
deleted
inserted
replaced
8021:75af96daee97 | 8022:8b7a96fdd54c |
---|---|
843 | 843 |
844 | 844 |
845 static ngx_int_t | 845 static ngx_int_t |
846 ngx_http_uwsgi_create_request(ngx_http_request_t *r) | 846 ngx_http_uwsgi_create_request(ngx_http_request_t *r) |
847 { | 847 { |
848 u_char ch, *lowcase_key; | 848 u_char ch, sep, *lowcase_key; |
849 size_t key_len, val_len, len, allocated; | 849 size_t key_len, val_len, len, allocated; |
850 ngx_uint_t i, n, hash, skip_empty, header_params; | 850 ngx_uint_t i, n, hash, skip_empty, header_params; |
851 ngx_buf_t *b; | 851 ngx_buf_t *b; |
852 ngx_chain_t *cl, *body; | 852 ngx_chain_t *cl, *body; |
853 ngx_list_part_t *part; | 853 ngx_list_part_t *part; |
854 ngx_table_elt_t *header, **ignored; | 854 ngx_table_elt_t *header, *hn, **ignored; |
855 ngx_http_uwsgi_params_t *params; | 855 ngx_http_uwsgi_params_t *params; |
856 ngx_http_script_code_pt code; | 856 ngx_http_script_code_pt code; |
857 ngx_http_script_engine_t e, le; | 857 ngx_http_script_engine_t e, le; |
858 ngx_http_uwsgi_loc_conf_t *uwcf; | 858 ngx_http_uwsgi_loc_conf_t *uwcf; |
859 ngx_http_script_len_code_pt lcode; | 859 ngx_http_script_len_code_pt lcode; |
903 if (uwcf->upstream.pass_request_headers) { | 903 if (uwcf->upstream.pass_request_headers) { |
904 | 904 |
905 allocated = 0; | 905 allocated = 0; |
906 lowcase_key = NULL; | 906 lowcase_key = NULL; |
907 | 907 |
908 if (params->number) { | 908 if (ngx_http_link_multi_headers(r) != NGX_OK) { |
909 return NGX_ERROR; | |
910 } | |
911 | |
912 if (params->number || r->headers_in.multi) { | |
909 n = 0; | 913 n = 0; |
910 part = &r->headers_in.headers.part; | 914 part = &r->headers_in.headers.part; |
911 | 915 |
912 while (part) { | 916 while (part) { |
913 n += part->nelts; | 917 n += part->nelts; |
931 } | 935 } |
932 | 936 |
933 part = part->next; | 937 part = part->next; |
934 header = part->elts; | 938 header = part->elts; |
935 i = 0; | 939 i = 0; |
940 } | |
941 | |
942 for (n = 0; n < header_params; n++) { | |
943 if (&header[i] == ignored[n]) { | |
944 goto next_length; | |
945 } | |
936 } | 946 } |
937 | 947 |
938 if (params->number) { | 948 if (params->number) { |
939 if (allocated < header[i].key.len) { | 949 if (allocated < header[i].key.len) { |
940 allocated = header[i].key.len + 16; | 950 allocated = header[i].key.len + 16; |
966 } | 976 } |
967 } | 977 } |
968 | 978 |
969 len += 2 + sizeof("HTTP_") - 1 + header[i].key.len | 979 len += 2 + sizeof("HTTP_") - 1 + header[i].key.len |
970 + 2 + header[i].value.len; | 980 + 2 + header[i].value.len; |
981 | |
982 for (hn = header[i].next; hn; hn = hn->next) { | |
983 len += hn->value.len + 2; | |
984 ignored[header_params++] = hn; | |
985 } | |
986 | |
987 next_length: | |
988 | |
989 continue; | |
971 } | 990 } |
972 } | 991 } |
973 | 992 |
974 len += uwcf->uwsgi_string.len; | 993 len += uwcf->uwsgi_string.len; |
975 | 994 |
1084 i = 0; | 1103 i = 0; |
1085 } | 1104 } |
1086 | 1105 |
1087 for (n = 0; n < header_params; n++) { | 1106 for (n = 0; n < header_params; n++) { |
1088 if (&header[i] == ignored[n]) { | 1107 if (&header[i] == ignored[n]) { |
1089 goto next; | 1108 goto next_value; |
1090 } | 1109 } |
1091 } | 1110 } |
1092 | 1111 |
1093 key_len = sizeof("HTTP_") - 1 + header[i].key.len; | 1112 key_len = sizeof("HTTP_") - 1 + header[i].key.len; |
1094 *b->last++ = (u_char) (key_len & 0xff); | 1113 *b->last++ = (u_char) (key_len & 0xff); |
1107 | 1126 |
1108 *b->last++ = ch; | 1127 *b->last++ = ch; |
1109 } | 1128 } |
1110 | 1129 |
1111 val_len = header[i].value.len; | 1130 val_len = header[i].value.len; |
1131 | |
1132 for (hn = header[i].next; hn; hn = hn->next) { | |
1133 val_len += hn->value.len + 2; | |
1134 } | |
1135 | |
1112 *b->last++ = (u_char) (val_len & 0xff); | 1136 *b->last++ = (u_char) (val_len & 0xff); |
1113 *b->last++ = (u_char) ((val_len >> 8) & 0xff); | 1137 *b->last++ = (u_char) ((val_len >> 8) & 0xff); |
1114 b->last = ngx_copy(b->last, header[i].value.data, val_len); | 1138 b->last = ngx_copy(b->last, header[i].value.data, |
1139 header[i].value.len); | |
1140 | |
1141 if (header[i].next) { | |
1142 | |
1143 if (header[i].key.len == sizeof("Cookie") - 1 | |
1144 && ngx_strncasecmp(header[i].key.data, (u_char *) "Cookie", | |
1145 sizeof("Cookie") - 1) | |
1146 == 0) | |
1147 { | |
1148 sep = ';'; | |
1149 | |
1150 } else { | |
1151 sep = ','; | |
1152 } | |
1153 | |
1154 for (hn = header[i].next; hn; hn = hn->next) { | |
1155 *b->last++ = sep; | |
1156 *b->last++ = ' '; | |
1157 b->last = ngx_copy(b->last, hn->value.data, hn->value.len); | |
1158 } | |
1159 } | |
1115 | 1160 |
1116 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | 1161 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
1117 "uwsgi param: \"%*s: %*s\"", | 1162 "uwsgi param: \"%*s: %*s\"", |
1118 key_len, b->last - (key_len + 2 + val_len), | 1163 key_len, b->last - (key_len + 2 + val_len), |
1119 val_len, b->last - val_len); | 1164 val_len, b->last - val_len); |
1120 next: | 1165 next_value: |
1121 | 1166 |
1122 continue; | 1167 continue; |
1123 } | 1168 } |
1124 } | 1169 } |
1125 | 1170 |