3. Reference Tables (参考表)
与 HPACK 不同, QPACK 静态表和动态表中的条目是分别寻址的. 以下各节描述如何寻址每个表中的条目.
3.1 Static Table (静态表)
静态表由预定义的字段行列表组成, 每个字段行都有一个随时间固定的索引. 其条目在附录 A 中定义.
静态表中的所有条目都有名称和值. 但是, 值可以为空 (即长度为 0). 每个条目由唯一索引标识.
请注意, QPACK 静态表从 0 开始索引, 而 HPACK 静态表从 1 开始索引.
当解码器在字段行表示中遇到无效的静态表索引时, 它必须 (MUST) 将其视为类型为 QPACK_DECOMPRESSION_FAILED 的连接错误. 如果在编码器流上接收到此索引, 则必须 (MUST) 将其视为类型为 QPACK_ENCODER_STREAM_ERROR 的连接错误.
3.2 Dynamic Table (动态表)
动态表由以先进先出 (First-In, First-Out) 顺序维护的字段行列表组成. QPACK 编码器和解码器共享一个最初为空的动态表. 编码器向动态表添加条目, 并通过编码器流上的指令将它们发送到解码器; 参见第 4.3 节.
动态表可以包含重复条目 (即具有相同名称和相同值的条目). 因此, 解码器禁止 (MUST NOT) 将重复条目视为错误.
动态表条目可以具有空值.
3.2.1 Dynamic Table Size (动态表大小)
动态表的大小是其条目大小的总和.
条目的大小是其名称的字节长度、其值的字节长度以及额外的 32 字节之和. 条目的大小使用其名称和值的长度计算, 而不应用 Huffman 编码.
3.2.2 Dynamic Table Capacity and Eviction (动态表容量和驱逐)
编码器设置动态表的容量, 它作为其大小的上限. 动态表的初始容量为零. 编码器发送具有非零容量的设置动态表容量 (Set Dynamic Table Capacity) 指令 (第 4.3.1 节) 以开始使用动态表.
在将新条目添加到动态表之前, 从动态表末尾驱逐条目, 直到动态表的大小小于或等于 (表容量 - 新条目的大小). 编码器禁止 (MUST NOT) 导致动态表条目被驱逐, 除非该条目是可驱逐的; 参见第 2.1.1 节. 然后将新条目添加到表中. 如果编码器尝试添加大于动态表容量的条目, 则是错误; 解码器必须 (MUST) 将其视为类型为 QPACK_ENCODER_STREAM_ERROR 的连接错误.
新条目可以引用动态表中的条目, 该条目在将此新条目添加到动态表时将被驱逐. 实现需要注意避免在引用的条目从动态表中驱逐之前删除引用的名称或值, 然后再插入新条目.
每当编码器减少动态表容量 (第 4.3.1 节) 时, 从动态表末尾驱逐条目, 直到动态表的大小小于或等于新的表容量. 此机制可用于通过设置容量为 0 来完全清除动态表中的条目, 随后可以恢复.
3.2.3 Maximum Dynamic Table Capacity (最大动态表容量)
为了限制解码器的内存需求, 解码器限制编码器允许为动态表容量设置的最大值. 在 HTTP/3 中, 此限制由解码器发送的 SETTINGS_QPACK_MAX_TABLE_CAPACITY 的值确定; 参见第 5 节. 编码器禁止 (MUST NOT) 设置超过此最大值的动态表容量, 但它可以选择使用较低的动态表容量; 参见第 4.3.1 节.
对于在 HTTP/3 中使用 0-RTT 数据的客户端, 服务器的最大表容量是设置的记忆值, 如果之前未发送该值, 则为零. 当客户端的 0-RTT 设置值为零时, 服务器可以 (MAY) 在其 SETTINGS 帧中将其设置为非零值. 如果记忆值非零, 服务器必须 (MUST) 在其 SETTINGS 帧中发送相同的非零值. 如果它指定任何其他值, 或从 SETTINGS 中省略 SETTINGS_QPACK_MAX_TABLE_CAPACITY, 编码器必须将其视为类型为 QPACK_DECODER_STREAM_ERROR 的连接错误.
对于不使用 0-RTT 数据的客户端 (无论是未尝试 0-RTT 还是被拒绝) 以及所有 HTTP/3 服务器, 最大表容量为 0, 直到编码器处理具有非零 SETTINGS_QPACK_MAX_TABLE_CAPACITY 值的 SETTINGS 帧.
当最大表容量为零时, 编码器禁止 (MUST NOT) 向动态表中插入条目, 并且禁止 (MUST NOT) 在编码器流上发送任何编码器指令.
3.2.4 Absolute Indexing (绝对索引)
每个条目都拥有一个在该条目生命周期内固定的绝对索引. 插入的第一个条目的绝对索引为 0; 索引随每次插入增加一.
3.2.5 Relative Indexing (相对索引)
相对索引从零开始, 并以与绝对索引相反的方向增加. 确定哪个条目具有相对索引 0 取决于引用的上下文.
在编码器指令 (第 4.3 节) 中, 相对索引 0 指的是动态表中最近插入的值. 请注意, 这意味着在解释编码器流上的指令时, 给定相对索引引用的条目将发生变化.
+-----+---------------+-------+
| n-1 | ... | d | Absolute Index (绝对索引)
+ - - +---------------+ - - - +
| 0 | ... | n-d-1 | Relative Index (相对索引)
+-----+---------------+-------+
^ |
| V
Insertion Point Dropping Point
(插入点) (丢弃点)
n = count of entries inserted (插入的条目数)
d = count of entries dropped (丢弃的条目数)
Figure 2: Example Dynamic Table Indexing - Encoder Stream
图 2: 动态表索引示例 - 编码器流
与编码器指令不同, 字段行表示中的相对索引相对于已编码字段区段开头的基准 (Base); 参见第 4.5.1 节. 这确保即使已编码的字段区段和动态表更新乱序处理, 引用也是稳定的.
在字段行表示中, 相对索引 0 指的是绝对索引等于 Base - 1 的条目.
Base
|
V
+-----+-----+-----+-----+-------+
| n-1 | n-2 | n-3 | ... | d | Absolute Index (绝对索引)
+-----+-----+ - +-----+ - +
| 0 | ... | n-d-3 | Relative Index (相对索引)
+-----+-----+-------+
n = count of entries inserted (插入的条目数)
d = count of entries dropped (丢弃的条目数)
In this example, Base = n - 2 (在此示例中)
Figure 3: Example Dynamic Table Indexing - Relative Index in
Representation
图 3: 动态表索引示例 - 表示中的相对索引
3.2.6 Post-Base Indexing (Post-Base 索引)
Post-Base 索引用于字段行表示中绝对索引大于或等于基准的条目, 从绝对索引等于基准的条目的 0 开始, 并以与绝对索引相同的方向增加.
Post-Base 索引允许编码器以单遍方式处理字段区段, 并包含对在处理此 (或其他) 字段区段时添加的条目的引用.
Base
|
V
+-----+-----+-----+-----+-----+
| n-1 | n-2 | n-3 | ... | d | Absolute Index (绝对索引)
+-----+-----+-----+-----+-----+
| 1 | 0 | Post-Base Index
+-----+-----+
n = count of entries inserted (插入的条目数)
d = count of entries dropped (丢弃的条目数)
In this example, Base = n - 2 (在此示例中)
Figure 4: Example Dynamic Table Indexing - Post-Base Index in
Representation
图 4: 动态表索引示例 - 表示中的 Post-Base 索引