From 30ff1476da5b2c00fc27f3cec827cfb4b2aa50a7 Mon Sep 17 00:00:00 2001 From: ldm0 Date: Tue, 29 Sep 2026 03:45:51 +0800 Subject: [PATCH] test(curl): tolerate an already closed TLS fixture socket A client can consume a complete length-delimited or chunked response and close before the fixture calls shutdown(Write). Treat NotConnected at that teardown step as complete; keep all other socket errors and the HTTP framing, invalid-record and certificate assertions unchanged. The original fixture failed 3 of 128 runs at 32-way parallelism, with backtraces pointing to the shutdown call. Validation includes the seven TLS EOF cases, the repeated framing case, cargo fmt --all, strict workspace Clippy and full cargo nextest run --no-fail-fast. Final full suite: 20,599 passed, 16 skipped at 32-way parallelism. The existing ci retry profile was selected, but no test needed a retry. Earlier loaded-run timing failures are retained in the local evidence. --- moli-curl/tests/tls_eof.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/moli-curl/tests/tls_eof.rs b/moli-curl/tests/tls_eof.rs index d13097e5df..74fcc86b9d 100644 --- a/moli-curl/tests/tls_eof.rs +++ b/moli-curl/tests/tls_eof.rs @@ -144,7 +144,12 @@ fn exchange_protocol( } // Send TCP EOF and drain any in-flight HTTP/2 SETTINGS ACK. Closing // a socket with unread data could send RST instead of the intended FIN. - stream.sock.shutdown(Shutdown::Write)?; + // A client can finish a framed response and close before this shutdown. + if let Err(error) = stream.sock.shutdown(Shutdown::Write) + && error.kind() != std::io::ErrorKind::NotConnected + { + return Err(error.into()); + } let mut pending = [0; 4096]; while matches!(stream.sock.read(&mut pending), Ok(n) if n > 0) {} // StreamOwned does not send close_notify on Drop.