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