Appendix B. Encoding and Decoding Examples
This appendix provides examples of QPACK encoding and decoding operations, illustrating how the encoder and decoder interact through their respective streams and how the dynamic table evolves.
B.1 Literal Field Line With Name Reference
This example shows encoding a field line with a name that exists in the static table. The encoder uses a literal representation with a static name reference.
Encoding
Field line to encode:
custom-key: custom-value
Assuming "custom-key" is at static table index 15, the encoder produces:
Encoded Field Section:
0x00 0x00 # Required Insert Count = 0, Base = 0
0x50 0x0c 0x63 0x75 0x73 0x74 0x6f 0x6d 0x2d 0x76 0x61 0x6c 0x75 0x65
# Literal with static name reference, index 15, value "custom-value"
Decoding
The decoder receives the encoded field section and processes it:
- Reads Required Insert Count = 0 (no dynamic table entries needed)
- Reads Base = 0
- Decodes the literal field line representation
- Produces the field line:
custom-key: custom-value
B.2 Dynamic Table Insertions
This example demonstrates inserting entries into the dynamic table and referencing them in subsequent field sections.
Step 1: Encoder Inserts Entry
The encoder decides to insert a new field line into the dynamic table:
Encoder Stream:
0xc0 0x0c 0x63 0x75 0x73 0x74 0x6f 0x6d 0x2d 0x76 0x61 0x6c 0x75 0x65
# Insert with name reference (static index 15), value "custom-value"
Dynamic Table State (after insertion):
[0] custom-key: custom-value
Insert Count: 1
Step 2: Encoder References Dynamic Entry
Now the encoder can reference this entry in a field section:
Encoded Field Section:
0x02 0x00 # Required Insert Count = 1, Base = 0
0x80 # Indexed Field Line, dynamic table index 0
Step 3: Decoder Processes
The decoder:
- Receives the encoder stream instruction and inserts the entry
- Receives the encoded field section
- Checks Required Insert Count = 1 (needs entry at absolute index 0)
- Decodes the indexed field line from dynamic table index 0
- Produces:
custom-key: custom-value
Step 4: Decoder Acknowledges
Decoder Stream:
0x80 # Section Acknowledgment (stream ID encoded)
This informs the encoder that the decoder has processed the field section referencing dynamic table entry 0.
B.3 Speculative Insertion
This example shows the encoder inserting an entry into the dynamic table before it is actually used, anticipating future use.
Step 1: Encoder Inserts Speculatively
Encoder Stream:
0x4a 0x63 0x75 0x73 0x74 0x6f 0x6d 0x2d 0x6b 0x65 0x79
0x0c 0x63 0x75 0x73 0x74 0x6f 0x6d 0x2d 0x76 0x61 0x6c 0x75 0x65
# Insert with literal name "custom-key", value "custom-value"
Dynamic Table State:
[0] custom-key: custom-value
Insert Count: 1
Step 2: Encoder Uses Entry Later
In a subsequent field section:
Encoded Field Section:
0x02 0x00 # Required Insert Count = 1, Base = 0
0x80 # Indexed Field Line, dynamic table index 0
B.4 Duplicate Instruction
This example demonstrates the duplicate instruction, which copies an existing dynamic table entry to the front of the table.
Initial Dynamic Table State
[0] custom-key: custom-value
[1] another-key: another-value
Insert Count: 2
Encoder Duplicates Entry
Encoder Stream:
0x01 # Duplicate, relative index 1
Dynamic Table State (after duplication):
[0] another-key: another-value # Duplicated entry
[1] custom-key: custom-value
[2] another-key: another-value # Original entry
Insert Count: 3
The duplicated entry becomes the most recent entry (absolute index 2, relative index 0).
B.5 Post-Base Indexing
This example illustrates Post-Base indexing, where the encoder references entries inserted after the Base value.
Step 1: Encoder Sets Base
The encoder starts encoding a field section with Base = 0:
Encoded Field Section Prefix:
0x02 0x80 # Required Insert Count = 1, Base = 0, Sign = 1 (negative delta)
This indicates Required Insert Count = 1, but Base = 0, meaning the field section will reference entry at absolute index 0.
Step 2: Encoder Inserts and References
While encoding, the encoder inserts a new entry:
Encoder Stream:
0xc0 0x0c 0x63 0x75 0x73 0x74 0x6f 0x6d 0x2d 0x76 0x61 0x6c 0x75 0x65
# Insert with name reference (static index 15), value "custom-value"
Dynamic Table State:
[0] custom-key: custom-value
Insert Count: 1
Encoded Field Section (continued):
0x10 # Post-Base Indexed Field Line, Post-Base Index = 0
This references the entry at absolute index 0 (Base + Post-Base Index = 0 + 0 = 0).
Step 3: Decoder Processes
The decoder:
- Receives the encoder stream instruction
- Inserts the entry into the dynamic table
- Receives the field section with Post-Base reference
- Waits if necessary until the required entry is available
- Decodes the field line
B.6 Stream Cancellation
This example shows the decoder canceling a stream, informing the encoder that a field section will not be processed.
Scenario
The decoder receives a field section on stream 4 but the stream is reset before processing completes.
Decoder Stream:
0x40 0x04 # Stream Cancellation, stream ID = 4
This informs the encoder that:
- The field section on stream 4 was not processed
- The encoder should not wait for acknowledgment
- Any dynamic table entries referenced only by that field section can be evicted sooner
B.7 Insert Count Increment
This example demonstrates the Insert Count Increment instruction, used by the decoder to acknowledge multiple insertions without referencing them in field sections.
Scenario
The encoder has inserted 5 entries, but the decoder has only acknowledged 2 through Section Acknowledgments.
Decoder Stream:
0x03 # Insert Count Increment, increment = 3
This informs the encoder that the decoder has received and processed 3 additional dynamic table insertions beyond those already acknowledged.
B.8 Complete Example: Multiple Field Sections
This comprehensive example shows a complete exchange with multiple field sections.
Initial State
Both encoder and decoder start with empty dynamic tables.
Exchange 1: First Request
Encoder Stream:
0xc0 0x0c 0x63 0x75 0x73 0x74 0x6f 0x6d 0x2d 0x76 0x61 0x6c 0x75 0x65
# Insert: custom-key: custom-value
Encoded Field Section (Stream 0):
0x02 0x00 # Required Insert Count = 1, Base = 0
0x80 # Indexed, dynamic index 0
0x51 0x04 0x74 0x65 0x73 0x74 # Literal with static name, value "test"
Dynamic Table State:
[0] custom-key: custom-value
Insert Count: 1
Decoded Field Lines:
custom-key: custom-value
another-key: test
Decoder Stream:
0x80 # Section Acknowledgment for stream 0
Exchange 2: Second Request
Encoded Field Section (Stream 4):
0x02 0x00 # Required Insert Count = 1, Base = 0
0x80 # Indexed, dynamic index 0
Decoded Field Lines:
custom-key: custom-value
Decoder Stream:
0x84 # Section Acknowledgment for stream 4
Exchange 3: Eviction
After receiving acknowledgments, the encoder can safely evict the entry if needed for new insertions.
Summary
These examples demonstrate:
- Literal Representations: Encoding field lines without dynamic table
- Dynamic Table Management: Inserting, referencing, and duplicating entries
- Synchronization: Decoder acknowledgments and encoder tracking
- Post-Base Indexing: Referencing recently inserted entries
- Error Recovery: Stream cancellation for incomplete processing
- Efficient Acknowledgment: Insert Count Increment for bulk acknowledgment
The interaction between encoder and decoder streams ensures proper synchronization while allowing for out-of-order delivery and efficient compression.