Skip to content

Commit

Permalink
stream: yield expected Error class on zlib errors
Browse files Browse the repository at this point in the history
PR-URL: nodejs#50712
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
  • Loading branch information
panva authored and martenrichter committed Nov 26, 2023
1 parent 15c5b31 commit 8a2bc14
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 23 deletions.
50 changes: 41 additions & 9 deletions lib/internal/webstreams/adapters.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
'use strict';

const {
ArrayPrototypeFilter,
ArrayPrototypeMap,
Boolean,
ObjectEntries,
PromisePrototypeThen,
PromiseResolve,
SafePromiseAll,
SafePromisePrototypeFinally,
SafeSet,
TypedArrayPrototypeGetBuffer,
TypedArrayPrototypeGetByteOffset,
TypedArrayPrototypeGetByteLength,
TypedArrayPrototypeGetByteOffset,
TypeError,
Uint8Array,
} = primordials;

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
15 changes: 1 addition & 14 deletions test/wpt/status/compression.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
]
}
},
Expand Down

0 comments on commit 8a2bc14

Please sign in to comment.