【问题标题】:Decoding Thrift Object what are these extra bytes?解码 Thrift 对象这些额外的字节是什么?
【发布时间】:2021-12-07 15:43:16
【问题描述】:

我正在编写一个不依赖于 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 尤其令人困惑,因为它既不是类型标识符,也似乎没有具体值。

我错过了什么?

【问题讨论】:

    标签: hex thrift decoding thrift-protocol


    【解决方案1】:

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

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

    在您的情况下,int 134(二进制 10000110)将需要 2 个字节进行编码,因为它超过 7 位。前 7 位存储在字节 1 中,0x80 位设置为标记“int 继续”。第二个也是最后一个字节编码最后一位(00000001)。您认为 134 只是前七位的编码。流浪者 1 是 134 的最后一位。

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

    【讨论】:

    • 好吧,我明白了。这将0x86 0x01 部分解释为(0x86 & 0x7F) + (0x01 << 7) = 134。但是,这并不能解释前面的 0x08 0xC8 0x01 字节,据我了解,这仍然意味着“二进制序列,提前 200 个字节”
    • 很难确切地说出发生了什么,因为我不知道原始消息是什么,也没有完整的编码消息,我的猜测,如答案中所述,是 0x08是类型,0xc8 0x01 是字段 ID(不是 len)。看看链接。这是用于执行这种精确编码的 Javascipt 代码(您可以使用它并且它会工作,或者您可以阅读它并理解所有的细微之处,例如我提到了增量编码)。
    • 我认为字段 id 限制为 4 位。但它看起来像是 4 位,作为类型标识符的一部分,或者如果是 0,那么它就是接下来的 16 位。这是有道理的。
    • 字段 id 尽可能进行增量编码(如上面的答案中所述),如果它不能与类型打包,则直接保存并压缩(与所有其他整数一样,因此不一定是 2 个字节如上面的答案所述)。认为有一个捷径可以处理解码是很诱人的,但我提供的链接中的代码与它所得到的一样短。如果您想可靠地解码 Thrift 紧凑协议,您应该使用该代码或理解它。
    【解决方案2】:

    字节序列如下

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

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

    【讨论】:

    • 这是一个不完整的描述。当您在解码器中遇到布尔时会发生什么?当你遇到负数时会发生什么?当 id 可以用 1 个字节编码时会发生什么。
    • @codeSF 问题不在于如何解码布尔值或负数,而在于0x08 0xC8 0x01 0x86 0x01 序列。我已经弄清楚了其他所有事情。
    猜你喜欢
    • 2018-07-20
    • 2012-07-22
    • 1970-01-01
    • 1970-01-01
    • 2013-11-09
    • 2012-11-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多