Mercurial > hg > nginx-quic
comparison src/http/v3/ngx_http_v3_request.c @ 7699:1e45c02f6376 quic
HTTP/3 $request_line variable.
author | Roman Arutyunyan <arut@nginx.com> |
---|---|
date | Wed, 18 Mar 2020 20:22:16 +0300 |
parents | 31f7c697b6d9 |
children | a3257a725b3d |
comparison
equal
deleted
inserted
replaced
7698:253cf267f95a | 7699:1e45c02f6376 |
---|---|
38 | 38 |
39 | 39 |
40 ngx_int_t | 40 ngx_int_t |
41 ngx_http_v3_parse_header(ngx_http_request_t *r, ngx_buf_t *b) | 41 ngx_http_v3_parse_header(ngx_http_request_t *r, ngx_buf_t *b) |
42 { | 42 { |
43 size_t n; | |
44 u_char *p; | |
43 ngx_int_t rc; | 45 ngx_int_t rc; |
44 ngx_str_t *name, *value; | 46 ngx_str_t *name, *value; |
45 ngx_connection_t *c; | 47 ngx_connection_t *c; |
46 ngx_http_v3_parse_headers_t *st; | 48 ngx_http_v3_parse_headers_t *st; |
47 enum { | 49 enum { |
95 } | 97 } |
96 | 98 |
97 name = &st->header_rep.header.name; | 99 name = &st->header_rep.header.name; |
98 value = &st->header_rep.header.value; | 100 value = &st->header_rep.header.value; |
99 | 101 |
100 if (r->state == sw_start | 102 if (r->state == sw_start) { |
101 && ngx_http_v3_process_pseudo_header(r, name, value) != NGX_OK) | 103 |
102 { | 104 if (ngx_http_v3_process_pseudo_header(r, name, value) == NGX_OK) { |
103 if (rc == NGX_DONE) { | 105 if (rc == NGX_OK) { |
106 continue; | |
107 } | |
108 | |
109 r->state = sw_done; | |
110 | |
111 } else if (rc == NGX_OK) { | |
112 r->state = sw_prev; | |
113 | |
114 } else { | |
104 r->state = sw_last; | 115 r->state = sw_last; |
105 } else { | |
106 r->state = sw_prev; | |
107 } | 116 } |
117 | |
118 n = (r->method_end - r->method_start) + 1 | |
119 + (r->uri_end - r->uri_start) + 1 | |
120 + sizeof("HTTP/3") - 1; | |
121 | |
122 p = ngx_pnalloc(c->pool, n); | |
123 if (p == NULL) { | |
124 goto failed; | |
125 } | |
126 | |
127 r->request_start = p; | |
128 | |
129 p = ngx_cpymem(p, r->method_start, r->method_end - r->method_start); | |
130 *p++ = ' '; | |
131 p = ngx_cpymem(p, r->uri_start, r->uri_end - r->uri_start); | |
132 *p++ = ' '; | |
133 p = ngx_cpymem(p, "HTTP/3", sizeof("HTTP/3") - 1); | |
134 | |
135 r->request_end = p; | |
108 | 136 |
109 } else if (rc == NGX_DONE) { | 137 } else if (rc == NGX_DONE) { |
110 r->state = sw_done; | 138 r->state = sw_done; |
111 } | |
112 | |
113 if (r->state == sw_start) { | |
114 continue; | |
115 } | 139 } |
116 | 140 |
117 r->header_name_start = name->data; | 141 r->header_name_start = name->data; |
118 r->header_name_end = name->data + name->len; | 142 r->header_name_end = name->data + name->len; |
119 r->header_start = value->data; | 143 r->header_start = value->data; |
136 | 160 |
137 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 parse header done"); | 161 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 parse header done"); |
138 | 162 |
139 return NGX_HTTP_PARSE_HEADER_DONE; | 163 return NGX_HTTP_PARSE_HEADER_DONE; |
140 } | 164 } |
141 | |
142 #if 0 | |
143 ngx_int_t | |
144 ngx_http_v3_parse_header(ngx_http_request_t *r, ngx_buf_t *b, ngx_uint_t pseudo) | |
145 { | |
146 u_char *p, ch; | |
147 ngx_str_t name, value; | |
148 ngx_int_t rc; | |
149 ngx_uint_t length, index, insert_count, sign, base, delta_base, | |
150 huffman, dynamic, offset; | |
151 ngx_connection_t *c; | |
152 ngx_http_v3_header_t *h; | |
153 enum { | |
154 sw_start = 0, | |
155 sw_length, | |
156 sw_length_1, | |
157 sw_length_2, | |
158 sw_length_3, | |
159 sw_header_block, | |
160 sw_req_insert_count, | |
161 sw_delta_base, | |
162 sw_read_delta_base, | |
163 sw_header, | |
164 sw_old_header, | |
165 sw_header_ri, | |
166 sw_header_pbi, | |
167 sw_header_lri, | |
168 sw_header_lpbi, | |
169 sw_header_l_name_len, | |
170 sw_header_l_name, | |
171 sw_header_value_len, | |
172 sw_header_read_value_len, | |
173 sw_header_value | |
174 } state; | |
175 | |
176 c = r->connection; | |
177 | |
178 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
179 "http3 parse header, pseudo:%ui", pseudo); | |
180 | |
181 if (r->state == sw_old_header) { | |
182 r->state = sw_header; | |
183 return NGX_OK; | |
184 } | |
185 | |
186 length = r->h3_length; | |
187 index = r->h3_index; | |
188 insert_count = r->h3_insert_count; | |
189 sign = r->h3_sign; | |
190 delta_base = r->h3_delta_base; | |
191 huffman = r->h3_huffman; | |
192 dynamic = r->h3_dynamic; | |
193 offset = r->h3_offset; | |
194 | |
195 name.data = r->header_name_start; | |
196 name.len = r->header_name_end - r->header_name_start; | |
197 value.data = r->header_start; | |
198 value.len = r->header_end - r->header_start; | |
199 | |
200 if (r->state == sw_start) { | |
201 length = 1; | |
202 } | |
203 | |
204 again: | |
205 | |
206 state = r->state; | |
207 | |
208 if (state == sw_header && length == 0) { | |
209 r->state = sw_start; | |
210 return NGX_HTTP_PARSE_HEADER_DONE; | |
211 } | |
212 | |
213 for (p = b->pos; p < b->last; p++) { | |
214 | |
215 if (state >= sw_header_block && length-- == 0) { | |
216 goto failed; | |
217 } | |
218 | |
219 ch = *p; | |
220 | |
221 switch (state) { | |
222 | |
223 case sw_start: | |
224 | |
225 if (ch != NGX_HTTP_V3_FRAME_HEADERS) { | |
226 goto failed; | |
227 } | |
228 | |
229 r->request_start = p; | |
230 state = sw_length; | |
231 break; | |
232 | |
233 case sw_length: | |
234 | |
235 length = ch; | |
236 if (length & 0xc0) { | |
237 state = sw_length_1; | |
238 break; | |
239 } | |
240 | |
241 state = sw_header_block; | |
242 break; | |
243 | |
244 case sw_length_1: | |
245 | |
246 length = (length << 8) + ch; | |
247 if ((length & 0xc000) != 0x4000) { | |
248 state = sw_length_2; | |
249 break; | |
250 } | |
251 | |
252 length &= 0x3fff; | |
253 state = sw_header_block; | |
254 break; | |
255 | |
256 case sw_length_2: | |
257 | |
258 length = (length << 8) + ch; | |
259 if ((length & 0xc00000) != 0x800000) { | |
260 state = sw_length_3; | |
261 break; | |
262 } | |
263 | |
264 length &= 0x3fffff; | |
265 state = sw_header_block; | |
266 break; | |
267 | |
268 case sw_length_3: | |
269 | |
270 length = (length << 8) + ch; | |
271 length &= 0x3fffffff; | |
272 state = sw_header_block; | |
273 break; | |
274 | |
275 case sw_header_block: | |
276 | |
277 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
278 "http3 header block length:%ui", length); | |
279 | |
280 if (ch != 0xff) { | |
281 insert_count = ch; | |
282 state = sw_delta_base; | |
283 break; | |
284 } | |
285 | |
286 insert_count = 0; | |
287 state = sw_req_insert_count; | |
288 break; | |
289 | |
290 case sw_req_insert_count: | |
291 | |
292 insert_count = (insert_count << 7) + (ch & 0x7f); | |
293 if (ch & 0x80) { | |
294 break; | |
295 } | |
296 | |
297 insert_count += 0xff; | |
298 state = sw_delta_base; | |
299 break; | |
300 | |
301 case sw_delta_base: | |
302 | |
303 sign = (ch & 0x80) ? 1 : 0; | |
304 delta_base = ch & 0x7f; | |
305 | |
306 if (delta_base != 0x7f) { | |
307 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
308 "http3 header block " | |
309 "insert_count:%ui, sign:%ui, delta_base:%ui", | |
310 insert_count, sign, delta_base); | |
311 goto done; | |
312 } | |
313 | |
314 delta_base = 0; | |
315 state = sw_read_delta_base; | |
316 break; | |
317 | |
318 case sw_read_delta_base: | |
319 | |
320 delta_base = (delta_base << 7) + (ch & 0x7f); | |
321 if (ch & 0x80) { | |
322 break; | |
323 } | |
324 | |
325 delta_base += 0x7f; | |
326 | |
327 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
328 "http3 header block " | |
329 "insert_count:%ui, sign:%ui, delta_base:%ui", | |
330 insert_count, sign, delta_base); | |
331 goto done; | |
332 | |
333 case sw_header: | |
334 | |
335 index = 0; | |
336 huffman = 0; | |
337 ngx_str_null(&name); | |
338 ngx_str_null(&value); | |
339 | |
340 if (ch & 0x80) { | |
341 /* Indexed Header Field */ | |
342 | |
343 dynamic = (ch & 0x40) ? 0 : 1; | |
344 index = ch & 0x3f; | |
345 | |
346 if (index != 0x3f) { | |
347 goto done; | |
348 } | |
349 | |
350 index = 0; | |
351 state = sw_header_ri; | |
352 break; | |
353 } | |
354 | |
355 if (ch & 0x40) { | |
356 /* Literal Header Field With Name Reference */ | |
357 | |
358 dynamic = (ch & 0x10) ? 0 : 1; | |
359 index = ch & 0x0f; | |
360 | |
361 if (index != 0x0f) { | |
362 state = sw_header_value_len; | |
363 break; | |
364 } | |
365 | |
366 index = 0; | |
367 state = sw_header_lri; | |
368 break; | |
369 } | |
370 | |
371 if (ch & 0x20) { | |
372 /* Literal Header Field Without Name Reference */ | |
373 | |
374 huffman = (ch & 0x08) ? 1 : 0; | |
375 name.len = ch & 0x07; | |
376 | |
377 if (name.len == 0) { | |
378 goto failed; | |
379 } | |
380 | |
381 if (name.len != 0x07) { | |
382 offset = 0; | |
383 state = sw_header_l_name; | |
384 break; | |
385 } | |
386 | |
387 name.len = 0; | |
388 state = sw_header_l_name_len; | |
389 break; | |
390 } | |
391 | |
392 if (ch & 10) { | |
393 /* Indexed Header Field With Post-Base Index */ | |
394 | |
395 dynamic = 2; | |
396 index = ch & 0x0f; | |
397 | |
398 if (index != 0x0f) { | |
399 goto done; | |
400 } | |
401 | |
402 index = 0; | |
403 state = sw_header_pbi; | |
404 break; | |
405 } | |
406 | |
407 /* Literal Header Field With Post-Base Name Reference */ | |
408 | |
409 dynamic = 2; | |
410 index = ch & 0x07; | |
411 | |
412 if (index != 0x07) { | |
413 state = sw_header_value_len; | |
414 break; | |
415 } | |
416 | |
417 index = 0; | |
418 state = sw_header_lpbi; | |
419 break; | |
420 | |
421 case sw_header_ri: | |
422 | |
423 index = (index << 7) + (ch & 0x7f); | |
424 if (ch & 0x80) { | |
425 break; | |
426 } | |
427 | |
428 index += 0x3f; | |
429 goto done; | |
430 | |
431 case sw_header_pbi: | |
432 | |
433 index = (index << 7) + (ch & 0x7f); | |
434 if (ch & 0x80) { | |
435 break; | |
436 } | |
437 | |
438 index += 0x0f; | |
439 goto done; | |
440 | |
441 case sw_header_lri: | |
442 | |
443 index = (index << 7) + (ch & 0x7f); | |
444 if (ch & 0x80) { | |
445 break; | |
446 } | |
447 | |
448 index += 0x0f; | |
449 state = sw_header_value_len; | |
450 break; | |
451 | |
452 case sw_header_lpbi: | |
453 | |
454 index = (index << 7) + (ch & 0x7f); | |
455 if (ch & 0x80) { | |
456 break; | |
457 } | |
458 | |
459 index += 0x07; | |
460 state = sw_header_value_len; | |
461 break; | |
462 | |
463 | |
464 case sw_header_l_name_len: | |
465 | |
466 name.len = (name.len << 7) + (ch & 0x7f); | |
467 if (ch & 0x80) { | |
468 break; | |
469 } | |
470 | |
471 name.len += 0x07; | |
472 offset = 0; | |
473 state = sw_header_l_name; | |
474 break; | |
475 | |
476 case sw_header_l_name: | |
477 if (offset++ == 0) { | |
478 name.data = p; | |
479 } | |
480 | |
481 if (offset != name.len) { | |
482 break; | |
483 } | |
484 | |
485 if (huffman) { | |
486 if (ngx_http_v3_decode_huffman(c, &name) != NGX_OK) { | |
487 goto failed; | |
488 } | |
489 } | |
490 | |
491 state = sw_header_value_len; | |
492 break; | |
493 | |
494 case sw_header_value_len: | |
495 | |
496 huffman = (ch & 0x80) ? 1 : 0; | |
497 value.len = ch & 0x7f; | |
498 | |
499 if (value.len == 0) { | |
500 value.data = p; | |
501 goto done; | |
502 } | |
503 | |
504 if (value.len != 0x7f) { | |
505 offset = 0; | |
506 state = sw_header_value; | |
507 break; | |
508 } | |
509 | |
510 value.len = 0; | |
511 state = sw_header_read_value_len; | |
512 break; | |
513 | |
514 case sw_header_read_value_len: | |
515 | |
516 value.len = (value.len << 7) + (ch & 0x7f); | |
517 if (ch & 0x80) { | |
518 break; | |
519 } | |
520 | |
521 value.len += 0x7f; | |
522 offset = 0; | |
523 state = sw_header_value; | |
524 break; | |
525 | |
526 case sw_header_value: | |
527 | |
528 if (offset++ == 0) { | |
529 value.data = p; | |
530 } | |
531 | |
532 if (offset != value.len) { | |
533 break; | |
534 } | |
535 | |
536 if (huffman) { | |
537 if (ngx_http_v3_decode_huffman(c, &value) != NGX_OK) { | |
538 goto failed; | |
539 } | |
540 } | |
541 | |
542 goto done; | |
543 | |
544 case sw_old_header: | |
545 | |
546 break; | |
547 } | |
548 } | |
549 | |
550 b->pos = p; | |
551 r->state = state; | |
552 r->h3_length = length; | |
553 r->h3_index = index; | |
554 r->h3_insert_count = insert_count; | |
555 r->h3_sign = sign; | |
556 r->h3_delta_base = delta_base; | |
557 r->h3_huffman = huffman; | |
558 r->h3_dynamic = dynamic; | |
559 r->h3_offset = offset; | |
560 | |
561 /* XXX fix large reallocations */ | |
562 r->header_name_start = name.data; | |
563 r->header_name_end = name.data + name.len; | |
564 r->header_start = value.data; | |
565 r->header_end = value.data + value.len; | |
566 | |
567 /* XXX r->lowcase_index = i; */ | |
568 | |
569 return NGX_AGAIN; | |
570 | |
571 done: | |
572 | |
573 b->pos = p + 1; | |
574 r->state = sw_header; | |
575 r->h3_length = length; | |
576 r->h3_insert_count = insert_count; | |
577 r->h3_sign = sign; | |
578 r->h3_delta_base = delta_base; | |
579 | |
580 if (state < sw_header) { | |
581 if (ngx_http_v3_check_insert_count(c, insert_count) != NGX_OK) { | |
582 return NGX_DONE; | |
583 } | |
584 | |
585 goto again; | |
586 } | |
587 | |
588 if (sign == 0) { | |
589 base = insert_count + delta_base; | |
590 } else { | |
591 base = insert_count - delta_base - 1; | |
592 } | |
593 | |
594 ngx_log_debug5(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
595 "http3 header %s[%ui], base:%ui, \"%V\":\"%V\"", | |
596 dynamic ? "dynamic" : "static", index, base, &name, &value); | |
597 | |
598 if (name.data == NULL) { | |
599 | |
600 if (dynamic == 2) { | |
601 index = base - index - 1; | |
602 } else if (dynamic == 1) { | |
603 index += base; | |
604 } | |
605 | |
606 h = ngx_http_v3_lookup_table(c, dynamic, index); | |
607 if (h == NULL) { | |
608 goto failed; | |
609 } | |
610 | |
611 name = h->name; | |
612 | |
613 if (value.data == NULL) { | |
614 value = h->value; | |
615 } | |
616 } | |
617 | |
618 /* XXX ugly reallocation for the trailing '\0' */ | |
619 | |
620 p = ngx_pnalloc(c->pool, name.len + value.len + 2); | |
621 if (p == NULL) { | |
622 return NGX_ERROR; | |
623 } | |
624 | |
625 ngx_memcpy(p, name.data, name.len); | |
626 name.data = p; | |
627 ngx_memcpy(p + name.len + 1, value.data, value.len); | |
628 value.data = p + name.len + 1; | |
629 | |
630 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
631 "http3 header \"%V\":\"%V\"", &name, &value); | |
632 | |
633 if (pseudo) { | |
634 rc = ngx_http_v3_process_pseudo_header(r, &name, &value); | |
635 | |
636 if (rc == NGX_ERROR) { | |
637 goto failed; | |
638 } | |
639 | |
640 if (rc == NGX_OK) { | |
641 r->request_end = p + 1; | |
642 goto again; | |
643 } | |
644 | |
645 /* rc == NGX_DONE */ | |
646 | |
647 r->state = sw_old_header; | |
648 } | |
649 | |
650 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
651 "http3 header left:%ui", length); | |
652 | |
653 r->header_name_start = name.data; | |
654 r->header_name_end = name.data + name.len; | |
655 r->header_start = value.data; | |
656 r->header_end = value.data + value.len; | |
657 r->header_hash = ngx_hash_key(name.data, name.len); /* XXX */ | |
658 | |
659 /* XXX r->lowcase_index = i; */ | |
660 | |
661 return NGX_OK; | |
662 | |
663 failed: | |
664 | |
665 return NGX_HTTP_PARSE_INVALID_REQUEST; | |
666 } | |
667 #endif | |
668 | 165 |
669 | 166 |
670 static ngx_int_t | 167 static ngx_int_t |
671 ngx_http_v3_process_pseudo_header(ngx_http_request_t *r, ngx_str_t *name, | 168 ngx_http_v3_process_pseudo_header(ngx_http_request_t *r, ngx_str_t *name, |
672 ngx_str_t *value) | 169 ngx_str_t *value) |
673 { | 170 { |
674 ngx_uint_t i; | 171 ngx_uint_t i; |
675 ngx_connection_t *c; | 172 ngx_connection_t *c; |
676 | 173 |
677 if (name->len == 0 || name->data[0] != ':') { | 174 if (name->len == 0 || name->data[0] != ':') { |
678 return NGX_DECLINED; | 175 return NGX_DONE; |
679 } | 176 } |
680 | 177 |
681 c = r->connection; | 178 c = r->connection; |
682 | 179 |
683 if (name->len == 7 && ngx_strncmp(name->data, ":method", 7) == 0) { | 180 if (name->len == 7 && ngx_strncmp(name->data, ":method", 7) == 0) { |