@@ -30,6 +30,8 @@ pub struct FramedRead<T> {
3030
3131 max_header_list_size : usize ,
3232
33+ max_continuation_frames : usize ,
34+
3335 partial : Option < Partial > ,
3436}
3537
@@ -41,6 +43,8 @@ struct Partial {
4143
4244 /// Partial header payload
4345 buf : BytesMut ,
46+
47+ continuation_frames_count : usize ,
4448}
4549
4650#[ derive( Debug ) ]
@@ -51,10 +55,14 @@ enum Continuable {
5155
5256impl < T > FramedRead < T > {
5357 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 ( ) ) ;
5461 FramedRead {
5562 inner,
5663 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,
5866 partial : None ,
5967 }
6068 }
@@ -68,7 +76,6 @@ impl<T> FramedRead<T> {
6876 }
6977
7078 /// Returns the current max frame size setting
71- #[ cfg( feature = "unstable" ) ]
7279 #[ inline]
7380 pub fn max_frame_size ( & self ) -> usize {
7481 self . inner . decoder ( ) . max_frame_length ( )
@@ -80,13 +87,17 @@ impl<T> FramedRead<T> {
8087 #[ inline]
8188 pub fn set_max_frame_size ( & mut self , val : usize ) {
8289 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) ;
8493 }
8594
8695 /// Update the max header list size setting.
8796 #[ inline]
8897 pub fn set_max_header_list_size ( & mut self , val : usize ) {
8998 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 ( ) ) ;
90101 }
91102
92103 /// Update the header table size setting.
@@ -96,12 +107,22 @@ impl<T> FramedRead<T> {
96107 }
97108}
98109
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+
99119/// Decodes a frame.
100120///
101121/// This method is intentionally de-generified and outlined because it is very large.
102122fn decode_frame (
103123 hpack : & mut hpack:: Decoder ,
104124 max_header_list_size : usize ,
125+ max_continuation_frames : usize ,
105126 partial_inout : & mut Option < Partial > ,
106127 mut bytes : BytesMut ,
107128) -> Result < Option < Frame > , Error > {
@@ -169,6 +190,7 @@ fn decode_frame(
169190 * partial_inout = Some ( Partial {
170191 frame: Continuable :: $frame( frame) ,
171192 buf: payload,
193+ continuation_frames_count: 0 ,
172194 } ) ;
173195
174196 return Ok ( None ) ;
@@ -273,6 +295,22 @@ fn decode_frame(
273295 return Err ( Error :: library_go_away ( Reason :: PROTOCOL_ERROR ) ) ;
274296 }
275297
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+
276314 // Extend the buf
277315 if partial. buf . is_empty ( ) {
278316 partial. buf = bytes. split_off ( frame:: HEADER_LEN ) ;
@@ -354,9 +392,16 @@ where
354392 ref mut hpack,
355393 max_header_list_size,
356394 ref mut partial,
395+ max_continuation_frames,
357396 ..
358397 } = * 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+ ) ? {
360405 tracing:: debug!( ?frame, "received" ) ;
361406 return Poll :: Ready ( Some ( Ok ( frame) ) ) ;
362407 }
0 commit comments