decode gzip frames, and ask the server for them #107
No reviewers
Labels
No labels
area:defold
area:docs
area:infra
area:protocol
area:testing
kind:bug
kind:chore
phase:breadth
phase:core
phase:hardening
phase:slice
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
yuris/spacetimedb-defold!107
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "feat-gzip"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
The server compresses any message over 1KiB and its default scheme is brotli, which is why
connecthas always pinnedcompression=None— an omitted parameter is a wire no Defold build can read. Gzip it can read, so it now asks for that and inflates.The fact this turned on
zlib.inflatelearned to sniff the1f 8bwrapper and strip it in Defold 1.12.4. I checked across releases rather than trust the commit subject, which reads as a routine miniz bump:engine/dlib/src/dlib/zlib.cppIsGZip,0x8b)That is now the documented floor. We pin 1.13.0 in
flake.nix, so CI would never have noticed the difference.Shape
connectasks forGzipwhen a gunzip is in reach,Nonewhen it is not — so a session that cannot inflate still gets a readable wire instead of a broken one. Never omitted.decode_server(data, inflate)takes the gunzip as an argument rather than reaching for thezlibglobal, keeping the module's no engine APIs promise.init.luaresolves the ambient one the same way the builder resolvesjson.The tag byte replaces the message's leading byte instead of prefixing the stream, so the gzip magic sits at byte 2 and the plaintext is the
ServerMessagefrom its sum tag.Proof
A fixture pair — the same 711-row readback captured off a live 2.8.2 twice, plain (33,338 B) and gzipped (14,526 B) — asserted to decode to the same tag, same table, and byte-identical rows. Both plausible slice errors were mutation-proven to fail it:
truncated read of 1 byte(s) at offset 0array count 67108864 exceeds 33323 remainingThe first conformance run failed, which is the useful part. Every frame in phases 1–5 and 7 is under the threshold, so six phases went green before the bulk subscription arrived compressed and hit
gzip frame but no inflate function was passed— the smoke's own timing wrapper had dropped the second argument. That is exactly the shape of bug this feature invites, and only a live run over 1KiB finds it.What it buys
Below 1KiB nothing changes, so ordinary per-transaction updates are untouched — this earns its keep on the initial subscription and nowhere else. Threshold confirmed by sweeping it: 941 B arrives plain, 1171 B arrives gzipped, matching
COMPRESS_THRESHOLD = 1024.On the v1 JSON wire the parameter changes nothing at all (measured identical across None/Gzip/Brotli), so v1 passes no gunzip.
Verification
Suite green, stylua clean, and all four conformance suites pass against a live server — native v2 and v1, HTML5 v2 and v1. The HTML5 legs are what prove the engine's real
zlib.inflateworks in wasm, which was the one thing I could not settle by reading.Version goes to 3.1.0: additive, since nobody is on an older engine to break.