From ea3c2ff19e7b4e103916b1606ccdde71cd714e6f Mon Sep 17 00:00:00 2001 From: Optio Agent Date: Sat, 28 Mar 2026 03:00:53 +0000 Subject: [PATCH] fix(http): don't reuse connection when --fail skips body (test 1328) When --fail triggers on a 4xx response, the body read is skipped but the connection was being returned to the pool with unread body data still on the socket. When URL globbing reuses that pooled connection for the next URL, the HTTP parser reads stale body data instead of fresh response headers, causing a hang. Fix: mark the connection as non-reusable when fail_skip is true and the response has body framing (Content-Length or chunked TE). Co-Authored-By: Claude Opus 4.6 (1M context) --- crates/liburlx/src/protocol/http/h1.rs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/crates/liburlx/src/protocol/http/h1.rs b/crates/liburlx/src/protocol/http/h1.rs index 8d3e580..8496865 100644 --- a/crates/liburlx/src/protocol/http/h1.rs +++ b/crates/liburlx/src/protocol/http/h1.rs @@ -823,7 +823,20 @@ where // Determine if connection can be reused let server_wants_close = ph.headers.get("connection").is_some_and(|v| v.eq_ignore_ascii_case("close")); - let can_reuse = keep_alive && !use_http10 && !server_wants_close && !body_read_to_eof; + // When --fail skips the body (fail_skip), the socket still has unread body data. + // Don't reuse the connection if the response has body framing (Content-Length or + // chunked Transfer-Encoding), because the next request would read stale data + // (curl compat: test 1328 — --fail with URL globbing). + let has_body_framing = ph.headers.contains_key("content-length") + || ph + .headers + .get("transfer-encoding") + .is_some_and(|te| te_contains_chunked(te)); + let can_reuse = keep_alive + && !use_http10 + && !server_wants_close + && !body_read_to_eof + && !(fail_skip && has_body_framing); let mut resp = Response::new(ph.status, ph.headers, response_body, url.to_string()); resp.set_header_original_names(ph.original_names);