HTTP2协议之HPACK--之头部压缩规范介绍
接下来打算把HTTP2协议的头部压缩算法给翻译下,敬请等候。
HPACK - Header Compression for HTTP/2
HPACK:HTTP/2头部压缩
概要说明
这个规范定义了HPACK,它是应用在HTTP/2中的了为了更加有效的表示HTTP头部属性的压缩格式规范。
内容列表
1.介绍
在HTTP/1.1中,头部域是没有压缩的。如果web页面请求从十几个增加大几百个,那么这些请求中的头部域就会消耗很多的带宽从而造成延迟。
SPY通过使用DEFLATE格式来压缩头部域的方式来解决这个问题,这个方法在表示大量的头部域中也是被证明是非常有效的。但是,这个方式在CRIME(Compression Ratio Info-leak Made Easy)攻击中就会暴露出安全隐患。
这个规范定义了一个可以头部域冗余的压缩器HPACK,它隐藏了安全攻击的弱点而且在有限制的环境中使用有界的内存。更多的关于HPACK的安全问题在Section 7部分。
HPACK格式被设计的简单和灵活。这两个特点减少了由于事先错误产生的互用性的隐患或者安全问题。它没有定义扩展机制,所以改变这种格式的唯一途径就是通过定义一个完整的替代者。
1.1概述
在这个规范中,会把头部域当成一个有序的名-值对的集合,而且有可能含有重复的名值对。名字和值会被当成八进制的,而且在解压缩后头部域的顺序会被反转。
头部域列表会被编码为映射头部域到索引值中。而且这些头部域列表在当新的头部域被解码或者编码后会更新。
在编码后,一个头部域要么是头部域列表中的一个值要么是指向一个头部域列表中的引用。因此,通过使用引用或者具体的值就可以对头部域进行编码。
字面值可以被直接编码也可以使用一个静态的哈夫曼编码。
一个编码器需要决定头部域列表中的哪一个头部域作为一个新的输入来插入。而解码器在重新构建头部域列表的过程中需要执行编码器对头部域进行的修改。这个样就解码器能够比较简单而且和种类繁多的编码器保持协作。
1.2约定
这个文档中的关键字 "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL"在RFC2119中能够得到合适的解释。
所有的数字都是以网络中的字节排序。除非由说明否则值都是无符号的。字面值按需要可能是小数的也可能是十六进制的。
1.3术语
这个规范中使用了下面的术语:
Header Field(头部域):一个名-值对。名字和值都是以八进制存在的。
Dynamic Table(动态表):动态表是用于存放含有索引值的头部域的。这个表示动态变化的而且针对于编码或者解码的内容的。
Static Table(静态表):静态表只要用于存放含有索引值的频繁出现的头部域的。这个表是有序的、只读、可访问的而且在几乎所有的编码或者解码的内容中可以共享的。
Header List(头部列表):头部列表是头部域的有序集合一起被编码的而且可能含有重复头部域。一个完整的含有Http/2头部快的头部域就是一个头部列表。
Header Field Respresentation(头部域表示):一个头部域在编码后可以以一个字面值也可以是一个索引值。
Header Block(头部块):一个有序的头部域表示在被解码的时候就是一个完成头部列表。
2.压缩过程概述
这个规范中没有表述针对一个编码器的具体算法。取而代之的是,它详细的定义了解码器需要做的事情,而且允许一个编码器产生这个规范允许的任何编码形式。
2.1头部列表序列
HPACK保证在头部列表中的头部域是有序的。一个编码器必须根据头部域在原始头部列表中的顺序来排序在头部块中的头部域。一个解码器必须根据在头部块的排列序列来在解码的头部列表排列头部域。
2.2内容的编码和解码
为了解压头部块,一个解码器只需要把动态表当做一个解码的内容来进行操作。不再需要其他的动态状态了。
比如在HTTP中,当用于双线的通信时,被某一端操作的编码和解码都是完全独立的,动态表的请求和相应都是独立的。
2.3索引化表
HPACK使用两个表格来将头部域和索引联系在一起。静态表被提前定义好并且含有公共的头部域(大部分的值都是空的)。动态表是动态的而且能够被编码器指向在编码的头部列表中重复的头部域的索引的时候。
这两个表为了定义索引值会结合成一个单一的地址空间。
2.3.1静态表
静态表是由提前定义好的静态头部列表组成。它的输入时在Appendix A中定义的。
2.3.2动态表
动态表是由头部域的列表组成,而且是按照先进先出的序列来操作的。第一个和最新加入动态表的索引值是最低的,而最先进入动态表的索引值是最高的。
动态表是初始化的时候是空表。当每个头部块被解压的时候就会添加新值。
动态表能够含有重复的值。因此,重复的值不能够被解码器当做是一个错误。
编码器决定如何去更新动态表而且能够控制被动态表使用的内存大小。为了限制解码器需要的内存,动态表的大小是被严格限制的。
解码器在处理头部域表的列表的时候会更新动态表。
2.3.3地址空间索引
静态表和董彪会被组合成单一的地址索引空间。
在1和静态表长度之间的mul指向了静态表中的元素。
比静态表长度的索引目录会指向动态表的元素。静态表的长度被减掉就是动态表的索引值的开始。
而比两个表的长度之和都大的索引一定是解码错误。
对于一个静态表的大小s和动态表的大小k,下面的图表示了完整的合法的索引地址空间。
<---------- Index Address Space ---------->
<-- Static Table --> <-- Dynamic Table -->
+---+-----------+---+ +---+-----------+---+
| 1 | ... | s | |s+1| ... |s+k|
+---+-----------+---+ +---+-----------+---+
^ |
| V
Insertion Point Dropping Point
2.4头部域表示
一个编码的头部域既可以是一个索引也可以是一个字面值。
一个索引化的表示定义了头部域的指向了静态表或者动态表的引用。
一个字面表示就是通过指明它的名字或者值来定义头部域。头部域名字能够用字面值来表示或者指向静态表或者动态表的值。头部域的值就是以字面量来表示的。
有三种不同的字面表示定义如下:
- 在动态表的开始处作为一个新的输入来添加头部域的字面表示。
- 不需要添加到动态表的头部域的字面表示。
- 含有额外的规定的头部域一般使用字面值表示,特别是通过中间媒介重新编码的。这种表示是为了避免压缩的时候头部域的值没有保存。
为了保护敏感的头部的值的时候,这些字面值的选择能够在做安全考虑的时候起到指导意义。
一个头部域的名字或者头部域的值的字面表示既能够直接使用八进制也可以使用一个静态的哈夫曼码。
3.头部块解码
3.1头部块处理
一个解码器在处理一个头部块的时候通常会重建原始的头部列表。
一个头部块就是头部域表示的串联。不同的头部域表示描述可见Section 6
一旦头部域被家吗并且被添加到重建的头部列表中,头部域就不能够被移除了。一个被添加到头部列表的头部域可以被安全的传给应用程序。
通过传递头部域给应用程序,一个解码器在除了动态表需啊哟的内存外能够使用最小的瞬息内存来进行提交处理。