affaan-m/ECC · error · anyhow::Error
Unexpected EOF while reading HTTP request body
Error message
Unexpected EOF while reading HTTP request body
What it means
Thrown while reading the HTTP request body: the Content-Length header declared N bytes, the server has read fewer than N so far, and stream.read() returned 0 (EOF) before the body was complete. The body loop cannot satisfy Content-Length so it bails rather than return a truncated request.
Source
Thrown at ecc2/src/main.rs:4244
let mut headers = BTreeMap::new();
for line in lines {
if line.is_empty() {
break;
}
if let Some((key, value)) = line.split_once(':') {
headers.insert(key.trim().to_ascii_lowercase(), value.trim().to_string());
}
}
let content_length = headers
.get("content-length")
.and_then(|value| value.parse::<usize>().ok())
.unwrap_or(0);
let mut body = buffer[header_end..].to_vec();
while body.len() < content_length {
let read = stream.read(&mut temp)?;
if read == 0 {
anyhow::bail!("Unexpected EOF while reading HTTP request body");
}
body.extend_from_slice(&temp[..read]);
}
body.truncate(content_length);
Ok((method, path, headers, body))
}
fn write_http_response(
stream: &mut TcpStream,
status: u16,
content_type: &str,
body: &str,
) -> Result<()> {
let status_text = match status {
200 => "OK",
202 => "Accepted",
400 => "Bad Request",View on GitHub (pinned to 01e15490f0)
Solutions
- Confirm the client actually sends the full number of bytes declared in Content-Length (compare with tcpdump or client-side logging).
- If the body legitimately may be absent, have the client omit Content-Length or send Content-Length: 0 for empty bodies.
- Raise the read/idle timeout on any reverse proxy or load balancer in front of the listener.
- If the client uses chunked Transfer-Encoding, note this parser only supports Content-Length; switch the client to Content-Length or add chunked-decoding support.
- Catch the error at the accept loop and respond with HTTP 400 so one bad upload does not kill the server.
Example fix
// caller: do not propagate body-read EOFs as server failures
match read_http_request(&mut stream) {
Ok(req) => handle(req),
Err(e) => {
let msg = format!("{e:#}");
let code = if msg.contains("EOF while reading HTTP request body") { 400 } else { 500 };
let _ = write_http_response(&mut stream, code, "text/plain", "request read error");
}
} Defensive patterns
Strategy: try-catch
Validate before calling
// Client side: never declare a Content-Length you will not fulfill. // Validate before sending: let body = serialize_body(); assert_eq!(body.len(), declared_content_length, "content-length mismatch");
Try / catch
match read_http_request(&mut stream) {
Ok(req) => handle(req),
Err(e) if e.to_string().contains("EOF while reading HTTP request body") => {
let _ = write_http_response(&mut stream, 400, "text/plain", "incomplete body");
}
Err(e) => return Err(e),
} Prevention
- Always send exactly Content-Length body bytes (or use a framing the server supports).
- Raise proxy timeouts for large uploads.
- Note this parser is Content-Length only; do not send chunked Transfer-Encoding.
When it happens
Trigger: A client sends a valid header with 'Content-Length: 100' but closes the connection after only 40 body bytes. Also caused by a reverse proxy that times out mid-upload, a client crash, an MTU/network drop, or a misconfigured proxy that forwards Content-Length but strips or truncates the body. Sending chunked Transfer-Encoding to this parser (which only supports Content-Length) and closing early also surfaces here.
Common situations: Flaky mobile networks dropping large POSTs; an upstream proxy with an aggressive read timeout; a client that sends Content-Length then streams slowly and gets killed; curl interrupted mid-upload (Ctrl-C).
Related errors
- Missing HTTP request line
- Missing HTTP method
- Missing HTTP path
- HTTP ${res.status}
- open failed (HTTP ${res.statusCode})
AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13).
Data as JSON: /api/errors/acf09cb8bd72311b.
Report an issue: GitHub.