diff --git a/packages/connect-node-test/src/compression.spec.ts b/packages/connect-node-test/src/compression.spec.ts index 25ce2bf50..fc1d5006f 100644 --- a/packages/connect-node-test/src/compression.spec.ts +++ b/packages/connect-node-test/src/compression.spec.ts @@ -40,6 +40,10 @@ describe("compression", () => { const equal = payload.every((value, index) => b[index] === value); expect(equal).toBeTrue(); }); + it("should decompress zero-length payload", async () => { + const b = await compression.decompress(new Uint8Array(0), 0xffffffff); + expect(b.byteLength).toBe(0); + }); it("should raise resource_exhausted if maxReadBytes exceeded", async () => { try { await compression.decompress(payloadCompressed, 2); diff --git a/packages/connect-node/src/compression.ts b/packages/connect-node/src/compression.ts index 3cae87f5e..643a1d278 100644 --- a/packages/connect-node/src/compression.ts +++ b/packages/connect-node/src/compression.ts @@ -35,6 +35,9 @@ export const compressionGzip: Compression = { return gzip(bytes, {}); }, decompress(bytes, readMaxBytes) { + if (bytes.length == 0) { + return Promise.resolve(new Uint8Array(0)); + } return wrapZLibErrors( gunzip(bytes, { maxOutputLength: readMaxBytes, @@ -56,6 +59,9 @@ export const compressionBrotli: Compression = { return brotliCompress(bytes, {}); }, decompress(bytes, readMaxBytes) { + if (bytes.length == 0) { + return Promise.resolve(new Uint8Array(0)); + } return wrapZLibErrors( brotliDecompress(bytes, { maxOutputLength: readMaxBytes, diff --git a/packages/connect/src/protocol/compression.ts b/packages/connect/src/protocol/compression.ts index 7492f5293..5e007b991 100644 --- a/packages/connect/src/protocol/compression.ts +++ b/packages/connect/src/protocol/compression.ts @@ -42,6 +42,8 @@ export interface Compression { /** * Decompress a chunk of data. * + * A zero-length chunk is acceptable, and will return a zero-length result. + * * Raises a ConnectError with Code.InvalidArgument if the decompressed * size exceeds readMaxBytes. */