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