@@ -5,7 +5,12 @@ use flate2::bufread::GzDecoder;
55
66use crate :: error:: ProtocolError ;
77
8- pub ( crate ) fn decode_gzip_chunk ( body : Bytes ) -> std:: result:: Result < Bytes , ProtocolError > {
8+ const MAX_GZIP_PREALLOCATED_BYTES : usize = 128 * 1024 * 1024 ;
9+
10+ pub ( crate ) fn decode_gzip_chunk (
11+ body : Bytes ,
12+ expected_uncompressed_size : Option < usize > ,
13+ ) -> std:: result:: Result < Bytes , ProtocolError > {
914 if body. is_empty ( ) {
1015 return Ok ( body) ;
1116 }
@@ -16,7 +21,8 @@ pub(crate) fn decode_gzip_chunk(body: Bytes) -> std::result::Result<Bytes, Proto
1621
1722 if body[ 0 ] == 0x1f && body[ 1 ] == 0x8b {
1823 let mut decoder = GzDecoder :: new ( & body[ ..] ) ;
19- let mut decoded = Vec :: new ( ) ;
24+ let mut decoded =
25+ Vec :: with_capacity ( gzip_preallocated_capacity ( expected_uncompressed_size) ) ;
2026 decoder
2127 . read_to_end ( & mut decoded)
2228 . map_err ( ProtocolError :: gzip_decode) ?;
@@ -26,6 +32,12 @@ pub(crate) fn decode_gzip_chunk(body: Bytes) -> std::result::Result<Bytes, Proto
2632 }
2733}
2834
35+ fn gzip_preallocated_capacity ( expected_uncompressed_size : Option < usize > ) -> usize {
36+ expected_uncompressed_size
37+ . filter ( |size| * size <= MAX_GZIP_PREALLOCATED_BYTES )
38+ . unwrap_or ( 0 )
39+ }
40+
2941#[ cfg( test) ]
3042mod tests {
3143 use std:: error:: Error as StdError ;
@@ -35,12 +47,26 @@ mod tests {
3547
3648 #[ test]
3749 fn malformed_gzip_is_protocol_error ( ) {
38- let err: Error = decode_gzip_chunk ( Bytes :: from_static ( b"\x1f \x8b garbage" ) )
50+ let err: Error = decode_gzip_chunk ( Bytes :: from_static ( b"\x1f \x8b garbage" ) , None )
3951 . unwrap_err ( )
4052 . into ( ) ;
4153
4254 assert_eq ! ( err. kind( ) , ErrorKind :: Protocol ) ;
4355 assert ! ( err. to_string( ) . contains( "gzip decompression failed" ) ) ;
4456 assert ! ( StdError :: source( & err) . is_some( ) ) ;
4557 }
58+
59+ #[ test]
60+ fn gzip_capacity_hint_uses_bounded_expected_size ( ) {
61+ assert_eq ! ( gzip_preallocated_capacity( Some ( 1024 ) ) , 1024 ) ;
62+ assert_eq ! (
63+ gzip_preallocated_capacity( Some ( MAX_GZIP_PREALLOCATED_BYTES ) ) ,
64+ MAX_GZIP_PREALLOCATED_BYTES
65+ ) ;
66+ assert_eq ! (
67+ gzip_preallocated_capacity( Some ( MAX_GZIP_PREALLOCATED_BYTES + 1 ) ) ,
68+ 0
69+ ) ;
70+ assert_eq ! ( gzip_preallocated_capacity( None ) , 0 ) ;
71+ }
4672}
0 commit comments