@@ -30,6 +30,8 @@ pub struct FramedRead<T> {
30
30
31
31
max_header_list_size : usize ,
32
32
33
+ max_continuation_frames : usize ,
34
+
33
35
partial : Option < Partial > ,
34
36
}
35
37
@@ -41,6 +43,8 @@ struct Partial {
41
43
42
44
/// Partial header payload
43
45
buf : BytesMut ,
46
+
47
+ continuation_frames_count : usize ,
44
48
}
45
49
46
50
#[ derive( Debug ) ]
@@ -51,10 +55,16 @@ enum Continuable {
51
55
52
56
impl < T > FramedRead < T > {
53
57
pub fn new ( inner : InnerFramedRead < T , LengthDelimitedCodec > ) -> FramedRead < T > {
58
+ let max_header_list_size = DEFAULT_SETTINGS_MAX_HEADER_LIST_SIZE ;
59
+ let max_continuation_frames = calc_max_continuation_frames (
60
+ max_header_list_size,
61
+ inner. decoder ( ) . max_frame_length ( ) ,
62
+ ) ;
54
63
FramedRead {
55
64
inner,
56
65
hpack : hpack:: Decoder :: new ( DEFAULT_SETTINGS_HEADER_TABLE_SIZE ) ,
57
- max_header_list_size : DEFAULT_SETTINGS_MAX_HEADER_LIST_SIZE ,
66
+ max_header_list_size,
67
+ max_continuation_frames,
58
68
partial : None ,
59
69
}
60
70
}
@@ -68,7 +78,6 @@ impl<T> FramedRead<T> {
68
78
}
69
79
70
80
/// Returns the current max frame size setting
71
- #[ cfg( feature = "unstable" ) ]
72
81
#[ inline]
73
82
pub fn max_frame_size ( & self ) -> usize {
74
83
self . inner . decoder ( ) . max_frame_length ( )
@@ -80,13 +89,23 @@ impl<T> FramedRead<T> {
80
89
#[ inline]
81
90
pub fn set_max_frame_size ( & mut self , val : usize ) {
82
91
assert ! ( DEFAULT_MAX_FRAME_SIZE as usize <= val && val <= MAX_MAX_FRAME_SIZE as usize ) ;
83
- self . inner . decoder_mut ( ) . set_max_frame_length ( val)
92
+ self . inner . decoder_mut ( ) . set_max_frame_length ( val) ;
93
+ // Update max CONTINUATION frames too, since its based on this
94
+ self . max_continuation_frames = calc_max_continuation_frames (
95
+ self . max_header_list_size ,
96
+ val,
97
+ ) ;
84
98
}
85
99
86
100
/// Update the max header list size setting.
87
101
#[ inline]
88
102
pub fn set_max_header_list_size ( & mut self , val : usize ) {
89
103
self . max_header_list_size = val;
104
+ // Update max CONTINUATION frames too, since its based on this
105
+ self . max_continuation_frames = calc_max_continuation_frames (
106
+ val,
107
+ self . max_frame_size ( ) ,
108
+ ) ;
90
109
}
91
110
92
111
/// Update the header table size setting.
@@ -96,12 +115,22 @@ impl<T> FramedRead<T> {
96
115
}
97
116
}
98
117
118
+ fn calc_max_continuation_frames ( header_max : usize , frame_max : usize ) -> usize {
119
+ // At least this many frames needed to use max header list size
120
+ let min_frames_for_list = ( header_max / frame_max) . max ( 1 ) ;
121
+ // Some padding for imperfectly packed frames
122
+ // 25% without floats
123
+ let padding = min_frames_for_list >> 2 ;
124
+ min_frames_for_list. saturating_add ( padding) . max ( 5 )
125
+ }
126
+
99
127
/// Decodes a frame.
100
128
///
101
129
/// This method is intentionally de-generified and outlined because it is very large.
102
130
fn decode_frame (
103
131
hpack : & mut hpack:: Decoder ,
104
132
max_header_list_size : usize ,
133
+ max_continuation_frames : usize ,
105
134
partial_inout : & mut Option < Partial > ,
106
135
mut bytes : BytesMut ,
107
136
) -> Result < Option < Frame > , Error > {
@@ -169,6 +198,7 @@ fn decode_frame(
169
198
* partial_inout = Some ( Partial {
170
199
frame: Continuable :: $frame( frame) ,
171
200
buf: payload,
201
+ continuation_frames_count: 0 ,
172
202
} ) ;
173
203
174
204
return Ok ( None ) ;
@@ -259,6 +289,7 @@ fn decode_frame(
259
289
Kind :: Continuation => {
260
290
let is_end_headers = ( head. flag ( ) & 0x4 ) == 0x4 ;
261
291
292
+
262
293
let mut partial = match partial_inout. take ( ) {
263
294
Some ( partial) => partial,
264
295
None => {
@@ -273,6 +304,23 @@ fn decode_frame(
273
304
return Err ( Error :: library_go_away ( Reason :: PROTOCOL_ERROR ) ) ;
274
305
}
275
306
307
+ // Check for CONTINUATION flood
308
+ if is_end_headers {
309
+ partial. continuation_frames_count = 0 ;
310
+ } else {
311
+ let cnt = partial. continuation_frames_count + 1 ;
312
+ if cnt > max_continuation_frames {
313
+ tracing:: debug!( "too_many_continuations, max = {}" , max_continuation_frames) ;
314
+ return Err ( Error :: library_go_away_data (
315
+ Reason :: ENHANCE_YOUR_CALM ,
316
+ "too_many_continuations" ,
317
+ ) ) ;
318
+ } else {
319
+ partial. continuation_frames_count = cnt;
320
+ }
321
+ }
322
+
323
+
276
324
// Extend the buf
277
325
if partial. buf . is_empty ( ) {
278
326
partial. buf = bytes. split_off ( frame:: HEADER_LEN ) ;
@@ -354,9 +402,16 @@ where
354
402
ref mut hpack,
355
403
max_header_list_size,
356
404
ref mut partial,
405
+ max_continuation_frames,
357
406
..
358
407
} = * self ;
359
- if let Some ( frame) = decode_frame ( hpack, max_header_list_size, partial, bytes) ? {
408
+ if let Some ( frame) = decode_frame (
409
+ hpack,
410
+ max_header_list_size,
411
+ max_continuation_frames,
412
+ partial,
413
+ bytes,
414
+ ) ? {
360
415
tracing:: debug!( ?frame, "received" ) ;
361
416
return Poll :: Ready ( Some ( Ok ( frame) ) ) ;
362
417
}
0 commit comments