comparison lib/Test/Nginx/HTTP3.pm @ 1875:f50c2a65ccc0

Tests: basic HTTP/3 support.
author Sergey Kandaurov <pluknet@nginx.com>
date Mon, 29 Aug 2022 15:20:31 +0400
parents d57a0fd293a3
children ff50c265a5ac
comparison
equal deleted inserted replaced
1874:d57a0fd293a3 1875:f50c2a65ccc0
42 $self->{sni} = exists $extra{sni} ? $extra{sni} : 'localhost'; 42 $self->{sni} = exists $extra{sni} ? $extra{sni} : 'localhost';
43 $self->{opts} = $extra{opts}; 43 $self->{opts} = $extra{opts};
44 44
45 $self->{zero} = pack("x5"); 45 $self->{zero} = pack("x5");
46 46
47 $self->{static_encode} = [ static_table() ];
48 $self->{static_decode} = [ static_table() ];
49 $self->{dynamic_encode} = [];
50 $self->{last_stream} = -4;
47 $self->{buf} = ''; 51 $self->{buf} = '';
48 52
49 $self->init(); 53 $self->init();
50 $self->init_key_schedule(); 54 $self->init_key_schedule();
51 $self->initial(); 55 $self->initial();
52 $self->handshake() or return; 56 $self->handshake() or return;
57
58 # RFC 9204, 4.3.1. Set Dynamic Table Capacity
59
60 my $buf = pack("B*", '001' . ipack(5, $extra{capacity} || 400));
61 $self->{encoder_offset} = length($buf) + 1;
62 $buf = "\x08\x02\x02" . $buf;
63
64 # RFC 9114, 6.2.1. Control Streams
65
66 $buf = "\x0a\x06\x03\x00\x04\x00" . $buf;
67 $self->{control_offset} = 3;
68
69 $self->raw_write($buf);
53 70
54 return $self; 71 return $self;
55 } 72 }
56 73
57 sub init { 74 sub init {
59 $self->{keys} = []; 76 $self->{keys} = [];
60 $self->{pn} = [[-1, -1, -1, -1], [-1, -1, -1, -1]]; 77 $self->{pn} = [[-1, -1, -1, -1], [-1, -1, -1, -1]];
61 $self->{crypto_in} = [[],[],[],[]]; 78 $self->{crypto_in} = [[],[],[],[]];
62 $self->{stream_in} = []; 79 $self->{stream_in} = [];
63 $self->{frames_in} = []; 80 $self->{frames_in} = [];
81 $self->{frames_incomplete} = [];
64 $self->{tlsm} = (); 82 $self->{tlsm} = ();
65 $self->{tlsm}{$_} = '' 83 $self->{tlsm}{$_} = ''
66 for 'ch', 'sh', 'ee', 'cert', 'cv', 'sf', 'cf', 'nst'; 84 for 'ch', 'sh', 'ee', 'cert', 'cv', 'sf', 'cf', 'nst';
67 $self->{requests} = 0; 85 $self->{requests} = 0;
68 86
254 272
255 sub path_response { 273 sub path_response {
256 my ($self, $data) = @_; 274 my ($self, $data) = @_;
257 my $frame = "\x1b" . $data; 275 my $frame = "\x1b" . $data;
258 $self->{socket}->syswrite($self->encrypt_aead($frame, 3)); 276 $self->{socket}->syswrite($self->encrypt_aead($frame, 3));
277 }
278
279 ###############################################################################
280
281 # HTTP/3 routines
282
283 # 4.3.2. Insert with Name Reference
284
285 sub insert_reference {
286 my ($self, $name, $value, %extra) = @_;
287 my $table = $extra{dyn}
288 ? $self->{dynamic_encode}
289 : $self->{static_encode};
290 my $huff = $extra{huff};
291 my $hbit = $huff ? '1' : '0';
292 my $dbit = $extra{dyn} ? '0' : '1';
293 my ($index, $buf) = 0;
294
295 ++$index until $index > $#$table
296 or $table->[$index][0] eq $name;
297 $table = $self->{dynamic_encode};
298 splice @$table, 0, 0, [ $name, $value ];
299
300 $value = $huff ? huff($value) : $value;
301
302 $buf = pack('B*', '1' . $dbit . ipack(6, $index));
303 $buf .= pack('B*', $hbit . ipack(7, length($value))) . $value;
304
305 my $offset = $self->{encoder_offset};
306 my $length = length($buf);
307
308 $self->{encoder_offset} += $length;
309 $self->raw_write("\x0e\x02"
310 . build_int($offset) . build_int($length) . $buf);
311 }
312
313 # 4.3.3. Insert with Literal Name
314
315 sub insert_literal {
316 my ($self, $name, $value, %extra) = @_;
317 my $table = $self->{dynamic_encode};
318 my $huff = $extra{huff};
319 my $hbit = $huff ? '1' : '0';
320
321 splice @$table, 0, 0, [ $name, $value ];
322
323 $name = $huff ? huff($name) : $name;
324 $value = $huff ? huff($value) : $value;
325
326 my $buf = pack('B*', '01' . $hbit . ipack(5, length($name))) . $name;
327 $buf .= pack('B*', $hbit . ipack(7, length($value))) . $value;
328
329 my $offset = $self->{encoder_offset};
330 my $length = length($buf);
331
332 $self->{encoder_offset} += $length;
333 $self->raw_write("\x0e\x02"
334 . build_int($offset) . build_int($length) . $buf);
335 }
336
337 # 4.3.4. Duplicate
338
339 sub duplicate {
340 my ($self, $name, $value, %extra) = @_;
341 my $table = $self->{dynamic_encode};
342 my $index = 0;
343
344 ++$index until $index > $#$table
345 or $table->[$index][0] eq $name;
346 splice @$table, 0, 0, [ $table->[$index][0], $table->[$index][1] ];
347
348 my $buf = pack('B*', '000' . ipack(5, $index));
349
350 my $offset = $self->{encoder_offset};
351 my $length = length($buf);
352
353 $self->{encoder_offset} += $length;
354 $self->raw_write("\x0e\x02"
355 . build_int($offset) . build_int($length) . $buf);
356 }
357
358 sub max_push_id {
359 my ($self, $val) = @_;
360 $val = build_int($val);
361 my $buf = "\x0d" . build_int(length($val)) . $val;
362
363 my $offset = $self->{control_offset};
364 my $length = length($buf);
365
366 $self->{control_offset} += $length;
367 $self->raw_write("\x0e\x06"
368 . build_int($offset) . build_int($length) . $buf);
369 }
370
371 sub cancel_push {
372 my ($self, $val) = @_;
373 $val = build_int($val);
374 my $buf = "\x03" . build_int(length($val)) . $val;
375
376 my $offset = $self->{control_offset};
377 my $length = length($buf);
378
379 $self->{control_offset} += $length;
380 $self->raw_write("\x0e\x06"
381 . build_int($offset) . build_int($length) . $buf);
382 }
383
384 sub new_stream {
385 my ($self, $uri, $stream) = @_;
386 my ($input, $buf);
387
388 $self->{headers} = '';
389
390 my $host = $uri->{host} || 'localhost';
391 my $method = $uri->{method} || 'GET';
392 my $scheme = $uri->{scheme} || 'http';
393 my $path = $uri->{path} || '/';
394 my $headers = $uri->{headers};
395 my $body = $uri->{body};
396
397 if ($stream) {
398 $self->{last_stream} = $stream;
399 } else {
400 $self->{last_stream} += 4;
401 }
402
403 unless ($headers) {
404 $input = qpack($self, ":method", $method);
405 $input .= qpack($self, ":scheme", $scheme);
406 $input .= qpack($self, ":path", $path);
407 $input .= qpack($self, ":authority", $host);
408 $input .= qpack($self, "content-length", length($body))
409 if $body;
410
411 } else {
412 $input = join '', map {
413 qpack($self, $_->{name}, $_->{value},
414 mode => $_->{mode}, huff => $_->{huff},
415 idx => $_->{idx}, dyn => $_->{dyn})
416 } @$headers if $headers;
417 }
418
419 # encoded field section prefix
420
421 my $table = $self->{dynamic_encode};
422 my $ric = scalar @$table ? scalar @$table + 1 : 0;
423 my $base = $uri->{base} || 0;
424 $base = $base < 0 ? 0x80 + abs($base) - 1 : $base;
425 $input = pack("CC", $ric, $base) . $input;
426
427 # set length, attach headers, body
428
429 $buf = pack("C", 1);
430 $buf .= build_int(length($input));
431 $buf .= $input;
432 $buf .= pack_body($self, $body) if defined $body;
433
434 $self->{streams}{$self->{last_stream}}{sent} = length($buf);
435 $self->raw_write($self->build_stream($buf, start => $uri->{body_more}));
436
437 return $self->{last_stream};
438 }
439
440 sub h3_body {
441 my ($self, $body, $sid, $extra) = @_;
442
443 my $buf = pack_body($self, $body) if defined $body;
444 my $offset = $self->{streams}{$sid}{sent};
445
446 $self->{streams}{$sid}{sent} += length($body);
447 $self->raw_write($self->build_stream($buf,
448 start => $extra->{body_more}, sid => $sid, offset => $offset));
449 }
450
451 sub pack_body {
452 my ($self, $body) = @_;
453
454 my $buf .= pack("C", 0);
455 $buf .= build_int(length($body));
456 $buf .= $body;
457 }
458
459 my %cframe = (
460 0 => { name => 'DATA', value => \&data },
461 1 => { name => 'HEADERS', value => \&headers },
462 # 3 => { name => 'CANCEL_PUSH', value => \&cancel_push },
463 4 => { name => 'SETTINGS', value => \&settings },
464 5 => { name => 'PUSH_PROMISE', value => \&push_promise },
465 7 => { name => 'GOAWAY', value => \&goaway },
466 );
467
468 sub read {
469 my ($self, %extra) = @_;
470 my (@got);
471 my $s = $self->{socket};
472 my $wait = $extra{wait};
473
474 local $Data::Dumper::Terse = 1;
475
476 while (1) {
477 my ($frame, $length, $uni);
478 my ($stream, $buf, $eof) = $self->read_stream_message($wait);
479
480 unless (defined $stream) {
481 return \@got unless scalar @{$self->{frames_in}};
482 goto frames;
483 }
484
485 if (length($self->{frames_incomplete}[$stream]{buf})) {
486 $buf = $self->{frames_incomplete}[$stream]{buf} . $buf;
487 }
488
489 again:
490 if (($stream % 4) == 3) {
491 unless (defined $self->{stream_uni}{$stream}{stream}) {
492 (my $len, $uni) = parse_int(substr($buf, 0));
493 $self->{stream_uni}{$stream}{stream} = $uni;
494 $buf = substr($buf, $len);
495
496 } else {
497 $uni = $self->{stream_uni}{$stream}{stream};
498 }
499
500 # push stream
501 if ($uni == 1 && !$self->{stream_uni}{$stream}{push}) {
502 $self->{stream_uni}{$stream}{push} = 1;
503 ($frame, $length) = push_stream($buf, $stream);
504 goto push_me;
505 }
506
507 # decoder
508 if ($uni == 3) {
509 ($frame, $length) = push_decoder($buf, $stream);
510 goto push_me;
511 }
512 }
513
514 my $offset = 0;
515 my ($len, $type);
516
517 if (!length($self->{frames_incomplete}[$stream]{buf})) {
518 ($len, $type) = parse_int(substr($buf, $offset));
519 $offset += $len;
520 ($len, $length) = parse_int(substr($buf, $offset));
521 $offset += $len;
522
523 $self->{frames_incomplete}[$stream]{type} = $type;
524 $self->{frames_incomplete}[$stream]{length} = $length;
525 $self->{frames_incomplete}[$stream]{offset} = $offset;
526 }
527
528 if (length($buf) < $self->{frames_incomplete}[$stream]{length}
529 + $self->{frames_incomplete}[$stream]{offset})
530 {
531 $self->{frames_incomplete}[$stream]{buf} = $buf;
532 next;
533 }
534
535 $type = $self->{frames_incomplete}[$stream]{type};
536 $length = $self->{frames_incomplete}[$stream]{length};
537 $offset = $self->{frames_incomplete}[$stream]{offset};
538
539 $buf = substr($buf, $offset);
540 $self->{frames_incomplete}[$stream]{buf} = "";
541
542 $frame = $cframe{$type}{value}($self, $buf, $length);
543 $frame->{length} = $length;
544 $frame->{type} = $cframe{$type}{name};
545 $frame->{flags} = $eof && length($buf) == $length;
546 $frame->{sid} = $stream;
547 $frame->{uni} = $uni if defined $uni;
548
549 push_me:
550 push @got, $frame;
551
552 Test::Nginx::log_core('||', $_) for split "\n", Dumper $frame;
553
554 $buf = substr($buf, $length);
555
556 last unless $extra{all} && test_fin($frame, $extra{all});
557 goto again if length($buf) > 0;
558
559 frames:
560 while ($frame = shift @{$self->{frames_in}}) {
561 push @got, $frame;
562 Test::Nginx::log_core('||', $_) for split "\n",
563 Dumper $frame;
564 return \@got unless test_fin($frame, $extra{all});
565 }
566 }
567 return \@got;
568 }
569
570 sub push_stream {
571 my ($buf, $stream) = @_;
572 my $frame = { sid => $stream, uni => 1, type => 'PUSH header' };
573
574 my ($len, $id) = parse_int($buf);
575 $frame->{push_id} = $id;
576 $frame->{length} = $len;
577
578 return ($frame, $len);
579 }
580
581 sub push_decoder {
582 my ($buf, $stream) = @_;
583 my ($skip, $val) = 0;
584 my $frame = { sid => $stream, uni => 3 };
585
586 if ($skip < length($buf)) {
587 my $bits = unpack("\@$skip B8", $buf);
588
589 if (substr($bits, 0, 1) eq '1') {
590 ($val, $skip) = iunpack(7, $buf, $skip);
591 $frame->{type} = 'DECODER_SA';
592
593 } elsif (substr($bits, 0, 2) eq '01') {
594 ($val, $skip) = iunpack(6, $buf, $skip);
595 $frame->{type} = 'DECODER_C';
596
597 } elsif (substr($bits, 0, 2) eq '00') {
598 ($val, $skip) = iunpack(6, $buf, $skip);
599 $frame->{type} = 'DECODER_ICI';
600 }
601
602 $frame->{val} = $val;
603 }
604
605 return ($frame, $skip);
606 }
607
608 sub test_fin {
609 my ($frame, $all) = @_;
610 my @test = @{$all};
611
612 # wait for the specified DATA length
613
614 for (@test) {
615 if ($_->{length} && $frame->{type} eq 'DATA') {
616 # check also for StreamID if needed
617
618 if (!$_->{sid} || $_->{sid} == $frame->{sid}) {
619 $_->{length} -= $frame->{length};
620 }
621 }
622 }
623 @test = grep { !(defined $_->{length} && $_->{length} == 0) } @test;
624
625 # wait for the fin flag
626
627 @test = grep { !(defined $_->{fin}
628 && (!defined $_->{sid} || $_->{sid} == $frame->{sid})
629 && $_->{fin} & $frame->{flags})
630 } @test if defined $frame->{flags};
631
632 # wait for the specified frame
633
634 @test = grep { !($_->{type} && $_->{type} eq $frame->{type}) } @test;
635
636 @{$all} = @test;
637 }
638
639 sub data {
640 my ($self, $buf, $len) = @_;
641 return { data => substr($buf, 0, $len) };
642 }
643
644 sub headers {
645 my ($self, $buf, $len) = @_;
646 my ($ric, $base);
647 $self->{headers} = substr($buf, 0, $len);
648 my $skip = 0;
649
650 ($ric, $skip) = iunpack(8, $buf, $skip);
651 ($base, $skip) = iunpack(7, $buf, $skip);
652
653 $buf = substr($buf, $skip);
654 $len -= $skip;
655 { headers => qunpack($self, $buf, $len) };
656 }
657
658 sub settings {
659 my ($self, $buf, $length) = @_;
660 my %payload;
661 my ($offset, $len) = 0;
662
663 while ($offset < $length) {
664 my ($id, $val);
665 ($len, $id) = parse_int(substr($buf, $offset));
666 $offset += $len;
667 ($len, $val) = parse_int(substr($buf, $offset));
668 $offset += $len;
669 $payload{$id} = $val;
670 }
671 return \%payload;
672 }
673
674 sub push_promise {
675 my ($self, $buf, $length) = @_;
676 my %payload;
677 my ($offset, $len, $id) = 0;
678
679 ($len, $id) = parse_int($buf);
680 $offset += $len;
681 $payload{push_id} = $id;
682
683 my ($ric, $base);
684 my $skip = $offset;
685
686 ($ric, $skip) = iunpack(8, $buf, $skip);
687 ($base, $skip) = iunpack(7, $buf, $skip);
688
689 $buf = substr($buf, $skip);
690 $length -= $skip;
691 $payload{headers} = qunpack($self, $buf, $length);
692 return \%payload;
693 }
694
695 sub goaway {
696 my ($self, $buf, $length) = @_;
697 my ($len, $stream) = parse_int($buf);
698 { last_sid => $stream }
699 }
700
701 # RFC 7541, 5.1. Integer Representation
702
703 sub ipack {
704 my ($base, $d) = @_;
705 return sprintf("%.*b", $base, $d) if $d < 2**$base - 1;
706
707 my $o = sprintf("%${base}b", 2**$base - 1);
708 $d -= 2**$base - 1;
709 while ($d >= 128) {
710 $o .= sprintf("%8b", $d % 128 + 128);
711 $d /= 128;
712 }
713 $o .= sprintf("%08b", $d);
714 return $o;
715 }
716
717 sub iunpack {
718 my ($base, $b, $s) = @_;
719
720 my $len = unpack("\@$s B8", $b); $s++;
721 my $huff = substr($len, 8 - $base - 1, 1);
722 $len = '0' x (8 - $base) . substr($len, 8 - $base);
723 $len = unpack("C", pack("B8", $len));
724
725 return ($len, $s, $huff) if $len < 2**$base - 1;
726
727 my $m = 0;
728 my $d;
729
730 do {
731 $d = unpack("\@$s C", $b); $s++;
732 $len += ($d & 127) * 2**$m;
733 $m += $base;
734 } while (($d & 128) == 128);
735
736 return ($len, $s, $huff);
737 }
738
739 sub qpack {
740 my ($ctx, $name, $value, %extra) = @_;
741 my $mode = defined $extra{mode} ? $extra{mode} : 4;
742 my $huff = $extra{huff};
743 my $hbit = $huff ? '1' : '0';
744 my $ibit = $extra{ni} ? '1' : '0';
745 my $dbit = $extra{dyn} ? '0' : '1';
746 my $table = $extra{dyn} ? $ctx->{dynamic_encode} : $ctx->{static_encode};
747 my ($index, $buf) = 0;
748
749 # 4.5.2. Indexed Field Line
750
751 if ($mode == 0) {
752 ++$index until $index > $#$table
753 or $table->[$index][0] eq $name
754 and $table->[$index][1] eq $value;
755 $buf = pack('B*', '1' . $dbit . ipack(6, $index));
756 }
757
758 # 4.5.3. Indexed Field Line with Post-Base Index
759
760 if ($mode == 1) {
761 $table = $ctx->{dynamic_encode};
762 ++$index until $index > $#$table
763 or $table->[$index][0] eq $name
764 and $table->[$index][1] eq $value;
765 $buf = pack('B*', '0001' . ipack(4, 0));
766 }
767
768 # 4.5.4. Literal Field Line with Name Reference
769
770 if ($mode == 2) {
771 ++$index until $index > $#$table
772 or $table->[$index][0] eq $name;
773 $value = $huff ? huff($value) : $value;
774
775 $buf = pack('B*', '01' . $ibit . $dbit . ipack(4, $index));
776 $buf .= pack('B*', $hbit . ipack(7, length($value))) . $value;
777 }
778
779 # 4.5.5. Literal Field Line with Post-Base Name Reference
780
781 if ($mode == 3) {
782 $table = $ctx->{dynamic_encode};
783 ++$index until $index > $#$table
784 or $table->[$index][0] eq $name;
785 $value = $huff ? huff($value) : $value;
786
787 $buf = pack('B*', '0000' . $ibit . ipack(3, $index));
788 $buf .= pack('B*', $hbit . ipack(7, length($value))) . $value;
789 }
790
791 # 4.5.6. Literal Field Line with Literal Name
792
793 if ($mode == 4) {
794 $name = $huff ? huff($name) : $name;
795 $value = $huff ? huff($value) : $value;
796
797 $buf = pack('B*', '001' . $ibit .
798 $hbit . ipack(3, length($name))) . $name;
799 $buf .= pack('B*', $hbit . ipack(7, length($value))) . $value;
800 }
801
802 return $buf;
803 }
804
805 sub qunpack {
806 my ($ctx, $data, $length) = @_;
807 my $table = $ctx->{static_decode};
808 my %headers;
809 my $skip = 0;
810 my ($index, $name, $value, $size);
811
812 my $field = sub {
813 my ($base, $b) = @_;
814 my ($len, $s, $huff) = iunpack(@_);
815
816 my $field = substr($b, $s, $len);
817 $field = $huff ? dehuff($field) : $field;
818 $s += $len;
819 return ($field, $s);
820 };
821
822 my $add = sub {
823 my ($h, $n, $v) = @_;
824 return $h->{$n} = $v unless exists $h->{$n};
825 $h->{$n} = [ $h->{$n} ] unless ref $h->{$n};
826 push @{$h->{$n}}, $v;
827 };
828
829 while ($skip < $length) {
830 my $ib = unpack("\@$skip B8", $data);
831
832 # 4.5.2. Indexed Field Line
833
834 if (substr($ib, 0, 2) eq '11') {
835 ($index, $skip) = iunpack(6, $data, $skip);
836
837 $add->(\%headers,
838 $table->[$index][0], $table->[$index][1]);
839 next;
840 }
841
842 # 4.5.4. Literal Field Line with Name Reference
843
844 if (substr($ib, 0, 4) eq '0101') {
845 ($index, $skip) = iunpack(4, $data, $skip);
846 $name = $table->[$index][0];
847 ($value, $skip) = $field->(7, $data, $skip);
848
849 $add->(\%headers, $name, $value);
850 next;
851 }
852
853 # 4.5.6. Literal Field Line with Literal Name
854
855 if (substr($ib, 0, 4) eq '0010') {
856 ($name, $skip) = $field->(3, $data, $skip);
857 ($value, $skip) = $field->(7, $data, $skip);
858
859 $add->(\%headers, $name, $value);
860 next;
861 }
862
863 last;
864 }
865
866 return \%headers;
867 }
868
869 sub static_table {
870 [ ':authority', '' ],
871 [ ':path', '/' ],
872 [ 'age', '0' ],
873 [ 'content-disposition', '' ],
874 [ 'content-length', '0' ],
875 [ 'cookie', '' ],
876 [ 'date', '' ],
877 [ 'etag', '' ],
878 [ 'if-modified-since', '' ],
879 [ 'if-none-match', '' ],
880 [ 'last-modified', '' ],
881 [ 'link', '' ],
882 [ 'location', '' ],
883 [ 'referer', '' ],
884 [ 'set-cookie', '' ],
885 [ ':method', 'CONNECT' ],
886 [ ':method', 'DELETE' ],
887 [ ':method', 'GET' ],
888 [ ':method', 'HEAD' ],
889 [ ':method', 'OPTIONS' ],
890 [ ':method', 'POST' ],
891 [ ':method', 'PUT' ],
892 [ ':scheme', 'http' ],
893 [ ':scheme', 'https' ],
894 [ ':status', '103' ],
895 [ ':status', '200' ],
896 [ ':status', '304' ],
897 [ ':status', '404' ],
898 [ ':status', '503' ],
899 [ 'accept', '*/*' ],
900 [ 'accept', 'application/dns-message' ],
901 [ 'accept-encoding', 'gzip, deflate, br' ],
902 [ 'accept-ranges', 'bytes' ],
903 [ 'access-control-allow-headers', 'cache-control' ],
904 [ 'access-control-allow-headers', 'content-type' ],
905 [ 'access-control-allow-origin', '*' ],
906 [ 'cache-control', 'max-age=0' ],
907 [ 'cache-control', 'max-age=2592000' ],
908 [ 'cache-control', 'max-age=604800' ],
909 [ 'cache-control', 'no-cache' ],
910 [ 'cache-control', 'no-store' ],
911 [ 'cache-control', 'public, max-age=31536000' ],
912 [ 'content-encoding', 'br' ],
913 [ 'content-encoding', 'gzip' ],
914 [ 'content-type', 'application/dns-message' ],
915 [ 'content-type', 'application/javascript' ],
916 [ 'content-type', 'application/json' ],
917 [ 'content-type', 'application/x-www-form-urlencoded' ],
918 [ 'content-type', 'image/gif' ],
919 [ 'content-type', 'image/jpeg' ],
920 [ 'content-type', 'image/png' ],
921 [ 'content-type', 'text/css' ],
922 [ 'content-type', 'text/html; charset=utf-8' ],
923 [ 'content-type', 'text/plain' ],
924 [ 'content-type', 'text/plain;charset=utf-8' ],
925 [ 'range', 'bytes=0-' ],
926 [ 'strict-transport-security', 'max-age=31536000' ],
927 [ 'strict-transport-security',
928 'max-age=31536000; includesubdomains' ],
929 [ 'strict-transport-security',
930 'max-age=31536000; includesubdomains; preload' ],
931 [ 'vary', 'accept-encoding' ],
932 [ 'vary', 'origin' ],
933 [ 'x-content-type-options', 'nosniff' ],
934 [ 'x-xss-protection', '1; mode=block' ],
935 [ ':status', '100' ],
936 [ ':status', '204' ],
937 [ ':status', '206' ],
938 [ ':status', '302' ],
939 [ ':status', '400' ],
940 [ ':status', '403' ],
941 [ ':status', '421' ],
942 [ ':status', '425' ],
943 [ ':status', '500' ],
944 [ 'accept-language', '' ],
945 [ 'access-control-allow-credentials', 'FALSE' ],
946 [ 'access-control-allow-credentials', 'TRUE' ],
947 [ 'access-control-allow-headers', '*' ],
948 [ 'access-control-allow-methods', 'get' ],
949 [ 'access-control-allow-methods', 'get, post, options' ],
950 [ 'access-control-allow-methods', 'options' ],
951 [ 'access-control-expose-headers', 'content-length' ],
952 [ 'access-control-request-headers', 'content-type' ],
953 [ 'access-control-request-method', 'get' ],
954 [ 'access-control-request-method', 'post' ],
955 [ 'alt-svc', 'clear' ],
956 [ 'authorization', '' ],
957 [ 'content-security-policy',
958 "script-src 'none'; object-src 'none'; base-uri 'none'" ],
959 [ 'early-data', '1' ],
960 [ 'expect-ct', '' ],
961 [ 'forwarded', '' ],
962 [ 'if-range', '' ],
963 [ 'origin', '' ],
964 [ 'purpose', 'prefetch' ],
965 [ 'server', '' ],
966 [ 'timing-allow-origin', '*' ],
967 [ 'upgrade-insecure-requests', '1' ],
968 [ 'user-agent', '' ],
969 [ 'x-forwarded-for', '' ],
970 [ 'x-frame-options', 'deny' ],
971 [ 'x-frame-options', 'sameorigin' ],
972 }
973
974 sub huff_code { scalar {
975 pack('C', 0) => '1111111111000',
976 pack('C', 1) => '11111111111111111011000',
977 pack('C', 2) => '1111111111111111111111100010',
978 pack('C', 3) => '1111111111111111111111100011',
979 pack('C', 4) => '1111111111111111111111100100',
980 pack('C', 5) => '1111111111111111111111100101',
981 pack('C', 6) => '1111111111111111111111100110',
982 pack('C', 7) => '1111111111111111111111100111',
983 pack('C', 8) => '1111111111111111111111101000',
984 pack('C', 9) => '111111111111111111101010',
985 pack('C', 10) => '111111111111111111111111111100',
986 pack('C', 11) => '1111111111111111111111101001',
987 pack('C', 12) => '1111111111111111111111101010',
988 pack('C', 13) => '111111111111111111111111111101',
989 pack('C', 14) => '1111111111111111111111101011',
990 pack('C', 15) => '1111111111111111111111101100',
991 pack('C', 16) => '1111111111111111111111101101',
992 pack('C', 17) => '1111111111111111111111101110',
993 pack('C', 18) => '1111111111111111111111101111',
994 pack('C', 19) => '1111111111111111111111110000',
995 pack('C', 20) => '1111111111111111111111110001',
996 pack('C', 21) => '1111111111111111111111110010',
997 pack('C', 22) => '111111111111111111111111111110',
998 pack('C', 23) => '1111111111111111111111110011',
999 pack('C', 24) => '1111111111111111111111110100',
1000 pack('C', 25) => '1111111111111111111111110101',
1001 pack('C', 26) => '1111111111111111111111110110',
1002 pack('C', 27) => '1111111111111111111111110111',
1003 pack('C', 28) => '1111111111111111111111111000',
1004 pack('C', 29) => '1111111111111111111111111001',
1005 pack('C', 30) => '1111111111111111111111111010',
1006 pack('C', 31) => '1111111111111111111111111011',
1007 pack('C', 32) => '010100',
1008 pack('C', 33) => '1111111000',
1009 pack('C', 34) => '1111111001',
1010 pack('C', 35) => '111111111010',
1011 pack('C', 36) => '1111111111001',
1012 pack('C', 37) => '010101',
1013 pack('C', 38) => '11111000',
1014 pack('C', 39) => '11111111010',
1015 pack('C', 40) => '1111111010',
1016 pack('C', 41) => '1111111011',
1017 pack('C', 42) => '11111001',
1018 pack('C', 43) => '11111111011',
1019 pack('C', 44) => '11111010',
1020 pack('C', 45) => '010110',
1021 pack('C', 46) => '010111',
1022 pack('C', 47) => '011000',
1023 pack('C', 48) => '00000',
1024 pack('C', 49) => '00001',
1025 pack('C', 50) => '00010',
1026 pack('C', 51) => '011001',
1027 pack('C', 52) => '011010',
1028 pack('C', 53) => '011011',
1029 pack('C', 54) => '011100',
1030 pack('C', 55) => '011101',
1031 pack('C', 56) => '011110',
1032 pack('C', 57) => '011111',
1033 pack('C', 58) => '1011100',
1034 pack('C', 59) => '11111011',
1035 pack('C', 60) => '111111111111100',
1036 pack('C', 61) => '100000',
1037 pack('C', 62) => '111111111011',
1038 pack('C', 63) => '1111111100',
1039 pack('C', 64) => '1111111111010',
1040 pack('C', 65) => '100001',
1041 pack('C', 66) => '1011101',
1042 pack('C', 67) => '1011110',
1043 pack('C', 68) => '1011111',
1044 pack('C', 69) => '1100000',
1045 pack('C', 70) => '1100001',
1046 pack('C', 71) => '1100010',
1047 pack('C', 72) => '1100011',
1048 pack('C', 73) => '1100100',
1049 pack('C', 74) => '1100101',
1050 pack('C', 75) => '1100110',
1051 pack('C', 76) => '1100111',
1052 pack('C', 77) => '1101000',
1053 pack('C', 78) => '1101001',
1054 pack('C', 79) => '1101010',
1055 pack('C', 80) => '1101011',
1056 pack('C', 81) => '1101100',
1057 pack('C', 82) => '1101101',
1058 pack('C', 83) => '1101110',
1059 pack('C', 84) => '1101111',
1060 pack('C', 85) => '1110000',
1061 pack('C', 86) => '1110001',
1062 pack('C', 87) => '1110010',
1063 pack('C', 88) => '11111100',
1064 pack('C', 89) => '1110011',
1065 pack('C', 90) => '11111101',
1066 pack('C', 91) => '1111111111011',
1067 pack('C', 92) => '1111111111111110000',
1068 pack('C', 93) => '1111111111100',
1069 pack('C', 94) => '11111111111100',
1070 pack('C', 95) => '100010',
1071 pack('C', 96) => '111111111111101',
1072 pack('C', 97) => '00011',
1073 pack('C', 98) => '100011',
1074 pack('C', 99) => '00100',
1075 pack('C', 100) => '100100',
1076 pack('C', 101) => '00101',
1077 pack('C', 102) => '100101',
1078 pack('C', 103) => '100110',
1079 pack('C', 104) => '100111',
1080 pack('C', 105) => '00110',
1081 pack('C', 106) => '1110100',
1082 pack('C', 107) => '1110101',
1083 pack('C', 108) => '101000',
1084 pack('C', 109) => '101001',
1085 pack('C', 110) => '101010',
1086 pack('C', 111) => '00111',
1087 pack('C', 112) => '101011',
1088 pack('C', 113) => '1110110',
1089 pack('C', 114) => '101100',
1090 pack('C', 115) => '01000',
1091 pack('C', 116) => '01001',
1092 pack('C', 117) => '101101',
1093 pack('C', 118) => '1110111',
1094 pack('C', 119) => '1111000',
1095 pack('C', 120) => '1111001',
1096 pack('C', 121) => '1111010',
1097 pack('C', 122) => '1111011',
1098 pack('C', 123) => '111111111111110',
1099 pack('C', 124) => '11111111100',
1100 pack('C', 125) => '11111111111101',
1101 pack('C', 126) => '1111111111101',
1102 pack('C', 127) => '1111111111111111111111111100',
1103 pack('C', 128) => '11111111111111100110',
1104 pack('C', 129) => '1111111111111111010010',
1105 pack('C', 130) => '11111111111111100111',
1106 pack('C', 131) => '11111111111111101000',
1107 pack('C', 132) => '1111111111111111010011',
1108 pack('C', 133) => '1111111111111111010100',
1109 pack('C', 134) => '1111111111111111010101',
1110 pack('C', 135) => '11111111111111111011001',
1111 pack('C', 136) => '1111111111111111010110',
1112 pack('C', 137) => '11111111111111111011010',
1113 pack('C', 138) => '11111111111111111011011',
1114 pack('C', 139) => '11111111111111111011100',
1115 pack('C', 140) => '11111111111111111011101',
1116 pack('C', 141) => '11111111111111111011110',
1117 pack('C', 142) => '111111111111111111101011',
1118 pack('C', 143) => '11111111111111111011111',
1119 pack('C', 144) => '111111111111111111101100',
1120 pack('C', 145) => '111111111111111111101101',
1121 pack('C', 146) => '1111111111111111010111',
1122 pack('C', 147) => '11111111111111111100000',
1123 pack('C', 148) => '111111111111111111101110',
1124 pack('C', 149) => '11111111111111111100001',
1125 pack('C', 150) => '11111111111111111100010',
1126 pack('C', 151) => '11111111111111111100011',
1127 pack('C', 152) => '11111111111111111100100',
1128 pack('C', 153) => '111111111111111011100',
1129 pack('C', 154) => '1111111111111111011000',
1130 pack('C', 155) => '11111111111111111100101',
1131 pack('C', 156) => '1111111111111111011001',
1132 pack('C', 157) => '11111111111111111100110',
1133 pack('C', 158) => '11111111111111111100111',
1134 pack('C', 159) => '111111111111111111101111',
1135 pack('C', 160) => '1111111111111111011010',
1136 pack('C', 161) => '111111111111111011101',
1137 pack('C', 162) => '11111111111111101001',
1138 pack('C', 163) => '1111111111111111011011',
1139 pack('C', 164) => '1111111111111111011100',
1140 pack('C', 165) => '11111111111111111101000',
1141 pack('C', 166) => '11111111111111111101001',
1142 pack('C', 167) => '111111111111111011110',
1143 pack('C', 168) => '11111111111111111101010',
1144 pack('C', 169) => '1111111111111111011101',
1145 pack('C', 170) => '1111111111111111011110',
1146 pack('C', 171) => '111111111111111111110000',
1147 pack('C', 172) => '111111111111111011111',
1148 pack('C', 173) => '1111111111111111011111',
1149 pack('C', 174) => '11111111111111111101011',
1150 pack('C', 175) => '11111111111111111101100',
1151 pack('C', 176) => '111111111111111100000',
1152 pack('C', 177) => '111111111111111100001',
1153 pack('C', 178) => '1111111111111111100000',
1154 pack('C', 179) => '111111111111111100010',
1155 pack('C', 180) => '11111111111111111101101',
1156 pack('C', 181) => '1111111111111111100001',
1157 pack('C', 182) => '11111111111111111101110',
1158 pack('C', 183) => '11111111111111111101111',
1159 pack('C', 184) => '11111111111111101010',
1160 pack('C', 185) => '1111111111111111100010',
1161 pack('C', 186) => '1111111111111111100011',
1162 pack('C', 187) => '1111111111111111100100',
1163 pack('C', 188) => '11111111111111111110000',
1164 pack('C', 189) => '1111111111111111100101',
1165 pack('C', 190) => '1111111111111111100110',
1166 pack('C', 191) => '11111111111111111110001',
1167 pack('C', 192) => '11111111111111111111100000',
1168 pack('C', 193) => '11111111111111111111100001',
1169 pack('C', 194) => '11111111111111101011',
1170 pack('C', 195) => '1111111111111110001',
1171 pack('C', 196) => '1111111111111111100111',
1172 pack('C', 197) => '11111111111111111110010',
1173 pack('C', 198) => '1111111111111111101000',
1174 pack('C', 199) => '1111111111111111111101100',
1175 pack('C', 200) => '11111111111111111111100010',
1176 pack('C', 201) => '11111111111111111111100011',
1177 pack('C', 202) => '11111111111111111111100100',
1178 pack('C', 203) => '111111111111111111111011110',
1179 pack('C', 204) => '111111111111111111111011111',
1180 pack('C', 205) => '11111111111111111111100101',
1181 pack('C', 206) => '111111111111111111110001',
1182 pack('C', 207) => '1111111111111111111101101',
1183 pack('C', 208) => '1111111111111110010',
1184 pack('C', 209) => '111111111111111100011',
1185 pack('C', 210) => '11111111111111111111100110',
1186 pack('C', 211) => '111111111111111111111100000',
1187 pack('C', 212) => '111111111111111111111100001',
1188 pack('C', 213) => '11111111111111111111100111',
1189 pack('C', 214) => '111111111111111111111100010',
1190 pack('C', 215) => '111111111111111111110010',
1191 pack('C', 216) => '111111111111111100100',
1192 pack('C', 217) => '111111111111111100101',
1193 pack('C', 218) => '11111111111111111111101000',
1194 pack('C', 219) => '11111111111111111111101001',
1195 pack('C', 220) => '1111111111111111111111111101',
1196 pack('C', 221) => '111111111111111111111100011',
1197 pack('C', 222) => '111111111111111111111100100',
1198 pack('C', 223) => '111111111111111111111100101',
1199 pack('C', 224) => '11111111111111101100',
1200 pack('C', 225) => '111111111111111111110011',
1201 pack('C', 226) => '11111111111111101101',
1202 pack('C', 227) => '111111111111111100110',
1203 pack('C', 228) => '1111111111111111101001',
1204 pack('C', 229) => '111111111111111100111',
1205 pack('C', 230) => '111111111111111101000',
1206 pack('C', 231) => '11111111111111111110011',
1207 pack('C', 232) => '1111111111111111101010',
1208 pack('C', 233) => '1111111111111111101011',
1209 pack('C', 234) => '1111111111111111111101110',
1210 pack('C', 235) => '1111111111111111111101111',
1211 pack('C', 236) => '111111111111111111110100',
1212 pack('C', 237) => '111111111111111111110101',
1213 pack('C', 238) => '11111111111111111111101010',
1214 pack('C', 239) => '11111111111111111110100',
1215 pack('C', 240) => '11111111111111111111101011',
1216 pack('C', 241) => '111111111111111111111100110',
1217 pack('C', 242) => '11111111111111111111101100',
1218 pack('C', 243) => '11111111111111111111101101',
1219 pack('C', 244) => '111111111111111111111100111',
1220 pack('C', 245) => '111111111111111111111101000',
1221 pack('C', 246) => '111111111111111111111101001',
1222 pack('C', 247) => '111111111111111111111101010',
1223 pack('C', 248) => '111111111111111111111101011',
1224 pack('C', 249) => '1111111111111111111111111110',
1225 pack('C', 250) => '111111111111111111111101100',
1226 pack('C', 251) => '111111111111111111111101101',
1227 pack('C', 252) => '111111111111111111111101110',
1228 pack('C', 253) => '111111111111111111111101111',
1229 pack('C', 254) => '111111111111111111111110000',
1230 pack('C', 255) => '11111111111111111111101110',
1231 '_eos' => '111111111111111111111111111111',
1232 }};
1233
1234 sub huff {
1235 my ($string) = @_;
1236 my $code = &huff_code;
1237
1238 my $ret = join '', map { $code->{$_} } (split //, $string);
1239 my $len = length($ret) + (8 - length($ret) % 8);
1240 $ret .= $code->{_eos};
1241
1242 return pack("B$len", $ret);
1243 }
1244
1245 sub dehuff {
1246 my ($string) = @_;
1247 my $code = &huff_code;
1248 my %decode = reverse %$code;
1249
1250 my $ret = ''; my $c = '';
1251 for (split //, unpack('B*', $string)) {
1252 $c .= $_;
1253 next unless exists $decode{$c};
1254 last if $decode{$c} eq '_eos';
1255
1256 $ret .= $decode{$c};
1257 $c = '';
1258 }
1259
1260 return $ret;
1261 }
1262
1263 sub raw_write {
1264 my ($self, $message) = @_;
1265
1266 if ($self->{chaining}) {
1267 return add_chain($self, $message);
1268 }
1269
1270 $self->{socket}->syswrite($self->encrypt_aead($message, 3));
1271 }
1272
1273 sub start_chain {
1274 my ($self) = @_;
1275
1276 $self->{chaining} = 1;
1277 }
1278
1279 sub add_chain {
1280 my ($self, $buf) = @_;
1281
1282 if ($self->{chained_buf}) {
1283 $self->{chained_buf} .= $buf;
1284 } else {
1285 $self->{chained_buf} = $buf;
1286 }
1287 }
1288
1289 sub send_chain {
1290 my ($self) = @_;
1291
1292 undef $self->{chaining};
1293 $self->raw_write($self->{chained_buf}) if $self->{chained_buf};
1294 undef $self->{chained_buf};
259 } 1295 }
260 1296
261 ############################################################################### 1297 ###############################################################################
262 1298
263 sub parse_frames { 1299 sub parse_frames {