Mercurial > hg > nginx
comparison src/http/v3/ngx_http_v3_parse.c @ 8226:268f4389130d quic
Refactored HTTP/3 parser.
author | Roman Arutyunyan <arut@nginx.com> |
---|---|
date | Wed, 18 Mar 2020 13:46:35 +0300 |
parents | |
children | 36af1dab65e5 |
comparison
equal
deleted
inserted
replaced
8225:714a19dba6af | 8226:268f4389130d |
---|---|
1 | |
2 /* | |
3 * Copyright (C) Roman Arutyunyan | |
4 * Copyright (C) Nginx, Inc. | |
5 */ | |
6 | |
7 | |
8 #include <ngx_config.h> | |
9 #include <ngx_core.h> | |
10 #include <ngx_http.h> | |
11 | |
12 | |
13 ngx_int_t | |
14 ngx_http_v3_parse_varlen_int(ngx_connection_t *c, | |
15 ngx_http_v3_parse_varlen_int_t *st, u_char ch) | |
16 { | |
17 enum { | |
18 sw_start = 0, | |
19 sw_length_2, | |
20 sw_length_3, | |
21 sw_length_4, | |
22 sw_length_5, | |
23 sw_length_6, | |
24 sw_length_7, | |
25 sw_length_8 | |
26 }; | |
27 | |
28 switch (st->state) { | |
29 | |
30 case sw_start: | |
31 | |
32 st->value = ch; | |
33 if (st->value & 0xc0) { | |
34 st->state = sw_length_2; | |
35 break; | |
36 } | |
37 | |
38 goto done; | |
39 | |
40 case sw_length_2: | |
41 | |
42 st->value = (st->value << 8) + ch; | |
43 if ((st->value & 0xc000) == 0x4000) { | |
44 st->value &= 0x3fff; | |
45 goto done; | |
46 } | |
47 | |
48 st->state = sw_length_3; | |
49 break; | |
50 | |
51 case sw_length_4: | |
52 | |
53 st->value = (st->value << 8) + ch; | |
54 if ((st->value & 0xc0000000) == 0x80000000) { | |
55 st->value &= 0x3fffffff; | |
56 goto done; | |
57 } | |
58 | |
59 st->state = sw_length_5; | |
60 break; | |
61 | |
62 case sw_length_3: | |
63 case sw_length_5: | |
64 case sw_length_6: | |
65 case sw_length_7: | |
66 | |
67 st->value = (st->value << 8) + ch; | |
68 st->state++; | |
69 break; | |
70 | |
71 case sw_length_8: | |
72 | |
73 st->value = (st->value << 8) + ch; | |
74 st->value &= 0x3fffffffffffffff; | |
75 goto done; | |
76 } | |
77 | |
78 return NGX_AGAIN; | |
79 | |
80 done: | |
81 | |
82 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
83 "http3 parse varlen int %uL", st->value); | |
84 | |
85 st->state = sw_start; | |
86 return NGX_DONE; | |
87 } | |
88 | |
89 | |
90 ngx_int_t | |
91 ngx_http_v3_parse_prefix_int(ngx_connection_t *c, | |
92 ngx_http_v3_parse_prefix_int_t *st, ngx_uint_t prefix, u_char ch) | |
93 { | |
94 enum { | |
95 sw_start = 0, | |
96 sw_value | |
97 }; | |
98 | |
99 switch (st->state) { | |
100 | |
101 case sw_start: | |
102 | |
103 st->mask = (1 << prefix) - 1; | |
104 st->value = (ch & st->mask); | |
105 | |
106 if (st->value != st->mask) { | |
107 goto done; | |
108 } | |
109 | |
110 st->value = 0; | |
111 st->state = sw_value; | |
112 break; | |
113 | |
114 case sw_value: | |
115 | |
116 st->value = (st->value << 7) + (ch & 0x7f); | |
117 if (ch & 0x80) { | |
118 break; | |
119 } | |
120 | |
121 st->value += st->mask; | |
122 goto done; | |
123 } | |
124 | |
125 return NGX_AGAIN; | |
126 | |
127 done: | |
128 | |
129 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
130 "http3 parse prefix int %uL", st->value); | |
131 | |
132 st->state = sw_start; | |
133 return NGX_DONE; | |
134 } | |
135 | |
136 | |
137 ngx_int_t | |
138 ngx_http_v3_parse_headers(ngx_connection_t *c, ngx_http_v3_parse_headers_t *st, | |
139 u_char ch) | |
140 { | |
141 ngx_int_t rc; | |
142 enum { | |
143 sw_start = 0, | |
144 sw_length, | |
145 sw_prefix, | |
146 sw_header_rep, | |
147 sw_done | |
148 }; | |
149 | |
150 switch (st->state) { | |
151 | |
152 case sw_start: | |
153 | |
154 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 parse headers"); | |
155 | |
156 if (ch != NGX_HTTP_V3_FRAME_HEADERS) { | |
157 return NGX_ERROR; | |
158 } | |
159 | |
160 st->state = sw_length; | |
161 break; | |
162 | |
163 case sw_length: | |
164 | |
165 if (ngx_http_v3_parse_varlen_int(c, &st->vlint, ch) != NGX_DONE) { | |
166 break; | |
167 } | |
168 | |
169 st->length = st->vlint.value; | |
170 | |
171 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
172 "http3 parse headers len:%ui", st->length); | |
173 | |
174 st->state = sw_prefix; | |
175 break; | |
176 | |
177 case sw_prefix: | |
178 | |
179 if (st->length-- == 0) { | |
180 return NGX_ERROR; | |
181 } | |
182 | |
183 rc = ngx_http_v3_parse_header_block_prefix(c, &st->prefix, ch); | |
184 | |
185 if (rc == NGX_ERROR) { | |
186 return NGX_ERROR; | |
187 } | |
188 | |
189 if (rc != NGX_DONE) { | |
190 break; | |
191 } | |
192 | |
193 if (st->length == 0) { | |
194 return NGX_ERROR; | |
195 } | |
196 | |
197 st->state = sw_header_rep; | |
198 break; | |
199 | |
200 case sw_header_rep: | |
201 | |
202 rc = ngx_http_v3_parse_header_rep(c, &st->header_rep, st->prefix.base, | |
203 ch); | |
204 | |
205 if (rc == NGX_ERROR) { | |
206 return NGX_ERROR; | |
207 } | |
208 | |
209 if (--st->length == 0) { | |
210 if (rc != NGX_DONE) { | |
211 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "XXX len"); | |
212 return NGX_ERROR; | |
213 } | |
214 | |
215 goto done; | |
216 } | |
217 | |
218 if (rc == NGX_DONE) { | |
219 return NGX_OK; | |
220 } | |
221 | |
222 break; | |
223 } | |
224 | |
225 return NGX_AGAIN; | |
226 | |
227 done: | |
228 | |
229 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 parse headers done"); | |
230 | |
231 st->state = sw_start; | |
232 return NGX_DONE; | |
233 } | |
234 | |
235 | |
236 ngx_int_t | |
237 ngx_http_v3_parse_header_block_prefix(ngx_connection_t *c, | |
238 ngx_http_v3_parse_header_block_prefix_t *st, u_char ch) | |
239 { | |
240 enum { | |
241 sw_start = 0, | |
242 sw_req_insert_count, | |
243 sw_delta_base, | |
244 sw_read_delta_base | |
245 }; | |
246 | |
247 switch (st->state) { | |
248 | |
249 case sw_start: | |
250 | |
251 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
252 "http3 parse header block prefix"); | |
253 | |
254 st->state = sw_req_insert_count; | |
255 | |
256 /* fall through */ | |
257 | |
258 case sw_req_insert_count: | |
259 | |
260 if (ngx_http_v3_parse_prefix_int(c, &st->pint, 8, ch) != NGX_DONE) { | |
261 break; | |
262 } | |
263 | |
264 st->insert_count = st->pint.value; | |
265 st->state = sw_delta_base; | |
266 break; | |
267 | |
268 case sw_delta_base: | |
269 | |
270 st->sign = (ch & 0x80) ? 1 : 0; | |
271 st->state = sw_read_delta_base; | |
272 | |
273 /* fall through */ | |
274 | |
275 case sw_read_delta_base: | |
276 | |
277 if (ngx_http_v3_parse_prefix_int(c, &st->pint, 7, ch) != NGX_DONE) { | |
278 break; | |
279 } | |
280 | |
281 st->delta_base = st->pint.value; | |
282 goto done; | |
283 } | |
284 | |
285 return NGX_AGAIN; | |
286 | |
287 done: | |
288 | |
289 if (st->sign) { | |
290 st->base = st->insert_count - st->delta_base - 1; | |
291 } else { | |
292 st->base = st->insert_count + st->delta_base; | |
293 } | |
294 | |
295 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
296 "http3 parse header block prefix done " | |
297 "i:%ui, s:%ui, d:%ui, base:%uL", | |
298 st->insert_count, st->sign, st->delta_base, st->base); | |
299 | |
300 st->state = sw_start; | |
301 return NGX_DONE; | |
302 } | |
303 | |
304 | |
305 ngx_int_t | |
306 ngx_http_v3_parse_header_rep(ngx_connection_t *c, | |
307 ngx_http_v3_parse_header_rep_t *st, ngx_uint_t base, u_char ch) | |
308 { | |
309 ngx_int_t rc; | |
310 enum { | |
311 sw_start = 0, | |
312 sw_header_ri, | |
313 sw_header_lri, | |
314 sw_header_l, | |
315 sw_header_pbi, | |
316 sw_header_lpbi | |
317 }; | |
318 | |
319 if (st->state == sw_start) { | |
320 | |
321 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
322 "http3 parse header representation"); | |
323 | |
324 ngx_memzero(&st->header, sizeof(ngx_http_v3_parse_header_t)); | |
325 | |
326 st->header.base = base; | |
327 | |
328 if (ch & 0x80) { | |
329 /* Indexed Header Field */ | |
330 | |
331 st->state = sw_header_ri; | |
332 | |
333 } else if (ch & 0x40) { | |
334 /* Literal Header Field With Name Reference */ | |
335 | |
336 st->state = sw_header_lri; | |
337 | |
338 } else if (ch & 0x20) { | |
339 /* Literal Header Field Without Name Reference */ | |
340 | |
341 st->state = sw_header_l; | |
342 | |
343 } else if (ch & 0x10) { | |
344 /* Indexed Header Field With Post-Base Index */ | |
345 | |
346 st->state = sw_header_pbi; | |
347 | |
348 } else { | |
349 /* Literal Header Field With Post-Base Name Reference */ | |
350 | |
351 st->state = sw_header_lpbi; | |
352 } | |
353 } | |
354 | |
355 switch (st->state) { | |
356 | |
357 case sw_header_ri: | |
358 rc = ngx_http_v3_parse_header_ri(c, &st->header, ch); | |
359 break; | |
360 | |
361 case sw_header_lri: | |
362 rc = ngx_http_v3_parse_header_lri(c, &st->header, ch); | |
363 break; | |
364 | |
365 case sw_header_l: | |
366 rc = ngx_http_v3_parse_header_l(c, &st->header, ch); | |
367 break; | |
368 | |
369 case sw_header_pbi: | |
370 rc = ngx_http_v3_parse_header_pbi(c, &st->header, ch); | |
371 break; | |
372 | |
373 case sw_header_lpbi: | |
374 rc = ngx_http_v3_parse_header_lpbi(c, &st->header, ch); | |
375 break; | |
376 | |
377 default: | |
378 rc = NGX_OK; | |
379 } | |
380 | |
381 if (rc == NGX_ERROR) { | |
382 return NGX_ERROR; | |
383 } | |
384 | |
385 if (rc == NGX_AGAIN) { | |
386 return NGX_AGAIN; | |
387 } | |
388 | |
389 /* rc == NGX_DONE */ | |
390 | |
391 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
392 "http3 parse header representation done"); | |
393 | |
394 st->state = sw_start; | |
395 return NGX_DONE; | |
396 } | |
397 | |
398 | |
399 ngx_int_t | |
400 ngx_http_v3_parse_literal(ngx_connection_t *c, ngx_http_v3_parse_literal_t *st, | |
401 u_char ch) | |
402 { | |
403 ngx_uint_t n; | |
404 enum { | |
405 sw_start = 0, | |
406 sw_value | |
407 }; | |
408 | |
409 switch (st->state) { | |
410 | |
411 case sw_start: | |
412 | |
413 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
414 "http3 parse literal huff:%ui, len:%ui", | |
415 st->huffman, st->length); | |
416 | |
417 n = st->length; | |
418 | |
419 if (st->huffman) { | |
420 n = n * 8 / 5; | |
421 st->huffstate = 0; | |
422 } | |
423 | |
424 st->last = ngx_pnalloc(c->pool, n + 1); | |
425 if (st->last == NULL) { | |
426 return NGX_ERROR; | |
427 } | |
428 | |
429 st->value.data = st->last; | |
430 st->state = sw_value; | |
431 | |
432 /* fall through */ | |
433 | |
434 case sw_value: | |
435 | |
436 if (st->huffman) { | |
437 if (ngx_http_v2_huff_decode(&st->huffstate, &ch, 1, &st->last, | |
438 st->length == 1, c->log) | |
439 != NGX_OK) | |
440 { | |
441 return NGX_ERROR; | |
442 } | |
443 | |
444 } else { | |
445 *st->last++ = ch; | |
446 } | |
447 | |
448 if (--st->length) { | |
449 break; | |
450 } | |
451 | |
452 st->value.len = st->last - st->value.data; | |
453 *st->last = '\0'; | |
454 goto done; | |
455 } | |
456 | |
457 return NGX_AGAIN; | |
458 | |
459 done: | |
460 | |
461 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
462 "http3 parse literal done \"%V\"", &st->value); | |
463 | |
464 st->state = sw_start; | |
465 return NGX_DONE; | |
466 } | |
467 | |
468 | |
469 ngx_int_t | |
470 ngx_http_v3_parse_header_ri(ngx_connection_t *c, ngx_http_v3_parse_header_t *st, | |
471 u_char ch) | |
472 { | |
473 ngx_http_v3_header_t *h; | |
474 enum { | |
475 sw_start = 0, | |
476 sw_index | |
477 }; | |
478 | |
479 switch (st->state) { | |
480 | |
481 case sw_start: | |
482 | |
483 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 parse header ri"); | |
484 | |
485 st->dynamic = (ch & 0x40) ? 0 : 1; | |
486 st->state = sw_index; | |
487 | |
488 /* fall through */ | |
489 | |
490 case sw_index: | |
491 | |
492 if (ngx_http_v3_parse_prefix_int(c, &st->pint, 6, ch) != NGX_DONE) { | |
493 break; | |
494 } | |
495 | |
496 st->index = st->pint.value; | |
497 goto done; | |
498 } | |
499 | |
500 return NGX_AGAIN; | |
501 | |
502 done: | |
503 | |
504 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
505 "http3 parse header ri done %s%ui]", | |
506 st->dynamic ? "dynamic[-" : "static[", st->index); | |
507 | |
508 if (st->dynamic) { | |
509 st->index = st->base - st->index - 1; | |
510 } | |
511 | |
512 h = ngx_http_v3_lookup_table(c, st->dynamic, st->index); | |
513 if (h == NULL) { | |
514 return NGX_ERROR; | |
515 } | |
516 | |
517 st->name = h->name; | |
518 st->value = h->value; | |
519 st->state = sw_start; | |
520 | |
521 return NGX_DONE; | |
522 } | |
523 | |
524 | |
525 ngx_int_t | |
526 ngx_http_v3_parse_header_lri(ngx_connection_t *c, | |
527 ngx_http_v3_parse_header_t *st, u_char ch) | |
528 { | |
529 ngx_int_t rc; | |
530 ngx_http_v3_header_t *h; | |
531 enum { | |
532 sw_start = 0, | |
533 sw_index, | |
534 sw_value_len, | |
535 sw_read_value_len, | |
536 sw_value | |
537 }; | |
538 | |
539 switch (st->state) { | |
540 | |
541 case sw_start: | |
542 | |
543 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 parse header lri"); | |
544 | |
545 st->dynamic = (ch & 0x10) ? 0 : 1; | |
546 st->state = sw_index; | |
547 | |
548 /* fall through */ | |
549 | |
550 case sw_index: | |
551 | |
552 if (ngx_http_v3_parse_prefix_int(c, &st->pint, 4, ch) != NGX_DONE) { | |
553 break; | |
554 } | |
555 | |
556 st->index = st->pint.value; | |
557 st->state = sw_value_len; | |
558 break; | |
559 | |
560 case sw_value_len: | |
561 | |
562 st->literal.huffman = (ch & 0x80) ? 1 : 0; | |
563 st->state = sw_read_value_len; | |
564 | |
565 /* fall through */ | |
566 | |
567 case sw_read_value_len: | |
568 | |
569 if (ngx_http_v3_parse_prefix_int(c, &st->pint, 7, ch) != NGX_DONE) { | |
570 break; | |
571 } | |
572 | |
573 st->literal.length = st->pint.value; | |
574 if (st->literal.length == 0) { | |
575 goto done; | |
576 } | |
577 | |
578 st->state = sw_value; | |
579 break; | |
580 | |
581 case sw_value: | |
582 | |
583 rc = ngx_http_v3_parse_literal(c, &st->literal, ch); | |
584 | |
585 if (rc == NGX_ERROR) { | |
586 return NGX_ERROR; | |
587 } | |
588 | |
589 if (rc == NGX_DONE) { | |
590 st->value = st->literal.value; | |
591 goto done; | |
592 } | |
593 | |
594 break; | |
595 } | |
596 | |
597 return NGX_AGAIN; | |
598 | |
599 done: | |
600 | |
601 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
602 "http3 parse header lri done %s%ui] \"%V\"", | |
603 st->dynamic ? "dynamic[-" : "static[", | |
604 st->index, &st->value); | |
605 | |
606 if (st->dynamic) { | |
607 st->index = st->base - st->index - 1; | |
608 } | |
609 | |
610 h = ngx_http_v3_lookup_table(c, st->dynamic, st->index); | |
611 if (h == NULL) { | |
612 return NGX_ERROR; | |
613 } | |
614 | |
615 st->name = h->name; | |
616 st->state = sw_start; | |
617 return NGX_DONE; | |
618 } | |
619 | |
620 | |
621 ngx_int_t | |
622 ngx_http_v3_parse_header_l(ngx_connection_t *c, | |
623 ngx_http_v3_parse_header_t *st, u_char ch) | |
624 { | |
625 ngx_int_t rc; | |
626 enum { | |
627 sw_start = 0, | |
628 sw_name_len, | |
629 sw_name, | |
630 sw_value_len, | |
631 sw_read_value_len, | |
632 sw_value | |
633 }; | |
634 | |
635 switch (st->state) { | |
636 | |
637 case sw_start: | |
638 | |
639 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 parse header l"); | |
640 | |
641 st->literal.huffman = (ch & 0x08) ? 1 : 0; | |
642 st->state = sw_name_len; | |
643 | |
644 /* fall through */ | |
645 | |
646 case sw_name_len: | |
647 | |
648 if (ngx_http_v3_parse_prefix_int(c, &st->pint, 3, ch) != NGX_DONE) { | |
649 break; | |
650 } | |
651 | |
652 st->literal.length = st->pint.value; | |
653 if (st->literal.length == 0) { | |
654 return NGX_ERROR; | |
655 } | |
656 | |
657 st->state = sw_name; | |
658 break; | |
659 | |
660 case sw_name: | |
661 | |
662 rc = ngx_http_v3_parse_literal(c, &st->literal, ch); | |
663 | |
664 if (rc == NGX_ERROR) { | |
665 return NGX_ERROR; | |
666 } | |
667 | |
668 if (rc == NGX_DONE) { | |
669 st->name = st->literal.value; | |
670 st->state = sw_value_len; | |
671 } | |
672 | |
673 break; | |
674 | |
675 case sw_value_len: | |
676 | |
677 st->literal.huffman = (ch & 0x80) ? 1 : 0; | |
678 st->state = sw_read_value_len; | |
679 | |
680 /* fall through */ | |
681 | |
682 case sw_read_value_len: | |
683 | |
684 if (ngx_http_v3_parse_prefix_int(c, &st->pint, 7, ch) != NGX_DONE) { | |
685 break; | |
686 } | |
687 | |
688 st->literal.length = st->pint.value; | |
689 if (st->literal.length == 0) { | |
690 goto done; | |
691 } | |
692 | |
693 st->state = sw_value; | |
694 break; | |
695 | |
696 case sw_value: | |
697 | |
698 rc = ngx_http_v3_parse_literal(c, &st->literal, ch); | |
699 | |
700 if (rc == NGX_ERROR) { | |
701 return NGX_ERROR; | |
702 } | |
703 | |
704 if (rc == NGX_DONE) { | |
705 st->value = st->literal.value; | |
706 goto done; | |
707 } | |
708 | |
709 break; | |
710 } | |
711 | |
712 return NGX_AGAIN; | |
713 | |
714 done: | |
715 | |
716 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
717 "http3 parse header l done \"%V\" \"%V\"", | |
718 &st->name, &st->value); | |
719 | |
720 st->state = sw_start; | |
721 return NGX_DONE; | |
722 } | |
723 | |
724 | |
725 ngx_int_t | |
726 ngx_http_v3_parse_header_pbi(ngx_connection_t *c, | |
727 ngx_http_v3_parse_header_t *st, u_char ch) | |
728 { | |
729 ngx_http_v3_header_t *h; | |
730 enum { | |
731 sw_start = 0, | |
732 sw_index | |
733 }; | |
734 | |
735 switch (st->state) { | |
736 | |
737 case sw_start: | |
738 | |
739 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 parse header pbi"); | |
740 | |
741 st->state = sw_index; | |
742 | |
743 /* fall through */ | |
744 | |
745 case sw_index: | |
746 | |
747 if (ngx_http_v3_parse_prefix_int(c, &st->pint, 4, ch) != NGX_DONE) { | |
748 break; | |
749 } | |
750 | |
751 st->index = st->pint.value; | |
752 goto done; | |
753 } | |
754 | |
755 return NGX_AGAIN; | |
756 | |
757 done: | |
758 | |
759 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
760 "http3 parse header pbi done dynamic[+%ui]", st->index); | |
761 | |
762 h = ngx_http_v3_lookup_table(c, 1, st->base + st->index); | |
763 if (h == NULL) { | |
764 return NGX_ERROR; | |
765 } | |
766 | |
767 st->name = h->name; | |
768 st->value = h->value; | |
769 st->state = sw_start; | |
770 return NGX_DONE; | |
771 } | |
772 | |
773 | |
774 ngx_int_t | |
775 ngx_http_v3_parse_header_lpbi(ngx_connection_t *c, | |
776 ngx_http_v3_parse_header_t *st, u_char ch) | |
777 { | |
778 ngx_int_t rc; | |
779 ngx_http_v3_header_t *h; | |
780 enum { | |
781 sw_start = 0, | |
782 sw_index, | |
783 sw_value_len, | |
784 sw_read_value_len, | |
785 sw_value | |
786 }; | |
787 | |
788 switch (st->state) { | |
789 | |
790 case sw_start: | |
791 | |
792 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
793 "http3 parse header lpbi"); | |
794 | |
795 st->state = sw_index; | |
796 | |
797 /* fall through */ | |
798 | |
799 case sw_index: | |
800 | |
801 if (ngx_http_v3_parse_prefix_int(c, &st->pint, 3, ch) != NGX_DONE) { | |
802 break; | |
803 } | |
804 | |
805 st->index = st->pint.value; | |
806 st->state = sw_value_len; | |
807 break; | |
808 | |
809 case sw_value_len: | |
810 | |
811 st->literal.huffman = (ch & 0x80) ? 1 : 0; | |
812 st->state = sw_read_value_len; | |
813 | |
814 /* fall through */ | |
815 | |
816 case sw_read_value_len: | |
817 | |
818 if (ngx_http_v3_parse_prefix_int(c, &st->pint, 7, ch) != NGX_DONE) { | |
819 break; | |
820 } | |
821 | |
822 st->literal.length = st->pint.value; | |
823 if (st->literal.length == 0) { | |
824 goto done; | |
825 } | |
826 | |
827 st->state = sw_value; | |
828 break; | |
829 | |
830 case sw_value: | |
831 | |
832 rc = ngx_http_v3_parse_literal(c, &st->literal, ch); | |
833 | |
834 if (rc == NGX_ERROR) { | |
835 return NGX_ERROR; | |
836 } | |
837 | |
838 if (rc == NGX_DONE) { | |
839 st->value = st->literal.value; | |
840 goto done; | |
841 } | |
842 | |
843 break; | |
844 } | |
845 | |
846 return NGX_AGAIN; | |
847 | |
848 done: | |
849 | |
850 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
851 "http3 parse header lpbi done dynamic[+%ui] \"%V\"", | |
852 st->index, &st->value); | |
853 | |
854 h = ngx_http_v3_lookup_table(c, 1, st->base + st->index); | |
855 if (h == NULL) { | |
856 return NGX_ERROR; | |
857 } | |
858 | |
859 st->name = h->name; | |
860 st->state = sw_start; | |
861 return NGX_DONE; | |
862 } | |
863 | |
864 | |
865 ngx_int_t | |
866 ngx_http_v3_parse_control(ngx_connection_t *c, void *data, u_char ch) | |
867 { | |
868 ngx_http_v3_parse_control_t *st = data; | |
869 | |
870 ngx_int_t rc; | |
871 enum { | |
872 sw_start = 0, | |
873 sw_type, | |
874 sw_length, | |
875 sw_settings, | |
876 sw_max_push_id, | |
877 sw_skip | |
878 }; | |
879 | |
880 switch (st->state) { | |
881 | |
882 case sw_start: | |
883 | |
884 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 parse control"); | |
885 | |
886 st->state = sw_type; | |
887 | |
888 /* fall through */ | |
889 | |
890 case sw_type: | |
891 | |
892 if (ngx_http_v3_parse_varlen_int(c, &st->vlint, ch) != NGX_DONE) { | |
893 break; | |
894 } | |
895 | |
896 st->type = st->vlint.value; | |
897 | |
898 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
899 "http3 parse frame type:%ui", st->type); | |
900 | |
901 st->state = sw_length; | |
902 break; | |
903 | |
904 case sw_length: | |
905 | |
906 if (ngx_http_v3_parse_varlen_int(c, &st->vlint, ch) != NGX_DONE) { | |
907 break; | |
908 } | |
909 | |
910 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
911 "http3 parse frame len:%uL", st->vlint.value); | |
912 | |
913 st->length = st->vlint.value; | |
914 if (st->length == 0) { | |
915 st->state = sw_type; | |
916 break; | |
917 } | |
918 | |
919 switch (st->type) { | |
920 | |
921 case NGX_HTTP_V3_FRAME_SETTINGS: | |
922 st->state = sw_settings; | |
923 break; | |
924 | |
925 case NGX_HTTP_V3_FRAME_MAX_PUSH_ID: | |
926 st->state = sw_max_push_id; | |
927 break; | |
928 | |
929 default: | |
930 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
931 "http3 parse skip unknown frame"); | |
932 st->state = sw_skip; | |
933 } | |
934 | |
935 break; | |
936 | |
937 case sw_settings: | |
938 | |
939 rc = ngx_http_v3_parse_settings(c, &st->settings, ch); | |
940 | |
941 if (rc == NGX_ERROR) { | |
942 return NGX_ERROR; | |
943 } | |
944 | |
945 if (--st->length > 0) { | |
946 break; | |
947 } | |
948 | |
949 if (rc != NGX_DONE) { | |
950 return NGX_ERROR; | |
951 } | |
952 | |
953 st->state = sw_type; | |
954 break; | |
955 | |
956 case sw_max_push_id: | |
957 | |
958 if (ngx_http_v3_parse_varlen_int(c, &st->vlint, ch) != NGX_DONE) { | |
959 break; | |
960 } | |
961 | |
962 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
963 "http3 parse MAX_PUSH_ID:%uL", st->vlint.value); | |
964 | |
965 st->state = sw_type; | |
966 break; | |
967 | |
968 case sw_skip: | |
969 | |
970 if (--st->length == 0) { | |
971 st->state = sw_type; | |
972 } | |
973 | |
974 break; | |
975 } | |
976 | |
977 return NGX_AGAIN; | |
978 } | |
979 | |
980 | |
981 ngx_int_t | |
982 ngx_http_v3_parse_settings(ngx_connection_t *c, | |
983 ngx_http_v3_parse_settings_t *st, u_char ch) | |
984 { | |
985 enum { | |
986 sw_start = 0, | |
987 sw_id, | |
988 sw_value | |
989 }; | |
990 | |
991 switch (st->state) { | |
992 | |
993 case sw_start: | |
994 | |
995 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 parse settings"); | |
996 | |
997 st->state = sw_id; | |
998 | |
999 /* fall through */ | |
1000 | |
1001 case sw_id: | |
1002 | |
1003 if (ngx_http_v3_parse_varlen_int(c, &st->vlint, ch) != NGX_DONE) { | |
1004 break; | |
1005 } | |
1006 | |
1007 st->id = st->vlint.value; | |
1008 st->state = sw_value; | |
1009 break; | |
1010 | |
1011 case sw_value: | |
1012 | |
1013 if (ngx_http_v3_parse_varlen_int(c, &st->vlint, ch) != NGX_DONE) { | |
1014 break; | |
1015 } | |
1016 | |
1017 if (ngx_http_v3_set_param(c, st->id, st->vlint.value) != NGX_OK) { | |
1018 return NGX_ERROR; | |
1019 } | |
1020 | |
1021 goto done; | |
1022 } | |
1023 | |
1024 return NGX_AGAIN; | |
1025 | |
1026 done: | |
1027 | |
1028 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 parse settings done"); | |
1029 | |
1030 st->state = sw_start; | |
1031 return NGX_DONE; | |
1032 } | |
1033 | |
1034 | |
1035 ngx_int_t | |
1036 ngx_http_v3_parse_encoder(ngx_connection_t *c, void *data, u_char ch) | |
1037 { | |
1038 ngx_http_v3_parse_encoder_t *st = data; | |
1039 | |
1040 ngx_int_t rc; | |
1041 enum { | |
1042 sw_start = 0, | |
1043 sw_inr, | |
1044 sw_iwnr, | |
1045 sw_capacity, | |
1046 sw_duplicate | |
1047 }; | |
1048 | |
1049 if (st->state == sw_start) { | |
1050 | |
1051 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
1052 "http3 parse encoder instruction"); | |
1053 | |
1054 if (ch & 0x80) { | |
1055 /* Insert With Name Reference */ | |
1056 | |
1057 st->state = sw_inr; | |
1058 | |
1059 } else if (ch & 0x40) { | |
1060 /* Insert Without Name Reference */ | |
1061 | |
1062 st->state = sw_iwnr; | |
1063 | |
1064 } else if (ch & 0x20) { | |
1065 /* Set Dynamic Table Capacity */ | |
1066 | |
1067 st->state = sw_capacity; | |
1068 | |
1069 } else { | |
1070 /* Duplicate */ | |
1071 | |
1072 st->state = sw_duplicate; | |
1073 } | |
1074 } | |
1075 | |
1076 switch (st->state) { | |
1077 | |
1078 case sw_inr: | |
1079 | |
1080 rc = ngx_http_v3_parse_header_inr(c, &st->header, ch); | |
1081 | |
1082 if (rc == NGX_ERROR) { | |
1083 return NGX_ERROR; | |
1084 } | |
1085 | |
1086 if (rc != NGX_DONE) { | |
1087 break; | |
1088 } | |
1089 | |
1090 goto done; | |
1091 | |
1092 case sw_iwnr: | |
1093 | |
1094 rc = ngx_http_v3_parse_header_iwnr(c, &st->header, ch); | |
1095 | |
1096 if (rc == NGX_ERROR) { | |
1097 return NGX_ERROR; | |
1098 } | |
1099 | |
1100 if (rc != NGX_DONE) { | |
1101 break; | |
1102 } | |
1103 | |
1104 goto done; | |
1105 | |
1106 case sw_capacity: | |
1107 | |
1108 if (ngx_http_v3_parse_prefix_int(c, &st->pint, 5, ch) != NGX_DONE) { | |
1109 break; | |
1110 } | |
1111 | |
1112 if (ngx_http_v3_set_capacity(c, st->pint.value) != NGX_OK) { | |
1113 return NGX_ERROR; | |
1114 } | |
1115 | |
1116 goto done; | |
1117 | |
1118 case sw_duplicate: | |
1119 | |
1120 if (ngx_http_v3_parse_prefix_int(c, &st->pint, 5, ch) != NGX_DONE) { | |
1121 break; | |
1122 } | |
1123 | |
1124 if (ngx_http_v3_duplicate(c, st->pint.value) != NGX_OK) { | |
1125 return NGX_ERROR; | |
1126 } | |
1127 | |
1128 goto done; | |
1129 } | |
1130 | |
1131 return NGX_AGAIN; | |
1132 | |
1133 done: | |
1134 | |
1135 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
1136 "http3 parse encoder instruction done"); | |
1137 | |
1138 st->state = sw_start; | |
1139 return NGX_DONE; | |
1140 } | |
1141 | |
1142 | |
1143 ngx_int_t | |
1144 ngx_http_v3_parse_header_inr(ngx_connection_t *c, | |
1145 ngx_http_v3_parse_header_t *st, u_char ch) | |
1146 { | |
1147 ngx_int_t rc; | |
1148 enum { | |
1149 sw_start = 0, | |
1150 sw_name_index, | |
1151 sw_value_len, | |
1152 sw_read_value_len, | |
1153 sw_value | |
1154 }; | |
1155 | |
1156 switch (st->state) { | |
1157 | |
1158 case sw_start: | |
1159 | |
1160 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 parse header inr"); | |
1161 | |
1162 st->dynamic = (ch & 0x40) ? 0 : 1; | |
1163 st->state = sw_name_index; | |
1164 | |
1165 /* fall through */ | |
1166 | |
1167 case sw_name_index: | |
1168 | |
1169 if (ngx_http_v3_parse_prefix_int(c, &st->pint, 6, ch) != NGX_DONE) { | |
1170 break; | |
1171 } | |
1172 | |
1173 st->index = st->pint.value; | |
1174 st->state = sw_value_len; | |
1175 break; | |
1176 | |
1177 case sw_value_len: | |
1178 | |
1179 st->literal.huffman = (ch & 0x80) ? 1 : 0; | |
1180 st->state = sw_read_value_len; | |
1181 | |
1182 /* fall through */ | |
1183 | |
1184 case sw_read_value_len: | |
1185 | |
1186 if (ngx_http_v3_parse_prefix_int(c, &st->pint, 7, ch) != NGX_DONE) { | |
1187 break; | |
1188 } | |
1189 | |
1190 st->literal.length = st->pint.value; | |
1191 if (st->literal.length == 0) { | |
1192 goto done; | |
1193 } | |
1194 | |
1195 st->state = sw_value; | |
1196 break; | |
1197 | |
1198 case sw_value: | |
1199 | |
1200 rc = ngx_http_v3_parse_literal(c, &st->literal, ch); | |
1201 | |
1202 if (rc == NGX_ERROR) { | |
1203 return NGX_ERROR; | |
1204 } | |
1205 | |
1206 if (rc == NGX_DONE) { | |
1207 st->value = st->literal.value; | |
1208 goto done; | |
1209 } | |
1210 | |
1211 break; | |
1212 } | |
1213 | |
1214 return NGX_AGAIN; | |
1215 | |
1216 done: | |
1217 | |
1218 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
1219 "http3 parse header inr done %s[%ui] \"%V\"", | |
1220 st->dynamic ? "dynamic" : "static", | |
1221 st->index, &st->value); | |
1222 | |
1223 if (ngx_http_v3_ref_insert(c, st->dynamic, st->index, &st->value) != NGX_OK) | |
1224 { | |
1225 return NGX_ERROR; | |
1226 } | |
1227 | |
1228 st->state = sw_start; | |
1229 return NGX_DONE; | |
1230 } | |
1231 | |
1232 | |
1233 ngx_int_t | |
1234 ngx_http_v3_parse_header_iwnr(ngx_connection_t *c, | |
1235 ngx_http_v3_parse_header_t *st, u_char ch) | |
1236 { | |
1237 ngx_int_t rc; | |
1238 enum { | |
1239 sw_start = 0, | |
1240 sw_name_len, | |
1241 sw_name, | |
1242 sw_value_len, | |
1243 sw_read_value_len, | |
1244 sw_value | |
1245 }; | |
1246 | |
1247 switch (st->state) { | |
1248 | |
1249 case sw_start: | |
1250 | |
1251 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
1252 "http3 parse header iwnr"); | |
1253 | |
1254 st->literal.huffman = (ch & 0x20) ? 1 : 0; | |
1255 st->state = sw_name_len; | |
1256 | |
1257 /* fall through */ | |
1258 | |
1259 case sw_name_len: | |
1260 | |
1261 if (ngx_http_v3_parse_prefix_int(c, &st->pint, 5, ch) != NGX_DONE) { | |
1262 break; | |
1263 } | |
1264 | |
1265 st->literal.length = st->pint.value; | |
1266 if (st->literal.length == 0) { | |
1267 return NGX_ERROR; | |
1268 } | |
1269 | |
1270 st->state = sw_name; | |
1271 break; | |
1272 | |
1273 case sw_name: | |
1274 | |
1275 rc = ngx_http_v3_parse_literal(c, &st->literal, ch); | |
1276 | |
1277 if (rc == NGX_ERROR) { | |
1278 return NGX_ERROR; | |
1279 } | |
1280 | |
1281 if (rc == NGX_DONE) { | |
1282 st->name = st->literal.value; | |
1283 st->state = sw_value_len; | |
1284 } | |
1285 | |
1286 break; | |
1287 | |
1288 case sw_value_len: | |
1289 | |
1290 st->literal.huffman = (ch & 0x80) ? 1 : 0; | |
1291 st->state = sw_read_value_len; | |
1292 | |
1293 /* fall through */ | |
1294 | |
1295 case sw_read_value_len: | |
1296 | |
1297 if (ngx_http_v3_parse_prefix_int(c, &st->pint, 7, ch) != NGX_DONE) { | |
1298 break; | |
1299 } | |
1300 | |
1301 st->literal.length = st->pint.value; | |
1302 if (st->literal.length == 0) { | |
1303 goto done; | |
1304 } | |
1305 | |
1306 st->state = sw_value; | |
1307 break; | |
1308 | |
1309 case sw_value: | |
1310 | |
1311 rc = ngx_http_v3_parse_literal(c, &st->literal, ch); | |
1312 | |
1313 if (rc == NGX_ERROR) { | |
1314 return NGX_ERROR; | |
1315 } | |
1316 | |
1317 if (rc == NGX_DONE) { | |
1318 st->value = st->literal.value; | |
1319 goto done; | |
1320 } | |
1321 | |
1322 break; | |
1323 } | |
1324 | |
1325 return NGX_AGAIN; | |
1326 | |
1327 done: | |
1328 | |
1329 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
1330 "http3 parse header iwnr done \"%V\":\"%V\"", | |
1331 &st->name, &st->value); | |
1332 | |
1333 if (ngx_http_v3_insert(c, &st->name, &st->value) != NGX_OK) { | |
1334 return NGX_ERROR; | |
1335 } | |
1336 | |
1337 st->state = sw_start; | |
1338 return NGX_DONE; | |
1339 } | |
1340 | |
1341 | |
1342 ngx_int_t | |
1343 ngx_http_v3_parse_decoder(ngx_connection_t *c, void *data, u_char ch) | |
1344 { | |
1345 ngx_http_v3_parse_decoder_t *st = data; | |
1346 | |
1347 enum { | |
1348 sw_start = 0, | |
1349 sw_ack_header, | |
1350 sw_cancel_stream, | |
1351 sw_inc_insert_count | |
1352 }; | |
1353 | |
1354 if (st->state == sw_start) { | |
1355 | |
1356 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
1357 "http3 parse decoder instruction"); | |
1358 | |
1359 if (ch & 0x80) { | |
1360 /* Header Acknowledgement */ | |
1361 | |
1362 st->state = sw_ack_header; | |
1363 | |
1364 } else if (ch & 0x40) { | |
1365 /* Stream Cancellation */ | |
1366 | |
1367 st->state = sw_cancel_stream; | |
1368 | |
1369 } else { | |
1370 /* Insert Count Increment */ | |
1371 | |
1372 st->state = sw_inc_insert_count; | |
1373 } | |
1374 } | |
1375 | |
1376 switch (st->state) { | |
1377 | |
1378 case sw_ack_header: | |
1379 | |
1380 if (ngx_http_v3_parse_prefix_int(c, &st->pint, 6, ch) != NGX_DONE) { | |
1381 break; | |
1382 } | |
1383 | |
1384 if (ngx_http_v3_ack_header(c, st->pint.value) != NGX_OK) { | |
1385 return NGX_ERROR; | |
1386 } | |
1387 | |
1388 goto done; | |
1389 | |
1390 case sw_cancel_stream: | |
1391 | |
1392 if (ngx_http_v3_parse_prefix_int(c, &st->pint, 6, ch) != NGX_DONE) { | |
1393 break; | |
1394 } | |
1395 | |
1396 if (ngx_http_v3_cancel_stream(c, st->pint.value) != NGX_OK) { | |
1397 return NGX_ERROR; | |
1398 } | |
1399 | |
1400 goto done; | |
1401 | |
1402 case sw_inc_insert_count: | |
1403 | |
1404 if (ngx_http_v3_parse_prefix_int(c, &st->pint, 6, ch) != NGX_DONE) { | |
1405 break; | |
1406 } | |
1407 | |
1408 if (ngx_http_v3_inc_insert_count(c, st->pint.value) != NGX_OK) { | |
1409 return NGX_ERROR; | |
1410 } | |
1411 | |
1412 goto done; | |
1413 } | |
1414 | |
1415 return NGX_AGAIN; | |
1416 | |
1417 done: | |
1418 | |
1419 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
1420 "http3 parse decoder instruction done"); | |
1421 | |
1422 st->state = sw_start; | |
1423 return NGX_DONE; | |
1424 } |