经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » Rust » 查看文章
9. 用Rust手把手编写一个wmproxy(代理,内网穿透等), HTTP2改造篇之HPACK示例, 了解http2头信息如何处理
来源:cnblogs  作者:问蒙服务框架  时间:2023/10/9 9:22:17  对本文有异议

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

最终的填充值:

  1. 0 1 2 3 4 5 6 7
  2. +---+---+---+---+---+---+---+---+
  3. | X | X | X | 1 | 1 | 1 | 1 | 1 | Prefix = 31, I = 1306
  4. | 1 | 0 | 0 | 1 | 1 | 0 | 1 | 0 | 1306>=128, encode(154), I=1306/128
  5. | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 10<128, encode(10), done
  6. +---+---+---+---+---+---+---+---+

头部编码示例

在静态列表中索引

以下待索引的值

  1. :method: GET

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

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

以下示例

  1. custom-key: custom-header

十六进制表示

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

解码过程

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

动态表 (解码之后):

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

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

以下示例

  1. :path: /sample/path

十六进制表示

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

解码过程

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

永不索引,未使用HUFFMAN

以下示例

  1. password: secret

十六进制表示

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

解码过程

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

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

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

第一次请求. 示例如下

  1. :method: GET
  2. :scheme: http
  3. :path: /
  4. :authority: www.example.com

十六进制表示

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

解码过程

  1. 82 | == Indexed - 静态表 ==
  2. | idx = 2
  3. | -> :method: GET
  4. 86 | == Indexed - 静态表 ==
  5. | idx = 6
  6. | -> :scheme: http
  7. 84 | == Indexed - 静态表 ==
  8. | idx = 4
  9. | -> :path: /
  10. 41 | == 01开头请求索引 indexed ==
  11. | Indexed name (idx = 1)
  12. | :authority
  13. 0f | Literal value (长度15)
  14. 7777 772e 6578 616d 706c 652e 636f 6d | www.example.com
  15. | -> :authority:
  16. | www.example.com

动态列表 (解码后):

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

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

  1. :method: GET
  2. :scheme: http
  3. :path: /
  4. :authority: www.example.com
  5. cache-control: no-cache

十六进制表示

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

解码过程

  1. 82 | == Indexed - 静态表 ==
  2. | idx = 2
  3. | -> :method: GET
  4. 86 | == Indexed - 静态表 ==
  5. | idx = 6
  6. | -> :scheme: http
  7. 84 | == Indexed - 静态表 ==
  8. | idx = 4
  9. | -> :path: /
  10. be | == Indexed - 动态表,索引值62及以上的为动态表 ==
  11. | idx = 62
  12. | -> :authority:
  13. | www.example.com
  14. 58 | == Literal indexed ==
  15. | Indexed name (idx = 24)
  16. | cache-control
  17. 08 | Literal value (8)
  18. 6e6f 2d63 6163 6865 | no-cache
  19. | -> cache-control: no-cache

动态列表 (解码后):

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

第三次请求. 示例如下

  1. :method: GET
  2. :scheme: https
  3. :path: /index.html
  4. :authority: www.example.com
  5. custom-key: custom-value

十六进制表示

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

解码过程

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

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

第一次请求. 示例如下

  1. :method: GET
  2. :scheme: http
  3. :path: /
  4. :authority: www.example.com

十六进制表示

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

比之前少了3字节

解码过程

  1. 82 | == Indexed - 静态表 ==
  2. | idx = 2
  3. | -> :method: GET
  4. 86 | == Indexed - 静态表 ==
  5. | idx = 6
  6. | -> :scheme: http
  7. 84 | == Indexed - 静态表 ==
  8. | idx = 4
  9. | -> :path: /
  10. 41 | == Literal indexed ==
  11. | Indexed name (idx = 1)
  12. | :authority
  13. 8c | Literal value (长度12)
  14. | Huffman encoded:
  15. f1e3 c2e5 f23a 6ba0 ab90 f4ff | .....:k.....
  16. | Decoded:
  17. | www.example.com
  18. | -> :authority:
  19. | www.example.com

动态列表 (解码后):

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

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

  1. :method: GET
  2. :scheme: http
  3. :path: /
  4. :authority: www.example.com
  5. cache-control: no-cache

十六进制表示

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

比之前少了2字节

解码过程

  1. 82 | == Indexed - 静态表 ==
  2. | idx = 2
  3. | -> :method: GET
  4. 86 | == Indexed - 静态表 ==
  5. | idx = 6
  6. | -> :scheme: http
  7. 84 | == Indexed - 静态表 ==
  8. | idx = 4
  9. | -> :path: /
  10. be | == Indexed - 动态表 ==
  11. | idx = 62
  12. | -> :authority:
  13. | www.example.com
  14. 58 | == Literal indexed ==
  15. | Indexed name (idx = 24)
  16. | cache-control
  17. 86 | Literal value (长度6)
  18. | Huffman encoded:
  19. a8eb 1064 9cbf | ...d..
  20. | Decoded:
  21. | no-cache
  22. | -> cache-control: no-cache

动态列表 (解码后):

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

第三次请求. 示例如下

  1. :method: GET
  2. :scheme: https
  3. :path: /index.html
  4. :authority: www.example.com
  5. custom-key: custom-value

十六进制表示

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

比之前少了5字节

解码过程

  1. 82 | == Indexed - 静态表 ==
  2. | idx = 2
  3. | -> :method: GET
  4. 87 | == Indexed - 静态表 ==
  5. | idx = 7
  6. | -> :scheme: https
  7. 85 | == Indexed - 静态表 ==
  8. | idx = 5
  9. | -> :path: /index.html
  10. bf | == Indexed - 动态表 ==
  11. | idx = 63
  12. | -> :authority:
  13. | www.example.com
  14. 40 | == Literal indexed ==
  15. 88 | Literal name (长度8)
  16. | Huffman encoded:
  17. 25a8 49e9 5ba9 7d7f | %.I.[.}.
  18. | Decoded:
  19. | custom-key
  20. 89 | Literal value (长度9)
  21. | Huffman encoded:
  22. 25a8 49e9 5bb8 e8b4 bf | %.I.[....
  23. | Decoded:
  24. | custom-value
  25. | -> custom-key:
  26. | custom-value

动态列表 (解码后):

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

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

完整的返回示例(HUFFMAN)

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

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

第一次返回. 示例如下

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

十六进制表示

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

解码过程

  1. 48 | == Literal indexed ==
  2. | Indexed name (idx = 8)
  3. | :status
  4. 82 | Literal value (长度2)
  5. | Huffman encoded:
  6. 6402 | d.
  7. | Decoded:
  8. | 302
  9. | -> :status: 302
  10. 58 | == Literal indexed ==
  11. | Indexed name (idx = 24)
  12. | cache-control
  13. 85 | Literal value (长度5)
  14. | Huffman encoded:
  15. aec3 771a 4b | ..w.K
  16. | Decoded:
  17. | private
  18. | -> cache-control: private
  19. 61 | == Literal indexed ==
  20. | Indexed name (idx = 33)
  21. | date
  22. 96 | Literal value (长度22)
  23. | Huffman encoded:
  24. d07a be94 1054 d444 a820 0595 040b 8166 | .z...T.D. .....f
  25. e082 a62d 1bff | ...-..
  26. | Decoded:
  27. | Mon, 21 Oct 2013 20:13:21
  28. | GMT
  29. | -> date: Mon, 21 Oct 2013
  30. | 20:13:21 GMT
  31. 6e | == Literal indexed ==
  32. | Indexed name (idx = 46)
  33. | location
  34. 91 | Literal value (长度17)
  35. | Huffman encoded:
  36. 9d29 ad17 1863 c78f 0b97 c8e9 ae82 ae43 | .)...c.........C
  37. d3 | .
  38. | Decoded:
  39. | https://www.example.com
  40. | -> location:
  41. | https://www.example.com

动态列表 (解码后):

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

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

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

十六进制表示

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

解码过程

  1. 48 | == Literal indexed ==
  2. | Indexed name (idx = 8)
  3. | :status
  4. 83 | Literal value (长度3)
  5. | Huffman encoded:
  6. 640e ff | d..
  7. | Decoded:
  8. | 307
  9. | - evict: :status: 302
  10. | -> :status: 307
  11. c1 | == Indexed - Add ==
  12. | idx = 65
  13. | -> cache-control: private
  14. c0 | == Indexed - Add ==
  15. | idx = 64
  16. | -> date: Mon, 21 Oct 2013
  17. | 20:13:21 GMT
  18. bf | == Indexed - Add ==
  19. | idx = 63
  20. | -> location:
  21. | https://www.example.com

动态列表 (解码后):

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

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

第三次请求. 示例如下

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

十六进制表示

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

比之前少了5字节

解码过程

  1. 88 | == Indexed - 静态表 ==
  2. | idx = 8
  3. | -> :status: 200
  4. c1 | == Indexed - 动态表 ==
  5. | idx = 65
  6. | -> cache-control: private
  7. 61 | == Literal indexed ==
  8. | Indexed name (idx = 33)
  9. | date
  10. 96 | Literal value (长度22)
  11. | Huffman encoded:
  12. d07a be94 1054 d444 a820 0595 040b 8166 | .z...T.D. .....f
  13. e084 a62d 1bff | ...-..
  14. | Decoded:
  15. | Mon, 21 Oct 2013 20:13:22
  16. | GMT
  17. | - evict: cache-control:
  18. | private
  19. | -> date: Mon, 21 Oct 2013
  20. | 20:13:22 GMT
  21. c0 | == Indexed - Add ==
  22. | idx = 64
  23. | -> location:
  24. | https://www.example.com
  25. 5a | == Literal indexed ==
  26. | Indexed name (idx = 26)
  27. | content-encoding
  28. 83 | Literal value (长度3)
  29. | Huffman encoded:
  30. 9bd9 ab | ...
  31. | Decoded:
  32. | gzip
  33. | - evict: date: Mon, 21 Oct
  34. | 2013 20:13:21 GMT
  35. | -> content-encoding: gzip
  36. 77 | == Literal indexed ==
  37. | Indexed name (idx = 55)
  38. | set-cookie
  39. ad | Literal value (长度45)
  40. | Huffman encoded:
  41. 94e7 821d d7f2 e6c7 b335 dfdf cd5b 3960 | .........5...[9`
  42. d5af 2708 7f36 72c1 ab27 0fb5 291f 9587 | ..'..6r..'..)...
  43. 3160 65c0 03ed 4ee5 b106 3d50 07 | 1`e...N...=P.
  44. | Decoded:
  45. | foo=ASDJKHQKBZXOQWEOPIUAXQ
  46. | WEOIU; max-age=3600; versi
  47. | on=1
  48. | - evict: location:
  49. | https://www.example.com
  50. | - evict: :status: 307
  51. | -> set-cookie: foo=ASDJKHQ
  52. | KBZXOQWEOPIUAXQWEOIU; ma
  53. | x-age=3600; version=1

动态列表 (解码后):

  1. [ 1->62] (s = 98) set-cookie: foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU;
  2. max-age=3600; version=1
  3. [ 2->63] (s = 52) content-encoding: gzip
  4. [ 3->64] (s = 65) date: Mon, 21 Oct 2013 20:13:22 GMT
  5. 总长度: 215

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

总结

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

原文链接:https://www.cnblogs.com/luojiawaf/p/17750621.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号