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; |