diff --git a/benchmark/zlib/creation.js b/benchmark/zlib/creation.js index 90b22780d2d312..41b1e4917a67bb 100644 --- a/benchmark/zlib/creation.js +++ b/benchmark/zlib/creation.js @@ -5,7 +5,7 @@ const zlib = require('zlib'); const bench = common.createBenchmark(main, { type: [ 'Deflate', 'DeflateRaw', 'Inflate', 'InflateRaw', 'Gzip', 'Gunzip', 'Unzip', - 'BrotliCompress', 'BrotliDecompress', + 'BrotliCompress', 'BrotliDecompress', 'ZstdCompress', 'ZstdDecompress', ], options: ['true', 'false'], n: [5e5], diff --git a/benchmark/zlib/pipe.js b/benchmark/zlib/pipe.js index a9c86e3de660a9..5a21c3ff417084 100644 --- a/benchmark/zlib/pipe.js +++ b/benchmark/zlib/pipe.js @@ -7,7 +7,7 @@ const bench = common.createBenchmark(main, { inputLen: [1024], duration: [5], type: ['string', 'buffer'], - algorithm: ['gzip', 'brotli'], + algorithm: ['gzip', 'brotli', 'zstd'], }, { test: { inputLen: 1024, @@ -15,14 +15,19 @@ const bench = common.createBenchmark(main, { }, }); +const algorithms = { + 'gzip': [zlib.createGzip, zlib.createGunzip], + 'brotli': [zlib.createBrotliCompress, zlib.createBrotliDecompress], + 'zstd': [zlib.createZstdCompress, zlib.createZstdDecompress], +}; + function main({ inputLen, duration, type, algorithm }) { const buffer = Buffer.alloc(inputLen, fs.readFileSync(__filename)); const chunk = type === 'buffer' ? buffer : buffer.toString('utf8'); - const input = algorithm === 'gzip' ? - zlib.createGzip() : zlib.createBrotliCompress(); - const output = algorithm === 'gzip' ? - zlib.createGunzip() : zlib.createBrotliDecompress(); + const [createCompress, createUncompress] = algorithms[algorithm]; + const input = createCompress(); + const output = createUncompress(); let readFromOutput = 0; input.pipe(output); diff --git a/doc/api/zlib.md b/doc/api/zlib.md index a33de3833cbe9f..da1979dbdce63d 100644 --- a/doc/api/zlib.md +++ b/doc/api/zlib.md @@ -124,8 +124,8 @@ operations be cached to avoid duplication of effort. ## Compressing HTTP requests and responses -The `node:zlib` module can be used to implement support for the `gzip`, `deflate` -and `br` content-encoding mechanisms defined by +The `node:zlib` module can be used to implement support for the `gzip`, `deflate`, +`br` and `zstd` content-encoding mechanisms defined by [HTTP](https://tools.ietf.org/html/rfc7230#section-4.2). The HTTP [`Accept-Encoding`][] header is used within an HTTP request to identify @@ -148,7 +148,7 @@ const { pipeline } = require('node:stream'); const request = http.get({ host: 'example.com', path: '/', port: 80, - headers: { 'Accept-Encoding': 'br,gzip,deflate' } }); + headers: { 'Accept-Encoding': 'br,gzip,deflate,zstd' } }); request.on('response', (response) => { const output = fs.createWriteStream('example.com_index.html'); @@ -170,6 +170,9 @@ request.on('response', (response) => { case 'deflate': pipeline(response, zlib.createInflate(), output, onError); break; + case 'zstd': + pipeline(response, zlib.createZstdDecompress(), output, onError); + break; default: pipeline(response, output, onError); break; @@ -218,6 +221,9 @@ http.createServer((request, response) => { } else if (/\bbr\b/.test(acceptEncoding)) { response.writeHead(200, { 'Content-Encoding': 'br' }); pipeline(raw, zlib.createBrotliCompress(), response, onError); + } else if (/\bzstd\b/.test(acceptEncoding)) { + response.writeHead(200, { 'Content-Encoding': 'zstd' }); + pipeline(raw, zlib.createZstdCompress(), response, onError); } else { response.writeHead(200, {}); pipeline(raw, response, onError); @@ -238,6 +244,7 @@ const buffer = Buffer.from('eJzT0yMA', 'base64'); zlib.unzip( buffer, // For Brotli, the equivalent is zlib.constants.BROTLI_OPERATION_FLUSH. + // For Zstd, the equivalent is zlib.constants.ZSTD_e_flush. { finishFlush: zlib.constants.Z_SYNC_FLUSH }, (err, buffer) => { if (err) { @@ -309,6 +316,16 @@ these options have different ranges than the zlib ones: See [below][Brotli parameters] for more details on Brotli-specific options. +### For Zstd-based streams + +There are equivalents to the zlib options for Zstd-based streams, although +these options have different ranges than the zlib ones: + +* zlib's `level` option matches Zstd's `ZSTD_c_compressionLevel` option. +* zlib's `windowBits` option matches Zstd's `ZSTD_c_windowLog` option. + +See [below][Zstd parameters] for more details on Zstd-specific options. + ## Flushing Calling [`.flush()`][] on a compression stream will make `zlib` return as much @@ -487,6 +504,44 @@ These advanced options are available for controlling decompression: * Boolean flag enabling “Large Window Brotli” mode (not compatible with the Brotli format as standardized in [RFC 7932][]). +### Zstd constants + + + +There are several options and other constants available for Zstd-based +streams: + +#### Flush operations + +The following values are valid flush operations for Zstd-based streams: + +* `zlib.constants.ZSTD_e_continue` (default for all operations) +* `zlib.constants.ZSTD_e_flush` (default when calling `.flush()`) +* `zlib.constants.ZSTD_e_end` (default for the last chunk) + +#### Compressor options + +There are several options that can be set on Zstd encoders, affecting +compression efficiency and speed. Both the keys and the values can be accessed +as properties of the `zlib.constants` object. + +The most important options are: + +* `ZSTD_c_compressionLevel` + * Set compression parameters according to pre-defined cLevel table. Default + level is ZSTD_CLEVEL_DEFAULT==3. + +#### Decompressor options + +These advanced options are available for controlling decompression: + +* `ZSTD_d_windowLogMax` + * Select a size limit (in power of 2) beyond which the streaming API will + refuse to allocate memory buffer in order to protect the host from + unreasonable memory requirements. + ## Class: `Options`