我试图为Postgres协议V3编写一个Katai定义:
我遇到的问题是,除StartupMessage之外的每一条消息都遵循相同的格式。StartupMessage的形状不同。
所以我需要说“对象可以是这两种类型中的一种”,但是我不知道该如何做.
大多数消息的布局如下:
|-----------------------------------------------|
| Type | Length | (Rest of payload)
|-----------------------------------------------|
| Char | Int32 | Bytes
|-----------------------------------------------|但是对于启动消息,在开头没有Type char来标识它:
|-----------------------------------------------|
| Length | Protocol Version | (Rest of payload)
|-----------------------------------------------|
| Int32 | Int32 | Bytes
|-----------------------------------------------|到目前为止,我尝试过这样的方法:
meta:
id: postgres_wire_protocol_frontend_v3
file-extension: postgres_wire_protocol_frontend_v3
endian: be
seq:
- id: type
type: str
encoding: ASCII
size: 1
- id: length
type: u4
- id: body
size: length
type:
switch-on: type
cases:
'"B"': bind_message
'"E"': execute_message
'"Q"': query_message
_: startup_message但不幸的是,这似乎行不通。
有什么办法在凯泰对此进行编码吗?
发布于 2022-04-20 19:33:02
会员免责声明:我是凯泰结构的维护者(见我的GitHub配置文件)。
纵观PostgreSQL文档,StartupMessage似乎只能是“第一条消息”:
消息的第一个字节标识消息类型,接下来的四个字节指定消息其余部分的长度(此长度计数包括自身,但不包括消息类型字节)。消息的其余内容由消息类型确定。由于历史原因,客户机发送的第一条消息(启动消息)没有初始消息类型字节.。
我不知道您的应用程序如何使用Kaitai生成的解析器,所以我不知道如何以适合您的方式使用这些信息。问题中的.ksy片段表明您将使用解析器类PostgresWireProtocolFrontendV3的新实例处理每条消息,因此我建议仅为StartupMessage创建一个新的.ksy文件。
meta:
id: postgres_protocol_startup_message
seq:
- id: len_message
type: u4
- id: body
size: len_message - len_message._sizeof
type: message_body
types:
message_body:
seq:
- id: version_major
type: u2
valid: 3
- id: version_minor
type: u2
valid: 0
# ...注意:len_message._sizeof将在编译时被翻译成4 (这是必要的,因为在PostgreSQL文档中,这个字段被描述为“消息内容的长度(以字节为单位),包括自我长度”)。虚拟sizeof运算符是一个0.9特征
sizeof和bitsizeof操作符(#84) sizeof<u4>,bitsizeof<b13>,sizeof<user_type>file_header._sizeof、flags._bitsizeof (file_header、flags是在当前类型中定义的字段)valid也是在0.9中引入的,目前还没有适当的文档(对不起),但是您可以在#435中阅读它的描述。
在您的应用程序代码中,您可能知道通信的状态(即您是否正在处理第一条消息),所以我假设您会这样做:
message_raw = b'...' # TODO: receive from the socket (probably)
if is_first_message:
startup_message = PostgresProtocolStartupMessage(KaitaiStream(BytesIO(message_raw)))
# ...
is_first_message = False
else:
message = PostgresWireProtocolFrontendV3(KaitaiStream(BytesIO(message_raw)))当然,我不知道您的用例,所以我只是猜测它可能是什么,但希望至少有一些对您有用。
所以我需要说“对象可以是这两种类型中的一种”,但我不知道该如何做。
这不是凯泰结构的工作方式。Kaitai (有意)没有回溯,它被设计用来处理不含糊的二进制格式(参见https://stackoverflow.com/a/55111070/12940655)。虽然可以使用instances进行某种展望以决定接下来的内容,但最好避免它,除非您真的需要它。
https://stackoverflow.com/questions/71898221
复制相似问题