@@ -5,7 +5,8 @@ use std::str::FromStr;
5
5
use async_dup:: { Arc , Mutex } ;
6
6
use async_std:: io:: { BufReader , Read , Write } ;
7
7
use async_std:: { prelude:: * , task} ;
8
- use http_types:: headers:: { CONTENT_LENGTH , EXPECT , TRANSFER_ENCODING } ;
8
+ use http_types:: content:: ContentLength ;
9
+ use http_types:: headers:: { EXPECT , TRANSFER_ENCODING } ;
9
10
use http_types:: { ensure, ensure_eq, format_err} ;
10
11
use http_types:: { Body , Method , Request , Url } ;
11
12
@@ -82,11 +83,16 @@ where
82
83
req. append_header ( header. name , std:: str:: from_utf8 ( header. value ) ?) ;
83
84
}
84
85
85
- let content_length = req . header ( CONTENT_LENGTH ) ;
86
+ let content_length = ContentLength :: from_headers ( & req ) ? ;
86
87
let transfer_encoding = req. header ( TRANSFER_ENCODING ) ;
87
88
88
- http_types:: ensure!(
89
+ // Return a 400 status if both Content-Length and Transfer-Encoding headers
90
+ // are set to prevent request smuggling attacks.
91
+ //
92
+ // https://tools.ietf.org/html/rfc7230#section-3.3.3
93
+ http_types:: ensure_status!(
89
94
content_length. is_none( ) || transfer_encoding. is_none( ) ,
95
+ 400 ,
90
96
"Unexpected Content-Length header"
91
97
) ;
92
98
@@ -123,11 +129,11 @@ where
123
129
req. set_body ( Body :: from_reader ( reader, None ) ) ;
124
130
return Ok ( Some ( ( req, BodyReader :: Chunked ( reader_clone) ) ) ) ;
125
131
} else if let Some ( len) = content_length {
126
- let len = len. last ( ) . as_str ( ) . parse :: < usize > ( ) ? ;
127
- let reader = Arc :: new ( Mutex :: new ( reader. take ( len as u64 ) ) ) ;
132
+ let len = len. len ( ) ;
133
+ let reader = Arc :: new ( Mutex :: new ( reader. take ( len) ) ) ;
128
134
req. set_body ( Body :: from_reader (
129
135
BufReader :: new ( ReadNotifier :: new ( reader. clone ( ) , body_read_sender) ) ,
130
- Some ( len) ,
136
+ Some ( len as usize ) ,
131
137
) ) ;
132
138
Ok ( Some ( ( req, BodyReader :: Fixed ( reader) ) ) )
133
139
} else {
0 commit comments