From f1d48390630527eb44094c6ba5e37906e52f88c2 Mon Sep 17 00:00:00 2001 From: zfaustk <4340287+zfaustk@users.noreply.github.com> Date: Mon, 31 Aug 2026 05:08:59 +0800 Subject: [PATCH] fix(http1): close client after completed response Close a client connection when a complete response arrives while the request body is still pending. This avoids parking the connection in a non-reusable terminal state. Closes #4176 --- src/proto/h1/conn.rs | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/proto/h1/conn.rs b/src/proto/h1/conn.rs index 19c1283df7..752e081659 100644 --- a/src/proto/h1/conn.rs +++ b/src/proto/h1/conn.rs @@ -1096,6 +1096,9 @@ impl State { (&Reading::Closed, &Writing::KeepAlive) | (&Reading::KeepAlive, &Writing::Closed) => { self.close(); } + (&Reading::KeepAlive, &Writing::Body(_)) if T::is_client() => { + self.close(); + } _ => (), } } @@ -1266,6 +1269,37 @@ mod tests { ); } + #[cfg(feature = "client")] + #[test] + fn client_closes_after_response_while_request_body_is_pending() { + let io = Compat(tokio_test::io::Builder::new().build()); + let mut conn = Conn::<_, Bytes, crate::proto::h1::ClientTransaction>::new(io); + conn.state.reading = Reading::KeepAlive; + conn.state.writing = Writing::Body(Encoder::chunked()); + + conn.state + .try_keep_alive::(); + + assert!(conn.state.is_read_closed()); + assert!(conn.state.is_write_closed()); + } + + #[cfg(feature = "server")] + #[test] + fn server_keeps_streaming_body_after_request_is_read() { + let io = Compat(tokio_test::io::Builder::new().build()); + let mut conn = Conn::<_, Bytes, crate::proto::h1::ServerTransaction>::new(io); + conn.state.reading = Reading::KeepAlive; + conn.state.writing = Writing::Body(Encoder::chunked()); + + conn.state + .try_keep_alive::(); + + assert!(!conn.state.is_read_closed()); + assert!(!conn.state.is_write_closed()); + assert!(matches!(conn.state.writing, Writing::Body(_))); + } + use super::*; use crate::common::io::Compat; #[cfg(feature = "client")]