affaan-m/ECC · error · anyhow::Error

Missing HTTP path

Error message

Missing HTTP path

What it means

Thrown by read_http_request when the request line contains a method token (e.g. 'GET') but no second whitespace-delimited token for the request path. The parser needs METHOD PATH VERSION; without a path it cannot route the request and bails.

Source

Thrown at ecc2/src/main.rs:4223

            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());
        }
    }

    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 {

View on GitHub (pinned to 01e15490f0)

Solutions

  1. Fix the client to send a complete request line: 'GET / HTTP/1.1\r\n'.
  2. If you do not control the client, catch this parse error at the accept loop and respond with HTTP 400.
  3. Add a unit test that asserts read_http_request rejects 'GET\r\n\r\n' so the behavior is documented.

Example fix

// before
let req = read_http_request(&mut stream)?;

// after
let req = match read_http_request(&mut stream) {
    Ok(r) => r,
    Err(e) => {
        log::warn!("rejecting malformed request: {e:#}");
        let _ = write_http_response(&mut stream, 400, "text/plain", "bad request");
        continue;
    }
};
Defensive patterns

Strategy: validation

Validate before calling

fn request_line_has_path(line: &str) -> bool {
    line.trim().split_whitespace().count() >= 2
}

Try / catch

match read_http_request(&mut stream) {
    Ok(req) => handle(req),
    Err(e) => {
        log::warn!("malformed request line: {e:#}");
        let _ = write_http_response(&mut stream, 400, "text/plain", "bad request");
    }
}

Prevention

When it happens

Trigger: A client sends a request line like 'GET\r\n' (method only), 'POST HTTP/1.1' (method plus protocol but no path), or any line whose whitespace split produces exactly one token. Common with minimal hand-rolled HTTP clients, some monitoring probes, or telnet sessions that type only the method.

Common situations: Telnet into the HTTP port and typing 'GET' then enter; a CLI tool that builds the request line by string concatenation and forgets the path; a health check configured to send only the method.

Related errors


AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13). Data as JSON: /api/errors/2a7137b15c01f1d1. Report an issue: GitHub.