Internet Engineering Task Force (IETF) R. Peon
请求评论: 7541 Google, Inc
类别:标准轨道 H. Ruellan
ISSN: 2070-1721 Canon CRF
2015年5月

HPACK:用于 HTTP/2 的头部压缩


摘要

本规范定义了 HPACK,一种用于在 HTTP/2 中高效表示 HTTP 头字段的压缩格式。

本备忘录的状态

这是一个互联网标准轨道文档。

本文档是 Internet Engineering Task Force (IETF) 的产物,代表 IETF 社区的共识。它已通过公开评审并已获 Internet Engineering Steering Group (IESG) 批准发表。有关互联网标准的更多信息,请参见 RFC 5741 第 2 节

有关本文档当前状态、任何勘误以及如何提供反馈的信息,可在 http://www.rfc-editor.org/info/rfc7541 获取。

Copyright Notice

Copyright (c) 2015 IETF Trust and the persons identified as the document authors. All rights reserved.

This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (http://trustee.ietf.org/license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Simplified BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Simplified BSD License.

1. 引言

在 HTTP/1.1(参见 [RFC7230])中,头字段不被压缩。随着网页发展到需要数十到数百个请求,这些请求中冗余的头字段不必要地消耗带宽,从而显著增加延迟。

SPDY [SPDY] 最初通过使用 DEFLATE [DEFLATE] 格式压缩头字段来解决该冗余问题,这被证明在高效表示冗余头字段方面非常有效。然而,这种方法暴露了安全风险,正如 CRIME(Compression Ratio Info-leak Made Easy)攻击所示(参见 [CRIME])。

本规范定义了 HPACK,一种新的压缩器,它消除了冗余头字段,限制了对已知安全攻击的脆弱性,并具有有界的内存需求以供受限环境使用。关于 HPACK 的潜在安全问题请参见 第 7 节

HPACK 格式有意保持简单且不具可扩展性。这两个特性可降低由于实现错误导致互操作性或安全问题的风险。未定义任何可扩展机制;对格式的更改只能通过定义完整替代方案来实现。

1.1. 概述

本规范定义的格式将头字段列表视为一个有序的名称-值对集合,该集合可以包含重复的对。名称和值被视为不透明的八位组序列,头字段的顺序在压缩和解压缩后得到保留。

编码由将头字段映射到索引值的头字段表提供信息。这些头字段表可以在编码或解码新头字段时增量更新。

在编码形式中,头字段要么以字面方式表示,要么作为对头字段表中某个头字段的引用。因此,头字段列表可以使用引用和字面值的混合来编码。

字面值要么直接编码,要么使用静态霍夫曼编码。

编码器负责决定将哪些头字段作为新条目插入头字段表。解码器执行编码器规定的对头字段表的修改,在此过程中重建头字段列表。这使得解码器可以保持简单,并与各种编码器互操作。

说明如何使用这些不同机制表示头字段的示例见 附录 C

1.2. 约定

本文档中关键字 "MUST"、"MUST NOT"、"REQUIRED"、"SHALL"、"SHALL NOT"、"SHOULD"、"SHOULD NOT"、"RECOMMENDED"、"MAY" 和 "OPTIONAL" 应按 RFC 2119 [RFC2119] 中的描述来解释。

所有数值均以网络字节序表示。除非另有说明,值为无符号。字面值根据需要以十进制或十六进制提供。

1.3. 术语

本规范使用下列术语:

Header Field:
一个名称-值对。名称和值都被视为不透明的八位组序列。
Dynamic Table:
动态表(参见 第 2.3.2 节)是一个将存储的头字段与索引值关联的表。该表为动态的,特定于一个编码或解码上下文。
Static Table:
静态表(参见 第 2.3.1 节)是一个静态地将经常出现的头字段与索引值关联的表。该表是有序的、只读的、始终可访问的,并且可以在所有编码或解码上下文之间共享。
Header List:
头列表是一个按顺序排列的头字段集合,它们被一起编码并且可以包含重复的头字段。HTTP/2 头块中包含的完整头字段列表即为头列表。
Header Field Representation:
头字段可以在编码形式中以字面方式或索引方式表示(参见 第 2.4 节)。
Header Block:
一系列有序的头字段表示,解码后生成完整的头列表。

2. 压缩过程概述

本规范未描述编码器的具体算法。相反,它精确定义了解码器应如何操作,允许编码器生成任何该定义允许的编码。

2.1. 头列表排序

HPACK 保留头列表内头字段的顺序。编码器必须根据原始头列表中的顺序在头块中排列头字段表示。解码器必须根据头块中的顺序在解码后的头列表中排列头字段。

2.2. 编码与解码上下文

要解压头块,解码器只需要维护一个作为解码上下文的动态表(参见 第 2.3.2 节)。不需要其他动态状态。

当用于双向通信(例如 HTTP)时,端点维护的编码和解码动态表是完全独立的,即请求和响应的动态表是分开的。

2.3. 索引表

HPACK 使用两张表将头字段与索引关联。静态表(参见 第 2.3.1 节)是预定义的,包含常见的头字段(大多数具有空值)。动态表(参见 第 2.3.2 节)是动态的,编码器可以使用它对在编码头列表中重复出现的头字段建立索引。

这两张表被组合成单一的地址空间以定义索引值(参见 第 2.3.3 节)。

2.3.1. 静态表

静态表由预定义的静态头字段列表组成。其条目在 附录 A 中定义。

2.3.2. 动态表

动态表由按先进先出顺序维护的头字段列表组成。动态表中第一个也是最新的条目位于最低索引处,动态表中最旧的条目位于最高索引处。

动态表初始为空。随着每个头块被解压,条目会被添加。

动态表可以包含重复条目(即具有相同名称和值的条目)。因此,解码器不得将重复条目视为错误。

编码器决定如何更新动态表,因此可以控制动态表使用的内存量。为限制解码器的内存需求,动态表的大小是严格有界的(参见 第 4.2 节)。

解码器在处理头字段表示列表期间更新动态表(参见 第 3.2 节)。

2.3.3. 索引地址空间

静态表和动态表被组合成单一的索引地址空间。

介于 1 和静态表长度(包含)之间的索引引用静态表中的元素(参见 第 2.3.1 节)。

严格大于静态表长度的索引引用动态表中的元素(参见 第 2.3.2 节)。应从该索引中减去静态表的长度以找到动态表中的索引。

严格大于两张表长度之和的索引必须被视为解码错误。

对于静态表大小为 s 且动态表大小为 k 的情况,下图显示了整个有效的索引地址空间。

        <----------  Index Address Space ---------->
        <-- Static  Table -->  <-- Dynamic Table -->
        +---+-----------+---+  +---+-----------+---+
        | 1 |    ...    | s |  |s+1|    ...    |s+k|
        +---+-----------+---+  +---+-----------+---+
                               ^                   |
                               |                   V
                        Insertion Point      Dropping Point

图 1:索引地址空间

2.4. 头字段表示

编码的头字段可以表示为索引或字面值。

索引表示将头字段定义为对静态表或动态表中条目的引用(参见 第 6.1 节)。

字面表示通过指定名称和值来定义头字段。头字段名称可以以字面方式表示,也可以作为对静态表或动态表中某个条目的引用。头字段值以字面方式表示。

定义了三种不同的字面表示:

  • 将头字段作为新条目添加到动态表开头的字面表示(参见 第 6.2.1 节)。
  • 不将头字段添加到动态表的字面表示(参见 第 6.2.2 节)。
  • 不将头字段添加到动态表的字面表示,并额外规定该头字段始终使用字面表示,尤其是在中间节点重新编码时(参见 第 6.2.3 节)。该表示旨在保护那些不应因压缩而被置于风险中的头字段值(详见 第 7.1.3 节)。

在选择这些字面表示之一时,可由安全考虑来指导,以保护敏感的头字段值(参见 第 7.1 节)。

头字段名称或头字段值的字面表示可以直接编码八位组序列,也可以使用静态霍夫曼编码(参见 第 5.2 节)。

3. 头块解码

3.1. 头块处理

解码器按顺序处理头块以重建原始头列表。

头块是头字段表示的串联。各种可能的头字段表示在 第 6 节 中描述。

一旦头字段被解码并添加到重建的头列表中,该头字段就不能被移除。添加到头列表中的头字段可以安全地传递给应用程序。

通过将结果头字段传递给应用程序,解码器在除了动态表所需的内存之外,可以实现最小的临时内存占用。

3.2. 头字段表示处理

本节定义了处理头块以获得头列表的过程。为确保解码能成功产生头列表,解码器必须遵守下列规则。

头块中包含的所有头字段表示按其出现的顺序进行处理,如下所述。关于各种头字段表示的格式细节和一些附加处理说明见 第 6 节

一个 索引表示 包含以下操作:

  • 将静态表或动态表中被引用条目对应的头字段追加到解码后的头列表。

一个 不被添加 到动态表的 字面表示 包含以下操作:

  • 将该头字段追加到解码后的头列表。

一个被 添加 到动态表的 字面表示 包含以下操作:

  • 将该头字段追加到解码后的头列表。
  • 将该头字段插入到动态表的开头。该插入可能导致动态表中先前条目的逐出(参见 第 4.4 节)。

4. 动态表管理

为限制解码器端的内存需求,动态表的大小受到约束。

4.1. 计算表大小

动态表的大小为其各条目大小之和。

一个条目的大小为其名称的字节长度(见 第 5.2 节)、其值的字节长度以及 32 的和。

条目的大小使用未应用任何霍夫曼编码的名称和值的长度来计算。

4.2. 最大表大小

使用 HPACK 的协议确定编码器被允许为动态表使用的最大大小。在 HTTP/2 中,该值由 SETTINGS_HEADER_TABLE_SIZE 设置确定(参见 RFC 7540 第 6.5.2 节)。

编码器可以选择使用低于该最大值的容量(参见 第 6.3 节),但所选大小必须小于或等于协议设定的最大值。

对动态表最大大小的更改通过动态表大小更新来表示(参见 第 6.3 节)。该动态表大小更新必须在动态表大小更改后第一个头块的开头进行。在 HTTP/2 中,这遵循设置确认(参见 RFC 7540 第 6.5.3 节)。

在两次头块传输之间可以发生多个最大表大小的更新。如果在此区间内多次更改此大小,则必须在一次动态表大小更新中通告该区间内出现的最小最大表大小。最终的最大大小始终会被通告,最多导致两次动态表大小更新。这可确保解码器能够基于动态表大小的减少执行逐出(参见 第 4.3 节)。

该机制可用于通过将最大大小设置为 0 完全清除动态表中的条目,之后可以恢复该大小。

4.3. 动态表大小更改时的条目逐出

每当动态表的最大大小被减小时,将从动态表末端逐出条目,直到动态表的大小小于或等于最大大小为止。

4.4. 添加新条目时的条目逐出

在将新条目添加到动态表之前,会从动态表末端逐出条目,直到动态表的大小小于或等于(最大大小 - 新条目大小),或者直到表为空。

如果新条目的大小小于或等于最大大小,则该条目将被添加到表中。尝试添加大于最大大小的条目并不是错误;尝试添加超过最大大小的条目会导致表中所有现有条目被清空,并导致表变为空。

一个新条目可以引用动态表中在添加该新条目时将被逐出的某个条目的名称。实现应谨慎,避免在插入新条目之前删除被引用的名称(如果被引用的条目在插入新条目之前已被逐出)。

5. 基本类型表示

HPACK 编码使用两种基本类型:无符号可变长度整数和八位组字符串。

5.1. 整数表示

整数用于表示名称索引、头字段索引或字符串长度。整数表示可以从八位组的任意位置开始。为了允许优化处理,整数表示总是在八位组的末端结束。

一个整数由两部分表示:填充当前八位组的前缀和一个可选的八位组列表(当整数值无法装入前缀时使用)。前缀的位数(称为 N)是整数表示的一个参数。

如果整数值足够小,即严格小于 2N-1,则该值编码在 N 位前缀内。

  0   1   2   3   4   5   6   7
+---+---+---+---+---+---+---+---+
| ? | ? | ? |       Value       |
+---+---+---+-------------------+

图 2:在前缀内编码的整数值(示例 N = 5)

否则,前缀的所有位都被置为 1,并且该值减去 2N-1 后使用一个或多个八位组来编码。每个八位组的最高位用作继续标志:除列表中的最后一个八位组外,该位都设置为 1。八位组的其余位用于编码减小后的值。

  0   1   2   3   4   5   6   7
+---+---+---+---+---+---+---+---+
| ? | ? | ? | 1   1   1   1   1 |
+---+---+---+-------------------+
| 1 |    Value-(2^N-1) LSB      |
+---+---------------------------+
               ...
+---+---------------------------+
| 0 |    Value-(2^N-1) MSB      |
+---+---------------------------+

图 3:在前缀后编码的整数值(示例 N = 5)

从八位组列表中解码整数值时,首先将列表中八位组的顺序反转。然后,对于每个八位组,移除其最高位。将八位组的其余位连接起来,并将结果值增加 2N-1 以获得整数值。

前缀大小 N 始终在 1 到 8 位之间。开始于八位组边界的整数将具有 8 位前缀。

表示整数 I 的伪代码如下:

if I < 2^N - 1, encode I on N bits
else
    encode (2^N - 1) on N bits
    I = I - (2^N - 1)
    while I >= 128
         encode (I % 128 + 128) on 8 bits
         I = I / 128
    encode I on 8 bits

解码整数 I 的伪代码如下:

decode I from the next N bits
if I < 2^N - 1, return I
else
    M = 0
    repeat
        B = next octet
        I = I + (B & 127) * 2^M
        M = M + 7
    while B & 128 == 128
    return I

关于整数编码的示例见 附录 C.1

该整数表示允许任意大小的值。编码器也可能发送大量的零值,这会浪费八位组并可能被用来溢出整数值。超过实现限制(无论是值或八位组长度)的整数编码必须被视为解码错误。可以针对整数的不同用途根据实现约束设置不同的限制。

5.2. 字符串字面量表示

头字段名称和头字段值可以表示为字符串字面量。字符串字面量编码为一系列八位组,要么直接编码字面量的八位组,要么使用霍夫曼码(参见 HUFFMAN)。

  0   1   2   3   4   5   6   7
+---+---+---+---+---+---+---+---+
| H |    String Length (7+)     |
+---+---------------------------+
|  String Data (Length octets)  |
+-------------------------------+

图 4:字符串字面量表示

字符串字面量表示包含以下字段:

H:
一个一位标志 H,指示字符串的八位组是否为霍夫曼编码。
String Length:
用于编码字符串字面量的八位组数,使用带有 7 位前缀的整数编码(见 第 5.1 节)。
String Data:
字符串字面量的编码数据。如果 H 为 '0',则编码数据为字符串字面量的原始八位组;如果 H 为 '1',则编码数据为字符串字面量的霍夫曼编码。

使用霍夫曼编码的字符串字面量采用 附录 B 中定义的霍夫曼码进行编码(请求示例见 附录 C.4,响应示例见 附录 C.6)。编码数据是对应于字符串字面量每个八位组的码的按位串联。

由于霍夫曼编码的数据不总是以八位组边界结束,会在其后插入一些填充,直到下一个八位组边界。为了防止这些填充被误解为字符串字面量的一部分,使用与 EOS(end-of-string)符号对应的码的最高有效位。

在解码时,编码数据末尾的不完整码应被视为填充并丢弃。严格超过 7 位的填充必须被视为解码错误。不对应于 EOS 符号码最高有效位的填充必须被视为解码错误。包含 EOS 符号的霍夫曼编码字符串字面量必须被视为解码错误。

6. 二进制格式

本节描述了各类头字段表示以及动态表大小更新指令的详细格式。

6.1. 索引头字段表示

索引头字段表示标识静态表或动态表中的一个条目(见 第 2.3 节)。

索引头字段表示会导致头字段被追加到解码后的头列表,如 第 3.2 节 所述。

  0   1   2   3   4   5   6   7
+---+---+---+---+---+---+---+---+
| 1 |        Index (7+)         |
+---+---------------------------+

图 5:索引头字段

索引头字段以 '1' 的 1 位模式开始,随后是匹配头字段的索引,该索引使用带 7 位前缀的整数表示(见 第 5.1 节)。

索引值 0 不被使用。如果在索引头字段表示中发现 0,必须将其视为解码错误。

6.2. 字面头字段表示

字面头字段表示包含一个字面头字段值。头字段名称要么以字面形式提供,要么通过引用现有表条目提供,该条目可以来自静态表或动态表(见 第 2.3 节)。

本规范定义了三种字面头字段表示形式:带索引、不带索引和永不索引。

6.2.1. 带增量索引的字面头字段

带增量索引的字面头字段表示会将头字段追加到解码后的头列表并将其作为新条目插入动态表。

  0   1   2   3   4   5   6   7
+---+---+---+---+---+---+---+---+
| 0 | 1 |      Index (6+)       |
+---+---+-----------------------+
| H |     Value Length (7+)     |
+---+---------------------------+
| Value String (Length octets)  |
+-------------------------------+

图 6:带增量索引的字面头字段 — 索引名称

  0   1   2   3   4   5   6   7
+---+---+---+---+---+---+---+---+
| 0 | 1 |           0           |
+---+---+-----------------------+
| H |     Name Length (7+)      |
+---+---------------------------+
|  Name String (Length octets)  |
+---+---------------------------+
| H |     Value Length (7+)     |
+---+---------------------------+
| Value String (Length octets)  |
+-------------------------------+

图 7:带增量索引的字面头字段 — 新名称

带增量索引的字面头字段表示以 '01' 的 2 位模式开始。

如果头字段名称与静态表或动态表中某个条目的头字段名称匹配,则可以使用该条目的索引来表示名称。在这种情况下,该索引用带 6 位前缀的整数表示(见 第 5.1 节)。该值始终非零。

否则,头字段名称表示为字符串字面量(见 第 5.2 节)。此情况下用值 0 代替 6 位索引,随后跟随头字段名称。

任一形式的头字段名称表示后面都跟随作为字符串字面量表示的头字段值(见 第 5.2 节)。

6.2.2. 不带索引的字面头字段

不带索引的字面头字段表示会将头字段追加到解码后的头列表而不更改动态表。

  0   1   2   3   4   5   6   7
+---+---+---+---+---+---+---+---+
| 0 | 0 | 0 | 0 |  Index (4+)   |
+---+---+-----------------------+
| H |     Value Length (7+)     |
+---+---------------------------+
| Value String (Length octets)  |
+-------------------------------+

图 8:不带索引的字面头字段 — 索引名称

  0   1   2   3   4   5   6   7
+---+---+---+---+---+---+---+---+
| 0 | 0 | 0 | 0 |       0       |
+---+---+-----------------------+
| H |     Name Length (7+)      |
+---+---------------------------+
|  Name String (Length octets)  |
+---+---------------------------+
| H |     Value Length (7+)     |
+---+---------------------------+
| Value String (Length octets)  |
+-------------------------------+

图 9:不带索引的字面头字段 — 新名称

不带索引的字面头字段表示以 '0000' 的 4 位模式开始。

如果头字段名称与静态表或动态表中某个条目的头字段名称匹配,则可以使用该条目的索引来表示名称。在这种情况下,该索引用带 4 位前缀的整数表示(见 第 5.1 节)。该值始终非零。

否则,头字段名称表示为字符串字面量(见 第 5.2 节)。此情况下用值 0 代替 4 位索引,随后跟随头字段名称。

任一形式的头字段名称表示后面都跟随作为字符串字面量表示的头字段值(见 第 5.2 节)。

6.2.3. 永不索引的字面头字段

永不索引的字面头字段表示会将头字段追加到解码后的头列表而不更改动态表。中间节点必须对该头字段使用相同的表示进行编码。

  0   1   2   3   4   5   6   7
+---+---+---+---+---+---+---+---+
| 0 | 0 | 0 | 1 |  Index (4+)   |
+---+---+-----------------------+
| H |     Value Length (7+)     |
+---+---------------------------+
| Value String (Length octets)  |
+-------------------------------+

图 10:永不索引的字面头字段 — 索引名称

  0   1   2   3   4   5   6   7
+---+---+---+---+---+---+---+---+
| 0 | 0 | 0 | 1 |       0       |
+---+---+-----------------------+
| H |     Name Length (7+)      |
+---+---------------------------+
|  Name String (Length octets)  |
+---+---------------------------+
| H |     Value Length (7+)     |
+---+---------------------------+
| Value String (Length octets)  |
+-------------------------------+

图 11:永不索引的字面头字段 — 新名称

永不索引的字面头字段表示以 '0001' 的 4 位模式开始。

当一个头字段被表示为永不索引的字面头字段时,它必须始终使用此特定的字面表示进行编码。尤其是,当对等方收到以永不索引字面表示形式接收的头字段并转发该头字段时,必须使用相同的表示。

该表示旨在保护那些不应因压缩而被置于风险中的头字段值(详细见 第 7.1 节)。

该表示的编码与不带索引的字面头字段相同(见 第 6.2.2 节)。

6.3. 动态表大小更新

动态表大小更新用于表示动态表大小的更改。

  0   1   2   3   4   5   6   7
+---+---+---+---+---+---+---+---+
| 0 | 0 | 1 |   Max size (5+)   |
+---+---------------------------+

图 12:最大动态表大小更改

动态表大小更新以 '001' 的 3 位模式开始,随后是新的最大大小,使用带 5 位前缀的整数表示(见 第 5.1 节)。

新的最大大小必须小于或等于使用 HPACK 的协议确定的限制。超过此限制的值必须被视为解码错误。在 HTTP/2 中,该限制是从解码器收到并由编码器确认的 SETTINGS_HEADER_TABLE_SIZE 参数的最后值(参见 RFC 7540 第 6.5.2 节)。

减小动态表的最大大小可能导致条目被逐出(参见 第 4.3 节)。

7. 安全性考虑

本节描述了 HPACK 可能存在的若干安全关注点:

  • 利用压缩作为基于长度的探测oracle,以验证被压缩到共享压缩上下文中的秘密猜测。
  • 由于耗尽解码器的处理或内存能力而引起的拒绝服务。

7.1. 探测动态表状态

HPACK 通过利用诸如 HTTP 之类协议中固有的冗余来缩短头字段编码的长度。其最终目标是减少发送 HTTP 请求或响应所需的数据量。

用于编码头字段的压缩上下文可以被能够定义要编码并传输的头字段并观测这些字段编码后长度的攻击者探测到。当攻击者既能定义要编码的字段又能观测到它们的编码长度时,攻击者可以自适应地修改请求以确认对动态表状态的猜测。如果某个猜测被压缩为更短的长度,攻击者即可通过观测编码长度推断该猜测为真。

即使在传输层安全(TLS)协议之上也可能发生此类情况(参见 [TLS12]),因为 TLS 虽然为内容提供了机密性保护,但对内容长度仅提供有限的保护。

CRIME [CRIME] 这样的攻击展示了这些一般攻击能力的存在。该具体攻击利用了 DEFLATE [DEFLATE] 基于前缀匹配移除冗余的事实,从而允许攻击者逐字符确认猜测,将指数时间攻击降为线性时间攻击。

7.1.1. 适用于 HPACK 和 HTTP

HPACK 通过强制猜测必须匹配整个头字段值而不是单个字符来缓解(但并不完全阻止)基于 CRIME [CRIME] 建模的攻击。攻击者只能得知猜测是否正确,因此被简化为对头字段值的暴力猜测。

因此,恢复特定头字段值的可行性取决于值的熵。高熵值不太可能被成功恢复,而低熵值仍然易受攻击。

只要两个互不信任的实体控制被放置到单个 HTTP/2 连接上的请求或响应,此类攻击就可能发生。如果共享的 HPACK 压缩器允许一个实体向动态表添加条目而另一个实体访问这些条目,则该表的状态可以被学习到。

当中间节点发生下列任一情况时,会出现来自互不信任实体的请求或响应:

  • 在单个连接上向源服务器发送来自多个客户端的请求,或
  • 将来自多个源服务器的响应放到发往客户端的共享连接上。

浏览器还需要假设由不同 web origins [ORIGIN] 在同一连接上发起的请求是由互不信任的实体发起的。

7.1.2. 缓解措施

需要对头字段保密的 HTTP 用户可以使用具有足够熵的值以使猜测不可行。然而,这作为通用解决方案不切实际,因为它强制所有 HTTP 用户采取措施来缓解攻击,并对 HTTP 的使用施加了新的约束。

实现 HPACK 的一方可以通过约束如何应用压缩来限制对动态表探测的可能性,而非对所有 HTTP 用户施加约束。

理想的解决方案是基于构造头字段的实体对动态表的访问进行隔离。被添加到表中的头字段值应归属于某个实体,并且只有创建了特定值的实体才能提取该值。

为提高该选项的压缩性能,某些条目可能被标记为公开的。例如,浏览器可能会在所有请求中公开 Accept-Encoding 头字段的值。

缺乏对头字段来源良好了解的编码器可能会对具有许多不同值的头字段引入惩罚措施,使得大量猜测尝试导致该头字段在未来消息中不再与动态表条目比较,从而有效地阻止进一步的猜测。

这一响应可能与头字段值的长度成反比。对较短值更快或更高概率地标记为不再使用动态表,可能比对较长值更早发生。

7.1.3. 永不索引的字面头字段

实现也可以选择通过不压缩敏感头字段而用字面量编码其值来保护它们。

拒绝为某个头字段生成索引表示仅在所有跳数上都避免压缩时才有效。永不索引的字面表示(参见 第 6.2.3 节)可用于向中间节点表明某个值是有意以字面方式发送的。

当一个值使用永不索引的字面表示时,中间节点不得用会对其进行索引的其他表示重新编码该值。如果使用 HPACK 进行重新编码,必须使用永不索引的字面表示。

对某个头字段使用永不索引字面表示的选择取决于多个因素。由于 HPACK 并不能防止对整个头字段值的猜测,短或低熵值更容易被对手恢复。因此,编码器可能选择不对低熵值建立索引。

编码器也可能选择不对被视为高度有价值或对恢复敏感的头字段值进行索引,例如 Cookie 或 Authorization 头字段。

相反,编码器可能更愿意对那些即使被暴露也几乎没有价值的头字段值进行索引。例如,User-Agent 头字段通常在请求之间不常改变并且发送给任意服务器。在这种情况下,确认特定的 User-Agent 值已被使用并没有太大价值。

请注意,决定使用永不索引字面表示的这些标准会随着新攻击的发现而演进。

7.2. 静态霍夫曼编码

当前尚无已知针对静态霍夫曼编码的攻击。一项研究表明使用静态霍夫曼编码表会产生信息泄露;然而,该研究得出结论称攻击者无法利用该信息泄露来恢复任何有意义的信息(参见 [PETAL])。

7.3. 内存消耗

攻击者可以尝试使端点耗尽其内存。HPACK 的设计能限制端点分配的峰值和状态内存量。

压缩器使用的内存量由使用 HPACK 的协议通过定义动态表的最大大小来限制。在 HTTP/2 中,该值由解码器通过设置参数 SETTINGS_HEADER_TABLE_SIZE 控制(参见 第 6.5.2 节)。该限制考虑了动态表中存储数据的大小以及用于开销的小幅度配额。

解码器可以通过为动态表设置适当的最大大小来限制所使用的状态内存量。在 HTTP/2 中,这通过为 SETTINGS_HEADER_TABLE_SIZE 参数设置适当的值来实现。编码器可以通过通告比解码器允许值更低的动态表大小来限制其使用的状态内存量(参见 第 6.3 节)。

编码器或解码器消耗的临时内存量可以通过顺序处理头字段来限制。实现不需要保留完整的头字段列表。然而请注意,应用可能由于其他原因需要保留完整的头列表;尽管 HPACK 不强制此类保留,但应用约束可能使其必要。

7.4. 实现限制

HPACK 的实现需要确保过大的整数值、过长的整数编码或过长的字符串字面量不会导致安全弱点。

实现必须为其接受的整数值以及其接受的编码长度设置限制(参见 第 5.1 节)。同样,也必须为其接受的字符串字面量长度设置限制(参见 第 5.2 节)。

8. 参考文献

8.1. 规范性参考文献

[HTTP2]
Belshe, M., Peon, R., 和 M. Thomson, 编., “超文本传输协议 版本 2 (HTTP/2)”,RFC 7540,DOI 10.17487/RFC7540, 2015 年 5 月, <http://www.rfc-editor.org/info/rfc7540>.
[RFC2119]
Bradner, S., “在 RFC 中表示要求级别的关键词用法”, BCP 14, RFC 2119, DOI 10.17487/RFC2119, 1997 年 3 月, <http://www.rfc-editor.org/info/rfc2119>.
[RFC7230]
Fielding, R., 编. 和 J. Reschke, 编., “超文本传输协议 (HTTP/1.1): 消息语法与路由”, RFC 7230, DOI 10.17487/RFC7230, 2014 年 6 月, <http://www.rfc-editor.org/info/rfc7230>.

8.2. 说明性参考文献

[CANONICAL]
Schwartz, E. 和 B. Kallick, “生成规范前缀编码”, Communications of the ACM, 第 7 卷 第 3 期, 第 166-169 页, 1964 年 3 月, <https://dl.acm.org/citation.cfm?id=363991>.
[CRIME]
Wikipedia, “CRIME”, 2015 年 5 月, <http://en.wikipedia.org/w/index.php?title=CRIME&oldid=660948120>.
[DEFLATE]
Deutsch, P., “DEFLATE 压缩数据格式规范 1.3 版”, RFC 1951, DOI 10.17487/RFC1951, 1996 年 5 月, <http://www.rfc-editor.org/info/rfc1951>.
[HUFFMAN]
Huffman, D., “构造最小冗余码的方法”, Proceedings of the Institute of Radio Engineers, 第 40 卷第 9 期, 第 1098-1101 页, 1952 年 9 月, <http://ieeexplore.ieee.org/xpl/articleDetails.jsp?arnumber=4051119>.
[ORIGIN]
Barth, A., “Web 原点概念”, RFC 6454, DOI 10.17487/RFC6454, 2011 年 12 月, <http://www.rfc-editor.org/info/rfc6454>.
[PETAL]
Tan, J. 和 J. Nahata, “PETAL: 预设编码表信息泄露”, 2013 年 4 月, <http://www.pdl.cmu.edu/PDL-FTP/associated/CMU-PDL-13-106.pdf>.
[SPDY]
Belshe, M. 和 R. Peon, “SPDY 协议”, 进行中的工作, draft-mbelshe-httpbis-spdy-00, 2012 年 2 月.
[TLS12]
Dierks, T. 和 E. Rescorla, “传输层安全 (TLS) 协议 1.2 版”, RFC 5246, DOI 10.17487/RFC5246, 2008 年 8 月, <http://www.rfc-editor.org/info/rfc5246>.

附录 A. 静态表定义

静态表(参见 第 2.3.1 节)由预定义且不可更改的头字段列表组成。

静态表是根据流行网站中最常用的头字段创建的,并加入了 HTTP/2 特定的伪头字段(参见 RFC 7540 第 8.1.2.1 节)。对于具有少数常见值的头字段,为每个常见值增加了一个条目。对于其他头字段,则添加了一个值为空的条目。

表 1 列出了构成静态表的预定义头字段,并给出了每个条目的索引。

表 1:静态表条目
索引 头字段名 头字段值
1 :authority
2 :method GET
3 :method POST
4 :path /
5 :path /index.html
6 :scheme http
7 :scheme https
8 :status 200
9 :status 204
10 :status 206
11 :status 304
12 :status 400
13 :status 404
14 :status 500
15 accept-charset
16 accept-encoding gzip, deflate
17 accept-language
18 accept-ranges
19 accept
20 access-control-allow-origin
21 age
22 allow
23 authorization
24 cache-control
25 content-disposition
26 content-encoding
27 content-language
28 content-length
29 content-location
30 content-range
31 content-type
32 cookie
33 date
34 etag
35 expect
36 expires
37 from
38 host
39 if-match
40 if-modified-since
41 if-none-match
42 if-range
43 if-unmodified-since
44 last-modified
45 link
46 location
47 max-forwards
48 proxy-authenticate
49 proxy-authorization
50 range
51 referer
52 refresh
53 retry-after
54 server
55 set-cookie
56 strict-transport-security
57 transfer-encoding
58 user-agent
59 vary
60 via
61 www-authenticate

附录 B. 霍夫曼编码

以下霍夫曼编码用于在对字符串字面量进行霍夫曼编码时(参见 第 5.2 节)。

该霍夫曼编码是基于对大量 HTTP 头部样本统计生成的。它是一个规范霍夫曼编码(参见 [CANONICAL]),并经过一些调整以确保没有符号具有唯一的码长。

表中的每一行定义用于表示某个符号的编码:

sym:
要表示的符号。它是一个八位组的十进制值,可能附带其 ASCII 表示。特定符号 "EOS" 用于指示字符串字面量的结束。
code as bits:
以位序列表示并按最高有效位(MSB)对齐的符号的霍夫曼码(以二进制整数形式)。
code as hex:
以十六进制整数表示并按最低有效位(LSB)对齐的符号的霍夫曼码。
len:
表示该符号的码的位数。

例如,符号 47(对应 ASCII 字符 "/")的码由 6 位 "0", "1", "1", "0", "0", "0" 组成。这对应于以 6 位编码的十六进制值 0x18。

                                                     code
                       code as bits                 as hex   len
     sym              aligned to MSB                aligned   in
                                                    to LSB   bits
    (  0)  |11111111|11000                             1ff8  [13]
    (  1)  |11111111|11111111|1011000                7fffd8  [23]
    (  2)  |11111111|11111111|11111110|0010         fffffe2  [28]
    (  3)  |11111111|11111111|11111110|0011         fffffe3  [28]
    (  4)  |11111111|11111111|11111110|0100         fffffe4  [28]
    (  5)  |11111111|11111111|11111110|0101         fffffe5  [28]
    (  6)  |11111111|11111111|11111110|0110         fffffe6  [28]
    (  7)  |11111111|11111111|11111110|0111         fffffe7  [28]
    (  8)  |11111111|11111111|11111110|1000         fffffe8  [28]
    (  9)  |11111111|11111111|11101010               ffffea  [24]
    ( 10)  |11111111|11111111|11111111|111100      3ffffffc  [30]
    ( 11)  |11111111|11111111|11111110|1001         fffffe9  [28]
    ( 12)  |11111111|11111111|11111110|1010         fffffea  [28]
    ( 13)  |11111111|11111111|11111111|111101      3ffffffd  [30]
    ( 14)  |11111111|11111111|11111110|1011         fffffeb  [28]
    ( 15)  |11111111|11111111|11111110|1100         fffffec  [28]
    ( 16)  |11111111|11111111|11111110|1101         fffffed  [28]
    ( 17)  |11111111|11111111|11111110|1110         fffffee  [28]
    ( 18)  |11111111|11111111|11111110|1111         fffffef  [28]
    ( 19)  |11111111|11111111|11111111|0000         ffffff0  [28]
    ( 20)  |11111111|11111111|11111111|0001         ffffff1  [28]
    ( 21)  |11111111|11111111|11111111|0010         ffffff2  [28]
    ( 22)  |11111111|11111111|11111111|111110      3ffffffe  [30]
    ( 23)  |11111111|11111111|11111111|0011         ffffff3  [28]
    ( 24)  |11111111|11111111|11111111|0100         ffffff4  [28]
    ( 25)  |11111111|11111111|11111111|0101         ffffff5  [28]
    ( 26)  |11111111|11111111|11111111|0110         ffffff6  [28]
    ( 27)  |11111111|11111111|11111111|0111         ffffff7  [28]
    ( 28)  |11111111|11111111|11111111|1000         ffffff8  [28]
    ( 29)  |11111111|11111111|11111111|1001         ffffff9  [28]
    ( 30)  |11111111|11111111|11111111|1010         ffffffa  [28]
    ( 31)  |11111111|11111111|11111111|1011         ffffffb  [28]
' ' ( 32)  |010100                                       14  [ 6]
'!' ( 33)  |11111110|00                                 3f8  [10]
'"' ( 34)  |11111110|01                                 3f9  [10]
'#' ( 35)  |11111111|1010                               ffa  [12]
'$' ( 36)  |11111111|11001                             1ff9  [13]
'%' ( 37)  |010101                                       15  [ 6]
'&' ( 38)  |11111000                                     f8  [ 8]
''' ( 39)  |11111111|010                                7fa  [11]
'(' ( 40)  |11111110|10                                 3fa  [10]
')' ( 41)  |11111110|11                                 3fb  [10]
'*' ( 42)  |11111001                                     f9  [ 8]
'+' ( 43)  |11111111|011                                7fb  [11]
',' ( 44)  |11111010                                     fa  [ 8]
'-' ( 45)  |010110                                       16  [ 6]
'.' ( 46)  |010111                                       17  [ 6]
'/' ( 47)  |011000                                       18  [ 6]
'0' ( 48)  |00000                                         0  [ 5]
'1' ( 49)  |00001                                         1  [ 5]
'2' ( 50)  |00010                                         2  [ 5]
'3' ( 51)  |011001                                       19  [ 6]
'4' ( 52)  |011010                                       1a  [ 6]
'5' ( 53)  |011011                                       1b  [ 6]
'6' ( 54)  |011100                                       1c  [ 6]
'7' ( 55)  |011101                                       1d  [ 6]
'8' ( 56)  |011110                                       1e  [ 6]
'9' ( 57)  |011111                                       1f  [ 6]
':' ( 58)  |1011100                                      5c  [ 7]
';' ( 59)  |11111011                                     fb  [ 8]
'<' ( 60)  |11111111|1111100                           7ffc  [15]
'=' ( 61)  |100000                                       20  [ 6]
'>' ( 62)  |11111111|1011                               ffb  [12]
'?' ( 63)  |11111111|00                                 3fc  [10]
'@' ( 64)  |11111111|11010                             1ffa  [13]
'A' ( 65)  |100001                                       21  [ 6]
'B' ( 66)  |1011101                                      5d  [ 7]
'C' ( 67)  |1011110                                      5e  [ 7]
'D' ( 68)  |1011111                                      5f  [ 7]
'E' ( 69)  |1100000                                      60  [ 7]
'F' ( 70)  |1100001                                      61  [ 7]
'G' ( 71)  |1100010                                      62  [ 7]
'H' ( 72)  |1100011                                      63  [ 7]
'I' ( 73)  |1100100                                      64  [ 7]
'J' ( 74)  |1100101                                      65  [ 7]
'K' ( 75)  |1100110                                      66  [ 7]
'L' ( 76)  |1100111                                      67  [ 7]
'M' ( 77)  |1101000                                      68  [ 7]
'N' ( 78)  |1101001                                      69  [ 7]
'O' ( 79)  |1101010                                      6a  [ 7]
'P' ( 80)  |1101011                                      6b  [ 7]
'Q' ( 81)  |1101100                                      6c  [ 7]
'R' ( 82)  |1101101                                      6d  [ 7]
'S' ( 83)  |1101110                                      6e  [ 7]
'T' ( 84)  |1101111                                      6f  [ 7]
'U' ( 85)  |1110000                                      70  [ 7]
'V' ( 86)  |1110001                                      71  [ 7]
'W' ( 87)  |1110010                                      72  [ 7]
'X' ( 88)  |11111100                                     fc  [ 8]
'Y' ( 89)  |1110011                                      73  [ 7]
'Z' ( 90)  |11111101                                     fd  [ 8]
'[' ( 91)  |11111111|11011                             1ffb  [13]
'\' ( 92)  |11111111|11111110|000                     7fff0  [19]
']' ( 93)  |11111111|11100                             1ffc  [13]
'^' ( 94)  |11111111|111100                            3ffc  [14]
'_' ( 95)  |100010                                       22  [ 6]
'`' ( 96)  |11111111|1111101                           7ffd  [15]
'a' ( 97)  |00011                                         3  [ 5]
'b' ( 98)  |100011                                       23  [ 6]
'c' ( 99)  |00100                                         4  [ 5]
'd' (100)  |100100                                       24  [ 6]
'e' (101)  |00101                                         5  [ 5]
'f' (102)  |100101                                       25  [ 6]
'g' (103)  |100110                                       26  [ 6]
'h' (104)  |100111                                       27  [ 6]
'i' (105)  |00110                                         6  [ 5]
'j' (106)  |1110100                                      74  [ 7]
'k' (107)  |1110101                                      75  [ 7]
'l' (108)  |101000                                       28  [ 6]
'm' (109)  |101001                                       29  [ 6]
'n' (110)  |101010                                       2a  [ 6]
'o' (111)  |00111                                         7  [ 5]
'p' (112)  |101011                                       2b  [ 6]
'q' (113)  |1110110                                      76  [ 7]
'r' (114)  |101100                                       2c  [ 6]
's' (115)  |01000                                         8  [ 5]
't' (116)  |01001                                         9  [ 5]
'u' (117)  |101101                                       2d  [ 6]
'v' (118)  |1110111                                      77  [ 7]
'w' (119)  |1111000                                      78  [ 7]
'x' (120)  |1111001                                      79  [ 7]
'y' (121)  |1111010                                      7a  [ 7]
'z' (122)  |1111011                                      7b  [ 7]
'{' (123)  |11111111|1111110                           7ffe  [15]
'|' (124)  |11111111|100                                7fc  [11]
'}' (125)  |11111111|111101                            3ffd  [14]
'~' (126)  |11111111|11101                             1ffd  [13]
    (127)  |11111111|11111111|11111111|1100         ffffffc  [28]
    (128)  |11111111|11111110|0110                    fffe6  [20]
    (129)  |11111111|11111111|010010                 3fffd2  [22]
    (130)  |11111111|11111110|0111                    fffe7  [20]
    (131)  |11111111|11111110|1000                    fffe8  [20]
    (132)  |11111111|11111111|010011                 3fffd3  [22]
    (133)  |11111111|11111111|010100                 3fffd4  [22]
    (134)  |11111111|11111111|010101                 3fffd5  [22]
    (135)  |11111111|11111111|1011001                7fffd9  [23]
    (136)  |11111111|11111111|010110                 3fffd6  [22]
    (137)  |11111111|11111111|1011010                7fffda  [23]
    (138)  |11111111|11111111|1011011                7fffdb  [23]
    (139)  |11111111|11111111|1011100                7fffdc  [23]
    (140)  |11111111|11111111|1011101                7fffdd  [23]
    (141)  |11111111|11111111|1011110                7fffde  [23]
    (142)  |11111111|11111111|11101011               ffffeb  [24]
    (143)  |11111111|11111111|1011111                7fffdf  [23]
    (144)  |11111111|11111111|11101100               ffffec  [24]
    (145)  |11111111|11111111|11101101               ffffed  [24]
    (146)  |11111111|11111111|010111                 3fffd7  [22]
    (147)  |11111111|11111111|1100000                7fffe0  [23]
    (148)  |11111111|11111111|11101110               ffffee  [24]
    (149)  |11111111|11111111|1100001                7fffe1  [23]
    (150)  |11111111|11111111|1100010                7fffe2  [23]
    (151)  |11111111|11111111|1100011                7fffe3  [23]
    (152)  |11111111|11111111|1100100                7fffe4  [23]
    (153)  |11111111|11111110|11100                  1fffdc  [21]
    (154)  |11111111|11111111|011000                 3fffd8  [22]
    (155)  |11111111|11111111|1100101                7fffe5  [23]
    (156)  |11111111|11111111|011001                 3fffd9  [22]
    (157)  |11111111|11111111|1100110                7fffe6  [23]
    (158)  |11111111|11111111|1100111                7fffe7  [23]
    (159)  |11111111|11111111|11101111               ffffef  [24]
    (160)  |11111111|11111111|011010                 3fffda  [22]
    (161)  |11111111|11111110|11101                  1fffdd  [21]
    (162)  |11111111|11111110|1001                    fffe9  [20]
    (163)  |11111111|11111111|011011                 3fffdb  [22]
    (164)  |11111111|11111111|011100                 3fffdc  [22]
    (165)  |11111111|11111111|1101000                7fffe8  [23]
    (166)  |11111111|11111111|1101001                7fffe9  [23]
    (167)  |11111111|11111110|11110                  1fffde  [21]
    (168)  |11111111|11111111|1101010                7fffea  [23]
    (169)  |11111111|11111111|011101                 3fffdd  [22]
    (170)  |11111111|11111111|011110                 3fffde  [22]
    (171)  |11111111|11111111|11110000               fffff0  [24]
    (172)  |11111111|11111110|11111                  1fffdf  [21]
    (173)  |11111111|11111111|011111                 3fffdf  [22]
    (174)  |11111111|11111111|1101011                7fffeb  [23]
    (175)  |11111111|11111111|1101100                7fffec  [23]
    (176)  |11111111|11111111|00000                  1fffe0  [21]
    (177)  |11111111|11111111|00001                  1fffe1  [21]
    (178)  |11111111|11111111|100000                 3fffe0  [22]
    (179)  |11111111|11111111|00010                  1fffe2  [21]
    (180)  |11111111|11111111|1101101                7fffed  [23]
    (181)  |11111111|11111111|100001                 3fffe1  [22]
    (182)  |11111111|11111111|1101110                7fffee  [23]
    (183)  |11111111|11111111|1101111                7fffef  [23]
    (184)  |11111111|11111110|1010                    fffea  [20]
    (185)  |11111111|11111111|100010                 3fffe2  [22]
    (186)  |11111111|11111111|100011                 3fffe3  [22]
    (187)  |11111111|11111111|100100                 3fffe4  [22]
    (188)  |11111111|11111111|1110000                7ffff0  [23]
    (189)  |11111111|11111111|100101                 3fffe5  [22]
    (190)  |11111111|11111111|100110                 3fffe6  [22]
    (191)  |11111111|11111111|1110001                7ffff1  [23]
    (192)  |11111111|11111111|11111000|00           3ffffe0  [26]
    (193)  |11111111|11111111|11111000|01           3ffffe1  [26]
    (194)  |11111111|11111111|11111110|1011                    fffeb  [20]
    (195)  |11111111|11111111|11111110|001                     7fff1  [19]
    (196)  |11111111|11111111|11111111|100111                 3fffe7  [22]
    (197)  |11111111|11111111|1110010                7ffff2  [23]
    (198)  |11111111|11111111|101000                 3fffe8  [22]
    (199)  |11111111|11111111|11110110|0            1ffffec  [25]
    (200)  |11111111|11111111|11111000|10           3ffffe2  [26]
    (201)  |11111111|11111111|11111000|11           3ffffe3  [26]
    (202)  |11111111|11111111|11111001|00           3ffffe4  [26]
    (203)  |11111111|11111111|11111011|110          7ffffde  [27]
    (204)  |11111111|11111111|11111011|111          7ffffdf  [27]
    (205)  |11111111|11111111|11111001|01           3ffffe5  [26]
    (206)  |11111111|11111111|11110001               fffff1  [24]
    (207)  |11111111|11111111|11110110|1            1ffffed  [25]
    (208)  |11111111|11111110|010                     7fff2  [19]
    (209)  |11111111|11111111|00011                  1fffe3  [21]
    (210)  |11111111|11111111|11111001|10           3ffffe6  [26]
    (211)  |11111111|11111111|11111100|000          7ffffe0  [27]
    (212)  |11111111|11111111|11111100|001          7ffffe1  [27]
    (213)  |11111111|11111111|11111001|11           3ffffe7  [26]
    (214)  |11111111|11111111|11111100|010          7ffffe2  [27]
    (215)  |11111111|11111111|11110010               fffff2  [24]
    (216)  |11111111|11111111|00100                  1fffe4  [21]
    (217)  |11111111|11111111|00101                  1fffe5  [21]
    (218)  |11111111|11111111|11111010|00           3ffffe8  [26]
    (219)  |11111111|11111111|11111010|01           3ffffe9  [26]
    (220)  |11111111|11111111|11111111|1101         ffffffd  [28]
    (221)  |11111111|11111111|11111100|011          7ffffe3  [27]
    (222)  |11111111|11111111|11111100|100          7ffffe4  [27]
    (223)  |11111111|11111111|11111100|101          7ffffe5  [27]
    (224)  |11111111|11111110|1100                    fffec  [20]
    (225)  |11111111|11111111|11110011               fffff3  [24]
    (226)  |11111111|11111111|11111110|1101                    fffed  [20]
    (227)  |11111111|11111111|00110                  1fffe6  [21]
    (228)  |11111111|11111111|101001                 3fffe9  [22]
    (229)  |11111111|11111111|00111                  1fffe7  [21]
    (230)  |11111111|11111111|01000                  1fffe8  [21]
    (231)  |11111111|11111111|1110011                7ffff3  [23]
    (232)  |11111111|11111111|101010                 3fffea  [22]
    (233)  |11111111|11111111|101011                 3fffeb  [22]
    (234)  |11111111|11111111|11110111|0            1ffffee  [25]
    (235)  |11111111|11111111|11110111|1            1ffffef  [25]
    (236)  |11111111|11111111|11110100               fffff4  [24]
    (237)  |11111111|11111111|11110101               fffff5  [24]
    (238)  |11111111|11111111|11111010|10           3ffffea  [26]
    (239)  |11111111|11111111|1110100                7ffff4  [23]
    (240)  |11111111|11111111|11111010|11           3ffffeb  [26]
    (241)  |11111111|11111111|11111100|110          7ffffe6  [27]
    (242)  |11111111|11111111|11111011|00           3ffffec  [26]
    (243)  |11111111|11111111|11111011|01           3ffffed  [26]
    (244)  |11111111|11111111|11111100|111          7ffffe7  [27]
    (245)  |11111111|11111111|11111101|000          7ffffe8  [27]
    (246)  |11111111|11111111|11111101|001          7ffffe9  [27]
    (247)  |11111111|11111111|11111101|010          7ffffea  [27]
    (248)  |11111111|11111111|11111101|011          7ffffeb  [27]
    (249)  |11111111|11111111|11111111|1110         ffffffe  [28]
    (250)  |11111111|11111111|11111101|100          7ffffec  [27]
    (251)  |11111111|11111111|11111101|101          7ffffed  [27]
    (252)  |11111111|11111111|11111101|110          7ffffee  [27]
    (253)  |11111111|11111111|11111101|111          7ffffef  [27]
    (254)  |11111111|11111111|11111110|000          7fffff0  [27]
    (255)  |11111111|11111111|11111011|10           3ffffee  [26]
EOS (256)  |11111111|11111111|11111111|111111      3fffffff  [30]

附录 C. 示例

本附录包含覆盖整数编码、头字段表示以及请求和响应的整个头字段列表编码的示例,包含使用和不使用霍夫曼编码的情况。

C.1. 整数表示示例

本节详细展示整数值的表示(参见 第 5.1 节)。

C.1.1. 示例 1:使用 5 位前缀编码 10

值 10 使用 5 位前缀进行编码。

  • 10 小于 31(25 - 1),使用 5 位前缀表示。
  0   1   2   3   4   5   6   7
+---+---+---+---+---+---+---+---+
| X | X | X | 0 | 1 | 0 | 1 | 0 |   10 stored on 5 bits
+---+---+---+---+---+---+---+---+

C.1.2. 示例 2:使用 5 位前缀编码 1337

值 I=1337 使用 5 位前缀进行编码。

  • 1337 大于 31(25 - 1)。
    • 5 位前缀被填充为其最大值(31)。
  • I = 1337 - (25 - 1) = 1306。
    • I(1306)大于或等于 128,因此执行 while 循环体:
      • I % 128 == 26
      • 26 + 128 == 154
      • 154 以 8 位编码为:10011010
      • I 被设置为 10(1306 / 128 == 10)
      • I 不再大于或等于 128,因此 while 循环终止。
    • I(现在为 10)以 8 位编码为:00001010。
  • 过程结束。
  0   1   2   3   4   5   6   7
+---+---+---+---+---+---+---+---+
| X | X | X | 1 | 1 | 1 | 1 | 1 |  Prefix = 31, I = 1306
| 1 | 0 | 0 | 1 | 1 | 0 | 1 | 0 |  1306>=128, encode(154), I=1306/128
| 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 |  10<128, encode(10), done
+---+---+---+---+---+---+---+---+

C.1.3. 示例 3:从八位组边界开始编码 42

值 42 从八位组边界开始编码,这意味着使用 8 位前缀。

  • 42 小于 255(28 - 1),使用 8 位前缀表示。
  0   1   2   3   4   5   6   7
+---+---+---+---+---+---+---+---+
| 0 | 0 | 1 | 0 | 1 | 0 | 1 | 0 |   42 stored on 8 bits
+---+---+---+---+---+---+---+---+

C.2. 头字段表示示例

本节展示若干独立的表示示例。

C.2.1. 带索引的字面头字段

该头字段表示使用字面名称和字面值。该头字段被添加到动态表中。

要编码的头列表:

custom-key: custom-header

编码数据的十六进制转储:

400a 6375 7374 6f6d 2d6b 6579 0d63 7573 | @.custom-key.cus
746f 6d2d 6865 6164 6572                | tom-header

解码过程:

40                                      | == Literal indexed ==
0a                                      |   Literal name (len = 10)
6375 7374 6f6d 2d6b 6579                | custom-key
0d                                      |   Literal value (len = 13)
6375 7374 6f6d 2d68 6561 6465 72        | custom-header
                                        | -> custom-key:
                                        |   custom-header

动态表(解码后):

[  1] (s =  55) custom-key: custom-header
      Table size:  55

解码后的头列表:

custom-key: custom-header

C.2.2. 不带索引的字面头字段

该头字段表示使用索引名称和字面值。该头字段不会被添加到动态表中。

要编码的头列表:

:path: /sample/path

编码数据的十六进制转储:

040c 2f73 616d 706c 652f 7061 7468      | ../sample/path

解码过程:

04                                      | == Literal not indexed ==
                                        |   Indexed name (idx = 4)
                                        |     :path
0c                                      |   Literal value (len = 12)
2f73 616d 706c 652f 7061 7468           | /sample/path
                                        | -> :path: /sample/path

动态表(解码后): 空。

解码后的头列表:

:path: /sample/path

C.2.3. 永不索引的字面头字段

该头字段表示使用字面名称和字面值。该头字段不会被添加到动态表,并且在中间节点重新编码时必须使用相同的表示。

要编码的头列表:

password: secret

编码数据的十六进制转储:

1008 7061 7373 776f 7264 0673 6563 7265 | ..password.secre
74                                      | t

解码过程:

10                                      | == Literal never indexed ==
08                                      |   Literal name (len = 8)
7061 7373 776f 7264                     | password
06                                      |   Literal value (len = 6)
7365 6372 6574                          | secret
                                        | -> password: secret

动态表(解码后): 空。

解码后的头列表:

password: secret

C.2.4. 索引头字段

该头字段表示使用来自静态表的索引头字段。

要编码的头列表:

:method: GET

编码数据的十六进制转储:

82                                      | .

解码过程:

82                                      | == Indexed - Add ==
                                        |   idx = 2
                                        | -> :method: GET

动态表(解码后): 空。

解码后的头列表:

:method: GET

C.3. 不使用霍夫曼编码的请求示例

本节展示在同一连接上对应多个 HTTP 请求的若干连续头列表示例。

C.3.1. 第一个请求

要编码的头列表:

:method: GET
:scheme: http
:path: /
:authority: www.example.com

编码数据的十六进制转储:

8286 8441 0f77 7777 2e65 7861 6d70 6c65 | ...A.www.example
2e63 6f6d                               | .com

解码过程:

82                                      | == Indexed - Add ==
                                        |   idx = 2
                                        | -> :method: GET
86                                      | == Indexed - Add ==
                                        |   idx = 6
                                        | -> :scheme: http
84                                      | == Indexed - Add ==
                                        |   idx = 4
                                        | -> :path: /
41                                      | == Literal indexed ==
                                        |   Indexed name (idx = 1)
                                        |     :authority
0f                                      |   Literal value (len = 15)
7777 772e 6578 616d 706c 652e 636f 6d   | www.example.com
                                        | -> :authority: 
                                        |   www.example.com

动态表(解码后):

[  1] (s =  57) :authority: www.example.com
      Table size:  57

解码后的头列表:

:method: GET
:scheme: http
:path: /
:authority: www.example.com

C.3.2. 第二个请求

要编码的头列表:

:method: GET
:scheme: http
:path: /
:authority: www.example.com
cache-control: no-cache

编码数据的十六进制转储:

8286 84be 5808 6e6f 2d63 6163 6865      | ....X.no-cache

解码过程:

82                                      | == Indexed - Add ==
                                        |   idx = 2
                                        | -> :method: GET
86                                      | == Indexed - Add ==
                                        |   idx = 6
                                        | -> :scheme: http
84                                      | == Indexed - Add ==
                                        |   idx = 4
                                        | -> :path: /
be                                      | == Indexed - Add ==
                                        |   idx = 62
                                        | -> :authority:
                                        |   www.example.com
58                                      | == Literal indexed ==
                                        |   Indexed name (idx = 24)
                                        |     cache-control
08                                      |   Literal value (len = 8)
6e6f 2d63 6163 6865                     | no-cache
                                        | -> cache-control: no-cache

动态表(解码后):

[  1] (s =  53) cache-control: no-cache
[  2] (s =  57) :authority: www.example.com
      Table size: 110

解码后的头列表:

:method: GET
:scheme: http
:path: /
:authority: www.example.com
cache-control: no-cache

C.3.3. 第三个请求

要编码的头列表:

:method: GET
:scheme: https
:path: /index.html
:authority: www.example.com
custom-key: custom-value

编码数据的十六进制转储:

8287 85bf 400a 6375 7374 6f6d 2d6b 6579 | ....@.custom-key
0c63 7573 746f 6d2d 7661 6c75 65        | .custom-value

解码过程:

82                                      | == Indexed - Add ==
                                        |   idx = 2
                                        | -> :method: GET
87                                      | == Indexed - Add ==
                                        |   idx = 7
                                        | -> :scheme: https
85                                      | == Indexed - Add ==
                                        |   idx = 5
                                        | -> :path: /index.html
bf                                      | == Indexed - Add ==
                                        |   idx = 63
                                        | -> :authority:
                                        |   www.example.com
40                                      | == Literal indexed ==
0a                                      |   Literal name (len = 10)
6375 7374 6f6d 2d6b 6579                | custom-key
0c                                      |   Literal value (len = 12)
6375 7374 6f6d 2d76 616c 7565           | custom-value
                                        | -> custom-key:
                                        |   custom-value

动态表(解码后):

[  1] (s =  54) custom-key: custom-value
[  2] (s =  53) cache-control: no-cache
[  3] (s =  57) :authority: www.example.com
      Table size: 164

解码后的头列表:

:method: GET
:scheme: https
:path: /index.html
:authority: www.example.com
custom-key: custom-value

C.4. 使用霍夫曼编码的请求示例

本节展示与上一节相同的示例,但对字面值使用霍夫曼编码。

C.4.1. 第一个请求

要编码的头列表:

:method: GET
:scheme: http
:path: /
:authority: www.example.com

编码数据的十六进制转储:

8286 8441 8cf1 e3c2 e5f2 3a6b a0ab 90f4 | ...A......:k....
ff                                      | .

解码过程:

82                                      | == Indexed - Add ==
                                        |   idx = 2
                                        | -> :method: GET
86                                      | == Indexed - Add ==
                                        |   idx = 6
                                        | -> :scheme: http
84                                      | == Indexed - Add ==
                                        |   idx = 4
                                        | -> :path: /
41                                      | == Literal indexed ==
                                        |   Indexed name (idx = 1)
                                        |     :authority
8c                                      |   Literal value (len = 12)
                                        |     Huffman encoded:
f1e3 c2e5 f23a 6ba0 ab90 f4ff           | .....:k.....
                                        |     Decoded:
                                        | www.example.com
                                        | -> :authority:
                                        |   www.example.com

动态表(解码后):

[  1] (s =  57) :authority: www.example.com
      Table size:  57

解码后的头列表:

:method: GET
:scheme: http
:path: /
:authority: www.example.com

C.4.2. 第二个请求

要编码的头列表:

:method: GET
:scheme: http
:path: /
:authority: www.example.com
cache-control: no-cache

编码数据的十六进制转储:

8286 84be 5886 a8eb 1064 9cbf           | ....X....d..

解码过程:

82                                      | == Indexed - Add ==
                                        |   idx = 2
                                        | -> :method: GET
86                                      | == Indexed - Add ==
                                        |   idx = 6
                                        | -> :scheme: http
84                                      | == Indexed - Add ==
                                        |   idx = 4
                                        | -> :path: /
be                                      | == Indexed - Add ==
                                        |   idx = 62
                                        | -> :authority:
                                        |   www.example.com
58                                      | == Literal indexed ==
                                        |   Indexed name (idx = 24)
                                        |     cache-control
86                                      |   Literal value (len = 6)
                                        |     Huffman encoded:
a8eb 1064 9cbf                          | ...d..
                                        |     Decoded:
                                        | no-cache
                                        | -> cache-control: no-cache

动态表(解码后):

[  1] (s =  53) cache-control: no-cache
[  2] (s =  57) :authority: www.example.com
      Table size: 110

解码后的头列表:

:method: GET
:scheme: http
:path: /
:authority: www.example.com
cache-control: no-cache

C.4.3. 第三个请求

要编码的头列表:

:method: GET
:scheme: https
:path: /index.html
:authority: www.example.com
custom-key: custom-value

编码数据的十六进制转储:

8287 85bf 4088 25a8 49e9 5ba9 7d7f 8925 | ....@.%.I.[.}..%
a849 e95b b8e8 b4bf                     | .I.[....

解码过程:

82                                      | == Indexed - Add ==
                                        |   idx = 2
                                        | -> :method: GET
87                                      | == Indexed - Add ==
                                        |   idx = 7
                                        | -> :scheme: https
85                                      | == Indexed - Add ==
                                        |   idx = 5
                                        | -> :path: /index.html
bf                                      | == Indexed - Add ==
                                        |   idx = 63
                                        | -> :authority:
                                        |   www.example.com
40                                      | == Literal indexed ==
88                                      |   Literal name (len = 8)
                                        |     Huffman encoded:
25a8 49e9 5ba9 7d7f                     | %.I.[.}.
                                        |     Decoded:
                                        | custom-key
89                                      |   Literal value (len = 9)
                                        |     Huffman encoded:
25a8 49e9 5bb8 e8b4 bf                  | %.I.[....
                                        |     Decoded:
                                        | custom-value
                                        | -> custom-key:
                                        |   custom-value

动态表(解码后):

[  1] (s =  54) custom-key: custom-value
[  2] (s =  53) cache-control: no-cache
[  3] (s =  57) :authority: www.example.com
      Table size: 164

解码后的头列表:

:method: GET
:scheme: https
:path: /index.html
:authority: www.example.com
custom-key: custom-value

C.5. 不使用霍夫曼编码的响应示例

本节展示在同一连接上对应多个 HTTP 响应的若干连续头列表示例。HTTP/2 的设置参数 SETTINGS_HEADER_TABLE_SIZE 设置为 256 八位组,导致发生一些逐出。

C.5.1. 第一个响应

要编码的头列表:

:status: 302
cache-control: private
date: Mon, 21 Oct 2013 20:13:21 GMT
location: https://www.example.com

编码数据的十六进制转储:

4803 3330 3258 0770 7269 7661 7465 611d | H.302X.privatea.
4d6f 6e2c 2032 3120 4f63 7420 3230 3133 | Mon, 21 Oct 2013
2032 303a 3133 3a32 3120 474d 546e 1768 |  20:13:21 GMTn.h
7474 7073 3a2f 2f77 7777 2e65 7861 6d70 | ttps://www.examp
6c65 2e63 6f6d                          | le.com

解码过程:

48                                      | == Literal indexed ==
                                        |   Indexed name (idx = 8)
                                        |     :status
03                                      |   Literal value (len = 3)
3330 32                                 | 302
                                        | -> :status: 302
58                                      | == Literal indexed ==
                                        |   Indexed name (idx = 24)
                                        |     cache-control
07                                      |   Literal value (len = 7)
7072 6976 6174 65                       | private
                                        | -> cache-control: private
61                                      | == Literal indexed ==
                                        |   Indexed name (idx = 33)
                                        |     date
1d                                      |   Literal value (len = 29)
4d6f 6e2c 2032 3120 4f63 7420 3230 3133 | Mon, 21 Oct 2013
2032 303a 3133 3a32 3120 474d 54        |  20:13:21 GMT
                                        | -> date: Mon, 21 Oct 2013
                                        |   20:13:21 GMT
6e                                      | == Literal indexed ==
                                        |   Indexed name (idx = 46)
                                        |     location
17                                      |   Literal value (len = 23)
6874 7470 733a 2f2f 7777 772e 6578 616d | https://www.exam
706c 652e 636f 6d                       | ple.com
                                        | -> location:
                                        |   https://www.example.com

动态表(解码后):

[  1] (s =  63) location: https://www.example.com
[  2] (s =  65) date: Mon, 21 Oct 2013 20:13:21 GMT
[  3] (s =  52) cache-control: private
[  4] (s =  42) :status: 302
      Table size: 222

解码后的头列表:

:status: 302
cache-control: private
date: Mon, 21 Oct 2013 20:13:21 GMT
location: https://www.example.com

C.5.2. 第二个响应

为腾出空间以添加 (":status", "307") 头字段,动态表中的 (":status", "302") 头字段被逐出。

要编码的头列表:

:status: 307
cache-control: private
date: Mon, 21 Oct 2013 20:13:21 GMT
location: https://www.example.com

编码数据的十六进制转储:

4803 3330 37c1 c0bf                     | H.307...

解码过程:

48                                      | == Literal indexed ==
                                        |   Indexed name (idx = 8)
                                        |     :status
03                                      |   Literal value (len = 3)
3330 37                                 | 307
                                        | - evict: :status: 302
                                        | -> :status: 307
c1                                      | == Indexed - Add ==
                                        |   idx = 65
                                        | -> cache-control: private
c0                                      | == Indexed - Add ==
                                        |   idx = 64
                                        | -> date: Mon, 21 Oct 2013
                                        |   20:13:21 GMT
bf                                      | == Indexed - Add ==
                                        |   idx = 63
                                        | -> location:
                                        |   https://www.example.com

动态表(解码后):

[  1] (s =  42) :status: 307
[  2] (s =  63) location: https://www.example.com
[  3] (s =  65) date: Mon, 21 Oct 2013 20:13:21 GMT
[  4] (s =  52) cache-control: private
      Table size: 222

解码后的头列表:

:status: 307
cache-control: private
date: Mon, 21 Oct 2013 20:13:21 GMT
location: https://www.example.com

C.5.3. 第三个响应

在处理该头列表期间,有若干头字段被逐出动态表。

要编码的头列表:

:status: 200
cache-control: private
date: Mon, 21 Oct 2013 20:13:22 GMT
location: https://www.example.com
content-encoding: gzip
set-cookie: foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1

编码数据的十六进制转储:

88c1 611d 4d6f 6e2c 2032 3120 4f63 7420 | ..a.Mon, 21 Oct
3230 3133 2032 303a 3133 3a32 3220 474d | 2013 20:13:22 GM
54c0 5a04 677a 6970 7738 666f 6f3d 4153 | T.Z.gzipw8foo=AS
444a 4b48 514b 425a 584f 5157 454f 5049 | DJKHQKBZXOQWEOPI
5541 5851 5745 4f49 553b 206d 6178 2d61 | UAXQWEOIU; max-a
6765 3d33 3630 303b 2076 6572 7369 6f6e | ge=3600; version
3d31                                    | =1

解码过程:

88                                      | == Indexed - Add ==
                                        |   idx = 8
                                        | -> :status: 200
c1                                      | == Indexed - Add ==
                                        |   idx = 65
                                        | -> cache-control: private
61                                      | == Literal indexed ==
                                        |   Indexed name (idx = 33)
                                        |     date
1d                                      |   Literal value (len = 29)
4d6f 6e2c 2032 3120 4f63 7420 3230 3133 | Mon, 21 Oct 2013
2032 303a 3133 3a32 3220 474d 54        |  20:13:22 GMT
                                        | - evict: cache-control:
                                        |   private
                                        | -> date: Mon, 21 Oct 2013
                                        |   20:13:22 GMT
c0                                      | == Indexed - Add ==
                                        |   idx = 64
                                        | -> location: 
                                        |   https://www.example.com
5a                                      | == Literal indexed ==
                                        |   Indexed name (idx = 26)
                                        |     content-encoding
04                                      |   Literal value (len = 4)
677a 6970                               | gzip
                                        | - evict: date: Mon, 21 Oct 
                                        |    2013 20:13:21 GMT
                                        | -> content-encoding: gzip
77                                      | == Literal indexed ==
                                        |   Indexed name (idx = 55)
                                        |     set-cookie
38                                      |   Literal value (len = 56)
666f 6f3d 4153 444a 4b48 514b 425a 584f | foo=ASDJKHQKBZXO
5157 454f 5049 5541 5851 5745 4f49 553b | QWEOPIUAXQWEOIU;
206d 6178 2d61 6765 3d33 3630 303b 2076 |  max-age=3600; v
6572 7369 6f6e 3d31                     | ersion=1
                                        | - evict: location:
                                        |   https://www.example.com
                                        | - evict: :status: 307
                                        | -> set-cookie: foo=ASDJKHQ
                                        |   KBZXOQWEOPIUAXQWEOIU; ma
                                        |   x-age=3600; version=1

动态表(解码后):

[  1] (s =  98) set-cookie: foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU;
                 max-age=3600; version=1
[  2] (s =  52) content-encoding: gzip
[  3] (s =  65) date: Mon, 21 Oct 2013 20:13:22 GMT
      Table size: 215

解码后的头列表:

:status: 200
cache-control: private
date: Mon, 21 Oct 2013 20:13:22 GMT
location: https://www.example.com
content-encoding: gzip
set-cookie: foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1

C.6. 使用霍夫曼编码的响应示例

本节展示与上一节相同的示例,但对字面值使用霍夫曼编码。HTTP/2 的设置参数 SETTINGS_HEADER_TABLE_SIZE 设置为 256 八位组,导致发生一些逐出。逐出机制使用解码后字面值的长度,因此发生的逐出与上一节相同。

C.6.1. 第一个响应

要编码的头列表:

:status: 302
cache-control: private
date: Mon, 21 Oct 2013 20:13:21 GMT
location: https://www.example.com

编码数据的十六进制转储:

4882 6402 5885 aec3 771a 4b61 96d0 7abe | H.d.X...w.Ka..z.
9410 54d4 44a8 2005 9504 0b81 66e0 82a6 | ..T.D. .....f...
2d1b ff6e 919d 29ad 1718 63c7 8f0b 97c8 | -..n..)...c.....
e9ae 82ae 43d3                          | ....C.

解码过程:

48                                      | == Literal indexed ==
                                        |   Indexed name (idx = 8)
                                        |     :status
82                                      |   Literal value (len = 2)
                                        |     Huffman encoded:
6402                                    | d.
                                        |     Decoded:
                                        | 302
                                        | -> :status: 302
58                                      | == Literal indexed ==
                                        |   Indexed name (idx = 24)
                                        |     cache-control
85                                      |   Literal value (len = 5)
                                        |     Huffman encoded:
aec3 771a 4b                            | ..w.K
                                        |     Decoded:
                                        | private
                                        | -> cache-control: private
61                                      | == Literal indexed ==
                                        |   Indexed name (idx = 33)
                                        |     date
96                                      |   Literal value (len = 22)
                                        |     Huffman encoded:
d07a be94 1054 d444 a820 0595 040b 8166 | .z...T.D. .....f
e082 a62d 1bff                          | ...-..
                                        |     Decoded:
                                        | Mon, 21 Oct 2013 20:13:21
                                        | GMT
                                        | -> date: Mon, 21 Oct 2013
                                        |   20:13:21 GMT
6e                                      | == Literal indexed ==
                                        |   Indexed name (idx = 46)
                                        |     location
91                                      |   Literal value (len = 17)
                                        |     Huffman encoded:
9d29 ad17 1863 c78f 0b97 c8e9 ae82 ae43 | .)...c.........C
d3                                      | .
                                        |     Decoded:
                                        | https://www.example.com
                                        | -> location:
                                        |   https://www.example.com

动态表(解码后):

[  1] (s =  63) location: https://www.example.com
[  2] (s =  65) date: Mon, 21 Oct 2013 20:13:21 GMT
[  3] (s =  52) cache-control: private
[  4] (s =  42) :status: 302
      Table size: 222

解码后的头列表:

:status: 302
cache-control: private
date: Mon, 21 Oct 2013 20:13:21 GMT
location: https://www.example.com

C.6.2. 第二个响应

为腾出空间以添加 (":status", "307") 头字段,动态表中的 (":status", "302") 头字段被逐出。

要编码的头列表:

:status: 307
cache-control: private
date: Mon, 21 Oct 2013 20:13:21 GMT
location: https://www.example.com

编码数据的十六进制转储:

4883 640e ffc1 c0bf                     | H.d.....

解码过程:

48                                      | == Literal indexed ==
                                        |   Indexed name (idx = 8)
                                        |     :status
83                                      |   Literal value (len = 3)
                                        |     Huffman encoded:
640e ff                                 | d..
                                        |     Decoded:
                                        | 307
                                        | - evict: :status: 302
                                        | -> :status: 307
c1                                      | == Indexed - Add ==
                                        |   idx = 65
                                        | -> cache-control: private
c0                                      | == Indexed - Add ==
                                        |   idx = 64
                                        | -> date: Mon, 21 Oct 2013
                                        |   20:13:21 GMT
bf                                      | == Indexed - Add ==
                                        |   idx = 63
                                        | -> location:
                                        |   https://www.example.com

动态表(解码后):

[  1] (s =  42) :status: 307
[  2] (s =  63) location: https://www.example.com
[  3] (s =  65) date: Mon, 21 Oct 2013 20:13:21 GMT
[  4] (s =  52) cache-control: private
      Table size: 222

解码后的头列表:

:status: 307
cache-control: private
date: Mon, 21 Oct 2013 20:13:21 GMT
location: https://www.example.com

C.6.3. 第三个响应

在处理该头列表期间,有若干头字段被逐出动态表。

要编码的头列表:

:status: 200
cache-control: private
date: Mon, 21 Oct 2013 20:13:22 GMT
location: https://www.example.com
content-encoding: gzip
set-cookie: foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1

编码数据的十六进制转储:

88c1 6196 d07a be94 1054 d444 a820 0595 | ..a..z...T.D. ..
040b 8166 e084 a62d 1bff c05a 839b d9ab | ...f...-...Z....
77ad 94e7 821d d7f2 e6c7 b335 dfdf cd5b | w..........5...[
3960 d5af 2708 7f36 72c1 ab27 0fb5 291f | 9`..'..6r..'..).
9587 3160 65c0 03ed 4ee5 b106 3d50 07   | ..1`e...N...=P.

解码过程:

88                                      | == Indexed - Add ==
                                        |   idx = 8
                                        | -> :status: 200
c1                                      | == Indexed - Add ==
                                        |   idx = 65
                                        | -> cache-control: private
61                                      | == Literal indexed ==
                                        |   Indexed name (idx = 33)
                                        |     date
96                                      |   Literal value (len = 22)
                                        |     Huffman encoded:
d07a be94 1054 d444 a820 0595 040b 8166 | .z...T.D. .....f
e084 a62d 1bff                          | ...-..
                                        |     Decoded:
                                        | Mon, 21 Oct 2013 20:13:22
                                        | GMT
                                        | - evict: cache-control:
                                        |   private
                                        | -> date: Mon, 21 Oct 2013 
                                        |   20:13:22 GMT
c0                                      | == Indexed - Add ==
                                        |   idx = 64
                                        | -> location:
                                        |   https://www.example.com
5a                                      | == Literal indexed ==
                                        |   Indexed name (idx = 26)
                                        |     content-encoding
83                                      |   Literal value (len = 3)
                                        |     Huffman encoded:
9bd9 ab                                 | ...
                                        |     Decoded:
                                        | gzip
                                        | - evict: date: Mon, 21 Oct
                                        |    2013 20:13:21 GMT
                                        | -> content-encoding: gzip
77                                      | == Literal indexed ==
                                        |   Indexed name (idx = 55)
                                        |     set-cookie
ad                                      |   Literal value (len = 45)
                                        |     Huffman encoded:
94e7 821d d7f2 e6c7 b335 dfdf cd5b 3960 | .........5...[9`
d5af 2708 7f36 72c1 ab27 0fb5 291f 9587 | ..'..6r..'..)...
3160 65c0 03ed 4ee5 b106 3d50 07        | 1`e...N...=P.
                                        |     Decoded:
                                        | foo=ASDJKHQKBZXOQWEOPIUAXQ
                                        | WEOIU; max-age=3600; versi
                                        | on=1
                                        | - evict: location:
                                        |   https://www.example.com
                                        | - evict: :status: 307
                                        | -> set-cookie: foo=ASDJKHQ
                                        |   KBZXOQWEOPIUAXQWEOIU; ma
                                        |   x-age=3600; version=1

动态表(解码后):

[  1] (s =  98) set-cookie: foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU;
                 max-age=3600; version=1
[  2] (s =  52) content-encoding: gzip
[  3] (s =  65) date: Mon, 21 Oct 2013 20:13:22 GMT
      Table size: 215

解码后的头列表:

:status: 200
cache-control: private
date: Mon, 21 Oct 2013 20:13:22 GMT
location: https://www.example.com
content-encoding: gzip
set-cookie: foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1

致谢

本规范包含以下个人的重要贡献:

  • Mike Bishop、Jeff Pinner、Julian Reschke 和 Martin Thomson(大量编辑贡献)。
  • Johnny Graettinger(霍夫曼码统计数据)。

作者地址

Roberto Peon
Google, Inc
电子邮件: fenix@google.com
Hervé Ruellan
Canon CRF
电子邮件: herve.ruellan@crf.canon.fr