GET /complete-body
/truncateReturns a body of `at` bytes with a Content-Length header that matches the actual bytes sent. Counterpart to the chaos /truncate endpoint, which lies about its body length.
at
Number of bytes to send. Range: 1–1000000. Default: 512.
build a request:
expect: 200 OK with Content-Length matching the actual body byte count. No early close, no premature EOF.
curl -i https://not.catastrophic.io/complete-body?at=512
import urllib.request, http.client
with urllib.request.urlopen("https://not.catastrophic.io/complete-body?at=512") as resp:
promised = resp.headers["Content-Length"]
try:
data = resp.read()
print(f"Got {len(data)} bytes, promised {promised}")
except http.client.IncompleteRead as e:
print(f"Truncated: got {len(e.partial)} of {promised} bytes")
// fetch raises on premature EOF when Content-Length is set.
const url = "https://not.catastrophic.io/complete-body?at=512";
try {
const res = await fetch(url);
const buf = await res.arrayBuffer();
console.log(`Got ${buf.byteLength} bytes, promised ${res.headers.get("content-length")}`);
} catch (e) {
console.error("Premature EOF:", e.message);
}
package main
import (
"fmt"
"io"
"net/http"
)
func main() {
resp, _ := http.Get("https://not.catastrophic.io/complete-body?at=512")
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
fmt.Printf("Read error after %d bytes: %v\n", len(body), err)
return
}
fmt.Printf("Got %d bytes, promised %s\n", len(body), resp.Header.Get("Content-Length"))
}
// Cargo.toml: reqwest = { version = "0.12", features = ["blocking"] }
fn main() -> Result<(), Box> {
let resp = reqwest::blocking::get("https://not.catastrophic.io/complete-body?at=512")?;
let promised = resp.headers().get("content-length").cloned();
match resp.bytes() {
Ok(b) => println!("Got {} bytes, promised {:?}", b.len(), promised),
Err(e) => eprintln!("Read error: {e}"),
}
Ok(())
}
import java.net.URI;
import java.net.http.*;
public class Truncate {
public static void main(String[] args) throws Exception {
var client = HttpClient.newHttpClient();
var req = HttpRequest.newBuilder(URI.create("https://not.catastrophic.io/complete-body?at=512")).build();
try {
var resp = client.send(req, HttpResponse.BodyHandlers.ofByteArray());
System.out.println("Got " + resp.body().length + " bytes, promised "
+ resp.headers().firstValue("Content-Length").orElse(""));
} catch (java.io.IOException e) {
System.err.println("Premature EOF: " + e.getMessage());
}
}
}
using var client = new HttpClient();
try {
var resp = await client.GetAsync("https://not.catastrophic.io/complete-body?at=512");
var bytes = await resp.Content.ReadAsByteArrayAsync();
Console.WriteLine($"Got {bytes.Length} bytes, promised {resp.Content.Headers.ContentLength}");
} catch (HttpRequestException e) {
Console.Error.WriteLine($"Premature EOF: {e.Message}");
}
require "net/http"
uri = URI("https://not.catastrophic.io/complete-body?at=512")
begin
res = Net::HTTP.get_response(uri)
puts "Got #{res.body.bytesize} bytes, promised #{res["Content-Length"]}"
rescue EOFError, IOError => e
puts "Read error: #{e.message}"
end
# The mismatch between Content-Length and actual bytes received
# will surface as a connection or parsing error in most clients.
$r = Invoke-WebRequest -Uri 'https://not.catastrophic.io/complete-body?at=512'
Write-Host "Promised: $($r.Headers['X-Chaos-Promised-Bytes'])"
Write-Host "Received: $($r.RawContentLength)"
headers
body