GET /bytes
Returns binary byte payloads with Content-Length or Content-Type lies. Default claims twice as many bytes as it sends, hanging clients that wait for the full declared body. Use ?mode= to isolate other violations.
mode
Which violation to send. One of: content-length-overshoot (default; claims 2× bytes, client hangs waiting for the rest), content-length-undershoot (claims half, extra bytes bleed into next keep-alive response), wrong-content-type (claims image/png, body is random bytes with no PNG magic header).
n
Number of bytes to send in the actual body (1–4096, default 256). The claimed Content-Length deviates from this in overshoot and undershoot modes.
seed
Integer seed for deterministic byte generation (default 42). Same seed + same n always produces the same body, useful for comparing chaos vs. not. responses.
build a request:
expect: A binary response with one of three header/metadata violations. X-Chaos-Bytes-Actual shows real byte count; X-Chaos-Bytes-Claimed shows the lying Content-Length.
curl -si 'https://chaos.catastrophic.io/bytes?mode=content-length-overshoot&n=256' | grep -E '^(HTTP|content-type|content-length|x-chaos-bytes)'
echo "actual body bytes:"
curl -sS 'https://chaos.catastrophic.io/bytes?mode=content-length-overshoot&n=256' | wc -c
# Default mode (content-length-overshoot) claims more bytes than it
# delivers. Clients buffering to Content-Length hang on the missing
# tail until a read timeout fires.
import urllib.request
resp = urllib.request.urlopen("https://chaos.catastrophic.io/bytes?mode=content-length-overshoot&n=256", timeout=5)
print("Content-Type:", resp.headers.get("Content-Type"))
print("Content-Length header:", resp.headers.get("Content-Length"))
print("X-Chaos-Bytes-Claimed:", resp.headers.get("X-Chaos-Bytes-Claimed"))
print("X-Chaos-Bytes-Actual:", resp.headers.get("X-Chaos-Bytes-Actual"))
print("X-Chaos-Bytes-Mode:", resp.headers.get("X-Chaos-Bytes-Mode"))
body = resp.read()
print("body bytes received:", len(body))
print("framing honest:", len(body) == int(resp.headers.get("Content-Length") or 0))
const res = await fetch("https://chaos.catastrophic.io/bytes?mode=content-length-overshoot&n=256");
console.log("Content-Length header:", res.headers.get("content-length"));
console.log("X-Chaos-Bytes-Mode:", res.headers.get("x-chaos-bytes-mode"));
const buf = await res.arrayBuffer();
console.log("body bytes received:", buf.byteLength);
console.log("framing honest:", buf.byteLength === parseInt(res.headers.get("content-length") || "0"));
package main
import (
"fmt"
"io"
"net/http"
"strconv"
)
func main() {
resp, _ := http.Get("https://chaos.catastrophic.io/bytes?mode=content-length-overshoot&n=256")
defer resp.Body.Close()
fmt.Println("Content-Length header:", resp.Header.Get("Content-Length"))
fmt.Println("X-Chaos-Bytes-Mode:", resp.Header.Get("X-Chaos-Bytes-Mode"))
body, _ := io.ReadAll(resp.Body)
claimed, _ := strconv.Atoi(resp.Header.Get("Content-Length"))
fmt.Printf("body bytes received: %d (claimed %d)\n", len(body), claimed)
fmt.Println("framing honest:", len(body) == claimed)
}
// Cargo.toml: reqwest = { version = "0.12", features = ["blocking"] }
fn main() -> Result<(), Box> {
let resp = reqwest::blocking::get("https://chaos.catastrophic.io/bytes?mode=content-length-overshoot&n=256")?;
let claimed: usize = resp.headers().get("content-length")
.and_then(|v| v.to_str().ok())
.and_then(|s| s.parse().ok()).unwrap_or(0);
println!("Mode: {:?}", resp.headers().get("x-chaos-bytes-mode"));
let body = resp.bytes()?;
println!("body bytes: {} (claimed {})", body.len(), claimed);
println!("framing honest: {}", body.len() == claimed);
Ok(())
}
import java.net.URI;
import java.net.http.*;
public class BytesChaos {
public static void main(String[] args) throws Exception {
var client = HttpClient.newHttpClient();
var req = HttpRequest.newBuilder(URI.create("https://chaos.catastrophic.io/bytes?mode=content-length-overshoot&n=256")).build();
var resp = client.send(req, HttpResponse.BodyHandlers.ofByteArray());
System.out.println("Content-Length: " + resp.headers().firstValue("Content-Length").orElse(""));
System.out.println("X-Chaos-Bytes-Mode: " + resp.headers().firstValue("X-Chaos-Bytes-Mode").orElse(""));
System.out.println("body bytes: " + resp.body().length);
}
}
using var client = new HttpClient();
var resp = await client.GetAsync("https://chaos.catastrophic.io/bytes?mode=content-length-overshoot&n=256");
Console.WriteLine($"Content-Length: {resp.Content.Headers.ContentLength}");
Console.WriteLine($"X-Chaos-Bytes-Mode: {resp.Headers.GetValues("X-Chaos-Bytes-Mode").FirstOrDefault()}");
var body = await resp.Content.ReadAsByteArrayAsync();
Console.WriteLine($"body bytes received: {body.Length}");
require "net/http"
uri = URI("https://chaos.catastrophic.io/bytes?mode=content-length-overshoot&n=256")
Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
res = http.get(uri.request_uri)
puts "Content-Length: #{res['Content-Length']}"
puts "X-Chaos-Bytes-Mode: #{res['X-Chaos-Bytes-Mode']}"
puts "body bytes: #{res.body.bytesize} (claimed #{res['Content-Length']})"
puts "framing honest: #{res.body.bytesize == res['Content-Length'].to_i}"
end
$r = Invoke-WebRequest -Uri 'https://chaos.catastrophic.io/bytes?mode=content-length-overshoot&n=256'
"Content-Length: $($r.Headers['Content-Length'])"
"X-Chaos-Bytes-Mode: $($r.Headers['X-Chaos-Bytes-Mode'])"
"body bytes: $($r.RawContentLength) (claimed $($r.Headers['Content-Length']))"
headers
body