diff --git a/lib/zlib.js b/lib/zlib.js index a39e9c20eeb1bc..5ce8637a50f04f 100644 --- a/lib/zlib.js +++ b/lib/zlib.js @@ -251,9 +251,19 @@ function Zlib(opts, mode) { opts.finishFlush, 'options.finishFlush', Z_NO_FLUSH, Z_BLOCK, Z_FINISH); - windowBits = checkRangesOrGetDefault( - opts.windowBits, 'options.windowBits', - Z_MIN_WINDOWBITS, Z_MAX_WINDOWBITS, Z_DEFAULT_WINDOWBITS); + // windowBits is special. On the compression side, 0 is an invalid value. + // But on the decompression side, a value of 0 for windowBits tells zlib + // to use the window size in the zlib header of the compressed stream. + if ((opts.windowBits == null || opts.windowBits === 0) && + (mode === INFLATE || + mode === GUNZIP || + mode === UNZIP)) { + windowBits = 0; + } else { + windowBits = checkRangesOrGetDefault( + opts.windowBits, 'options.windowBits', + Z_MIN_WINDOWBITS, Z_MAX_WINDOWBITS, Z_DEFAULT_WINDOWBITS); + } level = checkRangesOrGetDefault( opts.level, 'options.level', diff --git a/src/node_zlib.cc b/src/node_zlib.cc index 500a62a52bf6c4..4367d043d25a30 100644 --- a/src/node_zlib.cc +++ b/src/node_zlib.cc @@ -438,9 +438,17 @@ class ZCtx : public AsyncWrap { ZCtx* ctx; ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder()); + // windowBits is special. On the compression side, 0 is an invalid value. + // But on the decompression side, a value of 0 for windowBits tells zlib + // to use the window size in the zlib header of the compressed stream. int windowBits = args[0]->Uint32Value(); - CHECK((windowBits >= Z_MIN_WINDOWBITS && windowBits <= Z_MAX_WINDOWBITS) && - "invalid windowBits"); + if (!((windowBits == 0) && + (ctx->mode_ == INFLATE || + ctx->mode_ == GUNZIP || + ctx->mode_ == UNZIP))) { + CHECK((windowBits >= Z_MIN_WINDOWBITS && + windowBits <= Z_MAX_WINDOWBITS) && "invalid windowBits"); + } int level = args[1]->Int32Value(); CHECK((level >= Z_MIN_LEVEL && level <= Z_MAX_LEVEL) && diff --git a/test/parallel/test-zlib-zero-windowBits.js b/test/parallel/test-zlib-zero-windowBits.js new file mode 100644 index 00000000000000..a62e6148e33df7 --- /dev/null +++ b/test/parallel/test-zlib-zero-windowBits.js @@ -0,0 +1,33 @@ +'use strict'; + +const common = require('../common'); +const assert = require('assert'); +const zlib = require('zlib'); + + +// windowBits is a special case in zlib. On the compression side, 0 is invalid. +// On the decompression side, it indicates that zlib should use the value from +// the header of the compressed stream. +{ + const inflate = zlib.createInflate({ windowBits: 0 }); + assert(inflate instanceof zlib.Inflate); +} + +{ + const gunzip = zlib.createGunzip({ windowBits: 0 }); + assert(gunzip instanceof zlib.Gunzip); +} + +{ + const unzip = zlib.createUnzip({ windowBits: 0 }); + assert(unzip instanceof zlib.Unzip); +} + +{ + common.expectsError(() => zlib.createGzip({ windowBits: 0 }), { + code: 'ERR_OUT_OF_RANGE', + type: RangeError, + message: 'The value of "options.windowBits" is out of range. ' + + 'It must be >= 8 and <= 15. Received 0' + }); +}