{
  "flavors": {
    "ok": "The control: gzip if the set the edge reports for you lists gzip, identity otherwise (that set reads no header, \"*\" and an empty value as nothing); Vary: Accept-Encoding; a correct Content-Length as sent; and the plaintext's length and SHA-256 in x-badhttp-plain-bytes / x-badhttp-plain-sha256 so you can prove what you decoded. q-values are already dropped from that set, so gzip;q=0 still gets gzip and identity;q=0 cannot produce a 406 from here; x-badhttp-negotiated-from shows the set.",
    "br": "Brotli (RFC 7932), pre-computed for the default 4096-byte document because this runtime has no brotli encoder; ?length= is accepted only at 4096.",
    "zstd": "Zstandard (RFC 8878), the newest coding browsers advertise and one several SDKs still cannot decode. Pre-computed for the default 4096-byte document; ?length= is accepted only at 4096.",
    "deflate": "Content-Encoding: deflate done right: a zlib stream (RFC 1950 around RFC 1951), which is what the coding name means. No client probed on 2026-09-01 received it through this host — Cloudflare's edge, the CDN in front of this Worker, decoded it for every one of them, even one that asked for it (GET /compress → edge_transcoding has the per-flavor list) — and the flavor exists so that observation stays reproducible.",
    "not-compressed": "Content-Encoding: gzip on a body that is not compressed — plain text, the case most often reported in the wild (a proxy or framework that sets the header without compressing). A decoder that trusts the header fails on the first byte; some clients fall back to the raw body, some do not.",
    "undeclared": "The mirror image: the body IS gzip (starts 1f 8b) but there is no Content-Encoding header at all — text/plain says it is text. A client that trusts the headers hands you binary; a few sniff the magic bytes.",
    "truncated": "A valid gzip stream cut at about 60% (x-badhttp-wire-bytes-of says exactly) — inside the DEFLATE data, before the CRC-32 and length trailer. Content-Length matches the bytes actually sent, so the transport looks complete; only the decoder can tell. Does your client report the error, or return the partial plaintext as if it were everything?",
    "corrupt": "A gzip stream with up to four bytes flipped in the middle of the DEFLATE data (x-badhttp-flipped-bytes says how many and where; fewer only for streams under 25 bytes). A decoder either rejects the stream outright, or inflates it — often to the full length, correct up to the damage and garbage after — and then fails the CRC; a decoder that does not check the CRC (see bad-crc) returns that garbage with no error at all. Either way it may have handed you some of the garbage first.",
    "bad-crc": "A gzip stream whose DEFLATE data is intact but whose CRC-32 trailer is wrong (the ISIZE is right). Every byte of plaintext is recoverable; the question is whether your client checks the checksum, and what it does with the data it already delivered when the check fails at the very end.",
    "trailing-garbage": "A complete, valid gzip member followed by 49 bytes of junk, all counted in Content-Length. RFC 1952 says a stream is a series of members; the junk is not one. Some decoders ignore it, some fail after having produced the whole plaintext, some warn.",
    "multi-member": "Two gzip members back to back, each holding half the document — valid per RFC 1952 §2.2, and what some servers and concatenating CDNs really emit. Some HTTP clients decode only the first member and return half the document with no error (httpx and Ruby's Net::HTTP among them, 2026-09-01).",
    "double": "Content-Encoding: gzip, gzip — the document gzipped twice, with both codings declared in order, exactly as RFC 9110 §8.4 allows. Clients that apply only the first coding hand you a gzip stream and call it text; clients that compare the header to \"gzip\" exactly do not decode at all.",
    "double-hidden": "The document gzipped twice but Content-Encoding says gzip once. Decoding \"succeeds\" and yields 1f 8b…: a gzip stream where your text should be. The bug proxies that compress already-compressed responses produce.",
    "deflate-raw": "Content-Encoding: deflate with a raw RFC 1951 stream — no zlib header, no Adler-32 — the historic mistake that made \"deflate\" untrustworthy. Some clients detect the missing wrapper and recover; some fail on byte one; some do not decode deflate at all.",
    "unknown-coding": "Content-Encoding: badhttp, a coding that does not exist, on a plain-text body. There is no rule for a client here: pass the bytes through, or refuse. Which does yours do, and does it tell you?",
    "uppercase": "Content-Encoding: GZIP. Coding names are case-insensitive (RFC 9110 §8.4.1); the body is ordinary gzip. Clients that compare the header case-sensitively leave it compressed.",
    "x-gzip": "Content-Encoding: x-gzip, the legacy alias that RFC 9110 §8.4.1.3 says a recipient SHOULD treat as gzip. The body is ordinary gzip.",
    "empty": "Content-Encoding: gzip on a zero-byte body (Content-Length: 0) — what a proxy that strips a body but not its headers produces; with ?code=502 it is the stripped error page. An empty string is not a gzip stream; some decoders say so, some return nothing quietly. ?length= is accepted only at 0.",
    "wrong-length": "A correct gzip body whose Content-Length is the plaintext's length, not the wire's — the header a proxy leaves behind when it compresses without recounting. The declared bytes never arrive: the connection closes early (HTTP/1.1) or the stream is reset (HTTP/2), after the decoder has already seen a complete gzip stream. Which error do you get, if any? ?length= is at least 128 here, so the gzip member is really shorter than the length it claims.",
    "gzip-file": "The .gz download trap: a file that already IS gzip, served as a download (Content-Type: application/gzip, Content-Disposition: attachment; filename=\"badhttp-compress.txt.gz\") — and, wrongly, with Content-Encoding: gzip as well, the way misconfigured static servers and object stores label .tar.gz files. A client that applies transport decoding saves the plaintext under a .gz name: silent corruption of the download. x-badhttp-wire-sha256 is the hash of the bytes that should land in the file; x-badhttp-plain-sha256 the hash of what lands if the client decoded.",
    "bomb": "A decompression bomb, declared: one gzip member that inflates to ?size= MiB (default 8, max 32) from about 3 KB per MiB on the wire (x-badhttp-wire-bytes says exactly) — the same 64-byte line repeated. Only the requester's own memory is at risk: a client that decodes without a size limit allocates the whole thing. x-badhttp-plain-bytes states the inflated size, x-badhttp-plain-line carries the line without its newline (63 characters; the plaintext is that line plus a newline, repeated), and x-badhttp-plain-sha256 is the hash of the whole."
  },
  "edge_transcoding": {
    "ok": "Nothing to transcode: a client that did not list gzip is sent identity by this Worker itself — unless it refused gzip with q=0, which the edge reports as listing it, and then it gets gzip.",
    "br": "Delivered only to a client whose Accept-Encoding lists br; decoded to identity for everyone else, Content-Encoding removed and Content-Length dropped.",
    "zstd": "Delivered only to a client whose Accept-Encoding lists zstd (the edge honours that even though it drops zstd from the set it reports to this Worker); decoded to identity for everyone else.",
    "deflate": "Decoded to identity for every client probed on 2026-09-01, including one that sent Accept-Encoding: deflate — the only coding among those probed that no client received.",
    "not-compressed": "Cannot decode it, so it removes the header and delivers the text: a client without gzip sees a correct response.",
    "undeclared": "Nothing to transcode: everyone gets the gzip bytes labelled as text.",
    "truncated": "Inflates what it can and ends the body cleanly: a 200 with the partial plaintext (1,860 of 4,096 bytes at the default length; a correct prefix of 628,228 bytes at 1 MiB) and no error anywhere. For a document of a few bytes the partial text may be all of it.",
    "corrupt": "At the default length, a 200 with an EMPTY body: the decode fails, nothing is sent, no error anywhere. At 1 MiB it streamed the correct plaintext up to the damage and garbage after it, 60 bytes short, still no error — the CRC-skipping outcome.",
    "bad-crc": "Does not check the trailer: the full plaintext, no error.",
    "trailing-garbage": "The full plaintext; the junk is dropped without a word.",
    "multi-member": "The first member only — half the document (2,048 of 4,096 bytes at the default length), no error.",
    "double": "Removes exactly one layer and relabels the rest Content-Encoding: gzip — self-consistent (the header still matches the body), though RFC 9110 §7.7 forbids the transformation under no-transform, and the one case where the edge itself hands a client a coding it recognizes that the client never listed.",
    "double-hidden": "Removes one layer and the header: gzip bytes labelled as text.",
    "deflate-raw": "Cannot inflate it: the raw bytes go through with the header removed. Only a client whose reported set lists gzip gets them with the header intact; listing deflate does not help — the header is removed for that client too.",
    "unknown-coding": "Unrecognized, so untouched: everyone gets it as sent.",
    "uppercase": "Recognized: decoded to identity for a client without gzip.",
    "x-gzip": "Not recognized as gzip: passed to everyone as sent, header and all, whatever they advertised.",
    "empty": "Header removed, Content-Length: 0.",
    "wrong-length": "Decodes and re-chunks: the lie disappears and a client without gzip gets a complete, correct response.",
    "gzip-file": "Commits the corruption itself: a client without gzip receives the plaintext, still labelled application/gzip with the .gz filename, Content-Encoding and Content-Length removed (observed 2026-09-02).",
    "bomb": "Not served: a client whose reported set lacks gzip gets a 406 asking for Accept-Encoding: gzip. That set reads as empty for a client that sent no Accept-Encoding at all, or only \"*\" — requests RFC 9110 §12.5.3 says accept gzip — so the 406 is not negotiation but a refusal: the edge would otherwise inflate the member itself and ship the whole ?size= MiB as text (observed before the 406 was added), testing no decoder."
  },
  "params": {
    "ok": [
      "length",
      "code"
    ],
    "br": [
      "code",
      "length (only 4096)"
    ],
    "zstd": [
      "code",
      "length (only 4096)"
    ],
    "deflate": [
      "length",
      "code"
    ],
    "not-compressed": [
      "length",
      "code"
    ],
    "undeclared": [
      "length",
      "code"
    ],
    "truncated": [
      "length",
      "code"
    ],
    "corrupt": [
      "length",
      "code"
    ],
    "bad-crc": [
      "length",
      "code"
    ],
    "trailing-garbage": [
      "length",
      "code"
    ],
    "multi-member": [
      "length",
      "code"
    ],
    "double": [
      "length",
      "code"
    ],
    "double-hidden": [
      "length",
      "code"
    ],
    "deflate-raw": [
      "length",
      "code"
    ],
    "unknown-coding": [
      "length",
      "code"
    ],
    "uppercase": [
      "length",
      "code"
    ],
    "x-gzip": [
      "length",
      "code"
    ],
    "empty": [
      "code",
      "length (only 0)"
    ],
    "wrong-length": [
      "length (128–1048576)",
      "code"
    ],
    "gzip-file": [
      "length",
      "code"
    ],
    "bomb": [
      "size"
    ]
  },
  "usage": "/compress/{flavor}?length=4096&code=200",
  "document": "Deterministic and self-describing: 64-byte lines, each \"{offset:08d} {length:08d} badhttp compress body\" padded with dots to 63 characters plus a newline; the document is cut at ?length= (default 4096, max 1048576; wrong-length needs at least 128). br and zstd are fixed at 4096 bytes and empty at 0 (?length= accepted only at that value); bomb takes ?size= in MiB (1–32, default 8) instead. ?code= (200–599, not 204/205/304) sets the status on every flavor but bomb: a compressed or mislabelled error body is its own bug class.",
  "verification": "Every flavor response carries x-badhttp-plain-bytes and x-badhttp-plain-sha256 for the plaintext (bomb's hash comes from a table; gzip-file adds x-badhttp-wire-sha256 for the bytes a download should keep): decode the body, then compare length and SHA-256. A decoder that returns the wrong bytes without an error is the finding.",
  "accept_encoding": {
    "as_the_edge_reports_it": "gzip, deflate, br",
    "as_seen_by_this_worker": "gzip, br",
    "note": "The edge — Cloudflare's CDN, between you and this Worker — rewrites Accept-Encoding to \"gzip, br\" before this Worker runs and keeps your value in request.cf.clientAcceptEncoding, normalized: a canonical set in a fixed order, q-values dropped (q=0 included), x-gzip and case folded to gzip, \"*\" and an empty value reported as absent (null), a value containing any non-ASCII byte reported as absent, and zstd dropped from the set entirely (zstd alone reads as absent; \"gzip, zstd\" as \"gzip\") even though the edge delivers zstd to a client that lists it. /compress/ok and /compress/bomb negotiate from that set; the raw header (always \"gzip, br\" here) is shown but never used."
  },
  "edge": {
    "note": "The edge removes one coding layer it recognizes (gzip, br, zstd) unless the normalized set above lists it (q=0 counts as listing), transcoding the body to identity, cache-control: no-transform notwithstanding — lossily for broken streams; a second declared layer (double) is delivered regardless. It decoded zlib deflate for every client probed, including one that asked for it. It passes codings it does not recognize (x-gzip, badhttp) through untouched. edge_transcoding says what each flavor became for a client without gzip, at the default length unless a length is named. Send Accept-Encoding: gzip (br, zstd for those flavors) to receive the bytes as this Worker sent them.",
    "probed": "2026-09-01",
    "observations": "The home page carries the dated per-flavor results for six real clients (2026-09-02); the scripts and raw output are in the project repository (scripts/compress-witness/, docs/probe-compress-clients-2026-09-02.txt)."
  },
  "encodings": {
    "gzip": "computed per request (CompressionStream)",
    "deflate": "computed per request, zlib-wrapped as the coding requires — decoded by the edge for every client probed (2026-09-01)",
    "deflate-raw": "computed per request",
    "br": "pre-computed for the 4096-byte document",
    "zstd": "pre-computed for the 4096-byte document"
  },
  "headers": "Every flavor response is text/plain; charset=utf-8 (gzip-file: application/gzip) with cache-control: no-store, no-transform (without no-transform the edge would also compress the plain-text flavors); this index is no-transform too; error replies are ordinary JSON (no-store) that the edge may compress. HEAD returns the GET's headers and Content-Length as this Worker sends them; on HEAD the edge strips Content-Length and Content-Encoding from any response labelled with a coding it recognizes (gzip, br, zstd) that your reported set does not list — even not-compressed, which it delivers intact on GET — while x-gzip and badhttp keep both.",
  "limits": {
    "max_length_bytes": 1048576,
    "wrong_length_min_bytes": 128,
    "bomb_max_mib": 32
  },
  "spec": "RFC 9110 §8.4 and §12.5.3; RFC 1950, 1951, 1952; RFC 7932 (br); RFC 8878 (zstd)"
}
