From 584e74d8ccc01d8fa951260fb5f90cad372c9eff Mon Sep 17 00:00:00 2001 From: Jem Bezooyen Date: Fri, 6 Oct 2017 12:19:33 -0700 Subject: [PATCH] zlib: add ArrayBuffer support PR-URL: https://github.com/nodejs/node/pull/16042 Refs: https://github.com/nodejs/node/issues/1826 Reviewed-By: Timothy Gu Reviewed-By: Anna Henningsen Reviewed-By: Luigi Pinca Reviewed-By: Joyee Cheung Reviewed-By: James M Snell Reviewed-By: Ruben Bridgewater --- doc/api/zlib.md | 68 +++++++++++++++---- lib/zlib.js | 24 +++++-- test/common/README.md | 7 ++ test/common/index.js | 4 ++ .../parallel/test-zlib-convenience-methods.js | 2 +- test/parallel/test-zlib-dictionary.js | 2 +- .../test-zlib-not-string-or-buffer.js | 2 +- 7 files changed, 88 insertions(+), 21 deletions(-) diff --git a/doc/api/zlib.md b/doc/api/zlib.md index 7c55b94b26706b..7a8270702066e7 100644 --- a/doc/api/zlib.md +++ b/doc/api/zlib.md @@ -286,6 +286,9 @@ Compression strategy. -All of these take a [`Buffer`][], [`TypedArray`][], [`DataView`][], or string as -the first argument, an optional second argument to supply options to the `zlib` -classes and will call the supplied callback with `callback(error, result)`. +All of these take a [`Buffer`][], [`TypedArray`][], [`DataView`][], +[`ArrayBuffer`][] or string as the first argument, an optional second argument +to supply options to the `zlib` classes and will call the supplied callback +with `callback(error, result)`. Every method has a `*Sync` counterpart, which accept the same arguments, but without a callback. @@ -522,6 +526,9 @@ without a callback. -- `buffer` {Buffer|TypedArray|DataView|string} +- `buffer` {Buffer|TypedArray|DataView|ArrayBuffer|string} Compress a chunk of data with [Deflate][]. @@ -560,6 +570,9 @@ changes: -- `buffer` {Buffer|TypedArray|DataView|string} +- `buffer` {Buffer|TypedArray|DataView|ArrayBuffer|string} Compress a chunk of data with [DeflateRaw][]. @@ -576,6 +589,9 @@ Compress a chunk of data with [DeflateRaw][]. -- `buffer` {Buffer|TypedArray|DataView|string} +- `buffer` {Buffer|TypedArray|DataView|ArrayBuffer|string} Decompress a chunk of data with [Gunzip][]. @@ -603,6 +622,9 @@ Decompress a chunk of data with [Gunzip][]. -- `buffer` {Buffer|TypedArray|DataView|string} +- `buffer` {Buffer|TypedArray|DataView|ArrayBuffer|string} Compress a chunk of data with [Gzip][]. @@ -630,6 +655,9 @@ Compress a chunk of data with [Gzip][]. -- `buffer` {Buffer|TypedArray|DataView|string} +- `buffer` {Buffer|TypedArray|DataView|ArrayBuffer|string} Decompress a chunk of data with [Inflate][]. @@ -657,6 +688,9 @@ Decompress a chunk of data with [Inflate][]. -- `buffer` {Buffer|TypedArray|DataView|string} +- `buffer` {Buffer|TypedArray|DataView|ArrayBuffer|string} Decompress a chunk of data with [InflateRaw][]. @@ -684,6 +721,9 @@ Decompress a chunk of data with [InflateRaw][]. -- `buffer` {Buffer|TypedArray|DataView|string} +- `buffer` {Buffer|TypedArray|DataView|ArrayBuffer|string} Decompress a chunk of data with [Unzip][]. [`.flush()`]: #zlib_zlib_flush_kind_callback [`Accept-Encoding`]: https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.3 +[`ArrayBuffer`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer [`Buffer`]: buffer.html#buffer_class_buffer [`Content-Encoding`]: https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.11 [`DataView`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView diff --git a/lib/zlib.js b/lib/zlib.js index 7580288102a443..8446f3a03a0e8e 100644 --- a/lib/zlib.js +++ b/lib/zlib.js @@ -24,6 +24,7 @@ const errors = require('internal/errors'); const Transform = require('_stream_transform'); const { _extend } = require('util'); +const { isAnyArrayBuffer } = process.binding('util'); const { isArrayBufferView } = require('internal/util/types'); const binding = process.binding('zlib'); const assert = require('assert').ok; @@ -67,6 +68,8 @@ function zlibBuffer(engine, buffer, callback) { if (isArrayBufferView(buffer) && Object.getPrototypeOf(buffer) !== Buffer.prototype) { buffer = Buffer.from(buffer.buffer, buffer.byteOffset, buffer.byteLength); + } else if (isAnyArrayBuffer(buffer)) { + buffer = Buffer.from(buffer); } engine.buffers = null; engine.nread = 0; @@ -114,9 +117,14 @@ function zlibBufferSync(engine, buffer) { if (typeof buffer === 'string') { buffer = Buffer.from(buffer); } else if (!isArrayBufferView(buffer)) { - throw new errors.TypeError('ERR_INVALID_ARG_TYPE', - 'buffer', - ['string', 'Buffer', 'TypedArray', 'DataView']); + if (isAnyArrayBuffer(buffer)) { + buffer = Buffer.from(buffer); + } else { + throw new errors.TypeError('ERR_INVALID_ARG_TYPE', + 'buffer', + ['string', 'Buffer', 'TypedArray', 'DataView', + 'ArrayBuffer']); + } } buffer = processChunkSync(engine, buffer, engine._finishFlushFlag); if (engine._info) @@ -245,9 +253,13 @@ function Zlib(opts, mode) { dictionary = opts.dictionary; if (dictionary !== undefined && !isArrayBufferView(dictionary)) { - throw new errors.TypeError('ERR_INVALID_OPT_VALUE', - 'dictionary', - dictionary); + if (isAnyArrayBuffer(dictionary)) { + dictionary = Buffer.from(dictionary); + } else { + throw new errors.TypeError('ERR_INVALID_OPT_VALUE', + 'dictionary', + dictionary); + } } if (opts.encoding || opts.objectMode || opts.writableObjectMode) { diff --git a/test/common/README.md b/test/common/README.md index f48215836ecae5..87eeb28d545ec0 100644 --- a/test/common/README.md +++ b/test/common/README.md @@ -133,6 +133,13 @@ a reason otherwise. Returns an instance of all possible `ArrayBufferView`s of the provided Buffer. +### getBufferSources(buf) +* `buf` [<Buffer>] +* return [<BufferSource[]>] + +Returns an instance of all possible `BufferSource`s of the provided Buffer, +consisting of all `ArrayBufferView` and an `ArrayBuffer`. + ### getCallSite(func) * `func` [<Function>] * return [<String>] diff --git a/test/common/index.js b/test/common/index.js index 0767b0226cb9f9..5c4d6d1f9a4c68 100644 --- a/test/common/index.js +++ b/test/common/index.js @@ -814,6 +814,10 @@ exports.getArrayBufferViews = function getArrayBufferViews(buf) { return out; }; +exports.getBufferSources = function getBufferSources(buf) { + return [...exports.getArrayBufferViews(buf), new Uint8Array(buf).buffer]; +}; + // Crash the process on unhandled rejections. exports.crashOnUnhandledRejection = function() { process.on('unhandledRejection', diff --git a/test/parallel/test-zlib-convenience-methods.js b/test/parallel/test-zlib-convenience-methods.js index 5c1f7395062d9d..1cc393914a947e 100644 --- a/test/parallel/test-zlib-convenience-methods.js +++ b/test/parallel/test-zlib-convenience-methods.js @@ -43,7 +43,7 @@ const optsInfo = { for (const [type, expect] of [ ['string', expectStr], ['Buffer', expectBuf], - ...common.getArrayBufferViews(expectBuf).map((obj) => + ...common.getBufferSources(expectBuf).map((obj) => [obj[Symbol.toStringTag], obj] ) ]) { diff --git a/test/parallel/test-zlib-dictionary.js b/test/parallel/test-zlib-dictionary.js index 1662e63bca135c..b7f6a138555237 100644 --- a/test/parallel/test-zlib-dictionary.js +++ b/test/parallel/test-zlib-dictionary.js @@ -167,7 +167,7 @@ function deflateRawResetDictionaryTest(spdyDict) { }); } -for (const dict of [spdyDict, ...common.getArrayBufferViews(spdyDict)]) { +for (const dict of [spdyDict, ...common.getBufferSources(spdyDict)]) { basicDictionaryTest(dict); deflateResetDictionaryTest(dict); rawDictionaryTest(dict); diff --git a/test/parallel/test-zlib-not-string-or-buffer.js b/test/parallel/test-zlib-not-string-or-buffer.js index 94db59d77f0dd4..489bc07f5d051b 100644 --- a/test/parallel/test-zlib-not-string-or-buffer.js +++ b/test/parallel/test-zlib-not-string-or-buffer.js @@ -13,7 +13,7 @@ const zlib = require('zlib'); code: 'ERR_INVALID_ARG_TYPE', type: TypeError, message: 'The "buffer" argument must be one of type string, Buffer, ' + - 'TypedArray, or DataView' + 'TypedArray, DataView, or ArrayBuffer' } ); });