Mercurial > hg > nginx
comparison src/http/v3/ngx_http_v3_request.c @ 8679:e1eb7f4ca9f1 quic
HTTP/3: refactored request parser.
The change reduces diff to the default branch for
src/http/ngx_http_request.c and src/http/ngx_http_parse.c.
author | Roman Arutyunyan <arut@nginx.com> |
---|---|
date | Fri, 22 Jan 2021 16:34:06 +0300 |
parents | 96eb6915d244 |
children | 58acdba9b3b2 |
comparison
equal
deleted
inserted
replaced
8678:3443ee341cc1 | 8679:e1eb7f4ca9f1 |
---|---|
8 #include <ngx_config.h> | 8 #include <ngx_config.h> |
9 #include <ngx_core.h> | 9 #include <ngx_core.h> |
10 #include <ngx_http.h> | 10 #include <ngx_http.h> |
11 | 11 |
12 | 12 |
13 static void ngx_http_v3_process_request(ngx_event_t *rev); | |
14 static ngx_int_t ngx_http_v3_process_header(ngx_http_request_t *r, | |
15 ngx_str_t *name, ngx_str_t *value); | |
13 static ngx_int_t ngx_http_v3_process_pseudo_header(ngx_http_request_t *r, | 16 static ngx_int_t ngx_http_v3_process_pseudo_header(ngx_http_request_t *r, |
14 ngx_str_t *name, ngx_str_t *value); | 17 ngx_str_t *name, ngx_str_t *value); |
18 static ngx_int_t ngx_http_v3_init_pseudo_headers(ngx_http_request_t *r); | |
19 static ngx_int_t ngx_http_v3_process_request_header(ngx_http_request_t *r); | |
15 | 20 |
16 | 21 |
17 static const struct { | 22 static const struct { |
18 ngx_str_t name; | 23 ngx_str_t name; |
19 ngx_uint_t method; | 24 ngx_uint_t method; |
35 { ngx_string("PATCH"), NGX_HTTP_PATCH }, | 40 { ngx_string("PATCH"), NGX_HTTP_PATCH }, |
36 { ngx_string("TRACE"), NGX_HTTP_TRACE } | 41 { ngx_string("TRACE"), NGX_HTTP_TRACE } |
37 }; | 42 }; |
38 | 43 |
39 | 44 |
40 ngx_int_t | 45 void |
41 ngx_http_v3_parse_request(ngx_http_request_t *r, ngx_buf_t *b) | 46 ngx_http_v3_init(ngx_connection_t *c) |
42 { | 47 { |
43 size_t len; | 48 size_t size; |
44 u_char *p; | 49 ngx_buf_t *b; |
45 ngx_int_t rc, n; | 50 ngx_event_t *rev; |
46 ngx_str_t *name, *value; | 51 ngx_http_request_t *r; |
52 ngx_http_connection_t *hc; | |
53 ngx_http_core_srv_conf_t *cscf; | |
54 | |
55 if (ngx_http_v3_init_session(c) != NGX_OK) { | |
56 ngx_http_v3_finalize_connection(c, NGX_HTTP_V3_ERR_INTERNAL_ERROR, | |
57 "internal error"); | |
58 ngx_http_close_connection(c); | |
59 return; | |
60 } | |
61 | |
62 if (c->quic->id & NGX_QUIC_STREAM_UNIDIRECTIONAL) { | |
63 ngx_http_v3_init_uni_stream(c); | |
64 return; | |
65 } | |
66 | |
67 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 init request stream"); | |
68 | |
69 hc = c->data; | |
70 | |
71 cscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_core_module); | |
72 | |
73 size = cscf->client_header_buffer_size; | |
74 | |
75 b = c->buffer; | |
76 | |
77 if (b == NULL) { | |
78 b = ngx_create_temp_buf(c->pool, size); | |
79 if (b == NULL) { | |
80 ngx_http_close_connection(c); | |
81 return; | |
82 } | |
83 | |
84 c->buffer = b; | |
85 | |
86 } else if (b->start == NULL) { | |
87 | |
88 b->start = ngx_palloc(c->pool, size); | |
89 if (b->start == NULL) { | |
90 ngx_http_close_connection(c); | |
91 return; | |
92 } | |
93 | |
94 b->pos = b->start; | |
95 b->last = b->start; | |
96 b->end = b->last + size; | |
97 } | |
98 | |
99 c->log->action = "reading client request"; | |
100 | |
101 r = ngx_http_create_request(c); | |
102 if (r == NULL) { | |
103 ngx_http_close_connection(c); | |
104 return; | |
105 } | |
106 | |
107 r->http_version = NGX_HTTP_VERSION_30; | |
108 | |
109 c->data = r; | |
110 | |
111 rev = c->read; | |
112 rev->handler = ngx_http_v3_process_request; | |
113 | |
114 ngx_http_v3_process_request(rev); | |
115 } | |
116 | |
117 | |
118 static void | |
119 ngx_http_v3_process_request(ngx_event_t *rev) | |
120 { | |
121 ssize_t n; | |
122 ngx_buf_t *b; | |
123 ngx_int_t rc; | |
47 ngx_connection_t *c; | 124 ngx_connection_t *c; |
125 ngx_http_request_t *r; | |
126 ngx_http_core_srv_conf_t *cscf; | |
48 ngx_http_v3_parse_headers_t *st; | 127 ngx_http_v3_parse_headers_t *st; |
49 | 128 |
50 c = r->connection; | 129 c = rev->data; |
130 r = c->data; | |
131 | |
132 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, "http3 process request"); | |
133 | |
134 if (rev->timedout) { | |
135 ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out"); | |
136 c->timedout = 1; | |
137 ngx_http_close_request(r, NGX_HTTP_REQUEST_TIME_OUT); | |
138 return; | |
139 } | |
140 | |
51 st = r->h3_parse; | 141 st = r->h3_parse; |
52 | 142 |
53 if (st == NULL) { | 143 if (st == NULL) { |
54 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 parse header"); | |
55 | |
56 st = ngx_pcalloc(c->pool, sizeof(ngx_http_v3_parse_headers_t)); | 144 st = ngx_pcalloc(c->pool, sizeof(ngx_http_v3_parse_headers_t)); |
57 if (st == NULL) { | 145 if (st == NULL) { |
58 goto failed; | 146 ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); |
147 return; | |
59 } | 148 } |
60 | 149 |
61 r->h3_parse = st; | 150 r->h3_parse = st; |
62 r->parse_start = b->pos; | 151 } |
63 r->state = 1; | 152 |
64 } | 153 b = r->header_in; |
65 | 154 |
66 while (b->pos < b->last) { | 155 for ( ;; ) { |
156 | |
157 if (b->pos == b->last) { | |
158 | |
159 if (!rev->ready) { | |
160 break; | |
161 } | |
162 | |
163 n = c->recv(c, b->start, b->end - b->start); | |
164 | |
165 if (n == NGX_AGAIN) { | |
166 if (!rev->timer_set) { | |
167 cscf = ngx_http_get_module_srv_conf(r, | |
168 ngx_http_core_module); | |
169 ngx_add_timer(rev, cscf->client_header_timeout); | |
170 } | |
171 | |
172 if (ngx_handle_read_event(rev, 0) != NGX_OK) { | |
173 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); | |
174 } | |
175 | |
176 break; | |
177 } | |
178 | |
179 if (n == 0) { | |
180 ngx_log_error(NGX_LOG_INFO, c->log, 0, | |
181 "client prematurely closed connection"); | |
182 } | |
183 | |
184 if (n == 0 || n == NGX_ERROR) { | |
185 c->error = 1; | |
186 c->log->action = "reading client request"; | |
187 | |
188 ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); | |
189 break; | |
190 } | |
191 | |
192 b->pos = b->start; | |
193 b->last = b->start + n; | |
194 } | |
195 | |
67 rc = ngx_http_v3_parse_headers(c, st, *b->pos); | 196 rc = ngx_http_v3_parse_headers(c, st, *b->pos); |
68 | 197 |
69 if (rc > 0) { | 198 if (rc > 0) { |
70 ngx_http_v3_finalize_connection(c, rc, | 199 ngx_http_v3_finalize_connection(c, rc, |
71 "could not parse request headers"); | 200 "could not parse request headers"); |
72 goto failed; | 201 ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); |
202 break; | |
73 } | 203 } |
74 | 204 |
75 if (rc == NGX_ERROR) { | 205 if (rc == NGX_ERROR) { |
76 goto failed; | 206 ngx_http_v3_finalize_connection(c, NGX_HTTP_V3_ERR_INTERNAL_ERROR, |
207 "internal error"); | |
208 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); | |
209 break; | |
77 } | 210 } |
78 | 211 |
79 if (rc == NGX_BUSY) { | 212 if (rc == NGX_BUSY) { |
80 return NGX_BUSY; | 213 if (rev->error) { |
214 ngx_http_close_request(r, NGX_HTTP_CLOSE); | |
215 break; | |
216 } | |
217 | |
218 if (ngx_handle_read_event(rev, 0) != NGX_OK) { | |
219 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); | |
220 } | |
221 | |
222 break; | |
81 } | 223 } |
82 | 224 |
83 b->pos++; | 225 b->pos++; |
226 r->request_length++; | |
84 | 227 |
85 if (rc == NGX_AGAIN) { | 228 if (rc == NGX_AGAIN) { |
86 continue; | 229 continue; |
87 } | 230 } |
88 | 231 |
89 name = &st->header_rep.header.name; | 232 /* rc == NGX_OK || rc == NGX_DONE */ |
90 value = &st->header_rep.header.value; | 233 |
91 | 234 if (ngx_http_v3_process_header(r, &st->header_rep.header.name, |
92 n = ngx_http_v3_process_pseudo_header(r, name, value); | 235 &st->header_rep.header.value) |
93 | 236 != NGX_OK) |
94 if (n == NGX_ERROR) { | 237 { |
95 goto failed; | 238 break; |
96 } | |
97 | |
98 if (n == NGX_OK && rc == NGX_OK) { | |
99 continue; | |
100 } | |
101 | |
102 len = r->method_name.len + 1 | |
103 + (r->uri_end - r->uri_start) + 1 | |
104 + sizeof("HTTP/3.0") - 1; | |
105 | |
106 p = ngx_pnalloc(c->pool, len); | |
107 if (p == NULL) { | |
108 goto failed; | |
109 } | |
110 | |
111 r->request_start = p; | |
112 | |
113 p = ngx_cpymem(p, r->method_name.data, r->method_name.len); | |
114 r->method_end = p - 1; | |
115 *p++ = ' '; | |
116 p = ngx_cpymem(p, r->uri_start, r->uri_end - r->uri_start); | |
117 *p++ = ' '; | |
118 r->http_protocol.data = p; | |
119 p = ngx_cpymem(p, "HTTP/3.0", sizeof("HTTP/3.0") - 1); | |
120 | |
121 r->request_end = p; | |
122 r->state = 0; | |
123 | |
124 return NGX_OK; | |
125 } | |
126 | |
127 return NGX_AGAIN; | |
128 | |
129 failed: | |
130 | |
131 return NGX_HTTP_PARSE_INVALID_REQUEST; | |
132 } | |
133 | |
134 | |
135 ngx_int_t | |
136 ngx_http_v3_parse_header(ngx_http_request_t *r, ngx_buf_t *b, | |
137 ngx_uint_t allow_underscores) | |
138 { | |
139 u_char ch; | |
140 ngx_int_t rc; | |
141 ngx_str_t *name, *value; | |
142 ngx_uint_t hash, i, n; | |
143 ngx_connection_t *c; | |
144 ngx_http_v3_parse_headers_t *st; | |
145 enum { | |
146 sw_start = 0, | |
147 sw_done, | |
148 sw_next, | |
149 sw_header | |
150 }; | |
151 | |
152 c = r->connection; | |
153 st = r->h3_parse; | |
154 | |
155 switch (r->state) { | |
156 | |
157 case sw_start: | |
158 r->parse_start = b->pos; | |
159 | |
160 if (st->state) { | |
161 r->state = sw_next; | |
162 goto done; | |
163 } | |
164 | |
165 name = &st->header_rep.header.name; | |
166 | |
167 if (name->len && name->data[0] != ':') { | |
168 r->state = sw_done; | |
169 goto done; | |
170 } | |
171 | |
172 /* fall through */ | |
173 | |
174 case sw_done: | |
175 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
176 "http3 parse header done"); | |
177 return NGX_HTTP_PARSE_HEADER_DONE; | |
178 | |
179 case sw_next: | |
180 r->parse_start = b->pos; | |
181 r->invalid_header = 0; | |
182 break; | |
183 | |
184 case sw_header: | |
185 break; | |
186 } | |
187 | |
188 while (b->pos < b->last) { | |
189 rc = ngx_http_v3_parse_headers(c, st, *b->pos++); | |
190 | |
191 if (rc > 0) { | |
192 ngx_http_v3_finalize_connection(c, rc, | |
193 "could not parse request headers"); | |
194 return NGX_HTTP_PARSE_INVALID_HEADER; | |
195 } | |
196 | |
197 if (rc == NGX_ERROR) { | |
198 return NGX_HTTP_PARSE_INVALID_HEADER; | |
199 } | 239 } |
200 | 240 |
201 if (rc == NGX_DONE) { | 241 if (rc == NGX_DONE) { |
202 r->state = sw_done; | 242 if (ngx_http_v3_process_request_header(r) != NGX_OK) { |
203 goto done; | 243 break; |
204 } | 244 } |
205 | 245 |
206 if (rc == NGX_OK) { | 246 ngx_http_process_request(r); |
207 r->state = sw_next; | 247 break; |
208 goto done; | 248 } |
209 } | 249 } |
210 } | 250 |
211 | 251 ngx_http_run_posted_requests(c); |
212 r->state = sw_header; | 252 |
213 return NGX_AGAIN; | 253 return; |
214 | 254 } |
215 done: | 255 |
216 | 256 |
217 name = &st->header_rep.header.name; | 257 static ngx_int_t |
218 value = &st->header_rep.header.value; | 258 ngx_http_v3_process_header(ngx_http_request_t *r, ngx_str_t *name, |
219 | 259 ngx_str_t *value) |
220 r->header_name_start = name->data; | 260 { |
221 r->header_name_end = name->data + name->len; | 261 ngx_table_elt_t *h; |
222 r->header_start = value->data; | 262 ngx_http_header_t *hh; |
223 r->header_end = value->data + value->len; | 263 ngx_http_core_main_conf_t *cmcf; |
224 | 264 |
225 hash = 0; | 265 if (name->len && name->data[0] == ':') { |
226 i = 0; | 266 return ngx_http_v3_process_pseudo_header(r, name, value); |
227 | 267 } |
228 for (n = 0; n < name->len; n++) { | 268 |
229 ch = name->data[n]; | 269 if (ngx_http_v3_init_pseudo_headers(r) != NGX_OK) { |
230 | 270 return NGX_ERROR; |
231 if (ch >= 'A' && ch <= 'Z') { | 271 } |
232 /* | 272 |
233 * A request or response containing uppercase | 273 h = ngx_list_push(&r->headers_in.headers); |
234 * header field names MUST be treated as malformed | 274 if (h == NULL) { |
235 */ | 275 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); |
236 return NGX_HTTP_PARSE_INVALID_HEADER; | 276 return NGX_ERROR; |
237 } | 277 } |
238 | 278 |
239 if (ch == '\0') { | 279 h->key = *name; |
240 return NGX_HTTP_PARSE_INVALID_HEADER; | 280 h->value = *value; |
241 } | 281 h->lowcase_key = h->key.data; |
242 | 282 h->hash = ngx_hash_key(h->key.data, h->key.len); |
243 if (ch == '_' && !allow_underscores) { | 283 |
244 r->invalid_header = 1; | 284 cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); |
245 continue; | 285 |
246 } | 286 hh = ngx_hash_find(&cmcf->headers_in_hash, h->hash, |
247 | 287 h->lowcase_key, h->key.len); |
248 if ((ch < 'a' || ch > 'z') | 288 |
249 && (ch < '0' || ch > '9') | 289 if (hh && hh->handler(r, h, hh->offset) != NGX_OK) { |
250 && ch != '-' && ch != '_') | 290 return NGX_ERROR; |
251 { | 291 } |
252 r->invalid_header = 1; | 292 |
253 continue; | 293 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
254 } | 294 "http3 header: \"%V: %V\"", name, value); |
255 | |
256 hash = ngx_hash(hash, ch); | |
257 r->lowcase_header[i++] = ch; | |
258 i &= (NGX_HTTP_LC_HEADER_LEN - 1); | |
259 } | |
260 | |
261 r->header_hash = hash; | |
262 r->lowcase_index = i; | |
263 | |
264 return NGX_OK; | 295 return NGX_OK; |
265 } | 296 } |
266 | 297 |
267 | 298 |
268 static ngx_int_t | 299 static ngx_int_t |
269 ngx_http_v3_process_pseudo_header(ngx_http_request_t *r, ngx_str_t *name, | 300 ngx_http_v3_process_pseudo_header(ngx_http_request_t *r, ngx_str_t *name, |
270 ngx_str_t *value) | 301 ngx_str_t *value) |
271 { | 302 { |
272 ngx_uint_t i; | 303 ngx_uint_t i; |
273 ngx_connection_t *c; | 304 |
274 | 305 if (r->request_line.len) { |
275 if (name->len == 0 || name->data[0] != ':') { | 306 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, |
276 return NGX_DONE; | 307 "client sent out of order pseudo-headers"); |
277 } | 308 goto failed; |
278 | 309 } |
279 c = r->connection; | |
280 | 310 |
281 if (name->len == 7 && ngx_strncmp(name->data, ":method", 7) == 0) { | 311 if (name->len == 7 && ngx_strncmp(name->data, ":method", 7) == 0) { |
312 | |
282 r->method_name = *value; | 313 r->method_name = *value; |
283 | 314 |
284 for (i = 0; i < sizeof(ngx_http_v3_methods) | 315 for (i = 0; i < sizeof(ngx_http_v3_methods) |
285 / sizeof(ngx_http_v3_methods[0]); i++) | 316 / sizeof(ngx_http_v3_methods[0]); i++) |
286 { | 317 { |
287 if (value->len == ngx_http_v3_methods[i].name.len | 318 if (value->len == ngx_http_v3_methods[i].name.len |
288 && ngx_strncmp(value->data, ngx_http_v3_methods[i].name.data, | 319 && ngx_strncmp(value->data, |
289 value->len) == 0) | 320 ngx_http_v3_methods[i].name.data, value->len) |
321 == 0) | |
290 { | 322 { |
291 r->method = ngx_http_v3_methods[i].method; | 323 r->method = ngx_http_v3_methods[i].method; |
292 break; | 324 break; |
293 } | 325 } |
294 } | 326 } |
295 | 327 |
296 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, | 328 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
297 "http3 method \"%V\" %ui", value, r->method); | 329 "http3 method \"%V\" %ui", value, r->method); |
298 return NGX_OK; | 330 return NGX_OK; |
299 } | 331 } |
300 | 332 |
301 if (name->len == 5 && ngx_strncmp(name->data, ":path", 5) == 0) { | 333 if (name->len == 5 && ngx_strncmp(name->data, ":path", 5) == 0) { |
334 | |
302 r->uri_start = value->data; | 335 r->uri_start = value->data; |
303 r->uri_end = value->data + value->len; | 336 r->uri_end = value->data + value->len; |
304 | 337 |
305 if (ngx_http_parse_uri(r) != NGX_OK) { | 338 if (ngx_http_parse_uri(r) != NGX_OK) { |
306 ngx_log_error(NGX_LOG_INFO, c->log, 0, | 339 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, |
307 "client sent invalid :path header: \"%V\"", value); | 340 "client sent invalid \":path\" header: \"%V\"", |
308 return NGX_ERROR; | 341 value); |
309 } | 342 goto failed; |
310 | 343 } |
311 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, | 344 |
345 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
312 "http3 path \"%V\"", value); | 346 "http3 path \"%V\"", value); |
313 | |
314 return NGX_OK; | 347 return NGX_OK; |
315 } | 348 } |
316 | 349 |
317 if (name->len == 7 && ngx_strncmp(name->data, ":scheme", 7) == 0) { | 350 if (name->len == 7 && ngx_strncmp(name->data, ":scheme", 7) == 0) { |
318 r->schema_start = value->data; | 351 |
319 r->schema_end = value->data + value->len; | 352 r->schema = *value; |
320 | 353 |
321 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, | 354 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
322 "http3 schema \"%V\"", value); | 355 "http3 schema \"%V\"", value); |
323 | |
324 return NGX_OK; | 356 return NGX_OK; |
325 } | 357 } |
326 | 358 |
327 if (name->len == 10 && ngx_strncmp(name->data, ":authority", 10) == 0) { | 359 if (name->len == 10 && ngx_strncmp(name->data, ":authority", 10) == 0) { |
360 | |
328 r->host_start = value->data; | 361 r->host_start = value->data; |
329 r->host_end = value->data + value->len; | 362 r->host_end = value->data + value->len; |
330 | 363 |
331 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, | 364 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
332 "http3 authority \"%V\"", value); | 365 "http3 authority \"%V\"", value); |
333 | |
334 return NGX_OK; | 366 return NGX_OK; |
335 } | 367 } |
336 | 368 |
337 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, | 369 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, |
338 "http3 unknown pseudo header \"%V\" \"%V\"", name, value); | 370 "client sent unknown pseudo-header \"%V\"", name); |
371 | |
372 failed: | |
373 | |
374 ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); | |
375 return NGX_ERROR; | |
376 } | |
377 | |
378 | |
379 static ngx_int_t | |
380 ngx_http_v3_init_pseudo_headers(ngx_http_request_t *r) | |
381 { | |
382 size_t len; | |
383 u_char *p; | |
384 ngx_int_t rc; | |
385 ngx_str_t host; | |
386 | |
387 if (r->request_line.len) { | |
388 return NGX_OK; | |
389 } | |
390 | |
391 len = r->method_name.len + 1 | |
392 + (r->uri_end - r->uri_start) + 1 | |
393 + sizeof("HTTP/3.0") - 1; | |
394 | |
395 p = ngx_pnalloc(r->pool, len); | |
396 if (p == NULL) { | |
397 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); | |
398 return NGX_ERROR; | |
399 } | |
400 | |
401 r->request_line.data = p; | |
402 | |
403 p = ngx_cpymem(p, r->method_name.data, r->method_name.len); | |
404 *p++ = ' '; | |
405 p = ngx_cpymem(p, r->uri_start, r->uri_end - r->uri_start); | |
406 *p++ = ' '; | |
407 p = ngx_cpymem(p, "HTTP/3.0", sizeof("HTTP/3.0") - 1); | |
408 | |
409 r->request_line.len = p - r->request_line.data; | |
410 | |
411 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
412 "http3 request line: \"%V\"", &r->request_line); | |
413 | |
414 ngx_str_set(&r->http_protocol, "HTTP/3.0"); | |
415 | |
416 if (ngx_http_process_request_uri(r) != NGX_OK) { | |
417 return NGX_ERROR; | |
418 } | |
419 | |
420 if (r->host_end) { | |
421 | |
422 host.len = r->host_end - r->host_start; | |
423 host.data = r->host_start; | |
424 | |
425 rc = ngx_http_validate_host(&host, r->pool, 0); | |
426 | |
427 if (rc == NGX_DECLINED) { | |
428 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, | |
429 "client sent invalid host in request line"); | |
430 goto failed; | |
431 } | |
432 | |
433 if (rc == NGX_ERROR) { | |
434 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); | |
435 return NGX_ERROR; | |
436 } | |
437 | |
438 if (ngx_http_set_virtual_server(r, &host) == NGX_ERROR) { | |
439 return NGX_ERROR; | |
440 } | |
441 | |
442 r->headers_in.server = host; | |
443 } | |
444 | |
445 if (ngx_list_init(&r->headers_in.headers, r->pool, 20, | |
446 sizeof(ngx_table_elt_t)) | |
447 != NGX_OK) | |
448 { | |
449 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); | |
450 return NGX_ERROR; | |
451 } | |
339 | 452 |
340 return NGX_OK; | 453 return NGX_OK; |
454 | |
455 failed: | |
456 | |
457 ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); | |
458 return NGX_ERROR; | |
459 } | |
460 | |
461 | |
462 static ngx_int_t | |
463 ngx_http_v3_process_request_header(ngx_http_request_t *r) | |
464 { | |
465 if (ngx_http_v3_init_pseudo_headers(r) != NGX_OK) { | |
466 return NGX_ERROR; | |
467 } | |
468 | |
469 if (r->headers_in.server.len == 0) { | |
470 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, | |
471 "client sent neither \":authority\" nor \"Host\" header"); | |
472 goto failed; | |
473 } | |
474 | |
475 if (r->headers_in.host) { | |
476 if (r->headers_in.host->value.len != r->headers_in.server.len | |
477 || ngx_memcmp(r->headers_in.host->value.data, | |
478 r->headers_in.server.data, | |
479 r->headers_in.server.len) | |
480 != 0) | |
481 { | |
482 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, | |
483 "client sent \":authority\" and \"Host\" headers " | |
484 "with different values"); | |
485 goto failed; | |
486 } | |
487 } | |
488 | |
489 if (r->headers_in.content_length) { | |
490 r->headers_in.content_length_n = | |
491 ngx_atoof(r->headers_in.content_length->value.data, | |
492 r->headers_in.content_length->value.len); | |
493 | |
494 if (r->headers_in.content_length_n == NGX_ERROR) { | |
495 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, | |
496 "client sent invalid \"Content-Length\" header"); | |
497 goto failed; | |
498 } | |
499 } | |
500 | |
501 return NGX_OK; | |
502 | |
503 failed: | |
504 | |
505 ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); | |
506 return NGX_ERROR; | |
341 } | 507 } |
342 | 508 |
343 | 509 |
344 ngx_int_t | 510 ngx_int_t |
345 ngx_http_v3_parse_request_body(ngx_http_request_t *r, ngx_buf_t *b, | 511 ngx_http_v3_parse_request_body(ngx_http_request_t *r, ngx_buf_t *b, |