Home > Backend Development > Golang > How Can I Parse Unknown Protobuf Messages Without Type Information?

How Can I Parse Unknown Protobuf Messages Without Type Information?

Patricia Arquette
Release: 2024-11-28 01:36:10
Original
682 people have browsed it

How Can I Parse Unknown Protobuf Messages Without Type Information?

Unknown Proto Message Demarshalling Without Type Information

While protobuf's proto.Unmarshal() method requires a known message type, unknown messages present a challenge. However, we can extract limited information using the protowire package.

Approach:

  1. Use protowire.ConsumeField() to iterate through the unknown message payload.
  2. Identify the field type, which could be:

    • Varint
    • Fixed64
    • Bytes
    • StartGroup
    • Fixed32
  3. Parse the field payload based on its type.
  4. Handle sub-messages by recursively parsing their payloads.

Data Model:

type Field struct {
    Tag Tag
    Val Val
}

type Tag struct {
    Num int32
    Type protowire.Type
}

type Val struct {
    Payload interface{}
    Length int
}
Copy after login

Parser:

func parseUnknown(b []byte) []Field {
    // Iteratively consume and parse fields
    for len(b) > 0 {
        // Read field tag and length
        n, t, fieldlen := protowire.ConsumeField(b)
        if fieldlen < 1 {
            return nil
        }
        field := Field{Tag: Tag{Num: int32(n), Type: t}}

        // Read and process tag and value content
        _, _, taglen := protowire.ConsumeTag(b[:fieldlen])
        if taglen < 1 {
            return nil
        }
        var v interface{}
        var vlen int
        switch t {
            case protowire.VarintType:
                v, vlen = protowire.ConsumeVarint(b[taglen:fieldlen])
            case protowire.Fixed64Type:
                v, vlen = protowire.ConsumeFixed64(b[taglen:fieldlen])
            case protowire.BytesType:
                v, vlen = protowire.ConsumeBytes(b[taglen:fieldlen])
                sub := parseUnknown(v.([]byte))
                if sub != nil {
                    v = sub
                }
            case protowire.StartGroupType:
                v, vlen = protowire.ConsumeGroup(n, b[taglen:fieldlen])
                sub := parseUnknown(v.([]byte))
                if sub != nil {
                    v = sub
                }
            case protowire.Fixed32Type:
                v, vlen = protowire.ConsumeFixed32(b[taglen:fieldlen])
        }
        if vlen < 1 {
            return nil
        }

        field.Val = Val{Payload: v, Length: vlen - taglen}
        fields = append(fields, field)
        b = b[fieldlen:]
    }
    return fields
}
Copy after login

Example (Message Structure):

message Foo {
  string a = 1;
  string b = 2;
  Bar bar = 3;
}

message Bar {
  string c = 1;
}
Copy after login

Example (Parsed Output):

main.Field{Tag:main.Tag{Num:1, Type:2}, Val:main.Val{Payload:[]uint8{0x41}, Length:1}}
main.Field{Tag:main.Tag{Num:2, Type:2}, Val:main.Val{Payload:[]uint8{0x42}, Length:1}}
main.Field{Tag:main.Tag{Num:1, Type:2}, Val:main.Val{Payload:[]uint8{0x43}, Length:1}}
main.Field{Tag:main.Tag{Num:3, Type:2}, Val:main.Val{Payload:[]main.Field{main.Field{Tag:main.Tag{Num:1, Type:2}, Val:main.Val{Payload:[]uint8{0x43}, Length:1}}}, Length:3}}
Copy after login

Considerations:

  • Sub-messages: Recursive parsing of bytes payloads identified as messages.
  • Repeated fields: Handled based on identical field tag numbers.
  • Maps: Assumed to be similar to repeated k/v pairs.
  • Oneofs: Union type information is lost, only the actual value is parsed.

While this code does not provide a complete production-grade solution, it offers a method to parse unknown proto payloads while preserving some semantic information.

The above is the detailed content of How Can I Parse Unknown Protobuf Messages Without Type Information?. For more information, please follow other related articles on the PHP Chinese website!

source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Latest Articles by Author
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template