Skip to content

Commit

Permalink
stream: treat compression web stream format per its WebIDL definition
Browse files Browse the repository at this point in the history
PR-URL: nodejs#50631
Reviewed-By: James M Snell <[email protected]>
Reviewed-By: Matteo Collina <[email protected]>
  • Loading branch information
panva authored and nodejs-github-bot committed Nov 12, 2023
1 parent 635a5c8 commit 9d652f4
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 59 deletions.
41 changes: 5 additions & 36 deletions lib/internal/crypto/webidl.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,44 +19,29 @@ const {
MathTrunc,
Number,
NumberIsFinite,
ObjectAssign,
ObjectPrototypeIsPrototypeOf,
SafeArrayIterator,
SafeSet,
String,
SymbolIterator,
TypedArrayPrototypeGetBuffer,
TypedArrayPrototypeGetSymbolToStringTag,
TypeError,
globalThis: {
SharedArrayBuffer,
},
} = primordials;

const {
makeException,
createEnumConverter,
} = require('internal/webidl');

const {
kEmptyObject,
setOwnProperty,
} = require('internal/util');
const { CryptoKey } = require('internal/crypto/webcrypto');
const { getDataViewOrTypedArrayBuffer } = require('internal/crypto/util');

function codedTypeError(message, errorProperties = kEmptyObject) {
// eslint-disable-next-line no-restricted-syntax
const err = new TypeError(message);
ObjectAssign(err, errorProperties);
return err;
}

function makeException(message, opts = kEmptyObject) {
const prefix = opts.prefix ? opts.prefix + ': ' : '';
const context = opts.context?.length === 0 ?
'' : (opts.context ?? 'Value') + ' ';
return codedTypeError(
`${prefix}${context}${message}`,
{ code: opts.code || 'ERR_INVALID_ARG_TYPE' },
);
}

// https://tc39.es/ecma262/#sec-tonumber
function toNumber(value, opts = kEmptyObject) {
switch (typeof value) {
Expand Down Expand Up @@ -308,22 +293,6 @@ function createDictionaryConverter(name, dictionaries) {
};
}

function createEnumConverter(name, values) {
const E = new SafeSet(values);

return function(V, opts = kEmptyObject) {
const S = String(V);

if (!E.has(S)) {
throw makeException(
`value '${S}' is not a valid enum value of type ${name}.`,
{ __proto__: null, ...opts, code: 'ERR_INVALID_ARG_VALUE' });
}

return S;
};
}

function createSequenceConverter(converter) {
return function(V, opts = kEmptyObject) {
if (type(V) !== 'Object') {
Expand Down
40 changes: 39 additions & 1 deletion lib/internal/webidl.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ const {
NumberIsNaN,
NumberMAX_SAFE_INTEGER,
NumberMIN_SAFE_INTEGER,
ObjectAssign,
SafeSet,
String,
TypeError,
} = primordials;

const {
Expand Down Expand Up @@ -173,8 +176,43 @@ converters.DOMString = function DOMString(V) {
return String(V);
};

function codedTypeError(message, errorProperties = kEmptyObject) {
// eslint-disable-next-line no-restricted-syntax
const err = new TypeError(message);
ObjectAssign(err, errorProperties);
return err;
}

function makeException(message, opts = kEmptyObject) {
const prefix = opts.prefix ? opts.prefix + ': ' : '';
const context = opts.context?.length === 0 ?
'' : (opts.context ?? 'Value') + ' ';
return codedTypeError(
`${prefix}${context}${message}`,
{ code: opts.code || 'ERR_INVALID_ARG_TYPE' },
);
}

function createEnumConverter(name, values) {
const E = new SafeSet(values);

return function(V, opts = kEmptyObject) {
const S = String(V);

if (!E.has(S)) {
throw makeException(
`value '${S}' is not a valid enum value of type ${name}.`,
{ __proto__: null, ...opts, code: 'ERR_INVALID_ARG_VALUE' });
}

return S;
};
}

module.exports = {
converters,
convertToInt,
createEnumConverter,
evenRound,
converters,
makeException,
};
24 changes: 16 additions & 8 deletions lib/internal/webstreams/compression.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,6 @@ const {
ObjectDefineProperties,
} = primordials;

const {
codes: { ERR_INVALID_ARG_VALUE },
} = require('internal/errors');

const {
newReadableWritablePairFromDuplex,
} = require('internal/webstreams/adapters');
Expand All @@ -19,12 +15,20 @@ const {
kEnumerableProperty,
} = require('internal/util');

const { createEnumConverter } = require('internal/webidl');

let zlib;
function lazyZlib() {
zlib ??= require('zlib');
return zlib;
}

const formatConverter = createEnumConverter('CompressionFormat', [
'deflate',
'deflate-raw',
'gzip',
]);

/**
* @typedef {import('./readablestream').ReadableStream} ReadableStream
* @typedef {import('./writablestream').WritableStream} WritableStream
Expand All @@ -38,6 +42,10 @@ class CompressionStream {
* @param {'deflate'|'deflate-raw'|'gzip'} format
*/
constructor(format) {
format = formatConverter(format, {
prefix: "Failed to construct 'CompressionStream'",
context: '1st argument',
});
switch (format) {
case 'deflate':
this.#handle = lazyZlib().createDeflate();
Expand All @@ -48,8 +56,6 @@ class CompressionStream {
case 'gzip':
this.#handle = lazyZlib().createGzip();
break;
default:
throw new ERR_INVALID_ARG_VALUE('format', format);
}
this.#transform = newReadableWritablePairFromDuplex(this.#handle);
}
Expand Down Expand Up @@ -86,6 +92,10 @@ class DecompressionStream {
* @param {'deflate'|'deflate-raw'|'gzip'} format
*/
constructor(format) {
format = formatConverter(format, {
prefix: "Failed to construct 'DecompressionStream'",
context: '1st argument',
});
switch (format) {
case 'deflate':
this.#handle = lazyZlib().createInflate();
Expand All @@ -96,8 +106,6 @@ class DecompressionStream {
case 'gzip':
this.#handle = lazyZlib().createGunzip();
break;
default:
throw new ERR_INVALID_ARG_VALUE('format', format);
}
this.#transform = newReadableWritablePairFromDuplex(this.#handle);
}
Expand Down
14 changes: 0 additions & 14 deletions test/wpt/status/compression.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,12 @@
"compression-bad-chunks.tentative.any.js": {
"skip": "Execution \"hangs\", ArrayBuffer and TypedArray is not accepted and throws, instead of rejects during writer.write"
},
"compression-constructor-error.tentative.any.js": {
"fail": {
"expected": [
"non-string input should cause the constructor to throw"
]
}
},
"decompression-bad-chunks.tentative.any.js": {
"skip": "Execution \"hangs\", ArrayBuffer and TypedArray is not accepted and throws, instead of rejects during writer.write"
},
"decompression-buffersource.tentative.any.js": {
"skip": "ArrayBuffer and TypedArray is not accepted and throws, instead of rejects during writer.write"
},
"decompression-constructor-error.tentative.any.js": {
"fail": {
"expected": [
"non-string input should cause the constructor to throw"
]
}
},
"compression-with-detach.tentative.window.js": {
"requires": ["crypto"]
},
Expand Down

0 comments on commit 9d652f4

Please sign in to comment.