From c5c622f1b8f497fa654814d19abbe369fbd607f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=B7=E7=94=B5=E8=8A=BD=E8=A1=A3?= Date: Fri, 10 Jul 2026 10:48:41 -0400 Subject: [PATCH] fix(tests): read complete requests in the snapshot conflict server --- crates/ely_sync_client/src/client_tests.rs | 36 ++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/crates/ely_sync_client/src/client_tests.rs b/crates/ely_sync_client/src/client_tests.rs index 93be0ea..ffd5f54 100644 --- a/crates/ely_sync_client/src/client_tests.rs +++ b/crates/ely_sync_client/src/client_tests.rs @@ -238,8 +238,7 @@ fn spawn_conflict_server() -> Result<(String, TestServer), Box> { .to_string(); let server = thread::spawn(move || -> std::io::Result<()> { let (mut stream, _) = listener.accept()?; - let mut request = [0_u8; 16 * 1024]; - let _ = stream.read(&mut request)?; + read_complete_request(&mut stream)?; let response = format!( "HTTP/1.1 409 Conflict\r\nContent-Type: application/json\r\nContent-Length: {}\r\nConnection: close\r\n\r\n{body}", body.len() @@ -250,6 +249,39 @@ fn spawn_conflict_server() -> Result<(String, TestServer), Box> { Ok((format!("http://{address}"), server)) } +/// Reads headers plus the full `Content-Length` body. Responding before the +/// client finishes writing resets the connection and makes tests flaky. +fn read_complete_request(stream: &mut std::net::TcpStream) -> std::io::Result> { + let mut request = Vec::new(); + let mut chunk = [0_u8; 1024]; + let header_end = loop { + if let Some(position) = request.windows(4).position(|window| window == b"\r\n\r\n") { + break position + 4; + } + let read = stream.read(&mut chunk)?; + if read == 0 || request.len() + read > 64 * 1024 { + return Err(std::io::Error::other("request headers are incomplete")); + } + request.extend_from_slice(&chunk[..read]); + }; + let headers = String::from_utf8_lossy(&request[..header_end]); + let content_length = headers + .split("\r\n") + .find_map(|line| { + let (name, value) = line.split_once(':')?; + name.eq_ignore_ascii_case("content-length").then(|| value.trim().parse().ok())? + }) + .unwrap_or(0_usize); + while request.len() < header_end + content_length { + let read = stream.read(&mut chunk)?; + if read == 0 { + return Err(std::io::Error::other("request body is incomplete")); + } + request.extend_from_slice(&chunk[..read]); + } + Ok(request) +} + fn spawn_logout_server( status_line: &'static str, body: &str,