Skip to main content

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:

  1. Reads Required Insert Count = 0 (no dynamic table entries needed)
  2. Reads Base = 0
  3. Decodes the literal field line representation
  4. 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:

  1. Receives the encoder stream instruction and inserts the entry
  2. Receives the encoded field section
  3. Checks Required Insert Count = 1 (needs entry at absolute index 0)
  4. Decodes the indexed field line from dynamic table index 0
  5. 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:

  1. Receives the encoder stream instruction
  2. Inserts the entry into the dynamic table
  3. Receives the field section with Post-Base reference
  4. Waits if necessary until the required entry is available
  5. 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:

  1. Literal Representations: Encoding field lines without dynamic table
  2. Dynamic Table Management: Inserting, referencing, and duplicating entries
  3. Synchronization: Decoder acknowledgments and encoder tracking
  4. Post-Base Indexing: Referencing recently inserted entries
  5. Error Recovery: Stream cancellation for incomplete processing
  6. 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.