The Compression module provides low-level zlib-based data compression and decompression services for the noVNC client embedded in MeshCentral. It acts as a thin, performance-oriented wrapper around the bundled pako zlib implementation and is responsible for efficiently handling compressed binary streams used throughout the remote framebuffer (RFB) protocol.
Within the overall architecture, Compression is primarily consumed by:
- The Decoders module (e.g., Tight, ZRLE)
- The RFB and Display module
- The Websock transport layer
Compression is intentionally minimal and stateless at the application level, delegating stream state management to the underlying zlib ZStream implementation.
The Compression module provides two core capabilities:
- Deflation (Compression) – Compress raw binary data before transmission.
- Inflation (Decompression) – Decompress incoming zlib-compressed blocks.
These capabilities are essential for:
- Reducing bandwidth usage in remote desktop sessions.
- Supporting RFB encodings such as Tight and ZRLE.
- Maintaining protocol compatibility with VNC servers that rely on zlib streams.
The module consists of two primary classes:
Deflator– Handles zlib compression.Inflate– Handles zlib decompression.
flowchart LR
Websock["Websock Transport"] --> RFB["RFB Protocol Engine"]
RFB --> Decoders["Encoding Decoders"]
Decoders --> InflateClass["Inflate"]
RFB --> DeflatorClass["Deflator"]
subgraph compression_layer["Compression Module"]
DeflatorClass --> ZlibDeflate["pako zlib deflate"]
InflateClass --> ZlibInflate["pako zlib inflate"]
end
-
Incoming Data Path:
- Websock receives binary frames.
- RFB parses encoding type.
- If compressed, a decoder invokes
Inflate. - Decompressed data is passed to the Display pipeline.
-
Outgoing Data Path:
- RFB prepares protocol messages.
Deflatorcompresses payloads if required.- Websock transmits compressed bytes.
Component: meshcentral.public.novnc.core.deflator.Deflator
The Deflator class wraps the zlib deflate functionality from pako. It maintains an internal ZStream instance and performs chunked compression using Z_FULL_FLUSH.
- Uses
Z_DEFAULT_COMPRESSIONduring initialization. - Applies
Z_FULL_FLUSHfor each compression call. - Handles multi-chunk output automatically.
- Returns a single flattened
Uint8Array.
flowchart TD
Start["Input Uint8Array"] --> Setup["Configure ZStream"]
Setup --> DeflateCall["Call deflate() with Z_FULL_FLUSH"]
DeflateCall --> Check["More input remaining?"]
Check -->|"Yes"| Chunk["Allocate new output chunk"]
Chunk --> DeflateCall
Check -->|"No"| Combine["Merge output chunks"]
Combine --> EndNode["Return compressed Uint8Array"]
The Deflator:
- Sets
input,avail_in, andnext_inbefore compression. - Allocates a reusable output buffer (
chunkSizedefault 100 KB). - Iteratively calls
deflate()until all input is consumed. - Merges chunks if multiple passes are required.
- Clears input references after completion.
This design ensures:
- Efficient memory reuse.
- Proper flushing of zlib state.
- Safe handling of large payloads.
Component: meshcentral.public.novnc.core.inflator.Inflate
The Inflate class wraps zlib inflate operations for decompressing binary RFB data blocks.
- Initializes a persistent
ZStreamviainflateInit(). - Allows dynamic resizing of the output buffer.
- Requires the expected output size.
- Throws explicit errors on incomplete or failed decompression.
flowchart TD
Input["Compressed Uint8Array"] --> SetInput["Set ZStream input fields"]
SetInput --> Resize["Resize output buffer if needed"]
Resize --> InflateCall["Call inflate()"]
InflateCall --> Validate["next_out equals expected?"]
Validate -->|"No"| ErrorNode["Throw error"]
Validate -->|"Yes"| ReturnNode["Return decompressed Uint8Array"]
The Inflate class provides:
setInput(data)– Assigns compressed input to the stream.inflate(expected)– Decompresses exactlyexpectedbytes.reset()– Resets the zlib stream state.
Strict validation ensures:
- Detection of truncated or corrupted zlib blocks.
- Prevention of silent partial decompression.
The Decoders module relies heavily on Compression for RFB encodings such as:
- Tight
- TightPNG
- ZRLE
These encodings embed zlib-compressed pixel or tile data, which is passed through the Inflate class before rendering.
The RFB and Display module orchestrates protocol negotiation and framebuffer updates. When compression is negotiated, it:
- Uses Inflate for incoming compressed rectangles.
- May use Deflator for outgoing messages.
The Websock module provides raw binary transport over WebSocket. It does not interpret compression but supplies and receives the byte streams that Compression processes.
Both Deflator and Inflate follow a fail-fast model:
- Any negative zlib return code triggers an exception.
- Inflate validates output size strictly.
- Partial blocks result in explicit errors.
This approach prevents subtle rendering corruption and ensures protocol-level correctness.
Deflator supports multi-chunk compression for large inputs, reducing the risk of:
- Large contiguous memory allocations.
- Buffer overflow conditions.
Inflate pre-allocates its output buffer and resizes only when necessary, minimizing allocation overhead during frequent framebuffer updates.
Both classes reuse a single ZStream instance per object, avoiding repeated initialization costs.
Because compression operates on untrusted remote data:
- Inflate strictly enforces expected output size.
- Errors are surfaced immediately.
- No implicit buffer growth occurs beyond expected bounds.
This reduces risk from:
- Corrupted streams.
- Malformed zlib payloads.
- Resource exhaustion attacks.
The Compression module provides a focused, high-performance abstraction over zlib for the noVNC client in MeshCentral. By encapsulating pako stream handling inside the Deflator and Inflate classes, it:
- Simplifies integration with RFB encodings.
- Ensures protocol-compliant zlib handling.
- Maintains predictable memory and error behavior.
It forms a foundational layer beneath the Decoders and RFB modules, enabling efficient and reliable remote desktop rendering over WebSocket connections.