11use async_std:: io:: { BufReader , Read } ;
22use async_std:: prelude:: * ;
3- use http_types:: { ensure , ensure_eq , format_err } ;
3+ use http_types:: content :: ContentLength ;
44use http_types:: {
5- headers:: { CONTENT_LENGTH , DATE , TRANSFER_ENCODING } ,
5+ headers:: { DATE , TRANSFER_ENCODING } ,
66 Body , Response , StatusCode ,
77} ;
88
99use std:: convert:: TryFrom ;
1010
11- use crate :: chunked:: ChunkedDecoder ;
1211use crate :: date:: fmt_http_date;
12+ use crate :: { chunked:: ChunkedDecoder , Error } ;
1313use crate :: { MAX_HEADERS , MAX_HEAD_LENGTH } ;
1414
1515const CR : u8 = b'\r' ;
1616const LF : u8 = b'\n' ;
1717
1818/// Decode an HTTP response on the client.
19- pub async fn decode < R > ( reader : R ) -> http_types :: Result < Response >
19+ pub async fn decode < R > ( reader : R ) -> crate :: Result < Option < Response > >
2020where
2121 R : Read + Unpin + Send + Sync + ' static ,
2222{
@@ -29,13 +29,14 @@ where
2929 loop {
3030 let bytes_read = reader. read_until ( LF , & mut buf) . await ?;
3131 // No more bytes are yielded from the stream.
32- assert ! ( bytes_read != 0 , "Empty response" ) ; // TODO: ensure?
32+ if bytes_read == 0 {
33+ return Ok ( None ) ;
34+ }
3335
3436 // Prevent CWE-400 DDOS with large HTTP Headers.
35- ensure ! (
36- buf. len( ) < MAX_HEAD_LENGTH ,
37- "Head byte length should be less than 8kb"
38- ) ;
37+ if buf. len ( ) >= MAX_HEAD_LENGTH {
38+ return Err ( Error :: HeadersTooLong ) ;
39+ }
3940
4041 // We've hit the end delimiter of the stream.
4142 let idx = buf. len ( ) - 1 ;
@@ -49,17 +50,23 @@ where
4950
5051 // Convert our header buf into an httparse instance, and validate.
5152 let status = httparse_res. parse ( & buf) ?;
52- ensure ! ( !status. is_partial( ) , "Malformed HTTP head" ) ;
53+ if status. is_partial ( ) {
54+ return Err ( Error :: PartialHead ) ;
55+ }
5356
54- let code = httparse_res. code ;
55- let code = code. ok_or_else ( || format_err ! ( "No status code found" ) ) ?;
57+ let code = httparse_res. code . ok_or ( Error :: MissingStatusCode ) ?;
5658
5759 // Convert httparse headers + body into a `http_types::Response` type.
58- let version = httparse_res. version ;
59- let version = version. ok_or_else ( || format_err ! ( "No version found" ) ) ?;
60- ensure_eq ! ( version, 1 , "Unsupported HTTP version" ) ;
60+ let version = httparse_res. version . ok_or ( Error :: MissingVersion ) ?;
61+
62+ if version != 1 {
63+ return Err ( Error :: UnsupportedVersion ( version) ) ;
64+ }
65+
66+ let status_code =
67+ StatusCode :: try_from ( code) . map_err ( |_| Error :: UnrecognizedStatusCode ( code) ) ?;
68+ let mut res = Response :: new ( status_code) ;
6169
62- let mut res = Response :: new ( StatusCode :: try_from ( code) ?) ;
6370 for header in httparse_res. headers . iter ( ) {
6471 res. append_header ( header. name , std:: str:: from_utf8 ( header. value ) ?) ;
6572 }
@@ -69,13 +76,13 @@ where
6976 res. insert_header ( DATE , & format ! ( "date: {}\r \n " , date) [ ..] ) ;
7077 }
7178
72- let content_length = res. header ( CONTENT_LENGTH ) ;
79+ let content_length =
80+ ContentLength :: from_headers ( & res) . map_err ( |_| Error :: MalformedHeader ( "content-length" ) ) ?;
7381 let transfer_encoding = res. header ( TRANSFER_ENCODING ) ;
7482
75- ensure ! (
76- content_length. is_none( ) || transfer_encoding. is_none( ) ,
77- "Unexpected Content-Length header"
78- ) ;
83+ if content_length. is_some ( ) && transfer_encoding. is_some ( ) {
84+ return Err ( Error :: UnexpectedHeader ( "content-length" ) ) ;
85+ }
7986
8087 if let Some ( encoding) = transfer_encoding {
8188 if encoding. last ( ) . as_str ( ) == "chunked" {
@@ -84,16 +91,16 @@ where
8491 res. set_body ( Body :: from_reader ( reader, None ) ) ;
8592
8693 // Return the response.
87- return Ok ( res) ;
94+ return Ok ( Some ( res) ) ;
8895 }
8996 }
9097
9198 // Check for Content-Length.
92- if let Some ( len ) = content_length {
93- let len = len . last ( ) . as_str ( ) . parse :: < usize > ( ) ? ;
94- res. set_body ( Body :: from_reader ( reader. take ( len as u64 ) , Some ( len) ) ) ;
99+ if let Some ( content_length ) = content_length {
100+ let len = content_length . len ( ) ;
101+ res. set_body ( Body :: from_reader ( reader. take ( len) , Some ( len as usize ) ) ) ;
95102 }
96103
97104 // Return the response.
98- Ok ( res)
105+ Ok ( Some ( res) )
99106}
0 commit comments