/usr/share/perl5/Protocol/HTTP2/Frame.pm is in libprotocol-http2-perl 1.08-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 | package Protocol::HTTP2::Frame;
use strict;
use warnings;
use Protocol::HTTP2::Trace qw(tracer);
use Protocol::HTTP2::Constants
qw(const_name :frame_types :errors :preface :states :flags :limits :settings);
use Protocol::HTTP2::Frame::Data;
use Protocol::HTTP2::Frame::Headers;
use Protocol::HTTP2::Frame::Priority;
use Protocol::HTTP2::Frame::Rst_stream;
use Protocol::HTTP2::Frame::Settings;
use Protocol::HTTP2::Frame::Push_promise;
use Protocol::HTTP2::Frame::Ping;
use Protocol::HTTP2::Frame::Goaway;
use Protocol::HTTP2::Frame::Window_update;
use Protocol::HTTP2::Frame::Continuation;
# Table of payload decoders
my %frame_class = (
&DATA => 'Data',
&HEADERS => 'Headers',
&PRIORITY => 'Priority',
&RST_STREAM => 'Rst_stream',
&SETTINGS => 'Settings',
&PUSH_PROMISE => 'Push_promise',
&PING => 'Ping',
&GOAWAY => 'Goaway',
&WINDOW_UPDATE => 'Window_update',
&CONTINUATION => 'Continuation',
);
my %decoder =
map { $_ => \&{ 'Protocol::HTTP2::Frame::' . $frame_class{$_} . '::decode' } }
keys %frame_class;
my %encoder =
map { $_ => \&{ 'Protocol::HTTP2::Frame::' . $frame_class{$_} . '::encode' } }
keys %frame_class;
sub frame_encode {
my ( $con, $type, $flags, $stream_id, $data_ref ) = @_;
my $payload = $encoder{$type}->( $con, \$flags, $stream_id, $data_ref );
my $l = length $payload;
pack( 'CnC2N', ( $l >> 16 ), ( $l & 0xFFFF ), $type, $flags, $stream_id )
. $payload;
}
sub preface_decode {
my ( $con, $buf_ref, $buf_offset ) = @_;
return 0 if length($$buf_ref) - $buf_offset < length(PREFACE);
return
index( $$buf_ref, PREFACE, $buf_offset ) == -1 ? undef : length(PREFACE);
}
sub preface_encode {
PREFACE;
}
sub frame_header_decode {
my ( undef, $buf_ref, $buf_offset ) = @_;
my ( $hl, $ll, $type, $flags, $stream_id ) =
unpack( 'CnC2N', substr( $$buf_ref, $buf_offset, FRAME_HEADER_SIZE ) );
my $length = ( $hl << 16 ) + $ll;
$stream_id &= 0x7FFF_FFFF;
return $length, $type, $flags, $stream_id;
}
sub frame_decode {
my ( $con, $buf_ref, $buf_offset ) = @_;
return 0 if length($$buf_ref) - $buf_offset < FRAME_HEADER_SIZE;
my ( $length, $type, $flags, $stream_id ) =
$con->frame_header_decode( $buf_ref, $buf_offset );
if ( $length > $con->dec_setting(SETTINGS_MAX_FRAME_SIZE) ) {
tracer->error("Frame is too large: $length\n");
$con->error(FRAME_SIZE_ERROR);
return undef;
}
return 0
if length($$buf_ref) - $buf_offset - FRAME_HEADER_SIZE - $length < 0;
tracer->debug(
sprintf "TYPE = %s(%i), FLAGS = %08b, STREAM_ID = %i, "
. "LENGTH = %i\n",
exists $frame_class{$type}
? const_name( "frame_types", $type )
: "UNKNOWN",
$type,
$flags,
$stream_id,
$length
);
my $pending_stream_id = $con->pending_stream;
if ( $pending_stream_id
&& ( $type != CONTINUATION || $pending_stream_id != $stream_id ) )
{
tracer->debug("Expected CONTINUATION for stream $pending_stream_id");
$con->error(PROTOCOL_ERROR);
return undef;
}
# Unknown type of frame
if ( !exists $frame_class{$type} ) {
tracer->info("ignore unknown frame type $type");
return FRAME_HEADER_SIZE + $length;
}
$con->decode_context->{frame} = {
type => $type,
flags => $flags,
length => $length,
stream => $stream_id,
};
# Try to create new stream structure
if ( $stream_id
&& !$con->stream($stream_id)
&& !$con->new_peer_stream($stream_id) )
{
return $con->error ? undef : FRAME_HEADER_SIZE + $length;
}
return undef
unless defined $decoder{$type}
->( $con, $buf_ref, $buf_offset + FRAME_HEADER_SIZE, $length );
# Arrived frame may change state of stream
$con->state_machine( 'recv', $type, $flags, $stream_id );
return FRAME_HEADER_SIZE + $length;
}
=pod
=head1 NOTES
=head2 Frame Types vs Flags and Stream ID
Table represent possible combination of frame types and flags.
Last column -- Stream ID of frame types (x -- sid >= 1, 0 -- sid = 0)
+-END_STREAM 0x1
| +-ACK 0x1
| | +-END_HEADERS 0x4
| | | +-PADDED 0x8
| | | | +-PRIORITY 0x20
| | | | | +-stream id (value)
| | | | | |
| frame type\flag | V | V | V | V | V | | V |
| --------------- |:-:|:-:|:-:|:-:|:-:| - |:---:|
| DATA | x | | | x | | | x |
| HEADERS | x | | x | x | x | | x |
| PRIORITY | | | | | | | x |
| RST_STREAM | | | | | | | x |
| SETTINGS | | x | | | | | 0 |
| PUSH_PROMISE | | | x | x | | | x |
| PING | | x | | | | | 0 |
| GOAWAY | | | | | | | 0 |
| WINDOW_UPDATE | | | | | | | 0/x |
| CONTINUATION | | | x | x | | | x |
=cut
1;
|