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
- Cap Content-Length at a sane maximum (e.g. 64 MiB) and answer 413/400 before computing the end offset.
- Keep the checked arithmetic — never replace request_end with plain addition.
- Close the connection on absurd lengths; a client sending usize::MAX is hostile or broken.
- 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
- Cap accepted Content-Length at a realistic maximum and enforce it before any allocation.
- Never replace checked arithmetic with plain + when a client controls any operand.
- Close connections that send near-usize::MAX lengths rather than just erroring.
- Remember 32-bit servers overflow at 4 GiB, not usize::MAX.
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
- Invalid HTTP request
- Empty request
- Invalid request line
- HTTP request failed: ${e instanceof Error ? e.message : Stri
- HTTP error! status: ${response.status}
AI-assisted analysis of tursodatabase/turso@bad083fafb (2026-08-16).
Data as JSON: /api/errors/0a693c631eeb9044.
Report an issue: GitHub.