online / endpoints 59 / categories 14 / rate 60/min/ip /

GET /compression

GET /compression

Returns responses where Content-Encoding lies about the body's actual compression state, or where the body is gzip-compressed but the header doesn't say so. Tests how clients and proxies handle disagreement between encoding metadata and bytes.

mode gzip-header-plain-body (default; Content-Encoding: gzip but body is plain text), gzip-body-no-header (body is actually gzipped but no Content-Encoding header — looks like binary garbage), wrong-encoding-name (Content-Encoding: superzip — unknown), chained-claim (Content-Encoding: gzip, br — multiple encodings claimed, body is plain text).
build a request:

expect: 200 OK. gzip-header-plain-body and chained-claim send plain JSON with a lying Content-Encoding — most clients will attempt to gunzip and fail. gzip-body-no-header sends real gzip bytes without the header, so the body looks like binary garbage. wrong-encoding-name uses an unknown encoding name.

bash
# --compressed tells curl to honour Content-Encoding; will surface the lie
curl -i --compressed 'https://chaos.catastrophic.io/compression?mode=gzip-header-plain-body'
import urllib.request
resp = urllib.request.urlopen("https://chaos.catastrophic.io/compression?mode=gzip-header-plain-body")
print(resp.status, "Content-Encoding:", resp.headers.get("Content-Encoding"))
raw = resp.read()
print(f"Got {len(raw)} bytes")
print(raw[:200])
// Browsers auto-decompress when Content-Encoding is recognised. fetch will
// throw on a malformed gzip stream when the header claims gzip.
try {
    const res = await fetch("https://chaos.catastrophic.io/compression?mode=gzip-header-plain-body");
    console.log("status:", res.status, "Content-Encoding:", res.headers.get("content-encoding"));
    console.log("body:", await res.text());
} catch (e) {
    console.error("Decode error:", e.message);
}
package main

import (
    "fmt"
    "io"
    "net/http"
)

func main() {
    // Don't let the transport auto-decompress so we see exactly what's sent.
    tr := &http.Transport{DisableCompression: true}
    resp, _ := (&http.Client{Transport: tr}).Get("https://chaos.catastrophic.io/compression?mode=gzip-header-plain-body")
    defer resp.Body.Close()
    raw, _ := io.ReadAll(resp.Body)
    fmt.Println("Content-Encoding:", resp.Header.Get("Content-Encoding"))
    fmt.Printf("Got %d bytes\n", len(raw))
    fmt.Println(string(raw[:min(200, len(raw))]))
}

func min(a, b int) int { if a < b { return a }; return b }
// Cargo.toml: reqwest = { version = "0.12", features = ["blocking"] }
// (reqwest does NOT auto-decompress unless the "gzip" feature is enabled)
fn main() -> Result<(), Box> {
    let resp = reqwest::blocking::get("https://chaos.catastrophic.io/compression?mode=gzip-header-plain-body")?;
    println!("Content-Encoding: {:?}", resp.headers().get("content-encoding"));
    let bytes = resp.bytes()?;
    println!("Got {} bytes", bytes.len());
    println!("{:?}", &bytes[..200.min(bytes.len())]);
    Ok(())
}
// Java 11+ HttpClient. ofString assumes plain text — wrong encoding will
// surface as garbled output.
import java.net.URI;
import java.net.http.*;

public class CompressionChaos {
    public static void main(String[] args) throws Exception {
        var client = HttpClient.newHttpClient();
        var req = HttpRequest.newBuilder(URI.create("https://chaos.catastrophic.io/compression?mode=gzip-header-plain-body")).build();
        var resp = client.send(req, HttpResponse.BodyHandlers.ofByteArray());
        System.out.println("Content-Encoding: " +
            resp.headers().firstValue("Content-Encoding").orElse(""));
        System.out.println("Got " + resp.body().length + " bytes");
        System.out.println(new String(resp.body(),
            0, Math.min(200, resp.body().length)));
    }
}
// Disable auto-decompression so we see the raw bytes.
using var handler = new HttpClientHandler { AutomaticDecompression = System.Net.DecompressionMethods.None };
using var client = new HttpClient(handler);
var resp = await client.GetAsync("https://chaos.catastrophic.io/compression?mode=gzip-header-plain-body");
Console.WriteLine($"Content-Encoding: {resp.Content.Headers.ContentEncoding}");
var bytes = await resp.Content.ReadAsByteArrayAsync();
Console.WriteLine($"Got {bytes.Length} bytes");
Console.WriteLine(System.Text.Encoding.UTF8.GetString(bytes, 0, Math.Min(200, bytes.Length)));
require "net/http"
uri = URI("https://chaos.catastrophic.io/compression?mode=gzip-header-plain-body")
Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
    req = Net::HTTP::Get.new(uri)
    req["Accept-Encoding"] = "identity"  # ask for no decompression
    res = http.request(req)
    puts "Content-Encoding: #{res['Content-Encoding']}"
    puts "Got #{res.body.bytesize} bytes"
    puts res.body[0, 200]
end
# Invoke-WebRequest auto-decompresses gzip; the chaos surfaces as a decode error.
try {
    $r = Invoke-WebRequest -Uri 'https://chaos.catastrophic.io/compression?mode=gzip-header-plain-body'
    "Content-Encoding: $($r.Headers['Content-Encoding'])"
    "Content length: $($r.RawContentLength)"
    $r.Content.Substring(0, [Math]::Min(200, $r.Content.Length))
} catch {
    "Decode error: $($_.Exception.Message)"
}