affaan-m/ECC · error · anyhow::Error
Missing HTTP request line
Error message
Missing HTTP request line
What it means
Thrown by read_http_request after it reads the full header block (terminated by \r\n\r\n) but finds the first line is missing or blank. The parser splits headers on \r\n and requires the very first line to be a non-empty HTTP request line (e.g. 'GET /path HTTP/1.1'). If lines.next() is None or trims to empty, there is no request line to parse method/path from, so the request is rejected as malformed before any routing happens.
Source
Thrown at ecc2/src/main.rs:4215
if read == 0 {
anyhow::bail!("Unexpected EOF while reading HTTP request");
}
buffer.extend_from_slice(&temp[..read]);
if let Some(index) = buffer.windows(4).position(|window| window == b"\r\n\r\n") {
break index + 4;
}
if buffer.len() > 64 * 1024 {
anyhow::bail!("HTTP request headers too large");
}
};
let header_text = String::from_utf8(buffer[..header_end].to_vec())
.context("HTTP request headers were not valid UTF-8")?;
let mut lines = header_text.split("\r\n");
let request_line = lines
.next()
.filter(|line| !line.trim().is_empty())
.ok_or_else(|| anyhow::anyhow!("Missing HTTP request line"))?;
let mut request_parts = request_line.split_whitespace();
let method = request_parts
.next()
.ok_or_else(|| anyhow::anyhow!("Missing HTTP method"))?
.to_string();
let path = request_parts
.next()
.ok_or_else(|| anyhow::anyhow!("Missing HTTP path"))?
.to_string();
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());
}View on GitHub (pinned to 01e15490f0)
Solutions
- If this is a load balancer/health-check probe, point the probe at a path with a real GET request (e.g. 'GET /healthz HTTP/1.1') instead of an empty connect.
- Confirm the client is speaking plain HTTP/1.1 to this port and HTTPS/TLS is not being sent here (move TLS clients to the TLS port or terminate TLS upstream).
- Wrap the accept loop so read_http_request failures log the peer address and close the connection with a 400 rather than propagating the error.
- Reproduce with a netcat session to see the exact bytes the client sends: printf '' | nc host port.
Example fix
// before: bare parse with propagated error
let (method, path, headers, body) = read_http_request(&mut stream)?;
// after: treat malformed request as a 400 and keep serving
match read_http_request(&mut stream) {
Ok((method, path, headers, body)) => handle_request(method, path, headers, body),
Err(e) => {
log::warn!("malformed HTTP request from peer: {e:#}");
let _ = write_http_response(&mut stream, 400, "text/plain", "{\"error\":\"bad request\"}");
}
} Defensive patterns
Strategy: try-catch
Validate before calling
// Before accepting, peek at the first bytes to confirm a request line is present.
fn looks_like_http_request(buf: &[u8]) -> bool {
let text = std::str::from_utf8(buf).unwrap_or("");
text.lines()
.next()
.map(|line| line.trim().split_whitespace().count() >= 3)
.unwrap_or(false)
} Try / catch
// Isolate malformed-request errors at the accept loop and respond 400.
match read_http_request(&mut stream) {
Ok(req) => handle(req),
Err(e) => {
log::warn!("bad request from {peer}: {e:#}");
let _ = write_http_response(&mut stream, 400, "text/plain", "bad request");
}
} Prevention
- Front the HTTP listener with a reverse proxy that normalizes requests.
- Log the peer address on every accept so malformed clients are identifiable.
- Never expose the plaintext HTTP port directly to the internet without a proxy.
When it happens
Trigger: A TCP client connects to the embedded HTTP listener and sends only \r\n\r\n (empty request), or sends a header block whose first line is whitespace-only (e.g. '\r\nGET / HTTP/1.1'). Also produced by port scanners, TCP health probes that open the socket and immediately close, or TLS handshakes sent to a plaintext HTTP port (the TLS bytes do not split into a valid request line).
Common situations: Running the ecc2 HTTP listener on a port also exposed to load balancer health checks that send no data; a curl with no URL/method; telnet/netcat sessions that connect and disconnect; HTTPS client hitting an HTTP-only endpoint.
Related errors
- Missing HTTP method
- Missing HTTP path
- Unexpected EOF while reading HTTP request body
- HTTP ${res.status}
- open failed (HTTP ${res.statusCode})
AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13).
Data as JSON: /api/errors/dc613917d366d1e6.
Report an issue: GitHub.