fix(http1): ignore chunked trailers (#2357)
Previously, hyper returned an "Invalid chunk end CR" error on chunked responses with trailers, as described in RFC 7230 Section 4.1.2. This commit adds code to ignore the trailers. Closes #2171
This commit is contained in:
@@ -55,6 +55,8 @@ enum ChunkedState {
|
||||
Body,
|
||||
BodyCr,
|
||||
BodyLf,
|
||||
Trailer,
|
||||
TrailerLf,
|
||||
EndCr,
|
||||
EndLf,
|
||||
End,
|
||||
@@ -196,6 +198,8 @@ impl ChunkedState {
|
||||
Body => ChunkedState::read_body(cx, body, size, buf),
|
||||
BodyCr => ChunkedState::read_body_cr(cx, body),
|
||||
BodyLf => ChunkedState::read_body_lf(cx, body),
|
||||
Trailer => ChunkedState::read_trailer(cx, body),
|
||||
TrailerLf => ChunkedState::read_trailer_lf(cx, body),
|
||||
EndCr => ChunkedState::read_end_cr(cx, body),
|
||||
EndLf => ChunkedState::read_end_lf(cx, body),
|
||||
End => Poll::Ready(Ok(ChunkedState::End)),
|
||||
@@ -340,16 +344,36 @@ impl ChunkedState {
|
||||
}
|
||||
}
|
||||
|
||||
fn read_trailer<R: MemRead>(
|
||||
cx: &mut task::Context<'_>,
|
||||
rdr: &mut R,
|
||||
) -> Poll<Result<ChunkedState, io::Error>> {
|
||||
trace!("read_trailer");
|
||||
match byte!(rdr, cx) {
|
||||
b'\r' => Poll::Ready(Ok(ChunkedState::TrailerLf)),
|
||||
_ => Poll::Ready(Ok(ChunkedState::Trailer)),
|
||||
}
|
||||
}
|
||||
fn read_trailer_lf<R: MemRead>(
|
||||
cx: &mut task::Context<'_>,
|
||||
rdr: &mut R,
|
||||
) -> Poll<Result<ChunkedState, io::Error>> {
|
||||
match byte!(rdr, cx) {
|
||||
b'\n' => Poll::Ready(Ok(ChunkedState::EndCr)),
|
||||
_ => Poll::Ready(Err(io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
"Invalid trailer end LF",
|
||||
))),
|
||||
}
|
||||
}
|
||||
|
||||
fn read_end_cr<R: MemRead>(
|
||||
cx: &mut task::Context<'_>,
|
||||
rdr: &mut R,
|
||||
) -> Poll<Result<ChunkedState, io::Error>> {
|
||||
match byte!(rdr, cx) {
|
||||
b'\r' => Poll::Ready(Ok(ChunkedState::EndLf)),
|
||||
_ => Poll::Ready(Err(io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
"Invalid chunk end CR",
|
||||
))),
|
||||
_ => Poll::Ready(Ok(ChunkedState::Trailer)),
|
||||
}
|
||||
}
|
||||
fn read_end_lf<R: MemRead>(
|
||||
@@ -538,6 +562,15 @@ mod tests {
|
||||
assert_eq!("1234567890abcdef", &result);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_read_chunked_trailer_with_missing_lf() {
|
||||
let mut mock_buf = &b"10\r\n1234567890abcdef\r\n0\r\nbad\r\r\n"[..];
|
||||
let mut decoder = Decoder::chunked();
|
||||
decoder.decode_fut(&mut mock_buf).await.expect("decode");
|
||||
let e = decoder.decode_fut(&mut mock_buf).await.unwrap_err();
|
||||
assert_eq!(e.kind(), io::ErrorKind::InvalidInput);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_read_chunked_after_eof() {
|
||||
let mut mock_buf = &b"10\r\n1234567890abcdef\r\n0\r\n\r\n"[..];
|
||||
|
||||
Reference in New Issue
Block a user