From 42bffb7363c89d9a6bc3400a1892125a15767222 Mon Sep 17 00:00:00 2001 From: Martin Algesten Date: Fri, 28 Jun 2024 18:35:37 +0200 Subject: [PATCH] Handle missing \r\n with connection close --- src/chunked/decoder.rs | 55 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 2 deletions(-) diff --git a/src/chunked/decoder.rs b/src/chunked/decoder.rs index 410a753d..9016540e 100644 --- a/src/chunked/decoder.rs +++ b/src/chunked/decoder.rs @@ -109,6 +109,39 @@ where _ => Err(IoError::new(ErrorKind::InvalidInput, DecoderError)), } } + + // Sometimes the last \r\n is missing. + fn read_end(&mut self) -> IoResult<()> { + fn expect_or_end( + bytes: &mut impl Iterator>, + expected: u8, + ) -> IoResult<()> { + match bytes.next() { + Some(Ok(c)) => { + if c == expected { + Ok(()) + } else { + Err(IoError::new(ErrorKind::InvalidInput, DecoderError)) + } + } + Some(Err(e)) => { + match e.kind() { + // Closed connections are ok. + ErrorKind::ConnectionReset | ErrorKind::ConnectionAborted => Ok(()), + _ => Err(IoError::new(ErrorKind::InvalidInput, DecoderError)), + } + } + None => Ok(()), // End of iterator is ok + } + } + + let mut bytes = self.source.by_ref().bytes(); + + expect_or_end(&mut bytes, b'\r')?; + expect_or_end(&mut bytes, b'\n')?; + + Ok(()) + } } impl Read for Decoder @@ -125,8 +158,7 @@ where // if the chunk size is 0, we are at EOF if chunk_size == 0 { - self.read_carriage_return()?; - self.read_line_feed()?; + self.read_end()?; return Ok(0); } @@ -287,4 +319,23 @@ mod test { let mut string = String::new(); assert!(decoded.read_to_string(&mut string).is_err()); } + + #[test] + fn test_decode_end_missing_last_crlf() { + // This has been observed in the wild. + // See https://github.com/algesten/ureq/issues/325 + + // Missing last \r\n + let source = io::Cursor::new( + "3\r\nhel\r\nb\r\nlo world!!!\r\n0\r\n" + .to_string() + .into_bytes(), + ); + let mut decoded = Decoder::new(source); + + let mut string = String::new(); + decoded.read_to_string(&mut string).unwrap(); + + assert_eq!(string, "hello world!!!"); + } }