{"record":{"id":"acf09cb8bd72311b","repo":"affaan-m/ECC","slug":"unexpected-eof-while-reading-http-request-body","errorCode":null,"errorMessage":"Unexpected EOF while reading HTTP request body","messagePattern":"Unexpected EOF while reading HTTP request body","errorType":"http","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"ecc2/src/main.rs","lineNumber":4244,"sourceCode":"    let mut headers = BTreeMap::new();\n    for line in lines {\n        if line.is_empty() {\n            break;\n        }\n        if let Some((key, value)) = line.split_once(':') {\n            headers.insert(key.trim().to_ascii_lowercase(), value.trim().to_string());\n        }\n    }\n\n    let content_length = headers\n        .get(\"content-length\")\n        .and_then(|value| value.parse::<usize>().ok())\n        .unwrap_or(0);\n    let mut body = buffer[header_end..].to_vec();\n    while body.len() < content_length {\n        let read = stream.read(&mut temp)?;\n        if read == 0 {\n            anyhow::bail!(\"Unexpected EOF while reading HTTP request body\");\n        }\n        body.extend_from_slice(&temp[..read]);\n    }\n    body.truncate(content_length);\n\n    Ok((method, path, headers, body))\n}\n\nfn write_http_response(\n    stream: &mut TcpStream,\n    status: u16,\n    content_type: &str,\n    body: &str,\n) -> Result<()> {\n    let status_text = match status {\n        200 => \"OK\",\n        202 => \"Accepted\",\n        400 => \"Bad Request\",","sourceCodeStart":4226,"sourceCodeEnd":4262,"githubUrl":"https://github.com/affaan-m/ECC/blob/01e15490f04e29cfefe3896951f43db46994d8ee/ecc2/src/main.rs#L4226-L4262","documentation":"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.","triggerScenarios":"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.","commonSituations":"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).","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."],"exampleFix":"// caller: do not propagate body-read EOFs as server failures\nmatch read_http_request(&mut stream) {\n    Ok(req) => handle(req),\n    Err(e) => {\n        let msg = format!(\"{e:#}\");\n        let code = if msg.contains(\"EOF while reading HTTP request body\") { 400 } else { 500 };\n        let _ = write_http_response(&mut stream, code, \"text/plain\", \"request read error\");\n    }\n}","handlingStrategy":"try-catch","validationCode":"// Client side: never declare a Content-Length you will not fulfill.\n// Validate before sending:\nlet body = serialize_body();\nassert_eq!(body.len(), declared_content_length, \"content-length mismatch\");","typeGuard":null,"tryCatchPattern":"match read_http_request(&mut stream) {\n    Ok(req) => handle(req),\n    Err(e) if e.to_string().contains(\"EOF while reading HTTP request body\") => {\n        let _ = write_http_response(&mut stream, 400, \"text/plain\", \"incomplete body\");\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["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."],"tags":["http","network","tcp-server","body-read","content-length"],"backgroundTag":null,"analyzedSha":"01e15490f04e29cfefe3896951f43db46994d8ee","analyzedAt":"2026-08-13T00:31:08.655Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}