From a131111f9c3189bab36fed9f46872c88dc0d601e Mon Sep 17 00:00:00 2001 From: Sean McArthur Date: Mon, 16 Dec 2024 10:36:41 -0500 Subject: [PATCH] fix(http1): fix intermitent panic parsing partial headers (#3812) Closes #3811 --- src/proto/h1/io.rs | 4 ++++ tests/client.rs | 57 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/src/proto/h1/io.rs b/src/proto/h1/io.rs index 4f8b58eced..950bfee098 100644 --- a/src/proto/h1/io.rs +++ b/src/proto/h1/io.rs @@ -205,7 +205,11 @@ where return Poll::Ready(Err(crate::Error::new_too_large())); } if curr_len > 0 { + trace!("partial headers; {} bytes so far", curr_len); self.partial_len = Some(curr_len); + } else { + // 1xx gobled some bytes + self.partial_len = None; } } } diff --git a/tests/client.rs b/tests/client.rs index 6063322153..6808a6855f 100644 --- a/tests/client.rs +++ b/tests/client.rs @@ -2041,6 +2041,63 @@ mod conn { assert_eq!(vec, b"bar=foo"); } + #[tokio::test] + async fn client_100_then_http09() { + let (server, addr) = setup_std_test_server(); + + thread::spawn(move || { + let mut sock = server.accept().unwrap().0; + sock.set_read_timeout(Some(Duration::from_secs(5))).unwrap(); + sock.set_write_timeout(Some(Duration::from_secs(5))) + .unwrap(); + let mut buf = [0; 4096]; + sock.read(&mut buf).expect("read 1"); + sock.write_all( + b"\ + HTTP/1.1 100 Continue\r\n\ + Content-Type: text/plain\r\n\ + Server: BaseHTTP/0.6 Python/3.12.5\r\n\ + Date: Mon, 16 Dec 2024 03:08:27 GMT\r\n\ + ", + ) + .unwrap(); + // That it's separate writes is important to this test + thread::sleep(Duration::from_millis(50)); + sock.write_all( + b"\ + \r\n\ + ", + ) + .expect("write 2"); + thread::sleep(Duration::from_millis(50)); + sock.write_all( + b"\ + This is a sample text/plain document, without final headers.\ + \n\n\ + ", + ) + .expect("write 3"); + }); + + let tcp = tcp_connect(&addr).await.unwrap(); + + let (mut client, conn) = conn::http1::Builder::new() + .http09_responses(true) + .handshake(tcp) + .await + .unwrap(); + + tokio::spawn(async move { + let _ = conn.await; + }); + + let req = Request::builder() + .uri("/a") + .body(Empty::::new()) + .unwrap(); + let _res = client.send_request(req).await.expect("send_request"); + } + #[tokio::test] async fn test_try_send_request() { use std::future::Future;