RFC 9841 §8 Shared Brotli Framing Format parser — multi-resource container.
Module brotliFrame | Source packages/front/fw/src/io/compress/brotli_frame.js | Deps none | Worker-safe yes
Parser for the chunked container defined by RFC 9841 §8 (Shared Brotli Framing Format Stream). The container encapsulates one or more brotli/shared-brotli streams with per-chunk metadata, dictionary references, optional hashes and an optional central directory.
The signature 91 0a 42 52 is by construction an invalid WBITS pattern in brotli/large-window-brotli — a decoder can therefore disambiguate a framing container from a raw brotli stream.
This module does not decompress payloads — that is the job of brotli. Typical flow:
brotliFrame.parse(buf)
→ { chunks }
brotliFrame.extractResources(parsed)
→ [{ payload, codec, ... }, ...]
then for each resource:
brotli.brotliDecompressSync(resource.payload)
Resolve
const f = runtime.resolve('brotliFrame');
// Returns: { parse, extractResources, parseMetadataFields,
// CHUNK_TYPE_NAMES, CODEC_NAMES }
API
| Method | Signature | Returns |
|---|---|---|
parse |
(buf: Uint8Array) => ParsedFrame |
Container structure (chunks described, payloads exposed) |
extractResources |
(parsed: ParsedFrame) => Array<Resource> |
Grouped resources (first → middle* → last sequences concatenated) |
parseMetadataFields |
(payload: Uint8Array) => Array<Field> |
Parse §8.3 fields from a metadata chunk payload |
CHUNK_TYPE_NAMES |
Record<number, string> |
Numeric → name mapping |
CODEC_NAMES |
Record<number, string> |
Numeric → name mapping |
Format ParsedFrame
{
flags: number,
hasFinalFooter: boolean,
chunks: Array<{
type: number, // 0..10 per §8.2
typeName: string, // 'padding', 'data', 'first-partial-data', ...
codec: number, // -1 if chunk type has no codec; otherwise 0..3
codecName: string, // 'uncompressed' | 'keep-decoder' | 'brotli' | 'shared-brotli'
uncompressedSize: number, // -1 if codec='uncompressed'
dictionaryRefs: Array | null, // if codec='shared-brotli'
dataFlags: number, // for chunk types 2..5
hash: { type, bytes } | null, // 256-bit hash if dataFlags bit 1 set
headerStart, contentStart, payloadStart, contentEnd, // byte offsets
payload: Uint8Array,
}>,
finalFooter: Uint8Array | null,
}
Resource format (output of extractResources)
{
payload: Uint8Array, // concatenated payload bytes
codec: number,
codecName: string,
uncompressedSize: number,
dictionaryRefs: Array | null,
}
Field format (output of parseMetadataFields)
{
name: string, // 2 ASCII letters (e.g. 'id', 'mt', 'AP')
kind: 'standard' | 'custom', // lowercase = standard, uppercase = custom
content: Uint8Array, // raw bytes (length via varint)
}
Chunk types (§8.2)
| ID | Name | Has codec | Has flags byte |
|---|---|---|---|
| 0 | padding |
no | no |
| 1 | metadata |
yes | no |
| 2 | data |
yes | yes (+ optional hash) |
| 3 | first-partial-data |
yes | yes |
| 4 | middle-partial-data |
yes | yes |
| 5 | last-partial-data |
yes | yes |
| 6 | footer-metadata |
yes | no |
| 7 | global-metadata |
yes | no |
| 8 | repeat-metadata |
yes | no |
| 9 | central-directory |
no | no |
| 10 | final-footer |
no | no |
Codec values (§8.2)
| ID | Name | Description |
|---|---|---|
| 0 | uncompressed |
Raw bytes |
| 1 | keep-decoder |
Continuation of the decoder state from the previous chunk |
| 2 | brotli |
RFC 7932 stream |
| 3 | shared-brotli |
RFC 9841 stream (with dictionary refs) |
RFC 9841 §8 coverage
| Section | Coverage |
|---|---|
| §8.1 Main format (signature + flags) | ✅ |
| §8.2 Chunk format (length / type / codec / uSize / dict refs) | ✅ |
§8.3 Metadata fields (id, mt, customs) |
✅ via parseMetadataFields |
| §8.4.1 Padding chunk (type 0) | ✅ (validated, content skipped) |
| §8.4.2 Metadata chunk (type 1) | ✅ |
| §8.4.3 Data chunk (type 2) + flags + hash | ✅ |
| §8.4.4-6 Partial data chunks (types 3-5) | ✅ |
| §8.4.7-9 Footer / global / repeat metadata (types 6-8) | ✅ |
| §8.4.10 Central directory (type 9) | ✅ (payload exposed raw, entry parsing: future) |
| §8.4.11 Final footer (type 10) | ✅ |
| Hash verification (256-bit HighwayHash) | ❌ — HighwayHash impl absent from fw |
Examples
Simple parsing
const f = runtime.resolve('brotliFrame');
const parsed = f.parse(containerBytes);
console.log('Chunks:', parsed.chunks.length);
for (const c of parsed.chunks) {
console.log(' -', c.typeName, 'codec=' + c.codecName, 'len=' + c.payload.length);
}
Extraction + decompression of resources
const f = runtime.resolve('brotliFrame');
const br = runtime.resolve('brotli');
const parsed = f.parse(containerBytes);
const resources = f.extractResources(parsed);
for (const res of resources) {
if (res.codecName === 'brotli') {
const decoded = br.brotliDecompressSync(res.payload);
// ... usage ...
}
}
Reading metadata fields §8.3
const f = runtime.resolve('brotliFrame');
const parsed = f.parse(containerBytes);
for (const c of parsed.chunks) {
if (c.typeName === 'metadata' && c.codecName === 'uncompressed') {
const fields = f.parseMetadataFields(c.payload);
for (const field of fields) {
console.log(field.kind, field.name, new TextDecoder().decode(field.content));
}
}
}
Worker Usage
const worker = fw.createWorker(
function ({ libs, args }) {
const f = libs.brotliFrame;
const br = libs.brotli;
const parsed = f.parse(args[0]);
const resources = f.extractResources(parsed);
const decoded = resources
.filter(r => r.codecName === 'brotli')
.map(r => br.brotliDecompressSync(r.payload));
self.postMessage(decoded);
},
{
dependencies: ['brotli', 'brotliFrame'],
args: [containerBytes],
}
);
Notes
- The parser validates bounds: chunk length vs buffer size, reserved flags at zero, hash size, invalid dict-ref bit combinations.
extractResourcesgroupsfirst→middle*→lastsequences into a single resource. An unterminated sequence throwsEBADSTREAM.metadata/footer-metadata/global-metadata/repeat-metadata/central-directorychunks expose their payloads as rawUint8Array. The §8.3 field parser (parseMetadataFields) is available — parsing of central directory entries is yet to be delivered.- HighwayHash (32 bytes,
dataFlagsbit 1) is exposed but not verified — HighwayHash is not implemented infw. - Tests: 29 cases (signature + flags + all chunk types + dict refs +
parseMetadataFieldshappy/error paths + integration via hand-crafted container).
See also
- brotli — decompression of extracted resources
- brotliShared — RFC 9841 §3 / §5 / §6, Shared Dictionary Stream parser
- brotliDict, brotliDictWords — shared static dictionary