comparison src/http/v3/ngx_http_v3_parse.c @ 7951:c9538aef3211 quic

HTTP/3: refactored dynamic table implementation. Previously dynamic table was not functional because of zero limit on its size set by default. Now the following changes enable it: - new directives to set SETTINGS_QPACK_MAX_TABLE_CAPACITY and SETTINGS_QPACK_BLOCKED_STREAMS - send settings with SETTINGS_QPACK_MAX_TABLE_CAPACITY and SETTINGS_QPACK_BLOCKED_STREAMS to the client - send Insert Count Increment to the client - send Header Acknowledgement to the client - evict old dynamic table entries on overflow - decode Required Insert Count from client - block stream if Required Insert Count is not reached
author Roman Arutyunyan <arut@nginx.com>
date Thu, 02 Jul 2020 15:34:05 +0300
parents b0e81f49d7c0
children a7f64438aa3c
comparison
equal deleted inserted replaced
7950:b0e81f49d7c0 7951:c9538aef3211
6 6
7 7
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
12
13 static ngx_int_t ngx_http_v3_parse_lookup(ngx_connection_t *c,
14 ngx_uint_t dynamic, ngx_uint_t index, ngx_str_t *name, ngx_str_t *value);
11 15
12 16
13 ngx_int_t 17 ngx_int_t
14 ngx_http_v3_parse_varlen_int(ngx_connection_t *c, 18 ngx_http_v3_parse_varlen_int(ngx_connection_t *c,
15 ngx_http_v3_parse_varlen_int_t *st, u_char ch) 19 ngx_http_v3_parse_varlen_int_t *st, u_char ch)
142 ngx_int_t rc; 146 ngx_int_t rc;
143 enum { 147 enum {
144 sw_start = 0, 148 sw_start = 0,
145 sw_length, 149 sw_length,
146 sw_prefix, 150 sw_prefix,
151 sw_verify,
147 sw_header_rep, 152 sw_header_rep,
148 sw_done 153 sw_done
149 }; 154 };
150 155
151 switch (st->state) { 156 switch (st->state) {
193 198
194 if (st->length == 0) { 199 if (st->length == 0) {
195 return NGX_ERROR; 200 return NGX_ERROR;
196 } 201 }
197 202
203 st->state = sw_verify;
204 break;
205
206 case sw_verify:
207
208 rc = ngx_http_v3_check_insert_count(c, st->prefix.insert_count);
209 if (rc != NGX_OK) {
210 return rc;
211 }
212
198 st->state = sw_header_rep; 213 st->state = sw_header_rep;
199 break; 214
215 /* fall through */
200 216
201 case sw_header_rep: 217 case sw_header_rep:
202 218
203 rc = ngx_http_v3_parse_header_rep(c, &st->header_rep, st->prefix.base, 219 rc = ngx_http_v3_parse_header_rep(c, &st->header_rep, st->prefix.base,
204 ch); 220 ch);
226 242
227 done: 243 done:
228 244
229 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 parse headers done"); 245 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 parse headers done");
230 246
247 if (st->prefix.insert_count > 0) {
248 if (ngx_http_v3_client_ack_header(c, c->qs->id) != NGX_OK) {
249 return NGX_ERROR;
250 }
251 }
252
231 st->state = sw_start; 253 st->state = sw_start;
232 return NGX_DONE; 254 return NGX_DONE;
233 } 255 }
234 256
235 257
283 } 305 }
284 306
285 return NGX_AGAIN; 307 return NGX_AGAIN;
286 308
287 done: 309 done:
310
311 if (ngx_http_v3_decode_insert_count(c, &st->insert_count) != NGX_OK) {
312 return NGX_ERROR;
313 }
288 314
289 if (st->sign) { 315 if (st->sign) {
290 st->base = st->insert_count - st->delta_base - 1; 316 st->base = st->insert_count - st->delta_base - 1;
291 } else { 317 } else {
292 st->base = st->insert_count + st->delta_base; 318 st->base = st->insert_count + st->delta_base;
293 } 319 }
294 320
295 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, c->log, 0, 321 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, c->log, 0,
296 "http3 parse header block prefix done " 322 "http3 parse header block prefix done "
297 "i:%ui, s:%ui, d:%ui, base:%uL", 323 "insert_count:%ui, sign:%ui, delta_base:%ui, base:%uL",
298 st->insert_count, st->sign, st->delta_base, st->base); 324 st->insert_count, st->sign, st->delta_base, st->base);
299 325
300 st->state = sw_start; 326 st->state = sw_start;
301 return NGX_DONE; 327 return NGX_DONE;
302 } 328 }
477 503
478 ngx_int_t 504 ngx_int_t
479 ngx_http_v3_parse_header_ri(ngx_connection_t *c, ngx_http_v3_parse_header_t *st, 505 ngx_http_v3_parse_header_ri(ngx_connection_t *c, ngx_http_v3_parse_header_t *st,
480 u_char ch) 506 u_char ch)
481 { 507 {
482 ngx_http_v3_header_t *h;
483 enum { 508 enum {
484 sw_start = 0, 509 sw_start = 0,
485 sw_index 510 sw_index
486 }; 511 };
487 512
516 541
517 if (st->dynamic) { 542 if (st->dynamic) {
518 st->index = st->base - st->index - 1; 543 st->index = st->base - st->index - 1;
519 } 544 }
520 545
521 h = ngx_http_v3_lookup_table(c, st->dynamic, st->index); 546 if (ngx_http_v3_parse_lookup(c, st->dynamic, st->index, &st->name,
522 if (h == NULL) { 547 &st->value)
548 != NGX_OK)
549 {
523 return NGX_ERROR; 550 return NGX_ERROR;
524 } 551 }
525 552
526 st->name = h->name; 553 st->state = sw_start;
527 st->value = h->value;
528 st->state = sw_start;
529
530 return NGX_DONE; 554 return NGX_DONE;
531 } 555 }
532 556
533 557
534 ngx_int_t 558 ngx_int_t
535 ngx_http_v3_parse_header_lri(ngx_connection_t *c, 559 ngx_http_v3_parse_header_lri(ngx_connection_t *c,
536 ngx_http_v3_parse_header_t *st, u_char ch) 560 ngx_http_v3_parse_header_t *st, u_char ch)
537 { 561 {
538 ngx_int_t rc; 562 ngx_int_t rc;
539 ngx_http_v3_header_t *h;
540 enum { 563 enum {
541 sw_start = 0, 564 sw_start = 0,
542 sw_index, 565 sw_index,
543 sw_value_len, 566 sw_value_len,
544 sw_read_value_len, 567 sw_read_value_len,
614 637
615 if (st->dynamic) { 638 if (st->dynamic) {
616 st->index = st->base - st->index - 1; 639 st->index = st->base - st->index - 1;
617 } 640 }
618 641
619 h = ngx_http_v3_lookup_table(c, st->dynamic, st->index); 642 if (ngx_http_v3_parse_lookup(c, st->dynamic, st->index, &st->name, NULL)
620 if (h == NULL) { 643 != NGX_OK)
644 {
621 return NGX_ERROR; 645 return NGX_ERROR;
622 } 646 }
623 647
624 st->name = h->name;
625 st->state = sw_start; 648 st->state = sw_start;
626 return NGX_DONE; 649 return NGX_DONE;
627 } 650 }
628 651
629 652
733 756
734 ngx_int_t 757 ngx_int_t
735 ngx_http_v3_parse_header_pbi(ngx_connection_t *c, 758 ngx_http_v3_parse_header_pbi(ngx_connection_t *c,
736 ngx_http_v3_parse_header_t *st, u_char ch) 759 ngx_http_v3_parse_header_t *st, u_char ch)
737 { 760 {
738 ngx_http_v3_header_t *h;
739 enum { 761 enum {
740 sw_start = 0, 762 sw_start = 0,
741 sw_index 763 sw_index
742 }; 764 };
743 765
766 done: 788 done:
767 789
768 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, 790 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
769 "http3 parse header pbi done dynamic[+%ui]", st->index); 791 "http3 parse header pbi done dynamic[+%ui]", st->index);
770 792
771 h = ngx_http_v3_lookup_table(c, 1, st->base + st->index); 793 if (ngx_http_v3_parse_lookup(c, 1, st->base + st->index, &st->name,
772 if (h == NULL) { 794 &st->value)
795 != NGX_OK)
796 {
773 return NGX_ERROR; 797 return NGX_ERROR;
774 } 798 }
775 799
776 st->name = h->name;
777 st->value = h->value;
778 st->state = sw_start; 800 st->state = sw_start;
779 return NGX_DONE; 801 return NGX_DONE;
780 } 802 }
781 803
782 804
783 ngx_int_t 805 ngx_int_t
784 ngx_http_v3_parse_header_lpbi(ngx_connection_t *c, 806 ngx_http_v3_parse_header_lpbi(ngx_connection_t *c,
785 ngx_http_v3_parse_header_t *st, u_char ch) 807 ngx_http_v3_parse_header_t *st, u_char ch)
786 { 808 {
787 ngx_int_t rc; 809 ngx_int_t rc;
788 ngx_http_v3_header_t *h;
789 enum { 810 enum {
790 sw_start = 0, 811 sw_start = 0,
791 sw_index, 812 sw_index,
792 sw_value_len, 813 sw_value_len,
793 sw_read_value_len, 814 sw_read_value_len,
858 879
859 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, 880 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
860 "http3 parse header lpbi done dynamic[+%ui] \"%V\"", 881 "http3 parse header lpbi done dynamic[+%ui] \"%V\"",
861 st->index, &st->value); 882 st->index, &st->value);
862 883
863 h = ngx_http_v3_lookup_table(c, 1, st->base + st->index); 884 if (ngx_http_v3_parse_lookup(c, 1, st->base + st->index, &st->name, NULL)
864 if (h == NULL) { 885 != NGX_OK)
886 {
865 return NGX_ERROR; 887 return NGX_ERROR;
866 } 888 }
867 889
868 st->name = h->name;
869 st->state = sw_start; 890 st->state = sw_start;
870 return NGX_DONE; 891 return NGX_DONE;
892 }
893
894
895 static ngx_int_t
896 ngx_http_v3_parse_lookup(ngx_connection_t *c, ngx_uint_t dynamic,
897 ngx_uint_t index, ngx_str_t *name, ngx_str_t *value)
898 {
899 u_char *p;
900
901 if (!dynamic) {
902 return ngx_http_v3_lookup_static(c, index, name, value);
903 }
904
905 if (ngx_http_v3_lookup(c, index, name, value) != NGX_OK) {
906 return NGX_ERROR;
907 }
908
909 if (name) {
910 p = ngx_pnalloc(c->pool, name->len + 1);
911 if (p == NULL) {
912 return NGX_ERROR;
913 }
914
915 ngx_memcpy(p, name->data, name->len);
916 p[name->len] = '\0';
917 name->data = p;
918 }
919
920 if (value) {
921 p = ngx_pnalloc(c->pool, value->len + 1);
922 if (p == NULL) {
923 return NGX_ERROR;
924 }
925
926 ngx_memcpy(p, value->data, value->len);
927 p[value->len] = '\0';
928 value->data = p;
929 }
930
931 return NGX_OK;
871 } 932 }
872 933
873 934
874 ngx_int_t 935 ngx_int_t
875 ngx_http_v3_parse_control(ngx_connection_t *c, void *data, u_char ch) 936 ngx_http_v3_parse_control(ngx_connection_t *c, void *data, u_char ch)
1143 1204
1144 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, 1205 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
1145 "http3 parse encoder instruction done"); 1206 "http3 parse encoder instruction done");
1146 1207
1147 st->state = sw_start; 1208 st->state = sw_start;
1148 return NGX_DONE; 1209 return NGX_AGAIN;
1149 } 1210 }
1150 1211
1151 1212
1152 ngx_int_t 1213 ngx_int_t
1153 ngx_http_v3_parse_header_inr(ngx_connection_t *c, 1214 ngx_http_v3_parse_header_inr(ngx_connection_t *c,
1427 1488
1428 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, 1489 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
1429 "http3 parse decoder instruction done"); 1490 "http3 parse decoder instruction done");
1430 1491
1431 st->state = sw_start; 1492 st->state = sw_start;
1432 return NGX_DONE; 1493 return NGX_AGAIN;
1433 } 1494 }
1434 1495
1435 1496
1436 ngx_int_t 1497 ngx_int_t
1437 ngx_http_v3_parse_data(ngx_connection_t *c, ngx_http_v3_parse_data_t *st, 1498 ngx_http_v3_parse_data(ngx_connection_t *c, ngx_http_v3_parse_data_t *st,