tursodatabase/turso · error · anyhow::Error

HTTP request length overflows: {content_length}

Error message

HTTP request length overflows: {content_length}

What it means

request_end computes header_end + 4 + content_length with checked arithmetic and returns this error when the sum overflows usize. Content-Length is fully client-controlled (the code comment says exactly this), so a hostile or broken client can send a value near usize::MAX and the body-end computation must not wrap. On 32-bit servers any Content-Length >= ~4 GiB also overflows.

Source

Thrown at cli/sync_server.rs:1150

    let mut page = vec![0u8; PAGE_SIZE];
    if conn.try_wal_watermark_read_page(1, &mut page, Some(max_frame))? {
        Ok(db_size_from_page(&page) as u64)
    } else {
        Ok(0)
    }
}

fn db_size_from_page(page: &[u8]) -> u32 {
    u32::from_be_bytes(page[28..32].try_into().unwrap())
}

/// A client controls Content-Length, so the end of the body has to be
/// computed without trusting it to fit.
fn request_end(header_end: usize, content_length: usize) -> Result<usize> {
    (header_end + 4)
        .checked_add(content_length)
        .ok_or_else(|| anyhow!("HTTP request length overflows: {content_length}"))
}

fn find_header_end(data: &[u8], start: usize) -> Option<usize> {
    (start..data.len().saturating_sub(3)).find(|&i| &data[i..i + 4] == b"\r\n\r\n")
}

fn parse_content_length(headers: &str) -> Option<usize> {
    for line in headers.lines() {
        let lower = line.to_lowercase();
        if lower.starts_with("content-length:") {
            let value = line.split(':').nth(1)?.trim();
            return value.parse().ok();
        }
    }
    None
}

fn parse_http_request(data: &[u8]) -> Result<(String, String, Vec<u8>)> {

View on GitHub (pinned to bad083fafb)

Solutions

  1. Cap Content-Length at a sane maximum (e.g. 64 MiB) and answer 413/400 before computing the end offset.
  2. Keep the checked arithmetic — never replace request_end with plain addition.
  3. Close the connection on absurd lengths; a client sending usize::MAX is hostile or broken.
  4. On 32-bit builds, remember values >= 4 GiB overflow usize even when they look plausible.

Example fix

// before
let total_expected = request_end(header_end, content_length)?;

// after
const MAX_BODY_BYTES: usize = 64 * 1024 * 1024;
anyhow::ensure!(
    content_length <= MAX_BODY_BYTES,
    "HTTP body of {content_length} bytes exceeds cap"
);
let total_expected = request_end(header_end, content_length)?;
Defensive patterns

Strategy: validation

Validate before calling

const MAX_BODY_BYTES: usize = 64 * 1024 * 1024;
fn content_length_acceptable(header_end: usize, content_length: usize) -> bool {
    content_length <= MAX_BODY_BYTES
        && (header_end + 4)
            .checked_add(content_length)
            .is_some()
}
// before computing the read target:
anyhow::ensure!(
    content_length_acceptable(header_end, content_length),
    "Content-Length {content_length} rejected"
);

Type guard

fn content_length_fits(header_end: usize, content_length: usize) -> bool {
    (header_end + 4)
        .checked_add(content_length)
        .is_some()
}

Try / catch

match request_end(header_end, content_length) {
    Ok(total_expected) => { /* read until total_expected bytes */ }
    Err(err) if err.to_string().contains("HTTP request length overflows") => {
        // hostile or broken client: answer 400/413 and close the connection
    }
    Err(err) => return Err(err),
}

Prevention

When it happens

Trigger: handle_connection calls request_end(header_end, content_length) after a client sends 'Content-Length: 18446744073709551615' or any value greater than usize::MAX - header_end - 4; on 32-bit builds, any legitimate-looking value >= 4 GiB triggers it.

Common situations: Port scanners and DoS tools probing the sync port with maximal header values; HTTP clients with integer-handling bugs that parse u64 and pass it through; 32-bit deployments receiving large uploads.

Related errors


AI-assisted analysis of tursodatabase/turso@bad083fafb (2026-08-16). Data as JSON: /api/errors/0a693c631eeb9044. Report an issue: GitHub.