feat(compress): Decode brotli and zstd response bodies - #90
Merged
Conversation
A body arriving as br or zstd could not be asserted on at all: the three body assertions refused by name while the status and header assertions carried on. Both are what CDNs actually serve, so testing the payload behind content negotiation -- the ordinary case -- was the one thing the tool could not do. Neither coding is in the standard library, so each costs a dependency, and the count was cut to three deliberately when viper went (#54). Measured at release flags rather than guessed: brotli adds 233KB and zstd 186KB to a 7.38MB binary, 5.7% together, and both modules bring nothing transitively. klauspost/compress is a large repository but only its zstd package links, so the cost is the decoder rather than the library. That is a smaller price than a CDN-facing HTTP assertion tool that cannot read CDN responses. A build tag was the alternative and fits this project badly: released binaries are how the tool is used, so a tag either ships releases that cannot decode the thing the change is about, or doubles the artifacts and makes the user choose. The list of supported codings in the failure is now derived from the decoder map instead of being spelled out, so the next coding cannot be added while the message still claims otherwise. The test suite used br throughout as its stand-in for "an encoding with no decoder here", which is no longer true of it. That role moves to compress (LZW): RFC 9110 still registers it, effectively nothing serves it, and unlike br and zstd it is not a plausible candidate for support later. Brotli also gains a corrupt-stream fixture, a failure only reachable now that the bytes get as far as a decoder. Verified against streams from the reference implementations -- brotli 1.2.0 and zstd 1.5.7 -- rather than only against Go's own writers, and brotli end to end against jsdelivr and the npm registry. Closes #77 Closes #78 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CrknafJSP5hF8u865cbnqX
korya
force-pushed
the
korya-feat-brotli-zstd
branch
from
August 11, 2026 11:10
d9da582 to
e50374e
Compare
korya
marked this pull request as ready for review
August 11, 2026 11:22
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
A CDN response cannot have its payload asserted on, because brotli and zstd bodies are never decoded.
decodersknew only gzip and deflate, so--assert-body,--assert-body-eqand--assert-jqrefused by name while--assert-ok,--assert-statusand--assert-header*carried on:Brotli is the default for most CDNs and zstd is a registered coding (RFC 8878) being switched on across them. Testing content negotiation with
-H 'Accept-Encoding: br'is an ordinary thing to do, and it was the one thing this tool could not follow through on.Solution
Add both decoders —
andybalholm/brotliandklauspost/compress/zstd— and derive the "supported" list from the decoder map so it can no longer drift.The dependency question, with numbers instead of adjectives
The count was cut to three deliberately when viper went (#54), so both tickets asked for this to be weighed rather than assumed. Nothing tracked binary size, so it was measured at release flags (
-trimpath -ldflags="-s -w",CGO_ENABLED=0):+ brotli+ brotli + zstdBoth modules bring zero transitive dependencies. #78 worried that
klauspost/compressis "considerably larger than a brotli-only package" — true of the repository, not of the binary: only thezstdpackage links, so it costs 186 KB, less than brotli.The build-tag alternative was rejected because it fits this project's distribution badly. Released binaries are how the tool is used, so a tag either ships releases that cannot decode the thing the change is about, or doubles the artifacts to ten and makes the user pick.
The part the tickets called "one map entry"
The suite used
brthroughout as its stand-in for an encoding with no decoder here — which stopped being true of it. That role moves tocompress(LZW): RFC 9110 still registers it, effectively nothing serves it, and unlike br and zstd it is not a plausible candidate for support later, so the fixtures should stay honest this time.The e2e brotli fixture was also fake by construction — "the bytes are not real brotli because nothing in the suite could produce them, and the CLI never gets far enough to care." With a decoder the CLI does get far enough: fed to a real decoder those bytes give
unexpected EOF./brotlinow serves genuine brotli,/zstdgenuine zstd, and/brotli-corruptcovers a failure that was unreachable before — a body claiming br that is not br.Verification
New e2e tests cover decoding,
--assert-jqover a decoded body, and that theContent-Encodingheader still reports what arrived. They were mutation-checked: with the two map entries removed they fail, so they are testing the decoders rather than the fixtures.Manually, both codings were decoded from streams produced by the reference implementations —
brotli 1.2.0andzstd 1.5.7— not only by Go's own writers, which is the interop the test suite cannot prove on its own. Brotli additionally end-to-end against jsdelivr and the npm registry, asserting the payload and theContent-Encodingheader in the same run.Other Changes
no decoder for "compress"; br, deflate, gzip, zstd are supported, built from the map, with an e2e test pinning it.--helpand README updated; the README paragraph promising br and zstd "are not supported yet" is gone.Closes #77
Closes #78
Related:
🤖 Generated with Claude Code