Reputation: 41
I'm trying to reverse engineer a client that uploads an audio file to a server, and then uploads the file's metadata in a separate request afterwards. The metadata is serialized in Protobuf, and it uses a fairly simple and readable structure. Here's what it looks like after protoc --decode_raw
:
1 {
1: "title"
2: "This is the audio title"
}
1 {
1: "tags"
2 {
}
}
1 {
1: "loc"
2: "This is the location"
}
1 {
1: "transcription"
2: "A transcript"
}
1 {
1: "mapping"
2 {
1 {
1: 6
2 {
3: 840
}
}
2: 6
}
}
It seems to be just a repeated message at field 1
that holds a key-value pair each time, but sometimes the value is a string, and sometimes it's a more complex message. How can they assign both a string and a message to field 2
if Protobuf only lets you use one value type per field? If I'm going to craft my own request, I need something like this:
message KeyValuePair {
string key = 1;
oneof value {
string str_value = 2;
MessageValue msg_value = 2;
}
}
But that doesn't work, because Field number 2 has already been used in "package.name" by field "str_value"
. Any ideas? I'll be using Python to create and send the request data.
Upvotes: 3
Views: 4525
Reputation: 12270
There is an official way to achieve this: google.protobuf.Any
If a protobuf schema defines an any at the top level, e.g.:
message Root {
repeated google.protobuf.Any value = 1;
}
message Title {
string title= 2;
}
message Tags {
string name = 1;
repeated string tags = 2;
}
Then messages of any Protobuf-defined type can be serialized in a list.
However, I don't think that's what the existing code is doing:
Any
normally includes the type.googleapis.com
type urlAny
, the title / loc fields would be encapsulated in a nested object, not a string at the same level.E.g.:
1 {
1: "type.googleapis.com/Title"
2 {
1: "the title"
}
}
Upvotes: 1