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头信息如何处理的更多相关文章

  1. 借助FRP反向代理实现内网穿透

    一.frp 是什么? frp 是一个专注于内网穿透的高性能的反向代理应用,支持 TCP.UDP.HTTP.HTTPS 等多种协议.可以将内网服务以安全.便捷的方式通过具有公网 IP 节点的中转暴露到公 ...

  2. 分享一个内网穿透工具frp

    首先简单介绍一下内网穿透: 内网穿透:通过公网,访问局域网里的IP地址与端口,这需要将局域网里的电脑端口映射到公网的端口上:这就需要用到反向代理,即在公网服务器上必须运行一个服务程序,然后在局域网中需 ...

  3. 【代理】内网穿透工具 frp&frps

    frp 是一个高性能的反向代理应用,可以帮助您轻松地进行内网穿透,对外网提供服务,支持 tcp, http, https 等协议类型,并且 web 服务支持根据域名进行路由转发. ### frp 的作 ...

  4. frp实现基于反向代理的内网穿透

    个人博客主页: xzajyjs.cn frp是什么 简单地说,frp就是一个反向代理软件,它体积轻量但功能很强大,可以使处于内网或防火墙后的设备对外界提供服务,它支持HTTP.TCP.UDP等众多协议 ...

  5. 【新晋开源项目】内网穿透神器[中微子代理] 加入 Dromara 开源社区

    1.关于作者 dromara开源组织成员,dromara/neutrino-proxy项目作者 名称:傲世孤尘.雨韵诗泽 名言: 扎根土壤,心向太阳.积蓄能量,绽放微光. 拘浊酒邀明月,借赤日暖苍穹. ...

  6. 代理内网上网-iptables

    代理内网上网-iptables 1.1 环境说明 主机A:(能上网) ip:内172.16.1.7/24 外10.0.0.7/24 系统CentOS 6.9 主机B:(不能上网) ip:内172.16 ...

  7. [原创]K8飞刀20150725 支持SOCKS5代理(内网渗透)

    工具: K8飞刀编译: 自己查壳组织: K8搞基大队[K8team]作者: K8拉登哥哥博客: http://qqhack8.blog.163.com发布: 2015/7/26 3:41:11 简介: ...

  8. Mysql-proxy代理内网数据库

    Mysql-proxy 参考:https://segmentfault.com/q/1010000000394160 情景分析:首先您需要正在使用UCloud云主机(uhoust)以及云数据库(udb ...

  9. ssh后门反向代理实现内网穿透

    如图所示,内网主机ginger 无公网IP地址,防火墙只允许ginger连接blackbox.example.com主机 假如你是ginger的管理员root,你想要用tech主机连接ginger主机 ...

  10. CentOS squid代理内网主机上网 openVpn配置

随机推荐

  1. Javaweb文件上传至服务器/从服务器下载

    Javaweb文件上传至服务器/从服务器下载 思路图 文件上传思路: 也可以直接看代码 判断是不是文件表单(判断form的enctype是不是="multipart/form-data&qu ...

  2. 鸟类识别系统Python+Django+TensorFlow+卷积神经网络算法【完整代码】

    一.介绍 鸟类识别系统,使用Python作为主要开发语言,基于深度学习TensorFlow框架,搭建卷积神经网络算法.并通过对数据集进行训练,最后得到一个识别精度较高的模型.并基于Django框架,开 ...

  3. h2database BTree 设计实现与查询优化思考

    h2database 是使用Java 编写的开源数据库,兼容ANSI-SQL89. 即实现了常规基于 BTree 的存储引擎,又支持日志结构存储引擎.功能非常丰富(死锁检测机制.事务特性.MVCC.运 ...

  4. Hugging News #0703: 在浏览器中运行 Whisper 模型、WAIC 分论坛活动邀请报名

    每一周,我们的同事都会向社区的成员们发布一些关于 Hugging Face 相关的更新,包括我们的产品和平台更新.社区活动.学习资源和内容更新.开源库和模型更新等,我们将其称之为「Hugging Ne ...

  5. vue3 安装 3d-force-graph

    1.首先创建vue3的项目 2.创建好后通过开发工具打开项目并打开命令行,输入指令 npm install 3d-force-graph 安装即可 3.在使用的页面中引入 3d-force-graph ...

  6. Windows电脑环境变量(用户变量、系统变量)的修改

      本文介绍在Windows 10操作系统中,进行用户变量.系统变量等两种环境变量的新建.修改与删除的详细方法.   在很多时候,我们需要对Windows电脑的环境变量加以修改,例如安装一些专业软件. ...

  7. nginx配置文件内容(1)

    nginx.conf内容 在Nginx服务器的主配置文件nginx.conf中,包括全局配置.I/O事件配置.HTTP配置这三大块内容,配置语句的格式为"关键字  值:"(末尾以分 ...

  8. SketchUp Pro 2023 下载和安装教程

    SketchUp Pro 2023 下载和安装教程 下载链接 123云盘:https://www.123pan.com/s/JyAKVv-NTXB.html 安装教程 演示操作系统:Windows 1 ...

  9. Geo

    Geo 应用情景 打车时寻找半径在多少范围的司机 查找附近的酒店,微信摇一摇 Linux中文乱码如何处理? redis-cli --raw docker: docker exec -it redis ...

  10. Vue详解----一篇带你从头领悟到尾,享受飞升的感觉

    脚手架文件结构 """ ├── node_modules ├── public │ ├── favicon.ico: 页签图标 │ └── index.html: 主页面 ...