From 0e70a31a6db5b7502654be778efbfd56fe6928cc Mon Sep 17 00:00:00 2001 From: ihciah Date: Mon, 10 Jul 2023 07:37:28 +0000 Subject: [PATCH] fix: set error to Payload before dispatcher disconnect --- actix-http/src/h1/dispatcher.rs | 1 + actix-http/tests/test_server.rs | 53 +++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/actix-http/src/h1/dispatcher.rs b/actix-http/src/h1/dispatcher.rs index 27070780748..6d332010a66 100644 --- a/actix-http/src/h1/dispatcher.rs +++ b/actix-http/src/h1/dispatcher.rs @@ -1115,6 +1115,7 @@ where let inner = inner.as_mut().project(); inner.flags.insert(Flags::READ_DISCONNECT); if let Some(mut payload) = inner.payload.take() { + payload.set_error(io::Error::from(io::ErrorKind::UnexpectedEof).into()); payload.feed_eof(); } }; diff --git a/actix-http/tests/test_server.rs b/actix-http/tests/test_server.rs index f55b1b36c4b..17cbd7775e6 100644 --- a/actix-http/tests/test_server.rs +++ b/actix-http/tests/test_server.rs @@ -17,6 +17,7 @@ use bytes::Bytes; use derive_more::{Display, Error}; use futures_util::{stream::once, FutureExt as _, StreamExt as _}; use regex::Regex; +use tokio::io::{AsyncReadExt, AsyncWriteExt}; #[actix_rt::test] async fn h1_basic() { @@ -439,6 +440,58 @@ async fn content_length() { srv.stop().await; } +#[actix_rt::test] +async fn content_length_truncated() { + let mut srv = test_server(|| { + HttpService::build() + .h1(|mut req: Request| async move { + let expect_length: usize = req.uri().path()[1..].parse().unwrap(); + let mut payload = req.take_payload(); + + let mut length = 0; + let mut seen_error = false; + while let Some(chunk) = payload.next().await { + match chunk { + Ok(b) => length += b.len(), + Err(_) => { + seen_error = true; + break; + } + } + } + if seen_error { + return Result::<_, Infallible>::Ok(Response::bad_request()); + } + + assert_eq!(length, expect_length, "length must match when no error"); + Result::<_, Infallible>::Ok(Response::ok()) + }) + .tcp() + }) + .await; + + let addr = srv.addr(); + let mut buf = [0; 12]; + + let mut conn = TcpStream::connect(&addr).await.unwrap(); + conn.write_all(b"POST /10000 HTTP/1.1\r\nContent-Length: 10000\r\n\r\ndata_truncated") + .await + .unwrap(); + conn.shutdown().await.unwrap(); + conn.read_exact(&mut buf).await.unwrap(); + assert_eq!(&buf, b"HTTP/1.1 400"); + + let mut conn = TcpStream::connect(&addr).await.unwrap(); + conn.write_all(b"POST /4 HTTP/1.1\r\nContent-Length: 4\r\n\r\ndata") + .await + .unwrap(); + conn.shutdown().await.unwrap(); + conn.read_exact(&mut buf).await.unwrap(); + assert_eq!(&buf, b"HTTP/1.1 200"); + + srv.stop().await; +} + #[actix_rt::test] async fn h1_headers() { let data = STR.repeat(10);