diff --git a/lib/zlib.js b/lib/zlib.js index d4f2446a5976cb..55d7cf997e56a6 100644 --- a/lib/zlib.js +++ b/lib/zlib.js @@ -268,6 +268,7 @@ function ZlibBase(opts, mode, handle, { flush, finishFlush, fullFlush }) { this._defaultFlushFlag = flush; this._finishFlushFlag = finishFlush; this._defaultFullFlushFlag = fullFlush; + this._flushBoundIdx = flushBoundIdx; this._info = opts?.info; this._maxOutputLength = maxOutputLength; @@ -349,6 +350,11 @@ ZlibBase.prototype.flush = function(kind, callback) { kind = this._defaultFullFlushFlag; } + kind = checkRangesOrGetDefault( + kind, 'kind', + FLUSH_BOUND[this._flushBoundIdx][0], FLUSH_BOUND[this._flushBoundIdx][1], + this._defaultFullFlushFlag); + if (this.writableFinished) { if (callback) process.nextTick(callback); diff --git a/test/parallel/test-zlib-brotli-flush-invalid-kind.js b/test/parallel/test-zlib-brotli-flush-invalid-kind.js new file mode 100644 index 00000000000000..af8a2c67d1d9a4 --- /dev/null +++ b/test/parallel/test-zlib-brotli-flush-invalid-kind.js @@ -0,0 +1,92 @@ +'use strict'; +// Regression test for https://github.com/nodejs/node/issues/63701. +// Invalid Brotli flush kinds used to spin in native code. flush(kind) should +// reject invalid kinds before writing the fake flush chunk. + +require('../common'); +const assert = require('assert'); +const zlib = require('zlib'); + +const { + BROTLI_OPERATION_PROCESS, + BROTLI_OPERATION_FLUSH, + BROTLI_OPERATION_FINISH, + BROTLI_OPERATION_EMIT_METADATA, + Z_NO_FLUSH, + Z_BLOCK, + Z_FINISH, + ZSTD_e_continue, + ZSTD_e_flush, + ZSTD_e_end, +} = zlib.constants; + +const noop = () => {}; + +const flushKindTestCases = [ + { + factories: [zlib.createGzip], + validKinds: [Z_NO_FLUSH, Z_FINISH, Z_BLOCK], + invalidKinds: [-1, 6, 100], + }, + { + factories: [zlib.createBrotliCompress, zlib.createBrotliDecompress], + validKinds: [ + BROTLI_OPERATION_PROCESS, + BROTLI_OPERATION_FLUSH, + BROTLI_OPERATION_FINISH, + BROTLI_OPERATION_EMIT_METADATA, + ], + invalidKinds: [-1, Z_FINISH, Z_BLOCK, 6, 100], + }, + { + factories: [zlib.createZstdCompress, zlib.createZstdDecompress], + validKinds: [ZSTD_e_continue, ZSTD_e_flush, ZSTD_e_end], + invalidKinds: [-1, 3, Z_FINISH, Z_BLOCK, 100], + }, +]; + +for (const { factories, validKinds } of flushKindTestCases) { + for (const factory of factories) { + for (const kind of validKinds) { + const stream = factory(); + stream.on('error', noop); + stream.flush(kind); + } + } +} + +for (const { factories, invalidKinds } of flushKindTestCases) { + for (const factory of factories) { + for (const kind of invalidKinds) { + assert.throws( + () => factory().flush(kind), + { code: 'ERR_OUT_OF_RANGE', name: 'RangeError' }, + ); + } + } +} + +for (const { factories } of flushKindTestCases) { + for (const factory of factories) { + for (const kind of ['foobar', null, {}]) { + assert.throws( + () => factory().flush(kind), + { code: 'ERR_INVALID_ARG_TYPE', name: 'TypeError' }, + ); + } + } +} + +for (const { factories } of flushKindTestCases) { + for (const factory of factories) { + for (const kind of [undefined, NaN]) { + const stream = factory(); + stream.on('error', noop); + stream.flush(kind); + } + + const stream = factory(); + stream.on('error', noop); + stream.flush(noop); + } +}