diff --git a/lib/internal/webstreams/adapters.js b/lib/internal/webstreams/adapters.js index 878fd0a0d4d..cffa549eafd 100644 --- a/lib/internal/webstreams/adapters.js +++ b/lib/internal/webstreams/adapters.js @@ -1,13 +1,19 @@ 'use strict'; const { + ArrayPrototypeFilter, + ArrayPrototypeMap, + Boolean, + ObjectEntries, PromisePrototypeThen, PromiseResolve, SafePromiseAll, SafePromisePrototypeFinally, + SafeSet, TypedArrayPrototypeGetBuffer, - TypedArrayPrototypeGetByteOffset, TypedArrayPrototypeGetByteLength, + TypedArrayPrototypeGetByteOffset, + TypeError, Uint8Array, } = primordials; @@ -82,6 +88,38 @@ const { UV_EOF } = internalBinding('uv'); const encoder = new TextEncoder(); +// Collect all negative (error) ZLIB codes and Z_NEED_DICT +const ZLIB_FAILURES = new SafeSet([ + ...ArrayPrototypeFilter( + ArrayPrototypeMap( + ObjectEntries(internalBinding('constants').zlib), + ({ 0: code, 1: value }) => (value < 0 ? code : null), + ), + Boolean, + ), + 'Z_NEED_DICT', +]); + +/** + * @param {Error|null} cause + * @returns {Error|null} + */ +function handleKnownInternalErrors(cause) { + switch (true) { + case cause?.code === 'ERR_STREAM_PREMATURE_CLOSE': { + return new AbortError(undefined, { cause }); + } + case ZLIB_FAILURES.has(cause?.code): { + // eslint-disable-next-line no-restricted-syntax + const error = new TypeError(undefined, { cause }); + error.code = cause.code; + return error; + } + default: + return cause; + } +} + /** * @typedef {import('../../stream').Writable} Writable * @typedef {import('../../stream').Readable} Readable @@ -137,10 +175,7 @@ function newWritableStreamFromStreamWritable(streamWritable) { } const cleanup = finished(streamWritable, (error) => { - if (error?.code === 'ERR_STREAM_PREMATURE_CLOSE') { - const err = new AbortError(undefined, { cause: error }); - error = err; - } + error = handleKnownInternalErrors(error); cleanup(); // This is a protection against non-standard, legacy streams @@ -440,10 +475,7 @@ function newReadableStreamFromStreamReadable(streamReadable, options = kEmptyObj streamReadable.pause(); const cleanup = finished(streamReadable, (error) => { - if (error?.code === 'ERR_STREAM_PREMATURE_CLOSE') { - const err = new AbortError(undefined, { cause: error }); - error = err; - } + error = handleKnownInternalErrors(error); cleanup(); // This is a protection against non-standard, legacy streams diff --git a/test/wpt/status/compression.json b/test/wpt/status/compression.json index cf979345ea8..31a5a78b69d 100644 --- a/test/wpt/status/compression.json +++ b/test/wpt/status/compression.json @@ -14,21 +14,8 @@ "decompression-corrupt-input.tentative.any.js": { "fail": { "expected": [ - "truncating the input for 'deflate' should give an error", "trailing junk for 'deflate' should give an error", - "format 'deflate' field CMF should be error for 0", - "format 'deflate' field FLG should be error for 157", - "format 'deflate' field DATA should be error for 5", - "format 'deflate' field ADLER should be error for 255", - "truncating the input for 'gzip' should give an error", - "trailing junk for 'gzip' should give an error", - "format 'gzip' field ID should be error for 255", - "format 'gzip' field CM should be error for 0", - "format 'gzip' field FLG should be error for 2", - "format 'gzip' field DATA should be error for 3", - "format 'gzip' field CRC should be error for 0", - "format 'gzip' field ISIZE should be error for 1", - "the deflate input compressed with dictionary should give an error" + "trailing junk for 'gzip' should give an error" ] } },