comparison src/http/v3/ngx_http_v3_request.c @ 8958:10522e8dea41 quic

HTTP/3: improved processing of multiple Cookie field lines. As per draft-ietf-quic-http, 4.1.1.2, and similar to HTTP/2 specification, they ought to be concatenated. This closely follows ngx_http_v2_module.
author Sergey Kandaurov <pluknet@nginx.com>
date Thu, 30 Dec 2021 12:59:32 +0300
parents de7d36aa9bc7
children f9d7930d0eed
comparison
equal deleted inserted replaced
8957:de7d36aa9bc7 8958:10522e8dea41
23 ngx_str_t *name, ngx_str_t *value); 23 ngx_str_t *name, ngx_str_t *value);
24 static ngx_int_t ngx_http_v3_process_pseudo_header(ngx_http_request_t *r, 24 static ngx_int_t ngx_http_v3_process_pseudo_header(ngx_http_request_t *r,
25 ngx_str_t *name, ngx_str_t *value); 25 ngx_str_t *name, ngx_str_t *value);
26 static ngx_int_t ngx_http_v3_init_pseudo_headers(ngx_http_request_t *r); 26 static ngx_int_t ngx_http_v3_init_pseudo_headers(ngx_http_request_t *r);
27 static ngx_int_t ngx_http_v3_process_request_header(ngx_http_request_t *r); 27 static ngx_int_t ngx_http_v3_process_request_header(ngx_http_request_t *r);
28 static ngx_int_t ngx_http_v3_cookie(ngx_http_request_t *r, ngx_str_t *value);
29 static ngx_int_t ngx_http_v3_construct_cookie_header(ngx_http_request_t *r);
28 static void ngx_http_v3_read_client_request_body_handler(ngx_http_request_t *r); 30 static void ngx_http_v3_read_client_request_body_handler(ngx_http_request_t *r);
29 static ngx_int_t ngx_http_v3_do_read_client_request_body(ngx_http_request_t *r); 31 static ngx_int_t ngx_http_v3_do_read_client_request_body(ngx_http_request_t *r);
30 static ngx_int_t ngx_http_v3_request_body_filter(ngx_http_request_t *r, 32 static ngx_int_t ngx_http_v3_request_body_filter(ngx_http_request_t *r,
31 ngx_chain_t *in); 33 ngx_chain_t *in);
32 34
599 ngx_table_elt_t *h; 601 ngx_table_elt_t *h;
600 ngx_http_header_t *hh; 602 ngx_http_header_t *hh;
601 ngx_http_core_srv_conf_t *cscf; 603 ngx_http_core_srv_conf_t *cscf;
602 ngx_http_core_main_conf_t *cmcf; 604 ngx_http_core_main_conf_t *cmcf;
603 605
606 static ngx_str_t cookie = ngx_string("cookie");
607
604 len = name->len + value->len; 608 len = name->len + value->len;
605 609
606 if (len > r->v3_parse->header_limit) { 610 if (len > r->v3_parse->header_limit) {
607 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, 611 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
608 "client sent too large header"); 612 "client sent too large header");
634 638
635 if (ngx_http_v3_init_pseudo_headers(r) != NGX_OK) { 639 if (ngx_http_v3_init_pseudo_headers(r) != NGX_OK) {
636 return NGX_ERROR; 640 return NGX_ERROR;
637 } 641 }
638 642
639 h = ngx_list_push(&r->headers_in.headers); 643 if (name->len == cookie.len
640 if (h == NULL) { 644 && ngx_memcmp(name->data, cookie.data, cookie.len) == 0)
641 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); 645 {
642 return NGX_ERROR; 646 if (ngx_http_v3_cookie(r, value) != NGX_OK) {
643 } 647 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
644 648 return NGX_ERROR;
645 h->key = *name; 649 }
646 h->value = *value; 650
647 h->lowcase_key = h->key.data; 651 } else {
648 h->hash = ngx_hash_key(h->key.data, h->key.len); 652 h = ngx_list_push(&r->headers_in.headers);
649 653 if (h == NULL) {
650 cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); 654 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
651 655 return NGX_ERROR;
652 hh = ngx_hash_find(&cmcf->headers_in_hash, h->hash, 656 }
653 h->lowcase_key, h->key.len); 657
654 658 h->key = *name;
655 if (hh && hh->handler(r, h, hh->offset) != NGX_OK) { 659 h->value = *value;
656 return NGX_ERROR; 660 h->lowcase_key = h->key.data;
661 h->hash = ngx_hash_key(h->key.data, h->key.len);
662
663 cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
664
665 hh = ngx_hash_find(&cmcf->headers_in_hash, h->hash,
666 h->lowcase_key, h->key.len);
667
668 if (hh && hh->handler(r, h, hh->offset) != NGX_OK) {
669 return NGX_ERROR;
670 }
657 } 671 }
658 672
659 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 673 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
660 "http3 header: \"%V: %V\"", name, value); 674 "http3 header: \"%V: %V\"", name, value);
661 return NGX_OK; 675 return NGX_OK;
976 ngx_connection_t *c; 990 ngx_connection_t *c;
977 991
978 c = r->connection; 992 c = r->connection;
979 993
980 if (ngx_http_v3_init_pseudo_headers(r) != NGX_OK) { 994 if (ngx_http_v3_init_pseudo_headers(r) != NGX_OK) {
995 return NGX_ERROR;
996 }
997
998 if (ngx_http_v3_construct_cookie_header(r) != NGX_OK) {
981 return NGX_ERROR; 999 return NGX_ERROR;
982 } 1000 }
983 1001
984 if (r->headers_in.server.len == 0) { 1002 if (r->headers_in.server.len == 0) {
985 ngx_log_error(NGX_LOG_INFO, c->log, 0, 1003 ngx_log_error(NGX_LOG_INFO, c->log, 0,
1051 1069
1052 failed: 1070 failed:
1053 1071
1054 ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); 1072 ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
1055 return NGX_ERROR; 1073 return NGX_ERROR;
1074 }
1075
1076
1077 static ngx_int_t
1078 ngx_http_v3_cookie(ngx_http_request_t *r, ngx_str_t *value)
1079 {
1080 ngx_str_t *val;
1081 ngx_array_t *cookies;
1082
1083 cookies = r->v3_parse->cookies;
1084
1085 if (cookies == NULL) {
1086 cookies = ngx_array_create(r->pool, 2, sizeof(ngx_str_t));
1087 if (cookies == NULL) {
1088 return NGX_ERROR;
1089 }
1090
1091 r->v3_parse->cookies = cookies;
1092 }
1093
1094 val = ngx_array_push(cookies);
1095 if (val == NULL) {
1096 return NGX_ERROR;
1097 }
1098
1099 *val = *value;
1100
1101 return NGX_OK;
1102 }
1103
1104
1105 static ngx_int_t
1106 ngx_http_v3_construct_cookie_header(ngx_http_request_t *r)
1107 {
1108 u_char *buf, *p, *end;
1109 size_t len;
1110 ngx_str_t *vals;
1111 ngx_uint_t i;
1112 ngx_array_t *cookies;
1113 ngx_table_elt_t *h;
1114 ngx_http_header_t *hh;
1115 ngx_http_core_main_conf_t *cmcf;
1116
1117 static ngx_str_t cookie = ngx_string("cookie");
1118
1119 cookies = r->v3_parse->cookies;
1120
1121 if (cookies == NULL) {
1122 return NGX_OK;
1123 }
1124
1125 vals = cookies->elts;
1126
1127 i = 0;
1128 len = 0;
1129
1130 do {
1131 len += vals[i].len + 2;
1132 } while (++i != cookies->nelts);
1133
1134 len -= 2;
1135
1136 buf = ngx_pnalloc(r->pool, len + 1);
1137 if (buf == NULL) {
1138 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
1139 return NGX_ERROR;
1140 }
1141
1142 p = buf;
1143 end = buf + len;
1144
1145 for (i = 0; /* void */ ; i++) {
1146
1147 p = ngx_cpymem(p, vals[i].data, vals[i].len);
1148
1149 if (p == end) {
1150 *p = '\0';
1151 break;
1152 }
1153
1154 *p++ = ';'; *p++ = ' ';
1155 }
1156
1157 h = ngx_list_push(&r->headers_in.headers);
1158 if (h == NULL) {
1159 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
1160 return NGX_ERROR;
1161 }
1162
1163 h->hash = ngx_hash(ngx_hash(ngx_hash(ngx_hash(
1164 ngx_hash('c', 'o'), 'o'), 'k'), 'i'), 'e');
1165
1166 h->key.len = cookie.len;
1167 h->key.data = cookie.data;
1168
1169 h->value.len = len;
1170 h->value.data = buf;
1171
1172 h->lowcase_key = cookie.data;
1173
1174 cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
1175
1176 hh = ngx_hash_find(&cmcf->headers_in_hash, h->hash,
1177 h->lowcase_key, h->key.len);
1178
1179 if (hh == NULL) {
1180 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
1181 return NGX_ERROR;
1182 }
1183
1184 if (hh->handler(r, h, hh->offset) != NGX_OK) {
1185 /*
1186 * request has been finalized already
1187 * in ngx_http_process_multi_header_lines()
1188 */
1189 return NGX_ERROR;
1190 }
1191
1192 return NGX_OK;
1056 } 1193 }
1057 1194
1058 1195
1059 ngx_int_t 1196 ngx_int_t
1060 ngx_http_v3_read_request_body(ngx_http_request_t *r) 1197 ngx_http_v3_read_request_body(ngx_http_request_t *r)