解码节俭对象这些额外的字节是什么?

Decoding Thrift Object what are these extra bytes?

我正在编写一个不依赖于 thrift 定义的纯 JS thrift 解码器。我一直在关注这个方便的指南,它是我过去几天的圣经:https://erikvanoosten.github.io/thrift-missing-specification/

我的解析器几乎可以正常工作了,但是有一个字符串类型给程序带来了麻烦,我不太明白它在做什么。这是 hexdump 的摘录,我尽力对其进行了注释:

正确解析:

000001a0  0a 32 30 32 31 2d 31 31  2d 32 34 16 02 00 18 07  |.2021-11-24.....|
........................blah blah blah............|  |  |
                                       Object End-|  |  |
                           0x18 & 0xF = 0x8 = Binary-|  |
             The binary sequence is 0x7 characters long-|
000001b0  53 65 61 74 74 6c 65 18  02 55 53 18 02 55 53 18  |Seattle..US..US.|
          S  E  A  T  T  L  E  |___|  U  S  |___| U  S
    Another string, 2 bytes long |------------|

到目前为止一切顺利。

但后来我想到了这一点: 我要提取的字符串是 "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4592.0 Safari/537.36 Edg/94.0.975.1" 并且长 134 个字节。

000001c0  09 54 61 68 6f 65 2c 20  43 41 12 12 00 00 08 c8  |.Tahoe, CA......|
                                 Object ends here-|  |  |
                           0x8 & 0xF = 0x8 = Binary -|  |
                                  0xc8 bytes long (200)-|
000001d0  01 86 01 4d 6f 7a 69 6c  6c 61 2f 35 2e 30 20 28  |...Mozilla/5.0 (|
          |  |  |  M  o  z  i  l   l  a  
        ???? |--|-134, encoded as var-int
000001e0  4d 61 63 69 6e 74 6f 73  68 3b 20 49 6e 74 65 6c  |Macintosh; Intel|

如您所见,我有一个字节序列 0x08 0xC8 0x01 0x86 0x01,其中包含我正在寻找的字符串的长度,后面是我正在寻找的字符串,但有 3 个额外的字节目的不明确。

0x01 尤其令人困惑,因为它既不是类型标识符,也似乎没有具体值。

我错过了什么?

Thrift 支持可插入序列化方案。在树中,你有二进制、紧凑和 json。出了树什么都行。看样子你是在尝试解码紧凑协议,所以我会相应地回答。

Thrift RPC 调用中发送的所有内容和返回的所有内容都打包在一个结构中。结构中的每个字段都有一个 1 字节类型和一个 2 字节字段 ID 前缀。在紧凑协议中,字段 id 在可能的情况下被增量编码到类型中,并且所有 int 都被压缩到仅存储它们所需的位(和一些标志)。因为 int 现在可以占用不同数量的字节,所以我们需要知道它们何时结束。 Compact 协议将 int 位编码为一个字节的 7 位,如果下一个字节继续 int,则将高位设置为 1。如果高位为 0,则 int 完成。因此 int 5 (101) 将在一个字节中编码为 0000101。Compact 知道这是 int 的结尾,因为高位是 0.

在您的例子中,int 134(二进制 10000110)将需要 2 个字节进行编码,因为它超过 7 位。前 7 位存储在字节 1 中,0x80 位设置为标志“int continues”。第二个也是最后一个字节对最后一位 (00000001) 进行编码。你以为的 134 只是前七位的编码。杂散的 1 是 134 的最后一位。

我建议您使用 in tree 源来执行任何需要的协议 encoding/decoding。它已经编写和测试:https://github.com/apache/thrift/blob/master/lib/nodejs/lib/thrift/compact_protocol.js

字节序列如下

  • 0x08:String类型,后面2个字节定义elementId
  • 0xC8 0x01:ElementId,16位编码
  • 0x86 0x01:字符串长度,编码为 var int

事实证明,如果类型标识符不包含定义 elementId 的位,则 elementId 将存储在接下来的 2 个字节中。