http/2动态table解码出错
http/2 dynamic table decoding goes wrong
我尝试执行 http/2 代码,我正在尝试向 google 发送请求。我在 wireshark 中查看了 Mozilla Firefox 是如何做到的。这是一个例子:
这是对 google 的第一个请求,在第一个 SETTINGS
帧
之后
Header Block Fragment: 8205a563fc9a52c5649012cf829a03f1f3372e66f78c9eb6...
[Header Length: 590]
[Header Count: 11]
Header: :method: GET
Representation: Indexed Header Field
Header: :path: /?gfe_rd=cr&ei=oVxgWYizHcyRZK-lqKgG&gws_rd=ssl
Representation: Literal Header Field without Indexing - Indexed Name
Header: :authority: www.google.ru
Representation: Literal Header Field with Incremental Indexing - Indexed Name
Header: :scheme: https
Representation: Indexed Header Field
Header: user-agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:54.0) Gecko/20100101 Firefox/54.0
Representation: Literal Header Field with Incremental Indexing - Indexed Name
Header: accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Representation: Literal Header Field with Incremental Indexing - Indexed Name
Header: accept-language: ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3
Representation: Literal Header Field with Incremental Indexing - Indexed Name
Header: accept-encoding: gzip, deflate, br
Representation: Literal Header Field with Incremental Indexing - Indexed Name
Header: cookie: NID=107=L67kU0sEsfzwpItJcUZyRfjKENJ1xa2N8_m4xqnVLCj9dW289EDyzg7ZvXZCt9kEII0nd5BA2Tns95vlkCGlGP850ULPoOKFeMJoaQT_0o7Cl3skG4PDdQgUW2hlRh7Z
Representation: Literal Header Field with Incremental Indexing - Indexed Name
Header: dnt: 1
Representation: Literal Header Field with Incremental Indexing - New Name
Header: upgrade-insecure-requests: 1
Representation: Literal Header Field with Incremental Indexing - New Name
Padding: <MISSING>
因此客户端的动态 table 将如下所示,假设我理解正确:
1 ->upgrade-insecure-requests: 1
2 ->dnt :1
3 ->cookie: NID=107=kjxoLmF8StT6CO8a8T-z68DAIJB6cyzAwqWOjjmXGubtu2pmJSfGPCjUAo9D-OTzuk03u34YLxLMjH236FBDzKVYayleievvTkamyhrLuOz4AYT_7KiuVIS5JA_BuVEa
4 ->accept-encoding: gzip, deflate, br
5 ->accept-language: ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3
6 ->accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
7 ->user-agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:54.0) Gecko/20100101 Firefox/54.0
8 ->:authority: www.google.ru
所有标记为Representation: Literal Header Field with Incremental Indexing
的header都插入到动态table中,先插入的,移动到更高的索引,新条目在最前面.
但是这个 table 不起作用,因为当浏览器执行第二个请求时,要下载一些图像(google 徽标或其他),一些混乱正在发生,
第二个请求已解码:
[Header Length: 535]
[Header Count: 11]
Header: :method: GET
Representation: Indexed Header Field
Header: :path: /images/hpp/ic_wahlberg_product_core_48.png8.png
Representation: Literal Header Field without Indexing - Indexed Name
Header: :authority: www.google.ru
Representation: Indexed Header Field
Header: :scheme: https
Representation: Indexed Header Field
Header: user-agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:54.0) Gecko/20100101 Firefox/54.0
Representation: Indexed Header Field
Header: accept: */*
Representation: Literal Header Field with Incremental Indexing - Indexed Name
Header: accept-language: ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3
Representation: Indexed Header Field
Header: accept-encoding: gzip, deflate, br
Representation: Indexed Header Field
Header: referer: https://www.google.ru/
Representation: Literal Header Field with Incremental Indexing - Indexed Name
Header: cookie: NID=107=j8x_CchswQznRlhYWeTtf7rDE7QaxZBxbGeQevst16TVFJ3qOJjlsVwxEobdZaVAeUFboCuuUhu0VdJwujroT_u5hoGttx5Mcu4xnMZQIfK7OSMhqtSbO135AL8GlZWU
Representation: Literal Header Field with Incremental Indexing - Indexed Name
Header: dnt: 1
Representation: Indexed Header Field
Padding: <MISSING>
这是编码的第二个请求:
82 = :method: GET ( index 2 in the static table is "method: GET" )
05 a3 60 d4 8e 62 a1 89 eb ad 83 12 2f 03 9e 88
cb 64 d1 57 61 e4 b4 89 88 87 b0 b1 34 f2 f5 d5
33 cb d7 54 df = :path: /images/hpp/ic_wahlberg_product_core_48.png8.png (05 is the index of "path:" in static table, rest is huffman encoded literal )
c5 = :authority: www.google.ru ( index 8 at the dynamic table, 0xc5 & 0x7f = 69 (dec) static table length (61)? is this correct?
87 = scheme: https - static table
c4 = user-agent: Mozilla/5.0... ( index 7 at the dynamic table, 0xc5 & 0x7f = 68 (dec) static table length (61)? is this correct?
这里是我无法理解的地方:
7f 04 83 f9 63 e7
- 这假设根据 wireshark 表示 accept: */*
并且它被标记为 Literal Header Field with Incremental Indexing - Indexed Name
,所以 0x7f
应该是 [=51= 的索引].文字增量索引的掩码是 0x40
,所以我们用 0x3f
在 0x7f
上做布尔值 AND
,我们得到 63
十进制,也就是 dnt: 1
header 来自我们的动态 table,这是完全不正确的。
有人可以帮忙,这是如何正确解码的? http/2 是否使用相同的动态 table 进行响应解码? (也许这就是为什么我的解码搞砸了?)
您仅通过查看单个字节(0x7f
或 0x3f
剥离索引字段信息后计算索引号是错误的。但是,您还需要查看整数(以及 header 字段索引)在 HPACK 中的表示方式。这包含在 HPACK 规范的 5.1 Integer Representation 部分。
你可以在那里看到,如果第一个字节中用于数字的所有位都设置为零,你也需要考虑下一个字节。在这种情况下会发生这种情况,因为 0x3f 意味着所有使用的 6 位都设置为 1。因此实际索引号被编码为 0x7f 0x04
。我认为这应该导致 63+4 = 67,这是动态 table 的第 6 个条目。在第一次请求后,这将与您预期的动态 table 布局相匹配。
顺便说一句:有趣的是它没有 select 索引 19,它是来自静态 table 的 accept
。从我的角度来看,这里没有额外的价值来引用动态 table ,当只有字段名称(并且没有取值)时,在静态 table 中查找东西可能会减少开销对于某些实现。
并澄清这个问题:
Does http/2 uses the same dynamic table for response decoding?
不,所有发送的headers(客户端请求headers)有一个动态table实例,所有接收的header有一个实例]s(在客户端响应 headers)。
我尝试执行 http/2 代码,我正在尝试向 google 发送请求。我在 wireshark 中查看了 Mozilla Firefox 是如何做到的。这是一个例子:
这是对 google 的第一个请求,在第一个 SETTINGS
帧
Header Block Fragment: 8205a563fc9a52c5649012cf829a03f1f3372e66f78c9eb6...
[Header Length: 590]
[Header Count: 11]
Header: :method: GET
Representation: Indexed Header Field
Header: :path: /?gfe_rd=cr&ei=oVxgWYizHcyRZK-lqKgG&gws_rd=ssl
Representation: Literal Header Field without Indexing - Indexed Name
Header: :authority: www.google.ru
Representation: Literal Header Field with Incremental Indexing - Indexed Name
Header: :scheme: https
Representation: Indexed Header Field
Header: user-agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:54.0) Gecko/20100101 Firefox/54.0
Representation: Literal Header Field with Incremental Indexing - Indexed Name
Header: accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Representation: Literal Header Field with Incremental Indexing - Indexed Name
Header: accept-language: ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3
Representation: Literal Header Field with Incremental Indexing - Indexed Name
Header: accept-encoding: gzip, deflate, br
Representation: Literal Header Field with Incremental Indexing - Indexed Name
Header: cookie: NID=107=L67kU0sEsfzwpItJcUZyRfjKENJ1xa2N8_m4xqnVLCj9dW289EDyzg7ZvXZCt9kEII0nd5BA2Tns95vlkCGlGP850ULPoOKFeMJoaQT_0o7Cl3skG4PDdQgUW2hlRh7Z
Representation: Literal Header Field with Incremental Indexing - Indexed Name
Header: dnt: 1
Representation: Literal Header Field with Incremental Indexing - New Name
Header: upgrade-insecure-requests: 1
Representation: Literal Header Field with Incremental Indexing - New Name
Padding: <MISSING>
因此客户端的动态 table 将如下所示,假设我理解正确:
1 ->upgrade-insecure-requests: 1
2 ->dnt :1
3 ->cookie: NID=107=kjxoLmF8StT6CO8a8T-z68DAIJB6cyzAwqWOjjmXGubtu2pmJSfGPCjUAo9D-OTzuk03u34YLxLMjH236FBDzKVYayleievvTkamyhrLuOz4AYT_7KiuVIS5JA_BuVEa
4 ->accept-encoding: gzip, deflate, br
5 ->accept-language: ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3
6 ->accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
7 ->user-agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:54.0) Gecko/20100101 Firefox/54.0
8 ->:authority: www.google.ru
所有标记为Representation: Literal Header Field with Incremental Indexing
的header都插入到动态table中,先插入的,移动到更高的索引,新条目在最前面.
但是这个 table 不起作用,因为当浏览器执行第二个请求时,要下载一些图像(google 徽标或其他),一些混乱正在发生,
第二个请求已解码:
[Header Length: 535]
[Header Count: 11]
Header: :method: GET
Representation: Indexed Header Field
Header: :path: /images/hpp/ic_wahlberg_product_core_48.png8.png
Representation: Literal Header Field without Indexing - Indexed Name
Header: :authority: www.google.ru
Representation: Indexed Header Field
Header: :scheme: https
Representation: Indexed Header Field
Header: user-agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:54.0) Gecko/20100101 Firefox/54.0
Representation: Indexed Header Field
Header: accept: */*
Representation: Literal Header Field with Incremental Indexing - Indexed Name
Header: accept-language: ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3
Representation: Indexed Header Field
Header: accept-encoding: gzip, deflate, br
Representation: Indexed Header Field
Header: referer: https://www.google.ru/
Representation: Literal Header Field with Incremental Indexing - Indexed Name
Header: cookie: NID=107=j8x_CchswQznRlhYWeTtf7rDE7QaxZBxbGeQevst16TVFJ3qOJjlsVwxEobdZaVAeUFboCuuUhu0VdJwujroT_u5hoGttx5Mcu4xnMZQIfK7OSMhqtSbO135AL8GlZWU
Representation: Literal Header Field with Incremental Indexing - Indexed Name
Header: dnt: 1
Representation: Indexed Header Field
Padding: <MISSING>
这是编码的第二个请求:
82 = :method: GET ( index 2 in the static table is "method: GET" )
05 a3 60 d4 8e 62 a1 89 eb ad 83 12 2f 03 9e 88
cb 64 d1 57 61 e4 b4 89 88 87 b0 b1 34 f2 f5 d5
33 cb d7 54 df = :path: /images/hpp/ic_wahlberg_product_core_48.png8.png (05 is the index of "path:" in static table, rest is huffman encoded literal )
c5 = :authority: www.google.ru ( index 8 at the dynamic table, 0xc5 & 0x7f = 69 (dec) static table length (61)? is this correct?
87 = scheme: https - static table
c4 = user-agent: Mozilla/5.0... ( index 7 at the dynamic table, 0xc5 & 0x7f = 68 (dec) static table length (61)? is this correct?
这里是我无法理解的地方:
7f 04 83 f9 63 e7
- 这假设根据 wireshark 表示 accept: */*
并且它被标记为 Literal Header Field with Incremental Indexing - Indexed Name
,所以 0x7f
应该是 [=51= 的索引].文字增量索引的掩码是 0x40
,所以我们用 0x3f
在 0x7f
上做布尔值 AND
,我们得到 63
十进制,也就是 dnt: 1
header 来自我们的动态 table,这是完全不正确的。
有人可以帮忙,这是如何正确解码的? http/2 是否使用相同的动态 table 进行响应解码? (也许这就是为什么我的解码搞砸了?)
您仅通过查看单个字节(0x7f
或 0x3f
剥离索引字段信息后计算索引号是错误的。但是,您还需要查看整数(以及 header 字段索引)在 HPACK 中的表示方式。这包含在 HPACK 规范的 5.1 Integer Representation 部分。
你可以在那里看到,如果第一个字节中用于数字的所有位都设置为零,你也需要考虑下一个字节。在这种情况下会发生这种情况,因为 0x3f 意味着所有使用的 6 位都设置为 1。因此实际索引号被编码为 0x7f 0x04
。我认为这应该导致 63+4 = 67,这是动态 table 的第 6 个条目。在第一次请求后,这将与您预期的动态 table 布局相匹配。
顺便说一句:有趣的是它没有 select 索引 19,它是来自静态 table 的 accept
。从我的角度来看,这里没有额外的价值来引用动态 table ,当只有字段名称(并且没有取值)时,在静态 table 中查找东西可能会减少开销对于某些实现。
并澄清这个问题:
Does http/2 uses the same dynamic table for response decoding?
不,所有发送的headers(客户端请求headers)有一个动态table实例,所有接收的header有一个实例]s(在客户端响应 headers)。