Skip to content

Commit 3e73b1d

Browse files
committed
Handle gRPC compressed payloads
1 parent f5ec9ee commit 3e73b1d

File tree

1 file changed

+20
-4
lines changed

1 file changed

+20
-4
lines changed

src/util/protobuf.ts

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
import parseRawProto from 'rawprotoparse';
2+
import { gunzipSync, inflateSync } from 'zlib';
3+
4+
const GZIP_MAGIC_BYTES = '1f8b';
5+
const DEFLATE_MAGIC_BYTES = new Set<string>(['7801', '785e', '789c', '78da', '7820', '787d', '78bb', '78f9']);
26

37
export function isProbablyProtobuf(input: Uint8Array) {
48
// Protobuf data starts with a varint, consisting of a field
@@ -38,12 +42,24 @@ export const extractProtobufFromGrpc = (input: Buffer) => {
3842
const protobufMessasges: Buffer[] = [];
3943

4044
while (input.length > 0) {
41-
if (input.readInt8() != 0) {
42-
throw new Error("Compressed gRPC messages not yet supported")
45+
const compressionFlag = input.readInt8();
46+
const length = input.readInt32BE(1);
47+
let message = input.slice(5, 5 + length);
48+
49+
if (compressionFlag != 0) {
50+
// TODO: In theory we should check consistency of actual content encoding
51+
// with 'grpc-encoding' header, but we do not have access to it in this context
52+
const magicBytes = message.toString('hex', 0, 2);
53+
if (magicBytes == GZIP_MAGIC_BYTES) {
54+
message = gunzipSync(message);
55+
} else if (DEFLATE_MAGIC_BYTES.has(magicBytes)) {
56+
message = inflateSync(message);
57+
} else {
58+
throw new Error(`Unknown gRPC compression scheme, magic bytes = '${magicBytes}'`);
59+
}
4360
}
4461

45-
const length = input.readInt32BE(1);
46-
protobufMessasges.push(input.slice(5, 5 + length));
62+
protobufMessasges.push(message);
4763
input = input.subarray(5 + length);
4864
}
4965

0 commit comments

Comments
 (0)