The prefixed integer from
Section 5.1 of
RFC 7541 is used heavily throughout this document. The format from [
RFC 7541] is used unmodified. Note, however, that QPACK uses some prefix sizes not actually used in HPACK.
QPACK implementations
MUST be able to decode integers up to and including 62 bits long.
The string literal defined by
Section 5.2 of
RFC 7541 is also used throughout. This string format includes optional Huffman encoding.
HPACK defines string literals to begin on a byte boundary. They begin with a single bit flag, denoted as 'H' in this document (indicating whether the string is Huffman encoded), followed by the string length encoded as a 7-bit prefix integer, and finally the indicated number of bytes of data. When Huffman encoding is enabled, the Huffman table from
Appendix B of
RFC 7541 is used without modification and the indicated length is the size of the string after encoding.
This document expands the definition of string literals by permitting them to begin other than on a byte boundary. An "N-bit prefix string literal" begins mid-byte, with the first (8-N) bits allocated to a previous field. The string uses one bit for the Huffman flag, followed by the length of the encoded string as a (N-1)-bit prefix integer. The prefix size, N, can have a value between 2 and 8, inclusive. The remainder of the string literal is unmodified.
A string literal without a prefix length noted is an 8-bit prefix string literal and follows the definitions in [
RFC 7541] without modification.
QPACK defines two unidirectional stream types:
-
An encoder stream is a unidirectional stream of type 0x02. It carries an unframed sequence of encoder instructions from encoder to decoder.
-
A decoder stream is a unidirectional stream of type 0x03. It carries an unframed sequence of decoder instructions from decoder to encoder.
HTTP/3 endpoints contain a QPACK encoder and decoder. Each endpoint
MUST initiate, at most, one encoder stream and, at most, one decoder stream. Receipt of a second instance of either stream type
MUST be treated as a connection error of type H3_STREAM_CREATION_ERROR.
The sender
MUST NOT close either of these streams, and the receiver
MUST NOT request that the sender close either of these streams. Closure of either unidirectional stream type
MUST be treated as a connection error of type H3_CLOSED_CRITICAL_STREAM.
An endpoint
MAY avoid creating an encoder stream if it will not be used (for example, if its encoder does not wish to use the dynamic table or if the maximum size of the dynamic table permitted by the peer is zero).
An endpoint
MAY avoid creating a decoder stream if its decoder sets the maximum capacity of the dynamic table to zero.
An endpoint
MUST allow its peer to create an encoder stream and a decoder stream even if the connection's settings prevent their use.
An encoder sends encoder instructions on the encoder stream to set the capacity of the dynamic table and add dynamic table entries. Instructions adding table entries can use existing entries to avoid transmitting redundant information. The name can be transmitted as a reference to an existing entry in the static or the dynamic table or as a string literal. For entries that already exist in the dynamic table, the full entry can also be used by reference, creating a duplicate entry.
An encoder informs the decoder of a change to the dynamic table capacity using an instruction that starts with the '001' 3-bit pattern. This is followed by the new dynamic table capacity represented as an integer with a 5-bit prefix; see
Section 4.1.1.
0 1 2 3 4 5 6 7
+---+---+---+---+---+---+---+---+
| 0 | 0 | 1 | Capacity (5+) |
+---+---+---+-------------------+
The new capacity
MUST be lower than or equal to the limit described in
Section 3.2.3. In HTTP/3, this limit is the value of the SETTINGS_QPACK_MAX_TABLE_CAPACITY parameter (
Section 5) received from the decoder. The decoder
MUST treat a new dynamic table capacity value that exceeds this limit as a connection error of type QPACK_ENCODER_STREAM_ERROR.
Reducing the dynamic table capacity can cause entries to be evicted; see
Section 3.2.2. This
MUST NOT cause the eviction of entries that are not evictable; see
Section 2.1.1. Changing the capacity of the dynamic table is not acknowledged as this instruction does not insert an entry.
An encoder adds an entry to the dynamic table where the field name matches the field name of an entry stored in the static or the dynamic table using an instruction that starts with the '1' 1-bit pattern. The second ('T') bit indicates whether the reference is to the static or dynamic table. The 6-bit prefix integer (
Section 4.1.1) that follows is used to locate the table entry for the field name. When T=1, the number represents the static table index; when T=0, the number is the relative index of the entry in the dynamic table.
The field name reference is followed by the field value represented as a string literal; see
Section 4.1.2.
0 1 2 3 4 5 6 7
+---+---+---+---+---+---+---+---+
| 1 | T | Name Index (6+) |
+---+---+-----------------------+
| H | Value Length (7+) |
+---+---------------------------+
| Value String (Length bytes) |
+-------------------------------+
An encoder adds an entry to the dynamic table where both the field name and the field value are represented as string literals using an instruction that starts with the '01' 2-bit pattern.
This is followed by the name represented as a 6-bit prefix string literal and the value represented as an 8-bit prefix string literal; see
Section 4.1.2.
0 1 2 3 4 5 6 7
+---+---+---+---+---+---+---+---+
| 0 | 1 | H | Name Length (5+) |
+---+---+---+-------------------+
| Name String (Length bytes) |
+---+---------------------------+
| H | Value Length (7+) |
+---+---------------------------+
| Value String (Length bytes) |
+-------------------------------+
An encoder duplicates an existing entry in the dynamic table using an instruction that starts with the '000' 3-bit pattern. This is followed by the relative index of the existing entry represented as an integer with a 5-bit prefix; see
Section 4.1.1.
0 1 2 3 4 5 6 7
+---+---+---+---+---+---+---+---+
| 0 | 0 | 0 | Index (5+) |
+---+---+---+-------------------+
The existing entry is reinserted into the dynamic table without resending either the name or the value. This is useful to avoid adding a reference to an older entry, which might block inserting new entries.
A decoder sends decoder instructions on the decoder stream to inform the encoder about the processing of field sections and table updates to ensure consistency of the dynamic table.
After processing an encoded field section whose declared Required Insert Count is not zero, the decoder emits a Section Acknowledgment instruction. The instruction starts with the '1' 1-bit pattern, followed by the field section's associated stream ID encoded as a 7-bit prefix integer; see
Section 4.1.1.
This instruction is used as described in Sections [
2.1.4] and [
2.2.2].
0 1 2 3 4 5 6 7
+---+---+---+---+---+---+---+---+
| 1 | Stream ID (7+) |
+---+---------------------------+
If an encoder receives a Section Acknowledgment instruction referring to a stream on which every encoded field section with a non-zero Required Insert Count has already been acknowledged, this
MUST be treated as a connection error of type QPACK_DECODER_STREAM_ERROR.
The Section Acknowledgment instruction might increase the Known Received Count; see
Section 2.1.4.
When a stream is reset or reading is abandoned, the decoder emits a Stream Cancellation instruction. The instruction starts with the '01' 2-bit pattern, followed by the stream ID of the affected stream encoded as a 6-bit prefix integer.
This instruction is used as described in
Section 2.2.2.
0 1 2 3 4 5 6 7
+---+---+---+---+---+---+---+---+
| 0 | 1 | Stream ID (6+) |
+---+---+-----------------------+
The Insert Count Increment instruction starts with the '00' 2-bit pattern, followed by the Increment encoded as a 6-bit prefix integer. This instruction increases the Known Received Count (
Section 2.1.4) by the value of the Increment parameter. The decoder should send an Increment value that increases the Known Received Count to the total number of dynamic table insertions and duplications processed so far.
0 1 2 3 4 5 6 7
+---+---+---+---+---+---+---+---+
| 0 | 0 | Increment (6+) |
+---+---+-----------------------+
An encoder that receives an Increment field equal to zero, or one that increases the Known Received Count beyond what the encoder has sent,
MUST treat this as a connection error of type QPACK_DECODER_STREAM_ERROR.
An encoded field section consists of a prefix and a possibly empty sequence of representations defined in this section. Each representation corresponds to a single field line. These representations reference the static table or the dynamic table in a particular state, but they do not modify that state.
Encoded field sections are carried in frames on streams defined by the enclosing protocol.
Each encoded field section is prefixed with two integers. The Required Insert Count is encoded as an integer with an 8-bit prefix using the encoding described in
Section 4.5.1.1. The Base is encoded as a Sign bit ('S') and a Delta Base value with a 7-bit prefix; see
Section 4.5.1.2.
0 1 2 3 4 5 6 7
+---+---+---+---+---+---+---+---+
| Required Insert Count (8+) |
+---+---------------------------+
| S | Delta Base (7+) |
+---+---------------------------+
| Encoded Field Lines ...
+-------------------------------+
Required Insert Count identifies the state of the dynamic table needed to process the encoded field section. Blocking decoders use the Required Insert Count to determine when it is safe to process the rest of the field section.
The encoder transforms the Required Insert Count as follows before encoding:
if ReqInsertCount == 0:
EncInsertCount = 0
else:
EncInsertCount = (ReqInsertCount mod (2 * MaxEntries)) + 1
Here
MaxEntries is the maximum number of entries that the dynamic table can have. The smallest entry has empty name and value strings and has the size of 32. Hence,
MaxEntries is calculated as:
MaxEntries = floor( MaxTableCapacity / 32 )
MaxTableCapacity is the maximum capacity of the dynamic table as specified by the decoder; see
Section 3.2.3.
This encoding limits the length of the prefix on long-lived connections.
The decoder can reconstruct the Required Insert Count using an algorithm such as the following. If the decoder encounters a value of EncodedInsertCount that could not have been produced by a conformant encoder, it
MUST treat this as a connection error of type QPACK_DECOMPRESSION_FAILED.
TotalNumberOfInserts is the total number of inserts into the decoder's dynamic table.
FullRange = 2 * MaxEntries
if EncodedInsertCount == 0:
ReqInsertCount = 0
else:
if EncodedInsertCount > FullRange:
Error
MaxValue = TotalNumberOfInserts + MaxEntries
# MaxWrapped is the largest possible value of
# ReqInsertCount that is 0 mod 2 * MaxEntries
MaxWrapped = floor(MaxValue / FullRange) * FullRange
ReqInsertCount = MaxWrapped + EncodedInsertCount - 1
# If ReqInsertCount exceeds MaxValue, the Encoder's value
# must have wrapped one fewer time
if ReqInsertCount > MaxValue:
if ReqInsertCount <= FullRange:
Error
ReqInsertCount -= FullRange
# Value of 0 must be encoded as 0.
if ReqInsertCount == 0:
Error
For example, if the dynamic table is 100 bytes, then the Required Insert Count will be encoded modulo 6. If a decoder has received 10 inserts, then an encoded value of 4 indicates that the Required Insert Count is 9 for the field section.
The Base is used to resolve references in the dynamic table as described in
Section 3.2.5.
To save space, the Base is encoded relative to the Required Insert Count using a one-bit Sign ('S' in
Figure 12) and the Delta Base value. A Sign bit of 0 indicates that the Base is greater than or equal to the value of the Required Insert Count; the decoder adds the value of Delta Base to the Required Insert Count to determine the value of the Base. A Sign bit of 1 indicates that the Base is less than the Required Insert Count; the decoder subtracts the value of Delta Base from the Required Insert Count and also subtracts one to determine the value of the Base. That is:
if Sign == 0:
Base = ReqInsertCount + DeltaBase
else:
Base = ReqInsertCount - DeltaBase - 1
A single-pass encoder determines the Base before encoding a field section. If the encoder inserted entries in the dynamic table while encoding the field section and is referencing them, Required Insert Count will be greater than the Base, so the encoded difference is negative and the Sign bit is set to 1. If the field section was not encoded using representations that reference the most recent entry in the table and did not insert any new entries, the Base will be greater than the Required Insert Count, so the encoded difference will be positive and the Sign bit is set to 0.
The value of Base
MUST NOT be negative. Though the protocol might operate correctly with a negative Base using post-Base indexing, it is unnecessary and inefficient. An endpoint
MUST treat a field block with a Sign bit of 1 as invalid if the value of Required Insert Count is less than or equal to the value of Delta Base.
An encoder that produces table updates before encoding a field section might set Base to the value of Required Insert Count. In such a case, both the Sign bit and the Delta Base will be set to zero.
A field section that was encoded without references to the dynamic table can use any value for the Base; setting Delta Base to zero is one of the most efficient encodings.
For example, with a Required Insert Count of 9, a decoder receives a Sign bit of 1 and a Delta Base of 2. This sets the Base to 6 and enables post-Base indexing for three entries. In this example, a relative index of 1 refers to the fifth entry that was added to the table; a post-Base index of 1 refers to the eighth entry.
An indexed field line representation identifies an entry in the static table or an entry in the dynamic table with an absolute index less than the value of the Base.
0 1 2 3 4 5 6 7
+---+---+---+---+---+---+---+---+
| 1 | T | Index (6+) |
+---+---+-----------------------+
This representation starts with the '1' 1-bit pattern, followed by the 'T' bit, indicating whether the reference is into the static or dynamic table. The 6-bit prefix integer (
Section 4.1.1) that follows is used to locate the table entry for the field line. When T=1, the number represents the static table index; when T=0, the number is the relative index of the entry in the dynamic table.
An indexed field line with post-Base index representation identifies an entry in the dynamic table with an absolute index greater than or equal to the value of the Base.
0 1 2 3 4 5 6 7
+---+---+---+---+---+---+---+---+
| 0 | 0 | 0 | 1 | Index (4+) |
+---+---+---+---+---------------+
This representation starts with the '0001' 4-bit pattern. This is followed by the post-Base index (
Section 3.2.6) of the matching field line, represented as an integer with a 4-bit prefix; see
Section 4.1.1.
A literal field line with name reference representation encodes a field line where the field name matches the field name of an entry in the static table or the field name of an entry in the dynamic table with an absolute index less than the value of the Base.
0 1 2 3 4 5 6 7
+---+---+---+---+---+---+---+---+
| 0 | 1 | N | T |Name Index (4+)|
+---+---+---+---+---------------+
| H | Value Length (7+) |
+---+---------------------------+
| Value String (Length bytes) |
+-------------------------------+
This representation starts with the '01' 2-bit pattern. The following bit, 'N', indicates whether an intermediary is permitted to add this field line to the dynamic table on subsequent hops. When the 'N' bit is set, the encoded field line
MUST always be encoded with a literal representation. In particular, when a peer sends a field line that it received represented as a literal field line with the 'N' bit set, it
MUST use a literal representation to forward this field line. This bit is intended for protecting field values that are not to be put at risk by compressing them; see
Section 7.1 for more details.
The fourth ('T') bit indicates whether the reference is to the static or dynamic table. The 4-bit prefix integer (
Section 4.1.1) that follows is used to locate the table entry for the field name. When T=1, the number represents the static table index; when T=0, the number is the relative index of the entry in the dynamic table.
Only the field name is taken from the dynamic table entry; the field value is encoded as an 8-bit prefix string literal; see
Section 4.1.2.
A literal field line with post-Base name reference representation encodes a field line where the field name matches the field name of a dynamic table entry with an absolute index greater than or equal to the value of the Base.
0 1 2 3 4 5 6 7
+---+---+---+---+---+---+---+---+
| 0 | 0 | 0 | 0 | N |NameIdx(3+)|
+---+---+---+---+---+-----------+
| H | Value Length (7+) |
+---+---------------------------+
| Value String (Length bytes) |
+-------------------------------+
This representation starts with the '0000' 4-bit pattern. The fifth bit is the 'N' bit as described in
Section 4.5.4. This is followed by a post-Base index of the dynamic table entry (
Section 3.2.6) encoded as an integer with a 3-bit prefix; see
Section 4.1.1.
Only the field name is taken from the dynamic table entry; the field value is encoded as an 8-bit prefix string literal; see
Section 4.1.2.
The literal field line with literal name representation encodes a field name and a field value as string literals.
0 1 2 3 4 5 6 7
+---+---+---+---+---+---+---+---+
| 0 | 0 | 1 | N | H |NameLen(3+)|
+---+---+---+---+---+-----------+
| Name String (Length bytes) |
+---+---------------------------+
| H | Value Length (7+) |
+---+---------------------------+
| Value String (Length bytes) |
+-------------------------------+
This representation starts with the '001' 3-bit pattern. The fourth bit is the 'N' bit as described in
Section 4.5.4. The name follows, represented as a 4-bit prefix string literal, then the value, represented as an 8-bit prefix string literal; see
Section 4.1.2.