@@ -47,6 +47,7 @@ enum Kind {
4747
4848#[ derive( Debug , PartialEq , Clone , Copy ) ]
4949enum ChunkedState {
50+ Start ,
5051 Size ,
5152 SizeLws ,
5253 Extension ,
@@ -72,7 +73,7 @@ impl Decoder {
7273
7374 pub ( crate ) fn chunked ( ) -> Decoder {
7475 Decoder {
75- kind : Kind :: Chunked ( ChunkedState :: Size , 0 ) ,
76+ kind : Kind :: Chunked ( ChunkedState :: new ( ) , 0 ) ,
7677 }
7778 }
7879
@@ -180,7 +181,22 @@ macro_rules! byte (
180181 } )
181182) ;
182183
184+ macro_rules! or_overflow {
185+ ( $e: expr) => (
186+ match $e {
187+ Some ( val) => val,
188+ None => return Poll :: Ready ( Err ( io:: Error :: new(
189+ io:: ErrorKind :: InvalidData ,
190+ "invalid chunk size: overflow" ,
191+ ) ) ) ,
192+ }
193+ )
194+ }
195+
183196impl ChunkedState {
197+ fn new ( ) -> ChunkedState {
198+ ChunkedState :: Start
199+ }
184200 fn step < R : MemRead > (
185201 & self ,
186202 cx : & mut Context < ' _ > ,
@@ -190,6 +206,7 @@ impl ChunkedState {
190206 ) -> Poll < Result < ChunkedState , io:: Error > > {
191207 use self :: ChunkedState :: * ;
192208 match * self {
209+ Start => ChunkedState :: read_start ( cx, body, size) ,
193210 Size => ChunkedState :: read_size ( cx, body, size) ,
194211 SizeLws => ChunkedState :: read_size_lws ( cx, body) ,
195212 Extension => ChunkedState :: read_extension ( cx, body) ,
@@ -204,25 +221,46 @@ impl ChunkedState {
204221 End => Poll :: Ready ( Ok ( ChunkedState :: End ) ) ,
205222 }
206223 }
207- fn read_size < R : MemRead > (
224+
225+ fn read_start < R : MemRead > (
208226 cx : & mut Context < ' _ > ,
209227 rdr : & mut R ,
210228 size : & mut u64 ,
211229 ) -> Poll < Result < ChunkedState , io:: Error > > {
212- trace ! ( "Read chunk hex size " ) ;
230+ trace ! ( "Read chunk start " ) ;
213231
214- macro_rules! or_overflow {
215- ( $e: expr) => (
216- match $e {
217- Some ( val) => val,
218- None => return Poll :: Ready ( Err ( io:: Error :: new(
219- io:: ErrorKind :: InvalidData ,
220- "invalid chunk size: overflow" ,
221- ) ) ) ,
222- }
223- )
232+ let radix = 16 ;
233+ match byte ! ( rdr, cx) {
234+ b @ b'0' ..=b'9' => {
235+ * size = or_overflow ! ( size. checked_mul( radix) ) ;
236+ * size = or_overflow ! ( size. checked_add( ( b - b'0' ) as u64 ) ) ;
237+ }
238+ b @ b'a' ..=b'f' => {
239+ * size = or_overflow ! ( size. checked_mul( radix) ) ;
240+ * size = or_overflow ! ( size. checked_add( ( b + 10 - b'a' ) as u64 ) ) ;
241+ }
242+ b @ b'A' ..=b'F' => {
243+ * size = or_overflow ! ( size. checked_mul( radix) ) ;
244+ * size = or_overflow ! ( size. checked_add( ( b + 10 - b'A' ) as u64 ) ) ;
245+ }
246+ _ => {
247+ return Poll :: Ready ( Err ( io:: Error :: new (
248+ io:: ErrorKind :: InvalidInput ,
249+ "Invalid chunk size line: missing size digit" ,
250+ ) ) ) ;
251+ }
224252 }
225253
254+ Poll :: Ready ( Ok ( ChunkedState :: Size ) )
255+ }
256+
257+ fn read_size < R : MemRead > (
258+ cx : & mut Context < ' _ > ,
259+ rdr : & mut R ,
260+ size : & mut u64 ,
261+ ) -> Poll < Result < ChunkedState , io:: Error > > {
262+ trace ! ( "Read chunk hex size" ) ;
263+
226264 let radix = 16 ;
227265 match byte ! ( rdr, cx) {
228266 b @ b'0' ..=b'9' => {
@@ -478,7 +516,7 @@ mod tests {
478516 use std:: io:: ErrorKind :: { InvalidData , InvalidInput , UnexpectedEof } ;
479517
480518 async fn read ( s : & str ) -> u64 {
481- let mut state = ChunkedState :: Size ;
519+ let mut state = ChunkedState :: new ( ) ;
482520 let rdr = & mut s. as_bytes ( ) ;
483521 let mut size = 0 ;
484522 loop {
@@ -495,7 +533,7 @@ mod tests {
495533 }
496534
497535 async fn read_err ( s : & str , expected_err : io:: ErrorKind ) {
498- let mut state = ChunkedState :: Size ;
536+ let mut state = ChunkedState :: new ( ) ;
499537 let rdr = & mut s. as_bytes ( ) ;
500538 let mut size = 0 ;
501539 loop {
@@ -532,6 +570,9 @@ mod tests {
532570 // Missing LF or CRLF
533571 read_err ( "F\r F" , InvalidInput ) . await ;
534572 read_err ( "F" , UnexpectedEof ) . await ;
573+ // Missing digit
574+ read_err ( "\r \n \r \n " , InvalidInput ) . await ;
575+ read_err ( "\r \n " , InvalidInput ) . await ;
535576 // Invalid hex digit
536577 read_err ( "X\r \n " , InvalidInput ) . await ;
537578 read_err ( "1X\r \n " , InvalidInput ) . await ;
0 commit comments