Mercurial > hg > nginx
comparison src/http/v3/ngx_http_v3_streams.c @ 8215:38c0898b6df7 quic
HTTP/3.
author | Roman Arutyunyan <arut@nginx.com> |
---|---|
date | Fri, 13 Mar 2020 19:36:33 +0300 |
parents | |
children | 268f4389130d |
comparison
equal
deleted
inserted
replaced
8214:6fd2cce50fe2 | 8215:38c0898b6df7 |
---|---|
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 #define NGX_HTTP_V3_CONTROL_STREAM 0x00 | |
14 #define NGX_HTTP_V3_PUSH_STREAM 0x01 | |
15 #define NGX_HTTP_V3_ENCODER_STREAM 0x02 | |
16 #define NGX_HTTP_V3_DECODER_STREAM 0x03 | |
17 | |
18 | |
19 typedef struct { | |
20 uint32_t signature; /* QSTR */ | |
21 u_char buf[4]; | |
22 | |
23 ngx_uint_t len; | |
24 ngx_uint_t type; | |
25 ngx_uint_t state; | |
26 ngx_uint_t index; | |
27 ngx_uint_t offset; | |
28 | |
29 ngx_str_t name; | |
30 ngx_str_t value; | |
31 | |
32 unsigned client:1; | |
33 unsigned dynamic:1; | |
34 unsigned huffman:1; | |
35 } ngx_http_v3_uni_stream_t; | |
36 | |
37 | |
38 static void ngx_http_v3_close_uni_stream(ngx_connection_t *c); | |
39 static void ngx_http_v3_uni_stream_cleanup(void *data); | |
40 static void ngx_http_v3_read_uni_stream_type(ngx_event_t *rev); | |
41 static void ngx_http_v3_dummy_stream_handler(ngx_event_t *rev); | |
42 static void ngx_http_v3_client_encoder_handler(ngx_event_t *rev); | |
43 static void ngx_http_v3_client_decoder_handler(ngx_event_t *rev); | |
44 | |
45 static ngx_connection_t *ngx_http_v3_create_uni_stream(ngx_connection_t *c, | |
46 ngx_uint_t type); | |
47 static ngx_connection_t *ngx_http_v3_get_server_encoder(ngx_connection_t *c); | |
48 static ngx_connection_t *ngx_http_v3_get_server_decoder(ngx_connection_t *c); | |
49 | |
50 | |
51 void | |
52 ngx_http_v3_handle_client_uni_stream(ngx_connection_t *c) | |
53 { | |
54 ngx_pool_cleanup_t *cln; | |
55 ngx_http_v3_uni_stream_t *us; | |
56 | |
57 c->log->connection = c->number; | |
58 | |
59 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
60 "http3 new uni stream id:0x%uXL", c->qs->id); | |
61 | |
62 us = ngx_pcalloc(c->pool, sizeof(ngx_http_v3_uni_stream_t)); | |
63 if (us == NULL) { | |
64 ngx_http_v3_close_uni_stream(c); | |
65 return; | |
66 } | |
67 | |
68 us->signature = NGX_HTTP_V3_STREAM; | |
69 us->client = 1; | |
70 us->type = (ngx_uint_t) -1; | |
71 | |
72 c->data = us; | |
73 | |
74 cln = ngx_pool_cleanup_add(c->pool, 0); | |
75 if (cln == NULL) { | |
76 ngx_http_v3_close_uni_stream(c); | |
77 return; | |
78 } | |
79 | |
80 cln->handler = ngx_http_v3_uni_stream_cleanup; | |
81 cln->data = c; | |
82 | |
83 c->read->handler = ngx_http_v3_read_uni_stream_type; | |
84 c->read->handler(c->read); | |
85 } | |
86 | |
87 | |
88 static void | |
89 ngx_http_v3_close_uni_stream(ngx_connection_t *c) | |
90 { | |
91 ngx_pool_t *pool; | |
92 | |
93 c->destroyed = 1; | |
94 | |
95 pool = c->pool; | |
96 | |
97 ngx_close_connection(c); | |
98 | |
99 ngx_destroy_pool(pool); | |
100 } | |
101 | |
102 | |
103 static void | |
104 ngx_http_v3_uni_stream_cleanup(void *data) | |
105 { | |
106 ngx_connection_t *c = data; | |
107 | |
108 ngx_http_v3_connection_t *h3c; | |
109 ngx_http_v3_uni_stream_t *us; | |
110 | |
111 us = c->data; | |
112 h3c = c->qs->parent->data; | |
113 | |
114 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 close stream"); | |
115 | |
116 switch (us->type) { | |
117 | |
118 case NGX_HTTP_V3_ENCODER_STREAM: | |
119 | |
120 if (us->client) { | |
121 h3c->client_encoder = NULL; | |
122 } else { | |
123 h3c->server_encoder = NULL; | |
124 } | |
125 | |
126 break; | |
127 | |
128 case NGX_HTTP_V3_DECODER_STREAM: | |
129 | |
130 if (us->client) { | |
131 h3c->client_decoder = NULL; | |
132 } else { | |
133 h3c->server_decoder = NULL; | |
134 } | |
135 | |
136 break; | |
137 } | |
138 } | |
139 | |
140 | |
141 static void | |
142 ngx_http_v3_read_uni_stream_type(ngx_event_t *rev) | |
143 { | |
144 u_char *p; | |
145 ssize_t n, len; | |
146 ngx_connection_t *c; | |
147 ngx_http_v3_connection_t *h3c; | |
148 ngx_http_v3_uni_stream_t *us; | |
149 | |
150 c = rev->data; | |
151 us = c->data; | |
152 h3c = c->qs->parent->data; | |
153 | |
154 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 read stream type"); | |
155 | |
156 while (rev->ready) { | |
157 | |
158 p = &us->buf[us->len]; | |
159 | |
160 if (us->len == 0) { | |
161 len = 1; | |
162 } else { | |
163 len = (us->buf[0] >> 6) + 1 - us->len; | |
164 } | |
165 | |
166 n = c->recv(c, p, len); | |
167 | |
168 if (n == NGX_ERROR) { | |
169 goto failed; | |
170 } | |
171 | |
172 if (n == NGX_AGAIN) { | |
173 break; | |
174 } | |
175 | |
176 us->len += n; | |
177 | |
178 if (n != len) { | |
179 break; | |
180 } | |
181 | |
182 if ((us->buf[0] >> 6) + 1 == us->len) { | |
183 us->type = ngx_http_v3_decode_varlen_int(us->buf); | |
184 | |
185 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
186 "http3 stream type:%ui", us->type); | |
187 | |
188 switch (us->type) { | |
189 | |
190 case NGX_HTTP_V3_ENCODER_STREAM: | |
191 if (h3c->client_encoder) { | |
192 goto failed; | |
193 } | |
194 | |
195 h3c->client_encoder = c; | |
196 rev->handler = ngx_http_v3_client_encoder_handler; | |
197 break; | |
198 | |
199 case NGX_HTTP_V3_DECODER_STREAM: | |
200 if (h3c->client_decoder) { | |
201 goto failed; | |
202 } | |
203 | |
204 h3c->client_decoder = c; | |
205 rev->handler = ngx_http_v3_client_decoder_handler; | |
206 break; | |
207 | |
208 case NGX_HTTP_V3_CONTROL_STREAM: | |
209 case NGX_HTTP_V3_PUSH_STREAM: | |
210 | |
211 /* ignore these */ | |
212 | |
213 default: | |
214 rev->handler = ngx_http_v3_dummy_stream_handler; | |
215 } | |
216 | |
217 rev->handler(rev); | |
218 return; | |
219 } | |
220 } | |
221 | |
222 if (ngx_handle_read_event(rev, 0) != NGX_OK) { | |
223 goto failed; | |
224 } | |
225 | |
226 return; | |
227 | |
228 failed: | |
229 | |
230 ngx_http_v3_close_uni_stream(c); | |
231 } | |
232 | |
233 | |
234 static void | |
235 ngx_http_v3_dummy_stream_handler(ngx_event_t *rev) | |
236 { | |
237 u_char buf[128]; | |
238 ngx_connection_t *c; | |
239 | |
240 /* read out and ignore */ | |
241 | |
242 c = rev->data; | |
243 | |
244 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 dummy stream reader"); | |
245 | |
246 while (rev->ready) { | |
247 if (c->recv(c, buf, sizeof(buf)) == NGX_ERROR) { | |
248 goto failed; | |
249 } | |
250 } | |
251 | |
252 if (ngx_handle_read_event(rev, 0) != NGX_OK) { | |
253 goto failed; | |
254 } | |
255 | |
256 return; | |
257 | |
258 failed: | |
259 | |
260 ngx_http_v3_close_uni_stream(c); | |
261 } | |
262 | |
263 | |
264 static void | |
265 ngx_http_v3_client_encoder_handler(ngx_event_t *rev) | |
266 { | |
267 u_char v; | |
268 ssize_t n; | |
269 ngx_str_t name, value; | |
270 ngx_uint_t dynamic, huffman, index, offset; | |
271 ngx_connection_t *c, *pc; | |
272 ngx_http_v3_uni_stream_t *st; | |
273 enum { | |
274 sw_start = 0, | |
275 sw_inr_name_index, | |
276 sw_inr_value_length, | |
277 sw_inr_read_value_length, | |
278 sw_inr_value, | |
279 sw_iwnr_name_length, | |
280 sw_iwnr_name, | |
281 sw_iwnr_value_length, | |
282 sw_iwnr_read_value_length, | |
283 sw_iwnr_value, | |
284 sw_capacity, | |
285 sw_duplicate | |
286 } state; | |
287 | |
288 c = rev->data; | |
289 st = c->data; | |
290 pc = c->qs->parent; | |
291 | |
292 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 client encoder"); | |
293 | |
294 state = st->state; | |
295 dynamic = st->dynamic; | |
296 huffman = st->huffman; | |
297 index = st->index; | |
298 offset = st->offset; | |
299 name = st->name; | |
300 value = st->value; | |
301 | |
302 while (rev->ready) { | |
303 | |
304 /* XXX limit checks */ | |
305 /* XXX buffer input */ | |
306 | |
307 n = c->recv(c, &v, 1); | |
308 | |
309 if (n == NGX_ERROR || n == 0) { | |
310 goto failed; | |
311 } | |
312 | |
313 if (n != 1) { | |
314 break; | |
315 } | |
316 | |
317 /* XXX v -> ch */ | |
318 | |
319 switch (state) { | |
320 | |
321 case sw_start: | |
322 | |
323 if (v & 0x80) { | |
324 /* Insert With Name Reference */ | |
325 | |
326 dynamic = (v & 0x40) ? 0 : 1; | |
327 index = v & 0x3f; | |
328 | |
329 if (index != 0x3f) { | |
330 state = sw_inr_value_length; | |
331 break; | |
332 } | |
333 | |
334 index = 0; | |
335 state = sw_inr_name_index; | |
336 break; | |
337 } | |
338 | |
339 if (v & 0x40) { | |
340 /* Insert Without Name Reference */ | |
341 | |
342 huffman = (v & 0x20) ? 1 : 0; | |
343 name.len = v & 0x1f; | |
344 | |
345 if (name.len != 0x1f) { | |
346 offset = 0; | |
347 state = sw_iwnr_name; | |
348 break; | |
349 } | |
350 | |
351 name.len = 0; | |
352 state = sw_iwnr_name_length; | |
353 break; | |
354 } | |
355 | |
356 if (v & 0x20) { | |
357 /* Set Dynamic Table Capacity */ | |
358 | |
359 index = v & 0x1f; | |
360 | |
361 if (index != 0x1f) { | |
362 if (ngx_http_v3_set_capacity(c, index) != NGX_OK) { | |
363 goto failed; | |
364 } | |
365 | |
366 break; | |
367 } | |
368 | |
369 index = 0; | |
370 state = sw_capacity; | |
371 break; | |
372 } | |
373 | |
374 /* Duplicate */ | |
375 | |
376 index = v & 0x1f; | |
377 | |
378 if (index != 0x1f) { | |
379 if (ngx_http_v3_duplicate(c, index) != NGX_OK) { | |
380 goto failed; | |
381 } | |
382 | |
383 break; | |
384 } | |
385 | |
386 index = 0; | |
387 state = sw_duplicate; | |
388 break; | |
389 | |
390 case sw_inr_name_index: | |
391 | |
392 index = (index << 7) + (v & 0x7f); | |
393 if (v & 0x80) { | |
394 break; | |
395 } | |
396 | |
397 index += 0x3f; | |
398 state = sw_inr_value_length; | |
399 break; | |
400 | |
401 case sw_inr_value_length: | |
402 | |
403 huffman = (v & 0x80) ? 1 : 0; | |
404 value.len = v & 0x7f; | |
405 | |
406 if (value.len == 0) { | |
407 value.data = NULL; | |
408 | |
409 if (ngx_http_v3_ref_insert(c, dynamic, index, &value) != NGX_OK) | |
410 { | |
411 goto failed; | |
412 } | |
413 | |
414 state = sw_start; | |
415 break; | |
416 } | |
417 | |
418 if (value.len != 0x7f) { | |
419 value.data = ngx_pnalloc(pc->pool, value.len); | |
420 if (value.data == NULL) { | |
421 goto failed; | |
422 } | |
423 | |
424 state = sw_inr_value; | |
425 offset = 0; | |
426 break; | |
427 } | |
428 | |
429 value.len = 0; | |
430 state = sw_inr_read_value_length; | |
431 break; | |
432 | |
433 case sw_inr_read_value_length: | |
434 | |
435 value.len = (value.len << 7) + (v & 0x7f); | |
436 if (v & 0x80) { | |
437 break; | |
438 } | |
439 | |
440 value.len += 0x7f; | |
441 | |
442 value.data = ngx_pnalloc(pc->pool, value.len); | |
443 if (value.data == NULL) { | |
444 goto failed; | |
445 } | |
446 | |
447 state = sw_inr_value; | |
448 offset = 0; | |
449 break; | |
450 | |
451 case sw_inr_value: | |
452 | |
453 value.data[offset++] = v; | |
454 if (offset != value.len) { | |
455 break; | |
456 } | |
457 | |
458 if (huffman) { | |
459 if (ngx_http_v3_decode_huffman(pc, &value) != NGX_OK) { | |
460 goto failed; | |
461 } | |
462 } | |
463 | |
464 if (ngx_http_v3_ref_insert(c, dynamic, index, &value) != NGX_OK) { | |
465 goto failed; | |
466 } | |
467 | |
468 state = sw_start; | |
469 break; | |
470 | |
471 case sw_iwnr_name_length: | |
472 | |
473 name.len = (name.len << 7) + (v & 0x7f); | |
474 if (v & 0x80) { | |
475 break; | |
476 } | |
477 | |
478 name.len += 0x1f; | |
479 | |
480 name.data = ngx_pnalloc(pc->pool, name.len); | |
481 if (name.data == NULL) { | |
482 goto failed; | |
483 } | |
484 | |
485 offset = 0; | |
486 state = sw_iwnr_name; | |
487 break; | |
488 | |
489 case sw_iwnr_name: | |
490 | |
491 name.data[offset++] = v; | |
492 if (offset != name.len) { | |
493 break; | |
494 } | |
495 | |
496 if (huffman) { | |
497 if (ngx_http_v3_decode_huffman(pc, &name) != NGX_OK) { | |
498 goto failed; | |
499 } | |
500 } | |
501 | |
502 state = sw_iwnr_value_length; | |
503 break; | |
504 | |
505 case sw_iwnr_value_length: | |
506 | |
507 huffman = (v & 0x80) ? 1 : 0; | |
508 value.len = v & 0x7f; | |
509 | |
510 if (value.len == 0) { | |
511 value.data = NULL; | |
512 | |
513 if (ngx_http_v3_insert(c, &name, &value) != NGX_OK) { | |
514 goto failed; | |
515 } | |
516 | |
517 state = sw_start; | |
518 break; | |
519 } | |
520 | |
521 if (value.len != 0x7f) { | |
522 value.data = ngx_pnalloc(pc->pool, value.len); | |
523 if (value.data == NULL) { | |
524 goto failed; | |
525 } | |
526 | |
527 offset = 0; | |
528 state = sw_iwnr_value; | |
529 break; | |
530 } | |
531 | |
532 state = sw_iwnr_read_value_length; | |
533 break; | |
534 | |
535 case sw_iwnr_read_value_length: | |
536 | |
537 value.len = (value.len << 7) + (v & 0x7f); | |
538 if (v & 0x80) { | |
539 break; | |
540 } | |
541 | |
542 value.data = ngx_pnalloc(pc->pool, value.len); | |
543 if (value.data == NULL) { | |
544 goto failed; | |
545 } | |
546 | |
547 offset = 0; | |
548 state = sw_iwnr_value; | |
549 break; | |
550 | |
551 case sw_iwnr_value: | |
552 | |
553 value.data[offset++] = v; | |
554 if (offset != value.len) { | |
555 break; | |
556 } | |
557 | |
558 if (huffman) { | |
559 if (ngx_http_v3_decode_huffman(pc, &value) != NGX_OK) { | |
560 goto failed; | |
561 } | |
562 } | |
563 | |
564 if (ngx_http_v3_insert(c, &name, &value) != NGX_OK) { | |
565 goto failed; | |
566 } | |
567 | |
568 state = sw_start; | |
569 break; | |
570 | |
571 | |
572 case sw_capacity: | |
573 | |
574 index = (index << 7) + (v & 0x7f); | |
575 if (v & 0x80) { | |
576 break; | |
577 } | |
578 | |
579 index += 0x1f; | |
580 | |
581 if (ngx_http_v3_set_capacity(c, index) != NGX_OK) { | |
582 goto failed; | |
583 } | |
584 | |
585 state = sw_start; | |
586 break; | |
587 | |
588 case sw_duplicate: | |
589 | |
590 index = (index << 7) + (v & 0x7f); | |
591 if (v & 0x80) { | |
592 break; | |
593 } | |
594 | |
595 index += 0x1f; | |
596 | |
597 if (ngx_http_v3_duplicate(c, index) != NGX_OK) { | |
598 goto failed; | |
599 } | |
600 | |
601 state = sw_start; | |
602 break; | |
603 } | |
604 } | |
605 | |
606 st->state = state; | |
607 st->dynamic = dynamic; | |
608 st->huffman = huffman; | |
609 st->index = index; | |
610 st->offset = offset; | |
611 st->name = name; | |
612 st->value = value; | |
613 | |
614 if (ngx_handle_read_event(rev, 0) != NGX_OK) { | |
615 goto failed; | |
616 } | |
617 | |
618 return; | |
619 | |
620 failed: | |
621 | |
622 ngx_http_v3_close_uni_stream(c); | |
623 } | |
624 | |
625 | |
626 static void | |
627 ngx_http_v3_client_decoder_handler(ngx_event_t *rev) | |
628 { | |
629 u_char v; | |
630 ssize_t n; | |
631 ngx_uint_t index; | |
632 ngx_connection_t *c; | |
633 ngx_http_v3_uni_stream_t *st; | |
634 enum { | |
635 sw_start = 0, | |
636 sw_ack_header, | |
637 sw_cancel_stream, | |
638 sw_inc_insert_count | |
639 } state; | |
640 | |
641 c = rev->data; | |
642 st = c->data; | |
643 | |
644 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 client decoder"); | |
645 | |
646 state = st->state; | |
647 index = st->index; | |
648 | |
649 while (rev->ready) { | |
650 | |
651 /* XXX limit checks */ | |
652 /* XXX buffer input */ | |
653 | |
654 n = c->recv(c, &v, 1); | |
655 | |
656 if (n == NGX_ERROR || n == 0) { | |
657 goto failed; | |
658 } | |
659 | |
660 if (n != 1) { | |
661 break; | |
662 } | |
663 | |
664 switch (state) { | |
665 | |
666 case sw_start: | |
667 | |
668 if (v & 0x80) { | |
669 /* Header Acknowledgement */ | |
670 | |
671 index = v & 0x7f; | |
672 | |
673 if (index != 0x7f) { | |
674 if (ngx_http_v3_ack_header(c, index) != NGX_OK) { | |
675 goto failed; | |
676 } | |
677 | |
678 break; | |
679 } | |
680 | |
681 index = 0; | |
682 state = sw_ack_header; | |
683 break; | |
684 } | |
685 | |
686 if (v & 0x40) { | |
687 /* Stream Cancellation */ | |
688 | |
689 index = v & 0x3f; | |
690 | |
691 if (index != 0x3f) { | |
692 if (ngx_http_v3_cancel_stream(c, index) != NGX_OK) { | |
693 goto failed; | |
694 } | |
695 | |
696 break; | |
697 } | |
698 | |
699 index = 0; | |
700 state = sw_cancel_stream; | |
701 break; | |
702 } | |
703 | |
704 /* Insert Count Increment */ | |
705 | |
706 index = v & 0x3f; | |
707 | |
708 if (index != 0x3f) { | |
709 if (ngx_http_v3_inc_insert_count(c, index) != NGX_OK) { | |
710 goto failed; | |
711 } | |
712 | |
713 break; | |
714 } | |
715 | |
716 index = 0; | |
717 state = sw_inc_insert_count; | |
718 break; | |
719 | |
720 case sw_ack_header: | |
721 | |
722 index = (index << 7) + (v & 0x7f); | |
723 if (v & 0x80) { | |
724 break; | |
725 } | |
726 | |
727 index += 0x7f; | |
728 | |
729 if (ngx_http_v3_ack_header(c, index) != NGX_OK) { | |
730 goto failed; | |
731 } | |
732 | |
733 state = sw_start; | |
734 break; | |
735 | |
736 case sw_cancel_stream: | |
737 | |
738 index = (index << 7) + (v & 0x7f); | |
739 if (v & 0x80) { | |
740 break; | |
741 } | |
742 | |
743 index += 0x3f; | |
744 | |
745 if (ngx_http_v3_cancel_stream(c, index) != NGX_OK) { | |
746 goto failed; | |
747 } | |
748 | |
749 state = sw_start; | |
750 break; | |
751 | |
752 case sw_inc_insert_count: | |
753 | |
754 index = (index << 7) + (v & 0x7f); | |
755 if (v & 0x80) { | |
756 break; | |
757 } | |
758 | |
759 index += 0x3f; | |
760 | |
761 if (ngx_http_v3_inc_insert_count(c, index) != NGX_OK) { | |
762 goto failed; | |
763 } | |
764 | |
765 state = sw_start; | |
766 break; | |
767 } | |
768 } | |
769 | |
770 st->state = state; | |
771 st->index = index; | |
772 | |
773 if (ngx_handle_read_event(rev, 0) != NGX_OK) { | |
774 goto failed; | |
775 } | |
776 | |
777 return; | |
778 | |
779 failed: | |
780 | |
781 ngx_http_v3_close_uni_stream(c); | |
782 } | |
783 | |
784 | |
785 /* XXX async & buffered stream writes */ | |
786 | |
787 static ngx_connection_t * | |
788 ngx_http_v3_create_uni_stream(ngx_connection_t *c, ngx_uint_t type) | |
789 { | |
790 u_char buf[NGX_HTTP_V3_VARLEN_INT_LEN]; | |
791 size_t n; | |
792 ngx_connection_t *sc; | |
793 ngx_pool_cleanup_t *cln; | |
794 ngx_http_v3_uni_stream_t *us; | |
795 | |
796 sc = ngx_quic_create_uni_stream(c->qs->parent); | |
797 if (sc == NULL) { | |
798 return NULL; | |
799 } | |
800 | |
801 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
802 "http3 create uni stream, type:%ui", type); | |
803 | |
804 us = ngx_pcalloc(sc->pool, sizeof(ngx_http_v3_uni_stream_t)); | |
805 if (us == NULL) { | |
806 goto failed; | |
807 } | |
808 | |
809 us->signature = NGX_HTTP_V3_STREAM; | |
810 us->type = type; | |
811 sc->data = us; | |
812 | |
813 cln = ngx_pool_cleanup_add(sc->pool, 0); | |
814 if (cln == NULL) { | |
815 goto failed; | |
816 } | |
817 | |
818 cln->handler = ngx_http_v3_uni_stream_cleanup; | |
819 cln->data = sc; | |
820 | |
821 n = (u_char *) ngx_http_v3_encode_varlen_int(buf, type) - buf; | |
822 | |
823 if (sc->send(sc, buf, n) != (ssize_t) n) { | |
824 goto failed; | |
825 } | |
826 | |
827 return sc; | |
828 | |
829 failed: | |
830 | |
831 ngx_http_v3_close_uni_stream(sc); | |
832 | |
833 return NULL; | |
834 } | |
835 | |
836 | |
837 static ngx_connection_t * | |
838 ngx_http_v3_get_server_encoder(ngx_connection_t *c) | |
839 { | |
840 ngx_http_v3_connection_t *h3c; | |
841 | |
842 h3c = c->qs->parent->data; | |
843 | |
844 if (h3c->server_encoder == NULL) { | |
845 h3c->server_encoder = ngx_http_v3_create_uni_stream(c, | |
846 NGX_HTTP_V3_ENCODER_STREAM); | |
847 } | |
848 | |
849 return h3c->server_encoder; | |
850 } | |
851 | |
852 | |
853 static ngx_connection_t * | |
854 ngx_http_v3_get_server_decoder(ngx_connection_t *c) | |
855 { | |
856 ngx_http_v3_connection_t *h3c; | |
857 | |
858 h3c = c->qs->parent->data; | |
859 | |
860 if (h3c->server_decoder == NULL) { | |
861 h3c->server_decoder = ngx_http_v3_create_uni_stream(c, | |
862 NGX_HTTP_V3_DECODER_STREAM); | |
863 } | |
864 | |
865 return h3c->server_decoder; | |
866 } | |
867 | |
868 | |
869 ngx_int_t | |
870 ngx_http_v3_client_ref_insert(ngx_connection_t *c, ngx_uint_t dynamic, | |
871 ngx_uint_t index, ngx_str_t *value) | |
872 { | |
873 u_char *p, buf[NGX_HTTP_V3_PREFIX_INT_LEN * 2]; | |
874 size_t n; | |
875 ngx_connection_t *ec; | |
876 | |
877 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
878 "http3 client ref insert, %s[%ui] \"%V\"", | |
879 dynamic ? "dynamic" : "static", index, value); | |
880 | |
881 ec = ngx_http_v3_get_server_encoder(c); | |
882 if (ec == NULL) { | |
883 return NGX_ERROR; | |
884 } | |
885 | |
886 p = buf; | |
887 | |
888 *p = (dynamic ? 0x80 : 0xc0); | |
889 p = (u_char *) ngx_http_v3_encode_prefix_int(p, index, 6); | |
890 | |
891 /* XXX option for huffman? */ | |
892 *p = 0; | |
893 p = (u_char *) ngx_http_v3_encode_prefix_int(p, value->len, 7); | |
894 | |
895 n = p - buf; | |
896 | |
897 if (ec->send(ec, buf, n) != (ssize_t) n) { | |
898 goto failed; | |
899 } | |
900 | |
901 if (ec->send(ec, value->data, value->len) != (ssize_t) value->len) { | |
902 goto failed; | |
903 } | |
904 | |
905 return NGX_OK; | |
906 | |
907 failed: | |
908 | |
909 ngx_http_v3_close_uni_stream(ec); | |
910 | |
911 return NGX_ERROR; | |
912 } | |
913 | |
914 | |
915 ngx_int_t | |
916 ngx_http_v3_client_insert(ngx_connection_t *c, ngx_str_t *name, | |
917 ngx_str_t *value) | |
918 { | |
919 u_char buf[NGX_HTTP_V3_PREFIX_INT_LEN]; | |
920 size_t n; | |
921 ngx_connection_t *ec; | |
922 | |
923 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
924 "http3 client insert \"%V\":\"%V\"", name, value); | |
925 | |
926 ec = ngx_http_v3_get_server_encoder(c); | |
927 if (ec == NULL) { | |
928 return NGX_ERROR; | |
929 } | |
930 | |
931 /* XXX option for huffman? */ | |
932 buf[0] = 0x40; | |
933 n = (u_char *) ngx_http_v3_encode_prefix_int(buf, name->len, 5) - buf; | |
934 | |
935 if (ec->send(ec, buf, n) != (ssize_t) n) { | |
936 goto failed; | |
937 } | |
938 | |
939 if (ec->send(ec, name->data, name->len) != (ssize_t) name->len) { | |
940 goto failed; | |
941 } | |
942 | |
943 /* XXX option for huffman? */ | |
944 buf[0] = 0; | |
945 n = (u_char *) ngx_http_v3_encode_prefix_int(buf, value->len, 7) - buf; | |
946 | |
947 if (ec->send(ec, buf, n) != (ssize_t) n) { | |
948 goto failed; | |
949 } | |
950 | |
951 if (ec->send(ec, value->data, value->len) != (ssize_t) value->len) { | |
952 goto failed; | |
953 } | |
954 | |
955 return NGX_OK; | |
956 | |
957 failed: | |
958 | |
959 ngx_http_v3_close_uni_stream(ec); | |
960 | |
961 return NGX_ERROR; | |
962 } | |
963 | |
964 | |
965 ngx_int_t | |
966 ngx_http_v3_client_set_capacity(ngx_connection_t *c, ngx_uint_t capacity) | |
967 { | |
968 u_char buf[NGX_HTTP_V3_PREFIX_INT_LEN]; | |
969 size_t n; | |
970 ngx_connection_t *ec; | |
971 | |
972 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
973 "http3 client set capacity %ui", capacity); | |
974 | |
975 ec = ngx_http_v3_get_server_encoder(c); | |
976 if (ec == NULL) { | |
977 return NGX_ERROR; | |
978 } | |
979 | |
980 buf[0] = 0x20; | |
981 n = (u_char *) ngx_http_v3_encode_prefix_int(buf, capacity, 5) - buf; | |
982 | |
983 if (ec->send(ec, buf, n) != (ssize_t) n) { | |
984 ngx_http_v3_close_uni_stream(ec); | |
985 return NGX_ERROR; | |
986 } | |
987 | |
988 return NGX_OK; | |
989 } | |
990 | |
991 | |
992 ngx_int_t | |
993 ngx_http_v3_client_duplicate(ngx_connection_t *c, ngx_uint_t index) | |
994 { | |
995 u_char buf[NGX_HTTP_V3_PREFIX_INT_LEN]; | |
996 size_t n; | |
997 ngx_connection_t *ec; | |
998 | |
999 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
1000 "http3 client duplicate %ui", index); | |
1001 | |
1002 ec = ngx_http_v3_get_server_encoder(c); | |
1003 if (ec == NULL) { | |
1004 return NGX_ERROR; | |
1005 } | |
1006 | |
1007 buf[0] = 0; | |
1008 n = (u_char *) ngx_http_v3_encode_prefix_int(buf, index, 5) - buf; | |
1009 | |
1010 if (ec->send(ec, buf, n) != (ssize_t) n) { | |
1011 ngx_http_v3_close_uni_stream(ec); | |
1012 return NGX_ERROR; | |
1013 } | |
1014 | |
1015 return NGX_OK; | |
1016 } | |
1017 | |
1018 | |
1019 ngx_int_t | |
1020 ngx_http_v3_client_ack_header(ngx_connection_t *c, ngx_uint_t stream_id) | |
1021 { | |
1022 u_char buf[NGX_HTTP_V3_PREFIX_INT_LEN]; | |
1023 size_t n; | |
1024 ngx_connection_t *dc; | |
1025 | |
1026 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
1027 "http3 client ack header %ui", stream_id); | |
1028 | |
1029 dc = ngx_http_v3_get_server_decoder(c); | |
1030 if (dc == NULL) { | |
1031 return NGX_ERROR; | |
1032 } | |
1033 | |
1034 buf[0] = 0x80; | |
1035 n = (u_char *) ngx_http_v3_encode_prefix_int(buf, stream_id, 7) - buf; | |
1036 | |
1037 if (dc->send(dc, buf, n) != (ssize_t) n) { | |
1038 ngx_http_v3_close_uni_stream(dc); | |
1039 return NGX_ERROR; | |
1040 } | |
1041 | |
1042 return NGX_OK; | |
1043 } | |
1044 | |
1045 | |
1046 ngx_int_t | |
1047 ngx_http_v3_client_cancel_stream(ngx_connection_t *c, ngx_uint_t stream_id) | |
1048 { | |
1049 u_char buf[NGX_HTTP_V3_PREFIX_INT_LEN]; | |
1050 size_t n; | |
1051 ngx_connection_t *dc; | |
1052 | |
1053 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
1054 "http3 client cancel stream %ui", stream_id); | |
1055 | |
1056 dc = ngx_http_v3_get_server_decoder(c); | |
1057 if (dc == NULL) { | |
1058 return NGX_ERROR; | |
1059 } | |
1060 | |
1061 buf[0] = 0x40; | |
1062 n = (u_char *) ngx_http_v3_encode_prefix_int(buf, stream_id, 6) - buf; | |
1063 | |
1064 if (dc->send(dc, buf, n) != (ssize_t) n) { | |
1065 ngx_http_v3_close_uni_stream(dc); | |
1066 return NGX_ERROR; | |
1067 } | |
1068 | |
1069 return NGX_OK; | |
1070 } | |
1071 | |
1072 | |
1073 ngx_int_t | |
1074 ngx_http_v3_client_inc_insert_count(ngx_connection_t *c, ngx_uint_t inc) | |
1075 { | |
1076 u_char buf[NGX_HTTP_V3_PREFIX_INT_LEN]; | |
1077 size_t n; | |
1078 ngx_connection_t *dc; | |
1079 | |
1080 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
1081 "http3 client increment insert count %ui", inc); | |
1082 | |
1083 dc = ngx_http_v3_get_server_decoder(c); | |
1084 if (dc == NULL) { | |
1085 return NGX_ERROR; | |
1086 } | |
1087 | |
1088 buf[0] = 0; | |
1089 n = (u_char *) ngx_http_v3_encode_prefix_int(buf, inc, 6) - buf; | |
1090 | |
1091 if (dc->send(dc, buf, n) != (ssize_t) n) { | |
1092 ngx_http_v3_close_uni_stream(dc); | |
1093 return NGX_ERROR; | |
1094 } | |
1095 | |
1096 return NGX_OK; | |
1097 } |