Mercurial > hg > nginx-tests
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 { |