DecompressionStream should not accept data after the end

Version

24.0.1

Platform

Darwin 24.4.0 Darwin Kernel Version 24.4.0: Fri Apr 11 18:34:14 PDT 2025; root:xnu-11417.101.15~117/RELEASE_ARM64_T8122 arm64

Subsystem

webstreams

What steps will reproduce the bug?

Run this in Node.js and browsers

deflate:

;(async () => {
  const valid = new Uint8Array([120, 156, 75, 4, 0, 0, 98, 0, 98]) // deflate('a')
  const empty = new Uint8Array(1)
  const invalid = new Uint8Array([...valid, ...empty])
  const double = new Uint8Array([...valid, ...valid])
  for (const chunks of [[valid], [invalid], [valid, empty], [valid, valid], [double]]) {
    try {
      const stream = new Blob(chunks).stream().pipeThrough(new DecompressionStream('deflate'))
      const useFrom = Array.fromAsync && stream.values
      console.log(await (useFrom ? Array.fromAsync(stream) : new Response(stream).blob()))
    } catch (e) {
      console.error(e)
    }
  }
})()

gzip:

;(async () => {
  const valid = new Uint8Array([31, 139, 8, 0, 0, 0, 0, 0, 0, 19, 75, 4, 0, 67, 190, 183, 232, 1, 0, 0, 0]) // gzip('a')
  const empty = new Uint8Array(1)
  const invalid = new Uint8Array([...valid, ...empty])
  const double = new Uint8Array([...valid, ...valid])
  for (const chunks of [[valid], [invalid], [valid, empty], [valid, valid], [double]]) {
    try {
      const stream = new Blob(chunks).stream().pipeThrough(new DecompressionStream('gzip'))
      const useFrom = Array.fromAsync && stream.values
      console.log(await (useFrom ? Array.fromAsync(stream) : new Response(stream).blob()))
    } catch (e) {
      console.error(e)
    }
  }
})()

How often does it reproduce? Is there a required condition?

Always

What is the expected behavior? Why is that the expected behavior?

First one should be valid and produce an blob/array with [97]
The other four with input past the end should throw a TypeError (see refs)

Chrome/Firefox/Safari are consistent with the spec and are throwing a TypeError on any input past the compressed stream.

  • Chrome: TypeError: Junk found after end of compressed data.
  • Firefox: TypeError: Unexpected input after the end of stream
  • Safari: TypeError: Extra bytes past the end.

What do you see instead?

All cases do not throw and produce [ 97 ] for deflate.

For gzip, concatenating inputs concatenates outputs, and [valid, valid] and [double] produce [97, 97] (all other produce [97]).

Additional information

Refs: