Protobuf InvalidProtocolBufferException с некоторыми строками
Мы использовали protobuf v.3 для передачи сообщений от клиента C# на сервер Java через HTTP.
Прото сообщение выглядит так:
message CLIENT_MESSAGE {
string message = 1;
}
И клиент, и сервер используют кодировку UTF-8 для строк.
Все хорошо, когда мы используем короткие строковые значения, такие как "abc", но когда мы пытаемся передать строку с 198 символами в ней, мы ловим исключение:
com.google.protobuf.InvalidProtocolBufferException:
While parsing a protocol message, the input ended unexpectedly in the middle of a field. This could mean either that the input has been truncated or that an embedded message misreported its own length.
Мы попытались сравнить даже байтовый массив, содержащий данные protobuf, и не нашли решения. Для "aaa" строковый байтовый массив начинается с следующих байтов:
10 3 97 97 97
Где 10 - номер поля protobuf, а 3 - длина строки, 69 65 67 - "ааа".
Для строки
"Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
который содержит 198 символов, байтовый массив начинается с этого:
10 198 1 97 97 97....
Где 10 - это номер поля protobuf, а 198 - длина строки, а 1 кажется идентификатором строки или как?
И почему protobuf не может разобрать это сообщение?
Уже потратил почти день на поиски решения этой проблемы, любая помощь приветствуется.
ОБНОВИТЬ:
Мы сделали дампы как с клиента, так и с сервера, и что странно - дампы разные!
Дамп Protobuf от клиента, перед отправкой на сервер:
00000000 0A C6 01 61 61 61 61 61 61 61 61 61 61 61 61 61 ·Æ·aaaaaaaaaaaaa
00000010 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 aaaaaaaaaaaaaaaa
00000020 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 aaaaaaaaaaaaaaaa
00000030 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 aaaaaaaaaaaaaaaa
00000040 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 aaaaaaaaaaaaaaaa
00000050 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 aaaaaaaaaaaaaaaa
00000060 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 aaaaaaaaaaaaaaaa
00000070 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 aaaaaaaaaaaaaaaa
00000080 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 aaaaaaaaaaaaaaaa
00000090 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 aaaaaaaaaaaaaaaa
000000A0 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 aaaaaaaaaaaaaaaa
000000B0 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 aaaaaaaaaaaaaaaa
000000C0 61 61 61 61 61 61 61 61 61 aaaaaaaaa
Дамп Protobuf, который сервер получает:
0000: 0A EF BF BD 01 61 61 61 61 61 61 61 61 61 61 61 .....aaaaaaaaaaa
0010: 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 aaaaaaaaaaaaaaaa
0020: 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 aaaaaaaaaaaaaaaa
0030: 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 aaaaaaaaaaaaaaaa
0040: 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 aaaaaaaaaaaaaaaa
0050: 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 aaaaaaaaaaaaaaaa
0060: 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 aaaaaaaaaaaaaaaa
0070: 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 aaaaaaaaaaaaaaaa
0080: 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 aaaaaaaaaaaaaaaa
0090: 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 aaaaaaaaaaaaaaaa
00A0: 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 aaaaaaaaaaaaaaaa
00B0: 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 aaaaaaaaaaaaaaaa
00C0: 61 61 61 61 61 61 61 61 61 61 61 aaaaaaaaaaa
Как вы можете видеть, заголовки данных protobuf различаются... Как это могло произойти?
ОБНОВЛЕНИЕ 2: мы провели исследование и обнаружили, что эта проблема возникает только со строками длиннее 128 символов. Если строка состоит из 128 символов или меньше - проблем нет.
2 ответа
Где 10 - номер поля протокола;
Да; поле 1, с префиксом длины.
и 198 - длина строки, а 1 похоже на строковый идентификатор, или что?
198 1
длина строки, закодированная в кодировке "varint"; вычисляется как целое число 198, но для кодирования требуется два байта.
И почему protobuf не может разобрать это сообщение?
Нам нужно увидеть остальные байты; библиотека может быть очень правильной, если у вас нет всех байтов. У вас есть все байты для сбойного случая, возможно, в виде hex или base-64?
Ну, наконец, проблема была в кодировке символов - мы попытались преобразовать двоичные данные protobuf в строку.
Если вам нужно передать двоичные данные protobuf в виде строки - сначала закодируйте их в base64 на клиенте, а затем декодируйте из base 64 на сервере.
Спасибо @Marc Gravell за помощь