9. 用Rust手把手编写一个wmproxy(代理,内网穿透等), HTTP2改造篇之HPACK示例, 了解http2头信息如何处理

rust,手把手,编写,一个,wmproxy,代理,内网,穿透,http2,改造,hpack,示例,了解,信息,如何,处理 · 浏览次数 : 23

小编点评

内容生成时需要带简单的排版,例如: - ID索引不乱 - Huffman编码把头里面需要用到字符串的数据进行进一步的压缩 - 每个键值对的计算为name的字节数+value的字节数+32为确定的大小值

正文

9. 用Rust手把手编写一个wmproxy(代理,内网穿透等), HTTP2改造篇之HPACK示例, 了解http2头信息如何处理

项目 ++wmproxy++

gite: https://gitee.com/tickbh/wmproxy

github: https://github.com/tickbh/wmproxy

关于HPACK相关数据的示例

长度编码的示例,用5位的前缀示例

  • 将10进行编码,10小于2^5-1,故
  0   1   2   3   4   5   6   7
+---+---+---+---+---+---+---+---+
| X | X | X | 0 | 1 | 0 | 1 | 0 |   10 stored on 5 bits
+---+---+---+---+---+---+---+---+
  • 将1337进行编码
  1. 1337大于2^5-1,故前5位填充
  0   1   2   3   4   5   6   7
+---+---+---+---+---+---+---+---+
| X | X | X | 1 | 1 | 1 | 1 | 1 |  31
+---+---+---+---+---+---+---+---+
  1. 1337 - 31 = 1306,大于128,故需要二次填充,用1306 mod 128 = 21,首位填充1,故8位填充为,当前偏移值为7
  0   1   2   3   4   5   6   7
+---+---+---+---+---+---+---+---+
| 1 | 0 | 0 | 1 | 1 | 0 | 1 | 0 |  26
+---+---+---+---+---+---+---+---+
  1. 对1301-21=1280,1280 / 128 = 10, 10 < 128,故已经完成,首位填0
  0   1   2   3   4   5   6   7
+---+---+---+---+---+---+---+---+
| 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 |  10
+---+---+---+---+---+---+---+---+

最终的填充值:

  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
+---+---+---+---+---+---+---+---+

头部编码示例

在静态列表中索引

以下待索引的值

:method: GET

十六进制表示值82,二进制表示10000010,表示取静态表2的值,查表为(:method, GET)

不在列表中,但请求索引,未使用HUFFMAN

以下示例

custom-key: custom-header

十六进制表示

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

解码过程

40                                      | == 01开头请求索引 ==
0a                                      |   name (长度 10)
6375 7374 6f6d 2d6b 6579                | custom-key
0d                                      |   value (长度 13)
6375 7374 6f6d 2d68 6561 6465 72        | custom-header
                                        | -> custom-key:
                                        |   custom-header

动态表 (解码之后):

[ 1] (占用 55) custom-key: custom-header
占用长度: 10+13+32=55

名字在列表中,但不索引,未使用HUFFMAN

以下示例

:path: /sample/path

十六进制表示

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

解码过程

04                                      | == 0000开头,请求不索引 ==
                                        |   name从索引取 (idx = 4)
                                        |   值为:path
0c                                      |   value (长度12)
2f73 616d 706c 652f 7061 7468           | /sample/path
                                        | -> :path: /sample/path

永不索引,未使用HUFFMAN

以下示例

password: secret

十六进制表示

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

解码过程

10                                      | == 0001开头不索引 ==
08                                      |   name (长度8)
7061 7373 776f 7264                     | password
06                                      |   value (长度6)
7365 6372 6574                          | secret
                                        | -> password: secret

完整的请求示例,不使用HUFFMAN

以下几个示例将连接请求,后续的会用到前面的动态列表

第一次请求. 示例如下

: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 - 静态表 ==
                                        |   idx = 2
                                        | -> :method: GET
86                                      | == Indexed - 静态表 ==
                                        |   idx = 6
                                        | -> :scheme: http
84                                      | == Indexed - 静态表 ==
                                        |   idx = 4
                                        | -> :path: /
41                                      | == 01开头请求索引 indexed ==
                                        |   Indexed name (idx = 1)
                                        |     :authority
0f                                      |   Literal value (长度15)
7777 772e 6578 616d 706c 652e 636f 6d   | www.example.com
                                        | -> :authority: 
                                        |   www.example.com

动态列表 (解码后):

[ 1->62] (s = 57) :authority: www.example.com
列表长度: 57

第二次请求. 示例如下,新加了cache-control字段,其它和第一次一样

: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 - 静态表 ==
                                        |   idx = 2
                                        | -> :method: GET
86                                      | == Indexed - 静态表 ==
                                        |   idx = 6
                                        | -> :scheme: http
84                                      | == Indexed - 静态表 ==
                                        |   idx = 4
                                        | -> :path: /
be                                      | == Indexed - 动态表,索引值62及以上的为动态表 ==
                                        |   idx = 62
                                        | -> :authority:
                                        |   www.example.com
58                                      | == Literal indexed ==
                                        |   Indexed name (idx = 24)
                                        |     cache-control
08                                      |   Literal value (8)
6e6f 2d63 6163 6865                     | no-cache
                                        | -> cache-control: no-cache

动态列表 (解码后):

[ 1->62] (s = 53) cache-control: no-cache
[ 2->63] (s = 57) :authority: www.example.com
总长度: 110

第三次请求. 示例如下

: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 - 静态表 ==
                                        |   idx = 2
                                        | -> :method: GET
87                                      | == Indexed - 静态表 ==
                                        |   idx = 7
                                        | -> :scheme: https
85                                      | == Indexed - 静态表 ==
                                        |   idx = 5
                                        | -> :path: /index.html
bf                                      | == Indexed - 动态表 ==
                                        |   idx = 63
                                        | -> :authority:
                                        |   www.example.com
40                                      | == Literal indexed ==
0a                                      |   Literal name (长度10)
6375 7374 6f6d 2d6b 6579                | custom-key
0c                                      |   Literal value (长度12)
6375 7374 6f6d 2d76 616c 7565           | custom-value
                                        | -> custom-key:
                                        |   custom-value

动态列表 (解码后):

[ 1->62] (s = 54) custom-key: custom-value
[ 2->63] (s = 53) cache-control: no-cache
[ 3->64] (s = 57) :authority: www.example.com
总长度: 164

完整的请求示例(和上述例子一模一样,但是使用HUFFMAN)

以下几个示例将连接请求,后续的会用到前面的动态列表

第一次请求. 示例如下

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

十六进制表示

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

比之前少了3字节

解码过程

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

动态列表 (解码后):

[  1->62] (s =  57) :authority: www.example.com
      列表长度:  57

第二次请求. 示例如下,新加了cache-control字段,其它和第一次一样

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

十六进制表示

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

比之前少了2字节

解码过程

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

动态列表 (解码后):

[  1->62] (s =  53) cache-control: no-cache
[  2->63] (s =  57) :authority: www.example.com
      列表长度: 110

第三次请求. 示例如下

: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.[....

比之前少了5字节

解码过程

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

动态列表 (解码后):

[  1->62] (s =  54) custom-key: custom-value
[  2->63] (s =  53) cache-control: no-cache
[  3->64] (s =  57) :authority: www.example.com
      总长度: 164

HUFFMAN编码在于首次如果数据较大的时候优势会更加明显,如果数据较小,或者在后续的时候与普通编码命中索引时基本一致。

完整的返回示例(HUFFMAN)

HUFFMAN与普通的差别在于字符串编解码时的差别,这里只介绍一种,并且设置SETTINGS_HEADER_TABLE_SIZE为256

以下几个示例将连接请求,后续的会用到前面的动态列表

第一次返回. 示例如下

: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 (长度2)
                                        |     Huffman encoded:
6402                                    | d.
                                        |     Decoded:
                                        | 302
                                        | -> :status: 302
58                                      | == Literal indexed ==
                                        |   Indexed name (idx = 24)
                                        |     cache-control
85                                      |   Literal value (长度5)
                                        |     Huffman encoded:
aec3 771a 4b                            | ..w.K
                                        |     Decoded:
                                        | private
                                        | -> cache-control: private
61                                      | == Literal indexed ==
                                        |   Indexed name (idx = 33)
                                        |     date
96                                      |   Literal value (长度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 (长度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->62] (s =  63) location: https://www.example.com
[  2->63] (s =  65) date: Mon, 21 Oct 2013 20:13:21 GMT
[  3->64] (s =  52) cache-control: private
[  4->65] (s =  42) :status: 302
      Table size: 222

第二次请求. 示例如下,只是状态码发生了变更

: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 (长度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->62] (s =  42) :status: 307
[  2->63] (s =  63) location: https://www.example.com
[  3->64] (s =  65) date: Mon, 21 Oct 2013 20:13:21 GMT
[  4->65] (s =  52) cache-control: private
      Table size: 222

由于(:status, 302)的长度为42,且42+222=264>256,所以舍弃最大值

第三次请求. 示例如下

: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.

比之前少了5字节

解码过程


88                                      | == Indexed - 静态表 ==
                                        |   idx = 8
                                        | -> :status: 200
c1                                      | == Indexed - 动态表 ==
                                        |   idx = 65
                                        | -> cache-control: private
61                                      | == Literal indexed ==
                                        |   Indexed name (idx = 33)
                                        |     date
96                                      |   Literal value (长度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 (长度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 (长度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->62] (s =  98) set-cookie: foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU;
                 max-age=3600; version=1
[  2->63] (s =  52) content-encoding: gzip
[  3->64] (s =  65) date: Mon, 21 Oct 2013 20:13:22 GMT
总长度: 215

动态列表保留着一个最大的缓存大小值,每一个键值对的计算为name的字节数+value的字节数+32为确定的大小值。超出大小部分则丢弃不缓存,默认大小为4096。

总结

HPACK管理着HTTP2的头部的协议部分,有着高压缩比和重复请求的高复用性,双方编码解码需要各自维持一份动态表,动态根据处理数据来动态拓展,保证双方维持的表一模一样。从而保证ID索引不会乱。Huffman编码把头里面需要用到字符串的数据进行进一步的压缩,相对来说整个过程复杂度比HTTP1高很多,但相对的对使用者完全透明,在不影响其使用的情况下提高传输效率,并减少带宽的使用量。

与9. 用Rust手把手编写一个wmproxy(代理,内网穿透等), HTTP2改造篇之HPACK示例, 了解http2头信息如何处理相似的内容:

9. 用Rust手把手编写一个wmproxy(代理,内网穿透等), HTTP2改造篇之HPACK示例, 了解http2头信息如何处理

9. 用Rust手把手编写一个wmproxy(代理,内网穿透等), HTTP2改造篇之HPACK示例, 了解http2头信息如何处理 项目 ++wmproxy++ gite: https://gitee.com/tickbh/wmproxy github: https://github.com/ti

5. 用Rust手把手编写一个Proxy(代理), 通讯协议建立, 为内网穿透做准备

wmproxy, 通讯协议的定义, 粘包拆包的解决方案, 代理的网络的拓扑图, 协议的分类, 消息的包头, 消息类型的定义

文心一言 VS 讯飞星火 VS chatgpt (104)-- 算法导论10.1 2题

二、用go语言,说明如何在一个数组 A[1..n]中实现两个栈,使得当两个栈的元素个数之和不为 n 时,两者都不会发生上溢。要求 PUSH 和 POP 操作的运行时间为 O(1)。 文心一言: 在这个问题中,我们要在一个数组 A[1..n] 中实现两个栈,使得当两个栈的元素个数之和不为 n 时,两者

文心一言 VS 讯飞星火 VS chatgpt (103)-- 算法导论10.1 1题

一、用go语言,仿照图 10-1,画图表示依次执行操作 PUSH(S,4)、PUSH(S,1)、PUSH(S,3)、POP(S)、PUSH(S,8)和 POP(S)每一步的结果,栈 S初始为空,存储于数组 S[1..6]中。 文心一言: 图 10-1 展示了在执行一系列栈操作后栈的状态。我会用文字描

lvs的nat和dr模式混合用

机器部署信息 lvs : 10.0.0.200 vip 10.0.0.19 外网IP , 172.168.1.19 内网IP dr rs: 10.0.0.200 vip 10.0.0.18 rip nat rs: 172.168.1.17 rip 客户端: 10.0.0.14 cip lvs机器:

记录几十页html生成pdf的历程和坑(已用bookjs-easy解决)(生成、转换、拼接pdf)

懒得看的朋友,先说最终解决办法,主力为 前端依靠插件 bookjs-easy(点击直接跳转官网)并跳转到下面的第三点查看 接下来详细记录下整个试探的方向和历程 项目需求:是生成一个页数达到大几十页的pdf,然后这个pdf包含表格、折线图、图片等,且横竖幅交叉,即竖版页面和横板页面交叉 1.首先我们讨

2023-09-30:用go语言,给你一个整数数组 nums 和一个整数 k 。 nums 仅包含 0 和 1, 每一次移动,你可以选择 相邻 两个数字并将它们交换。 请你返回使 nums 中包含 k

2023-09-30:用go语言,给你一个整数数组 nums 和一个整数 k 。 nums 仅包含 0 和 1, 每一次移动,你可以选择 相邻 两个数字并将它们交换。 请你返回使 nums 中包含 k 个 连续 1 的 最少 交换次数。 输入:nums = [1,0,0,1,0,1], k = 2。

用StabilityMatrix一键安装Stable Diffusion

Stable Diffusion是2022年发布的深度学习文字到图像生成模型,它既能免费使用,又能部署在本地端,又有非常多的模型可以直接套用,在使用体验上比Midjourney和DALL-E更加强大。Stable Diffusion使用的模型有下列几大类,对照模型网站 https://civitai

我用 GitHub 9.8k 的 Go 语言 2D 游戏引擎写了个游戏

游戏引擎的贡献者依旧在积极维护,是一个兼具学习 & 娱乐的项目!为此我也用这个引擎写了一个生存游戏: avoid-the-enemies

Cert Manager 申请 SSL 证书流程及相关概念 - 一

2022.3.9 用 cert-manager 申请成功通配符证书 (*.ewhisper.cn), 2022.4.30 该证书距离过期还有 30 天,cert-manager 进行自动续期,但是却失败了。😱😱😱 然后过了几天,在 2022.5.8, 最终成功了。如下图: 正好借着这个情况捋一