@@ -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,14 @@ 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 =
60
+ calc_max_continuation_frames ( max_header_list_size, inner. decoder ( ) . max_frame_length ( ) ) ;
54
61
FramedRead {
55
62
inner,
56
63
hpack : hpack:: Decoder :: new ( DEFAULT_SETTINGS_HEADER_TABLE_SIZE ) ,
57
- max_header_list_size : DEFAULT_SETTINGS_MAX_HEADER_LIST_SIZE ,
64
+ max_header_list_size,
65
+ max_continuation_frames,
58
66
partial : None ,
59
67
}
60
68
}
@@ -68,7 +76,6 @@ impl<T> FramedRead<T> {
68
76
}
69
77
70
78
/// Returns the current max frame size setting
71
- #[ cfg( feature = "unstable" ) ]
72
79
#[ inline]
73
80
pub fn max_frame_size ( & self ) -> usize {
74
81
self . inner . decoder ( ) . max_frame_length ( )
@@ -80,13 +87,17 @@ impl<T> FramedRead<T> {
80
87
#[ inline]
81
88
pub fn set_max_frame_size ( & mut self , val : usize ) {
82
89
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)
90
+ self . inner . decoder_mut ( ) . set_max_frame_length ( val) ;
91
+ // Update max CONTINUATION frames too, since its based on this
92
+ self . max_continuation_frames = calc_max_continuation_frames ( self . max_header_list_size , val) ;
84
93
}
85
94
86
95
/// Update the max header list size setting.
87
96
#[ inline]
88
97
pub fn set_max_header_list_size ( & mut self , val : usize ) {
89
98
self . max_header_list_size = val;
99
+ // Update max CONTINUATION frames too, since its based on this
100
+ self . max_continuation_frames = calc_max_continuation_frames ( val, self . max_frame_size ( ) ) ;
90
101
}
91
102
92
103
/// Update the header table size setting.
@@ -96,12 +107,22 @@ impl<T> FramedRead<T> {
96
107
}
97
108
}
98
109
110
+ fn calc_max_continuation_frames ( header_max : usize , frame_max : usize ) -> usize {
111
+ // At least this many frames needed to use max header list size
112
+ let min_frames_for_list = ( header_max / frame_max) . max ( 1 ) ;
113
+ // Some padding for imperfectly packed frames
114
+ // 25% without floats
115
+ let padding = min_frames_for_list >> 2 ;
116
+ min_frames_for_list. saturating_add ( padding) . max ( 5 )
117
+ }
118
+
99
119
/// Decodes a frame.
100
120
///
101
121
/// This method is intentionally de-generified and outlined because it is very large.
102
122
fn decode_frame (
103
123
hpack : & mut hpack:: Decoder ,
104
124
max_header_list_size : usize ,
125
+ max_continuation_frames : usize ,
105
126
partial_inout : & mut Option < Partial > ,
106
127
mut bytes : BytesMut ,
107
128
) -> Result < Option < Frame > , Error > {
@@ -169,6 +190,7 @@ fn decode_frame(
169
190
* partial_inout = Some ( Partial {
170
191
frame: Continuable :: $frame( frame) ,
171
192
buf: payload,
193
+ continuation_frames_count: 0 ,
172
194
} ) ;
173
195
174
196
return Ok ( None ) ;
@@ -273,6 +295,22 @@ fn decode_frame(
273
295
return Err ( Error :: library_go_away ( Reason :: PROTOCOL_ERROR ) ) ;
274
296
}
275
297
298
+ // Check for CONTINUATION flood
299
+ if is_end_headers {
300
+ partial. continuation_frames_count = 0 ;
301
+ } else {
302
+ let cnt = partial. continuation_frames_count + 1 ;
303
+ if cnt > max_continuation_frames {
304
+ tracing:: debug!( "too_many_continuations, max = {}" , max_continuation_frames) ;
305
+ return Err ( Error :: library_go_away_data (
306
+ Reason :: ENHANCE_YOUR_CALM ,
307
+ "too_many_continuations" ,
308
+ ) ) ;
309
+ } else {
310
+ partial. continuation_frames_count = cnt;
311
+ }
312
+ }
313
+
276
314
// Extend the buf
277
315
if partial. buf . is_empty ( ) {
278
316
partial. buf = bytes. split_off ( frame:: HEADER_LEN ) ;
@@ -354,9 +392,16 @@ where
354
392
ref mut hpack,
355
393
max_header_list_size,
356
394
ref mut partial,
395
+ max_continuation_frames,
357
396
..
358
397
} = * self ;
359
- if let Some ( frame) = decode_frame ( hpack, max_header_list_size, partial, bytes) ? {
398
+ if let Some ( frame) = decode_frame (
399
+ hpack,
400
+ max_header_list_size,
401
+ max_continuation_frames,
402
+ partial,
403
+ bytes,
404
+ ) ? {
360
405
tracing:: debug!( ?frame, "received" ) ;
361
406
return Poll :: Ready ( Some ( Ok ( frame) ) ) ;
362
407
}
0 commit comments