@@ -67,6 +67,7 @@ pub(crate) trait MessageType: Sized {
6767 let mut has_upgrade_websocket = false ;
6868 let mut expect = false ;
6969 let mut chunked = false ;
70+ let mut seen_te = false ;
7071 let mut content_length = None ;
7172
7273 {
@@ -85,8 +86,17 @@ pub(crate) trait MessageType: Sized {
8586 } ;
8687
8788 match name {
88- header:: CONTENT_LENGTH => {
89- if let Ok ( s) = value. to_str ( ) {
89+ header:: CONTENT_LENGTH if content_length. is_some ( ) => {
90+ debug ! ( "multiple Content-Length" ) ;
91+ return Err ( ParseError :: Header ) ;
92+ }
93+
94+ header:: CONTENT_LENGTH => match value. to_str ( ) {
95+ Ok ( s) if s. trim ( ) . starts_with ( "+" ) => {
96+ debug ! ( "illegal Content-Length: {:?}" , s) ;
97+ return Err ( ParseError :: Header ) ;
98+ }
99+ Ok ( s) => {
90100 if let Ok ( len) = s. parse :: < u64 > ( ) {
91101 if len != 0 {
92102 content_length = Some ( len) ;
@@ -95,15 +105,31 @@ pub(crate) trait MessageType: Sized {
95105 debug ! ( "illegal Content-Length: {:?}" , s) ;
96106 return Err ( ParseError :: Header ) ;
97107 }
98- } else {
108+ }
109+ Err ( _) => {
99110 debug ! ( "illegal Content-Length: {:?}" , value) ;
100111 return Err ( ParseError :: Header ) ;
101112 }
102- }
113+ } ,
114+
103115 // transfer-encoding
116+ header:: TRANSFER_ENCODING if seen_te => {
117+ debug ! ( "multiple Transfer-Encoding not allowed" ) ;
118+ return Err ( ParseError :: Header ) ;
119+ }
120+
104121 header:: TRANSFER_ENCODING => {
122+ seen_te = true ;
123+
105124 if let Ok ( s) = value. to_str ( ) . map ( |s| s. trim ( ) ) {
106- chunked = s. eq_ignore_ascii_case ( "chunked" ) ;
125+ if s. eq_ignore_ascii_case ( "chunked" ) {
126+ chunked = true ;
127+ } else if s. eq_ignore_ascii_case ( "identity" ) {
128+ // allow silently since multiple TE headers are already checked
129+ } else {
130+ debug ! ( "illegal Transfer-Encoding: {:?}" , s) ;
131+ return Err ( ParseError :: Header ) ;
132+ }
107133 } else {
108134 return Err ( ParseError :: Header ) ;
109135 }
@@ -510,19 +536,11 @@ impl ChunkedState {
510536 size : & mut u64 ,
511537 ) -> Poll < Result < ChunkedState , io:: Error > > {
512538 let radix = 16 ;
513- match byte ! ( rdr) {
514- b @ b'0' ..=b'9' => {
515- * size *= radix;
516- * size += u64:: from ( b - b'0' ) ;
517- }
518- b @ b'a' ..=b'f' => {
519- * size *= radix;
520- * size += u64:: from ( b + 10 - b'a' ) ;
521- }
522- b @ b'A' ..=b'F' => {
523- * size *= radix;
524- * size += u64:: from ( b + 10 - b'A' ) ;
525- }
539+
540+ let rem = match byte ! ( rdr) {
541+ b @ b'0' ..=b'9' => b - b'0' ,
542+ b @ b'a' ..=b'f' => b + 10 - b'a' ,
543+ b @ b'A' ..=b'F' => b + 10 - b'A' ,
526544 b'\t' | b' ' => return Poll :: Ready ( Ok ( ChunkedState :: SizeLws ) ) ,
527545 b';' => return Poll :: Ready ( Ok ( ChunkedState :: Extension ) ) ,
528546 b'\r' => return Poll :: Ready ( Ok ( ChunkedState :: SizeLf ) ) ,
@@ -532,8 +550,23 @@ impl ChunkedState {
532550 "Invalid chunk size line: Invalid Size" ,
533551 ) ) ) ;
534552 }
553+ } ;
554+
555+ match size. checked_mul ( radix) {
556+ Some ( n) => {
557+ * size = n as u64 ;
558+ * size += rem as u64 ;
559+
560+ Poll :: Ready ( Ok ( ChunkedState :: Size ) )
561+ }
562+ None => {
563+ debug ! ( "chunk size would overflow" ) ;
564+ Poll :: Ready ( Err ( io:: Error :: new (
565+ io:: ErrorKind :: InvalidInput ,
566+ "Invalid chunk size line: Invalid Size" ,
567+ ) ) )
568+ }
535569 }
536- Poll :: Ready ( Ok ( ChunkedState :: Size ) )
537570 }
538571
539572 fn read_size_lws ( rdr : & mut BytesMut ) -> Poll < Result < ChunkedState , io:: Error > > {
@@ -552,6 +585,11 @@ impl ChunkedState {
552585 fn read_extension ( rdr : & mut BytesMut ) -> Poll < Result < ChunkedState , io:: Error > > {
553586 match byte ! ( rdr) {
554587 b'\r' => Poll :: Ready ( Ok ( ChunkedState :: SizeLf ) ) ,
588+ // strictly 0x20 (space) should be disallowed but we don't parse quoted strings here
589+ 0x00 ..=0x08 | 0x0a ..=0x1f | 0x7f => Poll :: Ready ( Err ( io:: Error :: new (
590+ io:: ErrorKind :: InvalidInput ,
591+ "Invalid character in chunk extension" ,
592+ ) ) ) ,
555593 _ => Poll :: Ready ( Ok ( ChunkedState :: Extension ) ) , // no supported extensions
556594 }
557595 }
@@ -977,13 +1015,7 @@ mod tests {
9771015 "GET /test HTTP/1.1\r \n \
9781016 transfer-encoding: chnked\r \n \r \n ",
9791017 ) ;
980- let req = parse_ready ! ( & mut buf) ;
981-
982- if let Ok ( val) = req. chunked ( ) {
983- assert ! ( !val) ;
984- } else {
985- unreachable ! ( "Error" ) ;
986- }
1018+ expect_parse_err ! ( & mut buf) ;
9871019 }
9881020
9891021 #[ test]
0 commit comments