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

HTTP request headers too large

Error message

HTTP request headers too large

What it means

Raised by `read_http_request` when the in-memory header buffer exceeds 64 KiB before the `\r\n\r\n` terminator is found. This is a deliberate bound to prevent unbounded memory growth from a malicious or buggy client that streams headers forever without terminating the request. It is a protocol-level guard, not a configuration limit.

Source

Thrown at ecc2/src/main.rs:4205

    }
}

fn read_http_request(
    stream: &mut TcpStream,
) -> Result<(String, String, BTreeMap<String, String>, Vec<u8>)> {
    let mut buffer = Vec::new();
    let mut temp = [0_u8; 1024];
    let header_end = loop {
        let read = stream.read(&mut temp)?;
        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"))?

View on GitHub (pinned to 01e15490f0)

Solutions

  1. Ensure clients send well-formed HTTP requests with headers under 64 KiB total.
  2. If legitimately large headers are expected, raise the cap in `read_http_request` (edit the `64 * 1024` literal) and document the new limit.
  3. Place a reverse proxy (nginx, caddy) in front that enforces its own header limits and rejects abuse before it reaches ECC.

Example fix

// before: hard cap at 64 KiB
if buffer.len() > 64 * 1024 {
    anyhow::bail!("HTTP request headers too large");
}

// after: configurable cap
const MAX_HEADER_BYTES: usize = 128 * 1024; // 128 KiB
if buffer.len() > MAX_HEADER_BYTES {
    anyhow::bail!("HTTP request headers too large");
}
Defensive patterns

Strategy: validation

Validate before calling

// Bound input before it reaches the parser
const MAX_HEADER_BYTES: usize = 64 * 1024;
if buffer.len() > MAX_HEADER_BYTES {
    stream.write_all(b"HTTP/1.1 431 Request Header Fields Too Large\r\n\r\n")?;
    return Ok(());
}

Try / catch

// Map the bail into a 431 response instead of an error
match read_http_request(&mut stream) {
    Ok(req) => handle(req),
    Err(e) if e.to_string().contains("headers too large") => {
        let _ = stream.write_all(b"HTTP/1.1 431 Request Header Fields Too Large\r\nConnection: close\r\n\r\n");
        return;
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: A client sends an extremely long header block (huge cookies, very long authorization tokens, or synthetic padding) without the terminating blank line. A malformed client that never sends `\r\n\r\n`. An attacker attempting a header-based resource exhaustion. A proxy forwarding an oversized accumulated header set.

Common situations: Security scanners / fuzzers. Misbehaving proxies that concatenate many forwarded headers. Legitimate clients with exceptionally large cookies or tokens that exceed 64 KiB (rare). Buggy custom integrations that omit the request terminator.

Related errors


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