blackbull.grpc.compression¶
blackbull.grpc.compression
¶
gRPC message compression (the grpc-encoding header + LPM Compressed-Flag).
Only gzip is implemented, via the stdlib :mod:zlib in gzip-framing mode
(RFC 1952); identity (no compression) needs no code. gzip is the encoding
grpcio and grpc-go negotiate by default, so it covers the real interop cases.
Compression is a transport concern and lives here beside the LPM codec, not
in a middleware and not in a serialisation package: gRPC compresses each message
inside its Length-Prefixed-Message frame (the flag + length stay in clear), so
it is entangled with framing, not a whole-body byte transform a send-wrapper
could apply. A second codec (deflate, snappy, …) is the one anticipated
extension of this module: lift SUPPORTED to a
{grpc-encoding-name: (compress, decompress)} registry and route it through
the two negotiation points already in :mod:~blackbull.grpc.asgi (the request
grpc-encoding lookup and the response grpc-accept-encoding selection).
Deferred until a real second codec is needed — YAGNI, gzip is the interop floor.
Compression is only one form of gRPC runtime extension, and this registry is
not the runtime's extension model. Do not fold other extension forms into
"compression": call-level concerns are gRPC interceptors (the analogue of
@app.intercept); service-level, protobuf-carrying features (reflection,
health, rich errors) are the Track B package; new wire protocols attach via the
framework Extension mechanism. Keep the problem's scope where it belongs.
This module is pure compression, with no gRPC-status dependency (mirroring
:mod:~blackbull.grpc.codec): callers translate :class:DecompressionError
into the appropriate gRPC status.
DecompressionBombError
¶
Bases: DecompressionError
Decompressed output exceeded the caller's size limit — a small compressed frame that inflates past the per-message cap (a "zip bomb").
DecompressionError
¶
Bases: ValueError
A compressed request message could not be decompressed (corrupt stream, or an output larger than the caller's limit).
compress_gzip(data)
¶
Compress data into a single gzip stream.
decompress_gzip(data, max_output)
¶
Decompress a gzip data stream, refusing to produce more than max_output bytes.
The gRPC 4-byte length prefix bounds only the compressed transfer size;
a small compressed payload can inflate to gigabytes. Decompression is
therefore capped: :meth:zlib.decompressobj.decompress is given a
max_length so it stops at the limit and parks any unprocessed input in
unconsumed_tail — a non-empty tail (or an output past max_output)
means the message would exceed the cap and raises
:class:DecompressionBombError. A corrupt stream (bad header or trailing
CRC) raises :class:DecompressionError via the final :func:flush.
supports(encoding)
¶
Return True if encoding is one this module can (de)compress.