rpc_dart_compression 0.2.0
rpc_dart_compression: ^0.2.0 copied to clipboard
Cross-platform compression codecs for rpc_dart (web/JS/Wasm compatible).
0.2.0 #
Security #
- Gzip inflation is bounded as it happens, not checked once it is over. The
limit ran on
result.length, so the output existed before it was refused: 4.0 MiB of compressed zeros against a 16 MiB limit cost 1873 MiB of RSS over 17.5 seconds (~470x). The gzip trailer's ISIZE is the size mod 2^32, so a pre-check on it clears trivially. - The residual on web is documented rather than claimed fixed.
dart2jshas no incremental inflater available, so the same payload is refused in 12 ms on the VM and 15 980 ms on dart2js — about 65 KiB of wire buys 64 MiB and sixteen seconds of the event loop. The ISIZE contract is now pinned by a test on both runtimes so the difference cannot drift unnoticed.
Changed #
- Requires rpc_dart 6. See its changelog.
0.1.3 #
Fixes (audit):
RpcGzipCodecnow validates the compressionlevel(0..9). An out-of-range level (e.g.10) made archive's deflate silently emit a gzip frame with NO compressed payload (its range throw is commented out upstream) — silently corrupt output. The constructor andregister({int level})nowassertthe range for dev builds, andcompressdefensivelylevel.clamp(0, 9)at the encode site so release / dart2js builds (where asserts are stripped) cannot emit a corrupt frame. Added a regression test: out-of-range throws in dev, and boundary levels always produce a valid gzip that decompresses back to the original.
0.1.2 #
Features:
RpcGzipCodecnow accepts a compressionlevel(0..9, default6matching the previous archive default, so existing callers are unchanged). It is forwarded toGZipEncoder.encodeBytes(level: ...). ConstantsRpcGzipCodec.fastestLevel(1),RpcGzipCodec.defaultLevel(6), andRpcGzipCodec.bestLevel(9) are provided.RpcGzipCodec.register({int level, int maxDecompressedSize})forwards both options.- Optional decompression-bomb guard via
maxDecompressedSize(default unlimited). The gzip ISIZE trailer is checked before allocating, so oversized declared output is rejected with aFormatExceptionat no cost for in-limit payloads.
Memory:
- Removed the redundant
Uint8List.fromList(...)copies incompress/decompress:GZipEncoder.encodeBytesandGZipDecoder.decodeBytesalready return aUint8Liston every platform. The archive 4.x streaming API (encodeStream/decodeStreamwithOutputMemoryStream) was evaluated but does not reduce peak memory for theUint8List -> Uint8Listinterface (output still accumulates into one contiguous buffer) and would bypass the integrity guards on web, so the validated whole-buffer path is kept. The integrity checks (header + CRC32 + ISIZE trailer) are unchanged.
0.1.1 #
Fixes (audit):
RpcGzipCodec.decompressnow verifies integrity instead of silently accepting corrupt input. It validates the gzip magic/compression method, decodes withverify: true, and independently checks the gzip trailer (CRC32 + ISIZE) against the decoded output. Malformed, truncated, or non-gzip input now throwsFormatExceptionconsistently across VM, dart2js, and Wasm -- previously the web decoder silently returned garbage/empty bytes.
0.1.0 #
- Initial release:
RpcGzipCodeccross-platform gzip codec (native/web/JS/Wasm via thearchivepackage).